@lunora/bindings 1.0.0-alpha.54 → 1.0.0-alpha.56

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.
@@ -1,4 +1,4 @@
1
- import{c as b,U as g}from"./concurrent-vRmSvRpF.mjs";const x=(s,c)=>{if(!c.includes("."))return s[c];let n=s;for(const d of c.split(".")){if(n===null||typeof n!="object"||Array.isArray(n))return;n=n[d]}return n},S=(s,c)=>{const n=c?.namespace,d=new Set(c?.shardedIndexNames),l=(t,a)=>{if(a!==void 0)return a;if(d.has(t)){if(n!==void 0)return n;throw new Error(`@lunora/bindings/vectors: index "${t}" belongs to a sharded table, but this DO instance has no shard key (it is the root/default DO) and no explicit namespace was given. A namespace-less operation here would reach every tenant's vectors — Vectorize indexes are account-global. Pass an explicit namespace, or issue this call from the sharded DO instance that owns the tenant.`)}},o=async(t,a)=>{await s.upsert(t,{embed:a.embed,id:a.id,input:a.input,metadata:a.metadata,namespace:l(t,a.namespace)})},h=async(t,a,i)=>{const r=await s.getByIds(t,a);return i===void 0?r:r.filter(m=>m.namespace===i)};return{deleteByIds:async(t,a,i)=>{const r=l(t,i);if(r===void 0){await s.deleteByIds(t,a);return}const m=await h(t,a,r);m.length!==0&&await s.deleteByIds(t,m.map(u=>u.id))},getByIds:async(t,a,i)=>{const r=l(t,i);return(await h(t,a,r)).map(u=>({id:u.id,metadata:u.metadata,namespace:u.namespace,values:u.values}))},query:async(t,a)=>{const i=await s.query(t,{embed:a.embed,filter:a.filter,input:a.input,namespace:l(t,a.namespace),returnMetadata:a.returnMetadata??"indexed",topK:a.topK,vector:a.vector});return{count:i.count,matches:i.matches.map(r=>({id:r.id,metadata:r.metadata,score:r.score}))}},upsert:o,upsertNow:o}},f=new Set,v=s=>{f.has(s)||(f.add(s),console.warn(`[@lunora/bindings/vectors] index "${s}" syncs vectors without a namespace — in a
1
+ import{c as b,U as g}from"./concurrent-vRmSvRpF.mjs";const x=(s,c)=>{if(!c.includes("."))return s[c];let n=s;for(const d of c.split(".")){if(n===null||typeof n!="object"||Array.isArray(n))return;n=n[d]}return n},S=(s,c)=>{const n=c?.namespace,d=new Set(c?.shardedIndexNames),l=(t,a)=>{if(a!==void 0)return a;if(d.has(t)){if(n!==void 0)return n;throw new Error(`@lunora/bindings/vectors: index "${t}" belongs to a sharded table, but this DO instance has no shard key (it is the root/default DO) and no explicit namespace was given. A namespace-less operation here would reach every tenant's vectors — Vectorize indexes are account-global. Pass an explicit namespace, or issue this call from the sharded DO instance that owns the tenant.`)}},o=async(t,a)=>{await s.upsert(t,{embed:a.embed,id:a.id,input:a.input,metadata:a.metadata,namespace:l(t,a.namespace)})},h=async(t,a,i)=>{const r=await s.getByIds(t,a);return i===void 0?r:r.filter(m=>m.namespace===i)};return{deleteByIds:async(t,a,i)=>{const r=l(t,i);if(r===void 0){await s.deleteByIds(t,a);return}const m=await h(t,a,r);m.length!==0&&await s.deleteByIds(t,m.map(u=>u.id))},getByIds:async(t,a,i)=>{const r=l(t,i);return(await h(t,a,r)).map(u=>({id:u.id,metadata:u.metadata,namespace:u.namespace,values:[...u.values]}))},query:async(t,a)=>{const i=await s.query(t,{embed:a.embed,filter:a.filter,input:a.input,namespace:l(t,a.namespace),returnMetadata:a.returnMetadata??"indexed",topK:a.topK,vector:a.vector});return{count:i.count,matches:i.matches.map(r=>({id:r.id,metadata:r.metadata,score:r.score}))}},upsert:o,upsertNow:o}},f=new Set,v=s=>{f.has(s)||(f.add(s),console.warn(`[@lunora/bindings/vectors] index "${s}" syncs vectors without a namespace — in a
2
2
  multi-tenant/sharded app this exposes one tenant's vectors (and any captured
3
3
  metadata) to every other tenant, since Vectorize indexes are account-global.
4
4
  Pass \`namespace\` (the shard/tenant key) on both write and query — query-side
@@ -0,0 +1 @@
1
+ import{LunoraError as a}from"@lunora/errors";const u=50,m=10,p=b=>{const{embedders:t,indexes:s,registry:g}=b,i=async()=>Promise.all(g.map(async e=>{const n=s[e.name];if(n?.describe===void 0)return{...e};try{const r=await n.describe();return{...e,dimensions:e.dimensions??r.dimensions,processedUpToMutation:r.processedUpToMutation===void 0?void 0:String(r.processedUpToMutation),vectorsCount:r.vectorCount??r.vectorsCount}}catch{return{...e}}}));return t!==void 0&&Object.keys(t).length>0?{listIndexes:i,queryIndex:async({name:e,text:n,topK:r})=>{const d=s[e];if(!Object.hasOwn(s,e)||d===void 0)throw new a("INTERNAL",`@lunora/bindings/vectors: no Vectorize binding registered for index "${e}"`);const c=t[e];if(!Object.hasOwn(t,e)||c===void 0)throw new a("INTERNAL",`@lunora/bindings/vectors: no embedder registered for index "${e}" — it lists read-only`);if(r!==void 0&&(!Number.isInteger(r)||r<1||r>u))throw new RangeError(`@lunora/bindings/vectors: topK must be an integer in [1, ${String(u)}] (got ${String(r)})`);const l=await c(n);return{matches:(await d.query(l,{returnMetadata:"all",topK:r??m})).matches.map(o=>({id:o.id,metadata:o.metadata,score:o.score}))}}}:{listIndexes:i}};export{p as createVectorAdminIntrospector};
@@ -0,0 +1 @@
1
+ import{LunoraError as b}from"@lunora/errors";import{c as w,U as h}from"./concurrent-vRmSvRpF.mjs";const a=(t,o)=>{const d=t[o];if(!Object.hasOwn(t,o)||d===void 0)throw new b("INTERNAL",`@lunora/bindings/vectors: no index registered for "${o}". Known indexes: ${Object.keys(t).join(", ")||"(none)"}`);return d},g=async t=>{const o=await t.embed(t.input);return{id:t.id,metadata:t.metadata,namespace:t.namespace,values:o}},m=100,u=50,c=1e3,y=1e3,K=t=>{if(Object.keys(t.indexes).length===0)throw new TypeError("@lunora/bindings/vectors: at least one index binding is required");return{deleteByIds:async(n,e)=>{const r=a(t.indexes,n);if(e.length>c)throw new RangeError(`@lunora/bindings/vectors: deleteByIds accepts at most ${String(c)} ids (got ${String(e.length)})`);return r.deleteByIds(e)},describe:async n=>{const e=a(t.indexes,n);if(!e.describe)throw new b("INTERNAL",`@lunora/bindings/vectors: binding for "${n}" does not implement describe()`);const r=await e.describe(),s=r.vectorCount??r.vectorsCount;return{...r,vectorCount:s,vectorsCount:s}},getByIds:async(n,e)=>{const r=a(t.indexes,n);if(e.length>c)throw new RangeError(`@lunora/bindings/vectors: getByIds accepts at most ${String(c)} ids (got ${String(e.length)})`);return r.getByIds(e)},query:async(n,e)=>{const r=a(t.indexes,n),s=e.returnValues===!0||e.returnMetadata==="all",l=s?u:m;if(e.topK!==void 0&&(!Number.isInteger(e.topK)||e.topK<1||e.topK>l)){const v=s?` (lowered to ${String(u)} because returnValues/returnMetadata:"all" is set)`:"";throw new RangeError(`@lunora/bindings/vectors: topK must be an integer in [1, ${String(l)}]${v} (got ${String(e.topK)})`)}let i;if(e.vector&&e.vector.length>0)i=e.vector;else{if(!e.embed||e.input===void 0)throw new TypeError("@lunora/bindings/vectors: query requires either `vector` or both `input` and `embed`");i=await e.embed(e.input)}return r.query(i,{filter:e.filter,namespace:e.namespace,returnMetadata:e.returnMetadata,returnValues:e.returnValues,topK:e.topK})},upsert:async(n,e)=>{const r=a(t.indexes,n),s=await g(e);return r.upsert([s])},upsertMany:async(n,e)=>{const r=a(t.indexes,n);if(e.length>y)throw new RangeError(`@lunora/bindings/vectors: upsertMany batch exceeds ${String(y)} (got ${String(e.length)}) — split across calls`);const s=await w(e,h,g);return r.upsert(s)}}};export{K as default};
@@ -18,6 +18,22 @@ declare const isSql: (value: unknown) => value is Sql;
18
18
  declare const raw: (text: string) => Sql;
19
19
  /** Resolve a `string | Sql` to its raw text. A bare string is taken as trusted SQL (callers pass identifiers/fragments here). */
20
20
  declare const toText: (value: Sql | string) => string;
21
+ /**
22
+ * Validate a table/namespace/database identifier that will be spliced into R2 SQL
23
+ * text (which has no parameter binding and no identifier quoting we can rely on).
24
+ * Accepts only dotted `\w` segments and throws otherwise, so a client-supplied
25
+ * `describe`/`showTables` argument can't inject SQL. For a genuinely dynamic
26
+ * identifier you built yourself, wrap it with {@link raw}.
27
+ */
28
+ declare const ident: (name: string) => string;
29
+ /**
30
+ * Validate a table REFERENCE for a `FROM`/`JOIN` position: a dotted identifier
31
+ * plus an optional `[AS] alias`. Broader than {@link ident} (which forbids the
32
+ * alias) but still an allowlist — no whitespace beyond the single alias, no
33
+ * punctuation — so a caller-supplied table string can't inject SQL. Use
34
+ * {@link raw} for anything more dynamic that you built yourself.
35
+ */
36
+ declare const tableRef: (ref: string) => string;
21
37
  /**
22
38
  * Render a JS value as an R2 SQL literal:
23
39
  *
@@ -408,4 +424,4 @@ export { type Condition, type OrderTerm, type OverSpec, type QueryExecutor, type
408
424
  * not tracked by Lunora live queries (see the `r2sql_outside_action` advisor
409
425
  * lint). See the README and `createR2Sql` JSDoc.
410
426
  */
411
- SelectBuilder, SetOperation, Sql, WindowExpression, WindowFunction, asc, createR2Sql, desc, fn, isSql, joinSql, lit, raw, renderOrderTerm, sql, toText };
427
+ SelectBuilder, SetOperation, Sql, WindowExpression, WindowFunction, asc, createR2Sql, desc, fn, ident, isSql, joinSql, lit, raw, renderOrderTerm, sql, tableRef, toText };
@@ -18,6 +18,22 @@ declare const isSql: (value: unknown) => value is Sql;
18
18
  declare const raw: (text: string) => Sql;
19
19
  /** Resolve a `string | Sql` to its raw text. A bare string is taken as trusted SQL (callers pass identifiers/fragments here). */
20
20
  declare const toText: (value: Sql | string) => string;
21
+ /**
22
+ * Validate a table/namespace/database identifier that will be spliced into R2 SQL
23
+ * text (which has no parameter binding and no identifier quoting we can rely on).
24
+ * Accepts only dotted `\w` segments and throws otherwise, so a client-supplied
25
+ * `describe`/`showTables` argument can't inject SQL. For a genuinely dynamic
26
+ * identifier you built yourself, wrap it with {@link raw}.
27
+ */
28
+ declare const ident: (name: string) => string;
29
+ /**
30
+ * Validate a table REFERENCE for a `FROM`/`JOIN` position: a dotted identifier
31
+ * plus an optional `[AS] alias`. Broader than {@link ident} (which forbids the
32
+ * alias) but still an allowlist — no whitespace beyond the single alias, no
33
+ * punctuation — so a caller-supplied table string can't inject SQL. Use
34
+ * {@link raw} for anything more dynamic that you built yourself.
35
+ */
36
+ declare const tableRef: (ref: string) => string;
21
37
  /**
22
38
  * Render a JS value as an R2 SQL literal:
23
39
  *
@@ -408,4 +424,4 @@ export { type Condition, type OrderTerm, type OverSpec, type QueryExecutor, type
408
424
  * not tracked by Lunora live queries (see the `r2sql_outside_action` advisor
409
425
  * lint). See the README and `createR2Sql` JSDoc.
410
426
  */
411
- SelectBuilder, SetOperation, Sql, WindowExpression, WindowFunction, asc, createR2Sql, desc, fn, isSql, joinSql, lit, raw, renderOrderTerm, sql, toText };
427
+ SelectBuilder, SetOperation, Sql, WindowExpression, WindowFunction, asc, createR2Sql, desc, fn, ident, isSql, joinSql, lit, raw, renderOrderTerm, sql, tableRef, toText };
@@ -1 +1 @@
1
- import{default as o}from"../packem_shared/SelectBuilder-DJXNSdqC.mjs";import{R2SqlError as l,createR2Sql as f}from"../packem_shared/R2SqlError-ZHgOWClB.mjs";import{asc as d,desc as i,renderOrderTerm as n}from"../packem_shared/asc-DP_WFiAE.mjs";import{default as s}from"../packem_shared/SetOperation-kiI5Wnlm.mjs";import{Sql as m,isSql as S,joinSql as q,lit as c,raw as u,sql as w,toText as E}from"../packem_shared/Sql-BfnxRway.mjs";import{WindowFunction as R,fn as T}from"../packem_shared/WindowFunction-CL4jYy2l.mjs";import{default as j}from"../packem_shared/WindowExpression-VX7EEV3h.mjs";export{l as R2SqlError,o as SelectBuilder,s as SetOperation,m as Sql,j as WindowExpression,R as WindowFunction,d as asc,f as createR2Sql,i as desc,T as fn,S as isSql,q as joinSql,c as lit,u as raw,n as renderOrderTerm,w as sql,E as toText};
1
+ import{default as o}from"../packem_shared/SelectBuilder-DJXNSdqC.mjs";import{R2SqlError as l,createR2Sql as f}from"../packem_shared/R2SqlError-ZHgOWClB.mjs";import{asc as d,desc as i,renderOrderTerm as n}from"../packem_shared/asc-DP_WFiAE.mjs";import{default as s}from"../packem_shared/SetOperation-kiI5Wnlm.mjs";import{Sql as m,ident as S,isSql as q,joinSql as c,lit as u,raw as w,sql as R,tableRef as E,toText as O}from"../packem_shared/Sql-BfnxRway.mjs";import{WindowFunction as W,fn as b}from"../packem_shared/WindowFunction-CL4jYy2l.mjs";import{default as B}from"../packem_shared/WindowExpression-VX7EEV3h.mjs";export{l as R2SqlError,o as SelectBuilder,s as SetOperation,m as Sql,B as WindowExpression,W as WindowFunction,d as asc,f as createR2Sql,i as desc,b as fn,S as ident,q as isSql,c as joinSql,u as lit,w as raw,n as renderOrderTerm,R as sql,E as tableRef,O as toText};
@@ -1 +1 @@
1
- import{createContextVectors as t,createVectorSyncHook as o}from"../packem_shared/createContextVectors-Bk6ZVCqQ.mjs";import{createVectorAdminIntrospector as a}from"../packem_shared/createVectorAdminIntrospector-1CS6sIlR.mjs";import{default as m}from"../packem_shared/createVectors-DirhBYpw.mjs";export{t as createContextVectors,a as createVectorAdminIntrospector,o as createVectorSyncHook,m as createVectors};
1
+ import{createContextVectors as t,createVectorSyncHook as o}from"../packem_shared/createContextVectors-BBJgaPoj.mjs";import{createVectorAdminIntrospector as a}from"../packem_shared/createVectorAdminIntrospector-Ct8v6PxJ.mjs";import{default as m}from"../packem_shared/createVectors-Dzv0ilKE.mjs";export{t as createContextVectors,a as createVectorAdminIntrospector,o as createVectorSyncHook,m as createVectors};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lunora/bindings",
3
- "version": "1.0.0-alpha.54",
3
+ "version": "1.0.0-alpha.56",
4
4
  "description": "Lightweight Cloudflare binding helpers for Lunora — ctx.kv, ctx.images, ctx.analytics, ctx.pipelines, ctx.vectors, ctx.r2sql — one install, per-binding subpaths",
5
5
  "keywords": [
6
6
  "analytics",
@@ -65,7 +65,7 @@
65
65
  },
66
66
  "dependencies": {
67
67
  "@lunora/errors": "1.0.0-alpha.35",
68
- "@lunora/platform": "1.0.0-alpha.27"
68
+ "@lunora/platform": "1.0.0-alpha.29"
69
69
  },
70
70
  "engines": {
71
71
  "node": "^22.15.0 || >=24.11.0"
@@ -1 +0,0 @@
1
- import{LunoraError as a}from"@lunora/errors";const u=50,m=10,x=b=>{const{embedders:n,indexes:s,registry:g}=b,i=async()=>Promise.all(g.map(async e=>{const t=s[e.name];if(t?.describe===void 0)return{...e};try{const r=await t.describe();return{...e,dimensions:e.dimensions??r.dimensions,processedUpToMutation:r.processedUpToMutation,vectorsCount:r.vectorsCount}}catch{return{...e}}}));return n!==void 0&&Object.keys(n).length>0?{listIndexes:i,queryIndex:async({name:e,text:t,topK:r})=>{const d=s[e];if(!Object.hasOwn(s,e)||d===void 0)throw new a("INTERNAL",`@lunora/bindings/vectors: no Vectorize binding registered for index "${e}"`);const c=n[e];if(!Object.hasOwn(n,e)||c===void 0)throw new a("INTERNAL",`@lunora/bindings/vectors: no embedder registered for index "${e}" — it lists read-only`);if(r!==void 0&&(!Number.isInteger(r)||r<1||r>u))throw new RangeError(`@lunora/bindings/vectors: topK must be an integer in [1, ${String(u)}] (got ${String(r)})`);const l=await c(t);return{matches:(await d.query(l,{returnMetadata:"all",topK:r??m})).matches.map(o=>({id:o.id,metadata:o.metadata,score:o.score}))}}}:{listIndexes:i}};export{x as createVectorAdminIntrospector};
@@ -1 +0,0 @@
1
- import{LunoraError as b}from"@lunora/errors";import{c as v,U as h}from"./concurrent-vRmSvRpF.mjs";const a=(r,s)=>{const d=r[s];if(!Object.hasOwn(r,s)||d===void 0)throw new b("INTERNAL",`@lunora/bindings/vectors: no index registered for "${s}". Known indexes: ${Object.keys(r).join(", ")||"(none)"}`);return d},g=async r=>{const s=await r.embed(r.input);return{id:r.id,metadata:r.metadata,namespace:r.namespace,values:s}},m=100,u=50,c=1e3,y=1e3,K=r=>{if(Object.keys(r.indexes).length===0)throw new TypeError("@lunora/bindings/vectors: at least one index binding is required");return{deleteByIds:async(t,e)=>{const n=a(r.indexes,t);if(e.length>c)throw new RangeError(`@lunora/bindings/vectors: deleteByIds accepts at most ${String(c)} ids (got ${String(e.length)})`);return n.deleteByIds(e)},describe:async t=>{const e=a(r.indexes,t);if(!e.describe)throw new b("INTERNAL",`@lunora/bindings/vectors: binding for "${t}" does not implement describe()`);return e.describe()},getByIds:async(t,e)=>{const n=a(r.indexes,t);if(e.length>c)throw new RangeError(`@lunora/bindings/vectors: getByIds accepts at most ${String(c)} ids (got ${String(e.length)})`);return n.getByIds(e)},query:async(t,e)=>{const n=a(r.indexes,t),o=e.returnValues===!0||e.returnMetadata==="all",l=o?u:m;if(e.topK!==void 0&&(!Number.isInteger(e.topK)||e.topK<1||e.topK>l)){const w=o?` (lowered to ${String(u)} because returnValues/returnMetadata:"all" is set)`:"";throw new RangeError(`@lunora/bindings/vectors: topK must be an integer in [1, ${String(l)}]${w} (got ${String(e.topK)})`)}let i;if(e.vector&&e.vector.length>0)i=e.vector;else{if(!e.embed||e.input===void 0)throw new TypeError("@lunora/bindings/vectors: query requires either `vector` or both `input` and `embed`");i=await e.embed(e.input)}return n.query(i,{filter:e.filter,namespace:e.namespace,returnMetadata:e.returnMetadata,returnValues:e.returnValues,topK:e.topK})},upsert:async(t,e)=>{const n=a(r.indexes,t),o=await g(e);return n.upsert([o])},upsertMany:async(t,e)=>{const n=a(r.indexes,t);if(e.length>y)throw new RangeError(`@lunora/bindings/vectors: upsertMany batch exceeds ${String(y)} (got ${String(e.length)}) — split across calls`);const o=await v(e,h,g);return n.upsert(o)}}};export{K as default};