@ddd-ts-kit/kernel 0.8.0 → 0.9.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/README.md +69 -0
- package/dist/application/files/accepts-media-type.d.ts +3 -0
- package/dist/application/files/accepts-media-type.d.ts.map +1 -0
- package/dist/application/files/accepts-media-type.js +11 -0
- package/dist/application/files/accepts-media-type.js.map +1 -0
- package/dist/application/files/assert-expiry.d.ts +3 -0
- package/dist/application/files/assert-expiry.d.ts.map +1 -0
- package/dist/application/files/assert-expiry.js +10 -0
- package/dist/application/files/assert-expiry.js.map +1 -0
- package/dist/application/files/assert-file-key.d.ts +3 -0
- package/dist/application/files/assert-file-key.d.ts.map +1 -0
- package/dist/application/files/assert-file-key.js +10 -0
- package/dist/application/files/assert-file-key.js.map +1 -0
- package/dist/application/files/assert-final-key.d.ts +3 -0
- package/dist/application/files/assert-final-key.d.ts.map +1 -0
- package/dist/application/files/assert-final-key.js +11 -0
- package/dist/application/files/assert-final-key.js.map +1 -0
- package/dist/application/files/content-disposition.d.ts +3 -0
- package/dist/application/files/content-disposition.d.ts.map +1 -0
- package/dist/application/files/content-disposition.js +9 -0
- package/dist/application/files/content-disposition.js.map +1 -0
- package/dist/application/files/content-expectation.d.ts +6 -0
- package/dist/application/files/content-expectation.d.ts.map +1 -0
- package/dist/application/files/content-expectation.js +2 -0
- package/dist/application/files/content-expectation.js.map +1 -0
- package/dist/application/files/content-matches.d.ts +7 -0
- package/dist/application/files/content-matches.d.ts.map +1 -0
- package/dist/application/files/content-matches.js +39 -0
- package/dist/application/files/content-matches.js.map +1 -0
- package/dist/application/files/download-url-options.d.ts +7 -0
- package/dist/application/files/download-url-options.d.ts.map +1 -0
- package/dist/application/files/download-url-options.js +2 -0
- package/dist/application/files/download-url-options.js.map +1 -0
- package/dist/application/files/file-content.d.ts +8 -0
- package/dist/application/files/file-content.d.ts.map +1 -0
- package/dist/application/files/file-content.js +2 -0
- package/dist/application/files/file-content.js.map +1 -0
- package/dist/application/files/file-error.d.ts +28 -0
- package/dist/application/files/file-error.d.ts.map +1 -0
- package/dist/application/files/file-error.js +29 -0
- package/dist/application/files/file-error.js.map +1 -0
- package/dist/application/files/file-metadata.d.ts +10 -0
- package/dist/application/files/file-metadata.d.ts.map +1 -0
- package/dist/application/files/file-metadata.js +2 -0
- package/dist/application/files/file-metadata.js.map +1 -0
- package/dist/application/files/file-source.d.ts +4 -0
- package/dist/application/files/file-source.d.ts.map +1 -0
- package/dist/application/files/file-source.js +2 -0
- package/dist/application/files/file-source.js.map +1 -0
- package/dist/application/files/file-upload.d.ts +25 -0
- package/dist/application/files/file-upload.d.ts.map +1 -0
- package/dist/application/files/file-upload.js +36 -0
- package/dist/application/files/file-upload.js.map +1 -0
- package/dist/application/files/index.d.ts +31 -0
- package/dist/application/files/index.d.ts.map +1 -0
- package/dist/application/files/index.js +31 -0
- package/dist/application/files/index.js.map +1 -0
- package/dist/application/files/inspection-limits.d.ts +8 -0
- package/dist/application/files/inspection-limits.d.ts.map +1 -0
- package/dist/application/files/inspection-limits.js +2 -0
- package/dist/application/files/inspection-limits.js.map +1 -0
- package/dist/application/files/is-file-key.d.ts +7 -0
- package/dist/application/files/is-file-key.d.ts.map +1 -0
- package/dist/application/files/is-file-key.js +11 -0
- package/dist/application/files/is-file-key.js.map +1 -0
- package/dist/application/files/listed-file.d.ts +7 -0
- package/dist/application/files/listed-file.d.ts.map +1 -0
- package/dist/application/files/listed-file.js +2 -0
- package/dist/application/files/listed-file.js.map +1 -0
- package/dist/application/files/max-signed-url-seconds.d.ts +3 -0
- package/dist/application/files/max-signed-url-seconds.d.ts.map +1 -0
- package/dist/application/files/max-signed-url-seconds.js +3 -0
- package/dist/application/files/max-signed-url-seconds.js.map +1 -0
- package/dist/application/files/media-type-of.d.ts +3 -0
- package/dist/application/files/media-type-of.d.ts.map +1 -0
- package/dist/application/files/media-type-of.js +5 -0
- package/dist/application/files/media-type-of.js.map +1 -0
- package/dist/application/files/pending-upload-link.d.ts +10 -0
- package/dist/application/files/pending-upload-link.d.ts.map +1 -0
- package/dist/application/files/pending-upload-link.js +2 -0
- package/dist/application/files/pending-upload-link.js.map +1 -0
- package/dist/application/files/pending-upload.d.ts +15 -0
- package/dist/application/files/pending-upload.d.ts.map +1 -0
- package/dist/application/files/pending-upload.js +2 -0
- package/dist/application/files/pending-upload.js.map +1 -0
- package/dist/application/files/put-options.d.ts +7 -0
- package/dist/application/files/put-options.d.ts.map +1 -0
- package/dist/application/files/put-options.js +2 -0
- package/dist/application/files/put-options.js.map +1 -0
- package/dist/application/files/received-file.d.ts +15 -0
- package/dist/application/files/received-file.d.ts.map +1 -0
- package/dist/application/files/received-file.js +2 -0
- package/dist/application/files/received-file.js.map +1 -0
- package/dist/application/files/scan-verdict.d.ts +8 -0
- package/dist/application/files/scan-verdict.d.ts.map +1 -0
- package/dist/application/files/scan-verdict.js +2 -0
- package/dist/application/files/scan-verdict.js.map +1 -0
- package/dist/application/files/signature-of.d.ts +3 -0
- package/dist/application/files/signature-of.d.ts.map +1 -0
- package/dist/application/files/signature-of.js +28 -0
- package/dist/application/files/signature-of.js.map +1 -0
- package/dist/application/files/signed-download.d.ts +6 -0
- package/dist/application/files/signed-download.d.ts.map +1 -0
- package/dist/application/files/signed-download.js +2 -0
- package/dist/application/files/signed-download.js.map +1 -0
- package/dist/application/files/signed-upload.d.ts +9 -0
- package/dist/application/files/signed-upload.d.ts.map +1 -0
- package/dist/application/files/signed-upload.js +2 -0
- package/dist/application/files/signed-upload.js.map +1 -0
- package/dist/application/files/signed-url.d.ts +6 -0
- package/dist/application/files/signed-url.d.ts.map +1 -0
- package/dist/application/files/signed-url.js +2 -0
- package/dist/application/files/signed-url.js.map +1 -0
- package/dist/application/files/staged-key-of.d.ts +5 -0
- package/dist/application/files/staged-key-of.d.ts.map +1 -0
- package/dist/application/files/staged-key-of.js +7 -0
- package/dist/application/files/staged-key-of.js.map +1 -0
- package/dist/application/files/stored-file.d.ts +16 -0
- package/dist/application/files/stored-file.d.ts.map +1 -0
- package/dist/application/files/stored-file.js +2 -0
- package/dist/application/files/stored-file.js.map +1 -0
- package/dist/application/files/upload-url-options.d.ts +12 -0
- package/dist/application/files/upload-url-options.d.ts.map +1 -0
- package/dist/application/files/upload-url-options.js +2 -0
- package/dist/application/files/upload-url-options.js.map +1 -0
- package/dist/application/ports/file-keys.d.ts +9 -0
- package/dist/application/ports/file-keys.d.ts.map +1 -0
- package/dist/application/ports/file-keys.js +10 -0
- package/dist/application/ports/file-keys.js.map +1 -0
- package/dist/application/ports/file-scanner.d.ts +13 -0
- package/dist/application/ports/file-scanner.d.ts.map +1 -0
- package/dist/application/ports/file-scanner.js +12 -0
- package/dist/application/ports/file-scanner.js.map +1 -0
- package/dist/application/ports/file-storage.d.ts +40 -0
- package/dist/application/ports/file-storage.d.ts.map +1 -0
- package/dist/application/ports/file-storage.js +15 -0
- package/dist/application/ports/file-storage.js.map +1 -0
- package/dist/application/ports/served-file-storage.d.ts +16 -0
- package/dist/application/ports/served-file-storage.d.ts.map +1 -0
- package/dist/application/ports/served-file-storage.js +12 -0
- package/dist/application/ports/served-file-storage.js.map +1 -0
- package/dist/index.d.ts +20 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +20 -0
- package/dist/index.js.map +1 -1
- package/dist/infrastructure/domain-events/after-commit.d.ts +10 -0
- package/dist/infrastructure/domain-events/after-commit.d.ts.map +1 -0
- package/dist/infrastructure/domain-events/after-commit.js +19 -0
- package/dist/infrastructure/domain-events/after-commit.js.map +1 -0
- package/dist/infrastructure/domain-events/at-commit.d.ts +11 -0
- package/dist/infrastructure/domain-events/at-commit.d.ts.map +1 -0
- package/dist/infrastructure/domain-events/at-commit.js +19 -0
- package/dist/infrastructure/domain-events/at-commit.js.map +1 -0
- package/dist/infrastructure/domain-events/commit-step.d.ts +10 -0
- package/dist/infrastructure/domain-events/commit-step.d.ts.map +1 -0
- package/dist/infrastructure/domain-events/commit-step.js +2 -0
- package/dist/infrastructure/domain-events/commit-step.js.map +1 -0
- package/dist/infrastructure/domain-events/unit-of-work-scope.d.ts +5 -0
- package/dist/infrastructure/domain-events/unit-of-work-scope.d.ts.map +1 -1
- package/dist/infrastructure/domain-events/unit-of-work-scope.js.map +1 -1
- package/dist/infrastructure/domain-events/within-unit-of-work.d.ts +3 -1
- package/dist/infrastructure/domain-events/within-unit-of-work.d.ts.map +1 -1
- package/dist/infrastructure/domain-events/within-unit-of-work.js +32 -5
- package/dist/infrastructure/domain-events/within-unit-of-work.js.map +1 -1
- package/dist/infrastructure/files/accept-every-file-scanner.d.ts +7 -0
- package/dist/infrastructure/files/accept-every-file-scanner.d.ts.map +1 -0
- package/dist/infrastructure/files/accept-every-file-scanner.js +7 -0
- package/dist/infrastructure/files/accept-every-file-scanner.js.map +1 -0
- package/dist/infrastructure/files/collect.d.ts +4 -0
- package/dist/infrastructure/files/collect.d.ts.map +1 -0
- package/dist/infrastructure/files/collect.js +11 -0
- package/dist/infrastructure/files/collect.js.map +1 -0
- package/dist/infrastructure/files/file-grant.d.ts +11 -0
- package/dist/infrastructure/files/file-grant.d.ts.map +1 -0
- package/dist/infrastructure/files/file-grant.js +2 -0
- package/dist/infrastructure/files/file-grant.js.map +1 -0
- package/dist/infrastructure/files/file-inspection.d.ts +22 -0
- package/dist/infrastructure/files/file-inspection.d.ts.map +1 -0
- package/dist/infrastructure/files/file-inspection.js +66 -0
- package/dist/infrastructure/files/file-inspection.js.map +1 -0
- package/dist/infrastructure/files/file-staging.d.ts +59 -0
- package/dist/infrastructure/files/file-staging.d.ts.map +1 -0
- package/dist/infrastructure/files/file-staging.js +142 -0
- package/dist/infrastructure/files/file-staging.js.map +1 -0
- package/dist/infrastructure/files/file-uploads-middleware.d.ts +11 -0
- package/dist/infrastructure/files/file-uploads-middleware.d.ts.map +1 -0
- package/dist/infrastructure/files/file-uploads-middleware.js +25 -0
- package/dist/infrastructure/files/file-uploads-middleware.js.map +1 -0
- package/dist/infrastructure/files/in-memory-file-storage.d.ts +25 -0
- package/dist/infrastructure/files/in-memory-file-storage.d.ts.map +1 -0
- package/dist/infrastructure/files/in-memory-file-storage.js +73 -0
- package/dist/infrastructure/files/in-memory-file-storage.js.map +1 -0
- package/dist/infrastructure/files/is-file-grant.d.ts +3 -0
- package/dist/infrastructure/files/is-file-grant.d.ts.map +1 -0
- package/dist/infrastructure/files/is-file-grant.js +16 -0
- package/dist/infrastructure/files/is-file-grant.js.map +1 -0
- package/dist/infrastructure/files/is-stored-metadata.d.ts +3 -0
- package/dist/infrastructure/files/is-stored-metadata.d.ts.map +1 -0
- package/dist/infrastructure/files/is-stored-metadata.js +8 -0
- package/dist/infrastructure/files/is-stored-metadata.js.map +1 -0
- package/dist/infrastructure/files/local-file-storage-options.d.ts +6 -0
- package/dist/infrastructure/files/local-file-storage-options.d.ts.map +1 -0
- package/dist/infrastructure/files/local-file-storage-options.js +2 -0
- package/dist/infrastructure/files/local-file-storage-options.js.map +1 -0
- package/dist/infrastructure/files/local-file-storage.d.ts +29 -0
- package/dist/infrastructure/files/local-file-storage.d.ts.map +1 -0
- package/dist/infrastructure/files/local-file-storage.js +103 -0
- package/dist/infrastructure/files/local-file-storage.js.map +1 -0
- package/dist/infrastructure/files/local-paths.d.ts +12 -0
- package/dist/infrastructure/files/local-paths.d.ts.map +1 -0
- package/dist/infrastructure/files/local-paths.js +33 -0
- package/dist/infrastructure/files/local-paths.js.map +1 -0
- package/dist/infrastructure/files/purge-staged-files.d.ts +16 -0
- package/dist/infrastructure/files/purge-staged-files.d.ts.map +1 -0
- package/dist/infrastructure/files/purge-staged-files.js +21 -0
- package/dist/infrastructure/files/purge-staged-files.js.map +1 -0
- package/dist/infrastructure/files/self-signed-file-storage.d.ts +23 -0
- package/dist/infrastructure/files/self-signed-file-storage.d.ts.map +1 -0
- package/dist/infrastructure/files/self-signed-file-storage.js +57 -0
- package/dist/infrastructure/files/self-signed-file-storage.js.map +1 -0
- package/dist/infrastructure/files/signed-file-tokens.d.ts +20 -0
- package/dist/infrastructure/files/signed-file-tokens.d.ts.map +1 -0
- package/dist/infrastructure/files/signed-file-tokens.js +45 -0
- package/dist/infrastructure/files/signed-file-tokens.js.map +1 -0
- package/dist/infrastructure/files/signed-link-options.d.ts +10 -0
- package/dist/infrastructure/files/signed-link-options.d.ts.map +1 -0
- package/dist/infrastructure/files/signed-link-options.js +2 -0
- package/dist/infrastructure/files/signed-link-options.js.map +1 -0
- package/dist/infrastructure/files/stored-metadata.d.ts +6 -0
- package/dist/infrastructure/files/stored-metadata.d.ts.map +1 -0
- package/dist/infrastructure/files/stored-metadata.js +2 -0
- package/dist/infrastructure/files/stored-metadata.js.map +1 -0
- package/dist/infrastructure/files/tenant-file-keys.d.ts +20 -0
- package/dist/infrastructure/files/tenant-file-keys.d.ts.map +1 -0
- package/dist/infrastructure/files/tenant-file-keys.js +27 -0
- package/dist/infrastructure/files/tenant-file-keys.js.map +1 -0
- package/dist/infrastructure/files/upload-desk.d.ts +8 -0
- package/dist/infrastructure/files/upload-desk.d.ts.map +1 -0
- package/dist/infrastructure/files/upload-desk.js +2 -0
- package/dist/infrastructure/files/upload-desk.js.map +1 -0
- package/dist/infrastructure/files/without-trailing-slashes.d.ts +3 -0
- package/dist/infrastructure/files/without-trailing-slashes.d.ts.map +1 -0
- package/dist/infrastructure/files/without-trailing-slashes.js +9 -0
- package/dist/infrastructure/files/without-trailing-slashes.js.map +1 -0
- package/package.json +1 -1
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import type { ContentExpectation } from '../../application/files/content-expectation.js';
|
|
2
|
+
import type { FileSource } from '../../application/files/file-source.js';
|
|
3
|
+
import type { PendingUpload } from '../../application/files/pending-upload.js';
|
|
4
|
+
import type { PendingUploadLink } from '../../application/files/pending-upload-link.js';
|
|
5
|
+
import type { PutOptions } from '../../application/files/put-options.js';
|
|
6
|
+
import type { StoredFile } from '../../application/files/stored-file.js';
|
|
7
|
+
import type { UploadUrlOptions } from '../../application/files/upload-url-options.js';
|
|
8
|
+
import type { ErrorReporter } from '../../application/ports/error-reporter.js';
|
|
9
|
+
import type { FileScanner } from '../../application/ports/file-scanner.js';
|
|
10
|
+
import type { FileStorage } from '../../application/ports/file-storage.js';
|
|
11
|
+
/**
|
|
12
|
+
* Keeps the storage consistent with the database, which a write to the storage cannot join in a
|
|
13
|
+
* transaction. A file is staged first (under `staging/`, scanned, where nothing reads), before
|
|
14
|
+
* the unit of work opens when it comes from a client. The handler records its reference, under
|
|
15
|
+
* its final key, in the aggregate it saves, and asks for `promoteOnCommit`: the file moves to its
|
|
16
|
+
* key as the last step of the transaction, and back to `staging/` if the transaction rolls back.
|
|
17
|
+
* So a committed row never points into `staging/`, and every staged file is an orphan (a refused
|
|
18
|
+
* command, a rollback, an upload never confirmed) that `purge` removes on a schedule.
|
|
19
|
+
*/
|
|
20
|
+
export declare class FileStaging {
|
|
21
|
+
private readonly storage;
|
|
22
|
+
private readonly scanner;
|
|
23
|
+
private readonly reporter;
|
|
24
|
+
constructor(storage: FileStorage, scanner: FileScanner, reporter: ErrorReporter);
|
|
25
|
+
/** Writes the content under the staged key, then has it scanned; a refused file is removed and `FILE_REJECTED` thrown. */
|
|
26
|
+
stage(key: string, content: FileSource, options: PutOptions): Promise<StoredFile>;
|
|
27
|
+
/**
|
|
28
|
+
* A request the client sends the file with, straight to the staged key, and the grant to keep
|
|
29
|
+
* on the server (on the aggregate that awaits the file) for `confirm` to read back.
|
|
30
|
+
*/
|
|
31
|
+
uploadUrl(key: string, options: UploadUrlOptions & Pick<ContentExpectation, 'accepted'>): Promise<PendingUploadLink>;
|
|
32
|
+
/**
|
|
33
|
+
* Reads a file uploaded straight to the staged key of a grant the server kept: its size against
|
|
34
|
+
* the cap of the grant, its media type on its bytes, its checksum, the scan. A file that fails
|
|
35
|
+
* is discarded.
|
|
36
|
+
*/
|
|
37
|
+
confirm(pending: PendingUpload): Promise<StoredFile>;
|
|
38
|
+
/**
|
|
39
|
+
* Moves the staged file to its key as the last step of the unit of work in progress, so that
|
|
40
|
+
* the commit and the file land together: a promotion that fails rolls the command back, and a
|
|
41
|
+
* transaction that rolls back after it returns the file to `staging/`. At once outside of any.
|
|
42
|
+
*/
|
|
43
|
+
promoteOnCommit(key: string): Promise<void>;
|
|
44
|
+
/** Moves the staged file to its key. Promoting twice is not an error; a key staged nowhere and stored nowhere is `FILE_NOT_FOUND`. */
|
|
45
|
+
promote(key: string): Promise<void>;
|
|
46
|
+
/** Deletes a stored file once the unit of work in progress has committed, the one its aggregate no longer references; a failure is reported. */
|
|
47
|
+
deleteAfterCommit(key: string): Promise<void>;
|
|
48
|
+
/** Removes a staged file, one a command will not record. */
|
|
49
|
+
discard(key: string): Promise<void>;
|
|
50
|
+
/**
|
|
51
|
+
* Removes the staged files older than the instant; answers how many. Each is an orphan: no
|
|
52
|
+
* committed row points into `staging/`, since a promotion lands with its commit.
|
|
53
|
+
*/
|
|
54
|
+
purge(olderThan: Date): Promise<number>;
|
|
55
|
+
/** A transaction rolled back after the promotion: the file goes back where the purge finds it; a failure is reported. */
|
|
56
|
+
private returnToStaging;
|
|
57
|
+
private scanned;
|
|
58
|
+
}
|
|
59
|
+
//# sourceMappingURL=file-staging.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"file-staging.d.ts","sourceRoot":"","sources":["../../../src/infrastructure/files/file-staging.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,gDAAgD,CAAC;AAEzF,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,wCAAwC,CAAC;AAEzE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,2CAA2C,CAAC;AAC/E,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,gDAAgD,CAAC;AACxF,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,wCAAwC,CAAC;AAEzE,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,wCAAwC,CAAC;AACzE,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,+CAA+C,CAAC;AACtF,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,2CAA2C,CAAC;AAC/E,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,yCAAyC,CAAC;AAC3E,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,yCAAyC,CAAC;AAK3E;;;;;;;;GAQG;AACH,qBAAa,WAAW;IAMpB,OAAO,CAAC,QAAQ,CAAC,OAAO;IACxB,OAAO,CAAC,QAAQ,CAAC,OAAO;IACxB,OAAO,CAAC,QAAQ,CAAC,QAAQ;IAH3B,YACmB,OAAO,EAAE,WAAW,EACpB,OAAO,EAAE,WAAW,EACpB,QAAQ,EAAE,aAAa,EACtC;IAEJ,0HAA0H;IACpH,KAAK,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,UAAU,EAAE,OAAO,EAAE,UAAU,GAAG,OAAO,CAAC,UAAU,CAAC,CAItF;IAED;;;OAGG;IACG,SAAS,CACb,GAAG,EAAE,MAAM,EACX,OAAO,EAAE,gBAAgB,GAAG,IAAI,CAAC,kBAAkB,EAAE,UAAU,CAAC,GAC/D,OAAO,CAAC,iBAAiB,CAAC,CAU5B;IAED;;;;OAIG;IACG,OAAO,CAAC,OAAO,EAAE,aAAa,GAAG,OAAO,CAAC,UAAU,CAAC,CAqBzD;IAED;;;;OAIG;IACH,eAAe,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAE1C;IAED,sIAAsI;IAChI,OAAO,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAUxC;IAED,gJAAgJ;IAChJ,iBAAiB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAM5C;IAED,4DAA4D;IAC5D,OAAO,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAElC;IAED;;;OAGG;IACG,KAAK,CAAC,SAAS,EAAE,IAAI,GAAG,OAAO,CAAC,MAAM,CAAC,CAW5C;IAED,yHAAyH;YAC3G,eAAe;YAUf,OAAO;CAkBtB"}
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
import { Writable } from 'node:stream';
|
|
2
|
+
import { pipeline } from 'node:stream/promises';
|
|
3
|
+
import { errorReportOf } from '../../application/error-reporting/error-report-of.js';
|
|
4
|
+
import { reportOnce } from '../../application/error-reporting/report-once.js';
|
|
5
|
+
import { assertFinalKey } from '../../application/files/assert-final-key.js';
|
|
6
|
+
import { FileError } from '../../application/files/file-error.js';
|
|
7
|
+
import { mediaTypeOf } from '../../application/files/media-type-of.js';
|
|
8
|
+
import { STAGING_PREFIX, stagedKeyOf } from '../../application/files/staged-key-of.js';
|
|
9
|
+
import { afterCommit } from '../domain-events/after-commit.js';
|
|
10
|
+
import { atCommit } from '../domain-events/at-commit.js';
|
|
11
|
+
import { FileInspection } from './file-inspection.js';
|
|
12
|
+
/**
|
|
13
|
+
* Keeps the storage consistent with the database, which a write to the storage cannot join in a
|
|
14
|
+
* transaction. A file is staged first (under `staging/`, scanned, where nothing reads), before
|
|
15
|
+
* the unit of work opens when it comes from a client. The handler records its reference, under
|
|
16
|
+
* its final key, in the aggregate it saves, and asks for `promoteOnCommit`: the file moves to its
|
|
17
|
+
* key as the last step of the transaction, and back to `staging/` if the transaction rolls back.
|
|
18
|
+
* So a committed row never points into `staging/`, and every staged file is an orphan (a refused
|
|
19
|
+
* command, a rollback, an upload never confirmed) that `purge` removes on a schedule.
|
|
20
|
+
*/
|
|
21
|
+
export class FileStaging {
|
|
22
|
+
storage;
|
|
23
|
+
scanner;
|
|
24
|
+
reporter;
|
|
25
|
+
static {
|
|
26
|
+
Object.defineProperty(this, 'tokenKey', { value: 'kernel.FileStaging' });
|
|
27
|
+
}
|
|
28
|
+
constructor(storage, scanner, reporter) {
|
|
29
|
+
this.storage = storage;
|
|
30
|
+
this.scanner = scanner;
|
|
31
|
+
this.reporter = reporter;
|
|
32
|
+
}
|
|
33
|
+
/** Writes the content under the staged key, then has it scanned; a refused file is removed and `FILE_REJECTED` thrown. */
|
|
34
|
+
async stage(key, content, options) {
|
|
35
|
+
const staged = await this.storage.put(stagedKeyOf(assertFinalKey(key)), content, options);
|
|
36
|
+
return this.scanned({ ...staged, key });
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* A request the client sends the file with, straight to the staged key, and the grant to keep
|
|
40
|
+
* on the server (on the aggregate that awaits the file) for `confirm` to read back.
|
|
41
|
+
*/
|
|
42
|
+
async uploadUrl(key, options) {
|
|
43
|
+
const { expiresInSeconds, mediaType, maxBytes, accepted } = options;
|
|
44
|
+
const link = await this.storage.signedUploadUrl(stagedKeyOf(assertFinalKey(key)), {
|
|
45
|
+
expiresInSeconds,
|
|
46
|
+
mediaType,
|
|
47
|
+
maxBytes,
|
|
48
|
+
});
|
|
49
|
+
return { link, pending: { key, mediaType: mediaTypeOf(mediaType), accepted, maxBytes } };
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Reads a file uploaded straight to the staged key of a grant the server kept: its size against
|
|
53
|
+
* the cap of the grant, its media type on its bytes, its checksum, the scan. A file that fails
|
|
54
|
+
* is discarded.
|
|
55
|
+
*/
|
|
56
|
+
async confirm(pending) {
|
|
57
|
+
const { key, maxBytes, mediaType, accepted } = pending;
|
|
58
|
+
const content = await this.storage.get(stagedKeyOf(assertFinalKey(key)));
|
|
59
|
+
if (content === undefined) {
|
|
60
|
+
throw FileError.notFound(key);
|
|
61
|
+
}
|
|
62
|
+
const inspection = new FileInspection({ maxBytes, expected: { mediaType, accepted } });
|
|
63
|
+
await pipeline(content.stream, inspection, sink()).catch(async (error) => {
|
|
64
|
+
await this.discard(key);
|
|
65
|
+
throw error;
|
|
66
|
+
});
|
|
67
|
+
return this.scanned({
|
|
68
|
+
key,
|
|
69
|
+
size: inspection.size,
|
|
70
|
+
mediaType: mediaTypeOf(mediaType),
|
|
71
|
+
checksum: inspection.checksum,
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Moves the staged file to its key as the last step of the unit of work in progress, so that
|
|
76
|
+
* the commit and the file land together: a promotion that fails rolls the command back, and a
|
|
77
|
+
* transaction that rolls back after it returns the file to `staging/`. At once outside of any.
|
|
78
|
+
*/
|
|
79
|
+
promoteOnCommit(key) {
|
|
80
|
+
return atCommit({ apply: () => this.promote(key), undo: () => this.returnToStaging(key) });
|
|
81
|
+
}
|
|
82
|
+
/** Moves the staged file to its key. Promoting twice is not an error; a key staged nowhere and stored nowhere is `FILE_NOT_FOUND`. */
|
|
83
|
+
async promote(key) {
|
|
84
|
+
if ((await this.storage.stat(stagedKeyOf(assertFinalKey(key)))) !== undefined) {
|
|
85
|
+
await this.storage.move(stagedKeyOf(key), key);
|
|
86
|
+
return;
|
|
87
|
+
}
|
|
88
|
+
if ((await this.storage.stat(key)) === undefined) {
|
|
89
|
+
throw FileError.notFound(key);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
/** Deletes a stored file once the unit of work in progress has committed, the one its aggregate no longer references; a failure is reported. */
|
|
93
|
+
deleteAfterCommit(key) {
|
|
94
|
+
return afterCommit(async () => {
|
|
95
|
+
await this.storage.delete(key).catch((error) => {
|
|
96
|
+
reportOnce(this.reporter, error, errorReportOf(error, { origin: 'process', operation: 'delete stored file' }));
|
|
97
|
+
});
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
/** Removes a staged file, one a command will not record. */
|
|
101
|
+
discard(key) {
|
|
102
|
+
return this.storage.delete(stagedKeyOf(key));
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* Removes the staged files older than the instant; answers how many. Each is an orphan: no
|
|
106
|
+
* committed row points into `staging/`, since a promotion lands with its commit.
|
|
107
|
+
*/
|
|
108
|
+
async purge(olderThan) {
|
|
109
|
+
let purged = 0;
|
|
110
|
+
for await (const file of this.storage.list(STAGING_PREFIX)) {
|
|
111
|
+
if (file.lastModified < olderThan) {
|
|
112
|
+
await this.storage.delete(file.key);
|
|
113
|
+
purged += 1;
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
return purged;
|
|
117
|
+
}
|
|
118
|
+
/** A transaction rolled back after the promotion: the file goes back where the purge finds it; a failure is reported. */
|
|
119
|
+
async returnToStaging(key) {
|
|
120
|
+
await this.storage.move(key, stagedKeyOf(key)).catch((error) => {
|
|
121
|
+
reportOnce(this.reporter, error, errorReportOf(error, { origin: 'process', operation: 'return file to staging' }));
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
async scanned(file) {
|
|
125
|
+
const verdict = await this.scanner.scan(file, async () => {
|
|
126
|
+
const content = await this.storage.get(stagedKeyOf(file.key));
|
|
127
|
+
if (content === undefined) {
|
|
128
|
+
throw FileError.notFound(file.key);
|
|
129
|
+
}
|
|
130
|
+
return content.stream;
|
|
131
|
+
});
|
|
132
|
+
if (!verdict.accepted) {
|
|
133
|
+
await this.discard(file.key);
|
|
134
|
+
throw FileError.rejected(file.key, verdict.reason);
|
|
135
|
+
}
|
|
136
|
+
return file;
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
function sink() {
|
|
140
|
+
return new Writable({ write: (_chunk, _encoding, done) => done() });
|
|
141
|
+
}
|
|
142
|
+
//# sourceMappingURL=file-staging.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"file-staging.js","sourceRoot":"","sources":["../../../src/infrastructure/files/file-staging.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { BusMiddleware } from '../../application/messaging/bus-middleware.js';
|
|
2
|
+
import type { UploadDesk } from './upload-desk.js';
|
|
3
|
+
/**
|
|
4
|
+
* Stages the `FileUpload` fields of a command, each under a new key of its area, scanned, then
|
|
5
|
+
* hands over to the next middleware. Installed after the permission check, so a refused actor
|
|
6
|
+
* stores nothing, and before the unit of work (and the audit entry that opens it), so that no
|
|
7
|
+
* transaction waits while a client uploads. `desk` is resolved only for a command that carries
|
|
8
|
+
* a file: building the bus opens nothing.
|
|
9
|
+
*/
|
|
10
|
+
export declare function fileUploadsMiddleware(desk: () => UploadDesk): BusMiddleware;
|
|
11
|
+
//# sourceMappingURL=file-uploads-middleware.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"file-uploads-middleware.d.ts","sourceRoot":"","sources":["../../../src/infrastructure/files/file-uploads-middleware.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,+CAA+C,CAAC;AAEnF,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAEnD;;;;;;GAMG;AACH,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,MAAM,UAAU,GAAG,aAAa,CAgB3E"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { FileUpload } from '../../application/files/file-upload.js';
|
|
2
|
+
/**
|
|
3
|
+
* Stages the `FileUpload` fields of a command, each under a new key of its area, scanned, then
|
|
4
|
+
* hands over to the next middleware. Installed after the permission check, so a refused actor
|
|
5
|
+
* stores nothing, and before the unit of work (and the audit entry that opens it), so that no
|
|
6
|
+
* transaction waits while a client uploads. `desk` is resolved only for a command that carries
|
|
7
|
+
* a file: building the bus opens nothing.
|
|
8
|
+
*/
|
|
9
|
+
export function fileUploadsMiddleware(desk) {
|
|
10
|
+
return async (message, next, info) => {
|
|
11
|
+
const uploads = info.kind === 'command' ? waitingUploadsOf(message) : [];
|
|
12
|
+
if (uploads.length > 0) {
|
|
13
|
+
const { keys, staging } = desk();
|
|
14
|
+
for (const upload of uploads) {
|
|
15
|
+
const { stream, mediaType } = upload.received;
|
|
16
|
+
upload.stagedAs(await staging.stage(keys.next(upload.area), stream, { mediaType }));
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
return next();
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
function waitingUploadsOf(message) {
|
|
23
|
+
return Object.values(message).filter((value) => value instanceof FileUpload && !value.isStaged);
|
|
24
|
+
}
|
|
25
|
+
//# sourceMappingURL=file-uploads-middleware.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"file-uploads-middleware.js","sourceRoot":"","sources":["../../../src/infrastructure/files/file-uploads-middleware.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,wCAAwC,CAAC;AAKpE;;;;;;GAMG;AACH,MAAM,UAAU,qBAAqB,CAAC,IAAsB;IAC1D,OAAO,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,EAAE;QACnC,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,gBAAgB,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;QAEzE,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACvB,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,GAAG,IAAI,EAAE,CAAC;YAEjC,KAAK,MAAM,MAAM,IAAI,OAAO,EAAE,CAAC;gBAC7B,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,GAAG,MAAM,CAAC,QAAQ,CAAC;gBAE9C,MAAM,CAAC,QAAQ,CAAC,MAAM,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,EAAE,SAAS,EAAE,CAAC,CAAC,CAAC;YACtF,CAAC;QACH,CAAC;QAED,OAAO,IAAI,EAAE,CAAC;IAChB,CAAC,CAAC;AACJ,CAAC;AAED,SAAS,gBAAgB,CAAC,OAAgB;IACxC,OAAO,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC,CAAC,KAAK,EAAuB,EAAE,CAAC,KAAK,YAAY,UAAU,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;AACvH,CAAC"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import type { FileContent } from '../../application/files/file-content.js';
|
|
2
|
+
import type { FileMetadata } from '../../application/files/file-metadata.js';
|
|
3
|
+
import type { FileSource } from '../../application/files/file-source.js';
|
|
4
|
+
import type { ListedFile } from '../../application/files/listed-file.js';
|
|
5
|
+
import type { PutOptions } from '../../application/files/put-options.js';
|
|
6
|
+
import type { StoredFile } from '../../application/files/stored-file.js';
|
|
7
|
+
import type { SignedLinkOptions } from './signed-link-options.js';
|
|
8
|
+
import { SelfSignedFileStorage } from './self-signed-file-storage.js';
|
|
9
|
+
/** The storage of the tests: files in a map, the same contract as every connector, links served by the application. */
|
|
10
|
+
export declare class InMemoryFileStorage extends SelfSignedFileStorage {
|
|
11
|
+
private readonly files;
|
|
12
|
+
private readonly clock;
|
|
13
|
+
constructor(options?: SignedLinkOptions);
|
|
14
|
+
/** The keys held, sorted: what a test asserts about the storage, for instance that a rollback left none. */
|
|
15
|
+
keys(): readonly string[];
|
|
16
|
+
put(key: string, content: FileSource, options: PutOptions): Promise<StoredFile>;
|
|
17
|
+
get(key: string): Promise<FileContent | undefined>;
|
|
18
|
+
stat(key: string): Promise<FileMetadata | undefined>;
|
|
19
|
+
delete(key: string): Promise<void>;
|
|
20
|
+
copy(from: string, to: string): Promise<void>;
|
|
21
|
+
move(from: string, to: string): Promise<void>;
|
|
22
|
+
list(prefix: string): AsyncIterable<ListedFile>;
|
|
23
|
+
private held;
|
|
24
|
+
}
|
|
25
|
+
//# sourceMappingURL=in-memory-file-storage.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"in-memory-file-storage.d.ts","sourceRoot":"","sources":["../../../src/infrastructure/files/in-memory-file-storage.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,yCAAyC,CAAC;AAG3E,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,0CAA0C,CAAC;AAC7E,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,wCAAwC,CAAC;AACzE,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,wCAAwC,CAAC;AAEzE,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,wCAAwC,CAAC;AACzE,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,wCAAwC,CAAC;AAKzE,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAClE,OAAO,EAAE,qBAAqB,EAAE,MAAM,+BAA+B,CAAC;AAOtE,uHAAuH;AACvH,qBAAa,mBAAoB,SAAQ,qBAAqB;IAC5D,OAAO,CAAC,QAAQ,CAAC,KAAK,CAA2B;IAEjD,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAQ;IAE9B,YAAY,OAAO,GAAE,iBAAsB,EAG1C;IAED,4GAA4G;IAC5G,IAAI,IAAI,SAAS,MAAM,EAAE,CAExB;IAEK,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,UAAU,EAAE,OAAO,EAAE,UAAU,GAAG,OAAO,CAAC,UAAU,CAAC,CAgBpF;IAED,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,GAAG,SAAS,CAAC,CAMjD;IAED,IAAI,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,GAAG,SAAS,CAAC,CAEnD;IAED,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAIjC;IAED,IAAI,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAS5C;IAEK,IAAI,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAMlD;IAEM,IAAI,CAAC,MAAM,EAAE,MAAM,GAAG,aAAa,CAAC,UAAU,CAAC,CAIrD;IAED,OAAO,CAAC,IAAI;CASb"}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import { Readable } from 'node:stream';
|
|
2
|
+
import { pipeline } from 'node:stream/promises';
|
|
3
|
+
import { FileError } from '../../application/files/file-error.js';
|
|
4
|
+
import { assertFileKey } from '../../application/files/assert-file-key.js';
|
|
5
|
+
import { mediaTypeOf } from '../../application/files/media-type-of.js';
|
|
6
|
+
import { SystemClock } from '../clock/system-clock.js';
|
|
7
|
+
import { collect } from './collect.js';
|
|
8
|
+
import { FileInspection } from './file-inspection.js';
|
|
9
|
+
import { SelfSignedFileStorage } from './self-signed-file-storage.js';
|
|
10
|
+
/** The storage of the tests: files in a map, the same contract as every connector, links served by the application. */
|
|
11
|
+
export class InMemoryFileStorage extends SelfSignedFileStorage {
|
|
12
|
+
files = new Map();
|
|
13
|
+
clock;
|
|
14
|
+
constructor(options = {}) {
|
|
15
|
+
super(options);
|
|
16
|
+
this.clock = options.clock ?? new SystemClock();
|
|
17
|
+
}
|
|
18
|
+
/** The keys held, sorted: what a test asserts about the storage, for instance that a rollback left none. */
|
|
19
|
+
keys() {
|
|
20
|
+
return [...this.files.keys()].sort();
|
|
21
|
+
}
|
|
22
|
+
async put(key, content, options) {
|
|
23
|
+
assertFileKey(key);
|
|
24
|
+
const inspection = new FileInspection(options.maxBytes === undefined ? {} : { maxBytes: options.maxBytes });
|
|
25
|
+
const chunks = [];
|
|
26
|
+
await pipeline(content, inspection, collect(chunks));
|
|
27
|
+
const { size, checksum } = inspection;
|
|
28
|
+
const mediaType = mediaTypeOf(options.mediaType);
|
|
29
|
+
this.files.set(key, {
|
|
30
|
+
bytes: Buffer.concat(chunks),
|
|
31
|
+
metadata: { key, size, mediaType, checksum, lastModified: this.clock.now() },
|
|
32
|
+
});
|
|
33
|
+
return { key, size, mediaType, checksum };
|
|
34
|
+
}
|
|
35
|
+
get(key) {
|
|
36
|
+
const held = this.files.get(assertFileKey(key));
|
|
37
|
+
return Promise.resolve(held === undefined ? undefined : { metadata: held.metadata, stream: Readable.from([held.bytes]) });
|
|
38
|
+
}
|
|
39
|
+
stat(key) {
|
|
40
|
+
return Promise.resolve(this.files.get(assertFileKey(key))?.metadata);
|
|
41
|
+
}
|
|
42
|
+
delete(key) {
|
|
43
|
+
this.files.delete(assertFileKey(key));
|
|
44
|
+
return Promise.resolve();
|
|
45
|
+
}
|
|
46
|
+
copy(from, to) {
|
|
47
|
+
const held = this.held(from);
|
|
48
|
+
this.files.set(assertFileKey(to), {
|
|
49
|
+
bytes: held.bytes,
|
|
50
|
+
metadata: { ...held.metadata, key: to, lastModified: this.clock.now() },
|
|
51
|
+
});
|
|
52
|
+
return Promise.resolve();
|
|
53
|
+
}
|
|
54
|
+
async move(from, to) {
|
|
55
|
+
await this.copy(from, to);
|
|
56
|
+
if (from !== to) {
|
|
57
|
+
this.files.delete(from);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
async *list(prefix) {
|
|
61
|
+
for (const { metadata } of [...this.files.values()].filter((held) => held.metadata.key.startsWith(prefix))) {
|
|
62
|
+
yield { key: metadata.key, size: metadata.size, lastModified: metadata.lastModified };
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
held(key) {
|
|
66
|
+
const held = this.files.get(assertFileKey(key));
|
|
67
|
+
if (held === undefined) {
|
|
68
|
+
throw FileError.notFound(key);
|
|
69
|
+
}
|
|
70
|
+
return held;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
//# sourceMappingURL=in-memory-file-storage.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"in-memory-file-storage.js","sourceRoot":"","sources":["../../../src/infrastructure/files/in-memory-file-storage.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AACvC,OAAO,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAEhD,OAAO,EAAE,SAAS,EAAE,MAAM,uCAAuC,CAAC;AAClE,OAAO,EAAE,aAAa,EAAE,MAAM,4CAA4C,CAAC;AAI3E,OAAO,EAAE,WAAW,EAAE,MAAM,0CAA0C,CAAC;AAIvE,OAAO,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AACvD,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AACvC,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAEtD,OAAO,EAAE,qBAAqB,EAAE,MAAM,+BAA+B,CAAC;AAOtE,uHAAuH;AACvH,MAAM,OAAO,mBAAoB,SAAQ,qBAAqB;IAC3C,KAAK,GAAG,IAAI,GAAG,EAAgB,CAAC;IAEhC,KAAK,CAAQ;IAE9B,YAAY,OAAO,GAAsB,EAAE;QACzC,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,KAAK,GAAG,OAAO,CAAC,KAAK,IAAI,IAAI,WAAW,EAAE,CAAC;IAClD,CAAC;IAED,4GAA4G;IAC5G,IAAI;QACF,OAAO,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC;IACvC,CAAC;IAED,KAAK,CAAC,GAAG,CAAC,GAAW,EAAE,OAAmB,EAAE,OAAmB;QAC7D,aAAa,CAAC,GAAG,CAAC,CAAC;QACnB,MAAM,UAAU,GAAG,IAAI,cAAc,CAAC,OAAO,CAAC,QAAQ,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,OAAO,CAAC,QAAQ,EAAE,CAAC,CAAC;QAC5G,MAAM,MAAM,GAAa,EAAE,CAAC;QAE5B,MAAM,QAAQ,CAAC,OAAO,EAAE,UAAU,EAAE,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC;QAErD,MAAM,EAAE,IAAI,EAAE,QAAQ,EAAE,GAAG,UAAU,CAAC;QACtC,MAAM,SAAS,GAAG,WAAW,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;QAEjD,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,EAAE;YAClB,KAAK,EAAE,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC;YAC5B,QAAQ,EAAE,EAAE,GAAG,EAAE,IAAI,EAAE,SAAS,EAAE,QAAQ,EAAE,YAAY,EAAE,IAAI,CAAC,KAAK,CAAC,GAAG,EAAE,EAAE;SAC7E,CAAC,CAAC;QAEH,OAAO,EAAE,GAAG,EAAE,IAAI,EAAE,SAAS,EAAE,QAAQ,EAAE,CAAC;IAC5C,CAAC;IAED,GAAG,CAAC,GAAW;QACb,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,aAAa,CAAC,GAAG,CAAC,CAAC,CAAC;QAEhD,OAAO,OAAO,CAAC,OAAO,CACpB,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,IAAI,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,CAClG,CAAC;IACJ,CAAC;IAED,IAAI,CAAC,GAAW;QACd,OAAO,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,aAAa,CAAC,GAAG,CAAC,CAAC,EAAE,QAAQ,CAAC,CAAC;IACvE,CAAC;IAED,MAAM,CAAC,GAAW;QAChB,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,aAAa,CAAC,GAAG,CAAC,CAAC,CAAC;QAEtC,OAAO,OAAO,CAAC,OAAO,EAAE,CAAC;IAC3B,CAAC;IAED,IAAI,CAAC,IAAY,EAAE,EAAU;QAC3B,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAE7B,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,aAAa,CAAC,EAAE,CAAC,EAAE;YAChC,KAAK,EAAE,IAAI,CAAC,KAAK;YACjB,QAAQ,EAAE,EAAE,GAAG,IAAI,CAAC,QAAQ,EAAE,GAAG,EAAE,EAAE,EAAE,YAAY,EAAE,IAAI,CAAC,KAAK,CAAC,GAAG,EAAE,EAAE;SACxE,CAAC,CAAC;QAEH,OAAO,OAAO,CAAC,OAAO,EAAE,CAAC;IAC3B,CAAC;IAED,KAAK,CAAC,IAAI,CAAC,IAAY,EAAE,EAAU;QACjC,MAAM,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;QAE1B,IAAI,IAAI,KAAK,EAAE,EAAE,CAAC;YAChB,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;QAC1B,CAAC;IACH,CAAC;IAED,KAAK,CAAC,CAAC,IAAI,CAAC,MAAc;QACxB,KAAK,MAAM,EAAE,QAAQ,EAAE,IAAI,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC;YAC3G,MAAM,EAAE,GAAG,EAAE,QAAQ,CAAC,GAAG,EAAE,IAAI,EAAE,QAAQ,CAAC,IAAI,EAAE,YAAY,EAAE,QAAQ,CAAC,YAAY,EAAE,CAAC;QACxF,CAAC;IACH,CAAC;IAEO,IAAI,CAAC,GAAW;QACtB,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,aAAa,CAAC,GAAG,CAAC,CAAC,CAAC;QAEhD,IAAI,IAAI,KAAK,SAAS,EAAE,CAAC;YACvB,MAAM,SAAS,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC;QAChC,CAAC;QAED,OAAO,IAAI,CAAC;IACd,CAAC;CACF"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"is-file-grant.d.ts","sourceRoot":"","sources":["../../../src/infrastructure/files/is-file-grant.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAEjD,wBAAgB,WAAW,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,SAAS,CAe9D"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
export function isFileGrant(value) {
|
|
2
|
+
if (typeof value !== 'object' || value === null) {
|
|
3
|
+
return false;
|
|
4
|
+
}
|
|
5
|
+
const grant = value;
|
|
6
|
+
return ((grant.action === 'download' || grant.action === 'upload') &&
|
|
7
|
+
typeof grant.key === 'string' &&
|
|
8
|
+
typeof grant.expiresAt === 'number' &&
|
|
9
|
+
optionalString(grant.fileName) &&
|
|
10
|
+
optionalString(grant.mediaType) &&
|
|
11
|
+
(grant.maxBytes === undefined || typeof grant.maxBytes === 'number'));
|
|
12
|
+
}
|
|
13
|
+
function optionalString(value) {
|
|
14
|
+
return value === undefined || typeof value === 'string';
|
|
15
|
+
}
|
|
16
|
+
//# sourceMappingURL=is-file-grant.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"is-file-grant.js","sourceRoot":"","sources":["../../../src/infrastructure/files/is-file-grant.ts"],"names":[],"mappings":"AAEA,MAAM,UAAU,WAAW,CAAC,KAAc;IACxC,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI,EAAE,CAAC;QAChD,OAAO,KAAK,CAAC;IACf,CAAC;IAED,MAAM,KAAK,GAA8C,KAAK,CAAC;IAE/D,OAAO,CACL,CAAC,KAAK,CAAC,MAAM,KAAK,UAAU,IAAI,KAAK,CAAC,MAAM,KAAK,QAAQ,CAAC;QAC1D,OAAO,KAAK,CAAC,GAAG,KAAK,QAAQ;QAC7B,OAAO,KAAK,CAAC,SAAS,KAAK,QAAQ;QACnC,cAAc,CAAC,KAAK,CAAC,QAAQ,CAAC;QAC9B,cAAc,CAAC,KAAK,CAAC,SAAS,CAAC;QAC/B,CAAC,KAAK,CAAC,QAAQ,KAAK,SAAS,IAAI,OAAO,KAAK,CAAC,QAAQ,KAAK,QAAQ,CAAC,CACrE,CAAC;AACJ,CAAC;AAED,SAAS,cAAc,CAAC,KAAc;IACpC,OAAO,KAAK,KAAK,SAAS,IAAI,OAAO,KAAK,KAAK,QAAQ,CAAC;AAC1D,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"is-stored-metadata.d.ts","sourceRoot":"","sources":["../../../src/infrastructure/files/is-stored-metadata.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAE3D,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,cAAc,CAQxE"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export function isStoredMetadata(value) {
|
|
2
|
+
if (typeof value !== 'object' || value === null) {
|
|
3
|
+
return false;
|
|
4
|
+
}
|
|
5
|
+
const metadata = value;
|
|
6
|
+
return typeof metadata.mediaType === 'string' && typeof metadata.checksum === 'string';
|
|
7
|
+
}
|
|
8
|
+
//# sourceMappingURL=is-stored-metadata.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"is-stored-metadata.js","sourceRoot":"","sources":["../../../src/infrastructure/files/is-stored-metadata.ts"],"names":[],"mappings":"AAEA,MAAM,UAAU,gBAAgB,CAAC,KAAc;IAC7C,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI,EAAE,CAAC;QAChD,OAAO,KAAK,CAAC;IACf,CAAC;IAED,MAAM,QAAQ,GAAmD,KAAK,CAAC;IAEvE,OAAO,OAAO,QAAQ,CAAC,SAAS,KAAK,QAAQ,IAAI,OAAO,QAAQ,CAAC,QAAQ,KAAK,QAAQ,CAAC;AACzF,CAAC"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { SignedLinkOptions } from './signed-link-options.js';
|
|
2
|
+
export interface LocalFileStorageOptions extends SignedLinkOptions {
|
|
3
|
+
/** The directory that holds the files, created when missing. Keep it out of version control. */
|
|
4
|
+
readonly directory: string;
|
|
5
|
+
}
|
|
6
|
+
//# sourceMappingURL=local-file-storage-options.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"local-file-storage-options.d.ts","sourceRoot":"","sources":["../../../src/infrastructure/files/local-file-storage-options.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAElE,MAAM,WAAW,uBAAwB,SAAQ,iBAAiB;IAChE,gGAAgG;IAChG,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;CAC5B"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"local-file-storage-options.js","sourceRoot":"","sources":["../../../src/infrastructure/files/local-file-storage-options.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import type { FileContent } from '../../application/files/file-content.js';
|
|
2
|
+
import type { FileMetadata } from '../../application/files/file-metadata.js';
|
|
3
|
+
import type { FileSource } from '../../application/files/file-source.js';
|
|
4
|
+
import type { ListedFile } from '../../application/files/listed-file.js';
|
|
5
|
+
import type { PutOptions } from '../../application/files/put-options.js';
|
|
6
|
+
import type { StoredFile } from '../../application/files/stored-file.js';
|
|
7
|
+
import type { LocalFileStorageOptions } from './local-file-storage-options.js';
|
|
8
|
+
import { SelfSignedFileStorage } from './self-signed-file-storage.js';
|
|
9
|
+
/**
|
|
10
|
+
* The storage of development: a directory, each file under its key and what the file system does
|
|
11
|
+
* not know beside it in `.metadata/`. A write goes to `.incoming/` first and is renamed into place,
|
|
12
|
+
* so a failed or refused write leaves nothing under its key. One machine only: in a deployment
|
|
13
|
+
* with several instances, use an object store.
|
|
14
|
+
*/
|
|
15
|
+
export declare class LocalFileStorage extends SelfSignedFileStorage {
|
|
16
|
+
private readonly paths;
|
|
17
|
+
constructor(options: LocalFileStorageOptions);
|
|
18
|
+
put(key: string, content: FileSource, options: PutOptions): Promise<StoredFile>;
|
|
19
|
+
get(key: string): Promise<FileContent | undefined>;
|
|
20
|
+
stat(key: string): Promise<FileMetadata | undefined>;
|
|
21
|
+
delete(key: string): Promise<void>;
|
|
22
|
+
copy(from: string, to: string): Promise<void>;
|
|
23
|
+
move(from: string, to: string): Promise<void>;
|
|
24
|
+
list(prefix: string): AsyncIterable<ListedFile>;
|
|
25
|
+
private existing;
|
|
26
|
+
private readMetadata;
|
|
27
|
+
private writeMetadata;
|
|
28
|
+
}
|
|
29
|
+
//# sourceMappingURL=local-file-storage.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"local-file-storage.d.ts","sourceRoot":"","sources":["../../../src/infrastructure/files/local-file-storage.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,yCAAyC,CAAC;AAE3E,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,0CAA0C,CAAC;AAC7E,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,wCAAwC,CAAC;AACzE,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,wCAAwC,CAAC;AAEzE,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,wCAAwC,CAAC;AACzE,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,wCAAwC,CAAC;AAEzE,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,iCAAiC,CAAC;AAI/E,OAAO,EAAE,qBAAqB,EAAE,MAAM,+BAA+B,CAAC;AAEtE;;;;;GAKG;AACH,qBAAa,gBAAiB,SAAQ,qBAAqB;IACzD,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAa;IAEnC,YAAY,OAAO,EAAE,uBAAuB,EAG3C;IAEK,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,UAAU,EAAE,OAAO,EAAE,UAAU,GAAG,OAAO,CAAC,UAAU,CAAC,CAuBpF;IAEK,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,GAAG,SAAS,CAAC,CAIvD;IAEK,IAAI,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,GAAG,SAAS,CAAC,CAUzD;IAEK,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAGvC;IAEK,IAAI,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAKlD;IAEK,IAAI,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAQlD;IAEM,IAAI,CAAC,MAAM,EAAE,MAAM,GAAG,aAAa,CAAC,UAAU,CAAC,CAYrD;YAEa,QAAQ;YAMR,YAAY;YAOZ,aAAa;CAO5B"}
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import { createReadStream, createWriteStream } from 'node:fs';
|
|
2
|
+
import fs from 'node:fs/promises';
|
|
3
|
+
import path from 'node:path';
|
|
4
|
+
import { pipeline } from 'node:stream/promises';
|
|
5
|
+
import { FileError } from '../../application/files/file-error.js';
|
|
6
|
+
import { mediaTypeOf } from '../../application/files/media-type-of.js';
|
|
7
|
+
import { FileInspection } from './file-inspection.js';
|
|
8
|
+
import { LocalPaths } from './local-paths.js';
|
|
9
|
+
import { isStoredMetadata } from './is-stored-metadata.js';
|
|
10
|
+
import { SelfSignedFileStorage } from './self-signed-file-storage.js';
|
|
11
|
+
/**
|
|
12
|
+
* The storage of development: a directory, each file under its key and what the file system does
|
|
13
|
+
* not know beside it in `.metadata/`. A write goes to `.incoming/` first and is renamed into place,
|
|
14
|
+
* so a failed or refused write leaves nothing under its key. One machine only: in a deployment
|
|
15
|
+
* with several instances, use an object store.
|
|
16
|
+
*/
|
|
17
|
+
export class LocalFileStorage extends SelfSignedFileStorage {
|
|
18
|
+
paths;
|
|
19
|
+
constructor(options) {
|
|
20
|
+
super(options);
|
|
21
|
+
this.paths = new LocalPaths(options.directory);
|
|
22
|
+
}
|
|
23
|
+
async put(key, content, options) {
|
|
24
|
+
const target = this.paths.contentOf(key);
|
|
25
|
+
const incoming = this.paths.incoming();
|
|
26
|
+
const inspection = new FileInspection(options.maxBytes === undefined ? {} : { maxBytes: options.maxBytes });
|
|
27
|
+
await fs.mkdir(path.dirname(incoming), { recursive: true });
|
|
28
|
+
await pipeline(content, inspection, createWriteStream(incoming)).catch(async (error) => {
|
|
29
|
+
await fs.rm(incoming, { force: true });
|
|
30
|
+
throw error;
|
|
31
|
+
});
|
|
32
|
+
const stored = {
|
|
33
|
+
key,
|
|
34
|
+
size: inspection.size,
|
|
35
|
+
mediaType: mediaTypeOf(options.mediaType),
|
|
36
|
+
checksum: inspection.checksum,
|
|
37
|
+
};
|
|
38
|
+
await this.writeMetadata(key, stored);
|
|
39
|
+
await placed(incoming, target);
|
|
40
|
+
return stored;
|
|
41
|
+
}
|
|
42
|
+
async get(key) {
|
|
43
|
+
const metadata = await this.stat(key);
|
|
44
|
+
return metadata === undefined ? undefined : { metadata, stream: createReadStream(this.paths.contentOf(key)) };
|
|
45
|
+
}
|
|
46
|
+
async stat(key) {
|
|
47
|
+
const found = await fs.stat(this.paths.contentOf(key)).catch(() => undefined);
|
|
48
|
+
if (found?.isFile() !== true) {
|
|
49
|
+
return undefined;
|
|
50
|
+
}
|
|
51
|
+
const { mediaType, checksum } = await this.readMetadata(key);
|
|
52
|
+
return { key, size: found.size, mediaType, lastModified: found.mtime, ...(checksum === '' ? {} : { checksum }) };
|
|
53
|
+
}
|
|
54
|
+
async delete(key) {
|
|
55
|
+
await fs.rm(this.paths.contentOf(key), { force: true });
|
|
56
|
+
await fs.rm(this.paths.metadataOf(key), { force: true });
|
|
57
|
+
}
|
|
58
|
+
async copy(from, to) {
|
|
59
|
+
await this.existing(from);
|
|
60
|
+
await this.writeMetadata(to, await this.readMetadata(from));
|
|
61
|
+
await fs.mkdir(path.dirname(this.paths.contentOf(to)), { recursive: true });
|
|
62
|
+
await fs.copyFile(this.paths.contentOf(from), this.paths.contentOf(to));
|
|
63
|
+
}
|
|
64
|
+
async move(from, to) {
|
|
65
|
+
await this.existing(from);
|
|
66
|
+
await this.writeMetadata(to, await this.readMetadata(from));
|
|
67
|
+
await placed(this.paths.contentOf(from), this.paths.contentOf(to));
|
|
68
|
+
if (from !== to) {
|
|
69
|
+
await fs.rm(this.paths.metadataOf(from), { force: true });
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
async *list(prefix) {
|
|
73
|
+
const entries = await fs.readdir(this.paths.root, { recursive: true, withFileTypes: true }).catch(() => []);
|
|
74
|
+
for (const entry of entries.filter((found) => found.isFile())) {
|
|
75
|
+
const key = this.paths.keyOf(path.join(entry.parentPath, entry.name));
|
|
76
|
+
if (key?.startsWith(prefix) === true) {
|
|
77
|
+
const { size, mtime } = await fs.stat(this.paths.contentOf(key));
|
|
78
|
+
yield { key, size, lastModified: mtime };
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
async existing(key) {
|
|
83
|
+
if ((await this.stat(key)) === undefined) {
|
|
84
|
+
throw FileError.notFound(key);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
async readMetadata(key) {
|
|
88
|
+
const text = await fs.readFile(this.paths.metadataOf(key), 'utf8').catch(() => '');
|
|
89
|
+
const value = text === '' ? undefined : JSON.parse(text);
|
|
90
|
+
return isStoredMetadata(value) ? value : { mediaType: 'application/octet-stream', checksum: '' };
|
|
91
|
+
}
|
|
92
|
+
async writeMetadata(key, metadata) {
|
|
93
|
+
const file = this.paths.metadataOf(key);
|
|
94
|
+
const { mediaType, checksum } = metadata;
|
|
95
|
+
await fs.mkdir(path.dirname(file), { recursive: true });
|
|
96
|
+
await fs.writeFile(file, JSON.stringify({ mediaType, checksum }));
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
async function placed(from, to) {
|
|
100
|
+
await fs.mkdir(path.dirname(to), { recursive: true });
|
|
101
|
+
await fs.rename(from, to);
|
|
102
|
+
}
|
|
103
|
+
//# sourceMappingURL=local-file-storage.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"local-file-storage.js","sourceRoot":"","sources":["../../../src/infrastructure/files/local-file-storage.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/** Where the local storage puts a key: its content, its metadata, and a private place for a write in progress. */
|
|
2
|
+
export declare class LocalPaths {
|
|
3
|
+
readonly root: string;
|
|
4
|
+
constructor(directory: string);
|
|
5
|
+
contentOf(key: string): string;
|
|
6
|
+
metadataOf(key: string): string;
|
|
7
|
+
incoming(): string;
|
|
8
|
+
/** The key of a file found under the root, or `undefined` for what the storage keeps for itself. */
|
|
9
|
+
keyOf(file: string): string | undefined;
|
|
10
|
+
private inside;
|
|
11
|
+
}
|
|
12
|
+
//# sourceMappingURL=local-paths.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"local-paths.d.ts","sourceRoot":"","sources":["../../../src/infrastructure/files/local-paths.ts"],"names":[],"mappings":"AAIA,kHAAkH;AAClH,qBAAa,UAAU;IACrB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IAEtB,YAAY,SAAS,EAAE,MAAM,EAE5B;IAED,SAAS,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAE7B;IAED,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAE9B;IAED,QAAQ,IAAI,MAAM,CAEjB;IAED,oGAAoG;IACpG,KAAK,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAItC;IAED,OAAO,CAAC,MAAM;CAUf"}
|