@dereekb/firebase-server 12.4.4 → 12.5.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/CHANGELOG.md +13 -0
- package/mailgun/package.json +1 -1
- package/model/package.json +1 -1
- package/model/src/lib/index.d.ts +1 -0
- package/model/src/lib/index.js +1 -0
- package/model/src/lib/index.js.map +1 -1
- package/model/src/lib/notification/notification.action.server.d.ts +2 -2
- package/model/src/lib/notification/notification.action.server.js +142 -93
- package/model/src/lib/notification/notification.action.server.js.map +1 -1
- package/model/src/lib/notification/notification.task.service.d.ts +1 -1
- package/model/src/lib/notification/notification.task.service.handler.d.ts +5 -1
- package/model/src/lib/notification/notification.task.service.handler.js +5 -1
- package/model/src/lib/notification/notification.task.service.handler.js.map +1 -1
- package/model/src/lib/notification/notification.task.service.util.d.ts +9 -0
- package/model/src/lib/notification/notification.task.service.util.js +27 -0
- package/model/src/lib/notification/notification.task.service.util.js.map +1 -0
- package/model/src/lib/storagefile/index.d.ts +7 -0
- package/model/src/lib/storagefile/index.js +11 -0
- package/model/src/lib/storagefile/index.js.map +1 -0
- package/model/src/lib/storagefile/storagefile.action.server.d.ts +41 -0
- package/model/src/lib/storagefile/storagefile.action.server.js +392 -0
- package/model/src/lib/storagefile/storagefile.action.server.js.map +1 -0
- package/model/src/lib/storagefile/storagefile.error.d.ts +11 -0
- package/model/src/lib/storagefile/storagefile.error.js +78 -0
- package/model/src/lib/storagefile/storagefile.error.js.map +1 -0
- package/model/src/lib/storagefile/storagefile.module.d.ts +30 -0
- package/model/src/lib/storagefile/storagefile.module.js +50 -0
- package/model/src/lib/storagefile/storagefile.module.js.map +1 -0
- package/model/src/lib/storagefile/storagefile.task.service.handler.d.ts +163 -0
- package/model/src/lib/storagefile/storagefile.task.service.handler.js +286 -0
- package/model/src/lib/storagefile/storagefile.task.service.handler.js.map +1 -0
- package/model/src/lib/storagefile/storagefile.upload.service.d.ts +57 -0
- package/model/src/lib/storagefile/storagefile.upload.service.initializer.d.ts +105 -0
- package/model/src/lib/storagefile/storagefile.upload.service.initializer.js +143 -0
- package/model/src/lib/storagefile/storagefile.upload.service.initializer.js.map +1 -0
- package/model/src/lib/storagefile/storagefile.upload.service.js +10 -0
- package/model/src/lib/storagefile/storagefile.upload.service.js.map +1 -0
- package/model/src/lib/storagefile/storagefile.util.d.ts +37 -0
- package/model/src/lib/storagefile/storagefile.util.js +54 -0
- package/model/src/lib/storagefile/storagefile.util.js.map +1 -0
- package/package.json +1 -1
- package/src/lib/storage/driver.accessor.d.ts +3 -3
- package/src/lib/storage/driver.accessor.js +111 -18
- package/src/lib/storage/driver.accessor.js.map +1 -1
- package/test/package.json +1 -1
- package/zoho/package.json +1 -1
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { FirebaseStorageAccessorFile, StorageFileDocument, StorageFileInitializeFromUploadResultType, UploadedFileTypeDeterminerResult } from '@dereekb/firebase';
|
|
2
|
+
import { Maybe, PromiseOrValue } from '@dereekb/util';
|
|
3
|
+
/**
|
|
4
|
+
* Provides a reference to a StorageFileInitializeFromUploadService instance.
|
|
5
|
+
*/
|
|
6
|
+
export interface StorageFileInitializeFromUploadServiceRef {
|
|
7
|
+
readonly storageFileInitializeFromUploadService: StorageFileInitializeFromUploadService;
|
|
8
|
+
}
|
|
9
|
+
export interface StorageFileInitializeFromUploadInput {
|
|
10
|
+
/**
|
|
11
|
+
* The target file.
|
|
12
|
+
*
|
|
13
|
+
* This file should not be modified (e.g. deleted) during the processor call.
|
|
14
|
+
*/
|
|
15
|
+
readonly file: FirebaseStorageAccessorFile;
|
|
16
|
+
}
|
|
17
|
+
export interface StorageFileInitializeFromUploadResult {
|
|
18
|
+
/**
|
|
19
|
+
* Whether or not the initialization was successful.
|
|
20
|
+
*/
|
|
21
|
+
readonly resultType: StorageFileInitializeFromUploadResultType;
|
|
22
|
+
/**
|
|
23
|
+
* The initialized StorageFile value, if applicable.
|
|
24
|
+
*/
|
|
25
|
+
readonly storageFileDocument?: Maybe<StorageFileDocument>;
|
|
26
|
+
/**
|
|
27
|
+
* Any error that occurred during processing.
|
|
28
|
+
*/
|
|
29
|
+
readonly initializationError?: Maybe<unknown>;
|
|
30
|
+
/**
|
|
31
|
+
* Number of StorageFiles that were flagged for deletion.
|
|
32
|
+
*
|
|
33
|
+
* Only set if flagPreviousForDelete was provided.
|
|
34
|
+
*/
|
|
35
|
+
readonly previousStorageFilesFlaggedForDeletion?: Maybe<number>;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Service dedicated to initializing a StorageFileDocument value from an uploaded file.
|
|
39
|
+
*/
|
|
40
|
+
export declare abstract class StorageFileInitializeFromUploadService {
|
|
41
|
+
/**
|
|
42
|
+
* Returns true if the file is allowed to be initialized.
|
|
43
|
+
*
|
|
44
|
+
* @param file
|
|
45
|
+
*/
|
|
46
|
+
abstract checkFileIsAllowedToBeInitialized(file: FirebaseStorageAccessorFile): PromiseOrValue<boolean>;
|
|
47
|
+
/**
|
|
48
|
+
* Used to determine the type of the input file.
|
|
49
|
+
*/
|
|
50
|
+
abstract determineUploadFileType(input: StorageFileInitializeFromUploadInput): Promise<Maybe<UploadedFileTypeDeterminerResult>>;
|
|
51
|
+
/**
|
|
52
|
+
* Initializes a StorageFileDocument value from an uploaded file.
|
|
53
|
+
*
|
|
54
|
+
* The input file is unchanged, only new content is created.
|
|
55
|
+
*/
|
|
56
|
+
abstract initializeFromUpload(input: StorageFileInitializeFromUploadInput): Promise<StorageFileInitializeFromUploadResult>;
|
|
57
|
+
}
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
import { CombineUploadFileTypeDeterminerConfig, CreateStorageFileDocumentPairResult, FirebaseStorageAccessorFile, StorageFileDocument, StorageFileFirestoreCollection, StorageFilePurposeAndUserQueryInput, StoredFileReader, UploadedFileTypeDeterminer, UploadedFileTypeDeterminerResult, UploadedFileTypeIdentifier } from '@dereekb/firebase';
|
|
2
|
+
import { ArrayOrValue, AsyncDecisionFunction, Maybe } from '@dereekb/util';
|
|
3
|
+
import { StorageFileInitializeFromUploadService } from './storagefile.upload.service';
|
|
4
|
+
export interface StorageFileInitializeFromUploadServiceInitializerInput {
|
|
5
|
+
/**
|
|
6
|
+
* The result of the determiner.
|
|
7
|
+
*/
|
|
8
|
+
readonly determinerResult: UploadedFileTypeDeterminerResult;
|
|
9
|
+
/**
|
|
10
|
+
* The uploaded file.
|
|
11
|
+
*/
|
|
12
|
+
readonly fileDetailsAccessor: StoredFileReader;
|
|
13
|
+
}
|
|
14
|
+
export type StorageFileInitializeFromUploadServiceInitializerResult = StorageFileInitializeFromUploadServiceInitializerStorageFileErrorResult | StorageFileInitializeFromUploadServiceInitializerCreateStorageFileResult | StorageFileInitializeFromUploadServiceInitializerStorageFileDocumentResult;
|
|
15
|
+
export interface StorageFileInitializeFromUploadServiceInitializerStorageFileErrorResult {
|
|
16
|
+
/**
|
|
17
|
+
* The error thrown initializing.
|
|
18
|
+
*/
|
|
19
|
+
readonly error: unknown;
|
|
20
|
+
/**
|
|
21
|
+
* If true, the initializer failed permanently and the file should be deleted.
|
|
22
|
+
*/
|
|
23
|
+
readonly permanentFailure?: boolean;
|
|
24
|
+
}
|
|
25
|
+
export interface StorageFileInitializeFromUploadServiceInitializerCreateStorageFileResult {
|
|
26
|
+
/**
|
|
27
|
+
* The result of the createStorageFileDocumentPair function, if a StorageFileDocument was created.
|
|
28
|
+
*/
|
|
29
|
+
readonly createStorageFileResult: CreateStorageFileDocumentPairResult;
|
|
30
|
+
/**
|
|
31
|
+
* If set, the initializer will query existing StorageFiles for the user and purpose and flag them for deletion.
|
|
32
|
+
*
|
|
33
|
+
* If true, createStorageFileResult will be used.
|
|
34
|
+
*/
|
|
35
|
+
readonly flagPreviousForDelete?: Maybe<boolean | StorageFilePurposeAndUserQueryInput>;
|
|
36
|
+
}
|
|
37
|
+
export interface StorageFileInitializeFromUploadServiceInitializerStorageFileDocumentResult {
|
|
38
|
+
/**
|
|
39
|
+
* The StorageFileDocument, if it was initialized.
|
|
40
|
+
*/
|
|
41
|
+
readonly storageFileDocument: StorageFileDocument;
|
|
42
|
+
/**
|
|
43
|
+
* If set, the initializer will query existing StorageFiles for the user and purpose and flag them for deletion.
|
|
44
|
+
*
|
|
45
|
+
* If true, createStorageFileResult will be used.
|
|
46
|
+
*/
|
|
47
|
+
readonly flagPreviousForDelete?: Maybe<StorageFilePurposeAndUserQueryInput>;
|
|
48
|
+
}
|
|
49
|
+
export declare function storageFileInitializeFromUploadServiceInitializerResultPermanentFailure(error: unknown): StorageFileInitializeFromUploadServiceInitializerResult;
|
|
50
|
+
/**
|
|
51
|
+
* Processes the input details accessor and returns the results.
|
|
52
|
+
*/
|
|
53
|
+
export type StorageFileInitializeFromUploadServiceInitializerFunction = (input: StorageFileInitializeFromUploadServiceInitializerInput) => Promise<StorageFileInitializeFromUploadServiceInitializerResult>;
|
|
54
|
+
export interface StorageFileInitializeFromUploadServiceInitializer {
|
|
55
|
+
/**
|
|
56
|
+
* The file type(s) identifier that this processor handles.
|
|
57
|
+
*/
|
|
58
|
+
readonly type: ArrayOrValue<UploadedFileTypeIdentifier>;
|
|
59
|
+
/**
|
|
60
|
+
* A determiner that is paired with the processor.
|
|
61
|
+
*
|
|
62
|
+
* Determiners defined here are modified to ONLY respond to the types specified in the `type` property. This means that
|
|
63
|
+
* if the determiner returns a separate type, that result will be altered to be null, instead of returned as a match.
|
|
64
|
+
*/
|
|
65
|
+
readonly determiner?: Maybe<UploadedFileTypeDeterminer>;
|
|
66
|
+
/**
|
|
67
|
+
* Handles the initialization of the StorageFileDocument from the uploaded file.
|
|
68
|
+
*/
|
|
69
|
+
readonly initialize: StorageFileInitializeFromUploadServiceInitializerFunction;
|
|
70
|
+
}
|
|
71
|
+
export interface StorageFileInitializeFromUploadServiceConfig {
|
|
72
|
+
/**
|
|
73
|
+
* If true, will validate that all processor file types have at least one corresponding determiner.
|
|
74
|
+
*/
|
|
75
|
+
readonly validate?: boolean;
|
|
76
|
+
/**
|
|
77
|
+
* The UploadedFileTypeDeterminer(s) to use for determining the upload type of each uploaded file.
|
|
78
|
+
*
|
|
79
|
+
* They will be combined together with determiners from the processors.
|
|
80
|
+
*/
|
|
81
|
+
readonly determiner?: Maybe<ArrayOrValue<UploadedFileTypeDeterminer>>;
|
|
82
|
+
/**
|
|
83
|
+
* StorageFilleFirestoreCollection used for retrieving existing StorageFiles for marking them as deleted.
|
|
84
|
+
*/
|
|
85
|
+
readonly storageFileCollection: StorageFileFirestoreCollection;
|
|
86
|
+
/**
|
|
87
|
+
* Configuration for combining the determiners.
|
|
88
|
+
*
|
|
89
|
+
* Defaults to:
|
|
90
|
+
* - completeSearchOnFirstMatch: true
|
|
91
|
+
*/
|
|
92
|
+
readonly combineDeterminersConfig?: Maybe<CombineUploadFileTypeDeterminerConfig>;
|
|
93
|
+
/**
|
|
94
|
+
* Optional function to check if the file is allowed to be initialized.
|
|
95
|
+
*/
|
|
96
|
+
readonly checkFileIsAllowedToBeInitialized?: Maybe<AsyncDecisionFunction<FirebaseStorageAccessorFile>>;
|
|
97
|
+
/**
|
|
98
|
+
* List of handlers for NotificationTaskTypes.
|
|
99
|
+
*/
|
|
100
|
+
readonly initializer: StorageFileInitializeFromUploadServiceInitializer[];
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* A basic StorageFileInitializeFromUploadService implementation.
|
|
104
|
+
*/
|
|
105
|
+
export declare function storageFileInitializeFromUploadService(config: StorageFileInitializeFromUploadServiceConfig): StorageFileInitializeFromUploadService;
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.storageFileInitializeFromUploadServiceInitializerResultPermanentFailure = storageFileInitializeFromUploadServiceInitializerResultPermanentFailure;
|
|
4
|
+
exports.storageFileInitializeFromUploadService = storageFileInitializeFromUploadService;
|
|
5
|
+
const firebase_1 = require("@dereekb/firebase");
|
|
6
|
+
const util_1 = require("@dereekb/util");
|
|
7
|
+
const storagefile_util_1 = require("./storagefile.util");
|
|
8
|
+
function storageFileInitializeFromUploadServiceInitializerResultPermanentFailure(error) {
|
|
9
|
+
return {
|
|
10
|
+
error,
|
|
11
|
+
permanentFailure: true
|
|
12
|
+
};
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* A basic StorageFileInitializeFromUploadService implementation.
|
|
16
|
+
*/
|
|
17
|
+
function storageFileInitializeFromUploadService(config) {
|
|
18
|
+
const { storageFileCollection, initializer: inputInitializers, determiner: inputDeterminers, validate, checkFileIsAllowedToBeInitialized: inputCheckFileIsAllowedToBeInitialized } = config;
|
|
19
|
+
const allDeterminers = [];
|
|
20
|
+
const initializers = {};
|
|
21
|
+
const detailsAccessorFactory = (0, firebase_1.storedFileReaderFactory)();
|
|
22
|
+
if (inputDeterminers) {
|
|
23
|
+
(0, util_1.pushItemOrArrayItemsIntoArray)(allDeterminers, inputDeterminers);
|
|
24
|
+
}
|
|
25
|
+
// iterate initializers
|
|
26
|
+
inputInitializers.forEach((initializer) => {
|
|
27
|
+
const { type: inputTypes, determiner: inputDeterminer } = initializer;
|
|
28
|
+
const types = (0, util_1.asArray)(inputTypes);
|
|
29
|
+
types.forEach((type) => {
|
|
30
|
+
initializers[type] = initializer;
|
|
31
|
+
});
|
|
32
|
+
if (inputDeterminer) {
|
|
33
|
+
const wrappedDeterminer = (0, firebase_1.limitUploadFileTypeDeterminer)(inputDeterminer, types);
|
|
34
|
+
allDeterminers.push(wrappedDeterminer);
|
|
35
|
+
}
|
|
36
|
+
});
|
|
37
|
+
const determiner = (0, firebase_1.combineUploadFileTypeDeterminers)({
|
|
38
|
+
determiners: allDeterminers,
|
|
39
|
+
...{
|
|
40
|
+
completeSearchOnFirstMatch: true,
|
|
41
|
+
...config.combineDeterminersConfig
|
|
42
|
+
}
|
|
43
|
+
});
|
|
44
|
+
// validate initializers
|
|
45
|
+
if (validate) {
|
|
46
|
+
const allInitializerTypes = Object.keys(initializers);
|
|
47
|
+
const allDeterminerTypes = new Set(determiner.getPossibleFileTypes());
|
|
48
|
+
// all initializer types should have a corresponding determiner
|
|
49
|
+
allInitializerTypes.forEach((type) => {
|
|
50
|
+
if (!allDeterminerTypes.has(type)) {
|
|
51
|
+
throw new Error(`Initializer type ${type} does not have a corresponding determiner.`);
|
|
52
|
+
}
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
async function determineUploadFileType(input) {
|
|
56
|
+
const { file } = input;
|
|
57
|
+
const fileDetailsAccessor = detailsAccessorFactory(file);
|
|
58
|
+
return determiner.determine(fileDetailsAccessor);
|
|
59
|
+
}
|
|
60
|
+
return {
|
|
61
|
+
checkFileIsAllowedToBeInitialized: inputCheckFileIsAllowedToBeInitialized ?? (0, util_1.asDecisionFunction)(true),
|
|
62
|
+
determineUploadFileType,
|
|
63
|
+
initializeFromUpload: async (input) => {
|
|
64
|
+
const determinerResult = await determineUploadFileType(input);
|
|
65
|
+
let resultType;
|
|
66
|
+
let storageFileDocument;
|
|
67
|
+
let processorError;
|
|
68
|
+
let previousStorageFilesFlaggedForDeletion;
|
|
69
|
+
if (determinerResult) {
|
|
70
|
+
const { input: fileDetailsAccessor } = determinerResult;
|
|
71
|
+
resultType = 'success';
|
|
72
|
+
const initializer = initializers[determinerResult.type];
|
|
73
|
+
if (initializer) {
|
|
74
|
+
try {
|
|
75
|
+
const initializerResult = await initializer.initialize({ determinerResult, fileDetailsAccessor });
|
|
76
|
+
if (initializerResult.error) {
|
|
77
|
+
processorError = initializerResult.error;
|
|
78
|
+
if (initializerResult.permanentFailure) {
|
|
79
|
+
resultType = 'permanent_initializer_failure';
|
|
80
|
+
}
|
|
81
|
+
else {
|
|
82
|
+
resultType = 'initializer_error';
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
else {
|
|
86
|
+
let flagPreviousForDelete;
|
|
87
|
+
if (initializerResult.createStorageFileResult) {
|
|
88
|
+
const { createStorageFileResult, flagPreviousForDelete: flagPreviousForDeleteResult } = initializerResult;
|
|
89
|
+
storageFileDocument = createStorageFileResult.storageFileDocument;
|
|
90
|
+
if (flagPreviousForDeleteResult) {
|
|
91
|
+
if (typeof flagPreviousForDeleteResult === 'object') {
|
|
92
|
+
flagPreviousForDelete = flagPreviousForDeleteResult;
|
|
93
|
+
}
|
|
94
|
+
else {
|
|
95
|
+
const { p, u } = createStorageFileResult.storageFile;
|
|
96
|
+
if (!p || !u) {
|
|
97
|
+
throw new Error('initializeFromUpload(): flagPreviousForDelete=true requires that the created StorageFile have a purpose (p) and user (u).');
|
|
98
|
+
}
|
|
99
|
+
flagPreviousForDelete = {
|
|
100
|
+
purpose: p,
|
|
101
|
+
user: u
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
else {
|
|
107
|
+
storageFileDocument = initializerResult.storageFileDocument;
|
|
108
|
+
flagPreviousForDelete = initializerResult.flagPreviousForDelete;
|
|
109
|
+
}
|
|
110
|
+
// if flagPreviousForDelete is set, flag the previous storage files for deletion
|
|
111
|
+
if (flagPreviousForDelete) {
|
|
112
|
+
const flagForDeleteResult = await (0, storagefile_util_1.queryAndFlagStorageFilesForDelete)({
|
|
113
|
+
storageFileCollection,
|
|
114
|
+
constraints: (0, firebase_1.storageFilePurposeAndUserQuery)(flagPreviousForDelete),
|
|
115
|
+
skipDeleteForKeys: [storageFileDocument.key]
|
|
116
|
+
});
|
|
117
|
+
previousStorageFilesFlaggedForDeletion = flagForDeleteResult.queuedForDeleteCount;
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
catch (e) {
|
|
122
|
+
resultType = 'initializer_error';
|
|
123
|
+
processorError = e;
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
else {
|
|
127
|
+
resultType = 'no_initializer_configured';
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
else {
|
|
131
|
+
resultType = 'no_determiner_match';
|
|
132
|
+
}
|
|
133
|
+
const result = {
|
|
134
|
+
resultType,
|
|
135
|
+
storageFileDocument,
|
|
136
|
+
initializationError: processorError,
|
|
137
|
+
previousStorageFilesFlaggedForDeletion
|
|
138
|
+
};
|
|
139
|
+
return result;
|
|
140
|
+
}
|
|
141
|
+
};
|
|
142
|
+
}
|
|
143
|
+
//# sourceMappingURL=storagefile.upload.service.initializer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"storagefile.upload.service.initializer.js","sourceRoot":"","sources":["../../../../../../../packages/firebase-server/model/src/lib/storagefile/storagefile.upload.service.initializer.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.StorageFileInitializeFromUploadService = void 0;
|
|
4
|
+
/**
|
|
5
|
+
* Service dedicated to initializing a StorageFileDocument value from an uploaded file.
|
|
6
|
+
*/
|
|
7
|
+
class StorageFileInitializeFromUploadService {
|
|
8
|
+
}
|
|
9
|
+
exports.StorageFileInitializeFromUploadService = StorageFileInitializeFromUploadService;
|
|
10
|
+
//# sourceMappingURL=storagefile.upload.service.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"storagefile.upload.service.js","sourceRoot":"","sources":["../../../../../../../packages/firebase-server/model/src/lib/storagefile/storagefile.upload.service.ts"],"names":[],"mappings":";;;AAwCA;;GAEG;AACH,MAAsB,sCAAsC;CAiB3D;AAjBD,wFAiBC"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { FirestoreQueryConstraint, StorageFile, StorageFileFirestoreCollection, StorageFileKey } from '@dereekb/firebase';
|
|
2
|
+
import { Maybe, Milliseconds, ArrayOrValue } from '@dereekb/util';
|
|
3
|
+
/**
|
|
4
|
+
* Describes when a StorageFile should be queued for deletion.
|
|
5
|
+
*
|
|
6
|
+
* If true, the StorageFile will be queued for deletion immediately.
|
|
7
|
+
* If a number, the StorageFile will be queued for deletion after the specified number of milliseconds.
|
|
8
|
+
* If a Date, the StorageFile will be queued for deletion at the specified date.
|
|
9
|
+
*/
|
|
10
|
+
export type StorageFileQueueForDeleteTime = true | Milliseconds | Date;
|
|
11
|
+
export interface QueryAndFlagStorageFilesForDeleteInput {
|
|
12
|
+
readonly storageFileCollection: StorageFileFirestoreCollection;
|
|
13
|
+
readonly constraints: FirestoreQueryConstraint[];
|
|
14
|
+
readonly queuedForDeleteTime?: Maybe<StorageFileQueueForDeleteTime>;
|
|
15
|
+
/**
|
|
16
|
+
* Array of document keys that should be ignored/skipped while flagging.
|
|
17
|
+
*/
|
|
18
|
+
readonly skipDeleteForKeys?: ArrayOrValue<StorageFileKey>;
|
|
19
|
+
}
|
|
20
|
+
export interface QueryAndFlagStorageFilesForDeleteResult {
|
|
21
|
+
readonly visitedCount: number;
|
|
22
|
+
readonly queuedForDeleteCount: number;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Performs a query and flags the matching StorageFiles for deletion.
|
|
26
|
+
*
|
|
27
|
+
* @param input The input for the query and flagging.
|
|
28
|
+
* @returns The result of the query and flagging.
|
|
29
|
+
*/
|
|
30
|
+
export declare function queryAndFlagStorageFilesForDelete(input: QueryAndFlagStorageFilesForDeleteInput): Promise<QueryAndFlagStorageFilesForDeleteResult>;
|
|
31
|
+
/**
|
|
32
|
+
* Creates a template for updating a StorageFile to be queued for deletion at the input time.
|
|
33
|
+
*
|
|
34
|
+
* @param queueForDeleteTime When to delete the StorageFile. If true or unset, the StorageFile will be flagged to be deleted immediately.
|
|
35
|
+
* @returns The update template for the StorageFile.
|
|
36
|
+
*/
|
|
37
|
+
export declare function markStorageFileForDeleteTemplate(queueForDeleteTime?: Maybe<StorageFileQueueForDeleteTime>): Pick<StorageFile, 'sdat' | 'fs'>;
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.queryAndFlagStorageFilesForDelete = queryAndFlagStorageFilesForDelete;
|
|
4
|
+
exports.markStorageFileForDeleteTemplate = markStorageFileForDeleteTemplate;
|
|
5
|
+
const firebase_1 = require("@dereekb/firebase");
|
|
6
|
+
const util_1 = require("@dereekb/util");
|
|
7
|
+
/**
|
|
8
|
+
* Performs a query and flags the matching StorageFiles for deletion.
|
|
9
|
+
*
|
|
10
|
+
* @param input The input for the query and flagging.
|
|
11
|
+
* @returns The result of the query and flagging.
|
|
12
|
+
*/
|
|
13
|
+
async function queryAndFlagStorageFilesForDelete(input) {
|
|
14
|
+
const { storageFileCollection, constraints, queuedForDeleteTime: inputQueueForDeleteTime, skipDeleteForKeys } = input;
|
|
15
|
+
const queuedForDeleteTime = inputQueueForDeleteTime ?? true;
|
|
16
|
+
const skipDeleteSet = new Set((0, util_1.asArray)(skipDeleteForKeys));
|
|
17
|
+
let visitedCount = 0;
|
|
18
|
+
let queuedForDeleteCount = 0;
|
|
19
|
+
await (0, firebase_1.iterateFirestoreDocumentSnapshotPairs)({
|
|
20
|
+
documentAccessor: storageFileCollection.documentAccessor(),
|
|
21
|
+
iterateSnapshotPair: async (snapshotPair) => {
|
|
22
|
+
const { document, data: storageFile } = snapshotPair;
|
|
23
|
+
if (!storageFile.sdat && !skipDeleteSet.has(storageFile.key)) {
|
|
24
|
+
await document.update(markStorageFileForDeleteTemplate(queuedForDeleteTime));
|
|
25
|
+
queuedForDeleteCount++;
|
|
26
|
+
}
|
|
27
|
+
visitedCount++;
|
|
28
|
+
},
|
|
29
|
+
queryFactory: storageFileCollection,
|
|
30
|
+
constraintsFactory: () => constraints,
|
|
31
|
+
batchSize: undefined,
|
|
32
|
+
performTasksConfig: {
|
|
33
|
+
maxParallelTasks: 20
|
|
34
|
+
}
|
|
35
|
+
});
|
|
36
|
+
return {
|
|
37
|
+
visitedCount,
|
|
38
|
+
queuedForDeleteCount
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Creates a template for updating a StorageFile to be queued for deletion at the input time.
|
|
43
|
+
*
|
|
44
|
+
* @param queueForDeleteTime When to delete the StorageFile. If true or unset, the StorageFile will be flagged to be deleted immediately.
|
|
45
|
+
* @returns The update template for the StorageFile.
|
|
46
|
+
*/
|
|
47
|
+
function markStorageFileForDeleteTemplate(queueForDeleteTime) {
|
|
48
|
+
const updateTemplate = {
|
|
49
|
+
sdat: queueForDeleteTime === true || queueForDeleteTime == null ? new Date() : (0, util_1.dateFromDateOrTimeNumber)(queueForDeleteTime),
|
|
50
|
+
fs: firebase_1.StorageFileState.QUEUED_FOR_DELETE
|
|
51
|
+
};
|
|
52
|
+
return updateTemplate;
|
|
53
|
+
}
|
|
54
|
+
//# sourceMappingURL=storagefile.util.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"storagefile.util.js","sourceRoot":"","sources":["../../../../../../../packages/firebase-server/model/src/lib/storagefile/storagefile.util.ts"],"names":[],"mappings":";;AAiCA,8EAgCC;AAQD,4EAOC;AAhFD,gDAAmL;AACnL,wCAAqG;AA0BrG;;;;;GAKG;AACI,KAAK,UAAU,iCAAiC,CAAC,KAA6C;IACnG,MAAM,EAAE,qBAAqB,EAAE,WAAW,EAAE,mBAAmB,EAAE,uBAAuB,EAAE,iBAAiB,EAAE,GAAG,KAAK,CAAC;IACtH,MAAM,mBAAmB,GAAG,uBAAuB,IAAI,IAAI,CAAC;IAC5D,MAAM,aAAa,GAAG,IAAI,GAAG,CAAC,IAAA,cAAO,EAAC,iBAAiB,CAAC,CAAC,CAAC;IAE1D,IAAI,YAAY,GAAG,CAAC,CAAC;IACrB,IAAI,oBAAoB,GAAG,CAAC,CAAC;IAE7B,MAAM,IAAA,gDAAqC,EAAC;QAC1C,gBAAgB,EAAE,qBAAqB,CAAC,gBAAgB,EAAE;QAC1D,mBAAmB,EAAE,KAAK,EAAE,YAAY,EAAE,EAAE;YAC1C,MAAM,EAAE,QAAQ,EAAE,IAAI,EAAE,WAAW,EAAE,GAAG,YAAY,CAAC;YAErD,IAAI,CAAC,WAAW,CAAC,IAAI,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,WAAW,CAAC,GAAG,CAAC,EAAE,CAAC;gBAC7D,MAAM,QAAQ,CAAC,MAAM,CAAC,gCAAgC,CAAC,mBAAmB,CAAC,CAAC,CAAC;gBAC7E,oBAAoB,EAAE,CAAC;YACzB,CAAC;YAED,YAAY,EAAE,CAAC;QACjB,CAAC;QACD,YAAY,EAAE,qBAAqB;QACnC,kBAAkB,EAAE,GAAG,EAAE,CAAC,WAAW;QACrC,SAAS,EAAE,SAAS;QACpB,kBAAkB,EAAE;YAClB,gBAAgB,EAAE,EAAE;SACrB;KACF,CAAC,CAAC;IAEH,OAAO;QACL,YAAY;QACZ,oBAAoB;KACrB,CAAC;AACJ,CAAC;AAED;;;;;GAKG;AACH,SAAgB,gCAAgC,CAAC,kBAAyD;IACxG,MAAM,cAAc,GAAqC;QACvD,IAAI,EAAE,kBAAkB,KAAK,IAAI,IAAI,kBAAkB,IAAI,IAAI,CAAC,CAAC,CAAC,IAAI,IAAI,EAAE,CAAC,CAAC,CAAC,IAAA,+BAAwB,EAAC,kBAAkB,CAAC;QAC3H,EAAE,EAAE,2BAAgB,CAAC,iBAAiB;KACvC,CAAC;IAEF,OAAO,cAAc,CAAC;AACxB,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { type FirebaseStorageAccessorDriver, type FirebaseStorageAccessorFile, type FirebaseStorageAccessorFolder, type StoragePath, type StorageMetadata, type StorageBucketId } from '@dereekb/firebase';
|
|
2
2
|
import { type SlashPathFolder } from '@dereekb/util';
|
|
3
|
-
import { type GetFilesOptions, type Storage as GoogleCloudStorage, type File as GoogleCloudFile, type FileMetadata } from '@google-cloud/storage';
|
|
4
|
-
export declare function googleCloudStorageBucketForStorageFilePath(storage: GoogleCloudStorage, path: StoragePath):
|
|
3
|
+
import { type GetFilesOptions, type Storage as GoogleCloudStorage, type File as GoogleCloudFile, type FileMetadata, Bucket } from '@google-cloud/storage';
|
|
4
|
+
export declare function googleCloudStorageBucketForStorageFilePath(storage: GoogleCloudStorage, path: StoragePath): Bucket;
|
|
5
5
|
export declare function googleCloudStorageFileForStorageFilePath(storage: GoogleCloudStorage, path: StoragePath): GoogleCloudFile;
|
|
6
|
-
export type GoogleCloudStorageAccessorFile = FirebaseStorageAccessorFile<GoogleCloudFile
|
|
6
|
+
export type GoogleCloudStorageAccessorFile = FirebaseStorageAccessorFile<GoogleCloudFile> & Required<Pick<FirebaseStorageAccessorFile<GoogleCloudFile>, 'uploadStream' | 'getStream'>>;
|
|
7
7
|
export declare function googleCloudFileMetadataToStorageMetadata(file: GoogleCloudFile, metadata: FileMetadata): StorageMetadata;
|
|
8
8
|
export declare function googleCloudStorageAccessorFile(storage: GoogleCloudStorage, storagePath: StoragePath): GoogleCloudStorageAccessorFile;
|
|
9
9
|
export type GoogleCloudStorageAccessorFolder = FirebaseStorageAccessorFolder<GoogleCloudFile>;
|
|
@@ -9,6 +9,8 @@ exports.googleCloudStorageAccessorFolder = googleCloudStorageAccessorFolder;
|
|
|
9
9
|
exports.googleCloudStorageFirebaseStorageAccessorDriver = googleCloudStorageFirebaseStorageAccessorDriver;
|
|
10
10
|
const firebase_1 = require("@dereekb/firebase");
|
|
11
11
|
const util_1 = require("@dereekb/util");
|
|
12
|
+
const storage_1 = require("@google-cloud/storage");
|
|
13
|
+
const date_fns_1 = require("date-fns");
|
|
12
14
|
const types_1 = require("util/types");
|
|
13
15
|
function googleCloudStorageBucketForStorageFilePath(storage, path) {
|
|
14
16
|
return storage.bucket(path.bucketId);
|
|
@@ -21,6 +23,7 @@ function googleCloudFileMetadataToStorageMetadata(file, metadata) {
|
|
|
21
23
|
const generation = String(metadata.generation ?? file.generation);
|
|
22
24
|
const metageneration = String(metadata.metageneration);
|
|
23
25
|
const size = Number(metadata.size);
|
|
26
|
+
const customMetadata = metadata.metadata;
|
|
24
27
|
return {
|
|
25
28
|
bucket: file.bucket.name,
|
|
26
29
|
fullPath,
|
|
@@ -36,7 +39,7 @@ function googleCloudFileMetadataToStorageMetadata(file, metadata) {
|
|
|
36
39
|
contentEncoding: metadata.contentEncoding,
|
|
37
40
|
contentLanguage: metadata.contentLanguage,
|
|
38
41
|
contentType: metadata.contentType,
|
|
39
|
-
customMetadata
|
|
42
|
+
customMetadata
|
|
40
43
|
};
|
|
41
44
|
}
|
|
42
45
|
function googleCloudStorageAccessorFile(storage, storagePath) {
|
|
@@ -51,26 +54,84 @@ function googleCloudStorageAccessorFile(storage, storagePath) {
|
|
|
51
54
|
: undefined)
|
|
52
55
|
};
|
|
53
56
|
}
|
|
57
|
+
function _configureMetadata(options) {
|
|
58
|
+
const customMetadata = (0, util_1.filterUndefinedValues)({
|
|
59
|
+
...options.metadata?.customMetadata,
|
|
60
|
+
...options?.customMetadata
|
|
61
|
+
});
|
|
62
|
+
return (0, util_1.filterUndefinedValues)({
|
|
63
|
+
cacheControl: options.metadata?.cacheControl,
|
|
64
|
+
contentDisposition: options.metadata?.contentDisposition,
|
|
65
|
+
contentEncoding: options.metadata?.contentEncoding,
|
|
66
|
+
contentLanguage: options.metadata?.contentLanguage,
|
|
67
|
+
contentType: options.metadata?.contentType,
|
|
68
|
+
metadata: !(0, util_1.objectHasNoKeys)(customMetadata) ? customMetadata : undefined
|
|
69
|
+
});
|
|
70
|
+
}
|
|
54
71
|
function makeUploadOptions(options) {
|
|
55
72
|
let metadata;
|
|
56
|
-
if (options
|
|
57
|
-
metadata = {
|
|
58
|
-
|
|
59
|
-
|
|
73
|
+
if (options != null) {
|
|
74
|
+
metadata = _configureMetadata({
|
|
75
|
+
metadata: {
|
|
76
|
+
...options.metadata,
|
|
77
|
+
contentType: options.contentType ?? options.metadata?.contentType
|
|
78
|
+
},
|
|
79
|
+
customMetadata: options.customMetadata
|
|
80
|
+
});
|
|
60
81
|
}
|
|
61
82
|
return {
|
|
62
83
|
// non-resumable
|
|
63
84
|
resumable: false,
|
|
64
|
-
// add content type
|
|
85
|
+
// add content type and other custom metadata
|
|
65
86
|
...(metadata ? { metadata } : undefined)
|
|
66
87
|
};
|
|
67
88
|
}
|
|
68
|
-
|
|
89
|
+
function asFileMetadata(metadata) {
|
|
90
|
+
return _configureMetadata({ metadata });
|
|
91
|
+
}
|
|
92
|
+
function makeStoragePathForPath(newPath) {
|
|
93
|
+
let path;
|
|
94
|
+
if (typeof newPath === 'string') {
|
|
95
|
+
path = {
|
|
96
|
+
bucketId: file.bucket.name,
|
|
97
|
+
pathString: newPath
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
else {
|
|
101
|
+
path = newPath;
|
|
102
|
+
}
|
|
103
|
+
return path;
|
|
104
|
+
}
|
|
105
|
+
async function copy(newPath, options) {
|
|
106
|
+
const newStoragePath = makeStoragePathForPath(newPath);
|
|
107
|
+
const newFile = googleCloudStorageAccessorFile(storage, newStoragePath);
|
|
108
|
+
return _copyWithFile(newFile, options);
|
|
109
|
+
}
|
|
110
|
+
async function _copyWithFile(newFile, options) {
|
|
111
|
+
const copyOptions = {
|
|
112
|
+
...options
|
|
113
|
+
};
|
|
114
|
+
await file.copy(newFile.reference, copyOptions);
|
|
115
|
+
return newFile;
|
|
116
|
+
}
|
|
117
|
+
const accessorFile = {
|
|
69
118
|
reference: file,
|
|
70
119
|
storagePath,
|
|
71
120
|
exists: async () => file.exists().then((x) => x[0]),
|
|
72
121
|
getDownloadUrl: async () => file.getMetadata().then((x) => file.publicUrl()),
|
|
122
|
+
getSignedUrl: async (input) => {
|
|
123
|
+
const expires = input?.expiresAt ?? (input?.expiresIn != null ? (0, date_fns_1.addMilliseconds)(new Date(), input.expiresIn) : (0, date_fns_1.addHours)(new Date(), 1));
|
|
124
|
+
const config = {
|
|
125
|
+
...input,
|
|
126
|
+
action: input?.action ?? 'read',
|
|
127
|
+
expiresIn: undefined,
|
|
128
|
+
expiresAt: undefined,
|
|
129
|
+
expires
|
|
130
|
+
};
|
|
131
|
+
return file.getSignedUrl(config).then((x) => x[0]);
|
|
132
|
+
},
|
|
73
133
|
getMetadata: () => file.getMetadata().then((x) => googleCloudFileMetadataToStorageMetadata(file, x[0])),
|
|
134
|
+
setMetadata: (metadata) => file.setMetadata(asFileMetadata(metadata)).then((x) => googleCloudFileMetadataToStorageMetadata(file, x[0])),
|
|
74
135
|
getBytes: (maxDownloadSizeBytes) => file.download(makeDownloadOptions(maxDownloadSizeBytes)).then((x) => x[0]),
|
|
75
136
|
getStream: (maxDownloadSizeBytes) => file.createReadStream(makeDownloadOptions(maxDownloadSizeBytes)),
|
|
76
137
|
upload: async (input, options) => {
|
|
@@ -105,8 +166,30 @@ function googleCloudStorageAccessorFile(storage, storagePath) {
|
|
|
105
166
|
return file.save(data, makeUploadOptions(options));
|
|
106
167
|
},
|
|
107
168
|
uploadStream: (options) => file.createWriteStream(makeUploadOptions(options)),
|
|
169
|
+
move: async (newPath, options) => {
|
|
170
|
+
const newStoragePath = makeStoragePathForPath(newPath);
|
|
171
|
+
const newFile = googleCloudStorageAccessorFile(storage, newStoragePath);
|
|
172
|
+
const moveOptions = {
|
|
173
|
+
...options
|
|
174
|
+
};
|
|
175
|
+
await file.moveFileAtomic(newFile.reference, moveOptions).catch(async (e) => {
|
|
176
|
+
if (e instanceof storage_1.ApiError && e.response?.statusMessage === 'Not Implemented') {
|
|
177
|
+
// NOTE: This is not implemented in storage emulator, so it will fail with this error in testing.
|
|
178
|
+
// https://github.com/firebase/firebase-tools/issues/3751
|
|
179
|
+
// we can perform the same task using copy and then deleting this file.
|
|
180
|
+
await copy(newPath, moveOptions);
|
|
181
|
+
await accessorFile.delete();
|
|
182
|
+
}
|
|
183
|
+
else {
|
|
184
|
+
throw e;
|
|
185
|
+
}
|
|
186
|
+
});
|
|
187
|
+
return newFile;
|
|
188
|
+
},
|
|
189
|
+
copy,
|
|
108
190
|
delete: (options) => file.delete(options).then((x) => undefined)
|
|
109
191
|
};
|
|
192
|
+
return accessorFile;
|
|
110
193
|
}
|
|
111
194
|
exports.googleCloudStorageListFilesResultFactory = (0, firebase_1.storageListFilesResultFactory)({
|
|
112
195
|
hasItems(result) {
|
|
@@ -115,8 +198,11 @@ exports.googleCloudStorageListFilesResultFactory = (0, firebase_1.storageListFil
|
|
|
115
198
|
hasNext: (result) => {
|
|
116
199
|
return result.nextQuery != null;
|
|
117
200
|
},
|
|
118
|
-
|
|
119
|
-
return
|
|
201
|
+
nextPageTokenFromResult(result) {
|
|
202
|
+
return result.nextQuery?.pageToken;
|
|
203
|
+
},
|
|
204
|
+
next(storage, options, folder, result) {
|
|
205
|
+
return folder.list({ ...options, ...result.nextQuery });
|
|
120
206
|
},
|
|
121
207
|
file(storage, fileResult) {
|
|
122
208
|
return googleCloudStorageAccessorFile(storage, fileResult.storagePath);
|
|
@@ -141,17 +227,23 @@ function googleCloudStorageAccessorFolder(storage, storagePath) {
|
|
|
141
227
|
storagePath,
|
|
142
228
|
exists: async () => folder.list({ maxResults: 1 }).then((x) => x.hasItems()),
|
|
143
229
|
list: (options) => {
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
230
|
+
const { maxResults, pageToken, includeNestedResults: listAll } = options ?? {};
|
|
231
|
+
const listOptions = {
|
|
232
|
+
maxResults,
|
|
233
|
+
pageToken,
|
|
148
234
|
autoPaginate: false,
|
|
149
235
|
versions: false,
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
236
|
+
...(listAll
|
|
237
|
+
? {
|
|
238
|
+
prefix: (0, util_1.toRelativeSlashPathStartType)((0, util_1.fixMultiSlashesInSlashPath)(storagePath.pathString + '/'))
|
|
239
|
+
}
|
|
240
|
+
: {
|
|
241
|
+
// includeTrailingDelimiter: true,
|
|
242
|
+
delimiter: util_1.SLASH_PATH_SEPARATOR,
|
|
243
|
+
prefix: (0, util_1.toRelativeSlashPathStartType)((0, util_1.fixMultiSlashesInSlashPath)(storagePath.pathString + '/')) // make sure the folder always ends with a slash
|
|
244
|
+
})
|
|
245
|
+
};
|
|
246
|
+
return bucket.getFiles(listOptions).then((x) => {
|
|
155
247
|
const files = x[0];
|
|
156
248
|
const nextQuery = x[1];
|
|
157
249
|
const apiResponse = x[2];
|
|
@@ -168,6 +260,7 @@ function googleCloudStorageAccessorFolder(storage, storagePath) {
|
|
|
168
260
|
}
|
|
169
261
|
function googleCloudStorageFirebaseStorageAccessorDriver() {
|
|
170
262
|
return {
|
|
263
|
+
type: 'server',
|
|
171
264
|
file: (storage, path) => googleCloudStorageAccessorFile(storage, path),
|
|
172
265
|
folder: (storage, path) => googleCloudStorageAccessorFolder(storage, path)
|
|
173
266
|
};
|