@mosano-product-framework/sdk 0.2.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 (74) hide show
  1. package/README.md +827 -0
  2. package/README.react.md +348 -0
  3. package/dist/auth/claims-types.d.ts +89 -0
  4. package/dist/auth/claims.d.ts +125 -0
  5. package/dist/auth/cross-tab.d.ts +114 -0
  6. package/dist/auth/errors.d.ts +40 -0
  7. package/dist/auth/index.d.ts +18 -0
  8. package/dist/auth/index.js +5 -0
  9. package/dist/auth/index.js.map +1 -0
  10. package/dist/auth/oauth-state.d.ts +93 -0
  11. package/dist/auth/session-manager.d.ts +253 -0
  12. package/dist/auth/storage.d.ts +36 -0
  13. package/dist/auth/tenant-directory.d.ts +59 -0
  14. package/dist/auth/tenant-selection.d.ts +92 -0
  15. package/dist/chunk-7WAV52EO.js +621 -0
  16. package/dist/chunk-7WAV52EO.js.map +1 -0
  17. package/dist/chunk-AJWM5MDZ.js +410 -0
  18. package/dist/chunk-AJWM5MDZ.js.map +1 -0
  19. package/dist/chunk-EXPYHNPV.js +212 -0
  20. package/dist/chunk-EXPYHNPV.js.map +1 -0
  21. package/dist/chunk-GPWGOYCA.js +85 -0
  22. package/dist/chunk-GPWGOYCA.js.map +1 -0
  23. package/dist/chunk-GQJ3QQPH.js +339 -0
  24. package/dist/chunk-GQJ3QQPH.js.map +1 -0
  25. package/dist/chunk-K2ELAI2X.js +64 -0
  26. package/dist/chunk-K2ELAI2X.js.map +1 -0
  27. package/dist/chunk-LRM6JJ63.js +616 -0
  28. package/dist/chunk-LRM6JJ63.js.map +1 -0
  29. package/dist/chunk-XAXFIIRT.js +959 -0
  30. package/dist/chunk-XAXFIIRT.js.map +1 -0
  31. package/dist/client/core/client-factory.d.ts +61 -0
  32. package/dist/client/core/client.d.ts +144 -0
  33. package/dist/client/core/errors.d.ts +105 -0
  34. package/dist/client/core/index.d.ts +9 -0
  35. package/dist/client/core/middleware.d.ts +67 -0
  36. package/dist/client/core/types.d.ts +99 -0
  37. package/dist/client/graphql/client.d.ts +66 -0
  38. package/dist/client/graphql/factory.d.ts +84 -0
  39. package/dist/client/graphql/operation.d.ts +24 -0
  40. package/dist/client/graphql/types.d.ts +60 -0
  41. package/dist/client/graphql/ws-client.d.ts +116 -0
  42. package/dist/client/index.d.ts +17 -0
  43. package/dist/client/index.js +227 -0
  44. package/dist/client/index.js.map +1 -0
  45. package/dist/client/middlewares/admin-auth.d.ts +90 -0
  46. package/dist/client/middlewares/auth.d.ts +81 -0
  47. package/dist/client/middlewares/index.d.ts +12 -0
  48. package/dist/client/middlewares/logging.d.ts +102 -0
  49. package/dist/client/middlewares/retry.d.ts +138 -0
  50. package/dist/client/middlewares/tenant.d.ts +60 -0
  51. package/dist/client/middlewares/turnstile.d.ts +41 -0
  52. package/dist/client/peer-free.d.ts +25 -0
  53. package/dist/client/utils/url.d.ts +19 -0
  54. package/dist/identity/index.d.ts +85 -0
  55. package/dist/identity/index.js +6 -0
  56. package/dist/identity/index.js.map +1 -0
  57. package/dist/identity/types.d.ts +690 -0
  58. package/dist/identity/v0.d.ts +594 -0
  59. package/dist/index.d.ts +50 -0
  60. package/dist/index.js +24 -0
  61. package/dist/index.js.map +1 -0
  62. package/dist/react/context.d.ts +47 -0
  63. package/dist/react/hooks.d.ts +120 -0
  64. package/dist/react/index.d.ts +19 -0
  65. package/dist/react/index.js +308 -0
  66. package/dist/react/index.js.map +1 -0
  67. package/dist/react/provider.d.ts +68 -0
  68. package/dist/react/store.d.ts +85 -0
  69. package/dist/storage/index.d.ts +31 -0
  70. package/dist/storage/index.js +5 -0
  71. package/dist/storage/index.js.map +1 -0
  72. package/dist/storage/types.d.ts +107 -0
  73. package/dist/storage/v0.d.ts +120 -0
  74. package/package.json +99 -0
@@ -0,0 +1,616 @@
1
+ import { MPFAPIError, MPFAuthError, MPFNetworkError, MPFError, tryDecodeAccessToken } from './chunk-AJWM5MDZ.js';
2
+
3
+ // src/client/core/middleware.ts
4
+ async function executeRequestMiddlewares(middlewares, ctx) {
5
+ let currentCtx = ctx;
6
+ for (const middleware of middlewares) {
7
+ if (middleware.onRequest) {
8
+ currentCtx = await middleware.onRequest(currentCtx);
9
+ }
10
+ }
11
+ return currentCtx;
12
+ }
13
+ async function executeResponseMiddlewares(middlewares, ctx) {
14
+ let currentCtx = ctx;
15
+ for (let i = middlewares.length - 1; i >= 0; i--) {
16
+ const middleware = middlewares[i];
17
+ if (middleware.onResponse) {
18
+ currentCtx = await middleware.onResponse(currentCtx);
19
+ }
20
+ }
21
+ return currentCtx;
22
+ }
23
+ async function executeErrorMiddlewares(middlewares, error, ctx) {
24
+ let currentError = error;
25
+ for (const middleware of middlewares) {
26
+ if (!middleware.onError) {
27
+ continue;
28
+ }
29
+ try {
30
+ await middleware.onError(currentError, ctx);
31
+ } catch (thrown) {
32
+ if (thrown instanceof Error) {
33
+ currentError = thrown;
34
+ }
35
+ }
36
+ }
37
+ throw currentError;
38
+ }
39
+
40
+ // src/client/middlewares/retry.ts
41
+ var RETRY_ATTEMPT_KEY = "__retryAttempt";
42
+ var SHOULD_RETRY_KEY = "__shouldRetry";
43
+ var NO_RETRY_KEY = "__noRetry";
44
+ var DEFAULT_RETRY_STATUS_CODES = [408, 429, 500, 502, 503, 504];
45
+ function sleep(ms) {
46
+ return new Promise((resolve) => setTimeout(resolve, ms));
47
+ }
48
+ function calculateDelay(attempt, baseDelay, backoffFactor, maxDelay, useJitter) {
49
+ const exponentialDelay = baseDelay * Math.pow(backoffFactor, attempt);
50
+ const cappedDelay = Math.min(exponentialDelay, maxDelay);
51
+ if (useJitter) {
52
+ const jitterFactor = 1 + Math.random() * 0.25;
53
+ return Math.floor(cappedDelay * jitterFactor);
54
+ }
55
+ return Math.floor(cappedDelay);
56
+ }
57
+ function createRetryMiddleware(options) {
58
+ const {
59
+ maxRetries = 3,
60
+ retryDelay = 1e3,
61
+ retryOn = DEFAULT_RETRY_STATUS_CODES,
62
+ backoffFactor = 2,
63
+ maxDelay = 3e4,
64
+ jitter = true,
65
+ onRetry,
66
+ shouldRetry: customShouldRetry
67
+ } = options ?? {};
68
+ function shouldRetry(error, attempt) {
69
+ if (attempt >= maxRetries) {
70
+ return false;
71
+ }
72
+ if (customShouldRetry) {
73
+ return customShouldRetry(error, attempt);
74
+ }
75
+ if (error instanceof MPFError && error.status !== void 0) {
76
+ return retryOn.includes(error.status);
77
+ }
78
+ if (error.name === "TypeError" && error.message.includes("fetch")) {
79
+ return true;
80
+ }
81
+ return false;
82
+ }
83
+ function getRetryAfterDelay(error) {
84
+ if (error instanceof MPFAPIError && error.details) {
85
+ const details = error.details;
86
+ const retryAfter = details["retryAfter"] || details["retry-after"] || details["Retry-After"];
87
+ if (typeof retryAfter === "number") {
88
+ return retryAfter * 1e3;
89
+ }
90
+ if (typeof retryAfter === "string") {
91
+ const seconds = parseInt(retryAfter, 10);
92
+ if (!isNaN(seconds)) {
93
+ return seconds * 1e3;
94
+ }
95
+ const date = new Date(retryAfter);
96
+ if (!isNaN(date.getTime())) {
97
+ const delay = date.getTime() - Date.now();
98
+ return delay > 0 ? delay : null;
99
+ }
100
+ }
101
+ }
102
+ return null;
103
+ }
104
+ return {
105
+ name: "retry",
106
+ onRequest(ctx) {
107
+ if (ctx.metadata[RETRY_ATTEMPT_KEY] === void 0) {
108
+ ctx.metadata[RETRY_ATTEMPT_KEY] = 0;
109
+ }
110
+ return ctx;
111
+ },
112
+ async onError(error, ctx) {
113
+ const currentAttempt = ctx.metadata[RETRY_ATTEMPT_KEY] ?? 0;
114
+ if (!shouldRetry(error, currentAttempt)) {
115
+ throw error;
116
+ }
117
+ let delay = getRetryAfterDelay(error);
118
+ if (delay === null) {
119
+ delay = calculateDelay(currentAttempt, retryDelay, backoffFactor, maxDelay, jitter);
120
+ }
121
+ delay = Math.min(delay, maxDelay);
122
+ if (onRetry) {
123
+ try {
124
+ await onRetry(currentAttempt + 1, error, delay);
125
+ } catch (callbackError) {
126
+ console.error("[MPF SDK] Error in onRetry callback:", callbackError);
127
+ }
128
+ }
129
+ await sleep(delay);
130
+ ctx.metadata[RETRY_ATTEMPT_KEY] = currentAttempt + 1;
131
+ requestRetry(ctx);
132
+ throw error;
133
+ }
134
+ };
135
+ }
136
+ function shouldRetryRequest(ctx) {
137
+ return ctx.metadata[SHOULD_RETRY_KEY] === true && !isRetryDisabled(ctx);
138
+ }
139
+ function requestRetry(ctx) {
140
+ ctx.metadata[SHOULD_RETRY_KEY] = true;
141
+ }
142
+ function disableRetry(ctx) {
143
+ ctx.metadata[NO_RETRY_KEY] = true;
144
+ }
145
+ function isRetryDisabled(ctx) {
146
+ return ctx.metadata[NO_RETRY_KEY] === true;
147
+ }
148
+ function isReplayableBody(body) {
149
+ if (body === null || body === void 0) {
150
+ return true;
151
+ }
152
+ if (typeof ReadableStream !== "undefined" && body instanceof ReadableStream) {
153
+ return false;
154
+ }
155
+ return true;
156
+ }
157
+ function getRetryAttempt(ctx) {
158
+ return ctx.metadata[RETRY_ATTEMPT_KEY] ?? 0;
159
+ }
160
+ function clearRetryFlag(ctx) {
161
+ delete ctx.metadata[SHOULD_RETRY_KEY];
162
+ }
163
+
164
+ // src/client/core/client.ts
165
+ var MAX_REQUEST_ATTEMPTS = 4;
166
+ var MPFClient = class {
167
+ baseUrl;
168
+ defaultHeaders;
169
+ middlewares;
170
+ constructor(config) {
171
+ this.baseUrl = config.baseUrl.replace(/\/+$/, "");
172
+ this.defaultHeaders = {
173
+ "Content-Type": "application/json",
174
+ "Accept": "application/json",
175
+ ...config.headers
176
+ };
177
+ this.middlewares = [...config.middlewares ?? []];
178
+ }
179
+ /**
180
+ * Add a middleware to the client
181
+ * Middlewares are executed in the order they are added for requests,
182
+ * and in reverse order for responses.
183
+ *
184
+ * @param middleware - The middleware to add
185
+ * @returns The client instance for chaining
186
+ */
187
+ use(middleware) {
188
+ this.middlewares.push(middleware);
189
+ return this;
190
+ }
191
+ /**
192
+ * Build a full URL with query parameters
193
+ *
194
+ * @param path - The API path (e.g., "/users" or "users")
195
+ * @param params - Optional query parameters
196
+ * @returns The full URL with query string
197
+ */
198
+ buildUrl(path, params) {
199
+ const normalizedPath = path.startsWith("/") ? path : `/${path}`;
200
+ const base = /^https?:\/\//.test(this.baseUrl) ? this.baseUrl : typeof window !== "undefined" ? window.location.origin : "http://localhost";
201
+ const url = new URL(`${this.baseUrl}${normalizedPath}`, base);
202
+ if (params) {
203
+ for (const [key, value] of Object.entries(params)) {
204
+ if (value !== void 0 && value !== null) {
205
+ url.searchParams.append(key, String(value));
206
+ }
207
+ }
208
+ }
209
+ return url.toString();
210
+ }
211
+ /**
212
+ * Merge headers from different sources
213
+ *
214
+ * @param requestHeaders - Headers specific to this request
215
+ * @returns Merged headers object
216
+ */
217
+ mergeHeaders(requestHeaders) {
218
+ return {
219
+ ...this.defaultHeaders,
220
+ ...requestHeaders
221
+ };
222
+ }
223
+ /**
224
+ * Build the headers for a single attempt.
225
+ *
226
+ * Rebuilt per attempt so request middlewares (auth, turnstile, ...) always
227
+ * inject a fresh token instead of replaying a stale one.
228
+ *
229
+ * For a `FormData` body the default JSON `Content-Type` is dropped so that
230
+ * fetch sets `multipart/form-data` with the correct boundary.
231
+ */
232
+ buildAttemptHeaders(init) {
233
+ const headers = this.mergeHeaders(init.headers);
234
+ if (typeof FormData !== "undefined" && init.body instanceof FormData) {
235
+ delete headers["Content-Type"];
236
+ }
237
+ return headers;
238
+ }
239
+ /**
240
+ * Parse the response body based on content type
241
+ *
242
+ * @param response - The fetch Response object
243
+ * @returns Parsed response data
244
+ */
245
+ async parseResponse(response) {
246
+ const contentType = response.headers.get("content-type") ?? "";
247
+ if (response.status === 204 || response.headers.get("content-length") === "0") {
248
+ return void 0;
249
+ }
250
+ if (contentType.includes("application/json")) {
251
+ const text2 = await response.text();
252
+ if (!text2) {
253
+ return void 0;
254
+ }
255
+ try {
256
+ return JSON.parse(text2);
257
+ } catch {
258
+ throw new MPFAPIError(
259
+ "Failed to parse JSON response",
260
+ "PARSE_ERROR",
261
+ response.status,
262
+ { text: text2 }
263
+ );
264
+ }
265
+ }
266
+ const text = await response.text();
267
+ return text;
268
+ }
269
+ /**
270
+ * Handle error responses from the API
271
+ *
272
+ * @param response - The fetch Response object
273
+ * @throws MPFAuthError for 401/403, MPFAPIError for other errors
274
+ */
275
+ async handleErrorResponse(response) {
276
+ let body;
277
+ let errorResponse;
278
+ try {
279
+ const text = await response.text();
280
+ if (text) {
281
+ body = JSON.parse(text);
282
+ errorResponse = body;
283
+ }
284
+ } catch {
285
+ }
286
+ const message = errorResponse?.message ?? errorResponse?.error ?? response.statusText ?? "Request failed";
287
+ const code = errorResponse?.code ?? `HTTP_${response.status}`;
288
+ const details = errorResponse?.details;
289
+ if (response.status === 401) {
290
+ const authType = code.toLowerCase().includes("expired") ? "token_expired" : "unauthorized";
291
+ throw new MPFAuthError(message, authType, 401, details, errorResponse?.code);
292
+ }
293
+ if (response.status === 403) {
294
+ throw new MPFAuthError(message, "forbidden", 403, details, errorResponse?.code);
295
+ }
296
+ throw new MPFAPIError(message, code, response.status, details, body);
297
+ }
298
+ /**
299
+ * Execute an HTTP request with the full middleware chain, retrying when a
300
+ * middleware asks for it.
301
+ *
302
+ * Retry contract:
303
+ * - `metadata` is created once and shared by every attempt. Middlewares keep
304
+ * their per-request state there (retry counter, auth-renew flag); rebuilding
305
+ * it per attempt would reset those counters and loop forever.
306
+ * - `init.headers` are rebuilt per attempt so request middlewares re-inject a
307
+ * fresh token rather than replaying the first attempt's headers.
308
+ * - `MAX_REQUEST_ATTEMPTS` bounds the loop regardless of middleware config.
309
+ * - Bodies that cannot be re-sent (`ReadableStream`) disable retrying.
310
+ *
311
+ * @param path - The API path
312
+ * @param init - Fetch RequestInit options
313
+ * @returns The parsed response data
314
+ * @throws MPFNetworkError for network failures
315
+ * @throws MPFAuthError for 401/403 responses
316
+ * @throws MPFAPIError for other error responses
317
+ */
318
+ async request(path, init = {}, params, options) {
319
+ const url = this.buildUrl(path, params);
320
+ const metadata = {};
321
+ for (let attempt = 0; attempt < MAX_REQUEST_ATTEMPTS; attempt++) {
322
+ const requestCtx = {
323
+ url,
324
+ init: {
325
+ ...init,
326
+ headers: this.buildAttemptHeaders(init)
327
+ },
328
+ metadata,
329
+ options
330
+ };
331
+ if (!isReplayableBody(init.body)) {
332
+ disableRetry(requestCtx);
333
+ }
334
+ try {
335
+ return await this.attempt(requestCtx);
336
+ } catch (error) {
337
+ const isLastAttempt = attempt === MAX_REQUEST_ATTEMPTS - 1;
338
+ if (isLastAttempt || !shouldRetryRequest(requestCtx)) {
339
+ throw error;
340
+ }
341
+ clearRetryFlag(requestCtx);
342
+ }
343
+ }
344
+ throw new MPFNetworkError("Request retry loop exhausted");
345
+ }
346
+ /**
347
+ * Execute a single request attempt through the middleware chain.
348
+ *
349
+ * On failure the error middleware chain runs before the error propagates, so
350
+ * the caller can inspect `ctx.metadata` for a retry request.
351
+ */
352
+ async attempt(ctx) {
353
+ let requestCtx = ctx;
354
+ try {
355
+ requestCtx = await executeRequestMiddlewares(this.middlewares, requestCtx);
356
+ let response;
357
+ try {
358
+ response = await fetch(requestCtx.url, requestCtx.init);
359
+ } catch (error) {
360
+ throw new MPFNetworkError(
361
+ error instanceof Error ? error.message : "Network request failed",
362
+ error instanceof Error ? error : void 0
363
+ );
364
+ }
365
+ if (!response.ok) {
366
+ await this.handleErrorResponse(response);
367
+ }
368
+ const data = await this.parseResponse(response);
369
+ let responseCtx = {
370
+ response,
371
+ data,
372
+ metadata: requestCtx.metadata
373
+ };
374
+ responseCtx = await executeResponseMiddlewares(this.middlewares, responseCtx);
375
+ return responseCtx.data;
376
+ } catch (error) {
377
+ try {
378
+ if (error instanceof Error && this.middlewares.some((m) => m.onError)) {
379
+ await executeErrorMiddlewares(this.middlewares, error, requestCtx);
380
+ }
381
+ throw error;
382
+ } finally {
383
+ if (requestCtx.metadata !== ctx.metadata) {
384
+ Object.assign(ctx.metadata, requestCtx.metadata);
385
+ }
386
+ }
387
+ }
388
+ }
389
+ /**
390
+ * Make a GET request
391
+ *
392
+ * @param path - The API path
393
+ * @param options - Request options
394
+ * @returns The parsed response data
395
+ */
396
+ async get(path, options = {}) {
397
+ return this.request(path, {
398
+ method: "GET",
399
+ headers: options.headers,
400
+ signal: options.signal
401
+ }, options.params, options);
402
+ }
403
+ /**
404
+ * Make a POST request
405
+ *
406
+ * @param path - The API path
407
+ * @param body - Request body (will be JSON stringified)
408
+ * @param options - Request options
409
+ * @returns The parsed response data
410
+ */
411
+ async post(path, body, options = {}) {
412
+ return this.request(path, {
413
+ method: "POST",
414
+ headers: options.headers,
415
+ signal: options.signal,
416
+ body: body !== void 0 ? JSON.stringify(body) : void 0
417
+ }, options.params, options);
418
+ }
419
+ /**
420
+ * Make a PUT request
421
+ *
422
+ * @param path - The API path
423
+ * @param body - Request body (will be JSON stringified)
424
+ * @param options - Request options
425
+ * @returns The parsed response data
426
+ */
427
+ async put(path, body, options = {}) {
428
+ return this.request(path, {
429
+ method: "PUT",
430
+ headers: options.headers,
431
+ signal: options.signal,
432
+ body: body !== void 0 ? JSON.stringify(body) : void 0
433
+ }, options.params, options);
434
+ }
435
+ /**
436
+ * Make a PATCH request
437
+ *
438
+ * @param path - The API path
439
+ * @param body - Request body (will be JSON stringified)
440
+ * @param options - Request options
441
+ * @returns The parsed response data
442
+ */
443
+ async patch(path, body, options = {}) {
444
+ return this.request(path, {
445
+ method: "PATCH",
446
+ headers: options.headers,
447
+ signal: options.signal,
448
+ body: body !== void 0 ? JSON.stringify(body) : void 0
449
+ }, options.params, options);
450
+ }
451
+ /**
452
+ * Make a DELETE request
453
+ *
454
+ * @param path - The API path
455
+ * @param body - Optional request body (will be JSON stringified)
456
+ * @param options - Request options
457
+ * @returns The parsed response data
458
+ */
459
+ async delete(path, body, options = {}) {
460
+ return this.request(path, {
461
+ method: "DELETE",
462
+ headers: options.headers,
463
+ signal: options.signal,
464
+ body: body !== void 0 ? JSON.stringify(body) : void 0
465
+ }, options.params, options);
466
+ }
467
+ };
468
+
469
+ // src/client/middlewares/auth.ts
470
+ var TOKEN_ATTACHED_KEY = "__authTokenAttached";
471
+ var RENEW_ATTEMPTED_KEY = "__authRenewAttempted";
472
+ function createAuthMiddleware(options) {
473
+ const {
474
+ getAccessToken,
475
+ onTokenExpired,
476
+ onUnauthorized,
477
+ tokenType = "Bearer",
478
+ headerName = "Authorization"
479
+ } = options;
480
+ return {
481
+ name: "auth",
482
+ async onRequest(ctx) {
483
+ if (ctx.options?.skipAuth) {
484
+ return ctx;
485
+ }
486
+ const token = await getAccessToken();
487
+ if (token) {
488
+ const headers = new Headers(ctx.init.headers);
489
+ headers.set(headerName, `${tokenType} ${token}`);
490
+ ctx.init.headers = headers;
491
+ ctx.metadata[TOKEN_ATTACHED_KEY] = true;
492
+ }
493
+ return ctx;
494
+ },
495
+ async onError(error, ctx) {
496
+ const status = error instanceof MPFError ? error.status : void 0;
497
+ if (status !== 401) {
498
+ throw error;
499
+ }
500
+ if (ctx.metadata[TOKEN_ATTACHED_KEY] !== true) {
501
+ throw error;
502
+ }
503
+ if (onUnauthorized && ctx.metadata[RENEW_ATTEMPTED_KEY] !== true) {
504
+ ctx.metadata[RENEW_ATTEMPTED_KEY] = true;
505
+ let renewed = false;
506
+ try {
507
+ renewed = await onUnauthorized();
508
+ } catch (renewError) {
509
+ console.error("[MPF SDK] Error in onUnauthorized callback:", renewError);
510
+ renewed = false;
511
+ }
512
+ if (renewed) {
513
+ requestRetry(ctx);
514
+ throw error;
515
+ }
516
+ }
517
+ if (onTokenExpired) {
518
+ try {
519
+ await onTokenExpired();
520
+ } catch (callbackError) {
521
+ console.error("[MPF SDK] Error in onTokenExpired callback:", callbackError);
522
+ }
523
+ }
524
+ throw error;
525
+ }
526
+ };
527
+ }
528
+
529
+ // src/client/middlewares/tenant.ts
530
+ var TENANT_HEADER = "X-MPF-Tenant";
531
+ var TENANT_ROLE_HEADER = "X-MPF-Tenant-Role";
532
+ var UNSCOPED_WARNING = "[MPF SDK] Request sent with no tenant selected, but the access token holds tenant memberships. The server will scope this request to the default (tenantless) role, which usually means empty results or a 403 rather than tenant data. Wire a tenantProvider (createTenantSelection()) into your client and call set(tenantId), or pass `{ tenant: null }` on the request to state explicitly that it is unscoped. This warning is shown once.";
533
+ function createTenantMiddleware(options = {}) {
534
+ const {
535
+ tenantProvider,
536
+ getAccessToken,
537
+ warnOnUnscoped = true,
538
+ logger = console
539
+ } = options;
540
+ let warned = false;
541
+ async function maybeWarnUnscoped() {
542
+ if (warned || !warnOnUnscoped || !getAccessToken) {
543
+ return;
544
+ }
545
+ let token;
546
+ try {
547
+ token = await getAccessToken();
548
+ } catch {
549
+ return;
550
+ }
551
+ const claims = tryDecodeAccessToken(token);
552
+ if (!claims || claims.tnts.length === 0) {
553
+ return;
554
+ }
555
+ warned = true;
556
+ logger.warn(UNSCOPED_WARNING);
557
+ }
558
+ return {
559
+ name: "tenant",
560
+ async onRequest(ctx) {
561
+ if (ctx.options?.skipTenant) {
562
+ return ctx;
563
+ }
564
+ const perRequest = ctx.options?.tenant;
565
+ const inherit = perRequest === void 0;
566
+ const selection = inherit ? tenantProvider?.get() : void 0;
567
+ const tenant = inherit ? selection?.tenant ?? null : perRequest;
568
+ const role = ctx.options?.tenantRole ?? (inherit ? selection?.role : void 0);
569
+ if (tenant === null || tenant === "") {
570
+ if (inherit) {
571
+ await maybeWarnUnscoped();
572
+ }
573
+ return ctx;
574
+ }
575
+ const headers = new Headers(ctx.init.headers);
576
+ headers.set(TENANT_HEADER, tenant);
577
+ if (role !== void 0 && role !== "") {
578
+ headers.set(TENANT_ROLE_HEADER, role);
579
+ }
580
+ ctx.init.headers = headers;
581
+ return ctx;
582
+ }
583
+ };
584
+ }
585
+
586
+ // src/client/core/client-factory.ts
587
+ function attachStandardMiddlewares(client, options) {
588
+ const { tokenProvider, tenantProvider } = options;
589
+ if (tokenProvider) {
590
+ client.use(
591
+ createAuthMiddleware({
592
+ getAccessToken: tokenProvider.getAccessToken,
593
+ onTokenExpired: tokenProvider.onTokenExpired,
594
+ ...tokenProvider.onUnauthorized ? { onUnauthorized: tokenProvider.onUnauthorized } : {}
595
+ })
596
+ );
597
+ }
598
+ if (tenantProvider) {
599
+ client.use(
600
+ createTenantMiddleware({
601
+ tenantProvider,
602
+ ...tokenProvider ? { getAccessToken: tokenProvider.getAccessToken } : {}
603
+ })
604
+ );
605
+ }
606
+ }
607
+ function createHttpClient(options) {
608
+ const { tokenProvider, tenantProvider, ...clientConfig } = options;
609
+ const client = new MPFClient(clientConfig);
610
+ attachStandardMiddlewares(client, { tokenProvider, tenantProvider });
611
+ return client;
612
+ }
613
+
614
+ export { MAX_REQUEST_ATTEMPTS, MPFClient, TENANT_HEADER, TENANT_ROLE_HEADER, attachStandardMiddlewares, clearRetryFlag, createAuthMiddleware, createHttpClient, createRetryMiddleware, createTenantMiddleware, disableRetry, executeErrorMiddlewares, executeRequestMiddlewares, executeResponseMiddlewares, getRetryAttempt, isReplayableBody, isRetryDisabled, requestRetry, shouldRetryRequest };
615
+ //# sourceMappingURL=chunk-LRM6JJ63.js.map
616
+ //# sourceMappingURL=chunk-LRM6JJ63.js.map