@nestm/storage 0.1.0-alpha.5 → 0.1.0-alpha.7

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 (119) hide show
  1. package/CHANGELOG.md +26 -0
  2. package/README.md +158 -92
  3. package/SECURITY.md +40 -0
  4. package/dist/ai-sdk/ai-sdk-workspace-tools.d.ts +63 -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 +383 -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/files-sdk/files-sdk.driver.d.ts +16 -2
  13. package/dist/files-sdk/files-sdk.driver.d.ts.map +1 -1
  14. package/dist/files-sdk/files-sdk.driver.js +159 -0
  15. package/dist/files-sdk/files-sdk.driver.js.map +1 -1
  16. package/dist/files-sdk/fs/index.d.ts +21 -2
  17. package/dist/files-sdk/fs/index.d.ts.map +1 -1
  18. package/dist/files-sdk/fs/index.js +600 -1
  19. package/dist/files-sdk/fs/index.js.map +1 -1
  20. package/dist/files-sdk/index.d.ts +1 -1
  21. package/dist/files-sdk/index.d.ts.map +1 -1
  22. package/dist/files-sdk/index.js.map +1 -1
  23. package/dist/files-sdk/provider/index.d.ts.map +1 -1
  24. package/dist/files-sdk/provider/index.js +7 -0
  25. package/dist/files-sdk/provider/index.js.map +1 -1
  26. package/dist/files-sdk/s3/index.d.ts +12 -3
  27. package/dist/files-sdk/s3/index.d.ts.map +1 -1
  28. package/dist/files-sdk/s3/index.js +203 -37
  29. package/dist/files-sdk/s3/index.js.map +1 -1
  30. package/dist/storage.client.d.ts +5 -1
  31. package/dist/storage.client.d.ts.map +1 -1
  32. package/dist/storage.client.js +49 -0
  33. package/dist/storage.client.js.map +1 -1
  34. package/dist/storage.driver.d.ts +3 -1
  35. package/dist/storage.driver.d.ts.map +1 -1
  36. package/dist/storage.driver.js.map +1 -1
  37. package/dist/storage.service.d.ts.map +1 -1
  38. package/dist/storage.service.js +28 -3
  39. package/dist/storage.service.js.map +1 -1
  40. package/dist/storage.types.d.ts +36 -0
  41. package/dist/storage.types.d.ts.map +1 -1
  42. package/dist/storage.types.js.map +1 -1
  43. package/dist/workspace/index.d.ts +4 -0
  44. package/dist/workspace/index.d.ts.map +1 -0
  45. package/dist/workspace/index.js +4 -0
  46. package/dist/workspace/index.js.map +1 -0
  47. package/dist/workspace/storage-workspace.cursor.d.ts +6 -0
  48. package/dist/workspace/storage-workspace.cursor.d.ts.map +1 -0
  49. package/dist/workspace/storage-workspace.cursor.js +45 -0
  50. package/dist/workspace/storage-workspace.cursor.js.map +1 -0
  51. package/dist/workspace/storage-workspace.d.ts +6 -0
  52. package/dist/workspace/storage-workspace.d.ts.map +1 -0
  53. package/dist/workspace/storage-workspace.error.d.ts +28 -0
  54. package/dist/workspace/storage-workspace.error.d.ts.map +1 -0
  55. package/dist/workspace/storage-workspace.error.js +67 -0
  56. package/dist/workspace/storage-workspace.error.js.map +1 -0
  57. package/dist/workspace/storage-workspace.js +747 -0
  58. package/dist/workspace/storage-workspace.js.map +1 -0
  59. package/dist/workspace/storage-workspace.path.d.ts +9 -0
  60. package/dist/workspace/storage-workspace.path.d.ts.map +1 -0
  61. package/dist/workspace/storage-workspace.path.js +68 -0
  62. package/dist/workspace/storage-workspace.path.js.map +1 -0
  63. package/dist/workspace/storage-workspace.types.d.ts +97 -0
  64. package/dist/workspace/storage-workspace.types.d.ts.map +1 -0
  65. package/dist/workspace/storage-workspace.types.js +20 -0
  66. package/dist/workspace/storage-workspace.types.js.map +1 -0
  67. package/package.json +23 -20
  68. package/dist/artifacts/artifact-storage.d.ts +0 -161
  69. package/dist/artifacts/artifact-storage.d.ts.map +0 -1
  70. package/dist/artifacts/artifact-storage.js +0 -452
  71. package/dist/artifacts/artifact-storage.js.map +0 -1
  72. package/dist/artifacts/crypto/codec.d.ts +0 -44
  73. package/dist/artifacts/crypto/codec.d.ts.map +0 -1
  74. package/dist/artifacts/crypto/codec.js +0 -273
  75. package/dist/artifacts/crypto/codec.js.map +0 -1
  76. package/dist/artifacts/crypto/context.d.ts +0 -48
  77. package/dist/artifacts/crypto/context.d.ts.map +0 -1
  78. package/dist/artifacts/crypto/context.js +0 -37
  79. package/dist/artifacts/crypto/context.js.map +0 -1
  80. package/dist/artifacts/crypto/dek-cache.d.ts +0 -38
  81. package/dist/artifacts/crypto/dek-cache.d.ts.map +0 -1
  82. package/dist/artifacts/crypto/dek-cache.js +0 -137
  83. package/dist/artifacts/crypto/dek-cache.js.map +0 -1
  84. package/dist/artifacts/crypto/index.d.ts +0 -25
  85. package/dist/artifacts/crypto/index.d.ts.map +0 -1
  86. package/dist/artifacts/crypto/index.js +0 -29
  87. package/dist/artifacts/crypto/index.js.map +0 -1
  88. package/dist/artifacts/crypto/key-provider.d.ts +0 -44
  89. package/dist/artifacts/crypto/key-provider.d.ts.map +0 -1
  90. package/dist/artifacts/crypto/key-provider.js +0 -36
  91. package/dist/artifacts/crypto/key-provider.js.map +0 -1
  92. package/dist/artifacts/crypto/kms-provider.d.ts +0 -16
  93. package/dist/artifacts/crypto/kms-provider.d.ts.map +0 -1
  94. package/dist/artifacts/crypto/kms-provider.js +0 -90
  95. package/dist/artifacts/crypto/kms-provider.js.map +0 -1
  96. package/dist/artifacts/crypto/local-provider.d.ts +0 -17
  97. package/dist/artifacts/crypto/local-provider.d.ts.map +0 -1
  98. package/dist/artifacts/crypto/local-provider.js +0 -58
  99. package/dist/artifacts/crypto/local-provider.js.map +0 -1
  100. package/dist/artifacts/env-config.d.ts +0 -15
  101. package/dist/artifacts/env-config.d.ts.map +0 -1
  102. package/dist/artifacts/env-config.js +0 -95
  103. package/dist/artifacts/env-config.js.map +0 -1
  104. package/dist/artifacts/index.d.ts +0 -6
  105. package/dist/artifacts/index.d.ts.map +0 -1
  106. package/dist/artifacts/index.js +0 -6
  107. package/dist/artifacts/index.js.map +0 -1
  108. package/dist/artifacts/nest/index.d.ts +0 -29
  109. package/dist/artifacts/nest/index.d.ts.map +0 -1
  110. package/dist/artifacts/nest/index.js +0 -129
  111. package/dist/artifacts/nest/index.js.map +0 -1
  112. package/dist/artifacts/object-store.d.ts +0 -27
  113. package/dist/artifacts/object-store.d.ts.map +0 -1
  114. package/dist/artifacts/object-store.js +0 -198
  115. package/dist/artifacts/object-store.js.map +0 -1
  116. package/dist/artifacts/storage-driver.d.ts +0 -48
  117. package/dist/artifacts/storage-driver.d.ts.map +0 -1
  118. package/dist/artifacts/storage-driver.js +0 -89
  119. package/dist/artifacts/storage-driver.js.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/files-sdk/fs/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,EAAE,EAAyC,MAAM,cAAc,CAAC;AAEzE,OAAO,EACL,oBAAoB,GAGrB,MAAM,wBAAwB,CAAC;AAShC;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,qBAAqB,CACnC,OAA+B;IAE/B,MAAM,EAAE,OAAO,EAAE,cAAc,EAAE,GAAG,YAAY,EAAE,GAAG,OAAO,CAAC;IAC7D,OAAO,oBAAoB,CAAC,EAAE,GAAG,YAAY,EAAE,OAAO,EAAE,EAAE,CAAC,cAAc,CAAC,EAAE,CAAC,CAAC;AAChF,CAAC;AAED,OAAO,EAAE,EAAE,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC","sourcesContent":["import { fs, type FsAdapter, type FsAdapterOptions } from 'files-sdk/fs';\n\nimport {\n createFilesSdkDriver,\n type FilesSdkDriverOptions,\n type FilesSdkStorageDriver,\n} from '../files-sdk.driver.js';\n\nexport interface FsStorageDriverOptions extends Omit<\n FilesSdkDriverOptions<FsAdapter>,\n 'adapter'\n> {\n adapter: FsAdapterOptions;\n}\n\n/**\n * Creates the files-sdk filesystem driver from the storage package's own\n * dependency context. The adapter reaches only `node:fs`, so this entry point\n * adds no native SDK to the install — unlike every object-store provider, it is\n * always available.\n *\n * The adapter keeps a `<key>.meta.json` sidecar beside each body to carry the\n * content type, ETag, and custom metadata that a filesystem has nowhere else to\n * put. Sidecars never surface as keys: `list` and `search` skip them, and\n * uploading a key that ends in `.meta.json` fails closed rather than colliding\n * with one.\n */\nexport function createFsStorageDriver(\n options: FsStorageDriverOptions,\n): FilesSdkStorageDriver<FsAdapter> {\n const { adapter: adapterOptions, ...filesOptions } = options;\n return createFilesSdkDriver({ ...filesOptions, adapter: fs(adapterOptions) });\n}\n\nexport { fs, mapFsError } from 'files-sdk/fs';\nexport type { FsAdapter, FsAdapterOptions } from 'files-sdk/fs';\n"]}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/files-sdk/fs/index.ts"],"names":[],"mappings":"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","sourcesContent":["import { createHash, randomUUID } from 'node:crypto';\nimport { constants as fsConstants, type Stats } from 'node:fs';\nimport * as fsp from 'node:fs/promises';\nimport path from 'node:path';\n\nimport type {\n Body,\n DownloadOptions,\n ListOptions,\n ListResult,\n OperationOptions,\n StoredFile,\n} from 'files-sdk';\nimport { fs, type FsAdapter, type FsAdapterOptions } from 'files-sdk/fs';\n\nimport { StorageError, StorageErrorCode } from '../../storage.error.js';\nimport type {\n StorageConditionalDeleteOptions,\n StorageConditionalUploadOptions,\n StorageOperationOptions,\n StorageUploadResult,\n} from '../../storage.types.js';\nimport {\n createFilesSdkDriver,\n type FilesSdkConditionalMutationAdapter,\n type FilesSdkDriverOptions,\n type FilesSdkStorageDriver,\n} from '../files-sdk.driver.js';\n\nexport interface FsStorageDriverOptions extends Omit<\n FilesSdkDriverOptions<FsAdapter>,\n 'adapter'\n> {\n adapter: FsAdapterOptions;\n}\n\nexport type FsStorageAdapter = FsAdapter & FilesSdkConditionalMutationAdapter;\n\nconst SIDECAR_SUFFIX = '.meta.json';\nconst TEMP_SUFFIX = '.fls-part';\nconst MAX_SIDECAR_BYTES = 1024 * 1024;\n\ninterface FsSidecar {\n contentType: string;\n cacheControl?: string;\n metadata?: Record<string, string>;\n etag: string;\n lastModified: number;\n}\n\ninterface OperationRuntime {\n signal: AbortSignal | undefined;\n timeoutSignal: AbortSignal | undefined;\n callerSignal: AbortSignal | undefined;\n}\n\nfunction fsErrorCode(error: unknown): string | undefined {\n if (typeof error === 'object' && error !== null && 'code' in error) {\n return typeof error.code === 'string' ? error.code : undefined;\n }\n return undefined;\n}\n\nfunction storageFsError(\n error: unknown,\n key: string,\n operation: 'upload' | 'delete',\n): StorageError {\n if (error instanceof StorageError) {\n return error;\n }\n const systemCode = fsErrorCode(error);\n const code =\n systemCode === 'ENOENT' || systemCode === 'ENOTDIR'\n ? StorageErrorCode.NOT_FOUND\n : systemCode === 'EEXIST'\n ? StorageErrorCode.CONFLICT\n : systemCode === 'EACCES' || systemCode === 'EPERM'\n ? StorageErrorCode.UNAUTHORIZED\n : StorageErrorCode.PROVIDER;\n return new StorageError(`Filesystem ${operation} failed for \"${key}\".`, {\n cause: error,\n code,\n key,\n operation,\n permanent:\n code === StorageErrorCode.NOT_FOUND ||\n code === StorageErrorCode.CONFLICT ||\n code === StorageErrorCode.UNAUTHORIZED,\n });\n}\n\nfunction invalidFsPath(key: string, message: string): never {\n throw new StorageError(`Invalid filesystem storage key: ${message}.`, {\n code: StorageErrorCode.INVALID_ARGUMENT,\n key,\n permanent: true,\n });\n}\n\nfunction strictSegments(key: string): string[] {\n if (key.length === 0 || key.includes('\\0')) {\n invalidFsPath(key, 'the key is empty or contains a null byte');\n }\n if (path.isAbsolute(key) || key.includes('\\\\')) {\n invalidFsPath(key, 'only relative POSIX paths are accepted');\n }\n const segments = key.split('/');\n if (\n segments.some(\n (segment) => segment.length === 0 || segment === '.' || segment === '..',\n )\n ) {\n invalidFsPath(key, 'empty, dot, and parent segments are not accepted');\n }\n if (segments.some((segment) => /[. ]$/u.test(segment))) {\n invalidFsPath(key, 'segments ending in a dot or space are not accepted');\n }\n const leaf = segments.at(-1)?.toLowerCase() ?? '';\n if (leaf.endsWith(SIDECAR_SUFFIX) || leaf.endsWith(TEMP_SUFFIX)) {\n invalidFsPath(key, 'the final segment uses a reserved adapter suffix');\n }\n return segments;\n}\n\nfunction symlinkError(key: string): StorageError {\n return new StorageError(\n `Filesystem storage key \"${key}\" crosses a symbolic link.`,\n {\n code: StorageErrorCode.INVALID_ARGUMENT,\n key,\n permanent: true,\n },\n );\n}\n\nfunction unsupportedUpload(key: string, message: string): never {\n throw new StorageError(message, {\n code: StorageErrorCode.NOT_SUPPORTED,\n key,\n operation: 'upload',\n permanent: true,\n });\n}\n\nfunction conflict(key: string): never {\n throw new StorageError(`Conditional mutation conflicted for \"${key}\".`, {\n code: StorageErrorCode.CONFLICT,\n key,\n permanent: true,\n });\n}\n\nfunction notFound(key: string): never {\n throw new StorageError(`Storage object \"${key}\" was not found.`, {\n code: StorageErrorCode.NOT_FOUND,\n key,\n permanent: true,\n });\n}\n\nfunction runtimeOf(options: StorageOperationOptions): OperationRuntime {\n const timeoutSignal =\n options.timeout === undefined || options.timeout <= 0\n ? undefined\n : AbortSignal.timeout(options.timeout);\n return {\n callerSignal: options.signal,\n signal:\n options.signal === undefined\n ? timeoutSignal\n : timeoutSignal === undefined\n ? options.signal\n : AbortSignal.any([options.signal, timeoutSignal]),\n timeoutSignal,\n };\n}\n\nfunction assertActive(runtime: OperationRuntime, key: string): void {\n if (runtime.signal?.aborted !== true) {\n return;\n }\n const timedOut =\n runtime.timeoutSignal?.aborted === true &&\n runtime.callerSignal?.aborted !== true;\n throw new StorageError(\n timedOut\n ? `Filesystem mutation timed out for \"${key}\".`\n : `Filesystem mutation was aborted for \"${key}\".`,\n {\n aborted: true,\n cause: runtime.signal.reason,\n code: timedOut ? StorageErrorCode.TIMEOUT : StorageErrorCode.ABORTED,\n key,\n permanent: true,\n timedOut,\n },\n );\n}\n\nasync function ensureRoot(root: string, key: string): Promise<void> {\n await fsp.mkdir(root, { mode: 0o700, recursive: true });\n const stat = await fsp.lstat(root);\n if (stat.isSymbolicLink()) {\n throw symlinkError(key);\n }\n if (!stat.isDirectory()) {\n invalidFsPath(key, 'the configured root is not a directory');\n }\n}\n\nasync function ensureParents(\n root: string,\n segments: readonly string[],\n key: string,\n create: boolean,\n runtime: OperationRuntime,\n): Promise<string> {\n await ensureRoot(root, key);\n let current = root;\n for (const segment of segments.slice(0, -1)) {\n assertActive(runtime, key);\n current = path.join(current, segment);\n let stat: Stats;\n try {\n stat = await fsp.lstat(current);\n } catch (error) {\n if (fsErrorCode(error) !== 'ENOENT') {\n throw error;\n }\n if (!create) {\n notFound(key);\n }\n try {\n await fsp.mkdir(current, { mode: 0o700 });\n } catch (mkdirError) {\n if (fsErrorCode(mkdirError) !== 'EEXIST') {\n throw mkdirError;\n }\n }\n stat = await fsp.lstat(current);\n }\n if (stat.isSymbolicLink()) {\n throw symlinkError(key);\n }\n if (!stat.isDirectory()) {\n invalidFsPath(key, 'a parent segment is not a directory');\n }\n }\n return path.join(root, ...segments);\n}\n\nasync function regularFileOrMissing(\n target: string,\n key: string,\n): Promise<Stats | undefined> {\n try {\n const stat = await fsp.lstat(target);\n if (stat.isSymbolicLink()) {\n throw symlinkError(key);\n }\n if (!stat.isFile()) {\n invalidFsPath(key, 'an object path is not a regular file');\n }\n if (stat.nlink !== 1) {\n invalidFsPath(key, 'hard-linked object files are not accepted');\n }\n return stat;\n } catch (error) {\n if (fsErrorCode(error) === 'ENOENT') {\n return undefined;\n }\n throw error;\n }\n}\n\nasync function assertSymlinkFreeReadPath(\n root: string,\n key: string,\n): Promise<void> {\n const segments = strictSegments(key);\n let rootStat: Stats;\n try {\n rootStat = await fsp.lstat(root);\n } catch (error) {\n if (fsErrorCode(error) === 'ENOENT') {\n return;\n }\n throw error;\n }\n if (rootStat.isSymbolicLink()) {\n throw symlinkError(key);\n }\n if (!rootStat.isDirectory()) {\n invalidFsPath(key, 'the configured root is not a directory');\n }\n\n let current = root;\n for (const [index, segment] of segments.entries()) {\n current = path.join(current, segment);\n let stat: Stats;\n try {\n stat = await fsp.lstat(current);\n } catch (error) {\n if (fsErrorCode(error) === 'ENOENT') {\n return;\n }\n throw error;\n }\n if (stat.isSymbolicLink()) {\n throw symlinkError(key);\n }\n const leaf = index === segments.length - 1;\n if ((!leaf && !stat.isDirectory()) || (leaf && !stat.isFile())) {\n invalidFsPath(\n key,\n leaf\n ? 'an object path is not a regular file'\n : 'a parent segment is not a directory',\n );\n }\n if (leaf && stat.nlink !== 1) {\n invalidFsPath(key, 'hard-linked object files are not accepted');\n }\n }\n\n const sidecar = await regularFileOrMissing(current + SIDECAR_SUFFIX, key);\n if (sidecar?.isSymbolicLink()) {\n throw symlinkError(key);\n }\n}\n\nasync function readSidecar(target: string, key: string): Promise<FsSidecar> {\n const handle = await fsp.open(\n target,\n fsConstants.O_RDONLY | fsConstants.O_NOFOLLOW,\n );\n try {\n const stat = await handle.stat();\n if (!stat.isFile() || stat.size > MAX_SIDECAR_BYTES) {\n throw new StorageError(`Filesystem metadata is invalid for \"${key}\".`, {\n code: StorageErrorCode.PROVIDER,\n key,\n permanent: true,\n });\n }\n const parsed: unknown = JSON.parse(await handle.readFile('utf8'));\n if (\n typeof parsed !== 'object' ||\n parsed === null ||\n !('etag' in parsed) ||\n typeof parsed.etag !== 'string' ||\n !('contentType' in parsed) ||\n typeof parsed.contentType !== 'string' ||\n !('lastModified' in parsed) ||\n typeof parsed.lastModified !== 'number'\n ) {\n throw new StorageError(`Filesystem metadata is invalid for \"${key}\".`, {\n code: StorageErrorCode.PROVIDER,\n key,\n permanent: true,\n });\n }\n return parsed as FsSidecar;\n } finally {\n await handle.close();\n }\n}\n\nfunction bodyBytes(body: Body): Uint8Array | undefined {\n if (typeof body === 'string') {\n return new TextEncoder().encode(body);\n }\n if (body instanceof Uint8Array) {\n return body;\n }\n if (body instanceof ArrayBuffer) {\n return new Uint8Array(body);\n }\n if (ArrayBuffer.isView(body)) {\n return new Uint8Array(body.buffer, body.byteOffset, body.byteLength);\n }\n return undefined;\n}\n\nfunction defaultContentType(body: Body, override: string | undefined): string {\n if (override !== undefined) {\n return override;\n }\n if (typeof body === 'string') {\n return 'text/plain; charset=utf-8';\n }\n if (body instanceof Blob && body.type.length > 0) {\n return body.type;\n }\n return 'application/octet-stream';\n}\n\nasync function writeAll(\n handle: fsp.FileHandle,\n bytes: Uint8Array,\n): Promise<void> {\n let offset = 0;\n while (offset < bytes.byteLength) {\n const { bytesWritten } = await handle.write(\n bytes,\n offset,\n bytes.byteLength - offset,\n );\n offset += bytesWritten;\n }\n}\n\nfunction tempPath(directory: string): string {\n return path.join(directory, `.nestm-${randomUUID()}${TEMP_SUFFIX}`);\n}\n\nasync function openTemp(directory: string): Promise<{\n handle: fsp.FileHandle;\n path: string;\n}> {\n const target = tempPath(directory);\n const handle = await fsp.open(\n target,\n fsConstants.O_CREAT |\n fsConstants.O_EXCL |\n fsConstants.O_WRONLY |\n fsConstants.O_NOFOLLOW,\n 0o600,\n );\n return { handle, path: target };\n}\n\nasync function removeTemp(target: string | undefined): Promise<void> {\n if (target === undefined) {\n return;\n }\n try {\n await fsp.unlink(target);\n } catch (error) {\n if (fsErrorCode(error) !== 'ENOENT') {\n throw error;\n }\n }\n}\n\nasync function stageBody(\n directory: string,\n key: string,\n body: Body,\n options: StorageConditionalUploadOptions,\n runtime: OperationRuntime,\n): Promise<{ etag: string; path: string; size: number }> {\n const staged = await openTemp(directory);\n const hash = createHash('sha256');\n let size = 0;\n const knownBytes = bodyBytes(body);\n const knownSize =\n knownBytes?.byteLength ?? (body instanceof Blob ? body.size : undefined);\n options.onProgress?.({\n loaded: 0,\n ...(knownSize !== undefined && { total: knownSize }),\n });\n try {\n if (knownBytes !== undefined) {\n assertActive(runtime, key);\n await writeAll(staged.handle, knownBytes);\n hash.update(knownBytes);\n size = knownBytes.byteLength;\n options.onProgress?.({ loaded: size, total: size });\n } else if (body instanceof Blob) {\n const bytes = new Uint8Array(await body.arrayBuffer());\n assertActive(runtime, key);\n await writeAll(staged.handle, bytes);\n hash.update(bytes);\n size = bytes.byteLength;\n options.onProgress?.({ loaded: size, total: size });\n } else {\n const reader = (body as ReadableStream<Uint8Array>).getReader();\n try {\n while (true) {\n assertActive(runtime, key);\n const chunk = await reader.read();\n if (chunk.done) {\n break;\n }\n await writeAll(staged.handle, chunk.value);\n hash.update(chunk.value);\n size += chunk.value.byteLength;\n options.onProgress?.({ loaded: size });\n }\n } catch (error) {\n await reader.cancel(error).catch(() => undefined);\n throw error;\n } finally {\n reader.releaseLock();\n }\n }\n await staged.handle.sync();\n await staged.handle.close();\n return {\n etag: `\"${hash.digest('hex')}\"`,\n path: staged.path,\n size,\n };\n } catch (error) {\n await staged.handle.close().catch(() => undefined);\n await removeTemp(staged.path).catch(() => undefined);\n throw error;\n }\n}\n\nasync function stageSidecar(\n directory: string,\n sidecar: FsSidecar,\n): Promise<string> {\n const staged = await openTemp(directory);\n try {\n await writeAll(\n staged.handle,\n new TextEncoder().encode(JSON.stringify(sidecar)),\n );\n await staged.handle.sync();\n await staged.handle.close();\n return staged.path;\n } catch (error) {\n await staged.handle.close().catch(() => undefined);\n await removeTemp(staged.path).catch(() => undefined);\n throw error;\n }\n}\n\nconst CONDITIONAL_FS_TAILS = new Map<string, Promise<void>>();\n\nasync function serializeFsKey<Result>(\n lockKey: string,\n operation: () => Promise<Result>,\n): Promise<Result> {\n const previous = CONDITIONAL_FS_TAILS.get(lockKey) ?? Promise.resolve();\n let release = (): void => undefined;\n const gate = new Promise<void>((resolve) => {\n release = resolve;\n });\n const tail = previous.then(() => gate);\n CONDITIONAL_FS_TAILS.set(lockKey, tail);\n await previous;\n try {\n return await operation();\n } finally {\n release();\n if (CONDITIONAL_FS_TAILS.get(lockKey) === tail) {\n CONDITIONAL_FS_TAILS.delete(lockKey);\n }\n }\n}\n\n/**\n * Adds symlink-defended reads and process-local conditional mutations to a\n * files-sdk fs adapter.\n *\n * The configured root must be dedicated to this driver: no other process and\n * no unconditional filesystem writer may mutate it concurrently. Each call\n * rejects symlinks in the existing key path and uses exclusive same-directory\n * temporary files plus atomic renames, but Node has no portable `openat2`\n * equivalent that could make those checks safe against a hostile concurrent\n * tree rewrite. This is a CAS implementation for an exclusively-owned local\n * workspace, not a host-filesystem sandbox. Body and metadata sidecars are two\n * files, so a process crash between their renames can still require cleanup.\n */\nexport function withFsConditionalMutation(base: FsAdapter): FsStorageAdapter {\n const root = path.resolve(base.root);\n const download = base.download.bind(base);\n const exists = base.exists.bind(base);\n const head = base.head.bind(base);\n const list = base.list.bind(base);\n const serialize = <Result>(\n key: string,\n operation: () => Promise<Result>,\n ): Promise<Result> =>\n serializeFsKey(`${root}\\0${key.normalize('NFC').toLowerCase()}`, operation);\n\n return Object.assign(base, {\n conditionalMutation: Object.freeze({\n create: true,\n delete: true,\n etag: true,\n replace: true,\n }),\n async download(\n key: string,\n options?: DownloadOptions,\n ): Promise<StoredFile> {\n await assertSymlinkFreeReadPath(root, key);\n return download(key, options);\n },\n async exists(key: string, options?: OperationOptions): Promise<boolean> {\n await assertSymlinkFreeReadPath(root, key);\n return exists(key, options);\n },\n async head(key: string, options?: OperationOptions): Promise<StoredFile> {\n await assertSymlinkFreeReadPath(root, key);\n return head(key, options);\n },\n async list(options?: ListOptions): Promise<ListResult> {\n const result = await list(options);\n for (const item of result.items) {\n await assertSymlinkFreeReadPath(root, item.key);\n }\n return result;\n },\n async deleteConditional(\n key: string,\n options: StorageConditionalDeleteOptions,\n ): Promise<void> {\n return serialize(key, async () => {\n const runtime = runtimeOf(options);\n try {\n const segments = strictSegments(key);\n const bodyPath = await ensureParents(\n root,\n segments,\n key,\n false,\n runtime,\n );\n const sidecarPath = bodyPath + SIDECAR_SUFFIX;\n if (\n (await regularFileOrMissing(bodyPath, key)) === undefined ||\n (await regularFileOrMissing(sidecarPath, key)) === undefined\n ) {\n notFound(key);\n }\n const sidecar = await readSidecar(sidecarPath, key);\n if (sidecar.etag !== options.condition.etag) {\n conflict(key);\n }\n\n assertActive(runtime, key);\n await ensureParents(root, segments, key, false, runtime);\n if (\n (await regularFileOrMissing(bodyPath, key)) === undefined ||\n (await regularFileOrMissing(sidecarPath, key)) === undefined ||\n (await readSidecar(sidecarPath, key)).etag !==\n options.condition.etag\n ) {\n conflict(key);\n }\n await fsp.unlink(bodyPath);\n try {\n await fsp.unlink(sidecarPath);\n } catch (error) {\n throw storageFsError(error, key, 'delete');\n }\n } catch (error) {\n throw storageFsError(error, key, 'delete');\n }\n });\n },\n async uploadConditional(\n key: string,\n body: Body,\n options: StorageConditionalUploadOptions,\n ): Promise<StorageUploadResult> {\n return serialize(key, async () => {\n let bodyTemp: string | undefined;\n let sidecarTemp: string | undefined;\n const runtime = runtimeOf(options);\n try {\n if (options.multipart !== undefined && options.multipart !== false) {\n unsupportedUpload(\n key,\n 'Conditional filesystem uploads do not support multipart mode.',\n );\n }\n if (options.control !== undefined) {\n unsupportedUpload(\n key,\n 'Conditional filesystem uploads do not support resumable control.',\n );\n }\n\n const segments = strictSegments(key);\n const bodyPath = await ensureParents(\n root,\n segments,\n key,\n true,\n runtime,\n );\n const sidecarPath = bodyPath + SIDECAR_SUFFIX;\n const existingBody = await regularFileOrMissing(bodyPath, key);\n const existingSidecar = await regularFileOrMissing(sidecarPath, key);\n if (options.condition.type === 'create') {\n if (existingBody !== undefined || existingSidecar !== undefined) {\n conflict(key);\n }\n } else {\n if (existingBody === undefined || existingSidecar === undefined) {\n notFound(key);\n }\n if (\n (await readSidecar(sidecarPath, key)).etag !==\n options.condition.etag\n ) {\n conflict(key);\n }\n }\n\n const staged = await stageBody(\n path.dirname(bodyPath),\n key,\n body,\n options,\n runtime,\n );\n bodyTemp = staged.path;\n const lastModified = Date.now();\n const contentType = defaultContentType(body, options.contentType);\n sidecarTemp = await stageSidecar(path.dirname(bodyPath), {\n contentType,\n etag: staged.etag,\n lastModified,\n ...(options.cacheControl !== undefined && {\n cacheControl: options.cacheControl,\n }),\n ...(options.metadata !== undefined && {\n metadata: options.metadata,\n }),\n });\n\n assertActive(runtime, key);\n await ensureParents(root, segments, key, false, runtime);\n const currentBody = await regularFileOrMissing(bodyPath, key);\n const currentSidecar = await regularFileOrMissing(sidecarPath, key);\n if (options.condition.type === 'create') {\n if (currentBody !== undefined || currentSidecar !== undefined) {\n conflict(key);\n }\n } else if (\n currentBody === undefined ||\n currentSidecar === undefined ||\n (await readSidecar(sidecarPath, key)).etag !==\n options.condition.etag\n ) {\n conflict(key);\n }\n\n await fsp.rename(bodyTemp, bodyPath);\n bodyTemp = undefined;\n await fsp.rename(sidecarTemp, sidecarPath);\n sidecarTemp = undefined;\n return {\n contentType,\n etag: staged.etag,\n key,\n lastModified: new Date(lastModified),\n size: staged.size,\n };\n } catch (error) {\n throw storageFsError(error, key, 'upload');\n } finally {\n await removeTemp(bodyTemp).catch(() => undefined);\n await removeTemp(sidecarTemp).catch(() => undefined);\n }\n });\n },\n } satisfies FilesSdkConditionalMutationAdapter &\n Pick<FsAdapter, 'download' | 'exists' | 'head' | 'list'>);\n}\n\n/**\n * Creates the files-sdk filesystem driver from the storage package's own\n * dependency context. The adapter reaches only `node:fs`, so this entry point\n * adds no native SDK to the install — unlike every object-store provider, it is\n * always available.\n *\n * The adapter keeps a `<key>.meta.json` sidecar beside each body to carry the\n * content type, ETag, and custom metadata that a filesystem has nowhere else to\n * put. Sidecars never surface as keys: `list` and `search` skip them, and\n * uploading a key that ends in `.meta.json` fails closed rather than colliding\n * with one.\n *\n * Conditional mutations additionally require an exclusively-owned root. See\n * {@link withFsConditionalMutation}; use an OS sandbox as well when running an\n * agent that has direct shell or filesystem tools.\n */\nexport function createFsStorageDriver(\n options: FsStorageDriverOptions,\n): FilesSdkStorageDriver<FsStorageAdapter> {\n const { adapter: adapterOptions, ...filesOptions } = options;\n return createFilesSdkDriver({\n ...filesOptions,\n adapter: withFsConditionalMutation(fs(adapterOptions)),\n });\n}\n\nexport { fs, mapFsError } from 'files-sdk/fs';\nexport type { FsAdapter, FsAdapterOptions } from 'files-sdk/fs';\n"]}
@@ -1,3 +1,3 @@
1
- export { FilesSdkStorageDriver, createFilesSdkDriver, type FilesSdkConditionalCopyAdapter, type FilesSdkSignedUploadPolicyAdapter, type FilesSdkSignedDownloadPolicyAdapter, type FilesSdkDriverOptions, } from './files-sdk.driver.js';
1
+ export { FilesSdkStorageDriver, createFilesSdkDriver, type FilesSdkConditionalCopyAdapter, type FilesSdkConditionalMutationAdapter, type FilesSdkSignedUploadPolicyAdapter, type FilesSdkSignedDownloadPolicyAdapter, type FilesSdkDriverOptions, } from './files-sdk.driver.js';
2
2
  export type { Adapter as FilesSdkAdapter, FilesHooks as FilesSdkHooks, FilesPlugin as FilesSdkPlugin, } from 'files-sdk';
3
3
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/files-sdk/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,qBAAqB,EACrB,oBAAoB,EACpB,KAAK,8BAA8B,EACnC,KAAK,iCAAiC,EACtC,KAAK,mCAAmC,EACxC,KAAK,qBAAqB,GAC3B,MAAM,uBAAuB,CAAC;AAE/B,YAAY,EACV,OAAO,IAAI,eAAe,EAC1B,UAAU,IAAI,aAAa,EAC3B,WAAW,IAAI,cAAc,GAC9B,MAAM,WAAW,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/files-sdk/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,qBAAqB,EACrB,oBAAoB,EACpB,KAAK,8BAA8B,EACnC,KAAK,kCAAkC,EACvC,KAAK,iCAAiC,EACtC,KAAK,mCAAmC,EACxC,KAAK,qBAAqB,GAC3B,MAAM,uBAAuB,CAAC;AAE/B,YAAY,EACV,OAAO,IAAI,eAAe,EAC1B,UAAU,IAAI,aAAa,EAC3B,WAAW,IAAI,cAAc,GAC9B,MAAM,WAAW,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/files-sdk/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,qBAAqB,EACrB,oBAAoB,GAKrB,MAAM,uBAAuB,CAAC","sourcesContent":["export {\n FilesSdkStorageDriver,\n createFilesSdkDriver,\n type FilesSdkConditionalCopyAdapter,\n type FilesSdkSignedUploadPolicyAdapter,\n type FilesSdkSignedDownloadPolicyAdapter,\n type FilesSdkDriverOptions,\n} from './files-sdk.driver.js';\n\nexport type {\n Adapter as FilesSdkAdapter,\n FilesHooks as FilesSdkHooks,\n FilesPlugin as FilesSdkPlugin,\n} from 'files-sdk';\n"]}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/files-sdk/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,qBAAqB,EACrB,oBAAoB,GAMrB,MAAM,uBAAuB,CAAC","sourcesContent":["export {\n FilesSdkStorageDriver,\n createFilesSdkDriver,\n type FilesSdkConditionalCopyAdapter,\n type FilesSdkConditionalMutationAdapter,\n type FilesSdkSignedUploadPolicyAdapter,\n type FilesSdkSignedDownloadPolicyAdapter,\n type FilesSdkDriverOptions,\n} from './files-sdk.driver.js';\n\nexport type {\n Adapter as FilesSdkAdapter,\n FilesHooks as FilesSdkHooks,\n FilesPlugin as FilesSdkPlugin,\n} from 'files-sdk';\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/files-sdk/provider/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACzC,OAAO,EAAa,KAAK,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AACpE,OAAO,EAKL,KAAK,MAAM,EACX,KAAK,QAAQ,EACb,KAAK,YAAY,EAClB,MAAM,qBAAqB,CAAC;AAG7B,OAAO,EAGL,KAAK,qBAAqB,EAC1B,KAAK,qBAAqB,EAC3B,MAAM,wBAAwB,CAAC;AAEhC,sEAAsE;AACtE,MAAM,MAAM,mBAAmB,GAAG,YAAY,CAAC;AAE/C;;;;;;;;GAQG;AACH,MAAM,MAAM,qBAAqB,GAAG,IAAI,CAAC,gBAAgB,EAAE,UAAU,CAAC,CAAC;AAEvE,MAAM,WAAW,4BAA6B,SAAQ,IAAI,CACxD,qBAAqB,CAAC,OAAO,CAAC,EAC9B,SAAS,CACV;IACC,wFAAwF;IACxF,QAAQ,EAAE,mBAAmB,CAAC;IAC9B,MAAM,CAAC,EAAE,qBAAqB,CAAC;CAChC;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAsB,2BAA2B,CAC/C,OAAO,EAAE,4BAA4B,GACpC,OAAO,CAAC,qBAAqB,CAAC,CAWhC;AAoCD,iFAAiF;AACjF,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,MAAM,GAAG,KAAK,IAAI,mBAAmB,CAE7E;AAED,wDAAwD;AACxD,wBAAgB,oBAAoB,IAAI,SAAS,QAAQ,EAAE,CAE1D;AAED,+EAA+E;AAC/E,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,GAAG,QAAQ,GAAG,SAAS,CAErE;AAED;;;;GAIG;AACH,wBAAgB,0BAA0B,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE,CAEjE;AAED,6EAA6E;AAC7E,wBAAgB,gCAAgC,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE,CAEvE;AAED,YAAY,EACV,MAAM,IAAI,qBAAqB,EAC/B,QAAQ,IAAI,mBAAmB,GAChC,MAAM,qBAAqB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/files-sdk/provider/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACzC,OAAO,EAAa,KAAK,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AACpE,OAAO,EAKL,KAAK,MAAM,EACX,KAAK,QAAQ,EACb,KAAK,YAAY,EAClB,MAAM,qBAAqB,CAAC;AAG7B,OAAO,EAGL,KAAK,qBAAqB,EAC1B,KAAK,qBAAqB,EAC3B,MAAM,wBAAwB,CAAC;AAEhC,sEAAsE;AACtE,MAAM,MAAM,mBAAmB,GAAG,YAAY,CAAC;AAE/C;;;;;;;;GAQG;AACH,MAAM,MAAM,qBAAqB,GAAG,IAAI,CAAC,gBAAgB,EAAE,UAAU,CAAC,CAAC;AAEvE,MAAM,WAAW,4BAA6B,SAAQ,IAAI,CACxD,qBAAqB,CAAC,OAAO,CAAC,EAC9B,SAAS,CACV;IACC,wFAAwF;IACxF,QAAQ,EAAE,mBAAmB,CAAC;IAC9B,MAAM,CAAC,EAAE,qBAAqB,CAAC;CAChC;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAsB,2BAA2B,CAC/C,OAAO,EAAE,4BAA4B,GACpC,OAAO,CAAC,qBAAqB,CAAC,CAWhC;AA6CD,iFAAiF;AACjF,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,MAAM,GAAG,KAAK,IAAI,mBAAmB,CAE7E;AAED,wDAAwD;AACxD,wBAAgB,oBAAoB,IAAI,SAAS,QAAQ,EAAE,CAE1D;AAED,+EAA+E;AAC/E,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,GAAG,QAAQ,GAAG,SAAS,CAErE;AAED;;;;GAIG;AACH,wBAAgB,0BAA0B,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE,CAEjE;AAED,6EAA6E;AAC7E,wBAAgB,gCAAgC,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE,CAEvE;AAED,YAAY,EACV,MAAM,IAAI,qBAAqB,EAC/B,QAAQ,IAAI,mBAAmB,GAChC,MAAM,qBAAqB,CAAC"}
@@ -38,6 +38,10 @@ async function resolveAdapter(provider, config) {
38
38
  throw mapFilesSdkError(error);
39
39
  }
40
40
  const { adapter } = resolved.files;
41
+ if (provider === 'fs') {
42
+ const { withFsConditionalMutation } = await import('../fs/index.js');
43
+ return withFsConditionalMutation(adapter);
44
+ }
41
45
  if (provider !== 's3') {
42
46
  return adapter;
43
47
  }
@@ -45,6 +49,9 @@ async function resolveAdapter(provider, config) {
45
49
  // holds. The S3-compatible wrappers keep only what they declare themselves.
46
50
  const { withS3Capabilities } = await import('../s3/index.js');
47
51
  return withS3Capabilities(adapter, {
52
+ ...(typeof config?.endpoint === 'string' && {
53
+ endpoint: config.endpoint,
54
+ }),
48
55
  ...(config?.publicBaseUrl !== undefined && {
49
56
  publicBaseUrl: config.publicBaseUrl,
50
57
  }),
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/files-sdk/provider/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,SAAS,EAAyB,MAAM,kBAAkB,CAAC;AACpE,OAAO,EACL,cAAc,EACd,WAAW,EACX,gBAAgB,EAChB,WAAW,GAIZ,MAAM,qBAAqB,CAAC;AAE7B,OAAO,EAAE,YAAY,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AACxE,OAAO,EACL,oBAAoB,EACpB,gBAAgB,GAGjB,MAAM,wBAAwB,CAAC;AAyBhC;;;;;;;;;;;;;;;GAeG;AACH,MAAM,CAAC,KAAK,UAAU,2BAA2B,CAC/C,OAAqC;IAErC,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,GAAG,YAAY,EAAE,GAAG,OAAO,CAAC;IACtD,IAAI,CAAC,iBAAiB,CAAC,QAAQ,CAAC,EAAE,CAAC;QACjC,MAAM,eAAe,CAAC,QAAQ,CAAC,CAAC;IAClC,CAAC;IAED,6EAA6E;IAC7E,6EAA6E;IAC7E,8EAA8E;IAC9E,MAAM,OAAO,GAAG,MAAM,cAAc,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;IACvD,OAAO,oBAAoB,CAAC,EAAE,GAAG,YAAY,EAAE,OAAO,EAAE,CAAC,CAAC;AAC5D,CAAC;AAED,KAAK,UAAU,cAAc,CAC3B,QAA6B,EAC7B,MAAyC;IAEzC,IAAI,QAAQ,CAAC;IACb,IAAI,CAAC;QACH,QAAQ,GAAG,MAAM,SAAS,CAAC,EAAE,GAAG,MAAM,EAAE,QAAQ,EAAE,CAAC,CAAC;IACtD,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,MAAM,gBAAgB,CAAC,KAAK,CAAC,CAAC;IAChC,CAAC;IACD,MAAM,EAAE,OAAO,EAAE,GAAG,QAAQ,CAAC,KAAK,CAAC;IACnC,IAAI,QAAQ,KAAK,IAAI,EAAE,CAAC;QACtB,OAAO,OAAO,CAAC;IACjB,CAAC;IACD,yEAAyE;IACzE,4EAA4E;IAC5E,MAAM,EAAE,kBAAkB,EAAE,GAAG,MAAM,MAAM,CAAC,gBAAgB,CAAC,CAAC;IAC9D,OAAO,kBAAkB,CACvB,OAAmD,EACnD;QACE,GAAG,CAAC,MAAM,EAAE,aAAa,KAAK,SAAS,IAAI;YACzC,aAAa,EAAE,MAAM,CAAC,aAAa;SACpC,CAAC;KACH,CACF,CAAC;AACJ,CAAC;AAED,SAAS,eAAe,CAAC,QAAgB;IACvC,OAAO,IAAI,YAAY,CACrB,6BAA6B,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,sBAAsB,cAAc,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,EACvG,EAAE,IAAI,EAAE,gBAAgB,CAAC,gBAAgB,EAAE,SAAS,EAAE,IAAI,EAAE,CAC7D,CAAC;AACJ,CAAC;AAED,iFAAiF;AACjF,MAAM,UAAU,iBAAiB,CAAC,KAAa;IAC7C,OAAO,WAAW,CAAC,KAAK,CAAC,KAAK,SAAS,CAAC;AAC1C,CAAC;AAED,wDAAwD;AACxD,MAAM,UAAU,oBAAoB;IAClC,OAAO,cAAc,CAAC,OAAO,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,WAAW,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC;AACnE,CAAC;AAED,+EAA+E;AAC/E,MAAM,UAAU,kBAAkB,CAAC,IAAY;IAC7C,OAAO,WAAW,CAAC,IAAI,CAAC,CAAC;AAC3B,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,0BAA0B,CAAC,IAAY;IACrD,OAAO,WAAW,CAAC,IAAI,CAAC,CAAC;AAC3B,CAAC;AAED,6EAA6E;AAC7E,MAAM,UAAU,gCAAgC,CAAC,IAAY;IAC3D,OAAO,gBAAgB,CAAC,IAAI,CAAC,CAAC;AAChC,CAAC","sourcesContent":["import type { Adapter } from 'files-sdk';\nimport { loadFiles, type LoadFilesOptions } from 'files-sdk/loader';\nimport {\n PROVIDER_NAMES,\n getProvider,\n getSecretEnvVars,\n listEnvVars,\n type EnvVar,\n type Provider,\n type ProviderSlug,\n} from 'files-sdk/providers';\n\nimport { StorageError, StorageErrorCode } from '../../storage.error.js';\nimport {\n createFilesSdkDriver,\n mapFilesSdkError,\n type FilesSdkDriverOptions,\n type FilesSdkStorageDriver,\n} from '../files-sdk.driver.js';\n\n/** Slug of a storage provider this package can build a driver for. */\nexport type StorageProviderName = ProviderSlug;\n\n/**\n * Flat, provider-specific settings — `bucket` and `region` for an object store,\n * `root` for the filesystem, `accountName` and `container` for Azure, and so\n * on. Every provider reads what it needs and ignores the rest, so one config\n * shape serves a deployment that switches providers by name.\n *\n * Credentials may be omitted for any provider whose SDK resolves its own chain\n * (an IAM role, Application Default Credentials, a shared profile).\n */\nexport type StorageProviderConfig = Omit<LoadFilesOptions, 'provider'>;\n\nexport interface ProviderStorageDriverOptions extends Omit<\n FilesSdkDriverOptions<Adapter>,\n 'adapter'\n> {\n /** Which provider to build. Validate untrusted input with {@link isStorageProvider}. */\n provider: StorageProviderName;\n config?: StorageProviderConfig;\n}\n\n/**\n * Builds a {@link FilesSdkStorageDriver} for a provider named at runtime,\n * importing that provider's adapter — and only that one — on demand. A\n * deployment selects its store with a string (`'s3'`, `'gcs'`, `'azure'`,\n * `'r2'`, `'fs'`, …) and installs one native SDK, instead of the application\n * hard-coding a driver per backend.\n *\n * The `s3` slug additionally gets the conditional-promotion and signed-policy\n * capabilities {@link createS3StorageDriver} attaches; every other provider\n * exposes exactly what its adapter declares. Import\n * `@nestm/storage/files-sdk/s3` directly when the provider is known at build\n * time and the extra indirection buys nothing.\n *\n * @throws StorageError `INVALID_ARGUMENT` for an unknown slug, and whatever the\n * adapter reports (mapped) when required config or credentials are missing.\n */\nexport async function createProviderStorageDriver(\n options: ProviderStorageDriverOptions,\n): Promise<FilesSdkStorageDriver> {\n const { provider, config, ...filesOptions } = options;\n if (!isStorageProvider(provider)) {\n throw unknownProvider(provider);\n }\n\n // `loadFiles` owns the slug → adapter mapping and keeps the import lazy; the\n // client it returns is discarded so the caller's own driver options (prefix,\n // hooks, plugins, readonly, retries) apply to the instance the bridge builds.\n const adapter = await resolveAdapter(provider, config);\n return createFilesSdkDriver({ ...filesOptions, adapter });\n}\n\nasync function resolveAdapter(\n provider: StorageProviderName,\n config: StorageProviderConfig | undefined,\n): Promise<Adapter> {\n let resolved;\n try {\n resolved = await loadFiles({ ...config, provider });\n } catch (error) {\n throw mapFilesSdkError(error);\n }\n const { adapter } = resolved.files;\n if (provider !== 's3') {\n return adapter;\n }\n // Built by `s3(...)`, so its `raw` is an S3Client and the promotion path\n // holds. The S3-compatible wrappers keep only what they declare themselves.\n const { withS3Capabilities } = await import('../s3/index.js');\n return withS3Capabilities(\n adapter as Parameters<typeof withS3Capabilities>[0],\n {\n ...(config?.publicBaseUrl !== undefined && {\n publicBaseUrl: config.publicBaseUrl,\n }),\n },\n );\n}\n\nfunction unknownProvider(provider: string): StorageError {\n return new StorageError(\n `Unknown storage provider: ${JSON.stringify(provider)}. Known providers: ${PROVIDER_NAMES.join(', ')}.`,\n { code: StorageErrorCode.INVALID_ARGUMENT, permanent: true },\n );\n}\n\n/** Narrows an untrusted string — an env var, a config file — to a known slug. */\nexport function isStorageProvider(value: string): value is StorageProviderName {\n return getProvider(value) !== undefined;\n}\n\n/** Every provider that can be named, sorted by slug. */\nexport function listStorageProviders(): readonly Provider[] {\n return PROVIDER_NAMES.flatMap((slug) => getProvider(slug) ?? []);\n}\n\n/** One provider's display name, description, native SDKs, and env contract. */\nexport function getStorageProvider(slug: string): Provider | undefined {\n return getProvider(slug);\n}\n\n/**\n * Every environment variable a provider reads, flattened across required, all\n * credential modes, and optional. Useful for validating a deployment's config\n * before the first upload rather than at it.\n */\nexport function listStorageProviderEnvVars(slug: string): EnvVar[] {\n return listEnvVars(slug);\n}\n\n/** The subset of {@link listStorageProviderEnvVars} that carries secrets. */\nexport function listStorageProviderSecretEnvVars(slug: string): EnvVar[] {\n return getSecretEnvVars(slug);\n}\n\nexport type {\n EnvVar as StorageProviderEnvVar,\n Provider as StorageProviderInfo,\n} from 'files-sdk/providers';\n"]}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/files-sdk/provider/index.ts"],"names":[],"mappings":"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","sourcesContent":["import type { Adapter } from 'files-sdk';\nimport { loadFiles, type LoadFilesOptions } from 'files-sdk/loader';\nimport {\n PROVIDER_NAMES,\n getProvider,\n getSecretEnvVars,\n listEnvVars,\n type EnvVar,\n type Provider,\n type ProviderSlug,\n} from 'files-sdk/providers';\n\nimport { StorageError, StorageErrorCode } from '../../storage.error.js';\nimport {\n createFilesSdkDriver,\n mapFilesSdkError,\n type FilesSdkDriverOptions,\n type FilesSdkStorageDriver,\n} from '../files-sdk.driver.js';\n\n/** Slug of a storage provider this package can build a driver for. */\nexport type StorageProviderName = ProviderSlug;\n\n/**\n * Flat, provider-specific settings — `bucket` and `region` for an object store,\n * `root` for the filesystem, `accountName` and `container` for Azure, and so\n * on. Every provider reads what it needs and ignores the rest, so one config\n * shape serves a deployment that switches providers by name.\n *\n * Credentials may be omitted for any provider whose SDK resolves its own chain\n * (an IAM role, Application Default Credentials, a shared profile).\n */\nexport type StorageProviderConfig = Omit<LoadFilesOptions, 'provider'>;\n\nexport interface ProviderStorageDriverOptions extends Omit<\n FilesSdkDriverOptions<Adapter>,\n 'adapter'\n> {\n /** Which provider to build. Validate untrusted input with {@link isStorageProvider}. */\n provider: StorageProviderName;\n config?: StorageProviderConfig;\n}\n\n/**\n * Builds a {@link FilesSdkStorageDriver} for a provider named at runtime,\n * importing that provider's adapter — and only that one — on demand. A\n * deployment selects its store with a string (`'s3'`, `'gcs'`, `'azure'`,\n * `'r2'`, `'fs'`, …) and installs one native SDK, instead of the application\n * hard-coding a driver per backend.\n *\n * The `s3` slug additionally gets the conditional-promotion and signed-policy\n * capabilities {@link createS3StorageDriver} attaches; every other provider\n * exposes exactly what its adapter declares. Import\n * `@nestm/storage/files-sdk/s3` directly when the provider is known at build\n * time and the extra indirection buys nothing.\n *\n * @throws StorageError `INVALID_ARGUMENT` for an unknown slug, and whatever the\n * adapter reports (mapped) when required config or credentials are missing.\n */\nexport async function createProviderStorageDriver(\n options: ProviderStorageDriverOptions,\n): Promise<FilesSdkStorageDriver> {\n const { provider, config, ...filesOptions } = options;\n if (!isStorageProvider(provider)) {\n throw unknownProvider(provider);\n }\n\n // `loadFiles` owns the slug → adapter mapping and keeps the import lazy; the\n // client it returns is discarded so the caller's own driver options (prefix,\n // hooks, plugins, readonly, retries) apply to the instance the bridge builds.\n const adapter = await resolveAdapter(provider, config);\n return createFilesSdkDriver({ ...filesOptions, adapter });\n}\n\nasync function resolveAdapter(\n provider: StorageProviderName,\n config: StorageProviderConfig | undefined,\n): Promise<Adapter> {\n let resolved;\n try {\n resolved = await loadFiles({ ...config, provider });\n } catch (error) {\n throw mapFilesSdkError(error);\n }\n const { adapter } = resolved.files;\n if (provider === 'fs') {\n const { withFsConditionalMutation } = await import('../fs/index.js');\n return withFsConditionalMutation(\n adapter as Parameters<typeof withFsConditionalMutation>[0],\n );\n }\n if (provider !== 's3') {\n return adapter;\n }\n // Built by `s3(...)`, so its `raw` is an S3Client and the promotion path\n // holds. The S3-compatible wrappers keep only what they declare themselves.\n const { withS3Capabilities } = await import('../s3/index.js');\n return withS3Capabilities(\n adapter as Parameters<typeof withS3Capabilities>[0],\n {\n ...(typeof config?.endpoint === 'string' && {\n endpoint: config.endpoint,\n }),\n ...(config?.publicBaseUrl !== undefined && {\n publicBaseUrl: config.publicBaseUrl,\n }),\n },\n );\n}\n\nfunction unknownProvider(provider: string): StorageError {\n return new StorageError(\n `Unknown storage provider: ${JSON.stringify(provider)}. Known providers: ${PROVIDER_NAMES.join(', ')}.`,\n { code: StorageErrorCode.INVALID_ARGUMENT, permanent: true },\n );\n}\n\n/** Narrows an untrusted string — an env var, a config file — to a known slug. */\nexport function isStorageProvider(value: string): value is StorageProviderName {\n return getProvider(value) !== undefined;\n}\n\n/** Every provider that can be named, sorted by slug. */\nexport function listStorageProviders(): readonly Provider[] {\n return PROVIDER_NAMES.flatMap((slug) => getProvider(slug) ?? []);\n}\n\n/** One provider's display name, description, native SDKs, and env contract. */\nexport function getStorageProvider(slug: string): Provider | undefined {\n return getProvider(slug);\n}\n\n/**\n * Every environment variable a provider reads, flattened across required, all\n * credential modes, and optional. Useful for validating a deployment's config\n * before the first upload rather than at it.\n */\nexport function listStorageProviderEnvVars(slug: string): EnvVar[] {\n return listEnvVars(slug);\n}\n\n/** The subset of {@link listStorageProviderEnvVars} that carries secrets. */\nexport function listStorageProviderSecretEnvVars(slug: string): EnvVar[] {\n return getSecretEnvVars(slug);\n}\n\nexport type {\n EnvVar as StorageProviderEnvVar,\n Provider as StorageProviderInfo,\n} from 'files-sdk/providers';\n"]}
@@ -1,9 +1,16 @@
1
1
  import { type S3Adapter, type S3AdapterOptions } from 'files-sdk/s3';
2
- import { type FilesSdkConditionalCopyAdapter, type FilesSdkDriverOptions, type FilesSdkSignedUploadPolicyAdapter, type FilesSdkSignedDownloadPolicyAdapter, type FilesSdkStorageDriver } from '../files-sdk.driver.js';
2
+ import { type FilesSdkConditionalCopyAdapter, type FilesSdkConditionalMutationAdapter, type FilesSdkDriverOptions, type FilesSdkSignedUploadPolicyAdapter, type FilesSdkSignedDownloadPolicyAdapter, type FilesSdkStorageDriver } from '../files-sdk.driver.js';
3
3
  export interface S3StorageDriverOptions extends Omit<FilesSdkDriverOptions<S3Adapter>, 'adapter'> {
4
4
  adapter: S3AdapterOptions;
5
+ /**
6
+ * Opt in or out of conditional writes for an S3-compatible endpoint whose
7
+ * support is known. Native AWS S3 enables them by default; custom endpoints
8
+ * default to false because compatibility varies.
9
+ */
10
+ conditionalMutation?: boolean;
5
11
  }
6
- export type S3StorageAdapter = S3Adapter & FilesSdkConditionalCopyAdapter & FilesSdkSignedDownloadPolicyAdapter & FilesSdkSignedUploadPolicyAdapter;
12
+ type S3StorageAdapterBase = S3Adapter & FilesSdkConditionalCopyAdapter & FilesSdkSignedDownloadPolicyAdapter & FilesSdkSignedUploadPolicyAdapter;
13
+ export type S3StorageAdapter = S3StorageAdapterBase & Partial<FilesSdkConditionalMutationAdapter>;
7
14
  /**
8
15
  * Adds the S3-only capabilities to an adapter already built by `s3(...)`: an
9
16
  * ETag/version-conditional server-side promotion, and the signed upload and
@@ -14,7 +21,9 @@ export type S3StorageAdapter = S3Adapter & FilesSdkConditionalCopyAdapter & File
14
21
  * from flat provider config. It expects an adapter whose `raw` is an `S3Client`
15
22
  * — pass one built by `s3(...)`, not an S3-compatible wrapper.
16
23
  */
17
- export declare function withS3Capabilities(base: S3Adapter, options?: Pick<S3AdapterOptions, 'publicBaseUrl'>): S3StorageAdapter;
24
+ export declare function withS3Capabilities(base: S3Adapter, options?: Pick<S3AdapterOptions, 'endpoint' | 'publicBaseUrl'> & {
25
+ conditionalMutation?: boolean;
26
+ }): S3StorageAdapter;
18
27
  /**
19
28
  * Creates the files-sdk S3 driver from the storage package's own dependency
20
29
  * context and adds an ETag/version-conditional server-side promotion.
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/files-sdk/s3/index.ts"],"names":[],"mappings":"AACA,OAAO,EAGL,KAAK,SAAS,EACd,KAAK,gBAAgB,EACtB,MAAM,cAAc,CAAC;AAGtB,OAAO,EAEL,KAAK,8BAA8B,EACnC,KAAK,qBAAqB,EAC1B,KAAK,iCAAiC,EACtC,KAAK,mCAAmC,EACxC,KAAK,qBAAqB,EAE3B,MAAM,wBAAwB,CAAC;AAEhC,MAAM,WAAW,sBAAuB,SAAQ,IAAI,CAClD,qBAAqB,CAAC,SAAS,CAAC,EAChC,SAAS,CACV;IACC,OAAO,EAAE,gBAAgB,CAAC;CAC3B;AAED,MAAM,MAAM,gBAAgB,GAAG,SAAS,GACtC,8BAA8B,GAC9B,mCAAmC,GACnC,iCAAiC,CAAC;AA6DpC;;;;;;;;;GASG;AACH,wBAAgB,kBAAkB,CAChC,IAAI,EAAE,SAAS,EACf,OAAO,GAAE,IAAI,CAAC,gBAAgB,EAAE,eAAe,CAAM,GACpD,gBAAgB,CAkElB;AAED;;;GAGG;AACH,wBAAgB,qBAAqB,CACnC,OAAO,EAAE,sBAAsB,GAC9B,qBAAqB,CAAC,gBAAgB,CAAC,CAMzC;AAED,OAAO,EAAE,UAAU,EAAE,EAAE,EAAE,MAAM,cAAc,CAAC;AAC9C,YAAY,EAAE,SAAS,EAAE,gBAAgB,EAAE,KAAK,EAAE,MAAM,cAAc,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/files-sdk/s3/index.ts"],"names":[],"mappings":"AAMA,OAAO,EAGL,KAAK,SAAS,EACd,KAAK,gBAAgB,EACtB,MAAM,cAAc,CAAC;AAWtB,OAAO,EAEL,KAAK,8BAA8B,EACnC,KAAK,kCAAkC,EACvC,KAAK,qBAAqB,EAC1B,KAAK,iCAAiC,EACtC,KAAK,mCAAmC,EACxC,KAAK,qBAAqB,EAE3B,MAAM,wBAAwB,CAAC;AAEhC,MAAM,WAAW,sBAAuB,SAAQ,IAAI,CAClD,qBAAqB,CAAC,SAAS,CAAC,EAChC,SAAS,CACV;IACC,OAAO,EAAE,gBAAgB,CAAC;IAC1B;;;;OAIG;IACH,mBAAmB,CAAC,EAAE,OAAO,CAAC;CAC/B;AAED,KAAK,oBAAoB,GAAG,SAAS,GACnC,8BAA8B,GAC9B,mCAAmC,GACnC,iCAAiC,CAAC;AAEpC,MAAM,MAAM,gBAAgB,GAAG,oBAAoB,GACjD,OAAO,CAAC,kCAAkC,CAAC,CAAC;AAmL9C;;;;;;;;;GASG;AACH,wBAAgB,kBAAkB,CAChC,IAAI,EAAE,SAAS,EACf,OAAO,GAAE,IAAI,CAAC,gBAAgB,EAAE,UAAU,GAAG,eAAe,CAAC,GAAG;IAC9D,mBAAmB,CAAC,EAAE,OAAO,CAAC;CAC1B,GACL,gBAAgB,CA6JlB;AAED;;;GAGG;AACH,wBAAgB,qBAAqB,CACnC,OAAO,EAAE,sBAAsB,GAC9B,qBAAqB,CAAC,gBAAgB,CAAC,CAUzC;AAED,OAAO,EAAE,UAAU,EAAE,EAAE,EAAE,MAAM,cAAc,CAAC;AAC9C,YAAY,EAAE,SAAS,EAAE,gBAAgB,EAAE,KAAK,EAAE,MAAM,cAAc,CAAC"}
@@ -1,5 +1,7 @@
1
- import { CopyObjectCommand } from '@aws-sdk/client-s3';
1
+ import { CopyObjectCommand, DeleteObjectCommand, PutObjectCommand, } from '@aws-sdk/client-s3';
2
+ import { Readable } from 'node:stream';
2
3
  import { mapS3Error, s3, } from 'files-sdk/s3';
4
+ import { StorageError, StorageErrorCode } from '../../storage.error.js';
3
5
  import { createFilesSdkDriver, mapFilesSdkError, } from '../files-sdk.driver.js';
4
6
  function copySource(bucket, key, version) {
5
7
  const source = `${encodeURIComponent(bucket)}/${encodeURIComponent(key)}`;
@@ -24,6 +26,105 @@ function maxRetries(options) {
24
26
  : options.retries?.max;
25
27
  return Math.max(0, Math.floor(configured ?? 0));
26
28
  }
29
+ function etagHeader(etag) {
30
+ return etag.startsWith('"') && etag.endsWith('"') ? etag : `"${etag}"`;
31
+ }
32
+ function stripEtag(etag) {
33
+ return etag?.replace(/^"+|"+$/gu, '');
34
+ }
35
+ function contentTypeOf(body, override) {
36
+ if (override !== undefined) {
37
+ return override;
38
+ }
39
+ if (typeof body === 'string') {
40
+ return 'text/plain; charset=utf-8';
41
+ }
42
+ if (body instanceof Blob && body.type.length > 0) {
43
+ return body.type;
44
+ }
45
+ return 'application/octet-stream';
46
+ }
47
+ async function normalizeConditionalBody(body, onProgress) {
48
+ let bytes;
49
+ if (typeof body === 'string') {
50
+ bytes = new TextEncoder().encode(body);
51
+ }
52
+ else if (body instanceof Uint8Array) {
53
+ bytes = body;
54
+ }
55
+ else if (body instanceof ArrayBuffer) {
56
+ bytes = new Uint8Array(body);
57
+ }
58
+ else if (ArrayBuffer.isView(body)) {
59
+ bytes = new Uint8Array(body.buffer, body.byteOffset, body.byteLength);
60
+ }
61
+ else if (body instanceof Blob) {
62
+ bytes = new Uint8Array(await body.arrayBuffer());
63
+ }
64
+ if (bytes !== undefined) {
65
+ const total = bytes.byteLength;
66
+ onProgress?.({ loaded: 0, total });
67
+ return { body: bytes, contentLength: total, size: () => total };
68
+ }
69
+ const stream = body instanceof Readable
70
+ ? Readable.toWeb(body)
71
+ : body;
72
+ if (!(stream instanceof ReadableStream)) {
73
+ throw new StorageError('Unsupported conditional upload body.', {
74
+ code: StorageErrorCode.INVALID_ARGUMENT,
75
+ operation: 'upload',
76
+ permanent: true,
77
+ });
78
+ }
79
+ const reader = stream.getReader();
80
+ let loaded = 0;
81
+ return {
82
+ body: new ReadableStream({
83
+ cancel(reason) {
84
+ return reader.cancel(reason);
85
+ },
86
+ async pull(controller) {
87
+ const result = await reader.read();
88
+ if (result.done) {
89
+ controller.close();
90
+ return;
91
+ }
92
+ loaded += result.value.byteLength;
93
+ controller.enqueue(result.value);
94
+ onProgress?.({ loaded });
95
+ },
96
+ }),
97
+ size: () => loaded,
98
+ };
99
+ }
100
+ async function withS3Retry(options, operation) {
101
+ const retries = maxRetries(options);
102
+ for (let attempt = 0;; attempt += 1) {
103
+ const signal = operationSignal(options);
104
+ try {
105
+ return await operation(signal);
106
+ }
107
+ catch (error) {
108
+ const mapped = mapS3Error(error);
109
+ if (attempt >= retries ||
110
+ mapped.code !== 'Provider' ||
111
+ mapped.aborted ||
112
+ mapped.permanent ||
113
+ signal?.aborted === true) {
114
+ throw mapped;
115
+ }
116
+ const storageError = mapFilesSdkError(mapped);
117
+ const delay = typeof options.retries === 'object' &&
118
+ options.retries.backoff !== undefined
119
+ ? options.retries.backoff({
120
+ attempt: attempt + 1,
121
+ error: storageError,
122
+ })
123
+ : Math.min(1000, 100 * 2 ** attempt);
124
+ await waitForRetry(delay, options.signal);
125
+ }
126
+ }
127
+ }
27
128
  async function waitForRetry(milliseconds, signal) {
28
129
  if (signal?.aborted === true) {
29
130
  throw signal.reason;
@@ -53,7 +154,8 @@ async function waitForRetry(milliseconds, signal) {
53
154
  * — pass one built by `s3(...)`, not an S3-compatible wrapper.
54
155
  */
55
156
  export function withS3Capabilities(base, options = {}) {
56
- return Object.assign(base, {
157
+ const supportsConditionalMutation = options.conditionalMutation ?? options.endpoint === undefined;
158
+ const common = Object.assign(base, {
57
159
  conditionalCopy: Object.freeze({
58
160
  etag: true,
59
161
  supported: true,
@@ -67,40 +169,100 @@ export function withS3Capabilities(base, options = {}) {
67
169
  expiresIn: options.publicBaseUrl === undefined,
68
170
  }),
69
171
  async promote(sourceKey, destinationKey, promotion) {
70
- const retries = maxRetries(promotion);
71
- for (let attempt = 0;; attempt += 1) {
72
- const signal = operationSignal(promotion);
73
- try {
74
- await base.raw.send(new CopyObjectCommand({
75
- Bucket: base.bucket,
76
- CopySource: copySource(base.bucket, sourceKey, promotion.sourceVersion),
77
- ...(promotion.sourceEtag !== undefined && {
78
- CopySourceIfMatch: promotion.sourceEtag,
79
- }),
80
- Key: destinationKey,
81
- }), signal === undefined ? undefined : { abortSignal: signal });
82
- return;
83
- }
84
- catch (error) {
85
- const mapped = mapS3Error(error);
86
- if (attempt >= retries ||
87
- mapped.code !== 'Provider' ||
88
- mapped.aborted ||
89
- mapped.permanent ||
90
- signal?.aborted === true) {
91
- throw mapped;
92
- }
93
- const storageError = mapFilesSdkError(mapped);
94
- const delay = typeof promotion.retries === 'object' &&
95
- promotion.retries.backoff !== undefined
96
- ? promotion.retries.backoff({
97
- attempt: attempt + 1,
98
- error: storageError,
99
- })
100
- : Math.min(1000, 100 * 2 ** attempt);
101
- await waitForRetry(delay, promotion.signal);
102
- }
172
+ await withS3Retry(promotion, async (signal) => {
173
+ await base.raw.send(new CopyObjectCommand({
174
+ Bucket: base.bucket,
175
+ CopySource: copySource(base.bucket, sourceKey, promotion.sourceVersion),
176
+ ...(promotion.sourceEtag !== undefined && {
177
+ CopySourceIfMatch: promotion.sourceEtag,
178
+ }),
179
+ Key: destinationKey,
180
+ }), signal === undefined ? undefined : { abortSignal: signal });
181
+ });
182
+ },
183
+ });
184
+ if (!supportsConditionalMutation) {
185
+ return common;
186
+ }
187
+ return Object.assign(common, {
188
+ conditionalMutation: Object.freeze({
189
+ create: true,
190
+ delete: true,
191
+ etag: true,
192
+ replace: true,
193
+ }),
194
+ async deleteConditional(key, options) {
195
+ await withS3Retry(options, async (signal) => {
196
+ await base.raw.send(new DeleteObjectCommand({
197
+ Bucket: base.bucket,
198
+ IfMatch: etagHeader(options.condition.etag),
199
+ Key: key,
200
+ }), signal === undefined ? undefined : { abortSignal: signal });
201
+ });
202
+ },
203
+ async uploadConditional(key, body, conditional) {
204
+ if (conditional.multipart !== undefined &&
205
+ conditional.multipart !== false) {
206
+ throw new StorageError('Conditional S3 uploads do not support multipart mode.', {
207
+ code: StorageErrorCode.NOT_SUPPORTED,
208
+ key,
209
+ operation: 'upload',
210
+ permanent: true,
211
+ });
212
+ }
213
+ if (conditional.control !== undefined) {
214
+ throw new StorageError('Conditional S3 uploads do not support resumable control.', {
215
+ code: StorageErrorCode.NOT_SUPPORTED,
216
+ key,
217
+ operation: 'upload',
218
+ permanent: true,
219
+ });
103
220
  }
221
+ const normalized = await normalizeConditionalBody(body, conditional.onProgress);
222
+ const contentType = contentTypeOf(body, conditional.contentType);
223
+ const retryOptions = normalized.contentLength === undefined
224
+ ? { ...conditional, retries: 0 }
225
+ : conditional;
226
+ const result = await withS3Retry(retryOptions, (signal) => base.raw.send(new PutObjectCommand({
227
+ Body: normalized.body,
228
+ Bucket: base.bucket,
229
+ ...(conditional.cacheControl !== undefined && {
230
+ CacheControl: conditional.cacheControl,
231
+ }),
232
+ ...(normalized.contentLength !== undefined && {
233
+ ContentLength: normalized.contentLength,
234
+ }),
235
+ ContentType: contentType,
236
+ ...(conditional.condition.type === 'create'
237
+ ? { IfNoneMatch: '*' }
238
+ : { IfMatch: etagHeader(conditional.condition.etag) }),
239
+ Key: key,
240
+ ...(conditional.metadata !== undefined && {
241
+ Metadata: conditional.metadata,
242
+ }),
243
+ }), signal === undefined ? undefined : { abortSignal: signal }));
244
+ const size = normalized.size();
245
+ conditional.onProgress?.({
246
+ loaded: size,
247
+ ...(normalized.contentLength !== undefined && {
248
+ total: normalized.contentLength,
249
+ }),
250
+ });
251
+ const etag = stripEtag(result.ETag);
252
+ if (etag === undefined || etag.length === 0) {
253
+ throw new StorageError('S3 committed a conditional upload without returning the ETag required to identify its result; reconcile the destination before retrying.', {
254
+ code: StorageErrorCode.PROVIDER,
255
+ key,
256
+ operation: 'upload',
257
+ permanent: true,
258
+ });
259
+ }
260
+ return {
261
+ contentType,
262
+ etag,
263
+ key,
264
+ size,
265
+ };
104
266
  },
105
267
  });
106
268
  }
@@ -110,9 +272,13 @@ export function withS3Capabilities(base, options = {}) {
110
272
  */
111
273
  export function createS3StorageDriver(options) {
112
274
  const { adapter: adapterOptions, ...filesOptions } = options;
275
+ const { conditionalMutation, ...plainFilesOptions } = filesOptions;
113
276
  return createFilesSdkDriver({
114
- ...filesOptions,
115
- adapter: withS3Capabilities(s3(adapterOptions), adapterOptions),
277
+ ...plainFilesOptions,
278
+ adapter: withS3Capabilities(s3(adapterOptions), {
279
+ ...adapterOptions,
280
+ ...(conditionalMutation !== undefined && { conditionalMutation }),
281
+ }),
116
282
  });
117
283
  }
118
284
  export { mapS3Error, s3 } from 'files-sdk/s3';
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/files-sdk/s3/index.ts"],"names":[],"mappings":"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","sourcesContent":["import { CopyObjectCommand } from '@aws-sdk/client-s3';\nimport {\n mapS3Error,\n s3,\n type S3Adapter,\n type S3AdapterOptions,\n} from 'files-sdk/s3';\n\nimport type { StoragePromotionOptions } from '../../storage.types.js';\nimport {\n createFilesSdkDriver,\n type FilesSdkConditionalCopyAdapter,\n type FilesSdkDriverOptions,\n type FilesSdkSignedUploadPolicyAdapter,\n type FilesSdkSignedDownloadPolicyAdapter,\n type FilesSdkStorageDriver,\n mapFilesSdkError,\n} from '../files-sdk.driver.js';\n\nexport interface S3StorageDriverOptions extends Omit<\n FilesSdkDriverOptions<S3Adapter>,\n 'adapter'\n> {\n adapter: S3AdapterOptions;\n}\n\nexport type S3StorageAdapter = S3Adapter &\n FilesSdkConditionalCopyAdapter &\n FilesSdkSignedDownloadPolicyAdapter &\n FilesSdkSignedUploadPolicyAdapter;\n\nfunction copySource(\n bucket: string,\n key: string,\n version: string | undefined,\n): string {\n const source = `${encodeURIComponent(bucket)}/${encodeURIComponent(key)}`;\n return version === undefined\n ? source\n : `${source}?versionId=${encodeURIComponent(version)}`;\n}\n\nfunction operationSignal(\n options: StoragePromotionOptions,\n): AbortSignal | undefined {\n const timeoutSignal =\n options.timeout === undefined || options.timeout <= 0\n ? undefined\n : AbortSignal.timeout(options.timeout);\n if (options.signal === undefined) {\n return timeoutSignal;\n }\n return timeoutSignal === undefined\n ? options.signal\n : AbortSignal.any([options.signal, timeoutSignal]);\n}\n\nfunction maxRetries(options: StoragePromotionOptions): number {\n const configured =\n typeof options.retries === 'number'\n ? options.retries\n : options.retries?.max;\n return Math.max(0, Math.floor(configured ?? 0));\n}\n\nasync function waitForRetry(\n milliseconds: number,\n signal: AbortSignal | undefined,\n): Promise<void> {\n if (signal?.aborted === true) {\n throw signal.reason;\n }\n await new Promise<void>((resolve, reject) => {\n const cleanup = (): void => signal?.removeEventListener('abort', abort);\n const timer = setTimeout(\n () => {\n cleanup();\n resolve();\n },\n Math.max(0, milliseconds),\n );\n const abort = (): void => {\n clearTimeout(timer);\n cleanup();\n reject(signal?.reason);\n };\n signal?.addEventListener('abort', abort, { once: true });\n });\n}\n\n/**\n * Adds the S3-only capabilities to an adapter already built by `s3(...)`: an\n * ETag/version-conditional server-side promotion, and the signed upload and\n * download policies the bridge advertises through `capabilities`.\n *\n * Exported so the provider factory can apply them to the adapter `loadFiles`\n * resolved for the `s3` slug instead of re-deriving {@link S3AdapterOptions}\n * from flat provider config. It expects an adapter whose `raw` is an `S3Client`\n * — pass one built by `s3(...)`, not an S3-compatible wrapper.\n */\nexport function withS3Capabilities(\n base: S3Adapter,\n options: Pick<S3AdapterOptions, 'publicBaseUrl'> = {},\n): S3StorageAdapter {\n return Object.assign(base, {\n conditionalCopy: Object.freeze({\n etag: true,\n supported: true,\n version: true,\n }),\n signedUploadPolicy: Object.freeze({\n contentType: true,\n sizeRange: true,\n }),\n signedDownloadPolicy: Object.freeze({\n expiresIn: options.publicBaseUrl === undefined,\n }),\n async promote(\n sourceKey: string,\n destinationKey: string,\n promotion: StoragePromotionOptions,\n ): Promise<void> {\n const retries = maxRetries(promotion);\n for (let attempt = 0; ; attempt += 1) {\n const signal = operationSignal(promotion);\n try {\n await base.raw.send(\n new CopyObjectCommand({\n Bucket: base.bucket,\n CopySource: copySource(\n base.bucket,\n sourceKey,\n promotion.sourceVersion,\n ),\n ...(promotion.sourceEtag !== undefined && {\n CopySourceIfMatch: promotion.sourceEtag,\n }),\n Key: destinationKey,\n }),\n signal === undefined ? undefined : { abortSignal: signal },\n );\n return;\n } catch (error) {\n const mapped = mapS3Error(error);\n if (\n attempt >= retries ||\n mapped.code !== 'Provider' ||\n mapped.aborted ||\n mapped.permanent ||\n signal?.aborted === true\n ) {\n throw mapped;\n }\n const storageError = mapFilesSdkError(mapped);\n const delay =\n typeof promotion.retries === 'object' &&\n promotion.retries.backoff !== undefined\n ? promotion.retries.backoff({\n attempt: attempt + 1,\n error: storageError,\n })\n : Math.min(1000, 100 * 2 ** attempt);\n await waitForRetry(delay, promotion.signal);\n }\n }\n },\n } satisfies FilesSdkConditionalCopyAdapter &\n FilesSdkSignedDownloadPolicyAdapter &\n FilesSdkSignedUploadPolicyAdapter);\n}\n\n/**\n * Creates the files-sdk S3 driver from the storage package's own dependency\n * context and adds an ETag/version-conditional server-side promotion.\n */\nexport function createS3StorageDriver(\n options: S3StorageDriverOptions,\n): FilesSdkStorageDriver<S3StorageAdapter> {\n const { adapter: adapterOptions, ...filesOptions } = options;\n return createFilesSdkDriver({\n ...filesOptions,\n adapter: withS3Capabilities(s3(adapterOptions), adapterOptions),\n });\n}\n\nexport { mapS3Error, s3 } from 'files-sdk/s3';\nexport type { S3Adapter, S3AdapterOptions, S3Sdk } from 'files-sdk/s3';\n"]}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/files-sdk/s3/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,iBAAiB,EACjB,mBAAmB,EACnB,gBAAgB,GACjB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AACvC,OAAO,EACL,UAAU,EACV,EAAE,GAGH,MAAM,cAAc,CAAC;AAUtB,OAAO,EAAE,YAAY,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AACxE,OAAO,EACL,oBAAoB,EAOpB,gBAAgB,GACjB,MAAM,wBAAwB,CAAC;AAuBhC,SAAS,UAAU,CACjB,MAAc,EACd,GAAW,EACX,OAA2B;IAE3B,MAAM,MAAM,GAAG,GAAG,kBAAkB,CAAC,MAAM,CAAC,IAAI,kBAAkB,CAAC,GAAG,CAAC,EAAE,CAAC;IAC1E,OAAO,OAAO,KAAK,SAAS;QAC1B,CAAC,CAAC,MAAM;QACR,CAAC,CAAC,GAAG,MAAM,cAAc,kBAAkB,CAAC,OAAO,CAAC,EAAE,CAAC;AAC3D,CAAC;AAED,SAAS,eAAe,CACtB,OAAgC;IAEhC,MAAM,aAAa,GACjB,OAAO,CAAC,OAAO,KAAK,SAAS,IAAI,OAAO,CAAC,OAAO,IAAI,CAAC;QACnD,CAAC,CAAC,SAAS;QACX,CAAC,CAAC,WAAW,CAAC,OAAO,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;IAC3C,IAAI,OAAO,CAAC,MAAM,KAAK,SAAS,EAAE,CAAC;QACjC,OAAO,aAAa,CAAC;IACvB,CAAC;IACD,OAAO,aAAa,KAAK,SAAS;QAChC,CAAC,CAAC,OAAO,CAAC,MAAM;QAChB,CAAC,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC,OAAO,CAAC,MAAM,EAAE,aAAa,CAAC,CAAC,CAAC;AACvD,CAAC;AAED,SAAS,UAAU,CAAC,OAAgC;IAClD,MAAM,UAAU,GACd,OAAO,OAAO,CAAC,OAAO,KAAK,QAAQ;QACjC,CAAC,CAAC,OAAO,CAAC,OAAO;QACjB,CAAC,CAAC,OAAO,CAAC,OAAO,EAAE,GAAG,CAAC;IAC3B,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,KAAK,CAAC,UAAU,IAAI,CAAC,CAAC,CAAC,CAAC;AAClD,CAAC;AAED,SAAS,UAAU,CAAC,IAAY;IAC9B,OAAO,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,IAAI,GAAG,CAAC;AACzE,CAAC;AAED,SAAS,SAAS,CAAC,IAAwB;IACzC,OAAO,IAAI,EAAE,OAAO,CAAC,WAAW,EAAE,EAAE,CAAC,CAAC;AACxC,CAAC;AAED,SAAS,aAAa,CACpB,IAAiB,EACjB,QAA4B;IAE5B,IAAI,QAAQ,KAAK,SAAS,EAAE,CAAC;QAC3B,OAAO,QAAQ,CAAC;IAClB,CAAC;IACD,IAAI,OAAO,IAAI,KAAK,QAAQ,EAAE,CAAC;QAC7B,OAAO,2BAA2B,CAAC;IACrC,CAAC;IACD,IAAI,IAAI,YAAY,IAAI,IAAI,IAAI,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACjD,OAAO,IAAI,CAAC,IAAI,CAAC;IACnB,CAAC;IACD,OAAO,0BAA0B,CAAC;AACpC,CAAC;AAED,KAAK,UAAU,wBAAwB,CACrC,IAAiB,EACjB,UAAyD;IAMzD,IAAI,KAA6B,CAAC;IAClC,IAAI,OAAO,IAAI,KAAK,QAAQ,EAAE,CAAC;QAC7B,KAAK,GAAG,IAAI,WAAW,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;IACzC,CAAC;SAAM,IAAI,IAAI,YAAY,UAAU,EAAE,CAAC;QACtC,KAAK,GAAG,IAAI,CAAC;IACf,CAAC;SAAM,IAAI,IAAI,YAAY,WAAW,EAAE,CAAC;QACvC,KAAK,GAAG,IAAI,UAAU,CAAC,IAAI,CAAC,CAAC;IAC/B,CAAC;SAAM,IAAI,WAAW,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC;QACpC,KAAK,GAAG,IAAI,UAAU,CAAC,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,UAAU,EAAE,IAAI,CAAC,UAAU,CAAC,CAAC;IACxE,CAAC;SAAM,IAAI,IAAI,YAAY,IAAI,EAAE,CAAC;QAChC,KAAK,GAAG,IAAI,UAAU,CAAC,MAAM,IAAI,CAAC,WAAW,EAAE,CAAC,CAAC;IACnD,CAAC;IAED,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;QACxB,MAAM,KAAK,GAAG,KAAK,CAAC,UAAU,CAAC;QAC/B,UAAU,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC;QACnC,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,aAAa,EAAE,KAAK,EAAE,IAAI,EAAE,GAAG,EAAE,CAAC,KAAK,EAAE,CAAC;IAClE,CAAC;IAED,MAAM,MAAM,GACV,IAAI,YAAY,QAAQ;QACtB,CAAC,CAAE,QAAQ,CAAC,KAAK,CAAC,IAAI,CAAgC;QACtD,CAAC,CAAC,IAAI,CAAC;IACX,IAAI,CAAC,CAAC,MAAM,YAAY,cAAc,CAAC,EAAE,CAAC;QACxC,MAAM,IAAI,YAAY,CAAC,sCAAsC,EAAE;YAC7D,IAAI,EAAE,gBAAgB,CAAC,gBAAgB;YACvC,SAAS,EAAE,QAAQ;YACnB,SAAS,EAAE,IAAI;SAChB,CAAC,CAAC;IACL,CAAC;IACD,MAAM,MAAM,GAAG,MAAM,CAAC,SAAS,EAAE,CAAC;IAClC,IAAI,MAAM,GAAG,CAAC,CAAC;IACf,OAAO;QACL,IAAI,EAAE,IAAI,cAAc,CAAa;YACnC,MAAM,CAAC,MAAM;gBACX,OAAO,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;YAC/B,CAAC;YACD,KAAK,CAAC,IAAI,CAAC,UAAU;gBACnB,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,IAAI,EAAE,CAAC;gBACnC,IAAI,MAAM,CAAC,IAAI,EAAE,CAAC;oBAChB,UAAU,CAAC,KAAK,EAAE,CAAC;oBACnB,OAAO;gBACT,CAAC;gBACD,MAAM,IAAI,MAAM,CAAC,KAAK,CAAC,UAAU,CAAC;gBAClC,UAAU,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;gBACjC,UAAU,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC;YAC3B,CAAC;SACF,CAAC;QACF,IAAI,EAAE,GAAG,EAAE,CAAC,MAAM;KACnB,CAAC;AACJ,CAAC;AAED,KAAK,UAAU,WAAW,CACxB,OAAgC,EAChC,SAA+D;IAE/D,MAAM,OAAO,GAAG,UAAU,CAAC,OAAO,CAAC,CAAC;IACpC,KAAK,IAAI,OAAO,GAAG,CAAC,GAAI,OAAO,IAAI,CAAC,EAAE,CAAC;QACrC,MAAM,MAAM,GAAG,eAAe,CAAC,OAAO,CAAC,CAAC;QACxC,IAAI,CAAC;YACH,OAAO,MAAM,SAAS,CAAC,MAAM,CAAC,CAAC;QACjC,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,MAAM,MAAM,GAAG,UAAU,CAAC,KAAK,CAAC,CAAC;YACjC,IACE,OAAO,IAAI,OAAO;gBAClB,MAAM,CAAC,IAAI,KAAK,UAAU;gBAC1B,MAAM,CAAC,OAAO;gBACd,MAAM,CAAC,SAAS;gBAChB,MAAM,EAAE,OAAO,KAAK,IAAI,EACxB,CAAC;gBACD,MAAM,MAAM,CAAC;YACf,CAAC;YACD,MAAM,YAAY,GAAG,gBAAgB,CAAC,MAAM,CAAC,CAAC;YAC9C,MAAM,KAAK,GACT,OAAO,OAAO,CAAC,OAAO,KAAK,QAAQ;gBACnC,OAAO,CAAC,OAAO,CAAC,OAAO,KAAK,SAAS;gBACnC,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,OAAO,CAAC;oBACtB,OAAO,EAAE,OAAO,GAAG,CAAC;oBACpB,KAAK,EAAE,YAAY;iBACpB,CAAC;gBACJ,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,GAAG,GAAG,CAAC,IAAI,OAAO,CAAC,CAAC;YACzC,MAAM,YAAY,CAAC,KAAK,EAAE,OAAO,CAAC,MAAM,CAAC,CAAC;QAC5C,CAAC;IACH,CAAC;AACH,CAAC;AAED,KAAK,UAAU,YAAY,CACzB,YAAoB,EACpB,MAA+B;IAE/B,IAAI,MAAM,EAAE,OAAO,KAAK,IAAI,EAAE,CAAC;QAC7B,MAAM,MAAM,CAAC,MAAM,CAAC;IACtB,CAAC;IACD,MAAM,IAAI,OAAO,CAAO,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;QAC1C,MAAM,OAAO,GAAG,GAAS,EAAE,CAAC,MAAM,EAAE,mBAAmB,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC;QACxE,MAAM,KAAK,GAAG,UAAU,CACtB,GAAG,EAAE;YACH,OAAO,EAAE,CAAC;YACV,OAAO,EAAE,CAAC;QACZ,CAAC,EACD,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,YAAY,CAAC,CAC1B,CAAC;QACF,MAAM,KAAK,GAAG,GAAS,EAAE;YACvB,YAAY,CAAC,KAAK,CAAC,CAAC;YACpB,OAAO,EAAE,CAAC;YACV,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;QACzB,CAAC,CAAC;QACF,MAAM,EAAE,gBAAgB,CAAC,OAAO,EAAE,KAAK,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;IAC3D,CAAC,CAAC,CAAC;AACL,CAAC;AAED;;;;;;;;;GASG;AACH,MAAM,UAAU,kBAAkB,CAChC,IAAe,EACf,OAAO,GAEH,EAAE;IAEN,MAAM,2BAA2B,GAC/B,OAAO,CAAC,mBAAmB,IAAI,OAAO,CAAC,QAAQ,KAAK,SAAS,CAAC;IAChE,MAAM,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE;QACjC,eAAe,EAAE,MAAM,CAAC,MAAM,CAAC;YAC7B,IAAI,EAAE,IAAI;YACV,SAAS,EAAE,IAAI;YACf,OAAO,EAAE,IAAI;SACd,CAAC;QACF,kBAAkB,EAAE,MAAM,CAAC,MAAM,CAAC;YAChC,WAAW,EAAE,IAAI;YACjB,SAAS,EAAE,IAAI;SAChB,CAAC;QACF,oBAAoB,EAAE,MAAM,CAAC,MAAM,CAAC;YAClC,SAAS,EAAE,OAAO,CAAC,aAAa,KAAK,SAAS;SAC/C,CAAC;QACF,KAAK,CAAC,OAAO,CACX,SAAiB,EACjB,cAAsB,EACtB,SAAkC;YAElC,MAAM,WAAW,CAAC,SAAS,EAAE,KAAK,EAAE,MAAM,EAAE,EAAE;gBAC5C,MAAM,IAAI,CAAC,GAAG,CAAC,IAAI,CACjB,IAAI,iBAAiB,CAAC;oBACpB,MAAM,EAAE,IAAI,CAAC,MAAM;oBACnB,UAAU,EAAE,UAAU,CACpB,IAAI,CAAC,MAAM,EACX,SAAS,EACT,SAAS,CAAC,aAAa,CACxB;oBACD,GAAG,CAAC,SAAS,CAAC,UAAU,KAAK,SAAS,IAAI;wBACxC,iBAAiB,EAAE,SAAS,CAAC,UAAU;qBACxC,CAAC;oBACF,GAAG,EAAE,cAAc;iBACpB,CAAC,EACF,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,WAAW,EAAE,MAAM,EAAE,CAC3D,CAAC;YACJ,CAAC,CAAC,CAAC;QACL,CAAC;KAGgC,CAAC,CAAC;IACrC,IAAI,CAAC,2BAA2B,EAAE,CAAC;QACjC,OAAO,MAAM,CAAC;IAChB,CAAC;IACD,OAAO,MAAM,CAAC,MAAM,CAAC,MAAM,EAAE;QAC3B,mBAAmB,EAAE,MAAM,CAAC,MAAM,CAAC;YACjC,MAAM,EAAE,IAAI;YACZ,MAAM,EAAE,IAAI;YACZ,IAAI,EAAE,IAAI;YACV,OAAO,EAAE,IAAI;SACd,CAAC;QACF,KAAK,CAAC,iBAAiB,CACrB,GAAW,EACX,OAAwC;YAExC,MAAM,WAAW,CAAC,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,EAAE;gBAC1C,MAAM,IAAI,CAAC,GAAG,CAAC,IAAI,CACjB,IAAI,mBAAmB,CAAC;oBACtB,MAAM,EAAE,IAAI,CAAC,MAAM;oBACnB,OAAO,EAAE,UAAU,CAAC,OAAO,CAAC,SAAS,CAAC,IAAI,CAAC;oBAC3C,GAAG,EAAE,GAAG;iBACT,CAAC,EACF,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,WAAW,EAAE,MAAM,EAAE,CAC3D,CAAC;YACJ,CAAC,CAAC,CAAC;QACL,CAAC;QACD,KAAK,CAAC,iBAAiB,CACrB,GAAW,EACX,IAAiB,EACjB,WAA4C;YAE5C,IACE,WAAW,CAAC,SAAS,KAAK,SAAS;gBACnC,WAAW,CAAC,SAAS,KAAK,KAAK,EAC/B,CAAC;gBACD,MAAM,IAAI,YAAY,CACpB,uDAAuD,EACvD;oBACE,IAAI,EAAE,gBAAgB,CAAC,aAAa;oBACpC,GAAG;oBACH,SAAS,EAAE,QAAQ;oBACnB,SAAS,EAAE,IAAI;iBAChB,CACF,CAAC;YACJ,CAAC;YACD,IAAI,WAAW,CAAC,OAAO,KAAK,SAAS,EAAE,CAAC;gBACtC,MAAM,IAAI,YAAY,CACpB,0DAA0D,EAC1D;oBACE,IAAI,EAAE,gBAAgB,CAAC,aAAa;oBACpC,GAAG;oBACH,SAAS,EAAE,QAAQ;oBACnB,SAAS,EAAE,IAAI;iBAChB,CACF,CAAC;YACJ,CAAC;YAED,MAAM,UAAU,GAAG,MAAM,wBAAwB,CAC/C,IAAI,EACJ,WAAW,CAAC,UAAU,CACvB,CAAC;YACF,MAAM,WAAW,GAAG,aAAa,CAAC,IAAI,EAAE,WAAW,CAAC,WAAW,CAAC,CAAC;YACjE,MAAM,YAAY,GAChB,UAAU,CAAC,aAAa,KAAK,SAAS;gBACpC,CAAC,CAAC,EAAE,GAAG,WAAW,EAAE,OAAO,EAAE,CAAC,EAAE;gBAChC,CAAC,CAAC,WAAW,CAAC;YAClB,MAAM,MAAM,GAAG,MAAM,WAAW,CAAC,YAAY,EAAE,CAAC,MAAM,EAAE,EAAE,CACxD,IAAI,CAAC,GAAG,CAAC,IAAI,CACX,IAAI,gBAAgB,CAAC;gBACnB,IAAI,EAAE,UAAU,CAAC,IAAI;gBACrB,MAAM,EAAE,IAAI,CAAC,MAAM;gBACnB,GAAG,CAAC,WAAW,CAAC,YAAY,KAAK,SAAS,IAAI;oBAC5C,YAAY,EAAE,WAAW,CAAC,YAAY;iBACvC,CAAC;gBACF,GAAG,CAAC,UAAU,CAAC,aAAa,KAAK,SAAS,IAAI;oBAC5C,aAAa,EAAE,UAAU,CAAC,aAAa;iBACxC,CAAC;gBACF,WAAW,EAAE,WAAW;gBACxB,GAAG,CAAC,WAAW,CAAC,SAAS,CAAC,IAAI,KAAK,QAAQ;oBACzC,CAAC,CAAC,EAAE,WAAW,EAAE,GAAG,EAAE;oBACtB,CAAC,CAAC,EAAE,OAAO,EAAE,UAAU,CAAC,WAAW,CAAC,SAAS,CAAC,IAAI,CAAC,EAAE,CAAC;gBACxD,GAAG,EAAE,GAAG;gBACR,GAAG,CAAC,WAAW,CAAC,QAAQ,KAAK,SAAS,IAAI;oBACxC,QAAQ,EAAE,WAAW,CAAC,QAAQ;iBAC/B,CAAC;aACH,CAAC,EACF,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,WAAW,EAAE,MAAM,EAAE,CAC3D,CACF,CAAC;YACF,MAAM,IAAI,GAAG,UAAU,CAAC,IAAI,EAAE,CAAC;YAC/B,WAAW,CAAC,UAAU,EAAE,CAAC;gBACvB,MAAM,EAAE,IAAI;gBACZ,GAAG,CAAC,UAAU,CAAC,aAAa,KAAK,SAAS,IAAI;oBAC5C,KAAK,EAAE,UAAU,CAAC,aAAa;iBAChC,CAAC;aACH,CAAC,CAAC;YACH,MAAM,IAAI,GAAG,SAAS,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;YACpC,IAAI,IAAI,KAAK,SAAS,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;gBAC5C,MAAM,IAAI,YAAY,CACpB,0IAA0I,EAC1I;oBACE,IAAI,EAAE,gBAAgB,CAAC,QAAQ;oBAC/B,GAAG;oBACH,SAAS,EAAE,QAAQ;oBACnB,SAAS,EAAE,IAAI;iBAChB,CACF,CAAC;YACJ,CAAC;YACD,OAAO;gBACL,WAAW;gBACX,IAAI;gBACJ,GAAG;gBACH,IAAI;aACL,CAAC;QACJ,CAAC;KAC2C,CAAC,CAAC;AAClD,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,qBAAqB,CACnC,OAA+B;IAE/B,MAAM,EAAE,OAAO,EAAE,cAAc,EAAE,GAAG,YAAY,EAAE,GAAG,OAAO,CAAC;IAC7D,MAAM,EAAE,mBAAmB,EAAE,GAAG,iBAAiB,EAAE,GAAG,YAAY,CAAC;IACnE,OAAO,oBAAoB,CAAC;QAC1B,GAAG,iBAAiB;QACpB,OAAO,EAAE,kBAAkB,CAAC,EAAE,CAAC,cAAc,CAAC,EAAE;YAC9C,GAAG,cAAc;YACjB,GAAG,CAAC,mBAAmB,KAAK,SAAS,IAAI,EAAE,mBAAmB,EAAE,CAAC;SAClE,CAAC;KACH,CAAC,CAAC;AACL,CAAC;AAED,OAAO,EAAE,UAAU,EAAE,EAAE,EAAE,MAAM,cAAc,CAAC","sourcesContent":["import {\n CopyObjectCommand,\n DeleteObjectCommand,\n PutObjectCommand,\n} from '@aws-sdk/client-s3';\nimport { Readable } from 'node:stream';\nimport {\n mapS3Error,\n s3,\n type S3Adapter,\n type S3AdapterOptions,\n} from 'files-sdk/s3';\n\nimport type {\n StorageBody,\n StorageConditionalDeleteOptions,\n StorageConditionalUploadOptions,\n StorageOperationOptions,\n StoragePromotionOptions,\n StorageUploadResult,\n} from '../../storage.types.js';\nimport { StorageError, StorageErrorCode } from '../../storage.error.js';\nimport {\n createFilesSdkDriver,\n type FilesSdkConditionalCopyAdapter,\n type FilesSdkConditionalMutationAdapter,\n type FilesSdkDriverOptions,\n type FilesSdkSignedUploadPolicyAdapter,\n type FilesSdkSignedDownloadPolicyAdapter,\n type FilesSdkStorageDriver,\n mapFilesSdkError,\n} from '../files-sdk.driver.js';\n\nexport interface S3StorageDriverOptions extends Omit<\n FilesSdkDriverOptions<S3Adapter>,\n 'adapter'\n> {\n adapter: S3AdapterOptions;\n /**\n * Opt in or out of conditional writes for an S3-compatible endpoint whose\n * support is known. Native AWS S3 enables them by default; custom endpoints\n * default to false because compatibility varies.\n */\n conditionalMutation?: boolean;\n}\n\ntype S3StorageAdapterBase = S3Adapter &\n FilesSdkConditionalCopyAdapter &\n FilesSdkSignedDownloadPolicyAdapter &\n FilesSdkSignedUploadPolicyAdapter;\n\nexport type S3StorageAdapter = S3StorageAdapterBase &\n Partial<FilesSdkConditionalMutationAdapter>;\n\nfunction copySource(\n bucket: string,\n key: string,\n version: string | undefined,\n): string {\n const source = `${encodeURIComponent(bucket)}/${encodeURIComponent(key)}`;\n return version === undefined\n ? source\n : `${source}?versionId=${encodeURIComponent(version)}`;\n}\n\nfunction operationSignal(\n options: StorageOperationOptions,\n): AbortSignal | undefined {\n const timeoutSignal =\n options.timeout === undefined || options.timeout <= 0\n ? undefined\n : AbortSignal.timeout(options.timeout);\n if (options.signal === undefined) {\n return timeoutSignal;\n }\n return timeoutSignal === undefined\n ? options.signal\n : AbortSignal.any([options.signal, timeoutSignal]);\n}\n\nfunction maxRetries(options: StorageOperationOptions): number {\n const configured =\n typeof options.retries === 'number'\n ? options.retries\n : options.retries?.max;\n return Math.max(0, Math.floor(configured ?? 0));\n}\n\nfunction etagHeader(etag: string): string {\n return etag.startsWith('\"') && etag.endsWith('\"') ? etag : `\"${etag}\"`;\n}\n\nfunction stripEtag(etag: string | undefined): string | undefined {\n return etag?.replace(/^\"+|\"+$/gu, '');\n}\n\nfunction contentTypeOf(\n body: StorageBody,\n override: string | undefined,\n): string {\n if (override !== undefined) {\n return override;\n }\n if (typeof body === 'string') {\n return 'text/plain; charset=utf-8';\n }\n if (body instanceof Blob && body.type.length > 0) {\n return body.type;\n }\n return 'application/octet-stream';\n}\n\nasync function normalizeConditionalBody(\n body: StorageBody,\n onProgress: StorageConditionalUploadOptions['onProgress'],\n): Promise<{\n body: Uint8Array | ReadableStream<Uint8Array>;\n size: () => number;\n contentLength?: number;\n}> {\n let bytes: Uint8Array | undefined;\n if (typeof body === 'string') {\n bytes = new TextEncoder().encode(body);\n } else if (body instanceof Uint8Array) {\n bytes = body;\n } else if (body instanceof ArrayBuffer) {\n bytes = new Uint8Array(body);\n } else if (ArrayBuffer.isView(body)) {\n bytes = new Uint8Array(body.buffer, body.byteOffset, body.byteLength);\n } else if (body instanceof Blob) {\n bytes = new Uint8Array(await body.arrayBuffer());\n }\n\n if (bytes !== undefined) {\n const total = bytes.byteLength;\n onProgress?.({ loaded: 0, total });\n return { body: bytes, contentLength: total, size: () => total };\n }\n\n const stream =\n body instanceof Readable\n ? (Readable.toWeb(body) as ReadableStream<Uint8Array>)\n : body;\n if (!(stream instanceof ReadableStream)) {\n throw new StorageError('Unsupported conditional upload body.', {\n code: StorageErrorCode.INVALID_ARGUMENT,\n operation: 'upload',\n permanent: true,\n });\n }\n const reader = stream.getReader();\n let loaded = 0;\n return {\n body: new ReadableStream<Uint8Array>({\n cancel(reason) {\n return reader.cancel(reason);\n },\n async pull(controller) {\n const result = await reader.read();\n if (result.done) {\n controller.close();\n return;\n }\n loaded += result.value.byteLength;\n controller.enqueue(result.value);\n onProgress?.({ loaded });\n },\n }),\n size: () => loaded,\n };\n}\n\nasync function withS3Retry<Result>(\n options: StorageOperationOptions,\n operation: (signal: AbortSignal | undefined) => Promise<Result>,\n): Promise<Result> {\n const retries = maxRetries(options);\n for (let attempt = 0; ; attempt += 1) {\n const signal = operationSignal(options);\n try {\n return await operation(signal);\n } catch (error) {\n const mapped = mapS3Error(error);\n if (\n attempt >= retries ||\n mapped.code !== 'Provider' ||\n mapped.aborted ||\n mapped.permanent ||\n signal?.aborted === true\n ) {\n throw mapped;\n }\n const storageError = mapFilesSdkError(mapped);\n const delay =\n typeof options.retries === 'object' &&\n options.retries.backoff !== undefined\n ? options.retries.backoff({\n attempt: attempt + 1,\n error: storageError,\n })\n : Math.min(1000, 100 * 2 ** attempt);\n await waitForRetry(delay, options.signal);\n }\n }\n}\n\nasync function waitForRetry(\n milliseconds: number,\n signal: AbortSignal | undefined,\n): Promise<void> {\n if (signal?.aborted === true) {\n throw signal.reason;\n }\n await new Promise<void>((resolve, reject) => {\n const cleanup = (): void => signal?.removeEventListener('abort', abort);\n const timer = setTimeout(\n () => {\n cleanup();\n resolve();\n },\n Math.max(0, milliseconds),\n );\n const abort = (): void => {\n clearTimeout(timer);\n cleanup();\n reject(signal?.reason);\n };\n signal?.addEventListener('abort', abort, { once: true });\n });\n}\n\n/**\n * Adds the S3-only capabilities to an adapter already built by `s3(...)`: an\n * ETag/version-conditional server-side promotion, and the signed upload and\n * download policies the bridge advertises through `capabilities`.\n *\n * Exported so the provider factory can apply them to the adapter `loadFiles`\n * resolved for the `s3` slug instead of re-deriving {@link S3AdapterOptions}\n * from flat provider config. It expects an adapter whose `raw` is an `S3Client`\n * — pass one built by `s3(...)`, not an S3-compatible wrapper.\n */\nexport function withS3Capabilities(\n base: S3Adapter,\n options: Pick<S3AdapterOptions, 'endpoint' | 'publicBaseUrl'> & {\n conditionalMutation?: boolean;\n } = {},\n): S3StorageAdapter {\n const supportsConditionalMutation =\n options.conditionalMutation ?? options.endpoint === undefined;\n const common = Object.assign(base, {\n conditionalCopy: Object.freeze({\n etag: true,\n supported: true,\n version: true,\n }),\n signedUploadPolicy: Object.freeze({\n contentType: true,\n sizeRange: true,\n }),\n signedDownloadPolicy: Object.freeze({\n expiresIn: options.publicBaseUrl === undefined,\n }),\n async promote(\n sourceKey: string,\n destinationKey: string,\n promotion: StoragePromotionOptions,\n ): Promise<void> {\n await withS3Retry(promotion, async (signal) => {\n await base.raw.send(\n new CopyObjectCommand({\n Bucket: base.bucket,\n CopySource: copySource(\n base.bucket,\n sourceKey,\n promotion.sourceVersion,\n ),\n ...(promotion.sourceEtag !== undefined && {\n CopySourceIfMatch: promotion.sourceEtag,\n }),\n Key: destinationKey,\n }),\n signal === undefined ? undefined : { abortSignal: signal },\n );\n });\n },\n } satisfies FilesSdkConditionalCopyAdapter &\n FilesSdkSignedDownloadPolicyAdapter &\n FilesSdkSignedUploadPolicyAdapter);\n if (!supportsConditionalMutation) {\n return common;\n }\n return Object.assign(common, {\n conditionalMutation: Object.freeze({\n create: true,\n delete: true,\n etag: true,\n replace: true,\n }),\n async deleteConditional(\n key: string,\n options: StorageConditionalDeleteOptions,\n ): Promise<void> {\n await withS3Retry(options, async (signal) => {\n await base.raw.send(\n new DeleteObjectCommand({\n Bucket: base.bucket,\n IfMatch: etagHeader(options.condition.etag),\n Key: key,\n }),\n signal === undefined ? undefined : { abortSignal: signal },\n );\n });\n },\n async uploadConditional(\n key: string,\n body: StorageBody,\n conditional: StorageConditionalUploadOptions,\n ): Promise<StorageUploadResult> {\n if (\n conditional.multipart !== undefined &&\n conditional.multipart !== false\n ) {\n throw new StorageError(\n 'Conditional S3 uploads do not support multipart mode.',\n {\n code: StorageErrorCode.NOT_SUPPORTED,\n key,\n operation: 'upload',\n permanent: true,\n },\n );\n }\n if (conditional.control !== undefined) {\n throw new StorageError(\n 'Conditional S3 uploads do not support resumable control.',\n {\n code: StorageErrorCode.NOT_SUPPORTED,\n key,\n operation: 'upload',\n permanent: true,\n },\n );\n }\n\n const normalized = await normalizeConditionalBody(\n body,\n conditional.onProgress,\n );\n const contentType = contentTypeOf(body, conditional.contentType);\n const retryOptions: StorageOperationOptions =\n normalized.contentLength === undefined\n ? { ...conditional, retries: 0 }\n : conditional;\n const result = await withS3Retry(retryOptions, (signal) =>\n base.raw.send(\n new PutObjectCommand({\n Body: normalized.body,\n Bucket: base.bucket,\n ...(conditional.cacheControl !== undefined && {\n CacheControl: conditional.cacheControl,\n }),\n ...(normalized.contentLength !== undefined && {\n ContentLength: normalized.contentLength,\n }),\n ContentType: contentType,\n ...(conditional.condition.type === 'create'\n ? { IfNoneMatch: '*' }\n : { IfMatch: etagHeader(conditional.condition.etag) }),\n Key: key,\n ...(conditional.metadata !== undefined && {\n Metadata: conditional.metadata,\n }),\n }),\n signal === undefined ? undefined : { abortSignal: signal },\n ),\n );\n const size = normalized.size();\n conditional.onProgress?.({\n loaded: size,\n ...(normalized.contentLength !== undefined && {\n total: normalized.contentLength,\n }),\n });\n const etag = stripEtag(result.ETag);\n if (etag === undefined || etag.length === 0) {\n throw new StorageError(\n 'S3 committed a conditional upload without returning the ETag required to identify its result; reconcile the destination before retrying.',\n {\n code: StorageErrorCode.PROVIDER,\n key,\n operation: 'upload',\n permanent: true,\n },\n );\n }\n return {\n contentType,\n etag,\n key,\n size,\n };\n },\n } satisfies FilesSdkConditionalMutationAdapter);\n}\n\n/**\n * Creates the files-sdk S3 driver from the storage package's own dependency\n * context and adds an ETag/version-conditional server-side promotion.\n */\nexport function createS3StorageDriver(\n options: S3StorageDriverOptions,\n): FilesSdkStorageDriver<S3StorageAdapter> {\n const { adapter: adapterOptions, ...filesOptions } = options;\n const { conditionalMutation, ...plainFilesOptions } = filesOptions;\n return createFilesSdkDriver({\n ...plainFilesOptions,\n adapter: withS3Capabilities(s3(adapterOptions), {\n ...adapterOptions,\n ...(conditionalMutation !== undefined && { conditionalMutation }),\n }),\n });\n}\n\nexport { mapS3Error, s3 } from 'files-sdk/s3';\nexport type { S3Adapter, S3AdapterOptions, S3Sdk } from 'files-sdk/s3';\n"]}