@lunora/runtime 1.0.0-alpha.22 → 1.0.0-alpha.221
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/LICENSE.md +120 -0
- package/README.md +52 -10
- package/dist/index.d.mts +4386 -1529
- package/dist/index.d.ts +4386 -1529
- package/dist/index.mjs +1 -16
- package/dist/packem_shared/BACKUP_KEY_PREFIX-BOtSu-_3.mjs +1 -0
- package/dist/packem_shared/DEFAULT_LOG_COLUMNS-gYMhXLzO.mjs +1 -0
- package/dist/packem_shared/DEFAULT_REGISTRY_CACHE_TTL_MS-CdACWUQW.mjs +1 -0
- package/dist/packem_shared/HEALTH_PATH-CAX2UeFy.mjs +1 -0
- package/dist/packem_shared/LOG_ARCHIVE_NOT_CONFIGURED-CDpi4yFD.mjs +1 -0
- package/dist/packem_shared/LOG_ARCHIVE_PATH-Hmjpz_Ko.mjs +1 -0
- package/dist/packem_shared/LunoraError-DksAgIpa.mjs +1 -0
- package/dist/packem_shared/NOOP_EXECUTION_CONTEXT-YmXqH-jH.mjs +1 -0
- package/dist/packem_shared/STORAGE_UPLOAD_MAX_BODY_BYTES-BIiV5kqV.mjs +1 -0
- package/dist/packem_shared/analyticsEngineSink-BZB-ZYCP.mjs +4 -0
- package/dist/packem_shared/applyJurisdiction-D4vryLhj.mjs +1 -0
- package/dist/packem_shared/applyRestCache-CEcBz3qq.mjs +1 -0
- package/dist/packem_shared/argsFromQuery-8InwnYmO.mjs +1 -0
- package/dist/packem_shared/base64-Bl1_r2k1.mjs +1 -0
- package/dist/packem_shared/composeIdentityResolvers-BHZ4jH8o.mjs +1 -0
- package/dist/packem_shared/composeWorker-DV9PGw3Z.mjs +6 -0
- package/dist/packem_shared/createCrossShardRelationCapabilities-BmGOuTrp.mjs +1 -0
- package/dist/packem_shared/createKvCursorStore-Bkn5pilz.mjs +1 -0
- package/dist/packem_shared/createQueryCoordinator-es4jrL6Q.mjs +1 -0
- package/dist/packem_shared/createShardClient-DIVRljRz.mjs +1 -0
- package/dist/packem_shared/declareAppJurisdiction-DEba2p42.mjs +1 -0
- package/dist/packem_shared/decorateResponse-CRBbtPYT.mjs +1 -0
- package/dist/packem_shared/emitLogEvent-C4keuLS-.mjs +1 -0
- package/dist/packem_shared/evict-oldest-BNXsKx4s.mjs +1 -0
- package/dist/packem_shared/export-tap-C2B_SATf.mjs +3 -0
- package/dist/packem_shared/identity-header-pR617HTs.mjs +1 -0
- package/dist/packem_shared/memoizeIdentity-BNnHkqeF.mjs +1 -0
- package/dist/packem_shared/method-guard-BG_vJNTl.mjs +1 -0
- package/dist/packem_shared/observability-DgurIZIR.mjs +1 -0
- package/dist/packem_shared/origin-paywall-B6eOO67m.mjs +1 -0
- package/dist/packem_shared/otlp-resource-BwFJnvwB.mjs +1 -0
- package/dist/packem_shared/parseStackFrames-CZddjveh.mjs +2 -0
- package/dist/packem_shared/pipeline-log-reader-C-nuWG_e.mjs +1 -0
- package/dist/packem_shared/portable-json-CSq6T1AU.mjs +1 -0
- package/dist/packem_shared/rest-cache-CmHN871W.mjs +1 -0
- package/dist/packem_shared/rest-routes-DQkyqlym.mjs +1 -0
- package/dist/packem_shared/toAirbyteMessages-DY0vsuEn.mjs +1 -0
- package/package.json +10 -2
- package/dist/packem_shared/DEFAULT_REGISTRY_CACHE_TTL_MS-B3pA7aXp.mjs +0 -79
- package/dist/packem_shared/LunoraError-Bpb9EFJ3.mjs +0 -22
- package/dist/packem_shared/NOOP_EXECUTION_CONTEXT-CCTu0Bf1.mjs +0 -8
- package/dist/packem_shared/analyticsEngineSink-DqEvrQs0.mjs +0 -141
- package/dist/packem_shared/applyJurisdiction-BkZtTkct.mjs +0 -20
- package/dist/packem_shared/composeIdentityResolvers-XGjO7V1J.mjs +0 -55
- package/dist/packem_shared/composeWorker-Dpw9d1s5.mjs +0 -3117
- package/dist/packem_shared/createCrossShardRelationCapabilities-CbcWjkAn.mjs +0 -63
- package/dist/packem_shared/createQueryCoordinator-DNCJzOZE.mjs +0 -847
- package/dist/packem_shared/decorateResponse-CsZc49QC.mjs +0 -266
- package/dist/packem_shared/emitLogEvent-pEdtqAK8.mjs +0 -20
- package/dist/packem_shared/toAirbyteMessages-DrHdplb4.mjs +0 -39
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{c as O,d as k,e as P,a as B,f as j}from"./rest-cache-CmHN871W.mjs";import{LunoraError as h}from"./LunoraError-DksAgIpa.mjs";import{m as x}from"./method-guard-BG_vJNTl.mjs";const D=async(e,r)=>{if(!e.body)return"";const t=e.body.getReader(),o=new TextDecoder;let s=0,c="";for(;;){const{done:n,value:a}=await t.read();if(n)break;if(a){if(s+=a.byteLength,s>r)return await t.cancel().catch(()=>{}),null;c+=o.decode(a,{stream:!0})}}return c+=o.decode(),c},p=1048576,L=e=>typeof e=="object"&&e!==null&&!Array.isArray(e),C=async(e,r=p)=>{const t=await D(e,r);if(t===null)throw new h("Body too large",{code:"PAYLOAD_TOO_LARGE",status:413});return t},re=async(e,r=p)=>{if(!e.body)return new ArrayBuffer(0);const t=e.body.getReader(),o=[];let s=0;for(;;){const{done:a,value:i}=await t.read();if(a)break;if(i){if(s+=i.byteLength,s>r)throw await t.cancel().catch(()=>{}),new h("Body too large",{code:"PAYLOAD_TOO_LARGE",status:413});o.push(i)}}const c=new Uint8Array(s);let n=0;for(const a of o)c.set(a,n),n+=a.byteLength;return c.buffer},ae=(e,r=p)=>{const t=e.body;let o=!1;if(t===null)return{overflowed:()=>o,request:e};let s,c=0;const n=new ReadableStream({cancel:async a=>{await(s??t).cancel(a)},pull:async a=>{s??=t.getReader();const{done:i,value:d}=await s.read();if(i){a.close();return}if(c+=d.byteLength,c>r){o=!0,a.error(new h("Body too large",{code:"PAYLOAD_TOO_LARGE",status:413})),s.cancel().catch(()=>{});return}a.enqueue(d)}},{highWaterMark:0});return{overflowed:()=>o,request:new Request(e,{body:n,duplex:"half"})}},U=async(e,r,t=p)=>{try{const o=await C(e,t);return o===""?{}:JSON.parse(o)}catch(o){throw o instanceof h?o:new h(`${r} body must be valid JSON`,{code:"BAD_REQUEST",status:400})}},oe=async(e,r=p)=>{const t=await U(e,"Request",r);if(!L(t))throw new h("Request body must be an object",{code:"BAD_REQUEST",status:400});return t},G=(e,r)=>{if(!L(e))throw new h(`${r} \`args\` must be an object`,{code:"BAD_REQUEST",status:400})},I=/^[\d.:a-f]+$/iu,N=e=>{const r=e.indexOf("%"),t=r===-1?e:e.slice(0,r);if(!t.includes(":")||!I.test(t))return e;let o;try{o=new URL(`http://[${t}]/`).hostname.slice(1,-1)}catch{return e}const[s="",c]=o.split("::"),n=s===""?[]:s.split(":"),a=c===void 0||c===""?[]:c.split(":"),i=[...n,...Array.from({length:8-n.length-a.length},()=>"0"),...a].map(d=>Number.parseInt(d,16));if(i.slice(0,5).every(d=>d===0)&&i[5]===65535){const[d=0,u=0]=i.slice(6);return[d>>8,d&255,u>>8,u&255].join(".")}return`${i.slice(0,4).map(d=>d.toString(16)).join(":")}::/64`},g="__lunora_vary",M="x-lunora-edge-cache",$=["x-d1-bookmark","x-lunora-shard-key"],H=()=>{try{return globalThis.caches?.default}catch{return}},S=e=>e.split(",").map(r=>r.trim().toLowerCase()).filter(r=>r!==""),K=(e,r)=>{const t=e.headers.get("vary");return t===null?!0:S(t).every(o=>o!=="*"&&r.includes(o))},Y=(e,r)=>{if(e===void 0||r===null||e.scope!=="public"||O(e.maxAge)<=0)return;const t=()=>r??H(),o=S(k(e)??""),s=n=>{const a=new URL(n.url);return a.searchParams.delete(g),o.length>0&&a.searchParams.set(g,o.map(i=>`${i}=${n.headers.get(i)??""}`).join("\0")),new Request(a.toString(),{method:"GET"})},c=(n,a)=>n.method==="GET"&&P(e,n,a)==="public";return{lookup:async(n,a)=>{const i=t();if(i===void 0||!c(n,a))return;let d;try{d=await i.match(s(n))}catch{return}if(d===void 0)return;const u=new Response(d.body,d);return u.headers.set(M,"hit"),u},store:(n,a,i)=>{const d=t();if(d===void 0||!c(a,i)||n.status!==200||n.headers.has("set-cookie")||n.headers.has("payment-response")||n.headers.has("x-payment-response")||!K(n,o))return n;try{const u=new Response(n.clone().body,n);for(const l of $)u.headers.delete(l);const f=Promise.resolve(d.put(s(a),u)).catch(()=>{});i?.waitUntil&&i.waitUntil(f)}catch{}return n}}},F=()=>globalThis.navigator?.userAgent==="Cloudflare-Workers",J=(e,r)=>{if(F())return e.get("cf-connecting-ip")??void 0;if(r===void 0)return;const t=e.get(r)?.trim();return t===void 0||t===""||t.includes(",")?void 0:t},Q=(e,r)=>{if(r.x402!==void 0&&r.expose?.cache?.scope==="public")throw new h(`REST route "${e}" is paid (.x402) but declares \`cache: { scope: "public" }\`: a shared cache would replay the paid response to callers who never paid. Use \`scope: "private"\` or drop the cache policy.`,{code:"MISCONFIGURED",status:500})},W=e=>j(Object.entries(e).map(([r,t])=>({exposure:t.expose,functionPath:r,kind:t.kind}))),V=(e,r)=>{const t=e.searchParams.get("shardKey");if(t!==null&&t!=="")return t;const o=r.headers.get("x-lunora-shard-key");return o===null||o===""?void 0:o},X=e=>{const r=Object.create(null);for(const[t,o]of e.searchParams.entries())if(!(t==="shardKey"||t===g))try{r[t]=JSON.parse(o)}catch{r[t]=o}return r},ne=e=>{const{edgeCache:r,functions:t,invoke:o,rateLimit:s,readJsonBody:c}=e,n={};for(const a of W(t)){const i=a.kind==="query"?["GET","POST"]:["POST"],d=t[a.functionPath];Q(a.functionPath,d);const u=d.expose?.cache,f=Y(u,r);n[a.path]=async(l,T,Z,y)=>{const R=x(l,i);if(R)return R;const v=new URL(l.url);if(s){const m=await s(l,a.functionPath);if(m)return m}const b=await f?.lookup(l,y);if(b)return b;let w;l.method==="GET"?w=X(v):w=l.body===null?{}:await c(l),G(w,"REST");const E=V(v,l),_=await o({args:w,env:T,functionPath:a.functionPath,request:l,...E===void 0?{}:{shardKey:E},...y?.waitUntil===void 0?{}:{waitUntil:m=>y.waitUntil?.(m)}}),A=B(_,u,l,y);return f?f.store(A,l,y):A}}return n},z=()=>Response.json({error:{code:"INTERNAL",message:"REST rate limit: no caller key could be resolved. Declare `trustedClientIpHeader` (a header your proxy stamps and callers cannot write), or pass `key` to identify callers by something unforgeable."}},{headers:{"content-type":"application/json"},status:500}),se=(e,r)=>async(t,o)=>{let s;if(r.key)s=r.key(t,o);else{const a=J(t.headers,r.trustedClientIpHeader);s=a===void 0?void 0:N(a)}if(s===void 0||s==="")return z();const c=await e.limit(r.name,{key:s});if(c.ok)return;if(c.reason==="deny")return Response.json({error:{code:"FORBIDDEN",message:"Request denied"}},{headers:{"content-type":"application/json"},status:403});const n=Math.max(1,Math.ceil(c.retryAfter/1e3));return Response.json({error:{code:"RATE_LIMITED",message:"Rate limit exceeded"}},{headers:{"content-type":"application/json","retry-after":String(n)},status:429})};export{p as M,X as a,ne as b,se as c,oe as d,U as e,re as f,G as g,C as h,W as r,J as t,ae as w};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{t as b}from"./portable-json-CSq6T1AU.mjs";const p="_id",f=(t,n=p)=>{const o=Object.create(null),s=Object.create(null),c=Object.create(null),a=Object.create(null),h=e=>typeof n=="string"?n:n[e]??p,l=(e,r)=>{const u=e[r];if(u)return u;const d=[];return e[r]=d,d};for(const e of t.changes){a[e.table]??={primary_key:[h(e.table)]};const r=b(e.doc);e.op==="delete"?l(c,e.table).push(r):e.op==="update"?l(s,e.table).push(r):l(o,e.table).push(r)}return{delete:c,hasMore:t.hasMore,insert:o,schema:a,state:{cursor:t.nextCursor},update:s}},m=(t,n=Date.now())=>{const o=[];for(const s of t.changes){const c=b(s.doc),a=s.op==="delete"?{...c,_lunora_deleted:!0}:c;o.push({record:{data:a,emitted_at:n,stream:s.table},type:"RECORD"})}return o.push({state:{data:{cursor:t.nextCursor}},type:"STATE"}),o};export{m as toAirbyteMessages,f as toFivetranResponse};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lunora/runtime",
|
|
3
|
-
"version": "1.0.0-alpha.
|
|
3
|
+
"version": "1.0.0-alpha.221",
|
|
4
4
|
"description": "Lunora Worker runtime: the RPC router, shard resolver, and query coordinator",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"cloudflare",
|
|
@@ -46,7 +46,15 @@
|
|
|
46
46
|
"access": "public"
|
|
47
47
|
},
|
|
48
48
|
"dependencies": {
|
|
49
|
-
"@lunora/
|
|
49
|
+
"@lunora/bindings": "1.0.0-alpha.125",
|
|
50
|
+
"@lunora/errors": ">=1.0.0-alpha.51 <2.0.0-0",
|
|
51
|
+
"@lunora/observability": "1.0.0-alpha.155",
|
|
52
|
+
"@lunora/platform": "1.0.0-alpha.70",
|
|
53
|
+
"@lunora/wire": "1.0.0-alpha.1"
|
|
54
|
+
},
|
|
55
|
+
"peerDependencies": {
|
|
56
|
+
"@lunora/shard-engine": ">=1.0.0-alpha.24 <2.0.0-0",
|
|
57
|
+
"@lunora/workflow": ">=1.0.0-alpha.24 <2.0.0-0"
|
|
50
58
|
},
|
|
51
59
|
"engines": {
|
|
52
60
|
"node": "^22.15.0 || >=24.11.0"
|
|
@@ -1,79 +0,0 @@
|
|
|
1
|
-
import { LunoraError } from './LunoraError-Bpb9EFJ3.mjs';
|
|
2
|
-
import { applyJurisdiction } from './applyJurisdiction-BkZtTkct.mjs';
|
|
3
|
-
|
|
4
|
-
const SHARD_REGISTRY_DO_NAME = "__lunora_shard_registry__";
|
|
5
|
-
const DEFAULT_REGISTRY_CACHE_TTL_MS = 3e4;
|
|
6
|
-
const REGISTRY_BASE_URL = "https://shard-registry.internal";
|
|
7
|
-
const decodeJson = async (response) => (
|
|
8
|
-
// Response.json() throws on non-JSON; the DO always returns JSON so this
|
|
9
|
-
// only surfaces if the DO route is misbehaving — let it bubble.
|
|
10
|
-
await response.json()
|
|
11
|
-
);
|
|
12
|
-
const createDynamicShardRegistry = (options) => {
|
|
13
|
-
const instanceName = options.instanceName ?? SHARD_REGISTRY_DO_NAME;
|
|
14
|
-
const cacheTtlMs = options.cacheTtlMs ?? DEFAULT_REGISTRY_CACHE_TTL_MS;
|
|
15
|
-
const cache = /* @__PURE__ */ new Map();
|
|
16
|
-
const namespace = applyJurisdiction(options.namespace, options.jurisdiction);
|
|
17
|
-
let cachedStub;
|
|
18
|
-
const stub = () => {
|
|
19
|
-
cachedStub ??= namespace.get(namespace.idFromName(instanceName));
|
|
20
|
-
return cachedStub;
|
|
21
|
-
};
|
|
22
|
-
const post = async (path, body) => stub().fetch(
|
|
23
|
-
new Request(`${REGISTRY_BASE_URL}${path}`, {
|
|
24
|
-
body: JSON.stringify(body),
|
|
25
|
-
headers: { "content-type": "application/json" },
|
|
26
|
-
method: "POST"
|
|
27
|
-
})
|
|
28
|
-
);
|
|
29
|
-
const get = async (path) => stub().fetch(new Request(`${REGISTRY_BASE_URL}${path}`, { method: "GET" }));
|
|
30
|
-
return {
|
|
31
|
-
invalidate(table) {
|
|
32
|
-
if (table === void 0) {
|
|
33
|
-
cache.clear();
|
|
34
|
-
} else {
|
|
35
|
-
cache.delete(table);
|
|
36
|
-
}
|
|
37
|
-
},
|
|
38
|
-
async listShardKeys(table) {
|
|
39
|
-
const now = Date.now();
|
|
40
|
-
const cached = cache.get(table);
|
|
41
|
-
if (cached && cached.expiresAt > now) {
|
|
42
|
-
return cached.shardKeys;
|
|
43
|
-
}
|
|
44
|
-
const response = await get(`/list?table=${encodeURIComponent(table)}`);
|
|
45
|
-
if (!response.ok) {
|
|
46
|
-
throw new LunoraError(`shard registry /list returned ${String(response.status)}`);
|
|
47
|
-
}
|
|
48
|
-
const { shardKeys } = await decodeJson(response);
|
|
49
|
-
if (cacheTtlMs > 0) {
|
|
50
|
-
cache.set(table, { expiresAt: now + cacheTtlMs, shardKeys });
|
|
51
|
-
}
|
|
52
|
-
return shardKeys;
|
|
53
|
-
},
|
|
54
|
-
async register(table, shardKey) {
|
|
55
|
-
const response = await post("/register", { shardKey, table });
|
|
56
|
-
if (!response.ok) {
|
|
57
|
-
throw new LunoraError(`shard registry /register returned ${String(response.status)}`);
|
|
58
|
-
}
|
|
59
|
-
cache.delete(table);
|
|
60
|
-
},
|
|
61
|
-
async snapshot() {
|
|
62
|
-
const response = await get("/snapshot");
|
|
63
|
-
if (!response.ok) {
|
|
64
|
-
throw new LunoraError(`shard registry /snapshot returned ${String(response.status)}`);
|
|
65
|
-
}
|
|
66
|
-
const { tables } = await decodeJson(response);
|
|
67
|
-
return tables;
|
|
68
|
-
},
|
|
69
|
-
async unregister(table, shardKey) {
|
|
70
|
-
const response = await post("/unregister", { shardKey, table });
|
|
71
|
-
if (!response.ok) {
|
|
72
|
-
throw new LunoraError(`shard registry /unregister returned ${String(response.status)}`);
|
|
73
|
-
}
|
|
74
|
-
cache.delete(table);
|
|
75
|
-
}
|
|
76
|
-
};
|
|
77
|
-
};
|
|
78
|
-
|
|
79
|
-
export { DEFAULT_REGISTRY_CACHE_TTL_MS, SHARD_REGISTRY_DO_NAME, createDynamicShardRegistry };
|
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
import { LunoraError as LunoraError$1, toErrorBody } from '@lunora/errors';
|
|
2
|
-
|
|
3
|
-
const toErrorResponse = (error) => {
|
|
4
|
-
const { body, redacted, status } = toErrorBody(error, { fallbackCode: "INTERNAL", redactedMessage: "Internal error" });
|
|
5
|
-
if (redacted) {
|
|
6
|
-
console.error("[lunora] internal error:", error);
|
|
7
|
-
}
|
|
8
|
-
return Response.json({ error: body }, {
|
|
9
|
-
headers: { "content-type": "application/json" },
|
|
10
|
-
status
|
|
11
|
-
});
|
|
12
|
-
};
|
|
13
|
-
class LunoraError extends LunoraError$1 {
|
|
14
|
-
constructor(message, options) {
|
|
15
|
-
super(options?.code ?? "INTERNAL", message, { cause: options?.cause, status: options?.status });
|
|
16
|
-
}
|
|
17
|
-
toResponse() {
|
|
18
|
-
return toErrorResponse(this);
|
|
19
|
-
}
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
export { LunoraError, toErrorResponse };
|
|
@@ -1,141 +0,0 @@
|
|
|
1
|
-
const shouldSkip = (event, onlyErrors) => onlyErrors === true && event.ok;
|
|
2
|
-
const mergeHeaders = (defaults, overrides) => {
|
|
3
|
-
if (!overrides) {
|
|
4
|
-
return { ...defaults };
|
|
5
|
-
}
|
|
6
|
-
const merged = {};
|
|
7
|
-
const seen = /* @__PURE__ */ new Map();
|
|
8
|
-
for (const [name, value] of Object.entries(defaults)) {
|
|
9
|
-
const lower = name.toLowerCase();
|
|
10
|
-
seen.set(lower, name);
|
|
11
|
-
merged[name] = value;
|
|
12
|
-
}
|
|
13
|
-
for (const [name, value] of Object.entries(overrides)) {
|
|
14
|
-
const lower = name.toLowerCase();
|
|
15
|
-
const existing = seen.get(lower);
|
|
16
|
-
if (existing === void 0) {
|
|
17
|
-
seen.set(lower, name);
|
|
18
|
-
merged[name] = value;
|
|
19
|
-
} else {
|
|
20
|
-
merged[existing] = value;
|
|
21
|
-
}
|
|
22
|
-
}
|
|
23
|
-
return merged;
|
|
24
|
-
};
|
|
25
|
-
const consoleSink = (options = {}) => {
|
|
26
|
-
const { onlyErrors } = options;
|
|
27
|
-
return {
|
|
28
|
-
onLog: (event) => {
|
|
29
|
-
if (event.level === "error") {
|
|
30
|
-
console.error("[lunora:log]", event.functionPath, event.message);
|
|
31
|
-
} else {
|
|
32
|
-
console.log("[lunora:log]", event.functionPath, event.message);
|
|
33
|
-
}
|
|
34
|
-
},
|
|
35
|
-
onRpc: (event) => {
|
|
36
|
-
if (shouldSkip(event, onlyErrors)) {
|
|
37
|
-
return;
|
|
38
|
-
}
|
|
39
|
-
if (event.ok) {
|
|
40
|
-
console.log("[lunora:rpc]", event);
|
|
41
|
-
} else {
|
|
42
|
-
console.error("[lunora:rpc]", event);
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
};
|
|
46
|
-
};
|
|
47
|
-
const webhookSink = (options) => {
|
|
48
|
-
const { headers, onlyErrors, transform, url } = options;
|
|
49
|
-
const mergedHeaders = mergeHeaders({ "content-type": "application/json" }, headers);
|
|
50
|
-
return {
|
|
51
|
-
onRpc: (event, context) => {
|
|
52
|
-
if (shouldSkip(event, onlyErrors)) {
|
|
53
|
-
return;
|
|
54
|
-
}
|
|
55
|
-
try {
|
|
56
|
-
let payload = event;
|
|
57
|
-
if (transform) {
|
|
58
|
-
try {
|
|
59
|
-
payload = transform(event);
|
|
60
|
-
} catch {
|
|
61
|
-
return;
|
|
62
|
-
}
|
|
63
|
-
}
|
|
64
|
-
if (payload === null || payload === void 0) {
|
|
65
|
-
return;
|
|
66
|
-
}
|
|
67
|
-
const sent = fetch(url, {
|
|
68
|
-
body: JSON.stringify(payload),
|
|
69
|
-
headers: mergedHeaders,
|
|
70
|
-
method: "POST"
|
|
71
|
-
}).catch(() => {
|
|
72
|
-
});
|
|
73
|
-
if (context?.waitUntil) {
|
|
74
|
-
context.waitUntil(sent);
|
|
75
|
-
}
|
|
76
|
-
} catch {
|
|
77
|
-
}
|
|
78
|
-
}
|
|
79
|
-
};
|
|
80
|
-
};
|
|
81
|
-
const sentrySink = (options) => {
|
|
82
|
-
const { capture } = options;
|
|
83
|
-
const onlyErrors = options.onlyErrors ?? true;
|
|
84
|
-
return {
|
|
85
|
-
onRpc: (event) => {
|
|
86
|
-
if (shouldSkip(event, onlyErrors)) {
|
|
87
|
-
return;
|
|
88
|
-
}
|
|
89
|
-
try {
|
|
90
|
-
capture(event);
|
|
91
|
-
} catch {
|
|
92
|
-
}
|
|
93
|
-
}
|
|
94
|
-
};
|
|
95
|
-
};
|
|
96
|
-
const analyticsEngineSink = (options) => {
|
|
97
|
-
const { dataset, onlyErrors } = options;
|
|
98
|
-
return {
|
|
99
|
-
onRpc: (event) => {
|
|
100
|
-
if (shouldSkip(event, onlyErrors)) {
|
|
101
|
-
return;
|
|
102
|
-
}
|
|
103
|
-
try {
|
|
104
|
-
dataset.writeDataPoint({
|
|
105
|
-
blobs: [event.functionPath, event.ok ? "ok" : "error", event.shardKey ?? "", event.error?.code ?? "", event.fanOut?.table ?? ""],
|
|
106
|
-
doubles: [event.durationMs, event.ok ? 0 : 1, event.fanOut?.shards ?? 0, event.fanOut?.failed ?? 0],
|
|
107
|
-
indexes: [event.functionPath]
|
|
108
|
-
});
|
|
109
|
-
} catch {
|
|
110
|
-
}
|
|
111
|
-
}
|
|
112
|
-
};
|
|
113
|
-
};
|
|
114
|
-
const combineSinks = (...sinks) => {
|
|
115
|
-
return {
|
|
116
|
-
onLog: (event, context) => {
|
|
117
|
-
for (const sink of sinks) {
|
|
118
|
-
if (!sink.onLog) {
|
|
119
|
-
continue;
|
|
120
|
-
}
|
|
121
|
-
try {
|
|
122
|
-
sink.onLog(event, context);
|
|
123
|
-
} catch {
|
|
124
|
-
}
|
|
125
|
-
}
|
|
126
|
-
},
|
|
127
|
-
onRpc: (event, context) => {
|
|
128
|
-
for (const sink of sinks) {
|
|
129
|
-
if (!sink.onRpc) {
|
|
130
|
-
continue;
|
|
131
|
-
}
|
|
132
|
-
try {
|
|
133
|
-
sink.onRpc(event, context);
|
|
134
|
-
} catch {
|
|
135
|
-
}
|
|
136
|
-
}
|
|
137
|
-
}
|
|
138
|
-
};
|
|
139
|
-
};
|
|
140
|
-
|
|
141
|
-
export { analyticsEngineSink, combineSinks, consoleSink, sentrySink, webhookSink };
|
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
const applyJurisdiction = (namespace, jurisdiction) => {
|
|
2
|
-
if (jurisdiction === void 0) {
|
|
3
|
-
return namespace;
|
|
4
|
-
}
|
|
5
|
-
if (typeof namespace.jurisdiction !== "function") {
|
|
6
|
-
throw new TypeError(
|
|
7
|
-
`@lunora/runtime: Durable Object namespace does not support jurisdiction("${jurisdiction}") — update @cloudflare/workers-types or remove the jurisdiction option`
|
|
8
|
-
);
|
|
9
|
-
}
|
|
10
|
-
return namespace.jurisdiction(jurisdiction);
|
|
11
|
-
};
|
|
12
|
-
const resolveShard = (namespace, shardKey) => {
|
|
13
|
-
if (typeof namespace.getByName === "function") {
|
|
14
|
-
return namespace.getByName(shardKey);
|
|
15
|
-
}
|
|
16
|
-
const id = namespace.idFromName(shardKey);
|
|
17
|
-
return namespace.get(id);
|
|
18
|
-
};
|
|
19
|
-
|
|
20
|
-
export { applyJurisdiction, resolveShard };
|
|
@@ -1,55 +0,0 @@
|
|
|
1
|
-
import { LunoraError } from './LunoraError-Bpb9EFJ3.mjs';
|
|
2
|
-
|
|
3
|
-
const composeIdentityResolvers = (resolvers, options = {}) => {
|
|
4
|
-
const onError = options.onError ?? "fail-closed";
|
|
5
|
-
return async (request, env) => {
|
|
6
|
-
for (const resolver of resolvers) {
|
|
7
|
-
let resolved;
|
|
8
|
-
try {
|
|
9
|
-
resolved = await resolver(request, env);
|
|
10
|
-
} catch (error) {
|
|
11
|
-
if (onError === "skip") {
|
|
12
|
-
continue;
|
|
13
|
-
}
|
|
14
|
-
throw error;
|
|
15
|
-
}
|
|
16
|
-
if (resolved) {
|
|
17
|
-
return resolved;
|
|
18
|
-
}
|
|
19
|
-
}
|
|
20
|
-
return null;
|
|
21
|
-
};
|
|
22
|
-
};
|
|
23
|
-
const routeIdentityResolvers = (routes) => {
|
|
24
|
-
const prefixes = Object.keys(routes).filter((key) => key !== "*").toSorted((a, b) => b.length - a.length);
|
|
25
|
-
return (request, env) => {
|
|
26
|
-
const { pathname } = new URL(request.url);
|
|
27
|
-
const matched = prefixes.find((prefix) => pathname === prefix || pathname.startsWith(prefix.endsWith("/") ? prefix : `${prefix}/`));
|
|
28
|
-
const resolver = matched === void 0 ? routes["*"] : routes[matched];
|
|
29
|
-
if (resolver === void 0) {
|
|
30
|
-
return null;
|
|
31
|
-
}
|
|
32
|
-
return resolver(request, env);
|
|
33
|
-
};
|
|
34
|
-
};
|
|
35
|
-
const wrapResolverWithContract = (baseResolveIdentity, contract) => {
|
|
36
|
-
if (contract === void 0 || baseResolveIdentity === void 0) {
|
|
37
|
-
return baseResolveIdentity;
|
|
38
|
-
}
|
|
39
|
-
return async (request, env) => {
|
|
40
|
-
const resolved = await baseResolveIdentity(request, env);
|
|
41
|
-
if (!resolved) {
|
|
42
|
-
return resolved;
|
|
43
|
-
}
|
|
44
|
-
const result = contract.validate(resolved);
|
|
45
|
-
if (result.ok) {
|
|
46
|
-
return resolved;
|
|
47
|
-
}
|
|
48
|
-
if (contract.onInvalid === "reject") {
|
|
49
|
-
throw new LunoraError(`identity claims failed the declared contract: ${result.error}`, { code: "UNAUTHENTICATED", status: 401 });
|
|
50
|
-
}
|
|
51
|
-
return null;
|
|
52
|
-
};
|
|
53
|
-
};
|
|
54
|
-
|
|
55
|
-
export { composeIdentityResolvers, routeIdentityResolvers, wrapResolverWithContract };
|