@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,85 @@
1
+ /**
2
+ * A tiny external store for `useSyncExternalStore`.
3
+ *
4
+ * Zero dependencies and no tearing: `useSyncExternalStore` is React's own
5
+ * contract for reading external mutable state, so concurrent rendering cannot
6
+ * observe two different snapshots within one commit. A `useState` +
7
+ * `useEffect` mirror would.
8
+ *
9
+ * `getSnapshot` must return a **referentially stable** value while nothing has
10
+ * changed, or React re-renders forever. Every mutation here therefore builds
11
+ * exactly one new state object and every non-mutation returns the existing one.
12
+ */
13
+ import type { MPFClaims } from '../auth/claims-types.js';
14
+ import type { TenantSelection } from '../auth/tenant-selection.js';
15
+ import type { TenantDirectoryEntry } from '../auth/tenant-directory.js';
16
+ /**
17
+ * Whether the selectable-tenant list is known.
18
+ *
19
+ * Only two states, because this list comes from the access token's claims: if
20
+ * there is a token the answer is known, and if there is not, it is not. There is
21
+ * no fetch, so there is nothing to fail. The thing that CAN fail is the display
22
+ * name lookup — see {@link TenantDirectoryStatus}, which is where the
23
+ * "loaded-but-empty vs failed" distinction actually earns its keep.
24
+ */
25
+ export type TenantsStatus = 'unloaded' | 'loaded';
26
+ /** Whether tenant display names have been fetched. */
27
+ export type TenantDirectoryStatus = 'unloaded' | 'loading' | 'loaded' | 'failed';
28
+ /** A tenant as surfaced to the UI. */
29
+ export interface TenantEntry {
30
+ id: string;
31
+ /** Every role held in this tenant. */
32
+ roles: string[];
33
+ /**
34
+ * That tenant's default role: its explicit `dfr` claim when the token carries
35
+ * one, otherwise `roles[0]`. Absent only when the tenant grants no roles.
36
+ *
37
+ * Surfaced separately because `roles[0]` is no longer authoritative — a token
38
+ * may name a default that is not the first role listed.
39
+ */
40
+ defaultRole?: string;
41
+ /**
42
+ * Display name, present only once the directory has loaded. Render
43
+ * `name ?? id` so a switcher degrades to the id rather than to nothing.
44
+ */
45
+ name?: string;
46
+ /** URL-friendly slug, present only once the directory has loaded. */
47
+ slug?: string;
48
+ }
49
+ export interface AuthState {
50
+ /** True once hydration has run. Always true after provider construction. */
51
+ hydrated: boolean;
52
+ /** True when an access token is present. */
53
+ authenticated: boolean;
54
+ /** Decoded (UNVERIFIED, UX-only) claims of the current access token. */
55
+ claims: MPFClaims | null;
56
+ /** Current tenant selection. */
57
+ selection: TenantSelection;
58
+ /** Whether the selectable-tenant list is known (i.e. whether a token exists). */
59
+ tenantsStatus: TenantsStatus;
60
+ /** Selectable tenants, meaningful only when `tenantsStatus === 'loaded'`. */
61
+ tenants: TenantEntry[];
62
+ /**
63
+ * Display-name lookup state.
64
+ *
65
+ * Tri-state on purpose: "this user belongs to zero tenants" and "we could not
66
+ * find out what they are called" must never be indistinguishable. Collapsing
67
+ * them is a real bug class — an empty switcher that silently means "the server
68
+ * was unreachable".
69
+ */
70
+ directoryStatus: TenantDirectoryStatus;
71
+ /** Fetched display metadata, keyed by tenant id. */
72
+ directory: Record<string, TenantDirectoryEntry>;
73
+ /** Why the directory fetch failed, when it did. */
74
+ directoryError: Error | null;
75
+ }
76
+ export interface AuthStore {
77
+ getSnapshot(): AuthState;
78
+ subscribe(listener: () => void): () => void;
79
+ setState(patch: Partial<AuthState>): void;
80
+ }
81
+ export declare function createInitialState(overrides?: Partial<AuthState>): AuthState;
82
+ /**
83
+ * Create an auth store.
84
+ */
85
+ export declare function createAuthStore(initial: AuthState): AuthStore;
@@ -0,0 +1,31 @@
1
+ import type { StorageClientOptions } from './types.js';
2
+ import { StorageClientV0 } from './v0.js';
3
+ /**
4
+ * Creates a Storage client for API v0
5
+ *
6
+ * @param options - Client configuration options
7
+ * @returns StorageClientV0 instance
8
+ *
9
+ * @example
10
+ * ```typescript
11
+ * import { createStorageClient } from '@mosano-product-framework/sdk/storage';
12
+ *
13
+ * // Create authenticated storage client
14
+ * const storage = createStorageClient({
15
+ * baseUrl: 'https://api.example.com/storage',
16
+ * tokenProvider: {
17
+ * getAccessToken: () => localStorage.getItem('accessToken'),
18
+ * onTokenExpired: () => { window.location.href = '/login'; },
19
+ * },
20
+ * });
21
+ *
22
+ * // Upload a file
23
+ * const metadata = await storage.uploadFile(myFile);
24
+ *
25
+ * // Get a download URL
26
+ * const { url } = await storage.getDownloadSignedUrl(metadata.id);
27
+ * ```
28
+ */
29
+ export declare function createStorageClient(options: StorageClientOptions): StorageClientV0;
30
+ export { StorageClientV0 } from './v0.js';
31
+ export * from './types.js';
@@ -0,0 +1,5 @@
1
+ export { StorageClientV0, createStorageClient } from '../chunk-EXPYHNPV.js';
2
+ import '../chunk-LRM6JJ63.js';
3
+ import '../chunk-AJWM5MDZ.js';
4
+ //# sourceMappingURL=index.js.map
5
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"names":[],"mappings":"","file":"index.js"}
@@ -0,0 +1,107 @@
1
+ import type { TokenProvider } from '../client/core/types.js';
2
+ import type { Middleware } from '../client/core/middleware.js';
3
+ /**
4
+ * Configuration options for the Storage client
5
+ */
6
+ export interface StorageClientOptions {
7
+ /** Base URL for the Storage service */
8
+ baseUrl: string;
9
+ /** Optional token provider. Auto-wires auth middleware when provided. */
10
+ tokenProvider?: TokenProvider;
11
+ /**
12
+ * Optional shared tenant selection. Auto-wires the tenant middleware when
13
+ * provided. Share one `createTenantSelection()` instance across clients.
14
+ */
15
+ tenantProvider?: import('../auth/tenant-selection.js').TenantSelectionStore;
16
+ /** Default headers to include in all requests */
17
+ headers?: Record<string, string>;
18
+ /** Middlewares to apply to all requests */
19
+ middlewares?: Middleware[];
20
+ }
21
+ /**
22
+ * File metadata returned by the storage service
23
+ */
24
+ export interface FileMetadataResponse {
25
+ /** File's unique identifier */
26
+ id: string;
27
+ /** Original file name */
28
+ name?: string;
29
+ /** File size in bytes */
30
+ size?: number;
31
+ /** MIME type of the file */
32
+ mime_type?: string;
33
+ /** Entity tag for cache validation */
34
+ etag?: string;
35
+ /** Current upload status */
36
+ upload_status: string;
37
+ /** When the file expires (ISO 8601) */
38
+ expires_at?: string;
39
+ /** When the file was created (ISO 8601) */
40
+ created_at: string;
41
+ /** When the file was last updated (ISO 8601) */
42
+ updated_at: string;
43
+ }
44
+ /**
45
+ * Response containing a signed URL for file upload
46
+ */
47
+ export interface UploadSignedUrlResponse {
48
+ /** File ID for the pending upload */
49
+ file_id: string;
50
+ /** Signed URL to upload the file to */
51
+ url: string;
52
+ }
53
+ /**
54
+ * Response containing a signed URL for file download
55
+ */
56
+ export interface DownloadSignedUrlResponse {
57
+ /** Signed URL to download the file from */
58
+ url: string;
59
+ /** Optional file metadata */
60
+ metadata?: FileMetadataResponse;
61
+ }
62
+ /**
63
+ * Request body for getting a single upload signed URL
64
+ */
65
+ export interface GetUploadSignedUrlRequest {
66
+ /** File name */
67
+ name: string;
68
+ /** MIME type of the file */
69
+ mime_type: string;
70
+ }
71
+ /**
72
+ * Request body for getting multiple upload signed URLs
73
+ */
74
+ export interface GetBatchUploadSignedUrlsRequest {
75
+ /** Array of file descriptors */
76
+ files: GetUploadSignedUrlRequest[];
77
+ }
78
+ /**
79
+ * Request body for getting multiple download signed URLs
80
+ */
81
+ export interface GetBatchDownloadSignedUrlsRequest {
82
+ /** Array of file IDs to download */
83
+ file_ids: string[];
84
+ }
85
+ /**
86
+ * Request body for batch deleting files
87
+ */
88
+ export interface BatchDeleteFilesRequest {
89
+ /** Array of file IDs to delete */
90
+ file_ids: string[];
91
+ }
92
+ /**
93
+ * Request body for batch confirming uploads
94
+ */
95
+ export interface BatchConfirmUploadsRequest {
96
+ /** Array of file IDs to confirm */
97
+ file_ids: string[];
98
+ }
99
+ /**
100
+ * Entry for batch file replacement
101
+ */
102
+ export interface BatchReplaceFilesEntry {
103
+ /** ID of the file to replace */
104
+ fileId: string;
105
+ /** New file content */
106
+ file: Blob | File;
107
+ }
@@ -0,0 +1,120 @@
1
+ import { MPFClient } from '../client/core/client.js';
2
+ import type { RequestOptions } from '../client/core/types.js';
3
+ import type { StorageClientOptions, FileMetadataResponse, UploadSignedUrlResponse, DownloadSignedUrlResponse, GetUploadSignedUrlRequest, GetBatchUploadSignedUrlsRequest, GetBatchDownloadSignedUrlsRequest, BatchDeleteFilesRequest, BatchConfirmUploadsRequest, BatchReplaceFilesEntry } from './types.js';
4
+ /**
5
+ * Storage API v0 client
6
+ *
7
+ * Provides methods for file upload, download, confirmation, deletion,
8
+ * and replacement using both signed URLs and direct multipart uploads.
9
+ */
10
+ export declare class StorageClientV0 extends MPFClient {
11
+ constructor(options: StorageClientOptions);
12
+ /**
13
+ * Get a signed URL for uploading a single file
14
+ *
15
+ * @param data - File name and MIME type
16
+ * @param options - Optional request options
17
+ * @returns Signed URL and file ID
18
+ */
19
+ getUploadSignedUrl(data: GetUploadSignedUrlRequest, options?: RequestOptions): Promise<UploadSignedUrlResponse>;
20
+ /**
21
+ * Get signed URLs for uploading multiple files
22
+ *
23
+ * @param data - Array of file descriptors
24
+ * @param options - Optional request options
25
+ * @returns Array of signed URLs and file IDs
26
+ */
27
+ getBatchUploadSignedUrls(data: GetBatchUploadSignedUrlsRequest, options?: RequestOptions): Promise<UploadSignedUrlResponse[]>;
28
+ /**
29
+ * Upload a single file via multipart form data
30
+ *
31
+ * @param file - The file or blob to upload
32
+ * @param options - Optional request options
33
+ * @returns File metadata
34
+ */
35
+ uploadFile(file: Blob | File, options?: RequestOptions): Promise<FileMetadataResponse>;
36
+ /**
37
+ * Upload multiple files via multipart form data
38
+ *
39
+ * @param files - Array of files or blobs to upload
40
+ * @param options - Optional request options
41
+ * @returns Array of file metadata
42
+ */
43
+ batchUploadFiles(files: (Blob | File)[], options?: RequestOptions): Promise<FileMetadataResponse[]>;
44
+ /**
45
+ * Get a signed URL for downloading a file
46
+ *
47
+ * @param fileId - The file ID
48
+ * @param options - Optional request options
49
+ * @returns Signed download URL and optional metadata
50
+ */
51
+ getDownloadSignedUrl(fileId: string, options?: RequestOptions): Promise<DownloadSignedUrlResponse>;
52
+ /**
53
+ * Get signed URLs for downloading multiple files
54
+ *
55
+ * @param data - Array of file IDs
56
+ * @param options - Optional request options
57
+ * @returns Array of signed download URLs
58
+ */
59
+ getBatchDownloadSignedUrls(data: GetBatchDownloadSignedUrlsRequest, options?: RequestOptions): Promise<DownloadSignedUrlResponse[]>;
60
+ /**
61
+ * Confirm a single file upload
62
+ *
63
+ * @param fileId - The file ID to confirm
64
+ * @param options - Optional request options
65
+ * @returns Updated file metadata
66
+ */
67
+ confirmUpload(fileId: string, options?: RequestOptions): Promise<FileMetadataResponse>;
68
+ /**
69
+ * Confirm multiple file uploads
70
+ *
71
+ * @param data - Array of file IDs to confirm
72
+ * @param options - Optional request options
73
+ * @returns Array of updated file metadata
74
+ */
75
+ batchConfirmUploads(data: BatchConfirmUploadsRequest, options?: RequestOptions): Promise<FileMetadataResponse[]>;
76
+ /**
77
+ * Delete a single file
78
+ *
79
+ * @param fileId - The file ID to delete
80
+ * @param options - Optional request options
81
+ * @returns Deleted file metadata
82
+ */
83
+ deleteFile(fileId: string, options?: RequestOptions): Promise<FileMetadataResponse>;
84
+ /**
85
+ * Delete multiple files
86
+ *
87
+ * @param data - Array of file IDs to delete
88
+ * @param options - Optional request options
89
+ * @returns Array of deleted file metadata
90
+ */
91
+ batchDeleteFiles(data: BatchDeleteFilesRequest, options?: RequestOptions): Promise<FileMetadataResponse[]>;
92
+ /**
93
+ * Replace a single file via multipart form data
94
+ *
95
+ * @param fileId - The file ID to replace
96
+ * @param file - The new file or blob
97
+ * @param options - Optional request options
98
+ * @returns Updated file metadata
99
+ */
100
+ replaceFile(fileId: string, file: Blob | File, options?: RequestOptions): Promise<FileMetadataResponse>;
101
+ /**
102
+ * Replace multiple files via multipart form data
103
+ *
104
+ * @param replacements - Array of file ID and new file pairs
105
+ * @param options - Optional request options
106
+ * @returns Array of updated file metadata
107
+ */
108
+ batchReplaceFiles(replacements: BatchReplaceFilesEntry[], options?: RequestOptions): Promise<FileMetadataResponse[]>;
109
+ /**
110
+ * Execute a multipart/form-data request.
111
+ *
112
+ * Delegates to `MPFClient.request()` so multipart uploads get the same
113
+ * middleware chain and retry loop as every other request. `request()` drops
114
+ * the default JSON `Content-Type` for a `FormData` body so that fetch sets
115
+ * `multipart/form-data` with the correct boundary string.
116
+ *
117
+ * `FormData` is re-readable, so a failed upload is safely retryable.
118
+ */
119
+ private multipartRequest;
120
+ }
package/package.json ADDED
@@ -0,0 +1,99 @@
1
+ {
2
+ "name": "@mosano-product-framework/sdk",
3
+ "version": "0.2.0",
4
+ "description": "MPF SDK: typed clients for the MPF services",
5
+ "type": "module",
6
+ "main": "./dist/index.js",
7
+ "module": "./dist/index.js",
8
+ "types": "./dist/index.d.ts",
9
+ "sideEffects": false,
10
+ "exports": {
11
+ ".": {
12
+ "types": "./dist/index.d.ts",
13
+ "import": "./dist/index.js"
14
+ },
15
+ "./client": {
16
+ "types": "./dist/client/index.d.ts",
17
+ "import": "./dist/client/index.js"
18
+ },
19
+ "./auth": {
20
+ "types": "./dist/auth/index.d.ts",
21
+ "import": "./dist/auth/index.js"
22
+ },
23
+ "./identity": {
24
+ "types": "./dist/identity/index.d.ts",
25
+ "import": "./dist/identity/index.js"
26
+ },
27
+ "./storage": {
28
+ "types": "./dist/storage/index.d.ts",
29
+ "import": "./dist/storage/index.js"
30
+ },
31
+ "./react": {
32
+ "types": "./dist/react/index.d.ts",
33
+ "import": "./dist/react/index.js"
34
+ }
35
+ },
36
+ "files": [
37
+ "dist"
38
+ ],
39
+ "scripts": {
40
+ "build": "tsup && tsc -p tsconfig.build.json",
41
+ "dev": "tsup --watch",
42
+ "typecheck": "tsc --noEmit && tsc --noEmit -p tsconfig.test.json",
43
+ "lint": "eslint .",
44
+ "test": "vitest run",
45
+ "test:watch": "vitest",
46
+ "verify:dist": "tsc --noEmit --skipLibCheck false --strict --target ES2022 --module ESNext --moduleResolution bundler --lib ES2022,DOM dist/index.d.ts dist/client/index.d.ts dist/auth/index.d.ts dist/identity/index.d.ts dist/storage/index.d.ts dist/react/index.d.ts",
47
+ "prepublishOnly": "pnpm build"
48
+ },
49
+ "devDependencies": {
50
+ "@eslint/js": "^9",
51
+ "@testing-library/dom": "^10.0.0",
52
+ "@testing-library/react": "^16.1.0",
53
+ "@types/node": "^20.0.0",
54
+ "@types/react": "^18.3.12",
55
+ "eslint": "^9",
56
+ "graphql": "^16.9.0",
57
+ "graphql-ws": "^5.16.0",
58
+ "jsdom": "^25.0.1",
59
+ "react": "^18.3.1",
60
+ "react-dom": "^18.3.1",
61
+ "tsup": "^8.0.0",
62
+ "typescript": "^5.3.0",
63
+ "typescript-eslint": "^8",
64
+ "vitest": "^2.1.9"
65
+ },
66
+ "peerDependencies": {
67
+ "react": ">=18.0.0",
68
+ "graphql": "^16.0.0",
69
+ "graphql-ws": "^5.14.0"
70
+ },
71
+ "peerDependenciesMeta": {
72
+ "react": {
73
+ "optional": true
74
+ },
75
+ "graphql": {
76
+ "optional": true
77
+ },
78
+ "graphql-ws": {
79
+ "optional": true
80
+ }
81
+ },
82
+ "engines": {
83
+ "node": ">=18.0.0"
84
+ },
85
+ "keywords": [
86
+ "mpf",
87
+ "sdk",
88
+ "auth"
89
+ ],
90
+ "license": "MIT",
91
+ "repository": {
92
+ "type": "git",
93
+ "url": "https://gitlab.com/mosano-product-framework/services.git",
94
+ "directory": "pkg/js-sdk"
95
+ },
96
+ "dependencies": {
97
+ "jose": "^6.2.3"
98
+ }
99
+ }