@gravito/nebula 3.0.1 → 4.0.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/dist/index.d.ts CHANGED
@@ -1,176 +1,287 @@
1
1
  import { PlanetCore, GravitoOrbit } from '@gravito/core';
2
2
 
3
3
  /**
4
- * Interface for a file storage provider.
4
+ * 底層儲存介面
5
5
  *
6
- * All storage backends (Local, S3, Cloudinary, etc.) must implement this interface.
7
- * It provides a consistent API for file operations across different runtimes
8
- * and cloud providers.
6
+ * 所有儲存後端 (Local, S3, GCS ) 必須實作此介面
9
7
  *
10
8
  * @public
11
- * @since 3.0.0
9
+ * @since 4.0.0
12
10
  */
13
- interface StorageProvider {
11
+ interface StorageStore {
14
12
  /**
15
- * Save data to the storage backend.
16
- *
17
- * @param key - Unique identifier or path for the file (e.g., 'avatars/user1.jpg').
18
- * @param data - The file content as a Blob, Buffer, or string.
19
- * @returns A promise that resolves when the file is successfully saved.
13
+ * 儲存檔案
14
+ * @param key - 檔案路徑 (例如: 'avatars/user1.jpg')
15
+ * @param data - 檔案內容
20
16
  */
21
17
  put(key: string, data: Blob | Buffer | string): Promise<void>;
22
18
  /**
23
- * Retrieve a file from the storage backend.
24
- *
25
- * @param key - The file identifier or path.
26
- * @returns The file as a Blob, or null if the file does not exist.
19
+ * 讀取檔案
20
+ * @param key - 檔案路徑
21
+ * @returns 檔案內容,若不存在則回傳 null
27
22
  */
28
23
  get(key: string): Promise<Blob | null>;
29
24
  /**
30
- * Remove a file from the storage backend.
31
- *
32
- * @param key - The file identifier or path to delete.
33
- * @returns A promise that resolves when the file is deleted.
25
+ * 刪除檔案
26
+ * @param key - 檔案路徑
27
+ * @returns 是否成功刪除 (若檔案不存在則回傳 false)
34
28
  */
35
- delete(key: string): Promise<void>;
29
+ delete(key: string): Promise<boolean>;
36
30
  /**
37
- * Get a publicly accessible URL for the given file key.
38
- *
39
- * Note: This may return a relative URL for local storage or a full URL
40
- * for cloud storage providers.
41
- *
42
- * @param key - The file identifier or path.
43
- * @returns The public URL string.
31
+ * 檢查檔案是否存在
32
+ * @param key - 檔案路徑
44
33
  */
45
- getUrl(key: string): string;
46
- }
47
- /**
48
- * Local file system storage provider.
49
- *
50
- * Stores files on the local disk using the configured root directory and
51
- * resolves URLs using a provided base URL prefix.
52
- *
53
- * @example
54
- * ```typescript
55
- * const local = new LocalStorageProvider('./storage', '/files');
56
- * await local.put('hello.txt', 'Hello World');
57
- * console.log(local.getUrl('hello.txt')); // "/files/hello.txt"
58
- * ```
59
- *
60
- * @public
61
- * @since 3.0.0
62
- */
63
- declare class LocalStorageProvider implements StorageProvider {
64
- private rootDir;
65
- private baseUrl;
66
- private runtime;
34
+ exists(key: string): Promise<boolean>;
67
35
  /**
68
- * Create a new LocalStorageProvider.
69
- *
70
- * @param rootDir - The absolute path to the local storage directory.
71
- * @param baseUrl - The public URL path for accessing stored files (e.g., '/storage').
36
+ * 複製檔案
37
+ * @param from - 來源路徑
38
+ * @param to - 目標路徑
72
39
  */
73
- constructor(rootDir: string, baseUrl?: string);
40
+ copy(from: string, to: string): Promise<void>;
74
41
  /**
75
- * Write data to the local disk.
42
+ * 移動/重命名檔案
43
+ * @param from - 來源路徑
44
+ * @param to - 目標路徑
76
45
  */
77
- put(key: string, data: Blob | Buffer | string): Promise<void>;
46
+ move(from: string, to: string): Promise<void>;
78
47
  /**
79
- * Read data from the local disk.
48
+ * 列出檔案 (可選實作,需要 RuntimeAdapter 支援)
49
+ * @param prefix - 路徑前綴 (例如: 'uploads/')
80
50
  */
81
- get(key: string): Promise<Blob | null>;
51
+ list?(prefix?: string): AsyncIterable<StorageItem>;
82
52
  /**
83
- * Delete a file from the local disk.
53
+ * 取得檔案元資料
54
+ * @param key - 檔案路徑
84
55
  */
85
- delete(key: string): Promise<void>;
56
+ getMetadata(key: string): Promise<StorageMetadata | null>;
86
57
  /**
87
- * Resolve the public URL for a locally stored file.
58
+ * 取得公開 URL
59
+ * @param key - 檔案路徑
88
60
  */
89
61
  getUrl(key: string): string;
90
- private normalizeKey;
91
- private resolveKeyPath;
62
+ /**
63
+ * 取得有時效的簽名 URL (可選實作)
64
+ * @param key - 檔案路徑
65
+ * @param expiresIn - 過期時間 (秒)
66
+ */
67
+ getSignedUrl?(key: string, expiresIn: number): Promise<string>;
92
68
  }
93
69
  /**
94
- * Configuration options for the Nebula Storage Orbit.
95
- *
70
+ * 檔案元資料
71
+ * @public
72
+ */
73
+ interface StorageMetadata {
74
+ /** 檔案路徑 */
75
+ key: string;
76
+ /** 檔案大小 (bytes) */
77
+ size: number;
78
+ /** MIME 類型 */
79
+ mimeType?: string;
80
+ /** 最後修改時間 */
81
+ lastModified?: Date;
82
+ /** ETag (用於快取驗證) */
83
+ etag?: string;
84
+ }
85
+ /**
86
+ * 檔案清單項目
87
+ * @public
88
+ */
89
+ interface StorageItem {
90
+ /** 檔案路徑 */
91
+ key: string;
92
+ /** 是否為目錄 */
93
+ isDirectory: boolean;
94
+ /** 檔案大小 (目錄為 undefined) */
95
+ size?: number;
96
+ /** 最後修改時間 */
97
+ lastModified?: Date;
98
+ }
99
+
100
+ /**
101
+ * 單一磁碟配置
102
+ * @public
103
+ */
104
+ type OrbitNebulaStoreConfig = {
105
+ driver: 'local';
106
+ root: string;
107
+ baseUrl?: string;
108
+ } | {
109
+ driver: 'memory';
110
+ } | {
111
+ driver: 'null';
112
+ } | {
113
+ driver: 'custom';
114
+ store: StorageStore;
115
+ };
116
+ /**
117
+ * OrbitNebula 配置選項
96
118
  * @public
97
- * @since 3.0.0
98
119
  */
99
120
  interface OrbitNebulaOptions {
100
- /**
101
- * Custom storage provider instance (e.g., S3Provider).
102
- * If not provided, a LocalStorageProvider will be created if `local` options are set.
103
- */
104
- provider?: StorageProvider;
105
- /**
106
- * The key used to expose the storage service in the request context.
107
- * @default 'storage'
108
- */
121
+ default?: string;
109
122
  exposeAs?: string;
110
- /** Configuration for the default LocalStorageProvider. */
123
+ disks?: Record<string, OrbitNebulaStoreConfig>;
124
+ eventsMode?: 'sync' | 'async';
125
+ /** @deprecated 使用 disks.local 替代 */
111
126
  local?: {
112
- /** Absolute or relative path to the root directory on disk. */
113
127
  root: string;
114
- /** Base URL prefix for serving files (e.g., '/public/storage'). @default '/storage' */
115
128
  baseUrl?: string;
116
129
  };
130
+ /** @deprecated 使用 disks[name] = { driver: 'custom', store } 替代 */
131
+ provider?: StorageStore;
132
+ }
133
+ /**
134
+ * Hooks 回調介面
135
+ * @internal
136
+ */
137
+ interface StorageHooks {
138
+ applyFilter<T>(hook: string, value: T, context?: Record<string, unknown>): Promise<T>;
139
+ doAction(hook: string, context?: Record<string, unknown>): Promise<void>;
140
+ }
141
+
142
+ declare class StorageRepository {
143
+ private readonly store;
144
+ private readonly hooks?;
145
+ constructor(store: StorageStore, hooks?: StorageHooks | undefined);
146
+ put(key: string, data: Blob | Buffer | string): Promise<void>;
147
+ get(key: string): Promise<Blob | null>;
148
+ delete(key: string): Promise<boolean>;
149
+ exists(key: string): Promise<boolean>;
150
+ copy(from: string, to: string): Promise<void>;
151
+ move(from: string, to: string): Promise<void>;
152
+ list(prefix?: string): AsyncIterable<StorageItem>;
153
+ getMetadata(key: string): Promise<StorageMetadata | null>;
154
+ getUrl(key: string): string;
155
+ getSignedUrl(key: string, expiresIn: number): Promise<string>;
156
+ }
157
+
158
+ declare class StorageManager {
159
+ private readonly storeFactory;
160
+ private readonly options;
161
+ private readonly hooks?;
162
+ private stores;
163
+ private repositories;
164
+ constructor(storeFactory: (name: string) => StorageStore, options: {
165
+ default: string;
166
+ prefix?: string;
167
+ }, hooks?: StorageHooks | undefined);
168
+ disk(name?: string): StorageRepository;
169
+ private resolveStore;
170
+ put(key: string, data: Blob | Buffer | string): Promise<void>;
171
+ get(key: string): Promise<Blob | null>;
172
+ delete(key: string): Promise<boolean>;
173
+ exists(key: string): Promise<boolean>;
174
+ copy(from: string, to: string): Promise<void>;
175
+ move(from: string, to: string): Promise<void>;
176
+ list(prefix?: string): AsyncIterable<StorageItem>;
177
+ getMetadata(key: string): Promise<StorageMetadata | null>;
178
+ getUrl(key: string): string;
179
+ getSignedUrl(key: string, expiresIn: number): Promise<string>;
117
180
  }
181
+
182
+ declare class LocalStore implements StorageStore {
183
+ private readonly rootDir;
184
+ private readonly baseUrl;
185
+ private runtime;
186
+ constructor(rootDir: string, baseUrl?: string);
187
+ put(key: string, data: Blob | Buffer | string): Promise<void>;
188
+ get(key: string): Promise<Blob | null>;
189
+ delete(key: string): Promise<boolean>;
190
+ exists(key: string): Promise<boolean>;
191
+ copy(from: string, to: string): Promise<void>;
192
+ move(from: string, to: string): Promise<void>;
193
+ list(prefix?: string): AsyncIterable<StorageItem>;
194
+ getMetadata(key: string): Promise<StorageMetadata | null>;
195
+ getUrl(key: string): string;
196
+ private normalizeKey;
197
+ private resolvePath;
198
+ private ensureDirectory;
199
+ private guessMimeType;
200
+ }
201
+
202
+ declare class MemoryStore implements StorageStore {
203
+ private files;
204
+ put(key: string, data: Blob | Buffer | string): Promise<void>;
205
+ get(key: string): Promise<Blob | null>;
206
+ delete(key: string): Promise<boolean>;
207
+ exists(key: string): Promise<boolean>;
208
+ copy(from: string, to: string): Promise<void>;
209
+ move(from: string, to: string): Promise<void>;
210
+ list(prefix?: string): AsyncIterable<StorageItem>;
211
+ getMetadata(key: string): Promise<StorageMetadata | null>;
212
+ getUrl(key: string): string;
213
+ }
214
+
215
+ declare class NullStore implements StorageStore {
216
+ put(_key: string, _data: Blob | Buffer | string): Promise<void>;
217
+ get(_key: string): Promise<Blob | null>;
218
+ delete(_key: string): Promise<boolean>;
219
+ exists(_key: string): Promise<boolean>;
220
+ copy(_from: string, _to: string): Promise<void>;
221
+ move(_from: string, _to: string): Promise<void>;
222
+ list(_prefix?: string): AsyncIterable<StorageItem>;
223
+ getMetadata(_key: string): Promise<StorageMetadata | null>;
224
+ getUrl(key: string): string;
225
+ }
226
+
227
+ /** @deprecated Use StorageStore instead */
228
+ type StorageProvider = StorageStore;
229
+
118
230
  /** @deprecated Use OrbitNebulaOptions instead */
119
231
  type OrbitStorageOptions = OrbitNebulaOptions;
120
232
  /**
121
233
  * OrbitNebula provides a unified file storage abstraction for Gravito.
122
234
  *
123
- * It supports multiple backends (local, S3, etc.) and provides a consistent API
124
- * for file operations. It also integrates with Gravito's hook system for
125
- * filtering uploads (`storage:upload`) and reacting to events (`storage:uploaded`).
235
+ * It supports multiple backends (local, S3, etc.) via the StorageManager.
126
236
  *
127
237
  * @example
128
238
  * ```typescript
129
239
  * const nebula = new OrbitNebula({
130
- * local: { root: './storage', baseUrl: '/public' }
240
+ * default: 'local',
241
+ * disks: {
242
+ * local: { driver: 'local', root: './uploads' }
243
+ * }
131
244
  * });
132
245
  * core.addOrbit(nebula);
133
- *
134
- * // Usage in controller
135
- * const storage = c.get('storage');
136
- * await storage.put('example.txt', 'Content');
137
246
  * ```
138
247
  *
139
248
  * @public
140
- * @since 3.0.0
249
+ * @since 3.0.0 (Refactored in 4.0.0)
141
250
  */
142
251
  declare class OrbitNebula implements GravitoOrbit {
143
252
  private options?;
253
+ private manager?;
144
254
  constructor(options?: OrbitNebulaOptions | undefined);
145
255
  /**
146
256
  * Install storage service into PlanetCore.
147
257
  *
148
258
  * @param core - The PlanetCore instance.
149
- * @throws {Error} If configuration or provider is missing.
150
259
  */
151
260
  install(core: PlanetCore): void;
261
+ /**
262
+ * Get the installed StorageManager instance.
263
+ *
264
+ * @returns The StorageManager instance.
265
+ * @throws {Error} If not installed.
266
+ */
267
+ getStorage(): StorageManager;
268
+ private createStoreFactory;
152
269
  }
153
270
  /**
154
271
  * Functional API for installing OrbitNebula.
155
272
  *
156
273
  * @param core - The PlanetCore instance.
157
274
  * @param options - Storage options.
158
- * @returns The configured storage provider wrapper.
159
- * @throws {Error} If provider is not configured.
275
+ * @returns The StorageManager instance.
160
276
  */
161
- declare function orbitStorage(core: PlanetCore, options: OrbitNebulaOptions): {
162
- put: (key: string, data: Blob | Buffer | string) => Promise<void>;
163
- get: (key: string) => Promise<Blob | null>;
164
- delete: (key: string) => Promise<void>;
165
- getUrl: (key: string) => string;
166
- };
277
+ declare function orbitStorage(core: PlanetCore, options: OrbitNebulaOptions): StorageManager;
167
278
  /** @deprecated Use OrbitNebula instead */
168
279
  declare const OrbitStorage: typeof OrbitNebula;
169
280
  declare module '@gravito/core' {
170
281
  interface GravitoVariables {
171
282
  /** File storage service */
172
- storage: StorageProvider;
283
+ storage: StorageManager;
173
284
  }
174
285
  }
175
286
 
176
- export { LocalStorageProvider, OrbitNebula, type OrbitNebulaOptions, OrbitStorage, type OrbitStorageOptions, type StorageProvider, orbitStorage as default };
287
+ export { LocalStore as LocalStorageProvider, LocalStore, MemoryStore, NullStore, OrbitNebula, type OrbitNebulaOptions, type OrbitNebulaStoreConfig, OrbitStorage, type OrbitStorageOptions, type StorageHooks, type StorageItem, StorageManager, type StorageMetadata, type StorageProvider, StorageRepository, type StorageStore, orbitStorage as default };