@proteinjs/db-file-storage-driver-gcs 1.3.15 → 1.4.1
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 +20 -0
- package/dist/generated/index.d.ts.map +1 -1
- package/dist/generated/index.js +1 -3
- package/dist/generated/index.js.map +1 -1
- package/dist/src/GoogleCloudStorageDriver.d.ts +5 -1
- package/dist/src/GoogleCloudStorageDriver.d.ts.map +1 -1
- package/dist/src/GoogleCloudStorageDriver.js +58 -10
- package/dist/src/GoogleCloudStorageDriver.js.map +1 -1
- package/generated/index.ts +1 -3
- package/package.json +5 -4
- package/src/GoogleCloudStorageDriver.ts +38 -14
- package/test/GoogleCloudStorageDriverByteEncoding.test.ts +65 -0
- package/test/GoogleCloudStorageDriverDeleteFile.test.ts +39 -0
- package/test/GoogleCloudStorageDriverSignedUrl.test.ts +64 -0
- package/dist/src/GoogleCloudStorageTableWatcher.d.ts +0 -13
- package/dist/src/GoogleCloudStorageTableWatcher.d.ts.map +0 -1
- package/dist/src/GoogleCloudStorageTableWatcher.js +0 -108
- package/dist/src/GoogleCloudStorageTableWatcher.js.map +0 -1
- package/src/GoogleCloudStorageTableWatcher.ts +0 -56
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,26 @@
|
|
|
3
3
|
All notable changes to this project will be documented in this file.
|
|
4
4
|
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
|
5
5
|
|
|
6
|
+
## [1.4.1](https://github.com/proteinjs/db/compare/@proteinjs/db-file-storage-driver-gcs@1.4.0...@proteinjs/db-file-storage-driver-gcs@1.4.1) (2026-08-19)
|
|
7
|
+
|
|
8
|
+
**Note:** Version bump only for package @proteinjs/db-file-storage-driver-gcs
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
# [1.4.0](https://github.com/proteinjs/db/compare/@proteinjs/db-file-storage-driver-gcs@1.3.15...@proteinjs/db-file-storage-driver-gcs@1.4.0) (2026-08-18)
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
### Features
|
|
18
|
+
|
|
19
|
+
* file bytes die with file rows — deleteFile is a required FileStorageDriver capability ([6d64305](https://github.com/proteinjs/db/commit/6d64305ec43cfaaa8aeb11490c548e803db8a14d))
|
|
20
|
+
* signed-URL file serving — GET /file/:id 302-redirects to the blob store, true bytes at rest, media metadata columns ([fa61db9](https://github.com/proteinjs/db/commit/fa61db9d11793a39ead08254d87c5168702b2035))
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
|
|
6
26
|
## [1.3.15](https://github.com/proteinjs/db/compare/@proteinjs/db-file-storage-driver-gcs@1.3.14...@proteinjs/db-file-storage-driver-gcs@1.3.15) (2026-08-17)
|
|
7
27
|
|
|
8
28
|
**Note:** Version bump only for package @proteinjs/db-file-storage-driver-gcs
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../generated/index.ts"],"names":[],"mappings":"AAAA,oCAAoC;AAEpC,OAAO,uBAAuB,CAAC;AAC/B,OAAO,eAAe,CAAC;AACvB,OAAO,oBAAoB,CAAC;AAC5B,OAAO,mBAAmB,CAAC;AAC3B,OAAO,uBAAuB,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../generated/index.ts"],"names":[],"mappings":"AAAA,oCAAoC;AAEpC,OAAO,uBAAuB,CAAC;AAC/B,OAAO,eAAe,CAAC;AACvB,OAAO,oBAAoB,CAAC;AAC5B,OAAO,mBAAmB,CAAC;AAC3B,OAAO,uBAAuB,CAAC;AAuB/B,cAAc,UAAU,CAAC"}
|
package/dist/generated/index.js
CHANGED
|
@@ -21,13 +21,11 @@ require("@proteinjs/db-file");
|
|
|
21
21
|
require("@proteinjs/logger");
|
|
22
22
|
require("@proteinjs/reflection");
|
|
23
23
|
/** Generate Source Graph */
|
|
24
|
-
var sourceGraph = "{\"options\":{\"directed\":true,\"multigraph\":false,\"compound\":false},\"nodes\":[{\"v\":\"@proteinjs/db-file-storage-driver-gcs/DefaultGoogleCloudStorageConfigFactory\",\"value\":{\"packageName\":\"@proteinjs/db-file-storage-driver-gcs\",\"name\":\"DefaultGoogleCloudStorageConfigFactory\",\"filePath\":\"/home/runner/work/db/db/packages/file-storage-drivers/google-cloud-storage/src/DefaultGoogleCloudStorageConfigFactory.ts\",\"qualifiedName\":\"@proteinjs/db-file-storage-driver-gcs/DefaultGoogleCloudStorageConfigFactory\",\"properties\":[],\"methods\":[{\"name\":\"getConfig\",\"returnType\":{\"packageName\":\"@proteinjs/db-file-storage-driver-gcs\",\"name\":\"GoogleCloudStorageConfig\",\"filePath\":null,\"qualifiedName\":\"@proteinjs/db-file-storage-driver-gcs/GoogleCloudStorageConfig\",\"typeParameters\":null,\"directParents\":null},\"isAsync\":false,\"isOptional\":false,\"isAbstract\":true,\"isStatic\":false,\"visibility\":\"public\",\"parameters\":[]}],\"typeParameters\":[],\"directParents\":[{\"packageName\":\"@proteinjs/reflection\",\"name\":\"Loadable\",\"filePath\":null,\"qualifiedName\":\"@proteinjs/reflection/Loadable\",\"properties\":[],\"methods\":[],\"typeParameters\":[],\"directParents\":[]}],\"sourceType\":3}},{\"v\":\"@proteinjs/reflection/Loadable\"},{\"v\":\"@proteinjs/db-file-storage-driver-gcs/GoogleCloudStorageDriver\",\"value\":{\"packageName\":\"@proteinjs/db-file-storage-driver-gcs\",\"name\":\"GoogleCloudStorageDriver\",\"filePath\":\"/home/runner/work/db/db/packages/file-storage-drivers/google-cloud-storage/src/GoogleCloudStorageDriver.ts\",\"qualifiedName\":\"@proteinjs/db-file-storage-driver-gcs/GoogleCloudStorageDriver\",\"isAbstract\":false,\"isStatic\":false,\"visibility\":\"public\",\"properties\":[{\"name\":\"storage\",\"type\":{\"packageName\":\"@google-cloud/storage\",\"name\":\"Storage\",\"filePath\":null,\"qualifiedName\":\"@google-cloud/storage/Storage\",\"typeParameters\":null,\"directParents\":null},\"isOptional\":false,\"isAbstract\":false,\"isStatic\":false,\"visibility\":\"private\"},{\"name\":\"bucketName\",\"type\":{\"packageName\":\"\",\"name\":\"string\",\"filePath\":null,\"qualifiedName\":\"/string\",\"typeParameters\":null,\"directParents\":null},\"isOptional\":false,\"isAbstract\":false,\"isStatic\":false,\"visibility\":\"private\"}],\"methods\":[{\"name\":\"
|
|
24
|
+
var sourceGraph = "{\"options\":{\"directed\":true,\"multigraph\":false,\"compound\":false},\"nodes\":[{\"v\":\"@proteinjs/db-file-storage-driver-gcs/DefaultGoogleCloudStorageConfigFactory\",\"value\":{\"packageName\":\"@proteinjs/db-file-storage-driver-gcs\",\"name\":\"DefaultGoogleCloudStorageConfigFactory\",\"filePath\":\"/home/runner/work/db/db/packages/file-storage-drivers/google-cloud-storage/src/DefaultGoogleCloudStorageConfigFactory.ts\",\"qualifiedName\":\"@proteinjs/db-file-storage-driver-gcs/DefaultGoogleCloudStorageConfigFactory\",\"properties\":[],\"methods\":[{\"name\":\"getConfig\",\"returnType\":{\"packageName\":\"@proteinjs/db-file-storage-driver-gcs\",\"name\":\"GoogleCloudStorageConfig\",\"filePath\":null,\"qualifiedName\":\"@proteinjs/db-file-storage-driver-gcs/GoogleCloudStorageConfig\",\"typeParameters\":null,\"directParents\":null},\"isAsync\":false,\"isOptional\":false,\"isAbstract\":true,\"isStatic\":false,\"visibility\":\"public\",\"parameters\":[]}],\"typeParameters\":[],\"directParents\":[{\"packageName\":\"@proteinjs/reflection\",\"name\":\"Loadable\",\"filePath\":null,\"qualifiedName\":\"@proteinjs/reflection/Loadable\",\"properties\":[],\"methods\":[],\"typeParameters\":[],\"directParents\":[]}],\"sourceType\":3}},{\"v\":\"@proteinjs/reflection/Loadable\"},{\"v\":\"@proteinjs/db-file-storage-driver-gcs/GoogleCloudStorageDriver\",\"value\":{\"packageName\":\"@proteinjs/db-file-storage-driver-gcs\",\"name\":\"GoogleCloudStorageDriver\",\"filePath\":\"/home/runner/work/db/db/packages/file-storage-drivers/google-cloud-storage/src/GoogleCloudStorageDriver.ts\",\"qualifiedName\":\"@proteinjs/db-file-storage-driver-gcs/GoogleCloudStorageDriver\",\"isAbstract\":false,\"isStatic\":false,\"visibility\":\"public\",\"properties\":[{\"name\":\"storage\",\"type\":{\"packageName\":\"@google-cloud/storage\",\"name\":\"Storage\",\"filePath\":null,\"qualifiedName\":\"@google-cloud/storage/Storage\",\"typeParameters\":null,\"directParents\":null},\"isOptional\":false,\"isAbstract\":false,\"isStatic\":false,\"visibility\":\"private\"},{\"name\":\"bucketName\",\"type\":{\"packageName\":\"\",\"name\":\"string\",\"filePath\":null,\"qualifiedName\":\"/string\",\"typeParameters\":null,\"directParents\":null},\"isOptional\":false,\"isAbstract\":false,\"isStatic\":false,\"visibility\":\"private\"}],\"methods\":[{\"name\":\"createFile\",\"returnType\":{\"packageName\":\"\",\"name\":\"Promise<void>\",\"filePath\":null,\"qualifiedName\":\"/Promise<void>\",\"typeParameters\":null,\"directParents\":null},\"isAsync\":true,\"isOptional\":false,\"isAbstract\":false,\"isStatic\":false,\"visibility\":\"public\",\"parameters\":[{\"name\":\"file\",\"type\":{\"packageName\":\"@proteinjs/db-file\",\"name\":\"File\",\"filePath\":null,\"qualifiedName\":\"@proteinjs/db-file/File\",\"typeParameters\":null,\"directParents\":null}},{\"name\":\"fileData\",\"type\":{\"packageName\":\"\",\"name\":\"string\",\"filePath\":null,\"qualifiedName\":\"/string\",\"typeParameters\":null,\"directParents\":null}}]},{\"name\":\"getFileData\",\"returnType\":{\"packageName\":\"\",\"name\":\"Promise<string>\",\"filePath\":null,\"qualifiedName\":\"/Promise<string>\",\"typeParameters\":null,\"directParents\":null},\"isAsync\":true,\"isOptional\":false,\"isAbstract\":false,\"isStatic\":false,\"visibility\":\"public\",\"parameters\":[{\"name\":\"fileId\",\"type\":{\"packageName\":\"\",\"name\":\"string\",\"filePath\":null,\"qualifiedName\":\"/string\",\"typeParameters\":null,\"directParents\":null}}]},{\"name\":\"updateFileData\",\"returnType\":{\"packageName\":\"\",\"name\":\"Promise<void>\",\"filePath\":null,\"qualifiedName\":\"/Promise<void>\",\"typeParameters\":null,\"directParents\":null},\"isAsync\":true,\"isOptional\":false,\"isAbstract\":false,\"isStatic\":false,\"visibility\":\"public\",\"parameters\":[{\"name\":\"fileId\",\"type\":{\"packageName\":\"\",\"name\":\"string\",\"filePath\":null,\"qualifiedName\":\"/string\",\"typeParameters\":null,\"directParents\":null}},{\"name\":\"data\",\"type\":{\"packageName\":\"\",\"name\":\"string\",\"filePath\":null,\"qualifiedName\":\"/string\",\"typeParameters\":null,\"directParents\":null}}]},{\"name\":\"updateFile\",\"returnType\":{\"packageName\":\"\",\"name\":\"Promise<void>\",\"filePath\":null,\"qualifiedName\":\"/Promise<void>\",\"typeParameters\":null,\"directParents\":null},\"isAsync\":true,\"isOptional\":false,\"isAbstract\":false,\"isStatic\":false,\"visibility\":\"public\",\"parameters\":[{\"name\":\"file\",\"type\":{\"packageName\":\"@proteinjs/db-file\",\"name\":\"File\",\"filePath\":null,\"qualifiedName\":\"@proteinjs/db-file/File\",\"typeParameters\":null,\"directParents\":null}}]},{\"name\":\"getSignedUrl\",\"returnType\":{\"packageName\":\"\",\"name\":\"Promise<string>\",\"filePath\":null,\"qualifiedName\":\"/Promise<string>\",\"typeParameters\":null,\"directParents\":null},\"isAsync\":true,\"isOptional\":false,\"isAbstract\":false,\"isStatic\":false,\"visibility\":\"public\",\"parameters\":[{\"name\":\"fileId\",\"type\":{\"packageName\":\"\",\"name\":\"string\",\"filePath\":null,\"qualifiedName\":\"/string\",\"typeParameters\":null,\"directParents\":null}},{\"name\":\"options\",\"type\":{\"packageName\":\"@proteinjs/db-file-storage-driver-gcs\",\"name\":\"{ ttlMs?: number }\",\"filePath\":null,\"qualifiedName\":\"@proteinjs/db-file-storage-driver-gcs/{ ttlMs?: number }\",\"typeParameters\":null,\"directParents\":null}}]},{\"name\":\"deleteFile\",\"returnType\":{\"packageName\":\"\",\"name\":\"Promise<void>\",\"filePath\":null,\"qualifiedName\":\"/Promise<void>\",\"typeParameters\":null,\"directParents\":null},\"isAsync\":true,\"isOptional\":false,\"isAbstract\":false,\"isStatic\":false,\"visibility\":\"public\",\"parameters\":[{\"name\":\"fileId\",\"type\":{\"packageName\":\"\",\"name\":\"string\",\"filePath\":null,\"qualifiedName\":\"/string\",\"typeParameters\":null,\"directParents\":null}}]},{\"name\":\"getDefaultConfig\",\"returnType\":{\"packageName\":\"@proteinjs/db-file-storage-driver-gcs\",\"name\":\"GoogleCloudStorageConfig\",\"filePath\":null,\"qualifiedName\":\"@proteinjs/db-file-storage-driver-gcs/GoogleCloudStorageConfig\",\"typeParameters\":null,\"directParents\":null},\"isAsync\":false,\"isOptional\":false,\"isAbstract\":false,\"isStatic\":false,\"visibility\":\"private\",\"parameters\":[]}],\"typeParameters\":[],\"directParentInterfaces\":[{\"packageName\":\"@proteinjs/db-file\",\"name\":\"FileStorageDriver\",\"filePath\":null,\"qualifiedName\":\"@proteinjs/db-file/FileStorageDriver\",\"properties\":[],\"methods\":[],\"typeParameters\":[],\"directParents\":[]}],\"directParentClasses\":[],\"sourceType\":2}},{\"v\":\"@proteinjs/db-file/FileStorageDriver\"}],\"edges\":[{\"v\":\"@proteinjs/db-file-storage-driver-gcs/DefaultGoogleCloudStorageConfigFactory\",\"w\":\"@proteinjs/reflection/Loadable\",\"value\":\"extends interface\"},{\"v\":\"@proteinjs/db-file-storage-driver-gcs/GoogleCloudStorageDriver\",\"w\":\"@proteinjs/db-file/FileStorageDriver\",\"value\":\"implements interface\"}]}";
|
|
25
25
|
/** Generate Source Links */
|
|
26
26
|
var GoogleCloudStorageDriver_1 = require("../src/GoogleCloudStorageDriver");
|
|
27
|
-
var GoogleCloudStorageTableWatcher_1 = require("../src/GoogleCloudStorageTableWatcher");
|
|
28
27
|
var sourceLinks = {
|
|
29
28
|
'@proteinjs/db-file-storage-driver-gcs/GoogleCloudStorageDriver': GoogleCloudStorageDriver_1.GoogleCloudStorageDriver,
|
|
30
|
-
'@proteinjs/db-file-storage-driver-gcs/GoogleCloudStorageTableWatcher': GoogleCloudStorageTableWatcher_1.GoogleCloudStorageTableWatcher,
|
|
31
29
|
};
|
|
32
30
|
/** Load Source Graph and Links */
|
|
33
31
|
var reflection_1 = require("@proteinjs/reflection");
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../generated/index.ts"],"names":[],"mappings":";AAAA,oCAAoC;;;;;;;;;;;;;;;;AAEpC,iCAA+B;AAC/B,yBAAuB;AACvB,8BAA4B;AAC5B,6BAA2B;AAC3B,iCAA+B;AAG/B,4BAA4B;AAE5B,IAAM,WAAW,GAAG,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../generated/index.ts"],"names":[],"mappings":";AAAA,oCAAoC;;;;;;;;;;;;;;;;AAEpC,iCAA+B;AAC/B,yBAAuB;AACvB,8BAA4B;AAC5B,6BAA2B;AAC3B,iCAA+B;AAG/B,4BAA4B;AAE5B,IAAM,WAAW,GAAG,k4NAAk4N,CAAC;AAGv5N,4BAA4B;AAE5B,4EAA2E;AAE3E,IAAM,WAAW,GAAG;IACnB,gEAAgE,EAAE,mDAAwB;CAC1F,CAAC;AAGF,kCAAkC;AAElC,oDAAyD;AACzD,6BAAgB,CAAC,KAAK,CAAC,WAAW,EAAE,WAAW,CAAC,CAAC;AAGjD,2CAAyB"}
|
|
@@ -4,10 +4,14 @@ export declare class GoogleCloudStorageDriver implements FileStorageDriver {
|
|
|
4
4
|
private storage;
|
|
5
5
|
private bucketName;
|
|
6
6
|
constructor(config?: GoogleCloudStorageConfig);
|
|
7
|
-
private getDefaultConfig;
|
|
8
7
|
createFile(file: File, fileData: string): Promise<void>;
|
|
9
8
|
getFileData(fileId: string): Promise<string>;
|
|
10
9
|
updateFileData(fileId: string, data: string): Promise<void>;
|
|
11
10
|
updateFile(file: File): Promise<void>;
|
|
11
|
+
getSignedUrl(fileId: string, options?: {
|
|
12
|
+
ttlMs?: number;
|
|
13
|
+
}): Promise<string>;
|
|
14
|
+
deleteFile(fileId: string): Promise<void>;
|
|
15
|
+
private getDefaultConfig;
|
|
12
16
|
}
|
|
13
17
|
//# sourceMappingURL=GoogleCloudStorageDriver.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"GoogleCloudStorageDriver.d.ts","sourceRoot":"","sources":["../../src/GoogleCloudStorageDriver.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,IAAI,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AAC7D,OAAO,EACL,wBAAwB,EAEzB,MAAM,0CAA0C,CAAC;
|
|
1
|
+
{"version":3,"file":"GoogleCloudStorageDriver.d.ts","sourceRoot":"","sources":["../../src/GoogleCloudStorageDriver.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,IAAI,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AAC7D,OAAO,EACL,wBAAwB,EAEzB,MAAM,0CAA0C,CAAC;AAMlD,qBAAa,wBAAyB,YAAW,iBAAiB;IAChE,OAAO,CAAC,OAAO,CAAU;IACzB,OAAO,CAAC,UAAU,CAAS;gBAEf,MAAM,CAAC,EAAE,wBAAwB;IAMvC,UAAU,CAAC,IAAI,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAmBvD,WAAW,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAM5C,cAAc,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAK3D,UAAU,CAAC,IAAI,EAAE,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC;IAYrC,YAAY,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE;QAAE,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC,MAAM,CAAC;IAU3E,UAAU,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAO/C,OAAO,CAAC,gBAAgB;CAUzB"}
|
|
@@ -50,19 +50,15 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
50
50
|
exports.GoogleCloudStorageDriver = void 0;
|
|
51
51
|
var storage_1 = require("@google-cloud/storage");
|
|
52
52
|
var DefaultGoogleCloudStorageConfigFactory_1 = require("./DefaultGoogleCloudStorageConfigFactory");
|
|
53
|
+
/** Signed URLs are short-lived read capabilities minted per serve — long enough to load and seek
|
|
54
|
+
* a video, short enough that a leaked URL goes stale quickly. */
|
|
55
|
+
var DEFAULT_SIGNED_URL_TTL_MS = 15 * 60 * 1000;
|
|
53
56
|
var GoogleCloudStorageDriver = /** @class */ (function () {
|
|
54
57
|
function GoogleCloudStorageDriver(config) {
|
|
55
58
|
var _a = config ? config : this.getDefaultConfig(), projectId = _a.projectId, bucketName = _a.bucketName, storageOptions = _a.storageOptions;
|
|
56
59
|
this.storage = new storage_1.Storage(__assign(__assign({}, storageOptions), { projectId: projectId }));
|
|
57
60
|
this.bucketName = bucketName;
|
|
58
61
|
}
|
|
59
|
-
GoogleCloudStorageDriver.prototype.getDefaultConfig = function () {
|
|
60
|
-
var defaultConfigFactory = (0, DefaultGoogleCloudStorageConfigFactory_1.getDefaultGoogleCloudStorageConfigFactory)();
|
|
61
|
-
if (!defaultConfigFactory) {
|
|
62
|
-
throw new Error("Unable to find a @proteinjs/db-file-storage-driver-gcs/DefaultGoogleCloudStorageConfigFactory implementation. Either implement DefaultGoogleCloudStorageConfigFactory or pass in a config when instantiating GoogleCloudStorageDriver.");
|
|
63
|
-
}
|
|
64
|
-
return defaultConfigFactory.getConfig();
|
|
65
|
-
};
|
|
66
62
|
GoogleCloudStorageDriver.prototype.createFile = function (file, fileData) {
|
|
67
63
|
return __awaiter(this, void 0, void 0, function () {
|
|
68
64
|
var bucket, gcsFile;
|
|
@@ -71,7 +67,10 @@ var GoogleCloudStorageDriver = /** @class */ (function () {
|
|
|
71
67
|
case 0:
|
|
72
68
|
bucket = this.storage.bucket(this.bucketName);
|
|
73
69
|
gcsFile = bucket.file(file.id);
|
|
74
|
-
|
|
70
|
+
// The GCS object stores the file's TRUE bytes (the interface string is base64 transport).
|
|
71
|
+
// Raw bytes at rest are what make signed-URL serving correct: the browser reads the object
|
|
72
|
+
// directly, so base64 text at rest would corrupt every binary served that way.
|
|
73
|
+
return [4 /*yield*/, gcsFile.save(Buffer.from(fileData, 'base64'), {
|
|
75
74
|
metadata: {
|
|
76
75
|
contentType: file.type,
|
|
77
76
|
metadata: {
|
|
@@ -82,6 +81,9 @@ var GoogleCloudStorageDriver = /** @class */ (function () {
|
|
|
82
81
|
},
|
|
83
82
|
})];
|
|
84
83
|
case 1:
|
|
84
|
+
// The GCS object stores the file's TRUE bytes (the interface string is base64 transport).
|
|
85
|
+
// Raw bytes at rest are what make signed-URL serving correct: the browser reads the object
|
|
86
|
+
// directly, so base64 text at rest would corrupt every binary served that way.
|
|
85
87
|
_a.sent();
|
|
86
88
|
return [2 /*return*/];
|
|
87
89
|
}
|
|
@@ -98,7 +100,7 @@ var GoogleCloudStorageDriver = /** @class */ (function () {
|
|
|
98
100
|
return [4 /*yield*/, file.download()];
|
|
99
101
|
case 1:
|
|
100
102
|
fileContent = (_a.sent())[0];
|
|
101
|
-
return [2 /*return*/, fileContent.toString()];
|
|
103
|
+
return [2 /*return*/, fileContent.toString('base64')];
|
|
102
104
|
}
|
|
103
105
|
});
|
|
104
106
|
});
|
|
@@ -110,7 +112,7 @@ var GoogleCloudStorageDriver = /** @class */ (function () {
|
|
|
110
112
|
switch (_a.label) {
|
|
111
113
|
case 0:
|
|
112
114
|
file = this.storage.bucket(this.bucketName).file(fileId);
|
|
113
|
-
return [4 /*yield*/, file.save(data)];
|
|
115
|
+
return [4 /*yield*/, file.save(Buffer.from(data, 'base64'))];
|
|
114
116
|
case 1:
|
|
115
117
|
_a.sent();
|
|
116
118
|
return [2 /*return*/];
|
|
@@ -140,6 +142,52 @@ var GoogleCloudStorageDriver = /** @class */ (function () {
|
|
|
140
142
|
});
|
|
141
143
|
});
|
|
142
144
|
};
|
|
145
|
+
GoogleCloudStorageDriver.prototype.getSignedUrl = function (fileId, options) {
|
|
146
|
+
var _a;
|
|
147
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
148
|
+
var gcsFile, url;
|
|
149
|
+
return __generator(this, function (_b) {
|
|
150
|
+
switch (_b.label) {
|
|
151
|
+
case 0:
|
|
152
|
+
gcsFile = this.storage.bucket(this.bucketName).file(fileId);
|
|
153
|
+
return [4 /*yield*/, gcsFile.getSignedUrl({
|
|
154
|
+
version: 'v4',
|
|
155
|
+
action: 'read',
|
|
156
|
+
expires: Date.now() + ((_a = options === null || options === void 0 ? void 0 : options.ttlMs) !== null && _a !== void 0 ? _a : DEFAULT_SIGNED_URL_TTL_MS),
|
|
157
|
+
})];
|
|
158
|
+
case 1:
|
|
159
|
+
url = (_b.sent())[0];
|
|
160
|
+
return [2 /*return*/, url];
|
|
161
|
+
}
|
|
162
|
+
});
|
|
163
|
+
});
|
|
164
|
+
};
|
|
165
|
+
GoogleCloudStorageDriver.prototype.deleteFile = function (fileId) {
|
|
166
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
167
|
+
var gcsFile;
|
|
168
|
+
return __generator(this, function (_a) {
|
|
169
|
+
switch (_a.label) {
|
|
170
|
+
case 0:
|
|
171
|
+
gcsFile = this.storage.bucket(this.bucketName).file(fileId);
|
|
172
|
+
// ignoreNotFound implements the driver contract's idempotency: a retried row delete must not
|
|
173
|
+
// wedge because a prior attempt already removed the blob. Every other failure throws loudly.
|
|
174
|
+
return [4 /*yield*/, gcsFile.delete({ ignoreNotFound: true })];
|
|
175
|
+
case 1:
|
|
176
|
+
// ignoreNotFound implements the driver contract's idempotency: a retried row delete must not
|
|
177
|
+
// wedge because a prior attempt already removed the blob. Every other failure throws loudly.
|
|
178
|
+
_a.sent();
|
|
179
|
+
return [2 /*return*/];
|
|
180
|
+
}
|
|
181
|
+
});
|
|
182
|
+
});
|
|
183
|
+
};
|
|
184
|
+
GoogleCloudStorageDriver.prototype.getDefaultConfig = function () {
|
|
185
|
+
var defaultConfigFactory = (0, DefaultGoogleCloudStorageConfigFactory_1.getDefaultGoogleCloudStorageConfigFactory)();
|
|
186
|
+
if (!defaultConfigFactory) {
|
|
187
|
+
throw new Error("Unable to find a @proteinjs/db-file-storage-driver-gcs/DefaultGoogleCloudStorageConfigFactory implementation. Either implement DefaultGoogleCloudStorageConfigFactory or pass in a config when instantiating GoogleCloudStorageDriver.");
|
|
188
|
+
}
|
|
189
|
+
return defaultConfigFactory.getConfig();
|
|
190
|
+
};
|
|
143
191
|
return GoogleCloudStorageDriver;
|
|
144
192
|
}());
|
|
145
193
|
exports.GoogleCloudStorageDriver = GoogleCloudStorageDriver;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"GoogleCloudStorageDriver.js","sourceRoot":"","sources":["../../src/GoogleCloudStorageDriver.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,iDAAgD;AAEhD,mGAGkD;AAElD;IAIE,kCAAY,MAAiC;QACrC,IAAA,KAA4C,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,gBAAgB,EAAE,EAAnF,SAAS,eAAA,EAAE,UAAU,gBAAA,EAAE,cAAc,oBAA8C,CAAC;QAC5F,IAAI,CAAC,OAAO,GAAG,IAAI,iBAAO,uBAAM,cAAc,KAAE,SAAS,WAAA,IAAG,CAAC;QAC7D,IAAI,CAAC,UAAU,GAAG,UAAU,CAAC;IAC/B,CAAC;
|
|
1
|
+
{"version":3,"file":"GoogleCloudStorageDriver.js","sourceRoot":"","sources":["../../src/GoogleCloudStorageDriver.ts"],"names":[],"mappings":"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"}
|
package/generated/index.ts
CHANGED
|
@@ -9,16 +9,14 @@ import '@proteinjs/reflection';
|
|
|
9
9
|
/** Generate Source Graph */
|
|
10
10
|
|
|
11
11
|
const sourceGraph =
|
|
12
|
-
'{"options":{"directed":true,"multigraph":false,"compound":false},"nodes":[{"v":"@proteinjs/db-file-storage-driver-gcs/DefaultGoogleCloudStorageConfigFactory","value":{"packageName":"@proteinjs/db-file-storage-driver-gcs","name":"DefaultGoogleCloudStorageConfigFactory","filePath":"/home/runner/work/db/db/packages/file-storage-drivers/google-cloud-storage/src/DefaultGoogleCloudStorageConfigFactory.ts","qualifiedName":"@proteinjs/db-file-storage-driver-gcs/DefaultGoogleCloudStorageConfigFactory","properties":[],"methods":[{"name":"getConfig","returnType":{"packageName":"@proteinjs/db-file-storage-driver-gcs","name":"GoogleCloudStorageConfig","filePath":null,"qualifiedName":"@proteinjs/db-file-storage-driver-gcs/GoogleCloudStorageConfig","typeParameters":null,"directParents":null},"isAsync":false,"isOptional":false,"isAbstract":true,"isStatic":false,"visibility":"public","parameters":[]}],"typeParameters":[],"directParents":[{"packageName":"@proteinjs/reflection","name":"Loadable","filePath":null,"qualifiedName":"@proteinjs/reflection/Loadable","properties":[],"methods":[],"typeParameters":[],"directParents":[]}],"sourceType":3}},{"v":"@proteinjs/reflection/Loadable"},{"v":"@proteinjs/db-file-storage-driver-gcs/GoogleCloudStorageDriver","value":{"packageName":"@proteinjs/db-file-storage-driver-gcs","name":"GoogleCloudStorageDriver","filePath":"/home/runner/work/db/db/packages/file-storage-drivers/google-cloud-storage/src/GoogleCloudStorageDriver.ts","qualifiedName":"@proteinjs/db-file-storage-driver-gcs/GoogleCloudStorageDriver","isAbstract":false,"isStatic":false,"visibility":"public","properties":[{"name":"storage","type":{"packageName":"@google-cloud/storage","name":"Storage","filePath":null,"qualifiedName":"@google-cloud/storage/Storage","typeParameters":null,"directParents":null},"isOptional":false,"isAbstract":false,"isStatic":false,"visibility":"private"},{"name":"bucketName","type":{"packageName":"","name":"string","filePath":null,"qualifiedName":"/string","typeParameters":null,"directParents":null},"isOptional":false,"isAbstract":false,"isStatic":false,"visibility":"private"}],"methods":[{"name":"
|
|
12
|
+
'{"options":{"directed":true,"multigraph":false,"compound":false},"nodes":[{"v":"@proteinjs/db-file-storage-driver-gcs/DefaultGoogleCloudStorageConfigFactory","value":{"packageName":"@proteinjs/db-file-storage-driver-gcs","name":"DefaultGoogleCloudStorageConfigFactory","filePath":"/home/runner/work/db/db/packages/file-storage-drivers/google-cloud-storage/src/DefaultGoogleCloudStorageConfigFactory.ts","qualifiedName":"@proteinjs/db-file-storage-driver-gcs/DefaultGoogleCloudStorageConfigFactory","properties":[],"methods":[{"name":"getConfig","returnType":{"packageName":"@proteinjs/db-file-storage-driver-gcs","name":"GoogleCloudStorageConfig","filePath":null,"qualifiedName":"@proteinjs/db-file-storage-driver-gcs/GoogleCloudStorageConfig","typeParameters":null,"directParents":null},"isAsync":false,"isOptional":false,"isAbstract":true,"isStatic":false,"visibility":"public","parameters":[]}],"typeParameters":[],"directParents":[{"packageName":"@proteinjs/reflection","name":"Loadable","filePath":null,"qualifiedName":"@proteinjs/reflection/Loadable","properties":[],"methods":[],"typeParameters":[],"directParents":[]}],"sourceType":3}},{"v":"@proteinjs/reflection/Loadable"},{"v":"@proteinjs/db-file-storage-driver-gcs/GoogleCloudStorageDriver","value":{"packageName":"@proteinjs/db-file-storage-driver-gcs","name":"GoogleCloudStorageDriver","filePath":"/home/runner/work/db/db/packages/file-storage-drivers/google-cloud-storage/src/GoogleCloudStorageDriver.ts","qualifiedName":"@proteinjs/db-file-storage-driver-gcs/GoogleCloudStorageDriver","isAbstract":false,"isStatic":false,"visibility":"public","properties":[{"name":"storage","type":{"packageName":"@google-cloud/storage","name":"Storage","filePath":null,"qualifiedName":"@google-cloud/storage/Storage","typeParameters":null,"directParents":null},"isOptional":false,"isAbstract":false,"isStatic":false,"visibility":"private"},{"name":"bucketName","type":{"packageName":"","name":"string","filePath":null,"qualifiedName":"/string","typeParameters":null,"directParents":null},"isOptional":false,"isAbstract":false,"isStatic":false,"visibility":"private"}],"methods":[{"name":"createFile","returnType":{"packageName":"","name":"Promise<void>","filePath":null,"qualifiedName":"/Promise<void>","typeParameters":null,"directParents":null},"isAsync":true,"isOptional":false,"isAbstract":false,"isStatic":false,"visibility":"public","parameters":[{"name":"file","type":{"packageName":"@proteinjs/db-file","name":"File","filePath":null,"qualifiedName":"@proteinjs/db-file/File","typeParameters":null,"directParents":null}},{"name":"fileData","type":{"packageName":"","name":"string","filePath":null,"qualifiedName":"/string","typeParameters":null,"directParents":null}}]},{"name":"getFileData","returnType":{"packageName":"","name":"Promise<string>","filePath":null,"qualifiedName":"/Promise<string>","typeParameters":null,"directParents":null},"isAsync":true,"isOptional":false,"isAbstract":false,"isStatic":false,"visibility":"public","parameters":[{"name":"fileId","type":{"packageName":"","name":"string","filePath":null,"qualifiedName":"/string","typeParameters":null,"directParents":null}}]},{"name":"updateFileData","returnType":{"packageName":"","name":"Promise<void>","filePath":null,"qualifiedName":"/Promise<void>","typeParameters":null,"directParents":null},"isAsync":true,"isOptional":false,"isAbstract":false,"isStatic":false,"visibility":"public","parameters":[{"name":"fileId","type":{"packageName":"","name":"string","filePath":null,"qualifiedName":"/string","typeParameters":null,"directParents":null}},{"name":"data","type":{"packageName":"","name":"string","filePath":null,"qualifiedName":"/string","typeParameters":null,"directParents":null}}]},{"name":"updateFile","returnType":{"packageName":"","name":"Promise<void>","filePath":null,"qualifiedName":"/Promise<void>","typeParameters":null,"directParents":null},"isAsync":true,"isOptional":false,"isAbstract":false,"isStatic":false,"visibility":"public","parameters":[{"name":"file","type":{"packageName":"@proteinjs/db-file","name":"File","filePath":null,"qualifiedName":"@proteinjs/db-file/File","typeParameters":null,"directParents":null}}]},{"name":"getSignedUrl","returnType":{"packageName":"","name":"Promise<string>","filePath":null,"qualifiedName":"/Promise<string>","typeParameters":null,"directParents":null},"isAsync":true,"isOptional":false,"isAbstract":false,"isStatic":false,"visibility":"public","parameters":[{"name":"fileId","type":{"packageName":"","name":"string","filePath":null,"qualifiedName":"/string","typeParameters":null,"directParents":null}},{"name":"options","type":{"packageName":"@proteinjs/db-file-storage-driver-gcs","name":"{ ttlMs?: number }","filePath":null,"qualifiedName":"@proteinjs/db-file-storage-driver-gcs/{ ttlMs?: number }","typeParameters":null,"directParents":null}}]},{"name":"deleteFile","returnType":{"packageName":"","name":"Promise<void>","filePath":null,"qualifiedName":"/Promise<void>","typeParameters":null,"directParents":null},"isAsync":true,"isOptional":false,"isAbstract":false,"isStatic":false,"visibility":"public","parameters":[{"name":"fileId","type":{"packageName":"","name":"string","filePath":null,"qualifiedName":"/string","typeParameters":null,"directParents":null}}]},{"name":"getDefaultConfig","returnType":{"packageName":"@proteinjs/db-file-storage-driver-gcs","name":"GoogleCloudStorageConfig","filePath":null,"qualifiedName":"@proteinjs/db-file-storage-driver-gcs/GoogleCloudStorageConfig","typeParameters":null,"directParents":null},"isAsync":false,"isOptional":false,"isAbstract":false,"isStatic":false,"visibility":"private","parameters":[]}],"typeParameters":[],"directParentInterfaces":[{"packageName":"@proteinjs/db-file","name":"FileStorageDriver","filePath":null,"qualifiedName":"@proteinjs/db-file/FileStorageDriver","properties":[],"methods":[],"typeParameters":[],"directParents":[]}],"directParentClasses":[],"sourceType":2}},{"v":"@proteinjs/db-file/FileStorageDriver"}],"edges":[{"v":"@proteinjs/db-file-storage-driver-gcs/DefaultGoogleCloudStorageConfigFactory","w":"@proteinjs/reflection/Loadable","value":"extends interface"},{"v":"@proteinjs/db-file-storage-driver-gcs/GoogleCloudStorageDriver","w":"@proteinjs/db-file/FileStorageDriver","value":"implements interface"}]}';
|
|
13
13
|
|
|
14
14
|
/** Generate Source Links */
|
|
15
15
|
|
|
16
16
|
import { GoogleCloudStorageDriver } from '../src/GoogleCloudStorageDriver';
|
|
17
|
-
import { GoogleCloudStorageTableWatcher } from '../src/GoogleCloudStorageTableWatcher';
|
|
18
17
|
|
|
19
18
|
const sourceLinks = {
|
|
20
19
|
'@proteinjs/db-file-storage-driver-gcs/GoogleCloudStorageDriver': GoogleCloudStorageDriver,
|
|
21
|
-
'@proteinjs/db-file-storage-driver-gcs/GoogleCloudStorageTableWatcher': GoogleCloudStorageTableWatcher,
|
|
22
20
|
};
|
|
23
21
|
|
|
24
22
|
/** Load Source Graph and Links */
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@proteinjs/db-file-storage-driver-gcs",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.4.1",
|
|
4
4
|
"description": "File storage in Google Cloud Storage",
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public"
|
|
@@ -18,12 +18,13 @@
|
|
|
18
18
|
"scripts": {
|
|
19
19
|
"clean": "rm -rf dist/ node_modules/ generated/",
|
|
20
20
|
"build": "reflection-build && tsc",
|
|
21
|
+
"test": "jest --runInBand --passWithNoTests",
|
|
21
22
|
"watch": "reflection-watch"
|
|
22
23
|
},
|
|
23
24
|
"dependencies": {
|
|
24
25
|
"@google-cloud/storage": "7.11.2",
|
|
25
|
-
"@proteinjs/db": "^1.
|
|
26
|
-
"@proteinjs/db-file": "^1.
|
|
26
|
+
"@proteinjs/db": "^1.34.1",
|
|
27
|
+
"@proteinjs/db-file": "^1.5.1",
|
|
27
28
|
"@proteinjs/logger": "^1.0.21",
|
|
28
29
|
"@proteinjs/reflection": "^1.1.12"
|
|
29
30
|
},
|
|
@@ -42,5 +43,5 @@
|
|
|
42
43
|
},
|
|
43
44
|
"main": "./dist/generated/index.js",
|
|
44
45
|
"types": "./dist/generated/index.d.ts",
|
|
45
|
-
"gitHead": "
|
|
46
|
+
"gitHead": "a5a56218a5757e47576cbe79858c9aacc6026816"
|
|
46
47
|
}
|
|
@@ -5,6 +5,10 @@ import {
|
|
|
5
5
|
getDefaultGoogleCloudStorageConfigFactory,
|
|
6
6
|
} from './DefaultGoogleCloudStorageConfigFactory';
|
|
7
7
|
|
|
8
|
+
/** Signed URLs are short-lived read capabilities minted per serve — long enough to load and seek
|
|
9
|
+
* a video, short enough that a leaked URL goes stale quickly. */
|
|
10
|
+
const DEFAULT_SIGNED_URL_TTL_MS = 15 * 60 * 1000;
|
|
11
|
+
|
|
8
12
|
export class GoogleCloudStorageDriver implements FileStorageDriver {
|
|
9
13
|
private storage: Storage;
|
|
10
14
|
private bucketName: string;
|
|
@@ -15,22 +19,14 @@ export class GoogleCloudStorageDriver implements FileStorageDriver {
|
|
|
15
19
|
this.bucketName = bucketName;
|
|
16
20
|
}
|
|
17
21
|
|
|
18
|
-
private getDefaultConfig(): GoogleCloudStorageConfig {
|
|
19
|
-
const defaultConfigFactory = getDefaultGoogleCloudStorageConfigFactory();
|
|
20
|
-
if (!defaultConfigFactory) {
|
|
21
|
-
throw new Error(
|
|
22
|
-
`Unable to find a @proteinjs/db-file-storage-driver-gcs/DefaultGoogleCloudStorageConfigFactory implementation. Either implement DefaultGoogleCloudStorageConfigFactory or pass in a config when instantiating GoogleCloudStorageDriver.`
|
|
23
|
-
);
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
return defaultConfigFactory.getConfig();
|
|
27
|
-
}
|
|
28
|
-
|
|
29
22
|
async createFile(file: File, fileData: string): Promise<void> {
|
|
30
23
|
const bucket = this.storage.bucket(this.bucketName);
|
|
31
24
|
const gcsFile = bucket.file(file.id);
|
|
32
25
|
|
|
33
|
-
|
|
26
|
+
// The GCS object stores the file's TRUE bytes (the interface string is base64 transport).
|
|
27
|
+
// Raw bytes at rest are what make signed-URL serving correct: the browser reads the object
|
|
28
|
+
// directly, so base64 text at rest would corrupt every binary served that way.
|
|
29
|
+
await gcsFile.save(Buffer.from(fileData, 'base64'), {
|
|
34
30
|
metadata: {
|
|
35
31
|
contentType: file.type,
|
|
36
32
|
metadata: {
|
|
@@ -45,12 +41,12 @@ export class GoogleCloudStorageDriver implements FileStorageDriver {
|
|
|
45
41
|
async getFileData(fileId: string): Promise<string> {
|
|
46
42
|
const file = this.storage.bucket(this.bucketName).file(fileId);
|
|
47
43
|
const [fileContent] = await file.download();
|
|
48
|
-
return fileContent.toString();
|
|
44
|
+
return fileContent.toString('base64');
|
|
49
45
|
}
|
|
50
46
|
|
|
51
47
|
async updateFileData(fileId: string, data: string): Promise<void> {
|
|
52
48
|
const file = this.storage.bucket(this.bucketName).file(fileId);
|
|
53
|
-
await file.save(data);
|
|
49
|
+
await file.save(Buffer.from(data, 'base64'));
|
|
54
50
|
}
|
|
55
51
|
|
|
56
52
|
async updateFile(file: File): Promise<void> {
|
|
@@ -64,4 +60,32 @@ export class GoogleCloudStorageDriver implements FileStorageDriver {
|
|
|
64
60
|
},
|
|
65
61
|
});
|
|
66
62
|
}
|
|
63
|
+
|
|
64
|
+
async getSignedUrl(fileId: string, options?: { ttlMs?: number }): Promise<string> {
|
|
65
|
+
const gcsFile = this.storage.bucket(this.bucketName).file(fileId);
|
|
66
|
+
const [url] = await gcsFile.getSignedUrl({
|
|
67
|
+
version: 'v4',
|
|
68
|
+
action: 'read',
|
|
69
|
+
expires: Date.now() + (options?.ttlMs ?? DEFAULT_SIGNED_URL_TTL_MS),
|
|
70
|
+
});
|
|
71
|
+
return url;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
async deleteFile(fileId: string): Promise<void> {
|
|
75
|
+
const gcsFile = this.storage.bucket(this.bucketName).file(fileId);
|
|
76
|
+
// ignoreNotFound implements the driver contract's idempotency: a retried row delete must not
|
|
77
|
+
// wedge because a prior attempt already removed the blob. Every other failure throws loudly.
|
|
78
|
+
await gcsFile.delete({ ignoreNotFound: true });
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
private getDefaultConfig(): GoogleCloudStorageConfig {
|
|
82
|
+
const defaultConfigFactory = getDefaultGoogleCloudStorageConfigFactory();
|
|
83
|
+
if (!defaultConfigFactory) {
|
|
84
|
+
throw new Error(
|
|
85
|
+
`Unable to find a @proteinjs/db-file-storage-driver-gcs/DefaultGoogleCloudStorageConfigFactory implementation. Either implement DefaultGoogleCloudStorageConfigFactory or pass in a config when instantiating GoogleCloudStorageDriver.`
|
|
86
|
+
);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
return defaultConfigFactory.getConfig();
|
|
90
|
+
}
|
|
67
91
|
}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { GoogleCloudStorageDriver } from '../src/GoogleCloudStorageDriver';
|
|
2
|
+
|
|
3
|
+
const saveMock = jest.fn();
|
|
4
|
+
const downloadMock = jest.fn();
|
|
5
|
+
const fileMock = jest.fn(() => ({ save: saveMock, download: downloadMock }));
|
|
6
|
+
const bucketMock = jest.fn(() => ({ file: fileMock }));
|
|
7
|
+
|
|
8
|
+
jest.mock('@google-cloud/storage', () => ({
|
|
9
|
+
Storage: jest.fn(() => ({ bucket: bucketMock })),
|
|
10
|
+
}));
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* The FileStorageDriver contract: `fileData` strings crossing the interface are base64 of the
|
|
14
|
+
* file's TRUE bytes, and the GCS object stores the true bytes — never base64 text. That at-rest
|
|
15
|
+
* shape is what signed-URL serving (GET /file/:id 302 redirect) depends on: GCS hands the browser
|
|
16
|
+
* the real bytes with the stored contentType, so binaries (video, pdf, gif) arrive byte-identical
|
|
17
|
+
* without transiting the app server.
|
|
18
|
+
*/
|
|
19
|
+
describe('GoogleCloudStorageDriver byte encoding', () => {
|
|
20
|
+
const driver = new GoogleCloudStorageDriver({ projectId: 'test-project', bucketName: 'test-bucket' });
|
|
21
|
+
// Every byte value once — a payload that corrupts under any text/base64 mix-up.
|
|
22
|
+
const rawBytes = Buffer.from(Array.from({ length: 256 }, (_, i) => i));
|
|
23
|
+
const base64 = rawBytes.toString('base64');
|
|
24
|
+
|
|
25
|
+
beforeEach(() => {
|
|
26
|
+
saveMock.mockReset();
|
|
27
|
+
downloadMock.mockReset();
|
|
28
|
+
fileMock.mockClear();
|
|
29
|
+
bucketMock.mockClear();
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
it('createFile stores the decoded true bytes (not base64 text), keeping the content metadata', async () => {
|
|
33
|
+
saveMock.mockResolvedValue(undefined);
|
|
34
|
+
|
|
35
|
+
await driver.createFile(
|
|
36
|
+
{ id: 'file-1', name: 'clip.mp4', type: 'video/mp4', size: rawBytes.length } as never,
|
|
37
|
+
base64
|
|
38
|
+
);
|
|
39
|
+
|
|
40
|
+
expect(fileMock).toHaveBeenCalledWith('file-1');
|
|
41
|
+
const [storedData, saveOptions] = saveMock.mock.calls[0];
|
|
42
|
+
expect(Buffer.isBuffer(storedData)).toBe(true);
|
|
43
|
+
expect(Buffer.compare(storedData, rawBytes)).toBe(0);
|
|
44
|
+
expect(saveOptions.metadata.contentType).toEqual('video/mp4');
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
it('getFileData returns base64 of the stored true bytes', async () => {
|
|
48
|
+
downloadMock.mockResolvedValue([rawBytes]);
|
|
49
|
+
|
|
50
|
+
const fileData = await driver.getFileData('file-1');
|
|
51
|
+
|
|
52
|
+
expect(fileData).toEqual(base64);
|
|
53
|
+
expect(Buffer.compare(Buffer.from(fileData, 'base64'), rawBytes)).toBe(0);
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
it('updateFileData stores the decoded true bytes', async () => {
|
|
57
|
+
saveMock.mockResolvedValue(undefined);
|
|
58
|
+
|
|
59
|
+
await driver.updateFileData('file-1', base64);
|
|
60
|
+
|
|
61
|
+
const [storedData] = saveMock.mock.calls[0];
|
|
62
|
+
expect(Buffer.isBuffer(storedData)).toBe(true);
|
|
63
|
+
expect(Buffer.compare(storedData, rawBytes)).toBe(0);
|
|
64
|
+
});
|
|
65
|
+
});
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { GoogleCloudStorageDriver } from '../src/GoogleCloudStorageDriver';
|
|
2
|
+
|
|
3
|
+
const deleteMock = jest.fn();
|
|
4
|
+
const fileMock = jest.fn(() => ({ delete: deleteMock }));
|
|
5
|
+
const bucketMock = jest.fn(() => ({ file: fileMock }));
|
|
6
|
+
|
|
7
|
+
jest.mock('@google-cloud/storage', () => ({
|
|
8
|
+
Storage: jest.fn(() => ({ bucket: bucketMock })),
|
|
9
|
+
}));
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* The driver is a thin adapter over the GCS SDK, so this asserts the adapter's contract against
|
|
13
|
+
* a mocked SDK (tests never touch real GCS): the blob delete is issued idempotently
|
|
14
|
+
* (ignoreNotFound — a retried row delete must not wedge on an already-deleted blob), and real
|
|
15
|
+
* SDK failures propagate loudly instead of being swallowed.
|
|
16
|
+
*/
|
|
17
|
+
describe('GoogleCloudStorageDriver.deleteFile', () => {
|
|
18
|
+
const driver = new GoogleCloudStorageDriver({ projectId: 'test-project', bucketName: 'test-bucket' });
|
|
19
|
+
|
|
20
|
+
beforeEach(() => {
|
|
21
|
+
deleteMock.mockReset();
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
it('deletes the blob for the file id, idempotently on missing blobs', async () => {
|
|
25
|
+
deleteMock.mockResolvedValue(undefined);
|
|
26
|
+
|
|
27
|
+
await driver.deleteFile('file-1');
|
|
28
|
+
|
|
29
|
+
expect(bucketMock).toHaveBeenCalledWith('test-bucket');
|
|
30
|
+
expect(fileMock).toHaveBeenCalledWith('file-1');
|
|
31
|
+
expect(deleteMock).toHaveBeenCalledWith({ ignoreNotFound: true });
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
it('propagates real SDK failures loudly', async () => {
|
|
35
|
+
deleteMock.mockRejectedValue(new Error('storage.objects.delete permission denied'));
|
|
36
|
+
|
|
37
|
+
await expect(driver.deleteFile('file-2')).rejects.toThrow('storage.objects.delete permission denied');
|
|
38
|
+
});
|
|
39
|
+
});
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { GoogleCloudStorageDriver } from '../src/GoogleCloudStorageDriver';
|
|
2
|
+
|
|
3
|
+
const getSignedUrlMock = jest.fn();
|
|
4
|
+
const fileMock = jest.fn(() => ({ getSignedUrl: getSignedUrlMock }));
|
|
5
|
+
const bucketMock = jest.fn(() => ({ file: fileMock }));
|
|
6
|
+
|
|
7
|
+
jest.mock('@google-cloud/storage', () => ({
|
|
8
|
+
Storage: jest.fn(() => ({ bucket: bucketMock })),
|
|
9
|
+
}));
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Signed URLs are the serving path (GET /file/:id 302-redirects to them): read-only, short-lived
|
|
13
|
+
* v4 URLs minted per request. The driver is a thin adapter, so this asserts the adapter's
|
|
14
|
+
* contract against a mocked SDK: read action, v4 signing, TTL-derived expiry (default and
|
|
15
|
+
* caller-provided), and loud failure propagation.
|
|
16
|
+
*/
|
|
17
|
+
describe('GoogleCloudStorageDriver.getSignedUrl', () => {
|
|
18
|
+
const driver = new GoogleCloudStorageDriver({ projectId: 'test-project', bucketName: 'test-bucket' });
|
|
19
|
+
const now = 1755400000000;
|
|
20
|
+
|
|
21
|
+
beforeEach(() => {
|
|
22
|
+
getSignedUrlMock.mockReset();
|
|
23
|
+
fileMock.mockClear();
|
|
24
|
+
bucketMock.mockClear();
|
|
25
|
+
jest.spyOn(Date, 'now').mockReturnValue(now);
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
afterEach(() => {
|
|
29
|
+
jest.restoreAllMocks();
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
it('mints a read-only v4 URL with the default 15-minute TTL', async () => {
|
|
33
|
+
getSignedUrlMock.mockResolvedValue(['https://storage.googleapis.com/test-bucket/file-1?signed']);
|
|
34
|
+
|
|
35
|
+
const url = await driver.getSignedUrl('file-1');
|
|
36
|
+
|
|
37
|
+
expect(bucketMock).toHaveBeenCalledWith('test-bucket');
|
|
38
|
+
expect(fileMock).toHaveBeenCalledWith('file-1');
|
|
39
|
+
expect(getSignedUrlMock).toHaveBeenCalledWith({
|
|
40
|
+
version: 'v4',
|
|
41
|
+
action: 'read',
|
|
42
|
+
expires: now + 15 * 60 * 1000,
|
|
43
|
+
});
|
|
44
|
+
expect(url).toEqual('https://storage.googleapis.com/test-bucket/file-1?signed');
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
it('honors a caller-provided TTL', async () => {
|
|
48
|
+
getSignedUrlMock.mockResolvedValue(['https://storage.googleapis.com/test-bucket/file-2?signed']);
|
|
49
|
+
|
|
50
|
+
await driver.getSignedUrl('file-2', { ttlMs: 60_000 });
|
|
51
|
+
|
|
52
|
+
expect(getSignedUrlMock).toHaveBeenCalledWith({
|
|
53
|
+
version: 'v4',
|
|
54
|
+
action: 'read',
|
|
55
|
+
expires: now + 60_000,
|
|
56
|
+
});
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
it('propagates real SDK failures loudly', async () => {
|
|
60
|
+
getSignedUrlMock.mockRejectedValue(new Error('iam.serviceAccounts.signBlob permission denied'));
|
|
61
|
+
|
|
62
|
+
await expect(driver.getSignedUrl('file-3')).rejects.toThrow('iam.serviceAccounts.signBlob permission denied');
|
|
63
|
+
});
|
|
64
|
+
});
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
import { QueryBuilder, Table, TableWatcher } from '@proteinjs/db';
|
|
2
|
-
import { File } from '@proteinjs/db-file';
|
|
3
|
-
export declare class GoogleCloudStorageTableWatcher implements TableWatcher<File> {
|
|
4
|
-
private logger;
|
|
5
|
-
private storage;
|
|
6
|
-
private bucketName;
|
|
7
|
-
constructor();
|
|
8
|
-
private getConfig;
|
|
9
|
-
name(): string;
|
|
10
|
-
table(): Table<File>;
|
|
11
|
-
beforeDelete<T extends File>(recordsToDelete: T[], initialQb: QueryBuilder<T>, deleteQb: QueryBuilder<T>): Promise<void>;
|
|
12
|
-
}
|
|
13
|
-
//# sourceMappingURL=GoogleCloudStorageTableWatcher.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"GoogleCloudStorageTableWatcher.d.ts","sourceRoot":"","sources":["../../src/GoogleCloudStorageTableWatcher.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,YAAY,EAAE,KAAK,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAClE,OAAO,EAAE,IAAI,EAAa,MAAM,oBAAoB,CAAC;AAOrD,qBAAa,8BAA+B,YAAW,YAAY,CAAC,IAAI,CAAC;IACvE,OAAO,CAAC,MAAM,CAA+C;IAC7D,OAAO,CAAC,OAAO,CAAU;IACzB,OAAO,CAAC,UAAU,CAAS;;IAQ3B,OAAO,CAAC,SAAS;IAWjB,IAAI,IAAI,MAAM;IAId,KAAK,IAAI,KAAK,CAAC,IAAI,CAAC;IAId,YAAY,CAAC,CAAC,SAAS,IAAI,EAC/B,eAAe,EAAE,CAAC,EAAE,EACpB,SAAS,EAAE,YAAY,CAAC,CAAC,CAAC,EAC1B,QAAQ,EAAE,YAAY,CAAC,CAAC,CAAC,GACxB,OAAO,CAAC,IAAI,CAAC;CAYjB"}
|
|
@@ -1,108 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __assign = (this && this.__assign) || function () {
|
|
3
|
-
__assign = Object.assign || function(t) {
|
|
4
|
-
for (var s, i = 1, n = arguments.length; i < n; i++) {
|
|
5
|
-
s = arguments[i];
|
|
6
|
-
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
|
|
7
|
-
t[p] = s[p];
|
|
8
|
-
}
|
|
9
|
-
return t;
|
|
10
|
-
};
|
|
11
|
-
return __assign.apply(this, arguments);
|
|
12
|
-
};
|
|
13
|
-
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
14
|
-
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
15
|
-
return new (P || (P = Promise))(function (resolve, reject) {
|
|
16
|
-
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
17
|
-
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
18
|
-
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
19
|
-
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
20
|
-
});
|
|
21
|
-
};
|
|
22
|
-
var __generator = (this && this.__generator) || function (thisArg, body) {
|
|
23
|
-
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
|
|
24
|
-
return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
|
|
25
|
-
function verb(n) { return function (v) { return step([n, v]); }; }
|
|
26
|
-
function step(op) {
|
|
27
|
-
if (f) throw new TypeError("Generator is already executing.");
|
|
28
|
-
while (g && (g = 0, op[0] && (_ = 0)), _) try {
|
|
29
|
-
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
|
|
30
|
-
if (y = 0, t) op = [op[0] & 2, t.value];
|
|
31
|
-
switch (op[0]) {
|
|
32
|
-
case 0: case 1: t = op; break;
|
|
33
|
-
case 4: _.label++; return { value: op[1], done: false };
|
|
34
|
-
case 5: _.label++; y = op[1]; op = [0]; continue;
|
|
35
|
-
case 7: op = _.ops.pop(); _.trys.pop(); continue;
|
|
36
|
-
default:
|
|
37
|
-
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
|
|
38
|
-
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
|
|
39
|
-
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
|
|
40
|
-
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
|
|
41
|
-
if (t[2]) _.ops.pop();
|
|
42
|
-
_.trys.pop(); continue;
|
|
43
|
-
}
|
|
44
|
-
op = body.call(thisArg, _);
|
|
45
|
-
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
|
|
46
|
-
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
|
|
47
|
-
}
|
|
48
|
-
};
|
|
49
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
50
|
-
exports.GoogleCloudStorageTableWatcher = void 0;
|
|
51
|
-
var storage_1 = require("@google-cloud/storage");
|
|
52
|
-
var db_file_1 = require("@proteinjs/db-file");
|
|
53
|
-
var logger_1 = require("@proteinjs/logger");
|
|
54
|
-
var DefaultGoogleCloudStorageConfigFactory_1 = require("./DefaultGoogleCloudStorageConfigFactory");
|
|
55
|
-
var GoogleCloudStorageTableWatcher = /** @class */ (function () {
|
|
56
|
-
function GoogleCloudStorageTableWatcher() {
|
|
57
|
-
this.logger = new logger_1.Logger({ name: this.constructor.name });
|
|
58
|
-
var _a = this.getConfig(), projectId = _a.projectId, bucketName = _a.bucketName, storageOptions = _a.storageOptions;
|
|
59
|
-
this.storage = new storage_1.Storage(__assign(__assign({}, storageOptions), { projectId: projectId }));
|
|
60
|
-
this.bucketName = bucketName;
|
|
61
|
-
}
|
|
62
|
-
GoogleCloudStorageTableWatcher.prototype.getConfig = function () {
|
|
63
|
-
var defaultConfigFactory = (0, DefaultGoogleCloudStorageConfigFactory_1.getDefaultGoogleCloudStorageConfigFactory)();
|
|
64
|
-
if (!defaultConfigFactory) {
|
|
65
|
-
throw new Error("Unable to find a @proteinjs/db-file-storage-driver-gcs/DefaultGoogleCloudStorageConfigFactory implementation when creating GoogleCloudStorageTableWatcher");
|
|
66
|
-
}
|
|
67
|
-
return defaultConfigFactory.getConfig();
|
|
68
|
-
};
|
|
69
|
-
GoogleCloudStorageTableWatcher.prototype.name = function () {
|
|
70
|
-
return this.constructor.name;
|
|
71
|
-
};
|
|
72
|
-
GoogleCloudStorageTableWatcher.prototype.table = function () {
|
|
73
|
-
return new db_file_1.FileTable();
|
|
74
|
-
};
|
|
75
|
-
GoogleCloudStorageTableWatcher.prototype.beforeDelete = function (recordsToDelete, initialQb, deleteQb) {
|
|
76
|
-
return __awaiter(this, void 0, void 0, function () {
|
|
77
|
-
var fileIdsToDelete, _i, fileIdsToDelete_1, fileId, file;
|
|
78
|
-
return __generator(this, function (_a) {
|
|
79
|
-
switch (_a.label) {
|
|
80
|
-
case 0:
|
|
81
|
-
fileIdsToDelete = recordsToDelete.map(function (record) { return record.id; });
|
|
82
|
-
_i = 0, fileIdsToDelete_1 = fileIdsToDelete;
|
|
83
|
-
_a.label = 1;
|
|
84
|
-
case 1:
|
|
85
|
-
if (!(_i < fileIdsToDelete_1.length)) return [3 /*break*/, 4];
|
|
86
|
-
fileId = fileIdsToDelete_1[_i];
|
|
87
|
-
file = this.storage.bucket(this.bucketName).file(fileId);
|
|
88
|
-
return [4 /*yield*/, file.delete()];
|
|
89
|
-
case 2:
|
|
90
|
-
_a.sent();
|
|
91
|
-
_a.label = 3;
|
|
92
|
-
case 3:
|
|
93
|
-
_i++;
|
|
94
|
-
return [3 /*break*/, 1];
|
|
95
|
-
case 4:
|
|
96
|
-
this.logger.info({
|
|
97
|
-
message: "Deleted the following files from Google Cloud Storage",
|
|
98
|
-
obj: { deletedFileIds: fileIdsToDelete },
|
|
99
|
-
});
|
|
100
|
-
return [2 /*return*/];
|
|
101
|
-
}
|
|
102
|
-
});
|
|
103
|
-
});
|
|
104
|
-
};
|
|
105
|
-
return GoogleCloudStorageTableWatcher;
|
|
106
|
-
}());
|
|
107
|
-
exports.GoogleCloudStorageTableWatcher = GoogleCloudStorageTableWatcher;
|
|
108
|
-
//# sourceMappingURL=GoogleCloudStorageTableWatcher.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"GoogleCloudStorageTableWatcher.js","sourceRoot":"","sources":["../../src/GoogleCloudStorageTableWatcher.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,iDAAgD;AAEhD,8CAAqD;AACrD,4CAA2C;AAC3C,mGAGkD;AAElD;IAKE;QAJQ,WAAM,GAAG,IAAI,eAAM,CAAC,EAAE,IAAI,EAAE,IAAI,CAAC,WAAW,CAAC,IAAI,EAAE,CAAC,CAAC;QAKrD,IAAA,KAA4C,IAAI,CAAC,SAAS,EAAE,EAA1D,SAAS,eAAA,EAAE,UAAU,gBAAA,EAAE,cAAc,oBAAqB,CAAC;QACnE,IAAI,CAAC,OAAO,GAAG,IAAI,iBAAO,uBAAM,cAAc,KAAE,SAAS,WAAA,IAAG,CAAC;QAC7D,IAAI,CAAC,UAAU,GAAG,UAAU,CAAC;IAC/B,CAAC;IAEO,kDAAS,GAAjB;QACE,IAAM,oBAAoB,GAAG,IAAA,kFAAyC,GAAE,CAAC;QACzE,IAAI,CAAC,oBAAoB,EAAE;YACzB,MAAM,IAAI,KAAK,CACb,2JAA2J,CAC5J,CAAC;SACH;QAED,OAAO,oBAAoB,CAAC,SAAS,EAAE,CAAC;IAC1C,CAAC;IAED,6CAAI,GAAJ;QACE,OAAO,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC;IAC/B,CAAC;IAED,8CAAK,GAAL;QACE,OAAO,IAAI,mBAAS,EAAE,CAAC;IACzB,CAAC;IAEK,qDAAY,GAAlB,UACE,eAAoB,EACpB,SAA0B,EAC1B,QAAyB;;;;;;wBAEnB,eAAe,GAAG,eAAe,CAAC,GAAG,CAAC,UAAC,MAAM,IAAK,OAAA,MAAM,CAAC,EAAE,EAAT,CAAS,CAAC,CAAC;8BAC/B,EAAf,mCAAe;;;6BAAf,CAAA,6BAAe,CAAA;wBAAzB,MAAM;wBACT,IAAI,GAAG,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;wBAC/D,qBAAM,IAAI,CAAC,MAAM,EAAE,EAAA;;wBAAnB,SAAmB,CAAC;;;wBAFD,IAAe,CAAA;;;wBAKpC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC;4BACf,OAAO,EAAE,uDAAuD;4BAChE,GAAG,EAAE,EAAE,cAAc,EAAE,eAAe,EAAE;yBACzC,CAAC,CAAC;;;;;KACJ;IACH,qCAAC;AAAD,CAAC,AA9CD,IA8CC;AA9CY,wEAA8B"}
|
|
@@ -1,56 +0,0 @@
|
|
|
1
|
-
import { Storage } from '@google-cloud/storage';
|
|
2
|
-
import { QueryBuilder, Table, TableWatcher } from '@proteinjs/db';
|
|
3
|
-
import { File, FileTable } from '@proteinjs/db-file';
|
|
4
|
-
import { Logger } from '@proteinjs/logger';
|
|
5
|
-
import {
|
|
6
|
-
GoogleCloudStorageConfig,
|
|
7
|
-
getDefaultGoogleCloudStorageConfigFactory,
|
|
8
|
-
} from './DefaultGoogleCloudStorageConfigFactory';
|
|
9
|
-
|
|
10
|
-
export class GoogleCloudStorageTableWatcher implements TableWatcher<File> {
|
|
11
|
-
private logger = new Logger({ name: this.constructor.name });
|
|
12
|
-
private storage: Storage;
|
|
13
|
-
private bucketName: string;
|
|
14
|
-
|
|
15
|
-
constructor() {
|
|
16
|
-
const { projectId, bucketName, storageOptions } = this.getConfig();
|
|
17
|
-
this.storage = new Storage({ ...storageOptions, projectId });
|
|
18
|
-
this.bucketName = bucketName;
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
private getConfig(): GoogleCloudStorageConfig {
|
|
22
|
-
const defaultConfigFactory = getDefaultGoogleCloudStorageConfigFactory();
|
|
23
|
-
if (!defaultConfigFactory) {
|
|
24
|
-
throw new Error(
|
|
25
|
-
`Unable to find a @proteinjs/db-file-storage-driver-gcs/DefaultGoogleCloudStorageConfigFactory implementation when creating GoogleCloudStorageTableWatcher`
|
|
26
|
-
);
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
return defaultConfigFactory.getConfig();
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
name(): string {
|
|
33
|
-
return this.constructor.name;
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
table(): Table<File> {
|
|
37
|
-
return new FileTable();
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
async beforeDelete<T extends File>(
|
|
41
|
-
recordsToDelete: T[],
|
|
42
|
-
initialQb: QueryBuilder<T>,
|
|
43
|
-
deleteQb: QueryBuilder<T>
|
|
44
|
-
): Promise<void> {
|
|
45
|
-
const fileIdsToDelete = recordsToDelete.map((record) => record.id);
|
|
46
|
-
for (const fileId of fileIdsToDelete) {
|
|
47
|
-
const file = this.storage.bucket(this.bucketName).file(fileId);
|
|
48
|
-
await file.delete();
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
this.logger.info({
|
|
52
|
-
message: `Deleted the following files from Google Cloud Storage`,
|
|
53
|
-
obj: { deletedFileIds: fileIdsToDelete },
|
|
54
|
-
});
|
|
55
|
-
}
|
|
56
|
-
}
|