@lunora/auth 1.0.0-alpha.14 → 1.0.0-alpha.140

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (76) hide show
  1. package/LICENSE.md +38 -0
  2. package/README.md +99 -10
  3. package/dist/adapter.d.mts +4 -43
  4. package/dist/adapter.d.ts +4 -43
  5. package/dist/adapter.mjs +1 -48
  6. package/dist/audit.d.mts +131 -0
  7. package/dist/audit.d.ts +131 -0
  8. package/dist/audit.mjs +12 -0
  9. package/dist/email-guard.d.mts +127 -0
  10. package/dist/email-guard.d.ts +127 -0
  11. package/dist/email-guard.mjs +1 -0
  12. package/dist/index.d.mts +801 -157
  13. package/dist/index.d.ts +801 -157
  14. package/dist/index.mjs +1 -12
  15. package/dist/middleware.d.mts +167 -156
  16. package/dist/middleware.d.ts +167 -156
  17. package/dist/middleware.mjs +1 -53
  18. package/dist/packem_shared/AUTH_DO_AUDIT_PATH-th2-Hb30.mjs +1 -0
  19. package/dist/packem_shared/DEFAULT_AUTH_BASE_PATH-DneiLGpv.mjs +1 -0
  20. package/dist/packem_shared/LunoraAuthAdminError-4r29Kj_y.mjs +1 -0
  21. package/dist/packem_shared/adapter-CG0Yv85f.mjs +2 -0
  22. package/dist/packem_shared/adapter.d-BW_ovHul.d.mts +89 -0
  23. package/dist/packem_shared/adapter.d-BWw-tC_U.d.ts +89 -0
  24. package/dist/packem_shared/authAuditHook-C9Gt2iYp.mjs +1 -0
  25. package/dist/packem_shared/authDoColumnAdditions-UwF3Rl41.mjs +1 -0
  26. package/dist/packem_shared/compileMigrationsSql-Ds2snsWg.mjs +1 -0
  27. package/dist/packem_shared/create-auth.d-D1CKOFWc.d.mts +142 -0
  28. package/dist/packem_shared/create-auth.d-D1CKOFWc.d.ts +142 -0
  29. package/dist/packem_shared/createAuth-8aUw8v8D.mjs +1 -0
  30. package/dist/packem_shared/createDoAuthWiring-C8BRUjf6.mjs +1 -0
  31. package/dist/packem_shared/createLunoraAuthClient-DhjhCwmM.mjs +1 -0
  32. package/dist/packem_shared/createSignUpInvitation-ClvskwuB.mjs +1 -0
  33. package/dist/packem_shared/emailGateDatabaseHooks-CAygR3iq.mjs +1 -0
  34. package/dist/packem_shared/invite-only.d-CsPJWAwM.d.ts +126 -0
  35. package/dist/packem_shared/invite-only.d-DKyHHkkQ.d.mts +126 -0
  36. package/dist/packem_shared/legacyIssuerCleanupStatements-D9Kf8OD1.mjs +1 -0
  37. package/dist/packem_shared/on-cloudflare-edge-Dx6gFjBO.mjs +1 -0
  38. package/dist/packem_shared/quote-identifier-CGiYFBvY.mjs +1 -0
  39. package/dist/packem_shared/sessionPresets-C867Mlo4.mjs +1 -0
  40. package/dist/packem_shared/sql-store-CYa4HJsO.mjs +1 -0
  41. package/dist/packem_shared/uiConfig-B8pN6pks.mjs +1 -0
  42. package/dist/plugins-client.d.mts +165 -1
  43. package/dist/plugins-client.d.ts +165 -1
  44. package/dist/plugins-client.mjs +1 -2
  45. package/dist/plugins-enterprise-client.d.mts +15 -0
  46. package/dist/plugins-enterprise-client.d.ts +15 -0
  47. package/dist/plugins-enterprise-client.mjs +1 -0
  48. package/dist/plugins-enterprise.d.mts +1670 -0
  49. package/dist/plugins-enterprise.d.ts +1670 -0
  50. package/dist/plugins-enterprise.mjs +1 -0
  51. package/dist/plugins.d.mts +125 -2
  52. package/dist/plugins.d.ts +125 -2
  53. package/dist/plugins.mjs +1 -22
  54. package/dist/schema.d.mts +39 -39
  55. package/dist/schema.d.ts +39 -39
  56. package/dist/schema.mjs +1 -62
  57. package/dist/sql-store.d.mts +28 -28
  58. package/dist/sql-store.d.ts +28 -28
  59. package/dist/sql-store.mjs +1 -184
  60. package/dist/store.d.mts +65 -47
  61. package/dist/store.d.ts +65 -47
  62. package/dist/store.mjs +1 -183
  63. package/dist/turnstile-middleware.d.mts +73 -55
  64. package/dist/turnstile-middleware.d.ts +73 -55
  65. package/dist/turnstile-middleware.mjs +1 -45
  66. package/dist/turnstile.d.mts +42 -59
  67. package/dist/turnstile.d.ts +42 -59
  68. package/dist/turnstile.mjs +1 -61
  69. package/package.json +39 -5
  70. package/dist/packem_shared/DEFAULT_AUTH_BASE_PATH-DjcUWEQl.mjs +0 -11
  71. package/dist/packem_shared/LunoraAuthAdminError-BxrfEeA_.mjs +0 -249
  72. package/dist/packem_shared/compileMigrationsSql-cyE5U18R.mjs +0 -29
  73. package/dist/packem_shared/create-auth.d-Mwhb4gSc.d.mts +0 -128
  74. package/dist/packem_shared/create-auth.d-Mwhb4gSc.d.ts +0 -128
  75. package/dist/packem_shared/createAuth-hRGxUJ9w.mjs +0 -85
  76. package/dist/packem_shared/sessionPresets-Dwwd74_J.mjs +0 -38
@@ -0,0 +1,126 @@
1
+ import { BetterAuthPlugin } from 'better-auth';
2
+ import { L as LunoraAuth } from "./create-auth.d-D1CKOFWc.mjs";
3
+ /** One pending or spent sign-up invitation. */
4
+ interface SignUpInvitation {
5
+ /** When an account was created for this address; `null` while the invitation is unspent. */
6
+ acceptedAt: Date | null;
7
+ createdAt: Date;
8
+ /** The invited address, lowercased — the only thing an invitation is matched on. */
9
+ email: string;
10
+ expiresAt: Date;
11
+ id: string;
12
+ /** Free-form attribution (a user id, an operator name); never read by the gate. */
13
+ invitedBy: null | string;
14
+ }
15
+ /**
16
+ * What {@link createSignUpInvitation} hands back: the stored row plus the one
17
+ * and only sight of the plaintext `token`. Nothing reads it back afterwards —
18
+ * the database holds a SHA-256 of it — so an invitation link that is lost is
19
+ * reissued, not recovered.
20
+ */
21
+ interface IssuedSignUpInvitation extends SignUpInvitation {
22
+ /** Put this in the sign-up link as `?invite=…`. Never stored, never logged, never listed. */
23
+ token: string;
24
+ }
25
+ /** Options for {@link inviteOnly}. */
26
+ interface InviteOnlyOptions {
27
+ /**
28
+ * Let the very first account through uninvited, so a fresh deployment can be
29
+ * bootstrapped without seeding a row.
30
+ *
31
+ * **Off by default.** The check is "the `user` table is empty", which two
32
+ * concurrent sign-ups can both observe, and the window it opens is the gap
33
+ * between deploying and the owner signing up — whoever finds the URL first
34
+ * gets an account on a deployment whose whole point is that nobody does. Seed
35
+ * the first invitation with {@link createSignUpInvitation} instead (a one-off
36
+ * call at worker init, or an internal mutation you run once).
37
+ * @default false
38
+ */
39
+ allowFirstUser?: boolean;
40
+ }
41
+ /**
42
+ * A better-auth server plugin that refuses to create an account for an address
43
+ * with no unspent invitation, and the `signUpInvitation` table those live in.
44
+ *
45
+ * Issue invitations with {@link createSignUpInvitation}; there is no HTTP
46
+ * endpoint for it on purpose. Who counts as an administrator is your
47
+ * application's question — call it from a mutation you already authorize, the
48
+ * same trust model `createAuthAdmin` documents.
49
+ *
50
+ * The return type is better-auth's own `BetterAuthPlugin` rather than the
51
+ * precise shape of the schema map, for the reason `./ui-config.ts` spells out:
52
+ * an anonymous inferred type is the difference between a build that emits
53
+ * declarations and one that fails in the bundler alone.
54
+ */
55
+ declare const inviteOnly: (options?: InviteOnlyOptions) => BetterAuthPlugin;
56
+ /**
57
+ * Invite `email` to sign up, or refresh an existing invitation for it.
58
+ *
59
+ * Re-inviting an address updates the row in place — a new expiry, and `acceptedAt`
60
+ * cleared — because `email` is unique. That is also how you re-open a seat after
61
+ * deleting the account that took it.
62
+ *
63
+ * This is a trusted server-side call with no authorization of its own; gate it
64
+ * the way you gate any other administrative action. Delivering the invitation is
65
+ * yours too: nothing here sends mail, so the returned row is the whole handoff.
66
+ *
67
+ * Nothing prunes the table — a spent or expired row stays until you delete it with
68
+ * {@link revokeSignUpInvitation}, which is also what keeps it a record of who was
69
+ * let in.
70
+ *
71
+ * Each call mints a **new token** and returns it in the clear, once. Only its
72
+ * SHA-256 is stored, so re-inviting an address invalidates the previous link, and
73
+ * a link that was never delivered is reissued rather than looked up.
74
+ */
75
+ declare const createSignUpInvitation: (auth: LunoraAuth, input: {
76
+ email: string;
77
+ expiresInSeconds?: number;
78
+ invitedBy?: string;
79
+ }) => Promise<IssuedSignUpInvitation>;
80
+ /**
81
+ * The most recent invitations, newest first, up to a fixed ceiling of
82
+ * {@link MAX_LISTED}. `pendingOnly` drops the spent and the expired, which is the
83
+ * list an operator usually wants; the unfiltered form doubles as the record of who
84
+ * was let in.
85
+ *
86
+ * Deliberately not paged. "Pending" is two conditions, one of them a comparison
87
+ * against `now`, and filtering those after a page would let page 1 come back empty
88
+ * while pending invitations sat on page 2. An operator list that outgrows the
89
+ * ceiling wants a query against the `signUpInvitation` table, not an offset.
90
+ */
91
+ declare const listSignUpInvitations: (auth: LunoraAuth, options?: {
92
+ pendingOnly?: boolean;
93
+ }) => Promise<SignUpInvitation[]>;
94
+ /**
95
+ * Withdraw the invitation for `email`. Deletes the row, so it also forgets a spent
96
+ * one — the account it created is untouched, and removing that is
97
+ * `AuthAdmin.removeUser`'s job.
98
+ *
99
+ * Not retroactive, and not atomic against a sign-up already in flight: better-auth
100
+ * creates the user without wrapping the `before` hook and the insert in one
101
+ * transaction, so a revoke landing between the two lets that one account through.
102
+ * There is no conditional consume in the adapter contract to close it with. Treat
103
+ * revocation as "no further sign-ups", and `AuthAdmin.removeUser` as the way to
104
+ * undo one that already happened.
105
+ */
106
+ declare const revokeSignUpInvitation: (auth: LunoraAuth, input: {
107
+ email: string;
108
+ }) => Promise<void>;
109
+ /**
110
+ * Delete invitations that expired without being used, and report how many went.
111
+ *
112
+ * Only the dead ones: a spent invitation is the record of who was let in, and an
113
+ * unexpired one is still live, so both stay. Nothing calls this for you — an app
114
+ * that invites at any volume should put it on a cron; one that doesn't can leave
115
+ * the rows.
116
+ *
117
+ * Bounded by `limit` and therefore incremental: a backlog larger than one pass
118
+ * takes several. It reads a page and deletes row by row rather than issuing one
119
+ * ranged `deleteMany`, because a `lt` comparison against a `date` column is the
120
+ * kind of thing that behaves differently on each of the three adapters this
121
+ * package ships, and a prune job is not where that should be discovered.
122
+ */
123
+ declare const pruneSignUpInvitations: (auth: LunoraAuth, options?: {
124
+ limit?: number;
125
+ }) => Promise<number>;
126
+ export { InviteOnlyOptions as I, SignUpInvitation as S, IssuedSignUpInvitation as a, createSignUpInvitation as c, inviteOnly as i, listSignUpInvitations as l, pruneSignUpInvitations as p, revokeSignUpInvitation as r };
@@ -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 o=()=>globalThis.navigator?.userAgent==="Cloudflare-Workers";export{o};
@@ -0,0 +1 @@
1
+ const t=e=>`"${e.replaceAll('"','""')}"`;export{t as q};
@@ -0,0 +1 @@
1
+ const t=n=>{const o=["expiresIn","updateAge","freshAge"];for(const s of o){const e=n[s];if(e!==void 0&&(typeof e!="number"||!Number.isFinite(e)||e<0))throw new TypeError(`@lunora/auth: \`session.${s}\` must be a non-negative, finite number of seconds`)}return n},i={longLived:{cookieCache:{enabled:!0,maxAge:60},expiresIn:2592e3,freshAge:86400,updateAge:86400},rolling:{cookieCache:{enabled:!0,maxAge:60},expiresIn:604800,freshAge:86400,updateAge:86400},strict:{cookieCache:{enabled:!1},expiresIn:3600,freshAge:300,updateAge:900}};export{i as sessionPresets,t as validateSessionPolicy};
@@ -0,0 +1 @@
1
+ const T="_creationTime",l=s=>`"${s.replaceAll('"','""')}"`,N=/no such column|column .{0,64}? does not exist/iu,g={params:[],sql:"0"},R=(s,r)=>r?{column:`LOWER(${s})`,placeholder:"LOWER(?)"}:{column:s,placeholder:"?"},M=(s,r,a,c)=>{if(typeof r!="string")return g;const t=R(s,c);return a==="contains"?{params:[r],sql:`instr(${t.column}, ${t.placeholder}) > 0`}:a==="starts_with"?{params:[r],sql:`instr(${t.column}, ${t.placeholder}) = 1`}:{params:[r,r],sql:`substr(${t.column}, -length(?)) = ${t.placeholder}`}},h=(s,r,a,c)=>{if(r===null)return{params:[],sql:`${s} IS ${c?"NOT ":""}NULL`};const t=R(s,a),n=c?"<>":"=";return{params:[r],sql:`${t.column} ${n} ${t.placeholder}`}},O=(s,r,a,c)=>{const t=Array.isArray(r)?r:[];if(t.length===0)return{params:[],sql:a?"1":"0"};const n=R(s,c),e=t.map(()=>n.placeholder).join(", ");return{params:[...t],sql:`${n.column} ${a?"NOT IN":"IN"} (${e})`}},L=s=>{const r=l(s.field),{mode:a,operator:c,value:t}=s,n=a==="insensitive";switch(c){case"contains":case"ends_with":case"starts_with":return M(r,t,c,n);case"gt":return{params:[t],sql:`${r} > ?`};case"gte":return{params:[t],sql:`${r} >= ?`};case"in":return O(r,t,!1,n);case"lt":return{params:[t],sql:`${r} < ?`};case"lte":return{params:[t],sql:`${r} <= ?`};case"ne":return h(r,t,n,!0);case"not_in":return O(r,t,!0,n);default:return h(r,t,n,!1)}},d=(s,r)=>{if(s.length===0)return;const a=s.map(c=>L(c));return{params:a.flatMap(c=>c.params),sql:a.map(c=>`(${c.sql})`).join(` ${r} `)}},E=s=>{const r=[d(s.filter(a=>a.connector!=="OR"),"AND"),d(s.filter(a=>a.connector==="OR"),"OR")].filter(a=>a!==void 0);return r.length===0?{params:[],sql:""}:{params:r.flatMap(a=>a.params),sql:r.map(a=>`(${a.sql})`).join(" AND ")}},$=s=>s.sql?` WHERE ${s.sql}`:"",S=s=>{const r=(t,n)=>{const e=E(n);return s.all(`SELECT * FROM ${l(t)}${$(e)}`,e.params)},a=new Map,c=async t=>{const n=a.get(t);if(n!==void 0)return n;try{await s.all(`SELECT ${l(t)}.${l(T)} FROM ${l(t)} LIMIT 0`,[])}catch(e){return N.test(e instanceof Error?e.message:String(e))&&a.set(t,!1),!1}return a.set(t,!0),!0};return{consumeOne:async(t,n)=>{const e=E(n),o=l(t),[i]=await s.all(`DELETE FROM ${o} WHERE rowid IN (SELECT rowid FROM ${o}${$(e)} LIMIT 1) RETURNING *`,e.params);return i},count:async(t,n)=>{const e=E(n),[o]=await s.all(`SELECT COUNT(*) AS __count FROM ${l(t)}${$(e)}`,e.params);return Number(o?.__count??0)},create:async(t,n)=>{const e=T in n||!await c(t)?n:{[T]:Date.now(),...n},o=Object.keys(e),i=o.map(()=>"?").join(", "),u=`INSERT INTO ${l(t)} (${o.map(m=>l(m)).join(", ")}) VALUES (${i})`;return await s.run(u,o.map(m=>e[m])),{...n}},incrementOne:async(t,n,e,o)=>{const i=l(t),u=Object.keys(e),m=o?Object.keys(o):[],f=E(n);if(u.length===0&&m.length===0){const[p]=await s.all(`SELECT * FROM ${i}${$(f)} LIMIT 1`,f.params);return p}const I=[...u.map(p=>`${l(p)} = COALESCE(${l(p)}, 0) + ?`),...m.map(p=>`${l(p)} = ?`)].join(", "),[w]=await s.all(`UPDATE ${i} SET ${I} WHERE rowid IN (SELECT rowid FROM ${i}${$(f)} LIMIT 1) RETURNING *`,[...u.map(p=>e[p]),...m.map(p=>o[p]),...f.params]);return w},read:async(t,n)=>{const e=E(n.where),o=[...e.params];let i=`SELECT * FROM ${l(t)}${$(e)}`;return n.sortBy&&(i+=` ORDER BY ${l(n.sortBy.field)} ${n.sortBy.direction==="asc"?"ASC":"DESC"}`),n.limit!==void 0&&(i+=" LIMIT ?",o.push(Math.trunc(n.limit))),n.offset&&(i+=`${n.limit===void 0?" LIMIT -1":""} OFFSET ?`,o.push(Math.trunc(n.offset))),s.all(i,o)},remove:async(t,n)=>{const e=E(n);return(await s.all(`DELETE FROM ${l(t)}${$(e)} RETURNING *`,e.params)).length},update:async(t,n,e)=>{const o=Object.keys(e);if(o.length===0)return r(t,n);const i=o.map(m=>`${l(m)} = ?`).join(", "),u=E(n);return s.all(`UPDATE ${l(t)} SET ${i}${$(u)} RETURNING *`,[...o.map(m=>e[m]),...u.params])}}},C=s=>({all:async(r,a)=>(await s.prepare(r).bind(...a).all()).results??[],run:async(r,a)=>{await s.prepare(r).bind(...a).run()}});export{T as C,S as c,C as d};
@@ -0,0 +1 @@
1
+ import{createAuthEndpoint as c}from"better-auth/api";import{getAuthTables as g}from"better-auth/db";const l=e=>[...e].toSorted((o,i)=>o.localeCompare(i)),m=(e,o={})=>{const i=o.expose??{},a=new Set((e.plugins??[]).map(t=>t.id)),r=e.emailAndPassword?.enabled??!1,s=g(e),n=(e.plugins??[]).find(t=>t.id==="organization")?.options??{},d={allowUserToCreate:typeof n.allowUserToCreateOrganization=="function"?!0:n.allowUserToCreateOrganization!==!1,enabled:a.has("organization"),invitationLimit:n.invitationLimit,limit:n.organizationLimit,membershipLimit:n.membershipLimit,roles:!!s.organizationRole,teams:!!s.team};return{emailAndPassword:r,signUp:r&&e.emailAndPassword?.disableSignUp!==!0,...i.organization===!1?{}:{organization:d},...i.plugins===!1?{}:{plugins:l(a)},...i.socialProviders===!1?{}:{socialProviders:l(new Set([...Object.keys(e.socialProviders??{}),...o.extraProviders??[]]))}}},p=e=>c(e.path??"/ui-config",{metadata:{openapi:{description:"Public description of the enabled auth plugins and social providers.",responses:{200:{description:"The UI configuration."}}}},method:"GET"},o=>{const i=o;return Promise.resolve(i.json(m(i.context.options,e)))}),h=(e={})=>({endpoints:{getUiConfig:p(e)},id:"lunora-ui-config"});export{m as deriveUiConfig,h as uiConfig};
@@ -1,2 +1,166 @@
1
+ import { organizationClient } from 'better-auth/client/plugins';
2
+ export { adminClient, anonymousClient, customSessionClient, deviceAuthorizationClient, emailOTPClient, inferAdditionalFields, inferOrgAdditionalFields, jwtClient, lastLoginMethodClient, magicLinkClient, multiSessionClient, oneTapClient, oneTimeTokenClient, organizationClient, phoneNumberClient, siweClient, twoFactorClient, usernameClient } from 'better-auth/client/plugins';
3
+ export { apiKeyClient } from '@better-auth/api-key/client';
4
+ export { oauthDeviceAuthorizationClient, oauthProviderClient } from '@better-auth/oauth-provider/client';
1
5
  export { passkeyClient } from '@better-auth/passkey/client';
2
- export { adminClient, anonymousClient, customSessionClient, deviceAuthorizationClient, emailOTPClient, genericOAuthClient, inferAdditionalFields, inferOrgAdditionalFields, jwtClient, lastLoginMethodClient, magicLinkClient, multiSessionClient, oidcClient, oneTimeTokenClient, organizationClient, phoneNumberClient, siweClient, twoFactorClient, usernameClient } from 'better-auth/client/plugins';
6
+ /**
7
+ * Which client plugins to include. Each defaults to `false`.
8
+ *
9
+ * These are the same names `@lunora/auth-ui` gates its cards on, so one object
10
+ * can drive both `createLunoraAuthClient` and `registerAuthClientPlugins` — a
11
+ * flow the UI can show but this cannot install would be a card that renders and
12
+ * then fails at call time.
13
+ *
14
+ * `oneTap` is absent on purpose: Google One Tap needs a client id, not a
15
+ * boolean, so it comes in through {@link CreateLunoraAuthClientOptions.oneTapClientId}.
16
+ */
17
+ interface LunoraAuthPluginToggles {
18
+ admin?: boolean;
19
+ anonymous?: boolean;
20
+ deviceAuthorization?: boolean;
21
+ emailOtp?: boolean;
22
+ lastLoginMethod?: boolean;
23
+ magicLink?: boolean;
24
+ multiSession?: boolean;
25
+ oauthProvider?: boolean;
26
+ organization?: boolean;
27
+ passkey?: boolean;
28
+ phoneNumber?: boolean;
29
+ twoFactor?: boolean;
30
+ username?: boolean;
31
+ }
32
+ type LunoraAuthClientPlugin = ReturnType<typeof organizationClient>;
33
+ declare const lunoraAuthPlugins: (toggles?: LunoraAuthPluginToggles) => LunoraAuthClientPlugin[];
34
+ /** Options for {@link createLunoraAuthClient}; anything else is forwarded to `createAuthClient`. */
35
+ interface CreateLunoraAuthClientOptions {
36
+ [option: string]: unknown;
37
+ /** Defaults to the current origin, which is right for a same-origin app. */
38
+ baseURL?: string;
39
+ /** Your own client plugins, appended after the standard set. */
40
+ extraPlugins?: LunoraAuthClientPlugin[];
41
+ /**
42
+ * Google OAuth client id. Setting it installs the One Tap client plugin —
43
+ * a boolean toggle can't, because the prompt is Google's and needs the id.
44
+ */
45
+ oneTapClientId?: string;
46
+ /** Which standard client plugins to include. */
47
+ plugins?: LunoraAuthPluginToggles;
48
+ }
49
+ /**
50
+ * Build a better-auth client with Lunora's standard plugin set from toggles.
51
+ *
52
+ * You pass your framework's `createAuthClient` in — `better-auth/react`,
53
+ * `/vue`, `/svelte`, or `/solid` — because the variant has to match the UI
54
+ * framework, and a helper that picked for you would either guess wrong or drag
55
+ * every variant into your bundle.
56
+ *
57
+ * ```ts
58
+ * import { createAuthClient } from "better-auth/react";
59
+ * import { createLunoraAuthClient } from "@lunora/auth/plugins/client";
60
+ *
61
+ * export const authClient = createLunoraAuthClient(createAuthClient, {
62
+ * plugins: { organization: true, passkey: true, twoFactor: true },
63
+ * });
64
+ * ```
65
+ *
66
+ * Reach for {@link lunoraAuthPlugins} instead when you want to own the
67
+ * `createAuthClient` call and only borrow the plugin array.
68
+ */
69
+ declare const createLunoraAuthClient: <TClient>(createAuthClient: (options: Record<string, unknown>) => TClient, options?: CreateLunoraAuthClientOptions) => TClient;
70
+ export {
71
+ /**
72
+ * Client-side counterparts to the server plugins re-exported from
73
+ * `@lunora/auth/plugins`, surfaced under `@lunora/auth/plugins/client`.
74
+ *
75
+ * better-auth plugins come in two halves: a **server** plugin you pass to
76
+ * `betterAuth()` (re-exported from `@lunora/auth/plugins`) and a **client**
77
+ * plugin you pass to `createAuthClient()`. Both halves must be registered for a
78
+ * plugin's endpoints, inferred types, and client actions (e.g.
79
+ * `authClient.twoFactor.*`, `authClient.organization.*`, the `twoFactorRedirect`
80
+ * sign-in flow) to exist. This module is the client half so consumers don't have
81
+ * to reach into better-auth's `better-auth/client/plugins` subpath directly.
82
+ *
83
+ * # Wiring
84
+ *
85
+ * ```ts
86
+ * import { createAuthClient } from "better-auth/client"; // or a framework adapter
87
+ * import { organizationClient, twoFactorClient } from "@lunora/auth/plugins/client";
88
+ *
89
+ * export const authClient = createAuthClient({
90
+ * baseURL: import.meta.env.VITE_AUTH_URL,
91
+ * plugins: [
92
+ * organizationClient(),
93
+ * twoFactorClient({ onTwoFactorRedirect: () => location.assign("/2fa") }),
94
+ * ],
95
+ * });
96
+ * ```
97
+ *
98
+ * Keep the client plugin list in parity with the server `plugins` array passed
99
+ * to `createAuth`: a server plugin without its client counterpart leaves
100
+ * those actions untyped/unavailable, and vice-versa.
101
+ */
102
+ type CreateLunoraAuthClientOptions,
103
+ /**
104
+ * Client-side counterparts to the server plugins re-exported from
105
+ * `@lunora/auth/plugins`, surfaced under `@lunora/auth/plugins/client`.
106
+ *
107
+ * better-auth plugins come in two halves: a **server** plugin you pass to
108
+ * `betterAuth()` (re-exported from `@lunora/auth/plugins`) and a **client**
109
+ * plugin you pass to `createAuthClient()`. Both halves must be registered for a
110
+ * plugin's endpoints, inferred types, and client actions (e.g.
111
+ * `authClient.twoFactor.*`, `authClient.organization.*`, the `twoFactorRedirect`
112
+ * sign-in flow) to exist. This module is the client half so consumers don't have
113
+ * to reach into better-auth's `better-auth/client/plugins` subpath directly.
114
+ *
115
+ * # Wiring
116
+ *
117
+ * ```ts
118
+ * import { createAuthClient } from "better-auth/client"; // or a framework adapter
119
+ * import { organizationClient, twoFactorClient } from "@lunora/auth/plugins/client";
120
+ *
121
+ * export const authClient = createAuthClient({
122
+ * baseURL: import.meta.env.VITE_AUTH_URL,
123
+ * plugins: [
124
+ * organizationClient(),
125
+ * twoFactorClient({ onTwoFactorRedirect: () => location.assign("/2fa") }),
126
+ * ],
127
+ * });
128
+ * ```
129
+ *
130
+ * Keep the client plugin list in parity with the server `plugins` array passed
131
+ * to `createAuth`: a server plugin without its client counterpart leaves
132
+ * those actions untyped/unavailable, and vice-versa.
133
+ */
134
+ type LunoraAuthClientPlugin,
135
+ /**
136
+ * Client-side counterparts to the server plugins re-exported from
137
+ * `@lunora/auth/plugins`, surfaced under `@lunora/auth/plugins/client`.
138
+ *
139
+ * better-auth plugins come in two halves: a **server** plugin you pass to
140
+ * `betterAuth()` (re-exported from `@lunora/auth/plugins`) and a **client**
141
+ * plugin you pass to `createAuthClient()`. Both halves must be registered for a
142
+ * plugin's endpoints, inferred types, and client actions (e.g.
143
+ * `authClient.twoFactor.*`, `authClient.organization.*`, the `twoFactorRedirect`
144
+ * sign-in flow) to exist. This module is the client half so consumers don't have
145
+ * to reach into better-auth's `better-auth/client/plugins` subpath directly.
146
+ *
147
+ * # Wiring
148
+ *
149
+ * ```ts
150
+ * import { createAuthClient } from "better-auth/client"; // or a framework adapter
151
+ * import { organizationClient, twoFactorClient } from "@lunora/auth/plugins/client";
152
+ *
153
+ * export const authClient = createAuthClient({
154
+ * baseURL: import.meta.env.VITE_AUTH_URL,
155
+ * plugins: [
156
+ * organizationClient(),
157
+ * twoFactorClient({ onTwoFactorRedirect: () => location.assign("/2fa") }),
158
+ * ],
159
+ * });
160
+ * ```
161
+ *
162
+ * Keep the client plugin list in parity with the server `plugins` array passed
163
+ * to `createAuth`: a server plugin without its client counterpart leaves
164
+ * those actions untyped/unavailable, and vice-versa.
165
+ */
166
+ type LunoraAuthPluginToggles, createLunoraAuthClient, lunoraAuthPlugins };
@@ -1,2 +1,166 @@
1
+ import { organizationClient } from 'better-auth/client/plugins';
2
+ export { adminClient, anonymousClient, customSessionClient, deviceAuthorizationClient, emailOTPClient, inferAdditionalFields, inferOrgAdditionalFields, jwtClient, lastLoginMethodClient, magicLinkClient, multiSessionClient, oneTapClient, oneTimeTokenClient, organizationClient, phoneNumberClient, siweClient, twoFactorClient, usernameClient } from 'better-auth/client/plugins';
3
+ export { apiKeyClient } from '@better-auth/api-key/client';
4
+ export { oauthDeviceAuthorizationClient, oauthProviderClient } from '@better-auth/oauth-provider/client';
1
5
  export { passkeyClient } from '@better-auth/passkey/client';
2
- export { adminClient, anonymousClient, customSessionClient, deviceAuthorizationClient, emailOTPClient, genericOAuthClient, inferAdditionalFields, inferOrgAdditionalFields, jwtClient, lastLoginMethodClient, magicLinkClient, multiSessionClient, oidcClient, oneTimeTokenClient, organizationClient, phoneNumberClient, siweClient, twoFactorClient, usernameClient } from 'better-auth/client/plugins';
6
+ /**
7
+ * Which client plugins to include. Each defaults to `false`.
8
+ *
9
+ * These are the same names `@lunora/auth-ui` gates its cards on, so one object
10
+ * can drive both `createLunoraAuthClient` and `registerAuthClientPlugins` — a
11
+ * flow the UI can show but this cannot install would be a card that renders and
12
+ * then fails at call time.
13
+ *
14
+ * `oneTap` is absent on purpose: Google One Tap needs a client id, not a
15
+ * boolean, so it comes in through {@link CreateLunoraAuthClientOptions.oneTapClientId}.
16
+ */
17
+ interface LunoraAuthPluginToggles {
18
+ admin?: boolean;
19
+ anonymous?: boolean;
20
+ deviceAuthorization?: boolean;
21
+ emailOtp?: boolean;
22
+ lastLoginMethod?: boolean;
23
+ magicLink?: boolean;
24
+ multiSession?: boolean;
25
+ oauthProvider?: boolean;
26
+ organization?: boolean;
27
+ passkey?: boolean;
28
+ phoneNumber?: boolean;
29
+ twoFactor?: boolean;
30
+ username?: boolean;
31
+ }
32
+ type LunoraAuthClientPlugin = ReturnType<typeof organizationClient>;
33
+ declare const lunoraAuthPlugins: (toggles?: LunoraAuthPluginToggles) => LunoraAuthClientPlugin[];
34
+ /** Options for {@link createLunoraAuthClient}; anything else is forwarded to `createAuthClient`. */
35
+ interface CreateLunoraAuthClientOptions {
36
+ [option: string]: unknown;
37
+ /** Defaults to the current origin, which is right for a same-origin app. */
38
+ baseURL?: string;
39
+ /** Your own client plugins, appended after the standard set. */
40
+ extraPlugins?: LunoraAuthClientPlugin[];
41
+ /**
42
+ * Google OAuth client id. Setting it installs the One Tap client plugin —
43
+ * a boolean toggle can't, because the prompt is Google's and needs the id.
44
+ */
45
+ oneTapClientId?: string;
46
+ /** Which standard client plugins to include. */
47
+ plugins?: LunoraAuthPluginToggles;
48
+ }
49
+ /**
50
+ * Build a better-auth client with Lunora's standard plugin set from toggles.
51
+ *
52
+ * You pass your framework's `createAuthClient` in — `better-auth/react`,
53
+ * `/vue`, `/svelte`, or `/solid` — because the variant has to match the UI
54
+ * framework, and a helper that picked for you would either guess wrong or drag
55
+ * every variant into your bundle.
56
+ *
57
+ * ```ts
58
+ * import { createAuthClient } from "better-auth/react";
59
+ * import { createLunoraAuthClient } from "@lunora/auth/plugins/client";
60
+ *
61
+ * export const authClient = createLunoraAuthClient(createAuthClient, {
62
+ * plugins: { organization: true, passkey: true, twoFactor: true },
63
+ * });
64
+ * ```
65
+ *
66
+ * Reach for {@link lunoraAuthPlugins} instead when you want to own the
67
+ * `createAuthClient` call and only borrow the plugin array.
68
+ */
69
+ declare const createLunoraAuthClient: <TClient>(createAuthClient: (options: Record<string, unknown>) => TClient, options?: CreateLunoraAuthClientOptions) => TClient;
70
+ export {
71
+ /**
72
+ * Client-side counterparts to the server plugins re-exported from
73
+ * `@lunora/auth/plugins`, surfaced under `@lunora/auth/plugins/client`.
74
+ *
75
+ * better-auth plugins come in two halves: a **server** plugin you pass to
76
+ * `betterAuth()` (re-exported from `@lunora/auth/plugins`) and a **client**
77
+ * plugin you pass to `createAuthClient()`. Both halves must be registered for a
78
+ * plugin's endpoints, inferred types, and client actions (e.g.
79
+ * `authClient.twoFactor.*`, `authClient.organization.*`, the `twoFactorRedirect`
80
+ * sign-in flow) to exist. This module is the client half so consumers don't have
81
+ * to reach into better-auth's `better-auth/client/plugins` subpath directly.
82
+ *
83
+ * # Wiring
84
+ *
85
+ * ```ts
86
+ * import { createAuthClient } from "better-auth/client"; // or a framework adapter
87
+ * import { organizationClient, twoFactorClient } from "@lunora/auth/plugins/client";
88
+ *
89
+ * export const authClient = createAuthClient({
90
+ * baseURL: import.meta.env.VITE_AUTH_URL,
91
+ * plugins: [
92
+ * organizationClient(),
93
+ * twoFactorClient({ onTwoFactorRedirect: () => location.assign("/2fa") }),
94
+ * ],
95
+ * });
96
+ * ```
97
+ *
98
+ * Keep the client plugin list in parity with the server `plugins` array passed
99
+ * to `createAuth`: a server plugin without its client counterpart leaves
100
+ * those actions untyped/unavailable, and vice-versa.
101
+ */
102
+ type CreateLunoraAuthClientOptions,
103
+ /**
104
+ * Client-side counterparts to the server plugins re-exported from
105
+ * `@lunora/auth/plugins`, surfaced under `@lunora/auth/plugins/client`.
106
+ *
107
+ * better-auth plugins come in two halves: a **server** plugin you pass to
108
+ * `betterAuth()` (re-exported from `@lunora/auth/plugins`) and a **client**
109
+ * plugin you pass to `createAuthClient()`. Both halves must be registered for a
110
+ * plugin's endpoints, inferred types, and client actions (e.g.
111
+ * `authClient.twoFactor.*`, `authClient.organization.*`, the `twoFactorRedirect`
112
+ * sign-in flow) to exist. This module is the client half so consumers don't have
113
+ * to reach into better-auth's `better-auth/client/plugins` subpath directly.
114
+ *
115
+ * # Wiring
116
+ *
117
+ * ```ts
118
+ * import { createAuthClient } from "better-auth/client"; // or a framework adapter
119
+ * import { organizationClient, twoFactorClient } from "@lunora/auth/plugins/client";
120
+ *
121
+ * export const authClient = createAuthClient({
122
+ * baseURL: import.meta.env.VITE_AUTH_URL,
123
+ * plugins: [
124
+ * organizationClient(),
125
+ * twoFactorClient({ onTwoFactorRedirect: () => location.assign("/2fa") }),
126
+ * ],
127
+ * });
128
+ * ```
129
+ *
130
+ * Keep the client plugin list in parity with the server `plugins` array passed
131
+ * to `createAuth`: a server plugin without its client counterpart leaves
132
+ * those actions untyped/unavailable, and vice-versa.
133
+ */
134
+ type LunoraAuthClientPlugin,
135
+ /**
136
+ * Client-side counterparts to the server plugins re-exported from
137
+ * `@lunora/auth/plugins`, surfaced under `@lunora/auth/plugins/client`.
138
+ *
139
+ * better-auth plugins come in two halves: a **server** plugin you pass to
140
+ * `betterAuth()` (re-exported from `@lunora/auth/plugins`) and a **client**
141
+ * plugin you pass to `createAuthClient()`. Both halves must be registered for a
142
+ * plugin's endpoints, inferred types, and client actions (e.g.
143
+ * `authClient.twoFactor.*`, `authClient.organization.*`, the `twoFactorRedirect`
144
+ * sign-in flow) to exist. This module is the client half so consumers don't have
145
+ * to reach into better-auth's `better-auth/client/plugins` subpath directly.
146
+ *
147
+ * # Wiring
148
+ *
149
+ * ```ts
150
+ * import { createAuthClient } from "better-auth/client"; // or a framework adapter
151
+ * import { organizationClient, twoFactorClient } from "@lunora/auth/plugins/client";
152
+ *
153
+ * export const authClient = createAuthClient({
154
+ * baseURL: import.meta.env.VITE_AUTH_URL,
155
+ * plugins: [
156
+ * organizationClient(),
157
+ * twoFactorClient({ onTwoFactorRedirect: () => location.assign("/2fa") }),
158
+ * ],
159
+ * });
160
+ * ```
161
+ *
162
+ * Keep the client plugin list in parity with the server `plugins` array passed
163
+ * to `createAuth`: a server plugin without its client counterpart leaves
164
+ * those actions untyped/unavailable, and vice-versa.
165
+ */
166
+ type LunoraAuthPluginToggles, createLunoraAuthClient, lunoraAuthPlugins };
@@ -1,2 +1 @@
1
- export { passkeyClient } from '@better-auth/passkey/client';
2
- export { adminClient, anonymousClient, customSessionClient, deviceAuthorizationClient, emailOTPClient, genericOAuthClient, inferAdditionalFields, inferOrgAdditionalFields, jwtClient, lastLoginMethodClient, magicLinkClient, multiSessionClient, oidcClient, oneTimeTokenClient, organizationClient, phoneNumberClient, siweClient, twoFactorClient, usernameClient } from 'better-auth/client/plugins';
1
+ import{createLunoraAuthClient as t,lunoraAuthPlugins as n}from"./packem_shared/createLunoraAuthClient-DhjhCwmM.mjs";import{apiKeyClient as l}from"@better-auth/api-key/client";import{oauthDeviceAuthorizationClient as a,oauthProviderClient as C}from"@better-auth/oauth-provider/client";import{passkeyClient as s}from"@better-auth/passkey/client";import{adminClient as d,anonymousClient as p,customSessionClient as h,deviceAuthorizationClient as f,emailOTPClient as c,inferAdditionalFields as A,inferOrgAdditionalFields as g,jwtClient as x,lastLoginMethodClient as T,magicLinkClient as k,multiSessionClient as v,oneTapClient as w,oneTimeTokenClient as y,organizationClient as z,phoneNumberClient as F,siweClient as L,twoFactorClient as P,usernameClient as O}from"better-auth/client/plugins";export{d as adminClient,p as anonymousClient,l as apiKeyClient,t as createLunoraAuthClient,h as customSessionClient,f as deviceAuthorizationClient,c as emailOTPClient,A as inferAdditionalFields,g as inferOrgAdditionalFields,x as jwtClient,T as lastLoginMethodClient,n as lunoraAuthPlugins,k as magicLinkClient,v as multiSessionClient,a as oauthDeviceAuthorizationClient,C as oauthProviderClient,w as oneTapClient,y as oneTimeTokenClient,z as organizationClient,s as passkeyClient,F as phoneNumberClient,L as siweClient,P as twoFactorClient,O as usernameClient};
@@ -0,0 +1,15 @@
1
+ import { ssoClient } from '@better-auth/sso/client';
2
+ export type {
3
+ /**
4
+ * Adds `authClient.signIn.sso({ email | domain | providerId })`. Registering the
5
+ * server `sso` plugin without this leaves those actions unavailable and untyped.
6
+ * @experimental
7
+ */
8
+ ssoClient } from '@better-auth/sso/client';
9
+ /**
10
+ * The plugin instance `ssoClient()` returns. Exported so an app can type the array it
11
+ * passes to `createAuthClient` when it assembles plugins conditionally.
12
+ * @experimental
13
+ */
14
+ type SSOClientPlugin = ReturnType<typeof ssoClient>;
15
+ export { SSOClientPlugin };
@@ -0,0 +1,15 @@
1
+ import { ssoClient } from '@better-auth/sso/client';
2
+ export type {
3
+ /**
4
+ * Adds `authClient.signIn.sso({ email | domain | providerId })`. Registering the
5
+ * server `sso` plugin without this leaves those actions unavailable and untyped.
6
+ * @experimental
7
+ */
8
+ ssoClient } from '@better-auth/sso/client';
9
+ /**
10
+ * The plugin instance `ssoClient()` returns. Exported so an app can type the array it
11
+ * passes to `createAuthClient` when it assembles plugins conditionally.
12
+ * @experimental
13
+ */
14
+ type SSOClientPlugin = ReturnType<typeof ssoClient>;
15
+ export { SSOClientPlugin };
@@ -0,0 +1 @@
1
+ import{ssoClient as r}from"@better-auth/sso/client";export{r as ssoClient};