@fragno-dev/test 2.0.0 → 2.0.2
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.
- package/.turbo/turbo-build.log +41 -31
- package/CHANGELOG.md +69 -0
- package/dist/adapters.d.ts +4 -7
- package/dist/adapters.d.ts.map +1 -1
- package/dist/adapters.js +18 -302
- package/dist/adapters.js.map +1 -1
- package/dist/db-test.d.ts +120 -18
- package/dist/db-test.d.ts.map +1 -1
- package/dist/db-test.js +203 -55
- package/dist/db-test.js.map +1 -1
- package/dist/durable-hooks.d.ts +6 -2
- package/dist/durable-hooks.d.ts.map +1 -1
- package/dist/durable-hooks.js +10 -5
- package/dist/durable-hooks.js.map +1 -1
- package/dist/index.d.ts +3 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/model-checker-actors.d.ts.map +1 -1
- package/dist/model-checker-actors.js +1 -1
- package/dist/model-checker-actors.js.map +1 -1
- package/dist/model-checker-adapter.d.ts +1 -1
- package/dist/model-checker-adapter.d.ts.map +1 -1
- package/dist/model-checker-adapter.js.map +1 -1
- package/dist/model-checker.d.ts.map +1 -1
- package/dist/model-checker.js.map +1 -1
- package/dist/test-adapters/drizzle-pglite.js +116 -0
- package/dist/test-adapters/drizzle-pglite.js.map +1 -0
- package/dist/test-adapters/in-memory.js +39 -0
- package/dist/test-adapters/in-memory.js.map +1 -0
- package/dist/test-adapters/kysely-pglite.js +105 -0
- package/dist/test-adapters/kysely-pglite.js.map +1 -0
- package/dist/test-adapters/kysely-sqlite.js +87 -0
- package/dist/test-adapters/kysely-sqlite.js.map +1 -0
- package/dist/test-adapters/model-checker.js +41 -0
- package/dist/test-adapters/model-checker.js.map +1 -0
- package/dist/tsconfig.tsbuildinfo +1 -0
- package/package.json +32 -33
- package/src/adapter-conformance.test.ts +3 -1
- package/src/adapters.ts +24 -455
- package/src/db-roundtrip-guard.test.ts +206 -0
- package/src/db-test.test.ts +131 -77
- package/src/db-test.ts +530 -96
- package/src/durable-hooks.test.ts +58 -0
- package/src/durable-hooks.ts +23 -8
- package/src/index.test.ts +188 -104
- package/src/index.ts +6 -2
- package/src/model-checker-actors.test.ts +5 -2
- package/src/model-checker-actors.ts +2 -1
- package/src/model-checker-adapter.ts +3 -2
- package/src/model-checker.test.ts +4 -1
- package/src/model-checker.ts +4 -3
- package/src/test-adapters/drizzle-pglite.ts +162 -0
- package/src/test-adapters/in-memory.ts +56 -0
- package/src/test-adapters/kysely-pglite.ts +151 -0
- package/src/test-adapters/kysely-sqlite.ts +119 -0
- package/src/test-adapters/model-checker.ts +58 -0
- package/tsconfig.json +1 -1
- package/vitest.config.ts +1 -0
package/dist/db-test.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"db-test.js","names":["#adapter","#fragments","schemaConfigs: SchemaConfig[]","builderConfigs: Array<{ config: any; routes: any; options: any }>","schema: AnySchema | undefined","namespace: string | null | undefined","providedServicesByName: Record<string, { service: any; orm: any }>","fragmentResults: any[]","serviceImplementations: Record<string, any>","fragmentResults","drainError: unknown","cleanupError: unknown"],"sources":["../src/db-test.ts"],"sourcesContent":["import type { AnySchema } from \"@fragno-dev/db/schema\";\nimport type {\n RequestThisContext,\n FragnoPublicConfig,\n FragmentInstantiationBuilder,\n FragnoInstantiatedFragment,\n FragmentDefinition,\n} from \"@fragno-dev/core\";\nimport type { AnyRouteOrFactory, FlattenRouteFactories } from \"@fragno-dev/core/route\";\nimport {\n createAdapter,\n type SupportedAdapter,\n type AdapterContext,\n type SchemaConfig,\n} from \"./adapters\";\nimport type { DatabaseAdapter } from \"@fragno-dev/db\";\nimport type { SimpleQueryInterface } from \"@fragno-dev/db/query\";\nimport type { BaseTestContext } from \".\";\nimport { drainDurableHooks } from \"./durable-hooks\";\n\n// BoundServices is an internal type that strips 'this' parameters from service methods\n// It's used to represent services after they've been bound to a context\ntype BoundServices<T> = {\n [K in keyof T]: T[K] extends (this: any, ...args: infer A) => infer R // eslint-disable-line @typescript-eslint/no-explicit-any\n ? (...args: A) => R\n : T[K] extends Record<string, unknown>\n ? BoundServices<T[K]>\n : T[K];\n};\n\n// Extract the schema type from database fragment dependencies\n// Database fragments have ImplicitDatabaseDependencies<TSchema> which includes `schema: TSchema`\ntype ExtractSchemaFromDeps<TDeps> = TDeps extends { schema: infer TSchema extends AnySchema }\n ? TSchema\n : AnySchema;\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\ntype AnyLinkedFragments = Record<string, any>;\n\n// Forward declarations for recursive type references\ninterface FragmentResult<\n TDeps,\n TServices extends Record<string, unknown>,\n TServiceThisContext extends RequestThisContext,\n THandlerThisContext extends RequestThisContext,\n TRequestStorage,\n TRoutes extends readonly any[], // eslint-disable-line @typescript-eslint/no-explicit-any\n TSchema extends AnySchema,\n TLinkedFragments extends AnyLinkedFragments = {},\n> {\n fragment: FragnoInstantiatedFragment<\n TRoutes,\n TDeps,\n TServices,\n TServiceThisContext,\n THandlerThisContext,\n TRequestStorage,\n FragnoPublicConfig,\n TLinkedFragments\n >;\n services: TServices;\n deps: TDeps;\n callRoute: FragnoInstantiatedFragment<\n TRoutes,\n TDeps,\n TServices,\n TServiceThisContext,\n THandlerThisContext,\n TRequestStorage,\n FragnoPublicConfig,\n TLinkedFragments\n >[\"callRoute\"];\n db: SimpleQueryInterface<TSchema>;\n}\n\n// Safe: Catch-all for any fragment result type\ntype AnyFragmentResult = FragmentResult<\n any, // eslint-disable-line @typescript-eslint/no-explicit-any\n any, // eslint-disable-line @typescript-eslint/no-explicit-any\n any, // eslint-disable-line @typescript-eslint/no-explicit-any\n any, // eslint-disable-line @typescript-eslint/no-explicit-any\n any, // eslint-disable-line @typescript-eslint/no-explicit-any\n any, // eslint-disable-line @typescript-eslint/no-explicit-any\n any, // eslint-disable-line @typescript-eslint/no-explicit-any\n any // eslint-disable-line @typescript-eslint/no-explicit-any\n>;\n\n// Safe: Catch-all for any fragment builder config type\ntype AnyFragmentBuilderConfig = FragmentBuilderConfig<\n any, // eslint-disable-line @typescript-eslint/no-explicit-any\n any, // eslint-disable-line @typescript-eslint/no-explicit-any\n any, // eslint-disable-line @typescript-eslint/no-explicit-any\n any, // eslint-disable-line @typescript-eslint/no-explicit-any\n any, // eslint-disable-line @typescript-eslint/no-explicit-any\n any, // eslint-disable-line @typescript-eslint/no-explicit-any\n any, // eslint-disable-line @typescript-eslint/no-explicit-any\n any, // eslint-disable-line @typescript-eslint/no-explicit-any\n any, // eslint-disable-line @typescript-eslint/no-explicit-any\n any, // eslint-disable-line @typescript-eslint/no-explicit-any\n any, // eslint-disable-line @typescript-eslint/no-explicit-any\n any // eslint-disable-line @typescript-eslint/no-explicit-any\n>;\n\n/**\n * Configuration for a single fragment in the test builder\n */\ninterface FragmentBuilderConfig<\n TConfig,\n TOptions extends FragnoPublicConfig,\n TDeps,\n TBaseServices extends Record<string, unknown>,\n TServices extends Record<string, unknown>,\n TServiceDependencies,\n TPrivateServices extends Record<string, unknown>,\n TServiceThisContext extends RequestThisContext,\n THandlerThisContext extends RequestThisContext,\n TRequestStorage,\n TRoutesOrFactories extends readonly AnyRouteOrFactory[],\n TLinkedFragments extends AnyLinkedFragments,\n> {\n definition: FragmentDefinition<\n TConfig,\n TOptions,\n TDeps,\n TBaseServices,\n TServices,\n TServiceDependencies,\n TPrivateServices,\n TServiceThisContext,\n THandlerThisContext,\n TRequestStorage,\n TLinkedFragments\n >;\n builder: FragmentInstantiationBuilder<\n TConfig,\n TOptions,\n TDeps,\n TBaseServices,\n TServices,\n TServiceDependencies,\n TPrivateServices,\n TServiceThisContext,\n THandlerThisContext,\n TRequestStorage,\n TRoutesOrFactories,\n TLinkedFragments\n >;\n migrateToVersion?: number;\n}\n\n/**\n * Test context combining base and adapter-specific functionality\n */\ntype TestContext<\n T extends SupportedAdapter,\n TFirstFragmentThisContext extends RequestThisContext = RequestThisContext,\n> = BaseTestContext &\n AdapterContext<T> & {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n adapter: DatabaseAdapter<any>;\n /**\n * Execute a callback within the first fragment's request context.\n * This is useful for calling services outside of route handlers in tests.\n */\n inContext<TResult>(callback: (this: TFirstFragmentThisContext) => TResult): TResult;\n inContext<TResult>(\n callback: (this: TFirstFragmentThisContext) => Promise<TResult>,\n ): Promise<TResult>;\n };\n\n/**\n * Result of building the database fragments test\n */\ninterface DatabaseFragmentsTestResult<\n TFragments extends Record<string, AnyFragmentResult>,\n TAdapter extends SupportedAdapter,\n TFirstFragmentThisContext extends RequestThisContext = RequestThisContext,\n> {\n fragments: TFragments;\n test: TestContext<TAdapter, TFirstFragmentThisContext>;\n}\n\n/**\n * Internal storage for fragment configurations\n */\ntype FragmentConfigMap = Map<string, AnyFragmentBuilderConfig>;\n\n/**\n * Builder for creating multiple database fragments for testing\n */\nexport class DatabaseFragmentsTestBuilder<\n TFragments extends Record<string, AnyFragmentResult>,\n TAdapter extends SupportedAdapter | undefined = undefined,\n TFirstFragmentThisContext extends RequestThisContext = RequestThisContext,\n> {\n #adapter?: SupportedAdapter;\n #fragments: FragmentConfigMap = new Map();\n\n /**\n * Set the test adapter configuration\n */\n withTestAdapter<TNewAdapter extends SupportedAdapter>(\n adapter: TNewAdapter,\n ): DatabaseFragmentsTestBuilder<TFragments, TNewAdapter, TFirstFragmentThisContext> {\n this.#adapter = adapter;\n return this as any; // eslint-disable-line @typescript-eslint/no-explicit-any\n }\n\n /**\n * Add a fragment to the test setup\n *\n * @param name - Unique name for the fragment\n * @param builder - Pre-configured instantiation builder\n * @param options - Additional options (optional)\n */\n withFragment<\n TName extends string,\n TConfig,\n TOptions extends FragnoPublicConfig,\n TDeps,\n TBaseServices extends Record<string, unknown>,\n TServices extends Record<string, unknown>,\n TServiceDependencies,\n TPrivateServices extends Record<string, unknown>,\n TServiceThisContext extends RequestThisContext,\n THandlerThisContext extends RequestThisContext,\n TRequestStorage,\n TRoutesOrFactories extends readonly AnyRouteOrFactory[],\n TLinkedFragments extends AnyLinkedFragments,\n >(\n name: TName,\n builder: FragmentInstantiationBuilder<\n TConfig,\n TOptions,\n TDeps,\n TBaseServices,\n TServices,\n TServiceDependencies,\n TPrivateServices,\n TServiceThisContext,\n THandlerThisContext,\n TRequestStorage,\n TRoutesOrFactories,\n TLinkedFragments\n >,\n options?: {\n migrateToVersion?: number;\n },\n ): DatabaseFragmentsTestBuilder<\n TFragments & {\n [K in TName]: FragmentResult<\n TDeps,\n BoundServices<TBaseServices & TServices>,\n TServiceThisContext,\n THandlerThisContext,\n TRequestStorage,\n FlattenRouteFactories<TRoutesOrFactories>,\n ExtractSchemaFromDeps<TDeps>, // Extract actual schema type from deps\n TLinkedFragments\n >;\n },\n TAdapter,\n // If this is the first fragment (TFragments is empty {}), use THandlerThisContext; otherwise keep existing\n keyof TFragments extends never ? THandlerThisContext : TFirstFragmentThisContext\n > {\n this.#fragments.set(name, {\n definition: builder.definition,\n builder,\n migrateToVersion: options?.migrateToVersion,\n });\n return this as any; // eslint-disable-line @typescript-eslint/no-explicit-any\n }\n\n /**\n * Build the test setup and return fragments and test context\n */\n async build(): Promise<\n TAdapter extends SupportedAdapter\n ? DatabaseFragmentsTestResult<TFragments, TAdapter, TFirstFragmentThisContext>\n : never\n > {\n if (!this.#adapter) {\n throw new Error(\"Test adapter must be set using withTestAdapter()\");\n }\n\n if (this.#fragments.size === 0) {\n throw new Error(\"At least one fragment must be added using withFragment()\");\n }\n\n const adapterConfig = this.#adapter;\n\n // Extract fragment names and configs\n const fragmentNames = Array.from(this.#fragments.keys());\n const fragmentConfigs = Array.from(this.#fragments.values());\n\n // Extract schemas from definitions and prepare schema configs\n const schemaConfigs: SchemaConfig[] = [];\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const builderConfigs: Array<{ config: any; routes: any; options: any }> = [];\n\n for (const fragmentConfig of fragmentConfigs) {\n const builder = fragmentConfig.builder;\n const definition = builder.definition;\n\n // Extract schema and namespace from definition by calling dependencies with a mock adapter\n let schema: AnySchema | undefined;\n let namespace: string | null | undefined;\n\n if (definition.dependencies) {\n try {\n // Create a mock adapter to extract the schema\n const mockAdapter = {\n createQueryEngine: () => ({ schema: null }),\n getSchemaVersion: async () => undefined,\n namingStrategy: {\n namespaceScope: \"suffix\",\n namespaceToSchema: (value: string) => value,\n tableName: (logicalTable: string, ns: string | null) =>\n ns ? `${logicalTable}_${ns}` : logicalTable,\n columnName: (logicalColumn: string) => logicalColumn,\n indexName: (logicalIndex: string) => logicalIndex,\n uniqueIndexName: (logicalIndex: string) => logicalIndex,\n foreignKeyName: ({ referenceName }: { referenceName: string }) => referenceName,\n },\n contextStorage: { run: (_data: unknown, fn: () => unknown) => fn() },\n close: async () => {},\n };\n\n // Use the actual config from the builder instead of an empty mock\n // This ensures dependencies can be properly initialized (e.g., Stripe with API keys)\n const actualConfig = builder.config ?? {};\n\n const deps = definition.dependencies({\n config: actualConfig,\n options: {\n databaseAdapter: mockAdapter as any, // eslint-disable-line @typescript-eslint/no-explicit-any\n } as any, // eslint-disable-line @typescript-eslint/no-explicit-any\n });\n\n // The schema and namespace are in deps for database fragments\n if (deps && typeof deps === \"object\" && \"schema\" in deps) {\n schema = (deps as any).schema; // eslint-disable-line @typescript-eslint/no-explicit-any\n namespace = (deps as any).namespace; // eslint-disable-line @typescript-eslint/no-explicit-any\n }\n } catch (error) {\n // If extraction fails, provide a helpful error message\n const errorMessage =\n error instanceof Error\n ? error.message\n : typeof error === \"string\"\n ? error\n : \"Unknown error\";\n\n throw new Error(\n `Failed to extract schema from fragment '${definition.name}'.\\n` +\n `Original error: ${errorMessage}\\n\\n` +\n `Make sure the fragment is a database fragment using defineFragment().extend(withDatabase(schema)).`,\n );\n }\n }\n\n if (!schema) {\n throw new Error(\n `Fragment '${definition.name}' does not have a database schema. ` +\n `Make sure you're using defineFragment().extend(withDatabase(schema)).`,\n );\n }\n\n if (namespace === undefined) {\n throw new Error(\n `Fragment '${definition.name}' does not have a namespace in dependencies. ` +\n `This should be automatically provided by withDatabase().`,\n );\n }\n\n schemaConfigs.push({\n schema,\n namespace,\n migrateToVersion: fragmentConfig.migrateToVersion,\n });\n\n // Extract config, routes, and options from builder using public getters\n builderConfigs.push({\n config: builder.config ?? {},\n routes: builder.routes ?? [],\n options: builder.options ?? {},\n });\n }\n\n const { testContext, adapter } = await createAdapter(adapterConfig, schemaConfigs);\n\n // Helper to create fragments with service wiring\n const createFragments = () => {\n // First pass: create fragments without service dependencies to extract provided services\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const providedServicesByName: Record<string, { service: any; orm: any }> = {};\n const fragmentResults: any[] = []; // eslint-disable-line @typescript-eslint/no-explicit-any\n\n for (let i = 0; i < fragmentConfigs.length; i++) {\n const fragmentConfig = fragmentConfigs[i]!;\n const builderConfig = builderConfigs[i]!;\n const namespace = schemaConfigs[i]!.namespace;\n const schema = schemaConfigs[i]!.schema;\n const orm = testContext.getOrm(namespace);\n\n // Merge builder options with database adapter\n const mergedOptions = {\n ...builderConfig.options,\n databaseAdapter: adapter,\n };\n\n // Instantiate fragment using the builder\n const fragment = fragmentConfig.builder.withOptions(mergedOptions).build();\n\n // Extract provided services based on serviceDependencies metadata\n // Note: serviceDependencies lists services this fragment USES, not provides\n // For provided services, we need to check what's actually in fragment.services\n // and match against other fragments' service dependencies\n\n // Store all services as potentially provided\n for (const [serviceName, serviceImpl] of Object.entries(fragment.services)) {\n providedServicesByName[serviceName] = {\n service: serviceImpl,\n orm,\n };\n }\n\n // Store the fragment result\n const deps = fragment.$internal?.deps;\n\n fragmentResults.push({\n fragment,\n services: fragment.services,\n deps: deps || {},\n callRoute: fragment.callRoute.bind(fragment),\n get db() {\n return orm;\n },\n _orm: orm,\n _schema: schema,\n });\n }\n\n // Second pass: rebuild fragments with service dependencies wired up\n for (let i = 0; i < fragmentConfigs.length; i++) {\n const fragmentConfig = fragmentConfigs[i]!;\n const definition = fragmentConfig.builder.definition;\n const builderConfig = builderConfigs[i]!;\n const namespace = schemaConfigs[i]!.namespace;\n const schema = schemaConfigs[i]!.schema;\n const orm = testContext.getOrm(namespace);\n\n // Build service implementations for services this fragment uses\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const serviceImplementations: Record<string, any> = {};\n const serviceDependencies = definition.serviceDependencies;\n\n if (serviceDependencies) {\n for (const serviceName of Object.keys(serviceDependencies)) {\n if (providedServicesByName[serviceName]) {\n serviceImplementations[serviceName] = providedServicesByName[serviceName]!.service;\n }\n }\n }\n\n // Merge builder options with database adapter\n const mergedOptions = {\n ...builderConfig.options,\n databaseAdapter: adapter,\n };\n\n // Rebuild the fragment with service implementations using the builder\n const fragment = fragmentConfig.builder\n .withOptions(mergedOptions)\n .withServices(serviceImplementations as any) // eslint-disable-line @typescript-eslint/no-explicit-any\n .build();\n\n // Update the result\n // Access deps from the internal property\n const deps = fragment.$internal?.deps;\n\n fragmentResults[i] = {\n fragment,\n services: fragment.services,\n deps: deps || {},\n callRoute: fragment.callRoute.bind(fragment),\n get db() {\n return orm;\n },\n _orm: orm,\n _schema: schema,\n };\n }\n\n return fragmentResults;\n };\n\n const fragmentResults = createFragments();\n\n // Wrap resetDatabase to also recreate all fragments\n const originalResetDatabase = testContext.resetDatabase;\n const resetDatabase = async () => {\n await originalResetDatabase();\n\n // Recreate all fragments with service wiring\n const newFragmentResults = createFragments();\n\n // Update the result objects\n newFragmentResults.forEach((newResult, index) => {\n const result = fragmentResults[index]!;\n result.fragment = newResult.fragment;\n result.services = newResult.services;\n result.deps = newResult.deps;\n result.callRoute = newResult.callRoute;\n result._orm = newResult._orm;\n });\n };\n\n // Get the first fragment's inContext method\n const firstFragment = fragmentResults[0]?.fragment;\n if (!firstFragment) {\n throw new Error(\"At least one fragment must be added\");\n }\n\n const originalCleanup = testContext.cleanup;\n const cleanup = async () => {\n let drainError: unknown;\n let cleanupError: unknown;\n\n for (const result of fragmentResults) {\n try {\n await drainDurableHooks(result.fragment);\n } catch (error) {\n if (!drainError) {\n drainError = error;\n }\n }\n }\n\n try {\n await originalCleanup();\n } catch (error) {\n cleanupError = error;\n }\n\n if (drainError && cleanupError) {\n throw new AggregateError(\n [drainError, cleanupError],\n \"Failed to drain durable hooks and clean up test context\",\n );\n }\n\n if (drainError) {\n throw drainError;\n }\n\n if (cleanupError) {\n throw cleanupError;\n }\n };\n\n const finalTestContext = {\n ...testContext,\n resetDatabase,\n cleanup,\n adapter,\n inContext: firstFragment.inContext.bind(firstFragment),\n };\n\n // Build result object with named fragments\n const fragmentsObject = Object.fromEntries(\n fragmentNames.map((name, index) => [name, fragmentResults[index]]),\n );\n\n // Safe cast: We've already validated that adapterConfig is SupportedAdapter at the beginning of build()\n // TypeScript can't infer this through the conditional return type, so we use 'as any'\n return {\n fragments: fragmentsObject as TFragments,\n test: finalTestContext,\n } as any; // eslint-disable-line @typescript-eslint/no-explicit-any\n }\n}\n\n/**\n * Create a builder for setting up multiple database fragments for testing.\n * This is the new builder-based API that works with the new fragment instantiation builders.\n *\n * @example\n * ```typescript\n * const userFragmentDef = defineFragment(\"user\")\n * .extend(withDatabase(userSchema))\n * .withDependencies(...)\n * .build();\n *\n * const postFragmentDef = defineFragment(\"post\")\n * .extend(withDatabase(postSchema))\n * .withDependencies(...)\n * .build();\n *\n * const { fragments, test } = await buildDatabaseFragmentsTest()\n * .withTestAdapter({ type: \"kysely-sqlite\" })\n * .withFragment(\"user\",\n * instantiate(userFragmentDef)\n * .withConfig({ ... })\n * .withRoutes([...])\n * )\n * .withFragment(\"post\",\n * instantiate(postFragmentDef)\n * .withRoutes([...])\n * )\n * .build();\n *\n * // Access fragments by name\n * await fragments.user.services.createUser(...);\n * await fragments.post.services.createPost(...);\n *\n * // Access dependencies directly\n * const userDeps = fragments.user.deps;\n *\n * // Shared test context\n * await test.resetDatabase();\n * await test.cleanup();\n * const adapter = test.adapter; // Access the database adapter\n * ```\n */\nexport function buildDatabaseFragmentsTest(): DatabaseFragmentsTestBuilder<\n {},\n undefined,\n RequestThisContext\n> {\n return new DatabaseFragmentsTestBuilder();\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"db-test.js","names":["#adapter","#dbRoundtripGuard","#fragments","schemaConfigs: SchemaConfig[]","fragmentPlans: Array<{\n name: string;\n kind: \"builder\" | \"instance\" | \"factory\";\n schema: AnySchema;\n namespace: string | null;\n migrateToVersion?: number;\n builderConfig?: {\n builder: AnyFragmentBuilderConfig[\"builder\"];\n definition: AnyFragmentBuilderConfig[\"definition\"];\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n config: any;\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n routes: any;\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n options: any;\n };\n factory?: FragmentFactoryConfig[\"factory\"];\n cachedFactoryResult?: FragmentFactoryResult;\n fragment?: AnyFragnoInstantiatedFragment;\n }>","schema: AnySchema | undefined","namespace: string | null | undefined","providedServicesByName: Record<string, { service: any; orm: any }>","fragment: AnyFragnoInstantiatedFragment | undefined","fragmentResults: any[]","serviceImplementations: Record<string, any>","fragmentResults","drainError: unknown","cleanupError: unknown"],"sources":["../src/db-test.ts"],"sourcesContent":["import type { AnyRouteOrFactory, FlattenRouteFactories } from \"@fragno-dev/core/route\";\nimport type { SimpleQueryInterface } from \"@fragno-dev/db/query\";\nimport type { AnySchema } from \"@fragno-dev/db/schema\";\n\nimport type {\n RequestThisContext,\n FragnoPublicConfig,\n FragmentInstantiationBuilder,\n FragnoInstantiatedFragment,\n AnyFragnoInstantiatedFragment,\n FragmentDefinition,\n} from \"@fragno-dev/core\";\nimport type { DatabaseAdapter, FragnoPublicConfigWithDatabase } from \"@fragno-dev/db\";\n\nimport type { BaseTestContext } from \".\";\nimport {\n createAdapter,\n type SupportedAdapter,\n type AdapterContext,\n type SchemaConfig,\n} from \"./adapters\";\nimport { drainDurableHooks } from \"./durable-hooks\";\n\n// BoundServices is an internal type that strips 'this' parameters from service methods\n// It's used to represent services after they've been bound to a context\ntype BoundServices<T> = {\n [K in keyof T]: T[K] extends (this: any, ...args: infer A) => infer R // eslint-disable-line @typescript-eslint/no-explicit-any\n ? (...args: A) => R\n : T[K] extends Record<string, unknown>\n ? BoundServices<T[K]>\n : T[K];\n};\n\ntype FragmentFactoryContext = {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n adapter: DatabaseAdapter<any>;\n test: BaseTestContext & AdapterContext<SupportedAdapter>;\n};\n\nconst disableAutoSchedule = <TOptions extends FragnoPublicConfig>(options: TOptions) => {\n const durableHooks = (options as { durableHooks?: Record<string, unknown> }).durableHooks ?? {};\n return {\n ...options,\n durableHooks: {\n ...durableHooks,\n autoSchedule: false,\n },\n };\n};\n\ntype FragmentFactoryResult =\n | FragmentInstantiationBuilder<\n any, // eslint-disable-line @typescript-eslint/no-explicit-any\n any, // eslint-disable-line @typescript-eslint/no-explicit-any\n any, // eslint-disable-line @typescript-eslint/no-explicit-any\n any, // eslint-disable-line @typescript-eslint/no-explicit-any\n any, // eslint-disable-line @typescript-eslint/no-explicit-any\n any, // eslint-disable-line @typescript-eslint/no-explicit-any\n any, // eslint-disable-line @typescript-eslint/no-explicit-any\n any, // eslint-disable-line @typescript-eslint/no-explicit-any\n any, // eslint-disable-line @typescript-eslint/no-explicit-any\n any, // eslint-disable-line @typescript-eslint/no-explicit-any\n any, // eslint-disable-line @typescript-eslint/no-explicit-any\n any // eslint-disable-line @typescript-eslint/no-explicit-any\n >\n | FragnoInstantiatedFragment<\n any, // eslint-disable-line @typescript-eslint/no-explicit-any\n any, // eslint-disable-line @typescript-eslint/no-explicit-any\n any, // eslint-disable-line @typescript-eslint/no-explicit-any\n any, // eslint-disable-line @typescript-eslint/no-explicit-any\n any, // eslint-disable-line @typescript-eslint/no-explicit-any\n any, // eslint-disable-line @typescript-eslint/no-explicit-any\n any // eslint-disable-line @typescript-eslint/no-explicit-any\n >;\n\ntype HandlerThisContextFromFactoryResult<T> =\n T extends FragmentInstantiationBuilder<\n any, // eslint-disable-line @typescript-eslint/no-explicit-any\n any, // eslint-disable-line @typescript-eslint/no-explicit-any\n any, // eslint-disable-line @typescript-eslint/no-explicit-any\n any, // eslint-disable-line @typescript-eslint/no-explicit-any\n any, // eslint-disable-line @typescript-eslint/no-explicit-any\n any, // eslint-disable-line @typescript-eslint/no-explicit-any\n any, // eslint-disable-line @typescript-eslint/no-explicit-any\n any, // eslint-disable-line @typescript-eslint/no-explicit-any\n infer THandlerThisContext,\n any, // eslint-disable-line @typescript-eslint/no-explicit-any\n any, // eslint-disable-line @typescript-eslint/no-explicit-any\n any // eslint-disable-line @typescript-eslint/no-explicit-any\n >\n ? THandlerThisContext\n : T extends FragnoInstantiatedFragment<\n any, // eslint-disable-line @typescript-eslint/no-explicit-any\n any, // eslint-disable-line @typescript-eslint/no-explicit-any\n any, // eslint-disable-line @typescript-eslint/no-explicit-any\n any, // eslint-disable-line @typescript-eslint/no-explicit-any\n infer THandlerThisContext,\n any, // eslint-disable-line @typescript-eslint/no-explicit-any\n any // eslint-disable-line @typescript-eslint/no-explicit-any\n >\n ? THandlerThisContext\n : RequestThisContext;\n\ntype FragmentResultFromFactoryResult<T> =\n T extends FragmentInstantiationBuilder<\n any, // eslint-disable-line @typescript-eslint/no-explicit-any\n any, // eslint-disable-line @typescript-eslint/no-explicit-any\n infer TDeps,\n infer TBaseServices,\n infer TServices,\n any, // eslint-disable-line @typescript-eslint/no-explicit-any\n any, // eslint-disable-line @typescript-eslint/no-explicit-any\n infer TServiceThisContext,\n infer THandlerThisContext,\n infer TRequestStorage,\n infer TRoutesOrFactories,\n any // eslint-disable-line @typescript-eslint/no-explicit-any\n >\n ? FragmentResult<\n TDeps,\n BoundServices<TBaseServices & TServices>,\n TServiceThisContext,\n THandlerThisContext,\n TRequestStorage,\n FlattenRouteFactories<TRoutesOrFactories>,\n ExtractSchemaFromDeps<TDeps>\n >\n : T extends FragnoInstantiatedFragment<\n infer TRoutes,\n infer TDeps,\n infer TServices,\n infer TServiceThisContext,\n infer THandlerThisContext,\n infer TRequestStorage,\n any // eslint-disable-line @typescript-eslint/no-explicit-any\n >\n ? FragmentResult<\n TDeps,\n BoundServices<TServices>,\n TServiceThisContext,\n THandlerThisContext,\n TRequestStorage,\n TRoutes,\n ExtractSchemaFromDeps<TDeps>\n >\n : never;\n\n// Extract the schema type from database fragment dependencies\n// Database fragments have ImplicitDatabaseDependencies<TSchema> which includes `schema: TSchema`\ntype ExtractSchemaFromDeps<TDeps> = TDeps extends { schema: infer TSchema extends AnySchema }\n ? TSchema\n : AnySchema;\n\n// Forward declarations for recursive type references\ninterface FragmentResult<\n TDeps,\n TServices extends Record<string, unknown>,\n TServiceThisContext extends RequestThisContext,\n THandlerThisContext extends RequestThisContext,\n TRequestStorage,\n TRoutes extends readonly any[], // eslint-disable-line @typescript-eslint/no-explicit-any\n TSchema extends AnySchema,\n> {\n fragment: FragnoInstantiatedFragment<\n TRoutes,\n TDeps,\n TServices,\n TServiceThisContext,\n THandlerThisContext,\n TRequestStorage,\n FragnoPublicConfig\n >;\n services: TServices;\n deps: TDeps;\n callRoute: FragnoInstantiatedFragment<\n TRoutes,\n TDeps,\n TServices,\n TServiceThisContext,\n THandlerThisContext,\n TRequestStorage,\n FragnoPublicConfig\n >[\"callRoute\"];\n db: SimpleQueryInterface<TSchema>;\n}\n\n// Safe: Catch-all for any fragment result type\nexport type AnyFragmentResult = FragmentResult<\n any, // eslint-disable-line @typescript-eslint/no-explicit-any\n any, // eslint-disable-line @typescript-eslint/no-explicit-any\n any, // eslint-disable-line @typescript-eslint/no-explicit-any\n any, // eslint-disable-line @typescript-eslint/no-explicit-any\n any, // eslint-disable-line @typescript-eslint/no-explicit-any\n any, // eslint-disable-line @typescript-eslint/no-explicit-any\n any // eslint-disable-line @typescript-eslint/no-explicit-any\n>;\n\n// Safe: Catch-all for any fragment builder config type\ntype AnyFragmentBuilderConfig = FragmentBuilderConfig<\n any, // eslint-disable-line @typescript-eslint/no-explicit-any\n any, // eslint-disable-line @typescript-eslint/no-explicit-any\n any, // eslint-disable-line @typescript-eslint/no-explicit-any\n any, // eslint-disable-line @typescript-eslint/no-explicit-any\n any, // eslint-disable-line @typescript-eslint/no-explicit-any\n any, // eslint-disable-line @typescript-eslint/no-explicit-any\n any, // eslint-disable-line @typescript-eslint/no-explicit-any\n any, // eslint-disable-line @typescript-eslint/no-explicit-any\n any, // eslint-disable-line @typescript-eslint/no-explicit-any\n any, // eslint-disable-line @typescript-eslint/no-explicit-any\n any, // eslint-disable-line @typescript-eslint/no-explicit-any\n any // eslint-disable-line @typescript-eslint/no-explicit-any\n>;\n\n/**\n * Configuration for a single fragment in the test builder\n */\ninterface FragmentBuilderConfig<\n TConfig,\n TOptions extends FragnoPublicConfig,\n TDeps,\n TBaseServices extends Record<string, unknown>,\n TServices extends Record<string, unknown>,\n TServiceDependencies,\n TPrivateServices extends Record<string, unknown>,\n TServiceThisContext extends RequestThisContext,\n THandlerThisContext extends RequestThisContext,\n TRequestStorage,\n TRoutesOrFactories extends readonly AnyRouteOrFactory[],\n TInternalRoutes extends readonly AnyRouteOrFactory[],\n> {\n kind: \"builder\";\n definition: FragmentDefinition<\n TConfig,\n TOptions,\n TDeps,\n TBaseServices,\n TServices,\n TServiceDependencies,\n TPrivateServices,\n TServiceThisContext,\n THandlerThisContext,\n TRequestStorage,\n TInternalRoutes\n >;\n builder: FragmentInstantiationBuilder<\n TConfig,\n TOptions,\n TDeps,\n TBaseServices,\n TServices,\n TServiceDependencies,\n TPrivateServices,\n TServiceThisContext,\n THandlerThisContext,\n TRequestStorage,\n TRoutesOrFactories,\n TInternalRoutes\n >;\n migrateToVersion?: number;\n}\n\n/**\n * Configuration for a pre-built fragment instance\n */\ninterface FragmentInstanceConfig<\n TDeps,\n TServices extends Record<string, unknown>,\n TServiceThisContext extends RequestThisContext,\n THandlerThisContext extends RequestThisContext,\n TRequestStorage,\n TRoutes extends readonly any[], // eslint-disable-line @typescript-eslint/no-explicit-any\n> {\n kind: \"instance\";\n fragment: FragnoInstantiatedFragment<\n TRoutes,\n TDeps,\n TServices,\n TServiceThisContext,\n THandlerThisContext,\n TRequestStorage,\n FragnoPublicConfig\n >;\n migrateToVersion?: number;\n}\n\n/**\n * Configuration for a fragment factory\n */\ninterface FragmentFactoryConfig {\n kind: \"factory\";\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n definition: FragmentDefinition<any, any, any, any, any, any, any, any, any, any, any>;\n factory: (context: FragmentFactoryContext) => FragmentFactoryResult;\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n config?: any;\n migrateToVersion?: number;\n}\n\n/**\n * Test context combining base and adapter-specific functionality\n */\ntype TestContext<\n T extends SupportedAdapter,\n TFirstFragmentThisContext extends RequestThisContext = RequestThisContext,\n> = BaseTestContext &\n AdapterContext<T> & {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n adapter: DatabaseAdapter<any>;\n /**\n * Execute a callback within the first fragment's request context.\n * This is useful for calling services outside of route handlers in tests.\n */\n inContext<TResult>(callback: (this: TFirstFragmentThisContext) => TResult): TResult;\n inContext<TResult>(\n callback: (this: TFirstFragmentThisContext) => Promise<TResult>,\n ): Promise<TResult>;\n };\n\n/**\n * Result of building the database fragments test\n */\ninterface DatabaseFragmentsTestResult<\n TFragments extends Record<string, AnyFragmentResult>,\n TAdapter extends SupportedAdapter,\n TFirstFragmentThisContext extends RequestThisContext = RequestThisContext,\n> {\n fragments: TFragments;\n test: TestContext<TAdapter, TFirstFragmentThisContext>;\n}\n\n/**\n * Internal storage for fragment configurations\n */\ntype AnyFragmentInstanceConfig = FragmentInstanceConfig<\n any, // eslint-disable-line @typescript-eslint/no-explicit-any\n any, // eslint-disable-line @typescript-eslint/no-explicit-any\n any, // eslint-disable-line @typescript-eslint/no-explicit-any\n any, // eslint-disable-line @typescript-eslint/no-explicit-any\n any, // eslint-disable-line @typescript-eslint/no-explicit-any\n any // eslint-disable-line @typescript-eslint/no-explicit-any\n>;\n\ntype AnyFragmentFactoryConfig = FragmentFactoryConfig;\n\ntype AnyFragmentConfig =\n | AnyFragmentBuilderConfig\n | AnyFragmentInstanceConfig\n | AnyFragmentFactoryConfig;\n\ntype FragmentConfigMap = Map<string, AnyFragmentConfig>;\n\n/**\n * Builder for creating multiple database fragments for testing\n */\nexport class DatabaseFragmentsTestBuilder<\n TFragments extends Record<string, AnyFragmentResult>,\n TAdapter extends SupportedAdapter | undefined = undefined,\n TFirstFragmentThisContext extends RequestThisContext = RequestThisContext,\n> {\n #adapter?: SupportedAdapter;\n #fragments: FragmentConfigMap = new Map();\n #dbRoundtripGuard?: FragnoPublicConfigWithDatabase[\"dbRoundtripGuard\"] = true;\n\n /**\n * Set the test adapter configuration\n */\n withTestAdapter<TNewAdapter extends SupportedAdapter>(\n adapter: TNewAdapter,\n ): DatabaseFragmentsTestBuilder<TFragments, TNewAdapter, TFirstFragmentThisContext> {\n this.#adapter = adapter;\n return this as any; // eslint-disable-line @typescript-eslint/no-explicit-any\n }\n\n /**\n * Opt out of the default roundtrip guard (enabled by default), or override its configuration.\n * Useful for allowing multi-roundtrip routes in tests.\n */\n withDbRoundtripGuard(\n guard: FragnoPublicConfigWithDatabase[\"dbRoundtripGuard\"] = false,\n ): DatabaseFragmentsTestBuilder<TFragments, TAdapter, TFirstFragmentThisContext> {\n this.#dbRoundtripGuard = guard;\n return this;\n }\n\n /**\n * Add a fragment to the test setup\n *\n * @param name - Unique name for the fragment\n * @param builder - Pre-configured instantiation builder\n * @param options - Additional options (optional)\n */\n withFragment<\n TName extends string,\n TConfig,\n TOptions extends FragnoPublicConfig,\n TDeps,\n TBaseServices extends Record<string, unknown>,\n TServices extends Record<string, unknown>,\n TServiceDependencies,\n TPrivateServices extends Record<string, unknown>,\n TServiceThisContext extends RequestThisContext,\n THandlerThisContext extends RequestThisContext,\n TRequestStorage,\n TRoutesOrFactories extends readonly AnyRouteOrFactory[],\n TInternalRoutes extends readonly AnyRouteOrFactory[],\n >(\n name: TName,\n builder: FragmentInstantiationBuilder<\n TConfig,\n TOptions,\n TDeps,\n TBaseServices,\n TServices,\n TServiceDependencies,\n TPrivateServices,\n TServiceThisContext,\n THandlerThisContext,\n TRequestStorage,\n TRoutesOrFactories,\n TInternalRoutes\n >,\n options?: {\n migrateToVersion?: number;\n },\n ): DatabaseFragmentsTestBuilder<\n TFragments & {\n [K in TName]: FragmentResult<\n TDeps,\n BoundServices<TBaseServices & TServices>,\n TServiceThisContext,\n THandlerThisContext,\n TRequestStorage,\n FlattenRouteFactories<TRoutesOrFactories>,\n ExtractSchemaFromDeps<TDeps> // Extract actual schema type from deps\n >;\n },\n TAdapter,\n // If this is the first fragment (TFragments is empty {}), use THandlerThisContext; otherwise keep existing\n keyof TFragments extends never ? THandlerThisContext : TFirstFragmentThisContext\n > {\n this.#fragments.set(name, {\n kind: \"builder\",\n definition: builder.definition,\n builder,\n migrateToVersion: options?.migrateToVersion,\n });\n return this as any; // eslint-disable-line @typescript-eslint/no-explicit-any\n }\n\n /**\n * Add a pre-built fragment instance to the test setup\n *\n * @param name - Unique name for the fragment\n * @param fragment - Already-built fragment instance\n */\n withFragmentInstance<\n TName extends string,\n TRoutes extends readonly any[], // eslint-disable-line @typescript-eslint/no-explicit-any\n TDeps,\n TServices extends Record<string, unknown>,\n TServiceThisContext extends RequestThisContext,\n THandlerThisContext extends RequestThisContext,\n TRequestStorage,\n >(\n name: TName,\n fragment: FragnoInstantiatedFragment<\n TRoutes,\n TDeps,\n TServices,\n TServiceThisContext,\n THandlerThisContext,\n TRequestStorage,\n FragnoPublicConfig\n >,\n options?: { migrateToVersion?: number },\n ): DatabaseFragmentsTestBuilder<\n TFragments & {\n [K in TName]: FragmentResult<\n TDeps,\n BoundServices<TServices>,\n TServiceThisContext,\n THandlerThisContext,\n TRequestStorage,\n TRoutes,\n ExtractSchemaFromDeps<TDeps>\n >;\n },\n TAdapter,\n keyof TFragments extends never ? THandlerThisContext : TFirstFragmentThisContext\n > {\n this.#fragments.set(name, {\n kind: \"instance\",\n fragment,\n migrateToVersion: options?.migrateToVersion,\n });\n\n return this as any; // eslint-disable-line @typescript-eslint/no-explicit-any\n }\n\n /**\n * Add a fragment factory to the test setup.\n * The factory runs after the adapter is created.\n *\n * @param name - Unique name for the fragment\n * @param definition - Fragment definition (used to extract schema/namespace)\n * @param factory - Factory that returns a builder or a pre-built fragment\n */\n withFragmentFactory<TName extends string, TFactoryResult extends FragmentFactoryResult>(\n name: TName,\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n definition: FragmentDefinition<any, any, any, any, any, any, any, any, any, any, any>,\n factory: (context: FragmentFactoryContext) => TFactoryResult,\n options?: {\n migrateToVersion?: number;\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n config?: any;\n },\n ): DatabaseFragmentsTestBuilder<\n TFragments & {\n [K in TName]: FragmentResultFromFactoryResult<TFactoryResult>;\n },\n TAdapter,\n keyof TFragments extends never\n ? HandlerThisContextFromFactoryResult<TFactoryResult>\n : TFirstFragmentThisContext\n > {\n this.#fragments.set(name, {\n kind: \"factory\",\n definition,\n factory,\n config: options?.config,\n migrateToVersion: options?.migrateToVersion,\n });\n\n return this as any; // eslint-disable-line @typescript-eslint/no-explicit-any\n }\n\n /**\n * Build the test setup and return fragments and test context\n */\n async build(): Promise<\n TAdapter extends SupportedAdapter\n ? DatabaseFragmentsTestResult<TFragments, TAdapter, TFirstFragmentThisContext>\n : never\n > {\n if (!this.#adapter) {\n throw new Error(\"Test adapter must be set using withTestAdapter()\");\n }\n\n if (this.#fragments.size === 0) {\n throw new Error(\n \"At least one fragment must be added using withFragment(), withFragmentFactory(), or withFragmentInstance().\",\n );\n }\n\n const adapterConfig = this.#adapter;\n\n // Extract fragment names and configs\n const fragmentEntries = Array.from(this.#fragments.entries());\n const fragmentNames = fragmentEntries.map(([name]) => name);\n\n // Extract schemas from definitions and prepare schema configs\n const schemaConfigs: SchemaConfig[] = [];\n const fragmentPlans: Array<{\n name: string;\n kind: \"builder\" | \"instance\" | \"factory\";\n schema: AnySchema;\n namespace: string | null;\n migrateToVersion?: number;\n builderConfig?: {\n builder: AnyFragmentBuilderConfig[\"builder\"];\n definition: AnyFragmentBuilderConfig[\"definition\"];\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n config: any;\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n routes: any;\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n options: any;\n };\n factory?: FragmentFactoryConfig[\"factory\"];\n cachedFactoryResult?: FragmentFactoryResult;\n fragment?: AnyFragnoInstantiatedFragment;\n }> = [];\n\n const extractSchemaFromDefinition = (\n definition: FragmentDefinition<any, any, any, any, any, any, any, any, any, any, any>, // eslint-disable-line @typescript-eslint/no-explicit-any\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n actualConfig: any,\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n actualOptions?: any,\n ) => {\n let schema: AnySchema | undefined;\n let namespace: string | null | undefined;\n\n if (definition.dependencies) {\n try {\n // Create a mock adapter to extract the schema\n const mockAdapter = {\n createQueryEngine: () => ({ schema: null }),\n getSchemaVersion: async () => undefined,\n namingStrategy: {\n namespaceScope: \"suffix\",\n namespaceToSchema: (value: string) => value,\n tableName: (logicalTable: string, ns: string | null) =>\n ns ? `${logicalTable}_${ns}` : logicalTable,\n columnName: (logicalColumn: string) => logicalColumn,\n indexName: (logicalIndex: string) => logicalIndex,\n uniqueIndexName: (logicalIndex: string) => logicalIndex,\n foreignKeyName: ({ referenceName }: { referenceName: string }) => referenceName,\n },\n contextStorage: { run: (_data: unknown, fn: () => unknown) => fn() },\n close: async () => {},\n };\n\n const deps = definition.dependencies({\n config: actualConfig ?? {},\n options: {\n ...actualOptions,\n databaseAdapter: mockAdapter as any, // eslint-disable-line @typescript-eslint/no-explicit-any\n } as any, // eslint-disable-line @typescript-eslint/no-explicit-any\n });\n\n if (deps && typeof deps === \"object\" && \"schema\" in deps) {\n schema = (deps as any).schema; // eslint-disable-line @typescript-eslint/no-explicit-any\n namespace = (deps as any).namespace; // eslint-disable-line @typescript-eslint/no-explicit-any\n }\n } catch (error) {\n const errorMessage =\n error instanceof Error\n ? error.message\n : typeof error === \"string\"\n ? error\n : \"Unknown error\";\n\n throw new Error(\n `Failed to extract schema from fragment '${definition.name}'.\\n` +\n `Original error: ${errorMessage}\\n\\n` +\n `Make sure the fragment is a database fragment using defineFragment().extend(withDatabase(schema)).`,\n );\n }\n }\n\n if (!schema) {\n throw new Error(\n `Fragment '${definition.name}' does not have a database schema. ` +\n `Make sure you're using defineFragment().extend(withDatabase(schema)).`,\n );\n }\n\n if (namespace === undefined) {\n throw new Error(\n `Fragment '${definition.name}' does not have a namespace in dependencies. ` +\n `This should be automatically provided by withDatabase().`,\n );\n }\n\n return { schema, namespace };\n };\n\n for (const [name, fragmentConfig] of fragmentEntries) {\n if (fragmentConfig.kind === \"builder\") {\n const builder = fragmentConfig.builder;\n const definition = builder.definition;\n const { schema, namespace } = extractSchemaFromDefinition(\n definition,\n builder.config ?? {},\n builder.options ?? {},\n );\n\n schemaConfigs.push({\n schema,\n namespace,\n migrateToVersion: fragmentConfig.migrateToVersion,\n });\n\n fragmentPlans.push({\n name,\n kind: \"builder\",\n schema,\n namespace,\n migrateToVersion: fragmentConfig.migrateToVersion,\n builderConfig: {\n builder: fragmentConfig.builder,\n definition: fragmentConfig.definition,\n config: builder.config ?? {},\n routes: builder.routes ?? [],\n options: builder.options ?? {},\n },\n });\n continue;\n }\n\n if (fragmentConfig.kind === \"factory\") {\n const definition = fragmentConfig.definition;\n const { schema, namespace } = extractSchemaFromDefinition(\n definition,\n fragmentConfig.config ?? {},\n );\n\n schemaConfigs.push({\n schema,\n namespace,\n migrateToVersion: fragmentConfig.migrateToVersion,\n });\n\n fragmentPlans.push({\n name,\n kind: \"factory\",\n schema,\n namespace,\n migrateToVersion: fragmentConfig.migrateToVersion,\n factory: fragmentConfig.factory,\n });\n\n continue;\n }\n\n const fragment = fragmentConfig.fragment;\n const deps = fragment.$internal?.deps as\n | {\n schema?: AnySchema;\n namespace?: string | null;\n }\n | undefined;\n\n if (!deps?.schema) {\n throw new Error(\n `Fragment '${name}' does not have a database schema in deps. ` +\n `Make sure you're using defineFragment().extend(withDatabase(schema)).`,\n );\n }\n\n schemaConfigs.push({\n schema: deps.schema,\n namespace: deps.namespace ?? null,\n migrateToVersion: fragmentConfig.migrateToVersion,\n });\n\n fragmentPlans.push({\n name,\n kind: \"instance\",\n schema: deps.schema,\n namespace: deps.namespace ?? null,\n migrateToVersion: fragmentConfig.migrateToVersion,\n fragment,\n });\n }\n\n const { testContext, adapter } = await createAdapter(adapterConfig, schemaConfigs);\n\n const resolveDbRoundtripGuardOption = (options: unknown) => {\n if (options && typeof options === \"object\") {\n if (Object.prototype.hasOwnProperty.call(options, \"dbRoundtripGuard\")) {\n return (options as { dbRoundtripGuard?: unknown }).dbRoundtripGuard as\n | FragnoPublicConfigWithDatabase[\"dbRoundtripGuard\"]\n | undefined;\n }\n }\n return this.#dbRoundtripGuard;\n };\n\n const mergeBuilderOptions = (options: unknown) => {\n const resolvedOptions = disableAutoSchedule((options ?? {}) as FragnoPublicConfig);\n const resolvedOptionsRecord = resolvedOptions as unknown as Record<string, unknown>;\n const merged = {\n ...resolvedOptionsRecord,\n databaseAdapter: adapter,\n } as Record<string, unknown>;\n const guardOption = resolveDbRoundtripGuardOption(resolvedOptions);\n if (guardOption !== undefined) {\n merged[\"dbRoundtripGuard\"] = guardOption;\n }\n return merged;\n };\n\n // Helper to create fragments with service wiring\n const createFragments = () => {\n const resolveBuilderConfig = (builder: AnyFragmentBuilderConfig[\"builder\"]) => ({\n builder,\n definition: builder.definition,\n config: builder.config ?? {},\n routes: builder.routes ?? [],\n options: builder.options ?? {},\n });\n\n const isBuilder = (\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n value: any,\n ): value is AnyFragmentBuilderConfig[\"builder\"] =>\n Boolean(value) && typeof value === \"object\" && \"build\" in value && \"definition\" in value;\n\n // First pass: create fragments without service dependencies to extract provided services\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const providedServicesByName: Record<string, { service: any; orm: any }> = {};\n const instanceResults = new Map<string, any>(); // eslint-disable-line @typescript-eslint/no-explicit-any\n const builderConfigs = new Map<string, ReturnType<typeof resolveBuilderConfig>>();\n\n for (const plan of fragmentPlans) {\n const orm = testContext.getOrm(plan.namespace);\n let fragment: AnyFragnoInstantiatedFragment | undefined;\n let builderConfig = plan.builderConfig;\n\n if (plan.kind === \"factory\") {\n const result =\n plan.cachedFactoryResult ??\n plan.factory!({\n adapter,\n test: testContext,\n });\n\n if (!plan.cachedFactoryResult) {\n plan.cachedFactoryResult = result;\n }\n\n if (isBuilder(result)) {\n builderConfig = resolveBuilderConfig(result);\n } else {\n fragment = result;\n }\n }\n\n const usesBuilder = plan.kind === \"builder\" || !!builderConfig;\n\n if (usesBuilder) {\n const resolvedBuilderConfig = builderConfig ?? plan.builderConfig!;\n const mergedOptions = mergeBuilderOptions(resolvedBuilderConfig.options);\n\n fragment = resolvedBuilderConfig.builder.withOptions(mergedOptions).build();\n builderConfigs.set(plan.name, resolvedBuilderConfig);\n } else {\n fragment = fragment ?? plan.fragment!;\n\n const deps = fragment.$internal?.deps as\n | { databaseAdapter?: DatabaseAdapter<unknown> }\n | undefined;\n if (deps?.databaseAdapter && deps.databaseAdapter !== adapter) {\n throw new Error(\n `Fragment '${plan.name}' was built with a different database adapter instance. ` +\n `Use withFragment() or ensure the fragment uses the same adapter instance as the test builder.`,\n );\n }\n }\n\n if (!fragment) {\n throw new Error(\n `Fragment '${plan.name}' did not return a valid fragment instance from its factory.`,\n );\n }\n\n for (const [serviceName, serviceImpl] of Object.entries(fragment.services)) {\n providedServicesByName[serviceName] = {\n service: serviceImpl,\n orm,\n };\n }\n\n if (!usesBuilder) {\n const deps = fragment.$internal?.deps;\n instanceResults.set(plan.name, {\n fragment,\n services: fragment.services,\n deps: deps || {},\n callRoute: fragment.callRoute.bind(fragment),\n get db() {\n return orm;\n },\n _orm: orm,\n _schema: plan.schema,\n });\n }\n }\n\n // Second pass: rebuild fragments with service dependencies wired up\n const fragmentResults: any[] = []; // eslint-disable-line @typescript-eslint/no-explicit-any\n\n for (const plan of fragmentPlans) {\n const orm = testContext.getOrm(plan.namespace);\n\n if (instanceResults.has(plan.name)) {\n fragmentResults.push(instanceResults.get(plan.name));\n continue;\n }\n\n const builderConfig = builderConfigs.get(plan.name);\n if (!builderConfig) {\n throw new Error(\n `Fragment '${plan.name}' was expected to produce a builder for service wiring.`,\n );\n }\n const definition = builderConfig.definition;\n\n // Build service implementations for services this fragment uses\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const serviceImplementations: Record<string, any> = {};\n const serviceDependencies = definition.serviceDependencies;\n\n if (serviceDependencies) {\n for (const serviceName of Object.keys(serviceDependencies)) {\n if (providedServicesByName[serviceName]) {\n serviceImplementations[serviceName] = providedServicesByName[serviceName]!.service;\n }\n }\n }\n\n // Merge builder options with database adapter\n const mergedOptions = mergeBuilderOptions(builderConfig.options);\n\n // Rebuild the fragment with service implementations using the builder\n const fragment = builderConfig.builder\n .withOptions(mergedOptions)\n .withServices(serviceImplementations as any) // eslint-disable-line @typescript-eslint/no-explicit-any\n .build();\n\n const deps = fragment.$internal?.deps;\n\n fragmentResults.push({\n fragment,\n services: fragment.services,\n deps: deps || {},\n callRoute: fragment.callRoute.bind(fragment),\n get db() {\n return orm;\n },\n _orm: orm,\n _schema: plan.schema,\n });\n }\n\n return fragmentResults;\n };\n\n const fragmentResults = createFragments();\n\n // Wrap resetDatabase to also recreate all fragments\n const originalResetDatabase = testContext.resetDatabase;\n const resetDatabase = async () => {\n await originalResetDatabase();\n\n // Recreate all fragments with service wiring\n const newFragmentResults = createFragments();\n\n // Update the result objects\n newFragmentResults.forEach((newResult, index) => {\n const result = fragmentResults[index]!;\n result.fragment = newResult.fragment;\n result.services = newResult.services;\n result.deps = newResult.deps;\n result.callRoute = newResult.callRoute;\n result._orm = newResult._orm;\n });\n };\n\n // Get the first fragment's inContext method\n const firstFragment = fragmentResults[0]?.fragment;\n if (!firstFragment) {\n throw new Error(\"At least one fragment must be added\");\n }\n\n const originalCleanup = testContext.cleanup;\n const cleanup = async () => {\n let drainError: unknown;\n let cleanupError: unknown;\n\n for (const result of fragmentResults) {\n try {\n await drainDurableHooks(result.fragment);\n } catch (error) {\n if (!drainError) {\n drainError = error;\n }\n }\n }\n\n try {\n await originalCleanup();\n } catch (error) {\n cleanupError = error;\n }\n\n if (drainError && cleanupError) {\n throw new AggregateError(\n [drainError, cleanupError],\n \"Failed to drain durable hooks and clean up test context\",\n );\n }\n\n if (drainError) {\n throw drainError;\n }\n\n if (cleanupError) {\n throw cleanupError;\n }\n };\n\n const finalTestContext = {\n ...testContext,\n resetDatabase,\n cleanup,\n adapter,\n inContext: firstFragment.inContext.bind(firstFragment),\n };\n\n // Build result object with named fragments\n const fragmentsObject = Object.fromEntries(\n fragmentNames.map((name, index) => [name, fragmentResults[index]]),\n );\n\n // Safe cast: We've already validated that adapterConfig is SupportedAdapter at the beginning of build()\n // TypeScript can't infer this through the conditional return type, so we use 'as any'\n return {\n fragments: fragmentsObject as TFragments,\n test: finalTestContext,\n } as any; // eslint-disable-line @typescript-eslint/no-explicit-any\n }\n}\n\n/**\n * Create a builder for setting up multiple database fragments for testing.\n * This is the new builder-based API that works with the new fragment instantiation builders.\n *\n * @example\n * ```typescript\n * const userFragmentDef = defineFragment(\"user\")\n * .extend(withDatabase(userSchema))\n * .withDependencies(...)\n * .build();\n *\n * const postFragmentDef = defineFragment(\"post\")\n * .extend(withDatabase(postSchema))\n * .withDependencies(...)\n * .build();\n *\n * const { fragments, test } = await buildDatabaseFragmentsTest()\n * .withTestAdapter({ type: \"kysely-sqlite\" })\n * .withFragment(\"user\",\n * instantiate(userFragmentDef)\n * .withConfig({ ... })\n * .withRoutes([...])\n * )\n * .withFragment(\"post\",\n * instantiate(postFragmentDef)\n * .withRoutes([...])\n * )\n * .build();\n *\n * // Access fragments by name\n * await fragments.user.services.createUser(...);\n * await fragments.post.services.createPost(...);\n *\n * // Access dependencies directly\n * const userDeps = fragments.user.deps;\n *\n * // Shared test context\n * await test.resetDatabase();\n * await test.cleanup();\n * const adapter = test.adapter; // Access the database adapter\n * ```\n */\nexport function buildDatabaseFragmentsTest(): DatabaseFragmentsTestBuilder<\n {},\n undefined,\n RequestThisContext\n> {\n return new DatabaseFragmentsTestBuilder();\n}\n"],"mappings":"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"}
|
package/dist/durable-hooks.d.ts
CHANGED
|
@@ -1,7 +1,11 @@
|
|
|
1
1
|
import { AnyFragnoInstantiatedFragment } from "@fragno-dev/core";
|
|
2
2
|
|
|
3
3
|
//#region src/durable-hooks.d.ts
|
|
4
|
-
|
|
4
|
+
type DrainDurableHooksMode = "untilIdle" | "singlePass";
|
|
5
|
+
type DrainDurableHooksOptions = {
|
|
6
|
+
mode?: DrainDurableHooksMode;
|
|
7
|
+
};
|
|
8
|
+
declare function drainDurableHooks(fragment: AnyFragnoInstantiatedFragment, options?: DrainDurableHooksOptions): Promise<void>;
|
|
5
9
|
//#endregion
|
|
6
|
-
export { drainDurableHooks };
|
|
10
|
+
export { DrainDurableHooksMode, DrainDurableHooksOptions, drainDurableHooks };
|
|
7
11
|
//# sourceMappingURL=durable-hooks.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"durable-hooks.d.ts","names":[],"sources":["../src/durable-hooks.ts"],"sourcesContent":[],"mappings":";;;
|
|
1
|
+
{"version":3,"file":"durable-hooks.d.ts","names":[],"sources":["../src/durable-hooks.ts"],"sourcesContent":[],"mappings":";;;KAKY,qBAAA;KAEA,wBAAA;EAFA,IAAA,CAAA,EAGH,qBAHwB;AAEjC,CAAA;AAIsB,iBAAA,iBAAA,CAAiB,QAAA,EAC3B,6BAD2B,EAAA,OAAA,CAAA,EAE5B,wBAF4B,CAAA,EAGpC,OAHoC,CAAA,IAAA,CAAA"}
|
package/dist/durable-hooks.js
CHANGED
|
@@ -1,10 +1,15 @@
|
|
|
1
|
-
import { createDurableHooksProcessor } from "@fragno-dev/db";
|
|
1
|
+
import { createDurableHooksProcessor } from "@fragno-dev/db/dispatchers/node";
|
|
2
|
+
import "@fragno-dev/db";
|
|
2
3
|
|
|
3
4
|
//#region src/durable-hooks.ts
|
|
4
|
-
async function drainDurableHooks(fragment) {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
5
|
+
async function drainDurableHooks(fragment, options = {}) {
|
|
6
|
+
if (!fragment.$internal?.durableHooksToken) return;
|
|
7
|
+
const dispatcher = createDurableHooksProcessor([fragment]);
|
|
8
|
+
if (options.mode === "singlePass") {
|
|
9
|
+
await dispatcher.wake();
|
|
10
|
+
return;
|
|
11
|
+
}
|
|
12
|
+
await dispatcher.drain();
|
|
8
13
|
}
|
|
9
14
|
|
|
10
15
|
//#endregion
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"durable-hooks.js","names":[],"sources":["../src/durable-hooks.ts"],"sourcesContent":["import {
|
|
1
|
+
{"version":3,"file":"durable-hooks.js","names":[],"sources":["../src/durable-hooks.ts"],"sourcesContent":["import { createDurableHooksProcessor } from \"@fragno-dev/db/dispatchers/node\";\n\nimport type { AnyFragnoInstantiatedFragment } from \"@fragno-dev/core\";\nimport { type AnyFragnoInstantiatedDatabaseFragment } from \"@fragno-dev/db\";\n\nexport type DrainDurableHooksMode = \"untilIdle\" | \"singlePass\";\n\nexport type DrainDurableHooksOptions = {\n mode?: DrainDurableHooksMode;\n};\n\nexport async function drainDurableHooks(\n fragment: AnyFragnoInstantiatedFragment,\n options: DrainDurableHooksOptions = {},\n): Promise<void> {\n const internal = fragment.$internal as { durableHooksToken?: object } | undefined;\n if (!internal?.durableHooksToken) {\n return;\n }\n const dispatcher = createDurableHooksProcessor([\n fragment as AnyFragnoInstantiatedDatabaseFragment,\n ]);\n if (options.mode === \"singlePass\") {\n await dispatcher.wake();\n return;\n }\n await dispatcher.drain();\n}\n"],"mappings":";;;;AAWA,eAAsB,kBACpB,UACA,UAAoC,EAAE,EACvB;AAEf,KAAI,CADa,SAAS,WACX,kBACb;CAEF,MAAM,aAAa,4BAA4B,CAC7C,SACD,CAAC;AACF,KAAI,QAAQ,SAAS,cAAc;AACjC,QAAM,WAAW,MAAM;AACvB;;AAEF,OAAM,WAAW,OAAO"}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { AdapterContext, DrizzlePgliteAdapter, InMemoryAdapterConfig, KyselyPgliteAdapter, KyselySqliteAdapter, SupportedAdapter } from "./adapters.js";
|
|
2
|
-
import { DatabaseFragmentsTestBuilder, buildDatabaseFragmentsTest } from "./db-test.js";
|
|
3
|
-
import { drainDurableHooks } from "./durable-hooks.js";
|
|
2
|
+
import { AnyFragmentResult, DatabaseFragmentsTestBuilder, buildDatabaseFragmentsTest } from "./db-test.js";
|
|
3
|
+
import { DrainDurableHooksMode, DrainDurableHooksOptions, drainDurableHooks } from "./durable-hooks.js";
|
|
4
4
|
import { ModelCheckerBounds, ModelCheckerConfig, ModelCheckerMode, ModelCheckerRunResult, ModelCheckerScheduleResult, ModelCheckerStep, ModelCheckerTrace, ModelCheckerTraceEvent, ModelCheckerTraceHashMode, ModelCheckerTraceHasher, ModelCheckerTraceRecorder, NormalizedMutationOperation, RawUowMutateContext, RawUowTransaction, RawUowTransactionBuilder, RawUowTransactionContext, createRawUowTransaction, defaultStateHasher, defaultTraceHasher, runModelChecker } from "./model-checker.js";
|
|
5
5
|
import { ModelCheckerAdapter, ModelCheckerScheduler } from "./model-checker-adapter.js";
|
|
6
6
|
import { ModelCheckerActor, ModelCheckerActorsConfig, ModelCheckerInvariant, ModelCheckerInvariantContext, runModelCheckerWithActors } from "./model-checker-actors.js";
|
|
@@ -35,5 +35,5 @@ declare function createCommonTestContextMethods(ormMap: Map<string | null, Simpl
|
|
|
35
35
|
*/
|
|
36
36
|
type TestContext<T extends SupportedAdapter> = BaseTestContext & AdapterContext<T>;
|
|
37
37
|
//#endregion
|
|
38
|
-
export { type AdapterContext, BaseTestContext, type CreateFragmentForTestOptions, DatabaseFragmentsTestBuilder, type DrizzlePgliteAdapter, type InMemoryAdapterConfig, InternalTestContextMethods, type KyselyPgliteAdapter, type KyselySqliteAdapter, type ModelCheckerActor, type ModelCheckerActorsConfig, ModelCheckerAdapter, type ModelCheckerBounds, type ModelCheckerConfig, type ModelCheckerInvariant, type ModelCheckerInvariantContext, type ModelCheckerMode, type ModelCheckerRunResult, type ModelCheckerScheduleResult, type ModelCheckerScheduler, type ModelCheckerStep, type ModelCheckerTrace, type ModelCheckerTraceEvent, type ModelCheckerTraceHashMode, type ModelCheckerTraceHasher, type ModelCheckerTraceRecorder, type NormalizedMutationOperation, type RawUowMutateContext, type RawUowTransaction, type RawUowTransactionBuilder, type RawUowTransactionContext, type RouteHandlerInputOptions, type SupportedAdapter, TestContext, buildDatabaseFragmentsTest, createCommonTestContextMethods, createFragmentForTest, createRawUowTransaction, defaultStateHasher, defaultTraceHasher, drainDurableHooks, runModelChecker, runModelCheckerWithActors };
|
|
38
|
+
export { type AdapterContext, type AnyFragmentResult, BaseTestContext, type CreateFragmentForTestOptions, DatabaseFragmentsTestBuilder, type DrainDurableHooksMode, type DrainDurableHooksOptions, type DrizzlePgliteAdapter, type InMemoryAdapterConfig, InternalTestContextMethods, type KyselyPgliteAdapter, type KyselySqliteAdapter, type ModelCheckerActor, type ModelCheckerActorsConfig, ModelCheckerAdapter, type ModelCheckerBounds, type ModelCheckerConfig, type ModelCheckerInvariant, type ModelCheckerInvariantContext, type ModelCheckerMode, type ModelCheckerRunResult, type ModelCheckerScheduleResult, type ModelCheckerScheduler, type ModelCheckerStep, type ModelCheckerTrace, type ModelCheckerTraceEvent, type ModelCheckerTraceHashMode, type ModelCheckerTraceHasher, type ModelCheckerTraceRecorder, type NormalizedMutationOperation, type RawUowMutateContext, type RawUowTransaction, type RawUowTransactionBuilder, type RawUowTransactionContext, type RouteHandlerInputOptions, type SupportedAdapter, TestContext, buildDatabaseFragmentsTest, createCommonTestContextMethods, createFragmentForTest, createRawUowTransaction, defaultStateHasher, defaultTraceHasher, drainDurableHooks, runModelChecker, runModelCheckerWithActors };
|
|
39
39
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","names":[],"sources":["../src/index.ts"],"sourcesContent":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.d.ts","names":[],"sources":["../src/index.ts"],"sourcesContent":[],"mappings":";;;;;;;;;;;;;;;;AA4EwB,UAJP,eAAA,CAIO;EAMP,SAAA,OAAA,EARG,eAQuB,CAAA,GAAA,CAAA;EAChB,aAAA,EAAA,GAAA,GARJ,OAQI,CAAA,IAAA,CAAA;EAA6D,OAAA,EAAA,GAAA,GAPvE,OAOuE,CAAA,IAAA,CAAA;;;AAOxF;;AAEU,UAVO,0BAAA,CAUP;EACP,MAAA,EAAA,CAAA,gBAVwB,SAUxB,CAAA,CAAA,SAAA,EAAA,MAAA,GAAA,IAAA,EAAA,GAVgE,oBAUhE,CAVqF,OAUrF,CAAA;;AAeH;;;;AAAwE,iBAlBxD,8BAAA,CAkBwD,MAAA,EAhB9D,GAgB8D,CAAA,MAAA,GAAA,IAAA,EAhB3C,oBAgB2C,CAAA,GAAA,CAAA,CAAA,CAAA,EAfrE,0BAeqE;;;;KAA5D,sBAAsB,oBAAoB,kBAAkB,eAAe"}
|
package/dist/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { ModelCheckerAdapter } from "./model-checker-adapter.js";
|
|
2
1
|
import { drainDurableHooks } from "./durable-hooks.js";
|
|
3
2
|
import { DatabaseFragmentsTestBuilder, buildDatabaseFragmentsTest } from "./db-test.js";
|
|
4
3
|
import { createRawUowTransaction, defaultStateHasher, defaultTraceHasher, runModelChecker } from "./model-checker.js";
|
|
4
|
+
import { ModelCheckerAdapter } from "./model-checker-adapter.js";
|
|
5
5
|
import { runModelCheckerWithActors } from "./model-checker-actors.js";
|
|
6
6
|
import { createFragmentForTest } from "@fragno-dev/core/test";
|
|
7
7
|
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":[],"sources":["../src/index.ts"],"sourcesContent":["import type {
|
|
1
|
+
{"version":3,"file":"index.js","names":[],"sources":["../src/index.ts"],"sourcesContent":["import type { SimpleQueryInterface } from \"@fragno-dev/db/query\";\nimport type { AnySchema } from \"@fragno-dev/db/schema\";\n\nimport type { DatabaseAdapter } from \"@fragno-dev/db\";\n\nimport type {\n SupportedAdapter,\n AdapterContext,\n KyselySqliteAdapter,\n KyselyPgliteAdapter,\n DrizzlePgliteAdapter,\n InMemoryAdapterConfig,\n} from \"./adapters\";\n\n// Re-export utilities from @fragno-dev/core/test\nexport {\n createFragmentForTest,\n type CreateFragmentForTestOptions,\n type RouteHandlerInputOptions,\n} from \"@fragno-dev/core/test\";\n\n// Re-export adapter types\nexport type {\n SupportedAdapter,\n KyselySqliteAdapter,\n KyselyPgliteAdapter,\n DrizzlePgliteAdapter,\n InMemoryAdapterConfig,\n AdapterContext,\n} from \"./adapters\";\n\n// Re-export new builder-based database test utilities\nexport { buildDatabaseFragmentsTest, DatabaseFragmentsTestBuilder } from \"./db-test\";\nexport type { AnyFragmentResult } from \"./db-test\";\nexport { drainDurableHooks } from \"./durable-hooks\";\nexport type { DrainDurableHooksMode, DrainDurableHooksOptions } from \"./durable-hooks\";\nexport {\n runModelChecker,\n defaultStateHasher,\n defaultTraceHasher,\n type ModelCheckerConfig,\n type ModelCheckerBounds,\n type ModelCheckerRunResult,\n type ModelCheckerScheduleResult,\n type ModelCheckerMode,\n type ModelCheckerStep,\n type ModelCheckerTraceEvent,\n type ModelCheckerTrace,\n type ModelCheckerTraceRecorder,\n type ModelCheckerTraceHasher,\n type ModelCheckerTraceHashMode,\n type NormalizedMutationOperation,\n type RawUowTransaction,\n type RawUowTransactionBuilder,\n type RawUowTransactionContext,\n type RawUowMutateContext,\n createRawUowTransaction,\n} from \"./model-checker\";\n\nexport {\n runModelCheckerWithActors,\n type ModelCheckerActor,\n type ModelCheckerInvariant,\n type ModelCheckerInvariantContext,\n type ModelCheckerActorsConfig,\n} from \"./model-checker-actors\";\n\nexport { ModelCheckerAdapter, type ModelCheckerScheduler } from \"./model-checker-adapter\";\n\n/**\n * Base test context with common functionality across all adapters\n */\nexport interface BaseTestContext {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n readonly adapter: DatabaseAdapter<any>;\n resetDatabase: () => Promise<void>;\n cleanup: () => Promise<void>;\n}\n\n/**\n * Internal interface with getOrm for adapter implementations\n */\nexport interface InternalTestContextMethods {\n getOrm: <TSchema extends AnySchema>(namespace: string | null) => SimpleQueryInterface<TSchema>;\n}\n\n/**\n * Helper to create common test context methods from an ORM map\n * This is used internally by adapter implementations to avoid code duplication\n */\nexport function createCommonTestContextMethods(\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n ormMap: Map<string | null, SimpleQueryInterface<any>>,\n): InternalTestContextMethods {\n return {\n getOrm: <TSchema extends AnySchema>(namespace: string | null) => {\n const orm = ormMap.get(namespace);\n if (!orm) {\n throw new Error(`No ORM found for namespace: ${String(namespace)}`);\n }\n return orm as SimpleQueryInterface<TSchema>;\n },\n };\n}\n\n/**\n * Complete test context combining base and adapter-specific functionality\n */\nexport type TestContext<T extends SupportedAdapter> = BaseTestContext & AdapterContext<T>;\n"],"mappings":";;;;;;;;;;;;AA0FA,SAAgB,+BAEd,QAC4B;AAC5B,QAAO,EACL,SAAoC,cAA6B;EAC/D,MAAM,MAAM,OAAO,IAAI,UAAU;AACjC,MAAI,CAAC,IACH,OAAM,IAAI,MAAM,+BAA+B,OAAO,UAAU,GAAG;AAErE,SAAO;IAEV"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"model-checker-actors.d.ts","names":[],"sources":["../src/model-checker-actors.ts"],"sourcesContent":[],"mappings":";;;;;;
|
|
1
|
+
{"version":3,"file":"model-checker-actors.d.ts","names":[],"sources":["../src/model-checker-actors.ts"],"sourcesContent":[],"mappings":";;;;;;KAgTY;;EAAA,GAAA,EAAA,CAAA,GAAA,EAEC,QAFD,EAAiB,GAEH,OAFG,CAAA,IAAA,CAAA,GAEhB,IAAA;AAGb,CAAA;AAAyD,KAA7C,4BAA6C,CAAA,gBAAA,SAAA,EAAA,UAAA,EAAA,QAAA,CAAA,GAAA;EAC/C,MAAA,EAAA,OAAA;EAC0B,WAAA,EAArB,oBAAqB,CAAA,OAAA,EAAS,UAAT,CAAA;EAAS,OAAA,EAClC,QADkC;EAA9B,QAAA,EAEH,gBAFG,EAAA;EACJ,SAAA,EAAA,MAAA;CACC;AAAgB,KAIhB,qBAJgB,CAAA,gBAIsB,SAJtB,EAAA,UAAA,EAAA,QAAA,CAAA,GAAA,CAAA,GAAA,EAKrB,4BALqB,CAKQ,OALR,EAKiB,UALjB,EAK6B,QAL7B,CAAA,EAAA,GAMvB,OANuB,CAAA,IAAA,CAAA,GAAA,IAAA;AAIhB,KAIA,wBAJqB,CAAA,gBAIoB,SAJpB,EAAA,UAAA,EAAA,QAAA,CAAA,GAAA;EAAiB,MAAA,EAKxC,OALwC;EACd,IAAA,CAAA,EAK3B,gBAL2B;EAAS,IAAA,CAAA,EAAA,MAAA;EAAY,YAAA,CAAA,EAAA,MAAA;EAAlD,MAAA,CAAA,EAQI,kBARJ;EACF,OAAA,CAAA,EAQO,mBARP;EAAO,yBAAA,CAAA,EAAA,OAAA;EAEA,WAAA,CAAA,EAAA,CAAA,GAAA,EAQU,8BARc,CAQiB,OARjB,EAQ0B,UAR1B,CAAA,EAAA,GAQ0C,OAR1C,CAAA,MAAA,CAAA;EAAiB,aAAA,EAAA,GAAA,GAS9B,OAT8B,CAAA;IAC3C,OAAA,EASG,mBATH,CASuB,UATvB,CAAA;IACD,GAAA,EASA,QATA;IAGE,WAAA,EAOM,oBAPN,CAO2B,OAP3B,EAOoC,UAPpC,CAAA;IACC,OAAA,CAAA,EAAA,GAAA,GAOQ,OAPR,CAAA,IAAA,CAAA;EAEyC,CAAA,CAAA;EAAS,KAAA,CAAA,EAAA,CAAA,GAAA,EAO9C,QAP8C,EAAA,GAOjC,OAPiC,CAAA,IAAA,CAAA;EAAxC,WAAA,EAAA,CAAA,GAAA,EAQD,QARC,EAAA,GAQY,iBARZ,CAQ8B,QAR9B,CAAA,EAAA;EAAwD,UAAA,CAAA,EAS/D,qBAT+D,CASzC,OATyC,EAShC,UATgC,EASpB,QAToB,CAAA,EAAA;CAE7C;AAApB,cAyNA,yBAzNA,EAAA,CAAA,gBAyNmD,SAzNnD,EAAA,UAAA,EAAA,QAAA,CAAA,CAAA,MAAA,EA0NH,wBA1NG,CA0NsB,OA1NtB,EA0N+B,UA1N/B,EA0N2C,QA1N3C,CAAA,EAAA,GA2NV,OA3NU,CA2NF,qBA3NE,CAAA"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"model-checker-actors.js","names":["#mode","#plan","#actorsDone","#pendingSignal","#uowPlans","phases: ModelCheckerPhase[]","#getOrCreateUowId","#assertPlanned","#inFlight","gate: PendingGate","#pending","#uowIds","schedules: ModelCheckerStep[][]","current: ModelCheckerStep[]","defaultHistoryConfig: ModelCheckerHistory","lastStateHash: string | null","schedule: ModelCheckerStep[]","choicePoints: number[]","schedules: ModelCheckerScheduleResult[]","stack: number[][]"],"sources":["../src/model-checker-actors.ts"],"sourcesContent":["import type { AnySchema } from \"@fragno-dev/db/schema\";\nimport type { SimpleQueryInterface } from \"@fragno-dev/db/query\";\nimport type { UOWInstrumentationContext } from \"@fragno-dev/db/unit-of-work\";\nimport {\n defaultStateHasher,\n type ModelCheckerBounds,\n type ModelCheckerHistory,\n type ModelCheckerMode,\n type ModelCheckerPhase,\n type ModelCheckerRunResult,\n type ModelCheckerScheduleResult,\n type ModelCheckerStateHasherContext,\n type ModelCheckerStep,\n} from \"./model-checker\";\nimport { ModelCheckerAdapter, type ModelCheckerScheduler } from \"./model-checker-adapter\";\n\ntype DeferredPromise<T> = {\n promise: Promise<T>;\n resolve: (value: T) => void;\n};\n\nconst createDeferred = <T>(): DeferredPromise<T> => {\n const { promise, resolve } = Promise.withResolvers<T>();\n return { promise, resolve };\n};\n\ntype PendingGate = {\n uowId: number;\n phase: ModelCheckerPhase;\n release: () => void;\n completion: Promise<void>;\n};\n\ntype UowPlan = {\n hasRetrieve: boolean;\n hasMutate: boolean;\n};\n\ntype SchedulePlan = {\n phasesPerTransaction: ModelCheckerPhase[][];\n};\n\ntype SchedulerMode = \"record\" | \"schedule\";\n\nclass PhaseScheduler implements ModelCheckerScheduler {\n #mode: SchedulerMode;\n #plan: SchedulePlan | null;\n #uowIds = new WeakMap<object, number>();\n #uowPlans: UowPlan[] = [];\n #pending: PendingGate[] = [];\n #pendingSignal = createDeferred<void>();\n #inFlight = new Map<string, DeferredPromise<void>>();\n #actorsDone = false;\n\n constructor(mode: SchedulerMode, plan?: SchedulePlan) {\n this.#mode = mode;\n this.#plan = plan ?? null;\n }\n\n markActorsDone(): void {\n this.#actorsDone = true;\n this.#pendingSignal.resolve();\n }\n\n getPlan(): SchedulePlan {\n return {\n phasesPerTransaction: this.#uowPlans.map((entry) => {\n const phases: ModelCheckerPhase[] = [];\n if (entry.hasRetrieve) {\n phases.push(\"retrieve\");\n }\n if (entry.hasMutate) {\n phases.push(\"mutate\");\n }\n return phases;\n }),\n };\n }\n\n async beforePhase(ctx: UOWInstrumentationContext, phase: ModelCheckerPhase): Promise<void> {\n const uow = ctx.uow as object;\n const uowId = this.#getOrCreateUowId(uow);\n\n if (phase === \"mutate\") {\n const plan = this.#uowPlans[uowId];\n if (plan) {\n plan.hasMutate = true;\n }\n } else {\n const plan = this.#uowPlans[uowId];\n if (plan) {\n plan.hasRetrieve = true;\n }\n }\n\n if (this.#mode === \"record\") {\n return;\n }\n\n this.#assertPlanned(uowId, phase);\n const release = createDeferred<void>();\n const completion = createDeferred<void>();\n this.#inFlight.set(`${uowId}:${phase}`, completion);\n const gate: PendingGate = {\n uowId,\n phase,\n release: () => {\n release.resolve();\n },\n completion: completion.promise,\n };\n this.#pending.push(gate);\n this.#pendingSignal.resolve();\n this.#pendingSignal = createDeferred<void>();\n await release.promise;\n }\n\n async afterPhase(ctx: UOWInstrumentationContext, phase: ModelCheckerPhase): Promise<void> {\n const uow = ctx.uow as object;\n const uowId = this.#getOrCreateUowId(uow);\n const key = `${uowId}:${phase}`;\n const completion = this.#inFlight.get(key);\n if (completion) {\n completion.resolve();\n this.#inFlight.delete(key);\n }\n }\n\n async releaseStep(step: ModelCheckerStep, actorsPromise: Promise<void>): Promise<void> {\n for (;;) {\n const matchIndex = this.#pending.findIndex(\n (gate) => gate.uowId === step.txId && gate.phase === step.phase,\n );\n if (matchIndex !== -1) {\n const [gate] = this.#pending.splice(matchIndex, 1);\n gate.release();\n await gate.completion;\n return;\n }\n\n if (this.#pending.length > 0) {\n const pendingSummary = this.#pending\n .map((gate) => `${gate.uowId}:${gate.phase}`)\n .join(\", \");\n throw new Error(\n `Model checker schedule mismatch. Expected ${step.txId}:${step.phase}, pending [${pendingSummary}]`,\n );\n }\n\n await Promise.race([this.#pendingSignal.promise, actorsPromise]);\n if (this.#actorsDone) {\n throw new Error(\n `Model checker schedule expects ${step.phase} for UOW ${step.txId}, but no gate appeared.`,\n );\n }\n }\n }\n\n async releaseAny(\n pickIndex: (pending: PendingGate[]) => number,\n actorsPromise: Promise<void>,\n ): Promise<ModelCheckerStep | null> {\n for (;;) {\n if (this.#pending.length > 0) {\n const index = Math.max(0, Math.min(pickIndex(this.#pending), this.#pending.length - 1));\n const [gate] = this.#pending.splice(index, 1);\n gate.release();\n await gate.completion;\n return { txId: gate.uowId, phase: gate.phase };\n }\n\n await Promise.race([this.#pendingSignal.promise, actorsPromise]);\n if (this.#actorsDone) {\n return null;\n }\n }\n }\n\n #getOrCreateUowId(uow: object): number {\n const existing = this.#uowIds.get(uow);\n if (existing !== undefined) {\n return existing;\n }\n\n const next = this.#uowPlans.length;\n if (this.#plan && next >= this.#plan.phasesPerTransaction.length) {\n throw new Error(\"Model checker saw more UOWs than planned.\");\n }\n\n this.#uowIds.set(uow, next);\n this.#uowPlans.push({ hasRetrieve: false, hasMutate: false });\n return next;\n }\n\n #assertPlanned(uowId: number, phase: ModelCheckerPhase): void {\n const plan = this.#plan;\n if (!plan) {\n return;\n }\n\n const phases = plan.phasesPerTransaction[uowId];\n if (!phases || phases.length === 0) {\n throw new Error(`Model checker saw unexpected UOW ${uowId}.`);\n }\n\n if (!phases.includes(phase)) {\n throw new Error(`Model checker saw unexpected ${phase} phase for UOW ${uowId}.`);\n }\n }\n}\n\nconst mulberry32 = (seed: number) => {\n let t = seed >>> 0;\n return () => {\n t += 1831565813;\n let r = Math.imul(t ^ (t >>> 15), t | 1);\n r ^= r + Math.imul(r ^ (r >>> 7), r | 61);\n return ((r ^ (r >>> 14)) >>> 0) / 4294967296;\n };\n};\n\nconst generateAllSchedules = (\n phasesPerTransaction: ModelCheckerPhase[][],\n): ModelCheckerStep[][] => {\n const schedules: ModelCheckerStep[][] = [];\n const totalSteps = phasesPerTransaction.reduce((sum, phases) => sum + phases.length, 0);\n const progress = phasesPerTransaction.map(() => 0);\n const current: ModelCheckerStep[] = [];\n\n const walk = () => {\n if (current.length === totalSteps) {\n schedules.push([...current]);\n return;\n }\n\n for (let txId = 0; txId < phasesPerTransaction.length; txId += 1) {\n if (progress[txId] >= phasesPerTransaction[txId].length) {\n continue;\n }\n const phase = phasesPerTransaction[txId][progress[txId]];\n if (!phase) {\n continue;\n }\n current.push({ txId, phase });\n progress[txId] += 1;\n walk();\n progress[txId] -= 1;\n current.pop();\n }\n };\n\n walk();\n return schedules;\n};\n\ntype HistoryTracker = {\n add: (key: string) => boolean;\n size: () => number;\n};\n\nconst createHistoryTracker = (history: ModelCheckerHistory): HistoryTracker | null => {\n if (!history) {\n return null;\n }\n\n if (history.type === \"unbounded\") {\n const set = new Set<string>();\n return {\n add: (key: string) => {\n const has = set.has(key);\n if (!has) {\n set.add(key);\n }\n return !has;\n },\n size: () => set.size,\n };\n }\n\n const maxEntries = Math.max(history.maxEntries, 1);\n const map = new Map<string, true>();\n return {\n add: (key: string) => {\n const existed = map.delete(key);\n map.set(key, true);\n if (map.size > maxEntries) {\n const first = map.keys().next().value;\n if (first) {\n map.delete(first);\n }\n }\n return !existed;\n },\n size: () => map.size,\n };\n};\n\nconst serializeSchedulePrefix = (schedule: ModelCheckerStep[]): string =>\n schedule.map((step) => `${step.txId}:${step.phase}`).join(\"|\");\n\nconst buildPathKey = (stateHash: string, prefix: ModelCheckerStep[]): string =>\n `${stateHash}::${serializeSchedulePrefix(prefix)}`;\n\nexport type ModelCheckerActor<TContext> = {\n name?: string;\n run: (ctx: TContext) => Promise<void> | void;\n};\n\nexport type ModelCheckerInvariantContext<TSchema extends AnySchema, TUowConfig, TContext> = {\n schema: TSchema;\n queryEngine: SimpleQueryInterface<TSchema, TUowConfig>;\n context: TContext;\n schedule: ModelCheckerStep[];\n stepIndex: number;\n};\n\nexport type ModelCheckerInvariant<TSchema extends AnySchema, TUowConfig, TContext> = (\n ctx: ModelCheckerInvariantContext<TSchema, TUowConfig, TContext>,\n) => Promise<void> | void;\n\nexport type ModelCheckerActorsConfig<TSchema extends AnySchema, TUowConfig, TContext> = {\n schema: TSchema;\n mode?: ModelCheckerMode;\n seed?: number;\n maxSchedules?: number;\n bounds?: ModelCheckerBounds;\n history?: ModelCheckerHistory;\n stopWhenFrontierExhausted?: boolean;\n stateHasher?: (ctx: ModelCheckerStateHasherContext<TSchema, TUowConfig>) => Promise<string>;\n createContext: () => Promise<{\n adapter: ModelCheckerAdapter<TUowConfig>;\n ctx: TContext;\n queryEngine: SimpleQueryInterface<TSchema, TUowConfig>;\n cleanup?: () => Promise<void>;\n }>;\n setup?: (ctx: TContext) => Promise<void>;\n buildActors: (ctx: TContext) => ModelCheckerActor<TContext>[];\n invariants?: ModelCheckerInvariant<TSchema, TUowConfig, TContext>[];\n};\n\nconst defaultHistoryConfig: ModelCheckerHistory = { type: \"lru\", maxEntries: 5000 };\n\nconst planTransactions = (phasesPerTransaction: ModelCheckerPhase[][]): SchedulePlan => {\n if (phasesPerTransaction.length === 0) {\n throw new Error(\"Model checker requires at least one transaction.\");\n }\n return { phasesPerTransaction };\n};\n\nconst recordPlan = async <TSchema extends AnySchema, TUowConfig, TContext>(\n config: ModelCheckerActorsConfig<TSchema, TUowConfig, TContext>,\n): Promise<SchedulePlan> => {\n const { adapter, ctx, cleanup } = await config.createContext();\n\n try {\n if (config.setup) {\n await config.setup(ctx);\n }\n const scheduler = new PhaseScheduler(\"record\");\n adapter.setScheduler(scheduler);\n const actors = config.buildActors(ctx);\n await Promise.all(actors.map((actor) => actor.run(ctx)));\n return planTransactions(scheduler.getPlan().phasesPerTransaction);\n } finally {\n adapter.setScheduler(null);\n if (cleanup) {\n await cleanup();\n }\n }\n};\n\nconst executeSchedule = async <TSchema extends AnySchema, TUowConfig, TContext>(\n schedule: ModelCheckerStep[],\n config: ModelCheckerActorsConfig<TSchema, TUowConfig, TContext>,\n plan: SchedulePlan,\n history: HistoryTracker | null,\n stateHasher: (ctx: ModelCheckerStateHasherContext<TSchema, TUowConfig>) => Promise<string>,\n): Promise<{ stateHash: string; newPathsAdded: boolean }> => {\n const { adapter, ctx, queryEngine, cleanup } = await config.createContext();\n\n try {\n if (config.setup) {\n await config.setup(ctx);\n }\n const scheduler = new PhaseScheduler(\"schedule\", plan);\n adapter.setScheduler(scheduler);\n\n const actors = config.buildActors(ctx);\n const actorsPromise = Promise.all(actors.map((actor) => actor.run(ctx))).then(() => {\n scheduler.markActorsDone();\n });\n\n let lastStateHash: string | null = null;\n let newPathsAdded = false;\n\n for (let stepIndex = 0; stepIndex < schedule.length; stepIndex += 1) {\n const step = schedule[stepIndex];\n if (!step) {\n throw new Error(\"Schedule step is missing.\");\n }\n\n await scheduler.releaseStep(step, actorsPromise);\n\n if (config.invariants) {\n for (const invariant of config.invariants) {\n await invariant({\n schema: config.schema,\n queryEngine,\n context: ctx,\n schedule,\n stepIndex,\n });\n }\n }\n\n if (history) {\n lastStateHash = await stateHasher({\n schema: config.schema,\n queryEngine,\n });\n const prefix = schedule.slice(0, stepIndex + 1);\n const added = history.add(buildPathKey(lastStateHash, prefix));\n if (added) {\n newPathsAdded = true;\n }\n }\n }\n\n await actorsPromise;\n\n if (!lastStateHash) {\n lastStateHash = await stateHasher({ schema: config.schema, queryEngine });\n }\n\n return { stateHash: lastStateHash, newPathsAdded };\n } finally {\n adapter.setScheduler(null);\n if (cleanup) {\n await cleanup();\n }\n }\n};\n\nconst executeScheduleDynamic = async <TSchema extends AnySchema, TUowConfig, TContext>(\n config: ModelCheckerActorsConfig<TSchema, TUowConfig, TContext>,\n history: HistoryTracker | null,\n stateHasher: (ctx: ModelCheckerStateHasherContext<TSchema, TUowConfig>) => Promise<string>,\n pickIndex: (pending: PendingGate[]) => number,\n): Promise<{ schedule: ModelCheckerStep[]; stateHash: string; newPathsAdded: boolean }> => {\n const { adapter, ctx, queryEngine, cleanup } = await config.createContext();\n\n try {\n if (config.setup) {\n await config.setup(ctx);\n }\n\n const scheduler = new PhaseScheduler(\"schedule\");\n adapter.setScheduler(scheduler);\n\n const actors = config.buildActors(ctx);\n const actorsPromise = Promise.all(actors.map((actor) => actor.run(ctx))).then(() => {\n scheduler.markActorsDone();\n });\n\n const schedule: ModelCheckerStep[] = [];\n let lastStateHash: string | null = null;\n let newPathsAdded = false;\n\n for (;;) {\n const step = await scheduler.releaseAny(pickIndex, actorsPromise);\n if (!step) {\n break;\n }\n\n schedule.push(step);\n const stepIndex = schedule.length - 1;\n\n if (config.invariants) {\n for (const invariant of config.invariants) {\n await invariant({\n schema: config.schema,\n queryEngine,\n context: ctx,\n schedule,\n stepIndex,\n });\n }\n }\n\n if (history) {\n lastStateHash = await stateHasher({\n schema: config.schema,\n queryEngine,\n });\n const prefix = schedule.slice(0, stepIndex + 1);\n const added = history.add(buildPathKey(lastStateHash, prefix));\n if (added) {\n newPathsAdded = true;\n }\n }\n }\n\n await actorsPromise;\n\n if (!lastStateHash) {\n lastStateHash = await stateHasher({ schema: config.schema, queryEngine });\n }\n\n return { schedule, stateHash: lastStateHash, newPathsAdded };\n } finally {\n adapter.setScheduler(null);\n if (cleanup) {\n await cleanup();\n }\n }\n};\n\nconst executeScheduleDynamicWithChoices = async <TSchema extends AnySchema, TUowConfig, TContext>(\n config: ModelCheckerActorsConfig<TSchema, TUowConfig, TContext>,\n history: HistoryTracker | null,\n stateHasher: (ctx: ModelCheckerStateHasherContext<TSchema, TUowConfig>) => Promise<string>,\n choices: number[],\n): Promise<{\n schedule: ModelCheckerStep[];\n stateHash: string;\n newPathsAdded: boolean;\n choicePoints: number[];\n}> => {\n const choicePoints: number[] = [];\n const result = await executeScheduleDynamic(config, history, stateHasher, (pending) => {\n const stepIndex = choicePoints.length;\n choicePoints.push(pending.length);\n const choice = choices[stepIndex];\n if (choice === undefined || choice < 0 || choice >= pending.length) {\n return 0;\n }\n return choice;\n });\n\n return {\n ...result,\n choicePoints,\n };\n};\n\nconst serializeChoices = (choices: number[]): string => choices.join(\",\");\n\nexport const runModelCheckerWithActors = async <TSchema extends AnySchema, TUowConfig, TContext>(\n config: ModelCheckerActorsConfig<TSchema, TUowConfig, TContext>,\n): Promise<ModelCheckerRunResult> => {\n const mode = config.mode ?? \"exhaustive\";\n const historyConfig = config.history ?? defaultHistoryConfig;\n const history = createHistoryTracker(historyConfig);\n const stateHasher = config.stateHasher ?? defaultStateHasher;\n const schedules: ModelCheckerScheduleResult[] = [];\n const maxSchedules = config.maxSchedules;\n const seed = config.seed ?? 1;\n\n if (mode === \"exhaustive\") {\n const plan = await recordPlan(config);\n const allSchedules = generateAllSchedules(plan.phasesPerTransaction);\n for (const schedule of allSchedules) {\n if (maxSchedules !== undefined && schedules.length >= maxSchedules) {\n break;\n }\n const result = await executeSchedule(schedule, config, plan, history, stateHasher);\n schedules.push({ schedule, stateHash: result.stateHash });\n }\n } else if (mode === \"bounded-exhaustive\") {\n const maxSteps = config.bounds?.maxSteps;\n if (!maxSteps || maxSteps < 1) {\n throw new Error(\"bounded-exhaustive mode requires bounds.maxSteps >= 1.\");\n }\n\n const stack: number[][] = [[]];\n const seen = new Set<string>();\n seen.add(\"\");\n\n while (stack.length > 0) {\n if (maxSchedules !== undefined && schedules.length >= maxSchedules) {\n break;\n }\n\n const choices = stack.pop();\n if (!choices) {\n break;\n }\n\n const result = await executeScheduleDynamicWithChoices(config, history, stateHasher, choices);\n schedules.push({ schedule: result.schedule, stateHash: result.stateHash });\n\n const limit = Math.min(result.choicePoints.length, maxSteps);\n for (let stepIndex = 0; stepIndex < limit; stepIndex += 1) {\n const count = result.choicePoints[stepIndex];\n const current = choices[stepIndex] ?? 0;\n for (let alt = current + 1; alt < count; alt += 1) {\n const next = choices.slice(0, stepIndex);\n next[stepIndex] = alt;\n const key = serializeChoices(next);\n if (!seen.has(key)) {\n seen.add(key);\n stack.push(next);\n }\n }\n }\n }\n } else if (mode === \"random\") {\n const rng = mulberry32(seed);\n const total = maxSchedules ?? 1;\n for (let i = 0; i < total; i += 1) {\n const result = await executeScheduleDynamic(config, history, stateHasher, (pending) =>\n Math.floor(rng() * pending.length),\n );\n schedules.push({ schedule: result.schedule, stateHash: result.stateHash });\n }\n } else {\n const rng = mulberry32(seed);\n const stopWhenFrontierExhausted = config.stopWhenFrontierExhausted ?? false;\n let iterations = 0;\n let frontierExhausted = false;\n\n while (!frontierExhausted) {\n if (maxSchedules !== undefined && iterations >= maxSchedules) {\n break;\n }\n const result = await executeScheduleDynamic(config, history, stateHasher, (pending) =>\n Math.floor(rng() * pending.length),\n );\n schedules.push({ schedule: result.schedule, stateHash: result.stateHash });\n iterations += 1;\n\n if (stopWhenFrontierExhausted && history) {\n frontierExhausted = !result.newPathsAdded;\n }\n }\n }\n\n return {\n schedules,\n visitedPaths: history?.size() ?? 0,\n };\n};\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"model-checker-actors.js","names":["#mode","#plan","#actorsDone","#pendingSignal","#uowPlans","phases: ModelCheckerPhase[]","#getOrCreateUowId","#assertPlanned","#inFlight","gate: PendingGate","#pending","#uowIds","schedules: ModelCheckerStep[][]","current: ModelCheckerStep[]","defaultHistoryConfig: ModelCheckerHistory","lastStateHash: string | null","schedule: ModelCheckerStep[]","choicePoints: number[]","schedules: ModelCheckerScheduleResult[]","stack: number[][]"],"sources":["../src/model-checker-actors.ts"],"sourcesContent":["import type { SimpleQueryInterface } from \"@fragno-dev/db/query\";\nimport type { AnySchema } from \"@fragno-dev/db/schema\";\nimport type { UOWInstrumentationContext } from \"@fragno-dev/db/unit-of-work\";\n\nimport {\n defaultStateHasher,\n type ModelCheckerBounds,\n type ModelCheckerHistory,\n type ModelCheckerMode,\n type ModelCheckerPhase,\n type ModelCheckerRunResult,\n type ModelCheckerScheduleResult,\n type ModelCheckerStateHasherContext,\n type ModelCheckerStep,\n} from \"./model-checker\";\nimport { ModelCheckerAdapter, type ModelCheckerScheduler } from \"./model-checker-adapter\";\n\ntype DeferredPromise<T> = {\n promise: Promise<T>;\n resolve: (value: T) => void;\n};\n\nconst createDeferred = <T>(): DeferredPromise<T> => {\n const { promise, resolve } = Promise.withResolvers<T>();\n return { promise, resolve };\n};\n\ntype PendingGate = {\n uowId: number;\n phase: ModelCheckerPhase;\n release: () => void;\n completion: Promise<void>;\n};\n\ntype UowPlan = {\n hasRetrieve: boolean;\n hasMutate: boolean;\n};\n\ntype SchedulePlan = {\n phasesPerTransaction: ModelCheckerPhase[][];\n};\n\ntype SchedulerMode = \"record\" | \"schedule\";\n\nclass PhaseScheduler implements ModelCheckerScheduler {\n #mode: SchedulerMode;\n #plan: SchedulePlan | null;\n #uowIds = new WeakMap<object, number>();\n #uowPlans: UowPlan[] = [];\n #pending: PendingGate[] = [];\n #pendingSignal = createDeferred<void>();\n #inFlight = new Map<string, DeferredPromise<void>>();\n #actorsDone = false;\n\n constructor(mode: SchedulerMode, plan?: SchedulePlan) {\n this.#mode = mode;\n this.#plan = plan ?? null;\n }\n\n markActorsDone(): void {\n this.#actorsDone = true;\n this.#pendingSignal.resolve();\n }\n\n getPlan(): SchedulePlan {\n return {\n phasesPerTransaction: this.#uowPlans.map((entry) => {\n const phases: ModelCheckerPhase[] = [];\n if (entry.hasRetrieve) {\n phases.push(\"retrieve\");\n }\n if (entry.hasMutate) {\n phases.push(\"mutate\");\n }\n return phases;\n }),\n };\n }\n\n async beforePhase(ctx: UOWInstrumentationContext, phase: ModelCheckerPhase): Promise<void> {\n const uow = ctx.uow as object;\n const uowId = this.#getOrCreateUowId(uow);\n\n if (phase === \"mutate\") {\n const plan = this.#uowPlans[uowId];\n if (plan) {\n plan.hasMutate = true;\n }\n } else {\n const plan = this.#uowPlans[uowId];\n if (plan) {\n plan.hasRetrieve = true;\n }\n }\n\n if (this.#mode === \"record\") {\n return;\n }\n\n this.#assertPlanned(uowId, phase);\n const release = createDeferred<void>();\n const completion = createDeferred<void>();\n this.#inFlight.set(`${uowId}:${phase}`, completion);\n const gate: PendingGate = {\n uowId,\n phase,\n release: () => {\n release.resolve();\n },\n completion: completion.promise,\n };\n this.#pending.push(gate);\n this.#pendingSignal.resolve();\n this.#pendingSignal = createDeferred<void>();\n await release.promise;\n }\n\n async afterPhase(ctx: UOWInstrumentationContext, phase: ModelCheckerPhase): Promise<void> {\n const uow = ctx.uow as object;\n const uowId = this.#getOrCreateUowId(uow);\n const key = `${uowId}:${phase}`;\n const completion = this.#inFlight.get(key);\n if (completion) {\n completion.resolve();\n this.#inFlight.delete(key);\n }\n }\n\n async releaseStep(step: ModelCheckerStep, actorsPromise: Promise<void>): Promise<void> {\n for (;;) {\n const matchIndex = this.#pending.findIndex(\n (gate) => gate.uowId === step.txId && gate.phase === step.phase,\n );\n if (matchIndex !== -1) {\n const [gate] = this.#pending.splice(matchIndex, 1);\n gate.release();\n await gate.completion;\n return;\n }\n\n if (this.#pending.length > 0) {\n const pendingSummary = this.#pending\n .map((gate) => `${gate.uowId}:${gate.phase}`)\n .join(\", \");\n throw new Error(\n `Model checker schedule mismatch. Expected ${step.txId}:${step.phase}, pending [${pendingSummary}]`,\n );\n }\n\n await Promise.race([this.#pendingSignal.promise, actorsPromise]);\n if (this.#actorsDone) {\n throw new Error(\n `Model checker schedule expects ${step.phase} for UOW ${step.txId}, but no gate appeared.`,\n );\n }\n }\n }\n\n async releaseAny(\n pickIndex: (pending: PendingGate[]) => number,\n actorsPromise: Promise<void>,\n ): Promise<ModelCheckerStep | null> {\n for (;;) {\n if (this.#pending.length > 0) {\n const index = Math.max(0, Math.min(pickIndex(this.#pending), this.#pending.length - 1));\n const [gate] = this.#pending.splice(index, 1);\n gate.release();\n await gate.completion;\n return { txId: gate.uowId, phase: gate.phase };\n }\n\n await Promise.race([this.#pendingSignal.promise, actorsPromise]);\n if (this.#actorsDone) {\n return null;\n }\n }\n }\n\n #getOrCreateUowId(uow: object): number {\n const existing = this.#uowIds.get(uow);\n if (existing !== undefined) {\n return existing;\n }\n\n const next = this.#uowPlans.length;\n if (this.#plan && next >= this.#plan.phasesPerTransaction.length) {\n throw new Error(\"Model checker saw more UOWs than planned.\");\n }\n\n this.#uowIds.set(uow, next);\n this.#uowPlans.push({ hasRetrieve: false, hasMutate: false });\n return next;\n }\n\n #assertPlanned(uowId: number, phase: ModelCheckerPhase): void {\n const plan = this.#plan;\n if (!plan) {\n return;\n }\n\n const phases = plan.phasesPerTransaction[uowId];\n if (!phases || phases.length === 0) {\n throw new Error(`Model checker saw unexpected UOW ${uowId}.`);\n }\n\n if (!phases.includes(phase)) {\n throw new Error(`Model checker saw unexpected ${phase} phase for UOW ${uowId}.`);\n }\n }\n}\n\nconst mulberry32 = (seed: number) => {\n let t = seed >>> 0;\n return () => {\n t += 1831565813;\n let r = Math.imul(t ^ (t >>> 15), t | 1);\n r ^= r + Math.imul(r ^ (r >>> 7), r | 61);\n return ((r ^ (r >>> 14)) >>> 0) / 4294967296;\n };\n};\n\nconst generateAllSchedules = (\n phasesPerTransaction: ModelCheckerPhase[][],\n): ModelCheckerStep[][] => {\n const schedules: ModelCheckerStep[][] = [];\n const totalSteps = phasesPerTransaction.reduce((sum, phases) => sum + phases.length, 0);\n const progress = phasesPerTransaction.map(() => 0);\n const current: ModelCheckerStep[] = [];\n\n const walk = () => {\n if (current.length === totalSteps) {\n schedules.push([...current]);\n return;\n }\n\n for (let txId = 0; txId < phasesPerTransaction.length; txId += 1) {\n if (progress[txId] >= phasesPerTransaction[txId].length) {\n continue;\n }\n const phase = phasesPerTransaction[txId][progress[txId]];\n if (!phase) {\n continue;\n }\n current.push({ txId, phase });\n progress[txId] += 1;\n walk();\n progress[txId] -= 1;\n current.pop();\n }\n };\n\n walk();\n return schedules;\n};\n\ntype HistoryTracker = {\n add: (key: string) => boolean;\n size: () => number;\n};\n\nconst createHistoryTracker = (history: ModelCheckerHistory): HistoryTracker | null => {\n if (!history) {\n return null;\n }\n\n if (history.type === \"unbounded\") {\n const set = new Set<string>();\n return {\n add: (key: string) => {\n const has = set.has(key);\n if (!has) {\n set.add(key);\n }\n return !has;\n },\n size: () => set.size,\n };\n }\n\n const maxEntries = Math.max(history.maxEntries, 1);\n const map = new Map<string, true>();\n return {\n add: (key: string) => {\n const existed = map.delete(key);\n map.set(key, true);\n if (map.size > maxEntries) {\n const first = map.keys().next().value;\n if (first) {\n map.delete(first);\n }\n }\n return !existed;\n },\n size: () => map.size,\n };\n};\n\nconst serializeSchedulePrefix = (schedule: ModelCheckerStep[]): string =>\n schedule.map((step) => `${step.txId}:${step.phase}`).join(\"|\");\n\nconst buildPathKey = (stateHash: string, prefix: ModelCheckerStep[]): string =>\n `${stateHash}::${serializeSchedulePrefix(prefix)}`;\n\nexport type ModelCheckerActor<TContext> = {\n name?: string;\n run: (ctx: TContext) => Promise<void> | void;\n};\n\nexport type ModelCheckerInvariantContext<TSchema extends AnySchema, TUowConfig, TContext> = {\n schema: TSchema;\n queryEngine: SimpleQueryInterface<TSchema, TUowConfig>;\n context: TContext;\n schedule: ModelCheckerStep[];\n stepIndex: number;\n};\n\nexport type ModelCheckerInvariant<TSchema extends AnySchema, TUowConfig, TContext> = (\n ctx: ModelCheckerInvariantContext<TSchema, TUowConfig, TContext>,\n) => Promise<void> | void;\n\nexport type ModelCheckerActorsConfig<TSchema extends AnySchema, TUowConfig, TContext> = {\n schema: TSchema;\n mode?: ModelCheckerMode;\n seed?: number;\n maxSchedules?: number;\n bounds?: ModelCheckerBounds;\n history?: ModelCheckerHistory;\n stopWhenFrontierExhausted?: boolean;\n stateHasher?: (ctx: ModelCheckerStateHasherContext<TSchema, TUowConfig>) => Promise<string>;\n createContext: () => Promise<{\n adapter: ModelCheckerAdapter<TUowConfig>;\n ctx: TContext;\n queryEngine: SimpleQueryInterface<TSchema, TUowConfig>;\n cleanup?: () => Promise<void>;\n }>;\n setup?: (ctx: TContext) => Promise<void>;\n buildActors: (ctx: TContext) => ModelCheckerActor<TContext>[];\n invariants?: ModelCheckerInvariant<TSchema, TUowConfig, TContext>[];\n};\n\nconst defaultHistoryConfig: ModelCheckerHistory = { type: \"lru\", maxEntries: 5000 };\n\nconst planTransactions = (phasesPerTransaction: ModelCheckerPhase[][]): SchedulePlan => {\n if (phasesPerTransaction.length === 0) {\n throw new Error(\"Model checker requires at least one transaction.\");\n }\n return { phasesPerTransaction };\n};\n\nconst recordPlan = async <TSchema extends AnySchema, TUowConfig, TContext>(\n config: ModelCheckerActorsConfig<TSchema, TUowConfig, TContext>,\n): Promise<SchedulePlan> => {\n const { adapter, ctx, cleanup } = await config.createContext();\n\n try {\n if (config.setup) {\n await config.setup(ctx);\n }\n const scheduler = new PhaseScheduler(\"record\");\n adapter.setScheduler(scheduler);\n const actors = config.buildActors(ctx);\n await Promise.all(actors.map((actor) => actor.run(ctx)));\n return planTransactions(scheduler.getPlan().phasesPerTransaction);\n } finally {\n adapter.setScheduler(null);\n if (cleanup) {\n await cleanup();\n }\n }\n};\n\nconst executeSchedule = async <TSchema extends AnySchema, TUowConfig, TContext>(\n schedule: ModelCheckerStep[],\n config: ModelCheckerActorsConfig<TSchema, TUowConfig, TContext>,\n plan: SchedulePlan,\n history: HistoryTracker | null,\n stateHasher: (ctx: ModelCheckerStateHasherContext<TSchema, TUowConfig>) => Promise<string>,\n): Promise<{ stateHash: string; newPathsAdded: boolean }> => {\n const { adapter, ctx, queryEngine, cleanup } = await config.createContext();\n\n try {\n if (config.setup) {\n await config.setup(ctx);\n }\n const scheduler = new PhaseScheduler(\"schedule\", plan);\n adapter.setScheduler(scheduler);\n\n const actors = config.buildActors(ctx);\n const actorsPromise = Promise.all(actors.map((actor) => actor.run(ctx))).then(() => {\n scheduler.markActorsDone();\n });\n\n let lastStateHash: string | null = null;\n let newPathsAdded = false;\n\n for (let stepIndex = 0; stepIndex < schedule.length; stepIndex += 1) {\n const step = schedule[stepIndex];\n if (!step) {\n throw new Error(\"Schedule step is missing.\");\n }\n\n await scheduler.releaseStep(step, actorsPromise);\n\n if (config.invariants) {\n for (const invariant of config.invariants) {\n await invariant({\n schema: config.schema,\n queryEngine,\n context: ctx,\n schedule,\n stepIndex,\n });\n }\n }\n\n if (history) {\n lastStateHash = await stateHasher({\n schema: config.schema,\n queryEngine,\n });\n const prefix = schedule.slice(0, stepIndex + 1);\n const added = history.add(buildPathKey(lastStateHash, prefix));\n if (added) {\n newPathsAdded = true;\n }\n }\n }\n\n await actorsPromise;\n\n if (!lastStateHash) {\n lastStateHash = await stateHasher({ schema: config.schema, queryEngine });\n }\n\n return { stateHash: lastStateHash, newPathsAdded };\n } finally {\n adapter.setScheduler(null);\n if (cleanup) {\n await cleanup();\n }\n }\n};\n\nconst executeScheduleDynamic = async <TSchema extends AnySchema, TUowConfig, TContext>(\n config: ModelCheckerActorsConfig<TSchema, TUowConfig, TContext>,\n history: HistoryTracker | null,\n stateHasher: (ctx: ModelCheckerStateHasherContext<TSchema, TUowConfig>) => Promise<string>,\n pickIndex: (pending: PendingGate[]) => number,\n): Promise<{ schedule: ModelCheckerStep[]; stateHash: string; newPathsAdded: boolean }> => {\n const { adapter, ctx, queryEngine, cleanup } = await config.createContext();\n\n try {\n if (config.setup) {\n await config.setup(ctx);\n }\n\n const scheduler = new PhaseScheduler(\"schedule\");\n adapter.setScheduler(scheduler);\n\n const actors = config.buildActors(ctx);\n const actorsPromise = Promise.all(actors.map((actor) => actor.run(ctx))).then(() => {\n scheduler.markActorsDone();\n });\n\n const schedule: ModelCheckerStep[] = [];\n let lastStateHash: string | null = null;\n let newPathsAdded = false;\n\n for (;;) {\n const step = await scheduler.releaseAny(pickIndex, actorsPromise);\n if (!step) {\n break;\n }\n\n schedule.push(step);\n const stepIndex = schedule.length - 1;\n\n if (config.invariants) {\n for (const invariant of config.invariants) {\n await invariant({\n schema: config.schema,\n queryEngine,\n context: ctx,\n schedule,\n stepIndex,\n });\n }\n }\n\n if (history) {\n lastStateHash = await stateHasher({\n schema: config.schema,\n queryEngine,\n });\n const prefix = schedule.slice(0, stepIndex + 1);\n const added = history.add(buildPathKey(lastStateHash, prefix));\n if (added) {\n newPathsAdded = true;\n }\n }\n }\n\n await actorsPromise;\n\n if (!lastStateHash) {\n lastStateHash = await stateHasher({ schema: config.schema, queryEngine });\n }\n\n return { schedule, stateHash: lastStateHash, newPathsAdded };\n } finally {\n adapter.setScheduler(null);\n if (cleanup) {\n await cleanup();\n }\n }\n};\n\nconst executeScheduleDynamicWithChoices = async <TSchema extends AnySchema, TUowConfig, TContext>(\n config: ModelCheckerActorsConfig<TSchema, TUowConfig, TContext>,\n history: HistoryTracker | null,\n stateHasher: (ctx: ModelCheckerStateHasherContext<TSchema, TUowConfig>) => Promise<string>,\n choices: number[],\n): Promise<{\n schedule: ModelCheckerStep[];\n stateHash: string;\n newPathsAdded: boolean;\n choicePoints: number[];\n}> => {\n const choicePoints: number[] = [];\n const result = await executeScheduleDynamic(config, history, stateHasher, (pending) => {\n const stepIndex = choicePoints.length;\n choicePoints.push(pending.length);\n const choice = choices[stepIndex];\n if (choice === undefined || choice < 0 || choice >= pending.length) {\n return 0;\n }\n return choice;\n });\n\n return {\n ...result,\n choicePoints,\n };\n};\n\nconst serializeChoices = (choices: number[]): string => choices.join(\",\");\n\nexport const runModelCheckerWithActors = async <TSchema extends AnySchema, TUowConfig, TContext>(\n config: ModelCheckerActorsConfig<TSchema, TUowConfig, TContext>,\n): Promise<ModelCheckerRunResult> => {\n const mode = config.mode ?? \"exhaustive\";\n const historyConfig = config.history ?? defaultHistoryConfig;\n const history = createHistoryTracker(historyConfig);\n const stateHasher = config.stateHasher ?? defaultStateHasher;\n const schedules: ModelCheckerScheduleResult[] = [];\n const maxSchedules = config.maxSchedules;\n const seed = config.seed ?? 1;\n\n if (mode === \"exhaustive\") {\n const plan = await recordPlan(config);\n const allSchedules = generateAllSchedules(plan.phasesPerTransaction);\n for (const schedule of allSchedules) {\n if (maxSchedules !== undefined && schedules.length >= maxSchedules) {\n break;\n }\n const result = await executeSchedule(schedule, config, plan, history, stateHasher);\n schedules.push({ schedule, stateHash: result.stateHash });\n }\n } else if (mode === \"bounded-exhaustive\") {\n const maxSteps = config.bounds?.maxSteps;\n if (!maxSteps || maxSteps < 1) {\n throw new Error(\"bounded-exhaustive mode requires bounds.maxSteps >= 1.\");\n }\n\n const stack: number[][] = [[]];\n const seen = new Set<string>();\n seen.add(\"\");\n\n while (stack.length > 0) {\n if (maxSchedules !== undefined && schedules.length >= maxSchedules) {\n break;\n }\n\n const choices = stack.pop();\n if (!choices) {\n break;\n }\n\n const result = await executeScheduleDynamicWithChoices(config, history, stateHasher, choices);\n schedules.push({ schedule: result.schedule, stateHash: result.stateHash });\n\n const limit = Math.min(result.choicePoints.length, maxSteps);\n for (let stepIndex = 0; stepIndex < limit; stepIndex += 1) {\n const count = result.choicePoints[stepIndex];\n const current = choices[stepIndex] ?? 0;\n for (let alt = current + 1; alt < count; alt += 1) {\n const next = choices.slice(0, stepIndex);\n next[stepIndex] = alt;\n const key = serializeChoices(next);\n if (!seen.has(key)) {\n seen.add(key);\n stack.push(next);\n }\n }\n }\n }\n } else if (mode === \"random\") {\n const rng = mulberry32(seed);\n const total = maxSchedules ?? 1;\n for (let i = 0; i < total; i += 1) {\n const result = await executeScheduleDynamic(config, history, stateHasher, (pending) =>\n Math.floor(rng() * pending.length),\n );\n schedules.push({ schedule: result.schedule, stateHash: result.stateHash });\n }\n } else {\n const rng = mulberry32(seed);\n const stopWhenFrontierExhausted = config.stopWhenFrontierExhausted ?? false;\n let iterations = 0;\n let frontierExhausted = false;\n\n while (!frontierExhausted) {\n if (maxSchedules !== undefined && iterations >= maxSchedules) {\n break;\n }\n const result = await executeScheduleDynamic(config, history, stateHasher, (pending) =>\n Math.floor(rng() * pending.length),\n );\n schedules.push({ schedule: result.schedule, stateHash: result.stateHash });\n iterations += 1;\n\n if (stopWhenFrontierExhausted && history) {\n frontierExhausted = !result.newPathsAdded;\n }\n }\n }\n\n return {\n schedules,\n visitedPaths: history?.size() ?? 0,\n };\n};\n"],"mappings":"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"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { ModelCheckerPhase } from "./model-checker.js";
|
|
2
|
-
import { DatabaseAdapter, DatabaseAdapterMetadata, DatabaseContextStorage, fragnoDatabaseAdapterNameFakeSymbol, fragnoDatabaseAdapterVersionFakeSymbol } from "@fragno-dev/db/adapters";
|
|
3
2
|
import { AnySchema } from "@fragno-dev/db/schema";
|
|
3
|
+
import { DatabaseAdapter, DatabaseAdapterMetadata, DatabaseContextStorage, fragnoDatabaseAdapterNameFakeSymbol, fragnoDatabaseAdapterVersionFakeSymbol } from "@fragno-dev/db/adapters";
|
|
4
4
|
import { SimpleQueryInterface } from "@fragno-dev/db/query";
|
|
5
5
|
import { RequestContextStorage } from "@fragno-dev/core/internal/request-context-storage";
|
|
6
6
|
import { UOWInstrumentationContext } from "@fragno-dev/db/unit-of-work";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"model-checker-adapter.d.ts","names":[],"sources":["../src/model-checker-adapter.ts"],"sourcesContent":[],"mappings":";;;;;;;;
|
|
1
|
+
{"version":3,"file":"model-checker-adapter.d.ts","names":[],"sources":["../src/model-checker-adapter.ts"],"sourcesContent":[],"mappings":";;;;;;;;KAqBK,aAAA,SAAsB,kCAAkC,sBAAsB;AAA9E,KAEO,qBAAA,GAFM;EAAS,WAAA,EAGZ,aAHY;EAAkC,UAAA,EAI/C,aAJ+C;CAAsB;AAAO,cAwF7E,mBAxF6E,CAAA,aAAA,IAAA,CAAA,YAwF3B,eAxF2B,CAwFX,UAxFW,CAAA,CAAA;EAE9E,CAAA,OAAA;EAsFC,CACV,mCAAA,CAD6B,EAAA,MAAA;EAA+C,CAE5E,sCAAA,CAF4E,EAAA,MAAA;EAC5E,SAAA,cAAA,EAGwB,qBAHxB,CAG8C,sBAH9C,CAAA;EACA,SAAA,eAAA,CAAA,EAG0B,uBAH1B;EAE8C,SAAA,cAAA,EAEtB,eAFsB,CAEN,UAFM,CAAA,CAAA,gBAAA,CAAA;EAAtB,iBAAA,CAAA,EAGL,eAHK,CAGW,UAHX,CAAA,CAAA,mBAAA,CAAA;EACE,WAAA,CAAA,WAAA,EAOF,eAPE,CAOc,UAPd,CAAA;EACc,YAAA,CAAA,SAAA,EAiBjB,qBAjBiB,GAAA,IAAA,CAAA,EAAA,IAAA;EAAhB,wBAAA,CAAA,CAAA,EAqBG,eArBH,CAqBmB,UArBnB,CAAA;EACW,gBAAA,CAAA,SAAA,EAAA,MAAA,CAAA,EAwBC,OAxBD,CAAA,MAAA,GAAA,SAAA,CAAA;EAAhB,iBAAA,CAAA,gBA4Bc,SA5Bd,CAAA,CAAA,MAAA,EA6BV,CA7BU,EAAA,SAAA,EAAA,MAAA,GAAA,IAAA,CAAA,EA+BjB,oBA/BiB,CA+BI,CA/BJ,EA+BO,UA/BP,CAAA;EAKqB,mBAAA,CAAA,CAAA,EAwElB,OAxEkB,CAAA,OAAA,CAAA;EAAhB,KAAA,CAAA,CAAA,EA4EhB,OA5EgB,CAAA,IAAA,CAAA"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"model-checker-adapter.js","names":["result: void | UOWInstrumentationInjection","#baseAdapter","#scheduler"],"sources":["../src/model-checker-adapter.ts"],"sourcesContent":["import type {
|
|
1
|
+
{"version":3,"file":"model-checker-adapter.js","names":["result: void | UOWInstrumentationInjection","#baseAdapter","#scheduler"],"sources":["../src/model-checker-adapter.ts"],"sourcesContent":["import type { RequestContextStorage } from \"@fragno-dev/core/internal/request-context-storage\";\nimport type {\n DatabaseAdapter,\n DatabaseAdapterMetadata,\n DatabaseContextStorage,\n} from \"@fragno-dev/db/adapters\";\nimport {\n fragnoDatabaseAdapterNameFakeSymbol,\n fragnoDatabaseAdapterVersionFakeSymbol,\n} from \"@fragno-dev/db/adapters\";\nimport type { SimpleQueryInterface } from \"@fragno-dev/db/query\";\nimport type { AnySchema } from \"@fragno-dev/db/schema\";\nimport type {\n UOWInstrumentation,\n UOWInstrumentationContext,\n UOWInstrumentationInjection,\n UOWInstrumentationFinalizer,\n} from \"@fragno-dev/db/unit-of-work\";\n\nimport type { ModelCheckerPhase } from \"./model-checker\";\n\ntype SchedulerHook = (ctx: UOWInstrumentationContext, phase: ModelCheckerPhase) => Promise<void>;\n\nexport type ModelCheckerScheduler = {\n beforePhase: SchedulerHook;\n afterPhase: SchedulerHook;\n};\n\nconst isInstrumentationInjection = (value: unknown): value is UOWInstrumentationInjection => {\n if (!value || typeof value !== \"object\") {\n return false;\n }\n const candidate = value as { type?: string };\n return candidate.type === \"conflict\" || candidate.type === \"error\";\n};\n\nconst mergeHook = (\n primary: UOWInstrumentation[keyof UOWInstrumentation] | undefined,\n secondary: UOWInstrumentation[keyof UOWInstrumentation] | undefined,\n options: { alwaysCallSecondary?: boolean } = {},\n): UOWInstrumentation[keyof UOWInstrumentation] | undefined => {\n if (!primary && !secondary) {\n return undefined;\n }\n\n const hook = async (\n ctx: UOWInstrumentationContext,\n ): Promise<void | UOWInstrumentationInjection> => {\n let result: void | UOWInstrumentationInjection;\n if (options.alwaysCallSecondary) {\n try {\n result = await primary?.(ctx);\n } finally {\n await secondary?.(ctx);\n }\n } else {\n result = await primary?.(ctx);\n if (!isInstrumentationInjection(result)) {\n const secondaryResult = await secondary?.(ctx);\n if (isInstrumentationInjection(secondaryResult)) {\n return secondaryResult;\n }\n }\n }\n\n if (isInstrumentationInjection(result)) {\n return result;\n }\n\n return undefined;\n };\n\n return hook as UOWInstrumentation[keyof UOWInstrumentation];\n};\n\nconst mergeInstrumentation = (\n existing: UOWInstrumentation | undefined,\n scheduler: ModelCheckerScheduler | null,\n): {\n instrumentation?: UOWInstrumentation;\n instrumentationFinalizer?: UOWInstrumentationFinalizer;\n} => {\n if (!scheduler) {\n return { instrumentation: existing };\n }\n\n const schedulerBeforeRetrieve = (ctx: UOWInstrumentationContext) =>\n scheduler.beforePhase(ctx, \"retrieve\");\n const schedulerAfterRetrieve = (ctx: UOWInstrumentationContext) =>\n scheduler.afterPhase(ctx, \"retrieve\");\n const schedulerBeforeMutate = (ctx: UOWInstrumentationContext) =>\n scheduler.beforePhase(ctx, \"mutate\");\n const schedulerAfterMutate = (ctx: UOWInstrumentationContext) =>\n scheduler.afterPhase(ctx, \"mutate\");\n\n return {\n instrumentation: {\n beforeRetrieve: mergeHook(schedulerBeforeRetrieve, existing?.beforeRetrieve),\n afterRetrieve: existing?.afterRetrieve,\n beforeMutate: mergeHook(schedulerBeforeMutate, existing?.beforeMutate),\n afterMutate: existing?.afterMutate,\n },\n instrumentationFinalizer: {\n afterRetrieve: schedulerAfterRetrieve,\n afterMutate: schedulerAfterMutate,\n },\n };\n};\n\nexport class ModelCheckerAdapter<TUowConfig = void> implements DatabaseAdapter<TUowConfig> {\n [fragnoDatabaseAdapterNameFakeSymbol]: string;\n [fragnoDatabaseAdapterVersionFakeSymbol]: number;\n\n readonly contextStorage: RequestContextStorage<DatabaseContextStorage>;\n readonly adapterMetadata?: DatabaseAdapterMetadata;\n readonly namingStrategy: DatabaseAdapter<TUowConfig>[\"namingStrategy\"];\n prepareMigrations?: DatabaseAdapter<TUowConfig>[\"prepareMigrations\"];\n\n #baseAdapter: DatabaseAdapter<TUowConfig>;\n #scheduler: ModelCheckerScheduler | null = null;\n\n constructor(baseAdapter: DatabaseAdapter<TUowConfig>) {\n this.#baseAdapter = baseAdapter;\n this.contextStorage = baseAdapter.contextStorage;\n this.adapterMetadata = baseAdapter.adapterMetadata;\n this.namingStrategy = baseAdapter.namingStrategy;\n this[fragnoDatabaseAdapterNameFakeSymbol] = baseAdapter[fragnoDatabaseAdapterNameFakeSymbol];\n this[fragnoDatabaseAdapterVersionFakeSymbol] =\n baseAdapter[fragnoDatabaseAdapterVersionFakeSymbol];\n this.prepareMigrations = baseAdapter.prepareMigrations?.bind(baseAdapter);\n }\n\n setScheduler(scheduler: ModelCheckerScheduler | null): void {\n this.#scheduler = scheduler;\n }\n\n getHookProcessingAdapter(): DatabaseAdapter<TUowConfig> {\n return this.#baseAdapter;\n }\n\n getSchemaVersion(namespace: string): Promise<string | undefined> {\n return this.#baseAdapter.getSchemaVersion(namespace);\n }\n\n createQueryEngine<const T extends AnySchema>(\n schema: T,\n namespace: string | null,\n ): SimpleQueryInterface<T, TUowConfig> {\n const engine = this.#baseAdapter.createQueryEngine(schema, namespace);\n\n const wrappedCreateUnitOfWork = (name?: string, config?: TUowConfig) => {\n const scheduler = this.#scheduler;\n if (!scheduler) {\n return engine.createUnitOfWork(name, config);\n }\n\n const configWithInstrumentation = (() => {\n if (!config || typeof config !== \"object\") {\n const merged = mergeInstrumentation(undefined, scheduler);\n return merged as TUowConfig;\n }\n\n const typedConfig = config as {\n instrumentation?: UOWInstrumentation;\n instrumentationFinalizer?: UOWInstrumentationFinalizer;\n };\n const merged = mergeInstrumentation(typedConfig.instrumentation, scheduler);\n return {\n ...typedConfig,\n instrumentation: merged.instrumentation,\n instrumentationFinalizer:\n merged.instrumentationFinalizer ?? typedConfig.instrumentationFinalizer,\n } as TUowConfig;\n })();\n\n return engine.createUnitOfWork(name, configWithInstrumentation);\n };\n\n const proxy = new Proxy(engine, {\n get(target, prop, receiver) {\n if (prop === \"createUnitOfWork\") {\n return wrappedCreateUnitOfWork;\n }\n const value = Reflect.get(target, prop, receiver);\n if (typeof value === \"function\") {\n return value.bind(target);\n }\n return value;\n },\n });\n return proxy;\n }\n\n isConnectionHealthy(): Promise<boolean> {\n return this.#baseAdapter.isConnectionHealthy();\n }\n\n close(): Promise<void> {\n return this.#baseAdapter.close();\n }\n}\n"],"mappings":";;;AA4BA,MAAM,8BAA8B,UAAyD;AAC3F,KAAI,CAAC,SAAS,OAAO,UAAU,SAC7B,QAAO;CAET,MAAM,YAAY;AAClB,QAAO,UAAU,SAAS,cAAc,UAAU,SAAS;;AAG7D,MAAM,aACJ,SACA,WACA,UAA6C,EAAE,KACc;AAC7D,KAAI,CAAC,WAAW,CAAC,UACf;CAGF,MAAM,OAAO,OACX,QACgD;EAChD,IAAIA;AACJ,MAAI,QAAQ,oBACV,KAAI;AACF,YAAS,MAAM,UAAU,IAAI;YACrB;AACR,SAAM,YAAY,IAAI;;OAEnB;AACL,YAAS,MAAM,UAAU,IAAI;AAC7B,OAAI,CAAC,2BAA2B,OAAO,EAAE;IACvC,MAAM,kBAAkB,MAAM,YAAY,IAAI;AAC9C,QAAI,2BAA2B,gBAAgB,CAC7C,QAAO;;;AAKb,MAAI,2BAA2B,OAAO,CACpC,QAAO;;AAMX,QAAO;;AAGT,MAAM,wBACJ,UACA,cAIG;AACH,KAAI,CAAC,UACH,QAAO,EAAE,iBAAiB,UAAU;CAGtC,MAAM,2BAA2B,QAC/B,UAAU,YAAY,KAAK,WAAW;CACxC,MAAM,0BAA0B,QAC9B,UAAU,WAAW,KAAK,WAAW;CACvC,MAAM,yBAAyB,QAC7B,UAAU,YAAY,KAAK,SAAS;CACtC,MAAM,wBAAwB,QAC5B,UAAU,WAAW,KAAK,SAAS;AAErC,QAAO;EACL,iBAAiB;GACf,gBAAgB,UAAU,yBAAyB,UAAU,eAAe;GAC5E,eAAe,UAAU;GACzB,cAAc,UAAU,uBAAuB,UAAU,aAAa;GACtE,aAAa,UAAU;GACxB;EACD,0BAA0B;GACxB,eAAe;GACf,aAAa;GACd;EACF;;AAGH,IAAa,sBAAb,MAA2F;CACzF,CAAC;CACD,CAAC;CAED,AAAS;CACT,AAAS;CACT,AAAS;CACT;CAEA;CACA,aAA2C;CAE3C,YAAY,aAA0C;AACpD,QAAKC,cAAe;AACpB,OAAK,iBAAiB,YAAY;AAClC,OAAK,kBAAkB,YAAY;AACnC,OAAK,iBAAiB,YAAY;AAClC,OAAK,uCAAuC,YAAY;AACxD,OAAK,0CACH,YAAY;AACd,OAAK,oBAAoB,YAAY,mBAAmB,KAAK,YAAY;;CAG3E,aAAa,WAA+C;AAC1D,QAAKC,YAAa;;CAGpB,2BAAwD;AACtD,SAAO,MAAKD;;CAGd,iBAAiB,WAAgD;AAC/D,SAAO,MAAKA,YAAa,iBAAiB,UAAU;;CAGtD,kBACE,QACA,WACqC;EACrC,MAAM,SAAS,MAAKA,YAAa,kBAAkB,QAAQ,UAAU;EAErE,MAAM,2BAA2B,MAAe,WAAwB;GACtE,MAAM,YAAY,MAAKC;AACvB,OAAI,CAAC,UACH,QAAO,OAAO,iBAAiB,MAAM,OAAO;GAG9C,MAAM,mCAAmC;AACvC,QAAI,CAAC,UAAU,OAAO,WAAW,SAE/B,QADe,qBAAqB,QAAW,UAAU;IAI3D,MAAM,cAAc;IAIpB,MAAM,SAAS,qBAAqB,YAAY,iBAAiB,UAAU;AAC3E,WAAO;KACL,GAAG;KACH,iBAAiB,OAAO;KACxB,0BACE,OAAO,4BAA4B,YAAY;KAClD;OACC;AAEJ,UAAO,OAAO,iBAAiB,MAAM,0BAA0B;;AAejE,SAZc,IAAI,MAAM,QAAQ,EAC9B,IAAI,QAAQ,MAAM,UAAU;AAC1B,OAAI,SAAS,mBACX,QAAO;GAET,MAAM,QAAQ,QAAQ,IAAI,QAAQ,MAAM,SAAS;AACjD,OAAI,OAAO,UAAU,WACnB,QAAO,MAAM,KAAK,OAAO;AAE3B,UAAO;KAEV,CAAC;;CAIJ,sBAAwC;AACtC,SAAO,MAAKD,YAAa,qBAAqB;;CAGhD,QAAuB;AACrB,SAAO,MAAKA,YAAa,OAAO"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"model-checker.d.ts","names":[],"sources":["../src/model-checker.ts"],"sourcesContent":[],"mappings":";;;;;;
|
|
1
|
+
{"version":3,"file":"model-checker.d.ts","names":[],"sources":["../src/model-checker.ts"],"sourcesContent":[],"mappings":"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"}
|