@happyvertical/smrt-core 0.40.70 → 0.42.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +3 -3
- package/agents/change-feed.md +1 -1
- package/agents/schema-paths.md +561 -32
- package/dist/browser.js +5 -4
- package/dist/cascade.d.ts +120 -0
- package/dist/cascade.d.ts.map +1 -0
- package/dist/cascade.js +430 -0
- package/dist/cascade.js.map +1 -0
- package/dist/change-feed.d.ts +34 -2
- package/dist/change-feed.d.ts.map +1 -1
- package/dist/change-feed.js +54 -13
- package/dist/change-feed.js.map +1 -1
- package/dist/change-signals.d.ts.map +1 -1
- package/dist/change-signals.js +8 -1
- package/dist/change-signals.js.map +1 -1
- package/dist/class.d.ts +36 -3
- package/dist/class.d.ts.map +1 -1
- package/dist/class.js +69 -14
- package/dist/class.js.map +1 -1
- package/dist/collection-cache.js +0 -0
- package/dist/collection-cache.js.map +1 -1
- package/dist/collection.d.ts +29 -0
- package/dist/collection.d.ts.map +1 -1
- package/dist/collection.js +68 -16
- package/dist/collection.js.map +1 -1
- package/dist/config.d.ts +10 -0
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js.map +1 -1
- package/dist/decorators/index.d.ts +63 -5
- package/dist/decorators/index.d.ts.map +1 -1
- package/dist/decorators/index.js +37 -5
- package/dist/decorators/index.js.map +1 -1
- package/dist/dispatch/collections/Dispatches.d.ts.map +1 -1
- package/dist/dispatch/collections/Dispatches.js +21 -6
- package/dist/dispatch/collections/Dispatches.js.map +1 -1
- package/dist/dispatch/models/Dispatch.d.ts +1 -1
- package/dist/dispatch/models/Dispatch.d.ts.map +1 -1
- package/dist/dispatch/models/Dispatch.js +3 -2
- package/dist/dispatch/models/Dispatch.js.map +1 -1
- package/dist/dispatch/models/DispatchSubscription.d.ts +1 -1
- package/dist/dispatch/models/DispatchSubscription.d.ts.map +1 -1
- package/dist/dispatch/models/DispatchSubscription.js +2 -1
- package/dist/dispatch/models/DispatchSubscription.js.map +1 -1
- package/dist/dispatch/types.d.ts +5 -0
- package/dist/dispatch/types.d.ts.map +1 -1
- package/dist/embedded-write-queue.d.ts +46 -0
- package/dist/embedded-write-queue.d.ts.map +1 -0
- package/dist/embedded-write-queue.js +66 -0
- package/dist/embedded-write-queue.js.map +1 -0
- package/dist/embeddings/storage.d.ts +7 -0
- package/dist/embeddings/storage.d.ts.map +1 -1
- package/dist/embeddings/storage.js +31 -13
- package/dist/embeddings/storage.js.map +1 -1
- package/dist/errors.d.ts +1 -1
- package/dist/hierarchical.js +1 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +8 -6
- package/dist/interceptors.d.ts +21 -0
- package/dist/interceptors.d.ts.map +1 -1
- package/dist/interceptors.js +27 -1
- package/dist/interceptors.js.map +1 -1
- package/dist/learning/memory.d.ts.map +1 -1
- package/dist/learning/memory.js +5 -4
- package/dist/learning/memory.js.map +1 -1
- package/dist/manifest/generator.d.ts.map +1 -1
- package/dist/manifest/generator.js +4 -7
- package/dist/manifest/generator.js.map +1 -1
- package/dist/manifest/static-manifest.js +10 -10
- package/dist/manifest/static-manifest.js.map +1 -1
- package/dist/manifest/store.js +1 -1
- package/dist/manifest/store.js.map +1 -1
- package/dist/manifest.json +19 -19
- package/dist/migrations/differ.d.ts +9 -1
- package/dist/migrations/differ.d.ts.map +1 -1
- package/dist/migrations/differ.js +12 -7
- package/dist/migrations/differ.js.map +1 -1
- package/dist/migrations/index.d.ts +2 -0
- package/dist/migrations/index.d.ts.map +1 -1
- package/dist/migrations/index.js +3 -1
- package/dist/migrations/integer-width.d.ts +99 -0
- package/dist/migrations/integer-width.d.ts.map +1 -0
- package/dist/migrations/integer-width.js +237 -0
- package/dist/migrations/integer-width.js.map +1 -0
- package/dist/migrations/minor-units.d.ts +162 -0
- package/dist/migrations/minor-units.d.ts.map +1 -0
- package/dist/migrations/minor-units.js +383 -0
- package/dist/migrations/minor-units.js.map +1 -0
- package/dist/migrations/tracker.d.ts.map +1 -1
- package/dist/migrations/tracker.js +28 -20
- package/dist/migrations/tracker.js.map +1 -1
- package/dist/migrations.js +3 -1
- package/dist/object.d.ts +98 -5
- package/dist/object.d.ts.map +1 -1
- package/dist/object.js +138 -30
- package/dist/object.js.map +1 -1
- package/dist/query-bounds.d.ts +5 -1
- package/dist/query-bounds.d.ts.map +1 -1
- package/dist/query-bounds.js +5 -1
- package/dist/query-bounds.js.map +1 -1
- package/dist/registry/class-registration.d.ts.map +1 -1
- package/dist/registry/class-registration.js +3 -1
- package/dist/registry/class-registration.js.map +1 -1
- package/dist/registry/manifest-field-merge.d.ts +12 -0
- package/dist/registry/manifest-field-merge.d.ts.map +1 -1
- package/dist/registry/manifest-field-merge.js +14 -2
- package/dist/registry/manifest-field-merge.js.map +1 -1
- package/dist/registry/schema-builder.d.ts +22 -1
- package/dist/registry/schema-builder.d.ts.map +1 -1
- package/dist/registry/schema-builder.js +205 -165
- package/dist/registry/schema-builder.js.map +1 -1
- package/dist/registry/types.d.ts +3 -2
- package/dist/registry/types.d.ts.map +1 -1
- package/dist/registry.d.ts +41 -46
- package/dist/registry.d.ts.map +1 -1
- package/dist/registry.js +61 -83
- package/dist/registry.js.map +1 -1
- package/dist/scanner/manifest-generator.d.ts +45 -0
- package/dist/scanner/manifest-generator.d.ts.map +1 -1
- package/dist/scanner/manifest-generator.js +92 -28
- package/dist/scanner/manifest-generator.js.map +1 -1
- package/dist/schema/conflict-target.d.ts +104 -0
- package/dist/schema/conflict-target.d.ts.map +1 -0
- package/dist/schema/conflict-target.js +129 -0
- package/dist/schema/conflict-target.js.map +1 -0
- package/dist/schema/ddl/duckdb-strategy.d.ts.map +1 -1
- package/dist/schema/ddl/duckdb-strategy.js +3 -1
- package/dist/schema/ddl/duckdb-strategy.js.map +1 -1
- package/dist/schema/ddl/postgres-strategy.d.ts.map +1 -1
- package/dist/schema/ddl/postgres-strategy.js +14 -1
- package/dist/schema/ddl/postgres-strategy.js.map +1 -1
- package/dist/schema/generator.d.ts +245 -41
- package/dist/schema/generator.d.ts.map +1 -1
- package/dist/schema/generator.js +397 -241
- package/dist/schema/generator.js.map +1 -1
- package/dist/schema/index-utils.d.ts +120 -0
- package/dist/schema/index-utils.d.ts.map +1 -1
- package/dist/schema/index-utils.js +242 -1
- package/dist/schema/index-utils.js.map +1 -1
- package/dist/schema/index.d.ts +2 -3
- package/dist/schema/index.d.ts.map +1 -1
- package/dist/schema/index.js +2 -3
- package/dist/schema/live-parity.d.ts +3 -1
- package/dist/schema/live-parity.d.ts.map +1 -1
- package/dist/schema/live-parity.js +23 -2
- package/dist/schema/live-parity.js.map +1 -1
- package/dist/schema/system-table-shapes.d.ts +13 -0
- package/dist/schema/system-table-shapes.d.ts.map +1 -1
- package/dist/schema/system-table-shapes.js +14 -1
- package/dist/schema/system-table-shapes.js.map +1 -1
- package/dist/schema/types.d.ts +17 -10
- package/dist/schema/types.d.ts.map +1 -1
- package/dist/schema/utils.d.ts +1 -1
- package/dist/schema/utils.d.ts.map +1 -1
- package/dist/schema/utils.js +3 -3
- package/dist/schema/utils.js.map +1 -1
- package/dist/schema.js +2 -3
- package/dist/smrt-knowledge.json +9 -9
- package/dist/system/compatibility.d.ts +42 -0
- package/dist/system/compatibility.d.ts.map +1 -1
- package/dist/system/compatibility.js +182 -9
- package/dist/system/compatibility.js.map +1 -1
- package/dist/system/index.d.ts +1 -0
- package/dist/system/index.d.ts.map +1 -1
- package/dist/system/index.js +3 -2
- package/dist/system/retention.d.ts +237 -0
- package/dist/system/retention.d.ts.map +1 -0
- package/dist/system/retention.js +497 -0
- package/dist/system/retention.js.map +1 -0
- package/dist/system/schema.d.ts +102 -16
- package/dist/system/schema.d.ts.map +1 -1
- package/dist/system/schema.js +85 -47
- package/dist/system/schema.js.map +1 -1
- package/dist/system/types.d.ts +0 -2
- package/dist/system/types.d.ts.map +1 -1
- package/dist/testing/database.d.ts.map +1 -1
- package/dist/testing/database.js.map +1 -1
- package/dist/utils/safe-integer.d.ts +19 -0
- package/dist/utils/safe-integer.d.ts.map +1 -0
- package/dist/utils/safe-integer.js +31 -0
- package/dist/utils/safe-integer.js.map +1 -0
- package/dist/utils.d.ts +2 -1
- package/dist/utils.d.ts.map +1 -1
- package/dist/utils.js +6 -3
- package/dist/utils.js.map +1 -1
- package/dist/vite-plugin/index.d.ts.map +1 -1
- package/dist/vite-plugin/index.js +4 -62
- package/dist/vite-plugin/index.js.map +1 -1
- package/package.json +4 -4
- package/dist/schema/override-system.d.ts +0 -43
- package/dist/schema/override-system.d.ts.map +0 -1
- package/dist/schema/override-system.js +0 -205
- package/dist/schema/override-system.js.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Dispatch.d.ts","sourceRoot":"","sources":["../../../src/dispatch/models/Dispatch.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;
|
|
1
|
+
{"version":3,"file":"Dispatch.d.ts","sourceRoot":"","sources":["../../../src/dispatch/models/Dispatch.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAKH,OAAO,KAAK,EAAE,gBAAgB,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAgCpE;;GAEG;AACH,MAAM,WAAW,YAAY;IAC3B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,MAAM,EAAE,cAAc,CAAC;IACvB,QAAQ,EAAE,MAAM,GAAG,MAAM,GAAG,MAAM,CAAC;IACnC,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,iBAAiB,EAAE,MAAM,GAAG,IAAI,CAAC;IACjC,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED;;GAEG;AACH,qBAAa,QAAQ;IACnB,gCAAgC;IAChC,MAAM,CAAC,QAAQ,CAAC,SAAS,oBAAoB;IAE7C,wBAAwB;IACxB,EAAE,EAAE,MAAM,CAAC;IAEX,+CAA+C;IAC/C,IAAI,EAAE,MAAM,CAAC;IAEb,0BAA0B;IAC1B,MAAM,EAAE,MAAM,CAAC;IAEf,iCAAiC;IACjC,QAAQ,EAAE,MAAM,CAAC;IAEjB,uBAAuB;IACvB,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAEjC,qBAAqB;IACrB,MAAM,EAAE,cAAc,CAAC;IAEvB,oCAAoC;IACpC,QAAQ,EAAE,MAAM,CAAC;IAEjB,mCAAmC;IACnC,SAAS,EAAE,MAAM,CAAC;IAElB,sCAAsC;IACtC,WAAW,EAAE,IAAI,GAAG,IAAI,CAAC;IAEzB,oCAAoC;IACpC,WAAW,EAAE,MAAM,CAAC;IAEpB,qEAAqE;IACrE,gBAAgB,EAAE,MAAM,GAAG,IAAI,CAAC;IAEhC,iEAAiE;IACjE,aAAa,EAAE,MAAM,CAAC;IAEtB;;;;;;OAMG;IACH,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IAExB,0BAA0B;IAC1B,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAElC,yBAAyB;IACzB,SAAS,EAAE,IAAI,CAAC;IAEhB,4BAA4B;IAC5B,SAAS,EAAE,IAAI,CAAC;gBAEJ,IAAI,GAAE,OAAO,CAAC,YAAY,CAAM;IA0B5C;;OAEG;IACH,MAAM,CAAC,OAAO,CAAC,GAAG,EAAE,YAAY,GAAG,QAAQ;IAI3C;;OAEG;IACH,KAAK,IAAI,YAAY;IAqBrB;;OAEG;IACH,WAAW,IAAI,gBAAgB;IAa/B;;OAEG;IACH,cAAc,IAAI,IAAI;IAMtB;;OAEG;IACH,aAAa,CAAC,WAAW,EAAE,MAAM,GAAG,IAAI;IAQxC;;OAEG;IACH,UAAU,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI;IAM/B;;OAEG;IACH,aAAa,IAAI,IAAI;IAKrB;;OAEG;IACH,QAAQ,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO;CAGvC"}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { toSafeInteger } from "../../utils/safe-integer.js";
|
|
1
2
|
import { createLogger } from "@happyvertical/logger";
|
|
2
3
|
import { makeId } from "@happyvertical/utils";
|
|
3
4
|
//#region src/dispatch/models/Dispatch.ts
|
|
@@ -79,7 +80,7 @@ var Dispatch = class Dispatch {
|
|
|
79
80
|
this.source = data.source || "";
|
|
80
81
|
this.sourceId = data.source_id || "";
|
|
81
82
|
this.status = data.status || "pending";
|
|
82
|
-
this.attempts = data.attempts
|
|
83
|
+
this.attempts = toSafeInteger(data.attempts ?? 0, "Dispatch attempts");
|
|
83
84
|
this.lastError = data.last_error || "";
|
|
84
85
|
this.processedBy = data.processed_by || "";
|
|
85
86
|
this.targetSubscriber = data.target_subscriber || null;
|
|
@@ -140,7 +141,7 @@ var Dispatch = class Dispatch {
|
|
|
140
141
|
*/
|
|
141
142
|
markProcessing() {
|
|
142
143
|
this.status = "processing";
|
|
143
|
-
this.attempts
|
|
144
|
+
this.attempts = toSafeInteger(this.attempts + 1, "Dispatch attempts");
|
|
144
145
|
this.updatedAt = /* @__PURE__ */ new Date();
|
|
145
146
|
}
|
|
146
147
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Dispatch.js","names":[],"sources":["../../../src/dispatch/models/Dispatch.ts"],"sourcesContent":["/**\n * Dispatch Model - Persistent dispatch message for inter-agent communication\n *\n * Dispatches are stored in the _smrt_dispatch system table and represent\n * messages sent between agents. They support async processing with retry logic.\n */\n\nimport { createLogger } from '@happyvertical/logger';\nimport { makeId } from '@happyvertical/utils';\nimport type { DispatchMetadata, DispatchStatus } from '../types.js';\n\nconst logger = createLogger({ level: 'info' });\n\n/**\n * Safely parses a JSON column from a `_smrt_dispatch` row.\n *\n * A single corrupted `payload`/`metadata` value must not throw out of the\n * `Dispatch` constructor, since `process()`/`list()` map `fromRow` over a whole\n * batch — one poison row would otherwise stall every dispatch in the batch\n * (#1378). On a parse failure, logs the offending row id + field and falls back\n * to an empty object so the rest of the batch keeps flowing.\n */\nfunction parseJsonField(\n raw: string,\n field: 'payload' | 'metadata',\n rowId: string,\n): Record<string, unknown> {\n try {\n // Only malformed JSON is treated as a poison value; valid JSON parses as\n // before (preserving prior behavior for the well-formed path).\n return JSON.parse(raw) as Record<string, unknown>;\n } catch (error) {\n logger.warn('Skipping corrupted _smrt_dispatch JSON field', {\n dispatchId: rowId,\n field,\n error: error instanceof Error ? error.message : String(error),\n });\n return {};\n }\n}\n\n/**\n * Raw dispatch data as stored in the database\n */\nexport interface DispatchData {\n id: string;\n type: string;\n source: string;\n source_id: string | null;\n payload: string | null;\n status: DispatchStatus;\n attempts: number;\n last_error: string | null;\n processed_at: string | null;\n processed_by: string | null;\n target_subscriber: string | null;\n correlation_id: string | null;\n tenant_id: string | null;\n metadata: string | null;\n created_at: string;\n updated_at: string;\n}\n\n/**\n * Dispatch model for inter-agent communication\n */\nexport class Dispatch {\n /** Table name for this model */\n static readonly tableName = '_smrt_dispatch';\n\n /** Unique identifier */\n id: string;\n\n /** Signal type (e.g., 'campaign.completed') */\n type: string;\n\n /** Emitting agent name */\n source: string;\n\n /** Emitting agent instance ID */\n sourceId: string;\n\n /** Dispatch payload */\n payload: Record<string, unknown>;\n\n /** Current status */\n status: DispatchStatus;\n\n /** Number of processing attempts */\n attempts: number;\n\n /** Last error message if failed */\n lastError: string;\n\n /** When the dispatch was processed */\n processedAt: Date | null;\n\n /** Which subscriber processed it */\n processedBy: string;\n\n /** Target subscriber for fan-out delivery (null for compete mode) */\n targetSubscriber: string | null;\n\n /** Correlation ID for linking request/response dispatch pairs */\n correlationId: string;\n\n /**\n * Tenant the dispatch was emitted in (server-derived, untrusted-input-proof).\n *\n * Stamped from the active tenant context at emit time — never from caller\n * options — so it cannot be spoofed. `null` for global / non-tenant\n * dispatches. Used to isolate reads/claims across tenants (S5 #1398).\n */\n tenantId: string | null;\n\n /** Additional metadata */\n metadata: Record<string, unknown>;\n\n /** Creation timestamp */\n createdAt: Date;\n\n /** Last update timestamp */\n updatedAt: Date;\n\n constructor(data: Partial<DispatchData> = {}) {\n this.id = data.id || makeId();\n this.type = data.type || '';\n this.source = data.source || '';\n this.sourceId = data.source_id || '';\n this.status = (data.status as DispatchStatus) || 'pending';\n this.attempts = data.attempts
|
|
1
|
+
{"version":3,"file":"Dispatch.js","names":[],"sources":["../../../src/dispatch/models/Dispatch.ts"],"sourcesContent":["/**\n * Dispatch Model - Persistent dispatch message for inter-agent communication\n *\n * Dispatches are stored in the _smrt_dispatch system table and represent\n * messages sent between agents. They support async processing with retry logic.\n */\n\nimport { createLogger } from '@happyvertical/logger';\nimport { makeId } from '@happyvertical/utils';\nimport { toSafeInteger } from '../../utils/safe-integer.js';\nimport type { DispatchMetadata, DispatchStatus } from '../types.js';\n\nconst logger = createLogger({ level: 'info' });\n\n/**\n * Safely parses a JSON column from a `_smrt_dispatch` row.\n *\n * A single corrupted `payload`/`metadata` value must not throw out of the\n * `Dispatch` constructor, since `process()`/`list()` map `fromRow` over a whole\n * batch — one poison row would otherwise stall every dispatch in the batch\n * (#1378). On a parse failure, logs the offending row id + field and falls back\n * to an empty object so the rest of the batch keeps flowing.\n */\nfunction parseJsonField(\n raw: string,\n field: 'payload' | 'metadata',\n rowId: string,\n): Record<string, unknown> {\n try {\n // Only malformed JSON is treated as a poison value; valid JSON parses as\n // before (preserving prior behavior for the well-formed path).\n return JSON.parse(raw) as Record<string, unknown>;\n } catch (error) {\n logger.warn('Skipping corrupted _smrt_dispatch JSON field', {\n dispatchId: rowId,\n field,\n error: error instanceof Error ? error.message : String(error),\n });\n return {};\n }\n}\n\n/**\n * Raw dispatch data as stored in the database\n */\nexport interface DispatchData {\n id: string;\n type: string;\n source: string;\n source_id: string | null;\n payload: string | null;\n status: DispatchStatus;\n attempts: number | string | bigint;\n last_error: string | null;\n processed_at: string | null;\n processed_by: string | null;\n target_subscriber: string | null;\n correlation_id: string | null;\n tenant_id: string | null;\n metadata: string | null;\n created_at: string;\n updated_at: string;\n}\n\n/**\n * Dispatch model for inter-agent communication\n */\nexport class Dispatch {\n /** Table name for this model */\n static readonly tableName = '_smrt_dispatch';\n\n /** Unique identifier */\n id: string;\n\n /** Signal type (e.g., 'campaign.completed') */\n type: string;\n\n /** Emitting agent name */\n source: string;\n\n /** Emitting agent instance ID */\n sourceId: string;\n\n /** Dispatch payload */\n payload: Record<string, unknown>;\n\n /** Current status */\n status: DispatchStatus;\n\n /** Number of processing attempts */\n attempts: number;\n\n /** Last error message if failed */\n lastError: string;\n\n /** When the dispatch was processed */\n processedAt: Date | null;\n\n /** Which subscriber processed it */\n processedBy: string;\n\n /** Target subscriber for fan-out delivery (null for compete mode) */\n targetSubscriber: string | null;\n\n /** Correlation ID for linking request/response dispatch pairs */\n correlationId: string;\n\n /**\n * Tenant the dispatch was emitted in (server-derived, untrusted-input-proof).\n *\n * Stamped from the active tenant context at emit time — never from caller\n * options — so it cannot be spoofed. `null` for global / non-tenant\n * dispatches. Used to isolate reads/claims across tenants (S5 #1398).\n */\n tenantId: string | null;\n\n /** Additional metadata */\n metadata: Record<string, unknown>;\n\n /** Creation timestamp */\n createdAt: Date;\n\n /** Last update timestamp */\n updatedAt: Date;\n\n constructor(data: Partial<DispatchData> = {}) {\n this.id = data.id || makeId();\n this.type = data.type || '';\n this.source = data.source || '';\n this.sourceId = data.source_id || '';\n this.status = (data.status as DispatchStatus) || 'pending';\n this.attempts = toSafeInteger(data.attempts ?? 0, 'Dispatch attempts');\n this.lastError = data.last_error || '';\n this.processedBy = data.processed_by || '';\n this.targetSubscriber = data.target_subscriber || null;\n this.correlationId = data.correlation_id || '';\n this.tenantId = data.tenant_id ?? null;\n this.createdAt = data.created_at ? new Date(data.created_at) : new Date();\n this.updatedAt = data.updated_at ? new Date(data.updated_at) : new Date();\n this.processedAt = data.processed_at ? new Date(data.processed_at) : null;\n\n // Parse JSON fields. Guarded so a single corrupted row cannot stall an\n // entire process()/list() batch (#1378).\n this.payload = data.payload\n ? parseJsonField(data.payload, 'payload', this.id)\n : {};\n this.metadata = data.metadata\n ? parseJsonField(data.metadata, 'metadata', this.id)\n : {};\n }\n\n /**\n * Create a Dispatch from a database row\n */\n static fromRow(row: DispatchData): Dispatch {\n return new Dispatch(row);\n }\n\n /**\n * Convert to database row format\n */\n toRow(): DispatchData {\n return {\n id: this.id,\n type: this.type,\n source: this.source,\n source_id: this.sourceId || null,\n payload: JSON.stringify(this.payload),\n status: this.status,\n attempts: this.attempts,\n last_error: this.lastError || null,\n processed_at: this.processedAt?.toISOString() || null,\n processed_by: this.processedBy || null,\n target_subscriber: this.targetSubscriber || null,\n correlation_id: this.correlationId || null,\n tenant_id: this.tenantId ?? null,\n metadata: JSON.stringify(this.metadata),\n created_at: this.createdAt.toISOString(),\n updated_at: new Date().toISOString(),\n };\n }\n\n /**\n * Get dispatch metadata for handlers\n */\n getMetadata(): DispatchMetadata {\n return {\n id: this.id,\n type: this.type,\n source: this.source,\n sourceId: this.sourceId,\n correlationId: this.correlationId,\n createdAt: this.createdAt,\n attempts: this.attempts,\n metadata: this.metadata,\n };\n }\n\n /**\n * Mark as processing\n */\n markProcessing(): void {\n this.status = 'processing';\n this.attempts = toSafeInteger(this.attempts + 1, 'Dispatch attempts');\n this.updatedAt = new Date();\n }\n\n /**\n * Mark as completed\n */\n markCompleted(processedBy: string): void {\n this.status = 'completed';\n this.processedAt = new Date();\n this.processedBy = processedBy;\n this.lastError = '';\n this.updatedAt = new Date();\n }\n\n /**\n * Mark as failed\n */\n markFailed(error: string): void {\n this.status = 'failed';\n this.lastError = error;\n this.updatedAt = new Date();\n }\n\n /**\n * Reset to pending for retry\n */\n resetForRetry(): void {\n this.status = 'pending';\n this.updatedAt = new Date();\n }\n\n /**\n * Check if this dispatch can be retried\n */\n canRetry(maxAttempts: number): boolean {\n return this.status === 'failed' && this.attempts < maxAttempts;\n }\n}\n"],"mappings":";;;;;;;;;;AAYA,IAAM,SAAS,aAAa,EAAE,OAAO,OAAO,CAAC;;;;;;;;;;AAW7C,SAAS,eACP,KACA,OACA,OACyB;CACzB,IAAI;EAGF,OAAO,KAAK,MAAM,GAAG;CACvB,SAAS,OAAO;EACd,OAAO,KAAK,gDAAgD;GAC1D,YAAY;GACZ;GACA,OAAO,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;EAC9D,CAAC;EACD,OAAO,CAAC;CACV;AACF;;;;AA2BA,IAAa,WAAb,MAAa,SAAS;;CAEpB,OAAgB,YAAY;;CAG5B;;CAGA;;CAGA;;CAGA;;CAGA;;CAGA;;CAGA;;CAGA;;CAGA;;CAGA;;CAGA;;CAGA;;;;;;;;CASA;;CAGA;;CAGA;;CAGA;CAEA,YAAY,OAA8B,CAAC,GAAG;EAC5C,KAAK,KAAK,KAAK,MAAM,OAAO;EAC5B,KAAK,OAAO,KAAK,QAAQ;EACzB,KAAK,SAAS,KAAK,UAAU;EAC7B,KAAK,WAAW,KAAK,aAAa;EAClC,KAAK,SAAU,KAAK,UAA6B;EACjD,KAAK,WAAW,cAAc,KAAK,YAAY,GAAG,mBAAmB;EACrE,KAAK,YAAY,KAAK,cAAc;EACpC,KAAK,cAAc,KAAK,gBAAgB;EACxC,KAAK,mBAAmB,KAAK,qBAAqB;EAClD,KAAK,gBAAgB,KAAK,kBAAkB;EAC5C,KAAK,WAAW,KAAK,aAAa;EAClC,KAAK,YAAY,KAAK,aAAa,IAAI,KAAK,KAAK,UAAU,oBAAI,IAAI,KAAK;EACxE,KAAK,YAAY,KAAK,aAAa,IAAI,KAAK,KAAK,UAAU,oBAAI,IAAI,KAAK;EACxE,KAAK,cAAc,KAAK,eAAe,IAAI,KAAK,KAAK,YAAY,IAAI;EAIrE,KAAK,UAAU,KAAK,UAChB,eAAe,KAAK,SAAS,WAAW,KAAK,EAAE,IAC/C,CAAC;EACL,KAAK,WAAW,KAAK,WACjB,eAAe,KAAK,UAAU,YAAY,KAAK,EAAE,IACjD,CAAC;CACP;;;;CAKA,OAAO,QAAQ,KAA6B;EAC1C,OAAO,IAAI,SAAS,GAAG;CACzB;;;;CAKA,QAAsB;EACpB,OAAO;GACL,IAAI,KAAK;GACT,MAAM,KAAK;GACX,QAAQ,KAAK;GACb,WAAW,KAAK,YAAY;GAC5B,SAAS,KAAK,UAAU,KAAK,OAAO;GACpC,QAAQ,KAAK;GACb,UAAU,KAAK;GACf,YAAY,KAAK,aAAa;GAC9B,cAAc,KAAK,aAAa,YAAY,KAAK;GACjD,cAAc,KAAK,eAAe;GAClC,mBAAmB,KAAK,oBAAoB;GAC5C,gBAAgB,KAAK,iBAAiB;GACtC,WAAW,KAAK,YAAY;GAC5B,UAAU,KAAK,UAAU,KAAK,QAAQ;GACtC,YAAY,KAAK,UAAU,YAAY;GACvC,6BAAY,IAAI,KAAK,EAAA,CAAE,YAAY;EACrC;CACF;;;;CAKA,cAAgC;EAC9B,OAAO;GACL,IAAI,KAAK;GACT,MAAM,KAAK;GACX,QAAQ,KAAK;GACb,UAAU,KAAK;GACf,eAAe,KAAK;GACpB,WAAW,KAAK;GAChB,UAAU,KAAK;GACf,UAAU,KAAK;EACjB;CACF;;;;CAKA,iBAAuB;EACrB,KAAK,SAAS;EACd,KAAK,WAAW,cAAc,KAAK,WAAW,GAAG,mBAAmB;EACpE,KAAK,4BAAY,IAAI,KAAK;CAC5B;;;;CAKA,cAAc,aAA2B;EACvC,KAAK,SAAS;EACd,KAAK,8BAAc,IAAI,KAAK;EAC5B,KAAK,cAAc;EACnB,KAAK,YAAY;EACjB,KAAK,4BAAY,IAAI,KAAK;CAC5B;;;;CAKA,WAAW,OAAqB;EAC9B,KAAK,SAAS;EACd,KAAK,YAAY;EACjB,KAAK,4BAAY,IAAI,KAAK;CAC5B;;;;CAKA,gBAAsB;EACpB,KAAK,SAAS;EACd,KAAK,4BAAY,IAAI,KAAK;CAC5B;;;;CAKA,SAAS,aAA8B;EACrC,OAAO,KAAK,WAAW,YAAY,KAAK,WAAW;CACrD;AACF"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"DispatchSubscription.d.ts","sourceRoot":"","sources":["../../../src/dispatch/models/DispatchSubscription.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;
|
|
1
|
+
{"version":3,"file":"DispatchSubscription.d.ts","sourceRoot":"","sources":["../../../src/dispatch/models/DispatchSubscription.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAKH;;GAEG;AACH,MAAM,WAAW,wBAAwB;IACvC,EAAE,EAAE,MAAM,CAAC;IACX,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,GAAG,MAAM,GAAG,MAAM,GAAG,IAAI,CAAC;IACzC,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED;;GAEG;AACH,qBAAa,oBAAoB;IAC/B,gCAAgC;IAChC,MAAM,CAAC,QAAQ,CAAC,SAAS,kCAAkC;IAE3D,wBAAwB;IACxB,EAAE,EAAE,MAAM,CAAC;IAEX,iEAAiE;IACjE,UAAU,EAAE,MAAM,CAAC;IAEnB,2CAA2C;IAC3C,UAAU,EAAE,MAAM,CAAC;IAEnB,0BAA0B;IAC1B,OAAO,EAAE,MAAM,CAAC;IAEhB,kFAAkF;IAClF,QAAQ,EAAE,SAAS,GAAG,QAAQ,CAAC;IAE/B,qCAAqC;IACrC,OAAO,EAAE,OAAO,CAAC;IAEjB;;;;OAIG;IACH,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IAExB,yBAAyB;IACzB,SAAS,EAAE,IAAI,CAAC;IAEhB,4BAA4B;IAC5B,SAAS,EAAE,IAAI,CAAC;gBAEJ,IAAI,GAAE,OAAO,CAAC,wBAAwB,CAAM;IAkBxD;;OAEG;IACH,MAAM,CAAC,OAAO,CAAC,GAAG,EAAE,wBAAwB,GAAG,oBAAoB;IAInE;;OAEG;IACH,KAAK,IAAI,wBAAwB;IAcjC;;;;;;;;;;OAUG;IACH,OAAO,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO;IAmCpC;;OAEG;IACH,UAAU,IAAI,OAAO;IAIrB;;OAEG;IACH,MAAM,IAAI,IAAI;IAKd;;OAEG;IACH,OAAO,IAAI,IAAI;CAIhB"}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { toSafeBooleanInteger } from "../../utils/safe-integer.js";
|
|
1
2
|
import { makeId } from "@happyvertical/utils";
|
|
2
3
|
//#region src/dispatch/models/DispatchSubscription.ts
|
|
3
4
|
/**
|
|
@@ -40,7 +41,7 @@ var DispatchSubscription = class DispatchSubscription {
|
|
|
40
41
|
this.subscriber = data.subscriber || "";
|
|
41
42
|
this.handler = data.handler || "handleDispatch";
|
|
42
43
|
this.delivery = data.delivery || "compete";
|
|
43
|
-
this.enabled = data.enabled
|
|
44
|
+
this.enabled = data.enabled != null ? toSafeBooleanInteger(data.enabled, "Dispatch subscription enabled flag") : true;
|
|
44
45
|
this.tenantId = data.tenant_id ?? null;
|
|
45
46
|
this.createdAt = data.created_at ? new Date(data.created_at) : /* @__PURE__ */ new Date();
|
|
46
47
|
this.updatedAt = data.updated_at ? new Date(data.updated_at) : /* @__PURE__ */ new Date();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"DispatchSubscription.js","names":[],"sources":["../../../src/dispatch/models/DispatchSubscription.ts"],"sourcesContent":["/**\n * DispatchSubscription Model - Persistent subscription for dispatch processing\n *\n * Subscriptions are stored in _smrt_dispatch_subscriptions and define which\n * agents should receive which dispatch types. Supports wildcard patterns.\n */\n\nimport { makeId } from '@happyvertical/utils';\n\n/**\n * Raw subscription data as stored in the database\n */\nexport interface DispatchSubscriptionData {\n id: string;\n signal_type: string;\n subscriber: string;\n handler: string;\n delivery: string;\n enabled: number;\n tenant_id: string | null;\n created_at: string;\n updated_at: string;\n}\n\n/**\n * DispatchSubscription model for persistent dispatch routing\n */\nexport class DispatchSubscription {\n /** Table name for this model */\n static readonly tableName = '_smrt_dispatch_subscriptions';\n\n /** Unique identifier */\n id: string;\n\n /** Signal type pattern (supports wildcards like 'campaign.*') */\n signalType: string;\n\n /** Subscriber name (usually agent name) */\n subscriber: string;\n\n /** Handler method name */\n handler: string;\n\n /** Delivery mode: 'compete' (first-to-claim) or 'fanout' (per-subscriber copy) */\n delivery: 'compete' | 'fanout';\n\n /** Whether subscription is active */\n enabled: boolean;\n\n /**\n * Tenant the subscription was registered in (server-derived). `null` for\n * global / non-tenant subscriptions. Recorded for auditing and per-tenant\n * subscription separation (S5 #1398).\n */\n tenantId: string | null;\n\n /** Creation timestamp */\n createdAt: Date;\n\n /** Last update timestamp */\n updatedAt: Date;\n\n constructor(data: Partial<DispatchSubscriptionData> = {}) {\n this.id = data.id || makeId();\n this.signalType = data.signal_type || '';\n this.subscriber = data.subscriber || '';\n this.handler = data.handler || 'handleDispatch';\n this.delivery = (data.delivery as 'compete' | 'fanout') || 'compete';\n this.enabled
|
|
1
|
+
{"version":3,"file":"DispatchSubscription.js","names":[],"sources":["../../../src/dispatch/models/DispatchSubscription.ts"],"sourcesContent":["/**\n * DispatchSubscription Model - Persistent subscription for dispatch processing\n *\n * Subscriptions are stored in _smrt_dispatch_subscriptions and define which\n * agents should receive which dispatch types. Supports wildcard patterns.\n */\n\nimport { makeId } from '@happyvertical/utils';\nimport { toSafeBooleanInteger } from '../../utils/safe-integer.js';\n\n/**\n * Raw subscription data as stored in the database\n */\nexport interface DispatchSubscriptionData {\n id: string;\n signal_type: string;\n subscriber: string;\n handler: string;\n delivery: string;\n enabled: number | string | bigint | null;\n tenant_id: string | null;\n created_at: string;\n updated_at: string;\n}\n\n/**\n * DispatchSubscription model for persistent dispatch routing\n */\nexport class DispatchSubscription {\n /** Table name for this model */\n static readonly tableName = '_smrt_dispatch_subscriptions';\n\n /** Unique identifier */\n id: string;\n\n /** Signal type pattern (supports wildcards like 'campaign.*') */\n signalType: string;\n\n /** Subscriber name (usually agent name) */\n subscriber: string;\n\n /** Handler method name */\n handler: string;\n\n /** Delivery mode: 'compete' (first-to-claim) or 'fanout' (per-subscriber copy) */\n delivery: 'compete' | 'fanout';\n\n /** Whether subscription is active */\n enabled: boolean;\n\n /**\n * Tenant the subscription was registered in (server-derived). `null` for\n * global / non-tenant subscriptions. Recorded for auditing and per-tenant\n * subscription separation (S5 #1398).\n */\n tenantId: string | null;\n\n /** Creation timestamp */\n createdAt: Date;\n\n /** Last update timestamp */\n updatedAt: Date;\n\n constructor(data: Partial<DispatchSubscriptionData> = {}) {\n this.id = data.id || makeId();\n this.signalType = data.signal_type || '';\n this.subscriber = data.subscriber || '';\n this.handler = data.handler || 'handleDispatch';\n this.delivery = (data.delivery as 'compete' | 'fanout') || 'compete';\n this.enabled =\n data.enabled != null\n ? toSafeBooleanInteger(\n data.enabled,\n 'Dispatch subscription enabled flag',\n )\n : true;\n this.tenantId = data.tenant_id ?? null;\n this.createdAt = data.created_at ? new Date(data.created_at) : new Date();\n this.updatedAt = data.updated_at ? new Date(data.updated_at) : new Date();\n }\n\n /**\n * Create a DispatchSubscription from a database row\n */\n static fromRow(row: DispatchSubscriptionData): DispatchSubscription {\n return new DispatchSubscription(row);\n }\n\n /**\n * Convert to database row format\n */\n toRow(): DispatchSubscriptionData {\n return {\n id: this.id,\n signal_type: this.signalType,\n subscriber: this.subscriber,\n handler: this.handler,\n delivery: this.delivery,\n enabled: this.enabled ? 1 : 0,\n tenant_id: this.tenantId ?? null,\n created_at: this.createdAt.toISOString(),\n updated_at: new Date().toISOString(),\n };\n }\n\n /**\n * Check if this subscription matches a given signal type\n *\n * Supports wildcard patterns:\n * - 'campaign.*' matches 'campaign.started', 'campaign.completed'\n * - '*' matches everything\n * - 'campaign.*.completed' matches 'campaign.summer.completed'\n *\n * @param signalType - The signal type to match against\n * @returns True if this subscription matches the signal type\n */\n matches(signalType: string): boolean {\n if (!this.enabled) {\n return false;\n }\n\n // Exact match\n if (this.signalType === signalType) {\n return true;\n }\n\n // If no wildcards, no match\n if (!this.signalType.includes('*')) {\n return false;\n }\n\n // Convert wildcard pattern to regex\n // First escape special regex characters except * and .\n // Then convert . to \\. and * to [^.]+\n let pattern = this.signalType;\n\n // Escape regex special chars except * and .\n pattern = pattern.replace(/[+?^${}()|[\\]\\\\]/g, '\\\\$&');\n\n // Escape dots\n pattern = pattern.replace(/\\./g, '\\\\.');\n\n // Convert * to match one segment (anything except .)\n pattern = pattern.replace(/\\*/g, '[^.]+');\n\n // Create regex for full match\n const regex = new RegExp(`^${pattern}$`);\n\n return regex.test(signalType);\n }\n\n /**\n * Check if this is a wildcard subscription\n */\n isWildcard(): boolean {\n return this.signalType.includes('*');\n }\n\n /**\n * Enable this subscription\n */\n enable(): void {\n this.enabled = true;\n this.updatedAt = new Date();\n }\n\n /**\n * Disable this subscription\n */\n disable(): void {\n this.enabled = false;\n this.updatedAt = new Date();\n }\n}\n"],"mappings":";;;;;;;;;;;;AA4BA,IAAa,uBAAb,MAAa,qBAAqB;;CAEhC,OAAgB,YAAY;;CAG5B;;CAGA;;CAGA;;CAGA;;CAGA;;CAGA;;;;;;CAOA;;CAGA;;CAGA;CAEA,YAAY,OAA0C,CAAC,GAAG;EACxD,KAAK,KAAK,KAAK,MAAM,OAAO;EAC5B,KAAK,aAAa,KAAK,eAAe;EACtC,KAAK,aAAa,KAAK,cAAc;EACrC,KAAK,UAAU,KAAK,WAAW;EAC/B,KAAK,WAAY,KAAK,YAAqC;EAC3D,KAAK,UACH,KAAK,WAAW,OACZ,qBACE,KAAK,SACL,oCACF,IACA;EACN,KAAK,WAAW,KAAK,aAAa;EAClC,KAAK,YAAY,KAAK,aAAa,IAAI,KAAK,KAAK,UAAU,oBAAI,IAAI,KAAK;EACxE,KAAK,YAAY,KAAK,aAAa,IAAI,KAAK,KAAK,UAAU,oBAAI,IAAI,KAAK;CAC1E;;;;CAKA,OAAO,QAAQ,KAAqD;EAClE,OAAO,IAAI,qBAAqB,GAAG;CACrC;;;;CAKA,QAAkC;EAChC,OAAO;GACL,IAAI,KAAK;GACT,aAAa,KAAK;GAClB,YAAY,KAAK;GACjB,SAAS,KAAK;GACd,UAAU,KAAK;GACf,SAAS,KAAK,UAAU,IAAI;GAC5B,WAAW,KAAK,YAAY;GAC5B,YAAY,KAAK,UAAU,YAAY;GACvC,6BAAY,IAAI,KAAK,EAAA,CAAE,YAAY;EACrC;CACF;;;;;;;;;;;;CAaA,QAAQ,YAA6B;EACnC,IAAI,CAAC,KAAK,SACR,OAAO;EAIT,IAAI,KAAK,eAAe,YACtB,OAAO;EAIT,IAAI,CAAC,KAAK,WAAW,SAAS,GAAG,GAC/B,OAAO;EAMT,IAAI,UAAU,KAAK;EAGnB,UAAU,QAAQ,QAAQ,qBAAqB,MAAM;EAGrD,UAAU,QAAQ,QAAQ,OAAO,KAAK;EAGtC,UAAU,QAAQ,QAAQ,OAAO,OAAO;EAKxC,OAAO,IAFW,OAAO,IAAI,QAAQ,EAE9B,CAAA,CAAM,KAAK,UAAU;CAC9B;;;;CAKA,aAAsB;EACpB,OAAO,KAAK,WAAW,SAAS,GAAG;CACrC;;;;CAKA,SAAe;EACb,KAAK,UAAU;EACf,KAAK,4BAAY,IAAI,KAAK;CAC5B;;;;CAKA,UAAgB;EACd,KAAK,UAAU;EACf,KAAK,4BAAY,IAAI,KAAK;CAC5B;AACF"}
|
package/dist/dispatch/types.d.ts
CHANGED
|
@@ -121,6 +121,11 @@ export interface DispatchCleanupOptions {
|
|
|
121
121
|
completedOlderThanDays?: number;
|
|
122
122
|
/** Delete failed dispatches older than this many days */
|
|
123
123
|
failedOlderThanDays?: number;
|
|
124
|
+
/**
|
|
125
|
+
* Count the dispatches the cutoffs select without deleting them (#2375).
|
|
126
|
+
* The result reports what a real cleanup with the same options would remove.
|
|
127
|
+
*/
|
|
128
|
+
dryRun?: boolean;
|
|
124
129
|
}
|
|
125
130
|
/**
|
|
126
131
|
* Result of dispatch cleanup
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/dispatch/types.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AAC5D,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,sBAAsB,CAAC;AAEhE;;GAEG;AACH,MAAM,MAAM,cAAc,GAAG,SAAS,GAAG,YAAY,GAAG,WAAW,GAAG,QAAQ,CAAC;AAE/E;;GAEG;AACH,MAAM,WAAW,mBAAmB;IAClC,wBAAwB;IACxB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,+BAA+B;IAC/B,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,iEAAiE;IACjE,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,0BAA0B;IAC1B,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACpC;AAED;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC/B,kBAAkB;IAClB,EAAE,EAAE,MAAM,CAAC;IACX,+CAA+C;IAC/C,IAAI,EAAE,MAAM,CAAC;IACb,wBAAwB;IACxB,MAAM,EAAE,MAAM,CAAC;IACf,+BAA+B;IAC/B,QAAQ,EAAE,MAAM,CAAC;IACjB,iEAAiE;IACjE,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,kCAAkC;IAClC,SAAS,EAAE,IAAI,CAAC;IAChB,oCAAoC;IACpC,QAAQ,EAAE,MAAM,CAAC;IACjB,wCAAwC;IACxC,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACnC;AAED;;GAEG;AACH,MAAM,MAAM,eAAe,GAAG,CAC5B,OAAO,EAAE,OAAO,EAChB,QAAQ,EAAE,gBAAgB,KACvB,OAAO,CAAC,IAAI,CAAC,CAAC;AAEnB;;GAEG;AACH,MAAM,WAAW,wBAAwB;IACvC,iEAAiE;IACjE,UAAU,EAAE,MAAM,CAAC;IACnB,2CAA2C;IAC3C,UAAU,EAAE,MAAM,CAAC;IACnB,sDAAsD;IACtD,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,sCAAsC;IACtC,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,qGAAqG;IACrG,QAAQ,CAAC,EAAE,SAAS,GAAG,QAAQ,CAAC;CACjC;AAED;;GAEG;AACH,MAAM,WAAW,sBAAsB;IACrC,8CAA8C;IAC9C,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,wDAAwD;IACxD,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC;CACxB;AAED;;GAEG;AACH,MAAM,WAAW,mBAAmB;IAClC,uBAAuB;IACvB,MAAM,CAAC,EAAE,cAAc,CAAC;IACxB,6BAA6B;IAC7B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,4BAA4B;IAC5B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,kCAAkC;IAClC,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,+BAA+B;IAC/B,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB;;;;;;;;;;;;;OAaG;IACH,WAAW,CAAC,EAAE,mBAAmB,CAAC;IAClC,sBAAsB;IACtB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,4BAA4B;IAC5B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,qBAAqB;IACrB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED;;GAEG;AACH,MAAM,WAAW,oBAAoB;IACnC,8CAA8C;IAC9C,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,iDAAiD;IACjD,SAAS,CAAC,EAAE,IAAI,CAAC;IACjB,uCAAuC;IACvC,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC;CACxB;AAED;;GAEG;AACH,MAAM,WAAW,sBAAsB;IACrC,4DAA4D;IAC5D,sBAAsB,CAAC,EAAE,MAAM,CAAC;IAChC,yDAAyD;IACzD,mBAAmB,CAAC,EAAE,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/dispatch/types.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* In-process write serialization for embedded database engines (#2360).
|
|
3
|
+
*
|
|
4
|
+
* File-backed SQLite (libsql) allows one writer at a time and the SDK opens a
|
|
5
|
+
* NEW connection for every null-aware upsert attempt (`transaction("write")`),
|
|
6
|
+
* with no busy timeout on either connection. Any other write on the root
|
|
7
|
+
* connection while such a transaction is open — most commonly the change-feed
|
|
8
|
+
* append that follows every model save — collides as `SQLITE_BUSY`, and under
|
|
9
|
+
* sustained concurrency (a `Promise.all` of creates) the two sides livelock
|
|
10
|
+
* through every retry tier. Before the tenant-led conflict target (#2360) the
|
|
11
|
+
* null-aware path was rare (custom conflict keys with NULL values, #1246);
|
|
12
|
+
* with `tenant_id` leading every tenant-scoped default key, EVERY NULL-tenant
|
|
13
|
+
* (global) create takes it, so the collision became the steady state.
|
|
14
|
+
*
|
|
15
|
+
* The queue makes the process a single writer per database for exactly the
|
|
16
|
+
* two participants of that collision:
|
|
17
|
+
*
|
|
18
|
+
* - a `save()` whose upsert conflict values contain NULL (the only shape the
|
|
19
|
+
* SDK routes through a second-connection transaction), and
|
|
20
|
+
* - the change-feed append (a root-connection write that follows every save).
|
|
21
|
+
*
|
|
22
|
+
* Each hold is a LEAF database call — never an interceptor or hook — so the
|
|
23
|
+
* queue cannot deadlock on nested saves. PostgreSQL is never serialized here:
|
|
24
|
+
* its null-aware upsert already arbitrates through advisory locks
|
|
25
|
+
* server-side, and cross-process writers exist that an in-process queue could
|
|
26
|
+
* not order anyway (which is also why this queue is a mitigation for embedded
|
|
27
|
+
* engines' in-process writers, not a cross-process guarantee — embedded
|
|
28
|
+
* engines have no cross-process writers in supported deployments).
|
|
29
|
+
*/
|
|
30
|
+
interface QueueableDatabase {
|
|
31
|
+
url?: string;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Whether `db` is an embedded engine (SQLite/DuckDB/JSON — anything that is
|
|
35
|
+
* not PostgreSQL). Handles without a URL are treated as embedded: serializing
|
|
36
|
+
* them is at worst a throughput cost, while not serializing an embedded
|
|
37
|
+
* handle reintroduces the livelock.
|
|
38
|
+
*/
|
|
39
|
+
export declare function isEmbeddedDatabase(db: QueueableDatabase): boolean;
|
|
40
|
+
/**
|
|
41
|
+
* Run `operation` after every previously queued write on the same database
|
|
42
|
+
* has settled. When `serialize` is false the operation runs immediately.
|
|
43
|
+
*/
|
|
44
|
+
export declare function withEmbeddedWriteQueue<T>(db: QueueableDatabase, serialize: boolean, operation: () => Promise<T>): Promise<T>;
|
|
45
|
+
export {};
|
|
46
|
+
//# sourceMappingURL=embedded-write-queue.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"embedded-write-queue.d.ts","sourceRoot":"","sources":["../src/embedded-write-queue.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AAMH,UAAU,iBAAiB;IACzB,GAAG,CAAC,EAAE,MAAM,CAAC;CACd;AAED;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAAC,EAAE,EAAE,iBAAiB,GAAG,OAAO,CAEjE;AAMD;;;GAGG;AACH,wBAAsB,sBAAsB,CAAC,CAAC,EAC5C,EAAE,EAAE,iBAAiB,EACrB,SAAS,EAAE,OAAO,EAClB,SAAS,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,GAC1B,OAAO,CAAC,CAAC,CAAC,CAoBZ"}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
//#region src/embedded-write-queue.ts
|
|
2
|
+
/**
|
|
3
|
+
* In-process write serialization for embedded database engines (#2360).
|
|
4
|
+
*
|
|
5
|
+
* File-backed SQLite (libsql) allows one writer at a time and the SDK opens a
|
|
6
|
+
* NEW connection for every null-aware upsert attempt (`transaction("write")`),
|
|
7
|
+
* with no busy timeout on either connection. Any other write on the root
|
|
8
|
+
* connection while such a transaction is open — most commonly the change-feed
|
|
9
|
+
* append that follows every model save — collides as `SQLITE_BUSY`, and under
|
|
10
|
+
* sustained concurrency (a `Promise.all` of creates) the two sides livelock
|
|
11
|
+
* through every retry tier. Before the tenant-led conflict target (#2360) the
|
|
12
|
+
* null-aware path was rare (custom conflict keys with NULL values, #1246);
|
|
13
|
+
* with `tenant_id` leading every tenant-scoped default key, EVERY NULL-tenant
|
|
14
|
+
* (global) create takes it, so the collision became the steady state.
|
|
15
|
+
*
|
|
16
|
+
* The queue makes the process a single writer per database for exactly the
|
|
17
|
+
* two participants of that collision:
|
|
18
|
+
*
|
|
19
|
+
* - a `save()` whose upsert conflict values contain NULL (the only shape the
|
|
20
|
+
* SDK routes through a second-connection transaction), and
|
|
21
|
+
* - the change-feed append (a root-connection write that follows every save).
|
|
22
|
+
*
|
|
23
|
+
* Each hold is a LEAF database call — never an interceptor or hook — so the
|
|
24
|
+
* queue cannot deadlock on nested saves. PostgreSQL is never serialized here:
|
|
25
|
+
* its null-aware upsert already arbitrates through advisory locks
|
|
26
|
+
* server-side, and cross-process writers exist that an in-process queue could
|
|
27
|
+
* not order anyway (which is also why this queue is a mitigation for embedded
|
|
28
|
+
* engines' in-process writers, not a cross-process guarantee — embedded
|
|
29
|
+
* engines have no cross-process writers in supported deployments).
|
|
30
|
+
*/
|
|
31
|
+
/** Queue tail per database identity (URL string, or the handle itself). */
|
|
32
|
+
var urlQueues = /* @__PURE__ */ new Map();
|
|
33
|
+
var handleQueues = /* @__PURE__ */ new WeakMap();
|
|
34
|
+
/**
|
|
35
|
+
* Whether `db` is an embedded engine (SQLite/DuckDB/JSON — anything that is
|
|
36
|
+
* not PostgreSQL). Handles without a URL are treated as embedded: serializing
|
|
37
|
+
* them is at worst a throughput cost, while not serializing an embedded
|
|
38
|
+
* handle reintroduces the livelock.
|
|
39
|
+
*/
|
|
40
|
+
function isEmbeddedDatabase(db) {
|
|
41
|
+
return !/^postgres(?:ql)?:/iu.test(db?.url ?? "");
|
|
42
|
+
}
|
|
43
|
+
function queueKey(db) {
|
|
44
|
+
return typeof db?.url === "string" && db.url.length > 0 ? db.url : db;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Run `operation` after every previously queued write on the same database
|
|
48
|
+
* has settled. When `serialize` is false the operation runs immediately.
|
|
49
|
+
*/
|
|
50
|
+
async function withEmbeddedWriteQueue(db, serialize, operation) {
|
|
51
|
+
if (!serialize) return operation();
|
|
52
|
+
const key = queueKey(db);
|
|
53
|
+
const next = ((typeof key === "string" ? urlQueues.get(key) : handleQueues.get(key)) ?? Promise.resolve()).then(operation, operation);
|
|
54
|
+
const tail = next.catch(() => void 0);
|
|
55
|
+
if (typeof key === "string") {
|
|
56
|
+
urlQueues.set(key, tail);
|
|
57
|
+
tail.finally(() => {
|
|
58
|
+
if (urlQueues.get(key) === tail) urlQueues.delete(key);
|
|
59
|
+
});
|
|
60
|
+
} else handleQueues.set(key, tail);
|
|
61
|
+
return next;
|
|
62
|
+
}
|
|
63
|
+
//#endregion
|
|
64
|
+
export { isEmbeddedDatabase, withEmbeddedWriteQueue };
|
|
65
|
+
|
|
66
|
+
//# sourceMappingURL=embedded-write-queue.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"embedded-write-queue.js","names":[],"sources":["../src/embedded-write-queue.ts"],"sourcesContent":["/**\n * In-process write serialization for embedded database engines (#2360).\n *\n * File-backed SQLite (libsql) allows one writer at a time and the SDK opens a\n * NEW connection for every null-aware upsert attempt (`transaction(\"write\")`),\n * with no busy timeout on either connection. Any other write on the root\n * connection while such a transaction is open — most commonly the change-feed\n * append that follows every model save — collides as `SQLITE_BUSY`, and under\n * sustained concurrency (a `Promise.all` of creates) the two sides livelock\n * through every retry tier. Before the tenant-led conflict target (#2360) the\n * null-aware path was rare (custom conflict keys with NULL values, #1246);\n * with `tenant_id` leading every tenant-scoped default key, EVERY NULL-tenant\n * (global) create takes it, so the collision became the steady state.\n *\n * The queue makes the process a single writer per database for exactly the\n * two participants of that collision:\n *\n * - a `save()` whose upsert conflict values contain NULL (the only shape the\n * SDK routes through a second-connection transaction), and\n * - the change-feed append (a root-connection write that follows every save).\n *\n * Each hold is a LEAF database call — never an interceptor or hook — so the\n * queue cannot deadlock on nested saves. PostgreSQL is never serialized here:\n * its null-aware upsert already arbitrates through advisory locks\n * server-side, and cross-process writers exist that an in-process queue could\n * not order anyway (which is also why this queue is a mitigation for embedded\n * engines' in-process writers, not a cross-process guarantee — embedded\n * engines have no cross-process writers in supported deployments).\n */\n\n/** Queue tail per database identity (URL string, or the handle itself). */\nconst urlQueues = new Map<string, Promise<unknown>>();\nconst handleQueues = new WeakMap<object, Promise<unknown>>();\n\ninterface QueueableDatabase {\n url?: string;\n}\n\n/**\n * Whether `db` is an embedded engine (SQLite/DuckDB/JSON — anything that is\n * not PostgreSQL). Handles without a URL are treated as embedded: serializing\n * them is at worst a throughput cost, while not serializing an embedded\n * handle reintroduces the livelock.\n */\nexport function isEmbeddedDatabase(db: QueueableDatabase): boolean {\n return !/^postgres(?:ql)?:/iu.test(db?.url ?? '');\n}\n\nfunction queueKey(db: QueueableDatabase): string | object {\n return typeof db?.url === 'string' && db.url.length > 0 ? db.url : db;\n}\n\n/**\n * Run `operation` after every previously queued write on the same database\n * has settled. When `serialize` is false the operation runs immediately.\n */\nexport async function withEmbeddedWriteQueue<T>(\n db: QueueableDatabase,\n serialize: boolean,\n operation: () => Promise<T>,\n): Promise<T> {\n if (!serialize) return operation();\n\n const key = queueKey(db);\n const previous =\n (typeof key === 'string' ? urlQueues.get(key) : handleQueues.get(key)) ??\n Promise.resolve();\n const next = previous.then(operation, operation);\n // The stored tail must never reject, or one failed write would poison the\n // queue for every later writer.\n const tail = next.catch(() => undefined);\n if (typeof key === 'string') {\n urlQueues.set(key, tail);\n void tail.finally(() => {\n if (urlQueues.get(key) === tail) urlQueues.delete(key);\n });\n } else {\n handleQueues.set(key, tail);\n }\n return next;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA+BA,IAAM,4BAAY,IAAI,IAA8B;AACpD,IAAM,+BAAe,IAAI,QAAkC;;;;;;;AAY3D,SAAgB,mBAAmB,IAAgC;CACjE,OAAO,CAAC,sBAAsB,KAAK,IAAI,OAAO,EAAE;AAClD;AAEA,SAAS,SAAS,IAAwC;CACxD,OAAO,OAAO,IAAI,QAAQ,YAAY,GAAG,IAAI,SAAS,IAAI,GAAG,MAAM;AACrE;;;;;AAMA,eAAsB,uBACpB,IACA,WACA,WACY;CACZ,IAAI,CAAC,WAAW,OAAO,UAAU;CAEjC,MAAM,MAAM,SAAS,EAAE;CAIvB,MAAM,SAFH,OAAO,QAAQ,WAAW,UAAU,IAAI,GAAG,IAAI,aAAa,IAAI,GAAG,MACpE,QAAQ,QAAQ,EAAA,CACI,KAAK,WAAW,SAAS;CAG/C,MAAM,OAAO,KAAK,YAAY,KAAA,CAAS;CACvC,IAAI,OAAO,QAAQ,UAAU;EAC3B,UAAU,IAAI,KAAK,IAAI;EACvB,KAAU,cAAc;GACtB,IAAI,UAAU,IAAI,GAAG,MAAM,MAAM,UAAU,OAAO,GAAG;EACvD,CAAC;CACH,OACE,aAAa,IAAI,KAAK,IAAI;CAE5B,OAAO;AACT"}
|
|
@@ -40,6 +40,13 @@ export declare class EmbeddingStorage {
|
|
|
40
40
|
model?: string;
|
|
41
41
|
limit?: number;
|
|
42
42
|
minSimilarity?: number;
|
|
43
|
+
/**
|
|
44
|
+
* Restrict candidates to these object ids BEFORE ranking (#2365).
|
|
45
|
+
* `undefined` means no restriction; an empty array means no candidates
|
|
46
|
+
* (the search returns no results). Used by tenant-scoped collections so
|
|
47
|
+
* top-K never ranks rows the caller is not allowed to see.
|
|
48
|
+
*/
|
|
49
|
+
objectIds?: string[];
|
|
43
50
|
}, vector?: VectorCapabilities): Promise<Array<{
|
|
44
51
|
objectId: string;
|
|
45
52
|
similarity: number;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"storage.d.ts","sourceRoot":"","sources":["../../src/embeddings/storage.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAIH,OAAO,KAAK,EAAE,iBAAiB,EAAE,kBAAkB,EAAE,MAAM,oBAAoB,CAAC;
|
|
1
|
+
{"version":3,"file":"storage.d.ts","sourceRoot":"","sources":["../../src/embeddings/storage.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAIH,OAAO,KAAK,EAAE,iBAAiB,EAAE,kBAAkB,EAAE,MAAM,oBAAoB,CAAC;AAIhF,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AAO/C;;GAEG;AACH,qBAAa,gBAAgB;IAC3B;;;;;;OAMG;WACU,MAAM,CACjB,EAAE,EAAE,iBAAiB,EACrB,IAAI,EAAE;QACJ,WAAW,EAAE,MAAM,CAAC;QACpB,QAAQ,EAAE,MAAM,CAAC;QACjB,SAAS,EAAE,MAAM,CAAC;QAClB,WAAW,EAAE,MAAM,CAAC;QACpB,SAAS,EAAE,MAAM,EAAE,CAAC;QACpB,KAAK,EAAE,MAAM,CAAC;QACd,UAAU,EAAE,MAAM,CAAC;QACnB,QAAQ,CAAC,EAAE,MAAM,CAAC;KACnB,EACD,MAAM,CAAC,EAAE,kBAAkB,GAC1B,OAAO,CAAC,IAAI,CAAC;IA6ChB;;;;;;;;;;;;;OAaG;WACU,aAAa,CACxB,EAAE,EAAE,iBAAiB,EACrB,WAAW,EAAE,MAAM,EACnB,SAAS,EAAE,MAAM,EAAE,EACnB,OAAO,GAAE;QACP,KAAK,CAAC,EAAE,MAAM,CAAC;QACf,KAAK,CAAC,EAAE,MAAM,CAAC;QACf,KAAK,CAAC,EAAE,MAAM,CAAC;QACf,aAAa,CAAC,EAAE,MAAM,CAAC;QACvB;;;;;WAKG;QACH,SAAS,CAAC,EAAE,MAAM,EAAE,CAAC;KACjB,EACN,MAAM,CAAC,EAAE,kBAAkB,GAC1B,OAAO,CAAC,KAAK,CAAC;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IA+G3D;;;;;;;OAOG;WACU,mBAAmB,CAC9B,GAAG,EAAE,iBAAiB,EACtB,UAAU,EAAE,MAAM,EAClB,MAAM,EAAE,kBAAkB,GACzB,OAAO,CAAC,IAAI,CAAC;IAShB;;;;;;;;;OASG;WACU,GAAG,CACd,EAAE,EAAE,iBAAiB,EACrB,WAAW,EAAE,MAAM,EACnB,QAAQ,EAAE,MAAM,EAChB,SAAS,EAAE,MAAM,EACjB,KAAK,EAAE,MAAM,GACZ,OAAO,CAAC,eAAe,GAAG,IAAI,CAAC;IAclC;;;;;;;OAOG;WACU,YAAY,CACvB,EAAE,EAAE,iBAAiB,EACrB,WAAW,EAAE,MAAM,EACnB,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC,eAAe,EAAE,CAAC;IAY7B;;;;;;;;OAQG;WACU,YAAY,CACvB,EAAE,EAAE,iBAAiB,EACrB,WAAW,EAAE,MAAM,EACnB,SAAS,CAAC,EAAE,MAAM,EAClB,KAAK,CAAC,EAAE,MAAM,GACb,OAAO,CAAC,eAAe,EAAE,CAAC;IAqB7B;;;;;;;OAOG;WACU,0BAA0B,CACrC,EAAE,EAAE,iBAAiB,EACrB,WAAW,EAAE,MAAM,EACnB,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,MAAM,EAAE,CAAC;IAWpB;;;;;;OAMG;WACU,eAAe,CAC1B,EAAE,EAAE,iBAAiB,EACrB,WAAW,EAAE,MAAM,EACnB,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC,IAAI,CAAC;IAQhB;;;;;;;;OAQG;WACU,MAAM,CACjB,EAAE,EAAE,iBAAiB,EACrB,WAAW,EAAE,MAAM,EACnB,QAAQ,EAAE,MAAM,EAChB,SAAS,EAAE,MAAM,EACjB,KAAK,EAAE,MAAM,GACZ,OAAO,CAAC,IAAI,CAAC;IAWhB;;;;;OAKG;WACU,WAAW,CAAC,EAAE,EAAE,iBAAiB,GAAG,OAAO,CAAC,OAAO,CAAC;IASjE;;OAEG;IACH,OAAO,CAAC,MAAM,CAAC,QAAQ;CAexB"}
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { chunkArray } from "../utils/chunk.js";
|
|
2
|
+
import { toSafeInteger } from "../utils/safe-integer.js";
|
|
1
3
|
import { CosineSimilarity } from "./similarity.js";
|
|
2
4
|
import { createLogger } from "@happyvertical/logger";
|
|
3
5
|
import { randomUUID } from "node:crypto";
|
|
@@ -69,7 +71,8 @@ var EmbeddingStorage = class EmbeddingStorage {
|
|
|
69
71
|
* @returns Array of { objectId, similarity } ranked by similarity (highest first)
|
|
70
72
|
*/
|
|
71
73
|
static async searchSimilar(db, objectClass, embedding, options = {}, vector) {
|
|
72
|
-
const { field, model, limit = 10, minSimilarity = 0 } = options;
|
|
74
|
+
const { field, model, limit = 10, minSimilarity = 0, objectIds } = options;
|
|
75
|
+
if (objectIds !== void 0 && objectIds.length === 0) return [];
|
|
73
76
|
if (vector) try {
|
|
74
77
|
const conditions = ["object_class = $2"];
|
|
75
78
|
const params = [objectClass];
|
|
@@ -81,21 +84,36 @@ var EmbeddingStorage = class EmbeddingStorage {
|
|
|
81
84
|
conditions.push(`model = $${params.length + 2}`);
|
|
82
85
|
params.push(model);
|
|
83
86
|
}
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
params
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
87
|
+
const idChunks = objectIds ? chunkArray(objectIds, 900) : [void 0];
|
|
88
|
+
const merged = [];
|
|
89
|
+
for (const chunk of idChunks) {
|
|
90
|
+
const chunkConditions = [...conditions];
|
|
91
|
+
const chunkParams = [...params];
|
|
92
|
+
if (chunk) {
|
|
93
|
+
const placeholders = chunk.map((_, index) => `$${chunkParams.length + 2 + index}`);
|
|
94
|
+
chunkConditions.push(`object_id IN (${placeholders.join(", ")})`);
|
|
95
|
+
chunkParams.push(...chunk);
|
|
96
|
+
}
|
|
97
|
+
const results = await vector.search("_smrt_embeddings", VECTOR_COLUMN, embedding, {
|
|
98
|
+
limit,
|
|
99
|
+
metric: "cosine",
|
|
100
|
+
where: chunkConditions.join(" AND "),
|
|
101
|
+
params: chunkParams
|
|
102
|
+
});
|
|
103
|
+
merged.push(...results.map((r) => ({
|
|
104
|
+
objectId: r.object_id,
|
|
105
|
+
similarity: 1 - r.distance
|
|
106
|
+
})));
|
|
107
|
+
}
|
|
108
|
+
return merged.filter((r) => r.similarity >= minSimilarity).sort((a, b) => b.similarity - a.similarity).slice(0, limit);
|
|
93
109
|
} catch (error) {
|
|
94
110
|
logger.warn(`[embeddings] Native vector search failed, falling back to in-memory: ${error instanceof Error ? error.message : String(error)}`);
|
|
95
111
|
}
|
|
96
112
|
const storedEmbeddings = await EmbeddingStorage.listForClass(db, objectClass, field, model);
|
|
97
|
-
|
|
98
|
-
|
|
113
|
+
const allowedIds = objectIds ? new Set(objectIds) : void 0;
|
|
114
|
+
const candidates = allowedIds ? storedEmbeddings.filter((stored) => allowedIds.has(stored.object_id)) : storedEmbeddings;
|
|
115
|
+
if (candidates.length === 0) return [];
|
|
116
|
+
return candidates.map((stored) => ({
|
|
99
117
|
objectId: stored.object_id,
|
|
100
118
|
similarity: CosineSimilarity.calculate(embedding, stored.embedding)
|
|
101
119
|
})).filter((item) => item.similarity >= minSimilarity).sort((a, b) => b.similarity - a.similarity).slice(0, limit);
|
|
@@ -234,7 +252,7 @@ var EmbeddingStorage = class EmbeddingStorage {
|
|
|
234
252
|
content_hash: row.content_hash,
|
|
235
253
|
embedding: JSON.parse(row.embedding),
|
|
236
254
|
model: row.model,
|
|
237
|
-
dimensions: row.dimensions,
|
|
255
|
+
dimensions: toSafeInteger(row.dimensions, "Embedding dimensions"),
|
|
238
256
|
provider: row.provider,
|
|
239
257
|
created_at: new Date(row.created_at),
|
|
240
258
|
updated_at: new Date(row.updated_at)
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"storage.js","names":[],"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"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"storage.js","names":[],"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 { chunkArray, IN_LIST_CHUNK_SIZE } from '../utils/chunk';\nimport { toSafeInteger } from '../utils/safe-integer.js';\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 * Restrict candidates to these object ids BEFORE ranking (#2365).\n * `undefined` means no restriction; an empty array means no candidates\n * (the search returns no results). Used by tenant-scoped collections so\n * top-K never ranks rows the caller is not allowed to see.\n */\n objectIds?: string[];\n } = {},\n vector?: VectorCapabilities,\n ): Promise<Array<{ objectId: string; similarity: number }>> {\n const { field, model, limit = 10, minSimilarity = 0, objectIds } = options;\n\n // An explicit empty candidate set means \"nothing is visible\" — never fall\n // through to the unrestricted search.\n if (objectIds !== undefined && objectIds.length === 0) {\n return [];\n }\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 // Candidate restriction (#2365). The id list is chunked so one query\n // never exceeds the backend's bind-variable limit; per-chunk top-K\n // results merge into an exact global top-K because every chunk\n // returns its own best `limit` candidates.\n const idChunks = objectIds\n ? chunkArray(objectIds, IN_LIST_CHUNK_SIZE)\n : [undefined];\n\n const merged: Array<{ objectId: string; similarity: number }> = [];\n for (const chunk of idChunks) {\n const chunkConditions = [...conditions];\n const chunkParams = [...params];\n if (chunk) {\n const placeholders = chunk.map(\n (_, index) => `$${chunkParams.length + 2 + index}`,\n );\n chunkConditions.push(`object_id IN (${placeholders.join(', ')})`);\n chunkParams.push(...chunk);\n }\n\n const results = await vector.search(\n '_smrt_embeddings',\n VECTOR_COLUMN,\n embedding,\n {\n limit,\n metric: 'cosine',\n where: chunkConditions.join(' AND '),\n params: chunkParams,\n },\n );\n\n // Convert cosine distance (0=identical, 2=opposite) to similarity\n // (1=identical, -1=opposite)\n merged.push(\n ...results.map((r) => ({\n objectId: r.object_id as string,\n similarity: 1 - r.distance,\n })),\n );\n }\n\n return merged\n .filter((r) => r.similarity >= minSimilarity)\n .sort((a, b) => b.similarity - a.similarity)\n .slice(0, limit);\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 // Candidate restriction (#2365): drop invisible rows BEFORE ranking so\n // top-K is computed only over what the caller may see.\n const allowedIds = objectIds ? new Set(objectIds) : undefined;\n const candidates = allowedIds\n ? storedEmbeddings.filter((stored) => allowedIds.has(stored.object_id))\n : storedEmbeddings;\n\n if (candidates.length === 0) {\n return [];\n }\n\n return candidates\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: toSafeInteger(row.dimensions, 'Embedding dimensions'),\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"],"mappings":"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"}
|
package/dist/errors.d.ts
CHANGED
|
@@ -17,7 +17,7 @@ export declare abstract class SmrtError extends Error {
|
|
|
17
17
|
name: string;
|
|
18
18
|
message: string;
|
|
19
19
|
code: string;
|
|
20
|
-
category: "
|
|
20
|
+
category: "database" | "ai" | "filesystem" | "validation" | "network" | "configuration" | "runtime";
|
|
21
21
|
details: Record<string, unknown> | undefined;
|
|
22
22
|
stack: string | undefined;
|
|
23
23
|
cause: {
|
package/dist/hierarchical.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
+
import { chunkArray } from "./utils/chunk.js";
|
|
1
2
|
import { SmrtObject } from "./object.js";
|
|
2
3
|
import { ObjectRegistry } from "./registry.js";
|
|
3
|
-
import { chunkArray } from "./utils/chunk.js";
|
|
4
4
|
//#region src/hierarchical.ts
|
|
5
5
|
var SmrtHierarchical = class SmrtHierarchical extends SmrtObject {
|
|
6
6
|
/**
|
package/dist/index.d.ts
CHANGED
|
@@ -16,6 +16,7 @@
|
|
|
16
16
|
* - MCPGenerator: Create MCP servers for AI model integration
|
|
17
17
|
*/
|
|
18
18
|
export * from './adapters/index';
|
|
19
|
+
export { buildCascadePlan, type CascadePlan, type CascadePolymorphicReference, type CascadeReference, type CascadeRegistryView, type CascadeResult, cascadeReferencesTo, normalizeOnDelete, type OnDeleteAction, runCascadeDelete, } from './cascade';
|
|
19
20
|
export { type AppendChangeInput, appendChange, bumpChangeFeed, CHANGE_FEED_INTERCEPTOR_NAME, CHANGE_FEED_TABLE, type ChangeFeedEntry, type ChangeFeedPage, type ChangeFeedRetention, type ChangeOperation, DEFAULT_CHANGES_LIMIT, ensureChangeFeedTable, type GetChangesOptions, getChangesSince, getTableVersion, getTenantScopedChangesSince, MAX_CHANGES_LIMIT, pruneChangeFeed, registerChangeFeedWriter, resetChangeFeedWarnings, unregisterChangeFeedWriter, } from './change-feed';
|
|
20
21
|
export { CHANGE_SIGNAL_CHANNEL, type ChangeSignal, type ChangeSignalListener, resetChangeSignals, stopChangeSignalListeners, subscribeToChangeSignals, } from './change-signals';
|
|
21
22
|
export { applyOneToManyChildAccessors, childAccessorName, } from './child-accessors';
|
|
@@ -54,7 +55,7 @@ export { smrt as smrtRegistry } from './registry';
|
|
|
54
55
|
export * from './runtime/index';
|
|
55
56
|
export { detectEngine, generateDDLForEngine } from './schema/ddl';
|
|
56
57
|
export { type ConflictTargetInput, checkLiveSchemaParity, type ExpectedTableOrigin, type LiveParityFinding, type LiveParityFindingKind, type LiveParitySeverity, LiveSchemaParityError, type LiveSchemaParityOptions, type LiveSchemaParityReport, } from './schema/live-parity';
|
|
57
|
-
export { getSystemTableShapes, type SystemTableShape, } from './schema/system-table-shapes';
|
|
58
|
+
export { getSystemTableShapes, SYSTEM_TABLE_NAMES, type SystemTableShape, } from './schema/system-table-shapes';
|
|
58
59
|
export type { SchemaDefinition } from './schema/types';
|
|
59
60
|
export * from './signals/index';
|
|
60
61
|
export * from './sync/apply';
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAGH,cAAc,kBAAkB,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|