From 3b99acd01304ce25ceceb4cfe240f097c8bef521 Mon Sep 17 00:00:00 2001 From: SandipBajracharya Date: Mon, 13 Apr 2026 18:49:36 +0545 Subject: [PATCH 1/7] test(OUT-3546): set up Vitest integration project with testcontainers Postgres Adds a reusable integration-test harness that spins up an ephemeral Postgres via testcontainers, applies Drizzle migrations, and wires it to the Next.js route handlers through next-test-api-route-handler. The harness is split from the existing unit project via Vitest `projects` so unit tests keep running fast without Docker. Key pieces: - globalSetup.ts starts the container, sets DATABASE_URL, runs migrations - setup.ts provides shared module mocks (CopilotAPI, IntuitAPI, Sentry) that avoid loading copilot-node-sdk's broken ESM directory import - helpers/{testDb,seed,mocks}.ts expose truncate + seed + mock-install utilities - .env.test holds non-secret stubs for src/config env vars - Integration project runs single-fork, no file parallelism, shares the container across files (TRUNCATE between tests) Co-Authored-By: Claude Opus 4.6 (1M context) --- .env.test | 32 + .gitignore | 5 +- package.json | 3 + test/fixtures/priceCreated.webhook.json | 17 + test/helpers/mocks.ts | 109 ++ test/helpers/seed.ts | 81 ++ test/helpers/testDb.ts | 26 + test/integration/globalSetup.ts | 64 + test/integration/setup.ts | 39 + vitest.config.ts | 49 +- yarn.lock | 1423 +++++++++++++++++++---- 11 files changed, 1634 insertions(+), 214 deletions(-) create mode 100644 .env.test create mode 100644 test/fixtures/priceCreated.webhook.json create mode 100644 test/helpers/mocks.ts create mode 100644 test/helpers/seed.ts create mode 100644 test/helpers/testDb.ts create mode 100644 test/integration/globalSetup.ts create mode 100644 test/integration/setup.ts diff --git a/.env.test b/.env.test new file mode 100644 index 00000000..010f8a22 --- /dev/null +++ b/.env.test @@ -0,0 +1,32 @@ +# Test-only environment variables. +# +# Loaded by test/integration/globalSetup.ts BEFORE the testcontainer Postgres +# is started. DATABASE_URL is intentionally NOT set here — globalSetup sets it +# dynamically to the container's connection URI. +# +# Everything in this file should be a non-secret stub. No real credentials. + +# Copilot +COPILOT_API_KEY=test-copilot-api-key +NEXT_PUBLIC_COPILOT_APP_API_KEY=test-copilot-app-key +NEXT_PUBLIC_COPILOT_DASHBOARD_URL=https://test.copilot.local +COPILOT_ENV=test + +# Intuit / QuickBooks +INTUIT_CLIENT_ID=test-intuit-client-id +INTUIT_CLIENT_SECRET=test-intuit-client-secret +INTUIT_REDIRECT_URI_PATH=/api/quickbooks/auth/callback +INTUIT_ENVIRONMENT=sandbox +INTUIT_SANDBOX_API_URL=https://sandbox-quickbooks.api.intuit.com +INTUIT_PRODUCTION_API_URL=https://quickbooks.api.intuit.com +INTUIT_API_MINOR_VERSION=75 + +# Supabase (stubs — tests don't hit Supabase) +NEXT_PUBLIC_SUPABASE_PROJECT_URL=https://test.supabase.local +NEXT_PUBLIC_SUPABASE_ANON_KEY=test-anon-key + +# Cron +CRON_SECRET=test-cron-secret + +# Vercel / Next +VERCEL_URL=localhost:3000 diff --git a/.gitignore b/.gitignore index 5211169f..be7263d6 100644 --- a/.gitignore +++ b/.gitignore @@ -41,4 +41,7 @@ yarn-error.log* *.tsbuildinfo next-env.d.ts -.trigger \ No newline at end of file +.trigger + +# local decision notes (not published) +/docs diff --git a/package.json b/package.json index fe754316..28ef7831 100644 --- a/package.json +++ b/package.json @@ -63,6 +63,7 @@ "@ngrok/ngrok": "^1.4.1", "@sentry/esbuild-plugin": "^4.6.1", "@tailwindcss/postcss": "^4.1.5", + "@testcontainers/postgresql": "^11.14.0", "@trigger.dev/build": "4.4.4", "@types/deep-equal": "^1.0.4", "@types/html-to-text": "^9", @@ -80,9 +81,11 @@ "eslint-plugin-prettier": "^5.2.6", "husky": "^9.1.7", "lint-staged": "^15.5.1", + "next-test-api-route-handler": "^5.0.4", "postcss": "^8.5.3", "prettier": "^3.5.3", "tailwindcss": "^4.1.5", + "testcontainers": "^11.14.0", "tsx": "^4.21.0", "typescript": "^5.8.3", "vitest": "^4.1.3" diff --git a/test/fixtures/priceCreated.webhook.json b/test/fixtures/priceCreated.webhook.json new file mode 100644 index 00000000..841d3588 --- /dev/null +++ b/test/fixtures/priceCreated.webhook.json @@ -0,0 +1,17 @@ +{ + "eventType": "price.created", + "created": "2024-09-11T13:59:58.845233992Z", + "object": "price", + "data": { + "id": "C-wch-eSg", + "createdAt": "2024-09-11T13:59:58.845233992Z", + "object": "price", + "amount": 60000, + "currency": "usd", + "interval": "month", + "intervalCount": 3, + "productId": "2cf93cf0-45fa-485f-b584-03c2c38a3999", + "type": "recurring", + "updatedAt": "2024-09-11T13:59:58.845233992Z" + } +} diff --git a/test/helpers/mocks.ts b/test/helpers/mocks.ts new file mode 100644 index 00000000..f6f3ab60 --- /dev/null +++ b/test/helpers/mocks.ts @@ -0,0 +1,109 @@ +import { vi, type Mock } from 'vitest' +import { CopilotAPI } from '@/utils/copilotAPI' +import IntuitAPI from '@/utils/intuitAPI' +import { + TEST_INCOME_ACCOUNT_REF, + TEST_INTERNAL_USER_ID, + TEST_PORTAL_ID, +} from './seed' + +/** + * Factory for a mocked CopilotAPI instance. + * + * Tests mock the CopilotAPI module with `vi.mock('@/utils/copilotAPI')`, then + * wire each `new CopilotAPI(token)` call to an object produced by this factory. + * Override any method via the `overrides` arg to tailor behavior per test. + */ +export function createMockCopilotAPI( + overrides: Partial> = {}, +) { + return { + getTokenPayload: vi.fn().mockResolvedValue({ + workspaceId: TEST_PORTAL_ID, + internalUserId: TEST_INTERNAL_USER_ID, + }), + getProduct: vi.fn().mockResolvedValue({ + id: '2cf93cf0-45fa-485f-b584-03c2c38a3999', + name: 'Test Product', + description: 'Test product description', + status: 'active', + createdAt: '2024-09-11T13:59:58.845233992Z', + updatedAt: '2024-09-11T13:59:58.845233992Z', + }), + ...overrides, + } +} + +/** + * Factory for a mocked IntuitAPI instance. + * + * Defaults represent the happy path for `price.created`: + * - getAnItem returns undefined (no existing item in QB) + * - getAnAccount returns an active income account matching the seeded ref + * - createItem returns a freshly-created QB item + */ +export function createMockIntuitAPI( + overrides: Partial> = {}, +) { + return { + getAnItem: vi.fn().mockResolvedValue(undefined), + getAnAccount: vi.fn().mockResolvedValue({ + Id: TEST_INCOME_ACCOUNT_REF, + Name: 'Sales of Product Income', + SyncToken: '0', + Active: true, + AccountType: 'Income', + }), + createItem: vi.fn().mockResolvedValue({ + Id: '999', + Name: 'Test Product', + SyncToken: '0', + UnitPrice: 600, + }), + ...overrides, + } +} + +export type MockCopilotAPI = ReturnType +export type MockIntuitAPI = ReturnType + +/** + * Wires the module-mocked CopilotAPI + IntuitAPI to return shared instances + * for the duration of a test. Pass pre-built instances (e.g., with overrides) + * or accept the defaults. + * + * Returns the instances so tests can assert on call counts / arguments. + * + * Must use `function` (not arrow) so the mock is callable with `new`. + * + * CAVEAT — shared instance across multiple `new` sites: + * The price.created flow constructs `new CopilotAPI(...)` TWICE per request — + * once in `authenticate()` (calls `.getTokenPayload()`) and once in + * `webhookPriceCreated` (calls `.getProduct()`). Both sites receive the SAME + * `copilot` mock object returned here. This is fine when asserting on + * different methods (e.g., `getProduct` only fires from the service call), + * but be careful with shared methods: `toHaveBeenCalledTimes(1)` on a method + * both sites touch would reflect the sum of both call sites. Same applies to + * IntuitAPI if/when it gets instantiated more than once per request. + */ +export function installMockApis(opts: { + copilot?: MockCopilotAPI + intuit?: MockIntuitAPI +} = {}): { copilot: MockCopilotAPI; intuit: MockIntuitAPI } { + const copilot = opts.copilot ?? createMockCopilotAPI() + const intuit = opts.intuit ?? createMockIntuitAPI() + + vi.mocked(CopilotAPI).mockImplementation(function ( + this: unknown, + ): CopilotAPI { + return copilot as unknown as CopilotAPI + } as unknown as typeof CopilotAPI) + + vi.mocked(IntuitAPI).mockImplementation(function ( + this: unknown, + ): IntuitAPI { + return intuit as unknown as IntuitAPI + } as unknown as typeof IntuitAPI) + + return { copilot, intuit } +} diff --git a/test/helpers/seed.ts b/test/helpers/seed.ts new file mode 100644 index 00000000..d7a77c95 --- /dev/null +++ b/test/helpers/seed.ts @@ -0,0 +1,81 @@ +import type { z } from 'zod' +import { db } from '@/db' +import { + QBPortalConnection, + QBPortalConnectionCreateSchema, +} from '@/db/schema/qbPortalConnections' +import { + QBSetting, + QBSettingCreateSchema, +} from '@/db/schema/qbSettings' + +export const TEST_PORTAL_ID = 'test-portal-00000001' +export const TEST_REALM_ID = 'test-realm-123' +export const TEST_ACCESS_TOKEN = 'test-access-token' +export const TEST_REFRESH_TOKEN = 'test-refresh-token' +export const TEST_INCOME_ACCOUNT_REF = '100' +export const TEST_ASSET_ACCOUNT_REF = '101' +export const TEST_EXPENSE_ACCOUNT_REF = '102' +export const TEST_INTERNAL_USER_ID = 'test-internal-user-id' + +// Override types are derived from the Drizzle-generated insert schemas so +// they stay in sync with the DB schema automatically. Using `Partial` +// would widen primitives (e.g., `true` → `boolean`) but wouldn't track column +// type changes in the underlying schema. +type PortalOverrides = Partial> +type SettingOverrides = Partial> + +const basePortalConnection: z.infer = { + portalId: TEST_PORTAL_ID, + intuitRealmId: TEST_REALM_ID, + accessToken: TEST_ACCESS_TOKEN, + refreshToken: TEST_REFRESH_TOKEN, + expiresIn: 3600, + XRefreshTokenExpiresIn: 8_726_400, + intiatedBy: TEST_INTERNAL_USER_ID, + incomeAccountRef: TEST_INCOME_ACCOUNT_REF, + assetAccountRef: TEST_ASSET_ACCOUNT_REF, + expenseAccountRef: TEST_EXPENSE_ACCOUNT_REF, +} + +const baseSetting: z.infer = { + portalId: TEST_PORTAL_ID, + absorbedFeeFlag: false, + useCompanyNameFlag: false, + createNewProductFlag: true, + initialInvoiceSettingMap: true, + initialProductSettingMap: true, + syncFlag: true, + isEnabled: true, +} + +export async function seedPortalConnection(overrides: PortalOverrides = {}) { + const [row] = await db + .insert(QBPortalConnection) + .values({ ...basePortalConnection, ...overrides }) + .returning() + return row +} + +export async function seedSetting(overrides: SettingOverrides = {}) { + const [row] = await db + .insert(QBSetting) + .values({ ...baseSetting, ...overrides }) + .returning() + return row +} + +/** + * Convenience seeder for the common "healthy portal" fixture used by + * most tests. Returns both rows for assertions if needed. + */ +export async function seedHealthyPortal( + opts: { + portal?: PortalOverrides + setting?: SettingOverrides + } = {}, +) { + const portal = await seedPortalConnection(opts.portal) + const setting = await seedSetting(opts.setting) + return { portal, setting } +} diff --git a/test/helpers/testDb.ts b/test/helpers/testDb.ts new file mode 100644 index 00000000..d6d88645 --- /dev/null +++ b/test/helpers/testDb.ts @@ -0,0 +1,26 @@ +import { sql } from 'drizzle-orm' +import { db } from '@/db' + +/** + * Wipes every table in the schema that integration tests can touch. Call in + * `beforeEach` — the testcontainer Postgres is shared across the full + * integration run, so cross-test contamination is a real risk. + * + * If a new table is added to `src/db/schema/*.ts`, add it here too. The + * consequence of forgetting is silent cross-test contamination — tests pass + * in isolation but fail in full-suite runs depending on file order. + */ +export async function truncateAllTestTables() { + await db.execute(sql` + TRUNCATE TABLE + qb_sync_logs, + qb_connection_logs, + qb_customers, + qb_invoice_sync, + qb_payment_sync, + qb_product_sync, + qb_settings, + qb_portal_connections + RESTART IDENTITY CASCADE + `) +} diff --git a/test/integration/globalSetup.ts b/test/integration/globalSetup.ts new file mode 100644 index 00000000..22cd1d5d --- /dev/null +++ b/test/integration/globalSetup.ts @@ -0,0 +1,64 @@ +import path from 'node:path' +import { fileURLToPath } from 'node:url' +import dotenv from 'dotenv' +import { + PostgreSqlContainer, + StartedPostgreSqlContainer, +} from '@testcontainers/postgresql' +import { drizzle } from 'drizzle-orm/postgres-js' +import { migrate } from 'drizzle-orm/postgres-js/migrator' +import postgres from 'postgres' + +/** + * Vitest globalSetup for integration tests. + * + * Responsibilities: + * - Start an ephemeral Postgres container via testcontainers + * - Set process.env.DATABASE_URL before any test worker imports src/config + * - Apply all Drizzle migrations from src/db/migrations to the fresh DB + * - Stub any src/config env vars that must be non-empty at import time + * - Stop the container on teardown + * + * Env var propagation: Vitest spawns worker processes AFTER globalSetup resolves, + * so process.env set here is inherited by workers. Combined with singleFork=true + * in vitest.config.ts, this gives us one container shared across all integration + * test files. + */ + +const __dirname = path.dirname(fileURLToPath(import.meta.url)) +const MIGRATIONS_FOLDER = path.resolve(__dirname, '../../src/db/migrations') +const ENV_TEST_FILE = path.resolve(__dirname, '../../.env.test') + +let container: StartedPostgreSqlContainer | undefined + +export default async function globalSetup() { + // Load .env.test into process.env BEFORE anything else. `override: true` + // ensures the developer's local `.env` doesn't leak into test runs. + // DATABASE_URL is intentionally not in .env.test — we set it below from the + // testcontainer's dynamic connection URI. + dotenv.config({ path: ENV_TEST_FILE, override: true }) + + console.info('[globalSetup] Starting Postgres test container...') + + container = await new PostgreSqlContainer('postgres:16-alpine') + .withDatabase('test_db') + .withUsername('test_user') + .withPassword('test_pass') + .start() + + const url = container.getConnectionUri() + process.env.DATABASE_URL = url + + console.info('[globalSetup] Running Drizzle migrations...') + const migrationClient = postgres(url, { max: 1, prepare: false }) + const migrationDb = drizzle(migrationClient) + await migrate(migrationDb, { migrationsFolder: MIGRATIONS_FOLDER }) + await migrationClient.end() + + console.info(`[globalSetup] Ready: ${url}`) + + return async () => { + console.info('[globalSetup] Stopping Postgres test container...') + await container?.stop() + } +} diff --git a/test/integration/setup.ts b/test/integration/setup.ts new file mode 100644 index 00000000..0be864e1 --- /dev/null +++ b/test/integration/setup.ts @@ -0,0 +1,39 @@ +import { vi } from 'vitest' + +/** + * Shared module mocks for all integration tests. + * + * Loaded via `setupFiles` in vitest.config.ts (integration project). Each + * test file still configures per-test behavior in beforeEach via + * `vi.mocked(CopilotAPI).mockImplementation(...)`. + * + * Why here instead of per-file: + * - Explicit factory for CopilotAPI/IntuitAPI avoids evaluating the real + * modules (copilot-node-sdk has an ESM directory-import that breaks). + * - Sentry has to be stubbed because withRetry.ts calls + * `scope.addEventProcessor(...)` inside Sentry.withScope. + */ + +vi.mock('@/utils/copilotAPI', () => ({ + CopilotAPI: vi.fn(), +})) + +vi.mock('@/utils/intuitAPI', () => ({ + default: vi.fn(), + // Named export used by src/utils/error.ts to detect Intuit-sourced APIErrors + // when unwrapping error messages in the webhook catch block. + IntuitAPIErrorMessage: '#IntuitAPIErrorMessage#', +})) + +vi.mock('@sentry/nextjs', () => ({ + withScope: vi.fn((cb: (scope: unknown) => void) => + cb({ + setTag: vi.fn(), + setExtra: vi.fn(), + addEventProcessor: vi.fn(), + }), + ), + captureException: vi.fn(), + captureMessage: vi.fn(), + init: vi.fn(), +})) diff --git a/vitest.config.ts b/vitest.config.ts index f2ce0f32..deb97a37 100644 --- a/vitest.config.ts +++ b/vitest.config.ts @@ -1,12 +1,10 @@ import { defineConfig } from 'vitest/config' +// Note: `resolve.tsconfigPaths` is configured per-project below. When +// `projects` is defined, the root-level `resolve` block is ignored by Vitest, +// so duplicating it here would be dead config. export default defineConfig({ - resolve: { - tsconfigPaths: true, - }, test: { - environment: 'node', - include: ['test/**/*.test.ts'], coverage: { provider: 'v8', reporter: ['text', 'lcov'], @@ -18,5 +16,46 @@ export default defineConfig({ 'src/components/**', ], }, + projects: [ + { + resolve: { + tsconfigPaths: true, + }, + test: { + name: 'unit', + environment: 'node', + include: ['test/unit/**/*.test.ts'], + sequence: { + // Run unit tests before integration tests when both projects run. + groupOrder: 0, + }, + }, + }, + { + resolve: { + tsconfigPaths: true, + }, + test: { + name: 'integration', + environment: 'node', + include: ['test/integration/**/*.test.ts'], + globalSetup: ['./test/integration/globalSetup.ts'], + setupFiles: ['./test/integration/setup.ts'], + testTimeout: 30_000, + hookTimeout: 120_000, + // One worker so the container URL set in globalSetup is inherited + // and all integration tests share a single DB container. + pool: 'forks', + // Disable parallel execution so separate test files can't collide + // on the shared test DB (e.g., concurrent inserts to qb_portal_connections). + fileParallelism: false, + isolate: false, + sequence: { + // Run integration tests after unit tests when both projects run. + groupOrder: 1, + }, + }, + }, + ], }, }) diff --git a/yarn.lock b/yarn.lock index 2277a3b1..f461a7c9 100644 --- a/yarn.lock +++ b/yarn.lock @@ -336,6 +336,13 @@ __metadata: languageName: node linkType: hard +"@balena/dockerignore@npm:^1.0.2": + version: 1.0.2 + resolution: "@balena/dockerignore@npm:1.0.2" + checksum: 10c0/0bcb067e86f6734ab943ce4ce9a7c8611f2e983a70bccebf9d2309db57695c09dded7faf5be49c929c4c9e9a9174ae55fc625626de0fb9958823c37423d12f4e + languageName: node + linkType: hard + "@bcoe/v8-coverage@npm:^1.0.2": version: 1.0.2 resolution: "@bcoe/v8-coverage@npm:1.0.2" @@ -388,13 +395,13 @@ __metadata: languageName: node linkType: hard -"@emnapi/core@npm:1.9.2": - version: 1.9.2 - resolution: "@emnapi/core@npm:1.9.2" +"@emnapi/core@npm:1.9.1": + version: 1.9.1 + resolution: "@emnapi/core@npm:1.9.1" dependencies: - "@emnapi/wasi-threads": "npm:1.2.1" + "@emnapi/wasi-threads": "npm:1.2.0" tslib: "npm:^2.4.0" - checksum: 10c0/5500393f953951bad0768fafaa9191f2d938956b20c6d6a79e5ab696a613a25ce6ad23422bc18e86e6ce8deb147619d8d0d7d413a69f84adc01a6633cc353cd9 + checksum: 10c0/00e7a99a2bc3ad908ca8272ba861a934da87dffa8797a41316c4a3b571a1e4d2743e2fa14b1a0f131fa4a3c2018ddb601cd2a8cb7f574fa940af696df3c2fe8d languageName: node linkType: hard @@ -408,12 +415,12 @@ __metadata: languageName: node linkType: hard -"@emnapi/runtime@npm:1.9.2": - version: 1.9.2 - resolution: "@emnapi/runtime@npm:1.9.2" +"@emnapi/runtime@npm:1.9.1, @emnapi/runtime@npm:^1.7.0": + version: 1.9.1 + resolution: "@emnapi/runtime@npm:1.9.1" dependencies: tslib: "npm:^2.4.0" - checksum: 10c0/61c3a59e0c36784558b8d58eb02bd04815aa5fb0dbfbaf84d1b3050a78aa0cc63ea129ae806bd1e48062bfeb7fc36eb0e5431740d62f64ea51bdf426404b8caa + checksum: 10c0/750edca117e0363ab2de10622f8ee60e57d8690c2f29c49704813da5cd627c641798d7f3cb0d953c62fdc71688e02e333ddbf2c1204f38b47e3e40657332a6f5 languageName: node linkType: hard @@ -426,15 +433,6 @@ __metadata: languageName: node linkType: hard -"@emnapi/runtime@npm:^1.7.0": - version: 1.9.1 - resolution: "@emnapi/runtime@npm:1.9.1" - dependencies: - tslib: "npm:^2.4.0" - checksum: 10c0/750edca117e0363ab2de10622f8ee60e57d8690c2f29c49704813da5cd627c641798d7f3cb0d953c62fdc71688e02e333ddbf2c1204f38b47e3e40657332a6f5 - languageName: node - linkType: hard - "@emnapi/wasi-threads@npm:1.0.2, @emnapi/wasi-threads@npm:^1.0.2": version: 1.0.2 resolution: "@emnapi/wasi-threads@npm:1.0.2" @@ -444,12 +442,12 @@ __metadata: languageName: node linkType: hard -"@emnapi/wasi-threads@npm:1.2.1": - version: 1.2.1 - resolution: "@emnapi/wasi-threads@npm:1.2.1" +"@emnapi/wasi-threads@npm:1.2.0": + version: 1.2.0 + resolution: "@emnapi/wasi-threads@npm:1.2.0" dependencies: tslib: "npm:^2.4.0" - checksum: 10c0/32fcfa81ab396533b2ec1f4082b1ff779a05d9c836bbbd3f4398405b0e6814c0d9503b7993130e37bc6941dbc1ded49f55e9700ae9ca4e803bab2b5bc5deb331 + checksum: 10c0/1e3724b5814b06c14782fda87eee9b9aa68af01576c81ffeaefdf621ddb74386e419d5b3b1027b6a8172397729d95a92f814fc4b8d3c224376428faa07a6a01a languageName: node linkType: hard @@ -593,6 +591,16 @@ __metadata: languageName: node linkType: hard +"@envelop/instrumentation@npm:^1.0.0": + version: 1.0.0 + resolution: "@envelop/instrumentation@npm:1.0.0" + dependencies: + "@whatwg-node/promise-helpers": "npm:^1.2.1" + tslib: "npm:^2.5.0" + checksum: 10c0/134df1ac481fb392aafc4522a22bcdc6ef0701f2d15d51b16207f3c9a4c7d3760adfa5f5bcc84f0c0ec7b011d84bcd40fff671eb471bed54bd928c165994b4e3 + languageName: node + linkType: hard + "@esbuild-kit/core-utils@npm:^3.3.2": version: 3.3.2 resolution: "@esbuild-kit/core-utils@npm:3.3.2" @@ -1237,6 +1245,13 @@ __metadata: languageName: node linkType: hard +"@fastify/busboy@npm:^3.1.1": + version: 3.2.0 + resolution: "@fastify/busboy@npm:3.2.0" + checksum: 10c0/3e4fb00a27e3149d1c68de8ff14007d2bbcbbc171a9d050d0a8772e836727329d4d3f130995ebaa19cf537d5d2f5ce2a88000366e6192e751457bfcc2125f351 + languageName: node + linkType: hard + "@floating-ui/core@npm:^1.6.0": version: 1.6.9 resolution: "@floating-ui/core@npm:1.6.9" @@ -1270,6 +1285,44 @@ __metadata: languageName: node linkType: hard +"@grpc/grpc-js@npm:^1.11.1": + version: 1.14.3 + resolution: "@grpc/grpc-js@npm:1.14.3" + dependencies: + "@grpc/proto-loader": "npm:^0.8.0" + "@js-sdsl/ordered-map": "npm:^4.4.2" + checksum: 10c0/f41f06a311b93cca8c472d56e21387e0f7b57bb2337a91d15ea4279bac8ec4fa0de6bd0d881201229ab800c0f0c55277911ecb850e057f20a828d0ddd623551d + languageName: node + linkType: hard + +"@grpc/proto-loader@npm:^0.7.13": + version: 0.7.15 + resolution: "@grpc/proto-loader@npm:0.7.15" + dependencies: + lodash.camelcase: "npm:^4.3.0" + long: "npm:^5.0.0" + protobufjs: "npm:^7.2.5" + yargs: "npm:^17.7.2" + bin: + proto-loader-gen-types: build/bin/proto-loader-gen-types.js + checksum: 10c0/514a134a724b56d73d0a202b7e02c84479da21e364547bacb2f4995ebc0d52412a1a21653add9f004ebd146c1e6eb4bcb0b8846fdfe1bfa8a98ed8f3d203da4a + languageName: node + linkType: hard + +"@grpc/proto-loader@npm:^0.8.0": + version: 0.8.0 + resolution: "@grpc/proto-loader@npm:0.8.0" + dependencies: + lodash.camelcase: "npm:^4.3.0" + long: "npm:^5.0.0" + protobufjs: "npm:^7.5.3" + yargs: "npm:^17.7.2" + bin: + proto-loader-gen-types: build/bin/proto-loader-gen-types.js + checksum: 10c0/a27da3b85d5d17bab956d536786c717287eae46ca264ea9ec774db90ff571955bae2705809f431b4622fbf3be9951d7c7bbb1360b2015ee88abe1587cf3d6fe0 + languageName: node + linkType: hard + "@humanfs/core@npm:^0.19.1": version: 0.19.1 resolution: "@humanfs/core@npm:0.19.1" @@ -1624,6 +1677,13 @@ __metadata: languageName: node linkType: hard +"@js-sdsl/ordered-map@npm:^4.4.2": + version: 4.4.2 + resolution: "@js-sdsl/ordered-map@npm:4.4.2" + checksum: 10c0/cc7e15dc4acf6d9ef663757279600bab70533d847dcc1ab01332e9e680bd30b77cdf9ad885cc774276f51d98b05a013571c940e5b360985af5eb798dc1a2ee2b + languageName: node + linkType: hard + "@jsonhero/path@npm:^1.0.21": version: 1.0.21 resolution: "@jsonhero/path@npm:1.0.21" @@ -1631,6 +1691,15 @@ __metadata: languageName: node linkType: hard +"@kwsites/file-exists@npm:^1.1.1": + version: 1.1.1 + resolution: "@kwsites/file-exists@npm:1.1.1" + dependencies: + debug: "npm:^4.1.1" + checksum: 10c0/39e693239a72ccd8408bb618a0200e4a8d61682057ca7ae2c87668d7e69196e8d7e2c9cde73db6b23b3b0230169a15e5f1bfe086539f4be43e767b2db68e8ee4 + languageName: node + linkType: hard + "@microsoft/fetch-event-source@npm:^2.0.1": version: 2.0.1 resolution: "@microsoft/fetch-event-source@npm:2.0.1" @@ -1649,15 +1718,15 @@ __metadata: languageName: node linkType: hard -"@napi-rs/wasm-runtime@npm:^1.1.3": - version: 1.1.4 - resolution: "@napi-rs/wasm-runtime@npm:1.1.4" +"@napi-rs/wasm-runtime@npm:^1.1.2": + version: 1.1.3 + resolution: "@napi-rs/wasm-runtime@npm:1.1.3" dependencies: "@tybys/wasm-util": "npm:^0.10.1" peerDependencies: "@emnapi/core": ^1.7.1 "@emnapi/runtime": ^1.7.1 - checksum: 10c0/2e88e1955258949ccf2d18c79975821ad38071b465ef126a5e14110977b97868867b016c1ad046e963cccc42c0bd9db6c8ff5fd1ebb61b87bb3487f339041658 + checksum: 10c0/745bb32a023b95095a18d93658bf4564403c2283ca0500a043afcf566ac6082bd0611792f14636276bab07dc2ce6d862591c8aabddae02ec697245b05bc6f144 languageName: node linkType: hard @@ -2596,10 +2665,10 @@ __metadata: languageName: node linkType: hard -"@oxc-project/types@npm:=0.124.0": - version: 0.124.0 - resolution: "@oxc-project/types@npm:0.124.0" - checksum: 10c0/9564ee3ce41f4b87802ffd0d62a7602d27f4503fbd39c1bedab98d54fde06e2ac254a8f85d8f679af1281a26e8fc7aa053fadbb3e09e786b38178eb38a8e2fb3 +"@oxc-project/types@npm:=0.123.0": + version: 0.123.0 + resolution: "@oxc-project/types@npm:0.123.0" + checksum: 10c0/7f71f9fa38796e6e5431390c213ec9626a3972feec07b513c513828bbfba5f6d908b04e8c679ae2b30b49cc1dee2dc0b2f1012f38ed1cb9e54bfeba09119f36d languageName: node linkType: hard @@ -3031,119 +3100,119 @@ __metadata: languageName: node linkType: hard -"@rolldown/binding-android-arm64@npm:1.0.0-rc.15": - version: 1.0.0-rc.15 - resolution: "@rolldown/binding-android-arm64@npm:1.0.0-rc.15" +"@rolldown/binding-android-arm64@npm:1.0.0-rc.13": + version: 1.0.0-rc.13 + resolution: "@rolldown/binding-android-arm64@npm:1.0.0-rc.13" conditions: os=android & cpu=arm64 languageName: node linkType: hard -"@rolldown/binding-darwin-arm64@npm:1.0.0-rc.15": - version: 1.0.0-rc.15 - resolution: "@rolldown/binding-darwin-arm64@npm:1.0.0-rc.15" +"@rolldown/binding-darwin-arm64@npm:1.0.0-rc.13": + version: 1.0.0-rc.13 + resolution: "@rolldown/binding-darwin-arm64@npm:1.0.0-rc.13" conditions: os=darwin & cpu=arm64 languageName: node linkType: hard -"@rolldown/binding-darwin-x64@npm:1.0.0-rc.15": - version: 1.0.0-rc.15 - resolution: "@rolldown/binding-darwin-x64@npm:1.0.0-rc.15" +"@rolldown/binding-darwin-x64@npm:1.0.0-rc.13": + version: 1.0.0-rc.13 + resolution: "@rolldown/binding-darwin-x64@npm:1.0.0-rc.13" conditions: os=darwin & cpu=x64 languageName: node linkType: hard -"@rolldown/binding-freebsd-x64@npm:1.0.0-rc.15": - version: 1.0.0-rc.15 - resolution: "@rolldown/binding-freebsd-x64@npm:1.0.0-rc.15" +"@rolldown/binding-freebsd-x64@npm:1.0.0-rc.13": + version: 1.0.0-rc.13 + resolution: "@rolldown/binding-freebsd-x64@npm:1.0.0-rc.13" conditions: os=freebsd & cpu=x64 languageName: node linkType: hard -"@rolldown/binding-linux-arm-gnueabihf@npm:1.0.0-rc.15": - version: 1.0.0-rc.15 - resolution: "@rolldown/binding-linux-arm-gnueabihf@npm:1.0.0-rc.15" +"@rolldown/binding-linux-arm-gnueabihf@npm:1.0.0-rc.13": + version: 1.0.0-rc.13 + resolution: "@rolldown/binding-linux-arm-gnueabihf@npm:1.0.0-rc.13" conditions: os=linux & cpu=arm languageName: node linkType: hard -"@rolldown/binding-linux-arm64-gnu@npm:1.0.0-rc.15": - version: 1.0.0-rc.15 - resolution: "@rolldown/binding-linux-arm64-gnu@npm:1.0.0-rc.15" +"@rolldown/binding-linux-arm64-gnu@npm:1.0.0-rc.13": + version: 1.0.0-rc.13 + resolution: "@rolldown/binding-linux-arm64-gnu@npm:1.0.0-rc.13" conditions: os=linux & cpu=arm64 & libc=glibc languageName: node linkType: hard -"@rolldown/binding-linux-arm64-musl@npm:1.0.0-rc.15": - version: 1.0.0-rc.15 - resolution: "@rolldown/binding-linux-arm64-musl@npm:1.0.0-rc.15" +"@rolldown/binding-linux-arm64-musl@npm:1.0.0-rc.13": + version: 1.0.0-rc.13 + resolution: "@rolldown/binding-linux-arm64-musl@npm:1.0.0-rc.13" conditions: os=linux & cpu=arm64 & libc=musl languageName: node linkType: hard -"@rolldown/binding-linux-ppc64-gnu@npm:1.0.0-rc.15": - version: 1.0.0-rc.15 - resolution: "@rolldown/binding-linux-ppc64-gnu@npm:1.0.0-rc.15" +"@rolldown/binding-linux-ppc64-gnu@npm:1.0.0-rc.13": + version: 1.0.0-rc.13 + resolution: "@rolldown/binding-linux-ppc64-gnu@npm:1.0.0-rc.13" conditions: os=linux & cpu=ppc64 & libc=glibc languageName: node linkType: hard -"@rolldown/binding-linux-s390x-gnu@npm:1.0.0-rc.15": - version: 1.0.0-rc.15 - resolution: "@rolldown/binding-linux-s390x-gnu@npm:1.0.0-rc.15" +"@rolldown/binding-linux-s390x-gnu@npm:1.0.0-rc.13": + version: 1.0.0-rc.13 + resolution: "@rolldown/binding-linux-s390x-gnu@npm:1.0.0-rc.13" conditions: os=linux & cpu=s390x & libc=glibc languageName: node linkType: hard -"@rolldown/binding-linux-x64-gnu@npm:1.0.0-rc.15": - version: 1.0.0-rc.15 - resolution: "@rolldown/binding-linux-x64-gnu@npm:1.0.0-rc.15" +"@rolldown/binding-linux-x64-gnu@npm:1.0.0-rc.13": + version: 1.0.0-rc.13 + resolution: "@rolldown/binding-linux-x64-gnu@npm:1.0.0-rc.13" conditions: os=linux & cpu=x64 & libc=glibc languageName: node linkType: hard -"@rolldown/binding-linux-x64-musl@npm:1.0.0-rc.15": - version: 1.0.0-rc.15 - resolution: "@rolldown/binding-linux-x64-musl@npm:1.0.0-rc.15" +"@rolldown/binding-linux-x64-musl@npm:1.0.0-rc.13": + version: 1.0.0-rc.13 + resolution: "@rolldown/binding-linux-x64-musl@npm:1.0.0-rc.13" conditions: os=linux & cpu=x64 & libc=musl languageName: node linkType: hard -"@rolldown/binding-openharmony-arm64@npm:1.0.0-rc.15": - version: 1.0.0-rc.15 - resolution: "@rolldown/binding-openharmony-arm64@npm:1.0.0-rc.15" +"@rolldown/binding-openharmony-arm64@npm:1.0.0-rc.13": + version: 1.0.0-rc.13 + resolution: "@rolldown/binding-openharmony-arm64@npm:1.0.0-rc.13" conditions: os=openharmony & cpu=arm64 languageName: node linkType: hard -"@rolldown/binding-wasm32-wasi@npm:1.0.0-rc.15": - version: 1.0.0-rc.15 - resolution: "@rolldown/binding-wasm32-wasi@npm:1.0.0-rc.15" +"@rolldown/binding-wasm32-wasi@npm:1.0.0-rc.13": + version: 1.0.0-rc.13 + resolution: "@rolldown/binding-wasm32-wasi@npm:1.0.0-rc.13" dependencies: - "@emnapi/core": "npm:1.9.2" - "@emnapi/runtime": "npm:1.9.2" - "@napi-rs/wasm-runtime": "npm:^1.1.3" + "@emnapi/core": "npm:1.9.1" + "@emnapi/runtime": "npm:1.9.1" + "@napi-rs/wasm-runtime": "npm:^1.1.2" conditions: cpu=wasm32 languageName: node linkType: hard -"@rolldown/binding-win32-arm64-msvc@npm:1.0.0-rc.15": - version: 1.0.0-rc.15 - resolution: "@rolldown/binding-win32-arm64-msvc@npm:1.0.0-rc.15" +"@rolldown/binding-win32-arm64-msvc@npm:1.0.0-rc.13": + version: 1.0.0-rc.13 + resolution: "@rolldown/binding-win32-arm64-msvc@npm:1.0.0-rc.13" conditions: os=win32 & cpu=arm64 languageName: node linkType: hard -"@rolldown/binding-win32-x64-msvc@npm:1.0.0-rc.15": - version: 1.0.0-rc.15 - resolution: "@rolldown/binding-win32-x64-msvc@npm:1.0.0-rc.15" +"@rolldown/binding-win32-x64-msvc@npm:1.0.0-rc.13": + version: 1.0.0-rc.13 + resolution: "@rolldown/binding-win32-x64-msvc@npm:1.0.0-rc.13" conditions: os=win32 & cpu=x64 languageName: node linkType: hard -"@rolldown/pluginutils@npm:1.0.0-rc.15": - version: 1.0.0-rc.15 - resolution: "@rolldown/pluginutils@npm:1.0.0-rc.15" - checksum: 10c0/15eef6a65ee6b2d07405c16999c2333c40d8aeea60bbc35e04957992fe6477c7b278d3f02679688bb928ad2ef3fbd3a6149c116d7dc9928ebf8d1434a0591674 +"@rolldown/pluginutils@npm:1.0.0-rc.13": + version: 1.0.0-rc.13 + resolution: "@rolldown/pluginutils@npm:1.0.0-rc.13" + checksum: 10c0/5ba268706b43ca0c05eed50b16a077cc014453077f70f9cdc652180561c85b0477cf073053c166016a33182021e320335832e36d9bf51b8c79799c6433018d95 languageName: node linkType: hard @@ -4036,6 +4105,15 @@ __metadata: languageName: node linkType: hard +"@testcontainers/postgresql@npm:^11.14.0": + version: 11.14.0 + resolution: "@testcontainers/postgresql@npm:11.14.0" + dependencies: + testcontainers: "npm:^11.14.0" + checksum: 10c0/2841b2362e847224a2b4dc47b289d32a8df770e20b6cac097b0af0eae96db5e4448090d99591feadada309aa0cc6c17b6c103d801632e909ff8d0bc42800244d + languageName: node + linkType: hard + "@trigger.dev/build@npm:4.4.4": version: 4.4.4 resolution: "@trigger.dev/build@npm:4.4.4" @@ -4187,6 +4265,27 @@ __metadata: languageName: node linkType: hard +"@types/docker-modem@npm:*": + version: 3.0.6 + resolution: "@types/docker-modem@npm:3.0.6" + dependencies: + "@types/node": "npm:*" + "@types/ssh2": "npm:*" + checksum: 10c0/d3ffd273148bc883ff9b1a972b1f84c1add6d9a197d2f4fc9774db4c814f39c2e51cc649385b55d781c790c16fb0bf9c1f4c62499bd0f372a4b920190919445d + languageName: node + linkType: hard + +"@types/dockerode@npm:^4.0.1": + version: 4.0.1 + resolution: "@types/dockerode@npm:4.0.1" + dependencies: + "@types/docker-modem": "npm:*" + "@types/node": "npm:*" + "@types/ssh2": "npm:*" + checksum: 10c0/d504d5568624e629663633da9df4a88757d55548e399f2001c478bcdc55ee2e2a4c2fc8a903c4616ebe820a411e256ad5a5caa9c0fb244dca0a5dbc0eb333e45 + languageName: node + linkType: hard + "@types/estree@npm:*, @types/estree@npm:^1.0.0, @types/estree@npm:^1.0.6": version: 1.0.7 resolution: "@types/estree@npm:1.0.7" @@ -4258,6 +4357,15 @@ __metadata: languageName: node linkType: hard +"@types/node@npm:^18.11.18": + version: 18.19.130 + resolution: "@types/node@npm:18.19.130" + dependencies: + undici-types: "npm:~5.26.4" + checksum: 10c0/22ba2bc9f8863101a7e90a56aaeba1eb3ebdc51e847cef4a6d188967ab1acbce9b4f92251372fd0329ecb924bbf610509e122c3dfe346c04dbad04013d4ad7d0 + languageName: node + linkType: hard + "@types/parse-json@npm:^4.0.0": version: 4.0.2 resolution: "@types/parse-json@npm:4.0.2" @@ -4353,6 +4461,34 @@ __metadata: languageName: node linkType: hard +"@types/ssh2-streams@npm:*": + version: 0.1.13 + resolution: "@types/ssh2-streams@npm:0.1.13" + dependencies: + "@types/node": "npm:*" + checksum: 10c0/c0734417ae1d964bcc0681e4cd45f6d25d49e87c1eba54a934dc9a78c40bf76ba4935a414561b6dec5fe0c9c42fe7ad94ef79a4e1592940d934f9c75a704ebb0 + languageName: node + linkType: hard + +"@types/ssh2@npm:*": + version: 1.15.5 + resolution: "@types/ssh2@npm:1.15.5" + dependencies: + "@types/node": "npm:^18.11.18" + checksum: 10c0/750e402ce60d6dd67011bf1a811dcbbe638da14baca30c0952b50bad646c4ef8d6fc400894e20f5d2f8882e38b4c35eb6d4f5fe2ecd1d1b1a2f9efef9cf6e773 + languageName: node + linkType: hard + +"@types/ssh2@npm:^0.5.48": + version: 0.5.52 + resolution: "@types/ssh2@npm:0.5.52" + dependencies: + "@types/node": "npm:*" + "@types/ssh2-streams": "npm:*" + checksum: 10c0/95c52fd3438dedae6a59ca87b6558cb36568db6b9144c6c8a28c168739e04c51e27c02908aae14950b7b5020e1c40fea039b1203ae2734c356a40a050fd51c84 + languageName: node + linkType: hard + "@types/stylis@npm:4.2.5": version: 4.2.5 resolution: "@types/stylis@npm:4.2.5" @@ -4528,25 +4664,25 @@ __metadata: languageName: node linkType: hard -"@vitest/expect@npm:4.1.4": - version: 4.1.4 - resolution: "@vitest/expect@npm:4.1.4" +"@vitest/expect@npm:4.1.3": + version: 4.1.3 + resolution: "@vitest/expect@npm:4.1.3" dependencies: "@standard-schema/spec": "npm:^1.1.0" "@types/chai": "npm:^5.2.2" - "@vitest/spy": "npm:4.1.4" - "@vitest/utils": "npm:4.1.4" + "@vitest/spy": "npm:4.1.3" + "@vitest/utils": "npm:4.1.3" chai: "npm:^6.2.2" tinyrainbow: "npm:^3.1.0" - checksum: 10c0/99b53a931366ddc985f26528495ec991fa2ce64018b00a56f989c322553045c5adf17e091eb7a12d786246712f84d36fc88e9d26c852538ff4dd5a6f9cf98715 + checksum: 10c0/e5e27e22b8f6d7bd8e5f7a5c862a54a52c8933ae5420fab14843b0d24c8e6bd834523c30d75e5ea699717934093ac79d8fab5b6e7b451950cc6f2c0a58662598 languageName: node linkType: hard -"@vitest/mocker@npm:4.1.4": - version: 4.1.4 - resolution: "@vitest/mocker@npm:4.1.4" +"@vitest/mocker@npm:4.1.3": + version: 4.1.3 + resolution: "@vitest/mocker@npm:4.1.3" dependencies: - "@vitest/spy": "npm:4.1.4" + "@vitest/spy": "npm:4.1.3" estree-walker: "npm:^3.0.3" magic-string: "npm:^0.30.21" peerDependencies: @@ -4557,7 +4693,7 @@ __metadata: optional: true vite: optional: true - checksum: 10c0/da61ee63743da4bc45df0488c994e284e7059a4005149195744705945d19aeb267c801b1f7d85e71b40f547ff2d5a195175c5d51e8455179c794ce67a019de87 + checksum: 10c0/cbe54a931756b27c454bad5a174d9c5d5d7971e06c1e2d1f97d7c267db526741adfe4825f3c7bacddb6bd0d9a9675d3220e9986ec407ae606a1d8195cf2624a2 languageName: node linkType: hard @@ -4570,41 +4706,32 @@ __metadata: languageName: node linkType: hard -"@vitest/pretty-format@npm:4.1.4": - version: 4.1.4 - resolution: "@vitest/pretty-format@npm:4.1.4" - dependencies: - tinyrainbow: "npm:^3.1.0" - checksum: 10c0/14a25c5acd02b1d18f9fab01d884658edb9137008d01025273617fb000e36391e4fda1513e94a257f5e611fb09041a0c042d145a90d359c9e810c0044b12763e - languageName: node - linkType: hard - -"@vitest/runner@npm:4.1.4": - version: 4.1.4 - resolution: "@vitest/runner@npm:4.1.4" +"@vitest/runner@npm:4.1.3": + version: 4.1.3 + resolution: "@vitest/runner@npm:4.1.3" dependencies: - "@vitest/utils": "npm:4.1.4" + "@vitest/utils": "npm:4.1.3" pathe: "npm:^2.0.3" - checksum: 10c0/a942ecf2e50e4c380f0d269f87272353dc40fe354357e1ecd0c6568fd37202bb86e33db676f4ad6cc5f1ab30937bba0b278d987729b21a0f22e9827f7f577da2 + checksum: 10c0/41a507f138f0f14aa19869d3096e30a284270f11d39a79dd424c7f688a557bd4dd6b63d0225f9da2db47ef140b0019fec82eb87bfd6c755e817511b10ffbf3e6 languageName: node linkType: hard -"@vitest/snapshot@npm:4.1.4": - version: 4.1.4 - resolution: "@vitest/snapshot@npm:4.1.4" +"@vitest/snapshot@npm:4.1.3": + version: 4.1.3 + resolution: "@vitest/snapshot@npm:4.1.3" dependencies: - "@vitest/pretty-format": "npm:4.1.4" - "@vitest/utils": "npm:4.1.4" + "@vitest/pretty-format": "npm:4.1.3" + "@vitest/utils": "npm:4.1.3" magic-string: "npm:^0.30.21" pathe: "npm:^2.0.3" - checksum: 10c0/9221df7c097665a204c811184ac2f3b89638ecd115344e703e9c4361dabd2ba80be4710ed20d127817d34227a74f21b90725deaecd4632954b492ad258d4913f + checksum: 10c0/bc42c5f9e4d8fc226bd578b9679e55bc5473a96f2917db79c71015003604cbe17580d17c38361e41fbce25881ad6de0aaffe1f87a6c1e2fe37959afc44c4b754 languageName: node linkType: hard -"@vitest/spy@npm:4.1.4": - version: 4.1.4 - resolution: "@vitest/spy@npm:4.1.4" - checksum: 10c0/1036591947668845e45515d5b66b2095071609c243d2c987d650c71d0a27418e5de75a8b1ad44b7f45c5d97e71176640f0f49da94b32fb3d11e87cdd009bed26 +"@vitest/spy@npm:4.1.3": + version: 4.1.3 + resolution: "@vitest/spy@npm:4.1.3" + checksum: 10c0/aa3279c404fbb8befed0c7b797e385438b9850c2df1a462dcfccda57679dcabbdf2601fa753f46d58d72a6bee7023db65b7ab4521406489edf470367484c8b75 languageName: node linkType: hard @@ -4619,14 +4746,57 @@ __metadata: languageName: node linkType: hard -"@vitest/utils@npm:4.1.4": - version: 4.1.4 - resolution: "@vitest/utils@npm:4.1.4" +"@whatwg-node/disposablestack@npm:^0.0.6": + version: 0.0.6 + resolution: "@whatwg-node/disposablestack@npm:0.0.6" dependencies: - "@vitest/pretty-format": "npm:4.1.4" - convert-source-map: "npm:^2.0.0" - tinyrainbow: "npm:^3.1.0" - checksum: 10c0/7f81db08e5a8db1e83a37a8d64db011ae3a08b5bcc9aa220a6da428385acb75b11c77b169ab7a9f753529cc25ec11406cff6099b92711fda6291f844fb840a4e + "@whatwg-node/promise-helpers": "npm:^1.0.0" + tslib: "npm:^2.6.3" + checksum: 10c0/e751da9f8552728f28a140fd78c1da88be167ee8a5688371da88e024a2bf151298d194a61c9750b44bbbb4cf5c687959d495d41b1388e4cfcfe9dbe3584c79b3 + languageName: node + linkType: hard + +"@whatwg-node/fetch@npm:^0.10.13": + version: 0.10.13 + resolution: "@whatwg-node/fetch@npm:0.10.13" + dependencies: + "@whatwg-node/node-fetch": "npm:^0.8.3" + urlpattern-polyfill: "npm:^10.0.0" + checksum: 10c0/afce42c44e9c5572ac5800615bac3a03865923af53af99098d2e931b40f6db556ad5d4a3e08c29e51ecf871809f0860fb11f2b024891daa26646a309f8b07fc1 + languageName: node + linkType: hard + +"@whatwg-node/node-fetch@npm:^0.8.3": + version: 0.8.5 + resolution: "@whatwg-node/node-fetch@npm:0.8.5" + dependencies: + "@fastify/busboy": "npm:^3.1.1" + "@whatwg-node/disposablestack": "npm:^0.0.6" + "@whatwg-node/promise-helpers": "npm:^1.3.2" + tslib: "npm:^2.6.3" + checksum: 10c0/9f0d944476cc40f5cfed79057cff269ddacf52bd4dda36017fe922cbf3e0a98850f26cb9c4e7990e87e6097f2f9dd94a20c6cc11f95d57652a516e99a5ccafc2 + languageName: node + linkType: hard + +"@whatwg-node/promise-helpers@npm:^1.0.0, @whatwg-node/promise-helpers@npm:^1.2.1, @whatwg-node/promise-helpers@npm:^1.3.2": + version: 1.3.2 + resolution: "@whatwg-node/promise-helpers@npm:1.3.2" + dependencies: + tslib: "npm:^2.6.3" + checksum: 10c0/d20e8d740cfa1f0eac7dce11e8a7a84f1567513a8ff0bd1772724b581a8ca77df3f9600a95047c0d2628335626113fa98367517abd01c1ff49817fccf225a29a + languageName: node + linkType: hard + +"@whatwg-node/server@npm:^0.10.18": + version: 0.10.18 + resolution: "@whatwg-node/server@npm:0.10.18" + dependencies: + "@envelop/instrumentation": "npm:^1.0.0" + "@whatwg-node/disposablestack": "npm:^0.0.6" + "@whatwg-node/fetch": "npm:^0.10.13" + "@whatwg-node/promise-helpers": "npm:^1.3.2" + tslib: "npm:^2.6.3" + checksum: 10c0/794c4776c8cb432d2f607f5a36392bec59649bbee6aa116b52866555e4852f00378e92d80702c1aa67cf32abe147b3eb96a999b7352237d64126b6e7e33acc6c languageName: node linkType: hard @@ -4637,6 +4807,15 @@ __metadata: languageName: node linkType: hard +"abort-controller@npm:^3.0.0": + version: 3.0.0 + resolution: "abort-controller@npm:3.0.0" + dependencies: + event-target-shim: "npm:^5.0.0" + checksum: 10c0/90ccc50f010250152509a344eb2e71977fbf8db0ab8f1061197e3275ddf6c61a41a6edfd7b9409c664513131dd96e962065415325ef23efa5db931b382d24ca5 + languageName: node + linkType: hard + "accepts@npm:~1.3.4": version: 1.3.8 resolution: "accepts@npm:1.3.8" @@ -4779,6 +4958,36 @@ __metadata: languageName: node linkType: hard +"archiver-utils@npm:^5.0.0, archiver-utils@npm:^5.0.2": + version: 5.0.2 + resolution: "archiver-utils@npm:5.0.2" + dependencies: + glob: "npm:^10.0.0" + graceful-fs: "npm:^4.2.0" + is-stream: "npm:^2.0.1" + lazystream: "npm:^1.0.0" + lodash: "npm:^4.17.15" + normalize-path: "npm:^3.0.0" + readable-stream: "npm:^4.0.0" + checksum: 10c0/3782c5fa9922186aa1a8e41ed0c2867569faa5f15c8e5e6418ea4c1b730b476e21bd68270b3ea457daf459ae23aaea070b2b9f90cf90a59def8dc79b9e4ef538 + languageName: node + linkType: hard + +"archiver@npm:^7.0.1": + version: 7.0.1 + resolution: "archiver@npm:7.0.1" + dependencies: + archiver-utils: "npm:^5.0.2" + async: "npm:^3.2.4" + buffer-crc32: "npm:^1.0.0" + readable-stream: "npm:^4.0.0" + readdir-glob: "npm:^1.1.2" + tar-stream: "npm:^3.0.0" + zip-stream: "npm:^6.0.1" + checksum: 10c0/02afd87ca16f6184f752db8e26884e6eff911c476812a0e7f7b26c4beb09f06119807f388a8e26ed2558aa8ba9db28646ebd147a4f99e46813b8b43158e1438e + languageName: node + linkType: hard + "argparse@npm:^2.0.1": version: 2.0.1 resolution: "argparse@npm:2.0.1" @@ -4949,6 +5158,15 @@ __metadata: languageName: node linkType: hard +"asn1@npm:^0.2.6": + version: 0.2.6 + resolution: "asn1@npm:0.2.6" + dependencies: + safer-buffer: "npm:~2.1.0" + checksum: 10c0/00c8a06c37e548762306bcb1488388d2f76c74c36f70c803f0c081a01d3bdf26090fc088cd812afc5e56a6d49e33765d451a5f8a68ab9c2b087eba65d2e980e0 + languageName: node + linkType: hard + "assertion-error@npm:^2.0.1": version: 2.0.1 resolution: "assertion-error@npm:2.0.1" @@ -4974,7 +5192,14 @@ __metadata: languageName: node linkType: hard -"async@npm:^3.2.3": +"async-lock@npm:^1.4.1": + version: 1.4.1 + resolution: "async-lock@npm:1.4.1" + checksum: 10c0/f696991c7d894af1dc91abc81cc4f14b3785190a35afb1646d8ab91138238d55cabd83bfdd56c42663a008d72b3dc39493ff83797e550effc577d1ccbde254af + languageName: node + linkType: hard + +"async@npm:^3.2.3, async@npm:^3.2.4": version: 3.2.6 resolution: "async@npm:3.2.6" checksum: 10c0/36484bb15ceddf07078688d95e27076379cc2f87b10c03b6dd8a83e89475a3c8df5848859dd06a4c95af1e4c16fc973de0171a77f18ea00be899aca2a4f85e70 @@ -5049,6 +5274,18 @@ __metadata: languageName: node linkType: hard +"b4a@npm:^1.6.4": + version: 1.8.0 + resolution: "b4a@npm:1.8.0" + peerDependencies: + react-native-b4a: "*" + peerDependenciesMeta: + react-native-b4a: + optional: true + checksum: 10c0/27eab5c50ea1f1314f36256f160d2e6d6950f55f02ee4942732ecafd8bcc4b3a2ed209fab532b288770d41df2befa97a2745175c06471875b716eb87abf31519 + languageName: node + linkType: hard + "babel-plugin-macros@npm:^3.1.0": version: 3.1.0 resolution: "babel-plugin-macros@npm:3.1.0" @@ -5067,6 +5304,89 @@ __metadata: languageName: node linkType: hard +"bare-events@npm:^2.5.4, bare-events@npm:^2.7.0": + version: 2.8.2 + resolution: "bare-events@npm:2.8.2" + peerDependencies: + bare-abort-controller: "*" + peerDependenciesMeta: + bare-abort-controller: + optional: true + checksum: 10c0/53fef240cf2cdcca62f78b6eead90ddb5a59b0929f414b13a63764c2b4f9de98ea8a578d033b04d64bb7b86dfbc402e937984e69950855cc3754c7b63da7db21 + languageName: node + linkType: hard + +"bare-fs@npm:^4.0.1, bare-fs@npm:^4.5.5": + version: 4.7.0 + resolution: "bare-fs@npm:4.7.0" + dependencies: + bare-events: "npm:^2.5.4" + bare-path: "npm:^3.0.0" + bare-stream: "npm:^2.6.4" + bare-url: "npm:^2.2.2" + fast-fifo: "npm:^1.3.2" + peerDependencies: + bare-buffer: "*" + peerDependenciesMeta: + bare-buffer: + optional: true + checksum: 10c0/723debe61be0cf73c6f476270513a652453da0341401af65471d5508125963b76199393656659b0ab147adab221cd0c8e3d333a05215366e3eeaa29c7bf88873 + languageName: node + linkType: hard + +"bare-os@npm:^3.0.1": + version: 3.8.7 + resolution: "bare-os@npm:3.8.7" + checksum: 10c0/6541b223a196a58b52e1103ef1f04d35018c1b56b6c250410fc54680767624273691ece741eb88502c95b058ab90b632972348a9231410df05c5df61a62c9c08 + languageName: node + linkType: hard + +"bare-path@npm:^3.0.0": + version: 3.0.0 + resolution: "bare-path@npm:3.0.0" + dependencies: + bare-os: "npm:^3.0.1" + checksum: 10c0/56a3ca82a9f808f4976cb1188640ac206546ce0ddff582afafc7bd2a6a5b31c3bd16422653aec656eeada2830cfbaa433c6cbf6d6b4d9eba033d5e06d60d9a68 + languageName: node + linkType: hard + +"bare-stream@npm:^2.6.4": + version: 2.13.0 + resolution: "bare-stream@npm:2.13.0" + dependencies: + streamx: "npm:^2.25.0" + teex: "npm:^1.0.1" + peerDependencies: + bare-abort-controller: "*" + bare-buffer: "*" + bare-events: "*" + peerDependenciesMeta: + bare-abort-controller: + optional: true + bare-buffer: + optional: true + bare-events: + optional: true + checksum: 10c0/3c81f169d3bda8af430c5cb0a1cf29f3f697f25fb0863941582112e588680fdfe28357083edcee4c099d3df5a7e3f4145ccc9552d9c7d9b5cab195644fff53d5 + languageName: node + linkType: hard + +"bare-url@npm:^2.2.2": + version: 2.4.0 + resolution: "bare-url@npm:2.4.0" + dependencies: + bare-path: "npm:^3.0.0" + checksum: 10c0/b349bf4d3826d6e9fea40aae0b8aaba6e7e83af89feac93ad0b87721c11e0dd84eb651549275242c5ae07a3a21d24620b76bf59c434db65e9605a6e3180f8af2 + languageName: node + linkType: hard + +"base64-js@npm:^1.3.1": + version: 1.5.1 + resolution: "base64-js@npm:1.5.1" + checksum: 10c0/f23823513b63173a001030fae4f2dabe283b99a9d324ade3ad3d148e218134676f1ee8568c877cd79ec1c53158dcf2d2ba527a97c606618928ba99dd930102bf + languageName: node + linkType: hard + "base64id@npm:2.0.0, base64id@npm:~2.0.0": version: 2.0.0 resolution: "base64id@npm:2.0.0" @@ -5074,6 +5394,15 @@ __metadata: languageName: node linkType: hard +"bcrypt-pbkdf@npm:^1.0.2": + version: 1.0.2 + resolution: "bcrypt-pbkdf@npm:1.0.2" + dependencies: + tweetnacl: "npm:^0.14.3" + checksum: 10c0/ddfe85230b32df25aeebfdccfbc61d3bc493ace49c884c9c68575de1f5dcf733a5d7de9def3b0f318b786616b8d85bad50a28b1da1750c43e0012c93badcc148 + languageName: node + linkType: hard + "bin-links@npm:^6.0.0": version: 6.0.0 resolution: "bin-links@npm:6.0.0" @@ -5101,6 +5430,17 @@ __metadata: languageName: node linkType: hard +"bl@npm:^4.0.3": + version: 4.1.0 + resolution: "bl@npm:4.1.0" + dependencies: + buffer: "npm:^5.5.0" + inherits: "npm:^2.0.4" + readable-stream: "npm:^3.4.0" + checksum: 10c0/02847e1d2cb089c9dc6958add42e3cdeaf07d13f575973963335ac0fdece563a50ac770ac4c8fa06492d2dd276f6cc3b7f08c7cd9c7a7ad0f8d388b2a28def5f + languageName: node + linkType: hard + "bottleneck@npm:^2.19.5": version: 2.19.5 resolution: "bottleneck@npm:2.19.5" @@ -5173,6 +5513,13 @@ __metadata: languageName: node linkType: hard +"buffer-crc32@npm:^1.0.0": + version: 1.0.0 + resolution: "buffer-crc32@npm:1.0.0" + checksum: 10c0/8b86e161cee4bb48d5fa622cbae4c18f25e4857e5203b89e23de59e627ab26beb82d9d7999f2b8de02580165f61f83f997beaf02980cdf06affd175b651921ab + languageName: node + linkType: hard + "buffer-equal-constant-time@npm:1.0.1": version: 1.0.1 resolution: "buffer-equal-constant-time@npm:1.0.1" @@ -5187,6 +5534,33 @@ __metadata: languageName: node linkType: hard +"buffer@npm:^5.5.0": + version: 5.7.1 + resolution: "buffer@npm:5.7.1" + dependencies: + base64-js: "npm:^1.3.1" + ieee754: "npm:^1.1.13" + checksum: 10c0/27cac81cff434ed2876058d72e7c4789d11ff1120ef32c9de48f59eab58179b66710c488987d295ae89a228f835fc66d088652dffeb8e3ba8659f80eb091d55e + languageName: node + linkType: hard + +"buffer@npm:^6.0.3": + version: 6.0.3 + resolution: "buffer@npm:6.0.3" + dependencies: + base64-js: "npm:^1.3.1" + ieee754: "npm:^1.2.1" + checksum: 10c0/2a905fbbcde73cc5d8bd18d1caa23715d5f83a5935867c2329f0ac06104204ba7947be098fe1317fbd8830e26090ff8e764f08cd14fefc977bb248c3487bcbd0 + languageName: node + linkType: hard + +"buildcheck@npm:~0.0.6": + version: 0.0.7 + resolution: "buildcheck@npm:0.0.7" + checksum: 10c0/987c605267b1b6311bb2ac0638b073d322370267445a6d059da27985fce0b41f85a59d3a9aa9af839e8ac2d63da8af07be6dc737f8bd5323e1dfe6779ad67228 + languageName: node + linkType: hard + "bundle-name@npm:^4.1.0": version: 4.1.0 resolution: "bundle-name@npm:4.1.0" @@ -5205,6 +5579,13 @@ __metadata: languageName: node linkType: hard +"byline@npm:^5.0.0": + version: 5.0.0 + resolution: "byline@npm:5.0.0" + checksum: 10c0/33fb64cd84440b3652a99a68d732c56ef18a748ded495ba38e7756a242fab0d4654b9b8ce269fd0ac14c5f97aa4e3c369613672b280a1f60b559b34223105c85 + languageName: node + linkType: hard + "c12@npm:3.1.0": version: 3.1.0 resolution: "c12@npm:3.1.0" @@ -5413,6 +5794,13 @@ __metadata: languageName: node linkType: hard +"chownr@npm:^1.1.1": + version: 1.1.4 + resolution: "chownr@npm:1.1.4" + checksum: 10c0/ed57952a84cc0c802af900cf7136de643d3aba2eecb59d29344bc2f3f9bf703a301b9d84cdc71f82c3ffc9ccde831b0d92f5b45f91727d6c9da62f23aef9d9db + languageName: node + linkType: hard + "chownr@npm:^2.0.0": version: 2.0.0 resolution: "chownr@npm:2.0.0" @@ -5476,6 +5864,17 @@ __metadata: languageName: node linkType: hard +"cliui@npm:^8.0.1": + version: 8.0.1 + resolution: "cliui@npm:8.0.1" + dependencies: + string-width: "npm:^4.2.0" + strip-ansi: "npm:^6.0.1" + wrap-ansi: "npm:^7.0.0" + checksum: 10c0/4bda0f09c340cbb6dfdc1ed508b3ca080f12992c18d68c6be4d9cf51756033d5266e61ec57529e610dacbf4da1c634423b0c1b11037709cc6b09045cbd815df5 + languageName: node + linkType: hard + "clsx@npm:^2.1.1": version: 2.1.1 resolution: "clsx@npm:2.1.1" @@ -5589,6 +5988,19 @@ __metadata: languageName: node linkType: hard +"compress-commons@npm:^6.0.2": + version: 6.0.2 + resolution: "compress-commons@npm:6.0.2" + dependencies: + crc-32: "npm:^1.2.0" + crc32-stream: "npm:^6.0.0" + is-stream: "npm:^2.0.1" + normalize-path: "npm:^3.0.0" + readable-stream: "npm:^4.0.0" + checksum: 10c0/2347031b7c92c8ed5011b07b93ec53b298fa2cd1800897532ac4d4d1aeae06567883f481b6e35f13b65fc31b190c751df6635434d525562f0203fde76f1f0814 + languageName: node + linkType: hard + "concat-map@npm:0.0.1": version: 0.0.1 resolution: "concat-map@npm:0.0.1" @@ -5631,6 +6043,13 @@ __metadata: languageName: node linkType: hard +"cookie@npm:^1.1.1": + version: 1.1.1 + resolution: "cookie@npm:1.1.1" + checksum: 10c0/79c4ddc0fcad9c4f045f826f42edf54bcc921a29586a4558b0898277fa89fb47be95bc384c2253f493af7b29500c830da28341274527328f18eba9f58afa112c + languageName: node + linkType: hard + "cookie@npm:~0.4.1": version: 0.4.2 resolution: "cookie@npm:0.4.2" @@ -5666,6 +6085,20 @@ __metadata: languageName: node linkType: hard +"core-js@npm:^3.49.0": + version: 3.49.0 + resolution: "core-js@npm:3.49.0" + checksum: 10c0/2e42edb47eda38fd5368380131623c8aa5d4a6b42164125b17744bdc08fa5ebbbdd06b4b4aa6ca3663470a560b0f2fba48e18f142dfe264b0039df85bc625694 + languageName: node + linkType: hard + +"core-util-is@npm:~1.0.0": + version: 1.0.3 + resolution: "core-util-is@npm:1.0.3" + checksum: 10c0/90a0e40abbddfd7618f8ccd63a74d88deea94e77d0e8dbbea059fa7ebebb8fbb4e2909667fe26f3a467073de1a542ebe6ae4c73a73745ac5833786759cd906c9 + languageName: node + linkType: hard + "cors@npm:~2.8.5": version: 2.8.6 resolution: "cors@npm:2.8.6" @@ -5689,6 +6122,36 @@ __metadata: languageName: node linkType: hard +"cpu-features@npm:~0.0.10": + version: 0.0.10 + resolution: "cpu-features@npm:0.0.10" + dependencies: + buildcheck: "npm:~0.0.6" + nan: "npm:^2.19.0" + node-gyp: "npm:latest" + checksum: 10c0/0c4a12904657b22477ffbcfd2b4b2bdd45b174f283616b18d9e1ade495083f9f6098493feb09f4ae2d0b36b240f9ecd32cfb4afe210cf0d0f8f0cc257bd58e54 + languageName: node + linkType: hard + +"crc-32@npm:^1.2.0": + version: 1.2.2 + resolution: "crc-32@npm:1.2.2" + bin: + crc32: bin/crc32.njs + checksum: 10c0/11dcf4a2e77ee793835d49f2c028838eae58b44f50d1ff08394a610bfd817523f105d6ae4d9b5bef0aad45510f633eb23c903e9902e4409bed1ce70cb82b9bf0 + languageName: node + linkType: hard + +"crc32-stream@npm:^6.0.0": + version: 6.0.0 + resolution: "crc32-stream@npm:6.0.0" + dependencies: + crc-32: "npm:^1.2.0" + readable-stream: "npm:^4.0.0" + checksum: 10c0/bf9c84571ede2d119c2b4f3a9ef5eeb9ff94b588493c0d3862259af86d3679dcce1c8569dd2b0a6eff2f35f5e2081cc1263b846d2538d4054da78cf34f262a3d + languageName: node + linkType: hard + "cronstrue@npm:^2.21.0": version: 2.59.0 resolution: "cronstrue@npm:2.59.0" @@ -5767,6 +6230,7 @@ __metadata: "@sentry/nextjs": "npm:^9.13.0" "@supabase/supabase-js": "npm:^2.49.4" "@tailwindcss/postcss": "npm:^4.1.5" + "@testcontainers/postgresql": "npm:^11.14.0" "@trigger.dev/build": "npm:4.4.4" "@trigger.dev/sdk": "npm:4.4.4" "@types/deep-equal": "npm:^1.0.4" @@ -5798,6 +6262,7 @@ __metadata: json-2-csv: "npm:^5.5.9" lint-staged: "npm:^15.5.1" next: "npm:15.5.15" + next-test-api-route-handler: "npm:^5.0.4" open: "npm:^10.1.0" p-retry: "npm:^6.2.1" postcss: "npm:^8.5.3" @@ -5813,6 +6278,7 @@ __metadata: supabase: "npm:2.84.4" swr: "npm:^2.3.3" tailwindcss: "npm:^4.1.5" + testcontainers: "npm:^11.14.0" tsx: "npm:^4.21.0" typescript: "npm:^5.8.3" vitest: "npm:^4.1.3" @@ -5954,7 +6420,7 @@ __metadata: languageName: node linkType: hard -"debug@npm:^4.4.3": +"debug@npm:^4.1.1, debug@npm:^4.4.3": version: 4.4.3 resolution: "debug@npm:4.4.3" dependencies: @@ -6134,6 +6600,42 @@ __metadata: languageName: node linkType: hard +"docker-compose@npm:^1.4.2": + version: 1.4.2 + resolution: "docker-compose@npm:1.4.2" + dependencies: + yaml: "npm:^2.2.2" + checksum: 10c0/2cd9182dafeac8ac3fed57e5aac85be5dec18eaa0241026d202e418577bfe185ab97ae2e066be01ade4ae55ffdcab04f4b40c754f3b2d11c314d6ca0117b51fa + languageName: node + linkType: hard + +"docker-modem@npm:^5.0.7": + version: 5.0.7 + resolution: "docker-modem@npm:5.0.7" + dependencies: + debug: "npm:^4.1.1" + readable-stream: "npm:^3.5.0" + split-ca: "npm:^1.0.1" + ssh2: "npm:^1.15.0" + checksum: 10c0/987dd7b04de57241d4e0fbdb5c44d41f898f5f520a3f6dbc6542c27cf9e84c91c44bf0c1bee2469be83096cb2941ea5e4a1bd3f57f60eb508c1d790d27ada8f9 + languageName: node + linkType: hard + +"dockerode@npm:^4.0.10": + version: 4.0.10 + resolution: "dockerode@npm:4.0.10" + dependencies: + "@balena/dockerignore": "npm:^1.0.2" + "@grpc/grpc-js": "npm:^1.11.1" + "@grpc/proto-loader": "npm:^0.7.13" + docker-modem: "npm:^5.0.7" + protobufjs: "npm:^7.3.2" + tar-fs: "npm:^2.1.4" + uuid: "npm:^10.0.0" + checksum: 10c0/064930c4446ee833227417952ee9450b6f2a0045bfb93041ce36dd3f831fd6f24b7f87b44b6ff067782d0f121e5e530044e7e9ef538ef0c83133928a486d2d47 + languageName: node + linkType: hard + "doctrine@npm:^2.1.0": version: 2.1.0 resolution: "doctrine@npm:2.1.0" @@ -6423,6 +6925,15 @@ __metadata: languageName: node linkType: hard +"end-of-stream@npm:^1.1.0, end-of-stream@npm:^1.4.1": + version: 1.4.5 + resolution: "end-of-stream@npm:1.4.5" + dependencies: + once: "npm:^1.4.0" + checksum: 10c0/b0701c92a10b89afb1cb45bf54a5292c6f008d744eb4382fa559d54775ff31617d1d7bc3ef617575f552e24fad2c7c1a1835948c66b3f3a4be0a6c1f35c883d8 + languageName: node + linkType: hard + "engine.io-client@npm:~6.5.2": version: 6.5.4 resolution: "engine.io-client@npm:6.5.4" @@ -7402,6 +7913,13 @@ __metadata: languageName: node linkType: hard +"event-target-shim@npm:^5.0.0": + version: 5.0.1 + resolution: "event-target-shim@npm:5.0.1" + checksum: 10c0/0255d9f936215fd206156fd4caa9e8d35e62075d720dc7d847e89b417e5e62cf1ce6c9b4e0a1633a9256de0efefaf9f8d26924b1f3c8620cffb9db78e7d3076b + languageName: node + linkType: hard + "eventemitter3@npm:^5.0.1": version: 5.0.1 resolution: "eventemitter3@npm:5.0.1" @@ -7409,6 +7927,22 @@ __metadata: languageName: node linkType: hard +"events-universal@npm:^1.0.0": + version: 1.0.1 + resolution: "events-universal@npm:1.0.1" + dependencies: + bare-events: "npm:^2.7.0" + checksum: 10c0/a1d9a5e9f95843650f8ec240dd1221454c110189a9813f32cdf7185759b43f1f964367ac7dca4ebc69150b59043f2d77c7e122b0d03abf7c25477ea5494785a5 + languageName: node + linkType: hard + +"events@npm:^3.3.0": + version: 3.3.0 + resolution: "events@npm:3.3.0" + checksum: 10c0/d6b6f2adbccbcda74ddbab52ed07db727ef52e31a61ed26db9feb7dc62af7fc8e060defa65e5f8af9449b86b52cc1a1f6a79f2eafcf4e62add2b7a1fa4a432f6 + languageName: node + linkType: hard + "eventsource-parser@npm:^3.0.0, eventsource-parser@npm:^3.0.1": version: 3.0.6 resolution: "eventsource-parser@npm:3.0.6" @@ -7497,6 +8031,13 @@ __metadata: languageName: node linkType: hard +"fast-fifo@npm:^1.2.0, fast-fifo@npm:^1.3.2": + version: 1.3.2 + resolution: "fast-fifo@npm:1.3.2" + checksum: 10c0/d53f6f786875e8b0529f784b59b4b05d4b5c31c651710496440006a398389a579c8dbcd2081311478b5bf77f4b0b21de69109c5a4eabea9d8e8783d1eb864e4c + languageName: node + linkType: hard + "fast-glob@npm:3.3.1": version: 3.3.1 resolution: "fast-glob@npm:3.3.1" @@ -7765,6 +8306,13 @@ __metadata: languageName: node linkType: hard +"fs-constants@npm:^1.0.0": + version: 1.0.0 + resolution: "fs-constants@npm:1.0.0" + checksum: 10c0/a0cde99085f0872f4d244e83e03a46aa387b74f5a5af750896c6b05e9077fac00e9932fdf5aef84f2f16634cd473c63037d7a512576da7d5c2b9163d1909f3a8 + languageName: node + linkType: hard + "fs-minipass@npm:^2.0.0": version: 2.1.0 resolution: "fs-minipass@npm:2.1.0" @@ -7856,6 +8404,13 @@ __metadata: languageName: node linkType: hard +"get-caller-file@npm:^2.0.5": + version: 2.0.5 + resolution: "get-caller-file@npm:2.0.5" + checksum: 10c0/c6c7b60271931fa752aeb92f2b47e355eac1af3a2673f47c9589e8f8a41adc74d45551c1bc57b5e66a80609f10ffb72b6f575e4370d61cc3f7f3aaff01757cde + languageName: node + linkType: hard + "get-east-asian-width@npm:^1.0.0": version: 1.3.0 resolution: "get-east-asian-width@npm:1.3.0" @@ -7894,6 +8449,13 @@ __metadata: languageName: node linkType: hard +"get-port@npm:^7.2.0": + version: 7.2.0 + resolution: "get-port@npm:7.2.0" + checksum: 10c0/4ed741d9008ad15a24e2098c8971918025cc8241624245e704ecc62bb65160db5c79de5d7112acdaabccbe0714cd0704008c74d43a1f7a24a5875e58b84621be + languageName: node + linkType: hard + "get-proto@npm:^1.0.0, get-proto@npm:^1.0.1": version: 1.0.1 resolution: "get-proto@npm:1.0.1" @@ -7994,22 +8556,7 @@ __metadata: languageName: node linkType: hard -"glob@npm:^10.2.2, glob@npm:^10.3.10": - version: 10.3.10 - resolution: "glob@npm:10.3.10" - dependencies: - foreground-child: "npm:^3.1.0" - jackspeak: "npm:^2.3.5" - minimatch: "npm:^9.0.1" - minipass: "npm:^5.0.0 || ^6.0.2 || ^7.0.0" - path-scurry: "npm:^1.10.1" - bin: - glob: dist/esm/bin.mjs - checksum: 10c0/13d8a1feb7eac7945f8c8480e11cd4a44b24d26503d99a8d8ac8d5aefbf3e9802a2b6087318a829fad04cb4e829f25c5f4f1110c68966c498720dd261c7e344d - languageName: node - linkType: hard - -"glob@npm:^10.5.0": +"glob@npm:^10.0.0, glob@npm:^10.5.0": version: 10.5.0 resolution: "glob@npm:10.5.0" dependencies: @@ -8025,6 +8572,21 @@ __metadata: languageName: node linkType: hard +"glob@npm:^10.2.2, glob@npm:^10.3.10": + version: 10.3.10 + resolution: "glob@npm:10.3.10" + dependencies: + foreground-child: "npm:^3.1.0" + jackspeak: "npm:^2.3.5" + minimatch: "npm:^9.0.1" + minipass: "npm:^5.0.0 || ^6.0.2 || ^7.0.0" + path-scurry: "npm:^1.10.1" + bin: + glob: dist/esm/bin.mjs + checksum: 10c0/13d8a1feb7eac7945f8c8480e11cd4a44b24d26503d99a8d8ac8d5aefbf3e9802a2b6087318a829fad04cb4e829f25c5f4f1110c68966c498720dd261c7e344d + languageName: node + linkType: hard + "glob@npm:^9.3.2": version: 9.3.5 resolution: "glob@npm:9.3.5" @@ -8086,7 +8648,7 @@ __metadata: languageName: node linkType: hard -"graceful-fs@npm:^4.2.11, graceful-fs@npm:^4.2.4, graceful-fs@npm:^4.2.6": +"graceful-fs@npm:^4.2.0, graceful-fs@npm:^4.2.11, graceful-fs@npm:^4.2.4, graceful-fs@npm:^4.2.6": version: 4.2.11 resolution: "graceful-fs@npm:4.2.11" checksum: 10c0/386d011a553e02bc594ac2ca0bd6d9e4c22d7fa8cfbfc448a6d148c59ea881b092db9dbe3547ae4b88e55f1b01f7c4a2ecc53b310c042793e63aa44cf6c257f2 @@ -8325,6 +8887,13 @@ __metadata: languageName: node linkType: hard +"ieee754@npm:^1.1.13, ieee754@npm:^1.2.1": + version: 1.2.1 + resolution: "ieee754@npm:1.2.1" + checksum: 10c0/b0782ef5e0935b9f12883a2e2aa37baa75da6e66ce6515c168697b42160807d9330de9a32ec1ed73149aea02e0d822e572bca6f1e22bdcbd2149e13b050b17bb + languageName: node + linkType: hard + "ignore@npm:^5.2.0": version: 5.3.1 resolution: "ignore@npm:5.3.1" @@ -8375,7 +8944,7 @@ __metadata: languageName: node linkType: hard -"inherits@npm:^2.0.3": +"inherits@npm:^2.0.3, inherits@npm:^2.0.4, inherits@npm:~2.0.3": version: 2.0.4 resolution: "inherits@npm:2.0.4" checksum: 10c0/4e531f648b29039fb7426fb94075e6545faa1eb9fe83c29f0b6d9e7263aceb4289d2d4557db0d428188eeb449cc7c5e77b0a0b2c4e248ff2a65933a0dee49ef2 @@ -8812,7 +9381,7 @@ __metadata: languageName: node linkType: hard -"is-stream@npm:^2.0.0": +"is-stream@npm:^2.0.0, is-stream@npm:^2.0.1": version: 2.0.1 resolution: "is-stream@npm:2.0.1" checksum: 10c0/7c284241313fc6efc329b8d7f08e16c0efeb6baab1b4cd0ba579eb78e5af1aa5da11e68559896a2067cd6c526bd29241dda4eb1225e627d5aa1a89a76d4635a5 @@ -8934,6 +9503,13 @@ __metadata: languageName: node linkType: hard +"isarray@npm:~1.0.0": + version: 1.0.0 + resolution: "isarray@npm:1.0.0" + checksum: 10c0/18b5be6669be53425f0b84098732670ed4e727e3af33bc7f948aac01782110eb9a18b3b329c5323bcdd3acdaae547ee077d3951317e7f133bff7105264b3003d + languageName: node + linkType: hard + "isexe@npm:^2.0.0": version: 2.0.0 resolution: "isexe@npm:2.0.0" @@ -9233,6 +9809,15 @@ __metadata: languageName: node linkType: hard +"lazystream@npm:^1.0.0": + version: 1.0.1 + resolution: "lazystream@npm:1.0.1" + dependencies: + readable-stream: "npm:^2.0.5" + checksum: 10c0/ea4e509a5226ecfcc303ba6782cc269be8867d372b9bcbd625c88955df1987ea1a20da4643bf9270336415a398d33531ebf0d5f0d393b9283dc7c98bfcbd7b69 + languageName: node + linkType: hard + "leac@npm:^0.6.0": version: 0.6.0 resolution: "leac@npm:0.6.0" @@ -9546,6 +10131,13 @@ __metadata: languageName: node linkType: hard +"lodash.camelcase@npm:^4.3.0": + version: 4.3.0 + resolution: "lodash.camelcase@npm:4.3.0" + checksum: 10c0/fcba15d21a458076dd309fce6b1b4bf611d84a0ec252cb92447c948c533ac250b95d2e00955801ebc367e5af5ed288b996d75d37d2035260a937008e14eaf432 + languageName: node + linkType: hard + "lodash.includes@npm:^4.3.0": version: 4.3.0 resolution: "lodash.includes@npm:4.3.0" @@ -9602,6 +10194,13 @@ __metadata: languageName: node linkType: hard +"lodash@npm:^4.17.15": + version: 4.18.1 + resolution: "lodash@npm:4.18.1" + checksum: 10c0/757228fc68805c59789e82185135cf85f05d0b2d3d54631d680ca79ec21944ec8314d4533639a14b8bcfbd97a517e78960933041a5af17ecb693ec6eecb99a27 + languageName: node + linkType: hard + "log-update@npm:^6.1.0": version: 6.1.0 resolution: "log-update@npm:6.1.0" @@ -9849,6 +10448,15 @@ __metadata: languageName: node linkType: hard +"minimatch@npm:^5.1.0": + version: 5.1.9 + resolution: "minimatch@npm:5.1.9" + dependencies: + brace-expansion: "npm:^2.0.1" + checksum: 10c0/4202718683815a7288b13e470160a4f9560cf392adef4f453927505817e01ef6b3476ecde13cfcaed17e7326dd3b69ad44eb2daeb19a217c5500f9277893f1d6 + languageName: node + linkType: hard + "minimatch@npm:^8.0.2": version: 8.0.4 resolution: "minimatch@npm:8.0.4" @@ -9990,6 +10598,13 @@ __metadata: languageName: node linkType: hard +"mkdirp-classic@npm:^0.5.2": + version: 0.5.3 + resolution: "mkdirp-classic@npm:0.5.3" + checksum: 10c0/95371d831d196960ddc3833cc6907e6b8f67ac5501a6582f47dfae5eb0f092e9f8ce88e0d83afcae95d6e2b61a01741ba03714eeafb6f7a6e9dcc158ac85b168 + languageName: node + linkType: hard + "mkdirp@npm:^1.0.3": version: 1.0.4 resolution: "mkdirp@npm:1.0.4" @@ -9999,6 +10614,15 @@ __metadata: languageName: node linkType: hard +"mkdirp@npm:^3.0.1": + version: 3.0.1 + resolution: "mkdirp@npm:3.0.1" + bin: + mkdirp: dist/cjs/src/bin.js + checksum: 10c0/9f2b975e9246351f5e3a40dcfac99fcd0baa31fbfab615fe059fb11e51f10e4803c63de1f384c54d656e4db31d000e4767e9ef076a22e12a641357602e31d57d + languageName: node + linkType: hard + "mlly@npm:^1.7.1, mlly@npm:^1.7.4": version: 1.8.0 resolution: "mlly@npm:1.8.0" @@ -10032,6 +10656,15 @@ __metadata: languageName: node linkType: hard +"nan@npm:^2.19.0, nan@npm:^2.23.0": + version: 2.26.2 + resolution: "nan@npm:2.26.2" + dependencies: + node-gyp: "npm:latest" + checksum: 10c0/ff204c964729279cf3abb8b170c77753ed36092e2235f11bfb0204dfd3e8cc2d5a3bcfdfd3b677f06a0743d7f835d873dce59f23a2dbf6fb671d9351cc655d73 + languageName: node + linkType: hard + "nanoid@npm:3.3.8": version: 3.3.8 resolution: "nanoid@npm:3.3.8" @@ -10073,6 +10706,19 @@ __metadata: languageName: node linkType: hard +"next-test-api-route-handler@npm:^5.0.4": + version: 5.0.4 + resolution: "next-test-api-route-handler@npm:5.0.4" + dependencies: + "@whatwg-node/server": "npm:^0.10.18" + cookie: "npm:^1.1.1" + core-js: "npm:^3.49.0" + peerDependencies: + next: ">=9" + checksum: 10c0/9da08408088353ab3e78580c038b451d78f7eded4594c43586bf4b911397442820978924b8a23320875b075b1a1296161f3684b21baec1c58d5a8bf071e71e21 + languageName: node + linkType: hard + "next@npm:15.5.15": version: 15.5.15 resolution: "next@npm:15.5.15" @@ -10459,6 +11105,15 @@ __metadata: languageName: node linkType: hard +"once@npm:^1.3.1, once@npm:^1.4.0": + version: 1.4.0 + resolution: "once@npm:1.4.0" + dependencies: + wrappy: "npm:1" + checksum: 10c0/5d48aca287dfefabd756621c5dfce5c91a549a93e9fdb7b8246bc4c4790aa2ec17b34a260530474635147aeb631a2dcc8b32c613df0675f96041cbb8244517d0 + languageName: node + linkType: hard + "one-time@npm:^1.0.0": version: 1.0.0 resolution: "one-time@npm:1.0.0" @@ -10866,13 +11521,13 @@ __metadata: linkType: hard "postcss@npm:^8.5.8": - version: 8.5.10 - resolution: "postcss@npm:8.5.10" + version: 8.5.9 + resolution: "postcss@npm:8.5.9" dependencies: nanoid: "npm:^3.3.11" picocolors: "npm:^1.1.1" source-map-js: "npm:^1.2.1" - checksum: 10c0/c592dffa0c4873b401f01955b265538d9942f425040df5e2b8f0ad34c83773a792ea0fa5859ccc99cfb5b955b4ebff118ab7056315388dc83b107b0fa8313576 + checksum: 10c0/7cb2b32202ea1ead03f15cfbb2756a64a0f98942378e99b3dfce33678fe5eaf93e31d675a46e3a0dfb417d7b49b82d8999d0dd42a33c3b128e71ade0f978719a languageName: node linkType: hard @@ -11057,6 +11712,20 @@ __metadata: languageName: node linkType: hard +"process-nextick-args@npm:~2.0.0": + version: 2.0.1 + resolution: "process-nextick-args@npm:2.0.1" + checksum: 10c0/bec089239487833d46b59d80327a1605e1c5287eaad770a291add7f45fda1bb5e28b38e0e061add0a1d0ee0984788ce74fa394d345eed1c420cacf392c554367 + languageName: node + linkType: hard + +"process@npm:^0.11.10": + version: 0.11.10 + resolution: "process@npm:0.11.10" + checksum: 10c0/40c3ce4b7e6d4b8c3355479df77aeed46f81b279818ccdc500124e6a5ab882c0cc81ff7ea16384873a95a74c4570b01b120f287abbdd4c877931460eca6084b3 + languageName: node + linkType: hard + "progress@npm:^2.0.3": version: 2.0.3 resolution: "progress@npm:2.0.3" @@ -11095,6 +11764,27 @@ __metadata: languageName: node linkType: hard +"proper-lockfile@npm:^4.1.2": + version: 4.1.2 + resolution: "proper-lockfile@npm:4.1.2" + dependencies: + graceful-fs: "npm:^4.2.4" + retry: "npm:^0.12.0" + signal-exit: "npm:^3.0.2" + checksum: 10c0/2f265dbad15897a43110a02dae55105c04d356ec4ed560723dcb9f0d34bc4fb2f13f79bb930e7561be10278e2314db5aca2527d5d3dcbbdee5e6b331d1571f6d + languageName: node + linkType: hard + +"properties-reader@npm:^3.0.1": + version: 3.0.1 + resolution: "properties-reader@npm:3.0.1" + dependencies: + "@kwsites/file-exists": "npm:^1.1.1" + mkdirp: "npm:^3.0.1" + checksum: 10c0/271fae77b717e25aa5773ab1e769f416ccfdc3606a62f25cd76b2cceeb04278f2ee0e4d671ff2c06391a5e093b4b1097f9ce3916fddd4de34077a4a6e92ccb48 + languageName: node + linkType: hard + "property-information@npm:^5.0.0": version: 5.6.0 resolution: "property-information@npm:5.6.0" @@ -11104,7 +11794,7 @@ __metadata: languageName: node linkType: hard -"protobufjs@npm:^7.3.0": +"protobufjs@npm:^7.2.5, protobufjs@npm:^7.3.0, protobufjs@npm:^7.3.2, protobufjs@npm:^7.5.3": version: 7.5.4 resolution: "protobufjs@npm:7.5.4" dependencies: @@ -11138,6 +11828,16 @@ __metadata: languageName: node linkType: hard +"pump@npm:^3.0.0": + version: 3.0.4 + resolution: "pump@npm:3.0.4" + dependencies: + end-of-stream: "npm:^1.1.0" + once: "npm:^1.3.1" + checksum: 10c0/2780e66b5471c19e3e3e1063b84f3f6a3a08367f24c5ed552f98cd5901e6ada27c7ad6495d4244f553fd03b01884a4561933064f053f47c8994d84fd352768ea + languageName: node + linkType: hard + "punycode@npm:^2.1.0": version: 2.3.1 resolution: "punycode@npm:2.3.1" @@ -11332,7 +12032,22 @@ __metadata: languageName: node linkType: hard -"readable-stream@npm:^3.4.0, readable-stream@npm:^3.6.2": +"readable-stream@npm:^2.0.5": + version: 2.3.8 + resolution: "readable-stream@npm:2.3.8" + dependencies: + core-util-is: "npm:~1.0.0" + inherits: "npm:~2.0.3" + isarray: "npm:~1.0.0" + process-nextick-args: "npm:~2.0.0" + safe-buffer: "npm:~5.1.1" + string_decoder: "npm:~1.1.1" + util-deprecate: "npm:~1.0.1" + checksum: 10c0/7efdb01f3853bc35ac62ea25493567bf588773213f5f4a79f9c365e1ad13bab845ac0dae7bc946270dc40c3929483228415e92a3fc600cc7e4548992f41ee3fa + languageName: node + linkType: hard + +"readable-stream@npm:^3.1.1, readable-stream@npm:^3.4.0, readable-stream@npm:^3.5.0, readable-stream@npm:^3.6.2": version: 3.6.2 resolution: "readable-stream@npm:3.6.2" dependencies: @@ -11343,6 +12058,28 @@ __metadata: languageName: node linkType: hard +"readable-stream@npm:^4.0.0": + version: 4.7.0 + resolution: "readable-stream@npm:4.7.0" + dependencies: + abort-controller: "npm:^3.0.0" + buffer: "npm:^6.0.3" + events: "npm:^3.3.0" + process: "npm:^0.11.10" + string_decoder: "npm:^1.3.0" + checksum: 10c0/fd86d068da21cfdb10f7a4479f2e47d9c0a9b0c862fc0c840a7e5360201580a55ac399c764b12a4f6fa291f8cee74d9c4b7562e0d53b3c4b2769f2c98155d957 + languageName: node + linkType: hard + +"readdir-glob@npm:^1.1.2": + version: 1.1.3 + resolution: "readdir-glob@npm:1.1.3" + dependencies: + minimatch: "npm:^5.1.0" + checksum: 10c0/a37e0716726650845d761f1041387acd93aa91b28dd5381950733f994b6c349ddc1e21e266ec7cc1f9b92e205a7a972232f9b89d5424d07361c2c3753d5dbace + languageName: node + linkType: hard + "readdirp@npm:^4.0.1": version: 4.1.2 resolution: "readdirp@npm:4.1.2" @@ -11426,6 +12163,13 @@ __metadata: languageName: node linkType: hard +"require-directory@npm:^2.1.1": + version: 2.1.1 + resolution: "require-directory@npm:2.1.1" + checksum: 10c0/83aa76a7bc1531f68d92c75a2ca2f54f1b01463cb566cf3fbc787d0de8be30c9dbc211d1d46be3497dac5785fe296f2dd11d531945ac29730643357978966e99 + languageName: node + linkType: hard + "require-in-the-middle@npm:^7.1.1": version: 7.5.2 resolution: "require-in-the-middle@npm:7.5.2" @@ -11574,27 +12318,27 @@ __metadata: languageName: node linkType: hard -"rolldown@npm:1.0.0-rc.15": - version: 1.0.0-rc.15 - resolution: "rolldown@npm:1.0.0-rc.15" - dependencies: - "@oxc-project/types": "npm:=0.124.0" - "@rolldown/binding-android-arm64": "npm:1.0.0-rc.15" - "@rolldown/binding-darwin-arm64": "npm:1.0.0-rc.15" - "@rolldown/binding-darwin-x64": "npm:1.0.0-rc.15" - "@rolldown/binding-freebsd-x64": "npm:1.0.0-rc.15" - "@rolldown/binding-linux-arm-gnueabihf": "npm:1.0.0-rc.15" - "@rolldown/binding-linux-arm64-gnu": "npm:1.0.0-rc.15" - "@rolldown/binding-linux-arm64-musl": "npm:1.0.0-rc.15" - "@rolldown/binding-linux-ppc64-gnu": "npm:1.0.0-rc.15" - "@rolldown/binding-linux-s390x-gnu": "npm:1.0.0-rc.15" - "@rolldown/binding-linux-x64-gnu": "npm:1.0.0-rc.15" - "@rolldown/binding-linux-x64-musl": "npm:1.0.0-rc.15" - "@rolldown/binding-openharmony-arm64": "npm:1.0.0-rc.15" - "@rolldown/binding-wasm32-wasi": "npm:1.0.0-rc.15" - "@rolldown/binding-win32-arm64-msvc": "npm:1.0.0-rc.15" - "@rolldown/binding-win32-x64-msvc": "npm:1.0.0-rc.15" - "@rolldown/pluginutils": "npm:1.0.0-rc.15" +"rolldown@npm:1.0.0-rc.13": + version: 1.0.0-rc.13 + resolution: "rolldown@npm:1.0.0-rc.13" + dependencies: + "@oxc-project/types": "npm:=0.123.0" + "@rolldown/binding-android-arm64": "npm:1.0.0-rc.13" + "@rolldown/binding-darwin-arm64": "npm:1.0.0-rc.13" + "@rolldown/binding-darwin-x64": "npm:1.0.0-rc.13" + "@rolldown/binding-freebsd-x64": "npm:1.0.0-rc.13" + "@rolldown/binding-linux-arm-gnueabihf": "npm:1.0.0-rc.13" + "@rolldown/binding-linux-arm64-gnu": "npm:1.0.0-rc.13" + "@rolldown/binding-linux-arm64-musl": "npm:1.0.0-rc.13" + "@rolldown/binding-linux-ppc64-gnu": "npm:1.0.0-rc.13" + "@rolldown/binding-linux-s390x-gnu": "npm:1.0.0-rc.13" + "@rolldown/binding-linux-x64-gnu": "npm:1.0.0-rc.13" + "@rolldown/binding-linux-x64-musl": "npm:1.0.0-rc.13" + "@rolldown/binding-openharmony-arm64": "npm:1.0.0-rc.13" + "@rolldown/binding-wasm32-wasi": "npm:1.0.0-rc.13" + "@rolldown/binding-win32-arm64-msvc": "npm:1.0.0-rc.13" + "@rolldown/binding-win32-x64-msvc": "npm:1.0.0-rc.13" + "@rolldown/pluginutils": "npm:1.0.0-rc.13" dependenciesMeta: "@rolldown/binding-android-arm64": optional: true @@ -11628,7 +12372,7 @@ __metadata: optional: true bin: rolldown: bin/cli.mjs - checksum: 10c0/95df21125dafd2a0ce6ae9a89d926540e47900684023126c84632e18123371020da8f6b3235a188c45af0e4f9a5b963235de33bd9658ee5db9f3ff5862200eed + checksum: 10c0/fc091b7df634c0b181a28914da708376e009092c67e98f1b062f216066f790d69c6b2adc6cb044741cbe4a93d944d222e599578019da090cb66d7bd91f3730a3 languageName: node linkType: hard @@ -11768,6 +12512,13 @@ __metadata: languageName: node linkType: hard +"safe-buffer@npm:~5.1.0, safe-buffer@npm:~5.1.1": + version: 5.1.2 + resolution: "safe-buffer@npm:5.1.2" + checksum: 10c0/780ba6b5d99cc9a40f7b951d47152297d0e260f0df01472a1b99d4889679a4b94a13d644f7dbc4f022572f09ae9005fa2fbb93bbbd83643316f365a3e9a45b21 + languageName: node + linkType: hard + "safe-push-apply@npm:^1.0.0": version: 1.0.0 resolution: "safe-push-apply@npm:1.0.0" @@ -11807,7 +12558,7 @@ __metadata: languageName: node linkType: hard -"safer-buffer@npm:>= 2.1.2 < 3.0.0": +"safer-buffer@npm:>= 2.1.2 < 3.0.0, safer-buffer@npm:~2.1.0": version: 2.1.2 resolution: "safer-buffer@npm:2.1.2" checksum: 10c0/7e3c8b2e88a1841c9671094bbaeebd94448111dd90a81a1f606f3f67708a6ec57763b3b47f06da09fc6054193e0e6709e77325415dc8422b04497a8070fa02d4 @@ -12088,6 +12839,13 @@ __metadata: languageName: node linkType: hard +"signal-exit@npm:^3.0.2": + version: 3.0.7 + resolution: "signal-exit@npm:3.0.7" + checksum: 10c0/25d272fa73e146048565e08f3309d5b942c1979a6f4a58a8c59d5fa299728e9c2fcd1a759ec870863b1fd38653670240cd420dad2ad9330c71f36608a6a1c912 + languageName: node + linkType: hard + "signal-exit@npm:^4.0.1, signal-exit@npm:^4.1.0": version: 4.1.0 resolution: "signal-exit@npm:4.1.0" @@ -12251,6 +13009,13 @@ __metadata: languageName: node linkType: hard +"split-ca@npm:^1.0.1": + version: 1.0.1 + resolution: "split-ca@npm:1.0.1" + checksum: 10c0/f339170b84c6b4706fcf4c60cc84acb36574c0447566bd713301a8d9b4feff7f4627efc8c334bec24944a3e2f35bc596bd58c673c9980d6bfe3137aae1116ba7 + languageName: node + linkType: hard + "split-on-first@npm:^1.0.0": version: 1.1.0 resolution: "split-on-first@npm:1.1.0" @@ -12265,6 +13030,33 @@ __metadata: languageName: node linkType: hard +"ssh-remote-port-forward@npm:^1.0.4": + version: 1.0.4 + resolution: "ssh-remote-port-forward@npm:1.0.4" + dependencies: + "@types/ssh2": "npm:^0.5.48" + ssh2: "npm:^1.4.0" + checksum: 10c0/33a441af12817577ea30d089b03c19f980d2fb2370933123a35026dc6be40f2dfce067e4dfc173e23d745464537ff647aa1bb7469be5571cc21f7cdb25181c09 + languageName: node + linkType: hard + +"ssh2@npm:^1.15.0, ssh2@npm:^1.4.0": + version: 1.17.0 + resolution: "ssh2@npm:1.17.0" + dependencies: + asn1: "npm:^0.2.6" + bcrypt-pbkdf: "npm:^1.0.2" + cpu-features: "npm:~0.0.10" + nan: "npm:^2.23.0" + dependenciesMeta: + cpu-features: + optional: true + nan: + optional: true + checksum: 10c0/637c1b7e8070fc8a3027f8abf771cd98419f56eaf3817171180e768004d4dea26c65fb3763294ed2f784429857f196c83c4f6889d2c31cc0e2648ea5ad730665 + languageName: node + linkType: hard + "ssri@npm:^10.0.0": version: 10.0.5 resolution: "ssri@npm:10.0.5" @@ -12305,9 +13097,9 @@ __metadata: linkType: hard "std-env@npm:^4.0.0-rc.1": - version: 4.1.0 - resolution: "std-env@npm:4.1.0" - checksum: 10c0/2e14b6b490db34cb969a48d9cf7c35bca4a47653914aac2814221baae7b867a5b15940d133625c391621971f98cd2266a5dc7036669960e883f1081db2a56558 + version: 4.0.0 + resolution: "std-env@npm:4.0.0" + checksum: 10c0/63b1716eae27947adde49e21b7225a0f75fb2c3d410273ae9de8333c07c7d5fc7a0628ae4c8af6b4b49b4274ed46c2bf118ed69b64f1261c9d8213d76ed1c16c languageName: node linkType: hard @@ -12328,6 +13120,17 @@ __metadata: languageName: node linkType: hard +"streamx@npm:^2.12.5, streamx@npm:^2.15.0, streamx@npm:^2.25.0": + version: 2.25.0 + resolution: "streamx@npm:2.25.0" + dependencies: + events-universal: "npm:^1.0.0" + fast-fifo: "npm:^1.3.2" + text-decoder: "npm:^1.1.0" + checksum: 10c0/1ecc4b722050e9088b99cde59d035e846ac97cedc3ef14a00b196d9c0b6f47d9fd18df454a19f56f0f586ab4f23fb7229069b9e8eaf22072a21bd9c909d4e0ea + languageName: node + linkType: hard + "strict-uri-encode@npm:^2.0.0": version: 2.0.0 resolution: "strict-uri-encode@npm:2.0.0" @@ -12342,7 +13145,7 @@ __metadata: languageName: node linkType: hard -"string-width-cjs@npm:string-width@^4.2.0, string-width@npm:^4.1.0": +"string-width-cjs@npm:string-width@^4.2.0, string-width@npm:^4.1.0, string-width@npm:^4.2.0, string-width@npm:^4.2.3": version: 4.2.3 resolution: "string-width@npm:4.2.3" dependencies: @@ -12489,7 +13292,7 @@ __metadata: languageName: node linkType: hard -"string_decoder@npm:^1.1.1": +"string_decoder@npm:^1.1.1, string_decoder@npm:^1.3.0": version: 1.3.0 resolution: "string_decoder@npm:1.3.0" dependencies: @@ -12498,6 +13301,15 @@ __metadata: languageName: node linkType: hard +"string_decoder@npm:~1.1.1": + version: 1.1.1 + resolution: "string_decoder@npm:1.1.1" + dependencies: + safe-buffer: "npm:~5.1.0" + checksum: 10c0/b4f89f3a92fd101b5653ca3c99550e07bdf9e13b35037e9e2a1c7b47cec4e55e06ff3fc468e314a0b5e80bfbaf65c1ca5a84978764884ae9413bec1fc6ca924e + languageName: node + linkType: hard + "strip-ansi-cjs@npm:strip-ansi@^6.0.1, strip-ansi@npm:^6.0.0, strip-ansi@npm:^6.0.1": version: 6.0.1 resolution: "strip-ansi@npm:6.0.1" @@ -12686,6 +13498,60 @@ __metadata: languageName: node linkType: hard +"tar-fs@npm:^2.1.4": + version: 2.1.4 + resolution: "tar-fs@npm:2.1.4" + dependencies: + chownr: "npm:^1.1.1" + mkdirp-classic: "npm:^0.5.2" + pump: "npm:^3.0.0" + tar-stream: "npm:^2.1.4" + checksum: 10c0/decb25acdc6839182c06ec83cba6136205bda1db984e120c8ffd0d80182bc5baa1d916f9b6c5c663ea3f9975b4dd49e3c6bb7b1707cbcdaba4e76042f43ec84c + languageName: node + linkType: hard + +"tar-fs@npm:^3.1.2": + version: 3.1.2 + resolution: "tar-fs@npm:3.1.2" + dependencies: + bare-fs: "npm:^4.0.1" + bare-path: "npm:^3.0.0" + pump: "npm:^3.0.0" + tar-stream: "npm:^3.1.5" + dependenciesMeta: + bare-fs: + optional: true + bare-path: + optional: true + checksum: 10c0/9dcbbbef9cdfc27f47651fe679f15952a6a8e6b3c9761c4bf3f416ace41cf462fb6292519bd3e041cadfcc0b89043a6bdecb46ff19f770b6864b77dcde7bad46 + languageName: node + linkType: hard + +"tar-stream@npm:^2.1.4": + version: 2.2.0 + resolution: "tar-stream@npm:2.2.0" + dependencies: + bl: "npm:^4.0.3" + end-of-stream: "npm:^1.4.1" + fs-constants: "npm:^1.0.0" + inherits: "npm:^2.0.3" + readable-stream: "npm:^3.1.1" + checksum: 10c0/2f4c910b3ee7196502e1ff015a7ba321ec6ea837667220d7bcb8d0852d51cb04b87f7ae471008a6fb8f5b1a1b5078f62f3a82d30c706f20ada1238ac797e7692 + languageName: node + linkType: hard + +"tar-stream@npm:^3.0.0, tar-stream@npm:^3.1.5": + version: 3.1.8 + resolution: "tar-stream@npm:3.1.8" + dependencies: + b4a: "npm:^1.6.4" + bare-fs: "npm:^4.5.5" + fast-fifo: "npm:^1.2.0" + streamx: "npm:^2.15.0" + checksum: 10c0/c4bf369de2302fcf30218d091167a5372ee79b69a1b5bb493ddb7714193ca805719558966334bab1f2775c8142826865f24e25459ff1c5f0a096bc3a3d5c5ce2 + languageName: node + linkType: hard + "tar@npm:7.5.13": version: 7.5.13 resolution: "tar@npm:7.5.13" @@ -12722,6 +13588,47 @@ __metadata: languageName: node linkType: hard +"teex@npm:^1.0.1": + version: 1.0.1 + resolution: "teex@npm:1.0.1" + dependencies: + streamx: "npm:^2.12.5" + checksum: 10c0/8df9166c037ba694b49d32a49858e314c60e513d55ac5e084dbf1ddbb827c5fa43cc389a81e87684419c21283308e9d68bb068798189c767ec4c252f890b8a77 + languageName: node + linkType: hard + +"testcontainers@npm:^11.14.0": + version: 11.14.0 + resolution: "testcontainers@npm:11.14.0" + dependencies: + "@balena/dockerignore": "npm:^1.0.2" + "@types/dockerode": "npm:^4.0.1" + archiver: "npm:^7.0.1" + async-lock: "npm:^1.4.1" + byline: "npm:^5.0.0" + debug: "npm:^4.4.3" + docker-compose: "npm:^1.4.2" + dockerode: "npm:^4.0.10" + get-port: "npm:^7.2.0" + proper-lockfile: "npm:^4.1.2" + properties-reader: "npm:^3.0.1" + ssh-remote-port-forward: "npm:^1.0.4" + tar-fs: "npm:^3.1.2" + tmp: "npm:^0.2.5" + undici: "npm:^7.24.5" + checksum: 10c0/a94294bb5f51a05c01252b7e0cdaa321696bed92a42d5d72e1467ae27d2a6547a63e287d8153b748dda3578df1ee08c1bf882919e6223ed3a26fefe91da88326 + languageName: node + linkType: hard + +"text-decoder@npm:^1.1.0": + version: 1.2.7 + resolution: "text-decoder@npm:1.2.7" + dependencies: + b4a: "npm:^1.6.4" + checksum: 10c0/929938ed154fbadb660a7f3d1aca30b7e53649a731af7583168fcfba0c158046325d35d945926e2a512bb62d1a49a7818151c987ea38b48853f01e1615722fc5 + languageName: node + linkType: hard + "text-hex@npm:1.0.x": version: 1.0.0 resolution: "text-hex@npm:1.0.0" @@ -12793,6 +13700,13 @@ __metadata: languageName: node linkType: hard +"tmp@npm:^0.2.5": + version: 0.2.5 + resolution: "tmp@npm:0.2.5" + checksum: 10c0/cee5bb7d674bb4ba3ab3f3841c2ca7e46daeb2109eec395c1ec7329a91d52fcb21032b79ac25161a37b2565c4858fefab927af9735926a113ef7bac9091a6e0e + languageName: node + linkType: hard + "to-regex-range@npm:^5.0.1": version: 5.0.1 resolution: "to-regex-range@npm:5.0.1" @@ -12865,6 +13779,13 @@ __metadata: languageName: node linkType: hard +"tslib@npm:^2.5.0, tslib@npm:^2.6.3, tslib@npm:^2.8.0, tslib@npm:^2.8.1": + version: 2.8.1 + resolution: "tslib@npm:2.8.1" + checksum: 10c0/9c4759110a19c53f992d9aae23aac5ced636e99887b51b9e61def52611732872ff7668757d4e4c61f19691e36f4da981cd9485e869b4a7408d689f6bf1f14e62 + languageName: node + linkType: hard + "tslib@npm:^2.6.0": version: 2.7.0 resolution: "tslib@npm:2.7.0" @@ -12872,13 +13793,6 @@ __metadata: languageName: node linkType: hard -"tslib@npm:^2.8.0, tslib@npm:^2.8.1": - version: 2.8.1 - resolution: "tslib@npm:2.8.1" - checksum: 10c0/9c4759110a19c53f992d9aae23aac5ced636e99887b51b9e61def52611732872ff7668757d4e4c61f19691e36f4da981cd9485e869b4a7408d689f6bf1f14e62 - languageName: node - linkType: hard - "tsscmp@npm:1.0.6": version: 1.0.6 resolution: "tsscmp@npm:1.0.6" @@ -12902,6 +13816,13 @@ __metadata: languageName: node linkType: hard +"tweetnacl@npm:^0.14.3": + version: 0.14.5 + resolution: "tweetnacl@npm:0.14.5" + checksum: 10c0/4612772653512c7bc19e61923fbf42903f5e0389ec76a4a1f17195859d114671ea4aa3b734c2029ce7e1fa7e5cc8b80580f67b071ecf0b46b5636d030a0102a2 + languageName: node + linkType: hard + "type-check@npm:^0.4.0, type-check@npm:~0.4.0": version: 0.4.0 resolution: "type-check@npm:0.4.0" @@ -13106,6 +14027,13 @@ __metadata: languageName: node linkType: hard +"undici-types@npm:~5.26.4": + version: 5.26.5 + resolution: "undici-types@npm:5.26.5" + checksum: 10c0/bb673d7876c2d411b6eb6c560e0c571eef4a01c1c19925175d16e3a30c4c428181fb8d7ae802a261f283e4166a0ac435e2f505743aa9e45d893f9a3df017b501 + languageName: node + linkType: hard + "undici-types@npm:~6.21.0": version: 6.21.0 resolution: "undici-types@npm:6.21.0" @@ -13120,6 +14048,13 @@ __metadata: languageName: node linkType: hard +"undici@npm:^7.24.5": + version: 7.24.8 + resolution: "undici@npm:7.24.8" + checksum: 10c0/5b3cb18b1c6ccff564c37390547b2f137c666ada5083af6d5b5671dc12f73530ae2872e16fab1e3948b46013fed7c81ed10bce23f7dbf21b73794244b70b7eea + languageName: node + linkType: hard + "unique-filename@npm:^3.0.0": version: 3.0.0 resolution: "unique-filename@npm:3.0.0" @@ -13187,6 +14122,13 @@ __metadata: languageName: node linkType: hard +"urlpattern-polyfill@npm:^10.0.0": + version: 10.1.0 + resolution: "urlpattern-polyfill@npm:10.1.0" + checksum: 10c0/5b124fd8d0ae920aa2a48b49a7a3b9ad1643b5ce7217b808fb6877826e751cabc01897fd4c85cd1989c4e729072b63aad5c3ba1c1325e4433e0d2f6329156bf1 + languageName: node + linkType: hard + "use-isomorphic-layout-effect@npm:^1.2.0": version: 1.2.0 resolution: "use-isomorphic-layout-effect@npm:1.2.0" @@ -13208,13 +14150,22 @@ __metadata: languageName: node linkType: hard -"util-deprecate@npm:^1.0.1": +"util-deprecate@npm:^1.0.1, util-deprecate@npm:~1.0.1": version: 1.0.2 resolution: "util-deprecate@npm:1.0.2" checksum: 10c0/41a5bdd214df2f6c3ecf8622745e4a366c4adced864bc3c833739791aeeeb1838119af7daed4ba36428114b5c67dcda034a79c882e97e43c03e66a4dd7389942 languageName: node linkType: hard +"uuid@npm:^10.0.0": + version: 10.0.0 + resolution: "uuid@npm:10.0.0" + bin: + uuid: dist/bin/uuid + checksum: 10c0/eab18c27fe4ab9fb9709a5d5f40119b45f2ec8314f8d4cf12ce27e4c6f4ffa4a6321dc7db6c515068fa373c075b49691ba969f0010bf37f44c37ca40cd6bf7fe + languageName: node + linkType: hard + "uuid@npm:^9.0.0, uuid@npm:^9.0.1": version: 9.0.1 resolution: "uuid@npm:9.0.1" @@ -13232,14 +14183,14 @@ __metadata: linkType: hard "vite@npm:^6.0.0 || ^7.0.0 || ^8.0.0": - version: 8.0.8 - resolution: "vite@npm:8.0.8" + version: 8.0.7 + resolution: "vite@npm:8.0.7" dependencies: fsevents: "npm:~2.3.3" lightningcss: "npm:^1.32.0" picomatch: "npm:^4.0.4" postcss: "npm:^8.5.8" - rolldown: "npm:1.0.0-rc.15" + rolldown: "npm:1.0.0-rc.13" tinyglobby: "npm:^0.2.15" peerDependencies: "@types/node": ^20.19.0 || >=22.12.0 @@ -13284,21 +14235,21 @@ __metadata: optional: true bin: vite: bin/vite.js - checksum: 10c0/63474b399612ccf087d0aa025d7eb5c0d675012b6257b7f64332ff39579d4af4d5d7f0ac330906fc99b101abbf592c756adf143bb5748a02aec08f7d3639054d + checksum: 10c0/88f8ec4e86275f32e88ae98df3bfda7e25f12e33e06b868b1abeee57740c9f043c9feaa3e5e993a903d6949e5cece358f7a527e6c19d9670d7401fded6d2f201 languageName: node linkType: hard "vitest@npm:^4.1.3": - version: 4.1.4 - resolution: "vitest@npm:4.1.4" - dependencies: - "@vitest/expect": "npm:4.1.4" - "@vitest/mocker": "npm:4.1.4" - "@vitest/pretty-format": "npm:4.1.4" - "@vitest/runner": "npm:4.1.4" - "@vitest/snapshot": "npm:4.1.4" - "@vitest/spy": "npm:4.1.4" - "@vitest/utils": "npm:4.1.4" + version: 4.1.3 + resolution: "vitest@npm:4.1.3" + dependencies: + "@vitest/expect": "npm:4.1.3" + "@vitest/mocker": "npm:4.1.3" + "@vitest/pretty-format": "npm:4.1.3" + "@vitest/runner": "npm:4.1.3" + "@vitest/snapshot": "npm:4.1.3" + "@vitest/spy": "npm:4.1.3" + "@vitest/utils": "npm:4.1.3" es-module-lexer: "npm:^2.0.0" expect-type: "npm:^1.3.0" magic-string: "npm:^0.30.21" @@ -13316,12 +14267,12 @@ __metadata: "@edge-runtime/vm": "*" "@opentelemetry/api": ^1.9.0 "@types/node": ^20.0.0 || ^22.0.0 || >=24.0.0 - "@vitest/browser-playwright": 4.1.4 - "@vitest/browser-preview": 4.1.4 - "@vitest/browser-webdriverio": 4.1.4 - "@vitest/coverage-istanbul": 4.1.4 - "@vitest/coverage-v8": 4.1.4 - "@vitest/ui": 4.1.4 + "@vitest/browser-playwright": 4.1.3 + "@vitest/browser-preview": 4.1.3 + "@vitest/browser-webdriverio": 4.1.3 + "@vitest/coverage-istanbul": 4.1.3 + "@vitest/coverage-v8": 4.1.3 + "@vitest/ui": 4.1.3 happy-dom: "*" jsdom: "*" vite: ^6.0.0 || ^7.0.0 || ^8.0.0 @@ -13352,7 +14303,7 @@ __metadata: optional: false bin: vitest: vitest.mjs - checksum: 10c0/a85288778cf6a6f0222aaac547fc84f917565ba78d1e32df4693226ec93aa8675f549b246b70913e9f1d80a87830b39843f9bd96b39d270e599ff4f71def6260 + checksum: 10c0/56f7d397ac7230df85e089402b17b2d53a621947db6d803ee6a1d168a841c7b5310e2e028aae747d8f4ba8357022124abab014e47b56aed2bcf9c241d9831369 languageName: node linkType: hard @@ -13552,7 +14503,7 @@ __metadata: languageName: node linkType: hard -"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0": +"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0, wrap-ansi@npm:^7.0.0": version: 7.0.0 resolution: "wrap-ansi@npm:7.0.0" dependencies: @@ -13585,6 +14536,13 @@ __metadata: languageName: node linkType: hard +"wrappy@npm:1": + version: 1.0.2 + resolution: "wrappy@npm:1.0.2" + checksum: 10c0/56fece1a4018c6a6c8e28fbc88c87e0fbf4ea8fd64fc6c63b18f4acc4bd13e0ad2515189786dd2c30d3eec9663d70f4ecf699330002f8ccb547e4a18231fc9f0 + languageName: node + linkType: hard + "write-file-atomic@npm:^7.0.0": version: 7.0.1 resolution: "write-file-atomic@npm:7.0.1" @@ -13653,6 +14611,13 @@ __metadata: languageName: node linkType: hard +"y18n@npm:^5.0.5": + version: 5.0.8 + resolution: "y18n@npm:5.0.8" + checksum: 10c0/4df2842c36e468590c3691c894bc9cdbac41f520566e76e24f59401ba7d8b4811eb1e34524d57e54bc6d864bcb66baab7ffd9ca42bf1eda596618f9162b91249 + languageName: node + linkType: hard + "yallist@npm:^3.0.2": version: 3.1.1 resolution: "yallist@npm:3.1.1" @@ -13681,6 +14646,15 @@ __metadata: languageName: node linkType: hard +"yaml@npm:^2.2.2": + version: 2.8.3 + resolution: "yaml@npm:2.8.3" + bin: + yaml: bin.mjs + checksum: 10c0/ddff0e11c1b467728d7eb4633db61c5f5de3d8e9373cf84d08fb0cdee03e1f58f02b9f1c51a4a8a865751695addbd465a77f73f1079be91fe5493b29c305fd77 + languageName: node + linkType: hard + "yaml@npm:^2.7.0": version: 2.7.1 resolution: "yaml@npm:2.7.1" @@ -13690,6 +14664,28 @@ __metadata: languageName: node linkType: hard +"yargs-parser@npm:^21.1.1": + version: 21.1.1 + resolution: "yargs-parser@npm:21.1.1" + checksum: 10c0/f84b5e48169479d2f402239c59f084cfd1c3acc197a05c59b98bab067452e6b3ea46d4dd8ba2985ba7b3d32a343d77df0debd6b343e5dae3da2aab2cdf5886b2 + languageName: node + linkType: hard + +"yargs@npm:^17.7.2": + version: 17.7.2 + resolution: "yargs@npm:17.7.2" + dependencies: + cliui: "npm:^8.0.1" + escalade: "npm:^3.1.1" + get-caller-file: "npm:^2.0.5" + require-directory: "npm:^2.1.1" + string-width: "npm:^4.2.3" + y18n: "npm:^5.0.5" + yargs-parser: "npm:^21.1.1" + checksum: 10c0/ccd7e723e61ad5965fffbb791366db689572b80cca80e0f96aad968dfff4156cd7cd1ad18607afe1046d8241e6fb2d6c08bf7fa7bfb5eaec818735d8feac8f05 + languageName: node + linkType: hard + "yocto-queue@npm:^0.1.0": version: 0.1.0 resolution: "yocto-queue@npm:0.1.0" @@ -13697,6 +14693,17 @@ __metadata: languageName: node linkType: hard +"zip-stream@npm:^6.0.1": + version: 6.0.1 + resolution: "zip-stream@npm:6.0.1" + dependencies: + archiver-utils: "npm:^5.0.0" + compress-commons: "npm:^6.0.2" + readable-stream: "npm:^4.0.0" + checksum: 10c0/50f2fb30327fb9d09879abf7ae2493705313adf403e794b030151aaae00009162419d60d0519e807673ec04d442e140c8879ca14314df0a0192de3b233e8f28b + languageName: node + linkType: hard + "zod-error@npm:1.5.0": version: 1.5.0 resolution: "zod-error@npm:1.5.0" From 5ec80eeac4ac1c40e7e49293ca22ea48d46d5f04 Mon Sep 17 00:00:00 2001 From: SandipBajracharya Date: Thu, 23 Apr 2026 10:52:18 +0545 Subject: [PATCH 2/7] test(OUT-3586): add addBreadcrumb to shared Sentry mock Integration tests were returning 400 because addSyncBreadcrumb in src/utils/sentry.ts calls Sentry.addBreadcrumb, which wasn't stubbed in the shared @sentry/nextjs mock. Co-Authored-By: Claude Opus 4.7 (1M context) --- test/integration/setup.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/test/integration/setup.ts b/test/integration/setup.ts index 0be864e1..a4d6a459 100644 --- a/test/integration/setup.ts +++ b/test/integration/setup.ts @@ -35,5 +35,6 @@ vi.mock('@sentry/nextjs', () => ({ ), captureException: vi.fn(), captureMessage: vi.fn(), + addBreadcrumb: vi.fn(), init: vi.fn(), })) From 87f50ac225e3c9fb0109402639fe6e4b2400614f Mon Sep 17 00:00:00 2001 From: SandipBajracharya Date: Fri, 24 Apr 2026 13:16:35 +0545 Subject: [PATCH 3/7] refactor(OUT-3586): nest priceCreated tests and extract shared helpers Move the six price.created integration tests into a priceCreated/ subfolder and extract shared setup into test/helpers/webhook.ts and test/helpers/priceCreatedTestSetup.ts so subsequent webhook suites can reuse the same scaffolding without duplicating mock-wiring and request boilerplate. Co-Authored-By: Claude Opus 4.7 (1M context) --- package.json | 1 - test/helpers/mocks.ts | 21 ++++-- test/helpers/priceCreatedTestSetup.ts | 46 ++++++++++++ test/helpers/seed.ts | 28 ++++++-- test/helpers/webhook.ts | 28 ++++++++ .../priceCreated/copilotNotFound.test.ts | 68 ++++++++++++++++++ .../quickbooks/priceCreated/flagOff.test.ts | 34 +++++++++ .../quickbooks/priceCreated/happyPath.test.ts | 59 ++++++++++++++++ .../priceCreated/idempotency.test.ts | 52 ++++++++++++++ .../priceCreated/multiPrice.test.ts | 70 +++++++++++++++++++ .../quickbooks/priceCreated/qbFailure.test.ts | 64 +++++++++++++++++ tsconfig.json | 3 +- yarn.lock | 1 - 13 files changed, 462 insertions(+), 13 deletions(-) create mode 100644 test/helpers/priceCreatedTestSetup.ts create mode 100644 test/helpers/webhook.ts create mode 100644 test/integration/quickbooks/priceCreated/copilotNotFound.test.ts create mode 100644 test/integration/quickbooks/priceCreated/flagOff.test.ts create mode 100644 test/integration/quickbooks/priceCreated/happyPath.test.ts create mode 100644 test/integration/quickbooks/priceCreated/idempotency.test.ts create mode 100644 test/integration/quickbooks/priceCreated/multiPrice.test.ts create mode 100644 test/integration/quickbooks/priceCreated/qbFailure.test.ts diff --git a/package.json b/package.json index 28ef7831..04a3070a 100644 --- a/package.json +++ b/package.json @@ -85,7 +85,6 @@ "postcss": "^8.5.3", "prettier": "^3.5.3", "tailwindcss": "^4.1.5", - "testcontainers": "^11.14.0", "tsx": "^4.21.0", "typescript": "^5.8.3", "vitest": "^4.1.3" diff --git a/test/helpers/mocks.ts b/test/helpers/mocks.ts index f6f3ab60..c32a8781 100644 --- a/test/helpers/mocks.ts +++ b/test/helpers/mocks.ts @@ -7,6 +7,19 @@ import { TEST_PORTAL_ID, } from './seed' +// Restricts override keys to the actual method names of the underlying class +// so typos produce a compile-time error. The Mock value type intentionally +// stays loose — tests routinely return shapes that don't match the real +// Promise return type. +type MockMethodOverrides = { + [K in keyof T as T[K] extends (...args: never[]) => unknown + ? K + : never]?: Mock +} + +type CopilotAPIOverrides = MockMethodOverrides +type IntuitAPIOverrides = MockMethodOverrides + /** * Factory for a mocked CopilotAPI instance. * @@ -14,9 +27,7 @@ import { * wire each `new CopilotAPI(token)` call to an object produced by this factory. * Override any method via the `overrides` arg to tailor behavior per test. */ -export function createMockCopilotAPI( - overrides: Partial> = {}, -) { +export function createMockCopilotAPI(overrides: CopilotAPIOverrides = {}) { return { getTokenPayload: vi.fn().mockResolvedValue({ workspaceId: TEST_PORTAL_ID, @@ -42,9 +53,7 @@ export function createMockCopilotAPI( * - getAnAccount returns an active income account matching the seeded ref * - createItem returns a freshly-created QB item */ -export function createMockIntuitAPI( - overrides: Partial> = {}, -) { +export function createMockIntuitAPI(overrides: IntuitAPIOverrides = {}) { return { getAnItem: vi.fn().mockResolvedValue(undefined), getAnAccount: vi.fn().mockResolvedValue({ diff --git a/test/helpers/priceCreatedTestSetup.ts b/test/helpers/priceCreatedTestSetup.ts new file mode 100644 index 00000000..c5c60a8c --- /dev/null +++ b/test/helpers/priceCreatedTestSetup.ts @@ -0,0 +1,46 @@ +import { beforeEach, afterEach, vi } from 'vitest' +import { truncateAllTestTables } from '@test/helpers/testDb' +import { + installMockApis, + type MockCopilotAPI, + type MockIntuitAPI, +} from '@test/helpers/mocks' + +type InstallOpts = Parameters[0] + +export interface PriceCreatedTestHandle { + copilot: MockCopilotAPI + intuit: MockIntuitAPI +} + +/** + * Registers the standard `beforeEach` (truncate + installMockApis) and + * `afterEach` (clearAllMocks) hooks used by every price.created integration + * test. Returns a live handle whose `copilot` / `intuit` properties are + * replaced with fresh mock instances before each test. + * + * The `optsFactory` is invoked once per test so callers can supply overrides + * whose underlying `vi.fn()`s are freshly instantiated — a static opts object + * would be broken by the `vi.clearAllMocks()` call in afterEach. + */ +export function setupPriceCreatedTest( + optsFactory?: () => InstallOpts, +): PriceCreatedTestHandle { + const handle = {} as PriceCreatedTestHandle + + beforeEach(async () => { + await truncateAllTestTables() + const { copilot, intuit } = installMockApis(optsFactory?.()) + handle.copilot = copilot + handle.intuit = intuit + }) + + afterEach(() => { + // clearAllMocks (not restoreAllMocks) — the module-level mock factories in + // test/integration/setup.ts must stay installed across tests; we only want + // to reset call counts and implementations set in beforeEach. + vi.clearAllMocks() + }) + + return handle +} diff --git a/test/helpers/seed.ts b/test/helpers/seed.ts index d7a77c95..5cb3a5d1 100644 --- a/test/helpers/seed.ts +++ b/test/helpers/seed.ts @@ -1,13 +1,12 @@ +import type { InferInsertModel } from 'drizzle-orm' import type { z } from 'zod' import { db } from '@/db' import { QBPortalConnection, QBPortalConnectionCreateSchema, } from '@/db/schema/qbPortalConnections' -import { - QBSetting, - QBSettingCreateSchema, -} from '@/db/schema/qbSettings' +import { QBProductSync } from '@/db/schema/qbProductSync' +import { QBSetting, QBSettingCreateSchema } from '@/db/schema/qbSettings' export const TEST_PORTAL_ID = 'test-portal-00000001' export const TEST_REALM_ID = 'test-realm-123' @@ -17,6 +16,7 @@ export const TEST_INCOME_ACCOUNT_REF = '100' export const TEST_ASSET_ACCOUNT_REF = '101' export const TEST_EXPENSE_ACCOUNT_REF = '102' export const TEST_INTERNAL_USER_ID = 'test-internal-user-id' +export const TEST_WEBHOOK_TOKEN = 'test-token-xyz' // Override types are derived from the Drizzle-generated insert schemas so // they stay in sync with the DB schema automatically. Using `Partial` @@ -24,6 +24,7 @@ export const TEST_INTERNAL_USER_ID = 'test-internal-user-id' // type changes in the underlying schema. type PortalOverrides = Partial> type SettingOverrides = Partial> +type ProductSyncOverrides = Partial> const basePortalConnection: z.infer = { portalId: TEST_PORTAL_ID, @@ -65,6 +66,25 @@ export async function seedSetting(overrides: SettingOverrides = {}) { return row } +const baseProductSync: InferInsertModel = { + portalId: TEST_PORTAL_ID, + productId: '2cf93cf0-45fa-485f-b584-03c2c38a3999', + priceId: 'C-wch-eSg', + name: 'Test Product', + copilotName: 'Test Product', + unitPrice: '60000.00', + qbItemId: '999', + qbSyncToken: '0', +} + +export async function seedProductSync(overrides: ProductSyncOverrides = {}) { + const [row] = await db + .insert(QBProductSync) + .values({ ...baseProductSync, ...overrides }) + .returning() + return row +} + /** * Convenience seeder for the common "healthy portal" fixture used by * most tests. Returns both rows for assertions if needed. diff --git a/test/helpers/webhook.ts b/test/helpers/webhook.ts new file mode 100644 index 00000000..d575beae --- /dev/null +++ b/test/helpers/webhook.ts @@ -0,0 +1,28 @@ +import { testApiHandler } from 'next-test-api-route-handler' +import * as appHandler from '@/app/api/quickbooks/webhook/route' +import { TEST_WEBHOOK_TOKEN } from '@test/helpers/seed' + +/** + * Posts a JSON payload to the QuickBooks webhook route through + * `next-test-api-route-handler` and returns the Response. The caller is + * responsible for asserting on status / body — this helper never asserts. + */ +export async function postWebhook( + payload: unknown, + opts: { token?: string } = {}, +): Promise { + const token = opts.token ?? TEST_WEBHOOK_TOKEN + let response!: Response + await testApiHandler({ + appHandler, + url: `/api/quickbooks/webhook?token=${token}`, + test: async ({ fetch }) => { + response = await fetch({ + method: 'POST', + body: JSON.stringify(payload), + headers: { 'content-type': 'application/json' }, + }) + }, + }) + return response +} diff --git a/test/integration/quickbooks/priceCreated/copilotNotFound.test.ts b/test/integration/quickbooks/priceCreated/copilotNotFound.test.ts new file mode 100644 index 00000000..9bcc3eea --- /dev/null +++ b/test/integration/quickbooks/priceCreated/copilotNotFound.test.ts @@ -0,0 +1,68 @@ +import { describe, it, expect, vi } from 'vitest' +import { eq } from 'drizzle-orm' + +import { db } from '@/db' +import { QBProductSync } from '@/db/schema/qbProductSync' +import { QBSyncLog } from '@/db/schema/qbSyncLogs' +import { EntityType, EventType, LogStatus } from '@/app/api/core/types/log' + +import priceCreatedPayload from '@test/fixtures/priceCreated.webhook.json' +import { seedHealthyPortal, TEST_PORTAL_ID } from '@test/helpers/seed' +import { createMockCopilotAPI } from '@test/helpers/mocks' +import { setupPriceCreatedTest } from '@test/helpers/priceCreatedTestSetup' +import { postWebhook } from '@test/helpers/webhook' + +/** + * Copilot product not found (deleted between webhook firing and handler + * running, or stale cache). ProductService throws APIError(404). The + * transaction rolls back, and the outer catch in WebhookService writes a + * FAILED sync log. + */ +describe('POST /api/quickbooks/webhook — price.created (copilot product 404)', () => { + const apis = setupPriceCreatedTest(() => ({ + copilot: createMockCopilotAPI({ + // Real CopilotAPI.getProduct returns undefined when the product + // doesn't exist; the service treats that as a 404. + getProduct: vi.fn().mockResolvedValue(undefined), + }), + })) + + it('writes a FAILED sync log and never touches QB', async () => { + await seedHealthyPortal() + + const res = await postWebhook(priceCreatedPayload) + expect(res.status).toBe(200) + + // Pin down that the 404 path actually went through Copilot — a future + // refactor that returns early before calling getProduct would otherwise + // still pass the "no QB calls" assertions below. + expect(apis.copilot.getProduct).toHaveBeenCalledWith( + priceCreatedPayload.data.productId, + ) + + // The 404 is raised BEFORE any QB call + expect(apis.intuit.getAnItem).not.toHaveBeenCalled() + expect(apis.intuit.createItem).not.toHaveBeenCalled() + + // No mapping row + const productRows = await db.select().from(QBProductSync) + expect(productRows).toHaveLength(0) + + // FAILED sync log + const failedLogs = await db + .select() + .from(QBSyncLog) + .where(eq(QBSyncLog.copilotPriceId, priceCreatedPayload.data.id)) + + expect(failedLogs).toHaveLength(1) + expect(failedLogs[0]).toMatchObject({ + portalId: TEST_PORTAL_ID, + entityType: EntityType.PRODUCT, + eventType: EventType.CREATED, + status: LogStatus.FAILED, + copilotId: priceCreatedPayload.data.productId, + copilotPriceId: priceCreatedPayload.data.id, + }) + expect(failedLogs[0].errorMessage).toMatch(/Product not found/i) + }) +}) diff --git a/test/integration/quickbooks/priceCreated/flagOff.test.ts b/test/integration/quickbooks/priceCreated/flagOff.test.ts new file mode 100644 index 00000000..a44d84fc --- /dev/null +++ b/test/integration/quickbooks/priceCreated/flagOff.test.ts @@ -0,0 +1,34 @@ +import { describe, it, expect } from 'vitest' + +import { db } from '@/db' +import { QBProductSync } from '@/db/schema/qbProductSync' +import { QBSyncLog } from '@/db/schema/qbSyncLogs' + +import priceCreatedPayload from '@test/fixtures/priceCreated.webhook.json' +import { seedHealthyPortal } from '@test/helpers/seed' +import { setupPriceCreatedTest } from '@test/helpers/priceCreatedTestSetup' +import { postWebhook } from '@test/helpers/webhook' + +describe('POST /api/quickbooks/webhook — price.created (createNewProductFlag=false)', () => { + const apis = setupPriceCreatedTest() + + it('returns 200 without syncing, makes no product API calls, writes no rows', async () => { + await seedHealthyPortal({ setting: { createNewProductFlag: false } }) + + const res = await postWebhook(priceCreatedPayload) + expect(res.status).toBe(200) + + // The flag gate sits BEFORE the switch in WebhookService#handleWebhookEvent, + // so no product-side API calls fire. + expect(apis.copilot.getProduct).not.toHaveBeenCalled() + expect(apis.intuit.getAnItem).not.toHaveBeenCalled() + expect(apis.intuit.createItem).not.toHaveBeenCalled() + + // And no mapping / sync log rows should exist. + const productRows = await db.select().from(QBProductSync) + expect(productRows).toHaveLength(0) + + const logRows = await db.select().from(QBSyncLog) + expect(logRows).toHaveLength(0) + }) +}) diff --git a/test/integration/quickbooks/priceCreated/happyPath.test.ts b/test/integration/quickbooks/priceCreated/happyPath.test.ts new file mode 100644 index 00000000..fdad39fa --- /dev/null +++ b/test/integration/quickbooks/priceCreated/happyPath.test.ts @@ -0,0 +1,59 @@ +import { describe, it, expect } from 'vitest' +import { eq } from 'drizzle-orm' + +import { db } from '@/db' +import { QBProductSync } from '@/db/schema/qbProductSync' +import { QBSyncLog } from '@/db/schema/qbSyncLogs' +import { EntityType, EventType, LogStatus } from '@/app/api/core/types/log' + +import priceCreatedPayload from '@test/fixtures/priceCreated.webhook.json' +import { seedHealthyPortal, TEST_PORTAL_ID } from '@test/helpers/seed' +import { setupPriceCreatedTest } from '@test/helpers/priceCreatedTestSetup' +import { postWebhook } from '@test/helpers/webhook' + +describe('POST /api/quickbooks/webhook — price.created (happy path)', () => { + setupPriceCreatedTest() + + it('creates the QB item, writes qb_product_sync row, and logs SUCCESS', async () => { + await seedHealthyPortal() + + const res = await postWebhook(priceCreatedPayload) + expect(res.status).toBe(200) + await expect(res.json()).resolves.toEqual({ ok: true }) + + // ---- Assert the product mapping was persisted ---- + const productSyncRows = await db + .select() + .from(QBProductSync) + .where(eq(QBProductSync.priceId, priceCreatedPayload.data.id)) + + expect(productSyncRows).toHaveLength(1) + expect(productSyncRows[0]).toMatchObject({ + portalId: TEST_PORTAL_ID, + productId: priceCreatedPayload.data.productId, + priceId: priceCreatedPayload.data.id, + qbItemId: '999', + qbSyncToken: '0', + // price is stored in cents as a decimal string + unitPrice: '60000.00', + copilotName: 'Test Product', + }) + + // ---- Assert a SUCCESS sync log was written ---- + const syncLogs = await db + .select() + .from(QBSyncLog) + .where(eq(QBSyncLog.copilotPriceId, priceCreatedPayload.data.id)) + + expect(syncLogs).toHaveLength(1) + expect(syncLogs[0]).toMatchObject({ + portalId: TEST_PORTAL_ID, + entityType: EntityType.PRODUCT, + eventType: EventType.CREATED, + status: LogStatus.SUCCESS, + copilotId: priceCreatedPayload.data.productId, + copilotPriceId: priceCreatedPayload.data.id, + quickbooksId: '999', + }) + }) +}) diff --git a/test/integration/quickbooks/priceCreated/idempotency.test.ts b/test/integration/quickbooks/priceCreated/idempotency.test.ts new file mode 100644 index 00000000..87c35bd7 --- /dev/null +++ b/test/integration/quickbooks/priceCreated/idempotency.test.ts @@ -0,0 +1,52 @@ +import { describe, it, expect } from 'vitest' + +import { db } from '@/db' +import { QBProductSync } from '@/db/schema/qbProductSync' +import { QBSyncLog } from '@/db/schema/qbSyncLogs' + +import priceCreatedPayload from '@test/fixtures/priceCreated.webhook.json' +import { seedHealthyPortal, seedProductSync } from '@test/helpers/seed' +import { setupPriceCreatedTest } from '@test/helpers/priceCreatedTestSetup' +import { postWebhook } from '@test/helpers/webhook' + +/** + * Idempotency: re-sending the same price.created webhook must not create a + * duplicate mapping. ProductService#webhookPriceCreated short-circuits when it + * finds an existing qb_product_sync row with the same productId AND priceId. + */ +describe('POST /api/quickbooks/webhook — price.created (idempotency)', () => { + const apis = setupPriceCreatedTest() + + it('skips QB calls and writes no new rows when the price is already mapped', async () => { + await seedHealthyPortal() + + // Pre-existing mapping for THIS exact productId + priceId. + // Direct insert intentionally bypasses ProductService.createQBProduct so + // the test doesn't exercise a second request path; if the duplicate-check + // logic ever starts depending on extra fields (description, copilotName), + // this seed may need to match those shape requirements. + await seedProductSync({ + productId: priceCreatedPayload.data.productId, + priceId: priceCreatedPayload.data.id, + qbItemId: 'pre-existing-qb-item', + }) + + const res = await postWebhook(priceCreatedPayload) + expect(res.status).toBe(200) + + // Duplicate check runs BEFORE copilot.getProduct and any QB call, so + // none of these external calls should fire at all. + expect(apis.copilot.getProduct).not.toHaveBeenCalled() + expect(apis.intuit.getAnItem).not.toHaveBeenCalled() + expect(apis.intuit.createItem).not.toHaveBeenCalled() + + // Still only one mapping row — the one we seeded — with its original qbItemId + const productRows = await db.select().from(QBProductSync) + expect(productRows).toHaveLength(1) + expect(productRows[0].qbItemId).toBe('pre-existing-qb-item') + + // And no sync log row (early return skips logging) + const logRows = await db.select().from(QBSyncLog) + expect(logRows).toHaveLength(0) + }) +}) diff --git a/test/integration/quickbooks/priceCreated/multiPrice.test.ts b/test/integration/quickbooks/priceCreated/multiPrice.test.ts new file mode 100644 index 00000000..5896a297 --- /dev/null +++ b/test/integration/quickbooks/priceCreated/multiPrice.test.ts @@ -0,0 +1,70 @@ +import { describe, it, expect } from 'vitest' +import { eq } from 'drizzle-orm' + +import { db } from '@/db' +import { QBProductSync } from '@/db/schema/qbProductSync' + +import priceCreatedPayload from '@test/fixtures/priceCreated.webhook.json' +import { seedHealthyPortal, seedProductSync } from '@test/helpers/seed' +import { setupPriceCreatedTest } from '@test/helpers/priceCreatedTestSetup' +import { postWebhook } from '@test/helpers/webhook' + +/** + * Multi-price: when a product already has a price mapped to QB, a new price + * for the SAME product gets a " (N)" suffix on the QB item name so the two + * QB items are distinguishable (QB item names must be unique per company). + * + * N = number of existing mappings for that productId. + */ +describe('POST /api/quickbooks/webhook — price.created (second price for same product)', () => { + // Copilot mock is installed (required for auth + getProduct) but this test + // does not assert on it directly — behavior is visible via the QB item name. + const apis = setupPriceCreatedTest() + + it('suffixes the new QB item name with " (1)" and inserts a new mapping row', async () => { + await seedHealthyPortal() + + // Existing mapping: same productId, DIFFERENT priceId (first price already mapped) + const existingPriceId = 'C-existing-price-id' + await seedProductSync({ + productId: priceCreatedPayload.data.productId, + priceId: existingPriceId, + unitPrice: '10000.00', + qbItemId: 'qb-item-first', + }) + + const res = await postWebhook(priceCreatedPayload) + expect(res.status).toBe(200) + + // The QB lookup + create should both use the suffixed name + const suffixedName = 'Test Product (1)' + expect(apis.intuit.getAnItem).toHaveBeenCalledWith( + suffixedName, + undefined, + true, + ) + expect(apis.intuit.createItem).toHaveBeenCalledTimes(1) + expect(apis.intuit.createItem).toHaveBeenCalledWith( + expect.objectContaining({ + Name: suffixedName, + UnitPrice: 600, // 60000 cents / 100 + }), + ) + + // Two mapping rows now exist; the new one carries the suffixed name + const allRows = await db.select().from(QBProductSync) + expect(allRows).toHaveLength(2) + + const newRow = await db + .select() + .from(QBProductSync) + .where(eq(QBProductSync.priceId, priceCreatedPayload.data.id)) + expect(newRow).toHaveLength(1) + expect(newRow[0]).toMatchObject({ + productId: priceCreatedPayload.data.productId, + priceId: priceCreatedPayload.data.id, + name: suffixedName, + qbItemId: '999', + }) + }) +}) diff --git a/test/integration/quickbooks/priceCreated/qbFailure.test.ts b/test/integration/quickbooks/priceCreated/qbFailure.test.ts new file mode 100644 index 00000000..85b5da3e --- /dev/null +++ b/test/integration/quickbooks/priceCreated/qbFailure.test.ts @@ -0,0 +1,64 @@ +import { describe, it, expect, vi } from 'vitest' +import { eq } from 'drizzle-orm' + +import { db } from '@/db' +import { QBProductSync } from '@/db/schema/qbProductSync' +import { QBSyncLog } from '@/db/schema/qbSyncLogs' +import { EntityType, EventType, LogStatus } from '@/app/api/core/types/log' + +import priceCreatedPayload from '@test/fixtures/priceCreated.webhook.json' +import { seedHealthyPortal, TEST_PORTAL_ID } from '@test/helpers/seed' +import { createMockIntuitAPI } from '@test/helpers/mocks' +import { setupPriceCreatedTest } from '@test/helpers/priceCreatedTestSetup' +import { postWebhook } from '@test/helpers/webhook' + +/** + * QB createItem failure: when the QB call fails inside the transaction, + * the DB transaction rolls back (no qb_product_sync row, no SUCCESS log), + * but the outer catch in WebhookService#handlePriceCreated writes a FAILED + * sync log OUTSIDE the transaction so the incident is recorded. + */ +describe('POST /api/quickbooks/webhook — price.created (QB createItem fails)', () => { + const apis = setupPriceCreatedTest(() => ({ + intuit: createMockIntuitAPI({ + createItem: vi.fn().mockRejectedValue(new Error('QuickBooks is on fire')), + }), + })) + + it('rolls back the tx, inserts no mapping row, and writes a FAILED sync log', async () => { + await seedHealthyPortal() + + const res = await postWebhook(priceCreatedPayload) + // The service swallows the error and returns ok:true so Copilot doesn't + // retry. The failure is observable only via qb_sync_logs. + expect(res.status).toBe(200) + + // Order-of-operations regression guard: we got far enough to fetch the + // Copilot product and attempt a QB item creation before the failure. + expect(apis.copilot.getProduct).toHaveBeenCalledWith( + priceCreatedPayload.data.productId, + ) + expect(apis.intuit.createItem).toHaveBeenCalledTimes(1) + + // Transaction must have rolled back — no mapping row written + const productRows = await db.select().from(QBProductSync) + expect(productRows).toHaveLength(0) + + // FAILED log exists (written outside the tx in the catch block) + const failedLogs = await db + .select() + .from(QBSyncLog) + .where(eq(QBSyncLog.copilotPriceId, priceCreatedPayload.data.id)) + + expect(failedLogs).toHaveLength(1) + expect(failedLogs[0]).toMatchObject({ + portalId: TEST_PORTAL_ID, + entityType: EntityType.PRODUCT, + eventType: EventType.CREATED, + status: LogStatus.FAILED, + copilotId: priceCreatedPayload.data.productId, + copilotPriceId: priceCreatedPayload.data.id, + }) + expect(failedLogs[0].errorMessage).toContain('QuickBooks is on fire') + }) +}) diff --git a/tsconfig.json b/tsconfig.json index d042c2bd..75d6f1ce 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -19,7 +19,8 @@ } ], "paths": { - "@/*": ["./src/*"] + "@/*": ["./src/*"], + "@test/*": ["./test/*"] } }, "include": [ diff --git a/yarn.lock b/yarn.lock index f461a7c9..b1dadd53 100644 --- a/yarn.lock +++ b/yarn.lock @@ -6278,7 +6278,6 @@ __metadata: supabase: "npm:2.84.4" swr: "npm:^2.3.3" tailwindcss: "npm:^4.1.5" - testcontainers: "npm:^11.14.0" tsx: "npm:^4.21.0" typescript: "npm:^5.8.3" vitest: "npm:^4.1.3" From 3f1c027039e9a99dcd1aeba354588cb2a92b5882 Mon Sep 17 00:00:00 2001 From: SandipBajracharya Date: Fri, 24 Apr 2026 13:31:23 +0545 Subject: [PATCH 4/7] fix(OUT-3586): skip dotenv.config under Vitest to prevent .env leakage src/config/index.ts unconditionally loaded .env on import, which backfilled any env var not stubbed in .env.test from the developer's local .env file during test runs. Harmless for mocked integration tests but a real risk for the upcoming nightly smoke tests (OUT-3649) that hit real QuickBooks and Copilot APIs. Guard the dotenv call on NODE_ENV !== 'test' so tests only see what globalSetup loads explicitly. Co-Authored-By: Claude Opus 4.7 (1M context) --- src/config/index.ts | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/config/index.ts b/src/config/index.ts index dcefff4c..66e6194d 100644 --- a/src/config/index.ts +++ b/src/config/index.ts @@ -2,7 +2,12 @@ import { EnvironmentType } from 'intuit-oauth' import dotenv from 'dotenv' -dotenv.config() +// Skip loading .env under Vitest so test runs can't silently inherit developer +// creds from the local .env file. Test envs are loaded explicitly by +// test/integration/globalSetup.ts from .env.test. +if (process.env.NODE_ENV !== 'test') { + dotenv.config() +} export const copilotDashboardUrl = process.env.NEXT_PUBLIC_COPILOT_DASHBOARD_URL || '' From 968aa291e9195416237f7b12d25183dd5168ca90 Mon Sep 17 00:00:00 2001 From: SandipBajracharya Date: Fri, 24 Apr 2026 13:39:35 +0545 Subject: [PATCH 5/7] docs(OUT-3586): correct globalSetup comment referencing Vitest config MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replace the stale singleFork=true reference with the actual mechanism — pool: 'forks' + fileParallelism: false — so a future maintainer searching the config for singleFork doesn't come up empty. Co-Authored-By: Claude Opus 4.7 (1M context) --- test/integration/globalSetup.ts | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/test/integration/globalSetup.ts b/test/integration/globalSetup.ts index 22cd1d5d..4397f811 100644 --- a/test/integration/globalSetup.ts +++ b/test/integration/globalSetup.ts @@ -20,9 +20,9 @@ import postgres from 'postgres' * - Stop the container on teardown * * Env var propagation: Vitest spawns worker processes AFTER globalSetup resolves, - * so process.env set here is inherited by workers. Combined with singleFork=true - * in vitest.config.ts, this gives us one container shared across all integration - * test files. + * so process.env set here is inherited by workers. Combined with `pool: 'forks'` + * and `fileParallelism: false` in vitest.config.ts, this gives us one container + * shared across all integration test files. */ const __dirname = path.dirname(fileURLToPath(import.meta.url)) @@ -52,8 +52,11 @@ export default async function globalSetup() { console.info('[globalSetup] Running Drizzle migrations...') const migrationClient = postgres(url, { max: 1, prepare: false }) const migrationDb = drizzle(migrationClient) - await migrate(migrationDb, { migrationsFolder: MIGRATIONS_FOLDER }) - await migrationClient.end() + try { + await migrate(migrationDb, { migrationsFolder: MIGRATIONS_FOLDER }) + } finally { + await migrationClient.end() + } console.info(`[globalSetup] Ready: ${url}`) From a99e01bb0bc88d11c6dc9c81b473d00c5a7b1ceb Mon Sep 17 00:00:00 2001 From: SandipBajracharya Date: Fri, 24 Apr 2026 14:33:35 +0545 Subject: [PATCH 6/7] chore(OUT-3586): lint fix --- test/helpers/mocks.ts | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/test/helpers/mocks.ts b/test/helpers/mocks.ts index c32a8781..0142a28f 100644 --- a/test/helpers/mocks.ts +++ b/test/helpers/mocks.ts @@ -95,10 +95,12 @@ export type MockIntuitAPI = ReturnType * both sites touch would reflect the sum of both call sites. Same applies to * IntuitAPI if/when it gets instantiated more than once per request. */ -export function installMockApis(opts: { - copilot?: MockCopilotAPI - intuit?: MockIntuitAPI -} = {}): { copilot: MockCopilotAPI; intuit: MockIntuitAPI } { +export function installMockApis( + opts: { + copilot?: MockCopilotAPI + intuit?: MockIntuitAPI + } = {}, +): { copilot: MockCopilotAPI; intuit: MockIntuitAPI } { const copilot = opts.copilot ?? createMockCopilotAPI() const intuit = opts.intuit ?? createMockIntuitAPI() @@ -108,9 +110,7 @@ export function installMockApis(opts: { return copilot as unknown as CopilotAPI } as unknown as typeof CopilotAPI) - vi.mocked(IntuitAPI).mockImplementation(function ( - this: unknown, - ): IntuitAPI { + vi.mocked(IntuitAPI).mockImplementation(function (this: unknown): IntuitAPI { return intuit as unknown as IntuitAPI } as unknown as typeof IntuitAPI) From 577334393cc101589a30aad6a4ce61f8a6ba211b Mon Sep 17 00:00:00 2001 From: SandipBajracharya Date: Fri, 24 Apr 2026 16:28:18 +0545 Subject: [PATCH 7/7] fix(OUT-3586): seed tokenSetTime so tests skip real Intuit OAuth refresh Without tokenSetTime, isTokenFresh() returns false and getValidQbTokens triggers a real HTTP call to Intuit's OAuth endpoint, which rejects the stub INTUIT_CLIENT_ID with invalid_client and fails every price.created integration test with a 400. Seeding tokenSetTime keeps the token in the fresh window so the refresh path is skipped entirely. Co-Authored-By: Claude Opus 4.7 (1M context) --- test/helpers/seed.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/test/helpers/seed.ts b/test/helpers/seed.ts index 5cb3a5d1..dee07274 100644 --- a/test/helpers/seed.ts +++ b/test/helpers/seed.ts @@ -31,6 +31,8 @@ const basePortalConnection: z.infer = { intuitRealmId: TEST_REALM_ID, accessToken: TEST_ACCESS_TOKEN, refreshToken: TEST_REFRESH_TOKEN, + // Keeps `isTokenFresh` true so tests don't trigger a real Intuit OAuth call. + tokenSetTime: new Date(), expiresIn: 3600, XRefreshTokenExpiresIn: 8_726_400, intiatedBy: TEST_INTERNAL_USER_ID,