@lunora/runtime 1.0.0-alpha.70 → 1.0.0-alpha.71
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/index.d.mts +5 -18
- package/dist/index.d.ts +5 -18
- package/dist/index.mjs +1 -1
- package/dist/packem_shared/{composeWorker-DVjmsFp1.mjs → composeWorker-Dsa42tcw.mjs} +1 -1
- package/dist/packem_shared/createKvCursorStore-kQ8HNv0l.mjs +3 -0
- package/dist/packem_shared/{createShardClient-DnQNYYNU.mjs → createShardClient-CCncsgTs.mjs} +1 -1
- package/dist/packem_shared/portable-json-BAMIgqk5.mjs +1 -0
- package/dist/packem_shared/toAirbyteMessages-CZimuevO.mjs +1 -0
- package/dist/packem_shared/{wire-codec-0SQDg-5_.mjs → wire-codec-D_qTfaaH.mjs} +1 -1
- package/package.json +1 -1
- package/dist/packem_shared/createKvCursorStore-VOd1DFsf.mjs +0 -3
- package/dist/packem_shared/toAirbyteMessages-Cy3uaySU.mjs +0 -1
package/dist/index.d.mts
CHANGED
|
@@ -76,24 +76,6 @@ interface BackupManifestEntry {
|
|
|
76
76
|
* without a guard.
|
|
77
77
|
*/
|
|
78
78
|
declare const isBackupManifestEntry: (value: unknown) => value is BackupManifestEntry;
|
|
79
|
-
/**
|
|
80
|
-
* Turn-key incremental-sync source helpers for warehouse connectors
|
|
81
|
-
* (Fivetran custom functions, Airbyte incremental sources).
|
|
82
|
-
*
|
|
83
|
-
* The runtime's admin `/_lunora/admin/connector/sync` endpoint returns a
|
|
84
|
-
* {@link ConnectorSyncPage}: a flat list of change records since an opaque
|
|
85
|
-
* cursor, a `nextCursor` to resume from, and a `hasMore` flag. These helpers
|
|
86
|
-
* reshape that page into the response envelopes the two ecosystems expect, so a
|
|
87
|
-
* connector wrapper stays a few lines.
|
|
88
|
-
*
|
|
89
|
-
* {@link toFivetranResponse} produces the `{ state, insert, update, delete,
|
|
90
|
-
* hasMore, schema }` object a Fivetran connector function returns from its
|
|
91
|
-
* handler. {@link toAirbyteMessages} produces an ordered array of Airbyte
|
|
92
|
-
* protocol messages (a `RECORD` per row, a trailing `STATE` carrying the cursor),
|
|
93
|
-
* the line-delimited stream an Airbyte incremental source emits.
|
|
94
|
-
*
|
|
95
|
-
* Both consume the SAME page, so a single endpoint feeds either ecosystem.
|
|
96
|
-
*/
|
|
97
79
|
/**
|
|
98
80
|
* One change record in a {@link ConnectorSyncPage}. Mirrors a row of the CDC log
|
|
99
81
|
* the shard / D1 change feed produces: an `op` (insert / update / delete), the
|
|
@@ -1436,6 +1418,11 @@ interface RunExportTapOptions {
|
|
|
1436
1418
|
* Project a raw op-log CDC record (`{ id, op, seq, table, ts, doc? }`) into a
|
|
1437
1419
|
* clean {@link ExportChange}. Mirrors `./connector-cdc`'s `flattenCdcChange` but
|
|
1438
1420
|
* PRESERVES `seq` / `id` / `ts` so a downstream warehouse can order and dedupe.
|
|
1421
|
+
*
|
|
1422
|
+
* The raw record arrives in wire form (the shard admin RPC encodes its result),
|
|
1423
|
+
* so `doc` is mapped through {@link toPortableDocument} — every sink NDJSON-encodes
|
|
1424
|
+
* it straight to a third party, where a `["$lunora.wire$","bigint",…]` tag would
|
|
1425
|
+
* land as an array instead of a value.
|
|
1439
1426
|
*/
|
|
1440
1427
|
declare const sanitizeChange: (raw: Record<string, unknown>) => ExportChange;
|
|
1441
1428
|
/**
|
package/dist/index.d.ts
CHANGED
|
@@ -76,24 +76,6 @@ interface BackupManifestEntry {
|
|
|
76
76
|
* without a guard.
|
|
77
77
|
*/
|
|
78
78
|
declare const isBackupManifestEntry: (value: unknown) => value is BackupManifestEntry;
|
|
79
|
-
/**
|
|
80
|
-
* Turn-key incremental-sync source helpers for warehouse connectors
|
|
81
|
-
* (Fivetran custom functions, Airbyte incremental sources).
|
|
82
|
-
*
|
|
83
|
-
* The runtime's admin `/_lunora/admin/connector/sync` endpoint returns a
|
|
84
|
-
* {@link ConnectorSyncPage}: a flat list of change records since an opaque
|
|
85
|
-
* cursor, a `nextCursor` to resume from, and a `hasMore` flag. These helpers
|
|
86
|
-
* reshape that page into the response envelopes the two ecosystems expect, so a
|
|
87
|
-
* connector wrapper stays a few lines.
|
|
88
|
-
*
|
|
89
|
-
* {@link toFivetranResponse} produces the `{ state, insert, update, delete,
|
|
90
|
-
* hasMore, schema }` object a Fivetran connector function returns from its
|
|
91
|
-
* handler. {@link toAirbyteMessages} produces an ordered array of Airbyte
|
|
92
|
-
* protocol messages (a `RECORD` per row, a trailing `STATE` carrying the cursor),
|
|
93
|
-
* the line-delimited stream an Airbyte incremental source emits.
|
|
94
|
-
*
|
|
95
|
-
* Both consume the SAME page, so a single endpoint feeds either ecosystem.
|
|
96
|
-
*/
|
|
97
79
|
/**
|
|
98
80
|
* One change record in a {@link ConnectorSyncPage}. Mirrors a row of the CDC log
|
|
99
81
|
* the shard / D1 change feed produces: an `op` (insert / update / delete), the
|
|
@@ -1436,6 +1418,11 @@ interface RunExportTapOptions {
|
|
|
1436
1418
|
* Project a raw op-log CDC record (`{ id, op, seq, table, ts, doc? }`) into a
|
|
1437
1419
|
* clean {@link ExportChange}. Mirrors `./connector-cdc`'s `flattenCdcChange` but
|
|
1438
1420
|
* PRESERVES `seq` / `id` / `ts` so a downstream warehouse can order and dedupe.
|
|
1421
|
+
*
|
|
1422
|
+
* The raw record arrives in wire form (the shard admin RPC encodes its result),
|
|
1423
|
+
* so `doc` is mapped through {@link toPortableDocument} — every sink NDJSON-encodes
|
|
1424
|
+
* it straight to a third party, where a `["$lunora.wire$","bigint",…]` tag would
|
|
1425
|
+
* land as an array instead of a value.
|
|
1439
1426
|
*/
|
|
1440
1427
|
declare const sanitizeChange: (raw: Record<string, unknown>) => ExportChange;
|
|
1441
1428
|
/**
|
package/dist/index.mjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{BACKUP_KEY_PREFIX as t,backupManifestKey as a,backupObjectKey as s,backupObjectKeyOfManifest as i,isBackupManifestEntry as n,isBackupManifestKey as p,normalizeBackupPrefix as c}from"./packem_shared/BACKUP_KEY_PREFIX-BOtSu-_3.mjs";import{toAirbyteMessages as f,toFivetranResponse as E}from"./packem_shared/toAirbyteMessages-
|
|
1
|
+
import{BACKUP_KEY_PREFIX as t,backupManifestKey as a,backupObjectKey as s,backupObjectKeyOfManifest as i,isBackupManifestEntry as n,isBackupManifestKey as p,normalizeBackupPrefix as c}from"./packem_shared/BACKUP_KEY_PREFIX-BOtSu-_3.mjs";import{toAirbyteMessages as f,toFivetranResponse as E}from"./packem_shared/toAirbyteMessages-CZimuevO.mjs";import{composeWorker as S,createLunoraHandler as x,createWorker as _,defineRpcEnvelope as d,resolveLunoraOptions as l,withFrameworkWorker as u}from"./packem_shared/composeWorker-Dsa42tcw.mjs";import{createCrossShardRelationCapabilities as k}from"./packem_shared/createCrossShardRelationCapabilities-DgQYQzd1.mjs";import{DEFAULT_REGISTRY_CACHE_TTL_MS as A,SHARD_REGISTRY_DO_NAME as C,createDynamicShardRegistry as L}from"./packem_shared/DEFAULT_REGISTRY_CACHE_TTL_MS-D5O7elXI.mjs";import{LunoraError as b,toErrorResponse as g}from"./packem_shared/LunoraError-DksAgIpa.mjs";import{createKvCursorStore as H,createMemoryCursorStore as I,defineExportSink as P,r2Sink as v,runExportTap as D,sanitizeChange as F,webhookExportSink as M}from"./packem_shared/createKvCursorStore-kQ8HNv0l.mjs";import{HEALTH_PATH as K,HEALTH_READY_PATH as N,buildHealthRoutes as U,d1Probe as B,durableObjectProbe as Y,presenceProbe as w}from"./packem_shared/HEALTH_PATH-jZsuCmSs.mjs";import{LOG_ARCHIVE_PATH as X,resolveLogArchiveFromEnv as j}from"./packem_shared/LOG_ARCHIVE_PATH-jgHjdsz2.mjs";import{memoizeIdentity as W,memoizeIdentityPerRequest as q}from"./packem_shared/memoizeIdentity-DnOj3QRi.mjs";import{e as J,a as Z}from"./packem_shared/observability-vDK-rMbs.mjs";import{analyticsEngineSink as ee,combineSinks as re,consoleSink as oe,otlpSink as te,pipelineLogSink as ae,sentrySink as se,webhookSink as ie}from"./packem_shared/analyticsEngineSink-BgmqAmTM.mjs";import{D as pe,a as ce,c as me}from"./packem_shared/pipeline-log-reader-BGrl66P5.mjs";import{createQueryCoordinator as Ee,createStaticShardRegistry as Re,mergeStrategyForAggregate as Se}from"./packem_shared/createQueryCoordinator-CnNyazLX.mjs";import{applyJurisdiction as _e,resolveShard as de}from"./packem_shared/applyJurisdiction-C0ddU7Tg.mjs";import{a as ue,r as ye,b as ke}from"./packem_shared/rest-cache-BnMq2hbO.mjs";import{a as Ae,b as Ce,c as Le,r as Te,d as be}from"./packem_shared/rest-routes-D2b3HXA9.mjs";import{decorateResponse as he,enforceOrigin as He,handleCorsPreflight as Ie,resolveSecurity as Pe}from"./packem_shared/decorateResponse-D3NzOIvB.mjs";import{createShardClient as De}from"./packem_shared/createShardClient-CCncsgTs.mjs";import{STORAGE_UPLOAD_MAX_BODY_BYTES as Me}from"./packem_shared/STORAGE_UPLOAD_MAX_BODY_BYTES-BqyO-1l6.mjs";import{LOG_ARCHIVE_NOT_CONFIGURED as Ke}from"./packem_shared/LOG_ARCHIVE_NOT_CONFIGURED-CDpi4yFD.mjs";import{NOOP_EXECUTION_CONTEXT as Ue}from"./packem_shared/NOOP_EXECUTION_CONTEXT-YmXqH-jH.mjs";import{composeIdentityResolvers as Ye,routeIdentityResolvers as we}from"./packem_shared/composeIdentityResolvers-BHZ4jH8o.mjs";const e="0.0.0";export{t as BACKUP_KEY_PREFIX,pe as DEFAULT_LOG_COLUMNS,ce as DEFAULT_LOG_LIMIT,A as DEFAULT_REGISTRY_CACHE_TTL_MS,K as HEALTH_PATH,N as HEALTH_READY_PATH,Ke as LOG_ARCHIVE_NOT_CONFIGURED,X as LOG_ARCHIVE_PATH,b as LunoraError,Ue as NOOP_EXECUTION_CONTEXT,C as SHARD_REGISTRY_DO_NAME,Me as STORAGE_UPLOAD_MAX_BODY_BYTES,e as VERSION,ee as analyticsEngineSink,_e as applyJurisdiction,ue as applyRestCache,Ae as argsFromQuery,a as backupManifestKey,s as backupObjectKey,i as backupObjectKeyOfManifest,U as buildHealthRoutes,Ce as buildRestRoutes,re as combineSinks,Ye as composeIdentityResolvers,S as composeWorker,oe as consoleSink,k as createCrossShardRelationCapabilities,L as createDynamicShardRegistry,H as createKvCursorStore,x as createLunoraHandler,I as createMemoryCursorStore,me as createPipelineLogReader,Ee as createQueryCoordinator,Le as createRestRateLimit,De as createShardClient,Re as createStaticShardRegistry,_ as createWorker,B as d1Probe,he as decorateResponse,P as defineExportSink,d as defineRpcEnvelope,Y as durableObjectProbe,J as emitLogEvent,Z as emitRpcEvent,He as enforceOrigin,Ie as handleCorsPreflight,n as isBackupManifestEntry,p as isBackupManifestKey,W as memoizeIdentity,q as memoizeIdentityPerRequest,Se as mergeStrategyForAggregate,c as normalizeBackupPrefix,te as otlpSink,ae as pipelineLogSink,w as presenceProbe,v as r2Sink,Te as readShardKey,ye as requestCarriesCredentials,j as resolveLogArchiveFromEnv,l as resolveLunoraOptions,Pe as resolveSecurity,de as resolveShard,ke as restCacheHeaders,be as restSurfaceFromRegistry,we as routeIdentityResolvers,D as runExportTap,F as sanitizeChange,se as sentrySink,f as toAirbyteMessages,g as toErrorResponse,E as toFivetranResponse,M as webhookExportSink,ie as webhookSink,u as withFrameworkWorker};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{isLunoraError as Nn,toErrorBody as Un}from"@lunora/errors";import{e as Nt}from"./evict-oldest-BNXsKx4s.mjs";import{NOOP_EXECUTION_CONTEXT as Cn}from"./NOOP_EXECUTION_CONTEXT-YmXqH-jH.mjs";import{e as Bn,a as xn}from"./identity-header-JF5q3H5w.mjs";import{o as Se,b as Hn,p as Ln,m as Mn,d as jn,a as $n,r as Kn}from"./otlp-resource-B4Yylr0V.mjs";import{e as Fe}from"./wire-codec-0SQDg-5_.mjs";import{e as Z,f as be,M as Ut,b as Fn,g as Gn,h as Ct,i as Bt}from"./rest-routes-D2b3HXA9.mjs";import{LunoraError as d,toErrorResponse as nt}from"./LunoraError-DksAgIpa.mjs";import{a as j,m as me}from"./method-guard-BG_vJNTl.mjs";import{normalizeBackupPrefix as Qe,BACKUP_KEY_PREFIX as ze,isBackupManifestKey as Qn,backupObjectKeyOfManifest as xt,backupObjectKey as zn,backupManifestKey as Wn}from"./BACKUP_KEY_PREFIX-BOtSu-_3.mjs";import{toHex as Vn,buildStorageAdminRoutes as Jn,STORAGE_UPLOAD_MAX_BODY_BYTES as qn,STORAGE_PATH as Yn}from"./STORAGE_UPLOAD_MAX_BODY_BYTES-BqyO-1l6.mjs";import{runExportTap as Xn}from"./createKvCursorStore-VOd1DFsf.mjs";import{buildHealthRoutes as Zn,durableObjectProbe as er,d1Probe as tr,presenceProbe as Ce}from"./HEALTH_PATH-jZsuCmSs.mjs";import{wrapResolverWithContract as nr}from"./composeIdentityResolvers-BHZ4jH8o.mjs";import{composeIdentityResolvers as Es,routeIdentityResolvers as As}from"./composeIdentityResolvers-BHZ4jH8o.mjs";import{buildLogArchiveAdminRoutes as rr}from"./LOG_ARCHIVE_PATH-jgHjdsz2.mjs";import{r as or,f as rt,a as ce}from"./observability-vDK-rMbs.mjs";import{resolveShard as we,applyJurisdiction as ot}from"./applyJurisdiction-C0ddU7Tg.mjs";import{resolveSecurity as at,handleCorsPreflight as ar,enforceOrigin as sr,decorateResponse as Be,enforceWebSocketOrigin as st}from"./decorateResponse-D3NzOIvB.mjs";const ir=e=>{const n=e??{};if(typeof n.bucket=="function")return n;const t={...n,bucketName:"default"};return t.bucket=()=>t,t},Ht="__lunoraBranch",cr=e=>typeof e=="object"&&e!==null&&Object.hasOwn(e,Ht),dr=`may not contain the reserved workflow branch-marker key ("${Ht}")`,We=(e,n)=>{const t=Math.max(e.length,n.length);let r=e.length^n.length;for(let a=0;a<t;a+=1){const s=a<e.length?e.charCodeAt(a):0,l=a<n.length?n.charCodeAt(a):0;r|=s^l}return r===0},Ve=new TextEncoder,ur=Array.from({length:32},(e,n)=>n);new RegExp(`[${ur.map(e=>String.fromCodePoint(e)).join("")}]`,"u");const lr=e=>{const n=String.fromCodePoint(...e);return btoa(n).replaceAll("+","-").replaceAll("/","_").replaceAll("=","")},hr=e=>{const n=e.replaceAll("-","+").replaceAll("_","/")+"===".slice((e.length+3)%4),t=atob(n),r=new Uint8Array(t.length);for(let a=0;a<t.length;a+=1)r[a]=t.codePointAt(a)??0;return r},fr=64,xe=new Map,Lt=async e=>{const n=xe.get(e);if(n)return n;Nt(xe,fr);const t=crypto.subtle.importKey("raw",Ve.encode(e),{hash:"SHA-256",name:"HMAC"},!1,["sign","verify"]);return xe.set(e,t),t},Mt=async(e,n)=>{const t=await Lt(e),r=await crypto.subtle.sign("HMAC",t,Ve.encode(n));return lr(new Uint8Array(r))},pr=async(e,n,t)=>{const r=await Lt(e);return crypto.subtle.verify("HMAC",r,t,Ve.encode(n))},mr=["wnam","enam","sam","weur","eeur","apac","apac-ne","apac-se","oc","afr","me"];new Set(mr);const wr=new Set(["AE","BH","IL","IQ","IR","JO","KW","LB","OM","PS","QA","SA","SY","TR","YE"]),gr=-100,yr=15,br=e=>{const n=Number(e.longitude??Number.NaN);switch(e.continent){case"AF":return"afr";case"AS":return e.country!==void 0&&wr.has(e.country)?"me":"apac";case"EU":return Number.isFinite(n)&&n>yr?"eeur":"weur";case"NA":return Number.isFinite(n)&&n<gr?"wnam":"enam";case"OC":return"oc";case"SA":return"sam";default:return}},it=e=>{const n=e.cf;return n===void 0?void 0:br(n)},jt="::relay::",_r=(e,n)=>`${e}${jt}${String(n)}`,$t="::replica::",Rr=(e,n)=>`${e}${$t}${n}`,Er=e=>{if(e==null||!/^\d+$/.test(e))return;const n=Number.parseInt(e,10);return Number.isSafeInteger(n)&&n>0?n:void 0},Ar=new Set(["1","enabled","on","true","yes"]),Sr=new Set(["0","disabled","false","no","off"]),Tr=(e,n)=>{const t=(e??"").trim().toLowerCase();return Ar.has(t)?!0:Sr.has(t)?!1:n},Kt="v1",Or=6e4,vr=async(e,n={})=>{const t=(n.now??Date.now())+(n.ttlMs??Or),r=`${Kt}.${String(t)}`,a=await Mt(e,r);return{expiresAtMs:t,token:`${r}.${a}`}},kr=async(e,n,t=Date.now())=>{if(e.length===0||n.length===0)return!1;const r=n.split(".");if(r.length!==3)return!1;const[a,s,l]=r;if(a!==Kt||l.length===0)return!1;const u=Number(s);if(!Number.isFinite(u)||u<=t)return!1;let f;try{f=hr(l)}catch{return!1}return pr(e,`${a}.${s}`,f)},P="/_lunora/admin/auth",Ir={INVITER_REQUIRED:400,ORG_SLUG_INVALID:400,ORG_SLUG_TAKEN:409,PASSWORD_TOO_LONG:400,PASSWORD_TOO_SHORT:400,USER_ALREADY_EXISTS:409,USER_NOT_FOUND:404},N=(e,n)=>{const t=e[n];if(typeof t!="string"||t==="")throw new d(`\`${n}\` is required`,{code:"BAD_REQUEST",status:400});return t},le=(e,n)=>{const t=e(n);if(t===void 0)throw new d(`\`${n}\` query parameter is required`,{code:"BAD_REQUEST",status:400});return t},Ft=e=>{if(typeof e=="string"||Array.isArray(e)&&e.every(n=>typeof n=="string"))return e},re=(e,n)=>typeof e[n]=="string"?e[n]:void 0,He=(e,n)=>{const t=e[n];return typeof t=="object"&&t!==null&&!Array.isArray(t)?t:void 0},ct=e=>{const n=Ft(e.role);if(n===void 0||typeof n=="string"&&n.trim()==="")throw new d("`role` is required",{code:"BAD_REQUEST",status:400});return n},dt=e=>{const n=e.permission;if(typeof n!="object"||n===null||Array.isArray(n))throw new d("`permission` object is required",{code:"BAD_REQUEST",status:400});const t={};for(const[r,a]of Object.entries(n))Array.isArray(a)&&a.every(s=>typeof s=="string")&&(t[r]=a);return t},Pr={[`${P}/capabilities`]:{build:()=>({}),http:"GET",method:"capabilities"},[`${P}/users`]:{build:({paging:e,query:n})=>{const t=n("sortDirection");return{...e,filterField:n("filterField"),filterValue:n("filterValue"),search:n("search"),searchField:n("searchField"),sortBy:n("sortBy"),sortDirection:t==="asc"||t==="desc"?t:void 0}},http:"GET",method:"listUsers"},[`${P}/sessions`]:{build:({paging:e,query:n})=>({...e,userId:n("userId")}),http:"GET",method:"listSessions"},[`${P}/accounts`]:{build:({query:e})=>({userId:le(e,"userId")}),http:"GET",method:"listAccounts"},[`${P}/passkeys`]:{build:({query:e})=>({userId:le(e,"userId")}),http:"GET",method:"listPasskeys"},[`${P}/organizations`]:{build:({paging:e})=>({...e}),http:"GET",method:"listOrganizations"},[`${P}/organizations/members`]:{build:({paging:e,query:n})=>({...e,organizationId:le(n,"organizationId")}),http:"GET",method:"listMembers"},[`${P}/organizations/invitations`]:{build:({paging:e,query:n})=>({...e,organizationId:le(n,"organizationId")}),http:"GET",method:"listInvitations"},[`${P}/config`]:{build:()=>({}),http:"GET",method:"config"},[`${P}/organizations/teams`]:{build:({paging:e,query:n})=>({...e,organizationId:le(n,"organizationId")}),http:"GET",method:"listTeams"},[`${P}/organizations/teams/members`]:{build:({paging:e,query:n})=>({...e,teamId:le(n,"teamId")}),http:"GET",method:"listTeamMembers"},[`${P}/organizations/roles`]:{build:({paging:e,query:n})=>({...e,organizationId:le(n,"organizationId")}),http:"GET",method:"listOrgRoles"},[`${P}/users/create`]:{build:({body:e})=>({data:He(e,"data"),email:N(e,"email"),name:N(e,"name"),password:re(e,"password"),role:Ft(e.role)}),http:"POST",method:"createUser"},[`${P}/users/update`]:{build:({body:e})=>{const{data:n}=e;if(typeof n!="object"||n===null||Array.isArray(n))throw new d("`data` object is required",{code:"BAD_REQUEST",status:400});return{data:n,userId:N(e,"userId")}},http:"POST",method:"updateUser"},[`${P}/users/role`]:{build:({body:e})=>({role:ct(e),userId:N(e,"userId")}),http:"POST",method:"setRole"},[`${P}/users/ban`]:{build:({body:e})=>({expiresInSeconds:typeof e.expiresInSeconds=="number"?e.expiresInSeconds:void 0,reason:re(e,"reason"),userId:N(e,"userId")}),http:"POST",method:"banUser"},[`${P}/users/unban`]:{build:({body:e})=>({userId:N(e,"userId")}),http:"POST",method:"unbanUser"},[`${P}/users/password`]:{build:({body:e})=>({newPassword:N(e,"newPassword"),userId:N(e,"userId")}),http:"POST",method:"setUserPassword",returns:"void"},[`${P}/users/remove`]:{build:({body:e})=>({userId:N(e,"userId")}),http:"POST",method:"removeUser",returns:"void"},[`${P}/users/impersonate`]:{build:({body:e})=>({userId:N(e,"userId")}),http:"POST",method:"impersonateUser"},[`${P}/sessions/revoke`]:{build:({body:e})=>({sessionId:N(e,"sessionId")}),http:"POST",method:"revokeUserSession",returns:"void"},[`${P}/sessions/revoke-all`]:{build:({body:e})=>({userId:N(e,"userId")}),http:"POST",method:"revokeUserSessions",returns:"void"},[`${P}/accounts/unlink`]:{build:({body:e})=>({accountId:N(e,"accountId"),userId:N(e,"userId")}),http:"POST",method:"unlinkAccount",returns:"void"},[`${P}/two-factor/disable`]:{build:({body:e})=>({userId:N(e,"userId")}),http:"POST",method:"disableTwoFactor",returns:"void"},[`${P}/passkeys/delete`]:{build:({body:e})=>({passkeyId:N(e,"passkeyId")}),http:"POST",method:"deletePasskey",returns:"void"},[`${P}/organizations/members/remove`]:{build:({body:e})=>({memberId:N(e,"memberId")}),http:"POST",method:"removeMember",returns:"void"},[`${P}/organizations/invitations/cancel`]:{build:({body:e})=>({invitationId:N(e,"invitationId")}),http:"POST",method:"cancelInvitation",returns:"void"},[`${P}/organizations/create`]:{build:({body:e})=>({logo:re(e,"logo"),metadata:He(e,"metadata"),name:N(e,"name"),ownerId:re(e,"ownerId"),slug:re(e,"slug")}),http:"POST",method:"createOrganization"},[`${P}/organizations/update`]:{build:({body:e})=>({logo:re(e,"logo"),metadata:He(e,"metadata"),name:re(e,"name"),organizationId:N(e,"organizationId"),slug:re(e,"slug")}),http:"POST",method:"updateOrganization"},[`${P}/organizations/remove`]:{build:({body:e})=>({organizationId:N(e,"organizationId")}),http:"POST",method:"deleteOrganization",returns:"void"},[`${P}/organizations/members/add`]:{build:({body:e})=>({organizationId:N(e,"organizationId"),role:re(e,"role"),userId:N(e,"userId")}),http:"POST",method:"addMember"},[`${P}/organizations/members/invite`]:{build:({body:e})=>({email:N(e,"email"),inviterId:re(e,"inviterId"),organizationId:N(e,"organizationId"),role:re(e,"role")}),http:"POST",method:"inviteMember"},[`${P}/organizations/members/role`]:{build:({body:e})=>({memberId:N(e,"memberId"),role:ct(e)}),http:"POST",method:"updateMemberRole"},[`${P}/organizations/teams/create`]:{build:({body:e})=>({name:N(e,"name"),organizationId:N(e,"organizationId")}),http:"POST",method:"createTeam"},[`${P}/organizations/teams/update`]:{build:({body:e})=>({name:N(e,"name"),teamId:N(e,"teamId")}),http:"POST",method:"updateTeam"},[`${P}/organizations/teams/remove`]:{build:({body:e})=>({teamId:N(e,"teamId")}),http:"POST",method:"removeTeam",returns:"void"},[`${P}/organizations/teams/members/add`]:{build:({body:e})=>({teamId:N(e,"teamId"),userId:N(e,"userId")}),http:"POST",method:"addTeamMember"},[`${P}/organizations/teams/members/remove`]:{build:({body:e})=>({teamMemberId:N(e,"teamMemberId")}),http:"POST",method:"removeTeamMember",returns:"void"},[`${P}/organizations/roles/create`]:{build:({body:e})=>({organizationId:N(e,"organizationId"),permission:dt(e),role:N(e,"role")}),http:"POST",method:"createOrgRole"},[`${P}/organizations/roles/update`]:{build:({body:e})=>({permission:dt(e),roleId:N(e,"roleId")}),http:"POST",method:"updateOrgRole"},[`${P}/organizations/roles/remove`]:{build:({body:e})=>({roleId:N(e,"roleId")}),http:"POST",method:"deleteOrgRole",returns:"void"}},Dr=e=>{const n=async a=>{try{return await a()}catch(s){if(s instanceof d)throw s;const l=s,u=typeof l.code=="string"?l.code:"AUTH_ADMIN_ERROR";throw console.error("[lunora] auth admin operation failed:",s),new d("auth admin operation failed",{code:u,status:Ir[u]??500})}},t=async(a,s)=>{if(e.assertAdmin(a),a.method!==s.http)throw new d(`Auth admin endpoint requires ${s.http}`,{code:"METHOD_NOT_ALLOWED",status:405});const l=e.getAuthAdmin();if(l===void 0)throw new d("auth endpoints require an `authAdmin` on the worker",{code:"AUTH_NOT_CONFIGURED",status:400});const u=l[s.method];if(u===void 0)throw new d(`auth admin does not support \`${s.method}\``,{code:"AUTH_OP_NOT_SUPPORTED",status:400});const f=new URL(a.url),g={body:s.http==="POST"?await e.readJsonBody(a):{},paging:e.parsePaging(a),query:v=>e.queryParameter(f,v)},E=s.build(g),k=await n(()=>u(E));return Response.json(s.returns==="void"?{ok:!0}:k,{headers:{"content-type":"application/json"},status:200})},r={};for(const[a,s]of Object.entries(Pr))r[a]=l=>t(l,s);return r},Nr="__lunora_admin__:getAuthAuditLog",ut=e=>typeof e=="string"&&e!==""?e:void 0,lt=e=>typeof e=="number"&&Number.isFinite(e)&&e>=0?e:void 0,Ur=e=>async(t,r)=>{e.assertAdmin(t);const a=e.getReader();if(a===void 0)throw new d("the auth/security audit endpoint requires an `authAuditReader` on the worker",{code:"AUTH_AUDIT_NOT_CONFIGURED",status:400});const s=ut(r.actorId),l=ut(r.event),u=lt(r.sinceSeq),f=lt(r.limit),g={...s===void 0?{}:{actorId:s},...l===void 0?{}:{event:l},...u===void 0?{}:{sinceSeq:u},...f===void 0?{}:{limit:f}};let E;try{E=await a.read(g)}catch(v){throw v instanceof d?v:(console.error("[lunora] auth audit read failed:",v),new d("auth audit read failed",{code:"AUTH_AUDIT_READ_FAILED",status:500}))}const k={entries:E};return Response.json({result:Fe(k)},{headers:{"content-type":"application/json"},status:200})},Cr=(e,n)=>{const t=[],r=[];if(n&&n.length>0)for(const a of n)e.resolveTableSharding?.(a)?.mode.kind==="global"?r.push(a):t.push(a);return{globalTables:r,shardLocalTables:t}},Br=async(e,n,t,r,a,s)=>{if(t!==void 0&&r.length===0)return;const l=await e.orchestrateExport(s,{args:{tables:r},headers:n,tables:r});for(const u of l.shards)if(!u.error)for(const f of u.rows??[])a(f)},Gt=async(e,n,t,r,a,s)=>{const{globalTables:l,shardLocalTables:u}=Cr(e,r);await Br(n,t,r,u,a,s);const f=e.exportGlobals;if((r===void 0||l.length>0)&&f)for await(const E of f({tables:l}))a(E)},xr=new TextEncoder,Hr=1e3,Qt=10,Lr=200,ht=8,zt="lunoraBackupCron",ft=24*1048576,pt=e=>{const n=e.slice(0,Qt).map(r=>xt(r)),t=e.length-n.length;return`${n.join(", ")}${t>0?` (+${String(t)} more)`:""}`},Mr=(e,n)=>{const t=new Uint8Array(new ArrayBuffer(n));let r=0;for(const a of e)t.set(a,r),r+=a.byteLength;return t},Je=async(e,n,t,r)=>{if(t===void 0||!Number.isInteger(t)||t<=0)return{eligible:0,stale:[]};const a=[];let s;for(let l=0;l<Hr;l+=1){const u=await e.list({cursor:s,include:["customMetadata"],prefix:n});for(const f of u.objects)Qn(f.key)&&f.customMetadata?.[zt]===r&&a.push(f.key);if(!u.truncated||u.cursor===void 0)break;s=u.cursor}return{eligible:a.length,stale:a.toSorted((l,u)=>u.localeCompare(l)).slice(t)}},jr=async(e,n,t,r,a)=>{const{stale:s}=await Je(e,n,t,r),l=new Set(a),u=s.filter(w=>l.has(w)),f=u.slice(0,Lr),g=s.length-f.length,E=a.length-u.length;if(f.length===0)return{deleted:[],failed:[],ignored:E,remaining:g};const k=[],v=[];for(let w=0;w<f.length;w+=ht){const b=await Promise.allSettled(f.slice(w,w+ht).map(async _=>(await e.delete(xt(_)),await e.delete(_),_)));for(const[_,p]of b.entries())p.status==="fulfilled"?k.push(p.value):v.push(f[w+_])}return k.length>0&&console.info(`[lunora] backup prune kept the newest ${String(t)} and deleted ${String(k.length)}: ${pt(k)}`),v.length>0&&console.warn(`[lunora] backup prune failed to remove ${String(v.length)}: ${pt(v)}`),{deleted:k,failed:v,ignored:E,remaining:g}},$r=async e=>{const n=e.backupStore;if(!n)throw new d("backup retention preview requires a `backupStore` on the worker",{code:"BACKUP_NOT_CONFIGURED",status:500});const t=Qe(e.backupPrefix??ze),r=e.backupCron,{eligible:a,stale:s}=r===void 0?{eligible:0,stale:[]}:await Je(n,t,e.backupRetain,r);return{cron:r,eligible:a,keep:e.backupRetain??0,prefix:t,wouldDelete:s}},Kr=async(e,n,t,r)=>{const a=e.backupStore,s=e.queryCoordinator;if(!a)throw new d("scheduled backup requires a `backupStore` on the worker",{code:"BACKUP_NOT_CONFIGURED",status:500});if(!s)throw new d("scheduled backup requires a `queryCoordinator` on the worker",{code:"BACKUP_NOT_CONFIGURED",status:500});if(!t||t.length===0)throw new d("scheduled backup requires an `adminToken` (or `env.LUNORA_ADMIN_TOKEN`) to authenticate the per-shard export gate",{code:"BACKUP_NOT_CONFIGURED",status:500});const l={authorization:`Bearer ${t}`,"content-type":"application/json"},u=e.backupTables;let f=0,g=0,E=[];await Gt(e,s,l,u,D=>{const T=xr.encode(`${JSON.stringify(D)}
|
|
1
|
+
import{isLunoraError as Nn,toErrorBody as Un}from"@lunora/errors";import{e as Nt}from"./evict-oldest-BNXsKx4s.mjs";import{NOOP_EXECUTION_CONTEXT as Cn}from"./NOOP_EXECUTION_CONTEXT-YmXqH-jH.mjs";import{e as Bn,a as xn}from"./identity-header-JF5q3H5w.mjs";import{o as Se,b as Hn,p as Ln,m as Mn,d as jn,a as $n,r as Kn}from"./otlp-resource-B4Yylr0V.mjs";import{e as Fe}from"./wire-codec-D_qTfaaH.mjs";import{e as Z,f as be,M as Ut,b as Fn,g as Gn,h as Ct,i as Bt}from"./rest-routes-D2b3HXA9.mjs";import{LunoraError as d,toErrorResponse as nt}from"./LunoraError-DksAgIpa.mjs";import{a as j,m as me}from"./method-guard-BG_vJNTl.mjs";import{normalizeBackupPrefix as Qe,BACKUP_KEY_PREFIX as ze,isBackupManifestKey as Qn,backupObjectKeyOfManifest as xt,backupObjectKey as zn,backupManifestKey as Wn}from"./BACKUP_KEY_PREFIX-BOtSu-_3.mjs";import{toHex as Vn,buildStorageAdminRoutes as Jn,STORAGE_UPLOAD_MAX_BODY_BYTES as qn,STORAGE_PATH as Yn}from"./STORAGE_UPLOAD_MAX_BODY_BYTES-BqyO-1l6.mjs";import{runExportTap as Xn}from"./createKvCursorStore-kQ8HNv0l.mjs";import{buildHealthRoutes as Zn,durableObjectProbe as er,d1Probe as tr,presenceProbe as Ce}from"./HEALTH_PATH-jZsuCmSs.mjs";import{wrapResolverWithContract as nr}from"./composeIdentityResolvers-BHZ4jH8o.mjs";import{composeIdentityResolvers as Es,routeIdentityResolvers as As}from"./composeIdentityResolvers-BHZ4jH8o.mjs";import{buildLogArchiveAdminRoutes as rr}from"./LOG_ARCHIVE_PATH-jgHjdsz2.mjs";import{r as or,f as rt,a as ce}from"./observability-vDK-rMbs.mjs";import{resolveShard as we,applyJurisdiction as ot}from"./applyJurisdiction-C0ddU7Tg.mjs";import{resolveSecurity as at,handleCorsPreflight as ar,enforceOrigin as sr,decorateResponse as Be,enforceWebSocketOrigin as st}from"./decorateResponse-D3NzOIvB.mjs";const ir=e=>{const n=e??{};if(typeof n.bucket=="function")return n;const t={...n,bucketName:"default"};return t.bucket=()=>t,t},Ht="__lunoraBranch",cr=e=>typeof e=="object"&&e!==null&&Object.hasOwn(e,Ht),dr=`may not contain the reserved workflow branch-marker key ("${Ht}")`,We=(e,n)=>{const t=Math.max(e.length,n.length);let r=e.length^n.length;for(let a=0;a<t;a+=1){const s=a<e.length?e.charCodeAt(a):0,l=a<n.length?n.charCodeAt(a):0;r|=s^l}return r===0},Ve=new TextEncoder,ur=Array.from({length:32},(e,n)=>n);new RegExp(`[${ur.map(e=>String.fromCodePoint(e)).join("")}]`,"u");const lr=e=>{const n=String.fromCodePoint(...e);return btoa(n).replaceAll("+","-").replaceAll("/","_").replaceAll("=","")},hr=e=>{const n=e.replaceAll("-","+").replaceAll("_","/")+"===".slice((e.length+3)%4),t=atob(n),r=new Uint8Array(t.length);for(let a=0;a<t.length;a+=1)r[a]=t.codePointAt(a)??0;return r},fr=64,xe=new Map,Lt=async e=>{const n=xe.get(e);if(n)return n;Nt(xe,fr);const t=crypto.subtle.importKey("raw",Ve.encode(e),{hash:"SHA-256",name:"HMAC"},!1,["sign","verify"]);return xe.set(e,t),t},Mt=async(e,n)=>{const t=await Lt(e),r=await crypto.subtle.sign("HMAC",t,Ve.encode(n));return lr(new Uint8Array(r))},pr=async(e,n,t)=>{const r=await Lt(e);return crypto.subtle.verify("HMAC",r,t,Ve.encode(n))},mr=["wnam","enam","sam","weur","eeur","apac","apac-ne","apac-se","oc","afr","me"];new Set(mr);const wr=new Set(["AE","BH","IL","IQ","IR","JO","KW","LB","OM","PS","QA","SA","SY","TR","YE"]),gr=-100,yr=15,br=e=>{const n=Number(e.longitude??Number.NaN);switch(e.continent){case"AF":return"afr";case"AS":return e.country!==void 0&&wr.has(e.country)?"me":"apac";case"EU":return Number.isFinite(n)&&n>yr?"eeur":"weur";case"NA":return Number.isFinite(n)&&n<gr?"wnam":"enam";case"OC":return"oc";case"SA":return"sam";default:return}},it=e=>{const n=e.cf;return n===void 0?void 0:br(n)},jt="::relay::",_r=(e,n)=>`${e}${jt}${String(n)}`,$t="::replica::",Rr=(e,n)=>`${e}${$t}${n}`,Er=e=>{if(e==null||!/^\d+$/.test(e))return;const n=Number.parseInt(e,10);return Number.isSafeInteger(n)&&n>0?n:void 0},Ar=new Set(["1","enabled","on","true","yes"]),Sr=new Set(["0","disabled","false","no","off"]),Tr=(e,n)=>{const t=(e??"").trim().toLowerCase();return Ar.has(t)?!0:Sr.has(t)?!1:n},Kt="v1",Or=6e4,vr=async(e,n={})=>{const t=(n.now??Date.now())+(n.ttlMs??Or),r=`${Kt}.${String(t)}`,a=await Mt(e,r);return{expiresAtMs:t,token:`${r}.${a}`}},kr=async(e,n,t=Date.now())=>{if(e.length===0||n.length===0)return!1;const r=n.split(".");if(r.length!==3)return!1;const[a,s,l]=r;if(a!==Kt||l.length===0)return!1;const u=Number(s);if(!Number.isFinite(u)||u<=t)return!1;let f;try{f=hr(l)}catch{return!1}return pr(e,`${a}.${s}`,f)},P="/_lunora/admin/auth",Ir={INVITER_REQUIRED:400,ORG_SLUG_INVALID:400,ORG_SLUG_TAKEN:409,PASSWORD_TOO_LONG:400,PASSWORD_TOO_SHORT:400,USER_ALREADY_EXISTS:409,USER_NOT_FOUND:404},N=(e,n)=>{const t=e[n];if(typeof t!="string"||t==="")throw new d(`\`${n}\` is required`,{code:"BAD_REQUEST",status:400});return t},le=(e,n)=>{const t=e(n);if(t===void 0)throw new d(`\`${n}\` query parameter is required`,{code:"BAD_REQUEST",status:400});return t},Ft=e=>{if(typeof e=="string"||Array.isArray(e)&&e.every(n=>typeof n=="string"))return e},re=(e,n)=>typeof e[n]=="string"?e[n]:void 0,He=(e,n)=>{const t=e[n];return typeof t=="object"&&t!==null&&!Array.isArray(t)?t:void 0},ct=e=>{const n=Ft(e.role);if(n===void 0||typeof n=="string"&&n.trim()==="")throw new d("`role` is required",{code:"BAD_REQUEST",status:400});return n},dt=e=>{const n=e.permission;if(typeof n!="object"||n===null||Array.isArray(n))throw new d("`permission` object is required",{code:"BAD_REQUEST",status:400});const t={};for(const[r,a]of Object.entries(n))Array.isArray(a)&&a.every(s=>typeof s=="string")&&(t[r]=a);return t},Pr={[`${P}/capabilities`]:{build:()=>({}),http:"GET",method:"capabilities"},[`${P}/users`]:{build:({paging:e,query:n})=>{const t=n("sortDirection");return{...e,filterField:n("filterField"),filterValue:n("filterValue"),search:n("search"),searchField:n("searchField"),sortBy:n("sortBy"),sortDirection:t==="asc"||t==="desc"?t:void 0}},http:"GET",method:"listUsers"},[`${P}/sessions`]:{build:({paging:e,query:n})=>({...e,userId:n("userId")}),http:"GET",method:"listSessions"},[`${P}/accounts`]:{build:({query:e})=>({userId:le(e,"userId")}),http:"GET",method:"listAccounts"},[`${P}/passkeys`]:{build:({query:e})=>({userId:le(e,"userId")}),http:"GET",method:"listPasskeys"},[`${P}/organizations`]:{build:({paging:e})=>({...e}),http:"GET",method:"listOrganizations"},[`${P}/organizations/members`]:{build:({paging:e,query:n})=>({...e,organizationId:le(n,"organizationId")}),http:"GET",method:"listMembers"},[`${P}/organizations/invitations`]:{build:({paging:e,query:n})=>({...e,organizationId:le(n,"organizationId")}),http:"GET",method:"listInvitations"},[`${P}/config`]:{build:()=>({}),http:"GET",method:"config"},[`${P}/organizations/teams`]:{build:({paging:e,query:n})=>({...e,organizationId:le(n,"organizationId")}),http:"GET",method:"listTeams"},[`${P}/organizations/teams/members`]:{build:({paging:e,query:n})=>({...e,teamId:le(n,"teamId")}),http:"GET",method:"listTeamMembers"},[`${P}/organizations/roles`]:{build:({paging:e,query:n})=>({...e,organizationId:le(n,"organizationId")}),http:"GET",method:"listOrgRoles"},[`${P}/users/create`]:{build:({body:e})=>({data:He(e,"data"),email:N(e,"email"),name:N(e,"name"),password:re(e,"password"),role:Ft(e.role)}),http:"POST",method:"createUser"},[`${P}/users/update`]:{build:({body:e})=>{const{data:n}=e;if(typeof n!="object"||n===null||Array.isArray(n))throw new d("`data` object is required",{code:"BAD_REQUEST",status:400});return{data:n,userId:N(e,"userId")}},http:"POST",method:"updateUser"},[`${P}/users/role`]:{build:({body:e})=>({role:ct(e),userId:N(e,"userId")}),http:"POST",method:"setRole"},[`${P}/users/ban`]:{build:({body:e})=>({expiresInSeconds:typeof e.expiresInSeconds=="number"?e.expiresInSeconds:void 0,reason:re(e,"reason"),userId:N(e,"userId")}),http:"POST",method:"banUser"},[`${P}/users/unban`]:{build:({body:e})=>({userId:N(e,"userId")}),http:"POST",method:"unbanUser"},[`${P}/users/password`]:{build:({body:e})=>({newPassword:N(e,"newPassword"),userId:N(e,"userId")}),http:"POST",method:"setUserPassword",returns:"void"},[`${P}/users/remove`]:{build:({body:e})=>({userId:N(e,"userId")}),http:"POST",method:"removeUser",returns:"void"},[`${P}/users/impersonate`]:{build:({body:e})=>({userId:N(e,"userId")}),http:"POST",method:"impersonateUser"},[`${P}/sessions/revoke`]:{build:({body:e})=>({sessionId:N(e,"sessionId")}),http:"POST",method:"revokeUserSession",returns:"void"},[`${P}/sessions/revoke-all`]:{build:({body:e})=>({userId:N(e,"userId")}),http:"POST",method:"revokeUserSessions",returns:"void"},[`${P}/accounts/unlink`]:{build:({body:e})=>({accountId:N(e,"accountId"),userId:N(e,"userId")}),http:"POST",method:"unlinkAccount",returns:"void"},[`${P}/two-factor/disable`]:{build:({body:e})=>({userId:N(e,"userId")}),http:"POST",method:"disableTwoFactor",returns:"void"},[`${P}/passkeys/delete`]:{build:({body:e})=>({passkeyId:N(e,"passkeyId")}),http:"POST",method:"deletePasskey",returns:"void"},[`${P}/organizations/members/remove`]:{build:({body:e})=>({memberId:N(e,"memberId")}),http:"POST",method:"removeMember",returns:"void"},[`${P}/organizations/invitations/cancel`]:{build:({body:e})=>({invitationId:N(e,"invitationId")}),http:"POST",method:"cancelInvitation",returns:"void"},[`${P}/organizations/create`]:{build:({body:e})=>({logo:re(e,"logo"),metadata:He(e,"metadata"),name:N(e,"name"),ownerId:re(e,"ownerId"),slug:re(e,"slug")}),http:"POST",method:"createOrganization"},[`${P}/organizations/update`]:{build:({body:e})=>({logo:re(e,"logo"),metadata:He(e,"metadata"),name:re(e,"name"),organizationId:N(e,"organizationId"),slug:re(e,"slug")}),http:"POST",method:"updateOrganization"},[`${P}/organizations/remove`]:{build:({body:e})=>({organizationId:N(e,"organizationId")}),http:"POST",method:"deleteOrganization",returns:"void"},[`${P}/organizations/members/add`]:{build:({body:e})=>({organizationId:N(e,"organizationId"),role:re(e,"role"),userId:N(e,"userId")}),http:"POST",method:"addMember"},[`${P}/organizations/members/invite`]:{build:({body:e})=>({email:N(e,"email"),inviterId:re(e,"inviterId"),organizationId:N(e,"organizationId"),role:re(e,"role")}),http:"POST",method:"inviteMember"},[`${P}/organizations/members/role`]:{build:({body:e})=>({memberId:N(e,"memberId"),role:ct(e)}),http:"POST",method:"updateMemberRole"},[`${P}/organizations/teams/create`]:{build:({body:e})=>({name:N(e,"name"),organizationId:N(e,"organizationId")}),http:"POST",method:"createTeam"},[`${P}/organizations/teams/update`]:{build:({body:e})=>({name:N(e,"name"),teamId:N(e,"teamId")}),http:"POST",method:"updateTeam"},[`${P}/organizations/teams/remove`]:{build:({body:e})=>({teamId:N(e,"teamId")}),http:"POST",method:"removeTeam",returns:"void"},[`${P}/organizations/teams/members/add`]:{build:({body:e})=>({teamId:N(e,"teamId"),userId:N(e,"userId")}),http:"POST",method:"addTeamMember"},[`${P}/organizations/teams/members/remove`]:{build:({body:e})=>({teamMemberId:N(e,"teamMemberId")}),http:"POST",method:"removeTeamMember",returns:"void"},[`${P}/organizations/roles/create`]:{build:({body:e})=>({organizationId:N(e,"organizationId"),permission:dt(e),role:N(e,"role")}),http:"POST",method:"createOrgRole"},[`${P}/organizations/roles/update`]:{build:({body:e})=>({permission:dt(e),roleId:N(e,"roleId")}),http:"POST",method:"updateOrgRole"},[`${P}/organizations/roles/remove`]:{build:({body:e})=>({roleId:N(e,"roleId")}),http:"POST",method:"deleteOrgRole",returns:"void"}},Dr=e=>{const n=async a=>{try{return await a()}catch(s){if(s instanceof d)throw s;const l=s,u=typeof l.code=="string"?l.code:"AUTH_ADMIN_ERROR";throw console.error("[lunora] auth admin operation failed:",s),new d("auth admin operation failed",{code:u,status:Ir[u]??500})}},t=async(a,s)=>{if(e.assertAdmin(a),a.method!==s.http)throw new d(`Auth admin endpoint requires ${s.http}`,{code:"METHOD_NOT_ALLOWED",status:405});const l=e.getAuthAdmin();if(l===void 0)throw new d("auth endpoints require an `authAdmin` on the worker",{code:"AUTH_NOT_CONFIGURED",status:400});const u=l[s.method];if(u===void 0)throw new d(`auth admin does not support \`${s.method}\``,{code:"AUTH_OP_NOT_SUPPORTED",status:400});const f=new URL(a.url),g={body:s.http==="POST"?await e.readJsonBody(a):{},paging:e.parsePaging(a),query:v=>e.queryParameter(f,v)},E=s.build(g),k=await n(()=>u(E));return Response.json(s.returns==="void"?{ok:!0}:k,{headers:{"content-type":"application/json"},status:200})},r={};for(const[a,s]of Object.entries(Pr))r[a]=l=>t(l,s);return r},Nr="__lunora_admin__:getAuthAuditLog",ut=e=>typeof e=="string"&&e!==""?e:void 0,lt=e=>typeof e=="number"&&Number.isFinite(e)&&e>=0?e:void 0,Ur=e=>async(t,r)=>{e.assertAdmin(t);const a=e.getReader();if(a===void 0)throw new d("the auth/security audit endpoint requires an `authAuditReader` on the worker",{code:"AUTH_AUDIT_NOT_CONFIGURED",status:400});const s=ut(r.actorId),l=ut(r.event),u=lt(r.sinceSeq),f=lt(r.limit),g={...s===void 0?{}:{actorId:s},...l===void 0?{}:{event:l},...u===void 0?{}:{sinceSeq:u},...f===void 0?{}:{limit:f}};let E;try{E=await a.read(g)}catch(v){throw v instanceof d?v:(console.error("[lunora] auth audit read failed:",v),new d("auth audit read failed",{code:"AUTH_AUDIT_READ_FAILED",status:500}))}const k={entries:E};return Response.json({result:Fe(k)},{headers:{"content-type":"application/json"},status:200})},Cr=(e,n)=>{const t=[],r=[];if(n&&n.length>0)for(const a of n)e.resolveTableSharding?.(a)?.mode.kind==="global"?r.push(a):t.push(a);return{globalTables:r,shardLocalTables:t}},Br=async(e,n,t,r,a,s)=>{if(t!==void 0&&r.length===0)return;const l=await e.orchestrateExport(s,{args:{tables:r},headers:n,tables:r});for(const u of l.shards)if(!u.error)for(const f of u.rows??[])a(f)},Gt=async(e,n,t,r,a,s)=>{const{globalTables:l,shardLocalTables:u}=Cr(e,r);await Br(n,t,r,u,a,s);const f=e.exportGlobals;if((r===void 0||l.length>0)&&f)for await(const E of f({tables:l}))a(E)},xr=new TextEncoder,Hr=1e3,Qt=10,Lr=200,ht=8,zt="lunoraBackupCron",ft=24*1048576,pt=e=>{const n=e.slice(0,Qt).map(r=>xt(r)),t=e.length-n.length;return`${n.join(", ")}${t>0?` (+${String(t)} more)`:""}`},Mr=(e,n)=>{const t=new Uint8Array(new ArrayBuffer(n));let r=0;for(const a of e)t.set(a,r),r+=a.byteLength;return t},Je=async(e,n,t,r)=>{if(t===void 0||!Number.isInteger(t)||t<=0)return{eligible:0,stale:[]};const a=[];let s;for(let l=0;l<Hr;l+=1){const u=await e.list({cursor:s,include:["customMetadata"],prefix:n});for(const f of u.objects)Qn(f.key)&&f.customMetadata?.[zt]===r&&a.push(f.key);if(!u.truncated||u.cursor===void 0)break;s=u.cursor}return{eligible:a.length,stale:a.toSorted((l,u)=>u.localeCompare(l)).slice(t)}},jr=async(e,n,t,r,a)=>{const{stale:s}=await Je(e,n,t,r),l=new Set(a),u=s.filter(w=>l.has(w)),f=u.slice(0,Lr),g=s.length-f.length,E=a.length-u.length;if(f.length===0)return{deleted:[],failed:[],ignored:E,remaining:g};const k=[],v=[];for(let w=0;w<f.length;w+=ht){const b=await Promise.allSettled(f.slice(w,w+ht).map(async _=>(await e.delete(xt(_)),await e.delete(_),_)));for(const[_,p]of b.entries())p.status==="fulfilled"?k.push(p.value):v.push(f[w+_])}return k.length>0&&console.info(`[lunora] backup prune kept the newest ${String(t)} and deleted ${String(k.length)}: ${pt(k)}`),v.length>0&&console.warn(`[lunora] backup prune failed to remove ${String(v.length)}: ${pt(v)}`),{deleted:k,failed:v,ignored:E,remaining:g}},$r=async e=>{const n=e.backupStore;if(!n)throw new d("backup retention preview requires a `backupStore` on the worker",{code:"BACKUP_NOT_CONFIGURED",status:500});const t=Qe(e.backupPrefix??ze),r=e.backupCron,{eligible:a,stale:s}=r===void 0?{eligible:0,stale:[]}:await Je(n,t,e.backupRetain,r);return{cron:r,eligible:a,keep:e.backupRetain??0,prefix:t,wouldDelete:s}},Kr=async(e,n,t,r)=>{const a=e.backupStore,s=e.queryCoordinator;if(!a)throw new d("scheduled backup requires a `backupStore` on the worker",{code:"BACKUP_NOT_CONFIGURED",status:500});if(!s)throw new d("scheduled backup requires a `queryCoordinator` on the worker",{code:"BACKUP_NOT_CONFIGURED",status:500});if(!t||t.length===0)throw new d("scheduled backup requires an `adminToken` (or `env.LUNORA_ADMIN_TOKEN`) to authenticate the per-shard export gate",{code:"BACKUP_NOT_CONFIGURED",status:500});const l={authorization:`Bearer ${t}`,"content-type":"application/json"},u=e.backupTables;let f=0,g=0,E=[];await Gt(e,s,l,u,D=>{const T=xr.encode(`${JSON.stringify(D)}
|
|
2
2
|
`);if(f+=1,g+=T.byteLength,g>ft)throw new d(`scheduled backup reached ${String(g)} bytes of NDJSON, past the ${String(ft)}-byte limit for a snapshot assembled inside a Worker — nothing was written. Narrow it with \`backupTables\`, or take this snapshot off-platform with \`lunora backup create --bucket\`.`,{code:"BACKUP_TOO_LARGE",status:507});E.push(T)},n);const v=Qe(e.backupPrefix??ze),w=new Date(r.scheduledTime).toISOString(),b=zn(v,w),_=Mr(E,g);E=[];const p=Vn(await crypto.subtle.digest("SHA-256",_));await a.put(b,_,{httpMetadata:{contentType:"application/x-ndjson"},sha256:p});const S={bytes:g,createdAt:w,cron:r.cron,file:b,id:w,rows:f,scheduledTime:r.scheduledTime,sha256:p,...u?{tables:u.join(",")}:{}};await a.put(Wn(b),`${JSON.stringify(S,void 0,2)}
|
|
3
3
|
`,{customMetadata:{[zt]:r.cron},httpMetadata:{contentType:"application/json"}});try{const{stale:D}=await Je(a,v,e.backupRetain,r.cron);if(D.length>0){const T=D.slice(0,Qt),x=D.length-T.length;console.info(`[lunora] backup retention: ${String(D.length)} snapshot(s) past the newest ${String(e.backupRetain)} — run \`lunora backup prune\` to remove them: ${T.join(", ")}${x>0?` (+${String(x)} more)`:""}`)}}catch(D){console.warn(`[lunora] backup ${b} was written, but the retention report failed:`,D)}},Fr=async(e,n)=>{const t=e.backupStore;if(!t)throw new d("backup prune requires a `backupStore` on the worker",{code:"BACKUP_NOT_CONFIGURED",status:500});const r=e.backupCron,a=e.backupRetain;if(r===void 0||a===void 0||!Number.isInteger(a)||a<=0)throw new d("backup prune needs a retention window: set `backupRetain` (and `backupCron`, which decides whose snapshots retention owns) on the worker. Without one there is nothing past the window to remove.",{code:"BACKUP_RETENTION_NOT_CONFIGURED",status:400});return jr(t,Qe(e.backupPrefix??ze),a,r,n)},Gr="/_lunora/admin/backup/retention",Qr="/_lunora/admin/backup/prune",zr=e=>{const{options:n,readJsonBody:t,requireAdminOption:r}=e,a=(u,f)=>{r(u,n.backupStore,{code:"BACKUP_NOT_CONFIGURED",message:`backup ${f} requires a \`backupStore\` on the worker`})},s=async u=>(j(u,"GET","Backup-retention"),a(u,"retention preview"),Response.json(await $r(n),{headers:{"cache-control":"no-store"}})),l=async u=>{j(u,"POST","Backup-prune"),a(u,"prune");const{confirm:f}=await t(u);if(!Array.isArray(f)||f.some(g=>typeof g!="string"))throw new d("backup prune requires a `confirm` array of the sidecar keys to remove — read them from `GET /_lunora/admin/backup/retention` and pass back the ones you mean to delete",{code:"BAD_REQUEST",status:400});return Response.json(await Fr(n,f),{headers:{"cache-control":"no-store"}})};return{[Qr]:l,[Gr]:s}},mt=500,Wr=(e,n,t)=>{if(typeof e!="object"||e===null||Array.isArray(e))throw new d("each batch call must be an object",{code:"BAD_REQUEST",status:400});const r=e;if(typeof r.functionPath!="string")throw new d("each batch call needs a string `functionPath`",{code:"BAD_REQUEST",status:400});if(r.functionPath.startsWith("__lunora_relation__:")||r.functionPath.startsWith("__lunora_admin__"))throw new d("reserved function path cannot be batched",{code:"FORBIDDEN",status:403});if(r.args!==void 0&&(typeof r.args!="object"||r.args===null||Array.isArray(r.args)))throw new d("each batch call `args` must be an object",{code:"BAD_REQUEST",status:400});return{entry:{args:r.args===void 0?{}:r.args,clientId:typeof r.clientId=="string"?r.clientId:void 0,clientSeq:typeof r.clientSeq=="number"?r.clientSeq:void 0,functionPath:r.functionPath,id:typeof r.id=="number"?r.id:n,mutationId:typeof r.mutationId=="string"?r.mutationId:void 0},shardKey:typeof r.shardKey=="string"?r.shardKey:t}},Vr=(e,n)=>{if(e.length>mt)throw new d(`RPC batch exceeds the ${String(mt)}-call limit`,{code:"BAD_REQUEST",status:400});const t=new Map;for(const[r,a]of e.entries()){const{entry:s,shardKey:l}=Wr(a,r,n),u=t.get(l)??[];u.push(s),t.set(l,u)}return t},Jr=new TextEncoder,qr=e=>{const n=JSON.stringify(e),t=Jr.encode(n);let r="";for(const a of t)r+=String.fromCodePoint(a);return btoa(r).replaceAll("+","-").replaceAll("/","_").replaceAll("=","")},Yr=e=>{const n={g:0,s:{},v:1};if(typeof e!="string"||e.length===0)return n;try{const t=atob(e.replaceAll("-","+").replaceAll("_","/")),r=new Uint8Array(t.length);for(let u=0;u<t.length;u+=1)r[u]=t.codePointAt(u)??0;const a=JSON.parse(new TextDecoder().decode(r)),s=a.s&&typeof a.s=="object"?a.s:{},l={};for(const[u,f]of Object.entries(s))typeof f=="number"&&Number.isFinite(f)&&(l[u]=f);return{g:typeof a.g=="number"&&Number.isFinite(a.g)?a.g:0,s:l,v:1}}catch{return n}},Xr=e=>{const n=typeof e.table=="string"?e.table:"",t=typeof e.op=="string"?e.op:"",r=t==="delete"||t==="insert"||t==="update"?t:"upsert",a=typeof e.id=="string"?e.id:void 0;return{doc:(e.doc&&typeof e.doc=="object"?e.doc:void 0)??(a===void 0?{}:{_id:a}),op:r,table:n}},wt=(e,n,t)=>{for(const r of n)e.push(Xr(r));return t!==void 0&&n.length>=t},Zr="/_lunora/admin/export",eo="/_lunora/admin/import",to="/_lunora/admin/sync",no="/_lunora/admin/connector/sync",ro="/_lunora/admin/apply",oo="/_lunora/admin/export-tap/run",ao=new TextEncoder,so=async e=>{const t=await be(e,"Export")??{};if(t.tables===void 0)return{tables:void 0};if(!Array.isArray(t.tables))throw new d("Export `tables` must be a string array",{code:"BAD_REQUEST",status:400});const r=[];for(const a of t.tables){if(typeof a!="string"||a.length===0)throw new d("Export `tables` entries must be non-empty strings",{code:"BAD_REQUEST",status:400});r.push(a)}return{tables:r}},Le=e=>Array.isArray(e)?e.filter(n=>typeof n=="string"):void 0,io=e=>{const{applyGlobals:n,exportCursorStore:t,exportSinks:r,knownTables:a,queryCoordinator:s,assertAdmin:l,requireAdminOption:u,resolveForwardContext:f,shardDO:g,streamExportRows:E,streamingImport:k,syncGlobals:v}=e,w=async(T,x)=>{const H=me(T,["POST"]);if(H)return H;const $=u(T,s,{code:"BAD_REQUEST",message:"Export endpoint requires a `queryCoordinator` on the worker"}),U=await so(T),{headers:W}=await f(T,x),K=new ReadableStream({async pull(V){const X=J=>{V.enqueue(ao.encode(`${JSON.stringify(J)}
|
|
4
4
|
`))};try{await E($,W,U.tables,X),V.close()}catch(J){V.error(J)}}});return new Response(K,{headers:{"content-type":"application/x-ndjson"},status:200})},b=async(T,x)=>{const H=me(T,["POST"]);if(H)return H;const $=u(T,s,{code:"BAD_REQUEST",message:"Sync endpoint requires a `queryCoordinator` on the worker"}),U=await Z(T),W=typeof U.cursors=="object"&&U.cursors!==null?U.cursors:{},K=typeof U.limit=="number"?U.limit:void 0,V=typeof U.globalCursor=="number"?U.globalCursor:0,X=Le(U.tables),{headers:J}=await f(T,x),ae=X??a(),F=await $.orchestrateCdcSync(g,{cursors:W,headers:J,limit:K,tables:ae}),he=v?await v({limit:K,sinceSeq:V}):void 0;return Response.json({global:he,shards:F.shards},{status:200})},_=async(T,x)=>{const H=me(T,["POST"]);if(H)return H;const $=u(T,s,{code:"BAD_REQUEST",message:"Connector sync endpoint requires a `queryCoordinator` on the worker"}),U=await Z(T),W=Yr(U.cursor),K=typeof U.limit=="number"&&U.limit>0?U.limit:void 0,V=Le(U.tables),{headers:X}=await f(T,x),J=V??a(),ae=await $.orchestrateCdcSync(g,{cursors:W.s,headers:X,limit:K,tables:J}),F=[],he={...W.s};let G=!1;for(const se of ae.shards)G=wt(F,se.changes??[],K)||G,he[se.shardKey]=se.cursor;let oe=W.g;if(v){const se=await v({limit:K,sinceSeq:W.g});G=wt(F,se.changes,K)||G,oe=se.cursor}const Te=qr({g:oe,s:he,v:1}),Oe={changes:F,hasMore:G,nextCursor:Te};return Response.json(Oe,{status:200})},p=async(T,x)=>{const H=me(T,["POST"]);if(H)return H;const $=u(T,s,{code:"BAD_REQUEST",message:"Apply endpoint requires a `queryCoordinator` on the worker"}),U=await Z(T),K=(Array.isArray(U.batches)?U.batches:[]).map(F=>F).filter(F=>F!==null&&typeof F=="object"&&typeof F.shardKey=="string"&&Array.isArray(F.changes)),V=Array.isArray(U.globalChanges)?U.globalChanges:[],{headers:X}=await f(T,x),J=await $.orchestrateApplyCdc(g,{batches:K,headers:X}),ae=V.length>0&&n?await n({changes:V}):0;return Response.json({applied:J.applied+ae,failed:J.failed,ok:J.ok},{status:200})},S=async(T,x)=>{const H=me(T,["POST"]);if(H)return H;l(T);const{headers:$}=await f(T,x),U=await k(T,$);return Response.json(U,{headers:{"content-type":"application/json"},status:200})},D=async(T,x)=>{const H=me(T,["POST"]);if(H)return H;const $=u(T,s,{code:"BAD_REQUEST",message:"Export-tap endpoint requires a `queryCoordinator` on the worker"});if(r===void 0||Object.keys(r).length===0||t===void 0)throw new d("Export-tap endpoint requires `exportSinks` + `exportCursorStore` on the worker",{code:"EXPORT_TAP_NOT_CONFIGURED",status:400});const U=await Z(T),W=typeof U.sink=="string"?U.sink:void 0,K=typeof U.limit=="number"&&U.limit>0?U.limit:void 0,V=Le(U.tables);if(W===void 0)throw new d("Export-tap `sink` must name a configured sink",{code:"BAD_REQUEST",status:400});const X=r[W];if(X===void 0)throw new d(`Export-tap sink "${W}" is not configured`,{code:"NOT_FOUND",status:404});const{headers:J}=await f(T,x),ae=V??a(),F=await Xn({coordinator:$,cursorStore:t,headers:J,limit:K,shardDO:g,sink:X,tables:ae});return Response.json(F,{headers:{"content-type":"application/json"},status:200})};return{[ro]:p,[no]:_,[Zr]:w,[oo]:D,[eo]:S,[to]:b}},co=(e,n)=>{let t;try{t=JSON.parse(e)}catch{return{error:{code:"BAD_ROW",line:n,message:"line is not valid JSON",table:""},ok:!1}}if(!t||typeof t!="object"||Array.isArray(t))return{error:{code:"BAD_ROW",line:n,message:"row must be a JSON object",table:""},ok:!1};const r=t;return typeof r.table!="string"||r.table.length===0?{error:{code:"BAD_ROW",line:n,message:"row is missing `table`",table:""},ok:!1}:!r.doc||typeof r.doc!="object"||Array.isArray(r.doc)?{error:{code:"BAD_ROW",line:n,message:"row is missing or malformed `doc`",table:r.table},ok:!1}:{doc:r.doc,ok:!0,table:r.table}},uo=(e,n,t,r,a)=>{if(t?.mode.kind==="shardBy"&&typeof t.mode.field=="string"){const s=e[t.mode.field];return s==null?{error:{code:"BAD_ROW",line:a,message:`row missing shard field "${t.mode.field}" for table "${n}"`,table:n},ok:!1}:{ok:!0,shardKey:typeof s=="string"?s:JSON.stringify(s)}}return{ok:!0,shardKey:r}},lo=async(e,n,t)=>{if(!e.body)throw new d("Import endpoint requires a request body",{code:"BAD_REQUEST",status:400});const r=[],a=[],s=new Map;let l=0,u=0;const f=e.body.getReader(),g=new TextDecoder;let E="",k=0;const v=w=>{u+=1;const b=w.trim();if(b.length===0)return;l+=1;const _=co(b,u);if(!_.ok){r.push(_.error);return}const{doc:p,table:S}=_,D=n.resolveTableSharding?.(S);if(D?.mode.kind==="global"){a.push({doc:p,line:u,table:S});return}const T=uo(p,S,D,t,u);if(!T.ok){r.push(T.error);return}const x=s.get(T.shardKey);x?x.rows.push({doc:p,table:S}):s.set(T.shardKey,{rows:[{doc:p,table:S}],shardKey:T.shardKey,startLine:u})};for(;;){const{done:w,value:b}=await f.read();if(w)break;if(b&&(k+=b.byteLength,k>Ut))throw await f.cancel().catch(()=>{}),new d("Body too large",{code:"PAYLOAD_TOO_LARGE",status:413});E+=g.decode(b,{stream:!0});let _=E.indexOf(`
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import{t as E}from"./portable-json-BAMIgqk5.mjs";const j=e=>new Promise(t=>{setTimeout(t,e)}),C=e=>{const t=typeof e.table=="string"?e.table:"",r=typeof e.op=="string"?e.op:"",s=r==="delete"||r==="insert"||r==="update"?r:"upsert",n=typeof e.id=="string"?e.id:void 0,o=e.doc&&typeof e.doc=="object"?E(e.doc):void 0,i=typeof e.seq=="number"&&Number.isFinite(e.seq)?e.seq:void 0,c=typeof e.ts=="number"&&Number.isFinite(e.ts)?e.ts:void 0;return{op:s,table:t,...o===void 0?{}:{doc:o},...n===void 0?{}:{id:n},...i===void 0?{}:{seq:i},...c===void 0?{}:{ts:c}}},$=async(e,t,r,s,n,o)=>{let i=0;for(;;)try{await e.deliver(t);return}catch(c){if(i>=r)throw c instanceof Error?c:new Error(String(c));const d=Math.min(s*2**i,n);await o(d),i+=1}},M=async e=>{const{coordinator:t,cursorStore:r,headers:s,initialBackoffMs:n=100,limit:o,maxBackoffMs:i=5e3,maxRetries:c=3,shardDO:d,sink:p,sleep:g=j,tables:w}=e,f=await r.read(p.name),v=await t.orchestrateCdcSync(d,{cursors:f,headers:s,limit:o,tables:w}),h={...f},y=[];let x=0,l=!1;for(const a of v.shards){if(a.error){y.push({error:a.error.message,shardKey:a.shardKey}),l=!0;continue}const m=a.changes??[];if(m.length===0){h[a.shardKey]=a.cursor;continue}const k=m.map(u=>C(u)),K={changes:k,cursor:a.cursor,shardKey:a.shardKey,sink:p.name};try{await $(p,K,c,n,i,g),h[a.shardKey]=a.cursor,x+=k.length,o!==void 0&&m.length>=o&&(l=!0)}catch(u){y.push({error:u instanceof Error?u.message:String(u),shardKey:a.shardKey}),l=!0}}return await r.write(p.name,h),{cursors:h,delivered:x,failures:y,hasMore:l,shards:v.shards.length}},S=e=>{if(typeof e.name!="string"||e.name.length===0)throw new Error("defineExportSink: `name` must be a non-empty string");if(typeof e.deliver!="function")throw new TypeError("defineExportSink: `deliver` must be a function");return{deliver:e.deliver,name:e.name}},b=e=>`${e.map(t=>JSON.stringify(t)).join(`
|
|
2
|
+
`)}
|
|
3
|
+
`,N=e=>{const t=e.fetchImpl??((r,s)=>fetch(r,s));return S({deliver:async r=>{const s=await t(e.url,{body:b(r.changes),headers:{"content-type":"application/x-ndjson","x-lunora-cursor":String(r.cursor),"x-lunora-shard":r.shardKey,"x-lunora-sink":r.sink,...e.headers},method:"POST"});if(!s.ok)throw new Error(`webhook export sink "${e.name}" returned ${String(s.status)}`)},name:e.name})},O=e=>{let t=e.prefix??"cdc";for(;t.endsWith("/");)t=t.slice(0,-1);return S({deliver:async r=>{const s=`${t}/${r.shardKey}/${String(r.cursor)}.ndjson`;await e.bucket.put(s,b(r.changes),{httpMetadata:{contentType:"application/x-ndjson"}})},name:e.name})},T=()=>{const e={};return{read:t=>Promise.resolve({...e[t]}),snapshot:()=>structuredClone(e),write:(t,r)=>(e[t]={...r},Promise.resolve())}},q=(e,t)=>{const r=t?.keyPrefix??"__lunora_source_cursor:export",s=n=>`${r}:${n}`;return{read:async n=>{const o=await e.get(s(n),"json");if(o===null||typeof o!="object")return{};const i={};for(const[c,d]of Object.entries(o))typeof d=="number"&&Number.isFinite(d)&&(i[c]=d);return i},write:async(n,o)=>{await e.put(s(n),JSON.stringify(o))}}};export{q as createKvCursorStore,T as createMemoryCursorStore,S as defineExportSink,O as r2Sink,M as runExportTap,C as sanitizeChange,N as webhookExportSink};
|
package/dist/packem_shared/{createShardClient-DnQNYYNU.mjs → createShardClient-CCncsgTs.mjs}
RENAMED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{LunoraError as n}from"@lunora/errors";import{e as S,a as w}from"./identity-header-JF5q3H5w.mjs";import{e as g,d as f}from"./wire-codec-
|
|
1
|
+
import{LunoraError as n}from"@lunora/errors";import{e as S,a as w}from"./identity-header-JF5q3H5w.mjs";import{e as g,d as f}from"./wire-codec-D_qTfaaH.mjs";import{applyJurisdiction as p,resolveShard as N}from"./applyJurisdiction-C0ddU7Tg.mjs";const I=e=>{if(typeof e=="string")return e;const t=e?.__lunoraRef;if(typeof t!="string"||t.length===0)throw new n("INTERNAL","createShardClient: expected a generated function reference (api.*/internal.*) or a 'namespace:fn' string");return t},x=e=>{const t=new n(e.code,e.message);return e.data!==void 0&&(t.data=f(e.data)),t},$=(e,t={})=>{const l=p(e,t.jurisdiction),m=t.system??!0,c=r=>$(e,{...t,...r});return{as:r=>c({as:r}),asSystem:()=>c({as:void 0}),call:async(r,y,o)=>{const d=I(r),h=o?.shardKey??t.shardKey;if(h===void 0||h.length===0)throw new n("INTERNAL",`createShardClient: no shard key for "${d}" — pass one to createShardClient({ shardKey }), .forShard(key), or the call's options`);const s={"content-type":"application/json"};m&&(s["x-lunora-system"]="1"),t.as&&(s["x-lunora-userid"]=S(t.as.userId),t.as.claims&&(s["x-lunora-identity"]=w(t.as.claims))),o?.mutationId!==void 0&&o.mutationId.length>0&&(s["x-lunora-mutation-id"]=o.mutationId);const a=await N(l,h).fetch(new Request("https://shard.internal/rpc",{body:JSON.stringify({args:g(y??{}),functionPath:d}),headers:s,method:"POST"})),u=a.statusText?` ${a.statusText}`:"";let i;try{i=await a.json()}catch{throw new n("INTERNAL",`createShardClient: shard response for "${d}" was not JSON (status ${String(a.status)}${u})`)}if("error"in i)throw x(i.error);if(!a.ok)throw new n("INTERNAL",`createShardClient: shard call "${d}" failed (status ${String(a.status)}${u})`);return f(i.result)},forShard:r=>c({shardKey:r})}};export{$ as createShardClient};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{t as i}from"./base64-CMlwEPti.mjs";import{d as f,i as s}from"./wire-codec-D_qTfaaH.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
|
+
import{t as b}from"./portable-json-BAMIgqk5.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};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{t as w,f as O}from"./base64-CMlwEPti.mjs";const o="$lunora.wire$",m=64,A=1024,d="__proto__",p={BigInt64Array,BigUint64Array,Float32Array,Float64Array,Int8Array,Int16Array,Int32Array,Uint8Array,Uint8ClampedArray,Uint16Array,Uint32Array},E={Error,EvalError,RangeError,ReferenceError,SyntaxError,TypeError,URIError},j=e=>{if(e===null||typeof e!="object")return!1;const t=Object.getPrototypeOf(e);return t===null||t===Object.prototype},a=(e,t=0)=>{if(t>m)throw new RangeError(`wire-codec: value nesting exceeds the ${m}-level limit`);if(e===void 0)return[o,"undefined"];if(e===null)return null;const y=typeof e;if(y==="bigint")return[o,"bigint",e.toString()];if(y==="number"){const r=e;return Number.isNaN(r)?[o,"nan"]:r===1/0?[o,"inf"]:r===-1/0?[o,"-inf"]:r}if(y!=="object")return e;if(e instanceof Date)return[o,"date",a(e.getTime(),t+1)];if(e instanceof Error){const r=e,n={};for(const c of Object.keys(r))r[c]!==void 0&&(n[c]=a(r[c],t+1));const i=[o,"error",r.name,r.message,n];return r.cause!==void 0&&i.push(a(r.cause,t+1)),i}if(e instanceof URL)return[o,"url",e.href];if(e instanceof Map)return[o,"map",[...e.entries()].map(([r,n])=>[a(r,t+1),a(n,t+1)])];if(e instanceof Set)return[o,"set",[...e].map(r=>a(r,t+1))];if(e instanceof ArrayBuffer)return[o,"bytes",w(new Uint8Array(e)),"ArrayBuffer"];if(ArrayBuffer.isView(e)){const r=e,n=r.constructor.name,i=new Uint8Array(r.buffer,r.byteOffset,r.byteLength);return n==="Uint8Array"?[o,"bytes",w(i)]:[o,"bytes",w(i),n]}if(Array.isArray(e)){const r=e.map(n=>a(n,t+1));return r.length>0&&r[0]===o?[o,"arr",r]:r}if(!j(e)){const r=e.constructor?.name??"value";throw new TypeError(`wire-codec: cannot encode a ${r} over the Lunora wire — only plain objects, arrays, and the supported built-ins (Date, Error, URL, Map, Set, ArrayBuffer/typed arrays, bigint) round-trip`)}const u=e,s={};for(const r of Object.keys(u)){const n=u[r];if(n===void 0)continue;const i=a(n,t+1);r===d?Object.defineProperty(s,r,{configurable:!0,enumerable:!0,value:i,writable:!0}):s[r]=i}return s},f=(e,t=0)=>{if(t>m)throw new RangeError(`wire-codec: value nesting exceeds the ${m}-level limit`);if(e===null||typeof e!="object")return e;if(Array.isArray(e)){if(e[0]===o)switch(e[1]){case"-inf":return-1/0;case"arr":return e[2].map(r=>f(r,t+1));case"bigint":{const r=e[2];if(typeof r!="string"||r.length>A||!/^-?\d+$/.test(r))throw new RangeError(`wire-codec: invalid or over-long bigint (max ${A} digits)`);return BigInt(r)}case"date":return new Date(f(e[2],t+1));case"map":return new Map(e[2].map(([r,n])=>[f(r,t+1),f(n,t+1)]));case"set":return new Set(e[2].map(r=>f(r,t+1)));case"url":return new URL(e[2]);case"error":{const r=e[2],n=e[3],i=(Object.hasOwn(E,r)?E[r]:void 0)??Error,c=new i(n);c.name!==r&&Object.defineProperty(c,"name",{configurable:!0,value:r,writable:!0});const g=f(e[4],t+1);for(const b of Object.keys(g))b===d?Object.defineProperty(c,b,{configurable:!0,enumerable:!0,value:g[b],writable:!0}):c[b]=g[b];return e.length>5&&Object.defineProperty(c,"cause",{configurable:!0,value:f(e[5],t+1),writable:!0}),c}case"bytes":{const r=O(e[2]),n=e[3]??"Uint8Array";if(n==="ArrayBuffer")return r.buffer.byteLength===r.byteLength?r.buffer:r.slice().buffer;const i=Object.hasOwn(p,n)?p[n]:void 0;return i?new i(r.slice().buffer):r}case"inf":return 1/0;case"nan":return Number.NaN;case"undefined":return;default:return e.map(r=>f(r,t+1))}return e.map(s=>f(s,t+1))}const y=e,u={};for(const s of Object.keys(y)){const r=f(y[s],t+1);s===d?Object.defineProperty(u,s,{configurable:!0,enumerable:!0,value:r,writable:!0}):u[s]=r}return u};export{f as d,a as e};
|
|
1
|
+
import{t as w,f as O}from"./base64-CMlwEPti.mjs";const o="$lunora.wire$",m=64,A=1024,d="__proto__",p={BigInt64Array,BigUint64Array,Float32Array,Float64Array,Int8Array,Int16Array,Int32Array,Uint8Array,Uint8ClampedArray,Uint16Array,Uint32Array},E={Error,EvalError,RangeError,ReferenceError,SyntaxError,TypeError,URIError},j=e=>{if(e===null||typeof e!="object")return!1;const t=Object.getPrototypeOf(e);return t===null||t===Object.prototype},a=(e,t=0)=>{if(t>m)throw new RangeError(`wire-codec: value nesting exceeds the ${m}-level limit`);if(e===void 0)return[o,"undefined"];if(e===null)return null;const y=typeof e;if(y==="bigint")return[o,"bigint",e.toString()];if(y==="number"){const r=e;return Number.isNaN(r)?[o,"nan"]:r===1/0?[o,"inf"]:r===-1/0?[o,"-inf"]:r}if(y!=="object")return e;if(e instanceof Date)return[o,"date",a(e.getTime(),t+1)];if(e instanceof Error){const r=e,n={};for(const c of Object.keys(r))r[c]!==void 0&&(n[c]=a(r[c],t+1));const i=[o,"error",r.name,r.message,n];return r.cause!==void 0&&i.push(a(r.cause,t+1)),i}if(e instanceof URL)return[o,"url",e.href];if(e instanceof Map)return[o,"map",[...e.entries()].map(([r,n])=>[a(r,t+1),a(n,t+1)])];if(e instanceof Set)return[o,"set",[...e].map(r=>a(r,t+1))];if(e instanceof ArrayBuffer)return[o,"bytes",w(new Uint8Array(e)),"ArrayBuffer"];if(ArrayBuffer.isView(e)){const r=e,n=r.constructor.name,i=new Uint8Array(r.buffer,r.byteOffset,r.byteLength);return n==="Uint8Array"?[o,"bytes",w(i)]:[o,"bytes",w(i),n]}if(Array.isArray(e)){const r=e.map(n=>a(n,t+1));return r.length>0&&r[0]===o?[o,"arr",r]:r}if(!j(e)){const r=e.constructor?.name??"value";throw new TypeError(`wire-codec: cannot encode a ${r} over the Lunora wire — only plain objects, arrays, and the supported built-ins (Date, Error, URL, Map, Set, ArrayBuffer/typed arrays, bigint) round-trip`)}const u=e,s={};for(const r of Object.keys(u)){const n=u[r];if(n===void 0)continue;const i=a(n,t+1);r===d?Object.defineProperty(s,r,{configurable:!0,enumerable:!0,value:i,writable:!0}):s[r]=i}return s},f=(e,t=0)=>{if(t>m)throw new RangeError(`wire-codec: value nesting exceeds the ${m}-level limit`);if(e===null||typeof e!="object")return e;if(Array.isArray(e)){if(e[0]===o)switch(e[1]){case"-inf":return-1/0;case"arr":return e[2].map(r=>f(r,t+1));case"bigint":{const r=e[2];if(typeof r!="string"||r.length>A||!/^-?\d+$/.test(r))throw new RangeError(`wire-codec: invalid or over-long bigint (max ${A} digits)`);return BigInt(r)}case"date":return new Date(f(e[2],t+1));case"map":return new Map(e[2].map(([r,n])=>[f(r,t+1),f(n,t+1)]));case"set":return new Set(e[2].map(r=>f(r,t+1)));case"url":return new URL(e[2]);case"error":{const r=e[2],n=e[3],i=(Object.hasOwn(E,r)?E[r]:void 0)??Error,c=new i(n);c.name!==r&&Object.defineProperty(c,"name",{configurable:!0,value:r,writable:!0});const g=f(e[4],t+1);for(const b of Object.keys(g))b===d?Object.defineProperty(c,b,{configurable:!0,enumerable:!0,value:g[b],writable:!0}):c[b]=g[b];return e.length>5&&Object.defineProperty(c,"cause",{configurable:!0,value:f(e[5],t+1),writable:!0}),c}case"bytes":{const r=O(e[2]),n=e[3]??"Uint8Array";if(n==="ArrayBuffer")return r.buffer.byteLength===r.byteLength?r.buffer:r.slice().buffer;const i=Object.hasOwn(p,n)?p[n]:void 0;return i?new i(r.slice().buffer):r}case"inf":return 1/0;case"nan":return Number.NaN;case"undefined":return;default:return e.map(r=>f(r,t+1))}return e.map(s=>f(s,t+1))}const y=e,u={};for(const s of Object.keys(y)){const r=f(y[s],t+1);s===d?Object.defineProperty(u,s,{configurable:!0,enumerable:!0,value:r,writable:!0}):u[s]=r}return u};export{f as d,a as e,j as i};
|
package/package.json
CHANGED
|
@@ -1,3 +0,0 @@
|
|
|
1
|
-
const E=e=>new Promise(t=>{setTimeout(t,e)}),j=e=>{const t=typeof e.table=="string"?e.table:"",r=typeof e.op=="string"?e.op:"",s=r==="delete"||r==="insert"||r==="update"?r:"upsert",o=typeof e.id=="string"?e.id:void 0,n=e.doc&&typeof e.doc=="object"?e.doc:void 0,i=typeof e.seq=="number"&&Number.isFinite(e.seq)?e.seq:void 0,c=typeof e.ts=="number"&&Number.isFinite(e.ts)?e.ts:void 0;return{op:s,table:t,...n===void 0?{}:{doc:n},...o===void 0?{}:{id:o},...i===void 0?{}:{seq:i},...c===void 0?{}:{ts:c}}},C=async(e,t,r,s,o,n)=>{let i=0;for(;;)try{await e.deliver(t);return}catch(c){if(i>=r)throw c instanceof Error?c:new Error(String(c));const d=Math.min(s*2**i,o);await n(d),i+=1}},$=async e=>{const{coordinator:t,cursorStore:r,headers:s,initialBackoffMs:o=100,limit:n,maxBackoffMs:i=5e3,maxRetries:c=3,shardDO:d,sink:h,sleep:w=E,tables:b}=e,f=await r.read(h.name),v=await t.orchestrateCdcSync(d,{cursors:f,headers:s,limit:n,tables:b}),p={...f},y=[];let x=0,l=!1;for(const a of v.shards){if(a.error){y.push({error:a.error.message,shardKey:a.shardKey}),l=!0;continue}const m=a.changes??[];if(m.length===0){p[a.shardKey]=a.cursor;continue}const k=m.map(u=>j(u)),K={changes:k,cursor:a.cursor,shardKey:a.shardKey,sink:h.name};try{await C(h,K,c,o,i,w),p[a.shardKey]=a.cursor,x+=k.length,n!==void 0&&m.length>=n&&(l=!0)}catch(u){y.push({error:u instanceof Error?u.message:String(u),shardKey:a.shardKey}),l=!0}}return await r.write(h.name,p),{cursors:p,delivered:x,failures:y,hasMore:l,shards:v.shards.length}},S=e=>{if(typeof e.name!="string"||e.name.length===0)throw new Error("defineExportSink: `name` must be a non-empty string");if(typeof e.deliver!="function")throw new TypeError("defineExportSink: `deliver` must be a function");return{deliver:e.deliver,name:e.name}},g=e=>`${e.map(t=>JSON.stringify(t)).join(`
|
|
2
|
-
`)}
|
|
3
|
-
`,M=e=>{const t=e.fetchImpl??((r,s)=>fetch(r,s));return S({deliver:async r=>{const s=await t(e.url,{body:g(r.changes),headers:{"content-type":"application/x-ndjson","x-lunora-cursor":String(r.cursor),"x-lunora-shard":r.shardKey,"x-lunora-sink":r.sink,...e.headers},method:"POST"});if(!s.ok)throw new Error(`webhook export sink "${e.name}" returned ${String(s.status)}`)},name:e.name})},N=e=>{let t=e.prefix??"cdc";for(;t.endsWith("/");)t=t.slice(0,-1);return S({deliver:async r=>{const s=`${t}/${r.shardKey}/${String(r.cursor)}.ndjson`;await e.bucket.put(s,g(r.changes),{httpMetadata:{contentType:"application/x-ndjson"}})},name:e.name})},O=()=>{const e={};return{read:t=>Promise.resolve({...e[t]}),snapshot:()=>structuredClone(e),write:(t,r)=>(e[t]={...r},Promise.resolve())}},P=(e,t)=>{const r=t?.keyPrefix??"__lunora_source_cursor:export",s=o=>`${r}:${o}`;return{read:async o=>{const n=await e.get(s(o),"json");if(n===null||typeof n!="object")return{};const i={};for(const[c,d]of Object.entries(n))typeof d=="number"&&Number.isFinite(d)&&(i[c]=d);return i},write:async(o,n)=>{await e.put(s(o),JSON.stringify(n))}}};export{P as createKvCursorStore,O as createMemoryCursorStore,S as defineExportSink,N as r2Sink,$ as runExportTap,j as sanitizeChange,M as webhookExportSink};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
const p=(s,c="_id")=>{const o=Object.create(null),t=Object.create(null),n=Object.create(null),a=Object.create(null),h=e=>typeof c=="string"?c:c[e]??"_id",r=(e,u)=>{const l=e[u];if(l)return l;const d=[];return e[u]=d,d};for(const e of s.changes)a[e.table]??={primary_key:[h(e.table)]},e.op==="delete"?r(n,e.table).push(e.doc):e.op==="update"?r(t,e.table).push(e.doc):r(o,e.table).push(e.doc);return{delete:n,hasMore:s.hasMore,insert:o,schema:a,state:{cursor:s.nextCursor},update:t}},b=(s,c=Date.now())=>{const o=[];for(const t of s.changes){const n=t.op==="delete"?{...t.doc,_lunora_deleted:!0}:t.doc;o.push({record:{data:n,emitted_at:c,stream:t.table},type:"RECORD"})}return o.push({state:{data:{cursor:s.nextCursor}},type:"STATE"}),o};export{b as toAirbyteMessages,p as toFivetranResponse};
|