@lunora/bindings 1.0.0-alpha.10 → 1.0.0-alpha.12

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 (45) hide show
  1. package/dist/analytics/index.mjs +1 -2
  2. package/dist/images/index.mjs +1 -3
  3. package/dist/kv/index.mjs +1 -2
  4. package/dist/packem_shared/AnalyticsSqlError-B-JcsUhX.mjs +1 -0
  5. package/dist/packem_shared/R2SqlError-Uaz0RJTR.mjs +1 -0
  6. package/dist/packem_shared/SelectBuilder-WMBQ2b4q.mjs +1 -0
  7. package/dist/packem_shared/SetOperation-BrzMB1Tb.mjs +1 -0
  8. package/dist/packem_shared/Sql-CwhZl1Q5.mjs +1 -0
  9. package/dist/packem_shared/WindowExpression-CxCuEy8V.mjs +1 -0
  10. package/dist/packem_shared/WindowFunction-rzl4CzYE.mjs +1 -0
  11. package/dist/packem_shared/asc-BsbdtIQU.mjs +1 -0
  12. package/dist/packem_shared/buildImageDeliveryUrl-eARoj3MG.mjs +1 -0
  13. package/dist/packem_shared/buildSignedImageUrl-Bpu3Hs42.mjs +4 -0
  14. package/dist/packem_shared/concurrent-DMFQCILU.mjs +1 -0
  15. package/dist/packem_shared/createAnalytics-HRPCzT1M.mjs +1 -0
  16. package/dist/packem_shared/createContextVectors-HVMMJ-88.mjs +6 -0
  17. package/dist/packem_shared/createImages-TW6ircG2.mjs +1 -0
  18. package/dist/packem_shared/createKv-CspEaB58.mjs +1 -0
  19. package/dist/packem_shared/createKvIntrospector-Bz0nqUjD.mjs +1 -0
  20. package/dist/packem_shared/createPipelines-n0Bf_p8Y.mjs +1 -0
  21. package/dist/packem_shared/createVectorAdminIntrospector-B9Yt09yj.mjs +1 -0
  22. package/dist/packem_shared/createVectors-jb8fAY6R.mjs +1 -0
  23. package/dist/pipelines/index.mjs +1 -1
  24. package/dist/r2sql/index.mjs +1 -7
  25. package/dist/vectors/index.mjs +1 -3
  26. package/package.json +2 -2
  27. package/dist/packem_shared/AnalyticsSqlError-C2nz3jpH.mjs +0 -41
  28. package/dist/packem_shared/R2SqlError-drPKSCZ3.mjs +0 -65
  29. package/dist/packem_shared/SelectBuilder-BOqJQHEv.mjs +0 -168
  30. package/dist/packem_shared/SetOperation-DmPgUL8W.mjs +0 -81
  31. package/dist/packem_shared/Sql-B3zq2YGx.mjs +0 -74
  32. package/dist/packem_shared/WindowExpression-BT_uA6g1.mjs +0 -44
  33. package/dist/packem_shared/WindowFunction-DrnuZUF6.mjs +0 -82
  34. package/dist/packem_shared/asc-DZbQCxh1.mjs +0 -16
  35. package/dist/packem_shared/buildImageDeliveryUrl-qZ7XbqTL.mjs +0 -35
  36. package/dist/packem_shared/buildSignedImageUrl-DNUFfyGP.mjs +0 -130
  37. package/dist/packem_shared/concurrent-CkCEVwqP.mjs +0 -39
  38. package/dist/packem_shared/createAnalytics-CEEI69o9.mjs +0 -57
  39. package/dist/packem_shared/createContextVectors-DwZtnPeC.mjs +0 -140
  40. package/dist/packem_shared/createImages-BzRnsz3H.mjs +0 -85
  41. package/dist/packem_shared/createKv-C8Iyu5hD.mjs +0 -145
  42. package/dist/packem_shared/createKvIntrospector-Byk4GfsY.mjs +0 -77
  43. package/dist/packem_shared/createPipelines-CfyJ6VGu.mjs +0 -10
  44. package/dist/packem_shared/createVectorAdminIntrospector-DuSvcBa5.mjs +0 -53
  45. package/dist/packem_shared/createVectors-CTSrctiK.mjs +0 -95
@@ -1,2 +1 @@
1
- export { createAnalytics } from '../packem_shared/createAnalytics-CEEI69o9.mjs';
2
- export { AnalyticsSqlError, createAnalyticsSqlClient } from '../packem_shared/AnalyticsSqlError-C2nz3jpH.mjs';
1
+ import{createAnalytics as e}from"../packem_shared/createAnalytics-HRPCzT1M.mjs";import{AnalyticsSqlError as a,createAnalyticsSqlClient as c}from"../packem_shared/AnalyticsSqlError-B-JcsUhX.mjs";export{a as AnalyticsSqlError,e as createAnalytics,c as createAnalyticsSqlClient};
@@ -1,3 +1 @@
1
- export { createImages } from '../packem_shared/createImages-BzRnsz3H.mjs';
2
- export { buildImageDeliveryUrl } from '../packem_shared/buildImageDeliveryUrl-qZ7XbqTL.mjs';
3
- export { buildSignedImageUrl, verifySignedImageUrl } from '../packem_shared/buildSignedImageUrl-DNUFfyGP.mjs';
1
+ import{createImages as m}from"../packem_shared/createImages-TW6ircG2.mjs";import{buildImageDeliveryUrl as i}from"../packem_shared/buildImageDeliveryUrl-eARoj3MG.mjs";import{buildSignedImageUrl as o,verifySignedImageUrl as a}from"../packem_shared/buildSignedImageUrl-Bpu3Hs42.mjs";export{i as buildImageDeliveryUrl,o as buildSignedImageUrl,m as createImages,a as verifySignedImageUrl};
package/dist/kv/index.mjs CHANGED
@@ -1,2 +1 @@
1
- export { createKv, scopeKey } from '../packem_shared/createKv-C8Iyu5hD.mjs';
2
- export { createKvIntrospector, createKvIntrospectorFromEnv } from '../packem_shared/createKvIntrospector-Byk4GfsY.mjs';
1
+ import{createKv as o,scopeKey as t}from"../packem_shared/createKv-CspEaB58.mjs";import{createKvIntrospector as p,createKvIntrospectorFromEnv as v}from"../packem_shared/createKvIntrospector-Bz0nqUjD.mjs";export{o as createKv,p as createKvIntrospector,v as createKvIntrospectorFromEnv,t as scopeKey};
@@ -0,0 +1 @@
1
+ import{LunoraError as l}from"@lunora/errors";const u="https://api.cloudflare.com/client/v4/accounts";class c extends l{constructor(e,o){super("ANALYTICS_SQL_ERROR",`Analytics Engine SQL API returned ${String(e)}: ${o}`,{name:"AnalyticsSqlError",status:e})}}const d=n=>{const e=n.fetch??globalThis.fetch,o=`${u}/${encodeURIComponent(n.accountId)}/analytics_engine/sql`;return{query:async i=>{const t=await e(o,{body:i,headers:{Authorization:`Bearer ${n.apiToken}`,"Content-Type":"text/plain"},method:"POST"});if(!t.ok)throw new c(t.status,await t.text());let a;try{a=await t.json()}catch{throw new c(t.status,"Analytics Engine SQL API returned a non-JSON body.")}const r=a,s=r.data??[];return{columns:r.meta??[],rowCount:r.rows??s.length,rows:s}}}};export{c as AnalyticsSqlError,d as createAnalyticsSqlClient};
@@ -0,0 +1 @@
1
+ import{LunoraError as h}from"@lunora/errors";import m from"./SelectBuilder-WMBQ2b4q.mjs";import{ident as l,toText as S}from"./Sql-CwhZl1Q5.mjs";const p="https://api.sql.cloudflarestorage.com/api/v1/accounts",w=t=>t[0]===void 0?[]:Object.keys(t[0]).map(e=>({name:e}));class i extends h{constructor(e,a){super("R2_SQL_ERROR",`R2 SQL query failed (${String(e)}): ${a}`,{name:"R2SqlError",status:e})}}const $=t=>{const e=t.fetch??globalThis.fetch,a=`${t.endpoint??p}/${encodeURIComponent(t.accountId)}/r2-sql/query/${encodeURIComponent(t.bucket)}`,d=`${t.accountId}_${t.bucket}`,n=async o=>{const r=await e(a,{body:JSON.stringify({query:o,warehouse:d}),headers:{Authorization:`Bearer ${t.apiToken}`,"Content-Type":"application/json"},method:"POST"});if(!r.ok)throw new i(r.status,await r.text());let u;try{u=await r.json()}catch{throw new i(r.status,"R2 SQL returned a non-JSON body.")}const s=u;if(s.success===!1||s.errors!==void 0&&s.errors.length>0)throw new i(r.status,JSON.stringify(s.errors??s));const c=s.result?.rows??[];return{columns:s.result?.schema??w(c),rowCount:c.length,rows:c}};return{describe:async o=>n(`DESCRIBE ${l(o)}`),explain:async(o,r)=>n(`EXPLAIN ${r?.format==="json"?"FORMAT JSON ":""}${S(o)}`),from:o=>new m(n,o),query:async o=>n(S(o)),showDatabases:async()=>n("SHOW DATABASES"),showTables:async o=>n(`SHOW TABLES IN ${l(o)}`)}};export{i as R2SqlError,$ as createR2Sql};
@@ -0,0 +1 @@
1
+ import{renderOrderTerm as o}from"./asc-BsbdtIQU.mjs";import h from"./SetOperation-BrzMB1Tb.mjs";import{tableRef as s,toText as e,assertLimit as u,lit as a}from"./Sql-CwhZl1Q5.mjs";const n={cross:"CROSS JOIN",full:"FULL OUTER JOIN",inner:"INNER JOIN",left:"LEFT JOIN",right:"RIGHT JOIN"};class I{exec;table;selectItems=[];distinctFlag=!1;distinctOnItems=[];joins=[];whereConditions=[];groupByItems=[];havingConditions=[];qualifyCondition;orderByItems=[];limitValue;constructor(t,i){this.exec=t,this.table=s(i)}select(...t){return this.selectItems.push(...t.map(i=>e(i))),this}distinct(){return this.distinctFlag=!0,this}distinctOn(...t){return this.distinctOnItems.push(...t.map(i=>e(i))),this}innerJoin(t,i){return this.addJoin("inner",t,i)}leftJoin(t,i){return this.addJoin("left",t,i)}rightJoin(t,i){return this.addJoin("right",t,i)}fullJoin(t,i){return this.addJoin("full",t,i)}crossJoin(t){return this.addJoin("cross",t)}where(...t){return this.whereConditions.push(...t.map(i=>e(i))),this}groupBy(...t){return this.groupByItems.push(...t.map(i=>e(i))),this}having(...t){return this.havingConditions.push(...t.map(i=>e(i))),this}qualify(t){return this.qualifyCondition=e(t),this}orderBy(...t){return this.orderByItems.push(...t.map(i=>o(i))),this}limit(t){return u(t),this.limitValue=t,this}returns(){return this}union(t){return this.setOperation("UNION",t)}unionAll(t){return this.setOperation("UNION ALL",t)}intersect(t){return this.setOperation("INTERSECT",t)}except(t){return this.setOperation("EXCEPT",t)}get needsWrapForSetOperation(){return this.orderByItems.length>0||this.limitValue!==void 0}toSQL(){const t=[`${this.renderHead()} ${this.selectItems.length>0?this.selectItems.join(", "):"*"}`,`FROM ${this.table}`];for(const i of this.joins)t.push(i.on===void 0?`${n[i.kind]} ${i.table}`:`${n[i.kind]} ${i.table} ON ${e(i.on)}`);return this.whereConditions.length>0&&t.push(`WHERE ${this.whereConditions.join(" AND ")}`),this.groupByItems.length>0&&t.push(`GROUP BY ${this.groupByItems.join(", ")}`),this.havingConditions.length>0&&t.push(`HAVING ${this.havingConditions.join(" AND ")}`),this.qualifyCondition!==void 0&&t.push(`QUALIFY ${this.qualifyCondition}`),this.orderByItems.length>0&&t.push(`ORDER BY ${this.orderByItems.join(", ")}`),this.limitValue!==void 0&&t.push(`LIMIT ${a(this.limitValue)}`),t.join(" ")}async run(){return this.exec(this.toSQL())}renderHead(){return this.distinctOnItems.length>0?`SELECT DISTINCT ON (${this.distinctOnItems.join(", ")})`:this.distinctFlag?"SELECT DISTINCT":"SELECT"}addJoin(t,i,r){return this.joins.push({kind:t,on:r,table:s(i)}),this}setOperation(t,i){return new h(this.exec,[{query:this},{operator:t,query:i}])}}export{I as default};
@@ -0,0 +1 @@
1
+ import{renderOrderTerm as o}from"./asc-BsbdtIQU.mjs";import{assertLimit as n,lit as u}from"./Sql-CwhZl1Q5.mjs";const h=e=>{const t=e.toSQL();return e.needsWrapForSetOperation===!0?`(${t})`:t};class d{needsWrapForSetOperation=!0;exec;members;orderByItems=[];limitValue;constructor(t,r){this.exec=t,this.members=r}union(t){return this.add("UNION",t)}unionAll(t){return this.add("UNION ALL",t)}intersect(t){return this.add("INTERSECT",t)}except(t){return this.add("EXCEPT",t)}orderBy(...t){return this.orderByItems.push(...t.map(r=>o(r))),this}limit(t){return n(t),this.limitValue=t,this}returns(){return this}toSQL(){const t=this.members.map(s=>{const i=h(s.query);return s.operator===void 0?i:`${s.operator} ${i}`}).join(" "),r=[];return this.orderByItems.length>0&&r.push(`ORDER BY ${this.orderByItems.join(", ")}`),this.limitValue!==void 0&&r.push(`LIMIT ${u(this.limitValue)}`),r.length>0?`${t} ${r.join(" ")}`:t}async run(){return this.exec(this.toSQL())}add(t,r){return this.members.push({operator:t,query:r}),this}}export{d as default};
@@ -0,0 +1 @@
1
+ const a=e=>`'${e.replaceAll("'","''")}'`,f=/^\w+(?:\.\w+)*$/,p=/^\w+(?:\.\w+)*(?:\s+(?:as\s+)?\w+)?$/i;class t{text;constructor(r){this.text=r}toString(){return this.text}}const o=e=>e instanceof t,u=e=>new t(e),w=e=>o(e)?e.text:e,y=e=>{if(typeof e!="string"||!f.test(e))throw new TypeError(`r2sql: invalid identifier ${JSON.stringify(e)} — expected dotted [A-Za-z0-9_] segments (e.g. "namespace.table").`);return e},g=e=>{if(typeof e!="string"||!p.test(e))throw new TypeError(`r2sql: invalid table reference ${JSON.stringify(e)} — expected "namespace.table" with an optional "[AS] alias".`);return e},s=e=>{if(e==null)return"NULL";if(typeof e=="boolean")return e?"true":"false";if(typeof e=="bigint")return e.toString();if(typeof e=="number"){if(!Number.isFinite(e))throw new TypeError(`r2sql: cannot inline a non-finite number (${String(e)}) as a SQL literal.`);return String(e)}if(typeof e=="string")return a(e);if(e instanceof Date)return a(e.toISOString());if(Array.isArray(e)){if(e.length===0)throw new TypeError("r2sql: cannot inline an empty array — `IN ()` is not valid SQL. Guard the empty case before building the query.");return`(${e.map(r=>s(r)).join(", ")})`}throw new TypeError(`r2sql: cannot inline a value of type ${typeof e} as a SQL literal. Wrap trusted SQL with raw(), or pass a primitive/Date/array.`)},c=(e,...r)=>{let n=e[0]??"";for(const[l,i]of r.entries())n+=o(i)?i.text:s(i),n+=e[l+1]??"";return new t(n)},S=(e,r)=>new t(e.map(n=>w(n)).join(r)),m=e=>{if(!Number.isInteger(e)||e<1||e>1e4)throw new RangeError(`r2sql: limit must be an integer between 1 and ${String(1e4)} (got ${String(e)}).`)};export{t as Sql,m as assertLimit,y as ident,o as isSql,S as joinSql,s as lit,u as raw,c as sql,g as tableRef,w as toText};
@@ -0,0 +1 @@
1
+ import{Sql as r,lit as s}from"./Sql-CwhZl1Q5.mjs";const n=/^[A-Z_][\w$]*$/i,a=t=>{if(!n.test(t))throw new TypeError(`r2sql: invalid identifier ${JSON.stringify(t)} — expected a simple SQL name (letters, digits, underscore).`);return t};let o=class extends r{as(e){return new r(`${this.text} AS ${a(e)}`)}between(e,i){return new r(`${this.text} BETWEEN ${s(e)} AND ${s(i)}`)}eq(e){return this.compare("=",e)}gt(e){return this.compare(">",e)}gte(e){return this.compare(">=",e)}lt(e){return this.compare("<",e)}lte(e){return this.compare("<=",e)}compare(e,i){return new r(`${this.text} ${e} ${s(i)}`)}};export{o as default};
@@ -0,0 +1 @@
1
+ import{renderOrderTerm as m}from"./asc-BsbdtIQU.mjs";import{lit as n,toText as o}from"./Sql-CwhZl1Q5.mjs";import u from"./WindowExpression-CxCuEy8V.mjs";const l=r=>r===void 0?[]:Array.isArray(r)?r:[r],c=r=>{const e=[],a=l(r.partitionBy).map(s=>o(s));a.length>0&&e.push(`PARTITION BY ${a.join(", ")}`);const i=l(r.orderBy).map(s=>m(s));return i.length>0&&e.push(`ORDER BY ${i.join(", ")}`),r.frame!==void 0&&r.frame.length>0&&e.push(r.frame),`OVER (${e.join(" ")})`},$=(r,e,a)=>{const i=[o(r)];return e!==void 0&&i.push(n(e)),a!==void 0&&i.push(n(a)),i.join(", ")};class p{callText;constructor(e){this.callText=e}over(e={}){return new u(`${this.callText} ${c(e)}`)}}const t=r=>new p(r),R={avg:r=>t(`AVG(${o(r)})`),count:r=>t(`COUNT(${r===void 0?"*":o(r)})`),cumeDist:()=>t("CUME_DIST()"),denseRank:()=>t("DENSE_RANK()"),firstValue:r=>t(`FIRST_VALUE(${o(r)})`),lag:(r,e,a)=>t(`LAG(${$(r,e,a)})`),lastValue:r=>t(`LAST_VALUE(${o(r)})`),lead:(r,e,a)=>t(`LEAD(${$(r,e,a)})`),max:r=>t(`MAX(${o(r)})`),min:r=>t(`MIN(${o(r)})`),nthValue:(r,e)=>t(`NTH_VALUE(${o(r)}, ${n(e)})`),ntile:r=>t(`NTILE(${n(r)})`),percentRank:()=>t("PERCENT_RANK()"),rank:()=>t("RANK()"),rowNumber:()=>t("ROW_NUMBER()"),sum:r=>t(`SUM(${o(r)})`)};export{p as WindowFunction,R as fn};
@@ -0,0 +1 @@
1
+ import{Sql as t,toText as r}from"./Sql-CwhZl1Q5.mjs";const d=e=>({dir:"ASC",expr:e}),i=e=>({dir:"DESC",expr:e}),p=e=>typeof e=="string"||e instanceof t?r(e):`${r(e.expr)} ${e.dir}`;export{d as asc,i as desc,p as renderOrderTerm};
@@ -0,0 +1 @@
1
+ import{LunoraError as a}from"@lunora/errors";const s=/^[a-z][a-z\d+\-.]*:\/\//i,c=[",","=","#","?","/"],d=e=>e.endsWith("/")?e.slice(0,-1):e,m=e=>e.startsWith("/")?e.slice(1):e,l=e=>Object.entries(e).filter(([,r])=>r!==void 0&&(typeof r=="string"||typeof r=="number")).map(([r,i])=>{const t=String(i),n=c.find(o=>t.includes(o));if(n!==void 0)throw new a("INTERNAL",`@lunora/bindings/images: transform option \`${r}\` value \`${t}\` contains a \`${n}\`, which the /cdn-cgi/image/ option path cannot represent (\`,\`/\`=\` are the option/key-value separators; \`#\`/\`?\`/\`/\` are URL-structural). Percent-encode the value — for colors use \`%23RRGGBB\`, not \`#RRGGBB\` or \`rgb(r,g,b)\`.`);return`${r}=${t}`}).join(","),g=e=>e.split("/").map(r=>encodeURIComponent(r)).join("/"),p=e=>{const r=d(e.baseUrl);if(e.imageId!==void 0){const o=e.variant??"public";return`${r}/${encodeURIComponent(e.imageId)}/${encodeURIComponent(o)}`}if(e.key===void 0)throw new a("INTERNAL","@lunora/bindings/images: buildImageDeliveryUrl requires either `imageId` or `key`");const i=e.transform===void 0?"":l(e.transform),t=s.test(e.key)?e.key:`/${g(m(e.key))}`,n=i===""?"/cdn-cgi/image":`/cdn-cgi/image/${i}`;return`${r}${n}${t.startsWith("/")?t:`/${t}`}`};export{p as buildImageDeliveryUrl};
@@ -0,0 +1,4 @@
1
+ const w=(e,r)=>{if(e.size<r)return;const t=e.keys().next().value;t!==void 0&&e.delete(t)},m=new TextEncoder,u=10080*60,$=/^[a-z][a-z0-9+\-.]*:\/\//i,v=e=>{const r=String.fromCodePoint(...e);return btoa(r).replaceAll("+","-").replaceAll("/","_").replaceAll("=","")},U=e=>{const r=e.replaceAll("-","+").replaceAll("_","/")+"===".slice((e.length+3)%4),t=atob(r),n=new Uint8Array(t.length);for(let a=0;a<t.length;a+=1)n[a]=t.codePointAt(a)??0;return n},x=64,p=new Map,f=async e=>{const r=p.get(e);if(r)return r;w(p,x);const t=crypto.subtle.importKey("raw",m.encode(e),{hash:"SHA-256",name:"HMAC"},!1,["sign","verify"]);return p.set(e,t),t},g=e=>{try{return new URL(e).host}catch{return e.replace($,"").split("/")[0]??""}},A=async(e,r)=>{const t=await f(e),n=await crypto.subtle.sign("HMAC",t,m.encode(r));return v(new Uint8Array(n))},S=async(e,r,t)=>{const n=await f(e);return crypto.subtle.verify("HMAC",n,t,m.encode(r))},y=/^\//,I=e=>e===void 0?"":Object.entries(e).filter(([,r])=>r!==void 0).toSorted(([r],[t])=>(r>t?1:0)-(r<t?1:0)).map(([r,t])=>`${r}=${typeof t=="object"?JSON.stringify(t):String(t)}`).join("&"),h=(e,r,t,n)=>`${e.toLowerCase()}
2
+ ${r}
3
+ ${String(t)}
4
+ ${n}`,R=e=>e.split("/").map(r=>encodeURIComponent(r)).join("/"),C=async e=>{const r=e.expiresInSeconds??3600;if(!Number.isFinite(r)||r<=0)throw new TypeError("@lunora/bindings/images: expiresInSeconds must be a positive finite number");if(r>u)throw new TypeError(`@lunora/bindings/images: expiresInSeconds must not exceed ${String(u)} (7 days)`);let t="";try{t=new URL(e.baseUrl).pathname}catch{}if(t!==""&&t!=="/")throw new TypeError(`@lunora/bindings/images: baseUrl must not carry a path ("${t}") — the key is verified from the full URL pathname, so a subpath base would make every signed URL fail verification`);const n=Math.floor(Date.now()/1e3)+r,a=g(e.baseUrl),s=I(e.transform),o=e.key.replace(y,""),i=await A(e.secret,h(a,o,n,s)),l=e.baseUrl.endsWith("/")?e.baseUrl.slice(0,-1):e.baseUrl,c=R(o),d=s===""?"":`&t=${encodeURIComponent(s)}`;return`${l}/${c}?exp=${String(n)}&sig=${i}${d}`},L=async(e,r,t)=>{let n;try{n=e instanceof URL?e:new URL(e)}catch{return{reason:"malformed",valid:!1}}const a=n.searchParams.get("exp"),s=a===null?Number.NaN:Number(a),o=n.searchParams.get("sig"),i=n.searchParams.get("t")??"";if(!o||!Number.isInteger(s))return{reason:"malformed",valid:!1};if(s<Math.floor(Date.now()/1e3))return{reason:"expired",valid:!1};let l,c;try{l=n.pathname.replace(y,"").split("/").map(b=>decodeURIComponent(b)).join("/"),c=U(o)}catch{return{reason:"malformed",valid:!1}}const d=t?.expectedHost===void 0?n.host:g(t.expectedHost);return await S(r,h(d,l,s,i),c)?{key:l,transform:i===""?void 0:i,valid:!0}:{reason:"bad_signature",valid:!1}};export{C as buildSignedImageUrl,L as verifySignedImageUrl};
@@ -0,0 +1 @@
1
+ const i=8,u=async(t,o,s)=>{if(t.length===0)return[];const h=Math.max(1,Math.min(o,t.length)),a=Array.from({length:t.length});let e=0,n=!1,c;const l=Array.from({length:h},async()=>{for(;;){if(n)return;const r=e;if(e+=1,r>=t.length)return;try{a[r]=await s(t[r],r)}catch(f){n||(n=!0,c=f);return}}});if(await Promise.all(l),n)throw c;return a};export{i as U,u as c};
@@ -0,0 +1 @@
1
+ const f=new TextEncoder,d=e=>e===null?0:typeof e=="string"?f.encode(e).length:e.byteLength,l=(e,t,n)=>{if(t>n)throw new RangeError(`@lunora/bindings/analytics: a data point may carry at most ${String(n)} ${e} (got ${String(t)}).`)},c=(e,t,n)=>{if(t>n)throw new RangeError(`@lunora/bindings/analytics: a data point's ${e} may total at most ${String(n)} bytes (got ${String(t)}).`)},p=e=>{const t=n=>{l("blobs",n.blobs?.length??0,20),l("doubles",n.doubles?.length??0,20),l("indexes",n.indexes?.length??0,1);const o=(n.blobs??[]).reduce((r,s)=>r+d(s),0);c("blobs",o,16384);for(const r of n.indexes??[])c("index",d(r),96);e.writeDataPoint(n)};return{track:(n,o={})=>{const r=Object.entries(o.dimensions??{}),s=Object.entries(o.metrics??{}),b=[n,...r.map(([,i])=>i)],g=s.map(([,i])=>i),m=o.index===void 0?[]:[o.index];t({blobs:b,doubles:g,indexes:m});const u=r.map(([i],a)=>({column:`blob${String(a+2)}`,field:i})),x=s.map(([i],a)=>({column:`double${String(a+1)}`,field:i})),y=o.index===void 0?null:{column:"index1",field:"index"};return{dimensions:u,index:y,metrics:x,name:n}},writeDataPoint:t}};export{p as createAnalytics};
@@ -0,0 +1,6 @@
1
+ import{c as w,U as b}from"./concurrent-DMFQCILU.mjs";const x=(n,d)=>{if(!d.includes("."))return n[d];let t=n;for(const a of d.split(".")){if(t===null||typeof t!="object"||Array.isArray(t))return;t=t[a]}return t},B=n=>{const d=async(t,a)=>{await n.upsert(t,{embed:a.embed,id:a.id,input:a.input,metadata:a.metadata,namespace:a.namespace})};return{deleteByIds:async(t,a)=>{await n.deleteByIds(t,a)},getByIds:async(t,a)=>(await n.getByIds(t,a)).map(i=>({id:i.id,metadata:i.metadata,values:i.values})),query:async(t,a)=>{const i=await n.query(t,{embed:a.embed,filter:a.filter,input:a.input,namespace:a.namespace,returnMetadata:a.returnMetadata??"indexed",topK:a.topK,vector:a.vector});return{count:i.count,matches:i.matches.map(s=>({id:s.id,metadata:s.metadata,score:s.score}))}},upsert:d,upsertNow:d}},y=new Set,v=n=>{y.has(n)||(y.add(n),console.warn(`[@lunora/bindings/vectors] index "${n}" syncs vectors without a namespace — in a
2
+ multi-tenant/sharded app this exposes one tenant's vectors (and any captured
3
+ metadata) to every other tenant, since Vectorize indexes are account-global.
4
+ Pass \`namespace\` (the shard/tenant key) on both write and query — query-side
5
+ namespace filtering is mandatory for multi-tenant apps. Single-tenant apps that
6
+ legitimately have no tenant key suppress this via { allowSharedNamespace: true }.`))},g=(n,d)=>{const t={};for(const a of d)a in n&&(t[a]=n[a]);return t},S=n=>{const{allowSharedNamespace:d,namespace:t,schema:a,vectors:i}=n;return async s=>{const c=a.tables[s.table]?.vectorIndexes??[],l=Object.entries(a.vectorIndexes).filter(([,e])=>e.table===s.table);if(c.length===0&&l.length===0)return;const m=[...c.map(e=>e.name),...l.map(([e])=>e)];if(s.op==="delete"){await Promise.all(m.map(e=>i.deleteByIds(e,[s.id])));return}const r=s.doc;if(!r)return;const u=c.map(e=>({index:e,value:x(r,e.field)})),p=u.filter(e=>e.value!==void 0&&e.value!==null),f=u.filter(e=>e.value===void 0||e.value===null);for(const{index:e,value:o}of p)if(typeof o!="string")throw new TypeError(`@lunora/bindings/vectors: inline index "${e.name}" expects a string source at "${e.field}" on table "${s.table}" (got ${typeof o}); use a standalone defineVectorIndex with a select() to derive text from non-string columns`);const h=[...f.map(e=>async()=>{await i.deleteByIds(e.index.name,[s.id])}),...p.map(e=>async()=>{!d&&t===void 0&&v(e.index.name),await i.upsert(e.index.name,{embed:e.index.embed,id:s.id,input:e.value,metadata:e.index.metadata?g(r,e.index.metadata):void 0,namespace:t})}),...l.map(([e,o])=>async()=>{!d&&t===void 0&&v(e),await i.upsert(e,{embed:o.embed,id:s.id,input:o.select(r),metadata:o.metadata?.(r),namespace:t})})];try{await w(h,b,async e=>e())}catch(e){throw await Promise.allSettled(m.map(o=>i.deleteByIds(o,[s.id]))),e}}};export{B as createContextVectors,S as createVectorSyncHook};
@@ -0,0 +1 @@
1
+ import{LunoraError as d}from"@lunora/errors";const f=new Set(["image/avif","image/gif","image/jpeg","image/png","image/webp"]),y=1e4,v="image/webp",A=n=>typeof n!="object"?!1:"body"in n&&!(n instanceof ArrayBuffer)&&!(n instanceof Uint8Array),e=n=>{if(n instanceof ReadableStream)return n;if(A(n)){if(n.body===null)throw new d("INTERNAL","@lunora/bindings/images: R2 object body is null (object missing or already consumed)");return n.body}if(n instanceof Blob)return n.stream();const t=n instanceof Uint8Array?n:new Uint8Array(n);return new ReadableStream({start(r){r.enqueue(t),r.close()}})},u=(n,t)=>{if(n===void 0)return{};const r=o=>{if(!Number.isFinite(o)||o<=0)throw new TypeError("@lunora/bindings/images: width/height must be a positive finite number");return Math.min(Math.floor(o),t)},i={...n};return delete i.draw,{...i,...n.width===void 0?{}:{width:r(n.width)},...n.height===void 0?{}:{height:r(n.height)}}},j=n=>{const{image:t,transform:r,...i}=n;return{drawOptions:i,image:t,transform:r}},N=n=>{const t=n?.format??v;if(!f.has(t))throw new d("INTERNAL",`@lunora/bindings/images: unsupported output format "${t}" (allowed: ${[...f].join(", ")})`);return{...n,format:t}},E=n=>{const{binding:t}=n,r=n.maxDimension??y;return{info:async i=>t.info(e(i)),transform:async(i,o,g,c)=>{const w=u(o,r),b=N(g);let a=t.input(e(i)).transform(w);for(const h of c??[]){const{drawOptions:l,image:s,transform:m}=j(h),p=m===void 0?e(s):t.input(e(s)).transform(u(m,r));a=a.draw(p,l)}return a.output(b)}}};export{E as createImages};
@@ -0,0 +1 @@
1
+ import{LunoraError as r}from"@lunora/errors";const l=512,y=1e3,g=new TextEncoder,u=t=>g.encode(t).length,p=t=>{if(typeof t!="string"||t.length===0)throw new TypeError("@lunora/bindings/kv: key must be a non-empty string");if(u(t)>l)throw new r("INTERNAL",`@lunora/bindings/kv: key exceeds ${String(l)}-byte limit`);if(t.includes("\0"))throw new r("INTERNAL","@lunora/bindings/kv: key contains NUL byte");const n=t.split("/");for(const o of n)if(o==="."||o==="..")throw new r("INTERNAL","@lunora/bindings/kv: key contains a `.`/`..` path component")},m=t=>{if(t.length===0)return;if(u(t)>l)throw new r("INTERNAL",`@lunora/bindings/kv: prefix exceeds ${String(l)}-byte limit`);if(t.includes("\0"))throw new r("INTERNAL","@lunora/bindings/kv: prefix contains NUL byte");const n=t.split("/");for(const o of n)if(o==="."||o==="..")throw new r("INTERNAL","@lunora/bindings/kv: prefix contains a `.`/`..` path component")},h=(t,n)=>{p(t),p(n);const o=`${t.endsWith("/")?t.slice(0,-1):t}/${n}`;if(u(o)>l)throw new r("INTERNAL",`@lunora/bindings/kv: scoped key exceeds ${String(l)}-byte limit`);return o},f=t=>{const n={};if(t.expiration!==void 0&&t.expirationTtl!==void 0)throw new r("INTERNAL","@lunora/bindings/kv: `expiration` and `expirationTtl` are mutually exclusive");return t.expiration!==void 0&&(n.expiration=t.expiration),t.expirationTtl!==void 0&&(n.expirationTtl=t.expirationTtl),t.metadata!==void 0&&(n.metadata=t.metadata),Object.keys(n).length>0?n:void 0},T=t=>{if(!t.namespace)throw new TypeError("@lunora/bindings/kv: `namespace` is required");const{keyPrefix:n,namespace:o}=t;n!==void 0&&p(n);const c=i=>n===void 0?(p(i),i):h(n,i),v=i=>{if(n===void 0)return i;const e=n.endsWith("/")?n:`${n}/`;return i.startsWith(e)?i.slice(e.length):i};return{delete:async i=>{await o.delete(c(i))},get:async(i,e={})=>await o.get(c(i),{cacheTtl:e.cacheTtl,type:"json"})??null,getRaw:async(i,e={})=>await o.get(c(i),{cacheTtl:e.cacheTtl,type:e.type??"text"})??null,getWithMetadata:async(i,e={})=>{const a=await o.getWithMetadata(c(i),{cacheTtl:e.cacheTtl,type:"json"});return{metadata:a.metadata??null,value:a.value??null}},list:async(i={})=>{if(i.limit!==void 0&&(!Number.isInteger(i.limit)||i.limit<=0))throw new TypeError("@lunora/bindings/kv: `limit` must be a positive integer");let{prefix:e}=i;if(e!==void 0&&m(e),n!==void 0){const d=n.endsWith("/")?n:`${n}/`;e=i.prefix===void 0?d:`${d}${i.prefix}`,m(e)}const a=i.limit===void 0?void 0:Math.min(i.limit,y),s=await o.list({cursor:i.cursor,limit:a,prefix:e}),w=s.keys.map(d=>({...d,name:v(d.name)}));return{cursor:s.list_complete?void 0:s.cursor,keys:w,listComplete:s.list_complete}},put:async(i,e,a={})=>{const s=a.raw?e:JSON.stringify(e);await o.put(c(i),s,f(a))}}};export{T as createKv,h as scopeKey};
@@ -0,0 +1 @@
1
+ import{LunoraError as o}from"@lunora/errors";const c=n=>{const{namespaces:e}=n,r=t=>{const a=e[t];if(!Object.hasOwn(e,t)||a===void 0)throw new o("BAD_REQUEST",`@lunora/bindings/kv: no namespace registered under binding "${t}"`);return a};return{deleteKey:async t=>{await r(t.namespace).delete(t.key)},getValue:async t=>{const a=await r(t.namespace).getWithMetadata(t.key,"text");return{metadata:a.metadata??null,value:a.value??null}},listKeys:async t=>{const a=await r(t.namespace).list({cursor:t.cursor,limit:t.limit,prefix:t.prefix}),s=a.keys.map(i=>({expiration:i.expiration,metadata:i.metadata,name:i.name}));return{cursor:a.list_complete?void 0:a.cursor,keys:s,listComplete:a.list_complete}},listNamespaces:()=>Promise.resolve(Object.keys(e).map(t=>({binding:t}))),putValue:async t=>{await r(t.namespace).put(t.key,t.value,{expiration:t.expiration,expirationTtl:t.expirationTtl,metadata:t.metadata})}}},p=n=>{if(typeof n!="object"||n===null)return!1;const e=n;return typeof e.getWithMetadata=="function"&&typeof e.list=="function"&&typeof e.put=="function"&&typeof e.delete=="function"},u=n=>{const e={};if(typeof n=="object"&&n!==null)for(const[r,t]of Object.entries(n))p(t)&&(e[r]=t);return c({namespaces:e})};export{c as createKvIntrospector,u as createKvIntrospectorFromEnv};
@@ -0,0 +1 @@
1
+ const s=e=>{const{binding:r}=e;return{send:async n=>{await r.send(Array.isArray(n)?n:[n])}}};export{s as createPipelines};
@@ -0,0 +1 @@
1
+ import{LunoraError as c}from"@lunora/errors";const l=20,b=10,h=m=>{const{embedders:n,indexes:o,registry:u}=m,i=async()=>Promise.all(u.map(async t=>{const r=o[t.name];if(r?.describe===void 0)return{...t};try{const e=await r.describe();return{...t,dimensions:t.dimensions??e.dimensions,processedUpToMutation:e.processedUpToMutation,vectorsCount:e.vectorsCount}}catch{return{...t}}}));return n!==void 0&&Object.keys(n).length>0?{listIndexes:i,queryIndex:async({name:t,text:r,topK:e})=>{const a=o[t];if(!Object.hasOwn(o,t)||a===void 0)throw new c("INTERNAL",`@lunora/bindings/vectors: no Vectorize binding registered for index "${t}"`);const d=n[t];if(!Object.hasOwn(n,t)||d===void 0)throw new c("INTERNAL",`@lunora/bindings/vectors: no embedder registered for index "${t}" — it lists read-only`);const p=await d(r);return{matches:(await a.query(p,{returnMetadata:"all",topK:Math.min(e??b,l)})).matches.map(s=>({id:s.id,metadata:s.metadata,score:s.score}))}}}:{listIndexes:i}};export{h as createVectorAdminIntrospector};
@@ -0,0 +1 @@
1
+ import{LunoraError as g}from"@lunora/errors";import{c as p,U as b}from"./concurrent-DMFQCILU.mjs";const i=(r,n)=>{const e=r[n];if(!Object.hasOwn(r,n)||e===void 0)throw new g("INTERNAL",`@lunora/bindings/vectors: no index registered for "${n}". Known indexes: ${Object.keys(r).join(", ")||"(none)"}`);return e},c=async r=>{const n=await r.embed(r.input);return{id:r.id,metadata:r.metadata,namespace:r.namespace,values:n}},w=100,y=20,o=1e3,u=1e3,f=r=>{if(Object.keys(r.indexes).length===0)throw new TypeError("@lunora/bindings/vectors: at least one index binding is required");return{deleteByIds:async(n,e)=>{const t=i(r.indexes,n);if(e.length>o)throw new RangeError(`@lunora/bindings/vectors: deleteByIds accepts at most ${String(o)} ids (got ${String(e.length)})`);return t.deleteByIds(e)},describe:async n=>{const e=i(r.indexes,n);if(!e.describe)throw new g("INTERNAL",`@lunora/bindings/vectors: binding for "${n}" does not implement describe()`);return e.describe()},getByIds:async(n,e)=>{const t=i(r.indexes,n);if(e.length>o)throw new RangeError(`@lunora/bindings/vectors: getByIds accepts at most ${String(o)} ids (got ${String(e.length)})`);return t.getByIds(e)},query:async(n,e)=>{const t=i(r.indexes,n),s=e.returnValues===!0||e.returnMetadata==="all",d=s?y:w;if(e.topK!==void 0&&(!Number.isInteger(e.topK)||e.topK<1||e.topK>d)){const l=s?' (lowered to 20 because returnValues/returnMetadata:"all" is set)':"";throw new RangeError(`@lunora/bindings/vectors: topK must be an integer in [1, ${String(d)}]${l} (got ${String(e.topK)})`)}let a;if(e.vector&&e.vector.length>0)a=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`");a=await e.embed(e.input)}return t.query(a,{filter:e.filter,namespace:e.namespace,returnMetadata:e.returnMetadata,returnValues:e.returnValues,topK:e.topK})},upsert:async(n,e)=>{const t=i(r.indexes,n),s=await c(e);return t.upsert([s])},upsertMany:async(n,e)=>{const t=i(r.indexes,n);if(e.length>u)throw new RangeError(`@lunora/bindings/vectors: upsertMany batch exceeds ${String(u)} (got ${String(e.length)}) — split across calls`);const s=await p(e,b,c);return t.upsert(s)}}};export{f as default};
@@ -1 +1 @@
1
- export { createPipelines } from '../packem_shared/createPipelines-CfyJ6VGu.mjs';
1
+ import{createPipelines as i}from"../packem_shared/createPipelines-n0Bf_p8Y.mjs";export{i as createPipelines};
@@ -1,7 +1 @@
1
- export { default as SelectBuilder } from '../packem_shared/SelectBuilder-BOqJQHEv.mjs';
2
- export { R2SqlError, createR2Sql } from '../packem_shared/R2SqlError-drPKSCZ3.mjs';
3
- export { asc, desc, renderOrderTerm } from '../packem_shared/asc-DZbQCxh1.mjs';
4
- export { default as SetOperation } from '../packem_shared/SetOperation-DmPgUL8W.mjs';
5
- export { Sql, isSql, joinSql, lit, raw, sql, toText } from '../packem_shared/Sql-B3zq2YGx.mjs';
6
- export { WindowFunction, fn } from '../packem_shared/WindowFunction-DrnuZUF6.mjs';
7
- export { default as WindowExpression } from '../packem_shared/WindowExpression-BT_uA6g1.mjs';
1
+ import{default as o}from"../packem_shared/SelectBuilder-WMBQ2b4q.mjs";import{R2SqlError as l,createR2Sql as f}from"../packem_shared/R2SqlError-Uaz0RJTR.mjs";import{asc as d,desc as i,renderOrderTerm as n}from"../packem_shared/asc-BsbdtIQU.mjs";import{default as s}from"../packem_shared/SetOperation-BrzMB1Tb.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-CwhZl1Q5.mjs";import{WindowFunction as R,fn as T}from"../packem_shared/WindowFunction-rzl4CzYE.mjs";import{default as j}from"../packem_shared/WindowExpression-CxCuEy8V.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,3 +1 @@
1
- export { createContextVectors, createVectorSyncHook } from '../packem_shared/createContextVectors-DwZtnPeC.mjs';
2
- export { createVectorAdminIntrospector } from '../packem_shared/createVectorAdminIntrospector-DuSvcBa5.mjs';
3
- export { default as createVectors } from '../packem_shared/createVectors-CTSrctiK.mjs';
1
+ import{createContextVectors as t,createVectorSyncHook as o}from"../packem_shared/createContextVectors-HVMMJ-88.mjs";import{createVectorAdminIntrospector as a}from"../packem_shared/createVectorAdminIntrospector-B9Yt09yj.mjs";import{default as m}from"../packem_shared/createVectors-jb8fAY6R.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.10",
3
+ "version": "1.0.0-alpha.12",
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",
@@ -64,7 +64,7 @@
64
64
  "access": "public"
65
65
  },
66
66
  "dependencies": {
67
- "@lunora/errors": "1.0.0-alpha.7"
67
+ "@lunora/errors": "1.0.0-alpha.8"
68
68
  },
69
69
  "engines": {
70
70
  "node": "^22.15.0 || >=24.11.0"
@@ -1,41 +0,0 @@
1
- import { LunoraError } from '@lunora/errors';
2
-
3
- const SQL_API_BASE = "https://api.cloudflare.com/client/v4/accounts";
4
- class AnalyticsSqlError extends LunoraError {
5
- constructor(status, body) {
6
- super("ANALYTICS_SQL_ERROR", `Analytics Engine SQL API returned ${String(status)}: ${body}`, { name: "AnalyticsSqlError", status });
7
- }
8
- }
9
- const createAnalyticsSqlClient = (config) => {
10
- const fetchImpl = config.fetch ?? globalThis.fetch;
11
- const endpoint = `${SQL_API_BASE}/${encodeURIComponent(config.accountId)}/analytics_engine/sql`;
12
- const query = async (sql) => {
13
- const response = await fetchImpl(endpoint, {
14
- body: sql,
15
- headers: {
16
- Authorization: `Bearer ${config.apiToken}`,
17
- "Content-Type": "text/plain"
18
- },
19
- method: "POST"
20
- });
21
- if (!response.ok) {
22
- throw new AnalyticsSqlError(response.status, await response.text());
23
- }
24
- let raw;
25
- try {
26
- raw = await response.json();
27
- } catch {
28
- throw new AnalyticsSqlError(response.status, "Analytics Engine SQL API returned a non-JSON body.");
29
- }
30
- const body = raw;
31
- const rows = body.data ?? [];
32
- return {
33
- columns: body.meta ?? [],
34
- rowCount: body.rows ?? rows.length,
35
- rows
36
- };
37
- };
38
- return { query };
39
- };
40
-
41
- export { AnalyticsSqlError, createAnalyticsSqlClient };
@@ -1,65 +0,0 @@
1
- import { LunoraError } from '@lunora/errors';
2
- import SelectBuilder from './SelectBuilder-BOqJQHEv.mjs';
3
- import { ident, toText } from './Sql-B3zq2YGx.mjs';
4
-
5
- const API_BASE = "https://api.sql.cloudflarestorage.com/api/v1/accounts";
6
- const inferColumns = (rows) => {
7
- if (rows[0] === void 0) {
8
- return [];
9
- }
10
- return Object.keys(rows[0]).map((name) => {
11
- return { name };
12
- });
13
- };
14
- class R2SqlError extends LunoraError {
15
- constructor(status, body) {
16
- super("R2_SQL_ERROR", `R2 SQL query failed (${String(status)}): ${body}`, { name: "R2SqlError", status });
17
- }
18
- }
19
- const createR2Sql = (config) => {
20
- const fetchImpl = config.fetch ?? globalThis.fetch;
21
- const base = config.endpoint ?? API_BASE;
22
- const endpoint = `${base}/${encodeURIComponent(config.accountId)}/r2-sql/query/${encodeURIComponent(config.bucket)}`;
23
- const warehouse = `${config.accountId}_${config.bucket}`;
24
- const exec = async (statement) => {
25
- const response = await fetchImpl(endpoint, {
26
- body: JSON.stringify({ query: statement, warehouse }),
27
- headers: {
28
- Authorization: `Bearer ${config.apiToken}`,
29
- "Content-Type": "application/json"
30
- },
31
- method: "POST"
32
- });
33
- if (!response.ok) {
34
- throw new R2SqlError(response.status, await response.text());
35
- }
36
- let raw;
37
- try {
38
- raw = await response.json();
39
- } catch {
40
- throw new R2SqlError(response.status, "R2 SQL returned a non-JSON body.");
41
- }
42
- const body = raw;
43
- if (body.success === false || body.errors !== void 0 && body.errors.length > 0) {
44
- throw new R2SqlError(response.status, JSON.stringify(body.errors ?? body));
45
- }
46
- const rows = body.result?.rows ?? [];
47
- return {
48
- columns: body.result?.schema ?? inferColumns(rows),
49
- rowCount: rows.length,
50
- rows
51
- };
52
- };
53
- return {
54
- describe: async (table) => exec(`DESCRIBE ${ident(table)}`),
55
- explain: async (statement, options) => exec(`EXPLAIN ${options?.format === "json" ? "FORMAT JSON " : ""}${toText(statement)}`),
56
- // `SelectBuilder`'s constructor validates the table reference (allowing an
57
- // optional `[AS] alias`), so no pre-validation here.
58
- from: (table) => new SelectBuilder(exec, table),
59
- query: async (statement) => exec(toText(statement)),
60
- showDatabases: async () => exec("SHOW DATABASES"),
61
- showTables: async (namespace) => exec(`SHOW TABLES IN ${ident(namespace)}`)
62
- };
63
- };
64
-
65
- export { R2SqlError, createR2Sql };
@@ -1,168 +0,0 @@
1
- import { renderOrderTerm } from './asc-DZbQCxh1.mjs';
2
- import SetOperation from './SetOperation-DmPgUL8W.mjs';
3
- import { tableRef, toText, assertLimit, lit } from './Sql-B3zq2YGx.mjs';
4
-
5
- const JOIN_KEYWORDS = {
6
- cross: "CROSS JOIN",
7
- full: "FULL OUTER JOIN",
8
- inner: "INNER JOIN",
9
- left: "LEFT JOIN",
10
- right: "RIGHT JOIN"
11
- };
12
- class SelectBuilder {
13
- exec;
14
- table;
15
- selectItems = [];
16
- distinctFlag = false;
17
- distinctOnItems = [];
18
- joins = [];
19
- whereConditions = [];
20
- groupByItems = [];
21
- havingConditions = [];
22
- qualifyCondition;
23
- orderByItems = [];
24
- limitValue;
25
- constructor(exec, table) {
26
- this.exec = exec;
27
- this.table = tableRef(table);
28
- }
29
- /** The `SELECT` list. Omit/empty for `SELECT *`. Items are columns, expressions, or aliased window fragments (`fn.rowNumber().over(...).as("rk")`). */
30
- select(...items) {
31
- this.selectItems.push(...items.map((item) => toText(item)));
32
- return this;
33
- }
34
- /** `SELECT DISTINCT` — unique rows. */
35
- distinct() {
36
- this.distinctFlag = true;
37
- return this;
38
- }
39
- /** `DISTINCT ON (cols)` — the first row per distinct combination, ordered by {@link orderBy}. */
40
- distinctOn(...columns) {
41
- this.distinctOnItems.push(...columns.map((column) => toText(column)));
42
- return this;
43
- }
44
- /** `INNER JOIN table ON condition`. */
45
- innerJoin(table, on) {
46
- return this.addJoin("inner", table, on);
47
- }
48
- /** `LEFT JOIN table ON condition`. */
49
- leftJoin(table, on) {
50
- return this.addJoin("left", table, on);
51
- }
52
- /** `RIGHT JOIN table ON condition`. */
53
- rightJoin(table, on) {
54
- return this.addJoin("right", table, on);
55
- }
56
- /** `FULL OUTER JOIN table ON condition`. */
57
- fullJoin(table, on) {
58
- return this.addJoin("full", table, on);
59
- }
60
- /** `CROSS JOIN table` (no `ON`). */
61
- crossJoin(table) {
62
- return this.addJoin("cross", table);
63
- }
64
- /** Add `WHERE` condition(s). Multiple calls (and multiple args) are `AND`-ed. Bind values with the `sql` tag. */
65
- where(...conditions) {
66
- this.whereConditions.push(...conditions.map((condition) => toText(condition)));
67
- return this;
68
- }
69
- /** `GROUP BY` column(s)/expression(s). */
70
- groupBy(...columns) {
71
- this.groupByItems.push(...columns.map((column) => toText(column)));
72
- return this;
73
- }
74
- /** Add `HAVING` condition(s) over aggregates; multiple are `AND`-ed. */
75
- having(...conditions) {
76
- this.havingConditions.push(...conditions.map((condition) => toText(condition)));
77
- return this;
78
- }
79
- /**
80
- * `QUALIFY` — filter on a window function without a subquery, e.g.
81
- * `.qualify(fn.rowNumber().over({ partitionBy: "region", orderBy: desc("total") }).lte(3))`.
82
- */
83
- qualify(condition) {
84
- this.qualifyCondition = toText(condition);
85
- return this;
86
- }
87
- /** `ORDER BY` term(s) — bare strings (ASC) or {@link import("./order").asc | asc}/{@link import("./order").desc | desc} tags. */
88
- orderBy(...terms) {
89
- this.orderByItems.push(...terms.map((term) => renderOrderTerm(term)));
90
- return this;
91
- }
92
- /** `LIMIT n` (R2 SQL: 1–10,000, default 500). */
93
- limit(n) {
94
- assertLimit(n);
95
- this.limitValue = n;
96
- return this;
97
- }
98
- /** Re-type the result rows without changing the query (the builder carries no schema of its own). */
99
- returns() {
100
- return this;
101
- }
102
- /** `this UNION other` — all rows from both, duplicates removed. */
103
- union(other) {
104
- return this.setOperation("UNION", other);
105
- }
106
- /** `this UNION ALL other` — all rows from both, duplicates kept. */
107
- unionAll(other) {
108
- return this.setOperation("UNION ALL", other);
109
- }
110
- /** `this INTERSECT other` — rows present in both. */
111
- intersect(other) {
112
- return this.setOperation("INTERSECT", other);
113
- }
114
- /** `this EXCEPT other` — rows in `this` but not `other`. */
115
- except(other) {
116
- return this.setOperation("EXCEPT", other);
117
- }
118
- /** True when this query carries its own `ORDER BY`/`LIMIT` — so a set operation must parenthesise it. */
119
- get needsWrapForSetOperation() {
120
- return this.orderByItems.length > 0 || this.limitValue !== void 0;
121
- }
122
- /** Render the `SELECT` statement (no trailing semicolon). */
123
- toSQL() {
124
- const parts = [`${this.renderHead()} ${this.selectItems.length > 0 ? this.selectItems.join(", ") : "*"}`, `FROM ${this.table}`];
125
- for (const join of this.joins) {
126
- parts.push(join.on === void 0 ? `${JOIN_KEYWORDS[join.kind]} ${join.table}` : `${JOIN_KEYWORDS[join.kind]} ${join.table} ON ${toText(join.on)}`);
127
- }
128
- if (this.whereConditions.length > 0) {
129
- parts.push(`WHERE ${this.whereConditions.join(" AND ")}`);
130
- }
131
- if (this.groupByItems.length > 0) {
132
- parts.push(`GROUP BY ${this.groupByItems.join(", ")}`);
133
- }
134
- if (this.havingConditions.length > 0) {
135
- parts.push(`HAVING ${this.havingConditions.join(" AND ")}`);
136
- }
137
- if (this.qualifyCondition !== void 0) {
138
- parts.push(`QUALIFY ${this.qualifyCondition}`);
139
- }
140
- if (this.orderByItems.length > 0) {
141
- parts.push(`ORDER BY ${this.orderByItems.join(", ")}`);
142
- }
143
- if (this.limitValue !== void 0) {
144
- parts.push(`LIMIT ${lit(this.limitValue)}`);
145
- }
146
- return parts.join(" ");
147
- }
148
- /** Execute the query and return the typed result. */
149
- async run() {
150
- return this.exec(this.toSQL());
151
- }
152
- /** The `SELECT [DISTINCT [ON (...)]]` head. */
153
- renderHead() {
154
- if (this.distinctOnItems.length > 0) {
155
- return `SELECT DISTINCT ON (${this.distinctOnItems.join(", ")})`;
156
- }
157
- return this.distinctFlag ? "SELECT DISTINCT" : "SELECT";
158
- }
159
- addJoin(kind, table, on) {
160
- this.joins.push({ kind, on, table: tableRef(table) });
161
- return this;
162
- }
163
- setOperation(operator, other) {
164
- return new SetOperation(this.exec, [{ query: this }, { operator, query: other }]);
165
- }
166
- }
167
-
168
- export { SelectBuilder as default };
@@ -1,81 +0,0 @@
1
- import { renderOrderTerm } from './asc-DZbQCxh1.mjs';
2
- import { assertLimit, lit } from './Sql-B3zq2YGx.mjs';
3
-
4
- const renderMember = (query) => {
5
- const text = query.toSQL();
6
- return query.needsWrapForSetOperation === true ? `(${text})` : text;
7
- };
8
- class SetOperation {
9
- /**
10
- * Always `true`: a nested set operation must be parenthesised when it is a
11
- * member of another set operation, or mixed operators mis-associate — e.g.
12
- * `a.union(b.except(c))` must render `a UNION (b EXCEPT c)`, not the flat
13
- * `a UNION b EXCEPT c`.
14
- */
15
- needsWrapForSetOperation = true;
16
- exec;
17
- members;
18
- orderByItems = [];
19
- limitValue;
20
- constructor(exec, members) {
21
- this.exec = exec;
22
- this.members = members;
23
- }
24
- /** Append `UNION other`. */
25
- union(other) {
26
- return this.add("UNION", other);
27
- }
28
- /** Append `UNION ALL other`. */
29
- unionAll(other) {
30
- return this.add("UNION ALL", other);
31
- }
32
- /** Append `INTERSECT other`. */
33
- intersect(other) {
34
- return this.add("INTERSECT", other);
35
- }
36
- /** Append `EXCEPT other`. */
37
- except(other) {
38
- return this.add("EXCEPT", other);
39
- }
40
- /** `ORDER BY` applied to the combined result. */
41
- orderBy(...terms) {
42
- this.orderByItems.push(...terms.map((term) => renderOrderTerm(term)));
43
- return this;
44
- }
45
- /** `LIMIT` applied to the combined result. */
46
- limit(n) {
47
- assertLimit(n);
48
- this.limitValue = n;
49
- return this;
50
- }
51
- /** Re-type the combined result rows. */
52
- returns() {
53
- return this;
54
- }
55
- /** Render the combined statement. */
56
- toSQL() {
57
- const parts = this.members.map((member) => {
58
- const text = renderMember(member.query);
59
- return member.operator === void 0 ? text : `${member.operator} ${text}`;
60
- });
61
- const combined = parts.join(" ");
62
- const tail = [];
63
- if (this.orderByItems.length > 0) {
64
- tail.push(`ORDER BY ${this.orderByItems.join(", ")}`);
65
- }
66
- if (this.limitValue !== void 0) {
67
- tail.push(`LIMIT ${lit(this.limitValue)}`);
68
- }
69
- return tail.length > 0 ? `${combined} ${tail.join(" ")}` : combined;
70
- }
71
- /** Execute the combined query and return the typed result. */
72
- async run() {
73
- return this.exec(this.toSQL());
74
- }
75
- add(operator, other) {
76
- this.members.push({ operator, query: other });
77
- return this;
78
- }
79
- }
80
-
81
- export { SetOperation as default };
@@ -1,74 +0,0 @@
1
- const quoteString = (value) => `'${value.replaceAll("'", "''")}'`;
2
- const IDENTIFIER_RE = /^\w+(?:\.\w+)*$/;
3
- const TABLE_REF_RE = /^\w+(?:\.\w+)*(?:\s+(?:as\s+)?\w+)?$/i;
4
- const MAX_LIMIT = 1e4;
5
- class Sql {
6
- text;
7
- constructor(text) {
8
- this.text = text;
9
- }
10
- toString() {
11
- return this.text;
12
- }
13
- }
14
- const isSql = (value) => value instanceof Sql;
15
- const raw = (text) => new Sql(text);
16
- const toText = (value) => isSql(value) ? value.text : value;
17
- const ident = (name) => {
18
- if (typeof name !== "string" || !IDENTIFIER_RE.test(name)) {
19
- throw new TypeError(`r2sql: invalid identifier ${JSON.stringify(name)} — expected dotted [A-Za-z0-9_] segments (e.g. "namespace.table").`);
20
- }
21
- return name;
22
- };
23
- const tableRef = (ref) => {
24
- if (typeof ref !== "string" || !TABLE_REF_RE.test(ref)) {
25
- throw new TypeError(`r2sql: invalid table reference ${JSON.stringify(ref)} — expected "namespace.table" with an optional "[AS] alias".`);
26
- }
27
- return ref;
28
- };
29
- const lit = (value) => {
30
- if (value === null || value === void 0) {
31
- return "NULL";
32
- }
33
- if (typeof value === "boolean") {
34
- return value ? "true" : "false";
35
- }
36
- if (typeof value === "bigint") {
37
- return value.toString();
38
- }
39
- if (typeof value === "number") {
40
- if (!Number.isFinite(value)) {
41
- throw new TypeError(`r2sql: cannot inline a non-finite number (${String(value)}) as a SQL literal.`);
42
- }
43
- return String(value);
44
- }
45
- if (typeof value === "string") {
46
- return quoteString(value);
47
- }
48
- if (value instanceof Date) {
49
- return quoteString(value.toISOString());
50
- }
51
- if (Array.isArray(value)) {
52
- if (value.length === 0) {
53
- throw new TypeError("r2sql: cannot inline an empty array — `IN ()` is not valid SQL. Guard the empty case before building the query.");
54
- }
55
- return `(${value.map((element) => lit(element)).join(", ")})`;
56
- }
57
- throw new TypeError(`r2sql: cannot inline a value of type ${typeof value} as a SQL literal. Wrap trusted SQL with raw(), or pass a primitive/Date/array.`);
58
- };
59
- const sql = (strings, ...values) => {
60
- let out = strings[0] ?? "";
61
- for (const [index, value] of values.entries()) {
62
- out += isSql(value) ? value.text : lit(value);
63
- out += strings[index + 1] ?? "";
64
- }
65
- return new Sql(out);
66
- };
67
- const joinSql = (parts, separator) => new Sql(parts.map((part) => toText(part)).join(separator));
68
- const assertLimit = (n) => {
69
- if (!Number.isInteger(n) || n < 1 || n > MAX_LIMIT) {
70
- throw new RangeError(`r2sql: limit must be an integer between 1 and ${String(MAX_LIMIT)} (got ${String(n)}).`);
71
- }
72
- };
73
-
74
- export { Sql, assertLimit, ident, isSql, joinSql, lit, raw, sql, tableRef, toText };