@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,138 @@
1
+ import type { Middleware } from '../core/middleware.js';
2
+ import type { RequestContext } from '../core/types.js';
3
+ /**
4
+ * Options for the retry middleware.
5
+ */
6
+ export interface RetryMiddlewareOptions {
7
+ /**
8
+ * Maximum number of retry attempts.
9
+ * @default 3
10
+ */
11
+ maxRetries?: number;
12
+ /**
13
+ * Base delay in milliseconds between retries.
14
+ * With exponential backoff, actual delay = retryDelay * (backoffFactor ^ attemptNumber)
15
+ * @default 1000
16
+ */
17
+ retryDelay?: number;
18
+ /**
19
+ * HTTP status codes that trigger a retry.
20
+ * @default [408, 429, 500, 502, 503, 504]
21
+ */
22
+ retryOn?: number[];
23
+ /**
24
+ * Exponential backoff factor.
25
+ * Each retry waits: retryDelay * (backoffFactor ^ attemptNumber)
26
+ * @default 2
27
+ */
28
+ backoffFactor?: number;
29
+ /**
30
+ * Maximum delay in milliseconds between retries (caps exponential growth).
31
+ * @default 30000 (30 seconds)
32
+ */
33
+ maxDelay?: number;
34
+ /**
35
+ * Whether to add random jitter to retry delays (prevents thundering herd).
36
+ * When enabled, adds random jitter up to 25% of the calculated delay.
37
+ * @default true
38
+ */
39
+ jitter?: boolean;
40
+ /**
41
+ * Optional callback called before each retry attempt.
42
+ * Can be used for logging or metrics.
43
+ */
44
+ onRetry?: (attempt: number, error: Error, delay: number) => void | Promise<void>;
45
+ /**
46
+ * Custom function to determine if an error should trigger a retry.
47
+ * If provided, this takes precedence over retryOn status codes.
48
+ */
49
+ shouldRetry?: (error: Error, attempt: number) => boolean;
50
+ }
51
+ /**
52
+ * Creates a retry middleware with exponential backoff.
53
+ *
54
+ * The middleware:
55
+ * - Automatically retries failed requests based on HTTP status codes
56
+ * - Uses exponential backoff to space out retry attempts
57
+ * - Optionally adds jitter to prevent thundering herd problems
58
+ * - Respects Retry-After headers when present
59
+ *
60
+ * @param options - Configuration options for the retry middleware
61
+ * @returns A middleware instance
62
+ *
63
+ * @example
64
+ * ```typescript
65
+ * const retryMiddleware = createRetryMiddleware({
66
+ * maxRetries: 3,
67
+ * retryDelay: 1000,
68
+ * retryOn: [500, 502, 503, 504],
69
+ * });
70
+ * ```
71
+ *
72
+ * @example
73
+ * ```typescript
74
+ * // With custom retry logic
75
+ * const retryMiddleware = createRetryMiddleware({
76
+ * maxRetries: 5,
77
+ * retryDelay: 500,
78
+ * backoffFactor: 1.5,
79
+ * jitter: true,
80
+ * onRetry: (attempt, error, delay) => {
81
+ * console.log(`Retry attempt ${attempt} after ${delay}ms:`, error.message);
82
+ * },
83
+ * shouldRetry: (error, attempt) => {
84
+ * // Custom retry logic
85
+ * if (error instanceof MPFError && error.status) {
86
+ * return error.status >= 500 && attempt < 3;
87
+ * }
88
+ * return false;
89
+ * }
90
+ * });
91
+ * ```
92
+ */
93
+ export declare function createRetryMiddleware(options?: RetryMiddlewareOptions): Middleware;
94
+ /**
95
+ * Check if a request context indicates a retry should be attempted.
96
+ * Used by `MPFClient.request()` to decide whether to run another attempt.
97
+ *
98
+ * Returns false when the request has been marked non-retryable, even if a
99
+ * middleware asked for a retry.
100
+ */
101
+ export declare function shouldRetryRequest(ctx: RequestContext): boolean;
102
+ /**
103
+ * Ask `MPFClient.request()` to run another attempt.
104
+ *
105
+ * The single writer of the retry flag. Any middleware that can recover from an
106
+ * error (the auth middleware's renew-and-retry, for instance) calls this from
107
+ * its `onError` and then rethrows.
108
+ *
109
+ * The client consults the flag unconditionally, so this works whether or not
110
+ * `createRetryMiddleware` is registered.
111
+ */
112
+ export declare function requestRetry(ctx: RequestContext): void;
113
+ /**
114
+ * Mark a request as non-retryable. Used for request bodies that cannot be
115
+ * re-sent (a `ReadableStream` is consumed by the first attempt).
116
+ */
117
+ export declare function disableRetry(ctx: RequestContext): void;
118
+ /**
119
+ * Whether the request has been marked non-retryable.
120
+ */
121
+ export declare function isRetryDisabled(ctx: RequestContext): boolean;
122
+ /**
123
+ * Whether a fetch body can be sent more than once.
124
+ *
125
+ * `FormData`, `Blob`, `ArrayBuffer`, `URLSearchParams` and strings are all
126
+ * re-readable, so retrying them is safe. A `ReadableStream` is consumed by the
127
+ * first attempt and must never be retried.
128
+ */
129
+ export declare function isReplayableBody(body: BodyInit | null | undefined): boolean;
130
+ /**
131
+ * Get the current retry attempt number from request context.
132
+ */
133
+ export declare function getRetryAttempt(ctx: RequestContext): number;
134
+ /**
135
+ * Clear the retry flag from the request context.
136
+ * Should be called after a successful retry or when giving up.
137
+ */
138
+ export declare function clearRetryFlag(ctx: RequestContext): void;
@@ -0,0 +1,60 @@
1
+ import type { Middleware } from '../core/middleware.js';
2
+ import type { TenantSelectionStore } from '../../auth/tenant-selection.js';
3
+ /** Header carrying the selected tenant id. */
4
+ export declare const TENANT_HEADER = "X-MPF-Tenant";
5
+ /** Header carrying the selected role within that tenant. */
6
+ export declare const TENANT_ROLE_HEADER = "X-MPF-Tenant-Role";
7
+ /**
8
+ * Options for the tenant middleware.
9
+ */
10
+ export interface TenantMiddlewareOptions {
11
+ /**
12
+ * The shared tenant selection. Read per request, so a `set()` takes effect on
13
+ * the next request with no client reconstruction.
14
+ */
15
+ tenantProvider?: TenantSelectionStore;
16
+ /**
17
+ * Access-token getter, used ONLY for the under-scoping warning below. When
18
+ * omitted the warning is disabled.
19
+ *
20
+ * Decoding is LRU-cached, and the warning fires at most once per middleware,
21
+ * so this costs nothing in steady state.
22
+ */
23
+ getAccessToken?: () => string | null | Promise<string | null>;
24
+ /**
25
+ * Whether to warn once when a request goes out unscoped while the token holds
26
+ * tenants.
27
+ * @default true
28
+ */
29
+ warnOnUnscoped?: boolean;
30
+ /** Logger for the warning. Defaults to `console`. */
31
+ logger?: {
32
+ warn: (message: string, ...args: unknown[]) => void;
33
+ };
34
+ }
35
+ /**
36
+ * Creates a middleware that puts the selected tenant on the wire.
37
+ *
38
+ * Resolution order for the tenant, using the three states of
39
+ * `options.tenant`:
40
+ *
41
+ * | `options.tenant` | meaning |
42
+ * |-------------------|--------------------------------------------|
43
+ * | `undefined` | inherit the client-wide selection |
44
+ * | `null` | deliberately unscoped for THIS request |
45
+ * | `"<uuid>"` | that tenant, for THIS request |
46
+ *
47
+ * `options.skipTenant` bypasses the middleware entirely.
48
+ *
49
+ * Header rules:
50
+ * - The tenant header is **omitted entirely** when there is no tenant. An
51
+ * empty-string header is a 400 server-side, deliberately, so that a bug
52
+ * cannot masquerade as the no-tenant path.
53
+ * - The role header is omitted unless a role was specified, letting the server
54
+ * apply that tenant's default role (its `dfr`, or `rls[0]` when it has
55
+ * none).
56
+ * - A per-request tenant does NOT inherit the client-wide role: the role only
57
+ * travels with the selection it belongs to. Selecting tenant B while tenant
58
+ * A's role is selected must not send A's role to B.
59
+ */
60
+ export declare function createTenantMiddleware(options?: TenantMiddlewareOptions): Middleware;
@@ -0,0 +1,41 @@
1
+ import type { Middleware } from '../core/middleware.js';
2
+ /**
3
+ * Options for the Turnstile middleware.
4
+ */
5
+ export interface TurnstileMiddlewareOptions {
6
+ /**
7
+ * Async function that mints a fresh Turnstile token.
8
+ * Called once per protected request. Must return a valid token string.
9
+ * Should throw if token cannot be obtained.
10
+ */
11
+ getToken: () => Promise<string>;
12
+ /**
13
+ * URL path suffixes that require a Turnstile token.
14
+ * Matched against the end of the request URL path.
15
+ * Example: ['/sign-up-email-password', '/sign-in-email-password']
16
+ */
17
+ protectedPaths: string[];
18
+ }
19
+ /**
20
+ * Creates a Cloudflare Turnstile middleware that attaches `X-Turnstile-Token`
21
+ * headers to requests matching the configured protected paths.
22
+ *
23
+ * The middleware only calls `getToken()` for requests whose URL path ends
24
+ * with one of the `protectedPaths` entries — all other requests pass through
25
+ * untouched with zero overhead.
26
+ *
27
+ * @param options - Configuration options for the turnstile middleware
28
+ * @returns A middleware instance
29
+ *
30
+ * @example
31
+ * ```typescript
32
+ * const turnstileMiddleware = createTurnstileMiddleware({
33
+ * getToken: async () => {
34
+ * // Render Turnstile widget and return token
35
+ * return await turnstile.execute(siteKey);
36
+ * },
37
+ * protectedPaths: ['/sign-up-email-password', '/sign-in-email-password'],
38
+ * });
39
+ * ```
40
+ */
41
+ export declare function createTurnstileMiddleware(options: TurnstileMiddlewareOptions): Middleware;
@@ -0,0 +1,25 @@
1
+ /**
2
+ * The part of `./client` that reaches NO optional peer dependency.
3
+ *
4
+ * This file exists so the root barrel can expose a `client` namespace without
5
+ * dragging `graphql-ws` into every consumer's module graph.
6
+ *
7
+ * `createGraphQLClient` (in `graphql/factory.ts`) and `createGraphQLWsTransport`
8
+ * (in `graphql/ws-client.ts`) reach `graphql-ws`. It is only ever loaded through
9
+ * a dynamic `import()`, so nothing breaks at runtime for an app that never
10
+ * subscribes — but a *static* export chain from `src/index.ts` still puts those
11
+ * modules (and the dynamic-import chunk a bundler emits for them) in the graph
12
+ * of every consumer, including plain-HTTP ones. So they are reachable from the
13
+ * `./client` subpath only, never from the root namespace.
14
+ *
15
+ * This is the same rule `./react` follows for its `react` peer. See
16
+ * `tests/module-boundaries.test.ts` ("depends on jose only") for the guard.
17
+ *
18
+ * @packageDocumentation
19
+ */
20
+ export * from './core/index.js';
21
+ export * from './middlewares/index.js';
22
+ export * from './utils/url.js';
23
+ export { MPFGraphQLClient, type GraphQLClientConfig } from './graphql/client.js';
24
+ export type { TypedDocumentNode, GraphQLError, GraphQLResponse, GraphQLRequestOptions, } from './graphql/types.js';
25
+ export { getOperationKind, isSubscription, type OperationKind } from './graphql/operation.js';
@@ -0,0 +1,19 @@
1
+ /**
2
+ * URL building utilities for the MPF SDK
3
+ */
4
+ /**
5
+ * Build a URL with query parameters
6
+ *
7
+ * @param baseUrl - The base URL
8
+ * @param path - The path to append
9
+ * @param params - Optional query parameters
10
+ * @returns The full URL with query string
11
+ */
12
+ export declare function buildUrl(baseUrl: string, path: string, params?: Record<string, string | number | boolean | undefined | null>): string;
13
+ /**
14
+ * Join URL segments safely
15
+ *
16
+ * @param segments - URL segments to join
17
+ * @returns Joined URL path
18
+ */
19
+ export declare function joinPath(...segments: string[]): string;
@@ -0,0 +1,85 @@
1
+ import type { ClientConfig, TokenProvider } from '../client/core/types.js';
2
+ import { type AdminAuthMiddlewareOptions } from '../client/middlewares/admin-auth.js';
3
+ import type { TenantSelectionStore } from '../auth/tenant-selection.js';
4
+ import type { OAuthStateStore } from '../auth/oauth-state.js';
5
+ import { AuthClientV0 } from './v0.js';
6
+ /**
7
+ * Provider for minting single-use Cloudflare Turnstile tokens.
8
+ */
9
+ export interface TurnstileProvider {
10
+ /** Mint a fresh single-use Turnstile token. */
11
+ getToken: () => Promise<string>;
12
+ }
13
+ /**
14
+ * Configuration options for the Auth client
15
+ */
16
+ export interface AuthClientOptions extends Omit<ClientConfig, 'baseUrl'> {
17
+ /**
18
+ * Base URL for the Auth service
19
+ */
20
+ baseUrl: string;
21
+ /** Optional token provider. Auto-wires auth middleware when provided. */
22
+ tokenProvider?: TokenProvider;
23
+ /** Optional Turnstile token provider for bot protection. */
24
+ turnstileProvider?: TurnstileProvider;
25
+ /**
26
+ * Optional shared tenant selection. When provided, every request carries the
27
+ * selected tenant headers. Construct it with `createTenantSelection()` and
28
+ * share the same instance across identity/storage/graphql clients.
29
+ */
30
+ tenantProvider?: TenantSelectionStore;
31
+ /**
32
+ * Optional store for the OAuth CSRF state. When provided,
33
+ * `getGoogleOAuthURL` persists the minted state so it survives the redirect.
34
+ * Build one with `createOAuthStateStore()`.
35
+ */
36
+ oauthStateStore?: OAuthStateStore;
37
+ }
38
+ export declare function createAuthClient(options: AuthClientOptions): AuthClientV0;
39
+ /**
40
+ * Configuration options for an admin-authenticated Auth client.
41
+ *
42
+ * SECURITY: Admin authentication uses the shared `ADMIN_JWT_SECRET`, which can
43
+ * impersonate any user. Only construct an admin client server-side / in trusted
44
+ * services. NEVER ship the secret to a browser.
45
+ */
46
+ export interface AdminClientOptions extends Omit<ClientConfig, 'baseUrl'> {
47
+ /** Base URL for the Auth service. */
48
+ baseUrl: string;
49
+ /** Admin auth options: either a pre-minted `token` or a minting `config`. */
50
+ admin: AdminAuthMiddlewareOptions;
51
+ }
52
+ /**
53
+ * Creates an admin-authenticated Auth client for API v0.
54
+ *
55
+ * The returned client sends `Authorization: Admin <jwt>` on every request,
56
+ * acting on behalf of the configured principal. Mirrors {@link createAuthClient}
57
+ * but wires the admin auth middleware instead of the Bearer one.
58
+ *
59
+ * SECURITY: Requires the shared `ADMIN_JWT_SECRET` (when using a minting
60
+ * `config`). Server-side / trusted-service use ONLY — never expose the secret
61
+ * to a browser.
62
+ *
63
+ * @param options - Client configuration options.
64
+ * @returns AuthClientV0 instance authenticated as an admin.
65
+ *
66
+ * @example
67
+ * ```typescript
68
+ * import { createAdminClient } from '@mosano-product-framework/sdk/identity';
69
+ *
70
+ * // Mint a fresh admin token per request (server-side only).
71
+ * const admin = createAdminClient({
72
+ * baseUrl: 'https://api.example.com/auth',
73
+ * admin: {
74
+ * config: {
75
+ * secret: process.env.ADMIN_JWT_SECRET!,
76
+ * actOnBehalfOf: { userId, onTenantId: tenantId },
77
+ * ttlSeconds: 60,
78
+ * },
79
+ * },
80
+ * });
81
+ * ```
82
+ */
83
+ export declare function createAdminClient(options: AdminClientOptions): AuthClientV0;
84
+ export { AuthClientV0, type AuthClientV0Config } from './v0.js';
85
+ export * from './types.js';
@@ -0,0 +1,6 @@
1
+ export { AuthClientV0, createAdminClient, createAuthClient, isMFARequired, isMFASetupRequired } from '../chunk-XAXFIIRT.js';
2
+ import '../chunk-K2ELAI2X.js';
3
+ import '../chunk-LRM6JJ63.js';
4
+ import '../chunk-AJWM5MDZ.js';
5
+ //# sourceMappingURL=index.js.map
6
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"names":[],"mappings":"","file":"index.js"}