bezzie 0.2.2 → 1.0.0

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/README.md CHANGED
@@ -1,12 +1,12 @@
1
1
  # Bezzie
2
2
 
3
- **Bezzie** — your BFF's BFF. Handles the Backend for Frontend OAuth pattern so you don't have to.
4
-
5
3
  [![npm downloads](https://img.shields.io/npm/dw/bezzie)](https://www.npmjs.com/package/bezzie)
6
4
 
7
- A BFF (Backend for Frontend) OAuth 2.0 auth library for Cloudflare Workers.
5
+ > Bezzie is a BFF (Backend for Frontend) OAuth 2.0 library for Cloudflare Workers. It implements [BCP212](https://datatracker.ietf.org/doc/html/draft-ietf-oauth-browser-based-apps) — your frontend never sees a JWT.
6
+
7
+ **Bezzie** — your BFF's BFF. Handles the Backend for Frontend OAuth pattern so you don't have to.
8
8
 
9
- Implements the [OAuth 2.0 for Browser-Based Apps (BCP212)](https://datatracker.ietf.org/doc/html/draft-ietf-oauth-browser-based-apps) pattern — JWTs never touch the browser. The BFF owns the OAuth flow and issues a session cookie to the frontend instead.
9
+ The BFF owns the OAuth flow and issues a session cookie to the frontend instead of handing tokens to the browser.
10
10
 
11
11
  ```
12
12
  npm install bezzie
@@ -33,13 +33,13 @@ wrangler secret put AUTH0_CLIENT_SECRET
33
33
 
34
34
  **4. Wire it up:**
35
35
  ```typescript
36
- import { createBezzie, providers, cloudflareKV } from 'bezzie'
36
+ import { createBezzie, providers, cloudflareKVAdapter } from 'bezzie'
37
37
 
38
38
  const auth = createBezzie({
39
39
  ...providers.auth0('your-tenant.auth0.com'),
40
40
  clientId: 'xxx',
41
41
  clientSecret: env.AUTH0_CLIENT_SECRET,
42
- adapter: cloudflareKV(env.SESSION_KV),
42
+ adapter: cloudflareKVAdapter(env.SESSION_KV),
43
43
  baseUrl: 'https://app.yourproject.com',
44
44
  })
45
45
 
@@ -75,14 +75,14 @@ There's no open source library for this specific combination (BFF OAuth on Cloud
75
75
  ## Usage
76
76
 
77
77
  ```typescript
78
- import { createBezzie, providers, cloudflareKV } from 'bezzie'
78
+ import { createBezzie, providers, cloudflareKVAdapter } from 'bezzie'
79
79
 
80
80
  const auth = createBezzie({
81
81
  ...providers.auth0('your-tenant.auth0.com'),
82
82
  clientId: 'xxx',
83
83
  clientSecret: env.AUTH0_CLIENT_SECRET,
84
84
  audience: 'https://api.yourproject.com',
85
- adapter: cloudflareKV(env.SESSION_KV),
85
+ adapter: cloudflareKVAdapter(env.SESSION_KV),
86
86
  baseUrl: 'https://app.yourproject.com',
87
87
  })
88
88
 
@@ -193,17 +193,22 @@ Bezzie supports multiple session storage backends:
193
193
  ### Cloudflare KV
194
194
  Recommended for production on Cloudflare Workers.
195
195
  ```typescript
196
- import { cloudflareKV } from 'bezzie'
196
+ import { cloudflareKVAdapter } from 'bezzie'
197
197
  // ...
198
- adapter: cloudflareKV(env.SESSION_KV)
198
+ adapter: cloudflareKVAdapter(env.SESSION_KV)
199
199
  ```
200
200
 
201
201
  ### Redis (Upstash)
202
- Good for cross-region session consistency.
202
+ Good for cross-region session consistency. Works with [Upstash Redis](https://upstash.com) (recommended for Cloudflare Workers) and any Redis client with `get`/`set`/`del` methods.
203
+
203
204
  ```typescript
204
- import { RedisAdapter } from 'bezzie'
205
- // ...
206
- adapter: new RedisAdapter({ url: env.REDIS_URL, token: env.REDIS_TOKEN })
205
+ import { redisAdapter } from 'bezzie'
206
+ import { Redis } from '@upstash/redis/cloudflare'
207
+
208
+ adapter: redisAdapter(new Redis({
209
+ url: env.UPSTASH_REDIS_REST_URL,
210
+ token: env.UPSTASH_REDIS_REST_TOKEN,
211
+ }))
207
212
  ```
208
213
 
209
214
  ### Memory
@@ -224,9 +229,9 @@ adapter: new MemoryAdapter()
224
229
  | `clientId` | `string` | OAuth client ID |
225
230
  | `clientSecret` | `string` | OAuth client secret — keep in Workers secrets |
226
231
  | `audience` | `string` | API audience identifier |
227
- | `adapter` | `SessionAdapter` | Session adapter (e.g. `cloudflareKV(env.SESSION_KV)`) |
232
+ | `adapter` | `SessionAdapter` | Session adapter (e.g. `cloudflareKVAdapter(env.SESSION_KV)`) |
228
233
  | `baseUrl` | `string` | Base URL of your application (used for callback and redirects) |
229
- | `providerHints` | `object` | Optional tweaks for specific providers (`logoutUrl`, `tokenEndpoint`) |
234
+ | `providerOverrides` | `object` | Hard overrides for specific provider values (`logoutUrl`, `tokenEndpoint`) |
230
235
 
231
236
  ---
232
237
 
@@ -248,6 +253,20 @@ wrangler secret put AUTH0_CLIENT_SECRET
248
253
 
249
254
  ---
250
255
 
256
+ ## Alternatives
257
+
258
+ | | Bezzie | Auth.js (NextAuth) | Lucia | Roll your own (oauth4webapi) |
259
+ |---|---|---|---|---|
260
+ | BFF pattern (tokens never in browser) | ✅ | ✅ (some adapters) | ❌ | You decide |
261
+ | Cloudflare Workers native | ✅ | ⚠️ Edge adapter | ⚠️ | ✅ |
262
+ | Hono integration | ✅ | ❌ | ❌ | ✅ |
263
+ | OIDC discovery | ✅ | ✅ | ❌ | ✅ |
264
+ | Token refresh | ✅ | ✅ | Manual | Manual |
265
+ | Pluggable session storage | ✅ (KV, Redis, Memory) | ✅ | ✅ | Manual |
266
+ | Zero Node.js deps | ✅ | ❌ | ✅ | ✅ |
267
+
268
+ ---
269
+
251
270
  ## Stack
252
271
 
253
272
  | Component | Choice |
@@ -265,6 +284,12 @@ v0.1.0 — pre-release
265
284
 
266
285
  ---
267
286
 
287
+ ## Changelog
288
+
289
+ See [CHANGELOG.md](CHANGELOG.md) for release history.
290
+
291
+ ---
292
+
268
293
  ## License
269
294
 
270
295
  MIT
@@ -1,5 +1,5 @@
1
1
  import { Session } from '../session';
2
- import { PKCEState, SessionAdapter } from './types';
2
+ import { PKCEState, SessionAdapter, SessionAdapterFactory } from './types';
3
3
  export declare class CloudflareKVAdapter<TUser extends Record<string, unknown> = Record<string, unknown>> implements SessionAdapter<TUser> {
4
4
  private kv;
5
5
  constructor(kv: KVNamespace);
@@ -7,4 +7,8 @@ export declare class CloudflareKVAdapter<TUser extends Record<string, unknown> =
7
7
  set(sessionId: string, session: Session<TUser> | PKCEState, ttlSeconds: number): Promise<void>;
8
8
  delete(sessionId: string): Promise<void>;
9
9
  }
10
+ /**
11
+ * Creates a Cloudflare KV session adapter factory.
12
+ */
13
+ export declare function cloudflareKVAdapter(kv: KVNamespace): SessionAdapterFactory;
10
14
  //# sourceMappingURL=cloudflare-kv.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"cloudflare-kv.d.ts","sourceRoot":"","sources":["../../src/adapters/cloudflare-kv.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,YAAY,CAAA;AACpC,OAAO,EAAE,SAAS,EAAE,cAAc,EAAE,MAAM,SAAS,CAAA;AAEnD,qBAAa,mBAAmB,CAAC,KAAK,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAC9F,YAAW,cAAc,CAAC,KAAK,CAAC;IAEpB,OAAO,CAAC,EAAE;gBAAF,EAAE,EAAE,WAAW;IAE7B,GAAG,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,KAAK,CAAC,GAAG,SAAS,GAAG,IAAI,CAAC;IAIlE,GAAG,CACP,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,OAAO,CAAC,KAAK,CAAC,GAAG,SAAS,EACnC,UAAU,EAAE,MAAM,GACjB,OAAO,CAAC,IAAI,CAAC;IASV,MAAM,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;CAG/C"}
1
+ {"version":3,"file":"cloudflare-kv.d.ts","sourceRoot":"","sources":["../../src/adapters/cloudflare-kv.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,YAAY,CAAA;AACpC,OAAO,EAAE,SAAS,EAAE,cAAc,EAAE,qBAAqB,EAAE,MAAM,SAAS,CAAA;AAG1E,qBAAa,mBAAmB,CAAC,KAAK,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAC9F,YAAW,cAAc,CAAC,KAAK,CAAC;IAEpB,OAAO,CAAC,EAAE;gBAAF,EAAE,EAAE,WAAW;IAE7B,GAAG,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,KAAK,CAAC,GAAG,SAAS,GAAG,IAAI,CAAC;IAIlE,GAAG,CACP,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,OAAO,CAAC,KAAK,CAAC,GAAG,SAAS,EACnC,UAAU,EAAE,MAAM,GACjB,OAAO,CAAC,IAAI,CAAC;IAYV,MAAM,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;CAG/C;AAED;;GAEG;AACH,wBAAgB,mBAAmB,CAAC,EAAE,EAAE,WAAW,GAAG,qBAAqB,CAG1E"}
@@ -1,3 +1,4 @@
1
+ import { SessionStoreError } from '../errors';
1
2
  export class CloudflareKVAdapter {
2
3
  kv;
3
4
  constructor(kv) {
@@ -8,7 +9,7 @@ export class CloudflareKVAdapter {
8
9
  }
9
10
  async set(sessionId, session, ttlSeconds) {
10
11
  if (ttlSeconds < 60) {
11
- throw new Error('Bezzie: KV TTL must be at least 60 seconds');
12
+ throw new SessionStoreError('session_storage_failed', 'Bezzie: KV TTL must be at least 60 seconds');
12
13
  }
13
14
  await this.kv.put(sessionId, JSON.stringify(session), {
14
15
  expirationTtl: ttlSeconds,
@@ -18,4 +19,10 @@ export class CloudflareKVAdapter {
18
19
  await this.kv.delete(sessionId);
19
20
  }
20
21
  }
22
+ /**
23
+ * Creates a Cloudflare KV session adapter factory.
24
+ */
25
+ export function cloudflareKVAdapter(kv) {
26
+ return () => new CloudflareKVAdapter(kv);
27
+ }
21
28
  //# sourceMappingURL=cloudflare-kv.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"cloudflare-kv.js","sourceRoot":"","sources":["../../src/adapters/cloudflare-kv.ts"],"names":[],"mappings":"AAGA,MAAM,OAAO,mBAAmB;IAGV;IAApB,YAAoB,EAAe;QAAf,OAAE,GAAF,EAAE,CAAa;IAAG,CAAC;IAEvC,KAAK,CAAC,GAAG,CAAC,SAAiB;QACzB,OAAO,MAAM,IAAI,CAAC,EAAE,CAAC,GAAG,CAA6B,SAAS,EAAE,MAAM,CAAC,CAAA;IACzE,CAAC;IAED,KAAK,CAAC,GAAG,CACP,SAAiB,EACjB,OAAmC,EACnC,UAAkB;QAElB,IAAI,UAAU,GAAG,EAAE,EAAE,CAAC;YACpB,MAAM,IAAI,KAAK,CAAC,4CAA4C,CAAC,CAAA;QAC/D,CAAC;QACD,MAAM,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,SAAS,EAAE,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,EAAE;YACpD,aAAa,EAAE,UAAU;SAC1B,CAAC,CAAA;IACJ,CAAC;IAED,KAAK,CAAC,MAAM,CAAC,SAAiB;QAC5B,MAAM,IAAI,CAAC,EAAE,CAAC,MAAM,CAAC,SAAS,CAAC,CAAA;IACjC,CAAC;CACF"}
1
+ {"version":3,"file":"cloudflare-kv.js","sourceRoot":"","sources":["../../src/adapters/cloudflare-kv.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,iBAAiB,EAAE,MAAM,WAAW,CAAA;AAE7C,MAAM,OAAO,mBAAmB;IAGV;IAApB,YAAoB,EAAe;QAAf,OAAE,GAAF,EAAE,CAAa;IAAG,CAAC;IAEvC,KAAK,CAAC,GAAG,CAAC,SAAiB;QACzB,OAAO,MAAM,IAAI,CAAC,EAAE,CAAC,GAAG,CAA6B,SAAS,EAAE,MAAM,CAAC,CAAA;IACzE,CAAC;IAED,KAAK,CAAC,GAAG,CACP,SAAiB,EACjB,OAAmC,EACnC,UAAkB;QAElB,IAAI,UAAU,GAAG,EAAE,EAAE,CAAC;YACpB,MAAM,IAAI,iBAAiB,CACzB,wBAAwB,EACxB,4CAA4C,CAC7C,CAAA;QACH,CAAC;QACD,MAAM,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,SAAS,EAAE,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,EAAE;YACpD,aAAa,EAAE,UAAU;SAC1B,CAAC,CAAA;IACJ,CAAC;IAED,KAAK,CAAC,MAAM,CAAC,SAAiB;QAC5B,MAAM,IAAI,CAAC,EAAE,CAAC,MAAM,CAAC,SAAS,CAAC,CAAA;IACjC,CAAC;CACF;AAED;;GAEG;AACH,MAAM,UAAU,mBAAmB,CAAC,EAAe;IACjD,OAAO,GAA2F,EAAE,CAClG,IAAI,mBAAmB,CAAQ,EAAE,CAAC,CAAA;AACtC,CAAC"}
@@ -1,9 +1,25 @@
1
1
  import { Session } from '../session';
2
- import { SessionAdapter, PKCEState } from './types';
2
+ import { SessionAdapter, SessionAdapterFactory, PKCEState } from './types';
3
3
  export declare class MemoryAdapter<TUser extends Record<string, unknown> = Record<string, unknown>> implements SessionAdapter<TUser> {
4
4
  private store;
5
+ private lastCleanup;
6
+ private static readonly CLEANUP_INTERVAL_MS;
7
+ /**
8
+ * Evicts all entries whose TTL has expired.
9
+ *
10
+ * Workers runtimes don't support long-lived timers (`setInterval`), so rather
11
+ * than scheduling cleanup we trigger it opportunistically from `get()` at
12
+ * most once every `CLEANUP_INTERVAL_MS`. This bounds memory growth for
13
+ * long-running processes (e.g. local dev, tests) without adding overhead to
14
+ * every read.
15
+ */
16
+ cleanup(): void;
5
17
  get(sessionId: string): Promise<Session<TUser> | PKCEState | null>;
6
18
  set(sessionId: string, session: Session<TUser> | PKCEState, ttlSeconds: number): Promise<void>;
7
19
  delete(sessionId: string): Promise<void>;
8
20
  }
21
+ /**
22
+ * Creates an in-memory session adapter factory. Useful for tests and local dev.
23
+ */
24
+ export declare function memoryAdapter(): SessionAdapterFactory;
9
25
  //# sourceMappingURL=memory.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"memory.d.ts","sourceRoot":"","sources":["../../src/adapters/memory.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,YAAY,CAAA;AACpC,OAAO,EAAE,cAAc,EAAE,SAAS,EAAE,MAAM,SAAS,CAAA;AAOnD,qBAAa,aAAa,CAAC,KAAK,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CACxF,YAAW,cAAc,CAAC,KAAK,CAAC;IAEhC,OAAO,CAAC,KAAK,CAA0C;IAEjD,GAAG,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,KAAK,CAAC,GAAG,SAAS,GAAG,IAAI,CAAC;IAUlE,GAAG,CACP,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,OAAO,CAAC,KAAK,CAAC,GAAG,SAAS,EACnC,UAAU,EAAE,MAAM,GACjB,OAAO,CAAC,IAAI,CAAC;IAOV,MAAM,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;CAG/C"}
1
+ {"version":3,"file":"memory.d.ts","sourceRoot":"","sources":["../../src/adapters/memory.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,YAAY,CAAA;AACpC,OAAO,EAAE,cAAc,EAAE,qBAAqB,EAAE,SAAS,EAAE,MAAM,SAAS,CAAA;AAO1E,qBAAa,aAAa,CAAC,KAAK,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CACxF,YAAW,cAAc,CAAC,KAAK,CAAC;IAEhC,OAAO,CAAC,KAAK,CAA0C;IACvD,OAAO,CAAC,WAAW,CAAI;IACvB,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,mBAAmB,CAAS;IAEpD;;;;;;;;OAQG;IACH,OAAO,IAAI,IAAI;IAUT,GAAG,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,KAAK,CAAC,GAAG,SAAS,GAAG,IAAI,CAAC;IAgBlE,GAAG,CACP,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,OAAO,CAAC,KAAK,CAAC,GAAG,SAAS,EACnC,UAAU,EAAE,MAAM,GACjB,OAAO,CAAC,IAAI,CAAC;IAOV,MAAM,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;CAG/C;AAED;;GAEG;AACH,wBAAgB,aAAa,IAAI,qBAAqB,CAGrD"}
@@ -1,10 +1,35 @@
1
1
  export class MemoryAdapter {
2
2
  store = new Map();
3
+ lastCleanup = 0;
4
+ static CLEANUP_INTERVAL_MS = 60_000;
5
+ /**
6
+ * Evicts all entries whose TTL has expired.
7
+ *
8
+ * Workers runtimes don't support long-lived timers (`setInterval`), so rather
9
+ * than scheduling cleanup we trigger it opportunistically from `get()` at
10
+ * most once every `CLEANUP_INTERVAL_MS`. This bounds memory growth for
11
+ * long-running processes (e.g. local dev, tests) without adding overhead to
12
+ * every read.
13
+ */
14
+ cleanup() {
15
+ const now = Date.now();
16
+ for (const [id, entry] of this.store) {
17
+ if (now > entry.expiresAt) {
18
+ this.store.delete(id);
19
+ }
20
+ }
21
+ this.lastCleanup = now;
22
+ }
3
23
  async get(sessionId) {
24
+ // Proactive TTL eviction (C6): run at most once per CLEANUP_INTERVAL_MS.
25
+ const now = Date.now();
26
+ if (now - this.lastCleanup > MemoryAdapter.CLEANUP_INTERVAL_MS) {
27
+ this.cleanup();
28
+ }
4
29
  const entry = this.store.get(sessionId);
5
30
  if (!entry)
6
31
  return null;
7
- if (Date.now() > entry.expiresAt) {
32
+ if (now > entry.expiresAt) {
8
33
  this.store.delete(sessionId);
9
34
  return null;
10
35
  }
@@ -20,4 +45,10 @@ export class MemoryAdapter {
20
45
  this.store.delete(sessionId);
21
46
  }
22
47
  }
48
+ /**
49
+ * Creates an in-memory session adapter factory. Useful for tests and local dev.
50
+ */
51
+ export function memoryAdapter() {
52
+ return () => new MemoryAdapter();
53
+ }
23
54
  //# sourceMappingURL=memory.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"memory.js","sourceRoot":"","sources":["../../src/adapters/memory.ts"],"names":[],"mappings":"AAQA,MAAM,OAAO,aAAa;IAGhB,KAAK,GAAG,IAAI,GAAG,EAAgC,CAAA;IAEvD,KAAK,CAAC,GAAG,CAAC,SAAiB;QACzB,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,SAAS,CAAC,CAAA;QACvC,IAAI,CAAC,KAAK;YAAE,OAAO,IAAI,CAAA;QACvB,IAAI,IAAI,CAAC,GAAG,EAAE,GAAG,KAAK,CAAC,SAAS,EAAE,CAAC;YACjC,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,SAAS,CAAC,CAAA;YAC5B,OAAO,IAAI,CAAA;QACb,CAAC;QACD,OAAO,KAAK,CAAC,OAAO,CAAA;IACtB,CAAC;IAED,KAAK,CAAC,GAAG,CACP,SAAiB,EACjB,OAAmC,EACnC,UAAkB;QAElB,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,SAAS,EAAE;YACxB,OAAO;YACP,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE,GAAG,UAAU,GAAG,IAAI;SAC1C,CAAC,CAAA;IACJ,CAAC;IAED,KAAK,CAAC,MAAM,CAAC,SAAiB;QAC5B,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,SAAS,CAAC,CAAA;IAC9B,CAAC;CACF"}
1
+ {"version":3,"file":"memory.js","sourceRoot":"","sources":["../../src/adapters/memory.ts"],"names":[],"mappings":"AAQA,MAAM,OAAO,aAAa;IAGhB,KAAK,GAAG,IAAI,GAAG,EAAgC,CAAA;IAC/C,WAAW,GAAG,CAAC,CAAA;IACf,MAAM,CAAU,mBAAmB,GAAG,MAAM,CAAA;IAEpD;;;;;;;;OAQG;IACH,OAAO;QACL,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,CAAA;QACtB,KAAK,MAAM,CAAC,EAAE,EAAE,KAAK,CAAC,IAAI,IAAI,CAAC,KAAK,EAAE,CAAC;YACrC,IAAI,GAAG,GAAG,KAAK,CAAC,SAAS,EAAE,CAAC;gBAC1B,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,EAAE,CAAC,CAAA;YACvB,CAAC;QACH,CAAC;QACD,IAAI,CAAC,WAAW,GAAG,GAAG,CAAA;IACxB,CAAC;IAED,KAAK,CAAC,GAAG,CAAC,SAAiB;QACzB,yEAAyE;QACzE,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,CAAA;QACtB,IAAI,GAAG,GAAG,IAAI,CAAC,WAAW,GAAG,aAAa,CAAC,mBAAmB,EAAE,CAAC;YAC/D,IAAI,CAAC,OAAO,EAAE,CAAA;QAChB,CAAC;QAED,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,SAAS,CAAC,CAAA;QACvC,IAAI,CAAC,KAAK;YAAE,OAAO,IAAI,CAAA;QACvB,IAAI,GAAG,GAAG,KAAK,CAAC,SAAS,EAAE,CAAC;YAC1B,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,SAAS,CAAC,CAAA;YAC5B,OAAO,IAAI,CAAA;QACb,CAAC;QACD,OAAO,KAAK,CAAC,OAAO,CAAA;IACtB,CAAC;IAED,KAAK,CAAC,GAAG,CACP,SAAiB,EACjB,OAAmC,EACnC,UAAkB;QAElB,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,SAAS,EAAE;YACxB,OAAO;YACP,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE,GAAG,UAAU,GAAG,IAAI;SAC1C,CAAC,CAAA;IACJ,CAAC;IAED,KAAK,CAAC,MAAM,CAAC,SAAiB;QAC5B,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,SAAS,CAAC,CAAA;IAC9B,CAAC;;AAGH;;GAEG;AACH,MAAM,UAAU,aAAa;IAC3B,OAAO,GAA2F,EAAE,CAClG,IAAI,aAAa,EAAS,CAAA;AAC9B,CAAC"}
@@ -1,5 +1,5 @@
1
1
  import { Session } from '../session';
2
- import { SessionAdapter, PKCEState } from './types';
2
+ import { SessionAdapter, SessionAdapterFactory, PKCEState } from './types';
3
3
  export interface RedisClient {
4
4
  get(key: string): Promise<string | null>;
5
5
  set(key: string, value: string, options?: {
@@ -7,6 +7,24 @@ export interface RedisClient {
7
7
  }): Promise<unknown>;
8
8
  del(key: string): Promise<unknown>;
9
9
  }
10
+ /**
11
+ * Redis-backed session adapter.
12
+ *
13
+ * Compatible with any Redis client that implements the {@link RedisClient} interface,
14
+ * including [Upstash Redis](https://upstash.com) — the recommended choice for Cloudflare Workers
15
+ * because it communicates over HTTP rather than TCP.
16
+ *
17
+ * @example
18
+ * ```typescript
19
+ * import { redisAdapter } from 'bezzie'
20
+ * import { Redis } from '@upstash/redis/cloudflare'
21
+ *
22
+ * adapter: redisAdapter(new Redis({
23
+ * url: env.UPSTASH_REDIS_REST_URL,
24
+ * token: env.UPSTASH_REDIS_REST_TOKEN,
25
+ * }))
26
+ * ```
27
+ */
10
28
  export declare class RedisAdapter<TUser extends Record<string, unknown> = Record<string, unknown>> implements SessionAdapter<TUser> {
11
29
  private redis;
12
30
  constructor(redis: RedisClient);
@@ -14,4 +32,23 @@ export declare class RedisAdapter<TUser extends Record<string, unknown> = Record
14
32
  set(sessionId: string, session: Session<TUser> | PKCEState, ttlSeconds: number): Promise<void>;
15
33
  delete(sessionId: string): Promise<void>;
16
34
  }
35
+ /**
36
+ * Creates a Redis-backed session adapter factory.
37
+ *
38
+ * Accepts any client that satisfies the {@link RedisClient} interface, including
39
+ * [Upstash Redis](https://upstash.com) (`@upstash/redis/cloudflare`) — recommended for
40
+ * Cloudflare Workers because it uses the Upstash REST API over HTTP rather than a TCP socket.
41
+ *
42
+ * @example
43
+ * ```typescript
44
+ * import { redisAdapter } from 'bezzie'
45
+ * import { Redis } from '@upstash/redis/cloudflare'
46
+ *
47
+ * adapter: redisAdapter(new Redis({
48
+ * url: env.UPSTASH_REDIS_REST_URL,
49
+ * token: env.UPSTASH_REDIS_REST_TOKEN,
50
+ * }))
51
+ * ```
52
+ */
53
+ export declare function redisAdapter(client: RedisClient): SessionAdapterFactory;
17
54
  //# sourceMappingURL=redis.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"redis.d.ts","sourceRoot":"","sources":["../../src/adapters/redis.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,YAAY,CAAA;AACpC,OAAO,EAAE,cAAc,EAAE,SAAS,EAAE,MAAM,SAAS,CAAA;AAEnD,MAAM,WAAW,WAAW;IAC1B,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAAA;IACxC,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE;QAAE,EAAE,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC,OAAO,CAAC,CAAA;IAC5E,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAA;CACnC;AAED,qBAAa,YAAY,CAAC,KAAK,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CACvF,YAAW,cAAc,CAAC,KAAK,CAAC;IAEpB,OAAO,CAAC,KAAK;gBAAL,KAAK,EAAE,WAAW;IAEhC,GAAG,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,KAAK,CAAC,GAAG,SAAS,GAAG,IAAI,CAAC;IAMlE,GAAG,CACP,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,OAAO,CAAC,KAAK,CAAC,GAAG,SAAS,EACnC,UAAU,EAAE,MAAM,GACjB,OAAO,CAAC,IAAI,CAAC;IAIV,MAAM,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;CAG/C"}
1
+ {"version":3,"file":"redis.d.ts","sourceRoot":"","sources":["../../src/adapters/redis.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,YAAY,CAAA;AACpC,OAAO,EAAE,cAAc,EAAE,qBAAqB,EAAE,SAAS,EAAE,MAAM,SAAS,CAAA;AAE1E,MAAM,WAAW,WAAW;IAC1B,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAAA;IACxC,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE;QAAE,EAAE,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC,OAAO,CAAC,CAAA;IAC5E,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAA;CACnC;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,qBAAa,YAAY,CAAC,KAAK,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CACvF,YAAW,cAAc,CAAC,KAAK,CAAC;IAEpB,OAAO,CAAC,KAAK;gBAAL,KAAK,EAAE,WAAW;IAEhC,GAAG,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,KAAK,CAAC,GAAG,SAAS,GAAG,IAAI,CAAC;IAMlE,GAAG,CACP,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,OAAO,CAAC,KAAK,CAAC,GAAG,SAAS,EACnC,UAAU,EAAE,MAAM,GACjB,OAAO,CAAC,IAAI,CAAC;IAIV,MAAM,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;CAG/C;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,YAAY,CAAC,MAAM,EAAE,WAAW,GAAG,qBAAqB,CAGvE"}
@@ -1,3 +1,21 @@
1
+ /**
2
+ * Redis-backed session adapter.
3
+ *
4
+ * Compatible with any Redis client that implements the {@link RedisClient} interface,
5
+ * including [Upstash Redis](https://upstash.com) — the recommended choice for Cloudflare Workers
6
+ * because it communicates over HTTP rather than TCP.
7
+ *
8
+ * @example
9
+ * ```typescript
10
+ * import { redisAdapter } from 'bezzie'
11
+ * import { Redis } from '@upstash/redis/cloudflare'
12
+ *
13
+ * adapter: redisAdapter(new Redis({
14
+ * url: env.UPSTASH_REDIS_REST_URL,
15
+ * token: env.UPSTASH_REDIS_REST_TOKEN,
16
+ * }))
17
+ * ```
18
+ */
1
19
  export class RedisAdapter {
2
20
  redis;
3
21
  constructor(redis) {
@@ -16,4 +34,25 @@ export class RedisAdapter {
16
34
  await this.redis.del(sessionId);
17
35
  }
18
36
  }
37
+ /**
38
+ * Creates a Redis-backed session adapter factory.
39
+ *
40
+ * Accepts any client that satisfies the {@link RedisClient} interface, including
41
+ * [Upstash Redis](https://upstash.com) (`@upstash/redis/cloudflare`) — recommended for
42
+ * Cloudflare Workers because it uses the Upstash REST API over HTTP rather than a TCP socket.
43
+ *
44
+ * @example
45
+ * ```typescript
46
+ * import { redisAdapter } from 'bezzie'
47
+ * import { Redis } from '@upstash/redis/cloudflare'
48
+ *
49
+ * adapter: redisAdapter(new Redis({
50
+ * url: env.UPSTASH_REDIS_REST_URL,
51
+ * token: env.UPSTASH_REDIS_REST_TOKEN,
52
+ * }))
53
+ * ```
54
+ */
55
+ export function redisAdapter(client) {
56
+ return () => new RedisAdapter(client);
57
+ }
19
58
  //# sourceMappingURL=redis.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"redis.js","sourceRoot":"","sources":["../../src/adapters/redis.ts"],"names":[],"mappings":"AASA,MAAM,OAAO,YAAY;IAGH;IAApB,YAAoB,KAAkB;QAAlB,UAAK,GAAL,KAAK,CAAa;IAAG,CAAC;IAE1C,KAAK,CAAC,GAAG,CAAC,SAAiB;QACzB,MAAM,OAAO,GAAG,MAAM,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,SAAS,CAAC,CAAA;QAC/C,IAAI,CAAC,OAAO;YAAE,OAAO,IAAI,CAAA;QACzB,OAAO,IAAI,CAAC,KAAK,CAAC,OAAO,CAA+B,CAAA;IAC1D,CAAC;IAED,KAAK,CAAC,GAAG,CACP,SAAiB,EACjB,OAAmC,EACnC,UAAkB;QAElB,MAAM,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,SAAS,EAAE,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,EAAE,EAAE,EAAE,EAAE,UAAU,EAAE,CAAC,CAAA;IAC9E,CAAC;IAED,KAAK,CAAC,MAAM,CAAC,SAAiB;QAC5B,MAAM,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,SAAS,CAAC,CAAA;IACjC,CAAC;CACF"}
1
+ {"version":3,"file":"redis.js","sourceRoot":"","sources":["../../src/adapters/redis.ts"],"names":[],"mappings":"AASA;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,OAAO,YAAY;IAGH;IAApB,YAAoB,KAAkB;QAAlB,UAAK,GAAL,KAAK,CAAa;IAAG,CAAC;IAE1C,KAAK,CAAC,GAAG,CAAC,SAAiB;QACzB,MAAM,OAAO,GAAG,MAAM,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,SAAS,CAAC,CAAA;QAC/C,IAAI,CAAC,OAAO;YAAE,OAAO,IAAI,CAAA;QACzB,OAAO,IAAI,CAAC,KAAK,CAAC,OAAO,CAA+B,CAAA;IAC1D,CAAC;IAED,KAAK,CAAC,GAAG,CACP,SAAiB,EACjB,OAAmC,EACnC,UAAkB;QAElB,MAAM,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,SAAS,EAAE,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,EAAE,EAAE,EAAE,EAAE,UAAU,EAAE,CAAC,CAAA;IAC9E,CAAC;IAED,KAAK,CAAC,MAAM,CAAC,SAAiB;QAC5B,MAAM,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,SAAS,CAAC,CAAA;IACjC,CAAC;CACF;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,UAAU,YAAY,CAAC,MAAmB;IAC9C,OAAO,GAA2F,EAAE,CAClG,IAAI,YAAY,CAAQ,MAAM,CAAC,CAAA;AACnC,CAAC"}
@@ -20,6 +20,12 @@ export interface PKCEState {
20
20
  * Used to prevent login-CSRF attacks (S4).
21
21
  */
22
22
  csrfToken: string;
23
+ /**
24
+ * OIDC `nonce` value. Generated at `/login`, passed in the authorization
25
+ * request, and verified against the `nonce` claim of the returned ID token
26
+ * at `/callback` to prevent ID token replay attacks (S8).
27
+ */
28
+ nonce: string;
23
29
  }
24
30
  /**
25
31
  * Interface for session storage adapters.
@@ -47,4 +53,12 @@ export interface SessionAdapter<TUser extends Record<string, unknown> = Record<s
47
53
  */
48
54
  delete(sessionId: string): Promise<void>;
49
55
  }
56
+ /**
57
+ * Factory function that produces a {@link SessionAdapter} for a given `TUser`.
58
+ *
59
+ * Consumers construct adapters via the factory form (e.g. `memoryAdapter()`,
60
+ * `cloudflareKVAdapter(env.SESSION_KV)`) so `TUser` is inferred from
61
+ * `createBezzie<TUser>(...)` rather than needing to be specified twice.
62
+ */
63
+ export type SessionAdapterFactory = <TUser extends Record<string, unknown> = Record<string, unknown>>() => SessionAdapter<TUser>;
50
64
  //# sourceMappingURL=types.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/adapters/types.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,YAAY,CAAA;AAEpC;;GAEG;AACH,MAAM,WAAW,SAAS;IACxB;;OAEG;IACH,KAAK,EAAE,MAAM,CAAA;IACb;;OAEG;IACH,YAAY,EAAE,MAAM,CAAA;IACpB;;OAEG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB;;;OAGG;IACH,SAAS,EAAE,MAAM,CAAA;CAClB;AAED;;GAEG;AACH,MAAM,WAAW,cAAc,CAAC,KAAK,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;IAC7F;;;;;OAKG;IACH,GAAG,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,KAAK,CAAC,GAAG,SAAS,GAAG,IAAI,CAAC,CAAA;IAElE;;;;;;OAMG;IACH,GAAG,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,CAAC,KAAK,CAAC,GAAG,SAAS,EAAE,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;IAE9F;;;;OAIG;IACH,MAAM,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;CACzC"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/adapters/types.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,YAAY,CAAA;AAEpC;;GAEG;AACH,MAAM,WAAW,SAAS;IACxB;;OAEG;IACH,KAAK,EAAE,MAAM,CAAA;IACb;;OAEG;IACH,YAAY,EAAE,MAAM,CAAA;IACpB;;OAEG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB;;;OAGG;IACH,SAAS,EAAE,MAAM,CAAA;IACjB;;;;OAIG;IACH,KAAK,EAAE,MAAM,CAAA;CACd;AAED;;GAEG;AACH,MAAM,WAAW,cAAc,CAAC,KAAK,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;IAC7F;;;;;OAKG;IACH,GAAG,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,KAAK,CAAC,GAAG,SAAS,GAAG,IAAI,CAAC,CAAA;IAElE;;;;;;OAMG;IACH,GAAG,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,CAAC,KAAK,CAAC,GAAG,SAAS,EAAE,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;IAE9F;;;;OAIG;IACH,MAAM,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;CACzC;AAED;;;;;;GAMG;AACH,MAAM,MAAM,qBAAqB,GAAG,CAAC,KAAK,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,OAAO,cAAc,CAAC,KAAK,CAAC,CAAA"}
@@ -1,10 +1,21 @@
1
1
  import * as oauth from 'oauth4webapi';
2
- import type { BezzieConfig } from './index';
2
+ /**
3
+ * Minimal config shape that discovery needs — it only reads `issuer` and
4
+ * `providerOverrides.tokenEndpoint`. Accepting this interface (rather than
5
+ * `BezzieConfig`) avoids a generic parameter that has no bearing on discovery.
6
+ */
7
+ interface DiscoveryConfig {
8
+ issuer: string;
9
+ providerOverrides?: {
10
+ tokenEndpoint?: string;
11
+ };
12
+ }
3
13
  export interface DiscoveryCache {
4
14
  cachedAS: oauth.AuthorizationServer | null;
5
15
  cacheExpiresAt: number;
6
16
  jwksCache: oauth.JWKSCacheInput;
7
17
  }
8
18
  export declare function createDiscoveryCache(): DiscoveryCache;
9
- export declare function getAuthorizationServer(config: BezzieConfig, cache: DiscoveryCache): Promise<oauth.AuthorizationServer>;
19
+ export declare function getAuthorizationServer(config: DiscoveryConfig, cache: DiscoveryCache): Promise<oauth.AuthorizationServer>;
20
+ export {};
10
21
  //# sourceMappingURL=discovery.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"discovery.d.ts","sourceRoot":"","sources":["../src/discovery.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,cAAc,CAAA;AACrC,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,SAAS,CAAA;AAE3C,MAAM,WAAW,cAAc;IAC7B,QAAQ,EAAE,KAAK,CAAC,mBAAmB,GAAG,IAAI,CAAA;IAC1C,cAAc,EAAE,MAAM,CAAA;IACtB,SAAS,EAAE,KAAK,CAAC,cAAc,CAAA;CAChC;AAED,wBAAgB,oBAAoB,IAAI,cAAc,CAErD;AAED,wBAAsB,sBAAsB,CAC1C,MAAM,EAAE,YAAY,EACpB,KAAK,EAAE,cAAc,GACpB,OAAO,CAAC,KAAK,CAAC,mBAAmB,CAAC,CAoBpC"}
1
+ {"version":3,"file":"discovery.d.ts","sourceRoot":"","sources":["../src/discovery.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,cAAc,CAAA;AAGrC;;;;GAIG;AACH,UAAU,eAAe;IACvB,MAAM,EAAE,MAAM,CAAA;IACd,iBAAiB,CAAC,EAAE;QAClB,aAAa,CAAC,EAAE,MAAM,CAAA;KACvB,CAAA;CACF;AAED,MAAM,WAAW,cAAc;IAC7B,QAAQ,EAAE,KAAK,CAAC,mBAAmB,GAAG,IAAI,CAAA;IAC1C,cAAc,EAAE,MAAM,CAAA;IACtB,SAAS,EAAE,KAAK,CAAC,cAAc,CAAA;CAChC;AAED,wBAAgB,oBAAoB,IAAI,cAAc,CAErD;AAED,wBAAsB,sBAAsB,CAC1C,MAAM,EAAE,eAAe,EACvB,KAAK,EAAE,cAAc,GACpB,OAAO,CAAC,KAAK,CAAC,mBAAmB,CAAC,CAoBpC"}
package/dist/discovery.js CHANGED
@@ -1,4 +1,5 @@
1
1
  import * as oauth from 'oauth4webapi';
2
+ import { DiscoveryError } from './errors';
2
3
  export function createDiscoveryCache() {
3
4
  return { cachedAS: null, cacheExpiresAt: 0, jwksCache: {} };
4
5
  }
@@ -8,17 +9,17 @@ export async function getAuthorizationServer(config, cache) {
8
9
  }
9
10
  const issuer = new URL(config.issuer);
10
11
  try {
11
- const response = await oauth.discoveryRequest(issuer);
12
+ const response = await oauth.discoveryRequest(issuer, { signal: AbortSignal.timeout(5000) });
12
13
  const as = await oauth.processDiscoveryResponse(issuer, response);
13
- const cachedAS = config.providerHints?.tokenEndpoint
14
- ? { ...as, token_endpoint: config.providerHints.tokenEndpoint }
14
+ const cachedAS = config.providerOverrides?.tokenEndpoint
15
+ ? { ...as, token_endpoint: config.providerOverrides.tokenEndpoint }
15
16
  : as;
16
17
  cache.cachedAS = cachedAS;
17
18
  cache.cacheExpiresAt = Date.now() + 60 * 60 * 1000;
18
19
  return cachedAS;
19
20
  }
20
21
  catch (err) {
21
- throw new Error(`Bezzie: OIDC discovery failed for ${config.issuer}: ${err instanceof Error ? err.message : String(err)}`, { cause: err });
22
+ throw new DiscoveryError(`Bezzie: OIDC discovery failed for ${config.issuer}: ${err instanceof Error ? err.message : String(err)}`, { cause: err });
22
23
  }
23
24
  }
24
25
  //# sourceMappingURL=discovery.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"discovery.js","sourceRoot":"","sources":["../src/discovery.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,cAAc,CAAA;AASrC,MAAM,UAAU,oBAAoB;IAClC,OAAO,EAAE,QAAQ,EAAE,IAAI,EAAE,cAAc,EAAE,CAAC,EAAE,SAAS,EAAE,EAAE,EAAE,CAAA;AAC7D,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,sBAAsB,CAC1C,MAAoB,EACpB,KAAqB;IAErB,IAAI,KAAK,CAAC,QAAQ,IAAI,IAAI,CAAC,GAAG,EAAE,GAAG,KAAK,CAAC,cAAc,EAAE,CAAC;QACxD,OAAO,KAAK,CAAC,QAAQ,CAAA;IACvB,CAAC;IACD,MAAM,MAAM,GAAG,IAAI,GAAG,CAAC,MAAM,CAAC,MAAM,CAAC,CAAA;IACrC,IAAI,CAAC;QACH,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,gBAAgB,CAAC,MAAM,CAAC,CAAA;QACrD,MAAM,EAAE,GAAG,MAAM,KAAK,CAAC,wBAAwB,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAA;QACjE,MAAM,QAAQ,GAAG,MAAM,CAAC,aAAa,EAAE,aAAa;YAClD,CAAC,CAAC,EAAE,GAAG,EAAE,EAAE,cAAc,EAAE,MAAM,CAAC,aAAa,CAAC,aAAa,EAAE;YAC/D,CAAC,CAAC,EAAE,CAAA;QACN,KAAK,CAAC,QAAQ,GAAG,QAAQ,CAAA;QACzB,KAAK,CAAC,cAAc,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI,CAAA;QAClD,OAAO,QAAQ,CAAA;IACjB,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,MAAM,IAAI,KAAK,CACb,qCAAqC,MAAM,CAAC,MAAM,KAAK,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,EACzG,EAAE,KAAK,EAAE,GAAG,EAAE,CACf,CAAA;IACH,CAAC;AACH,CAAC"}
1
+ {"version":3,"file":"discovery.js","sourceRoot":"","sources":["../src/discovery.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,cAAc,CAAA;AACrC,OAAO,EAAE,cAAc,EAAE,MAAM,UAAU,CAAA;AAoBzC,MAAM,UAAU,oBAAoB;IAClC,OAAO,EAAE,QAAQ,EAAE,IAAI,EAAE,cAAc,EAAE,CAAC,EAAE,SAAS,EAAE,EAAE,EAAE,CAAA;AAC7D,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,sBAAsB,CAC1C,MAAuB,EACvB,KAAqB;IAErB,IAAI,KAAK,CAAC,QAAQ,IAAI,IAAI,CAAC,GAAG,EAAE,GAAG,KAAK,CAAC,cAAc,EAAE,CAAC;QACxD,OAAO,KAAK,CAAC,QAAQ,CAAA;IACvB,CAAC;IACD,MAAM,MAAM,GAAG,IAAI,GAAG,CAAC,MAAM,CAAC,MAAM,CAAC,CAAA;IACrC,IAAI,CAAC;QACH,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,gBAAgB,CAAC,MAAM,EAAE,EAAE,MAAM,EAAE,WAAW,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC,CAAA;QAC5F,MAAM,EAAE,GAAG,MAAM,KAAK,CAAC,wBAAwB,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAA;QACjE,MAAM,QAAQ,GAAG,MAAM,CAAC,iBAAiB,EAAE,aAAa;YACtD,CAAC,CAAC,EAAE,GAAG,EAAE,EAAE,cAAc,EAAE,MAAM,CAAC,iBAAiB,CAAC,aAAa,EAAE;YACnE,CAAC,CAAC,EAAE,CAAA;QACN,KAAK,CAAC,QAAQ,GAAG,QAAQ,CAAA;QACzB,KAAK,CAAC,cAAc,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI,CAAA;QAClD,OAAO,QAAQ,CAAA;IACjB,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,MAAM,IAAI,cAAc,CACtB,qCAAqC,MAAM,CAAC,MAAM,KAAK,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,EACzG,EAAE,KAAK,EAAE,GAAG,EAAE,CACf,CAAA;IACH,CAAC;AACH,CAAC"}
@@ -0,0 +1,28 @@
1
+ export type BezzieErrorCode = 'discovery_failed' | 'callback_invalid_state' | 'callback_provider_error' | 'token_exchange_failed' | 'refresh_failed' | 'refresh_token_revoked' | 'session_storage_failed' | 'session_not_found' | 'config_invalid';
2
+ export interface BezzieErrorOptions {
3
+ cause?: unknown;
4
+ httpStatus?: number;
5
+ oauthError?: string;
6
+ oauthErrorDescription?: string;
7
+ }
8
+ export declare class BezzieError extends Error {
9
+ readonly code: BezzieErrorCode;
10
+ readonly httpStatus?: number;
11
+ readonly oauthError?: string;
12
+ readonly oauthErrorDescription?: string;
13
+ constructor(code: BezzieErrorCode, message: string, opts?: BezzieErrorOptions);
14
+ }
15
+ export declare class DiscoveryError extends BezzieError {
16
+ constructor(message: string, opts?: BezzieErrorOptions);
17
+ }
18
+ export declare class CallbackError extends BezzieError {
19
+ }
20
+ export declare class TokenExchangeError extends BezzieError {
21
+ }
22
+ export declare class RefreshError extends BezzieError {
23
+ }
24
+ export declare class SessionStoreError extends BezzieError {
25
+ }
26
+ export declare class ConfigError extends BezzieError {
27
+ }
28
+ //# sourceMappingURL=errors.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,eAAe,GACvB,kBAAkB,GAClB,wBAAwB,GACxB,yBAAyB,GACzB,uBAAuB,GACvB,gBAAgB,GAChB,uBAAuB,GACvB,wBAAwB,GACxB,mBAAmB,GACnB,gBAAgB,CAAA;AAEpB,MAAM,WAAW,kBAAkB;IACjC,KAAK,CAAC,EAAE,OAAO,CAAA;IACf,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,qBAAqB,CAAC,EAAE,MAAM,CAAA;CAC/B;AAED,qBAAa,WAAY,SAAQ,KAAK;IACpC,QAAQ,CAAC,IAAI,EAAE,eAAe,CAAA;IAC9B,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAA;IAC5B,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAA;IAC5B,QAAQ,CAAC,qBAAqB,CAAC,EAAE,MAAM,CAAA;gBAE3B,IAAI,EAAE,eAAe,EAAE,OAAO,EAAE,MAAM,EAAE,IAAI,GAAE,kBAAuB;CASlF;AAED,qBAAa,cAAe,SAAQ,WAAW;gBACjC,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,kBAAkB;CAGvD;AAED,qBAAa,aAAc,SAAQ,WAAW;CAAG;AACjD,qBAAa,kBAAmB,SAAQ,WAAW;CAAG;AACtD,qBAAa,YAAa,SAAQ,WAAW;CAAG;AAChD,qBAAa,iBAAkB,SAAQ,WAAW;CAAG;AACrD,qBAAa,WAAY,SAAQ,WAAW;CAAG"}
package/dist/errors.js ADDED
@@ -0,0 +1,31 @@
1
+ export class BezzieError extends Error {
2
+ code;
3
+ httpStatus;
4
+ oauthError;
5
+ oauthErrorDescription;
6
+ constructor(code, message, opts = {}) {
7
+ super(message, { cause: opts.cause });
8
+ this.name = this.constructor.name;
9
+ this.code = code;
10
+ this.httpStatus = opts.httpStatus;
11
+ this.oauthError = opts.oauthError;
12
+ this.oauthErrorDescription = opts.oauthErrorDescription;
13
+ Object.setPrototypeOf(this, new.target.prototype);
14
+ }
15
+ }
16
+ export class DiscoveryError extends BezzieError {
17
+ constructor(message, opts) {
18
+ super('discovery_failed', message, opts);
19
+ }
20
+ }
21
+ export class CallbackError extends BezzieError {
22
+ }
23
+ export class TokenExchangeError extends BezzieError {
24
+ }
25
+ export class RefreshError extends BezzieError {
26
+ }
27
+ export class SessionStoreError extends BezzieError {
28
+ }
29
+ export class ConfigError extends BezzieError {
30
+ }
31
+ //# sourceMappingURL=errors.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.js","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAkBA,MAAM,OAAO,WAAY,SAAQ,KAAK;IAC3B,IAAI,CAAiB;IACrB,UAAU,CAAS;IACnB,UAAU,CAAS;IACnB,qBAAqB,CAAS;IAEvC,YAAY,IAAqB,EAAE,OAAe,EAAE,OAA2B,EAAE;QAC/E,KAAK,CAAC,OAAO,EAAE,EAAE,KAAK,EAAE,IAAI,CAAC,KAAK,EAAE,CAAC,CAAA;QACrC,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC,WAAW,CAAC,IAAI,CAAA;QACjC,IAAI,CAAC,IAAI,GAAG,IAAI,CAAA;QAChB,IAAI,CAAC,UAAU,GAAG,IAAI,CAAC,UAAU,CAAA;QACjC,IAAI,CAAC,UAAU,GAAG,IAAI,CAAC,UAAU,CAAA;QACjC,IAAI,CAAC,qBAAqB,GAAG,IAAI,CAAC,qBAAqB,CAAA;QACvD,MAAM,CAAC,cAAc,CAAC,IAAI,EAAE,GAAG,CAAC,MAAM,CAAC,SAAS,CAAC,CAAA;IACnD,CAAC;CACF;AAED,MAAM,OAAO,cAAe,SAAQ,WAAW;IAC7C,YAAY,OAAe,EAAE,IAAyB;QACpD,KAAK,CAAC,kBAAkB,EAAE,OAAO,EAAE,IAAI,CAAC,CAAA;IAC1C,CAAC;CACF;AAED,MAAM,OAAO,aAAc,SAAQ,WAAW;CAAG;AACjD,MAAM,OAAO,kBAAmB,SAAQ,WAAW;CAAG;AACtD,MAAM,OAAO,YAAa,SAAQ,WAAW;CAAG;AAChD,MAAM,OAAO,iBAAkB,SAAQ,WAAW;CAAG;AACrD,MAAM,OAAO,WAAY,SAAQ,WAAW;CAAG"}