@iqauth/sdk 2.6.4 → 2.7.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.
Files changed (110) 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 +181 -41
  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 +271 -32
  9. package/dist/browser.mjs +5 -5
  10. package/dist/{chunk-6I6RM4MN.mjs → chunk-6PJRLRB4.mjs} +33 -3
  11. package/dist/{chunk-LIZYFXH7.mjs → chunk-DFWHSDYQ.mjs} +1 -1
  12. package/dist/chunk-GLXSIGVS.mjs +66 -0
  13. package/dist/{chunk-DJIBN2N7.mjs → chunk-GN37E64I.mjs} +29 -7
  14. package/dist/{chunk-WQWBJSSS.mjs → chunk-HVHNYPDC.mjs} +6 -6
  15. package/dist/{chunk-W3F4JYGP.mjs → chunk-JXQI62A7.mjs} +108 -18
  16. package/dist/{chunk-UNYDG2L4.mjs → chunk-NUO2I65G.mjs} +56 -23
  17. package/dist/chunk-PMAFENVI.mjs +229 -0
  18. package/dist/chunk-RR2MGPTK.mjs +2724 -0
  19. package/dist/{chunk-XAWYUPMO.mjs → chunk-RTJAIBXY.mjs} +220 -20
  20. package/dist/{chunk-6TDJJER7.mjs → chunk-RUJXRTEW.mjs} +164 -5
  21. package/dist/{chunk-3JULWS6F.mjs → chunk-WCELYTJ3.mjs} +3 -3
  22. package/dist/{chunk-MKKZULZR.mjs → chunk-WIFG74IK.mjs} +1 -1
  23. package/dist/{chunk-BVV54LPI.mjs → chunk-YVALAG3B.mjs} +10 -4
  24. package/dist/cli/index.js +2 -2
  25. package/dist/cli/index.mjs +2 -2
  26. package/dist/{client-kYlJFgPv.d.mts → client-BGFnBpfc.d.mts} +47 -4
  27. package/dist/{client-BNQe3AgF.d.ts → client-CDQ21LvW.d.ts} +47 -4
  28. package/dist/{doctor-YYNHNMLD.mjs → doctor-JAFXWU3X.mjs} +2 -2
  29. package/dist/errors-Jl1Jtm-6.d.mts +107 -0
  30. package/dist/errors-Jl1Jtm-6.d.ts +107 -0
  31. package/dist/{express-B6_1vBYZ.d.mts → express-CVNQEkOr.d.mts} +2 -2
  32. package/dist/{express-CHpfa7D_.d.ts → express-Piv2WhWM.d.ts} +2 -2
  33. package/dist/express.d.mts +7 -6
  34. package/dist/express.d.ts +7 -6
  35. package/dist/express.js +349 -52
  36. package/dist/express.mjs +39 -12
  37. package/dist/fastify.d.mts +2 -0
  38. package/dist/fastify.d.ts +2 -0
  39. package/dist/fastify.js +332 -52
  40. package/dist/fastify.mjs +23 -8
  41. package/dist/hono.d.mts +2 -0
  42. package/dist/hono.d.ts +2 -0
  43. package/dist/hono.js +329 -52
  44. package/dist/hono.mjs +20 -8
  45. package/dist/index-5KSZEnDe.d.ts +1626 -0
  46. package/dist/index-CKoZHAoc.d.mts +1626 -0
  47. package/dist/index.d.mts +56 -8
  48. package/dist/index.d.ts +56 -8
  49. package/dist/index.js +565 -69
  50. package/dist/index.mjs +29 -9
  51. package/dist/{keys-NLWFAOEM.mjs → keys-6Y776TG2.mjs} +2 -2
  52. package/dist/locales.d.mts +1 -1
  53. package/dist/locales.d.ts +1 -1
  54. package/dist/mobile.d.mts +77 -7
  55. package/dist/mobile.d.ts +77 -7
  56. package/dist/mobile.js +276 -41
  57. package/dist/mobile.mjs +98 -3
  58. package/dist/next.d.mts +2 -1
  59. package/dist/next.d.ts +2 -1
  60. package/dist/next.js +391 -201
  61. package/dist/next.mjs +22 -7
  62. package/dist/{provisioningBridge-DnTfzdZK.d.ts → provisioningBridge-CGpMRie4.d.ts} +1 -1
  63. package/dist/{provisioningBridge-88xjOS2n.d.mts → provisioningBridge-M5G47LWO.d.mts} +1 -1
  64. package/dist/{publishableKey-BaR0HoAH.d.ts → publishableKey-f2kq-rKw.d.mts} +1 -1
  65. package/dist/{publishableKey-BaR0HoAH.d.mts → publishableKey-f2kq-rKw.d.ts} +1 -1
  66. package/dist/react-permissions.d.mts +52 -0
  67. package/dist/react-permissions.d.ts +52 -0
  68. package/dist/react-permissions.js +239 -0
  69. package/dist/react-permissions.mjs +97 -0
  70. package/dist/react.d.mts +9 -1624
  71. package/dist/react.d.ts +9 -1624
  72. package/dist/react.js +313 -33
  73. package/dist/react.mjs +58 -2632
  74. package/dist/{reverify-4UEJXUS6.mjs → reverify-C64QXKJO.mjs} +2 -2
  75. package/dist/server/handlers.d.mts +148 -3
  76. package/dist/server/handlers.d.ts +148 -3
  77. package/dist/server/handlers.js +410 -11
  78. package/dist/server/handlers.mjs +12 -3
  79. package/dist/server.d.mts +151 -8
  80. package/dist/server.d.ts +151 -8
  81. package/dist/server.js +406 -50
  82. package/dist/server.mjs +93 -11
  83. package/dist/service.d.mts +4 -4
  84. package/dist/service.d.ts +4 -4
  85. package/dist/service.js +181 -41
  86. package/dist/service.mjs +3 -3
  87. package/dist/{signIn-OCr88Zf8.d.ts → signIn-BLFnz8SV.d.ts} +78 -3
  88. package/dist/{signIn-4OKLDEIH.mjs → signIn-SHBW6Z4T.mjs} +1 -1
  89. package/dist/{signIn-CiIBTJIh.d.mts → signIn-T-CZ6t6r.d.mts} +78 -3
  90. package/dist/test.mjs +3 -3
  91. package/dist/{tokens-DCyzzn8L.d.mts → tokens-Bqhmqq_R.d.ts} +9 -2
  92. package/dist/{tokens-aHiGFr_E.d.ts → tokens-CITeoG6P.d.mts} +9 -2
  93. package/dist/{types-6bNdxesb.d.ts → types-BdQ2lqfT.d.mts} +1 -1
  94. package/dist/{types-6bNdxesb.d.mts → types-BdQ2lqfT.d.ts} +1 -1
  95. package/dist/{types-DZAflmmq.d.mts → types-XOV9XPVi.d.mts} +99 -10
  96. package/dist/{types-DZAflmmq.d.ts → types-XOV9XPVi.d.ts} +99 -10
  97. package/dist/webhooks.d.mts +100 -17
  98. package/dist/webhooks.d.ts +100 -17
  99. package/dist/webhooks.js +164 -15
  100. package/dist/webhooks.mjs +7 -1
  101. package/dist/ws.d.mts +2 -2
  102. package/dist/ws.d.ts +2 -2
  103. package/dist/ws.js +80 -30
  104. package/dist/ws.mjs +4 -4
  105. package/docs/error-handling.md +101 -0
  106. package/docs/guides/effective-permissions.md +171 -0
  107. package/package.json +13 -3
  108. package/dist/chunk-UKZLOHZG.mjs +0 -83
  109. package/dist/errors-CDdl24MP.d.mts +0 -52
  110. package/dist/errors-CDdl24MP.d.ts +0 -52
package/dist/server.d.mts CHANGED
@@ -1,10 +1,153 @@
1
- import { b as IQAuthTokenClientConfig, N as ExpressMiddlewareOptions, Q as IQAuthRequestLike, R as IQAuthResponseLike, V as IQAuthNextFunction } 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
- export { C as CookieAwareMiddlewareOptions, D as DEFAULT_ACCESS_COOKIE, a as DEFAULT_REFRESH_COOKIE, i as iqAuthMiddleware } from './express-B6_1vBYZ.mjs';
5
- export { HandlerResponse, IQAuthHelperConfig, SetCookieDirective, handleCallback, handleRefresh, handleSignout, serializeCookie } from './server/handlers.mjs';
6
- export { P as ProvisioningBridge, a as ProvisioningBridgeOptions, d as ProvisioningContext, b as ProvisioningStorage, c as createProvisioningBridge } from './provisioningBridge-88xjOS2n.mjs';
7
- import './tokens-DCyzzn8L.mjs';
1
+ import { J as JwtClaims, f as IQAuthTokenClientConfig, X as ExpressMiddlewareOptions, a as IQAuthRequestLike, b as IQAuthResponseLike, c as IQAuthNextFunction } from './types-XOV9XPVi.mjs';
2
+ import { I as IQAuthClient } from './client-BGFnBpfc.mjs';
3
+ export { E as ErrorCodes, I as IQAuthError } from './errors-Jl1Jtm-6.mjs';
4
+ export { C as CookieAwareMiddlewareOptions, D as DEFAULT_ACCESS_COOKIE, a as DEFAULT_REFRESH_COOKIE, i as iqAuthMiddleware } from './express-CVNQEkOr.mjs';
5
+ export { HandlerResponse, IQAuthHelperConfig, SetCookieDirective, UserinfoResponse, buildUserinfoResponse, handleCallback, handleRefresh, handleSignout, handleUserinfo, serializeCookie } from './server/handlers.mjs';
6
+ export { P as ProvisioningBridge, a as ProvisioningBridgeOptions, d as ProvisioningContext, b as ProvisioningStorage, c as createProvisioningBridge } from './provisioningBridge-M5G47LWO.mjs';
7
+ import './tokens-CITeoG6P.mjs';
8
+
9
+ /**
10
+ * linkLocalUserToIqAuthSub — first-time-migration helper.
11
+ *
12
+ * Use case: an app already had local users before adopting IQAuth. After a
13
+ * user signs in via IQAuth, the JWT's `sub` won't match any local row. The
14
+ * conventional self-heal is "look up by email, write the sub onto the matching
15
+ * row". Doing this safely requires:
16
+ *
17
+ * 1. An atomic transaction (find + write) so two concurrent first-time
18
+ * sign-ins for the same user can't both succeed.
19
+ * 2. Email matching that's case-insensitive by default (since email
20
+ * providers fold case in delivery).
21
+ * 3. A refusal to link when the candidate row already has a different
22
+ * non-null `iqauthSub` (i.e. that local row belongs to someone else).
23
+ * 4. A refusal to link when more than one local row matches the email
24
+ * (duplicate-email collision in the legacy table).
25
+ *
26
+ * The helper is ORM-agnostic. Pass any adapter that implements
27
+ * `LinkAdapter`. A reference Drizzle adapter is exported as
28
+ * `createDrizzleLinkAdapter`.
29
+ *
30
+ * Result codes:
31
+ * - 'linked' — wrote claims.sub onto the matched local row.
32
+ * - 'already_linked' — a row was already keyed by claims.sub. No write.
33
+ * - 'conflict' — matched row already has a different non-null sub,
34
+ * OR more than one local row matches the email.
35
+ * - 'not_found' — no local row matched any of the provided lookupBy
36
+ * keys. Caller should provision a new row separately.
37
+ */
38
+
39
+ type LinkLookupBy = "email";
40
+ type LinkResult = {
41
+ status: "linked";
42
+ userId: string;
43
+ } | {
44
+ status: "already_linked";
45
+ userId: string;
46
+ } | {
47
+ status: "conflict";
48
+ userId?: string;
49
+ reason: "different_sub" | "duplicate_email";
50
+ } | {
51
+ status: "not_found";
52
+ };
53
+ interface LinkCandidate {
54
+ id: string;
55
+ email: string | null;
56
+ iqauthSub: string | null;
57
+ }
58
+ interface LinkAdapterTx {
59
+ findByIqAuthSub(sub: string): Promise<LinkCandidate | null>;
60
+ findByEmail(email: string, opts: {
61
+ caseInsensitive: boolean;
62
+ }): Promise<LinkCandidate[]>;
63
+ /**
64
+ * Write the IQAuth `sub` onto the matched row. Implementations SHOULD make
65
+ * this a conditional update (`WHERE id=? AND iqauth_sub IS NULL OR iqauth_sub=?`)
66
+ * and return `false` if no row was updated — that signals a concurrent
67
+ * writer claimed the row first and the helper will surface a `conflict`.
68
+ * For backward-compatibility, returning `void` is treated as "succeeded".
69
+ */
70
+ setIqAuthSub(userId: string, sub: string): Promise<void | boolean>;
71
+ }
72
+ interface LinkAdapter {
73
+ /**
74
+ * Run `fn` inside a serialized transaction. Implementations MUST guarantee
75
+ * that candidate rows surfaced by `findByIqAuthSub` / `findByEmail` are
76
+ * held under a row-level lock (or equivalent isolation) for the duration
77
+ * of the transaction so the read+write pair is atomic against other
78
+ * concurrent first-time logins for the same user. Concretely:
79
+ * - Postgres / MySQL: implement the read with `SELECT … FOR UPDATE`.
80
+ * - SQLite: relies on the file-level write lock — no extra clause needed.
81
+ * - Otherwise: run the transaction at SERIALIZABLE isolation.
82
+ * The reference `createDrizzleLinkAdapter` does this for you.
83
+ */
84
+ withTransaction<T>(fn: (tx: LinkAdapterTx) => Promise<T>): Promise<T>;
85
+ }
86
+ interface LinkLocalUserOptions {
87
+ adapter: LinkAdapter;
88
+ claims: Pick<JwtClaims, "sub" | "email">;
89
+ /**
90
+ * Lookup keys to try, in order. Currently only `'email'` is supported.
91
+ * Defaults to `['email']`.
92
+ */
93
+ lookupBy?: LinkLookupBy[];
94
+ /**
95
+ * Email matching. Default true — most legacy stores fold case in delivery
96
+ * but preserve the cased original at registration time.
97
+ */
98
+ caseInsensitiveEmail?: boolean;
99
+ }
100
+ declare function linkLocalUserToIqAuthSub(options: LinkLocalUserOptions): Promise<LinkResult>;
101
+ interface DrizzleLikeDb {
102
+ transaction<T>(fn: (tx: unknown) => Promise<T>): Promise<T>;
103
+ }
104
+ interface DrizzleLinkAdapterDeps {
105
+ /** Drizzle DB instance with `.transaction()`. */
106
+ db: DrizzleLikeDb;
107
+ /** Drizzle table object (e.g. `users`). */
108
+ table: unknown;
109
+ /** Column refs on the table — `id`, `email`, and the iqauth sub column. */
110
+ columns: {
111
+ id: unknown;
112
+ email: unknown;
113
+ iqauthSub: unknown;
114
+ };
115
+ /**
116
+ * Optional override for the schema property keys used by `.set(...)` on
117
+ * UPDATE. Drizzle's `.set()` is keyed by the table's TypeScript property
118
+ * names (the keys of your schema object), which need not match the
119
+ * underlying column name. Defaults to `{ iqauthSub: 'iqauthSub' }`.
120
+ */
121
+ columnNames?: {
122
+ iqauthSub?: string;
123
+ };
124
+ /** Drizzle `eq` operator import (`drizzle-orm`). */
125
+ eq: (a: unknown, b: unknown) => unknown;
126
+ /**
127
+ * Drizzle `sql` template tag (`drizzle-orm`). Used for case-insensitive
128
+ * email comparison via `lower(email) = lower($1)`.
129
+ */
130
+ sql: (strings: TemplateStringsArray, ...values: unknown[]) => unknown;
131
+ }
132
+ /**
133
+ * Reference adapter for Drizzle ORM (Postgres / SQLite / MySQL). The host
134
+ * app passes its own `db`, `table`, column refs, and `eq` / `sql` imports
135
+ * so this SDK has no hard dependency on `drizzle-orm`.
136
+ *
137
+ * Example:
138
+ *
139
+ * import { eq, sql } from 'drizzle-orm';
140
+ * import { db } from './db';
141
+ * import { users } from './schema';
142
+ * import { createDrizzleLinkAdapter, linkLocalUserToIqAuthSub } from '@iqauth/sdk/server';
143
+ *
144
+ * const adapter = createDrizzleLinkAdapter({
145
+ * db, table: users, eq, sql,
146
+ * columns: { id: users.id, email: users.email, iqauthSub: users.iqauthSub },
147
+ * });
148
+ * const result = await linkLocalUserToIqAuthSub({ adapter, claims: req.auth });
149
+ */
150
+ declare function createDrizzleLinkAdapter(deps: DrizzleLinkAdapterDeps): LinkAdapter;
8
151
 
9
152
  declare class ServerIQAuthClient extends IQAuthClient {
10
153
  constructor(config: IQAuthTokenClientConfig);
@@ -12,4 +155,4 @@ declare class ServerIQAuthClient extends IQAuthClient {
12
155
  }
13
156
  declare function createServerClient(config: IQAuthTokenClientConfig): ServerIQAuthClient;
14
157
 
15
- export { ExpressMiddlewareOptions, IQAuthClient, IQAuthTokenClientConfig, ServerIQAuthClient, createServerClient };
158
+ export { type DrizzleLinkAdapterDeps, ExpressMiddlewareOptions, IQAuthClient, IQAuthTokenClientConfig, type LinkAdapter, type LinkAdapterTx, type LinkCandidate, type LinkLocalUserOptions, type LinkLookupBy, type LinkResult, ServerIQAuthClient, createDrizzleLinkAdapter, createServerClient, linkLocalUserToIqAuthSub };
package/dist/server.d.ts CHANGED
@@ -1,10 +1,153 @@
1
- import { b as IQAuthTokenClientConfig, N as ExpressMiddlewareOptions, Q as IQAuthRequestLike, R as IQAuthResponseLike, V as IQAuthNextFunction } 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
- export { C as CookieAwareMiddlewareOptions, D as DEFAULT_ACCESS_COOKIE, a as DEFAULT_REFRESH_COOKIE, i as iqAuthMiddleware } from './express-CHpfa7D_.js';
5
- export { HandlerResponse, IQAuthHelperConfig, SetCookieDirective, handleCallback, handleRefresh, handleSignout, serializeCookie } from './server/handlers.js';
6
- export { P as ProvisioningBridge, a as ProvisioningBridgeOptions, d as ProvisioningContext, b as ProvisioningStorage, c as createProvisioningBridge } from './provisioningBridge-DnTfzdZK.js';
7
- import './tokens-aHiGFr_E.js';
1
+ import { J as JwtClaims, f as IQAuthTokenClientConfig, X as ExpressMiddlewareOptions, a as IQAuthRequestLike, b as IQAuthResponseLike, c as IQAuthNextFunction } from './types-XOV9XPVi.js';
2
+ import { I as IQAuthClient } from './client-CDQ21LvW.js';
3
+ export { E as ErrorCodes, I as IQAuthError } from './errors-Jl1Jtm-6.js';
4
+ export { C as CookieAwareMiddlewareOptions, D as DEFAULT_ACCESS_COOKIE, a as DEFAULT_REFRESH_COOKIE, i as iqAuthMiddleware } from './express-Piv2WhWM.js';
5
+ export { HandlerResponse, IQAuthHelperConfig, SetCookieDirective, UserinfoResponse, buildUserinfoResponse, handleCallback, handleRefresh, handleSignout, handleUserinfo, serializeCookie } from './server/handlers.js';
6
+ export { P as ProvisioningBridge, a as ProvisioningBridgeOptions, d as ProvisioningContext, b as ProvisioningStorage, c as createProvisioningBridge } from './provisioningBridge-CGpMRie4.js';
7
+ import './tokens-Bqhmqq_R.js';
8
+
9
+ /**
10
+ * linkLocalUserToIqAuthSub — first-time-migration helper.
11
+ *
12
+ * Use case: an app already had local users before adopting IQAuth. After a
13
+ * user signs in via IQAuth, the JWT's `sub` won't match any local row. The
14
+ * conventional self-heal is "look up by email, write the sub onto the matching
15
+ * row". Doing this safely requires:
16
+ *
17
+ * 1. An atomic transaction (find + write) so two concurrent first-time
18
+ * sign-ins for the same user can't both succeed.
19
+ * 2. Email matching that's case-insensitive by default (since email
20
+ * providers fold case in delivery).
21
+ * 3. A refusal to link when the candidate row already has a different
22
+ * non-null `iqauthSub` (i.e. that local row belongs to someone else).
23
+ * 4. A refusal to link when more than one local row matches the email
24
+ * (duplicate-email collision in the legacy table).
25
+ *
26
+ * The helper is ORM-agnostic. Pass any adapter that implements
27
+ * `LinkAdapter`. A reference Drizzle adapter is exported as
28
+ * `createDrizzleLinkAdapter`.
29
+ *
30
+ * Result codes:
31
+ * - 'linked' — wrote claims.sub onto the matched local row.
32
+ * - 'already_linked' — a row was already keyed by claims.sub. No write.
33
+ * - 'conflict' — matched row already has a different non-null sub,
34
+ * OR more than one local row matches the email.
35
+ * - 'not_found' — no local row matched any of the provided lookupBy
36
+ * keys. Caller should provision a new row separately.
37
+ */
38
+
39
+ type LinkLookupBy = "email";
40
+ type LinkResult = {
41
+ status: "linked";
42
+ userId: string;
43
+ } | {
44
+ status: "already_linked";
45
+ userId: string;
46
+ } | {
47
+ status: "conflict";
48
+ userId?: string;
49
+ reason: "different_sub" | "duplicate_email";
50
+ } | {
51
+ status: "not_found";
52
+ };
53
+ interface LinkCandidate {
54
+ id: string;
55
+ email: string | null;
56
+ iqauthSub: string | null;
57
+ }
58
+ interface LinkAdapterTx {
59
+ findByIqAuthSub(sub: string): Promise<LinkCandidate | null>;
60
+ findByEmail(email: string, opts: {
61
+ caseInsensitive: boolean;
62
+ }): Promise<LinkCandidate[]>;
63
+ /**
64
+ * Write the IQAuth `sub` onto the matched row. Implementations SHOULD make
65
+ * this a conditional update (`WHERE id=? AND iqauth_sub IS NULL OR iqauth_sub=?`)
66
+ * and return `false` if no row was updated — that signals a concurrent
67
+ * writer claimed the row first and the helper will surface a `conflict`.
68
+ * For backward-compatibility, returning `void` is treated as "succeeded".
69
+ */
70
+ setIqAuthSub(userId: string, sub: string): Promise<void | boolean>;
71
+ }
72
+ interface LinkAdapter {
73
+ /**
74
+ * Run `fn` inside a serialized transaction. Implementations MUST guarantee
75
+ * that candidate rows surfaced by `findByIqAuthSub` / `findByEmail` are
76
+ * held under a row-level lock (or equivalent isolation) for the duration
77
+ * of the transaction so the read+write pair is atomic against other
78
+ * concurrent first-time logins for the same user. Concretely:
79
+ * - Postgres / MySQL: implement the read with `SELECT … FOR UPDATE`.
80
+ * - SQLite: relies on the file-level write lock — no extra clause needed.
81
+ * - Otherwise: run the transaction at SERIALIZABLE isolation.
82
+ * The reference `createDrizzleLinkAdapter` does this for you.
83
+ */
84
+ withTransaction<T>(fn: (tx: LinkAdapterTx) => Promise<T>): Promise<T>;
85
+ }
86
+ interface LinkLocalUserOptions {
87
+ adapter: LinkAdapter;
88
+ claims: Pick<JwtClaims, "sub" | "email">;
89
+ /**
90
+ * Lookup keys to try, in order. Currently only `'email'` is supported.
91
+ * Defaults to `['email']`.
92
+ */
93
+ lookupBy?: LinkLookupBy[];
94
+ /**
95
+ * Email matching. Default true — most legacy stores fold case in delivery
96
+ * but preserve the cased original at registration time.
97
+ */
98
+ caseInsensitiveEmail?: boolean;
99
+ }
100
+ declare function linkLocalUserToIqAuthSub(options: LinkLocalUserOptions): Promise<LinkResult>;
101
+ interface DrizzleLikeDb {
102
+ transaction<T>(fn: (tx: unknown) => Promise<T>): Promise<T>;
103
+ }
104
+ interface DrizzleLinkAdapterDeps {
105
+ /** Drizzle DB instance with `.transaction()`. */
106
+ db: DrizzleLikeDb;
107
+ /** Drizzle table object (e.g. `users`). */
108
+ table: unknown;
109
+ /** Column refs on the table — `id`, `email`, and the iqauth sub column. */
110
+ columns: {
111
+ id: unknown;
112
+ email: unknown;
113
+ iqauthSub: unknown;
114
+ };
115
+ /**
116
+ * Optional override for the schema property keys used by `.set(...)` on
117
+ * UPDATE. Drizzle's `.set()` is keyed by the table's TypeScript property
118
+ * names (the keys of your schema object), which need not match the
119
+ * underlying column name. Defaults to `{ iqauthSub: 'iqauthSub' }`.
120
+ */
121
+ columnNames?: {
122
+ iqauthSub?: string;
123
+ };
124
+ /** Drizzle `eq` operator import (`drizzle-orm`). */
125
+ eq: (a: unknown, b: unknown) => unknown;
126
+ /**
127
+ * Drizzle `sql` template tag (`drizzle-orm`). Used for case-insensitive
128
+ * email comparison via `lower(email) = lower($1)`.
129
+ */
130
+ sql: (strings: TemplateStringsArray, ...values: unknown[]) => unknown;
131
+ }
132
+ /**
133
+ * Reference adapter for Drizzle ORM (Postgres / SQLite / MySQL). The host
134
+ * app passes its own `db`, `table`, column refs, and `eq` / `sql` imports
135
+ * so this SDK has no hard dependency on `drizzle-orm`.
136
+ *
137
+ * Example:
138
+ *
139
+ * import { eq, sql } from 'drizzle-orm';
140
+ * import { db } from './db';
141
+ * import { users } from './schema';
142
+ * import { createDrizzleLinkAdapter, linkLocalUserToIqAuthSub } from '@iqauth/sdk/server';
143
+ *
144
+ * const adapter = createDrizzleLinkAdapter({
145
+ * db, table: users, eq, sql,
146
+ * columns: { id: users.id, email: users.email, iqauthSub: users.iqauthSub },
147
+ * });
148
+ * const result = await linkLocalUserToIqAuthSub({ adapter, claims: req.auth });
149
+ */
150
+ declare function createDrizzleLinkAdapter(deps: DrizzleLinkAdapterDeps): LinkAdapter;
8
151
 
9
152
  declare class ServerIQAuthClient extends IQAuthClient {
10
153
  constructor(config: IQAuthTokenClientConfig);
@@ -12,4 +155,4 @@ declare class ServerIQAuthClient extends IQAuthClient {
12
155
  }
13
156
  declare function createServerClient(config: IQAuthTokenClientConfig): ServerIQAuthClient;
14
157
 
15
- export { ExpressMiddlewareOptions, IQAuthClient, IQAuthTokenClientConfig, ServerIQAuthClient, createServerClient };
158
+ export { type DrizzleLinkAdapterDeps, ExpressMiddlewareOptions, IQAuthClient, IQAuthTokenClientConfig, type LinkAdapter, type LinkAdapterTx, type LinkCandidate, type LinkLocalUserOptions, type LinkLookupBy, type LinkResult, ServerIQAuthClient, createDrizzleLinkAdapter, createServerClient, linkLocalUserToIqAuthSub };