@happyvertical/smrt-core 0.36.4 → 0.36.6

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.
Files changed (115) hide show
  1. package/dist/collection.d.ts +9 -4
  2. package/dist/collection.d.ts.map +1 -1
  3. package/dist/collection.js +6 -0
  4. package/dist/collection.js.map +1 -1
  5. package/dist/config.d.ts +1 -1
  6. package/dist/config.d.ts.map +1 -1
  7. package/dist/config.js.map +1 -1
  8. package/dist/consumer-plugin/index.d.ts.map +1 -1
  9. package/dist/consumer-plugin/index.js +7 -3
  10. package/dist/consumer-plugin/index.js.map +1 -1
  11. package/dist/database.d.ts +3 -3
  12. package/dist/database.d.ts.map +1 -1
  13. package/dist/database.js.map +1 -1
  14. package/dist/embeddings/provider.d.ts +14 -2
  15. package/dist/embeddings/provider.d.ts.map +1 -1
  16. package/dist/embeddings/provider.js +3 -3
  17. package/dist/embeddings/provider.js.map +1 -1
  18. package/dist/embeddings/storage.js.map +1 -1
  19. package/dist/errors.d.ts +22 -22
  20. package/dist/errors.d.ts.map +1 -1
  21. package/dist/errors.js +5 -4
  22. package/dist/errors.js.map +1 -1
  23. package/dist/knowledge.d.ts +12 -1
  24. package/dist/knowledge.d.ts.map +1 -1
  25. package/dist/knowledge.js.map +1 -1
  26. package/dist/lazy-config.d.ts.map +1 -1
  27. package/dist/lazy-config.js.map +1 -1
  28. package/dist/manifest/generator.d.ts.map +1 -1
  29. package/dist/manifest/generator.js +14 -12
  30. package/dist/manifest/generator.js.map +1 -1
  31. package/dist/manifest/manager.d.ts +3 -3
  32. package/dist/manifest/manager.d.ts.map +1 -1
  33. package/dist/manifest/manager.js.map +1 -1
  34. package/dist/manifest/manifest-loader.d.ts +3 -2
  35. package/dist/manifest/manifest-loader.d.ts.map +1 -1
  36. package/dist/manifest/manifest-loader.js +3 -2
  37. package/dist/manifest/manifest-loader.js.map +1 -1
  38. package/dist/manifest/static-manifest.d.ts.map +1 -1
  39. package/dist/manifest/static-manifest.js +13 -198
  40. package/dist/manifest/static-manifest.js.map +1 -1
  41. package/dist/manifest/store.js +2 -2
  42. package/dist/manifest/store.js.map +1 -1
  43. package/dist/manifest/test-manifest-stub.d.ts.map +1 -1
  44. package/dist/manifest/test-manifest-stub.js +13 -198
  45. package/dist/manifest/test-manifest-stub.js.map +1 -1
  46. package/dist/manifest.json +13 -175
  47. package/dist/mcp-advisor/index.d.ts +1 -1
  48. package/dist/mcp-advisor/index.d.ts.map +1 -1
  49. package/dist/mcp-advisor/tools/get-object-config.d.ts.map +1 -1
  50. package/dist/mcp-advisor/types.d.ts +5 -5
  51. package/dist/mcp-advisor/types.d.ts.map +1 -1
  52. package/dist/migrations/differ.js.map +1 -1
  53. package/dist/registry/types.d.ts +21 -0
  54. package/dist/registry/types.d.ts.map +1 -1
  55. package/dist/registry.d.ts.map +1 -1
  56. package/dist/registry.js +9 -0
  57. package/dist/registry.js.map +1 -1
  58. package/dist/scanner/manifest-generator.d.ts +13 -3
  59. package/dist/scanner/manifest-generator.d.ts.map +1 -1
  60. package/dist/scanner/manifest-generator.js +49 -16
  61. package/dist/scanner/manifest-generator.js.map +1 -1
  62. package/dist/scanner/types.d.ts +60 -6
  63. package/dist/scanner/types.d.ts.map +1 -1
  64. package/dist/schema/code-generator.d.ts.map +1 -1
  65. package/dist/schema/ddl/base-strategy.d.ts +2 -2
  66. package/dist/schema/ddl/base-strategy.d.ts.map +1 -1
  67. package/dist/schema/ddl/base-strategy.js.map +1 -1
  68. package/dist/schema/ddl/sqlite-strategy.d.ts +1 -1
  69. package/dist/schema/ddl/sqlite-strategy.d.ts.map +1 -1
  70. package/dist/schema/ddl/sqlite-strategy.js.map +1 -1
  71. package/dist/schema/ddl/types.d.ts +1 -1
  72. package/dist/schema/ddl/types.d.ts.map +1 -1
  73. package/dist/schema/generator.d.ts +27 -4
  74. package/dist/schema/generator.d.ts.map +1 -1
  75. package/dist/schema/generator.js +3 -2
  76. package/dist/schema/generator.js.map +1 -1
  77. package/dist/schema/override-system.d.ts +3 -3
  78. package/dist/schema/override-system.d.ts.map +1 -1
  79. package/dist/schema/schema-aggregator.d.ts.map +1 -1
  80. package/dist/schema/schema-manager.d.ts.map +1 -1
  81. package/dist/schema/schema-manager.js +12 -4
  82. package/dist/schema/schema-manager.js.map +1 -1
  83. package/dist/schema/types.d.ts +1 -1
  84. package/dist/schema/types.d.ts.map +1 -1
  85. package/dist/schema/utils.d.ts +6 -1
  86. package/dist/schema/utils.d.ts.map +1 -1
  87. package/dist/schema/utils.js +2 -1
  88. package/dist/schema/utils.js.map +1 -1
  89. package/dist/signals/sanitizer.d.ts +1 -1
  90. package/dist/signals/sanitizer.d.ts.map +1 -1
  91. package/dist/signals/sanitizer.js +12 -2
  92. package/dist/signals/sanitizer.js.map +1 -1
  93. package/dist/smrt-knowledge.json +14 -26
  94. package/dist/system/types.d.ts +2 -2
  95. package/dist/system/types.d.ts.map +1 -1
  96. package/dist/system-fields.d.ts +5 -43
  97. package/dist/system-fields.d.ts.map +1 -1
  98. package/dist/system-fields.js +2 -1
  99. package/dist/system-fields.js.map +1 -1
  100. package/dist/test-utils.d.ts +39 -13
  101. package/dist/test-utils.d.ts.map +1 -1
  102. package/dist/testing/database.d.ts.map +1 -1
  103. package/dist/testing/database.js.map +1 -1
  104. package/dist/utils/json.js.map +1 -1
  105. package/dist/utils.d.ts +16 -8
  106. package/dist/utils.d.ts.map +1 -1
  107. package/dist/utils.js.map +1 -1
  108. package/dist/vite-plugin/index.d.ts.map +1 -1
  109. package/dist/vite-plugin/index.js +11 -7
  110. package/dist/vite-plugin/index.js.map +1 -1
  111. package/dist/vite-plugin/sveltekit-generator.d.ts.map +1 -1
  112. package/dist/vite-plugin/sveltekit-generator.js +4 -3
  113. package/dist/vite-plugin/sveltekit-generator.js.map +1 -1
  114. package/dist/vite-plugin/templates/default-ui.ts +20 -6
  115. package/package.json +10 -10
@@ -1 +1 @@
1
- {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../src/schema/utils.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AAG5D,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAKrD,OAAO,EAAE,eAAe,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AAEtE;;;;;;;;;;;;;GAaG;AACH,wBAAsB,cAAc,CAClC,SAAS,EAAE,KAAK,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,GAAG,EACtC,cAAc,CAAC,EAAE,GAAG,CAAC,MAAM,EAAE,GAAG,CAAC,EACjC,OAAO,GAAE;IAAE,MAAM,CAAC,EAAE,cAAc,CAAA;CAAO,mBAqI1C;AAED;;;;;;;;;GASG;AACH,wBAAsB,YAAY,CAChC,EAAE,EAAE,iBAAiB,EACrB,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,IAAI,CAAC,CAyEf"}
1
+ {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../src/schema/utils.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AAC5D,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAE/C,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AAE3D,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAKrD,OAAO,EAAE,eAAe,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AAEtE;;;;;;;;;;;;;GAaG;AACH,wBAAsB,cAAc,CAMlC,SAAS,EAAE;IAAE,KAAK,GAAG,IAAI,EAAE,KAAK,EAAE,GAAG,UAAU,CAAC;IAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;CAAE,EACxE,cAAc,CAAC,EAAE,GAAG,CAAC,MAAM,EAAE,eAAe,CAAC,EAC7C,OAAO,GAAE;IAAE,MAAM,CAAC,EAAE,cAAc,CAAA;CAAO,mBAyI1C;AAED;;;;;;;;;GASG;AACH,wBAAsB,YAAY,CAChC,EAAE,EAAE,iBAAiB,EACrB,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,IAAI,CAAC,CAyEf"}
@@ -10,7 +10,8 @@ async function generateSchema(ClassType, providedFields, options = {}) {
10
10
  }
11
11
  const cachedFields = providedFields && providedFields.size > 0 ? providedFields : await ObjectRegistry.getAllFields(className);
12
12
  if (cachedFields.size === 0) {
13
- const isTestEnv = process.env.NODE_ENV === "test" || process.env.VITEST === "true" || typeof globalThis.describe !== "undefined" || typeof globalThis.it !== "undefined";
13
+ const testGlobals = globalThis;
14
+ const isTestEnv = process.env.NODE_ENV === "test" || process.env.VITEST === "true" || typeof testGlobals.describe !== "undefined" || typeof testGlobals.it !== "undefined";
14
15
  const testHint = isTestEnv ? `
15
16
 
16
17
  ⚠️ Are you using 'smrt test'? Tests require manifest generation.
@@ -1 +1 @@
1
- {"version":3,"file":"utils.js","sources":["../../src/schema/utils.ts"],"sourcesContent":["/**\n * Schema generation utilities - Node.js only\n *\n * These functions use SchemaGenerator which depends on node:crypto.\n * Separated from main utils.ts to prevent bundling in browser builds.\n *\n * SMRT handles ALL database maintenance directly.\n * SDK SQL remains a pure query/CRUD layer.\n */\n\nimport type { DatabaseInterface } from '@happyvertical/sql';\nimport { ObjectRegistry } from '../registry.js';\nimport { tableNameFromClass } from '../utils.js';\nimport type { DatabaseEngine } from './ddl/types.js';\nimport { SchemaManager } from './schema-manager.js';\n\n// Index-rendering helpers live in a separate file to avoid pulling the\n// heavyweight registry/collection module graph into the DDL strategies.\nexport { isJsonPathIndex, renderIndexTarget } from './index-utils.js';\n\n/**\n * Generates a complete database schema SQL statement for a class\n *\n * This is a thin wrapper around SchemaGenerator that provides the\n * single source of truth for schema generation. Uses ObjectRegistry\n * cached fields from AST manifest for consistent schema generation.\n *\n * **Note**: Uses dynamic import for SchemaGenerator to avoid bundling\n * Node.js-only code (node:crypto) in browser builds.\n *\n * @param ClassType - Class constructor to generate schema for\n * @param providedFields - Optional fields map (used during registration)\n * @returns SQL schema creation statement with CREATE TABLE and CREATE INDEX statements\n */\nexport async function generateSchema(\n ClassType: new (...args: any[]) => any,\n providedFields?: Map<string, any>,\n options: { engine?: DatabaseEngine } = {},\n) {\n const className = ClassType.name;\n const tableName = tableNameFromClass(ClassType);\n\n // For external packages, ensure manifest is loaded before proceeding\n if (!providedFields || providedFields.size === 0) {\n await ObjectRegistry.ensureManifestLoaded(className);\n }\n\n // Use provided fields if available AND non-empty (during registration), otherwise get from registry\n // NEW: Use getAllFields() to include inherited fields from parent classes\n const cachedFields =\n providedFields && providedFields.size > 0\n ? providedFields\n : await ObjectRegistry.getAllFields(className);\n\n // Throw error if no fields found\n if (cachedFields.size === 0) {\n // Detect if running in test environment\n const isTestEnv =\n process.env.NODE_ENV === 'test' ||\n process.env.VITEST === 'true' ||\n typeof (globalThis as any).describe !== 'undefined' ||\n typeof (globalThis as any).it !== 'undefined';\n\n const testHint = isTestEnv\n ? `\\n\\n⚠️ Are you using 'smrt test'? ` +\n `Tests require manifest generation.\\n` +\n ` ✅ Use: smrt test\\n` +\n ` ❌ NOT: npx vitest\\n`\n : '';\n\n // Check if class is actually registered (decorator ran but no fields loaded)\n const isRegistered = ObjectRegistry.hasClass(className);\n\n if (isRegistered) {\n // Class registered but no fields - manifest problem\n throw new Error(\n `No field metadata found for class '${className}'. ` +\n `The class is registered (decorator ran) but has no field definitions. ` +\n `This usually means the manifest file is missing or stale.` +\n testHint,\n );\n } else {\n // Class not registered - decorator never ran\n throw new Error(\n `Cannot generate schema for unregistered class '${className}'. ` +\n `Ensure the class is decorated with @smrt() for schema generation to work. ` +\n `Runtime introspection has been removed per issue #131.` +\n testHint,\n );\n }\n }\n\n // Check if class uses STI strategy\n const tableStrategy = ObjectRegistry.getTableStrategy(className);\n\n // Dynamic import SchemaGenerator (Node.js-only, uses node:crypto)\n // This prevents bundling it into browser builds\n const { SchemaGenerator } = await import('./generator.js');\n const generator = new SchemaGenerator();\n const registeredClass = ObjectRegistry.getClass(className);\n const runtimeSchemaConfig = registeredClass?.config\n ? {\n conflictColumns: registeredClass.config.conflictColumns,\n idType: registeredClass.config.idType,\n registry: ObjectRegistry,\n }\n : undefined;\n\n let schemaDefinition: Awaited<\n ReturnType<\n InstanceType<typeof SchemaGenerator>['generateSchemaFromRegistry']\n >\n >;\n\n if (tableStrategy === 'sti') {\n // STI: Generate shared table for base class\n const stiBase = ObjectRegistry.getSTIBase(className);\n\n if (!stiBase) {\n throw new Error(\n `STI strategy detected for '${className}' but no STI base class found. ` +\n `This should not happen - please report this bug.`,\n );\n }\n\n // Only generate schema for the base class (not for children).\n // R5-canon: `getSTIBase` returns the qualified name; compare against\n // the qualified form of this class so an STI base isn't\n // mis-classified as a subclass and skipped.\n const qualifiedClassName =\n registeredClass?.qualifiedName ?? registeredClass?.name ?? className;\n if (qualifiedClassName === stiBase || className === stiBase) {\n // This is the base class - generate STI schema\n schemaDefinition = await generator.generateSTISchemaFromRegistry(\n className,\n tableName,\n cachedFields,\n runtimeSchemaConfig,\n );\n } else {\n // This is a child class - return null or empty schema\n // The base class schema already includes all fields\n // Child classes don't need their own tables\n return ''; // Empty SQL - table already created by base class\n }\n } else {\n // CTI: Generate separate table for each class\n schemaDefinition = generator.generateSchemaFromRegistry(\n className,\n tableName,\n cachedFields,\n runtimeSchemaConfig,\n );\n }\n\n // Store the full schema definition in the registry\n // This is critical for:\n // - STI tables where descendants have additional columns (issue #427)\n // - Per-engine DDL generation via SchemaManager\n if (registeredClass) {\n // Store the full SchemaDefinition for SchemaManager to use\n registeredClass.schema = schemaDefinition;\n // Also store generated DDL for backward compatibility\n registeredClass.schema.ddl = generator.generateSQL(\n schemaDefinition,\n 'sqlite',\n );\n }\n\n return generator.generateSQL(schemaDefinition, options.engine);\n}\n\n/**\n * Ensure schema exists for a registered class.\n *\n * This compatibility helper is kept for tooling flows such as CLI commands that\n * explicitly prepare schema ahead of runtime. Core runtime no longer calls this\n * automatically.\n *\n * @deprecated Prefer explicit migration/bootstrap tooling. Runtime verifies\n * schema and fails fast when tables are missing.\n */\nexport async function ensureSchema(\n db: DatabaseInterface,\n className: string,\n): Promise<void> {\n const registered = ObjectRegistry.getClass(className);\n if (!registered) {\n throw new Error(\n `Cannot ensure schema for unregistered class '${className}'. ` +\n `Ensure the class is decorated with @smrt() and registered in the ObjectRegistry.`,\n );\n }\n\n const tableStrategy = ObjectRegistry.getTableStrategy(className);\n if (tableStrategy === 'sti') {\n const stiBase = ObjectRegistry.getSTIBase(className);\n // R5-canon: `getSTIBase` returns the qualified name. Compare\n // against the qualified form of `className` so an STI base isn't\n // mis-classified as a child and recursed on. Falls back to a\n // simple-name compare for classes without a package context.\n const qualifiedClassName =\n registered.qualifiedName ?? registered.name ?? className;\n if (stiBase && stiBase !== qualifiedClassName && stiBase !== className) {\n await ensureSchema(db, stiBase);\n return;\n }\n }\n\n let schemaDefinition = ObjectRegistry.getSchema(className);\n if (tableStrategy === 'sti') {\n const tableName = ObjectRegistry.getTableName(className);\n if (tableName) {\n const mergedSchema =\n ObjectRegistry.getAllSchemasAsDefinitions()[tableName];\n if (mergedSchema) {\n schemaDefinition = mergedSchema;\n }\n }\n }\n\n if (!schemaDefinition?.tableName) {\n const providedFields =\n registered.fields.size > 0 ? registered.fields : undefined;\n await generateSchema(registered.constructor, providedFields);\n schemaDefinition = ObjectRegistry.getSchema(className);\n\n if (tableStrategy === 'sti') {\n const tableName = ObjectRegistry.getTableName(className);\n if (tableName) {\n const mergedSchema =\n ObjectRegistry.getAllSchemasAsDefinitions()[tableName];\n if (mergedSchema) {\n schemaDefinition = mergedSchema;\n }\n }\n }\n }\n\n if (!schemaDefinition?.tableName) {\n throw new Error(\n `No schema definition found for class '${className}'. ` +\n `Run the manifest generation/build step before preparing schema.`,\n );\n }\n\n // Use the merged table definition for shared tables (especially STI).\n // Per-class schema metadata can reflect only the current class, while\n // the database table must include columns from all classes sharing it.\n const mergedSchemaDefinition =\n ObjectRegistry.getAllSchemasAsDefinitions()[schemaDefinition.tableName];\n const effectiveSchemaDefinition = mergedSchemaDefinition ?? schemaDefinition;\n\n const schemaManager = new SchemaManager(db, {\n skipTriggers:\n typeof (db as { exportTable?: unknown }).exportTable === 'function',\n });\n await schemaManager.ensureTable(effectiveSchemaDefinition);\n}\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"utils.js","sources":["../../src/schema/utils.ts"],"sourcesContent":["/**\n * Schema generation utilities - Node.js only\n *\n * These functions use SchemaGenerator which depends on node:crypto.\n * Separated from main utils.ts to prevent bundling in browser builds.\n *\n * SMRT handles ALL database maintenance directly.\n * SDK SQL remains a pure query/CRUD layer.\n */\n\nimport type { DatabaseInterface } from '@happyvertical/sql';\nimport type { SmrtObject } from '../object.js';\nimport { ObjectRegistry } from '../registry.js';\nimport type { FieldDefinition } from '../scanner/types.js';\nimport { tableNameFromClass } from '../utils.js';\nimport type { DatabaseEngine } from './ddl/types.js';\nimport { SchemaManager } from './schema-manager.js';\n\n// Index-rendering helpers live in a separate file to avoid pulling the\n// heavyweight registry/collection module graph into the DDL strategies.\nexport { isJsonPathIndex, renderIndexTarget } from './index-utils.js';\n\n/**\n * Generates a complete database schema SQL statement for a class\n *\n * This is a thin wrapper around SchemaGenerator that provides the\n * single source of truth for schema generation. Uses ObjectRegistry\n * cached fields from AST manifest for consistent schema generation.\n *\n * **Note**: Uses dynamic import for SchemaGenerator to avoid bundling\n * Node.js-only code (node:crypto) in browser builds.\n *\n * @param ClassType - Class constructor to generate schema for\n * @param providedFields - Optional fields map (used during registration)\n * @returns SQL schema creation statement with CREATE TABLE and CREATE INDEX statements\n */\nexport async function generateSchema(\n // Accepts any SmrtObject constructor: the registry-stored `typeof SmrtObject`\n // as well as collection item classes whose construct signature is narrower\n // than the full static surface. Only `.name` and the construct identity are\n // used here. `never[]` keeps the construct signature contravariantly\n // compatible with constructors that declare their own argument shapes.\n ClassType: { new (...args: never[]): SmrtObject; readonly name: string },\n providedFields?: Map<string, FieldDefinition>,\n options: { engine?: DatabaseEngine } = {},\n) {\n const className = ClassType.name;\n const tableName = tableNameFromClass(ClassType);\n\n // For external packages, ensure manifest is loaded before proceeding\n if (!providedFields || providedFields.size === 0) {\n await ObjectRegistry.ensureManifestLoaded(className);\n }\n\n // Use provided fields if available AND non-empty (during registration), otherwise get from registry\n // NEW: Use getAllFields() to include inherited fields from parent classes\n const cachedFields =\n providedFields && providedFields.size > 0\n ? providedFields\n : await ObjectRegistry.getAllFields(className);\n\n // Throw error if no fields found\n if (cachedFields.size === 0) {\n // Detect if running in test environment\n const testGlobals = globalThis as {\n describe?: unknown;\n it?: unknown;\n };\n const isTestEnv =\n process.env.NODE_ENV === 'test' ||\n process.env.VITEST === 'true' ||\n typeof testGlobals.describe !== 'undefined' ||\n typeof testGlobals.it !== 'undefined';\n\n const testHint = isTestEnv\n ? `\\n\\n⚠️ Are you using 'smrt test'? ` +\n `Tests require manifest generation.\\n` +\n ` ✅ Use: smrt test\\n` +\n ` ❌ NOT: npx vitest\\n`\n : '';\n\n // Check if class is actually registered (decorator ran but no fields loaded)\n const isRegistered = ObjectRegistry.hasClass(className);\n\n if (isRegistered) {\n // Class registered but no fields - manifest problem\n throw new Error(\n `No field metadata found for class '${className}'. ` +\n `The class is registered (decorator ran) but has no field definitions. ` +\n `This usually means the manifest file is missing or stale.` +\n testHint,\n );\n } else {\n // Class not registered - decorator never ran\n throw new Error(\n `Cannot generate schema for unregistered class '${className}'. ` +\n `Ensure the class is decorated with @smrt() for schema generation to work. ` +\n `Runtime introspection has been removed per issue #131.` +\n testHint,\n );\n }\n }\n\n // Check if class uses STI strategy\n const tableStrategy = ObjectRegistry.getTableStrategy(className);\n\n // Dynamic import SchemaGenerator (Node.js-only, uses node:crypto)\n // This prevents bundling it into browser builds\n const { SchemaGenerator } = await import('./generator.js');\n const generator = new SchemaGenerator();\n const registeredClass = ObjectRegistry.getClass(className);\n const runtimeSchemaConfig = registeredClass?.config\n ? {\n conflictColumns: registeredClass.config.conflictColumns,\n idType: registeredClass.config.idType,\n registry: ObjectRegistry,\n }\n : undefined;\n\n let schemaDefinition: Awaited<\n ReturnType<\n InstanceType<typeof SchemaGenerator>['generateSchemaFromRegistry']\n >\n >;\n\n if (tableStrategy === 'sti') {\n // STI: Generate shared table for base class\n const stiBase = ObjectRegistry.getSTIBase(className);\n\n if (!stiBase) {\n throw new Error(\n `STI strategy detected for '${className}' but no STI base class found. ` +\n `This should not happen - please report this bug.`,\n );\n }\n\n // Only generate schema for the base class (not for children).\n // R5-canon: `getSTIBase` returns the qualified name; compare against\n // the qualified form of this class so an STI base isn't\n // mis-classified as a subclass and skipped.\n const qualifiedClassName =\n registeredClass?.qualifiedName ?? registeredClass?.name ?? className;\n if (qualifiedClassName === stiBase || className === stiBase) {\n // This is the base class - generate STI schema\n schemaDefinition = await generator.generateSTISchemaFromRegistry(\n className,\n tableName,\n cachedFields,\n runtimeSchemaConfig,\n );\n } else {\n // This is a child class - return null or empty schema\n // The base class schema already includes all fields\n // Child classes don't need their own tables\n return ''; // Empty SQL - table already created by base class\n }\n } else {\n // CTI: Generate separate table for each class\n schemaDefinition = generator.generateSchemaFromRegistry(\n className,\n tableName,\n cachedFields,\n runtimeSchemaConfig,\n );\n }\n\n // Store the full schema definition in the registry\n // This is critical for:\n // - STI tables where descendants have additional columns (issue #427)\n // - Per-engine DDL generation via SchemaManager\n if (registeredClass) {\n // Store the full SchemaDefinition for SchemaManager to use\n registeredClass.schema = schemaDefinition;\n // Also store generated DDL for backward compatibility\n registeredClass.schema.ddl = generator.generateSQL(\n schemaDefinition,\n 'sqlite',\n );\n }\n\n return generator.generateSQL(schemaDefinition, options.engine);\n}\n\n/**\n * Ensure schema exists for a registered class.\n *\n * This compatibility helper is kept for tooling flows such as CLI commands that\n * explicitly prepare schema ahead of runtime. Core runtime no longer calls this\n * automatically.\n *\n * @deprecated Prefer explicit migration/bootstrap tooling. Runtime verifies\n * schema and fails fast when tables are missing.\n */\nexport async function ensureSchema(\n db: DatabaseInterface,\n className: string,\n): Promise<void> {\n const registered = ObjectRegistry.getClass(className);\n if (!registered) {\n throw new Error(\n `Cannot ensure schema for unregistered class '${className}'. ` +\n `Ensure the class is decorated with @smrt() and registered in the ObjectRegistry.`,\n );\n }\n\n const tableStrategy = ObjectRegistry.getTableStrategy(className);\n if (tableStrategy === 'sti') {\n const stiBase = ObjectRegistry.getSTIBase(className);\n // R5-canon: `getSTIBase` returns the qualified name. Compare\n // against the qualified form of `className` so an STI base isn't\n // mis-classified as a child and recursed on. Falls back to a\n // simple-name compare for classes without a package context.\n const qualifiedClassName =\n registered.qualifiedName ?? registered.name ?? className;\n if (stiBase && stiBase !== qualifiedClassName && stiBase !== className) {\n await ensureSchema(db, stiBase);\n return;\n }\n }\n\n let schemaDefinition = ObjectRegistry.getSchema(className);\n if (tableStrategy === 'sti') {\n const tableName = ObjectRegistry.getTableName(className);\n if (tableName) {\n const mergedSchema =\n ObjectRegistry.getAllSchemasAsDefinitions()[tableName];\n if (mergedSchema) {\n schemaDefinition = mergedSchema;\n }\n }\n }\n\n if (!schemaDefinition?.tableName) {\n const providedFields =\n registered.fields.size > 0 ? registered.fields : undefined;\n await generateSchema(registered.constructor, providedFields);\n schemaDefinition = ObjectRegistry.getSchema(className);\n\n if (tableStrategy === 'sti') {\n const tableName = ObjectRegistry.getTableName(className);\n if (tableName) {\n const mergedSchema =\n ObjectRegistry.getAllSchemasAsDefinitions()[tableName];\n if (mergedSchema) {\n schemaDefinition = mergedSchema;\n }\n }\n }\n }\n\n if (!schemaDefinition?.tableName) {\n throw new Error(\n `No schema definition found for class '${className}'. ` +\n `Run the manifest generation/build step before preparing schema.`,\n );\n }\n\n // Use the merged table definition for shared tables (especially STI).\n // Per-class schema metadata can reflect only the current class, while\n // the database table must include columns from all classes sharing it.\n const mergedSchemaDefinition =\n ObjectRegistry.getAllSchemasAsDefinitions()[schemaDefinition.tableName];\n const effectiveSchemaDefinition = mergedSchemaDefinition ?? schemaDefinition;\n\n const schemaManager = new SchemaManager(db, {\n skipTriggers:\n typeof (db as { exportTable?: unknown }).exportTable === 'function',\n });\n await schemaManager.ensureTable(effectiveSchemaDefinition);\n}\n"],"names":[],"mappings":"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"}
@@ -12,7 +12,7 @@ export interface SanitizationConfig {
12
12
  * Custom replacer function for sanitization
13
13
  * Return undefined to redact the value entirely
14
14
  */
15
- replacer?: (key: string, value: any) => any;
15
+ replacer?: (key: string, value: unknown) => unknown;
16
16
  /**
17
17
  * Replacement value for redacted fields
18
18
  * Default: '[REDACTED]'
@@ -1 +1 @@
1
- {"version":3,"file":"sanitizer.d.ts","sourceRoot":"","sources":["../../src/signals/sanitizer.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,2BAA2B,CAAC;AAExD;;GAEG;AACH,MAAM,WAAW,kBAAkB;IACjC;;;OAGG;IACH,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;IAEtB;;;OAGG;IACH,QAAQ,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,GAAG,KAAK,GAAG,CAAC;IAE5C;;;OAGG;IACH,aAAa,CAAC,EAAE,MAAM,CAAC;IAEvB;;;OAGG;IACH,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAgCD;;;;;GAKG;AACH,qBAAa,eAAe;IAC1B,OAAO,CAAC,MAAM,CAA+B;gBAEjC,MAAM,GAAE,kBAAuB;IAS3C;;;;OAIG;IACH,OAAO,CAAC,eAAe;IAiBvB;;OAEG;IACH,OAAO,CAAC,aAAa;IAgDrB;;;;;OAKG;IACH,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM;CAkBjC"}
1
+ {"version":3,"file":"sanitizer.d.ts","sourceRoot":"","sources":["../../src/signals/sanitizer.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,2BAA2B,CAAC;AAExD;;GAEG;AACH,MAAM,WAAW,kBAAkB;IACjC;;;OAGG;IACH,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;IAEtB;;;OAGG;IACH,QAAQ,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,KAAK,OAAO,CAAC;IAEpD;;;OAGG;IACH,aAAa,CAAC,EAAE,MAAM,CAAC;IAEvB;;;OAGG;IACH,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAgCD;;;;;GAKG;AACH,qBAAa,eAAe;IAC1B,OAAO,CAAC,MAAM,CAA+B;gBAEjC,MAAM,GAAE,kBAAuB;IAS3C;;;;OAIG;IACH,OAAO,CAAC,eAAe;IAiBvB;;OAEG;IACH,OAAO,CAAC,aAAa;IAgDrB;;;;;OAKG;IACH,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM;CA+BjC"}
@@ -98,10 +98,20 @@ class SignalSanitizer {
98
98
  timestamp: signal.timestamp,
99
99
  ...signal.step && { step: signal.step },
100
100
  ...signal.duration !== void 0 && { duration: signal.duration },
101
+ // `signal.args` is an array, so `sanitizeValue` always returns an array
102
+ // (the `Array.isArray` branch maps element-wise).
101
103
  ...signal.args && { args: this.sanitizeValue(signal.args) },
102
104
  ...signal.result !== void 0 ? { result: this.sanitizeValue(signal.result) } : {},
103
- ...signal.error && { error: this.sanitizeValue(signal.error) },
104
- ...signal.metadata && { metadata: this.sanitizeValue(signal.metadata) }
105
+ // `sanitizeValue` flattens an `Error` into an Error-shaped plain object
106
+ // (`{ message, name, stack }`); the Signal contract still types it as
107
+ // `Error`, so retain that surface here.
108
+ ...signal.error && {
109
+ error: this.sanitizeValue(signal.error)
110
+ },
111
+ // Sanitizing an object yields a `Record<string, unknown>`.
112
+ ...signal.metadata && {
113
+ metadata: this.sanitizeValue(signal.metadata)
114
+ }
105
115
  };
106
116
  }
107
117
  }
@@ -1 +1 @@
1
- {"version":3,"file":"sanitizer.js","sources":["../../src/signals/sanitizer.ts"],"sourcesContent":["/**\n * Signal payload sanitization for security\n *\n * Prevents sensitive data (passwords, tokens, PII) from being leaked\n * into logs, metrics, or other signal outputs.\n */\n\nimport type { Signal } from '@happyvertical/smrt-types';\n\n/**\n * Sanitization configuration\n */\nexport interface SanitizationConfig {\n /**\n * Keys to redact from signal payloads\n * Default: common sensitive fields\n */\n redactKeys?: string[];\n\n /**\n * Custom replacer function for sanitization\n * Return undefined to redact the value entirely\n */\n replacer?: (key: string, value: any) => any;\n\n /**\n * Replacement value for redacted fields\n * Default: '[REDACTED]'\n */\n redactedValue?: string;\n\n /**\n * Maximum number of stack trace lines to include in sanitized errors\n * Default: 10\n */\n maxStackLines?: number;\n}\n\n/**\n * Default sensitive keys to redact\n */\nconst DEFAULT_REDACT_KEYS = [\n 'password',\n 'passwd',\n 'pwd',\n 'secret',\n 'token',\n 'apiKey',\n 'api_key',\n 'accessToken',\n 'access_token',\n 'refreshToken',\n 'refresh_token',\n 'privateKey',\n 'private_key',\n 'authToken',\n 'auth_token',\n 'bearerToken',\n 'bearer_token',\n 'sessionId',\n 'session_id',\n 'ssn',\n 'creditCard',\n 'credit_card',\n 'cvv',\n 'pin',\n];\n\n/**\n * Signal sanitizer\n *\n * Removes or redacts sensitive data from signal payloads before\n * they are processed by adapters.\n */\nexport class SignalSanitizer {\n private config: Required<SanitizationConfig>;\n\n constructor(config: SanitizationConfig = {}) {\n this.config = {\n redactKeys: config.redactKeys ?? DEFAULT_REDACT_KEYS,\n replacer: config.replacer ?? this.defaultReplacer.bind(this),\n redactedValue: config.redactedValue ?? '[REDACTED]',\n maxStackLines: config.maxStackLines ?? 10,\n };\n }\n\n /**\n * Default replacer function\n *\n * Redacts sensitive keys and truncates long strings\n */\n private defaultReplacer(key: string, value: any): any {\n // Check if key should be redacted\n const lowerKey = key.toLowerCase();\n if (\n this.config.redactKeys.some((k) => lowerKey.includes(k.toLowerCase()))\n ) {\n return this.config.redactedValue;\n }\n\n // Truncate very long strings (potential data dumps)\n if (typeof value === 'string' && value.length > 1000) {\n return `${value.substring(0, 1000)}... [TRUNCATED]`;\n }\n\n return value;\n }\n\n /**\n * Sanitize a value using the configured replacer\n */\n private sanitizeValue(value: any, seen = new WeakSet()): any {\n // Handle null/undefined\n if (value == null) {\n return value;\n }\n\n // Handle primitives\n if (typeof value !== 'object') {\n return value;\n }\n\n // Prevent circular reference infinite loops\n if (seen.has(value)) {\n return '[CIRCULAR]';\n }\n seen.add(value);\n\n // Handle arrays\n if (Array.isArray(value)) {\n return value.map((item) => this.sanitizeValue(item, seen));\n }\n\n // Handle Error objects specially\n if (value instanceof Error) {\n return {\n message: value.message,\n name: value.name,\n stack: value.stack\n ? value.stack\n .split('\\n')\n .slice(0, this.config.maxStackLines)\n .join('\\n')\n : undefined,\n };\n }\n\n // Handle regular objects\n const sanitized: Record<string, any> = {};\n for (const [key, val] of Object.entries(value)) {\n const replacedValue = this.config.replacer(key, val);\n if (replacedValue !== undefined) {\n sanitized[key] = this.sanitizeValue(replacedValue, seen);\n }\n }\n\n return sanitized;\n }\n\n /**\n * Sanitize a signal payload\n *\n * @param signal - Signal to sanitize\n * @returns Sanitized signal (new object, doesn't mutate original)\n */\n sanitize(signal: Signal): Signal {\n return {\n id: signal.id,\n objectId: signal.objectId,\n className: signal.className,\n method: signal.method,\n type: signal.type,\n timestamp: signal.timestamp,\n ...(signal.step && { step: signal.step }),\n ...(signal.duration !== undefined && { duration: signal.duration }),\n ...(signal.args && { args: this.sanitizeValue(signal.args) }),\n ...(signal.result !== undefined\n ? { result: this.sanitizeValue(signal.result) }\n : {}),\n ...(signal.error && { error: this.sanitizeValue(signal.error) }),\n ...(signal.metadata && { metadata: this.sanitizeValue(signal.metadata) }),\n };\n }\n}\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"sanitizer.js","sources":["../../src/signals/sanitizer.ts"],"sourcesContent":["/**\n * Signal payload sanitization for security\n *\n * Prevents sensitive data (passwords, tokens, PII) from being leaked\n * into logs, metrics, or other signal outputs.\n */\n\nimport type { Signal } from '@happyvertical/smrt-types';\n\n/**\n * Sanitization configuration\n */\nexport interface SanitizationConfig {\n /**\n * Keys to redact from signal payloads\n * Default: common sensitive fields\n */\n redactKeys?: string[];\n\n /**\n * Custom replacer function for sanitization\n * Return undefined to redact the value entirely\n */\n replacer?: (key: string, value: unknown) => unknown;\n\n /**\n * Replacement value for redacted fields\n * Default: '[REDACTED]'\n */\n redactedValue?: string;\n\n /**\n * Maximum number of stack trace lines to include in sanitized errors\n * Default: 10\n */\n maxStackLines?: number;\n}\n\n/**\n * Default sensitive keys to redact\n */\nconst DEFAULT_REDACT_KEYS = [\n 'password',\n 'passwd',\n 'pwd',\n 'secret',\n 'token',\n 'apiKey',\n 'api_key',\n 'accessToken',\n 'access_token',\n 'refreshToken',\n 'refresh_token',\n 'privateKey',\n 'private_key',\n 'authToken',\n 'auth_token',\n 'bearerToken',\n 'bearer_token',\n 'sessionId',\n 'session_id',\n 'ssn',\n 'creditCard',\n 'credit_card',\n 'cvv',\n 'pin',\n];\n\n/**\n * Signal sanitizer\n *\n * Removes or redacts sensitive data from signal payloads before\n * they are processed by adapters.\n */\nexport class SignalSanitizer {\n private config: Required<SanitizationConfig>;\n\n constructor(config: SanitizationConfig = {}) {\n this.config = {\n redactKeys: config.redactKeys ?? DEFAULT_REDACT_KEYS,\n replacer: config.replacer ?? this.defaultReplacer.bind(this),\n redactedValue: config.redactedValue ?? '[REDACTED]',\n maxStackLines: config.maxStackLines ?? 10,\n };\n }\n\n /**\n * Default replacer function\n *\n * Redacts sensitive keys and truncates long strings\n */\n private defaultReplacer(key: string, value: unknown): unknown {\n // Check if key should be redacted\n const lowerKey = key.toLowerCase();\n if (\n this.config.redactKeys.some((k) => lowerKey.includes(k.toLowerCase()))\n ) {\n return this.config.redactedValue;\n }\n\n // Truncate very long strings (potential data dumps)\n if (typeof value === 'string' && value.length > 1000) {\n return `${value.substring(0, 1000)}... [TRUNCATED]`;\n }\n\n return value;\n }\n\n /**\n * Sanitize a value using the configured replacer\n */\n private sanitizeValue(value: unknown, seen = new WeakSet()): unknown {\n // Handle null/undefined\n if (value == null) {\n return value;\n }\n\n // Handle primitives\n if (typeof value !== 'object') {\n return value;\n }\n\n // Prevent circular reference infinite loops\n if (seen.has(value)) {\n return '[CIRCULAR]';\n }\n seen.add(value);\n\n // Handle arrays\n if (Array.isArray(value)) {\n return value.map((item) => this.sanitizeValue(item, seen));\n }\n\n // Handle Error objects specially\n if (value instanceof Error) {\n return {\n message: value.message,\n name: value.name,\n stack: value.stack\n ? value.stack\n .split('\\n')\n .slice(0, this.config.maxStackLines)\n .join('\\n')\n : undefined,\n };\n }\n\n // Handle regular objects\n const sanitized: Record<string, unknown> = {};\n for (const [key, val] of Object.entries(value)) {\n const replacedValue = this.config.replacer(key, val);\n if (replacedValue !== undefined) {\n sanitized[key] = this.sanitizeValue(replacedValue, seen);\n }\n }\n\n return sanitized;\n }\n\n /**\n * Sanitize a signal payload\n *\n * @param signal - Signal to sanitize\n * @returns Sanitized signal (new object, doesn't mutate original)\n */\n sanitize(signal: Signal): Signal {\n return {\n id: signal.id,\n objectId: signal.objectId,\n className: signal.className,\n method: signal.method,\n type: signal.type,\n timestamp: signal.timestamp,\n ...(signal.step && { step: signal.step }),\n ...(signal.duration !== undefined && { duration: signal.duration }),\n // `signal.args` is an array, so `sanitizeValue` always returns an array\n // (the `Array.isArray` branch maps element-wise).\n ...(signal.args && { args: this.sanitizeValue(signal.args) as unknown[] }),\n ...(signal.result !== undefined\n ? { result: this.sanitizeValue(signal.result) }\n : {}),\n // `sanitizeValue` flattens an `Error` into an Error-shaped plain object\n // (`{ message, name, stack }`); the Signal contract still types it as\n // `Error`, so retain that surface here.\n ...(signal.error && {\n error: this.sanitizeValue(signal.error) as Error,\n }),\n // Sanitizing an object yields a `Record<string, unknown>`.\n ...(signal.metadata && {\n metadata: this.sanitizeValue(signal.metadata) as Record<\n string,\n unknown\n >,\n }),\n };\n }\n}\n"],"names":[],"mappings":"AAyCA,MAAM,sBAAsB;AAAA,EAC1B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;AAQO,MAAM,gBAAgB;AAAA,EACnB;AAAA,EAER,YAAY,SAA6B,IAAI;AAC3C,SAAK,SAAS;AAAA,MACZ,YAAY,OAAO,cAAc;AAAA,MACjC,UAAU,OAAO,YAAY,KAAK,gBAAgB,KAAK,IAAI;AAAA,MAC3D,eAAe,OAAO,iBAAiB;AAAA,MACvC,eAAe,OAAO,iBAAiB;AAAA,IAAA;AAAA,EAE3C;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOQ,gBAAgB,KAAa,OAAyB;AAE5D,UAAM,WAAW,IAAI,YAAA;AACrB,QACE,KAAK,OAAO,WAAW,KAAK,CAAC,MAAM,SAAS,SAAS,EAAE,YAAA,CAAa,CAAC,GACrE;AACA,aAAO,KAAK,OAAO;AAAA,IACrB;AAGA,QAAI,OAAO,UAAU,YAAY,MAAM,SAAS,KAAM;AACpD,aAAO,GAAG,MAAM,UAAU,GAAG,GAAI,CAAC;AAAA,IACpC;AAEA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA,EAKQ,cAAc,OAAgB,OAAO,oBAAI,WAAoB;AAEnE,QAAI,SAAS,MAAM;AACjB,aAAO;AAAA,IACT;AAGA,QAAI,OAAO,UAAU,UAAU;AAC7B,aAAO;AAAA,IACT;AAGA,QAAI,KAAK,IAAI,KAAK,GAAG;AACnB,aAAO;AAAA,IACT;AACA,SAAK,IAAI,KAAK;AAGd,QAAI,MAAM,QAAQ,KAAK,GAAG;AACxB,aAAO,MAAM,IAAI,CAAC,SAAS,KAAK,cAAc,MAAM,IAAI,CAAC;AAAA,IAC3D;AAGA,QAAI,iBAAiB,OAAO;AAC1B,aAAO;AAAA,QACL,SAAS,MAAM;AAAA,QACf,MAAM,MAAM;AAAA,QACZ,OAAO,MAAM,QACT,MAAM,MACH,MAAM,IAAI,EACV,MAAM,GAAG,KAAK,OAAO,aAAa,EAClC,KAAK,IAAI,IACZ;AAAA,MAAA;AAAA,IAER;AAGA,UAAM,YAAqC,CAAA;AAC3C,eAAW,CAAC,KAAK,GAAG,KAAK,OAAO,QAAQ,KAAK,GAAG;AAC9C,YAAM,gBAAgB,KAAK,OAAO,SAAS,KAAK,GAAG;AACnD,UAAI,kBAAkB,QAAW;AAC/B,kBAAU,GAAG,IAAI,KAAK,cAAc,eAAe,IAAI;AAAA,MACzD;AAAA,IACF;AAEA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,SAAS,QAAwB;AAC/B,WAAO;AAAA,MACL,IAAI,OAAO;AAAA,MACX,UAAU,OAAO;AAAA,MACjB,WAAW,OAAO;AAAA,MAClB,QAAQ,OAAO;AAAA,MACf,MAAM,OAAO;AAAA,MACb,WAAW,OAAO;AAAA,MAClB,GAAI,OAAO,QAAQ,EAAE,MAAM,OAAO,KAAA;AAAA,MAClC,GAAI,OAAO,aAAa,UAAa,EAAE,UAAU,OAAO,SAAA;AAAA;AAAA;AAAA,MAGxD,GAAI,OAAO,QAAQ,EAAE,MAAM,KAAK,cAAc,OAAO,IAAI,EAAA;AAAA,MACzD,GAAI,OAAO,WAAW,SAClB,EAAE,QAAQ,KAAK,cAAc,OAAO,MAAM,EAAA,IAC1C,CAAA;AAAA;AAAA;AAAA;AAAA,MAIJ,GAAI,OAAO,SAAS;AAAA,QAClB,OAAO,KAAK,cAAc,OAAO,KAAK;AAAA,MAAA;AAAA;AAAA,MAGxC,GAAI,OAAO,YAAY;AAAA,QACrB,UAAU,KAAK,cAAc,OAAO,QAAQ;AAAA,MAAA;AAAA,IAI9C;AAAA,EAEJ;AACF;"}
@@ -1,13 +1,13 @@
1
1
  {
2
2
  "schemaVersion": 1,
3
- "generatedAt": "2026-06-26T13:47:22.384Z",
3
+ "generatedAt": "2026-06-26T18:49:16.333Z",
4
4
  "packageName": "@happyvertical/smrt-core",
5
- "packageVersion": "0.36.4",
5
+ "packageVersion": "0.36.6",
6
6
  "sourceManifestPath": "dist/manifest.json",
7
7
  "agentDocPath": "AGENTS.md",
8
8
  "sourceHashes": {
9
- "manifest": "3ac19b272f05e4db698c10cc04c9acdf76f47441473c007a510fc48a7bf68806",
10
- "packageJson": "41e370f5dcba8967fd290da0183c536bc6a1b011fb80d5dafcaff2cd4c233a39",
9
+ "manifest": "d67962963275387e02f1822f5e49429cc2ec8d1ba98fe97a8f4baacaa6d0463d",
10
+ "packageJson": "041c48882424b539736ba83dc232b7ce559bc924c684bed8cc4526669ebf7b89",
11
11
  "agents": "0fa157a078aa44a0bc104540bd27f0b1e52e66549b7994cba751438a8d44c827"
12
12
  },
13
13
  "exports": [
@@ -130,6 +130,7 @@
130
130
  "getDiff",
131
131
  "getFields",
132
132
  "getFieldsSync",
133
+ "getItemClass",
133
134
  "getOrUpsert",
134
135
  "getStiChildMetaType",
135
136
  "initialize",
@@ -153,15 +154,13 @@
153
154
  "name": "SmrtHierarchical",
154
155
  "qualifiedName": "@happyvertical/smrt-core:SmrtHierarchical",
155
156
  "collection": "smrthierarchicals",
156
- "tableName": "smrt_hierarchicals",
157
157
  "packageName": "@happyvertical/smrt-core",
158
158
  "extends": "SmrtObject",
159
159
  "fields": [
160
160
  {
161
161
  "name": "parentId",
162
162
  "type": "text",
163
- "required": false,
164
- "columnType": "TEXT"
163
+ "required": false
165
164
  }
166
165
  ],
167
166
  "relationships": [],
@@ -174,9 +173,7 @@
174
173
  "moveTo"
175
174
  ],
176
175
  "surfaces": [],
177
- "relationshipFeatures": [
178
- "uuidColumns"
179
- ],
176
+ "relationshipFeatures": [],
180
177
  "tags": [],
181
178
  "risks": []
182
179
  },
@@ -184,7 +181,6 @@
184
181
  "name": "SmrtJunction",
185
182
  "qualifiedName": "@happyvertical/smrt-core:SmrtJunction",
186
183
  "collection": "smrtjunctions",
187
- "tableName": "smrt_junctions",
188
184
  "packageName": "@happyvertical/smrt-core",
189
185
  "extends": "SmrtCollection",
190
186
  "fields": [],
@@ -197,9 +193,7 @@
197
193
  "setLinks"
198
194
  ],
199
195
  "surfaces": [],
200
- "relationshipFeatures": [
201
- "uuidColumns"
202
- ],
196
+ "relationshipFeatures": [],
203
197
  "tags": [],
204
198
  "risks": []
205
199
  },
@@ -272,33 +266,28 @@
272
266
  "name": "SmrtPolymorphicAssociation",
273
267
  "qualifiedName": "@happyvertical/smrt-core:SmrtPolymorphicAssociation",
274
268
  "collection": "smrtpolymorphicassociations",
275
- "tableName": "smrt_polymorphic_associations",
276
269
  "packageName": "@happyvertical/smrt-core",
277
270
  "extends": "SmrtObject",
278
271
  "fields": [
279
272
  {
280
273
  "name": "metaType",
281
274
  "type": "text",
282
- "required": true,
283
- "columnType": "TEXT"
275
+ "required": true
284
276
  },
285
277
  {
286
278
  "name": "metaId",
287
279
  "type": "text",
288
- "required": true,
289
- "columnType": "TEXT"
280
+ "required": true
290
281
  },
291
282
  {
292
283
  "name": "role",
293
284
  "type": "text",
294
- "required": true,
295
- "columnType": "TEXT"
285
+ "required": true
296
286
  },
297
287
  {
298
288
  "name": "sortOrder",
299
289
  "type": "integer",
300
- "required": false,
301
- "columnType": "INTEGER"
290
+ "required": false
302
291
  }
303
292
  ],
304
293
  "relationships": [],
@@ -307,8 +296,7 @@
307
296
  ],
308
297
  "surfaces": [],
309
298
  "relationshipFeatures": [
310
- "SmrtPolymorphicAssociation",
311
- "uuidColumns"
299
+ "SmrtPolymorphicAssociation"
312
300
  ],
313
301
  "tags": [],
314
302
  "risks": []
@@ -330,7 +318,7 @@
330
318
  "junctionCollections": 0,
331
319
  "hierarchicalObjects": 0,
332
320
  "polymorphicAssociations": 1,
333
- "uuidColumns": 6
321
+ "uuidColumns": 3
334
322
  },
335
323
  "agentDoc": "# @happyvertical/smrt-core\n\nORM, code generation, AI integration, and the DispatchBus. Everything else builds on this.\n\n## Key Classes\n\n| Class | File | Purpose |\n|-------|------|---------|\n| SmrtObject | `src/object.ts` | Base persistent object — save, delete, is(), do(), loadFromId/Slug |\n| SmrtCollection | `src/collection.ts` | CRUD collection — list, get, create, delete, getOrUpsert |\n| ObjectRegistry | `src/registry.ts` | Global singleton (globalThis) — class metadata, fields, STI chains, manifests |\n| DispatchBus | `src/dispatch/bus.ts` | Inter-agent messaging — emit, subscribe (persistent), process |\n| GlobalInterceptors | `src/interceptors.ts` | Plugin system — beforeList/Get/Save/Delete hooks (used by tenancy) |\n\n## SmrtObject Lifecycle\n\n`constructor(options)` → `initialize()` → ready for `save()`/`delete()`/`loadFromId()`\n\n- `initialize()`: loads field initializers, applies option values (options override initializers), loads from DB if id/slug provided\n- `save()`: upsert with STI validation, interceptor execution, auto-embeddings. Persisted objects (`isPersisted` — set by DB hydration and successful saves) upsert on `['id']` so natural-key edits (e.g. slug renames) update in place; new objects upsert on the natural-key conflict columns for ingestion-style dedup (#1472)\n- `is(criteria)` / `do(instructions)` / `describe()`: AI operations via function calling. They inject the object's own `toPublicJSON()` (sensitive fields stripped) as a \"content body\" so the model reasons over the instance. Options: `includeData: false` skips injection (for callers that already curate the relevant fields into the instruction); `maxDataLength` overrides the truncation budget. Neither key is forwarded to `ai.message()`. (#1567)\n- `getSlug()`: auto-generates from name → title → label → id\n- `loadRelated(fieldName)`: lazy-loads relationships (cached in `_loadedRelationships` Map)\n\n## SmrtCollection Query\n\n```typescript\nawait collection.list({\n where: { status: 'active', price: { op: '>', value: 10 } },\n limit: 50, offset: 0, orderBy: 'created_at DESC'\n});\n```\n\n**WHERE operators**: `=`, `>`, `<`, `>=`, `<=`, `!=`, `in`, `not in`, `like`, `is null`, `is not null`. Arrays auto-detect `IN`. Dot notation for JSON paths: `metadata.userId`.\n\nSTI child collections auto-filter by `_meta_type`.\n\n## @smrt() Decorator Options\n\nKey options: `tableName`, `tableStrategy` ('cti'|'sti'), `conflictColumns`, `api`/`mcp`/`cli` (generation config), `ai` (callable methods), `hooks` (beforeSave/afterSave/beforeDelete/afterDelete), `embeddings` (auto-generate), `tenantScoped`, `agent`.\n\nRegistration sets `SMRT_TABLE_NAME` static property (survives minification).\n\n## Domain Knowledge Artifacts\n\n`smrtPlugin()` writes runtime manifests and agent/developer knowledge artifacts:\n\n- local dev/build: `.smrt/manifest.json` and `.smrt/smrt-knowledge.json`\n- package build: `dist/manifest.json` and `dist/smrt-knowledge.json`\n\nKeep `manifest.json` runtime-focused. `smrt-knowledge.json` is the deterministic\nagent contract for downstream review and architecture tools.\n\nConfig precedence for knowledge is defaults → top-level `knowledge` in\n`smrt.config.ts` → `packages[packageName].knowledge` → plugin option →\nobject-level `@smrt({ knowledge })`.\n\nObject-level `knowledge: false` excludes an object from authored context only;\nit must not change runtime manifest registration. Use\n`knowledge: { tags, summary, risks }` for review-sensitive domain objects.\n\nHTTP knowledge routes are disabled by default. If `knowledge.api.enabled` is\ntrue, generated SvelteKit routes must stay GET-only and guarded by dev mode or\nadmin auth.\n\n## DispatchBus\n\n- `emit(signalType, payload, metadata)` → creates persistent Dispatch record\n- `on(pattern, handler)` → in-memory handler (immediate)\n- `subscribe({ signalType, subscriber })` → persistent subscription (survives restarts)\n- `process(subscriberName, handler)` → process pending dispatches\n- Wildcards: `campaign.*` matches `campaign.completed` (single segment only)\n- Tables: `_smrt_dispatch`, `_smrt_dispatch_subscriptions`\n- Status: `pending → processing → completed` (or `failed`)\n\n## Single Table Inheritance (STI)\n\n- Base: `@smrt({ tableStrategy: 'sti' })` — children inherit, share one table\n- Discriminator: `_meta_type` column with qualified names (`@happyvertical/smrt-content:Article`)\n- Child fields: `@meta()` decorator → stored in `_meta_data` JSONB (not as columns)\n- Polymorphic queries: collection loads `_meta_type`, creates correct subclass dynamically\n- Validation: fail-fast on save if `_meta_type` missing or mismatched\n\n## Code Generators\n\n| Generator | Location | Output |\n|-----------|----------|--------|\n| REST API | `src/generators/rest.ts` | OpenAPI-compliant CRUD endpoints |\n| CLI | `src/generators/cli.ts` | `objectname:action` admin commands — writable allowlist, exhaustive-include, `--from-file`, fail-closed tenant context |\n| MCP Server | `src/generators/mcp.ts` | Model Context Protocol tools |\n\n## Child Accessors (R10)\n\n`src/child-accessors.ts` installs a consistent `get<FieldName>()` instance method for every `@oneToMany` field at `@smrt()` registration time (e.g. `@oneToMany('OrderItem') items` → `order.getItems()`), delegating to `loadRelatedMany`. Two invariants:\n\n- **Additive** — never overwrites a hand-rolled method of the same name (checks the whole prototype chain). `Profile.getMetadata()` (key-value) and `ProfileRelationship.getTerms()` are preserved.\n- **Runtime-only** — attached to the prototype, invisible to the build-time manifest, so it never leaks into the REST/CLI/MCP surface.\n\nWhen the target declares multiple FKs back to the parent, annotate `@oneToMany(Target, { foreignKey: '<inverseField>' })`; `loadRelatedMany` and the eager `include:` loader both honor it (else first-match).\n\n## Vite Plugin\n\n```typescript\n// vite.config.ts — required for @smrt() decorators\nexport default defineConfig({\n esbuild: {\n tsconfigRaw: {\n compilerOptions: { experimentalDecorators: true, emitDecoratorMetadata: true }\n }\n }\n});\n```\n\n## Gotchas\n\n- **Never override toJSON()** — handles STI discriminator + meta field extraction. Use `transformJSON()`\n- **Property init order**: TypeScript initializers run first, then `initialize()` applies option values (options win)\n- **No runtime schema creation**: application tables must be prepared explicitly via migrations/tooling; runtime only verifies and fails clearly\n- **Retry logic**: `db.get()` (3 retries, 250ms) and `db.upsert()` (3 retries, 500ms) have built-in retry\n- **Field caching**: `_cachedFields` populated during `Collection.create()` — eliminates async `getFields()` per query\n- **Smart cloning**: arrays/objects shallow-cloned in property init to prevent aliasing (Issue #22)\n- **Table verification cache**: `isTableVerified(dbUrl, tableName)` avoids redundant `tableExists()` calls\n- **Manifest required**: build-time AST scanning creates manifest. Without vitest plugin → \"No field metadata\"\n- **Vite plugin loads scanner from `dist/` first**: `src/vite-plugin/import-build-aware.ts` prefers `dist/` when it exists on disk; it only falls back to `src/` on fresh clones. So if you edit `src/scanner/*.ts` or `src/schema/generator.ts` and want those edits reflected in consumer manifest generation, you must rebuild (`pnpm build` or have `pnpm dev` / `pnpm build:watch` running in core). This is intentional — sniffing `.ts` vs `.js` via `import.meta.url` was non-deterministic under tsx and broke 12–13 publishes (#1139).\n"
336
324
  }
@@ -10,7 +10,7 @@ export interface NoteOptions {
10
10
  /** Normalized identifier (e.g., URL, entity ID) */
11
11
  key: string;
12
12
  /** Strategy data (regex patterns, selectors, etc.) */
13
- value: any;
13
+ value: unknown;
14
14
  /** Additional metadata */
15
15
  metadata?: NoteMetadata;
16
16
  /** Confidence score (0.0 to 1.0) */
@@ -54,7 +54,7 @@ export interface NoteMetadata {
54
54
  /** Review notes */
55
55
  reviewNotes?: string;
56
56
  /** Allow any other properties */
57
- [key: string]: any;
57
+ [key: string]: unknown;
58
58
  }
59
59
  /**
60
60
  * Options for recalling notes
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/system/types.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/system/types.ts"],"names":[],"mappings":"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"}
@@ -1,44 +1,6 @@
1
- /**
2
- * Canonical SMRT system fields inherited from `SmrtObject`.
3
- *
4
- * These fields exist on every persistent object at runtime even when they are
5
- * not declared in a child class manifest. Keep this definition lightweight:
6
- * presence matters for metadata consumers, while schema generation still owns
7
- * the exact SQL defaults and constraints for these columns.
8
- */
9
- export declare const SMRT_SYSTEM_FIELDS: Readonly<{
10
- id: Readonly<{
11
- type: "text";
12
- _meta: Readonly<{
13
- __smrtSystemField: true;
14
- }>;
15
- }>;
16
- slug: Readonly<{
17
- type: "text";
18
- _meta: Readonly<{
19
- __smrtSystemField: true;
20
- }>;
21
- }>;
22
- context: Readonly<{
23
- type: "text";
24
- _meta: Readonly<{
25
- __smrtSystemField: true;
26
- }>;
27
- }>;
28
- created_at: Readonly<{
29
- type: "datetime";
30
- _meta: Readonly<{
31
- __smrtSystemField: true;
32
- }>;
33
- }>;
34
- updated_at: Readonly<{
35
- type: "datetime";
36
- _meta: Readonly<{
37
- __smrtSystemField: true;
38
- }>;
39
- }>;
40
- }>;
41
- export declare function isInjectedSmrtSystemField(field: any): boolean;
42
- export declare function cloneSmrtSystemFields(): Record<string, any>;
43
- export declare function prependSmrtSystemFields(fields: Map<string, any>): Map<string, any>;
1
+ import { FieldDefinition } from './scanner/types.js';
2
+ export declare const SMRT_SYSTEM_FIELDS: Readonly<Record<string, FieldDefinition>>;
3
+ export declare function isInjectedSmrtSystemField(field: unknown): boolean;
4
+ export declare function cloneSmrtSystemFields(): Record<string, FieldDefinition>;
5
+ export declare function prependSmrtSystemFields(fields: Map<string, FieldDefinition>): Map<string, FieldDefinition>;
44
6
  //# sourceMappingURL=system-fields.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"system-fields.d.ts","sourceRoot":"","sources":["../src/system-fields.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,eAAO,MAAM,kBAAkB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAqB7B,CAAC;AAEH,wBAAgB,yBAAyB,CAAC,KAAK,EAAE,GAAG,GAAG,OAAO,CAE7D;AAED,wBAAgB,qBAAqB,IAAI,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAW3D;AAED,wBAAgB,uBAAuB,CACrC,MAAM,EAAE,GAAG,CAAC,MAAM,EAAE,GAAG,CAAC,GACvB,GAAG,CAAC,MAAM,EAAE,GAAG,CAAC,CAelB"}
1
+ {"version":3,"file":"system-fields.d.ts","sourceRoot":"","sources":["../src/system-fields.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AAE1D,eAAO,MAAM,kBAAkB,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,eAAe,CAAC,CAsBrE,CAAC;AAEL,wBAAgB,yBAAyB,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAIjE;AAED,wBAAgB,qBAAqB,IAAI,MAAM,CAAC,MAAM,EAAE,eAAe,CAAC,CAWvE;AAED,wBAAgB,uBAAuB,CACrC,MAAM,EAAE,GAAG,CAAC,MAAM,EAAE,eAAe,CAAC,GACnC,GAAG,CAAC,MAAM,EAAE,eAAe,CAAC,CAe9B"}
@@ -21,7 +21,8 @@ const SMRT_SYSTEM_FIELDS = Object.freeze({
21
21
  })
22
22
  });
23
23
  function isInjectedSmrtSystemField(field) {
24
- return Boolean(field?._meta?.__smrtSystemField);
24
+ const meta = field?._meta;
25
+ return Boolean(meta?.__smrtSystemField);
25
26
  }
26
27
  function cloneSmrtSystemFields() {
27
28
  const fields = {};
@@ -1 +1 @@
1
- {"version":3,"file":"system-fields.js","sources":["../src/system-fields.ts"],"sourcesContent":["/**\n * Canonical SMRT system fields inherited from `SmrtObject`.\n *\n * These fields exist on every persistent object at runtime even when they are\n * not declared in a child class manifest. Keep this definition lightweight:\n * presence matters for metadata consumers, while schema generation still owns\n * the exact SQL defaults and constraints for these columns.\n */\n\nexport const SMRT_SYSTEM_FIELDS = Object.freeze({\n id: Object.freeze({\n type: 'text',\n _meta: Object.freeze({ __smrtSystemField: true }),\n }),\n slug: Object.freeze({\n type: 'text',\n _meta: Object.freeze({ __smrtSystemField: true }),\n }),\n context: Object.freeze({\n type: 'text',\n _meta: Object.freeze({ __smrtSystemField: true }),\n }),\n created_at: Object.freeze({\n type: 'datetime',\n _meta: Object.freeze({ __smrtSystemField: true }),\n }),\n updated_at: Object.freeze({\n type: 'datetime',\n _meta: Object.freeze({ __smrtSystemField: true }),\n }),\n});\n\nexport function isInjectedSmrtSystemField(field: any): boolean {\n return Boolean(field?._meta?.__smrtSystemField);\n}\n\nexport function cloneSmrtSystemFields(): Record<string, any> {\n const fields: Record<string, any> = {};\n\n for (const [fieldName, fieldDef] of Object.entries(SMRT_SYSTEM_FIELDS)) {\n fields[fieldName] = {\n ...fieldDef,\n _meta: { ...(fieldDef._meta || {}) },\n };\n }\n\n return fields;\n}\n\nexport function prependSmrtSystemFields(\n fields: Map<string, any>,\n): Map<string, any> {\n const merged = new Map<string, any>();\n\n for (const [fieldName, fieldDef] of Object.entries(cloneSmrtSystemFields())) {\n merged.set(fieldName, fieldDef);\n }\n\n for (const [fieldName, fieldDef] of fields.entries()) {\n if (isInjectedSmrtSystemField(fieldDef) && merged.has(fieldName)) {\n continue;\n }\n merged.set(fieldName, fieldDef);\n }\n\n return merged;\n}\n"],"names":[],"mappings":"AASO,MAAM,qBAAqB,OAAO,OAAO;AAAA,EAC9C,IAAI,OAAO,OAAO;AAAA,IAChB,MAAM;AAAA,IACN,OAAO,OAAO,OAAO,EAAE,mBAAmB,MAAM;AAAA,EAAA,CACjD;AAAA,EACD,MAAM,OAAO,OAAO;AAAA,IAClB,MAAM;AAAA,IACN,OAAO,OAAO,OAAO,EAAE,mBAAmB,MAAM;AAAA,EAAA,CACjD;AAAA,EACD,SAAS,OAAO,OAAO;AAAA,IACrB,MAAM;AAAA,IACN,OAAO,OAAO,OAAO,EAAE,mBAAmB,MAAM;AAAA,EAAA,CACjD;AAAA,EACD,YAAY,OAAO,OAAO;AAAA,IACxB,MAAM;AAAA,IACN,OAAO,OAAO,OAAO,EAAE,mBAAmB,MAAM;AAAA,EAAA,CACjD;AAAA,EACD,YAAY,OAAO,OAAO;AAAA,IACxB,MAAM;AAAA,IACN,OAAO,OAAO,OAAO,EAAE,mBAAmB,MAAM;AAAA,EAAA,CACjD;AACH,CAAC;AAEM,SAAS,0BAA0B,OAAqB;AAC7D,SAAO,QAAQ,OAAO,OAAO,iBAAiB;AAChD;AAEO,SAAS,wBAA6C;AAC3D,QAAM,SAA8B,CAAA;AAEpC,aAAW,CAAC,WAAW,QAAQ,KAAK,OAAO,QAAQ,kBAAkB,GAAG;AACtE,WAAO,SAAS,IAAI;AAAA,MAClB,GAAG;AAAA,MACH,OAAO,EAAE,GAAI,SAAS,SAAS,CAAA,EAAC;AAAA,IAAG;AAAA,EAEvC;AAEA,SAAO;AACT;AAEO,SAAS,wBACd,QACkB;AAClB,QAAM,6BAAa,IAAA;AAEnB,aAAW,CAAC,WAAW,QAAQ,KAAK,OAAO,QAAQ,sBAAA,CAAuB,GAAG;AAC3E,WAAO,IAAI,WAAW,QAAQ;AAAA,EAChC;AAEA,aAAW,CAAC,WAAW,QAAQ,KAAK,OAAO,WAAW;AACpD,QAAI,0BAA0B,QAAQ,KAAK,OAAO,IAAI,SAAS,GAAG;AAChE;AAAA,IACF;AACA,WAAO,IAAI,WAAW,QAAQ;AAAA,EAChC;AAEA,SAAO;AACT;"}
1
+ {"version":3,"file":"system-fields.js","sources":["../src/system-fields.ts"],"sourcesContent":["/**\n * Canonical SMRT system fields inherited from `SmrtObject`.\n *\n * These fields exist on every persistent object at runtime even when they are\n * not declared in a child class manifest. Keep this definition lightweight:\n * presence matters for metadata consumers, while schema generation still owns\n * the exact SQL defaults and constraints for these columns.\n */\n\nimport type { FieldDefinition } from './scanner/types.js';\n\nexport const SMRT_SYSTEM_FIELDS: Readonly<Record<string, FieldDefinition>> =\n Object.freeze({\n id: Object.freeze({\n type: 'text',\n _meta: Object.freeze({ __smrtSystemField: true }),\n }),\n slug: Object.freeze({\n type: 'text',\n _meta: Object.freeze({ __smrtSystemField: true }),\n }),\n context: Object.freeze({\n type: 'text',\n _meta: Object.freeze({ __smrtSystemField: true }),\n }),\n created_at: Object.freeze({\n type: 'datetime',\n _meta: Object.freeze({ __smrtSystemField: true }),\n }),\n updated_at: Object.freeze({\n type: 'datetime',\n _meta: Object.freeze({ __smrtSystemField: true }),\n }),\n });\n\nexport function isInjectedSmrtSystemField(field: unknown): boolean {\n const meta = (field as { _meta?: { __smrtSystemField?: unknown } } | null)\n ?._meta;\n return Boolean(meta?.__smrtSystemField);\n}\n\nexport function cloneSmrtSystemFields(): Record<string, FieldDefinition> {\n const fields: Record<string, FieldDefinition> = {};\n\n for (const [fieldName, fieldDef] of Object.entries(SMRT_SYSTEM_FIELDS)) {\n fields[fieldName] = {\n ...fieldDef,\n _meta: { ...(fieldDef._meta || {}) },\n };\n }\n\n return fields;\n}\n\nexport function prependSmrtSystemFields(\n fields: Map<string, FieldDefinition>,\n): Map<string, FieldDefinition> {\n const merged = new Map<string, FieldDefinition>();\n\n for (const [fieldName, fieldDef] of Object.entries(cloneSmrtSystemFields())) {\n merged.set(fieldName, fieldDef);\n }\n\n for (const [fieldName, fieldDef] of fields.entries()) {\n if (isInjectedSmrtSystemField(fieldDef) && merged.has(fieldName)) {\n continue;\n }\n merged.set(fieldName, fieldDef);\n }\n\n return merged;\n}\n"],"names":[],"mappings":"AAWO,MAAM,qBACX,OAAO,OAAO;AAAA,EACZ,IAAI,OAAO,OAAO;AAAA,IAChB,MAAM;AAAA,IACN,OAAO,OAAO,OAAO,EAAE,mBAAmB,MAAM;AAAA,EAAA,CACjD;AAAA,EACD,MAAM,OAAO,OAAO;AAAA,IAClB,MAAM;AAAA,IACN,OAAO,OAAO,OAAO,EAAE,mBAAmB,MAAM;AAAA,EAAA,CACjD;AAAA,EACD,SAAS,OAAO,OAAO;AAAA,IACrB,MAAM;AAAA,IACN,OAAO,OAAO,OAAO,EAAE,mBAAmB,MAAM;AAAA,EAAA,CACjD;AAAA,EACD,YAAY,OAAO,OAAO;AAAA,IACxB,MAAM;AAAA,IACN,OAAO,OAAO,OAAO,EAAE,mBAAmB,MAAM;AAAA,EAAA,CACjD;AAAA,EACD,YAAY,OAAO,OAAO;AAAA,IACxB,MAAM;AAAA,IACN,OAAO,OAAO,OAAO,EAAE,mBAAmB,MAAM;AAAA,EAAA,CACjD;AACH,CAAC;AAEI,SAAS,0BAA0B,OAAyB;AACjE,QAAM,OAAQ,OACV;AACJ,SAAO,QAAQ,MAAM,iBAAiB;AACxC;AAEO,SAAS,wBAAyD;AACvE,QAAM,SAA0C,CAAA;AAEhD,aAAW,CAAC,WAAW,QAAQ,KAAK,OAAO,QAAQ,kBAAkB,GAAG;AACtE,WAAO,SAAS,IAAI;AAAA,MAClB,GAAG;AAAA,MACH,OAAO,EAAE,GAAI,SAAS,SAAS,CAAA,EAAC;AAAA,IAAG;AAAA,EAEvC;AAEA,SAAO;AACT;AAEO,SAAS,wBACd,QAC8B;AAC9B,QAAM,6BAAa,IAAA;AAEnB,aAAW,CAAC,WAAW,QAAQ,KAAK,OAAO,QAAQ,sBAAA,CAAuB,GAAG;AAC3E,WAAO,IAAI,WAAW,QAAQ;AAAA,EAChC;AAEA,aAAW,CAAC,WAAW,QAAQ,KAAK,OAAO,WAAW;AACpD,QAAI,0BAA0B,QAAQ,KAAK,OAAO,IAAI,SAAS,GAAG;AAChE;AAAA,IACF;AACA,WAAO,IAAI,WAAW,QAAQ;AAAA,EAChC;AAEA,SAAO;AACT;"}
@@ -1,9 +1,4 @@
1
- /**
2
- * Comprehensive test utilities for SMRT framework testing
3
- *
4
- * Provides unified mocking for collections, objects, and database operations
5
- * to support both CLI and API generator testing scenarios.
6
- */
1
+ import { Mock } from 'vitest';
7
2
  /**
8
3
  * Snapshot ObjectRegistry state and return a restore function for manifest-heavy
9
4
  * tests that mutate registry internals at runtime.
@@ -17,19 +12,31 @@ export interface MockObject {
17
12
  slug?: string;
18
13
  created_at?: string;
19
14
  updated_at?: string;
20
- [key: string]: any;
15
+ [key: string]: unknown;
21
16
  save: () => Promise<MockObject>;
22
17
  delete: () => Promise<void>;
23
18
  initialize: () => Promise<void>;
24
19
  }
20
+ /**
21
+ * Query options accepted by the mock collection's `list()`.
22
+ * Mirrors the loosely-typed SmrtCollection query surface used in tests:
23
+ * `where` keys may carry operator suffixes (e.g. `"age >"`), values are
24
+ * arbitrary, and ordering/pagination are simple primitives.
25
+ */
26
+ export interface MockListOptions {
27
+ where?: Record<string, unknown>;
28
+ orderBy?: string;
29
+ offset?: number;
30
+ limit?: number;
31
+ }
25
32
  /**
26
33
  * Mock collection with all CRUD operations
27
34
  */
28
35
  export interface MockCollection {
29
- list: (options?: any) => Promise<MockObject[]>;
36
+ list: (options?: MockListOptions) => Promise<MockObject[]>;
30
37
  get: (id: string) => Promise<MockObject | null>;
31
- create: (data: any) => Promise<MockObject>;
32
- update: (id: string, data: any) => Promise<MockObject>;
38
+ create: (data: Partial<MockObject>) => Promise<MockObject>;
39
+ update: (id: string, data: Partial<MockObject>) => Promise<MockObject>;
33
40
  delete: (id: string) => Promise<void>;
34
41
  initialize: () => Promise<void>;
35
42
  save: (object: MockObject) => Promise<MockObject>;
@@ -65,6 +72,17 @@ export declare class MockCollectionFactory {
65
72
  */
66
73
  getStorage(): Map<string, MockObject>;
67
74
  }
75
+ /**
76
+ * Overrides accepted by {@link MockContextFactory.createMockContext}.
77
+ * `db`/`ai`/`user` are shallow-merged into the default mock sub-contexts; any
78
+ * additional keys are spread onto the resulting context object.
79
+ */
80
+ export interface MockContextOverrides {
81
+ db?: Record<string, unknown>;
82
+ ai?: Record<string, unknown>;
83
+ user?: Record<string, unknown>;
84
+ [key: string]: unknown;
85
+ }
68
86
  /**
69
87
  * Complete mock context factory for CLI and API testing
70
88
  */
@@ -73,7 +91,11 @@ export declare class MockContextFactory {
73
91
  /**
74
92
  * Create a comprehensive mock context with database and AI
75
93
  */
76
- createMockContext(overrides?: any): any;
94
+ createMockContext(overrides?: MockContextOverrides): {
95
+ db: Record<string, unknown>;
96
+ ai: Record<string, unknown>;
97
+ user: Record<string, unknown>;
98
+ };
77
99
  /**
78
100
  * Create mock collections for testing
79
101
  */
@@ -95,7 +117,11 @@ export declare class TestSetup {
95
117
  * Set up complete test environment
96
118
  */
97
119
  static setupTestEnvironment(): {
98
- mockContext: any;
120
+ mockContext: {
121
+ db: Record<string, unknown>;
122
+ ai: Record<string, unknown>;
123
+ user: Record<string, unknown>;
124
+ };
99
125
  mockCollections: {
100
126
  TestUser: MockCollection;
101
127
  TestProduct: MockCollection;
@@ -105,7 +131,7 @@ export declare class TestSetup {
105
131
  /**
106
132
  * Mock collection constructor to return mock instances
107
133
  */
108
- static mockCollectionConstructors(mockCollections: any): any;
134
+ static mockCollectionConstructors(mockCollections: Partial<Record<'TestUser' | 'TestProduct', MockCollection>>): Mock;
109
135
  /**
110
136
  * Create realistic database query responses
111
137
  */
@@ -1 +1 @@
1
- {"version":3,"file":"test-utils.d.ts","sourceRoot":"","sources":["../src/test-utils.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"test-utils.d.ts","sourceRoot":"","sources":["../src/test-utils.ts"],"names":[],"mappings":"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"}
@@ -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;AAgJ5D;;GAEG;AACH,MAAM,WAAW,mBAAmB;IAClC;;;;OAIG;IACH,IAAI,CAAC,EAAE,QAAQ,GAAG,MAAM,CAAC;IAEzB;;;;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;CAC/B;AAuCD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqCG;AACH,wBAAsB,eAAe,CACnC,OAAO,GAAE,mBAAwB,GAChC,OAAO,CAAC,iBAAiB,CAAC,CAqH5B"}
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;AAgJ5D;;GAEG;AACH,MAAM,WAAW,mBAAmB;IAClC;;;;OAIG;IACH,IAAI,CAAC,EAAE,QAAQ,GAAG,MAAM,CAAC;IAEzB;;;;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;CAC/B;AAuCD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqCG;AACH,wBAAsB,eAAe,CACnC,OAAO,GAAE,mBAAwB,GAChC,OAAO,CAAC,iBAAiB,CAAC,CAsH5B"}