@happyvertical/smrt-core 0.57.32 → 0.57.33

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.
@@ -2,7 +2,7 @@
2
2
  "version": "1.0.0",
3
3
  "timestamp": 0,
4
4
  "packageName": "@happyvertical/smrt-core",
5
- "packageVersion": "0.57.32",
5
+ "packageVersion": "0.57.33",
6
6
  "objects": {
7
7
  "@happyvertical/smrt-core:SmrtClass": {
8
8
  "name": "smrtclass",
@@ -3,18 +3,18 @@
3
3
  "sensitiveFieldsExcluded": true,
4
4
  "generatedAt": "1970-01-01T00:00:00.000Z",
5
5
  "packageName": "@happyvertical/smrt-core",
6
- "packageVersion": "0.57.32",
6
+ "packageVersion": "0.57.33",
7
7
  "sourceManifestPath": "dist/manifest.json",
8
8
  "agentDocPath": "AGENTS.md",
9
9
  "sourceHashes": {
10
- "manifest": "7d1109a2963406b400683204d48276f2b9ebdee2d8b11fb6c30d8d1452d5fe99",
11
- "packageJson": "0bf6bf65d2d7f03263a19caf78db044dd842a36e7e222f9b0baf3e962c973c11",
10
+ "manifest": "0b94da6d4daa3f7336a765a0ee07948c74627c88785b94a01454c77f09fc7159",
11
+ "packageJson": "3f3c55acc5cd39c63a89099e539cb3deb44cf813d299b01b38fae7e057c2fa6c",
12
12
  "agents": "952dd7df7461bd7657b346f3ea63f1d240a625863b6ceef7b0f6d4960f978068",
13
13
  "moduleDoc:agents/object-runtime.md": "fd2748649e820c2fe5960fa4a44c5f3e2a5afa57da89925e8b4cb3b53d67a07b",
14
14
  "moduleDoc:agents/revision-guard.md": "f6ea32a6860964c98aba14b93587f40b33c8f7d0deccb2c54d21bff45db3da42",
15
15
  "moduleDoc:agents/collection-reads.md": "39acea7faf3505d38bfb999e414f4c4c6f964ec7c3d19cc52993302c29223029",
16
16
  "moduleDoc:agents/query-bounds.md": "3a0601ddaf2bea4e90e3f22e16a2eb3508a6fb8c019e3fb2c1f930c90a377cd5",
17
- "moduleDoc:agents/data-query.md": "1b72411d441ce2285bf0c89674e7aa996832a58b552b23a6d43834b907d91355",
17
+ "moduleDoc:agents/data-query.md": "b75c84f716457d0229714ffeec686bf49bc68f25e698938f80c9d28ad8bb0160",
18
18
  "moduleDoc:agents/schema-paths.md": "aef1b6fd687d0dbe444d20bf318e7c62fb9ef063ead933d2fd8168b87fee032e",
19
19
  "moduleDoc:agents/deployment-phases.md": "e1036073f31d54db95de95e498c74cddce5e47f367d56ccc00aad69f4e5a28e1",
20
20
  "moduleDoc:agents/change-feed.md": "c3d6206758dd1d2e0475177e1938fb7d7b6cfe8a6c4d3c3b56ef62bc7bc7739d",
@@ -83,7 +83,6 @@
83
83
  "@noble/hashes": "^2.4.0",
84
84
  "@oxc-project/runtime": "^0.150.0",
85
85
  "cheerio": "^1.2.0",
86
- "fast-glob": "3.3.3",
87
86
  "import-meta-resolve": "4.2.0",
88
87
  "minimatch": "10.2.6",
89
88
  "oxc-transform": "0.150.0",
@@ -1174,7 +1173,7 @@
1174
1173
  {
1175
1174
  "path": "agents/data-query.md",
1176
1175
  "module": "data-query",
1177
- "content": "<!-- Module doc for packages/core/AGENTS.md. Linked from the Modules table there. -->\n\n# Bounded data queries (#2444)\n\n`normalizeDataQueryRequest()` and `normalizeDataQueryResult()` define the trust\nboundary for the transport-neutral table/report/content query envelope. A\ntrusted adapter supplies `DataQuerySchema`; callers receive only its declared\nprojectable, sortable, filterable, and facetable fields. The helpers validate\nand normalize but never execute SQL or decide tenant/principal access.\n\nUse `createDataQueryFingerprint()` for cache and result correlation. It omits\nrequest id and page position, canonicalizes equivalent filter/projection/facet\nforms, and adds the identity sort tie-break. Keep values scalar and request,\npage, and facet sizes positive and bounded. Results must stay within the schema\nbyte cap with declared field types preserved; datetimes are RFC 3339 instants,\nidentity fields are string/number/datetime-compatible, and JSON values are\nbounded by depth, container count, string size, and bytes before cloning.\n\nOnly normalized `DataQueryResult` envelopes cross REST, MCP, WebMCP, and browser\nboundaries. Adapter-specific report/content context wraps the base envelope; it\ndoes not add unsafe fields or SQL-like controls.\n"
1176
+ "content": "<!-- Module doc for packages/core/AGENTS.md. Linked from the Modules table there. -->\n\n# Bounded data queries (#2444)\n\n`normalizeDataQueryRequest()` and `normalizeDataQueryResult()` define the trust\nboundary for the transport-neutral table/report/content query envelope. A\ntrusted adapter supplies `DataQuerySchema`; callers receive only its declared\nprojectable, sortable, filterable, and facetable fields. The helpers validate\nand normalize but never execute SQL or decide tenant/principal access.\n\nUse `createDataQueryFingerprint()` for cache and result correlation. It omits\nrequest id and page position, canonicalizes equivalent filter/projection/facet\nforms, and adds the identity sort tie-break. Keep values scalar and request,\npage, and facet sizes positive and bounded. Results must stay within the schema\nbyte cap with declared field types preserved; datetimes are RFC 3339 instants,\nidentity fields are string/number/datetime-compatible, and JSON values are\nbounded by depth, container count, string size, and bytes before cloning.\n\n## Allowed field values (#4381)\n\nA `string`, `number`, or `boolean` field may declare `values`: a closed set of\n`{ value, label?, description? }` entries in declaration order, so an agent can\nmap \"open\" onto `status in [pending, in_progress]`. Values are host-declared\nschema, never inferred from rows. `normalizeDataQuerySchema()` (via the\nexported `normalizeDataQueryFieldValues()`) requires a non-empty, duplicate-free\nlist of at most `MAX_DATA_QUERY_FIELD_VALUES` (100) entries whose values match\nthe field type; value, label, and description text are bounded\n(`MAX_DATA_QUERY_FIELD_VALUE_LENGTH` 256, `..._LABEL_LENGTH` 128,\n`..._DESCRIPTION_LENGTH` 512) and reject Unicode control, format (bidi,\nzero-width), surrogate, and line/paragraph-separator characters. Declared values\nare enforced by default: non-null `eq`/`ne`/`in`/`notIn` filter values must be\nmembers, or the request fails with `DATA_QUERY_VALUE_NOT_ALLOWED` and a message\nlisting the allowed values. The message and `details.allowedValues` both stop\nat the first 20 values; `details.allowedValueCount` gives the full size.\n`ne`/`notIn` are checked too: a misspelled value there would otherwise\nsilently match every row. `valuesEnforced: false` (valid only with `values`) marks the set advisory and\nskips that check; the normalized schema keeps only the `false` form. Range and\n`like` operators, result rows, and facets are never checked against the set.\n\nOnly normalized `DataQueryResult` envelopes cross REST, MCP, WebMCP, and browser\nboundaries. Adapter-specific report/content context wraps the base envelope; it\ndoes not add unsafe fields or SQL-like controls.\n"
1178
1177
  },
1179
1178
  {
1180
1179
  "path": "agents/schema-paths.md",
@@ -1 +1 @@
1
- {"version":3,"file":"database.d.ts","sourceRoot":"","sources":["../../src/testing/database.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AA0J5D;;GAEG;AACH,MAAM,WAAW,mBAAmB;IAClC;;;;;;OAMG;IACH,IAAI,CAAC,EAAE,QAAQ,GAAG,MAAM,GAAG,QAAQ,GAAG,UAAU,CAAC;IAEjD;;;;OAIG;IACH,GAAG,CAAC,EAAE,MAAM,CAAC;IAEb;;;OAGG;IACH,EAAE,CAAC,EAAE,iBAAiB,CAAC;IAEvB;;;OAGG;IACH,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;IAEnB;;;OAGG;IACH,mBAAmB,CAAC,EAAE,OAAO,CAAC;IAE9B;;;;;OAKG;IACH,yBAAyB,CAAC,EAAE,OAAO,CAAC;CACrC;AAED,6EAA6E;AAC7E,wBAAgB,4BAA4B,CAC1C,IAAI,EAAE,mBAAmB,CAAC,MAAM,CAAC,EACjC,EAAE,EAAE,iBAAiB,EACrB,iBAAiB,UAAQ,GACxB,QAAQ,GAAG,MAAM,GAAG,QAAQ,GAAG,UAAU,CAwC3C;AA4DD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6CG;AACH,wBAAsB,eAAe,CACnC,OAAO,GAAE,mBAAwB,GAChC,OAAO,CAAC,iBAAiB,CAAC,CAgQ5B"}
1
+ {"version":3,"file":"database.d.ts","sourceRoot":"","sources":["../../src/testing/database.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AAmL5D;;GAEG;AACH,MAAM,WAAW,mBAAmB;IAClC;;;;;;OAMG;IACH,IAAI,CAAC,EAAE,QAAQ,GAAG,MAAM,GAAG,QAAQ,GAAG,UAAU,CAAC;IAEjD;;;;OAIG;IACH,GAAG,CAAC,EAAE,MAAM,CAAC;IAEb;;;OAGG;IACH,EAAE,CAAC,EAAE,iBAAiB,CAAC;IAEvB;;;OAGG;IACH,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;IAEnB;;;OAGG;IACH,mBAAmB,CAAC,EAAE,OAAO,CAAC;IAE9B;;;;;OAKG;IACH,yBAAyB,CAAC,EAAE,OAAO,CAAC;CACrC;AAED,6EAA6E;AAC7E,wBAAgB,4BAA4B,CAC1C,IAAI,EAAE,mBAAmB,CAAC,MAAM,CAAC,EACjC,EAAE,EAAE,iBAAiB,EACrB,iBAAiB,UAAQ,GACxB,QAAQ,GAAG,MAAM,GAAG,QAAQ,GAAG,UAAU,CAwC3C;AA4DD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6CG;AACH,wBAAsB,eAAe,CACnC,OAAO,GAAE,mBAAwB,GAChC,OAAO,CAAC,iBAAiB,CAAC,CAiQ5B"}
@@ -11,6 +11,23 @@ import { SchemaGenerator } from "../schema/generator.js";
11
11
  import { planForeignKeyCreation } from "../schema/foreign-key-planner.js";
12
12
  import { getDatabase } from "@happyvertical/sql";
13
13
  //#region src/testing/database.ts
14
+ /**
15
+ * Strip crash durability from a fresh local file-backed SQLite test database.
16
+ *
17
+ * Opening with `__smrtSkipVitestSchemaPreparation` also bypasses smrt-vitest's
18
+ * speed pragmas (#2221), so every commit here would otherwise fsync: on a
19
+ * loaded host that made a single ingestion fixture take 15 s. Mirrors
20
+ * smrt-vitest's `applySqliteSpeedPragmas()`; best-effort, never fails setup.
21
+ */
22
+ async function applySqliteTestPragmas(db, type, url) {
23
+ if ((type ?? "sqlite") !== "sqlite") return;
24
+ if (/^(:memory:|memory$|file::memory:|https?:\/\/|libsql:\/\/)/.test(url)) return;
25
+ try {
26
+ await db.query("PRAGMA synchronous = OFF");
27
+ await db.query("PRAGMA journal_mode = MEMORY");
28
+ await db.query("PRAGMA temp_store = MEMORY");
29
+ } catch {}
30
+ }
14
31
  function resolveSTIBaseRegistration(className, stiBaseName) {
15
32
  const registered = ObjectRegistry.getClass(className);
16
33
  if (stiBaseName.includes(":")) return ObjectRegistry.getClass(stiBaseName);
@@ -154,6 +171,7 @@ async function getTestDatabase(options = {}) {
154
171
  url,
155
172
  __smrtSkipVitestSchemaPreparation: true
156
173
  });
174
+ if (!existingDb) await applySqliteTestPragmas(db, type, url);
157
175
  if (includeSystemTables) await initializeSystemTables(db);
158
176
  const isImplicitClassList = classes === void 0;
159
177
  const classNames = resolveRequestedSchemaClassNames(classes ?? ObjectRegistry.getQualifiedClassNames());
@@ -1 +1 @@
1
- {"version":3,"file":"database.js","names":[],"sources":["../../src/testing/database.ts"],"sourcesContent":["/**\n * Test database utilities for SMRT framework\n *\n * Provides `getTestDatabase()` which creates an in-memory database with all\n * registered SMRT object schemas. Uses the same schema generation logic as\n * the migration system to ensure consistency between test and production.\n *\n * @example\n * ```typescript\n * import { getTestDatabase } from '@happyvertical/smrt-core/testing';\n *\n * beforeEach(async () => {\n * const db = await getTestDatabase();\n * collection = await MyCollection.create({ db });\n * });\n * ```\n */\n\nimport type { DatabaseInterface } from '@happyvertical/sql';\nimport { getDatabase } from '@happyvertical/sql';\nimport { ensurePostgresChangeFeedAppendFunction } from '../change-feed.js';\nimport {\n type CollectionRegistrationLookup,\n isCollectionRegistration,\n resolveCollectionItemClassName,\n resolveRelatedRegistration,\n} from '../registry/collection-resolution.js';\nimport { recordRegistryDiagnostic } from '../registry/diagnostics.js';\nimport { isFrameworkBaseClass } from '../registry/framework-base-classes.js';\nimport { ObjectRegistry } from '../registry.js';\nimport { detectEngine } from '../schema/ddl/index.js';\nimport {\n schemaForeignKeys,\n schemaForeignKeysForEngine,\n} from '../schema/foreign-key-ddl.js';\nimport { planForeignKeyCreation } from '../schema/foreign-key-planner.js';\nimport { SchemaGenerator } from '../schema/generator.js';\nimport type { SchemaDefinition } from '../schema/types.js';\nimport { ensureLegacySystemTableCompatibility } from '../system/compatibility.js';\nimport { getSystemTableDDL } from '../system/schema.js';\n\ntype TestDatabaseConnectionOptions = Parameters<typeof getDatabase>[0] & {\n __smrtSkipVitestSchemaPreparation?: boolean;\n};\n\nfunction resolveSTIBaseRegistration(className: string, stiBaseName: string) {\n const registered = ObjectRegistry.getClass(className);\n\n if (stiBaseName.includes(':')) {\n return ObjectRegistry.getClass(stiBaseName);\n }\n\n if (registered?.packageName) {\n const samePackageBase = ObjectRegistry.getClassInPackage(\n registered.packageName,\n stiBaseName,\n );\n if (samePackageBase) {\n return samePackageBase;\n }\n }\n\n return ObjectRegistry.getClass(stiBaseName);\n}\n\nfunction resolveSTIBaseLookupName(\n className: string,\n stiBaseName: string,\n): string {\n const stiBase = resolveSTIBaseRegistration(className, stiBaseName);\n return stiBase?.qualifiedName || stiBase?.name || stiBaseName;\n}\n\nfunction isSTIChild(className: string): boolean {\n const stiBaseName = ObjectRegistry.getSTIBase(className);\n if (!stiBaseName) {\n return false;\n }\n\n const registered = ObjectRegistry.getClass(className);\n const stiBase = resolveSTIBaseRegistration(className, stiBaseName);\n\n if (registered && stiBase) {\n return registered !== stiBase;\n }\n\n return stiBaseName !== className;\n}\n\ntype RegisteredSchemaClass = NonNullable<\n ReturnType<typeof ObjectRegistry.getClass>\n>;\n\nconst collectionRegistrationLookup: CollectionRegistrationLookup = {\n findClass: (className) => ObjectRegistry.getClass(className),\n findClassInPackage: (packageName, className) =>\n ObjectRegistry.getClassInPackage(packageName, className),\n getInheritanceChain: (className) =>\n ObjectRegistry.getInheritanceChain(className),\n};\n\nfunction resolveCollectionSchemaClassName(\n className: string,\n registered: RegisteredSchemaClass,\n): string {\n const itemClassName = resolveCollectionItemClassName(\n className,\n registered,\n collectionRegistrationLookup,\n );\n if (itemClassName) {\n const itemRegistration = resolveRelatedRegistration(\n itemClassName,\n registered,\n collectionRegistrationLookup,\n );\n const itemLookupName =\n itemRegistration?.qualifiedName ||\n itemRegistration?.name ||\n itemClassName;\n const stiBase = ObjectRegistry.getSTIBase(itemLookupName);\n return stiBase\n ? resolveSTIBaseLookupName(itemLookupName, stiBase)\n : itemLookupName;\n }\n\n const tableName =\n registered.schema?.tableName ||\n registered.config.tableName ||\n ObjectRegistry.getTableName(className);\n if (!tableName) {\n return className;\n }\n\n const collectionPackage = registered.packageName;\n\n for (const candidate of ObjectRegistry.getAllClasses().values()) {\n if (\n candidate === registered ||\n isCollectionRegistration(\n candidate.qualifiedName || candidate.name,\n candidate,\n collectionRegistrationLookup,\n )\n ) {\n continue;\n }\n\n const candidateTableName =\n candidate.schema?.tableName || candidate.config.tableName;\n if (candidateTableName !== tableName) {\n continue;\n }\n\n if (\n collectionPackage &&\n candidate.packageName &&\n candidate.packageName !== collectionPackage\n ) {\n continue;\n }\n\n const candidateLookupName = candidate.qualifiedName || candidate.name;\n const stiBase = ObjectRegistry.getSTIBase(candidateLookupName);\n return stiBase\n ? resolveSTIBaseLookupName(candidateLookupName, stiBase)\n : candidateLookupName;\n }\n\n return className;\n}\n\n/**\n * Options for creating a test database\n */\nexport interface TestDatabaseOptions {\n /**\n * Database type (default: 'sqlite')\n * - 'sqlite': SQLite database\n * - 'json': JSON adapter (stores data as JSON files with DuckDB for querying)\n * - 'duckdb': Native DuckDB database\n * - 'postgres': PostgreSQL database (normally supplied through `db`)\n */\n type?: 'sqlite' | 'json' | 'duckdb' | 'postgres';\n\n /**\n * Database URL (default: ':memory:')\n * Use ':memory:' for in-memory databases (fastest for tests)\n * Or provide a file path for persistent test databases\n */\n url?: string;\n\n /**\n * Pre-existing database to initialize schemas in.\n * If provided, `type` and `url` are ignored.\n */\n db?: DatabaseInterface;\n\n /**\n * Specific classes to setup schemas for.\n * If not provided, sets up schemas for all registered classes.\n */\n classes?: string[];\n\n /**\n * Whether to include system tables (default: true)\n * System tables include _smrt_contexts, _smrt_migrations, etc.\n */\n includeSystemTables?: boolean;\n\n /**\n * Explicitly omit physical FK constraints for adapter/query tests whose\n * subject is unrelated to referential enforcement. Defaults to `false`.\n * This is required (and deliberately noisy at the call site) when a DuckDB\n * fixture uses generated `ON UPDATE CASCADE`, which DuckDB cannot enforce.\n */\n omitForeignKeyConstraints?: boolean;\n}\n\n/** Resolve the DDL dialect used when preparing an existing test database. */\nexport function resolveTestDatabaseDDLEngine(\n type: TestDatabaseOptions['type'],\n db: DatabaseInterface,\n inferFromDatabase = false,\n): 'sqlite' | 'json' | 'duckdb' | 'postgres' {\n // When this helper created the adapter, the requested type is authoritative.\n // Native DuckDB and JSON-on-DuckDB both expose exportTable(), so capability\n // inference must not override an explicit native DuckDB request.\n if (!inferFromDatabase) {\n return type ?? 'sqlite';\n }\n\n const configuredDb = db as DatabaseInterface & {\n config?: { type?: string; url?: string };\n type?: string;\n exportTable?: unknown;\n inferSchemaFromJSON?: unknown;\n getTableLoadErrors?: unknown;\n };\n\n if (\n typeof configuredDb.inferSchemaFromJSON === 'function' ||\n typeof configuredDb.getTableLoadErrors === 'function'\n ) {\n return 'json';\n }\n\n if (typeof configuredDb.exportTable === 'function') {\n // The native DuckDB adapter exposes schema evolution capabilities that the\n // JSON adapter does not. Keep exportTable-only test doubles compatible with\n // the historical JSON structural marker.\n if (\n typeof configuredDb.getTableSchema === 'function' &&\n typeof configuredDb.alterTable?.addColumn === 'function'\n ) {\n return 'duckdb';\n }\n return 'json';\n }\n\n return detectEngine(\n db.url || configuredDb.config?.url || '',\n configuredDb.type || configuredDb.config?.type,\n );\n}\n\nfunction omitTestForeignKeyConstraints(\n schema: SchemaDefinition,\n): SchemaDefinition {\n const foreignKeyTargets = new Set(\n schemaForeignKeys(schema).map((foreignKey) => foreignKey.referencesTable),\n );\n return {\n ...schema,\n columns: Object.fromEntries(\n Object.entries(schema.columns).map(([name, column]) => [\n name,\n column.foreignKey ? { ...column, foreignKey: undefined } : column,\n ]),\n ),\n foreignKeys: [],\n dependencies: schema.dependencies.filter(\n (dependency) => !foreignKeyTargets.has(dependency),\n ),\n };\n}\n\nfunction resolveRequestedSchemaClassName(className: string): string {\n const registered = ObjectRegistry.getClass(className);\n if (!registered) {\n return className;\n }\n\n if (\n !isCollectionRegistration(\n className,\n registered,\n collectionRegistrationLookup,\n )\n ) {\n const stiBase = ObjectRegistry.getSTIBase(className);\n return stiBase ? resolveSTIBaseLookupName(className, stiBase) : className;\n }\n\n return resolveCollectionSchemaClassName(className, registered);\n}\n\nfunction resolveRequestedSchemaClassNames(classNames: string[]): string[] {\n const resolved: string[] = [];\n const seen = new Set<string>();\n\n for (const className of classNames) {\n const schemaClassName = resolveRequestedSchemaClassName(className);\n if (seen.has(schemaClassName)) {\n continue;\n }\n\n seen.add(schemaClassName);\n resolved.push(schemaClassName);\n }\n\n return resolved;\n}\n\n/**\n * Creates an in-memory test database with schemas pre-created\n *\n * This utility is designed for testing. It creates an in-memory database\n * and initializes all registered SMRT object schemas using the **same\n * schema generation logic** as the production migration system.\n *\n * **Key features:**\n * - Uses `SchemaGenerator.generateSQL()` - the single source of truth for DDL\n * - Handles STI (Single Table Inheritance) correctly\n * - Creates system tables for framework functionality\n * - Safe for parallel test execution: each call creates an isolated\n * in-memory instance with its own embedded write-queue identity, so\n * unrelated `:memory:` databases never serialize writes against each\n * other (#2707). A `cache=shared` URL is the deliberate exception: it\n * asks SQLite/DuckDB to genuinely share the underlying database, so it\n * keeps sharing one write-queue identity too.\n *\n * @param options - Configuration options\n * @returns Promise resolving to configured DatabaseInterface\n *\n * @example\n * ```typescript\n * // Basic usage - all registered schemas\n * const db = await getTestDatabase();\n *\n * // Specific classes only\n * const db = await getTestDatabase({ classes: ['Council', 'Meeting'] });\n *\n * // JSON adapter instead of SQLite\n * const db = await getTestDatabase({ type: 'json' });\n *\n * // Native DuckDB adapter\n * const db = await getTestDatabase({ type: 'duckdb', url: ':memory:' });\n *\n * // File-based database for persistent tests\n * const db = await getTestDatabase({ type: 'sqlite', url: '/tmp/test.db' });\n *\n * // Initialize schemas in an existing database\n * const myDb = await getDatabase({ type: 'sqlite', url: ':memory:' });\n * await getTestDatabase({ db: myDb });\n *\n * // Skip system tables (rare use case)\n * const db = await getTestDatabase({ includeSystemTables: false });\n * ```\n */\nexport async function getTestDatabase(\n options: TestDatabaseOptions = {},\n): Promise<DatabaseInterface> {\n const {\n type,\n url = ':memory:',\n db: existingDb,\n classes,\n includeSystemTables = true,\n omitForeignKeyConstraints = false,\n } = options;\n\n // Use existing database or create new one\n const db =\n existingDb ??\n (await getDatabase({\n type: type ?? 'sqlite',\n url,\n __smrtSkipVitestSchemaPreparation: true,\n } as TestDatabaseConnectionOptions));\n\n // Initialize system tables (same as production)\n if (includeSystemTables) {\n await initializeSystemTables(db);\n }\n\n // Get class names to setup. The framework-base filter below only applies\n // when the caller left `classes` implicit: an explicit list naming a\n // framework base class must still be honored (#2645).\n const isImplicitClassList = classes === undefined;\n const classNames = resolveRequestedSchemaClassNames(\n classes ?? ObjectRegistry.getQualifiedClassNames(),\n );\n\n // Skip if no classes registered. When the caller left `classes` implicit,\n // an empty registry usually means registration never reached this\n // process/module instance of ObjectRegistry (e.g. a Vitest plugin hook\n // registering manifests in a different worker/process than the test code\n // — #2750) rather than a deliberate \"system tables only\" setup. Warn (never\n // throw by default) so that failure surfaces here instead of as a much\n // later, harder-to-diagnose \"no such table\" error. An explicit empty\n // `classes: []` array is a deliberate choice and stays silent.\n if (classNames.length === 0) {\n if (isImplicitClassList) {\n const emptyRegistryMessage =\n 'getTestDatabase() found zero registered classes in ObjectRegistry and ' +\n 'created only system tables. If you expected model tables, the ' +\n 'registry is likely empty in this process — for smrt-vitest ' +\n 'consumers, confirm registration (smrtVitestPlugin() manifest ' +\n 'loading, or your setupFiles) actually runs in the same process ' +\n 'as your test code, or pass an explicit `classes` list to ' +\n 'getTestDatabase() to opt out of this check.';\n // recordRegistryDiagnostic('warn', ...) only buffers -- nothing reads\n // that buffer automatically (only strict-mode 'error' severity throws;\n // printing the buffer requires an explicit flushRegistryDiagnostics()\n // call this package never makes). Pair it with an immediate\n // console.warn so the failure is actually visible at the point of the\n // problem, which is the entire point of this diagnostic (#2750) --\n // the buffered record stays available for programmatic inspection via\n // getRegistryDiagnostics().\n console.warn(`[getTestDatabase] ${emptyRegistryMessage}`);\n recordRegistryDiagnostic(\n 'warn',\n 'TEST_DATABASE_EMPTY_IMPLICIT_REGISTRY',\n emptyRegistryMessage,\n );\n }\n return db;\n }\n\n // Use the same schema generation as production\n const schemaGenerator = new SchemaGenerator();\n const ddlEngine = resolveTestDatabaseDDLEngine(\n type,\n db,\n existingDb !== undefined,\n );\n\n // Collect every table before executing DDL so dependency ordering and cycle\n // handling are identical to production migration/schema paths (#2413).\n const schemas = new Map<\n string,\n { schema: SchemaDefinition; className: string }\n >();\n const authoritativeSchemas = ObjectRegistry.getAllSchemasAsDefinitions();\n\n for (const className of classNames) {\n // R11: the registration carries idType (native uuid vs text); read it\n // below when building runtimeSchemaConfig.\n const registered = ObjectRegistry.getClass(className);\n // Skip STI children - their schema is part of the base class table.\n // main (#1324): isSTIChild() compares RegisteredClass *identity* rather\n // than raw strings, so it stays correct under R5-canon (getSTIBase returns\n // qualified names) while also handling collection/override registrations.\n if (isSTIChild(className)) {\n continue;\n }\n\n // Framework abstract base classes (SmrtObject, SmrtClass, ...) are\n // scaffolding, not resources, and produce phantom smrt_objects/\n // smrt_classes/smrt_collections/smrt_hierarchicals/\n // smrt_polymorphic_associations tables when the default registry\n // snapshot happens to include them (#2645). Mirrors the production\n // `buildMergedTableSchemas()` filter in `registry/schema-builder.ts`, but\n // only for the implicit class list — an explicit `classes: [...]` caller\n // that names a framework base class is still honored.\n if (\n isImplicitClassList &&\n isFrameworkBaseClass(registered?.name, registered?.packageName)\n ) {\n continue;\n }\n\n const tableName = ObjectRegistry.getTableName(className);\n if (!tableName || schemas.has(tableName)) {\n continue;\n }\n\n const fields = await ObjectRegistry.getAllFields(className);\n const strategy = ObjectRegistry.getTableStrategy(className);\n // Mirrors `schema/utils.ts`: this bag is rebuilt by hand, so every `@smrt()`\n // option the generator reads has to be listed or tests silently diverge\n // from the production schema. `indexes` (#2357) was missing from both.\n const runtimeSchemaConfig = {\n conflictColumns: ObjectRegistry.getConflictColumns(className),\n idType: registered?.config.idType,\n indexes: registered?.config.indexes,\n registry: ObjectRegistry,\n };\n\n // Generate schema through the registry paths. Production (`manifest.json`\n // and therefore `smrt db:migrate`) uses the manifest paths\n // (`generateSTISchemaFromManifest` / `generateCTISchemaFromManifest`);\n // the two families are held to the same column and index sets by\n // `src/schema/schema-path-parity.test.ts` (#2359) — do not assume they\n // agree by construction.\n const schema =\n strategy === 'sti'\n ? await schemaGenerator.generateSTISchemaFromRegistry(\n className,\n tableName,\n fields,\n runtimeSchemaConfig,\n )\n : schemaGenerator.generateSchemaFromRegistry(\n className,\n tableName,\n fields,\n runtimeSchemaConfig,\n );\n\n // Manifest registrations can carry explicit FK actions that differ from\n // decorator defaults. The deterministic merged table schema preserves\n // those authoritative actions while still backfilling runtime-only fields.\n const authoritativeSchema = authoritativeSchemas[tableName];\n const effectiveColumns = authoritativeSchema\n ? Object.fromEntries(\n Object.entries(schema.columns).map(([name, column]) => {\n const manifestColumn = authoritativeSchema.columns[name];\n return [\n name,\n manifestColumn\n ? { ...column, foreignKey: manifestColumn.foreignKey }\n : column,\n ];\n }),\n )\n : schema.columns;\n const effectiveForeignKeys = schemaForeignKeys({\n columns: effectiveColumns,\n foreignKeys: [],\n });\n const effectiveSchema: SchemaDefinition = {\n ...schema,\n columns: effectiveColumns,\n foreignKeys: effectiveForeignKeys,\n dependencies: effectiveForeignKeys\n .map((foreignKey) => foreignKey.referencesTable)\n .filter((dependency) => dependency !== tableName),\n };\n\n schemas.set(tableName, {\n schema: omitForeignKeyConstraints\n ? omitTestForeignKeyConstraints(effectiveSchema)\n : effectiveSchema,\n className,\n });\n }\n\n // Explicitly requested test classes still need their registered parents.\n // Add the authoritative dependency closure so a child-only request cannot\n // emit a physical reference to a table this helper never creates.\n const addDependencies = (schema: SchemaDefinition): void => {\n for (const foreignKey of schemaForeignKeysForEngine(schema, ddlEngine)) {\n if (schemas.has(foreignKey.referencesTable)) continue;\n const dependency = authoritativeSchemas[foreignKey.referencesTable];\n if (!dependency) continue;\n const effectiveDependency = omitForeignKeyConstraints\n ? omitTestForeignKeyConstraints(dependency)\n : dependency;\n schemas.set(dependency.tableName, {\n schema: effectiveDependency,\n className: dependency.tableName,\n });\n addDependencies(effectiveDependency);\n }\n };\n for (const { schema } of [...schemas.values()]) addDependencies(schema);\n\n const tablePlan = planForeignKeyCreation(\n [...schemas.values()].map(({ schema }) => schema),\n ddlEngine,\n );\n const ddlStrategy = (await import('../schema/ddl/index.js')).getDDLStrategy(\n ddlEngine,\n );\n\n for (const schema of tablePlan.schemas) {\n const className = schemas.get(schema.tableName)?.className ?? 'unknown';\n const ddl = schemaGenerator.generateSQL(schema, ddlEngine);\n\n try {\n await db.query(ddl);\n\n // Create indexes (use DDL strategy so jsonPath / where / etc. render)\n const indexStatements = ddlStrategy.generateIndexes(schema);\n for (const indexSQL of indexStatements) {\n try {\n await db.query(indexSQL);\n } catch (indexError) {\n // Log but don't fail on index creation errors\n // Some indexes may fail if columns don't exist (STI meta fields)\n console.warn(\n `[getTestDatabase] Warning: Failed to create index: ${indexError instanceof Error ? indexError.message : String(indexError)} (SQL: ${indexSQL})`,\n );\n }\n }\n } catch (error) {\n // Provide helpful error message for table creation failures\n throw new Error(\n `[getTestDatabase] Failed to create table '${schema.tableName}' for class '${className}': ${error instanceof Error ? error.message : String(error)}`,\n { cause: error },\n );\n }\n }\n\n for (const statement of tablePlan.deferredStatements) {\n try {\n await db.query(statement);\n } catch (error) {\n throw new Error(\n `[getTestDatabase] Failed to add deferred foreign-key constraint: ${error instanceof Error ? error.message : String(error)} (SQL: ${statement})`,\n { cause: error },\n );\n }\n }\n\n return db;\n}\n\n/**\n * Initialize SMRT system tables in a database\n *\n * System tables use _smrt_ prefix and store framework metadata.\n * All statements use `IF NOT EXISTS` for idempotency.\n *\n * @param db - Database interface to initialize\n */\nasync function initializeSystemTables(db: DatabaseInterface): Promise<void> {\n await ensureLegacySystemTableCompatibility(db);\n\n const configuredDb = db as DatabaseInterface & {\n config?: { type?: string; url?: string };\n type?: string;\n };\n const engine = detectEngine(\n db.url || configuredDb.config?.url || '',\n configuredDb.type || configuredDb.config?.type,\n );\n\n // Split multi-statement SQL into individual statements\n const allStatements: string[] = [];\n for (const multiStatementSQL of getSystemTableDDL(engine)) {\n const statements = multiStatementSQL\n .split(';')\n .map((s) => s.trim())\n .filter((s) => s.length > 0);\n allStatements.push(...statements);\n }\n\n // Use db.query() — system tables use CREATE TABLE/INDEX IF NOT EXISTS\n // which databases handle natively without per-column existence checks.\n for (const statement of allStatements) {\n await db.query(statement);\n }\n\n // PostgreSQL keeps the best-effort append boundary in a function that must\n // be executed whole rather than included in semicolon-split portable DDL.\n await ensurePostgresChangeFeedAppendFunction(db);\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"database.js","names":[],"sources":["../../src/testing/database.ts"],"sourcesContent":["/**\n * Test database utilities for SMRT framework\n *\n * Provides `getTestDatabase()` which creates an in-memory database with all\n * registered SMRT object schemas. Uses the same schema generation logic as\n * the migration system to ensure consistency between test and production.\n *\n * @example\n * ```typescript\n * import { getTestDatabase } from '@happyvertical/smrt-core/testing';\n *\n * beforeEach(async () => {\n * const db = await getTestDatabase();\n * collection = await MyCollection.create({ db });\n * });\n * ```\n */\n\nimport type { DatabaseInterface } from '@happyvertical/sql';\nimport { getDatabase } from '@happyvertical/sql';\nimport { ensurePostgresChangeFeedAppendFunction } from '../change-feed.js';\nimport {\n type CollectionRegistrationLookup,\n isCollectionRegistration,\n resolveCollectionItemClassName,\n resolveRelatedRegistration,\n} from '../registry/collection-resolution.js';\nimport { recordRegistryDiagnostic } from '../registry/diagnostics.js';\nimport { isFrameworkBaseClass } from '../registry/framework-base-classes.js';\nimport { ObjectRegistry } from '../registry.js';\nimport { detectEngine } from '../schema/ddl/index.js';\nimport {\n schemaForeignKeys,\n schemaForeignKeysForEngine,\n} from '../schema/foreign-key-ddl.js';\nimport { planForeignKeyCreation } from '../schema/foreign-key-planner.js';\nimport { SchemaGenerator } from '../schema/generator.js';\nimport type { SchemaDefinition } from '../schema/types.js';\nimport { ensureLegacySystemTableCompatibility } from '../system/compatibility.js';\nimport { getSystemTableDDL } from '../system/schema.js';\n\ntype TestDatabaseConnectionOptions = Parameters<typeof getDatabase>[0] & {\n __smrtSkipVitestSchemaPreparation?: boolean;\n};\n\n/**\n * Strip crash durability from a fresh local file-backed SQLite test database.\n *\n * Opening with `__smrtSkipVitestSchemaPreparation` also bypasses smrt-vitest's\n * speed pragmas (#2221), so every commit here would otherwise fsync: on a\n * loaded host that made a single ingestion fixture take 15 s. Mirrors\n * smrt-vitest's `applySqliteSpeedPragmas()`; best-effort, never fails setup.\n */\nasync function applySqliteTestPragmas(\n db: DatabaseInterface,\n type: string | undefined,\n url: string,\n): Promise<void> {\n if ((type ?? 'sqlite') !== 'sqlite') return;\n if (/^(:memory:|memory$|file::memory:|https?:\\/\\/|libsql:\\/\\/)/.test(url))\n return;\n try {\n await db.query('PRAGMA synchronous = OFF');\n await db.query('PRAGMA journal_mode = MEMORY');\n await db.query('PRAGMA temp_store = MEMORY');\n } catch {\n // An adapter that rejects pragmas keeps its defaults.\n }\n}\n\nfunction resolveSTIBaseRegistration(className: string, stiBaseName: string) {\n const registered = ObjectRegistry.getClass(className);\n\n if (stiBaseName.includes(':')) {\n return ObjectRegistry.getClass(stiBaseName);\n }\n\n if (registered?.packageName) {\n const samePackageBase = ObjectRegistry.getClassInPackage(\n registered.packageName,\n stiBaseName,\n );\n if (samePackageBase) {\n return samePackageBase;\n }\n }\n\n return ObjectRegistry.getClass(stiBaseName);\n}\n\nfunction resolveSTIBaseLookupName(\n className: string,\n stiBaseName: string,\n): string {\n const stiBase = resolveSTIBaseRegistration(className, stiBaseName);\n return stiBase?.qualifiedName || stiBase?.name || stiBaseName;\n}\n\nfunction isSTIChild(className: string): boolean {\n const stiBaseName = ObjectRegistry.getSTIBase(className);\n if (!stiBaseName) {\n return false;\n }\n\n const registered = ObjectRegistry.getClass(className);\n const stiBase = resolveSTIBaseRegistration(className, stiBaseName);\n\n if (registered && stiBase) {\n return registered !== stiBase;\n }\n\n return stiBaseName !== className;\n}\n\ntype RegisteredSchemaClass = NonNullable<\n ReturnType<typeof ObjectRegistry.getClass>\n>;\n\nconst collectionRegistrationLookup: CollectionRegistrationLookup = {\n findClass: (className) => ObjectRegistry.getClass(className),\n findClassInPackage: (packageName, className) =>\n ObjectRegistry.getClassInPackage(packageName, className),\n getInheritanceChain: (className) =>\n ObjectRegistry.getInheritanceChain(className),\n};\n\nfunction resolveCollectionSchemaClassName(\n className: string,\n registered: RegisteredSchemaClass,\n): string {\n const itemClassName = resolveCollectionItemClassName(\n className,\n registered,\n collectionRegistrationLookup,\n );\n if (itemClassName) {\n const itemRegistration = resolveRelatedRegistration(\n itemClassName,\n registered,\n collectionRegistrationLookup,\n );\n const itemLookupName =\n itemRegistration?.qualifiedName ||\n itemRegistration?.name ||\n itemClassName;\n const stiBase = ObjectRegistry.getSTIBase(itemLookupName);\n return stiBase\n ? resolveSTIBaseLookupName(itemLookupName, stiBase)\n : itemLookupName;\n }\n\n const tableName =\n registered.schema?.tableName ||\n registered.config.tableName ||\n ObjectRegistry.getTableName(className);\n if (!tableName) {\n return className;\n }\n\n const collectionPackage = registered.packageName;\n\n for (const candidate of ObjectRegistry.getAllClasses().values()) {\n if (\n candidate === registered ||\n isCollectionRegistration(\n candidate.qualifiedName || candidate.name,\n candidate,\n collectionRegistrationLookup,\n )\n ) {\n continue;\n }\n\n const candidateTableName =\n candidate.schema?.tableName || candidate.config.tableName;\n if (candidateTableName !== tableName) {\n continue;\n }\n\n if (\n collectionPackage &&\n candidate.packageName &&\n candidate.packageName !== collectionPackage\n ) {\n continue;\n }\n\n const candidateLookupName = candidate.qualifiedName || candidate.name;\n const stiBase = ObjectRegistry.getSTIBase(candidateLookupName);\n return stiBase\n ? resolveSTIBaseLookupName(candidateLookupName, stiBase)\n : candidateLookupName;\n }\n\n return className;\n}\n\n/**\n * Options for creating a test database\n */\nexport interface TestDatabaseOptions {\n /**\n * Database type (default: 'sqlite')\n * - 'sqlite': SQLite database\n * - 'json': JSON adapter (stores data as JSON files with DuckDB for querying)\n * - 'duckdb': Native DuckDB database\n * - 'postgres': PostgreSQL database (normally supplied through `db`)\n */\n type?: 'sqlite' | 'json' | 'duckdb' | 'postgres';\n\n /**\n * Database URL (default: ':memory:')\n * Use ':memory:' for in-memory databases (fastest for tests)\n * Or provide a file path for persistent test databases\n */\n url?: string;\n\n /**\n * Pre-existing database to initialize schemas in.\n * If provided, `type` and `url` are ignored.\n */\n db?: DatabaseInterface;\n\n /**\n * Specific classes to setup schemas for.\n * If not provided, sets up schemas for all registered classes.\n */\n classes?: string[];\n\n /**\n * Whether to include system tables (default: true)\n * System tables include _smrt_contexts, _smrt_migrations, etc.\n */\n includeSystemTables?: boolean;\n\n /**\n * Explicitly omit physical FK constraints for adapter/query tests whose\n * subject is unrelated to referential enforcement. Defaults to `false`.\n * This is required (and deliberately noisy at the call site) when a DuckDB\n * fixture uses generated `ON UPDATE CASCADE`, which DuckDB cannot enforce.\n */\n omitForeignKeyConstraints?: boolean;\n}\n\n/** Resolve the DDL dialect used when preparing an existing test database. */\nexport function resolveTestDatabaseDDLEngine(\n type: TestDatabaseOptions['type'],\n db: DatabaseInterface,\n inferFromDatabase = false,\n): 'sqlite' | 'json' | 'duckdb' | 'postgres' {\n // When this helper created the adapter, the requested type is authoritative.\n // Native DuckDB and JSON-on-DuckDB both expose exportTable(), so capability\n // inference must not override an explicit native DuckDB request.\n if (!inferFromDatabase) {\n return type ?? 'sqlite';\n }\n\n const configuredDb = db as DatabaseInterface & {\n config?: { type?: string; url?: string };\n type?: string;\n exportTable?: unknown;\n inferSchemaFromJSON?: unknown;\n getTableLoadErrors?: unknown;\n };\n\n if (\n typeof configuredDb.inferSchemaFromJSON === 'function' ||\n typeof configuredDb.getTableLoadErrors === 'function'\n ) {\n return 'json';\n }\n\n if (typeof configuredDb.exportTable === 'function') {\n // The native DuckDB adapter exposes schema evolution capabilities that the\n // JSON adapter does not. Keep exportTable-only test doubles compatible with\n // the historical JSON structural marker.\n if (\n typeof configuredDb.getTableSchema === 'function' &&\n typeof configuredDb.alterTable?.addColumn === 'function'\n ) {\n return 'duckdb';\n }\n return 'json';\n }\n\n return detectEngine(\n db.url || configuredDb.config?.url || '',\n configuredDb.type || configuredDb.config?.type,\n );\n}\n\nfunction omitTestForeignKeyConstraints(\n schema: SchemaDefinition,\n): SchemaDefinition {\n const foreignKeyTargets = new Set(\n schemaForeignKeys(schema).map((foreignKey) => foreignKey.referencesTable),\n );\n return {\n ...schema,\n columns: Object.fromEntries(\n Object.entries(schema.columns).map(([name, column]) => [\n name,\n column.foreignKey ? { ...column, foreignKey: undefined } : column,\n ]),\n ),\n foreignKeys: [],\n dependencies: schema.dependencies.filter(\n (dependency) => !foreignKeyTargets.has(dependency),\n ),\n };\n}\n\nfunction resolveRequestedSchemaClassName(className: string): string {\n const registered = ObjectRegistry.getClass(className);\n if (!registered) {\n return className;\n }\n\n if (\n !isCollectionRegistration(\n className,\n registered,\n collectionRegistrationLookup,\n )\n ) {\n const stiBase = ObjectRegistry.getSTIBase(className);\n return stiBase ? resolveSTIBaseLookupName(className, stiBase) : className;\n }\n\n return resolveCollectionSchemaClassName(className, registered);\n}\n\nfunction resolveRequestedSchemaClassNames(classNames: string[]): string[] {\n const resolved: string[] = [];\n const seen = new Set<string>();\n\n for (const className of classNames) {\n const schemaClassName = resolveRequestedSchemaClassName(className);\n if (seen.has(schemaClassName)) {\n continue;\n }\n\n seen.add(schemaClassName);\n resolved.push(schemaClassName);\n }\n\n return resolved;\n}\n\n/**\n * Creates an in-memory test database with schemas pre-created\n *\n * This utility is designed for testing. It creates an in-memory database\n * and initializes all registered SMRT object schemas using the **same\n * schema generation logic** as the production migration system.\n *\n * **Key features:**\n * - Uses `SchemaGenerator.generateSQL()` - the single source of truth for DDL\n * - Handles STI (Single Table Inheritance) correctly\n * - Creates system tables for framework functionality\n * - Safe for parallel test execution: each call creates an isolated\n * in-memory instance with its own embedded write-queue identity, so\n * unrelated `:memory:` databases never serialize writes against each\n * other (#2707). A `cache=shared` URL is the deliberate exception: it\n * asks SQLite/DuckDB to genuinely share the underlying database, so it\n * keeps sharing one write-queue identity too.\n *\n * @param options - Configuration options\n * @returns Promise resolving to configured DatabaseInterface\n *\n * @example\n * ```typescript\n * // Basic usage - all registered schemas\n * const db = await getTestDatabase();\n *\n * // Specific classes only\n * const db = await getTestDatabase({ classes: ['Council', 'Meeting'] });\n *\n * // JSON adapter instead of SQLite\n * const db = await getTestDatabase({ type: 'json' });\n *\n * // Native DuckDB adapter\n * const db = await getTestDatabase({ type: 'duckdb', url: ':memory:' });\n *\n * // File-based database for persistent tests\n * const db = await getTestDatabase({ type: 'sqlite', url: '/tmp/test.db' });\n *\n * // Initialize schemas in an existing database\n * const myDb = await getDatabase({ type: 'sqlite', url: ':memory:' });\n * await getTestDatabase({ db: myDb });\n *\n * // Skip system tables (rare use case)\n * const db = await getTestDatabase({ includeSystemTables: false });\n * ```\n */\nexport async function getTestDatabase(\n options: TestDatabaseOptions = {},\n): Promise<DatabaseInterface> {\n const {\n type,\n url = ':memory:',\n db: existingDb,\n classes,\n includeSystemTables = true,\n omitForeignKeyConstraints = false,\n } = options;\n\n // Use existing database or create new one\n const db =\n existingDb ??\n (await getDatabase({\n type: type ?? 'sqlite',\n url,\n __smrtSkipVitestSchemaPreparation: true,\n } as TestDatabaseConnectionOptions));\n if (!existingDb) await applySqliteTestPragmas(db, type, url);\n\n // Initialize system tables (same as production)\n if (includeSystemTables) {\n await initializeSystemTables(db);\n }\n\n // Get class names to setup. The framework-base filter below only applies\n // when the caller left `classes` implicit: an explicit list naming a\n // framework base class must still be honored (#2645).\n const isImplicitClassList = classes === undefined;\n const classNames = resolveRequestedSchemaClassNames(\n classes ?? ObjectRegistry.getQualifiedClassNames(),\n );\n\n // Skip if no classes registered. When the caller left `classes` implicit,\n // an empty registry usually means registration never reached this\n // process/module instance of ObjectRegistry (e.g. a Vitest plugin hook\n // registering manifests in a different worker/process than the test code\n // — #2750) rather than a deliberate \"system tables only\" setup. Warn (never\n // throw by default) so that failure surfaces here instead of as a much\n // later, harder-to-diagnose \"no such table\" error. An explicit empty\n // `classes: []` array is a deliberate choice and stays silent.\n if (classNames.length === 0) {\n if (isImplicitClassList) {\n const emptyRegistryMessage =\n 'getTestDatabase() found zero registered classes in ObjectRegistry and ' +\n 'created only system tables. If you expected model tables, the ' +\n 'registry is likely empty in this process — for smrt-vitest ' +\n 'consumers, confirm registration (smrtVitestPlugin() manifest ' +\n 'loading, or your setupFiles) actually runs in the same process ' +\n 'as your test code, or pass an explicit `classes` list to ' +\n 'getTestDatabase() to opt out of this check.';\n // recordRegistryDiagnostic('warn', ...) only buffers -- nothing reads\n // that buffer automatically (only strict-mode 'error' severity throws;\n // printing the buffer requires an explicit flushRegistryDiagnostics()\n // call this package never makes). Pair it with an immediate\n // console.warn so the failure is actually visible at the point of the\n // problem, which is the entire point of this diagnostic (#2750) --\n // the buffered record stays available for programmatic inspection via\n // getRegistryDiagnostics().\n console.warn(`[getTestDatabase] ${emptyRegistryMessage}`);\n recordRegistryDiagnostic(\n 'warn',\n 'TEST_DATABASE_EMPTY_IMPLICIT_REGISTRY',\n emptyRegistryMessage,\n );\n }\n return db;\n }\n\n // Use the same schema generation as production\n const schemaGenerator = new SchemaGenerator();\n const ddlEngine = resolveTestDatabaseDDLEngine(\n type,\n db,\n existingDb !== undefined,\n );\n\n // Collect every table before executing DDL so dependency ordering and cycle\n // handling are identical to production migration/schema paths (#2413).\n const schemas = new Map<\n string,\n { schema: SchemaDefinition; className: string }\n >();\n const authoritativeSchemas = ObjectRegistry.getAllSchemasAsDefinitions();\n\n for (const className of classNames) {\n // R11: the registration carries idType (native uuid vs text); read it\n // below when building runtimeSchemaConfig.\n const registered = ObjectRegistry.getClass(className);\n // Skip STI children - their schema is part of the base class table.\n // main (#1324): isSTIChild() compares RegisteredClass *identity* rather\n // than raw strings, so it stays correct under R5-canon (getSTIBase returns\n // qualified names) while also handling collection/override registrations.\n if (isSTIChild(className)) {\n continue;\n }\n\n // Framework abstract base classes (SmrtObject, SmrtClass, ...) are\n // scaffolding, not resources, and produce phantom smrt_objects/\n // smrt_classes/smrt_collections/smrt_hierarchicals/\n // smrt_polymorphic_associations tables when the default registry\n // snapshot happens to include them (#2645). Mirrors the production\n // `buildMergedTableSchemas()` filter in `registry/schema-builder.ts`, but\n // only for the implicit class list — an explicit `classes: [...]` caller\n // that names a framework base class is still honored.\n if (\n isImplicitClassList &&\n isFrameworkBaseClass(registered?.name, registered?.packageName)\n ) {\n continue;\n }\n\n const tableName = ObjectRegistry.getTableName(className);\n if (!tableName || schemas.has(tableName)) {\n continue;\n }\n\n const fields = await ObjectRegistry.getAllFields(className);\n const strategy = ObjectRegistry.getTableStrategy(className);\n // Mirrors `schema/utils.ts`: this bag is rebuilt by hand, so every `@smrt()`\n // option the generator reads has to be listed or tests silently diverge\n // from the production schema. `indexes` (#2357) was missing from both.\n const runtimeSchemaConfig = {\n conflictColumns: ObjectRegistry.getConflictColumns(className),\n idType: registered?.config.idType,\n indexes: registered?.config.indexes,\n registry: ObjectRegistry,\n };\n\n // Generate schema through the registry paths. Production (`manifest.json`\n // and therefore `smrt db:migrate`) uses the manifest paths\n // (`generateSTISchemaFromManifest` / `generateCTISchemaFromManifest`);\n // the two families are held to the same column and index sets by\n // `src/schema/schema-path-parity.test.ts` (#2359) — do not assume they\n // agree by construction.\n const schema =\n strategy === 'sti'\n ? await schemaGenerator.generateSTISchemaFromRegistry(\n className,\n tableName,\n fields,\n runtimeSchemaConfig,\n )\n : schemaGenerator.generateSchemaFromRegistry(\n className,\n tableName,\n fields,\n runtimeSchemaConfig,\n );\n\n // Manifest registrations can carry explicit FK actions that differ from\n // decorator defaults. The deterministic merged table schema preserves\n // those authoritative actions while still backfilling runtime-only fields.\n const authoritativeSchema = authoritativeSchemas[tableName];\n const effectiveColumns = authoritativeSchema\n ? Object.fromEntries(\n Object.entries(schema.columns).map(([name, column]) => {\n const manifestColumn = authoritativeSchema.columns[name];\n return [\n name,\n manifestColumn\n ? { ...column, foreignKey: manifestColumn.foreignKey }\n : column,\n ];\n }),\n )\n : schema.columns;\n const effectiveForeignKeys = schemaForeignKeys({\n columns: effectiveColumns,\n foreignKeys: [],\n });\n const effectiveSchema: SchemaDefinition = {\n ...schema,\n columns: effectiveColumns,\n foreignKeys: effectiveForeignKeys,\n dependencies: effectiveForeignKeys\n .map((foreignKey) => foreignKey.referencesTable)\n .filter((dependency) => dependency !== tableName),\n };\n\n schemas.set(tableName, {\n schema: omitForeignKeyConstraints\n ? omitTestForeignKeyConstraints(effectiveSchema)\n : effectiveSchema,\n className,\n });\n }\n\n // Explicitly requested test classes still need their registered parents.\n // Add the authoritative dependency closure so a child-only request cannot\n // emit a physical reference to a table this helper never creates.\n const addDependencies = (schema: SchemaDefinition): void => {\n for (const foreignKey of schemaForeignKeysForEngine(schema, ddlEngine)) {\n if (schemas.has(foreignKey.referencesTable)) continue;\n const dependency = authoritativeSchemas[foreignKey.referencesTable];\n if (!dependency) continue;\n const effectiveDependency = omitForeignKeyConstraints\n ? omitTestForeignKeyConstraints(dependency)\n : dependency;\n schemas.set(dependency.tableName, {\n schema: effectiveDependency,\n className: dependency.tableName,\n });\n addDependencies(effectiveDependency);\n }\n };\n for (const { schema } of [...schemas.values()]) addDependencies(schema);\n\n const tablePlan = planForeignKeyCreation(\n [...schemas.values()].map(({ schema }) => schema),\n ddlEngine,\n );\n const ddlStrategy = (await import('../schema/ddl/index.js')).getDDLStrategy(\n ddlEngine,\n );\n\n for (const schema of tablePlan.schemas) {\n const className = schemas.get(schema.tableName)?.className ?? 'unknown';\n const ddl = schemaGenerator.generateSQL(schema, ddlEngine);\n\n try {\n await db.query(ddl);\n\n // Create indexes (use DDL strategy so jsonPath / where / etc. render)\n const indexStatements = ddlStrategy.generateIndexes(schema);\n for (const indexSQL of indexStatements) {\n try {\n await db.query(indexSQL);\n } catch (indexError) {\n // Log but don't fail on index creation errors\n // Some indexes may fail if columns don't exist (STI meta fields)\n console.warn(\n `[getTestDatabase] Warning: Failed to create index: ${indexError instanceof Error ? indexError.message : String(indexError)} (SQL: ${indexSQL})`,\n );\n }\n }\n } catch (error) {\n // Provide helpful error message for table creation failures\n throw new Error(\n `[getTestDatabase] Failed to create table '${schema.tableName}' for class '${className}': ${error instanceof Error ? error.message : String(error)}`,\n { cause: error },\n );\n }\n }\n\n for (const statement of tablePlan.deferredStatements) {\n try {\n await db.query(statement);\n } catch (error) {\n throw new Error(\n `[getTestDatabase] Failed to add deferred foreign-key constraint: ${error instanceof Error ? error.message : String(error)} (SQL: ${statement})`,\n { cause: error },\n );\n }\n }\n\n return db;\n}\n\n/**\n * Initialize SMRT system tables in a database\n *\n * System tables use _smrt_ prefix and store framework metadata.\n * All statements use `IF NOT EXISTS` for idempotency.\n *\n * @param db - Database interface to initialize\n */\nasync function initializeSystemTables(db: DatabaseInterface): Promise<void> {\n await ensureLegacySystemTableCompatibility(db);\n\n const configuredDb = db as DatabaseInterface & {\n config?: { type?: string; url?: string };\n type?: string;\n };\n const engine = detectEngine(\n db.url || configuredDb.config?.url || '',\n configuredDb.type || configuredDb.config?.type,\n );\n\n // Split multi-statement SQL into individual statements\n const allStatements: string[] = [];\n for (const multiStatementSQL of getSystemTableDDL(engine)) {\n const statements = multiStatementSQL\n .split(';')\n .map((s) => s.trim())\n .filter((s) => s.length > 0);\n allStatements.push(...statements);\n }\n\n // Use db.query() — system tables use CREATE TABLE/INDEX IF NOT EXISTS\n // which databases handle natively without per-column existence checks.\n for (const statement of allStatements) {\n await db.query(statement);\n }\n\n // PostgreSQL keeps the best-effort append boundary in a function that must\n // be executed whole rather than included in semicolon-split portable DDL.\n await ensurePostgresChangeFeedAppendFunction(db);\n}\n"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@happyvertical/smrt-core",
3
- "version": "0.57.32",
3
+ "version": "0.57.33",
4
4
  "description": "Core AI agent framework with standardized collections, object-relational mapping, and code generators",
5
5
  "author": "HappyVertical",
6
6
  "type": "module",
@@ -199,15 +199,14 @@
199
199
  "@happyvertical/files": "^0.108.0",
200
200
  "@happyvertical/json": "^0.108.0",
201
201
  "@happyvertical/logger": "^0.108.0",
202
- "@happyvertical/smrt-config": "0.57.32",
203
- "@happyvertical/smrt-scanner": "0.57.32",
204
- "@happyvertical/smrt-types": "0.57.32",
202
+ "@happyvertical/smrt-config": "0.57.33",
203
+ "@happyvertical/smrt-scanner": "0.57.33",
204
+ "@happyvertical/smrt-types": "0.57.33",
205
205
  "@happyvertical/sql": "^0.108.0",
206
206
  "@happyvertical/utils": "^0.108.0",
207
207
  "@noble/hashes": "^2.4.0",
208
208
  "@oxc-project/runtime": "^0.150.0",
209
209
  "cheerio": "^1.2.0",
210
- "fast-glob": "3.3.3",
211
210
  "import-meta-resolve": "4.2.0",
212
211
  "minimatch": "10.2.6",
213
212
  "oxc-transform": "0.150.0",