@zjlab-fe/data-hub-ui 0.8.0 → 0.9.1
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/.github/instructions/i.instructions.md +249 -0
- package/README.md +1 -1
- package/dist/types/components/apply-perm-modal/demo/index.d.ts +1 -0
- package/dist/types/components/apply-perm-modal/index.d.ts +15 -0
- package/dist/types/components/feature-card/demo/moha.d.ts +1 -0
- package/dist/types/components/feature-card/index.d.ts +7 -1
- package/dist/types/components/file-uploader/components/circle-progress.d.ts +6 -0
- package/dist/types/components/file-uploader/components/hooks/use-drop-zone.d.ts +17 -0
- package/dist/types/components/file-uploader/components/hooks/use-file-validation.d.ts +12 -0
- package/dist/types/components/file-uploader/components/icons.d.ts +5 -0
- package/dist/types/components/file-uploader/components/uploader-drop-zone.d.ts +49 -0
- package/dist/types/components/file-uploader/components/uploader-file-item.d.ts +40 -0
- package/dist/types/components/file-uploader/components/uploader-file-list.d.ts +29 -0
- package/dist/types/components/file-uploader/components/uploader.d.ts +64 -0
- package/dist/types/components/file-uploader/components/utils/directory-reader.d.ts +4 -0
- package/dist/types/components/file-uploader/constants.d.ts +27 -0
- package/dist/types/components/file-uploader/context/file-state-store.d.ts +64 -0
- package/dist/types/components/file-uploader/context/handler-registry.d.ts +96 -0
- package/dist/types/components/file-uploader/context/upload-context.d.ts +14 -0
- package/dist/types/components/file-uploader/context/upload-provider.d.ts +47 -0
- package/dist/types/components/file-uploader/context/upload-reducer.d.ts +6 -0
- package/dist/types/components/file-uploader/context/use-upload-engine.d.ts +22 -0
- package/dist/types/components/file-uploader/demo/index.d.ts +2 -0
- package/dist/types/components/file-uploader/engine/queue-callbacks.d.ts +21 -0
- package/dist/types/components/file-uploader/engine/queue-manager.d.ts +63 -0
- package/dist/types/components/file-uploader/engine/queue-types.d.ts +37 -0
- package/dist/types/components/file-uploader/engine/queue-uploader.d.ts +8 -0
- package/dist/types/components/file-uploader/hooks/use-upload-batch.d.ts +36 -0
- package/dist/types/components/file-uploader/hooks/use-upload-control.d.ts +37 -0
- package/dist/types/components/file-uploader/hooks/use-upload-files.d.ts +40 -0
- package/dist/types/components/file-uploader/hooks/use-upload-operations.d.ts +43 -0
- package/dist/types/components/file-uploader/hooks/use-upload.d.ts +74 -0
- package/dist/types/components/file-uploader/index.d.ts +16 -0
- package/dist/types/components/file-uploader/persistence/file-blob-store.d.ts +71 -0
- package/dist/types/components/file-uploader/persistence/file-handle-store.d.ts +116 -0
- package/dist/types/components/file-uploader/persistence/index.d.ts +42 -0
- package/dist/types/components/file-uploader/persistence/metadata-store.d.ts +63 -0
- package/dist/types/components/file-uploader/persistence/persistence-context.d.ts +20 -0
- package/dist/types/components/file-uploader/persistence/persistence-manager.d.ts +103 -0
- package/dist/types/components/file-uploader/persistence/persistence-provider.d.ts +49 -0
- package/dist/types/components/file-uploader/persistence/types.d.ts +266 -0
- package/dist/types/components/file-uploader/persistence/use-persistence.d.ts +78 -0
- package/dist/types/components/file-uploader/types.d.ts +138 -0
- package/dist/types/components/file-uploader/utils/chunk-handlers.d.ts +40 -0
- package/dist/types/components/file-uploader/utils/ensure-handlers.d.ts +7 -0
- package/dist/types/components/file-uploader/utils/error-handler.d.ts +59 -0
- package/dist/types/components/file-uploader/utils/upload-controllers.d.ts +72 -0
- package/dist/types/components/file-uploader/utils/upload-handler.d.ts +17 -0
- package/dist/types/components/file-uploader/utils/validate-handlers.d.ts +6 -0
- package/dist/types/components/section-heading/index.d.ts +1 -1
- package/dist/types/index.d.ts +1 -0
- package/es/index.js +1 -1
- package/lib/index.js +1 -1
- package/package.json +2 -2
- package/tailwind.config.js +4 -0
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* File Handle Store - IndexedDB storage for FileSystemFileHandle
|
|
3
|
+
*
|
|
4
|
+
* This store handles FileSystemFileHandle persistence for the 'file-system-access' mode.
|
|
5
|
+
* FileSystemFileHandle can be stored in IndexedDB via structured clone.
|
|
6
|
+
*
|
|
7
|
+
* Note: After page reload, permission must be re-requested with a user gesture.
|
|
8
|
+
*/
|
|
9
|
+
/**
|
|
10
|
+
* Stored handle entry structure
|
|
11
|
+
*/
|
|
12
|
+
interface StoredHandleEntry {
|
|
13
|
+
/** File ID (key) */
|
|
14
|
+
id: string;
|
|
15
|
+
/** The FileSystemFileHandle - can be cloned to IndexedDB */
|
|
16
|
+
handle: FileSystemFileHandle;
|
|
17
|
+
/** Original file name at save time */
|
|
18
|
+
fileName: string;
|
|
19
|
+
/** Storage timestamp */
|
|
20
|
+
createdAt: number;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Permission check result
|
|
24
|
+
*/
|
|
25
|
+
export interface PermissionResult {
|
|
26
|
+
/** Whether permission is granted */
|
|
27
|
+
granted: boolean;
|
|
28
|
+
/** Permission state */
|
|
29
|
+
state: PermissionState;
|
|
30
|
+
/** Whether permission can be requested (user gesture available) */
|
|
31
|
+
canRequest: boolean;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* File Handle Store class for FileSystemFileHandle persistence
|
|
35
|
+
*/
|
|
36
|
+
export declare class FileHandleStore {
|
|
37
|
+
private prefix;
|
|
38
|
+
private db;
|
|
39
|
+
constructor(prefix?: string);
|
|
40
|
+
/**
|
|
41
|
+
* Check if File System Access API is supported
|
|
42
|
+
*/
|
|
43
|
+
static isSupported(): boolean;
|
|
44
|
+
/**
|
|
45
|
+
* Initialize the store (open database connection)
|
|
46
|
+
*/
|
|
47
|
+
initialize(): Promise<void>;
|
|
48
|
+
/**
|
|
49
|
+
* Ensure database is initialized
|
|
50
|
+
*/
|
|
51
|
+
private ensureDb;
|
|
52
|
+
/**
|
|
53
|
+
* Save a file handle
|
|
54
|
+
* @param fileId - Unique file identifier
|
|
55
|
+
* @param handle - FileSystemFileHandle to store
|
|
56
|
+
* @param fileName - Original file name
|
|
57
|
+
*/
|
|
58
|
+
saveHandle(fileId: string, handle: FileSystemFileHandle, fileName?: string): Promise<void>;
|
|
59
|
+
/**
|
|
60
|
+
* Get a file handle by ID
|
|
61
|
+
*/
|
|
62
|
+
getHandle(fileId: string): Promise<FileSystemFileHandle | null>;
|
|
63
|
+
/**
|
|
64
|
+
* Get handle entry with metadata
|
|
65
|
+
*/
|
|
66
|
+
getHandleEntry(fileId: string): Promise<StoredHandleEntry | null>;
|
|
67
|
+
/**
|
|
68
|
+
* Check permission status for a handle
|
|
69
|
+
* @param handle - FileSystemFileHandle to check
|
|
70
|
+
* @param requestIfNeeded - Whether to request permission (requires user gesture)
|
|
71
|
+
*/
|
|
72
|
+
checkPermission(handle: FileSystemFileHandle, requestIfNeeded?: boolean): Promise<PermissionResult>;
|
|
73
|
+
/**
|
|
74
|
+
* Get file from handle (with permission check)
|
|
75
|
+
* @param handle - FileSystemFileHandle
|
|
76
|
+
* @param requestPermission - Whether to request permission if needed
|
|
77
|
+
*/
|
|
78
|
+
getFileFromHandle(handle: FileSystemFileHandle, requestPermission?: boolean): Promise<File | null>;
|
|
79
|
+
/**
|
|
80
|
+
* Check if a handle exists
|
|
81
|
+
*/
|
|
82
|
+
hasHandle(fileId: string): Promise<boolean>;
|
|
83
|
+
/**
|
|
84
|
+
* Delete a handle
|
|
85
|
+
*/
|
|
86
|
+
deleteHandle(fileId: string): Promise<void>;
|
|
87
|
+
/**
|
|
88
|
+
* Delete multiple handles
|
|
89
|
+
*/
|
|
90
|
+
deleteMany(fileIds: string[]): Promise<void>;
|
|
91
|
+
/**
|
|
92
|
+
* Clear all handles
|
|
93
|
+
*/
|
|
94
|
+
clearAll(): Promise<void>;
|
|
95
|
+
/**
|
|
96
|
+
* Get all stored file IDs
|
|
97
|
+
*/
|
|
98
|
+
getAllIds(): Promise<string[]>;
|
|
99
|
+
/**
|
|
100
|
+
* Get all entries
|
|
101
|
+
*/
|
|
102
|
+
getAllEntries(): Promise<StoredHandleEntry[]>;
|
|
103
|
+
/**
|
|
104
|
+
* Close the database connection
|
|
105
|
+
*/
|
|
106
|
+
close(): void;
|
|
107
|
+
/**
|
|
108
|
+
* Delete the entire database (for mode switching)
|
|
109
|
+
*/
|
|
110
|
+
deleteDatabase(): Promise<void>;
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* Default singleton instance
|
|
114
|
+
*/
|
|
115
|
+
export declare const fileHandleStore: FileHandleStore;
|
|
116
|
+
export {};
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Persistence Module - File persistence for upload state
|
|
3
|
+
*
|
|
4
|
+
* Provides three persistence modes:
|
|
5
|
+
* - `repick`: No persistence; user reselects files after reload (default)
|
|
6
|
+
* - `indexeddb`: Store file blobs in IndexedDB for auto-resume
|
|
7
|
+
* - `file-system-access`: Store FileSystemFileHandle for efficient resume (Chromium + HTTPS)
|
|
8
|
+
*
|
|
9
|
+
* Storage architecture:
|
|
10
|
+
* - Metadata is ALWAYS stored in IndexedDB (separate database)
|
|
11
|
+
* - File blobs stored in IndexedDB when mode='indexeddb'
|
|
12
|
+
* - File handles stored in IndexedDB when mode='file-system-access'
|
|
13
|
+
*
|
|
14
|
+
* @example
|
|
15
|
+
* ```tsx
|
|
16
|
+
* // Wrap with PersistenceProvider inside UploadProvider
|
|
17
|
+
* <UploadProvider config={{ concurrentFiles: 3 }}>
|
|
18
|
+
* <PersistenceProvider
|
|
19
|
+
* config={{ mode: 'indexeddb' }}
|
|
20
|
+
* restoreHandler={(runtime, meta) => ({
|
|
21
|
+
* onGetUploadUrls: (name, count) => api.getUrls(runtime.folderId, name, count),
|
|
22
|
+
* onPartComplete: (name, uploadId, part) => api.completePart(name, uploadId, part),
|
|
23
|
+
* onFileComplete: (name, uploadId) => api.completeFile(name, uploadId),
|
|
24
|
+
* })}
|
|
25
|
+
* >
|
|
26
|
+
* <App />
|
|
27
|
+
* </PersistenceProvider>
|
|
28
|
+
* </UploadProvider>
|
|
29
|
+
*
|
|
30
|
+
* // In your component, use the hook
|
|
31
|
+
* const { pendingFiles, restoreFiles, repickFile } = usePersistence();
|
|
32
|
+
* ```
|
|
33
|
+
*/
|
|
34
|
+
export type { PersistenceMode, PersistenceStorageConfig, PersistenceConfig, // Deprecated, use PersistenceStorageConfig
|
|
35
|
+
RestoreHandlerFn, StoredFileMeta, StoredChunkMeta, FileRecoveryResult, StorageQuotaInfo, PersistenceManagerInterface, FileSystemPermissionDescriptor, FileSystemHandleWithPermission, FilePickerOptions, WindowWithFileSystem, PendingFile, RestoreFilesResult, RepickFileResult, PersistenceContextValue, } from './types';
|
|
36
|
+
export { MetadataStore, metadataStore } from './metadata-store';
|
|
37
|
+
export { FileBlobStore, fileBlobStore } from './file-blob-store';
|
|
38
|
+
export { FileHandleStore, fileHandleStore, type PermissionResult } from './file-handle-store';
|
|
39
|
+
export { PersistenceManager, createPersistenceManager } from './persistence-manager';
|
|
40
|
+
export { PersistenceContext, usePersistence, usePersistenceOptional } from './persistence-context';
|
|
41
|
+
export { PersistenceProvider, type PersistenceProviderProps } from './persistence-provider';
|
|
42
|
+
export { uploadFileToStoredMeta, storedMetaToUploadFile } from './use-persistence';
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Metadata Store - IndexedDB storage for file metadata
|
|
3
|
+
*
|
|
4
|
+
* This store handles ONLY file metadata, separate from actual file blob storage.
|
|
5
|
+
* Metadata is stored in IndexedDB regardless of persistence mode.
|
|
6
|
+
*/
|
|
7
|
+
import type { StoredFileMeta } from './types';
|
|
8
|
+
/**
|
|
9
|
+
* Metadata Store class for file metadata persistence
|
|
10
|
+
*/
|
|
11
|
+
export declare class MetadataStore {
|
|
12
|
+
private prefix;
|
|
13
|
+
private db;
|
|
14
|
+
constructor(prefix?: string);
|
|
15
|
+
/**
|
|
16
|
+
* Initialize the store (open database connection)
|
|
17
|
+
*/
|
|
18
|
+
initialize(): Promise<void>;
|
|
19
|
+
/**
|
|
20
|
+
* Ensure database is initialized
|
|
21
|
+
*/
|
|
22
|
+
private ensureDb;
|
|
23
|
+
/**
|
|
24
|
+
* Save file metadata
|
|
25
|
+
*/
|
|
26
|
+
saveMeta(meta: StoredFileMeta): Promise<void>;
|
|
27
|
+
/**
|
|
28
|
+
* Get file metadata by ID
|
|
29
|
+
*/
|
|
30
|
+
getMeta(fileId: string): Promise<StoredFileMeta | null>;
|
|
31
|
+
/**
|
|
32
|
+
* Get all file metadata
|
|
33
|
+
*/
|
|
34
|
+
getAllMeta(): Promise<StoredFileMeta[]>;
|
|
35
|
+
/**
|
|
36
|
+
* Delete file metadata by ID
|
|
37
|
+
*/
|
|
38
|
+
deleteMeta(fileId: string): Promise<void>;
|
|
39
|
+
/**
|
|
40
|
+
* Delete multiple file metadata by IDs
|
|
41
|
+
*/
|
|
42
|
+
deleteMany(fileIds: string[]): Promise<void>;
|
|
43
|
+
/**
|
|
44
|
+
* Clear all metadata
|
|
45
|
+
*/
|
|
46
|
+
clearAll(): Promise<void>;
|
|
47
|
+
/**
|
|
48
|
+
* Query metadata by status
|
|
49
|
+
*/
|
|
50
|
+
getByStatus(status: string): Promise<StoredFileMeta[]>;
|
|
51
|
+
/**
|
|
52
|
+
* Close the database connection
|
|
53
|
+
*/
|
|
54
|
+
close(): void;
|
|
55
|
+
/**
|
|
56
|
+
* Delete the entire database (for mode switching)
|
|
57
|
+
*/
|
|
58
|
+
deleteDatabase(): Promise<void>;
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Default singleton instance
|
|
62
|
+
*/
|
|
63
|
+
export declare const metadataStore: MetadataStore;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Persistence Context
|
|
3
|
+
*
|
|
4
|
+
* Context for the pluggable PersistenceProvider component.
|
|
5
|
+
*/
|
|
6
|
+
import type { PersistenceContextValue } from './types';
|
|
7
|
+
/**
|
|
8
|
+
* Persistence context - null before provider mounts
|
|
9
|
+
*/
|
|
10
|
+
export declare const PersistenceContext: import("react").Context<PersistenceContextValue | null>;
|
|
11
|
+
/**
|
|
12
|
+
* Hook to consume persistence context
|
|
13
|
+
* Must be used within PersistenceProvider
|
|
14
|
+
*/
|
|
15
|
+
export declare function usePersistence(): PersistenceContextValue;
|
|
16
|
+
/**
|
|
17
|
+
* Hook to optionally consume persistence context
|
|
18
|
+
* Returns null if not within PersistenceProvider (no error thrown)
|
|
19
|
+
*/
|
|
20
|
+
export declare function usePersistenceOptional(): PersistenceContextValue | null;
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Persistence Manager - Orchestrates file persistence across modes
|
|
3
|
+
*
|
|
4
|
+
* Manages mode selection, storage switching, and coordinated data recovery.
|
|
5
|
+
* Handles the complexity of switching between persistence modes and ensures
|
|
6
|
+
* data integrity during transitions.
|
|
7
|
+
*
|
|
8
|
+
* Storage separation:
|
|
9
|
+
* - Metadata: Always in IndexedDB (metadata-store)
|
|
10
|
+
* - File blobs: IndexedDB when mode='indexeddb' (file-blob-store)
|
|
11
|
+
* - File handles: IndexedDB when mode='file-system-access' (file-handle-store)
|
|
12
|
+
*/
|
|
13
|
+
import type { PersistenceMode, PersistenceStorageConfig, StoredFileMeta, FileRecoveryResult, StorageQuotaInfo, PersistenceManagerInterface } from './types';
|
|
14
|
+
import { MetadataStore } from './metadata-store';
|
|
15
|
+
import { FileBlobStore } from './file-blob-store';
|
|
16
|
+
import { FileHandleStore } from './file-handle-store';
|
|
17
|
+
/**
|
|
18
|
+
* Persistence Manager class
|
|
19
|
+
*/
|
|
20
|
+
export declare class PersistenceManager implements PersistenceManagerInterface {
|
|
21
|
+
private config;
|
|
22
|
+
private metadataStore;
|
|
23
|
+
private blobStore;
|
|
24
|
+
private handleStore;
|
|
25
|
+
private initialized;
|
|
26
|
+
private _mode;
|
|
27
|
+
constructor(config?: Partial<PersistenceStorageConfig>);
|
|
28
|
+
/**
|
|
29
|
+
* Current persistence mode
|
|
30
|
+
*/
|
|
31
|
+
get mode(): PersistenceMode;
|
|
32
|
+
/**
|
|
33
|
+
* Initialize the persistence manager
|
|
34
|
+
* Handles mode switching if stored mode differs from config mode
|
|
35
|
+
*/
|
|
36
|
+
initialize(): Promise<void>;
|
|
37
|
+
/**
|
|
38
|
+
* Hard reset - clear all persisted data (used during mode switch)
|
|
39
|
+
*/
|
|
40
|
+
hardReset(): Promise<void>;
|
|
41
|
+
/**
|
|
42
|
+
* Save file metadata to IndexedDB
|
|
43
|
+
*/
|
|
44
|
+
saveFileMeta(meta: StoredFileMeta): Promise<void>;
|
|
45
|
+
/**
|
|
46
|
+
* Save file blob to IndexedDB (indexeddb mode only)
|
|
47
|
+
*/
|
|
48
|
+
saveFileBlob(fileId: string, file: File): Promise<void>;
|
|
49
|
+
/**
|
|
50
|
+
* Save file handle to IndexedDB (file-system-access mode only)
|
|
51
|
+
*/
|
|
52
|
+
saveFileHandle(fileId: string, handle: FileSystemFileHandle): Promise<void>;
|
|
53
|
+
/**
|
|
54
|
+
* Load all stored file metadata
|
|
55
|
+
*/
|
|
56
|
+
loadAllFileMeta(): Promise<StoredFileMeta[]>;
|
|
57
|
+
/**
|
|
58
|
+
* Recover a single file with its data/handle
|
|
59
|
+
*/
|
|
60
|
+
recoverFile(meta: StoredFileMeta): Promise<FileRecoveryResult>;
|
|
61
|
+
/**
|
|
62
|
+
* Request permission for a file handle (requires user gesture)
|
|
63
|
+
* @param fileId - File ID to request permission for
|
|
64
|
+
* @returns The file if permission granted, null otherwise
|
|
65
|
+
*/
|
|
66
|
+
requestFilePermission(fileId: string): Promise<File | null>;
|
|
67
|
+
/**
|
|
68
|
+
* Remove file data from all storage
|
|
69
|
+
*/
|
|
70
|
+
removeFile(fileId: string): Promise<void>;
|
|
71
|
+
/**
|
|
72
|
+
* Remove multiple files from storage
|
|
73
|
+
*/
|
|
74
|
+
removeFiles(fileIds: string[]): Promise<void>;
|
|
75
|
+
/**
|
|
76
|
+
* Clear all persisted data
|
|
77
|
+
*/
|
|
78
|
+
clearAll(): Promise<void>;
|
|
79
|
+
/**
|
|
80
|
+
* Get storage quota information
|
|
81
|
+
*/
|
|
82
|
+
getStorageQuota(): Promise<StorageQuotaInfo>;
|
|
83
|
+
/**
|
|
84
|
+
* Check if File System Access API is supported
|
|
85
|
+
*/
|
|
86
|
+
isFileSystemAccessSupported(): boolean;
|
|
87
|
+
/**
|
|
88
|
+
* Get the raw stores for advanced usage
|
|
89
|
+
*/
|
|
90
|
+
getStores(): {
|
|
91
|
+
metadata: MetadataStore;
|
|
92
|
+
blob: FileBlobStore;
|
|
93
|
+
handle: FileHandleStore;
|
|
94
|
+
};
|
|
95
|
+
/**
|
|
96
|
+
* Close all database connections
|
|
97
|
+
*/
|
|
98
|
+
close(): void;
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* Create a persistence manager instance with the given config
|
|
102
|
+
*/
|
|
103
|
+
export declare function createPersistenceManager(config?: Partial<PersistenceStorageConfig>): PersistenceManager;
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Persistence Provider - Pluggable component for file persistence
|
|
3
|
+
*
|
|
4
|
+
* Wraps inside UploadProvider to add persistence capabilities.
|
|
5
|
+
* Handles auto-save, restore, and exposes pending files for dev to manage.
|
|
6
|
+
*
|
|
7
|
+
* @example
|
|
8
|
+
* ```tsx
|
|
9
|
+
* <UploadProvider config={{ concurrentFiles: 3 }}>
|
|
10
|
+
* <PersistenceProvider
|
|
11
|
+
* config={{ mode: 'indexeddb' }}
|
|
12
|
+
* restoreHandler={(runtime, meta) => ({
|
|
13
|
+
* onGetUploadUrls: (name, count) => api.getUrls(runtime.folderId, name, count),
|
|
14
|
+
* onPartComplete: (name, uploadId, part) => api.completePart(name, uploadId, part),
|
|
15
|
+
* onFileComplete: (name, uploadId) => api.completeFile(name, uploadId),
|
|
16
|
+
* })}
|
|
17
|
+
* >
|
|
18
|
+
* <App />
|
|
19
|
+
* </PersistenceProvider>
|
|
20
|
+
* </UploadProvider>
|
|
21
|
+
*
|
|
22
|
+
* // In App:
|
|
23
|
+
* const { pendingFiles, restoreFiles, repickFile } = usePersistence();
|
|
24
|
+
* ```
|
|
25
|
+
*/
|
|
26
|
+
import { type ReactNode } from 'react';
|
|
27
|
+
import type { PersistenceStorageConfig, RestoreHandlerFn } from './types';
|
|
28
|
+
export interface PersistenceProviderProps {
|
|
29
|
+
/** Storage configuration (mode, prefix, quota) */
|
|
30
|
+
config: PersistenceStorageConfig;
|
|
31
|
+
/** Auto-restore files on provider mount (default: true) */
|
|
32
|
+
autoRestore?: boolean;
|
|
33
|
+
/** Auto-save file state changes (default: true) */
|
|
34
|
+
autoSave?: boolean;
|
|
35
|
+
/** Cleanup completed uploads from storage (default: true) */
|
|
36
|
+
cleanupOnComplete?: boolean;
|
|
37
|
+
/**
|
|
38
|
+
* Handler to rebuild upload handlers for restored files.
|
|
39
|
+
* Called for each file that can be auto-restored.
|
|
40
|
+
* Return null if handlers cannot be rebuilt (file will be added to pendingFiles).
|
|
41
|
+
*/
|
|
42
|
+
restoreHandler?: RestoreHandlerFn;
|
|
43
|
+
/** Child components */
|
|
44
|
+
children: ReactNode;
|
|
45
|
+
}
|
|
46
|
+
export declare function PersistenceProvider({ config, autoRestore, autoSave, cleanupOnComplete, restoreHandler, children, }: PersistenceProviderProps): import("react/jsx-runtime").JSX.Element;
|
|
47
|
+
export declare namespace PersistenceProvider {
|
|
48
|
+
var displayName: string;
|
|
49
|
+
}
|
|
@@ -0,0 +1,266 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Persistence Types for File Uploader
|
|
3
|
+
*
|
|
4
|
+
* Defines types for three persistence modes:
|
|
5
|
+
* - `repick`: No persistence; user reselects files after reload
|
|
6
|
+
* - `indexeddb`: Store file blobs in IndexedDB for auto-resume
|
|
7
|
+
* - `file-system-access`: Store FileSystemFileHandle in IndexedDB (Chromium + HTTPS only)
|
|
8
|
+
*/
|
|
9
|
+
import type { UploadStatusType, ChunkStatusType } from '../constants';
|
|
10
|
+
import type { UploadHandlers } from '../types';
|
|
11
|
+
/**
|
|
12
|
+
* Persistence modes for file storage
|
|
13
|
+
*/
|
|
14
|
+
export type PersistenceMode = 'repick' | 'indexeddb' | 'file-system-access';
|
|
15
|
+
/**
|
|
16
|
+
* Storage configuration for persistence (how to persist)
|
|
17
|
+
*/
|
|
18
|
+
export interface PersistenceStorageConfig {
|
|
19
|
+
/** Selected persistence mode */
|
|
20
|
+
mode: PersistenceMode;
|
|
21
|
+
/** Storage key prefix for namespacing (default: 'file-uploader') */
|
|
22
|
+
storageKeyPrefix?: string;
|
|
23
|
+
/** Maximum storage quota in bytes before cleanup warning (default: 500MB) */
|
|
24
|
+
maxStorageQuota?: number;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* @deprecated Use PersistenceStorageConfig instead. This is kept for backward compatibility.
|
|
28
|
+
*/
|
|
29
|
+
export interface PersistenceConfig extends PersistenceStorageConfig {
|
|
30
|
+
/** @deprecated Move to PersistenceProviderProps.autoRestore */
|
|
31
|
+
autoRestore?: boolean;
|
|
32
|
+
/** @deprecated Move to PersistenceProviderProps.autoSave */
|
|
33
|
+
autoSave?: boolean;
|
|
34
|
+
/** @deprecated Move to PersistenceProviderProps.cleanupOnComplete */
|
|
35
|
+
cleanupOnComplete?: boolean;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Handler restore function type
|
|
39
|
+
* Called for each file being restored to rebuild its upload handlers
|
|
40
|
+
*
|
|
41
|
+
* @param runtime - The runtime context stored with the file (dev's custom data)
|
|
42
|
+
* @param meta - The stored file metadata
|
|
43
|
+
* @returns Upload handlers for the file, or null if cannot restore
|
|
44
|
+
*
|
|
45
|
+
* @example
|
|
46
|
+
* ```ts
|
|
47
|
+
* restoreHandler: (runtime, meta) => {
|
|
48
|
+
* const { folderId } = runtime as { folderId: string };
|
|
49
|
+
* return {
|
|
50
|
+
* onGetUploadUrls: (name, count) => api.getUrls(folderId, name, count),
|
|
51
|
+
* onPartComplete: (name, uploadId, part) => api.completePart(name, uploadId, part),
|
|
52
|
+
* onFileComplete: (name, uploadId) => api.completeFile(name, uploadId),
|
|
53
|
+
* };
|
|
54
|
+
* }
|
|
55
|
+
* ```
|
|
56
|
+
*/
|
|
57
|
+
export type RestoreHandlerFn = (runtime: unknown, meta: StoredFileMeta) => UploadHandlers | null;
|
|
58
|
+
/**
|
|
59
|
+
* Stored chunk metadata (without actual data)
|
|
60
|
+
*/
|
|
61
|
+
export interface StoredChunkMeta {
|
|
62
|
+
partNum: number;
|
|
63
|
+
status: ChunkStatusType;
|
|
64
|
+
progress: number;
|
|
65
|
+
uploadUrl?: string;
|
|
66
|
+
error?: string;
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Stored file metadata - saved in IndexedDB for all modes
|
|
70
|
+
* This is separate from the actual file blob storage
|
|
71
|
+
*/
|
|
72
|
+
export interface StoredFileMeta {
|
|
73
|
+
/** Unique file ID */
|
|
74
|
+
id: string;
|
|
75
|
+
/** Original file name */
|
|
76
|
+
fileName: string;
|
|
77
|
+
/** File size in bytes */
|
|
78
|
+
fileSize: number;
|
|
79
|
+
/** File last modified timestamp */
|
|
80
|
+
lastModified: number;
|
|
81
|
+
/** Current upload status */
|
|
82
|
+
status: UploadStatusType;
|
|
83
|
+
/** Upload progress (0-100) */
|
|
84
|
+
progress: number;
|
|
85
|
+
/** Server-assigned upload ID */
|
|
86
|
+
uploadId: string;
|
|
87
|
+
/** Chunk states */
|
|
88
|
+
chunks: StoredChunkMeta[];
|
|
89
|
+
/** Chunk size used for this upload */
|
|
90
|
+
chunkSize: number;
|
|
91
|
+
/** Arbitrary runtime context for handler rebuild */
|
|
92
|
+
runtime?: unknown;
|
|
93
|
+
/** Error message if failed */
|
|
94
|
+
error?: string;
|
|
95
|
+
/** Structured error code */
|
|
96
|
+
errorCode?: string;
|
|
97
|
+
/** Number of retry attempts */
|
|
98
|
+
retryCount?: number;
|
|
99
|
+
/** File creation timestamp */
|
|
100
|
+
createdAt: number;
|
|
101
|
+
/** Last updated timestamp */
|
|
102
|
+
updatedAt: number;
|
|
103
|
+
/** MIME type of the file */
|
|
104
|
+
mimeType?: string;
|
|
105
|
+
/** Hash of file content for integrity check (optional) */
|
|
106
|
+
contentHash?: string;
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* Result of file recovery operation
|
|
110
|
+
*/
|
|
111
|
+
export interface FileRecoveryResult {
|
|
112
|
+
/** Successfully recovered file metadata */
|
|
113
|
+
meta: StoredFileMeta;
|
|
114
|
+
/** Recovered File object (if available) */
|
|
115
|
+
file: File | null;
|
|
116
|
+
/** FileSystemFileHandle (for file-system-access mode) */
|
|
117
|
+
handle?: FileSystemFileHandle;
|
|
118
|
+
/** Whether user action is needed (e.g., permission grant, repick) */
|
|
119
|
+
needsUserAction: boolean;
|
|
120
|
+
/** Reason for needing user action */
|
|
121
|
+
userActionReason?: 'permission_required' | 'repick_required' | 'file_modified';
|
|
122
|
+
}
|
|
123
|
+
/**
|
|
124
|
+
* Storage quota information
|
|
125
|
+
*/
|
|
126
|
+
export interface StorageQuotaInfo {
|
|
127
|
+
/** Used storage in bytes */
|
|
128
|
+
used: number;
|
|
129
|
+
/** Available storage quota in bytes */
|
|
130
|
+
quota: number;
|
|
131
|
+
/** Percentage of quota used (0-100) */
|
|
132
|
+
usagePercent: number;
|
|
133
|
+
}
|
|
134
|
+
/**
|
|
135
|
+
* Persistence manager interface
|
|
136
|
+
*/
|
|
137
|
+
export interface PersistenceManagerInterface {
|
|
138
|
+
/** Current persistence mode */
|
|
139
|
+
readonly mode: PersistenceMode;
|
|
140
|
+
/** Initialize the persistence manager */
|
|
141
|
+
initialize(): Promise<void>;
|
|
142
|
+
/** Save file metadata */
|
|
143
|
+
saveFileMeta(meta: StoredFileMeta): Promise<void>;
|
|
144
|
+
/** Save file blob (indexeddb mode only) */
|
|
145
|
+
saveFileBlob(fileId: string, blob: Blob): Promise<void>;
|
|
146
|
+
/** Save file handle (file-system-access mode only) */
|
|
147
|
+
saveFileHandle(fileId: string, handle: FileSystemFileHandle): Promise<void>;
|
|
148
|
+
/** Load all stored file metadata */
|
|
149
|
+
loadAllFileMeta(): Promise<StoredFileMeta[]>;
|
|
150
|
+
/** Recover a single file with its data/handle */
|
|
151
|
+
recoverFile(meta: StoredFileMeta): Promise<FileRecoveryResult>;
|
|
152
|
+
/** Remove file data from storage */
|
|
153
|
+
removeFile(fileId: string): Promise<void>;
|
|
154
|
+
/** Clear all persisted data */
|
|
155
|
+
clearAll(): Promise<void>;
|
|
156
|
+
/** Get storage quota information */
|
|
157
|
+
getStorageQuota(): Promise<StorageQuotaInfo>;
|
|
158
|
+
/** Check if file-system-access mode is supported */
|
|
159
|
+
isFileSystemAccessSupported(): boolean;
|
|
160
|
+
}
|
|
161
|
+
/**
|
|
162
|
+
* Pending file that needs user action to restore
|
|
163
|
+
*/
|
|
164
|
+
export interface PendingFile {
|
|
165
|
+
/** Unique file ID */
|
|
166
|
+
id: string;
|
|
167
|
+
/** Original file name - dev can show this to guide user */
|
|
168
|
+
fileName: string;
|
|
169
|
+
/** File size in bytes */
|
|
170
|
+
fileSize: number;
|
|
171
|
+
/** File last modified timestamp */
|
|
172
|
+
lastModified: number;
|
|
173
|
+
/** Upload progress before interruption (0-100) */
|
|
174
|
+
progress: number;
|
|
175
|
+
/** Reason why file needs action */
|
|
176
|
+
reason: 'permission_required' | 'repick_required' | 'file_modified' | 'handlers_unavailable';
|
|
177
|
+
/** Full metadata for internal use */
|
|
178
|
+
meta: StoredFileMeta;
|
|
179
|
+
/** FileSystemFileHandle if available (file-system-access mode) */
|
|
180
|
+
handle?: FileSystemFileHandle;
|
|
181
|
+
}
|
|
182
|
+
/**
|
|
183
|
+
* Result of restoreFiles operation (for file-system-access mode)
|
|
184
|
+
*/
|
|
185
|
+
export interface RestoreFilesResult {
|
|
186
|
+
/** Successfully restored file IDs */
|
|
187
|
+
restored: string[];
|
|
188
|
+
/** Files that failed to restore */
|
|
189
|
+
failed: Array<{
|
|
190
|
+
id: string;
|
|
191
|
+
reason: 'permission_denied' | 'file_modified' | 'file_not_found' | 'unknown_error';
|
|
192
|
+
fileName: string;
|
|
193
|
+
}>;
|
|
194
|
+
}
|
|
195
|
+
/**
|
|
196
|
+
* Result of repickFile operation
|
|
197
|
+
*/
|
|
198
|
+
export type RepickFileResult = {
|
|
199
|
+
success: true;
|
|
200
|
+
} | {
|
|
201
|
+
success: false;
|
|
202
|
+
reason: 'name_mismatch';
|
|
203
|
+
expected: string;
|
|
204
|
+
actual: string;
|
|
205
|
+
} | {
|
|
206
|
+
success: false;
|
|
207
|
+
reason: 'size_mismatch';
|
|
208
|
+
expected: number;
|
|
209
|
+
actual: number;
|
|
210
|
+
} | {
|
|
211
|
+
success: false;
|
|
212
|
+
reason: 'modified_mismatch';
|
|
213
|
+
expected: number;
|
|
214
|
+
actual: number;
|
|
215
|
+
} | {
|
|
216
|
+
success: false;
|
|
217
|
+
reason: 'file_not_pending';
|
|
218
|
+
};
|
|
219
|
+
/**
|
|
220
|
+
* Persistence context value exposed via usePersistence hook
|
|
221
|
+
*/
|
|
222
|
+
export interface PersistenceContextValue {
|
|
223
|
+
/** Whether persistence is initialized */
|
|
224
|
+
isInitialized: boolean;
|
|
225
|
+
/** Current persistence mode */
|
|
226
|
+
mode: PersistenceMode;
|
|
227
|
+
/** Files pending user action to restore */
|
|
228
|
+
pendingFiles: PendingFile[];
|
|
229
|
+
/**
|
|
230
|
+
* Restore files by requesting permission (file-system-access mode)
|
|
231
|
+
* Call this after user confirms they want to restore
|
|
232
|
+
*/
|
|
233
|
+
restoreFiles: (fileIds?: string[]) => Promise<RestoreFilesResult>;
|
|
234
|
+
/**
|
|
235
|
+
* Repick a file (repick mode)
|
|
236
|
+
* Dev passes the file user selected, we validate and restore
|
|
237
|
+
*/
|
|
238
|
+
repickFile: (fileId: string, file: File) => Promise<RepickFileResult>;
|
|
239
|
+
/** Dismiss a pending file without restoring */
|
|
240
|
+
dismissFile: (fileId: string) => Promise<void>;
|
|
241
|
+
/** Dismiss all pending files */
|
|
242
|
+
dismissAll: () => Promise<void>;
|
|
243
|
+
/** Storage quota info */
|
|
244
|
+
storageQuota: StorageQuotaInfo | null;
|
|
245
|
+
}
|
|
246
|
+
/**
|
|
247
|
+
* File-system-access API types (for TypeScript)
|
|
248
|
+
*/
|
|
249
|
+
export interface FileSystemPermissionDescriptor {
|
|
250
|
+
mode?: 'read' | 'readwrite';
|
|
251
|
+
}
|
|
252
|
+
export interface FileSystemHandleWithPermission extends FileSystemFileHandle {
|
|
253
|
+
queryPermission(descriptor?: FileSystemPermissionDescriptor): Promise<PermissionState>;
|
|
254
|
+
requestPermission(descriptor?: FileSystemPermissionDescriptor): Promise<PermissionState>;
|
|
255
|
+
}
|
|
256
|
+
export interface FilePickerOptions {
|
|
257
|
+
types?: Array<{
|
|
258
|
+
description?: string;
|
|
259
|
+
accept: Record<string, string[]>;
|
|
260
|
+
}>;
|
|
261
|
+
excludeAcceptAllOption?: boolean;
|
|
262
|
+
multiple?: boolean;
|
|
263
|
+
}
|
|
264
|
+
export interface WindowWithFileSystem extends Window {
|
|
265
|
+
showOpenFilePicker(options?: FilePickerOptions): Promise<FileSystemFileHandle[]>;
|
|
266
|
+
}
|