diff --git a/.changeset/clever-walls-fold.md b/.changeset/clever-walls-fold.md new file mode 100644 index 00000000000..bdd6c1f4f4d --- /dev/null +++ b/.changeset/clever-walls-fold.md @@ -0,0 +1,7 @@ +--- +"@atproto/oauth-client-browser": patch +"@atproto/oauth-client": patch +--- + +Add `allowHttp` OAuthClient construction option to allow working with "http:" oauth providers (for development & testing purposes). + diff --git a/.changeset/eleven-avocados-switch.md b/.changeset/eleven-avocados-switch.md new file mode 100644 index 00000000000..9821a415683 --- /dev/null +++ b/.changeset/eleven-avocados-switch.md @@ -0,0 +1,5 @@ +--- +"@atproto/oauth-types": minor +--- + +Allow oauthIssuerIdentifier to be an "http:" url. Make sure to manually check for "http:" issuers if you don't allow them. diff --git a/.changeset/gentle-socks-punch.md b/.changeset/gentle-socks-punch.md new file mode 100644 index 00000000000..204b32da565 --- /dev/null +++ b/.changeset/gentle-socks-punch.md @@ -0,0 +1,5 @@ +--- +"@atproto-labs/did-resolver": patch +--- + +Add "allowHttp" did:web method option diff --git a/.changeset/hungry-ways-decide.md b/.changeset/hungry-ways-decide.md new file mode 100644 index 00000000000..8f53200d793 --- /dev/null +++ b/.changeset/hungry-ways-decide.md @@ -0,0 +1,5 @@ +--- +"@atproto/oauth-client-node": patch +--- + +Bugfix: Prevent accidental override of `NodeOAuthClient` constructor options diff --git a/.changeset/thirty-jeans-itch.md b/.changeset/thirty-jeans-itch.md new file mode 100644 index 00000000000..15decf5612c --- /dev/null +++ b/.changeset/thirty-jeans-itch.md @@ -0,0 +1,5 @@ +--- +"@atproto/oauth-types": minor +--- + +Remove ALLOW_UNSECURE_ORIGINS constant diff --git a/.changeset/witty-masks-wave.md b/.changeset/witty-masks-wave.md new file mode 100644 index 00000000000..c7e28e36067 --- /dev/null +++ b/.changeset/witty-masks-wave.md @@ -0,0 +1,5 @@ +--- +"@atproto/oauth-provider": patch +--- + +Improve error message when invalid client id used during code exchange diff --git a/.changeset/young-paws-poke.md b/.changeset/young-paws-poke.md new file mode 100644 index 00000000000..ef011ff287e --- /dev/null +++ b/.changeset/young-paws-poke.md @@ -0,0 +1,5 @@ +--- +"@atproto/oauth-types": patch +--- + +Improve typing of oauthIssuerIdentifierSchema diff --git a/.github/workflows/repo.yaml b/.github/workflows/repo.yaml index 005bacb421b..bbfc064f74f 100644 --- a/.github/workflows/repo.yaml +++ b/.github/workflows/repo.yaml @@ -23,6 +23,13 @@ jobs: with: node-version: 18 cache: 'pnpm' + - name: Get current month + run: echo "CURRENT_MONTH=$(date +'%Y-%m')" >> $GITHUB_ENV + - uses: actions/cache@v4 + name: Cache Puppeteer browser binaries + with: + path: ~/.cache + key: ${{ env.CURRENT_MONTH }}-${{ runner.os }} - run: pnpm i --frozen-lockfile - run: pnpm build - uses: actions/upload-artifact@v4 @@ -49,6 +56,13 @@ jobs: with: node-version: 18 cache: 'pnpm' + - name: Get current month + run: echo "CURRENT_MONTH=$(date +'%Y-%m')" >> $GITHUB_ENV + - uses: actions/cache@v4 + name: Cache Puppeteer browser binaries + with: + path: ~/.cache + key: ${{ env.CURRENT_MONTH }}-${{ runner.os }} - run: pnpm i --frozen-lockfile - uses: actions/download-artifact@v4 with: @@ -69,6 +83,13 @@ jobs: with: node-version: 18 cache: 'pnpm' + - name: Get current month + run: echo "CURRENT_MONTH=$(date +'%Y-%m')" >> $GITHUB_ENV + - uses: actions/cache@v4 + name: Cache Puppeteer browser binaries + with: + path: ~/.cache + key: ${{ env.CURRENT_MONTH }}-${{ runner.os }} - run: pnpm i --frozen-lockfile - uses: actions/download-artifact@v4 with: diff --git a/packages/api/jest.config.js b/packages/api/jest.config.js index 23994feaf41..1c938059f3e 100644 --- a/packages/api/jest.config.js +++ b/packages/api/jest.config.js @@ -1,8 +1,7 @@ /** @type {import('jest').Config} */ module.exports = { displayName: 'API', - transform: { '^.+\\.(t|j)s$': '@swc/jest' }, - transformIgnorePatterns: [`/node_modules/(?!get-port)`], + transform: { '^.+\\.ts$': '@swc/jest' }, testTimeout: 60000, setupFiles: ['/../../jest.setup.ts'], setupFilesAfterEnv: ['/jest.setup.ts'], diff --git a/packages/api/package.json b/packages/api/package.json index c35056510b9..204f02057e6 100644 --- a/packages/api/package.json +++ b/packages/api/package.json @@ -33,7 +33,6 @@ }, "devDependencies": { "@atproto/lex-cli": "workspace:^", - "get-port": "^6.1.2", "jest": "^28.1.2", "prettier": "^3.2.5", "typescript": "^5.6.2" diff --git a/packages/api/tests/dispatcher.test.ts b/packages/api/tests/dispatcher.test.ts index 6ccd4783ea6..0c686aa966a 100644 --- a/packages/api/tests/dispatcher.test.ts +++ b/packages/api/tests/dispatcher.test.ts @@ -1,5 +1,5 @@ +import { AddressInfo } from 'node:net' import assert from 'assert' -import getPort from 'get-port' import { AtpAgent, AtpSessionEvent, @@ -443,8 +443,8 @@ describe('AtpAgent', () => { describe('App labelers header', () => { it('adds the labelers header as expected', async () => { - const port = await getPort() - const server = await createHeaderEchoServer(port) + const server = await createHeaderEchoServer() + const port = (server.address() as AddressInfo).port const agent = new AtpAgent({ service: `http://localhost:${port}` }) const agent2 = new AtpAgent({ service: `http://localhost:${port}` }) @@ -470,8 +470,8 @@ describe('AtpAgent', () => { describe('configureLabelers', () => { it('adds the labelers header as expected', async () => { - const port = await getPort() - const server = await createHeaderEchoServer(port) + const server = await createHeaderEchoServer() + const port = (server.address() as AddressInfo).port const agent = new AtpAgent({ service: `http://localhost:${port}` }) agent.configureLabelers(['did:plc:test1']) @@ -492,8 +492,8 @@ describe('AtpAgent', () => { describe('configureProxy', () => { it('adds the proxy header as expected', async () => { - const port = await getPort() - const server = await createHeaderEchoServer(port) + const server = await createHeaderEchoServer() + const port = (server.address() as AddressInfo).port const agent = new AtpAgent({ service: `http://localhost:${port}` }) const res1 = await agent.com.atproto.server.describeServer() diff --git a/packages/api/tests/util/echo-server.ts b/packages/api/tests/util/echo-server.ts index 428398dbc3f..2ae1da12268 100644 --- a/packages/api/tests/util/echo-server.ts +++ b/packages/api/tests/util/echo-server.ts @@ -1,21 +1,21 @@ -import http from 'node:http' +import { once } from 'node:events' +import { createServer } from 'node:http' -export async function createHeaderEchoServer(port: number) { - return new Promise((resolve) => { - const server = http.createServer() - - server - .on('request', (request, response) => { - response.setHeader('content-type', 'application/json') - response.end( - JSON.stringify({ - ...request.headers, - did: 'did:web:fake.com', - availableUserDomains: [], - }), - ) - }) - .on('listening', () => resolve(server)) - .listen(port) +export async function createHeaderEchoServer(port: number = 0) { + const server = createServer((req, res) => { + res.writeHead(200, undefined, { 'content-type': 'application/json' }) + res.end( + JSON.stringify({ + ...req.headers, + did: 'did:web:fake.com', + availableUserDomains: [], + }), + ) }) + + server.listen(port) + + await once(server, 'listening') + + return server } diff --git a/packages/bsky/jest.config.js b/packages/bsky/jest.config.js index ee315e79d22..0de38d9de00 100644 --- a/packages/bsky/jest.config.js +++ b/packages/bsky/jest.config.js @@ -2,7 +2,7 @@ module.exports = { displayName: 'Bsky App View', transform: { '^.+\\.(t|j)s$': '@swc/jest' }, - transformIgnorePatterns: [`/node_modules/(?!get-port)`], + transformIgnorePatterns: ['/node_modules/.pnpm/(?!(get-port)@)'], testTimeout: 60000, setupFiles: ['/../../jest.setup.ts'], } diff --git a/packages/identity/jest.config.js b/packages/identity/jest.config.js index 768288c07bf..c8ff8355630 100644 --- a/packages/identity/jest.config.js +++ b/packages/identity/jest.config.js @@ -2,6 +2,6 @@ module.exports = { displayName: 'Identity', transform: { '^.+\\.(t|j)s$': '@swc/jest' }, - transformIgnorePatterns: [`/node_modules/(?!get-port)`], + transformIgnorePatterns: ['/node_modules/.pnpm/(?!(get-port)@)'], setupFiles: ['/../../jest.setup.ts'], } diff --git a/packages/internal/did-resolver/src/methods/web.ts b/packages/internal/did-resolver/src/methods/web.ts index 5302c22513d..5130309884b 100644 --- a/packages/internal/did-resolver/src/methods/web.ts +++ b/packages/internal/did-resolver/src/methods/web.ts @@ -18,18 +18,31 @@ const fetchSuccessHandler = pipe( export type DidWebMethodOptions = { fetch?: Fetch + /** @default true */ + allowHttp?: boolean } export class DidWebMethod implements DidMethod<'web'> { protected readonly fetch: Fetch + protected readonly allowHttp: boolean - constructor({ fetch = globalThis.fetch }: DidWebMethodOptions = {}) { + constructor({ + fetch = globalThis.fetch, + allowHttp = true, + }: DidWebMethodOptions = {}) { this.fetch = bindFetch(fetch) + this.allowHttp = allowHttp } async resolve(did: Did<'web'>, options?: ResolveDidOptions) { const didDocumentUrl = buildDidWebDocumentUrl(did) + if (!this.allowHttp && didDocumentUrl.protocol === 'http:') { + throw new Error( + `Cannot resolve DID document for localhost: ${didDocumentUrl}`, + ) + } + // Note we do not explicitly check for "localhost" here. Instead, we rely on // the injected 'fetch' function to handle the URL. If the URL is // "localhost", or resolves to a private IP address, the fetch function is diff --git a/packages/lexicon/jest.config.js b/packages/lexicon/jest.config.js index cb439bdfb43..2aa5609eff2 100644 --- a/packages/lexicon/jest.config.js +++ b/packages/lexicon/jest.config.js @@ -1,7 +1,6 @@ /** @type {import('jest').Config} */ module.exports = { displayName: 'Lexicon', - transform: { '^.+\\.(t|j)s$': '@swc/jest' }, - transformIgnorePatterns: [`/node_modules/(?!get-port)`], + transform: { '^.+\\.ts$': '@swc/jest' }, setupFiles: ['/../../jest.setup.ts'], } diff --git a/packages/oauth/oauth-client-browser/example/.gitignore b/packages/oauth/oauth-client-browser-example/.gitignore similarity index 100% rename from packages/oauth/oauth-client-browser/example/.gitignore rename to packages/oauth/oauth-client-browser-example/.gitignore diff --git a/packages/oauth/oauth-client-browser/example/.postcssrc.yml b/packages/oauth/oauth-client-browser-example/.postcssrc.yml similarity index 100% rename from packages/oauth/oauth-client-browser/example/.postcssrc.yml rename to packages/oauth/oauth-client-browser-example/.postcssrc.yml diff --git a/packages/oauth/oauth-client-browser-example/package.json b/packages/oauth/oauth-client-browser-example/package.json new file mode 100644 index 00000000000..e24803d1e5a --- /dev/null +++ b/packages/oauth/oauth-client-browser-example/package.json @@ -0,0 +1,60 @@ +{ + "name": "@atproto/oauth-client-browser-example", + "version": "0.0.0", + "license": "MIT", + "description": "Example single page application app using ATPROTO OAuth", + "keywords": [ + "example", + "spa", + "atproto", + "oauth", + "browser", + "client" + ], + "homepage": "https://atproto.com", + "repository": { + "type": "git", + "url": "https://github.com/bluesky-social/atproto", + "directory": "packages/oauth/oauth-client-browser" + }, + "type": "commonjs", + "exports": { + ".": { + "default": "./dist/files.json" + } + }, + "files": [ + "dist" + ], + "dependencies": {}, + "devDependencies": { + "@atproto-labs/rollup-plugin-bundle-manifest": "workspace:*", + "@atproto/api": "workspace:*", + "@atproto/oauth-client": "workspace:*", + "@atproto/oauth-client-browser": "workspace:*", + "@atproto/oauth-types": "workspace:*", + "@atproto/xrpc": "workspace:*", + "@rollup/plugin-commonjs": "^25.0.7", + "@rollup/plugin-json": "^6.1.0", + "@rollup/plugin-html": "^1.0.4", + "@rollup/plugin-node-resolve": "^15.2.3", + "@rollup/plugin-replace": "^5.0.5", + "@rollup/plugin-terser": "^0.4.4", + "@rollup/plugin-typescript": "^11.1.6", + "@types/react": "^18.2.50", + "@types/react-dom": "^18.2.18", + "autoprefixer": "^10.4.17", + "postcss": "^8.4.33", + "react": "^18.2.0", + "react-dom": "^18.2.0", + "rollup": "^4.13.0", + "rollup-plugin-postcss": "^4.0.2", + "rollup-plugin-serve": "^1.1.1", + "tailwindcss": "^3.4.1", + "typescript": "^5.6.3" + }, + "scripts": { + "build": "rollup --config rollup.config.js", + "dev": "rollup --config rollup.config.js --watch" + } +} diff --git a/packages/oauth/oauth-client-browser-example/rollup.config.js b/packages/oauth/oauth-client-browser-example/rollup.config.js new file mode 100644 index 00000000000..91e0f741347 --- /dev/null +++ b/packages/oauth/oauth-client-browser-example/rollup.config.js @@ -0,0 +1,99 @@ +/* eslint-env node */ + +const { defineConfig } = require('rollup') + +const { + default: manifest, +} = require('@atproto-labs/rollup-plugin-bundle-manifest') +const { default: commonjs } = require('@rollup/plugin-commonjs') +const { default: html, makeHtmlAttributes } = require('@rollup/plugin-html') +const { default: json } = require('@rollup/plugin-json') +const { default: nodeResolve } = require('@rollup/plugin-node-resolve') +const { default: replace } = require('@rollup/plugin-replace') +const { default: terser } = require('@rollup/plugin-terser') +const { default: typescript } = require('@rollup/plugin-typescript') +const postcss = ((m) => m.default || m)(require('rollup-plugin-postcss')) +const serve = ((m) => m.default || m)(require('rollup-plugin-serve')) + +module.exports = defineConfig((commandLineArguments) => { + const NODE_ENV = + process.env['NODE_ENV'] ?? + (commandLineArguments.watch ? 'development' : 'production') + + const minify = NODE_ENV !== 'development' + + return { + input: 'src/main.tsx', + output: { + manualChunks: undefined, + sourcemap: true, + file: 'dist/main.js', + format: 'iife', + }, + plugins: [ + nodeResolve({ preferBuiltins: false, browser: true }), + commonjs(), + json(), + postcss({ config: true, extract: true, minimize: false }), + typescript({ + tsconfig: './tsconfig.build.json', + outputToFilesystem: true, + }), + replace({ + preventAssignment: true, + values: { 'process.env.NODE_ENV': JSON.stringify(NODE_ENV) }, + }), + html({ + title: 'OAuth Client Example', + template: ({ attributes, files, meta, publicPath, title }) => ` + + + + ${meta + .map((attrs) => ``) + .join('\n')} + + ${title} + ${files.css + .map( + (asset) => + ``, + ) + .join('\n')} + + +
+ ${files.js + .map( + (asset) => + ``, + ) + .join('\n')} + + + `, + }), + minify && terser({}), + manifest({ name: 'files.json', data: true }), + + commandLineArguments.watch && + serve({ + contentBase: 'dist', + port: 8080, + headers: { 'Cache-Control': 'no-store' }, + }), + ], + onwarn(warning, warn) { + // 'use client' directives are fine + if (warning.code === 'MODULE_LEVEL_DIRECTIVE') return + warn(warning) + }, + } +}) diff --git a/packages/oauth/oauth-client-browser/example/src/app.tsx b/packages/oauth/oauth-client-browser-example/src/app.tsx similarity index 100% rename from packages/oauth/oauth-client-browser/example/src/app.tsx rename to packages/oauth/oauth-client-browser-example/src/app.tsx diff --git a/packages/oauth/oauth-client-browser/example/src/auth/auth-form.tsx b/packages/oauth/oauth-client-browser-example/src/auth/auth-form.tsx similarity index 100% rename from packages/oauth/oauth-client-browser/example/src/auth/auth-form.tsx rename to packages/oauth/oauth-client-browser-example/src/auth/auth-form.tsx diff --git a/packages/oauth/oauth-client-browser/example/src/auth/auth-provider.tsx b/packages/oauth/oauth-client-browser-example/src/auth/auth-provider.tsx similarity index 100% rename from packages/oauth/oauth-client-browser/example/src/auth/auth-provider.tsx rename to packages/oauth/oauth-client-browser-example/src/auth/auth-provider.tsx diff --git a/packages/oauth/oauth-client-browser/example/src/auth/credential/credential-sign-in-form.tsx b/packages/oauth/oauth-client-browser-example/src/auth/credential/credential-sign-in-form.tsx similarity index 100% rename from packages/oauth/oauth-client-browser/example/src/auth/credential/credential-sign-in-form.tsx rename to packages/oauth/oauth-client-browser-example/src/auth/credential/credential-sign-in-form.tsx diff --git a/packages/oauth/oauth-client-browser/example/src/auth/credential/use-credential-auth.ts b/packages/oauth/oauth-client-browser-example/src/auth/credential/use-credential-auth.ts similarity index 100% rename from packages/oauth/oauth-client-browser/example/src/auth/credential/use-credential-auth.ts rename to packages/oauth/oauth-client-browser-example/src/auth/credential/use-credential-auth.ts diff --git a/packages/oauth/oauth-client-browser/example/src/auth/oauth/oauth-sign-in-form.tsx b/packages/oauth/oauth-client-browser-example/src/auth/oauth/oauth-sign-in-form.tsx similarity index 99% rename from packages/oauth/oauth-client-browser/example/src/auth/oauth/oauth-sign-in-form.tsx rename to packages/oauth/oauth-client-browser-example/src/auth/oauth/oauth-sign-in-form.tsx index 72b07c67c87..c965209aeb3 100644 --- a/packages/oauth/oauth-client-browser/example/src/auth/oauth/oauth-sign-in-form.tsx +++ b/packages/oauth/oauth-client-browser-example/src/auth/oauth/oauth-sign-in-form.tsx @@ -57,7 +57,6 @@ export function OAuthSignInForm({
> @@ -70,6 +71,7 @@ function useOAuthClient( handleResolver, responseMode, plcDirectoryUrl, + allowHttp, } = options const [client, setClient] = useState( @@ -92,6 +94,7 @@ function useOAuthClient( responseMode, plcDirectoryUrl, fetch, + allowHttp, signal, }).then( (client) => { diff --git a/packages/oauth/oauth-client-browser-example/src/constants.ts b/packages/oauth/oauth-client-browser-example/src/constants.ts new file mode 100644 index 00000000000..f437722747d --- /dev/null +++ b/packages/oauth/oauth-client-browser-example/src/constants.ts @@ -0,0 +1,14 @@ +const { searchParams } = new URL(window.location.href) + +// Inserted during build +declare const process: { env: { NODE_ENV: string } } + +export const ENV = searchParams.get('env') ?? process.env.NODE_ENV + +export const PLC_DIRECTORY_URL: string | undefined = + searchParams.get('plc_directory_url') ?? + (ENV === 'development' ? 'http://localhost:2582' : undefined) + +export const HANDLE_RESOLVER_URL: string = + searchParams.get('handle_resolver') ?? + (ENV === 'development' ? 'http://localhost:2584' : 'https://bsky.social') diff --git a/packages/oauth/oauth-client-browser/example/src/index.css b/packages/oauth/oauth-client-browser-example/src/index.css similarity index 100% rename from packages/oauth/oauth-client-browser/example/src/index.css rename to packages/oauth/oauth-client-browser-example/src/index.css diff --git a/packages/oauth/oauth-client-browser-example/src/main.tsx b/packages/oauth/oauth-client-browser-example/src/main.tsx new file mode 100644 index 00000000000..fdf51f138f7 --- /dev/null +++ b/packages/oauth/oauth-client-browser-example/src/main.tsx @@ -0,0 +1,33 @@ +import './index.css' + +import React from 'react' +import ReactDOM from 'react-dom/client' + +import App from './app' +import { AuthProvider } from './auth/auth-provider' +import { ENV, HANDLE_RESOLVER_URL, PLC_DIRECTORY_URL } from './constants' + +const clientId = `http://localhost?${new URLSearchParams({ + scope: 'atproto transition:generic', + redirect_uri: Object.assign(new URL(window.location.origin), { + hostname: '127.0.0.1', + search: new URLSearchParams({ + env: ENV, + handle_resolver: HANDLE_RESOLVER_URL, + ...(PLC_DIRECTORY_URL && { plc_directory_url: PLC_DIRECTORY_URL }), + }).toString(), + }).href, +})}` + +ReactDOM.createRoot(document.getElementById('root')!).render( + + + + + , +) diff --git a/packages/oauth/oauth-client-browser/example/tailwind.config.js b/packages/oauth/oauth-client-browser-example/tailwind.config.js similarity index 65% rename from packages/oauth/oauth-client-browser/example/tailwind.config.js rename to packages/oauth/oauth-client-browser-example/tailwind.config.js index 7141e4528c6..aea8d354b11 100644 --- a/packages/oauth/oauth-client-browser/example/tailwind.config.js +++ b/packages/oauth/oauth-client-browser-example/tailwind.config.js @@ -1,6 +1,6 @@ /** @type {import('tailwindcss').Config} */ export default { - content: ['./index.html', './src/**/*.{js,ts,jsx,tsx}'], + content: ['./src/**/*.{js,ts,jsx,tsx}'], theme: { extend: {}, }, diff --git a/packages/oauth/oauth-client-browser/example/tsconfig.build.json b/packages/oauth/oauth-client-browser-example/tsconfig.build.json similarity index 64% rename from packages/oauth/oauth-client-browser/example/tsconfig.build.json rename to packages/oauth/oauth-client-browser-example/tsconfig.build.json index 5d2476f34aa..20d8c5472f3 100644 --- a/packages/oauth/oauth-client-browser/example/tsconfig.build.json +++ b/packages/oauth/oauth-client-browser-example/tsconfig.build.json @@ -1,7 +1,7 @@ { "extends": [ - "../../../../tsconfig/browser.json", - "../../../../tsconfig/bundler.json" + "../../../tsconfig/browser.json", + "../../../tsconfig/bundler.json" ], "compilerOptions": { "rootDir": "./src", diff --git a/packages/oauth/oauth-client-browser/example/tsconfig.json b/packages/oauth/oauth-client-browser-example/tsconfig.json similarity index 100% rename from packages/oauth/oauth-client-browser/example/tsconfig.json rename to packages/oauth/oauth-client-browser-example/tsconfig.json diff --git a/packages/oauth/oauth-client-browser-example/tsconfig.tools.json b/packages/oauth/oauth-client-browser-example/tsconfig.tools.json new file mode 100644 index 00000000000..147ae9c50d1 --- /dev/null +++ b/packages/oauth/oauth-client-browser-example/tsconfig.tools.json @@ -0,0 +1,9 @@ +{ + "extends": "../../../tsconfig/node.json", + "compilerOptions": { + "rootDir": ".", + "noEmit": true + }, + "include": ["./*.js", "./*.ts"], + "exclude": [] +} diff --git a/packages/oauth/oauth-client-browser/example/package.json b/packages/oauth/oauth-client-browser/example/package.json deleted file mode 100644 index 3dbc1ca591c..00000000000 --- a/packages/oauth/oauth-client-browser/example/package.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "type": "module" -} diff --git a/packages/oauth/oauth-client-browser/example/rollup.config.js b/packages/oauth/oauth-client-browser/example/rollup.config.js deleted file mode 100644 index bea6c33c379..00000000000 --- a/packages/oauth/oauth-client-browser/example/rollup.config.js +++ /dev/null @@ -1,91 +0,0 @@ -/* eslint-env node */ - -import { defineConfig } from 'rollup' - -import commonjs from '@rollup/plugin-commonjs' -import html, { makeHtmlAttributes } from '@rollup/plugin-html' -import json from '@rollup/plugin-json' -import nodeResolve from '@rollup/plugin-node-resolve' -import replace from '@rollup/plugin-replace' -import typescript from '@rollup/plugin-typescript' -import postcss from 'rollup-plugin-postcss' -import serve from 'rollup-plugin-serve' - -export default defineConfig((commandLineArguments) => { - const NODE_ENV = - process.env['NODE_ENV'] ?? - (commandLineArguments.watch ? 'development' : 'production') - - return { - input: 'src/main.tsx', - output: { dir: 'dist', sourcemap: true }, - plugins: [ - nodeResolve({ preferBuiltins: false, browser: true }), - commonjs(), - postcss({ config: true, extract: true, minimize: false }), - json(), - typescript({ - tsconfig: './tsconfig.build.json', - outputToFilesystem: true, - }), - replace({ - preventAssignment: true, - values: { 'process.env.NODE_ENV': JSON.stringify(NODE_ENV) }, - }), - html({ - title: 'OAuth Client Example', - template: (templateOptions) => { - // https://github.com/rollup/plugins/pull/1718 - if (!templateOptions) throw new Error('No template options provided') - const { attributes, files, meta, publicPath, title } = templateOptions - - return ` - - - - ${meta - .map((attrs) => ``) - .join('\n')} - - ${title} - ${files.css - .map( - (asset) => - ``, - ) - .join('\n')} - - -
- ${files.js - .map( - (asset) => - ``, - ) - .join('\n')} - - - ` - }, - }), - commandLineArguments.watch && - serve({ - contentBase: 'dist', - port: 8080, - headers: { 'Cache-Control': 'no-store' }, - }), - ], - onwarn(warning, warn) { - // 'use client' directives are fine - if (warning.code === 'MODULE_LEVEL_DIRECTIVE') return - warn(warning) - }, - } -}) diff --git a/packages/oauth/oauth-client-browser/example/src/main.tsx b/packages/oauth/oauth-client-browser/example/src/main.tsx deleted file mode 100644 index 0cd9df67c32..00000000000 --- a/packages/oauth/oauth-client-browser/example/src/main.tsx +++ /dev/null @@ -1,23 +0,0 @@ -import './index.css' - -import React from 'react' -import ReactDOM from 'react-dom/client' - -import App from './app' -import { AuthProvider } from './auth/auth-provider' - -ReactDOM.createRoot(document.getElementById('root')!).render( - - - - - , -) diff --git a/packages/oauth/oauth-client-browser/example/tsconfig.tools.json b/packages/oauth/oauth-client-browser/example/tsconfig.tools.json deleted file mode 100644 index 1588d29506e..00000000000 --- a/packages/oauth/oauth-client-browser/example/tsconfig.tools.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "extends": "../../../../tsconfig/node.json", - "compilerOptions": { - "rootDir": ".", - "noEmit": true - }, - "include": ["./*.js", "./*.ts"] -} diff --git a/packages/oauth/oauth-client-browser/package.json b/packages/oauth/oauth-client-browser/package.json index 15ac663fa0c..d006a78265a 100644 --- a/packages/oauth/oauth-client-browser/package.json +++ b/packages/oauth/oauth-client-browser/package.json @@ -41,32 +41,9 @@ "@atproto/oauth-types": "workspace:*" }, "devDependencies": { - "@atproto/api": "workspace:*", - "@atproto/oauth-client": "workspace:*", - "@atproto/oauth-client-browser": "workspace:*", - "@atproto/oauth-types": "workspace:*", - "@atproto/xrpc": "workspace:*", - "@rollup/plugin-commonjs": "^25.0.7", - "@rollup/plugin-html": "^1.0.3", - "@rollup/plugin-json": "^6.1.0", - "@rollup/plugin-node-resolve": "^15.2.3", - "@rollup/plugin-replace": "^5.0.5", - "@rollup/plugin-terser": "^0.4.4", - "@rollup/plugin-typescript": "^11.1.6", - "@types/react": "^18.2.50", - "@types/react-dom": "^18.2.18", - "autoprefixer": "^10.4.17", - "postcss": "^8.4.33", - "react": "^18.2.0", - "react-dom": "^18.2.0", - "rollup": "^4.13.0", - "rollup-plugin-postcss": "^4.0.2", - "rollup-plugin-serve": "^1.1.1", - "tailwindcss": "^3.4.1", "typescript": "^5.6.2" }, "scripts": { - "build": "tsc --build tsconfig.build.json", - "dev": "cd ./example && rollup --config rollup.config.js --watch" + "build": "tsc --build tsconfig.build.json" } } diff --git a/packages/oauth/oauth-client-browser/src/browser-oauth-client.ts b/packages/oauth/oauth-client-browser/src/browser-oauth-client.ts index 177c60e71f0..f7bafb9b47f 100644 --- a/packages/oauth/oauth-client-browser/src/browser-oauth-client.ts +++ b/packages/oauth/oauth-client-browser/src/browser-oauth-client.ts @@ -1,10 +1,10 @@ -import { HandleResolver } from '@atproto-labs/handle-resolver' import { AuthorizeOptions, ClientMetadata, Fetch, OAuthCallbackError, OAuthClient, + OAuthClientOptions, OAuthSession, SessionEventMap, } from '@atproto/oauth-client' @@ -13,21 +13,41 @@ import { atprotoLoopbackClientMetadata, isOAuthClientIdLoopback, OAuthClientMetadataInput, + OAuthResponseMode, } from '@atproto/oauth-types' import { BrowserOAuthDatabase } from './browser-oauth-database.js' import { BrowserRuntimeImplementation } from './browser-runtime-implementation.js' import { LoginContinuedInParentWindowError } from './errors.js' -import { buildLoopbackClientId, TypedBroadcastChannel } from './util.js' - -export type BrowserOAuthClientOptions = { - clientMetadata?: OAuthClientMetadataInput - handleResolver: HandleResolver | string | URL - responseMode?: 'query' | 'fragment' - plcDirectoryUrl?: string | URL - - fetch?: Fetch -} +import { + buildLoopbackClientId, + Simplify, + TypedBroadcastChannel, +} from './util.js' + +export type BrowserOAuthClientOptions = Simplify< + { + clientMetadata?: Readonly + responseMode?: Exclude + fetch?: Fetch + } & Omit< + OAuthClientOptions, + // Overridden by this lib + | 'clientMetadata' + | 'responseMode' + | 'keyset' + | 'fetch' + // Provided by this lib + | 'runtimeImplementation' + | 'sessionStore' + | 'stateStore' + | 'didCache' + | 'handleCache' + | 'dpopNonceCache' + | 'authorizationServerMetadataCache' + | 'protectedResourceMetadataCache' + > +> const NAMESPACE = `@@atproto/oauth-client-browser` @@ -57,13 +77,12 @@ type SyncChannelMessage = { const syncChannel: TypedBroadcastChannel = new BroadcastChannel(`${NAMESPACE}(synchronization-channel)`) -export type BrowserOAuthClientLoadOptions = Omit< - BrowserOAuthClientOptions, - 'clientMetadata' -> & { - clientId: string - signal?: AbortSignal -} +export type BrowserOAuthClientLoadOptions = Simplify< + { + clientId: string + signal?: AbortSignal + } & Omit +> export class BrowserOAuthClient extends OAuthClient implements Disposable { static async load({ clientId, ...options }: BrowserOAuthClientLoadOptions) { @@ -85,14 +104,12 @@ export class BrowserOAuthClient extends OAuthClient implements Disposable { readonly [Symbol.dispose]: () => void constructor({ - handleResolver, clientMetadata = atprotoLoopbackClientMetadata( buildLoopbackClientId(window.location), ), // "fragment" is a safer default as the query params will not be sent to the server responseMode = 'fragment', - plcDirectoryUrl = undefined, - fetch = undefined, + ...options }: BrowserOAuthClientOptions) { if (!globalThis.crypto?.subtle) { throw new Error('WebCrypto API is required') @@ -106,11 +123,11 @@ export class BrowserOAuthClient extends OAuthClient implements Disposable { const database = new BrowserOAuthDatabase() super({ + ...options, + clientMetadata, responseMode, - fetch, - plcDirectoryUrl, - handleResolver, + keyset: undefined, runtimeImplementation: new BrowserRuntimeImplementation(), diff --git a/packages/oauth/oauth-client-browser/tsconfig.json b/packages/oauth/oauth-client-browser/tsconfig.json index 808f8cd9302..e84b8178b47 100644 --- a/packages/oauth/oauth-client-browser/tsconfig.json +++ b/packages/oauth/oauth-client-browser/tsconfig.json @@ -1,7 +1,4 @@ { "include": [], - "references": [ - { "path": "./tsconfig.build.json" }, - { "path": "./example/tsconfig.json" } - ] + "references": [{ "path": "./tsconfig.build.json" }] } diff --git a/packages/oauth/oauth-client-node/src/node-oauth-client.ts b/packages/oauth/oauth-client-node/src/node-oauth-client.ts index ac1d353c385..8a90d7ce547 100644 --- a/packages/oauth/oauth-client-node/src/node-oauth-client.ts +++ b/packages/oauth/oauth-client-node/src/node-oauth-client.ts @@ -24,17 +24,20 @@ export type { OAuthClientOptions, OAuthResponseMode, RuntimeLock } export type NodeOAuthClientOptions = Omit< OAuthClientOptions, + // Overridden by this lib | 'responseMode' - | 'runtimeImplementation' - | 'handleResolver' - | 'sessionStore' | 'stateStore' + | 'sessionStore' + // Provided by this lib + | 'runtimeImplementation' // only "requestLock" needed + | 'handleResolver' // Will be build based on "fallbackNameservers" > & { - fallbackNameservers?: AtprotoHandleResolverNodeOptions['fallbackNameservers'] - responseMode?: OAuthResponseMode + responseMode?: Exclude stateStore: NodeSavedStateStore sessionStore: NodeSavedSessionStore + + fallbackNameservers?: AtprotoHandleResolverNodeOptions['fallbackNameservers'] requestLock?: RuntimeLock } @@ -65,6 +68,8 @@ export class NodeOAuthClient extends OAuthClient { } super({ + ...options, + fetch, responseMode, handleResolver: new AtprotoHandleResolverNode({ @@ -81,8 +86,6 @@ export class NodeOAuthClient extends OAuthClient { stateStore: toDpopKeyStore(stateStore), sessionStore: toDpopKeyStore(sessionStore), - - ...options, }) } } diff --git a/packages/oauth/oauth-client/src/oauth-authorization-server-metadata-resolver.ts b/packages/oauth/oauth-client/src/oauth-authorization-server-metadata-resolver.ts index 083bf9e1f1c..cf23dea7707 100644 --- a/packages/oauth/oauth-client/src/oauth-authorization-server-metadata-resolver.ts +++ b/packages/oauth/oauth-client/src/oauth-authorization-server-metadata-resolver.ts @@ -14,7 +14,7 @@ import { oauthAuthorizationServerMetadataValidator, oauthIssuerIdentifierSchema, } from '@atproto/oauth-types' -import { contentMime } from './util' +import { contentMime } from './util.js' export type { GetCachedOptions, OAuthAuthorizationServerMetadata } @@ -23,6 +23,10 @@ export type AuthorizationServerMetadataCache = SimpleStore< OAuthAuthorizationServerMetadata > +export type OAuthAuthorizationServerMetadataResolverConfig = { + allowHttpIssuer?: boolean +} + /** * @see {@link https://datatracker.ietf.org/doc/html/rfc8414} */ @@ -31,18 +35,30 @@ export class OAuthAuthorizationServerMetadataResolver extends CachedGetter< OAuthAuthorizationServerMetadata > { private readonly fetch: Fetch + private readonly allowHttpIssuer: boolean - constructor(cache: AuthorizationServerMetadataCache, fetch?: Fetch) { + constructor( + cache: AuthorizationServerMetadataCache, + fetch?: Fetch, + config?: OAuthAuthorizationServerMetadataResolverConfig, + ) { super(async (issuer, options) => this.fetchMetadata(issuer, options), cache) this.fetch = bindFetch(fetch) + this.allowHttpIssuer = config?.allowHttpIssuer === true } async get( - issuer: string, + input: string, options?: GetCachedOptions, ): Promise { - return super.get(oauthIssuerIdentifierSchema.parse(issuer), options) + const issuer = oauthIssuerIdentifierSchema.parse(input) + if (!this.allowHttpIssuer && issuer.startsWith('http:')) { + throw new TypeError( + 'Unsecure issuer URL protocol only allowed in development and test environments', + ) + } + return super.get(issuer, options) } private async fetchMetadata( diff --git a/packages/oauth/oauth-client/src/oauth-client.ts b/packages/oauth/oauth-client/src/oauth-client.ts index 374c53c15ac..06ac645177d 100644 --- a/packages/oauth/oauth-client/src/oauth-client.ts +++ b/packages/oauth/oauth-client/src/oauth-client.ts @@ -2,6 +2,8 @@ import { DidCache, DidResolverCached, DidResolverCommon, + // eslint-disable-next-line @typescript-eslint/no-unused-vars + type DidResolverCommonOptions, } from '@atproto-labs/did-resolver' import { Fetch } from '@atproto-labs/fetch' import { @@ -73,6 +75,21 @@ export type OAuthClientOptions = { responseMode: OAuthResponseMode clientMetadata: Readonly keyset?: Keyset | Iterable + /** + * Determines if the client will allow communicating with the OAuth Servers + * (Authorization & Resource), or to retrieve "did:web" documents, over + * unsafe HTTP connections. It is recommended to set this to `true` only for + * development purposes. + * + * @note This does not affect the identity resolution mechanism, which will + * allow HTTP connections to the PLC Directory (if the provided directory url + * is "http:" based). + * @default false + * @see {@link OAuthProtectedResourceMetadataResolver.allowHttpResource} + * @see {@link OAuthAuthorizationServerMetadataResolver.allowHttpIssuer} + * @see {@link DidResolverCommonOptions.allowHttp} + */ + allowHttp?: boolean // Stores stateStore: StateStore @@ -148,6 +165,7 @@ export class OAuthClient extends CustomEventTarget { constructor({ fetch = globalThis.fetch, + allowHttp = false, stateStore, sessionStore, @@ -186,7 +204,7 @@ export class OAuthClient extends CustomEventTarget { this.oauthResolver = new OAuthResolver( new IdentityResolver( new DidResolverCached( - new DidResolverCommon({ fetch, plcDirectoryUrl }), + new DidResolverCommon({ fetch, plcDirectoryUrl, allowHttp }), didCache, ), new CachedHandleResolver( @@ -197,10 +215,12 @@ export class OAuthClient extends CustomEventTarget { new OAuthProtectedResourceMetadataResolver( protectedResourceMetadataCache, fetch, + { allowHttpResource: allowHttp }, ), new OAuthAuthorizationServerMetadataResolver( authorizationServerMetadataCache, fetch, + { allowHttpIssuer: allowHttp }, ), ) this.serverFactory = new OAuthServerFactory( diff --git a/packages/oauth/oauth-client/src/oauth-protected-resource-metadata-resolver.ts b/packages/oauth/oauth-client/src/oauth-protected-resource-metadata-resolver.ts index c54e2b957eb..26135d60783 100644 --- a/packages/oauth/oauth-client/src/oauth-protected-resource-metadata-resolver.ts +++ b/packages/oauth/oauth-client/src/oauth-protected-resource-metadata-resolver.ts @@ -10,11 +10,10 @@ import { SimpleStore, } from '@atproto-labs/simple-store' import { - ALLOW_UNSECURE_ORIGINS, OAuthProtectedResourceMetadata, oauthProtectedResourceMetadataSchema, } from '@atproto/oauth-types' -import { contentMime } from './util' +import { contentMime } from './util.js' export type { GetCachedOptions, OAuthProtectedResourceMetadata } @@ -23,6 +22,10 @@ export type ProtectedResourceMetadataCache = SimpleStore< OAuthProtectedResourceMetadata > +export type OAuthProtectedResourceMetadataResolverConfig = { + allowHttpResource?: boolean +} + /** * @see {@link https://datatracker.ietf.org/doc/html/draft-ietf-oauth-resource-metadata-05} */ @@ -31,14 +34,17 @@ export class OAuthProtectedResourceMetadataResolver extends CachedGetter< OAuthProtectedResourceMetadata > { private readonly fetch: Fetch + private readonly allowHttpResource: boolean constructor( cache: ProtectedResourceMetadataCache, fetch: Fetch = globalThis.fetch, + config?: OAuthProtectedResourceMetadataResolverConfig, ) { super(async (origin, options) => this.fetchMetadata(origin, options), cache) this.fetch = bindFetch(fetch) + this.allowHttpResource = config?.allowHttpResource === true } async get( @@ -46,14 +52,20 @@ export class OAuthProtectedResourceMetadataResolver extends CachedGetter< options?: GetCachedOptions, ): Promise { const { protocol, origin } = new URL(resource) - if ( - protocol === 'https:' || - (protocol === 'http:' && ALLOW_UNSECURE_ORIGINS) - ) { - return super.get(origin, options) + + if (protocol !== 'https:' && protocol !== 'http:') { + throw new TypeError( + `Invalid protected resource metadata URL protocol: ${protocol}`, + ) + } + + if (protocol === 'http:' && !this.allowHttpResource) { + throw new TypeError( + `Unsecure resource metadata URL (${protocol}) only allowed in development and test environments`, + ) } - throw new TypeError(`Forbidden resource sercure protocol "${protocol}"`) + return super.get(origin, options) } private async fetchMetadata( diff --git a/packages/oauth/oauth-provider/src/metadata/build-metadata.ts b/packages/oauth/oauth-provider/src/metadata/build-metadata.ts index a772a6eb34b..dece6e45af9 100644 --- a/packages/oauth/oauth-provider/src/metadata/build-metadata.ts +++ b/packages/oauth/oauth-provider/src/metadata/build-metadata.ts @@ -1,5 +1,8 @@ import { Keyset } from '@atproto/jwk' -import { OAuthAuthorizationServerMetadata } from '@atproto/oauth-types' +import { + OAuthAuthorizationServerMetadata, + oauthAuthorizationServerMetadataSchema, +} from '@atproto/oauth-types' import { Client } from '../client/client.js' import { VERIFY_ALGOS } from '../lib/util/crypto.js' @@ -19,7 +22,7 @@ export function buildMetadata( keyset: Keyset, customMetadata?: CustomMetadata, ): OAuthAuthorizationServerMetadata { - return { + return oauthAuthorizationServerMetadataSchema.parse({ issuer, scopes_supported: [ @@ -119,5 +122,5 @@ export function buildMetadata( // https://drafts.aaronpk.com/draft-parecki-oauth-client-id-metadata-document/draft-parecki-oauth-client-id-metadata-document.html client_id_metadata_document_supported: true, - } + }) } diff --git a/packages/oauth/oauth-provider/src/request/request-manager.ts b/packages/oauth/oauth-provider/src/request/request-manager.ts index 14c6439feae..3635bf3b727 100644 --- a/packages/oauth/oauth-provider/src/request/request-manager.ts +++ b/packages/oauth/oauth-provider/src/request/request-manager.ts @@ -442,7 +442,10 @@ export class RequestManager { } if (data.clientId !== client.id) { - throw new InvalidGrantError('This code was issued for another client') + // Note: do not reveal the original client ID to the client using an invalid id + throw new InvalidGrantError( + `The code was not issued to client "${client.id}"`, + ) } if (data.expiresAt < new Date()) { diff --git a/packages/oauth/oauth-types/src/constants.ts b/packages/oauth/oauth-types/src/constants.ts index 4635387ccdf..69b1cbc64a7 100644 --- a/packages/oauth/oauth-types/src/constants.ts +++ b/packages/oauth/oauth-types/src/constants.ts @@ -1,18 +1,2 @@ -/** - * A variable that allows to determine if unsecure origins should be allowed - * in OAuth related URI's. This variable is only set to `true` when NODE_ENV - * is either `development` or `test`. - */ -export const ALLOW_UNSECURE_ORIGINS = (() => { - // try/catch to support running in a browser, including when process.env is - // shimmed (e.g. by webpack) - try { - const env = process.env.NODE_ENV - return env === 'development' || env === 'test' - } catch { - return false - } -})() - export const CLIENT_ASSERTION_TYPE_JWT_BEARER = 'urn:ietf:params:oauth:client-assertion-type:jwt-bearer' diff --git a/packages/oauth/oauth-types/src/oauth-issuer-identifier.ts b/packages/oauth/oauth-types/src/oauth-issuer-identifier.ts index 78ff77f4af1..0e99809122e 100644 --- a/packages/oauth/oauth-types/src/oauth-issuer-identifier.ts +++ b/packages/oauth/oauth-types/src/oauth-issuer-identifier.ts @@ -1,10 +1,9 @@ import { z } from 'zod' -import { ALLOW_UNSECURE_ORIGINS } from './constants.js' import { safeUrl } from './util.js' export const oauthIssuerIdentifierSchema = z .string() - .superRefine((value, ctx) => { + .superRefine((value, ctx): value is `${'http' | 'https'}://${string}` => { // Validate the issuer (MIX-UP attacks) if (value.endsWith('/')) { @@ -12,25 +11,24 @@ export const oauthIssuerIdentifierSchema = z code: z.ZodIssueCode.custom, message: 'Issuer URL must not end with a slash', }) + return false } const url = safeUrl(value) if (!url) { - return ctx.addIssue({ + ctx.addIssue({ code: z.ZodIssueCode.custom, message: 'Invalid url', }) + return false } - if (url.protocol !== 'https:') { - if (ALLOW_UNSECURE_ORIGINS && url.protocol === 'http:') { - // We'll allow HTTP in development mode - } else { - ctx.addIssue({ - code: z.ZodIssueCode.custom, - message: 'Issuer must be an HTTPS URL', - }) - } + if (url.protocol !== 'https:' && url.protocol !== 'http:') { + ctx.addIssue({ + code: z.ZodIssueCode.custom, + message: `Invalid issuer URL protocol "${url.protocol}"`, + }) + return false } if (url.username || url.password) { @@ -38,6 +36,7 @@ export const oauthIssuerIdentifierSchema = z code: z.ZodIssueCode.custom, message: 'Issuer URL must not contain a username or password', }) + return false } if (url.hash || url.search) { @@ -45,6 +44,7 @@ export const oauthIssuerIdentifierSchema = z code: z.ZodIssueCode.custom, message: 'Issuer URL must not contain a query or fragment', }) + return false } const canonicalValue = url.pathname === '/' ? url.origin : url.href @@ -53,5 +53,10 @@ export const oauthIssuerIdentifierSchema = z code: z.ZodIssueCode.custom, message: 'Issuer URL must be in the canonical form', }) + return false } + + return true }) + +export type OAuthIssuerIdentifier = z.infer diff --git a/packages/ozone/jest.config.js b/packages/ozone/jest.config.js index 3cf6bcaabe6..8ee383876a5 100644 --- a/packages/ozone/jest.config.js +++ b/packages/ozone/jest.config.js @@ -2,7 +2,9 @@ module.exports = { displayName: 'Ozone', transform: { '^.+\\.(t|j)s$': '@swc/jest' }, - transformIgnorePatterns: [`/node_modules/(?!get-port)`], + transformIgnorePatterns: [ + `/node_modules/.pnpm/(?!(get-port|lande|toygrad)@)`, + ], testTimeout: 60000, setupFiles: ['/../../jest.setup.ts'], } diff --git a/packages/pds/jest.config.js b/packages/pds/jest.config.js index e66657f9546..0b9836b23cd 100644 --- a/packages/pds/jest.config.js +++ b/packages/pds/jest.config.js @@ -2,7 +2,11 @@ module.exports = { displayName: 'PDS', transform: { '^.+\\.(t|j)s$': '@swc/jest' }, - transformIgnorePatterns: [`/node_modules/(?!get-port)`], + // Jest requires all ESM dependencies to be transpiled (even if they are + // dynamically import()ed). + transformIgnorePatterns: [ + `/node_modules/.pnpm/(?!(get-port|lande|toygrad)@)`, + ], testTimeout: 60000, setupFiles: ['/../../jest.setup.ts'], } diff --git a/packages/pds/package.json b/packages/pds/package.json index 55b83399a06..52b509bfe23 100644 --- a/packages/pds/package.json +++ b/packages/pds/package.json @@ -17,6 +17,7 @@ "types": "dist/index.d.ts", "bin": "dist/bin.js", "scripts": { + "postinstall": "puppeteer browsers install chrome", "codegen": "lex gen-server --yes ./src/lexicon ../../lexicons/com/atproto/*/* ../../lexicons/app/bsky/*/* ../../lexicons/chat/bsky/*/* ../../lexicons/tools/ozone/*/*", "build": "tsc --build tsconfig.build.json", "postbuild": "node ./build.templates.js", @@ -73,6 +74,7 @@ "@atproto/api": "workspace:^", "@atproto/bsky": "workspace:^", "@atproto/lex-cli": "workspace:^", + "@atproto/oauth-client-browser-example": "workspace:*", "@atproto/pds-entryway": "npm:@atproto/pds@0.3.0-entryway.3", "@did-plc/server": "^0.0.1", "@types/cors": "^2.8.12", @@ -86,6 +88,7 @@ "esbuild-plugin-handlebars": "^1.0.3", "get-port": "^6.1.2", "jest": "^28.1.2", + "puppeteer": "^23.5.2", "ts-node": "^10.8.2", "typescript": "^5.6.2", "ws": "^8.12.0" diff --git a/packages/pds/tests/oauth.test.ts b/packages/pds/tests/oauth.test.ts new file mode 100644 index 00000000000..3087a6f5265 --- /dev/null +++ b/packages/pds/tests/oauth.test.ts @@ -0,0 +1,152 @@ +import assert from 'node:assert' +import { TestNetworkNoAppView } from '@atproto/dev-env' +// @ts-expect-error (json file) +import files from '@atproto/oauth-client-browser-example' +import { Browser, launch, Page } from 'puppeteer' +import { once } from 'node:events' +import { createServer, Server } from 'node:http' +import { AddressInfo } from 'node:net' + +const getVisibleElement = async (page: Page, selector: string) => { + const elementHandle = await page.waitForSelector(selector) + + expect(elementHandle).not.toBeNull() + assert(elementHandle) + + await expect(elementHandle.isVisible()).resolves.toBe(true) + + return elementHandle +} + +describe('oauth', () => { + let browser: Browser + let network: TestNetworkNoAppView + let server: Server + + let appUrl: string + + beforeAll(async () => { + browser = await launch({ + browser: 'chrome', + + // For debugging: + // headless: false, + // devtools: true, + // slowMo: 250, + }) + + network = await TestNetworkNoAppView.create({ + dbPostgresSchema: 'oauth', + }) + + const sc = network.getSeedClient() + + await sc.createAccount('alice', { + email: 'alice@test.com', + handle: 'alice.test', + password: 'alice-pass', + }) + + server = await createClientServer() + + const { port } = server.address() as AddressInfo + + appUrl = `http://127.0.0.1:${port}?${new URLSearchParams({ + plc_directory_url: network.plc.url, + handle_resolver: network.pds.url, + env: 'test', + })}` + }) + + afterAll(async () => { + await server?.close() + await network?.close() + await browser?.close() + }) + + it('starts', async () => { + const page = await browser.newPage() + + await page.goto(appUrl) + + await expect(page.title()).resolves.toBe('OAuth Client Example') + + const handleInput = await getVisibleElement( + page, + 'input[placeholder="@handle, DID or PDS url"]', + ) + + await handleInput.focus() + + await handleInput.type('alice.test') + + await Promise.all([ + // + handleInput.press('Enter'), + page.waitForNavigation(), + ]) + + await expect(page.title()).resolves.toBe('Authorize') + + const passwordInput = await getVisibleElement( + page, + 'input[type="password"]', + ) + + await passwordInput.focus() + + // Make sure the warning is visible + await getVisibleElement(page, 'p::-p-text(Warning)') + + await passwordInput.type('alice-pass') + + const rememberCheckbox = await getVisibleElement( + page, + 'label::-p-text(Remember this account on this device)', + ) + + await rememberCheckbox.click() + + const nextButton = await getVisibleElement(page, 'button::-p-text(Next)') + + await nextButton.click() + + const acceptButton = await getVisibleElement( + page, + 'button::-p-text(Accept)', + ) + + await Promise.all([ + // + acceptButton.click(), + page.waitForNavigation(), + ]) + + await expect(page.title()).resolves.toBe('OAuth Client Example') + + // Check that the "Logged in!" message is visible + await getVisibleElement(page, 'p::-p-text(Logged in!)') + }) +}) + +async function createClientServer() { + const server = createServer((req, res) => { + const path = req.url?.split('?')[0].slice(1) || 'index.html' + const file = Object.hasOwn(files, path) ? files[path] : null + + if (file) { + res + .writeHead(200, 'OK', { 'content-type': file.type }) + .end(Buffer.from(file.data, 'base64')) + } else { + res + .writeHead(404, 'Not Found', { 'content-type': 'text/plain' }) + .end('Page not found') + } + }) + + server.listen(0) + await once(server, 'listening') + + return server +} diff --git a/packages/pds/tests/proxied/proxy-catchall.test.ts b/packages/pds/tests/proxied/proxy-catchall.test.ts index 64d05769abd..e6726d79813 100644 --- a/packages/pds/tests/proxied/proxy-catchall.test.ts +++ b/packages/pds/tests/proxied/proxy-catchall.test.ts @@ -4,9 +4,9 @@ import { TestNetworkNoAppView } from '@atproto/dev-env' import { LexiconDoc } from '@atproto/lexicon' import * as plc from '@did-plc/lib' import express from 'express' -import getPort from 'get-port' import { once } from 'node:events' import http from 'node:http' +import { AddressInfo } from 'node:net' import { setTimeout as sleep } from 'node:timers/promises' const lexicons = [ @@ -217,11 +217,11 @@ class ProxyServer { res.status(500).json({ error: 'FooBar', message: 'My message' }) }) - const port = await getPort() - const server = app.listen(port) + const server = app.listen(0) server.keepAliveTimeout = 30 * 1000 server.headersTimeout = 35 * 1000 await once(server, 'listening') + const { port } = server.address() as AddressInfo const plcOp = await plc.signOperation( { diff --git a/packages/pds/tests/proxied/proxy-header.test.ts b/packages/pds/tests/proxied/proxy-header.test.ts index 4259225ff0f..1dfdc2aff47 100644 --- a/packages/pds/tests/proxied/proxy-header.test.ts +++ b/packages/pds/tests/proxied/proxy-header.test.ts @@ -4,10 +4,11 @@ import express from 'express' import axios from 'axios' import * as plc from '@did-plc/lib' import { SeedClient, TestNetworkNoAppView, usersSeed } from '@atproto/dev-env' -import getPort from 'get-port' import { Keypair } from '@atproto/crypto' import { verifyJwt } from '@atproto/xrpc-server' import { parseProxyHeader } from '../../src/pipethrough' +import { once } from 'node:events' +import { AddressInfo } from 'node:net' describe('proxy header', () => { let network: TestNetworkNoAppView @@ -167,8 +168,12 @@ class ProxyServer { }) res.sendStatus(200) }) - const port = await getPort() - const server = app.listen(port) + + const server = app.listen(0) + await once(server, 'listening') + + const { port } = server.address() as AddressInfo + const url = `http://localhost:${port}` const plcOp = await plc.signOperation( { diff --git a/packages/sync/jest.config.js b/packages/sync/jest.config.js index b4f3c3d516f..022b62b3158 100644 --- a/packages/sync/jest.config.js +++ b/packages/sync/jest.config.js @@ -1,8 +1,7 @@ /** @type {import('jest').Config} */ module.exports = { displayName: 'Sync', - transform: { '^.+\\.(t|j)s$': '@swc/jest' }, - transformIgnorePatterns: [`/node_modules/(?!get-port)`], + transform: { '^.+\\.ts$': '@swc/jest' }, testTimeout: 60000, setupFiles: ['/../../jest.setup.ts'], } diff --git a/packages/xrpc-server/jest.config.js b/packages/xrpc-server/jest.config.js index 1ecdecded6d..351e8a35a8b 100644 --- a/packages/xrpc-server/jest.config.js +++ b/packages/xrpc-server/jest.config.js @@ -1,7 +1,7 @@ /** @type {import('jest').Config} */ module.exports = { displayName: 'XRPC Server', - transform: { '^.+\\.(t|j)s$': '@swc/jest' }, - transformIgnorePatterns: [`/node_modules/(?!get-port)`], + transform: { '^.+\\.(j|t)s$': '@swc/jest' }, + transformIgnorePatterns: ['/node_modules/.pnpm/(?!(get-port)@)'], setupFiles: ['/../../jest.setup.ts'], } diff --git a/packages/xrpc-server/tests/_util.ts b/packages/xrpc-server/tests/_util.ts index 2b313e5484f..f3bc70be7b1 100644 --- a/packages/xrpc-server/tests/_util.ts +++ b/packages/xrpc-server/tests/_util.ts @@ -1,16 +1,16 @@ -import * as http from 'http' +import * as http from 'node:http' +import { once } from 'node:events' import express from 'express' import * as xrpc from '../src' import { AuthRequiredError } from '../src' -export async function createServer( - port: number, - server: xrpc.Server, -): Promise { +export async function createServer({ + router, +}: xrpc.Server): Promise { const app = express() - app.use(server.router) - const httpServer = app.listen(port) - await new Promise((r) => httpServer.on('listening', r)) + app.use(router) + const httpServer = app.listen(0) + await once(httpServer, 'listening') return httpServer } diff --git a/packages/xrpc-server/tests/auth.test.ts b/packages/xrpc-server/tests/auth.test.ts index 5cbdd579ece..66a561061c4 100644 --- a/packages/xrpc-server/tests/auth.test.ts +++ b/packages/xrpc-server/tests/auth.test.ts @@ -1,6 +1,6 @@ import * as http from 'node:http' import { KeyObject, createPrivateKey } from 'node:crypto' -import getPort from 'get-port' +import { AddressInfo } from 'node:net' import * as jose from 'jose' import KeyEncoder from 'key-encoder' import * as ui8 from 'uint8arrays' @@ -65,8 +65,8 @@ describe('Auth', () => { let client: XrpcClient beforeAll(async () => { - const port = await getPort() - s = await createServer(port, server) + s = await createServer(server) + const { port } = s.address() as AddressInfo client = new XrpcClient(`http://localhost:${port}`, LEXICONS) }) diff --git a/packages/xrpc-server/tests/bodies.test.ts b/packages/xrpc-server/tests/bodies.test.ts index 60fbc2b1cb6..90fcd7c1947 100644 --- a/packages/xrpc-server/tests/bodies.test.ts +++ b/packages/xrpc-server/tests/bodies.test.ts @@ -1,7 +1,7 @@ -import * as http from 'http' -import { Readable } from 'stream' -import { brotliCompressSync, deflateSync, gzipSync } from 'zlib' -import getPort from 'get-port' +import * as http from 'node:http' +import { AddressInfo } from 'node:net' +import { Readable } from 'node:stream' +import { brotliCompressSync, deflateSync, gzipSync } from 'node:zlib' import { LexiconDoc } from '@atproto/lexicon' import { ResponseType, XrpcClient } from '@atproto/xrpc' import { cidForCbor } from '@atproto/common' @@ -153,8 +153,8 @@ describe('Bodies', () => { let client: XrpcClient let url: string beforeAll(async () => { - const port = await getPort() - s = await createServer(port, server) + s = await createServer(server) + const { port } = s.address() as AddressInfo url = `http://localhost:${port}` client = new XrpcClient(url, LEXICONS) }) diff --git a/packages/xrpc-server/tests/errors.test.ts b/packages/xrpc-server/tests/errors.test.ts index 5628147b428..25b0b04e594 100644 --- a/packages/xrpc-server/tests/errors.test.ts +++ b/packages/xrpc-server/tests/errors.test.ts @@ -1,5 +1,5 @@ -import * as http from 'http' -import getPort from 'get-port' +import * as http from 'node:http' +import { AddressInfo } from 'node:net' import { LexiconDoc } from '@atproto/lexicon' import { XRPCError, XRPCInvalidResponseError, XrpcClient } from '@atproto/xrpc' import { createServer, closeServer } from './_util' @@ -129,8 +129,8 @@ describe('Errors', () => { let client: XrpcClient let badClient: XrpcClient beforeAll(async () => { - const port = await getPort() - s = await createServer(port, server) + s = await createServer(server) + const { port } = s.address() as AddressInfo client = new XrpcClient(`http://localhost:${port}`, LEXICONS) badClient = new XrpcClient(`http://localhost:${port}`, MISMATCHED_LEXICONS) }) diff --git a/packages/xrpc-server/tests/ipld.test.ts b/packages/xrpc-server/tests/ipld.test.ts index 7d2c4b4cc53..78e5774861f 100644 --- a/packages/xrpc-server/tests/ipld.test.ts +++ b/packages/xrpc-server/tests/ipld.test.ts @@ -1,8 +1,8 @@ -import * as http from 'http' +import * as http from 'node:http' +import { AddressInfo } from 'node:net' import { LexiconDoc } from '@atproto/lexicon' import { XrpcClient } from '@atproto/xrpc' import { CID } from 'multiformats/cid' -import getPort from 'get-port' import { createServer, closeServer } from './_util' import * as xrpcServer from '../src' @@ -66,8 +66,8 @@ describe('Ipld vals', () => { let client: XrpcClient beforeAll(async () => { - const port = await getPort() - s = await createServer(port, server) + s = await createServer(server) + const { port } = s.address() as AddressInfo client = new XrpcClient(`http://localhost:${port}`, LEXICONS) }) afterAll(async () => { diff --git a/packages/xrpc-server/tests/parameters.test.ts b/packages/xrpc-server/tests/parameters.test.ts index 2767d11da92..2ab1bf1aadd 100644 --- a/packages/xrpc-server/tests/parameters.test.ts +++ b/packages/xrpc-server/tests/parameters.test.ts @@ -1,5 +1,5 @@ -import * as http from 'http' -import getPort from 'get-port' +import * as http from 'node:http' +import { AddressInfo } from 'node:net' import { LexiconDoc } from '@atproto/lexicon' import { XrpcClient } from '@atproto/xrpc' import { createServer, closeServer } from './_util' @@ -44,8 +44,8 @@ describe('Parameters', () => { let client: XrpcClient beforeAll(async () => { - const port = await getPort() - s = await createServer(port, server) + s = await createServer(server) + const { port } = s.address() as AddressInfo client = new XrpcClient(`http://localhost:${port}`, LEXICONS) }) afterAll(async () => { diff --git a/packages/xrpc-server/tests/procedures.test.ts b/packages/xrpc-server/tests/procedures.test.ts index e0130a313d4..195138a1053 100644 --- a/packages/xrpc-server/tests/procedures.test.ts +++ b/packages/xrpc-server/tests/procedures.test.ts @@ -1,10 +1,10 @@ -import * as http from 'http' -import { Readable } from 'stream' +import * as http from 'node:http' +import { Readable } from 'node:stream' import { LexiconDoc } from '@atproto/lexicon' import { XrpcClient } from '@atproto/xrpc' -import getPort from 'get-port' import { createServer, closeServer } from './_util' import * as xrpcServer from '../src' +import { AddressInfo } from 'node:net' const LEXICONS: LexiconDoc[] = [ { @@ -124,8 +124,8 @@ describe('Procedures', () => { let client: XrpcClient beforeAll(async () => { - const port = await getPort() - s = await createServer(port, server) + s = await createServer(server) + const { port } = s.address() as AddressInfo client = new XrpcClient(`http://localhost:${port}`, LEXICONS) }) afterAll(async () => { diff --git a/packages/xrpc-server/tests/queries.test.ts b/packages/xrpc-server/tests/queries.test.ts index 560b4d98a5f..39845f82594 100644 --- a/packages/xrpc-server/tests/queries.test.ts +++ b/packages/xrpc-server/tests/queries.test.ts @@ -1,5 +1,5 @@ -import * as http from 'http' -import getPort from 'get-port' +import * as http from 'node:http' +import { AddressInfo } from 'node:net' import { LexiconDoc } from '@atproto/lexicon' import { XrpcClient } from '@atproto/xrpc' import { createServer, closeServer } from './_util' @@ -92,8 +92,8 @@ describe('Queries', () => { let client: XrpcClient beforeAll(async () => { - const port = await getPort() - s = await createServer(port, server) + s = await createServer(server) + const { port } = s.address() as AddressInfo client = new XrpcClient(`http://localhost:${port}`, LEXICONS) }) afterAll(async () => { diff --git a/packages/xrpc-server/tests/rate-limiter.test.ts b/packages/xrpc-server/tests/rate-limiter.test.ts index b9987492540..08a59d85169 100644 --- a/packages/xrpc-server/tests/rate-limiter.test.ts +++ b/packages/xrpc-server/tests/rate-limiter.test.ts @@ -1,11 +1,11 @@ -import * as http from 'http' -import getPort from 'get-port' +import * as http from 'node:http' +import { AddressInfo } from 'node:net' +import { MINUTE } from '@atproto/common' import { LexiconDoc } from '@atproto/lexicon' import { XrpcClient } from '@atproto/xrpc' -import { createServer, closeServer } from './_util' import * as xrpcServer from '../src' import { RateLimiter } from '../src' -import { MINUTE } from '@atproto/common' +import { closeServer, createServer } from './_util' const LEXICONS: LexiconDoc[] = [ { @@ -192,8 +192,8 @@ describe('Parameters', () => { let client: XrpcClient beforeAll(async () => { - const port = await getPort() - s = await createServer(port, server) + s = await createServer(server) + const { port } = s.address() as AddressInfo client = new XrpcClient(`http://localhost:${port}`, LEXICONS) }) afterAll(async () => { diff --git a/packages/xrpc-server/tests/responses.test.ts b/packages/xrpc-server/tests/responses.test.ts index fbc394e191f..5feb42bc3ed 100644 --- a/packages/xrpc-server/tests/responses.test.ts +++ b/packages/xrpc-server/tests/responses.test.ts @@ -1,5 +1,5 @@ -import * as http from 'http' -import getPort from 'get-port' +import * as http from 'node:http' +import { AddressInfo } from 'node:net' import { LexiconDoc } from '@atproto/lexicon' import { XrpcClient } from '@atproto/xrpc' import { byteIterableToStream } from '@atproto/common' @@ -50,8 +50,8 @@ describe('Responses', () => { let client: XrpcClient beforeAll(async () => { - const port = await getPort() - s = await createServer(port, server) + s = await createServer(server) + const { port } = s.address() as AddressInfo client = new XrpcClient(`http://localhost:${port}`, LEXICONS) }) afterAll(async () => { diff --git a/packages/xrpc-server/tests/subscriptions.test.ts b/packages/xrpc-server/tests/subscriptions.test.ts index e23cef5e3d4..cff7646a802 100644 --- a/packages/xrpc-server/tests/subscriptions.test.ts +++ b/packages/xrpc-server/tests/subscriptions.test.ts @@ -1,4 +1,5 @@ -import * as http from 'http' +import * as http from 'node:http' +import { AddressInfo } from 'node:net' import { WebSocket, WebSocketServer, createWebSocketStream } from 'ws' import getPort from 'get-port' import { wait } from '@atproto/common' @@ -117,11 +118,11 @@ describe('Subscriptions', () => { let port: number beforeAll(async () => { - port = await getPort() - s = await createServer(port, server) + s = await createServer(server) + port = (s.address() as AddressInfo).port }) afterAll(async () => { - await closeServer(s) + if (s) await closeServer(s) }) it('streams messages', async () => { diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index a06265a0b21..a9f82ad7643 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -31,10 +31,10 @@ importers: version: 18.19.50 '@typescript-eslint/eslint-plugin': specifier: ^7.4.0 - version: 7.4.0(@typescript-eslint/parser@7.4.0)(eslint@8.57.0)(typescript@5.6.2) + version: 7.4.0(@typescript-eslint/parser@7.4.0)(eslint@8.57.0)(typescript@5.6.3) '@typescript-eslint/parser': specifier: ^7.4.0 - version: 7.4.0(eslint@8.57.0)(typescript@5.6.2) + version: 7.4.0(eslint@8.57.0)(typescript@5.6.3) dotenv: specifier: ^16.0.3 version: 16.0.3 @@ -64,7 +64,7 @@ importers: version: 7.0.0(prettier@3.2.5) typescript: specifier: ^5.6.2 - version: 5.6.2 + version: 5.6.3 packages/api: dependencies: @@ -96,9 +96,6 @@ importers: '@atproto/lex-cli': specifier: workspace:^ version: link:../lex-cli - get-port: - specifier: ^6.1.2 - version: 6.1.2 jest: specifier: ^28.1.2 version: 28.1.2(@types/node@18.19.50)(ts-node@10.8.2) @@ -107,7 +104,7 @@ importers: version: 3.2.5 typescript: specifier: ^5.6.2 - version: 5.6.2 + version: 5.6.3 packages/aws: dependencies: @@ -147,7 +144,7 @@ importers: devDependencies: typescript: specifier: ^5.6.2 - version: 5.6.2 + version: 5.6.3 packages/bsky: dependencies: @@ -298,10 +295,10 @@ importers: version: 28.1.2(@types/node@18.19.50)(ts-node@10.8.2) ts-node: specifier: ^10.8.2 - version: 10.8.2(@swc/core@1.3.42)(@types/node@18.19.50)(typescript@5.6.2) + version: 10.8.2(@swc/core@1.3.42)(@types/node@18.19.50)(typescript@5.6.3) typescript: specifier: ^5.6.2 - version: 5.6.2 + version: 5.6.3 packages/bsync: dependencies: @@ -356,10 +353,10 @@ importers: version: 28.1.2(@types/node@18.19.50)(ts-node@10.8.2) ts-node: specifier: ^10.8.2 - version: 10.8.2(@swc/core@1.3.42)(@types/node@18.19.50)(typescript@5.6.2) + version: 10.8.2(@swc/core@1.3.42)(@types/node@18.19.50)(typescript@5.6.3) typescript: specifier: ^5.6.2 - version: 5.6.2 + version: 5.6.3 packages/common: dependencies: @@ -387,7 +384,7 @@ importers: version: 28.1.2(@types/node@18.19.50)(ts-node@10.8.2) typescript: specifier: ^5.6.2 - version: 5.6.2 + version: 5.6.3 uint8arrays: specifier: 3.0.0 version: 3.0.0 @@ -412,7 +409,7 @@ importers: version: 28.1.2(@types/node@18.19.50)(ts-node@10.8.2) typescript: specifier: ^5.6.2 - version: 5.6.2 + version: 5.6.3 packages/crypto: dependencies: @@ -434,7 +431,7 @@ importers: version: 28.1.2(@types/node@18.19.50)(ts-node@10.8.2) typescript: specifier: ^5.6.2 - version: 5.6.2 + version: 5.6.3 packages/dev-env: dependencies: @@ -504,7 +501,7 @@ importers: version: 4.17.21 typescript: specifier: ^5.6.2 - version: 5.6.2 + version: 5.6.3 packages/did: dependencies: @@ -514,7 +511,7 @@ importers: devDependencies: typescript: specifier: ^5.6.2 - version: 5.6.2 + version: 5.6.3 packages/identity: dependencies: @@ -548,7 +545,7 @@ importers: version: 28.1.2(@types/node@18.19.50)(ts-node@10.8.2) typescript: specifier: ^5.6.2 - version: 5.6.2 + version: 5.6.3 packages/internal/did-resolver: dependencies: @@ -573,7 +570,7 @@ importers: devDependencies: typescript: specifier: ^5.6.2 - version: 5.6.2 + version: 5.6.3 packages/internal/fetch: dependencies: @@ -587,7 +584,7 @@ importers: devDependencies: typescript: specifier: ^5.6.2 - version: 5.6.2 + version: 5.6.3 packages/internal/fetch-node: dependencies: @@ -612,7 +609,7 @@ importers: version: 1.1.3 typescript: specifier: ^5.6.2 - version: 5.6.2 + version: 5.6.3 packages/internal/handle-resolver: dependencies: @@ -631,7 +628,7 @@ importers: devDependencies: typescript: specifier: ^5.6.2 - version: 5.6.2 + version: 5.6.3 packages/internal/handle-resolver-node: dependencies: @@ -647,7 +644,7 @@ importers: devDependencies: typescript: specifier: ^5.6.2 - version: 5.6.2 + version: 5.6.3 packages/internal/identity-resolver: dependencies: @@ -663,13 +660,13 @@ importers: devDependencies: typescript: specifier: ^5.6.2 - version: 5.6.2 + version: 5.6.3 packages/internal/pipe: devDependencies: typescript: specifier: ^5.6.2 - version: 5.6.2 + version: 5.6.3 packages/internal/rollup-plugin-bundle-manifest: dependencies: @@ -682,13 +679,13 @@ importers: version: 4.18.0 typescript: specifier: ^5.6.2 - version: 5.6.2 + version: 5.6.3 packages/internal/simple-store: devDependencies: typescript: specifier: ^5.6.2 - version: 5.6.2 + version: 5.6.3 packages/internal/simple-store-memory: dependencies: @@ -701,7 +698,7 @@ importers: devDependencies: typescript: specifier: ^5.6.2 - version: 5.6.2 + version: 5.6.3 packages/lex-cli: dependencies: @@ -732,7 +729,7 @@ importers: devDependencies: typescript: specifier: ^5.6.2 - version: 5.6.2 + version: 5.6.3 packages/lexicon: dependencies: @@ -757,7 +754,7 @@ importers: version: 28.1.2(@types/node@18.19.50)(ts-node@10.8.2) typescript: specifier: ^5.6.2 - version: 5.6.2 + version: 5.6.3 packages/oauth/jwk: dependencies: @@ -770,7 +767,7 @@ importers: devDependencies: typescript: specifier: ^5.6.2 - version: 5.6.2 + version: 5.6.3 packages/oauth/jwk-jose: dependencies: @@ -783,7 +780,7 @@ importers: devDependencies: typescript: specifier: ^5.6.2 - version: 5.6.2 + version: 5.6.3 packages/oauth/jwk-webcrypto: dependencies: @@ -796,7 +793,7 @@ importers: devDependencies: typescript: specifier: ^5.6.2 - version: 5.6.2 + version: 5.6.3 packages/oauth/oauth-client: dependencies: @@ -839,7 +836,7 @@ importers: devDependencies: typescript: specifier: ^5.6.2 - version: 5.6.2 + version: 5.6.3 packages/oauth/oauth-client-browser: dependencies: @@ -868,12 +865,27 @@ importers: specifier: workspace:* version: link:../oauth-types devDependencies: + typescript: + specifier: ^5.6.2 + version: 5.6.3 + + packages/oauth/oauth-client-browser-example: + devDependencies: + '@atproto-labs/rollup-plugin-bundle-manifest': + specifier: workspace:* + version: link:../../internal/rollup-plugin-bundle-manifest '@atproto/api': specifier: workspace:* version: link:../../api + '@atproto/oauth-client': + specifier: workspace:* + version: link:../oauth-client '@atproto/oauth-client-browser': specifier: workspace:* - version: 'link:' + version: link:../oauth-client-browser + '@atproto/oauth-types': + specifier: workspace:* + version: link:../oauth-types '@atproto/xrpc': specifier: workspace:* version: link:../../xrpc @@ -881,8 +893,8 @@ importers: specifier: ^25.0.7 version: 25.0.8(rollup@4.18.0) '@rollup/plugin-html': - specifier: ^1.0.3 - version: 1.0.3(rollup@4.18.0) + specifier: ^1.0.4 + version: 1.0.4(rollup@4.18.0) '@rollup/plugin-json': specifier: ^6.1.0 version: 6.1.0(rollup@4.18.0) @@ -897,7 +909,7 @@ importers: version: 0.4.4(rollup@4.18.0) '@rollup/plugin-typescript': specifier: ^11.1.6 - version: 11.1.6(rollup@4.18.0)(typescript@5.6.2) + version: 11.1.6(rollup@4.18.0)(typescript@5.6.3) '@types/react': specifier: ^18.2.50 version: 18.3.2 @@ -929,8 +941,8 @@ importers: specifier: ^3.4.1 version: 3.4.3 typescript: - specifier: ^5.6.2 - version: 5.6.2 + specifier: ^5.6.3 + version: 5.6.3 packages/oauth/oauth-client-node: dependencies: @@ -964,7 +976,7 @@ importers: devDependencies: typescript: specifier: ^5.6.2 - version: 5.6.2 + version: 5.6.3 packages/oauth/oauth-provider: dependencies: @@ -1044,7 +1056,7 @@ importers: version: 0.4.4(rollup@4.18.0) '@rollup/plugin-typescript': specifier: ^11.1.6 - version: 11.1.6(rollup@4.18.0)(typescript@5.6.2) + version: 11.1.6(rollup@4.18.0)(typescript@5.6.3) '@types/cookie': specifier: ^0.6.0 version: 0.6.0 @@ -1089,7 +1101,7 @@ importers: version: 3.4.3 typescript: specifier: ^5.6.2 - version: 5.6.2 + version: 5.6.3 packages/oauth/oauth-types: dependencies: @@ -1102,7 +1114,7 @@ importers: devDependencies: typescript: specifier: ^5.6.2 - version: 5.6.2 + version: 5.6.3 packages/ozone: dependencies: @@ -1205,10 +1217,10 @@ importers: version: 28.1.2(@types/node@18.19.50)(ts-node@10.8.2) ts-node: specifier: ^10.8.2 - version: 10.8.2(@swc/core@1.3.42)(@types/node@18.19.50)(typescript@5.6.2) + version: 10.8.2(@swc/core@1.3.42)(@types/node@18.19.50)(typescript@5.6.3) typescript: specifier: ^5.6.2 - version: 5.6.2 + version: 5.6.3 packages/pds: dependencies: @@ -1336,6 +1348,9 @@ importers: '@atproto/lex-cli': specifier: workspace:^ version: link:../lex-cli + '@atproto/oauth-client-browser-example': + specifier: workspace:* + version: link:../oauth/oauth-client-browser-example '@atproto/pds-entryway': specifier: npm:@atproto/pds@0.3.0-entryway.3 version: /@atproto/pds@0.3.0-entryway.3 @@ -1375,12 +1390,15 @@ importers: jest: specifier: ^28.1.2 version: 28.1.2(@types/node@18.19.50)(ts-node@10.8.2) + puppeteer: + specifier: ^23.5.2 + version: 23.5.3(typescript@5.6.3) ts-node: specifier: ^10.8.2 - version: 10.8.2(@swc/core@1.3.42)(@types/node@18.19.50)(typescript@5.6.2) + version: 10.8.2(@swc/core@1.3.42)(@types/node@18.19.50)(typescript@5.6.3) typescript: specifier: ^5.6.2 - version: 5.6.2 + version: 5.6.3 ws: specifier: ^8.12.0 version: 8.12.0 @@ -1420,7 +1438,7 @@ importers: version: 28.1.2(@types/node@18.19.50)(ts-node@10.8.2) typescript: specifier: ^5.6.2 - version: 5.6.2 + version: 5.6.3 packages/sync: dependencies: @@ -1454,7 +1472,7 @@ importers: version: 28.1.2(@types/node@18.19.50)(ts-node@10.8.2) typescript: specifier: ^5.6.2 - version: 5.6.2 + version: 5.6.3 packages/syntax: devDependencies: @@ -1463,7 +1481,7 @@ importers: version: 28.1.2(@types/node@18.19.50)(ts-node@10.8.2) typescript: specifier: ^5.6.2 - version: 5.6.2 + version: 5.6.3 packages/xrpc: dependencies: @@ -1476,7 +1494,7 @@ importers: devDependencies: typescript: specifier: ^5.6.2 - version: 5.6.2 + version: 5.6.3 packages/xrpc-server: dependencies: @@ -1546,7 +1564,7 @@ importers: version: 9.9.0 typescript: specifier: ^5.6.2 - version: 5.6.2 + version: 5.6.3 services/bsky: dependencies: @@ -5502,6 +5520,23 @@ packages: resolution: {integrity: sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw==} dev: false + /@puppeteer/browsers@2.4.0: + resolution: {integrity: sha512-x8J1csfIygOwf6D6qUAZ0ASk3z63zPb7wkNeHRerCMh82qWKUrOgkuP005AJC8lDL6/evtXETGEJVcwykKT4/g==} + engines: {node: '>=18'} + hasBin: true + dependencies: + debug: 4.3.7 + extract-zip: 2.0.1 + progress: 2.0.3 + proxy-agent: 6.4.0 + semver: 7.6.3 + tar-fs: 3.0.6 + unbzip2-stream: 1.4.3 + yargs: 17.7.2 + transitivePeerDependencies: + - supports-color + dev: true + /@rollup/plugin-commonjs@25.0.8(rollup@4.18.0): resolution: {integrity: sha512-ZEZWTK5n6Qde0to4vS9Mr5x/0UZoqCxPVR9KRUjU4kA2sO7GEUn1fop0DAwpO6z0Nw/kJON9bDmSxdWxO/TT1A==} engines: {node: '>=14.0.0'} @@ -5537,8 +5572,8 @@ packages: rollup: 4.18.0 dev: true - /@rollup/plugin-html@1.0.3(rollup@4.18.0): - resolution: {integrity: sha512-bbjQciNXitHX+Bgk0xsW3/0wFWih/356/r7/kvmdz4wzWhAU/a0zYBWTczihrlzz/6Qpw/kZ0yXqOJwsETgg7A==} + /@rollup/plugin-html@1.0.4(rollup@4.18.0): + resolution: {integrity: sha512-dbxJ8JAuelwdiW7nqeRbe564XPwxX234lsBHrmgVJ+yTL9Nt5zFbZIRcgIIlcTtNNp6M9spK5M+spjcnSExj1w==} engines: {node: '>=14.0.0'} peerDependencies: rollup: ^1.20.0||^2.0.0||^3.0.0||^4.0.0 @@ -5609,7 +5644,7 @@ packages: terser: 5.31.0 dev: true - /@rollup/plugin-typescript@11.1.6(rollup@4.18.0)(typescript@5.6.2): + /@rollup/plugin-typescript@11.1.6(rollup@4.18.0)(typescript@5.6.3): resolution: {integrity: sha512-R92yOmIACgYdJ7dJ97p4K69I8gg6IEHt8M7dUBxN3W6nrO8uUxX5ixl0yU/N3aZTi8WhPuICvOHXQvF6FaykAA==} engines: {node: '>=14.0.0'} peerDependencies: @@ -5625,7 +5660,7 @@ packages: '@rollup/pluginutils': 5.1.0(rollup@4.18.0) resolve: 1.22.4 rollup: 4.18.0 - typescript: 5.6.2 + typescript: 5.6.3 dev: true /@rollup/pluginutils@5.1.0(rollup@4.18.0): @@ -5928,6 +5963,10 @@ packages: engines: {node: '>= 10'} dev: true + /@tootallnate/quickjs-emscripten@0.23.0: + resolution: {integrity: sha512-C5Mc6rdnsaJDjO3UpGW/CQTHtCKaYlScZTly4JIu97Jxo/odCiH0ITnDXSJPTOrEKk/ycSZ0AOgTmkDtkOsvIA==} + dev: true + /@trysound/sax@0.2.0: resolution: {integrity: sha512-L7z9BgrNEcYyUYtF+HaEfiS5ebkh9jXqbszz7pC0hRBPaatV0XjSD3+eHrpqFemQfgwiFF0QPIarnIihIDn7OA==} engines: {node: '>=10.13.0'} @@ -6221,7 +6260,15 @@ packages: '@types/yargs-parser': 21.0.0 dev: true - /@typescript-eslint/eslint-plugin@7.4.0(@typescript-eslint/parser@7.4.0)(eslint@8.57.0)(typescript@5.6.2): + /@types/yauzl@2.10.3: + resolution: {integrity: sha512-oJoftv0LSuaDZE3Le4DbKX+KS9G36NzOeSap90UIK0yMA/NhKJhqlSGtNDORNRaIbQfzjXDrQa0ytJ6mNRGz/Q==} + requiresBuild: true + dependencies: + '@types/node': 18.19.50 + dev: true + optional: true + + /@typescript-eslint/eslint-plugin@7.4.0(@typescript-eslint/parser@7.4.0)(eslint@8.57.0)(typescript@5.6.3): resolution: {integrity: sha512-yHMQ/oFaM7HZdVrVm/M2WHaNPgyuJH4WelkSVEWSSsir34kxW2kDJCxlXRhhGWEsMN0WAW/vLpKfKVcm8k+MPw==} engines: {node: ^18.18.0 || >=20.0.0} peerDependencies: @@ -6233,10 +6280,10 @@ packages: optional: true dependencies: '@eslint-community/regexpp': 4.10.0 - '@typescript-eslint/parser': 7.4.0(eslint@8.57.0)(typescript@5.6.2) + '@typescript-eslint/parser': 7.4.0(eslint@8.57.0)(typescript@5.6.3) '@typescript-eslint/scope-manager': 7.4.0 - '@typescript-eslint/type-utils': 7.4.0(eslint@8.57.0)(typescript@5.6.2) - '@typescript-eslint/utils': 7.4.0(eslint@8.57.0)(typescript@5.6.2) + '@typescript-eslint/type-utils': 7.4.0(eslint@8.57.0)(typescript@5.6.3) + '@typescript-eslint/utils': 7.4.0(eslint@8.57.0)(typescript@5.6.3) '@typescript-eslint/visitor-keys': 7.4.0 debug: 4.3.4 eslint: 8.57.0 @@ -6244,13 +6291,13 @@ packages: ignore: 5.2.4 natural-compare: 1.4.0 semver: 7.5.4 - ts-api-utils: 1.0.3(typescript@5.6.2) - typescript: 5.6.2 + ts-api-utils: 1.0.3(typescript@5.6.3) + typescript: 5.6.3 transitivePeerDependencies: - supports-color dev: true - /@typescript-eslint/parser@7.4.0(eslint@8.57.0)(typescript@5.6.2): + /@typescript-eslint/parser@7.4.0(eslint@8.57.0)(typescript@5.6.3): resolution: {integrity: sha512-ZvKHxHLusweEUVwrGRXXUVzFgnWhigo4JurEj0dGF1tbcGh6buL+ejDdjxOQxv6ytcY1uhun1p2sm8iWStlgLQ==} engines: {node: ^18.18.0 || >=20.0.0} peerDependencies: @@ -6262,11 +6309,11 @@ packages: dependencies: '@typescript-eslint/scope-manager': 7.4.0 '@typescript-eslint/types': 7.4.0 - '@typescript-eslint/typescript-estree': 7.4.0(typescript@5.6.2) + '@typescript-eslint/typescript-estree': 7.4.0(typescript@5.6.3) '@typescript-eslint/visitor-keys': 7.4.0 debug: 4.3.4 eslint: 8.57.0 - typescript: 5.6.2 + typescript: 5.6.3 transitivePeerDependencies: - supports-color dev: true @@ -6279,7 +6326,7 @@ packages: '@typescript-eslint/visitor-keys': 7.4.0 dev: true - /@typescript-eslint/type-utils@7.4.0(eslint@8.57.0)(typescript@5.6.2): + /@typescript-eslint/type-utils@7.4.0(eslint@8.57.0)(typescript@5.6.3): resolution: {integrity: sha512-247ETeHgr9WTRMqHbbQdzwzhuyaJ8dPTuyuUEMANqzMRB1rj/9qFIuIXK7l0FX9i9FXbHeBQl/4uz6mYuCE7Aw==} engines: {node: ^18.18.0 || >=20.0.0} peerDependencies: @@ -6289,12 +6336,12 @@ packages: typescript: optional: true dependencies: - '@typescript-eslint/typescript-estree': 7.4.0(typescript@5.6.2) - '@typescript-eslint/utils': 7.4.0(eslint@8.57.0)(typescript@5.6.2) + '@typescript-eslint/typescript-estree': 7.4.0(typescript@5.6.3) + '@typescript-eslint/utils': 7.4.0(eslint@8.57.0)(typescript@5.6.3) debug: 4.3.4 eslint: 8.57.0 - ts-api-utils: 1.0.3(typescript@5.6.2) - typescript: 5.6.2 + ts-api-utils: 1.0.3(typescript@5.6.3) + typescript: 5.6.3 transitivePeerDependencies: - supports-color dev: true @@ -6304,7 +6351,7 @@ packages: engines: {node: ^18.18.0 || >=20.0.0} dev: true - /@typescript-eslint/typescript-estree@7.4.0(typescript@5.6.2): + /@typescript-eslint/typescript-estree@7.4.0(typescript@5.6.3): resolution: {integrity: sha512-A99j5AYoME/UBQ1ucEbbMEmGkN7SE0BvZFreSnTd1luq7yulcHdyGamZKizU7canpGDWGJ+Q6ZA9SyQobipePg==} engines: {node: ^18.18.0 || >=20.0.0} peerDependencies: @@ -6320,13 +6367,13 @@ packages: is-glob: 4.0.3 minimatch: 9.0.3 semver: 7.5.4 - ts-api-utils: 1.0.3(typescript@5.6.2) - typescript: 5.6.2 + ts-api-utils: 1.0.3(typescript@5.6.3) + typescript: 5.6.3 transitivePeerDependencies: - supports-color dev: true - /@typescript-eslint/utils@7.4.0(eslint@8.57.0)(typescript@5.6.2): + /@typescript-eslint/utils@7.4.0(eslint@8.57.0)(typescript@5.6.3): resolution: {integrity: sha512-NQt9QLM4Tt8qrlBVY9lkMYzfYtNz8/6qwZg8pI3cMGlPnj6mOpRxxAm7BMJN9K0AiY+1BwJ5lVC650YJqYOuNg==} engines: {node: ^18.18.0 || >=20.0.0} peerDependencies: @@ -6337,7 +6384,7 @@ packages: '@types/semver': 7.5.0 '@typescript-eslint/scope-manager': 7.4.0 '@typescript-eslint/types': 7.4.0 - '@typescript-eslint/typescript-estree': 7.4.0(typescript@5.6.2) + '@typescript-eslint/typescript-estree': 7.4.0(typescript@5.6.3) eslint: 8.57.0 semver: 7.5.4 transitivePeerDependencies: @@ -6430,6 +6477,15 @@ packages: - supports-color dev: true + /agent-base@7.1.1: + resolution: {integrity: sha512-H0TSyFNDMomMNJQBn8wFV5YC/2eJ+VXECwOadZJT554xP6cODZHPX3H9QMQECxvrgiSOP1pHjy1sMWQVYJOUOA==} + engines: {node: '>= 14'} + dependencies: + debug: 4.3.7 + transitivePeerDependencies: + - supports-color + dev: true + /agentkeepalive@4.5.0: resolution: {integrity: sha512-5GG/5IbQQpC9FpkRGsSvZI5QYeSCzlJHdpBQntCsuTOxhKD8lqKhrleg2Yi7yvMIf82Ycmmqln9U8V9qwEiJew==} engines: {node: '>= 8.0.0'} @@ -6606,6 +6662,13 @@ packages: minimalistic-assert: 1.0.1 safer-buffer: 2.1.2 + /ast-types@0.13.4: + resolution: {integrity: sha512-x1FCFnFifvYDDzTaLII71vG5uvDwgtmDTEVWAxrgeiR8VjMONcCXJx7E+USjDtHlwFmt9MysbqgF9b9Vjr6w+w==} + engines: {node: '>=4'} + dependencies: + tslib: 2.6.2 + dev: true + /astring@1.8.6: resolution: {integrity: sha512-ISvCdHdlTDlH5IpxQJIex7BWBywFWgjJSVdwst+/iQCoEYnyOaQ95+X1JGshuBjGp6nxKUy1jMgE3zPqN7fQdg==} hasBin: true @@ -6629,7 +6692,7 @@ packages: caniuse-lite: 1.0.30001621 fraction.js: 4.3.7 normalize-range: 0.1.2 - picocolors: 1.0.0 + picocolors: 1.0.1 postcss: 8.4.38 postcss-value-parser: 4.2.0 dev: true @@ -6681,6 +6744,12 @@ packages: /b4a@1.6.4: resolution: {integrity: sha512-fpWrvyVHEKyeEvbKZTVOeZF3VSKKWtJxFIxX/jaVPf+cLbGUSitjb49pHLqPV2BUNNZ0LcoeEGfE/YCpyDYHIw==} + /b4a@1.6.7: + resolution: {integrity: sha512-OnAYlL5b7LEkALw87fUVafQw5rVR9RjwGd4KUwNQ6DrrNmaVaUCgLipfVlzrPQ4tWOR9P0IXGNOx50jYCCdSJg==} + requiresBuild: true + dev: true + optional: true + /babel-jest@28.1.3(@babel/core@7.18.6): resolution: {integrity: sha512-epUaPOEWMk3cWX0M/sPvCHHCe9fMFAa/9hXEgKP8nFfNl/jlGkE9ucq9NqkZGXLDduCJYS0UvSlPUwC0S+rH6Q==} engines: {node: ^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0} @@ -6756,9 +6825,53 @@ packages: /balanced-match@1.0.2: resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} + /bare-events@2.5.0: + resolution: {integrity: sha512-/E8dDe9dsbLyh2qrZ64PEPadOQ0F4gbl1sUJOrmph7xOiIxfY8vwab/4bFLh4Y88/Hk/ujKcrQKc+ps0mv873A==} + requiresBuild: true + dev: true + optional: true + + /bare-fs@2.3.5: + resolution: {integrity: sha512-SlE9eTxifPDJrT6YgemQ1WGFleevzwY+XAP1Xqgl56HtcrisC2CHCZ2tq6dBpcH2TnNxwUEUGhweo+lrQtYuiw==} + requiresBuild: true + dependencies: + bare-events: 2.5.0 + bare-path: 2.1.3 + bare-stream: 2.3.0 + dev: true + optional: true + + /bare-os@2.4.4: + resolution: {integrity: sha512-z3UiI2yi1mK0sXeRdc4O1Kk8aOa/e+FNWZcTiPB/dfTWyLypuE99LibgRaQki914Jq//yAWylcAt+mknKdixRQ==} + requiresBuild: true + dev: true + optional: true + + /bare-path@2.1.3: + resolution: {integrity: sha512-lh/eITfU8hrj9Ru5quUp0Io1kJWIk1bTjzo7JH1P5dWmQ2EL4hFUlfI8FonAhSlgIfhn63p84CDY/x+PisgcXA==} + requiresBuild: true + dependencies: + bare-os: 2.4.4 + dev: true + optional: true + + /bare-stream@2.3.0: + resolution: {integrity: sha512-pVRWciewGUeCyKEuRxwv06M079r+fRjAQjBEK2P6OYGrO43O+Z0LrPZZEjlc4mB6C2RpZ9AxJ1s7NLEtOHO6eA==} + requiresBuild: true + dependencies: + b4a: 1.6.7 + streamx: 2.20.1 + dev: true + optional: true + /base64-js@1.5.1: resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==} + /basic-ftp@5.0.5: + resolution: {integrity: sha512-4Bcg1P8xhUuqcii/S0Z9wiHIrQVPMermM1any+MX5GeGD7faD3/msQUDGLol9wOcz4/jbg/WJnGqoJF6LiBdtg==} + engines: {node: '>=10.0.0'} + dev: true + /better-path-resolve@1.0.0: resolution: {integrity: sha512-pbnl5XzGBdrFU/wT4jqmJVPn2B6UHPBOhzMQkY/SPUPB6QtUXtmBHBIwCbXJol93mOpGMnQyP/+BB19q04xj7g==} engines: {node: '>=4'} @@ -6890,6 +7003,10 @@ packages: node-int64: 0.4.0 dev: true + /buffer-crc32@0.2.13: + resolution: {integrity: sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==} + dev: true + /buffer-equal-constant-time@1.0.1: resolution: {integrity: sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==} dev: true @@ -7086,6 +7203,17 @@ packages: engines: {node: '>=10'} dev: true + /chromium-bidi@0.8.0(devtools-protocol@0.0.1342118): + resolution: {integrity: sha512-uJydbGdTw0DEUjhoogGveneJVWX/9YuqkWePzMmkBYwtdAqo5d3J/ovNKFr+/2hWXYmYCr6it8mSSTIj6SS6Ug==} + peerDependencies: + devtools-protocol: '*' + dependencies: + devtools-protocol: 0.0.1342118 + mitt: 3.0.1 + urlpattern-polyfill: 10.0.0 + zod: 3.23.8 + dev: true + /ci-info@3.8.0: resolution: {integrity: sha512-eXTggHWSooYhq49F2opQhuHWgzucfF2YgODK4e1566GQs5BIfP30B0oenwBJHfWxAs2fyPB1s7Mg949zLf61Yw==} engines: {node: '>=8'} @@ -7279,6 +7407,22 @@ packages: object-assign: 4.1.1 vary: 1.1.2 + /cosmiconfig@9.0.0(typescript@5.6.3): + resolution: {integrity: sha512-itvL5h8RETACmOTFc4UfIyB2RfEHi71Ax6E/PivVxq9NseKbOWpeyHEOIbmAw1rs8Ak0VursQNww7lf7YtUwzg==} + engines: {node: '>=14'} + peerDependencies: + typescript: '>=4.9.5' + peerDependenciesMeta: + typescript: + optional: true + dependencies: + env-paths: 2.2.1 + import-fresh: 3.3.0 + js-yaml: 4.1.0 + parse-json: 5.2.0 + typescript: 5.6.3 + dev: true + /create-require@1.1.1: resolution: {integrity: sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==} dev: true @@ -7433,6 +7577,11 @@ packages: stream-transform: 2.1.3 dev: true + /data-uri-to-buffer@6.0.2: + resolution: {integrity: sha512-7hvf7/GW8e86rW0ptuwS3OcBGDjIi6SZva7hCyWC0yYry2cOPmLIjXAUHI6DK2HsnwJd9ifmt57i8eV2n4YNpw==} + engines: {node: '>= 14'} + dev: true + /dataloader@1.4.0: resolution: {integrity: sha512-68s5jYdlvasItOJnCuI2Q9s4q98g0pCyL3HrcKJu8KNugUl8ahgmZYg38ysLTgQjjXX3H8CJLkAvWrclWfcalw==} dev: true @@ -7545,6 +7694,18 @@ packages: dependencies: ms: 2.1.2 + /debug@4.3.7: + resolution: {integrity: sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==} + engines: {node: '>=6.0'} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + dependencies: + ms: 2.1.3 + dev: true + /decamelize-keys@1.1.1: resolution: {integrity: sha512-WiPxgEirIV0/eIOMcnFBA3/IJZAZqKnwAwWyvvdi4lsr1WCN22nhdf/3db3DoZcUjTV2SqfzIwNyp6y2xs3nmg==} engines: {node: '>=0.10.0'} @@ -7593,6 +7754,15 @@ packages: has-property-descriptors: 1.0.0 object-keys: 1.1.1 + /degenerator@5.0.1: + resolution: {integrity: sha512-TllpMR/t0M5sqCXfj85i4XaAzxmS5tVA16dqvdkMwGmzI+dXLXnw3J+3Vdv7VKw+ThlTMboK6i9rnZ6Nntj5CQ==} + engines: {node: '>= 14'} + dependencies: + ast-types: 0.13.4 + escodegen: 2.1.0 + esprima: 4.0.1 + dev: true + /delay@5.0.0: resolution: {integrity: sha512-ReEBKkIfe4ya47wlPYf/gu5ib6yUG0/Aez0JQZQz94kiWtRQvZIQbTiehsnwHvLSWJnQdhVeqYue7Id1dKr0qw==} engines: {node: '>=10'} @@ -7634,6 +7804,10 @@ packages: resolution: {integrity: sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==} engines: {node: '>=8'} + /devtools-protocol@0.0.1342118: + resolution: {integrity: sha512-75fMas7PkYNDTmDyb6PRJCH7ILmHLp+BhrZGeMsa4bCh40DTxgCz2NRy5UDzII4C5KuD0oBMZ9vXKhEl6UD/3w==} + dev: true + /diagnostics_channel@1.1.0: resolution: {integrity: sha512-OE1ngLDjSBPG6Tx0YATELzYzy3RKHC+7veQ8gLa8yS7AAgw65mFbVdcsu3501abqOZCEZqZyAIemB0zXlqDSuw==} engines: {node: '>=4'} @@ -8097,6 +8271,18 @@ packages: engines: {node: '>=10'} dev: true + /escodegen@2.1.0: + resolution: {integrity: sha512-2NlIDTwUWJN0mRPQOdtQBzbUHvdGY2P1VXSyU83Q3xKxM7WHX2Ql8dKq782Q9TgQUNOLEzEYu9bzLNj1q88I5w==} + engines: {node: '>=6.0'} + hasBin: true + dependencies: + esprima: 4.0.1 + estraverse: 5.3.0 + esutils: 2.0.3 + optionalDependencies: + source-map: 0.6.1 + dev: true + /eslint-config-prettier@9.1.0(eslint@8.57.0): resolution: {integrity: sha512-NSWl5BFQWEPi1j4TjVNItzYV7dZXZ+wP6I6ZhrBGpChQhZRUaElihE9uRRkcbRnNb76UMKDF3r+WTmNcGPKsqw==} hasBin: true @@ -8346,6 +8532,20 @@ packages: tmp: 0.0.33 dev: true + /extract-zip@2.0.1: + resolution: {integrity: sha512-GDhU9ntwuKyGXdZBUgTIe+vXnWj0fppUEtMDL0+idd5Sta8TGpHssn/eusA9mrPr9qNDym6SxAYZjNvCn/9RBg==} + engines: {node: '>= 10.17.0'} + hasBin: true + dependencies: + debug: 4.3.7 + get-stream: 5.2.0 + yauzl: 2.10.0 + optionalDependencies: + '@types/yauzl': 2.10.3 + transitivePeerDependencies: + - supports-color + dev: true + /fast-copy@2.1.7: resolution: {integrity: sha512-ozrGwyuCTAy7YgFCua8rmqmytECYk/JYAMXcswOcm0qvGoE3tPb7ivBeIHTOK2DiapBhDZgacIhzhQIKU5TCfA==} dev: true @@ -8423,6 +8623,12 @@ packages: bser: 2.1.1 dev: true + /fd-slicer@1.1.0: + resolution: {integrity: sha512-cE1qsB/VwyQozZ+q1dGxR8LBYNZeofhEdUNGSMbQD3Gw2lAzX9Zb3uIU6Ebc/Fmyjo9AWWfnn0AUCHqtevs/8g==} + dependencies: + pend: 1.2.0 + dev: true + /file-entry-cache@6.0.1: resolution: {integrity: sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==} engines: {node: ^10.12.0 || >=12.0.0} @@ -8564,6 +8770,15 @@ packages: /fs-constants@1.0.0: resolution: {integrity: sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==} + /fs-extra@11.2.0: + resolution: {integrity: sha512-PmDi3uwK5nFuXh7XDTlVnS17xJS7vW36is2+w3xcv8SVxiB4NyATf4ctkVY5bkSjX0Y4nbvZCq1/EjtEyr9ktw==} + engines: {node: '>=14.14'} + dependencies: + graceful-fs: 4.2.11 + jsonfile: 6.1.0 + universalify: 2.0.1 + dev: true + /fs-extra@7.0.1: resolution: {integrity: sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw==} engines: {node: '>=6 <7 || >=8'} @@ -8669,6 +8884,13 @@ packages: engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} dev: true + /get-stream@5.2.0: + resolution: {integrity: sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==} + engines: {node: '>=8'} + dependencies: + pump: 3.0.0 + dev: true + /get-stream@6.0.1: resolution: {integrity: sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==} engines: {node: '>=10'} @@ -8682,6 +8904,18 @@ packages: get-intrinsic: 1.2.1 dev: true + /get-uri@6.0.3: + resolution: {integrity: sha512-BzUrJBS9EcUb4cFol8r4W3v1cPsSyajLSthNkz5BxbpDcHN5tIrM10E2eNvfnvBn3DaT3DUgx0OpsBKkaOpanw==} + engines: {node: '>= 14'} + dependencies: + basic-ftp: 5.0.5 + data-uri-to-buffer: 6.0.2 + debug: 4.3.7 + fs-extra: 11.2.0 + transitivePeerDependencies: + - supports-color + dev: true + /github-from-package@0.0.0: resolution: {integrity: sha512-SyHy3T1v2NUXn29OsWdxmK6RwHD+vkj3v8en8AOBZ1wBQ/hCAQ5bAQTD02kW4W9tUp/3Qh6J8r9EvntiyCmOOw==} @@ -8939,6 +9173,16 @@ packages: - supports-color dev: true + /http-proxy-agent@7.0.2: + resolution: {integrity: sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==} + engines: {node: '>= 14'} + dependencies: + agent-base: 7.1.1 + debug: 4.3.7 + transitivePeerDependencies: + - supports-color + dev: true + /http-terminator@3.2.0: resolution: {integrity: sha512-JLjck1EzPaWjsmIf8bziM3p9fgR1Y3JoUKAkyYEbZmFrIvJM6I8vVJfBGWlEtV9IWOvzNnaTtjuwZeBY2kwB4g==} engines: {node: '>=14'} @@ -8958,6 +9202,16 @@ packages: - supports-color dev: true + /https-proxy-agent@7.0.5: + resolution: {integrity: sha512-1e4Wqeblerz+tMKPIq2EMGiiWW1dIjZOksyHWSUm1rmuvw/how9hBHZ38lAGj5ID4Ik6EdkOw7NmWPy6LAwalw==} + engines: {node: '>= 14'} + dependencies: + agent-base: 7.1.1 + debug: 4.3.7 + transitivePeerDependencies: + - supports-color + dev: true + /human-id@1.0.2: resolution: {integrity: sha512-UNopramDEhHJD+VR+ehk8rOslwSfByxPIZyJRfV739NDhN5LF1fa1MqnzKm2lGTQRjNrjK19Q5fhkgIfjlVUKw==} dev: true @@ -9104,6 +9358,14 @@ packages: transitivePeerDependencies: - supports-color + /ip-address@9.0.5: + resolution: {integrity: sha512-zHtQzGojZXTwZTHQqra+ETKd4Sn3vgi7uBmlPoXVWZqYvuKmtI0l/VZTjqGmJY9x88GGOaZ9+G9ES8hC4T4X8g==} + engines: {node: '>= 12'} + dependencies: + jsbn: 1.1.0 + sprintf-js: 1.1.3 + dev: true + /ip3country@5.0.0: resolution: {integrity: sha512-lcFLMFU4eO1Z7tIpbVFZkaZ5ltqpeaRx7L9NsAbA9uA7/O/rj3RF8+evE5gDitooaTTIqjdzZrenFO/OOxQ2ew==} dev: false @@ -9471,7 +9733,7 @@ packages: pretty-format: 28.1.3 slash: 3.0.0 strip-json-comments: 3.1.1 - ts-node: 10.8.2(@swc/core@1.3.42)(@types/node@18.19.50)(typescript@5.6.2) + ts-node: 10.8.2(@swc/core@1.3.42)(@types/node@18.19.50)(typescript@5.6.3) transitivePeerDependencies: - supports-color dev: true @@ -9828,6 +10090,10 @@ packages: argparse: 2.0.1 dev: true + /jsbn@1.1.0: + resolution: {integrity: sha512-4bYVV3aAMtDTTu4+xsDYa6sy9GyJ69/amsu9sYF2zqjiEoZA5xJi3BrfX3uY+/IekIu7MwdObdbDWpoZdBv3/A==} + dev: true + /jsesc@2.5.2: resolution: {integrity: sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==} engines: {node: '>=4'} @@ -9865,6 +10131,14 @@ packages: graceful-fs: 4.2.11 dev: true + /jsonfile@6.1.0: + resolution: {integrity: sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==} + dependencies: + universalify: 2.0.1 + optionalDependencies: + graceful-fs: 4.2.11 + dev: true + /jsonwebtoken@9.0.2: resolution: {integrity: sha512-PRp66vJ865SSqOlgqS8hujT5U4AOgMfhrwYIuIhfKaoSCZcirrmASQr8CX7cUg+RMih+hgznrjp99o+W4pJLHQ==} engines: {node: '>=12', npm: '>=6'} @@ -10350,6 +10624,10 @@ packages: yallist: 4.0.0 dev: true + /mitt@3.0.1: + resolution: {integrity: sha512-vKivATfr97l2/QBCYAkXYDbrIWPM2IIKEl7YPhjCvKlG3kE2gm+uBo6nEXK3M5/Ffh/FLpKExzOQ3JJoJGFKBw==} + dev: true + /mixme@0.5.9: resolution: {integrity: sha512-VC5fg6ySUscaWUpI4gxCBTQMH2RdUpNrk+MsbpCYtIvf9SBJdiUey4qE7BXviJsJR4nDQxCZ+3yaYNW3guz/Pw==} engines: {node: '>= 8.0.0'} @@ -10421,6 +10699,11 @@ packages: /neo-async@2.6.2: resolution: {integrity: sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==} + /netmask@2.0.2: + resolution: {integrity: sha512-dBpDMdxv9Irdq66304OLfEmQ9tbNRFnFTuZiLo+bD+r332bBmMJ8GBLXklIXXgxd3+v9+KUnZaUR5PJMa75Gsg==} + engines: {node: '>= 0.4.0'} + dev: true + /node-abi@3.47.0: resolution: {integrity: sha512-2s6B2CWZM//kPgwnuI0KrYwNjfdByE25zvAaEpq9IH4zcNsarH8Ihu/UuX6XMPEogDAxkuUFeZn60pXNHAqn3A==} engines: {node: '>=10'} @@ -10740,6 +11023,30 @@ packages: dependencies: p-timeout: 3.2.0 + /pac-proxy-agent@7.0.2: + resolution: {integrity: sha512-BFi3vZnO9X5Qt6NRz7ZOaPja3ic0PhlsmCRYLOpN11+mWBCR6XJDqW5RF3j8jm4WGGQZtBA+bTfxYzeKW73eHg==} + engines: {node: '>= 14'} + dependencies: + '@tootallnate/quickjs-emscripten': 0.23.0 + agent-base: 7.1.1 + debug: 4.3.7 + get-uri: 6.0.3 + http-proxy-agent: 7.0.2 + https-proxy-agent: 7.0.5 + pac-resolver: 7.0.1 + socks-proxy-agent: 8.0.4 + transitivePeerDependencies: + - supports-color + dev: true + + /pac-resolver@7.0.1: + resolution: {integrity: sha512-5NPgf87AT2STgwa2ntRMr45jTKrYBGkVU36yT0ig/n/GMAa3oPqhZfIQ2kMEimReg0+t9kZViDVZ83qfVUlckg==} + engines: {node: '>= 14'} + dependencies: + degenerator: 5.0.1 + netmask: 2.0.2 + dev: true + /packet-reader@1.0.0: resolution: {integrity: sha512-HAKu/fG3HpHFO0AA8WE8q2g+gBJaZ9MG7fcKk+IJPLTGAD6Psw4443l+9DGRbOIh3/aXr7Phy0TjilYivJo5XQ==} @@ -10804,6 +11111,10 @@ packages: resolution: {integrity: sha512-ZI3LnwUv5nOGbQzD9c2iDG6toheuXSZP5esSHBjopsXH4dg19soufvpUGA3uohi5anFtGb2lhAVdHzH6R/Evvg==} engines: {node: '>=8'} + /pend@1.2.0: + resolution: {integrity: sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==} + dev: true + /pg-connection-string@2.6.2: resolution: {integrity: sha512-ch6OwaeaPYcova4kKZ15sbJ2hKb/VP48ZD2gE7i1J+L4MspCtBMAx8nMgz7bksc7IojCIIWuEhHibSMFH8m8oA==} @@ -10980,7 +11291,7 @@ packages: peerDependencies: postcss: ^8.2.15 dependencies: - browserslist: 4.21.10 + browserslist: 4.23.0 postcss: 8.4.38 postcss-value-parser: 4.2.0 dev: true @@ -11373,7 +11684,7 @@ packages: engines: {node: ^10 || ^12 || >=14} dependencies: nanoid: 3.3.7 - picocolors: 1.0.0 + picocolors: 1.0.1 source-map-js: 1.2.0 dev: true @@ -11493,6 +11804,11 @@ packages: resolution: {integrity: sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==} engines: {node: '>= 0.6.0'} + /progress@2.0.3: + resolution: {integrity: sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==} + engines: {node: '>=0.4.0'} + dev: true + /promise-inflight@1.0.1: resolution: {integrity: sha512-6zWPyEOFaQBJYcGMHBKTKJ3u6TBsnMFOIZSa6ce1e/ZrrsOlnHRHbabMjLiBYKp+n44X9eUI6VUPaukCXHuG4g==} peerDependencies: @@ -11549,6 +11865,22 @@ packages: forwarded: 0.2.0 ipaddr.js: 1.9.1 + /proxy-agent@6.4.0: + resolution: {integrity: sha512-u0piLU+nCOHMgGjRbimiXmA9kM/L9EHh3zL81xCdp7m+Y2pHIsnmbdDoEDoAz5geaonNR6q6+yOPQs6n4T6sBQ==} + engines: {node: '>= 14'} + dependencies: + agent-base: 7.1.1 + debug: 4.3.7 + http-proxy-agent: 7.0.2 + https-proxy-agent: 7.0.5 + lru-cache: 7.18.3 + pac-proxy-agent: 7.0.2 + proxy-from-env: 1.1.0 + socks-proxy-agent: 8.0.4 + transitivePeerDependencies: + - supports-color + dev: true + /proxy-from-env@1.1.0: resolution: {integrity: sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==} @@ -11570,6 +11902,41 @@ packages: resolution: {integrity: sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==} engines: {node: '>=6'} + /puppeteer-core@23.5.3: + resolution: {integrity: sha512-V58MZD/B3CwkYsqSEQlHKbavMJptF04fzhMdUpiCRCmUVhwZNwSGEPhaiZ1f8I3ABQUirg3VNhXVB6Z1ubHXtQ==} + engines: {node: '>=18'} + dependencies: + '@puppeteer/browsers': 2.4.0 + chromium-bidi: 0.8.0(devtools-protocol@0.0.1342118) + debug: 4.3.7 + devtools-protocol: 0.0.1342118 + typed-query-selector: 2.12.0 + ws: 8.18.0 + transitivePeerDependencies: + - bufferutil + - supports-color + - utf-8-validate + dev: true + + /puppeteer@23.5.3(typescript@5.6.3): + resolution: {integrity: sha512-FghmfBsr/UUpe48OiCg1gV3W4vVfQJKjQehbF07SjnQvEpWcvPTah1nykfGWdOQQ1ydJPIXcajzWN7fliCU3zw==} + engines: {node: '>=18'} + hasBin: true + requiresBuild: true + dependencies: + '@puppeteer/browsers': 2.4.0 + chromium-bidi: 0.8.0(devtools-protocol@0.0.1342118) + cosmiconfig: 9.0.0(typescript@5.6.3) + devtools-protocol: 0.0.1342118 + puppeteer-core: 23.5.3 + typed-query-selector: 2.12.0 + transitivePeerDependencies: + - bufferutil + - supports-color + - typescript + - utf-8-validate + dev: true + /qs@6.11.0: resolution: {integrity: sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==} engines: {node: '>=0.6'} @@ -11996,6 +12363,12 @@ packages: dependencies: lru-cache: 6.0.0 + /semver@7.6.3: + resolution: {integrity: sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==} + engines: {node: '>=10'} + hasBin: true + dev: true + /send@0.18.0: resolution: {integrity: sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==} engines: {node: '>= 0.8.0'} @@ -12157,6 +12530,17 @@ packages: - supports-color dev: true + /socks-proxy-agent@8.0.4: + resolution: {integrity: sha512-GNAq/eg8Udq2x0eNiFkr9gRg5bA7PXEWagQdeRX4cPSG+X/8V38v637gim9bjFptMk1QWsCTr0ttrJEiXbNnRw==} + engines: {node: '>= 14'} + dependencies: + agent-base: 7.1.1 + debug: 4.3.7 + socks: 2.8.3 + transitivePeerDependencies: + - supports-color + dev: true + /socks@2.7.1: resolution: {integrity: sha512-7maUZy1N7uo6+WVEX6psASxtNlKaNVMlGQKkG/63nEDdLOWNbiUMoLK7X4uYoLhQstau72mLgfEWcXcwsaHbYQ==} engines: {node: '>= 10.13.0', npm: '>= 3.0.0'} @@ -12165,6 +12549,14 @@ packages: smart-buffer: 4.2.0 dev: true + /socks@2.8.3: + resolution: {integrity: sha512-l5x7VUUWbjVFbafGLxPWkYsHIhEvmF85tbIeFZWc8ZPtoMyybuEhL7Jye/ooC4/d48FgOjSJXgsF/AJPYCW8Zw==} + engines: {node: '>= 10.0.0', npm: '>= 3.0.0'} + dependencies: + ip-address: 9.0.5 + smart-buffer: 4.2.0 + dev: true + /sonic-boom@3.3.0: resolution: {integrity: sha512-LYxp34KlZ1a2Jb8ZQgFCK3niIHzibdwtwNUWKg0qQRzsDoJ3Gfgkf8KdBTFU3SkejDEIlWwnSnpVdOZIhFMl/g==} dependencies: @@ -12247,6 +12639,10 @@ packages: resolution: {integrity: sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==} dev: true + /sprintf-js@1.1.3: + resolution: {integrity: sha512-Oo+0REFV59/rz3gfJNKQiBlwfHaSESl1pcGyABQsnnIfWOFt6JNj5gCog2U6MLZ//IGYD+nA8nI+mTShREReaA==} + dev: true + /ssri@9.0.1: resolution: {integrity: sha512-o57Wcn66jMQvfHG1FlYbWeZWW/dHZhJXjpIcTfXldXEk5nz5lStPo3mK0OJQfGR3RbZUlbISexbljkJzuEj/8Q==} engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0} @@ -12303,6 +12699,18 @@ packages: fast-fifo: 1.3.2 queue-tick: 1.0.1 + /streamx@2.20.1: + resolution: {integrity: sha512-uTa0mU6WUC65iUvzKH4X9hEdvSW7rbPxPtwfWiLMSj3qTdQbAiUboZTxauKfpFuGIGa1C2BYijZ7wgdUXICJhA==} + requiresBuild: true + dependencies: + fast-fifo: 1.3.2 + queue-tick: 1.0.1 + text-decoder: 1.2.0 + optionalDependencies: + bare-events: 2.5.0 + dev: true + optional: true + /string-hash@1.1.3: resolution: {integrity: sha512-kJUvRUFK49aub+a7T1nNE66EJbZBMnBgoC1UbCZ5n6bsZKBRga4KgBRTMn/pFkeCZSYtNeSyMxPDM0AXWELk2A==} dev: true @@ -12491,7 +12899,7 @@ packages: css-select: 4.3.0 css-tree: 1.1.3 csso: 4.2.0 - picocolors: 1.0.0 + picocolors: 1.0.1 stable: 0.1.8 dev: true @@ -12549,6 +12957,16 @@ packages: pump: 3.0.0 tar-stream: 3.1.6 + /tar-fs@3.0.6: + resolution: {integrity: sha512-iokBDQQkUyeXhgPYaZxmczGPhnhXZ0CmrqI+MOb/WFGS9DW5wnfrLgtjUJBvz50vQ3qfRwJ62QVoCFu8mPVu5w==} + dependencies: + pump: 3.0.0 + tar-stream: 3.1.6 + optionalDependencies: + bare-fs: 2.3.5 + bare-path: 2.1.3 + dev: true + /tar-stream@2.2.0: resolution: {integrity: sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==} engines: {node: '>=6'} @@ -12611,6 +13029,14 @@ packages: minimatch: 3.1.2 dev: true + /text-decoder@1.2.0: + resolution: {integrity: sha512-n1yg1mOj9DNpk3NeZOx7T6jchTbyJS3i3cucbNN6FcdPriMZx7NsgrGpWWdWZZGxD7ES1XB+3uoqHMgOKaN+fg==} + requiresBuild: true + dependencies: + b4a: 1.6.7 + dev: true + optional: true + /text-table@0.2.0: resolution: {integrity: sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==} dev: true @@ -12635,7 +13061,6 @@ packages: /through@2.3.8: resolution: {integrity: sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==} - dev: false /tlds@1.234.0: resolution: {integrity: sha512-TNDfeyDIC+oroH44bMbWC+Jn/2qNrfRvDK2EXt1icOXYG5NMqoRyUosADrukfb4D8lJ3S1waaBWSvQro0erdng==} @@ -12687,13 +13112,13 @@ packages: engines: {node: '>=8'} dev: true - /ts-api-utils@1.0.3(typescript@5.6.2): + /ts-api-utils@1.0.3(typescript@5.6.3): resolution: {integrity: sha512-wNMeqtMz5NtwpT/UZGY5alT+VoKdSsOOP/kqHFcUW1P/VRhH2wJ48+DN2WwUliNbQ976ETwDL0Ifd2VVvgonvg==} engines: {node: '>=16.13.0'} peerDependencies: typescript: '>=4.2.0' dependencies: - typescript: 5.6.2 + typescript: 5.6.3 dev: true /ts-interface-checker@0.1.13: @@ -12707,7 +13132,7 @@ packages: code-block-writer: 11.0.3 dev: false - /ts-node@10.8.2(@swc/core@1.3.42)(@types/node@18.19.50)(typescript@5.6.2): + /ts-node@10.8.2(@swc/core@1.3.42)(@types/node@18.19.50)(typescript@5.6.3): resolution: {integrity: sha512-LYdGnoGddf1D6v8REPtIH+5iq/gTDuZqv2/UJUU7tKjuEU8xVZorBM+buCGNjj+pGEud+sOoM4CX3/YzINpENA==} hasBin: true peerDependencies: @@ -12734,7 +13159,7 @@ packages: create-require: 1.1.1 diff: 4.0.2 make-error: 1.3.6 - typescript: 5.6.2 + typescript: 5.6.3 v8-compile-cache-lib: 3.0.1 yn: 3.1.1 dev: true @@ -12881,14 +13306,18 @@ packages: optionalDependencies: rxjs: 7.8.1 + /typed-query-selector@2.12.0: + resolution: {integrity: sha512-SbklCd1F0EiZOyPiW192rrHZzZ5sBijB6xM+cpmrwDqObvdtunOHHIk9fCGsoK5JVIYXoyEp4iEdE3upFH3PAg==} + dev: true + /typescript@4.5.2: resolution: {integrity: sha512-5BlMof9H1yGt0P8/WF+wPNw6GfctgGjXp5hkblpyT+8rkASSmkUKMXrxR0Xg8ThVCi/JnHQiKXeBaEwCeQwMFw==} engines: {node: '>=4.2.0'} hasBin: true dev: true - /typescript@5.6.2: - resolution: {integrity: sha512-NW8ByodCSNCwZeghjN3o+JX5OFH0Ojg6sadjEKY4huZ52TqbJTJnDo5+Tw98lSy63NZvi4n+ez5m2u5d4PkZyw==} + /typescript@5.6.3: + resolution: {integrity: sha512-hjcS1mhfuyi4WW8IWtjP7brDrG2cuDZukyrYrSauoXGNgx0S7zceP07adYkJycEr56BOUTNPzbInooiN3fn1qw==} engines: {node: '>=14.17'} hasBin: true dev: true @@ -12918,6 +13347,13 @@ packages: which-boxed-primitive: 1.0.2 dev: true + /unbzip2-stream@1.4.3: + resolution: {integrity: sha512-mlExGW4w71ebDJviH16lQLtZS32VKqsSfk80GCfUlwT/4/hNRFsoscrF/c++9xinkMzECL1uL9DDwXqFWkruPg==} + dependencies: + buffer: 5.7.1 + through: 2.3.8 + dev: true + /undici-types@5.26.5: resolution: {integrity: sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==} @@ -12951,6 +13387,11 @@ packages: engines: {node: '>= 4.0.0'} dev: true + /universalify@2.0.1: + resolution: {integrity: sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==} + engines: {node: '>= 10.0.0'} + dev: true + /unpipe@1.0.0: resolution: {integrity: sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==} engines: {node: '>= 0.8'} @@ -12963,7 +13404,7 @@ packages: dependencies: browserslist: 4.21.10 escalade: 3.1.2 - picocolors: 1.0.0 + picocolors: 1.0.1 dev: true /update-browserslist-db@1.0.16(browserslist@4.23.0): @@ -12989,6 +13430,10 @@ packages: requires-port: 1.0.0 dev: true + /urlpattern-polyfill@10.0.0: + resolution: {integrity: sha512-H/A06tKD7sS1O1X2SshBVeA5FLycRpjqiBeqGKmBwBDBy28EnRjORxTNe269KSSr5un5qyWi1iL61wLxpd+ZOg==} + dev: true + /util-deprecate@1.0.2: resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} @@ -13154,6 +13599,19 @@ packages: utf-8-validate: optional: true + /ws@8.18.0: + resolution: {integrity: sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==} + engines: {node: '>=10.0.0'} + peerDependencies: + bufferutil: ^4.0.1 + utf-8-validate: '>=5.0.2' + peerDependenciesMeta: + bufferutil: + optional: true + utf-8-validate: + optional: true + dev: true + /xmlbuilder@13.0.2: resolution: {integrity: sha512-Eux0i2QdDYKbdbA6AM6xE4m6ZTZr4G4xF9kahI2ukSEMCzwce2eX9WlTI5J3s+NU7hpasFsr8hWIONae7LluAQ==} engines: {node: '>=6.0'} @@ -13237,6 +13695,13 @@ packages: yargs-parser: 21.1.1 dev: true + /yauzl@2.10.0: + resolution: {integrity: sha512-p4a9I6X6nu6IhoGmBqAcbJy1mlC4j27vEPZX9F4L4/vZT3Lyq1VkFHw/V/PUcB9Buo+DG3iHkT0x3Qya58zc3g==} + dependencies: + buffer-crc32: 0.2.13 + fd-slicer: 1.1.0 + dev: true + /yesno@0.4.0: resolution: {integrity: sha512-tdBxmHvbXPBKYIg81bMCB7bVeDmHkRzk5rVJyYYXurwKkHq/MCd8rz4HSJUP7hW0H2NlXiq8IFiWvYKEHhlotA==} dev: false