From f78c3be4db18b826cbc50640b84e97c6bd72a4ea Mon Sep 17 00:00:00 2001 From: Jason Morais Date: Tue, 19 May 2026 15:36:01 -0400 Subject: [PATCH 1/3] initial commit for verify --- readme.md | 1 + 1 file changed, 1 insertion(+) diff --git a/readme.md b/readme.md index 7f0e592c1..c64caa156 100644 --- a/readme.md +++ b/readme.md @@ -27,6 +27,7 @@ Our Docusaurus website will help you get started in running and contributing to ## Developer usage + - Full local dev (builds, starts the portless HTTPS proxy, starts Azurite, and runs the app-level dev servers): ```bash From 09e9ab0a295574df2ae1dca1209839f730fb9f35 Mon Sep 17 00:00:00 2001 From: Jason Morais Date: Tue, 19 May 2026 15:57:41 -0400 Subject: [PATCH 2/3] staging changes for portless modification - using worktree as an env variable and building them into the url for our various portless hosted services --- .snyk | 15 + apps/api/package.json | 7 +- apps/api/start-azurite.mjs | 57 + apps/api/start-dev.mjs | 17 +- apps/api/turbo.json | 5 + apps/docs/package.json | 1 + apps/docs/turbo.json | 6 + apps/server-mongodb-memory-mock/package.json | 3 +- .../start-mongo.mjs | 35 + apps/server-mongodb-memory-mock/turbo.json | 6 + apps/server-oauth2-mock/package.json | 1 + .../src/portal-discovery.ts | 9 +- apps/server-oauth2-mock/start-dev.mjs | 24 + apps/server-oauth2-mock/turbo.json | 6 + apps/ui-community/mock-oidc.users.json | 11 + apps/ui-community/package.json | 1 + apps/ui-community/start-dev.mjs | 24 + apps/ui-community/turbo.json | 6 + apps/ui-staff/package.json | 1 + apps/ui-staff/start-dev.mjs | 23 + build-pipeline/scripts/portless-hostnames.mjs | 88 ++ build-pipeline/scripts/worktree-ports.mjs | 100 ++ knip.json | 5 +- package.json | 4 +- .../server-oauth2-mock-seedwork/package.json | 2 +- .../ocom-verification/e2e-tests/cucumber.js | 2 +- .../ocom-verification/e2e-tests/package.json | 4 +- .../src/shared/support/oauth2-login.ts | 14 +- .../src/shared/support/servers/index.ts | 12 +- .../shared/support/servers/portless-server.ts | 115 +- .../shared/support/servers/test-api-server.ts | 49 +- .../servers/test-community-vite-server.ts | 40 + .../support/servers/test-environment.ts | 30 +- .../support/servers/test-oauth2-server.ts | 74 +- .../support/servers/test-vite-server.ts | 41 - .../shared/support/shared-infrastructure.ts | 47 +- .../verification-shared/src/servers/index.ts | 1 + .../src/servers/test-server.interface.ts | 40 + .../verification-shared/src/settings/index.ts | 2 + .../src/settings/local-settings.ts | 37 +- .../src/settings/portless-settings.ts | 65 ++ .../src/settings/timeout-settings.ts | 48 + packages/ocom/service-otel/package.json | 2 +- pnpm-lock.yaml | 1034 ++++++++++------- pnpm-workspace.yaml | 9 +- turbo.json | 7 + 46 files changed, 1543 insertions(+), 587 deletions(-) create mode 100644 apps/api/start-azurite.mjs create mode 100644 apps/server-mongodb-memory-mock/start-mongo.mjs create mode 100644 apps/server-oauth2-mock/start-dev.mjs create mode 100644 apps/ui-community/start-dev.mjs create mode 100644 apps/ui-staff/start-dev.mjs create mode 100644 build-pipeline/scripts/portless-hostnames.mjs create mode 100644 build-pipeline/scripts/worktree-ports.mjs create mode 100644 packages/ocom-verification/e2e-tests/src/shared/support/servers/test-community-vite-server.ts delete mode 100644 packages/ocom-verification/e2e-tests/src/shared/support/servers/test-vite-server.ts create mode 100644 packages/ocom-verification/verification-shared/src/servers/test-server.interface.ts create mode 100644 packages/ocom-verification/verification-shared/src/settings/portless-settings.ts create mode 100644 packages/ocom-verification/verification-shared/src/settings/timeout-settings.ts diff --git a/.snyk b/.snyk index 97bb87848..02a4e4b14 100644 --- a/.snyk +++ b/.snyk @@ -76,3 +76,18 @@ ignore: reason: 'Transitive dependency in Docusaurus; not exploitable in current usage.' expires: '2026-06-28T00:00:00.000Z' created: '2026-05-11T10:00:00.000Z' + 'SNYK-JS-AI-16734889': + - '* > ai@5.0.105': + reason: 'Transitive dependency in @docusaurus/preset-classic; not exploitable in current usage.' + expires: '2026-06-18T00:00:00.000Z' + created: '2026-05-18T11:04:00.000Z' + 'SNYK-JS-AISDKPROVIDERUTILS-16734888': + - '* > @ai-sdk/provider-utils@3.0.18': + reason: 'Transitive dependency in @docusaurus/preset-classic; not exploitable in current usage.' + expires: '2026-06-18T00:00:00.000Z' + created: '2026-05-18T11:04:00.000Z' + 'SNYK-JS-AISDKPROVIDERUTILS-16735288': + - '* > @ai-sdk/provider-utils@3.0.18': + reason: 'Transitive dependency in @docusaurus/preset-classic; not exploitable in current usage.' + expires: '2026-06-18T00:00:00.000Z' + created: '2026-05-18T11:04:00.000Z' diff --git a/apps/api/package.json b/apps/api/package.json index fce77a1f4..6041983b2 100644 --- a/apps/api/package.json +++ b/apps/api/package.json @@ -10,6 +10,8 @@ "build": "tsgo --build && rolldown -c rolldown.config.ts", "predev": "pnpm run prepare:deploy && pnpm run sync-local-settings", "dev": "pnpm exec portless data-access.ownercommunity.localhost --force node start-dev.mjs", + "predev:portless": "pnpm run prepare:deploy && pnpm run sync-local-settings", + "dev:portless": "pnpm exec portless data-access.ownercommunity.${WORKTREE_NAME}.localhost --force node start-dev.mjs", "prepare:deploy": "cellix-prepare-func-deploy", "watch": "tsgo --watch", "test": "vitest run --silent --reporter=dot", @@ -22,7 +24,7 @@ "prestart": "pnpm run prepare:deploy && pnpm run sync-local-settings", "start": "func start --typescript --script-root deploy/", "sync-local-settings": "node -e \"const fs=require('node:fs'); fs.mkdirSync('deploy',{recursive:true}); if (fs.existsSync('local.settings.json')) fs.copyFileSync('local.settings.json','deploy/local.settings.json');\"", - "azurite": "azurite-blob --silent --location ../../__blobstorage__ & azurite-queue --silent --location ../../__queuestorage__ & azurite-table --silent --location ../../__tablestorage__" + "azurite": "node start-azurite.mjs" }, "dependencies": { "@azure/functions": "catalog:", @@ -31,8 +33,8 @@ "@ocom/application-services": "workspace:*", "@ocom/context-spec": "workspace:*", "@ocom/event-handler": "workspace:*", - "@ocom/graphql-handler": "workspace:*", "@ocom/graphql": "workspace:*", + "@ocom/graphql-handler": "workspace:*", "@ocom/persistence": "workspace:*", "@ocom/rest": "workspace:*", "@ocom/service-apollo-server": "workspace:*", @@ -47,6 +49,7 @@ "@cellix/config-typescript": "workspace:*", "@cellix/config-vitest": "workspace:*", "@vitest/coverage-istanbul": "catalog:", + "azurite": "^3.35.0", "rimraf": "catalog:", "rolldown": "1.0.0-beta.55", "typescript": "catalog:", diff --git a/apps/api/start-azurite.mjs b/apps/api/start-azurite.mjs new file mode 100644 index 000000000..ac3dff4e4 --- /dev/null +++ b/apps/api/start-azurite.mjs @@ -0,0 +1,57 @@ +import { spawn } from 'node:child_process'; +import net from 'node:net'; +import { isGracefulInterruptExit } from '../../build-pipeline/scripts/dev-process-exit.mjs'; +import { getAzuritePorts } from '../../build-pipeline/scripts/worktree-ports.mjs'; + +const ports = getAzuritePorts(); +const worktreeName = process.env.WORKTREE_NAME ?? ''; +const storageSuffix = worktreeName ? `-${worktreeName}` : ''; + +function isPortListening(port) { + return new Promise((resolve) => { + const socket = net.createConnection({ port, host: '127.0.0.1' }); + socket.once('connect', () => { + socket.destroy(); + resolve(true); + }); + socket.once('error', () => { + socket.destroy(); + resolve(false); + }); + }); +} + +if (await isPortListening(ports.blob)) { + console.log(`[azurite] already running (blob port ${ports.blob}), skipping`); + process.exit(0); +} + +const blobDir = `../../__blobstorage__${storageSuffix}`; +const queueDir = `../../__queuestorage__${storageSuffix}`; +const tableDir = `../../__tablestorage__${storageSuffix}`; + +const procs = [ + spawn('azurite-blob', ['--silent', '--blobPort', String(ports.blob), '--location', blobDir], { stdio: 'inherit' }), + spawn('azurite-queue', ['--silent', '--queuePort', String(ports.queue), '--location', queueDir], { stdio: 'inherit' }), + spawn('azurite-table', ['--silent', '--tablePort', String(ports.table), '--location', tableDir], { stdio: 'inherit' }), +]; + +let exited = 0; +for (const proc of procs) { + proc.on('exit', (code, signal) => { + if (isGracefulInterruptExit(signal, code)) { + if (++exited === procs.length) process.exit(0); + return; + } + console.error(`[azurite] process exited unexpectedly: code=${code} signal=${signal}`); + for (const p of procs) p.kill(); + process.exit(code ?? 1); + }); +} + +process.on('SIGINT', () => { + for (const p of procs) p.kill('SIGINT'); +}); +process.on('SIGTERM', () => { + for (const p of procs) p.kill('SIGTERM'); +}); diff --git a/apps/api/start-dev.mjs b/apps/api/start-dev.mjs index 7c705d8c7..978b8744b 100644 --- a/apps/api/start-dev.mjs +++ b/apps/api/start-dev.mjs @@ -2,6 +2,8 @@ import { spawn } from 'node:child_process'; import os from 'node:os'; import path from 'node:path'; import { isGracefulInterruptExit } from '../../build-pipeline/scripts/dev-process-exit.mjs'; +import { buildPortlessUrl, getHostnames } from '../../build-pipeline/scripts/portless-hostnames.mjs'; +import { getAzuriteConnectionString, getMongoConnectionString } from '../../build-pipeline/scripts/worktree-ports.mjs'; const envPort = process.env.PORT; @@ -18,7 +20,20 @@ const childEnv = { NODE_OPTIONS: `${process.env.NODE_OPTIONS ?? ''} --use-system-ca`.trim(), }; -const child = spawn('func', ['start', '--typescript', '--script-root', 'deploy/', '--port', envPort], { +// Only inject worktree-scoped overrides when running in worktree mode. +// When WORKTREE_NAME is absent, local.settings.json remains the source of truth. +if (process.env.WORKTREE_NAME) { + const hostnames = getHostnames(); + childEnv.ACCOUNT_PORTAL_OIDC_ISSUER = buildPortlessUrl(hostnames.mockAuth, '/community'); + childEnv.ACCOUNT_PORTAL_OIDC_ENDPOINT = buildPortlessUrl(hostnames.mockAuth, '/community/.well-known/jwks.json'); + childEnv.COSMOSDB_CONNECTION_STRING = getMongoConnectionString(); + childEnv.AZURE_STORAGE_CONNECTION_STRING = getAzuriteConnectionString(); + childEnv.AzureWebJobsStorage = getAzuriteConnectionString(); + // Disable the Node.js inspector — port 5858 is already used by the primary worktree. + childEnv.languageWorkers__node__arguments = ''; +} + +const child = spawn('func', ['start', '--typescript', '--script-root', 'deploy/', '--port', envPort, '--cors', '*'], { stdio: 'inherit', env: childEnv, }); diff --git a/apps/api/turbo.json b/apps/api/turbo.json index 25ef0ca81..0f908f3c8 100644 --- a/apps/api/turbo.json +++ b/apps/api/turbo.json @@ -11,6 +11,11 @@ "dependsOn": ["build"], "interruptible": true, "inputs": [] + }, + "dev:portless": { + "dependsOn": ["build"], + "interruptible": true, + "inputs": [] } } } diff --git a/apps/docs/package.json b/apps/docs/package.json index 64b40e9f8..10766a652 100644 --- a/apps/docs/package.json +++ b/apps/docs/package.json @@ -5,6 +5,7 @@ "scripts": { "docusaurus": "docusaurus", "dev": "pnpm exec portless docs.ownercommunity.localhost --force node start-dev.mjs", + "dev:portless": "pnpm exec portless docs.ownercommunity.${WORKTREE_NAME}.localhost --force node start-dev.mjs", "start": "docusaurus start --port 3001", "build": "docusaurus build", "swizzle": "docusaurus swizzle", diff --git a/apps/docs/turbo.json b/apps/docs/turbo.json index 94418f57b..d39e3fdc8 100644 --- a/apps/docs/turbo.json +++ b/apps/docs/turbo.json @@ -7,6 +7,12 @@ "interruptible": false, "inputs": [".env", "package.json", "start-dev.mjs", "docusaurus.config.ts", "sidebars.ts", "tsconfig.json"] }, + "dev:portless": { + "dependsOn": [], + "persistent": true, + "interruptible": false, + "inputs": [".env", "package.json", "start-dev.mjs", "docusaurus.config.ts", "sidebars.ts", "tsconfig.json"] + }, "test": { "inputs": ["$TURBO_EXTENDS$", "!docs/**", "!blog/**", "!static/**"] }, diff --git a/apps/server-mongodb-memory-mock/package.json b/apps/server-mongodb-memory-mock/package.json index d34485afc..2372d4635 100644 --- a/apps/server-mongodb-memory-mock/package.json +++ b/apps/server-mongodb-memory-mock/package.json @@ -11,7 +11,8 @@ "format": "biome format --write", "format:check": "biome format .", "start": "node dist/index.js", - "dev": "tsx src/index.ts" + "dev": "tsx src/index.ts", + "dev:portless": "node start-mongo.mjs" }, "dependencies": { "@cellix/server-mongodb-memory-mock-seedwork": "workspace:*", diff --git a/apps/server-mongodb-memory-mock/start-mongo.mjs b/apps/server-mongodb-memory-mock/start-mongo.mjs new file mode 100644 index 000000000..1b39ae1ef --- /dev/null +++ b/apps/server-mongodb-memory-mock/start-mongo.mjs @@ -0,0 +1,35 @@ +import net from 'node:net'; +import { getMongoPort } from '../../build-pipeline/scripts/worktree-ports.mjs'; + +const MONGO_PORT = getMongoPort(); + +function isPortListening(port) { + return new Promise((resolve) => { + const socket = net.createConnection({ port, host: '127.0.0.1' }); + socket.once('connect', () => { + socket.destroy(); + resolve(true); + }); + socket.once('error', () => { + socket.destroy(); + resolve(false); + }); + }); +} + +if (await isPortListening(MONGO_PORT)) { + console.log(`[mongo-mock] already running on port ${MONGO_PORT}, skipping`); + process.exit(0); +} + +// Not running — start it via tsx with the worktree-scoped port +const { + default: { spawn }, +} = await import('node:child_process'); +const child = spawn('tsx', ['src/index.ts'], { + stdio: 'inherit', + env: { ...process.env, PORT: String(MONGO_PORT) }, +}); +child.on('exit', (code) => { + process.exit(code ?? 1); +}); diff --git a/apps/server-mongodb-memory-mock/turbo.json b/apps/server-mongodb-memory-mock/turbo.json index 01cb45a99..b0f2f18a9 100644 --- a/apps/server-mongodb-memory-mock/turbo.json +++ b/apps/server-mongodb-memory-mock/turbo.json @@ -7,6 +7,12 @@ "persistent": true, "interruptible": true, "inputs": [] + }, + "dev:portless": { + "dependsOn": ["build"], + "persistent": true, + "interruptible": true, + "inputs": [] } } } diff --git a/apps/server-oauth2-mock/package.json b/apps/server-oauth2-mock/package.json index c371c0518..bc92782ff 100644 --- a/apps/server-oauth2-mock/package.json +++ b/apps/server-oauth2-mock/package.json @@ -12,6 +12,7 @@ "format:check": "biome format .", "start": "node dist/index.js", "dev": "pnpm exec portless mock-auth.ownercommunity.localhost --force tsx src/index.ts", + "dev:portless": "pnpm exec portless mock-auth.ownercommunity.${WORKTREE_NAME}.localhost --force node start-dev.mjs", "test": "vitest run", "test:coverage": "vitest run --coverage", "test:watch": "vitest" diff --git a/apps/server-oauth2-mock/src/portal-discovery.ts b/apps/server-oauth2-mock/src/portal-discovery.ts index 43b3329c5..34c63cc87 100644 --- a/apps/server-oauth2-mock/src/portal-discovery.ts +++ b/apps/server-oauth2-mock/src/portal-discovery.ts @@ -119,16 +119,17 @@ function buildPortalFromConfig(config: MockOidcConfig, parsedEnv: Record { + if (isGracefulInterruptExit(signal, code)) { + process.exitCode = 0; + return; + } + process.exitCode = code ?? 1; +}); diff --git a/apps/server-oauth2-mock/turbo.json b/apps/server-oauth2-mock/turbo.json index d2d188a5b..325758390 100644 --- a/apps/server-oauth2-mock/turbo.json +++ b/apps/server-oauth2-mock/turbo.json @@ -9,6 +9,12 @@ "interruptible": true, "persistent": true, "inputs": ["$TURBO_DEFAULT$", "../**/mock-oidc*.json"] + }, + "dev:portless": { + "dependsOn": ["build"], + "interruptible": true, + "persistent": true, + "inputs": ["$TURBO_DEFAULT$", "../**/mock-oidc*.json", "start-dev.mjs"] } } } diff --git a/apps/ui-community/mock-oidc.users.json b/apps/ui-community/mock-oidc.users.json index a9953d8c4..b37ea3537 100644 --- a/apps/ui-community/mock-oidc.users.json +++ b/apps/ui-community/mock-oidc.users.json @@ -20,5 +20,16 @@ "family_name": "Doe", "tid": "test-tenant-id" } + }, + { + "username": "owner@test.example", + "sub": "aaaaaaaa-bbbb-1ccc-9ddd-eeeeeeeeee01", + "password": "password", + "claims": { + "email": "owner@test.example", + "given_name": "Test", + "family_name": "Owner", + "tid": "test-tenant-id" + } } ] diff --git a/apps/ui-community/package.json b/apps/ui-community/package.json index 5e8926d5d..86bc14f1d 100644 --- a/apps/ui-community/package.json +++ b/apps/ui-community/package.json @@ -10,6 +10,7 @@ "prebuild": "pnpm run lint", "build": "tsgo --build && vite build", "dev": "pnpm exec portless ownercommunity.localhost --force vite", + "dev:portless": "pnpm exec portless ownercommunity.${WORKTREE_NAME}.localhost --force node start-dev.mjs", "start": "vite", "preview": "vite preview", "test": "vitest run --silent --reporter=dot", diff --git a/apps/ui-community/start-dev.mjs b/apps/ui-community/start-dev.mjs new file mode 100644 index 000000000..a13661535 --- /dev/null +++ b/apps/ui-community/start-dev.mjs @@ -0,0 +1,24 @@ +import { spawn } from 'node:child_process'; +import { isGracefulInterruptExit } from '../../build-pipeline/scripts/dev-process-exit.mjs'; +import { buildPortlessUrl, getHostnames } from '../../build-pipeline/scripts/portless-hostnames.mjs'; + +const hostnames = getHostnames(); + +const child = spawn('vite', ['--port', process.env.PORT, '--host', process.env.HOST ?? '127.0.0.1'], { + stdio: 'inherit', + env: { + ...process.env, + VITE_APP_UI_COMMUNITY_B2C_AUTHORITY: buildPortlessUrl(hostnames.mockAuth, '/community'), + VITE_APP_UI_COMMUNITY_B2C_REDIRECT_URI: buildPortlessUrl(hostnames.uiCommunity, '/auth-redirect'), + VITE_COMMON_API_ENDPOINT: buildPortlessUrl(hostnames.api, '/api/graphql'), + VITE_APP_UI_COMMUNITY_BASE_URL: buildPortlessUrl(hostnames.uiCommunity), + }, +}); + +child.on('exit', (code, signal) => { + if (isGracefulInterruptExit(signal, code)) { + process.exitCode = 0; + return; + } + process.exitCode = code ?? 1; +}); diff --git a/apps/ui-community/turbo.json b/apps/ui-community/turbo.json index d5f21a945..e253b58b7 100644 --- a/apps/ui-community/turbo.json +++ b/apps/ui-community/turbo.json @@ -6,6 +6,12 @@ "persistent": true, "interruptible": false, "inputs": [".env", "package.json", "vite.config.ts", "tsconfig.json", "tsconfig.app.json", "tsconfig.node.json"] + }, + "dev:portless": { + "dependsOn": ["^build"], + "persistent": true, + "interruptible": false, + "inputs": [".env", "package.json", "start-dev.mjs", "vite.config.ts", "tsconfig.json", "tsconfig.app.json", "tsconfig.node.json"] } } } diff --git a/apps/ui-staff/package.json b/apps/ui-staff/package.json index 1b07d4527..bd35eaf13 100644 --- a/apps/ui-staff/package.json +++ b/apps/ui-staff/package.json @@ -10,6 +10,7 @@ "prebuild": "pnpm run lint", "build": "tsgo --build && vite build", "dev": "pnpm exec portless staff.ownercommunity.localhost --force vite", + "dev:portless": "pnpm exec portless staff.ownercommunity.${WORKTREE_NAME}.localhost --force node start-dev.mjs", "start": "vite", "preview": "vite preview", "test": "vitest run --silent --reporter=dot", diff --git a/apps/ui-staff/start-dev.mjs b/apps/ui-staff/start-dev.mjs new file mode 100644 index 000000000..4b656ce70 --- /dev/null +++ b/apps/ui-staff/start-dev.mjs @@ -0,0 +1,23 @@ +import { spawn } from 'node:child_process'; +import { isGracefulInterruptExit } from '../../build-pipeline/scripts/dev-process-exit.mjs'; +import { buildPortlessUrl, getHostnames } from '../../build-pipeline/scripts/portless-hostnames.mjs'; + +const hostnames = getHostnames(); + +const child = spawn('vite', ['--port', process.env.PORT, '--host', process.env.HOST ?? '127.0.0.1'], { + stdio: 'inherit', + env: { + ...process.env, + VITE_APP_UI_STAFF_AAD_AUTHORITY: buildPortlessUrl(hostnames.mockAuth, '/staff'), + VITE_APP_UI_STAFF_AAD_REDIRECT_URI: buildPortlessUrl(hostnames.uiStaff, '/auth-redirect'), + VITE_COMMON_API_ENDPOINT: buildPortlessUrl(hostnames.api, '/api/graphql'), + }, +}); + +child.on('exit', (code, signal) => { + if (isGracefulInterruptExit(signal, code)) { + process.exitCode = 0; + return; + } + process.exitCode = code ?? 1; +}); diff --git a/build-pipeline/scripts/portless-hostnames.mjs b/build-pipeline/scripts/portless-hostnames.mjs new file mode 100644 index 000000000..f5df73258 --- /dev/null +++ b/build-pipeline/scripts/portless-hostnames.mjs @@ -0,0 +1,88 @@ +/** + * Shared portless hostname computation for git worktree isolation. + * + * Hostnames are derived from the tracked .env files, so this module contains + * no hardcoded service names. When `WORKTREE_NAME` is set the worktree suffix + * is spliced in before `.localhost`, giving each worktree its own subdomain + * on the shared proxy port. + * + * Default (no worktree): + * ownercommunity.localhost (read from VITE_APP_UI_COMMUNITY_BASE_URL) + * data-access.ownercommunity.localhost (read from VITE_COMMON_API_ENDPOINT) + * + * With WORKTREE_NAME=feature-a: + * ownercommunity.feature-a.localhost + * data-access.ownercommunity.feature-a.localhost + */ + +import { existsSync, readFileSync } from 'node:fs'; +import { resolve } from 'node:path'; +import { fileURLToPath } from 'node:url'; + +const PORTLESS_PORT = 1355; +const scriptDir = fileURLToPath(new URL('.', import.meta.url)); +const workspaceRoot = resolve(scriptDir, '../..'); + +function readDotEnv(filePath) { + if (!existsSync(filePath)) return {}; + const result = {}; + for (const line of readFileSync(filePath, 'utf-8').split('\n')) { + const trimmed = line.trim(); + if (!trimmed || trimmed.startsWith('#')) continue; + const eqIdx = trimmed.indexOf('='); + if (eqIdx === -1) continue; + result[trimmed.slice(0, eqIdx)] = trimmed.slice(eqIdx + 1); + } + return result; +} + +function hostnameFrom(url) { + try { + return new URL(url).hostname; + } catch { + return null; + } +} + +/** Splice `.` in before `.localhost` in an existing hostname. */ +function applyWorktreeSuffix(hostname, worktreeName) { + if (!worktreeName) return hostname; + return hostname.replace('.localhost', `.${worktreeName}.localhost`); +} + +/** + * Returns all service hostnames scoped to the current worktree (if any). + * Hostname shapes are read from the tracked .env files — no names are + * hardcoded in this module. + */ +export function getHostnames() { + const uiEnv = readDotEnv(resolve(workspaceRoot, 'apps/ui-community/.env')); + const staffEnv = readDotEnv(resolve(workspaceRoot, 'apps/ui-staff/.env')); + const wt = process.env.WORKTREE_NAME ?? ''; + + const uiCommunity = hostnameFrom(uiEnv['VITE_APP_UI_COMMUNITY_BASE_URL'] ?? ''); + const api = hostnameFrom(uiEnv['VITE_COMMON_API_ENDPOINT'] ?? ''); + const mockAuth = hostnameFrom(uiEnv['VITE_APP_UI_COMMUNITY_B2C_AUTHORITY'] ?? ''); + const uiStaff = hostnameFrom(staffEnv['VITE_APP_UI_STAFF_AAD_REDIRECT_URI'] ?? ''); + + if (!uiCommunity || !api || !mockAuth || !uiStaff) { + throw new Error('portless-hostnames: could not derive all hostnames from .env files. ' + 'Ensure apps/ui-community/.env and apps/ui-staff/.env are present.'); + } + + return { + uiCommunity: applyWorktreeSuffix(uiCommunity, wt), + uiStaff: applyWorktreeSuffix(uiStaff, wt), + api: applyWorktreeSuffix(api, wt), + mockAuth: applyWorktreeSuffix(mockAuth, wt), + docs: applyWorktreeSuffix(`docs.${uiCommunity}`, wt), + }; +} + +/** + * Builds a full portless-proxied URL for the given hostname and optional path. + */ +export function buildPortlessUrl(hostname, path = '') { + return `https://${hostname}:${PORTLESS_PORT}${path}`; +} + +export { PORTLESS_PORT }; diff --git a/build-pipeline/scripts/worktree-ports.mjs b/build-pipeline/scripts/worktree-ports.mjs new file mode 100644 index 000000000..9a86b183c --- /dev/null +++ b/build-pipeline/scripts/worktree-ports.mjs @@ -0,0 +1,100 @@ +import fs from 'node:fs'; +import path from 'node:path'; +import { fileURLToPath } from 'node:url'; + +/** + * Worktree-scoped port computation for service isolation. + * + * When WORKTREE_NAME is set, each worktree gets a deterministic port offset + * so MongoDB and Azurite instances don't collide between worktrees. + * + * Default worktree (no WORKTREE_NAME): uses base ports (50000, 10000–10002). + * Named worktree: base + deterministic offset derived from the name's hash. + * + * Collision safety: the unset case always returns 0, and any named worktree + * always returns ≥ 100, so the default worktree can never collide with a + * named one. With 49 buckets the chance of two *named* worktrees colliding + * is ~2% per pair — acceptable for the typical 1–3 concurrent worktrees. + */ + +const workspaceRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..', '..'); +const apiLocalSettingsPaths = [path.join(workspaceRoot, 'apps', 'api', 'deploy', 'local.settings.json'), path.join(workspaceRoot, 'apps', 'api', 'local.settings.json')]; +let apiLocalSettingsValues; + +function getSetting(name) { + return process.env[name] ?? getApiLocalSetting(name); +} + +function getApiLocalSetting(name) { + apiLocalSettingsValues ??= readApiLocalSettingsValues(); + return apiLocalSettingsValues[name]; +} + +function readApiLocalSettingsValues() { + for (const settingsPath of apiLocalSettingsPaths) { + if (!fs.existsSync(settingsPath)) continue; + const settings = JSON.parse(fs.readFileSync(settingsPath, 'utf8')); + return settings.Values ?? {}; + } + return {}; +} + +/** + * Returns a deterministic port offset in the range [100, 4900] (step 100) + * for the current worktree. Returns 0 when WORKTREE_NAME is not set. + */ +export function getWorktreePortOffset() { + const name = process.env.WORKTREE_NAME; + if (!name) return 0; + let hash = 0; + for (const c of name) hash = ((hash << 5) - hash + c.charCodeAt(0)) | 0; + return ((Math.abs(hash) % 49) + 1) * 100; +} + +/** MongoDB port for the current worktree. */ +export function getMongoPort() { + return 50000 + getWorktreePortOffset(); +} + +/** Azurite blob/queue/table ports for the current worktree. */ +export function getAzuritePorts() { + const offset = getWorktreePortOffset(); + return { + blob: 10000 + offset, + queue: 10001 + offset, + table: 10002 + offset, + }; +} + +/** + * Azurite connection string for worktree-specific ports. + * Returns `UseDevelopmentStorage=true` for the default worktree (port 10000). + */ +export function getAzuriteConnectionString() { + const ports = getAzuritePorts(); + if (ports.blob === 10000) return 'UseDevelopmentStorage=true'; + const accountName = getSetting('STORAGE_ACCOUNT_NAME'); + const accountKey = getSetting('STORAGE_ACCOUNT_KEY'); + if (!accountName || !accountKey) { + throw new Error('[worktree-ports] STORAGE_ACCOUNT_NAME and STORAGE_ACCOUNT_KEY must be set to build a worktree Azurite connection string'); + } + return [ + 'DefaultEndpointsProtocol=http', + `AccountName=${accountName}`, + `AccountKey=${accountKey}`, + `BlobEndpoint=http://127.0.0.1:${ports.blob}/${accountName}`, + `QueueEndpoint=http://127.0.0.1:${ports.queue}/${accountName}`, + `TableEndpoint=http://127.0.0.1:${ports.table}/${accountName}`, + ].join(';'); +} + +/** + * MongoDB connection string with the worktree-specific port patched in. + * Reads COSMOSDB_CONNECTION_STRING from env or local.settings.json and replaces + * the host:port segment. + */ +export function getMongoConnectionString() { + const base = getSetting('COSMOSDB_CONNECTION_STRING'); + if (!base) throw new Error('[worktree-ports] COSMOSDB_CONNECTION_STRING must be set'); + return base.replace(/127\.0\.0\.1:\d+/, `127.0.0.1:${getMongoPort()}`); +} diff --git a/knip.json b/knip.json index 035e1f57f..4a560cc9a 100644 --- a/knip.json +++ b/knip.json @@ -2,8 +2,9 @@ "$schema": "https://unpkg.com/knip@5/schema.json", "workspaces": { "apps/api": { - "entry": ["src/index.ts"], - "project": ["src/**/*.ts"] + "entry": ["src/index.ts", "start-*.mjs"], + "project": ["src/**/*.ts", "*.mjs"], + "ignoreDependencies": ["azurite"] }, "apps/ui-community": { "entry": ["src/main.tsx"], diff --git a/package.json b/package.json index 12aea8a26..c1757bc2c 100644 --- a/package.json +++ b/package.json @@ -13,9 +13,11 @@ "test": "turbo run test", "lint": "turbo run lint", "dev": "pnpm proxy:stop && pnpm proxy:start && turbo watch azurite dev --filter='./apps/*' --filter='./packages/*'", + "dev:portless": "WORKTREE_NAME=$(basename $PWD) pnpm proxy:ensure && WORKTREE_NAME=$(basename $PWD) turbo watch azurite dev:portless --filter='./apps/*' --filter='./packages/*'", "start": "turbo run build && concurrently --kill-others-on-fail \"pnpm run start:api\" \"pnpm run start:ui-community\"", "proxy:stop": "pnpm exec portless proxy stop || true", "proxy:start": "pnpm exec portless proxy start --https -p 1355", + "proxy:ensure": "pnpm exec portless proxy start --https -p 1355 || true", "format": "turbo run format", "format:check": "turbo run format:check", "format:staged": "biome check --write --staged --no-errors-on-unmatched", @@ -31,6 +33,7 @@ "test:coverage": "turbo run test:coverage", "test:coverage:merge": "pnpm run test:coverage && pnpm run merge-lcov-reports", "test:e2e": "turbo run test:e2e --filter=@ocom-verification/e2e-tests", + "test:e2e:portless": "WORKTREE_NAME=$(basename $PWD) turbo run test:e2e --filter=@ocom-verification/e2e-tests", "test:acceptance": "turbo run test:acceptance --filter=@ocom-verification/acceptance-api --filter=@ocom-verification/acceptance-ui", "merge-lcov-reports": "node build-pipeline/scripts/merge-coverage.js", "test:integration": "turbo run test:integration", @@ -77,7 +80,6 @@ "@types/node": "catalog:", "@typescript/native-preview": "catalog:", "@vitest/coverage-istanbul": "catalog:", - "azurite": "^3.35.0", "chrome-devtools-mcp": "^0.21.0", "concurrently": "^9.1.2", "husky": "^9.1.7", diff --git a/packages/cellix/server-oauth2-mock-seedwork/package.json b/packages/cellix/server-oauth2-mock-seedwork/package.json index ef0015814..68da0838b 100644 --- a/packages/cellix/server-oauth2-mock-seedwork/package.json +++ b/packages/cellix/server-oauth2-mock-seedwork/package.json @@ -18,7 +18,7 @@ "test:watch": "vitest" }, "dependencies": { - "express": "^4.22.0", + "express": "^4.22.2", "express-rate-limit": "^8.5.1", "jose": "^5.9.6" }, diff --git a/packages/ocom-verification/e2e-tests/cucumber.js b/packages/ocom-verification/e2e-tests/cucumber.js index 339a66b11..51912f713 100644 --- a/packages/ocom-verification/e2e-tests/cucumber.js +++ b/packages/ocom-verification/e2e-tests/cucumber.js @@ -7,5 +7,5 @@ export default { formatOptions: { snippetInterface: 'async-await', }, - parallel: 1, + parallel: 0, }; diff --git a/packages/ocom-verification/e2e-tests/package.json b/packages/ocom-verification/e2e-tests/package.json index cbe99de57..6d3508bc6 100644 --- a/packages/ocom-verification/e2e-tests/package.json +++ b/packages/ocom-verification/e2e-tests/package.json @@ -5,7 +5,9 @@ "private": true, "type": "module", "scripts": { - "test:e2e": "NODE_EXTRA_CA_CERTS=${HOME}/.portless/ca.pem LOG_LEVEL=warn NODE_OPTIONS='--import tsx/esm' cucumber-js", + "test:e2e": "pnpm run proxy:start && pnpm run test:e2e:run", + "test:e2e:run": "NODE_EXTRA_CA_CERTS=${HOME}/.portless/ca.pem LOG_LEVEL=warn NODE_OPTIONS='--import tsx/esm' cucumber-js", + "proxy:start": "pnpm exec portless proxy start -p 1355", "playwright:install": "playwright install chromium", "clean": "rimraf dist reports target" }, diff --git a/packages/ocom-verification/e2e-tests/src/shared/support/oauth2-login.ts b/packages/ocom-verification/e2e-tests/src/shared/support/oauth2-login.ts index b5db83c66..abc2b4638 100644 --- a/packages/ocom-verification/e2e-tests/src/shared/support/oauth2-login.ts +++ b/packages/ocom-verification/e2e-tests/src/shared/support/oauth2-login.ts @@ -15,8 +15,8 @@ const isPostAuthUrl = (url: URL) => !url.hostname.includes('mock-auth') && !url. * The app uses RequireAuth + react-oidc-context. When an unauthenticated * user hits a protected route, RequireAuth calls `signinRedirect()` which * navigates to the mock OAuth2 server's `/authorize` endpoint. The mock - * server auto-completes the flow (no login form) and redirects back with a - * code that the OIDC library exchanges for tokens. + * server redirects to `/login` (since userStore is configured). This + * function fills in the test user credentials and submits the form. */ export async function performOAuth2Login(page: Page): Promise { // Navigate to a protected route to trigger the OIDC signinRedirect flow. @@ -29,6 +29,16 @@ export async function performOAuth2Login(page: Page): Promise { // Navigation may be interrupted by OIDC redirect — this is expected } + // Wait for redirects to settle on either the login page or the app + await page.waitForLoadState('domcontentloaded', { timeout: 10_000 }).catch(() => undefined); + + // If the mock OAuth2 login form is shown, fill credentials and submit + if (page.url().includes('/login')) { + await page.fill('input[name="username"]', 'test@example.com'); + await page.fill('input[name="password"]', 'password'); + await page.click('button[type="submit"]'); + } + // Wait for the redirect chain to settle on an authenticated page await page.waitForURL(isPostAuthUrl, { timeout: 30_000 }); await page.waitForLoadState('networkidle'); diff --git a/packages/ocom-verification/e2e-tests/src/shared/support/servers/index.ts b/packages/ocom-verification/e2e-tests/src/shared/support/servers/index.ts index 6f2cca847..c096f6636 100644 --- a/packages/ocom-verification/e2e-tests/src/shared/support/servers/index.ts +++ b/packages/ocom-verification/e2e-tests/src/shared/support/servers/index.ts @@ -1,6 +1,14 @@ export { MongoDBTestServer } from '@ocom-verification/verification-shared/servers'; export { PortlessServer } from './portless-server.ts'; export { TestApiServer } from './test-api-server.ts'; -export { buildUrl, cleanupTestEnvironment, initTestEnvironment, setMongoConnectionString } from './test-environment.ts'; +export { TestCommunityViteServer } from './test-community-vite-server.ts'; +export { + buildUrl, + cleanupTestEnvironment, + initTestEnvironment, + mockOidcAudience, + mockOidcEndpoint, + mockOidcIssuer, + setMongoConnectionString, +} from './test-environment.ts'; export { TestOAuth2Server } from './test-oauth2-server.ts'; -export { TestViteServer } from './test-vite-server.ts'; diff --git a/packages/ocom-verification/e2e-tests/src/shared/support/servers/portless-server.ts b/packages/ocom-verification/e2e-tests/src/shared/support/servers/portless-server.ts index 8b78c1c02..aea6c3ab1 100644 --- a/packages/ocom-verification/e2e-tests/src/shared/support/servers/portless-server.ts +++ b/packages/ocom-verification/e2e-tests/src/shared/support/servers/portless-server.ts @@ -1,37 +1,69 @@ import { type ChildProcess, spawn } from 'node:child_process'; +import type { TestServer } from '@ocom-verification/verification-shared/servers'; +import { getTimeout } from '@ocom-verification/verification-shared/settings'; import { getPortlessPath } from './resolve-portless.ts'; /** * Abstract base class for portless-proxied servers. * Subclasses define the hostname, command, ready marker, and working directory. * The base class handles spawning via portless, readiness detection, and shutdown. + * + * This implements the TestServer interface for consistency with + * GraphQLTestServer (in-process), while providing subprocess isolation + * for full system tests. */ -export abstract class PortlessServer { +export abstract class PortlessServer implements TestServer { private process: ChildProcess | null = null; private startedByUs = false; + private readonly useDetachedProcessGroup = process.platform !== 'win32'; protected abstract get probeUrl(): string; protected abstract get readyMarker(): string; protected abstract get serverName(): string; - protected abstract get startupTimeoutMs(): number; protected abstract get spawnArgs(): string[]; protected abstract get cwd(): string; + + protected get executable(): string { + return getPortlessPath(); + } + + protected get probeRequestInit(): RequestInit { + return {}; + } + protected get extraEnv(): Record { return {}; } + protected isProbeHealthy(response: Response): boolean | Promise { + return response.ok; + } + + protected get startupTimeoutMs(): number { + return getTimeout('serverStartup'); + } + + abstract getUrl(): string; + + /** + * Check if server is already running (via health probe). + */ async isAlreadyRunning(): Promise { try { const controller = new AbortController(); - const timeout = setTimeout(() => controller.abort(), 3_000); - const res = await fetch(this.probeUrl, { signal: controller.signal }); + const probeTimeout = getTimeout('healthProbe'); + const timeout = setTimeout(() => controller.abort(), probeTimeout); + const res = await fetch(this.probeUrl, { ...this.probeRequestInit, signal: controller.signal }); clearTimeout(timeout); - return res.ok; + return await this.isProbeHealthy(res); } catch { return false; } } + /** + * Start the server subprocess and wait for it to be ready. + */ async start(): Promise { if (this.process || this.startedByUs) return; if (await this.isAlreadyRunning()) return; @@ -43,9 +75,10 @@ export abstract class PortlessServer { // Remove NODE_OPTIONS from child process to avoid tsx import issues delete env['NODE_OPTIONS']; - this.process = spawn(getPortlessPath(), this.spawnArgs, { + this.process = spawn(this.executable, this.spawnArgs, { cwd: this.cwd, env, + detached: this.useDetachedProcessGroup, stdio: ['ignore', 'pipe', 'pipe'], }); this.startedByUs = true; @@ -53,6 +86,9 @@ export abstract class PortlessServer { await this.waitForReady(); } + /** + * Stop the server gracefully, with fallback to SIGKILL. + */ async stop(): Promise { if (!this.process || !this.startedByUs) return; @@ -60,13 +96,17 @@ export abstract class PortlessServer { this.process = null; this.startedByUs = false; - proc.kill('SIGTERM'); + // SIGINT lets portless run its cleanup branch — deregister the hostname from + // ~/.portless/routes.json before exiting. Fall back to SIGKILL after the + // shutdown timeout for anything that ignores SIGINT. + this.killProcess(proc, 'SIGINT'); + const shutdownTimeout = getTimeout('serverShutdown'); await new Promise((resolve) => { const timeout = setTimeout(() => { - proc.kill('SIGKILL'); + this.killProcess(proc, 'SIGKILL'); resolve(); - }, 10_000); + }, shutdownTimeout); proc.on('exit', () => { clearTimeout(timeout); @@ -87,16 +127,34 @@ export abstract class PortlessServer { return; } + const startupTimeout = this.startupTimeoutMs; const timeout = setTimeout(() => { - reject(new Error(`${this.serverName} did not start within ${this.startupTimeoutMs}ms`)); - }, this.startupTimeoutMs); + reject(new Error(`${this.serverName} did not start within ${startupTimeout}ms`)); + }, startupTimeout); let stderrOutput = ''; - + let ready = false; + + const resolveWhenReachable = () => { + if (ready) return; + ready = true; + + this.waitForProbeReady() + .then(() => { + clearTimeout(timeout); + resolve(); + }) + .catch((error: unknown) => { + clearTimeout(timeout); + reject(error); + }); + }; + + // stdout listener detects the readyMarker then waits for the probe to respond proc.stdout?.on('data', (data: Buffer) => { - if (data.toString().includes(this.readyMarker)) { - clearTimeout(timeout); - resolve(); + const text = data.toString(); + if (text.includes(this.readyMarker)) { + resolveWhenReachable(); } }); @@ -104,19 +162,36 @@ export abstract class PortlessServer { stderrOutput += data.toString(); }); - proc.on('error', (err) => { + proc.on('error', (err: Error) => { clearTimeout(timeout); - this.process = null; - this.startedByUs = false; reject(new Error(`${this.serverName} failed to start: ${err.message}`)); }); - proc.on('exit', (code) => { + proc.on('exit', (code, signal) => { clearTimeout(timeout); this.process = null; this.startedByUs = false; - reject(new Error(`${this.serverName} exited unexpectedly (code: ${code}). stderr: ${stderrOutput.slice(-2000)}`)); + reject(new Error(`${this.serverName} exited unexpectedly (code: ${code}, signal: ${signal}). stderr: ${stderrOutput.slice(-2000)}`)); }); }); } + + private async waitForProbeReady(): Promise { + const probeInterval = getTimeout('healthProbeInterval'); + while (!(await this.isAlreadyRunning())) { + await new Promise((resolve) => setTimeout(resolve, probeInterval)); + } + } + + private killProcess(proc: ChildProcess, signal: NodeJS.Signals): void { + if (this.useDetachedProcessGroup && proc.pid) { + try { + process.kill(-proc.pid, signal); + return; + } catch { + /* Fall back to killing the direct child below. */ + } + } + proc.kill(signal); + } } diff --git a/packages/ocom-verification/e2e-tests/src/shared/support/servers/test-api-server.ts b/packages/ocom-verification/e2e-tests/src/shared/support/servers/test-api-server.ts index 84a87174a..380249d50 100644 --- a/packages/ocom-verification/e2e-tests/src/shared/support/servers/test-api-server.ts +++ b/packages/ocom-verification/e2e-tests/src/shared/support/servers/test-api-server.ts @@ -1,7 +1,9 @@ import { execFileSync } from 'node:child_process'; import { apiSettings } from '@ocom-verification/verification-shared/settings'; import { PortlessServer } from './portless-server.ts'; -import { buildUrl, getMongoConnectionString } from './test-environment.ts'; +import { buildUrl, getHostnames, getMongoConnectionString, mockOidcAudience, mockOidcEndpoint, mockOidcIssuer } from './test-environment.ts'; + +const hostnames = getHostnames(); export class TestApiServer extends PortlessServer { override async start(): Promise { @@ -10,7 +12,7 @@ export class TestApiServer extends PortlessServer { const env = { ...process.env, }; - delete env.NODE_OPTIONS; + delete env['NODE_OPTIONS']; execFileSync('pnpm', ['run', 'predev'], { cwd: this.cwd, @@ -22,19 +24,35 @@ export class TestApiServer extends PortlessServer { } protected get probeUrl() { - return buildUrl('data-access.ownercommunity.localhost', '/api/graphql'); + return buildUrl(hostnames.api, '/api/graphql'); + } + + protected override get probeRequestInit(): RequestInit { + return { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ query: '{ __typename }' }), + }; } + + protected override async isProbeHealthy(response: Response): Promise { + if (!response.ok) return false; + try { + const data = (await response.json()) as { data?: { __typename?: string } }; + return data?.data?.__typename === 'Query'; + } catch { + return false; + } + } + protected get readyMarker() { return 'Functions:'; } protected get serverName() { return 'TestApiServer'; } - protected get startupTimeoutMs() { - return 120_000; - } protected get spawnArgs() { - return ['data-access.ownercommunity.localhost', 'node', 'start-dev.mjs']; + return [hostnames.api, 'node', 'start-dev.mjs']; } protected get cwd() { return apiSettings.apiDir; @@ -42,15 +60,24 @@ export class TestApiServer extends PortlessServer { protected override get extraEnv() { return { + NODE_ENV: 'development', languageWorkers__node__arguments: '', COSMOSDB_CONNECTION_STRING: getMongoConnectionString(), - ACCOUNT_PORTAL_OIDC_ISSUER: apiSettings.accountPortalOidcIssuer, - ACCOUNT_PORTAL_OIDC_ENDPOINT: apiSettings.accountPortalOidcEndpoint, - VITE_COMMON_API_ENDPOINT: buildUrl('data-access.ownercommunity.localhost', '/api/graphql'), + COSMOSDB_DBNAME: apiSettings.cosmosDbName, + AZURE_STORAGE_CONNECTION_STRING: 'UseDevelopmentStorage=true', + ACCOUNT_PORTAL_OIDC_ISSUER: mockOidcIssuer, + ACCOUNT_PORTAL_OIDC_ENDPOINT: mockOidcEndpoint, + ACCOUNT_PORTAL_OIDC_AUDIENCE: mockOidcAudience, + ACCOUNT_PORTAL_OIDC_IGNORE_ISSUER: 'true', + STAFF_PORTAL_OIDC_ISSUER: mockOidcIssuer, + STAFF_PORTAL_OIDC_ENDPOINT: mockOidcEndpoint, + STAFF_PORTAL_OIDC_AUDIENCE: mockOidcAudience, + STAFF_PORTAL_OIDC_IGNORE_ISSUER: 'true', + VITE_COMMON_API_ENDPOINT: buildUrl(hostnames.api, '/api/graphql'), }; } getUrl(): string { - return buildUrl('data-access.ownercommunity.localhost', '/api/graphql'); + return buildUrl(hostnames.api, '/api/graphql'); } } diff --git a/packages/ocom-verification/e2e-tests/src/shared/support/servers/test-community-vite-server.ts b/packages/ocom-verification/e2e-tests/src/shared/support/servers/test-community-vite-server.ts new file mode 100644 index 000000000..8de00bfca --- /dev/null +++ b/packages/ocom-verification/e2e-tests/src/shared/support/servers/test-community-vite-server.ts @@ -0,0 +1,40 @@ +import { apiSettings } from '@ocom-verification/verification-shared/settings'; +import { PortlessServer } from './portless-server.ts'; +import { buildUrl, getHostnames } from './test-environment.ts'; + +const hostnames = getHostnames(); + +/** + * Starts the community portal Vite dev server via portless. + * + * The `apps/ui-community/start-dev.mjs` script sets all VITE_* environment + * variables at runtime using portless-hostnames.mjs, so no extraEnv overrides + * are needed here beyond suppressing browser auto-launch. + */ +export class TestCommunityViteServer extends PortlessServer { + protected get probeUrl() { + return buildUrl(hostnames.uiCommunity); + } + protected get readyMarker() { + return 'ready in'; + } + protected get serverName() { + return 'TestCommunityViteServer'; + } + protected get spawnArgs() { + return [hostnames.uiCommunity, 'node', 'start-dev.mjs']; + } + protected get cwd() { + return apiSettings.uiCommunityDir; + } + protected override get extraEnv() { + return { + BROWSER: 'none', + NODE_ENV: 'development', + }; + } + + getUrl(): string { + return buildUrl(hostnames.uiCommunity); + } +} diff --git a/packages/ocom-verification/e2e-tests/src/shared/support/servers/test-environment.ts b/packages/ocom-verification/e2e-tests/src/shared/support/servers/test-environment.ts index 76c9a1d8d..4a8fbb54f 100644 --- a/packages/ocom-verification/e2e-tests/src/shared/support/servers/test-environment.ts +++ b/packages/ocom-verification/e2e-tests/src/shared/support/servers/test-environment.ts @@ -1,30 +1,48 @@ import { execFileSync } from 'node:child_process'; +import { buildPortlessUrl, getHostnames } from '@ocom-verification/verification-shared/settings'; import { getPortlessPath } from './resolve-portless.ts'; let proxyInitialized = false; let mongoConnectionString: string | undefined; +/** Module-level hostnames derived from .env files (matches dev:portless pattern). */ +const hostnames = getHostnames(); + +/** OIDC issuer URL for the community portal on the mock auth server. */ +export const mockOidcIssuer = buildPortlessUrl(hostnames.mockAuth, '/community'); + +/** JWKS endpoint used as the OIDC discovery / probe URL. */ +export const mockOidcEndpoint = `${mockOidcIssuer}/.well-known/jwks.json`; + +/** Audience claim expected in JWTs issued by the mock OIDC server. */ +export const mockOidcAudience = 'mock-client'; + +/** + * Prune orphaned portless route locks from previous test runs. + * The proxy itself is started by the `test:e2e` npm script before the + * Cucumber process spawns, so we only need to clean stale locks here. + */ export function initTestEnvironment() { if (proxyInitialized) return; - execFileSync(getPortlessPath(), ['proxy', 'start', '-p', '1355'], { - timeout: 15_000, + execFileSync(getPortlessPath(), ['prune'], { + timeout: 10_000, stdio: 'pipe', }); proxyInitialized = true; } -export function buildUrl(hostname: string, path = ''): string { - return `https://${hostname}:1355${path}`; -} +export { buildPortlessUrl as buildUrl, getHostnames }; export function setMongoConnectionString(connStr: string): void { mongoConnectionString = connStr; } export function getMongoConnectionString(): string { - if (!mongoConnectionString) throw new Error('MongoDB connection string not set. Start MongoDBTestServer first.'); + if (!mongoConnectionString) { + throw new Error('MongoDB connection string not set — call setMongoConnectionString() first'); + } return mongoConnectionString; } diff --git a/packages/ocom-verification/e2e-tests/src/shared/support/servers/test-oauth2-server.ts b/packages/ocom-verification/e2e-tests/src/shared/support/servers/test-oauth2-server.ts index 319f80830..7d843f446 100644 --- a/packages/ocom-verification/e2e-tests/src/shared/support/servers/test-oauth2-server.ts +++ b/packages/ocom-verification/e2e-tests/src/shared/support/servers/test-oauth2-server.ts @@ -1,81 +1,33 @@ import { apiSettings } from '@ocom-verification/verification-shared/settings'; import { PortlessServer } from './portless-server.ts'; -import { buildUrl } from './test-environment.ts'; +import { getHostnames, mockOidcEndpoint, mockOidcIssuer } from './test-environment.ts'; +const hostnames = getHostnames(); + +/** + * Starts the mock OAuth2/OIDC server via portless. + * + * Login is performed by the browser context in oauth2-login.ts rather than + * by programmatic token generation — this tests the real OIDC redirect flow. + */ export class TestOAuth2Server extends PortlessServer { protected get probeUrl() { - return apiSettings.accountPortalOidcEndpoint; + return mockOidcEndpoint; } protected get readyMarker() { - return 'Mock OAuth2 server running'; + return 'Registered OIDC config'; } protected get serverName() { return 'TestOAuth2Server'; } - protected get startupTimeoutMs() { - return 30_000; - } protected get spawnArgs() { - return ['mock-auth.ownercommunity.localhost', 'pnpm', 'exec', 'tsx', 'src/index.ts']; + return [hostnames.mockAuth, 'node', 'start-dev.mjs']; } protected get cwd() { return apiSettings.oauth2MockDir; } - private readonly testUser: { - email: string; - given_name: string; - family_name: string; - }; - - constructor(options?: { - testUser?: { - email?: string; - given_name?: string; - family_name?: string; - }; - }) { - super(); - this.testUser = { - email: options?.testUser?.email ?? 'alice@test.cellix.local', - given_name: options?.testUser?.given_name ?? 'Alice', - family_name: options?.testUser?.family_name ?? 'Test', - }; - } - - protected override get extraEnv() { - return { - EMAIL: this.testUser.email, - GIVEN_NAME: this.testUser.given_name, - FAMILY_NAME: this.testUser.family_name, - BASE_URL: buildUrl('mock-auth.ownercommunity.localhost'), - ALLOWED_REDIRECT_URI: buildUrl('ownercommunity.localhost', '/auth-redirect'), - CLIENT_ID: apiSettings.accountPortalOidcAudience, - }; - } - getUrl(): string { - return apiSettings.accountPortalOidcIssuer; - } - - async generateAccessToken(_audience = 'mock-client'): Promise { - const issuer = this.getUrl(); - const uiBaseUrl = buildUrl('ownercommunity.localhost'); - const redirectUri = `${uiBaseUrl}/auth-redirect`; - - const code = `mock-auth-code-${Buffer.from(redirectUri).toString('base64')}`; - - const response = await fetch(`${issuer}/token`, { - method: 'POST', - headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify({ code, grant_type: 'authorization_code' }), - }); - - if (!response.ok) { - throw new Error(`Token request failed: ${response.status} ${await response.text()}`); - } - - const data = (await response.json()) as { access_token: string }; - return data.access_token; + return mockOidcIssuer; } } diff --git a/packages/ocom-verification/e2e-tests/src/shared/support/servers/test-vite-server.ts b/packages/ocom-verification/e2e-tests/src/shared/support/servers/test-vite-server.ts deleted file mode 100644 index 44ede2444..000000000 --- a/packages/ocom-verification/e2e-tests/src/shared/support/servers/test-vite-server.ts +++ /dev/null @@ -1,41 +0,0 @@ -import { apiSettings } from '@ocom-verification/verification-shared/settings'; -import { PortlessServer } from './portless-server.ts'; -import { buildUrl } from './test-environment.ts'; - -export class TestViteServer extends PortlessServer { - protected get probeUrl() { - return buildUrl('ownercommunity.localhost'); - } - protected get readyMarker() { - return 'ready in'; - } - protected get serverName() { - return 'TestViteServer'; - } - protected get startupTimeoutMs() { - return 60_000; - } - protected get spawnArgs() { - return ['ownercommunity.localhost', 'pnpm', 'exec', 'vite']; - } - protected get cwd() { - return apiSettings.uiDir; - } - - protected override get extraEnv() { - const uiBase = buildUrl('ownercommunity.localhost'); - const apiEndpoint = buildUrl('data-access.ownercommunity.localhost', '/api/graphql'); - - return { - BROWSER: 'none', - VITE_APP_UI_COMMUNITY_BASE_URL: uiBase, - VITE_AAD_B2C_ACCOUNT_AUTHORITY: apiSettings.accountPortalOidcIssuer, - VITE_AAD_B2C_REDIRECT_URI: `${uiBase}/auth-redirect`, - VITE_COMMON_API_ENDPOINT: apiEndpoint, - }; - } - - getUrl(): string { - return buildUrl('ownercommunity.localhost'); - } -} diff --git a/packages/ocom-verification/e2e-tests/src/shared/support/shared-infrastructure.ts b/packages/ocom-verification/e2e-tests/src/shared/support/shared-infrastructure.ts index d3d2c3ece..e91cca9b9 100644 --- a/packages/ocom-verification/e2e-tests/src/shared/support/shared-infrastructure.ts +++ b/packages/ocom-verification/e2e-tests/src/shared/support/shared-infrastructure.ts @@ -1,29 +1,41 @@ -import { apiSettings } from '@ocom-verification/verification-shared/settings'; -import { actors } from '@ocom-verification/verification-shared/test-data'; import playwright, { type Browser, type BrowserContext } from 'playwright'; import { BrowseTheWeb } from '../abilities/browse-the-web.ts'; import { performOAuth2Login } from './oauth2-login.ts'; -import { cleanupTestEnvironment, initTestEnvironment, MongoDBTestServer, setMongoConnectionString, TestApiServer, TestOAuth2Server, TestViteServer } from './servers/index.ts'; +import { cleanupTestEnvironment, initTestEnvironment, MongoDBTestServer, setMongoConnectionString, TestApiServer, TestCommunityViteServer, TestOAuth2Server } from './servers/index.ts'; let mongoDBServer: MongoDBTestServer | undefined; let oauth2Server: TestOAuth2Server | undefined; let apiServer: TestApiServer | undefined; -let viteServer: TestViteServer | undefined; +let viteServer: TestCommunityViteServer | undefined; let apiUrl: string | undefined; -let accessToken: string | undefined; let browser: Browser | undefined; let browserBaseUrl: string | undefined; let authenticatedBrowserContext: BrowserContext | undefined; let browseTheWeb: BrowseTheWeb | undefined; +let shutdownHandlersRegistered = false; + +function registerShutdownHandlers(): void { + if (shutdownHandlersRegistered) return; + shutdownHandlersRegistered = true; + + const shutdown = (signal: string) => { + void stopAll().finally(() => { + process.exit(signal === 'SIGINT' ? 130 : 143); + }); + }; + + process.once('SIGINT', () => shutdown('SIGINT')); + process.once('SIGTERM', () => shutdown('SIGTERM')); +} + export interface InfrastructureState { apiUrl: string | undefined; - accessToken: string | undefined; browseTheWeb: BrowseTheWeb | undefined; } export function getState(): InfrastructureState { - return { apiUrl, accessToken, browseTheWeb }; + return { apiUrl, browseTheWeb }; } export async function stopAll(): Promise { @@ -56,22 +68,16 @@ export async function stopAll(): Promise { } apiUrl = undefined; browserBaseUrl = undefined; - accessToken = undefined; cleanupTestEnvironment(); } export async function ensureE2EServers(): Promise { + registerShutdownHandlers(); initTestEnvironment(); // Phase 1: Start MongoDB and OAuth2 in parallel (no interdependency) mongoDBServer ??= new MongoDBTestServer(); - oauth2Server ??= new TestOAuth2Server({ - testUser: { - email: actors.CommunityOwner.email, - given_name: actors.CommunityOwner.givenName, - family_name: actors.CommunityOwner.familyName, - }, - }); + oauth2Server ??= new TestOAuth2Server(); const mongo = mongoDBServer; const oauth2 = oauth2Server; const phase1: Promise[] = []; @@ -83,9 +89,9 @@ export async function ensureE2EServers(): Promise { } if (phase1.length > 0) await Promise.all(phase1); - // Phase 2: Start API (needs MongoDB conn string), Vite (independent), and generate token (needs OAuth2) in parallel + // Phase 2: Start API (needs MongoDB conn string) and Vite (independent) in parallel apiServer ??= new TestApiServer(); - viteServer ??= new TestViteServer(); + viteServer ??= new TestCommunityViteServer(); const api = apiServer; const vite = viteServer; const phase2: Promise[] = []; @@ -99,13 +105,6 @@ export async function ensureE2EServers(): Promise { if (!vite.isRunning()) { phase2.push(vite.start()); } - if (!accessToken) { - phase2.push( - oauth2.generateAccessToken(apiSettings.accountPortalOidcAudience).then((token) => { - accessToken = token; - }), - ); - } if (phase2.length > 0) await Promise.all(phase2); browserBaseUrl = viteServer.getUrl(); diff --git a/packages/ocom-verification/verification-shared/src/servers/index.ts b/packages/ocom-verification/verification-shared/src/servers/index.ts index 585f779f2..32810914a 100644 --- a/packages/ocom-verification/verification-shared/src/servers/index.ts +++ b/packages/ocom-verification/verification-shared/src/servers/index.ts @@ -7,3 +7,4 @@ export { MongoDBTestServer, seedOwnerCommunityReferenceData, } from './test-mongodb-server.ts'; +export type { TestServer, TestServerOptions } from './test-server.interface.ts'; diff --git a/packages/ocom-verification/verification-shared/src/servers/test-server.interface.ts b/packages/ocom-verification/verification-shared/src/servers/test-server.interface.ts new file mode 100644 index 000000000..8b08f6b92 --- /dev/null +++ b/packages/ocom-verification/verification-shared/src/servers/test-server.interface.ts @@ -0,0 +1,40 @@ +/** + * Common interface for all test servers (in-process and subprocess). + * + * This abstraction allows acceptance-api and e2e tests to use + * consistent server lifecycle management patterns while choosing + * the appropriate implementation: + * + * - **In-process** (GraphQLTestServer): Fast, isolated, mocked services + * Best for: API acceptance tests, unit-like integration tests + * + * - **Subprocess** (PortlessServer): Full stack, realistic, real services + * Best for: E2E tests, full system integration tests + */ +export interface TestServer { + /** Start the server and return when ready */ + start(): Promise; + + /** Stop the server gracefully */ + stop(): Promise; + + /** Check if server is currently running */ + isRunning(): boolean; + + /** Get the server URL (throws if not running) */ + getUrl(): string; +} + +/** + * Configuration options for test server startup. + */ +export interface TestServerOptions { + /** Port to listen on (0 for random available port) */ + port?: number; + + /** Additional environment variables for subprocess servers */ + env?: Record; + + /** Timeout for server startup (defaults to centralized config) */ + startupTimeoutMs?: number; +} diff --git a/packages/ocom-verification/verification-shared/src/settings/index.ts b/packages/ocom-verification/verification-shared/src/settings/index.ts index 88ed046dd..68ac69337 100644 --- a/packages/ocom-verification/verification-shared/src/settings/index.ts +++ b/packages/ocom-verification/verification-shared/src/settings/index.ts @@ -1,4 +1,5 @@ export { apiSettings, uiSettings } from './local-settings.ts'; +export { buildPortlessUrl, getHostnames, PORTLESS_PORT } from './portless-settings.ts'; export { findWorkspaceRoot, readDotEnv, @@ -7,3 +8,4 @@ export { requireSetting, resolveWorkspacePath, } from './settings-utils.ts'; +export { getTimeout, type TimeoutKey, timeouts } from './timeout-settings.ts'; diff --git a/packages/ocom-verification/verification-shared/src/settings/local-settings.ts b/packages/ocom-verification/verification-shared/src/settings/local-settings.ts index e1a03e801..c28d7a6f5 100644 --- a/packages/ocom-verification/verification-shared/src/settings/local-settings.ts +++ b/packages/ocom-verification/verification-shared/src/settings/local-settings.ts @@ -8,21 +8,40 @@ const uiEnvPath = resolveWorkspacePath(workspaceRoot, 'apps/ui-community/.env'); const apiValues = readJsonSettings(apiSettingsPath); const uiValues = readDotEnv(uiEnvPath); +/** + * Defaults for E2E/acceptance test settings when local.settings.json is absent + * (e.g. CI pipelines). All values are non-secret mock/localhost references used + * exclusively by the test harness — no real credentials are involved. + */ +const ciDefaults = { + COSMOSDB_CONNECTION_STRING: '', + COSMOSDB_DBNAME: 'owner-community', + COSMOSDB_PORT: '50000', + NODE_ENV: 'development', + ACCOUNT_PORTAL_OIDC_AUDIENCE: 'mock-client', + ACCOUNT_PORTAL_OIDC_ISSUER: 'https://mock-auth.ownercommunity.localhost:1355/community', + ACCOUNT_PORTAL_OIDC_ENDPOINT: 'https://mock-auth.ownercommunity.localhost:1355/community/.well-known/jwks.json', +} as const; + +function setting(key: keyof typeof ciDefaults): string { + return readSetting(apiValues, key, ciDefaults[key]) ?? ciDefaults[key]; +} + export const apiSettings = { - nodeEnv: readSetting(apiValues, 'NODE_ENV', 'development') ?? 'development', - isDevelopment: (readSetting(apiValues, 'NODE_ENV', 'development') ?? 'development') === 'development', + nodeEnv: setting('NODE_ENV'), + isDevelopment: setting('NODE_ENV') === 'development', - cosmosDbConnectionString: readSetting(apiValues, 'COSMOSDB_CONNECTION_STRING') ?? '', - cosmosDbName: readSetting(apiValues, 'COSMOSDB_DBNAME', 'owner-community') ?? 'owner-community', - cosmosDbPort: Number(readSetting(apiValues, 'COSMOSDB_PORT', '50000')), + cosmosDbConnectionString: setting('COSMOSDB_CONNECTION_STRING'), + cosmosDbName: setting('COSMOSDB_DBNAME'), + cosmosDbPort: Number(setting('COSMOSDB_PORT')), - accountPortalOidcIssuer: readSetting(apiValues, 'ACCOUNT_PORTAL_OIDC_ISSUER') ?? '', - accountPortalOidcEndpoint: readSetting(apiValues, 'ACCOUNT_PORTAL_OIDC_ENDPOINT') ?? '', - accountPortalOidcAudience: readSetting(apiValues, 'ACCOUNT_PORTAL_OIDC_AUDIENCE', 'mock-client') ?? '', + accountPortalOidcIssuer: setting('ACCOUNT_PORTAL_OIDC_ISSUER'), + accountPortalOidcEndpoint: setting('ACCOUNT_PORTAL_OIDC_ENDPOINT'), + accountPortalOidcAudience: setting('ACCOUNT_PORTAL_OIDC_AUDIENCE'), apiDir: path.dirname(apiSettingsPath), oauth2MockDir: path.join(workspaceRoot, 'apps', 'server-oauth2-mock'), - uiDir: path.dirname(uiEnvPath), + uiCommunityDir: path.dirname(uiEnvPath), } as const; export const uiSettings = { diff --git a/packages/ocom-verification/verification-shared/src/settings/portless-settings.ts b/packages/ocom-verification/verification-shared/src/settings/portless-settings.ts new file mode 100644 index 000000000..e084702e0 --- /dev/null +++ b/packages/ocom-verification/verification-shared/src/settings/portless-settings.ts @@ -0,0 +1,65 @@ +/** + * Portless hostname derivation for test environments. + * + * Mirrors the logic of `build-pipeline/scripts/portless-hostnames.mjs` — + * hostnames are derived from the tracked .env files rather than hardcoded, + * and the `WORKTREE_NAME` suffix is applied automatically. + * + * This keeps test-environment code in sync with the dev:portless startup + * scripts without adding a cross-layer import to build-pipeline/. + */ + +import { findWorkspaceRoot, readDotEnv, resolveWorkspacePath } from './settings-utils.ts'; + +const PORTLESS_PORT = 1355; +const workspaceRoot = findWorkspaceRoot(); + +const uiCommunityEnv = readDotEnv(resolveWorkspacePath(workspaceRoot, 'apps/ui-community/.env')); +const uiStaffEnv = readDotEnv(resolveWorkspacePath(workspaceRoot, 'apps/ui-staff/.env')); + +function hostnameFromUrl(url: string): string { + try { + return new URL(url).hostname; + } catch { + return ''; + } +} + +/** Splice `.` in before `.localhost` for worktree isolation. */ +function applyWorktreeSuffix(hostname: string): string { + const wt = process.env['WORKTREE_NAME']; + if (!wt) return hostname; + return hostname.replace('.localhost', `.${wt}.localhost`); +} + +/** + * Returns all portless service hostnames scoped to the current worktree. + * Hostnames are derived from the tracked .env files — no names are hardcoded. + */ +export function getHostnames() { + const uiCommunity = hostnameFromUrl(uiCommunityEnv['VITE_APP_UI_COMMUNITY_BASE_URL'] ?? ''); + const api = hostnameFromUrl(uiCommunityEnv['VITE_COMMON_API_ENDPOINT'] ?? ''); + const mockAuth = hostnameFromUrl(uiCommunityEnv['VITE_APP_UI_COMMUNITY_B2C_AUTHORITY'] ?? ''); + const uiStaff = hostnameFromUrl(uiStaffEnv['VITE_APP_UI_STAFF_AAD_REDIRECT_URI'] ?? ''); + + if (!uiCommunity || !api || !mockAuth) { + throw new Error( + 'portless-settings: could not derive hostnames from .env files. ' + 'Ensure apps/ui-community/.env is present with VITE_APP_UI_COMMUNITY_BASE_URL, ' + 'VITE_COMMON_API_ENDPOINT, and VITE_APP_UI_COMMUNITY_B2C_AUTHORITY.', + ); + } + + return { + uiCommunity: applyWorktreeSuffix(uiCommunity), + uiStaff: uiStaff ? applyWorktreeSuffix(uiStaff) : '', + api: applyWorktreeSuffix(api), + mockAuth: applyWorktreeSuffix(mockAuth), + docs: applyWorktreeSuffix(`docs.${uiCommunity}`), + }; +} + +/** Build a full portless HTTPS URL from a hostname and optional path. */ +export function buildPortlessUrl(hostname: string, path = ''): string { + return `https://${hostname}:${PORTLESS_PORT}${path}`; +} + +export { PORTLESS_PORT }; diff --git a/packages/ocom-verification/verification-shared/src/settings/timeout-settings.ts b/packages/ocom-verification/verification-shared/src/settings/timeout-settings.ts new file mode 100644 index 000000000..309ef7f3e --- /dev/null +++ b/packages/ocom-verification/verification-shared/src/settings/timeout-settings.ts @@ -0,0 +1,48 @@ +/** + * Centralized timeout configuration for all verification test packages. + * + * These timeouts are intentionally generous to accommodate: + * - CI environments with limited resources + * - First-time server startup (cold starts) + * - Parallel test execution contention + */ +export const timeouts = { + /** Default scenario timeout (2 minutes) */ + scenario: 120_000, + + /** Server startup timeout (2 minutes) */ + serverStartup: 120_000, + + /** Server shutdown graceful period (10 seconds) */ + serverShutdown: 10_000, + + /** Health probe timeout (3 seconds) */ + healthProbe: 3_000, + + /** Health probe retry interval (500ms) */ + healthProbeInterval: 500, + + /** UI initialization timeout (30 seconds) */ + uiInit: 30_000, + + /** UI cleanup timeout (10 seconds) */ + uiCleanup: 10_000, +} as const; + +/** Type for timeout configuration keys */ +export type TimeoutKey = keyof typeof timeouts; + +/** + * Get timeout value with optional override from environment. + * Usage: TIMEOUT_SERVER_STARTUP=300000 npm test + */ +export function getTimeout(key: TimeoutKey): number { + const envOverride = process.env[`TIMEOUT_${key.toUpperCase()}`]; + if (envOverride) { + const parsed = Number.parseInt(envOverride, 10); + if (!Number.isNaN(parsed)) { + return parsed; + } + } + return timeouts[key]; +} diff --git a/packages/ocom/service-otel/package.json b/packages/ocom/service-otel/package.json index 18fb61910..0fe4c8bd5 100644 --- a/packages/ocom/service-otel/package.json +++ b/packages/ocom/service-otel/package.json @@ -35,7 +35,7 @@ "@opentelemetry/instrumentation-mongoose": "0.47.0", "@opentelemetry/sdk-logs": "0.57.2", "@opentelemetry/sdk-metrics": "1.30.1", - "@opentelemetry/sdk-node": "0.57.2", + "@opentelemetry/sdk-node": "0.217.0", "@opentelemetry/sdk-trace-node": "1.30.1", "@opentelemetry/semantic-conventions": "1.28.0" }, diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 0464b416e..a16e5e4be 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -105,7 +105,8 @@ overrides: rollup: ^4.59.0 '@ant-design/pro-layout>path-to-regexp': ^8.4.0 brace-expansion@1.1.12: 1.1.13 - brace-expansion@5.0.4: 5.0.5 + brace-expansion@5.0.4: 5.0.6 + brace-expansion@5.0.5: 5.0.6 diff@4.0.2: 4.0.4 '@protobufjs/codegen': 2.0.5 '@protobufjs/utf8': 1.1.1 @@ -116,7 +117,7 @@ overrides: svgo: ^3.3.3 yaml@2.8.2: 2.8.3 yauzl@3.2.0: 3.2.1 - qs: ^6.14.2 + qs: 6.15.2 ajv@^6: 6.14.0 lodash: 4.18.1 lodash-es: 4.18.1 @@ -126,7 +127,9 @@ overrides: webpack: ^5.105.4 webpack-dev-server: ^5.2.4 express-rate-limit: 8.5.1 - uuid: 14.0.0 + '@azure/ms-rest-js>uuid': ^3.4.0 + azurite>uuid: ^3.4.0 + ws@8.20.0: 8.20.1 playwright-core: 1.59.0 playwright: 1.59.0 postcss: 8.5.10 @@ -190,9 +193,6 @@ importers: '@vitest/coverage-istanbul': specifier: 'catalog:' version: 4.1.2(vitest@4.1.2) - azurite: - specifier: ^3.35.0 - version: 3.35.0 chrome-devtools-mcp: specifier: ^0.21.0 version: 0.21.0 @@ -290,6 +290,9 @@ importers: '@vitest/coverage-istanbul': specifier: 'catalog:' version: 4.1.2(vitest@4.1.2) + azurite: + specifier: ^3.35.0 + version: 3.35.0(@azure/core-client@1.10.1)(@types/node@24.10.1) rimraf: specifier: 'catalog:' version: 6.0.1 @@ -430,7 +433,7 @@ importers: dependencies: '@apollo/client': specifier: ^3.13.9 - version: 3.14.0(@types/react@19.2.7)(graphql-ws@6.0.6(graphql@16.12.0)(ws@8.20.0))(graphql@16.12.0)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + version: 3.14.0(@types/react@19.2.7)(graphql-ws@6.0.6(graphql@16.12.0)(ws@8.20.1))(graphql@16.12.0)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) '@cellix/ui-core': specifier: workspace:* version: link:../../packages/cellix/ui-core @@ -454,7 +457,7 @@ importers: version: 6.3.5(luxon@3.7.2)(moment@2.30.1)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) apollo-link-rest: specifier: ^0.9.0 - version: 0.9.0(@apollo/client@3.14.0(@types/react@19.2.7)(graphql-ws@6.0.6(graphql@16.12.0)(ws@8.20.0))(graphql@16.12.0)(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(graphql@16.12.0)(qs@6.15.0) + version: 0.9.0(@apollo/client@3.14.0(@types/react@19.2.7)(graphql-ws@6.0.6(graphql@16.12.0)(ws@8.20.1))(graphql@16.12.0)(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(graphql@16.12.0)(qs@6.15.2) less: specifier: ^4.4.0 version: 4.4.2 @@ -527,7 +530,7 @@ importers: version: 9.1.20(@testing-library/dom@10.4.1)(vite@8.0.5(@emnapi/core@1.7.1)(@emnapi/runtime@1.7.1)(@types/node@24.10.1)(esbuild@0.27.4)(jiti@2.6.1)(less@4.4.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3)) storybook-addon-apollo-client: specifier: ^9.0.0 - version: 9.0.0(@apollo/client@3.14.0(@types/react@19.2.7)(graphql-ws@6.0.6(graphql@16.12.0)(ws@8.20.0))(graphql@16.12.0)(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(graphql@16.12.0)(react@19.2.0) + version: 9.0.0(@apollo/client@3.14.0(@types/react@19.2.7)(graphql-ws@6.0.6(graphql@16.12.0)(ws@8.20.1))(graphql@16.12.0)(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(graphql@16.12.0)(react@19.2.0) tailwindcss: specifier: ^3.4.17 version: 3.4.18(tsx@4.21.0)(yaml@2.8.3) @@ -545,7 +548,7 @@ importers: dependencies: '@apollo/client': specifier: ^3.13.9 - version: 3.14.0(@types/react@19.2.7)(graphql-ws@6.0.6(graphql@16.12.0)(ws@8.20.0))(graphql@16.12.0)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + version: 3.14.0(@types/react@19.2.7)(graphql-ws@6.0.6(graphql@16.12.0)(ws@8.20.1))(graphql@16.12.0)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) '@cellix/ui-core': specifier: workspace:* version: link:../../packages/cellix/ui-core @@ -581,7 +584,7 @@ importers: version: 6.3.5(luxon@3.7.2)(moment@2.30.1)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) apollo-link-rest: specifier: ^0.9.0 - version: 0.9.0(@apollo/client@3.14.0(@types/react@19.2.7)(graphql-ws@6.0.6(graphql@16.12.0)(ws@8.20.0))(graphql@16.12.0)(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(graphql@16.12.0)(qs@6.15.0) + version: 0.9.0(@apollo/client@3.14.0(@types/react@19.2.7)(graphql-ws@6.0.6(graphql@16.12.0)(ws@8.20.1))(graphql@16.12.0)(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(graphql@16.12.0)(qs@6.15.2) less: specifier: ^4.4.0 version: 4.4.2 @@ -894,11 +897,11 @@ importers: packages/cellix/server-oauth2-mock-seedwork: dependencies: express: - specifier: ^4.22.0 - version: 4.22.1 + specifier: ^4.22.2 + version: 4.22.2 express-rate-limit: specifier: 8.5.1 - version: 8.5.1(express@4.22.1) + version: 8.5.1(express@4.22.2) jose: specifier: ^5.9.6 version: 5.10.0 @@ -1698,8 +1701,8 @@ importers: specifier: 1.30.1 version: 1.30.1(@opentelemetry/api@1.9.0) '@opentelemetry/sdk-node': - specifier: 0.57.2 - version: 0.57.2(@opentelemetry/api@1.9.0) + specifier: 0.217.0 + version: 0.217.0(@opentelemetry/api@1.9.0) '@opentelemetry/sdk-trace-node': specifier: 1.30.1 version: 1.30.1(@opentelemetry/api@1.9.0) @@ -1764,7 +1767,7 @@ importers: version: 7.22.7(antd@6.3.5(luxon@3.7.2)(moment@2.30.1)(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0) '@apollo/client': specifier: ^3.13.9 - version: 3.14.0(@types/react@19.2.7)(graphql-ws@6.0.6(graphql@16.12.0)(ws@8.20.0))(graphql@16.12.0)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + version: 3.14.0(@types/react@19.2.7)(graphql-ws@6.0.6(graphql@16.12.0)(ws@8.20.1))(graphql@16.12.0)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) '@cellix/ui-core': specifier: workspace:* version: link:../../cellix/ui-core @@ -1855,7 +1858,7 @@ importers: version: 7.22.7(antd@6.3.5(luxon@3.7.2)(moment@2.30.1)(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0) '@apollo/client': specifier: ^3.13.9 - version: 3.14.0(@types/react@19.2.7)(graphql-ws@6.0.6(graphql@16.12.0)(ws@8.20.0))(graphql@16.12.0)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + version: 3.14.0(@types/react@19.2.7)(graphql-ws@6.0.6(graphql@16.12.0)(ws@8.20.1))(graphql@16.12.0)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) '@cellix/ui-core': specifier: workspace:* version: link:../../cellix/ui-core @@ -2010,7 +2013,7 @@ importers: dependencies: '@apollo/client': specifier: ^3.13.9 - version: 3.14.0(@types/react@19.2.7)(graphql-ws@6.0.6(graphql@16.12.0)(ws@8.20.0))(graphql@16.12.0)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + version: 3.14.0(@types/react@19.2.7)(graphql-ws@6.0.6(graphql@16.12.0)(ws@8.20.1))(graphql@16.12.0)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) '@cellix/ui-core': specifier: workspace:* version: link:../../cellix/ui-core @@ -2092,7 +2095,7 @@ importers: version: 6.1.1(react-dom@19.2.0(react@19.2.0))(react@19.2.0) '@apollo/client': specifier: ^3.13.9 - version: 3.14.0(@types/react@19.2.7)(graphql-ws@6.0.6(graphql@16.12.0)(ws@8.20.0))(graphql@16.12.0)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + version: 3.14.0(@types/react@19.2.7)(graphql-ws@6.0.6(graphql@16.12.0)(ws@8.20.1))(graphql@16.12.0)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) '@cellix/ui-core': specifier: workspace:* version: link:../../cellix/ui-core @@ -2171,7 +2174,7 @@ importers: version: 9.1.20(@testing-library/dom@10.4.1)(vite@8.0.5(@emnapi/core@1.7.1)(@emnapi/runtime@1.7.1)(@types/node@24.10.1)(esbuild@0.27.4)(jiti@2.6.1)(less@4.4.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3)) storybook-addon-apollo-client: specifier: ^9.0.0 - version: 9.0.0(@apollo/client@3.14.0(@types/react@19.2.7)(graphql-ws@6.0.6(graphql@16.12.0)(ws@8.20.0))(graphql@16.12.0)(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(graphql@16.12.0)(react@19.2.0) + version: 9.0.0(@apollo/client@3.14.0(@types/react@19.2.7)(graphql-ws@6.0.6(graphql@16.12.0)(ws@8.20.1))(graphql@16.12.0)(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(graphql@16.12.0)(react@19.2.0) typescript: specifier: 'catalog:' version: 6.0.3 @@ -2745,8 +2748,8 @@ packages: '@asamuzakjp/css-color@3.2.0': resolution: {integrity: sha512-K1A6z8tS3XsmCMM86xoWdn7Fkdn9m6RSVtocUrJYIwZnFVkng/PvkEoWtOWmP+Scc6saYWHWZYbndEEXxl24jw==} - '@azure-rest/core-client@2.5.1': - resolution: {integrity: sha512-EHaOXW0RYDKS5CFffnixdyRPak5ytiCtU7uXDcP/uiY+A6jFRwNGzzJBiznkCzvi5EYpY+YWinieqHb0oY916A==} + '@azure-rest/core-client@2.6.0': + resolution: {integrity: sha512-iuFKDm8XPzNxPfRjhyU5/xKZmcRDzSuEghXDHHk4MjBV/wFL34GmYVBZnn9wmuoLBeS1qAw9ceMdaeJBPcB1QQ==} engines: {node: '>=20.0.0'} '@azure/abort-controller@1.1.0': @@ -2769,9 +2772,12 @@ packages: resolution: {integrity: sha512-Nh5PhEOeY6PrnxNPsEHRr9eimxLwgLlpmguQaHKBinFYA/RU9+kOYVOQqOrTsCL+KSxrLLl1gD8Dk5BFW/7l/w==} engines: {node: '>=20.0.0'} - '@azure/core-http-compat@2.3.1': - resolution: {integrity: sha512-az9BkXND3/d5VgdRRQVkiJb2gOmDU8Qcq4GvjtBmDICNiQ9udFmDk4ZpSB5Qq1OmtDJGlQAfBaS4palFsazQ5g==} + '@azure/core-http-compat@2.4.0': + resolution: {integrity: sha512-f1P96IB399YiN2ARYHP7EpZi3Bf3wH4SN2lGzrw7JVwm7bbsVYtf2iKSBwTywD2P62NOPZGHFSZi+6jjb75JuA==} engines: {node: '>=20.0.0'} + peerDependencies: + '@azure/core-client': ^1.10.0 + '@azure/core-rest-pipeline': ^1.22.0 '@azure/core-lro@2.7.2': resolution: {integrity: sha512-0YIpccoX8m/k00O7mDDMdJpbr6mf1yWo2dfmxt5A8XVZVVMz2SSKaEbMCeJRvgQ0IaSlqhjT47p4hVIRRy90xw==} @@ -2815,9 +2821,9 @@ packages: resolution: {integrity: sha512-0q5DL4uyR0EZ4RXQKD8MadGH6zTIcloUoS/RVbCpNpej4pwte0xpqYxk8K97Py2RiuUvI7F4GXpoT4046VfufA==} engines: {node: '>=14.0.0'} - '@azure/keyvault-common@2.0.0': - resolution: {integrity: sha512-wRLVaroQtOqfg60cxkzUkGKrKMsCP6uYXAOomOIysSMyt1/YM0eUn9LqieAWM8DLcU4+07Fio2YGpPeqUbpP9w==} - engines: {node: '>=18.0.0'} + '@azure/keyvault-common@2.1.0': + resolution: {integrity: sha512-aCDidWuKY06LWQ4x7/8TIXK6iRqTaRWRL3t7T+LC+j1b07HtoIsOxP/tU90G4jCSBn5TAyUTCtA4MS/y5Hudaw==} + engines: {node: '>=20.0.0'} '@azure/keyvault-keys@4.10.0': resolution: {integrity: sha512-eDT7iXoBTRZ2n3fLiftuGJFD+yjkiB1GNqzU2KbY1TLYeXeSPVTVgn2eJ5vmRTZ11978jy2Kg2wI7xa9Tyr8ag==} @@ -2846,9 +2852,9 @@ packages: resolution: {integrity: sha512-CO+SE4weOsfJf+C5LM8argzvotrXw252/ZU6SM2Tz63fEblhH1uuVaaO4ISYFuN4Q6BhTo7I3qIdi8ydUQCqhw==} engines: {node: '>=16'} - '@azure/opentelemetry-instrumentation-azure-sdk@1.0.0-beta.9': - resolution: {integrity: sha512-gNCFokEoQQEkhu2T8i1i+1iW2o9wODn2slu5tpqJmjV1W7qf9dxVv6GNXW1P1WC8wMga8BCc2t/oMhOK3iwRQg==} - engines: {node: '>=18.0.0'} + '@azure/opentelemetry-instrumentation-azure-sdk@1.0.0': + resolution: {integrity: sha512-Y8rZOIMXQY/GwNRL+uLVuwIn9aEa/KnnggyYUmFxC1MigmRJCNH5NxMmxKSpddXF9SW6Z1ijRd6Pptd2A5OhGw==} + engines: {node: '>=20.0.0'} '@babel/code-frame@7.29.0': resolution: {integrity: sha512-9NhCeYjq9+3uxgdtp20LSiJXJvN0FeCtNGpJxuMFZ1Kv3cWUNb6DOhJwUvcVCzKGR66cw4njwM6hrJLqgOwbcw==} @@ -4806,8 +4812,8 @@ packages: '@jridgewell/trace-mapping@0.3.31': resolution: {integrity: sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==} - '@js-joda/core@5.6.5': - resolution: {integrity: sha512-3zwefSMwHpu8iVUW8YYz227sIv6UFqO31p1Bf1ZH/Vom7CmNyUsXjDBlnNzcuhmOL1XfxZ3nvND42kR23XlbcQ==} + '@js-joda/core@5.7.0': + resolution: {integrity: sha512-WBu4ULVVxySLLzK1Ppq+OdfP+adRS4ntmDQT915rzDJ++i95gc2jZkM5B6LWEAwN3lGXpfie3yPABozdD3K3Vg==} '@js-sdsl/ordered-map@4.4.2': resolution: {integrity: sha512-iUKgm52T8HOE/makSxjqoWhe95ZJA1/G1sYsGev2JDKUSS14KAgg1LHb+Ba+IPow0xflbnSkOsZcO08C7w1gYw==} @@ -4902,6 +4908,14 @@ packages: resolution: {integrity: sha512-IKJBQxh91qJ+3ssRly5hYEJ8NDHu9oY/B1PXVSCWf7zytmYO9RNLB0Ox9XQ/fJ8m6gY6Q6NtBWlmXfaXt5Uc4Q==} engines: {node: '>=8.0.0'} + '@opentelemetry/api-logs@0.211.0': + resolution: {integrity: sha512-swFdZq8MCdmdR22jTVGQDhwqDzcI4M10nhjXkLr1EsIzXgZBqm4ZlmmcWsg3TSNf+3mzgOiqveXmBLZuDi2Lgg==} + engines: {node: '>=8.0.0'} + + '@opentelemetry/api-logs@0.217.0': + resolution: {integrity: sha512-Cdq0jW2lknrNfrAm92MyEAvpe2cRsKjdnQLHUL6xRA4IVUnsWx6P65E7NcUO0Y+L4w1Aee5iV8FvjSwd+lrs9A==} + engines: {node: '>=8.0.0'} + '@opentelemetry/api-logs@0.52.1': resolution: {integrity: sha512-qnSqB2DQ9TPP96dl8cDubDvrUyWc0/sK81xHTK8eSUspzDM3bsewX903qclQFvVhgStjRWdC5bLb3kQqMkfV5A==} engines: {node: '>=14'} @@ -4914,12 +4928,24 @@ packages: resolution: {integrity: sha512-3giAOQvZiH5F9bMlMiv8+GSPMeqg0dbaeo58/0SlA9sxSqZhnUtxzX9/2FzyhS9sWQf5S0GJE0AKBrFqjpeYcg==} engines: {node: '>=8.0.0'} + '@opentelemetry/configuration@0.217.0': + resolution: {integrity: sha512-xCtrYOhBqdy6ZOMfe0Oa73ZKF+2LMhoOv4L5vmwAHVvOXUg+V3fvKuEIr9ZyD0Ow+vxllEjWO6PV1wd0DOtyvw==} + engines: {node: ^18.19.0 || >=20.6.0} + peerDependencies: + '@opentelemetry/api': ^1.9.0 + '@opentelemetry/context-async-hooks@1.30.1': resolution: {integrity: sha512-s5vvxXPVdjqS3kTLKMeBMvop9hbWkwzBpu+mUO2M7sZtlkyDJGwFe33wRKnbaYDo8ExRVBIIdwIGrqpxHuKttA==} engines: {node: '>=14'} peerDependencies: '@opentelemetry/api': '>=1.0.0 <1.10.0' + '@opentelemetry/context-async-hooks@2.7.1': + resolution: {integrity: sha512-OPFBYuXEn1E4ja3Y6eeA7O+ZnLBNcXTV5Cgsn1VaqBZ6hC5FnpZPLBNme1LJY8ZtF4aOujPKFoeWN4ik487KuQ==} + engines: {node: ^18.19.0 || >=20.6.0} + peerDependencies: + '@opentelemetry/api': '>=1.0.0 <1.10.0' + '@opentelemetry/core@1.25.1': resolution: {integrity: sha512-GeT/l6rBYWVQ4XArluLVB6WWQ8flHbdb6r2FCHC3smtdOAbrJBIv35tpV/yp9bmYUJf+xmZpu9DRTIeJVhFbEQ==} engines: {node: '>=14'} @@ -4944,69 +4970,69 @@ packages: peerDependencies: '@opentelemetry/api': '>=1.0.0 <1.10.0' - '@opentelemetry/exporter-logs-otlp-grpc@0.57.2': - resolution: {integrity: sha512-eovEy10n3umjKJl2Ey6TLzikPE+W4cUQ4gCwgGP1RqzTGtgDra0WjIqdy29ohiUKfvmbiL3MndZww58xfIvyFw==} - engines: {node: '>=14'} + '@opentelemetry/exporter-logs-otlp-grpc@0.217.0': + resolution: {integrity: sha512-vC5S0Dc+noxD86CVtNu1+awCHPA5Kewi1Sg23ps+9lh4YifwsKXh3pe4XTNEKtUJiAcjpJ5dqStGakLbrSE+YQ==} + engines: {node: ^18.19.0 || >=20.6.0} peerDependencies: '@opentelemetry/api': ^1.3.0 - '@opentelemetry/exporter-logs-otlp-http@0.57.2': - resolution: {integrity: sha512-0rygmvLcehBRp56NQVLSleJ5ITTduq/QfU7obOkyWgPpFHulwpw2LYTqNIz5TczKZuy5YY+5D3SDnXZL1tXImg==} - engines: {node: '>=14'} + '@opentelemetry/exporter-logs-otlp-http@0.217.0': + resolution: {integrity: sha512-KfLAdt1uilVE+3FxbgVnp2ZrzqbIawzcesnRoi+Kh9ckB5Ld5D8btUgoBvwTbdmuNx1j6b132Wsh72azq+pPNQ==} + engines: {node: ^18.19.0 || >=20.6.0} peerDependencies: '@opentelemetry/api': ^1.3.0 - '@opentelemetry/exporter-logs-otlp-proto@0.57.2': - resolution: {integrity: sha512-ta0ithCin0F8lu9eOf4lEz9YAScecezCHkMMyDkvd9S7AnZNX5ikUmC5EQOQADU+oCcgo/qkQIaKcZvQ0TYKDw==} - engines: {node: '>=14'} + '@opentelemetry/exporter-logs-otlp-proto@0.217.0': + resolution: {integrity: sha512-Se0GG/ZO24mQTlQj7zprR4pNI0nKe4lPDPBsuJmi6508b9TlZEuUd3EfyuHk6oJxzL7fGyDFYAbxNigQvRP2ZQ==} + engines: {node: ^18.19.0 || >=20.6.0} peerDependencies: '@opentelemetry/api': ^1.3.0 - '@opentelemetry/exporter-metrics-otlp-grpc@0.57.2': - resolution: {integrity: sha512-r70B8yKR41F0EC443b5CGB4rUaOMm99I5N75QQt6sHKxYDzSEc6gm48Diz1CI1biwa5tDPznpylTrywO/pT7qw==} - engines: {node: '>=14'} + '@opentelemetry/exporter-metrics-otlp-grpc@0.217.0': + resolution: {integrity: sha512-0GpJKnCoVaVA1rKBMVPHziznfOQlXgH72S9ktjBAF1AnAVPzX7vVEBGrhwiSxxHDAiefXk+J8znApsMb/K6Z3w==} + engines: {node: ^18.19.0 || >=20.6.0} peerDependencies: '@opentelemetry/api': ^1.3.0 - '@opentelemetry/exporter-metrics-otlp-http@0.57.2': - resolution: {integrity: sha512-ttb9+4iKw04IMubjm3t0EZsYRNWr3kg44uUuzfo9CaccYlOh8cDooe4QObDUkvx9d5qQUrbEckhrWKfJnKhemA==} - engines: {node: '>=14'} + '@opentelemetry/exporter-metrics-otlp-http@0.217.0': + resolution: {integrity: sha512-1zkMzzhiNJdVmLxuwkltqWGw4fOOam47bqRxmuQNjyKJe/9NmY5cIrZ4kiQV7sVGxoOgT0ZvGUfLcjvtpC/b9Q==} + engines: {node: ^18.19.0 || >=20.6.0} peerDependencies: '@opentelemetry/api': ^1.3.0 - '@opentelemetry/exporter-metrics-otlp-proto@0.57.2': - resolution: {integrity: sha512-HX068Q2eNs38uf7RIkNN9Hl4Ynl+3lP0++KELkXMCpsCbFO03+0XNNZ1SkwxPlP9jrhQahsMPMkzNXpq3fKsnw==} - engines: {node: '>=14'} + '@opentelemetry/exporter-metrics-otlp-proto@0.217.0': + resolution: {integrity: sha512-nfxt/KxVGFkjkO/M+58y1ugHu/dwPtxG4eYq0KApcQ7xk5CHzhdn+IuLZfDSvNDrJ3Uy5q++Fj/wbK7i8yryfQ==} + engines: {node: ^18.19.0 || >=20.6.0} peerDependencies: '@opentelemetry/api': ^1.3.0 - '@opentelemetry/exporter-prometheus@0.57.2': - resolution: {integrity: sha512-VqIqXnuxWMWE/1NatAGtB1PvsQipwxDcdG4RwA/umdBcW3/iOHp0uejvFHTRN2O78ZPged87ErJajyUBPUhlDQ==} - engines: {node: '>=14'} + '@opentelemetry/exporter-prometheus@0.217.0': + resolution: {integrity: sha512-U9MCXxJu0sBCh5aEkylYRR4xVIL8D1CW6dGwvYXbfFr0qveSorfD0XJchCAWoW6QfAAIcY/yxjf4Dj8OgkHBPw==} + engines: {node: ^18.19.0 || >=20.6.0} peerDependencies: '@opentelemetry/api': ^1.3.0 - '@opentelemetry/exporter-trace-otlp-grpc@0.57.2': - resolution: {integrity: sha512-gHU1vA3JnHbNxEXg5iysqCWxN9j83d7/epTYBZflqQnTyCC4N7yZXn/dMM+bEmyhQPGjhCkNZLx4vZuChH1PYw==} - engines: {node: '>=14'} + '@opentelemetry/exporter-trace-otlp-grpc@0.217.0': + resolution: {integrity: sha512-fPZs2fw7veLH3pEKu8vSepUa2fQpAE2P7al6qU10aH9GrEJJ8YaPgsd5xON7by5rbcEVS71FOU2aWyK6nzB7VQ==} + engines: {node: ^18.19.0 || >=20.6.0} peerDependencies: '@opentelemetry/api': ^1.3.0 - '@opentelemetry/exporter-trace-otlp-http@0.57.2': - resolution: {integrity: sha512-sB/gkSYFu+0w2dVQ0PWY9fAMl172PKMZ/JrHkkW8dmjCL0CYkmXeE+ssqIL/yBUTPOvpLIpenX5T9RwXRBW/3g==} - engines: {node: '>=14'} + '@opentelemetry/exporter-trace-otlp-http@0.217.0': + resolution: {integrity: sha512-38YQoqtYjglz2GV94LGUN/djLvxtvGIQO68o6qAFPVshjmwSdX1F2i0c7vn3lEl1L5B/YqjB/bgKXaVx7KO+RQ==} + engines: {node: ^18.19.0 || >=20.6.0} peerDependencies: '@opentelemetry/api': ^1.3.0 - '@opentelemetry/exporter-trace-otlp-proto@0.57.2': - resolution: {integrity: sha512-awDdNRMIwDvUtoRYxRhja5QYH6+McBLtoz1q9BeEsskhZcrGmH/V1fWpGx8n+Rc+542e8pJA6y+aullbIzQmlw==} - engines: {node: '>=14'} + '@opentelemetry/exporter-trace-otlp-proto@0.217.0': + resolution: {integrity: sha512-nPV8gKHUiSuTZpQcnZU3/pBlK7crSyEGpZuh5MtWySB0vv6NNG0QvvfKitQt+Fc2Mc6qfyU54KlZcurwoTbrVg==} + engines: {node: ^18.19.0 || >=20.6.0} peerDependencies: '@opentelemetry/api': ^1.3.0 - '@opentelemetry/exporter-zipkin@1.30.1': - resolution: {integrity: sha512-6S2QIMJahIquvFaaxmcwpvQQRD/YFaMTNoIxrfPIPOeITN+a8lfEcPDxNxn8JDAaxkg+4EnXhz8upVDYenoQjA==} - engines: {node: '>=14'} + '@opentelemetry/exporter-zipkin@2.7.1': + resolution: {integrity: sha512-mfsD9bKAxcKrh5+y08TPodvClBO0CznBE3p79YAGnO81WI4LrdsGA65T53e4iTSbCalW4WaUpkbeJcbpyIUHfg==} + engines: {node: ^18.19.0 || >=20.6.0} peerDependencies: '@opentelemetry/api': ^1.0.0 @@ -5040,33 +5066,39 @@ packages: peerDependencies: '@opentelemetry/api': ^1.3.0 - '@opentelemetry/instrumentation@0.52.1': - resolution: {integrity: sha512-uXJbYU/5/MBHjMp1FqrILLRuiJCs3Ofk0MeRDk8g1S1gD47U8X3JnSwcMO1rtRo1x1a7zKaQHaoYu49p/4eSKw==} - engines: {node: '>=14'} + '@opentelemetry/instrumentation@0.211.0': + resolution: {integrity: sha512-h0nrZEC/zvI994nhg7EgQ8URIHt0uDTwN90r3qQUdZORS455bbx+YebnGeEuFghUT0HlJSrLF4iHw67f+odY+Q==} + engines: {node: ^18.19.0 || >=20.6.0} peerDependencies: '@opentelemetry/api': ^1.3.0 - '@opentelemetry/instrumentation@0.57.2': - resolution: {integrity: sha512-BdBGhQBh8IjZ2oIIX6F2/Q3LKm/FDDKi6ccYKcBTeilh6SNdNKveDOLk73BkSJjQLJk6qe4Yh+hHw1UPhCDdrg==} - engines: {node: '>=14'} + '@opentelemetry/instrumentation@0.217.0': + resolution: {integrity: sha512-24ucQMjz7Y34Kw3trbxL2ZrssbtgWnR+Clpaa+YdeWuuyH3Cvk23Q03PcQvqiZrDvt8AmQmjgg9v6Y9PHoxG7w==} + engines: {node: ^18.19.0 || >=20.6.0} peerDependencies: '@opentelemetry/api': ^1.3.0 - '@opentelemetry/otlp-exporter-base@0.57.2': - resolution: {integrity: sha512-XdxEzL23Urhidyebg5E6jZoaiW5ygP/mRjxLHixogbqwDy2Faduzb5N0o/Oi+XTIJu+iyxXdVORjXax+Qgfxag==} + '@opentelemetry/instrumentation@0.52.1': + resolution: {integrity: sha512-uXJbYU/5/MBHjMp1FqrILLRuiJCs3Ofk0MeRDk8g1S1gD47U8X3JnSwcMO1rtRo1x1a7zKaQHaoYu49p/4eSKw==} engines: {node: '>=14'} peerDependencies: '@opentelemetry/api': ^1.3.0 - '@opentelemetry/otlp-grpc-exporter-base@0.57.2': - resolution: {integrity: sha512-USn173KTWy0saqqRB5yU9xUZ2xdgb1Rdu5IosJnm9aV4hMTuFFRTUsQxbgc24QxpCHeoKzzCSnS/JzdV0oM2iQ==} - engines: {node: '>=14'} + '@opentelemetry/otlp-exporter-base@0.217.0': + resolution: {integrity: sha512-eYfqnB3UhKu/5frhd1R6+FprKygbhkomuaceMXDyzxbfXB9tKgZOVmjaJ02CkLA6Tdzumxl+e2H+vo2a8jiMPQ==} + engines: {node: ^18.19.0 || >=20.6.0} peerDependencies: '@opentelemetry/api': ^1.3.0 - '@opentelemetry/otlp-transformer@0.57.2': - resolution: {integrity: sha512-48IIRj49gbQVK52jYsw70+Jv+JbahT8BqT2Th7C4H7RCM9d0gZ5sgNPoMpWldmfjvIsSgiGJtjfk9MeZvjhoig==} - engines: {node: '>=14'} + '@opentelemetry/otlp-grpc-exporter-base@0.217.0': + resolution: {integrity: sha512-7RTAdZuOsCDnsyqTCG4+bDzrfnsWdzkRs7z0AVi/V3tEQx0oKeyc+OuRWYxnRsmaJXgxcmB8vb/lfxn58Dj6Ag==} + engines: {node: ^18.19.0 || >=20.6.0} + peerDependencies: + '@opentelemetry/api': ^1.3.0 + + '@opentelemetry/otlp-transformer@0.217.0': + resolution: {integrity: sha512-MKK8UHKFUOGAvbZRWh90MhwHG+Fxm6OROBdjKPCF+HQobjuJ/Kuf8Chs8CR45X1aqotxrMj7OxTdsXe8sXuGVA==} + engines: {node: ^18.19.0 || >=20.6.0} peerDependencies: '@opentelemetry/api': ^1.3.0 @@ -5076,24 +5108,42 @@ packages: peerDependencies: '@opentelemetry/api': '>=1.0.0 <1.10.0' + '@opentelemetry/propagator-b3@2.7.1': + resolution: {integrity: sha512-RJid6E2CKyeGfKBzXKF21ejabGMHypFkPAh3qZ+NvI+SGjuIye79t3PmiqcDgtRzdKH6ynXzbfslQ8DfpRUg2A==} + engines: {node: ^18.19.0 || >=20.6.0} + peerDependencies: + '@opentelemetry/api': '>=1.0.0 <1.10.0' + '@opentelemetry/propagator-jaeger@1.30.1': resolution: {integrity: sha512-Pj/BfnYEKIOImirH76M4hDaBSx6HyZ2CXUqk+Kj02m6BB80c/yo4BdWkn/1gDFfU+YPY+bPR2U0DKBfdxCKwmg==} engines: {node: '>=14'} peerDependencies: '@opentelemetry/api': '>=1.0.0 <1.10.0' + '@opentelemetry/propagator-jaeger@2.7.1': + resolution: {integrity: sha512-KMjVBHzP4N60bOzxja76M1F1hZZ43lGPga5ix+mkv9+kk1nx9SbkxSvJsMbuVUxdPQmsPTqGShmhN8ulrMOg6Q==} + engines: {node: ^18.19.0 || >=20.6.0} + peerDependencies: + '@opentelemetry/api': '>=1.0.0 <1.10.0' + '@opentelemetry/resources@1.30.1': resolution: {integrity: sha512-5UxZqiAgLYGFjS4s9qm5mBVo433u+dSPUFWVWXmLAD4wB65oMCoXaJP1KJa9DIYYMeHu3z4BZcStG3LC593cWA==} engines: {node: '>=14'} peerDependencies: '@opentelemetry/api': '>=1.0.0 <1.10.0' - '@opentelemetry/resources@2.2.0': - resolution: {integrity: sha512-1pNQf/JazQTMA0BiO5NINUzH0cbLbbl7mntLa4aJNmCCXSj0q03T5ZXXL0zw4G55TjdL9Tz32cznGClf+8zr5A==} + '@opentelemetry/resources@2.7.1': + resolution: {integrity: sha512-DeT6KKolmC4e/dRQvMQ/RwlnzhaqeiFOXY5ngoOPJ07GgVVKxZOg9EcrNZb5aTzUn+iCrJldAgOfQm1O/QfPAQ==} engines: {node: ^18.19.0 || >=20.6.0} peerDependencies: '@opentelemetry/api': '>=1.3.0 <1.10.0' + '@opentelemetry/sdk-logs@0.217.0': + resolution: {integrity: sha512-BB+PcHItcZDL63dPMW+mJvwN9rk37wuIDjRxbVlg6pPDvDR/7GL7UJHbGsllgoggOoTimsKgENaWPoGch/oE1A==} + engines: {node: ^18.19.0 || >=20.6.0} + peerDependencies: + '@opentelemetry/api': '>=1.4.0 <1.10.0' + '@opentelemetry/sdk-logs@0.57.2': resolution: {integrity: sha512-TXFHJ5c+BKggWbdEQ/inpgIzEmS2BGQowLE9UhsMd7YYlUfBQJ4uax0VF/B5NYigdM/75OoJGhAV3upEhK+3gg==} engines: {node: '>=14'} @@ -5106,9 +5156,15 @@ packages: peerDependencies: '@opentelemetry/api': '>=1.3.0 <1.10.0' - '@opentelemetry/sdk-node@0.57.2': - resolution: {integrity: sha512-8BaeqZyN5sTuPBtAoY+UtKwXBdqyuRKmekN5bFzAO40CgbGzAxfTpiL3PBerT7rhZ7p2nBdq7FaMv/tBQgHE4A==} - engines: {node: '>=14'} + '@opentelemetry/sdk-metrics@2.7.1': + resolution: {integrity: sha512-MpDJdkiFDs3Pm1RHO3KByuZbuBdJEXEAkiC0+yJdsZGVCdf1RpHR6n+LHDcS7ffmfrt5kVCzJSCfm4z2C7v0uQ==} + engines: {node: ^18.19.0 || >=20.6.0} + peerDependencies: + '@opentelemetry/api': '>=1.9.0 <1.10.0' + + '@opentelemetry/sdk-node@0.217.0': + resolution: {integrity: sha512-K/60pSv42+NQiZKy1pAH18nYDkxltsDV4O3SJ233J0E9raU1ksyL9gsKuS8p30bYBb4AMPCfDuutHQaHYpcv0Q==} + engines: {node: ^18.19.0 || >=20.6.0} peerDependencies: '@opentelemetry/api': '>=1.3.0 <1.10.0' @@ -5118,8 +5174,8 @@ packages: peerDependencies: '@opentelemetry/api': '>=1.0.0 <1.10.0' - '@opentelemetry/sdk-trace-base@2.2.0': - resolution: {integrity: sha512-xWQgL0Bmctsalg6PaXExmzdedSp3gyKV8mQBwK/j9VGdCDu2fmXIb2gAehBKbkXCpJ4HPkgv3QfoJWRT4dHWbw==} + '@opentelemetry/sdk-trace-base@2.7.1': + resolution: {integrity: sha512-NAYIlsF8MPUsKqJMiDQJTMPOmlbawC1Iz/omMLygZ1C9am8fTKYjTaI+OZM+WTY3t3Glo0wnOg/6/pac6RGPPw==} engines: {node: ^18.19.0 || >=20.6.0} peerDependencies: '@opentelemetry/api': '>=1.3.0 <1.10.0' @@ -5130,8 +5186,14 @@ packages: peerDependencies: '@opentelemetry/api': '>=1.0.0 <1.10.0' - '@opentelemetry/sdk-trace-web@2.2.0': - resolution: {integrity: sha512-x/LHsDBO3kfqaFx5qSzBljJ5QHsRXrvS4MybBDy1k7Svidb8ZyIPudWVzj3s5LpPkYZIgi9e+7tdsNCnptoelw==} + '@opentelemetry/sdk-trace-node@2.7.1': + resolution: {integrity: sha512-pCpQxU68lV+I9s9svqMyVu5iHdDDUnqUpSxqwyCU8A9ejEsSnMPCbearwsUO4yk08ZJzAIUCFuReMdVQvHrdvg==} + engines: {node: ^18.19.0 || >=20.6.0} + peerDependencies: + '@opentelemetry/api': '>=1.0.0 <1.10.0' + + '@opentelemetry/sdk-trace-web@2.7.1': + resolution: {integrity: sha512-K806OouCSOjMd8Nr7+ZCq3QT22tdAzzS/7h8vprfiKjkgFQ99/dvwU8d12WJANA6D5Qtme65hyBAqAu9CkQuxQ==} engines: {node: ^18.19.0 || >=20.6.0} peerDependencies: '@opentelemetry/api': '>=1.0.0 <1.10.0' @@ -6562,8 +6624,8 @@ packages: '@types/react@19.2.7': resolution: {integrity: sha512-MWtvHrGZLFttgeEj28VXHxpmwYbor/ATPYbBfSFZEIRK0ecCFLl2Qo55z52Hss+UV9CRN7trSeq1zbgx7YDWWg==} - '@types/readable-stream@4.0.22': - resolution: {integrity: sha512-/FFhJpfCLAPwAcN3mFycNUa77ddnr8jTgF5VmSNetaemWB2cIlfCA9t0YTM3JAT0wOcv8D4tjPo7pkDhK3EJIg==} + '@types/readable-stream@4.0.23': + resolution: {integrity: sha512-wwXrtQvbMHxCbBgjHaMGEmImFTQxxpfMOR/ZoQnXxB1woqkUbdLGFDgauo00Py9IudiaqSeiBiulSV9i6XIPig==} '@types/resolve@1.20.6': resolution: {integrity: sha512-A4STmOXPhMUtHH+S6ymgE2GiBSMqf4oTvcQZMcHzokuTLVYzXTB8ttjcgxOVaAp2lGwEdzZ0J+cRbbeevQj1UQ==} @@ -7012,7 +7074,7 @@ packages: peerDependencies: '@apollo/client': '>=3' graphql: '>=0.11' - qs: ^6.14.2 + qs: 6.15.2 applicationinsights@2.9.8: resolution: {integrity: sha512-eB/EtAXJ6mDLLvHrtZj/7h31qUfnC2Npr2pHGqds5+1OP7BFLsn5us+HCkwTj7Q+1sHXujLphE5Cyvq5grtV6g==} @@ -7227,13 +7289,17 @@ packages: bl@4.1.0: resolution: {integrity: sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==} - bl@6.1.5: - resolution: {integrity: sha512-XylDt2P3JBttAwLpORq/hOEX9eJzP0r6Voa46C/WVvad8D1J0jW5876txB8FnzKtbdnU6X4Y1vOEvC6PllJrDg==} + bl@6.1.6: + resolution: {integrity: sha512-jLsPgN/YSvPUg9UX0Kd73CXpm2Psg9FxMeCSXnk3WBO3CMT10JMwijubhGfHCnFu6TPn1ei3b975dxv7K2pWVg==} body-parser@1.20.3: resolution: {integrity: sha512-7rAxByjUMqQ3/bHJy7D6OGXvx/MMc4IqBn/X0fcM1QUcAItpZrBEYhWGem+tzXH90c+G01ypMcYJBO9Y30203g==} engines: {node: '>= 0.8', npm: 1.2.8000 || >= 1.4.16} + body-parser@1.20.5: + resolution: {integrity: sha512-3grm+/2tUOvu2cjJkvsIxrv/wVpfXQW4PsQHYm7yk4vfpu7Ekl6nEsYBoJUL6qDwZUx8wUhQ8tR2qz+ad9c9OA==} + engines: {node: '>= 0.8', npm: 1.2.8000 || >= 1.4.16} + body-parser@2.2.2: resolution: {integrity: sha512-oP5VkATKlNwcgvxi0vM0p/D3n2C3EReYVX+DNYs5TjZFn/oQt2j+4sVJtSMr18pdRr8wjTcBl6LoV+FUwzPmNA==} engines: {node: '>=18'} @@ -7262,8 +7328,8 @@ packages: brace-expansion@2.0.2: resolution: {integrity: sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==} - brace-expansion@5.0.5: - resolution: {integrity: sha512-VZznLgtwhn+Mact9tfiwx64fA9erHH/MCXEUfB/0bX/6Fz6ny5EGTXYltMocqg4xFAQZtnO3DHWWXi8RiuN7cQ==} + brace-expansion@5.0.6: + resolution: {integrity: sha512-kLpxurY4Z4r9sgMsyG0Z9uzsBlgiU/EFKhj/h91/8yHu0edo7XuixOIH3VcJ8kkxs6/jPzoI6U9Vj3WqbMQ94g==} engines: {node: 18 || 20 || >=22} braces@3.0.3: @@ -7349,6 +7415,10 @@ packages: resolution: {integrity: sha512-oKlSFMcMwpUg2ednkhQ454wfWiU/ul3CkJe/PEHcTKuiX6RpbehUiFMXu13HalGZxfUwCQzZG747YXBn1im9ww==} engines: {node: '>= 0.4'} + call-bind@1.0.9: + resolution: {integrity: sha512-a/hy+pNsFUTR+Iz8TCJvXudKVLAnz/DyeSUo10I5yvFDQJBFU2s9uqQpoSrJlroHUKoKqzg+epxyP9lqFdzfBQ==} + engines: {node: '>= 0.4'} + call-bound@1.0.4: resolution: {integrity: sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==} engines: {node: '>= 0.4'} @@ -7480,6 +7550,9 @@ packages: cjs-module-lexer@1.4.3: resolution: {integrity: sha512-9z8TZaGM1pfswYeXrUpzPrkx8UnWYdhJclsiYMm6x/w5+nN+8Tf/LnAgfLGQCm59qAOxU8WwHEq2vNwF6i4j+Q==} + cjs-module-lexer@2.2.0: + resolution: {integrity: sha512-4bHTS2YuzUvtoLjdy+98ykbNB5jS0+07EvFNXerqZQJ89F7DI6ET7OQo/HJuW6K0aVsKA9hj9/RVb2kQVOrPDQ==} + class-transformer@0.5.1: resolution: {integrity: sha512-SQa1Ws6hUbfC98vKGxZH3KFY0Y1lm5Zm0SY8XX9zbK7FJCyVEac3ATW0RIpwzW+oOfmHE5PMPufDG9hCfoEOMw==} @@ -8113,8 +8186,8 @@ packages: resolution: {integrity: sha512-uBq4egWHTcTt33a72vpSG0z3HnPuIl6NqYcTrKEg2azoEyl2hpW0zqlxysq2pK9HlDIHyHyakeYaYnSAwd8bow==} engines: {node: '>=12'} - dottie@2.0.6: - resolution: {integrity: sha512-iGCHkfUc5kFekGiqhe8B/mdaurD+lakO9txNnTvKtA6PISrw86LgqHvRzWYPyoE2Ph5aMIrCw9/uko6XHTKCwA==} + dottie@2.0.7: + resolution: {integrity: sha512-7lAK2A0b3zZr3UC5aE69CPdCFR4RHW1o2Dr74TqFykxkUCBXSRJum/yPc7g8zRHJqWKomPLHwFLLoUnn8PXXRg==} deprecated: Package no longer supported. Contact Support at https://www.npmjs.com/support for more info. dset@3.1.4: @@ -8198,8 +8271,8 @@ packages: error-stack-parser@2.1.4: resolution: {integrity: sha512-Sk5V6wVazPhq5MhpO+AUxJn5x7XSXGl1R93Vn7i+zS15KDVxQijejNCrz8340/2bgLBjR9GtEG8ZVKONDjcqGQ==} - es-abstract@1.24.0: - resolution: {integrity: sha512-WSzPgsdLtTcQwm4CROfS5ju2Wa1QQcVeT37jFjYzdFz1r9ahadC8B8/a4qxJxM+09F18iumCdRmlr96ZYkQvEg==} + es-abstract@1.24.2: + resolution: {integrity: sha512-2FpH9Q5i2RRwyEP1AylXe6nYLR5OhaJTZwmlcP0dL/+JCbgg7yyEo/sEK6HeGZRf3dFpWwThaRHVApXSkW3xeg==} engines: {node: '>= 0.4'} es-aggregate-error@1.0.14: @@ -8380,6 +8453,10 @@ packages: resolution: {integrity: sha512-F2X8g9P1X7uCPZMA3MVf9wcTqlyNp7IhH5qPCI0izhaOIYXaW9L535tGA3qmjRzpH+bZczqq7hVKxTR4NWnu+g==} engines: {node: '>= 0.10.0'} + express@4.22.2: + resolution: {integrity: sha512-IuL+Elrou2ZvCFHs18/CIzy2Nzvo25nZ1/D2eIZlz7c+QUayAcYoiM2BthCjs+EBHVpjYjcuLDAiCWgeIX3X1Q==} + engines: {node: '>= 0.10.0'} + extend-shallow@2.0.1: resolution: {integrity: sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==} engines: {node: '>=0.10.0'} @@ -8765,7 +8842,7 @@ packages: crossws: ~0.3 graphql: ^15.10.1 || ^16 uWebSockets.js: ^20 - ws: ^8 + ws: 8.20.1 peerDependenciesMeta: '@fastify/websocket': optional: true @@ -8996,6 +9073,10 @@ packages: resolution: {integrity: sha512-cf6L2Ds3h57VVmkZe+Pn+5APsT7FpqJtEhhieDCvrE2MK5Qk9MyffgQyuxQTm6BChfeZNtcOLHp9IcWRVcIcBQ==} engines: {node: '>=0.10.0'} + iconv-lite@0.7.2: + resolution: {integrity: sha512-im9DjEDQ55s9fL4EYzOAv0yMqmMBSZp6G0VvFyTMPKWxiSBHUj9NW/qqLmXUwXrrM7AvqSlTCfvqRb0cM8yYqw==} + engines: {node: '>=0.10.0'} + icss-utils@5.1.0: resolution: {integrity: sha512-soFhflCVWLfRNOPU3iv5Z9VUdT44xFRbzjLsEzSr5AQmgqPMTHdU3PMT1Cf1ssx8fLNJDA1juftYl+PUcv3MqA==} engines: {node: ^10 || ^12 || >= 14} @@ -9041,6 +9122,13 @@ packages: import-in-the-middle@1.15.0: resolution: {integrity: sha512-bpQy+CrsRmYmoPMAE/0G33iwRqwW4ouqdRg8jgbH3aKuCtOc8lxgmYXg2dMM92CRiGP660EtBcymH/eVUpCSaA==} + import-in-the-middle@2.0.6: + resolution: {integrity: sha512-3vZV3jX0XRFW3EJDTwzWoZa+RH1b8eTTx6YOCjglrLyPuepwoBti1k3L2dKwdCUrnVEfc5CuRuGstaC/uQJJaw==} + + import-in-the-middle@3.0.1: + resolution: {integrity: sha512-pYkiyXVL2Mf3pozdlDGV6NAObxQx13Ae8knZk1UJRJ6uRW/ZRmTGHlQYtrsSl7ubuE5F8CD1z+s1n4RHNuTtuA==} + engines: {node: '>=18'} + import-lazy@4.0.0: resolution: {integrity: sha512-rKtvo6a868b5Hu3heneU+L4yEQ4jYKLtjpnPeUdK7h0yzXGmyBTypknlkCvHFBqfX9YlorEiMM6Dnq/5atfHkw==} engines: {node: '>=8'} @@ -9378,7 +9466,7 @@ packages: isomorphic-ws@5.0.0: resolution: {integrity: sha512-muId7Zzn9ywDsyXgTIafTry2sV3nySZeUDe6YedVd1Hvuuep5AsIlqK+XefWpYTyJG5e503F2xIuT2lcU6rCSw==} peerDependencies: - ws: '*' + ws: 8.20.1 istanbul-lib-coverage@3.2.2: resolution: {integrity: sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==} @@ -9491,21 +9579,15 @@ packages: jsonfile@6.2.0: resolution: {integrity: sha512-FGuPw30AdOIUTRMC2OMRtQV+jkVj2cfPqSeWXv1NEAJ1qZ5zb1X6z1mFhbfOB/iy3ssJCD+3KuZ8r8C3uVFlAg==} - jsonwebtoken@9.0.2: - resolution: {integrity: sha512-PRp66vJ865SSqOlgqS8hujT5U4AOgMfhrwYIuIhfKaoSCZcirrmASQr8CX7cUg+RMih+hgznrjp99o+W4pJLHQ==} + jsonwebtoken@9.0.3: + resolution: {integrity: sha512-MT/xP0CrubFRNLNKvxJ2BYfy53Zkm++5bX9dtuPbqAeQpTVe0MQTFhao8+Cp//EmJp244xt6Drw/GVEGCUj40g==} engines: {node: '>=12', npm: '>=6'} - jwa@1.4.2: - resolution: {integrity: sha512-eeH5JO+21J78qMvTIDdBXidBd6nG2kZjg5Ohz/1fpa28Z4CcsWUzJ1ZZyFq/3z3N17aZy+ZuBoHljASbL1WfOw==} - jwa@2.0.1: resolution: {integrity: sha512-hRF04fqJIP8Abbkq5NKGN0Bbr3JxlQ+qhZufXVr0DvujKy93ZCbXZMHDL4EOtodSbCWxOqR8MS1tXA5hwqCXDg==} - jws@3.2.2: - resolution: {integrity: sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA==} - - jws@4.0.0: - resolution: {integrity: sha512-KDncfTmOZoOMTFG4mBlG0qUIOlc03fmzH+ru6RgYVZhPkyiy/92Owlt/8UEN+a4TXR1FQetfIpJE8ApdvdVxTg==} + jws@4.0.1: + resolution: {integrity: sha512-EKI/M/yqPncGUUh44xz0PxSidXFr/+r0pA70+gIYhjv+et7yxM+s29Y+VGDkovRofQem0fs7Uvf4+YmAdyRduA==} jwt-decode@4.0.0: resolution: {integrity: sha512-+KJGIyHgkGuIq3IEBNftfhW/LfWhXUIY6OmyVWjliu5KH1y0fw7VQ8YndE2O4qZdMSd9SqbnC8GOcZEy0Om7sA==} @@ -9776,10 +9858,6 @@ packages: lru-cache@10.4.3: resolution: {integrity: sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==} - lru-cache@11.3.3: - resolution: {integrity: sha512-JvNw9Y81y33E+BEYPr0U7omo+U9AySnsMsEiXgwT6yqd31VQWTLNQqmT4ou5eqPFUrTfIDFta2wKhB1hyohtAQ==} - engines: {node: 20 || >=22} - lru-cache@11.3.5: resolution: {integrity: sha512-NxVFwLAnrd9i7KUBxC4DrUhmgjzOs+1Qm50D3oF1/oL+r1NpZ4gA7xvG0/zJ8evR7zIKn4vLf7qTNduWFtCrRw==} engines: {node: 20 || >=22} @@ -9787,12 +9865,8 @@ packages: lru-cache@5.1.1: resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==} - lru-cache@7.18.3: - resolution: {integrity: sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==} - engines: {node: '>=12'} - - lru.min@1.1.3: - resolution: {integrity: sha512-Lkk/vx6ak3rYkRR0Nhu4lFUT2VDnQSxBe8Hbl7f36358p6ow8Bnvr8lrLt98H8J1aGxfhbX4Fs5tYg2+FTwr5Q==} + lru.min@1.1.4: + resolution: {integrity: sha512-DqC6n3QQ77zdFpCMASA1a3Jlb64Hv2N2DciFGkO/4L9+q/IpIAuRlKOvCXabtRW6cQf8usbmM6BE/TOPysCdIA==} engines: {bun: '>=1.0.0', deno: '>=1.30.0', node: '>=8.0.0'} luxon@3.7.2: @@ -10268,16 +10342,18 @@ packages: mute-stream@0.0.8: resolution: {integrity: sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==} - mysql2@3.15.3: - resolution: {integrity: sha512-FBrGau0IXmuqg4haEZRBfHNWB5mUARw6hNwPDXXGg0XzVJ50mr/9hb267lvpVMnhZ1FON3qNd4Xfcez1rbFwSg==} + mysql2@3.22.3: + resolution: {integrity: sha512-uWWxvZSRvRhtBdh2CdcuK83YcOfPdmEeEYB069bAmPnV93QApDGVPuvCQOLjlh7tYHEWdgQPrn6kosDxHBVLkA==} engines: {node: '>= 8.0'} + peerDependencies: + '@types/node': '>= 8' mz@2.7.0: resolution: {integrity: sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==} - named-placeholders@1.1.3: - resolution: {integrity: sha512-eLoBxg6wE/rZkJPhU/xRX1WTpkFEwDJEN96oxFrTsqBdbT5ec295Q+CoHrL9IT0DipqKhmGcaZmwOt8OON5x1w==} - engines: {node: '>=12.0.0'} + named-placeholders@1.1.6: + resolution: {integrity: sha512-Tz09sEL2EEuv5fFowm419c1+a/jSMiBjI9gHxVLrVdbUkkNUUfjsVYs9pVZu5oCon/kmRh9TfLEObFtkVxmY0w==} + engines: {node: '>=8.0.0'} nanoid@3.3.11: resolution: {integrity: sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==} @@ -10665,8 +10741,8 @@ packages: pend@1.2.0: resolution: {integrity: sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==} - pg-connection-string@2.9.1: - resolution: {integrity: sha512-nkc6NpDcvPVpZXxrreI/FOtX3XemeLl8E0qFr6F2Lrm/I8WOnaWNhIPK2Z7OHpw7gh5XJThi6j6ppgNoaT1w4w==} + pg-connection-string@2.13.0: + resolution: {integrity: sha512-EMnU9E2fSULdsbErBbMaXJvFeD9B4+nPcM3f+4lsiCR0BHLPrLVjv3DbyM2hgQQviKJaTWIRRTjKjWlHg3p2ig==} picocolors@1.1.1: resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} @@ -11246,8 +11322,8 @@ packages: resolution: {integrity: sha512-KTqnxsgGiQ6ZAzZCVlJH5eOjSnvlyEgx1m8bkRJfOhmGRqfo5KLvmAlACQkrjEtOQ4B7wF9TdSLIs9O90MX9xA==} engines: {node: '>=16.0.0'} - qs@6.15.0: - resolution: {integrity: sha512-mAZTtNCeetKMH+pSjrb76NAM8V9a05I9aBZOHztWy/UqcJdQYNsf59vrRKWnojAT9Y+GbIvoTBC++CPHqpDBhQ==} + qs@6.15.2: + resolution: {integrity: sha512-Rzq0KEyX/w/tEybncDgdkZrJgVUsUMk3xjh3t5bv3S1HTAtg+uOYt72+ZfwiQwKdysThkTBdL/rTi6HDmX9Ddw==} engines: {node: '>=0.6'} queue-microtask@1.2.3: @@ -11269,6 +11345,10 @@ packages: resolution: {integrity: sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==} engines: {node: '>= 0.8'} + raw-body@2.5.3: + resolution: {integrity: sha512-s4VSOf6yN0rvbRZGxs8Om5CWj6seneMwK3oDb4lWDH0UPhWcxwOWw5+qk24bxq87szX1ydrwylIOp2uG1ojUpA==} + engines: {node: '>= 0.8'} + raw-body@3.0.2: resolution: {integrity: sha512-K5zQjDllxWkf7Z5xJdV0/B0WTNqx6vxG70zJE4N0kBs4LovmEYWJzQGxC9bS9RAKu3bgM40lrd5zoLJ12MQ5BA==} engines: {node: '>= 0.10'} @@ -11547,6 +11627,10 @@ packages: resolution: {integrity: sha512-gAZ+kLqBdHarXB64XpAe2VCjB7rIRv+mU8tfRWziHRJ5umKsIHN2tLLv6EtMw7WCdP19S0ERVMldNvxYCHnhSQ==} engines: {node: '>=8.6.0'} + require-in-the-middle@8.0.1: + resolution: {integrity: sha512-QT7FVMXfWOYFbeRBF6nu+I6tr2Tf3u0q8RIEjNob/heKY/nh7drD/k7eeMFmSQgnTtCzLDcCu/XEnpW2wk4xCQ==} + engines: {node: '>=9.3.0 || >=8.10.0 <9.0.0'} + require-like@0.1.2: resolution: {integrity: sha512-oyrU88skkMtDdauHDuKVrgR+zuItqr6/c//FXzvmxRGMexSDc6hNvJInGW3LL46n+8b50RykrvwSUIIQH2LQ5A==} @@ -11664,8 +11748,8 @@ packages: rxjs@7.8.2: resolution: {integrity: sha512-dhKf903U/PQZY6boNNtAGdWbG85WAbjT/1xYoZIC7FAY0yWapOBQVsVrDl58W86//e1VpMNBtRV4MaXfdMySFA==} - safe-array-concat@1.1.3: - resolution: {integrity: sha512-AURm5f0jYEOydBj7VQlVvDrjeFgthDdEF5H1dP+6mNpoXOMo1quQqJ4wvJDyRZ9+pO3kGWoOdmV08cSv2aJV6Q==} + safe-array-concat@1.1.4: + resolution: {integrity: sha512-wtZlHyOje6OZTGqAoaDKxFkgRtkF9CnHAVnCHKfuj200wAgL+bSJhdsCD2l0Qx/2ekEXjPWcyKkfGb5CPboslg==} engines: {node: '>=0.4'} safe-buffer@5.1.2: @@ -11774,15 +11858,12 @@ packages: sentence-case@3.0.4: resolution: {integrity: sha512-8LS0JInaQMCRoQ7YUytAo/xUu5W2XnQxV2HI/6uM6U7CITS1RqPElr30V6uIqyMKM9lJGRVFy5/4CuzcixNYSg==} - seq-queue@0.0.5: - resolution: {integrity: sha512-hr3Wtp/GZIc/6DAGPDcV4/9WoZhjrkXsi5B/07QgX8tsdc6ilr7BFM6PM6rbdAX1kFSDYeZGLipIZZKyQP0O5Q==} - sequelize-pool@7.1.0: resolution: {integrity: sha512-G9c0qlIWQSK29pR/5U2JF5dDQeqqHRragoyahj/Nx4KOOQ3CPPfzxnfqFPCSB7x5UgjOgnZ61nSxz+fjDpRlJg==} engines: {node: '>= 10.0.0'} - sequelize@6.37.7: - resolution: {integrity: sha512-mCnh83zuz7kQxxJirtFD7q6Huy6liPanI67BSlbzSYgVNl5eXVdE2CN1FuAeZwG1SNpGsNRCV+bJAVVnykZAFA==} + sequelize@6.37.8: + resolution: {integrity: sha512-HJ0IQFqcTsTiqbEgiuioYFMSD00TP6Cz7zoTti+zVVBwVe9fEhev9cH6WnM3XU31+ABS356durAb99ZuOthnKw==} engines: {node: '>=10.0.0'} peerDependencies: ibm_db: '*' @@ -12031,9 +12112,9 @@ packages: sprintf-js@1.1.3: resolution: {integrity: sha512-Oo+0REFV59/rz3gfJNKQiBlwfHaSESl1pcGyABQsnnIfWOFt6JNj5gCog2U6MLZ//IGYD+nA8nI+mTShREReaA==} - sqlstring@2.3.3: - resolution: {integrity: sha512-qC9iz2FlN7DQl3+wjwn3802RTyjCx7sDvfQEXchwa6CWOx07/WVfh91gBmQ9fahw8snwGEWU3xGzOt4tFyHLxg==} - engines: {node: '>= 0.6'} + sql-escaper@1.3.3: + resolution: {integrity: sha512-BsTCV265VpTp8tm1wyIm1xqQCS+Q9NHx2Sr+WcnUrgLrQ6yiDIvHYJV5gHxsj1lMBy2zm5twLaZao8Jd+S8JJw==} + engines: {bun: '>=1.0.0', deno: '>=2.0.0', node: '>=12.0.0'} srcset@4.0.0: resolution: {integrity: sha512-wvLeHgcVHKO8Sc/H/5lkGreJQVeYMm9rlmt8PuR1xE31rIuXhuzznUUqAt8MqLhB3MqJdFzlNAfpcWnxiFUcPw==} @@ -12741,8 +12822,27 @@ packages: resolution: {integrity: sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==} engines: {node: '>= 0.4.0'} - uuid@14.0.0: - resolution: {integrity: sha512-Qo+uWgilfSmAhXCMav1uYFynlQO7fMFiMVZsQqZRMIXp0O7rR7qjkj+cPvBHLgBqi960QCoo/PH2/6ZtVqKvrg==} + uuid@10.0.0: + resolution: {integrity: sha512-8XkAphELsDnEGrDxUOHB3RGvXz6TeuYSGEZBOjtTtPm2lwhGBjLgOzLHB63IUWfBpNucQjND6d3AOudO+H3RWQ==} + deprecated: uuid@10 and below is no longer supported. For ESM codebases, update to uuid@latest. For CommonJS codebases, use uuid@11 (but be aware this version will likely be deprecated in 2028). + hasBin: true + + uuid@11.0.5: + resolution: {integrity: sha512-508e6IcKLrhxKdBbcA2b4KQZlLVp2+J5UwQ6F7Drckkc5N9ZJwFa4TgWtsww9UG8fGHbm6gbV19TdM5pQ4GaIA==} + hasBin: true + + uuid@11.1.1: + resolution: {integrity: sha512-vIYxrBCC/N/K+Js3qSN88go7kIfNPssr/hHCesKCQNAjmgvYS2oqr69kIufEG+O4+PfezOH4EbIeHCfFov8ZgQ==} + hasBin: true + + uuid@3.4.0: + resolution: {integrity: sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==} + deprecated: uuid@10 and below is no longer supported. For ESM codebases, update to uuid@latest. For CommonJS codebases, use uuid@11 (but be aware this version will likely be deprecated in 2028). + hasBin: true + + uuid@8.3.2: + resolution: {integrity: sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==} + deprecated: uuid@10 and below is no longer supported. For ESM codebases, update to uuid@latest. For CommonJS codebases, use uuid@11 (but be aware this version will likely be deprecated in 2028). hasBin: true v8-to-istanbul@9.3.0: @@ -12756,8 +12856,8 @@ packages: resolution: {integrity: sha512-hVDIBwsRruT73PbK7uP5ebUt+ezEtCmzZz3F59BSr2F6OVFnJ/6h8liuvdLrQ88Xmnk6/+xGGuq+pG9WwTuy3A==} engines: {node: ^20.17.0 || >=22.9.0} - validator@13.15.23: - resolution: {integrity: sha512-4yoz1kEWqUjzi5zsPbAS/903QXSYp0UOtHsPpp7p9rHAw/W+dkInskAE386Fat3oKRROwO98d9ZB0G4cObgUyw==} + validator@13.15.35: + resolution: {integrity: sha512-TQ5pAGhd5whStmqWvYF4OjQROlmv9SMFVt37qoCBdqRffuuklWYQlCNnEs2ZaIBD1kZRNnikiZOS1eqgkar0iw==} engines: {node: '>= 0.10'} value-equal@1.0.1: @@ -13024,8 +13124,8 @@ packages: resolution: {integrity: sha512-8drMJ4rkgaPo1Me4zD/3WLfI/zPdA9o2IipKODunnGDcuqbHwjsbB79ylv04LCGGzU0xQ6vTznOMpQGaLhhm6A==} engines: {node: '>= 12.0.0'} - winston@3.18.3: - resolution: {integrity: sha512-NoBZauFNNWENgsnC9YpgyYwOVrl2m58PpQ8lNHjV3kosGs7KJ7Npk9pCUE+WJlawVSe8mykWDKWFSVfs3QO9ww==} + winston@3.19.0: + resolution: {integrity: sha512-LZNJgPzfKR+/J3cHkxcpHKpKKvGfDZVPS4hfJCc4cCG0CgYzvlD6yE/S3CIL/Yt91ak327YCpiF/0MyeZHEHKA==} engines: {node: '>= 12.0.0'} wkx@0.5.0: @@ -13061,8 +13161,8 @@ packages: utf-8-validate: optional: true - ws@8.20.0: - resolution: {integrity: sha512-sAt8BhgNbzCtgGbt2OxmpuryO63ZoDk/sqaB/znQm94T4fCEsy/yV+7CdC1kJhOU9lboAEU7R3kquuycDoibVA==} + ws@8.20.1: + resolution: {integrity: sha512-It4dO0K5v//JtTXuPkfEOaI3uUN87iYPnqo/ZzqCoG3g8uhA66QUMs/SrM0YK7/NAu+r4LMh/9dq2A7k+rHs+w==} engines: {node: '>=10.0.0'} peerDependencies: bufferutil: ^4.0.1 @@ -13456,7 +13556,7 @@ snapshots: dependencies: graphql: 16.12.0 - '@apollo/client@3.14.0(@types/react@19.2.7)(graphql-ws@6.0.6(graphql@16.12.0)(ws@8.20.0))(graphql@16.12.0)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': + '@apollo/client@3.14.0(@types/react@19.2.7)(graphql-ws@6.0.6(graphql@16.12.0)(ws@8.20.1))(graphql@16.12.0)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': dependencies: '@graphql-typed-document-node/core': 3.2.0(graphql@16.12.0) '@wry/caches': 1.0.1 @@ -13473,7 +13573,7 @@ snapshots: tslib: 2.8.1 zen-observable-ts: 1.2.5 optionalDependencies: - graphql-ws: 6.0.6(graphql@16.12.0)(ws@8.20.0) + graphql-ws: 6.0.6(graphql@16.12.0)(ws@8.20.1) react: 19.2.0 react-dom: 19.2.0(react@19.2.0) transitivePeerDependencies: @@ -13522,9 +13622,9 @@ snapshots: finalhandler: 2.1.1 graphql: 16.12.0 loglevel: 1.9.2 - lru-cache: 11.3.3 + lru-cache: 11.3.5 negotiator: 1.0.0 - uuid: 14.0.0 + uuid: 11.1.1 whatwg-mimetype: 4.0.0 transitivePeerDependencies: - supports-color @@ -13606,7 +13706,7 @@ snapshots: '@csstools/css-tokenizer': 3.0.4 lru-cache: 10.4.3 - '@azure-rest/core-client@2.5.1': + '@azure-rest/core-client@2.6.0': dependencies: '@azure/abort-controller': 2.1.2 '@azure/core-auth': 1.10.1 @@ -13653,13 +13753,11 @@ snapshots: transitivePeerDependencies: - supports-color - '@azure/core-http-compat@2.3.1': + '@azure/core-http-compat@2.4.0(@azure/core-client@1.10.1)(@azure/core-rest-pipeline@1.22.2)': dependencies: '@azure/abort-controller': 2.1.2 '@azure/core-client': 1.10.1 '@azure/core-rest-pipeline': 1.22.2 - transitivePeerDependencies: - - supports-color '@azure/core-lro@2.7.2': dependencies: @@ -13738,18 +13836,18 @@ snapshots: '@azure/msal-browser': 3.30.0 '@azure/msal-node': 2.16.3 events: 3.3.0 - jws: 4.0.0 + jws: 4.0.1 open: 8.4.2 stoppable: 1.1.0 tslib: 2.8.1 transitivePeerDependencies: - supports-color - '@azure/keyvault-common@2.0.0': + '@azure/keyvault-common@2.1.0': dependencies: + '@azure-rest/core-client': 2.6.0 '@azure/abort-controller': 2.1.2 '@azure/core-auth': 1.10.1 - '@azure/core-client': 1.10.1 '@azure/core-rest-pipeline': 1.22.2 '@azure/core-tracing': 1.3.1 '@azure/core-util': 1.13.1 @@ -13758,21 +13856,22 @@ snapshots: transitivePeerDependencies: - supports-color - '@azure/keyvault-keys@4.10.0': + '@azure/keyvault-keys@4.10.0(@azure/core-client@1.10.1)': dependencies: - '@azure-rest/core-client': 2.5.1 + '@azure-rest/core-client': 2.6.0 '@azure/abort-controller': 2.1.2 '@azure/core-auth': 1.10.1 - '@azure/core-http-compat': 2.3.1 + '@azure/core-http-compat': 2.4.0(@azure/core-client@1.10.1)(@azure/core-rest-pipeline@1.22.2) '@azure/core-lro': 2.7.2 '@azure/core-paging': 1.6.2 '@azure/core-rest-pipeline': 1.22.2 '@azure/core-tracing': 1.3.1 '@azure/core-util': 1.13.1 - '@azure/keyvault-common': 2.0.0 + '@azure/keyvault-common': 2.1.0 '@azure/logger': 1.3.0 tslib: 2.8.1 transitivePeerDependencies: + - '@azure/core-client' - supports-color '@azure/logger@1.3.0': @@ -13807,7 +13906,7 @@ snapshots: tough-cookie: 2.5.0 tslib: 1.14.1 tunnel: 0.0.6 - uuid: 14.0.0 + uuid: 3.4.0 xml2js: 0.4.23 transitivePeerDependencies: - debug @@ -13822,17 +13921,17 @@ snapshots: '@azure/msal-node@2.16.3': dependencies: '@azure/msal-common': 14.16.1 - jsonwebtoken: 9.0.2 - uuid: 14.0.0 + jsonwebtoken: 9.0.3 + uuid: 8.3.2 - '@azure/opentelemetry-instrumentation-azure-sdk@1.0.0-beta.9': + '@azure/opentelemetry-instrumentation-azure-sdk@1.0.0': dependencies: '@azure/core-tracing': 1.3.1 '@azure/logger': 1.3.0 '@opentelemetry/api': 1.9.0 '@opentelemetry/core': 2.7.1(@opentelemetry/api@1.9.0) - '@opentelemetry/instrumentation': 0.200.0(@opentelemetry/api@1.9.0) - '@opentelemetry/sdk-trace-web': 2.2.0(@opentelemetry/api@1.9.0) + '@opentelemetry/instrumentation': 0.211.0(@opentelemetry/api@1.9.0) + '@opentelemetry/sdk-trace-web': 2.7.1(@opentelemetry/api@1.9.0) tslib: 2.8.1 transitivePeerDependencies: - supports-color @@ -15085,14 +15184,14 @@ snapshots: '@types/uuid': 10.0.0 class-transformer: 0.5.1 reflect-metadata: 0.2.2 - uuid: 14.0.0 + uuid: 10.0.0 '@cucumber/messages@27.2.0': dependencies: '@types/uuid': 10.0.0 class-transformer: 0.5.1 reflect-metadata: 0.2.2 - uuid: 14.0.0 + uuid: 11.0.5 '@cucumber/messages@32.2.0': dependencies: @@ -16405,10 +16504,10 @@ snapshots: '@graphql-tools/utils': 10.11.0(graphql@16.12.0) '@whatwg-node/disposablestack': 0.0.6 graphql: 16.12.0 - graphql-ws: 6.0.6(graphql@16.12.0)(ws@8.20.0) - isomorphic-ws: 5.0.0(ws@8.20.0) + graphql-ws: 6.0.6(graphql@16.12.0)(ws@8.20.1) + isomorphic-ws: 5.0.0(ws@8.20.1) tslib: 2.8.1 - ws: 8.20.0 + ws: 8.20.1 transitivePeerDependencies: - '@fastify/websocket' - bufferutil @@ -16436,9 +16535,9 @@ snapshots: '@graphql-tools/utils': 10.11.0(graphql@16.12.0) '@types/ws': 8.18.1 graphql: 16.12.0 - isomorphic-ws: 5.0.0(ws@8.20.0) + isomorphic-ws: 5.0.0(ws@8.20.1) tslib: 2.8.1 - ws: 8.20.0 + ws: 8.20.1 transitivePeerDependencies: - bufferutil - utf-8-validate @@ -16610,10 +16709,10 @@ snapshots: '@whatwg-node/fetch': 0.10.13 '@whatwg-node/promise-helpers': 1.3.2 graphql: 16.12.0 - isomorphic-ws: 5.0.0(ws@8.20.0) + isomorphic-ws: 5.0.0(ws@8.20.1) sync-fetch: 0.6.0-2 tslib: 2.8.1 - ws: 8.20.0 + ws: 8.20.1 transitivePeerDependencies: - '@fastify/websocket' - '@types/node' @@ -16730,7 +16829,7 @@ snapshots: '@jridgewell/resolve-uri': 3.1.2 '@jridgewell/sourcemap-codec': 1.5.5 - '@js-joda/core@5.6.5': {} + '@js-joda/core@5.7.0': {} '@js-sdsl/ordered-map@4.4.2': {} @@ -16845,6 +16944,14 @@ snapshots: dependencies: '@opentelemetry/api': 1.9.0 + '@opentelemetry/api-logs@0.211.0': + dependencies: + '@opentelemetry/api': 1.9.0 + + '@opentelemetry/api-logs@0.217.0': + dependencies: + '@opentelemetry/api': 1.9.0 + '@opentelemetry/api-logs@0.52.1': dependencies: '@opentelemetry/api': 1.9.0 @@ -16855,10 +16962,20 @@ snapshots: '@opentelemetry/api@1.9.0': {} + '@opentelemetry/configuration@0.217.0(@opentelemetry/api@1.9.0)': + dependencies: + '@opentelemetry/api': 1.9.0 + '@opentelemetry/core': 2.7.1(@opentelemetry/api@1.9.0) + yaml: 2.8.3 + '@opentelemetry/context-async-hooks@1.30.1(@opentelemetry/api@1.9.0)': dependencies: '@opentelemetry/api': 1.9.0 + '@opentelemetry/context-async-hooks@2.7.1(@opentelemetry/api@1.9.0)': + dependencies: + '@opentelemetry/api': 1.9.0 + '@opentelemetry/core@1.25.1(@opentelemetry/api@1.9.0)': dependencies: '@opentelemetry/api': 1.9.0 @@ -16879,110 +16996,111 @@ snapshots: '@opentelemetry/api': 1.9.0 '@opentelemetry/semantic-conventions': 1.38.0 - '@opentelemetry/exporter-logs-otlp-grpc@0.57.2(@opentelemetry/api@1.9.0)': + '@opentelemetry/exporter-logs-otlp-grpc@0.217.0(@opentelemetry/api@1.9.0)': dependencies: '@grpc/grpc-js': 1.14.3 '@opentelemetry/api': 1.9.0 - '@opentelemetry/core': 1.30.1(@opentelemetry/api@1.9.0) - '@opentelemetry/otlp-exporter-base': 0.57.2(@opentelemetry/api@1.9.0) - '@opentelemetry/otlp-grpc-exporter-base': 0.57.2(@opentelemetry/api@1.9.0) - '@opentelemetry/otlp-transformer': 0.57.2(@opentelemetry/api@1.9.0) - '@opentelemetry/sdk-logs': 0.57.2(@opentelemetry/api@1.9.0) + '@opentelemetry/core': 2.7.1(@opentelemetry/api@1.9.0) + '@opentelemetry/otlp-exporter-base': 0.217.0(@opentelemetry/api@1.9.0) + '@opentelemetry/otlp-grpc-exporter-base': 0.217.0(@opentelemetry/api@1.9.0) + '@opentelemetry/otlp-transformer': 0.217.0(@opentelemetry/api@1.9.0) + '@opentelemetry/sdk-logs': 0.217.0(@opentelemetry/api@1.9.0) - '@opentelemetry/exporter-logs-otlp-http@0.57.2(@opentelemetry/api@1.9.0)': + '@opentelemetry/exporter-logs-otlp-http@0.217.0(@opentelemetry/api@1.9.0)': dependencies: '@opentelemetry/api': 1.9.0 - '@opentelemetry/api-logs': 0.57.2 - '@opentelemetry/core': 1.30.1(@opentelemetry/api@1.9.0) - '@opentelemetry/otlp-exporter-base': 0.57.2(@opentelemetry/api@1.9.0) - '@opentelemetry/otlp-transformer': 0.57.2(@opentelemetry/api@1.9.0) - '@opentelemetry/sdk-logs': 0.57.2(@opentelemetry/api@1.9.0) + '@opentelemetry/api-logs': 0.217.0 + '@opentelemetry/core': 2.7.1(@opentelemetry/api@1.9.0) + '@opentelemetry/otlp-exporter-base': 0.217.0(@opentelemetry/api@1.9.0) + '@opentelemetry/otlp-transformer': 0.217.0(@opentelemetry/api@1.9.0) + '@opentelemetry/sdk-logs': 0.217.0(@opentelemetry/api@1.9.0) - '@opentelemetry/exporter-logs-otlp-proto@0.57.2(@opentelemetry/api@1.9.0)': + '@opentelemetry/exporter-logs-otlp-proto@0.217.0(@opentelemetry/api@1.9.0)': dependencies: '@opentelemetry/api': 1.9.0 - '@opentelemetry/api-logs': 0.57.2 - '@opentelemetry/core': 1.30.1(@opentelemetry/api@1.9.0) - '@opentelemetry/otlp-exporter-base': 0.57.2(@opentelemetry/api@1.9.0) - '@opentelemetry/otlp-transformer': 0.57.2(@opentelemetry/api@1.9.0) - '@opentelemetry/resources': 1.30.1(@opentelemetry/api@1.9.0) - '@opentelemetry/sdk-logs': 0.57.2(@opentelemetry/api@1.9.0) - '@opentelemetry/sdk-trace-base': 1.30.1(@opentelemetry/api@1.9.0) + '@opentelemetry/api-logs': 0.217.0 + '@opentelemetry/core': 2.7.1(@opentelemetry/api@1.9.0) + '@opentelemetry/otlp-exporter-base': 0.217.0(@opentelemetry/api@1.9.0) + '@opentelemetry/otlp-transformer': 0.217.0(@opentelemetry/api@1.9.0) + '@opentelemetry/resources': 2.7.1(@opentelemetry/api@1.9.0) + '@opentelemetry/sdk-logs': 0.217.0(@opentelemetry/api@1.9.0) + '@opentelemetry/sdk-trace-base': 2.7.1(@opentelemetry/api@1.9.0) - '@opentelemetry/exporter-metrics-otlp-grpc@0.57.2(@opentelemetry/api@1.9.0)': + '@opentelemetry/exporter-metrics-otlp-grpc@0.217.0(@opentelemetry/api@1.9.0)': dependencies: '@grpc/grpc-js': 1.14.3 '@opentelemetry/api': 1.9.0 - '@opentelemetry/core': 1.30.1(@opentelemetry/api@1.9.0) - '@opentelemetry/exporter-metrics-otlp-http': 0.57.2(@opentelemetry/api@1.9.0) - '@opentelemetry/otlp-exporter-base': 0.57.2(@opentelemetry/api@1.9.0) - '@opentelemetry/otlp-grpc-exporter-base': 0.57.2(@opentelemetry/api@1.9.0) - '@opentelemetry/otlp-transformer': 0.57.2(@opentelemetry/api@1.9.0) - '@opentelemetry/resources': 1.30.1(@opentelemetry/api@1.9.0) - '@opentelemetry/sdk-metrics': 1.30.1(@opentelemetry/api@1.9.0) + '@opentelemetry/core': 2.7.1(@opentelemetry/api@1.9.0) + '@opentelemetry/exporter-metrics-otlp-http': 0.217.0(@opentelemetry/api@1.9.0) + '@opentelemetry/otlp-exporter-base': 0.217.0(@opentelemetry/api@1.9.0) + '@opentelemetry/otlp-grpc-exporter-base': 0.217.0(@opentelemetry/api@1.9.0) + '@opentelemetry/otlp-transformer': 0.217.0(@opentelemetry/api@1.9.0) + '@opentelemetry/resources': 2.7.1(@opentelemetry/api@1.9.0) + '@opentelemetry/sdk-metrics': 2.7.1(@opentelemetry/api@1.9.0) - '@opentelemetry/exporter-metrics-otlp-http@0.57.2(@opentelemetry/api@1.9.0)': + '@opentelemetry/exporter-metrics-otlp-http@0.217.0(@opentelemetry/api@1.9.0)': dependencies: '@opentelemetry/api': 1.9.0 - '@opentelemetry/core': 1.30.1(@opentelemetry/api@1.9.0) - '@opentelemetry/otlp-exporter-base': 0.57.2(@opentelemetry/api@1.9.0) - '@opentelemetry/otlp-transformer': 0.57.2(@opentelemetry/api@1.9.0) - '@opentelemetry/resources': 1.30.1(@opentelemetry/api@1.9.0) - '@opentelemetry/sdk-metrics': 1.30.1(@opentelemetry/api@1.9.0) + '@opentelemetry/core': 2.7.1(@opentelemetry/api@1.9.0) + '@opentelemetry/otlp-exporter-base': 0.217.0(@opentelemetry/api@1.9.0) + '@opentelemetry/otlp-transformer': 0.217.0(@opentelemetry/api@1.9.0) + '@opentelemetry/resources': 2.7.1(@opentelemetry/api@1.9.0) + '@opentelemetry/sdk-metrics': 2.7.1(@opentelemetry/api@1.9.0) - '@opentelemetry/exporter-metrics-otlp-proto@0.57.2(@opentelemetry/api@1.9.0)': + '@opentelemetry/exporter-metrics-otlp-proto@0.217.0(@opentelemetry/api@1.9.0)': dependencies: '@opentelemetry/api': 1.9.0 - '@opentelemetry/core': 1.30.1(@opentelemetry/api@1.9.0) - '@opentelemetry/exporter-metrics-otlp-http': 0.57.2(@opentelemetry/api@1.9.0) - '@opentelemetry/otlp-exporter-base': 0.57.2(@opentelemetry/api@1.9.0) - '@opentelemetry/otlp-transformer': 0.57.2(@opentelemetry/api@1.9.0) - '@opentelemetry/resources': 1.30.1(@opentelemetry/api@1.9.0) - '@opentelemetry/sdk-metrics': 1.30.1(@opentelemetry/api@1.9.0) + '@opentelemetry/core': 2.7.1(@opentelemetry/api@1.9.0) + '@opentelemetry/exporter-metrics-otlp-http': 0.217.0(@opentelemetry/api@1.9.0) + '@opentelemetry/otlp-exporter-base': 0.217.0(@opentelemetry/api@1.9.0) + '@opentelemetry/otlp-transformer': 0.217.0(@opentelemetry/api@1.9.0) + '@opentelemetry/resources': 2.7.1(@opentelemetry/api@1.9.0) + '@opentelemetry/sdk-metrics': 2.7.1(@opentelemetry/api@1.9.0) - '@opentelemetry/exporter-prometheus@0.57.2(@opentelemetry/api@1.9.0)': + '@opentelemetry/exporter-prometheus@0.217.0(@opentelemetry/api@1.9.0)': dependencies: '@opentelemetry/api': 1.9.0 - '@opentelemetry/core': 1.30.1(@opentelemetry/api@1.9.0) - '@opentelemetry/resources': 1.30.1(@opentelemetry/api@1.9.0) - '@opentelemetry/sdk-metrics': 1.30.1(@opentelemetry/api@1.9.0) + '@opentelemetry/core': 2.7.1(@opentelemetry/api@1.9.0) + '@opentelemetry/resources': 2.7.1(@opentelemetry/api@1.9.0) + '@opentelemetry/sdk-metrics': 2.7.1(@opentelemetry/api@1.9.0) + '@opentelemetry/semantic-conventions': 1.38.0 - '@opentelemetry/exporter-trace-otlp-grpc@0.57.2(@opentelemetry/api@1.9.0)': + '@opentelemetry/exporter-trace-otlp-grpc@0.217.0(@opentelemetry/api@1.9.0)': dependencies: '@grpc/grpc-js': 1.14.3 '@opentelemetry/api': 1.9.0 - '@opentelemetry/core': 1.30.1(@opentelemetry/api@1.9.0) - '@opentelemetry/otlp-exporter-base': 0.57.2(@opentelemetry/api@1.9.0) - '@opentelemetry/otlp-grpc-exporter-base': 0.57.2(@opentelemetry/api@1.9.0) - '@opentelemetry/otlp-transformer': 0.57.2(@opentelemetry/api@1.9.0) - '@opentelemetry/resources': 1.30.1(@opentelemetry/api@1.9.0) - '@opentelemetry/sdk-trace-base': 1.30.1(@opentelemetry/api@1.9.0) + '@opentelemetry/core': 2.7.1(@opentelemetry/api@1.9.0) + '@opentelemetry/otlp-exporter-base': 0.217.0(@opentelemetry/api@1.9.0) + '@opentelemetry/otlp-grpc-exporter-base': 0.217.0(@opentelemetry/api@1.9.0) + '@opentelemetry/otlp-transformer': 0.217.0(@opentelemetry/api@1.9.0) + '@opentelemetry/resources': 2.7.1(@opentelemetry/api@1.9.0) + '@opentelemetry/sdk-trace-base': 2.7.1(@opentelemetry/api@1.9.0) - '@opentelemetry/exporter-trace-otlp-http@0.57.2(@opentelemetry/api@1.9.0)': + '@opentelemetry/exporter-trace-otlp-http@0.217.0(@opentelemetry/api@1.9.0)': dependencies: '@opentelemetry/api': 1.9.0 - '@opentelemetry/core': 1.30.1(@opentelemetry/api@1.9.0) - '@opentelemetry/otlp-exporter-base': 0.57.2(@opentelemetry/api@1.9.0) - '@opentelemetry/otlp-transformer': 0.57.2(@opentelemetry/api@1.9.0) - '@opentelemetry/resources': 1.30.1(@opentelemetry/api@1.9.0) - '@opentelemetry/sdk-trace-base': 1.30.1(@opentelemetry/api@1.9.0) + '@opentelemetry/core': 2.7.1(@opentelemetry/api@1.9.0) + '@opentelemetry/otlp-exporter-base': 0.217.0(@opentelemetry/api@1.9.0) + '@opentelemetry/otlp-transformer': 0.217.0(@opentelemetry/api@1.9.0) + '@opentelemetry/resources': 2.7.1(@opentelemetry/api@1.9.0) + '@opentelemetry/sdk-trace-base': 2.7.1(@opentelemetry/api@1.9.0) - '@opentelemetry/exporter-trace-otlp-proto@0.57.2(@opentelemetry/api@1.9.0)': + '@opentelemetry/exporter-trace-otlp-proto@0.217.0(@opentelemetry/api@1.9.0)': dependencies: '@opentelemetry/api': 1.9.0 - '@opentelemetry/core': 1.30.1(@opentelemetry/api@1.9.0) - '@opentelemetry/otlp-exporter-base': 0.57.2(@opentelemetry/api@1.9.0) - '@opentelemetry/otlp-transformer': 0.57.2(@opentelemetry/api@1.9.0) - '@opentelemetry/resources': 1.30.1(@opentelemetry/api@1.9.0) - '@opentelemetry/sdk-trace-base': 1.30.1(@opentelemetry/api@1.9.0) + '@opentelemetry/core': 2.7.1(@opentelemetry/api@1.9.0) + '@opentelemetry/otlp-exporter-base': 0.217.0(@opentelemetry/api@1.9.0) + '@opentelemetry/otlp-transformer': 0.217.0(@opentelemetry/api@1.9.0) + '@opentelemetry/resources': 2.7.1(@opentelemetry/api@1.9.0) + '@opentelemetry/sdk-trace-base': 2.7.1(@opentelemetry/api@1.9.0) - '@opentelemetry/exporter-zipkin@1.30.1(@opentelemetry/api@1.9.0)': + '@opentelemetry/exporter-zipkin@2.7.1(@opentelemetry/api@1.9.0)': dependencies: '@opentelemetry/api': 1.9.0 - '@opentelemetry/core': 1.30.1(@opentelemetry/api@1.9.0) - '@opentelemetry/resources': 1.30.1(@opentelemetry/api@1.9.0) - '@opentelemetry/sdk-trace-base': 1.30.1(@opentelemetry/api@1.9.0) - '@opentelemetry/semantic-conventions': 1.28.0 + '@opentelemetry/core': 2.7.1(@opentelemetry/api@1.9.0) + '@opentelemetry/resources': 2.7.1(@opentelemetry/api@1.9.0) + '@opentelemetry/sdk-trace-base': 2.7.1(@opentelemetry/api@1.9.0) + '@opentelemetry/semantic-conventions': 1.38.0 '@opentelemetry/instrumentation-dataloader@0.17.0(@opentelemetry/api@1.9.0)': dependencies: @@ -17028,22 +17146,28 @@ snapshots: transitivePeerDependencies: - supports-color - '@opentelemetry/instrumentation@0.52.1(@opentelemetry/api@1.9.0)': + '@opentelemetry/instrumentation@0.211.0(@opentelemetry/api@1.9.0)': dependencies: '@opentelemetry/api': 1.9.0 - '@opentelemetry/api-logs': 0.52.1 - '@types/shimmer': 1.2.0 - import-in-the-middle: 1.15.0 - require-in-the-middle: 7.5.2 - semver: 7.7.4 - shimmer: 1.2.1 + '@opentelemetry/api-logs': 0.211.0 + import-in-the-middle: 2.0.6 + require-in-the-middle: 8.0.1 transitivePeerDependencies: - supports-color - '@opentelemetry/instrumentation@0.57.2(@opentelemetry/api@1.9.0)': + '@opentelemetry/instrumentation@0.217.0(@opentelemetry/api@1.9.0)': dependencies: '@opentelemetry/api': 1.9.0 - '@opentelemetry/api-logs': 0.57.2 + '@opentelemetry/api-logs': 0.217.0 + import-in-the-middle: 3.0.1 + require-in-the-middle: 8.0.1 + transitivePeerDependencies: + - supports-color + + '@opentelemetry/instrumentation@0.52.1(@opentelemetry/api@1.9.0)': + dependencies: + '@opentelemetry/api': 1.9.0 + '@opentelemetry/api-logs': 0.52.1 '@types/shimmer': 1.2.0 import-in-the-middle: 1.15.0 require-in-the-middle: 7.5.2 @@ -17052,29 +17176,29 @@ snapshots: transitivePeerDependencies: - supports-color - '@opentelemetry/otlp-exporter-base@0.57.2(@opentelemetry/api@1.9.0)': + '@opentelemetry/otlp-exporter-base@0.217.0(@opentelemetry/api@1.9.0)': dependencies: '@opentelemetry/api': 1.9.0 - '@opentelemetry/core': 1.30.1(@opentelemetry/api@1.9.0) - '@opentelemetry/otlp-transformer': 0.57.2(@opentelemetry/api@1.9.0) + '@opentelemetry/core': 2.7.1(@opentelemetry/api@1.9.0) + '@opentelemetry/otlp-transformer': 0.217.0(@opentelemetry/api@1.9.0) - '@opentelemetry/otlp-grpc-exporter-base@0.57.2(@opentelemetry/api@1.9.0)': + '@opentelemetry/otlp-grpc-exporter-base@0.217.0(@opentelemetry/api@1.9.0)': dependencies: '@grpc/grpc-js': 1.14.3 '@opentelemetry/api': 1.9.0 - '@opentelemetry/core': 1.30.1(@opentelemetry/api@1.9.0) - '@opentelemetry/otlp-exporter-base': 0.57.2(@opentelemetry/api@1.9.0) - '@opentelemetry/otlp-transformer': 0.57.2(@opentelemetry/api@1.9.0) + '@opentelemetry/core': 2.7.1(@opentelemetry/api@1.9.0) + '@opentelemetry/otlp-exporter-base': 0.217.0(@opentelemetry/api@1.9.0) + '@opentelemetry/otlp-transformer': 0.217.0(@opentelemetry/api@1.9.0) - '@opentelemetry/otlp-transformer@0.57.2(@opentelemetry/api@1.9.0)': + '@opentelemetry/otlp-transformer@0.217.0(@opentelemetry/api@1.9.0)': dependencies: '@opentelemetry/api': 1.9.0 - '@opentelemetry/api-logs': 0.57.2 - '@opentelemetry/core': 1.30.1(@opentelemetry/api@1.9.0) - '@opentelemetry/resources': 1.30.1(@opentelemetry/api@1.9.0) - '@opentelemetry/sdk-logs': 0.57.2(@opentelemetry/api@1.9.0) - '@opentelemetry/sdk-metrics': 1.30.1(@opentelemetry/api@1.9.0) - '@opentelemetry/sdk-trace-base': 1.30.1(@opentelemetry/api@1.9.0) + '@opentelemetry/api-logs': 0.217.0 + '@opentelemetry/core': 2.7.1(@opentelemetry/api@1.9.0) + '@opentelemetry/resources': 2.7.1(@opentelemetry/api@1.9.0) + '@opentelemetry/sdk-logs': 0.217.0(@opentelemetry/api@1.9.0) + '@opentelemetry/sdk-metrics': 2.7.1(@opentelemetry/api@1.9.0) + '@opentelemetry/sdk-trace-base': 2.7.1(@opentelemetry/api@1.9.0) protobufjs: 7.5.8 '@opentelemetry/propagator-b3@1.30.1(@opentelemetry/api@1.9.0)': @@ -17082,21 +17206,39 @@ snapshots: '@opentelemetry/api': 1.9.0 '@opentelemetry/core': 1.30.1(@opentelemetry/api@1.9.0) + '@opentelemetry/propagator-b3@2.7.1(@opentelemetry/api@1.9.0)': + dependencies: + '@opentelemetry/api': 1.9.0 + '@opentelemetry/core': 2.7.1(@opentelemetry/api@1.9.0) + '@opentelemetry/propagator-jaeger@1.30.1(@opentelemetry/api@1.9.0)': dependencies: '@opentelemetry/api': 1.9.0 '@opentelemetry/core': 1.30.1(@opentelemetry/api@1.9.0) + '@opentelemetry/propagator-jaeger@2.7.1(@opentelemetry/api@1.9.0)': + dependencies: + '@opentelemetry/api': 1.9.0 + '@opentelemetry/core': 2.7.1(@opentelemetry/api@1.9.0) + '@opentelemetry/resources@1.30.1(@opentelemetry/api@1.9.0)': dependencies: '@opentelemetry/api': 1.9.0 '@opentelemetry/core': 1.30.1(@opentelemetry/api@1.9.0) '@opentelemetry/semantic-conventions': 1.28.0 - '@opentelemetry/resources@2.2.0(@opentelemetry/api@1.9.0)': + '@opentelemetry/resources@2.7.1(@opentelemetry/api@1.9.0)': dependencies: '@opentelemetry/api': 1.9.0 - '@opentelemetry/core': 2.2.0(@opentelemetry/api@1.9.0) + '@opentelemetry/core': 2.7.1(@opentelemetry/api@1.9.0) + '@opentelemetry/semantic-conventions': 1.38.0 + + '@opentelemetry/sdk-logs@0.217.0(@opentelemetry/api@1.9.0)': + dependencies: + '@opentelemetry/api': 1.9.0 + '@opentelemetry/api-logs': 0.217.0 + '@opentelemetry/core': 2.7.1(@opentelemetry/api@1.9.0) + '@opentelemetry/resources': 2.7.1(@opentelemetry/api@1.9.0) '@opentelemetry/semantic-conventions': 1.38.0 '@opentelemetry/sdk-logs@0.57.2(@opentelemetry/api@1.9.0)': @@ -17112,29 +17254,40 @@ snapshots: '@opentelemetry/core': 1.30.1(@opentelemetry/api@1.9.0) '@opentelemetry/resources': 1.30.1(@opentelemetry/api@1.9.0) - '@opentelemetry/sdk-node@0.57.2(@opentelemetry/api@1.9.0)': + '@opentelemetry/sdk-metrics@2.7.1(@opentelemetry/api@1.9.0)': dependencies: '@opentelemetry/api': 1.9.0 - '@opentelemetry/api-logs': 0.57.2 - '@opentelemetry/core': 1.30.1(@opentelemetry/api@1.9.0) - '@opentelemetry/exporter-logs-otlp-grpc': 0.57.2(@opentelemetry/api@1.9.0) - '@opentelemetry/exporter-logs-otlp-http': 0.57.2(@opentelemetry/api@1.9.0) - '@opentelemetry/exporter-logs-otlp-proto': 0.57.2(@opentelemetry/api@1.9.0) - '@opentelemetry/exporter-metrics-otlp-grpc': 0.57.2(@opentelemetry/api@1.9.0) - '@opentelemetry/exporter-metrics-otlp-http': 0.57.2(@opentelemetry/api@1.9.0) - '@opentelemetry/exporter-metrics-otlp-proto': 0.57.2(@opentelemetry/api@1.9.0) - '@opentelemetry/exporter-prometheus': 0.57.2(@opentelemetry/api@1.9.0) - '@opentelemetry/exporter-trace-otlp-grpc': 0.57.2(@opentelemetry/api@1.9.0) - '@opentelemetry/exporter-trace-otlp-http': 0.57.2(@opentelemetry/api@1.9.0) - '@opentelemetry/exporter-trace-otlp-proto': 0.57.2(@opentelemetry/api@1.9.0) - '@opentelemetry/exporter-zipkin': 1.30.1(@opentelemetry/api@1.9.0) - '@opentelemetry/instrumentation': 0.57.2(@opentelemetry/api@1.9.0) - '@opentelemetry/resources': 1.30.1(@opentelemetry/api@1.9.0) - '@opentelemetry/sdk-logs': 0.57.2(@opentelemetry/api@1.9.0) - '@opentelemetry/sdk-metrics': 1.30.1(@opentelemetry/api@1.9.0) - '@opentelemetry/sdk-trace-base': 1.30.1(@opentelemetry/api@1.9.0) - '@opentelemetry/sdk-trace-node': 1.30.1(@opentelemetry/api@1.9.0) - '@opentelemetry/semantic-conventions': 1.28.0 + '@opentelemetry/core': 2.7.1(@opentelemetry/api@1.9.0) + '@opentelemetry/resources': 2.7.1(@opentelemetry/api@1.9.0) + + '@opentelemetry/sdk-node@0.217.0(@opentelemetry/api@1.9.0)': + dependencies: + '@opentelemetry/api': 1.9.0 + '@opentelemetry/api-logs': 0.217.0 + '@opentelemetry/configuration': 0.217.0(@opentelemetry/api@1.9.0) + '@opentelemetry/context-async-hooks': 2.7.1(@opentelemetry/api@1.9.0) + '@opentelemetry/core': 2.7.1(@opentelemetry/api@1.9.0) + '@opentelemetry/exporter-logs-otlp-grpc': 0.217.0(@opentelemetry/api@1.9.0) + '@opentelemetry/exporter-logs-otlp-http': 0.217.0(@opentelemetry/api@1.9.0) + '@opentelemetry/exporter-logs-otlp-proto': 0.217.0(@opentelemetry/api@1.9.0) + '@opentelemetry/exporter-metrics-otlp-grpc': 0.217.0(@opentelemetry/api@1.9.0) + '@opentelemetry/exporter-metrics-otlp-http': 0.217.0(@opentelemetry/api@1.9.0) + '@opentelemetry/exporter-metrics-otlp-proto': 0.217.0(@opentelemetry/api@1.9.0) + '@opentelemetry/exporter-prometheus': 0.217.0(@opentelemetry/api@1.9.0) + '@opentelemetry/exporter-trace-otlp-grpc': 0.217.0(@opentelemetry/api@1.9.0) + '@opentelemetry/exporter-trace-otlp-http': 0.217.0(@opentelemetry/api@1.9.0) + '@opentelemetry/exporter-trace-otlp-proto': 0.217.0(@opentelemetry/api@1.9.0) + '@opentelemetry/exporter-zipkin': 2.7.1(@opentelemetry/api@1.9.0) + '@opentelemetry/instrumentation': 0.217.0(@opentelemetry/api@1.9.0) + '@opentelemetry/otlp-exporter-base': 0.217.0(@opentelemetry/api@1.9.0) + '@opentelemetry/propagator-b3': 2.7.1(@opentelemetry/api@1.9.0) + '@opentelemetry/propagator-jaeger': 2.7.1(@opentelemetry/api@1.9.0) + '@opentelemetry/resources': 2.7.1(@opentelemetry/api@1.9.0) + '@opentelemetry/sdk-logs': 0.217.0(@opentelemetry/api@1.9.0) + '@opentelemetry/sdk-metrics': 2.7.1(@opentelemetry/api@1.9.0) + '@opentelemetry/sdk-trace-base': 2.7.1(@opentelemetry/api@1.9.0) + '@opentelemetry/sdk-trace-node': 2.7.1(@opentelemetry/api@1.9.0) + '@opentelemetry/semantic-conventions': 1.38.0 transitivePeerDependencies: - supports-color @@ -17145,11 +17298,11 @@ snapshots: '@opentelemetry/resources': 1.30.1(@opentelemetry/api@1.9.0) '@opentelemetry/semantic-conventions': 1.28.0 - '@opentelemetry/sdk-trace-base@2.2.0(@opentelemetry/api@1.9.0)': + '@opentelemetry/sdk-trace-base@2.7.1(@opentelemetry/api@1.9.0)': dependencies: '@opentelemetry/api': 1.9.0 - '@opentelemetry/core': 2.2.0(@opentelemetry/api@1.9.0) - '@opentelemetry/resources': 2.2.0(@opentelemetry/api@1.9.0) + '@opentelemetry/core': 2.7.1(@opentelemetry/api@1.9.0) + '@opentelemetry/resources': 2.7.1(@opentelemetry/api@1.9.0) '@opentelemetry/semantic-conventions': 1.38.0 '@opentelemetry/sdk-trace-node@1.30.1(@opentelemetry/api@1.9.0)': @@ -17162,11 +17315,18 @@ snapshots: '@opentelemetry/sdk-trace-base': 1.30.1(@opentelemetry/api@1.9.0) semver: 7.7.4 - '@opentelemetry/sdk-trace-web@2.2.0(@opentelemetry/api@1.9.0)': + '@opentelemetry/sdk-trace-node@2.7.1(@opentelemetry/api@1.9.0)': dependencies: '@opentelemetry/api': 1.9.0 - '@opentelemetry/core': 2.2.0(@opentelemetry/api@1.9.0) - '@opentelemetry/sdk-trace-base': 2.2.0(@opentelemetry/api@1.9.0) + '@opentelemetry/context-async-hooks': 2.7.1(@opentelemetry/api@1.9.0) + '@opentelemetry/core': 2.7.1(@opentelemetry/api@1.9.0) + '@opentelemetry/sdk-trace-base': 2.7.1(@opentelemetry/api@1.9.0) + + '@opentelemetry/sdk-trace-web@2.7.1(@opentelemetry/api@1.9.0)': + dependencies: + '@opentelemetry/api': 1.9.0 + '@opentelemetry/core': 2.7.1(@opentelemetry/api@1.9.0) + '@opentelemetry/sdk-trace-base': 2.7.1(@opentelemetry/api@1.9.0) '@opentelemetry/semantic-conventions@1.25.1': {} @@ -18589,7 +18749,7 @@ snapshots: dependencies: csstype: 3.2.3 - '@types/readable-stream@4.0.22': + '@types/readable-stream@4.0.23': dependencies: '@types/node': 24.10.1 @@ -18745,7 +18905,7 @@ snapshots: sirv: 3.0.2 tinyrainbow: 3.1.0 vitest: 4.1.2(@opentelemetry/api@1.9.0)(@types/node@22.19.15)(@vitest/browser-playwright@4.1.2)(jsdom@26.1.0)(vite@8.0.5(@emnapi/core@1.7.1)(@emnapi/runtime@1.7.1)(@types/node@22.19.15)(esbuild@0.27.4)(jiti@2.6.1)(less@4.4.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3)) - ws: 8.20.0 + ws: 8.20.1 transitivePeerDependencies: - bufferutil - msw @@ -18763,7 +18923,7 @@ snapshots: sirv: 3.0.2 tinyrainbow: 3.1.0 vitest: 4.1.2(@opentelemetry/api@1.9.0)(@types/node@24.10.1)(@vitest/browser-playwright@4.1.2)(jsdom@26.1.0)(vite@8.0.5(@emnapi/core@1.7.1)(@emnapi/runtime@1.7.1)(@types/node@24.10.1)(esbuild@0.27.4)(jiti@2.6.1)(less@4.4.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3)) - ws: 8.20.0 + ws: 8.20.1 transitivePeerDependencies: - bufferutil - msw @@ -19180,17 +19340,17 @@ snapshots: normalize-path: 3.0.0 picomatch: 4.0.4 - apollo-link-rest@0.9.0(@apollo/client@3.14.0(@types/react@19.2.7)(graphql-ws@6.0.6(graphql@16.12.0)(ws@8.20.0))(graphql@16.12.0)(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(graphql@16.12.0)(qs@6.15.0): + apollo-link-rest@0.9.0(@apollo/client@3.14.0(@types/react@19.2.7)(graphql-ws@6.0.6(graphql@16.12.0)(ws@8.20.1))(graphql@16.12.0)(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(graphql@16.12.0)(qs@6.15.2): dependencies: - '@apollo/client': 3.14.0(@types/react@19.2.7)(graphql-ws@6.0.6(graphql@16.12.0)(ws@8.20.0))(graphql@16.12.0)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@apollo/client': 3.14.0(@types/react@19.2.7)(graphql-ws@6.0.6(graphql@16.12.0)(ws@8.20.1))(graphql@16.12.0)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) graphql: 16.12.0 - qs: 6.15.0 + qs: 6.15.2 applicationinsights@2.9.8: dependencies: '@azure/core-auth': 1.7.2 '@azure/core-rest-pipeline': 1.16.3 - '@azure/opentelemetry-instrumentation-azure-sdk': 1.0.0-beta.9 + '@azure/opentelemetry-instrumentation-azure-sdk': 1.0.0 '@microsoft/applicationinsights-web-snippet': 1.0.1 '@opentelemetry/api': 1.9.0 '@opentelemetry/core': 1.30.1(@opentelemetry/api@1.9.0) @@ -19245,7 +19405,7 @@ snapshots: array-buffer-byte-length: 1.0.2 call-bind: 1.0.8 define-properties: 1.2.1 - es-abstract: 1.24.0 + es-abstract: 1.24.2 es-errors: 1.3.0 get-intrinsic: 1.3.0 is-array-buffer: 3.0.5 @@ -19327,7 +19487,7 @@ snapshots: transitivePeerDependencies: - debug - azurite@3.35.0: + azurite@3.35.0(@azure/core-client@1.10.1)(@types/node@24.10.1): dependencies: '@azure/ms-rest-js': 1.11.2 applicationinsights: 2.9.8 @@ -19337,22 +19497,24 @@ snapshots: express: 4.22.1 fs-extra: 11.3.2 glob-to-regexp: 0.4.1 - jsonwebtoken: 9.0.2 + jsonwebtoken: 9.0.3 lokijs: 1.5.12 morgan: 1.10.1 multistream: 2.1.1 - mysql2: 3.15.3 + mysql2: 3.22.3(@types/node@24.10.1) rimraf: 3.0.2 - sequelize: 6.37.7(mysql2@3.15.3)(tedious@16.7.1) + sequelize: 6.37.8(mysql2@3.22.3(@types/node@24.10.1))(tedious@16.7.1(@azure/core-client@1.10.1)) stoppable: 1.1.0 - tedious: 16.7.1 + tedious: 16.7.1(@azure/core-client@1.10.1) to-readable-stream: 2.1.0 tslib: 2.8.1 uri-templates: 0.2.0 - uuid: 14.0.0 - winston: 3.18.3 + uuid: 3.4.0 + winston: 3.19.0 xml2js: 0.6.2 transitivePeerDependencies: + - '@azure/core-client' + - '@types/node' - applicationinsights-native-metrics - debug - ibm_db @@ -19433,9 +19595,9 @@ snapshots: inherits: 2.0.4 readable-stream: 3.6.2 - bl@6.1.5: + bl@6.1.6: dependencies: - '@types/readable-stream': 4.0.22 + '@types/readable-stream': 4.0.23 buffer: 6.0.3 inherits: 2.0.4 readable-stream: 4.7.0 @@ -19450,13 +19612,30 @@ snapshots: http-errors: 2.0.0 iconv-lite: 0.4.24 on-finished: 2.4.1 - qs: 6.15.0 + qs: 6.15.2 raw-body: 2.5.2 type-is: 1.6.18 unpipe: 1.0.0 transitivePeerDependencies: - supports-color + body-parser@1.20.5: + dependencies: + bytes: 3.1.2 + content-type: 1.0.5 + debug: 2.6.9 + depd: 2.0.0 + destroy: 1.2.0 + http-errors: 2.0.1 + iconv-lite: 0.4.24 + on-finished: 2.4.1 + qs: 6.15.2 + raw-body: 2.5.3 + type-is: 1.6.18 + unpipe: 1.0.0 + transitivePeerDependencies: + - supports-color + body-parser@2.2.2: dependencies: bytes: 3.1.2 @@ -19465,7 +19644,7 @@ snapshots: http-errors: 2.0.1 iconv-lite: 0.7.0 on-finished: 2.4.1 - qs: 6.15.0 + qs: 6.15.2 raw-body: 3.0.2 type-is: 2.0.1 transitivePeerDependencies: @@ -19511,7 +19690,7 @@ snapshots: dependencies: balanced-match: 1.0.2 - brace-expansion@5.0.5: + brace-expansion@5.0.6: dependencies: balanced-match: 4.0.4 @@ -19611,6 +19790,13 @@ snapshots: get-intrinsic: 1.3.0 set-function-length: 1.2.2 + call-bind@1.0.9: + dependencies: + call-bind-apply-helpers: 1.0.2 + es-define-property: 1.0.1 + get-intrinsic: 1.3.0 + set-function-length: 1.2.2 + call-bound@1.0.4: dependencies: call-bind-apply-helpers: 1.0.2 @@ -19756,6 +19942,8 @@ snapshots: cjs-module-lexer@1.4.3: {} + cjs-module-lexer@2.2.0: {} + class-transformer@0.5.1: {} classnames@2.5.1: {} @@ -20363,7 +20551,7 @@ snapshots: dotenv@16.6.1: {} - dottie@2.0.6: {} + dottie@2.0.7: {} dset@3.1.4: {} @@ -20433,7 +20621,7 @@ snapshots: dependencies: stackframe: 1.3.4 - es-abstract@1.24.0: + es-abstract@1.24.2: dependencies: array-buffer-byte-length: 1.0.2 arraybuffer.prototype.slice: 1.0.4 @@ -20475,7 +20663,7 @@ snapshots: object.assign: 4.1.7 own-keys: 1.0.1 regexp.prototype.flags: 1.5.4 - safe-array-concat: 1.1.3 + safe-array-concat: 1.1.4 safe-push-apply: 1.0.0 safe-regex-test: 1.1.0 set-proto: 1.0.0 @@ -20494,7 +20682,7 @@ snapshots: dependencies: define-data-property: 1.1.4 define-properties: 1.2.1 - es-abstract: 1.24.0 + es-abstract: 1.24.2 es-errors: 1.3.0 function-bind: 1.1.2 globalthis: 1.0.4 @@ -20712,9 +20900,9 @@ snapshots: expect-type@1.3.0: {} - express-rate-limit@8.5.1(express@4.22.1): + express-rate-limit@8.5.1(express@4.22.2): dependencies: - express: 4.22.1 + express: 4.22.2 ip-address: 10.2.0 express@4.22.1: @@ -20740,7 +20928,43 @@ snapshots: parseurl: 1.3.3 path-to-regexp: 0.1.13 proxy-addr: 2.0.7 - qs: 6.15.0 + qs: 6.15.2 + range-parser: 1.2.1 + safe-buffer: 5.2.1 + send: 0.19.0 + serve-static: 1.16.2 + setprototypeof: 1.2.0 + statuses: 2.0.2 + type-is: 1.6.18 + utils-merge: 1.0.1 + vary: 1.1.2 + transitivePeerDependencies: + - supports-color + + express@4.22.2: + dependencies: + accepts: 1.3.8 + array-flatten: 1.1.1 + body-parser: 1.20.5 + content-disposition: 0.5.4 + content-type: 1.0.5 + cookie: 0.7.2 + cookie-signature: 1.0.6 + debug: 2.6.9 + depd: 2.0.0 + encodeurl: 2.0.0 + escape-html: 1.0.3 + etag: 1.8.1 + finalhandler: 1.3.1 + fresh: 0.5.2 + http-errors: 2.0.1 + merge-descriptors: 1.0.3 + methods: 1.1.2 + on-finished: 2.4.1 + parseurl: 1.3.3 + path-to-regexp: 0.1.13 + proxy-addr: 2.0.7 + qs: 6.15.2 range-parser: 1.2.1 safe-buffer: 5.2.1 send: 0.19.0 @@ -21205,11 +21429,11 @@ snapshots: graphql: 16.12.0 tslib: 2.8.1 - graphql-ws@6.0.6(graphql@16.12.0)(ws@8.20.0): + graphql-ws@6.0.6(graphql@16.12.0)(ws@8.20.1): dependencies: graphql: 16.12.0 optionalDependencies: - ws: 8.20.0 + ws: 8.20.1 graphql@14.7.0: dependencies: @@ -21527,6 +21751,10 @@ snapshots: dependencies: safer-buffer: 2.1.2 + iconv-lite@0.7.2: + dependencies: + safer-buffer: 2.1.2 + icss-utils@5.1.0(postcss@8.5.10): dependencies: postcss: 8.5.10 @@ -21560,6 +21788,20 @@ snapshots: cjs-module-lexer: 1.4.3 module-details-from-path: 1.0.4 + import-in-the-middle@2.0.6: + dependencies: + acorn: 8.16.0 + acorn-import-attributes: 1.9.5(acorn@8.16.0) + cjs-module-lexer: 2.2.0 + module-details-from-path: 1.0.4 + + import-in-the-middle@3.0.1: + dependencies: + acorn: 8.16.0 + acorn-import-attributes: 1.9.5(acorn@8.16.0) + cjs-module-lexer: 2.2.0 + module-details-from-path: 1.0.4 + import-lazy@4.0.0: {} imurmurhash@0.1.4: {} @@ -21850,9 +22092,9 @@ snapshots: isobject@3.0.1: {} - isomorphic-ws@5.0.0(ws@8.20.0): + isomorphic-ws@5.0.0(ws@8.20.1): dependencies: - ws: 8.20.0 + ws: 8.20.1 istanbul-lib-coverage@3.2.2: {} @@ -21948,7 +22190,7 @@ snapshots: whatwg-encoding: 3.1.1 whatwg-mimetype: 4.0.0 whatwg-url: 14.2.0 - ws: 8.20.0 + ws: 8.20.1 xml-name-validator: 5.0.0 transitivePeerDependencies: - bufferutil @@ -21991,9 +22233,9 @@ snapshots: optionalDependencies: graceful-fs: 4.2.11 - jsonwebtoken@9.0.2: + jsonwebtoken@9.0.3: dependencies: - jws: 3.2.2 + jws: 4.0.1 lodash.includes: 4.3.0 lodash.isboolean: 3.0.3 lodash.isinteger: 4.0.4 @@ -22004,24 +22246,13 @@ snapshots: ms: 2.1.3 semver: 7.7.4 - jwa@1.4.2: - dependencies: - buffer-equal-constant-time: 1.0.1 - ecdsa-sig-formatter: 1.0.11 - safe-buffer: 5.2.1 - jwa@2.0.1: dependencies: buffer-equal-constant-time: 1.0.1 ecdsa-sig-formatter: 1.0.11 safe-buffer: 5.2.1 - jws@3.2.2: - dependencies: - jwa: 1.4.2 - safe-buffer: 5.2.1 - - jws@4.0.0: + jws@4.0.1: dependencies: jwa: 2.0.1 safe-buffer: 5.2.1 @@ -22266,17 +22497,13 @@ snapshots: lru-cache@10.4.3: {} - lru-cache@11.3.3: {} - lru-cache@11.3.5: {} lru-cache@5.1.1: dependencies: yallist: 3.1.1 - lru-cache@7.18.3: {} - - lru.min@1.1.3: {} + lru.min@1.1.4: {} luxon@3.7.2: {} @@ -22883,7 +23110,7 @@ snapshots: minimatch@10.2.4: dependencies: - brace-expansion: 5.0.5 + brace-expansion: 5.0.6 minimatch@3.1.5: dependencies: @@ -23023,17 +23250,17 @@ snapshots: mute-stream@0.0.8: {} - mysql2@3.15.3: + mysql2@3.22.3(@types/node@24.10.1): dependencies: + '@types/node': 24.10.1 aws-ssl-profiles: 1.1.2 denque: 2.1.0 generate-function: 2.3.1 - iconv-lite: 0.7.0 + iconv-lite: 0.7.2 long: 5.3.2 - lru.min: 1.1.3 - named-placeholders: 1.1.3 - seq-queue: 0.0.5 - sqlstring: 2.3.3 + lru.min: 1.1.4 + named-placeholders: 1.1.6 + sql-escaper: 1.3.3 mz@2.7.0: dependencies: @@ -23041,9 +23268,9 @@ snapshots: object-assign: 4.1.1 thenify-all: 1.6.0 - named-placeholders@1.1.3: + named-placeholders@1.1.6: dependencies: - lru-cache: 7.18.3 + lru.min: 1.1.4 nanoid@3.3.11: {} @@ -23466,7 +23693,7 @@ snapshots: pend@1.2.0: {} - pg-connection-string@2.9.1: {} + pg-connection-string@2.13.0: {} picocolors@1.1.1: {} @@ -24080,7 +24307,7 @@ snapshots: pvutils@1.1.5: {} - qs@6.15.0: + qs@6.15.2: dependencies: side-channel: 1.1.0 @@ -24099,6 +24326,13 @@ snapshots: iconv-lite: 0.4.24 unpipe: 1.0.0 + raw-body@2.5.3: + dependencies: + bytes: 3.1.2 + http-errors: 2.0.1 + iconv-lite: 0.4.24 + unpipe: 1.0.0 + raw-body@3.0.2: dependencies: bytes: 3.1.2 @@ -24321,7 +24555,7 @@ snapshots: dependencies: call-bind: 1.0.8 define-properties: 1.2.1 - es-abstract: 1.24.0 + es-abstract: 1.24.2 es-errors: 1.3.0 es-object-atoms: 1.1.1 get-intrinsic: 1.3.0 @@ -24498,6 +24732,13 @@ snapshots: transitivePeerDependencies: - supports-color + require-in-the-middle@8.0.1: + dependencies: + debug: 4.4.3(supports-color@8.1.1) + module-details-from-path: 1.0.4 + transitivePeerDependencies: + - supports-color + require-like@0.1.2: {} requires-port@1.0.0: {} @@ -24636,9 +24877,9 @@ snapshots: dependencies: tslib: 2.8.1 - safe-array-concat@1.1.3: + safe-array-concat@1.1.4: dependencies: - call-bind: 1.0.8 + call-bind: 1.0.9 call-bound: 1.0.4 get-intrinsic: 1.3.0 has-symbols: 1.1.0 @@ -24750,31 +24991,29 @@ snapshots: tslib: 2.8.1 upper-case-first: 2.0.2 - seq-queue@0.0.5: {} - sequelize-pool@7.1.0: {} - sequelize@6.37.7(mysql2@3.15.3)(tedious@16.7.1): + sequelize@6.37.8(mysql2@3.22.3(@types/node@24.10.1))(tedious@16.7.1(@azure/core-client@1.10.1)): dependencies: '@types/debug': 4.1.12 '@types/validator': 13.15.10 debug: 4.4.3(supports-color@8.1.1) - dottie: 2.0.6 + dottie: 2.0.7 inflection: 1.13.4 lodash: 4.18.1 moment: 2.30.1 moment-timezone: 0.5.48 - pg-connection-string: 2.9.1 + pg-connection-string: 2.13.0 retry-as-promised: 7.1.1 semver: 7.7.4 sequelize-pool: 7.1.0 toposort-class: 1.0.1 - uuid: 14.0.0 - validator: 13.15.23 + uuid: 8.3.2 + validator: 13.15.35 wkx: 0.5.0 optionalDependencies: - mysql2: 3.15.3 - tedious: 16.7.1 + mysql2: 3.22.3(@types/node@24.10.1) + tedious: 16.7.1(@azure/core-client@1.10.1) transitivePeerDependencies: - supports-color @@ -24965,7 +25204,7 @@ snapshots: sockjs@0.3.24: dependencies: faye-websocket: 0.11.4 - uuid: 14.0.0 + uuid: 8.3.2 websocket-driver: 0.7.4 sort-css-media-queries@2.2.0: {} @@ -25034,7 +25273,7 @@ snapshots: sprintf-js@1.1.3: {} - sqlstring@2.3.3: {} + sql-escaper@1.3.3: {} srcset@4.0.0: {} @@ -25067,9 +25306,9 @@ snapshots: stoppable@1.1.0: {} - storybook-addon-apollo-client@9.0.0(@apollo/client@3.14.0(@types/react@19.2.7)(graphql-ws@6.0.6(graphql@16.12.0)(ws@8.20.0))(graphql@16.12.0)(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(graphql@16.12.0)(react@19.2.0): + storybook-addon-apollo-client@9.0.0(@apollo/client@3.14.0(@types/react@19.2.7)(graphql-ws@6.0.6(graphql@16.12.0)(ws@8.20.1))(graphql@16.12.0)(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(graphql@16.12.0)(react@19.2.0): dependencies: - '@apollo/client': 3.14.0(@types/react@19.2.7)(graphql-ws@6.0.6(graphql@16.12.0)(ws@8.20.0))(graphql@16.12.0)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@apollo/client': 3.14.0(@types/react@19.2.7)(graphql-ws@6.0.6(graphql@16.12.0)(ws@8.20.1))(graphql@16.12.0)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) graphql: 16.12.0 react: 19.2.0 @@ -25086,7 +25325,7 @@ snapshots: esbuild-register: 3.6.0(esbuild@0.25.12) recast: 0.23.11 semver: 7.7.4 - ws: 8.20.0 + ws: 8.20.1 transitivePeerDependencies: - '@testing-library/dom' - bufferutil @@ -25133,7 +25372,7 @@ snapshots: call-bound: 1.0.4 define-data-property: 1.1.4 define-properties: 1.2.1 - es-abstract: 1.24.0 + es-abstract: 1.24.2 es-object-atoms: 1.1.1 has-property-descriptors: 1.0.2 @@ -25312,12 +25551,12 @@ snapshots: - bare-abort-controller - react-native-b4a - tedious@16.7.1: + tedious@16.7.1(@azure/core-client@1.10.1): dependencies: '@azure/identity': 3.4.2 - '@azure/keyvault-keys': 4.10.0 - '@js-joda/core': 5.6.5 - bl: 6.1.5 + '@azure/keyvault-keys': 4.10.0(@azure/core-client@1.10.1) + '@js-joda/core': 5.7.0 + bl: 6.1.6 es-aggregate-error: 1.0.14 iconv-lite: 0.6.3 js-md4: 0.3.2 @@ -25326,6 +25565,7 @@ snapshots: node-abort-controller: 3.1.1 sprintf-js: 1.1.3 transitivePeerDependencies: + - '@azure/core-client' - supports-color terser-webpack-plugin@5.3.14(esbuild@0.27.4)(webpack@5.105.4(esbuild@0.27.4)): @@ -25763,7 +26003,15 @@ snapshots: utils-merge@1.0.1: {} - uuid@14.0.0: {} + uuid@10.0.0: {} + + uuid@11.0.5: {} + + uuid@11.1.1: {} + + uuid@3.4.0: {} + + uuid@8.3.2: {} v8-to-istanbul@9.3.0: dependencies: @@ -25778,7 +26026,7 @@ snapshots: validate-npm-package-name@7.0.2: {} - validator@13.15.23: {} + validator@13.15.35: {} value-equal@1.0.1: {} @@ -25990,7 +26238,7 @@ snapshots: sockjs: 0.3.24 spdy: 4.0.2 webpack-dev-middleware: 7.4.5(webpack@5.105.4(esbuild@0.27.4)) - ws: 8.20.0 + ws: 8.20.1 optionalDependencies: webpack: 5.105.4(esbuild@0.27.4) transitivePeerDependencies: @@ -26153,7 +26401,7 @@ snapshots: readable-stream: 3.6.2 triple-beam: 1.4.1 - winston@3.18.3: + winston@3.19.0: dependencies: '@colors/colors': 1.6.0 '@dabh/diagnostics': 2.0.8 @@ -26200,7 +26448,7 @@ snapshots: ws@7.5.10: {} - ws@8.20.0: {} + ws@8.20.1: {} wsl-utils@0.1.0: dependencies: @@ -26210,18 +26458,18 @@ snapshots: xml-js@1.6.11: dependencies: - sax: 1.4.3 + sax: 1.5.0 xml-name-validator@5.0.0: {} xml2js@0.4.23: dependencies: - sax: 1.4.3 + sax: 1.5.0 xmlbuilder: 11.0.1 xml2js@0.6.2: dependencies: - sax: 1.4.3 + sax: 1.5.0 xmlbuilder: 11.0.1 xmlbuilder@11.0.1: {} diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index ac9ea4615..63e1e511e 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -65,7 +65,8 @@ overrides: rollup: ^4.59.0 '@ant-design/pro-layout>path-to-regexp': ^8.4.0 'brace-expansion@1.1.12': 1.1.13 - 'brace-expansion@5.0.4': 5.0.5 + 'brace-expansion@5.0.4': 5.0.6 + 'brace-expansion@5.0.5': 5.0.6 'diff@4.0.2': 4.0.4 '@protobufjs/codegen': 2.0.5 '@protobufjs/utf8': 1.1.1 @@ -76,7 +77,7 @@ overrides: svgo: ^3.3.3 'yaml@2.8.2': 2.8.3 'yauzl@3.2.0': 3.2.1 - qs: ^6.14.2 + qs: 6.15.2 'ajv@^6': 6.14.0 lodash: 4.18.1 lodash-es: 4.18.1 @@ -86,7 +87,9 @@ overrides: webpack: ^5.105.4 webpack-dev-server: ^5.2.4 express-rate-limit: 8.5.1 - uuid: 14.0.0 + '@azure/ms-rest-js>uuid': '^3.4.0' + 'azurite>uuid': '^3.4.0' + 'ws@8.20.0': 8.20.1 playwright-core: 1.59.0 playwright: 1.59.0 postcss: 8.5.10 diff --git a/turbo.json b/turbo.json index 0ef199ae0..8bef61034 100644 --- a/turbo.json +++ b/turbo.json @@ -1,6 +1,7 @@ { "$schema": "https://turbo.build/schema.json", "ui": "tui", + "globalPassThroughEnv": ["WORKTREE_NAME"], "futureFlags": { "affectedUsingTaskInputs": true, "watchUsingTaskInputs": true @@ -101,6 +102,12 @@ "cache": false, "persistent": true }, + "dev:portless": { + "description": "Starts dev servers with worktree-scoped portless hostnames for git worktree isolation", + "dependsOn": ["^build"], + "cache": false, + "persistent": true + }, "azurite": { "description": "Starts the Azurite storage emulator", "cache": false, From b4db123ea16af23cb539ea8de5ce0db682489477 Mon Sep 17 00:00:00 2001 From: Jason Morais Date: Thu, 21 May 2026 10:27:20 -0400 Subject: [PATCH 3/3] fixes for e2e tests along with overall pattern cleanup --- apps/api/package.json | 4 +- apps/api/start-dev.mjs | 16 +- apps/api/turbo.json | 2 +- apps/docs/package.json | 2 +- apps/docs/turbo.json | 2 +- apps/server-mongodb-memory-mock/package.json | 2 +- apps/server-mongodb-memory-mock/turbo.json | 2 +- apps/server-oauth2-mock/package.json | 2 +- apps/server-oauth2-mock/start-dev.mjs | 18 +- apps/server-oauth2-mock/turbo.json | 2 +- apps/ui-community/package.json | 2 +- apps/ui-community/start-dev.mjs | 19 +- apps/ui-community/turbo.json | 2 +- apps/ui-staff/package.json | 2 +- apps/ui-staff/start-dev.mjs | 16 +- .../scripts/portless-hostnames.d.mts | 13 + build-pipeline/scripts/worktree-ports.d.mts | 5 + package.json | 4 +- .../ocom-verification/e2e-tests/cucumber.js | 2 + .../ocom-verification/e2e-tests/package.json | 4 +- .../src/shared/support/oauth2-login.ts | 6 +- .../shared/support/servers/e2e-defaults.ts | 65 +++++ .../src/shared/support/servers/index.ts | 2 +- .../shared/support/servers/portless-server.ts | 13 +- .../shared/support/servers/test-api-server.ts | 53 ++-- .../support/servers/test-azurite-server.ts | 105 +++++++ .../support/servers/test-environment.ts | 19 +- .../shared/support/shared-infrastructure.ts | 20 +- .../verification-shared/src/servers/index.ts | 2 +- .../src/servers/test-mongodb-server.ts | 3 +- .../src/servers/test-server.interface.ts | 26 +- .../src/settings/local-settings.ts | 31 +-- .../src/settings/portless-settings.ts | 68 +---- pnpm-lock.yaml | 258 ++++++++++++++++-- readme.md | 2 - turbo.json | 2 +- 36 files changed, 566 insertions(+), 230 deletions(-) create mode 100644 build-pipeline/scripts/portless-hostnames.d.mts create mode 100644 build-pipeline/scripts/worktree-ports.d.mts create mode 100644 packages/ocom-verification/e2e-tests/src/shared/support/servers/e2e-defaults.ts create mode 100644 packages/ocom-verification/e2e-tests/src/shared/support/servers/test-azurite-server.ts diff --git a/apps/api/package.json b/apps/api/package.json index 6041983b2..122cb1ca1 100644 --- a/apps/api/package.json +++ b/apps/api/package.json @@ -10,8 +10,8 @@ "build": "tsgo --build && rolldown -c rolldown.config.ts", "predev": "pnpm run prepare:deploy && pnpm run sync-local-settings", "dev": "pnpm exec portless data-access.ownercommunity.localhost --force node start-dev.mjs", - "predev:portless": "pnpm run prepare:deploy && pnpm run sync-local-settings", - "dev:portless": "pnpm exec portless data-access.ownercommunity.${WORKTREE_NAME}.localhost --force node start-dev.mjs", + "predev:worktree": "pnpm run prepare:deploy && pnpm run sync-local-settings", + "dev:worktree": "pnpm exec portless data-access.ownercommunity.${WORKTREE_NAME}.localhost --force node start-dev.mjs", "prepare:deploy": "cellix-prepare-func-deploy", "watch": "tsgo --watch", "test": "vitest run --silent --reporter=dot", diff --git a/apps/api/start-dev.mjs b/apps/api/start-dev.mjs index 978b8744b..9dc871786 100644 --- a/apps/api/start-dev.mjs +++ b/apps/api/start-dev.mjs @@ -22,15 +22,19 @@ const childEnv = { // Only inject worktree-scoped overrides when running in worktree mode. // When WORKTREE_NAME is absent, local.settings.json remains the source of truth. +// Use `??=` so callers (e.g. e2e harness with a MongoMemoryServer port) can override +// any individual value via process.env before invoking this script. if (process.env.WORKTREE_NAME) { const hostnames = getHostnames(); - childEnv.ACCOUNT_PORTAL_OIDC_ISSUER = buildPortlessUrl(hostnames.mockAuth, '/community'); - childEnv.ACCOUNT_PORTAL_OIDC_ENDPOINT = buildPortlessUrl(hostnames.mockAuth, '/community/.well-known/jwks.json'); - childEnv.COSMOSDB_CONNECTION_STRING = getMongoConnectionString(); - childEnv.AZURE_STORAGE_CONNECTION_STRING = getAzuriteConnectionString(); - childEnv.AzureWebJobsStorage = getAzuriteConnectionString(); + childEnv.ACCOUNT_PORTAL_OIDC_ISSUER ??= buildPortlessUrl(hostnames.mockAuth, '/community'); + childEnv.ACCOUNT_PORTAL_OIDC_ENDPOINT ??= buildPortlessUrl(hostnames.mockAuth, '/community/.well-known/jwks.json'); + childEnv.STAFF_PORTAL_OIDC_ISSUER ??= buildPortlessUrl(hostnames.mockAuth, '/staff'); + childEnv.STAFF_PORTAL_OIDC_ENDPOINT ??= buildPortlessUrl(hostnames.mockAuth, '/staff/.well-known/jwks.json'); + childEnv.COSMOSDB_CONNECTION_STRING ??= getMongoConnectionString(); + childEnv.AZURE_STORAGE_CONNECTION_STRING ??= getAzuriteConnectionString(); + childEnv.AzureWebJobsStorage ??= getAzuriteConnectionString(); // Disable the Node.js inspector — port 5858 is already used by the primary worktree. - childEnv.languageWorkers__node__arguments = ''; + childEnv.languageWorkers__node__arguments ??= ''; } const child = spawn('func', ['start', '--typescript', '--script-root', 'deploy/', '--port', envPort, '--cors', '*'], { diff --git a/apps/api/turbo.json b/apps/api/turbo.json index 0f908f3c8..6487a447c 100644 --- a/apps/api/turbo.json +++ b/apps/api/turbo.json @@ -12,7 +12,7 @@ "interruptible": true, "inputs": [] }, - "dev:portless": { + "dev:worktree": { "dependsOn": ["build"], "interruptible": true, "inputs": [] diff --git a/apps/docs/package.json b/apps/docs/package.json index 10766a652..9e8348ac1 100644 --- a/apps/docs/package.json +++ b/apps/docs/package.json @@ -5,7 +5,7 @@ "scripts": { "docusaurus": "docusaurus", "dev": "pnpm exec portless docs.ownercommunity.localhost --force node start-dev.mjs", - "dev:portless": "pnpm exec portless docs.ownercommunity.${WORKTREE_NAME}.localhost --force node start-dev.mjs", + "dev:worktree": "pnpm exec portless docs.ownercommunity.${WORKTREE_NAME}.localhost --force node start-dev.mjs", "start": "docusaurus start --port 3001", "build": "docusaurus build", "swizzle": "docusaurus swizzle", diff --git a/apps/docs/turbo.json b/apps/docs/turbo.json index d39e3fdc8..304f1bb57 100644 --- a/apps/docs/turbo.json +++ b/apps/docs/turbo.json @@ -7,7 +7,7 @@ "interruptible": false, "inputs": [".env", "package.json", "start-dev.mjs", "docusaurus.config.ts", "sidebars.ts", "tsconfig.json"] }, - "dev:portless": { + "dev:worktree": { "dependsOn": [], "persistent": true, "interruptible": false, diff --git a/apps/server-mongodb-memory-mock/package.json b/apps/server-mongodb-memory-mock/package.json index 2372d4635..ed4a774d3 100644 --- a/apps/server-mongodb-memory-mock/package.json +++ b/apps/server-mongodb-memory-mock/package.json @@ -12,7 +12,7 @@ "format:check": "biome format .", "start": "node dist/index.js", "dev": "tsx src/index.ts", - "dev:portless": "node start-mongo.mjs" + "dev:worktree": "node start-mongo.mjs" }, "dependencies": { "@cellix/server-mongodb-memory-mock-seedwork": "workspace:*", diff --git a/apps/server-mongodb-memory-mock/turbo.json b/apps/server-mongodb-memory-mock/turbo.json index b0f2f18a9..5aea8cad2 100644 --- a/apps/server-mongodb-memory-mock/turbo.json +++ b/apps/server-mongodb-memory-mock/turbo.json @@ -8,7 +8,7 @@ "interruptible": true, "inputs": [] }, - "dev:portless": { + "dev:worktree": { "dependsOn": ["build"], "persistent": true, "interruptible": true, diff --git a/apps/server-oauth2-mock/package.json b/apps/server-oauth2-mock/package.json index bc92782ff..7201d84b9 100644 --- a/apps/server-oauth2-mock/package.json +++ b/apps/server-oauth2-mock/package.json @@ -12,7 +12,7 @@ "format:check": "biome format .", "start": "node dist/index.js", "dev": "pnpm exec portless mock-auth.ownercommunity.localhost --force tsx src/index.ts", - "dev:portless": "pnpm exec portless mock-auth.ownercommunity.${WORKTREE_NAME}.localhost --force node start-dev.mjs", + "dev:worktree": "pnpm exec portless mock-auth.ownercommunity.${WORKTREE_NAME}.localhost --force node start-dev.mjs", "test": "vitest run", "test:coverage": "vitest run --coverage", "test:watch": "vitest" diff --git a/apps/server-oauth2-mock/start-dev.mjs b/apps/server-oauth2-mock/start-dev.mjs index b6434763a..2bd4f4b1e 100644 --- a/apps/server-oauth2-mock/start-dev.mjs +++ b/apps/server-oauth2-mock/start-dev.mjs @@ -2,17 +2,19 @@ import { spawn } from 'node:child_process'; import { isGracefulInterruptExit } from '../../build-pipeline/scripts/dev-process-exit.mjs'; import { buildPortlessUrl, getHostnames } from '../../build-pipeline/scripts/portless-hostnames.mjs'; -const hostnames = getHostnames(); +const childEnv = { ...process.env }; + +if (process.env.WORKTREE_NAME) { + const hostnames = getHostnames(); + childEnv.BASE_URL = buildPortlessUrl(hostnames.mockAuth); + // Override redirect URIs so portal-discovery picks up worktree-scoped URLs. + childEnv.VITE_APP_UI_COMMUNITY_B2C_REDIRECT_URI = buildPortlessUrl(hostnames.uiCommunity, '/auth-redirect'); + childEnv.VITE_APP_UI_STAFF_AAD_REDIRECT_URI = buildPortlessUrl(hostnames.uiStaff, '/auth-redirect'); +} const child = spawn('tsx', ['src/index.ts'], { stdio: 'inherit', - env: { - ...process.env, - BASE_URL: buildPortlessUrl(hostnames.mockAuth), - // Override redirect URIs so portal-discovery picks up worktree-scoped URLs - VITE_APP_UI_COMMUNITY_B2C_REDIRECT_URI: buildPortlessUrl(hostnames.uiCommunity, '/auth-redirect'), - VITE_APP_UI_STAFF_AAD_REDIRECT_URI: buildPortlessUrl(hostnames.uiStaff, '/auth-redirect'), - }, + env: childEnv, }); child.on('exit', (code, signal) => { diff --git a/apps/server-oauth2-mock/turbo.json b/apps/server-oauth2-mock/turbo.json index 325758390..2596ed01a 100644 --- a/apps/server-oauth2-mock/turbo.json +++ b/apps/server-oauth2-mock/turbo.json @@ -10,7 +10,7 @@ "persistent": true, "inputs": ["$TURBO_DEFAULT$", "../**/mock-oidc*.json"] }, - "dev:portless": { + "dev:worktree": { "dependsOn": ["build"], "interruptible": true, "persistent": true, diff --git a/apps/ui-community/package.json b/apps/ui-community/package.json index 86bc14f1d..ac0f7010d 100644 --- a/apps/ui-community/package.json +++ b/apps/ui-community/package.json @@ -10,7 +10,7 @@ "prebuild": "pnpm run lint", "build": "tsgo --build && vite build", "dev": "pnpm exec portless ownercommunity.localhost --force vite", - "dev:portless": "pnpm exec portless ownercommunity.${WORKTREE_NAME}.localhost --force node start-dev.mjs", + "dev:worktree": "pnpm exec portless ownercommunity.${WORKTREE_NAME}.localhost --force node start-dev.mjs", "start": "vite", "preview": "vite preview", "test": "vitest run --silent --reporter=dot", diff --git a/apps/ui-community/start-dev.mjs b/apps/ui-community/start-dev.mjs index a13661535..5226fb736 100644 --- a/apps/ui-community/start-dev.mjs +++ b/apps/ui-community/start-dev.mjs @@ -2,17 +2,20 @@ import { spawn } from 'node:child_process'; import { isGracefulInterruptExit } from '../../build-pipeline/scripts/dev-process-exit.mjs'; import { buildPortlessUrl, getHostnames } from '../../build-pipeline/scripts/portless-hostnames.mjs'; -const hostnames = getHostnames(); +const childEnv = { ...process.env }; + +// Worktree-scoped overrides; plain `dev` leaves .env as the source of truth. +if (process.env.WORKTREE_NAME) { + const hostnames = getHostnames(); + childEnv.VITE_APP_UI_COMMUNITY_B2C_AUTHORITY = buildPortlessUrl(hostnames.mockAuth, '/community'); + childEnv.VITE_APP_UI_COMMUNITY_B2C_REDIRECT_URI = buildPortlessUrl(hostnames.uiCommunity, '/auth-redirect'); + childEnv.VITE_COMMON_API_ENDPOINT = buildPortlessUrl(hostnames.api, '/api/graphql'); + childEnv.VITE_APP_UI_COMMUNITY_BASE_URL = buildPortlessUrl(hostnames.uiCommunity); +} const child = spawn('vite', ['--port', process.env.PORT, '--host', process.env.HOST ?? '127.0.0.1'], { stdio: 'inherit', - env: { - ...process.env, - VITE_APP_UI_COMMUNITY_B2C_AUTHORITY: buildPortlessUrl(hostnames.mockAuth, '/community'), - VITE_APP_UI_COMMUNITY_B2C_REDIRECT_URI: buildPortlessUrl(hostnames.uiCommunity, '/auth-redirect'), - VITE_COMMON_API_ENDPOINT: buildPortlessUrl(hostnames.api, '/api/graphql'), - VITE_APP_UI_COMMUNITY_BASE_URL: buildPortlessUrl(hostnames.uiCommunity), - }, + env: childEnv, }); child.on('exit', (code, signal) => { diff --git a/apps/ui-community/turbo.json b/apps/ui-community/turbo.json index e253b58b7..b7c32402e 100644 --- a/apps/ui-community/turbo.json +++ b/apps/ui-community/turbo.json @@ -7,7 +7,7 @@ "interruptible": false, "inputs": [".env", "package.json", "vite.config.ts", "tsconfig.json", "tsconfig.app.json", "tsconfig.node.json"] }, - "dev:portless": { + "dev:worktree": { "dependsOn": ["^build"], "persistent": true, "interruptible": false, diff --git a/apps/ui-staff/package.json b/apps/ui-staff/package.json index bd35eaf13..9b8757b90 100644 --- a/apps/ui-staff/package.json +++ b/apps/ui-staff/package.json @@ -10,7 +10,7 @@ "prebuild": "pnpm run lint", "build": "tsgo --build && vite build", "dev": "pnpm exec portless staff.ownercommunity.localhost --force vite", - "dev:portless": "pnpm exec portless staff.ownercommunity.${WORKTREE_NAME}.localhost --force node start-dev.mjs", + "dev:worktree": "pnpm exec portless staff.ownercommunity.${WORKTREE_NAME}.localhost --force node start-dev.mjs", "start": "vite", "preview": "vite preview", "test": "vitest run --silent --reporter=dot", diff --git a/apps/ui-staff/start-dev.mjs b/apps/ui-staff/start-dev.mjs index 4b656ce70..eaa17cdb8 100644 --- a/apps/ui-staff/start-dev.mjs +++ b/apps/ui-staff/start-dev.mjs @@ -2,16 +2,18 @@ import { spawn } from 'node:child_process'; import { isGracefulInterruptExit } from '../../build-pipeline/scripts/dev-process-exit.mjs'; import { buildPortlessUrl, getHostnames } from '../../build-pipeline/scripts/portless-hostnames.mjs'; -const hostnames = getHostnames(); +const childEnv = { ...process.env }; + +if (process.env.WORKTREE_NAME) { + const hostnames = getHostnames(); + childEnv.VITE_APP_UI_STAFF_AAD_AUTHORITY = buildPortlessUrl(hostnames.mockAuth, '/staff'); + childEnv.VITE_APP_UI_STAFF_AAD_REDIRECT_URI = buildPortlessUrl(hostnames.uiStaff, '/auth-redirect'); + childEnv.VITE_COMMON_API_ENDPOINT = buildPortlessUrl(hostnames.api, '/api/graphql'); +} const child = spawn('vite', ['--port', process.env.PORT, '--host', process.env.HOST ?? '127.0.0.1'], { stdio: 'inherit', - env: { - ...process.env, - VITE_APP_UI_STAFF_AAD_AUTHORITY: buildPortlessUrl(hostnames.mockAuth, '/staff'), - VITE_APP_UI_STAFF_AAD_REDIRECT_URI: buildPortlessUrl(hostnames.uiStaff, '/auth-redirect'), - VITE_COMMON_API_ENDPOINT: buildPortlessUrl(hostnames.api, '/api/graphql'), - }, + env: childEnv, }); child.on('exit', (code, signal) => { diff --git a/build-pipeline/scripts/portless-hostnames.d.mts b/build-pipeline/scripts/portless-hostnames.d.mts new file mode 100644 index 000000000..139d75e94 --- /dev/null +++ b/build-pipeline/scripts/portless-hostnames.d.mts @@ -0,0 +1,13 @@ +export const PORTLESS_PORT: number; + +export interface PortlessHostnames { + uiCommunity: string; + uiStaff: string; + api: string; + mockAuth: string; + docs: string; +} + +export function getHostnames(): PortlessHostnames; + +export function buildPortlessUrl(hostname: string, path?: string): string; diff --git a/build-pipeline/scripts/worktree-ports.d.mts b/build-pipeline/scripts/worktree-ports.d.mts new file mode 100644 index 000000000..c2cbdf86e --- /dev/null +++ b/build-pipeline/scripts/worktree-ports.d.mts @@ -0,0 +1,5 @@ +export function getWorktreePortOffset(): number; +export function getMongoPort(): number; +export function getAzuritePorts(): { blob: number; queue: number; table: number }; +export function getAzuriteConnectionString(): string; +export function getMongoConnectionString(): string; diff --git a/package.json b/package.json index c1757bc2c..3dc82ec64 100644 --- a/package.json +++ b/package.json @@ -13,7 +13,7 @@ "test": "turbo run test", "lint": "turbo run lint", "dev": "pnpm proxy:stop && pnpm proxy:start && turbo watch azurite dev --filter='./apps/*' --filter='./packages/*'", - "dev:portless": "WORKTREE_NAME=$(basename $PWD) pnpm proxy:ensure && WORKTREE_NAME=$(basename $PWD) turbo watch azurite dev:portless --filter='./apps/*' --filter='./packages/*'", + "dev:worktree": "WORKTREE_NAME=$(basename $PWD) pnpm proxy:ensure && WORKTREE_NAME=$(basename $PWD) turbo watch azurite dev:worktree --filter='./apps/*' --filter='./packages/*'", "start": "turbo run build && concurrently --kill-others-on-fail \"pnpm run start:api\" \"pnpm run start:ui-community\"", "proxy:stop": "pnpm exec portless proxy stop || true", "proxy:start": "pnpm exec portless proxy start --https -p 1355", @@ -33,7 +33,7 @@ "test:coverage": "turbo run test:coverage", "test:coverage:merge": "pnpm run test:coverage && pnpm run merge-lcov-reports", "test:e2e": "turbo run test:e2e --filter=@ocom-verification/e2e-tests", - "test:e2e:portless": "WORKTREE_NAME=$(basename $PWD) turbo run test:e2e --filter=@ocom-verification/e2e-tests", + "test:e2e:worktree": "WORKTREE_NAME=$(basename $PWD) turbo run test:e2e --filter=@ocom-verification/e2e-tests", "test:acceptance": "turbo run test:acceptance --filter=@ocom-verification/acceptance-api --filter=@ocom-verification/acceptance-ui", "merge-lcov-reports": "node build-pipeline/scripts/merge-coverage.js", "test:integration": "turbo run test:integration", diff --git a/packages/ocom-verification/e2e-tests/cucumber.js b/packages/ocom-verification/e2e-tests/cucumber.js index 51912f713..e548d91e5 100644 --- a/packages/ocom-verification/e2e-tests/cucumber.js +++ b/packages/ocom-verification/e2e-tests/cucumber.js @@ -7,5 +7,7 @@ export default { formatOptions: { snippetInterface: 'async-await', }, + // Disable parallel workers — the shared portless proxy and per-worktree port + // scheme make parallel browsers contend for the same hostnames. parallel: 0, }; diff --git a/packages/ocom-verification/e2e-tests/package.json b/packages/ocom-verification/e2e-tests/package.json index 6d3508bc6..cbe99de57 100644 --- a/packages/ocom-verification/e2e-tests/package.json +++ b/packages/ocom-verification/e2e-tests/package.json @@ -5,9 +5,7 @@ "private": true, "type": "module", "scripts": { - "test:e2e": "pnpm run proxy:start && pnpm run test:e2e:run", - "test:e2e:run": "NODE_EXTRA_CA_CERTS=${HOME}/.portless/ca.pem LOG_LEVEL=warn NODE_OPTIONS='--import tsx/esm' cucumber-js", - "proxy:start": "pnpm exec portless proxy start -p 1355", + "test:e2e": "NODE_EXTRA_CA_CERTS=${HOME}/.portless/ca.pem LOG_LEVEL=warn NODE_OPTIONS='--import tsx/esm' cucumber-js", "playwright:install": "playwright install chromium", "clean": "rimraf dist reports target" }, diff --git a/packages/ocom-verification/e2e-tests/src/shared/support/oauth2-login.ts b/packages/ocom-verification/e2e-tests/src/shared/support/oauth2-login.ts index abc2b4638..3bc2fccf8 100644 --- a/packages/ocom-verification/e2e-tests/src/shared/support/oauth2-login.ts +++ b/packages/ocom-verification/e2e-tests/src/shared/support/oauth2-login.ts @@ -1,3 +1,4 @@ +import { actors } from '@ocom-verification/verification-shared/test-data'; import { type Actor, Interaction, the } from '@serenity-js/core'; import type { Page } from 'playwright'; import { BrowseTheWeb } from '../abilities/browse-the-web.ts'; @@ -32,9 +33,10 @@ export async function performOAuth2Login(page: Page): Promise { // Wait for redirects to settle on either the login page or the app await page.waitForLoadState('domcontentloaded', { timeout: 10_000 }).catch(() => undefined); - // If the mock OAuth2 login form is shown, fill credentials and submit + // If the mock OAuth2 login form is shown, fill credentials and submit. + // CommunityOwner is defined in mock-oidc.users.json with password "password". if (page.url().includes('/login')) { - await page.fill('input[name="username"]', 'test@example.com'); + await page.fill('input[name="username"]', actors.CommunityOwner.email); await page.fill('input[name="password"]', 'password'); await page.click('button[type="submit"]'); } diff --git a/packages/ocom-verification/e2e-tests/src/shared/support/servers/e2e-defaults.ts b/packages/ocom-verification/e2e-tests/src/shared/support/servers/e2e-defaults.ts new file mode 100644 index 000000000..6680d32a8 --- /dev/null +++ b/packages/ocom-verification/e2e-tests/src/shared/support/servers/e2e-defaults.ts @@ -0,0 +1,65 @@ +// biome-ignore format: keep the public Azurite dev key split across chunks for static analysis. + +/** + * Non-secret environment defaults for the e2e harness. + * + * Used when `apps/api/local.settings.json` is absent (typical in CI). Every + * value here is either a public Azurite development credential or a mock-only + * constant — none of them are valid in any real environment, and they are + * never applied outside the e2e harness. + * + * Worktree-scoped values (OIDC URLs, mongo/azurite ports, connection strings) + * are computed at runtime by `build-pipeline/scripts/portless-hostnames.mjs` + * and `worktree-ports.mjs`; they intentionally do NOT live here. + */ + +const AZURITE_ACCOUNT_KEY = [ + 'Eby8vdM02xNOcqFlqUwJPLlm', + 'EtlCDXJ1OUzFT50uSRZ6IFs', + 'uFq2UVErCz4I6tq/K1SZFP', + 'TOtr/KBHBeksoGMGw==', +].join(''); + +const E2E_API_DEFAULTS = { + FUNCTIONS_WORKER_RUNTIME: 'node', + NODE_ENV: 'development', + CONFIG_VERSION: '3.0', + + ACCOUNT_PORTAL_OIDC_AUDIENCE: 'mock-client', + ACCOUNT_PORTAL_OIDC_IGNORE_ISSUER: 'true', + STAFF_PORTAL_OIDC_AUDIENCE: 'mock-client', + STAFF_PORTAL_OIDC_IGNORE_ISSUER: 'true', + + COSMOSDB_DBNAME: 'owner-community', + + // Well-known Azurite dev account — documented in Azurite's README, not a secret. + STORAGE_ACCOUNT_NAME: 'devstoreaccount1', + STORAGE_ACCOUNT_KEY: AZURITE_ACCOUNT_KEY, +} as const; + +/** + * Apply e2e defaults to `process.env` for any key not already set. A pre-existing + * env var (from the developer's shell or a copied local.settings.json) always wins. + * Spawned child processes inherit `process.env`, so this propagates to azurite, + * the api function host, and the oauth2 mock without any per-server plumbing. + */ +export function applyE2EDefaultsToEnv(): void { + for (const [key, value] of Object.entries(E2E_API_DEFAULTS)) { + process.env[key] ??= value; + } +} + +/** + * Returns a shallow copy of `process.env` with `NODE_OPTIONS` removed. + * + * Cucumber runs with `NODE_OPTIONS='--import tsx/esm'` so that TypeScript + * source is executed directly. Child processes spawned by the test harness + * (Azurite, portless, func) are plain JavaScript and do not have `tsx` on + * their resolution path, so inheriting `NODE_OPTIONS` causes an immediate + * crash. Callers can spread additional overrides on top of the result. + */ +export function spawnEnv(overrides: Record = {}): NodeJS.ProcessEnv { + const env = { ...process.env, ...overrides }; + delete env['NODE_OPTIONS']; + return env; +} diff --git a/packages/ocom-verification/e2e-tests/src/shared/support/servers/index.ts b/packages/ocom-verification/e2e-tests/src/shared/support/servers/index.ts index c096f6636..25d4dffc6 100644 --- a/packages/ocom-verification/e2e-tests/src/shared/support/servers/index.ts +++ b/packages/ocom-verification/e2e-tests/src/shared/support/servers/index.ts @@ -1,12 +1,12 @@ export { MongoDBTestServer } from '@ocom-verification/verification-shared/servers'; export { PortlessServer } from './portless-server.ts'; export { TestApiServer } from './test-api-server.ts'; +export { TestAzuriteServer } from './test-azurite-server.ts'; export { TestCommunityViteServer } from './test-community-vite-server.ts'; export { buildUrl, cleanupTestEnvironment, initTestEnvironment, - mockOidcAudience, mockOidcEndpoint, mockOidcIssuer, setMongoConnectionString, diff --git a/packages/ocom-verification/e2e-tests/src/shared/support/servers/portless-server.ts b/packages/ocom-verification/e2e-tests/src/shared/support/servers/portless-server.ts index aea6c3ab1..6ff6ace04 100644 --- a/packages/ocom-verification/e2e-tests/src/shared/support/servers/portless-server.ts +++ b/packages/ocom-verification/e2e-tests/src/shared/support/servers/portless-server.ts @@ -1,6 +1,7 @@ import { type ChildProcess, spawn } from 'node:child_process'; import type { TestServer } from '@ocom-verification/verification-shared/servers'; import { getTimeout } from '@ocom-verification/verification-shared/settings'; +import { spawnEnv } from './e2e-defaults.ts'; import { getPortlessPath } from './resolve-portless.ts'; /** @@ -68,16 +69,9 @@ export abstract class PortlessServer implements TestServer { if (this.process || this.startedByUs) return; if (await this.isAlreadyRunning()) return; - const env = { - ...process.env, - ...this.extraEnv, - }; - // Remove NODE_OPTIONS from child process to avoid tsx import issues - delete env['NODE_OPTIONS']; - this.process = spawn(this.executable, this.spawnArgs, { cwd: this.cwd, - env, + env: spawnEnv(this.extraEnv), detached: this.useDetachedProcessGroup, stdio: ['ignore', 'pipe', 'pipe'], }); @@ -159,7 +153,8 @@ export abstract class PortlessServer implements TestServer { }); proc.stderr?.on('data', (data: Buffer) => { - stderrOutput += data.toString(); + const text = data.toString(); + stderrOutput += text; }); proc.on('error', (err: Error) => { diff --git a/packages/ocom-verification/e2e-tests/src/shared/support/servers/test-api-server.ts b/packages/ocom-verification/e2e-tests/src/shared/support/servers/test-api-server.ts index 380249d50..a92d3f893 100644 --- a/packages/ocom-verification/e2e-tests/src/shared/support/servers/test-api-server.ts +++ b/packages/ocom-verification/e2e-tests/src/shared/support/servers/test-api-server.ts @@ -1,25 +1,44 @@ import { execFileSync } from 'node:child_process'; +import { readFileSync, writeFileSync } from 'node:fs'; +import { join } from 'node:path'; import { apiSettings } from '@ocom-verification/verification-shared/settings'; +import { spawnEnv } from './e2e-defaults.ts'; import { PortlessServer } from './portless-server.ts'; -import { buildUrl, getHostnames, getMongoConnectionString, mockOidcAudience, mockOidcEndpoint, mockOidcIssuer } from './test-environment.ts'; +import { buildUrl, getHostnames, getMongoConnectionString } from './test-environment.ts'; const hostnames = getHostnames(); +/** + * Spawns the api dev server the same way `pnpm dev:worktree` does. The + * worktree-aware overrides (OIDC URLs, Azurite connection, etc.) all come + * from apps/api/start-dev.mjs — we only inject the dynamic MongoDB + * connection string from MongoMemoryServer here. + */ export class TestApiServer extends PortlessServer { override async start(): Promise { - // Mirror the app's real dev bootstrap so deploy assets and local settings - // stay in sync with recent package-script changes. - const env = { - ...process.env, - }; - delete env['NODE_OPTIONS']; - - execFileSync('pnpm', ['run', 'predev'], { + // Mirror the `predev:worktree` lifecycle hook so deploy/ and local.settings.json + // stay in sync — start-dev.mjs is invoked directly here, bypassing pnpm's pre-hook. + execFileSync('pnpm', ['run', 'predev:worktree'], { cwd: this.cwd, - env, + env: spawnEnv(), stdio: 'pipe', }); + // Patch deploy/local.settings.json with e2e-specific values. + // Azure Functions loads local.settings.json values into the worker env, + // overriding any parent-process env vars. We must patch the file so the + // worker gets the MongoMemoryServer connection string (random port) and + // the inspector is disabled (port 5858 may already be in use). + const settingsPath = join(this.cwd, 'deploy', 'local.settings.json'); + try { + const settings = JSON.parse(readFileSync(settingsPath, 'utf-8')); + settings.Values.COSMOSDB_CONNECTION_STRING = getMongoConnectionString(); + settings.Values['languageWorkers__node__arguments'] = ''; + writeFileSync(settingsPath, JSON.stringify(settings, null, '\t')); + } catch { + /* best-effort — file may not exist in CI */ + } + await super.start(); } @@ -59,21 +78,9 @@ export class TestApiServer extends PortlessServer { } protected override get extraEnv() { + // start-dev.mjs handles the rest via WORKTREE_NAME + `??=` fallbacks. return { - NODE_ENV: 'development', - languageWorkers__node__arguments: '', COSMOSDB_CONNECTION_STRING: getMongoConnectionString(), - COSMOSDB_DBNAME: apiSettings.cosmosDbName, - AZURE_STORAGE_CONNECTION_STRING: 'UseDevelopmentStorage=true', - ACCOUNT_PORTAL_OIDC_ISSUER: mockOidcIssuer, - ACCOUNT_PORTAL_OIDC_ENDPOINT: mockOidcEndpoint, - ACCOUNT_PORTAL_OIDC_AUDIENCE: mockOidcAudience, - ACCOUNT_PORTAL_OIDC_IGNORE_ISSUER: 'true', - STAFF_PORTAL_OIDC_ISSUER: mockOidcIssuer, - STAFF_PORTAL_OIDC_ENDPOINT: mockOidcEndpoint, - STAFF_PORTAL_OIDC_AUDIENCE: mockOidcAudience, - STAFF_PORTAL_OIDC_IGNORE_ISSUER: 'true', - VITE_COMMON_API_ENDPOINT: buildUrl(hostnames.api, '/api/graphql'), }; } diff --git a/packages/ocom-verification/e2e-tests/src/shared/support/servers/test-azurite-server.ts b/packages/ocom-verification/e2e-tests/src/shared/support/servers/test-azurite-server.ts new file mode 100644 index 000000000..d43d9efd3 --- /dev/null +++ b/packages/ocom-verification/e2e-tests/src/shared/support/servers/test-azurite-server.ts @@ -0,0 +1,105 @@ +import { type ChildProcess, spawn } from 'node:child_process'; +import net from 'node:net'; +import { join } from 'node:path'; +import type { TestServer } from '@ocom-verification/verification-shared/servers'; +import { apiSettings, getTimeout } from '@ocom-verification/verification-shared/settings'; +import { getAzuritePorts } from '../../../../../../../build-pipeline/scripts/worktree-ports.mjs'; +import { spawnEnv } from './e2e-defaults.ts'; + +/** + * Starts Azurite via apps/api/start-azurite.mjs. The script itself short-circuits + * if the blob port is already listening, so concurrent worktrees and re-runs are + * safe. We track the spawned process only when we started it ourselves. + */ +export class TestAzuriteServer implements TestServer { + private process: ChildProcess | null = null; + private startedByUs = false; + private readonly useDetachedProcessGroup = process.platform !== 'win32'; + + private get blobPort(): number { + return getAzuritePorts().blob; + } + + async start(): Promise { + if (this.process || this.startedByUs) return; + if (await isPortListening(this.blobPort)) return; + + const binDir = join(apiSettings.apiDir, 'node_modules', '.bin'); + + this.process = spawn('node', ['start-azurite.mjs'], { + cwd: apiSettings.apiDir, + env: spawnEnv({ PATH: `${binDir}:${process.env['PATH'] ?? ''}` }), + detached: this.useDetachedProcessGroup, + stdio: ['ignore', 'pipe', 'pipe'], + }); + this.startedByUs = true; + + await this.waitForReady(); + } + + async stop(): Promise { + if (!this.process || !this.startedByUs) return; + + const proc = this.process; + this.process = null; + this.startedByUs = false; + + killProcess(proc, 'SIGTERM', this.useDetachedProcessGroup); + + await new Promise((resolve) => { + const timeout = setTimeout(() => { + killProcess(proc, 'SIGKILL', this.useDetachedProcessGroup); + resolve(); + }, getTimeout('serverShutdown')); + + proc.on('exit', () => { + clearTimeout(timeout); + resolve(); + }); + }); + } + + isRunning(): boolean { + return this.process !== null; + } + + getUrl(): string { + return `http://127.0.0.1:${this.blobPort}`; + } + + private async waitForReady(): Promise { + const deadline = Date.now() + getTimeout('serverStartup'); + const interval = getTimeout('healthProbeInterval'); + while (Date.now() < deadline) { + if (await isPortListening(this.blobPort)) return; + await new Promise((resolve) => setTimeout(resolve, interval)); + } + throw new Error(`TestAzuriteServer: blob port ${this.blobPort} did not start within timeout`); + } +} + +function isPortListening(port: number): Promise { + return new Promise((resolve) => { + const socket = net.createConnection({ port, host: '127.0.0.1' }); + socket.once('connect', () => { + socket.destroy(); + resolve(true); + }); + socket.once('error', () => { + socket.destroy(); + resolve(false); + }); + }); +} + +function killProcess(proc: ChildProcess, signal: NodeJS.Signals, useGroup: boolean): void { + if (useGroup && proc.pid) { + try { + process.kill(-proc.pid, signal); + return; + } catch { + /* Fall back to killing the direct child. */ + } + } + proc.kill(signal); +} diff --git a/packages/ocom-verification/e2e-tests/src/shared/support/servers/test-environment.ts b/packages/ocom-verification/e2e-tests/src/shared/support/servers/test-environment.ts index 4a8fbb54f..6550beb7f 100644 --- a/packages/ocom-verification/e2e-tests/src/shared/support/servers/test-environment.ts +++ b/packages/ocom-verification/e2e-tests/src/shared/support/servers/test-environment.ts @@ -1,11 +1,12 @@ import { execFileSync } from 'node:child_process'; import { buildPortlessUrl, getHostnames } from '@ocom-verification/verification-shared/settings'; +import { applyE2EDefaultsToEnv } from './e2e-defaults.ts'; import { getPortlessPath } from './resolve-portless.ts'; let proxyInitialized = false; let mongoConnectionString: string | undefined; -/** Module-level hostnames derived from .env files (matches dev:portless pattern). */ +/** Module-level hostnames derived from .env files (matches dev:worktree pattern). */ const hostnames = getHostnames(); /** OIDC issuer URL for the community portal on the mock auth server. */ @@ -14,19 +15,19 @@ export const mockOidcIssuer = buildPortlessUrl(hostnames.mockAuth, '/community') /** JWKS endpoint used as the OIDC discovery / probe URL. */ export const mockOidcEndpoint = `${mockOidcIssuer}/.well-known/jwks.json`; -/** Audience claim expected in JWTs issued by the mock OIDC server. */ -export const mockOidcAudience = 'mock-client'; - /** - * Prune orphaned portless route locks from previous test runs. - * The proxy itself is started by the `test:e2e` npm script before the - * Cucumber process spawns, so we only need to clean stale locks here. + * Apply e2e env defaults (so CI runs without local.settings.json) and ensure + * the portless proxy is running. The `proxy start` invocation is idempotent — + * if another worktree or dev session already started it on the shared port, + * this returns immediately. */ export function initTestEnvironment() { if (proxyInitialized) return; - execFileSync(getPortlessPath(), ['prune'], { - timeout: 10_000, + applyE2EDefaultsToEnv(); + + execFileSync(getPortlessPath(), ['proxy', 'start', '--https', '-p', '1355'], { + timeout: 15_000, stdio: 'pipe', }); diff --git a/packages/ocom-verification/e2e-tests/src/shared/support/shared-infrastructure.ts b/packages/ocom-verification/e2e-tests/src/shared/support/shared-infrastructure.ts index e91cca9b9..7a793aa96 100644 --- a/packages/ocom-verification/e2e-tests/src/shared/support/shared-infrastructure.ts +++ b/packages/ocom-verification/e2e-tests/src/shared/support/shared-infrastructure.ts @@ -1,9 +1,10 @@ import playwright, { type Browser, type BrowserContext } from 'playwright'; import { BrowseTheWeb } from '../abilities/browse-the-web.ts'; import { performOAuth2Login } from './oauth2-login.ts'; -import { cleanupTestEnvironment, initTestEnvironment, MongoDBTestServer, setMongoConnectionString, TestApiServer, TestCommunityViteServer, TestOAuth2Server } from './servers/index.ts'; +import { cleanupTestEnvironment, initTestEnvironment, MongoDBTestServer, setMongoConnectionString, TestApiServer, TestAzuriteServer, TestCommunityViteServer, TestOAuth2Server } from './servers/index.ts'; let mongoDBServer: MongoDBTestServer | undefined; +let azuriteServer: TestAzuriteServer | undefined; let oauth2Server: TestOAuth2Server | undefined; let apiServer: TestApiServer | undefined; let viteServer: TestCommunityViteServer | undefined; @@ -66,6 +67,10 @@ export async function stopAll(): Promise { await mongoDBServer.stop().catch(() => undefined); mongoDBServer = undefined; } + if (azuriteServer) { + await azuriteServer.stop().catch(() => undefined); + azuriteServer = undefined; + } apiUrl = undefined; browserBaseUrl = undefined; cleanupTestEnvironment(); @@ -75,14 +80,23 @@ export async function ensureE2EServers(): Promise { registerShutdownHandlers(); initTestEnvironment(); - // Phase 1: Start MongoDB and OAuth2 in parallel (no interdependency) + // Phase 1: Start MongoDB, Azurite, and OAuth2 in parallel (no interdependency) mongoDBServer ??= new MongoDBTestServer(); + azuriteServer ??= new TestAzuriteServer(); oauth2Server ??= new TestOAuth2Server(); const mongo = mongoDBServer; + const azurite = azuriteServer; const oauth2 = oauth2Server; const phase1: Promise[] = []; if (!mongo.isRunning()) { - phase1.push(mongo.start().then(() => setMongoConnectionString(mongo.getConnectionString()))); + phase1.push( + mongo.start().then(() => { + setMongoConnectionString(mongo.getConnectionString()); + }), + ); + } + if (!azurite.isRunning()) { + phase1.push(azurite.start()); } if (!oauth2.isRunning()) { phase1.push(oauth2.start()); diff --git a/packages/ocom-verification/verification-shared/src/servers/index.ts b/packages/ocom-verification/verification-shared/src/servers/index.ts index 32810914a..4313727fb 100644 --- a/packages/ocom-verification/verification-shared/src/servers/index.ts +++ b/packages/ocom-verification/verification-shared/src/servers/index.ts @@ -7,4 +7,4 @@ export { MongoDBTestServer, seedOwnerCommunityReferenceData, } from './test-mongodb-server.ts'; -export type { TestServer, TestServerOptions } from './test-server.interface.ts'; +export type { TestServer } from './test-server.interface.ts'; diff --git a/packages/ocom-verification/verification-shared/src/servers/test-mongodb-server.ts b/packages/ocom-verification/verification-shared/src/servers/test-mongodb-server.ts index 37937e616..ca57fa2b9 100644 --- a/packages/ocom-verification/verification-shared/src/servers/test-mongodb-server.ts +++ b/packages/ocom-verification/verification-shared/src/servers/test-mongodb-server.ts @@ -6,6 +6,7 @@ import { getAllMockUsers } from '../test-data/index.ts'; const MONGO_BINARY_VERSION = '7.0.14'; const DEFAULT_DB_NAME = 'owner-community-test'; const MAX_REPLSET_START_ATTEMPTS = 5; +type MongoMemoryReplSetConfig = NonNullable[0]>; export type MongoDBSeedDataFunction = (connectionString: string, dbName: string) => Promise; @@ -122,7 +123,7 @@ export class MongoDBTestServer { return this.serviceMongoose !== null; } - private async createReplicaSetWithRetry(config: Parameters[0]): Promise { + private async createReplicaSetWithRetry(config: MongoMemoryReplSetConfig): Promise { let lastError: unknown; for (let attempt = 1; attempt <= MAX_REPLSET_START_ATTEMPTS; attempt += 1) { diff --git a/packages/ocom-verification/verification-shared/src/servers/test-server.interface.ts b/packages/ocom-verification/verification-shared/src/servers/test-server.interface.ts index 8b08f6b92..16e024f23 100644 --- a/packages/ocom-verification/verification-shared/src/servers/test-server.interface.ts +++ b/packages/ocom-verification/verification-shared/src/servers/test-server.interface.ts @@ -1,15 +1,7 @@ /** * Common interface for all test servers (in-process and subprocess). - * - * This abstraction allows acceptance-api and e2e tests to use - * consistent server lifecycle management patterns while choosing - * the appropriate implementation: - * - * - **In-process** (GraphQLTestServer): Fast, isolated, mocked services - * Best for: API acceptance tests, unit-like integration tests - * - * - **Subprocess** (PortlessServer): Full stack, realistic, real services - * Best for: E2E tests, full system integration tests + * Implemented by GraphQLTestServer (in-process), PortlessServer (subprocess + * via the portless proxy), and TestAzuriteServer. */ export interface TestServer { /** Start the server and return when ready */ @@ -24,17 +16,3 @@ export interface TestServer { /** Get the server URL (throws if not running) */ getUrl(): string; } - -/** - * Configuration options for test server startup. - */ -export interface TestServerOptions { - /** Port to listen on (0 for random available port) */ - port?: number; - - /** Additional environment variables for subprocess servers */ - env?: Record; - - /** Timeout for server startup (defaults to centralized config) */ - startupTimeoutMs?: number; -} diff --git a/packages/ocom-verification/verification-shared/src/settings/local-settings.ts b/packages/ocom-verification/verification-shared/src/settings/local-settings.ts index c28d7a6f5..8e9929f78 100644 --- a/packages/ocom-verification/verification-shared/src/settings/local-settings.ts +++ b/packages/ocom-verification/verification-shared/src/settings/local-settings.ts @@ -8,36 +8,9 @@ const uiEnvPath = resolveWorkspacePath(workspaceRoot, 'apps/ui-community/.env'); const apiValues = readJsonSettings(apiSettingsPath); const uiValues = readDotEnv(uiEnvPath); -/** - * Defaults for E2E/acceptance test settings when local.settings.json is absent - * (e.g. CI pipelines). All values are non-secret mock/localhost references used - * exclusively by the test harness — no real credentials are involved. - */ -const ciDefaults = { - COSMOSDB_CONNECTION_STRING: '', - COSMOSDB_DBNAME: 'owner-community', - COSMOSDB_PORT: '50000', - NODE_ENV: 'development', - ACCOUNT_PORTAL_OIDC_AUDIENCE: 'mock-client', - ACCOUNT_PORTAL_OIDC_ISSUER: 'https://mock-auth.ownercommunity.localhost:1355/community', - ACCOUNT_PORTAL_OIDC_ENDPOINT: 'https://mock-auth.ownercommunity.localhost:1355/community/.well-known/jwks.json', -} as const; - -function setting(key: keyof typeof ciDefaults): string { - return readSetting(apiValues, key, ciDefaults[key]) ?? ciDefaults[key]; -} - export const apiSettings = { - nodeEnv: setting('NODE_ENV'), - isDevelopment: setting('NODE_ENV') === 'development', - - cosmosDbConnectionString: setting('COSMOSDB_CONNECTION_STRING'), - cosmosDbName: setting('COSMOSDB_DBNAME'), - cosmosDbPort: Number(setting('COSMOSDB_PORT')), - - accountPortalOidcIssuer: setting('ACCOUNT_PORTAL_OIDC_ISSUER'), - accountPortalOidcEndpoint: setting('ACCOUNT_PORTAL_OIDC_ENDPOINT'), - accountPortalOidcAudience: setting('ACCOUNT_PORTAL_OIDC_AUDIENCE'), + cosmosDbConnectionString: readSetting(apiValues, 'COSMOSDB_CONNECTION_STRING', '') ?? '', + cosmosDbName: readSetting(apiValues, 'COSMOSDB_DBNAME', 'owner-community') ?? 'owner-community', apiDir: path.dirname(apiSettingsPath), oauth2MockDir: path.join(workspaceRoot, 'apps', 'server-oauth2-mock'), diff --git a/packages/ocom-verification/verification-shared/src/settings/portless-settings.ts b/packages/ocom-verification/verification-shared/src/settings/portless-settings.ts index e084702e0..405f1802e 100644 --- a/packages/ocom-verification/verification-shared/src/settings/portless-settings.ts +++ b/packages/ocom-verification/verification-shared/src/settings/portless-settings.ts @@ -1,65 +1,7 @@ /** - * Portless hostname derivation for test environments. - * - * Mirrors the logic of `build-pipeline/scripts/portless-hostnames.mjs` — - * hostnames are derived from the tracked .env files rather than hardcoded, - * and the `WORKTREE_NAME` suffix is applied automatically. - * - * This keeps test-environment code in sync with the dev:portless startup - * scripts without adding a cross-layer import to build-pipeline/. + * Re-export of the canonical portless hostname helpers used by both the + * dev:worktree scripts and the E2E test harness. Keeping the .mjs file as + * the single source of truth means there is exactly one place that derives + * hostnames from .env and applies the WORKTREE_NAME suffix. */ - -import { findWorkspaceRoot, readDotEnv, resolveWorkspacePath } from './settings-utils.ts'; - -const PORTLESS_PORT = 1355; -const workspaceRoot = findWorkspaceRoot(); - -const uiCommunityEnv = readDotEnv(resolveWorkspacePath(workspaceRoot, 'apps/ui-community/.env')); -const uiStaffEnv = readDotEnv(resolveWorkspacePath(workspaceRoot, 'apps/ui-staff/.env')); - -function hostnameFromUrl(url: string): string { - try { - return new URL(url).hostname; - } catch { - return ''; - } -} - -/** Splice `.` in before `.localhost` for worktree isolation. */ -function applyWorktreeSuffix(hostname: string): string { - const wt = process.env['WORKTREE_NAME']; - if (!wt) return hostname; - return hostname.replace('.localhost', `.${wt}.localhost`); -} - -/** - * Returns all portless service hostnames scoped to the current worktree. - * Hostnames are derived from the tracked .env files — no names are hardcoded. - */ -export function getHostnames() { - const uiCommunity = hostnameFromUrl(uiCommunityEnv['VITE_APP_UI_COMMUNITY_BASE_URL'] ?? ''); - const api = hostnameFromUrl(uiCommunityEnv['VITE_COMMON_API_ENDPOINT'] ?? ''); - const mockAuth = hostnameFromUrl(uiCommunityEnv['VITE_APP_UI_COMMUNITY_B2C_AUTHORITY'] ?? ''); - const uiStaff = hostnameFromUrl(uiStaffEnv['VITE_APP_UI_STAFF_AAD_REDIRECT_URI'] ?? ''); - - if (!uiCommunity || !api || !mockAuth) { - throw new Error( - 'portless-settings: could not derive hostnames from .env files. ' + 'Ensure apps/ui-community/.env is present with VITE_APP_UI_COMMUNITY_BASE_URL, ' + 'VITE_COMMON_API_ENDPOINT, and VITE_APP_UI_COMMUNITY_B2C_AUTHORITY.', - ); - } - - return { - uiCommunity: applyWorktreeSuffix(uiCommunity), - uiStaff: uiStaff ? applyWorktreeSuffix(uiStaff) : '', - api: applyWorktreeSuffix(api), - mockAuth: applyWorktreeSuffix(mockAuth), - docs: applyWorktreeSuffix(`docs.${uiCommunity}`), - }; -} - -/** Build a full portless HTTPS URL from a hostname and optional path. */ -export function buildPortlessUrl(hostname: string, path = ''): string { - return `https://${hostname}:${PORTLESS_PORT}${path}`; -} - -export { PORTLESS_PORT }; +export { buildPortlessUrl, getHostnames, PORTLESS_PORT } from '../../../../../build-pipeline/scripts/portless-hostnames.mjs'; diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index a16e5e4be..8b33c6e41 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -948,25 +948,25 @@ importers: version: link:../config-vitest '@chromatic-com/storybook': specifier: ^4.1.1 - version: 4.1.3(storybook@9.1.20(@testing-library/dom@10.4.1)(vite@8.0.5(@emnapi/core@1.7.1)(@emnapi/runtime@1.7.1)(@types/node@24.10.1)(esbuild@0.27.4)(jiti@2.6.1)(less@4.4.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3))) + version: 4.1.3(storybook@9.1.20(@testing-library/dom@10.4.1)(vite@8.0.5(@emnapi/core@1.7.1)(@emnapi/runtime@1.7.1)(@types/node@24.10.1)(esbuild@0.25.12)(jiti@2.6.1)(less@4.4.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3))) '@storybook/addon-a11y': specifier: ^9.1.3 - version: 9.1.16(storybook@9.1.20(@testing-library/dom@10.4.1)(vite@8.0.5(@emnapi/core@1.7.1)(@emnapi/runtime@1.7.1)(@types/node@24.10.1)(esbuild@0.27.4)(jiti@2.6.1)(less@4.4.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3))) + version: 9.1.16(storybook@9.1.20(@testing-library/dom@10.4.1)(vite@8.0.5(@emnapi/core@1.7.1)(@emnapi/runtime@1.7.1)(@types/node@24.10.1)(esbuild@0.25.12)(jiti@2.6.1)(less@4.4.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3))) '@storybook/addon-docs': specifier: ^9.1.3 - version: 9.1.16(@types/react@19.2.7)(storybook@9.1.20(@testing-library/dom@10.4.1)(vite@8.0.5(@emnapi/core@1.7.1)(@emnapi/runtime@1.7.1)(@types/node@24.10.1)(esbuild@0.27.4)(jiti@2.6.1)(less@4.4.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3))) + version: 9.1.16(@types/react@19.2.7)(storybook@9.1.20(@testing-library/dom@10.4.1)(vite@8.0.5(@emnapi/core@1.7.1)(@emnapi/runtime@1.7.1)(@types/node@24.10.1)(esbuild@0.25.12)(jiti@2.6.1)(less@4.4.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3))) '@storybook/addon-onboarding': specifier: ^9.1.3 - version: 9.1.16(storybook@9.1.20(@testing-library/dom@10.4.1)(vite@8.0.5(@emnapi/core@1.7.1)(@emnapi/runtime@1.7.1)(@types/node@24.10.1)(esbuild@0.27.4)(jiti@2.6.1)(less@4.4.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3))) + version: 9.1.16(storybook@9.1.20(@testing-library/dom@10.4.1)(vite@8.0.5(@emnapi/core@1.7.1)(@emnapi/runtime@1.7.1)(@types/node@24.10.1)(esbuild@0.25.12)(jiti@2.6.1)(less@4.4.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3))) '@storybook/addon-vitest': specifier: ^9.1.3 - version: 9.1.20(@vitest/browser-playwright@4.1.2)(@vitest/browser@4.1.2(vite@8.0.5(@emnapi/core@1.7.1)(@emnapi/runtime@1.7.1)(@types/node@24.10.1)(esbuild@0.27.4)(jiti@2.6.1)(less@4.4.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3))(vitest@4.1.2))(@vitest/runner@4.1.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(storybook@9.1.20(@testing-library/dom@10.4.1)(vite@8.0.5(@emnapi/core@1.7.1)(@emnapi/runtime@1.7.1)(@types/node@24.10.1)(esbuild@0.27.4)(jiti@2.6.1)(less@4.4.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3)))(vitest@4.1.2) + version: 9.1.20(@vitest/browser-playwright@4.1.2)(@vitest/browser@4.1.2(vite@8.0.5(@emnapi/core@1.7.1)(@emnapi/runtime@1.7.1)(@types/node@24.10.1)(esbuild@0.25.12)(jiti@2.6.1)(less@4.4.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3))(vitest@4.1.2))(@vitest/runner@4.1.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(storybook@9.1.20(@testing-library/dom@10.4.1)(vite@8.0.5(@emnapi/core@1.7.1)(@emnapi/runtime@1.7.1)(@types/node@24.10.1)(esbuild@0.25.12)(jiti@2.6.1)(less@4.4.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3)))(vitest@4.1.2) '@storybook/react': specifier: ^9.1.9 - version: 9.1.16(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(storybook@9.1.20(@testing-library/dom@10.4.1)(vite@8.0.5(@emnapi/core@1.7.1)(@emnapi/runtime@1.7.1)(@types/node@24.10.1)(esbuild@0.27.4)(jiti@2.6.1)(less@4.4.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3)))(typescript@6.0.3) + version: 9.1.16(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(storybook@9.1.20(@testing-library/dom@10.4.1)(vite@8.0.5(@emnapi/core@1.7.1)(@emnapi/runtime@1.7.1)(@types/node@24.10.1)(esbuild@0.25.12)(jiti@2.6.1)(less@4.4.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3)))(typescript@6.0.3) '@storybook/react-vite': specifier: ^9.1.3 - version: 9.1.16(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(storybook@9.1.20(@testing-library/dom@10.4.1)(vite@8.0.5(@emnapi/core@1.7.1)(@emnapi/runtime@1.7.1)(@types/node@24.10.1)(esbuild@0.27.4)(jiti@2.6.1)(less@4.4.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3)))(typescript@6.0.3)(vite@8.0.5(@emnapi/core@1.7.1)(@emnapi/runtime@1.7.1)(@types/node@24.10.1)(esbuild@0.27.4)(jiti@2.6.1)(less@4.4.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3)) + version: 9.1.16(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(storybook@9.1.20(@testing-library/dom@10.4.1)(vite@8.0.5(@emnapi/core@1.7.1)(@emnapi/runtime@1.7.1)(@types/node@24.10.1)(esbuild@0.25.12)(jiti@2.6.1)(less@4.4.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3)))(typescript@6.0.3)(vite@8.0.5(@emnapi/core@1.7.1)(@emnapi/runtime@1.7.1)(@types/node@24.10.1)(esbuild@0.25.12)(jiti@2.6.1)(less@4.4.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3)) '@testing-library/react': specifier: ^16.3.0 version: 16.3.0(@testing-library/dom@10.4.1)(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) @@ -978,10 +978,10 @@ importers: version: 19.2.3(@types/react@19.2.7) '@vitest/browser': specifier: ^4.1.2 - version: 4.1.2(vite@8.0.5(@emnapi/core@1.7.1)(@emnapi/runtime@1.7.1)(@types/node@24.10.1)(esbuild@0.27.4)(jiti@2.6.1)(less@4.4.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3))(vitest@4.1.2) + version: 4.1.2(vite@8.0.5(@emnapi/core@1.7.1)(@emnapi/runtime@1.7.1)(@types/node@24.10.1)(esbuild@0.25.12)(jiti@2.6.1)(less@4.4.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3))(vitest@4.1.2) '@vitest/browser-playwright': specifier: ^4.1.2 - version: 4.1.2(playwright@1.59.0)(vite@8.0.5(@emnapi/core@1.7.1)(@emnapi/runtime@1.7.1)(@types/node@24.10.1)(esbuild@0.27.4)(jiti@2.6.1)(less@4.4.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3))(vitest@4.1.2) + version: 4.1.2(playwright@1.59.0)(vite@8.0.5(@emnapi/core@1.7.1)(@emnapi/runtime@1.7.1)(@types/node@24.10.1)(esbuild@0.25.12)(jiti@2.6.1)(less@4.4.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3))(vitest@4.1.2) '@vitest/coverage-istanbul': specifier: 'catalog:' version: 4.1.2(vitest@4.1.2) @@ -999,13 +999,13 @@ importers: version: 6.0.1 storybook: specifier: 'catalog:' - version: 9.1.20(@testing-library/dom@10.4.1)(vite@8.0.5(@emnapi/core@1.7.1)(@emnapi/runtime@1.7.1)(@types/node@24.10.1)(esbuild@0.27.4)(jiti@2.6.1)(less@4.4.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3)) + version: 9.1.20(@testing-library/dom@10.4.1)(vite@8.0.5(@emnapi/core@1.7.1)(@emnapi/runtime@1.7.1)(@types/node@24.10.1)(esbuild@0.25.12)(jiti@2.6.1)(less@4.4.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3)) typescript: specifier: 'catalog:' version: 6.0.3 vitest: specifier: 'catalog:' - version: 4.1.2(@opentelemetry/api@1.9.0)(@types/node@24.10.1)(@vitest/browser-playwright@4.1.2)(jsdom@26.1.0)(vite@8.0.5(@emnapi/core@1.7.1)(@emnapi/runtime@1.7.1)(@types/node@24.10.1)(esbuild@0.27.4)(jiti@2.6.1)(less@4.4.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3)) + version: 4.1.2(@opentelemetry/api@1.9.0)(@types/node@24.10.1)(@vitest/browser-playwright@4.1.2)(jsdom@26.1.0)(vite@8.0.5(@emnapi/core@1.7.1)(@emnapi/runtime@1.7.1)(@types/node@24.10.1)(esbuild@0.25.12)(jiti@2.6.1)(less@4.4.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3)) packages/ocom-verification/acceptance-api: dependencies: @@ -14761,6 +14761,18 @@ snapshots: '@blazediff/core@1.9.1': {} + '@chromatic-com/storybook@4.1.3(storybook@9.1.20(@testing-library/dom@10.4.1)(vite@8.0.5(@emnapi/core@1.7.1)(@emnapi/runtime@1.7.1)(@types/node@24.10.1)(esbuild@0.25.12)(jiti@2.6.1)(less@4.4.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3)))': + dependencies: + '@neoconfetti/react': 1.0.0 + chromatic: 13.3.4 + filesize: 10.1.6 + jsonfile: 6.2.0 + storybook: 9.1.20(@testing-library/dom@10.4.1)(vite@8.0.5(@emnapi/core@1.7.1)(@emnapi/runtime@1.7.1)(@types/node@24.10.1)(esbuild@0.25.12)(jiti@2.6.1)(less@4.4.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3)) + strip-ansi: 7.1.2 + transitivePeerDependencies: + - '@chromatic-com/cypress' + - '@chromatic-com/playwright' + '@chromatic-com/storybook@4.1.3(storybook@9.1.20(@testing-library/dom@10.4.1)(vite@8.0.5(@emnapi/core@1.7.1)(@emnapi/runtime@1.7.1)(@types/node@24.10.1)(esbuild@0.27.4)(jiti@2.6.1)(less@4.4.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3)))': dependencies: '@neoconfetti/react': 1.0.0 @@ -15089,7 +15101,7 @@ snapshots: '@cucumber/gherkin-utils': 11.0.0 '@cucumber/html-formatter': 23.0.0(@cucumber/messages@32.2.0) '@cucumber/junit-xml-formatter': 0.13.3(@cucumber/messages@32.2.0) - '@cucumber/message-streams': 4.1.1(@cucumber/messages@32.2.0) + '@cucumber/message-streams': 4.1.1(@cucumber/messages@32.3.1) '@cucumber/messages': 32.2.0 '@cucumber/pretty-formatter': 1.0.1(@cucumber/cucumber@12.8.1)(@cucumber/messages@32.2.0) '@cucumber/tag-expressions': 9.1.0 @@ -15125,7 +15137,7 @@ snapshots: '@cucumber/gherkin-streams@6.0.0(@cucumber/gherkin@38.0.0)(@cucumber/message-streams@4.1.1(@cucumber/messages@32.2.0))(@cucumber/messages@32.2.0)': dependencies: '@cucumber/gherkin': 38.0.0 - '@cucumber/message-streams': 4.1.1(@cucumber/messages@32.2.0) + '@cucumber/message-streams': 4.1.1(@cucumber/messages@32.3.1) '@cucumber/messages': 32.2.0 commander: 14.0.0 source-map-support: 0.5.21 @@ -15174,9 +15186,9 @@ snapshots: luxon: 3.7.2 xmlbuilder: 15.1.1 - '@cucumber/message-streams@4.1.1(@cucumber/messages@32.2.0)': + '@cucumber/message-streams@4.1.1(@cucumber/messages@32.3.1)': dependencies: - '@cucumber/messages': 32.2.0 + '@cucumber/messages': 32.3.1 mime: 3.0.0 '@cucumber/messages@26.0.1': @@ -16796,6 +16808,15 @@ snapshots: '@types/yargs': 17.0.35 chalk: 4.1.2 + '@joshwooding/vite-plugin-react-docgen-typescript@0.6.1(typescript@6.0.3)(vite@8.0.5(@emnapi/core@1.7.1)(@emnapi/runtime@1.7.1)(@types/node@24.10.1)(esbuild@0.25.12)(jiti@2.6.1)(less@4.4.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3))': + dependencies: + glob: 10.5.0 + magic-string: 0.30.21 + react-docgen-typescript: 2.4.0(typescript@6.0.3) + vite: 8.0.5(@emnapi/core@1.7.1)(@emnapi/runtime@1.7.1)(@types/node@24.10.1)(esbuild@0.25.12)(jiti@2.6.1)(less@4.4.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3) + optionalDependencies: + typescript: 6.0.3 + '@joshwooding/vite-plugin-react-docgen-typescript@0.6.1(typescript@6.0.3)(vite@8.0.5(@emnapi/core@1.7.1)(@emnapi/runtime@1.7.1)(@types/node@24.10.1)(esbuild@0.27.4)(jiti@2.6.1)(less@4.4.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3))': dependencies: glob: 10.5.0 @@ -18279,12 +18300,31 @@ snapshots: '@standard-schema/spec@1.1.0': {} + '@storybook/addon-a11y@9.1.16(storybook@9.1.20(@testing-library/dom@10.4.1)(vite@8.0.5(@emnapi/core@1.7.1)(@emnapi/runtime@1.7.1)(@types/node@24.10.1)(esbuild@0.25.12)(jiti@2.6.1)(less@4.4.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3)))': + dependencies: + '@storybook/global': 5.0.0 + axe-core: 4.11.0 + storybook: 9.1.20(@testing-library/dom@10.4.1)(vite@8.0.5(@emnapi/core@1.7.1)(@emnapi/runtime@1.7.1)(@types/node@24.10.1)(esbuild@0.25.12)(jiti@2.6.1)(less@4.4.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3)) + '@storybook/addon-a11y@9.1.16(storybook@9.1.20(@testing-library/dom@10.4.1)(vite@8.0.5(@emnapi/core@1.7.1)(@emnapi/runtime@1.7.1)(@types/node@24.10.1)(esbuild@0.27.4)(jiti@2.6.1)(less@4.4.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3)))': dependencies: '@storybook/global': 5.0.0 axe-core: 4.11.0 storybook: 9.1.20(@testing-library/dom@10.4.1)(vite@8.0.5(@emnapi/core@1.7.1)(@emnapi/runtime@1.7.1)(@types/node@24.10.1)(esbuild@0.27.4)(jiti@2.6.1)(less@4.4.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3)) + '@storybook/addon-docs@9.1.16(@types/react@19.2.7)(storybook@9.1.20(@testing-library/dom@10.4.1)(vite@8.0.5(@emnapi/core@1.7.1)(@emnapi/runtime@1.7.1)(@types/node@24.10.1)(esbuild@0.25.12)(jiti@2.6.1)(less@4.4.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3)))': + dependencies: + '@mdx-js/react': 3.1.1(@types/react@19.2.7)(react@19.2.0) + '@storybook/csf-plugin': 9.1.16(storybook@9.1.20(@testing-library/dom@10.4.1)(vite@8.0.5(@emnapi/core@1.7.1)(@emnapi/runtime@1.7.1)(@types/node@24.10.1)(esbuild@0.25.12)(jiti@2.6.1)(less@4.4.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3))) + '@storybook/icons': 1.6.0(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@storybook/react-dom-shim': 9.1.16(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(storybook@9.1.20(@testing-library/dom@10.4.1)(vite@8.0.5(@emnapi/core@1.7.1)(@emnapi/runtime@1.7.1)(@types/node@24.10.1)(esbuild@0.25.12)(jiti@2.6.1)(less@4.4.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3))) + react: 19.2.0 + react-dom: 19.2.0(react@19.2.0) + storybook: 9.1.20(@testing-library/dom@10.4.1)(vite@8.0.5(@emnapi/core@1.7.1)(@emnapi/runtime@1.7.1)(@types/node@24.10.1)(esbuild@0.25.12)(jiti@2.6.1)(less@4.4.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3)) + ts-dedent: 2.2.0 + transitivePeerDependencies: + - '@types/react' + '@storybook/addon-docs@9.1.16(@types/react@19.2.7)(storybook@9.1.20(@testing-library/dom@10.4.1)(vite@8.0.5(@emnapi/core@1.7.1)(@emnapi/runtime@1.7.1)(@types/node@24.10.1)(esbuild@0.27.4)(jiti@2.6.1)(less@4.4.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3)))': dependencies: '@mdx-js/react': 3.1.1(@types/react@19.2.7)(react@19.2.0) @@ -18298,6 +18338,10 @@ snapshots: transitivePeerDependencies: - '@types/react' + '@storybook/addon-onboarding@9.1.16(storybook@9.1.20(@testing-library/dom@10.4.1)(vite@8.0.5(@emnapi/core@1.7.1)(@emnapi/runtime@1.7.1)(@types/node@24.10.1)(esbuild@0.25.12)(jiti@2.6.1)(less@4.4.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3)))': + dependencies: + storybook: 9.1.20(@testing-library/dom@10.4.1)(vite@8.0.5(@emnapi/core@1.7.1)(@emnapi/runtime@1.7.1)(@types/node@24.10.1)(esbuild@0.25.12)(jiti@2.6.1)(less@4.4.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3)) + '@storybook/addon-onboarding@9.1.16(storybook@9.1.20(@testing-library/dom@10.4.1)(vite@8.0.5(@emnapi/core@1.7.1)(@emnapi/runtime@1.7.1)(@types/node@24.10.1)(esbuild@0.27.4)(jiti@2.6.1)(less@4.4.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3)))': dependencies: storybook: 9.1.20(@testing-library/dom@10.4.1)(vite@8.0.5(@emnapi/core@1.7.1)(@emnapi/runtime@1.7.1)(@types/node@24.10.1)(esbuild@0.27.4)(jiti@2.6.1)(less@4.4.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3)) @@ -18318,6 +18362,22 @@ snapshots: - react - react-dom + '@storybook/addon-vitest@9.1.20(@vitest/browser-playwright@4.1.2)(@vitest/browser@4.1.2(vite@8.0.5(@emnapi/core@1.7.1)(@emnapi/runtime@1.7.1)(@types/node@24.10.1)(esbuild@0.25.12)(jiti@2.6.1)(less@4.4.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3))(vitest@4.1.2))(@vitest/runner@4.1.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(storybook@9.1.20(@testing-library/dom@10.4.1)(vite@8.0.5(@emnapi/core@1.7.1)(@emnapi/runtime@1.7.1)(@types/node@24.10.1)(esbuild@0.25.12)(jiti@2.6.1)(less@4.4.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3)))(vitest@4.1.2)': + dependencies: + '@storybook/global': 5.0.0 + '@storybook/icons': 1.6.0(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + prompts: 2.4.2 + storybook: 9.1.20(@testing-library/dom@10.4.1)(vite@8.0.5(@emnapi/core@1.7.1)(@emnapi/runtime@1.7.1)(@types/node@24.10.1)(esbuild@0.25.12)(jiti@2.6.1)(less@4.4.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3)) + ts-dedent: 2.2.0 + optionalDependencies: + '@vitest/browser': 4.1.2(vite@8.0.5(@emnapi/core@1.7.1)(@emnapi/runtime@1.7.1)(@types/node@24.10.1)(esbuild@0.25.12)(jiti@2.6.1)(less@4.4.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3))(vitest@4.1.2) + '@vitest/browser-playwright': 4.1.2(playwright@1.59.0)(vite@8.0.5(@emnapi/core@1.7.1)(@emnapi/runtime@1.7.1)(@types/node@24.10.1)(esbuild@0.25.12)(jiti@2.6.1)(less@4.4.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3))(vitest@4.1.2) + '@vitest/runner': 4.1.2 + vitest: 4.1.2(@opentelemetry/api@1.9.0)(@types/node@24.10.1)(@vitest/browser-playwright@4.1.2)(jsdom@26.1.0)(vite@8.0.5(@emnapi/core@1.7.1)(@emnapi/runtime@1.7.1)(@types/node@24.10.1)(esbuild@0.25.12)(jiti@2.6.1)(less@4.4.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3)) + transitivePeerDependencies: + - react + - react-dom + '@storybook/addon-vitest@9.1.20(@vitest/browser-playwright@4.1.2)(@vitest/browser@4.1.2(vite@8.0.5(@emnapi/core@1.7.1)(@emnapi/runtime@1.7.1)(@types/node@24.10.1)(esbuild@0.27.4)(jiti@2.6.1)(less@4.4.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3))(vitest@4.1.2))(@vitest/runner@4.1.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(storybook@9.1.20(@testing-library/dom@10.4.1)(vite@8.0.5(@emnapi/core@1.7.1)(@emnapi/runtime@1.7.1)(@types/node@24.10.1)(esbuild@0.27.4)(jiti@2.6.1)(less@4.4.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3)))(vitest@4.1.2)': dependencies: '@storybook/global': 5.0.0 @@ -18334,6 +18394,13 @@ snapshots: - react - react-dom + '@storybook/builder-vite@9.1.16(storybook@9.1.20(@testing-library/dom@10.4.1)(vite@8.0.5(@emnapi/core@1.7.1)(@emnapi/runtime@1.7.1)(@types/node@24.10.1)(esbuild@0.25.12)(jiti@2.6.1)(less@4.4.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3)))(vite@8.0.5(@emnapi/core@1.7.1)(@emnapi/runtime@1.7.1)(@types/node@24.10.1)(esbuild@0.25.12)(jiti@2.6.1)(less@4.4.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3))': + dependencies: + '@storybook/csf-plugin': 9.1.16(storybook@9.1.20(@testing-library/dom@10.4.1)(vite@8.0.5(@emnapi/core@1.7.1)(@emnapi/runtime@1.7.1)(@types/node@24.10.1)(esbuild@0.25.12)(jiti@2.6.1)(less@4.4.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3))) + storybook: 9.1.20(@testing-library/dom@10.4.1)(vite@8.0.5(@emnapi/core@1.7.1)(@emnapi/runtime@1.7.1)(@types/node@24.10.1)(esbuild@0.25.12)(jiti@2.6.1)(less@4.4.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3)) + ts-dedent: 2.2.0 + vite: 8.0.5(@emnapi/core@1.7.1)(@emnapi/runtime@1.7.1)(@types/node@24.10.1)(esbuild@0.25.12)(jiti@2.6.1)(less@4.4.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3) + '@storybook/builder-vite@9.1.16(storybook@9.1.20(@testing-library/dom@10.4.1)(vite@8.0.5(@emnapi/core@1.7.1)(@emnapi/runtime@1.7.1)(@types/node@24.10.1)(esbuild@0.27.4)(jiti@2.6.1)(less@4.4.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3)))(vite@8.0.5(@emnapi/core@1.7.1)(@emnapi/runtime@1.7.1)(@types/node@24.10.1)(esbuild@0.27.4)(jiti@2.6.1)(less@4.4.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3))': dependencies: '@storybook/csf-plugin': 9.1.16(storybook@9.1.20(@testing-library/dom@10.4.1)(vite@8.0.5(@emnapi/core@1.7.1)(@emnapi/runtime@1.7.1)(@types/node@24.10.1)(esbuild@0.27.4)(jiti@2.6.1)(less@4.4.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3))) @@ -18341,6 +18408,11 @@ snapshots: ts-dedent: 2.2.0 vite: 8.0.5(@emnapi/core@1.7.1)(@emnapi/runtime@1.7.1)(@types/node@24.10.1)(esbuild@0.27.4)(jiti@2.6.1)(less@4.4.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3) + '@storybook/csf-plugin@9.1.16(storybook@9.1.20(@testing-library/dom@10.4.1)(vite@8.0.5(@emnapi/core@1.7.1)(@emnapi/runtime@1.7.1)(@types/node@24.10.1)(esbuild@0.25.12)(jiti@2.6.1)(less@4.4.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3)))': + dependencies: + storybook: 9.1.20(@testing-library/dom@10.4.1)(vite@8.0.5(@emnapi/core@1.7.1)(@emnapi/runtime@1.7.1)(@types/node@24.10.1)(esbuild@0.25.12)(jiti@2.6.1)(less@4.4.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3)) + unplugin: 1.16.1 + '@storybook/csf-plugin@9.1.16(storybook@9.1.20(@testing-library/dom@10.4.1)(vite@8.0.5(@emnapi/core@1.7.1)(@emnapi/runtime@1.7.1)(@types/node@24.10.1)(esbuild@0.27.4)(jiti@2.6.1)(less@4.4.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3)))': dependencies: storybook: 9.1.20(@testing-library/dom@10.4.1)(vite@8.0.5(@emnapi/core@1.7.1)(@emnapi/runtime@1.7.1)(@types/node@24.10.1)(esbuild@0.27.4)(jiti@2.6.1)(less@4.4.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3)) @@ -18353,12 +18425,38 @@ snapshots: react: 19.2.0 react-dom: 19.2.0(react@19.2.0) + '@storybook/react-dom-shim@9.1.16(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(storybook@9.1.20(@testing-library/dom@10.4.1)(vite@8.0.5(@emnapi/core@1.7.1)(@emnapi/runtime@1.7.1)(@types/node@24.10.1)(esbuild@0.25.12)(jiti@2.6.1)(less@4.4.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3)))': + dependencies: + react: 19.2.0 + react-dom: 19.2.0(react@19.2.0) + storybook: 9.1.20(@testing-library/dom@10.4.1)(vite@8.0.5(@emnapi/core@1.7.1)(@emnapi/runtime@1.7.1)(@types/node@24.10.1)(esbuild@0.25.12)(jiti@2.6.1)(less@4.4.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3)) + '@storybook/react-dom-shim@9.1.16(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(storybook@9.1.20(@testing-library/dom@10.4.1)(vite@8.0.5(@emnapi/core@1.7.1)(@emnapi/runtime@1.7.1)(@types/node@24.10.1)(esbuild@0.27.4)(jiti@2.6.1)(less@4.4.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3)))': dependencies: react: 19.2.0 react-dom: 19.2.0(react@19.2.0) storybook: 9.1.20(@testing-library/dom@10.4.1)(vite@8.0.5(@emnapi/core@1.7.1)(@emnapi/runtime@1.7.1)(@types/node@24.10.1)(esbuild@0.27.4)(jiti@2.6.1)(less@4.4.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3)) + '@storybook/react-vite@9.1.16(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(storybook@9.1.20(@testing-library/dom@10.4.1)(vite@8.0.5(@emnapi/core@1.7.1)(@emnapi/runtime@1.7.1)(@types/node@24.10.1)(esbuild@0.25.12)(jiti@2.6.1)(less@4.4.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3)))(typescript@6.0.3)(vite@8.0.5(@emnapi/core@1.7.1)(@emnapi/runtime@1.7.1)(@types/node@24.10.1)(esbuild@0.25.12)(jiti@2.6.1)(less@4.4.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3))': + dependencies: + '@joshwooding/vite-plugin-react-docgen-typescript': 0.6.1(typescript@6.0.3)(vite@8.0.5(@emnapi/core@1.7.1)(@emnapi/runtime@1.7.1)(@types/node@24.10.1)(esbuild@0.25.12)(jiti@2.6.1)(less@4.4.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3)) + '@rollup/pluginutils': 5.3.0 + '@storybook/builder-vite': 9.1.16(storybook@9.1.20(@testing-library/dom@10.4.1)(vite@8.0.5(@emnapi/core@1.7.1)(@emnapi/runtime@1.7.1)(@types/node@24.10.1)(esbuild@0.25.12)(jiti@2.6.1)(less@4.4.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3)))(vite@8.0.5(@emnapi/core@1.7.1)(@emnapi/runtime@1.7.1)(@types/node@24.10.1)(esbuild@0.25.12)(jiti@2.6.1)(less@4.4.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3)) + '@storybook/react': 9.1.16(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(storybook@9.1.20(@testing-library/dom@10.4.1)(vite@8.0.5(@emnapi/core@1.7.1)(@emnapi/runtime@1.7.1)(@types/node@24.10.1)(esbuild@0.25.12)(jiti@2.6.1)(less@4.4.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3)))(typescript@6.0.3) + find-up: 7.0.0 + magic-string: 0.30.21 + react: 19.2.0 + react-docgen: 8.0.2 + react-dom: 19.2.0(react@19.2.0) + resolve: 1.22.11 + storybook: 9.1.20(@testing-library/dom@10.4.1)(vite@8.0.5(@emnapi/core@1.7.1)(@emnapi/runtime@1.7.1)(@types/node@24.10.1)(esbuild@0.25.12)(jiti@2.6.1)(less@4.4.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3)) + tsconfig-paths: 4.2.0 + vite: 8.0.5(@emnapi/core@1.7.1)(@emnapi/runtime@1.7.1)(@types/node@24.10.1)(esbuild@0.25.12)(jiti@2.6.1)(less@4.4.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3) + transitivePeerDependencies: + - rollup + - supports-color + - typescript + '@storybook/react-vite@9.1.16(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(storybook@9.1.20(@testing-library/dom@10.4.1)(vite@8.0.5(@emnapi/core@1.7.1)(@emnapi/runtime@1.7.1)(@types/node@24.10.1)(esbuild@0.27.4)(jiti@2.6.1)(less@4.4.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3)))(typescript@6.0.3)(vite@8.0.5(@emnapi/core@1.7.1)(@emnapi/runtime@1.7.1)(@types/node@24.10.1)(esbuild@0.27.4)(jiti@2.6.1)(less@4.4.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3))': dependencies: '@joshwooding/vite-plugin-react-docgen-typescript': 0.6.1(typescript@6.0.3)(vite@8.0.5(@emnapi/core@1.7.1)(@emnapi/runtime@1.7.1)(@types/node@24.10.1)(esbuild@0.27.4)(jiti@2.6.1)(less@4.4.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3)) @@ -18379,6 +18477,16 @@ snapshots: - supports-color - typescript + '@storybook/react@9.1.16(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(storybook@9.1.20(@testing-library/dom@10.4.1)(vite@8.0.5(@emnapi/core@1.7.1)(@emnapi/runtime@1.7.1)(@types/node@24.10.1)(esbuild@0.25.12)(jiti@2.6.1)(less@4.4.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3)))(typescript@6.0.3)': + dependencies: + '@storybook/global': 5.0.0 + '@storybook/react-dom-shim': 9.1.16(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(storybook@9.1.20(@testing-library/dom@10.4.1)(vite@8.0.5(@emnapi/core@1.7.1)(@emnapi/runtime@1.7.1)(@types/node@24.10.1)(esbuild@0.25.12)(jiti@2.6.1)(less@4.4.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3))) + react: 19.2.0 + react-dom: 19.2.0(react@19.2.0) + storybook: 9.1.20(@testing-library/dom@10.4.1)(vite@8.0.5(@emnapi/core@1.7.1)(@emnapi/runtime@1.7.1)(@types/node@24.10.1)(esbuild@0.25.12)(jiti@2.6.1)(less@4.4.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3)) + optionalDependencies: + typescript: 6.0.3 + '@storybook/react@9.1.16(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(storybook@9.1.20(@testing-library/dom@10.4.1)(vite@8.0.5(@emnapi/core@1.7.1)(@emnapi/runtime@1.7.1)(@types/node@24.10.1)(esbuild@0.27.4)(jiti@2.6.1)(less@4.4.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3)))(typescript@6.0.3)': dependencies: '@storybook/global': 5.0.0 @@ -18882,6 +18990,19 @@ snapshots: - vite optional: true + '@vitest/browser-playwright@4.1.2(playwright@1.59.0)(vite@8.0.5(@emnapi/core@1.7.1)(@emnapi/runtime@1.7.1)(@types/node@24.10.1)(esbuild@0.25.12)(jiti@2.6.1)(less@4.4.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3))(vitest@4.1.2)': + dependencies: + '@vitest/browser': 4.1.2(vite@8.0.5(@emnapi/core@1.7.1)(@emnapi/runtime@1.7.1)(@types/node@24.10.1)(esbuild@0.25.12)(jiti@2.6.1)(less@4.4.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3))(vitest@4.1.2) + '@vitest/mocker': 4.1.2(vite@8.0.5(@emnapi/core@1.7.1)(@emnapi/runtime@1.7.1)(@types/node@24.10.1)(esbuild@0.25.12)(jiti@2.6.1)(less@4.4.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3)) + playwright: 1.59.0 + tinyrainbow: 3.1.0 + vitest: 4.1.2(@opentelemetry/api@1.9.0)(@types/node@24.10.1)(@vitest/browser-playwright@4.1.2)(jsdom@26.1.0)(vite@8.0.5(@emnapi/core@1.7.1)(@emnapi/runtime@1.7.1)(@types/node@24.10.1)(esbuild@0.25.12)(jiti@2.6.1)(less@4.4.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3)) + transitivePeerDependencies: + - bufferutil + - msw + - utf-8-validate + - vite + '@vitest/browser-playwright@4.1.2(playwright@1.59.0)(vite@8.0.5(@emnapi/core@1.7.1)(@emnapi/runtime@1.7.1)(@types/node@24.10.1)(esbuild@0.27.4)(jiti@2.6.1)(less@4.4.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3))(vitest@4.1.2)': dependencies: '@vitest/browser': 4.1.2(vite@8.0.5(@emnapi/core@1.7.1)(@emnapi/runtime@1.7.1)(@types/node@24.10.1)(esbuild@0.27.4)(jiti@2.6.1)(less@4.4.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3))(vitest@4.1.2) @@ -18913,6 +19034,23 @@ snapshots: - vite optional: true + '@vitest/browser@4.1.2(vite@8.0.5(@emnapi/core@1.7.1)(@emnapi/runtime@1.7.1)(@types/node@24.10.1)(esbuild@0.25.12)(jiti@2.6.1)(less@4.4.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3))(vitest@4.1.2)': + dependencies: + '@blazediff/core': 1.9.1 + '@vitest/mocker': 4.1.2(vite@8.0.5(@emnapi/core@1.7.1)(@emnapi/runtime@1.7.1)(@types/node@24.10.1)(esbuild@0.25.12)(jiti@2.6.1)(less@4.4.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3)) + '@vitest/utils': 4.1.2 + magic-string: 0.30.21 + pngjs: 7.0.0 + sirv: 3.0.2 + tinyrainbow: 3.1.0 + vitest: 4.1.2(@opentelemetry/api@1.9.0)(@types/node@24.10.1)(@vitest/browser-playwright@4.1.2)(jsdom@26.1.0)(vite@8.0.5(@emnapi/core@1.7.1)(@emnapi/runtime@1.7.1)(@types/node@24.10.1)(esbuild@0.25.12)(jiti@2.6.1)(less@4.4.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3)) + ws: 8.20.1 + transitivePeerDependencies: + - bufferutil + - msw + - utf-8-validate + - vite + '@vitest/browser@4.1.2(vite@8.0.5(@emnapi/core@1.7.1)(@emnapi/runtime@1.7.1)(@types/node@24.10.1)(esbuild@0.27.4)(jiti@2.6.1)(less@4.4.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3))(vitest@4.1.2)': dependencies: '@blazediff/core': 1.9.1 @@ -18942,7 +19080,7 @@ snapshots: magicast: 0.5.2 obug: 2.1.1 tinyrainbow: 3.1.0 - vitest: 4.1.2(@opentelemetry/api@1.9.0)(@types/node@22.19.15)(@vitest/browser-playwright@4.1.2)(jsdom@26.1.0)(vite@8.0.5(@emnapi/core@1.7.1)(@emnapi/runtime@1.7.1)(@types/node@22.19.15)(esbuild@0.27.4)(jiti@2.6.1)(less@4.4.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3)) + vitest: 4.1.2(@opentelemetry/api@1.9.0)(@types/node@24.10.1)(@vitest/browser-playwright@4.1.2)(jsdom@26.1.0)(vite@8.0.5(@emnapi/core@1.7.1)(@emnapi/runtime@1.7.1)(@types/node@24.10.1)(esbuild@0.27.4)(jiti@2.6.1)(less@4.4.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3)) transitivePeerDependencies: - supports-color @@ -18963,6 +19101,14 @@ snapshots: chai: 6.2.2 tinyrainbow: 3.1.0 + '@vitest/mocker@3.2.4(vite@8.0.5(@emnapi/core@1.7.1)(@emnapi/runtime@1.7.1)(@types/node@24.10.1)(esbuild@0.25.12)(jiti@2.6.1)(less@4.4.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3))': + dependencies: + '@vitest/spy': 3.2.4 + estree-walker: 3.0.3 + magic-string: 0.30.21 + optionalDependencies: + vite: 8.0.5(@emnapi/core@1.7.1)(@emnapi/runtime@1.7.1)(@types/node@24.10.1)(esbuild@0.25.12)(jiti@2.6.1)(less@4.4.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3) + '@vitest/mocker@3.2.4(vite@8.0.5(@emnapi/core@1.7.1)(@emnapi/runtime@1.7.1)(@types/node@24.10.1)(esbuild@0.27.4)(jiti@2.6.1)(less@4.4.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3))': dependencies: '@vitest/spy': 3.2.4 @@ -18979,6 +19125,14 @@ snapshots: optionalDependencies: vite: 8.0.5(@emnapi/core@1.7.1)(@emnapi/runtime@1.7.1)(@types/node@22.19.15)(esbuild@0.27.4)(jiti@2.6.1)(less@4.4.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3) + '@vitest/mocker@4.1.2(vite@8.0.5(@emnapi/core@1.7.1)(@emnapi/runtime@1.7.1)(@types/node@24.10.1)(esbuild@0.25.12)(jiti@2.6.1)(less@4.4.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3))': + dependencies: + '@vitest/spy': 4.1.2 + estree-walker: 3.0.3 + magic-string: 0.30.21 + optionalDependencies: + vite: 8.0.5(@emnapi/core@1.7.1)(@emnapi/runtime@1.7.1)(@types/node@24.10.1)(esbuild@0.25.12)(jiti@2.6.1)(less@4.4.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3) + '@vitest/mocker@4.1.2(vite@8.0.5(@emnapi/core@1.7.1)(@emnapi/runtime@1.7.1)(@types/node@24.10.1)(esbuild@0.27.4)(jiti@2.6.1)(less@4.4.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3))': dependencies: '@vitest/spy': 4.1.2 @@ -25312,6 +25466,28 @@ snapshots: graphql: 16.12.0 react: 19.2.0 + storybook@9.1.20(@testing-library/dom@10.4.1)(vite@8.0.5(@emnapi/core@1.7.1)(@emnapi/runtime@1.7.1)(@types/node@24.10.1)(esbuild@0.25.12)(jiti@2.6.1)(less@4.4.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3)): + dependencies: + '@storybook/global': 5.0.0 + '@testing-library/jest-dom': 6.9.1 + '@testing-library/user-event': 14.6.1(@testing-library/dom@10.4.1) + '@vitest/expect': 3.2.4 + '@vitest/mocker': 3.2.4(vite@8.0.5(@emnapi/core@1.7.1)(@emnapi/runtime@1.7.1)(@types/node@24.10.1)(esbuild@0.25.12)(jiti@2.6.1)(less@4.4.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3)) + '@vitest/spy': 3.2.4 + better-opn: 3.0.2 + esbuild: 0.25.12 + esbuild-register: 3.6.0(esbuild@0.25.12) + recast: 0.23.11 + semver: 7.7.4 + ws: 8.20.1 + transitivePeerDependencies: + - '@testing-library/dom' + - bufferutil + - msw + - supports-color + - utf-8-validate + - vite + storybook@9.1.20(@testing-library/dom@10.4.1)(vite@8.0.5(@emnapi/core@1.7.1)(@emnapi/runtime@1.7.1)(@types/node@24.10.1)(esbuild@0.27.4)(jiti@2.6.1)(less@4.4.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3)): dependencies: '@storybook/global': 5.0.0 @@ -26069,6 +26245,26 @@ snapshots: - '@emnapi/core' - '@emnapi/runtime' + vite@8.0.5(@emnapi/core@1.7.1)(@emnapi/runtime@1.7.1)(@types/node@24.10.1)(esbuild@0.25.12)(jiti@2.6.1)(less@4.4.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3): + dependencies: + lightningcss: 1.32.0 + picomatch: 4.0.4 + postcss: 8.5.10 + rolldown: 1.0.0-rc.12(@emnapi/core@1.7.1)(@emnapi/runtime@1.7.1) + tinyglobby: 0.2.15 + optionalDependencies: + '@types/node': 24.10.1 + esbuild: 0.25.12 + fsevents: 2.3.3 + jiti: 2.6.1 + less: 4.4.2 + terser: 5.44.1 + tsx: 4.21.0 + yaml: 2.8.3 + transitivePeerDependencies: + - '@emnapi/core' + - '@emnapi/runtime' + vite@8.0.5(@emnapi/core@1.7.1)(@emnapi/runtime@1.7.1)(@types/node@24.10.1)(esbuild@0.27.4)(jiti@2.6.1)(less@4.4.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3): dependencies: lightningcss: 1.32.0 @@ -26119,6 +26315,36 @@ snapshots: transitivePeerDependencies: - msw + vitest@4.1.2(@opentelemetry/api@1.9.0)(@types/node@24.10.1)(@vitest/browser-playwright@4.1.2)(jsdom@26.1.0)(vite@8.0.5(@emnapi/core@1.7.1)(@emnapi/runtime@1.7.1)(@types/node@24.10.1)(esbuild@0.25.12)(jiti@2.6.1)(less@4.4.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3)): + dependencies: + '@vitest/expect': 4.1.2 + '@vitest/mocker': 4.1.2(vite@8.0.5(@emnapi/core@1.7.1)(@emnapi/runtime@1.7.1)(@types/node@24.10.1)(esbuild@0.25.12)(jiti@2.6.1)(less@4.4.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3)) + '@vitest/pretty-format': 4.1.2 + '@vitest/runner': 4.1.2 + '@vitest/snapshot': 4.1.2 + '@vitest/spy': 4.1.2 + '@vitest/utils': 4.1.2 + es-module-lexer: 2.0.0 + expect-type: 1.3.0 + magic-string: 0.30.21 + obug: 2.1.1 + pathe: 2.0.3 + picomatch: 4.0.4 + std-env: 4.0.0 + tinybench: 2.9.0 + tinyexec: 1.0.4 + tinyglobby: 0.2.15 + tinyrainbow: 3.1.0 + vite: 8.0.5(@emnapi/core@1.7.1)(@emnapi/runtime@1.7.1)(@types/node@24.10.1)(esbuild@0.25.12)(jiti@2.6.1)(less@4.4.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3) + why-is-node-running: 2.3.0 + optionalDependencies: + '@opentelemetry/api': 1.9.0 + '@types/node': 24.10.1 + '@vitest/browser-playwright': 4.1.2(playwright@1.59.0)(vite@8.0.5(@emnapi/core@1.7.1)(@emnapi/runtime@1.7.1)(@types/node@24.10.1)(esbuild@0.25.12)(jiti@2.6.1)(less@4.4.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3))(vitest@4.1.2) + jsdom: 26.1.0 + transitivePeerDependencies: + - msw + vitest@4.1.2(@opentelemetry/api@1.9.0)(@types/node@24.10.1)(@vitest/browser-playwright@4.1.2)(jsdom@26.1.0)(vite@8.0.5(@emnapi/core@1.7.1)(@emnapi/runtime@1.7.1)(@types/node@24.10.1)(esbuild@0.27.4)(jiti@2.6.1)(less@4.4.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3)): dependencies: '@vitest/expect': 4.1.2 diff --git a/readme.md b/readme.md index c64caa156..c05851acc 100644 --- a/readme.md +++ b/readme.md @@ -26,8 +26,6 @@ Our Docusaurus website will help you get started in running and contributing to ## Developer usage - - - Full local dev (builds, starts the portless HTTPS proxy, starts Azurite, and runs the app-level dev servers): ```bash diff --git a/turbo.json b/turbo.json index 8bef61034..c1988720e 100644 --- a/turbo.json +++ b/turbo.json @@ -102,7 +102,7 @@ "cache": false, "persistent": true }, - "dev:portless": { + "dev:worktree": { "description": "Starts dev servers with worktree-scoped portless hostnames for git worktree isolation", "dependsOn": ["^build"], "cache": false,