@iqauth/sdk 2.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.
Files changed (112) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +287 -0
  3. package/dist/browser-session.d.mts +12 -0
  4. package/dist/browser-session.d.ts +12 -0
  5. package/dist/browser-session.js +1812 -0
  6. package/dist/browser-session.mjs +28 -0
  7. package/dist/browser.d.mts +46 -0
  8. package/dist/browser.d.ts +46 -0
  9. package/dist/browser.js +768 -0
  10. package/dist/browser.mjs +47 -0
  11. package/dist/chunk-5HF3OBNO.mjs +189 -0
  12. package/dist/chunk-5WFR6Y33.mjs +59 -0
  13. package/dist/chunk-6I6RM4MN.mjs +51 -0
  14. package/dist/chunk-73R6BEGO.mjs +176 -0
  15. package/dist/chunk-E46DKOVI.mjs +632 -0
  16. package/dist/chunk-JQWYIIIS.mjs +1740 -0
  17. package/dist/chunk-X3K3WOBR.mjs +64 -0
  18. package/dist/chunk-Y6FXYEAI.mjs +10 -0
  19. package/dist/cli/index.d.mts +1 -0
  20. package/dist/cli/index.d.ts +1 -0
  21. package/dist/cli/index.js +581 -0
  22. package/dist/cli/index.mjs +57 -0
  23. package/dist/client-C1DXfB8Z.d.mts +911 -0
  24. package/dist/client-CggvJmmm.d.ts +911 -0
  25. package/dist/dev-FUTJZSWN.mjs +56 -0
  26. package/dist/doctor-OHJRZBBT.mjs +89 -0
  27. package/dist/errors-CDdl24MP.d.mts +52 -0
  28. package/dist/errors-CDdl24MP.d.ts +52 -0
  29. package/dist/express-BKAXB5Nl.d.ts +61 -0
  30. package/dist/express-CpfyYTmw.d.mts +61 -0
  31. package/dist/express.d.mts +45 -0
  32. package/dist/express.d.ts +45 -0
  33. package/dist/express.js +2252 -0
  34. package/dist/express.mjs +122 -0
  35. package/dist/fastify.d.mts +23 -0
  36. package/dist/fastify.d.ts +23 -0
  37. package/dist/fastify.js +2062 -0
  38. package/dist/fastify.mjs +118 -0
  39. package/dist/hono.d.mts +22 -0
  40. package/dist/hono.d.ts +22 -0
  41. package/dist/hono.js +2051 -0
  42. package/dist/hono.mjs +107 -0
  43. package/dist/index.d.mts +6 -0
  44. package/dist/index.d.ts +6 -0
  45. package/dist/index.js +2070 -0
  46. package/dist/index.mjs +83 -0
  47. package/dist/init-LLCSQGNL.mjs +198 -0
  48. package/dist/keys-NLWFAOEM.mjs +63 -0
  49. package/dist/mobile.d.mts +11 -0
  50. package/dist/mobile.d.ts +11 -0
  51. package/dist/mobile.js +1809 -0
  52. package/dist/mobile.mjs +25 -0
  53. package/dist/next.d.mts +37 -0
  54. package/dist/next.d.ts +37 -0
  55. package/dist/next.js +2078 -0
  56. package/dist/next.mjs +130 -0
  57. package/dist/publishableKey-B5DIK81A.d.mts +24 -0
  58. package/dist/publishableKey-B5DIK81A.d.ts +24 -0
  59. package/dist/react.d.mts +196 -0
  60. package/dist/react.d.ts +196 -0
  61. package/dist/react.js +1457 -0
  62. package/dist/react.mjs +787 -0
  63. package/dist/server/handlers.d.mts +96 -0
  64. package/dist/server/handlers.d.ts +96 -0
  65. package/dist/server/handlers.js +243 -0
  66. package/dist/server/handlers.mjs +14 -0
  67. package/dist/server.d.mts +14 -0
  68. package/dist/server.d.ts +14 -0
  69. package/dist/server.js +2195 -0
  70. package/dist/server.mjs +47 -0
  71. package/dist/service.d.mts +11 -0
  72. package/dist/service.d.ts +11 -0
  73. package/dist/service.js +1809 -0
  74. package/dist/service.mjs +25 -0
  75. package/dist/signIn-C8f6qVjD.d.mts +238 -0
  76. package/dist/signIn-Cy2lbEXb.d.ts +238 -0
  77. package/dist/types-Cxl3bQHt.d.mts +900 -0
  78. package/dist/types-Cxl3bQHt.d.ts +900 -0
  79. package/docs/APP_INTEGRATION_MATRIX.md +59 -0
  80. package/docs/BROWSER_SESSION_MIGRATION.md +69 -0
  81. package/docs/FRESH_IMPLEMENTATION_GUIDE.md +188 -0
  82. package/docs/TARBALL_RELEASE_WORKFLOW.md +98 -0
  83. package/docs/V1_TO_V2_UPGRADE_GUIDE.md +318 -0
  84. package/docs/guides/api-keys.md +130 -0
  85. package/docs/guides/app-registration.md +149 -0
  86. package/docs/guides/auth-flows.md +168 -0
  87. package/docs/guides/branding.md +160 -0
  88. package/docs/guides/entitlements.md +115 -0
  89. package/docs/guides/entity-hierarchy.md +200 -0
  90. package/docs/guides/error-handling.md +251 -0
  91. package/docs/guides/gdpr-compliance.md +123 -0
  92. package/docs/guides/invitations.md +143 -0
  93. package/docs/guides/mfa-enrollment.md +170 -0
  94. package/docs/guides/middleware-reference.md +205 -0
  95. package/docs/guides/mobile-native.md +110 -0
  96. package/docs/guides/roles-and-permissions.md +220 -0
  97. package/docs/guides/scoped-authorization.md +247 -0
  98. package/docs/guides/server-platform-integration.md +52 -0
  99. package/docs/guides/service-automation-integration.md +36 -0
  100. package/docs/guides/session-management.md +97 -0
  101. package/docs/guides/tenant-management.md +216 -0
  102. package/docs/guides/token-verification.md +178 -0
  103. package/docs/guides/user-management.md +184 -0
  104. package/docs/guides/webhooks.md +136 -0
  105. package/docs/integration-prompts/README.md +20 -0
  106. package/docs/integration-prompts/first-party-browser-app.md +29 -0
  107. package/docs/integration-prompts/install-from-tarball.md +41 -0
  108. package/docs/integration-prompts/migrate-from-local-packages-source.md +57 -0
  109. package/docs/integration-prompts/native-mobile-app.md +24 -0
  110. package/docs/integration-prompts/server-platform-app.md +20 -0
  111. package/docs/integration-prompts/service-automation-app.md +20 -0
  112. package/package.json +115 -0
@@ -0,0 +1,1809 @@
1
+ "use strict";
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __export = (target, all) => {
9
+ for (var name in all)
10
+ __defProp(target, name, { get: all[name], enumerable: true });
11
+ };
12
+ var __copyProps = (to, from, except, desc) => {
13
+ if (from && typeof from === "object" || typeof from === "function") {
14
+ for (let key of __getOwnPropNames(from))
15
+ if (!__hasOwnProp.call(to, key) && key !== except)
16
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
17
+ }
18
+ return to;
19
+ };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
+ mod
27
+ ));
28
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
+
30
+ // src/service.ts
31
+ var service_exports = {};
32
+ __export(service_exports, {
33
+ ErrorCodes: () => ErrorCodes,
34
+ IQAuthClient: () => IQAuthClient,
35
+ IQAuthError: () => IQAuthError,
36
+ ServiceIQAuthClient: () => ServiceIQAuthClient,
37
+ createServiceClient: () => createServiceClient
38
+ });
39
+ module.exports = __toCommonJS(service_exports);
40
+
41
+ // src/errors.ts
42
+ var IQAuthError = class extends Error {
43
+ constructor(code, message, status, raw) {
44
+ super(message);
45
+ this.name = "IQAuthError";
46
+ this.code = code;
47
+ this.status = status;
48
+ this.raw = raw;
49
+ }
50
+ };
51
+ var ErrorCodes = {
52
+ VALIDATION_ERROR: "VALIDATION_ERROR",
53
+ INVALID_CREDENTIALS: "INVALID_CREDENTIALS",
54
+ ACCOUNT_INACTIVE: "ACCOUNT_INACTIVE",
55
+ ACCOUNT_LOCKED: "ACCOUNT_LOCKED",
56
+ INSUFFICIENT_PERMISSIONS: "INSUFFICIENT_PERMISSIONS",
57
+ TOKEN_INVALID: "TOKEN_INVALID",
58
+ TOKEN_EXPIRED: "TOKEN_EXPIRED",
59
+ TOKEN_REVOKED: "TOKEN_REVOKED",
60
+ USER_INACTIVE: "USER_INACTIVE",
61
+ INTERNAL_ERROR: "INTERNAL_ERROR",
62
+ NOT_FOUND: "NOT_FOUND",
63
+ SESSION_INVALID: "SESSION_INVALID",
64
+ SESSION_EXPIRED: "SESSION_EXPIRED",
65
+ REFRESH_TOKEN_REUSED: "REFRESH_TOKEN_REUSED",
66
+ PASSWORD_EXPIRED: "PASSWORD_EXPIRED",
67
+ PIN_EXPIRED: "PIN_EXPIRED",
68
+ PASSWORD_POLICY_VIOLATION: "PASSWORD_POLICY_VIOLATION",
69
+ MFA_INVALID_CODE: "MFA_INVALID_CODE",
70
+ MFA_METHOD_UNAVAILABLE: "MFA_METHOD_UNAVAILABLE",
71
+ MFA_RATE_LIMITED: "MFA_RATE_LIMITED",
72
+ MFA_ENROLLMENT_REQUIRED: "MFA_ENROLLMENT_REQUIRED",
73
+ API_KEY_REQUIRED: "API_KEY_REQUIRED",
74
+ API_KEY_INVALID: "API_KEY_INVALID",
75
+ AUTH_REQUIRED: "AUTH_REQUIRED",
76
+ ALREADY_EXISTS: "ALREADY_EXISTS",
77
+ FORBIDDEN: "FORBIDDEN",
78
+ OAUTH_NOT_CONFIGURED: "OAUTH_NOT_CONFIGURED",
79
+ UPLOAD_ERROR: "UPLOAD_ERROR",
80
+ EMAIL_SERVICE_UNAVAILABLE: "EMAIL_SERVICE_UNAVAILABLE",
81
+ INVALID_CODE: "INVALID_CODE",
82
+ CODE_ALREADY_USED: "CODE_ALREADY_USED",
83
+ CODE_EXPIRED: "CODE_EXPIRED",
84
+ CODE_IP_MISMATCH: "CODE_IP_MISMATCH",
85
+ UNKNOWN_PAYLOAD: "UNKNOWN_PAYLOAD"
86
+ };
87
+
88
+ // src/http.ts
89
+ var DEFAULT_RETRY = {
90
+ maxAttempts: 3,
91
+ baseDelayMs: 100,
92
+ maxDelayMs: 2e3
93
+ };
94
+ function resolveRetry(cfg) {
95
+ return {
96
+ maxAttempts: Math.max(1, cfg?.maxAttempts ?? DEFAULT_RETRY.maxAttempts),
97
+ baseDelayMs: Math.max(0, cfg?.baseDelayMs ?? DEFAULT_RETRY.baseDelayMs),
98
+ maxDelayMs: Math.max(0, cfg?.maxDelayMs ?? DEFAULT_RETRY.maxDelayMs)
99
+ };
100
+ }
101
+ function sleep(ms) {
102
+ if (ms <= 0) return Promise.resolve();
103
+ return new Promise((resolve) => setTimeout(resolve, ms));
104
+ }
105
+ var HttpClient = class {
106
+ constructor(config) {
107
+ this.refreshPromise = null;
108
+ this.config = config;
109
+ this.retryConfig = resolveRetry(config.retry);
110
+ }
111
+ computeBackoffDelay(attempt) {
112
+ const exp = Math.min(this.retryConfig.maxDelayMs, this.retryConfig.baseDelayMs * 2 ** (attempt - 1));
113
+ return Math.floor(Math.random() * exp);
114
+ }
115
+ isRetryableStatus(status) {
116
+ return status === 429 || status >= 500 && status <= 599;
117
+ }
118
+ async fetchWithRetry(url, init) {
119
+ const { maxAttempts } = this.retryConfig;
120
+ let lastError;
121
+ for (let attempt = 1; attempt <= maxAttempts; attempt++) {
122
+ try {
123
+ const res = await fetch(url, init);
124
+ if (this.isRetryableStatus(res.status) && attempt < maxAttempts) {
125
+ await sleep(this.computeBackoffDelay(attempt));
126
+ continue;
127
+ }
128
+ return res;
129
+ } catch (err) {
130
+ lastError = err;
131
+ if (attempt >= maxAttempts) break;
132
+ await sleep(this.computeBackoffDelay(attempt));
133
+ }
134
+ }
135
+ throw lastError instanceof Error ? lastError : new IQAuthError("INTERNAL_ERROR", "Network request failed");
136
+ }
137
+ get baseUrl() {
138
+ return this.config.baseUrl;
139
+ }
140
+ get environment() {
141
+ return this.config.environment;
142
+ }
143
+ isBrowserSession() {
144
+ return this.config.environment === "browser_session";
145
+ }
146
+ hasCredentials() {
147
+ return this.isBrowserSession() || !!(this.config.getApiKey() || this.config.getAccessToken());
148
+ }
149
+ buildHeaders(overrideAuth) {
150
+ const headers = {
151
+ "Content-Type": "application/json"
152
+ };
153
+ if (this.isBrowserSession()) {
154
+ const headerName = this.config.sessionHeaderName || "x-iqauth-session";
155
+ headers[headerName] = this.config.sessionHeaderValue || "cookie";
156
+ return headers;
157
+ }
158
+ const authMode = overrideAuth || (this.config.getApiKey() ? "apikey" : "bearer");
159
+ if (authMode === "apikey") {
160
+ const apiKey = this.config.getApiKey();
161
+ if (apiKey) {
162
+ headers["X-API-Key"] = apiKey;
163
+ }
164
+ } else {
165
+ const token = this.config.getAccessToken();
166
+ if (token) {
167
+ headers["Authorization"] = `Bearer ${token}`;
168
+ }
169
+ }
170
+ return headers;
171
+ }
172
+ isTokenExpiringSoon() {
173
+ const token = this.config.getAccessToken();
174
+ if (!token) return false;
175
+ try {
176
+ const parts = token.split(".");
177
+ if (parts.length !== 3) return false;
178
+ const payload = JSON.parse(
179
+ typeof atob === "function" ? atob(parts[1].replace(/-/g, "+").replace(/_/g, "/")) : Buffer.from(parts[1], "base64url").toString("utf8")
180
+ );
181
+ if (!payload.exp) return false;
182
+ const now = Math.floor(Date.now() / 1e3);
183
+ return payload.exp - now < 60;
184
+ } catch {
185
+ return false;
186
+ }
187
+ }
188
+ async attemptRefresh() {
189
+ if (this.refreshPromise) {
190
+ return this.refreshPromise;
191
+ }
192
+ this.refreshPromise = (async () => {
193
+ try {
194
+ const res = await this.fetchWithRetry(`${this.config.baseUrl}/api/v1/auth/refresh`, {
195
+ method: "POST",
196
+ headers: this.buildHeaders(),
197
+ ...this.isBrowserSession() ? { credentials: "include" } : (() => {
198
+ const refreshToken = this.config.getRefreshToken();
199
+ if (!refreshToken) throw new IQAuthError("TOKEN_INVALID", "No refresh token available");
200
+ return { body: JSON.stringify({ refreshToken }) };
201
+ })()
202
+ });
203
+ const body = await res.json();
204
+ if (!body.success) {
205
+ throw new IQAuthError(
206
+ body.error.code,
207
+ body.error.message,
208
+ res.status,
209
+ body
210
+ );
211
+ }
212
+ if (this.isBrowserSession()) {
213
+ return;
214
+ }
215
+ if (!body.data.accessToken || !body.data.refreshToken) {
216
+ throw new IQAuthError("TOKEN_INVALID", "Refresh response did not include a token pair");
217
+ }
218
+ const tokens = {
219
+ accessToken: body.data.accessToken,
220
+ refreshToken: body.data.refreshToken
221
+ };
222
+ this.config.setTokens(tokens);
223
+ this.config.onTokenRefresh?.(tokens);
224
+ } finally {
225
+ this.refreshPromise = null;
226
+ }
227
+ })();
228
+ return this.refreshPromise;
229
+ }
230
+ async request(method, path, body, options) {
231
+ return this.requestWithRetry(method, path, body, options, false);
232
+ }
233
+ async requestWithRetry(method, path, body, options, hasRetried) {
234
+ if (this.config.autoRefresh && !options?.skipAutoRefresh && !this.isBrowserSession() && this.config.getRefreshToken() && this.isTokenExpiringSoon()) {
235
+ await this.attemptRefresh();
236
+ }
237
+ const url = `${this.config.baseUrl}${path}`;
238
+ const headers = this.buildHeaders(options?.authMode);
239
+ const fetchOptions = {
240
+ method,
241
+ headers,
242
+ ...this.isBrowserSession() ? { credentials: "include" } : {}
243
+ };
244
+ if (body !== void 0 && method !== "GET") {
245
+ fetchOptions.body = JSON.stringify(body);
246
+ }
247
+ const res = await this.fetchWithRetry(url, fetchOptions);
248
+ if (res.status === 204) {
249
+ return void 0;
250
+ }
251
+ const responseBody = await res.json();
252
+ if (!responseBody.success) {
253
+ const shouldRetryRefresh = !hasRetried && this.config.autoRefresh && !options?.skipAutoRefresh && responseBody.error.code === "TOKEN_EXPIRED" && (this.isBrowserSession() || !!this.config.getRefreshToken());
254
+ if (shouldRetryRefresh) {
255
+ await this.attemptRefresh();
256
+ return this.requestWithRetry(method, path, body, options, true);
257
+ }
258
+ throw new IQAuthError(
259
+ responseBody.error.code,
260
+ responseBody.error.message,
261
+ res.status,
262
+ responseBody
263
+ );
264
+ }
265
+ return responseBody.data;
266
+ }
267
+ async requestRaw(method, path, body) {
268
+ const url = `${this.config.baseUrl}${path}`;
269
+ const headers = { "Content-Type": "application/json" };
270
+ if (this.isBrowserSession()) {
271
+ const headerName = this.config.sessionHeaderName || "x-iqauth-session";
272
+ headers[headerName] = this.config.sessionHeaderValue || "cookie";
273
+ }
274
+ const token = this.config.getAccessToken();
275
+ if (token) {
276
+ headers["Authorization"] = `Bearer ${token}`;
277
+ }
278
+ const fetchOptions = { method, headers };
279
+ if (this.isBrowserSession()) {
280
+ fetchOptions.credentials = "include";
281
+ }
282
+ if (body !== void 0 && method !== "GET") {
283
+ fetchOptions.body = JSON.stringify(body);
284
+ }
285
+ const res = await fetch(url, fetchOptions);
286
+ return await res.json();
287
+ }
288
+ };
289
+
290
+ // src/modules/auth.ts
291
+ function parseLoginResponse(data, browserSessionMode) {
292
+ if (data.accessToken && data.refreshToken && data.user) {
293
+ return {
294
+ status: "authenticated",
295
+ authMode: "token",
296
+ tokens: { accessToken: data.accessToken, refreshToken: data.refreshToken },
297
+ user: data.user
298
+ };
299
+ }
300
+ if (browserSessionMode && data.user) {
301
+ return {
302
+ status: "authenticated",
303
+ authMode: "session",
304
+ user: data.user
305
+ };
306
+ }
307
+ if (data.mfaChallengeToken && !data.tenantSelectionToken) {
308
+ return {
309
+ status: "mfa_required",
310
+ mfaChallengeToken: data.mfaChallengeToken,
311
+ availableMethods: data.availableMethods ?? []
312
+ };
313
+ }
314
+ if (data.tenantSelectionToken && data.tenants) {
315
+ return {
316
+ status: "tenant_selection",
317
+ tenantSelectionToken: data.tenantSelectionToken,
318
+ tenants: data.tenants
319
+ };
320
+ }
321
+ throw new Error("Unexpected login response shape");
322
+ }
323
+ var AuthModule = class {
324
+ constructor(http) {
325
+ this.http = http;
326
+ }
327
+ async login(email, password) {
328
+ const data = await this.http.request(
329
+ "POST",
330
+ "/api/v1/auth/login",
331
+ { email, password },
332
+ { skipAutoRefresh: true }
333
+ );
334
+ return parseLoginResponse(data, this.http.isBrowserSession());
335
+ }
336
+ async signup(input) {
337
+ const data = await this.http.request(
338
+ "POST",
339
+ "/api/v1/auth/signup",
340
+ input,
341
+ { skipAutoRefresh: true }
342
+ );
343
+ return parseLoginResponse(data, this.http.isBrowserSession());
344
+ }
345
+ async completeMfa(mfaChallengeToken, code, method) {
346
+ const data = await this.http.request(
347
+ "POST",
348
+ "/api/v1/mfa/verify",
349
+ { mfaChallengeToken, code, method },
350
+ { skipAutoRefresh: true }
351
+ );
352
+ return parseMfaResponse(data, this.http.isBrowserSession());
353
+ }
354
+ async completeMfaWithBackup(mfaChallengeToken, backupCode) {
355
+ const data = await this.http.request(
356
+ "POST",
357
+ "/api/v1/mfa/verify-backup",
358
+ { mfaChallengeToken, backupCode },
359
+ { skipAutoRefresh: true }
360
+ );
361
+ return parseMfaResponse(data, this.http.isBrowserSession());
362
+ }
363
+ async sendMfaChallenge(mfaChallengeToken, method) {
364
+ return this.http.request("POST", "/api/v1/mfa/challenge", {
365
+ mfaChallengeToken,
366
+ method
367
+ }, { skipAutoRefresh: true });
368
+ }
369
+ async selectTenant(tenantSelectionToken, tenantId) {
370
+ const data = await this.http.request(
371
+ "POST",
372
+ "/api/v1/auth/select-tenant",
373
+ {
374
+ tenantSelectionToken,
375
+ tenantId
376
+ },
377
+ { skipAutoRefresh: true }
378
+ );
379
+ return parseLoginResponse(data, this.http.isBrowserSession());
380
+ }
381
+ async logout() {
382
+ return this.http.request("POST", "/api/v1/auth/logout");
383
+ }
384
+ async logoutAll() {
385
+ return this.http.request("POST", "/api/v1/auth/logout-all");
386
+ }
387
+ async refreshTokens(refreshToken) {
388
+ if (this.http.isBrowserSession()) {
389
+ throw new Error("refreshTokens(refreshToken) is not used in browser_session mode; the backend session should own refresh.");
390
+ }
391
+ const data = await this.http.request(
392
+ "POST",
393
+ "/api/v1/auth/refresh",
394
+ { refreshToken },
395
+ { skipAutoRefresh: true }
396
+ );
397
+ return { accessToken: data.accessToken, refreshToken: data.refreshToken };
398
+ }
399
+ async forgotPassword(email) {
400
+ return this.http.request("POST", "/api/v1/auth/password/reset/request", { email }, { skipAutoRefresh: true });
401
+ }
402
+ async resetPassword(token, newPassword) {
403
+ return this.http.request("POST", "/api/v1/auth/password/reset/confirm", { token, newPassword }, { skipAutoRefresh: true });
404
+ }
405
+ async changePassword(currentPassword, newPassword) {
406
+ return this.http.request("POST", "/api/v1/auth/password/change", {
407
+ currentPassword,
408
+ newPassword
409
+ });
410
+ }
411
+ async verifyToken() {
412
+ return this.http.request("GET", "/api/v1/auth/verify");
413
+ }
414
+ async exchangeOAuthCode(code) {
415
+ const data = await this.http.request(
416
+ "POST",
417
+ "/api/v1/auth/oauth/exchange",
418
+ { code },
419
+ { skipAutoRefresh: true }
420
+ );
421
+ return parseLoginResponse(data, this.http.isBrowserSession());
422
+ }
423
+ async getSessionUser() {
424
+ return this.http.request("GET", "/api/v1/auth/me");
425
+ }
426
+ };
427
+ function parseMfaResponse(data, browserSessionMode) {
428
+ if (data.accessToken && data.refreshToken && data.user) {
429
+ return {
430
+ authMode: "token",
431
+ tokens: { accessToken: data.accessToken, refreshToken: data.refreshToken },
432
+ user: data.user,
433
+ ...data.remainingBackupCodes !== void 0 ? { remainingBackupCodes: data.remainingBackupCodes } : {},
434
+ ...data.warning ? { warning: data.warning } : {}
435
+ };
436
+ }
437
+ if (browserSessionMode && data.user) {
438
+ return {
439
+ authMode: "session",
440
+ user: data.user,
441
+ ...data.remainingBackupCodes !== void 0 ? { remainingBackupCodes: data.remainingBackupCodes } : {},
442
+ ...data.warning ? { warning: data.warning } : {}
443
+ };
444
+ }
445
+ throw new Error("Unexpected MFA response shape");
446
+ }
447
+
448
+ // src/modules/tokens.ts
449
+ var import_crypto = __toESM(require("crypto"));
450
+ var import_jsonwebtoken = __toESM(require("jsonwebtoken"));
451
+ var JWKS_CACHE_TTL_MS = 60 * 60 * 1e3;
452
+ var DEFAULT_TOKEN_ISSUER = "auth.dispositioniq.com";
453
+ var DEFAULT_TOKEN_AUDIENCE = [
454
+ "dispositioniq",
455
+ "iqcapture",
456
+ "iqreuse",
457
+ "iqvalidate"
458
+ ];
459
+ var DEFAULT_CLOCK_TOLERANCE_SECONDS = 30;
460
+ var TokensModule = class {
461
+ constructor(baseUrl, options = {}) {
462
+ this.jwksCache = null;
463
+ this.inFlightRefresh = null;
464
+ this.baseUrl = baseUrl;
465
+ this.defaultIssuer = options.issuer ?? DEFAULT_TOKEN_ISSUER;
466
+ this.defaultAudience = options.audience ?? DEFAULT_TOKEN_AUDIENCE;
467
+ this.defaultClockTolerance = options.clockTolerance ?? DEFAULT_CLOCK_TOLERANCE_SECONDS;
468
+ }
469
+ /**
470
+ * Verify a JWT access token using RS256 via JWKS from /.well-known/jwks.json.
471
+ * Caches JWKS keys for 1 hour. Retries once on unknown `kid`.
472
+ *
473
+ * @remarks Validates against /.well-known/jwks.json. Issuer, audience, and
474
+ * clock tolerance default to client config but can be overridden per call.
475
+ */
476
+ async verify(token, options = {}) {
477
+ const decoded = import_jsonwebtoken.default.decode(token, { complete: true });
478
+ if (!decoded || typeof decoded === "string") {
479
+ throw new IQAuthError("TOKEN_INVALID", "Unable to decode token");
480
+ }
481
+ const kid = decoded.header.kid;
482
+ if (!kid) {
483
+ throw new IQAuthError("TOKEN_INVALID", "Token missing kid header");
484
+ }
485
+ let publicKey = await this.getPublicKey(kid);
486
+ if (!publicKey) {
487
+ await this.refreshJwks();
488
+ publicKey = await this.getPublicKey(kid);
489
+ }
490
+ if (!publicKey) {
491
+ throw new IQAuthError("TOKEN_INVALID", `Unknown key ID: ${kid}`);
492
+ }
493
+ const issuer = options.issuer ?? this.defaultIssuer;
494
+ const audience = options.audience ?? this.defaultAudience;
495
+ const clockTolerance = options.clockTolerance ?? this.defaultClockTolerance;
496
+ const algorithms = options.algorithms ?? ["RS256"];
497
+ try {
498
+ const verifyOptions = {
499
+ algorithms,
500
+ clockTolerance,
501
+ // The jsonwebtoken types insist on tuple types for arrays; runtime
502
+ // accepts plain string[] so we cast to satisfy the compiler.
503
+ issuer,
504
+ audience
505
+ };
506
+ const verified = import_jsonwebtoken.default.verify(token, publicKey, verifyOptions);
507
+ return verified;
508
+ } catch (err) {
509
+ if (err instanceof Error) {
510
+ if (err.name === "TokenExpiredError") {
511
+ throw new IQAuthError("TOKEN_EXPIRED", "Token has expired");
512
+ }
513
+ throw new IQAuthError("TOKEN_INVALID", err.message);
514
+ }
515
+ throw new IQAuthError("TOKEN_INVALID", "Token verification failed");
516
+ }
517
+ }
518
+ /**
519
+ * Decode a JWT without verification. Returns null if malformed.
520
+ *
521
+ * @remarks Local decode only — no network call
522
+ */
523
+ decode(token) {
524
+ const decoded = import_jsonwebtoken.default.decode(token);
525
+ return decoded;
526
+ }
527
+ /**
528
+ * Check if a token is expired based on the `exp` claim.
529
+ *
530
+ * @remarks Local check only — no network call
531
+ */
532
+ isExpired(token) {
533
+ const claims = this.decode(token);
534
+ if (!claims?.exp) return true;
535
+ const now = Math.floor(Date.now() / 1e3);
536
+ return claims.exp <= now;
537
+ }
538
+ /**
539
+ * Get the claims from a token without verification.
540
+ *
541
+ * @remarks Local decode only — no network call
542
+ */
543
+ getClaims(token) {
544
+ const claims = this.decode(token);
545
+ if (!claims) {
546
+ throw new IQAuthError("TOKEN_INVALID", "Unable to decode token claims");
547
+ }
548
+ return claims;
549
+ }
550
+ async getPublicKey(kid) {
551
+ if (!this.jwksCache || Date.now() - this.jwksCache.fetchedAt > JWKS_CACHE_TTL_MS) {
552
+ await this.refreshJwks();
553
+ }
554
+ return this.jwksCache?.keys.get(kid) ?? null;
555
+ }
556
+ async refreshJwks() {
557
+ if (this.inFlightRefresh) {
558
+ return this.inFlightRefresh;
559
+ }
560
+ this.inFlightRefresh = (async () => {
561
+ try {
562
+ const res = await fetch(`${this.baseUrl}/.well-known/jwks.json`);
563
+ if (!res.ok) {
564
+ throw new IQAuthError(
565
+ "INTERNAL_ERROR",
566
+ `Failed to fetch JWKS: ${res.status}`
567
+ );
568
+ }
569
+ let jwks;
570
+ try {
571
+ jwks = await res.json();
572
+ } catch {
573
+ throw new IQAuthError("INTERNAL_ERROR", "Malformed JWKS response: invalid JSON");
574
+ }
575
+ if (!jwks || !Array.isArray(jwks.keys)) {
576
+ throw new IQAuthError(
577
+ "INTERNAL_ERROR",
578
+ "Malformed JWKS response: expected { keys: [...] }"
579
+ );
580
+ }
581
+ const keys = /* @__PURE__ */ new Map();
582
+ for (const key of jwks.keys) {
583
+ if (!key || typeof key.kid !== "string" || typeof key.n !== "string" || typeof key.e !== "string") {
584
+ throw new IQAuthError(
585
+ "INTERNAL_ERROR",
586
+ "Malformed JWKS response: key missing required fields"
587
+ );
588
+ }
589
+ const pem = this.jwkToPem(key);
590
+ keys.set(key.kid, pem);
591
+ }
592
+ this.jwksCache = { keys, fetchedAt: Date.now() };
593
+ } finally {
594
+ this.inFlightRefresh = null;
595
+ }
596
+ })();
597
+ return this.inFlightRefresh;
598
+ }
599
+ jwkToPem(jwk) {
600
+ const keyObject = import_crypto.default.createPublicKey({
601
+ key: {
602
+ kty: jwk.kty,
603
+ n: jwk.n,
604
+ e: jwk.e
605
+ },
606
+ format: "jwk"
607
+ });
608
+ return keyObject.export({ type: "spki", format: "pem" });
609
+ }
610
+ /** @internal Exposed for testing — clears JWKS cache */
611
+ clearCache() {
612
+ this.jwksCache = null;
613
+ }
614
+ };
615
+
616
+ // src/modules/sessions.ts
617
+ var SessionsModule = class {
618
+ constructor(http) {
619
+ this.http = http;
620
+ }
621
+ /**
622
+ * List all active sessions for the current user.
623
+ *
624
+ * @remarks Wraps GET /api/v1/sessions
625
+ */
626
+ async list() {
627
+ return this.http.request("GET", "/api/v1/sessions");
628
+ }
629
+ /**
630
+ * Revoke (terminate) a specific session by ID.
631
+ *
632
+ * @remarks Wraps DELETE /api/v1/sessions/:sessionId
633
+ */
634
+ async revoke(sessionId) {
635
+ return this.http.request("DELETE", `/api/v1/sessions/${sessionId}`);
636
+ }
637
+ /**
638
+ * Revoke all sessions for the current user.
639
+ *
640
+ * @remarks Wraps POST /api/v1/auth/logout-all
641
+ */
642
+ async revokeAll() {
643
+ return this.http.request("POST", "/api/v1/auth/logout-all");
644
+ }
645
+ };
646
+
647
+ // src/modules/users.ts
648
+ var UsersModule = class {
649
+ constructor(http) {
650
+ this.http = http;
651
+ }
652
+ /**
653
+ * Get the currently authenticated user's profile.
654
+ *
655
+ * @remarks Wraps GET /api/v1/users/me
656
+ */
657
+ async getCurrent() {
658
+ return this.http.request("GET", "/api/v1/users/me");
659
+ }
660
+ /**
661
+ * Get a user by ID.
662
+ *
663
+ * @remarks Wraps GET /api/v1/users/:id
664
+ */
665
+ async getById(userId) {
666
+ return this.http.request("GET", `/api/v1/users/${userId}`);
667
+ }
668
+ /**
669
+ * List users in the current tenant. Requires tenant_admin role.
670
+ *
671
+ * @remarks Wraps GET /api/v1/users
672
+ */
673
+ async list(params) {
674
+ const query = new URLSearchParams();
675
+ if (params?.email) query.set("email", params.email);
676
+ if (params?.tenantId) query.set("tenantId", params.tenantId);
677
+ const qs = query.toString();
678
+ return this.http.request("GET", `/api/v1/users${qs ? `?${qs}` : ""}`);
679
+ }
680
+ /**
681
+ * Provision (create) a new user in a tenant. Requires platform_admin or tenant-scoped API key with admin role.
682
+ *
683
+ * @remarks Wraps POST /api/v1/tenants/:tenantId/users/provision
684
+ */
685
+ async create(tenantId, data) {
686
+ return this.http.request("POST", `/api/v1/tenants/${tenantId}/users/provision`, data);
687
+ }
688
+ /**
689
+ * Update the current user's profile (name, picture).
690
+ *
691
+ * @remarks Wraps PATCH /api/v1/users/me
692
+ */
693
+ async update(data) {
694
+ return this.http.request("PATCH", "/api/v1/users/me", data);
695
+ }
696
+ /**
697
+ * Deactivate a user in the current tenant. Requires tenant_admin role.
698
+ *
699
+ * @remarks Wraps PATCH /api/v1/users/:id/deactivate
700
+ */
701
+ async deactivate(userId) {
702
+ return this.http.request("PATCH", `/api/v1/users/${userId}/deactivate`);
703
+ }
704
+ /**
705
+ * Reactivate a user in the current tenant. Requires tenant_admin role.
706
+ *
707
+ * @remarks Wraps PATCH /api/v1/users/:id/reactivate
708
+ */
709
+ async reactivate(userId) {
710
+ return this.http.request("PATCH", `/api/v1/users/${userId}/reactivate`);
711
+ }
712
+ /**
713
+ * Unlock a locked user account in the current tenant. Requires tenant_admin role.
714
+ *
715
+ * @remarks Wraps PATCH /api/v1/users/:id/unlock
716
+ */
717
+ async unlock(userId) {
718
+ return this.http.request("PATCH", `/api/v1/users/${userId}/unlock`);
719
+ }
720
+ /**
721
+ * Get effective permissions for a user for a specific product.
722
+ *
723
+ * @remarks Wraps GET /api/v1/users/:id/permissions?product=...
724
+ */
725
+ async getPermissions(userId, product) {
726
+ return this.http.request("GET", `/api/v1/users/${userId}/permissions?product=${encodeURIComponent(product)}`);
727
+ }
728
+ /**
729
+ * Change the current user's password.
730
+ *
731
+ * @remarks Wraps POST /api/v1/auth/password/change
732
+ */
733
+ async updatePassword(currentPassword, newPassword) {
734
+ return this.http.request("POST", "/api/v1/auth/password/change", {
735
+ currentPassword,
736
+ newPassword
737
+ });
738
+ }
739
+ };
740
+
741
+ // src/modules/permissions.ts
742
+ var PermissionsModule = class {
743
+ constructor(claimsProvider) {
744
+ this.getClaims = claimsProvider;
745
+ }
746
+ /**
747
+ * Get the roles from the current JWT claims.
748
+ *
749
+ * @remarks Extracted from JWT claim `roles` (string[])
750
+ */
751
+ getRoles() {
752
+ return this.getClaims()?.roles ?? [];
753
+ }
754
+ /**
755
+ * Get the entitlements from the current JWT claims.
756
+ *
757
+ * @remarks Extracted from JWT claim `entitlements` (string[])
758
+ */
759
+ getEntitlements() {
760
+ return this.getClaims()?.entitlements ?? [];
761
+ }
762
+ /**
763
+ * Check if the current user has a specific role.
764
+ *
765
+ * @remarks Checks against JWT claim `roles`
766
+ */
767
+ hasRole(role) {
768
+ return this.getRoles().includes(role);
769
+ }
770
+ /**
771
+ * Check if the current user has a specific entitlement.
772
+ *
773
+ * @remarks Checks against JWT claim `entitlements`
774
+ */
775
+ hasEntitlement(entitlement) {
776
+ return this.getEntitlements().includes(entitlement);
777
+ }
778
+ /**
779
+ * Check if the current user has all of the specified roles.
780
+ *
781
+ * @remarks Checks against JWT claim `roles`
782
+ */
783
+ hasAllRoles(roles) {
784
+ const userRoles = this.getRoles();
785
+ return roles.every((r) => userRoles.includes(r));
786
+ }
787
+ /**
788
+ * Check if the current user has any of the specified roles.
789
+ *
790
+ * @remarks Checks against JWT claim `roles`
791
+ */
792
+ hasAnyRole(roles) {
793
+ const userRoles = this.getRoles();
794
+ return roles.some((r) => userRoles.includes(r));
795
+ }
796
+ /**
797
+ * Check if the current user has all of the specified entitlements.
798
+ *
799
+ * @remarks Checks against JWT claim `entitlements`
800
+ */
801
+ hasAllEntitlements(entitlements) {
802
+ const userEntitlements = this.getEntitlements();
803
+ return entitlements.every((e) => userEntitlements.includes(e));
804
+ }
805
+ /**
806
+ * Check if the current user has any of the specified entitlements.
807
+ *
808
+ * @remarks Checks against JWT claim `entitlements`
809
+ */
810
+ hasAnyEntitlement(entitlements) {
811
+ const userEntitlements = this.getEntitlements();
812
+ return entitlements.some((e) => userEntitlements.includes(e));
813
+ }
814
+ };
815
+
816
+ // src/modules/oidc.ts
817
+ var import_crypto2 = __toESM(require("crypto"));
818
+ var InMemoryOidcStateStore = class {
819
+ constructor() {
820
+ this.map = /* @__PURE__ */ new Map();
821
+ }
822
+ set(state, value) {
823
+ this.map.set(state, value);
824
+ }
825
+ get(state) {
826
+ const entry = this.map.get(state);
827
+ if (!entry) return null;
828
+ if (entry.expiresAt < Date.now()) {
829
+ this.map.delete(state);
830
+ return null;
831
+ }
832
+ return entry;
833
+ }
834
+ delete(state) {
835
+ this.map.delete(state);
836
+ }
837
+ };
838
+ var DEFAULT_REQUEST_TTL_MS = 10 * 60 * 1e3;
839
+ function base64UrlEncode(buf) {
840
+ return buf.toString("base64").replace(/=/g, "").replace(/\+/g, "-").replace(/\//g, "_");
841
+ }
842
+ var OidcModule = class {
843
+ constructor(http, baseUrl, options = {}) {
844
+ this.http = http;
845
+ this.baseUrl = baseUrl;
846
+ this.stateStore = options.stateStore ?? new InMemoryOidcStateStore();
847
+ this.requestTtlMs = options.requestTtlMs ?? DEFAULT_REQUEST_TTL_MS;
848
+ this.tokensModule = options.tokens;
849
+ }
850
+ /** @internal Allow the client to inject its TokensModule after construction. */
851
+ _setTokensModule(tokens) {
852
+ if (!this.tokensModule) this.tokensModule = tokens;
853
+ }
854
+ /**
855
+ * Fetch the OpenID Connect discovery document.
856
+ *
857
+ * @remarks Wraps GET /.well-known/openid-configuration
858
+ */
859
+ async getDiscovery() {
860
+ const res = await fetch(`${this.baseUrl}/.well-known/openid-configuration`);
861
+ if (!res.ok) throw new Error(`Failed to fetch OIDC discovery: ${res.status}`);
862
+ return res.json();
863
+ }
864
+ /**
865
+ * Fetch the JSON Web Key Set.
866
+ *
867
+ * @remarks Wraps GET /.well-known/jwks.json
868
+ */
869
+ async getJwks() {
870
+ const res = await fetch(`${this.baseUrl}/.well-known/jwks.json`);
871
+ if (!res.ok) throw new Error(`Failed to fetch JWKS: ${res.status}`);
872
+ return res.json();
873
+ }
874
+ /**
875
+ * Build an OIDC authorization URL for redirect-based login.
876
+ *
877
+ * @remarks Constructs URL pointing to /oidc/authorize. Prefer
878
+ * {@link createAuthRequest} which also generates and stores PKCE/state/nonce.
879
+ */
880
+ buildAuthorizationUrl(params) {
881
+ const url = new URL("/oidc/authorize", this.baseUrl);
882
+ url.searchParams.set("response_type", "code");
883
+ url.searchParams.set("client_id", params.clientId);
884
+ url.searchParams.set("redirect_uri", params.redirectUri);
885
+ url.searchParams.set("scope", params.scope || "openid");
886
+ url.searchParams.set("state", params.state);
887
+ if (params.nonce) url.searchParams.set("nonce", params.nonce);
888
+ if (params.codeChallenge) url.searchParams.set("code_challenge", params.codeChallenge);
889
+ if (params.codeChallengeMethod) url.searchParams.set("code_challenge_method", params.codeChallengeMethod);
890
+ return url.toString();
891
+ }
892
+ /**
893
+ * Generate `code_verifier`, `code_challenge`, `state`, and `nonce`, persist
894
+ * them via the configured storage adapter, and return an authorization URL
895
+ * ready to redirect the user to.
896
+ */
897
+ async createAuthRequest(params) {
898
+ const codeVerifier = base64UrlEncode(import_crypto2.default.randomBytes(32));
899
+ const codeChallenge = base64UrlEncode(
900
+ import_crypto2.default.createHash("sha256").update(codeVerifier).digest()
901
+ );
902
+ const state = base64UrlEncode(import_crypto2.default.randomBytes(16));
903
+ const nonce = base64UrlEncode(import_crypto2.default.randomBytes(16));
904
+ await this.stateStore.set(state, {
905
+ codeVerifier,
906
+ state,
907
+ nonce,
908
+ redirectUri: params.redirectUri,
909
+ clientId: params.clientId,
910
+ expiresAt: Date.now() + this.requestTtlMs
911
+ });
912
+ const authorizationUrl = this.buildAuthorizationUrl({
913
+ clientId: params.clientId,
914
+ redirectUri: params.redirectUri,
915
+ scope: params.scope,
916
+ state,
917
+ nonce,
918
+ codeChallenge,
919
+ codeChallengeMethod: "S256"
920
+ });
921
+ return {
922
+ authorizationUrl,
923
+ state,
924
+ nonce,
925
+ codeVerifier,
926
+ codeChallenge,
927
+ codeChallengeMethod: "S256"
928
+ };
929
+ }
930
+ /**
931
+ * Validate the callback `state`, exchange the code with the bound PKCE
932
+ * verifier, and verify that the returned `id_token` (if any) carries the
933
+ * stored `nonce` and `aud === clientId`.
934
+ */
935
+ async handleCallback(params) {
936
+ if (!params.state) {
937
+ throw new IQAuthError("VALIDATION_ERROR", "OIDC callback missing state parameter");
938
+ }
939
+ if (!params.code) {
940
+ throw new IQAuthError("VALIDATION_ERROR", "OIDC callback missing code parameter");
941
+ }
942
+ const stored = await this.stateStore.get(params.state);
943
+ if (!stored) {
944
+ throw new IQAuthError("VALIDATION_ERROR", "Unknown or expired OIDC state");
945
+ }
946
+ let tokens;
947
+ try {
948
+ tokens = await this.exchangeCode({
949
+ code: params.code,
950
+ redirectUri: stored.redirectUri,
951
+ clientId: stored.clientId,
952
+ clientSecret: params.clientSecret,
953
+ codeVerifier: stored.codeVerifier
954
+ });
955
+ } finally {
956
+ await this.stateStore.delete(params.state);
957
+ }
958
+ let idTokenClaims = null;
959
+ if (tokens.id_token) {
960
+ if (!this.tokensModule) {
961
+ throw new IQAuthError(
962
+ "INTERNAL_ERROR",
963
+ "OIDC handleCallback received an id_token but no TokensModule is configured for verification"
964
+ );
965
+ }
966
+ idTokenClaims = await this.tokensModule.verify(tokens.id_token, {
967
+ audience: stored.clientId
968
+ });
969
+ const claimsBag = idTokenClaims;
970
+ const tokenNonce = typeof claimsBag.nonce === "string" ? claimsBag.nonce : void 0;
971
+ if (!tokenNonce || tokenNonce !== stored.nonce) {
972
+ throw new IQAuthError(
973
+ "TOKEN_INVALID",
974
+ "OIDC id_token nonce did not match the stored value"
975
+ );
976
+ }
977
+ }
978
+ return { tokens, idTokenClaims };
979
+ }
980
+ /**
981
+ * Exchange an authorization code for tokens at the OIDC token endpoint.
982
+ *
983
+ * @remarks Wraps POST /oidc/token (or /api/v1/oidc/token)
984
+ */
985
+ async exchangeCode(params) {
986
+ const body = {
987
+ grant_type: "authorization_code",
988
+ code: params.code,
989
+ redirect_uri: params.redirectUri,
990
+ client_id: params.clientId
991
+ };
992
+ if (params.clientSecret) body.client_secret = params.clientSecret;
993
+ if (params.codeVerifier) body.code_verifier = params.codeVerifier;
994
+ const res = await fetch(`${this.baseUrl}/oidc/token`, {
995
+ method: "POST",
996
+ headers: { "Content-Type": "application/json" },
997
+ body: JSON.stringify(body)
998
+ });
999
+ if (!res.ok) {
1000
+ const err = await res.json().catch(() => ({}));
1001
+ throw new Error(
1002
+ `OIDC token exchange failed: ${err.error_description || err.error || res.status}`
1003
+ );
1004
+ }
1005
+ return res.json();
1006
+ }
1007
+ /**
1008
+ * Get user info from the OIDC userinfo endpoint.
1009
+ *
1010
+ * @remarks Wraps GET /oidc/userinfo (requires Bearer token)
1011
+ */
1012
+ async getUserInfo() {
1013
+ if (this.http.isBrowserSession()) {
1014
+ throw new Error("oidc.getUserInfo() requires a bearer token and is not supported in browser_session mode.");
1015
+ }
1016
+ return this.http.requestRaw("GET", "/oidc/userinfo");
1017
+ }
1018
+ async getClientContext(clientId) {
1019
+ const res = await fetch(`${this.baseUrl}/oidc/client-context?client_id=${encodeURIComponent(clientId)}`);
1020
+ if (!res.ok) throw new Error(`Failed to fetch OIDC client context: ${res.status}`);
1021
+ const payload = await res.json();
1022
+ if (!payload.success || !payload.data) {
1023
+ throw new Error("OIDC client context response was invalid");
1024
+ }
1025
+ return payload.data;
1026
+ }
1027
+ };
1028
+
1029
+ // src/modules/tenants.ts
1030
+ function normalizeBrandingConfig(config) {
1031
+ return {
1032
+ ...config,
1033
+ brandName: config.brandName ?? config.companyName,
1034
+ loginHeadline: config.loginHeadline ?? config.headline ?? null,
1035
+ loginSubheadline: config.loginSubheadline ?? config.subheadline ?? null,
1036
+ companyName: config.companyName ?? config.brandName,
1037
+ headline: config.headline ?? config.loginHeadline ?? null,
1038
+ subheadline: config.subheadline ?? config.loginSubheadline ?? null
1039
+ };
1040
+ }
1041
+ var TenantsModule = class {
1042
+ constructor(http) {
1043
+ this.http = http;
1044
+ }
1045
+ async getCurrent(tenantId) {
1046
+ return this.http.request("GET", `/api/v1/tenants/${tenantId}`);
1047
+ }
1048
+ async get(tenantId) {
1049
+ return this.http.request("GET", `/api/v1/tenants/${tenantId}`);
1050
+ }
1051
+ async list(params) {
1052
+ const query = new URLSearchParams();
1053
+ if (params?.vendorId) query.set("vendorId", params.vendorId);
1054
+ const qs = query.toString();
1055
+ return this.http.request("GET", `/api/v1/tenants${qs ? `?${qs}` : ""}`);
1056
+ }
1057
+ async create(data) {
1058
+ return this.http.request("POST", "/api/v1/tenants", data);
1059
+ }
1060
+ async update(tenantId, data) {
1061
+ return this.http.request("PATCH", `/api/v1/tenants/${tenantId}`, data);
1062
+ }
1063
+ async delete(tenantId) {
1064
+ return this.http.request("DELETE", `/api/v1/tenants/${tenantId}`);
1065
+ }
1066
+ async promoteToVendor(tenantId, data) {
1067
+ return this.http.request("POST", `/api/v1/tenants/${tenantId}/promote-to-vendor`, data);
1068
+ }
1069
+ async getUsers(tenantId) {
1070
+ return this.http.request("GET", `/api/v1/tenants/${tenantId}/users`);
1071
+ }
1072
+ async inviteUser(tenantId, data) {
1073
+ return this.http.request("POST", `/api/v1/tenants/${tenantId}/users/invite`, data);
1074
+ }
1075
+ async changeUserRole(tenantId, userId, role) {
1076
+ return this.http.request("PATCH", `/api/v1/tenants/${tenantId}/users/${userId}/role`, { role });
1077
+ }
1078
+ async migrateUser(tenantId, userId, data) {
1079
+ return this.http.request("POST", `/api/v1/tenants/${tenantId}/users/${userId}/migrate`, data);
1080
+ }
1081
+ async removeUser(tenantId, userId) {
1082
+ return this.http.request("DELETE", `/api/v1/tenants/${tenantId}/users/${userId}`);
1083
+ }
1084
+ async getPasswordPolicy(tenantId) {
1085
+ return this.http.request("GET", `/api/v1/tenants/${tenantId}/password-policy`);
1086
+ }
1087
+ async updatePasswordPolicy(tenantId, data) {
1088
+ return this.http.request("PATCH", `/api/v1/tenants/${tenantId}/password-policy`, data);
1089
+ }
1090
+ async getMfaPolicies(tenantId) {
1091
+ return this.http.request("GET", `/api/v1/tenants/${tenantId}/mfa-policies`);
1092
+ }
1093
+ async updateMfaPolicy(tenantId, role, data) {
1094
+ return this.http.request("PATCH", `/api/v1/tenants/${tenantId}/mfa-policies/${role}`, data);
1095
+ }
1096
+ async getPublicBranding(params) {
1097
+ const query = new URLSearchParams();
1098
+ if (params?.vendor) query.set("vendor", params.vendor);
1099
+ const qs = query.toString();
1100
+ const url = `${this.http.baseUrl}/api/public/branding${qs ? `?${qs}` : ""}`;
1101
+ const res = await fetch(url);
1102
+ if (!res.ok) return null;
1103
+ const body = await res.json();
1104
+ if (body.success && body.data) return normalizeBrandingConfig(body.data);
1105
+ return null;
1106
+ }
1107
+ async getPublicBrandingBySlug(vendorSlug) {
1108
+ const url = `${this.http.baseUrl}/api/public/branding/by-slug/${encodeURIComponent(vendorSlug)}`;
1109
+ const res = await fetch(url);
1110
+ if (!res.ok) return null;
1111
+ const body = await res.json();
1112
+ if (body.success && body.data) return normalizeBrandingConfig(body.data);
1113
+ return null;
1114
+ }
1115
+ };
1116
+
1117
+ // src/modules/apps.ts
1118
+ var AppsModule = class {
1119
+ constructor(http) {
1120
+ this.http = http;
1121
+ }
1122
+ /**
1123
+ * Self-service Phase A: provision an app + OIDC client + key pair in one shot.
1124
+ * Caller must be authenticated as a tenant_admin (or platform_admin).
1125
+ *
1126
+ * @remarks Wraps POST /api/v1/apps
1127
+ */
1128
+ async create(data) {
1129
+ return this.http.request("POST", "/api/v1/apps", data);
1130
+ }
1131
+ async update(id, data) {
1132
+ return this.http.request("PATCH", `/api/v1/apps/${encodeURIComponent(id)}`, data);
1133
+ }
1134
+ async remove(id) {
1135
+ return this.http.request("DELETE", `/api/v1/apps/${encodeURIComponent(id)}`);
1136
+ }
1137
+ async listOrigins(id) {
1138
+ return this.http.request("GET", `/api/v1/apps/${encodeURIComponent(id)}/origins`);
1139
+ }
1140
+ async addOrigin(id, origin) {
1141
+ return this.http.request("POST", `/api/v1/apps/${encodeURIComponent(id)}/origins`, { origin });
1142
+ }
1143
+ async removeOrigin(id, origin) {
1144
+ return this.http.request("DELETE", `/api/v1/apps/${encodeURIComponent(id)}/origins/${encodeURIComponent(origin)}`);
1145
+ }
1146
+ async listKeys(id) {
1147
+ return this.http.request("GET", `/api/v1/apps/${encodeURIComponent(id)}/keys`);
1148
+ }
1149
+ async createKey(id, data) {
1150
+ return this.http.request("POST", `/api/v1/apps/${encodeURIComponent(id)}/keys`, data);
1151
+ }
1152
+ async rotateKey(id, keyId) {
1153
+ return this.http.request("POST", `/api/v1/apps/${encodeURIComponent(id)}/keys/${encodeURIComponent(keyId)}/rotate`, {});
1154
+ }
1155
+ async revokeKey(id, keyId) {
1156
+ return this.http.request("DELETE", `/api/v1/apps/${encodeURIComponent(id)}/keys/${encodeURIComponent(keyId)}`);
1157
+ }
1158
+ /**
1159
+ * List all registered applications.
1160
+ * Requires `apps.view` permission on the `iqauth-admin` app.
1161
+ *
1162
+ * @remarks Wraps GET /api/v1/apps
1163
+ */
1164
+ async list() {
1165
+ return this.http.request("GET", "/api/v1/apps");
1166
+ }
1167
+ /**
1168
+ * Get a registered application by its unique key, including its permission nodes.
1169
+ * Requires `apps.view` permission on the `iqauth-admin` app.
1170
+ *
1171
+ * @remarks Wraps GET /api/v1/apps/:appKey
1172
+ */
1173
+ async get(appKey) {
1174
+ return this.http.request("GET", `/api/v1/apps/${encodeURIComponent(appKey)}`);
1175
+ }
1176
+ /**
1177
+ * Register or sync an application manifest. This is an idempotent upsert —
1178
+ * it creates the app if it doesn't exist, or updates it if it does.
1179
+ * Permission nodes are also upserted (created or updated) from the manifest tree.
1180
+ *
1181
+ * Requires `platform_admin` role and `apps.manage` permission.
1182
+ *
1183
+ * @remarks Wraps POST /api/v1/apps/sync
1184
+ */
1185
+ async register(manifest) {
1186
+ if (!this.http.hasCredentials()) {
1187
+ throw new IQAuthError(
1188
+ "AUTH_REQUIRED",
1189
+ "Cannot sync app manifest: no API key or access token configured. Initialize the client with an apiKey or accessToken.",
1190
+ 401
1191
+ );
1192
+ }
1193
+ return this.http.request("POST", "/api/v1/apps/sync", manifest);
1194
+ }
1195
+ /**
1196
+ * Check if an application is registered by its key.
1197
+ * Returns `true` if the app exists, `false` otherwise.
1198
+ *
1199
+ * @remarks Uses GET /api/v1/apps/:appKey — catches 404 errors
1200
+ */
1201
+ async isRegistered(appKey) {
1202
+ try {
1203
+ await this.get(appKey);
1204
+ return true;
1205
+ } catch (err) {
1206
+ if (err.code === "NOT_FOUND" || err.status === 404) {
1207
+ return false;
1208
+ }
1209
+ throw err;
1210
+ }
1211
+ }
1212
+ };
1213
+
1214
+ // src/modules/roles.ts
1215
+ var RolesModule = class {
1216
+ constructor(http) {
1217
+ this.http = http;
1218
+ }
1219
+ async list(tenantId) {
1220
+ return this.http.request("GET", `/api/v1/tenants/${tenantId}/roles`);
1221
+ }
1222
+ async create(tenantId, data) {
1223
+ return this.http.request("POST", `/api/v1/tenants/${tenantId}/roles`, data);
1224
+ }
1225
+ async update(tenantId, roleId, data) {
1226
+ return this.http.request("PATCH", `/api/v1/tenants/${tenantId}/roles/${roleId}`, data);
1227
+ }
1228
+ async delete(tenantId, roleId) {
1229
+ return this.http.request("DELETE", `/api/v1/tenants/${tenantId}/roles/${roleId}`);
1230
+ }
1231
+ async getUserRoles(tenantId, userId) {
1232
+ return this.http.request("GET", `/api/v1/tenants/${tenantId}/users/${userId}/roles`);
1233
+ }
1234
+ async assignRole(tenantId, userId, data) {
1235
+ return this.http.request("POST", `/api/v1/tenants/${tenantId}/users/${userId}/roles`, data);
1236
+ }
1237
+ async removeRole(tenantId, userId, roleId) {
1238
+ return this.http.request("DELETE", `/api/v1/tenants/${tenantId}/users/${userId}/roles/${roleId}`);
1239
+ }
1240
+ };
1241
+
1242
+ // src/modules/permissionGroups.ts
1243
+ var PermissionGroupsModule = class {
1244
+ constructor(http) {
1245
+ this.http = http;
1246
+ }
1247
+ async list(tenantId) {
1248
+ return this.http.request("GET", `/api/v1/tenants/${tenantId}/permission-groups`);
1249
+ }
1250
+ async create(tenantId, name, description) {
1251
+ return this.http.request("POST", `/api/v1/tenants/${tenantId}/permission-groups`, { name, description });
1252
+ }
1253
+ async update(tenantId, groupId, data) {
1254
+ return this.http.request("PATCH", `/api/v1/tenants/${tenantId}/permission-groups/${groupId}`, data);
1255
+ }
1256
+ async delete(tenantId, groupId) {
1257
+ return this.http.request("DELETE", `/api/v1/tenants/${tenantId}/permission-groups/${groupId}`);
1258
+ }
1259
+ async getPermissions(tenantId, groupId) {
1260
+ return this.http.request("GET", `/api/v1/tenants/${tenantId}/permission-groups/${groupId}/permissions`);
1261
+ }
1262
+ async addPermission(tenantId, groupId, data) {
1263
+ return this.http.request("POST", `/api/v1/tenants/${tenantId}/permission-groups/${groupId}/permissions`, data);
1264
+ }
1265
+ async removePermission(tenantId, groupId, permissionId) {
1266
+ return this.http.request("DELETE", `/api/v1/tenants/${tenantId}/permission-groups/${groupId}/permissions/${permissionId}`);
1267
+ }
1268
+ async addInheritance(tenantId, groupId, inheritsFromGroupId) {
1269
+ return this.http.request("POST", `/api/v1/tenants/${tenantId}/permission-groups/${groupId}/inherit`, { inheritsFromGroupId });
1270
+ }
1271
+ async removeInheritance(tenantId, groupId, inheritedGroupId) {
1272
+ return this.http.request("DELETE", `/api/v1/tenants/${tenantId}/permission-groups/${groupId}/inherit/${inheritedGroupId}`);
1273
+ }
1274
+ async getUserGroups(tenantId, userId) {
1275
+ return this.http.request("GET", `/api/v1/tenants/${tenantId}/users/${userId}/groups`);
1276
+ }
1277
+ async assignUserToGroup(tenantId, userId, groupId) {
1278
+ return this.http.request("POST", `/api/v1/tenants/${tenantId}/users/${userId}/groups`, { groupId });
1279
+ }
1280
+ async removeUserFromGroup(tenantId, userId, groupId) {
1281
+ return this.http.request("DELETE", `/api/v1/tenants/${tenantId}/users/${userId}/groups/${groupId}`);
1282
+ }
1283
+ async getUserOverrides(tenantId, userId) {
1284
+ return this.http.request("GET", `/api/v1/tenants/${tenantId}/users/${userId}/permissions/overrides`);
1285
+ }
1286
+ async addUserOverride(tenantId, userId, data) {
1287
+ return this.http.request("POST", `/api/v1/tenants/${tenantId}/users/${userId}/permissions/overrides`, data);
1288
+ }
1289
+ async removeUserOverride(tenantId, userId, overrideId) {
1290
+ return this.http.request("DELETE", `/api/v1/tenants/${tenantId}/users/${userId}/permissions/overrides/${overrideId}`);
1291
+ }
1292
+ async getEffectivePermissions(tenantId, userId, params) {
1293
+ const query = new URLSearchParams();
1294
+ if (params.product) query.set("product", params.product);
1295
+ if (params.appKey) query.set("appKey", params.appKey);
1296
+ const qs = query.toString();
1297
+ return this.http.request("GET", `/api/v1/tenants/${tenantId}/users/${userId}/permissions/effective${qs ? `?${qs}` : ""}`);
1298
+ }
1299
+ async checkPermission(tenantId, userId, appKey, nodeKey) {
1300
+ return this.http.request("POST", `/api/v1/tenants/${tenantId}/users/${userId}/permissions/check`, { appKey, nodeKey });
1301
+ }
1302
+ };
1303
+
1304
+ // src/modules/apiKeys.ts
1305
+ var ApiKeysModule = class {
1306
+ constructor(http) {
1307
+ this.http = http;
1308
+ }
1309
+ async create(data) {
1310
+ return this.http.request("POST", "/api/v1/api-keys", data);
1311
+ }
1312
+ async list(params) {
1313
+ const query = new URLSearchParams();
1314
+ if (params?.tenantId) query.set("tenantId", params.tenantId);
1315
+ const qs = query.toString();
1316
+ return this.http.request("GET", `/api/v1/api-keys${qs ? `?${qs}` : ""}`);
1317
+ }
1318
+ async revoke(id) {
1319
+ return this.http.request("DELETE", `/api/v1/api-keys/${id}`);
1320
+ }
1321
+ async introspect(apiKey) {
1322
+ return this.http.request("POST", "/api/v1/api-keys/introspect", { apiKey }, { skipAutoRefresh: true });
1323
+ }
1324
+ };
1325
+
1326
+ // src/modules/invites.ts
1327
+ var InvitesModule = class {
1328
+ constructor(http) {
1329
+ this.http = http;
1330
+ }
1331
+ async create(data) {
1332
+ return this.http.request("POST", "/api/v1/invites", data);
1333
+ }
1334
+ async validate(token) {
1335
+ return this.http.request("GET", `/api/v1/invites/${token}/validate`);
1336
+ }
1337
+ async accept(token, data) {
1338
+ return this.http.request("POST", `/api/v1/invites/${token}/accept`, data, { skipAutoRefresh: true });
1339
+ }
1340
+ };
1341
+
1342
+ // src/modules/webhooks.ts
1343
+ function normalizeWebhookDelivery(delivery) {
1344
+ return {
1345
+ ...delivery,
1346
+ endpointId: delivery.endpointId ?? delivery.webhookEndpointId,
1347
+ webhookEndpointId: delivery.webhookEndpointId ?? delivery.endpointId,
1348
+ event: delivery.event ?? delivery.eventType,
1349
+ eventType: delivery.eventType ?? delivery.event,
1350
+ statusCode: delivery.statusCode ?? delivery.responseStatus ?? null,
1351
+ responseStatus: delivery.responseStatus ?? delivery.statusCode ?? null,
1352
+ response: delivery.response ?? delivery.responseBody ?? null,
1353
+ responseBody: delivery.responseBody ?? delivery.response ?? null,
1354
+ deliveredAt: delivery.deliveredAt ?? delivery.createdAt
1355
+ };
1356
+ }
1357
+ var WebhooksModule = class {
1358
+ constructor(http) {
1359
+ this.http = http;
1360
+ }
1361
+ async createEndpoint(data) {
1362
+ return this.http.request("POST", "/api/v1/webhooks/endpoints", data);
1363
+ }
1364
+ async listEndpoints() {
1365
+ return this.http.request("GET", "/api/v1/webhooks/endpoints");
1366
+ }
1367
+ async deleteEndpoint(id) {
1368
+ return this.http.request("DELETE", `/api/v1/webhooks/endpoints/${id}`);
1369
+ }
1370
+ async getDeliveries(endpointId) {
1371
+ const deliveries = await this.http.request("GET", `/api/v1/webhooks/deliveries?endpointId=${encodeURIComponent(endpointId)}`);
1372
+ return deliveries.map(normalizeWebhookDelivery);
1373
+ }
1374
+ async testEndpoint(id) {
1375
+ return this.http.request("POST", `/api/v1/webhooks/endpoints/${id}/test`);
1376
+ }
1377
+ async rotateSecret(id) {
1378
+ return this.http.request("POST", `/api/v1/webhooks/endpoints/${id}/rotate-secret`);
1379
+ }
1380
+ };
1381
+
1382
+ // src/modules/entitlements.ts
1383
+ var EntitlementsModule = class {
1384
+ constructor(http) {
1385
+ this.http = http;
1386
+ }
1387
+ async list(tenantId) {
1388
+ return this.http.request("GET", `/api/v1/tenants/${tenantId}/entitlements`);
1389
+ }
1390
+ async grant(tenantId, data) {
1391
+ return this.http.request("POST", `/api/v1/tenants/${tenantId}/entitlements`, data);
1392
+ }
1393
+ async revoke(tenantId, product) {
1394
+ return this.http.request("DELETE", `/api/v1/tenants/${tenantId}/entitlements/${encodeURIComponent(product)}`);
1395
+ }
1396
+ };
1397
+
1398
+ // src/modules/vendors.ts
1399
+ var VendorsModule = class {
1400
+ constructor(http) {
1401
+ this.http = http;
1402
+ }
1403
+ async list() {
1404
+ return this.http.request("GET", "/api/v1/vendors");
1405
+ }
1406
+ async get(vendorId) {
1407
+ return this.http.request("GET", `/api/v1/vendors/${vendorId}`);
1408
+ }
1409
+ async create(data) {
1410
+ return this.http.request("POST", "/api/v1/vendors", data);
1411
+ }
1412
+ async update(vendorId, data) {
1413
+ return this.http.request("PATCH", `/api/v1/vendors/${vendorId}`, data);
1414
+ }
1415
+ async delete(vendorId) {
1416
+ return this.http.request("DELETE", `/api/v1/vendors/${vendorId}`);
1417
+ }
1418
+ };
1419
+
1420
+ // src/modules/sources.ts
1421
+ var SourcesModule = class {
1422
+ constructor(http) {
1423
+ this.http = http;
1424
+ }
1425
+ async create(vendorId, data) {
1426
+ return this.http.request("POST", `/api/v1/vendors/${vendorId}/sources`, data);
1427
+ }
1428
+ async listForVendor(vendorId) {
1429
+ return this.http.request("GET", `/api/v1/vendors/${vendorId}/sources`);
1430
+ }
1431
+ async get(sourceId) {
1432
+ return this.http.request("GET", `/api/v1/sources/${sourceId}`);
1433
+ }
1434
+ async update(sourceId, data) {
1435
+ return this.http.request("PATCH", `/api/v1/sources/${sourceId}`, data);
1436
+ }
1437
+ async delete(sourceId) {
1438
+ return this.http.request("DELETE", `/api/v1/sources/${sourceId}`);
1439
+ }
1440
+ async createClient(sourceId, data) {
1441
+ return this.http.request("POST", `/api/v1/sources/${sourceId}/clients`, data);
1442
+ }
1443
+ async listClients(sourceId) {
1444
+ return this.http.request("GET", `/api/v1/sources/${sourceId}/clients`);
1445
+ }
1446
+ };
1447
+
1448
+ // src/modules/clients.ts
1449
+ var ClientsModule = class {
1450
+ constructor(http) {
1451
+ this.http = http;
1452
+ }
1453
+ async get(clientId) {
1454
+ return this.http.request("GET", `/api/v1/clients/${clientId}`);
1455
+ }
1456
+ async update(clientId, data) {
1457
+ return this.http.request("PATCH", `/api/v1/clients/${clientId}`, data);
1458
+ }
1459
+ async delete(clientId) {
1460
+ return this.http.request("DELETE", `/api/v1/clients/${clientId}`);
1461
+ }
1462
+ };
1463
+
1464
+ // src/modules/hierarchy.ts
1465
+ var HierarchyModule = class {
1466
+ constructor(http) {
1467
+ this.http = http;
1468
+ }
1469
+ async getGraph() {
1470
+ return this.http.request("GET", "/api/v1/hierarchy");
1471
+ }
1472
+ async linkVendorSource(vendorId, sourceId) {
1473
+ return this.http.request("POST", "/api/v1/hierarchy/link/vendor-source", { vendorId, sourceId });
1474
+ }
1475
+ async unlinkVendorSource(vendorId, sourceId) {
1476
+ return this.http.request("DELETE", "/api/v1/hierarchy/link/vendor-source", { vendorId, sourceId });
1477
+ }
1478
+ async linkSourceClient(sourceId, clientId) {
1479
+ return this.http.request("POST", "/api/v1/hierarchy/link/source-client", { sourceId, clientId });
1480
+ }
1481
+ async unlinkSourceClient(sourceId, clientId) {
1482
+ return this.http.request("DELETE", "/api/v1/hierarchy/link/source-client", { sourceId, clientId });
1483
+ }
1484
+ };
1485
+
1486
+ // src/modules/memberships.ts
1487
+ var MembershipsModule = class {
1488
+ constructor(http) {
1489
+ this.http = http;
1490
+ }
1491
+ async listForUser(userId, tenantId) {
1492
+ return this.http.request("GET", `/api/v1/users/${userId}/memberships?tenantId=${encodeURIComponent(tenantId)}`);
1493
+ }
1494
+ async listForScope(scopeType, scopeId) {
1495
+ return this.http.request("GET", `/api/v1/memberships/scope/${scopeType}/${scopeId}`);
1496
+ }
1497
+ async grant(data) {
1498
+ return this.http.request("POST", "/api/v1/memberships", data);
1499
+ }
1500
+ async revoke(id) {
1501
+ return this.http.request("DELETE", `/api/v1/memberships/${id}`);
1502
+ }
1503
+ async update(id, data) {
1504
+ return this.http.request("PATCH", `/api/v1/memberships/${id}`, data);
1505
+ }
1506
+ async listForTenant(params) {
1507
+ const query = new URLSearchParams();
1508
+ if (params?.scopeType) query.set("scopeType", params.scopeType);
1509
+ if (params?.roleName) query.set("roleName", params.roleName);
1510
+ const qs = query.toString();
1511
+ return this.http.request("GET", `/api/v1/memberships/tenant${qs ? `?${qs}` : ""}`);
1512
+ }
1513
+ };
1514
+
1515
+ // src/modules/scope.ts
1516
+ var ScopeModule = class {
1517
+ constructor(http) {
1518
+ this.http = http;
1519
+ }
1520
+ async getAvailable() {
1521
+ return this.http.request("GET", "/api/v1/auth/available-scopes");
1522
+ }
1523
+ async switchScope(scopeType, scopeId) {
1524
+ return this.http.request("POST", "/api/v1/auth/switch-scope", { scopeType, scopeId });
1525
+ }
1526
+ };
1527
+
1528
+ // src/modules/gdpr.ts
1529
+ var GdprModule = class {
1530
+ constructor(http) {
1531
+ this.http = http;
1532
+ }
1533
+ async exportData() {
1534
+ return this.http.request("GET", "/api/v1/gdpr/export");
1535
+ }
1536
+ async deleteAccount(confirmEmail) {
1537
+ return this.http.request("POST", "/api/v1/gdpr/delete", { confirmEmail });
1538
+ }
1539
+ };
1540
+
1541
+ // src/modules/pin.ts
1542
+ var PinModule = class {
1543
+ constructor(http) {
1544
+ this.http = http;
1545
+ }
1546
+ async set(pin) {
1547
+ return this.http.request("POST", "/api/v1/pin/set", { pin });
1548
+ }
1549
+ async change(currentPin, newPin) {
1550
+ return this.http.request("POST", "/api/v1/pin/change", { currentPin, newPin });
1551
+ }
1552
+ async remove() {
1553
+ return this.http.request("DELETE", "/api/v1/pin");
1554
+ }
1555
+ async getStatus() {
1556
+ return this.http.request("GET", "/api/v1/pin/status");
1557
+ }
1558
+ async login(email, pin, deviceFingerprint) {
1559
+ const data = await this.http.request(
1560
+ "POST",
1561
+ "/api/v1/pin/login",
1562
+ { email, pin, ...deviceFingerprint && { deviceFingerprint } },
1563
+ { skipAutoRefresh: true }
1564
+ );
1565
+ if (data.type === "success" && data.accessToken && data.refreshToken && data.user) {
1566
+ return {
1567
+ status: "authenticated",
1568
+ authMode: "token",
1569
+ tokens: { accessToken: data.accessToken, refreshToken: data.refreshToken },
1570
+ user: data.user
1571
+ };
1572
+ }
1573
+ if (data.type === "mfa_required" && data.mfaChallengeToken) {
1574
+ return {
1575
+ status: "mfa_required",
1576
+ mfaChallengeToken: data.mfaChallengeToken,
1577
+ availableMethods: data.availableMethods || []
1578
+ };
1579
+ }
1580
+ if (data.type === "tenant_selection" && data.tenantSelectionToken && data.tenants) {
1581
+ return {
1582
+ status: "tenant_selection",
1583
+ tenantSelectionToken: data.tenantSelectionToken,
1584
+ tenants: data.tenants
1585
+ };
1586
+ }
1587
+ throw new Error("Unexpected PIN login response shape");
1588
+ }
1589
+ };
1590
+
1591
+ // src/modules/mfa.ts
1592
+ var MfaModule = class {
1593
+ constructor(http) {
1594
+ this.http = http;
1595
+ }
1596
+ async getAvailableMethods() {
1597
+ return this.http.request("GET", "/api/v1/mfa/methods");
1598
+ }
1599
+ async enrollTotp() {
1600
+ return this.http.request("POST", "/api/v1/mfa/enroll/totp");
1601
+ }
1602
+ async verifyTotpEnrollment(code, secret) {
1603
+ return this.http.request("POST", "/api/v1/mfa/enroll/totp/verify", { code, secret });
1604
+ }
1605
+ async enrollSms(phoneNumber) {
1606
+ return this.http.request("POST", "/api/v1/mfa/enroll/sms", { phoneNumber });
1607
+ }
1608
+ async verifySmsEnrollment(code, phoneNumber) {
1609
+ return this.http.request("POST", "/api/v1/mfa/enroll/sms/verify", { code, phoneNumber });
1610
+ }
1611
+ async startEmailEnrollment() {
1612
+ return this.http.request("POST", "/api/v1/mfa/enroll/email/start");
1613
+ }
1614
+ async verifyEmailEnrollment(code) {
1615
+ return this.http.request("POST", "/api/v1/mfa/enroll/email/verify", { code });
1616
+ }
1617
+ async listEnrollments() {
1618
+ return this.http.request("GET", "/api/v1/mfa/enrollments");
1619
+ }
1620
+ async setPrimaryEnrollment(enrollmentId) {
1621
+ return this.http.request("PATCH", `/api/v1/mfa/enrollments/${enrollmentId}/primary`);
1622
+ }
1623
+ async deactivateEnrollment(enrollmentId) {
1624
+ return this.http.request("DELETE", `/api/v1/mfa/enrollments/${enrollmentId}`);
1625
+ }
1626
+ async regenerateBackupCodes() {
1627
+ return this.http.request("POST", "/api/v1/mfa/backup-codes/regenerate");
1628
+ }
1629
+ async getBackupCodeCount() {
1630
+ return this.http.request("GET", "/api/v1/mfa/backup-codes/count");
1631
+ }
1632
+ };
1633
+
1634
+ // src/modules/branding.ts
1635
+ function normalizeBrandingConfig2(config) {
1636
+ return {
1637
+ ...config,
1638
+ brandName: config.brandName ?? config.companyName,
1639
+ loginHeadline: config.loginHeadline ?? config.headline ?? null,
1640
+ loginSubheadline: config.loginSubheadline ?? config.subheadline ?? null,
1641
+ companyName: config.companyName ?? config.brandName,
1642
+ headline: config.headline ?? config.loginHeadline ?? null,
1643
+ subheadline: config.subheadline ?? config.loginSubheadline ?? null
1644
+ };
1645
+ }
1646
+ function normalizeBrandingAsset(asset) {
1647
+ return {
1648
+ ...asset,
1649
+ url: asset.url ?? asset.publicUrl,
1650
+ publicUrl: asset.publicUrl ?? asset.url
1651
+ };
1652
+ }
1653
+ function normalizeBrandingUpdate(data) {
1654
+ return {
1655
+ ...data,
1656
+ brandName: data.brandName ?? data.companyName,
1657
+ loginHeadline: data.loginHeadline ?? data.headline,
1658
+ loginSubheadline: data.loginSubheadline ?? data.subheadline
1659
+ };
1660
+ }
1661
+ var BrandingModule = class {
1662
+ constructor(http) {
1663
+ this.http = http;
1664
+ }
1665
+ async get(vendorId) {
1666
+ const config = await this.http.request("GET", `/api/v1/branding/${vendorId}`);
1667
+ return normalizeBrandingConfig2(config);
1668
+ }
1669
+ async updateBranding(vendorId, data) {
1670
+ const config = await this.http.request("PUT", `/api/v1/branding/${vendorId}`, normalizeBrandingUpdate(data));
1671
+ return normalizeBrandingConfig2(config);
1672
+ }
1673
+ async publishBranding(vendorId) {
1674
+ const config = await this.http.request("POST", `/api/v1/branding/${vendorId}/publish`);
1675
+ return normalizeBrandingConfig2(config);
1676
+ }
1677
+ async unpublishBranding(vendorId) {
1678
+ const config = await this.http.request("POST", `/api/v1/branding/${vendorId}/unpublish`);
1679
+ return normalizeBrandingConfig2(config);
1680
+ }
1681
+ async resetBranding(vendorId) {
1682
+ const config = await this.http.request("POST", `/api/v1/branding/${vendorId}/reset`);
1683
+ return normalizeBrandingConfig2(config);
1684
+ }
1685
+ async uploadAsset(vendorId, data) {
1686
+ const asset = await this.http.request("POST", `/api/v1/branding/${vendorId}/upload`, data);
1687
+ return normalizeBrandingAsset(asset);
1688
+ }
1689
+ async listAssets(vendorId) {
1690
+ const assets = await this.http.request("GET", `/api/v1/branding/${vendorId}/assets`);
1691
+ return assets.map(normalizeBrandingAsset);
1692
+ }
1693
+ async deleteAsset(vendorId, assetId) {
1694
+ return this.http.request("DELETE", `/api/v1/branding/${vendorId}/assets/${assetId}`);
1695
+ }
1696
+ async listDomains(vendorId) {
1697
+ return this.http.request("GET", `/api/v1/branding/${vendorId}/domains`);
1698
+ }
1699
+ async addDomain(vendorId, domain) {
1700
+ return this.http.request("POST", `/api/v1/branding/${vendorId}/domains`, { domain });
1701
+ }
1702
+ async removeDomain(vendorId, domainId) {
1703
+ return this.http.request("DELETE", `/api/v1/branding/${vendorId}/domains/${domainId}`);
1704
+ }
1705
+ };
1706
+
1707
+ // src/client.ts
1708
+ var IQAuthClient = class _IQAuthClient {
1709
+ constructor(config) {
1710
+ this.config = config;
1711
+ this.environment = _IQAuthClient.resolveEnvironment(config);
1712
+ this._accessToken = "accessToken" in config ? config.accessToken : void 0;
1713
+ this._refreshToken = "refreshToken" in config ? config.refreshToken : void 0;
1714
+ this._apiKey = "apiKey" in config ? config.apiKey : void 0;
1715
+ this.httpClient = new HttpClient({
1716
+ baseUrl: config.baseUrl,
1717
+ environment: this.environment,
1718
+ getAccessToken: () => this._accessToken,
1719
+ getRefreshToken: () => this._refreshToken,
1720
+ getApiKey: () => this._apiKey,
1721
+ setTokens: (tokens) => {
1722
+ this._accessToken = tokens.accessToken;
1723
+ this._refreshToken = tokens.refreshToken;
1724
+ },
1725
+ autoRefresh: "autoRefresh" in config ? config.autoRefresh !== false : true,
1726
+ onTokenRefresh: "onTokenRefresh" in config ? config.onTokenRefresh : void 0,
1727
+ sessionHeaderName: config.sessionHeaderName,
1728
+ sessionHeaderValue: config.sessionHeaderValue,
1729
+ retry: config.retry
1730
+ });
1731
+ this.auth = new AuthModule(this.httpClient);
1732
+ this.tokens = new TokensModule(config.baseUrl, {
1733
+ issuer: config.verify?.issuer,
1734
+ audience: config.verify?.audience,
1735
+ clockTolerance: config.verify?.clockTolerance
1736
+ });
1737
+ this.sessions = new SessionsModule(this.httpClient);
1738
+ this.users = new UsersModule(this.httpClient);
1739
+ this.permissions = new PermissionsModule(() => this.getCurrentClaims());
1740
+ this.oidc = new OidcModule(this.httpClient, config.baseUrl, { tokens: this.tokens });
1741
+ this.tenants = new TenantsModule(this.httpClient);
1742
+ this.apps = new AppsModule(this.httpClient);
1743
+ this.roles = new RolesModule(this.httpClient);
1744
+ this.permissionGroups = new PermissionGroupsModule(this.httpClient);
1745
+ this.apiKeys = new ApiKeysModule(this.httpClient);
1746
+ this.invites = new InvitesModule(this.httpClient);
1747
+ this.webhooks = new WebhooksModule(this.httpClient);
1748
+ this.entitlements = new EntitlementsModule(this.httpClient);
1749
+ this.vendors = new VendorsModule(this.httpClient);
1750
+ this.sources = new SourcesModule(this.httpClient);
1751
+ this.clients = new ClientsModule(this.httpClient);
1752
+ this.hierarchy = new HierarchyModule(this.httpClient);
1753
+ this.memberships = new MembershipsModule(this.httpClient);
1754
+ this.scope = new ScopeModule(this.httpClient);
1755
+ this.gdpr = new GdprModule(this.httpClient);
1756
+ this.pin = new PinModule(this.httpClient);
1757
+ this.mfa = new MfaModule(this.httpClient);
1758
+ this.branding = new BrandingModule(this.httpClient);
1759
+ }
1760
+ static forBrowserSession(config) {
1761
+ return new _IQAuthClient({ ...config, environment: "browser_session" });
1762
+ }
1763
+ static forServer(config) {
1764
+ return new _IQAuthClient({ ...config, environment: "server" });
1765
+ }
1766
+ static forMobile(config) {
1767
+ return new _IQAuthClient({ ...config, environment: "mobile" });
1768
+ }
1769
+ static forService(config) {
1770
+ return new _IQAuthClient({ ...config, environment: "service" });
1771
+ }
1772
+ setTokens(tokens) {
1773
+ this._accessToken = tokens.accessToken;
1774
+ this._refreshToken = tokens.refreshToken;
1775
+ }
1776
+ getAccessToken() {
1777
+ return this._accessToken;
1778
+ }
1779
+ getRefreshToken() {
1780
+ return this._refreshToken;
1781
+ }
1782
+ getCurrentClaims() {
1783
+ if (!this._accessToken) return null;
1784
+ return this.tokens.decode(this._accessToken);
1785
+ }
1786
+ static resolveEnvironment(config) {
1787
+ if (config.environment) return config.environment;
1788
+ if (config.apiKey) return "service";
1789
+ return "server";
1790
+ }
1791
+ };
1792
+
1793
+ // src/service.ts
1794
+ var ServiceIQAuthClient = class extends IQAuthClient {
1795
+ constructor(config) {
1796
+ super({ ...config, environment: "service" });
1797
+ }
1798
+ };
1799
+ function createServiceClient(config) {
1800
+ return new ServiceIQAuthClient(config);
1801
+ }
1802
+ // Annotate the CommonJS export names for ESM import in node:
1803
+ 0 && (module.exports = {
1804
+ ErrorCodes,
1805
+ IQAuthClient,
1806
+ IQAuthError,
1807
+ ServiceIQAuthClient,
1808
+ createServiceClient
1809
+ });