@lunora/runtime 1.0.0-alpha.26 → 1.0.0-alpha.261

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 (59) hide show
  1. package/LICENSE.md +120 -0
  2. package/README.md +52 -10
  3. package/dist/index.d.mts +4555 -1618
  4. package/dist/index.d.ts +4555 -1618
  5. package/dist/index.mjs +1 -16
  6. package/dist/packem_shared/BACKUP_KEY_PREFIX-BOtSu-_3.mjs +1 -0
  7. package/dist/packem_shared/DEFAULT_LOG_COLUMNS-gYMhXLzO.mjs +1 -0
  8. package/dist/packem_shared/DEFAULT_REGISTRY_CACHE_TTL_MS-w_RLPiwj.mjs +2 -0
  9. package/dist/packem_shared/HEALTH_PATH-B8ndDG3s.mjs +1 -0
  10. package/dist/packem_shared/LOG_ARCHIVE_NOT_CONFIGURED-CDpi4yFD.mjs +1 -0
  11. package/dist/packem_shared/LOG_ARCHIVE_PATH-dTuCzfyj.mjs +1 -0
  12. package/dist/packem_shared/LunoraError-PkZWF-_g.mjs +1 -0
  13. package/dist/packem_shared/NOOP_EXECUTION_CONTEXT-YmXqH-jH.mjs +1 -0
  14. package/dist/packem_shared/STORAGE_UPLOAD_MAX_BODY_BYTES-DiZho96u.mjs +1 -0
  15. package/dist/packem_shared/analyticsEngineSink-s5j-3P1X.mjs +1 -0
  16. package/dist/packem_shared/applyJurisdiction-DKQE8kOA.mjs +1 -0
  17. package/dist/packem_shared/applyRestCache-CEcBz3qq.mjs +1 -0
  18. package/dist/packem_shared/argsFromQuery-C8Ox3sr1.mjs +1 -0
  19. package/dist/packem_shared/base64-Bl1_r2k1.mjs +1 -0
  20. package/dist/packem_shared/composeIdentityResolvers-CpdHuDyk.mjs +1 -0
  21. package/dist/packem_shared/composeWorker-DgrKHFdI.mjs +37 -0
  22. package/dist/packem_shared/createCrossShardRelationCapabilities-DRYvyR4Y.mjs +1 -0
  23. package/dist/packem_shared/createKvCursorStore-Bkn5pilz.mjs +1 -0
  24. package/dist/packem_shared/createQueryCoordinator-D3Pz-Jdr.mjs +1 -0
  25. package/dist/packem_shared/createShardClient-rKSKWKAG.mjs +1 -0
  26. package/dist/packem_shared/declareAppJurisdiction-DEba2p42.mjs +1 -0
  27. package/dist/packem_shared/decorateResponse-CdelJSUs.mjs +1 -0
  28. package/dist/packem_shared/emitLogEvent-CdybnWG8.mjs +1 -0
  29. package/dist/packem_shared/enrichSink-44NOapaE.mjs +1 -0
  30. package/dist/packem_shared/error-detail-C46mdOTW.mjs +1 -0
  31. package/dist/packem_shared/export-tap-C2B_SATf.mjs +3 -0
  32. package/dist/packem_shared/identity-header-ByHiZBcH.mjs +1 -0
  33. package/dist/packem_shared/memoize-identity-DFkwm3x6.mjs +1 -0
  34. package/dist/packem_shared/memoizeIdentity-C4BJchsg.mjs +1 -0
  35. package/dist/packem_shared/method-guard-8Jo4Q8uS.mjs +1 -0
  36. package/dist/packem_shared/observability-9slk__Gi.mjs +1 -0
  37. package/dist/packem_shared/observability-sinks-lLKqc_rV.mjs +4 -0
  38. package/dist/packem_shared/origin-paywall-B6eOO67m.mjs +1 -0
  39. package/dist/packem_shared/otlp-resource-Ch_8_U0e.mjs +1 -0
  40. package/dist/packem_shared/parseStackFrames-CZddjveh.mjs +2 -0
  41. package/dist/packem_shared/pipeline-log-reader-C-nuWG_e.mjs +1 -0
  42. package/dist/packem_shared/portable-json-CSq6T1AU.mjs +1 -0
  43. package/dist/packem_shared/rest-cache-CmHN871W.mjs +1 -0
  44. package/dist/packem_shared/rest-routes-CDQ1F7kI.mjs +1 -0
  45. package/dist/packem_shared/toAirbyteMessages-DY0vsuEn.mjs +1 -0
  46. package/package.json +10 -2
  47. package/dist/packem_shared/DEFAULT_REGISTRY_CACHE_TTL_MS-B3pA7aXp.mjs +0 -79
  48. package/dist/packem_shared/LunoraError-Bpb9EFJ3.mjs +0 -22
  49. package/dist/packem_shared/NOOP_EXECUTION_CONTEXT-CCTu0Bf1.mjs +0 -8
  50. package/dist/packem_shared/analyticsEngineSink-F-5ZAdUA.mjs +0 -200
  51. package/dist/packem_shared/applyJurisdiction-BkZtTkct.mjs +0 -20
  52. package/dist/packem_shared/composeIdentityResolvers-XGjO7V1J.mjs +0 -55
  53. package/dist/packem_shared/composeWorker-BMxMYwKq.mjs +0 -3175
  54. package/dist/packem_shared/createCrossShardRelationCapabilities-CbcWjkAn.mjs +0 -63
  55. package/dist/packem_shared/createQueryCoordinator-DNCJzOZE.mjs +0 -847
  56. package/dist/packem_shared/decorateResponse-DRWQFNhF.mjs +0 -273
  57. package/dist/packem_shared/emitLogEvent-pEdtqAK8.mjs +0 -20
  58. package/dist/packem_shared/otlp-D_YzGXu1.mjs +0 -81
  59. package/dist/packem_shared/toAirbyteMessages-DrHdplb4.mjs +0 -39
@@ -0,0 +1 @@
1
+ import{m as i,a as o,b as a}from"./memoize-identity-DFkwm3x6.mjs";import"./identity-header-ByHiZBcH.mjs";export{i as memoizeIdentity,o as memoizeIdentityPerRequest,a as memoizedIdentityHeader};
@@ -0,0 +1 @@
1
+ import{LunoraError as t}from"./LunoraError-PkZWF-_g.mjs";const n=(e,o)=>o.includes(e.method)?void 0:new Response(void 0,{headers:{allow:o.join(", ")},status:405}),a=(e,o,s)=>{if(e.method!==o)throw new t(`${s} endpoint requires ${o}`,{code:"METHOD_NOT_ALLOWED",status:405})};export{a,n as m};
@@ -0,0 +1 @@
1
+ import{redactCredentials as s}from"@lunora/observability";import{t as i}from"./error-detail-C46mdOTW.mjs";const h="x-lunora-sample-errors",o=1,u=r=>{const t=Number.parseInt(r.slice(-8),16);return Number.isFinite(t)?t/4294967296:0},d=(r,t=o)=>{const e=Number.isFinite(t)?t:o;return e>=1?!0:e<=0?!1:u(r)<e},l=(r,t)=>({isTraced:d(t,r?.headRate??o),keepErrors:r?.alwaysSampleErrors??!0}),p=(r,t)=>r.isTraced||r.keepErrors&&t,E=r=>{const t=i(r);return t===void 0?void 0:s(t)},f=r=>{if(r.error===void 0)return r;let t;try{t=r.error.internal}catch{const e=Object.getOwnPropertyDescriptors(r.error);return delete e.internal,{...r,error:Object.create(Object.getPrototypeOf(r.error),e)}}return t===void 0?r:{...r,error:{...r.error,internal:E(t)}}},T=(r,t,e,n,c)=>{if(!r?.onRpc)return;const a=c??(n!==void 0&&t.traceId!==void 0?l(n,t.traceId):void 0);if(!(a!==void 0&&!p(a,!t.ok)))try{r.onRpc(f(t),e)}catch{}},S=(r,t,e)=>{if(r?.onLog)try{r.onLog(t,e)}catch{}},y=(r,t)=>{if(r?.flush)try{r.flush(t)}catch{}};export{h as S,T as a,S as e,y as f,l as r};
@@ -0,0 +1,4 @@
1
+ import{LunoraError as Z}from"@lunora/errors";import{redactCredentials as Q,redactArgs as N}from"@lunora/observability";import{stableStringify as v}from"@lunora/wire";import{e as c,L as m,c as H,o as j,f as I,O as z,g as rr,h as J,w as tr,i as or,j as sr,m as er}from"./otlp-resource-Ch_8_U0e.mjs";import{t as ar}from"./error-detail-C46mdOTW.mjs";const nr=r=>{if(typeof r=="string")return r;if(r instanceof Error)return String(r);try{return JSON.stringify(r)??String(r)}catch{return String(r)}},R=r=>typeof r=="boolean"||typeof r=="number"||typeof r=="string"?r:nr(r),ir=(r,s,t)=>{Object.defineProperty(r,s,{configurable:!0,enumerable:!0,value:t,writable:!0})},Dr=(r,s)=>{if(r===void 0&&s===void 0)return;const t={};if(r!==void 0)for(const[o,e]of Object.entries(r))ir(t,o,R(e));return Object.keys(t).length===0?void 0:t},cr=512,dr=200,ur=r=>{const s=r.maxItems??cr,t=r.maxDelayMs??dr;let o=[],e,i,a;const p=()=>{e!==void 0&&(clearTimeout(e),e=void 0)},g=async()=>{p();const l=o;o=[];const d=a;i=void 0,a=void 0;try{l.length>0&&await r.export(l)}catch{}finally{d?.()}},h=l=>{i===void 0&&(i=new Promise(d=>{a=d}),e=setTimeout(()=>{g()},t)),l?.(i)};return{add:(l,d)=>{for(o.push(l);o.length>s;)o.shift();h(d),o.length>=s&&g()},flush:async l=>{if(o.length===0){p();return}const d=g();return l?.(d),d},get size(){return o.length}}},lr=1,pr=0,fr=new Set(["cloudflare.ray_id","error.type","http.request.method","http.response.status_code","http.route","lunora.error_status","lunora.fanout.failed","lunora.fanout.shards","lunora.fanout.table","lunora.function_path","lunora.ok","lunora.shard_key","server.address","server.port","url.path","url.scheme","user_agent.original"]),mr={errorType:m.errorType,functionPath:m.functionPath,rayId:m.rayId,shardKey:m.shardKey,userId:m.userId},hr=r=>{const s=ar(r);return s===void 0?[]:[c("lunora.error.internal",JSON.stringify(Q(s)))]},G=(r,s,t,o)=>[c("exception.type",r),c("exception.message",s),...t===void 0?[]:[c("exception.stacktrace",t)],...o===void 0?[]:hr(o)],gr=(r,s)=>{const t=[c(m.functionPath,r.functionPath),c(m.ok,r.ok)];if(r.method!==void 0&&t.push(c("http.request.method",r.method)),r.path!==void 0&&t.push(c("url.path",r.path)),t.push(c("http.route",r.functionPath)),r.scheme!==void 0&&t.push(c("url.scheme",r.scheme)),r.host!==void 0&&t.push(c("server.address",r.host)),r.port!==void 0&&t.push(c("server.port",r.port)),r.userAgent!==void 0&&t.push(c("user_agent.original",r.userAgent)),r.shardKey!==void 0&&t.push(c(m.shardKey,r.shardKey)),r.rayId!==void 0&&t.push(c(m.rayId,r.rayId)),t.push(c("http.response.status_code",r.error?.status??200)),r.error&&t.push(c(m.errorType,r.error.code),c("lunora.error_status",r.error.status)),r.fanOut&&t.push(c("lunora.fanout.table",r.fanOut.table),c("lunora.fanout.shards",r.fanOut.shards),c("lunora.fanout.failed",r.fanOut.failed)),r.attributes!==void 0){const e=new Set([...fr,...t.map(a=>a.key)]),i=H(Object.fromEntries(Object.entries(r.attributes).map(([a,p])=>[a,R(p)])));t.push(...i.filter(a=>!e.has(a.key)))}const o={attributes:t,endTimeUnixNano:I(s),kind:z.server,name:r.functionPath,...r.parentSpanId===void 0?{}:{parentSpanId:r.parentSpanId},spanId:r.spanId??j(8),startTimeUnixNano:I(s-r.durationMs),status:r.ok?{code:1}:{code:2,message:r.error?.message??""},traceId:r.traceId??j(16)};return r.traceFlags!==void 0&&(o.flags=r.traceFlags),r.error&&(o.events=[{attributes:G(r.error.code,r.error.message,r.error.stack,r.error.internal),name:"exception",timeUnixNano:I(s)}]),o},x=(r,s)=>{const t=new Map,o=new Set(Object.keys(r).map(e=>mr[e]));for(const[e,i]of Object.entries(s??{}))o.has(e)||t.set(e,c(e,R(i)));return t.set(m.functionPath,c(m.functionPath,r.functionPath)),r.shardKey!==void 0&&t.set(m.shardKey,c(m.shardKey,r.shardKey)),r.userId!==void 0&&t.set(m.userId,c(m.userId,r.userId)),r.rayId!==void 0&&t.set(m.rayId,c(m.rayId,r.rayId)),r.errorType!==void 0&&t.set(m.errorType,c(m.errorType,r.errorType)),[...t.values()]},yr=r=>{const s={attributes:x({errorType:r.error?.type,functionPath:r.functionPath,rayId:r.rayId,shardKey:r.shardKey,userId:r.userId},r.attributes),endTimeUnixNano:I(r.startTs+r.durationMs),flags:r.sampled===!1?pr:lr,kind:z[r.kind??"internal"],name:r.name,parentSpanId:r.parentSpanId,spanId:r.spanId,startTimeUnixNano:I(r.startTs),status:r.ok?{code:1}:{code:2,message:r.error?.message??""},traceId:r.traceId},t=o=>H(Object.fromEntries(Object.entries(o??{}).map(([e,i])=>[e,R(i)])));return r.events!==void 0&&r.events.length>0&&(s.events=r.events.map(o=>({attributes:t(o.attributes),name:o.name,timeUnixNano:I(o.ts)}))),r.links!==void 0&&r.links.length>0&&(s.links=r.links.map(o=>({attributes:t(o.attributes),spanId:o.spanId,traceId:o.traceId}))),s},br=r=>{const s=I(r.ts),t=x({functionPath:r.functionPath,shardKey:r.shardKey},r.attributes),o=r.traceId===void 0?void 0:[{asDouble:r.value,timeUnixNano:s,traceId:r.traceId}],e={asDouble:r.value,attributes:t,...o===void 0?{}:{exemplars:o},timeUnixNano:s};return r.kind==="gauge"?{gauge:{dataPoints:[e]},name:r.name}:r.kind==="histogram"?{histogram:{aggregationTemporality:1,dataPoints:[{attributes:t,bucketCounts:["1"],count:"1",...o===void 0?{}:{exemplars:o},explicitBounds:[],max:r.value,min:r.value,sum:r.value,timeUnixNano:s}]},name:r.name}:{name:r.name,sum:{aggregationTemporality:1,dataPoints:[e],isMonotonic:!0}}},kr=r=>{const s={attributes:x({functionPath:r.functionPath,rayId:r.rayId,shardKey:r.shardKey,userId:r.userId},r.fields),body:{stringValue:r.message},severityNumber:rr[r.level],severityText:r.level.toUpperCase(),timeUnixNano:I(r.ts)};if(r.traceId!==void 0&&(s.traceId=r.traceId),r.spanId!==void 0&&(s.spanId=r.spanId),r.error!==void 0){const t=G(r.error.name,r.error.message,r.error.stack,r.error.internal),o=new Set(t.map(e=>e.key));s.attributes=[...s.attributes.filter(e=>!o.has(e.key)),...t]}return r.eventName!==void 0&&(s.eventName=r.eventName,s.attributes=[...s.attributes.filter(t=>t.key!=="event.name"),c("event.name",r.eventName)]),s},Ir=1024,B=5;let _=0;const Sr=(r,s)=>{if(_>=B)return;_+=1;let t;try{t=new URL(r).host}catch{t="<unparseable endpoint>"}const o=_===B?" Further OTLP rejections are silenced until the isolate restarts.":"";console.error(`[lunora:otlp] collector ${t} rejected the export with HTTP ${String(s)}; the batch is DROPPED (there is no retry).${o}`)},Tr=async r=>{const s=new Blob([r]).stream().pipeThrough(new CompressionStream("gzip"));return new Response(s).arrayBuffer()},W=async(r,s,t,o)=>{try{const e=JSON.stringify(s),{byteLength:i}=new TextEncoder().encode(e),a=(i<Ir?fetch(r,{body:e,headers:t,method:"POST"}):Tr(e).then(p=>fetch(r,{body:p,headers:{...t,"content-encoding":"gzip"},method:"POST"}))).then(p=>{p.ok||Sr(r,p.status)},()=>{});o?.(a),await a}catch{}},Pr=(r,s,t,o)=>{W(r,s,t,o?.waitUntil).catch(()=>{})},E=(r,s)=>s===!0&&r.ok,wr=r=>r.kind==="metric"?void 0:r.event.traceId,Or=r=>{const s=Map.groupBy(r,o=>wr(o)),t=s.get(void 0)??[];return s.delete(void 0),{byTrace:s,untraced:t}},C=5,Er=(r,s,t)=>{if(s===void 0)return r;const{byTrace:o,untraced:e}=Or(r),i=[...e];let a=0,p;for(const[g,h]of o){let l;try{l=s({logs:h.filter(d=>d.kind==="log").map(d=>d.event),rpc:h.filter(d=>d.kind==="rpc").map(d=>d.event),spans:h.filter(d=>d.kind==="span").map(d=>d.event),traceId:g})}catch(d){a+=1,a===1&&(p=d),l=!0}l&&i.push(...h)}return a>0&&t(p,a),i},w=(r,s)=>{let t;try{t=s===void 0?r:s(r)}catch{t=void 0}return t??void 0},Lr=r=>{const s=N(r.message);if(r.stack===void 0)return{...r,message:s};const t=`: ${r.message}`,o=r.stack.indexOf(t),i=r.message!==""&&o!==-1&&!r.stack.slice(0,o).includes(`
2
+ `)?r.stack.slice(o+t.length):r.stack.split(`
3
+ `).filter(a=>a.trimStart().startsWith("at ")).map(a=>`
4
+ ${a}`).join("");return{...r,message:s,stack:`${r.name}: ${s}${i}`}},Rr=r=>({...r,...r.error===void 0?{}:{error:Lr(r.error)},...r.fields===void 0?{}:{fields:N(r.fields)},message:N(r.message)}),V=(r,s,t)=>{if(r.kind==="rpc"){const e=w(r.event,s?.rpc);return e===void 0?void 0:{bucket:"spans",encoded:gr(e,r.endMs)}}if(r.kind==="span"){const e=w(r.event,s?.span);return e===void 0?void 0:{bucket:"spans",encoded:yr(e)}}if(r.kind==="log"){const e=w(t?Rr(r.event):r.event,s?.log);return e===void 0?void 0:{bucket:"logs",encoded:kr(e)}}const o=w(r.event,s?.metric);return o===void 0?void 0:{bucket:"metrics",encoded:br(o)}},Ar=["fuseCloudflareTraces","instrumentDatabase","metricHistory","traceFetch"],Fr=(r={})=>{const{onlyErrors:s}=r;return{onLog:t=>{t.level==="error"||t.level==="fatal"?console.error("[lunora:log]",t.functionPath,t.message):console.log("[lunora:log]",t.functionPath,t.message)},onMetric:t=>{console.log("[lunora:metric]",`${t.name}=${String(t.value)}`,t.kind,t.functionPath)},onRpc:t=>{E(t,s)||(t.ok?console.log("[lunora:rpc]",t):console.error("[lunora:rpc]",t))},onSpan:t=>{const o=t.ok?"ok":`error ${t.error?.type??""}`.trim();console.log("[lunora:span]",t.name,`${String(t.durationMs)}ms`,o,t.functionPath)}}},Kr=r=>{const{headers:s,onlyErrors:t,transform:o,transformLog:e,url:i}=r,a=J({"content-type":"application/json"},s),p=(g,h)=>{try{const l=fetch(i,{body:JSON.stringify(g),headers:a,method:"POST"}).catch(()=>{});h?.waitUntil&&h.waitUntil(l)}catch{}};return{onLog:(g,h)=>{const l=w(g,e);l!==void 0&&p(l,h)},onRpc:(g,h)=>{if(E(g,t))return;const l=w(g,o);l!==void 0&&p(l,h)}}},$r=r=>{const{dataset:s,onlyErrors:t}=r;return{onRpc:o=>{if(!E(o,t))try{s.writeDataPoint({blobs:[o.functionPath,o.ok?"ok":"error",o.shardKey??"",o.error?.code??"",o.fanOut?.table??""],doubles:[o.durationMs,o.ok?0:1,o.fanOut?.shards??0,o.fanOut?.failed??0],indexes:[o.functionPath]})}catch{}}}},jr=r=>{const{pipeline:s,serializeFields:t}=r;return{onLog:(o,e)=>{try{const i={functionPath:o.functionPath,level:o.level,message:o.message,ts:o.ts};o.fields&&(i.fields=t===!0?JSON.stringify(o.fields):o.fields);for(const p of["shardKey","userId","traceId","spanId"])o[p]!==void 0&&(i[p]=o[p]);const a=s.send([i]).catch(()=>{});e?.waitUntil&&e.waitUntil(a)}catch{}}}},Br=r=>{const{batch:s,deploymentEnvironment:t,detectResources:o,endpoint:e,headers:i,onlyErrors:a,postProcessor:p,resourceAttributes:g,serviceNamespace:h,serviceVersion:l,tailSampler:d,token:X}=r,M=r.serviceName??"lunora",U=r.redactLogs??!0;if(s!==!1&&s?.maxItems!==void 0&&(!Number.isInteger(s.maxItems)||s.maxItems<1))throw new Z("ENV_INVALID",`otlpSink: \`batch.maxItems\` must be a positive integer, received ${String(s.maxItems)}.`);const D={...l===void 0?{}:{"service.version":l},...h===void 0?{}:{"service.namespace":h},...t===void 0?{}:{"deployment.environment":t},...g},F=new WeakMap,k=u=>{if(o!==!0||u?.resourceAttributes===void 0)return D;const n=F.get(u);if(n!==void 0)return n;const f=er(u.resourceAttributes(),D);return F.set(u,f),f};let S=e;for(;S.endsWith("/");)S=S.slice(0,-1);const K={logs:{url:`${S}/v1/logs`,wrap:sr},metrics:{url:`${S}/v1/metrics`,wrap:or},spans:{url:`${S}/v1/traces`,wrap:tr}},$=J({"content-type":"application/json"},i,X);let A=0;const Y=(u,n)=>{if(A>=C)return;A+=1;const f=A===C?" Further tailSampler failures from this sink are silenced until the isolate restarts.":"";console.error(`[lunora:otlp] tailSampler threw for ${String(n)} trace(s) in this flush window; keeping them (fail-open), so the sampling policy did NOT apply.${f}`,u)},q=async u=>{const n=Er(u,d,Y),f=new Map;for(const y of n){const b=V(y,p,U);if(b===void 0)continue;const L=v(y.resource);let P=f.get(L);P===void 0&&(P={logs:[],metrics:[],resource:y.resource,spans:[]},f.set(L,P)),P[b.bucket].push(b.encoded)}const T=[];for(const[,y]of f)for(const b of["spans","logs","metrics"])if(y[b].length>0){const{url:L,wrap:P}=K[b];T.push(W(L,P(y[b],"@lunora/runtime",M,y.resource),$))}await Promise.all(T)};if(s===!1){const u=(n,f)=>{const T=V(n,p,U);if(T!==void 0){const{url:y,wrap:b}=K[T.bucket];Pr(y,b(T.encoded,"@lunora/runtime",M,n.resource),$,f)}};return{onLog:(n,f)=>{u({event:n,kind:"log",resource:k(f)},f)},onMetric:(n,f)=>{u({event:n,kind:"metric",resource:k(f)},f)},onRpc:(n,f)=>{E(n,a)||u({endMs:Date.now(),event:n,kind:"rpc",resource:k(f)},f)},onSpan:(n,f)=>{u({event:n,kind:"span",resource:k(f)},f)}}}const O=ur({export:q,...s?.maxDelayMs===void 0?{}:{maxDelayMs:s.maxDelayMs},...s?.maxItems===void 0?{}:{maxItems:s.maxItems}});return{flush:u=>{O.flush(u?.waitUntil).catch(()=>{})},onLog:(u,n)=>{O.add({event:u,kind:"log",resource:k(n)},n?.waitUntil)},onMetric:(u,n)=>{O.add({event:u,kind:"metric",resource:k(n)},n?.waitUntil)},onRpc:(u,n)=>{E(u,a)||O.add({endMs:Date.now(),event:u,kind:"rpc",resource:k(n)},n?.waitUntil)},onSpan:(u,n)=>{O.add({event:u,kind:"span",resource:k(n)},n?.waitUntil)}}},Cr=(...r)=>{const s=(o,e)=>{for(const i of r){const a=i[o];if(a)try{a.apply(i,e)}catch{}}},t={};for(const o of r)for(const e of Ar)t[e]===void 0&&o[e]!==void 0&&(t[e]=o[e]);return{...t,flush:o=>{s("flush",[o])},onLog:(o,e)=>{s("onLog",[o,e])},onMetric:(o,e)=>{s("onMetric",[o,e])},onRpc:(o,e)=>{s("onRpc",[o,e])},onSpan:(o,e)=>{s("onSpan",[o,e])}}};export{Ar as S,$r as a,Fr as b,Cr as c,Dr as n,Br as o,jr as p,Kr as w};
@@ -0,0 +1 @@
1
+ const a="x-lunora-paywall",A="1";export{A as O,a};
@@ -0,0 +1 @@
1
+ const R={debug:5,error:17,fatal:21,info:9,log:9,trace:1,warn:13},N=e=>`${String(Math.round(e))}000000`,A=Array.from({length:256},(e,r)=>r.toString(16).padStart(2,"0")),l=512,O=new Uint8Array(l);let a=l;const m=(e,r,t)=>{let o="";for(let n=0;n<t;n+=1)o+=A[e[r+n]];return o},T=e=>{if(e>l){const t=new Uint8Array(e);return crypto.getRandomValues(t),m(t,0,e)}a+e>l&&(crypto.getRandomValues(O),a=0);const r=m(O,a,e);return a+=e,r},u=/^[0-9a-f]+$/,S=(e,r,t=!0)=>`00-${e}-${r}-${t?"01":"00"}`,I=e=>{if(e==null)return;const r=e.split("-"),[t,o,n,s]=r;if(!(r.length<4||t===void 0||t.length!==2||!u.test(t)||t==="ff"||t==="00"&&r.length!==4||o===void 0||n===void 0||s===void 0||s.length!==2||!u.test(s)||o.length!==32||n.length!==16||!u.test(o)||!u.test(n)||o==="00000000000000000000000000000000"||n==="0000000000000000"))return{parentSpanId:n,sampled:(Number.parseInt(s,16)&1)===1,traceId:o}},_=(e,r)=>typeof r=="boolean"?{key:e,value:{boolValue:r}}:typeof r=="number"?Number.isFinite(r)?Number.isSafeInteger(r)?{key:e,value:{intValue:String(r)}}:{key:e,value:{doubleValue:r}}:{key:e,value:{stringValue:String(r)}}:{key:e,value:{stringValue:r}},b=e=>e===void 0?[]:Object.entries(e).map(([r,t])=>_(r,t)),h=(e,r,t)=>{const o={},n=new Map,s=(c,i)=>{const g=c.toLowerCase(),v=n.get(g);v===void 0?(n.set(g,c),o[c]=i):o[v]=i};for(const[c,i]of Object.entries(e))s(c,i);for(const[c,i]of Object.entries(r??{}))s(c,i);return t!==void 0&&t.length>0&&s("authorization",`Bearer ${t}`),o},f=e=>Array.isArray(e)?e:[e],C={client:3,consumer:5,internal:1,producer:4,server:2},L=Object.freeze({durationMs:"lunora.duration_ms",errorMessage:"error.message",errorType:"error.type",functionPath:"lunora.function_path",ok:"lunora.ok",rayId:"cloudflare.ray_id",shardKey:"lunora.shard_key",userId:"lunora.user_id"}),p=(e,r)=>{const t={"service.name":e};for(const[o,n]of Object.entries(r??{}))t[o]=n;return Object.entries(t).map(([o,n])=>_(o,n))},V=(e,r,t,o)=>({resourceSpans:[{resource:{attributes:p(t,o)},scopeSpans:[{scope:{name:r},spans:f(e)}]}]}),M=(e,r,t,o)=>({resourceLogs:[{resource:{attributes:p(t,o)},scopeLogs:[{logRecords:f(e),scope:{name:r}}]}]}),y=(e,r,t,o)=>({resourceMetrics:[{resource:{attributes:p(t,o)},scopeMetrics:[{metrics:f(e),scope:{name:r}}]}]}),E="CF_VERSION_METADATA",d=(e,r)=>{if(typeof e!="object"||e===null)return;const t=e[r];return typeof t=="string"&&t.length>0?t:void 0},w=e=>r=>{const t=e?.[r];if(typeof t=="string")return t.length>0?t:void 0;if(r===E)return d(t,"tag")??d(t,"id")},D=e=>{const r={},t=e("SERVICE_VERSION")??e("CF_VERSION_METADATA")??e("VERCEL_GIT_COMMIT_SHA")??e("GITHUB_SHA")??e("COMMIT_SHA");t!==void 0&&(r["service.version"]=t);const o=e("DEPLOYMENT_ENVIRONMENT")??e("ENVIRONMENT")??e("NODE_ENV");return o!==void 0&&(r["deployment.environment"]=o),r},x=(e,r)=>{if(!(r!==void 0||e("CLOUDFLARE")!==void 0||e("CF_ACCOUNT_ID")!==void 0))return{};const o={"cloud.provider":"cloudflare"},n=d(r,"colo")??e("CF_COLO")??e("CLOUDFLARE_COLO");return n!==void 0&&(o["cloud.region"]=n),o},F=(...e)=>{const r={};for(const t of e)if(t!==void 0)for(const[o,n]of Object.entries(t))r[o]=n;return r};export{L,C as O,D as a,S as b,b as c,x as d,_ as e,N as f,R as g,h,y as i,M as j,F as m,T as o,I as p,w as r,V as w};
@@ -0,0 +1,2 @@
1
+ const l=e=>{const t=e.trim();if(!t.startsWith("at "))return;let n=t.slice(3),o="<anonymous>";const i=n.lastIndexOf(" (");n.endsWith(")")&&i!==-1&&(o=n.slice(0,i),n=n.slice(i+2,-1));const s=n.lastIndexOf(":"),c=s<=0?-1:n.lastIndexOf(":",s-1),a=Number.parseInt(n.slice(c+1,s),10),r=Number.parseInt(n.slice(s+1),10);if(!(c<=0||Number.isNaN(a)||Number.isNaN(r)))return{colno:r,filename:n.slice(0,c),function:o,lineno:a}},f=e=>{const t=new Error(e.message);return t.name=e.name??e.code??"Error",e.stack!==void 0&&(t.stack=e.stack),e.code!==void 0&&(t.code=e.code),t},m=e=>{if(e===void 0)return[];const t=[];for(const n of e.split(`
2
+ `)){const o=l(n);o!==void 0&&t.push(o)}return t.toReversed()};export{m as parseStackFrames,f as toError};
@@ -0,0 +1 @@
1
+ import{raw as n,desc as F,sql as r}from"@lunora/bindings/r2sql";const u=["trace","debug","log","info","warn","error","fatal"],T={fields:"fields",functionPath:"functionPath",level:"level",message:"message",shardKey:"shardKey",spanId:"spanId",traceId:"traceId",ts:"ts",userId:"userId"},N=500,w=1e4,_=e=>e===void 0||!Number.isFinite(e)?N:Math.min(Math.max(Math.floor(e),1),w),D=e=>typeof e=="number"?e:Number(e),L=e=>e==null?"":String(e),U=e=>{if(typeof e!="string")return e;try{return JSON.parse(e)}catch{return e}},S=e=>{const s=JSON.stringify([e.ts,e.level,e.functionPath,e.message,e.traceId,e.spanId,e.shardKey,e.userId,e.fields]);let t=0,l=0;for(const v of s){const I=v.codePointAt(0)??0;t=(t*31+I)%2147483647,l=(l*131+I)%4294967291}return`${t.toString(36)}.${l.toString(36)}`},y=(e,s,t,l)=>{if(s.sinceTs!==void 0&&e.where(r`${n(t.ts)} >= ${s.sinceTs}`),s.untilTs!==void 0&&e.where(r`${n(t.ts)} <= ${s.untilTs}`),s.level!==void 0)e.where(r`${n(t.level)} = ${s.level}`);else if(s.minLevel!==void 0){const v=u.indexOf(s.minLevel),I=v===-1?[...u]:u.slice(v);e.where(r`${n(t.level)} IN ${I}`)}s.functionPath!==void 0&&e.where(r`${n(t.functionPath)} = ${s.functionPath}`),s.functionPathPrefix!==void 0&&e.where(r`${n(t.functionPath)} LIKE ${`${s.functionPathPrefix}%`}`),s.traceId!==void 0&&e.where(r`${n(t.traceId)} = ${s.traceId}`),s.shardKey!==void 0&&e.where(r`${n(t.shardKey)} = ${s.shardKey}`),s.userId!==void 0&&e.where(r`${n(t.userId)} = ${s.userId}`),l!==void 0&&e.where(r`${n(t.ts)} <= ${l}`)},G=T,J=(e,s)=>{const t={...T,...s.columnMap},l=s.namespace===void 0?s.table:`${s.namespace}.${s.table}`,v=a=>{const c={functionPath:L(a[t.functionPath]),level:L(a[t.level]),message:L(a[t.message]),ts:D(a[t.ts])},o=a[t.fields];o!=null&&(c.fields=U(o));for(const d of["shardKey","userId","traceId","spanId"]){const i=a[t[d]];i!=null&&(c[d]=L(i))}return c},I=async(a,c,o)=>{const d=e.from(l).select(n(t.functionPath),n(t.level),n(t.message),n(t.ts),n(t.fields),n(t.shardKey),n(t.userId),n(t.traceId),n(t.spanId));y(d,a,t,c),d.orderBy(F(n(t.ts))).limit(o);const{rows:i}=await d.run();return i},A=async(a,c,o,d)=>{const i=await I(a,c,d),$=[];for(const P of i){const f=v(P);o!==void 0&&c!==void 0&&f.ts===c&&o.has(S(f))||$.push(f)}return{decoded:$,truncated:i.length>=d}};return{query:async(a={})=>{const c=_(a.limit),{cursor:o}=a,d=o?.ts,i=o?.seen!==void 0&&o.seen.length>0?new Set(o.seen):void 0,$=Math.min(c+1,w),P=3;let f=[],m=!1;for(let h=0;h<P;h+=1){const K=Math.min($*2**h,w),O=await A(a,d,i,K);if(f=O.decoded,m=O.truncated,f.length>c||!m||K>=w)break}const R=f.length>c,g=R?f.slice(0,c):f,M=g.at(-1);if(M===void 0||!(R||m))return{rows:g};const p=M.ts,E=g.filter(h=>h.ts===p).map(h=>S(h)),x=[...d===p&&o?.seen!==void 0?o.seen:[],...E];return{nextCursor:x.length>0?{seen:x,ts:p}:{ts:p},rows:g}}}};export{G as D,u as L,J as c};
@@ -0,0 +1 @@
1
+ import{decodeWire as f,isPlainObject as s}from"@lunora/wire";import{a as i}from"./base64-Bl1_r2k1.mjs";const o=r=>{if(typeof r=="bigint")return r.toString();if(r instanceof ArrayBuffer)return i(new Uint8Array(r));if(ArrayBuffer.isView(r))return i(new Uint8Array(r.buffer,r.byteOffset,r.byteLength));if(Array.isArray(r))return r.map(t=>o(t));if(s(r)){const t={};for(const e of Object.keys(r)){const n=o(r[e]);e==="__proto__"?Object.defineProperty(t,e,{configurable:!0,enumerable:!0,value:n,writable:!0}):t[e]=n}return t}return r},y=r=>o(f(r));export{y as t};
@@ -0,0 +1 @@
1
+ const m="/_lunora/rest",v=["authorization","cf-access-jwt-assertion","cookie","payment-signature","x-payment"],d=["x-d1-bookmark","x-lunora-shard-key"],h=e=>[...v,...(e.credentialHeaders??[]).map(t=>t.toLowerCase())],u=e=>Number.isFinite(e)?Math.max(0,Math.floor(e)):0,c=(...e)=>{const t=[];for(const a of e)for(const s of a?.split(",")??[]){const n=s.trim().toLowerCase();n!==""&&!t.includes(n)&&t.push(n)}return t.length===0?void 0:t.join(", ")},l=(e,t)=>{const a=[t,`max-age=${String(u(e.maxAge))}`];return e.staleWhileRevalidate!==void 0&&a.push(`stale-while-revalidate=${String(u(e.staleWhileRevalidate))}`),a.join(", ")},p=e=>e.scope==="public"?c(e.vary,...h(e),...d):c(e.vary,...d),f=e=>{const t=e.indexOf(":");if(!(t<=0||t>=e.length-1||e.indexOf(":",t+1)!==-1))return{name:e.slice(t+1),namespace:e.slice(0,t)}},g=e=>{const t=f(e);if(t!==void 0)return`${m}/${t.namespace}/${t.name}`},E=e=>e==="query"?"GET":"POST",b=e=>{const t=[];for(const a of e){if(a.exposure?.rest!==!0||a.kind==="stream")continue;const s=f(a.functionPath),n=g(a.functionPath);s===void 0||n===void 0||t.push({functionPath:a.functionPath,kind:a.kind,method:E(a.kind),name:s.name,namespace:s.namespace,path:n})}return t.sort((a,s)=>a.path<s.path?-1:+(a.path>s.path)),t},R=(e,t,a)=>a?.access!==void 0||h(t).some(s=>e.headers.has(s)),x=(e,t,a)=>e.scope==="public"&&!R(t,e,a)?"public":"private",S=(e,t,a,s)=>{if(t.method!=="GET"||a<200||a>299)return;const n={"cache-control":l(e,x(e,t,s))};e.tag!==void 0&&e.tag!==""&&(n["cache-tag"]=e.tag);const r=p(e);return r!==void 0&&(n.vary=r),n},C=(e,t,a,s)=>{if(t===void 0)return e;const n=S(t,a,e.status,s);if(n===void 0)return e;const r=new Response(e.body,e);for(const[i,o]of Object.entries(n))r.headers.set(i,i==="vary"?c(r.headers.get("vary")??void 0,o)??o:o);return r};export{C as a,S as b,u as c,p as d,x as e,b as f,R as r};
@@ -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-PkZWF-_g.mjs";import{m as x}from"./method-guard-8Jo4Q8uS.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.26",
3
+ "version": "1.0.0-alpha.261",
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/errors": "1.0.0-alpha.4"
49
+ "@lunora/bindings": "1.0.0-alpha.144",
50
+ "@lunora/errors": ">=1.0.0-alpha.51 <2.0.0-0",
51
+ "@lunora/observability": "1.0.0-alpha.191",
52
+ "@lunora/platform": "1.0.0-alpha.76",
53
+ "@lunora/wire": "1.0.0-alpha.6"
54
+ },
55
+ "peerDependencies": {
56
+ "@lunora/shard-engine": ">=1.0.0-alpha.135 <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,8 +0,0 @@
1
- const NOOP_EXECUTION_CONTEXT = {
2
- passThroughOnException: () => {
3
- },
4
- waitUntil: () => {
5
- }
6
- };
7
-
8
- export { NOOP_EXECUTION_CONTEXT };
@@ -1,200 +0,0 @@
1
- import { m as mergeHeaders, o as otlpRandomHex, w as wrapResourceSpans, a as wrapResourceLogs, e as encodeAttribute, O as OTLP_SEVERITY, c as otlpUnixNano } from './otlp-D_YzGXu1.mjs';
2
-
3
- const shouldSkip = (event, onlyErrors) => onlyErrors === true && event.ok;
4
- const otlpTraceBody = (event, serviceName, endMs) => {
5
- const attributes = [encodeAttribute("lunora.function_path", event.functionPath), encodeAttribute("lunora.ok", event.ok)];
6
- if (event.shardKey !== void 0) {
7
- attributes.push(encodeAttribute("lunora.shard_key", event.shardKey));
8
- }
9
- if (event.error) {
10
- attributes.push(encodeAttribute("error.type", event.error.code), encodeAttribute("lunora.error_status", event.error.status));
11
- }
12
- if (event.fanOut) {
13
- attributes.push(
14
- encodeAttribute("lunora.fanout.table", event.fanOut.table),
15
- encodeAttribute("lunora.fanout.shards", event.fanOut.shards),
16
- encodeAttribute("lunora.fanout.failed", event.fanOut.failed)
17
- );
18
- }
19
- const span = {
20
- attributes,
21
- endTimeUnixNano: otlpUnixNano(endMs),
22
- // SPAN_KIND_SERVER — a dispatched RPC is server-side request handling.
23
- kind: 2,
24
- name: event.functionPath,
25
- // Reuse the dispatch's trace context when the runtime set it (so this span
26
- // shares the id it propagated as `traceparent`); else mint fresh ids.
27
- spanId: event.spanId ?? otlpRandomHex(8),
28
- startTimeUnixNano: otlpUnixNano(endMs - event.durationMs),
29
- // STATUS_CODE_OK (1) / STATUS_CODE_ERROR (2).
30
- status: event.ok ? { code: 1 } : { code: 2, message: event.error?.message ?? "" },
31
- traceId: event.traceId ?? otlpRandomHex(16)
32
- };
33
- return wrapResourceSpans(span, "@lunora/runtime", serviceName);
34
- };
35
- const otlpLogBody = (event, serviceName) => {
36
- const attributes = [encodeAttribute("lunora.function_path", event.functionPath)];
37
- if (event.shardKey !== void 0) {
38
- attributes.push(encodeAttribute("lunora.shard_key", event.shardKey));
39
- }
40
- if (event.userId !== void 0) {
41
- attributes.push(encodeAttribute("lunora.user_id", event.userId));
42
- }
43
- const logRecord = {
44
- attributes,
45
- body: { stringValue: event.message },
46
- severityNumber: OTLP_SEVERITY[event.level],
47
- severityText: event.level.toUpperCase(),
48
- timeUnixNano: otlpUnixNano(event.ts)
49
- };
50
- return wrapResourceLogs(logRecord, "@lunora/runtime", serviceName);
51
- };
52
- const otlpPost = (url, body, headers, context) => {
53
- try {
54
- const sent = fetch(url, { body: JSON.stringify(body), headers, method: "POST" }).catch(() => {
55
- });
56
- if (context?.waitUntil) {
57
- context.waitUntil(sent);
58
- }
59
- } catch {
60
- }
61
- };
62
- const consoleSink = (options = {}) => {
63
- const { onlyErrors } = options;
64
- return {
65
- onLog: (event) => {
66
- if (event.level === "error") {
67
- console.error("[lunora:log]", event.functionPath, event.message);
68
- } else {
69
- console.log("[lunora:log]", event.functionPath, event.message);
70
- }
71
- },
72
- onRpc: (event) => {
73
- if (shouldSkip(event, onlyErrors)) {
74
- return;
75
- }
76
- if (event.ok) {
77
- console.log("[lunora:rpc]", event);
78
- } else {
79
- console.error("[lunora:rpc]", event);
80
- }
81
- }
82
- };
83
- };
84
- const webhookSink = (options) => {
85
- const { headers, onlyErrors, transform, url } = options;
86
- const mergedHeaders = mergeHeaders({ "content-type": "application/json" }, headers);
87
- return {
88
- onRpc: (event, context) => {
89
- if (shouldSkip(event, onlyErrors)) {
90
- return;
91
- }
92
- try {
93
- let payload = event;
94
- if (transform) {
95
- try {
96
- payload = transform(event);
97
- } catch {
98
- return;
99
- }
100
- }
101
- if (payload === null || payload === void 0) {
102
- return;
103
- }
104
- const sent = fetch(url, {
105
- body: JSON.stringify(payload),
106
- headers: mergedHeaders,
107
- method: "POST"
108
- }).catch(() => {
109
- });
110
- if (context?.waitUntil) {
111
- context.waitUntil(sent);
112
- }
113
- } catch {
114
- }
115
- }
116
- };
117
- };
118
- const sentrySink = (options) => {
119
- const { capture } = options;
120
- const onlyErrors = options.onlyErrors ?? true;
121
- return {
122
- onRpc: (event) => {
123
- if (shouldSkip(event, onlyErrors)) {
124
- return;
125
- }
126
- try {
127
- capture(event);
128
- } catch {
129
- }
130
- }
131
- };
132
- };
133
- const analyticsEngineSink = (options) => {
134
- const { dataset, onlyErrors } = options;
135
- return {
136
- onRpc: (event) => {
137
- if (shouldSkip(event, onlyErrors)) {
138
- return;
139
- }
140
- try {
141
- dataset.writeDataPoint({
142
- blobs: [event.functionPath, event.ok ? "ok" : "error", event.shardKey ?? "", event.error?.code ?? "", event.fanOut?.table ?? ""],
143
- doubles: [event.durationMs, event.ok ? 0 : 1, event.fanOut?.shards ?? 0, event.fanOut?.failed ?? 0],
144
- indexes: [event.functionPath]
145
- });
146
- } catch {
147
- }
148
- }
149
- };
150
- };
151
- const otlpSink = (options) => {
152
- const { endpoint, headers, onlyErrors, token } = options;
153
- const serviceName = options.serviceName ?? "lunora";
154
- let base = endpoint;
155
- while (base.endsWith("/")) {
156
- base = base.slice(0, -1);
157
- }
158
- const tracesUrl = `${base}/v1/traces`;
159
- const logsUrl = `${base}/v1/logs`;
160
- const mergedHeaders = mergeHeaders({ "content-type": "application/json" }, headers, token);
161
- return {
162
- onLog: (event, context) => {
163
- otlpPost(logsUrl, otlpLogBody(event, serviceName), mergedHeaders, context);
164
- },
165
- onRpc: (event, context) => {
166
- if (shouldSkip(event, onlyErrors)) {
167
- return;
168
- }
169
- otlpPost(tracesUrl, otlpTraceBody(event, serviceName, Date.now()), mergedHeaders, context);
170
- }
171
- };
172
- };
173
- const combineSinks = (...sinks) => {
174
- return {
175
- onLog: (event, context) => {
176
- for (const sink of sinks) {
177
- if (!sink.onLog) {
178
- continue;
179
- }
180
- try {
181
- sink.onLog(event, context);
182
- } catch {
183
- }
184
- }
185
- },
186
- onRpc: (event, context) => {
187
- for (const sink of sinks) {
188
- if (!sink.onRpc) {
189
- continue;
190
- }
191
- try {
192
- sink.onRpc(event, context);
193
- } catch {
194
- }
195
- }
196
- }
197
- };
198
- };
199
-
200
- export { analyticsEngineSink, combineSinks, consoleSink, otlpSink, 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 };