@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.
- package/README.md +827 -0
- package/README.react.md +348 -0
- package/dist/auth/claims-types.d.ts +89 -0
- package/dist/auth/claims.d.ts +125 -0
- package/dist/auth/cross-tab.d.ts +114 -0
- package/dist/auth/errors.d.ts +40 -0
- package/dist/auth/index.d.ts +18 -0
- package/dist/auth/index.js +5 -0
- package/dist/auth/index.js.map +1 -0
- package/dist/auth/oauth-state.d.ts +93 -0
- package/dist/auth/session-manager.d.ts +253 -0
- package/dist/auth/storage.d.ts +36 -0
- package/dist/auth/tenant-directory.d.ts +59 -0
- package/dist/auth/tenant-selection.d.ts +92 -0
- package/dist/chunk-7WAV52EO.js +621 -0
- package/dist/chunk-7WAV52EO.js.map +1 -0
- package/dist/chunk-AJWM5MDZ.js +410 -0
- package/dist/chunk-AJWM5MDZ.js.map +1 -0
- package/dist/chunk-EXPYHNPV.js +212 -0
- package/dist/chunk-EXPYHNPV.js.map +1 -0
- package/dist/chunk-GPWGOYCA.js +85 -0
- package/dist/chunk-GPWGOYCA.js.map +1 -0
- package/dist/chunk-GQJ3QQPH.js +339 -0
- package/dist/chunk-GQJ3QQPH.js.map +1 -0
- package/dist/chunk-K2ELAI2X.js +64 -0
- package/dist/chunk-K2ELAI2X.js.map +1 -0
- package/dist/chunk-LRM6JJ63.js +616 -0
- package/dist/chunk-LRM6JJ63.js.map +1 -0
- package/dist/chunk-XAXFIIRT.js +959 -0
- package/dist/chunk-XAXFIIRT.js.map +1 -0
- package/dist/client/core/client-factory.d.ts +61 -0
- package/dist/client/core/client.d.ts +144 -0
- package/dist/client/core/errors.d.ts +105 -0
- package/dist/client/core/index.d.ts +9 -0
- package/dist/client/core/middleware.d.ts +67 -0
- package/dist/client/core/types.d.ts +99 -0
- package/dist/client/graphql/client.d.ts +66 -0
- package/dist/client/graphql/factory.d.ts +84 -0
- package/dist/client/graphql/operation.d.ts +24 -0
- package/dist/client/graphql/types.d.ts +60 -0
- package/dist/client/graphql/ws-client.d.ts +116 -0
- package/dist/client/index.d.ts +17 -0
- package/dist/client/index.js +227 -0
- package/dist/client/index.js.map +1 -0
- package/dist/client/middlewares/admin-auth.d.ts +90 -0
- package/dist/client/middlewares/auth.d.ts +81 -0
- package/dist/client/middlewares/index.d.ts +12 -0
- package/dist/client/middlewares/logging.d.ts +102 -0
- package/dist/client/middlewares/retry.d.ts +138 -0
- package/dist/client/middlewares/tenant.d.ts +60 -0
- package/dist/client/middlewares/turnstile.d.ts +41 -0
- package/dist/client/peer-free.d.ts +25 -0
- package/dist/client/utils/url.d.ts +19 -0
- package/dist/identity/index.d.ts +85 -0
- package/dist/identity/index.js +6 -0
- package/dist/identity/index.js.map +1 -0
- package/dist/identity/types.d.ts +690 -0
- package/dist/identity/v0.d.ts +594 -0
- package/dist/index.d.ts +50 -0
- package/dist/index.js +24 -0
- package/dist/index.js.map +1 -0
- package/dist/react/context.d.ts +47 -0
- package/dist/react/hooks.d.ts +120 -0
- package/dist/react/index.d.ts +19 -0
- package/dist/react/index.js +308 -0
- package/dist/react/index.js.map +1 -0
- package/dist/react/provider.d.ts +68 -0
- package/dist/react/store.d.ts +85 -0
- package/dist/storage/index.d.ts +31 -0
- package/dist/storage/index.js +5 -0
- package/dist/storage/index.js.map +1 -0
- package/dist/storage/types.d.ts +107 -0
- package/dist/storage/v0.d.ts +120 -0
- package/package.json +99 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/client/core/middleware.ts","../src/client/middlewares/retry.ts","../src/client/core/client.ts","../src/client/middlewares/auth.ts","../src/client/middlewares/tenant.ts","../src/client/core/client-factory.ts"],"names":["text"],"mappings":"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","file":"chunk-LRM6JJ63.js","sourcesContent":["/**\n * Middleware system for request/response interceptors\n */\n\nimport type { RequestContext, ResponseContext } from './types.js';\n\n/**\n * Middleware interface for intercepting requests and responses\n */\nexport interface Middleware {\n /** Unique identifier for the middleware */\n name: string;\n\n /**\n * Called before the request is sent\n * Can modify the request context or throw to abort\n */\n onRequest?: (ctx: RequestContext) => Promise<RequestContext> | RequestContext;\n\n /**\n * Called after a successful response is received\n * Can modify the response context or throw to trigger error handling\n */\n onResponse?: <T>(ctx: ResponseContext<T>) => Promise<ResponseContext<T>> | ResponseContext<T>;\n\n /**\n * Called when an error occurs during the request lifecycle\n * Can transform the error or re-throw\n */\n onError?: (error: Error, ctx: RequestContext) => Promise<never> | never;\n}\n\n/**\n * Execute the request middleware chain in order\n *\n * Middlewares are executed in the order they were added.\n * Each middleware can modify the context before passing it to the next.\n *\n * @param middlewares - Array of middlewares to execute\n * @param ctx - Initial request context\n * @returns Modified request context after all middlewares\n */\nexport async function executeRequestMiddlewares(\n middlewares: Middleware[],\n ctx: RequestContext\n): Promise<RequestContext> {\n let currentCtx = ctx;\n\n for (const middleware of middlewares) {\n if (middleware.onRequest) {\n currentCtx = await middleware.onRequest(currentCtx);\n }\n }\n\n return currentCtx;\n}\n\n/**\n * Execute the response middleware chain in reverse order\n *\n * Middlewares are executed in reverse order (last added runs first).\n * This allows middlewares to \"unwrap\" their effects in the correct order.\n *\n * @param middlewares - Array of middlewares to execute\n * @param ctx - Initial response context\n * @returns Modified response context after all middlewares\n */\nexport async function executeResponseMiddlewares<T>(\n middlewares: Middleware[],\n ctx: ResponseContext<T>\n): Promise<ResponseContext<T>> {\n let currentCtx = ctx;\n\n // Execute in reverse order for response processing\n for (let i = middlewares.length - 1; i >= 0; i--) {\n const middleware = middlewares[i];\n if (middleware.onResponse) {\n currentCtx = await middleware.onResponse(currentCtx);\n }\n }\n\n return currentCtx;\n}\n\n/**\n * Execute error handlers in the middleware chain\n *\n * EVERY middleware's `onError` handler runs, in registration order. Because\n * `onError` is typed `never` it signals completion by throwing, so a thrown\n * error is its normal exit path and must NOT terminate the chain — otherwise\n * the first handler that throws (e.g. the retry middleware, which always\n * throws) would silently swallow every handler registered after it.\n *\n * A handler may transform the error by throwing a different one; the\n * transformed error is passed to the remaining handlers and is what finally\n * propagates to the caller.\n *\n * @param middlewares - Array of middlewares to try\n * @param error - The error that occurred\n * @param ctx - The request context when the error occurred\n * @throws The original or transformed error\n */\nexport async function executeErrorMiddlewares(\n middlewares: Middleware[],\n error: Error,\n ctx: RequestContext\n): Promise<never> {\n let currentError = error;\n\n for (const middleware of middlewares) {\n if (!middleware.onError) {\n continue;\n }\n\n try {\n await middleware.onError(currentError, ctx);\n } catch (thrown) {\n // Throwing is how an `onError` handler returns. Adopt a transformed\n // error (if any) and continue so later handlers still observe it.\n if (thrown instanceof Error) {\n currentError = thrown;\n }\n }\n }\n\n throw currentError;\n}\n","import type { Middleware } from '../core/middleware.js';\nimport type { RequestContext } from '../core/types.js';\nimport { MPFError, MPFAPIError } from '../core/errors.js';\n\n/**\n * Options for the retry middleware.\n */\nexport interface RetryMiddlewareOptions {\n /**\n * Maximum number of retry attempts.\n * @default 3\n */\n maxRetries?: number;\n\n /**\n * Base delay in milliseconds between retries.\n * With exponential backoff, actual delay = retryDelay * (backoffFactor ^ attemptNumber)\n * @default 1000\n */\n retryDelay?: number;\n\n /**\n * HTTP status codes that trigger a retry.\n * @default [408, 429, 500, 502, 503, 504]\n */\n retryOn?: number[];\n\n /**\n * Exponential backoff factor.\n * Each retry waits: retryDelay * (backoffFactor ^ attemptNumber)\n * @default 2\n */\n backoffFactor?: number;\n\n /**\n * Maximum delay in milliseconds between retries (caps exponential growth).\n * @default 30000 (30 seconds)\n */\n maxDelay?: number;\n\n /**\n * Whether to add random jitter to retry delays (prevents thundering herd).\n * When enabled, adds random jitter up to 25% of the calculated delay.\n * @default true\n */\n jitter?: boolean;\n\n /**\n * Optional callback called before each retry attempt.\n * Can be used for logging or metrics.\n */\n onRetry?: (attempt: number, error: Error, delay: number) => void | Promise<void>;\n\n /**\n * Custom function to determine if an error should trigger a retry.\n * If provided, this takes precedence over retryOn status codes.\n */\n shouldRetry?: (error: Error, attempt: number) => boolean;\n}\n\n/** Metadata key for storing retry attempt count */\nconst RETRY_ATTEMPT_KEY = '__retryAttempt';\n\n/** Metadata key set by the retry middleware to request another attempt */\nconst SHOULD_RETRY_KEY = '__shouldRetry';\n\n/**\n * Metadata key marking a request as non-retryable regardless of what any\n * middleware asks for (e.g. a one-shot streaming body that cannot be re-sent).\n */\nconst NO_RETRY_KEY = '__noRetry';\n\n/**\n * Default HTTP status codes that should trigger a retry.\n * - 408: Request Timeout\n * - 429: Too Many Requests\n * - 500: Internal Server Error\n * - 502: Bad Gateway\n * - 503: Service Unavailable\n * - 504: Gateway Timeout\n */\nconst DEFAULT_RETRY_STATUS_CODES = [408, 429, 500, 502, 503, 504];\n\n/**\n * Sleep for a specified duration.\n */\nfunction sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n\n/**\n * Calculate delay with exponential backoff and optional jitter.\n */\nfunction calculateDelay(\n attempt: number,\n baseDelay: number,\n backoffFactor: number,\n maxDelay: number,\n useJitter: boolean\n): number {\n // Calculate exponential delay: baseDelay * (factor ^ attempt)\n const exponentialDelay = baseDelay * Math.pow(backoffFactor, attempt);\n\n // Cap at maxDelay\n const cappedDelay = Math.min(exponentialDelay, maxDelay);\n\n // Add jitter (0-25% of the delay) to prevent thundering herd\n if (useJitter) {\n const jitterFactor = 1 + Math.random() * 0.25;\n return Math.floor(cappedDelay * jitterFactor);\n }\n\n return Math.floor(cappedDelay);\n}\n\n/**\n * Creates a retry middleware with exponential backoff.\n *\n * The middleware:\n * - Automatically retries failed requests based on HTTP status codes\n * - Uses exponential backoff to space out retry attempts\n * - Optionally adds jitter to prevent thundering herd problems\n * - Respects Retry-After headers when present\n *\n * @param options - Configuration options for the retry middleware\n * @returns A middleware instance\n *\n * @example\n * ```typescript\n * const retryMiddleware = createRetryMiddleware({\n * maxRetries: 3,\n * retryDelay: 1000,\n * retryOn: [500, 502, 503, 504],\n * });\n * ```\n *\n * @example\n * ```typescript\n * // With custom retry logic\n * const retryMiddleware = createRetryMiddleware({\n * maxRetries: 5,\n * retryDelay: 500,\n * backoffFactor: 1.5,\n * jitter: true,\n * onRetry: (attempt, error, delay) => {\n * console.log(`Retry attempt ${attempt} after ${delay}ms:`, error.message);\n * },\n * shouldRetry: (error, attempt) => {\n * // Custom retry logic\n * if (error instanceof MPFError && error.status) {\n * return error.status >= 500 && attempt < 3;\n * }\n * return false;\n * }\n * });\n * ```\n */\nexport function createRetryMiddleware(options?: RetryMiddlewareOptions): Middleware {\n const {\n maxRetries = 3,\n retryDelay = 1000,\n retryOn = DEFAULT_RETRY_STATUS_CODES,\n backoffFactor = 2,\n maxDelay = 30000,\n jitter = true,\n onRetry,\n shouldRetry: customShouldRetry,\n } = options ?? {};\n\n /**\n * Determine if an error should trigger a retry.\n */\n function shouldRetry(error: Error, attempt: number): boolean {\n // Don't retry if we've exhausted attempts\n if (attempt >= maxRetries) {\n return false;\n }\n\n // Use custom retry logic if provided\n if (customShouldRetry) {\n return customShouldRetry(error, attempt);\n }\n\n // Check if it's an MPF error with a retryable status code\n if (error instanceof MPFError && error.status !== undefined) {\n return retryOn.includes(error.status);\n }\n\n // Retry on network errors (no status code)\n if (error.name === 'TypeError' && error.message.includes('fetch')) {\n return true;\n }\n\n return false;\n }\n\n /**\n * Get delay from Retry-After header if present.\n * Note: This requires the error to have a retryAfter property or be passed separately.\n * For MPFAPIError, we check the details for a retryAfter value.\n */\n function getRetryAfterDelay(error: Error): number | null {\n // Check if error has details with retryAfter (from API response)\n if (error instanceof MPFAPIError && error.details) {\n const details = error.details as Record<string, unknown>;\n const retryAfter = details['retryAfter'] || details['retry-after'] || details['Retry-After'];\n\n if (typeof retryAfter === 'number') {\n return retryAfter * 1000;\n }\n\n if (typeof retryAfter === 'string') {\n // Retry-After can be seconds or a date string\n const seconds = parseInt(retryAfter, 10);\n if (!isNaN(seconds)) {\n return seconds * 1000;\n }\n\n // Try parsing as date\n const date = new Date(retryAfter);\n if (!isNaN(date.getTime())) {\n const delay = date.getTime() - Date.now();\n return delay > 0 ? delay : null;\n }\n }\n }\n\n return null;\n }\n\n return {\n name: 'retry',\n\n onRequest(ctx: RequestContext): RequestContext {\n // Initialize retry attempt counter if not present\n if (ctx.metadata[RETRY_ATTEMPT_KEY] === undefined) {\n ctx.metadata[RETRY_ATTEMPT_KEY] = 0;\n }\n return ctx;\n },\n\n async onError(error: Error, ctx: RequestContext): Promise<never> {\n const currentAttempt = (ctx.metadata[RETRY_ATTEMPT_KEY] as number) ?? 0;\n\n if (!shouldRetry(error, currentAttempt)) {\n throw error;\n }\n\n // Calculate delay\n let delay = getRetryAfterDelay(error);\n if (delay === null) {\n delay = calculateDelay(currentAttempt, retryDelay, backoffFactor, maxDelay, jitter);\n }\n\n // Cap Retry-After delay at maxDelay\n delay = Math.min(delay, maxDelay);\n\n // Call onRetry callback if provided\n if (onRetry) {\n try {\n await onRetry(currentAttempt + 1, error, delay);\n } catch (callbackError) {\n // Log but don't fail the retry\n console.error('[MPF SDK] Error in onRetry callback:', callbackError);\n }\n }\n\n // Wait before retrying\n await sleep(delay);\n\n // Increment attempt counter\n ctx.metadata[RETRY_ATTEMPT_KEY] = currentAttempt + 1;\n\n // Mark that this request should be retried.\n // MPFClient.request() checks this flag after the error middleware chain\n // has run and starts another attempt when it is set.\n requestRetry(ctx);\n\n // Re-throw to signal the SDK to retry\n // The SDK should catch this and check __shouldRetry\n throw error;\n },\n };\n}\n\n/**\n * Check if a request context indicates a retry should be attempted.\n * Used by `MPFClient.request()` to decide whether to run another attempt.\n *\n * Returns false when the request has been marked non-retryable, even if a\n * middleware asked for a retry.\n */\nexport function shouldRetryRequest(ctx: RequestContext): boolean {\n return ctx.metadata[SHOULD_RETRY_KEY] === true && !isRetryDisabled(ctx);\n}\n\n/**\n * Ask `MPFClient.request()` to run another attempt.\n *\n * The single writer of the retry flag. Any middleware that can recover from an\n * error (the auth middleware's renew-and-retry, for instance) calls this from\n * its `onError` and then rethrows.\n *\n * The client consults the flag unconditionally, so this works whether or not\n * `createRetryMiddleware` is registered.\n */\nexport function requestRetry(ctx: RequestContext): void {\n ctx.metadata[SHOULD_RETRY_KEY] = true;\n}\n\n/**\n * Mark a request as non-retryable. Used for request bodies that cannot be\n * re-sent (a `ReadableStream` is consumed by the first attempt).\n */\nexport function disableRetry(ctx: RequestContext): void {\n ctx.metadata[NO_RETRY_KEY] = true;\n}\n\n/**\n * Whether the request has been marked non-retryable.\n */\nexport function isRetryDisabled(ctx: RequestContext): boolean {\n return ctx.metadata[NO_RETRY_KEY] === true;\n}\n\n/**\n * Whether a fetch body can be sent more than once.\n *\n * `FormData`, `Blob`, `ArrayBuffer`, `URLSearchParams` and strings are all\n * re-readable, so retrying them is safe. A `ReadableStream` is consumed by the\n * first attempt and must never be retried.\n */\nexport function isReplayableBody(body: BodyInit | null | undefined): boolean {\n if (body === null || body === undefined) {\n return true;\n }\n\n if (typeof ReadableStream !== 'undefined' && body instanceof ReadableStream) {\n return false;\n }\n\n return true;\n}\n\n/**\n * Get the current retry attempt number from request context.\n */\nexport function getRetryAttempt(ctx: RequestContext): number {\n return (ctx.metadata[RETRY_ATTEMPT_KEY] as number) ?? 0;\n}\n\n/**\n * Clear the retry flag from the request context.\n * Should be called after a successful retry or when giving up.\n */\nexport function clearRetryFlag(ctx: RequestContext): void {\n delete ctx.metadata[SHOULD_RETRY_KEY];\n}\n","/**\n * Base HTTP client for the MPF SDK\n */\n\nimport type { ClientConfig, RequestOptions, RequestContext, ResponseContext, APIErrorResponse } from './types.js';\nimport type { Middleware } from './middleware.js';\nimport { executeRequestMiddlewares, executeResponseMiddlewares, executeErrorMiddlewares } from './middleware.js';\nimport { MPFNetworkError, MPFAPIError, MPFAuthError } from './errors.js';\nimport { shouldRetryRequest, clearRetryFlag, disableRetry, isReplayableBody } from '../middlewares/retry.js';\n\n/**\n * Hard ceiling on the number of attempts a single `request()` call may make\n * (the initial attempt plus retries).\n *\n * This is deliberately independent of any middleware's own `maxRetries`: a\n * misbehaving or misconfigured middleware can keep asking for retries, and this\n * bound guarantees the loop terminates. 4 attempts = 1 initial + 3 retries,\n * matching the retry middleware's default `maxRetries: 3`.\n */\nexport const MAX_REQUEST_ATTEMPTS = 4;\n\n/**\n * Base client for making HTTP requests with middleware support\n */\nexport class MPFClient {\n protected readonly baseUrl: string;\n protected readonly defaultHeaders: Record<string, string>;\n protected readonly middlewares: Middleware[];\n\n constructor(config: ClientConfig) {\n // Remove trailing slash from base URL for consistent URL building\n this.baseUrl = config.baseUrl.replace(/\\/+$/, '');\n this.defaultHeaders = {\n 'Content-Type': 'application/json',\n 'Accept': 'application/json',\n ...config.headers,\n };\n this.middlewares = [...(config.middlewares ?? [])];\n }\n\n /**\n * Add a middleware to the client\n * Middlewares are executed in the order they are added for requests,\n * and in reverse order for responses.\n *\n * @param middleware - The middleware to add\n * @returns The client instance for chaining\n */\n use(middleware: Middleware): this {\n this.middlewares.push(middleware);\n return this;\n }\n\n /**\n * Build a full URL with query parameters\n *\n * @param path - The API path (e.g., \"/users\" or \"users\")\n * @param params - Optional query parameters\n * @returns The full URL with query string\n */\n protected buildUrl(path: string, params?: Record<string, string | number | boolean | undefined>): string {\n // Ensure path starts with a slash\n const normalizedPath = path.startsWith('/') ? path : `/${path}`;\n const base = /^https?:\\/\\//.test(this.baseUrl)\n ? this.baseUrl\n : (typeof window !== 'undefined' ? window.location.origin : 'http://localhost');\n const url = new URL(`${this.baseUrl}${normalizedPath}`, base);\n\n if (params) {\n for (const [key, value] of Object.entries(params)) {\n if (value !== undefined && value !== null) {\n url.searchParams.append(key, String(value));\n }\n }\n }\n\n return url.toString();\n }\n\n /**\n * Merge headers from different sources\n *\n * @param requestHeaders - Headers specific to this request\n * @returns Merged headers object\n */\n protected mergeHeaders(requestHeaders?: Record<string, string>): Record<string, string> {\n return {\n ...this.defaultHeaders,\n ...requestHeaders,\n };\n }\n\n /**\n * Build the headers for a single attempt.\n *\n * Rebuilt per attempt so request middlewares (auth, turnstile, ...) always\n * inject a fresh token instead of replaying a stale one.\n *\n * For a `FormData` body the default JSON `Content-Type` is dropped so that\n * fetch sets `multipart/form-data` with the correct boundary.\n */\n private buildAttemptHeaders(init: RequestInit): Record<string, string> {\n const headers = this.mergeHeaders(init.headers as Record<string, string> | undefined);\n\n if (typeof FormData !== 'undefined' && init.body instanceof FormData) {\n delete headers['Content-Type'];\n }\n\n return headers;\n }\n\n /**\n * Parse the response body based on content type\n *\n * @param response - The fetch Response object\n * @returns Parsed response data\n */\n protected async parseResponse<T>(response: Response): Promise<T> {\n const contentType = response.headers.get('content-type') ?? '';\n\n // Handle empty responses (204 No Content, etc.)\n if (response.status === 204 || response.headers.get('content-length') === '0') {\n return undefined as T;\n }\n\n // Parse JSON responses\n if (contentType.includes('application/json')) {\n const text = await response.text();\n if (!text) {\n return undefined as T;\n }\n try {\n return JSON.parse(text) as T;\n } catch {\n throw new MPFAPIError(\n 'Failed to parse JSON response',\n 'PARSE_ERROR',\n response.status,\n { text }\n );\n }\n }\n\n // Return text for non-JSON responses\n const text = await response.text();\n return text as T;\n }\n\n /**\n * Handle error responses from the API\n *\n * @param response - The fetch Response object\n * @throws MPFAuthError for 401/403, MPFAPIError for other errors\n */\n protected async handleErrorResponse(response: Response): Promise<never> {\n let body: unknown;\n let errorResponse: APIErrorResponse | undefined;\n\n try {\n const text = await response.text();\n if (text) {\n body = JSON.parse(text);\n errorResponse = body as APIErrorResponse;\n }\n } catch {\n // Body is not JSON, that's fine\n }\n\n const message = errorResponse?.message ?? errorResponse?.error ?? response.statusText ?? 'Request failed';\n const code = errorResponse?.code ?? `HTTP_${response.status}`;\n const details = errorResponse?.details;\n\n // Handle authentication errors\n if (response.status === 401) {\n const authType = code.toLowerCase().includes('expired') ? 'token_expired' : 'unauthorized';\n // Preserve the server's own code: `authType` collapses distinct 401s\n // (notably REFRESH_TOKEN_SUPERSEDED) into 'unauthorized'.\n throw new MPFAuthError(message, authType, 401, details, errorResponse?.code);\n }\n\n if (response.status === 403) {\n throw new MPFAuthError(message, 'forbidden', 403, details, errorResponse?.code);\n }\n\n // Handle all other errors\n throw new MPFAPIError(message, code, response.status, details, body);\n }\n\n /**\n * Execute an HTTP request with the full middleware chain, retrying when a\n * middleware asks for it.\n *\n * Retry contract:\n * - `metadata` is created once and shared by every attempt. Middlewares keep\n * their per-request state there (retry counter, auth-renew flag); rebuilding\n * it per attempt would reset those counters and loop forever.\n * - `init.headers` are rebuilt per attempt so request middlewares re-inject a\n * fresh token rather than replaying the first attempt's headers.\n * - `MAX_REQUEST_ATTEMPTS` bounds the loop regardless of middleware config.\n * - Bodies that cannot be re-sent (`ReadableStream`) disable retrying.\n *\n * @param path - The API path\n * @param init - Fetch RequestInit options\n * @returns The parsed response data\n * @throws MPFNetworkError for network failures\n * @throws MPFAuthError for 401/403 responses\n * @throws MPFAPIError for other error responses\n */\n async request<T>(path: string, init: RequestInit = {}, params?: Record<string, string | number | boolean | undefined>, options?: RequestOptions): Promise<T> {\n const url = this.buildUrl(path, params);\n\n // Shared across every attempt — see the retry contract above.\n const metadata: Record<string, unknown> = {};\n\n for (let attempt = 0; attempt < MAX_REQUEST_ATTEMPTS; attempt++) {\n const requestCtx: RequestContext = {\n url,\n init: {\n ...init,\n headers: this.buildAttemptHeaders(init),\n },\n metadata,\n options,\n };\n\n if (!isReplayableBody(init.body)) {\n disableRetry(requestCtx);\n }\n\n try {\n return await this.attempt<T>(requestCtx);\n } catch (error) {\n // The error middleware chain already ran inside attempt(); a retry\n // middleware has had its chance to set the retry flag (and to sleep for\n // its backoff) by now.\n const isLastAttempt = attempt === MAX_REQUEST_ATTEMPTS - 1;\n\n if (isLastAttempt || !shouldRetryRequest(requestCtx)) {\n throw error;\n }\n\n clearRetryFlag(requestCtx);\n }\n }\n\n // Unreachable: the loop either returns or throws on the last attempt.\n throw new MPFNetworkError('Request retry loop exhausted');\n }\n\n /**\n * Execute a single request attempt through the middleware chain.\n *\n * On failure the error middleware chain runs before the error propagates, so\n * the caller can inspect `ctx.metadata` for a retry request.\n */\n private async attempt<T>(ctx: RequestContext): Promise<T> {\n let requestCtx = ctx;\n\n try {\n // Execute request middlewares\n requestCtx = await executeRequestMiddlewares(this.middlewares, requestCtx);\n\n // Make the actual fetch request\n let response: Response;\n try {\n response = await fetch(requestCtx.url, requestCtx.init);\n } catch (error) {\n throw new MPFNetworkError(\n error instanceof Error ? error.message : 'Network request failed',\n error instanceof Error ? error : undefined\n );\n }\n\n // Handle error responses\n if (!response.ok) {\n await this.handleErrorResponse(response);\n }\n\n // Parse successful response\n const data = await this.parseResponse<T>(response);\n\n // Build response context\n let responseCtx: ResponseContext<T> = {\n response,\n data,\n metadata: requestCtx.metadata,\n };\n\n // Execute response middlewares\n responseCtx = await executeResponseMiddlewares(this.middlewares, responseCtx);\n\n return responseCtx.data;\n } catch (error) {\n try {\n // Execute error middlewares if available\n if (error instanceof Error && this.middlewares.some(m => m.onError)) {\n await executeErrorMiddlewares(this.middlewares, error, requestCtx);\n }\n throw error;\n } finally {\n // A request middleware may have returned a cloned context; make sure\n // any metadata it wrote (including the retry flag) reaches the caller's\n // shared metadata object.\n if (requestCtx.metadata !== ctx.metadata) {\n Object.assign(ctx.metadata, requestCtx.metadata);\n }\n }\n }\n }\n\n /**\n * Make a GET request\n *\n * @param path - The API path\n * @param options - Request options\n * @returns The parsed response data\n */\n async get<T>(path: string, options: RequestOptions = {}): Promise<T> {\n return this.request<T>(path, {\n method: 'GET',\n headers: options.headers,\n signal: options.signal,\n }, options.params, options);\n }\n\n /**\n * Make a POST request\n *\n * @param path - The API path\n * @param body - Request body (will be JSON stringified)\n * @param options - Request options\n * @returns The parsed response data\n */\n async post<T>(path: string, body?: unknown, options: RequestOptions = {}): Promise<T> {\n return this.request<T>(path, {\n method: 'POST',\n headers: options.headers,\n signal: options.signal,\n body: body !== undefined ? JSON.stringify(body) : undefined,\n }, options.params, options);\n }\n\n /**\n * Make a PUT request\n *\n * @param path - The API path\n * @param body - Request body (will be JSON stringified)\n * @param options - Request options\n * @returns The parsed response data\n */\n async put<T>(path: string, body?: unknown, options: RequestOptions = {}): Promise<T> {\n return this.request<T>(path, {\n method: 'PUT',\n headers: options.headers,\n signal: options.signal,\n body: body !== undefined ? JSON.stringify(body) : undefined,\n }, options.params, options);\n }\n\n /**\n * Make a PATCH request\n *\n * @param path - The API path\n * @param body - Request body (will be JSON stringified)\n * @param options - Request options\n * @returns The parsed response data\n */\n async patch<T>(path: string, body?: unknown, options: RequestOptions = {}): Promise<T> {\n return this.request<T>(path, {\n method: 'PATCH',\n headers: options.headers,\n signal: options.signal,\n body: body !== undefined ? JSON.stringify(body) : undefined,\n }, options.params, options);\n }\n\n /**\n * Make a DELETE request\n *\n * @param path - The API path\n * @param body - Optional request body (will be JSON stringified)\n * @param options - Request options\n * @returns The parsed response data\n */\n async delete<T>(path: string, body?: unknown, options: RequestOptions = {}): Promise<T> {\n return this.request<T>(path, {\n method: 'DELETE',\n headers: options.headers,\n signal: options.signal,\n body: body !== undefined ? JSON.stringify(body) : undefined,\n }, options.params, options);\n }\n}\n","import type { Middleware } from '../core/middleware.js';\nimport type { RequestContext } from '../core/types.js';\nimport { MPFError } from '../core/errors.js';\nimport { requestRetry } from './retry.js';\n\n/**\n * Metadata key: set in `onRequest` only when an Authorization header was\n * actually injected.\n *\n * This is the wrong-password guard. Without it, a 401 from `signIn` (bad\n * credentials, `skipAuth`, no token yet) is indistinguishable from a 401 caused\n * by an expired session, and every consumer ends up reimplementing the same\n * check in app code — usually by string-matching an error message. Keying off\n * \"did we send a token\" makes it structural.\n */\nconst TOKEN_ATTACHED_KEY = '__authTokenAttached';\n\n/**\n * Metadata key: set BEFORE awaiting the renew, capping renewal at one attempt\n * per logical request no matter how many times the retry loop runs.\n *\n * Set before rather than after the await because two concurrent error handlers\n * on the same request would otherwise both observe \"not attempted\" and both\n * renew — and the refresh token is single-use, so the second renew kills the\n * session it was trying to save.\n */\nconst RENEW_ATTEMPTED_KEY = '__authRenewAttempted';\n\n/**\n * Options for the auth middleware.\n */\nexport interface AuthMiddlewareOptions {\n /**\n * Function to get the current access token.\n * Can be sync or async (e.g., reading from localStorage or refreshing token).\n *\n * @returns The access token, or null if not authenticated\n */\n getAccessToken: () => string | null | Promise<string | null>;\n\n /**\n * Called when a 401 is final — i.e. a token WAS attached and renewal either\n * was not possible, failed, or had already been tried for this request.\n *\n * This is the \"log the user out\" hook. It is deliberately NOT called for a\n * 401 on a request that carried no token (a wrong password must not log you\n * out of a session you do have), nor for the first 401 when `onUnauthorized`\n * successfully renews.\n */\n onTokenExpired?: () => void | Promise<void>;\n\n /**\n * Called on the first 401 of a request that DID carry a token.\n *\n * Should attempt a session renewal and resolve `true` when a fresh token is\n * now available, `false` otherwise. On `true` the request is retried once,\n * with headers rebuilt so the new token is picked up.\n *\n * Capped at one call per logical request by `__authRenewAttempted`, so a\n * second 401 falls through to `onTokenExpired` instead of looping.\n */\n onUnauthorized?: () => Promise<boolean>;\n\n /**\n * The token type prefix for the Authorization header.\n * @default 'Bearer'\n */\n tokenType?: string;\n\n /**\n * Custom header name for the authorization token.\n * @default 'Authorization'\n */\n headerName?: string;\n}\n\n/**\n * Creates an authentication middleware that adds authorization headers to requests.\n *\n * The middleware:\n * - Adds an Authorization header with the token from getAccessToken()\n * - Calls onTokenExpired() when a 401 response is received\n *\n * @param options - Configuration options for the auth middleware\n * @returns A middleware instance\n *\n * @example\n * ```typescript\n * const authMiddleware = createAuthMiddleware({\n * getAccessToken: () => localStorage.getItem('accessToken'),\n * onTokenExpired: () => {\n * // Redirect to login or refresh token\n * window.location.href = '/login';\n * }\n * });\n * ```\n *\n * @example\n * ```typescript\n * // With async token retrieval\n * const authMiddleware = createAuthMiddleware({\n * getAccessToken: async () => {\n * const session = await authService.getSession();\n * return session?.accessToken ?? null;\n * },\n * tokenType: 'Bearer',\n * onTokenExpired: async () => {\n * await authService.refreshToken();\n * }\n * });\n * ```\n */\nexport function createAuthMiddleware(options: AuthMiddlewareOptions): Middleware {\n const {\n getAccessToken,\n onTokenExpired,\n onUnauthorized,\n tokenType = 'Bearer',\n headerName = 'Authorization',\n } = options;\n\n return {\n name: 'auth',\n\n async onRequest(ctx: RequestContext): Promise<RequestContext> {\n if (ctx.options?.skipAuth) {\n return ctx;\n }\n\n const token = await getAccessToken();\n\n if (token) {\n // Create a new Headers object to avoid mutating the original\n const headers = new Headers(ctx.init.headers);\n headers.set(headerName, `${tokenType} ${token}`);\n ctx.init.headers = headers;\n\n // Record that THIS attempt actually carried a token.\n ctx.metadata[TOKEN_ATTACHED_KEY] = true;\n }\n\n return ctx;\n },\n\n async onError(error: Error, ctx: RequestContext): Promise<never> {\n // Key off the numeric status, not the error's classification string: the\n // classification is derived from a server-supplied code and is not a\n // reliable discriminator.\n const status = error instanceof MPFError ? error.status : undefined;\n if (status !== 401) {\n throw error;\n }\n\n // Guard 1: no token was attached, so this 401 is about the credentials in\n // the request body (wrong password, expired invite, ...) and says nothing\n // about session health. Do not renew and do not log anyone out.\n if (ctx.metadata[TOKEN_ATTACHED_KEY] !== true) {\n throw error;\n }\n\n // Guard 2: at most one renewal per logical request. Set before awaiting.\n if (onUnauthorized && ctx.metadata[RENEW_ATTEMPTED_KEY] !== true) {\n ctx.metadata[RENEW_ATTEMPTED_KEY] = true;\n\n let renewed = false;\n try {\n renewed = await onUnauthorized();\n } catch (renewError) {\n console.error('[MPF SDK] Error in onUnauthorized callback:', renewError);\n renewed = false;\n }\n\n if (renewed) {\n // Retry once. The client rebuilds headers per attempt, so the fresh\n // token is picked up automatically.\n requestRetry(ctx);\n throw error;\n }\n }\n\n // The 401 is final: renewal was impossible, failed, or already tried.\n if (onTokenExpired) {\n try {\n await onTokenExpired();\n } catch (callbackError) {\n // Log but don't swallow the original error\n console.error('[MPF SDK] Error in onTokenExpired callback:', callbackError);\n }\n }\n\n // Always re-throw the original error\n throw error;\n },\n };\n}\n","import type { Middleware } from '../core/middleware.js';\nimport type { RequestContext } from '../core/types.js';\nimport type { MPFRole } from '../../auth/claims-types.js';\nimport type { TenantSelectionStore } from '../../auth/tenant-selection.js';\nimport { tryDecodeAccessToken } from '../../auth/claims.js';\n\n/** Header carrying the selected tenant id. */\nexport const TENANT_HEADER = 'X-MPF-Tenant';\n\n/** Header carrying the selected role within that tenant. */\nexport const TENANT_ROLE_HEADER = 'X-MPF-Tenant-Role';\n\n/**\n * Options for the tenant middleware.\n */\nexport interface TenantMiddlewareOptions {\n /**\n * The shared tenant selection. Read per request, so a `set()` takes effect on\n * the next request with no client reconstruction.\n */\n tenantProvider?: TenantSelectionStore;\n\n /**\n * Access-token getter, used ONLY for the under-scoping warning below. When\n * omitted the warning is disabled.\n *\n * Decoding is LRU-cached, and the warning fires at most once per middleware,\n * so this costs nothing in steady state.\n */\n getAccessToken?: () => string | null | Promise<string | null>;\n\n /**\n * Whether to warn once when a request goes out unscoped while the token holds\n * tenants.\n * @default true\n */\n warnOnUnscoped?: boolean;\n\n /** Logger for the warning. Defaults to `console`. */\n logger?: { warn: (message: string, ...args: unknown[]) => void };\n}\n\nconst UNSCOPED_WARNING =\n '[MPF SDK] Request sent with no tenant selected, but the access token holds tenant ' +\n 'memberships. The server will scope this request to the default (tenantless) role, ' +\n 'which usually means empty results or a 403 rather than tenant data. Wire a ' +\n 'tenantProvider (createTenantSelection()) into your client and call set(tenantId), ' +\n 'or pass `{ tenant: null }` on the request to state explicitly that it is unscoped. ' +\n 'This warning is shown once.';\n\n/**\n * Creates a middleware that puts the selected tenant on the wire.\n *\n * Resolution order for the tenant, using the three states of\n * `options.tenant`:\n *\n * | `options.tenant` | meaning |\n * |-------------------|--------------------------------------------|\n * | `undefined` | inherit the client-wide selection |\n * | `null` | deliberately unscoped for THIS request |\n * | `\"<uuid>\"` | that tenant, for THIS request |\n *\n * `options.skipTenant` bypasses the middleware entirely.\n *\n * Header rules:\n * - The tenant header is **omitted entirely** when there is no tenant. An\n * empty-string header is a 400 server-side, deliberately, so that a bug\n * cannot masquerade as the no-tenant path.\n * - The role header is omitted unless a role was specified, letting the server\n * apply that tenant's default role (its `dfr`, or `rls[0]` when it has\n * none).\n * - A per-request tenant does NOT inherit the client-wide role: the role only\n * travels with the selection it belongs to. Selecting tenant B while tenant\n * A's role is selected must not send A's role to B.\n */\nexport function createTenantMiddleware(options: TenantMiddlewareOptions = {}): Middleware {\n const {\n tenantProvider,\n getAccessToken,\n warnOnUnscoped = true,\n logger = console,\n } = options;\n\n let warned = false;\n\n async function maybeWarnUnscoped(): Promise<void> {\n if (warned || !warnOnUnscoped || !getAccessToken) {\n return;\n }\n\n // Mark first: a failure below must not turn this into a per-request cost,\n // and the warning is best-effort diagnostics.\n let token: string | null;\n try {\n token = await getAccessToken();\n } catch {\n return;\n }\n\n const claims = tryDecodeAccessToken(token);\n if (!claims || claims.tnts.length === 0) {\n return;\n }\n\n warned = true;\n logger.warn(UNSCOPED_WARNING);\n }\n\n return {\n name: 'tenant',\n\n async onRequest(ctx: RequestContext): Promise<RequestContext> {\n if (ctx.options?.skipTenant) {\n return ctx;\n }\n\n const perRequest = ctx.options?.tenant;\n const inherit = perRequest === undefined;\n const selection = inherit ? tenantProvider?.get() : undefined;\n\n const tenant: string | null = inherit ? (selection?.tenant ?? null) : perRequest;\n\n // Role travels with its own selection; see the note above.\n const role: MPFRole | undefined =\n ctx.options?.tenantRole ?? (inherit ? selection?.role : undefined);\n\n if (tenant === null || tenant === '') {\n // Warn only when the request is unscoped by OMISSION, never when the\n // caller passed `{ tenant: null }`. Explicit null is a developer stating\n // intent; `undefined` with a tenant-bearing token is the oversight we\n // are trying to catch. Warning on the deliberate case would train people\n // to ignore the warning and cost us the signal in the case that matters\n // — which is the whole reason `undefined | null | string` is three-state.\n if (inherit) {\n await maybeWarnUnscoped();\n }\n return ctx;\n }\n\n const headers = new Headers(ctx.init.headers);\n headers.set(TENANT_HEADER, tenant);\n if (role !== undefined && role !== '') {\n headers.set(TENANT_ROLE_HEADER, role);\n }\n ctx.init.headers = headers;\n\n return ctx;\n },\n };\n}\n","/**\n * Generic HTTP client factory.\n *\n * `createAuthClient`, `createStorageClient` and `createGraphQLClient` all wire\n * the SAME two middlewares (auth, tenant) by hand today, which is how they\n * drift: three copies of \"if tokenProvider, use(createAuthMiddleware(...))\".\n * This is the single place that wiring happens now; the three factories\n * become thin wrappers that just pick the right `MPFClient` subclass.\n *\n * The point of pulling this out is reuse, NOT a new concept: a `tokenProvider`\n * here is still just `{ getAccessToken, onTokenExpired?, onUnauthorized? }` —\n * typically `{ getAccessToken: () => sessionManager.getAccessToken(), ... }`\n * from ONE shared `SessionManager` (see `auth/session-manager.ts`), so every\n * client built through this factory (REST or GraphQL) shares the same\n * proactive/reactive renewal, coalesced to one network call across the whole\n * browser — not per client, not just per tab.\n */\n\nimport { MPFClient } from './client.js';\nimport type { ClientConfig, TokenProvider } from './types.js';\nimport { createAuthMiddleware } from '../middlewares/auth.js';\nimport { createTenantMiddleware } from '../middlewares/tenant.js';\nimport type { TenantSelectionStore } from '../../auth/tenant-selection.js';\n\n/**\n * Configuration shared by every client built through this factory.\n */\nexport interface HttpClientOptions extends ClientConfig {\n /**\n * Optional token provider. When provided, auto-wires the auth middleware so\n * every request carries `Authorization: Bearer <token>` and 401s trigger\n * renewal per {@link TokenProvider.onUnauthorized}.\n *\n * Share ONE instance (backed by ONE `SessionManager`) across every client an\n * app constructs — that is what makes renewal happen once per browser\n * rather than once per client.\n */\n tokenProvider?: TokenProvider;\n /**\n * Optional shared tenant selection. When provided, every request carries the\n * selected tenant headers. Construct it once with `createTenantSelection()`\n * and share the same instance across every client.\n */\n tenantProvider?: TenantSelectionStore;\n}\n\n/**\n * Attach the standard auth + tenant middlewares to an already-constructed\n * client, in the standard order (auth before tenant — the tenant middleware's\n * under-scoping warning needs a token to decode).\n *\n * Exists as its own function (not inlined in {@link createHttpClient}) so a\n * subclass-specific factory (`createAuthClient`, `createStorageClient`,\n * `createGraphQLClient`) can construct its own `MPFClient` subclass and still\n * reuse this exact wiring instead of re-deriving it.\n */\nexport function attachStandardMiddlewares(\n client: MPFClient,\n options: Pick<HttpClientOptions, 'tokenProvider' | 'tenantProvider'>,\n): void {\n const { tokenProvider, tenantProvider } = options;\n\n if (tokenProvider) {\n client.use(\n createAuthMiddleware({\n getAccessToken: tokenProvider.getAccessToken,\n onTokenExpired: tokenProvider.onTokenExpired,\n ...(tokenProvider.onUnauthorized ? { onUnauthorized: tokenProvider.onUnauthorized } : {}),\n }),\n );\n }\n\n if (tenantProvider) {\n client.use(\n createTenantMiddleware({\n tenantProvider,\n ...(tokenProvider ? { getAccessToken: tokenProvider.getAccessToken } : {}),\n }),\n );\n }\n}\n\n/**\n * Create a generic HTTP client with the standard auth + tenant middlewares\n * pre-wired.\n *\n * Use this directly for a plain REST client; `createAuthClient` and\n * `createStorageClient` use it internally for their typed `MPFClient`\n * subclasses, and `createGraphQLClient` uses it for its HTTP transport.\n */\nexport function createHttpClient(options: HttpClientOptions): MPFClient {\n const { tokenProvider, tenantProvider, ...clientConfig } = options;\n const client = new MPFClient(clientConfig);\n attachStandardMiddlewares(client, { tokenProvider, tenantProvider });\n return client;\n}\n"]}
|