@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
package/dist/config.d.ts CHANGED
@@ -41,7 +41,7 @@ export interface AIConfig {
41
41
  /**
42
42
  * Additional provider-specific options
43
43
  */
44
- [key: string]: any;
44
+ [key: string]: unknown;
45
45
  }
46
46
  /**
47
47
  * AI usage tracking configuration
@@ -1 +1 @@
1
- {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;AAC1D,OAAO,KAAK,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,2BAA2B,CAAC;AAC/E,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAClD,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,wBAAwB,CAAC;AAEjE;;GAEG;AACH,MAAM,WAAW,aAAa;IAC5B,8BAA8B;IAC9B,OAAO,EAAE,OAAO,CAAC;CAClB;AAED;;GAEG;AACH,MAAM,WAAW,YAAY;IAC3B,kCAAkC;IAClC,OAAO,EAAE,OAAO,CAAC;CAClB;AAED;;;;;GAKG;AACH,MAAM,WAAW,QAAQ;IACvB;;;OAGG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;IAElB;;;OAGG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IAEf;;;OAGG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;IAEhB;;OAEG;IACH,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAC;CACpB;AAED;;GAEG;AACH,MAAM,WAAW,aAAa;IAC5B,0DAA0D;IAC1D,OAAO,CAAC,EAAE,OAAO,CAAC;IAElB,4EAA4E;IAC5E,OAAO,CAAC,EAAE,OAAO,CAAC;IAElB,yDAAyD;IACzD,aAAa,CAAC,EAAE,OAAO,CAAC;IAExB,2CAA2C;IAC3C,SAAS,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAE9D,gCAAgC;IAChC,QAAQ,CAAC,EAAE,cAAc,EAAE,CAAC;CAC7B;AAED;;;;;GAKG;AACH,MAAM,WAAW,kBAAkB;IACjC,qEAAqE;IACrE,OAAO,CAAC,EAAE,YAAY,CAAC;IAEvB,0DAA0D;IAC1D,OAAO,CAAC,EAAE,aAAa,CAAC;IAExB,0DAA0D;IAC1D,MAAM,CAAC,EAAE,YAAY,CAAC;IAEtB;;;OAGG;IACH,EAAE,CAAC,EAAE,QAAQ,CAAC;IAEd;;OAEG;IACH,KAAK,CAAC,EAAE,aAAa,CAAC;IAEtB;;;OAGG;IACH,YAAY,CAAC,EAAE,kBAAkB,GAAG,KAAK,CAAC;IAE1C,kCAAkC;IAClC,OAAO,CAAC,EAAE;QACR,iCAAiC;QACjC,GAAG,CAAC,EAAE,SAAS,CAAC;QAChB,iCAAiC;QACjC,QAAQ,CAAC,EAAE,aAAa,EAAE,CAAC;KAC5B,CAAC;CACH;AAmDD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqCG;AACH,iBAAS,MAAM,CAAC,OAAO,EAAE,kBAAkB,GAAG,IAAI,CAEjD;kBAFQ,MAAM;qBAOI,IAAI;sBAUH,kBAAkB;wBAQhB,MAAM;;AAG5B,OAAO,EAAE,MAAM,EAAE,CAAC;AAGlB,OAAO,EACL,KAAK,aAAa,EAClB,WAAW,EACX,aAAa,EACb,WAAW,EACX,oBAAoB,GACrB,MAAM,sBAAsB,CAAC"}
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;AAC1D,OAAO,KAAK,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,2BAA2B,CAAC;AAC/E,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAClD,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,wBAAwB,CAAC;AAEjE;;GAEG;AACH,MAAM,WAAW,aAAa;IAC5B,8BAA8B;IAC9B,OAAO,EAAE,OAAO,CAAC;CAClB;AAED;;GAEG;AACH,MAAM,WAAW,YAAY;IAC3B,kCAAkC;IAClC,OAAO,EAAE,OAAO,CAAC;CAClB;AAED;;;;;GAKG;AACH,MAAM,WAAW,QAAQ;IACvB;;;OAGG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;IAElB;;;OAGG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IAEf;;;OAGG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;IAEhB;;OAEG;IACH,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB;AAED;;GAEG;AACH,MAAM,WAAW,aAAa;IAC5B,0DAA0D;IAC1D,OAAO,CAAC,EAAE,OAAO,CAAC;IAElB,4EAA4E;IAC5E,OAAO,CAAC,EAAE,OAAO,CAAC;IAElB,yDAAyD;IACzD,aAAa,CAAC,EAAE,OAAO,CAAC;IAExB,2CAA2C;IAC3C,SAAS,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAE9D,gCAAgC;IAChC,QAAQ,CAAC,EAAE,cAAc,EAAE,CAAC;CAC7B;AAED;;;;;GAKG;AACH,MAAM,WAAW,kBAAkB;IACjC,qEAAqE;IACrE,OAAO,CAAC,EAAE,YAAY,CAAC;IAEvB,0DAA0D;IAC1D,OAAO,CAAC,EAAE,aAAa,CAAC;IAExB,0DAA0D;IAC1D,MAAM,CAAC,EAAE,YAAY,CAAC;IAEtB;;;OAGG;IACH,EAAE,CAAC,EAAE,QAAQ,CAAC;IAEd;;OAEG;IACH,KAAK,CAAC,EAAE,aAAa,CAAC;IAEtB;;;OAGG;IACH,YAAY,CAAC,EAAE,kBAAkB,GAAG,KAAK,CAAC;IAE1C,kCAAkC;IAClC,OAAO,CAAC,EAAE;QACR,iCAAiC;QACjC,GAAG,CAAC,EAAE,SAAS,CAAC;QAChB,iCAAiC;QACjC,QAAQ,CAAC,EAAE,aAAa,EAAE,CAAC;KAC5B,CAAC;CACH;AAmDD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqCG;AACH,iBAAS,MAAM,CAAC,OAAO,EAAE,kBAAkB,GAAG,IAAI,CAEjD;kBAFQ,MAAM;qBAOI,IAAI;sBAUH,kBAAkB;wBAQhB,MAAM;;AAG5B,OAAO,EAAE,MAAM,EAAE,CAAC;AAGlB,OAAO,EACL,KAAK,aAAa,EAClB,WAAW,EACX,aAAa,EACb,WAAW,EACX,oBAAoB,GACrB,MAAM,sBAAsB,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"config.js","sources":["../src/config.ts"],"sourcesContent":["/**\n * Global SMRT configuration system\n *\n * Provides application-level defaults for signal adapters.\n * Configuration follows a three-tier pattern:\n * 1. Global defaults (via smrt.configure())\n * 2. Per-instance overrides (via SmrtClassOptions)\n * 3. Runtime behavior (from merged config)\n */\n\nimport type { LoggerConfig } from '@happyvertical/logger';\nimport type { AiUsageHandler, SignalAdapter } from '@happyvertical/smrt-types';\nimport type { SignalBus } from './signals/bus.js';\nimport type { SanitizationConfig } from './signals/sanitizer.js';\n\n/**\n * Metrics adapter configuration\n */\nexport interface MetricsConfig {\n /** Enable metrics tracking */\n enabled: boolean;\n}\n\n/**\n * Pub/Sub adapter configuration\n */\nexport interface PubSubConfig {\n /** Enable pub/sub broadcasting */\n enabled: boolean;\n}\n\n/**\n * AI provider configuration\n *\n * Global defaults for AI client initialization.\n * Provides fallback values when AI options are not specified per-instance.\n */\nexport interface AIConfig {\n /**\n * Default AI provider to use\n * Examples: 'openai', 'anthropic', 'claude-cli', 'gemini', etc.\n */\n provider?: string;\n\n /**\n * Default model to use with the provider\n * Examples: 'gpt-4', 'claude-3-opus', 'sonnet', etc.\n */\n model?: string;\n\n /**\n * Default API key for the provider\n * Can be overridden by environment variables or instance options\n */\n apiKey?: string;\n\n /**\n * Additional provider-specific options\n */\n [key: string]: any;\n}\n\n/**\n * AI usage tracking configuration\n */\nexport interface AiUsageConfig {\n /** Enable normalized AI usage tracking (default: true) */\n enabled?: boolean;\n\n /** Enable persistence to _smrt_ai_usage when a DB exists (default: true) */\n persist?: boolean;\n\n /** Enable best-effort cost estimation (default: true) */\n estimateCosts?: boolean;\n\n /** Override USD-per-1K-token cost rates */\n costRates?: Record<string, { input: number; output: number }>;\n\n /** Additional usage handlers */\n handlers?: AiUsageHandler[];\n}\n\n/**\n * Global signal configuration\n *\n * Application-level defaults for signal adapters.\n * These can be overridden per-instance via SmrtClassOptions.\n */\nexport interface GlobalSignalConfig {\n /** Logging configuration (default: true with console, info level) */\n logging?: LoggerConfig;\n\n /** Metrics configuration (default: undefined/disabled) */\n metrics?: MetricsConfig;\n\n /** Pub/Sub configuration (default: undefined/disabled) */\n pubsub?: PubSubConfig;\n\n /**\n * AI provider configuration (default: undefined)\n * Provides global defaults for AI client initialization\n */\n ai?: AIConfig;\n\n /**\n * AI usage tracking configuration (default: enabled)\n */\n usage?: AiUsageConfig;\n\n /**\n * Signal sanitization configuration (default: enabled with standard redactions)\n * Set to false to disable sanitization\n */\n sanitization?: SanitizationConfig | false;\n\n /** Custom signal configuration */\n signals?: {\n /** Shared signal bus instance */\n bus?: SignalBus;\n /** Additional custom adapters */\n adapters?: SignalAdapter[];\n };\n}\n\n/**\n * Singleton configuration manager\n *\n * Manages global SMRT configuration with sensible defaults.\n */\nclass SmrtConfig {\n private static instance: SmrtConfig;\n private config: GlobalSignalConfig = {\n logging: true, // Default: console logging at info level\n };\n\n private constructor() {}\n\n /**\n * Get singleton instance\n */\n static getInstance(): SmrtConfig {\n if (!SmrtConfig.instance) {\n SmrtConfig.instance = new SmrtConfig();\n }\n return SmrtConfig.instance;\n }\n\n /**\n * Configure global defaults\n *\n * @param config - Configuration to apply\n */\n configure(config: GlobalSignalConfig): void {\n this.config = { ...this.config, ...config };\n }\n\n /**\n * Get current configuration\n *\n * @returns Current global configuration\n */\n getConfig(): GlobalSignalConfig {\n return { ...this.config };\n }\n\n /**\n * Reset to default configuration\n */\n reset(): void {\n this.config = { logging: true };\n }\n}\n\n/**\n * Global configuration API\n *\n * Callable function with attached methods for managing SMRT configuration.\n *\n * @example\n * ```typescript\n * import { config } from '@happyvertical/smrt-core';\n *\n * // Set application-level defaults\n * config({\n * logging: { level: 'debug' },\n * metrics: { enabled: true },\n * pubsub: { enabled: false },\n * ai: {\n * provider: 'claude-cli',\n * model: 'sonnet'\n * }\n * });\n *\n * // Reset to defaults\n * config.reset();\n *\n * // Get current configuration\n * const current = config.toJSON();\n *\n * // Auto-convert to string\n * console.log(`Config: ${config}`);\n *\n * // Auto-convert to JSON\n * JSON.stringify(config);\n *\n * // All SmrtClass instances now use these defaults\n * const product = new Product({ name: 'Widget' });\n * await product.initialize();\n * // product has logging at debug level, metrics enabled, and uses claude-cli by default\n * ```\n */\nfunction config(options: GlobalSignalConfig): void {\n SmrtConfig.getInstance().configure(options);\n}\n\n/**\n * Reset configuration to defaults\n */\nconfig.reset = (): void => {\n SmrtConfig.getInstance().reset();\n};\n\n/**\n * Get current configuration as object\n * Called automatically by JSON.stringify()\n *\n * @returns Current global configuration\n */\nconfig.toJSON = (): GlobalSignalConfig => SmrtConfig.getInstance().getConfig();\n\n/**\n * Convert configuration to string\n * Called automatically in string contexts\n *\n * @returns JSON string representation of configuration\n */\nconfig.toString = (): string =>\n JSON.stringify(SmrtConfig.getInstance().getConfig(), null, 2);\n\nexport { config };\n\n// Re-export env-config utilities from @happyvertical/utils\nexport {\n type ConfigOptions,\n convertType,\n loadEnvConfig,\n toCamelCase,\n toScreamingSnakeCase,\n} from '@happyvertical/utils';\n"],"names":["config"],"mappings":";AAiIA,MAAM,WAAW;AAAA,EACf,OAAe;AAAA,EACP,SAA6B;AAAA,IACnC,SAAS;AAAA;AAAA,EAAA;AAAA,EAGH,cAAc;AAAA,EAAC;AAAA;AAAA;AAAA;AAAA,EAKvB,OAAO,cAA0B;AAC/B,QAAI,CAAC,WAAW,UAAU;AACxB,iBAAW,WAAW,IAAI,WAAA;AAAA,IAC5B;AACA,WAAO,WAAW;AAAA,EACpB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,UAAUA,SAAkC;AAC1C,SAAK,SAAS,EAAE,GAAG,KAAK,QAAQ,GAAGA,QAAAA;AAAAA,EACrC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,YAAgC;AAC9B,WAAO,EAAE,GAAG,KAAK,OAAA;AAAA,EACnB;AAAA;AAAA;AAAA;AAAA,EAKA,QAAc;AACZ,SAAK,SAAS,EAAE,SAAS,KAAA;AAAA,EAC3B;AACF;AAwCA,SAAS,OAAO,SAAmC;AACjD,aAAW,YAAA,EAAc,UAAU,OAAO;AAC5C;AAKA,OAAO,QAAQ,MAAY;AACzB,aAAW,YAAA,EAAc,MAAA;AAC3B;AAQA,OAAO,SAAS,MAA0B,WAAW,YAAA,EAAc,UAAA;AAQnE,OAAO,WAAW,MAChB,KAAK,UAAU,WAAW,cAAc,UAAA,GAAa,MAAM,CAAC;"}
1
+ {"version":3,"file":"config.js","sources":["../src/config.ts"],"sourcesContent":["/**\n * Global SMRT configuration system\n *\n * Provides application-level defaults for signal adapters.\n * Configuration follows a three-tier pattern:\n * 1. Global defaults (via smrt.configure())\n * 2. Per-instance overrides (via SmrtClassOptions)\n * 3. Runtime behavior (from merged config)\n */\n\nimport type { LoggerConfig } from '@happyvertical/logger';\nimport type { AiUsageHandler, SignalAdapter } from '@happyvertical/smrt-types';\nimport type { SignalBus } from './signals/bus.js';\nimport type { SanitizationConfig } from './signals/sanitizer.js';\n\n/**\n * Metrics adapter configuration\n */\nexport interface MetricsConfig {\n /** Enable metrics tracking */\n enabled: boolean;\n}\n\n/**\n * Pub/Sub adapter configuration\n */\nexport interface PubSubConfig {\n /** Enable pub/sub broadcasting */\n enabled: boolean;\n}\n\n/**\n * AI provider configuration\n *\n * Global defaults for AI client initialization.\n * Provides fallback values when AI options are not specified per-instance.\n */\nexport interface AIConfig {\n /**\n * Default AI provider to use\n * Examples: 'openai', 'anthropic', 'claude-cli', 'gemini', etc.\n */\n provider?: string;\n\n /**\n * Default model to use with the provider\n * Examples: 'gpt-4', 'claude-3-opus', 'sonnet', etc.\n */\n model?: string;\n\n /**\n * Default API key for the provider\n * Can be overridden by environment variables or instance options\n */\n apiKey?: string;\n\n /**\n * Additional provider-specific options\n */\n [key: string]: unknown;\n}\n\n/**\n * AI usage tracking configuration\n */\nexport interface AiUsageConfig {\n /** Enable normalized AI usage tracking (default: true) */\n enabled?: boolean;\n\n /** Enable persistence to _smrt_ai_usage when a DB exists (default: true) */\n persist?: boolean;\n\n /** Enable best-effort cost estimation (default: true) */\n estimateCosts?: boolean;\n\n /** Override USD-per-1K-token cost rates */\n costRates?: Record<string, { input: number; output: number }>;\n\n /** Additional usage handlers */\n handlers?: AiUsageHandler[];\n}\n\n/**\n * Global signal configuration\n *\n * Application-level defaults for signal adapters.\n * These can be overridden per-instance via SmrtClassOptions.\n */\nexport interface GlobalSignalConfig {\n /** Logging configuration (default: true with console, info level) */\n logging?: LoggerConfig;\n\n /** Metrics configuration (default: undefined/disabled) */\n metrics?: MetricsConfig;\n\n /** Pub/Sub configuration (default: undefined/disabled) */\n pubsub?: PubSubConfig;\n\n /**\n * AI provider configuration (default: undefined)\n * Provides global defaults for AI client initialization\n */\n ai?: AIConfig;\n\n /**\n * AI usage tracking configuration (default: enabled)\n */\n usage?: AiUsageConfig;\n\n /**\n * Signal sanitization configuration (default: enabled with standard redactions)\n * Set to false to disable sanitization\n */\n sanitization?: SanitizationConfig | false;\n\n /** Custom signal configuration */\n signals?: {\n /** Shared signal bus instance */\n bus?: SignalBus;\n /** Additional custom adapters */\n adapters?: SignalAdapter[];\n };\n}\n\n/**\n * Singleton configuration manager\n *\n * Manages global SMRT configuration with sensible defaults.\n */\nclass SmrtConfig {\n private static instance: SmrtConfig;\n private config: GlobalSignalConfig = {\n logging: true, // Default: console logging at info level\n };\n\n private constructor() {}\n\n /**\n * Get singleton instance\n */\n static getInstance(): SmrtConfig {\n if (!SmrtConfig.instance) {\n SmrtConfig.instance = new SmrtConfig();\n }\n return SmrtConfig.instance;\n }\n\n /**\n * Configure global defaults\n *\n * @param config - Configuration to apply\n */\n configure(config: GlobalSignalConfig): void {\n this.config = { ...this.config, ...config };\n }\n\n /**\n * Get current configuration\n *\n * @returns Current global configuration\n */\n getConfig(): GlobalSignalConfig {\n return { ...this.config };\n }\n\n /**\n * Reset to default configuration\n */\n reset(): void {\n this.config = { logging: true };\n }\n}\n\n/**\n * Global configuration API\n *\n * Callable function with attached methods for managing SMRT configuration.\n *\n * @example\n * ```typescript\n * import { config } from '@happyvertical/smrt-core';\n *\n * // Set application-level defaults\n * config({\n * logging: { level: 'debug' },\n * metrics: { enabled: true },\n * pubsub: { enabled: false },\n * ai: {\n * provider: 'claude-cli',\n * model: 'sonnet'\n * }\n * });\n *\n * // Reset to defaults\n * config.reset();\n *\n * // Get current configuration\n * const current = config.toJSON();\n *\n * // Auto-convert to string\n * console.log(`Config: ${config}`);\n *\n * // Auto-convert to JSON\n * JSON.stringify(config);\n *\n * // All SmrtClass instances now use these defaults\n * const product = new Product({ name: 'Widget' });\n * await product.initialize();\n * // product has logging at debug level, metrics enabled, and uses claude-cli by default\n * ```\n */\nfunction config(options: GlobalSignalConfig): void {\n SmrtConfig.getInstance().configure(options);\n}\n\n/**\n * Reset configuration to defaults\n */\nconfig.reset = (): void => {\n SmrtConfig.getInstance().reset();\n};\n\n/**\n * Get current configuration as object\n * Called automatically by JSON.stringify()\n *\n * @returns Current global configuration\n */\nconfig.toJSON = (): GlobalSignalConfig => SmrtConfig.getInstance().getConfig();\n\n/**\n * Convert configuration to string\n * Called automatically in string contexts\n *\n * @returns JSON string representation of configuration\n */\nconfig.toString = (): string =>\n JSON.stringify(SmrtConfig.getInstance().getConfig(), null, 2);\n\nexport { config };\n\n// Re-export env-config utilities from @happyvertical/utils\nexport {\n type ConfigOptions,\n convertType,\n loadEnvConfig,\n toCamelCase,\n toScreamingSnakeCase,\n} from '@happyvertical/utils';\n"],"names":["config"],"mappings":";AAiIA,MAAM,WAAW;AAAA,EACf,OAAe;AAAA,EACP,SAA6B;AAAA,IACnC,SAAS;AAAA;AAAA,EAAA;AAAA,EAGH,cAAc;AAAA,EAAC;AAAA;AAAA;AAAA;AAAA,EAKvB,OAAO,cAA0B;AAC/B,QAAI,CAAC,WAAW,UAAU;AACxB,iBAAW,WAAW,IAAI,WAAA;AAAA,IAC5B;AACA,WAAO,WAAW;AAAA,EACpB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,UAAUA,SAAkC;AAC1C,SAAK,SAAS,EAAE,GAAG,KAAK,QAAQ,GAAGA,QAAAA;AAAAA,EACrC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,YAAgC;AAC9B,WAAO,EAAE,GAAG,KAAK,OAAA;AAAA,EACnB;AAAA;AAAA;AAAA;AAAA,EAKA,QAAc;AACZ,SAAK,SAAS,EAAE,SAAS,KAAA;AAAA,EAC3B;AACF;AAwCA,SAAS,OAAO,SAAmC;AACjD,aAAW,YAAA,EAAc,UAAU,OAAO;AAC5C;AAKA,OAAO,QAAQ,MAAY;AACzB,aAAW,YAAA,EAAc,MAAA;AAC3B;AAQA,OAAO,SAAS,MAA0B,WAAW,YAAA,EAAc,UAAA;AAQnE,OAAO,WAAW,MAChB,KAAK,UAAU,WAAW,cAAc,UAAA,GAAa,MAAM,CAAC;"}
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/consumer-plugin/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAIH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,MAAM,CAAC;AAGnC,MAAM,WAAW,mBAAmB;IAClC,4EAA4E;IAC5E,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;IACpB,uCAAuC;IACvC,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,2CAA2C;IAC3C,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,wBAAwB;IACxB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,iCAAiC;IACjC,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,oDAAoD;IACpD,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,4BAA4B;IAC5B,eAAe,CAAC,EAAE,OAAO,CAAC;CAC3B;AAUD;;GAEG;AACH,wBAAgB,YAAY,CAAC,OAAO,GAAE,mBAAwB,GAAG,MAAM,CAiGtE"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/consumer-plugin/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAIH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,MAAM,CAAC;AAsDnC,MAAM,WAAW,mBAAmB;IAClC,4EAA4E;IAC5E,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;IACpB,uCAAuC;IACvC,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,2CAA2C;IAC3C,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,wBAAwB;IACxB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,iCAAiC;IACjC,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,oDAAoD;IACpD,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,4BAA4B;IAC5B,eAAe,CAAC,EAAE,OAAO,CAAC;CAC3B;AAUD;;GAEG;AACH,wBAAgB,YAAY,CAAC,OAAO,GAAE,mBAAwB,GAAG,MAAM,CAiGtE"}
@@ -191,11 +191,12 @@ function determineImportPath(packageJson) {
191
191
  }
192
192
  const mainExport = packageJson.exports["."];
193
193
  if (mainExport) {
194
- if (typeof mainExport === "object") {
195
- if (mainExport.import) {
194
+ if (typeof mainExport === "object" && mainExport !== null) {
195
+ const conditional = mainExport;
196
+ if (conditional.import) {
196
197
  return packageName;
197
198
  }
198
- if (mainExport.default) {
199
+ if (conditional.default) {
199
200
  return packageName;
200
201
  }
201
202
  }
@@ -342,6 +343,9 @@ async function generateProjectTypes(typeManifest, typesDir, projectRoot) {
342
343
  return;
343
344
  }
344
345
  await generateDeclarations({
346
+ // The aggregated manifest is a runtime SMRT manifest assembled from external
347
+ // package manifests; it is intentionally typed loosely at the JSON boundary,
348
+ // so narrow it to the declaration generator's strict manifest shape here.
345
349
  manifest: typeManifest,
346
350
  outDir: typesDir,
347
351
  projectRoot,
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sources":["../../src/consumer-plugin/index.ts"],"sourcesContent":["/**\n * Vite plugin for consuming SMRT packages\n * Solves virtual module resolution in downstream projects\n */\n\nimport * as fs from 'node:fs';\nimport * as path from 'node:path';\nimport type { Plugin } from 'vite';\nimport { generateDeclarations } from '../prebuild/index.js';\n\nexport interface SmrtConsumerOptions {\n /** SMRT packages to scan (e.g., ['@my-org/products', '@my-org/content']) */\n packages?: string[];\n /** Generate TypeScript declarations */\n generateTypes?: boolean;\n /** Output directory for generated types */\n typesDir?: string;\n /** Project root path */\n projectRoot?: string;\n /** SvelteKit integration mode */\n svelteKit?: boolean;\n /** Use static types only (for federation builds) */\n staticTypes?: boolean;\n /** Disable file scanning */\n disableScanning?: boolean;\n}\n\nconst VIRTUAL_MODULES = {\n '@smrt/routes': 'smrt:routes',\n '@smrt/client': 'smrt:client',\n '@smrt/mcp': 'smrt:mcp',\n '@smrt/types': 'smrt:types',\n '@smrt/manifest': 'smrt:manifest',\n};\n\n/**\n * Consumer plugin for projects that use SMRT packages\n */\nexport function smrtConsumer(options: SmrtConsumerOptions = {}): Plugin {\n const {\n packages = [],\n generateTypes = true,\n typesDir = 'src/types/smrt-generated',\n projectRoot = process.cwd(),\n disableScanning = false,\n } = options;\n\n let smrtPackages: string[] = [];\n let typeManifest: any = null;\n let typesGenerated = false;\n\n return {\n name: 'smrt-consumer',\n\n async buildStart() {\n console.log('[smrt:consumer] Initializing SMRT consumer plugin');\n\n // Discover SMRT packages if not explicitly specified\n if (packages.length === 0 && !disableScanning) {\n smrtPackages = await discoverSmrtPackages(projectRoot);\n } else {\n smrtPackages = packages;\n }\n\n if (smrtPackages.length > 0) {\n console.log(\n `[smrt:consumer] Found SMRT packages: ${smrtPackages.join(', ')}`,\n );\n\n // Aggregate type manifests from discovered packages\n typeManifest = await aggregateTypeManifests(smrtPackages, projectRoot);\n\n // Save aggregated manifest for CLI discovery\n await saveAggregatedManifest(typeManifest, projectRoot);\n\n // Generate registration file for CLI class loading\n await generateRegistrationFile(typeManifest, projectRoot);\n\n // Generate types if requested\n if (generateTypes && !typesGenerated) {\n await generateProjectTypes(typeManifest, typesDir, projectRoot);\n typesGenerated = true;\n }\n } else {\n console.log('[smrt:consumer] No SMRT packages found');\n typeManifest = { version: '1.0.0', timestamp: Date.now(), objects: {} };\n }\n },\n\n resolveId(id, _importer) {\n // Resolve virtual modules to generated type declarations\n if (id in VIRTUAL_MODULES) {\n const typeFileName = getTypeFileName(id);\n const typePath = path.join(projectRoot, typesDir, typeFileName);\n\n // If types file exists, resolve to it\n if (fs.existsSync(typePath)) {\n return typePath;\n }\n\n // Otherwise use virtual module ID for runtime resolution\n return `\\0${VIRTUAL_MODULES[id as keyof typeof VIRTUAL_MODULES]}`;\n }\n return null;\n },\n\n async load(id) {\n // Handle virtual modules if types aren't available\n const cleanId = id.startsWith('\\0') ? id.slice(1) : id;\n\n if (!typeManifest) {\n typeManifest = { version: '1.0.0', timestamp: Date.now(), objects: {} };\n }\n\n switch (cleanId) {\n case 'smrt:routes':\n return generateFallbackRoutesModule();\n\n case 'smrt:client':\n return generateFallbackClientModule(typeManifest);\n\n case 'smrt:mcp':\n return generateFallbackMcpModule();\n\n case 'smrt:types':\n return generateFallbackTypesModule(typeManifest);\n\n case 'smrt:manifest':\n return generateFallbackManifestModule(typeManifest);\n\n default:\n return null;\n }\n },\n };\n}\n\n/**\n * Discover SMRT packages in node_modules\n */\nasync function discoverSmrtPackages(projectRoot: string): Promise<string[]> {\n const packages: string[] = [];\n const nodeModulesPath = path.join(projectRoot, 'node_modules');\n\n if (!fs.existsSync(nodeModulesPath)) {\n return packages;\n }\n\n try {\n // Check package.json for workspace dependencies\n const packageJsonPath = path.join(projectRoot, 'package.json');\n if (fs.existsSync(packageJsonPath)) {\n const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf-8'));\n const allDeps = {\n ...packageJson.dependencies,\n ...packageJson.devDependencies,\n ...packageJson.peerDependencies,\n };\n\n // Look for packages that likely contain SMRT objects\n for (const [name, version] of Object.entries(allDeps)) {\n if (\n typeof version === 'string' &&\n (name.includes('smrt') ||\n name.includes('@have/') ||\n (await hasSmrtManifest(nodeModulesPath, name)))\n ) {\n packages.push(name);\n }\n }\n }\n } catch (error) {\n console.warn('[smrt:consumer] Error discovering packages:', error);\n }\n\n return packages;\n}\n\n/**\n * Check if a package has SMRT manifest\n */\nasync function hasSmrtManifest(\n nodeModulesPath: string,\n packageName: string,\n): Promise<boolean> {\n const packagePath = path.join(nodeModulesPath, packageName);\n const manifestPath = path.join(\n packagePath,\n 'dist',\n 'manifest',\n 'static-manifest.js',\n );\n return fs.existsSync(manifestPath);\n}\n\n/**\n * Aggregate type manifests from multiple packages\n */\nasync function aggregateTypeManifests(\n packages: string[],\n projectRoot: string,\n): Promise<any> {\n const aggregatedManifest = {\n version: '1.0.0',\n timestamp: Date.now(),\n objects: {} as Record<string, any>,\n };\n\n for (const packageName of packages) {\n try {\n const packageDir = path.join(projectRoot, 'node_modules', packageName);\n\n // Load package.json for version and export information\n const packageJsonPath = path.join(packageDir, 'package.json');\n let packageJson: any;\n try {\n const packageJsonContent = fs.readFileSync(packageJsonPath, 'utf-8');\n packageJson = JSON.parse(packageJsonContent);\n } catch {\n console.warn(\n `[smrt:consumer] Could not read package.json for ${packageName}`,\n );\n continue;\n }\n\n // Try multiple manifest locations\n const manifestCandidates = [\n path.join(packageDir, 'dist', 'manifest', 'static-manifest.js'),\n path.join(packageDir, 'dist', 'manifest.json'),\n path.join(packageDir, 'manifest.json'),\n ];\n\n for (const manifestPath of manifestCandidates) {\n if (fs.existsSync(manifestPath)) {\n // Import or read the manifest\n let manifest: any;\n if (manifestPath.endsWith('.js')) {\n const manifestModule = await import(manifestPath);\n manifest = manifestModule.staticManifest || manifestModule.default;\n } else {\n const manifestContent = fs.readFileSync(manifestPath, 'utf-8');\n manifest = JSON.parse(manifestContent);\n }\n\n if (manifest?.objects) {\n console.log(\n `[smrt:consumer] Loaded manifest from ${packageName} (${Object.keys(manifest.objects).length} objects)`,\n );\n\n // ENHANCED: Preserve package metadata for each object\n for (const [objectName, objectDef] of Object.entries(\n manifest.objects,\n )) {\n const def = objectDef as any;\n\n aggregatedManifest.objects[objectName] = {\n ...def,\n // Ensure package metadata is preserved/set\n packageName:\n def.packageName || manifest.packageName || packageName,\n packageVersion:\n def.packageVersion ||\n manifest.packageVersion ||\n packageJson.version,\n // Add fallback import paths if missing\n importPath: def.importPath || determineImportPath(packageJson),\n exportName: def.exportName || def.className || objectName,\n collectionExportName:\n def.collectionExportName ||\n `${def.className || objectName}Collection`,\n };\n }\n\n break; // Use first found manifest for this package\n }\n }\n }\n } catch (error) {\n console.warn(\n `[smrt:consumer] Error loading manifest from ${packageName}:`,\n error,\n );\n }\n }\n\n return aggregatedManifest;\n}\n\n/**\n * Determine import path from package.json\n */\nfunction determineImportPath(packageJson: any): string {\n const packageName = packageJson.name;\n\n if (!packageName) {\n throw new Error('Package name not found in package.json');\n }\n\n // Strategy 1: Check for specific exports\n if (packageJson.exports) {\n // Check for objects export\n if (packageJson.exports['./objects']) {\n return `${packageName}/objects`;\n }\n\n // Check for main export\n const mainExport = packageJson.exports['.'];\n if (mainExport) {\n // Handle conditional exports\n if (typeof mainExport === 'object') {\n if (mainExport.import) {\n return packageName;\n }\n if (mainExport.default) {\n return packageName;\n }\n }\n return packageName;\n }\n }\n\n // Strategy 2: Check main field\n if (packageJson.main) {\n return packageName;\n }\n\n // Strategy 3: Fallback to package name\n return packageName;\n}\n\n/**\n * Save aggregated manifest to .smrt/manifest.json for CLI discovery\n */\nasync function saveAggregatedManifest(\n manifest: any,\n projectRoot: string,\n): Promise<void> {\n const smrtDir = path.join(projectRoot, '.smrt');\n const manifestPath = path.join(smrtDir, 'manifest.json');\n\n try {\n // Create .smrt directory if it doesn't exist\n if (!fs.existsSync(smrtDir)) {\n fs.mkdirSync(smrtDir, { recursive: true });\n }\n\n // Write manifest\n fs.writeFileSync(manifestPath, JSON.stringify(manifest, null, 2), 'utf-8');\n\n console.log(\n `[smrt:consumer] Saved aggregated manifest to .smrt/manifest.json (${Object.keys(manifest.objects).length} objects)`,\n );\n } catch (error) {\n console.warn('[smrt:consumer] Failed to save aggregated manifest:', error);\n }\n}\n\n/**\n * Generate registration file for CLI class loading\n *\n * Creates .smrt/register.js with static imports and registrations\n * for all external SMRT objects discovered during build.\n */\nasync function generateRegistrationFile(\n manifest: any,\n projectRoot: string,\n): Promise<void> {\n const smrtDir = path.join(projectRoot, '.smrt');\n const registerPath = path.join(smrtDir, 'register.js');\n\n // Build import statements and registrations\n const imports: string[] = [];\n const registrations: string[] = [];\n let importedEntryCount = 0;\n let registeredObjectCount = 0;\n\n const manifestObjects = manifest.objects as Record<string, any>;\n const manifestObjectLookup = new Map<string, any>();\n for (const [key, def] of Object.entries(manifestObjects)) {\n const candidate = def as any;\n const lookupKeys = [\n key,\n key.includes(':') ? key.split(':').pop() : undefined,\n candidate.qualifiedName,\n candidate.className,\n candidate.exportName,\n ];\n\n for (const lookupKey of lookupKeys) {\n if (lookupKey && !manifestObjectLookup.has(lookupKey)) {\n manifestObjectLookup.set(lookupKey, candidate);\n }\n }\n }\n\n const collectionClassMemo = new WeakMap<object, boolean>();\n\n const isCollectionClass = (def: any, seen = new Set<string>()): boolean => {\n if (!def || typeof def !== 'object') {\n return false;\n }\n\n const cached = collectionClassMemo.get(def);\n if (cached !== undefined) {\n return cached;\n }\n\n if (\n def?.extends === 'SmrtCollection' ||\n def?.extendsTypeArg !== undefined\n ) {\n collectionClassMemo.set(def, true);\n return true;\n }\n\n const parentName = def?.extendsQualified || def?.extends;\n if (!parentName || seen.has(parentName)) {\n collectionClassMemo.set(def, false);\n return false;\n }\n seen.add(parentName);\n\n const parentDef = manifestObjectLookup.get(parentName);\n const isCollection = parentDef ? isCollectionClass(parentDef, seen) : false;\n collectionClassMemo.set(def, isCollection);\n\n return isCollection;\n };\n\n for (const [objectName, objectDef] of Object.entries(manifestObjects)) {\n const def = objectDef as any;\n\n // Skip local objects (they're imported from local entry point)\n if (!def.packageName || def.packageName === manifest.packageName) {\n continue;\n }\n\n const importPath = def.importPath || def.packageName;\n const exportName = def.exportName || def.className || objectName;\n const collectionExportName = def.collectionExportName;\n const hasCollection = def.hasCollection; // Check if collection class actually exists\n const tableName = def.collection || objectName.toLowerCase();\n\n // Generate import statement\n // Only import collection if it exists (hasCollection is truthy)\n if (hasCollection && collectionExportName) {\n imports.push(\n `import { ${exportName}, ${collectionExportName} } from '${importPath}';`,\n );\n } else {\n imports.push(`import { ${exportName} } from '${importPath}';`);\n }\n importedEntryCount++;\n\n if (isCollectionClass(def)) {\n continue;\n }\n\n // Generate registration calls\n // The import above already triggers the @smrt() decorator which registers the class\n // properly with its simple name and qualified name. We call register() again with\n // an empty config just to ensure the class is registered (in case it lacks a decorator).\n // Do NOT pass { name: qualifiedName } as that creates a separate registry entry.\n registrations.push(\n `ObjectRegistry.register(${exportName}, { name: ${JSON.stringify(exportName)}, packageName: ${JSON.stringify(def.packageName)} });`,\n );\n\n // Only register collection if it exists\n if (hasCollection && collectionExportName) {\n registrations.push(\n `ObjectRegistry.registerCollection('${tableName}', ${collectionExportName});`,\n );\n }\n\n registeredObjectCount++;\n }\n\n // Skip generation if no external entries\n if (importedEntryCount === 0) {\n console.log('[smrt:consumer] No external entries - skipping register.js');\n return;\n }\n\n const registeredObjectLabel =\n registeredObjectCount === 1 ? 'object' : 'objects';\n\n // Generate file content\n const content = `/**\n * Auto-generated by @happyvertical/smrt-core/consumer-plugin\n * DO NOT EDIT - This file is regenerated on every build\n *\n * Registers SMRT objects from external packages for CLI discovery.\n * Generated at: ${new Date().toISOString()}\n */\n\nimport { ObjectRegistry } from '@happyvertical/smrt-core';\n\n${imports.join('\\n')}\n\n// Register all objects (executed during module evaluation)\n${registrations.join('\\n')}\n\nexport function registerAll() {\n // Objects are already registered during module evaluation\n console.log('[smrt:register] Registered ${registeredObjectCount} external ${registeredObjectLabel}');\n}\n`;\n\n // Create .smrt directory if needed\n if (!fs.existsSync(smrtDir)) {\n fs.mkdirSync(smrtDir, { recursive: true });\n }\n\n // Write registration file\n fs.writeFileSync(registerPath, content, 'utf-8');\n\n console.log(\n `[smrt:consumer] Generated .smrt/register.js with ${importedEntryCount} external entries (${registeredObjectCount} registered ${registeredObjectLabel})`,\n );\n}\n\n/**\n * Generate project-specific types\n */\nasync function generateProjectTypes(\n typeManifest: any,\n typesDir: string,\n projectRoot: string,\n): Promise<void> {\n if (!typeManifest || Object.keys(typeManifest.objects).length === 0) {\n console.log(\n '[smrt:consumer] No SMRT objects found, skipping type generation',\n );\n return;\n }\n\n await generateDeclarations({\n manifest: typeManifest,\n outDir: typesDir,\n projectRoot,\n includeVirtualModules: true,\n includeObjectTypes: true,\n });\n\n console.log(\n `[smrt:consumer] Generated types for ${Object.keys(typeManifest.objects).length} objects`,\n );\n}\n\n/**\n * Get type file name for virtual module\n */\nfunction getTypeFileName(virtualModule: string): string {\n const moduleMap: Record<string, string> = {\n '@smrt/routes': 'smrt-routes.d.ts',\n '@smrt/client': 'smrt-client.d.ts',\n '@smrt/mcp': 'smrt-mcp.d.ts',\n '@smrt/types': 'smrt-types.d.ts',\n '@smrt/manifest': 'smrt-manifest.d.ts',\n };\n return moduleMap[virtualModule] || 'smrt-unknown.d.ts';\n}\n\n/**\n * Fallback modules for when types aren't available\n */\nfunction generateFallbackRoutesModule(): string {\n return `\n// Fallback routes module\nexport function setupRoutes(app) {\n console.warn('[smrt:consumer] No routes available - SMRT packages may not be properly configured');\n}\nexport default setupRoutes;\n`;\n}\n\nfunction generateFallbackClientModule(manifest: any): string {\n const objects = Object.entries(manifest?.objects || {});\n if (objects.length === 0) {\n return `\n// Fallback client module\nexport function createClient(basePath = '/api/v1') {\n console.warn('[smrt:consumer] No API client available - SMRT packages may not be properly configured');\n return {};\n}\nexport default createClient;\n`;\n }\n\n // Generate basic client from manifest\n const clientMethods = objects\n .map(([name, obj]: [string, any]) => {\n const { collection } = obj;\n return `\n ${name}: {\n list: () => fetch(basePath + '/${collection}').then(r => r.json()),\n get: (id) => fetch(basePath + '/${collection}/' + id).then(r => r.json()),\n create: (data) => fetch(basePath + '/${collection}', {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify(data)\n }).then(r => r.json()),\n update: (id, data) => fetch(basePath + '/${collection}/' + id, {\n method: 'PUT',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify(data)\n }).then(r => r.json()),\n delete: (id) => fetch(basePath + '/${collection}/' + id, {\n method: 'DELETE'\n }).then(r => r.ok)\n }`;\n })\n .join(',');\n\n return `\n// Auto-generated API client from SMRT consumer\nexport function createClient(basePath = '/api/v1') {\n return {${clientMethods}\n };\n}\nexport default createClient;\n`;\n}\n\nfunction generateFallbackMcpModule(): string {\n return `\n// Fallback MCP module\nexport const tools = [];\nexport function createMCPServer() {\n console.warn('[smrt:consumer] No MCP tools available - SMRT packages may not be properly configured');\n return { name: 'smrt-consumer', version: '1.0.0', tools: [] };\n}\nexport default createMCPServer;\n`;\n}\n\nfunction generateFallbackTypesModule(manifest: any): string {\n const objects = Object.entries(manifest?.objects || {});\n if (objects.length === 0) {\n return `// No types available`;\n }\n\n // Generate basic interfaces\n const interfaces = objects.map(([_name, obj]: [string, any]) => {\n return `export interface ${obj.className}Data {\n id?: string;\n created_at?: string;\n updated_at?: string;\n [key: string]: any;\n}`;\n });\n\n return interfaces.join('\\n\\n');\n}\n\nfunction generateFallbackManifestModule(manifest: any): string {\n return `\n// Auto-generated manifest from SMRT consumer\nexport const manifest = ${JSON.stringify(manifest, null, 2)};\nexport default manifest;\n`;\n}\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sources":["../../src/consumer-plugin/index.ts"],"sourcesContent":["/**\n * Vite plugin for consuming SMRT packages\n * Solves virtual module resolution in downstream projects\n */\n\nimport * as fs from 'node:fs';\nimport * as path from 'node:path';\nimport type { Plugin } from 'vite';\nimport { generateDeclarations } from '../prebuild/index.js';\nimport type { SmartObjectManifest } from '../scanner/types.js';\n\n/**\n * Loosely-typed view of an object definition as carried by an external\n * package's static manifest. The static manifests are read from JSON at the\n * package boundary, so only the fields this plugin consumes are typed; the\n * index signature preserves any additional fields (e.g. for spreads). This is\n * a structural superset of a manifest `SmartObjectDefinition` plus the\n * consumer-only `hasCollection` marker.\n */\ninterface ConsumerObjectDefinition {\n className?: string;\n packageName?: string;\n packageVersion?: string;\n qualifiedName?: string;\n importPath?: string;\n exportName?: string;\n collectionExportName?: string;\n hasCollection?: boolean;\n collection?: string;\n extends?: string;\n extendsQualified?: string;\n extendsTypeArg?: string;\n [key: string]: unknown;\n}\n\n/**\n * Aggregated manifest assembled by the consumer plugin from one or more\n * external package manifests. Loosely typed because the inputs originate from\n * JSON read at the package boundary.\n */\ninterface ConsumerManifest {\n version: string;\n timestamp: number;\n packageName?: string;\n packageVersion?: string;\n objects: Record<string, ConsumerObjectDefinition>;\n}\n\n/**\n * Minimal structural shape of a parsed `package.json` consumed here (name,\n * version, and the export map used to derive import paths). The index\n * signature keeps the remaining fields accessible.\n */\ninterface ConsumerPackageJson {\n name?: string;\n version?: string;\n main?: string;\n exports?: Record<string, unknown>;\n [key: string]: unknown;\n}\n\nexport interface SmrtConsumerOptions {\n /** SMRT packages to scan (e.g., ['@my-org/products', '@my-org/content']) */\n packages?: string[];\n /** Generate TypeScript declarations */\n generateTypes?: boolean;\n /** Output directory for generated types */\n typesDir?: string;\n /** Project root path */\n projectRoot?: string;\n /** SvelteKit integration mode */\n svelteKit?: boolean;\n /** Use static types only (for federation builds) */\n staticTypes?: boolean;\n /** Disable file scanning */\n disableScanning?: boolean;\n}\n\nconst VIRTUAL_MODULES = {\n '@smrt/routes': 'smrt:routes',\n '@smrt/client': 'smrt:client',\n '@smrt/mcp': 'smrt:mcp',\n '@smrt/types': 'smrt:types',\n '@smrt/manifest': 'smrt:manifest',\n};\n\n/**\n * Consumer plugin for projects that use SMRT packages\n */\nexport function smrtConsumer(options: SmrtConsumerOptions = {}): Plugin {\n const {\n packages = [],\n generateTypes = true,\n typesDir = 'src/types/smrt-generated',\n projectRoot = process.cwd(),\n disableScanning = false,\n } = options;\n\n let smrtPackages: string[] = [];\n let typeManifest: ConsumerManifest | null = null;\n let typesGenerated = false;\n\n return {\n name: 'smrt-consumer',\n\n async buildStart() {\n console.log('[smrt:consumer] Initializing SMRT consumer plugin');\n\n // Discover SMRT packages if not explicitly specified\n if (packages.length === 0 && !disableScanning) {\n smrtPackages = await discoverSmrtPackages(projectRoot);\n } else {\n smrtPackages = packages;\n }\n\n if (smrtPackages.length > 0) {\n console.log(\n `[smrt:consumer] Found SMRT packages: ${smrtPackages.join(', ')}`,\n );\n\n // Aggregate type manifests from discovered packages\n typeManifest = await aggregateTypeManifests(smrtPackages, projectRoot);\n\n // Save aggregated manifest for CLI discovery\n await saveAggregatedManifest(typeManifest, projectRoot);\n\n // Generate registration file for CLI class loading\n await generateRegistrationFile(typeManifest, projectRoot);\n\n // Generate types if requested\n if (generateTypes && !typesGenerated) {\n await generateProjectTypes(typeManifest, typesDir, projectRoot);\n typesGenerated = true;\n }\n } else {\n console.log('[smrt:consumer] No SMRT packages found');\n typeManifest = { version: '1.0.0', timestamp: Date.now(), objects: {} };\n }\n },\n\n resolveId(id, _importer) {\n // Resolve virtual modules to generated type declarations\n if (id in VIRTUAL_MODULES) {\n const typeFileName = getTypeFileName(id);\n const typePath = path.join(projectRoot, typesDir, typeFileName);\n\n // If types file exists, resolve to it\n if (fs.existsSync(typePath)) {\n return typePath;\n }\n\n // Otherwise use virtual module ID for runtime resolution\n return `\\0${VIRTUAL_MODULES[id as keyof typeof VIRTUAL_MODULES]}`;\n }\n return null;\n },\n\n async load(id) {\n // Handle virtual modules if types aren't available\n const cleanId = id.startsWith('\\0') ? id.slice(1) : id;\n\n if (!typeManifest) {\n typeManifest = { version: '1.0.0', timestamp: Date.now(), objects: {} };\n }\n\n switch (cleanId) {\n case 'smrt:routes':\n return generateFallbackRoutesModule();\n\n case 'smrt:client':\n return generateFallbackClientModule(typeManifest);\n\n case 'smrt:mcp':\n return generateFallbackMcpModule();\n\n case 'smrt:types':\n return generateFallbackTypesModule(typeManifest);\n\n case 'smrt:manifest':\n return generateFallbackManifestModule(typeManifest);\n\n default:\n return null;\n }\n },\n };\n}\n\n/**\n * Discover SMRT packages in node_modules\n */\nasync function discoverSmrtPackages(projectRoot: string): Promise<string[]> {\n const packages: string[] = [];\n const nodeModulesPath = path.join(projectRoot, 'node_modules');\n\n if (!fs.existsSync(nodeModulesPath)) {\n return packages;\n }\n\n try {\n // Check package.json for workspace dependencies\n const packageJsonPath = path.join(projectRoot, 'package.json');\n if (fs.existsSync(packageJsonPath)) {\n const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf-8'));\n const allDeps = {\n ...packageJson.dependencies,\n ...packageJson.devDependencies,\n ...packageJson.peerDependencies,\n };\n\n // Look for packages that likely contain SMRT objects\n for (const [name, version] of Object.entries(allDeps)) {\n if (\n typeof version === 'string' &&\n (name.includes('smrt') ||\n name.includes('@have/') ||\n (await hasSmrtManifest(nodeModulesPath, name)))\n ) {\n packages.push(name);\n }\n }\n }\n } catch (error) {\n console.warn('[smrt:consumer] Error discovering packages:', error);\n }\n\n return packages;\n}\n\n/**\n * Check if a package has SMRT manifest\n */\nasync function hasSmrtManifest(\n nodeModulesPath: string,\n packageName: string,\n): Promise<boolean> {\n const packagePath = path.join(nodeModulesPath, packageName);\n const manifestPath = path.join(\n packagePath,\n 'dist',\n 'manifest',\n 'static-manifest.js',\n );\n return fs.existsSync(manifestPath);\n}\n\n/**\n * Aggregate type manifests from multiple packages\n */\nasync function aggregateTypeManifests(\n packages: string[],\n projectRoot: string,\n): Promise<ConsumerManifest> {\n const aggregatedManifest: ConsumerManifest = {\n version: '1.0.0',\n timestamp: Date.now(),\n objects: {},\n };\n\n for (const packageName of packages) {\n try {\n const packageDir = path.join(projectRoot, 'node_modules', packageName);\n\n // Load package.json for version and export information\n const packageJsonPath = path.join(packageDir, 'package.json');\n let packageJson: ConsumerPackageJson;\n try {\n const packageJsonContent = fs.readFileSync(packageJsonPath, 'utf-8');\n packageJson = JSON.parse(packageJsonContent) as ConsumerPackageJson;\n } catch {\n console.warn(\n `[smrt:consumer] Could not read package.json for ${packageName}`,\n );\n continue;\n }\n\n // Try multiple manifest locations\n const manifestCandidates = [\n path.join(packageDir, 'dist', 'manifest', 'static-manifest.js'),\n path.join(packageDir, 'dist', 'manifest.json'),\n path.join(packageDir, 'manifest.json'),\n ];\n\n for (const manifestPath of manifestCandidates) {\n if (fs.existsSync(manifestPath)) {\n // Import or read the manifest\n let manifest: Partial<ConsumerManifest> | undefined;\n if (manifestPath.endsWith('.js')) {\n const manifestModule = await import(manifestPath);\n manifest = manifestModule.staticManifest || manifestModule.default;\n } else {\n const manifestContent = fs.readFileSync(manifestPath, 'utf-8');\n manifest = JSON.parse(manifestContent) as Partial<ConsumerManifest>;\n }\n\n if (manifest?.objects) {\n console.log(\n `[smrt:consumer] Loaded manifest from ${packageName} (${Object.keys(manifest.objects).length} objects)`,\n );\n\n // ENHANCED: Preserve package metadata for each object\n for (const [objectName, objectDef] of Object.entries(\n manifest.objects,\n )) {\n const def = objectDef;\n\n aggregatedManifest.objects[objectName] = {\n ...def,\n // Ensure package metadata is preserved/set\n packageName:\n def.packageName || manifest.packageName || packageName,\n packageVersion:\n def.packageVersion ||\n manifest.packageVersion ||\n packageJson.version,\n // Add fallback import paths if missing\n importPath: def.importPath || determineImportPath(packageJson),\n exportName: def.exportName || def.className || objectName,\n collectionExportName:\n def.collectionExportName ||\n `${def.className || objectName}Collection`,\n };\n }\n\n break; // Use first found manifest for this package\n }\n }\n }\n } catch (error) {\n console.warn(\n `[smrt:consumer] Error loading manifest from ${packageName}:`,\n error,\n );\n }\n }\n\n return aggregatedManifest;\n}\n\n/**\n * Determine import path from package.json\n */\nfunction determineImportPath(packageJson: ConsumerPackageJson): string {\n const packageName = packageJson.name;\n\n if (!packageName) {\n throw new Error('Package name not found in package.json');\n }\n\n // Strategy 1: Check for specific exports\n if (packageJson.exports) {\n // Check for objects export\n if (packageJson.exports['./objects']) {\n return `${packageName}/objects`;\n }\n\n // Check for main export\n const mainExport = packageJson.exports['.'];\n if (mainExport) {\n // Handle conditional exports\n if (typeof mainExport === 'object' && mainExport !== null) {\n const conditional = mainExport as Record<string, unknown>;\n if (conditional.import) {\n return packageName;\n }\n if (conditional.default) {\n return packageName;\n }\n }\n return packageName;\n }\n }\n\n // Strategy 2: Check main field\n if (packageJson.main) {\n return packageName;\n }\n\n // Strategy 3: Fallback to package name\n return packageName;\n}\n\n/**\n * Save aggregated manifest to .smrt/manifest.json for CLI discovery\n */\nasync function saveAggregatedManifest(\n manifest: ConsumerManifest,\n projectRoot: string,\n): Promise<void> {\n const smrtDir = path.join(projectRoot, '.smrt');\n const manifestPath = path.join(smrtDir, 'manifest.json');\n\n try {\n // Create .smrt directory if it doesn't exist\n if (!fs.existsSync(smrtDir)) {\n fs.mkdirSync(smrtDir, { recursive: true });\n }\n\n // Write manifest\n fs.writeFileSync(manifestPath, JSON.stringify(manifest, null, 2), 'utf-8');\n\n console.log(\n `[smrt:consumer] Saved aggregated manifest to .smrt/manifest.json (${Object.keys(manifest.objects).length} objects)`,\n );\n } catch (error) {\n console.warn('[smrt:consumer] Failed to save aggregated manifest:', error);\n }\n}\n\n/**\n * Generate registration file for CLI class loading\n *\n * Creates .smrt/register.js with static imports and registrations\n * for all external SMRT objects discovered during build.\n */\nasync function generateRegistrationFile(\n manifest: ConsumerManifest,\n projectRoot: string,\n): Promise<void> {\n const smrtDir = path.join(projectRoot, '.smrt');\n const registerPath = path.join(smrtDir, 'register.js');\n\n // Build import statements and registrations\n const imports: string[] = [];\n const registrations: string[] = [];\n let importedEntryCount = 0;\n let registeredObjectCount = 0;\n\n const manifestObjects = manifest.objects;\n const manifestObjectLookup = new Map<string, ConsumerObjectDefinition>();\n for (const [key, def] of Object.entries(manifestObjects)) {\n const candidate = def;\n const lookupKeys = [\n key,\n key.includes(':') ? key.split(':').pop() : undefined,\n candidate.qualifiedName,\n candidate.className,\n candidate.exportName,\n ];\n\n for (const lookupKey of lookupKeys) {\n if (lookupKey && !manifestObjectLookup.has(lookupKey)) {\n manifestObjectLookup.set(lookupKey, candidate);\n }\n }\n }\n\n const collectionClassMemo = new WeakMap<object, boolean>();\n\n const isCollectionClass = (\n def: ConsumerObjectDefinition | undefined,\n seen = new Set<string>(),\n ): boolean => {\n if (!def || typeof def !== 'object') {\n return false;\n }\n\n const cached = collectionClassMemo.get(def);\n if (cached !== undefined) {\n return cached;\n }\n\n if (\n def?.extends === 'SmrtCollection' ||\n def?.extendsTypeArg !== undefined\n ) {\n collectionClassMemo.set(def, true);\n return true;\n }\n\n const parentName = def?.extendsQualified || def?.extends;\n if (!parentName || seen.has(parentName)) {\n collectionClassMemo.set(def, false);\n return false;\n }\n seen.add(parentName);\n\n const parentDef = manifestObjectLookup.get(parentName);\n const isCollection = parentDef ? isCollectionClass(parentDef, seen) : false;\n collectionClassMemo.set(def, isCollection);\n\n return isCollection;\n };\n\n for (const [objectName, objectDef] of Object.entries(manifestObjects)) {\n const def = objectDef;\n\n // Skip local objects (they're imported from local entry point)\n if (!def.packageName || def.packageName === manifest.packageName) {\n continue;\n }\n\n const importPath = def.importPath || def.packageName;\n const exportName = def.exportName || def.className || objectName;\n const collectionExportName = def.collectionExportName;\n const hasCollection = def.hasCollection; // Check if collection class actually exists\n const tableName = def.collection || objectName.toLowerCase();\n\n // Generate import statement\n // Only import collection if it exists (hasCollection is truthy)\n if (hasCollection && collectionExportName) {\n imports.push(\n `import { ${exportName}, ${collectionExportName} } from '${importPath}';`,\n );\n } else {\n imports.push(`import { ${exportName} } from '${importPath}';`);\n }\n importedEntryCount++;\n\n if (isCollectionClass(def)) {\n continue;\n }\n\n // Generate registration calls\n // The import above already triggers the @smrt() decorator which registers the class\n // properly with its simple name and qualified name. We call register() again with\n // an empty config just to ensure the class is registered (in case it lacks a decorator).\n // Do NOT pass { name: qualifiedName } as that creates a separate registry entry.\n registrations.push(\n `ObjectRegistry.register(${exportName}, { name: ${JSON.stringify(exportName)}, packageName: ${JSON.stringify(def.packageName)} });`,\n );\n\n // Only register collection if it exists\n if (hasCollection && collectionExportName) {\n registrations.push(\n `ObjectRegistry.registerCollection('${tableName}', ${collectionExportName});`,\n );\n }\n\n registeredObjectCount++;\n }\n\n // Skip generation if no external entries\n if (importedEntryCount === 0) {\n console.log('[smrt:consumer] No external entries - skipping register.js');\n return;\n }\n\n const registeredObjectLabel =\n registeredObjectCount === 1 ? 'object' : 'objects';\n\n // Generate file content\n const content = `/**\n * Auto-generated by @happyvertical/smrt-core/consumer-plugin\n * DO NOT EDIT - This file is regenerated on every build\n *\n * Registers SMRT objects from external packages for CLI discovery.\n * Generated at: ${new Date().toISOString()}\n */\n\nimport { ObjectRegistry } from '@happyvertical/smrt-core';\n\n${imports.join('\\n')}\n\n// Register all objects (executed during module evaluation)\n${registrations.join('\\n')}\n\nexport function registerAll() {\n // Objects are already registered during module evaluation\n console.log('[smrt:register] Registered ${registeredObjectCount} external ${registeredObjectLabel}');\n}\n`;\n\n // Create .smrt directory if needed\n if (!fs.existsSync(smrtDir)) {\n fs.mkdirSync(smrtDir, { recursive: true });\n }\n\n // Write registration file\n fs.writeFileSync(registerPath, content, 'utf-8');\n\n console.log(\n `[smrt:consumer] Generated .smrt/register.js with ${importedEntryCount} external entries (${registeredObjectCount} registered ${registeredObjectLabel})`,\n );\n}\n\n/**\n * Generate project-specific types\n */\nasync function generateProjectTypes(\n typeManifest: ConsumerManifest,\n typesDir: string,\n projectRoot: string,\n): Promise<void> {\n if (!typeManifest || Object.keys(typeManifest.objects).length === 0) {\n console.log(\n '[smrt:consumer] No SMRT objects found, skipping type generation',\n );\n return;\n }\n\n await generateDeclarations({\n // The aggregated manifest is a runtime SMRT manifest assembled from external\n // package manifests; it is intentionally typed loosely at the JSON boundary,\n // so narrow it to the declaration generator's strict manifest shape here.\n manifest: typeManifest as unknown as SmartObjectManifest,\n outDir: typesDir,\n projectRoot,\n includeVirtualModules: true,\n includeObjectTypes: true,\n });\n\n console.log(\n `[smrt:consumer] Generated types for ${Object.keys(typeManifest.objects).length} objects`,\n );\n}\n\n/**\n * Get type file name for virtual module\n */\nfunction getTypeFileName(virtualModule: string): string {\n const moduleMap: Record<string, string> = {\n '@smrt/routes': 'smrt-routes.d.ts',\n '@smrt/client': 'smrt-client.d.ts',\n '@smrt/mcp': 'smrt-mcp.d.ts',\n '@smrt/types': 'smrt-types.d.ts',\n '@smrt/manifest': 'smrt-manifest.d.ts',\n };\n return moduleMap[virtualModule] || 'smrt-unknown.d.ts';\n}\n\n/**\n * Fallback modules for when types aren't available\n */\nfunction generateFallbackRoutesModule(): string {\n return `\n// Fallback routes module\nexport function setupRoutes(app) {\n console.warn('[smrt:consumer] No routes available - SMRT packages may not be properly configured');\n}\nexport default setupRoutes;\n`;\n}\n\nfunction generateFallbackClientModule(manifest: ConsumerManifest): string {\n const objects = Object.entries(manifest?.objects || {});\n if (objects.length === 0) {\n return `\n// Fallback client module\nexport function createClient(basePath = '/api/v1') {\n console.warn('[smrt:consumer] No API client available - SMRT packages may not be properly configured');\n return {};\n}\nexport default createClient;\n`;\n }\n\n // Generate basic client from manifest\n const clientMethods = objects\n .map(([name, obj]) => {\n const { collection } = obj;\n return `\n ${name}: {\n list: () => fetch(basePath + '/${collection}').then(r => r.json()),\n get: (id) => fetch(basePath + '/${collection}/' + id).then(r => r.json()),\n create: (data) => fetch(basePath + '/${collection}', {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify(data)\n }).then(r => r.json()),\n update: (id, data) => fetch(basePath + '/${collection}/' + id, {\n method: 'PUT',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify(data)\n }).then(r => r.json()),\n delete: (id) => fetch(basePath + '/${collection}/' + id, {\n method: 'DELETE'\n }).then(r => r.ok)\n }`;\n })\n .join(',');\n\n return `\n// Auto-generated API client from SMRT consumer\nexport function createClient(basePath = '/api/v1') {\n return {${clientMethods}\n };\n}\nexport default createClient;\n`;\n}\n\nfunction generateFallbackMcpModule(): string {\n return `\n// Fallback MCP module\nexport const tools = [];\nexport function createMCPServer() {\n console.warn('[smrt:consumer] No MCP tools available - SMRT packages may not be properly configured');\n return { name: 'smrt-consumer', version: '1.0.0', tools: [] };\n}\nexport default createMCPServer;\n`;\n}\n\nfunction generateFallbackTypesModule(manifest: ConsumerManifest): string {\n const objects = Object.entries(manifest?.objects || {});\n if (objects.length === 0) {\n return `// No types available`;\n }\n\n // Generate basic interfaces\n const interfaces = objects.map(([_name, obj]) => {\n return `export interface ${obj.className}Data {\n id?: string;\n created_at?: string;\n updated_at?: string;\n [key: string]: any;\n}`;\n });\n\n return interfaces.join('\\n\\n');\n}\n\nfunction generateFallbackManifestModule(manifest: ConsumerManifest): string {\n return `\n// Auto-generated manifest from SMRT consumer\nexport const manifest = ${JSON.stringify(manifest, null, 2)};\nexport default manifest;\n`;\n}\n"],"names":[],"mappings":"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"}
@@ -1,4 +1,4 @@
1
- import { DatabaseInterface } from '@happyvertical/sql';
1
+ import { DatabaseInterface, SchemasOption } from '@happyvertical/sql';
2
2
  /**
3
3
  * Unified type for all database configuration formats
4
4
  *
@@ -28,7 +28,7 @@ export type DatabaseConfig = string | {
28
28
  url?: string;
29
29
  type?: 'sqlite' | 'postgres' | 'duckdb' | 'json';
30
30
  authToken?: string;
31
- [key: string]: any;
31
+ [key: string]: unknown;
32
32
  } | DatabaseInterface;
33
33
  /**
34
34
  * Type guard to check if a value is a DatabaseInterface instance
@@ -60,7 +60,7 @@ export interface ResolveDatabaseOptions {
60
60
  * Intended for explicit tooling and test utilities that bootstrap schema
61
61
  * ahead of runtime. Core runtime no longer passes these automatically.
62
62
  */
63
- schemas?: Record<string, any>;
63
+ schemas?: SchemasOption;
64
64
  }
65
65
  /**
66
66
  * Resolve any DatabaseConfig format to a DatabaseInterface instance
@@ -1 +1 @@
1
- {"version":3,"file":"database.d.ts","sourceRoot":"","sources":["../src/database.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AAG5D;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,MAAM,MAAM,cAAc,GACtB,MAAM,GACN;IACE,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,QAAQ,GAAG,UAAU,GAAG,QAAQ,GAAG,MAAM,CAAC;IACjD,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAC;CACpB,GACD,iBAAiB,CAAC;AAEtB;;;;;;;;;;;;;GAaG;AACH,wBAAgB,mBAAmB,CACjC,KAAK,EAAE,OAAO,GACb,KAAK,IAAI,iBAAiB,CAO5B;AAED;;GAEG;AACH,MAAM,WAAW,sBAAsB;IACrC;;;OAGG;IACH,IAAI,CAAC,EAAE,MAAM,CAAC;IAEd;;;;;OAKG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;CAC/B;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH,wBAAsB,eAAe,CACnC,MAAM,EAAE,cAAc,EACtB,OAAO,GAAE,sBAA2B,GACnC,OAAO,CAAC,iBAAiB,CAAC,CA8B5B"}
1
+ {"version":3,"file":"database.d.ts","sourceRoot":"","sources":["../src/database.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,iBAAiB,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAG3E;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,MAAM,MAAM,cAAc,GACtB,MAAM,GACN;IACE,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,QAAQ,GAAG,UAAU,GAAG,QAAQ,GAAG,MAAM,CAAC;IACjD,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB,GACD,iBAAiB,CAAC;AAEtB;;;;;;;;;;;;;GAaG;AACH,wBAAgB,mBAAmB,CACjC,KAAK,EAAE,OAAO,GACb,KAAK,IAAI,iBAAiB,CAO5B;AAED;;GAEG;AACH,MAAM,WAAW,sBAAsB;IACrC;;;OAGG;IACH,IAAI,CAAC,EAAE,MAAM,CAAC;IAEd;;;;;OAKG;IACH,OAAO,CAAC,EAAE,aAAa,CAAC;CACzB;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH,wBAAsB,eAAe,CACnC,MAAM,EAAE,cAAc,EACtB,OAAO,GAAE,sBAA2B,GACnC,OAAO,CAAC,iBAAiB,CAAC,CAkC5B"}
@@ -1 +1 @@
1
- {"version":3,"file":"database.js","sources":["../src/database.ts"],"sourcesContent":["/**\n * Database configuration and resolution utilities\n *\n * This module provides a unified type for database configuration options\n * and a utility function to resolve any config format to a DatabaseInterface.\n *\n * @module\n */\n\nimport type { DatabaseInterface } from '@happyvertical/sql';\nimport { getDatabase } from '@happyvertical/sql';\n\n/**\n * Unified type for all database configuration formats\n *\n * Supports three formats:\n * - **String**: Connection URL (e.g., 'products.db', ':memory:', 'postgres://...')\n * - **Config object**: Full configuration with type, url, and options\n * - **DatabaseInterface**: Pre-initialized database instance\n *\n * @example\n * ```typescript\n * // String shortcut\n * const config: DatabaseConfig = 'products.db';\n *\n * // Config object\n * const config: DatabaseConfig = {\n * type: 'sqlite',\n * url: 'products.db',\n * authToken: 'token'\n * };\n *\n * // Pre-initialized instance\n * const db = await getDatabase({ type: 'sqlite', url: ':memory:' });\n * const config: DatabaseConfig = db;\n * ```\n */\nexport type DatabaseConfig =\n | string\n | {\n url?: string;\n type?: 'sqlite' | 'postgres' | 'duckdb' | 'json';\n authToken?: string;\n [key: string]: any;\n }\n | DatabaseInterface;\n\n/**\n * Type guard to check if a value is a DatabaseInterface instance\n *\n * @param value - Value to check\n * @returns True if value has query() and close() methods\n *\n * @example\n * ```typescript\n * if (isDatabaseInterface(config)) {\n * // config is DatabaseInterface\n * await config.query('SELECT 1');\n * }\n * ```\n */\nexport function isDatabaseInterface(\n value: unknown,\n): value is DatabaseInterface {\n return (\n value !== null &&\n typeof value === 'object' &&\n 'query' in value &&\n typeof (value as any).query === 'function'\n );\n}\n\n/**\n * Options for resolving a database configuration\n */\nexport interface ResolveDatabaseOptions {\n /**\n * Cache key for connection pooling.\n * If provided, the same dbid returns the same cached connection.\n */\n dbid?: string;\n\n /**\n * Optional pre-generated schemas to pass to the database adapter.\n *\n * Intended for explicit tooling and test utilities that bootstrap schema\n * ahead of runtime. Core runtime no longer passes these automatically.\n */\n schemas?: Record<string, any>;\n}\n\n/**\n * Resolve any DatabaseConfig format to a DatabaseInterface instance\n *\n * This utility function normalizes the three config formats:\n * 1. **String URL**: Passed to getDatabase() with auto-detected type\n * 2. **Config object**: Passed to getDatabase() directly\n * 3. **DatabaseInterface**: Returned as-is\n *\n * @param config - Database configuration in any supported format\n * @param options - Resolution options (dbid for caching, optional explicit schemas)\n * @returns Promise resolving to a DatabaseInterface instance\n *\n * @example\n * ```typescript\n * // String URL\n * const db = await resolveDatabase('products.db');\n *\n * // Config object\n * const db = await resolveDatabase({\n * type: 'postgres',\n * url: 'postgres://localhost/mydb'\n * });\n *\n * // Pre-initialized instance (returned as-is)\n * const existingDb = await getDatabase({ url: ':memory:' });\n * const db = await resolveDatabase(existingDb);\n * console.log(db === existingDb); // true\n * ```\n */\nexport async function resolveDatabase(\n config: DatabaseConfig,\n options: ResolveDatabaseOptions = {},\n): Promise<DatabaseInterface> {\n const { dbid, schemas } = options;\n\n // Already a DatabaseInterface instance - return as-is\n if (isDatabaseInterface(config)) {\n return config;\n }\n\n // String URL shortcut\n if (typeof config === 'string') {\n const isMemoryDb = config === ':memory:';\n return getDatabase({\n url: config,\n schemas,\n ...(isMemoryDb ? {} : { dbid: dbid ?? `smrt:${config}` }),\n });\n }\n\n // Config object\n // Only default to :memory: for SQLite (or unspecified type which defaults to SQLite)\n // Other adapters (json, postgres, duckdb) require explicit URLs\n const canUseMemory = !config.type || config.type === 'sqlite';\n const dbUrl = config.url || (canUseMemory ? ':memory:' : '');\n const isMemoryDb = dbUrl === ':memory:';\n return getDatabase({\n ...config,\n url: dbUrl,\n schemas,\n ...(isMemoryDb ? {} : { dbid: dbid ?? `smrt:${dbUrl}` }),\n } as any);\n}\n"],"names":["isMemoryDb"],"mappings":";AA6DO,SAAS,oBACd,OAC4B;AAC5B,SACE,UAAU,QACV,OAAO,UAAU,YACjB,WAAW,SACX,OAAQ,MAAc,UAAU;AAEpC;AAkDA,eAAsB,gBACpB,QACA,UAAkC,IACN;AAC5B,QAAM,EAAE,MAAM,QAAA,IAAY;AAG1B,MAAI,oBAAoB,MAAM,GAAG;AAC/B,WAAO;AAAA,EACT;AAGA,MAAI,OAAO,WAAW,UAAU;AAC9B,UAAMA,cAAa,WAAW;AAC9B,WAAO,YAAY;AAAA,MACjB,KAAK;AAAA,MACL;AAAA,MACA,GAAIA,cAAa,CAAA,IAAK,EAAE,MAAM,QAAQ,QAAQ,MAAM,GAAA;AAAA,IAAG,CACxD;AAAA,EACH;AAKA,QAAM,eAAe,CAAC,OAAO,QAAQ,OAAO,SAAS;AACrD,QAAM,QAAQ,OAAO,QAAQ,eAAe,aAAa;AACzD,QAAM,aAAa,UAAU;AAC7B,SAAO,YAAY;AAAA,IACjB,GAAG;AAAA,IACH,KAAK;AAAA,IACL;AAAA,IACA,GAAI,aAAa,CAAA,IAAK,EAAE,MAAM,QAAQ,QAAQ,KAAK,GAAA;AAAA,EAAG,CAChD;AACV;"}
1
+ {"version":3,"file":"database.js","sources":["../src/database.ts"],"sourcesContent":["/**\n * Database configuration and resolution utilities\n *\n * This module provides a unified type for database configuration options\n * and a utility function to resolve any config format to a DatabaseInterface.\n *\n * @module\n */\n\nimport type { DatabaseInterface, SchemasOption } from '@happyvertical/sql';\nimport { getDatabase } from '@happyvertical/sql';\n\n/**\n * Unified type for all database configuration formats\n *\n * Supports three formats:\n * - **String**: Connection URL (e.g., 'products.db', ':memory:', 'postgres://...')\n * - **Config object**: Full configuration with type, url, and options\n * - **DatabaseInterface**: Pre-initialized database instance\n *\n * @example\n * ```typescript\n * // String shortcut\n * const config: DatabaseConfig = 'products.db';\n *\n * // Config object\n * const config: DatabaseConfig = {\n * type: 'sqlite',\n * url: 'products.db',\n * authToken: 'token'\n * };\n *\n * // Pre-initialized instance\n * const db = await getDatabase({ type: 'sqlite', url: ':memory:' });\n * const config: DatabaseConfig = db;\n * ```\n */\nexport type DatabaseConfig =\n | string\n | {\n url?: string;\n type?: 'sqlite' | 'postgres' | 'duckdb' | 'json';\n authToken?: string;\n [key: string]: unknown;\n }\n | DatabaseInterface;\n\n/**\n * Type guard to check if a value is a DatabaseInterface instance\n *\n * @param value - Value to check\n * @returns True if value has query() and close() methods\n *\n * @example\n * ```typescript\n * if (isDatabaseInterface(config)) {\n * // config is DatabaseInterface\n * await config.query('SELECT 1');\n * }\n * ```\n */\nexport function isDatabaseInterface(\n value: unknown,\n): value is DatabaseInterface {\n return (\n value !== null &&\n typeof value === 'object' &&\n 'query' in value &&\n typeof (value as { query: unknown }).query === 'function'\n );\n}\n\n/**\n * Options for resolving a database configuration\n */\nexport interface ResolveDatabaseOptions {\n /**\n * Cache key for connection pooling.\n * If provided, the same dbid returns the same cached connection.\n */\n dbid?: string;\n\n /**\n * Optional pre-generated schemas to pass to the database adapter.\n *\n * Intended for explicit tooling and test utilities that bootstrap schema\n * ahead of runtime. Core runtime no longer passes these automatically.\n */\n schemas?: SchemasOption;\n}\n\n/**\n * Resolve any DatabaseConfig format to a DatabaseInterface instance\n *\n * This utility function normalizes the three config formats:\n * 1. **String URL**: Passed to getDatabase() with auto-detected type\n * 2. **Config object**: Passed to getDatabase() directly\n * 3. **DatabaseInterface**: Returned as-is\n *\n * @param config - Database configuration in any supported format\n * @param options - Resolution options (dbid for caching, optional explicit schemas)\n * @returns Promise resolving to a DatabaseInterface instance\n *\n * @example\n * ```typescript\n * // String URL\n * const db = await resolveDatabase('products.db');\n *\n * // Config object\n * const db = await resolveDatabase({\n * type: 'postgres',\n * url: 'postgres://localhost/mydb'\n * });\n *\n * // Pre-initialized instance (returned as-is)\n * const existingDb = await getDatabase({ url: ':memory:' });\n * const db = await resolveDatabase(existingDb);\n * console.log(db === existingDb); // true\n * ```\n */\nexport async function resolveDatabase(\n config: DatabaseConfig,\n options: ResolveDatabaseOptions = {},\n): Promise<DatabaseInterface> {\n const { dbid, schemas } = options;\n\n // Already a DatabaseInterface instance - return as-is\n if (isDatabaseInterface(config)) {\n return config;\n }\n\n // String URL shortcut\n if (typeof config === 'string') {\n const isMemoryDb = config === ':memory:';\n return getDatabase({\n url: config,\n schemas,\n ...(isMemoryDb ? {} : { dbid: dbid ?? `smrt:${config}` }),\n });\n }\n\n // Config object\n // Only default to :memory: for SQLite (or unspecified type which defaults to SQLite)\n // Other adapters (json, postgres, duckdb) require explicit URLs\n const canUseMemory = !config.type || config.type === 'sqlite';\n const dbUrl = config.url || (canUseMemory ? ':memory:' : '');\n const isMemoryDb = dbUrl === ':memory:';\n // `config` is the loosely-typed config-object variant of `DatabaseConfig`\n // (it carries an open `[key: string]: unknown` index for adapter-specific\n // options). Cast the merged options to `getDatabase`'s own parameter type at\n // this boundary; the adapter validates the concrete shape at runtime.\n return getDatabase({\n ...config,\n url: dbUrl,\n schemas,\n ...(isMemoryDb ? {} : { dbid: dbid ?? `smrt:${dbUrl}` }),\n } as Parameters<typeof getDatabase>[0]);\n}\n"],"names":["isMemoryDb"],"mappings":";AA6DO,SAAS,oBACd,OAC4B;AAC5B,SACE,UAAU,QACV,OAAO,UAAU,YACjB,WAAW,SACX,OAAQ,MAA6B,UAAU;AAEnD;AAkDA,eAAsB,gBACpB,QACA,UAAkC,IACN;AAC5B,QAAM,EAAE,MAAM,QAAA,IAAY;AAG1B,MAAI,oBAAoB,MAAM,GAAG;AAC/B,WAAO;AAAA,EACT;AAGA,MAAI,OAAO,WAAW,UAAU;AAC9B,UAAMA,cAAa,WAAW;AAC9B,WAAO,YAAY;AAAA,MACjB,KAAK;AAAA,MACL;AAAA,MACA,GAAIA,cAAa,CAAA,IAAK,EAAE,MAAM,QAAQ,QAAQ,MAAM,GAAA;AAAA,IAAG,CACxD;AAAA,EACH;AAKA,QAAM,eAAe,CAAC,OAAO,QAAQ,OAAO,SAAS;AACrD,QAAM,QAAQ,OAAO,QAAQ,eAAe,aAAa;AACzD,QAAM,aAAa,UAAU;AAK7B,SAAO,YAAY;AAAA,IACjB,GAAG;AAAA,IACH,KAAK;AAAA,IACL;AAAA,IACA,GAAI,aAAa,CAAA,IAAK,EAAE,MAAM,QAAQ,QAAQ,KAAK,GAAA;AAAA,EAAG,CAClB;AACxC;"}
@@ -1,9 +1,21 @@
1
1
  import { EmbeddingProviderType, ProjectEmbeddingConfig } from './types';
2
- export type OptionalModuleImporter = (moduleName: string) => Promise<any>;
2
+ export type OptionalModuleImporter = (moduleName: string) => Promise<unknown>;
3
3
  export declare const LOCAL_TRANSFORMERS_PACKAGES: readonly ["@huggingface/transformers", "@xenova/transformers"];
4
4
  export type LocalTransformersPackage = (typeof LOCAL_TRANSFORMERS_PACKAGES)[number];
5
+ /**
6
+ * Minimal surface of a transformers.js package used for local embeddings.
7
+ * Only the `pipeline` factory is consumed; its result is narrowed to a
8
+ * {@link FeatureExtractionPipeline} at the call site.
9
+ */
10
+ export interface TransformersModule {
11
+ pipeline: (task: string, model: string) => Promise<unknown>;
12
+ }
5
13
  export interface TransformersModuleResolution {
6
- module: any;
14
+ /**
15
+ * The imported module namespace. Typed as `unknown` because the importer may
16
+ * resolve arbitrary modules; consumers cast to {@link TransformersModule}.
17
+ */
18
+ module: unknown;
7
19
  packageName: LocalTransformersPackage;
8
20
  }
9
21
  export declare function resolveLocalTransformersModule(importModule?: OptionalModuleImporter): Promise<TransformersModuleResolution>;
@@ -1 +1 @@
1
- {"version":3,"file":"provider.d.ts","sourceRoot":"","sources":["../../src/embeddings/provider.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAE,qBAAqB,EAAE,sBAAsB,EAAE,MAAM,SAAS,CAAC;AAY7E,MAAM,MAAM,sBAAsB,GAAG,CAAC,UAAU,EAAE,MAAM,KAAK,OAAO,CAAC,GAAG,CAAC,CAAC;AAE1E,eAAO,MAAM,2BAA2B,gEAG9B,CAAC;AAEX,MAAM,MAAM,wBAAwB,GAClC,CAAC,OAAO,2BAA2B,CAAC,CAAC,MAAM,CAAC,CAAC;AAE/C,MAAM,WAAW,4BAA4B;IAC3C,MAAM,EAAE,GAAG,CAAC;IACZ,WAAW,EAAE,wBAAwB,CAAC;CACvC;AAmBD,wBAAsB,8BAA8B,CAClD,YAAY,GAAE,sBAAuC,GACpD,OAAO,CAAC,4BAA4B,CAAC,CAavC;AAoBD;;;;;;;GAOG;AACH,qBAAa,iBAAiB;IAC5B,OAAO,CAAC,aAAa,CAA0C;IAC/D,OAAO,CAAC,oBAAoB,CACrB;IACP,OAAO,CAAC,MAAM,CAAyB;IACvC,OAAO,CAAC,EAAE,CAA4B;IAEtC;;;;;OAKG;gBACS,MAAM,EAAE,sBAAsB,EAAE,EAAE,CAAC,EAAE,OAAO;IAUxD;;;;;;OAMG;IACG,KAAK,CACT,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE,EACvB,gBAAgB,CAAC,EAAE,qBAAqB,GACvC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC;IAuBtB;;OAEG;YACW,UAAU;IAMxB;;OAEG;YACW,gBAAgB;IAoB9B;;OAEG;YACW,iBAAiB;IAY/B;;OAEG;YACW,WAAW;IAiBzB;;OAEG;IACH,YAAY,IAAI,MAAM;IAUtB;;OAEG;IACH,aAAa,IAAI,MAAM;IAIvB;;OAEG;IACG,gBAAgB,IAAI,OAAO,CAAC,OAAO,CAAC;IAS1C;;OAEG;IACH,aAAa,IAAI,OAAO;CAGzB;AAED;;GAEG;AACH,eAAO,MAAM,wBAAwB,EAAE,sBAKtC,CAAC"}
1
+ {"version":3,"file":"provider.d.ts","sourceRoot":"","sources":["../../src/embeddings/provider.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAE,qBAAqB,EAAE,sBAAsB,EAAE,MAAM,SAAS,CAAC;AAe7E,MAAM,MAAM,sBAAsB,GAAG,CAAC,UAAU,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;AAE9E,eAAO,MAAM,2BAA2B,gEAG9B,CAAC;AAEX,MAAM,MAAM,wBAAwB,GAClC,CAAC,OAAO,2BAA2B,CAAC,CAAC,MAAM,CAAC,CAAC;AAE/C;;;;GAIG;AACH,MAAM,WAAW,kBAAkB;IACjC,QAAQ,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;CAC7D;AAED,MAAM,WAAW,4BAA4B;IAC3C;;;OAGG;IACH,MAAM,EAAE,OAAO,CAAC;IAChB,WAAW,EAAE,wBAAwB,CAAC;CACvC;AAmBD,wBAAsB,8BAA8B,CAClD,YAAY,GAAE,sBAAuC,GACpD,OAAO,CAAC,4BAA4B,CAAC,CAavC;AAoBD;;;;;;;GAOG;AACH,qBAAa,iBAAiB;IAC5B,OAAO,CAAC,aAAa,CAA0C;IAC/D,OAAO,CAAC,oBAAoB,CACrB;IACP,OAAO,CAAC,MAAM,CAAyB;IACvC,OAAO,CAAC,EAAE,CAA4B;IAEtC;;;;;OAKG;gBACS,MAAM,EAAE,sBAAsB,EAAE,EAAE,CAAC,EAAE,OAAO;IAcxD;;;;;;OAMG;IACG,KAAK,CACT,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE,EACvB,gBAAgB,CAAC,EAAE,qBAAqB,GACvC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC;IAuBtB;;OAEG;YACW,UAAU;IAMxB;;OAEG;YACW,gBAAgB;IAoB9B;;OAEG;YACW,iBAAiB;IAc/B;;OAEG;YACW,WAAW;IAiBzB;;OAEG;IACH,YAAY,IAAI,MAAM;IAUtB;;OAEG;IACH,aAAa,IAAI,MAAM;IAIvB;;OAEG;IACG,gBAAgB,IAAI,OAAO,CAAC,OAAO,CAAC;IAS1C;;OAEG;IACH,aAAa,IAAI,OAAO;CAGzB;AAED;;GAEG;AACH,eAAO,MAAM,wBAAwB,EAAE,sBAKtC,CAAC"}
@@ -43,7 +43,7 @@ class EmbeddingProvider {
43
43
  */
44
44
  constructor(config, ai) {
45
45
  this.config = config;
46
- if (ai && typeof ai.embed === "function") {
46
+ if (typeof ai === "object" && ai !== null && typeof ai.embed === "function") {
47
47
  this.ai = ai;
48
48
  } else {
49
49
  this.ai = null;
@@ -100,8 +100,8 @@ class EmbeddingProvider {
100
100
  * Initialize the local embedding pipeline
101
101
  */
102
102
  async initLocalPipeline() {
103
- const { module: transformers } = await resolveLocalTransformersModule();
104
- const { pipeline } = transformers;
103
+ const { module } = await resolveLocalTransformersModule();
104
+ const { pipeline } = module;
105
105
  const model = this.config.localModel || "Xenova/bge-base-en-v1.5";
106
106
  const pipe = await pipeline("feature-extraction", model);
107
107
  return pipe;
@@ -1 +1 @@
1
- {"version":3,"file":"provider.js","sources":["../../src/embeddings/provider.ts"],"sourcesContent":["/**\n * Embedding Provider\n *\n * Unified interface for generating embeddings using local models or AI APIs.\n * Supports transformers.js packages for local inference and @happyvertical/ai\n * for cloud embeddings.\n */\n\nimport type { EmbeddingProviderType, ProjectEmbeddingConfig } from './types';\n\n/**\n * Dynamically import an optional dependency.\n * Uses a variable to prevent TypeScript from statically analyzing the import.\n */\nasync function importOptional(moduleName: string): Promise<any> {\n // Using a variable prevents TypeScript from trying to resolve the module at compile time\n const name = moduleName;\n return import(/* @vite-ignore */ name);\n}\n\nexport type OptionalModuleImporter = (moduleName: string) => Promise<any>;\n\nexport const LOCAL_TRANSFORMERS_PACKAGES = [\n '@huggingface/transformers',\n '@xenova/transformers',\n] as const;\n\nexport type LocalTransformersPackage =\n (typeof LOCAL_TRANSFORMERS_PACKAGES)[number];\n\nexport interface TransformersModuleResolution {\n module: any;\n packageName: LocalTransformersPackage;\n}\n\nfunction isModuleNotFoundError(error: unknown, moduleName: string): boolean {\n return (\n error instanceof Error &&\n (error.message.includes(`Cannot find module '${moduleName}'`) ||\n error.message.includes(`Cannot find package '${moduleName}'`))\n );\n}\n\nfunction formatTransformersResolutionError(\n attemptedPackages: readonly string[],\n): Error {\n return new Error(\n `Local embeddings require one of: ${attemptedPackages.join(', ')}. ` +\n `Install one of them to use provider: \"local\", or switch to provider: \"ai\".`,\n );\n}\n\nexport async function resolveLocalTransformersModule(\n importModule: OptionalModuleImporter = importOptional,\n): Promise<TransformersModuleResolution> {\n for (const packageName of LOCAL_TRANSFORMERS_PACKAGES) {\n try {\n const module = await importModule(packageName);\n return { module, packageName };\n } catch (error) {\n if (!isModuleNotFoundError(error, packageName)) {\n throw error;\n }\n }\n }\n\n throw formatTransformersResolutionError(LOCAL_TRANSFORMERS_PACKAGES);\n}\n\n/**\n * Interface for AI client that can generate embeddings\n */\ninterface EmbeddingCapableAI {\n embed(\n text: string | string[],\n options?: { model?: string; dimensions?: number },\n ): Promise<{ embeddings: number[][] }>;\n}\n\n/**\n * Pipeline type for local transformers packages\n */\ntype FeatureExtractionPipeline = (\n texts: string[],\n options?: { pooling?: string; normalize?: boolean },\n) => Promise<{ tolist: () => number[][] }>;\n\n/**\n * Embedding provider that supports both local and AI-based embedding generation.\n *\n * The \"auto\" provider prefers an already-configured AI embedding client.\n * Local transformer models are still available via provider: \"local\", but should\n * be an explicit choice for server workloads because model initialization can be\n * CPU and memory intensive.\n */\nexport class EmbeddingProvider {\n private localPipeline: FeatureExtractionPipeline | null = null;\n private localPipelineLoading: Promise<FeatureExtractionPipeline> | null =\n null;\n private config: ProjectEmbeddingConfig;\n private ai: EmbeddingCapableAI | null;\n\n /**\n * Create an embedding provider\n *\n * @param config - Project embedding configuration\n * @param ai - Optional AI client for cloud embeddings (must have embed method)\n */\n constructor(config: ProjectEmbeddingConfig, ai?: unknown) {\n this.config = config;\n // Cast to EmbeddingCapableAI if it has an embed method\n if (ai && typeof (ai as any).embed === 'function') {\n this.ai = ai as EmbeddingCapableAI;\n } else {\n this.ai = null;\n }\n }\n\n /**\n * Generate embeddings for text(s)\n *\n * @param text - Single string or array of strings to embed\n * @param providerOverride - Override the configured provider\n * @returns Array of embedding vectors\n */\n async embed(\n text: string | string[],\n providerOverride?: EmbeddingProviderType,\n ): Promise<number[][]> {\n const provider = providerOverride || this.config.provider;\n const texts = Array.isArray(text) ? text : [text];\n\n if (provider === 'local') {\n return this.embedLocal(texts);\n }\n\n if (provider === 'ai') {\n return this.embedWithAI(texts);\n }\n\n // 'auto' - use the configured AI client when present. This avoids\n // unexpectedly loading a large local transformer model inside app workers.\n // Local embeddings remain the explicit no-AI fallback for callers that\n // invoke embedding generation without an AI client.\n if (this.ai) {\n return this.embedWithAI(texts);\n }\n\n return this.embedLocal(texts);\n }\n\n /**\n * Generate embeddings using a local transformers model\n */\n private async embedLocal(texts: string[]): Promise<number[][]> {\n const pipeline = await this.getLocalPipeline();\n const results = await pipeline(texts, { pooling: 'mean', normalize: true });\n return results.tolist();\n }\n\n /**\n * Get or initialize the local embedding pipeline\n */\n private async getLocalPipeline(): Promise<FeatureExtractionPipeline> {\n if (this.localPipeline) {\n return this.localPipeline;\n }\n\n // Prevent multiple concurrent initializations\n if (this.localPipelineLoading) {\n return this.localPipelineLoading;\n }\n\n this.localPipelineLoading = this.initLocalPipeline();\n\n try {\n this.localPipeline = await this.localPipelineLoading;\n return this.localPipeline;\n } finally {\n this.localPipelineLoading = null;\n }\n }\n\n /**\n * Initialize the local embedding pipeline\n */\n private async initLocalPipeline(): Promise<FeatureExtractionPipeline> {\n const { module: transformers } = await resolveLocalTransformersModule();\n const { pipeline } = transformers;\n\n const model = this.config.localModel || 'Xenova/bge-base-en-v1.5';\n\n // Initialize the feature extraction pipeline\n const pipe = await pipeline('feature-extraction', model);\n\n return pipe as unknown as FeatureExtractionPipeline;\n }\n\n /**\n * Generate embeddings using AI API\n */\n private async embedWithAI(texts: string[]): Promise<number[][]> {\n if (!this.ai) {\n throw new Error(\n 'AI client not available for embeddings. ' +\n 'Either configure an AI client or use provider: \"local\".',\n );\n }\n\n const model = this.config.aiModel || 'text-embedding-3-small';\n const response = await this.ai.embed(texts, {\n model,\n dimensions: this.config.dimensions,\n });\n\n return response.embeddings;\n }\n\n /**\n * Get the model name being used\n */\n getModelName(): string {\n if (\n this.config.provider === 'ai' ||\n (this.config.provider === 'auto' && this.ai)\n ) {\n return this.config.aiModel || 'text-embedding-3-small';\n }\n return this.config.localModel || 'Xenova/bge-base-en-v1.5';\n }\n\n /**\n * Get the configured dimensions\n */\n getDimensions(): number {\n return this.config.dimensions;\n }\n\n /**\n * Check if local embeddings are available\n */\n async isLocalAvailable(): Promise<boolean> {\n try {\n await resolveLocalTransformersModule();\n return true;\n } catch {\n return false;\n }\n }\n\n /**\n * Check if AI embeddings are available\n */\n isAIAvailable(): boolean {\n return this.ai !== null;\n }\n}\n\n/**\n * Default project embedding configuration\n */\nexport const DEFAULT_EMBEDDING_CONFIG: ProjectEmbeddingConfig = {\n dimensions: 768,\n provider: 'local',\n localModel: 'Xenova/bge-base-en-v1.5',\n aiModel: 'text-embedding-3-small',\n};\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"provider.js","sources":["../../src/embeddings/provider.ts"],"sourcesContent":["/**\n * Embedding Provider\n *\n * Unified interface for generating embeddings using local models or AI APIs.\n * Supports transformers.js packages for local inference and @happyvertical/ai\n * for cloud embeddings.\n */\n\nimport type { EmbeddingProviderType, ProjectEmbeddingConfig } from './types';\n\n/**\n * Dynamically import an optional dependency.\n * Uses a variable to prevent TypeScript from statically analyzing the import.\n *\n * The resolved value is the imported module namespace; callers narrow it to a\n * concrete shape (e.g. {@link TransformersModule}) at the point of use.\n */\nasync function importOptional(moduleName: string): Promise<unknown> {\n // Using a variable prevents TypeScript from trying to resolve the module at compile time\n const name = moduleName;\n return import(/* @vite-ignore */ name);\n}\n\nexport type OptionalModuleImporter = (moduleName: string) => Promise<unknown>;\n\nexport const LOCAL_TRANSFORMERS_PACKAGES = [\n '@huggingface/transformers',\n '@xenova/transformers',\n] as const;\n\nexport type LocalTransformersPackage =\n (typeof LOCAL_TRANSFORMERS_PACKAGES)[number];\n\n/**\n * Minimal surface of a transformers.js package used for local embeddings.\n * Only the `pipeline` factory is consumed; its result is narrowed to a\n * {@link FeatureExtractionPipeline} at the call site.\n */\nexport interface TransformersModule {\n pipeline: (task: string, model: string) => Promise<unknown>;\n}\n\nexport interface TransformersModuleResolution {\n /**\n * The imported module namespace. Typed as `unknown` because the importer may\n * resolve arbitrary modules; consumers cast to {@link TransformersModule}.\n */\n module: unknown;\n packageName: LocalTransformersPackage;\n}\n\nfunction isModuleNotFoundError(error: unknown, moduleName: string): boolean {\n return (\n error instanceof Error &&\n (error.message.includes(`Cannot find module '${moduleName}'`) ||\n error.message.includes(`Cannot find package '${moduleName}'`))\n );\n}\n\nfunction formatTransformersResolutionError(\n attemptedPackages: readonly string[],\n): Error {\n return new Error(\n `Local embeddings require one of: ${attemptedPackages.join(', ')}. ` +\n `Install one of them to use provider: \"local\", or switch to provider: \"ai\".`,\n );\n}\n\nexport async function resolveLocalTransformersModule(\n importModule: OptionalModuleImporter = importOptional,\n): Promise<TransformersModuleResolution> {\n for (const packageName of LOCAL_TRANSFORMERS_PACKAGES) {\n try {\n const module = await importModule(packageName);\n return { module, packageName };\n } catch (error) {\n if (!isModuleNotFoundError(error, packageName)) {\n throw error;\n }\n }\n }\n\n throw formatTransformersResolutionError(LOCAL_TRANSFORMERS_PACKAGES);\n}\n\n/**\n * Interface for AI client that can generate embeddings\n */\ninterface EmbeddingCapableAI {\n embed(\n text: string | string[],\n options?: { model?: string; dimensions?: number },\n ): Promise<{ embeddings: number[][] }>;\n}\n\n/**\n * Pipeline type for local transformers packages\n */\ntype FeatureExtractionPipeline = (\n texts: string[],\n options?: { pooling?: string; normalize?: boolean },\n) => Promise<{ tolist: () => number[][] }>;\n\n/**\n * Embedding provider that supports both local and AI-based embedding generation.\n *\n * The \"auto\" provider prefers an already-configured AI embedding client.\n * Local transformer models are still available via provider: \"local\", but should\n * be an explicit choice for server workloads because model initialization can be\n * CPU and memory intensive.\n */\nexport class EmbeddingProvider {\n private localPipeline: FeatureExtractionPipeline | null = null;\n private localPipelineLoading: Promise<FeatureExtractionPipeline> | null =\n null;\n private config: ProjectEmbeddingConfig;\n private ai: EmbeddingCapableAI | null;\n\n /**\n * Create an embedding provider\n *\n * @param config - Project embedding configuration\n * @param ai - Optional AI client for cloud embeddings (must have embed method)\n */\n constructor(config: ProjectEmbeddingConfig, ai?: unknown) {\n this.config = config;\n // Cast to EmbeddingCapableAI if it has an embed method\n if (\n typeof ai === 'object' &&\n ai !== null &&\n typeof (ai as { embed?: unknown }).embed === 'function'\n ) {\n this.ai = ai as EmbeddingCapableAI;\n } else {\n this.ai = null;\n }\n }\n\n /**\n * Generate embeddings for text(s)\n *\n * @param text - Single string or array of strings to embed\n * @param providerOverride - Override the configured provider\n * @returns Array of embedding vectors\n */\n async embed(\n text: string | string[],\n providerOverride?: EmbeddingProviderType,\n ): Promise<number[][]> {\n const provider = providerOverride || this.config.provider;\n const texts = Array.isArray(text) ? text : [text];\n\n if (provider === 'local') {\n return this.embedLocal(texts);\n }\n\n if (provider === 'ai') {\n return this.embedWithAI(texts);\n }\n\n // 'auto' - use the configured AI client when present. This avoids\n // unexpectedly loading a large local transformer model inside app workers.\n // Local embeddings remain the explicit no-AI fallback for callers that\n // invoke embedding generation without an AI client.\n if (this.ai) {\n return this.embedWithAI(texts);\n }\n\n return this.embedLocal(texts);\n }\n\n /**\n * Generate embeddings using a local transformers model\n */\n private async embedLocal(texts: string[]): Promise<number[][]> {\n const pipeline = await this.getLocalPipeline();\n const results = await pipeline(texts, { pooling: 'mean', normalize: true });\n return results.tolist();\n }\n\n /**\n * Get or initialize the local embedding pipeline\n */\n private async getLocalPipeline(): Promise<FeatureExtractionPipeline> {\n if (this.localPipeline) {\n return this.localPipeline;\n }\n\n // Prevent multiple concurrent initializations\n if (this.localPipelineLoading) {\n return this.localPipelineLoading;\n }\n\n this.localPipelineLoading = this.initLocalPipeline();\n\n try {\n this.localPipeline = await this.localPipelineLoading;\n return this.localPipeline;\n } finally {\n this.localPipelineLoading = null;\n }\n }\n\n /**\n * Initialize the local embedding pipeline\n */\n private async initLocalPipeline(): Promise<FeatureExtractionPipeline> {\n const { module } = await resolveLocalTransformersModule();\n // The resolved module is the transformers.js namespace; narrow to the\n // minimal surface we consume.\n const { pipeline } = module as TransformersModule;\n\n const model = this.config.localModel || 'Xenova/bge-base-en-v1.5';\n\n // Initialize the feature extraction pipeline\n const pipe = await pipeline('feature-extraction', model);\n\n return pipe as unknown as FeatureExtractionPipeline;\n }\n\n /**\n * Generate embeddings using AI API\n */\n private async embedWithAI(texts: string[]): Promise<number[][]> {\n if (!this.ai) {\n throw new Error(\n 'AI client not available for embeddings. ' +\n 'Either configure an AI client or use provider: \"local\".',\n );\n }\n\n const model = this.config.aiModel || 'text-embedding-3-small';\n const response = await this.ai.embed(texts, {\n model,\n dimensions: this.config.dimensions,\n });\n\n return response.embeddings;\n }\n\n /**\n * Get the model name being used\n */\n getModelName(): string {\n if (\n this.config.provider === 'ai' ||\n (this.config.provider === 'auto' && this.ai)\n ) {\n return this.config.aiModel || 'text-embedding-3-small';\n }\n return this.config.localModel || 'Xenova/bge-base-en-v1.5';\n }\n\n /**\n * Get the configured dimensions\n */\n getDimensions(): number {\n return this.config.dimensions;\n }\n\n /**\n * Check if local embeddings are available\n */\n async isLocalAvailable(): Promise<boolean> {\n try {\n await resolveLocalTransformersModule();\n return true;\n } catch {\n return false;\n }\n }\n\n /**\n * Check if AI embeddings are available\n */\n isAIAvailable(): boolean {\n return this.ai !== null;\n }\n}\n\n/**\n * Default project embedding configuration\n */\nexport const DEFAULT_EMBEDDING_CONFIG: ProjectEmbeddingConfig = {\n dimensions: 768,\n provider: 'local',\n localModel: 'Xenova/bge-base-en-v1.5',\n aiModel: 'text-embedding-3-small',\n};\n"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"storage.js","sources":["../../src/embeddings/storage.ts"],"sourcesContent":["/**\n * Embedding Storage Operations\n *\n * CRUD operations for the _smrt_embeddings system table.\n * Supports both JSON-based and native vector storage strategies.\n */\n\nimport { randomUUID } from 'node:crypto';\nimport { createLogger } from '@happyvertical/logger';\nimport type { DatabaseInterface, VectorCapabilities } from '@happyvertical/sql';\nimport { CosineSimilarity } from './similarity';\nimport type { StoredEmbedding } from './types';\n\nconst logger = createLogger({ level: 'info' });\n\n/** Column name for native vector storage */\nconst VECTOR_COLUMN = 'embedding_vector';\n\n/**\n * Storage operations for embeddings in _smrt_embeddings table\n */\nexport class EmbeddingStorage {\n /**\n * Insert or update an embedding\n *\n * @param db - Database interface\n * @param data - Embedding data to store\n * @param vector - Optional vector capabilities for native storage\n */\n static async upsert(\n db: DatabaseInterface,\n data: {\n objectClass: string;\n objectId: string;\n fieldName: string;\n contentHash: string;\n embedding: number[];\n model: string;\n dimensions: number;\n provider?: string;\n },\n vector?: VectorCapabilities,\n ): Promise<void> {\n const now = new Date().toISOString();\n const id = randomUUID();\n\n await db.upsert(\n '_smrt_embeddings',\n ['object_class', 'object_id', 'field_name', 'model'],\n {\n id,\n object_class: data.objectClass,\n object_id: data.objectId,\n field_name: data.fieldName,\n content_hash: data.contentHash,\n embedding: JSON.stringify(data.embedding),\n model: data.model,\n dimensions: data.dimensions,\n provider: data.provider || null,\n created_at: now,\n updated_at: now,\n },\n );\n\n // Also store native vector if capability is available\n if (vector) {\n try {\n await vector.upsertVector(\n '_smrt_embeddings',\n {\n object_class: data.objectClass,\n object_id: data.objectId,\n field_name: data.fieldName,\n model: data.model,\n },\n VECTOR_COLUMN,\n data.embedding,\n );\n } catch (error) {\n // Log but don't fail — JSON fallback is always available\n logger.warn(\n `[embeddings] Failed to store native vector: ${error instanceof Error ? error.message : String(error)}`,\n );\n }\n }\n }\n\n /**\n * Search for similar embeddings using the best available strategy.\n *\n * When vector capabilities are provided, delegates to database-level\n * vector search. Otherwise falls back to loading all embeddings and\n * computing cosine similarity in memory.\n *\n * @param db - Database interface\n * @param objectClass - Class name to search within\n * @param embedding - Query embedding vector\n * @param options - Search options\n * @param vector - Optional vector capabilities for native search\n * @returns Array of { objectId, similarity } ranked by similarity (highest first)\n */\n static async searchSimilar(\n db: DatabaseInterface,\n objectClass: string,\n embedding: number[],\n options: {\n field?: string;\n model?: string;\n limit?: number;\n minSimilarity?: number;\n } = {},\n vector?: VectorCapabilities,\n ): Promise<Array<{ objectId: string; similarity: number }>> {\n const { field, model, limit = 10, minSimilarity = 0 } = options;\n\n // Native vector search path\n if (vector) {\n try {\n // Build WHERE clause for class/field/model filtering.\n // Parameter numbering starts at $2 because vector.search() reserves\n // $1 for the query vector embedding in its internal SQL query.\n const conditions: string[] = ['object_class = $2'];\n const params: any[] = [objectClass];\n\n if (field) {\n conditions.push(`field_name = $${params.length + 2}`);\n params.push(field);\n }\n\n if (model) {\n conditions.push(`model = $${params.length + 2}`);\n params.push(model);\n }\n\n const results = await vector.search(\n '_smrt_embeddings',\n VECTOR_COLUMN,\n embedding,\n {\n limit,\n metric: 'cosine',\n where: conditions.join(' AND '),\n params,\n },\n );\n\n // Convert cosine distance (0=identical, 2=opposite) to similarity (1=identical, -1=opposite)\n return results\n .map((r) => ({\n objectId: r.object_id as string,\n similarity: 1 - r.distance,\n }))\n .filter((r) => r.similarity >= minSimilarity);\n } catch (error) {\n // Fall back to in-memory search on vector search failure\n logger.warn(\n `[embeddings] Native vector search failed, falling back to in-memory: ${error instanceof Error ? error.message : String(error)}`,\n );\n }\n }\n\n // In-memory fallback: load all embeddings and compute cosine similarity\n const storedEmbeddings = await EmbeddingStorage.listForClass(\n db,\n objectClass,\n field,\n model,\n );\n\n if (storedEmbeddings.length === 0) {\n return [];\n }\n\n return storedEmbeddings\n .map((stored) => ({\n objectId: stored.object_id,\n similarity: CosineSimilarity.calculate(embedding, stored.embedding),\n }))\n .filter((item) => item.similarity >= minSimilarity)\n .sort((a, b) => b.similarity - a.similarity)\n .slice(0, limit);\n }\n\n /**\n * Ensure the native vector column and index exist on _smrt_embeddings.\n * Called once during initialization when storage: 'native' is configured.\n *\n * @param db - Database interface\n * @param dimensions - Vector dimensions\n * @param vector - Vector capabilities\n */\n static async ensureVectorStorage(\n _db: DatabaseInterface,\n dimensions: number,\n vector: VectorCapabilities,\n ): Promise<void> {\n await vector.ensureColumn('_smrt_embeddings', VECTOR_COLUMN, dimensions);\n await vector.ensureIndex('_smrt_embeddings', VECTOR_COLUMN, {\n dimensions,\n metric: 'cosine',\n type: 'hnsw',\n });\n }\n\n /**\n * Get a specific embedding\n *\n * @param db - Database interface\n * @param objectClass - Class name\n * @param objectId - Object ID\n * @param fieldName - Field name\n * @param model - Model used\n * @returns Stored embedding or null\n */\n static async get(\n db: DatabaseInterface,\n objectClass: string,\n objectId: string,\n fieldName: string,\n model: string,\n ): Promise<StoredEmbedding | null> {\n const result = await db.single`\n SELECT * FROM _smrt_embeddings\n WHERE object_class = ${objectClass}\n AND object_id = ${objectId}\n AND field_name = ${fieldName}\n AND model = ${model}\n `;\n\n if (!result) return null;\n\n return EmbeddingStorage.parseRow(result);\n }\n\n /**\n * Get all embeddings for an object\n *\n * @param db - Database interface\n * @param objectClass - Class name\n * @param objectId - Object ID\n * @returns Array of stored embeddings\n */\n static async getForObject(\n db: DatabaseInterface,\n objectClass: string,\n objectId: string,\n ): Promise<StoredEmbedding[]> {\n const { rows } = await db.query(\n `SELECT * FROM _smrt_embeddings WHERE object_class = ? AND object_id = ?`,\n objectClass,\n objectId,\n );\n\n return rows.map((row: Record<string, unknown>) =>\n EmbeddingStorage.parseRow(row),\n );\n }\n\n /**\n * List embeddings for a class (optionally filtered by field and model)\n *\n * @param db - Database interface\n * @param objectClass - Class name\n * @param fieldName - Optional field filter\n * @param model - Optional model filter\n * @returns Array of stored embeddings\n */\n static async listForClass(\n db: DatabaseInterface,\n objectClass: string,\n fieldName?: string,\n model?: string,\n ): Promise<StoredEmbedding[]> {\n let sql = `SELECT * FROM _smrt_embeddings WHERE object_class = ?`;\n const params: unknown[] = [objectClass];\n\n if (fieldName) {\n sql += ` AND field_name = ?`;\n params.push(fieldName);\n }\n\n if (model) {\n sql += ` AND model = ?`;\n params.push(model);\n }\n\n const { rows } = await db.query(sql, ...params);\n\n return rows.map((row: Record<string, unknown>) =>\n EmbeddingStorage.parseRow(row),\n );\n }\n\n /**\n * Get object IDs that have embeddings for a specific field\n *\n * @param db - Database interface\n * @param objectClass - Class name\n * @param fieldName - Field name\n * @returns Array of object IDs\n */\n static async getObjectIdsWithEmbeddings(\n db: DatabaseInterface,\n objectClass: string,\n fieldName: string,\n ): Promise<string[]> {\n const { rows } = await db.query(\n `SELECT DISTINCT object_id FROM _smrt_embeddings\n WHERE object_class = ? AND field_name = ?`,\n objectClass,\n fieldName,\n );\n\n return rows.map((row: Record<string, unknown>) => row.object_id as string);\n }\n\n /**\n * Delete all embeddings for an object\n *\n * @param db - Database interface\n * @param objectClass - Class name\n * @param objectId - Object ID\n */\n static async deleteForObject(\n db: DatabaseInterface,\n objectClass: string,\n objectId: string,\n ): Promise<void> {\n await db.query(\n `DELETE FROM _smrt_embeddings WHERE object_class = ? AND object_id = ?`,\n objectClass,\n objectId,\n );\n }\n\n /**\n * Delete a specific embedding\n *\n * @param db - Database interface\n * @param objectClass - Class name\n * @param objectId - Object ID\n * @param fieldName - Field name\n * @param model - Model used\n */\n static async delete(\n db: DatabaseInterface,\n objectClass: string,\n objectId: string,\n fieldName: string,\n model: string,\n ): Promise<void> {\n await db.query(\n `DELETE FROM _smrt_embeddings\n WHERE object_class = ? AND object_id = ? AND field_name = ? AND model = ?`,\n objectClass,\n objectId,\n fieldName,\n model,\n );\n }\n\n /**\n * Check if embedding table exists\n *\n * @param db - Database interface\n * @returns True if table exists\n */\n static async tableExists(db: DatabaseInterface): Promise<boolean> {\n try {\n await db.query(`SELECT 1 FROM _smrt_embeddings LIMIT 1`);\n return true;\n } catch {\n return false;\n }\n }\n\n /**\n * Parse a database row into StoredEmbedding\n */\n private static parseRow(row: Record<string, unknown>): StoredEmbedding {\n return {\n id: row.id as string,\n object_class: row.object_class as string,\n object_id: row.object_id as string,\n field_name: row.field_name as string,\n content_hash: row.content_hash as string,\n embedding: JSON.parse(row.embedding as string) as number[],\n model: row.model as string,\n dimensions: row.dimensions as number,\n provider: row.provider as string | undefined,\n created_at: new Date(row.created_at as string),\n updated_at: new Date(row.updated_at as string),\n };\n }\n}\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"storage.js","sources":["../../src/embeddings/storage.ts"],"sourcesContent":["/**\n * Embedding Storage Operations\n *\n * CRUD operations for the _smrt_embeddings system table.\n * Supports both JSON-based and native vector storage strategies.\n */\n\nimport { randomUUID } from 'node:crypto';\nimport { createLogger } from '@happyvertical/logger';\nimport type { DatabaseInterface, VectorCapabilities } from '@happyvertical/sql';\nimport { CosineSimilarity } from './similarity';\nimport type { StoredEmbedding } from './types';\n\nconst logger = createLogger({ level: 'info' });\n\n/** Column name for native vector storage */\nconst VECTOR_COLUMN = 'embedding_vector';\n\n/**\n * Storage operations for embeddings in _smrt_embeddings table\n */\nexport class EmbeddingStorage {\n /**\n * Insert or update an embedding\n *\n * @param db - Database interface\n * @param data - Embedding data to store\n * @param vector - Optional vector capabilities for native storage\n */\n static async upsert(\n db: DatabaseInterface,\n data: {\n objectClass: string;\n objectId: string;\n fieldName: string;\n contentHash: string;\n embedding: number[];\n model: string;\n dimensions: number;\n provider?: string;\n },\n vector?: VectorCapabilities,\n ): Promise<void> {\n const now = new Date().toISOString();\n const id = randomUUID();\n\n await db.upsert(\n '_smrt_embeddings',\n ['object_class', 'object_id', 'field_name', 'model'],\n {\n id,\n object_class: data.objectClass,\n object_id: data.objectId,\n field_name: data.fieldName,\n content_hash: data.contentHash,\n embedding: JSON.stringify(data.embedding),\n model: data.model,\n dimensions: data.dimensions,\n provider: data.provider || null,\n created_at: now,\n updated_at: now,\n },\n );\n\n // Also store native vector if capability is available\n if (vector) {\n try {\n await vector.upsertVector(\n '_smrt_embeddings',\n {\n object_class: data.objectClass,\n object_id: data.objectId,\n field_name: data.fieldName,\n model: data.model,\n },\n VECTOR_COLUMN,\n data.embedding,\n );\n } catch (error) {\n // Log but don't fail — JSON fallback is always available\n logger.warn(\n `[embeddings] Failed to store native vector: ${error instanceof Error ? error.message : String(error)}`,\n );\n }\n }\n }\n\n /**\n * Search for similar embeddings using the best available strategy.\n *\n * When vector capabilities are provided, delegates to database-level\n * vector search. Otherwise falls back to loading all embeddings and\n * computing cosine similarity in memory.\n *\n * @param db - Database interface\n * @param objectClass - Class name to search within\n * @param embedding - Query embedding vector\n * @param options - Search options\n * @param vector - Optional vector capabilities for native search\n * @returns Array of { objectId, similarity } ranked by similarity (highest first)\n */\n static async searchSimilar(\n db: DatabaseInterface,\n objectClass: string,\n embedding: number[],\n options: {\n field?: string;\n model?: string;\n limit?: number;\n minSimilarity?: number;\n } = {},\n vector?: VectorCapabilities,\n ): Promise<Array<{ objectId: string; similarity: number }>> {\n const { field, model, limit = 10, minSimilarity = 0 } = options;\n\n // Native vector search path\n if (vector) {\n try {\n // Build WHERE clause for class/field/model filtering.\n // Parameter numbering starts at $2 because vector.search() reserves\n // $1 for the query vector embedding in its internal SQL query.\n const conditions: string[] = ['object_class = $2'];\n const params: unknown[] = [objectClass];\n\n if (field) {\n conditions.push(`field_name = $${params.length + 2}`);\n params.push(field);\n }\n\n if (model) {\n conditions.push(`model = $${params.length + 2}`);\n params.push(model);\n }\n\n const results = await vector.search(\n '_smrt_embeddings',\n VECTOR_COLUMN,\n embedding,\n {\n limit,\n metric: 'cosine',\n where: conditions.join(' AND '),\n params,\n },\n );\n\n // Convert cosine distance (0=identical, 2=opposite) to similarity (1=identical, -1=opposite)\n return results\n .map((r) => ({\n objectId: r.object_id as string,\n similarity: 1 - r.distance,\n }))\n .filter((r) => r.similarity >= minSimilarity);\n } catch (error) {\n // Fall back to in-memory search on vector search failure\n logger.warn(\n `[embeddings] Native vector search failed, falling back to in-memory: ${error instanceof Error ? error.message : String(error)}`,\n );\n }\n }\n\n // In-memory fallback: load all embeddings and compute cosine similarity\n const storedEmbeddings = await EmbeddingStorage.listForClass(\n db,\n objectClass,\n field,\n model,\n );\n\n if (storedEmbeddings.length === 0) {\n return [];\n }\n\n return storedEmbeddings\n .map((stored) => ({\n objectId: stored.object_id,\n similarity: CosineSimilarity.calculate(embedding, stored.embedding),\n }))\n .filter((item) => item.similarity >= minSimilarity)\n .sort((a, b) => b.similarity - a.similarity)\n .slice(0, limit);\n }\n\n /**\n * Ensure the native vector column and index exist on _smrt_embeddings.\n * Called once during initialization when storage: 'native' is configured.\n *\n * @param db - Database interface\n * @param dimensions - Vector dimensions\n * @param vector - Vector capabilities\n */\n static async ensureVectorStorage(\n _db: DatabaseInterface,\n dimensions: number,\n vector: VectorCapabilities,\n ): Promise<void> {\n await vector.ensureColumn('_smrt_embeddings', VECTOR_COLUMN, dimensions);\n await vector.ensureIndex('_smrt_embeddings', VECTOR_COLUMN, {\n dimensions,\n metric: 'cosine',\n type: 'hnsw',\n });\n }\n\n /**\n * Get a specific embedding\n *\n * @param db - Database interface\n * @param objectClass - Class name\n * @param objectId - Object ID\n * @param fieldName - Field name\n * @param model - Model used\n * @returns Stored embedding or null\n */\n static async get(\n db: DatabaseInterface,\n objectClass: string,\n objectId: string,\n fieldName: string,\n model: string,\n ): Promise<StoredEmbedding | null> {\n const result = await db.single`\n SELECT * FROM _smrt_embeddings\n WHERE object_class = ${objectClass}\n AND object_id = ${objectId}\n AND field_name = ${fieldName}\n AND model = ${model}\n `;\n\n if (!result) return null;\n\n return EmbeddingStorage.parseRow(result);\n }\n\n /**\n * Get all embeddings for an object\n *\n * @param db - Database interface\n * @param objectClass - Class name\n * @param objectId - Object ID\n * @returns Array of stored embeddings\n */\n static async getForObject(\n db: DatabaseInterface,\n objectClass: string,\n objectId: string,\n ): Promise<StoredEmbedding[]> {\n const { rows } = await db.query(\n `SELECT * FROM _smrt_embeddings WHERE object_class = ? AND object_id = ?`,\n objectClass,\n objectId,\n );\n\n return rows.map((row: Record<string, unknown>) =>\n EmbeddingStorage.parseRow(row),\n );\n }\n\n /**\n * List embeddings for a class (optionally filtered by field and model)\n *\n * @param db - Database interface\n * @param objectClass - Class name\n * @param fieldName - Optional field filter\n * @param model - Optional model filter\n * @returns Array of stored embeddings\n */\n static async listForClass(\n db: DatabaseInterface,\n objectClass: string,\n fieldName?: string,\n model?: string,\n ): Promise<StoredEmbedding[]> {\n let sql = `SELECT * FROM _smrt_embeddings WHERE object_class = ?`;\n const params: unknown[] = [objectClass];\n\n if (fieldName) {\n sql += ` AND field_name = ?`;\n params.push(fieldName);\n }\n\n if (model) {\n sql += ` AND model = ?`;\n params.push(model);\n }\n\n const { rows } = await db.query(sql, ...params);\n\n return rows.map((row: Record<string, unknown>) =>\n EmbeddingStorage.parseRow(row),\n );\n }\n\n /**\n * Get object IDs that have embeddings for a specific field\n *\n * @param db - Database interface\n * @param objectClass - Class name\n * @param fieldName - Field name\n * @returns Array of object IDs\n */\n static async getObjectIdsWithEmbeddings(\n db: DatabaseInterface,\n objectClass: string,\n fieldName: string,\n ): Promise<string[]> {\n const { rows } = await db.query(\n `SELECT DISTINCT object_id FROM _smrt_embeddings\n WHERE object_class = ? AND field_name = ?`,\n objectClass,\n fieldName,\n );\n\n return rows.map((row: Record<string, unknown>) => row.object_id as string);\n }\n\n /**\n * Delete all embeddings for an object\n *\n * @param db - Database interface\n * @param objectClass - Class name\n * @param objectId - Object ID\n */\n static async deleteForObject(\n db: DatabaseInterface,\n objectClass: string,\n objectId: string,\n ): Promise<void> {\n await db.query(\n `DELETE FROM _smrt_embeddings WHERE object_class = ? AND object_id = ?`,\n objectClass,\n objectId,\n );\n }\n\n /**\n * Delete a specific embedding\n *\n * @param db - Database interface\n * @param objectClass - Class name\n * @param objectId - Object ID\n * @param fieldName - Field name\n * @param model - Model used\n */\n static async delete(\n db: DatabaseInterface,\n objectClass: string,\n objectId: string,\n fieldName: string,\n model: string,\n ): Promise<void> {\n await db.query(\n `DELETE FROM _smrt_embeddings\n WHERE object_class = ? AND object_id = ? AND field_name = ? AND model = ?`,\n objectClass,\n objectId,\n fieldName,\n model,\n );\n }\n\n /**\n * Check if embedding table exists\n *\n * @param db - Database interface\n * @returns True if table exists\n */\n static async tableExists(db: DatabaseInterface): Promise<boolean> {\n try {\n await db.query(`SELECT 1 FROM _smrt_embeddings LIMIT 1`);\n return true;\n } catch {\n return false;\n }\n }\n\n /**\n * Parse a database row into StoredEmbedding\n */\n private static parseRow(row: Record<string, unknown>): StoredEmbedding {\n return {\n id: row.id as string,\n object_class: row.object_class as string,\n object_id: row.object_id as string,\n field_name: row.field_name as string,\n content_hash: row.content_hash as string,\n embedding: JSON.parse(row.embedding as string) as number[],\n model: row.model as string,\n dimensions: row.dimensions as number,\n provider: row.provider as string | undefined,\n created_at: new Date(row.created_at as string),\n updated_at: new Date(row.updated_at as string),\n };\n }\n}\n"],"names":[],"mappings":"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"}