@lunora/auth 1.0.0-alpha.2 → 1.0.0-alpha.20
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/LICENSE.md +6 -0
- package/__assets__/package-og.svg +1 -1
- package/dist/adapter.mjs +1 -0
- package/dist/index.d.mts +17 -7
- package/dist/index.d.ts +17 -7
- package/dist/index.mjs +4 -4
- package/dist/middleware.d.mts +3 -2
- package/dist/middleware.d.ts +3 -2
- package/dist/middleware.mjs +6 -3
- package/dist/packem_shared/{LunoraAuthAdminError-BxrfEeA_.mjs → LunoraAuthAdminError-BpVImgEy.mjs} +4 -5
- package/dist/packem_shared/{compileMigrationsSql-wZH3oXDu.mjs → compileMigrationsSql-B9bj-mJv.mjs} +2 -1
- package/dist/packem_shared/create-auth.d-Mwhb4gSc.d.mts +128 -0
- package/dist/packem_shared/create-auth.d-Mwhb4gSc.d.ts +128 -0
- package/dist/packem_shared/{createAuth-B-tvsvQU.mjs → createAuth-BVMMllTm.mjs} +39 -8
- package/dist/packem_shared/{sessionPresets-B95rXrd8.mjs → sessionPresets-Dwwd74_J.mjs} +3 -0
- package/dist/schema.d.mts +1 -1
- package/dist/schema.d.ts +1 -1
- package/dist/sql-store.mjs +22 -0
- package/dist/store.d.mts +18 -0
- package/dist/store.d.ts +18 -0
- package/dist/store.mjs +13 -0
- package/package.json +7 -6
- package/dist/packem_shared/create-auth.d-M36jwG_Y.d.mts +0 -58
- package/dist/packem_shared/create-auth.d-M36jwG_Y.d.ts +0 -58
package/dist/store.d.ts
CHANGED
|
@@ -43,6 +43,24 @@ interface AuthStore {
|
|
|
43
43
|
count: (model: string, where: ReadonlyArray<AuthWhereClause>) => Promise<number>;
|
|
44
44
|
/** Insert `data` into `model`; return the stored row (the adapter pre-fills `id`). */
|
|
45
45
|
create: (model: string, data: AuthRow) => Promise<AuthRow>;
|
|
46
|
+
/**
|
|
47
|
+
* Atomically apply signed numeric deltas to **at most one** row in `model`
|
|
48
|
+
* matching `where`, then return the updated row (or `undefined` if the guard
|
|
49
|
+
* matched none). For each `increment` entry it applies `field = field + delta`
|
|
50
|
+
* (a negative delta decrements); the optional `set` map assigns absolute
|
|
51
|
+
* values in the same step. The `where` clause is both selector **and** guard
|
|
52
|
+
* — comparison operators are honoured, so a guard like
|
|
53
|
+
* `{ field: "count", operator: "lt", value: max }` only mutates the row while
|
|
54
|
+
* it still satisfies the predicate.
|
|
55
|
+
*
|
|
56
|
+
* Backs better-auth's durable (`storage: "database"`) rate limiter, whose
|
|
57
|
+
* counter rides these tables. Implementing it natively — one statement that
|
|
58
|
+
* guards, increments, and returns — gives the **one-winner-across-isolates**
|
|
59
|
+
* guarantee the read-then-update fallback cannot: on Workers two concurrent
|
|
60
|
+
* requests would otherwise both read `count=4` and both write `5`, letting a
|
|
61
|
+
* `max` of 5 pass 6+. Same race-closing rationale as {@link AuthStore.consumeOne}.
|
|
62
|
+
*/
|
|
63
|
+
incrementOne: (model: string, where: ReadonlyArray<AuthWhereClause>, increment: Record<string, number>, set?: AuthRow) => Promise<AuthRow | undefined>;
|
|
46
64
|
/** Read rows from `model` honouring the filter/sort/window in `query`. */
|
|
47
65
|
read: (model: string, query: AuthQuery) => Promise<AuthRow[]>;
|
|
48
66
|
/** Delete rows in `model` matching `where`; return how many were removed. */
|
package/dist/store.mjs
CHANGED
|
@@ -128,6 +128,19 @@ const createMemoryAuthStore = () => {
|
|
|
128
128
|
tableOf(model).push(row);
|
|
129
129
|
return Promise.resolve({ ...row });
|
|
130
130
|
},
|
|
131
|
+
incrementOne: (model, where, increment, set) => {
|
|
132
|
+
const row = tableOf(model).find((candidate) => matchesWhere(candidate, where));
|
|
133
|
+
if (!row) {
|
|
134
|
+
return Promise.resolve(void 0);
|
|
135
|
+
}
|
|
136
|
+
for (const [field, delta] of Object.entries(increment)) {
|
|
137
|
+
row[field] = (typeof row[field] === "number" ? row[field] : 0) + delta;
|
|
138
|
+
}
|
|
139
|
+
if (set) {
|
|
140
|
+
Object.assign(row, set);
|
|
141
|
+
}
|
|
142
|
+
return Promise.resolve({ ...row });
|
|
143
|
+
},
|
|
131
144
|
read: (model, query) => {
|
|
132
145
|
let rows = tableOf(model).filter((row) => matchesWhere(row, query.where));
|
|
133
146
|
if (query.sortBy) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lunora/auth",
|
|
3
|
-
"version": "1.0.0-alpha.
|
|
3
|
+
"version": "1.0.0-alpha.20",
|
|
4
4
|
"description": "Auth for Lunora — a thin better-auth wrapper: email/password, OAuth, plugins, D1-backed",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"auth",
|
|
@@ -25,7 +25,7 @@
|
|
|
25
25
|
"directory": "packages/auth"
|
|
26
26
|
},
|
|
27
27
|
"files": [
|
|
28
|
-
"dist",
|
|
28
|
+
"./dist",
|
|
29
29
|
"__assets__",
|
|
30
30
|
"README.md",
|
|
31
31
|
"LICENSE.md"
|
|
@@ -82,10 +82,11 @@
|
|
|
82
82
|
"access": "public"
|
|
83
83
|
},
|
|
84
84
|
"dependencies": {
|
|
85
|
-
"@better-auth/passkey": "^1.6.
|
|
86
|
-
"@lunora/
|
|
87
|
-
"@lunora/
|
|
88
|
-
"
|
|
85
|
+
"@better-auth/passkey": "^1.6.23",
|
|
86
|
+
"@lunora/errors": "1.0.0-alpha.1",
|
|
87
|
+
"@lunora/server": "1.0.0-alpha.16",
|
|
88
|
+
"@lunora/values": "1.0.0-alpha.4",
|
|
89
|
+
"better-auth": "^1.6.23"
|
|
89
90
|
},
|
|
90
91
|
"engines": {
|
|
91
92
|
"node": "^22.15.0 || >=24.11.0"
|
|
@@ -1,58 +0,0 @@
|
|
|
1
|
-
import { betterAuth, BetterAuthOptions } from 'better-auth';
|
|
2
|
-
/**
|
|
3
|
-
* Lunora's options pass straight through to better-auth — the only thing we add
|
|
4
|
-
* is requiring `secret` up front so a misconfigured deployment fails loudly
|
|
5
|
-
* instead of at the first sign-in.
|
|
6
|
-
*
|
|
7
|
-
* For `database`, prefer `lunoraD1Adapter` (`database: lunoraD1Adapter(env.DB)`)
|
|
8
|
-
* over passing the raw `env.DB`. better-auth *does* accept a D1Database directly,
|
|
9
|
-
* but it then resolves its Kysely adapter via a runtime `await import(...)` inside
|
|
10
|
-
* `auth.$context` — and that import never settles under `@cloudflare/vite-plugin`'s
|
|
11
|
-
* worker runner, hanging every auth request in `pnpm dev`. The explicit adapter
|
|
12
|
-
* skips it, so dev and prod behave the same. (Raw `env.DB` is still correct for
|
|
13
|
-
* the migration-only instance — see `lunoraD1Adapter`'s note.)
|
|
14
|
-
*
|
|
15
|
-
* Session rotation / richer session policies are configured via the `session`
|
|
16
|
-
* field (a `SessionPolicy`); Lunora validates it for obviously-broken
|
|
17
|
-
* durations and forwards it verbatim to better-auth. See `sessionPresets`
|
|
18
|
-
* for ready-made rotation/expiry trade-offs.
|
|
19
|
-
*
|
|
20
|
-
* ## Serverless background tasks (Cloudflare Workers)
|
|
21
|
-
*
|
|
22
|
-
* better-auth runs some work *after* sending the response — most importantly the
|
|
23
|
-
* password-reset email, whose background send is what keeps reset responses
|
|
24
|
-
* constant-time (a timing-attack defence: the response doesn't reveal whether
|
|
25
|
-
* the account exists). On Cloudflare Workers a promise that isn't handed to
|
|
26
|
-
* `ctx.waitUntil` can be cancelled the moment the response returns, dropping
|
|
27
|
-
* that send and weakening the guarantee. Wire your request's `ctx.waitUntil`
|
|
28
|
-
* into better-auth's background handler so the work survives:
|
|
29
|
-
*
|
|
30
|
-
* ```ts
|
|
31
|
-
* // in your worker fetch handler, where `ctx: ExecutionContext` is in scope
|
|
32
|
-
* const auth = createAuth({
|
|
33
|
-
* secret: env.AUTH_SECRET,
|
|
34
|
-
* database: lunoraD1Adapter(env.DB),
|
|
35
|
-
* advanced: {
|
|
36
|
-
* backgroundTasks: { handler: (promise) => ctx.waitUntil(promise) },
|
|
37
|
-
* },
|
|
38
|
-
* });
|
|
39
|
-
* ```
|
|
40
|
-
*
|
|
41
|
-
* (Lunora can't set this for you — `ctx.waitUntil` is per-request, but
|
|
42
|
-
* `createAuth` runs once at worker setup.)
|
|
43
|
-
*/
|
|
44
|
-
type LunoraAuthOptions = BetterAuthOptions;
|
|
45
|
-
/**
|
|
46
|
-
* The full better-auth instance: `auth.handler` accepts a `Request` and
|
|
47
|
-
* returns a `Response` (used by `handleAuthRequest`); `auth.api`
|
|
48
|
-
* exposes the typed endpoint surface for server-side calls (e.g.
|
|
49
|
-
* `auth.api.getSession({ headers })` inside a query/mutation).
|
|
50
|
-
*/
|
|
51
|
-
type LunoraAuth = ReturnType<typeof betterAuth>;
|
|
52
|
-
/**
|
|
53
|
-
* Create the auth instance. Thin wrapper around `betterAuth` that enforces
|
|
54
|
-
* the `secret` requirement at construction time so misconfigured deployments
|
|
55
|
-
* fail loudly at the first fetch rather than the first sign-in attempt.
|
|
56
|
-
*/
|
|
57
|
-
declare const createAuth: (options: LunoraAuthOptions) => LunoraAuth;
|
|
58
|
-
export { LunoraAuth as L, LunoraAuthOptions as a, createAuth as c };
|
|
@@ -1,58 +0,0 @@
|
|
|
1
|
-
import { betterAuth, BetterAuthOptions } from 'better-auth';
|
|
2
|
-
/**
|
|
3
|
-
* Lunora's options pass straight through to better-auth — the only thing we add
|
|
4
|
-
* is requiring `secret` up front so a misconfigured deployment fails loudly
|
|
5
|
-
* instead of at the first sign-in.
|
|
6
|
-
*
|
|
7
|
-
* For `database`, prefer `lunoraD1Adapter` (`database: lunoraD1Adapter(env.DB)`)
|
|
8
|
-
* over passing the raw `env.DB`. better-auth *does* accept a D1Database directly,
|
|
9
|
-
* but it then resolves its Kysely adapter via a runtime `await import(...)` inside
|
|
10
|
-
* `auth.$context` — and that import never settles under `@cloudflare/vite-plugin`'s
|
|
11
|
-
* worker runner, hanging every auth request in `pnpm dev`. The explicit adapter
|
|
12
|
-
* skips it, so dev and prod behave the same. (Raw `env.DB` is still correct for
|
|
13
|
-
* the migration-only instance — see `lunoraD1Adapter`'s note.)
|
|
14
|
-
*
|
|
15
|
-
* Session rotation / richer session policies are configured via the `session`
|
|
16
|
-
* field (a `SessionPolicy`); Lunora validates it for obviously-broken
|
|
17
|
-
* durations and forwards it verbatim to better-auth. See `sessionPresets`
|
|
18
|
-
* for ready-made rotation/expiry trade-offs.
|
|
19
|
-
*
|
|
20
|
-
* ## Serverless background tasks (Cloudflare Workers)
|
|
21
|
-
*
|
|
22
|
-
* better-auth runs some work *after* sending the response — most importantly the
|
|
23
|
-
* password-reset email, whose background send is what keeps reset responses
|
|
24
|
-
* constant-time (a timing-attack defence: the response doesn't reveal whether
|
|
25
|
-
* the account exists). On Cloudflare Workers a promise that isn't handed to
|
|
26
|
-
* `ctx.waitUntil` can be cancelled the moment the response returns, dropping
|
|
27
|
-
* that send and weakening the guarantee. Wire your request's `ctx.waitUntil`
|
|
28
|
-
* into better-auth's background handler so the work survives:
|
|
29
|
-
*
|
|
30
|
-
* ```ts
|
|
31
|
-
* // in your worker fetch handler, where `ctx: ExecutionContext` is in scope
|
|
32
|
-
* const auth = createAuth({
|
|
33
|
-
* secret: env.AUTH_SECRET,
|
|
34
|
-
* database: lunoraD1Adapter(env.DB),
|
|
35
|
-
* advanced: {
|
|
36
|
-
* backgroundTasks: { handler: (promise) => ctx.waitUntil(promise) },
|
|
37
|
-
* },
|
|
38
|
-
* });
|
|
39
|
-
* ```
|
|
40
|
-
*
|
|
41
|
-
* (Lunora can't set this for you — `ctx.waitUntil` is per-request, but
|
|
42
|
-
* `createAuth` runs once at worker setup.)
|
|
43
|
-
*/
|
|
44
|
-
type LunoraAuthOptions = BetterAuthOptions;
|
|
45
|
-
/**
|
|
46
|
-
* The full better-auth instance: `auth.handler` accepts a `Request` and
|
|
47
|
-
* returns a `Response` (used by `handleAuthRequest`); `auth.api`
|
|
48
|
-
* exposes the typed endpoint surface for server-side calls (e.g.
|
|
49
|
-
* `auth.api.getSession({ headers })` inside a query/mutation).
|
|
50
|
-
*/
|
|
51
|
-
type LunoraAuth = ReturnType<typeof betterAuth>;
|
|
52
|
-
/**
|
|
53
|
-
* Create the auth instance. Thin wrapper around `betterAuth` that enforces
|
|
54
|
-
* the `secret` requirement at construction time so misconfigured deployments
|
|
55
|
-
* fail loudly at the first fetch rather than the first sign-in attempt.
|
|
56
|
-
*/
|
|
57
|
-
declare const createAuth: (options: LunoraAuthOptions) => LunoraAuth;
|
|
58
|
-
export { LunoraAuth as L, LunoraAuthOptions as a, createAuth as c };
|