@modern-admin/feature-upload 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.
- package/dist/graphql.d.ts +36 -0
- package/dist/graphql.d.ts.map +1 -0
- package/dist/graphql.js +141 -0
- package/dist/graphql.js.map +1 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +12 -0
- package/dist/index.js.map +1 -0
- package/dist/nest/index.d.ts +3 -0
- package/dist/nest/index.d.ts.map +1 -0
- package/dist/nest/index.js +4 -0
- package/dist/nest/index.js.map +1 -0
- package/dist/nest/upload-sweeper.service.d.ts +32 -0
- package/dist/nest/upload-sweeper.service.d.ts.map +1 -0
- package/dist/nest/upload-sweeper.service.js +68 -0
- package/dist/nest/upload-sweeper.service.js.map +1 -0
- package/dist/nest/upload.controller.d.ts +51 -0
- package/dist/nest/upload.controller.d.ts.map +1 -0
- package/dist/nest/upload.controller.js +220 -0
- package/dist/nest/upload.controller.js.map +1 -0
- package/dist/nest/upload.module.d.ts +28 -0
- package/dist/nest/upload.module.d.ts.map +1 -0
- package/dist/nest/upload.module.js +51 -0
- package/dist/nest/upload.module.js.map +1 -0
- package/dist/nest/upload.tokens.d.ts +23 -0
- package/dist/nest/upload.tokens.d.ts.map +1 -0
- package/dist/nest/upload.tokens.js +6 -0
- package/dist/nest/upload.tokens.js.map +1 -0
- package/dist/pending-registry.d.ts +60 -0
- package/dist/pending-registry.d.ts.map +1 -0
- package/dist/pending-registry.js +106 -0
- package/dist/pending-registry.js.map +1 -0
- package/dist/providers/local.d.ts +36 -0
- package/dist/providers/local.d.ts.map +1 -0
- package/dist/providers/local.js +44 -0
- package/dist/providers/local.js.map +1 -0
- package/dist/providers/s3.d.ts +96 -0
- package/dist/providers/s3.d.ts.map +1 -0
- package/dist/providers/s3.js +164 -0
- package/dist/providers/s3.js.map +1 -0
- package/dist/registry.d.ts +27 -0
- package/dist/registry.d.ts.map +1 -0
- package/dist/registry.js +25 -0
- package/dist/registry.js.map +1 -0
- package/dist/types.d.ts +130 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +9 -0
- package/dist/types.js.map +1 -0
- package/dist/upload-feature.d.ts +31 -0
- package/dist/upload-feature.d.ts.map +1 -0
- package/dist/upload-feature.js +170 -0
- package/dist/upload-feature.js.map +1 -0
- package/package.json +94 -0
- package/src/graphql.ts +185 -0
- package/src/index.ts +22 -0
- package/src/nest/index.ts +4 -0
- package/src/nest/upload-sweeper.service.ts +52 -0
- package/src/nest/upload.controller.ts +228 -0
- package/src/nest/upload.module.ts +44 -0
- package/src/nest/upload.tokens.ts +24 -0
- package/src/pending-registry.ts +115 -0
- package/src/providers/local.ts +63 -0
- package/src/providers/s3.ts +226 -0
- package/src/registry.ts +39 -0
- package/src/types.ts +137 -0
- package/src/upload-feature.ts +208 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"s3.js","sourceRoot":"","sources":["../../src/providers/s3.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Process-level upload provider registry.
|
|
3
|
+
*
|
|
4
|
+
* `uploadFeature()` registers upload configs here (keyed by a generated id) at
|
|
5
|
+
* feature application time. The NestJS `UploadController` looks up configs by
|
|
6
|
+
* the id stored in the property's `custom.uploadProviderId` field.
|
|
7
|
+
*
|
|
8
|
+
* The registry is intentionally a module-level singleton so it is available
|
|
9
|
+
* before the NestJS DI container is initialised — the same pattern used by
|
|
10
|
+
* `ModernAdminFeatureRegistry` in `@modern-admin/nest`.
|
|
11
|
+
*/
|
|
12
|
+
import type { IUploadProvider } from './types.js';
|
|
13
|
+
/** Everything stored per upload property registration. */
|
|
14
|
+
export interface RegisteredUploadConfig {
|
|
15
|
+
provider: IUploadProvider;
|
|
16
|
+
/** Optional custom key generator (from `UploadPropertyConfig.uploadPath`). */
|
|
17
|
+
uploadPath?: (filename: string) => string;
|
|
18
|
+
/** True for multi-file properties — controller will accept N files per request. */
|
|
19
|
+
isArray?: boolean;
|
|
20
|
+
}
|
|
21
|
+
export declare const UploadProviderRegistry: {
|
|
22
|
+
register(id: string, config: RegisteredUploadConfig): void;
|
|
23
|
+
get(id: string): RegisteredUploadConfig | undefined;
|
|
24
|
+
/** For test cleanup. */
|
|
25
|
+
clear(): void;
|
|
26
|
+
};
|
|
27
|
+
//# sourceMappingURL=registry.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../src/registry.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,YAAY,CAAA;AAEjD,0DAA0D;AAC1D,MAAM,WAAW,sBAAsB;IACrC,QAAQ,EAAE,eAAe,CAAA;IACzB,8EAA8E;IAC9E,UAAU,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,MAAM,CAAA;IACzC,mFAAmF;IACnF,OAAO,CAAC,EAAE,OAAO,CAAA;CAClB;AAID,eAAO,MAAM,sBAAsB;iBACpB,MAAM,UAAU,sBAAsB,GAAG,IAAI;YAIlD,MAAM,GAAG,sBAAsB,GAAG,SAAS;IAInD,wBAAwB;aACf,IAAI;CAGd,CAAA"}
|
package/dist/registry.js
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Process-level upload provider registry.
|
|
3
|
+
*
|
|
4
|
+
* `uploadFeature()` registers upload configs here (keyed by a generated id) at
|
|
5
|
+
* feature application time. The NestJS `UploadController` looks up configs by
|
|
6
|
+
* the id stored in the property's `custom.uploadProviderId` field.
|
|
7
|
+
*
|
|
8
|
+
* The registry is intentionally a module-level singleton so it is available
|
|
9
|
+
* before the NestJS DI container is initialised — the same pattern used by
|
|
10
|
+
* `ModernAdminFeatureRegistry` in `@modern-admin/nest`.
|
|
11
|
+
*/
|
|
12
|
+
const _registry = new Map();
|
|
13
|
+
export const UploadProviderRegistry = {
|
|
14
|
+
register(id, config) {
|
|
15
|
+
_registry.set(id, config);
|
|
16
|
+
},
|
|
17
|
+
get(id) {
|
|
18
|
+
return _registry.get(id);
|
|
19
|
+
},
|
|
20
|
+
/** For test cleanup. */
|
|
21
|
+
clear() {
|
|
22
|
+
_registry.clear();
|
|
23
|
+
},
|
|
24
|
+
};
|
|
25
|
+
//# sourceMappingURL=registry.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"registry.js","sourceRoot":"","sources":["../src/registry.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAaH,MAAM,SAAS,GAAG,IAAI,GAAG,EAAkC,CAAA;AAE3D,MAAM,CAAC,MAAM,sBAAsB,GAAG;IACpC,QAAQ,CAAC,EAAU,EAAE,MAA8B;QACjD,SAAS,CAAC,GAAG,CAAC,EAAE,EAAE,MAAM,CAAC,CAAA;IAC3B,CAAC;IAED,GAAG,CAAC,EAAU;QACZ,OAAO,SAAS,CAAC,GAAG,CAAC,EAAE,CAAC,CAAA;IAC1B,CAAC;IAED,wBAAwB;IACxB,KAAK;QACH,SAAS,CAAC,KAAK,EAAE,CAAA;IACnB,CAAC;CACF,CAAA"}
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Core types for the upload feature plugin.
|
|
3
|
+
*
|
|
4
|
+
* `IUploadProvider` is the single port contract that upload backends must
|
|
5
|
+
* implement. `LocalUploadProvider` and `S3UploadProvider` ship as built-in
|
|
6
|
+
* adapters; custom providers only need to implement these four methods.
|
|
7
|
+
*/
|
|
8
|
+
/** Parsed file data received from a multipart request. */
|
|
9
|
+
export interface UploadedFile {
|
|
10
|
+
/** Original filename from the client. */
|
|
11
|
+
originalName: string;
|
|
12
|
+
/** MIME type reported by the client (e.g. 'image/jpeg'). */
|
|
13
|
+
mimeType: string;
|
|
14
|
+
/** File size in bytes. */
|
|
15
|
+
size: number;
|
|
16
|
+
/** Raw file bytes. */
|
|
17
|
+
buffer: Buffer;
|
|
18
|
+
}
|
|
19
|
+
/** Metadata returned by the upload endpoint. */
|
|
20
|
+
export interface UploadedFileInfo {
|
|
21
|
+
/** Storage key (relative path or object key). Stored in the DB field. */
|
|
22
|
+
key: string;
|
|
23
|
+
/** Public URL for browser display / download. */
|
|
24
|
+
url: string;
|
|
25
|
+
/** Original filename. */
|
|
26
|
+
name: string;
|
|
27
|
+
/** Size in bytes. */
|
|
28
|
+
size: number;
|
|
29
|
+
/** MIME type. */
|
|
30
|
+
mimeType: string;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Upload provider port. Implement this interface to add a new storage backend.
|
|
34
|
+
*
|
|
35
|
+
* @example
|
|
36
|
+
* class GcsUploadProvider implements IUploadProvider {
|
|
37
|
+
* async upload(file) { ... }
|
|
38
|
+
* getUrl(key) { ... }
|
|
39
|
+
* async delete(key) { ... }
|
|
40
|
+
* }
|
|
41
|
+
*/
|
|
42
|
+
export interface IUploadProvider {
|
|
43
|
+
/**
|
|
44
|
+
* Upload a file and return its storage key.
|
|
45
|
+
* The key is the value that will be persisted in the database field.
|
|
46
|
+
*
|
|
47
|
+
* @param file Parsed file data from the multipart request.
|
|
48
|
+
* @param key Optional pre-computed storage key (from `uploadPath`). When
|
|
49
|
+
* omitted the provider generates a key internally (UUID + extension).
|
|
50
|
+
*/
|
|
51
|
+
upload(file: UploadedFile, key?: string): Promise<string>;
|
|
52
|
+
/**
|
|
53
|
+
* Compute the public URL for a stored key. May be sync or async.
|
|
54
|
+
* Used both by the upload endpoint (to return the URL) and by the frontend
|
|
55
|
+
* URL template when `urlTemplate()` is not implemented.
|
|
56
|
+
*/
|
|
57
|
+
getUrl(key: string): string | Promise<string>;
|
|
58
|
+
/**
|
|
59
|
+
* Delete the file identified by `key`. Must not throw if the file does not
|
|
60
|
+
* exist (e.g. was already deleted or was never stored).
|
|
61
|
+
*/
|
|
62
|
+
delete(key: string): Promise<void>;
|
|
63
|
+
/**
|
|
64
|
+
* Optional URL template string for the frontend to construct display URLs
|
|
65
|
+
* from stored keys without calling the backend.
|
|
66
|
+
* Use `{key}` as the placeholder, e.g. `'https://cdn.example.com/{key}'`.
|
|
67
|
+
* Return `undefined` (or omit the method) when URLs cannot be statically
|
|
68
|
+
* computed (e.g. signed/pre-signed S3 URLs — each URL is unique and time-limited).
|
|
69
|
+
*/
|
|
70
|
+
urlTemplate?(): string | undefined;
|
|
71
|
+
}
|
|
72
|
+
/** Per-property upload configuration passed to `uploadFeature()`. */
|
|
73
|
+
export interface UploadPropertyConfig {
|
|
74
|
+
/** Storage provider for this property. */
|
|
75
|
+
provider: IUploadProvider;
|
|
76
|
+
/**
|
|
77
|
+
* Allowed MIME type patterns (same syntax as the HTML `accept` attribute).
|
|
78
|
+
* Examples: `['image/*']`, `['image/jpeg', 'application/pdf']`.
|
|
79
|
+
* Enforcement is advisory on the frontend; the controller does not re-validate.
|
|
80
|
+
*/
|
|
81
|
+
mimeTypes?: string[];
|
|
82
|
+
/** Maximum upload size in bytes. Advisory (frontend warning only). */
|
|
83
|
+
maxSize?: number;
|
|
84
|
+
/**
|
|
85
|
+
* Treat the property as an array of file keys (multi-file upload).
|
|
86
|
+
* When true, the property is stored as `string[]`, the editor allows
|
|
87
|
+
* uploading multiple files (a single multipart request can include several),
|
|
88
|
+
* and the action hooks diff arrays on edit and delete every key on delete.
|
|
89
|
+
*/
|
|
90
|
+
isArray?: boolean;
|
|
91
|
+
/**
|
|
92
|
+
* Custom storage key generator. Receives the original filename from the
|
|
93
|
+
* client and returns the key to use for storage.
|
|
94
|
+
*
|
|
95
|
+
* Use this to organise files into sub-directories, include the resource
|
|
96
|
+
* name, add timestamps, etc. The provider's internal UUID generator is
|
|
97
|
+
* used when this is omitted.
|
|
98
|
+
*
|
|
99
|
+
* @example
|
|
100
|
+
* // avatars/2024/01/uuid.jpg
|
|
101
|
+
* uploadPath: (filename) => {
|
|
102
|
+
* const ext = filename.split('.').pop()
|
|
103
|
+
* const d = new Date()
|
|
104
|
+
* return `avatars/${d.getFullYear()}/${String(d.getMonth()+1).padStart(2,'0')}/${uuidv7()}.${ext}`
|
|
105
|
+
* }
|
|
106
|
+
*
|
|
107
|
+
* @example
|
|
108
|
+
* // resource-specific prefix
|
|
109
|
+
* uploadPath: (filename) => `products/images/${uuidv7()}-${filename}`
|
|
110
|
+
*/
|
|
111
|
+
uploadPath?: (filename: string) => string;
|
|
112
|
+
}
|
|
113
|
+
/** Options passed to `uploadFeature()`. */
|
|
114
|
+
export interface UploadFeatureOptions {
|
|
115
|
+
/**
|
|
116
|
+
* Map from property path to its upload configuration.
|
|
117
|
+
* Each entry makes the property a `type: 'file'` field wired to the
|
|
118
|
+
* specified provider.
|
|
119
|
+
*
|
|
120
|
+
* @example
|
|
121
|
+
* uploadFeature({
|
|
122
|
+
* properties: {
|
|
123
|
+
* avatar: { provider: new LocalUploadProvider({ uploadDir: './uploads', baseUrl: '/uploads' }) },
|
|
124
|
+
* resume: { provider: new S3UploadProvider({ bucket: 'my-bucket', region: 'us-east-1' }), mimeTypes: ['application/pdf'] },
|
|
125
|
+
* },
|
|
126
|
+
* })
|
|
127
|
+
*/
|
|
128
|
+
properties: Record<string, UploadPropertyConfig>;
|
|
129
|
+
}
|
|
130
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,0DAA0D;AAC1D,MAAM,WAAW,YAAY;IAC3B,yCAAyC;IACzC,YAAY,EAAE,MAAM,CAAA;IACpB,4DAA4D;IAC5D,QAAQ,EAAE,MAAM,CAAA;IAChB,0BAA0B;IAC1B,IAAI,EAAE,MAAM,CAAA;IACZ,sBAAsB;IACtB,MAAM,EAAE,MAAM,CAAA;CACf;AAED,gDAAgD;AAChD,MAAM,WAAW,gBAAgB;IAC/B,yEAAyE;IACzE,GAAG,EAAE,MAAM,CAAA;IACX,iDAAiD;IACjD,GAAG,EAAE,MAAM,CAAA;IACX,yBAAyB;IACzB,IAAI,EAAE,MAAM,CAAA;IACZ,qBAAqB;IACrB,IAAI,EAAE,MAAM,CAAA;IACZ,iBAAiB;IACjB,QAAQ,EAAE,MAAM,CAAA;CACjB;AAED;;;;;;;;;GASG;AACH,MAAM,WAAW,eAAe;IAC9B;;;;;;;OAOG;IACH,MAAM,CAAC,IAAI,EAAE,YAAY,EAAE,GAAG,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAA;IAEzD;;;;OAIG;IACH,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAA;IAE7C;;;OAGG;IACH,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;IAElC;;;;;;OAMG;IACH,WAAW,CAAC,IAAI,MAAM,GAAG,SAAS,CAAA;CACnC;AAED,qEAAqE;AACrE,MAAM,WAAW,oBAAoB;IACnC,0CAA0C;IAC1C,QAAQ,EAAE,eAAe,CAAA;IACzB;;;;OAIG;IACH,SAAS,CAAC,EAAE,MAAM,EAAE,CAAA;IACpB,sEAAsE;IACtE,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB;;;;;OAKG;IACH,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB;;;;;;;;;;;;;;;;;;;OAmBG;IACH,UAAU,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,MAAM,CAAA;CAC1C;AAED,2CAA2C;AAC3C,MAAM,WAAW,oBAAoB;IACnC;;;;;;;;;;;;OAYG;IACH,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,oBAAoB,CAAC,CAAA;CACjD"}
|
package/dist/types.js
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Core types for the upload feature plugin.
|
|
3
|
+
*
|
|
4
|
+
* `IUploadProvider` is the single port contract that upload backends must
|
|
5
|
+
* implement. `LocalUploadProvider` and `S3UploadProvider` ship as built-in
|
|
6
|
+
* adapters; custom providers only need to implement these four methods.
|
|
7
|
+
*/
|
|
8
|
+
export {};
|
|
9
|
+
//# sourceMappingURL=types.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `uploadFeature` — resource plugin that wires file upload into any resource.
|
|
3
|
+
*
|
|
4
|
+
* Returns a `FeatureFn` that, when applied to a resource's `ResourceOptions`,
|
|
5
|
+
* marks the configured properties as `type: 'file'` (with `isArray` when
|
|
6
|
+
* configured), registers the upload providers in `UploadProviderRegistry`, and
|
|
7
|
+
* installs action hooks that:
|
|
8
|
+
*
|
|
9
|
+
* - on `new.after` / `edit.after` — confirm freshly-uploaded keys against
|
|
10
|
+
* `PendingUploadsRegistry` so the orphan sweeper leaves them alone;
|
|
11
|
+
* - on `edit.after` — delete files whose key was replaced or removed
|
|
12
|
+
* (single-value: old !== new; array: keys present in old but missing
|
|
13
|
+
* from new);
|
|
14
|
+
* - on `delete.after` — delete every file referenced by the deleted record.
|
|
15
|
+
*
|
|
16
|
+
* Hooks are **chained**, not replaced: if the incoming `ResourceOptions`
|
|
17
|
+
* already has hooks (e.g. from another feature), the upload hooks are
|
|
18
|
+
* appended so all hooks run in order.
|
|
19
|
+
*
|
|
20
|
+
* @example
|
|
21
|
+
* uploadFeature({
|
|
22
|
+
* properties: {
|
|
23
|
+
* thumbnail: { provider: localProvider, mimeTypes: ['image/*'] },
|
|
24
|
+
* gallery: { provider: localProvider, isArray: true, mimeTypes: ['image/*'] },
|
|
25
|
+
* },
|
|
26
|
+
* })
|
|
27
|
+
*/
|
|
28
|
+
import { type FeatureFn } from '@modern-admin/core';
|
|
29
|
+
import type { UploadFeatureOptions } from './types.js';
|
|
30
|
+
export declare function uploadFeature(options: UploadFeatureOptions): FeatureFn;
|
|
31
|
+
//# sourceMappingURL=upload-feature.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"upload-feature.d.ts","sourceRoot":"","sources":["../src/upload-feature.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AAEH,OAAO,EAAmD,KAAK,SAAS,EAAwB,MAAM,oBAAoB,CAAA;AAC1H,OAAO,KAAK,EAAE,oBAAoB,EAAwB,MAAM,YAAY,CAAA;AAiD5E,wBAAgB,aAAa,CAAC,OAAO,EAAE,oBAAoB,GAAG,SAAS,CAiItE"}
|
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `uploadFeature` — resource plugin that wires file upload into any resource.
|
|
3
|
+
*
|
|
4
|
+
* Returns a `FeatureFn` that, when applied to a resource's `ResourceOptions`,
|
|
5
|
+
* marks the configured properties as `type: 'file'` (with `isArray` when
|
|
6
|
+
* configured), registers the upload providers in `UploadProviderRegistry`, and
|
|
7
|
+
* installs action hooks that:
|
|
8
|
+
*
|
|
9
|
+
* - on `new.after` / `edit.after` — confirm freshly-uploaded keys against
|
|
10
|
+
* `PendingUploadsRegistry` so the orphan sweeper leaves them alone;
|
|
11
|
+
* - on `edit.after` — delete files whose key was replaced or removed
|
|
12
|
+
* (single-value: old !== new; array: keys present in old but missing
|
|
13
|
+
* from new);
|
|
14
|
+
* - on `delete.after` — delete every file referenced by the deleted record.
|
|
15
|
+
*
|
|
16
|
+
* Hooks are **chained**, not replaced: if the incoming `ResourceOptions`
|
|
17
|
+
* already has hooks (e.g. from another feature), the upload hooks are
|
|
18
|
+
* appended so all hooks run in order.
|
|
19
|
+
*
|
|
20
|
+
* @example
|
|
21
|
+
* uploadFeature({
|
|
22
|
+
* properties: {
|
|
23
|
+
* thumbnail: { provider: localProvider, mimeTypes: ['image/*'] },
|
|
24
|
+
* gallery: { provider: localProvider, isArray: true, mimeTypes: ['image/*'] },
|
|
25
|
+
* },
|
|
26
|
+
* })
|
|
27
|
+
*/
|
|
28
|
+
import { uuidv7 } from '@modern-admin/core';
|
|
29
|
+
import { UploadProviderRegistry } from './registry.js';
|
|
30
|
+
import { PendingUploadsRegistry } from './pending-registry.js';
|
|
31
|
+
/** Normalise a hook value (fn | fn[] | undefined) into an array. */
|
|
32
|
+
function toArray(hook) {
|
|
33
|
+
if (!hook)
|
|
34
|
+
return [];
|
|
35
|
+
return Array.isArray(hook) ? hook : [hook];
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Merge `after` hooks from an existing action override with new hooks,
|
|
39
|
+
* producing an array that runs all of them in order.
|
|
40
|
+
* If `existing` already defines `after`, the new hooks are appended.
|
|
41
|
+
*/
|
|
42
|
+
function mergeAfterHook(existing, newHook) {
|
|
43
|
+
const existing_after = toArray(existing?.after);
|
|
44
|
+
return [...existing_after, newHook];
|
|
45
|
+
}
|
|
46
|
+
// ─── Value helpers ────────────────────────────────────────────────────────────
|
|
47
|
+
/** Return non-empty file keys for the given value (handles single + array). */
|
|
48
|
+
function toKeys(value) {
|
|
49
|
+
if (value == null || value === '')
|
|
50
|
+
return [];
|
|
51
|
+
if (Array.isArray(value)) {
|
|
52
|
+
return value.flatMap((v) => (v == null || v === '' ? [] : [String(v)]));
|
|
53
|
+
}
|
|
54
|
+
return [String(value)];
|
|
55
|
+
}
|
|
56
|
+
// ─── Feature function ─────────────────────────────────────────────────────────
|
|
57
|
+
export function uploadFeature(options) {
|
|
58
|
+
// Register configs immediately — before the FeatureFn is called.
|
|
59
|
+
const registered = new Map();
|
|
60
|
+
for (const [propPath, config] of Object.entries(options.properties)) {
|
|
61
|
+
const providerId = `up_${uuidv7().replace(/-/g, '')}`;
|
|
62
|
+
UploadProviderRegistry.register(providerId, {
|
|
63
|
+
provider: config.provider,
|
|
64
|
+
uploadPath: config.uploadPath,
|
|
65
|
+
isArray: config.isArray ?? false,
|
|
66
|
+
});
|
|
67
|
+
registered.set(propPath, { providerId, config });
|
|
68
|
+
}
|
|
69
|
+
return (resourceOptions) => {
|
|
70
|
+
// --- Property overrides ---
|
|
71
|
+
const propOverrides = {};
|
|
72
|
+
for (const [propPath, { providerId, config }] of registered) {
|
|
73
|
+
// S3 with signed URLs has no static URL template.
|
|
74
|
+
const urlTmpl = config.provider.urlTemplate?.() ?? null;
|
|
75
|
+
propOverrides[propPath] = {
|
|
76
|
+
type: 'file',
|
|
77
|
+
...(config.isArray ? { isArray: true } : {}),
|
|
78
|
+
custom: {
|
|
79
|
+
uploadProviderId: providerId,
|
|
80
|
+
uploadUrlTemplate: urlTmpl,
|
|
81
|
+
uploadMimeTypes: config.mimeTypes ?? null,
|
|
82
|
+
uploadMaxSize: config.maxSize ?? null,
|
|
83
|
+
},
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
// --- Action hooks ---
|
|
87
|
+
// After new: confirm every freshly-uploaded key against the pending registry.
|
|
88
|
+
const newAfterHook = (response, _request, _context) => {
|
|
89
|
+
const rec = response;
|
|
90
|
+
const params = rec.record?.params ?? {};
|
|
91
|
+
const newKeys = [];
|
|
92
|
+
for (const propPath of registered.keys()) {
|
|
93
|
+
newKeys.push(...toKeys(params[propPath]));
|
|
94
|
+
}
|
|
95
|
+
if (newKeys.length > 0)
|
|
96
|
+
PendingUploadsRegistry.confirm(newKeys);
|
|
97
|
+
return response;
|
|
98
|
+
};
|
|
99
|
+
// After edit: delete keys that disappeared and confirm keys that arrived.
|
|
100
|
+
const editAfterHook = async (response, _request, context) => {
|
|
101
|
+
const ctx = context;
|
|
102
|
+
const rec = response;
|
|
103
|
+
const params = rec.record?.params ?? {};
|
|
104
|
+
for (const [propPath, { config }] of registered) {
|
|
105
|
+
const oldKeys = new Set(toKeys(ctx.record?.get(propPath)));
|
|
106
|
+
const newKeys = toKeys(params[propPath]);
|
|
107
|
+
// Confirm new keys (possibly fresh uploads).
|
|
108
|
+
if (newKeys.length > 0)
|
|
109
|
+
PendingUploadsRegistry.confirm(newKeys);
|
|
110
|
+
// Delete keys that were present before and are gone now.
|
|
111
|
+
const newSet = new Set(newKeys);
|
|
112
|
+
for (const k of oldKeys) {
|
|
113
|
+
if (!newSet.has(k)) {
|
|
114
|
+
try {
|
|
115
|
+
await config.provider.delete(k);
|
|
116
|
+
}
|
|
117
|
+
catch {
|
|
118
|
+
// Non-fatal — don't break the action response.
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
return response;
|
|
124
|
+
};
|
|
125
|
+
// After delete: delete every file referenced by the (now-removed) record.
|
|
126
|
+
const deleteAfterHook = async (response, _request, context) => {
|
|
127
|
+
const ctx = context;
|
|
128
|
+
for (const [propPath, { config }] of registered) {
|
|
129
|
+
const keys = toKeys(ctx.record?.get(propPath));
|
|
130
|
+
for (const k of keys) {
|
|
131
|
+
try {
|
|
132
|
+
await config.provider.delete(k);
|
|
133
|
+
}
|
|
134
|
+
catch {
|
|
135
|
+
// Non-fatal.
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
return response;
|
|
140
|
+
};
|
|
141
|
+
// Retrieve any existing action overrides so we can chain, not replace.
|
|
142
|
+
const existingActions = resourceOptions.actions;
|
|
143
|
+
const existingNew = existingActions?.['new'];
|
|
144
|
+
const existingEdit = existingActions?.['edit'];
|
|
145
|
+
const existingDelete = existingActions?.['delete'];
|
|
146
|
+
const actionOverrides = {
|
|
147
|
+
new: {
|
|
148
|
+
...existingNew,
|
|
149
|
+
after: mergeAfterHook(existingNew, newAfterHook),
|
|
150
|
+
},
|
|
151
|
+
edit: {
|
|
152
|
+
...existingEdit,
|
|
153
|
+
after: mergeAfterHook(existingEdit, editAfterHook),
|
|
154
|
+
},
|
|
155
|
+
delete: {
|
|
156
|
+
...existingDelete,
|
|
157
|
+
after: mergeAfterHook(existingDelete, deleteAfterHook),
|
|
158
|
+
},
|
|
159
|
+
};
|
|
160
|
+
return {
|
|
161
|
+
...resourceOptions,
|
|
162
|
+
properties: { ...resourceOptions.properties, ...propOverrides },
|
|
163
|
+
actions: {
|
|
164
|
+
...(resourceOptions.actions ?? {}),
|
|
165
|
+
...actionOverrides,
|
|
166
|
+
},
|
|
167
|
+
};
|
|
168
|
+
};
|
|
169
|
+
}
|
|
170
|
+
//# sourceMappingURL=upload-feature.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"upload-feature.js","sourceRoot":"","sources":["../src/upload-feature.ts"],"names":[],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@modern-admin/feature-upload",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "File upload feature plugin for Modern Admin (local + S3 providers).",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"license": "MIT",
|
|
7
|
+
"repository": {
|
|
8
|
+
"type": "git",
|
|
9
|
+
"url": "https://github.com/modern-admin/modern-admin.git",
|
|
10
|
+
"directory": "packages/feature-upload"
|
|
11
|
+
},
|
|
12
|
+
"main": "./dist/index.js",
|
|
13
|
+
"types": "./dist/index.d.ts",
|
|
14
|
+
"exports": {
|
|
15
|
+
".": {
|
|
16
|
+
"types": "./dist/index.d.ts",
|
|
17
|
+
"default": "./dist/index.js"
|
|
18
|
+
},
|
|
19
|
+
"./nest": {
|
|
20
|
+
"types": "./dist/nest/index.d.ts",
|
|
21
|
+
"default": "./dist/nest/index.js"
|
|
22
|
+
},
|
|
23
|
+
"./graphql": {
|
|
24
|
+
"types": "./dist/graphql.d.ts",
|
|
25
|
+
"default": "./dist/graphql.js"
|
|
26
|
+
}
|
|
27
|
+
},
|
|
28
|
+
"files": [
|
|
29
|
+
"dist",
|
|
30
|
+
"src"
|
|
31
|
+
],
|
|
32
|
+
"publishConfig": {
|
|
33
|
+
"registry": "https://registry.npmjs.org",
|
|
34
|
+
"access": "public",
|
|
35
|
+
"main": "./dist/index.js",
|
|
36
|
+
"types": "./dist/index.d.ts",
|
|
37
|
+
"exports": {
|
|
38
|
+
".": {
|
|
39
|
+
"types": "./dist/index.d.ts",
|
|
40
|
+
"default": "./dist/index.js"
|
|
41
|
+
},
|
|
42
|
+
"./nest": {
|
|
43
|
+
"types": "./dist/nest/index.d.ts",
|
|
44
|
+
"default": "./dist/nest/index.js"
|
|
45
|
+
},
|
|
46
|
+
"./graphql": {
|
|
47
|
+
"types": "./dist/graphql.d.ts",
|
|
48
|
+
"default": "./dist/graphql.js"
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
},
|
|
52
|
+
"dependencies": {
|
|
53
|
+
"@modern-admin/core": "0.1.0",
|
|
54
|
+
"@nestjs/common": "^11.1.19",
|
|
55
|
+
"@nestjs/core": "^11.1.19",
|
|
56
|
+
"busboy": "^1.6.0",
|
|
57
|
+
"reflect-metadata": "^0.2.2",
|
|
58
|
+
"rxjs": "^7.8.2"
|
|
59
|
+
},
|
|
60
|
+
"devDependencies": {
|
|
61
|
+
"@modern-admin/graphql": "0.1.0",
|
|
62
|
+
"@modern-admin/nest": "0.1.0",
|
|
63
|
+
"@modern-admin/tsconfig": "0.1.0",
|
|
64
|
+
"@nestjs/swagger": "^11.4.2",
|
|
65
|
+
"@types/bun": "^1.3.13",
|
|
66
|
+
"@types/busboy": "^1.5.4",
|
|
67
|
+
"graphql": "^16.11.0",
|
|
68
|
+
"typescript": "^6.0.3"
|
|
69
|
+
},
|
|
70
|
+
"peerDependencies": {
|
|
71
|
+
"@aws-sdk/client-s3": "^3.0.0",
|
|
72
|
+
"@modern-admin/graphql": "0.1.0",
|
|
73
|
+
"@modern-admin/nest": "0.1.0",
|
|
74
|
+
"@nestjs/swagger": "^11.4.2",
|
|
75
|
+
"graphql": "^16.0.0"
|
|
76
|
+
},
|
|
77
|
+
"peerDependenciesMeta": {
|
|
78
|
+
"@aws-sdk/client-s3": {
|
|
79
|
+
"optional": true
|
|
80
|
+
},
|
|
81
|
+
"@modern-admin/graphql": {
|
|
82
|
+
"optional": true
|
|
83
|
+
},
|
|
84
|
+
"@modern-admin/nest": {
|
|
85
|
+
"optional": true
|
|
86
|
+
},
|
|
87
|
+
"@nestjs/swagger": {
|
|
88
|
+
"optional": true
|
|
89
|
+
},
|
|
90
|
+
"graphql": {
|
|
91
|
+
"optional": true
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
}
|