diff --git a/.changeset/cruel-suits-move.md b/.changeset/cruel-suits-move.md new file mode 100644 index 000000000..f38e1d006 --- /dev/null +++ b/.changeset/cruel-suits-move.md @@ -0,0 +1,5 @@ +--- +'@vercel/edge-config': minor +--- + +[experimental] stream updates during development diff --git a/.gitignore b/.gitignore index f8abbdade..1d05a2b49 100644 --- a/.gitignore +++ b/.gitignore @@ -10,3 +10,5 @@ npm-debug.log .turbo .DS_Store .vscode + +packages/edge-config/DEVELOPMENT.md diff --git a/packages/edge-config/package.json b/packages/edge-config/package.json index 2c49d962d..a9b547f79 100644 --- a/packages/edge-config/package.json +++ b/packages/edge-config/package.json @@ -41,7 +41,8 @@ "testEnvironment": "node" }, "dependencies": { - "@vercel/edge-config-fs": "workspace:*" + "@vercel/edge-config-fs": "workspace:*", + "eventsource-client": "1.2.0" }, "devDependencies": { "@changesets/cli": "2.28.1", diff --git a/packages/edge-config/src/index.common.test.ts b/packages/edge-config/src/index.common.test.ts index 19559f282..4ba148f11 100644 --- a/packages/edge-config/src/index.common.test.ts +++ b/packages/edge-config/src/index.common.test.ts @@ -436,13 +436,16 @@ describe('connectionStrings', () => { describe('in-memory cache with swr behaviour', () => { const originalEnv = process.env.NODE_ENV; + const originalDisableStream = process.env.EDGE_CONFIG_DISABLE_STREAM; beforeAll(() => { process.env.NODE_ENV = 'development'; + process.env.EDGE_CONFIG_DISABLE_STREAM = '1'; }); afterAll(() => { process.env.NODE_ENV = originalEnv; + process.env.EDGE_CONFIG_DISABLE_STREAM = originalDisableStream; }); it('use in-memory cache', async () => { diff --git a/packages/edge-config/src/index.ts b/packages/edge-config/src/index.ts index f617b064a..2cbde91b8 100644 --- a/packages/edge-config/src/index.ts +++ b/packages/edge-config/src/index.ts @@ -1,4 +1,9 @@ import { readFile } from '@vercel/edge-config-fs'; +import { + createEventSource, + type EventSourceClient, + type FetchLike, +} from 'eventsource-client'; import { name as sdkName, version as sdkVersion } from '../package.json'; import { assertIsKey, @@ -246,6 +251,105 @@ async function consumeResponseBody(res: Response): Promise { await res.arrayBuffer(); } +class StreamManager { + private stream: EventSourceClient; + private connection: Connection; + /** + * Callback with either the Edge Config or null when the Edge Config + * does not exist or the token is invalid. + */ + private onEdgeConfig: (edgeConfig: EmbeddedEdgeConfig | null) => void; + private resolveStreamUsable?: (value: boolean) => void; + + private primedPromise: Promise = new Promise((resolve) => { + this.resolveStreamUsable = resolve; + }); + + constructor( + connection: Connection, + onEdgeConfig: (edgeConfig: EmbeddedEdgeConfig | null) => void, + ) { + this.connection = connection; + this.onEdgeConfig = onEdgeConfig; + + // TODO we can remove the custom fetch once eventstream-client supports + // seeing the status code. We only need this to be able to stop retrying + // on 401, 403, 404. + const fetchKeepResponse = (): FetchLike & { + status?: number; + statusText?: string; + } => { + const f: FetchLike & { status?: number; statusText?: string } = async ( + url, + fetchInit, + ) => { + f.status = undefined; + f.statusText = undefined; + const response = await fetch(url, fetchInit); + f.status = response.status; + f.statusText = response.statusText; + return response; + }; + return f; + }; + + const customFetch = fetchKeepResponse(); + + this.stream = createEventSource({ + url: `https://api.vercel.com/v1/edge-config/${this.connection.id}/stream`, + headers: { Authorization: `Bearer ${this.connection.token}` }, + fetch: customFetch, + onDisconnect: () => { + if (!customFetch.status || customFetch.status >= 400) { + this.resolveStreamUsable?.(false); + this.stream.close(); + } + }, + }); + } + + async listen(): Promise { + for await (const { data, event } of this.stream) { + if (event === 'status' && data === 'token_invalidated') { + this.stream.close(); + return; + } + + if (event === 'status' && data === 'primed') { + this.resolveStreamUsable?.(true); + continue; + } + + if (event === 'embed') { + try { + const parsedEdgeConfig = JSON.parse(data) as EmbeddedEdgeConfig; + this.onEdgeConfig(parsedEdgeConfig); + } catch (e) { + // eslint-disable-next-line no-console -- intentional error logging + console.error( + '@vercel/edge-config: Error parsing streamed edge config', + e, + ); + } + } + } + + this.stream.close(); + } + + primed(): Promise { + return this.primedPromise; + } + + readyState(): 'open' | 'connecting' | 'closed' { + return this.stream.readyState; + } + + close(): void { + this.stream.close(); + } +} + interface EdgeConfigClientOptions { /** * The stale-if-error response directive indicates that the cache can reuse a @@ -270,6 +374,11 @@ interface EdgeConfigClientOptions { */ disableDevelopmentCache?: boolean; + /** + * Disables the streaming of the Edge Config. + */ + disableStream?: boolean; + /** * Sets a `cache` option on the `fetch` call made by Edge Config. * @@ -334,6 +443,11 @@ export const createClient = trace( process.env.NODE_ENV === 'development' && process.env.EDGE_CONFIG_DISABLE_DEVELOPMENT_SWR !== '1'; + const shouldUseStream = + !options.disableStream && + process.env.NODE_ENV === 'development' && + process.env.EDGE_CONFIG_DISABLE_STREAM !== '1'; + const getInMemoryEdgeConfig = createGetInMemoryEdgeConfig( shouldUseDevelopmentCache, connection, @@ -341,12 +455,36 @@ export const createClient = trace( fetchCache, ); + let streamManager: StreamManager | null = null; + + let streamedEdgeConfig: EmbeddedEdgeConfig | null = null; + if (shouldUseStream) { + streamManager = new StreamManager(connection, (edgeConfig) => { + streamedEdgeConfig = edgeConfig; + }); + + void streamManager.listen().catch(() => { + // reset streamedEdgeConfig so it does not get used when there was an + // unexpected error with the stream + streamedEdgeConfig = null; + }); + } + const api: Omit = { get: trace( async function get( key: string, localOptions?: EdgeConfigFunctionsOptions, ): Promise { + if ( + streamManager && + streamedEdgeConfig && + streamManager.readyState() !== 'closed' && + (await streamManager.primed()) + ) { + return streamedEdgeConfig.items[key] as T; + } + const localEdgeConfig = (await getInMemoryEdgeConfig(localOptions)) || (await getLocalEdgeConfig(connection, localOptions)); @@ -397,6 +535,15 @@ export const createClient = trace( key, localOptions?: EdgeConfigFunctionsOptions, ): Promise { + if ( + streamManager && + streamedEdgeConfig && + streamManager.readyState() !== 'closed' && + (await streamManager.primed()) + ) { + return hasOwnProperty(streamedEdgeConfig.items, key); + } + const localEdgeConfig = (await getInMemoryEdgeConfig(localOptions)) || (await getLocalEdgeConfig(connection, localOptions)); @@ -438,6 +585,20 @@ export const createClient = trace( keys?: (keyof T)[], localOptions?: EdgeConfigFunctionsOptions, ): Promise { + if ( + streamManager && + streamedEdgeConfig && + streamManager.readyState() !== 'closed' && + (await streamManager.primed()) + ) { + if (keys === undefined) { + return streamedEdgeConfig.items as T; + } + + assertIsKeys(keys); + return pick(streamedEdgeConfig.items, keys) as T; + } + const localEdgeConfig = (await getInMemoryEdgeConfig(localOptions)) || (await getLocalEdgeConfig(connection, localOptions)); @@ -497,6 +658,15 @@ export const createClient = trace( async function digest( localOptions?: EdgeConfigFunctionsOptions, ): Promise { + if ( + streamManager && + streamedEdgeConfig && + streamManager.readyState() !== 'closed' && + (await streamManager.primed()) + ) { + return streamedEdgeConfig.digest; + } + const localEdgeConfig = (await getInMemoryEdgeConfig(localOptions)) || (await getLocalEdgeConfig(connection, localOptions)); diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 82d09b737..4b061a6c0 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -37,7 +37,7 @@ importers: version: 0.3.7 ts-jest: specifier: 29.2.6 - version: 29.2.6(@babel/core@7.26.0)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.26.0))(jest@29.7.0(@types/node@22.13.5)(ts-node@10.9.2(@types/node@22.13.5)(typescript@5.7.3)))(typescript@5.7.3) + version: 29.2.6(@babel/core@7.23.9)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.23.9))(jest@29.7.0(@types/node@22.13.5)(ts-node@10.9.2(@types/node@22.13.5)(typescript@5.7.3)))(typescript@5.7.3) turbo: specifier: 2.4.4 version: 2.4.4 @@ -92,7 +92,7 @@ importers: version: 29.7.0(bufferutil@4.0.8) ts-jest: specifier: 29.2.6 - version: 29.2.6(@babel/core@7.23.2)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.23.2))(esbuild@0.25.0)(jest@29.7.0(@types/node@22.13.5)(ts-node@10.9.2(@types/node@22.13.5)(typescript@5.7.3)))(typescript@5.7.3) + version: 29.2.6(@babel/core@7.26.0)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.26.0))(jest@29.7.0(@types/node@22.13.5)(ts-node@10.9.2(@types/node@22.13.5)(typescript@5.7.3)))(typescript@5.7.3) tsconfig: specifier: workspace:* version: link:../../tooling/tsconfig @@ -108,6 +108,9 @@ importers: '@vercel/edge-config-fs': specifier: workspace:* version: link:../edge-config-fs + eventsource-client: + specifier: 1.2.0 + version: 1.2.0 devDependencies: '@changesets/cli': specifier: 2.28.1 @@ -144,7 +147,7 @@ importers: version: 3.5.2 ts-jest: specifier: 29.2.6 - version: 29.2.6(@babel/core@7.26.0)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.26.0))(jest@29.7.0(@types/node@22.13.5)(ts-node@10.9.2(@types/node@22.13.5)(typescript@5.7.3)))(typescript@5.7.3) + version: 29.2.6(@babel/core@7.23.2)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.23.2))(esbuild@0.25.0)(jest@29.7.0(@types/node@22.13.5)(ts-node@10.9.2(@types/node@22.13.5)(typescript@5.7.3)))(typescript@5.7.3) tsconfig: specifier: workspace:* version: link:../../tooling/tsconfig @@ -371,7 +374,7 @@ importers: version: 2.1.3 next: specifier: ^15.2.0 - version: 15.2.0(@babel/core@7.23.9)(@opentelemetry/api@1.7.0)(@playwright/test@1.50.1)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + version: 15.2.0(@babel/core@7.26.0)(@opentelemetry/api@1.7.0)(@playwright/test@1.50.1)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) postcss: specifier: ^8.5.3 version: 8.5.3 @@ -2996,6 +2999,14 @@ packages: eventemitter3@5.0.1: resolution: {integrity: sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==} + eventsource-client@1.2.0: + resolution: {integrity: sha512-kDI75RSzO3TwyG/K9w1ap8XwqSPcwi6jaMkNulfVeZmSeUM49U8kUzk1s+vKNt0tGrXgK47i+620Yasn1ccFiw==} + engines: {node: '>=18.0.0'} + + eventsource-parser@3.0.6: + resolution: {integrity: sha512-Vo1ab+QXPzZ4tCa8SwIHJFaSzy4R6SHf7BY79rFBDf0idraZWAkYrDjDj8uWaSm3S2TK+hJ7/t1CEmZ7jXw+pg==} + engines: {node: '>=18.0.0'} + execa@5.1.1: resolution: {integrity: sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==} engines: {node: '>=10'} @@ -4198,6 +4209,7 @@ packages: node-domexception@2.0.1: resolution: {integrity: sha512-M85rnSC7WQ7wnfQTARPT4LrK7nwCHLdDFOCcItZMhTQjyCebJH8GciKqYJNgaOFZs9nFmTmd/VMyi3OW5jA47w==} engines: {node: '>=16'} + deprecated: Use your platform's native DOMException instead node-fetch@2.6.7: resolution: {integrity: sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==} @@ -4962,6 +4974,7 @@ packages: source-map@0.8.0-beta.0: resolution: {integrity: sha512-2ymg6oRBpebeZi9UUNsgQ89bhx01TcTkmNTGnNO88imTmbSgy4nfujrgVEFKWpMTEGA11EDkTt7mqObTPdigIA==} engines: {node: '>= 8'} + deprecated: The work that was done in this beta branch won't be included in future versions spawndamnit@3.0.1: resolution: {integrity: sha512-MmnduQUuHCoFckZoWnXsTg7JaiLBJrKFj9UI2MbRPGaJeVpsLcVBu6P/IGZovziM/YBsellCmsprgNA+w0CzVg==} @@ -5918,6 +5931,12 @@ snapshots: '@babel/core': 7.23.2 '@babel/helper-plugin-utils': 7.20.2 + '@babel/plugin-syntax-async-generators@7.8.4(@babel/core@7.23.9)': + dependencies: + '@babel/core': 7.23.9 + '@babel/helper-plugin-utils': 7.20.2 + optional: true + '@babel/plugin-syntax-async-generators@7.8.4(@babel/core@7.26.0)': dependencies: '@babel/core': 7.26.0 @@ -5929,6 +5948,12 @@ snapshots: '@babel/core': 7.23.2 '@babel/helper-plugin-utils': 7.20.2 + '@babel/plugin-syntax-bigint@7.8.3(@babel/core@7.23.9)': + dependencies: + '@babel/core': 7.23.9 + '@babel/helper-plugin-utils': 7.20.2 + optional: true + '@babel/plugin-syntax-bigint@7.8.3(@babel/core@7.26.0)': dependencies: '@babel/core': 7.26.0 @@ -5940,6 +5965,12 @@ snapshots: '@babel/core': 7.23.2 '@babel/helper-plugin-utils': 7.20.2 + '@babel/plugin-syntax-class-properties@7.12.13(@babel/core@7.23.9)': + dependencies: + '@babel/core': 7.23.9 + '@babel/helper-plugin-utils': 7.20.2 + optional: true + '@babel/plugin-syntax-class-properties@7.12.13(@babel/core@7.26.0)': dependencies: '@babel/core': 7.26.0 @@ -5951,6 +5982,12 @@ snapshots: '@babel/core': 7.23.2 '@babel/helper-plugin-utils': 7.20.2 + '@babel/plugin-syntax-import-meta@7.10.4(@babel/core@7.23.9)': + dependencies: + '@babel/core': 7.23.9 + '@babel/helper-plugin-utils': 7.20.2 + optional: true + '@babel/plugin-syntax-import-meta@7.10.4(@babel/core@7.26.0)': dependencies: '@babel/core': 7.26.0 @@ -5962,6 +5999,12 @@ snapshots: '@babel/core': 7.23.2 '@babel/helper-plugin-utils': 7.20.2 + '@babel/plugin-syntax-json-strings@7.8.3(@babel/core@7.23.9)': + dependencies: + '@babel/core': 7.23.9 + '@babel/helper-plugin-utils': 7.20.2 + optional: true + '@babel/plugin-syntax-json-strings@7.8.3(@babel/core@7.26.0)': dependencies: '@babel/core': 7.26.0 @@ -5978,6 +6021,12 @@ snapshots: '@babel/core': 7.23.2 '@babel/helper-plugin-utils': 7.20.2 + '@babel/plugin-syntax-logical-assignment-operators@7.10.4(@babel/core@7.23.9)': + dependencies: + '@babel/core': 7.23.9 + '@babel/helper-plugin-utils': 7.20.2 + optional: true + '@babel/plugin-syntax-logical-assignment-operators@7.10.4(@babel/core@7.26.0)': dependencies: '@babel/core': 7.26.0 @@ -5989,6 +6038,12 @@ snapshots: '@babel/core': 7.23.2 '@babel/helper-plugin-utils': 7.20.2 + '@babel/plugin-syntax-nullish-coalescing-operator@7.8.3(@babel/core@7.23.9)': + dependencies: + '@babel/core': 7.23.9 + '@babel/helper-plugin-utils': 7.20.2 + optional: true + '@babel/plugin-syntax-nullish-coalescing-operator@7.8.3(@babel/core@7.26.0)': dependencies: '@babel/core': 7.26.0 @@ -6000,6 +6055,12 @@ snapshots: '@babel/core': 7.23.2 '@babel/helper-plugin-utils': 7.20.2 + '@babel/plugin-syntax-numeric-separator@7.10.4(@babel/core@7.23.9)': + dependencies: + '@babel/core': 7.23.9 + '@babel/helper-plugin-utils': 7.20.2 + optional: true + '@babel/plugin-syntax-numeric-separator@7.10.4(@babel/core@7.26.0)': dependencies: '@babel/core': 7.26.0 @@ -6011,6 +6072,12 @@ snapshots: '@babel/core': 7.23.2 '@babel/helper-plugin-utils': 7.20.2 + '@babel/plugin-syntax-object-rest-spread@7.8.3(@babel/core@7.23.9)': + dependencies: + '@babel/core': 7.23.9 + '@babel/helper-plugin-utils': 7.20.2 + optional: true + '@babel/plugin-syntax-object-rest-spread@7.8.3(@babel/core@7.26.0)': dependencies: '@babel/core': 7.26.0 @@ -6022,6 +6089,12 @@ snapshots: '@babel/core': 7.23.2 '@babel/helper-plugin-utils': 7.20.2 + '@babel/plugin-syntax-optional-catch-binding@7.8.3(@babel/core@7.23.9)': + dependencies: + '@babel/core': 7.23.9 + '@babel/helper-plugin-utils': 7.20.2 + optional: true + '@babel/plugin-syntax-optional-catch-binding@7.8.3(@babel/core@7.26.0)': dependencies: '@babel/core': 7.26.0 @@ -6033,6 +6106,12 @@ snapshots: '@babel/core': 7.23.2 '@babel/helper-plugin-utils': 7.20.2 + '@babel/plugin-syntax-optional-chaining@7.8.3(@babel/core@7.23.9)': + dependencies: + '@babel/core': 7.23.9 + '@babel/helper-plugin-utils': 7.20.2 + optional: true + '@babel/plugin-syntax-optional-chaining@7.8.3(@babel/core@7.26.0)': dependencies: '@babel/core': 7.26.0 @@ -6044,6 +6123,12 @@ snapshots: '@babel/core': 7.23.2 '@babel/helper-plugin-utils': 7.20.2 + '@babel/plugin-syntax-top-level-await@7.14.5(@babel/core@7.23.9)': + dependencies: + '@babel/core': 7.23.9 + '@babel/helper-plugin-utils': 7.20.2 + optional: true + '@babel/plugin-syntax-top-level-await@7.14.5(@babel/core@7.26.0)': dependencies: '@babel/core': 7.26.0 @@ -7200,10 +7285,10 @@ snapshots: dependencies: '@types/yargs-parser': 21.0.0 - '@typescript-eslint/eslint-plugin@6.21.0(@typescript-eslint/parser@8.25.0(eslint@8.56.0)(typescript@5.7.3))(eslint@8.56.0)(typescript@5.7.3)': + '@typescript-eslint/eslint-plugin@6.21.0(@typescript-eslint/parser@6.21.0(eslint@8.56.0)(typescript@5.7.3))(eslint@8.56.0)(typescript@5.7.3)': dependencies: '@eslint-community/regexpp': 4.10.0 - '@typescript-eslint/parser': 8.25.0(eslint@8.56.0)(typescript@5.7.3) + '@typescript-eslint/parser': 6.21.0(eslint@8.56.0)(typescript@5.7.3) '@typescript-eslint/scope-manager': 6.21.0 '@typescript-eslint/type-utils': 6.21.0(eslint@8.56.0)(typescript@5.7.3) '@typescript-eslint/utils': 6.21.0(eslint@8.56.0)(typescript@5.7.3) @@ -7415,7 +7500,7 @@ snapshots: '@babel/core': 7.23.9 '@babel/eslint-parser': 7.23.10(@babel/core@7.23.9)(eslint@8.56.0) '@rushstack/eslint-patch': 1.7.2 - '@typescript-eslint/eslint-plugin': 6.21.0(@typescript-eslint/parser@8.25.0(eslint@8.56.0)(typescript@5.7.3))(eslint@8.56.0)(typescript@5.7.3) + '@typescript-eslint/eslint-plugin': 6.21.0(@typescript-eslint/parser@6.21.0(eslint@8.56.0)(typescript@5.7.3))(eslint@8.56.0)(typescript@5.7.3) '@typescript-eslint/parser': 6.21.0(eslint@8.56.0)(typescript@5.7.3) eslint-config-prettier: 9.1.0(eslint@8.56.0) eslint-import-resolver-alias: 1.1.2(eslint-plugin-import@2.29.1) @@ -7729,6 +7814,20 @@ snapshots: transitivePeerDependencies: - supports-color + babel-jest@29.7.0(@babel/core@7.23.9): + dependencies: + '@babel/core': 7.23.9 + '@jest/transform': 29.7.0 + '@types/babel__core': 7.20.0 + babel-plugin-istanbul: 6.1.1 + babel-preset-jest: 29.6.3(@babel/core@7.23.9) + chalk: 4.1.2 + graceful-fs: 4.2.11 + slash: 3.0.0 + transitivePeerDependencies: + - supports-color + optional: true + babel-jest@29.7.0(@babel/core@7.26.0): dependencies: '@babel/core': 7.26.0 @@ -7776,6 +7875,23 @@ snapshots: '@babel/plugin-syntax-optional-chaining': 7.8.3(@babel/core@7.23.2) '@babel/plugin-syntax-top-level-await': 7.14.5(@babel/core@7.23.2) + babel-preset-current-node-syntax@1.0.1(@babel/core@7.23.9): + dependencies: + '@babel/core': 7.23.9 + '@babel/plugin-syntax-async-generators': 7.8.4(@babel/core@7.23.9) + '@babel/plugin-syntax-bigint': 7.8.3(@babel/core@7.23.9) + '@babel/plugin-syntax-class-properties': 7.12.13(@babel/core@7.23.9) + '@babel/plugin-syntax-import-meta': 7.10.4(@babel/core@7.23.9) + '@babel/plugin-syntax-json-strings': 7.8.3(@babel/core@7.23.9) + '@babel/plugin-syntax-logical-assignment-operators': 7.10.4(@babel/core@7.23.9) + '@babel/plugin-syntax-nullish-coalescing-operator': 7.8.3(@babel/core@7.23.9) + '@babel/plugin-syntax-numeric-separator': 7.10.4(@babel/core@7.23.9) + '@babel/plugin-syntax-object-rest-spread': 7.8.3(@babel/core@7.23.9) + '@babel/plugin-syntax-optional-catch-binding': 7.8.3(@babel/core@7.23.9) + '@babel/plugin-syntax-optional-chaining': 7.8.3(@babel/core@7.23.9) + '@babel/plugin-syntax-top-level-await': 7.14.5(@babel/core@7.23.9) + optional: true + babel-preset-current-node-syntax@1.0.1(@babel/core@7.26.0): dependencies: '@babel/core': 7.26.0 @@ -7799,6 +7915,13 @@ snapshots: babel-plugin-jest-hoist: 29.6.3 babel-preset-current-node-syntax: 1.0.1(@babel/core@7.23.2) + babel-preset-jest@29.6.3(@babel/core@7.23.9): + dependencies: + '@babel/core': 7.23.9 + babel-plugin-jest-hoist: 29.6.3 + babel-preset-current-node-syntax: 1.0.1(@babel/core@7.23.9) + optional: true + babel-preset-jest@29.6.3(@babel/core@7.26.0): dependencies: '@babel/core': 7.26.0 @@ -8598,7 +8721,7 @@ snapshots: debug: 4.3.7 enhanced-resolve: 5.15.0 eslint: 8.56.0 - eslint-module-utils: 2.8.0(@typescript-eslint/parser@6.21.0(eslint@8.56.0)(typescript@5.7.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1)(eslint@8.56.0) + eslint-module-utils: 2.8.0(@typescript-eslint/parser@6.21.0(eslint@8.56.0)(typescript@5.7.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@6.21.0(eslint@8.56.0)(typescript@5.7.3))(eslint-plugin-import@2.29.1)(eslint@8.56.0))(eslint@8.56.0) eslint-plugin-import: 2.29.1(@typescript-eslint/parser@6.21.0(eslint@8.56.0)(typescript@5.7.3))(eslint-import-resolver-typescript@3.6.1)(eslint@8.56.0) fast-glob: 3.3.2 get-tsconfig: 4.7.2 @@ -8636,7 +8759,7 @@ snapshots: transitivePeerDependencies: - supports-color - eslint-module-utils@2.8.0(@typescript-eslint/parser@6.21.0(eslint@8.56.0)(typescript@5.7.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1)(eslint@8.56.0): + eslint-module-utils@2.8.0(@typescript-eslint/parser@6.21.0(eslint@8.56.0)(typescript@5.7.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@6.21.0(eslint@8.56.0)(typescript@5.7.3))(eslint-plugin-import@2.29.1)(eslint@8.56.0))(eslint@8.56.0): dependencies: debug: 3.2.7 optionalDependencies: @@ -8663,7 +8786,7 @@ snapshots: doctrine: 2.1.0 eslint: 8.56.0 eslint-import-resolver-node: 0.3.9 - eslint-module-utils: 2.8.0(@typescript-eslint/parser@6.21.0(eslint@8.56.0)(typescript@5.7.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1)(eslint@8.56.0) + eslint-module-utils: 2.8.0(@typescript-eslint/parser@6.21.0(eslint@8.56.0)(typescript@5.7.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@6.21.0(eslint@8.56.0)(typescript@5.7.3))(eslint-plugin-import@2.29.1)(eslint@8.56.0))(eslint@8.56.0) hasown: 2.0.1 is-core-module: 2.13.1 is-glob: 4.0.3 @@ -8714,7 +8837,7 @@ snapshots: '@typescript-eslint/utils': 5.62.0(eslint@8.56.0)(typescript@5.7.3) eslint: 8.56.0 optionalDependencies: - '@typescript-eslint/eslint-plugin': 6.21.0(@typescript-eslint/parser@8.25.0(eslint@8.56.0)(typescript@5.7.3))(eslint@8.56.0)(typescript@5.7.3) + '@typescript-eslint/eslint-plugin': 6.21.0(@typescript-eslint/parser@6.21.0(eslint@8.56.0)(typescript@5.7.3))(eslint@8.56.0)(typescript@5.7.3) jest: 29.7.0(@types/node@22.13.5)(ts-node@10.9.2(@types/node@22.13.5)(typescript@5.7.3)) transitivePeerDependencies: - supports-color @@ -8936,6 +9059,12 @@ snapshots: eventemitter3@5.0.1: {} + eventsource-client@1.2.0: + dependencies: + eventsource-parser: 3.0.6 + + eventsource-parser@3.0.6: {} + execa@5.1.1: dependencies: cross-spawn: 7.0.6 @@ -10490,7 +10619,7 @@ snapshots: natural-compare@1.4.0: {} - next@15.2.0(@babel/core@7.23.9)(@opentelemetry/api@1.7.0)(@playwright/test@1.50.1)(react-dom@19.0.0(react@19.0.0))(react@19.0.0): + next@15.2.0(@babel/core@7.26.0)(@opentelemetry/api@1.7.0)(@playwright/test@1.50.1)(react-dom@19.0.0(react@19.0.0))(react@19.0.0): dependencies: '@next/env': 15.2.0 '@swc/counter': 0.1.3 @@ -10500,7 +10629,7 @@ snapshots: postcss: 8.4.31 react: 19.0.0 react-dom: 19.0.0(react@19.0.0) - styled-jsx: 5.1.6(@babel/core@7.23.9)(react@19.0.0) + styled-jsx: 5.1.6(@babel/core@7.26.0)(react@19.0.0) optionalDependencies: '@next/swc-darwin-arm64': 15.2.0 '@next/swc-darwin-x64': 15.2.0 @@ -11476,12 +11605,12 @@ snapshots: strip-json-comments@3.1.1: {} - styled-jsx@5.1.6(@babel/core@7.23.9)(react@19.0.0): + styled-jsx@5.1.6(@babel/core@7.26.0)(react@19.0.0): dependencies: client-only: 0.0.1 react: 19.0.0 optionalDependencies: - '@babel/core': 7.23.9 + '@babel/core': 7.26.0 sucrase@3.35.0: dependencies: @@ -11657,6 +11786,25 @@ snapshots: babel-jest: 29.7.0(@babel/core@7.23.2) esbuild: 0.25.0 + ts-jest@29.2.6(@babel/core@7.23.9)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.23.9))(jest@29.7.0(@types/node@22.13.5)(ts-node@10.9.2(@types/node@22.13.5)(typescript@5.7.3)))(typescript@5.7.3): + dependencies: + bs-logger: 0.2.6 + ejs: 3.1.10 + fast-json-stable-stringify: 2.1.0 + jest: 29.7.0(@types/node@22.13.5)(ts-node@10.9.2(@types/node@22.13.5)(typescript@5.7.3)) + jest-util: 29.7.0 + json5: 2.2.3 + lodash.memoize: 4.1.2 + make-error: 1.3.6 + semver: 7.7.1 + typescript: 5.7.3 + yargs-parser: 21.1.1 + optionalDependencies: + '@babel/core': 7.23.9 + '@jest/transform': 29.7.0 + '@jest/types': 29.6.3 + babel-jest: 29.7.0(@babel/core@7.23.9) + ts-jest@29.2.6(@babel/core@7.26.0)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.26.0))(jest@29.7.0(@types/node@22.13.5)(ts-node@10.9.2(@types/node@22.13.5)(typescript@5.7.3)))(typescript@5.7.3): dependencies: bs-logger: 0.2.6