@lunora/bindings 1.0.0-alpha.57 → 1.0.0-alpha.58

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.
@@ -8,12 +8,11 @@
8
8
  * (`input(stream).transform(opts).output(opts)` + `info(stream)`), not the full
9
9
  * hosted-images CRUD surface.
10
10
  *
11
- * TODO(workers-types): the 2026-06-16 optimization features the `aspect-crop`
12
- * / `scale-up` fit modes and the `upscale` param are modeled here by hand
13
- * because `@cloudflare/workers-types` (through 4.20260616.1) does not type them
14
- * yet. Re-check on the next `@cloudflare/workers-types` bump: once `ImageTransform`
15
- * carries `fit: "aspect-crop" | "scale-up"` and `upscale`, drop our hand-rolled
16
- * additions and lean on the upstream type.
11
+ * TODO(workers-types): the `aspect-crop` fit mode is modeled here by hand because
12
+ * `@cloudflare/workers-types` still does not type itchecked at the pinned
13
+ * 5.20260811.1, whose `ImageTransform` now carries `fit: "scale-up"` and `upscale`.
14
+ * Re-check on the next bump: once `ImageTransform` also carries
15
+ * `fit: "aspect-crop"`, drop our hand-rolled addition and lean on the upstream type.
17
16
  */
18
17
  /**
19
18
  * Porter-Duff compositing operation controlling how an overlay is blended onto
@@ -8,12 +8,11 @@
8
8
  * (`input(stream).transform(opts).output(opts)` + `info(stream)`), not the full
9
9
  * hosted-images CRUD surface.
10
10
  *
11
- * TODO(workers-types): the 2026-06-16 optimization features the `aspect-crop`
12
- * / `scale-up` fit modes and the `upscale` param are modeled here by hand
13
- * because `@cloudflare/workers-types` (through 4.20260616.1) does not type them
14
- * yet. Re-check on the next `@cloudflare/workers-types` bump: once `ImageTransform`
15
- * carries `fit: "aspect-crop" | "scale-up"` and `upscale`, drop our hand-rolled
16
- * additions and lean on the upstream type.
11
+ * TODO(workers-types): the `aspect-crop` fit mode is modeled here by hand because
12
+ * `@cloudflare/workers-types` still does not type itchecked at the pinned
13
+ * 5.20260811.1, whose `ImageTransform` now carries `fit: "scale-up"` and `upscale`.
14
+ * Re-check on the next bump: once `ImageTransform` also carries
15
+ * `fit: "aspect-crop"`, drop our hand-rolled addition and lean on the upstream type.
17
16
  */
18
17
  /**
19
18
  * Porter-Duff compositing operation controlling how an overlay is blended onto
@@ -1,6 +1,6 @@
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 x,U as I}from"./concurrent-vRmSvRpF.mjs";const B=(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},C=(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}},v=new Set,w=s=>{v.has(s)||(v.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
5
5
  namespace filtering is mandatory for multi-tenant apps. Single-tenant apps that
6
- legitimately have no tenant key suppress this via { allowSharedNamespace: true }.`))},I=(s,c)=>{const n={};for(const d of c)d in s&&(n[d]=s[d]);return n},D=s=>{const{allowSharedNamespace:c,namespace:n,schema:d,vectors:l}=s;return async o=>{const t=d.tables[o.table]?.vectorIndexes??[],a=Object.entries(d.vectorIndexes).filter(([,e])=>e.table===o.table);if(t.length===0&&a.length===0)return;const i=[...t.map(e=>e.name),...a.map(([e])=>e)];if(o.op==="delete"){await Promise.all(i.map(e=>l.deleteByIds(e,[o.id])));return}const r=o.doc;if(!r)return;const m=t.map(e=>({index:e,value:x(r,e.field)})),u=m.filter(e=>e.value!==void 0&&e.value!==null),y=m.filter(e=>e.value===void 0||e.value===null);for(const{index:e,value:p}of u)if(typeof p!="string")throw new TypeError(`@lunora/bindings/vectors: inline index "${e.name}" expects a string source at "${e.field}" on table "${o.table}" (got ${typeof p}); use a standalone defineVectorIndex with a select() to derive text from non-string columns`);const w=[...y.map(e=>async()=>{await l.deleteByIds(e.index.name,[o.id])}),...u.map(e=>async()=>{!c&&n===void 0&&v(e.index.name),await l.upsert(e.index.name,{embed:e.index.embed,id:o.id,input:e.value,metadata:e.index.metadata?I(r,e.index.metadata):void 0,namespace:n})}),...a.map(([e,p])=>async()=>{!c&&n===void 0&&v(e),await l.upsert(e,{embed:p.embed,id:o.id,input:p.select(r),metadata:p.metadata?.(r),namespace:n})})];try{await b(w,g,async e=>e())}catch(e){throw await Promise.allSettled(i.map(p=>l.deleteByIds(p,[o.id]))),e}}};export{S as createContextVectors,D as createVectorSyncHook};
6
+ legitimately have no tenant key suppress this via { allowSharedNamespace: true }.`))},S=(s,c)=>{const n={};for(const d of c)d in s&&(n[d]=s[d]);return n},E=s=>{const{allowSharedNamespace:c,namespace:n,schema:d,vectors:l}=s;return async o=>{const t=d.tables[o.table]?.vectorIndexes??[],a=Object.entries(d.vectorIndexes).filter(([,e])=>e.table===o.table);if(t.length===0&&a.length===0)return;const i=[...t.map(e=>e.name),...a.map(([e])=>e)];if(o.op==="delete"){await Promise.all(i.map(e=>l.deleteByIds(e,[o.id])));return}const r=o.doc;if(!r)return;const m=t.map(e=>({index:e,value:B(r,e.field)})),u=m.filter(e=>e.value!==void 0&&e.value!==null),y=m.filter(e=>e.value===void 0||e.value===null);for(const{index:e,value:p}of u)if(typeof p!="string")throw new TypeError(`@lunora/bindings/vectors: inline index "${e.name}" expects a string source at "${e.field}" on table "${o.table}" (got ${typeof p}); use a standalone defineVectorIndex with a select() to derive text from non-string columns`);const f=[],b=[...y.map(e=>async()=>{await l.deleteByIds(e.index.name,[o.id])}),...u.map(e=>async()=>{!c&&n===void 0&&w(e.index.name),await l.upsert(e.index.name,{embed:e.index.embed,id:o.id,input:e.value,metadata:e.index.metadata?S(r,e.index.metadata):void 0,namespace:n}),f.push(e.index.name)}),...a.map(([e,p])=>async()=>{!c&&n===void 0&&w(e),await l.upsert(e,{embed:p.embed,id:o.id,input:p.select(r),metadata:p.metadata?.(r),namespace:n}),f.push(e)})];try{await x(b,I,async e=>e())}catch(e){const p=o.op==="insert"?i:f;throw await Promise.allSettled(p.map(g=>l.deleteByIds(g,[o.id]))),e}}};export{C as createContextVectors,E as createVectorSyncHook};
@@ -260,9 +260,11 @@ interface SchemaLike {
260
260
  * Vectorize diverged. We mitigate, not eliminate: upserts/deletes are
261
261
  * idempotent (keyed by row id), so a retry of the same write converges; and on
262
262
  * a fan-out failure we attempt a best-effort compensating delete of the row's
263
- * id from every affected index before re-throwing. A delete after a failed
264
- * upsert can itself fail this is best-effort, the authoritative recovery is
265
- * re-running the (idempotent) write.
263
+ * id before re-throwing — from every index of the table on an insert, and on an
264
+ * update from the indexes this fan-out actually wrote, since the rollback leaves
265
+ * the untouched ones holding the prior row's still-correct vector. A delete
266
+ * after a failed upsert can itself fail — this is best-effort, the authoritative
267
+ * recovery is re-running the (idempotent) write.
266
268
  */
267
269
  declare const createVectorSyncHook: (options: {
268
270
  allowSharedNamespace?: boolean;
@@ -260,9 +260,11 @@ interface SchemaLike {
260
260
  * Vectorize diverged. We mitigate, not eliminate: upserts/deletes are
261
261
  * idempotent (keyed by row id), so a retry of the same write converges; and on
262
262
  * a fan-out failure we attempt a best-effort compensating delete of the row's
263
- * id from every affected index before re-throwing. A delete after a failed
264
- * upsert can itself fail this is best-effort, the authoritative recovery is
265
- * re-running the (idempotent) write.
263
+ * id before re-throwing — from every index of the table on an insert, and on an
264
+ * update from the indexes this fan-out actually wrote, since the rollback leaves
265
+ * the untouched ones holding the prior row's still-correct vector. A delete
266
+ * after a failed upsert can itself fail — this is best-effort, the authoritative
267
+ * recovery is re-running the (idempotent) write.
266
268
  */
267
269
  declare const createVectorSyncHook: (options: {
268
270
  allowSharedNamespace?: boolean;
@@ -1 +1 @@
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};
1
+ import{createContextVectors as t,createVectorSyncHook as o}from"../packem_shared/createContextVectors-BcfM30uc.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.57",
3
+ "version": "1.0.0-alpha.58",
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",