@lunora/auth 1.0.0-alpha.123 → 1.0.0-alpha.125

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 CHANGED
@@ -930,6 +930,21 @@ declare const DEFAULT_AUTH_BASE_PATH: string;
930
930
  * exact-path map `createWorker` consumes for top-level routes.
931
931
  */
932
932
  declare const handleAuthRequest: (auth: LunoraAuth, request: Request, basePath?: string) => Promise<Response | undefined>;
933
+ /**
934
+ * The cleanup statements, in execution order: every blocking index, then the column.
935
+ *
936
+ * Exported for the pre-applied-schema path (`compileMigrationsSql` + `wrangler d1 execute`),
937
+ * which compiles DDL without ever reading the database and so can neither tell whether the
938
+ * column is present nor discover the index names — SQLite has no `DROP COLUMN IF EXISTS` to
939
+ * make either unnecessary. Pass the names from
940
+ * `SELECT name, sql FROM sqlite_master WHERE type = 'index' AND tbl_name = 'account'`, and
941
+ * run this only against a database that still has the column.
942
+ * @param accountTable Physical name of the account table (`account` unless renamed via `account.modelName`).
943
+ * @param indexNames Indexes to drop first, from {@link indexesReferencingIssuer}.
944
+ * @returns The `DROP INDEX` statements followed by the `DROP COLUMN`.
945
+ * @experimental
946
+ */
947
+ declare const legacyIssuerCleanupStatements: (accountTable?: string, indexNames?: Iterable<string>) => string[];
933
948
  /**
934
949
  * Apply better-auth's required schema (`user`, `session`, `account`,
935
950
  * `verification`) to the configured database. Idempotent — better-auth
@@ -958,6 +973,13 @@ declare const ensureMigrated: (auth: LunoraAuth | {
958
973
  * `rateLimit` table the worker's default-on durable limiter writes to. Compiling
959
974
  * from the raw options would omit it, and the running worker would then write to
960
975
  * a table the migration never created.
976
+ *
977
+ * **Upgrading a database created by an older `@lunora/auth`.** This compiles DDL without
978
+ * reading the database, so it cannot know whether the `account.issuer` column better-auth
979
+ * 1.7.0 required and 1.7.3 reverted is present — and SQLite has no `DROP COLUMN IF EXISTS`
980
+ * to make that moot. `ensureMigrated` handles it automatically; on this path, run
981
+ * `legacyIssuerCleanupStatements()` once against a database that still has the column.
982
+ * Leaving it in place fails every sign-up with `NOT NULL constraint failed: account.issuer`.
961
983
  */
962
984
  declare const compileMigrationsSql: (options: LunoraAuthOptions) => Promise<string>;
963
985
  /**
@@ -1015,4 +1037,4 @@ declare const validateSessionPolicy: (policy: SessionPolicy) => SessionPolicy;
1015
1037
  * with the same 60s cookie cache as `rolling`.
1016
1038
  */
1017
1039
  declare const sessionPresets: Record<"longLived" | "rolling" | "strict", SessionPolicy>;
1018
- export { READ_AUDIT_PATH as AUTH_DO_AUDIT_PATH, INTERNAL_SECRET_HEADER as AUTH_DO_SECRET_HEADER, RESOLVE_SESSION_PATH as AUTH_DO_SESSION_PATH, type AppendAuthAuditEntry, type AppendAuthAuditOptions, type AuthAccount, type AuthAdmin, type AuthAdminSession, type AuthAdminUser, type AuthAuditEvent, type AuthAuditHookConfig, type AuthAuditReader, type AuthCapabilities, type AuthConfigInfo, type AuthDoOptions, type AuthDoState, type AuthInvitation, type AuthMember, type AuthNamespaceLike, type AuthOrgRole, type AuthOrganization, type AuthPage, type AuthPasskey, type AuthSignUpInvitation, type AuthTeam, type AuthTeamMember, type AuthTimestamp, type AuthUserFieldSpec, type CreateAuthAdminOptions, DEFAULT_AUTH_BASE_PATH, type DoAuthWiring, type DoAuthWiringOptions, type EmailClassification, type EmailGateConfig, type EmailGateHookConfig, type ImpersonationResult, type ListUsersOptions, type LunoraAuth, LunoraAuthAdminError, LunoraAuthDO, type LunoraAuthOptions, type SessionPolicy, type SqlExecutor, authAuditHook, authDoColumnAdditions, authDoSchemaStatements, buildAuditEntry, compileMigrationsSql, createAuthAdmin, createDoAuthWiring, emailGateDatabaseHooks, ensureMigrated, eventForPath, handleAuthRequest, sessionPresets, validateSessionPolicy, withAuthAudit, withEmailGate };
1040
+ export { READ_AUDIT_PATH as AUTH_DO_AUDIT_PATH, INTERNAL_SECRET_HEADER as AUTH_DO_SECRET_HEADER, RESOLVE_SESSION_PATH as AUTH_DO_SESSION_PATH, type AppendAuthAuditEntry, type AppendAuthAuditOptions, type AuthAccount, type AuthAdmin, type AuthAdminSession, type AuthAdminUser, type AuthAuditEvent, type AuthAuditHookConfig, type AuthAuditReader, type AuthCapabilities, type AuthConfigInfo, type AuthDoOptions, type AuthDoState, type AuthInvitation, type AuthMember, type AuthNamespaceLike, type AuthOrgRole, type AuthOrganization, type AuthPage, type AuthPasskey, type AuthSignUpInvitation, type AuthTeam, type AuthTeamMember, type AuthTimestamp, type AuthUserFieldSpec, type CreateAuthAdminOptions, DEFAULT_AUTH_BASE_PATH, type DoAuthWiring, type DoAuthWiringOptions, type EmailClassification, type EmailGateConfig, type EmailGateHookConfig, type ImpersonationResult, type ListUsersOptions, type LunoraAuth, LunoraAuthAdminError, LunoraAuthDO, type LunoraAuthOptions, type SessionPolicy, type SqlExecutor, authAuditHook, authDoColumnAdditions, authDoSchemaStatements, buildAuditEntry, compileMigrationsSql, createAuthAdmin, createDoAuthWiring, emailGateDatabaseHooks, ensureMigrated, eventForPath, handleAuthRequest, legacyIssuerCleanupStatements, sessionPresets, validateSessionPolicy, withAuthAudit, withEmailGate };
package/dist/index.d.ts CHANGED
@@ -930,6 +930,21 @@ declare const DEFAULT_AUTH_BASE_PATH: string;
930
930
  * exact-path map `createWorker` consumes for top-level routes.
931
931
  */
932
932
  declare const handleAuthRequest: (auth: LunoraAuth, request: Request, basePath?: string) => Promise<Response | undefined>;
933
+ /**
934
+ * The cleanup statements, in execution order: every blocking index, then the column.
935
+ *
936
+ * Exported for the pre-applied-schema path (`compileMigrationsSql` + `wrangler d1 execute`),
937
+ * which compiles DDL without ever reading the database and so can neither tell whether the
938
+ * column is present nor discover the index names — SQLite has no `DROP COLUMN IF EXISTS` to
939
+ * make either unnecessary. Pass the names from
940
+ * `SELECT name, sql FROM sqlite_master WHERE type = 'index' AND tbl_name = 'account'`, and
941
+ * run this only against a database that still has the column.
942
+ * @param accountTable Physical name of the account table (`account` unless renamed via `account.modelName`).
943
+ * @param indexNames Indexes to drop first, from {@link indexesReferencingIssuer}.
944
+ * @returns The `DROP INDEX` statements followed by the `DROP COLUMN`.
945
+ * @experimental
946
+ */
947
+ declare const legacyIssuerCleanupStatements: (accountTable?: string, indexNames?: Iterable<string>) => string[];
933
948
  /**
934
949
  * Apply better-auth's required schema (`user`, `session`, `account`,
935
950
  * `verification`) to the configured database. Idempotent — better-auth
@@ -958,6 +973,13 @@ declare const ensureMigrated: (auth: LunoraAuth | {
958
973
  * `rateLimit` table the worker's default-on durable limiter writes to. Compiling
959
974
  * from the raw options would omit it, and the running worker would then write to
960
975
  * a table the migration never created.
976
+ *
977
+ * **Upgrading a database created by an older `@lunora/auth`.** This compiles DDL without
978
+ * reading the database, so it cannot know whether the `account.issuer` column better-auth
979
+ * 1.7.0 required and 1.7.3 reverted is present — and SQLite has no `DROP COLUMN IF EXISTS`
980
+ * to make that moot. `ensureMigrated` handles it automatically; on this path, run
981
+ * `legacyIssuerCleanupStatements()` once against a database that still has the column.
982
+ * Leaving it in place fails every sign-up with `NOT NULL constraint failed: account.issuer`.
961
983
  */
962
984
  declare const compileMigrationsSql: (options: LunoraAuthOptions) => Promise<string>;
963
985
  /**
@@ -1015,4 +1037,4 @@ declare const validateSessionPolicy: (policy: SessionPolicy) => SessionPolicy;
1015
1037
  * with the same 60s cookie cache as `rolling`.
1016
1038
  */
1017
1039
  declare const sessionPresets: Record<"longLived" | "rolling" | "strict", SessionPolicy>;
1018
- export { READ_AUDIT_PATH as AUTH_DO_AUDIT_PATH, INTERNAL_SECRET_HEADER as AUTH_DO_SECRET_HEADER, RESOLVE_SESSION_PATH as AUTH_DO_SESSION_PATH, type AppendAuthAuditEntry, type AppendAuthAuditOptions, type AuthAccount, type AuthAdmin, type AuthAdminSession, type AuthAdminUser, type AuthAuditEvent, type AuthAuditHookConfig, type AuthAuditReader, type AuthCapabilities, type AuthConfigInfo, type AuthDoOptions, type AuthDoState, type AuthInvitation, type AuthMember, type AuthNamespaceLike, type AuthOrgRole, type AuthOrganization, type AuthPage, type AuthPasskey, type AuthSignUpInvitation, type AuthTeam, type AuthTeamMember, type AuthTimestamp, type AuthUserFieldSpec, type CreateAuthAdminOptions, DEFAULT_AUTH_BASE_PATH, type DoAuthWiring, type DoAuthWiringOptions, type EmailClassification, type EmailGateConfig, type EmailGateHookConfig, type ImpersonationResult, type ListUsersOptions, type LunoraAuth, LunoraAuthAdminError, LunoraAuthDO, type LunoraAuthOptions, type SessionPolicy, type SqlExecutor, authAuditHook, authDoColumnAdditions, authDoSchemaStatements, buildAuditEntry, compileMigrationsSql, createAuthAdmin, createDoAuthWiring, emailGateDatabaseHooks, ensureMigrated, eventForPath, handleAuthRequest, sessionPresets, validateSessionPolicy, withAuthAudit, withEmailGate };
1040
+ export { READ_AUDIT_PATH as AUTH_DO_AUDIT_PATH, INTERNAL_SECRET_HEADER as AUTH_DO_SECRET_HEADER, RESOLVE_SESSION_PATH as AUTH_DO_SESSION_PATH, type AppendAuthAuditEntry, type AppendAuthAuditOptions, type AuthAccount, type AuthAdmin, type AuthAdminSession, type AuthAdminUser, type AuthAuditEvent, type AuthAuditHookConfig, type AuthAuditReader, type AuthCapabilities, type AuthConfigInfo, type AuthDoOptions, type AuthDoState, type AuthInvitation, type AuthMember, type AuthNamespaceLike, type AuthOrgRole, type AuthOrganization, type AuthPage, type AuthPasskey, type AuthSignUpInvitation, type AuthTeam, type AuthTeamMember, type AuthTimestamp, type AuthUserFieldSpec, type CreateAuthAdminOptions, DEFAULT_AUTH_BASE_PATH, type DoAuthWiring, type DoAuthWiringOptions, type EmailClassification, type EmailGateConfig, type EmailGateHookConfig, type ImpersonationResult, type ListUsersOptions, type LunoraAuth, LunoraAuthAdminError, LunoraAuthDO, type LunoraAuthOptions, type SessionPolicy, type SqlExecutor, authAuditHook, authDoColumnAdditions, authDoSchemaStatements, buildAuditEntry, compileMigrationsSql, createAuthAdmin, createDoAuthWiring, emailGateDatabaseHooks, ensureMigrated, eventForPath, handleAuthRequest, legacyIssuerCleanupStatements, sessionPresets, validateSessionPolicy, withAuthAudit, withEmailGate };
package/dist/index.mjs CHANGED
@@ -1 +1 @@
1
- import{l as r,a as o,b as a}from"./packem_shared/adapter-DA8DdALX.mjs";import{LunoraAuthAdminError as A,createAuthAdmin as u}from"./packem_shared/LunoraAuthAdminError-BIpCQR2m.mjs";import{AUTH_AUDIT_TABLE as s,appendAuthAuditEntry as m,createAuthAuditReader as l,ensureAuthAuditTable as p,readAuthAuditLog as d}from"./audit.mjs";import{authAuditHook as E,buildAuditEntry as T,eventForPath as f,withAuthAudit as S}from"./packem_shared/authAuditHook-C9Gt2iYp.mjs";import{READ_AUDIT_PATH as x,INTERNAL_SECRET_HEADER as D,RESOLVE_SESSION_PATH as H,LunoraAuthDO as U}from"./packem_shared/AUTH_DO_AUDIT_PATH-BgmrlMWt.mjs";import{createAuth as I,resolveAuthOptions as R}from"./packem_shared/createAuth-8aUw8v8D.mjs";import{authDoColumnAdditions as L,authDoSchemaStatements as P}from"./packem_shared/authDoColumnAdditions-BCSs7qaN.mjs";import{createDoAuthWiring as O}from"./packem_shared/createDoAuthWiring-DlQ87uIT.mjs";import{emailGateDatabaseHooks as N,withEmailGate as w}from"./packem_shared/emailGateDatabaseHooks-CAygR3iq.mjs";import{assertEmailAllowed as M,classifyEmail as k,emailGateMiddleware as q,loadEmailDomainLists as C}from"./email-guard.mjs";import{DEFAULT_AUTH_BASE_PATH as G,handleAuthRequest as B}from"./packem_shared/DEFAULT_AUTH_BASE_PATH-DneiLGpv.mjs";import{createSignUpInvitation as W,listSignUpInvitations as Y,pruneSignUpInvitations as j,revokeSignUpInvitation as z}from"./packem_shared/createSignUpInvitation-CqqQc4S8.mjs";import{LunoraAuthHeadersError as K,withAuthPlugins as Q}from"./middleware.mjs";import{compileMigrationsSql as Z,ensureMigrated as $}from"./packem_shared/compileMigrationsSql-DWKoCboe.mjs";import{default as et}from"./schema.mjs";import{sessionPresets as ot,validateSessionPolicy as at}from"./packem_shared/sessionPresets-C867Mlo4.mjs";import{createSqlAuthStore as At,d1Executor as ut}from"./sql-store.mjs";import{createMemoryAuthStore as st,matchesWhere as mt}from"./store.mjs";import{TURNSTILE_VERIFY_ENDPOINT as pt,verifyTurnstile as dt}from"./turnstile.mjs";import{verifyTurnstileMiddleware as Et}from"./turnstile-middleware.mjs";export{s as AUTH_AUDIT_TABLE,x as AUTH_DO_AUDIT_PATH,D as AUTH_DO_SECRET_HEADER,H as AUTH_DO_SESSION_PATH,G as DEFAULT_AUTH_BASE_PATH,A as LunoraAuthAdminError,U as LunoraAuthDO,K as LunoraAuthHeadersError,pt as TURNSTILE_VERIFY_ENDPOINT,m as appendAuthAuditEntry,M as assertEmailAllowed,E as authAuditHook,L as authDoColumnAdditions,P as authDoSchemaStatements,et as authTables,T as buildAuditEntry,k as classifyEmail,Z as compileMigrationsSql,I as createAuth,u as createAuthAdmin,l as createAuthAuditReader,O as createDoAuthWiring,st as createMemoryAuthStore,W as createSignUpInvitation,At as createSqlAuthStore,ut as d1Executor,N as emailGateDatabaseHooks,q as emailGateMiddleware,p as ensureAuthAuditTable,$ as ensureMigrated,f as eventForPath,B as handleAuthRequest,Y as listSignUpInvitations,C as loadEmailDomainLists,r as lunoraAuthAdapter,o as lunoraD1Adapter,a as lunoraDoAdapter,mt as matchesWhere,j as pruneSignUpInvitations,d as readAuthAuditLog,R as resolveAuthOptions,z as revokeSignUpInvitation,ot as sessionPresets,at as validateSessionPolicy,dt as verifyTurnstile,Et as verifyTurnstileMiddleware,S as withAuthAudit,Q as withAuthPlugins,w as withEmailGate};
1
+ import{l as r,a as o,b as a}from"./packem_shared/adapter-DA8DdALX.mjs";import{LunoraAuthAdminError as A,createAuthAdmin as u}from"./packem_shared/LunoraAuthAdminError-DVW1DiAt.mjs";import{AUTH_AUDIT_TABLE as s,appendAuthAuditEntry as m,createAuthAuditReader as l,ensureAuthAuditTable as p,readAuthAuditLog as d}from"./audit.mjs";import{authAuditHook as E,buildAuditEntry as f,eventForPath as T,withAuthAudit as S}from"./packem_shared/authAuditHook-C9Gt2iYp.mjs";import{READ_AUDIT_PATH as _,INTERNAL_SECRET_HEADER as D,RESOLVE_SESSION_PATH as H,LunoraAuthDO as c}from"./packem_shared/AUTH_DO_AUDIT_PATH-ucS0M60j.mjs";import{createAuth as U,resolveAuthOptions as R}from"./packem_shared/createAuth-8aUw8v8D.mjs";import{authDoColumnAdditions as v,authDoSchemaStatements as L}from"./packem_shared/authDoColumnAdditions-UwF3Rl41.mjs";import{createDoAuthWiring as O}from"./packem_shared/createDoAuthWiring-68YJP-VM.mjs";import{emailGateDatabaseHooks as N,withEmailGate as w}from"./packem_shared/emailGateDatabaseHooks-CAygR3iq.mjs";import{assertEmailAllowed as M,classifyEmail as C,emailGateMiddleware as k,loadEmailDomainLists as q}from"./email-guard.mjs";import{DEFAULT_AUTH_BASE_PATH as G,handleAuthRequest as B}from"./packem_shared/DEFAULT_AUTH_BASE_PATH-DneiLGpv.mjs";import{createSignUpInvitation as W,listSignUpInvitations as Y,pruneSignUpInvitations as j,revokeSignUpInvitation as z}from"./packem_shared/createSignUpInvitation-CqqQc4S8.mjs";import{legacyIssuerCleanupStatements as K}from"./packem_shared/legacyIssuerCleanupStatements-D9Kf8OD1.mjs";import{LunoraAuthHeadersError as X,withAuthPlugins as Z}from"./middleware.mjs";import{compileMigrationsSql as tt,ensureMigrated as et}from"./packem_shared/compileMigrationsSql-ByVJhjR6.mjs";import{default as ot}from"./schema.mjs";import{sessionPresets as it,validateSessionPolicy as At}from"./packem_shared/sessionPresets-C867Mlo4.mjs";import{createSqlAuthStore as nt,d1Executor as st}from"./sql-store.mjs";import{createMemoryAuthStore as lt,matchesWhere as pt}from"./store.mjs";import{TURNSTILE_VERIFY_ENDPOINT as ht,verifyTurnstile as Et}from"./turnstile.mjs";import{verifyTurnstileMiddleware as Tt}from"./turnstile-middleware.mjs";export{s as AUTH_AUDIT_TABLE,_ as AUTH_DO_AUDIT_PATH,D as AUTH_DO_SECRET_HEADER,H as AUTH_DO_SESSION_PATH,G as DEFAULT_AUTH_BASE_PATH,A as LunoraAuthAdminError,c as LunoraAuthDO,X as LunoraAuthHeadersError,ht as TURNSTILE_VERIFY_ENDPOINT,m as appendAuthAuditEntry,M as assertEmailAllowed,E as authAuditHook,v as authDoColumnAdditions,L as authDoSchemaStatements,ot as authTables,f as buildAuditEntry,C as classifyEmail,tt as compileMigrationsSql,U as createAuth,u as createAuthAdmin,l as createAuthAuditReader,O as createDoAuthWiring,lt as createMemoryAuthStore,W as createSignUpInvitation,nt as createSqlAuthStore,st as d1Executor,N as emailGateDatabaseHooks,k as emailGateMiddleware,p as ensureAuthAuditTable,et as ensureMigrated,T as eventForPath,B as handleAuthRequest,K as legacyIssuerCleanupStatements,Y as listSignUpInvitations,q as loadEmailDomainLists,r as lunoraAuthAdapter,o as lunoraD1Adapter,a as lunoraDoAdapter,pt as matchesWhere,j as pruneSignUpInvitations,d as readAuthAuditLog,R as resolveAuthOptions,z as revokeSignUpInvitation,it as sessionPresets,At as validateSessionPolicy,Et as verifyTurnstile,Tt as verifyTurnstileMiddleware,S as withAuthAudit,Z as withAuthPlugins,w as withEmailGate};
@@ -0,0 +1 @@
1
+ import{getAuthTablesWithResolvedIndexes as u}from"@better-auth/core/db/internal";import{b as c,d as l}from"./adapter-DA8DdALX.mjs";import{ensureAuthAuditTable as h,createAuthAuditReader as m}from"../audit.mjs";import{resolveAuthOptions as d,createAuth as p}from"./createAuth-8aUw8v8D.mjs";import{authDoSchemaStatements as f,authDoColumnAdditions as A}from"./authDoColumnAdditions-UwF3Rl41.mjs";import{handleAuthRequest as g}from"./DEFAULT_AUTH_BASE_PATH-DneiLGpv.mjs";import{schemaDeclaresIssuer as y,legacyIssuerCleanupStatements as R,indexesReferencingIssuer as x}from"./legacyIssuerCleanupStatements-D9Kf8OD1.mjs";const b=(i,s)=>{const t=Math.max(i.length,s.length);let e=i.length^s.length;for(let r=0;r<t;r+=1){const o=r<i.length?i.charCodeAt(r):0,n=r<s.length?s.charCodeAt(r):0;e|=o^n}return e===0},E="/__lunora/auth/session",S="/__lunora/auth/audit",v="x-lunora-auth-do-secret",_=i=>{if(i===null||typeof i!="object"||Array.isArray(i))return{error:"body must be a JSON object"};const s={};for(const[t,e]of Object.entries(i))if(t==="limit"||t==="sinceSeq"){if(typeof e!="number"||!Number.isFinite(e))return{error:`"${t}" must be a finite number`};s[t]=e}else if(t==="actorId"||t==="event"){if(typeof e!="string")return{error:`"${t}" must be a string`};s[t]=e}else return{error:`unknown audit read option "${t}"`};return{options:s}};class q{#s;#r;#e;#t;#n=!1;constructor(s,t,e={}){this.#e=s.storage,this.#r=t,this.#s=e}#o(){if(this.#t!==void 0)return this.#t;const s=this.#r();if(!this.#n){const t=d(s);for(const e of f(t))[...this.#e.sql.exec(e)];for(const e of A(t,r=>this.#i(r)))[...this.#e.sql.exec(e)];this.#u(t),this.#n=!0}return this.#t=p({...s,database:c(this.#e)}),this.#t}#i(s){return[...this.#e.sql.exec("SELECT name FROM pragma_table_info(?)",s)].map(e=>String(e.name))}#u(s){const{tables:t}=u(s),{account:e}=t;if(e===void 0)return;const r=Object.entries(e.fields).map(([o,n])=>n.fieldName??o);if(!(y(r)||!this.#i(e.modelName).includes("issuer")))try{const o=[...this.#e.sql.exec("SELECT name, sql FROM sqlite_master WHERE type = 'index' AND tbl_name = ?",e.modelName)].map(n=>({name:String(n.name),sql:typeof n.sql=="string"?n.sql:void 0}));for(const n of R(e.modelName,x(o)))[...this.#e.sql.exec(n)]}catch(o){console.error("@lunora/auth: could not drop the reverted `account.issuer` column; sign-ups will fail until it is removed.",o)}}async#c(s){if(!this.#a(s))return Response.json({error:"unauthorized"},{status:401});let t;try{t=await s.json()}catch{return Response.json({error:"invalid body"},{status:400})}const e=_(t??{});if("error"in e)return Response.json({error:e.error},{status:400});const r=l(this.#e);await h(r);const o=await m(r).read(e.options);return Response.json({entries:o})}#a(s){const{internalSecret:t}=this.#s;if(t===void 0||t==="")return!1;const e=s.headers.get(v);return e!==null&&b(e,t)}async#l(s){if(!this.#a(s))return Response.json({error:"unauthorized"},{status:401});const e=await this.#o().api.getSession({headers:s.headers}),r=e?.user.id;if(r===void 0)return Response.json({});const o=e?.session.expiresAt,n=e?.user,a=n?.role;return Response.json({...typeof n?.email=="string"&&n.email.length>0?{email:n.email}:{},...o instanceof Date?{expiresAtMs:o.getTime()}:{},...typeof n?.name=="string"&&n.name.length>0?{name:n.name}:{},...typeof a=="string"&&a.length>0?{role:a}:{},userId:r})}async fetch(s){const t=new URL(s.url);if(t.pathname===E)return this.#l(s);if(t.pathname===S)return this.#c(s);const e=this.#o();return await g(e,s,this.#s.basePath)??Response.json({error:"not an auth route"},{status:404})}}export{v as INTERNAL_SECRET_HEADER,q as LunoraAuthDO,S as READ_AUDIT_PATH,E as RESOLVE_SESSION_PATH};
@@ -1 +1 @@
1
- import{createLocalAccountIssuer as I}from"@better-auth/core/db";import{LunoraError as U}from"@lunora/errors";import{getAuthTables as b}from"better-auth/db";import{revokeSignUpInvitation as R,createSignUpInvitation as N}from"./createSignUpInvitation-CqqQc4S8.mjs";class p extends U{constructor(m,f){super(f,m,{name:"LunoraAuthAdminError"})}}const E=50,D=500,M=3600,T=M*24,z=100*365*24*60*60,k=2880*60*1e3,L=[{field:"userId",model:"member"},{field:"userId",model:"teamMember"},{field:"userId",model:"passkey"},{field:"userId",model:"twoFactor"},{field:"userId",model:"oauthAccessToken"},{field:"userId",model:"oauthRefreshToken"},{field:"userId",model:"oauthConsent"},{field:"userId",model:"deviceCode"},{field:"userId",model:"walletAddress"},{field:"inviterId",model:"invitation"}],C=new Set(["accessToken","backupCodes","idToken","password","publicKey","refreshToken","secret","token","tokenHash"]),P=o=>Math.min(Math.max(Math.trunc(o??E),1),D),B=o=>Math.max(0,Math.trunc(o??0)),u=o=>{const m={};for(const[f,l]of Object.entries(o))C.has(f)||(m[f]=l instanceof Date?l.getTime():l);return m},g=o=>Array.isArray(o)?o.join(","):o,S=o=>o.toLowerCase().replaceAll(/[^\da-z]+/g,"-").replaceAll(/^-|-$/g,""),F=new Set(["banExpires","banned","banReason","createdAt","email","emailVerified","id","name","role","updatedAt"]),G={displayUsername:"username",phoneNumber:"phone-number",phoneNumberVerified:"phone-number",username:"username"},V=o=>o==="boolean"||o==="date"||o==="number"?o:"string",_=o=>{const m=[];for(const[f,l]of Object.entries(o))l.input===!1||l.references!==void 0||F.has(f)||m.push({name:f,plugin:G[f],required:l.required===!0,type:V(l.type),unique:l.unique===!0});return m},O=o=>typeof o=="string"&&o.includes("owner"),j=async(o,m)=>{const l=(await o.adapter.findMany({model:"member",where:[{field:"userId",value:m}]})).filter(w=>O(w.role)&&typeof w.organizationId=="string").map(w=>w.organizationId);if(l.length===0)return;const A=await Promise.all(l.map(async w=>o.adapter.findMany({model:"member",where:[{field:"organizationId",value:w}]}))),n=l.find((w,v)=>!A[v]?.some(e=>e.userId!==m&&O(e.role)));if(n!==void 0)throw new p(`user is the last owner of organization ${n} — transfer ownership or delete the organization first`,"LAST_ORGANIZATION_OWNER")},q=o=>{if(o instanceof p)return o;const m=o,f=m?.body?.code??m?.code??"AUTH_ADMIN_ERROR",l=m?.body?.message??m?.message??"auth admin operation failed";return new p(l,f)},H=(o,m={})=>{const f=o.$context,l=m.features??{},A=e=>{const a=new Set((e.plugins??[]).map(i=>i.id)),t=i=>a.has(i);return{accounts:l.accounts??!0,admin:l.admin??t("admin"),inviteOnly:l.inviteOnly??t("lunora-invite-only"),organization:l.organization??t("organization"),passkey:l.passkey??t("passkey"),twoFactor:l.twoFactor??t("two-factor")}},n=async e=>{try{return await e(await f)}catch(a){throw q(a)}},w=e=>u(e),v=async(e,a,t)=>{const i=t.where&&t.where.length>0?t.where:void 0,[r,s]=await Promise.all([e.adapter.findMany({limit:P(t.limit),model:a,offset:B(t.offset),sortBy:t.sortBy,where:i}),e.adapter.count({model:a,where:i})]);return{rows:r.map(d=>u(d)),total:s}};return{banUser:({expiresInSeconds:e,reason:a,userId:t})=>n(async i=>{let r=null;if(e!==void 0){if(!Number.isInteger(e)||e<=0)throw new p("expiresInSeconds must be a positive finite integer","INVALID_BAN_SECONDS");const d=Math.min(e,z);r=new Date(Date.now()+d*1e3)}const s=await i.internalAdapter.updateUser(t,{banExpires:r,banned:!0,banReason:a??"No reason"});return await i.internalAdapter.deleteUserSessions(t),w(s)}),cancelInvitation:({invitationId:e})=>n(async a=>{await a.adapter.delete({model:"invitation",where:[{field:"id",value:e}]})}),capabilities:()=>n(e=>Promise.resolve(A(e.options))),addMember:({organizationId:e,role:a,userId:t})=>n(async i=>{const r=await i.adapter.create({data:{createdAt:new Date,organizationId:e,role:a===void 0||a===""?"member":a,userId:t},model:"member"});return u(r)}),addTeamMember:({teamId:e,userId:a})=>n(async t=>{const i=await t.adapter.create({data:{createdAt:new Date,teamId:e,userId:a},model:"teamMember"});return u(i)}),config:()=>n(e=>{const a=e.options,t=A(a),i=new Set((a.plugins??[]).map(c=>c.id)),r=b(a),s=a.session??{},d=a.rateLimit??{};return Promise.resolve({capabilities:t,emailAndPassword:a.emailAndPassword?.enabled??!1,organization:{enabled:t.organization,roles:!!r.organizationRole,teams:!!r.team},plugins:[...i].toSorted((c,h)=>c.localeCompare(h)),rateLimit:{enabled:d.enabled??!1,max:d.max,window:d.window},session:{cookieCache:s.cookieCache?.enabled,expiresIn:s.expiresIn,freshAge:s.freshAge,updateAge:s.updateAge},socialProviders:Object.keys(a.socialProviders??{}).toSorted((c,h)=>c.localeCompare(h)),userFields:_(r.user?.fields??{})})}),createOrganization:({logo:e,metadata:a,name:t,ownerId:i,slug:r})=>n(async s=>{const d=S(r!==void 0&&r!==""?r:t);if(d==="")throw new p("could not derive a slug from the organization name","ORG_SLUG_INVALID");if(await s.adapter.findOne({model:"organization",where:[{field:"slug",value:d}]}))throw new p("an organization with this slug already exists","ORG_SLUG_TAKEN");const h=await s.adapter.create({data:{createdAt:new Date,logo:e===void 0||e===""?void 0:e,metadata:a===void 0?void 0:JSON.stringify(a),name:t,slug:d},model:"organization"});return i!==void 0&&i!==""&&await s.adapter.create({data:{createdAt:new Date,organizationId:h.id,role:"owner",userId:i},model:"member"}),u(h)}),createOrgRole:({organizationId:e,permission:a,role:t})=>n(async i=>{const r=await i.adapter.create({data:{createdAt:new Date,organizationId:e,permission:JSON.stringify(a),role:t},model:"organizationRole"});return u(r)}),createTeam:({name:e,organizationId:a})=>n(async t=>{const i=await t.adapter.create({data:{createdAt:new Date,name:e,organizationId:a},model:"team"});return u(i)}),deleteOrganization:({organizationId:e})=>n(async a=>{const t=b(a.options);if(await a.adapter.deleteMany({model:"member",where:[{field:"organizationId",value:e}]}),await a.adapter.deleteMany({model:"invitation",where:[{field:"organizationId",value:e}]}),t.team){const i=await a.adapter.findMany({model:"team",where:[{field:"organizationId",value:e}]});for(const r of i)await a.adapter.deleteMany({model:"teamMember",where:[{field:"teamId",value:r.id}]});await a.adapter.deleteMany({model:"team",where:[{field:"organizationId",value:e}]})}t.organizationRole&&await a.adapter.deleteMany({model:"organizationRole",where:[{field:"organizationId",value:e}]}),await a.adapter.delete({model:"organization",where:[{field:"id",value:e}]})}),deleteOrgRole:({roleId:e})=>n(async a=>{await a.adapter.delete({model:"organizationRole",where:[{field:"id",value:e}]})}),inviteMember:({email:e,inviterId:a,organizationId:t,role:i})=>n(async r=>{let s=a;if(s===void 0||s===""){const c=await r.adapter.findMany({model:"member",where:[{field:"organizationId",value:t}]});s=(c.find(y=>typeof y.role=="string"&&y.role.includes("owner"))??c[0])?.userId}if(s===void 0||s==="")throw new p("provide an inviter — the organization has no members to attribute the invitation to","INVITER_REQUIRED");const d=await r.adapter.create({data:{createdAt:new Date,email:e.toLowerCase(),expiresAt:new Date(Date.now()+k),inviterId:s,organizationId:t,role:i===void 0||i===""?"member":i,status:"pending"},model:"invitation"});return u(d)}),listOrgRoles:({limit:e,offset:a,organizationId:t})=>n(i=>v(i,"organizationRole",{limit:e,offset:a,sortBy:{direction:"desc",field:"createdAt"},where:[{field:"organizationId",value:t}]})),listTeamMembers:({limit:e,offset:a,teamId:t})=>n(i=>v(i,"teamMember",{limit:e,offset:a,where:[{field:"teamId",value:t}]})),listTeams:({limit:e,offset:a,organizationId:t})=>n(i=>v(i,"team",{limit:e,offset:a,sortBy:{direction:"desc",field:"createdAt"},where:[{field:"organizationId",value:t}]})),removeTeam:({teamId:e})=>n(async a=>{await a.adapter.deleteMany({model:"teamMember",where:[{field:"teamId",value:e}]}),await a.adapter.delete({model:"team",where:[{field:"id",value:e}]})}),removeTeamMember:({teamMemberId:e})=>n(async a=>{await a.adapter.delete({model:"teamMember",where:[{field:"id",value:e}]})}),updateMemberRole:({memberId:e,role:a})=>n(async t=>{const i=await t.adapter.update({model:"member",update:{role:g(a)},where:[{field:"id",value:e}]});return u(i??{id:e,role:g(a)})}),updateOrganization:({logo:e,metadata:a,name:t,organizationId:i,slug:r})=>n(async s=>{const d={};if(t!==void 0&&(d.name=t),r!==void 0&&r!==""&&(d.slug=S(r)),e!==void 0&&(d.logo=e===""?void 0:e),a!==void 0&&(d.metadata=JSON.stringify(a)),Object.keys(d).length===0)return u({id:i});const c=await s.adapter.update({model:"organization",update:d,where:[{field:"id",value:i}]});return u(c??{id:i})}),updateOrgRole:({permission:e,roleId:a})=>n(async t=>{const i=await t.adapter.update({model:"organizationRole",update:{permission:JSON.stringify(e),updatedAt:new Date},where:[{field:"id",value:a}]});return u(i??{id:a,permission:JSON.stringify(e)})}),updateTeam:({name:e,teamId:a})=>n(async t=>{const i=await t.adapter.update({model:"team",update:{name:e,updatedAt:new Date},where:[{field:"id",value:a}]});return u(i??{id:a,name:e})}),createUser:({data:e,email:a,name:t,password:i,role:r})=>n(async s=>{const d=a.toLowerCase();if(await s.internalAdapter.findUserByEmail(d))throw new p("a user with this email already exists","USER_ALREADY_EXISTS");const c=await s.internalAdapter.createUser({email:d,name:t,role:r===void 0?void 0:g(r),...e},{method:"admin"});if(i!==void 0&&i!==""){const h=await s.password.hash(i);await s.internalAdapter.linkAccount({accountId:c.id,issuer:I("credential"),password:h,providerId:"credential",userId:c.id})}return w(c)}),deletePasskey:({passkeyId:e})=>n(async a=>{await a.adapter.delete({model:"passkey",where:[{field:"id",value:e}]})}),disableTwoFactor:({userId:e})=>n(async a=>{await a.adapter.deleteMany({model:"twoFactor",where:[{field:"userId",value:e}]}),await a.internalAdapter.updateUser(e,{twoFactorEnabled:!1})}),impersonateUser:({userId:e})=>n(async a=>{const t=await a.internalAdapter.findUserById(e);if(!t)throw new p("user not found","USER_NOT_FOUND");const i=m.impersonationSeconds;let r=M;if(i!==void 0){if(!Number.isInteger(i)||!Number.isFinite(i)||i<=0)throw new p("impersonationSeconds must be a positive finite integer","INVALID_IMPERSONATION_SECONDS");r=Math.min(i,T)}const s=new Date(Date.now()+r*1e3),d=await a.internalAdapter.createSession(e,!0,{expiresAt:s,impersonatedBy:m.impersonatedBy??e},!0);return{expiresAt:d.expiresAt instanceof Date?d.expiresAt.getTime():s.getTime(),token:d.token,user:w(t)}}),listAccounts:({userId:e})=>n(async a=>(await a.adapter.findMany({model:"account",where:[{field:"userId",value:e}]})).map(i=>u(i))),listInvitations:({limit:e,offset:a,organizationId:t})=>n(i=>v(i,"invitation",{limit:e,offset:a,where:[{field:"organizationId",value:t}]})),createSignUpInvitation:({email:e,expiresInSeconds:a,invitedBy:t})=>n(async()=>{const i=await N(o,{email:e,expiresInSeconds:a,invitedBy:t});return{...u({...i}),token:i.token}}),listSignUpInvitations:({limit:e,offset:a})=>n(t=>v(t,"signUpInvitation",{limit:e,offset:a,sortBy:{direction:"desc",field:"createdAt"}})),revokeSignUpInvitation:({email:e})=>n(async()=>R(o,{email:e})),listMembers:({limit:e,offset:a,organizationId:t})=>n(i=>v(i,"member",{limit:e,offset:a,sortBy:{direction:"desc",field:"createdAt"},where:[{field:"organizationId",value:t}]})),listOrganizations:({limit:e,offset:a})=>n(t=>v(t,"organization",{limit:e,offset:a,sortBy:{direction:"desc",field:"createdAt"}})),listPasskeys:({userId:e})=>n(async a=>(await a.adapter.findMany({model:"passkey",where:[{field:"userId",value:e}]})).map(i=>u(i))),listSessions:({limit:e,offset:a,userId:t})=>n(i=>v(i,"session",{limit:e,offset:a,sortBy:{direction:"desc",field:"createdAt"},where:t===void 0||t===""?void 0:[{field:"userId",value:t}]})),listUsers:({filterField:e,filterValue:a,limit:t,offset:i,search:r,searchField:s,sortBy:d,sortDirection:c})=>n(h=>{const y=[];return r!==void 0&&r!==""&&y.push({field:s??"email",operator:"contains",value:r}),a!==void 0&&y.push({field:e??"email",operator:"eq",value:a}),v(h,"user",{limit:t,offset:i,sortBy:{direction:c??"desc",field:d??"createdAt"},where:y})}),removeMember:({memberId:e})=>n(async a=>{await a.adapter.delete({model:"member",where:[{field:"id",value:e}]})}),removeUser:({userId:e})=>n(async a=>{const t=b(a.options);t.member&&await j(a,e),await Promise.all(L.filter(({model:i})=>t[i]).map(({field:i,model:r})=>a.adapter.deleteMany({model:r,where:[{field:i,value:e}]}))),await a.internalAdapter.deleteUserSessions(e),await a.internalAdapter.deleteUser(e)}),revokeUserSession:({sessionId:e})=>n(async a=>{const t=await a.adapter.findOne({model:"session",where:[{field:"id",value:e}]});t?.token&&await a.internalAdapter.deleteSession(t.token)}),revokeUserSessions:({userId:e})=>n(async a=>{await a.internalAdapter.deleteUserSessions(e)}),setRole:({role:e,userId:a})=>n(async t=>{const i=await t.internalAdapter.updateUser(a,{role:g(e)});return w(i)}),setUserPassword:({newPassword:e,userId:a})=>n(async t=>{const i=t.password.config.minPasswordLength,r=t.password.config.maxPasswordLength;if(e.length<i)throw new p(`password must be at least ${i.toString()} characters`,"PASSWORD_TOO_SHORT");if(e.length>r)throw new p(`password must be at most ${r.toString()} characters`,"PASSWORD_TOO_LONG");if(!await t.internalAdapter.findUserById(a))throw new p("user not found","USER_NOT_FOUND");const d=(await t.internalAdapter.findAccounts(a)).some(h=>h.providerId==="credential");if(!d&&t.options.emailAndPassword?.enabled!==!0)throw new p("email/password sign-in is disabled for this deployment","EMAIL_PASSWORD_DISABLED");const c=await t.password.hash(e);d?await t.internalAdapter.updatePassword(a,c):await t.internalAdapter.linkAccount({accountId:a,issuer:I("credential"),password:c,providerId:"credential",userId:a})}),unbanUser:({userId:e})=>n(async a=>{const t=await a.internalAdapter.updateUser(e,{banExpires:null,banned:!1,banReason:null});return w(t)}),unlinkAccount:({accountId:e,userId:a})=>n(async t=>{await t.adapter.delete({model:"account",where:[{field:"id",value:e},{connector:"AND",field:"userId",value:a}]})}),updateUser:({data:e,userId:a})=>n(async t=>{const i=await t.internalAdapter.updateUser(a,e);return w(i)})}};export{p as LunoraAuthAdminError,H as createAuthAdmin};
1
+ import{LunoraError as M}from"@lunora/errors";import{getAuthTables as b}from"better-auth/db";import{revokeSignUpInvitation as U,createSignUpInvitation as R}from"./createSignUpInvitation-CqqQc4S8.mjs";class p extends M{constructor(m,f){super(f,m,{name:"LunoraAuthAdminError"})}}const N=50,E=500,O=3600,D=O*24,T=100*365*24*60*60,z=2880*60*1e3,k=[{field:"userId",model:"member"},{field:"userId",model:"teamMember"},{field:"userId",model:"passkey"},{field:"userId",model:"twoFactor"},{field:"userId",model:"oauthAccessToken"},{field:"userId",model:"oauthRefreshToken"},{field:"userId",model:"oauthConsent"},{field:"userId",model:"deviceCode"},{field:"userId",model:"walletAddress"},{field:"inviterId",model:"invitation"}],L=new Set(["accessToken","backupCodes","idToken","password","publicKey","refreshToken","secret","token","tokenHash"]),C=o=>Math.min(Math.max(Math.trunc(o??N),1),E),P=o=>Math.max(0,Math.trunc(o??0)),u=o=>{const m={};for(const[f,l]of Object.entries(o))L.has(f)||(m[f]=l instanceof Date?l.getTime():l);return m},g=o=>Array.isArray(o)?o.join(","):o,S=o=>o.toLowerCase().replaceAll(/[^\da-z]+/g,"-").replaceAll(/^-|-$/g,""),B=new Set(["banExpires","banned","banReason","createdAt","email","emailVerified","id","name","role","updatedAt"]),F={displayUsername:"username",phoneNumber:"phone-number",phoneNumberVerified:"phone-number",username:"username"},G=o=>o==="boolean"||o==="date"||o==="number"?o:"string",V=o=>{const m=[];for(const[f,l]of Object.entries(o))l.input===!1||l.references!==void 0||B.has(f)||m.push({name:f,plugin:F[f],required:l.required===!0,type:G(l.type),unique:l.unique===!0});return m},I=o=>typeof o=="string"&&o.includes("owner"),_=async(o,m)=>{const l=(await o.adapter.findMany({model:"member",where:[{field:"userId",value:m}]})).filter(w=>I(w.role)&&typeof w.organizationId=="string").map(w=>w.organizationId);if(l.length===0)return;const A=await Promise.all(l.map(async w=>o.adapter.findMany({model:"member",where:[{field:"organizationId",value:w}]}))),n=l.find((w,v)=>!A[v]?.some(e=>e.userId!==m&&I(e.role)));if(n!==void 0)throw new p(`user is the last owner of organization ${n} — transfer ownership or delete the organization first`,"LAST_ORGANIZATION_OWNER")},j=o=>{if(o instanceof p)return o;const m=o,f=m?.body?.code??m?.code??"AUTH_ADMIN_ERROR",l=m?.body?.message??m?.message??"auth admin operation failed";return new p(l,f)},W=(o,m={})=>{const f=o.$context,l=m.features??{},A=e=>{const a=new Set((e.plugins??[]).map(i=>i.id)),t=i=>a.has(i);return{accounts:l.accounts??!0,admin:l.admin??t("admin"),inviteOnly:l.inviteOnly??t("lunora-invite-only"),organization:l.organization??t("organization"),passkey:l.passkey??t("passkey"),twoFactor:l.twoFactor??t("two-factor")}},n=async e=>{try{return await e(await f)}catch(a){throw j(a)}},w=e=>u(e),v=async(e,a,t)=>{const i=t.where&&t.where.length>0?t.where:void 0,[r,s]=await Promise.all([e.adapter.findMany({limit:C(t.limit),model:a,offset:P(t.offset),sortBy:t.sortBy,where:i}),e.adapter.count({model:a,where:i})]);return{rows:r.map(d=>u(d)),total:s}};return{banUser:({expiresInSeconds:e,reason:a,userId:t})=>n(async i=>{let r=null;if(e!==void 0){if(!Number.isInteger(e)||e<=0)throw new p("expiresInSeconds must be a positive finite integer","INVALID_BAN_SECONDS");const d=Math.min(e,T);r=new Date(Date.now()+d*1e3)}const s=await i.internalAdapter.updateUser(t,{banExpires:r,banned:!0,banReason:a??"No reason"});return await i.internalAdapter.deleteUserSessions(t),w(s)}),cancelInvitation:({invitationId:e})=>n(async a=>{await a.adapter.delete({model:"invitation",where:[{field:"id",value:e}]})}),capabilities:()=>n(e=>Promise.resolve(A(e.options))),addMember:({organizationId:e,role:a,userId:t})=>n(async i=>{const r=await i.adapter.create({data:{createdAt:new Date,organizationId:e,role:a===void 0||a===""?"member":a,userId:t},model:"member"});return u(r)}),addTeamMember:({teamId:e,userId:a})=>n(async t=>{const i=await t.adapter.create({data:{createdAt:new Date,teamId:e,userId:a},model:"teamMember"});return u(i)}),config:()=>n(e=>{const a=e.options,t=A(a),i=new Set((a.plugins??[]).map(c=>c.id)),r=b(a),s=a.session??{},d=a.rateLimit??{};return Promise.resolve({capabilities:t,emailAndPassword:a.emailAndPassword?.enabled??!1,organization:{enabled:t.organization,roles:!!r.organizationRole,teams:!!r.team},plugins:[...i].toSorted((c,h)=>c.localeCompare(h)),rateLimit:{enabled:d.enabled??!1,max:d.max,window:d.window},session:{cookieCache:s.cookieCache?.enabled,expiresIn:s.expiresIn,freshAge:s.freshAge,updateAge:s.updateAge},socialProviders:Object.keys(a.socialProviders??{}).toSorted((c,h)=>c.localeCompare(h)),userFields:V(r.user?.fields??{})})}),createOrganization:({logo:e,metadata:a,name:t,ownerId:i,slug:r})=>n(async s=>{const d=S(r!==void 0&&r!==""?r:t);if(d==="")throw new p("could not derive a slug from the organization name","ORG_SLUG_INVALID");if(await s.adapter.findOne({model:"organization",where:[{field:"slug",value:d}]}))throw new p("an organization with this slug already exists","ORG_SLUG_TAKEN");const h=await s.adapter.create({data:{createdAt:new Date,logo:e===void 0||e===""?void 0:e,metadata:a===void 0?void 0:JSON.stringify(a),name:t,slug:d},model:"organization"});return i!==void 0&&i!==""&&await s.adapter.create({data:{createdAt:new Date,organizationId:h.id,role:"owner",userId:i},model:"member"}),u(h)}),createOrgRole:({organizationId:e,permission:a,role:t})=>n(async i=>{const r=await i.adapter.create({data:{createdAt:new Date,organizationId:e,permission:JSON.stringify(a),role:t},model:"organizationRole"});return u(r)}),createTeam:({name:e,organizationId:a})=>n(async t=>{const i=await t.adapter.create({data:{createdAt:new Date,name:e,organizationId:a},model:"team"});return u(i)}),deleteOrganization:({organizationId:e})=>n(async a=>{const t=b(a.options);if(await a.adapter.deleteMany({model:"member",where:[{field:"organizationId",value:e}]}),await a.adapter.deleteMany({model:"invitation",where:[{field:"organizationId",value:e}]}),t.team){const i=await a.adapter.findMany({model:"team",where:[{field:"organizationId",value:e}]});for(const r of i)await a.adapter.deleteMany({model:"teamMember",where:[{field:"teamId",value:r.id}]});await a.adapter.deleteMany({model:"team",where:[{field:"organizationId",value:e}]})}t.organizationRole&&await a.adapter.deleteMany({model:"organizationRole",where:[{field:"organizationId",value:e}]}),await a.adapter.delete({model:"organization",where:[{field:"id",value:e}]})}),deleteOrgRole:({roleId:e})=>n(async a=>{await a.adapter.delete({model:"organizationRole",where:[{field:"id",value:e}]})}),inviteMember:({email:e,inviterId:a,organizationId:t,role:i})=>n(async r=>{let s=a;if(s===void 0||s===""){const c=await r.adapter.findMany({model:"member",where:[{field:"organizationId",value:t}]});s=(c.find(y=>typeof y.role=="string"&&y.role.includes("owner"))??c[0])?.userId}if(s===void 0||s==="")throw new p("provide an inviter — the organization has no members to attribute the invitation to","INVITER_REQUIRED");const d=await r.adapter.create({data:{createdAt:new Date,email:e.toLowerCase(),expiresAt:new Date(Date.now()+z),inviterId:s,organizationId:t,role:i===void 0||i===""?"member":i,status:"pending"},model:"invitation"});return u(d)}),listOrgRoles:({limit:e,offset:a,organizationId:t})=>n(i=>v(i,"organizationRole",{limit:e,offset:a,sortBy:{direction:"desc",field:"createdAt"},where:[{field:"organizationId",value:t}]})),listTeamMembers:({limit:e,offset:a,teamId:t})=>n(i=>v(i,"teamMember",{limit:e,offset:a,where:[{field:"teamId",value:t}]})),listTeams:({limit:e,offset:a,organizationId:t})=>n(i=>v(i,"team",{limit:e,offset:a,sortBy:{direction:"desc",field:"createdAt"},where:[{field:"organizationId",value:t}]})),removeTeam:({teamId:e})=>n(async a=>{await a.adapter.deleteMany({model:"teamMember",where:[{field:"teamId",value:e}]}),await a.adapter.delete({model:"team",where:[{field:"id",value:e}]})}),removeTeamMember:({teamMemberId:e})=>n(async a=>{await a.adapter.delete({model:"teamMember",where:[{field:"id",value:e}]})}),updateMemberRole:({memberId:e,role:a})=>n(async t=>{const i=await t.adapter.update({model:"member",update:{role:g(a)},where:[{field:"id",value:e}]});return u(i??{id:e,role:g(a)})}),updateOrganization:({logo:e,metadata:a,name:t,organizationId:i,slug:r})=>n(async s=>{const d={};if(t!==void 0&&(d.name=t),r!==void 0&&r!==""&&(d.slug=S(r)),e!==void 0&&(d.logo=e===""?void 0:e),a!==void 0&&(d.metadata=JSON.stringify(a)),Object.keys(d).length===0)return u({id:i});const c=await s.adapter.update({model:"organization",update:d,where:[{field:"id",value:i}]});return u(c??{id:i})}),updateOrgRole:({permission:e,roleId:a})=>n(async t=>{const i=await t.adapter.update({model:"organizationRole",update:{permission:JSON.stringify(e),updatedAt:new Date},where:[{field:"id",value:a}]});return u(i??{id:a,permission:JSON.stringify(e)})}),updateTeam:({name:e,teamId:a})=>n(async t=>{const i=await t.adapter.update({model:"team",update:{name:e,updatedAt:new Date},where:[{field:"id",value:a}]});return u(i??{id:a,name:e})}),createUser:({data:e,email:a,name:t,password:i,role:r})=>n(async s=>{const d=a.toLowerCase();if(await s.internalAdapter.findUserByEmail(d))throw new p("a user with this email already exists","USER_ALREADY_EXISTS");const c=await s.internalAdapter.createUser({email:d,name:t,role:r===void 0?void 0:g(r),...e},{method:"admin"});if(i!==void 0&&i!==""){const h=await s.password.hash(i);await s.internalAdapter.linkAccount({accountId:c.id,password:h,providerId:"credential",userId:c.id})}return w(c)}),deletePasskey:({passkeyId:e})=>n(async a=>{await a.adapter.delete({model:"passkey",where:[{field:"id",value:e}]})}),disableTwoFactor:({userId:e})=>n(async a=>{await a.adapter.deleteMany({model:"twoFactor",where:[{field:"userId",value:e}]}),await a.internalAdapter.updateUser(e,{twoFactorEnabled:!1})}),impersonateUser:({userId:e})=>n(async a=>{const t=await a.internalAdapter.findUserById(e);if(!t)throw new p("user not found","USER_NOT_FOUND");const i=m.impersonationSeconds;let r=O;if(i!==void 0){if(!Number.isInteger(i)||!Number.isFinite(i)||i<=0)throw new p("impersonationSeconds must be a positive finite integer","INVALID_IMPERSONATION_SECONDS");r=Math.min(i,D)}const s=new Date(Date.now()+r*1e3),d=await a.internalAdapter.createSession(e,!0,{expiresAt:s,impersonatedBy:m.impersonatedBy??e},!0);return{expiresAt:d.expiresAt instanceof Date?d.expiresAt.getTime():s.getTime(),token:d.token,user:w(t)}}),listAccounts:({userId:e})=>n(async a=>(await a.adapter.findMany({model:"account",where:[{field:"userId",value:e}]})).map(i=>u(i))),listInvitations:({limit:e,offset:a,organizationId:t})=>n(i=>v(i,"invitation",{limit:e,offset:a,where:[{field:"organizationId",value:t}]})),createSignUpInvitation:({email:e,expiresInSeconds:a,invitedBy:t})=>n(async()=>{const i=await R(o,{email:e,expiresInSeconds:a,invitedBy:t});return{...u({...i}),token:i.token}}),listSignUpInvitations:({limit:e,offset:a})=>n(t=>v(t,"signUpInvitation",{limit:e,offset:a,sortBy:{direction:"desc",field:"createdAt"}})),revokeSignUpInvitation:({email:e})=>n(async()=>U(o,{email:e})),listMembers:({limit:e,offset:a,organizationId:t})=>n(i=>v(i,"member",{limit:e,offset:a,sortBy:{direction:"desc",field:"createdAt"},where:[{field:"organizationId",value:t}]})),listOrganizations:({limit:e,offset:a})=>n(t=>v(t,"organization",{limit:e,offset:a,sortBy:{direction:"desc",field:"createdAt"}})),listPasskeys:({userId:e})=>n(async a=>(await a.adapter.findMany({model:"passkey",where:[{field:"userId",value:e}]})).map(i=>u(i))),listSessions:({limit:e,offset:a,userId:t})=>n(i=>v(i,"session",{limit:e,offset:a,sortBy:{direction:"desc",field:"createdAt"},where:t===void 0||t===""?void 0:[{field:"userId",value:t}]})),listUsers:({filterField:e,filterValue:a,limit:t,offset:i,search:r,searchField:s,sortBy:d,sortDirection:c})=>n(h=>{const y=[];return r!==void 0&&r!==""&&y.push({field:s??"email",operator:"contains",value:r}),a!==void 0&&y.push({field:e??"email",operator:"eq",value:a}),v(h,"user",{limit:t,offset:i,sortBy:{direction:c??"desc",field:d??"createdAt"},where:y})}),removeMember:({memberId:e})=>n(async a=>{await a.adapter.delete({model:"member",where:[{field:"id",value:e}]})}),removeUser:({userId:e})=>n(async a=>{const t=b(a.options);t.member&&await _(a,e),await Promise.all(k.filter(({model:i})=>t[i]).map(({field:i,model:r})=>a.adapter.deleteMany({model:r,where:[{field:i,value:e}]}))),await a.internalAdapter.deleteUserSessions(e),await a.internalAdapter.deleteUser(e)}),revokeUserSession:({sessionId:e})=>n(async a=>{const t=await a.adapter.findOne({model:"session",where:[{field:"id",value:e}]});t?.token&&await a.internalAdapter.deleteSession(t.token)}),revokeUserSessions:({userId:e})=>n(async a=>{await a.internalAdapter.deleteUserSessions(e)}),setRole:({role:e,userId:a})=>n(async t=>{const i=await t.internalAdapter.updateUser(a,{role:g(e)});return w(i)}),setUserPassword:({newPassword:e,userId:a})=>n(async t=>{const i=t.password.config.minPasswordLength,r=t.password.config.maxPasswordLength;if(e.length<i)throw new p(`password must be at least ${i.toString()} characters`,"PASSWORD_TOO_SHORT");if(e.length>r)throw new p(`password must be at most ${r.toString()} characters`,"PASSWORD_TOO_LONG");if(!await t.internalAdapter.findUserById(a))throw new p("user not found","USER_NOT_FOUND");const d=(await t.internalAdapter.findAccounts(a)).some(h=>h.providerId==="credential");if(!d&&t.options.emailAndPassword?.enabled!==!0)throw new p("email/password sign-in is disabled for this deployment","EMAIL_PASSWORD_DISABLED");const c=await t.password.hash(e);d?await t.internalAdapter.updatePassword(a,c):await t.internalAdapter.linkAccount({accountId:a,password:c,providerId:"credential",userId:a})}),unbanUser:({userId:e})=>n(async a=>{const t=await a.internalAdapter.updateUser(e,{banExpires:null,banned:!1,banReason:null});return w(t)}),unlinkAccount:({accountId:e,userId:a})=>n(async t=>{await t.adapter.delete({model:"account",where:[{field:"id",value:e},{connector:"AND",field:"userId",value:a}]})}),updateUser:({data:e,userId:a})=>n(async t=>{const i=await t.internalAdapter.updateUser(a,e);return w(i)})}};export{p as LunoraAuthAdminError,W as createAuthAdmin};
@@ -0,0 +1 @@
1
+ import{getAuthTablesWithResolvedIndexes as l,getDatabaseFieldIndexName as N}from"@better-auth/core/db/internal";import{q as r}from"./quote-identifier-CGiYFBvY.mjs";const f=(n,e)=>{if(n==="id"||e.references?.field==="id")return"text";const{type:t}=e;if(Array.isArray(t))return"text";switch(t){case"boolean":return"integer";case"date":return"date";case"number":return"bigint"in e&&e.bigint===!0?"bigint":"integer";default:return"text"}},b=n=>{const{defaultValue:e,type:t,unique:o}=n;if(!(o===!0&&n.required===!1)&&!(e==null||typeof e=="function")){if(t==="boolean")return e===!0?"1":"0";if(t==="number"&&typeof e=="number"&&Number.isFinite(e))return String(e);if(t==="string"&&typeof e=="string")return`'${e.replaceAll("'","''")}'`}},p=(n,e)=>{const t=[];for(const[o,i]of Object.entries(e)){const s=i.unique===!0;if(!s&&i.index!==!0)continue;const c=i.fieldName??o,u=N(n,c,s);t.push(`CREATE ${s?"UNIQUE ":""}INDEX IF NOT EXISTS ${r(u)} ON ${r(n)} (${r(c)})`)}return t},T=(n,e)=>{const t=[r(n),f(n,e)],o=b(e);return e.required!==!1&&o!==void 0&&t.push("NOT NULL"),o!==void 0&&t.push(`DEFAULT ${o}`),t.join(" ")},E=(n,e)=>{const t=[r(n),f(n,e)];return e.required!==!1&&t.push("NOT NULL"),t.join(" ")},$=n=>{const{indexesByTable:e,tables:t}=l(n),o=[],i=[];for(const s of Object.values(t)){if(s.disableMigrations===!0)continue;const c=[`${r("id")} text NOT NULL PRIMARY KEY`,...Object.entries(s.fields).map(([u,a])=>E(a.fieldName??u,a))];o.push(`CREATE TABLE IF NOT EXISTS ${r(s.modelName)} (${c.join(", ")})`),i.push(...p(s.modelName,s.fields));for(const u of e.get(s.modelName)??[]){const a=u.unique===!0?"UNIQUE ":"",m=u.columns.map(d=>r(d)).join(", ");i.push(`CREATE ${a}INDEX IF NOT EXISTS ${r(u.name)} ON ${r(s.modelName)} (${m})`)}}return[...o,...i]},A=(n,e)=>{const{tables:t}=l(n),o=[];for(const i of Object.values(t)){if(i.disableMigrations===!0)continue;const s=new Set(e(i.modelName));if(s.size!==0)for(const[c,u]of Object.entries(i.fields)){const a=u.fieldName??c;s.has(a)||o.push(`ALTER TABLE ${r(i.modelName)} ADD COLUMN ${T(a,u)}`)}}return o};export{A as authDoColumnAdditions,$ as authDoSchemaStatements};
@@ -0,0 +1 @@
1
+ import{getAuthTablesWithResolvedIndexes as w}from"@better-auth/core/db/internal";import{LunoraError as y}from"@lunora/errors";import{getMigrations as l}from"better-auth/db/migration";import{q as u}from"./quote-identifier-CGiYFBvY.mjs";import{resolveAuthOptions as R}from"./createAuth-8aUw8v8D.mjs";import{schemaDeclaresIssuer as _,legacyIssuerCleanupStatements as x,indexesReferencingIssuer as M}from"./legacyIssuerCleanupStatements-D9Kf8OD1.mjs";const T=/pragma_index_list\s*\(/iu,N=/sqlite_master/iu,D=/^["`[]|["\]`]$/gu,A=/\s+/u,C=/create\s+unique\s+index/iu,O=/\bwhere\b/iu,P=t=>T.test(t)&&N.test(t),S=t=>(t.trim().split(A)[0]??"").replaceAll(D,"").trim(),L=t=>{const e=t.indexOf("(");if(e===-1)return{columns:[],tail:""};let a=0;for(let n=e;n<t.length;n+=1){const s=t[n];if(s==="(")a+=1;else if(s===")"&&(a-=1,a===0))return{columns:t.slice(e+1,n).split(",").map(r=>S(r)).filter(r=>r!==""),tail:t.slice(n+1)}}return{columns:[],tail:""}},U=async t=>{const e=t.prepare("SELECT name, tbl_name, sql FROM sqlite_master WHERE type = 'index'"),{results:a}=await e.all(),n=[];for(const s of a??[]){const r=s.name,o=s.tbl_name,i=s.sql;if(typeof r!="string"||typeof o!="string")continue;if(typeof i!="string"){n.push({columnPosition:0,indexName:r,isPartial:0,isUnique:1,tableName:o});continue}const f=C.test(i)?1:0,{columns:h,tail:b}=L(i),E=O.test(b)?1:0;for(const[I,g]of h.entries())n.push({columnName:g,columnPosition:I,indexName:r,isPartial:E,isUnique:f,tableName:o})}return n},q=t=>{const e=async()=>{const n=await U(t);return{meta:{},results:n,success:!0}},a={all:e,bind:()=>a,run:e};return a},W=t=>new Proxy(t,{get(e,a,n){if(a==="prepare")return r=>P(r)?q(e):e.prepare(r);const s=Reflect.get(e,a,n);return typeof s=="function"?s.bind(e):s}}),m=t=>typeof t=="object"&&t!==null&&typeof t.prepare=="function"&&typeof t.batch=="function",p=t=>{const{database:e}=t;if(!(e&&typeof e!="function"))throw new y("AUTH_MIGRATOR_UNSUPPORTED",e?"@lunora/auth: this auth instance's `database` is a custom adapter, which better-auth's migrator cannot drive.":"@lunora/auth: this auth instance has no `database`, so better-auth's migrator has nothing to introspect.")},d=t=>m(t.database)?{...t,database:W(t.database)}:t,v=async(t,e)=>{try{return await t.prepare(`SELECT ${u("issuer")} FROM ${u(e)} LIMIT 0`).run(),!0}catch{return!1}},F=async t=>{const{database:e}=t,{tables:a}=w(t),{account:n}=a;if(n!==void 0&&!_(Object.entries(n.fields).map(([s,r])=>r.fieldName??s))&&m(e)&&await v(e,n.modelName))try{const{results:s}=await e.prepare("SELECT name, sql FROM sqlite_master WHERE type = 'index' AND tbl_name = ?").bind(n.modelName).all();await e.batch(x(n.modelName,M(s)).map(r=>e.prepare(r)))}catch(s){console.error("@lunora/auth: could not drop the reverted `account.issuer` column; sign-ups will fail until it is removed.",s)}},c=new WeakMap,k=async t=>{const{options:e}=t;p(e);const a=c.get(e);if(a){await a;return}const n=(async()=>{const{runMigrations:s}=await l(d(e));await s(),await F(e)})();c.set(e,n);try{await n}catch(s){throw c.delete(e),s}},K=async t=>{const e=R(t);p(e);const{compileMigrations:a}=await l(d(e));return a()};export{K as compileMigrationsSql,k as ensureMigrated};
@@ -1 +1 @@
1
- import{INTERNAL_SECRET_HEADER as u,RESOLVE_SESSION_PATH as p,READ_AUDIT_PATH as f}from"./AUTH_DO_AUDIT_PATH-BgmrlMWt.mjs";import{DEFAULT_AUTH_BASE_PATH as h,isAuthRoutePath as A}from"./DEFAULT_AUTH_BASE_PATH-DneiLGpv.mjs";const g=l=>{const{basePath:c=h,internalSecret:a,namespace:o,objectName:d="auth"}=l,i=()=>{if(o)return o.get(o.idFromName(d))},m=async(t,n,r)=>{if(!a)return;const s=i();if(!s)return;const e=await s.fetch(new Request(new URL(t,n),{body:JSON.stringify(r),headers:{"content-type":"application/json",[u]:a},method:"POST"}));return e.ok?e:void 0};return{auditReader:{read:async t=>{const n=await m(f,"https://auth-do.invalid",t);return n?(await n.json())?.entries??[]:[]}},authHandler:async t=>{if(A(new URL(t.url).pathname,c))return i()?.fetch(t)},resolveIdentity:async t=>{if(!a)return null;const n=i();if(!n)return null;const r=new Headers(t.headers);r.set(u,a);const s=await n.fetch(new Request(new URL(p,t.url),{headers:r}));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{g as createDoAuthWiring};
1
+ import{INTERNAL_SECRET_HEADER as u,RESOLVE_SESSION_PATH as p,READ_AUDIT_PATH as f}from"./AUTH_DO_AUDIT_PATH-ucS0M60j.mjs";import{DEFAULT_AUTH_BASE_PATH as h,isAuthRoutePath as A}from"./DEFAULT_AUTH_BASE_PATH-DneiLGpv.mjs";const g=l=>{const{basePath:c=h,internalSecret:a,namespace:o,objectName:d="auth"}=l,i=()=>{if(o)return o.get(o.idFromName(d))},m=async(t,n,r)=>{if(!a)return;const s=i();if(!s)return;const e=await s.fetch(new Request(new URL(t,n),{body:JSON.stringify(r),headers:{"content-type":"application/json",[u]:a},method:"POST"}));return e.ok?e:void 0};return{auditReader:{read:async t=>{const n=await m(f,"https://auth-do.invalid",t);return n?(await n.json())?.entries??[]:[]}},authHandler:async t=>{if(A(new URL(t.url).pathname,c))return i()?.fetch(t)},resolveIdentity:async t=>{if(!a)return null;const n=i();if(!n)return null;const r=new Headers(t.headers);r.set(u,a);const s=await n.fetch(new Request(new URL(p,t.url),{headers:r}));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{g as createDoAuthWiring};
@@ -0,0 +1 @@
1
+ import{q as r}from"./quote-identifier-CGiYFBvY.mjs";const i="issuer",c=new RegExp(String.raw`\b${i}\b`,"iu"),u=e=>{const s=e.indexOf("(");if(s===-1)return"";let n=0;for(let t=s;t<e.length;t+=1){const o=e[t];if(o==="(")n+=1;else if(o===")"&&(n-=1,n===0))return e.slice(s+1,t)}return""},f=e=>[...e].includes(i),p=e=>[...e].filter(s=>c.test(u(s.sql??""))).map(s=>s.name),l=(e="account",s=[])=>[...[...s].map(n=>`DROP INDEX IF EXISTS ${r(n)}`),`ALTER TABLE ${r(e)} DROP COLUMN ${r(i)}`];export{p as indexesReferencingIssuer,l as legacyIssuerCleanupStatements,f as schemaDeclaresIssuer};
@@ -0,0 +1 @@
1
+ const t=e=>`"${e.replaceAll('"','""')}"`;export{t as q};
@@ -1479,7 +1479,7 @@ declare const callbackSSO: (options?: SSOOptions) => _$better_call0.StrictEndpoi
1479
1479
  };
1480
1480
  scope: "server";
1481
1481
  };
1482
- }, void>;
1482
+ }, never>;
1483
1483
  /**
1484
1484
  * Shared OIDC callback endpoint (no `:providerId` in path).
1485
1485
  * Used when `options.redirectURI` is set — the `providerId` is read from
@@ -1507,7 +1507,7 @@ declare const callbackSSOShared: (options?: SSOOptions) => _$better_call0.Strict
1507
1507
  error_description: z.ZodOptional<z.ZodString>;
1508
1508
  }, z.core.$strip>;
1509
1509
  allowedMediaTypes: readonly ["application/x-www-form-urlencoded", "application/json"];
1510
- }, void>;
1510
+ }, never>;
1511
1511
  declare const acsEndpoint: (options?: SSOOptions) => _$better_call0.StrictEndpoint<"/sso/saml2/sp/acs/:providerId", {
1512
1512
  method: ("GET" | "POST")[];
1513
1513
  body: z.ZodOptional<z.ZodObject<{
@@ -1479,7 +1479,7 @@ declare const callbackSSO: (options?: SSOOptions) => _$better_call0.StrictEndpoi
1479
1479
  };
1480
1480
  scope: "server";
1481
1481
  };
1482
- }, void>;
1482
+ }, never>;
1483
1483
  /**
1484
1484
  * Shared OIDC callback endpoint (no `:providerId` in path).
1485
1485
  * Used when `options.redirectURI` is set — the `providerId` is read from
@@ -1507,7 +1507,7 @@ declare const callbackSSOShared: (options?: SSOOptions) => _$better_call0.Strict
1507
1507
  error_description: z.ZodOptional<z.ZodString>;
1508
1508
  }, z.core.$strip>;
1509
1509
  allowedMediaTypes: readonly ["application/x-www-form-urlencoded", "application/json"];
1510
- }, void>;
1510
+ }, never>;
1511
1511
  declare const acsEndpoint: (options?: SSOOptions) => _$better_call0.StrictEndpoint<"/sso/saml2/sp/acs/:providerId", {
1512
1512
  method: ("GET" | "POST")[];
1513
1513
  body: z.ZodOptional<z.ZodObject<{
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lunora/auth",
3
- "version": "1.0.0-alpha.123",
3
+ "version": "1.0.0-alpha.125",
4
4
  "description": "Auth for Lunora — a thin better-auth wrapper: email/password, OAuth, plugins, D1-backed",
5
5
  "keywords": [
6
6
  "auth",
@@ -98,23 +98,23 @@
98
98
  "access": "public"
99
99
  },
100
100
  "dependencies": {
101
- "@better-auth/api-key": "1.7.1",
102
- "@better-auth/mcp": "1.7.1",
103
- "@better-auth/oauth-provider": "1.7.1",
104
- "@better-auth/passkey": "1.7.1",
105
- "@better-auth/scim": "1.7.1",
101
+ "@better-auth/api-key": "1.7.3",
102
+ "@better-auth/mcp": "1.7.3",
103
+ "@better-auth/oauth-provider": "1.7.3",
104
+ "@better-auth/passkey": "1.7.3",
105
+ "@better-auth/scim": "1.7.3",
106
106
  "@lunora/errors": "1.0.0-alpha.35",
107
107
  "@lunora/values": "1.0.0-alpha.43",
108
- "@visulima/disposable-email-domains": "1.1.0",
109
- "@visulima/email-verifier": "1.0.2",
108
+ "@visulima/disposable-email-domains": "1.1.1",
109
+ "@visulima/email-verifier": "1.0.9",
110
110
  "@visulima/free-email-domains": "1.0.1",
111
- "@visulima/redact": "4.0.0"
111
+ "@visulima/redact": "5.0.0"
112
112
  },
113
113
  "peerDependencies": {
114
- "@better-auth/core": ">=1.7.1 <2.0.0-0",
115
- "@better-auth/sso": ">=1.7.1 <2.0.0-0",
114
+ "@better-auth/core": ">=1.7.3 <2.0.0-0",
115
+ "@better-auth/sso": ">=1.7.3 <2.0.0-0",
116
116
  "@lunora/server": ">=1.0.0-alpha.24 <2.0.0-0",
117
- "better-auth": ">=1.7.1 <2.0.0-0"
117
+ "better-auth": ">=1.7.3 <2.0.0-0"
118
118
  },
119
119
  "peerDependenciesMeta": {
120
120
  "@better-auth/sso": {
@@ -1 +0,0 @@
1
- import{b as u,d as h}from"./adapter-DA8DdALX.mjs";import{ensureAuthAuditTable as c,createAuthAuditReader as l}from"../audit.mjs";import{resolveAuthOptions as m,createAuth as d}from"./createAuth-8aUw8v8D.mjs";import{authDoSchemaStatements as p,authDoColumnAdditions as f}from"./authDoColumnAdditions-BCSs7qaN.mjs";import{handleAuthRequest as A}from"./DEFAULT_AUTH_BASE_PATH-DneiLGpv.mjs";const g=(n,e)=>{const s=Math.max(n.length,e.length);let t=n.length^e.length;for(let r=0;r<s;r+=1){const i=r<n.length?n.charCodeAt(r):0,o=r<e.length?e.charCodeAt(r):0;t|=i^o}return t===0},R="/__lunora/auth/session",y="/__lunora/auth/audit",S="x-lunora-auth-do-secret",b=n=>{if(n===null||typeof n!="object"||Array.isArray(n))return{error:"body must be a JSON object"};const e={};for(const[s,t]of Object.entries(n))if(s==="limit"||s==="sinceSeq"){if(typeof t!="number"||!Number.isFinite(t))return{error:`"${s}" must be a finite number`};e[s]=t}else if(s==="actorId"||s==="event"){if(typeof t!="string")return{error:`"${s}" must be a string`};e[s]=t}else return{error:`unknown audit read option "${s}"`};return{options:e}};class v{#s;#r;#t;#e;#n=!1;constructor(e,s,t={}){this.#t=e.storage,this.#r=s,this.#s=t}#o(){if(this.#e!==void 0)return this.#e;const e=this.#r();if(!this.#n){const s=m(e);for(const t of p(s))[...this.#t.sql.exec(t)];for(const t of f(s,r=>this.#a(r)))[...this.#t.sql.exec(t)];this.#n=!0}return this.#e=d({...e,database:u(this.#t)}),this.#e}#a(e){return[...this.#t.sql.exec("SELECT name FROM pragma_table_info(?)",e)].map(t=>String(t.name))}async#u(e){if(!this.#i(e))return Response.json({error:"unauthorized"},{status:401});let s;try{s=await e.json()}catch{return Response.json({error:"invalid body"},{status:400})}const t=b(s??{});if("error"in t)return Response.json({error:t.error},{status:400});const r=h(this.#t);await c(r);const i=await l(r).read(t.options);return Response.json({entries:i})}#i(e){const{internalSecret:s}=this.#s;if(s===void 0||s==="")return!1;const t=e.headers.get(S);return t!==null&&g(t,s)}async#h(e){if(!this.#i(e))return Response.json({error:"unauthorized"},{status:401});const t=await this.#o().api.getSession({headers:e.headers}),r=t?.user.id;if(r===void 0)return Response.json({});const i=t?.session.expiresAt,o=t?.user,a=o?.role;return Response.json({...typeof o?.email=="string"&&o.email.length>0?{email:o.email}:{},...i instanceof Date?{expiresAtMs:i.getTime()}:{},...typeof o?.name=="string"&&o.name.length>0?{name:o.name}:{},...typeof a=="string"&&a.length>0?{role:a}:{},userId:r})}async fetch(e){const s=new URL(e.url);if(s.pathname===R)return this.#h(e);if(s.pathname===y)return this.#u(e);const t=this.#o();return await A(t,e,this.#s.basePath)??Response.json({error:"not an auth route"},{status:404})}}export{S as INTERNAL_SECRET_HEADER,v as LunoraAuthDO,y as READ_AUDIT_PATH,R as RESOLVE_SESSION_PATH};
@@ -1 +0,0 @@
1
- import{getAuthTablesWithResolvedIndexes as l,getDatabaseFieldIndexName as N}from"@better-auth/core/db/internal";const r=n=>`"${n.replaceAll('"','""')}"`,d=(n,e)=>{if(n==="id"||e.references?.field==="id")return"text";const{type:t}=e;if(Array.isArray(t))return"text";switch(t){case"boolean":return"integer";case"date":return"date";case"number":return"bigint"in e&&e.bigint===!0?"bigint":"integer";default:return"text"}},b=n=>{const{defaultValue:e,type:t,unique:o}=n;if(!(o===!0&&n.required===!1)&&!(e==null||typeof e=="function")){if(t==="boolean")return e===!0?"1":"0";if(t==="number"&&typeof e=="number"&&Number.isFinite(e))return String(e);if(t==="string"&&typeof e=="string")return`'${e.replaceAll("'","''")}'`}},p=(n,e)=>{const t=[];for(const[o,i]of Object.entries(e)){const s=i.unique===!0;if(!s&&i.index!==!0)continue;const c=i.fieldName??o,u=N(n,c,s);t.push(`CREATE ${s?"UNIQUE ":""}INDEX IF NOT EXISTS ${r(u)} ON ${r(n)} (${r(c)})`)}return t},T=(n,e)=>{const t=[r(n),d(n,e)],o=b(e);return e.required!==!1&&o!==void 0&&t.push("NOT NULL"),o!==void 0&&t.push(`DEFAULT ${o}`),t.join(" ")},E=(n,e)=>{const t=[r(n),d(n,e)];return e.required!==!1&&t.push("NOT NULL"),t.join(" ")},h=n=>{const{indexesByTable:e,tables:t}=l(n),o=[],i=[];for(const s of Object.values(t)){if(s.disableMigrations===!0)continue;const c=[`${r("id")} text NOT NULL PRIMARY KEY`,...Object.entries(s.fields).map(([u,a])=>E(a.fieldName??u,a))];o.push(`CREATE TABLE IF NOT EXISTS ${r(s.modelName)} (${c.join(", ")})`),i.push(...p(s.modelName,s.fields));for(const u of e.get(s.modelName)??[]){const a=u.unique===!0?"UNIQUE ":"",f=u.columns.map(m=>r(m)).join(", ");i.push(`CREATE ${a}INDEX IF NOT EXISTS ${r(u.name)} ON ${r(s.modelName)} (${f})`)}}return[...o,...i]},A=(n,e)=>{const{tables:t}=l(n),o=[];for(const i of Object.values(t)){if(i.disableMigrations===!0)continue;const s=new Set(e(i.modelName));if(s.size!==0)for(const[c,u]of Object.entries(i.fields)){const a=u.fieldName??c;s.has(a)||o.push(`ALTER TABLE ${r(i.modelName)} ADD COLUMN ${T(a,u)}`)}}return o};export{A as authDoColumnAdditions,h as authDoSchemaStatements};
@@ -1 +0,0 @@
1
- import{LunoraError as g}from"@lunora/errors";import{getMigrations as u}from"better-auth/db/migration";import{resolveAuthOptions as w}from"./createAuth-8aUw8v8D.mjs";const I=/pragma_index_list\s*\(/iu,_=/sqlite_master/iu,y=/^["`[]|["\]`]$/gu,R=/\s+/u,x=/create\s+unique\s+index/iu,M=/\bwhere\b/iu,T=t=>I.test(t)&&_.test(t),D=t=>(t.trim().split(R)[0]??"").replaceAll(y,"").trim(),A=t=>{const n=t.indexOf("(");if(n===-1)return{columns:[],tail:""};let s=0;for(let e=n;e<t.length;e+=1){const o=t[e];if(o==="(")s+=1;else if(o===")"&&(s-=1,s===0))return{columns:t.slice(n+1,e).split(",").map(i=>D(i)).filter(i=>i!==""),tail:t.slice(e+1)}}return{columns:[],tail:""}},P=async t=>{const n=t.prepare("SELECT name, tbl_name, sql FROM sqlite_master WHERE type = 'index'"),{results:s}=await n.all(),e=[];for(const o of s??[]){const i=o.name,a=o.tbl_name,r=o.sql;if(typeof i!="string"||typeof a!="string")continue;if(typeof r!="string"){e.push({columnPosition:0,indexName:i,isPartial:0,isUnique:1,tableName:a});continue}const m=x.test(r)?1:0,{columns:f,tail:d}=A(r),h=M.test(d)?1:0;for(const[E,b]of f.entries())e.push({columnName:b,columnPosition:E,indexName:i,isPartial:h,isUnique:m,tableName:a})}return e},N=t=>{const n=async()=>{const e=await P(t);return{meta:{},results:e,success:!0}},s={all:n,bind:()=>s,run:n};return s},U=t=>new Proxy(t,{get(n,s,e){if(s==="prepare")return i=>T(i)?N(n):n.prepare(i);const o=Reflect.get(n,s,e);return typeof o=="function"?o.bind(n):o}}),O=t=>typeof t=="object"&&t!==null&&typeof t.prepare=="function"&&typeof t.batch=="function",l=t=>{const{database:n}=t;if(!(n&&typeof n!="function"))throw new g("AUTH_MIGRATOR_UNSUPPORTED",n?"@lunora/auth: this auth instance's `database` is a custom adapter, which better-auth's migrator cannot drive.":"@lunora/auth: this auth instance has no `database`, so better-auth's migrator has nothing to introspect.")},p=t=>O(t.database)?{...t,database:U(t.database)}:t,c=new WeakMap,H=async t=>{const{options:n}=t;l(n);const s=c.get(n);if(s){await s;return}const e=(async()=>{const{runMigrations:o}=await u(p(n));await o()})();c.set(n,e);try{await e}catch(o){throw c.delete(n),o}},L=async t=>{const n=w(t);l(n);const{compileMigrations:s}=await u(p(n));return s()};export{L as compileMigrationsSql,H as ensureMigrated};