ai-database 2.1.3 → 2.3.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/CHANGELOG.md +35 -1
- package/README.md +880 -669
- package/dist/actions.d.ts +2 -2
- package/dist/actions.d.ts.map +1 -1
- package/dist/actions.js +1 -1
- package/dist/actions.js.map +1 -1
- package/dist/ai-promise-db.d.ts +49 -23
- package/dist/ai-promise-db.d.ts.map +1 -1
- package/dist/ai-promise-db.js +91 -63
- package/dist/ai-promise-db.js.map +1 -1
- package/dist/authorization.d.ts.map +1 -1
- package/dist/authorization.js +38 -30
- package/dist/authorization.js.map +1 -1
- package/dist/cascade-orchestrator.d.ts +404 -0
- package/dist/cascade-orchestrator.d.ts.map +1 -0
- package/dist/cascade-orchestrator.js +828 -0
- package/dist/cascade-orchestrator.js.map +1 -0
- package/dist/cascade-write-strategy.d.ts +584 -0
- package/dist/cascade-write-strategy.d.ts.map +1 -0
- package/dist/cascade-write-strategy.js +590 -0
- package/dist/cascade-write-strategy.js.map +1 -0
- package/dist/ch-adapter.d.ts +358 -0
- package/dist/ch-adapter.d.ts.map +1 -0
- package/dist/ch-adapter.js +929 -0
- package/dist/ch-adapter.js.map +1 -0
- package/dist/client/index.d.ts +42 -0
- package/dist/client/index.d.ts.map +1 -0
- package/dist/client/index.js +43 -0
- package/dist/client/index.js.map +1 -0
- package/dist/client.d.ts +266 -0
- package/dist/client.d.ts.map +1 -0
- package/dist/client.js +81 -0
- package/dist/client.js.map +1 -0
- package/dist/constants.d.ts +64 -1
- package/dist/constants.d.ts.map +1 -1
- package/dist/constants.js +52 -2
- package/dist/constants.js.map +1 -1
- package/dist/dataloader.d.ts +99 -0
- package/dist/dataloader.d.ts.map +1 -0
- package/dist/dataloader.js +225 -0
- package/dist/dataloader.js.map +1 -0
- package/dist/db-provider-port.d.ts +501 -0
- package/dist/db-provider-port.d.ts.map +1 -0
- package/dist/db-provider-port.js +113 -0
- package/dist/db-provider-port.js.map +1 -0
- package/dist/digital-objects-provider.d.ts +49 -0
- package/dist/digital-objects-provider.d.ts.map +1 -0
- package/dist/digital-objects-provider.js +55 -0
- package/dist/digital-objects-provider.js.map +1 -0
- package/dist/do-sqlite-adapter.d.ts +402 -0
- package/dist/do-sqlite-adapter.d.ts.map +1 -0
- package/dist/do-sqlite-adapter.js +745 -0
- package/dist/do-sqlite-adapter.js.map +1 -0
- package/dist/docs-rels/custom-types.d.ts +134 -0
- package/dist/docs-rels/custom-types.d.ts.map +1 -0
- package/dist/docs-rels/custom-types.js +70 -0
- package/dist/docs-rels/custom-types.js.map +1 -0
- package/dist/docs-rels/index.d.ts +16 -0
- package/dist/docs-rels/index.d.ts.map +1 -0
- package/dist/docs-rels/index.js +16 -0
- package/dist/docs-rels/index.js.map +1 -0
- package/dist/docs-rels/migrations/index.d.ts +30 -0
- package/dist/docs-rels/migrations/index.d.ts.map +1 -0
- package/dist/docs-rels/migrations/index.js +128 -0
- package/dist/docs-rels/migrations/index.js.map +1 -0
- package/dist/docs-rels/schema.d.ts +2961 -0
- package/dist/docs-rels/schema.d.ts.map +1 -0
- package/dist/docs-rels/schema.js +244 -0
- package/dist/docs-rels/schema.js.map +1 -0
- package/dist/durable-clickhouse.d.ts.map +1 -1
- package/dist/durable-clickhouse.js +16 -13
- package/dist/durable-clickhouse.js.map +1 -1
- package/dist/durable-promise.d.ts.map +1 -1
- package/dist/durable-promise.js +34 -15
- package/dist/durable-promise.js.map +1 -1
- package/dist/errors.d.ts +127 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +210 -0
- package/dist/errors.js.map +1 -0
- package/dist/eventbridge.d.ts +117 -0
- package/dist/eventbridge.d.ts.map +1 -0
- package/dist/eventbridge.js +238 -0
- package/dist/eventbridge.js.map +1 -0
- package/dist/events.d.ts +2 -2
- package/dist/events.d.ts.map +1 -1
- package/dist/events.js +1 -1
- package/dist/events.js.map +1 -1
- package/dist/execution-queue.d.ts.map +1 -1
- package/dist/execution-queue.js +4 -5
- package/dist/execution-queue.js.map +1 -1
- package/dist/index.d.ts +35 -8
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +106 -6
- package/dist/index.js.map +1 -1
- package/dist/linguistic.d.ts +3 -108
- package/dist/linguistic.d.ts.map +1 -1
- package/dist/linguistic.js +3 -372
- package/dist/linguistic.js.map +1 -1
- package/dist/logger.d.ts +132 -0
- package/dist/logger.d.ts.map +1 -0
- package/dist/logger.js +137 -0
- package/dist/logger.js.map +1 -0
- package/dist/memory-provider.d.ts +128 -0
- package/dist/memory-provider.d.ts.map +1 -1
- package/dist/memory-provider.js +592 -257
- package/dist/memory-provider.js.map +1 -1
- package/dist/pg-adapter.d.ts +424 -0
- package/dist/pg-adapter.d.ts.map +1 -0
- package/dist/pg-adapter.js +921 -0
- package/dist/pg-adapter.js.map +1 -0
- package/dist/pipelines-iceberg-emitter.d.ts +327 -0
- package/dist/pipelines-iceberg-emitter.d.ts.map +1 -0
- package/dist/pipelines-iceberg-emitter.js +351 -0
- package/dist/pipelines-iceberg-emitter.js.map +1 -0
- package/dist/provider-capabilities.d.ts +146 -0
- package/dist/provider-capabilities.d.ts.map +1 -0
- package/dist/provider-capabilities.js +214 -0
- package/dist/provider-capabilities.js.map +1 -0
- package/dist/rdb-provider-adapter.d.ts +195 -0
- package/dist/rdb-provider-adapter.d.ts.map +1 -0
- package/dist/rdb-provider-adapter.js +291 -0
- package/dist/rdb-provider-adapter.js.map +1 -0
- package/dist/schema/cascade.d.ts +48 -17
- package/dist/schema/cascade.d.ts.map +1 -1
- package/dist/schema/cascade.js +477 -278
- package/dist/schema/cascade.js.map +1 -1
- package/dist/schema/definition-caches.d.ts +24 -0
- package/dist/schema/definition-caches.d.ts.map +1 -0
- package/dist/schema/definition-caches.js +26 -0
- package/dist/schema/definition-caches.js.map +1 -0
- package/dist/schema/dependency-graph.d.ts +21 -109
- package/dist/schema/dependency-graph.d.ts.map +1 -1
- package/dist/schema/dependency-graph.js +25 -333
- package/dist/schema/dependency-graph.js.map +1 -1
- package/dist/schema/diff.d.ts +103 -0
- package/dist/schema/diff.d.ts.map +1 -0
- package/dist/schema/diff.js +329 -0
- package/dist/schema/diff.js.map +1 -0
- package/dist/schema/entity-operations.d.ts +99 -0
- package/dist/schema/entity-operations.d.ts.map +1 -0
- package/dist/schema/entity-operations.js +818 -0
- package/dist/schema/entity-operations.js.map +1 -0
- package/dist/schema/index.d.ts +28 -34
- package/dist/schema/index.d.ts.map +1 -1
- package/dist/schema/index.js +454 -521
- package/dist/schema/index.js.map +1 -1
- package/dist/schema/migration.d.ts +205 -0
- package/dist/schema/migration.d.ts.map +1 -0
- package/dist/schema/migration.js +327 -0
- package/dist/schema/migration.js.map +1 -0
- package/dist/schema/nl-query-generator.d.ts +68 -0
- package/dist/schema/nl-query-generator.d.ts.map +1 -0
- package/dist/schema/nl-query-generator.js +362 -0
- package/dist/schema/nl-query-generator.js.map +1 -0
- package/dist/schema/nl-query.d.ts +65 -0
- package/dist/schema/nl-query.d.ts.map +1 -0
- package/dist/schema/nl-query.js +178 -0
- package/dist/schema/nl-query.js.map +1 -0
- package/dist/schema/parse.d.ts.map +1 -1
- package/dist/schema/parse.js +144 -89
- package/dist/schema/parse.js.map +1 -1
- package/dist/schema/provider.d.ts +37 -0
- package/dist/schema/provider.d.ts.map +1 -1
- package/dist/schema/provider.js +15 -7
- package/dist/schema/provider.js.map +1 -1
- package/dist/schema/resolve.d.ts +46 -5
- package/dist/schema/resolve.d.ts.map +1 -1
- package/dist/schema/resolve.js +237 -95
- package/dist/schema/resolve.js.map +1 -1
- package/dist/schema/search-utils.d.ts +76 -0
- package/dist/schema/search-utils.d.ts.map +1 -0
- package/dist/schema/search-utils.js +86 -0
- package/dist/schema/search-utils.js.map +1 -0
- package/dist/schema/seed.d.ts +53 -0
- package/dist/schema/seed.d.ts.map +1 -0
- package/dist/schema/seed.js +94 -0
- package/dist/schema/seed.js.map +1 -0
- package/dist/schema/semantic.d.ts +10 -0
- package/dist/schema/semantic.d.ts.map +1 -1
- package/dist/schema/semantic.js +192 -86
- package/dist/schema/semantic.js.map +1 -1
- package/dist/schema/sub-apis.d.ts +52 -0
- package/dist/schema/sub-apis.d.ts.map +1 -0
- package/dist/schema/sub-apis.js +216 -0
- package/dist/schema/sub-apis.js.map +1 -0
- package/dist/schema/system-entities.d.ts +42 -0
- package/dist/schema/system-entities.d.ts.map +1 -0
- package/dist/schema/system-entities.js +101 -0
- package/dist/schema/system-entities.js.map +1 -0
- package/dist/schema/types.d.ts +91 -9
- package/dist/schema/types.d.ts.map +1 -1
- package/dist/schema/union-fallback.d.ts.map +1 -1
- package/dist/schema/union-fallback.js +21 -15
- package/dist/schema/union-fallback.js.map +1 -1
- package/dist/schema/value-generators/ai.d.ts +54 -0
- package/dist/schema/value-generators/ai.d.ts.map +1 -0
- package/dist/schema/value-generators/ai.js +136 -0
- package/dist/schema/value-generators/ai.js.map +1 -0
- package/dist/schema/value-generators/index.d.ts +126 -0
- package/dist/schema/value-generators/index.d.ts.map +1 -0
- package/dist/schema/value-generators/index.js +219 -0
- package/dist/schema/value-generators/index.js.map +1 -0
- package/dist/schema/value-generators/placeholder.d.ts +52 -0
- package/dist/schema/value-generators/placeholder.d.ts.map +1 -0
- package/dist/schema/value-generators/placeholder.js +328 -0
- package/dist/schema/value-generators/placeholder.js.map +1 -0
- package/dist/schema/value-generators/types.d.ts +116 -0
- package/dist/schema/value-generators/types.d.ts.map +1 -0
- package/dist/schema/value-generators/types.js +11 -0
- package/dist/schema/value-generators/types.js.map +1 -0
- package/dist/schema/version.d.ts +111 -0
- package/dist/schema/version.d.ts.map +1 -0
- package/dist/schema/version.js +190 -0
- package/dist/schema/version.js.map +1 -0
- package/dist/schema.d.ts +1095 -24
- package/dist/schema.d.ts.map +1 -1
- package/dist/schema.js +2852 -40
- package/dist/schema.js.map +1 -1
- package/dist/semantic-vectors.d.ts +39 -0
- package/dist/semantic-vectors.d.ts.map +1 -0
- package/dist/semantic-vectors.js +334 -0
- package/dist/semantic-vectors.js.map +1 -0
- package/dist/semantic.d.ts +29 -1
- package/dist/semantic.d.ts.map +1 -1
- package/dist/semantic.js +26 -16
- package/dist/semantic.js.map +1 -1
- package/dist/telemetry.d.ts +128 -0
- package/dist/telemetry.d.ts.map +1 -0
- package/dist/telemetry.js +305 -0
- package/dist/telemetry.js.map +1 -0
- package/dist/tests.d.ts.map +1 -1
- package/dist/tests.js +30 -22
- package/dist/tests.js.map +1 -1
- package/dist/type-guards.d.ts +50 -5
- package/dist/type-guards.d.ts.map +1 -1
- package/dist/type-guards.js +87 -16
- package/dist/type-guards.js.map +1 -1
- package/dist/types.d.ts +33 -245
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +62 -72
- package/dist/types.js.map +1 -1
- package/dist/validation.d.ts +2 -5
- package/dist/validation.d.ts.map +1 -1
- package/dist/validation.js +65 -93
- package/dist/validation.js.map +1 -1
- package/dist/worker/db-provider.d.ts +168 -0
- package/dist/worker/db-provider.d.ts.map +1 -0
- package/dist/worker/db-provider.js +277 -0
- package/dist/worker/db-provider.js.map +1 -0
- package/dist/worker/index.d.ts +35 -0
- package/dist/worker/index.d.ts.map +1 -0
- package/dist/worker/index.js +37 -0
- package/dist/worker/index.js.map +1 -0
- package/dist/worker.d.ts +779 -0
- package/dist/worker.d.ts.map +1 -0
- package/dist/worker.js +2786 -0
- package/dist/worker.js.map +1 -0
- package/package.json +46 -16
- package/src/docs-rels/migrations/0001-init.sql +125 -0
- package/LICENSE +0 -21
|
@@ -0,0 +1,351 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pipelines → Iceberg analytical fan-out emitter — Phase 2 final, bead `aip-0ypt`.
|
|
3
|
+
*
|
|
4
|
+
* Implements the {@link AnalyticalEmitter} contract surfaced by
|
|
5
|
+
* {@link CascadeWriteStrategy} so cascade writes can dual-write into
|
|
6
|
+
* Iceberg via Cloudflare Pipelines without changing the strategy or
|
|
7
|
+
* orchestrator surface. Per
|
|
8
|
+
* [ADR-0003](../../../docs/adr/0003-storage-strategy-pg-clickhouse-default.md),
|
|
9
|
+
* Stack B's storage shape is:
|
|
10
|
+
*
|
|
11
|
+
* ```text
|
|
12
|
+
* cascade write
|
|
13
|
+
* │
|
|
14
|
+
* ▼
|
|
15
|
+
* DO SQLite (per-cascade, transactional, source of truth for traversal)
|
|
16
|
+
* │
|
|
17
|
+
* └──► CascadeWriteStrategy.analyticalEmitter ──► Cloudflare Pipelines ──► R2 Iceberg
|
|
18
|
+
* (analytical SOR; ClickHouse reads from here)
|
|
19
|
+
* ```
|
|
20
|
+
*
|
|
21
|
+
* The transactional path through DO SQLite is the source of truth for
|
|
22
|
+
* cascade correctness. The analytical fan-out is **fire-and-forget** on
|
|
23
|
+
* the hot path: emitter failures MUST NOT fail the cascade write. The
|
|
24
|
+
* `CascadeWriteStrategy` already swallows thrown errors from the
|
|
25
|
+
* emitter; this module additionally never throws — even on completely
|
|
26
|
+
* misconfigured bindings — so callers get the same shape regardless of
|
|
27
|
+
* runtime.
|
|
28
|
+
*
|
|
29
|
+
* ## Schema mapping
|
|
30
|
+
*
|
|
31
|
+
* Iceberg tables for `things` and `actions` mirror the SVO surface used
|
|
32
|
+
* by the PG/CH/DO SQLite adapters. Columns are kept in lowercase
|
|
33
|
+
* snake_case (Iceberg is case-insensitive but tooling typically
|
|
34
|
+
* normalises this way):
|
|
35
|
+
*
|
|
36
|
+
* **things table**
|
|
37
|
+
* - `id` STRING (Thing id; content-hashed by the orchestrator)
|
|
38
|
+
* - `type` STRING (Thing `$type`)
|
|
39
|
+
* - `data` STRING (jsonb-style — emitted as a stringified JSON blob;
|
|
40
|
+
* downstream readers (CH `JSONExtract`, DataFusion `arrow_cast`) parse
|
|
41
|
+
* on read. Iceberg has STRUCT columns but cascade Things are
|
|
42
|
+
* open-shape so we keep the column STRING)
|
|
43
|
+
* - `cascade_id` STRING (the cascade this row belongs to; partition key)
|
|
44
|
+
* - `tenant_id` STRING NULL (when sharded by tenant)
|
|
45
|
+
* - `shard_key` STRING (the strategy's routing key, e.g. `cascade:abc`)
|
|
46
|
+
* - `created_at` TIMESTAMP (emit time; stable)
|
|
47
|
+
* - `updated_at` TIMESTAMP (emit time; bumped on re-emit)
|
|
48
|
+
*
|
|
49
|
+
* **actions table** — wire-compatible with `SVOAction`
|
|
50
|
+
* - `id` STRING (Action id; orchestrator-supplied or adapter-generated)
|
|
51
|
+
* - `verb` STRING
|
|
52
|
+
* - `subject` STRING NULL
|
|
53
|
+
* - `object` STRING NULL
|
|
54
|
+
* - `roles` STRING (JSON-stringified Frame role map)
|
|
55
|
+
* - `data` STRING (JSON-stringified payload)
|
|
56
|
+
* - `status` STRING (`pending` | `completed` | `failed` | `cancelled`)
|
|
57
|
+
* - `cascade_id` STRING (partition key)
|
|
58
|
+
* - `tenant_id` STRING NULL
|
|
59
|
+
* - `shard_key` STRING
|
|
60
|
+
* - `timestamp` TIMESTAMP (emit time)
|
|
61
|
+
*
|
|
62
|
+
* Schema bootstrap (creating the Iceberg tables) is a deployment-time
|
|
63
|
+
* concern; this emitter only writes records into an existing table
|
|
64
|
+
* via the Pipelines binding's `send()`.
|
|
65
|
+
*
|
|
66
|
+
* ## Bindings
|
|
67
|
+
*
|
|
68
|
+
* The emitter accepts a structurally-typed
|
|
69
|
+
* {@link PipelinesStreamBindingLike} so the module compiles in plain
|
|
70
|
+
* Node tests without `@cloudflare/workers-types`. Real Pipelines
|
|
71
|
+
* bindings produced by `wrangler.toml` satisfy this shape at runtime.
|
|
72
|
+
* For non-Workers callers (Node / dev / batch jobs) an
|
|
73
|
+
* {@link HttpPipelinesEmitterOptions} HTTP fallback is supported,
|
|
74
|
+
* issuing `POST` requests against the Pipelines stream endpoint.
|
|
75
|
+
*
|
|
76
|
+
* ## Exactly-once / dedup
|
|
77
|
+
*
|
|
78
|
+
* Cloudflare Pipelines is at-least-once by default. Cascade entity
|
|
79
|
+
* ids are content-hashed by the orchestrator (same inputs → same id),
|
|
80
|
+
* so re-emits of the same cascade re-use the same `id` field — Iceberg
|
|
81
|
+
* MERGE-on-read jobs (or the Pipelines binding's optional dedup key)
|
|
82
|
+
* collapse duplicates downstream. Callers wanting strict
|
|
83
|
+
* exactly-once semantics should configure dedup on the Pipelines
|
|
84
|
+
* stream itself; this emitter exposes `dedupKey?: 'id' | null` to
|
|
85
|
+
* indicate which field to use.
|
|
86
|
+
*
|
|
87
|
+
* @see {@link ../../../docs/adr/0003-storage-strategy-pg-clickhouse-default.md}
|
|
88
|
+
* @see {@link ./cascade-write-strategy.ts}
|
|
89
|
+
* @packageDocumentation
|
|
90
|
+
*/
|
|
91
|
+
// =============================================================================
|
|
92
|
+
// Public API
|
|
93
|
+
// =============================================================================
|
|
94
|
+
/**
|
|
95
|
+
* Create an {@link AnalyticalEmitter} that fans out cascade writes
|
|
96
|
+
* into Iceberg via Cloudflare Pipelines.
|
|
97
|
+
*
|
|
98
|
+
* The returned emitter satisfies the
|
|
99
|
+
* {@link CascadeWriteStrategy.analyticalEmitter} contract — pass it
|
|
100
|
+
* directly to {@link CascadeWriteStrategy} or
|
|
101
|
+
* {@link generateCascade} via the `analyticalEmitter` option.
|
|
102
|
+
*
|
|
103
|
+
* @example Workers binding mode
|
|
104
|
+
* ```ts
|
|
105
|
+
* import { createPipelinesIcebergEmitter, generateCascade } from 'ai-database'
|
|
106
|
+
*
|
|
107
|
+
* const emitter = createPipelinesIcebergEmitter({
|
|
108
|
+
* binding: env.ANALYTICAL_PIPE,
|
|
109
|
+
* thingsTable: 'aidb.things',
|
|
110
|
+
* actionsTable: 'aidb.actions',
|
|
111
|
+
* tenantId: 'acme',
|
|
112
|
+
* })
|
|
113
|
+
*
|
|
114
|
+
* await generateCascade({
|
|
115
|
+
* adapter,
|
|
116
|
+
* rootNoun: 'Customer',
|
|
117
|
+
* analyticalEmitter: emitter,
|
|
118
|
+
* // ...
|
|
119
|
+
* })
|
|
120
|
+
* ```
|
|
121
|
+
*
|
|
122
|
+
* @example Node HTTP fallback (dev / batch)
|
|
123
|
+
* ```ts
|
|
124
|
+
* import { createHttpPipelinesIcebergEmitter } from 'ai-database'
|
|
125
|
+
*
|
|
126
|
+
* const emitter = createHttpPipelinesIcebergEmitter({
|
|
127
|
+
* url: process.env.PIPELINES_URL,
|
|
128
|
+
* authToken: process.env.PIPELINES_TOKEN,
|
|
129
|
+
* })
|
|
130
|
+
* ```
|
|
131
|
+
*/
|
|
132
|
+
export function createPipelinesIcebergEmitter(options) {
|
|
133
|
+
const thingsBinding = options.thingsBinding ?? options.binding;
|
|
134
|
+
const actionsBinding = options.actionsBinding ?? options.binding;
|
|
135
|
+
if (!thingsBinding && !actionsBinding) {
|
|
136
|
+
throw new Error('createPipelinesIcebergEmitter: at least one of `binding`, ' +
|
|
137
|
+
'`thingsBinding`, or `actionsBinding` must be provided. For ' +
|
|
138
|
+
'non-Workers callers, use createHttpPipelinesIcebergEmitter() ' +
|
|
139
|
+
'with an HTTPS endpoint URL instead.');
|
|
140
|
+
}
|
|
141
|
+
return makeEmitter({
|
|
142
|
+
options,
|
|
143
|
+
sendThings: thingsBinding ? (rows) => Promise.resolve(thingsBinding.send(rows)) : null,
|
|
144
|
+
sendActions: actionsBinding ? (rows) => Promise.resolve(actionsBinding.send(rows)) : null,
|
|
145
|
+
});
|
|
146
|
+
}
|
|
147
|
+
/**
|
|
148
|
+
* Create an {@link AnalyticalEmitter} that fans out cascade writes
|
|
149
|
+
* into Iceberg via the Pipelines HTTPS stream endpoint.
|
|
150
|
+
*
|
|
151
|
+
* Used by non-Workers callers (Node / dev / batch jobs). Workers
|
|
152
|
+
* deployments should prefer {@link createPipelinesIcebergEmitter}
|
|
153
|
+
* for lower latency.
|
|
154
|
+
*/
|
|
155
|
+
export function createHttpPipelinesIcebergEmitter(options) {
|
|
156
|
+
const thingsUrl = options.thingsUrl ?? options.url;
|
|
157
|
+
const actionsUrl = options.actionsUrl ?? options.url;
|
|
158
|
+
if (!thingsUrl && !actionsUrl) {
|
|
159
|
+
throw new Error('createHttpPipelinesIcebergEmitter: at least one of `url`, ' +
|
|
160
|
+
'`thingsUrl`, or `actionsUrl` must be provided.');
|
|
161
|
+
}
|
|
162
|
+
const fetchImpl = options.fetch ??
|
|
163
|
+
((input, init) => {
|
|
164
|
+
// Defer to the runtime's global fetch. Pulled inline so tests can
|
|
165
|
+
// pass a structural fake without monkey-patching globals.
|
|
166
|
+
const g = globalThis;
|
|
167
|
+
if (typeof g.fetch !== 'function') {
|
|
168
|
+
return Promise.reject(new Error('createHttpPipelinesIcebergEmitter: no global `fetch` available. ' +
|
|
169
|
+
'Pass `fetch` in options for non-Worker / non-Node-18+ environments.'));
|
|
170
|
+
}
|
|
171
|
+
return g.fetch(input, init);
|
|
172
|
+
});
|
|
173
|
+
const headers = { 'Content-Type': 'application/json' };
|
|
174
|
+
if (options.authToken)
|
|
175
|
+
headers['Authorization'] = `Bearer ${options.authToken}`;
|
|
176
|
+
const send = async (url, rows) => {
|
|
177
|
+
const res = await fetchImpl(url, {
|
|
178
|
+
method: 'POST',
|
|
179
|
+
headers,
|
|
180
|
+
body: JSON.stringify(rows),
|
|
181
|
+
});
|
|
182
|
+
if (!res.ok) {
|
|
183
|
+
throw new Error(`Pipelines HTTP send failed: ${res.status} ${res.statusText}`);
|
|
184
|
+
}
|
|
185
|
+
};
|
|
186
|
+
return makeEmitter({
|
|
187
|
+
options,
|
|
188
|
+
sendThings: thingsUrl ? (rows) => send(thingsUrl, rows) : null,
|
|
189
|
+
sendActions: actionsUrl
|
|
190
|
+
? (rows) => send(actionsUrl, thingsUrl === actionsUrl ? rows : rows /* same payload shape */)
|
|
191
|
+
: null,
|
|
192
|
+
});
|
|
193
|
+
}
|
|
194
|
+
function makeEmitter(args) {
|
|
195
|
+
const thingsTable = args.options.thingsTable ?? 'things';
|
|
196
|
+
const actionsTable = args.options.actionsTable ?? 'actions';
|
|
197
|
+
const dedupKey = args.options.dedupKey === undefined ? 'id' : args.options.dedupKey;
|
|
198
|
+
const nowFn = args.options.now ?? (() => new Date().toISOString());
|
|
199
|
+
const logger = args.options.logger;
|
|
200
|
+
const awaitSend = args.options.awaitSend ?? false;
|
|
201
|
+
const optionTenantId = args.options.tenantId;
|
|
202
|
+
return async (input) => {
|
|
203
|
+
// Resolve cascade-routing columns from the shard ref. The strategy
|
|
204
|
+
// guarantees `shard.context` carries `cascadeId` / `tenantId` when
|
|
205
|
+
// the active strategy needed them.
|
|
206
|
+
const shard = input.shard;
|
|
207
|
+
const cascadeId = resolveCascadeId(shard);
|
|
208
|
+
const tenantId = optionTenantId ?? resolveTenantId(shard);
|
|
209
|
+
const shardKey = shard.key;
|
|
210
|
+
const timestamp = nowFn();
|
|
211
|
+
const thingsRows = buildThingsRows(input.batch, {
|
|
212
|
+
thingsTable,
|
|
213
|
+
cascadeId,
|
|
214
|
+
tenantId,
|
|
215
|
+
shardKey,
|
|
216
|
+
timestamp,
|
|
217
|
+
dedupKey,
|
|
218
|
+
});
|
|
219
|
+
const actionsRows = buildActionsRows(input.batch, {
|
|
220
|
+
actionsTable,
|
|
221
|
+
cascadeId,
|
|
222
|
+
tenantId,
|
|
223
|
+
shardKey,
|
|
224
|
+
timestamp,
|
|
225
|
+
dedupKey,
|
|
226
|
+
});
|
|
227
|
+
const tasks = [];
|
|
228
|
+
if (thingsRows.length > 0 && args.sendThings) {
|
|
229
|
+
const task = Promise.resolve()
|
|
230
|
+
.then(() => args.sendThings(thingsRows))
|
|
231
|
+
.catch((err) => {
|
|
232
|
+
logger?.warn?.('pipelines-iceberg-emitter:things:send-failed', {
|
|
233
|
+
error: errorMessage(err),
|
|
234
|
+
rows: thingsRows.length,
|
|
235
|
+
shardKey,
|
|
236
|
+
});
|
|
237
|
+
});
|
|
238
|
+
tasks.push(task);
|
|
239
|
+
}
|
|
240
|
+
if (actionsRows.length > 0 && args.sendActions) {
|
|
241
|
+
const task = Promise.resolve()
|
|
242
|
+
.then(() => args.sendActions(actionsRows))
|
|
243
|
+
.catch((err) => {
|
|
244
|
+
logger?.warn?.('pipelines-iceberg-emitter:actions:send-failed', {
|
|
245
|
+
error: errorMessage(err),
|
|
246
|
+
rows: actionsRows.length,
|
|
247
|
+
shardKey,
|
|
248
|
+
});
|
|
249
|
+
});
|
|
250
|
+
tasks.push(task);
|
|
251
|
+
}
|
|
252
|
+
if (awaitSend && tasks.length > 0) {
|
|
253
|
+
await Promise.all(tasks);
|
|
254
|
+
}
|
|
255
|
+
};
|
|
256
|
+
}
|
|
257
|
+
function buildThingsRows(batch, ctx) {
|
|
258
|
+
const things = batch.things ?? [];
|
|
259
|
+
if (things.length === 0)
|
|
260
|
+
return [];
|
|
261
|
+
const rows = [];
|
|
262
|
+
for (const t of things) {
|
|
263
|
+
const row = {
|
|
264
|
+
id: t.id,
|
|
265
|
+
type: t.type,
|
|
266
|
+
data: stableJsonStringify(t.data),
|
|
267
|
+
cascade_id: ctx.cascadeId,
|
|
268
|
+
tenant_id: ctx.tenantId,
|
|
269
|
+
shard_key: ctx.shardKey,
|
|
270
|
+
created_at: ctx.timestamp,
|
|
271
|
+
updated_at: ctx.timestamp,
|
|
272
|
+
_table: ctx.thingsTable,
|
|
273
|
+
};
|
|
274
|
+
if (ctx.dedupKey)
|
|
275
|
+
row['_dedup_key'] = row[ctx.dedupKey];
|
|
276
|
+
rows.push(row);
|
|
277
|
+
}
|
|
278
|
+
return rows;
|
|
279
|
+
}
|
|
280
|
+
function buildActionsRows(batch, ctx) {
|
|
281
|
+
const actions = batch.actions ?? [];
|
|
282
|
+
if (actions.length === 0)
|
|
283
|
+
return [];
|
|
284
|
+
const rows = [];
|
|
285
|
+
for (const a of actions) {
|
|
286
|
+
const row = {
|
|
287
|
+
id: a.id ?? generateActionId(ctx.cascadeId, ctx.timestamp, rows.length),
|
|
288
|
+
verb: a.verb,
|
|
289
|
+
subject: a.subject ?? null,
|
|
290
|
+
object: a.object ?? null,
|
|
291
|
+
roles: stableJsonStringify(a.roles ?? {}),
|
|
292
|
+
data: stableJsonStringify(a.data ?? {}),
|
|
293
|
+
status: a.status ?? 'completed',
|
|
294
|
+
cascade_id: ctx.cascadeId,
|
|
295
|
+
tenant_id: ctx.tenantId,
|
|
296
|
+
shard_key: ctx.shardKey,
|
|
297
|
+
timestamp: ctx.timestamp,
|
|
298
|
+
_table: ctx.actionsTable,
|
|
299
|
+
};
|
|
300
|
+
if (ctx.dedupKey)
|
|
301
|
+
row['_dedup_key'] = row[ctx.dedupKey];
|
|
302
|
+
rows.push(row);
|
|
303
|
+
}
|
|
304
|
+
return rows;
|
|
305
|
+
}
|
|
306
|
+
// =============================================================================
|
|
307
|
+
// Internals — utilities
|
|
308
|
+
// =============================================================================
|
|
309
|
+
function resolveCascadeId(shard) {
|
|
310
|
+
const ctxId = shard.context.cascadeId;
|
|
311
|
+
if (typeof ctxId === 'string' && ctxId.length > 0)
|
|
312
|
+
return ctxId;
|
|
313
|
+
// Fall back to the shard key — for `partitioned-by-tenant` and
|
|
314
|
+
// `unsharded` strategies there is no per-cascade id, so the routing
|
|
315
|
+
// key is the best we can do. Iceberg readers can group on it.
|
|
316
|
+
return shard.key;
|
|
317
|
+
}
|
|
318
|
+
function resolveTenantId(shard) {
|
|
319
|
+
const t = shard.context.tenantId;
|
|
320
|
+
return typeof t === 'string' && t.length > 0 ? t : null;
|
|
321
|
+
}
|
|
322
|
+
/**
|
|
323
|
+
* Stable JSON stringify — keys sorted recursively. Iceberg dedup at
|
|
324
|
+
* compaction time depends on identical row bytes for the same logical
|
|
325
|
+
* row; un-sorted key ordering would defeat that.
|
|
326
|
+
*/
|
|
327
|
+
function stableJsonStringify(value) {
|
|
328
|
+
return JSON.stringify(value, (_key, val) => {
|
|
329
|
+
if (val === null || typeof val !== 'object' || Array.isArray(val))
|
|
330
|
+
return val;
|
|
331
|
+
const sortedKeys = Object.keys(val).sort();
|
|
332
|
+
const result = {};
|
|
333
|
+
for (const k of sortedKeys) {
|
|
334
|
+
result[k] = val[k];
|
|
335
|
+
}
|
|
336
|
+
return result;
|
|
337
|
+
});
|
|
338
|
+
}
|
|
339
|
+
/**
|
|
340
|
+
* Generate a deterministic-enough Action id when the orchestrator
|
|
341
|
+
* didn't supply one. Production callers always supply Action ids via
|
|
342
|
+
* the orchestrator's content-hash; this is a safety net for ad-hoc
|
|
343
|
+
* `writeBatch` callers.
|
|
344
|
+
*/
|
|
345
|
+
function generateActionId(cascadeId, timestamp, index) {
|
|
346
|
+
return `act-${cascadeId.slice(0, 16)}-${timestamp.replace(/[^0-9]/g, '').slice(0, 14)}-${index}`;
|
|
347
|
+
}
|
|
348
|
+
function errorMessage(err) {
|
|
349
|
+
return err instanceof Error ? err.message : String(err);
|
|
350
|
+
}
|
|
351
|
+
//# sourceMappingURL=pipelines-iceberg-emitter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pipelines-iceberg-emitter.js","sourceRoot":"","sources":["../src/pipelines-iceberg-emitter.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Provider Capability Detection and Management
|
|
3
|
+
*
|
|
4
|
+
* This module provides runtime detection of provider capabilities,
|
|
5
|
+
* enabling graceful degradation when advanced features are unavailable.
|
|
6
|
+
*
|
|
7
|
+
* @packageDocumentation
|
|
8
|
+
*/
|
|
9
|
+
import type { DBProvider } from './schema.js';
|
|
10
|
+
/**
|
|
11
|
+
* Capability flags indicating which features a provider supports
|
|
12
|
+
*
|
|
13
|
+
* @example
|
|
14
|
+
* ```ts
|
|
15
|
+
* const capabilities: ProviderCapabilities = {
|
|
16
|
+
* hasSemanticSearch: true,
|
|
17
|
+
* hasEvents: true,
|
|
18
|
+
* hasActions: true,
|
|
19
|
+
* hasArtifacts: true,
|
|
20
|
+
* hasBatchOperations: true,
|
|
21
|
+
* }
|
|
22
|
+
* ```
|
|
23
|
+
*/
|
|
24
|
+
export interface ProviderCapabilities {
|
|
25
|
+
/** Whether the provider supports semantic/vector search */
|
|
26
|
+
hasSemanticSearch: boolean;
|
|
27
|
+
/** Whether the provider supports event emission and subscription */
|
|
28
|
+
hasEvents: boolean;
|
|
29
|
+
/** Whether the provider supports durable actions (pending/active/completed) */
|
|
30
|
+
hasActions: boolean;
|
|
31
|
+
/** Whether the provider supports artifact storage (embeddings, caches) */
|
|
32
|
+
hasArtifacts: boolean;
|
|
33
|
+
/** Whether the provider supports batch operations with concurrency control */
|
|
34
|
+
hasBatchOperations: boolean;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Detect which capabilities a provider supports by examining its methods
|
|
38
|
+
*
|
|
39
|
+
* Probes the provider for the presence of advanced methods to determine
|
|
40
|
+
* which features are available. Results are cached per-provider.
|
|
41
|
+
*
|
|
42
|
+
* @param provider - The database provider to inspect
|
|
43
|
+
* @returns Detected capabilities
|
|
44
|
+
*
|
|
45
|
+
* @example
|
|
46
|
+
* ```ts
|
|
47
|
+
* const provider = createMemoryProvider()
|
|
48
|
+
* const capabilities = await detectCapabilities(provider)
|
|
49
|
+
*
|
|
50
|
+
* if (capabilities.hasSemanticSearch) {
|
|
51
|
+
* const results = await provider.semanticSearch('Post', 'machine learning')
|
|
52
|
+
* } else {
|
|
53
|
+
* const results = await provider.search('Post', 'machine learning')
|
|
54
|
+
* }
|
|
55
|
+
* ```
|
|
56
|
+
*/
|
|
57
|
+
export declare function detectCapabilities(provider: DBProvider): Promise<ProviderCapabilities>;
|
|
58
|
+
/**
|
|
59
|
+
* Clear the capability cache for a specific provider
|
|
60
|
+
*
|
|
61
|
+
* Useful when a provider's capabilities change dynamically.
|
|
62
|
+
*
|
|
63
|
+
* @param provider - The provider to clear from cache
|
|
64
|
+
*/
|
|
65
|
+
export declare function clearCapabilityCache(provider: DBProvider): void;
|
|
66
|
+
/**
|
|
67
|
+
* Error thrown when attempting to use a feature that the provider doesn't support
|
|
68
|
+
*
|
|
69
|
+
* @example
|
|
70
|
+
* ```ts
|
|
71
|
+
* try {
|
|
72
|
+
* await provider.semanticSearch('Post', 'query')
|
|
73
|
+
* } catch (e) {
|
|
74
|
+
* if (isCapabilityNotSupportedError(e)) {
|
|
75
|
+
* console.log(`${e.capability} is not supported, using fallback...`)
|
|
76
|
+
* }
|
|
77
|
+
* throw e
|
|
78
|
+
* }
|
|
79
|
+
* ```
|
|
80
|
+
*/
|
|
81
|
+
export declare class CapabilityNotSupportedError extends Error {
|
|
82
|
+
/** The capability that was requested but not supported */
|
|
83
|
+
readonly capability: string;
|
|
84
|
+
/** Optional suggested alternative */
|
|
85
|
+
readonly alternative?: string | undefined;
|
|
86
|
+
readonly code = "CAPABILITY_NOT_SUPPORTED";
|
|
87
|
+
readonly name = "CapabilityNotSupportedError";
|
|
88
|
+
constructor(
|
|
89
|
+
/** The capability that was requested but not supported */
|
|
90
|
+
capability: string,
|
|
91
|
+
/** Optional custom error message */
|
|
92
|
+
message?: string,
|
|
93
|
+
/** Optional suggested alternative */
|
|
94
|
+
alternative?: string | undefined);
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* Type guard to check if an error is a CapabilityNotSupportedError
|
|
98
|
+
*
|
|
99
|
+
* @param error - The error to check
|
|
100
|
+
* @returns True if the error is a CapabilityNotSupportedError
|
|
101
|
+
*/
|
|
102
|
+
export declare function isCapabilityNotSupportedError(error: unknown): error is CapabilityNotSupportedError;
|
|
103
|
+
/**
|
|
104
|
+
* Require a capability to be available, throwing if not
|
|
105
|
+
*
|
|
106
|
+
* Use this before calling methods that require specific capabilities.
|
|
107
|
+
*
|
|
108
|
+
* @param capabilities - The detected capabilities
|
|
109
|
+
* @param capability - The capability key to require
|
|
110
|
+
* @param message - Optional custom error message
|
|
111
|
+
* @throws CapabilityNotSupportedError if the capability is not available
|
|
112
|
+
*
|
|
113
|
+
* @example
|
|
114
|
+
* ```ts
|
|
115
|
+
* const capabilities = await detectCapabilities(provider)
|
|
116
|
+
* requireCapability(capabilities, 'hasSemanticSearch')
|
|
117
|
+
* // Safe to call semanticSearch now
|
|
118
|
+
* ```
|
|
119
|
+
*/
|
|
120
|
+
export declare function requireCapability(capabilities: ProviderCapabilities, capability: keyof ProviderCapabilities, message?: string): void;
|
|
121
|
+
/**
|
|
122
|
+
* Log a warning if a capability is unavailable (only once per capability)
|
|
123
|
+
*
|
|
124
|
+
* @param capabilities - The detected capabilities
|
|
125
|
+
* @param capability - The capability key to check
|
|
126
|
+
* @param featureName - Human-readable name for the warning message
|
|
127
|
+
*
|
|
128
|
+
* @example
|
|
129
|
+
* ```ts
|
|
130
|
+
* warnIfUnavailable(capabilities, 'hasSemanticSearch', 'semanticSearch')
|
|
131
|
+
* // Logs: "Warning: semanticSearch is not available with this provider"
|
|
132
|
+
* ```
|
|
133
|
+
*/
|
|
134
|
+
export declare function warnIfUnavailable(capabilities: ProviderCapabilities, capability: keyof ProviderCapabilities, featureName: string): void;
|
|
135
|
+
/**
|
|
136
|
+
* Clear warning suppression (useful for testing)
|
|
137
|
+
*/
|
|
138
|
+
export declare function clearWarningHistory(): void;
|
|
139
|
+
/**
|
|
140
|
+
* Standard capability matrix for known providers
|
|
141
|
+
*
|
|
142
|
+
* This is a reference for documentation purposes. Actual capabilities
|
|
143
|
+
* are detected at runtime using detectCapabilities().
|
|
144
|
+
*/
|
|
145
|
+
export declare const PROVIDER_CAPABILITY_MATRIX: Record<string, ProviderCapabilities>;
|
|
146
|
+
//# sourceMappingURL=provider-capabilities.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"provider-capabilities.d.ts","sourceRoot":"","sources":["../src/provider-capabilities.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,aAAa,CAAA;AAO7C;;;;;;;;;;;;;GAaG;AACH,MAAM,WAAW,oBAAoB;IACnC,2DAA2D;IAC3D,iBAAiB,EAAE,OAAO,CAAA;IAC1B,oEAAoE;IACpE,SAAS,EAAE,OAAO,CAAA;IAClB,+EAA+E;IAC/E,UAAU,EAAE,OAAO,CAAA;IACnB,0EAA0E;IAC1E,YAAY,EAAE,OAAO,CAAA;IACrB,8EAA8E;IAC9E,kBAAkB,EAAE,OAAO,CAAA;CAC5B;AAWD;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAsB,kBAAkB,CAAC,QAAQ,EAAE,UAAU,GAAG,OAAO,CAAC,oBAAoB,CAAC,CAuC5F;AAED;;;;;;GAMG;AACH,wBAAgB,oBAAoB,CAAC,QAAQ,EAAE,UAAU,GAAG,IAAI,CAE/D;AAMD;;;;;;;;;;;;;;GAcG;AACH,qBAAa,2BAA4B,SAAQ,KAAK;IAKlD,0DAA0D;aAC1C,UAAU,EAAE,MAAM;IAGlC,qCAAqC;aACrB,WAAW,CAAC,EAAE,MAAM;IATtC,SAAgB,IAAI,8BAA6B;IACjD,SAAyB,IAAI,iCAAgC;;IAG3D,0DAA0D;IAC1C,UAAU,EAAE,MAAM;IAClC,oCAAoC;IACpC,OAAO,CAAC,EAAE,MAAM;IAChB,qCAAqC;IACrB,WAAW,CAAC,EAAE,MAAM,YAAA;CAKvC;AAED;;;;;GAKG;AACH,wBAAgB,6BAA6B,CAC3C,KAAK,EAAE,OAAO,GACb,KAAK,IAAI,2BAA2B,CAQtC;AAMD;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,iBAAiB,CAC/B,YAAY,EAAE,oBAAoB,EAClC,UAAU,EAAE,MAAM,oBAAoB,EACtC,OAAO,CAAC,EAAE,MAAM,GACf,IAAI,CAIN;AAWD;;;;;;;;;;;;GAYG;AACH,wBAAgB,iBAAiB,CAC/B,YAAY,EAAE,oBAAoB,EAClC,UAAU,EAAE,MAAM,oBAAoB,EACtC,WAAW,EAAE,MAAM,GAClB,IAAI,CAKN;AAED;;GAEG;AACH,wBAAgB,mBAAmB,IAAI,IAAI,CAE1C;AAMD;;;;;GAKG;AACH,eAAO,MAAM,0BAA0B,EAAE,MAAM,CAAC,MAAM,EAAE,oBAAoB,CAsB3E,CAAA"}
|