@lunora/auth 1.0.0-alpha.213 → 1.0.0-alpha.215

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.mjs CHANGED
@@ -1 +1 @@
1
- import{l as r,a as o,b as a}from"./packem_shared/adapter-CBZ17jKi.mjs";import{LunoraAuthAdminError as u,createAuthAdmin as s}from"./packem_shared/LunoraAuthAdminError-uhKG1MgQ.mjs";import{AUTH_AUDIT_TABLE as n,appendAuthAuditEntry as m,createAuthAuditReader as h,ensureAuthAuditTable as l,readAuthAuditLog as p}from"./audit.mjs";import{authAuditHook as f,buildAuditEntry as x,eventForPath as E,withAuthAudit as T}from"./packem_shared/authAuditHook-DPTKdjBe.mjs";import{R as c,I as S,a as _,L as v}from"./packem_shared/auth-do-Dr3ogic7.mjs";import{createAuth as H,resolveAuthOptions as I}from"./packem_shared/createAuth-B-Pq7nmN.mjs";import{authDiscoveryPaths as P,authDiscoveryPathsFor as L,handleAuthDiscoveryRequest as g}from"./packem_shared/authDiscoveryPaths-B14lM14u.mjs";import{authDoColumnAdditions as O,authDoSchemaStatements as w}from"./packem_shared/authDoColumnAdditions-UwF3Rl41.mjs";import{createDoAuthWiring as F}from"./packem_shared/createDoAuthWiring-BpLmcH71.mjs";import{emailGateDatabaseHooks as k,withEmailGate as q}from"./packem_shared/emailGateDatabaseHooks-BYLUpiN_.mjs";import{assertEmailAllowed as G,classifyEmail as M,emailGateMiddleware as B,loadEmailDomainLists as W}from"./email-guard.mjs";import{DEFAULT_AUTH_BASE_PATH as Y,handleAuthRequest as j}from"./packem_shared/DEFAULT_AUTH_BASE_PATH-DneiLGpv.mjs";import{createSignUpInvitation as J,listSignUpInvitations as K,pruneSignUpInvitations as Q,revokeSignUpInvitation as X}from"./packem_shared/createSignUpInvitation-DHZL9fNl.mjs";import{legacyIssuerCleanupStatements as $}from"./packem_shared/legacyIssuerCleanupStatements-D9Kf8OD1.mjs";import{LunoraAuthHeadersError as et,withAuthPlugins as rt}from"./middleware.mjs";import{default as at}from"./schema.mjs";import{sessionPresets as ut,validateSessionPolicy as st}from"./packem_shared/sessionPresets-C867Mlo4.mjs";import{c as nt,d as mt}from"./packem_shared/sql-store-uMubPYI9.mjs";import{createMemoryAuthStore as lt,matchesWhere as pt}from"./store.mjs";import{TURNSTILE_VERIFY_ENDPOINT as ft,verifyTurnstile as xt}from"./turnstile.mjs";import{verifyTurnstileMiddleware as Tt}from"./turnstile-middleware.mjs";export{n as AUTH_AUDIT_TABLE,c as AUTH_DO_AUDIT_PATH,S as AUTH_DO_SECRET_HEADER,_ as AUTH_DO_SESSION_PATH,Y as DEFAULT_AUTH_BASE_PATH,u as LunoraAuthAdminError,v as LunoraAuthDO,et as LunoraAuthHeadersError,ft as TURNSTILE_VERIFY_ENDPOINT,m as appendAuthAuditEntry,G as assertEmailAllowed,f as authAuditHook,P as authDiscoveryPaths,L as authDiscoveryPathsFor,O as authDoColumnAdditions,w as authDoSchemaStatements,at as authTables,x as buildAuditEntry,M as classifyEmail,H as createAuth,s as createAuthAdmin,h as createAuthAuditReader,F as createDoAuthWiring,lt as createMemoryAuthStore,J as createSignUpInvitation,nt as createSqlAuthStore,mt as d1Executor,k as emailGateDatabaseHooks,B as emailGateMiddleware,l as ensureAuthAuditTable,E as eventForPath,g as handleAuthDiscoveryRequest,j as handleAuthRequest,$ as legacyIssuerCleanupStatements,K as listSignUpInvitations,W as loadEmailDomainLists,r as lunoraAuthAdapter,o as lunoraD1Adapter,a as lunoraDoAdapter,pt as matchesWhere,Q as pruneSignUpInvitations,p as readAuthAuditLog,I as resolveAuthOptions,X as revokeSignUpInvitation,ut as sessionPresets,st as validateSessionPolicy,xt as verifyTurnstile,Tt as verifyTurnstileMiddleware,T as withAuthAudit,rt as withAuthPlugins,q as withEmailGate};
1
+ import{l as r,a as o,b as a}from"./packem_shared/adapter-CBZ17jKi.mjs";import{LunoraAuthAdminError as u,createAuthAdmin as s}from"./packem_shared/LunoraAuthAdminError-uhKG1MgQ.mjs";import{AUTH_AUDIT_TABLE as n,appendAuthAuditEntry as m,createAuthAuditReader as h,ensureAuthAuditTable as l,readAuthAuditLog as p}from"./audit.mjs";import{authAuditHook as f,buildAuditEntry as x,eventForPath as E,withAuthAudit as T}from"./packem_shared/authAuditHook-DPTKdjBe.mjs";import{R as c,I as S,a as _,L as v}from"./packem_shared/auth-do-nKx0bUTe.mjs";import{createAuth as H,resolveAuthOptions as I}from"./packem_shared/createAuth-B-Pq7nmN.mjs";import{authDiscoveryPaths as P,authDiscoveryPathsFor as L,handleAuthDiscoveryRequest as g}from"./packem_shared/authDiscoveryPaths-B14lM14u.mjs";import{authDoColumnAdditions as O,authDoSchemaStatements as w}from"./packem_shared/authDoColumnAdditions-UwF3Rl41.mjs";import{createDoAuthWiring as F}from"./packem_shared/createDoAuthWiring-az8FcbYw.mjs";import{emailGateDatabaseHooks as k,withEmailGate as q}from"./packem_shared/emailGateDatabaseHooks-BYLUpiN_.mjs";import{assertEmailAllowed as G,classifyEmail as M,emailGateMiddleware as B,loadEmailDomainLists as W}from"./email-guard.mjs";import{DEFAULT_AUTH_BASE_PATH as Y,handleAuthRequest as j}from"./packem_shared/DEFAULT_AUTH_BASE_PATH-DneiLGpv.mjs";import{createSignUpInvitation as J,listSignUpInvitations as K,pruneSignUpInvitations as Q,revokeSignUpInvitation as X}from"./packem_shared/createSignUpInvitation-DHZL9fNl.mjs";import{legacyIssuerCleanupStatements as $}from"./packem_shared/legacyIssuerCleanupStatements-D9Kf8OD1.mjs";import{LunoraAuthHeadersError as et,withAuthPlugins as rt}from"./middleware.mjs";import{default as at}from"./schema.mjs";import{sessionPresets as ut,validateSessionPolicy as st}from"./packem_shared/sessionPresets-C867Mlo4.mjs";import{c as nt,d as mt}from"./packem_shared/sql-store-uMubPYI9.mjs";import{createMemoryAuthStore as lt,matchesWhere as pt}from"./store.mjs";import{TURNSTILE_VERIFY_ENDPOINT as ft,verifyTurnstile as xt}from"./turnstile.mjs";import{verifyTurnstileMiddleware as Tt}from"./turnstile-middleware.mjs";export{n as AUTH_AUDIT_TABLE,c as AUTH_DO_AUDIT_PATH,S as AUTH_DO_SECRET_HEADER,_ as AUTH_DO_SESSION_PATH,Y as DEFAULT_AUTH_BASE_PATH,u as LunoraAuthAdminError,v as LunoraAuthDO,et as LunoraAuthHeadersError,ft as TURNSTILE_VERIFY_ENDPOINT,m as appendAuthAuditEntry,G as assertEmailAllowed,f as authAuditHook,P as authDiscoveryPaths,L as authDiscoveryPathsFor,O as authDoColumnAdditions,w as authDoSchemaStatements,at as authTables,x as buildAuditEntry,M as classifyEmail,H as createAuth,s as createAuthAdmin,h as createAuthAuditReader,F as createDoAuthWiring,lt as createMemoryAuthStore,J as createSignUpInvitation,nt as createSqlAuthStore,mt as d1Executor,k as emailGateDatabaseHooks,B as emailGateMiddleware,l as ensureAuthAuditTable,E as eventForPath,g as handleAuthDiscoveryRequest,j as handleAuthRequest,$ as legacyIssuerCleanupStatements,K as listSignUpInvitations,W as loadEmailDomainLists,r as lunoraAuthAdapter,o as lunoraD1Adapter,a as lunoraDoAdapter,pt as matchesWhere,Q as pruneSignUpInvitations,p as readAuthAuditLog,I as resolveAuthOptions,X as revokeSignUpInvitation,ut as sessionPresets,st as validateSessionPolicy,xt as verifyTurnstile,Tt as verifyTurnstileMiddleware,T as withAuthAudit,rt as withAuthPlugins,q as withEmailGate};
@@ -1 +1 @@
1
- import{I as R,L as _,R as S,a as T}from"./auth-do-Dr3ogic7.mjs";import"./adapter-CBZ17jKi.mjs";import"../audit.mjs";import"./createAuth-B-Pq7nmN.mjs";import"./authDiscoveryPaths-B14lM14u.mjs";import"./authDoColumnAdditions-UwF3Rl41.mjs";import"./DEFAULT_AUTH_BASE_PATH-DneiLGpv.mjs";import"./legacyIssuerCleanupStatements-D9Kf8OD1.mjs";export{R as INTERNAL_SECRET_HEADER,_ as LunoraAuthDO,S as READ_AUDIT_PATH,T as RESOLVE_SESSION_PATH};
1
+ import{I as R,L as _,R as S,a as T}from"./auth-do-nKx0bUTe.mjs";import"./adapter-CBZ17jKi.mjs";import"../audit.mjs";import"./createAuth-B-Pq7nmN.mjs";import"./authDiscoveryPaths-B14lM14u.mjs";import"./authDoColumnAdditions-UwF3Rl41.mjs";import"./DEFAULT_AUTH_BASE_PATH-DneiLGpv.mjs";import"./legacyIssuerCleanupStatements-D9Kf8OD1.mjs";export{R as INTERNAL_SECRET_HEADER,_ as LunoraAuthDO,S as READ_AUDIT_PATH,T as RESOLVE_SESSION_PATH};
@@ -0,0 +1 @@
1
+ import{getAuthTablesWithResolvedIndexes as M}from"@better-auth/core/db/internal";import{LunoraError as w,toErrorBody as Y}from"@lunora/errors";import{d as U,b as K}from"./adapter-CBZ17jKi.mjs";import{AUTH_AUDIT_TABLE as Q,ensureAuthAuditTable as z,createAuthAuditReader as Z}from"../audit.mjs";import{resolveAuthOptions as ee,createAuth as te}from"./createAuth-B-Pq7nmN.mjs";import{handleAuthDiscoveryRequest as ne}from"./authDiscoveryPaths-B14lM14u.mjs";import{authDoSchemaStatements as se,authDoColumnAdditions as re}from"./authDoColumnAdditions-UwF3Rl41.mjs";import{handleAuthRequest as oe}from"./DEFAULT_AUTH_BASE_PATH-DneiLGpv.mjs";import{decodeWire as I,encodeWire as j}from"@lunora/wire";import{q as a}from"./quote-identifier-CGiYFBvY.mjs";import{schemaDeclaresIssuer as ie,legacyIssuerCleanupStatements as ae,indexesReferencingIssuer as ce}from"./legacyIssuerCleanupStatements-D9Kf8OD1.mjs";const ue=(t,e)=>{const n=Math.max(t.length,e.length);let s=t.length^e.length;for(let r=0;r<n;r+=1){const o=r<t.length?t.charCodeAt(r):0,i=r<e.length?e.charCodeAt(r):0;s|=o^i}return s===0},v=2166136261,F=16777619,k=(t,e=v)=>{let n=e;for(let s=0;s<t.length;s+=1)n^=t.charCodeAt(s),n=Math.imul(n,F);return(n>>>0).toString(16).padStart(8,"0")},le=t=>`${k(t,v)}${k(t,F)}`,fe="/__lunora/auth/move",T="__lunora_auth_move__",R="__lunora_auth_move_rows__",y="__lunora_auth_purged__",x=100,me=16,pe=100,de=2n**64n,H=t=>t.startsWith("sqlite_")||t.startsWith("_cf_")||t===T||t===R||t===y,P=async(t,e)=>t.transaction(async()=>Promise.resolve().then(e)),m=(t,e,...n)=>[...t.sql.exec(e,...n)],u=(t,e,...n)=>{[...t.sql.exec(e,...n)]},_=t=>m(t,"SELECT name FROM sqlite_master WHERE type = 'table' ORDER BY name").map(e=>String(e.name)).filter(e=>!H(e)),q=(t,e)=>m(t,"SELECT name, pk FROM pragma_table_info(?)",e).map(n=>({name:String(n.name),pk:Number(n.pk)})),g=(t,e)=>q(t,e).map(({name:n})=>n),W=(t,e)=>{const n=q(t,e),s=n.filter(({pk:r})=>r>0).toSorted((r,o)=>r.pk-o.pk).map(({name:r})=>r);return s.length>0?s:n.map(({name:r})=>r)},B=(t,e)=>Number(m(t,`SELECT count(*) AS n FROM ${a(e)}`)[0]?.n??0),V=t=>JSON.stringify(j(t)),b=(t,e)=>BigInt(`0x${le(V(e.map(n=>t[n]??null)))}`),G=(t,e)=>{let n=0,s=0n;for(const r of t)n+=1,s=(s+e(r))%de;return`${String(n)}:${s.toString(16)}`},X=(t,e)=>{const n=g(t,e).toSorted((s,r)=>s.localeCompare(r));return G(t.sql.exec(`SELECT * FROM ${a(e)}`),s=>b(s,n))},Ee=t=>_(t).map(e=>{const n=m(t,"SELECT sql FROM sqlite_master WHERE type = 'table' AND name = ?",e)[0]?.sql,s=m(t,"SELECT name, sql FROM sqlite_master WHERE type = 'index' AND tbl_name = ? AND sql IS NOT NULL",e).map(r=>({name:String(r.name),sql:String(r.sql)}));return{columns:g(t,e),indexes:s,name:e,rows:B(t,e),sql:typeof n=="string"?n:""}}),C=(t,e)=>{if(typeof e!="string"||!_(t).includes(e))throw new TypeError(`unknown table ${JSON.stringify(e)}`);return e},he=(t,e,n)=>{const s=m(t,`SELECT rowid AS "__lunora_rowid__", * FROM ${a(e)} WHERE rowid > ? ORDER BY rowid LIMIT ?`,n,x),r=s.at(-1)?.__lunora_rowid__;return{last:typeof r=="number"?r:void 0,rows:s.map(({__lunora_rowid__:o,...i})=>i)}},Te=t=>g(t,T).length>0,O=t=>Te(t)?Object.fromEntries(m(t,`SELECT tbl, after, done, pass, cols, watermark FROM ${a(T)}`).map(e=>[String(e.tbl),{after:Number(e.after),columns:JSON.parse(String(e.cols)),done:e.done===1,pass:Number(e.pass),watermark:Number(e.watermark)}])):{},Se=(t,e,n)=>G(t.sql.exec(`SELECT h FROM ${a(R)} WHERE tbl = ? AND pass = ?`,e,n),s=>BigInt(`0x${String(s.h)}`)),we=t=>{u(t,`CREATE TABLE IF NOT EXISTS ${a(T)} (tbl TEXT NOT NULL PRIMARY KEY, after INTEGER NOT NULL, done INTEGER NOT NULL, pass INTEGER NOT NULL, cols TEXT NOT NULL, watermark INTEGER NOT NULL DEFAULT 0)`),u(t,`CREATE TABLE IF NOT EXISTS ${a(R)} (tbl TEXT NOT NULL, k TEXT NOT NULL, h TEXT NOT NULL, pass INTEGER NOT NULL, PRIMARY KEY (tbl, k))`)},Re=(t,e,n)=>{if(!_(t).includes(e))return 0;const s=W(t,e).map(r=>`u.${a(r)}`).join(", ");return Number(m(t,`SELECT count(*) AS n FROM ${a(e)} u WHERE u.rowid > ? AND NOT EXISTS (SELECT 1 FROM ${a(R)} c WHERE c.tbl = ? AND c.k = json_array(${s}))`,n,e)[0]?.n??0)},Ae=/^CREATE TABLE /iu,Ne=/^CREATE (?:UNIQUE )?INDEX /iu,_e=(t,e,n)=>{if(H(e.name))throw new TypeError(`refusing reserved table ${JSON.stringify(e.name)}`);if(!Ae.test(e.sql)||e.indexes.some(({sql:r})=>!Ne.test(r)))throw new TypeError(`refusing unexpected DDL for ${JSON.stringify(e.name)}`);if(n.has(e.name)){const r=new Set(g(t,e.name));for(const o of e.columns.filter(i=>!r.has(i)))u(t,`ALTER TABLE ${a(e.name)} ADD COLUMN ${a(o)}`)}else u(t,e.sql);const s=new Set(m(t,"SELECT name FROM sqlite_master WHERE type = 'index'").map(r=>String(r.name)));for(const r of e.indexes.filter(({name:o})=>!s.has(o)))u(t,r.sql)},Oe=(t,e,n)=>{we(t);const s=Re(t,n.userTable,O(t)[n.userTable]?.watermark??0);if(s>0&&!n.force)throw new w("AUTH_MOVE_TARGET_NOT_EMPTY",`the pinned auth object has ${String(s)} user(s) the copy did not write; copying into it would merge two user bases — pass force to copy anyway`,{data:{users:s}});const r=new Set(_(t)),o=O(t);for(const c of e){_e(t,c,r);const f=o[c.name],p=JSON.stringify(c.columns.toSorted((d,E)=>d.localeCompare(E)));f===void 0?u(t,`INSERT INTO ${a(T)} (tbl, after, done, pass, cols) VALUES (?, 0, 0, 1, ?)`,c.name,p):u(t,`UPDATE ${a(T)} SET cols = ? WHERE tbl = ?`,p,c.name)}u(t,`UPDATE ${a(T)} SET watermark = (SELECT coalesce(max(rowid), 0) FROM ${a(n.userTable)}) WHERE tbl = ?`,n.userTable);const i=O(t);return{cursors:Object.fromEntries(e.map(({name:c})=>[c,i[c]?.after??0])),done:Object.fromEntries(e.map(({name:c})=>[c,i[c]?.done??!1])),targetRows:Object.fromEntries(e.map(({name:c})=>[c,B(t,c)]))}},J=(t,e,n,s,r)=>m(t,`SELECT ${r.map(o=>a(o)).join(", ")} FROM ${a(e)} WHERE ${n.map(o=>`${a(o)} IS ?`).join(" AND ")} LIMIT 1`,...s)[0],$=(t,e)=>{if(!e)throw new w("AUTH_MOVE_CONFLICT",`a row copied into ${t} collides with a row the pinned auth object holds on its own — nothing from this page was written; pass force to keep the pinned object's rows`,{data:{table:t}});return"conflicts"},ge=t=>t instanceof Error&&t.message.includes("UNIQUE constraint failed"),Le=(t,e)=>{if(e.prior!==void 0)return $(e.table,e.force);try{u(t,`INSERT INTO ${a(e.table)} (${e.columns.map(n=>a(n)).join(", ")}) VALUES (${e.columns.map(()=>"?").join(", ")})`,...e.columns.map(n=>e.row[n]))}catch(n){if(!ge(n))throw n;return $(e.table,e.force)}return"copied"},ye=(t,e,n)=>{const s=b(n,e.columns).toString(16);return s===e.h?"unchanged":e.prior===void 0||s!==e.prior?$(e.table,e.force):(u(t,`UPDATE ${a(e.table)} SET ${e.columns.map(r=>`${a(r)} = ?`).join(", ")} WHERE ${e.keys.map(r=>`${a(r)} IS ?`).join(" AND ")}`,...e.columns.map(r=>e.row[r]),...e.key),"updated")},$e=(t,e,n,s)=>{const{force:r,keys:o,pass:i}=s,c=Object.keys(n).toSorted((S,L)=>S.localeCompare(L));if(c.length+o.length>pe)throw new TypeError(`${e} has too many columns to copy`);const f=o.map(S=>n[S]??null),p=V(f),d=b(n,c).toString(16),E=m(t,`SELECT h FROM ${a(R)} WHERE tbl = ? AND k = ?`,e,p)[0]?.h,l={columns:c,force:r,h:d,key:f,keys:o,prior:typeof E=="string"?E:void 0,row:n,table:e},h=l.prior===d?void 0:J(t,e,o,f,c);let A="unchanged";return l.prior!==d&&(A=h===void 0?Le(t,l):ye(t,l,h)),u(t,`INSERT INTO ${a(R)} (tbl, k, h, pass) VALUES (?, ?, ?, ?) ON CONFLICT (tbl, k) DO UPDATE SET h = excluded.h, pass = excluded.pass`,e,p,d,i),A},be=(t,e,n)=>{const{counts:s,force:r,keys:o,marker:i}=n,c=m(t,`SELECT k, h FROM ${a(R)} WHERE tbl = ? AND pass < ?`,e,i.pass);for(const f of c){const p=I(JSON.parse(String(f.k))),d=J(t,e,o,p,i.columns);d!==void 0&&(b(d,i.columns).toString(16)===String(f.h)?(u(t,`DELETE FROM ${a(e)} WHERE ${o.map(E=>`${a(E)} IS ?`).join(" AND ")}`,...p),s.deleted+=1):s[$(e,r)]+=1),u(t,`DELETE FROM ${a(R)} WHERE tbl = ? AND k = ?`,e,String(f.k))}},Ie=async(t,e,n)=>{const s=O(t)[e];if(s===void 0)throw new TypeError(`table ${JSON.stringify(e)} was not part of this move`);return P(t,()=>{const r={conflicts:0,copied:0,deleted:0,unchanged:0,updated:0},o=W(t,e);for(const i of n.rows)r[$e(t,e,i,{force:n.force,keys:o,pass:s.pass})]+=1;return n.final&&be(t,e,{counts:r,force:n.force,keys:o,marker:s}),u(t,`UPDATE ${a(T)} SET after = ?, done = ? WHERE tbl = ?`,n.last,n.final?1:0,e),r})},De=async(t,e)=>{const n=_(t);return await P(t,()=>{const s=n.filter(o=>e[o]===void 0);if(s.length>0)throw new w("AUTH_MOVE_INCOMPLETE",`refusing to purge the un-pinned auth object: ${s.join(", ")} not fully copied — run the copy to done: true first`,{data:{unfinished:s}});const r=n.filter(o=>X(t,o)!==e[o]);if(r.length>0)throw new w("AUTH_MOVE_SOURCE_CHANGED",`refusing to purge the un-pinned auth object: ${r.join(", ")} changed since it was copied — run the copy again to carry the changes, then purge`,{data:{changed:r}});for(const o of n)u(t,`DROP TABLE ${a(o)}`);u(t,`CREATE TABLE IF NOT EXISTS ${a(y)} (at INTEGER NOT NULL)`),u(t,`INSERT INTO ${a(y)} (at) VALUES (?)`,Date.now())}),{dropped:n}},Me=t=>{if(g(t,y).length>0)throw new w("AUTH_MOVE_SOURCE_PURGED","the un-pinned auth object was purged after its tables were copied; anything in it now is new, and copying it would delete the pinned object's users")},Ue=new Set(["fingerprints","manifest","page","purge"]),ke=(t,e,n)=>{e.prepare();const s=O(t);return{copied:n?Object.fromEntries(Object.entries(s).map(([r,o])=>[r,Se(t,r,o.pass)])):{},markers:s,order:e.order()}},Ce=(t,e)=>{for(const n of e)u(t,`UPDATE ${a(T)} SET after = 0, done = 0, pass = pass + 1 WHERE tbl = ?`,n);return{}},je=[/(?:UNIQUE|NOT NULL|CHECK|FOREIGN KEY|PRIMARY KEY) constraint failed/u,/no such (?:table|column)/u,/datatype mismatch/u,/SQLITE_[A-Z_]+/u],ve=t=>{const e=t instanceof Error?t.message:String(t);for(const n of je){const s=n.exec(e);if(s)return s[0]}return t instanceof Error?t.name:"unknown"},Fe=async(t,e,n)=>{switch(Ue.has(String(e.op))&&Me(t),e.op){case"begin":return n.prepare(),Oe(t,e.tables,{force:e.force===!0,userTable:n.userTable()});case"fingerprints":return{fingerprints:Object.fromEntries(_(t).map(s=>[s,X(t,s)]))};case"manifest":return{tables:Ee(t)};case"page":{const s=he(t,C(t,e.table),Number(e.after??0));return{last:s.last,rows:j(s.rows)}}case"purge":{const s=await De(t,e.expected??{});return n.onPurge(),s}case"rescan":return Ce(t,e.tables??[]);case"status":return ke(t,n,e.fingerprints===!0);case"write":return Ie(t,C(t,e.table),{final:e.final===!0,force:e.force===!0,last:Number(e.last),rows:I(e.rows)});default:throw new TypeError(`unknown move op ${JSON.stringify(e.op)}`)}},xe=async(t,e,n)=>{try{return await Fe(t,e,n)}catch(s){if(s instanceof w)throw s;console.error("@lunora/auth: auth move step failed",s);const r=String(e.op),o=typeof e.table=="string"?e.table:void 0,i=ve(s);throw new w("AUTH_MOVE_FAILED",`auth move ${r}${o===void 0?"":` on ${o}`} failed: ${i}`,{data:{cause:i,op:r,...o===void 0?{}:{table:o}}})}},He=(t,e)=>{const n=s=>{const r=e.first.indexOf(s);if(r!==-1)return r;const o=e.last.indexOf(s);return o===-1?e.first.length:e.first.length+1+o};return t.toSorted((s,r)=>n(s.name)-n(r.name)||s.name.localeCompare(r.name))},Pe=(t,e)=>({conflicts:0,copied:0,deleted:0,sourceRows:t.rows,table:t.name,targetRows:e,unchanged:0,updated:0}),st=t=>{const e=async(n,s)=>{const r=await t(n,s);if(!r.ok){let o={};try{const i=await r.json();typeof i.error=="object"&&i.error!==null&&(o=i.error)}catch{}throw new w(o.code??"AUTH_MOVE_FAILED",o.message??`auth move ${String(s.op)} on the ${n} object failed (${String(r.status)})`,{data:o.data,status:r.status})}return r.json()};return{copy:async(n={})=>{const s=n.force===!0,r=await e("target",{op:"status"}),{tables:o}=await e("source",{op:"manifest"}),i=await e("target",{force:s,op:"begin",tables:o}),c=[];let f=0;for(const l of He(o,r.order)){const h=Pe(l,i.targetRows[l.name]??0);let A=i.cursors[l.name]??0;for(c.push(h);;){if(f>=me)return{done:!1,tables:c};f+=1;const S=await e("source",{after:A,op:"page",table:l.name}),L=I(S.rows),D=L.length<x;if(L.length===0&&i.done[l.name]===!0)break;const N=await e("target",{final:D,force:s,last:S.last??A,op:"write",rows:S.rows,table:l.name});if(h.conflicts+=N.conflicts,h.copied+=N.copied,h.deleted+=N.deleted,h.unchanged+=N.unchanged,h.updated+=N.updated,h.targetRows+=N.copied-N.deleted,A=S.last??A,D)break}}const{fingerprints:p}=await e("source",{op:"fingerprints"}),d=await e("target",{fingerprints:!0,op:"status"}),E=Object.keys(p).filter(l=>d.copied[l]!==p[l]);return E.length>0&&await e("target",{op:"rescan",tables:E}),{done:E.length===0,tables:c}},purge:async()=>{const{copied:n,markers:s}=await e("target",{fingerprints:!0,op:"status"}),r=Object.fromEntries(Object.entries(s).filter(([,o])=>o.done).map(([o])=>[o,n[o]]));return e("source",{expected:r,op:"purge"})}}},qe="/__lunora/auth/session",We="/__lunora/auth/audit",Be="x-lunora-auth-do-secret",Ve=t=>{if(t===null||typeof t!="object"||Array.isArray(t))return{error:"body must be a JSON object"};const e={};for(const[n,s]of Object.entries(t))if(n==="limit"||n==="sinceSeq"){if(typeof s!="number"||!Number.isFinite(s))return{error:`"${n}" must be a finite number`};e[n]=s}else if(n==="actorId"||n==="event"){if(typeof s!="string")return{error:`"${n}" must be a string`};e[n]=s}else return{error:`unknown audit read option "${n}"`};return{options:e}};class rt{#n;#a;#c;#e;#t;#s=!1;#r={first:["user"],last:[]};constructor(e,n,s={}){this.#e=e.storage,this.#n=U(e.storage),this.#c=n,this.#a=s}#o(){if(this.#t!==void 0)return this.#t;const e=this.#c(),n=ee(e),{tables:s}=M(n);if(this.#r={first:[s.user?.modelName??"user",s.account?.modelName??"account",s.session?.modelName??"session"],last:[Q,s.rateLimit?.modelName??"rateLimit"]},!this.#s){for(const r of se(n))[...this.#e.sql.exec(r)];for(const r of re(n,o=>this.#u(o)))[...this.#e.sql.exec(r)];this.#l(n),this.#s=!0}return this.#t=te({...e,database:K(this.#e)}),this.#t}#u(e){return[...this.#e.sql.exec("SELECT name FROM pragma_table_info(?)",e)].map(s=>String(s.name))}#l(e){const{tables:n}=M(e),{account:s}=n;if(s===void 0)return;const r=Object.entries(s.fields).map(([o,i])=>i.fieldName??o);if(!(ie(r)||!this.#u(s.modelName).includes("issuer")))try{const o=[...this.#e.sql.exec("SELECT name, sql FROM sqlite_master WHERE type = 'index' AND tbl_name = ?",s.modelName)].map(i=>({name:String(i.name),sql:typeof i.sql=="string"?i.sql:void 0}));for(const i of ae(s.modelName,ce(o)))[...this.#e.sql.exec(i)]}catch(o){console.error("@lunora/auth: could not drop the reverted `account.issuer` column; if it is still present, sign-ups will fail until it is removed.",o)}}async#f(e){if(!this.#i(e))return Response.json({error:"unauthorized"},{status:401});let n;try{n=await e.json()}catch{return Response.json({error:"invalid body"},{status:400})}const s=Ve(n??{});if("error"in s)return Response.json({error:s.error},{status:400});await z(this.#n);const r=await Z(this.#n).read(s.options);return Response.json({entries:r})}async#m(e){if(e.method!=="POST"||!this.#i(e))return Response.json({error:"unauthorized"},{status:401});try{const n=await e.json(),s=await xe(this.#e,n,{onPurge:()=>{this.#s=!1,this.#t=void 0,this.#n=U(this.#e)},order:()=>this.#r,prepare:()=>{this.#o()},userTable:()=>this.#r.first[0]??"user"});return Response.json(s)}catch(n){const{body:s,redacted:r,status:o}=Y(n,{encodeData:i=>i,fallbackCode:"AUTH_MOVE_FAILED",redactedMessage:"auth move failed"});return r&&console.error("@lunora/auth: auth move failed",n),Response.json({error:s},{status:o})}}#i(e){const{internalSecret:n}=this.#a;if(n===void 0||n==="")return!1;const s=e.headers.get(Be);return s!==null&&ue(s,n)}async#p(e){if(!this.#i(e))return Response.json({error:"unauthorized"},{status:401});const s=await this.#o().api.getSession({headers:e.headers}),r=s?.user.id;if(r===void 0)return Response.json({});const o=s?.session.expiresAt,i=s?.user,c=i?.role;return Response.json({...typeof i?.email=="string"&&i.email.length>0?{email:i.email}:{},...o instanceof Date?{expiresAtMs:o.getTime()}:{},...typeof i?.name=="string"&&i.name.length>0?{name:i.name}:{},...typeof c=="string"&&c.length>0?{role:c}:{},userId:r})}async fetch(e){const n=new URL(e.url);if(n.pathname===qe)return this.#p(e);if(n.pathname===We)return this.#f(e);if(n.pathname===fe)return this.#m(e);const s=this.#o();return await oe(s,e)??await ne(s,e)??Response.json({error:"not an auth route"},{status:404})}}export{Be as I,rt as L,fe as M,We as R,qe as a,st as c};
@@ -1 +1 @@
1
- import{LunoraError as v}from"@lunora/errors";import{I as d,a as w,c as A,R,M as E}from"./auth-do-Dr3ogic7.mjs";import{isDiscoveryRequest as g,unlessNotFound as j}from"./authDiscoveryPaths-B14lM14u.mjs";import{isAuthRoutePath as T,DEFAULT_AUTH_BASE_PATH as b}from"./DEFAULT_AUTH_BASE_PATH-DneiLGpv.mjs";const H=a=>{const{internalSecret:i,jurisdiction:c,objectName:l="auth"}=a,m=new Set(a.discoveryPaths),h=a.namespace;let{namespace:r}=a;if(r&&c!==void 0){if(typeof r.jurisdiction!="function")throw new TypeError(`@lunora/auth: Durable Object namespace does not support jurisdiction("${c}") — update @cloudflare/workers-types or remove the jurisdiction option`);r=r.jurisdiction(c)}const u=()=>{if(r)return r.get(r.idFromName(l))},y=async(t,n,o)=>{if(!i)return;const s=u();if(!s)return;const e=await s.fetch(new Request(new URL(t,n),{body:JSON.stringify(o),headers:{"content-type":"application/json",[d]:i},method:"POST"}));return e.ok?e:void 0},p=r,f=h&&p&&c!==void 0?A(async(t,n)=>{if(!i)throw new v("AUTH_MOVE_NOT_CONFIGURED","copying the auth object needs its internal secret; set the auth object's `internalSecret`");const o=t==="source"?h:p;return o.get(o.idFromName(l)).fetch(new Request(new URL(E,"https://auth-do.invalid"),{body:JSON.stringify(n),headers:{"content-type":"application/json",[d]:i},method:"POST"}))}):void 0;return{...f===void 0?{}:{jurisdictionMove:f},auditReader:{read:async t=>{const n=await y(R,"https://auth-do.invalid",t);return n?(await n.json())?.entries??[]:[]}},authHandler:async t=>{if(T(new URL(t.url).pathname,b))return u()?.fetch(t)},discoveryHandler:async t=>{if(g(t,m))return j(await u()?.fetch(t))},resolveIdentity:async t=>{if(!i)return null;const n=u();if(!n)return null;const o=new Headers(t.headers);o.set(d,i);const s=await n.fetch(new Request(new URL(w,t.url),{headers:o}));if(!s.ok)return null;const e=await s.json();return e?.userId?{...typeof e.email=="string"&&e.email.length>0?{email:e.email}:{},...typeof e.expiresAtMs=="number"&&Number.isFinite(e.expiresAtMs)?{expiresAtMs:e.expiresAtMs}:{},...typeof e.name=="string"&&e.name.length>0?{name:e.name}:{},...typeof e.role=="string"&&e.role.length>0?{role:e.role}:{},userId:e.userId}:null}}};export{H as createDoAuthWiring};
1
+ import{LunoraError as v}from"@lunora/errors";import{I as d,a as w,c as A,R,M as E}from"./auth-do-nKx0bUTe.mjs";import{isDiscoveryRequest as g,unlessNotFound as j}from"./authDiscoveryPaths-B14lM14u.mjs";import{isAuthRoutePath as T,DEFAULT_AUTH_BASE_PATH as b}from"./DEFAULT_AUTH_BASE_PATH-DneiLGpv.mjs";const H=a=>{const{internalSecret:i,jurisdiction:c,objectName:l="auth"}=a,m=new Set(a.discoveryPaths),h=a.namespace;let{namespace:r}=a;if(r&&c!==void 0){if(typeof r.jurisdiction!="function")throw new TypeError(`@lunora/auth: Durable Object namespace does not support jurisdiction("${c}") — update @cloudflare/workers-types or remove the jurisdiction option`);r=r.jurisdiction(c)}const u=()=>{if(r)return r.get(r.idFromName(l))},y=async(t,n,o)=>{if(!i)return;const s=u();if(!s)return;const e=await s.fetch(new Request(new URL(t,n),{body:JSON.stringify(o),headers:{"content-type":"application/json",[d]:i},method:"POST"}));return e.ok?e:void 0},p=r,f=h&&p&&c!==void 0?A(async(t,n)=>{if(!i)throw new v("AUTH_MOVE_NOT_CONFIGURED","copying the auth object needs its internal secret; set the auth object's `internalSecret`");const o=t==="source"?h:p;return o.get(o.idFromName(l)).fetch(new Request(new URL(E,"https://auth-do.invalid"),{body:JSON.stringify(n),headers:{"content-type":"application/json",[d]:i},method:"POST"}))}):void 0;return{...f===void 0?{}:{jurisdictionMove:f},auditReader:{read:async t=>{const n=await y(R,"https://auth-do.invalid",t);return n?(await n.json())?.entries??[]:[]}},authHandler:async t=>{if(T(new URL(t.url).pathname,b))return u()?.fetch(t)},discoveryHandler:async t=>{if(g(t,m))return j(await u()?.fetch(t))},resolveIdentity:async t=>{if(!i)return null;const n=u();if(!n)return null;const o=new Headers(t.headers);o.set(d,i);const s=await n.fetch(new Request(new URL(w,t.url),{headers:o}));if(!s.ok)return null;const e=await s.json();return e?.userId?{...typeof e.email=="string"&&e.email.length>0?{email:e.email}:{},...typeof e.expiresAtMs=="number"&&Number.isFinite(e.expiresAtMs)?{expiresAtMs:e.expiresAtMs}:{},...typeof e.name=="string"&&e.name.length>0?{name:e.name}:{},...typeof e.role=="string"&&e.role.length>0?{role:e.role}:{},userId:e.userId}:null}}};export{H as createDoAuthWiring};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lunora/auth",
3
- "version": "1.0.0-alpha.213",
3
+ "version": "1.0.0-alpha.215",
4
4
  "description": "Auth for Lunora — a thin better-auth wrapper: email/password, OAuth, plugins, D1-backed",
5
5
  "keywords": [
6
6
  "auth",
@@ -117,7 +117,8 @@
117
117
  "@better-auth/passkey": "1.7.7",
118
118
  "@better-auth/scim": "1.7.7",
119
119
  "@lunora/errors": ">=1.0.0-alpha.51 <2.0.0-0",
120
- "@lunora/values": "1.0.0-alpha.65",
120
+ "@lunora/values": "1.0.0-alpha.72",
121
+ "@lunora/wire": "1.0.0-alpha.1",
121
122
  "@visulima/disposable-email-domains": "1.1.25",
122
123
  "@visulima/email-verifier": "1.0.42",
123
124
  "@visulima/free-email-domains": "1.0.2",
@@ -1 +0,0 @@
1
- import{getAuthTablesWithResolvedIndexes as F}from"@better-auth/core/db/internal";import{LunoraError as b,toErrorBody as re}from"@lunora/errors";import{d as P,b as ne}from"./adapter-CBZ17jKi.mjs";import{AUTH_AUDIT_TABLE as oe,ensureAuthAuditTable as se,createAuthAuditReader as ie}from"../audit.mjs";import{resolveAuthOptions as ae,createAuth as ce}from"./createAuth-B-Pq7nmN.mjs";import{handleAuthDiscoveryRequest as ue}from"./authDiscoveryPaths-B14lM14u.mjs";import{authDoSchemaStatements as fe,authDoColumnAdditions as le}from"./authDoColumnAdditions-UwF3Rl41.mjs";import{handleAuthRequest as me}from"./DEFAULT_AUTH_BASE_PATH-DneiLGpv.mjs";import{q as c}from"./quote-identifier-CGiYFBvY.mjs";import{schemaDeclaresIssuer as de,legacyIssuerCleanupStatements as pe,indexesReferencingIssuer as Ee}from"./legacyIssuerCleanupStatements-D9Kf8OD1.mjs";const he=(t,e)=>{const r=Math.max(t.length,e.length);let n=t.length^e.length;for(let s=0;s<r;s+=1){const o=s<t.length?t.charCodeAt(s):0,i=s<e.length?e.charCodeAt(s):0;n|=o^i}return n===0},W=2166136261,V=16777619,H=(t,e=W)=>{let r=e;for(let n=0;n<t.length;n+=1)r^=t.charCodeAt(n),r=Math.imul(r,V);return(r>>>0).toString(16).padStart(8,"0")},we=t=>`${H(t,W)}${H(t,V)}`,$=t=>{let e="";for(let n=0;n<t.length;n+=32768)e+=String.fromCharCode(...t.subarray(n,n+32768));return btoa(e)},ye=t=>{const e=atob(t),r=new Uint8Array(e.length);for(let n=0;n<e.length;n+=1)r[n]=e.codePointAt(n)??0;return r},d="$lunora.wire$",j=64,U=1024,M="__proto__",B={BigInt64Array,BigUint64Array,Float32Array,Float64Array,Int8Array,Int16Array,Int32Array,Uint8Array,Uint8ClampedArray,Uint16Array,Uint32Array},q={Error,EvalError,RangeError,ReferenceError,SyntaxError,TypeError,URIError},Te=t=>{if(t===null||typeof t!="object")return!1;const e=Object.getPrototypeOf(t);return e===null||e===Object.prototype},T=(t,e=0)=>{if(e>j)throw new RangeError(`wire-codec: value nesting exceeds the ${j}-level limit`);if(t===void 0)return[d,"undefined"];if(t===null)return null;const r=typeof t;if(r==="bigint"){const o=t.toString();if(o.length>U)throw new RangeError(`wire-codec: over-long bigint (max ${U} digits)`);return[d,"bigint",o]}if(r==="number"){const o=t;return Number.isNaN(o)?[d,"nan"]:o===1/0?[d,"inf"]:o===-1/0?[d,"-inf"]:o}if(r!=="object")return t;if(t instanceof Date)return[d,"date",T(t.getTime(),e+1)];if(t instanceof Error){const o=t,i=T(Object.fromEntries(Object.keys(o).map(u=>[u,o[u]])),e+1),a=[d,"error",String(o.name),String(o.message),i];return o.cause!==void 0&&a.push(T(o.cause,e+1)),a}if(t instanceof URL)return[d,"url",t.href];if(t instanceof Map)return[d,"map",[...t.entries()].map(([o,i])=>[T(o,e+1),T(i,e+1)])];if(t instanceof Set)return[d,"set",[...t].map(o=>T(o,e+1))];if(t instanceof ArrayBuffer)return[d,"bytes",$(new Uint8Array(t)),"ArrayBuffer"];if(ArrayBuffer.isView(t)){const o=t,i=o.constructor.name,a=new Uint8Array(o.buffer,o.byteOffset,o.byteLength);return i==="Uint8Array"?[d,"bytes",$(a)]:[d,"bytes",$(a),i]}if(Array.isArray(t)){const o=t.map(i=>T(i,e+1));return o.length>0&&o[0]===d?[d,"arr",o]:o}if(!Te(t)){const o=t.constructor?.name??"value";throw new TypeError(`wire-codec: cannot encode a ${o} 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 n=t,s={};for(const o of Object.keys(n)){const i=n[o];if(i===void 0)continue;const a=T(i,e+1);o===M?Object.defineProperty(s,o,{configurable:!0,enumerable:!0,value:a,writable:!0}):s[o]=a}return s},E=(t,e=0)=>{if(e>j)throw new RangeError(`wire-codec: value nesting exceeds the ${j}-level limit`);if(t===null||typeof t!="object")return t;if(Array.isArray(t)){if(t[0]===d)switch(t[1]){case"-inf":return-1/0;case"arr":return t[2].map(o=>E(o,e+1));case"bigint":{const o=t[2];if(typeof o!="string"||o.length>U||!/^-?\d+$/.test(o))throw new RangeError(`wire-codec: invalid or over-long bigint (max ${U} digits)`);return BigInt(o)}case"date":{const o=E(t[2],e+1);if(typeof o!="number")throw new TypeError("wire-codec: malformed date — epoch must be a number");return new Date(o)}case"map":{const o=t[2];return new Map(o.map(i=>{if(!Array.isArray(i)||i.length!==2)throw new TypeError("wire-codec: malformed map entry — expected a [key, value] pair");return[E(i[0],e+1),E(i[1],e+1)]}))}case"set":return new Set(t[2].map(o=>E(o,e+1)));case"url":{const o=t[2];if(typeof o!="string")throw new TypeError("wire-codec: malformed url — href must be a string");return new URL(o)}case"error":{const o=t[2],i=t[3];if(typeof o!="string"||typeof i!="string")throw new TypeError("wire-codec: malformed error — name and message must be strings");const a=(Object.hasOwn(q,o)?q[o]:void 0)??Error,u=new a(i);u.name!==o&&Object.defineProperty(u,"name",{configurable:!0,value:o,writable:!0});const f=E(t[4],e+1);if(f===null||typeof f!="object"||Array.isArray(f))throw new TypeError("wire-codec: malformed error — props must be an object");for(const m of Object.keys(f))m===M?Object.defineProperty(u,m,{configurable:!0,enumerable:!0,value:f[m],writable:!0}):u[m]=f[m];return t.length>5&&Object.defineProperty(u,"cause",{configurable:!0,value:E(t[5],e+1),writable:!0}),u}case"bytes":{const o=t[2];if(typeof o!="string")throw new TypeError("wire-codec: malformed bytes — payload must be a base64 string");const i=ye(o);if($(i)!==o)throw new TypeError("wire-codec: malformed bytes — payload must be canonical padded base64");const a=t[3]??"Uint8Array";if(a==="ArrayBuffer")return i.buffer.byteLength===i.byteLength?i.buffer:i.slice().buffer;const u=Object.hasOwn(B,a)?B[a]:void 0;return u?new u(i.slice().buffer):i}case"inf":return 1/0;case"nan":return Number.NaN;case"undefined":return;default:return t.map(o=>E(o,e+1))}return t.map(s=>E(s,e+1))}const r=t,n={};for(const s of Object.keys(r)){const o=E(r[s],e+1);s===M?Object.defineProperty(n,s,{configurable:!0,enumerable:!0,value:o,writable:!0}):n[s]=o}return n},ge="/__lunora/auth/move",g="__lunora_auth_move__",S="__lunora_auth_move_rows__",D="__lunora_auth_purged__",G=100,Ae=16,be=100,Se=2n**64n,X=t=>t.startsWith("sqlite_")||t.startsWith("_cf_")||t===g||t===S||t===D,Y=async(t,e)=>t.transaction(async()=>Promise.resolve().then(e)),h=(t,e,...r)=>[...t.sql.exec(e,...r)],l=(t,e,...r)=>{[...t.sql.exec(e,...r)]},N=t=>h(t,"SELECT name FROM sqlite_master WHERE type = 'table' ORDER BY name").map(e=>String(e.name)).filter(e=>!X(e)),J=(t,e)=>h(t,"SELECT name, pk FROM pragma_table_info(?)",e).map(r=>({name:String(r.name),pk:Number(r.pk)})),L=(t,e)=>J(t,e).map(({name:r})=>r),K=(t,e)=>{const r=J(t,e),n=r.filter(({pk:s})=>s>0).toSorted((s,o)=>s.pk-o.pk).map(({name:s})=>s);return n.length>0?n:r.map(({name:s})=>s)},Q=(t,e)=>Number(h(t,`SELECT count(*) AS n FROM ${c(e)}`)[0]?.n??0),z=t=>JSON.stringify(T(t)),C=(t,e)=>BigInt(`0x${we(z(e.map(r=>t[r]??null)))}`),Z=(t,e)=>{let r=0,n=0n;for(const s of t)r+=1,n=(n+e(s))%Se;return`${String(r)}:${n.toString(16)}`},ee=(t,e)=>{const r=L(t,e).toSorted((n,s)=>n.localeCompare(s));return Z(t.sql.exec(`SELECT * FROM ${c(e)}`),n=>C(n,r))},Re=t=>N(t).map(e=>{const r=h(t,"SELECT sql FROM sqlite_master WHERE type = 'table' AND name = ?",e)[0]?.sql,n=h(t,"SELECT name, sql FROM sqlite_master WHERE type = 'index' AND tbl_name = ? AND sql IS NOT NULL",e).map(s=>({name:String(s.name),sql:String(s.sql)}));return{columns:L(t,e),indexes:n,name:e,rows:Q(t,e),sql:typeof r=="string"?r:""}}),v=(t,e)=>{if(typeof e!="string"||!N(t).includes(e))throw new TypeError(`unknown table ${JSON.stringify(e)}`);return e},Oe=(t,e,r)=>{const n=h(t,`SELECT rowid AS "__lunora_rowid__", * FROM ${c(e)} WHERE rowid > ? ORDER BY rowid LIMIT ?`,r,G),s=n.at(-1)?.__lunora_rowid__;return{last:typeof s=="number"?s:void 0,rows:n.map(({__lunora_rowid__:o,...i})=>i)}},Ne=t=>L(t,g).length>0,_=t=>Ne(t)?Object.fromEntries(h(t,`SELECT tbl, after, done, pass, cols, watermark FROM ${c(g)}`).map(e=>[String(e.tbl),{after:Number(e.after),columns:JSON.parse(String(e.cols)),done:e.done===1,pass:Number(e.pass),watermark:Number(e.watermark)}])):{},_e=(t,e,r)=>Z(t.sql.exec(`SELECT h FROM ${c(S)} WHERE tbl = ? AND pass = ?`,e,r),n=>BigInt(`0x${String(n.h)}`)),Le=t=>{l(t,`CREATE TABLE IF NOT EXISTS ${c(g)} (tbl TEXT NOT NULL PRIMARY KEY, after INTEGER NOT NULL, done INTEGER NOT NULL, pass INTEGER NOT NULL, cols TEXT NOT NULL, watermark INTEGER NOT NULL DEFAULT 0)`),l(t,`CREATE TABLE IF NOT EXISTS ${c(S)} (tbl TEXT NOT NULL, k TEXT NOT NULL, h TEXT NOT NULL, pass INTEGER NOT NULL, PRIMARY KEY (tbl, k))`)},Ie=(t,e,r)=>{if(!N(t).includes(e))return 0;const n=K(t,e).map(s=>`u.${c(s)}`).join(", ");return Number(h(t,`SELECT count(*) AS n FROM ${c(e)} u WHERE u.rowid > ? AND NOT EXISTS (SELECT 1 FROM ${c(S)} c WHERE c.tbl = ? AND c.k = json_array(${n}))`,r,e)[0]?.n??0)},$e=/^CREATE TABLE /iu,je=/^CREATE (?:UNIQUE )?INDEX /iu,Ue=(t,e,r)=>{if(X(e.name))throw new TypeError(`refusing reserved table ${JSON.stringify(e.name)}`);if(!$e.test(e.sql)||e.indexes.some(({sql:s})=>!je.test(s)))throw new TypeError(`refusing unexpected DDL for ${JSON.stringify(e.name)}`);if(r.has(e.name)){const s=new Set(L(t,e.name));for(const o of e.columns.filter(i=>!s.has(i)))l(t,`ALTER TABLE ${c(e.name)} ADD COLUMN ${c(o)}`)}else l(t,e.sql);const n=new Set(h(t,"SELECT name FROM sqlite_master WHERE type = 'index'").map(s=>String(s.name)));for(const s of e.indexes.filter(({name:o})=>!n.has(o)))l(t,s.sql)},De=(t,e,r)=>{Le(t);const n=Ie(t,r.userTable,_(t)[r.userTable]?.watermark??0);if(n>0&&!r.force)throw new b("AUTH_MOVE_TARGET_NOT_EMPTY",`the pinned auth object has ${String(n)} user(s) the copy did not write; copying into it would merge two user bases — pass force to copy anyway`,{data:{users:n}});const s=new Set(N(t)),o=_(t);for(const a of e){Ue(t,a,s);const u=o[a.name],f=JSON.stringify(a.columns.toSorted((m,w)=>m.localeCompare(w)));u===void 0?l(t,`INSERT INTO ${c(g)} (tbl, after, done, pass, cols) VALUES (?, 0, 0, 1, ?)`,a.name,f):l(t,`UPDATE ${c(g)} SET cols = ? WHERE tbl = ?`,f,a.name)}l(t,`UPDATE ${c(g)} SET watermark = (SELECT coalesce(max(rowid), 0) FROM ${c(r.userTable)}) WHERE tbl = ?`,r.userTable);const i=_(t);return{cursors:Object.fromEntries(e.map(({name:a})=>[a,i[a]?.after??0])),done:Object.fromEntries(e.map(({name:a})=>[a,i[a]?.done??!1])),targetRows:Object.fromEntries(e.map(({name:a})=>[a,Q(t,a)]))}},te=(t,e,r,n,s)=>h(t,`SELECT ${s.map(o=>c(o)).join(", ")} FROM ${c(e)} WHERE ${r.map(o=>`${c(o)} IS ?`).join(" AND ")} LIMIT 1`,...n)[0],k=(t,e)=>{if(!e)throw new b("AUTH_MOVE_CONFLICT",`a row copied into ${t} collides with a row the pinned auth object holds on its own — nothing from this page was written; pass force to keep the pinned object's rows`,{data:{table:t}});return"conflicts"},ke=t=>t instanceof Error&&t.message.includes("UNIQUE constraint failed"),Ce=(t,e)=>{if(e.prior!==void 0)return k(e.table,e.force);try{l(t,`INSERT INTO ${c(e.table)} (${e.columns.map(r=>c(r)).join(", ")}) VALUES (${e.columns.map(()=>"?").join(", ")})`,...e.columns.map(r=>e.row[r]))}catch(r){if(!ke(r))throw r;return k(e.table,e.force)}return"copied"},Me=(t,e,r)=>{const n=C(r,e.columns).toString(16);return n===e.h?"unchanged":e.prior===void 0||n!==e.prior?k(e.table,e.force):(l(t,`UPDATE ${c(e.table)} SET ${e.columns.map(s=>`${c(s)} = ?`).join(", ")} WHERE ${e.keys.map(s=>`${c(s)} IS ?`).join(" AND ")}`,...e.columns.map(s=>e.row[s]),...e.key),"updated")},xe=(t,e,r,n)=>{const{force:s,keys:o,pass:i}=n,a=Object.keys(r).toSorted((A,I)=>A.localeCompare(I));if(a.length+o.length>be)throw new TypeError(`${e} has too many columns to copy`);const u=o.map(A=>r[A]??null),f=z(u),m=C(r,a).toString(16),w=h(t,`SELECT h FROM ${c(S)} WHERE tbl = ? AND k = ?`,e,f)[0]?.h,p={columns:a,force:s,h:m,key:u,keys:o,prior:typeof w=="string"?w:void 0,row:r,table:e},y=p.prior===m?void 0:te(t,e,o,u,a);let R="unchanged";return p.prior!==m&&(R=y===void 0?Ce(t,p):Me(t,p,y)),l(t,`INSERT INTO ${c(S)} (tbl, k, h, pass) VALUES (?, ?, ?, ?) ON CONFLICT (tbl, k) DO UPDATE SET h = excluded.h, pass = excluded.pass`,e,f,m,i),R},Fe=(t,e,r)=>{const{counts:n,force:s,keys:o,marker:i}=r,a=h(t,`SELECT k, h FROM ${c(S)} WHERE tbl = ? AND pass < ?`,e,i.pass);for(const u of a){const f=E(JSON.parse(String(u.k))),m=te(t,e,o,f,i.columns);m!==void 0&&(C(m,i.columns).toString(16)===String(u.h)?(l(t,`DELETE FROM ${c(e)} WHERE ${o.map(w=>`${c(w)} IS ?`).join(" AND ")}`,...f),n.deleted+=1):n[k(e,s)]+=1),l(t,`DELETE FROM ${c(S)} WHERE tbl = ? AND k = ?`,e,String(u.k))}},Pe=async(t,e,r)=>{const n=_(t)[e];if(n===void 0)throw new TypeError(`table ${JSON.stringify(e)} was not part of this move`);return Y(t,()=>{const s={conflicts:0,copied:0,deleted:0,unchanged:0,updated:0},o=K(t,e);for(const i of r.rows)s[xe(t,e,i,{force:r.force,keys:o,pass:n.pass})]+=1;return r.final&&Fe(t,e,{counts:s,force:r.force,keys:o,marker:n}),l(t,`UPDATE ${c(g)} SET after = ?, done = ? WHERE tbl = ?`,r.last,r.final?1:0,e),s})},He=async(t,e)=>{const r=N(t);return await Y(t,()=>{const n=r.filter(o=>e[o]===void 0);if(n.length>0)throw new b("AUTH_MOVE_INCOMPLETE",`refusing to purge the un-pinned auth object: ${n.join(", ")} not fully copied — run the copy to done: true first`,{data:{unfinished:n}});const s=r.filter(o=>ee(t,o)!==e[o]);if(s.length>0)throw new b("AUTH_MOVE_SOURCE_CHANGED",`refusing to purge the un-pinned auth object: ${s.join(", ")} changed since it was copied — run the copy again to carry the changes, then purge`,{data:{changed:s}});for(const o of r)l(t,`DROP TABLE ${c(o)}`);l(t,`CREATE TABLE IF NOT EXISTS ${c(D)} (at INTEGER NOT NULL)`),l(t,`INSERT INTO ${c(D)} (at) VALUES (?)`,Date.now())}),{dropped:r}},Be=t=>{if(L(t,D).length>0)throw new b("AUTH_MOVE_SOURCE_PURGED","the un-pinned auth object was purged after its tables were copied; anything in it now is new, and copying it would delete the pinned object's users")},qe=new Set(["fingerprints","manifest","page","purge"]),ve=(t,e,r)=>{e.prepare();const n=_(t);return{copied:r?Object.fromEntries(Object.entries(n).map(([s,o])=>[s,_e(t,s,o.pass)])):{},markers:n,order:e.order()}},We=(t,e)=>{for(const r of e)l(t,`UPDATE ${c(g)} SET after = 0, done = 0, pass = pass + 1 WHERE tbl = ?`,r);return{}},Ve=[/(?:UNIQUE|NOT NULL|CHECK|FOREIGN KEY|PRIMARY KEY) constraint failed/u,/no such (?:table|column)/u,/datatype mismatch/u,/SQLITE_[A-Z_]+/u],Ge=t=>{const e=t instanceof Error?t.message:String(t);for(const r of Ve){const n=r.exec(e);if(n)return n[0]}return t instanceof Error?t.name:"unknown"},Xe=async(t,e,r)=>{switch(qe.has(String(e.op))&&Be(t),e.op){case"begin":return r.prepare(),De(t,e.tables,{force:e.force===!0,userTable:r.userTable()});case"fingerprints":return{fingerprints:Object.fromEntries(N(t).map(n=>[n,ee(t,n)]))};case"manifest":return{tables:Re(t)};case"page":{const n=Oe(t,v(t,e.table),Number(e.after??0));return{last:n.last,rows:T(n.rows)}}case"purge":{const n=await He(t,e.expected??{});return r.onPurge(),n}case"rescan":return We(t,e.tables??[]);case"status":return ve(t,r,e.fingerprints===!0);case"write":return Pe(t,v(t,e.table),{final:e.final===!0,force:e.force===!0,last:Number(e.last),rows:E(e.rows)});default:throw new TypeError(`unknown move op ${JSON.stringify(e.op)}`)}},Ye=async(t,e,r)=>{try{return await Xe(t,e,r)}catch(n){if(n instanceof b)throw n;console.error("@lunora/auth: auth move step failed",n);const s=String(e.op),o=typeof e.table=="string"?e.table:void 0,i=Ge(n);throw new b("AUTH_MOVE_FAILED",`auth move ${s}${o===void 0?"":` on ${o}`} failed: ${i}`,{data:{cause:i,op:s,...o===void 0?{}:{table:o}}})}},Je=(t,e)=>{const r=n=>{const s=e.first.indexOf(n);if(s!==-1)return s;const o=e.last.indexOf(n);return o===-1?e.first.length:e.first.length+1+o};return t.toSorted((n,s)=>r(n.name)-r(s.name)||n.name.localeCompare(s.name))},Ke=(t,e)=>({conflicts:0,copied:0,deleted:0,sourceRows:t.rows,table:t.name,targetRows:e,unchanged:0,updated:0}),lt=t=>{const e=async(r,n)=>{const s=await t(r,n);if(!s.ok){let o={};try{const i=await s.json();typeof i.error=="object"&&i.error!==null&&(o=i.error)}catch{}throw new b(o.code??"AUTH_MOVE_FAILED",o.message??`auth move ${String(n.op)} on the ${r} object failed (${String(s.status)})`,{data:o.data,status:s.status})}return s.json()};return{copy:async(r={})=>{const n=r.force===!0,s=await e("target",{op:"status"}),{tables:o}=await e("source",{op:"manifest"}),i=await e("target",{force:n,op:"begin",tables:o}),a=[];let u=0;for(const p of Je(o,s.order)){const y=Ke(p,i.targetRows[p.name]??0);let R=i.cursors[p.name]??0;for(a.push(y);;){if(u>=Ae)return{done:!1,tables:a};u+=1;const A=await e("source",{after:R,op:"page",table:p.name}),I=E(A.rows),x=I.length<G;if(I.length===0&&i.done[p.name]===!0)break;const O=await e("target",{final:x,force:n,last:A.last??R,op:"write",rows:A.rows,table:p.name});if(y.conflicts+=O.conflicts,y.copied+=O.copied,y.deleted+=O.deleted,y.unchanged+=O.unchanged,y.updated+=O.updated,y.targetRows+=O.copied-O.deleted,R=A.last??R,x)break}}const{fingerprints:f}=await e("source",{op:"fingerprints"}),m=await e("target",{fingerprints:!0,op:"status"}),w=Object.keys(f).filter(p=>m.copied[p]!==f[p]);return w.length>0&&await e("target",{op:"rescan",tables:w}),{done:w.length===0,tables:a}},purge:async()=>{const{copied:r,markers:n}=await e("target",{fingerprints:!0,op:"status"}),s=Object.fromEntries(Object.entries(n).filter(([,o])=>o.done).map(([o])=>[o,r[o]]));return e("source",{expected:s,op:"purge"})}}},Qe="/__lunora/auth/session",ze="/__lunora/auth/audit",Ze="x-lunora-auth-do-secret",et=t=>{if(t===null||typeof t!="object"||Array.isArray(t))return{error:"body must be a JSON object"};const e={};for(const[r,n]of Object.entries(t))if(r==="limit"||r==="sinceSeq"){if(typeof n!="number"||!Number.isFinite(n))return{error:`"${r}" must be a finite number`};e[r]=n}else if(r==="actorId"||r==="event"){if(typeof n!="string")return{error:`"${r}" must be a string`};e[r]=n}else return{error:`unknown audit read option "${r}"`};return{options:e}};class mt{#r;#a;#c;#e;#t;#n=!1;#o={first:["user"],last:[]};constructor(e,r,n={}){this.#e=e.storage,this.#r=P(e.storage),this.#c=r,this.#a=n}#s(){if(this.#t!==void 0)return this.#t;const e=this.#c(),r=ae(e),{tables:n}=F(r);if(this.#o={first:[n.user?.modelName??"user",n.account?.modelName??"account",n.session?.modelName??"session"],last:[oe,n.rateLimit?.modelName??"rateLimit"]},!this.#n){for(const s of fe(r))[...this.#e.sql.exec(s)];for(const s of le(r,o=>this.#u(o)))[...this.#e.sql.exec(s)];this.#f(r),this.#n=!0}return this.#t=ce({...e,database:ne(this.#e)}),this.#t}#u(e){return[...this.#e.sql.exec("SELECT name FROM pragma_table_info(?)",e)].map(n=>String(n.name))}#f(e){const{tables:r}=F(e),{account:n}=r;if(n===void 0)return;const s=Object.entries(n.fields).map(([o,i])=>i.fieldName??o);if(!(de(s)||!this.#u(n.modelName).includes("issuer")))try{const o=[...this.#e.sql.exec("SELECT name, sql FROM sqlite_master WHERE type = 'index' AND tbl_name = ?",n.modelName)].map(i=>({name:String(i.name),sql:typeof i.sql=="string"?i.sql:void 0}));for(const i of pe(n.modelName,Ee(o)))[...this.#e.sql.exec(i)]}catch(o){console.error("@lunora/auth: could not drop the reverted `account.issuer` column; if it is still present, sign-ups will fail until it is removed.",o)}}async#l(e){if(!this.#i(e))return Response.json({error:"unauthorized"},{status:401});let r;try{r=await e.json()}catch{return Response.json({error:"invalid body"},{status:400})}const n=et(r??{});if("error"in n)return Response.json({error:n.error},{status:400});await se(this.#r);const s=await ie(this.#r).read(n.options);return Response.json({entries:s})}async#m(e){if(e.method!=="POST"||!this.#i(e))return Response.json({error:"unauthorized"},{status:401});try{const r=await e.json(),n=await Ye(this.#e,r,{onPurge:()=>{this.#n=!1,this.#t=void 0,this.#r=P(this.#e)},order:()=>this.#o,prepare:()=>{this.#s()},userTable:()=>this.#o.first[0]??"user"});return Response.json(n)}catch(r){const{body:n,redacted:s,status:o}=re(r,{encodeData:i=>i,fallbackCode:"AUTH_MOVE_FAILED",redactedMessage:"auth move failed"});return s&&console.error("@lunora/auth: auth move failed",r),Response.json({error:n},{status:o})}}#i(e){const{internalSecret:r}=this.#a;if(r===void 0||r==="")return!1;const n=e.headers.get(Ze);return n!==null&&he(n,r)}async#d(e){if(!this.#i(e))return Response.json({error:"unauthorized"},{status:401});const n=await this.#s().api.getSession({headers:e.headers}),s=n?.user.id;if(s===void 0)return Response.json({});const o=n?.session.expiresAt,i=n?.user,a=i?.role;return Response.json({...typeof i?.email=="string"&&i.email.length>0?{email:i.email}:{},...o instanceof Date?{expiresAtMs:o.getTime()}:{},...typeof i?.name=="string"&&i.name.length>0?{name:i.name}:{},...typeof a=="string"&&a.length>0?{role:a}:{},userId:s})}async fetch(e){const r=new URL(e.url);if(r.pathname===Qe)return this.#d(e);if(r.pathname===ze)return this.#l(e);if(r.pathname===ge)return this.#m(e);const n=this.#s();return await me(n,e)??await ue(n,e)??Response.json({error:"not an auth route"},{status:404})}}export{Ze as I,mt as L,ge as M,ze as R,Qe as a,lt as c};