@iqauth/sdk 2.6.4 → 2.8.1

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 (117) hide show
  1. package/README.md +173 -1
  2. package/dist/browser-session.d.mts +4 -4
  3. package/dist/browser-session.d.ts +4 -4
  4. package/dist/browser-session.js +212 -46
  5. package/dist/browser-session.mjs +3 -3
  6. package/dist/browser.d.mts +5 -5
  7. package/dist/browser.d.ts +5 -5
  8. package/dist/browser.js +293 -34
  9. package/dist/browser.mjs +5 -5
  10. package/dist/{chunk-BVV54LPI.mjs → chunk-25SSYDIP.mjs} +10 -4
  11. package/dist/{chunk-XAWYUPMO.mjs → chunk-4V7FKOTG.mjs} +242 -22
  12. package/dist/{chunk-6I6RM4MN.mjs → chunk-6PJRLRB4.mjs} +33 -3
  13. package/dist/{chunk-SL3KRS4W.mjs → chunk-CIJORODR.mjs} +23 -1
  14. package/dist/{chunk-LIZYFXH7.mjs → chunk-DFWHSDYQ.mjs} +1 -1
  15. package/dist/chunk-GLXSIGVS.mjs +66 -0
  16. package/dist/{chunk-DJIBN2N7.mjs → chunk-GN37E64I.mjs} +29 -7
  17. package/dist/{chunk-WQWBJSSS.mjs → chunk-HVHNYPDC.mjs} +6 -6
  18. package/dist/chunk-JRDVUWAL.mjs +46 -0
  19. package/dist/{chunk-UNYDG2L4.mjs → chunk-NUO2I65G.mjs} +56 -23
  20. package/dist/{chunk-5T7GHBX6.mjs → chunk-TLET552H.mjs} +36 -0
  21. package/dist/chunk-VYQ3ETCK.mjs +244 -0
  22. package/dist/{chunk-3JULWS6F.mjs → chunk-WCELYTJ3.mjs} +3 -3
  23. package/dist/chunk-WHT6WKTY.mjs +3180 -0
  24. package/dist/{chunk-MKKZULZR.mjs → chunk-WIFG74IK.mjs} +1 -1
  25. package/dist/chunk-WSH4SW7F.mjs +490 -0
  26. package/dist/{chunk-W3F4JYGP.mjs → chunk-ZLJPABB7.mjs} +139 -23
  27. package/dist/cli/index.js +2 -2
  28. package/dist/cli/index.mjs +2 -2
  29. package/dist/{client-BNQe3AgF.d.ts → client-D8L-PaWr.d.mts} +59 -6
  30. package/dist/{client-kYlJFgPv.d.mts → client-DkPL0EPZ.d.ts} +59 -6
  31. package/dist/{doctor-YYNHNMLD.mjs → doctor-JAFXWU3X.mjs} +2 -2
  32. package/dist/errors-Jl1Jtm-6.d.mts +107 -0
  33. package/dist/errors-Jl1Jtm-6.d.ts +107 -0
  34. package/dist/{express-CHpfa7D_.d.ts → express-Budysq4h.d.ts} +2 -2
  35. package/dist/{express-B6_1vBYZ.d.mts → express-DDTA3qV1.d.mts} +2 -2
  36. package/dist/express.d.mts +7 -6
  37. package/dist/express.d.ts +7 -6
  38. package/dist/express.js +563 -85
  39. package/dist/express.mjs +73 -34
  40. package/dist/fastify.d.mts +10 -0
  41. package/dist/fastify.d.ts +10 -0
  42. package/dist/fastify.js +589 -65
  43. package/dist/fastify.mjs +101 -11
  44. package/dist/hono.d.mts +10 -0
  45. package/dist/hono.d.ts +10 -0
  46. package/dist/hono.js +566 -65
  47. package/dist/hono.mjs +78 -11
  48. package/dist/index-Cko-d5po.d.mts +1848 -0
  49. package/dist/index-RNqwEcmY.d.ts +1848 -0
  50. package/dist/index.d.mts +56 -8
  51. package/dist/index.d.ts +56 -8
  52. package/dist/index.js +694 -75
  53. package/dist/index.mjs +30 -10
  54. package/dist/{keys-NLWFAOEM.mjs → keys-6Y776TG2.mjs} +2 -2
  55. package/dist/locales.d.mts +1 -1
  56. package/dist/locales.d.ts +1 -1
  57. package/dist/locales.js +36 -0
  58. package/dist/locales.mjs +1 -1
  59. package/dist/mobile.d.mts +77 -7
  60. package/dist/mobile.d.ts +77 -7
  61. package/dist/mobile.js +307 -46
  62. package/dist/mobile.mjs +98 -3
  63. package/dist/next.d.mts +10 -1
  64. package/dist/next.d.ts +10 -1
  65. package/dist/next.js +596 -205
  66. package/dist/next.mjs +83 -10
  67. package/dist/{provisioningBridge-88xjOS2n.d.mts → provisioningBridge-BXPMZCLe.d.ts} +30 -2
  68. package/dist/{provisioningBridge-DnTfzdZK.d.ts → provisioningBridge-IEycmsgb.d.mts} +30 -2
  69. package/dist/{publishableKey-BaR0HoAH.d.ts → publishableKey-f2kq-rKw.d.mts} +1 -1
  70. package/dist/{publishableKey-BaR0HoAH.d.mts → publishableKey-f2kq-rKw.d.ts} +1 -1
  71. package/dist/react-permissions.d.mts +52 -0
  72. package/dist/react-permissions.d.ts +52 -0
  73. package/dist/react-permissions.js +239 -0
  74. package/dist/react-permissions.mjs +98 -0
  75. package/dist/react.d.mts +9 -1624
  76. package/dist/react.d.ts +9 -1624
  77. package/dist/react.js +882 -73
  78. package/dist/react.mjs +71 -2631
  79. package/dist/{reverify-4UEJXUS6.mjs → reverify-C64QXKJO.mjs} +2 -2
  80. package/dist/server/handlers.d.mts +200 -4
  81. package/dist/server/handlers.d.ts +200 -4
  82. package/dist/server/handlers.js +530 -16
  83. package/dist/server/handlers.mjs +14 -3
  84. package/dist/server.d.mts +171 -8
  85. package/dist/server.d.ts +171 -8
  86. package/dist/server.js +579 -61
  87. package/dist/server.mjs +99 -12
  88. package/dist/service.d.mts +4 -4
  89. package/dist/service.d.ts +4 -4
  90. package/dist/service.js +212 -46
  91. package/dist/service.mjs +3 -3
  92. package/dist/{signIn-CiIBTJIh.d.mts → signIn-CReqfXsh.d.mts} +95 -3
  93. package/dist/{signIn-OCr88Zf8.d.ts → signIn-Cfa1GTpO.d.ts} +95 -3
  94. package/dist/{signIn-4OKLDEIH.mjs → signIn-SHBW6Z4T.mjs} +1 -1
  95. package/dist/test.mjs +3 -3
  96. package/dist/{tokens-DCyzzn8L.d.mts → tokens-9F6ETrzk.d.ts} +9 -2
  97. package/dist/{tokens-aHiGFr_E.d.ts → tokens-B06VtvUi.d.mts} +9 -2
  98. package/dist/{types-DZAflmmq.d.mts → types-Bn8O-OEd.d.mts} +164 -11
  99. package/dist/{types-DZAflmmq.d.ts → types-Bn8O-OEd.d.ts} +164 -11
  100. package/dist/{types-6bNdxesb.d.ts → types-DnU2LhXR.d.mts} +7 -1
  101. package/dist/{types-6bNdxesb.d.mts → types-DnU2LhXR.d.ts} +7 -1
  102. package/dist/webhooks.d.mts +113 -17
  103. package/dist/webhooks.d.ts +113 -17
  104. package/dist/webhooks.js +179 -15
  105. package/dist/webhooks.mjs +7 -1
  106. package/dist/ws.d.mts +2 -2
  107. package/dist/ws.d.ts +2 -2
  108. package/dist/ws.js +80 -30
  109. package/dist/ws.mjs +4 -4
  110. package/docs/error-handling.md +101 -0
  111. package/docs/guides/effective-permissions.md +171 -0
  112. package/docs/guides/invitations.md +65 -0
  113. package/package.json +19 -4
  114. package/dist/chunk-6TDJJER7.mjs +0 -217
  115. package/dist/chunk-UKZLOHZG.mjs +0 -83
  116. package/dist/errors-CDdl24MP.d.mts +0 -52
  117. package/dist/errors-CDdl24MP.d.ts +0 -52
package/README.md CHANGED
@@ -8,7 +8,7 @@
8
8
 
9
9
  The canonical TypeScript SDK for **IQAuthService** — DispositionIQ's multi-tenant identity and authorization platform. One package covers the React client, the four major Node frameworks (Express, Fastify, Hono, Next.js), native mobile, and headless service automation.
10
10
 
11
- > **New in 2.0.3** — `SessionManager` gains `serverManagedSession: true` for confidential-client apps, and the cookie-managed `/refresh` helper no longer wipes cookies on transient failures. See [What's new in 2.0.3](#whats-new-in-203).
11
+ > **New in 2.7.0** — `IQAuthError` now exposes a typed `code` taxonomy (`token_expired`, `jwks_unavailable`, `rate_limited`, …) plus `err.is(code)` / `IQAuthError.isIQAuthError(value)` helpers, and `tokens.verify<T>()` accepts a custom-claims generic so the returned object is fully typed. Both changes are purely additive — existing `catch (e: Error)` and untyped `verify()` callers keep compiling. See [What's new in 2.7.0](#whats-new-in-270).
12
12
 
13
13
  ---
14
14
 
@@ -17,6 +17,8 @@ The canonical TypeScript SDK for **IQAuthService** — DispositionIQ's multi-ten
17
17
  - [Install](#install)
18
18
  - [Five-line integration](#five-line-integration)
19
19
  - [Pick your environment](#pick-your-environment)
20
+ - [What's new in 2.7.0](#whats-new-in-270)
21
+ - [What's new in 2.6.5](#whats-new-in-265)
20
22
  - [What's new in 2.6.2](#whats-new-in-262)
21
23
  - [What's new in 2.6.1](#whats-new-in-261)
22
24
  - [What's new in 2.0.3](#whats-new-in-203)
@@ -174,6 +176,121 @@ The SDK is not "one auth model for every environment". The safe pattern depends
174
176
 
175
177
  ---
176
178
 
179
+ ## What's new in 2.7.0
180
+
181
+ ### 1. Typed `IQAuthError` taxonomy
182
+
183
+ Every SDK-originated throw now carries a `code` from a fixed 10-value union,
184
+ so callers can stop string-matching on `err.message` or guessing whether
185
+ `err.code` is upper-snake or lowercase. Two helpers ship alongside it:
186
+ `IQAuthError.isIQAuthError(value)` (instanceof-safe across realms) and
187
+ `err.is(code)` (narrow-friendly).
188
+
189
+ ```ts
190
+ import { IQAuthError, type IQAuthErrorCode } from "@iqauth/sdk";
191
+
192
+ try {
193
+ const claims = await client.tokens.verify(token);
194
+ } catch (err) {
195
+ if (IQAuthError.isIQAuthError(err)) {
196
+ if (err.is("token_expired")) return refreshAndRetry();
197
+ if (err.is("jwks_fetch_failed")) return retryAfterBackoff();
198
+ if (err.is("rate_limited")) return showRateLimitToast();
199
+ if (err.is("network")) return showOfflineBanner();
200
+ if (err.is("config_invalid")) throw err; // boot-time misconfig
201
+ }
202
+ throw err;
203
+ }
204
+ ```
205
+
206
+ The full union:
207
+
208
+ ```ts
209
+ type IQAuthErrorCode =
210
+ | "token_expired"
211
+ | "token_invalid"
212
+ | "jwks_unavailable"
213
+ | "jwks_fetch_failed"
214
+ | "rate_limited"
215
+ | "network"
216
+ | "config_invalid"
217
+ | "app_not_found"
218
+ | "permission_denied"
219
+ | "unknown";
220
+ ```
221
+
222
+ **Back-compat:** the field is widened to `IQAuthErrorCode | (string & {})`,
223
+ so server-rethrown codes (`TOKEN_REVOKED`, `SESSION_EXPIRED_INACTIVITY`, …)
224
+ still flow through unchanged. The framework adapters (`/express`,
225
+ `/fastify`, `/hono`) map both upper-snake and the new lowercase codes to
226
+ `401`, so this rollout is invisible to existing app code. `IQAuthError`
227
+ also gains a `cause` accessor (alias for the legacy `raw`).
228
+
229
+ See [`docs/error-handling.md`](./docs/error-handling.md) for the full
230
+ recipe book.
231
+
232
+ ### 2. `IQAuthClaims<T>` generic on `tokens.verify`
233
+
234
+ `verify()` now accepts a custom-claims generic so your app's bespoke
235
+ claims show up *typed* on the result — no index-signature widening, no
236
+ `as any`:
237
+
238
+ ```ts
239
+ interface MyClaims { plan: "free" | "pro"; orgId: string }
240
+
241
+ const claims = await client.tokens.verify<MyClaims>(token);
242
+ // ^? IQAuthBaseClaims & MyClaims & JwtClaims
243
+
244
+ if (claims.plan === "pro") doProThing(claims.orgId);
245
+ console.log(claims.tenantId, claims.sub); // base claims still typed
246
+ ```
247
+
248
+ `IQAuthBaseClaims` is exported separately for callers composing their own
249
+ envelope. `JwtClaims` continues to be exported and remains the return
250
+ type of `tokens.decode()` / `tokens.getClaims()` for back-compat. Calls
251
+ to `verify()` without a generic argument behave exactly as before.
252
+
253
+ ---
254
+
255
+ ## What's new in 2.6.5
256
+
257
+ ### Server-managed userinfo (`mountUserinfo: true`)
258
+
259
+ The framework adapters can now auto-mount `GET /api/iqauth/me` so
260
+ server-managed integrators don't have to hand-roll a userinfo handler
261
+ that calls `tokens.verify` and shapes a `data.user` / `data.claims`
262
+ envelope.
263
+
264
+ ```ts
265
+ app.use(iqAuth({
266
+ publishableKey: process.env.IQAUTH_PUBLISHABLE_KEY!,
267
+ secretKey: process.env.IQAUTH_SECRET_KEY!,
268
+ mountUserinfo: true,
269
+ // Optional — shallow-merged over the claim-derived SessionUser defaults.
270
+ userinfoEnricher: async (claims, req) => ({
271
+ name: await loadDisplayName(claims.sub),
272
+ }),
273
+ }));
274
+ ```
275
+
276
+ Returns the documented `UserinfoResponse` envelope —
277
+ `{ success: true, data: { user, claims, tenantId } }` — which is exactly
278
+ the shape the browser SDK's `SessionManager.bootstrap()` already accepts
279
+ (`data.user` is preferred; `claimsToSessionUser(data.claims)` is the
280
+ fallback). The token is read from `Authorization: Bearer …` OR the
281
+ `iqauth_at` cookie; verification reuses a per-issuer cached
282
+ `TokensModule` so JWKS fetches are amortized.
283
+
284
+ Two new framework-neutral exports for integrators who'd rather mount
285
+ their own route but still emit the canonical envelope:
286
+ `buildUserinfoResponse(claims, { enrich? })` and
287
+ `handleUserinfo(config, { accessToken, req? })`. Re-exported from both
288
+ `@iqauth/sdk` and `@iqauth/sdk/server`. See the
289
+ [Server-managed userinfo](#server-managed-userinfo) section below for
290
+ the full reference.
291
+
292
+ ---
293
+
177
294
  ## What's new in 2.6.2
178
295
 
179
296
  ### Card grows responsively on desktop (no more phone-sized form)
@@ -381,6 +498,7 @@ app.use("/admin",
381
498
  | `GET` | `/api/iqauth/callback` | Receives the OIDC redirect, exchanges the code, sets `iqauth_at` + `iqauth_rt`, redirects to `return_to` |
382
499
  | `POST` | `/api/iqauth/refresh` | Reads `iqauth_rt`, rotates, sets new cookies. Honors `clearCookiesOnRefreshFailure` |
383
500
  | `POST` | `/api/iqauth/signout` | Revokes the refresh token upstream and clears both cookies |
501
+ | `GET` | `/api/iqauth/me` | **Opt-in via `mountUserinfo: true`.** Verifies the access token and returns the documented userinfo envelope. See [Server-managed userinfo](#server-managed-userinfo) |
384
502
 
385
503
  All three set cookies with `HttpOnly; Secure; SameSite=lax; Path=/` by default. Override per-app:
386
504
 
@@ -398,6 +516,60 @@ iqAuth({
398
516
 
399
517
  ---
400
518
 
519
+ ### Server-managed userinfo
520
+
521
+ When you're doing the cookie-managed pattern (browser SDK proxies through
522
+ your own backend), your frontend needs *some* endpoint to learn "who am I"
523
+ on first paint. Before 2.6.5 you had to hand-roll that handler — call
524
+ `tokens.verify`, shape a `data.user` envelope, and remember to read the
525
+ token from either `Authorization: Bearer …` OR the `iqauth_at` cookie.
526
+
527
+ Opt into the auto-mounted route instead:
528
+
529
+ ```ts
530
+ app.use(iqAuth({
531
+ publishableKey: process.env.IQAUTH_PUBLISHABLE_KEY!,
532
+ secretKey: process.env.IQAUTH_SECRET_KEY!,
533
+ mountUserinfo: true,
534
+ // Optional — shallow-merged over the claim-derived SessionUser defaults.
535
+ userinfoEnricher: async (claims, req) => ({
536
+ name: await loadDisplayName(claims.sub),
537
+ }),
538
+ }));
539
+ ```
540
+
541
+ `GET /api/iqauth/me` returns the documented `UserinfoResponse` envelope:
542
+
543
+ ```jsonc
544
+ {
545
+ "success": true,
546
+ "data": {
547
+ "user": { "sub": "...", "email": "...", "name": "...", "tenantId": "...", "roles": [...], "entitlements": [...] },
548
+ "claims": { /* full verified JWT payload */ },
549
+ "tenantId": "ten_..." // or null
550
+ }
551
+ }
552
+ ```
553
+
554
+ This is exactly the shape `SessionManager.bootstrap()` already accepts:
555
+ `data.user` is preferred when present, `claimsToSessionUser(data.claims)`
556
+ is the documented fallback. Same option works on Express, Fastify, Hono,
557
+ and the Next.js handler. Token is verified with a per-issuer cached
558
+ `TokensModule` so JWKS fetches are amortized across requests.
559
+
560
+ Want to mount your own route but still emit the canonical envelope? Use
561
+ the framework-neutral helpers:
562
+
563
+ ```ts
564
+ import { buildUserinfoResponse, type UserinfoResponse } from "@iqauth/sdk/server";
565
+
566
+ const envelope: UserinfoResponse = await buildUserinfoResponse(verifiedClaims, {
567
+ enrich: (c) => ({ name: lookupName(c.sub) }),
568
+ });
569
+ ```
570
+
571
+ ---
572
+
401
573
  ## Token verification without a framework adapter
402
574
 
403
575
  If you're not using Express/Fastify/Hono/Next (custom Node server, AWS Lambda, Cloudflare Worker, etc.):
@@ -1,7 +1,7 @@
1
- import { c as IQAuthBrowserSessionClientConfig, d as SessionUser } from './types-DZAflmmq.mjs';
2
- import { I as IQAuthClient } from './client-kYlJFgPv.mjs';
3
- export { E as ErrorCodes, I as IQAuthError } from './errors-CDdl24MP.mjs';
4
- import './tokens-DCyzzn8L.mjs';
1
+ import { I as IQAuthBrowserSessionClientConfig, S as SessionUser } from './types-Bn8O-OEd.mjs';
2
+ import { I as IQAuthClient } from './client-D8L-PaWr.mjs';
3
+ export { E as ErrorCodes, I as IQAuthError } from './errors-Jl1Jtm-6.mjs';
4
+ import './tokens-B06VtvUi.mjs';
5
5
 
6
6
  declare class BrowserSessionIQAuthClient extends IQAuthClient {
7
7
  constructor(config: Omit<IQAuthBrowserSessionClientConfig, "environment">);
@@ -1,7 +1,7 @@
1
- import { c as IQAuthBrowserSessionClientConfig, d as SessionUser } from './types-DZAflmmq.js';
2
- import { I as IQAuthClient } from './client-BNQe3AgF.js';
3
- export { E as ErrorCodes, I as IQAuthError } from './errors-CDdl24MP.js';
4
- import './tokens-aHiGFr_E.js';
1
+ import { I as IQAuthBrowserSessionClientConfig, S as SessionUser } from './types-Bn8O-OEd.js';
2
+ import { I as IQAuthClient } from './client-DkPL0EPZ.js';
3
+ export { E as ErrorCodes, I as IQAuthError } from './errors-Jl1Jtm-6.js';
4
+ import './tokens-9F6ETrzk.js';
5
5
 
6
6
  declare class BrowserSessionIQAuthClient extends IQAuthClient {
7
7
  constructor(config: Omit<IQAuthBrowserSessionClientConfig, "environment">);