@nestm/storage 0.1.0-alpha.0 → 0.1.0-alpha.10

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.
Files changed (122) hide show
  1. package/CHANGELOG.md +264 -0
  2. package/README.md +724 -25
  3. package/SECURITY.md +101 -0
  4. package/dist/ai-sdk/ai-sdk-workspace-tools.d.ts +91 -0
  5. package/dist/ai-sdk/ai-sdk-workspace-tools.d.ts.map +1 -0
  6. package/dist/ai-sdk/ai-sdk-workspace-tools.js +491 -0
  7. package/dist/ai-sdk/ai-sdk-workspace-tools.js.map +1 -0
  8. package/dist/ai-sdk/index.d.ts +2 -0
  9. package/dist/ai-sdk/index.d.ts.map +1 -0
  10. package/dist/ai-sdk/index.js +2 -0
  11. package/dist/ai-sdk/index.js.map +1 -0
  12. package/dist/core/index.d.ts +6 -0
  13. package/dist/core/index.d.ts.map +1 -0
  14. package/dist/core/index.js +4 -0
  15. package/dist/core/index.js.map +1 -0
  16. package/dist/files-sdk/files-sdk.driver.d.ts +85 -3
  17. package/dist/files-sdk/files-sdk.driver.d.ts.map +1 -1
  18. package/dist/files-sdk/files-sdk.driver.js +1437 -37
  19. package/dist/files-sdk/files-sdk.driver.js.map +1 -1
  20. package/dist/files-sdk/fs/index.d.ts +42 -0
  21. package/dist/files-sdk/fs/index.d.ts.map +1 -0
  22. package/dist/files-sdk/fs/index.js +1117 -0
  23. package/dist/files-sdk/fs/index.js.map +1 -0
  24. package/dist/files-sdk/index.d.ts +1 -1
  25. package/dist/files-sdk/index.d.ts.map +1 -1
  26. package/dist/files-sdk/index.js.map +1 -1
  27. package/dist/files-sdk/provider/index.d.ts +58 -0
  28. package/dist/files-sdk/provider/index.d.ts.map +1 -0
  29. package/dist/files-sdk/provider/index.js +147 -0
  30. package/dist/files-sdk/provider/index.js.map +1 -0
  31. package/dist/files-sdk/s3/construction-metadata.d.ts +9 -0
  32. package/dist/files-sdk/s3/construction-metadata.d.ts.map +1 -0
  33. package/dist/files-sdk/s3/construction-metadata.js +24 -0
  34. package/dist/files-sdk/s3/construction-metadata.js.map +1 -0
  35. package/dist/files-sdk/s3/index.d.ts +54 -0
  36. package/dist/files-sdk/s3/index.d.ts.map +1 -0
  37. package/dist/files-sdk/s3/index.js +1505 -0
  38. package/dist/files-sdk/s3/index.js.map +1 -0
  39. package/dist/gateway/index.d.ts +1 -1
  40. package/dist/gateway/index.d.ts.map +1 -1
  41. package/dist/gateway/index.js.map +1 -1
  42. package/dist/gateway/storage-gateway-fastify-parser.d.ts.map +1 -1
  43. package/dist/gateway/storage-gateway-fastify-parser.js.map +1 -1
  44. package/dist/gateway/storage-gateway.controller.d.ts +12 -11
  45. package/dist/gateway/storage-gateway.controller.d.ts.map +1 -1
  46. package/dist/gateway/storage-gateway.controller.js +240 -70
  47. package/dist/gateway/storage-gateway.controller.js.map +1 -1
  48. package/dist/gateway/storage-gateway.guard.d.ts.map +1 -1
  49. package/dist/gateway/storage-gateway.guard.js.map +1 -1
  50. package/dist/gateway/storage-gateway.module.d.ts.map +1 -1
  51. package/dist/gateway/storage-gateway.module.js +60 -1
  52. package/dist/gateway/storage-gateway.module.js.map +1 -1
  53. package/dist/gateway/storage-gateway.tokens.d.ts +1 -0
  54. package/dist/gateway/storage-gateway.tokens.d.ts.map +1 -1
  55. package/dist/gateway/storage-gateway.tokens.js +1 -0
  56. package/dist/gateway/storage-gateway.tokens.js.map +1 -1
  57. package/dist/gateway/storage-gateway.types.d.ts +53 -10
  58. package/dist/gateway/storage-gateway.types.d.ts.map +1 -1
  59. package/dist/gateway/storage-gateway.types.js.map +1 -1
  60. package/dist/index.d.ts +1 -5
  61. package/dist/index.d.ts.map +1 -1
  62. package/dist/index.js +1 -3
  63. package/dist/index.js.map +1 -1
  64. package/dist/inject-storage.decorator.js.map +1 -1
  65. package/dist/storage-etag.d.ts +13 -0
  66. package/dist/storage-etag.d.ts.map +1 -0
  67. package/dist/storage-etag.js +31 -0
  68. package/dist/storage-etag.js.map +1 -0
  69. package/dist/storage-upload-control.d.ts.map +1 -1
  70. package/dist/storage.client.d.ts +15 -3
  71. package/dist/storage.client.d.ts.map +1 -1
  72. package/dist/storage.client.js +204 -2
  73. package/dist/storage.client.js.map +1 -1
  74. package/dist/storage.driver.d.ts +28 -1
  75. package/dist/storage.driver.d.ts.map +1 -1
  76. package/dist/storage.driver.js.map +1 -1
  77. package/dist/storage.error.d.ts +17 -10
  78. package/dist/storage.error.d.ts.map +1 -1
  79. package/dist/storage.error.js +47 -1
  80. package/dist/storage.error.js.map +1 -1
  81. package/dist/storage.module.d.ts.map +1 -1
  82. package/dist/storage.module.js.map +1 -1
  83. package/dist/storage.service.d.ts.map +1 -1
  84. package/dist/storage.service.js +28 -3
  85. package/dist/storage.service.js.map +1 -1
  86. package/dist/storage.tokens.js.map +1 -1
  87. package/dist/storage.types.d.ts +150 -1
  88. package/dist/storage.types.d.ts.map +1 -1
  89. package/dist/storage.types.js.map +1 -1
  90. package/dist/testing/index.d.ts +1 -0
  91. package/dist/testing/index.d.ts.map +1 -1
  92. package/dist/testing/index.js +1 -0
  93. package/dist/testing/index.js.map +1 -1
  94. package/dist/testing/provider-conformance.d.ts +65 -0
  95. package/dist/testing/provider-conformance.d.ts.map +1 -0
  96. package/dist/testing/provider-conformance.js +869 -0
  97. package/dist/testing/provider-conformance.js.map +1 -0
  98. package/dist/workspace/index.d.ts +5 -0
  99. package/dist/workspace/index.d.ts.map +1 -0
  100. package/dist/workspace/index.js +5 -0
  101. package/dist/workspace/index.js.map +1 -0
  102. package/dist/workspace/storage-workspace.cursor.d.ts +71 -0
  103. package/dist/workspace/storage-workspace.cursor.d.ts.map +1 -0
  104. package/dist/workspace/storage-workspace.cursor.js +408 -0
  105. package/dist/workspace/storage-workspace.cursor.js.map +1 -0
  106. package/dist/workspace/storage-workspace.d.ts +6 -0
  107. package/dist/workspace/storage-workspace.d.ts.map +1 -0
  108. package/dist/workspace/storage-workspace.error.d.ts +32 -0
  109. package/dist/workspace/storage-workspace.error.d.ts.map +1 -0
  110. package/dist/workspace/storage-workspace.error.js +75 -0
  111. package/dist/workspace/storage-workspace.error.js.map +1 -0
  112. package/dist/workspace/storage-workspace.js +849 -0
  113. package/dist/workspace/storage-workspace.js.map +1 -0
  114. package/dist/workspace/storage-workspace.path.d.ts +9 -0
  115. package/dist/workspace/storage-workspace.path.d.ts.map +1 -0
  116. package/dist/workspace/storage-workspace.path.js +68 -0
  117. package/dist/workspace/storage-workspace.path.js.map +1 -0
  118. package/dist/workspace/storage-workspace.types.d.ts +123 -0
  119. package/dist/workspace/storage-workspace.types.d.ts.map +1 -0
  120. package/dist/workspace/storage-workspace.types.js +22 -0
  121. package/dist/workspace/storage-workspace.types.js.map +1 -0
  122. package/package.json +103 -35
package/dist/index.js CHANGED
@@ -1,8 +1,6 @@
1
- export { DEFAULT_BUFFER_LIMIT, StorageClient, } from './storage.client.js';
2
- export { StorageError, StorageErrorCode, isStorageError, normalizeStorageError, } from './storage.error.js';
1
+ export * from './core/index.js';
3
2
  export { InjectStorage } from './inject-storage.decorator.js';
4
3
  export { StorageModule } from './storage.module.js';
5
4
  export { StorageService } from './storage.service.js';
6
5
  export { DEFAULT_STORAGE_NAME, STORAGE, getStorageToken, } from './storage.tokens.js';
7
- export { StorageUploadControl, } from './storage-upload-control.js';
8
6
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,oBAAoB,EACpB,aAAa,GAEd,MAAM,qBAAqB,CAAC;AAE7B,OAAO,EACL,YAAY,EACZ,gBAAgB,EAChB,cAAc,EACd,qBAAqB,GAEtB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EAAE,aAAa,EAAE,MAAM,+BAA+B,CAAC;AAC9D,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAapD,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AACtD,OAAO,EACL,oBAAoB,EACpB,OAAO,EACP,eAAe,GAChB,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EACL,oBAAoB,GAGrB,MAAM,6BAA6B,CAAC","sourcesContent":["export {\n DEFAULT_BUFFER_LIMIT,\n StorageClient,\n type StorageFileHandle,\n} from './storage.client.js';\nexport type { StorageDriver } from './storage.driver.js';\nexport {\n StorageError,\n StorageErrorCode,\n isStorageError,\n normalizeStorageError,\n type StorageErrorOptions,\n} from './storage.error.js';\nexport { InjectStorage } from './inject-storage.decorator.js';\nexport { StorageModule } from './storage.module.js';\nexport type {\n StorageAsyncStoreDefinition,\n StorageClassStoreDefinition,\n StorageDriverFactory,\n StorageExistingStoreDefinition,\n StorageFactoryStoreDefinition,\n StorageFeatureAsyncOptions,\n StorageFeatureOptions,\n StorageModuleAsyncOptions,\n StorageModuleOptions,\n StorageStoreDefinition,\n} from './storage-module.options.js';\nexport { StorageService } from './storage.service.js';\nexport {\n DEFAULT_STORAGE_NAME,\n STORAGE,\n getStorageToken,\n} from './storage.tokens.js';\nexport {\n StorageUploadControl,\n type StorageResumableToken,\n type StorageUploadStatus,\n} from './storage-upload-control.js';\nexport type * from './storage.types.js';\n"]}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,iBAAiB,CAAC;AAChC,OAAO,EAAE,aAAa,EAAE,MAAM,+BAA+B,CAAC;AAC9D,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAapD,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AACtD,OAAO,EACL,oBAAoB,EACpB,OAAO,EACP,eAAe,GAChB,MAAM,qBAAqB,CAAC","sourcesContent":["export * from './core/index.js';\nexport { InjectStorage } from './inject-storage.decorator.js';\nexport { StorageModule } from './storage.module.js';\nexport type {\n StorageAsyncStoreDefinition,\n StorageClassStoreDefinition,\n StorageDriverFactory,\n StorageExistingStoreDefinition,\n StorageFactoryStoreDefinition,\n StorageFeatureAsyncOptions,\n StorageFeatureOptions,\n StorageModuleAsyncOptions,\n StorageModuleOptions,\n StorageStoreDefinition,\n} from './storage-module.options.js';\nexport { StorageService } from './storage.service.js';\nexport {\n DEFAULT_STORAGE_NAME,\n STORAGE,\n getStorageToken,\n} from './storage.tokens.js';\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"inject-storage.decorator.js","sourceRoot":"","sources":["../src/inject-storage.decorator.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,gBAAgB,CAAC;AAExC,OAAO,EAAE,oBAAoB,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AAE5E,MAAM,UAAU,aAAa,CAC3B,OAAe,oBAAoB;IAEnC,OAAO,MAAM,CAAC,eAAe,CAAC,IAAI,CAAC,CAAC,CAAC;AACvC,CAAC","sourcesContent":["import { Inject } from '@nestjs/common';\n\nimport { DEFAULT_STORAGE_NAME, getStorageToken } from './storage.tokens.js';\n\nexport function InjectStorage(\n name: string = DEFAULT_STORAGE_NAME,\n): ParameterDecorator & PropertyDecorator {\n return Inject(getStorageToken(name));\n}\n"]}
1
+ {"version":3,"file":"inject-storage.decorator.js","sourceRoot":"","sources":["../src/inject-storage.decorator.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,gBAAgB,CAAC;AAExC,OAAO,EAAE,oBAAoB,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AAE5E,MAAM,UAAU,aAAa,CAC3B,IAAI,GAAW,oBAAoB;IAEnC,OAAO,MAAM,CAAC,eAAe,CAAC,IAAI,CAAC,CAAC,CAAC;AACvC,CAAC","sourcesContent":["import { Inject } from '@nestjs/common';\n\nimport { DEFAULT_STORAGE_NAME, getStorageToken } from './storage.tokens.js';\n\nexport function InjectStorage(\n name: string = DEFAULT_STORAGE_NAME,\n): ParameterDecorator & PropertyDecorator {\n return Inject(getStorageToken(name));\n}\n"]}
@@ -0,0 +1,13 @@
1
+ /** Maximum UTF-8 byte length of a normalized storage ETag. */
2
+ export declare const MAX_STORAGE_ETAG_BYTES = 1024;
3
+ /** Returns whether a value is the package's canonical bare ETag form. */
4
+ export declare function isCanonicalStorageEtag(value: unknown): value is string;
5
+ /**
6
+ * Normalizes one provider-returned strong entity tag to the canonical bare
7
+ * form. Providers may return either the HTTP-quoted representation or an
8
+ * already-normalized value; lists, weak tags, and malformed values fail.
9
+ */
10
+ export declare function normalizeProviderStorageEtag(value: unknown): string | undefined;
11
+ /** Serializes one canonical bare ETag as exactly one HTTP entity tag. */
12
+ export declare function storageEtagHeader(value: unknown): string | undefined;
13
+ //# sourceMappingURL=storage-etag.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"storage-etag.d.ts","sourceRoot":"","sources":["../src/storage-etag.ts"],"names":[],"mappings":"AAAA,8DAA8D;AAC9D,eAAO,MAAM,sBAAsB,OAAO,CAAC;AAQ3C,yEAAyE;AACzE,wBAAgB,sBAAsB,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,MAAM,CAMtE;AAED;;;;GAIG;AACH,wBAAgB,4BAA4B,CAC1C,KAAK,EAAE,OAAO,GACb,MAAM,GAAG,SAAS,CASpB;AAED,yEAAyE;AACzE,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,GAAG,SAAS,CAEpE"}
@@ -0,0 +1,31 @@
1
+ /** Maximum UTF-8 byte length of a normalized storage ETag. */
2
+ export const MAX_STORAGE_ETAG_BYTES = 1024;
3
+ // Deliberately narrower than RFC 9110's etagc grammar. Commas and backslashes
4
+ // are excluded so a normalized value cannot be confused with an entity-tag
5
+ // list or be interpreted differently by legacy HTTP implementations.
6
+ const canonicalStorageEtag = /^(?!\*$)(?![Ww]\/)[\x21\x23-\x2B\x2D-\x5B\x5D-\x7E]+$/u;
7
+ /** Returns whether a value is the package's canonical bare ETag form. */
8
+ export function isCanonicalStorageEtag(value) {
9
+ return (typeof value === 'string' &&
10
+ value.length <= MAX_STORAGE_ETAG_BYTES &&
11
+ canonicalStorageEtag.test(value));
12
+ }
13
+ /**
14
+ * Normalizes one provider-returned strong entity tag to the canonical bare
15
+ * form. Providers may return either the HTTP-quoted representation or an
16
+ * already-normalized value; lists, weak tags, and malformed values fail.
17
+ */
18
+ export function normalizeProviderStorageEtag(value) {
19
+ if (typeof value !== 'string') {
20
+ return undefined;
21
+ }
22
+ const opaque = value.startsWith('"') && value.endsWith('"') && value.length >= 3
23
+ ? value.slice(1, -1)
24
+ : value;
25
+ return isCanonicalStorageEtag(opaque) ? opaque : undefined;
26
+ }
27
+ /** Serializes one canonical bare ETag as exactly one HTTP entity tag. */
28
+ export function storageEtagHeader(value) {
29
+ return isCanonicalStorageEtag(value) ? `"${value}"` : undefined;
30
+ }
31
+ //# sourceMappingURL=storage-etag.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"storage-etag.js","sourceRoot":"","sources":["../src/storage-etag.ts"],"names":[],"mappings":"AAAA,8DAA8D;AAC9D,MAAM,CAAC,MAAM,sBAAsB,GAAG,IAAI,CAAC;AAE3C,8EAA8E;AAC9E,2EAA2E;AAC3E,qEAAqE;AACrE,MAAM,oBAAoB,GACxB,wDAAwD,CAAC;AAE3D,yEAAyE;AACzE,MAAM,UAAU,sBAAsB,CAAC,KAAc;IACnD,OAAO,CACL,OAAO,KAAK,KAAK,QAAQ;QACzB,KAAK,CAAC,MAAM,IAAI,sBAAsB;QACtC,oBAAoB,CAAC,IAAI,CAAC,KAAK,CAAC,CACjC,CAAC;AACJ,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,4BAA4B,CAC1C,KAAc;IAEd,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;QAC9B,OAAO,SAAS,CAAC;IACnB,CAAC;IACD,MAAM,MAAM,GACV,KAAK,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,KAAK,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,KAAK,CAAC,MAAM,IAAI,CAAC;QAC/D,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;QACpB,CAAC,CAAC,KAAK,CAAC;IACZ,OAAO,sBAAsB,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,SAAS,CAAC;AAC7D,CAAC;AAED,yEAAyE;AACzE,MAAM,UAAU,iBAAiB,CAAC,KAAc;IAC9C,OAAO,sBAAsB,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,KAAK,GAAG,CAAC,CAAC,CAAC,SAAS,CAAC;AAClE,CAAC","sourcesContent":["/** Maximum UTF-8 byte length of a normalized storage ETag. */\nexport const MAX_STORAGE_ETAG_BYTES = 1024;\n\n// Deliberately narrower than RFC 9110's etagc grammar. Commas and backslashes\n// are excluded so a normalized value cannot be confused with an entity-tag\n// list or be interpreted differently by legacy HTTP implementations.\nconst canonicalStorageEtag =\n /^(?!\\*$)(?![Ww]\\/)[\\x21\\x23-\\x2B\\x2D-\\x5B\\x5D-\\x7E]+$/u;\n\n/** Returns whether a value is the package's canonical bare ETag form. */\nexport function isCanonicalStorageEtag(value: unknown): value is string {\n return (\n typeof value === 'string' &&\n value.length <= MAX_STORAGE_ETAG_BYTES &&\n canonicalStorageEtag.test(value)\n );\n}\n\n/**\n * Normalizes one provider-returned strong entity tag to the canonical bare\n * form. Providers may return either the HTTP-quoted representation or an\n * already-normalized value; lists, weak tags, and malformed values fail.\n */\nexport function normalizeProviderStorageEtag(\n value: unknown,\n): string | undefined {\n if (typeof value !== 'string') {\n return undefined;\n }\n const opaque =\n value.startsWith('\"') && value.endsWith('\"') && value.length >= 3\n ? value.slice(1, -1)\n : value;\n return isCanonicalStorageEtag(opaque) ? opaque : undefined;\n}\n\n/** Serializes one canonical bare ETag as exactly one HTTP entity tag. */\nexport function storageEtagHeader(value: unknown): string | undefined {\n return isCanonicalStorageEtag(value) ? `\"${value}\"` : undefined;\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"storage-upload-control.d.ts","sourceRoot":"","sources":["../src/storage-upload-control.ts"],"names":[],"mappings":"AAIA,MAAM,MAAM,mBAAmB,GAC7B,MAAM,GAAG,WAAW,GAAG,QAAQ,GAAG,WAAW,GAAG,SAAS,GAAG,OAAO,CAAC;AAEtE;;;GAGG;AACH,MAAM,WAAW,qBAAqB;IACpC,QAAQ,CAAC,OAAO,EAAE,CAAC,CAAC;IACpB,QAAQ,CAAC,MAAM,EAAE,0BAA0B,CAAC;IAC5C,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;CAC3B;AAkHD,qBAAa,oBAAoB;;IAK/B,MAAM,CAAC,IAAI,CAAC,KAAK,EAAE,OAAO,GAAG,oBAAoB;IAmBjD,IAAI,MAAM,IAAI,mBAAmB,CAEhC;IAED,IAAI,MAAM,IAAI,MAAM,CAEnB;IAED,IAAI,KAAK,IAAI,MAAM,GAAG,SAAS,CAE9B;IAED,KAAK,IAAI,IAAI;IAIb,MAAM,IAAI,IAAI;IAId,KAAK,CAAC,MAAM,CAAC,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC;IAItC,MAAM,IAAI,qBAAqB,GAAG,SAAS;CAY5C"}
1
+ {"version":3,"file":"storage-upload-control.d.ts","sourceRoot":"","sources":["../src/storage-upload-control.ts"],"names":[],"mappings":"AAIA,MAAM,MAAM,mBAAmB,GAC7B,MAAM,GAAG,WAAW,GAAG,QAAQ,GAAG,WAAW,GAAG,SAAS,GAAG,OAAO,CAAC;AAEtE;;;GAGG;AACH,MAAM,WAAW,qBAAqB;IACpC,QAAQ,CAAC,OAAO,EAAE,CAAC,CAAC;IACpB,QAAQ,CAAC,MAAM,EAAE,0BAA0B,CAAC;IAC5C,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;CAC3B;AAkHD,qBAAa,oBAAoB;IAC/B,cAEC;IAED,MAAM,CAAC,IAAI,CAAC,KAAK,EAAE,OAAO,GAAG,oBAAoB,CAiBhD;IAED,IAAI,MAAM,IAAI,mBAAmB,CAEhC;IAED,IAAI,MAAM,IAAI,MAAM,CAEnB;IAED,IAAI,KAAK,IAAI,MAAM,GAAG,SAAS,CAE9B;IAED,KAAK,IAAI,IAAI,CAEZ;IAED,MAAM,IAAI,IAAI,CAEb;IAED,KAAK,CAAC,MAAM,CAAC,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CAErC;IAED,MAAM,IAAI,qBAAqB,GAAG,SAAS,CAW1C;CACF"}
@@ -1,24 +1,28 @@
1
- import type { OnApplicationShutdown } from '@nestjs/common';
2
1
  import type { StorageDriver } from './storage.driver.js';
3
- import type { StorageBody, StorageBufferedDownloadOptions, StorageBulkOptions, StorageCapabilities, StorageDeleteManyResult, StorageDownloadManyResult, StorageDownloadOptions, StorageExistsManyResult, StorageHeadManyResult, StorageListOptions, StorageListResult, StorageObject, StorageObjectMetadata, StorageOperationOptions, StoragePlugin, StorageSearchOptions, StorageSignedDownloadOptions, StorageSignedUpload, StorageSignedUploadOptions, StorageUploadManyItem, StorageUploadManyOptions, StorageUploadManyResult, StorageUploadOptions, StorageUploadResult } from './storage.types.js';
2
+ import type { StorageBody, StorageBufferedDownloadOptions, StorageBulkOptions, StorageCapabilities, StorageConditionalDeleteOptions, StorageConditionalReadOptions, StorageConditionalUploadOptions, StorageDeleteManyResult, StorageDownloadManyResult, StorageDownloadOptions, StorageExistsManyResult, StorageHeadManyResult, StorageListOptions, StorageListResult, StorageObject, StorageObjectMetadata, StorageOperationOptions, StoragePlugin, StoragePromotionOptions, StorageSearchOptions, StorageSignedDownloadOptions, StorageSignedUpload, StorageSignedUploadOptions, StorageUploadManyItem, StorageUploadManyOptions, StorageUploadManyResult, StorageUploadOptions, StorageUploadResult } from './storage.types.js';
4
3
  export declare const DEFAULT_BUFFER_LIMIT: number;
5
4
  type BulkOperationOptions = StorageBulkOptions & StorageOperationOptions;
6
5
  type DownloadManyOptions = StorageBulkOptions & StorageDownloadOptions;
7
6
  export interface StorageFileHandle {
8
7
  readonly key: string;
9
8
  upload(body: StorageBody, options?: StorageUploadOptions): Promise<StorageUploadResult>;
9
+ uploadConditional(body: StorageBody, options: StorageConditionalUploadOptions): Promise<StorageUploadResult>;
10
10
  download(options?: StorageDownloadOptions): Promise<StorageObject>;
11
+ downloadConditional(options: StorageConditionalReadOptions): Promise<StorageObject>;
11
12
  bytes(options?: StorageBufferedDownloadOptions): Promise<Uint8Array>;
12
13
  text(options?: StorageBufferedDownloadOptions): Promise<string>;
13
14
  head(options?: StorageOperationOptions): Promise<StorageObjectMetadata>;
14
15
  exists(options?: StorageOperationOptions): Promise<boolean>;
15
16
  delete(options?: StorageOperationOptions): Promise<void>;
17
+ deleteConditional(options: StorageConditionalDeleteOptions): Promise<void>;
16
18
  signDownload(options?: StorageSignedDownloadOptions): Promise<string>;
17
19
  signUpload(options: StorageSignedUploadOptions): Promise<StorageSignedUpload>;
18
20
  copyTo(destinationKey: string, options?: StorageOperationOptions): Promise<void>;
19
21
  moveTo(destinationKey: string, options?: StorageOperationOptions): Promise<void>;
22
+ /** Conditionally copies this staged object and deliberately retains it. */
23
+ promoteTo(destinationKey: string, options: StoragePromotionOptions): Promise<void>;
20
24
  }
21
- export declare class StorageClient implements OnApplicationShutdown {
25
+ export declare class StorageClient {
22
26
  #private;
23
27
  readonly name: string;
24
28
  constructor(name: string, driver: StorageDriver, plugins?: readonly StoragePlugin[]);
@@ -26,15 +30,23 @@ export declare class StorageClient implements OnApplicationShutdown {
26
30
  get capabilities(): Readonly<StorageCapabilities>;
27
31
  file(key: string): StorageFileHandle;
28
32
  upload(key: string, body: StorageBody, options?: StorageUploadOptions): Promise<StorageUploadResult>;
33
+ uploadConditional(key: string, body: StorageBody, options: StorageConditionalUploadOptions): Promise<StorageUploadResult>;
29
34
  downloadStream(key: string, options?: StorageDownloadOptions): Promise<StorageObject>;
35
+ downloadConditional(key: string, options: StorageConditionalReadOptions): Promise<StorageObject>;
30
36
  downloadBytes(key: string, options?: StorageBufferedDownloadOptions): Promise<Uint8Array>;
31
37
  downloadText(key: string, options?: StorageBufferedDownloadOptions): Promise<string>;
32
38
  downloadJson<Result = unknown>(key: string, options?: StorageBufferedDownloadOptions): Promise<Result>;
33
39
  head(key: string, options?: StorageOperationOptions): Promise<StorageObjectMetadata>;
34
40
  exists(key: string, options?: StorageOperationOptions): Promise<boolean>;
35
41
  delete(key: string, options?: StorageOperationOptions): Promise<void>;
42
+ deleteConditional(key: string, options: StorageConditionalDeleteOptions): Promise<void>;
36
43
  copy(sourceKey: string, destinationKey: string, options?: StorageOperationOptions): Promise<void>;
37
44
  move(sourceKey: string, destinationKey: string, options?: StorageOperationOptions): Promise<void>;
45
+ /**
46
+ * Conditionally copies a staged object to a final key. This operation does
47
+ * not delete the source; delete it after the application commit succeeds.
48
+ */
49
+ promote(sourceKey: string, destinationKey: string, options: StoragePromotionOptions): Promise<void>;
38
50
  list(options?: StorageListOptions): Promise<StorageListResult>;
39
51
  listAll(options?: StorageListOptions): AsyncGenerator<StorageObjectMetadata, void>;
40
52
  search(pattern: string | RegExp, options?: StorageSearchOptions): AsyncIterable<StorageObjectMetadata>;
@@ -1 +1 @@
1
- {"version":3,"file":"storage.client.d.ts","sourceRoot":"","sources":["../src/storage.client.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"storage.client.d.ts","sourceRoot":"","sources":["../src/storage.client.ts"],"names":[],"mappings":"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"}
@@ -1,4 +1,5 @@
1
1
  import { settleMany } from './internal/settle-many.js';
2
+ import { isCanonicalStorageEtag } from './storage-etag.js';
2
3
  import { StorageError, StorageErrorCode, normalizeStorageError, } from './storage.error.js';
3
4
  export const DEFAULT_BUFFER_LIMIT = 10 * 1024 * 1024;
4
5
  function assertKey(key, label = 'key') {
@@ -146,27 +147,116 @@ export class StorageClient {
146
147
  return {
147
148
  copyTo: (destinationKey, options) => this.copy(key, destinationKey, options),
148
149
  delete: (options) => this.delete(key, options),
150
+ deleteConditional: (options) => this.deleteConditional(key, options),
149
151
  download: (options) => this.downloadStream(key, options),
152
+ downloadConditional: (options) => this.downloadConditional(key, options),
150
153
  exists: (options) => this.exists(key, options),
151
154
  head: (options) => this.head(key, options),
152
155
  key,
153
156
  moveTo: (destinationKey, options) => this.move(key, destinationKey, options),
157
+ promoteTo: (destinationKey, options) => this.promote(key, destinationKey, options),
154
158
  signDownload: (options) => this.signDownload(key, options),
155
159
  signUpload: (options) => this.signUpload(key, options),
156
160
  bytes: (options) => this.downloadBytes(key, options),
157
161
  text: (options) => this.downloadText(key, options),
158
162
  upload: (body, options) => this.upload(key, body, options),
163
+ uploadConditional: (body, options) => this.uploadConditional(key, body, options),
159
164
  };
160
165
  }
161
166
  upload(key, body, options) {
162
167
  assertKey(key);
163
168
  return this.#execute({ key, operation: 'upload', store: this.name }, () => this.#driver.upload(key, body, options));
164
169
  }
170
+ uploadConditional(key, body, options) {
171
+ assertKey(key);
172
+ const condition = options.condition;
173
+ if (condition === undefined ||
174
+ (condition.type !== 'create' && condition.type !== 'replace')) {
175
+ invalidArgument('condition.type must be "create" or "replace".');
176
+ }
177
+ if (condition.type === 'replace' &&
178
+ !isCanonicalStorageEtag(condition.etag)) {
179
+ invalidArgument('condition.etag must be a canonical storage ETag.');
180
+ }
181
+ const capability = condition.type === 'create'
182
+ ? this.#driver.capabilities.conditionalCreate
183
+ : this.#driver.capabilities.conditionalReplace;
184
+ const uploadConditional = this.#driver.uploadConditional;
185
+ const multipartRequested = options.multipart !== undefined && options.multipart !== false;
186
+ const multipartCapability = this.#driver.capabilities.conditionalMultipartCompletion;
187
+ const multipartSupported = !multipartRequested ||
188
+ (condition.type === 'create'
189
+ ? multipartCapability?.create === true
190
+ : multipartCapability?.replace === true);
191
+ if (capability === undefined ||
192
+ !multipartSupported ||
193
+ uploadConditional === undefined) {
194
+ throw new StorageError(`Store "${this.name}" does not support the requested conditional upload.`, {
195
+ code: StorageErrorCode.NOT_SUPPORTED,
196
+ key,
197
+ operation: 'upload',
198
+ permanent: true,
199
+ store: this.name,
200
+ });
201
+ }
202
+ return this.#execute({ key, operation: 'upload', store: this.name }, () => uploadConditional.call(this.#driver, key, body, options), (result) => {
203
+ if (capability.resultEtag && !isCanonicalStorageEtag(result.etag)) {
204
+ throw new StorageError(`Store "${this.name}" committed a conditional upload without the advertised result ETag.`, {
205
+ code: StorageErrorCode.PROVIDER,
206
+ key,
207
+ operation: 'upload',
208
+ permanent: true,
209
+ store: this.name,
210
+ });
211
+ }
212
+ return {
213
+ ...(isCanonicalStorageEtag(result.etag) && {
214
+ appliedEtag: result.etag,
215
+ }),
216
+ };
217
+ });
218
+ }
165
219
  downloadStream(key, options) {
166
220
  assertKey(key);
167
221
  assertDownloadOptions(options);
168
222
  return this.#execute({ key, operation: 'download', store: this.name }, () => this.#driver.download(key, options));
169
223
  }
224
+ downloadConditional(key, options) {
225
+ assertKey(key);
226
+ assertDownloadOptions(options);
227
+ if (options === undefined ||
228
+ options.condition === undefined ||
229
+ typeof options.condition !== 'object' ||
230
+ options.condition === null) {
231
+ invalidArgument('conditional read requires a condition object.');
232
+ }
233
+ const { etag, version } = options.condition;
234
+ if (etag !== undefined && !isCanonicalStorageEtag(etag)) {
235
+ invalidArgument('condition.etag must be a canonical storage ETag.');
236
+ }
237
+ if (version !== undefined &&
238
+ (typeof version !== 'string' || version.length === 0)) {
239
+ invalidArgument('condition.version must be a non-empty string.');
240
+ }
241
+ if (etag === undefined && version === undefined) {
242
+ invalidArgument('conditional read requires an etag, version, or both.');
243
+ }
244
+ const capability = this.#driver.capabilities.conditionalRead;
245
+ const downloadConditional = this.#driver.downloadConditional;
246
+ if (downloadConditional === undefined ||
247
+ capability === undefined ||
248
+ (etag !== undefined && !capability.etag) ||
249
+ (version !== undefined && !capability.version)) {
250
+ throw new StorageError(`Store "${this.name}" does not support the requested conditional read.`, {
251
+ code: StorageErrorCode.NOT_SUPPORTED,
252
+ key,
253
+ operation: 'download',
254
+ permanent: true,
255
+ store: this.name,
256
+ });
257
+ }
258
+ return this.#execute({ key, operation: 'download', store: this.name }, () => downloadConditional.call(this.#driver, key, options));
259
+ }
170
260
  async downloadBytes(key, options) {
171
261
  const { maxBytes = DEFAULT_BUFFER_LIMIT, ...download } = options ?? {};
172
262
  const object = await this.downloadStream(key, download);
@@ -203,6 +293,25 @@ export class StorageClient {
203
293
  assertKey(key);
204
294
  return this.#execute({ key, operation: 'delete', store: this.name }, () => this.#driver.delete(key, options));
205
295
  }
296
+ deleteConditional(key, options) {
297
+ assertKey(key);
298
+ if (options.condition === undefined ||
299
+ !isCanonicalStorageEtag(options.condition.etag)) {
300
+ invalidArgument('condition.etag must be a canonical storage ETag.');
301
+ }
302
+ const capability = this.#driver.capabilities.conditionalDelete;
303
+ const deleteConditional = this.#driver.deleteConditional;
304
+ if (capability?.etag !== true || deleteConditional === undefined) {
305
+ throw new StorageError(`Store "${this.name}" does not support conditional delete.`, {
306
+ code: StorageErrorCode.NOT_SUPPORTED,
307
+ key,
308
+ operation: 'delete',
309
+ permanent: true,
310
+ store: this.name,
311
+ });
312
+ }
313
+ return this.#execute({ key, operation: 'delete', store: this.name }, () => deleteConditional.call(this.#driver, key, options), () => ({}));
314
+ }
206
315
  copy(sourceKey, destinationKey, options) {
207
316
  assertKey(sourceKey, 'source key');
208
317
  assertKey(destinationKey, 'destination key');
@@ -223,6 +332,73 @@ export class StorageClient {
223
332
  to: destinationKey,
224
333
  }, () => this.#driver.move(sourceKey, destinationKey, options));
225
334
  }
335
+ /**
336
+ * Conditionally copies a staged object to a final key. This operation does
337
+ * not delete the source; delete it after the application commit succeeds.
338
+ */
339
+ promote(sourceKey, destinationKey, options) {
340
+ assertKey(sourceKey, 'source key');
341
+ assertKey(destinationKey, 'destination key');
342
+ const sourceEtag = options.sourceEtag;
343
+ const sourceVersion = options.sourceVersion;
344
+ if (sourceEtag !== undefined && !isCanonicalStorageEtag(sourceEtag)) {
345
+ invalidArgument('sourceEtag must be a canonical storage ETag.');
346
+ }
347
+ if (sourceVersion !== undefined &&
348
+ (typeof sourceVersion !== 'string' || sourceVersion.length === 0)) {
349
+ invalidArgument('sourceVersion must be a non-empty string.');
350
+ }
351
+ const destination = options.destination;
352
+ if (destination !== undefined &&
353
+ (typeof destination !== 'object' ||
354
+ destination === null ||
355
+ (destination.type !== 'create' && destination.type !== 'replace'))) {
356
+ invalidArgument('destination.type must be "create" or "replace".');
357
+ }
358
+ if (sourceEtag === undefined &&
359
+ sourceVersion === undefined &&
360
+ destination === undefined) {
361
+ invalidArgument('promote requires a source or destination precondition.');
362
+ }
363
+ if (destination?.type === 'replace' &&
364
+ !isCanonicalStorageEtag(destination.etag)) {
365
+ invalidArgument('destination.etag must be a canonical storage ETag.');
366
+ }
367
+ const sourceCapability = this.#driver.capabilities.conditionalCopySource;
368
+ const destinationCapability = this.#driver.capabilities.conditionalCopyDestination;
369
+ const promote = this.#driver.promote;
370
+ const hasSourcePredicate = sourceEtag !== undefined || sourceVersion !== undefined;
371
+ if (promote === undefined ||
372
+ (sourceEtag !== undefined && sourceCapability?.etag !== true) ||
373
+ (sourceVersion !== undefined && sourceCapability?.version !== true) ||
374
+ (hasSourcePredicate &&
375
+ destination === undefined &&
376
+ sourceCapability?.requiresDestinationPredicate === true) ||
377
+ (destination?.type === 'create' &&
378
+ destinationCapability?.create !== true) ||
379
+ (destination?.type === 'replace' &&
380
+ destinationCapability?.replace !== true) ||
381
+ (destination !== undefined &&
382
+ !hasSourcePredicate &&
383
+ destinationCapability?.requiresSourcePredicate === true) ||
384
+ (destination !== undefined &&
385
+ hasSourcePredicate &&
386
+ destinationCapability?.atomicWithSource !== true)) {
387
+ throw new StorageError(`Store "${this.name}" does not support the requested conditional promotion.`, {
388
+ code: StorageErrorCode.NOT_SUPPORTED,
389
+ key: sourceKey,
390
+ operation: 'promote',
391
+ permanent: true,
392
+ store: this.name,
393
+ });
394
+ }
395
+ return this.#execute({
396
+ from: sourceKey,
397
+ operation: 'promote',
398
+ store: this.name,
399
+ to: destinationKey,
400
+ }, () => promote.call(this.#driver, sourceKey, destinationKey, options), () => ({}));
401
+ }
226
402
  list(options) {
227
403
  assertListOptions(options);
228
404
  return this.#execute({ operation: 'list', store: this.name }, () => this.#driver.list(options));
@@ -363,23 +539,49 @@ export class StorageClient {
363
539
  this.#closed = true;
364
540
  await this.#driver.close?.();
365
541
  }
366
- async #execute(context, operation) {
542
+ async #execute(context, operation, appliedMutation) {
543
+ let appliedSettlement;
367
544
  try {
368
545
  for (const plugin of this.#plugins) {
369
546
  await plugin.beforeOperation?.(context);
370
547
  }
371
548
  const result = await operation();
549
+ if (appliedMutation !== undefined) {
550
+ // Settle before describing the result so even an unexpected local
551
+ // result-validation failure cannot turn a committed mutation into a
552
+ // safe-to-retry error.
553
+ appliedSettlement = {};
554
+ appliedSettlement = appliedMutation(result);
555
+ }
372
556
  for (const plugin of this.#plugins) {
373
557
  await plugin.afterOperation?.(context, result);
374
558
  }
375
559
  return result;
376
560
  }
377
561
  catch (error) {
378
- const normalized = normalizeStorageError(error, {
562
+ let normalized = normalizeStorageError(error, {
379
563
  ...(context.key !== undefined && { key: context.key }),
380
564
  operation: context.operation,
381
565
  store: this.name,
382
566
  });
567
+ if (appliedSettlement !== undefined) {
568
+ normalized = new StorageError(normalized.message, {
569
+ aborted: normalized.aborted,
570
+ applied: true,
571
+ ...(isCanonicalStorageEtag(appliedSettlement.appliedEtag) && {
572
+ appliedEtag: appliedSettlement.appliedEtag,
573
+ }),
574
+ cause: normalized.cause,
575
+ code: normalized.code,
576
+ ...(normalized.key !== undefined && { key: normalized.key }),
577
+ ...(normalized.operation !== undefined && {
578
+ operation: normalized.operation,
579
+ }),
580
+ permanent: normalized.permanent,
581
+ ...(normalized.store !== undefined && { store: normalized.store }),
582
+ timedOut: normalized.timedOut,
583
+ });
584
+ }
383
585
  for (const plugin of this.#plugins) {
384
586
  try {
385
587
  await plugin.onError?.(context, normalized);