@rezwanul7/storage 0.0.0 → 0.1.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.
@@ -0,0 +1,269 @@
1
+ import { S as SharedFileRules } from '../fileRules.types-CGXBnwzd.cjs';
2
+
3
+ /** The full Rules the server checks: the shared size and extension Rules, MIME and block lists, and your own checks. */
4
+ interface ServerValidationRules extends SharedFileRules {
5
+ /** MIME types a file's bytes may show. Any is allowed when omitted. */
6
+ allowedMimeTypes?: string[];
7
+ /** MIME types to reject. */
8
+ blockedMimeTypes?: string[];
9
+ /** Extensions to reject, lower case and without the dot. */
10
+ blockedExtensions?: string[];
11
+ /** Your own checks, run after the built-in ones. */
12
+ customValidators?: ServerFileValidator[];
13
+ }
14
+ /**
15
+ * Your own check on an uploaded file. Return a message to reject the file, or nothing to accept it.
16
+ *
17
+ * @param params - The file's bytes and what is known about its type.
18
+ * @returns A message that is safe to show to users, or nothing.
19
+ */
20
+ type ServerFileValidator = (params: ServerFileValidationContext) => Promise<string | null | undefined> | string | null | undefined;
21
+ /** What a {@link ServerFileValidator} receives about the file it checks. */
22
+ interface ServerFileValidationContext {
23
+ /** The file's bytes. */
24
+ buffer: Uint8Array;
25
+ /** The name the file was uploaded with. */
26
+ originalName: string;
27
+ /** The MIME type the browser declared, if any. */
28
+ declaredMime: string | undefined;
29
+ /** The MIME type its bytes show, or the best guess from its name. */
30
+ detectedMime: string | undefined;
31
+ /** The extension its bytes show, or the one in its name. */
32
+ detectedExt: string | undefined;
33
+ /** The file's size, in bytes. */
34
+ size: number;
35
+ }
36
+
37
+ /**
38
+ * Where the package logs failures it handles itself. A `@rezwanul7/logger` instance fits it as is.
39
+ */
40
+ interface StorageLogger {
41
+ /**
42
+ * Logs a failure the package recovered from, such as `storage.rollback_delete_failed`.
43
+ *
44
+ * @param event - The event name.
45
+ * @param data - Structured context.
46
+ */
47
+ error(event: string, data?: Record<string, unknown>): void;
48
+ }
49
+ /** One file an Upload stored. */
50
+ interface FileUploadResult {
51
+ /** The name the file was uploaded with. */
52
+ originalFileName: string;
53
+ /** The name of the Provider that stored the file. Save it: read and delete the file through the same Provider. */
54
+ provider: string;
55
+ /** The file's Storage ID. Save it to read or delete the file later. */
56
+ storageId: string;
57
+ /** The Provider's URL for the file. `LocalFileStorage`'s isn't served; serve files through the app. */
58
+ url: string;
59
+ /** The file's size, in bytes. */
60
+ size: number;
61
+ /** The MIME type its bytes show, not the one the browser declared. */
62
+ mime: string;
63
+ /** The extension its bytes show, lower case and without the dot. */
64
+ ext: string;
65
+ }
66
+ /**
67
+ * What {@link FileUpload.store} did: stored every file, or stored none and says why. Errors are keyed by the file's
68
+ * index, and their messages are safe to show to users.
69
+ */
70
+ type FileStoreResult = {
71
+ /** Every file was stored. */
72
+ ok: true;
73
+ /** The stored files, in the order given. */
74
+ files: FileUploadResult[];
75
+ } | {
76
+ /** No file was stored. */
77
+ ok: false;
78
+ /** Each failed file's messages, keyed by its index. */
79
+ errors: Record<number, string[]>;
80
+ };
81
+ /** Checks untrusted files and stores them; built by `createFileUpload`. */
82
+ interface FileUpload {
83
+ /**
84
+ * Checks every file against `rules` and stores them under `directory` only when all of them pass. If storing one
85
+ * fails, the files stored before it are deleted and a `StorageError` is thrown, so nothing is left half-stored.
86
+ *
87
+ * @param files - One file or several.
88
+ * @param rules - The Rules every file must satisfy.
89
+ * @param options - The folder to store the files under.
90
+ * @returns The stored files, or every failed file's messages keyed by its index in `files` (0 for a single file).
91
+ */
92
+ store(files: File | File[], rules: ServerValidationRules, options: {
93
+ directory: string;
94
+ }): Promise<FileStoreResult>;
95
+ }
96
+
97
+ /** What a Storage returns for a file it stored. */
98
+ interface StorageUploadResult {
99
+ /** The Provider's URL for the file. It is not necessarily served to browsers. */
100
+ url: string;
101
+ /** The Storage ID: the key the Storage gave the file, such as a path or an object key. */
102
+ storageId: string;
103
+ /** The stored size, in bytes. */
104
+ size: number;
105
+ /** The MIME type the file was stored with. */
106
+ mime: string;
107
+ }
108
+ /** A stored file read back from its Provider. */
109
+ interface StoredFile {
110
+ /** The file's bytes. */
111
+ stream: ReadableStream<Uint8Array>;
112
+ /** The file's size, in bytes. */
113
+ size: number;
114
+ }
115
+ /**
116
+ * The adapter to one kind of Provider. Implement it to add a Provider: pick each file's key under the given
117
+ * `directory`, take settings as constructor options, and throw `StorageError` with `STORAGE_INVALID_ID` for a
118
+ * Storage ID outside the Provider.
119
+ */
120
+ interface FileStorage {
121
+ /** The Provider's name, saved with each file, such as `"local"`. Read and delete a file through the same one. */
122
+ readonly provider: string;
123
+ /**
124
+ * Stores one checked file.
125
+ *
126
+ * @param params - The file's bytes, its MIME type and extension, and the folder to store it under. The Storage
127
+ * picks the file's own name.
128
+ * @returns Where the file was stored.
129
+ */
130
+ upload(params: {
131
+ buffer: Uint8Array;
132
+ mime: string;
133
+ ext: string;
134
+ directory: string;
135
+ }): Promise<StorageUploadResult>;
136
+ /**
137
+ * Reads a stored file.
138
+ *
139
+ * @param storageId - The file's Storage ID.
140
+ * @returns The file, or null when nothing is stored under `storageId`.
141
+ */
142
+ read(storageId: string): Promise<StoredFile | null>;
143
+ /**
144
+ * Deletes a stored file. Deleting a file that isn't there succeeds.
145
+ *
146
+ * @param storageId - The file's Storage ID.
147
+ */
148
+ delete(storageId: string): Promise<void>;
149
+ /**
150
+ * The Provider's URL for a stored file.
151
+ *
152
+ * @param storageId - The file's Storage ID.
153
+ * @returns The URL. It is not necessarily served to browsers.
154
+ */
155
+ getUrl(storageId: string): string;
156
+ /**
157
+ * Whether a file is stored under `storageId`. Optional.
158
+ *
159
+ * @param storageId - The file's Storage ID.
160
+ * @returns True when a file is stored there.
161
+ */
162
+ exists?(storageId: string): Promise<boolean>;
163
+ }
164
+
165
+ /** What {@link createFileUpload} needs. */
166
+ interface FileUploadOptions {
167
+ /** The Storage checked files are stored through. */
168
+ storage: FileStorage;
169
+ /**
170
+ * Where files a failed Upload couldn't remove are logged, as `storage.rollback_delete_failed`. Defaults to a logger
171
+ * that writes nothing.
172
+ */
173
+ logger?: StorageLogger;
174
+ }
175
+ /**
176
+ * Builds the uploader, which checks untrusted files and stores them through `storage`.
177
+ *
178
+ * @param options - The Storage and an optional logger.
179
+ * @returns The uploader.
180
+ *
181
+ * @example
182
+ * const uploader = createFileUpload({ storage: new LocalFileStorage({ root: "./uploads", urlPrefix: "/uploads" }) });
183
+ */
184
+ declare function createFileUpload({ storage, logger, }: FileUploadOptions): FileUpload;
185
+
186
+ /** Settings of a {@link LocalFileStorage}. */
187
+ interface LocalFileStorageOptions {
188
+ /** Folder the files are stored under. Keep it outside `public/`. */
189
+ root: string;
190
+ /** Prefix of the URL `getUrl` returns, without a trailing slash, e.g. "/uploads". */
191
+ urlPrefix: string;
192
+ }
193
+ /**
194
+ * The Storage for the server's disk, Provider name `"local"`. Keep `root` outside any folder the web server serves, so
195
+ * nothing is served without going through the app.
196
+ *
197
+ * @example
198
+ * const storage = new LocalFileStorage({ root: "./uploads", urlPrefix: "/uploads" });
199
+ */
200
+ declare class LocalFileStorage implements FileStorage {
201
+ /** The Provider's name, saved with each file. */
202
+ readonly provider = "local";
203
+ private readonly root;
204
+ private readonly urlPrefix;
205
+ /**
206
+ * @param options - The folder to store under and the URL prefix.
207
+ */
208
+ constructor({ root, urlPrefix }: LocalFileStorageOptions);
209
+ /**
210
+ * Writes a file under `directory` with a random name.
211
+ *
212
+ * @param params - The file's bytes, MIME type, extension and folder.
213
+ * @returns Where the file was stored.
214
+ */
215
+ upload({ buffer, mime, ext, directory, }: Parameters<FileStorage["upload"]>[0]): Promise<StorageUploadResult>;
216
+ /**
217
+ * Reads a stored file as a stream.
218
+ *
219
+ * @param storageId - The file's Storage ID.
220
+ * @returns The file, or null when nothing is stored there.
221
+ */
222
+ read(storageId: string): Promise<StoredFile | null>;
223
+ /**
224
+ * Deletes a stored file; succeeds when it isn't there.
225
+ *
226
+ * @param storageId - The file's Storage ID.
227
+ */
228
+ delete(storageId: string): Promise<void>;
229
+ /**
230
+ * The file's URL under `urlPrefix`. Nothing serves it until your app does.
231
+ *
232
+ * @param storageId - The file's Storage ID.
233
+ * @returns The URL.
234
+ */
235
+ getUrl(storageId: string): string;
236
+ /** Maps a storage ID to a path under the root, refusing IDs that would escape it. */
237
+ private resolve;
238
+ }
239
+
240
+ /**
241
+ * The stable code of a {@link StorageError}.
242
+ *
243
+ * - `STORAGE_INVALID_ID`: the Storage ID points outside the Provider (a bug or a tampered ID).
244
+ * - `STORAGE_UPLOAD_FAILED`: the Storage couldn't store a file; `cause` is its error.
245
+ */
246
+ type StorageErrorCode = "STORAGE_INVALID_ID" | "STORAGE_UPLOAD_FAILED";
247
+ /**
248
+ * A storage operation failed. Branch on `code`; `cause` is the Provider's error and `meta` its context, for logs. The
249
+ * message is for developers: the caller decides what its users see.
250
+ */
251
+ declare class StorageError extends Error {
252
+ /** Always `"StorageError"`. */
253
+ readonly name = "StorageError";
254
+ /** Stable code naming what went wrong. */
255
+ readonly code: StorageErrorCode;
256
+ /** Context for logs, such as the Provider's name. */
257
+ readonly meta?: Record<string, unknown>;
258
+ /**
259
+ * @param code - The stable code.
260
+ * @param opts - The message, the underlying `cause` and context for logs.
261
+ */
262
+ constructor(code: StorageErrorCode, opts: {
263
+ message: string;
264
+ cause?: unknown;
265
+ meta?: Record<string, unknown>;
266
+ });
267
+ }
268
+
269
+ export { type FileStorage, type FileStoreResult, type FileUpload, type FileUploadOptions, type FileUploadResult, LocalFileStorage, type LocalFileStorageOptions, type ServerFileValidationContext, type ServerFileValidator, type ServerValidationRules, StorageError, type StorageErrorCode, type StorageLogger, type StorageUploadResult, type StoredFile, createFileUpload };
@@ -0,0 +1,269 @@
1
+ import { S as SharedFileRules } from '../fileRules.types-CGXBnwzd.js';
2
+
3
+ /** The full Rules the server checks: the shared size and extension Rules, MIME and block lists, and your own checks. */
4
+ interface ServerValidationRules extends SharedFileRules {
5
+ /** MIME types a file's bytes may show. Any is allowed when omitted. */
6
+ allowedMimeTypes?: string[];
7
+ /** MIME types to reject. */
8
+ blockedMimeTypes?: string[];
9
+ /** Extensions to reject, lower case and without the dot. */
10
+ blockedExtensions?: string[];
11
+ /** Your own checks, run after the built-in ones. */
12
+ customValidators?: ServerFileValidator[];
13
+ }
14
+ /**
15
+ * Your own check on an uploaded file. Return a message to reject the file, or nothing to accept it.
16
+ *
17
+ * @param params - The file's bytes and what is known about its type.
18
+ * @returns A message that is safe to show to users, or nothing.
19
+ */
20
+ type ServerFileValidator = (params: ServerFileValidationContext) => Promise<string | null | undefined> | string | null | undefined;
21
+ /** What a {@link ServerFileValidator} receives about the file it checks. */
22
+ interface ServerFileValidationContext {
23
+ /** The file's bytes. */
24
+ buffer: Uint8Array;
25
+ /** The name the file was uploaded with. */
26
+ originalName: string;
27
+ /** The MIME type the browser declared, if any. */
28
+ declaredMime: string | undefined;
29
+ /** The MIME type its bytes show, or the best guess from its name. */
30
+ detectedMime: string | undefined;
31
+ /** The extension its bytes show, or the one in its name. */
32
+ detectedExt: string | undefined;
33
+ /** The file's size, in bytes. */
34
+ size: number;
35
+ }
36
+
37
+ /**
38
+ * Where the package logs failures it handles itself. A `@rezwanul7/logger` instance fits it as is.
39
+ */
40
+ interface StorageLogger {
41
+ /**
42
+ * Logs a failure the package recovered from, such as `storage.rollback_delete_failed`.
43
+ *
44
+ * @param event - The event name.
45
+ * @param data - Structured context.
46
+ */
47
+ error(event: string, data?: Record<string, unknown>): void;
48
+ }
49
+ /** One file an Upload stored. */
50
+ interface FileUploadResult {
51
+ /** The name the file was uploaded with. */
52
+ originalFileName: string;
53
+ /** The name of the Provider that stored the file. Save it: read and delete the file through the same Provider. */
54
+ provider: string;
55
+ /** The file's Storage ID. Save it to read or delete the file later. */
56
+ storageId: string;
57
+ /** The Provider's URL for the file. `LocalFileStorage`'s isn't served; serve files through the app. */
58
+ url: string;
59
+ /** The file's size, in bytes. */
60
+ size: number;
61
+ /** The MIME type its bytes show, not the one the browser declared. */
62
+ mime: string;
63
+ /** The extension its bytes show, lower case and without the dot. */
64
+ ext: string;
65
+ }
66
+ /**
67
+ * What {@link FileUpload.store} did: stored every file, or stored none and says why. Errors are keyed by the file's
68
+ * index, and their messages are safe to show to users.
69
+ */
70
+ type FileStoreResult = {
71
+ /** Every file was stored. */
72
+ ok: true;
73
+ /** The stored files, in the order given. */
74
+ files: FileUploadResult[];
75
+ } | {
76
+ /** No file was stored. */
77
+ ok: false;
78
+ /** Each failed file's messages, keyed by its index. */
79
+ errors: Record<number, string[]>;
80
+ };
81
+ /** Checks untrusted files and stores them; built by `createFileUpload`. */
82
+ interface FileUpload {
83
+ /**
84
+ * Checks every file against `rules` and stores them under `directory` only when all of them pass. If storing one
85
+ * fails, the files stored before it are deleted and a `StorageError` is thrown, so nothing is left half-stored.
86
+ *
87
+ * @param files - One file or several.
88
+ * @param rules - The Rules every file must satisfy.
89
+ * @param options - The folder to store the files under.
90
+ * @returns The stored files, or every failed file's messages keyed by its index in `files` (0 for a single file).
91
+ */
92
+ store(files: File | File[], rules: ServerValidationRules, options: {
93
+ directory: string;
94
+ }): Promise<FileStoreResult>;
95
+ }
96
+
97
+ /** What a Storage returns for a file it stored. */
98
+ interface StorageUploadResult {
99
+ /** The Provider's URL for the file. It is not necessarily served to browsers. */
100
+ url: string;
101
+ /** The Storage ID: the key the Storage gave the file, such as a path or an object key. */
102
+ storageId: string;
103
+ /** The stored size, in bytes. */
104
+ size: number;
105
+ /** The MIME type the file was stored with. */
106
+ mime: string;
107
+ }
108
+ /** A stored file read back from its Provider. */
109
+ interface StoredFile {
110
+ /** The file's bytes. */
111
+ stream: ReadableStream<Uint8Array>;
112
+ /** The file's size, in bytes. */
113
+ size: number;
114
+ }
115
+ /**
116
+ * The adapter to one kind of Provider. Implement it to add a Provider: pick each file's key under the given
117
+ * `directory`, take settings as constructor options, and throw `StorageError` with `STORAGE_INVALID_ID` for a
118
+ * Storage ID outside the Provider.
119
+ */
120
+ interface FileStorage {
121
+ /** The Provider's name, saved with each file, such as `"local"`. Read and delete a file through the same one. */
122
+ readonly provider: string;
123
+ /**
124
+ * Stores one checked file.
125
+ *
126
+ * @param params - The file's bytes, its MIME type and extension, and the folder to store it under. The Storage
127
+ * picks the file's own name.
128
+ * @returns Where the file was stored.
129
+ */
130
+ upload(params: {
131
+ buffer: Uint8Array;
132
+ mime: string;
133
+ ext: string;
134
+ directory: string;
135
+ }): Promise<StorageUploadResult>;
136
+ /**
137
+ * Reads a stored file.
138
+ *
139
+ * @param storageId - The file's Storage ID.
140
+ * @returns The file, or null when nothing is stored under `storageId`.
141
+ */
142
+ read(storageId: string): Promise<StoredFile | null>;
143
+ /**
144
+ * Deletes a stored file. Deleting a file that isn't there succeeds.
145
+ *
146
+ * @param storageId - The file's Storage ID.
147
+ */
148
+ delete(storageId: string): Promise<void>;
149
+ /**
150
+ * The Provider's URL for a stored file.
151
+ *
152
+ * @param storageId - The file's Storage ID.
153
+ * @returns The URL. It is not necessarily served to browsers.
154
+ */
155
+ getUrl(storageId: string): string;
156
+ /**
157
+ * Whether a file is stored under `storageId`. Optional.
158
+ *
159
+ * @param storageId - The file's Storage ID.
160
+ * @returns True when a file is stored there.
161
+ */
162
+ exists?(storageId: string): Promise<boolean>;
163
+ }
164
+
165
+ /** What {@link createFileUpload} needs. */
166
+ interface FileUploadOptions {
167
+ /** The Storage checked files are stored through. */
168
+ storage: FileStorage;
169
+ /**
170
+ * Where files a failed Upload couldn't remove are logged, as `storage.rollback_delete_failed`. Defaults to a logger
171
+ * that writes nothing.
172
+ */
173
+ logger?: StorageLogger;
174
+ }
175
+ /**
176
+ * Builds the uploader, which checks untrusted files and stores them through `storage`.
177
+ *
178
+ * @param options - The Storage and an optional logger.
179
+ * @returns The uploader.
180
+ *
181
+ * @example
182
+ * const uploader = createFileUpload({ storage: new LocalFileStorage({ root: "./uploads", urlPrefix: "/uploads" }) });
183
+ */
184
+ declare function createFileUpload({ storage, logger, }: FileUploadOptions): FileUpload;
185
+
186
+ /** Settings of a {@link LocalFileStorage}. */
187
+ interface LocalFileStorageOptions {
188
+ /** Folder the files are stored under. Keep it outside `public/`. */
189
+ root: string;
190
+ /** Prefix of the URL `getUrl` returns, without a trailing slash, e.g. "/uploads". */
191
+ urlPrefix: string;
192
+ }
193
+ /**
194
+ * The Storage for the server's disk, Provider name `"local"`. Keep `root` outside any folder the web server serves, so
195
+ * nothing is served without going through the app.
196
+ *
197
+ * @example
198
+ * const storage = new LocalFileStorage({ root: "./uploads", urlPrefix: "/uploads" });
199
+ */
200
+ declare class LocalFileStorage implements FileStorage {
201
+ /** The Provider's name, saved with each file. */
202
+ readonly provider = "local";
203
+ private readonly root;
204
+ private readonly urlPrefix;
205
+ /**
206
+ * @param options - The folder to store under and the URL prefix.
207
+ */
208
+ constructor({ root, urlPrefix }: LocalFileStorageOptions);
209
+ /**
210
+ * Writes a file under `directory` with a random name.
211
+ *
212
+ * @param params - The file's bytes, MIME type, extension and folder.
213
+ * @returns Where the file was stored.
214
+ */
215
+ upload({ buffer, mime, ext, directory, }: Parameters<FileStorage["upload"]>[0]): Promise<StorageUploadResult>;
216
+ /**
217
+ * Reads a stored file as a stream.
218
+ *
219
+ * @param storageId - The file's Storage ID.
220
+ * @returns The file, or null when nothing is stored there.
221
+ */
222
+ read(storageId: string): Promise<StoredFile | null>;
223
+ /**
224
+ * Deletes a stored file; succeeds when it isn't there.
225
+ *
226
+ * @param storageId - The file's Storage ID.
227
+ */
228
+ delete(storageId: string): Promise<void>;
229
+ /**
230
+ * The file's URL under `urlPrefix`. Nothing serves it until your app does.
231
+ *
232
+ * @param storageId - The file's Storage ID.
233
+ * @returns The URL.
234
+ */
235
+ getUrl(storageId: string): string;
236
+ /** Maps a storage ID to a path under the root, refusing IDs that would escape it. */
237
+ private resolve;
238
+ }
239
+
240
+ /**
241
+ * The stable code of a {@link StorageError}.
242
+ *
243
+ * - `STORAGE_INVALID_ID`: the Storage ID points outside the Provider (a bug or a tampered ID).
244
+ * - `STORAGE_UPLOAD_FAILED`: the Storage couldn't store a file; `cause` is its error.
245
+ */
246
+ type StorageErrorCode = "STORAGE_INVALID_ID" | "STORAGE_UPLOAD_FAILED";
247
+ /**
248
+ * A storage operation failed. Branch on `code`; `cause` is the Provider's error and `meta` its context, for logs. The
249
+ * message is for developers: the caller decides what its users see.
250
+ */
251
+ declare class StorageError extends Error {
252
+ /** Always `"StorageError"`. */
253
+ readonly name = "StorageError";
254
+ /** Stable code naming what went wrong. */
255
+ readonly code: StorageErrorCode;
256
+ /** Context for logs, such as the Provider's name. */
257
+ readonly meta?: Record<string, unknown>;
258
+ /**
259
+ * @param code - The stable code.
260
+ * @param opts - The message, the underlying `cause` and context for logs.
261
+ */
262
+ constructor(code: StorageErrorCode, opts: {
263
+ message: string;
264
+ cause?: unknown;
265
+ meta?: Record<string, unknown>;
266
+ });
267
+ }
268
+
269
+ export { type FileStorage, type FileStoreResult, type FileUpload, type FileUploadOptions, type FileUploadResult, LocalFileStorage, type LocalFileStorageOptions, type ServerFileValidationContext, type ServerFileValidator, type ServerValidationRules, StorageError, type StorageErrorCode, type StorageLogger, type StorageUploadResult, type StoredFile, createFileUpload };