@lunora/bindings 0.0.0 → 1.0.0-alpha.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (40) hide show
  1. package/LICENSE.md +105 -0
  2. package/README.md +39 -1
  3. package/__assets__/package-og.svg +14 -0
  4. package/dist/analytics/index.d.mts +148 -0
  5. package/dist/analytics/index.d.ts +148 -0
  6. package/dist/analytics/index.mjs +2 -0
  7. package/dist/images/index.d.mts +338 -0
  8. package/dist/images/index.d.ts +338 -0
  9. package/dist/images/index.mjs +3 -0
  10. package/dist/kv/index.d.mts +177 -0
  11. package/dist/kv/index.d.ts +177 -0
  12. package/dist/kv/index.mjs +1 -0
  13. package/dist/packem_shared/AnalyticsSqlError-CGTdsi4H.mjs +42 -0
  14. package/dist/packem_shared/R2SqlError-DlDd_SrE.mjs +67 -0
  15. package/dist/packem_shared/SelectBuilder-DHaXZwn_.mjs +167 -0
  16. package/dist/packem_shared/SetOperation-RDHcxccj.mjs +80 -0
  17. package/dist/packem_shared/Sql-DceGtcUd.mjs +68 -0
  18. package/dist/packem_shared/WindowExpression-Cg9s2xcr.mjs +44 -0
  19. package/dist/packem_shared/WindowFunction-DA3pGC3N.mjs +82 -0
  20. package/dist/packem_shared/asc-Cur-xO8v.mjs +16 -0
  21. package/dist/packem_shared/buildImageDeliveryUrl-D1sVfIOP.mjs +30 -0
  22. package/dist/packem_shared/buildSignedImageUrl-Otdgc_jO.mjs +113 -0
  23. package/dist/packem_shared/concurrent-Dj5sOibv.mjs +23 -0
  24. package/dist/packem_shared/createAnalytics-CEEI69o9.mjs +57 -0
  25. package/dist/packem_shared/createContextVectors-BSizpmu5.mjs +140 -0
  26. package/dist/packem_shared/createImages-CJrvqX0u.mjs +80 -0
  27. package/dist/packem_shared/createKv-DTiSt216.mjs +141 -0
  28. package/dist/packem_shared/createPipelines-CfyJ6VGu.mjs +10 -0
  29. package/dist/packem_shared/createVectorAdminIntrospector-BJUOM6VW.mjs +51 -0
  30. package/dist/packem_shared/createVectors-LSpGoKCd.mjs +91 -0
  31. package/dist/pipelines/index.d.mts +41 -0
  32. package/dist/pipelines/index.d.ts +41 -0
  33. package/dist/pipelines/index.mjs +1 -0
  34. package/dist/r2sql/index.d.mts +383 -0
  35. package/dist/r2sql/index.d.ts +383 -0
  36. package/dist/r2sql/index.mjs +7 -0
  37. package/dist/vectors/index.d.mts +285 -0
  38. package/dist/vectors/index.d.ts +285 -0
  39. package/dist/vectors/index.mjs +3 -0
  40. package/package.json +54 -4
@@ -0,0 +1,285 @@
1
+ /**
2
+ * Minimal structural projection of `VectorizeIndex` so unit tests can pass a
3
+ * plain-object double and the real Cloudflare binding satisfies the same shape.
4
+ * Mirrors the surface documented at
5
+ * https://developers.cloudflare.com/vectorize/reference/client-api/.
6
+ */
7
+ interface VectorizeIndexLike {
8
+ deleteByIds: (ids: ReadonlyArray<string>) => Promise<VectorizeDeleteMutation>;
9
+ describe?: () => Promise<VectorizeIndexDetails>;
10
+ getByIds: (ids: ReadonlyArray<string>) => Promise<ReadonlyArray<VectorizeVector>>;
11
+ insert: (vectors: ReadonlyArray<VectorizeVector>) => Promise<VectorizeUpsertMutation>;
12
+ query: (vector: ReadonlyArray<number>, options?: VectorizeQueryOptions) => Promise<VectorizeMatches>;
13
+ upsert: (vectors: ReadonlyArray<VectorizeVector>) => Promise<VectorizeUpsertMutation>;
14
+ }
15
+ type VectorMetric = "cosine" | "euclidean" | "dot-product";
16
+ interface VectorizeVector {
17
+ id: string;
18
+ metadata?: Record<string, unknown>;
19
+ namespace?: string;
20
+ values: ReadonlyArray<number>;
21
+ }
22
+ interface VectorizeQueryOptions {
23
+ filter?: Record<string, unknown>;
24
+ namespace?: string;
25
+ returnMetadata?: "none" | "indexed" | "all";
26
+ returnValues?: boolean;
27
+ topK?: number;
28
+ }
29
+ interface VectorizeMatch {
30
+ id: string;
31
+ metadata?: Record<string, unknown>;
32
+ namespace?: string;
33
+ score: number;
34
+ values?: ReadonlyArray<number>;
35
+ }
36
+ interface VectorizeMatches {
37
+ count: number;
38
+ matches: ReadonlyArray<VectorizeMatch>;
39
+ }
40
+ interface VectorizeUpsertMutation {
41
+ mutationId: string;
42
+ }
43
+ interface VectorizeDeleteMutation {
44
+ count?: number;
45
+ mutationId: string;
46
+ }
47
+ interface VectorizeIndexDetails {
48
+ dimensions: number;
49
+ processedUpToDatetime?: string;
50
+ processedUpToMutation?: string;
51
+ vectorsCount: number;
52
+ }
53
+ /**
54
+ * Bring-your-own-embedder: a user-supplied async fn that converts a single
55
+ * source value (a row, a chunk, an arbitrary string) into a numeric vector.
56
+ * The runtime calls this at upsert time so we don't couple to any provider.
57
+ */
58
+ type EmbedFunction<TInput = unknown> = (input: TInput) => Promise<ReadonlyArray<number>> | ReadonlyArray<number>;
59
+ interface LunoraVectorsOptions {
60
+ /**
61
+ * Map of logical index name -> Vectorize binding. Most apps wire one
62
+ * binding per index; multi-index apps register all of them here so calls
63
+ * like `vectors.query("docs-body", ...)` can resolve to the right binding.
64
+ */
65
+ indexes: Record<string, VectorizeIndexLike>;
66
+ }
67
+ interface UpsertInput<TInput = unknown> {
68
+ embed: EmbedFunction<TInput>;
69
+ id: string;
70
+ input: TInput;
71
+ metadata?: Record<string, unknown>;
72
+ namespace?: string;
73
+ }
74
+ interface QueryInput<TInput = unknown> {
75
+ embed?: EmbedFunction<TInput>;
76
+ filter?: Record<string, unknown>;
77
+ input?: TInput;
78
+ namespace?: string;
79
+ returnMetadata?: "none" | "indexed" | "all";
80
+ returnValues?: boolean;
81
+ topK?: number;
82
+ /** Either a precomputed vector or a value to embed via `embed`. */
83
+ vector?: ReadonlyArray<number>;
84
+ }
85
+ interface LunoraVectors {
86
+ deleteByIds: (indexName: string, ids: ReadonlyArray<string>) => Promise<VectorizeDeleteMutation>;
87
+ describe: (indexName: string) => Promise<VectorizeIndexDetails>;
88
+ getByIds: (indexName: string, ids: ReadonlyArray<string>) => Promise<ReadonlyArray<VectorizeVector>>;
89
+ query: <TInput>(indexName: string, input: QueryInput<TInput>) => Promise<VectorizeMatches>;
90
+ upsert: <TInput>(indexName: string, input: UpsertInput<TInput>) => Promise<VectorizeUpsertMutation>;
91
+ upsertMany: <TInput>(indexName: string, inputs: ReadonlyArray<UpsertInput<TInput>>) => Promise<VectorizeUpsertMutation>;
92
+ }
93
+ /**
94
+ * `(input: string) => vector`. Matches `@lunora/server`'s `VectorEmbedder` so
95
+ * the bridged surface is assignable to the server's `VectorSearch` contract.
96
+ */
97
+ type VectorEmbedderLike = (input: string) => Promise<ReadonlyArray<number>> | ReadonlyArray<number>;
98
+ interface VectorMatchLike {
99
+ id: string;
100
+ metadata?: Record<string, unknown>;
101
+ score: number;
102
+ }
103
+ interface VectorMatchesLike {
104
+ count: number;
105
+ matches: ReadonlyArray<VectorMatchLike>;
106
+ }
107
+ interface VectorRecordLike {
108
+ id: string;
109
+ metadata?: Record<string, unknown>;
110
+ values: ReadonlyArray<number>;
111
+ }
112
+ interface VectorQueryInputLike {
113
+ embed?: VectorEmbedderLike;
114
+ filter?: Record<string, unknown>;
115
+ input?: string;
116
+ namespace?: string;
117
+ /**
118
+ * How much stored metadata to return on matches. Defaults to `"indexed"`
119
+ * (only fields declared as index metadata) rather than `"all"`, so a query
120
+ * never leaks arbitrary stored fields by default. Callers that genuinely
121
+ * need every field opt in with `"all"`; pass `"none"` to drop metadata.
122
+ */
123
+ returnMetadata?: "none" | "indexed" | "all";
124
+ topK?: number;
125
+ vector?: ReadonlyArray<number>;
126
+ }
127
+ interface VectorUpsertInputLike {
128
+ embed: VectorEmbedderLike;
129
+ id: string;
130
+ input: string;
131
+ metadata?: Record<string, unknown>;
132
+ namespace?: string;
133
+ }
134
+ /**
135
+ * Structural mirror of `@lunora/server`'s `VectorSearch`. Declared here so the
136
+ * adapter never imports `@lunora/server` (keeps the dependency edge one-way:
137
+ * the generated DO depends on both, neither depends on the other).
138
+ */
139
+ interface VectorSearchLike {
140
+ deleteByIds: (indexName: string, ids: ReadonlyArray<string>) => Promise<void>;
141
+ getByIds: (indexName: string, ids: ReadonlyArray<string>) => Promise<ReadonlyArray<VectorRecordLike>>;
142
+ query: (indexName: string, input: VectorQueryInputLike) => Promise<VectorMatchesLike>;
143
+ upsert: (indexName: string, input: VectorUpsertInputLike) => Promise<void>;
144
+ upsertNow: (indexName: string, input: VectorUpsertInputLike) => Promise<void>;
145
+ }
146
+ /**
147
+ * Bridge `LunoraVectors` (returns Vectorize mutation receipts) to the server's
148
+ * `VectorSearch` contract (void mutations, server match/record shapes). Both
149
+ * `upsert` and `upsertNow` write inline — this design has no post-commit queue,
150
+ * so "now" and "deferred" collapse to the same synchronous call.
151
+ */
152
+ declare const createContextVectors: (lunora: LunoraVectors) => VectorSearchLike;
153
+ /** A single row mutation observed by the ctx-db, fed to {@link createVectorSyncHook}. */
154
+ interface WriteEvent {
155
+ doc?: Record<string, unknown>;
156
+ id: string;
157
+ op: "delete" | "insert" | "update";
158
+ table: string;
159
+ }
160
+ type WriteHook = (event: WriteEvent) => Promise<void>;
161
+ /** Inline vector index declared via `.vectorize(field, ...)` (DSL Shape A). */
162
+ interface TableVectorIndexLike {
163
+ embed: VectorEmbedderLike;
164
+ field: string;
165
+ metadata?: ReadonlyArray<string>;
166
+ name: string;
167
+ }
168
+ interface TableDefinitionLike {
169
+ vectorIndexes?: ReadonlyArray<TableVectorIndexLike>;
170
+ }
171
+ /** Standalone vector index declared via `defineVectorIndex(...)` (DSL Shape B). */
172
+ interface VectorIndexDefinitionLike {
173
+ embed: VectorEmbedderLike;
174
+ metadata?: (row: Record<string, unknown>) => Record<string, unknown>;
175
+ select: (row: Record<string, unknown>) => string;
176
+ table: string;
177
+ }
178
+ /**
179
+ * Structural mirror of `@lunora/server`'s `Schema`, narrowed to the fields the
180
+ * sync hook reads. Carries live `embed`/`select` closures, so the hook must be
181
+ * built from the imported `schema` value — never a serialized descriptor.
182
+ */
183
+ interface SchemaLike {
184
+ tables: Record<string, TableDefinitionLike>;
185
+ vectorIndexes: Record<string, VectorIndexDefinitionLike>;
186
+ }
187
+ /**
188
+ * Build a {@link WriteHook} that keeps Vectorize in sync with row writes. On
189
+ * insert/update it embeds each matching index's source (Shape A `row[field]`,
190
+ * Shape B `select(row)`) and upserts; on delete it removes the row's id from
191
+ * every index sourced from the table. Runs inline within the write path.
192
+ *
193
+ * Tenant isolation — IMPORTANT: Vectorize indexes are account-global and shared
194
+ * by every shard DO. Without a `namespace`, a multi-tenant sharded app has NO
195
+ * isolation between tenants in the vector index — one tenant's vectors are
196
+ * queryable by another (ids/scores leak existence + semantic similarity even
197
+ * when no metadata is indexed). The caller MUST pass `options.namespace` (the
198
+ * shard / tenant key) so upserts are scoped, and MUST apply the same namespace
199
+ * on the query side — query-side namespace filtering is mandatory, not optional.
200
+ * The namespace is threaded onto upserts here; pass it from the shard DO that
201
+ * owns this hook. Any namespace-less sync emits a one-time-per-index dev warning
202
+ * (regardless of whether metadata is present); a genuinely single-tenant app
203
+ * suppresses it with `allowSharedNamespace: true`.
204
+ *
205
+ * Consistency — IMPORTANT: this hook runs inline within the mutation but talks
206
+ * to Vectorize, which is external and non-transactional. The per-index calls
207
+ * fan out; if one fails after others have already applied, the SQLite write may
208
+ * roll back while the applied Vectorize mutations cannot — leaving SQLite and
209
+ * Vectorize diverged. We mitigate, not eliminate: upserts/deletes are
210
+ * idempotent (keyed by row id), so a retry of the same write converges; and on
211
+ * a fan-out failure we attempt a best-effort compensating delete of the row's
212
+ * id from every affected index before re-throwing. A delete after a failed
213
+ * upsert can itself fail — this is best-effort, the authoritative recovery is
214
+ * re-running the (idempotent) write.
215
+ */
216
+ declare const createVectorSyncHook: (options: {
217
+ allowSharedNamespace?: boolean;
218
+ namespace?: string;
219
+ schema: SchemaLike;
220
+ vectors: VectorSearchLike;
221
+ }) => WriteHook;
222
+ /**
223
+ * One vector index as the generated `LUNORA_VECTOR_INDEXES` registry describes
224
+ * it — the static schema shape, independent of any live binding. Structurally
225
+ * the codegen `LunoraVectorIndex`, restated here so this package stays free of a
226
+ * dependency on `@lunora/codegen`.
227
+ */
228
+ interface VectorIndexRegistryEntry {
229
+ dimensions?: number;
230
+ field?: string;
231
+ metadata?: ReadonlyArray<string>;
232
+ metric?: VectorMetric;
233
+ name: string;
234
+ table: string;
235
+ }
236
+ /** A registry entry merged with the live `describe()` stats (when the binding is reachable). */
237
+ interface VectorAdminIndexSummary extends VectorIndexRegistryEntry {
238
+ processedUpToMutation?: string;
239
+ vectorsCount?: number;
240
+ }
241
+ /** One nearest-neighbour hit from an admin similarity query. */
242
+ interface VectorAdminQueryMatch {
243
+ id: string;
244
+ metadata?: Record<string, unknown>;
245
+ score: number;
246
+ }
247
+ /**
248
+ * The admin introspector the worker passes to `createWorker({ vectorIntrospector })`.
249
+ * `queryIndex` is present only when at least one embedder is wired.
250
+ */
251
+ interface VectorAdminIntrospector {
252
+ listIndexes: () => Promise<VectorAdminIndexSummary[]>;
253
+ queryIndex?: (options: {
254
+ name: string;
255
+ text: string;
256
+ topK?: number;
257
+ }) => Promise<{
258
+ matches: VectorAdminQueryMatch[];
259
+ }>;
260
+ }
261
+ interface VectorAdminIntrospectorOptions {
262
+ /**
263
+ * Per-index embedder (text → vector), keyed by index name. Supply the
264
+ * schema's embedders to enable studio similarity queries; omit it (or leave
265
+ * an index out) and that index lists read-only — `queryIndex` is withheld
266
+ * entirely when no embedder is provided.
267
+ */
268
+ embedders?: Record<string, EmbedFunction<string>>;
269
+ /** Live Vectorize bindings keyed by index name, from `env`. */
270
+ indexes: Record<string, VectorizeIndexLike>;
271
+ /** The generated `LUNORA_VECTOR_INDEXES` registry (Vectorize can't enumerate at runtime). */
272
+ registry: ReadonlyArray<VectorIndexRegistryEntry>;
273
+ }
274
+ /**
275
+ * Build the read-only Vectorize introspector backing the studio's vector
276
+ * browser. `listIndexes` returns the static registry, enriching each entry with
277
+ * live `describe()` stats when the matching binding is present (a binding that
278
+ * throws or lacks `describe` degrades to the static shape rather than failing
279
+ * the whole list). `queryIndex` embeds the query text via the index's embedder
280
+ * and runs an ANN search; it is omitted when no embedders are configured, so the
281
+ * worker reports `VECTOR_QUERY_UNSUPPORTED` rather than half-answering.
282
+ */
283
+ declare const createVectorAdminIntrospector: (options: VectorAdminIntrospectorOptions) => VectorAdminIntrospector;
284
+ declare const createVectors: (options: LunoraVectorsOptions) => LunoraVectors;
285
+ export { type EmbedFunction, type LunoraVectors, type LunoraVectorsOptions, type QueryInput, type SchemaLike, type TableDefinitionLike, type TableVectorIndexLike, type UpsertInput, type VectorAdminIndexSummary, type VectorAdminIntrospector, type VectorAdminIntrospectorOptions, type VectorAdminQueryMatch, type VectorEmbedderLike, type VectorIndexDefinitionLike, type VectorIndexRegistryEntry, type VectorMatchLike, type VectorMatchesLike, type VectorMetric, type VectorQueryInputLike, type VectorRecordLike, type VectorSearchLike, type VectorUpsertInputLike, type VectorizeDeleteMutation, type VectorizeIndexDetails, type VectorizeIndexLike, type VectorizeMatch, type VectorizeMatches, type VectorizeQueryOptions, type VectorizeUpsertMutation, type VectorizeVector, type WriteEvent, type WriteHook, createContextVectors, createVectorAdminIntrospector, createVectorSyncHook, createVectors };
@@ -0,0 +1,3 @@
1
+ export { createContextVectors, createVectorSyncHook } from '../packem_shared/createContextVectors-BSizpmu5.mjs';
2
+ export { createVectorAdminIntrospector } from '../packem_shared/createVectorAdminIntrospector-BJUOM6VW.mjs';
3
+ export { default as createVectors } from '../packem_shared/createVectors-LSpGoKCd.mjs';
package/package.json CHANGED
@@ -1,19 +1,69 @@
1
1
  {
2
2
  "name": "@lunora/bindings",
3
- "version": "0.0.0",
4
- "description": "Placeholder to reserve the npm name. Real releases are published from CI — install the latest version.",
3
+ "version": "1.0.0-alpha.2",
4
+ "description": "Lightweight Cloudflare binding helpers for Lunora — ctx.kv, ctx.images, ctx.analytics, ctx.pipelines, ctx.vectors, ctx.r2sqlone install, per-binding subpaths",
5
+ "keywords": [
6
+ "analytics",
7
+ "cloudflare",
8
+ "images",
9
+ "kv",
10
+ "lunora",
11
+ "pipelines",
12
+ "r2-sql",
13
+ "vectorize",
14
+ "workers"
15
+ ],
16
+ "homepage": "https://lunora.sh",
17
+ "bugs": "https://github.com/anolilab/lunora/issues",
5
18
  "license": "FSL-1.1-Apache-2.0",
6
19
  "author": {
7
20
  "name": "Daniel Bannert",
8
21
  "email": "d.bannert@anolilab.de"
9
22
  },
10
- "homepage": "https://lunora.sh",
11
23
  "repository": {
12
24
  "type": "git",
13
25
  "url": "git+https://github.com/anolilab/lunora.git",
14
26
  "directory": "packages/bindings"
15
27
  },
28
+ "files": [
29
+ "./dist",
30
+ "README.md",
31
+ "LICENSE.md",
32
+ "__assets__"
33
+ ],
34
+ "type": "module",
35
+ "sideEffects": false,
36
+ "exports": {
37
+ "./kv": {
38
+ "types": "./dist/kv/index.d.ts",
39
+ "import": "./dist/kv/index.mjs"
40
+ },
41
+ "./images": {
42
+ "types": "./dist/images/index.d.ts",
43
+ "import": "./dist/images/index.mjs"
44
+ },
45
+ "./analytics": {
46
+ "types": "./dist/analytics/index.d.ts",
47
+ "import": "./dist/analytics/index.mjs"
48
+ },
49
+ "./pipelines": {
50
+ "types": "./dist/pipelines/index.d.ts",
51
+ "import": "./dist/pipelines/index.mjs"
52
+ },
53
+ "./vectors": {
54
+ "types": "./dist/vectors/index.d.ts",
55
+ "import": "./dist/vectors/index.mjs"
56
+ },
57
+ "./r2sql": {
58
+ "types": "./dist/r2sql/index.d.ts",
59
+ "import": "./dist/r2sql/index.mjs"
60
+ },
61
+ "./package.json": "./package.json"
62
+ },
16
63
  "publishConfig": {
17
64
  "access": "public"
65
+ },
66
+ "engines": {
67
+ "node": "^22.15.0 || >=24.11.0"
18
68
  }
19
- }
69
+ }