@lunora/bindings 1.0.0-alpha.32 → 1.0.0-alpha.34
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/analytics/index.d.mts +10 -0
- package/dist/analytics/index.d.ts +10 -0
- package/dist/analytics/index.mjs +1 -1
- package/dist/images/index.d.mts +25 -1
- package/dist/images/index.d.ts +25 -1
- package/dist/images/index.mjs +1 -1
- package/dist/packem_shared/AnalyticsSqlError-BEKML_Dg.mjs +1 -0
- package/dist/packem_shared/R2SqlError-D51drQVA.mjs +1 -0
- package/dist/packem_shared/buildSignedImageUrl-BZ4Q4ej7.mjs +4 -0
- package/dist/r2sql/index.d.mts +10 -0
- package/dist/r2sql/index.d.ts +10 -0
- package/dist/r2sql/index.mjs +1 -1
- package/package.json +2 -2
- package/dist/packem_shared/AnalyticsSqlError-cZQ6kiae.mjs +0 -1
- package/dist/packem_shared/R2SqlError-Ba9yHVqU.mjs +0 -1
- package/dist/packem_shared/buildSignedImageUrl-fucJNAbd.mjs +0 -4
|
@@ -91,6 +91,16 @@ interface AnalyticsSqlConfig {
|
|
|
91
91
|
* so the SQL path never touches the network.
|
|
92
92
|
*/
|
|
93
93
|
fetch?: typeof globalThis.fetch;
|
|
94
|
+
/**
|
|
95
|
+
* Milliseconds before an in-flight query (the fetch AND its body read) is
|
|
96
|
+
* aborted and surfaced as an `AnalyticsSqlError` with status 504. Defaults
|
|
97
|
+
* to 60_000 — analytical scans legitimately run tens of seconds.
|
|
98
|
+
* `undefined` means the default, not unbounded.
|
|
99
|
+
*
|
|
100
|
+
* The deadline is carried by the request's `signal`, so a custom `fetch`
|
|
101
|
+
* (above) that ignores `signal` leaves the query unbounded.
|
|
102
|
+
*/
|
|
103
|
+
timeoutMs?: number;
|
|
94
104
|
}
|
|
95
105
|
/**
|
|
96
106
|
* One column descriptor in a SQL-API response's `meta` array: the column `name`
|
|
@@ -91,6 +91,16 @@ interface AnalyticsSqlConfig {
|
|
|
91
91
|
* so the SQL path never touches the network.
|
|
92
92
|
*/
|
|
93
93
|
fetch?: typeof globalThis.fetch;
|
|
94
|
+
/**
|
|
95
|
+
* Milliseconds before an in-flight query (the fetch AND its body read) is
|
|
96
|
+
* aborted and surfaced as an `AnalyticsSqlError` with status 504. Defaults
|
|
97
|
+
* to 60_000 — analytical scans legitimately run tens of seconds.
|
|
98
|
+
* `undefined` means the default, not unbounded.
|
|
99
|
+
*
|
|
100
|
+
* The deadline is carried by the request's `signal`, so a custom `fetch`
|
|
101
|
+
* (above) that ignores `signal` leaves the query unbounded.
|
|
102
|
+
*/
|
|
103
|
+
timeoutMs?: number;
|
|
94
104
|
}
|
|
95
105
|
/**
|
|
96
106
|
* One column descriptor in a SQL-API response's `meta` array: the column `name`
|
package/dist/analytics/index.mjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{createAnalytics as e}from"../packem_shared/createAnalytics-BXTNc57d.mjs";import{AnalyticsSqlError as a,createAnalyticsSqlClient as c}from"../packem_shared/AnalyticsSqlError-
|
|
1
|
+
import{createAnalytics as e}from"../packem_shared/createAnalytics-BXTNc57d.mjs";import{AnalyticsSqlError as a,createAnalyticsSqlClient as c}from"../packem_shared/AnalyticsSqlError-BEKML_Dg.mjs";export{a as AnalyticsSqlError,e as createAnalytics,c as createAnalyticsSqlClient};
|
package/dist/images/index.d.mts
CHANGED
|
@@ -288,6 +288,21 @@ interface ImageDeliveryUrlOptions {
|
|
|
288
288
|
* Pure and deterministic — usable from any handler.
|
|
289
289
|
*/
|
|
290
290
|
declare const buildImageDeliveryUrl: (options: ImageDeliveryUrlOptions) => string;
|
|
291
|
+
/**
|
|
292
|
+
* Parse a verified transform string (the `t` query value handed back by
|
|
293
|
+
* {@link verifySignedImageUrl}) back into the {@link TransformOptions} it was
|
|
294
|
+
* serialized from, so the Worker can apply exactly the signed transform via
|
|
295
|
+
* `ctx.images.transform(...)` without hand-writing the inverse encoding.
|
|
296
|
+
*
|
|
297
|
+
* The exact inverse of `serializeTransform` above — the two MUST evolve
|
|
298
|
+
* together (the round-trip test in
|
|
299
|
+
* `__tests__/images/signed-delivery-url.test.ts` pins the pairing). Throws a
|
|
300
|
+
* `TypeError` on an unknown key or an uncoercible value: the input is meant to
|
|
301
|
+
* be a string whose HMAC already verified, so a parse failure means
|
|
302
|
+
* encoder/decoder drift in the library, never user input — fail loud rather
|
|
303
|
+
* than silently un-binding the transform the signature protects.
|
|
304
|
+
*/
|
|
305
|
+
declare const parseSignedTransform: (t: string) => TransformOptions;
|
|
291
306
|
interface SignedImageUrlOptions {
|
|
292
307
|
/** Delivery / Worker origin the signed URL points at (e.g. `https://cdn.acme.test`). */
|
|
293
308
|
baseUrl: string;
|
|
@@ -324,6 +339,15 @@ interface VerifyImageResult {
|
|
|
324
339
|
reason?: "bad_signature" | "expired" | "malformed";
|
|
325
340
|
/** The raw, verified transform string (the `t` query value), when present. */
|
|
326
341
|
transform?: string;
|
|
342
|
+
/**
|
|
343
|
+
* The verified transform decoded back into the options object to pass to
|
|
344
|
+
* `ctx.images.transform(...)` — {@link parseSignedTransform} applied to
|
|
345
|
+
* `transform`. Left `undefined` when `transform` is absent, and also when a
|
|
346
|
+
* genuinely signed transform carries a key this build does not know (an
|
|
347
|
+
* old URL minted before a key was renamed): the request stays `valid`, the
|
|
348
|
+
* raw `transform` is still returned, and the caller decides.
|
|
349
|
+
*/
|
|
350
|
+
transformOptions?: TransformOptions;
|
|
327
351
|
valid: boolean;
|
|
328
352
|
}
|
|
329
353
|
/**
|
|
@@ -335,4 +359,4 @@ interface VerifyImageResult {
|
|
|
335
359
|
declare const verifySignedImageUrl: (input: string | URL, secret: string, options?: {
|
|
336
360
|
expectedHost?: string;
|
|
337
361
|
}) => Promise<VerifyImageResult>;
|
|
338
|
-
export { type DrawOverlay, type ImageCompositeMode, type ImageDeliveryUrlOptions, type ImageDrawOptions, type ImageInfoLike, type ImageInput, type ImageOutputFormat, type ImageOverlay, type ImageTransformationResultLike, type ImageTransformerLike, type Images, type ImagesBindingLike, type LunoraImagesOptions, type OutputOptions, type R2ObjectBodyLike, type SignedImageUrlOptions, type TransformOptions, type VerifyImageResult, buildImageDeliveryUrl, buildSignedImageUrl, createImages, verifySignedImageUrl };
|
|
362
|
+
export { type DrawOverlay, type ImageCompositeMode, type ImageDeliveryUrlOptions, type ImageDrawOptions, type ImageInfoLike, type ImageInput, type ImageOutputFormat, type ImageOverlay, type ImageTransformationResultLike, type ImageTransformerLike, type Images, type ImagesBindingLike, type LunoraImagesOptions, type OutputOptions, type R2ObjectBodyLike, type SignedImageUrlOptions, type TransformOptions, type VerifyImageResult, buildImageDeliveryUrl, buildSignedImageUrl, createImages, parseSignedTransform, verifySignedImageUrl };
|
package/dist/images/index.d.ts
CHANGED
|
@@ -288,6 +288,21 @@ interface ImageDeliveryUrlOptions {
|
|
|
288
288
|
* Pure and deterministic — usable from any handler.
|
|
289
289
|
*/
|
|
290
290
|
declare const buildImageDeliveryUrl: (options: ImageDeliveryUrlOptions) => string;
|
|
291
|
+
/**
|
|
292
|
+
* Parse a verified transform string (the `t` query value handed back by
|
|
293
|
+
* {@link verifySignedImageUrl}) back into the {@link TransformOptions} it was
|
|
294
|
+
* serialized from, so the Worker can apply exactly the signed transform via
|
|
295
|
+
* `ctx.images.transform(...)` without hand-writing the inverse encoding.
|
|
296
|
+
*
|
|
297
|
+
* The exact inverse of `serializeTransform` above — the two MUST evolve
|
|
298
|
+
* together (the round-trip test in
|
|
299
|
+
* `__tests__/images/signed-delivery-url.test.ts` pins the pairing). Throws a
|
|
300
|
+
* `TypeError` on an unknown key or an uncoercible value: the input is meant to
|
|
301
|
+
* be a string whose HMAC already verified, so a parse failure means
|
|
302
|
+
* encoder/decoder drift in the library, never user input — fail loud rather
|
|
303
|
+
* than silently un-binding the transform the signature protects.
|
|
304
|
+
*/
|
|
305
|
+
declare const parseSignedTransform: (t: string) => TransformOptions;
|
|
291
306
|
interface SignedImageUrlOptions {
|
|
292
307
|
/** Delivery / Worker origin the signed URL points at (e.g. `https://cdn.acme.test`). */
|
|
293
308
|
baseUrl: string;
|
|
@@ -324,6 +339,15 @@ interface VerifyImageResult {
|
|
|
324
339
|
reason?: "bad_signature" | "expired" | "malformed";
|
|
325
340
|
/** The raw, verified transform string (the `t` query value), when present. */
|
|
326
341
|
transform?: string;
|
|
342
|
+
/**
|
|
343
|
+
* The verified transform decoded back into the options object to pass to
|
|
344
|
+
* `ctx.images.transform(...)` — {@link parseSignedTransform} applied to
|
|
345
|
+
* `transform`. Left `undefined` when `transform` is absent, and also when a
|
|
346
|
+
* genuinely signed transform carries a key this build does not know (an
|
|
347
|
+
* old URL minted before a key was renamed): the request stays `valid`, the
|
|
348
|
+
* raw `transform` is still returned, and the caller decides.
|
|
349
|
+
*/
|
|
350
|
+
transformOptions?: TransformOptions;
|
|
327
351
|
valid: boolean;
|
|
328
352
|
}
|
|
329
353
|
/**
|
|
@@ -335,4 +359,4 @@ interface VerifyImageResult {
|
|
|
335
359
|
declare const verifySignedImageUrl: (input: string | URL, secret: string, options?: {
|
|
336
360
|
expectedHost?: string;
|
|
337
361
|
}) => Promise<VerifyImageResult>;
|
|
338
|
-
export { type DrawOverlay, type ImageCompositeMode, type ImageDeliveryUrlOptions, type ImageDrawOptions, type ImageInfoLike, type ImageInput, type ImageOutputFormat, type ImageOverlay, type ImageTransformationResultLike, type ImageTransformerLike, type Images, type ImagesBindingLike, type LunoraImagesOptions, type OutputOptions, type R2ObjectBodyLike, type SignedImageUrlOptions, type TransformOptions, type VerifyImageResult, buildImageDeliveryUrl, buildSignedImageUrl, createImages, verifySignedImageUrl };
|
|
362
|
+
export { type DrawOverlay, type ImageCompositeMode, type ImageDeliveryUrlOptions, type ImageDrawOptions, type ImageInfoLike, type ImageInput, type ImageOutputFormat, type ImageOverlay, type ImageTransformationResultLike, type ImageTransformerLike, type Images, type ImagesBindingLike, type LunoraImagesOptions, type OutputOptions, type R2ObjectBodyLike, type SignedImageUrlOptions, type TransformOptions, type VerifyImageResult, buildImageDeliveryUrl, buildSignedImageUrl, createImages, parseSignedTransform, verifySignedImageUrl };
|
package/dist/images/index.mjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{createImages as m}from"../packem_shared/createImages-CHgMZP4g.mjs";import{buildImageDeliveryUrl as
|
|
1
|
+
import{createImages as m}from"../packem_shared/createImages-CHgMZP4g.mjs";import{buildImageDeliveryUrl as g}from"../packem_shared/buildImageDeliveryUrl-Brqs-dcZ.mjs";import{buildSignedImageUrl as o,parseSignedTransform as l,verifySignedImageUrl as d}from"../packem_shared/buildSignedImageUrl-BZ4Q4ej7.mjs";export{g as buildImageDeliveryUrl,o as buildSignedImageUrl,m as createImages,l as parseSignedTransform,d as verifySignedImageUrl};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{LunoraError as h}from"@lunora/errors";const m="https://api.cloudflare.com/client/v4/accounts",w=6e4;class r extends h{constructor(o,a){super("ANALYTICS_SQL_ERROR",`Analytics Engine SQL API returned ${String(o)}: ${a}`,{name:"AnalyticsSqlError",status:o})}}const p=e=>{const o=e.fetch??globalThis.fetch,a=`${m}/${encodeURIComponent(e.accountId)}/analytics_engine/sql`,i=e.timeoutMs??w;return{query:async u=>{const n=new AbortController,d=setTimeout(()=>{n.abort()},i);try{const t=await o(a,{body:u,headers:{Authorization:`Bearer ${e.apiToken}`,"Content-Type":"text/plain"},method:"POST",signal:n.signal});if(!t.ok)throw new r(t.status,await t.text().catch(()=>"<error body unavailable: the request deadline fired before it was read>"));let c;try{c=await t.json()}catch(y){throw n.signal.aborted?y:new r(t.status,"Analytics Engine SQL API returned a non-JSON body.")}const s=c,l=s.data??[];return{columns:s.meta??[],rowCount:s.rows??l.length,rows:l}}catch(t){throw n.signal.aborted&&!(t instanceof r)?new r(504,`query timed out after ${String(i)}ms (AnalyticsSqlConfig.timeoutMs)`):t}finally{clearTimeout(d)}}}};export{r as AnalyticsSqlError,p as createAnalyticsSqlClient};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{LunoraError as b}from"@lunora/errors";import f from"./SelectBuilder-C3dn71re.mjs";import{ident as m,toText as h}from"./Sql-CJr-IlfQ.mjs";const R="https://api.sql.cloudflarestorage.com/api/v1/accounts",T=6e4,$=e=>e[0]===void 0?[]:Object.keys(e[0]).map(s=>({name:s}));class c extends b{constructor(s,l){super("R2_SQL_ERROR",`R2 SQL query failed (${String(s)}): ${l}`,{name:"R2SqlError",status:s})}}const O=e=>{const s=e.fetch??globalThis.fetch,S=`${e.endpoint??R}/${encodeURIComponent(e.accountId)}/r2-sql/query/${encodeURIComponent(e.bucket)}`,w=`${e.accountId}_${e.bucket}`,u=e.timeoutMs??T,n=async t=>{const a=new AbortController,y=setTimeout(()=>{a.abort()},u);try{const r=await s(S,{body:JSON.stringify({query:t,warehouse:w}),headers:{Authorization:`Bearer ${e.apiToken}`,"Content-Type":"application/json"},method:"POST",signal:a.signal});if(!r.ok)throw new c(r.status,await r.text().catch(()=>"<error body unavailable: the request deadline fired before it was read>"));let d;try{d=await r.json()}catch(p){throw a.signal.aborted?p:new c(r.status,"R2 SQL returned a non-JSON body.")}const o=d;if(o.success===!1||o.errors!==void 0&&o.errors.length>0)throw new c(r.status,JSON.stringify(o.errors??o));const i=o.result?.rows??[];return{columns:o.result?.schema??$(i),rowCount:i.length,rows:i}}catch(r){throw a.signal.aborted&&!(r instanceof c)?new c(504,`query timed out after ${String(u)}ms (R2SqlConfig.timeoutMs)`):r}finally{clearTimeout(y)}};return{describe:async t=>n(`DESCRIBE ${m(t)}`),explain:async(t,a)=>n(`EXPLAIN ${a?.format==="json"?"FORMAT JSON ":""}${h(t)}`),from:t=>new f(n,t),query:async t=>n(h(t)),showDatabases:async()=>n("SHOW DATABASES"),showTables:async t=>n(`SHOW TABLES IN ${m(t)}`)}};export{c as R2SqlError,O as createR2Sql};
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
const E=(e,t)=>{if(e.size<t)return;const n=e.keys().next().value;n!==void 0&&e.delete(n)},f=new TextEncoder,g=10080*60,x=/^[a-z][a-z0-9+\-.]*:\/\//i,C=Array.from({length:32},(e,t)=>t),R=new RegExp(`[${C.map(e=>String.fromCodePoint(e)).join("")}]`,"u"),U=e=>{const t=String.fromCodePoint(...e);return btoa(t).replaceAll("+","-").replaceAll("/","_").replaceAll("=","")},_=e=>{const t=e.replaceAll("-","+").replaceAll("_","/")+"===".slice((e.length+3)%4),n=atob(t),r=new Uint8Array(n.length);for(let s=0;s<n.length;s+=1)r[s]=n.codePointAt(s)??0;return r},$=64,u=new Map,y=async e=>{const t=u.get(e);if(t)return t;E(u,$);const n=crypto.subtle.importKey("raw",f.encode(e),{hash:"SHA-256",name:"HMAC"},!1,["sign","verify"]);return u.set(e,n),n},p=e=>{try{return new URL(e).host}catch{return e.replace(x,"").split("/")[0]??""}},h=e=>{if(R.test(e))throw new TypeError("hmac-url: value must not contain control characters (including CR/LF)")},A=async(e,t)=>{const n=await y(e),r=await crypto.subtle.sign("HMAC",n,f.encode(t));return U(new Uint8Array(r))},N=async(e,t,n)=>{const r=await y(e);return crypto.subtle.verify("HMAC",r,n,f.encode(t))},b=/^\//,T=e=>e===void 0?"":Object.entries(e).filter(([,t])=>t!==void 0).toSorted(([t],[n])=>(t>n?1:0)-(t<n?1:0)).map(([t,n])=>`${t}=${typeof n=="object"?JSON.stringify(n):String(n)}`).join("&"),O={background:"string",blur:"number",brightness:"number",contrast:"number",draw:"json",fit:"string",flip:"string",gamma:"number",gravity:"string-or-json",height:"number",rotate:"number",saturation:"number",segment:"string",sharpen:"number",upscale:"string",width:"number"},w=new Map(Object.entries(O)),I=e=>{const t=[];for(const n of e.split("&")){const r=n.indexOf("="),s=r!==-1&&w.has(n.slice(0,r)),o=t.at(-1);s||o===void 0?t.push(n):t[t.length-1]=`${o}&${n}`}return t},K=(e,t,n)=>{if(t==="string"||t==="string-or-json"&&!n.startsWith("{"))return n;if(t==="number"){const r=Number(n);if(n===""||!Number.isFinite(r))throw new TypeError(`@lunora/bindings/images: transform key "${e}" expects a number, got "${n}"`);return r}try{return JSON.parse(n)}catch{throw new TypeError(`@lunora/bindings/images: transform key "${e}" carries malformed JSON`)}},S=(e,t,n,r)=>`${e.toLowerCase()}
|
|
2
|
+
${t}
|
|
3
|
+
${String(n)}
|
|
4
|
+
${r}`,L=e=>e.split("/").map(t=>encodeURIComponent(t)).join("/"),H=e=>{if(e==="")return{};const t={};for(const n of I(e)){const r=n.indexOf("=");if(r===-1)throw new TypeError(`@lunora/bindings/images: malformed transform segment "${n}" — expected key=value`);const s=n.slice(0,r),o=w.get(s);if(o===void 0)throw new TypeError(`@lunora/bindings/images: unknown transform key "${s}" — the serialized transform does not match this version's TransformOptions`);t[s]=K(s,o,n.slice(r+1))}return t},M=async e=>{const t=e.expiresInSeconds??3600;if(!Number.isFinite(t)||t<=0)throw new TypeError("@lunora/bindings/images: expiresInSeconds must be a positive finite number");if(t>g)throw new TypeError(`@lunora/bindings/images: expiresInSeconds must not exceed ${String(g)} (7 days)`);let n="";try{n=new URL(e.baseUrl).pathname}catch{}if(n!==""&&n!=="/")throw new TypeError(`@lunora/bindings/images: baseUrl must not carry a path ("${n}") — the key is verified from the full URL pathname, so a subpath base would make every signed URL fail verification`);const r=Math.floor(Date.now()/1e3)+t,s=p(e.baseUrl),o=T(e.transform),i=e.key.replace(b,"");h(i);const c=await A(e.secret,S(s,i,r,o)),a=e.baseUrl.endsWith("/")?e.baseUrl.slice(0,-1):e.baseUrl,l=L(i),m=o===""?"":`&t=${encodeURIComponent(o)}`;return`${a}/${l}?exp=${String(r)}&sig=${c}${m}`},j=async(e,t,n)=>{let r;try{r=e instanceof URL?e:new URL(e)}catch{return{reason:"malformed",valid:!1}}const s=r.searchParams.get("exp"),o=s===null?Number.NaN:Number(s),i=r.searchParams.get("sig"),c=r.searchParams.get("t")??"";if(!i||!Number.isInteger(o))return{reason:"malformed",valid:!1};if(o<Math.floor(Date.now()/1e3))return{reason:"expired",valid:!1};let a,l;try{a=r.pathname.replace(b,"").split("/").map(v=>decodeURIComponent(v)).join("/"),h(a),l=_(i)}catch{return{reason:"malformed",valid:!1}}const m=n?.expectedHost===void 0?r.host:p(n.expectedHost);if(!await N(t,S(m,a,o,c),l))return{reason:"bad_signature",valid:!1};if(c==="")return{key:a,valid:!0};let d;try{d=H(c)}catch{d=void 0}return{key:a,transform:c,transformOptions:d,valid:!0}};export{M as buildSignedImageUrl,H as parseSignedTransform,j as verifySignedImageUrl};
|
package/dist/r2sql/index.d.mts
CHANGED
|
@@ -93,6 +93,16 @@ interface R2SqlConfig {
|
|
|
93
93
|
* so a query never touches the network.
|
|
94
94
|
*/
|
|
95
95
|
fetch?: typeof globalThis.fetch;
|
|
96
|
+
/**
|
|
97
|
+
* Milliseconds before an in-flight query (the fetch AND its body read) is
|
|
98
|
+
* aborted and surfaced as an `R2SqlError` with status 504. Defaults to
|
|
99
|
+
* 60_000 — analytical scans legitimately run tens of seconds. `undefined`
|
|
100
|
+
* means the default, not unbounded.
|
|
101
|
+
*
|
|
102
|
+
* The deadline is carried by the request's `signal`, so a custom `fetch`
|
|
103
|
+
* (above) that ignores `signal` leaves the query unbounded.
|
|
104
|
+
*/
|
|
105
|
+
timeoutMs?: number;
|
|
96
106
|
}
|
|
97
107
|
/**
|
|
98
108
|
* One column descriptor in a result's schema: the column `name` and, when the
|
package/dist/r2sql/index.d.ts
CHANGED
|
@@ -93,6 +93,16 @@ interface R2SqlConfig {
|
|
|
93
93
|
* so a query never touches the network.
|
|
94
94
|
*/
|
|
95
95
|
fetch?: typeof globalThis.fetch;
|
|
96
|
+
/**
|
|
97
|
+
* Milliseconds before an in-flight query (the fetch AND its body read) is
|
|
98
|
+
* aborted and surfaced as an `R2SqlError` with status 504. Defaults to
|
|
99
|
+
* 60_000 — analytical scans legitimately run tens of seconds. `undefined`
|
|
100
|
+
* means the default, not unbounded.
|
|
101
|
+
*
|
|
102
|
+
* The deadline is carried by the request's `signal`, so a custom `fetch`
|
|
103
|
+
* (above) that ignores `signal` leaves the query unbounded.
|
|
104
|
+
*/
|
|
105
|
+
timeoutMs?: number;
|
|
96
106
|
}
|
|
97
107
|
/**
|
|
98
108
|
* One column descriptor in a result's schema: the column `name` and, when the
|
package/dist/r2sql/index.mjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{default as o}from"../packem_shared/SelectBuilder-C3dn71re.mjs";import{R2SqlError as l,createR2Sql as f}from"../packem_shared/R2SqlError-
|
|
1
|
+
import{default as o}from"../packem_shared/SelectBuilder-C3dn71re.mjs";import{R2SqlError as l,createR2Sql as f}from"../packem_shared/R2SqlError-D51drQVA.mjs";import{asc as d,desc as i,renderOrderTerm as n}from"../packem_shared/asc-DQLvku7R.mjs";import{default as s}from"../packem_shared/SetOperation-DwBivS9U.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-CJr-IlfQ.mjs";import{WindowFunction as R,fn as T}from"../packem_shared/WindowFunction-BAPoVyhc.mjs";import{default as j}from"../packem_shared/WindowExpression-D2wkQ8zz.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};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lunora/bindings",
|
|
3
|
-
"version": "1.0.0-alpha.
|
|
3
|
+
"version": "1.0.0-alpha.34",
|
|
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.22",
|
|
68
|
-
"@lunora/platform": "1.0.0-alpha.
|
|
68
|
+
"@lunora/platform": "1.0.0-alpha.16"
|
|
69
69
|
},
|
|
70
70
|
"engines": {
|
|
71
71
|
"node": "^22.15.0 || >=24.11.0"
|
|
@@ -1 +0,0 @@
|
|
|
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 h=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,h as createAnalyticsSqlClient};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{LunoraError as h}from"@lunora/errors";import m from"./SelectBuilder-C3dn71re.mjs";import{ident as l,toText as d}from"./Sql-CJr-IlfQ.mjs";const y="https://api.sql.cloudflarestorage.com/api/v1/accounts",w=e=>e[0]===void 0?[]:Object.keys(e[0]).map(s=>({name:s}));class c extends h{constructor(s,u){super("R2_SQL_ERROR",`R2 SQL query failed (${String(s)}): ${u}`,{name:"R2SqlError",status:s})}}const f=e=>{const s=e.fetch??globalThis.fetch,p=`${e.endpoint??y}/${encodeURIComponent(e.accountId)}/r2-sql/query/${encodeURIComponent(e.bucket)}`,S=`${e.accountId}_${e.bucket}`,n=async t=>{const r=await s(p,{body:JSON.stringify({query:t,warehouse:S}),headers:{Authorization:`Bearer ${e.apiToken}`,"Content-Type":"application/json"},method:"POST"});if(!r.ok)throw new c(r.status,await r.text());let i;try{i=await r.json()}catch{throw new c(r.status,"R2 SQL returned a non-JSON body.")}const o=i;if(o.success===!1||o.errors!==void 0&&o.errors.length>0)throw new c(r.status,JSON.stringify(o.errors??o));const a=o.result?.rows??[];return{columns:o.result?.schema??w(a),rowCount:a.length,rows:a}};return{describe:async t=>n(`DESCRIBE ${l(t)}`),explain:async(t,r)=>n(`EXPLAIN ${r?.format==="json"?"FORMAT JSON ":""}${d(t)}`),from:t=>new m(n,t),query:async t=>n(d(t)),showDatabases:async()=>n("SHOW DATABASES"),showTables:async t=>n(`SHOW TABLES IN ${l(t)}`)}};export{c as R2SqlError,f as createR2Sql};
|
|
@@ -1,4 +0,0 @@
|
|
|
1
|
-
const S=(e,t)=>{if(e.size<t)return;const n=e.keys().next().value;n!==void 0&&e.delete(n)},y=new TextEncoder,f=10080*60,C=/^[a-z][a-z0-9+\-.]*:\/\//i,v=Array.from({length:32},(e,t)=>t),U=new RegExp(`[${v.map(e=>String.fromCodePoint(e)).join("")}]`,"u"),R=e=>{const t=String.fromCodePoint(...e);return btoa(t).replaceAll("+","-").replaceAll("/","_").replaceAll("=","")},x=e=>{const t=e.replaceAll("-","+").replaceAll("_","/")+"===".slice((e.length+3)%4),n=atob(t),r=new Uint8Array(n.length);for(let a=0;a<n.length;a+=1)r[a]=n.codePointAt(a)??0;return r},A=64,m=new Map,u=async e=>{const t=m.get(e);if(t)return t;S(m,A);const n=crypto.subtle.importKey("raw",y.encode(e),{hash:"SHA-256",name:"HMAC"},!1,["sign","verify"]);return m.set(e,n),n},g=e=>{try{return new URL(e).host}catch{return e.replace(C,"").split("/")[0]??""}},h=e=>{if(U.test(e))throw new TypeError("hmac-url: value must not contain control characters (including CR/LF)")},E=async(e,t)=>{const n=await u(e),r=await crypto.subtle.sign("HMAC",n,y.encode(t));return R(new Uint8Array(r))},_=async(e,t,n)=>{const r=await u(e);return crypto.subtle.verify("HMAC",r,n,y.encode(t))},p=/^\//,$=e=>e===void 0?"":Object.entries(e).filter(([,t])=>t!==void 0).toSorted(([t],[n])=>(t>n?1:0)-(t<n?1:0)).map(([t,n])=>`${t}=${typeof n=="object"?JSON.stringify(n):String(n)}`).join("&"),b=(e,t,n,r)=>`${e.toLowerCase()}
|
|
2
|
-
${t}
|
|
3
|
-
${String(n)}
|
|
4
|
-
${r}`,L=e=>e.split("/").map(t=>encodeURIComponent(t)).join("/"),I=async e=>{const t=e.expiresInSeconds??3600;if(!Number.isFinite(t)||t<=0)throw new TypeError("@lunora/bindings/images: expiresInSeconds must be a positive finite number");if(t>f)throw new TypeError(`@lunora/bindings/images: expiresInSeconds must not exceed ${String(f)} (7 days)`);let n="";try{n=new URL(e.baseUrl).pathname}catch{}if(n!==""&&n!=="/")throw new TypeError(`@lunora/bindings/images: baseUrl must not carry a path ("${n}") — the key is verified from the full URL pathname, so a subpath base would make every signed URL fail verification`);const r=Math.floor(Date.now()/1e3)+t,a=g(e.baseUrl),s=$(e.transform),o=e.key.replace(p,"");h(o);const i=await E(e.secret,b(a,o,r,s)),c=e.baseUrl.endsWith("/")?e.baseUrl.slice(0,-1):e.baseUrl,l=L(o),d=s===""?"":`&t=${encodeURIComponent(s)}`;return`${c}/${l}?exp=${String(r)}&sig=${i}${d}`},N=async(e,t,n)=>{let r;try{r=e instanceof URL?e:new URL(e)}catch{return{reason:"malformed",valid:!1}}const a=r.searchParams.get("exp"),s=a===null?Number.NaN:Number(a),o=r.searchParams.get("sig"),i=r.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 c,l;try{c=r.pathname.replace(p,"").split("/").map(w=>decodeURIComponent(w)).join("/"),h(c),l=x(o)}catch{return{reason:"malformed",valid:!1}}const d=n?.expectedHost===void 0?r.host:g(n.expectedHost);return await _(t,b(d,c,s,i),l)?{key:c,transform:i===""?void 0:i,valid:!0}:{reason:"bad_signature",valid:!1}};export{I as buildSignedImageUrl,N as verifySignedImageUrl};
|