@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 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;AAyB/B,cAAc,UAAU,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"}
@@ -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\":\"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\":[]},{\"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}}]}],\"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\"},{\"v\":\"@proteinjs/db-file-storage-driver-gcs/GoogleCloudStorageTableWatcher\",\"value\":{\"packageName\":\"@proteinjs/db-file-storage-driver-gcs\",\"name\":\"GoogleCloudStorageTableWatcher\",\"filePath\":\"/home/runner/work/db/db/packages/file-storage-drivers/google-cloud-storage/src/GoogleCloudStorageTableWatcher.ts\",\"qualifiedName\":\"@proteinjs/db-file-storage-driver-gcs/GoogleCloudStorageTableWatcher\",\"isAbstract\":false,\"isStatic\":false,\"visibility\":\"public\",\"properties\":[{\"name\":\"logger\",\"type\":null,\"isOptional\":false,\"isAbstract\":false,\"isStatic\":false,\"visibility\":\"private\"},{\"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\":\"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\":false,\"isStatic\":false,\"visibility\":\"private\",\"parameters\":[]},{\"name\":\"name\",\"returnType\":{\"packageName\":\"\",\"name\":\"string\",\"filePath\":null,\"qualifiedName\":\"/string\",\"typeParameters\":null,\"directParents\":null},\"isAsync\":false,\"isOptional\":false,\"isAbstract\":false,\"isStatic\":false,\"visibility\":\"public\",\"parameters\":[]},{\"name\":\"table\",\"returnType\":{\"packageName\":\"\",\"name\":\"Table<File>\",\"filePath\":null,\"qualifiedName\":\"/Table<File>\",\"typeParameters\":null,\"directParents\":null},\"isAsync\":false,\"isOptional\":false,\"isAbstract\":false,\"isStatic\":false,\"visibility\":\"public\",\"parameters\":[]},{\"name\":\"beforeDelete\",\"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\":\"recordsToDelete\",\"type\":{\"packageName\":\"\",\"name\":\"T[]\",\"filePath\":null,\"qualifiedName\":\"/T[]\",\"typeParameters\":null,\"directParents\":null}},{\"name\":\"initialQb\",\"type\":{\"packageName\":\"\",\"name\":\"QueryBuilder<T>\",\"filePath\":null,\"qualifiedName\":\"/QueryBuilder<T>\",\"typeParameters\":null,\"directParents\":null}},{\"name\":\"deleteQb\",\"type\":{\"packageName\":\"\",\"name\":\"QueryBuilder<T>\",\"filePath\":null,\"qualifiedName\":\"/QueryBuilder<T>\",\"typeParameters\":null,\"directParents\":null}}]}],\"typeParameters\":[],\"directParentInterfaces\":[{\"packageName\":\"@proteinjs/db\",\"name\":\"TableWatcher\",\"filePath\":null,\"qualifiedName\":\"@proteinjs/db/TableWatcher\",\"properties\":[],\"methods\":[],\"typeParameters\":[\"@proteinjs/db-file/File\"],\"directParents\":[]}],\"directParentClasses\":[],\"sourceType\":2}},{\"v\":\"@proteinjs/db/TableWatcher\"}],\"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\"},{\"v\":\"@proteinjs/db-file-storage-driver-gcs/GoogleCloudStorageTableWatcher\",\"w\":\"@proteinjs/db/TableWatcher\",\"value\":\"implements interface\"}]}";
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,2rSAA2rS,CAAC;AAGhtS,4BAA4B;AAE5B,4EAA2E;AAC3E,wFAAuF;AAEvF,IAAM,WAAW,GAAG;IACnB,gEAAgE,EAAE,mDAAwB;IAC1F,sEAAsE,EAAE,+DAA8B;CACtG,CAAC;AAGF,kCAAkC;AAElC,oDAAyD;AACzD,6BAAgB,CAAC,KAAK,CAAC,WAAW,EAAE,WAAW,CAAC,CAAC;AAGjD,2CAAyB"}
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;AAElD,qBAAa,wBAAyB,YAAW,iBAAiB;IAChE,OAAO,CAAC,OAAO,CAAU;IACzB,OAAO,CAAC,UAAU,CAAS;gBAEf,MAAM,CAAC,EAAE,wBAAwB;IAM7C,OAAO,CAAC,gBAAgB;IAWlB,UAAU,CAAC,IAAI,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAgBvD,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;CAW5C"}
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
- return [4 /*yield*/, gcsFile.save(fileData, {
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;IAEO,mDAAgB,GAAxB;QACE,IAAM,oBAAoB,GAAG,IAAA,kFAAyC,GAAE,CAAC;QACzE,IAAI,CAAC,oBAAoB,EAAE;YACzB,MAAM,IAAI,KAAK,CACb,wOAAwO,CACzO,CAAC;SACH;QAED,OAAO,oBAAoB,CAAC,SAAS,EAAE,CAAC;IAC1C,CAAC;IAEK,6CAAU,GAAhB,UAAiB,IAAU,EAAE,QAAgB;;;;;;wBACrC,MAAM,GAAG,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;wBAC9C,OAAO,GAAG,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;wBAErC,qBAAM,OAAO,CAAC,IAAI,CAAC,QAAQ,EAAE;gCAC3B,QAAQ,EAAE;oCACR,WAAW,EAAE,IAAI,CAAC,IAAI;oCACtB,QAAQ,EAAE;wCACR,MAAM,EAAE,IAAI,CAAC,EAAE;wCACf,QAAQ,EAAE,IAAI,CAAC,IAAI;wCACnB,QAAQ,EAAE,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE;qCAC/B;iCACF;6BACF,CAAC,EAAA;;wBATF,SASE,CAAC;;;;;KACJ;IAEK,8CAAW,GAAjB,UAAkB,MAAc;;;;;;wBACxB,IAAI,GAAG,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;wBACzC,qBAAM,IAAI,CAAC,QAAQ,EAAE,EAAA;;wBAApC,WAAW,GAAI,CAAA,SAAqB,CAAA,GAAzB;wBAClB,sBAAO,WAAW,CAAC,QAAQ,EAAE,EAAC;;;;KAC/B;IAEK,iDAAc,GAApB,UAAqB,MAAc,EAAE,IAAY;;;;;;wBACzC,IAAI,GAAG,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;wBAC/D,qBAAM,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,EAAA;;wBAArB,SAAqB,CAAC;;;;;KACvB;IAEK,6CAAU,GAAhB,UAAiB,IAAU;;;;;;wBACnB,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;wBACnE,qBAAM,OAAO,CAAC,WAAW,CAAC;gCACxB,WAAW,EAAE,IAAI,CAAC,IAAI;gCACtB,QAAQ,EAAE;oCACR,MAAM,EAAE,IAAI,CAAC,EAAE;oCACf,QAAQ,EAAE,IAAI,CAAC,IAAI;oCACnB,QAAQ,EAAE,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE;iCAC/B;6BACF,CAAC,EAAA;;wBAPF,SAOE,CAAC;;;;;KACJ;IACH,+BAAC;AAAD,CAAC,AA3DD,IA2DC;AA3DY,4DAAwB"}
1
+ {"version":3,"file":"GoogleCloudStorageDriver.js","sourceRoot":"","sources":["../../src/GoogleCloudStorageDriver.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,iDAAgD;AAEhD,mGAGkD;AAElD;kEACkE;AAClE,IAAM,yBAAyB,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC;AAEjD;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;IAEK,6CAAU,GAAhB,UAAiB,IAAU,EAAE,QAAgB;;;;;;wBACrC,MAAM,GAAG,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;wBAC9C,OAAO,GAAG,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;wBAErC,0FAA0F;wBAC1F,2FAA2F;wBAC3F,+EAA+E;wBAC/E,qBAAM,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,QAAQ,EAAE,QAAQ,CAAC,EAAE;gCAClD,QAAQ,EAAE;oCACR,WAAW,EAAE,IAAI,CAAC,IAAI;oCACtB,QAAQ,EAAE;wCACR,MAAM,EAAE,IAAI,CAAC,EAAE;wCACf,QAAQ,EAAE,IAAI,CAAC,IAAI;wCACnB,QAAQ,EAAE,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE;qCAC/B;iCACF;6BACF,CAAC,EAAA;;wBAZF,0FAA0F;wBAC1F,2FAA2F;wBAC3F,+EAA+E;wBAC/E,SASE,CAAC;;;;;KACJ;IAEK,8CAAW,GAAjB,UAAkB,MAAc;;;;;;wBACxB,IAAI,GAAG,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;wBACzC,qBAAM,IAAI,CAAC,QAAQ,EAAE,EAAA;;wBAApC,WAAW,GAAI,CAAA,SAAqB,CAAA,GAAzB;wBAClB,sBAAO,WAAW,CAAC,QAAQ,CAAC,QAAQ,CAAC,EAAC;;;;KACvC;IAEK,iDAAc,GAApB,UAAqB,MAAc,EAAE,IAAY;;;;;;wBACzC,IAAI,GAAG,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;wBAC/D,qBAAM,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC,EAAA;;wBAA5C,SAA4C,CAAC;;;;;KAC9C;IAEK,6CAAU,GAAhB,UAAiB,IAAU;;;;;;wBACnB,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;wBACnE,qBAAM,OAAO,CAAC,WAAW,CAAC;gCACxB,WAAW,EAAE,IAAI,CAAC,IAAI;gCACtB,QAAQ,EAAE;oCACR,MAAM,EAAE,IAAI,CAAC,EAAE;oCACf,QAAQ,EAAE,IAAI,CAAC,IAAI;oCACnB,QAAQ,EAAE,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE;iCAC/B;6BACF,CAAC,EAAA;;wBAPF,SAOE,CAAC;;;;;KACJ;IAEK,+CAAY,GAAlB,UAAmB,MAAc,EAAE,OAA4B;;;;;;;wBACvD,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;wBACpD,qBAAM,OAAO,CAAC,YAAY,CAAC;gCACvC,OAAO,EAAE,IAAI;gCACb,MAAM,EAAE,MAAM;gCACd,OAAO,EAAE,IAAI,CAAC,GAAG,EAAE,GAAG,CAAC,MAAA,OAAO,aAAP,OAAO,uBAAP,OAAO,CAAE,KAAK,mCAAI,yBAAyB,CAAC;6BACpE,CAAC,EAAA;;wBAJK,GAAG,GAAI,CAAA,SAIZ,CAAA,GAJQ;wBAKV,sBAAO,GAAG,EAAC;;;;KACZ;IAEK,6CAAU,GAAhB,UAAiB,MAAc;;;;;;wBACvB,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;wBAClE,6FAA6F;wBAC7F,6FAA6F;wBAC7F,qBAAM,OAAO,CAAC,MAAM,CAAC,EAAE,cAAc,EAAE,IAAI,EAAE,CAAC,EAAA;;wBAF9C,6FAA6F;wBAC7F,6FAA6F;wBAC7F,SAA8C,CAAC;;;;;KAChD;IAEO,mDAAgB,GAAxB;QACE,IAAM,oBAAoB,GAAG,IAAA,kFAAyC,GAAE,CAAC;QACzE,IAAI,CAAC,oBAAoB,EAAE;YACzB,MAAM,IAAI,KAAK,CACb,wOAAwO,CACzO,CAAC;SACH;QAED,OAAO,oBAAoB,CAAC,SAAS,EAAE,CAAC;IAC1C,CAAC;IACH,+BAAC;AAAD,CAAC,AA/ED,IA+EC;AA/EY,4DAAwB"}
@@ -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":"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":[]},{"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}}]}],"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"},{"v":"@proteinjs/db-file-storage-driver-gcs/GoogleCloudStorageTableWatcher","value":{"packageName":"@proteinjs/db-file-storage-driver-gcs","name":"GoogleCloudStorageTableWatcher","filePath":"/home/runner/work/db/db/packages/file-storage-drivers/google-cloud-storage/src/GoogleCloudStorageTableWatcher.ts","qualifiedName":"@proteinjs/db-file-storage-driver-gcs/GoogleCloudStorageTableWatcher","isAbstract":false,"isStatic":false,"visibility":"public","properties":[{"name":"logger","type":null,"isOptional":false,"isAbstract":false,"isStatic":false,"visibility":"private"},{"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":"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":false,"isStatic":false,"visibility":"private","parameters":[]},{"name":"name","returnType":{"packageName":"","name":"string","filePath":null,"qualifiedName":"/string","typeParameters":null,"directParents":null},"isAsync":false,"isOptional":false,"isAbstract":false,"isStatic":false,"visibility":"public","parameters":[]},{"name":"table","returnType":{"packageName":"","name":"Table<File>","filePath":null,"qualifiedName":"/Table<File>","typeParameters":null,"directParents":null},"isAsync":false,"isOptional":false,"isAbstract":false,"isStatic":false,"visibility":"public","parameters":[]},{"name":"beforeDelete","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":"recordsToDelete","type":{"packageName":"","name":"T[]","filePath":null,"qualifiedName":"/T[]","typeParameters":null,"directParents":null}},{"name":"initialQb","type":{"packageName":"","name":"QueryBuilder<T>","filePath":null,"qualifiedName":"/QueryBuilder<T>","typeParameters":null,"directParents":null}},{"name":"deleteQb","type":{"packageName":"","name":"QueryBuilder<T>","filePath":null,"qualifiedName":"/QueryBuilder<T>","typeParameters":null,"directParents":null}}]}],"typeParameters":[],"directParentInterfaces":[{"packageName":"@proteinjs/db","name":"TableWatcher","filePath":null,"qualifiedName":"@proteinjs/db/TableWatcher","properties":[],"methods":[],"typeParameters":["@proteinjs/db-file/File"],"directParents":[]}],"directParentClasses":[],"sourceType":2}},{"v":"@proteinjs/db/TableWatcher"}],"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"},{"v":"@proteinjs/db-file-storage-driver-gcs/GoogleCloudStorageTableWatcher","w":"@proteinjs/db/TableWatcher","value":"implements interface"}]}';
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.15",
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.33.0",
26
- "@proteinjs/db-file": "^1.4.15",
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": "23b168ca8f82ba392500b545230adc6e8c761b4e"
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
- await gcsFile.save(fileData, {
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
- }