@geekmidas/constructs 10.0.0-alpha.87 → 10.0.0-alpha.88

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- {"version":3,"file":"testing.cjs","names":["EnvironmentParser","ServiceDiscovery","http","TEST_CONTEXT_HEADER","Hono","ServiceDiscovery","EnvironmentParser","createObjectHeaders","createCookieHeaderAccessor","runWithRequestContext","ForbiddenError","DefaultAuditor","executeWithAuditTransaction","ResponseBuilder","Endpoint","publishConstructEvents","ServiceDiscovery","EnvironmentParser","FunctionBuilder","DefaultAuditor","runWithRequestContext","publishEvents","ServiceDiscovery","EnvironmentParser","runWithRequestContext","ServiceDiscovery","EnvironmentParser","runWithRequestContext","fileURLToPath","readFileSync","existsSync","tls","TestBrowser","setupServer","installContextFetch","randomUUID","TransactionRegistry","ServiceDiscovery","runInTestContext","test","EnvironmentParser","Endpoint","KyselyDatabase","BetterAuth","Email","isConsumable","Topic","Queue","provideKey","createMailbox","runAsServer","currentTestContext","http","hono","Hono","serviceContext","testContextOf","faker"],"sources":["../../src/testing/peer.ts","../../src/endpoints/MswEndpointAdaptor.ts","../../src/endpoints/TestEndpointAdaptor.ts","../../src/functions/TestFunctionAdaptor.ts","../../src/queue/TestQueueAdaptor.ts","../../src/subscribers/TestSubscriberAdaptor.ts","../../src/testing/manifest.ts","../../src/testing/featureTest.ts"],"sourcesContent":["/**\n * The TCP peer a test's in-process requests arrive from.\n *\n * A feature test hands a request straight to a surface's Hono app — no\n * socket, no server — so the app's bindings have no peer to read. Deployed,\n * every request has one, and what a surface trusts follows from it: the auth\n * server honours `x-gkm-client-ip` only from an internal caller, a loopback\n * or private peer with no `Origin` and no forwarding header. With no peer at\n * all the header was dropped, and every test's session check became the same\n * client to Better Auth's rate limiter.\n *\n * So an in-process dispatch says where it came from, the way\n * `@hono/node-server` does: its bindings carry `incoming.socket.remoteAddress`.\n * The address is loopback because that is the truth — the request came from\n * this process. A browser's own address still travels in its\n * `x-forwarded-for`, which makes it outside traffic exactly as it would be\n * behind the stack's proxy.\n *\n * Only a test's dispatch passes these. A runtime with no socket of its own\n * (Lambda, Bun) still has no peer, and a request with no peer is still not an\n * internal caller's.\n */\n\n/** The address an in-process request presents as its peer. */\nexport const IN_PROCESS_PEER_ADDRESS = '127.0.0.1';\n\n/** The part of `@hono/node-server`'s bindings a surface reads its peer from. */\nexport interface InProcessBindings {\n\tincoming: { socket: { remoteAddress: string } };\n}\n\n/** Bindings for `app.fetch(request, bindings)` from inside this process. */\nexport function inProcessBindings(): InProcessBindings {\n\treturn { incoming: { socket: { remoteAddress: IN_PROCESS_PEER_ADDRESS } } };\n}\n","import { EnvironmentParser } from '@geekmidas/envkit';\nimport type { Service } from '@geekmidas/services';\nimport { ServiceDiscovery } from '@geekmidas/services';\nimport { TEST_CONTEXT_HEADER } from '@geekmidas/testkit/context';\nimport { Hono } from 'hono';\nimport { type HttpHandler, http } from 'msw';\nimport { inProcessBindings } from '../testing/peer';\nimport type { Endpoint } from './Endpoint';\nimport { HonoEndpoint } from './HonoEndpointAdaptor';\n\n/**\n * Header used to identify which test context a request belongs to — defined\n * once, in testkit, where the stamped `fetch` that writes it lives.\n */\nexport { TEST_CONTEXT_HEADER };\n\n/**\n * Per-test context containing an isolated ServiceDiscovery instance.\n * Registered in the context map and looked up per-request via the context ID header.\n */\nexport interface MswTestContext {\n\tserviceDiscovery: ServiceDiscovery<any>;\n}\n\n/**\n * Options for creating MSW handlers from endpoint constructs.\n *\n * @example\n * ```typescript\n * import { createMswHandlers, registerTestContext } from '@geekmidas/constructs/testing';\n * import { setupServer } from 'msw/node';\n *\n * // Create handlers once (global)\n * const { handlers, registerContext, removeContext } = createMswHandlers(\n * [getUsers, createUser],\n * { baseURL: 'http://localhost:3000' },\n * );\n * const server = setupServer(...handlers);\n *\n * // Per test: register an isolated context with its own services/transaction\n * it('should list users', async ({ db }) => {\n * const contextId = crypto.randomUUID();\n * registerContext(contextId, {\n * services: { database: db, auth: mockAuth },\n * });\n *\n * const api = createApi({\n * baseURL: 'http://localhost:3000',\n * headers: { [TEST_CONTEXT_HEADER]: contextId },\n * });\n *\n * const result = await api('GET /users');\n * expect(result).toBeDefined();\n *\n * removeContext(contextId);\n * });\n * ```\n */\nexport interface CreateMswHandlersOptions {\n\t/** Base URL the client fetches from (e.g., 'http://localhost:3000') */\n\tbaseURL: string;\n}\n\n/**\n * Options for registering a per-test context.\n * Follows the same pattern as TestRequestAdaptor — services, database and\n * auditorStorage are provided explicitly. A topic is a service under its own\n * name, so a recorder in `services` (`{ users: recorder }`) captures what an\n * endpoint publishes to it.\n */\nexport interface RegisterContextOptions {\n\t/** Service instances keyed by serviceName */\n\tservices?: Record<string, unknown>;\n\t/** Database instance — required when endpoints use .database() */\n\tdatabase?: unknown;\n\t/** Audit storage instance — required when endpoints use .auditor() */\n\tauditorStorage?: unknown;\n}\n\nconst MSW_HTTP_METHODS = [\n\t'get',\n\t'post',\n\t'put',\n\t'patch',\n\t'delete',\n\t'options',\n] as const;\n\ntype MswHttpMethod = (typeof MSW_HTTP_METHODS)[number];\n\n/**\n * Result of creating MSW handlers from endpoint constructs.\n */\nexport interface CreateMswHandlersResult {\n\t/** MSW handlers to pass to setupServer() */\n\thandlers: HttpHandler[];\n\t/** Register an isolated context for a test */\n\tregisterContext: (id: string, options: RegisterContextOptions) => void;\n}\n\n/**\n * Creates MSW HTTP handlers from endpoint constructs.\n *\n * Mounts endpoints on a Hono app and creates MSW handlers that intercept\n * fetch requests and route them through `app.request()` — giving frontend\n * tests full endpoint behavior (validation, auth, sessions) without HTTP.\n *\n * Each test registers its own isolated context via `registerContext()`,\n * which is resolved per-request using the `x-test-context-id` header.\n * This allows concurrent tests with their own transactions and services.\n *\n * @param endpoints - Array of endpoint constructs to create handlers for\n * @param options - Configuration including baseURL\n * @returns MSW handlers, the Hono app, and context management functions\n */\nexport function createMswHandlers(\n\tendpoints: Endpoint<any, any, any, any, any, any>[],\n\toptions: CreateMswHandlersOptions,\n): CreateMswHandlersResult {\n\tconst { baseURL } = options;\n\tconst contexts = new Map<string, MswTestContext>();\n\n\t/**\n\t * Register an isolated context for a test.\n\t * Creates a fresh ServiceDiscovery and pre-registers all provided services.\n\t */\n\tfunction registerContext(id: string, ctxOptions: RegisterContextOptions) {\n\t\tconst envParser = new EnvironmentParser({});\n\t\tconst serviceDiscovery = new ServiceDiscovery(envParser);\n\n\t\tconst serviceDefs: Service[] = [];\n\n\t\t// Register explicit services\n\t\tif (ctxOptions.services) {\n\t\t\tfor (const [name, instance] of Object.entries(ctxOptions.services)) {\n\t\t\t\tserviceDefs.push({\n\t\t\t\t\tserviceName: name,\n\t\t\t\t\tregister: () => instance,\n\t\t\t\t} as Service);\n\t\t\t}\n\t\t}\n\n\t\t// Register database service from endpoint metadata\n\t\tif (ctxOptions.database !== undefined) {\n\t\t\tfor (const endpoint of endpoints) {\n\t\t\t\tif (endpoint.databaseService) {\n\t\t\t\t\tserviceDefs.push({\n\t\t\t\t\t\tserviceName: endpoint.databaseService.serviceName,\n\t\t\t\t\t\tregister: () => ctxOptions.database,\n\t\t\t\t\t} as Service);\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// Register auditor storage service from endpoint metadata\n\t\tif (ctxOptions.auditorStorage !== undefined) {\n\t\t\tfor (const endpoint of endpoints) {\n\t\t\t\tif (endpoint.auditorStorageService) {\n\t\t\t\t\tserviceDefs.push({\n\t\t\t\t\t\tserviceName: endpoint.auditorStorageService.serviceName,\n\t\t\t\t\t\tregister: () => ctxOptions.auditorStorage,\n\t\t\t\t\t} as Service);\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tif (serviceDefs.length > 0) {\n\t\t\tserviceDiscovery.register(serviceDefs);\n\t\t}\n\n\t\tcontexts.set(id, { serviceDiscovery });\n\t}\n\n\t// Create a Hono app per-request that uses the correct ServiceDiscovery.\n\t// We use a wrapper app that resolves the context from the header,\n\t// then delegates to a context-specific Hono app.\n\tconst handlers: HttpHandler[] = [];\n\n\tfor (const endpoint of endpoints) {\n\t\tconst method = endpoint.method.toLowerCase() as MswHttpMethod;\n\t\tif (!MSW_HTTP_METHODS.includes(method)) continue;\n\n\t\tconst mswUrl = `${baseURL}${endpoint.route}`;\n\t\tconst mswMethod = http[method];\n\n\t\thandlers.push(\n\t\t\tmswMethod(mswUrl, async ({ request }) => {\n\t\t\t\tconst contextId = request.headers.get(TEST_CONTEXT_HEADER);\n\t\t\t\tconst ctx = contextId ? contexts.get(contextId) : undefined;\n\n\t\t\t\tif (!ctx) {\n\t\t\t\t\treturn new Response(\n\t\t\t\t\t\tJSON.stringify({\n\t\t\t\t\t\t\terror: 'Missing or unknown test context ID',\n\t\t\t\t\t\t\thint: `Set the '${TEST_CONTEXT_HEADER}' header to a registered context ID`,\n\t\t\t\t\t\t}),\n\t\t\t\t\t\t{ status: 500, headers: { 'content-type': 'application/json' } },\n\t\t\t\t\t);\n\t\t\t\t}\n\n\t\t\t\t// Build a fresh Hono app with this context's ServiceDiscovery\n\t\t\t\tconst app = new Hono();\n\t\t\t\tHonoEndpoint.addRoute(endpoint, ctx.serviceDiscovery as any, app);\n\n\t\t\t\t// From this process: a loopback peer, as a socket on this machine has.\n\t\t\t\tconst response = await app.request(\n\t\t\t\t\trequest,\n\t\t\t\t\tundefined,\n\t\t\t\t\tinProcessBindings(),\n\t\t\t\t);\n\n\t\t\t\treturn new Response(response.body, {\n\t\t\t\t\tstatus: response.status,\n\t\t\t\t\tstatusText: response.statusText,\n\t\t\t\t\theaders: response.headers,\n\t\t\t\t});\n\t\t\t}),\n\t\t);\n\t}\n\n\treturn {\n\t\thandlers,\n\t\tregisterContext,\n\t};\n}\n","import type {\n\tAuditActor,\n\tAuditableAction,\n\tAuditStorage,\n} from '@geekmidas/audit';\nimport { DefaultAuditor } from '@geekmidas/audit';\nimport { EnvironmentParser } from '@geekmidas/envkit';\nimport { ForbiddenError } from '@geekmidas/errors';\nimport type { EventPublisher } from '@geekmidas/events';\nimport type { Logger } from '@geekmidas/logger';\nimport type {\n\tInferComposableStandardSchema,\n\tInferStandardSchema,\n} from '@geekmidas/schema';\nimport {\n\trunWithRequestContext,\n\ttype Service,\n\tServiceDiscovery,\n\ttype ServiceRecord,\n} from '@geekmidas/services';\nimport type { StandardSchemaV1 } from '@standard-schema/spec';\nimport { publishConstructEvents } from '../publisher';\nimport type { HttpMethod } from '../types';\nimport type { MappedAudit } from './audit';\nimport {\n\ttype CookieOptions,\n\tEndpoint,\n\ttype EndpointSchemas,\n\tResponseBuilder,\n} from './Endpoint';\nimport {\n\tcreateCookieHeaderAccessor,\n\tcreateObjectHeaders,\n} from './lazyAccessors';\nimport {\n\ttype AuditExecutionContext,\n\texecuteWithAuditTransaction,\n} from './processAudits';\n\nexport type TestHttpResponse<TBody = any> = {\n\tbody: TBody;\n\tstatus: number;\n\theaders: Record<string, string | string[]>;\n};\n\n/**\n * Serializes a cookie into a Set-Cookie header string\n */\nfunction serializeCookie(\n\tname: string,\n\tvalue: string,\n\toptions?: CookieOptions,\n): string {\n\tlet cookieString = `${name}=${value}`;\n\n\tif (options) {\n\t\tif (options.maxAge !== undefined) {\n\t\t\tcookieString += `; Max-Age=${options.maxAge}`;\n\t\t}\n\t\tif (options.expires) {\n\t\t\tcookieString += `; Expires=${options.expires.toUTCString()}`;\n\t\t}\n\t\tif (options.domain) {\n\t\t\tcookieString += `; Domain=${options.domain}`;\n\t\t}\n\t\tif (options.path) {\n\t\t\tcookieString += `; Path=${options.path}`;\n\t\t}\n\t\tif (options.httpOnly) {\n\t\t\tcookieString += '; HttpOnly';\n\t\t}\n\t\tif (options.secure) {\n\t\t\tcookieString += '; Secure';\n\t\t}\n\t\tif (options.sameSite) {\n\t\t\tcookieString += `; SameSite=${options.sameSite}`;\n\t\t}\n\t}\n\n\treturn cookieString;\n}\n\nexport class TestEndpointAdaptor<\n\tTRoute extends string,\n\tTMethod extends HttpMethod,\n\tTInput extends EndpointSchemas = {},\n\tTOutSchema extends StandardSchemaV1 | undefined = undefined,\n\tTServices extends Service[] = [],\n\tTLogger extends Logger = Logger,\n\tTSession = unknown,\n\tTAuditStorage extends AuditStorage | undefined = undefined,\n\tTAuditStorageServiceName extends string = string,\n\tTAuditAction extends AuditableAction<string, unknown> = AuditableAction<\n\t\tstring,\n\t\tunknown\n\t>,\n\tTDatabase = undefined,\n\tTDatabaseServiceName extends string = string,\n> {\n\tstatic getDefaultServiceDiscover<\n\t\tTRoute extends string,\n\t\tTMethod extends HttpMethod,\n\t\tTInput extends EndpointSchemas = {},\n\t\tTOutSchema extends StandardSchemaV1 | undefined = undefined,\n\t\tTServices extends Service[] = [],\n\t\tTLogger extends Logger = Logger,\n\t\tTSession = unknown,\n\t\tTAuditStorage extends AuditStorage | undefined = undefined,\n\t\tTAuditStorageServiceName extends string = string,\n\t\tTAuditAction extends AuditableAction<string, unknown> = AuditableAction<\n\t\t\tstring,\n\t\t\tunknown\n\t\t>,\n\t\tTDatabase = undefined,\n\t\tTDatabaseServiceName extends string = string,\n\t>(\n\t\t_endpoint: Endpoint<\n\t\t\tTRoute,\n\t\t\tTMethod,\n\t\t\tTInput,\n\t\t\tTOutSchema,\n\t\t\tTServices,\n\t\t\tTLogger,\n\t\t\tTSession,\n\t\t\tTAuditStorage,\n\t\t\tTAuditStorageServiceName,\n\t\t\tTAuditAction,\n\t\t\tTDatabase,\n\t\t\tTDatabaseServiceName\n\t\t>,\n\t) {\n\t\treturn ServiceDiscovery.getInstance(new EnvironmentParser({}));\n\t}\n\tconstructor(\n\t\tprivate readonly endpoint: Endpoint<\n\t\t\tTRoute,\n\t\t\tTMethod,\n\t\t\tTInput,\n\t\t\tTOutSchema,\n\t\t\tTServices,\n\t\t\tTLogger,\n\t\t\tTSession,\n\t\t\tTAuditStorage,\n\t\t\tTAuditStorageServiceName,\n\t\t\tTAuditAction,\n\t\t\tTDatabase,\n\t\t\tTDatabaseServiceName\n\t\t>,\n\t\tprivate serviceDiscovery: ServiceDiscovery<any> = TestEndpointAdaptor.getDefaultServiceDiscover(\n\t\t\tendpoint,\n\t\t),\n\t) {}\n\n\tasync fullRequest(\n\t\tctx: TestRequestAdaptor<\n\t\t\tTInput,\n\t\t\tTServices,\n\t\t\tTAuditStorage,\n\t\t\tTAuditStorageServiceName,\n\t\t\tTDatabase,\n\t\t\tTDatabaseServiceName\n\t\t>,\n\t): Promise<TestHttpResponse<InferStandardSchema<TOutSchema>>> {\n\t\tconst body = await this.endpoint.parseInput((ctx as any).body, 'body');\n\t\tconst query = await this.endpoint.parseInput((ctx as any).query, 'query');\n\t\tconst params = await this.endpoint.parseInput(\n\t\t\t(ctx as any).params,\n\t\t\t'params',\n\t\t);\n\n\t\t// Lazy accessors - defer parsing until needed\n\t\tconst header = createObjectHeaders(ctx.headers);\n\t\tconst cookie = createCookieHeaderAccessor(ctx.headers.cookie);\n\n\t\t// Request context setup\n\t\tconst startTime = Date.now();\n\t\tconst requestId =\n\t\t\t(ctx as any).requestId ??\n\t\t\tctx.headers['x-request-id'] ??\n\t\t\tcrypto.randomUUID();\n\n\t\tconst logger = this.endpoint.logger.child({\n\t\t\trequestId,\n\t\t\troute: this.endpoint.route,\n\t\t\thost: ctx.headers.host,\n\t\t\tmethod: this.endpoint.method,\n\t\t}) as TLogger;\n\n\t\t// Get database from context for session extraction\n\t\tconst rawDb = (ctx as any).database as TDatabase;\n\n\t\t// Wrap handler execution in request context\n\t\tconst operation = `${this.endpoint.method} ${this.endpoint.route}`;\n\t\treturn runWithRequestContext(\n\t\t\t{ logger, requestId, startTime, operation },\n\t\t\tasync () => {\n\t\t\t\tconst session = await this.endpoint.getSession({\n\t\t\t\t\tlogger,\n\t\t\t\t\tservices: ctx.services,\n\t\t\t\t\theader,\n\t\t\t\t\tcookie,\n\t\t\t\t\t...(rawDb !== undefined && { db: rawDb }),\n\t\t\t\t} as any);\n\n\t\t\t\t// Check authorization\n\t\t\t\tconst isAuthorized = await this.endpoint.authorize({\n\t\t\t\t\theader,\n\t\t\t\t\tcookie,\n\t\t\t\t\tservices: ctx.services,\n\t\t\t\t\tlogger,\n\t\t\t\t\tsession,\n\t\t\t\t\t...(rawDb !== undefined && { db: rawDb }),\n\t\t\t\t\tbody,\n\t\t\t\t\tquery,\n\t\t\t\t\tparams,\n\t\t\t\t} as any);\n\n\t\t\t\tif (!isAuthorized) {\n\t\t\t\t\tlogger.warn('Forbidden access attempt');\n\t\t\t\t\tthrow new ForbiddenError(\n\t\t\t\t\t\t'Forbidden access to the endpoint',\n\t\t\t\t\t\t'You do not have permission to access this resource.',\n\t\t\t\t\t);\n\t\t\t\t}\n\n\t\t\t\t// Create audit context if audit storage is provided\n\t\t\t\t// The auditorStorage instance is required when endpoint uses .auditor()\n\t\t\t\tconst auditorStorage = (ctx as any).auditorStorage as TAuditStorage;\n\t\t\t\tlet auditContext: AuditExecutionContext<TAuditAction> | undefined;\n\n\t\t\t\tif (auditorStorage) {\n\t\t\t\t\t// Extract actor if configured\n\t\t\t\t\tlet actor: AuditActor = { id: 'system', type: 'system' };\n\t\t\t\t\tif (this.endpoint.actorExtractor) {\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\tactor = await this.endpoint.actorExtractor({\n\t\t\t\t\t\t\t\tservices: ctx.services as any,\n\t\t\t\t\t\t\t\tsession,\n\t\t\t\t\t\t\t\theader,\n\t\t\t\t\t\t\t\tcookie,\n\t\t\t\t\t\t\t\tlogger,\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t} catch (error) {\n\t\t\t\t\t\t\tlogger.error(\n\t\t\t\t\t\t\t\terror as Error,\n\t\t\t\t\t\t\t\t'Failed to extract actor for audits',\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\tconst auditor = new DefaultAuditor<TAuditAction>({\n\t\t\t\t\t\tactor,\n\t\t\t\t\t\tstorage: auditorStorage as AuditStorage,\n\t\t\t\t\t\tmetadata: {\n\t\t\t\t\t\t\tendpoint: this.endpoint.route,\n\t\t\t\t\t\t\tmethod: this.endpoint.method,\n\t\t\t\t\t\t},\n\t\t\t\t\t});\n\n\t\t\t\t\tauditContext = { auditor, storage: auditorStorage as AuditStorage };\n\t\t\t\t}\n\n\t\t\t\t// Warn if declarative audits are configured but no audit storage\n\t\t\t\tconst audits = this.endpoint.audits as MappedAudit<\n\t\t\t\t\tTAuditAction,\n\t\t\t\t\tTOutSchema\n\t\t\t\t>[];\n\t\t\t\tif (!auditContext && audits?.length) {\n\t\t\t\t\tlogger.warn('No auditor storage service available');\n\t\t\t\t}\n\n\t\t\t\t// Execute handler with automatic audit transaction support\n\t\t\t\tconst result = await executeWithAuditTransaction(\n\t\t\t\t\tauditContext,\n\t\t\t\t\tasync (auditor) => {\n\t\t\t\t\t\t// Use audit transaction as db if available (when storage has same database)\n\t\t\t\t\t\t// For testing, the tester controls whether to use transactional auditing\n\t\t\t\t\t\tconst trx = auditor?.getTransaction?.();\n\t\t\t\t\t\tconst db = trx ?? rawDb;\n\n\t\t\t\t\t\tconst responseBuilder = new ResponseBuilder();\n\t\t\t\t\t\tconst response = await this.endpoint.handler(\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tbody,\n\t\t\t\t\t\t\t\tquery,\n\t\t\t\t\t\t\t\tparams,\n\t\t\t\t\t\t\t\tsession,\n\t\t\t\t\t\t\t\tservices: ctx.services,\n\t\t\t\t\t\t\t\tlogger,\n\t\t\t\t\t\t\t\theader,\n\t\t\t\t\t\t\t\tcookie,\n\t\t\t\t\t\t\t\tauditor,\n\t\t\t\t\t\t\t\tdb,\n\t\t\t\t\t\t\t} as any,\n\t\t\t\t\t\t\tresponseBuilder,\n\t\t\t\t\t\t);\n\n\t\t\t\t\t\t// Check if response has metadata\n\t\t\t\t\t\tlet data = response;\n\t\t\t\t\t\tlet metadata = responseBuilder.getMetadata();\n\n\t\t\t\t\t\tif (Endpoint.hasMetadata(response)) {\n\t\t\t\t\t\t\tdata = response.data;\n\t\t\t\t\t\t\tmetadata = response.metadata;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tconst output = await this.endpoint.parseOutput(data);\n\n\t\t\t\t\t\treturn { output, metadata, responseBuilder };\n\t\t\t\t\t},\n\t\t\t\t\t// Process declarative audits after handler (inside transaction)\n\t\t\t\t\tasync (result, auditor) => {\n\t\t\t\t\t\tif (!audits?.length) return;\n\n\t\t\t\t\t\tfor (const audit of audits) {\n\t\t\t\t\t\t\tif (audit.when && !audit.when(result.output as any)) {\n\t\t\t\t\t\t\t\tcontinue;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tconst payload = audit.payload(result.output as any);\n\t\t\t\t\t\t\tconst entityId = audit.entityId?.(result.output as any);\n\t\t\t\t\t\t\tauditor.audit(audit.type as any, payload as any, {\n\t\t\t\t\t\t\t\ttable: audit.table,\n\t\t\t\t\t\t\t\tentityId,\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t}\n\t\t\t\t\t},\n\t\t\t\t\t// Pass rawDb so storage can reuse existing transactions\n\t\t\t\t\t{ db: rawDb },\n\t\t\t\t);\n\n\t\t\t\tconst { output, metadata } = result;\n\n\t\t\t\t// A topic the test handed in as a service — a recorder — is published\n\t\t\t\t// to directly; any other is registered as it is deployed.\n\t\t\t\tawait publishConstructEvents(\n\t\t\t\t\tthis.endpoint,\n\t\t\t\t\toutput,\n\t\t\t\t\tthis.serviceDiscovery,\n\t\t\t\t\tthis.endpoint.logger,\n\t\t\t\t\tctx.services as Record<string, unknown>,\n\t\t\t\t);\n\n\t\t\t\t// Convert cookies to Set-Cookie headers\n\t\t\t\tconst headers: Record<string, string | string[]> = {\n\t\t\t\t\t...(metadata.headers || {}),\n\t\t\t\t};\n\n\t\t\t\tif (metadata.cookies && metadata.cookies.size > 0) {\n\t\t\t\t\tconst setCookieValues: string[] = [];\n\t\t\t\t\tfor (const [name, cookie] of metadata.cookies.entries()) {\n\t\t\t\t\t\tsetCookieValues.push(\n\t\t\t\t\t\t\tserializeCookie(name, cookie.value, cookie.options),\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t\theaders['set-cookie'] = setCookieValues;\n\t\t\t\t}\n\n\t\t\t\t// Return HTTP response format\n\t\t\t\treturn {\n\t\t\t\t\tbody: output,\n\t\t\t\t\tstatus: metadata.status || 200,\n\t\t\t\t\theaders,\n\t\t\t\t};\n\t\t\t},\n\t\t);\n\t}\n\n\tasync request(\n\t\tctx: TestRequestAdaptor<\n\t\t\tTInput,\n\t\t\tTServices,\n\t\t\tTAuditStorage,\n\t\t\tTAuditStorageServiceName,\n\t\t\tTDatabase,\n\t\t\tTDatabaseServiceName\n\t\t>,\n\t): Promise<InferStandardSchema<TOutSchema>> {\n\t\tconst response = await this.fullRequest(ctx);\n\t\treturn response.body;\n\t}\n}\n\n/**\n * Conditional audit storage requirement - required when TAuditStorage is configured\n */\ntype AuditStorageRequirement<\n\tTAuditStorage extends AuditStorage | undefined = undefined,\n> = TAuditStorage extends undefined\n\t? {}\n\t: {\n\t\t\t/** Audit storage instance - required when endpoint uses .auditor() */\n\t\t\tauditorStorage: TAuditStorage;\n\t\t};\n\n/**\n * Conditional database requirement - required when TDatabase is configured\n */\ntype DatabaseRequirement<TDatabase = undefined> = TDatabase extends undefined\n\t? {}\n\t: {\n\t\t\t/** Database instance - required when endpoint uses .database() */\n\t\t\tdatabase: TDatabase;\n\t\t};\n\nexport type TestRequestAdaptor<\n\tTInput extends EndpointSchemas = {},\n\tTServices extends Service[] = [],\n\tTAuditStorage extends AuditStorage | undefined = undefined,\n\t_TAuditStorageServiceName extends string = string,\n\tTDatabase = undefined,\n\t_TDatabaseServiceName extends string = string,\n> = {\n\tservices: ServiceRecord<TServices>;\n\theaders: Record<string, string>;\n} & InferComposableStandardSchema<TInput> &\n\tAuditStorageRequirement<TAuditStorage> &\n\tDatabaseRequirement<TDatabase>;\n","import type { AuditableAction, Auditor, AuditStorage } from '@geekmidas/audit';\nimport { DefaultAuditor } from '@geekmidas/audit';\nimport { EnvironmentParser } from '@geekmidas/envkit';\nimport type { EventPublisher } from '@geekmidas/events';\nimport type { Logger } from '@geekmidas/logger';\nimport type {\n\tComposableStandardSchema,\n\tInferComposableStandardSchema,\n\tInferStandardSchema,\n} from '@geekmidas/schema';\nimport {\n\trunWithRequestContext,\n\ttype Service,\n\tServiceDiscovery,\n\ttype ServiceRecord,\n} from '@geekmidas/services';\nimport type { StandardSchemaV1 } from '@standard-schema/spec';\nimport { publishEvents } from '../publisher';\nimport type { Function } from './Function';\nimport { FunctionBuilder } from './FunctionBuilder';\n\nexport class TestFunctionAdaptor<\n\tTInput extends ComposableStandardSchema | undefined = undefined,\n\tTOutSchema extends StandardSchemaV1 | undefined = undefined,\n\tTServices extends Service[] = [],\n\tTLogger extends Logger = Logger,\n\tTAuditStorage extends AuditStorage | undefined = undefined,\n\tTAuditStorageServiceName extends string = string,\n\tTDatabase = undefined,\n\tTDatabaseServiceName extends string = string,\n\tTAuditAction extends AuditableAction<string, unknown> = AuditableAction<\n\t\tstring,\n\t\tunknown\n\t>,\n> {\n\tstatic getDefaultServiceDiscovery<\n\t\tTInput extends ComposableStandardSchema | undefined = undefined,\n\t\tTOutSchema extends StandardSchemaV1 | undefined = undefined,\n\t\tTServices extends Service[] = [],\n\t\tTLogger extends Logger = Logger,\n\t\tTAuditStorage extends AuditStorage | undefined = undefined,\n\t\tTAuditStorageServiceName extends string = string,\n\t\tTDatabase = undefined,\n\t\tTDatabaseServiceName extends string = string,\n\t\tTAuditAction extends AuditableAction<string, unknown> = AuditableAction<\n\t\t\tstring,\n\t\t\tunknown\n\t\t>,\n\t>(\n\t\t_fn: Function<\n\t\t\tTInput,\n\t\t\tTServices,\n\t\t\tTLogger,\n\t\t\tTOutSchema,\n\t\t\tTAuditStorage,\n\t\t\tTAuditStorageServiceName,\n\t\t\tTDatabase,\n\t\t\tTDatabaseServiceName,\n\t\t\tTAuditAction,\n\t\t\tany\n\t\t>,\n\t) {\n\t\treturn ServiceDiscovery.getInstance(new EnvironmentParser({}));\n\t}\n\n\tconstructor(\n\t\tprivate readonly fn: Function<\n\t\t\tTInput,\n\t\t\tTServices,\n\t\t\tTLogger,\n\t\t\tTOutSchema,\n\t\t\tTAuditStorage,\n\t\t\tTAuditStorageServiceName,\n\t\t\tTDatabase,\n\t\t\tTDatabaseServiceName,\n\t\t\tTAuditAction,\n\t\t\tany\n\t\t>,\n\t\tprivate serviceDiscovery: ServiceDiscovery<any> = TestFunctionAdaptor.getDefaultServiceDiscovery(\n\t\t\tfn,\n\t\t),\n\t) {}\n\n\tasync invoke(\n\t\tctx: TestFunctionRequest<TInput, TServices, TDatabase, TAuditAction>,\n\t): Promise<InferStandardSchema<TOutSchema>> {\n\t\t// Parse input if schema is provided\n\n\t\tconst parsedInput = await FunctionBuilder.parseComposableStandardSchema(\n\t\t\tctx.input,\n\t\t\tthis.fn.input,\n\t\t);\n\n\t\t// Create logger with context\n\t\tconst logger = this.fn.logger.child({\n\t\t\ttest: true,\n\t\t}) as TLogger;\n\n\t\t// Register services (use provided services or register from function)\n\t\tlet services: ServiceRecord<TServices>;\n\t\tif (ctx.services) {\n\t\t\tservices = ctx.services;\n\t\t} else {\n\t\t\tservices = await this.serviceDiscovery.register(this.fn.services);\n\t\t}\n\n\t\t// Resolve database (use provided db or register from function)\n\t\tlet db: TDatabase | undefined;\n\t\tif ('db' in ctx && ctx.db !== undefined) {\n\t\t\tdb = ctx.db;\n\t\t} else if (this.fn.databaseService) {\n\t\t\tconst dbServices = await this.serviceDiscovery.register([\n\t\t\t\tthis.fn.databaseService,\n\t\t\t]);\n\t\t\tdb = dbServices[\n\t\t\t\tthis.fn.databaseService.serviceName as keyof typeof dbServices\n\t\t\t] as TDatabase;\n\t\t}\n\n\t\t// Resolve auditor (use provided auditor or create from function)\n\t\tlet auditor: Auditor<TAuditAction> | undefined;\n\t\tif ('auditor' in ctx && ctx.auditor !== undefined) {\n\t\t\tauditor = ctx.auditor;\n\t\t} else if (this.fn.auditorStorageService) {\n\t\t\tconst auditServices = await this.serviceDiscovery.register([\n\t\t\t\tthis.fn.auditorStorageService,\n\t\t\t]);\n\t\t\tconst storage = auditServices[\n\t\t\t\tthis.fn.auditorStorageService.serviceName as keyof typeof auditServices\n\t\t\t] as AuditStorage;\n\n\t\t\tauditor = new DefaultAuditor<TAuditAction>({\n\t\t\t\tactor: { id: 'system', type: 'system' },\n\t\t\t\tstorage,\n\t\t\t\tmetadata: {\n\t\t\t\t\tfunction: this.fn.type,\n\t\t\t\t\ttest: true,\n\t\t\t\t},\n\t\t\t});\n\t\t}\n\n\t\t// Wrap execution in request context for service access via context.getLogger()\n\t\tconst requestId = `test-${Date.now()}`;\n\t\tconst startTime = Date.now();\n\n\t\treturn runWithRequestContext({ logger, requestId, startTime }, async () => {\n\t\t\t// Execute the function\n\t\t\tconst response = await this.fn.fn({\n\t\t\t\tinput: parsedInput,\n\t\t\t\tservices,\n\t\t\t\tlogger,\n\t\t\t\tdb,\n\t\t\t\tauditor,\n\t\t\t} as any);\n\n\t\t\t// Parse output if schema is provided\n\t\t\tconst output = await this.fn.parseOutput(response);\n\n\t\t\t// Flush audits if any were recorded\n\t\t\tif (auditor) {\n\t\t\t\tconst records = auditor.getRecords();\n\t\t\t\tif (records.length > 0) {\n\t\t\t\t\tlogger.debug(\n\t\t\t\t\t\t{ auditCount: records.length },\n\t\t\t\t\t\t'Flushing function audits',\n\t\t\t\t\t);\n\t\t\t\t\tawait auditor.flush();\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// A topic the test handed in as a service — a recorder — is published\n\t\t\t// to directly, as `TestEndpointAdaptor` does.\n\t\t\tawait publishEvents(\n\t\t\t\tlogger,\n\t\t\t\tthis.serviceDiscovery,\n\t\t\t\tthis.fn.events,\n\t\t\t\toutput,\n\t\t\t\tservices as Record<string, unknown>,\n\t\t\t);\n\n\t\t\treturn output;\n\t\t}) as Promise<InferStandardSchema<TOutSchema>>;\n\t}\n}\n\nexport type TestFunctionRequest<\n\tTInput extends ComposableStandardSchema | undefined = undefined,\n\tTServices extends Service[] = [],\n\tTDatabase = undefined,\n\tTAuditAction extends AuditableAction<string, unknown> = AuditableAction<\n\t\tstring,\n\t\tunknown\n\t>,\n> = {\n\tinput: InferComposableStandardSchema<TInput>;\n\tservices: ServiceRecord<TServices>;\n\tdb?: TDatabase;\n\tauditor?: Auditor<TAuditAction>;\n} & InferComposableStandardSchema<{ input: TInput }>;\n","import { EnvironmentParser } from '@geekmidas/envkit';\nimport type { Logger } from '@geekmidas/logger';\nimport type { InferStandardSchema } from '@geekmidas/schema';\nimport type { Service, ServiceRecord } from '@geekmidas/services';\nimport { runWithRequestContext, ServiceDiscovery } from '@geekmidas/services';\nimport type { StandardSchemaV1 } from '@standard-schema/spec';\nimport type { Queue, QueueContext } from './Queue';\n\n/**\n * In-memory test driver for a {@link Queue} worker. Hand it a batch of messages\n * and it registers the queue's services, runs the handler in a request context,\n * and returns the handler result — no SQS/pg-boss required. A queue with a\n * database gets `db` registered from it, or the one the request passes.\n *\n * @example\n * const adapter = new TestQueueAdaptor(ordersQueue);\n * await adapter.invoke({ messages: [{ orderId: '123' }] });\n */\nexport class TestQueueAdaptor<\n\tTName extends string = string,\n\tTMessage extends StandardSchemaV1 = StandardSchemaV1,\n\tTServices extends Service[] = [],\n\tTLogger extends Logger = Logger,\n\tTDatabase = undefined,\n\tTDatabaseServiceName extends string = string,\n> {\n\tstatic getDefaultServiceDiscovery() {\n\t\treturn ServiceDiscovery.getInstance(new EnvironmentParser({}));\n\t}\n\n\tconstructor(\n\t\tprivate readonly queue: Queue<\n\t\t\tTName,\n\t\t\tTMessage,\n\t\t\tTServices,\n\t\t\tTLogger,\n\t\t\tTDatabase,\n\t\t\tTDatabaseServiceName\n\t\t>,\n\t\tprivate serviceDiscovery: ServiceDiscovery<any> = TestQueueAdaptor.getDefaultServiceDiscovery(),\n\t) {}\n\n\tasync invoke(\n\t\trequest: TestQueueRequest<TMessage, TServices, TDatabase>,\n\t): Promise<unknown> {\n\t\tconst logger = this.queue.logger.child({ test: true }) as TLogger;\n\n\t\tconst services =\n\t\t\trequest.services ??\n\t\t\t((await this.serviceDiscovery.register(\n\t\t\t\tthis.queue.services,\n\t\t\t)) as ServiceRecord<TServices>);\n\n\t\tconst db = request.db !== undefined ? request.db : await this.getDatabase();\n\n\t\tconst requestId = `test-${Date.now()}`;\n\t\tconst startTime = Date.now();\n\n\t\tconst operation = `queue ${this.queue.name}`;\n\t\treturn runWithRequestContext(\n\t\t\t{ logger, requestId, startTime, operation },\n\t\t\t() =>\n\t\t\t\tthis.queue.handler({\n\t\t\t\t\tmessages: request.messages,\n\t\t\t\t\tservices,\n\t\t\t\t\tlogger,\n\t\t\t\t\tdb,\n\t\t\t\t} as unknown as QueueContext<TMessage, TServices, TLogger, TDatabase>),\n\t\t);\n\t}\n\n\tprivate async getDatabase(): Promise<TDatabase | undefined> {\n\t\tconst service = this.queue.databaseService;\n\t\tif (!service) return undefined;\n\n\t\tconst registered = await this.serviceDiscovery.register([service]);\n\n\t\treturn registered[service.serviceName] as TDatabase | undefined;\n\t}\n}\n\nexport type TestQueueRequest<\n\tTMessage extends StandardSchemaV1 = StandardSchemaV1,\n\tTServices extends Service[] = [],\n\tTDatabase = undefined,\n> = {\n\tmessages: InferStandardSchema<TMessage>[];\n\tservices?: ServiceRecord<TServices>;\n\t/** Stands in for the queue's database — a transaction, say. */\n\tdb?: TDatabase;\n};\n","import { EnvironmentParser } from '@geekmidas/envkit';\nimport type {\n\tEventPublisher,\n\tExtractPublisherMessage,\n} from '@geekmidas/events';\nimport type { Logger } from '@geekmidas/logger';\nimport type { InferStandardSchema } from '@geekmidas/schema';\nimport type { Service, ServiceRecord } from '@geekmidas/services';\nimport { runWithRequestContext, ServiceDiscovery } from '@geekmidas/services';\nimport type { StandardSchemaV1 } from '@standard-schema/spec';\nimport type { Subscriber } from './Subscriber';\n\n// Helper type to extract payload types for subscribed events\ntype ExtractEventPayloads<\n\tTPublisher extends EventPublisher<any> | undefined,\n\tTEventTypes extends any[],\n> = TPublisher extends EventPublisher<any>\n\t? Extract<ExtractPublisherMessage<TPublisher>, { type: TEventTypes[number] }>\n\t: never;\n\nexport class TestSubscriberAdaptor<\n\tTServices extends Service[] = [],\n\tTLogger extends Logger = Logger,\n\tOutSchema extends StandardSchemaV1 | undefined = undefined,\n\tTEventPublisher extends EventPublisher<any> | undefined = undefined,\n\tTSubscribedEvents extends\n\t\tExtractPublisherMessage<TEventPublisher>['type'][] = ExtractPublisherMessage<TEventPublisher>['type'][],\n\tTDatabase = undefined,\n\tTDatabaseServiceName extends string = string,\n> {\n\tstatic getDefaultServiceDiscovery() {\n\t\treturn ServiceDiscovery.getInstance(new EnvironmentParser({}));\n\t}\n\n\tconstructor(\n\t\tprivate readonly subscriber: Subscriber<\n\t\t\tTServices,\n\t\t\tTLogger,\n\t\t\tOutSchema,\n\t\t\tTEventPublisher,\n\t\t\tTSubscribedEvents,\n\t\t\tTDatabase,\n\t\t\tTDatabaseServiceName\n\t\t>,\n\t\tprivate serviceDiscovery: ServiceDiscovery<any> = TestSubscriberAdaptor.getDefaultServiceDiscovery(),\n\t) {}\n\n\tasync invoke(\n\t\trequest: TestSubscriberRequest<\n\t\t\tTEventPublisher,\n\t\t\tTSubscribedEvents,\n\t\t\tTServices,\n\t\t\tTDatabase\n\t\t>,\n\t): Promise<InferStandardSchema<OutSchema>> {\n\t\t// Create logger with test context\n\t\tconst logger = this.subscriber.logger.child({\n\t\t\ttest: true,\n\t\t}) as TLogger;\n\n\t\t// Resolve services (use provided or auto-register)\n\t\tlet services: ServiceRecord<TServices>;\n\t\tif (request.services) {\n\t\t\tservices = request.services;\n\t\t} else {\n\t\t\tservices = await this.serviceDiscovery.register(this.subscriber.services);\n\t\t}\n\n\t\t// The request's db stands in for the subscriber's — a transaction, say.\n\t\tconst db = request.db !== undefined ? request.db : await this.getDatabase();\n\n\t\t// Filter events to only subscribed types\n\t\tconst filteredEvents = this.filterEvents(request.events);\n\n\t\t// Return early if no events after filtering (mirrors AWSLambdaSubscriber)\n\t\tif (filteredEvents.length === 0) {\n\t\t\treturn { batchItemFailures: [] } as any;\n\t\t}\n\n\t\t// Wrap execution in request context for service access via context.getLogger()\n\t\tconst requestId = `test-${Date.now()}`;\n\t\tconst startTime = Date.now();\n\n\t\tconst operation = `subscriber ${this.subscriber.topicName ?? 'test'}`;\n\t\treturn runWithRequestContext(\n\t\t\t{ logger, requestId, startTime, operation },\n\t\t\tasync () => {\n\t\t\t\t// Execute the subscriber handler\n\t\t\t\tconst result = await this.subscriber.handler({\n\t\t\t\t\tevents: filteredEvents,\n\t\t\t\t\tservices,\n\t\t\t\t\tlogger,\n\t\t\t\t\tdb,\n\t\t\t\t} as unknown as Parameters<typeof this.subscriber.handler>[0]);\n\n\t\t\t\t// Validate output if schema is provided\n\t\t\t\tlet output: any = result;\n\t\t\t\tif (this.subscriber.outputSchema && result) {\n\t\t\t\t\tconst validationResult =\n\t\t\t\t\t\tawait this.subscriber.outputSchema['~standard'].validate(result);\n\n\t\t\t\t\tif (validationResult.issues) {\n\t\t\t\t\t\tthrow new Error('Subscriber output validation failed');\n\t\t\t\t\t}\n\n\t\t\t\t\toutput = validationResult.value;\n\t\t\t\t}\n\n\t\t\t\treturn output;\n\t\t\t},\n\t\t) as Promise<InferStandardSchema<OutSchema>>;\n\t}\n\n\tprivate async getDatabase(): Promise<TDatabase | undefined> {\n\t\tconst service = this.subscriber.databaseService;\n\t\tif (!service) return undefined;\n\n\t\tconst registered = await this.serviceDiscovery.register([service]);\n\n\t\treturn registered[service.serviceName] as TDatabase | undefined;\n\t}\n\n\tprivate filterEvents(\n\t\tevents: ExtractEventPayloads<TEventPublisher, TSubscribedEvents>[],\n\t): ExtractEventPayloads<TEventPublisher, TSubscribedEvents>[] {\n\t\tif (!this.subscriber.subscribedEvents) {\n\t\t\treturn events;\n\t\t}\n\n\t\treturn events.filter((event: any) =>\n\t\t\tthis.subscriber.subscribedEvents!.includes(event.type),\n\t\t);\n\t}\n}\n\nexport type TestSubscriberRequest<\n\tTEventPublisher extends EventPublisher<any> | undefined = undefined,\n\tTSubscribedEvents extends any[] = [],\n\tTServices extends Service[] = [],\n\tTDatabase = undefined,\n> = {\n\tevents: ExtractEventPayloads<TEventPublisher, TSubscribedEvents>[];\n\tservices?: ServiceRecord<TServices>;\n\t/** Stands in for the subscriber's database — a transaction, say. */\n\tdb?: TDatabase;\n};\n","/**\n * The test manifest: what `gkm test` knows about an app, written down for the\n * suite it starts.\n *\n * `gkm test` discovers the constructs, reconciles the test stage and resolves\n * its environment — then, until this existed, threw all of it away and left a\n * test to declare it again by hand. The manifest keeps it: which construct and\n * endpoint is exported where, and the environment the test stage resolved,\n * under the keys the constructs themselves derive. A feature test is built from\n * it, so nothing a test says can drift from what the app declares.\n */\n\nimport { existsSync, readFileSync } from 'node:fs';\nimport tls from 'node:tls';\nimport { fileURLToPath } from 'node:url';\n\n/** Where an export lives: what an import statement has to say. */\nexport interface TestManifestSource {\n\t/** Absolute path to the module. */\n\tfile: string;\n\t/** The name it is exported as. */\n\texport: string;\n}\n\nexport interface TestManifest {\n\t/** The stage the environment was resolved for — `test`. */\n\tstage: string;\n\t/** Every construct the app declares, by id. */\n\tconstructs: Record<string, { kind: string; source: TestManifestSource }>;\n\t/** Every endpoint, and the surface that serves it. */\n\tendpoints: { surface: string; source: TestManifestSource }[];\n\t/**\n\t * Every topic subscriber — what a topic's events are delivered to. Not a\n\t * construct, so not in `constructs`: the build finds them, as it finds\n\t * endpoints.\n\t */\n\tsubscribers?: { source: TestManifestSource }[];\n\t/**\n\t * The test stage's environment — reconcile's output, keyed as the\n\t * constructs derive their keys.\n\t */\n\tenv: Record<string, string>;\n}\n\n/** The environment variable `gkm test` names the manifest in. */\nexport const TEST_MANIFEST_ENV = 'GKM_TEST_MANIFEST';\n\n/**\n * Read a test manifest: from a path, a `file:` URL, or — given nothing — the\n * one `gkm test` named in `GKM_TEST_MANIFEST`.\n */\nexport function loadTestManifest(from?: string | URL): TestManifest {\n\tconst location = from ?? process.env[TEST_MANIFEST_ENV];\n\tif (!location) throw new NoTestManifest();\n\n\ttrustLocalEdge();\n\n\tconst path =\n\t\tlocation instanceof URL || location.startsWith('file:')\n\t\t\t? fileURLToPath(location)\n\t\t\t: location;\n\n\treturn JSON.parse(readFileSync(path, 'utf-8')) as TestManifest;\n}\n\nlet trusted = false;\n\n/**\n * Trust the local edge's certificate authority in this thread.\n *\n * `NODE_EXTRA_CA_CERTS` does it for a process started with it — which a\n * suite started by `gkm test` is, and one started by plain `vitest` or an\n * editor is not: its setup only learns the path once Vitest is running, and a\n * worker *thread* shares that process and keeps a TLS store of its own. Every\n * feature test loads the manifest, so this is the one place each worker passes\n * through.\n */\nfunction trustLocalEdge(): void {\n\tconst certificate = process.env.NODE_EXTRA_CA_CERTS;\n\tif (trusted || !certificate || !existsSync(certificate)) return;\n\ttrusted = true;\n\n\ttls.setDefaultCACertificates([\n\t\t...tls.getCACertificates('default'),\n\t\treadFileSync(certificate, 'utf-8'),\n\t]);\n}\n\n/** A feature test ran without a manifest to build itself from. */\nexport class NoTestManifest extends Error {\n\tconstructor() {\n\t\tsuper(\n\t\t\t`No test manifest: run the suite with \\`gkm test\\`, or add ` +\n\t\t\t\t`\\`globalSetup: ['@geekmidas/cli/vitest']\\` to the root vitest config — ` +\n\t\t\t\t`either writes one and names it in ${TEST_MANIFEST_ENV}.`,\n\t\t);\n\t\tthis.name = 'NoTestManifest';\n\t}\n}\n","/**\n * `featureTest`: an app, driven the way it runs deployed.\n *\n * A browser signs in and calls the API; the API calls the auth server; each\n * over its URL, each database in its own transaction. Nothing runs as a server:\n * every URL an app's constructs answer on is served in-process through MSW,\n * from the real handler, for the test that made the request. Everything else\n * with a real local equivalent — Postgres, Mailpit, MinIO — is used directly.\n *\n * It is built from the test manifest `gkm test` writes — the constructs and\n * endpoints the app exports, and the environment the test stage resolved — so\n * a test declares none of it. `gkm test` also generates the configured `it`\n * and a `Browser` with a typed client per surface:\n *\n * ```ts\n * import { it } from '#test';\n *\n * it('shows the signed-in user their profile', async ({ browser, mailbox }) => {\n * await browser.auth.signIn.magicLink({ email: 'ada@shop.test' });\n * await browser.visit((await mailbox('ada@shop.test').last()).link!);\n * expect(await browser.api.get('/profile')).toMatchObject({ email: 'ada@shop.test' });\n * });\n * ```\n */\n\nimport { randomUUID } from 'node:crypto';\nimport { EnvironmentParser } from '@geekmidas/envkit';\nimport { provideKey } from '@geekmidas/manifest';\nimport { ServiceDiscovery, serviceContext } from '@geekmidas/services';\nimport { Browser as TestBrowser } from '@geekmidas/testkit/browser';\nimport {\n\tcurrentTestContext,\n\tinstallContextFetch,\n\trunAsServer,\n\trunInTestContext,\n\ttestContextOf,\n} from '@geekmidas/testkit/context';\nimport { type FakerFactory, faker } from '@geekmidas/testkit/faker';\nimport { createMailbox, type Mailbox } from '@geekmidas/testkit/mailbox';\nimport { TransactionRegistry } from '@geekmidas/testkit/transactions';\nimport type { StandardSchemaV1 } from '@standard-schema/spec';\nimport { Hono } from 'hono';\nimport type { Kysely } from 'kysely';\nimport { http } from 'msw';\nimport { type SetupServer, setupServer } from 'msw/node';\nimport { afterAll, beforeAll, test } from 'vitest';\nimport { BetterAuth } from '../auth';\nimport { type Consumable, isConsumable } from '../construct-interface';\nimport { KyselyDatabase } from '../database/kysely';\nimport { Email } from '../email';\nimport { Endpoint } from '../endpoints/Endpoint';\nimport { HonoEndpoint } from '../endpoints/HonoEndpointAdaptor';\nimport type { Fake } from '../external-api';\nimport { Queue } from '../queue/Queue';\nimport { TestQueueAdaptor } from '../queue/TestQueueAdaptor';\nimport type { Subscriber } from '../subscribers/Subscriber';\nimport { TestSubscriberAdaptor } from '../subscribers/TestSubscriberAdaptor';\nimport { Topic } from '../topic/Topic';\nimport { loadTestManifest, type TestManifest } from './manifest';\nimport { inProcessBindings } from './peer';\n\n/** How each database's test factory is built, keyed by its service name. */\nexport type FactoryBuilders = Record<string, (db: Kysely<any>) => unknown>;\n\nexport interface FeatureTestOptions<\n\tTBrowser extends TestBrowser,\n\tTFactories extends FactoryBuilders = {},\n> {\n\t/**\n\t * What the app declares and the environment its test stage resolved.\n\t * Defaults to the manifest `gkm test` names in `GKM_TEST_MANIFEST`.\n\t */\n\tmanifest?: TestManifest;\n\t/**\n\t * The app's modules, already imported, by the absolute path the manifest\n\t * records for them. The generated harness imports them statically, from\n\t * inside the app, so they resolve the way the app's own code does — its\n\t * tsconfig paths included. A module not here is imported by path.\n\t */\n\tmodules?: Readonly<Record<string, Record<string, unknown>>>;\n\t/** The browser each test gets — the generated one, with the app's clients. */\n\tbrowser?: new () => TBrowser;\n\t/**\n\t * Each database's test factory — `createFactory` from\n\t * `test/factories/<construct>.ts`, which the generated harness imports —\n\t * keyed by the database's service name. Each is called once per test with\n\t * that database's transaction, so what a test inserts through it is rolled\n\t * back with everything else, and seen by the endpoints it calls.\n\t */\n\tfactories?: TFactories;\n\t/**\n\t * Each external API's fake — the default export of `test/fakes/<id>.ts`,\n\t * which the generated harness imports — keyed by the API's construct id.\n\t * An app fake is served at the URL the test stage resolved for it.\n\t */\n\tfakes?: Readonly<Record<string, Fake>>;\n}\n\n/** Each database's schema, keyed by its service name. */\nexport type DatabaseSchemas = Record<string, unknown>;\n\n/** Each construct's client, keyed by its service name — what `services` types. */\nexport type ServiceClients = Record<string, unknown>;\n\n/** The client a construct's service registers — what a handler is handed. */\nexport type ClientOf<C> = C extends {\n\tservice: { register: (...args: any[]) => infer TClient };\n}\n\t? Awaited<TClient>\n\t: never;\n\n/**\n * The app's services for this test, by service name — `services.get('shipping')`.\n *\n * What a handler that depends on the construct is handed, resolved the way the\n * test's endpoints resolve it: an external API's client aimed at whatever the\n * test stage resolved (its fake, which the test never sees), a topic or queue's\n * recorder, a database's transaction for this test.\n */\nexport interface TestServices<TServices extends ServiceClients> {\n\tget<K extends keyof TServices & string>(name: K): Promise<TServices[K]>;\n}\n\n/**\n * The app's databases for this test, by service name — `db.get('database')`.\n *\n * Each is this test's transaction on that database: opened by whatever reaches\n * it first — the test, a factory, an endpoint — and the same one for all of\n * them, rolled back after the test.\n */\nexport interface TestDatabases<TDatabases extends DatabaseSchemas> {\n\tget<K extends keyof TDatabases & string>(\n\t\tname: K,\n\t): Promise<Kysely<TDatabases[K]>>;\n}\n\n/**\n * Each of the app's databases' test factory, by service name —\n * `await factories.get('database')`. Built on first use, on that database's\n * transaction for this test — the one `db.get` returns — and the same factory\n * for the rest of the test.\n */\nexport interface TestFactories<TFactories extends FactoryBuilders> {\n\tget<K extends keyof TFactories & string>(\n\t\tname: K,\n\t): Promise<ReturnType<TFactories[K]>>;\n}\n\nexport interface FeatureContext<\n\tTBrowser extends TestBrowser,\n\tTDatabases extends DatabaseSchemas = {},\n\tTFactories extends FactoryBuilders = {},\n\tTServices extends ServiceClients = {},\n> {\n\t/** This test's browser, already the global `fetch`. */\n\tbrowser: TBrowser;\n\t/**\n\t * The app's own databases — not a tenant an auth server owns, not a\n\t * reader — by service name: `await db.get('database')`. The same\n\t * transaction the test's endpoints and factories use.\n\t */\n\tdb: TestDatabases<TDatabases>;\n\t/**\n\t * Each of the app's databases' test factory, by service name —\n\t * `await factories.get('database')` — on the same transaction `db.get`\n\t * returns.\n\t */\n\tfactories: TestFactories<TFactories>;\n\t/**\n\t * Testkit's faker — the one factories are handed — seeded from this test's\n\t * name, so a failing test fails again with the same data, and so a test\n\t * imports nothing to make some.\n\t */\n\tfaker: FakerFactory;\n\t/** The mail sent to an address during this test, read from Mailpit. */\n\tmailbox: (address: string) => Mailbox;\n\t/**\n\t * What this test published to a topic or enqueued on a queue, in order.\n\t *\n\t * Also delivered: once each request the test makes has answered, a queue's\n\t * messages reach its consumer and a topic's events every subscriber that\n\t * named them, in this test's transaction — see {@link deliver}.\n\t */\n\tpublished: (channel: { id: string }) => PublishedMessage[];\n\t/**\n\t * A subscriber, run on its own — handed events rather than delivered them —\n\t * with this test's services: its databases resolve to this test's\n\t * transactions, as an endpoint's do.\n\t */\n\tsubscriber: <S extends Subscriber<any, any, any, any, any, any, any>>(\n\t\tsubscriber: S,\n\t) => SubscriberAdaptorOf<S>;\n\t/**\n\t * The app's services, by service name — `await services.get('shipping')` —\n\t * as a handler is handed them. Assert on an external API through its own\n\t * client: the fake behind it stays hidden, and the same assertion holds\n\t * against the real API.\n\t */\n\tservices: TestServices<TServices>;\n\t/** A queue's worker, run on its own with this test's services. */\n\tqueue: <Q extends Queue<any, any, any, any, any, any>>(\n\t\tqueue: Q,\n\t) => QueueAdaptorOf<Q>;\n}\n\ntype SubscriberAdaptorOf<S> =\n\tS extends Subscriber<\n\t\tinfer TServices,\n\t\tinfer TLogger,\n\t\tinfer OutSchema,\n\t\tinfer TEventPublisher,\n\t\tinfer TSubscribedEvents,\n\t\tinfer TDatabase,\n\t\tinfer TDatabaseServiceName\n\t>\n\t\t? TestSubscriberAdaptor<\n\t\t\t\tTServices,\n\t\t\t\tTLogger,\n\t\t\t\tOutSchema,\n\t\t\t\tTEventPublisher,\n\t\t\t\tTSubscribedEvents,\n\t\t\t\tTDatabase,\n\t\t\t\tTDatabaseServiceName\n\t\t\t>\n\t\t: never;\n\ntype QueueAdaptorOf<Q> =\n\tQ extends Queue<\n\t\tinfer TName,\n\t\tinfer TMessage,\n\t\tinfer TServices,\n\t\tinfer TLogger,\n\t\tinfer TDatabase,\n\t\tinfer TDatabaseServiceName\n\t>\n\t\t? TestQueueAdaptor<\n\t\t\t\tTName,\n\t\t\t\tTMessage,\n\t\t\t\tTServices,\n\t\t\t\tTLogger,\n\t\t\t\tTDatabase,\n\t\t\t\tTDatabaseServiceName\n\t\t\t>\n\t\t: never;\n\n/** The schema a database construct was declared with — what `db` is typed by. */\nexport type DatabaseOf<C> =\n\tC extends KyselyDatabase<infer DB, any> ? DB : unknown;\n\n/** One message as it was published: its type and its payload. */\nexport interface PublishedMessage {\n\ttype: string;\n\tpayload: unknown;\n}\n\ntype FeatureFn<\n\tTBrowser extends TestBrowser,\n\tTDatabases extends DatabaseSchemas,\n\tTFactories extends FactoryBuilders,\n\tTServices extends ServiceClients,\n> = (\n\tcontext: FeatureContext<TBrowser, TDatabases, TFactories, TServices>,\n) => unknown;\n\nexport interface FeatureIt<\n\tTBrowser extends TestBrowser,\n\tTDatabases extends DatabaseSchemas = {},\n\tTFactories extends FactoryBuilders = {},\n\tTServices extends ServiceClients = {},\n> {\n\t(\n\t\tname: string,\n\t\tfn: FeatureFn<TBrowser, TDatabases, TFactories, TServices>,\n\t\ttimeout?: number,\n\t): void;\n\tonly(\n\t\tname: string,\n\t\tfn: FeatureFn<TBrowser, TDatabases, TFactories, TServices>,\n\t\ttimeout?: number,\n\t): void;\n\tskip(\n\t\tname: string,\n\t\tfn: FeatureFn<TBrowser, TDatabases, TFactories, TServices>,\n\t\ttimeout?: number,\n\t): void;\n}\n\n/** Everything one test owns, found again from its id. */\ninterface ContextState {\n\ttransactions: TransactionRegistry;\n\tdiscovery: ServiceDiscovery<any>;\n\t/** One app per surface, with this test's services. */\n\tsurfaces: Map<string, Promise<Hono>>;\n\t/** One auth server per construct, on this test's transaction. */\n\tauth: Map<BetterAuth, Promise<Hono>>;\n\t/** The addresses this test read mail for, cleared after it. */\n\taddresses: Set<string>;\n\t/** This test's inbox, when the app sends mail — what `browser.signIn` reads. */\n\tmailbox?: (address: string) => Mailbox;\n\t/** What this test published, by topic or queue id. */\n\tpublished: Map<string, PublishedMessage[]>;\n\t/** What was published and is still to be delivered, in order. */\n\tpending: {\n\t\tchannel: Topic<any, any> | Queue<any, any>;\n\t\tmessages: PublishedMessage[];\n\t}[];\n\t/** Set while delivering, so a consumer's own requests do not deliver again. */\n\tdelivering: boolean;\n}\n\n/** Every test in flight in this process, by id. */\nconst contexts = new Map<string, ContextState>();\n\n/** Databases already resolving to test transactions — patched once each. */\nconst bound = new WeakSet<KyselyDatabase>();\n\n/** What the manifest points at, imported: the app's own instances. */\ninterface LoadedApp {\n\tenvParser: EnvironmentParser<{}>;\n\tendpoints: Endpoint<any, any, any, any>[];\n\tdatabases: KyselyDatabase[];\n\tauths: BetterAuth[];\n\temails: Email[];\n\t/** Every topic and queue — what a test's publishing is recorded for. */\n\tchannels: (Topic<any, any> | Queue<any, any>)[];\n\t/** Every construct a handler can depend on — what `services` resolves. */\n\tconsumables: Consumable[];\n\t/** Every topic subscriber, by the name it is exported as. */\n\tsubscribers: {\n\t\tname: string;\n\t\tsubscriber: Subscriber<any, any, any, any, any>;\n\t}[];\n\treadMail?: (address: string) => Mailbox;\n}\n\nexport function featureTest<\n\tTBrowser extends TestBrowser = TestBrowser,\n\tTDatabases extends DatabaseSchemas = {},\n\tTFactories extends FactoryBuilders = {},\n\tTServices extends ServiceClients = {},\n>(\n\toptions: FeatureTestOptions<TBrowser, TFactories> = {},\n): FeatureIt<TBrowser, TDatabases, TFactories, TServices> {\n\tconst manifest = options.manifest ?? loadTestManifest();\n\tconst BrowserClass = (options.browser ?? TestBrowser) as new () => TBrowser;\n\n\tlet app: LoadedApp;\n\tlet factoryDatabases: [string, KyselyDatabase][] = [];\n\tlet owned: KyselyDatabase[] = [];\n\tlet network: SetupServer;\n\tlet restoreFetch: () => void = () => {};\n\n\tbeforeAll(async () => {\n\t\tapp = await load(manifest, options.modules ?? {});\n\t\towned = ownDatabases(app, manifest);\n\t\tfactoryDatabases = databasesFor(options.factories ?? {}, owned);\n\t\tfor (const database of app.databases) bindToTests(database);\n\n\t\tnetwork = setupServer(\n\t\t\t...surfaceHandlers(app.endpoints, manifest.env),\n\t\t\t...app.auths.map((auth) =>\n\t\t\t\tauthHandler(auth, manifest.env, app.envParser),\n\t\t\t),\n\t\t\t...Object.entries(options.fakes ?? {}).flatMap(([id, fake]) =>\n\t\t\t\tfakeHandler(id, fake, manifest.env),\n\t\t\t),\n\t\t);\n\t\tnetwork.listen({\n\t\t\tonUnhandledRequest(request, print) {\n\t\t\t\t// A real local service — Mailpit, MinIO — is used directly; only a\n\t\t\t\t// URL with nothing real behind it has to be answered here.\n\t\t\t\tif (isLocal(new URL(request.url))) return;\n\t\t\t\tprint.error();\n\t\t\t},\n\t\t});\n\t\t// After MSW's interceptor, so the stamp is on before a request is caught.\n\t\tconst restoreStamp = installContextFetch();\n\t\t// Outermost: once a request the test made has answered, what it\n\t\t// published is delivered before the test sees the response.\n\t\tconst stamped = globalThis.fetch;\n\t\tglobalThis.fetch = deliveringFetch(stamped, (id) => {\n\t\t\tconst state = contexts.get(id);\n\t\t\treturn state ? deliver(app, state, id) : Promise.resolve();\n\t\t});\n\t\trestoreFetch = () => {\n\t\t\tglobalThis.fetch = stamped;\n\t\t\trestoreStamp();\n\t\t};\n\t});\n\tafterAll(() => {\n\t\trestoreFetch();\n\t\tnetwork?.close();\n\t});\n\n\tconst run =\n\t\t(\n\t\t\tname: string,\n\t\t\tfn: FeatureFn<TBrowser, TDatabases, TFactories, TServices>,\n\t\t) =>\n\t\tasync (): Promise<void> => {\n\t\t\tconst id = randomUUID();\n\t\t\tfaker.seed(seedOf(name));\n\t\t\tconst state: ContextState = {\n\t\t\t\ttransactions: new TransactionRegistry(),\n\t\t\t\tdiscovery: new ServiceDiscovery(app.envParser),\n\t\t\t\tsurfaces: new Map(),\n\t\t\t\tauth: new Map(),\n\t\t\t\taddresses: new Set(),\n\t\t\t\tpublished: new Map(),\n\t\t\t\tpending: [],\n\t\t\t\tdelivering: false,\n\t\t\t};\n\t\t\tconst readMail = app.readMail;\n\t\t\tif (readMail) {\n\t\t\t\tstate.mailbox = (address) => {\n\t\t\t\t\tstate.addresses.add(address);\n\t\t\t\t\treturn readMail(address);\n\t\t\t\t};\n\t\t\t}\n\t\t\tcontexts.set(id, state);\n\t\t\t// Before anything resolves them: a publisher is a service, so the one this\n\t\t\t// test's endpoints get is whichever is registered under its name first.\n\t\t\tawait state.discovery.register(recorders(app.channels, state));\n\n\t\t\ttry {\n\t\t\t\tawait runInTestContext(id, async () => {\n\t\t\t\t\tconst browser = new BrowserClass();\n\t\t\t\t\tconst restore = browser.install();\n\t\t\t\t\ttry {\n\t\t\t\t\t\t// A database's transaction for this test, opened on first use —\n\t\t\t\t\t\t// the registry hands everyone in the test the same one.\n\t\t\t\t\t\tconst transaction = (database: KyselyDatabase) =>\n\t\t\t\t\t\t\tstate.transactions.get(\n\t\t\t\t\t\t\t\tdatabase.id,\n\t\t\t\t\t\t\t\turlOf(database, app.envParser),\n\t\t\t\t\t\t\t\tdatabase.clientConfig,\n\t\t\t\t\t\t\t) as Promise<Kysely<any>>;\n\t\t\t\t\t\tconst db: TestDatabases<any> = {\n\t\t\t\t\t\t\tget: (name) => {\n\t\t\t\t\t\t\t\tconst database = owned.find(\n\t\t\t\t\t\t\t\t\t(candidate) => candidate.service.serviceName === name,\n\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t\tif (!database) {\n\t\t\t\t\t\t\t\t\tthrow new UnknownDatabase(\n\t\t\t\t\t\t\t\t\t\tname,\n\t\t\t\t\t\t\t\t\t\towned.map((candidate) => candidate.service.serviceName),\n\t\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\treturn transaction(database);\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t};\n\t\t\t\t\t\tconst built = new Map<string, Promise<unknown>>();\n\t\t\t\t\t\tconst factories: TestFactories<any> = {\n\t\t\t\t\t\t\tget: (name) => {\n\t\t\t\t\t\t\t\tconst database = factoryDatabases.find(\n\t\t\t\t\t\t\t\t\t([candidate]) => candidate === name,\n\t\t\t\t\t\t\t\t)?.[1];\n\t\t\t\t\t\t\t\tif (!database) {\n\t\t\t\t\t\t\t\t\tthrow new UnknownFactory(\n\t\t\t\t\t\t\t\t\t\tname,\n\t\t\t\t\t\t\t\t\t\tfactoryDatabases.map(([candidate]) => candidate),\n\t\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\tlet factory = built.get(name);\n\t\t\t\t\t\t\t\tif (!factory) {\n\t\t\t\t\t\t\t\t\tfactory = transaction(database).then(\n\t\t\t\t\t\t\t\t\t\toptions.factories![name]!,\n\t\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t\t\tbuilt.set(name, factory);\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\treturn factory as Promise<any>;\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t};\n\t\t\t\t\t\tawait fn({\n\t\t\t\t\t\t\tbrowser,\n\t\t\t\t\t\t\tdb: db as TestDatabases<TDatabases>,\n\t\t\t\t\t\t\tfactories: factories as TestFactories<TFactories>,\n\t\t\t\t\t\t\tfaker,\n\t\t\t\t\t\t\tmailbox: (address) => {\n\t\t\t\t\t\t\t\tif (!state.mailbox) throw new NoInbox();\n\t\t\t\t\t\t\t\treturn state.mailbox(address);\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\tpublished: (channel) => [\n\t\t\t\t\t\t\t\t...(state.published.get(channel.id) ?? []),\n\t\t\t\t\t\t\t],\n\t\t\t\t\t\t\tservices: {\n\t\t\t\t\t\t\t\tget: (name) => resolveService(app, state, name) as never,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t// A consumer run by hand delivers what it published, as a\n\t\t\t\t\t\t\t// request does.\n\t\t\t\t\t\t\tsubscriber: (subscriber) =>\n\t\t\t\t\t\t\t\tthenDeliver(\n\t\t\t\t\t\t\t\t\tnew TestSubscriberAdaptor(subscriber, state.discovery),\n\t\t\t\t\t\t\t\t\t() => deliver(app, state, id),\n\t\t\t\t\t\t\t\t) as SubscriberAdaptorOf<typeof subscriber>,\n\t\t\t\t\t\t\tqueue: (queue) =>\n\t\t\t\t\t\t\t\tthenDeliver(new TestQueueAdaptor(queue, state.discovery), () =>\n\t\t\t\t\t\t\t\t\tdeliver(app, state, id),\n\t\t\t\t\t\t\t\t) as QueueAdaptorOf<typeof queue>,\n\t\t\t\t\t\t} as FeatureContext<TBrowser, TDatabases, TFactories, TServices>);\n\t\t\t\t\t} finally {\n\t\t\t\t\t\trestore();\n\t\t\t\t\t}\n\t\t\t\t});\n\t\t\t} finally {\n\t\t\t\tcontexts.delete(id);\n\t\t\t\tawait Promise.all([\n\t\t\t\t\tstate.transactions.rollbackAll(),\n\t\t\t\t\t...[...state.addresses].map((address) =>\n\t\t\t\t\t\tapp.readMail?.(address).clear(),\n\t\t\t\t\t),\n\t\t\t\t]);\n\t\t\t}\n\t\t};\n\n\tconst it = ((name, fn, timeout) =>\n\t\ttest(name, run(name, fn), timeout)) as FeatureIt<\n\t\tTBrowser,\n\t\tTDatabases,\n\t\tTFactories,\n\t\tTServices\n\t>;\n\tit.only = (name, fn, timeout) => test.only(name, run(name, fn), timeout);\n\tit.skip = (name, fn, timeout) => test.skip(name, run(name, fn), timeout);\n\treturn it;\n}\n\n/**\n * A test's faker seed, from its name: the same test draws the same data on\n * every run, and two tests draw different data.\n */\nfunction seedOf(name: string): number {\n\tlet hash = 0;\n\tfor (const char of name) {\n\t\thash = (Math.imul(hash, 31) + char.charCodeAt(0)) | 0;\n\t}\n\treturn hash >>> 0;\n}\n\n/**\n * Import what the manifest points at.\n *\n * The same modules the app runs, so a construct here *is* the app's construct —\n * the one its endpoints were built from — never a copy declared again.\n */\nasync function load(\n\tmanifest: TestManifest,\n\tmodules: Readonly<Record<string, Record<string, unknown>>>,\n): Promise<LoadedApp> {\n\tconst envParser = new EnvironmentParser({ ...manifest.env });\n\tconst imported = async ({\n\t\tfile,\n\t\texport: name,\n\t}: {\n\t\tfile: string;\n\t\texport: string;\n\t}) =>\n\t\t// Imported by path only as a fallback: from inside `node_modules`, a\n\t\t// dynamic import is left to Node, which knows nothing of the app's\n\t\t// tsconfig paths — `~/router.ts` resolves in the app and not here.\n\t\t(modules[file] ?? ((await import(file)) as Record<string, unknown>))[name];\n\n\tconst constructs = await Promise.all(\n\t\tObject.values(manifest.constructs).map(({ source }) => imported(source)),\n\t);\n\tconst endpoints = (\n\t\tawait Promise.all(manifest.endpoints.map(({ source }) => imported(source)))\n\t).filter((value): value is Endpoint<any, any, any, any> =>\n\t\tEndpoint.isEndpoint(value),\n\t);\n\tconst subscribers = (\n\t\tawait Promise.all(\n\t\t\t(manifest.subscribers ?? []).map(async ({ source }) => ({\n\t\t\t\tname: source.export,\n\t\t\t\tsubscriber: await imported(source),\n\t\t\t})),\n\t\t)\n\t).filter(\n\t\t(\n\t\t\tentry,\n\t\t): entry is {\n\t\t\tname: string;\n\t\t\tsubscriber: Subscriber<any, any, any, any, any>;\n\t\t} =>\n\t\t\t(entry.subscriber as { __IS_SUBSCRIBER__?: unknown })\n\t\t\t\t?.__IS_SUBSCRIBER__ === true,\n\t);\n\n\tconst unique = <T>(values: T[]) => [...new Set(values)];\n\tconst databases = unique(\n\t\tconstructs.filter(\n\t\t\t(value): value is KyselyDatabase => value instanceof KyselyDatabase,\n\t\t),\n\t);\n\tconst auths = unique(\n\t\tconstructs.filter(\n\t\t\t(value): value is BetterAuth => value instanceof BetterAuth,\n\t\t),\n\t);\n\tconst emails = unique(\n\t\tconstructs.filter((value): value is Email => value instanceof Email),\n\t);\n\tconst consumables = unique(constructs.filter(isConsumable));\n\tconst channels = unique(\n\t\tconstructs.filter(\n\t\t\t(value): value is Topic<any, any> | Queue<any, any> =>\n\t\t\t\tvalue instanceof Topic || value instanceof Queue,\n\t\t),\n\t);\n\n\tconst inbox = emails\n\t\t.map((email) => manifest.env[provideKey(email.id, 'inboxUrl')])\n\t\t.find(Boolean);\n\n\treturn {\n\t\tenvParser,\n\t\tendpoints,\n\t\tdatabases,\n\t\tauths,\n\t\temails,\n\t\tchannels,\n\t\tconsumables,\n\t\tsubscribers,\n\t\t...(inbox ? { readMail: createMailbox({ inbox }) } : {}),\n\t};\n}\n\n/**\n * A publisher that records rather than sends, under the name a topic or queue\n * is injected by — `services.users` — which is also the one `.event(users, …)`\n * publishes through.\n */\nfunction recorders(\n\tchannels: LoadedApp['channels'],\n\tstate: ContextState,\n): { serviceName: string; register: () => unknown }[] {\n\treturn channels.map((channel) => {\n\t\tconst publisher = {\n\t\t\tasync publish(messages: PublishedMessage[]) {\n\t\t\t\tconst sent = messages.map(({ type, payload }) => ({ type, payload }));\n\t\t\t\tstate.published.set(channel.id, [\n\t\t\t\t\t...(state.published.get(channel.id) ?? []),\n\t\t\t\t\t...sent,\n\t\t\t\t]);\n\t\t\t\tstate.pending.push({ channel, messages: sent });\n\t\t\t},\n\t\t};\n\t\treturn {\n\t\t\tserviceName: channel.service.serviceName,\n\t\t\tregister: () => publisher,\n\t\t};\n\t});\n}\n\n/**\n * The databases a test is handed: the app's own. A schema tenant an auth server\n * owns is reached through that server, as the app reaches it, and a reader is\n * the same database through a read-only role — neither is another database to\n * test against.\n */\nfunction ownDatabases(\n\tapp: LoadedApp,\n\tmanifest: TestManifest,\n): KyselyDatabase[] {\n\tconst owners = new Set(app.auths.map((auth) => auth.databaseId));\n\treturn app.databases.filter(\n\t\t(database) =>\n\t\t\t!owners.has(database.id) &&\n\t\t\tmanifest.constructs[database.id]?.kind !== 'database-reader',\n\t);\n}\n\n/** Each factory's database, found by the service name it is keyed by. */\nfunction databasesFor(\n\tfactories: FactoryBuilders,\n\tdatabases: KyselyDatabase[],\n): [string, KyselyDatabase][] {\n\treturn Object.keys(factories).map((name) => {\n\t\tconst database = databases.find(\n\t\t\t(candidate) => candidate.service.serviceName === name,\n\t\t);\n\t\tif (!database) {\n\t\t\tthrow new UnknownFactory(\n\t\t\t\tname,\n\t\t\t\tdatabases.map((candidate) => candidate.service.serviceName),\n\t\t\t);\n\t\t}\n\t\treturn [name, database];\n\t});\n}\n\n/**\n * Make a database resolve, inside a test, to that test's transaction.\n *\n * Everything reaches a database through its service — an endpoint through\n * service discovery, the auth server through its tenant directly — so this is\n * the one place a test's connection can be handed over. Outside a test it is\n * the database it always was.\n */\n/** Rounds of delivery before a chain of consumers is called a loop. */\nconst MAX_DELIVERY_ROUNDS = 25;\n\n/**\n * Deliver what this test published, in-process, as the broker would — and\n * keep delivering what the consumers publish in turn, until nothing is left.\n *\n * - A queue's messages go to its one consumer, as a batch.\n * - A topic's events go to every subscriber that named their type, and only\n * those: fan-out, as the filter policy (SNS) or the per-subscriber queue\n * (pg-boss) does it.\n * - Each payload is checked against the consumer's schema first. Turning an\n * SNS envelope or an SQS record into `{ type, payload }` is each adaptor's\n * job and tested there; what is tested here is what the handler is handed.\n * - Consumers run as the server side of this test, so their databases are\n * this test's transactions and their writes roll back with it.\n * - A consumer that throws fails the test. Deployed, the message would be\n * retried; here a retry would only hide the bug.\n */\nasync function deliver(\n\tapp: LoadedApp,\n\tstate: ContextState,\n\tid: string,\n): Promise<void> {\n\tif (state.delivering) return;\n\tstate.delivering = true;\n\ttry {\n\t\tfor (let round = 0; state.pending.length > 0; round++) {\n\t\t\tif (round === MAX_DELIVERY_ROUNDS) {\n\t\t\t\tthrow new DeliveryDidNotSettle(MAX_DELIVERY_ROUNDS, [\n\t\t\t\t\t...new Set(state.pending.map(({ channel }) => channel.id)),\n\t\t\t\t]);\n\t\t\t}\n\t\t\tfor (const { channel, messages } of state.pending.splice(0)) {\n\t\t\t\tif (channel instanceof Queue) {\n\t\t\t\t\tawait toQueue(channel, messages, state, id);\n\t\t\t\t} else {\n\t\t\t\t\tawait toSubscribers(channel, messages, app, state, id);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t} finally {\n\t\tstate.delivering = false;\n\t}\n}\n\nasync function toQueue(\n\tqueue: Queue<any, any>,\n\tmessages: PublishedMessage[],\n\tstate: ContextState,\n\tid: string,\n): Promise<void> {\n\tconst payloads: unknown[] = [];\n\tfor (const message of messages) {\n\t\tpayloads.push(\n\t\t\tawait accepted(queue.messageSchema, message, `queue '${queue.name}'`),\n\t\t);\n\t}\n\n\tawait runAsServer(id, () =>\n\t\tnew TestQueueAdaptor(queue, state.discovery).invoke({ messages: payloads }),\n\t).catch((error: unknown) => {\n\t\tthrow new DeliveryFailed(`queue '${queue.name}'`, messages, error);\n\t});\n}\n\nasync function toSubscribers(\n\ttopic: Topic<any, any>,\n\tmessages: PublishedMessage[],\n\tapp: LoadedApp,\n\tstate: ContextState,\n\tid: string,\n): Promise<void> {\n\tfor (const { name, subscriber } of app.subscribers) {\n\t\tif (subscriber.topicName !== topic.name) continue;\n\n\t\tconst named = messages.filter(({ type }) =>\n\t\t\t(subscriber.subscribedEvents ?? []).includes(type),\n\t\t);\n\t\tif (named.length === 0) continue;\n\n\t\tconst consumer = `subscriber '${name}'`;\n\t\tconst events: PublishedMessage[] = [];\n\t\tfor (const message of named) {\n\t\t\tconst schema = (topic.eventSchemas as Record<string, unknown>)[\n\t\t\t\tmessage.type\n\t\t\t];\n\t\t\tevents.push({\n\t\t\t\ttype: message.type,\n\t\t\t\tpayload: await accepted(schema, message, consumer),\n\t\t\t});\n\t\t}\n\n\t\tawait runAsServer(id, () =>\n\t\t\tnew TestSubscriberAdaptor(subscriber, state.discovery).invoke({\n\t\t\t\tevents,\n\t\t\t} as never),\n\t\t).catch((error: unknown) => {\n\t\t\tthrow new DeliveryFailed(consumer, named, error);\n\t\t});\n\t}\n}\n\n/** The payload, if the consumer's schema takes it — what the handler is handed. */\nasync function accepted(\n\tschema: unknown,\n\tmessage: PublishedMessage,\n\tconsumer: string,\n): Promise<unknown> {\n\tconst standard = (schema as StandardSchemaV1 | undefined)?.['~standard'];\n\tif (!standard) return message.payload;\n\n\tconst result = await standard.validate(message.payload);\n\tif (result.issues) {\n\t\tthrow new MessageRejected(consumer, message, result.issues);\n\t}\n\treturn result.value;\n}\n\n/** `fetch`, delivering what the test published once each of its requests answers. */\nfunction deliveringFetch(\n\tinner: typeof fetch,\n\tsettle: (id: string) => Promise<void>,\n): typeof fetch {\n\treturn async (input, init) => {\n\t\tconst context = currentTestContext();\n\t\tconst response = await inner(input, init);\n\t\t// The test's own requests only: a handler's requests are part of the one\n\t\t// being served, and a consumer's are part of a delivery already running.\n\t\tif (context?.side === 'client') await settle(context.id);\n\t\treturn response;\n\t};\n}\n\n/** An adaptor whose `invoke` delivers what it published before returning. */\nfunction thenDeliver<\n\tT extends { invoke: (...args: any[]) => Promise<unknown> },\n>(adaptor: T, settle: () => Promise<void>): T {\n\tconst invoke = adaptor.invoke.bind(adaptor);\n\tadaptor.invoke = (async (...args: unknown[]) => {\n\t\tconst result = await invoke(...args);\n\t\tawait settle();\n\t\treturn result;\n\t}) as T['invoke'];\n\treturn adaptor;\n}\n\nfunction bindToTests(database: KyselyDatabase): void {\n\tif (bound.has(database)) return;\n\tbound.add(database);\n\n\tconst service = database.service as { register: (options: any) => unknown };\n\tconst register = service.register;\n\n\tservice.register = (options) => {\n\t\tconst context = currentTestContext();\n\t\tconst state = context && contexts.get(context.id);\n\t\tif (!state) return register(options);\n\n\t\treturn state.transactions.get(\n\t\t\tdatabase.id,\n\t\t\turlOf(database, options.envParser),\n\t\t\tdatabase.clientConfig,\n\t\t);\n\t};\n}\n\nfunction urlOf(database: { id: string }, envParser: EnvironmentParser<{}>) {\n\treturn envParser\n\t\t.create((get) => ({ url: get(provideKey(database.id, 'url')).string() }))\n\t\t.parse().url;\n}\n\n/** Each surface's endpoints, served at its URL for the test that asked. */\nfunction surfaceHandlers(\n\tendpoints: Endpoint<any, any, any, any>[],\n\tenv: Record<string, string | undefined>,\n) {\n\tconst bySurface = new Map<string, Endpoint<any, any, any, any>[]>();\n\tfor (const endpoint of endpoints) {\n\t\tconst surface = endpoint.surface?.id;\n\t\tif (!surface) continue;\n\t\tbySurface.set(surface, [...(bySurface.get(surface) ?? []), endpoint]);\n\t}\n\n\treturn [...bySurface].flatMap(([surface, served]) => {\n\t\tconst base = env[provideKey(surface, 'url')];\n\t\tif (!base) return [];\n\n\t\treturn http.all(`${trim(base)}/*`, ({ request }) =>\n\t\t\tserve(request, async (state) => {\n\t\t\t\tlet app = state.surfaces.get(surface);\n\t\t\t\tif (!app) {\n\t\t\t\t\tapp = Promise.resolve().then(() => {\n\t\t\t\t\t\tconst hono = new Hono();\n\t\t\t\t\t\tHonoEndpoint.addRoutes(served, state.discovery, hono);\n\t\t\t\t\t\treturn hono;\n\t\t\t\t\t});\n\t\t\t\t\tstate.surfaces.set(surface, app);\n\t\t\t\t}\n\t\t\t\t// From this process, so from a loopback peer: see `./peer`.\n\t\t\t\treturn (await app).fetch(request, inProcessBindings());\n\t\t\t}),\n\t\t);\n\t});\n}\n\n/**\n * An external API's app fake, answering at the URL the test stage resolved for\n * it — so a handler that calls Polar calls the fake, and the test sets up\n * nothing.\n *\n * Not per test, unlike a surface: a fake stands in for somebody else's server,\n * which no test's transaction reaches. An image fake has no handler here — its\n * container answers on localhost, which is let through.\n */\nfunction fakeHandler(\n\tid: string,\n\tfake: Fake,\n\tenv: Record<string, string | undefined>,\n) {\n\tconst base = env[provideKey(id, 'url')];\n\tif (fake.kind !== 'app' || !base) return [];\n\n\treturn [\n\t\thttp.all(`${trim(base)}/*`, ({ request }) => fake.handler.fetch(request)),\n\t];\n}\n\n/**\n * A construct's client for this test, by service name — through the test's own\n * discovery, so a topic or queue is its recorder and a database its\n * transaction, exactly as the test's endpoints get them.\n */\nasync function resolveService(\n\tapp: LoadedApp,\n\tstate: ContextState,\n\tname: string,\n): Promise<unknown> {\n\tconst construct = app.consumables.find(\n\t\t(candidate) => candidate.service.serviceName === name,\n\t);\n\tif (!construct) {\n\t\tthrow new UnknownService(\n\t\t\tname,\n\t\t\tapp.consumables.map((candidate) => candidate.service.serviceName),\n\t\t);\n\t}\n\n\tconst registered = await state.discovery.register([construct.service]);\n\treturn (registered as Record<string, unknown>)[name];\n}\n\n/** An auth server, served at its URL, on the transaction of the test that asked. */\nfunction authHandler(\n\tauth: BetterAuth,\n\tenv: Record<string, string | undefined>,\n\tenvParser: EnvironmentParser<{}>,\n) {\n\tconst base = trim(env[provideKey(auth.id, 'url')] ?? '');\n\n\t// The whole origin, not only `basePath`: the auth server answers its own\n\t// host deployed, and a redirect it issues — to `/` after verifying a magic\n\t// link — lands on it. Paths it does not route get its own 404.\n\treturn http.all(`${base}/*`, ({ request }) =>\n\t\tserve(request, async (state) => {\n\t\t\tlet app = state.auth.get(auth);\n\t\t\tif (!app) {\n\t\t\t\tapp = auth\n\t\t\t\t\t.server({ envParser, context: serviceContext })\n\t\t\t\t\t.then(({ app }) => app);\n\t\t\t\tstate.auth.set(auth, app);\n\t\t\t}\n\t\t\t// A loopback peer, so an API's session check — an internal caller —\n\t\t\t// keeps the browser's address it carries: see `./peer`.\n\t\t\treturn (await app).fetch(request, inProcessBindings());\n\t\t}),\n\t);\n}\n\n/** Handle a request as the server side of the test it was made for. */\nasync function serve(\n\trequest: Request,\n\thandle: (state: ContextState) => Promise<Response>,\n): Promise<Response> {\n\tconst id = testContextOf(request);\n\tconst state = id ? contexts.get(id) : undefined;\n\tif (!id || !state) throw new UnknownTestContext(request.url, id);\n\n\treturn runAsServer(id, () => handle(state));\n}\n\nfunction trim(url: string): string {\n\treturn url.replace(/\\/$/, '');\n}\n\nfunction isLocal(url: URL): boolean {\n\treturn (\n\t\turl.hostname === 'localhost' ||\n\t\turl.hostname === '127.0.0.1' ||\n\t\turl.hostname.endsWith('.localhost')\n\t);\n}\n\n/** What `signInWithMagicLink` uses of a better-auth client. */\nexport interface MagicLinkAuthClient<TSession> {\n\tsignIn: {\n\t\tmagicLink(input: {\n\t\t\temail: string;\n\t\t}): Promise<{ error?: { message?: string } | null }>;\n\t};\n\tgetSession(): Promise<{ data: TSession | null }>;\n}\n\n/**\n * Sign a test's browser in the way a person does: ask the auth server for a\n * magic link, open the email it sent, follow the link.\n *\n * What the generated `browser.signIn(email)` calls. The address's mail is\n * cleared first — so the link is this request's, not one an earlier test left\n * — and cleared again after the test, like any address a test reads. Returns\n * the session the auth server then reports, as better-auth hands it back.\n */\nexport async function signInWithMagicLink<TSession>(\n\tbrowser: TestBrowser,\n\tauth: MagicLinkAuthClient<TSession>,\n\temail: string = freshAddress(),\n): Promise<TSession> {\n\tconst context = currentTestContext();\n\tconst state = context && contexts.get(context.id);\n\tif (!state) throw new UnknownTestContext('signIn', context?.id);\n\tif (!state.mailbox) throw new NoInbox();\n\n\tconst inbox = state.mailbox(email);\n\tawait inbox.clear();\n\n\tconst requested = await auth.signIn.magicLink({ email });\n\tif (requested.error) {\n\t\tthrow new SignInFailed(\n\t\t\temail,\n\t\t\t`the auth server refused the magic link: ${requested.error.message ?? 'no reason given'}`,\n\t\t);\n\t}\n\n\tconst mail = await inbox.last();\n\tif (!mail.link) throw new SignInFailed(email, 'its email held no link');\n\tawait browser.visit(mail.link);\n\n\tconst { data } = await auth.getSession();\n\tif (!data) {\n\t\tthrow new SignInFailed(\n\t\t\temail,\n\t\t\t'the auth server reported no session after the link was opened',\n\t\t);\n\t}\n\treturn data;\n}\n\n/**\n * An address nobody else signs in as — what `browser.signIn()` uses when the\n * test does not care who it is.\n *\n * Unique rather than only seeded: tests in other files run at the same time,\n * against the same Mailpit and the same unique columns, and a seeded address\n * repeats wherever two tests share a name. The readable half is the seeded\n * faker's, so a failure still names somebody.\n */\nfunction freshAddress(): string {\n\tconst name = faker.internet\n\t\t.username()\n\t\t.toLowerCase()\n\t\t.replace(/[^a-z0-9]/g, '');\n\n\treturn `${name}.${randomUUID().slice(0, 8)}@example.test`;\n}\n\n/** `browser.signIn` finished without a session. */\nexport class SignInFailed extends Error {\n\tconstructor(\n\t\treadonly email: string,\n\t\treadonly reason: string,\n\t) {\n\t\tsuper(`Signing ${email} in failed: ${reason}.`);\n\t\tthis.name = 'SignInFailed';\n\t}\n}\n\n/** A request reached an in-process server without a test to belong to. */\nexport class UnknownTestContext extends Error {\n\tconstructor(\n\t\treadonly url: string,\n\t\treadonly id: string | undefined,\n\t) {\n\t\tsuper(\n\t\t\tid\n\t\t\t\t? `${url} was requested for test ${id}, which is not running. A ` +\n\t\t\t\t\t\t`request that outlives its test — an un-awaited call — lands here.`\n\t\t\t\t: `${url} was requested outside any test. Make the request inside a ` +\n\t\t\t\t\t\t`featureTest, so it reaches that test's transactions.`,\n\t\t);\n\t\tthis.name = 'UnknownTestContext';\n\t}\n}\n\n/** `mailbox` was used in an app that declares no Email construct. */\nexport class NoInbox extends Error {\n\tconstructor() {\n\t\tsuper(\n\t\t\t`mailbox() reads the inbox of the app's Email construct, and none was ` +\n\t\t\t\t`found in featureTest's modules — or \\`gkm test\\` did not inject its ` +\n\t\t\t\t`<ID>_INBOX_URL.`,\n\t\t);\n\t\tthis.name = 'NoInbox';\n\t}\n}\n\n/** `db.get(name)` named no database the test is handed. */\nexport class UnknownDatabase extends Error {\n\tconstructor(\n\t\treadonly database: string,\n\t\treadonly known: readonly string[],\n\t) {\n\t\tsuper(\n\t\t\t`db.get('${database}') names no database of this app's. ` +\n\t\t\t\t(known.length > 0\n\t\t\t\t\t? `Its databases: ${known.join(', ')}. `\n\t\t\t\t\t: 'It declares no database of its own. ') +\n\t\t\t\t`A tenant an auth server owns is reached through that server, and a ` +\n\t\t\t\t`reader through the database it reads.`,\n\t\t);\n\t\tthis.name = 'UnknownDatabase';\n\t}\n}\n\n/** A factory keyed by a service name no database the app declares has. */\nexport class UnknownFactory extends Error {\n\tconstructor(\n\t\treadonly factory: string,\n\t\treadonly known: readonly string[],\n\t) {\n\t\tsuper(\n\t\t\t`There is a test factory for '${factory}', and no database this app ` +\n\t\t\t\t`declares is called that. ` +\n\t\t\t\t(known.length > 0\n\t\t\t\t\t? `Its databases: ${known.join(', ')}. `\n\t\t\t\t\t: 'It declares no database. ') +\n\t\t\t\t`Name the file after the database construct: test/factories/<construct>.ts.`,\n\t\t);\n\t\tthis.name = 'UnknownFactory';\n\t}\n}\n\n/** A published message the consumer's own schema refuses. */\nexport class MessageRejected extends Error {\n\tconstructor(\n\t\treadonly consumer: string,\n\t\treadonly published: PublishedMessage,\n\t\treadonly issues: ReadonlyArray<StandardSchemaV1.Issue>,\n\t) {\n\t\tsuper(\n\t\t\t`${consumer} refuses '${published.type}': ${issues\n\t\t\t\t.map((issue) => issue.message)\n\t\t\t\t.join('; ')}. What is published must be what the consumer's schema ` +\n\t\t\t\t'takes — fix the producer, or the schema.',\n\t\t);\n\t\tthis.name = 'MessageRejected';\n\t}\n}\n\n/** A consumer that threw while handling what the test published. */\nexport class DeliveryFailed extends Error {\n\tconstructor(\n\t\treadonly consumer: string,\n\t\treadonly messages: readonly PublishedMessage[],\n\t\toverride readonly cause: unknown,\n\t) {\n\t\tsuper(\n\t\t\t`${consumer} failed handling ${messages\n\t\t\t\t.map(({ type }) => `'${type}'`)\n\t\t\t\t.join(', ')}: ${(cause as Error)?.message ?? String(cause)}. ` +\n\t\t\t\t'Deployed, the message would be retried; here the failure is the result.',\n\t\t\t{ cause },\n\t\t);\n\t\tthis.name = 'DeliveryFailed';\n\t}\n}\n\n/** Consumers that kept publishing to each other without settling. */\nexport class DeliveryDidNotSettle extends Error {\n\tconstructor(\n\t\treadonly rounds: number,\n\t\treadonly channels: readonly string[],\n\t) {\n\t\tsuper(\n\t\t\t`Delivery did not settle after ${rounds} rounds — consumers are still ` +\n\t\t\t\t`publishing to ${channels.join(', ')}. A consumer that publishes to ` +\n\t\t\t\t'what triggers it loops forever deployed too.',\n\t\t);\n\t\tthis.name = 'DeliveryDidNotSettle';\n\t}\n}\n\n/** `services.get(name)` for a name no construct of the app is served by. */\nexport class UnknownService extends Error {\n\tconstructor(\n\t\treadonly serviceName: string,\n\t\treadonly available: readonly string[],\n\t) {\n\t\tsuper(\n\t\t\t`The app declares no construct served as '${serviceName}'. Its services are: ` +\n\t\t\t\t`${available.join(', ') || 'none'}.`,\n\t\t);\n\t\tthis.name = 'UnknownService';\n\t}\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"testing.cjs","names":["EnvironmentParser","ServiceDiscovery","http","TEST_CONTEXT_HEADER","Hono","ServiceDiscovery","EnvironmentParser","createObjectHeaders","createCookieHeaderAccessor","runWithRequestContext","ForbiddenError","DefaultAuditor","executeWithAuditTransaction","ResponseBuilder","Endpoint","publishConstructEvents","ServiceDiscovery","EnvironmentParser","FunctionBuilder","DefaultAuditor","runWithRequestContext","publishEvents","ServiceDiscovery","EnvironmentParser","runWithRequestContext","ServiceDiscovery","EnvironmentParser","runWithRequestContext","fileURLToPath","readFileSync","existsSync","tls","TestBrowser","setupServer","installContextFetch","randomUUID","TransactionRegistry","ServiceDiscovery","runInTestContext","test","EnvironmentParser","Endpoint","KyselyDatabase","BetterAuth","Email","isConsumable","Topic","Queue","provideKey","createMailbox","runAsServer","currentTestContext","http","hono","Hono","serviceContext","testContextOf","faker"],"sources":["../../src/testing/peer.ts","../../src/endpoints/MswEndpointAdaptor.ts","../../src/endpoints/TestEndpointAdaptor.ts","../../src/functions/TestFunctionAdaptor.ts","../../src/queue/TestQueueAdaptor.ts","../../src/subscribers/TestSubscriberAdaptor.ts","../../src/testing/manifest.ts","../../src/testing/featureTest.ts"],"sourcesContent":["/**\n * The TCP peer a test's in-process requests arrive from.\n *\n * A feature test hands a request straight to a surface's Hono app — no\n * socket, no server — so the app's bindings have no peer to read. Deployed,\n * every request has one, and what a surface trusts follows from it: the auth\n * server honours `x-gkm-client-ip` only from an internal caller, a loopback\n * or private peer with no `Origin` and no forwarding header. With no peer at\n * all the header was dropped, and every test's session check became the same\n * client to Better Auth's rate limiter.\n *\n * So an in-process dispatch says where it came from, the way\n * `@hono/node-server` does: its bindings carry `incoming.socket.remoteAddress`.\n * The address is loopback because that is the truth — the request came from\n * this process. A browser's own address still travels in its\n * `x-forwarded-for`, which makes it outside traffic exactly as it would be\n * behind the stack's proxy.\n *\n * Only a test's dispatch passes these. A runtime with no socket of its own\n * (Lambda, Bun) still has no peer, and a request with no peer is still not an\n * internal caller's.\n */\n\n/** The address an in-process request presents as its peer. */\nexport const IN_PROCESS_PEER_ADDRESS = '127.0.0.1';\n\n/** The part of `@hono/node-server`'s bindings a surface reads its peer from. */\nexport interface InProcessBindings {\n\tincoming: { socket: { remoteAddress: string } };\n}\n\n/** Bindings for `app.fetch(request, bindings)` from inside this process. */\nexport function inProcessBindings(): InProcessBindings {\n\treturn { incoming: { socket: { remoteAddress: IN_PROCESS_PEER_ADDRESS } } };\n}\n","import { EnvironmentParser } from '@geekmidas/envkit';\nimport type { Service } from '@geekmidas/services';\nimport { ServiceDiscovery } from '@geekmidas/services';\nimport { TEST_CONTEXT_HEADER } from '@geekmidas/testkit/context';\nimport { Hono } from 'hono';\nimport { type HttpHandler, http } from 'msw';\nimport { inProcessBindings } from '../testing/peer';\nimport type { Endpoint } from './Endpoint';\nimport { HonoEndpoint } from './HonoEndpointAdaptor';\n\n/**\n * Header used to identify which test context a request belongs to — defined\n * once, in testkit, where the stamped `fetch` that writes it lives.\n */\nexport { TEST_CONTEXT_HEADER };\n\n/**\n * Per-test context containing an isolated ServiceDiscovery instance.\n * Registered in the context map and looked up per-request via the context ID header.\n */\nexport interface MswTestContext {\n\tserviceDiscovery: ServiceDiscovery<any>;\n}\n\n/**\n * Options for creating MSW handlers from endpoint constructs.\n *\n * @example\n * ```typescript\n * import { createMswHandlers, registerTestContext } from '@geekmidas/constructs/testing';\n * import { setupServer } from 'msw/node';\n *\n * // Create handlers once (global)\n * const { handlers, registerContext, removeContext } = createMswHandlers(\n * [getUsers, createUser],\n * { baseURL: 'http://localhost:3000' },\n * );\n * const server = setupServer(...handlers);\n *\n * // Per test: register an isolated context with its own services/transaction\n * it('should list users', async ({ db }) => {\n * const contextId = crypto.randomUUID();\n * registerContext(contextId, {\n * services: { database: db, auth: mockAuth },\n * });\n *\n * const api = createApi({\n * baseURL: 'http://localhost:3000',\n * headers: { [TEST_CONTEXT_HEADER]: contextId },\n * });\n *\n * const result = await api('GET /users');\n * expect(result).toBeDefined();\n *\n * removeContext(contextId);\n * });\n * ```\n */\nexport interface CreateMswHandlersOptions {\n\t/** Base URL the client fetches from (e.g., 'http://localhost:3000') */\n\tbaseURL: string;\n}\n\n/**\n * Options for registering a per-test context.\n * Follows the same pattern as TestRequestAdaptor — services, database and\n * auditorStorage are provided explicitly. A topic is a service under its own\n * name, so a recorder in `services` (`{ users: recorder }`) captures what an\n * endpoint publishes to it.\n */\nexport interface RegisterContextOptions {\n\t/** Service instances keyed by serviceName */\n\tservices?: Record<string, unknown>;\n\t/** Database instance — required when endpoints use .database() */\n\tdatabase?: unknown;\n\t/** Audit storage instance — required when endpoints use .auditor() */\n\tauditorStorage?: unknown;\n}\n\nconst MSW_HTTP_METHODS = [\n\t'get',\n\t'post',\n\t'put',\n\t'patch',\n\t'delete',\n\t'options',\n] as const;\n\ntype MswHttpMethod = (typeof MSW_HTTP_METHODS)[number];\n\n/**\n * Result of creating MSW handlers from endpoint constructs.\n */\nexport interface CreateMswHandlersResult {\n\t/** MSW handlers to pass to setupServer() */\n\thandlers: HttpHandler[];\n\t/** Register an isolated context for a test */\n\tregisterContext: (id: string, options: RegisterContextOptions) => void;\n}\n\n/**\n * Creates MSW HTTP handlers from endpoint constructs.\n *\n * Mounts endpoints on a Hono app and creates MSW handlers that intercept\n * fetch requests and route them through `app.request()` — giving frontend\n * tests full endpoint behavior (validation, auth, sessions) without HTTP.\n *\n * Each test registers its own isolated context via `registerContext()`,\n * which is resolved per-request using the `x-test-context-id` header.\n * This allows concurrent tests with their own transactions and services.\n *\n * @param endpoints - Array of endpoint constructs to create handlers for\n * @param options - Configuration including baseURL\n * @returns MSW handlers, the Hono app, and context management functions\n */\nexport function createMswHandlers(\n\tendpoints: Endpoint<any, any, any, any, any, any>[],\n\toptions: CreateMswHandlersOptions,\n): CreateMswHandlersResult {\n\tconst { baseURL } = options;\n\tconst contexts = new Map<string, MswTestContext>();\n\n\t/**\n\t * Register an isolated context for a test.\n\t * Creates a fresh ServiceDiscovery and pre-registers all provided services.\n\t */\n\tfunction registerContext(id: string, ctxOptions: RegisterContextOptions) {\n\t\tconst envParser = new EnvironmentParser({});\n\t\tconst serviceDiscovery = new ServiceDiscovery(envParser);\n\n\t\tconst serviceDefs: Service[] = [];\n\n\t\t// Register explicit services\n\t\tif (ctxOptions.services) {\n\t\t\tfor (const [name, instance] of Object.entries(ctxOptions.services)) {\n\t\t\t\tserviceDefs.push({\n\t\t\t\t\tserviceName: name,\n\t\t\t\t\tregister: () => instance,\n\t\t\t\t} as Service);\n\t\t\t}\n\t\t}\n\n\t\t// Register database service from endpoint metadata\n\t\tif (ctxOptions.database !== undefined) {\n\t\t\tfor (const endpoint of endpoints) {\n\t\t\t\tif (endpoint.databaseService) {\n\t\t\t\t\tserviceDefs.push({\n\t\t\t\t\t\tserviceName: endpoint.databaseService.serviceName,\n\t\t\t\t\t\tregister: () => ctxOptions.database,\n\t\t\t\t\t} as Service);\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// Register auditor storage service from endpoint metadata\n\t\tif (ctxOptions.auditorStorage !== undefined) {\n\t\t\tfor (const endpoint of endpoints) {\n\t\t\t\tif (endpoint.auditorStorageService) {\n\t\t\t\t\tserviceDefs.push({\n\t\t\t\t\t\tserviceName: endpoint.auditorStorageService.serviceName,\n\t\t\t\t\t\tregister: () => ctxOptions.auditorStorage,\n\t\t\t\t\t} as Service);\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tif (serviceDefs.length > 0) {\n\t\t\tserviceDiscovery.register(serviceDefs);\n\t\t}\n\n\t\tcontexts.set(id, { serviceDiscovery });\n\t}\n\n\t// Create a Hono app per-request that uses the correct ServiceDiscovery.\n\t// We use a wrapper app that resolves the context from the header,\n\t// then delegates to a context-specific Hono app.\n\tconst handlers: HttpHandler[] = [];\n\n\tfor (const endpoint of endpoints) {\n\t\tconst method = endpoint.method.toLowerCase() as MswHttpMethod;\n\t\tif (!MSW_HTTP_METHODS.includes(method)) continue;\n\n\t\tconst mswUrl = `${baseURL}${endpoint.route}`;\n\t\tconst mswMethod = http[method];\n\n\t\thandlers.push(\n\t\t\tmswMethod(mswUrl, async ({ request }) => {\n\t\t\t\tconst contextId = request.headers.get(TEST_CONTEXT_HEADER);\n\t\t\t\tconst ctx = contextId ? contexts.get(contextId) : undefined;\n\n\t\t\t\tif (!ctx) {\n\t\t\t\t\treturn new Response(\n\t\t\t\t\t\tJSON.stringify({\n\t\t\t\t\t\t\terror: 'Missing or unknown test context ID',\n\t\t\t\t\t\t\thint: `Set the '${TEST_CONTEXT_HEADER}' header to a registered context ID`,\n\t\t\t\t\t\t}),\n\t\t\t\t\t\t{ status: 500, headers: { 'content-type': 'application/json' } },\n\t\t\t\t\t);\n\t\t\t\t}\n\n\t\t\t\t// Build a fresh Hono app with this context's ServiceDiscovery\n\t\t\t\tconst app = new Hono();\n\t\t\t\tHonoEndpoint.addRoute(endpoint, ctx.serviceDiscovery as any, app);\n\n\t\t\t\t// From this process: a loopback peer, as a socket on this machine has.\n\t\t\t\tconst response = await app.request(\n\t\t\t\t\trequest,\n\t\t\t\t\tundefined,\n\t\t\t\t\tinProcessBindings(),\n\t\t\t\t);\n\n\t\t\t\treturn new Response(response.body, {\n\t\t\t\t\tstatus: response.status,\n\t\t\t\t\tstatusText: response.statusText,\n\t\t\t\t\theaders: response.headers,\n\t\t\t\t});\n\t\t\t}),\n\t\t);\n\t}\n\n\treturn {\n\t\thandlers,\n\t\tregisterContext,\n\t};\n}\n","import type {\n\tAuditActor,\n\tAuditableAction,\n\tAuditStorage,\n} from '@geekmidas/audit';\nimport { DefaultAuditor } from '@geekmidas/audit';\nimport { EnvironmentParser } from '@geekmidas/envkit';\nimport { ForbiddenError } from '@geekmidas/errors';\nimport type { EventPublisher } from '@geekmidas/events';\nimport type { Logger } from '@geekmidas/logger';\nimport type {\n\tInferComposableStandardSchema,\n\tInferStandardSchema,\n} from '@geekmidas/schema';\nimport {\n\trunWithRequestContext,\n\ttype Service,\n\tServiceDiscovery,\n\ttype ServiceRecord,\n} from '@geekmidas/services';\nimport type { StandardSchemaV1 } from '@standard-schema/spec';\nimport { publishConstructEvents } from '../publisher';\nimport type { HttpMethod } from '../types';\nimport type { MappedAudit } from './audit';\nimport {\n\ttype CookieOptions,\n\tEndpoint,\n\ttype EndpointSchemas,\n\tResponseBuilder,\n} from './Endpoint';\nimport {\n\tcreateCookieHeaderAccessor,\n\tcreateObjectHeaders,\n} from './lazyAccessors';\nimport {\n\ttype AuditExecutionContext,\n\texecuteWithAuditTransaction,\n} from './processAudits';\n\nexport type TestHttpResponse<TBody = any> = {\n\tbody: TBody;\n\tstatus: number;\n\theaders: Record<string, string | string[]>;\n};\n\n/**\n * Serializes a cookie into a Set-Cookie header string\n */\nfunction serializeCookie(\n\tname: string,\n\tvalue: string,\n\toptions?: CookieOptions,\n): string {\n\tlet cookieString = `${name}=${value}`;\n\n\tif (options) {\n\t\tif (options.maxAge !== undefined) {\n\t\t\tcookieString += `; Max-Age=${options.maxAge}`;\n\t\t}\n\t\tif (options.expires) {\n\t\t\tcookieString += `; Expires=${options.expires.toUTCString()}`;\n\t\t}\n\t\tif (options.domain) {\n\t\t\tcookieString += `; Domain=${options.domain}`;\n\t\t}\n\t\tif (options.path) {\n\t\t\tcookieString += `; Path=${options.path}`;\n\t\t}\n\t\tif (options.httpOnly) {\n\t\t\tcookieString += '; HttpOnly';\n\t\t}\n\t\tif (options.secure) {\n\t\t\tcookieString += '; Secure';\n\t\t}\n\t\tif (options.sameSite) {\n\t\t\tcookieString += `; SameSite=${options.sameSite}`;\n\t\t}\n\t}\n\n\treturn cookieString;\n}\n\nexport class TestEndpointAdaptor<\n\tTRoute extends string,\n\tTMethod extends HttpMethod,\n\tTInput extends EndpointSchemas = {},\n\tTOutSchema extends StandardSchemaV1 | undefined = undefined,\n\tTServices extends Service[] = [],\n\tTLogger extends Logger = Logger,\n\tTSession = unknown,\n\tTAuditStorage extends AuditStorage | undefined = undefined,\n\tTAuditStorageServiceName extends string = string,\n\tTAuditAction extends AuditableAction<string, unknown> = AuditableAction<\n\t\tstring,\n\t\tunknown\n\t>,\n\tTDatabase = undefined,\n\tTDatabaseServiceName extends string = string,\n> {\n\tstatic getDefaultServiceDiscover<\n\t\tTRoute extends string,\n\t\tTMethod extends HttpMethod,\n\t\tTInput extends EndpointSchemas = {},\n\t\tTOutSchema extends StandardSchemaV1 | undefined = undefined,\n\t\tTServices extends Service[] = [],\n\t\tTLogger extends Logger = Logger,\n\t\tTSession = unknown,\n\t\tTAuditStorage extends AuditStorage | undefined = undefined,\n\t\tTAuditStorageServiceName extends string = string,\n\t\tTAuditAction extends AuditableAction<string, unknown> = AuditableAction<\n\t\t\tstring,\n\t\t\tunknown\n\t\t>,\n\t\tTDatabase = undefined,\n\t\tTDatabaseServiceName extends string = string,\n\t>(\n\t\t_endpoint: Endpoint<\n\t\t\tTRoute,\n\t\t\tTMethod,\n\t\t\tTInput,\n\t\t\tTOutSchema,\n\t\t\tTServices,\n\t\t\tTLogger,\n\t\t\tTSession,\n\t\t\tTAuditStorage,\n\t\t\tTAuditStorageServiceName,\n\t\t\tTAuditAction,\n\t\t\tTDatabase,\n\t\t\tTDatabaseServiceName\n\t\t>,\n\t) {\n\t\treturn ServiceDiscovery.getInstance(new EnvironmentParser({}));\n\t}\n\tconstructor(\n\t\tprivate readonly endpoint: Endpoint<\n\t\t\tTRoute,\n\t\t\tTMethod,\n\t\t\tTInput,\n\t\t\tTOutSchema,\n\t\t\tTServices,\n\t\t\tTLogger,\n\t\t\tTSession,\n\t\t\tTAuditStorage,\n\t\t\tTAuditStorageServiceName,\n\t\t\tTAuditAction,\n\t\t\tTDatabase,\n\t\t\tTDatabaseServiceName\n\t\t>,\n\t\tprivate serviceDiscovery: ServiceDiscovery<any> = TestEndpointAdaptor.getDefaultServiceDiscover(\n\t\t\tendpoint,\n\t\t),\n\t) {}\n\n\tasync fullRequest(\n\t\tctx: TestRequestAdaptor<\n\t\t\tTInput,\n\t\t\tTServices,\n\t\t\tTAuditStorage,\n\t\t\tTAuditStorageServiceName,\n\t\t\tTDatabase,\n\t\t\tTDatabaseServiceName\n\t\t>,\n\t): Promise<TestHttpResponse<InferStandardSchema<TOutSchema>>> {\n\t\tconst body = await this.endpoint.parseInput((ctx as any).body, 'body');\n\t\tconst query = await this.endpoint.parseInput((ctx as any).query, 'query');\n\t\tconst params = await this.endpoint.parseInput(\n\t\t\t(ctx as any).params,\n\t\t\t'params',\n\t\t);\n\n\t\t// Lazy accessors - defer parsing until needed\n\t\tconst header = createObjectHeaders(ctx.headers);\n\t\tconst cookie = createCookieHeaderAccessor(ctx.headers.cookie);\n\n\t\t// Request context setup\n\t\tconst startTime = Date.now();\n\t\tconst requestId =\n\t\t\t(ctx as any).requestId ??\n\t\t\tctx.headers['x-request-id'] ??\n\t\t\tcrypto.randomUUID();\n\n\t\tconst logger = this.endpoint.logger.child({\n\t\t\trequestId,\n\t\t\troute: this.endpoint.route,\n\t\t\thost: ctx.headers.host,\n\t\t\tmethod: this.endpoint.method,\n\t\t}) as TLogger;\n\n\t\t// Get database from context for session extraction\n\t\tconst rawDb = (ctx as any).database as TDatabase;\n\n\t\t// Wrap handler execution in request context\n\t\tconst operation = `${this.endpoint.method} ${this.endpoint.route}`;\n\t\treturn runWithRequestContext(\n\t\t\t{ logger, requestId, startTime, operation },\n\t\t\tasync () => {\n\t\t\t\tconst session = await this.endpoint.getSession({\n\t\t\t\t\tlogger,\n\t\t\t\t\tservices: ctx.services,\n\t\t\t\t\theader,\n\t\t\t\t\tcookie,\n\t\t\t\t\t...(rawDb !== undefined && { db: rawDb }),\n\t\t\t\t} as any);\n\n\t\t\t\t// Check authorization\n\t\t\t\tconst isAuthorized = await this.endpoint.authorize({\n\t\t\t\t\theader,\n\t\t\t\t\tcookie,\n\t\t\t\t\tservices: ctx.services,\n\t\t\t\t\tlogger,\n\t\t\t\t\tsession,\n\t\t\t\t\t...(rawDb !== undefined && { db: rawDb }),\n\t\t\t\t\tbody,\n\t\t\t\t\tquery,\n\t\t\t\t\tparams,\n\t\t\t\t} as any);\n\n\t\t\t\tif (!isAuthorized) {\n\t\t\t\t\tlogger.warn('Forbidden access attempt');\n\t\t\t\t\tthrow new ForbiddenError(\n\t\t\t\t\t\t'Forbidden access to the endpoint',\n\t\t\t\t\t\t'You do not have permission to access this resource.',\n\t\t\t\t\t);\n\t\t\t\t}\n\n\t\t\t\t// Create audit context if audit storage is provided\n\t\t\t\t// The auditorStorage instance is required when endpoint uses .auditor()\n\t\t\t\tconst auditorStorage = (ctx as any).auditorStorage as TAuditStorage;\n\t\t\t\tlet auditContext: AuditExecutionContext<TAuditAction> | undefined;\n\n\t\t\t\tif (auditorStorage) {\n\t\t\t\t\t// Extract actor if configured\n\t\t\t\t\tlet actor: AuditActor = { id: 'system', type: 'system' };\n\t\t\t\t\tif (this.endpoint.actorExtractor) {\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\tactor = await this.endpoint.actorExtractor({\n\t\t\t\t\t\t\t\tservices: ctx.services as any,\n\t\t\t\t\t\t\t\tsession,\n\t\t\t\t\t\t\t\theader,\n\t\t\t\t\t\t\t\tcookie,\n\t\t\t\t\t\t\t\tlogger,\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t} catch (error) {\n\t\t\t\t\t\t\tlogger.error(\n\t\t\t\t\t\t\t\terror as Error,\n\t\t\t\t\t\t\t\t'Failed to extract actor for audits',\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\tconst auditor = new DefaultAuditor<TAuditAction>({\n\t\t\t\t\t\tactor,\n\t\t\t\t\t\tstorage: auditorStorage as AuditStorage,\n\t\t\t\t\t\tmetadata: {\n\t\t\t\t\t\t\tendpoint: this.endpoint.route,\n\t\t\t\t\t\t\tmethod: this.endpoint.method,\n\t\t\t\t\t\t},\n\t\t\t\t\t});\n\n\t\t\t\t\tauditContext = { auditor, storage: auditorStorage as AuditStorage };\n\t\t\t\t}\n\n\t\t\t\t// Warn if declarative audits are configured but no audit storage\n\t\t\t\tconst audits = this.endpoint.audits as MappedAudit<\n\t\t\t\t\tTAuditAction,\n\t\t\t\t\tTOutSchema\n\t\t\t\t>[];\n\t\t\t\tif (!auditContext && audits?.length) {\n\t\t\t\t\tlogger.warn('No auditor storage service available');\n\t\t\t\t}\n\n\t\t\t\t// Execute handler with automatic audit transaction support\n\t\t\t\tconst result = await executeWithAuditTransaction(\n\t\t\t\t\tauditContext,\n\t\t\t\t\tasync (auditor) => {\n\t\t\t\t\t\t// Use audit transaction as db if available (when storage has same database)\n\t\t\t\t\t\t// For testing, the tester controls whether to use transactional auditing\n\t\t\t\t\t\tconst trx = auditor?.getTransaction?.();\n\t\t\t\t\t\tconst db = trx ?? rawDb;\n\n\t\t\t\t\t\tconst responseBuilder = new ResponseBuilder();\n\t\t\t\t\t\tconst response = await this.endpoint.handler(\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tbody,\n\t\t\t\t\t\t\t\tquery,\n\t\t\t\t\t\t\t\tparams,\n\t\t\t\t\t\t\t\tsession,\n\t\t\t\t\t\t\t\tservices: ctx.services,\n\t\t\t\t\t\t\t\tlogger,\n\t\t\t\t\t\t\t\theader,\n\t\t\t\t\t\t\t\tcookie,\n\t\t\t\t\t\t\t\tauditor,\n\t\t\t\t\t\t\t\tdb,\n\t\t\t\t\t\t\t} as any,\n\t\t\t\t\t\t\tresponseBuilder,\n\t\t\t\t\t\t);\n\n\t\t\t\t\t\t// Check if response has metadata\n\t\t\t\t\t\tlet data = response;\n\t\t\t\t\t\tlet metadata = responseBuilder.getMetadata();\n\n\t\t\t\t\t\tif (Endpoint.hasMetadata(response)) {\n\t\t\t\t\t\t\tdata = response.data;\n\t\t\t\t\t\t\tmetadata = response.metadata;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tconst output = await this.endpoint.parseOutput(data);\n\n\t\t\t\t\t\treturn { output, metadata, responseBuilder };\n\t\t\t\t\t},\n\t\t\t\t\t// Process declarative audits after handler (inside transaction)\n\t\t\t\t\tasync (result, auditor) => {\n\t\t\t\t\t\tif (!audits?.length) return;\n\n\t\t\t\t\t\tfor (const audit of audits) {\n\t\t\t\t\t\t\tif (audit.when && !audit.when(result.output as any)) {\n\t\t\t\t\t\t\t\tcontinue;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tconst payload = audit.payload(result.output as any);\n\t\t\t\t\t\t\tconst entityId = audit.entityId?.(result.output as any);\n\t\t\t\t\t\t\tauditor.audit(audit.type as any, payload as any, {\n\t\t\t\t\t\t\t\ttable: audit.table,\n\t\t\t\t\t\t\t\tentityId,\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t}\n\t\t\t\t\t},\n\t\t\t\t\t// Pass rawDb so storage can reuse existing transactions\n\t\t\t\t\t{ db: rawDb },\n\t\t\t\t);\n\n\t\t\t\tconst { output, metadata } = result;\n\n\t\t\t\t// A topic the test handed in as a service — a recorder — is published\n\t\t\t\t// to directly; any other is registered as it is deployed.\n\t\t\t\tawait publishConstructEvents(\n\t\t\t\t\tthis.endpoint,\n\t\t\t\t\toutput,\n\t\t\t\t\tthis.serviceDiscovery,\n\t\t\t\t\tthis.endpoint.logger,\n\t\t\t\t\tctx.services as Record<string, unknown>,\n\t\t\t\t);\n\n\t\t\t\t// Convert cookies to Set-Cookie headers\n\t\t\t\tconst headers: Record<string, string | string[]> = {\n\t\t\t\t\t...(metadata.headers || {}),\n\t\t\t\t};\n\n\t\t\t\tif (metadata.cookies && metadata.cookies.size > 0) {\n\t\t\t\t\tconst setCookieValues: string[] = [];\n\t\t\t\t\tfor (const [name, cookie] of metadata.cookies.entries()) {\n\t\t\t\t\t\tsetCookieValues.push(\n\t\t\t\t\t\t\tserializeCookie(name, cookie.value, cookie.options),\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t\theaders['set-cookie'] = setCookieValues;\n\t\t\t\t}\n\n\t\t\t\t// Return HTTP response format\n\t\t\t\treturn {\n\t\t\t\t\tbody: output,\n\t\t\t\t\tstatus: metadata.status || 200,\n\t\t\t\t\theaders,\n\t\t\t\t};\n\t\t\t},\n\t\t);\n\t}\n\n\tasync request(\n\t\tctx: TestRequestAdaptor<\n\t\t\tTInput,\n\t\t\tTServices,\n\t\t\tTAuditStorage,\n\t\t\tTAuditStorageServiceName,\n\t\t\tTDatabase,\n\t\t\tTDatabaseServiceName\n\t\t>,\n\t): Promise<InferStandardSchema<TOutSchema>> {\n\t\tconst response = await this.fullRequest(ctx);\n\t\treturn response.body;\n\t}\n}\n\n/**\n * Conditional audit storage requirement - required when TAuditStorage is configured\n */\ntype AuditStorageRequirement<\n\tTAuditStorage extends AuditStorage | undefined = undefined,\n> = TAuditStorage extends undefined\n\t? {}\n\t: {\n\t\t\t/** Audit storage instance - required when endpoint uses .auditor() */\n\t\t\tauditorStorage: TAuditStorage;\n\t\t};\n\n/**\n * Conditional database requirement - required when TDatabase is configured\n */\ntype DatabaseRequirement<TDatabase = undefined> = TDatabase extends undefined\n\t? {}\n\t: {\n\t\t\t/** Database instance - required when endpoint uses .database() */\n\t\t\tdatabase: TDatabase;\n\t\t};\n\nexport type TestRequestAdaptor<\n\tTInput extends EndpointSchemas = {},\n\tTServices extends Service[] = [],\n\tTAuditStorage extends AuditStorage | undefined = undefined,\n\t_TAuditStorageServiceName extends string = string,\n\tTDatabase = undefined,\n\t_TDatabaseServiceName extends string = string,\n> = {\n\tservices: ServiceRecord<TServices>;\n\theaders: Record<string, string>;\n} & InferComposableStandardSchema<TInput> &\n\tAuditStorageRequirement<TAuditStorage> &\n\tDatabaseRequirement<TDatabase>;\n","import type { AuditableAction, Auditor, AuditStorage } from '@geekmidas/audit';\nimport { DefaultAuditor } from '@geekmidas/audit';\nimport { EnvironmentParser } from '@geekmidas/envkit';\nimport type { EventPublisher } from '@geekmidas/events';\nimport type { Logger } from '@geekmidas/logger';\nimport type {\n\tComposableStandardSchema,\n\tInferComposableStandardSchema,\n\tInferStandardSchema,\n} from '@geekmidas/schema';\nimport {\n\trunWithRequestContext,\n\ttype Service,\n\tServiceDiscovery,\n\ttype ServiceRecord,\n} from '@geekmidas/services';\nimport type { StandardSchemaV1 } from '@standard-schema/spec';\nimport { publishEvents } from '../publisher';\nimport type { Function } from './Function';\nimport { FunctionBuilder } from './FunctionBuilder';\n\nexport class TestFunctionAdaptor<\n\tTInput extends ComposableStandardSchema | undefined = undefined,\n\tTOutSchema extends StandardSchemaV1 | undefined = undefined,\n\tTServices extends Service[] = [],\n\tTLogger extends Logger = Logger,\n\tTAuditStorage extends AuditStorage | undefined = undefined,\n\tTAuditStorageServiceName extends string = string,\n\tTDatabase = undefined,\n\tTDatabaseServiceName extends string = string,\n\tTAuditAction extends AuditableAction<string, unknown> = AuditableAction<\n\t\tstring,\n\t\tunknown\n\t>,\n> {\n\tstatic getDefaultServiceDiscovery<\n\t\tTInput extends ComposableStandardSchema | undefined = undefined,\n\t\tTOutSchema extends StandardSchemaV1 | undefined = undefined,\n\t\tTServices extends Service[] = [],\n\t\tTLogger extends Logger = Logger,\n\t\tTAuditStorage extends AuditStorage | undefined = undefined,\n\t\tTAuditStorageServiceName extends string = string,\n\t\tTDatabase = undefined,\n\t\tTDatabaseServiceName extends string = string,\n\t\tTAuditAction extends AuditableAction<string, unknown> = AuditableAction<\n\t\t\tstring,\n\t\t\tunknown\n\t\t>,\n\t>(\n\t\t_fn: Function<\n\t\t\tTInput,\n\t\t\tTServices,\n\t\t\tTLogger,\n\t\t\tTOutSchema,\n\t\t\tTAuditStorage,\n\t\t\tTAuditStorageServiceName,\n\t\t\tTDatabase,\n\t\t\tTDatabaseServiceName,\n\t\t\tTAuditAction,\n\t\t\tany\n\t\t>,\n\t) {\n\t\treturn ServiceDiscovery.getInstance(new EnvironmentParser({}));\n\t}\n\n\tconstructor(\n\t\tprivate readonly fn: Function<\n\t\t\tTInput,\n\t\t\tTServices,\n\t\t\tTLogger,\n\t\t\tTOutSchema,\n\t\t\tTAuditStorage,\n\t\t\tTAuditStorageServiceName,\n\t\t\tTDatabase,\n\t\t\tTDatabaseServiceName,\n\t\t\tTAuditAction,\n\t\t\tany\n\t\t>,\n\t\tprivate serviceDiscovery: ServiceDiscovery<any> = TestFunctionAdaptor.getDefaultServiceDiscovery(\n\t\t\tfn,\n\t\t),\n\t) {}\n\n\tasync invoke(\n\t\tctx: TestFunctionRequest<TInput, TServices, TDatabase, TAuditAction>,\n\t): Promise<InferStandardSchema<TOutSchema>> {\n\t\t// Parse input if schema is provided\n\n\t\tconst parsedInput = await FunctionBuilder.parseComposableStandardSchema(\n\t\t\tctx.input,\n\t\t\tthis.fn.input,\n\t\t);\n\n\t\t// Create logger with context\n\t\tconst logger = this.fn.logger.child({\n\t\t\ttest: true,\n\t\t}) as TLogger;\n\n\t\t// Register services (use provided services or register from function)\n\t\tlet services: ServiceRecord<TServices>;\n\t\tif (ctx.services) {\n\t\t\tservices = ctx.services;\n\t\t} else {\n\t\t\tservices = await this.serviceDiscovery.register(this.fn.services);\n\t\t}\n\n\t\t// Resolve database (use provided db or register from function)\n\t\tlet db: TDatabase | undefined;\n\t\tif ('db' in ctx && ctx.db !== undefined) {\n\t\t\tdb = ctx.db;\n\t\t} else if (this.fn.databaseService) {\n\t\t\tconst dbServices = await this.serviceDiscovery.register([\n\t\t\t\tthis.fn.databaseService,\n\t\t\t]);\n\t\t\tdb = dbServices[\n\t\t\t\tthis.fn.databaseService.serviceName as keyof typeof dbServices\n\t\t\t] as TDatabase;\n\t\t}\n\n\t\t// Resolve auditor (use provided auditor or create from function)\n\t\tlet auditor: Auditor<TAuditAction> | undefined;\n\t\tif ('auditor' in ctx && ctx.auditor !== undefined) {\n\t\t\tauditor = ctx.auditor;\n\t\t} else if (this.fn.auditorStorageService) {\n\t\t\tconst auditServices = await this.serviceDiscovery.register([\n\t\t\t\tthis.fn.auditorStorageService,\n\t\t\t]);\n\t\t\tconst storage = auditServices[\n\t\t\t\tthis.fn.auditorStorageService.serviceName as keyof typeof auditServices\n\t\t\t] as AuditStorage;\n\n\t\t\tauditor = new DefaultAuditor<TAuditAction>({\n\t\t\t\tactor: { id: 'system', type: 'system' },\n\t\t\t\tstorage,\n\t\t\t\tmetadata: {\n\t\t\t\t\tfunction: this.fn.type,\n\t\t\t\t\ttest: true,\n\t\t\t\t},\n\t\t\t});\n\t\t}\n\n\t\t// Wrap execution in request context for service access via context.getLogger()\n\t\tconst requestId = `test-${Date.now()}`;\n\t\tconst startTime = Date.now();\n\n\t\treturn runWithRequestContext({ logger, requestId, startTime }, async () => {\n\t\t\t// Execute the function\n\t\t\tconst response = await this.fn.fn({\n\t\t\t\tinput: parsedInput,\n\t\t\t\tservices,\n\t\t\t\tlogger,\n\t\t\t\tdb,\n\t\t\t\tauditor,\n\t\t\t} as any);\n\n\t\t\t// Parse output if schema is provided\n\t\t\tconst output = await this.fn.parseOutput(response);\n\n\t\t\t// Flush audits if any were recorded\n\t\t\tif (auditor) {\n\t\t\t\tconst records = auditor.getRecords();\n\t\t\t\tif (records.length > 0) {\n\t\t\t\t\tlogger.debug(\n\t\t\t\t\t\t{ auditCount: records.length },\n\t\t\t\t\t\t'Flushing function audits',\n\t\t\t\t\t);\n\t\t\t\t\tawait auditor.flush();\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// A topic the test handed in as a service — a recorder — is published\n\t\t\t// to directly, as `TestEndpointAdaptor` does.\n\t\t\tawait publishEvents(\n\t\t\t\tlogger,\n\t\t\t\tthis.serviceDiscovery,\n\t\t\t\tthis.fn.events,\n\t\t\t\toutput,\n\t\t\t\tservices as Record<string, unknown>,\n\t\t\t);\n\n\t\t\treturn output;\n\t\t}) as Promise<InferStandardSchema<TOutSchema>>;\n\t}\n}\n\nexport type TestFunctionRequest<\n\tTInput extends ComposableStandardSchema | undefined = undefined,\n\tTServices extends Service[] = [],\n\tTDatabase = undefined,\n\tTAuditAction extends AuditableAction<string, unknown> = AuditableAction<\n\t\tstring,\n\t\tunknown\n\t>,\n> = {\n\tinput: InferComposableStandardSchema<TInput>;\n\tservices: ServiceRecord<TServices>;\n\tdb?: TDatabase;\n\tauditor?: Auditor<TAuditAction>;\n} & InferComposableStandardSchema<{ input: TInput }>;\n","import { EnvironmentParser } from '@geekmidas/envkit';\nimport type { Logger } from '@geekmidas/logger';\nimport type { InferStandardSchema } from '@geekmidas/schema';\nimport type { Service, ServiceRecord } from '@geekmidas/services';\nimport { runWithRequestContext, ServiceDiscovery } from '@geekmidas/services';\nimport type { StandardSchemaV1 } from '@standard-schema/spec';\nimport type { Queue, QueueContext } from './Queue';\n\n/**\n * In-memory test driver for a {@link Queue} worker. Hand it a batch of messages\n * and it registers the queue's services, runs the handler in a request context,\n * and returns the handler result — no SQS/pg-boss required. A queue with a\n * database gets `db` registered from it, or the one the request passes.\n *\n * @example\n * const adapter = new TestQueueAdaptor(ordersQueue);\n * await adapter.invoke({ messages: [{ orderId: '123' }] });\n */\nexport class TestQueueAdaptor<\n\tTName extends string = string,\n\tTMessage extends StandardSchemaV1 = StandardSchemaV1,\n\tTServices extends Service[] = [],\n\tTLogger extends Logger = Logger,\n\tTDatabase = undefined,\n\tTDatabaseServiceName extends string = string,\n> {\n\tstatic getDefaultServiceDiscovery() {\n\t\treturn ServiceDiscovery.getInstance(new EnvironmentParser({}));\n\t}\n\n\tconstructor(\n\t\tprivate readonly queue: Queue<\n\t\t\tTName,\n\t\t\tTMessage,\n\t\t\tTServices,\n\t\t\tTLogger,\n\t\t\tTDatabase,\n\t\t\tTDatabaseServiceName\n\t\t>,\n\t\tprivate serviceDiscovery: ServiceDiscovery<any> = TestQueueAdaptor.getDefaultServiceDiscovery(),\n\t) {}\n\n\tasync invoke(\n\t\trequest: TestQueueRequest<TMessage, TServices, TDatabase>,\n\t): Promise<unknown> {\n\t\tconst logger = this.queue.logger.child({ test: true }) as TLogger;\n\n\t\tconst services =\n\t\t\trequest.services ??\n\t\t\t((await this.serviceDiscovery.register(\n\t\t\t\tthis.queue.services,\n\t\t\t)) as ServiceRecord<TServices>);\n\n\t\tconst db = request.db !== undefined ? request.db : await this.getDatabase();\n\n\t\tconst requestId = `test-${Date.now()}`;\n\t\tconst startTime = Date.now();\n\n\t\tconst operation = `queue ${this.queue.name}`;\n\t\treturn runWithRequestContext(\n\t\t\t{ logger, requestId, startTime, operation },\n\t\t\t() =>\n\t\t\t\tthis.queue.handler({\n\t\t\t\t\tmessages: request.messages,\n\t\t\t\t\tservices,\n\t\t\t\t\tlogger,\n\t\t\t\t\tdb,\n\t\t\t\t} as unknown as QueueContext<TMessage, TServices, TLogger, TDatabase>),\n\t\t);\n\t}\n\n\tprivate async getDatabase(): Promise<TDatabase | undefined> {\n\t\tconst service = this.queue.databaseService;\n\t\tif (!service) return undefined;\n\n\t\tconst registered = await this.serviceDiscovery.register([service]);\n\n\t\treturn registered[service.serviceName] as TDatabase | undefined;\n\t}\n}\n\nexport type TestQueueRequest<\n\tTMessage extends StandardSchemaV1 = StandardSchemaV1,\n\tTServices extends Service[] = [],\n\tTDatabase = undefined,\n> = {\n\tmessages: InferStandardSchema<TMessage>[];\n\tservices?: ServiceRecord<TServices>;\n\t/** Stands in for the queue's database — a transaction, say. */\n\tdb?: TDatabase;\n};\n","import { EnvironmentParser } from '@geekmidas/envkit';\nimport type {\n\tEventPublisher,\n\tExtractPublisherMessage,\n} from '@geekmidas/events';\nimport type { Logger } from '@geekmidas/logger';\nimport type { InferStandardSchema } from '@geekmidas/schema';\nimport type { Service, ServiceRecord } from '@geekmidas/services';\nimport { runWithRequestContext, ServiceDiscovery } from '@geekmidas/services';\nimport type { StandardSchemaV1 } from '@standard-schema/spec';\nimport type { Subscriber } from './Subscriber';\n\n// Helper type to extract payload types for subscribed events\ntype ExtractEventPayloads<\n\tTPublisher extends EventPublisher<any> | undefined,\n\tTEventTypes extends any[],\n> = TPublisher extends EventPublisher<any>\n\t? Extract<ExtractPublisherMessage<TPublisher>, { type: TEventTypes[number] }>\n\t: never;\n\nexport class TestSubscriberAdaptor<\n\tTServices extends Service[] = [],\n\tTLogger extends Logger = Logger,\n\tOutSchema extends StandardSchemaV1 | undefined = undefined,\n\tTEventPublisher extends EventPublisher<any> | undefined = undefined,\n\tTSubscribedEvents extends\n\t\tExtractPublisherMessage<TEventPublisher>['type'][] = ExtractPublisherMessage<TEventPublisher>['type'][],\n\tTDatabase = undefined,\n\tTDatabaseServiceName extends string = string,\n> {\n\tstatic getDefaultServiceDiscovery() {\n\t\treturn ServiceDiscovery.getInstance(new EnvironmentParser({}));\n\t}\n\n\tconstructor(\n\t\tprivate readonly subscriber: Subscriber<\n\t\t\tTServices,\n\t\t\tTLogger,\n\t\t\tOutSchema,\n\t\t\tTEventPublisher,\n\t\t\tTSubscribedEvents,\n\t\t\tTDatabase,\n\t\t\tTDatabaseServiceName\n\t\t>,\n\t\tprivate serviceDiscovery: ServiceDiscovery<any> = TestSubscriberAdaptor.getDefaultServiceDiscovery(),\n\t) {}\n\n\tasync invoke(\n\t\trequest: TestSubscriberRequest<\n\t\t\tTEventPublisher,\n\t\t\tTSubscribedEvents,\n\t\t\tTServices,\n\t\t\tTDatabase\n\t\t>,\n\t): Promise<InferStandardSchema<OutSchema>> {\n\t\t// Create logger with test context\n\t\tconst logger = this.subscriber.logger.child({\n\t\t\ttest: true,\n\t\t}) as TLogger;\n\n\t\t// Resolve services (use provided or auto-register)\n\t\tlet services: ServiceRecord<TServices>;\n\t\tif (request.services) {\n\t\t\tservices = request.services;\n\t\t} else {\n\t\t\tservices = await this.serviceDiscovery.register(this.subscriber.services);\n\t\t}\n\n\t\t// The request's db stands in for the subscriber's — a transaction, say.\n\t\tconst db = request.db !== undefined ? request.db : await this.getDatabase();\n\n\t\t// Filter events to only subscribed types\n\t\tconst filteredEvents = this.filterEvents(request.events);\n\n\t\t// Return early if no events after filtering (mirrors AWSLambdaSubscriber)\n\t\tif (filteredEvents.length === 0) {\n\t\t\treturn { batchItemFailures: [] } as any;\n\t\t}\n\n\t\t// Wrap execution in request context for service access via context.getLogger()\n\t\tconst requestId = `test-${Date.now()}`;\n\t\tconst startTime = Date.now();\n\n\t\tconst operation = `subscriber ${this.subscriber.topicName ?? 'test'}`;\n\t\treturn runWithRequestContext(\n\t\t\t{ logger, requestId, startTime, operation },\n\t\t\tasync () => {\n\t\t\t\t// Execute the subscriber handler\n\t\t\t\tconst result = await this.subscriber.handler({\n\t\t\t\t\tevents: filteredEvents,\n\t\t\t\t\tservices,\n\t\t\t\t\tlogger,\n\t\t\t\t\tdb,\n\t\t\t\t} as unknown as Parameters<typeof this.subscriber.handler>[0]);\n\n\t\t\t\t// Validate output if schema is provided\n\t\t\t\tlet output: any = result;\n\t\t\t\tif (this.subscriber.outputSchema && result) {\n\t\t\t\t\tconst validationResult =\n\t\t\t\t\t\tawait this.subscriber.outputSchema['~standard'].validate(result);\n\n\t\t\t\t\tif (validationResult.issues) {\n\t\t\t\t\t\tthrow new Error('Subscriber output validation failed');\n\t\t\t\t\t}\n\n\t\t\t\t\toutput = validationResult.value;\n\t\t\t\t}\n\n\t\t\t\treturn output;\n\t\t\t},\n\t\t) as Promise<InferStandardSchema<OutSchema>>;\n\t}\n\n\tprivate async getDatabase(): Promise<TDatabase | undefined> {\n\t\tconst service = this.subscriber.databaseService;\n\t\tif (!service) return undefined;\n\n\t\tconst registered = await this.serviceDiscovery.register([service]);\n\n\t\treturn registered[service.serviceName] as TDatabase | undefined;\n\t}\n\n\tprivate filterEvents(\n\t\tevents: ExtractEventPayloads<TEventPublisher, TSubscribedEvents>[],\n\t): ExtractEventPayloads<TEventPublisher, TSubscribedEvents>[] {\n\t\tif (!this.subscriber.subscribedEvents) {\n\t\t\treturn events;\n\t\t}\n\n\t\treturn events.filter((event: any) =>\n\t\t\tthis.subscriber.subscribedEvents!.includes(event.type),\n\t\t);\n\t}\n}\n\nexport type TestSubscriberRequest<\n\tTEventPublisher extends EventPublisher<any> | undefined = undefined,\n\tTSubscribedEvents extends any[] = [],\n\tTServices extends Service[] = [],\n\tTDatabase = undefined,\n> = {\n\tevents: ExtractEventPayloads<TEventPublisher, TSubscribedEvents>[];\n\tservices?: ServiceRecord<TServices>;\n\t/** Stands in for the subscriber's database — a transaction, say. */\n\tdb?: TDatabase;\n};\n","/**\n * The test manifest: what `gkm test` knows about an app, written down for the\n * suite it starts.\n *\n * `gkm test` discovers the constructs, reconciles the test stage and resolves\n * its environment — then, until this existed, threw all of it away and left a\n * test to declare it again by hand. The manifest keeps it: which construct and\n * endpoint is exported where, and the environment the test stage resolved,\n * under the keys the constructs themselves derive. A feature test is built from\n * it, so nothing a test says can drift from what the app declares.\n */\n\nimport { existsSync, readFileSync } from 'node:fs';\nimport tls from 'node:tls';\nimport { fileURLToPath } from 'node:url';\nimport type { TestStage } from '../stages';\n\n/** Where an export lives: what an import statement has to say. */\nexport interface TestManifestSource {\n\t/** Absolute path to the module. */\n\tfile: string;\n\t/** The name it is exported as. */\n\texport: string;\n}\n\nexport interface TestManifest {\n\t/** The stage the environment was resolved for — `test`. */\n\tstage: TestStage;\n\t/** Every construct the app declares, by id. */\n\tconstructs: Record<string, { kind: string; source: TestManifestSource }>;\n\t/** Every endpoint, and the surface that serves it. */\n\tendpoints: { surface: string; source: TestManifestSource }[];\n\t/**\n\t * Every topic subscriber — what a topic's events are delivered to. Not a\n\t * construct, so not in `constructs`: the build finds them, as it finds\n\t * endpoints.\n\t */\n\tsubscribers?: { source: TestManifestSource }[];\n\t/**\n\t * The test stage's environment — reconcile's output, keyed as the\n\t * constructs derive their keys.\n\t */\n\tenv: Record<string, string>;\n}\n\n/** The environment variable `gkm test` names the manifest in. */\nexport const TEST_MANIFEST_ENV = 'GKM_TEST_MANIFEST';\n\n/**\n * Read a test manifest: from a path, a `file:` URL, or — given nothing — the\n * one `gkm test` named in `GKM_TEST_MANIFEST`.\n */\nexport function loadTestManifest(from?: string | URL): TestManifest {\n\tconst location = from ?? process.env[TEST_MANIFEST_ENV];\n\tif (!location) throw new NoTestManifest();\n\n\ttrustLocalEdge();\n\n\tconst path =\n\t\tlocation instanceof URL || location.startsWith('file:')\n\t\t\t? fileURLToPath(location)\n\t\t\t: location;\n\n\treturn JSON.parse(readFileSync(path, 'utf-8')) as TestManifest;\n}\n\nlet trusted = false;\n\n/**\n * Trust the local edge's certificate authority in this thread.\n *\n * `NODE_EXTRA_CA_CERTS` does it for a process started with it — which a\n * suite started by `gkm test` is, and one started by plain `vitest` or an\n * editor is not: its setup only learns the path once Vitest is running, and a\n * worker *thread* shares that process and keeps a TLS store of its own. Every\n * feature test loads the manifest, so this is the one place each worker passes\n * through.\n */\nfunction trustLocalEdge(): void {\n\tconst certificate = process.env.NODE_EXTRA_CA_CERTS;\n\tif (trusted || !certificate || !existsSync(certificate)) return;\n\ttrusted = true;\n\n\ttls.setDefaultCACertificates([\n\t\t...tls.getCACertificates('default'),\n\t\treadFileSync(certificate, 'utf-8'),\n\t]);\n}\n\n/** A feature test ran without a manifest to build itself from. */\nexport class NoTestManifest extends Error {\n\tconstructor() {\n\t\tsuper(\n\t\t\t`No test manifest: run the suite with \\`gkm test\\`, or add ` +\n\t\t\t\t`\\`globalSetup: ['@geekmidas/cli/vitest']\\` to the root vitest config — ` +\n\t\t\t\t`either writes one and names it in ${TEST_MANIFEST_ENV}.`,\n\t\t);\n\t\tthis.name = 'NoTestManifest';\n\t}\n}\n","/**\n * `featureTest`: an app, driven the way it runs deployed.\n *\n * A browser signs in and calls the API; the API calls the auth server; each\n * over its URL, each database in its own transaction. Nothing runs as a server:\n * every URL an app's constructs answer on is served in-process through MSW,\n * from the real handler, for the test that made the request. Everything else\n * with a real local equivalent — Postgres, Mailpit, MinIO — is used directly.\n *\n * It is built from the test manifest `gkm test` writes — the constructs and\n * endpoints the app exports, and the environment the test stage resolved — so\n * a test declares none of it. `gkm test` also generates the configured `it`\n * and a `Browser` with a typed client per surface:\n *\n * ```ts\n * import { it } from '#test';\n *\n * it('shows the signed-in user their profile', async ({ browser, mailbox }) => {\n * await browser.auth.signIn.magicLink({ email: 'ada@shop.test' });\n * await browser.visit((await mailbox('ada@shop.test').last()).link!);\n * expect(await browser.api.get('/profile')).toMatchObject({ email: 'ada@shop.test' });\n * });\n * ```\n */\n\nimport { randomUUID } from 'node:crypto';\nimport { EnvironmentParser } from '@geekmidas/envkit';\nimport { provideKey } from '@geekmidas/manifest';\nimport { ServiceDiscovery, serviceContext } from '@geekmidas/services';\nimport { Browser as TestBrowser } from '@geekmidas/testkit/browser';\nimport {\n\tcurrentTestContext,\n\tinstallContextFetch,\n\trunAsServer,\n\trunInTestContext,\n\ttestContextOf,\n} from '@geekmidas/testkit/context';\nimport { type FakerFactory, faker } from '@geekmidas/testkit/faker';\nimport { createMailbox, type Mailbox } from '@geekmidas/testkit/mailbox';\nimport { TransactionRegistry } from '@geekmidas/testkit/transactions';\nimport type { StandardSchemaV1 } from '@standard-schema/spec';\nimport { Hono } from 'hono';\nimport type { Kysely } from 'kysely';\nimport { http } from 'msw';\nimport { type SetupServer, setupServer } from 'msw/node';\nimport { afterAll, beforeAll, test } from 'vitest';\nimport { BetterAuth } from '../auth';\nimport { type Consumable, isConsumable } from '../construct-interface';\nimport { KyselyDatabase } from '../database/kysely';\nimport { Email } from '../email';\nimport { Endpoint } from '../endpoints/Endpoint';\nimport { HonoEndpoint } from '../endpoints/HonoEndpointAdaptor';\nimport type { Fake } from '../external-api';\nimport { Queue } from '../queue/Queue';\nimport { TestQueueAdaptor } from '../queue/TestQueueAdaptor';\nimport type { Subscriber } from '../subscribers/Subscriber';\nimport { TestSubscriberAdaptor } from '../subscribers/TestSubscriberAdaptor';\nimport { Topic } from '../topic/Topic';\nimport { loadTestManifest, type TestManifest } from './manifest';\nimport { inProcessBindings } from './peer';\n\n/** How each database's test factory is built, keyed by its service name. */\nexport type FactoryBuilders = Record<string, (db: Kysely<any>) => unknown>;\n\nexport interface FeatureTestOptions<\n\tTBrowser extends TestBrowser,\n\tTFactories extends FactoryBuilders = {},\n> {\n\t/**\n\t * What the app declares and the environment its test stage resolved.\n\t * Defaults to the manifest `gkm test` names in `GKM_TEST_MANIFEST`.\n\t */\n\tmanifest?: TestManifest;\n\t/**\n\t * The app's modules, already imported, by the absolute path the manifest\n\t * records for them. The generated harness imports them statically, from\n\t * inside the app, so they resolve the way the app's own code does — its\n\t * tsconfig paths included. A module not here is imported by path.\n\t */\n\tmodules?: Readonly<Record<string, Record<string, unknown>>>;\n\t/** The browser each test gets — the generated one, with the app's clients. */\n\tbrowser?: new () => TBrowser;\n\t/**\n\t * Each database's test factory — `createFactory` from\n\t * `test/factories/<construct>.ts`, which the generated harness imports —\n\t * keyed by the database's service name. Each is called once per test with\n\t * that database's transaction, so what a test inserts through it is rolled\n\t * back with everything else, and seen by the endpoints it calls.\n\t */\n\tfactories?: TFactories;\n\t/**\n\t * Each external API's fake — the default export of `test/fakes/<id>.ts`,\n\t * which the generated harness imports — keyed by the API's construct id.\n\t * An app fake is served at the URL the test stage resolved for it.\n\t */\n\tfakes?: Readonly<Record<string, Fake>>;\n}\n\n/** Each database's schema, keyed by its service name. */\nexport type DatabaseSchemas = Record<string, unknown>;\n\n/** Each construct's client, keyed by its service name — what `services` types. */\nexport type ServiceClients = Record<string, unknown>;\n\n/** The client a construct's service registers — what a handler is handed. */\nexport type ClientOf<C> = C extends {\n\tservice: { register: (...args: any[]) => infer TClient };\n}\n\t? Awaited<TClient>\n\t: never;\n\n/**\n * The app's services for this test, by service name — `services.get('shipping')`.\n *\n * What a handler that depends on the construct is handed, resolved the way the\n * test's endpoints resolve it: an external API's client aimed at whatever the\n * test stage resolved (its fake, which the test never sees), a topic or queue's\n * recorder, a database's transaction for this test.\n */\nexport interface TestServices<TServices extends ServiceClients> {\n\tget<K extends keyof TServices & string>(name: K): Promise<TServices[K]>;\n}\n\n/**\n * The app's databases for this test, by service name — `db.get('database')`.\n *\n * Each is this test's transaction on that database: opened by whatever reaches\n * it first — the test, a factory, an endpoint — and the same one for all of\n * them, rolled back after the test.\n */\nexport interface TestDatabases<TDatabases extends DatabaseSchemas> {\n\tget<K extends keyof TDatabases & string>(\n\t\tname: K,\n\t): Promise<Kysely<TDatabases[K]>>;\n}\n\n/**\n * Each of the app's databases' test factory, by service name —\n * `await factories.get('database')`. Built on first use, on that database's\n * transaction for this test — the one `db.get` returns — and the same factory\n * for the rest of the test.\n */\nexport interface TestFactories<TFactories extends FactoryBuilders> {\n\tget<K extends keyof TFactories & string>(\n\t\tname: K,\n\t): Promise<ReturnType<TFactories[K]>>;\n}\n\nexport interface FeatureContext<\n\tTBrowser extends TestBrowser,\n\tTDatabases extends DatabaseSchemas = {},\n\tTFactories extends FactoryBuilders = {},\n\tTServices extends ServiceClients = {},\n> {\n\t/** This test's browser, already the global `fetch`. */\n\tbrowser: TBrowser;\n\t/**\n\t * The app's own databases — not a tenant an auth server owns, not a\n\t * reader — by service name: `await db.get('database')`. The same\n\t * transaction the test's endpoints and factories use.\n\t */\n\tdb: TestDatabases<TDatabases>;\n\t/**\n\t * Each of the app's databases' test factory, by service name —\n\t * `await factories.get('database')` — on the same transaction `db.get`\n\t * returns.\n\t */\n\tfactories: TestFactories<TFactories>;\n\t/**\n\t * Testkit's faker — the one factories are handed — seeded from this test's\n\t * name, so a failing test fails again with the same data, and so a test\n\t * imports nothing to make some.\n\t */\n\tfaker: FakerFactory;\n\t/** The mail sent to an address during this test, read from Mailpit. */\n\tmailbox: (address: string) => Mailbox;\n\t/**\n\t * What this test published to a topic or enqueued on a queue, in order.\n\t *\n\t * Also delivered: once each request the test makes has answered, a queue's\n\t * messages reach its consumer and a topic's events every subscriber that\n\t * named them, in this test's transaction — see {@link deliver}.\n\t */\n\tpublished: (channel: { id: string }) => PublishedMessage[];\n\t/**\n\t * A subscriber, run on its own — handed events rather than delivered them —\n\t * with this test's services: its databases resolve to this test's\n\t * transactions, as an endpoint's do.\n\t */\n\tsubscriber: <S extends Subscriber<any, any, any, any, any, any, any>>(\n\t\tsubscriber: S,\n\t) => SubscriberAdaptorOf<S>;\n\t/**\n\t * The app's services, by service name — `await services.get('shipping')` —\n\t * as a handler is handed them. Assert on an external API through its own\n\t * client: the fake behind it stays hidden, and the same assertion holds\n\t * against the real API.\n\t */\n\tservices: TestServices<TServices>;\n\t/** A queue's worker, run on its own with this test's services. */\n\tqueue: <Q extends Queue<any, any, any, any, any, any>>(\n\t\tqueue: Q,\n\t) => QueueAdaptorOf<Q>;\n}\n\ntype SubscriberAdaptorOf<S> =\n\tS extends Subscriber<\n\t\tinfer TServices,\n\t\tinfer TLogger,\n\t\tinfer OutSchema,\n\t\tinfer TEventPublisher,\n\t\tinfer TSubscribedEvents,\n\t\tinfer TDatabase,\n\t\tinfer TDatabaseServiceName\n\t>\n\t\t? TestSubscriberAdaptor<\n\t\t\t\tTServices,\n\t\t\t\tTLogger,\n\t\t\t\tOutSchema,\n\t\t\t\tTEventPublisher,\n\t\t\t\tTSubscribedEvents,\n\t\t\t\tTDatabase,\n\t\t\t\tTDatabaseServiceName\n\t\t\t>\n\t\t: never;\n\ntype QueueAdaptorOf<Q> =\n\tQ extends Queue<\n\t\tinfer TName,\n\t\tinfer TMessage,\n\t\tinfer TServices,\n\t\tinfer TLogger,\n\t\tinfer TDatabase,\n\t\tinfer TDatabaseServiceName\n\t>\n\t\t? TestQueueAdaptor<\n\t\t\t\tTName,\n\t\t\t\tTMessage,\n\t\t\t\tTServices,\n\t\t\t\tTLogger,\n\t\t\t\tTDatabase,\n\t\t\t\tTDatabaseServiceName\n\t\t\t>\n\t\t: never;\n\n/** The schema a database construct was declared with — what `db` is typed by. */\nexport type DatabaseOf<C> =\n\tC extends KyselyDatabase<infer DB, any> ? DB : unknown;\n\n/** One message as it was published: its type and its payload. */\nexport interface PublishedMessage {\n\ttype: string;\n\tpayload: unknown;\n}\n\ntype FeatureFn<\n\tTBrowser extends TestBrowser,\n\tTDatabases extends DatabaseSchemas,\n\tTFactories extends FactoryBuilders,\n\tTServices extends ServiceClients,\n> = (\n\tcontext: FeatureContext<TBrowser, TDatabases, TFactories, TServices>,\n) => unknown;\n\nexport interface FeatureIt<\n\tTBrowser extends TestBrowser,\n\tTDatabases extends DatabaseSchemas = {},\n\tTFactories extends FactoryBuilders = {},\n\tTServices extends ServiceClients = {},\n> {\n\t(\n\t\tname: string,\n\t\tfn: FeatureFn<TBrowser, TDatabases, TFactories, TServices>,\n\t\ttimeout?: number,\n\t): void;\n\tonly(\n\t\tname: string,\n\t\tfn: FeatureFn<TBrowser, TDatabases, TFactories, TServices>,\n\t\ttimeout?: number,\n\t): void;\n\tskip(\n\t\tname: string,\n\t\tfn: FeatureFn<TBrowser, TDatabases, TFactories, TServices>,\n\t\ttimeout?: number,\n\t): void;\n}\n\n/** Everything one test owns, found again from its id. */\ninterface ContextState {\n\ttransactions: TransactionRegistry;\n\tdiscovery: ServiceDiscovery<any>;\n\t/** One app per surface, with this test's services. */\n\tsurfaces: Map<string, Promise<Hono>>;\n\t/** One auth server per construct, on this test's transaction. */\n\tauth: Map<BetterAuth, Promise<Hono>>;\n\t/** The addresses this test read mail for, cleared after it. */\n\taddresses: Set<string>;\n\t/** This test's inbox, when the app sends mail — what `browser.signIn` reads. */\n\tmailbox?: (address: string) => Mailbox;\n\t/** What this test published, by topic or queue id. */\n\tpublished: Map<string, PublishedMessage[]>;\n\t/** What was published and is still to be delivered, in order. */\n\tpending: {\n\t\tchannel: Topic<any, any> | Queue<any, any>;\n\t\tmessages: PublishedMessage[];\n\t}[];\n\t/** Set while delivering, so a consumer's own requests do not deliver again. */\n\tdelivering: boolean;\n}\n\n/** Every test in flight in this process, by id. */\nconst contexts = new Map<string, ContextState>();\n\n/** Databases already resolving to test transactions — patched once each. */\nconst bound = new WeakSet<KyselyDatabase>();\n\n/** What the manifest points at, imported: the app's own instances. */\ninterface LoadedApp {\n\tenvParser: EnvironmentParser<{}>;\n\tendpoints: Endpoint<any, any, any, any>[];\n\tdatabases: KyselyDatabase[];\n\tauths: BetterAuth[];\n\temails: Email[];\n\t/** Every topic and queue — what a test's publishing is recorded for. */\n\tchannels: (Topic<any, any> | Queue<any, any>)[];\n\t/** Every construct a handler can depend on — what `services` resolves. */\n\tconsumables: Consumable[];\n\t/** Every topic subscriber, by the name it is exported as. */\n\tsubscribers: {\n\t\tname: string;\n\t\tsubscriber: Subscriber<any, any, any, any, any>;\n\t}[];\n\treadMail?: (address: string) => Mailbox;\n}\n\nexport function featureTest<\n\tTBrowser extends TestBrowser = TestBrowser,\n\tTDatabases extends DatabaseSchemas = {},\n\tTFactories extends FactoryBuilders = {},\n\tTServices extends ServiceClients = {},\n>(\n\toptions: FeatureTestOptions<TBrowser, TFactories> = {},\n): FeatureIt<TBrowser, TDatabases, TFactories, TServices> {\n\tconst manifest = options.manifest ?? loadTestManifest();\n\tconst BrowserClass = (options.browser ?? TestBrowser) as new () => TBrowser;\n\n\tlet app: LoadedApp;\n\tlet factoryDatabases: [string, KyselyDatabase][] = [];\n\tlet owned: KyselyDatabase[] = [];\n\tlet network: SetupServer;\n\tlet restoreFetch: () => void = () => {};\n\n\tbeforeAll(async () => {\n\t\tapp = await load(manifest, options.modules ?? {});\n\t\towned = ownDatabases(app, manifest);\n\t\tfactoryDatabases = databasesFor(options.factories ?? {}, owned);\n\t\tfor (const database of app.databases) bindToTests(database);\n\n\t\tnetwork = setupServer(\n\t\t\t...surfaceHandlers(app.endpoints, manifest.env),\n\t\t\t...app.auths.map((auth) =>\n\t\t\t\tauthHandler(auth, manifest.env, app.envParser),\n\t\t\t),\n\t\t\t...Object.entries(options.fakes ?? {}).flatMap(([id, fake]) =>\n\t\t\t\tfakeHandler(id, fake, manifest.env),\n\t\t\t),\n\t\t);\n\t\tnetwork.listen({\n\t\t\tonUnhandledRequest(request, print) {\n\t\t\t\t// A real local service — Mailpit, MinIO — is used directly; only a\n\t\t\t\t// URL with nothing real behind it has to be answered here.\n\t\t\t\tif (isLocal(new URL(request.url))) return;\n\t\t\t\tprint.error();\n\t\t\t},\n\t\t});\n\t\t// After MSW's interceptor, so the stamp is on before a request is caught.\n\t\tconst restoreStamp = installContextFetch();\n\t\t// Outermost: once a request the test made has answered, what it\n\t\t// published is delivered before the test sees the response.\n\t\tconst stamped = globalThis.fetch;\n\t\tglobalThis.fetch = deliveringFetch(stamped, (id) => {\n\t\t\tconst state = contexts.get(id);\n\t\t\treturn state ? deliver(app, state, id) : Promise.resolve();\n\t\t});\n\t\trestoreFetch = () => {\n\t\t\tglobalThis.fetch = stamped;\n\t\t\trestoreStamp();\n\t\t};\n\t});\n\tafterAll(() => {\n\t\trestoreFetch();\n\t\tnetwork?.close();\n\t});\n\n\tconst run =\n\t\t(\n\t\t\tname: string,\n\t\t\tfn: FeatureFn<TBrowser, TDatabases, TFactories, TServices>,\n\t\t) =>\n\t\tasync (): Promise<void> => {\n\t\t\tconst id = randomUUID();\n\t\t\tfaker.seed(seedOf(name));\n\t\t\tconst state: ContextState = {\n\t\t\t\ttransactions: new TransactionRegistry(),\n\t\t\t\tdiscovery: new ServiceDiscovery(app.envParser),\n\t\t\t\tsurfaces: new Map(),\n\t\t\t\tauth: new Map(),\n\t\t\t\taddresses: new Set(),\n\t\t\t\tpublished: new Map(),\n\t\t\t\tpending: [],\n\t\t\t\tdelivering: false,\n\t\t\t};\n\t\t\tconst readMail = app.readMail;\n\t\t\tif (readMail) {\n\t\t\t\tstate.mailbox = (address) => {\n\t\t\t\t\tstate.addresses.add(address);\n\t\t\t\t\treturn readMail(address);\n\t\t\t\t};\n\t\t\t}\n\t\t\tcontexts.set(id, state);\n\t\t\t// Before anything resolves them: a publisher is a service, so the one this\n\t\t\t// test's endpoints get is whichever is registered under its name first.\n\t\t\tawait state.discovery.register(recorders(app.channels, state));\n\n\t\t\ttry {\n\t\t\t\tawait runInTestContext(id, async () => {\n\t\t\t\t\tconst browser = new BrowserClass();\n\t\t\t\t\tconst restore = browser.install();\n\t\t\t\t\ttry {\n\t\t\t\t\t\t// A database's transaction for this test, opened on first use —\n\t\t\t\t\t\t// the registry hands everyone in the test the same one.\n\t\t\t\t\t\tconst transaction = (database: KyselyDatabase) =>\n\t\t\t\t\t\t\tstate.transactions.get(\n\t\t\t\t\t\t\t\tdatabase.id,\n\t\t\t\t\t\t\t\turlOf(database, app.envParser),\n\t\t\t\t\t\t\t\tdatabase.clientConfig,\n\t\t\t\t\t\t\t) as Promise<Kysely<any>>;\n\t\t\t\t\t\tconst db: TestDatabases<any> = {\n\t\t\t\t\t\t\tget: (name) => {\n\t\t\t\t\t\t\t\tconst database = owned.find(\n\t\t\t\t\t\t\t\t\t(candidate) => candidate.service.serviceName === name,\n\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t\tif (!database) {\n\t\t\t\t\t\t\t\t\tthrow new UnknownDatabase(\n\t\t\t\t\t\t\t\t\t\tname,\n\t\t\t\t\t\t\t\t\t\towned.map((candidate) => candidate.service.serviceName),\n\t\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\treturn transaction(database);\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t};\n\t\t\t\t\t\tconst built = new Map<string, Promise<unknown>>();\n\t\t\t\t\t\tconst factories: TestFactories<any> = {\n\t\t\t\t\t\t\tget: (name) => {\n\t\t\t\t\t\t\t\tconst database = factoryDatabases.find(\n\t\t\t\t\t\t\t\t\t([candidate]) => candidate === name,\n\t\t\t\t\t\t\t\t)?.[1];\n\t\t\t\t\t\t\t\tif (!database) {\n\t\t\t\t\t\t\t\t\tthrow new UnknownFactory(\n\t\t\t\t\t\t\t\t\t\tname,\n\t\t\t\t\t\t\t\t\t\tfactoryDatabases.map(([candidate]) => candidate),\n\t\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\tlet factory = built.get(name);\n\t\t\t\t\t\t\t\tif (!factory) {\n\t\t\t\t\t\t\t\t\tfactory = transaction(database).then(\n\t\t\t\t\t\t\t\t\t\toptions.factories![name]!,\n\t\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t\t\tbuilt.set(name, factory);\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\treturn factory as Promise<any>;\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t};\n\t\t\t\t\t\tawait fn({\n\t\t\t\t\t\t\tbrowser,\n\t\t\t\t\t\t\tdb: db as TestDatabases<TDatabases>,\n\t\t\t\t\t\t\tfactories: factories as TestFactories<TFactories>,\n\t\t\t\t\t\t\tfaker,\n\t\t\t\t\t\t\tmailbox: (address) => {\n\t\t\t\t\t\t\t\tif (!state.mailbox) throw new NoInbox();\n\t\t\t\t\t\t\t\treturn state.mailbox(address);\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\tpublished: (channel) => [\n\t\t\t\t\t\t\t\t...(state.published.get(channel.id) ?? []),\n\t\t\t\t\t\t\t],\n\t\t\t\t\t\t\tservices: {\n\t\t\t\t\t\t\t\tget: (name) => resolveService(app, state, name) as never,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t// A consumer run by hand delivers what it published, as a\n\t\t\t\t\t\t\t// request does.\n\t\t\t\t\t\t\tsubscriber: (subscriber) =>\n\t\t\t\t\t\t\t\tthenDeliver(\n\t\t\t\t\t\t\t\t\tnew TestSubscriberAdaptor(subscriber, state.discovery),\n\t\t\t\t\t\t\t\t\t() => deliver(app, state, id),\n\t\t\t\t\t\t\t\t) as SubscriberAdaptorOf<typeof subscriber>,\n\t\t\t\t\t\t\tqueue: (queue) =>\n\t\t\t\t\t\t\t\tthenDeliver(new TestQueueAdaptor(queue, state.discovery), () =>\n\t\t\t\t\t\t\t\t\tdeliver(app, state, id),\n\t\t\t\t\t\t\t\t) as QueueAdaptorOf<typeof queue>,\n\t\t\t\t\t\t} as FeatureContext<TBrowser, TDatabases, TFactories, TServices>);\n\t\t\t\t\t} finally {\n\t\t\t\t\t\trestore();\n\t\t\t\t\t}\n\t\t\t\t});\n\t\t\t} finally {\n\t\t\t\tcontexts.delete(id);\n\t\t\t\tawait Promise.all([\n\t\t\t\t\tstate.transactions.rollbackAll(),\n\t\t\t\t\t...[...state.addresses].map((address) =>\n\t\t\t\t\t\tapp.readMail?.(address).clear(),\n\t\t\t\t\t),\n\t\t\t\t]);\n\t\t\t}\n\t\t};\n\n\tconst it = ((name, fn, timeout) =>\n\t\ttest(name, run(name, fn), timeout)) as FeatureIt<\n\t\tTBrowser,\n\t\tTDatabases,\n\t\tTFactories,\n\t\tTServices\n\t>;\n\tit.only = (name, fn, timeout) => test.only(name, run(name, fn), timeout);\n\tit.skip = (name, fn, timeout) => test.skip(name, run(name, fn), timeout);\n\treturn it;\n}\n\n/**\n * A test's faker seed, from its name: the same test draws the same data on\n * every run, and two tests draw different data.\n */\nfunction seedOf(name: string): number {\n\tlet hash = 0;\n\tfor (const char of name) {\n\t\thash = (Math.imul(hash, 31) + char.charCodeAt(0)) | 0;\n\t}\n\treturn hash >>> 0;\n}\n\n/**\n * Import what the manifest points at.\n *\n * The same modules the app runs, so a construct here *is* the app's construct —\n * the one its endpoints were built from — never a copy declared again.\n */\nasync function load(\n\tmanifest: TestManifest,\n\tmodules: Readonly<Record<string, Record<string, unknown>>>,\n): Promise<LoadedApp> {\n\tconst envParser = new EnvironmentParser({ ...manifest.env });\n\tconst imported = async ({\n\t\tfile,\n\t\texport: name,\n\t}: {\n\t\tfile: string;\n\t\texport: string;\n\t}) =>\n\t\t// Imported by path only as a fallback: from inside `node_modules`, a\n\t\t// dynamic import is left to Node, which knows nothing of the app's\n\t\t// tsconfig paths — `~/router.ts` resolves in the app and not here.\n\t\t(modules[file] ?? ((await import(file)) as Record<string, unknown>))[name];\n\n\tconst constructs = await Promise.all(\n\t\tObject.values(manifest.constructs).map(({ source }) => imported(source)),\n\t);\n\tconst endpoints = (\n\t\tawait Promise.all(manifest.endpoints.map(({ source }) => imported(source)))\n\t).filter((value): value is Endpoint<any, any, any, any> =>\n\t\tEndpoint.isEndpoint(value),\n\t);\n\tconst subscribers = (\n\t\tawait Promise.all(\n\t\t\t(manifest.subscribers ?? []).map(async ({ source }) => ({\n\t\t\t\tname: source.export,\n\t\t\t\tsubscriber: await imported(source),\n\t\t\t})),\n\t\t)\n\t).filter(\n\t\t(\n\t\t\tentry,\n\t\t): entry is {\n\t\t\tname: string;\n\t\t\tsubscriber: Subscriber<any, any, any, any, any>;\n\t\t} =>\n\t\t\t(entry.subscriber as { __IS_SUBSCRIBER__?: unknown })\n\t\t\t\t?.__IS_SUBSCRIBER__ === true,\n\t);\n\n\tconst unique = <T>(values: T[]) => [...new Set(values)];\n\tconst databases = unique(\n\t\tconstructs.filter(\n\t\t\t(value): value is KyselyDatabase => value instanceof KyselyDatabase,\n\t\t),\n\t);\n\tconst auths = unique(\n\t\tconstructs.filter(\n\t\t\t(value): value is BetterAuth => value instanceof BetterAuth,\n\t\t),\n\t);\n\tconst emails = unique(\n\t\tconstructs.filter((value): value is Email => value instanceof Email),\n\t);\n\tconst consumables = unique(constructs.filter(isConsumable));\n\tconst channels = unique(\n\t\tconstructs.filter(\n\t\t\t(value): value is Topic<any, any> | Queue<any, any> =>\n\t\t\t\tvalue instanceof Topic || value instanceof Queue,\n\t\t),\n\t);\n\n\tconst inbox = emails\n\t\t.map((email) => manifest.env[provideKey(email.id, 'inboxUrl')])\n\t\t.find(Boolean);\n\n\treturn {\n\t\tenvParser,\n\t\tendpoints,\n\t\tdatabases,\n\t\tauths,\n\t\temails,\n\t\tchannels,\n\t\tconsumables,\n\t\tsubscribers,\n\t\t...(inbox ? { readMail: createMailbox({ inbox }) } : {}),\n\t};\n}\n\n/**\n * A publisher that records rather than sends, under the name a topic or queue\n * is injected by — `services.users` — which is also the one `.event(users, …)`\n * publishes through.\n */\nfunction recorders(\n\tchannels: LoadedApp['channels'],\n\tstate: ContextState,\n): { serviceName: string; register: () => unknown }[] {\n\treturn channels.map((channel) => {\n\t\tconst publisher = {\n\t\t\tasync publish(messages: PublishedMessage[]) {\n\t\t\t\tconst sent = messages.map(({ type, payload }) => ({ type, payload }));\n\t\t\t\tstate.published.set(channel.id, [\n\t\t\t\t\t...(state.published.get(channel.id) ?? []),\n\t\t\t\t\t...sent,\n\t\t\t\t]);\n\t\t\t\tstate.pending.push({ channel, messages: sent });\n\t\t\t},\n\t\t};\n\t\treturn {\n\t\t\tserviceName: channel.service.serviceName,\n\t\t\tregister: () => publisher,\n\t\t};\n\t});\n}\n\n/**\n * The databases a test is handed: the app's own. A schema tenant an auth server\n * owns is reached through that server, as the app reaches it, and a reader is\n * the same database through a read-only role — neither is another database to\n * test against.\n */\nfunction ownDatabases(\n\tapp: LoadedApp,\n\tmanifest: TestManifest,\n): KyselyDatabase[] {\n\tconst owners = new Set(app.auths.map((auth) => auth.databaseId));\n\treturn app.databases.filter(\n\t\t(database) =>\n\t\t\t!owners.has(database.id) &&\n\t\t\tmanifest.constructs[database.id]?.kind !== 'database-reader',\n\t);\n}\n\n/** Each factory's database, found by the service name it is keyed by. */\nfunction databasesFor(\n\tfactories: FactoryBuilders,\n\tdatabases: KyselyDatabase[],\n): [string, KyselyDatabase][] {\n\treturn Object.keys(factories).map((name) => {\n\t\tconst database = databases.find(\n\t\t\t(candidate) => candidate.service.serviceName === name,\n\t\t);\n\t\tif (!database) {\n\t\t\tthrow new UnknownFactory(\n\t\t\t\tname,\n\t\t\t\tdatabases.map((candidate) => candidate.service.serviceName),\n\t\t\t);\n\t\t}\n\t\treturn [name, database];\n\t});\n}\n\n/**\n * Make a database resolve, inside a test, to that test's transaction.\n *\n * Everything reaches a database through its service — an endpoint through\n * service discovery, the auth server through its tenant directly — so this is\n * the one place a test's connection can be handed over. Outside a test it is\n * the database it always was.\n */\n/** Rounds of delivery before a chain of consumers is called a loop. */\nconst MAX_DELIVERY_ROUNDS = 25;\n\n/**\n * Deliver what this test published, in-process, as the broker would — and\n * keep delivering what the consumers publish in turn, until nothing is left.\n *\n * - A queue's messages go to its one consumer, as a batch.\n * - A topic's events go to every subscriber that named their type, and only\n * those: fan-out, as the filter policy (SNS) or the per-subscriber queue\n * (pg-boss) does it.\n * - Each payload is checked against the consumer's schema first. Turning an\n * SNS envelope or an SQS record into `{ type, payload }` is each adaptor's\n * job and tested there; what is tested here is what the handler is handed.\n * - Consumers run as the server side of this test, so their databases are\n * this test's transactions and their writes roll back with it.\n * - A consumer that throws fails the test. Deployed, the message would be\n * retried; here a retry would only hide the bug.\n */\nasync function deliver(\n\tapp: LoadedApp,\n\tstate: ContextState,\n\tid: string,\n): Promise<void> {\n\tif (state.delivering) return;\n\tstate.delivering = true;\n\ttry {\n\t\tfor (let round = 0; state.pending.length > 0; round++) {\n\t\t\tif (round === MAX_DELIVERY_ROUNDS) {\n\t\t\t\tthrow new DeliveryDidNotSettle(MAX_DELIVERY_ROUNDS, [\n\t\t\t\t\t...new Set(state.pending.map(({ channel }) => channel.id)),\n\t\t\t\t]);\n\t\t\t}\n\t\t\tfor (const { channel, messages } of state.pending.splice(0)) {\n\t\t\t\tif (channel instanceof Queue) {\n\t\t\t\t\tawait toQueue(channel, messages, state, id);\n\t\t\t\t} else {\n\t\t\t\t\tawait toSubscribers(channel, messages, app, state, id);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t} finally {\n\t\tstate.delivering = false;\n\t}\n}\n\nasync function toQueue(\n\tqueue: Queue<any, any>,\n\tmessages: PublishedMessage[],\n\tstate: ContextState,\n\tid: string,\n): Promise<void> {\n\tconst payloads: unknown[] = [];\n\tfor (const message of messages) {\n\t\tpayloads.push(\n\t\t\tawait accepted(queue.messageSchema, message, `queue '${queue.name}'`),\n\t\t);\n\t}\n\n\tawait runAsServer(id, () =>\n\t\tnew TestQueueAdaptor(queue, state.discovery).invoke({ messages: payloads }),\n\t).catch((error: unknown) => {\n\t\tthrow new DeliveryFailed(`queue '${queue.name}'`, messages, error);\n\t});\n}\n\nasync function toSubscribers(\n\ttopic: Topic<any, any>,\n\tmessages: PublishedMessage[],\n\tapp: LoadedApp,\n\tstate: ContextState,\n\tid: string,\n): Promise<void> {\n\tfor (const { name, subscriber } of app.subscribers) {\n\t\tif (subscriber.topicName !== topic.name) continue;\n\n\t\tconst named = messages.filter(({ type }) =>\n\t\t\t(subscriber.subscribedEvents ?? []).includes(type),\n\t\t);\n\t\tif (named.length === 0) continue;\n\n\t\tconst consumer = `subscriber '${name}'`;\n\t\tconst events: PublishedMessage[] = [];\n\t\tfor (const message of named) {\n\t\t\tconst schema = (topic.eventSchemas as Record<string, unknown>)[\n\t\t\t\tmessage.type\n\t\t\t];\n\t\t\tevents.push({\n\t\t\t\ttype: message.type,\n\t\t\t\tpayload: await accepted(schema, message, consumer),\n\t\t\t});\n\t\t}\n\n\t\tawait runAsServer(id, () =>\n\t\t\tnew TestSubscriberAdaptor(subscriber, state.discovery).invoke({\n\t\t\t\tevents,\n\t\t\t} as never),\n\t\t).catch((error: unknown) => {\n\t\t\tthrow new DeliveryFailed(consumer, named, error);\n\t\t});\n\t}\n}\n\n/** The payload, if the consumer's schema takes it — what the handler is handed. */\nasync function accepted(\n\tschema: unknown,\n\tmessage: PublishedMessage,\n\tconsumer: string,\n): Promise<unknown> {\n\tconst standard = (schema as StandardSchemaV1 | undefined)?.['~standard'];\n\tif (!standard) return message.payload;\n\n\tconst result = await standard.validate(message.payload);\n\tif (result.issues) {\n\t\tthrow new MessageRejected(consumer, message, result.issues);\n\t}\n\treturn result.value;\n}\n\n/** `fetch`, delivering what the test published once each of its requests answers. */\nfunction deliveringFetch(\n\tinner: typeof fetch,\n\tsettle: (id: string) => Promise<void>,\n): typeof fetch {\n\treturn async (input, init) => {\n\t\tconst context = currentTestContext();\n\t\tconst response = await inner(input, init);\n\t\t// The test's own requests only: a handler's requests are part of the one\n\t\t// being served, and a consumer's are part of a delivery already running.\n\t\tif (context?.side === 'client') await settle(context.id);\n\t\treturn response;\n\t};\n}\n\n/** An adaptor whose `invoke` delivers what it published before returning. */\nfunction thenDeliver<\n\tT extends { invoke: (...args: any[]) => Promise<unknown> },\n>(adaptor: T, settle: () => Promise<void>): T {\n\tconst invoke = adaptor.invoke.bind(adaptor);\n\tadaptor.invoke = (async (...args: unknown[]) => {\n\t\tconst result = await invoke(...args);\n\t\tawait settle();\n\t\treturn result;\n\t}) as T['invoke'];\n\treturn adaptor;\n}\n\nfunction bindToTests(database: KyselyDatabase): void {\n\tif (bound.has(database)) return;\n\tbound.add(database);\n\n\tconst service = database.service as { register: (options: any) => unknown };\n\tconst register = service.register;\n\n\tservice.register = (options) => {\n\t\tconst context = currentTestContext();\n\t\tconst state = context && contexts.get(context.id);\n\t\tif (!state) return register(options);\n\n\t\treturn state.transactions.get(\n\t\t\tdatabase.id,\n\t\t\turlOf(database, options.envParser),\n\t\t\tdatabase.clientConfig,\n\t\t);\n\t};\n}\n\nfunction urlOf(database: { id: string }, envParser: EnvironmentParser<{}>) {\n\treturn envParser\n\t\t.create((get) => ({ url: get(provideKey(database.id, 'url')).string() }))\n\t\t.parse().url;\n}\n\n/** Each surface's endpoints, served at its URL for the test that asked. */\nfunction surfaceHandlers(\n\tendpoints: Endpoint<any, any, any, any>[],\n\tenv: Record<string, string | undefined>,\n) {\n\tconst bySurface = new Map<string, Endpoint<any, any, any, any>[]>();\n\tfor (const endpoint of endpoints) {\n\t\tconst surface = endpoint.surface?.id;\n\t\tif (!surface) continue;\n\t\tbySurface.set(surface, [...(bySurface.get(surface) ?? []), endpoint]);\n\t}\n\n\treturn [...bySurface].flatMap(([surface, served]) => {\n\t\tconst base = env[provideKey(surface, 'url')];\n\t\tif (!base) return [];\n\n\t\treturn http.all(`${trim(base)}/*`, ({ request }) =>\n\t\t\tserve(request, async (state) => {\n\t\t\t\tlet app = state.surfaces.get(surface);\n\t\t\t\tif (!app) {\n\t\t\t\t\tapp = Promise.resolve().then(() => {\n\t\t\t\t\t\tconst hono = new Hono();\n\t\t\t\t\t\tHonoEndpoint.addRoutes(served, state.discovery, hono);\n\t\t\t\t\t\treturn hono;\n\t\t\t\t\t});\n\t\t\t\t\tstate.surfaces.set(surface, app);\n\t\t\t\t}\n\t\t\t\t// From this process, so from a loopback peer: see `./peer`.\n\t\t\t\treturn (await app).fetch(request, inProcessBindings());\n\t\t\t}),\n\t\t);\n\t});\n}\n\n/**\n * An external API's app fake, answering at the URL the test stage resolved for\n * it — so a handler that calls Polar calls the fake, and the test sets up\n * nothing.\n *\n * Not per test, unlike a surface: a fake stands in for somebody else's server,\n * which no test's transaction reaches. An image fake has no handler here — its\n * container answers on localhost, which is let through.\n */\nfunction fakeHandler(\n\tid: string,\n\tfake: Fake,\n\tenv: Record<string, string | undefined>,\n) {\n\tconst base = env[provideKey(id, 'url')];\n\tif (fake.kind !== 'app' || !base) return [];\n\n\treturn [\n\t\thttp.all(`${trim(base)}/*`, ({ request }) => fake.handler.fetch(request)),\n\t];\n}\n\n/**\n * A construct's client for this test, by service name — through the test's own\n * discovery, so a topic or queue is its recorder and a database its\n * transaction, exactly as the test's endpoints get them.\n */\nasync function resolveService(\n\tapp: LoadedApp,\n\tstate: ContextState,\n\tname: string,\n): Promise<unknown> {\n\tconst construct = app.consumables.find(\n\t\t(candidate) => candidate.service.serviceName === name,\n\t);\n\tif (!construct) {\n\t\tthrow new UnknownService(\n\t\t\tname,\n\t\t\tapp.consumables.map((candidate) => candidate.service.serviceName),\n\t\t);\n\t}\n\n\tconst registered = await state.discovery.register([construct.service]);\n\treturn (registered as Record<string, unknown>)[name];\n}\n\n/** An auth server, served at its URL, on the transaction of the test that asked. */\nfunction authHandler(\n\tauth: BetterAuth,\n\tenv: Record<string, string | undefined>,\n\tenvParser: EnvironmentParser<{}>,\n) {\n\tconst base = trim(env[provideKey(auth.id, 'url')] ?? '');\n\n\t// The whole origin, not only `basePath`: the auth server answers its own\n\t// host deployed, and a redirect it issues — to `/` after verifying a magic\n\t// link — lands on it. Paths it does not route get its own 404.\n\treturn http.all(`${base}/*`, ({ request }) =>\n\t\tserve(request, async (state) => {\n\t\t\tlet app = state.auth.get(auth);\n\t\t\tif (!app) {\n\t\t\t\tapp = auth\n\t\t\t\t\t.server({ envParser, context: serviceContext })\n\t\t\t\t\t.then(({ app }) => app);\n\t\t\t\tstate.auth.set(auth, app);\n\t\t\t}\n\t\t\t// A loopback peer, so an API's session check — an internal caller —\n\t\t\t// keeps the browser's address it carries: see `./peer`.\n\t\t\treturn (await app).fetch(request, inProcessBindings());\n\t\t}),\n\t);\n}\n\n/** Handle a request as the server side of the test it was made for. */\nasync function serve(\n\trequest: Request,\n\thandle: (state: ContextState) => Promise<Response>,\n): Promise<Response> {\n\tconst id = testContextOf(request);\n\tconst state = id ? contexts.get(id) : undefined;\n\tif (!id || !state) throw new UnknownTestContext(request.url, id);\n\n\treturn runAsServer(id, () => handle(state));\n}\n\nfunction trim(url: string): string {\n\treturn url.replace(/\\/$/, '');\n}\n\nfunction isLocal(url: URL): boolean {\n\treturn (\n\t\turl.hostname === 'localhost' ||\n\t\turl.hostname === '127.0.0.1' ||\n\t\turl.hostname.endsWith('.localhost')\n\t);\n}\n\n/** What `signInWithMagicLink` uses of a better-auth client. */\nexport interface MagicLinkAuthClient<TSession> {\n\tsignIn: {\n\t\tmagicLink(input: {\n\t\t\temail: string;\n\t\t}): Promise<{ error?: { message?: string } | null }>;\n\t};\n\tgetSession(): Promise<{ data: TSession | null }>;\n}\n\n/**\n * Sign a test's browser in the way a person does: ask the auth server for a\n * magic link, open the email it sent, follow the link.\n *\n * What the generated `browser.signIn(email)` calls. The address's mail is\n * cleared first — so the link is this request's, not one an earlier test left\n * — and cleared again after the test, like any address a test reads. Returns\n * the session the auth server then reports, as better-auth hands it back.\n */\nexport async function signInWithMagicLink<TSession>(\n\tbrowser: TestBrowser,\n\tauth: MagicLinkAuthClient<TSession>,\n\temail: string = freshAddress(),\n): Promise<TSession> {\n\tconst context = currentTestContext();\n\tconst state = context && contexts.get(context.id);\n\tif (!state) throw new UnknownTestContext('signIn', context?.id);\n\tif (!state.mailbox) throw new NoInbox();\n\n\tconst inbox = state.mailbox(email);\n\tawait inbox.clear();\n\n\tconst requested = await auth.signIn.magicLink({ email });\n\tif (requested.error) {\n\t\tthrow new SignInFailed(\n\t\t\temail,\n\t\t\t`the auth server refused the magic link: ${requested.error.message ?? 'no reason given'}`,\n\t\t);\n\t}\n\n\tconst mail = await inbox.last();\n\tif (!mail.link) throw new SignInFailed(email, 'its email held no link');\n\tawait browser.visit(mail.link);\n\n\tconst { data } = await auth.getSession();\n\tif (!data) {\n\t\tthrow new SignInFailed(\n\t\t\temail,\n\t\t\t'the auth server reported no session after the link was opened',\n\t\t);\n\t}\n\treturn data;\n}\n\n/**\n * An address nobody else signs in as — what `browser.signIn()` uses when the\n * test does not care who it is.\n *\n * Unique rather than only seeded: tests in other files run at the same time,\n * against the same Mailpit and the same unique columns, and a seeded address\n * repeats wherever two tests share a name. The readable half is the seeded\n * faker's, so a failure still names somebody.\n */\nfunction freshAddress(): string {\n\tconst name = faker.internet\n\t\t.username()\n\t\t.toLowerCase()\n\t\t.replace(/[^a-z0-9]/g, '');\n\n\treturn `${name}.${randomUUID().slice(0, 8)}@example.test`;\n}\n\n/** `browser.signIn` finished without a session. */\nexport class SignInFailed extends Error {\n\tconstructor(\n\t\treadonly email: string,\n\t\treadonly reason: string,\n\t) {\n\t\tsuper(`Signing ${email} in failed: ${reason}.`);\n\t\tthis.name = 'SignInFailed';\n\t}\n}\n\n/** A request reached an in-process server without a test to belong to. */\nexport class UnknownTestContext extends Error {\n\tconstructor(\n\t\treadonly url: string,\n\t\treadonly id: string | undefined,\n\t) {\n\t\tsuper(\n\t\t\tid\n\t\t\t\t? `${url} was requested for test ${id}, which is not running. A ` +\n\t\t\t\t\t\t`request that outlives its test — an un-awaited call — lands here.`\n\t\t\t\t: `${url} was requested outside any test. Make the request inside a ` +\n\t\t\t\t\t\t`featureTest, so it reaches that test's transactions.`,\n\t\t);\n\t\tthis.name = 'UnknownTestContext';\n\t}\n}\n\n/** `mailbox` was used in an app that declares no Email construct. */\nexport class NoInbox extends Error {\n\tconstructor() {\n\t\tsuper(\n\t\t\t`mailbox() reads the inbox of the app's Email construct, and none was ` +\n\t\t\t\t`found in featureTest's modules — or \\`gkm test\\` did not inject its ` +\n\t\t\t\t`<ID>_INBOX_URL.`,\n\t\t);\n\t\tthis.name = 'NoInbox';\n\t}\n}\n\n/** `db.get(name)` named no database the test is handed. */\nexport class UnknownDatabase extends Error {\n\tconstructor(\n\t\treadonly database: string,\n\t\treadonly known: readonly string[],\n\t) {\n\t\tsuper(\n\t\t\t`db.get('${database}') names no database of this app's. ` +\n\t\t\t\t(known.length > 0\n\t\t\t\t\t? `Its databases: ${known.join(', ')}. `\n\t\t\t\t\t: 'It declares no database of its own. ') +\n\t\t\t\t`A tenant an auth server owns is reached through that server, and a ` +\n\t\t\t\t`reader through the database it reads.`,\n\t\t);\n\t\tthis.name = 'UnknownDatabase';\n\t}\n}\n\n/** A factory keyed by a service name no database the app declares has. */\nexport class UnknownFactory extends Error {\n\tconstructor(\n\t\treadonly factory: string,\n\t\treadonly known: readonly string[],\n\t) {\n\t\tsuper(\n\t\t\t`There is a test factory for '${factory}', and no database this app ` +\n\t\t\t\t`declares is called that. ` +\n\t\t\t\t(known.length > 0\n\t\t\t\t\t? `Its databases: ${known.join(', ')}. `\n\t\t\t\t\t: 'It declares no database. ') +\n\t\t\t\t`Name the file after the database construct: test/factories/<construct>.ts.`,\n\t\t);\n\t\tthis.name = 'UnknownFactory';\n\t}\n}\n\n/** A published message the consumer's own schema refuses. */\nexport class MessageRejected extends Error {\n\tconstructor(\n\t\treadonly consumer: string,\n\t\treadonly published: PublishedMessage,\n\t\treadonly issues: ReadonlyArray<StandardSchemaV1.Issue>,\n\t) {\n\t\tsuper(\n\t\t\t`${consumer} refuses '${published.type}': ${issues\n\t\t\t\t.map((issue) => issue.message)\n\t\t\t\t.join('; ')}. What is published must be what the consumer's schema ` +\n\t\t\t\t'takes — fix the producer, or the schema.',\n\t\t);\n\t\tthis.name = 'MessageRejected';\n\t}\n}\n\n/** A consumer that threw while handling what the test published. */\nexport class DeliveryFailed extends Error {\n\tconstructor(\n\t\treadonly consumer: string,\n\t\treadonly messages: readonly PublishedMessage[],\n\t\toverride readonly cause: unknown,\n\t) {\n\t\tsuper(\n\t\t\t`${consumer} failed handling ${messages\n\t\t\t\t.map(({ type }) => `'${type}'`)\n\t\t\t\t.join(', ')}: ${(cause as Error)?.message ?? String(cause)}. ` +\n\t\t\t\t'Deployed, the message would be retried; here the failure is the result.',\n\t\t\t{ cause },\n\t\t);\n\t\tthis.name = 'DeliveryFailed';\n\t}\n}\n\n/** Consumers that kept publishing to each other without settling. */\nexport class DeliveryDidNotSettle extends Error {\n\tconstructor(\n\t\treadonly rounds: number,\n\t\treadonly channels: readonly string[],\n\t) {\n\t\tsuper(\n\t\t\t`Delivery did not settle after ${rounds} rounds — consumers are still ` +\n\t\t\t\t`publishing to ${channels.join(', ')}. A consumer that publishes to ` +\n\t\t\t\t'what triggers it loops forever deployed too.',\n\t\t);\n\t\tthis.name = 'DeliveryDidNotSettle';\n\t}\n}\n\n/** `services.get(name)` for a name no construct of the app is served by. */\nexport class UnknownService extends Error {\n\tconstructor(\n\t\treadonly serviceName: string,\n\t\treadonly available: readonly string[],\n\t) {\n\t\tsuper(\n\t\t\t`The app declares no construct served as '${serviceName}'. Its services are: ` +\n\t\t\t\t`${available.join(', ') || 'none'}.`,\n\t\t);\n\t\tthis.name = 'UnknownService';\n\t}\n}\n"],"mappings":"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"}
@@ -5,7 +5,8 @@ import { c as EndpointSchemas, i as Endpoint } from "../Endpoint-C4PZn_mD.cjs";
5
5
  import { t as Queue } from "../Queue-HPyi0e1i.cjs";
6
6
  import { t as Subscriber } from "../Subscriber-Bpp02cGr.cjs";
7
7
  import { t as KyselyDatabase } from "../kysely-D0bpzgPs.cjs";
8
- import { r as Fake } from "../external-api-BaIgJ6Ey.cjs";
8
+ import { o as TestStage } from "../stages-BSCF19o2.cjs";
9
+ import { i as Fake } from "../external-api-O107yzZJ.cjs";
9
10
  import { Logger } from "@geekmidas/logger";
10
11
  import { ComposableStandardSchema, InferComposableStandardSchema, InferStandardSchema } from "@geekmidas/schema";
11
12
  import { Service, ServiceDiscovery, ServiceRecord } from "@geekmidas/services";
@@ -194,17 +195,6 @@ type TestSubscriberRequest<TEventPublisher extends EventPublisher<any> | undefin
194
195
  };
195
196
  //#endregion
196
197
  //#region src/testing/manifest.d.ts
197
- /**
198
- * The test manifest: what `gkm test` knows about an app, written down for the
199
- * suite it starts.
200
- *
201
- * `gkm test` discovers the constructs, reconciles the test stage and resolves
202
- * its environment — then, until this existed, threw all of it away and left a
203
- * test to declare it again by hand. The manifest keeps it: which construct and
204
- * endpoint is exported where, and the environment the test stage resolved,
205
- * under the keys the constructs themselves derive. A feature test is built from
206
- * it, so nothing a test says can drift from what the app declares.
207
- */
208
198
  /** Where an export lives: what an import statement has to say. */
209
199
  interface TestManifestSource {
210
200
  /** Absolute path to the module. */
@@ -214,7 +204,7 @@ interface TestManifestSource {
214
204
  }
215
205
  interface TestManifest {
216
206
  /** The stage the environment was resolved for — `test`. */
217
- stage: string;
207
+ stage: TestStage;
218
208
  /** Every construct the app declares, by id. */
219
209
  constructs: Record<string, {
220
210
  kind: string;
@@ -1 +1 @@
1
- {"version":3,"file":"testing.d.cts","names":["TestBrowser"],"sources":["../../src/endpoints/MswEndpointAdaptor.ts","../../src/endpoints/TestEndpointAdaptor.ts","../../src/functions/TestFunctionAdaptor.ts","../../src/queue/TestQueueAdaptor.ts","../../src/subscribers/TestSubscriberAdaptor.ts","../../src/testing/manifest.ts","../../src/testing/featureTest.ts","../../src/testing/peer.ts"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;UA0DiB;;EAEhB;;;;;;;;;UAUgB;;EAEhB,WAAW;;EAEX;;EAEA;;;;;UAiBgB;;EAEhB,UAAU;;EAEV,kBAAkB,YAAY,SAAS;;;;;;;;;;;;;;;;;wBAkBxB,kBACf,WAAW,0CACX,SAAS,2BACP;;;KC/ES,iBAAiB;EAC5B,MAAM;EACN;EACA,SAAS;;qBAwCG,oBACZ,uBACA,gBAAgB,YAChB,eAAe,sBACf,mBAAmB,0CACnB,kBAAkB,gBAClB,gBAAgB,SAAS,QACzB,oBACA,sBAAsB,sCACtB,kDACA,qBAAqB,mCAAmC,kCAIxD,uBACA;mBAqCkB;UAcT;SAjDF,0BACN,uBACA,gBAAgB,YAChB,eAAe,sBACf,mBAAmB,0CACnB,kBAAkB,gBAClB,gBAAgB,SAAS,QACzB,oBACA,sBAAsB,sCACtB,kDACA,qBAAqB,mCAAmC,kCAIxD,uBACA,8CAEA,WAAW,SACV,QACA,SACA,QACA,YACA,WACA,SACA,UACA,eACA,0BACA,cACA,WACA;EAKF,YACkB,UAAU,SAC1B,QACA,SACA,QACA,YACA,WACA,SACA,UACA,eACA,0BACA,cACA,WACA,uBAEO,mBAAkB;EAKrB,YACL,KAAK,mBACJ,QACA,WACA,eACA,0BACA,WACA,wBAEC,QAAQ,iBAAiB,oBAAoB;EA6M1C,QACL,KAAK,mBACJ,QACA,WACA,eACA,0BACA,WACA,wBAEC,QAAQ,oBAAoB;;;;;KAS3B,wBACJ,sBAAsB,wCACnB;;EAID,gBAAgB;;;;;KAMd,oBAAoB,yBAAyB;;EAI/C,UAAU;;KAGD,mBACX,eAAe,sBACf,kBAAkB,gBAClB,sBAAsB,sCACtB,mDACA,uBACA;EAEA,UAAU,cAAc;EACxB,SAAS;IACN,8BAA8B,UACjC,wBAAwB,iBACxB,oBAAoB;;;qBC3YR,oBACZ,eAAe,kDACf,mBAAmB,0CACnB,kBAAkB,gBAClB,gBAAgB,SAAS,QACzB,sBAAsB,sCACtB,kDACA,uBACA,8CACA,qBAAqB,mCAAmC;mBAoCtC;UAYT;SA3CF,2BACN,eAAe,kDACf,mBAAmB,0CACnB,kBAAkB,gBAClB,gBAAgB,SAAS,QACzB,sBAAsB,sCACtB,kDACA,uBACA,8CACA,qBAAqB,mCAAmC,kCAKxD,KAAK,SACJ,QACA,WACA,SACA,YACA,eACA,0BACA,WACA,sBACA;EAOF,YACkB,IAAI,SACpB,QACA,WACA,SACA,YACA,eACA,0BACA,WACA,sBACA,oBAGO,mBAAkB;EAKrB,OACL,KAAK,oBAAoB,QAAQ,WAAW,WAAW,gBACrD,QAAQ,oBAAoB;;KAoGpB,oBACX,eAAe,kDACf,kBAAkB,gBAClB,uBACA,qBAAqB,mCAAmC;EAKxD,OAAO,8BAA8B;EACrC,UAAU,cAAc;EACxB,KAAK;EACL,UAAU,QAAQ;IACf;EAAgC,OAAO;;;;;;;;;;;;;;qBCpL9B,iBACZ,+BACA,iBAAiB,mBAAmB,kBACpC,kBAAkB,gBAClB,gBAAgB,SAAS,QACzB,uBACA;mBAOkB;UAQT;SAbF;EAIP,YACkB,OAAO,MACvB,OACA,UACA,WACA,SACA,WACA,uBAEO,mBAAkB;EAGrB,OACL,SAAS,iBAAiB,UAAU,WAAW,aAC7C;UA2BW;;KAUH,iBACX,iBAAiB,mBAAmB,kBACpC,kBAAkB,gBAClB;EAEA,UAAU,oBAAoB;EAC9B,WAAW,cAAc;;EAEzB,KAAK;;;;KC5ED,qBACJ,mBAAmB,iCACnB,6BACG,mBAAmB,sBACpB,QAAQ,wBAAwB;EAAe,MAAM;;qBAG3C,sBACZ,kBAAkB,gBAClB,gBAAgB,SAAS,QACzB,kBAAkB,0CAClB,wBAAwB,6CACxB,0BACC,wBAAwB,6BAA6B,wBAAwB,4BAC9E,uBACA;mBAOkB;UAST;SAdF;EAIP,YACkB,YAAY,WAC5B,WACA,SACA,WACA,iBACA,mBACA,WACA,uBAEO,mBAAkB;EAGrB,OACL,SAAS,sBACR,iBACA,mBACA,WACA,aAEC,QAAQ,oBAAoB;UA2DjB;UASN;;KAaG,sBACX,wBAAwB,6CACxB,sCACA,kBAAkB,gBAClB;EAEA,QAAQ,qBAAqB,iBAAiB;EAC9C,WAAW,cAAc;;EAEzB,KAAK;;;;;;;;;;;;;;;;UC/HW;;EAEhB;;EAEA;;UAGgB;;EAEhB;;EAEA,YAAY;IAAiB;IAAc,QAAQ;;;EAEnD;IAAa;IAAiB,QAAQ;;;;;;;EAMtC;IAAgB,QAAQ;;;;;;EAKxB,KAAK;;;qBAIO;;;;;wBAMG,iBAAiB,gBAAgB,MAAM;;qBAsC1C,uBAAuB;EACnC;;;;;KC5BW,kBAAkB,gBAAgB,IAAI;UAEjC,mBAChB,iBAAiBA,SACjB,mBAAmB;;;;;EAMnB,WAAW;;;;;;;EAOX,UAAU,SAAS,eAAe;;EAElC,oBAAoB;;;;;;;;EAQpB,YAAY;;;;;;EAMZ,QAAQ,SAAS,eAAe;;;KAIrB,kBAAkB;;KAGlB,iBAAiB;;KAGjB,SAAS,KAAK;EACzB;IAAW,cAAc,sBAAsB;;IAE7C,QAAQ;;;;;;;;;UAWM,aAAa,kBAAkB;EAC/C,IAAI,gBAAgB,oBAAoB,MAAM,IAAI,QAAQ,UAAU;;;;;;;;;UAUpD,cAAc,mBAAmB;EACjD,IAAI,gBAAgB,qBACnB,MAAM,IACJ,QAAQ,OAAO,WAAW;;;;;;;;UASb,cAAc,mBAAmB;EACjD,IAAI,gBAAgB,qBACnB,MAAM,IACJ,QAAQ,WAAW,WAAW;;UAGjB,eAChB,iBAAiBA,SACjB,mBAAmB,sBACnB,mBAAmB,sBACnB,kBAAkB;;EAGlB,SAAS;;;;;;EAMT,IAAI,cAAc;;;;;;EAMlB,WAAW,cAAc;;;;;;EAMzB,OAAO;;EAEP,UAAU,oBAAoB;;;;;;;;EAQ9B,YAAY;IAAW;QAAiB;;;;;;EAMxC,aAAa,UAAU,+CACtB,YAAY,MACR,oBAAoB;;;;;;;EAOzB,UAAU,aAAa;;EAEvB,QAAQ,UAAU,qCACjB,OAAO,MACH,eAAe;;KAGhB,oBAAoB,KACxB,UAAU,iBACH,iBACA,eACA,iBACA,uBACA,yBACA,iBACA,wBAEJ,sBACA,WACA,SACA,WACA,iBACA,mBACA,WACA;KAIC,eAAe,KACnB,UAAU,YACH,aACA,gBACA,iBACA,eACA,iBACA,wBAEJ,iBACA,OACA,UACA,WACA,SACA,WACA;;KAKQ,WAAW,KACtB,UAAU,qBAAqB,WAAW;;UAG1B;EAChB;EACA;;KAGI,UACJ,iBAAiBA,SACjB,mBAAmB,iBACnB,mBAAmB,iBACnB,kBAAkB,mBAElB,SAAS,eAAe,UAAU,YAAY,YAAY;UAG1C,UAChB,iBAAiBA,SACjB,mBAAmB,sBACnB,mBAAmB,sBACnB,kBAAkB;GAGjB,cACA,IAAI,UAAU,UAAU,YAAY,YAAY,YAChD;EAED,KACC,cACA,IAAI,UAAU,UAAU,YAAY,YAAY,YAChD;EAED,KACC,cACA,IAAI,UAAU,UAAU,YAAY,YAAY,YAChD;;wBAoDc,YACf,iBAAiBA,UAAcA,SAC/B,mBAAmB,sBACnB,mBAAmB,sBACnB,kBAAkB,qBAElB,UAAS,mBAAmB,UAAU,cACpC,UAAU,UAAU,YAAY,YAAY;;UAspB9B,oBAAoB;EACpC;IACC,UAAU;MACT;QACG;MAAU;QAAU;;;;EAEzB,cAAc;IAAU,MAAM;;;;;;;;;;;;wBAYT,oBAAoB,UACzC,SAASA,SACT,MAAM,oBAAoB,WAC1B,iBACE,QAAQ;;qBAkDE,qBAAqB;WAEvB;WACA;EAFV,YACU,eACA;;;qBAQE,2BAA2B;WAE7B;WACA;EAFV,YACU,aACA;;;qBAcE,gBAAgB;EAC5B;;;qBAWY,wBAAwB;WAE1B;WACA;EAFV,YACU,kBACA;;;qBAeE,uBAAuB;WAEzB;WACA;EAFV,YACU,iBACA;;;qBAeE,wBAAwB;WAE1B;WACA,WAAW;WACX,QAAQ,cAAc,iBAAiB;EAHjD,YACU,kBACA,WAAW,kBACX,QAAQ,cAAc,iBAAiB;;;qBAarC,uBAAuB;WAEzB;WACA,mBAAmB;WACV;EAHnB,YACU,kBACA,mBAAmB,oBACV;;;qBAcP,6BAA6B;WAE/B;WACA;EAFV,YACU,gBACA;;;qBAYE,uBAAuB;WAEzB;WACA;EAFV,YACU,qBACA;;;;;;;;;;;;;;;;;;;;;;;;;;;qBC7pCE;;UAGI;EAChB;IAAY;MAAU;;;;;wBAIP,qBAAqB"}
1
+ {"version":3,"file":"testing.d.cts","names":["TestBrowser"],"sources":["../../src/endpoints/MswEndpointAdaptor.ts","../../src/endpoints/TestEndpointAdaptor.ts","../../src/functions/TestFunctionAdaptor.ts","../../src/queue/TestQueueAdaptor.ts","../../src/subscribers/TestSubscriberAdaptor.ts","../../src/testing/manifest.ts","../../src/testing/featureTest.ts","../../src/testing/peer.ts"],"mappings":"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"}