@warlock.js/core 5.2.2 → 5.2.4

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 (238) hide show
  1. package/CHANGELOG.md +13 -0
  2. package/esm/application/application.d.mts.map +1 -1
  3. package/esm/application/application.mjs.map +1 -1
  4. package/esm/benchmark/benchmark-snapshots.d.mts.map +1 -1
  5. package/esm/benchmark/benchmark.d.mts.map +1 -1
  6. package/esm/benchmark/channels/console.channel.mjs.map +1 -1
  7. package/esm/benchmark/channels/noop.channel.d.mts.map +1 -1
  8. package/esm/benchmark/profiler.d.mts.map +1 -1
  9. package/esm/benchmark/profiler.mjs.map +1 -1
  10. package/esm/bootstrap/setup.d.mts.map +1 -1
  11. package/esm/bootstrap/setup.mjs.map +1 -1
  12. package/esm/bootstrap.d.mts.map +1 -1
  13. package/esm/cache/database-cache-driver.d.mts.map +1 -1
  14. package/esm/cache/database-cache-driver.mjs.map +1 -1
  15. package/esm/cli/cli-commands.manager.mjs.map +1 -1
  16. package/esm/cli/cli-commands.utils.mjs.map +1 -1
  17. package/esm/cli/commands/doctor/boot-for-diagnostics.mjs.map +1 -1
  18. package/esm/cli/commands/doctor/checks/connectors.check.mjs.map +1 -1
  19. package/esm/cli/commands/doctor/checks/handler-signature.check.mjs.map +1 -1
  20. package/esm/cli/commands/doctor/checks/health.check.mjs.map +1 -1
  21. package/esm/cli/commands/doctor/checks/optional-peers.check.mjs.map +1 -1
  22. package/esm/cli/commands/doctor/checks/routes.check.mjs.map +1 -1
  23. package/esm/cli/commands/generate/generate.command.mjs.map +1 -1
  24. package/esm/cli/commands/generate/generators/column-dsl-parser.mjs.map +1 -1
  25. package/esm/cli/commands/generate/generators/migration.generator.mjs.map +1 -1
  26. package/esm/cli/commands/generate/generators/model.generator.mjs.map +1 -1
  27. package/esm/cli/commands/generate/templates/stubs.mjs.map +1 -1
  28. package/esm/cli/commands/generate/utils/name-parser.mjs.map +1 -1
  29. package/esm/cli/commands/generate/utils/prompt.mjs.map +1 -1
  30. package/esm/cli/commands/routes/diff-page-routes.mjs.map +1 -1
  31. package/esm/cli/commands/routes/format-routes-table.mjs.map +1 -1
  32. package/esm/cli/commands/routes/route-row.mjs.map +1 -1
  33. package/esm/cli/commands/routes/routes-command.action.mjs.map +1 -1
  34. package/esm/cli/commands/routes/routes-diff.action.mjs.map +1 -1
  35. package/esm/cli/commands/storage-put.action.mjs.map +1 -1
  36. package/esm/cli/commands/typings-generator.command.mjs.map +1 -1
  37. package/esm/cli/commands-loader.mjs.map +1 -1
  38. package/esm/cli/start.mjs.map +1 -1
  39. package/esm/cli/string-similarity.mjs.map +1 -1
  40. package/esm/commands/cli-command.mjs.map +1 -1
  41. package/esm/config/config-loader.mjs.map +1 -1
  42. package/esm/config/config-setter.d.mts.map +1 -1
  43. package/esm/config/load-config-files.mjs.map +1 -1
  44. package/esm/connectors/access-connector.d.mts.map +1 -1
  45. package/esm/connectors/ai-connector.d.mts.map +1 -1
  46. package/esm/connectors/assert-no-reserved-connector-names.mjs.map +1 -1
  47. package/esm/connectors/assert-unique-connector-names.mjs.map +1 -1
  48. package/esm/connectors/base-connector.d.mts.map +1 -1
  49. package/esm/connectors/base-connector.mjs.map +1 -1
  50. package/esm/connectors/cache-connector.d.mts.map +1 -1
  51. package/esm/connectors/connectors-manager.d.mts.map +1 -1
  52. package/esm/connectors/connectors-manager.mjs.map +1 -1
  53. package/esm/connectors/database-connector.d.mts.map +1 -1
  54. package/esm/connectors/describe-server-address.mjs.map +1 -1
  55. package/esm/connectors/herald-connector.d.mts.map +1 -1
  56. package/esm/connectors/http-connector.d.mts.map +1 -1
  57. package/esm/connectors/http-connector.mjs.map +1 -1
  58. package/esm/connectors/logger-connector.d.mts.map +1 -1
  59. package/esm/connectors/mail-connector.d.mts.map +1 -1
  60. package/esm/connectors/notifications-connector.d.mts.map +1 -1
  61. package/esm/connectors/register-configured-connectors.mjs.map +1 -1
  62. package/esm/connectors/socket-connector.d.mts.map +1 -1
  63. package/esm/connectors/socket-connector.mjs.map +1 -1
  64. package/esm/connectors/storage.connector.d.mts.map +1 -1
  65. package/esm/container/index.d.mts.map +1 -1
  66. package/esm/database/create-database-action.mjs.map +1 -1
  67. package/esm/database/drop-tables-action.mjs.map +1 -1
  68. package/esm/database/migrate-action.mjs.map +1 -1
  69. package/esm/database/seed-command-action.mjs.map +1 -1
  70. package/esm/database/seeds/seed-records-table-migration.mjs.map +1 -1
  71. package/esm/database/seeds/seeders.manager.mjs.map +1 -1
  72. package/esm/database/seeds/seeds-table-migration.mjs.map +1 -1
  73. package/esm/dev-server/check-for-updates.mjs.map +1 -1
  74. package/esm/dev-server/dependency-graph.d.mts.map +1 -1
  75. package/esm/dev-server/dependency-graph.mjs.map +1 -1
  76. package/esm/dev-server/dev-logger.mjs.map +1 -1
  77. package/esm/dev-server/development-server.mjs.map +1 -1
  78. package/esm/dev-server/file-event-handler.mjs.map +1 -1
  79. package/esm/dev-server/file-manager.d.mts.map +1 -1
  80. package/esm/dev-server/file-manager.mjs.map +1 -1
  81. package/esm/dev-server/file-operations.d.mts.map +1 -1
  82. package/esm/dev-server/files-orchestrator.mjs.map +1 -1
  83. package/esm/dev-server/files-watcher.mjs.map +1 -1
  84. package/esm/dev-server/health-checker/checkers/eslint-health-checker.mjs.map +1 -1
  85. package/esm/dev-server/health-checker/checkers/typescript-health-checker.mjs.map +1 -1
  86. package/esm/dev-server/health-checker/file-health-result.d.mts.map +1 -1
  87. package/esm/dev-server/health-checker/file-health-result.mjs.map +1 -1
  88. package/esm/dev-server/health-checker/files-healthcare.manager.mjs.map +1 -1
  89. package/esm/dev-server/layer-executor.mjs.map +1 -1
  90. package/esm/dev-server/loader/hook-thread.d.mts.map +1 -1
  91. package/esm/dev-server/loader/own-resolver.mjs.map +1 -1
  92. package/esm/dev-server/loader/register-loader.mjs.map +1 -1
  93. package/esm/dev-server/loader/resolve-hook.mjs.map +1 -1
  94. package/esm/dev-server/loader/source-slug.mjs.map +1 -1
  95. package/esm/dev-server/loader/transpile-cache.mjs.map +1 -1
  96. package/esm/dev-server/loader/version-registry.mjs.map +1 -1
  97. package/esm/dev-server/manifest-manager.d.mts.map +1 -1
  98. package/esm/dev-server/manifest-manager.mjs.map +1 -1
  99. package/esm/dev-server/module-loader.mjs.map +1 -1
  100. package/esm/dev-server/package-json-manager.mjs.map +1 -1
  101. package/esm/dev-server/parse-imports.mjs.map +1 -1
  102. package/esm/dev-server/ready-block.mjs.map +1 -1
  103. package/esm/dev-server/special-files-collector.d.mts.map +1 -1
  104. package/esm/dev-server/special-files-collector.mjs.map +1 -1
  105. package/esm/dev-server/tsconfig-manager.mjs.map +1 -1
  106. package/esm/dev-server/type-generator.mjs.map +1 -1
  107. package/esm/dev-server/utils.mjs.map +1 -1
  108. package/esm/encryption/encrypt.mjs.map +1 -1
  109. package/esm/encryption/hash.mjs.map +1 -1
  110. package/esm/generations/add-command.action.mjs +28 -11
  111. package/esm/generations/add-command.action.mjs.map +1 -1
  112. package/esm/generations/features/shadcn.feature.mjs.map +1 -1
  113. package/esm/generations/features/shared/migration-timestamp.mjs.map +1 -1
  114. package/esm/generations/features/tailwind.feature.mjs.map +1 -1
  115. package/esm/generations/features/web.feature.mjs +8 -7
  116. package/esm/generations/features/web.feature.mjs.map +1 -1
  117. package/esm/generations/stubs.mjs +49 -33
  118. package/esm/generations/stubs.mjs.map +1 -1
  119. package/esm/http/boot-port-preflight.d.mts.map +1 -1
  120. package/esm/http/context/request-context.d.mts.map +1 -1
  121. package/esm/http/context/request-context.mjs.map +1 -1
  122. package/esm/http/context/request-memo.d.mts.map +1 -1
  123. package/esm/http/context/request-memo.mjs.map +1 -1
  124. package/esm/http/createHttpApplication.d.mts.map +1 -1
  125. package/esm/http/createHttpApplication.mjs.map +1 -1
  126. package/esm/http/health.d.mts.map +1 -1
  127. package/esm/http/middleware/cache-response-middleware.mjs.map +1 -1
  128. package/esm/http/middleware/idempotency.middleware.mjs.map +1 -1
  129. package/esm/http/middleware/inject-request-context.mjs.map +1 -1
  130. package/esm/http/middleware/maintenance.middleware.mjs.map +1 -1
  131. package/esm/http/middleware/utils/idempotency-key.mjs.map +1 -1
  132. package/esm/http/ready-report.d.mts.map +1 -1
  133. package/esm/http/request-controller.d.mts.map +1 -1
  134. package/esm/http/request.d.mts.map +1 -1
  135. package/esm/http/request.mjs.map +1 -1
  136. package/esm/http/response.d.mts.map +1 -1
  137. package/esm/http/response.mjs.map +1 -1
  138. package/esm/http/server.d.mts.map +1 -1
  139. package/esm/http/server.mjs.map +1 -1
  140. package/esm/http/uploaded-file.d.mts.map +1 -1
  141. package/esm/http/uploaded-file.mjs.map +1 -1
  142. package/esm/http/uploads-config.d.mts.map +1 -1
  143. package/esm/image/image.d.mts.map +1 -1
  144. package/esm/image/image.mjs.map +1 -1
  145. package/esm/logger/logger.mjs.map +1 -1
  146. package/esm/mail/config.d.mts.map +1 -1
  147. package/esm/mail/events.d.mts.map +1 -1
  148. package/esm/mail/mail.d.mts.map +1 -1
  149. package/esm/mail/mail.mjs.map +1 -1
  150. package/esm/mail/mailer-pool.d.mts.map +1 -1
  151. package/esm/mail/mailer-pool.mjs.map +1 -1
  152. package/esm/mail/send-mail.mjs.map +1 -1
  153. package/esm/mail/test-mailbox.d.mts.map +1 -1
  154. package/esm/mail/test-mailbox.mjs.map +1 -1
  155. package/esm/production/assert-generated-imports.mjs.map +1 -1
  156. package/esm/production/build-app-production.mjs.map +1 -1
  157. package/esm/production/dist-build-manifest.mjs.map +1 -1
  158. package/esm/production/production-builder.mjs.map +1 -1
  159. package/esm/production/production-supervisor.mjs.map +1 -1
  160. package/esm/production/promote-dist.mjs.map +1 -1
  161. package/esm/production/resolve-build-config.mjs.map +1 -1
  162. package/esm/repositories/adapters/cascade/cascade-adapter.d.mts.map +1 -1
  163. package/esm/repositories/adapters/cascade/cascade-adapter.mjs.map +1 -1
  164. package/esm/repositories/adapters/cascade/cascade-query-builder.d.mts.map +1 -1
  165. package/esm/repositories/adapters/cascade/cascade-query-builder.mjs.map +1 -1
  166. package/esm/repositories/adapters/cascade/filter-applicator.mjs.map +1 -1
  167. package/esm/repositories/repository.manager.d.mts.map +1 -1
  168. package/esm/repositories/repository.manager.mjs.map +1 -1
  169. package/esm/resource/register-resource.d.mts.map +1 -1
  170. package/esm/resource/resource-field-builder.d.mts.map +1 -1
  171. package/esm/resource/resource-field-builder.mjs.map +1 -1
  172. package/esm/resource/resource.d.mts.map +1 -1
  173. package/esm/resource/resource.mjs.map +1 -1
  174. package/esm/restful/restful.d.mts.map +1 -1
  175. package/esm/restful/restful.mjs.map +1 -1
  176. package/esm/router/log-request-lifecycle.mjs.map +1 -1
  177. package/esm/router/normalize-route-path.d.mts.map +1 -1
  178. package/esm/router/positional-handler-diagnostics.d.mts.map +1 -1
  179. package/esm/router/positional-handler-diagnostics.mjs.map +1 -1
  180. package/esm/router/route-registry.d.mts.map +1 -1
  181. package/esm/router/route-registry.mjs.map +1 -1
  182. package/esm/router/router.d.mts.map +1 -1
  183. package/esm/router/router.mjs.map +1 -1
  184. package/esm/socket/utils.d.mts.map +1 -1
  185. package/esm/storage/config.d.mts.map +1 -1
  186. package/esm/storage/context/storage-driver-context.d.mts.map +1 -1
  187. package/esm/storage/drivers/cloud-driver.d.mts.map +1 -1
  188. package/esm/storage/drivers/cloud-driver.mjs.map +1 -1
  189. package/esm/storage/drivers/do-spaces-driver.d.mts.map +1 -1
  190. package/esm/storage/drivers/local-driver.d.mts.map +1 -1
  191. package/esm/storage/drivers/local-driver.mjs.map +1 -1
  192. package/esm/storage/drivers/r2-driver.d.mts.map +1 -1
  193. package/esm/storage/scoped-storage.d.mts.map +1 -1
  194. package/esm/storage/scoped-storage.mjs.map +1 -1
  195. package/esm/storage/storage-file.d.mts.map +1 -1
  196. package/esm/storage/storage-file.mjs.map +1 -1
  197. package/esm/storage/storage.d.mts.map +1 -1
  198. package/esm/storage/utils/safe-fetch.mjs.map +1 -1
  199. package/esm/tests/start-http-development-server.d.mts.map +1 -1
  200. package/esm/tests/test-connectors-selection.mjs.map +1 -1
  201. package/esm/tests/test-helpers.d.mts.map +1 -1
  202. package/esm/tests/test-setup-timeout.mjs.map +1 -1
  203. package/esm/tests/vitest-setup.d.mts.map +1 -1
  204. package/esm/tests/vitest-setup.mjs.map +1 -1
  205. package/esm/updater/package-manager.mjs +15 -1
  206. package/esm/updater/package-manager.mjs.map +1 -1
  207. package/esm/updater/update-warlock-packages.mjs.map +1 -1
  208. package/esm/use-cases/use-case-broadcast.d.mts.map +1 -1
  209. package/esm/use-cases/use-case-events.d.mts.map +1 -1
  210. package/esm/use-cases/use-case-pipeline.d.mts.map +1 -1
  211. package/esm/use-cases/use-case.d.mts.map +1 -1
  212. package/esm/use-cases/use-cases-registry.d.mts.map +1 -1
  213. package/esm/use-cases/use-cases-registry.mjs.map +1 -1
  214. package/esm/utils/database-log.d.mts.map +1 -1
  215. package/esm/utils/database-log.mjs.map +1 -1
  216. package/esm/utils/environment.d.mts.map +1 -1
  217. package/esm/utils/framework-vesion.mjs.map +1 -1
  218. package/esm/utils/get-localized.mjs.map +1 -1
  219. package/esm/utils/load-environment.mjs.map +1 -1
  220. package/esm/utils/normalized-path.d.mts.map +1 -1
  221. package/esm/utils/paths.d.mts.map +1 -1
  222. package/esm/utils/promise-all-object.d.mts.map +1 -1
  223. package/esm/utils/promise-all-object.mjs.map +1 -1
  224. package/esm/utils/sluggable.mjs.map +1 -1
  225. package/esm/utils/version-compare.mjs.map +1 -1
  226. package/esm/validation/database/exists-except-current-id.mjs.map +1 -1
  227. package/esm/validation/database/exists-except-current-user.mjs.map +1 -1
  228. package/esm/validation/database/unique-except-current-id.mjs.map +1 -1
  229. package/esm/validation/plugins/localized-plugin.mjs.map +1 -1
  230. package/esm/validation/validators/file-validator.mjs.map +1 -1
  231. package/esm/vite/lower-stage3-decorators.d.mts.map +1 -1
  232. package/esm/warlock-config/warlock-config.manager.d.mts.map +1 -1
  233. package/esm/warlock-config/warlock-config.manager.mjs.map +1 -1
  234. package/llms-full.txt +4 -1
  235. package/llms.txt +1 -1
  236. package/package.json +12 -12
  237. package/skills/README.md +1 -1
  238. package/skills/write-cli-command/SKILL.md +4 -1
@@ -1 +1 @@
1
- {"version":3,"file":"cloud-driver.mjs","names":[],"sources":["../../../../../../../../core/src/storage/drivers/cloud-driver.ts"],"sourcesContent":["import crypto from \"crypto\";\nimport { createRequire } from \"module\";\nimport type { Readable } from \"stream\";\nimport { storageDriverContext } from \"../context/storage-driver-context\";\nimport type {\n CloudStorageDriverContract,\n CloudStorageDriverOptions,\n CloudStorageFileData,\n DeleteManyResult,\n FileVisibility,\n ListOptions,\n PresignedOptions,\n PresignedUploadOptions,\n PutOptions,\n StorageDriverType,\n StorageFileInfo,\n} from \"../types\";\nimport { getMimeType } from \"../utils/mime\";\n\n// ============================================================\n// Lazy-loaded S3 SDK Types\n// ============================================================\n\n/**\n * Cached S3 SDK modules (loaded once, reused)\n */\nlet S3Client: typeof import(\"@aws-sdk/client-s3\");\nlet S3Storage: typeof import(\"@aws-sdk/lib-storage\");\nlet S3Presigner: typeof import(\"@aws-sdk/s3-request-presigner\");\n\nlet isModuleExists: boolean | null = null;\n\n/**\n * Installation instructions for S3 SDK packages\n */\nconst S3_INSTALL_INSTRUCTIONS = `\nCloud storage requires the AWS S3 SDK packages.\nInstall them with:\n\n npm install @aws-sdk/client-s3 @aws-sdk/lib-storage @aws-sdk/s3-request-presigner\n\nOr with your preferred package manager:\n\n pnpm add @aws-sdk/client-s3 @aws-sdk/lib-storage @aws-sdk/s3-request-presigner\n yarn add @aws-sdk/client-s3 @aws-sdk/lib-storage @aws-sdk/s3-request-presigner\n`.trim();\n\n/**\n * Atomic initialization promise to handle concurrent calls to loadS3\n */\nlet initializationPromise: Promise<void> | null = null;\n\n/**\n * Load S3 modules lazily\n *\n * @example\n * await loadS3();\n * if (isModuleExists) {\n * // Safe to use S3Client, S3Storage, S3Presigner\n * }\n */\nexport async function loadS3(): Promise<void> {\n // If already successfully loaded, no need to do anything\n if (isModuleExists === true) return;\n\n // If currently loading, return the existing promise so the caller waits\n if (initializationPromise) return initializationPromise;\n\n initializationPromise = (async () => {\n try {\n // Use Promise.all to load modules in parallel for efficiency\n const [client, storage, presigner] = await Promise.all([\n import(\"@aws-sdk/client-s3\"),\n import(\"@aws-sdk/lib-storage\"),\n import(\"@aws-sdk/s3-request-presigner\"),\n ]);\n\n S3Client = client;\n S3Storage = storage;\n S3Presigner = presigner;\n\n isModuleExists = true;\n } catch {\n // Mark as failed if any import fails (usually means packages aren't installed)\n isModuleExists = false;\n }\n })();\n\n return initializationPromise;\n}\n\nloadS3();\n\n/**\n * Synchronous fallback loader.\n *\n * `loadS3()` above is async and fire-and-forget at module load, so on the\n * very first *synchronous* `CloudDriver` construction the dynamic `import()`\n * microtask has not yet resolved — `isModuleExists` is still `null` even when\n * the SDK is genuinely installed. The constructor's install-check would then\n * throw the misleading \"SDK not installed\" error.\n *\n * This probes the modules synchronously via `require` (the AWS SDK ships\n * CJS-compatible builds) so a present SDK resolves the install-check\n * immediately, without waiting on the async path. Returns `true` when all\n * three modules loaded, `false` otherwise. Only invoked while\n * `isModuleExists` is still indeterminate.\n */\nfunction loadS3Sync(): boolean {\n if (isModuleExists !== null) {\n return isModuleExists;\n }\n\n try {\n // `createRequire` gives an ESM-safe synchronous `require` regardless of\n // whether this module runs as CJS or ESM at runtime.\n const req = createRequire(import.meta.url);\n S3Client = req(\"@aws-sdk/client-s3\");\n S3Storage = req(\"@aws-sdk/lib-storage\");\n S3Presigner = req(\"@aws-sdk/s3-request-presigner\");\n isModuleExists = true;\n } catch {\n isModuleExists = false;\n }\n\n return isModuleExists;\n}\n\n// ============================================================\n// CloudDriver Base Class\n// ============================================================\n\n/**\n * Base abstract class for all S3-compatible cloud storage drivers\n *\n * This class contains all shared logic for S3-compatible storage services\n * including AWS S3, Cloudflare R2, DigitalOcean Spaces, and others.\n *\n * **Important:** S3 SDK packages are lazy-loaded on first use.\n * Users must install them separately:\n * ```\n * npm install @aws-sdk/client-s3 @aws-sdk/lib-storage @aws-sdk/s3-request-presigner\n * ```\n *\n * Subclasses must implement:\n * - `name`: Driver identifier (e.g., \"s3\", \"r2\", \"spaces\")\n * - `url()`: Returns the public URL for a file (provider-specific format)\n */\nexport abstract class CloudDriver<\n TOptions extends Partial<CloudStorageDriverOptions> = CloudStorageDriverOptions,\n> implements CloudStorageDriverContract {\n /**\n * S3-compatible client (lazy-loaded)\n */\n protected client!: InstanceType<typeof import(\"@aws-sdk/client-s3\").S3Client>;\n\n /**\n * Retry configuration\n */\n protected retryConfig: {\n maxRetries: number;\n initialDelayMs: number;\n maxDelayMs: number;\n backoffMultiplier: number;\n };\n\n public constructor(public options: TOptions) {\n // The async loadS3() may not have resolved yet on the first synchronous\n // construction. When the flag is still indeterminate, probe synchronously\n // so a genuinely-installed SDK never triggers the misleading throw below.\n if (isModuleExists === null) {\n loadS3Sync();\n }\n\n if (!isModuleExists) {\n throw new Error(S3_INSTALL_INSTRUCTIONS);\n }\n\n this.client = new S3Client.S3Client({\n region: this.options.region!,\n credentials: {\n accessKeyId: this.options.accessKeyId!,\n secretAccessKey: this.options.secretAccessKey!,\n },\n ...(this.getEndpoint() && { endpoint: this.getEndpoint() }),\n });\n\n // Initialize retry configuration\n this.retryConfig = {\n maxRetries: this.options.retry?.maxRetries ?? 3,\n initialDelayMs: this.options.retry?.initialDelayMs ?? 1000,\n maxDelayMs: this.options.retry?.maxDelayMs ?? 10000,\n backoffMultiplier: this.options.retry?.backoffMultiplier ?? 2,\n };\n }\n\n /**\n * Driver name identifier\n */\n public abstract readonly name: StorageDriverType;\n\n /**\n * Get public URL for file\n * Must be implemented by subclasses with provider-specific format\n */\n public abstract url(location: string): string;\n\n /**\n * Get endpoint URL\n * Can be overridden by subclasses for provider-specific endpoints\n */\n protected getEndpoint(): string | undefined {\n return this.options.endpoint;\n }\n\n // ============================================================\n // Helper Methods\n // ============================================================\n\n /**\n * Apply prefix to location path\n *\n * Priority: context prefix > driver options prefix > no prefix\n * This allows multi-tenant scenarios where context overrides driver config.\n *\n * @param location - Original location path\n * @returns Location with prefix applied if one exists\n */\n public applyPrefix(location: string): string {\n // Check context prefix first (highest priority)\n const contextPrefix = storageDriverContext.getPrefix();\n const prefix = contextPrefix || this.options.prefix;\n\n if (!prefix) {\n return location;\n }\n\n const cleanPrefix = prefix.replace(/\\/+$/, \"\");\n const cleanLocation = location.replace(/^\\/+/, \"\");\n\n // Avoid double-prefixing\n if (cleanLocation.startsWith(cleanPrefix + \"/\") || cleanLocation === cleanPrefix) {\n return cleanLocation;\n }\n\n return `${cleanPrefix}/${cleanLocation}`;\n }\n\n /**\n * Normalize storage path (remove double slashes, sanitize)\n * @internal\n */\n protected normalizePath(path: string): string {\n return path\n .replace(/\\/+/g, \"/\") // Remove multiple slashes\n .replace(/^\\//, \"\") // Remove leading slash\n .trim();\n }\n\n /**\n * Execute an operation with retry logic\n *\n * Retries on transient errors with exponential backoff.\n *\n * @param operation - Async operation to execute\n * @param operationName - Name for logging\n * @returns Result of the operation\n * @internal\n */\n protected async withRetry<T>(\n operation: () => Promise<T>,\n operationName: string = \"operation\",\n ): Promise<T> {\n const { maxRetries, initialDelayMs, backoffMultiplier, maxDelayMs } = this.retryConfig;\n\n let lastError: Error | undefined;\n\n for (let attempt = 0; attempt < maxRetries; attempt++) {\n try {\n return await operation();\n } catch (error) {\n lastError = error as Error;\n\n // Don't retry on the last attempt\n if (attempt === maxRetries - 1) {\n break;\n }\n\n // Check if error is retryable\n if (!this.isRetryableError(error)) {\n throw error; // Non-retryable error, fail immediately\n }\n\n // Calculate delay with exponential backoff\n const delayMs = Math.min(initialDelayMs * Math.pow(backoffMultiplier, attempt), maxDelayMs);\n\n // Wait before retrying\n await new Promise((resolve) => setTimeout(resolve, delayMs));\n }\n }\n\n throw new Error(`${operationName} failed after ${maxRetries} attempts: ${lastError?.message}`);\n }\n\n /**\n * Check if an error is retryable\n *\n * Retries on:\n * - Network errors\n * - 5xx server errors\n * - Rate limiting (429)\n * - Timeout errors\n *\n * Does NOT retry on:\n * - 4xx client errors (except 429)\n * - Authentication errors\n * - Not found errors\n *\n * @param error - Error to check\n * @returns true if error is retryable\n * @internal\n */\n protected isRetryableError(error: any): boolean {\n // Network errors\n if (error.code === \"ECONNRESET\" || error.code === \"ETIMEDOUT\" || error.code === \"ENOTFOUND\") {\n return true;\n }\n\n // S3 SDK errors\n if (error.name === \"NetworkingError\" || error.name === \"TimeoutError\") {\n return true;\n }\n\n // HTTP status codes\n const statusCode = error.$metadata?.httpStatusCode || error.statusCode;\n if (statusCode) {\n // 5xx server errors are retryable\n if (statusCode >= 500 && statusCode < 600) {\n return true;\n }\n\n // 429 Too Many Requests is retryable\n if (statusCode === 429) {\n return true;\n }\n }\n\n return false;\n }\n\n // ============================================================\n // Core File Operations\n // ============================================================\n\n /**\n * Put file to cloud storage\n */\n public async put(\n file: Buffer,\n location: string,\n options?: PutOptions,\n ): Promise<CloudStorageFileData> {\n return this.withRetry(async () => {\n const { PutObjectCommand } = S3Client;\n\n // Apply storage prefix\n location = this.applyPrefix(location);\n\n const hash = this.calculateHash(file);\n const mimeType = options?.mimeType || this.guessMimeType(location);\n\n const command = new PutObjectCommand({\n Bucket: this.options.bucket,\n Key: location,\n Body: file,\n ContentType: mimeType,\n CacheControl: options?.cacheControl,\n ContentDisposition: options?.contentDisposition,\n Metadata: options?.metadata,\n ACL: options?.visibility === \"public\" ? \"public-read\" : undefined,\n });\n\n const result = await this.client.send(command);\n\n return {\n path: location,\n url: this.url(location),\n size: file.length,\n hash,\n mimeType,\n driver: this.name,\n bucket: this.options.bucket!,\n region: this.options.region!,\n etag: result.ETag,\n versionId: result.VersionId,\n };\n }, \"put\");\n }\n\n /**\n * Put file from a readable stream (for large files)\n * Uses S3 multipart upload for efficient streaming\n */\n public async putStream(\n stream: Readable,\n location: string,\n options?: PutOptions,\n ): Promise<CloudStorageFileData> {\n return this.withRetry(async () => {\n const { Upload } = S3Storage;\n\n // Apply storage prefix\n location = this.applyPrefix(location);\n\n const mimeType = options?.mimeType || this.guessMimeType(location);\n\n const upload = new Upload({\n client: this.client,\n params: {\n Bucket: this.options.bucket,\n Key: location,\n Body: stream,\n ContentType: mimeType,\n CacheControl: options?.cacheControl,\n ContentDisposition: options?.contentDisposition,\n Metadata: options?.metadata,\n ACL: options?.visibility === \"public\" ? \"public-read\" : undefined,\n },\n });\n\n const result = await upload.done();\n\n // Get file info for size and hash\n const info = await this.metadata(location);\n\n return {\n path: location,\n url: this.url(location),\n size: info.size,\n hash: info.etag?.replace(/\"/g, \"\") || \"\",\n mimeType,\n driver: this.name,\n bucket: this.options.bucket!,\n region: this.options.region!,\n etag: result.ETag,\n versionId: result.VersionId,\n };\n }, \"putStream\");\n }\n\n /**\n * Get file contents as Buffer\n */\n public async get(location: string): Promise<Buffer> {\n return this.withRetry(async () => {\n const { GetObjectCommand } = S3Client;\n\n // Apply storage prefix\n location = this.applyPrefix(location);\n\n const command = new GetObjectCommand({\n Bucket: this.options.bucket,\n Key: location,\n });\n\n const result = await this.client.send(command);\n\n if (!result.Body) {\n throw new Error(`File not found: ${location}`);\n }\n\n return Buffer.from(await result.Body.transformToByteArray());\n }, \"get\");\n }\n\n /**\n * Get file as a readable stream (for large files)\n */\n public async getStream(location: string): Promise<Readable> {\n return this.withRetry(async () => {\n const { GetObjectCommand } = S3Client;\n\n // Apply storage prefix\n location = this.applyPrefix(location);\n\n const command = new GetObjectCommand({\n Bucket: this.options.bucket,\n Key: location,\n });\n\n const result = await this.client.send(command);\n\n if (!result.Body) {\n throw new Error(`File not found: ${location}`);\n }\n\n return result.Body as Readable;\n }, \"getStream\");\n }\n\n /**\n * Delete a file\n */\n public async delete(location: string): Promise<boolean> {\n return this.withRetry(async () => {\n const { DeleteObjectCommand } = S3Client;\n\n // Apply storage prefix\n location = this.applyPrefix(location);\n\n const command = new DeleteObjectCommand({\n Bucket: this.options.bucket,\n Key: location,\n });\n\n await this.client.send(command);\n\n return true;\n }, \"delete\");\n }\n\n /**\n * Delete multiple files at once (uses batch delete for efficiency)\n */\n public async deleteMany(locations: string[]): Promise<DeleteManyResult[]> {\n if (locations.length === 0) {\n return [];\n }\n\n return this.withRetry(async () => {\n const { DeleteObjectsCommand } = S3Client;\n\n // Apply storage prefix to all locations\n const prefixedLocations = locations.map((loc) => this.applyPrefix(loc));\n\n const command = new DeleteObjectsCommand({\n Bucket: this.options.bucket,\n Delete: {\n Objects: prefixedLocations.map((Key) => ({ Key })),\n Quiet: false,\n },\n });\n\n const result = await this.client.send(command);\n const results: DeleteManyResult[] = [];\n\n // Process successful deletes\n for (const deleted of result.Deleted || []) {\n if (deleted.Key) {\n results.push({ location: deleted.Key, deleted: true });\n }\n }\n\n // Process errors\n for (const error of result.Errors || []) {\n if (error.Key) {\n results.push({\n location: error.Key,\n deleted: false,\n error: error.Message || \"Unknown error\",\n });\n }\n }\n\n return results;\n }, \"deleteMany\");\n }\n\n /**\n * Delete directory (recursively deletes all objects with matching prefix)\n *\n * S3/R2 doesn't have true directories - only key prefixes.\n * This method lists all objects with the prefix and deletes them in batches.\n *\n * @param directoryPath - Directory prefix to delete\n * @returns true when all objects are deleted\n */\n public async deleteDirectory(directoryPath: string): Promise<boolean> {\n const { ListObjectsV2Command, DeleteObjectsCommand } = S3Client;\n\n // Apply storage prefix\n directoryPath = this.applyPrefix(directoryPath);\n\n // Ensure directory path ends with / for proper prefix matching\n const prefix = directoryPath.endsWith(\"/\") ? directoryPath : `${directoryPath}/`;\n\n // Drive the loop with the ListObjectsV2 IsTruncated / ContinuationToken\n // contract rather than guessing termination from page size. Each page\n // carries its own ContinuationToken so we never re-list page one.\n let continuationToken: string | undefined;\n\n do {\n const listResult = await this.withRetry(\n () =>\n this.client.send(\n new ListObjectsV2Command({\n Bucket: this.options.bucket,\n Prefix: prefix,\n ContinuationToken: continuationToken,\n }),\n ),\n \"deleteDirectory:list\",\n );\n\n const keys = (listResult.Contents || [])\n .map((object) => object.Key)\n .filter((key): key is string => Boolean(key));\n\n if (keys.length > 0) {\n // Delete the raw keys directly — they already carry the full prefix\n // from the listing, so we bypass deleteMany's applyPrefix step.\n await this.withRetry(\n () =>\n this.client.send(\n new DeleteObjectsCommand({\n Bucket: this.options.bucket,\n Delete: {\n Objects: keys.map((Key) => ({ Key })),\n Quiet: true,\n },\n }),\n ),\n \"deleteDirectory:delete\",\n );\n }\n\n continuationToken = listResult.IsTruncated\n ? listResult.NextContinuationToken\n : undefined;\n } while (continuationToken);\n\n return true;\n }\n\n /**\n * Check if file exists\n */\n public async exists(location: string): Promise<boolean> {\n // No retry for exists - it should be fast and failure means non-existent\n try {\n const { HeadObjectCommand } = S3Client;\n\n // Apply storage prefix\n location = this.applyPrefix(location);\n\n const command = new HeadObjectCommand({\n Bucket: this.options.bucket,\n Key: location,\n });\n\n await this.client.send(command);\n return true;\n } catch {\n return false;\n }\n }\n\n // ============================================================\n // URL Operations\n // ============================================================\n\n /**\n * Get a temporary presigned URL (alias for getPresignedUrl)\n */\n public async temporaryUrl(location: string, expiresIn = 3600): Promise<string> {\n return this.getPresignedUrl(location, { expiresIn });\n }\n\n /**\n * Get presigned URL for downloading\n */\n public async getPresignedUrl(location: string, options?: PresignedOptions): Promise<string> {\n return this.withRetry(async () => {\n const { GetObjectCommand } = S3Client;\n const { getSignedUrl } = S3Presigner;\n\n // Apply storage prefix\n location = this.applyPrefix(location);\n\n const command = new GetObjectCommand({\n Bucket: this.options.bucket,\n Key: location,\n });\n\n return getSignedUrl(this.client, command, {\n expiresIn: options?.expiresIn || 3600,\n });\n }, \"getPresignedUrl\");\n }\n\n /**\n * Get presigned URL for uploading\n */\n public async getPresignedUploadUrl(\n location: string,\n options?: PresignedUploadOptions,\n ): Promise<string> {\n return this.withRetry(async () => {\n const { PutObjectCommand } = S3Client;\n const { getSignedUrl } = S3Presigner;\n\n // Apply storage prefix\n location = this.applyPrefix(location);\n\n const command = new PutObjectCommand({\n Bucket: this.options.bucket,\n Key: location,\n ContentType: options?.contentType,\n Metadata: options?.metadata,\n });\n\n return getSignedUrl(this.client, command, {\n expiresIn: options?.expiresIn || 3600,\n });\n }, \"getPresignedUploadUrl\");\n }\n\n // ============================================================\n // Metadata Operations\n // ============================================================\n\n /**\n * Get file info/metadata without downloading\n */\n public async metadata(location: string): Promise<StorageFileInfo> {\n return this.withRetry(async () => {\n const { HeadObjectCommand } = S3Client;\n\n // Apply storage prefix\n location = this.applyPrefix(location);\n\n const command = new HeadObjectCommand({\n Bucket: this.options.bucket,\n Key: location,\n });\n\n const result = await this.client.send(command);\n const name = location.split(\"/\").pop() || \"\";\n\n return {\n path: location,\n name,\n size: result.ContentLength || 0,\n isDirectory: false,\n lastModified: result.LastModified,\n mimeType: result.ContentType || this.guessMimeType(location),\n etag: result.ETag,\n storageClass: result.StorageClass,\n };\n }, \"metadata\");\n }\n\n /**\n * Get file size in bytes (shortcut for metadata().size)\n */\n public async size(location: string): Promise<number> {\n const info = await this.metadata(location);\n return info.size;\n }\n\n // ============================================================\n // File Operations\n // ============================================================\n\n /**\n * Copy file to a new location\n */\n public async copy(from: string, to: string): Promise<CloudStorageFileData> {\n return this.withRetry(async () => {\n const { CopyObjectCommand, HeadObjectCommand } = S3Client;\n\n // Apply storage prefix to both paths\n from = this.applyPrefix(from);\n to = this.applyPrefix(to);\n\n const command = new CopyObjectCommand({\n Bucket: this.options.bucket,\n CopySource: `${this.options.bucket}/${from}`,\n Key: to,\n });\n\n const result = await this.client.send(command);\n\n // Get file metadata\n const headCommand = new HeadObjectCommand({\n Bucket: this.options.bucket,\n Key: to,\n });\n const headResult = await this.client.send(headCommand);\n\n return {\n path: to,\n url: this.url(to),\n size: headResult.ContentLength || 0,\n hash: headResult.ETag?.replace(/\"/g, \"\") || \"\",\n mimeType: headResult.ContentType || this.guessMimeType(to),\n driver: this.name,\n bucket: this.options.bucket!,\n region: this.options.region!,\n etag: result.CopyObjectResult?.ETag,\n versionId: result.VersionId,\n };\n }, \"copy\");\n }\n\n /**\n * Move file to a new location\n */\n public async move(from: string, to: string): Promise<CloudStorageFileData> {\n const file = await this.copy(from, to);\n await this.delete(from);\n return file;\n }\n\n /**\n * List files in a directory\n */\n public async list(directory: string, options?: ListOptions): Promise<StorageFileInfo[]> {\n return this.withRetry(async () => {\n const { ListObjectsV2Command } = S3Client;\n\n // Apply storage prefix\n directory = this.applyPrefix(directory);\n\n const command = new ListObjectsV2Command({\n Bucket: this.options.bucket,\n Prefix: directory,\n MaxKeys: options?.limit,\n ContinuationToken: options?.cursor,\n Delimiter: options?.recursive ? undefined : \"/\",\n });\n\n const result = await this.client.send(command);\n const files: StorageFileInfo[] = [];\n\n // Add files\n for (const object of result.Contents || []) {\n if (!object.Key) continue;\n\n files.push({\n path: object.Key,\n name: object.Key.split(\"/\").pop() || \"\",\n size: object.Size || 0,\n isDirectory: false,\n lastModified: object.LastModified,\n etag: object.ETag,\n storageClass: object.StorageClass,\n });\n }\n\n // Add directories\n for (const prefix of result.CommonPrefixes || []) {\n if (!prefix.Prefix) continue;\n\n files.push({\n path: prefix.Prefix,\n name: prefix.Prefix.split(\"/\").filter(Boolean).pop() || \"\",\n size: 0,\n isDirectory: true,\n });\n }\n\n return files;\n }, \"list\");\n }\n\n // ============================================================\n // Cloud-Specific Operations\n // ============================================================\n\n /**\n * Get bucket name\n */\n public getBucket(): string {\n return this.options.bucket!;\n }\n\n /**\n * Get region\n */\n public getRegion(): string {\n return this.options.region!;\n }\n\n /**\n * Set storage class (e.g., STANDARD, GLACIER, etc.)\n */\n public async setStorageClass(location: string, storageClass: string): Promise<void> {\n return this.withRetry(async () => {\n const { CopyObjectCommand } = S3Client;\n\n // Apply storage prefix\n location = this.applyPrefix(location);\n\n const command = new CopyObjectCommand({\n Bucket: this.options.bucket,\n CopySource: `${this.options.bucket}/${location}`,\n Key: location,\n StorageClass: storageClass as any,\n MetadataDirective: \"COPY\",\n });\n\n await this.client.send(command);\n }, \"setStorageClass\");\n }\n\n /**\n * Set file visibility (public or private)\n */\n public async setVisibility(location: string, visibility: FileVisibility): Promise<void> {\n return this.withRetry(async () => {\n const { PutObjectAclCommand } = S3Client;\n\n // Apply storage prefix\n location = this.applyPrefix(location);\n\n const command = new PutObjectAclCommand({\n Bucket: this.options.bucket,\n Key: location,\n ACL: visibility === \"public\" ? \"public-read\" : \"private\",\n });\n\n await this.client.send(command);\n }, \"setVisibility\");\n }\n\n /**\n * Get file visibility\n */\n public async getVisibility(location: string): Promise<FileVisibility> {\n return this.withRetry(async () => {\n const { GetObjectAclCommand } = S3Client;\n\n // Apply storage prefix\n location = this.applyPrefix(location);\n\n const command = new GetObjectAclCommand({\n Bucket: this.options.bucket,\n Key: location,\n });\n\n const result = await this.client.send(command);\n\n // Check if any grant allows public read\n const hasPublicRead = result.Grants?.some(\n (grant) =>\n grant.Grantee?.URI === \"http://acs.amazonaws.com/groups/global/AllUsers\" &&\n grant.Permission === \"READ\",\n );\n\n return hasPublicRead ? \"public\" : \"private\";\n }, \"getVisibility\");\n }\n\n // ============================================================\n // Utilities\n // ============================================================\n\n /**\n * Calculate SHA-256 hash\n */\n protected calculateHash(buffer: Buffer): string {\n return crypto.createHash(\"sha256\").update(new Uint8Array(buffer)).digest(\"hex\");\n }\n\n /**\n * Guess MIME type from file extension\n */\n protected guessMimeType(location: string): string {\n return getMimeType(location);\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"cloud-driver.mjs","names":[],"sources":["../../../../../../../../core/src/storage/drivers/cloud-driver.ts"],"sourcesContent":["import crypto from \"crypto\";\nimport { createRequire } from \"module\";\nimport type { Readable } from \"stream\";\nimport { storageDriverContext } from \"../context/storage-driver-context\";\nimport type {\n CloudStorageDriverContract,\n CloudStorageDriverOptions,\n CloudStorageFileData,\n DeleteManyResult,\n FileVisibility,\n ListOptions,\n PresignedOptions,\n PresignedUploadOptions,\n PutOptions,\n StorageDriverType,\n StorageFileInfo,\n} from \"../types\";\nimport { getMimeType } from \"../utils/mime\";\n\n// ============================================================\n// Lazy-loaded S3 SDK Types\n// ============================================================\n\n/**\n * Cached S3 SDK modules (loaded once, reused)\n */\nlet S3Client: typeof import(\"@aws-sdk/client-s3\");\nlet S3Storage: typeof import(\"@aws-sdk/lib-storage\");\nlet S3Presigner: typeof import(\"@aws-sdk/s3-request-presigner\");\n\nlet isModuleExists: boolean | null = null;\n\n/**\n * Installation instructions for S3 SDK packages\n */\nconst S3_INSTALL_INSTRUCTIONS = `\nCloud storage requires the AWS S3 SDK packages.\nInstall them with:\n\n npm install @aws-sdk/client-s3 @aws-sdk/lib-storage @aws-sdk/s3-request-presigner\n\nOr with your preferred package manager:\n\n pnpm add @aws-sdk/client-s3 @aws-sdk/lib-storage @aws-sdk/s3-request-presigner\n yarn add @aws-sdk/client-s3 @aws-sdk/lib-storage @aws-sdk/s3-request-presigner\n`.trim();\n\n/**\n * Atomic initialization promise to handle concurrent calls to loadS3\n */\nlet initializationPromise: Promise<void> | null = null;\n\n/**\n * Load S3 modules lazily\n *\n * @example\n * await loadS3();\n * if (isModuleExists) {\n * // Safe to use S3Client, S3Storage, S3Presigner\n * }\n */\nexport async function loadS3(): Promise<void> {\n // If already successfully loaded, no need to do anything\n if (isModuleExists === true) return;\n\n // If currently loading, return the existing promise so the caller waits\n if (initializationPromise) return initializationPromise;\n\n initializationPromise = (async () => {\n try {\n // Use Promise.all to load modules in parallel for efficiency\n const [client, storage, presigner] = await Promise.all([\n import(\"@aws-sdk/client-s3\"),\n import(\"@aws-sdk/lib-storage\"),\n import(\"@aws-sdk/s3-request-presigner\"),\n ]);\n\n S3Client = client;\n S3Storage = storage;\n S3Presigner = presigner;\n\n isModuleExists = true;\n } catch {\n // Mark as failed if any import fails (usually means packages aren't installed)\n isModuleExists = false;\n }\n })();\n\n return initializationPromise;\n}\n\nloadS3();\n\n/**\n * Synchronous fallback loader.\n *\n * `loadS3()` above is async and fire-and-forget at module load, so on the\n * very first *synchronous* `CloudDriver` construction the dynamic `import()`\n * microtask has not yet resolved — `isModuleExists` is still `null` even when\n * the SDK is genuinely installed. The constructor's install-check would then\n * throw the misleading \"SDK not installed\" error.\n *\n * This probes the modules synchronously via `require` (the AWS SDK ships\n * CJS-compatible builds) so a present SDK resolves the install-check\n * immediately, without waiting on the async path. Returns `true` when all\n * three modules loaded, `false` otherwise. Only invoked while\n * `isModuleExists` is still indeterminate.\n */\nfunction loadS3Sync(): boolean {\n if (isModuleExists !== null) {\n return isModuleExists;\n }\n\n try {\n // `createRequire` gives an ESM-safe synchronous `require` regardless of\n // whether this module runs as CJS or ESM at runtime.\n const req = createRequire(import.meta.url);\n S3Client = req(\"@aws-sdk/client-s3\");\n S3Storage = req(\"@aws-sdk/lib-storage\");\n S3Presigner = req(\"@aws-sdk/s3-request-presigner\");\n isModuleExists = true;\n } catch {\n isModuleExists = false;\n }\n\n return isModuleExists;\n}\n\n// ============================================================\n// CloudDriver Base Class\n// ============================================================\n\n/**\n * Base abstract class for all S3-compatible cloud storage drivers\n *\n * This class contains all shared logic for S3-compatible storage services\n * including AWS S3, Cloudflare R2, DigitalOcean Spaces, and others.\n *\n * **Important:** S3 SDK packages are lazy-loaded on first use.\n * Users must install them separately:\n * ```\n * npm install @aws-sdk/client-s3 @aws-sdk/lib-storage @aws-sdk/s3-request-presigner\n * ```\n *\n * Subclasses must implement:\n * - `name`: Driver identifier (e.g., \"s3\", \"r2\", \"spaces\")\n * - `url()`: Returns the public URL for a file (provider-specific format)\n */\nexport abstract class CloudDriver<\n TOptions extends Partial<CloudStorageDriverOptions> = CloudStorageDriverOptions,\n> implements CloudStorageDriverContract {\n /**\n * S3-compatible client (lazy-loaded)\n */\n protected client!: InstanceType<typeof import(\"@aws-sdk/client-s3\").S3Client>;\n\n /**\n * Retry configuration\n */\n protected retryConfig: {\n maxRetries: number;\n initialDelayMs: number;\n maxDelayMs: number;\n backoffMultiplier: number;\n };\n\n public constructor(public options: TOptions) {\n // The async loadS3() may not have resolved yet on the first synchronous\n // construction. When the flag is still indeterminate, probe synchronously\n // so a genuinely-installed SDK never triggers the misleading throw below.\n if (isModuleExists === null) {\n loadS3Sync();\n }\n\n if (!isModuleExists) {\n throw new Error(S3_INSTALL_INSTRUCTIONS);\n }\n\n this.client = new S3Client.S3Client({\n region: this.options.region!,\n credentials: {\n accessKeyId: this.options.accessKeyId!,\n secretAccessKey: this.options.secretAccessKey!,\n },\n ...(this.getEndpoint() && { endpoint: this.getEndpoint() }),\n });\n\n // Initialize retry configuration\n this.retryConfig = {\n maxRetries: this.options.retry?.maxRetries ?? 3,\n initialDelayMs: this.options.retry?.initialDelayMs ?? 1000,\n maxDelayMs: this.options.retry?.maxDelayMs ?? 10000,\n backoffMultiplier: this.options.retry?.backoffMultiplier ?? 2,\n };\n }\n\n /**\n * Driver name identifier\n */\n public abstract readonly name: StorageDriverType;\n\n /**\n * Get public URL for file\n * Must be implemented by subclasses with provider-specific format\n */\n public abstract url(location: string): string;\n\n /**\n * Get endpoint URL\n * Can be overridden by subclasses for provider-specific endpoints\n */\n protected getEndpoint(): string | undefined {\n return this.options.endpoint;\n }\n\n // ============================================================\n // Helper Methods\n // ============================================================\n\n /**\n * Apply prefix to location path\n *\n * Priority: context prefix > driver options prefix > no prefix\n * This allows multi-tenant scenarios where context overrides driver config.\n *\n * @param location - Original location path\n * @returns Location with prefix applied if one exists\n */\n public applyPrefix(location: string): string {\n // Check context prefix first (highest priority)\n const contextPrefix = storageDriverContext.getPrefix();\n const prefix = contextPrefix || this.options.prefix;\n\n if (!prefix) {\n return location;\n }\n\n const cleanPrefix = prefix.replace(/\\/+$/, \"\");\n const cleanLocation = location.replace(/^\\/+/, \"\");\n\n // Avoid double-prefixing\n if (cleanLocation.startsWith(cleanPrefix + \"/\") || cleanLocation === cleanPrefix) {\n return cleanLocation;\n }\n\n return `${cleanPrefix}/${cleanLocation}`;\n }\n\n /**\n * Normalize storage path (remove double slashes, sanitize)\n * @internal\n */\n protected normalizePath(path: string): string {\n return path\n .replace(/\\/+/g, \"/\") // Remove multiple slashes\n .replace(/^\\//, \"\") // Remove leading slash\n .trim();\n }\n\n /**\n * Execute an operation with retry logic\n *\n * Retries on transient errors with exponential backoff.\n *\n * @param operation - Async operation to execute\n * @param operationName - Name for logging\n * @returns Result of the operation\n * @internal\n */\n protected async withRetry<T>(\n operation: () => Promise<T>,\n operationName: string = \"operation\",\n ): Promise<T> {\n const { maxRetries, initialDelayMs, backoffMultiplier, maxDelayMs } = this.retryConfig;\n\n let lastError: Error | undefined;\n\n for (let attempt = 0; attempt < maxRetries; attempt++) {\n try {\n return await operation();\n } catch (error) {\n lastError = error as Error;\n\n // Don't retry on the last attempt\n if (attempt === maxRetries - 1) {\n break;\n }\n\n // Check if error is retryable\n if (!this.isRetryableError(error)) {\n throw error; // Non-retryable error, fail immediately\n }\n\n // Calculate delay with exponential backoff\n const delayMs = Math.min(initialDelayMs * Math.pow(backoffMultiplier, attempt), maxDelayMs);\n\n // Wait before retrying\n await new Promise((resolve) => setTimeout(resolve, delayMs));\n }\n }\n\n throw new Error(`${operationName} failed after ${maxRetries} attempts: ${lastError?.message}`);\n }\n\n /**\n * Check if an error is retryable\n *\n * Retries on:\n * - Network errors\n * - 5xx server errors\n * - Rate limiting (429)\n * - Timeout errors\n *\n * Does NOT retry on:\n * - 4xx client errors (except 429)\n * - Authentication errors\n * - Not found errors\n *\n * @param error - Error to check\n * @returns true if error is retryable\n * @internal\n */\n protected isRetryableError(error: any): boolean {\n // Network errors\n if (error.code === \"ECONNRESET\" || error.code === \"ETIMEDOUT\" || error.code === \"ENOTFOUND\") {\n return true;\n }\n\n // S3 SDK errors\n if (error.name === \"NetworkingError\" || error.name === \"TimeoutError\") {\n return true;\n }\n\n // HTTP status codes\n const statusCode = error.$metadata?.httpStatusCode || error.statusCode;\n if (statusCode) {\n // 5xx server errors are retryable\n if (statusCode >= 500 && statusCode < 600) {\n return true;\n }\n\n // 429 Too Many Requests is retryable\n if (statusCode === 429) {\n return true;\n }\n }\n\n return false;\n }\n\n // ============================================================\n // Core File Operations\n // ============================================================\n\n /**\n * Put file to cloud storage\n */\n public async put(\n file: Buffer,\n location: string,\n options?: PutOptions,\n ): Promise<CloudStorageFileData> {\n return this.withRetry(async () => {\n const { PutObjectCommand } = S3Client;\n\n // Apply storage prefix\n location = this.applyPrefix(location);\n\n const hash = this.calculateHash(file);\n const mimeType = options?.mimeType || this.guessMimeType(location);\n\n const command = new PutObjectCommand({\n Bucket: this.options.bucket,\n Key: location,\n Body: file,\n ContentType: mimeType,\n CacheControl: options?.cacheControl,\n ContentDisposition: options?.contentDisposition,\n Metadata: options?.metadata,\n ACL: options?.visibility === \"public\" ? \"public-read\" : undefined,\n });\n\n const result = await this.client.send(command);\n\n return {\n path: location,\n url: this.url(location),\n size: file.length,\n hash,\n mimeType,\n driver: this.name,\n bucket: this.options.bucket!,\n region: this.options.region!,\n etag: result.ETag,\n versionId: result.VersionId,\n };\n }, \"put\");\n }\n\n /**\n * Put file from a readable stream (for large files)\n * Uses S3 multipart upload for efficient streaming\n */\n public async putStream(\n stream: Readable,\n location: string,\n options?: PutOptions,\n ): Promise<CloudStorageFileData> {\n return this.withRetry(async () => {\n const { Upload } = S3Storage;\n\n // Apply storage prefix\n location = this.applyPrefix(location);\n\n const mimeType = options?.mimeType || this.guessMimeType(location);\n\n const upload = new Upload({\n client: this.client,\n params: {\n Bucket: this.options.bucket,\n Key: location,\n Body: stream,\n ContentType: mimeType,\n CacheControl: options?.cacheControl,\n ContentDisposition: options?.contentDisposition,\n Metadata: options?.metadata,\n ACL: options?.visibility === \"public\" ? \"public-read\" : undefined,\n },\n });\n\n const result = await upload.done();\n\n // Get file info for size and hash\n const info = await this.metadata(location);\n\n return {\n path: location,\n url: this.url(location),\n size: info.size,\n hash: info.etag?.replace(/\"/g, \"\") || \"\",\n mimeType,\n driver: this.name,\n bucket: this.options.bucket!,\n region: this.options.region!,\n etag: result.ETag,\n versionId: result.VersionId,\n };\n }, \"putStream\");\n }\n\n /**\n * Get file contents as Buffer\n */\n public async get(location: string): Promise<Buffer> {\n return this.withRetry(async () => {\n const { GetObjectCommand } = S3Client;\n\n // Apply storage prefix\n location = this.applyPrefix(location);\n\n const command = new GetObjectCommand({\n Bucket: this.options.bucket,\n Key: location,\n });\n\n const result = await this.client.send(command);\n\n if (!result.Body) {\n throw new Error(`File not found: ${location}`);\n }\n\n return Buffer.from(await result.Body.transformToByteArray());\n }, \"get\");\n }\n\n /**\n * Get file as a readable stream (for large files)\n */\n public async getStream(location: string): Promise<Readable> {\n return this.withRetry(async () => {\n const { GetObjectCommand } = S3Client;\n\n // Apply storage prefix\n location = this.applyPrefix(location);\n\n const command = new GetObjectCommand({\n Bucket: this.options.bucket,\n Key: location,\n });\n\n const result = await this.client.send(command);\n\n if (!result.Body) {\n throw new Error(`File not found: ${location}`);\n }\n\n return result.Body as Readable;\n }, \"getStream\");\n }\n\n /**\n * Delete a file\n */\n public async delete(location: string): Promise<boolean> {\n return this.withRetry(async () => {\n const { DeleteObjectCommand } = S3Client;\n\n // Apply storage prefix\n location = this.applyPrefix(location);\n\n const command = new DeleteObjectCommand({\n Bucket: this.options.bucket,\n Key: location,\n });\n\n await this.client.send(command);\n\n return true;\n }, \"delete\");\n }\n\n /**\n * Delete multiple files at once (uses batch delete for efficiency)\n */\n public async deleteMany(locations: string[]): Promise<DeleteManyResult[]> {\n if (locations.length === 0) {\n return [];\n }\n\n return this.withRetry(async () => {\n const { DeleteObjectsCommand } = S3Client;\n\n // Apply storage prefix to all locations\n const prefixedLocations = locations.map((loc) => this.applyPrefix(loc));\n\n const command = new DeleteObjectsCommand({\n Bucket: this.options.bucket,\n Delete: {\n Objects: prefixedLocations.map((Key) => ({ Key })),\n Quiet: false,\n },\n });\n\n const result = await this.client.send(command);\n const results: DeleteManyResult[] = [];\n\n // Process successful deletes\n for (const deleted of result.Deleted || []) {\n if (deleted.Key) {\n results.push({ location: deleted.Key, deleted: true });\n }\n }\n\n // Process errors\n for (const error of result.Errors || []) {\n if (error.Key) {\n results.push({\n location: error.Key,\n deleted: false,\n error: error.Message || \"Unknown error\",\n });\n }\n }\n\n return results;\n }, \"deleteMany\");\n }\n\n /**\n * Delete directory (recursively deletes all objects with matching prefix)\n *\n * S3/R2 doesn't have true directories - only key prefixes.\n * This method lists all objects with the prefix and deletes them in batches.\n *\n * @param directoryPath - Directory prefix to delete\n * @returns true when all objects are deleted\n */\n public async deleteDirectory(directoryPath: string): Promise<boolean> {\n const { ListObjectsV2Command, DeleteObjectsCommand } = S3Client;\n\n // Apply storage prefix\n directoryPath = this.applyPrefix(directoryPath);\n\n // Ensure directory path ends with / for proper prefix matching\n const prefix = directoryPath.endsWith(\"/\") ? directoryPath : `${directoryPath}/`;\n\n // Drive the loop with the ListObjectsV2 IsTruncated / ContinuationToken\n // contract rather than guessing termination from page size. Each page\n // carries its own ContinuationToken so we never re-list page one.\n let continuationToken: string | undefined;\n\n do {\n const listResult = await this.withRetry(\n () =>\n this.client.send(\n new ListObjectsV2Command({\n Bucket: this.options.bucket,\n Prefix: prefix,\n ContinuationToken: continuationToken,\n }),\n ),\n \"deleteDirectory:list\",\n );\n\n const keys = (listResult.Contents || [])\n .map((object) => object.Key)\n .filter((key): key is string => Boolean(key));\n\n if (keys.length > 0) {\n // Delete the raw keys directly — they already carry the full prefix\n // from the listing, so we bypass deleteMany's applyPrefix step.\n await this.withRetry(\n () =>\n this.client.send(\n new DeleteObjectsCommand({\n Bucket: this.options.bucket,\n Delete: {\n Objects: keys.map((Key) => ({ Key })),\n Quiet: true,\n },\n }),\n ),\n \"deleteDirectory:delete\",\n );\n }\n\n continuationToken = listResult.IsTruncated\n ? listResult.NextContinuationToken\n : undefined;\n } while (continuationToken);\n\n return true;\n }\n\n /**\n * Check if file exists\n */\n public async exists(location: string): Promise<boolean> {\n // No retry for exists - it should be fast and failure means non-existent\n try {\n const { HeadObjectCommand } = S3Client;\n\n // Apply storage prefix\n location = this.applyPrefix(location);\n\n const command = new HeadObjectCommand({\n Bucket: this.options.bucket,\n Key: location,\n });\n\n await this.client.send(command);\n return true;\n } catch {\n return false;\n }\n }\n\n // ============================================================\n // URL Operations\n // ============================================================\n\n /**\n * Get a temporary presigned URL (alias for getPresignedUrl)\n */\n public async temporaryUrl(location: string, expiresIn = 3600): Promise<string> {\n return this.getPresignedUrl(location, { expiresIn });\n }\n\n /**\n * Get presigned URL for downloading\n */\n public async getPresignedUrl(location: string, options?: PresignedOptions): Promise<string> {\n return this.withRetry(async () => {\n const { GetObjectCommand } = S3Client;\n const { getSignedUrl } = S3Presigner;\n\n // Apply storage prefix\n location = this.applyPrefix(location);\n\n const command = new GetObjectCommand({\n Bucket: this.options.bucket,\n Key: location,\n });\n\n return getSignedUrl(this.client, command, {\n expiresIn: options?.expiresIn || 3600,\n });\n }, \"getPresignedUrl\");\n }\n\n /**\n * Get presigned URL for uploading\n */\n public async getPresignedUploadUrl(\n location: string,\n options?: PresignedUploadOptions,\n ): Promise<string> {\n return this.withRetry(async () => {\n const { PutObjectCommand } = S3Client;\n const { getSignedUrl } = S3Presigner;\n\n // Apply storage prefix\n location = this.applyPrefix(location);\n\n const command = new PutObjectCommand({\n Bucket: this.options.bucket,\n Key: location,\n ContentType: options?.contentType,\n Metadata: options?.metadata,\n });\n\n return getSignedUrl(this.client, command, {\n expiresIn: options?.expiresIn || 3600,\n });\n }, \"getPresignedUploadUrl\");\n }\n\n // ============================================================\n // Metadata Operations\n // ============================================================\n\n /**\n * Get file info/metadata without downloading\n */\n public async metadata(location: string): Promise<StorageFileInfo> {\n return this.withRetry(async () => {\n const { HeadObjectCommand } = S3Client;\n\n // Apply storage prefix\n location = this.applyPrefix(location);\n\n const command = new HeadObjectCommand({\n Bucket: this.options.bucket,\n Key: location,\n });\n\n const result = await this.client.send(command);\n const name = location.split(\"/\").pop() || \"\";\n\n return {\n path: location,\n name,\n size: result.ContentLength || 0,\n isDirectory: false,\n lastModified: result.LastModified,\n mimeType: result.ContentType || this.guessMimeType(location),\n etag: result.ETag,\n storageClass: result.StorageClass,\n };\n }, \"metadata\");\n }\n\n /**\n * Get file size in bytes (shortcut for metadata().size)\n */\n public async size(location: string): Promise<number> {\n const info = await this.metadata(location);\n return info.size;\n }\n\n // ============================================================\n // File Operations\n // ============================================================\n\n /**\n * Copy file to a new location\n */\n public async copy(from: string, to: string): Promise<CloudStorageFileData> {\n return this.withRetry(async () => {\n const { CopyObjectCommand, HeadObjectCommand } = S3Client;\n\n // Apply storage prefix to both paths\n from = this.applyPrefix(from);\n to = this.applyPrefix(to);\n\n const command = new CopyObjectCommand({\n Bucket: this.options.bucket,\n CopySource: `${this.options.bucket}/${from}`,\n Key: to,\n });\n\n const result = await this.client.send(command);\n\n // Get file metadata\n const headCommand = new HeadObjectCommand({\n Bucket: this.options.bucket,\n Key: to,\n });\n const headResult = await this.client.send(headCommand);\n\n return {\n path: to,\n url: this.url(to),\n size: headResult.ContentLength || 0,\n hash: headResult.ETag?.replace(/\"/g, \"\") || \"\",\n mimeType: headResult.ContentType || this.guessMimeType(to),\n driver: this.name,\n bucket: this.options.bucket!,\n region: this.options.region!,\n etag: result.CopyObjectResult?.ETag,\n versionId: result.VersionId,\n };\n }, \"copy\");\n }\n\n /**\n * Move file to a new location\n */\n public async move(from: string, to: string): Promise<CloudStorageFileData> {\n const file = await this.copy(from, to);\n await this.delete(from);\n return file;\n }\n\n /**\n * List files in a directory\n */\n public async list(directory: string, options?: ListOptions): Promise<StorageFileInfo[]> {\n return this.withRetry(async () => {\n const { ListObjectsV2Command } = S3Client;\n\n // Apply storage prefix\n directory = this.applyPrefix(directory);\n\n const command = new ListObjectsV2Command({\n Bucket: this.options.bucket,\n Prefix: directory,\n MaxKeys: options?.limit,\n ContinuationToken: options?.cursor,\n Delimiter: options?.recursive ? undefined : \"/\",\n });\n\n const result = await this.client.send(command);\n const files: StorageFileInfo[] = [];\n\n // Add files\n for (const object of result.Contents || []) {\n if (!object.Key) continue;\n\n files.push({\n path: object.Key,\n name: object.Key.split(\"/\").pop() || \"\",\n size: object.Size || 0,\n isDirectory: false,\n lastModified: object.LastModified,\n etag: object.ETag,\n storageClass: object.StorageClass,\n });\n }\n\n // Add directories\n for (const prefix of result.CommonPrefixes || []) {\n if (!prefix.Prefix) continue;\n\n files.push({\n path: prefix.Prefix,\n name: prefix.Prefix.split(\"/\").filter(Boolean).pop() || \"\",\n size: 0,\n isDirectory: true,\n });\n }\n\n return files;\n }, \"list\");\n }\n\n // ============================================================\n // Cloud-Specific Operations\n // ============================================================\n\n /**\n * Get bucket name\n */\n public getBucket(): string {\n return this.options.bucket!;\n }\n\n /**\n * Get region\n */\n public getRegion(): string {\n return this.options.region!;\n }\n\n /**\n * Set storage class (e.g., STANDARD, GLACIER, etc.)\n */\n public async setStorageClass(location: string, storageClass: string): Promise<void> {\n return this.withRetry(async () => {\n const { CopyObjectCommand } = S3Client;\n\n // Apply storage prefix\n location = this.applyPrefix(location);\n\n const command = new CopyObjectCommand({\n Bucket: this.options.bucket,\n CopySource: `${this.options.bucket}/${location}`,\n Key: location,\n StorageClass: storageClass as any,\n MetadataDirective: \"COPY\",\n });\n\n await this.client.send(command);\n }, \"setStorageClass\");\n }\n\n /**\n * Set file visibility (public or private)\n */\n public async setVisibility(location: string, visibility: FileVisibility): Promise<void> {\n return this.withRetry(async () => {\n const { PutObjectAclCommand } = S3Client;\n\n // Apply storage prefix\n location = this.applyPrefix(location);\n\n const command = new PutObjectAclCommand({\n Bucket: this.options.bucket,\n Key: location,\n ACL: visibility === \"public\" ? \"public-read\" : \"private\",\n });\n\n await this.client.send(command);\n }, \"setVisibility\");\n }\n\n /**\n * Get file visibility\n */\n public async getVisibility(location: string): Promise<FileVisibility> {\n return this.withRetry(async () => {\n const { GetObjectAclCommand } = S3Client;\n\n // Apply storage prefix\n location = this.applyPrefix(location);\n\n const command = new GetObjectAclCommand({\n Bucket: this.options.bucket,\n Key: location,\n });\n\n const result = await this.client.send(command);\n\n // Check if any grant allows public read\n const hasPublicRead = result.Grants?.some(\n (grant) =>\n grant.Grantee?.URI === \"http://acs.amazonaws.com/groups/global/AllUsers\" &&\n grant.Permission === \"READ\",\n );\n\n return hasPublicRead ? \"public\" : \"private\";\n }, \"getVisibility\");\n }\n\n // ============================================================\n // Utilities\n // ============================================================\n\n /**\n * Calculate SHA-256 hash\n */\n protected calculateHash(buffer: Buffer): string {\n return crypto.createHash(\"sha256\").update(new Uint8Array(buffer)).digest(\"hex\");\n }\n\n /**\n * Guess MIME type from file extension\n */\n protected guessMimeType(location: string): string {\n return getMimeType(location);\n }\n}\n"],"mappings":";;;;;;;;;AA0BA,IAAI;AACJ,IAAI;AACJ,IAAI;AAEJ,IAAI,iBAAiC;;;;AAKrC,MAAM,0BAA0B;;;;;;;;;;EAU9B,KAAK;;;;AAKP,IAAI,wBAA8C;;;;;;;;;;AAWlD,eAAsB,SAAwB;CAE5C,IAAI,mBAAmB,MAAM;CAG7B,IAAI,uBAAuB,OAAO;CAElC,yBAAyB,YAAY;EACnC,IAAI;GAEF,MAAM,CAAC,QAAQ,SAAS,aAAa,MAAM,QAAQ,IAAI;IACrD,OAAO;IACP,OAAO;IACP,OAAO;GACT,CAAC;GAED,WAAW;GACX,YAAY;GACZ,cAAc;GAEd,iBAAiB;EACnB,QAAQ;GAEN,iBAAiB;EACnB;CACF,EAAC,CAAE;CAEH,OAAO;AACT;AAEA,OAAO;;;;;;;;;;;;;;;;AAiBP,SAAS,aAAsB;CAC7B,IAAI,mBAAmB,MACrB,OAAO;CAGT,IAAI;EAGF,MAAM,MAAM,cAAc,OAAO,KAAK,GAAG;EACzC,WAAW,IAAI,oBAAoB;EACnC,YAAY,IAAI,sBAAsB;EACtC,cAAc,IAAI,+BAA+B;EACjD,iBAAiB;CACnB,QAAQ;EACN,iBAAiB;CACnB;CAEA,OAAO;AACT;;;;;;;;;;;;;;;;;AAsBA,IAAsB,cAAtB,MAEwC;CAgBtC,AAAO,YAAY,AAAO,SAAmB;EAAnB;EAIxB,IAAI,mBAAmB,MACrB,WAAW;EAGb,IAAI,CAAC,gBACH,MAAM,IAAI,MAAM,uBAAuB;EAGzC,KAAK,SAAS,IAAI,SAAS,SAAS;GAClC,QAAQ,KAAK,QAAQ;GACrB,aAAa;IACX,aAAa,KAAK,QAAQ;IAC1B,iBAAiB,KAAK,QAAQ;GAChC;GACA,GAAI,KAAK,YAAY,KAAK,EAAE,UAAU,KAAK,YAAY,EAAE;EAC3D,CAAC;EAGD,KAAK,cAAc;GACjB,YAAY,KAAK,QAAQ,OAAO,cAAc;GAC9C,gBAAgB,KAAK,QAAQ,OAAO,kBAAkB;GACtD,YAAY,KAAK,QAAQ,OAAO,cAAc;GAC9C,mBAAmB,KAAK,QAAQ,OAAO,qBAAqB;EAC9D;CACF;;;;;CAiBA,AAAU,cAAkC;EAC1C,OAAO,KAAK,QAAQ;CACtB;;;;;;;;;;CAeA,AAAO,YAAY,UAA0B;EAG3C,MAAM,SADgB,qBAAqB,UAChB,KAAK,KAAK,QAAQ;EAE7C,IAAI,CAAC,QACH,OAAO;EAGT,MAAM,cAAc,OAAO,QAAQ,QAAQ,EAAE;EAC7C,MAAM,gBAAgB,SAAS,QAAQ,QAAQ,EAAE;EAGjD,IAAI,cAAc,WAAW,cAAc,GAAG,KAAK,kBAAkB,aACnE,OAAO;EAGT,OAAO,GAAG,YAAY,GAAG;CAC3B;;;;;CAMA,AAAU,cAAc,MAAsB;EAC5C,OAAO,KACJ,QAAQ,QAAQ,GAAG,CAAC,CACpB,QAAQ,OAAO,EAAE,CAAC,CAClB,KAAK;CACV;;;;;;;;;;;CAYA,MAAgB,UACd,WACA,gBAAwB,aACZ;EACZ,MAAM,EAAE,YAAY,gBAAgB,mBAAmB,eAAe,KAAK;EAE3E,IAAI;EAEJ,KAAK,IAAI,UAAU,GAAG,UAAU,YAAY,WAC1C,IAAI;GACF,OAAO,MAAM,UAAU;EACzB,SAAS,OAAO;GACd,YAAY;GAGZ,IAAI,YAAY,aAAa,GAC3B;GAIF,IAAI,CAAC,KAAK,iBAAiB,KAAK,GAC9B,MAAM;GAIR,MAAM,UAAU,KAAK,IAAI,iBAAiB,KAAK,IAAI,mBAAmB,OAAO,GAAG,UAAU;GAG1F,MAAM,IAAI,SAAS,YAAY,WAAW,SAAS,OAAO,CAAC;EAC7D;EAGF,MAAM,IAAI,MAAM,GAAG,cAAc,gBAAgB,WAAW,aAAa,WAAW,SAAS;CAC/F;;;;;;;;;;;;;;;;;;;CAoBA,AAAU,iBAAiB,OAAqB;EAE9C,IAAI,MAAM,SAAS,gBAAgB,MAAM,SAAS,eAAe,MAAM,SAAS,aAC9E,OAAO;EAIT,IAAI,MAAM,SAAS,qBAAqB,MAAM,SAAS,gBACrD,OAAO;EAIT,MAAM,aAAa,MAAM,WAAW,kBAAkB,MAAM;EAC5D,IAAI,YAAY;GAEd,IAAI,cAAc,OAAO,aAAa,KACpC,OAAO;GAIT,IAAI,eAAe,KACjB,OAAO;EAEX;EAEA,OAAO;CACT;;;;CASA,MAAa,IACX,MACA,UACA,SAC+B;EAC/B,OAAO,KAAK,UAAU,YAAY;GAChC,MAAM,EAAE,qBAAqB;GAG7B,WAAW,KAAK,YAAY,QAAQ;GAEpC,MAAM,OAAO,KAAK,cAAc,IAAI;GACpC,MAAM,WAAW,SAAS,YAAY,KAAK,cAAc,QAAQ;GAEjE,MAAM,UAAU,IAAI,iBAAiB;IACnC,QAAQ,KAAK,QAAQ;IACrB,KAAK;IACL,MAAM;IACN,aAAa;IACb,cAAc,SAAS;IACvB,oBAAoB,SAAS;IAC7B,UAAU,SAAS;IACnB,KAAK,SAAS,eAAe,WAAW,gBAAgB;GAC1D,CAAC;GAED,MAAM,SAAS,MAAM,KAAK,OAAO,KAAK,OAAO;GAE7C,OAAO;IACL,MAAM;IACN,KAAK,KAAK,IAAI,QAAQ;IACtB,MAAM,KAAK;IACX;IACA;IACA,QAAQ,KAAK;IACb,QAAQ,KAAK,QAAQ;IACrB,QAAQ,KAAK,QAAQ;IACrB,MAAM,OAAO;IACb,WAAW,OAAO;GACpB;EACF,GAAG,KAAK;CACV;;;;;CAMA,MAAa,UACX,QACA,UACA,SAC+B;EAC/B,OAAO,KAAK,UAAU,YAAY;GAChC,MAAM,EAAE,WAAW;GAGnB,WAAW,KAAK,YAAY,QAAQ;GAEpC,MAAM,WAAW,SAAS,YAAY,KAAK,cAAc,QAAQ;GAgBjE,MAAM,SAAS,MAAM,IAdF,OAAO;IACxB,QAAQ,KAAK;IACb,QAAQ;KACN,QAAQ,KAAK,QAAQ;KACrB,KAAK;KACL,MAAM;KACN,aAAa;KACb,cAAc,SAAS;KACvB,oBAAoB,SAAS;KAC7B,UAAU,SAAS;KACnB,KAAK,SAAS,eAAe,WAAW,gBAAgB;IAC1D;GACF,CAE0B,CAAC,CAAC,KAAK;GAGjC,MAAM,OAAO,MAAM,KAAK,SAAS,QAAQ;GAEzC,OAAO;IACL,MAAM;IACN,KAAK,KAAK,IAAI,QAAQ;IACtB,MAAM,KAAK;IACX,MAAM,KAAK,MAAM,QAAQ,MAAM,EAAE,KAAK;IACtC;IACA,QAAQ,KAAK;IACb,QAAQ,KAAK,QAAQ;IACrB,QAAQ,KAAK,QAAQ;IACrB,MAAM,OAAO;IACb,WAAW,OAAO;GACpB;EACF,GAAG,WAAW;CAChB;;;;CAKA,MAAa,IAAI,UAAmC;EAClD,OAAO,KAAK,UAAU,YAAY;GAChC,MAAM,EAAE,qBAAqB;GAG7B,WAAW,KAAK,YAAY,QAAQ;GAEpC,MAAM,UAAU,IAAI,iBAAiB;IACnC,QAAQ,KAAK,QAAQ;IACrB,KAAK;GACP,CAAC;GAED,MAAM,SAAS,MAAM,KAAK,OAAO,KAAK,OAAO;GAE7C,IAAI,CAAC,OAAO,MACV,MAAM,IAAI,MAAM,mBAAmB,UAAU;GAG/C,OAAO,OAAO,KAAK,MAAM,OAAO,KAAK,qBAAqB,CAAC;EAC7D,GAAG,KAAK;CACV;;;;CAKA,MAAa,UAAU,UAAqC;EAC1D,OAAO,KAAK,UAAU,YAAY;GAChC,MAAM,EAAE,qBAAqB;GAG7B,WAAW,KAAK,YAAY,QAAQ;GAEpC,MAAM,UAAU,IAAI,iBAAiB;IACnC,QAAQ,KAAK,QAAQ;IACrB,KAAK;GACP,CAAC;GAED,MAAM,SAAS,MAAM,KAAK,OAAO,KAAK,OAAO;GAE7C,IAAI,CAAC,OAAO,MACV,MAAM,IAAI,MAAM,mBAAmB,UAAU;GAG/C,OAAO,OAAO;EAChB,GAAG,WAAW;CAChB;;;;CAKA,MAAa,OAAO,UAAoC;EACtD,OAAO,KAAK,UAAU,YAAY;GAChC,MAAM,EAAE,wBAAwB;GAGhC,WAAW,KAAK,YAAY,QAAQ;GAEpC,MAAM,UAAU,IAAI,oBAAoB;IACtC,QAAQ,KAAK,QAAQ;IACrB,KAAK;GACP,CAAC;GAED,MAAM,KAAK,OAAO,KAAK,OAAO;GAE9B,OAAO;EACT,GAAG,QAAQ;CACb;;;;CAKA,MAAa,WAAW,WAAkD;EACxE,IAAI,UAAU,WAAW,GACvB,OAAO,CAAC;EAGV,OAAO,KAAK,UAAU,YAAY;GAChC,MAAM,EAAE,yBAAyB;GAGjC,MAAM,oBAAoB,UAAU,KAAK,QAAQ,KAAK,YAAY,GAAG,CAAC;GAEtE,MAAM,UAAU,IAAI,qBAAqB;IACvC,QAAQ,KAAK,QAAQ;IACrB,QAAQ;KACN,SAAS,kBAAkB,KAAK,SAAS,EAAE,IAAI,EAAE;KACjD,OAAO;IACT;GACF,CAAC;GAED,MAAM,SAAS,MAAM,KAAK,OAAO,KAAK,OAAO;GAC7C,MAAM,UAA8B,CAAC;GAGrC,KAAK,MAAM,WAAW,OAAO,WAAW,CAAC,GACvC,IAAI,QAAQ,KACV,QAAQ,KAAK;IAAE,UAAU,QAAQ;IAAK,SAAS;GAAK,CAAC;GAKzD,KAAK,MAAM,SAAS,OAAO,UAAU,CAAC,GACpC,IAAI,MAAM,KACR,QAAQ,KAAK;IACX,UAAU,MAAM;IAChB,SAAS;IACT,OAAO,MAAM,WAAW;GAC1B,CAAC;GAIL,OAAO;EACT,GAAG,YAAY;CACjB;;;;;;;;;;CAWA,MAAa,gBAAgB,eAAyC;EACpE,MAAM,EAAE,sBAAsB,yBAAyB;EAGvD,gBAAgB,KAAK,YAAY,aAAa;EAG9C,MAAM,SAAS,cAAc,SAAS,GAAG,IAAI,gBAAgB,GAAG,cAAc;EAK9E,IAAI;EAEJ,GAAG;GACD,MAAM,aAAa,MAAM,KAAK,gBAE1B,KAAK,OAAO,KACV,IAAI,qBAAqB;IACvB,QAAQ,KAAK,QAAQ;IACrB,QAAQ;IACR,mBAAmB;GACrB,CAAC,CACH,GACF,sBACF;GAEA,MAAM,QAAQ,WAAW,YAAY,CAAC,EAAC,CACpC,KAAK,WAAW,OAAO,GAAG,CAAC,CAC3B,QAAQ,QAAuB,QAAQ,GAAG,CAAC;GAE9C,IAAI,KAAK,SAAS,GAGhB,MAAM,KAAK,gBAEP,KAAK,OAAO,KACV,IAAI,qBAAqB;IACvB,QAAQ,KAAK,QAAQ;IACrB,QAAQ;KACN,SAAS,KAAK,KAAK,SAAS,EAAE,IAAI,EAAE;KACpC,OAAO;IACT;GACF,CAAC,CACH,GACF,wBACF;GAGF,oBAAoB,WAAW,cAC3B,WAAW,wBACX;EACN,SAAS;EAET,OAAO;CACT;;;;CAKA,MAAa,OAAO,UAAoC;EAEtD,IAAI;GACF,MAAM,EAAE,sBAAsB;GAG9B,WAAW,KAAK,YAAY,QAAQ;GAEpC,MAAM,UAAU,IAAI,kBAAkB;IACpC,QAAQ,KAAK,QAAQ;IACrB,KAAK;GACP,CAAC;GAED,MAAM,KAAK,OAAO,KAAK,OAAO;GAC9B,OAAO;EACT,QAAQ;GACN,OAAO;EACT;CACF;;;;CASA,MAAa,aAAa,UAAkB,YAAY,MAAuB;EAC7E,OAAO,KAAK,gBAAgB,UAAU,EAAE,UAAU,CAAC;CACrD;;;;CAKA,MAAa,gBAAgB,UAAkB,SAA6C;EAC1F,OAAO,KAAK,UAAU,YAAY;GAChC,MAAM,EAAE,qBAAqB;GAC7B,MAAM,EAAE,iBAAiB;GAGzB,WAAW,KAAK,YAAY,QAAQ;GAEpC,MAAM,UAAU,IAAI,iBAAiB;IACnC,QAAQ,KAAK,QAAQ;IACrB,KAAK;GACP,CAAC;GAED,OAAO,aAAa,KAAK,QAAQ,SAAS,EACxC,WAAW,SAAS,aAAa,KACnC,CAAC;EACH,GAAG,iBAAiB;CACtB;;;;CAKA,MAAa,sBACX,UACA,SACiB;EACjB,OAAO,KAAK,UAAU,YAAY;GAChC,MAAM,EAAE,qBAAqB;GAC7B,MAAM,EAAE,iBAAiB;GAGzB,WAAW,KAAK,YAAY,QAAQ;GAEpC,MAAM,UAAU,IAAI,iBAAiB;IACnC,QAAQ,KAAK,QAAQ;IACrB,KAAK;IACL,aAAa,SAAS;IACtB,UAAU,SAAS;GACrB,CAAC;GAED,OAAO,aAAa,KAAK,QAAQ,SAAS,EACxC,WAAW,SAAS,aAAa,KACnC,CAAC;EACH,GAAG,uBAAuB;CAC5B;;;;CASA,MAAa,SAAS,UAA4C;EAChE,OAAO,KAAK,UAAU,YAAY;GAChC,MAAM,EAAE,sBAAsB;GAG9B,WAAW,KAAK,YAAY,QAAQ;GAEpC,MAAM,UAAU,IAAI,kBAAkB;IACpC,QAAQ,KAAK,QAAQ;IACrB,KAAK;GACP,CAAC;GAED,MAAM,SAAS,MAAM,KAAK,OAAO,KAAK,OAAO;GAC7C,MAAM,OAAO,SAAS,MAAM,GAAG,CAAC,CAAC,IAAI,KAAK;GAE1C,OAAO;IACL,MAAM;IACN;IACA,MAAM,OAAO,iBAAiB;IAC9B,aAAa;IACb,cAAc,OAAO;IACrB,UAAU,OAAO,eAAe,KAAK,cAAc,QAAQ;IAC3D,MAAM,OAAO;IACb,cAAc,OAAO;GACvB;EACF,GAAG,UAAU;CACf;;;;CAKA,MAAa,KAAK,UAAmC;EAEnD,QAAO,MADY,KAAK,SAAS,QAAQ,EAC9B,CAAC;CACd;;;;CASA,MAAa,KAAK,MAAc,IAA2C;EACzE,OAAO,KAAK,UAAU,YAAY;GAChC,MAAM,EAAE,mBAAmB,sBAAsB;GAGjD,OAAO,KAAK,YAAY,IAAI;GAC5B,KAAK,KAAK,YAAY,EAAE;GAExB,MAAM,UAAU,IAAI,kBAAkB;IACpC,QAAQ,KAAK,QAAQ;IACrB,YAAY,GAAG,KAAK,QAAQ,OAAO,GAAG;IACtC,KAAK;GACP,CAAC;GAED,MAAM,SAAS,MAAM,KAAK,OAAO,KAAK,OAAO;GAG7C,MAAM,cAAc,IAAI,kBAAkB;IACxC,QAAQ,KAAK,QAAQ;IACrB,KAAK;GACP,CAAC;GACD,MAAM,aAAa,MAAM,KAAK,OAAO,KAAK,WAAW;GAErD,OAAO;IACL,MAAM;IACN,KAAK,KAAK,IAAI,EAAE;IAChB,MAAM,WAAW,iBAAiB;IAClC,MAAM,WAAW,MAAM,QAAQ,MAAM,EAAE,KAAK;IAC5C,UAAU,WAAW,eAAe,KAAK,cAAc,EAAE;IACzD,QAAQ,KAAK;IACb,QAAQ,KAAK,QAAQ;IACrB,QAAQ,KAAK,QAAQ;IACrB,MAAM,OAAO,kBAAkB;IAC/B,WAAW,OAAO;GACpB;EACF,GAAG,MAAM;CACX;;;;CAKA,MAAa,KAAK,MAAc,IAA2C;EACzE,MAAM,OAAO,MAAM,KAAK,KAAK,MAAM,EAAE;EACrC,MAAM,KAAK,OAAO,IAAI;EACtB,OAAO;CACT;;;;CAKA,MAAa,KAAK,WAAmB,SAAmD;EACtF,OAAO,KAAK,UAAU,YAAY;GAChC,MAAM,EAAE,yBAAyB;GAGjC,YAAY,KAAK,YAAY,SAAS;GAEtC,MAAM,UAAU,IAAI,qBAAqB;IACvC,QAAQ,KAAK,QAAQ;IACrB,QAAQ;IACR,SAAS,SAAS;IAClB,mBAAmB,SAAS;IAC5B,WAAW,SAAS,YAAY,SAAY;GAC9C,CAAC;GAED,MAAM,SAAS,MAAM,KAAK,OAAO,KAAK,OAAO;GAC7C,MAAM,QAA2B,CAAC;GAGlC,KAAK,MAAM,UAAU,OAAO,YAAY,CAAC,GAAG;IAC1C,IAAI,CAAC,OAAO,KAAK;IAEjB,MAAM,KAAK;KACT,MAAM,OAAO;KACb,MAAM,OAAO,IAAI,MAAM,GAAG,CAAC,CAAC,IAAI,KAAK;KACrC,MAAM,OAAO,QAAQ;KACrB,aAAa;KACb,cAAc,OAAO;KACrB,MAAM,OAAO;KACb,cAAc,OAAO;IACvB,CAAC;GACH;GAGA,KAAK,MAAM,UAAU,OAAO,kBAAkB,CAAC,GAAG;IAChD,IAAI,CAAC,OAAO,QAAQ;IAEpB,MAAM,KAAK;KACT,MAAM,OAAO;KACb,MAAM,OAAO,OAAO,MAAM,GAAG,CAAC,CAAC,OAAO,OAAO,CAAC,CAAC,IAAI,KAAK;KACxD,MAAM;KACN,aAAa;IACf,CAAC;GACH;GAEA,OAAO;EACT,GAAG,MAAM;CACX;;;;CASA,AAAO,YAAoB;EACzB,OAAO,KAAK,QAAQ;CACtB;;;;CAKA,AAAO,YAAoB;EACzB,OAAO,KAAK,QAAQ;CACtB;;;;CAKA,MAAa,gBAAgB,UAAkB,cAAqC;EAClF,OAAO,KAAK,UAAU,YAAY;GAChC,MAAM,EAAE,sBAAsB;GAG9B,WAAW,KAAK,YAAY,QAAQ;GAEpC,MAAM,UAAU,IAAI,kBAAkB;IACpC,QAAQ,KAAK,QAAQ;IACrB,YAAY,GAAG,KAAK,QAAQ,OAAO,GAAG;IACtC,KAAK;IACL,cAAc;IACd,mBAAmB;GACrB,CAAC;GAED,MAAM,KAAK,OAAO,KAAK,OAAO;EAChC,GAAG,iBAAiB;CACtB;;;;CAKA,MAAa,cAAc,UAAkB,YAA2C;EACtF,OAAO,KAAK,UAAU,YAAY;GAChC,MAAM,EAAE,wBAAwB;GAGhC,WAAW,KAAK,YAAY,QAAQ;GAEpC,MAAM,UAAU,IAAI,oBAAoB;IACtC,QAAQ,KAAK,QAAQ;IACrB,KAAK;IACL,KAAK,eAAe,WAAW,gBAAgB;GACjD,CAAC;GAED,MAAM,KAAK,OAAO,KAAK,OAAO;EAChC,GAAG,eAAe;CACpB;;;;CAKA,MAAa,cAAc,UAA2C;EACpE,OAAO,KAAK,UAAU,YAAY;GAChC,MAAM,EAAE,wBAAwB;GAGhC,WAAW,KAAK,YAAY,QAAQ;GAEpC,MAAM,UAAU,IAAI,oBAAoB;IACtC,QAAQ,KAAK,QAAQ;IACrB,KAAK;GACP,CAAC;GAWD,QANsB,MAHD,KAAK,OAAO,KAAK,OAAO,EAGjB,CAAC,QAAQ,MAClC,UACC,MAAM,SAAS,QAAQ,qDACvB,MAAM,eAAe,MACzB,IAEuB,WAAW;EACpC,GAAG,eAAe;CACpB;;;;CASA,AAAU,cAAc,QAAwB;EAC9C,OAAO,OAAO,WAAW,QAAQ,CAAC,CAAC,OAAO,IAAI,WAAW,MAAM,CAAC,CAAC,CAAC,OAAO,KAAK;CAChF;;;;CAKA,AAAU,cAAc,UAA0B;EAChD,OAAO,YAAY,QAAQ;CAC7B;AACF"}
@@ -1 +1 @@
1
- {"version":3,"file":"do-spaces-driver.d.mts","names":[],"sources":["../../../../../../../../core/src/storage/drivers/do-spaces-driver.ts"],"mappings":";;;;;;AA0BA;;;;;;;;;;;AAoB6B;;;;;;;;;cApBhB,cAAA,SAAuB,WAAW,CAAC,yBAAA;;;;WAI9B,IAAA;;;;;;YAON,WAAA,CAAA;;;;;;EASH,GAAA,CAAI,QAAA;AAAA"}
1
+ {"version":3,"file":"do-spaces-driver.d.mts","names":[],"sources":["../../../../../../../../core/src/storage/drivers/do-spaces-driver.ts"],"mappings":";;;;;;AA0BA;;;;;;;;;;;AAoB6B;;;;;;;;;cApBhB,cAAA,SAAuB,WAAW,CAAC,yBAAA;;;;WAI9B,IAAA;;;;;;YAON,WAAA;;;;;;EASH,GAAA,CAAI,QAAA;AAAA"}
@@ -1 +1 @@
1
- {"version":3,"file":"local-driver.d.mts","names":[],"sources":["../../../../../../../../core/src/storage/drivers/local-driver.ts"],"mappings":";;;;;;;;AA0CA;;;;;;cAAa,WAAA,YAAuB,qBAAA;EA+BR,OAAA,EAAS,yBAAA;EAmD3B;;;EAAA,SA9EQ,IAAA,EAAM,iBAAA;EAiFnB;;;EAAA,UA5EO,IAAA;EA6GP;;;EAAA,UAxGO,SAAA;EAoJgC;;;EAAA,UA/IhC,kBAAA;EAwMwC;;;EAAA,UAnMxC,YAAA;EA+Q0C;;;EAAA,UA1Q1C,SAAA,EAAS,GAAA,SAAA,eAAA;cAEO,OAAA,GAAS,yBAAA;EA6XU;;;;;;;;;EAtWtC,WAAA,CAAY,QAAA;EAkgBa;;;EAvenB,GAAA,CACX,IAAA,EAAM,MAAA,YAAkB,YAAA,EACxB,QAAA,UACA,OAAA,GAAU,UAAA,GACT,OAAA,CAAQ,eAAA;EArFuB;;;EAkHrB,SAAA,CACX,MAAA,EAAQ,QAAA,EACR,QAAA,UACA,OAAA,GAAU,UAAA,GACT,OAAA,CAAQ,eAAA;EAlHW;;;EAiJT,GAAA,CAAI,QAAA,WAAmB,OAAA,CAAQ,MAAA;EA7HlC;;;EA0IG,SAAA,CAAU,QAAA,WAAmB,OAAA,CAAQ,QAAA;;;;EAarC,MAAA,CAAO,QAAA,WAAmB,OAAA;EAzHpB;;;EA2IN,UAAA,CAAW,SAAA,aAAsB,OAAA,CAAQ,gBAAA;EA/GpD;;;;;;;EAyIW,eAAA,CAAgB,aAAA,WAAqB,OAAA;EAxGhD;;;EAmHW,MAAA,CAAO,QAAA,WAAmB,OAAA;EAhHpC;;;EA4HI,GAAA,CAAI,QAAA;EA7FyB;;;;;;;EAwGvB,YAAA,CAAa,QAAA,UAAkB,SAAA,YAAmB,OAAA;EA9ExB;;;;;;EAgGhC,oBAAA,CAAqB,QAAA,UAAkB,SAAA;EApDI;;;;;;EA4ErC,sBAAA,CAAuB,KAAA,WAAgB,OAAA,CAAQ,wBAAA;EA1ClC;;;EAsHb,QAAA,CAAS,QAAA,WAAmB,OAAA,CAAQ,eAAA;EApGrB;;;EAiIf,IAAA,CAAK,QAAA,WAAmB,OAAA;EAzGe;;;EAqHvC,IAAA,CAAK,IAAA,UAAc,EAAA,WAAa,OAAA,CAAQ,eAAA;EAzCZ;;;EAwE5B,IAAA,CAAK,IAAA,UAAc,EAAA,WAAa,OAAA,CAAQ,eAAA;EA3ChB;;;EA2ExB,IAAA,CAAK,SAAA,UAAmB,OAAA,GAAU,WAAA,GAAc,OAAA,CAAQ,eAAA;EA/DxB;;;EA+GtC,IAAA,CAAK,QAAA;EAhFoB;;;EAuFzB,OAAA,CAAA;EAvDW;;;;;;;EAAA,UAsER,eAAA,CAAgB,QAAA;EAAhB;;;EAAA,UAQM,QAAA,CAAS,IAAA,EAAM,MAAA,YAAkB,YAAA,GAAe,OAAA,CAAQ,MAAA;EAAvB;;;EAAA,UAevC,aAAA,CAAc,MAAA,EAAQ,MAAA;EAAtB;;;EAAA,UAOA,aAAA,CAAc,QAAA;AAAA"}
1
+ {"version":3,"file":"local-driver.d.mts","names":[],"sources":["../../../../../../../../core/src/storage/drivers/local-driver.ts"],"mappings":";;;;;;;;AA0CA;;;;;;cAAa,WAAA,YAAuB,qBAAA;EA+BR,OAAA,EAAS,yBAAA;EAmD3B;;;EAAA,SA9EQ,IAAA,EAAM,iBAAA;EAiFnB;;;EAAA,UA5EO,IAAA;EA6GP;;;EAAA,UAxGO,SAAA;EAoJgC;;;EAAA,UA/IhC,kBAAA;EAwMwC;;;EAAA,UAnMxC,YAAA;EA+Q0C;;;EAAA,UA1Q1C,SAAA,EAAS,GAAA,SAAA,eAAA;cAEO,OAAA,GAAS,yBAAA;EA6XU;;;;;;;;;EAtWtC,WAAA,CAAY,QAAA;EAkgBa;;;EAvenB,GAAA,CACX,IAAA,EAAM,MAAA,YAAkB,YAAA,EACxB,QAAA,UACA,OAAA,GAAU,UAAA,GACT,OAAA,CAAQ,eAAA;EArFuB;;;EAkHrB,SAAA,CACX,MAAA,EAAQ,QAAA,EACR,QAAA,UACA,OAAA,GAAU,UAAA,GACT,OAAA,CAAQ,eAAA;EAlHW;;;EAiJT,GAAA,CAAI,QAAA,WAAmB,OAAA,CAAQ,MAAA;EA7HlC;;;EA0IG,SAAA,CAAU,QAAA,WAAmB,OAAA,CAAQ,QAAA;;;;EAarC,MAAA,CAAO,QAAA,WAAmB,OAAA;EAzHpB;;;EA2IN,UAAA,CAAW,SAAA,aAAsB,OAAA,CAAQ,gBAAA;EA/GpD;;;;;;;EAyIW,eAAA,CAAgB,aAAA,WAAqB,OAAA;EAxGhD;;;EAmHW,MAAA,CAAO,QAAA,WAAmB,OAAA;EAhHpC;;;EA4HI,GAAA,CAAI,QAAA;EA7FyB;;;;;;;EAwGvB,YAAA,CAAa,QAAA,UAAkB,SAAA,YAAmB,OAAA;EA9ExB;;;;;;EAgGhC,oBAAA,CAAqB,QAAA,UAAkB,SAAA;EApDI;;;;;;EA4ErC,sBAAA,CAAuB,KAAA,WAAgB,OAAA,CAAQ,wBAAA;EA1ClC;;;EAsHb,QAAA,CAAS,QAAA,WAAmB,OAAA,CAAQ,eAAA;EApGrB;;;EAiIf,IAAA,CAAK,QAAA,WAAmB,OAAA;EAzGe;;;EAqHvC,IAAA,CAAK,IAAA,UAAc,EAAA,WAAa,OAAA,CAAQ,eAAA;EAzCZ;;;EAwE5B,IAAA,CAAK,IAAA,UAAc,EAAA,WAAa,OAAA,CAAQ,eAAA;EA3ChB;;;EA2ExB,IAAA,CAAK,SAAA,UAAmB,OAAA,GAAU,WAAA,GAAc,OAAA,CAAQ,eAAA;EA/DxB;;;EA+GtC,IAAA,CAAK,QAAA;EAhFoB;;;EAuFzB,OAAA;EAvDW;;;;;;;EAAA,UAsER,eAAA,CAAgB,QAAA;EAAhB;;;EAAA,UAQM,QAAA,CAAS,IAAA,EAAM,MAAA,YAAkB,YAAA,GAAe,OAAA,CAAQ,MAAA;EAAvB;;;EAAA,UAevC,aAAA,CAAc,MAAA,EAAQ,MAAA;EAAtB;;;EAAA,UAOA,aAAA,CAAc,QAAA;AAAA"}
@@ -1 +1 @@
1
- {"version":3,"file":"local-driver.mjs","names":[],"sources":["../../../../../../../../core/src/storage/drivers/local-driver.ts"],"sourcesContent":["import {\n directoryExistsAsync,\n ensureDirectoryAsync,\n fileExistsAsync,\n removeDirectoryAsync,\n unlinkAsync,\n} from \"@warlock.js/fs\";\nimport { ltrim } from \"@mongez/reinforcements\";\nimport crypto from \"crypto\";\nimport { createReadStream, createWriteStream } from \"fs\";\nimport { copyFile, readFile, readdir, rename, stat, writeFile } from \"fs/promises\";\nimport { dirname, join, resolve } from \"path\";\nimport type { Readable } from \"stream\";\nimport { pipeline } from \"stream/promises\";\nimport { UploadedFile } from \"../../http\";\nimport { storagePath } from \"../../utils/paths\";\nimport { url } from \"../../utils/urls\";\nimport { storageDriverContext } from \"../context/storage-driver-context\";\nimport { resolveWithinRoot } from \"../utils/contain-path\";\nimport type {\n DeleteManyResult,\n ListOptions,\n LocalStorageDriverOptions,\n PutOptions,\n StorageDriverContract,\n StorageDriverType,\n StorageFileData,\n StorageFileInfo,\n TemporaryTokenPayload,\n TemporaryTokenValidation,\n} from \"../types\";\nimport { getMimeType } from \"../utils/mime\";\n\n/**\n * Local filesystem storage driver\n *\n * Stores files on the local filesystem with support for:\n * - File operations (put, get, delete, copy, move)\n * - Stream operations for large files\n * - Batch operations\n * - Signed temporary URLs\n */\nexport class LocalDriver implements StorageDriverContract {\n /**\n * Driver name\n */\n public readonly name: StorageDriverType = \"local\";\n\n /**\n * Root path for storage\n */\n protected root: string;\n\n /**\n * URL prefix for file URLs\n */\n protected urlPrefix: string = \"\";\n\n /**\n * URL prefix for temporary file URLs\n */\n protected temporaryUrlPrefix: string;\n\n /**\n * Secret key for signing temporary URLs\n */\n protected signatureKey?: string;\n\n /**\n * Cached Storage File Metadata\n */\n protected _metadata = new Map<string, StorageFileInfo>();\n\n public constructor(public options: LocalStorageDriverOptions = {}) {\n // Resolve the root to an absolute, normalized path up front so the\n // path-traversal containment check (resolveWithinRoot) has a stable\n // anchor to compare resolved locations against.\n this.root = resolve(options.root ?? storagePath());\n this.urlPrefix = options.urlPrefix ?? \"\";\n this.temporaryUrlPrefix = options.temporaryUrlPrefix ?? \"/temp-files\";\n this.signatureKey = options.signatureKey;\n }\n\n // ============================================================\n // Prefix Operations\n // ============================================================\n\n /**\n * Apply prefix to location path\n *\n * Priority: context prefix > driver options prefix > no prefix\n * This allows multi-tenant scenarios where context overrides driver config.\n *\n * @param location - Original location path\n * @returns Location with prefix applied if one exists\n */\n public applyPrefix(location: string): string {\n // Check context prefix first (highest priority)\n const contextPrefix = storageDriverContext.getPrefix();\n const prefix = contextPrefix || this.options.prefix;\n\n if (!prefix) {\n return location;\n }\n\n const cleanPrefix = prefix.replace(/\\/+$/, \"\");\n const cleanLocation = location.replace(/^\\/+/, \"\");\n\n // Avoid double-prefixing\n if (cleanLocation.startsWith(cleanPrefix + \"/\") || cleanLocation === cleanPrefix) {\n return cleanLocation;\n }\n\n return `${cleanPrefix}/${cleanLocation}`;\n }\n\n // ============================================================\n // Core File Operations\n // ============================================================\n\n /**\n * Put file to local storage\n */\n public async put(\n file: Buffer | string | UploadedFile,\n location: string,\n options?: PutOptions,\n ): Promise<StorageFileData> {\n const absolutePath = this.getAbsolutePath(location);\n\n await ensureDirectoryAsync(dirname(absolutePath));\n\n const fileBuffer = await this.toBuffer(file);\n const hash = this.calculateHash(fileBuffer);\n\n await writeFile(absolutePath, new Uint8Array(fileBuffer));\n\n // Invalidate any stale cached metadata for this location.\n this._metadata.delete(location);\n\n const stats = await stat(absolutePath);\n const mimeType = options?.mimeType || this.guessMimeType(location);\n\n return {\n path: location,\n url: this.url(location),\n size: stats.size,\n hash,\n mimeType,\n driver: this.name,\n };\n }\n\n /**\n * Put file from a readable stream (for large files)\n */\n public async putStream(\n stream: Readable,\n location: string,\n options?: PutOptions,\n ): Promise<StorageFileData> {\n const absolutePath = this.getAbsolutePath(location);\n\n await ensureDirectoryAsync(dirname(absolutePath));\n\n // Create write stream and pipe\n const writeStream = createWriteStream(absolutePath);\n await pipeline(stream, writeStream);\n\n // Invalidate any stale cached metadata for this location.\n this._metadata.delete(location);\n\n // Calculate hash and get stats\n const fileBuffer = await readFile(absolutePath);\n const hash = this.calculateHash(fileBuffer);\n const stats = await stat(absolutePath);\n const mimeType = options?.mimeType || this.guessMimeType(location);\n\n return {\n path: location,\n url: this.url(location),\n size: stats.size,\n hash,\n mimeType,\n driver: this.name,\n };\n }\n\n /**\n * Get file contents as Buffer\n */\n public async get(location: string): Promise<Buffer> {\n const absolutePath = this.getAbsolutePath(location);\n\n if (!(await fileExistsAsync(absolutePath))) {\n throw new Error(`File not found: ${location}`);\n }\n\n return readFile(absolutePath);\n }\n\n /**\n * Get file as a readable stream (for large files)\n */\n public async getStream(location: string): Promise<Readable> {\n const absolutePath = this.getAbsolutePath(location);\n\n if (!(await fileExistsAsync(absolutePath))) {\n throw new Error(`File not found: ${location}`);\n }\n\n return createReadStream(absolutePath);\n }\n\n /**\n * Delete a file\n */\n public async delete(location: string): Promise<boolean> {\n const absolutePath = this.getAbsolutePath(location);\n\n if (!(await fileExistsAsync(absolutePath))) {\n return false;\n }\n\n await unlinkAsync(absolutePath);\n\n // Invalidate any stale cached metadata for this location.\n this._metadata.delete(location);\n\n return true;\n }\n\n /**\n * Delete multiple files at once\n */\n public async deleteMany(locations: string[]): Promise<DeleteManyResult[]> {\n const results: DeleteManyResult[] = [];\n\n for (const location of locations) {\n try {\n const deleted = await this.delete(location);\n results.push({ location, deleted });\n } catch (error) {\n results.push({\n location,\n deleted: false,\n error: error instanceof Error ? error.message : \"Unknown error\",\n });\n }\n }\n\n return results;\n }\n\n /**\n * Delete directory\n *\n * The directory path is resolved through {@link getAbsolutePath} so it is\n * contained within the storage root — the raw, caller-supplied argument is\n * never handed to the filesystem (preventing `../` traversal deletes).\n */\n public async deleteDirectory(directoryPath: string) {\n const absolutePath = this.getAbsolutePath(directoryPath);\n\n await removeDirectoryAsync(absolutePath);\n\n return true;\n }\n\n /**\n * Check if file exists\n */\n public async exists(location: string): Promise<boolean> {\n const absolutePath = this.getAbsolutePath(location);\n return Boolean(await fileExistsAsync(absolutePath));\n }\n\n // ============================================================\n // URL Operations\n // ============================================================\n\n /**\n * Get public URL for file\n */\n public url(location: string): string {\n return url(this.urlPrefix + \"/\" + ltrim(location, \"/\"));\n }\n\n /**\n * Get a temporary signed URL that expires\n * Returns a clean URL with encoded token: {temporaryUrlPrefix}/{token}\n *\n * @param location - File path\n * @param expiresIn - Seconds until expiration (default: 3600)\n */\n public async temporaryUrl(location: string, expiresIn = 3600): Promise<string> {\n if (!this.signatureKey) {\n throw new Error(\n \"Temporary URLs require a signatureKey in LocalDriver options. \" +\n \"Configure storage.drivers.local.signatureKey in your config.\",\n );\n }\n\n const token = this.encodeTemporaryToken(location, expiresIn);\n return `${this.temporaryUrlPrefix}/${token}`;\n }\n\n /**\n * Encode a temporary token containing path, expiry, and signature\n *\n * @param location - File path\n * @param expiresIn - Seconds until expiration\n */\n public encodeTemporaryToken(location: string, expiresIn: number): string {\n if (!this.signatureKey) {\n throw new Error(\"Temporary tokens require a signatureKey\");\n }\n\n const exp = Math.floor(Date.now() / 1000) + expiresIn;\n const sig = crypto\n .createHmac(\"sha256\", this.signatureKey)\n .update(`${location}:${exp}`)\n .digest(\"hex\");\n\n const payload: TemporaryTokenPayload = { path: location, exp, sig };\n const json = JSON.stringify(payload);\n\n // Use base64url encoding (URL-safe base64)\n return Buffer.from(json).toString(\"base64url\");\n }\n\n /**\n * Validate a temporary URL token\n * Returns a result object with validation status, file info, and convenience methods\n *\n * @param token - The token from the URL\n */\n public async validateTemporaryToken(token: string): Promise<TemporaryTokenValidation> {\n // Check signature key\n if (!this.signatureKey) {\n return { valid: false, error: \"missing_key\" };\n }\n\n // Decode token\n let payload: TemporaryTokenPayload;\n try {\n const json = Buffer.from(token, \"base64url\").toString(\"utf-8\");\n payload = JSON.parse(json);\n } catch {\n return { valid: false, error: \"invalid_token\" };\n }\n\n // Validate payload structure\n if (!payload.path || !payload.exp || !payload.sig) {\n return { valid: false, error: \"invalid_token\" };\n }\n\n // Check expiration\n const now = Math.floor(Date.now() / 1000);\n if (payload.exp < now) {\n return { valid: false, error: \"expired\" };\n }\n\n // Verify signature\n const expectedSig = crypto\n .createHmac(\"sha256\", this.signatureKey)\n .update(`${payload.path}:${payload.exp}`)\n .digest(\"hex\");\n\n const sigBuffer = Buffer.from(payload.sig, \"hex\");\n const expectedBuffer = Buffer.from(expectedSig, \"hex\");\n\n if (sigBuffer.length !== expectedBuffer.length) {\n return { valid: false, error: \"invalid_signature\" };\n }\n\n const isValidSig = crypto.timingSafeEqual(\n new Uint8Array(sigBuffer),\n new Uint8Array(expectedBuffer),\n );\n\n if (!isValidSig) {\n return { valid: false, error: \"invalid_signature\" };\n }\n\n // Check file exists\n const absolutePath = this.getAbsolutePath(payload.path);\n if (!(await fileExistsAsync(absolutePath))) {\n return { valid: false, error: \"file_not_found\" };\n }\n\n // Build successful result with convenience methods\n const result: TemporaryTokenValidation = {\n valid: true,\n path: payload.path,\n absolutePath,\n expiresAt: new Date(payload.exp * 1000),\n mimeType: this.guessMimeType(payload.path),\n driver: this,\n getFile: () => this.get(payload.path),\n getStream: () => this.getStream(payload.path),\n };\n\n return result;\n }\n\n // ============================================================\n // Metadata Operations\n // ============================================================\n\n /**\n * Get file info/metadata without downloading\n */\n public async metadata(location: string): Promise<StorageFileInfo> {\n if (this._metadata.has(location)) {\n return this._metadata.get(location)!;\n }\n\n const absolutePath = this.getAbsolutePath(location);\n\n if (!(await fileExistsAsync(absolutePath))) {\n throw new Error(`File not found: ${absolutePath}`);\n }\n\n const stats = await stat(absolutePath);\n const name = location.split(\"/\").pop() || \"\";\n\n this._metadata.set(location, {\n path: location,\n name,\n size: stats.size,\n isDirectory: stats.isDirectory(),\n lastModified: stats.mtime,\n mimeType: this.guessMimeType(location),\n });\n\n return this._metadata.get(location)!;\n }\n\n /**\n * Get file size in bytes (shortcut for metadata().size)\n */\n public async size(location: string): Promise<number> {\n const metadata = await this.metadata(location);\n return metadata.size;\n }\n\n // ============================================================\n // File Operations\n // ============================================================\n\n /**\n * Copy file to a new location\n */\n public async copy(from: string, to: string): Promise<StorageFileData> {\n const fromPath = this.getAbsolutePath(from);\n const toPath = this.getAbsolutePath(to);\n\n if (!(await fileExistsAsync(fromPath))) {\n throw new Error(`Source file not found: ${from}`);\n }\n\n await ensureDirectoryAsync(dirname(toPath));\n await copyFile(fromPath, toPath);\n\n // Invalidate any stale cached metadata for the destination.\n this._metadata.delete(to);\n\n const fileBuffer = await readFile(toPath);\n const hash = this.calculateHash(fileBuffer);\n const stats = await stat(toPath);\n\n return {\n path: to,\n url: this.url(to),\n size: stats.size,\n hash,\n mimeType: this.guessMimeType(to),\n driver: this.name,\n };\n }\n\n /**\n * Move file to a new location\n */\n public async move(from: string, to: string): Promise<StorageFileData> {\n const fromPath = this.getAbsolutePath(from);\n const toPath = this.getAbsolutePath(to);\n\n if (!(await fileExistsAsync(fromPath))) {\n throw new Error(`Source file not found: ${from}`);\n }\n\n await ensureDirectoryAsync(dirname(toPath));\n await rename(fromPath, toPath);\n\n // Invalidate any stale cached metadata for both source and destination.\n this._metadata.delete(from);\n this._metadata.delete(to);\n\n const fileBuffer = await readFile(toPath);\n const hash = this.calculateHash(fileBuffer);\n const stats = await stat(toPath);\n\n return {\n path: to,\n url: this.url(to),\n size: stats.size,\n hash,\n mimeType: this.guessMimeType(to),\n driver: this.name,\n };\n }\n\n /**\n * List files in a directory\n */\n public async list(directory: string, options?: ListOptions): Promise<StorageFileInfo[]> {\n const absolutePath = this.getAbsolutePath(directory);\n const files: StorageFileInfo[] = [];\n\n // A listing target is a DIRECTORY, so guard with `directoryExistsAsync`.\n // `fileExistsAsync` resolves `false` for a folder, which would make `list`\n // always return [] for a real, populated directory.\n if (!(await directoryExistsAsync(absolutePath))) {\n return files;\n }\n\n const entries = await readdir(absolutePath, { withFileTypes: true });\n\n for (const entry of entries) {\n const entryPath = join(directory, entry.name);\n const entryStats = await stat(this.getAbsolutePath(entryPath));\n\n files.push({\n path: entryPath,\n name: entry.name,\n size: entryStats.size,\n isDirectory: entry.isDirectory(),\n lastModified: entryStats.mtime,\n mimeType: entry.isFile() ? this.guessMimeType(entry.name) : undefined,\n });\n\n // Recursively list subdirectories if requested\n if (options?.recursive && entry.isDirectory()) {\n const subFiles = await this.list(entryPath, options);\n files.push(...subFiles);\n }\n\n // Respect limit\n if (options?.limit && files.length >= options.limit) {\n break;\n }\n }\n\n return files;\n }\n\n // ============================================================\n // Path Operations\n // ============================================================\n\n /**\n * Get absolute filesystem path for a location\n */\n public path(location: string): string {\n return this.getAbsolutePath(location);\n }\n\n /**\n * Get the storage root directory\n */\n public getRoot(): string {\n return this.root;\n }\n\n // ============================================================\n // Utilities\n // ============================================================\n\n /**\n * Get absolute file path\n *\n * Routes through {@link resolveWithinRoot} so a location can never escape\n * the configured storage root via `..` traversal, an absolute path, or a\n * prefix breakout.\n */\n protected getAbsolutePath(location: string): string {\n const prefixedLocation = this.applyPrefix(location);\n return resolveWithinRoot(this.root, prefixedLocation);\n }\n\n /**\n * Convert various input types to Buffer\n */\n protected async toBuffer(file: Buffer | string | UploadedFile): Promise<Buffer> {\n if (Buffer.isBuffer(file)) {\n return file;\n }\n\n if (typeof file === \"string\") {\n return readFile(file);\n }\n\n return file.buffer();\n }\n\n /**\n * Calculate SHA-256 hash\n */\n protected calculateHash(buffer: Buffer): string {\n return crypto.createHash(\"sha256\").update(new Uint8Array(buffer)).digest(\"hex\");\n }\n\n /**\n * Guess MIME type from file extension\n */\n protected guessMimeType(location: string): string {\n return getMimeType(location);\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"local-driver.mjs","names":[],"sources":["../../../../../../../../core/src/storage/drivers/local-driver.ts"],"sourcesContent":["import {\n directoryExistsAsync,\n ensureDirectoryAsync,\n fileExistsAsync,\n removeDirectoryAsync,\n unlinkAsync,\n} from \"@warlock.js/fs\";\nimport { ltrim } from \"@mongez/reinforcements\";\nimport crypto from \"crypto\";\nimport { createReadStream, createWriteStream } from \"fs\";\nimport { copyFile, readFile, readdir, rename, stat, writeFile } from \"fs/promises\";\nimport { dirname, join, resolve } from \"path\";\nimport type { Readable } from \"stream\";\nimport { pipeline } from \"stream/promises\";\nimport { UploadedFile } from \"../../http\";\nimport { storagePath } from \"../../utils/paths\";\nimport { url } from \"../../utils/urls\";\nimport { storageDriverContext } from \"../context/storage-driver-context\";\nimport { resolveWithinRoot } from \"../utils/contain-path\";\nimport type {\n DeleteManyResult,\n ListOptions,\n LocalStorageDriverOptions,\n PutOptions,\n StorageDriverContract,\n StorageDriverType,\n StorageFileData,\n StorageFileInfo,\n TemporaryTokenPayload,\n TemporaryTokenValidation,\n} from \"../types\";\nimport { getMimeType } from \"../utils/mime\";\n\n/**\n * Local filesystem storage driver\n *\n * Stores files on the local filesystem with support for:\n * - File operations (put, get, delete, copy, move)\n * - Stream operations for large files\n * - Batch operations\n * - Signed temporary URLs\n */\nexport class LocalDriver implements StorageDriverContract {\n /**\n * Driver name\n */\n public readonly name: StorageDriverType = \"local\";\n\n /**\n * Root path for storage\n */\n protected root: string;\n\n /**\n * URL prefix for file URLs\n */\n protected urlPrefix: string = \"\";\n\n /**\n * URL prefix for temporary file URLs\n */\n protected temporaryUrlPrefix: string;\n\n /**\n * Secret key for signing temporary URLs\n */\n protected signatureKey?: string;\n\n /**\n * Cached Storage File Metadata\n */\n protected _metadata = new Map<string, StorageFileInfo>();\n\n public constructor(public options: LocalStorageDriverOptions = {}) {\n // Resolve the root to an absolute, normalized path up front so the\n // path-traversal containment check (resolveWithinRoot) has a stable\n // anchor to compare resolved locations against.\n this.root = resolve(options.root ?? storagePath());\n this.urlPrefix = options.urlPrefix ?? \"\";\n this.temporaryUrlPrefix = options.temporaryUrlPrefix ?? \"/temp-files\";\n this.signatureKey = options.signatureKey;\n }\n\n // ============================================================\n // Prefix Operations\n // ============================================================\n\n /**\n * Apply prefix to location path\n *\n * Priority: context prefix > driver options prefix > no prefix\n * This allows multi-tenant scenarios where context overrides driver config.\n *\n * @param location - Original location path\n * @returns Location with prefix applied if one exists\n */\n public applyPrefix(location: string): string {\n // Check context prefix first (highest priority)\n const contextPrefix = storageDriverContext.getPrefix();\n const prefix = contextPrefix || this.options.prefix;\n\n if (!prefix) {\n return location;\n }\n\n const cleanPrefix = prefix.replace(/\\/+$/, \"\");\n const cleanLocation = location.replace(/^\\/+/, \"\");\n\n // Avoid double-prefixing\n if (cleanLocation.startsWith(cleanPrefix + \"/\") || cleanLocation === cleanPrefix) {\n return cleanLocation;\n }\n\n return `${cleanPrefix}/${cleanLocation}`;\n }\n\n // ============================================================\n // Core File Operations\n // ============================================================\n\n /**\n * Put file to local storage\n */\n public async put(\n file: Buffer | string | UploadedFile,\n location: string,\n options?: PutOptions,\n ): Promise<StorageFileData> {\n const absolutePath = this.getAbsolutePath(location);\n\n await ensureDirectoryAsync(dirname(absolutePath));\n\n const fileBuffer = await this.toBuffer(file);\n const hash = this.calculateHash(fileBuffer);\n\n await writeFile(absolutePath, new Uint8Array(fileBuffer));\n\n // Invalidate any stale cached metadata for this location.\n this._metadata.delete(location);\n\n const stats = await stat(absolutePath);\n const mimeType = options?.mimeType || this.guessMimeType(location);\n\n return {\n path: location,\n url: this.url(location),\n size: stats.size,\n hash,\n mimeType,\n driver: this.name,\n };\n }\n\n /**\n * Put file from a readable stream (for large files)\n */\n public async putStream(\n stream: Readable,\n location: string,\n options?: PutOptions,\n ): Promise<StorageFileData> {\n const absolutePath = this.getAbsolutePath(location);\n\n await ensureDirectoryAsync(dirname(absolutePath));\n\n // Create write stream and pipe\n const writeStream = createWriteStream(absolutePath);\n await pipeline(stream, writeStream);\n\n // Invalidate any stale cached metadata for this location.\n this._metadata.delete(location);\n\n // Calculate hash and get stats\n const fileBuffer = await readFile(absolutePath);\n const hash = this.calculateHash(fileBuffer);\n const stats = await stat(absolutePath);\n const mimeType = options?.mimeType || this.guessMimeType(location);\n\n return {\n path: location,\n url: this.url(location),\n size: stats.size,\n hash,\n mimeType,\n driver: this.name,\n };\n }\n\n /**\n * Get file contents as Buffer\n */\n public async get(location: string): Promise<Buffer> {\n const absolutePath = this.getAbsolutePath(location);\n\n if (!(await fileExistsAsync(absolutePath))) {\n throw new Error(`File not found: ${location}`);\n }\n\n return readFile(absolutePath);\n }\n\n /**\n * Get file as a readable stream (for large files)\n */\n public async getStream(location: string): Promise<Readable> {\n const absolutePath = this.getAbsolutePath(location);\n\n if (!(await fileExistsAsync(absolutePath))) {\n throw new Error(`File not found: ${location}`);\n }\n\n return createReadStream(absolutePath);\n }\n\n /**\n * Delete a file\n */\n public async delete(location: string): Promise<boolean> {\n const absolutePath = this.getAbsolutePath(location);\n\n if (!(await fileExistsAsync(absolutePath))) {\n return false;\n }\n\n await unlinkAsync(absolutePath);\n\n // Invalidate any stale cached metadata for this location.\n this._metadata.delete(location);\n\n return true;\n }\n\n /**\n * Delete multiple files at once\n */\n public async deleteMany(locations: string[]): Promise<DeleteManyResult[]> {\n const results: DeleteManyResult[] = [];\n\n for (const location of locations) {\n try {\n const deleted = await this.delete(location);\n results.push({ location, deleted });\n } catch (error) {\n results.push({\n location,\n deleted: false,\n error: error instanceof Error ? error.message : \"Unknown error\",\n });\n }\n }\n\n return results;\n }\n\n /**\n * Delete directory\n *\n * The directory path is resolved through {@link getAbsolutePath} so it is\n * contained within the storage root — the raw, caller-supplied argument is\n * never handed to the filesystem (preventing `../` traversal deletes).\n */\n public async deleteDirectory(directoryPath: string) {\n const absolutePath = this.getAbsolutePath(directoryPath);\n\n await removeDirectoryAsync(absolutePath);\n\n return true;\n }\n\n /**\n * Check if file exists\n */\n public async exists(location: string): Promise<boolean> {\n const absolutePath = this.getAbsolutePath(location);\n return Boolean(await fileExistsAsync(absolutePath));\n }\n\n // ============================================================\n // URL Operations\n // ============================================================\n\n /**\n * Get public URL for file\n */\n public url(location: string): string {\n return url(this.urlPrefix + \"/\" + ltrim(location, \"/\"));\n }\n\n /**\n * Get a temporary signed URL that expires\n * Returns a clean URL with encoded token: {temporaryUrlPrefix}/{token}\n *\n * @param location - File path\n * @param expiresIn - Seconds until expiration (default: 3600)\n */\n public async temporaryUrl(location: string, expiresIn = 3600): Promise<string> {\n if (!this.signatureKey) {\n throw new Error(\n \"Temporary URLs require a signatureKey in LocalDriver options. \" +\n \"Configure storage.drivers.local.signatureKey in your config.\",\n );\n }\n\n const token = this.encodeTemporaryToken(location, expiresIn);\n return `${this.temporaryUrlPrefix}/${token}`;\n }\n\n /**\n * Encode a temporary token containing path, expiry, and signature\n *\n * @param location - File path\n * @param expiresIn - Seconds until expiration\n */\n public encodeTemporaryToken(location: string, expiresIn: number): string {\n if (!this.signatureKey) {\n throw new Error(\"Temporary tokens require a signatureKey\");\n }\n\n const exp = Math.floor(Date.now() / 1000) + expiresIn;\n const sig = crypto\n .createHmac(\"sha256\", this.signatureKey)\n .update(`${location}:${exp}`)\n .digest(\"hex\");\n\n const payload: TemporaryTokenPayload = { path: location, exp, sig };\n const json = JSON.stringify(payload);\n\n // Use base64url encoding (URL-safe base64)\n return Buffer.from(json).toString(\"base64url\");\n }\n\n /**\n * Validate a temporary URL token\n * Returns a result object with validation status, file info, and convenience methods\n *\n * @param token - The token from the URL\n */\n public async validateTemporaryToken(token: string): Promise<TemporaryTokenValidation> {\n // Check signature key\n if (!this.signatureKey) {\n return { valid: false, error: \"missing_key\" };\n }\n\n // Decode token\n let payload: TemporaryTokenPayload;\n try {\n const json = Buffer.from(token, \"base64url\").toString(\"utf-8\");\n payload = JSON.parse(json);\n } catch {\n return { valid: false, error: \"invalid_token\" };\n }\n\n // Validate payload structure\n if (!payload.path || !payload.exp || !payload.sig) {\n return { valid: false, error: \"invalid_token\" };\n }\n\n // Check expiration\n const now = Math.floor(Date.now() / 1000);\n if (payload.exp < now) {\n return { valid: false, error: \"expired\" };\n }\n\n // Verify signature\n const expectedSig = crypto\n .createHmac(\"sha256\", this.signatureKey)\n .update(`${payload.path}:${payload.exp}`)\n .digest(\"hex\");\n\n const sigBuffer = Buffer.from(payload.sig, \"hex\");\n const expectedBuffer = Buffer.from(expectedSig, \"hex\");\n\n if (sigBuffer.length !== expectedBuffer.length) {\n return { valid: false, error: \"invalid_signature\" };\n }\n\n const isValidSig = crypto.timingSafeEqual(\n new Uint8Array(sigBuffer),\n new Uint8Array(expectedBuffer),\n );\n\n if (!isValidSig) {\n return { valid: false, error: \"invalid_signature\" };\n }\n\n // Check file exists\n const absolutePath = this.getAbsolutePath(payload.path);\n if (!(await fileExistsAsync(absolutePath))) {\n return { valid: false, error: \"file_not_found\" };\n }\n\n // Build successful result with convenience methods\n const result: TemporaryTokenValidation = {\n valid: true,\n path: payload.path,\n absolutePath,\n expiresAt: new Date(payload.exp * 1000),\n mimeType: this.guessMimeType(payload.path),\n driver: this,\n getFile: () => this.get(payload.path),\n getStream: () => this.getStream(payload.path),\n };\n\n return result;\n }\n\n // ============================================================\n // Metadata Operations\n // ============================================================\n\n /**\n * Get file info/metadata without downloading\n */\n public async metadata(location: string): Promise<StorageFileInfo> {\n if (this._metadata.has(location)) {\n return this._metadata.get(location)!;\n }\n\n const absolutePath = this.getAbsolutePath(location);\n\n if (!(await fileExistsAsync(absolutePath))) {\n throw new Error(`File not found: ${absolutePath}`);\n }\n\n const stats = await stat(absolutePath);\n const name = location.split(\"/\").pop() || \"\";\n\n this._metadata.set(location, {\n path: location,\n name,\n size: stats.size,\n isDirectory: stats.isDirectory(),\n lastModified: stats.mtime,\n mimeType: this.guessMimeType(location),\n });\n\n return this._metadata.get(location)!;\n }\n\n /**\n * Get file size in bytes (shortcut for metadata().size)\n */\n public async size(location: string): Promise<number> {\n const metadata = await this.metadata(location);\n return metadata.size;\n }\n\n // ============================================================\n // File Operations\n // ============================================================\n\n /**\n * Copy file to a new location\n */\n public async copy(from: string, to: string): Promise<StorageFileData> {\n const fromPath = this.getAbsolutePath(from);\n const toPath = this.getAbsolutePath(to);\n\n if (!(await fileExistsAsync(fromPath))) {\n throw new Error(`Source file not found: ${from}`);\n }\n\n await ensureDirectoryAsync(dirname(toPath));\n await copyFile(fromPath, toPath);\n\n // Invalidate any stale cached metadata for the destination.\n this._metadata.delete(to);\n\n const fileBuffer = await readFile(toPath);\n const hash = this.calculateHash(fileBuffer);\n const stats = await stat(toPath);\n\n return {\n path: to,\n url: this.url(to),\n size: stats.size,\n hash,\n mimeType: this.guessMimeType(to),\n driver: this.name,\n };\n }\n\n /**\n * Move file to a new location\n */\n public async move(from: string, to: string): Promise<StorageFileData> {\n const fromPath = this.getAbsolutePath(from);\n const toPath = this.getAbsolutePath(to);\n\n if (!(await fileExistsAsync(fromPath))) {\n throw new Error(`Source file not found: ${from}`);\n }\n\n await ensureDirectoryAsync(dirname(toPath));\n await rename(fromPath, toPath);\n\n // Invalidate any stale cached metadata for both source and destination.\n this._metadata.delete(from);\n this._metadata.delete(to);\n\n const fileBuffer = await readFile(toPath);\n const hash = this.calculateHash(fileBuffer);\n const stats = await stat(toPath);\n\n return {\n path: to,\n url: this.url(to),\n size: stats.size,\n hash,\n mimeType: this.guessMimeType(to),\n driver: this.name,\n };\n }\n\n /**\n * List files in a directory\n */\n public async list(directory: string, options?: ListOptions): Promise<StorageFileInfo[]> {\n const absolutePath = this.getAbsolutePath(directory);\n const files: StorageFileInfo[] = [];\n\n // A listing target is a DIRECTORY, so guard with `directoryExistsAsync`.\n // `fileExistsAsync` resolves `false` for a folder, which would make `list`\n // always return [] for a real, populated directory.\n if (!(await directoryExistsAsync(absolutePath))) {\n return files;\n }\n\n const entries = await readdir(absolutePath, { withFileTypes: true });\n\n for (const entry of entries) {\n const entryPath = join(directory, entry.name);\n const entryStats = await stat(this.getAbsolutePath(entryPath));\n\n files.push({\n path: entryPath,\n name: entry.name,\n size: entryStats.size,\n isDirectory: entry.isDirectory(),\n lastModified: entryStats.mtime,\n mimeType: entry.isFile() ? this.guessMimeType(entry.name) : undefined,\n });\n\n // Recursively list subdirectories if requested\n if (options?.recursive && entry.isDirectory()) {\n const subFiles = await this.list(entryPath, options);\n files.push(...subFiles);\n }\n\n // Respect limit\n if (options?.limit && files.length >= options.limit) {\n break;\n }\n }\n\n return files;\n }\n\n // ============================================================\n // Path Operations\n // ============================================================\n\n /**\n * Get absolute filesystem path for a location\n */\n public path(location: string): string {\n return this.getAbsolutePath(location);\n }\n\n /**\n * Get the storage root directory\n */\n public getRoot(): string {\n return this.root;\n }\n\n // ============================================================\n // Utilities\n // ============================================================\n\n /**\n * Get absolute file path\n *\n * Routes through {@link resolveWithinRoot} so a location can never escape\n * the configured storage root via `..` traversal, an absolute path, or a\n * prefix breakout.\n */\n protected getAbsolutePath(location: string): string {\n const prefixedLocation = this.applyPrefix(location);\n return resolveWithinRoot(this.root, prefixedLocation);\n }\n\n /**\n * Convert various input types to Buffer\n */\n protected async toBuffer(file: Buffer | string | UploadedFile): Promise<Buffer> {\n if (Buffer.isBuffer(file)) {\n return file;\n }\n\n if (typeof file === \"string\") {\n return readFile(file);\n }\n\n return file.buffer();\n }\n\n /**\n * Calculate SHA-256 hash\n */\n protected calculateHash(buffer: Buffer): string {\n return crypto.createHash(\"sha256\").update(new Uint8Array(buffer)).digest(\"hex\");\n }\n\n /**\n * Guess MIME type from file extension\n */\n protected guessMimeType(location: string): string {\n return getMimeType(location);\n }\n}\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"r2-driver.d.mts","names":[],"sources":["../../../../../../../../core/src/storage/drivers/r2-driver.ts"],"mappings":";;;;;;AA0BA;;;;;;;;;;;AAwB6B;;;;;;;;;cAxBhB,QAAA,SAAiB,WAAW,CAAC,sBAAA;;;;WAIxB,IAAA;;;;;;YAON,WAAA,CAAA;;;;;;;;;;EAaH,GAAA,CAAI,QAAA;AAAA"}
1
+ {"version":3,"file":"r2-driver.d.mts","names":[],"sources":["../../../../../../../../core/src/storage/drivers/r2-driver.ts"],"mappings":";;;;;;AA0BA;;;;;;;;;;;AAwB6B;;;;;;;;;cAxBhB,QAAA,SAAiB,WAAW,CAAC,sBAAA;;;;WAIxB,IAAA;;;;;;YAON,WAAA;;;;;;;;;;EAaH,GAAA,CAAI,QAAA;AAAA"}
@@ -1 +1 @@
1
- {"version":3,"file":"scoped-storage.d.mts","names":[],"sources":["../../../../../../../core/src/storage/scoped-storage.ts"],"mappings":"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"}
1
+ {"version":3,"file":"scoped-storage.d.mts","names":[],"sources":["../../../../../../../core/src/storage/scoped-storage.ts"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"scoped-storage.mjs","names":["fs"],"sources":["../../../../../../../core/src/storage/scoped-storage.ts"],"sourcesContent":["import { fileExistsAsync } from \"@warlock.js/fs\";\nimport { createReadStream } from \"fs\";\nimport fs from \"fs/promises\";\nimport path from \"path\";\nimport type { Readable } from \"stream\";\nimport type { UploadedFile } from \"../http\";\nimport { StorageFile } from \"./storage-file\";\nimport type {\n DeleteManyResult,\n ListOptions,\n PutDirectoryOptions,\n PutDirectoryResult,\n PutFromUrlOptions,\n PutOptions,\n ScopedStorageContract,\n StorageDriverContract,\n StorageDriverType,\n StorageFileInfo,\n} from \"./types\";\nimport { safeFetchToBuffer } from \"./utils/safe-fetch\";\n\n/**\n * ScopedStorage - Base class for storage operations\n *\n * Wraps a storage driver and provides a consistent, developer-friendly API\n * that returns `StorageFile` instances instead of raw data objects.\n *\n * This class serves as the base for both direct driver usage and the\n * full `Storage` manager class.\n *\n * @example\n * ```typescript\n * // Using via storage.use()\n * const s3Storage = storage.use(\"s3\");\n * const file = await s3Storage.put(buffer, \"images/photo.jpg\");\n *\n * // file is a StorageFile instance with rich API\n * console.log(file.name); // \"photo.jpg\"\n * console.log(file.url); // \"https://...\"\n * await file.copy(\"backup/photo.jpg\");\n * ```\n */\nexport class ScopedStorage implements ScopedStorageContract {\n /**\n * The underlying storage driver instance\n * @internal\n */\n protected _driver: StorageDriverContract;\n\n /**\n * Create a new ScopedStorage instance\n *\n * @param driver - The storage driver to wrap\n */\n public constructor(driver: StorageDriverContract) {\n this._driver = driver;\n }\n\n // ============================================================\n // Properties\n // ============================================================\n\n /**\n * Get the driver name\n *\n * @returns The name identifier of the underlying driver (e.g., \"local\", \"s3\", \"r2\")\n */\n public get name(): StorageDriverType {\n return this.activeDriver.name;\n }\n\n /**\n * Get the default driver instance\n *\n * Use this for advanced operations that require direct driver access.\n *\n * @returns The raw storage driver\n */\n public get defaultDriver(): StorageDriverContract {\n return this._driver;\n }\n\n /**\n * Get the currently active driver\n *\n * Returns the driver being used for storage operations.\n * Can be overridden in subclasses for dynamic driver resolution (e.g., multi-tenant contexts).\n *\n * @returns The active storage driver\n */\n public get activeDriver(): StorageDriverContract {\n return this._driver;\n }\n\n // ============================================================\n // File Operations\n // ============================================================\n\n /**\n * Store a file in storage\n *\n * Accepts multiple input types and stores the file at the specified location.\n * Returns a `StorageFile` instance for further operations.\n *\n * @param file - File content as Buffer, string path, UploadedFile, or Readable stream\n * @param location - Destination path in storage (e.g., \"uploads/images/photo.jpg\")\n * @param options - Optional storage options\n * @returns StorageFile instance with cached metadata\n *\n * @example\n * ```typescript\n * // From buffer\n * const file = await storage.put(buffer, \"documents/report.pdf\");\n *\n * // From uploaded file\n * const file = await storage.put(uploadedFile, \"avatars/user-123.jpg\");\n *\n * // With options\n * const file = await storage.put(buffer, \"images/photo.jpg\", {\n * mimeType: \"image/jpeg\",\n * cacheControl: \"max-age=31536000\"\n * });\n * ```\n */\n public async put(\n file: UploadedFile | Buffer | string | Readable,\n location: string,\n options?: PutOptions,\n ): Promise<StorageFile> {\n const buffer = await this.toBuffer(file);\n const data = await this.activeDriver.put(buffer, location, options);\n return StorageFile.fromData(data, this.activeDriver);\n }\n\n /**\n * Store a file from a readable stream\n *\n * Optimized for large files - streams data directly without full buffering.\n * Ideal for file uploads, remote file fetching, or processing pipelines.\n *\n * @param stream - Readable stream of file content\n * @param location - Destination path in storage\n * @param options - Optional storage options\n * @returns StorageFile instance with cached metadata\n *\n * @example\n * ```typescript\n * import { createReadStream } from \"fs\";\n *\n * const stream = createReadStream(\"./large-video.mp4\");\n * const file = await storage.putStream(stream, \"videos/upload.mp4\");\n * ```\n */\n public async putStream(\n stream: Readable,\n location: string,\n options?: PutOptions,\n ): Promise<StorageFile> {\n const data = await this.activeDriver.putStream(stream, location, options);\n return StorageFile.fromData(data, this.activeDriver);\n }\n\n /**\n * Store a file from a URL\n *\n * Downloads the file from the URL and stores it. The download is\n * SSRF-guarded by default: the URL scheme must be https/http, the host\n * must not resolve to a private / loopback / link-local / cloud-metadata\n * address, the body is capped, and the request times out. Tune or relax\n * via the {@link PutFromUrlOptions} guard fields.\n *\n * @param url - URL to download from\n * @param location - Destination path in storage\n * @param options - Storage + outbound-download guard options\n * @returns StorageFile instance\n *\n * @example\n * ```typescript\n * const file = await storage.putFromUrl(\n * \"https://example.com/image.jpg\",\n * \"images/downloaded.jpg\"\n * );\n * ```\n */\n public async putFromUrl(\n url: string,\n location: string,\n options?: PutFromUrlOptions,\n ): Promise<StorageFile> {\n const { allowPrivateHosts, maxBytes, timeoutMs, allowedSchemes, ...putOptions } =\n options ?? {};\n\n const result = await safeFetchToBuffer(url, {\n allowPrivateHosts,\n maxBytes,\n timeoutMs,\n allowedSchemes,\n });\n\n if (!result.ok) {\n throw new Error(`Failed to fetch file from ${url}: ${result.statusText}`);\n }\n\n if (!result.contentType) {\n throw new Error(`Failed to fetch file from ${url}: missing content-type header`);\n }\n\n const mimeType = putOptions.mimeType || result.contentType;\n\n return this.put(result.buffer, location, { ...putOptions, mimeType });\n }\n\n /**\n * Store a file from base64 data URL\n *\n * @param dataUrl - Data URL (data:image/png;base64,iVBORw0KG...)\n * @param location - Destination path in storage\n * @param options - Optional storage options\n * @returns StorageFile instance\n *\n * @example\n * ```typescript\n * const file = await storage.putFromBase64(\n * \"data:image/png;base64,iVBORw0KGgoAAAANS...\",\n * \"images/upload.png\"\n * );\n * ```\n */\n public async putFromBase64(\n dataUrl: string,\n location: string,\n options?: PutOptions,\n ): Promise<StorageFile> {\n // Parse data URL: data:image/png;base64,iVBORw0KG...\n const matches = dataUrl.match(/^data:([^;]+);base64,(.+)$/);\n\n if (!matches) {\n throw new Error(\"Invalid base64 data URL format. Expected: data:mime/type;base64,<data>\");\n }\n\n const [, mimeType, base64Data] = matches;\n const buffer = Buffer.from(base64Data, \"base64\");\n\n return this.put(buffer, location, {\n ...options,\n mimeType: options?.mimeType || mimeType,\n });\n }\n\n /**\n * Retrieve file contents as a Buffer\n *\n * Downloads the entire file into memory. For large files,\n * consider using `getStream()` instead.\n *\n * @param location - Path to the file in storage\n * @returns Buffer containing file contents\n * @throws Error if file not found\n *\n * @example\n * ```typescript\n * const buffer = await storage.get(\"documents/report.pdf\");\n * const content = buffer.toString(\"utf-8\");\n * ```\n */\n public async get(location: string): Promise<Buffer> {\n return this.activeDriver.get(location);\n }\n\n /**\n * Retrieve file contents as a readable stream\n *\n * Streams file data without loading entire file into memory.\n * Ideal for large files or when piping to a response.\n *\n * @param location - Path to the file in storage\n * @returns Readable stream of file contents\n * @throws Error if file not found\n *\n * @example\n * ```typescript\n * const stream = await storage.getStream(\"videos/large.mp4\");\n * stream.pipe(response.raw);\n * ```\n */\n public async getStream(location: string): Promise<Readable> {\n return this.activeDriver.getStream(location);\n }\n\n /**\n * Delete a file from storage\n *\n * @param location - Path to the file, or a StorageFile instance\n * @returns `true` if deleted, `false` if file not found\n *\n * @example\n * ```typescript\n * // By path\n * await storage.delete(\"temp/old-file.txt\");\n *\n * // From StorageFile instance\n * const file = await storage.put(buffer, \"temp/file.txt\");\n * await storage.delete(file);\n * ```\n */\n public async delete(location: string | StorageFile): Promise<boolean> {\n const path = typeof location === \"string\" ? location : location.path;\n return this.activeDriver.delete(path);\n }\n\n /**\n * Delete multiple files at once\n *\n * Performs batch deletion for efficiency. Returns results for each file\n * including success/failure status.\n *\n * @param locations - Array of file paths to delete\n * @returns Array of delete results with status for each file\n *\n * @example\n * ```typescript\n * const results = await storage.deleteMany([\n * \"temp/file1.txt\",\n * \"temp/file2.txt\",\n * \"temp/file3.txt\"\n * ]);\n *\n * for (const result of results) {\n * console.log(`${result.location}: ${result.deleted ? \"deleted\" : result.error}`);\n * }\n * ```\n */\n public async deleteMany(locations: string[]): Promise<DeleteManyResult[]> {\n return this.activeDriver.deleteMany(locations);\n }\n\n /**\n * Delete a directory\n *\n * @param directoryPath - Path to the directory\n */\n public async deleteDirectory(directoryPath: string): Promise<boolean> {\n return await this.activeDriver.deleteDirectory(directoryPath);\n }\n\n /**\n * Check if a file exists in storage\n *\n * @param location - Path to check\n * @returns `true` if file exists, `false` otherwise\n *\n * @example\n * ```typescript\n * if (await storage.exists(\"config/settings.json\")) {\n * const config = await storage.get(\"config/settings.json\");\n * }\n * ```\n */\n public async exists(location: string): Promise<boolean> {\n return this.activeDriver.exists(location);\n }\n\n /**\n * Copy a file to a new location\n *\n * Creates a copy of the file at the destination path.\n * The original file remains unchanged.\n *\n * @param from - Source path or StorageFile instance\n * @param to - Destination path\n * @returns StorageFile instance at the new location\n *\n * @example\n * ```typescript\n * // Copy by path\n * const backup = await storage.copy(\"documents/report.pdf\", \"backups/report.pdf\");\n *\n * // Copy from StorageFile\n * const original = await storage.file(\"documents/report.pdf\");\n * const backup = await storage.copy(original, \"backups/report.pdf\");\n * ```\n */\n public async copy(from: string | StorageFile, to: string): Promise<StorageFile> {\n const fromPath = typeof from === \"string\" ? from : from.path;\n const data = await this.activeDriver.copy(fromPath, to);\n return StorageFile.fromData(data, this.activeDriver);\n }\n\n /**\n * Move a file to a new location\n *\n * Moves the file to the destination path. The original file\n * is deleted after successful copy.\n *\n * @param from - Source path or StorageFile instance\n * @param to - Destination path\n * @returns StorageFile instance at the new location\n *\n * @example\n * ```typescript\n * // Move by path\n * const file = await storage.move(\"uploads/temp.jpg\", \"images/photo.jpg\");\n *\n * // Move from StorageFile\n * const temp = await storage.file(\"uploads/temp.jpg\");\n * const final = await storage.move(temp, \"images/photo.jpg\");\n * ```\n */\n public async move(from: string | StorageFile, to: string): Promise<StorageFile> {\n const fromPath = typeof from === \"string\" ? from : from.path;\n const data = await this.activeDriver.move(fromPath, to);\n return StorageFile.fromData(data, this.activeDriver);\n }\n\n /**\n * Copy an entire directory recursively\n *\n * Copies all files from the source directory to the destination directory,\n * preserving the directory structure.\n *\n * @param from - Source directory path\n * @param to - Destination directory path\n * @param options - Optional concurrency control\n * @returns Number of files copied\n *\n * @example\n * ```typescript\n * // Copy entire directory\n * const count = await storage.copyDirectory(\"uploads/temp\", \"uploads/final\");\n * console.log(`Copied ${count} files`);\n *\n * // With concurrency limit\n * const count = await storage.copyDirectory(\"large-dir\", \"backup\", {\n * concurrency: 10\n * });\n * ```\n */\n public async copyDirectory(\n from: string,\n to: string,\n options?: { concurrency?: number },\n ): Promise<number> {\n const concurrency = options?.concurrency || 5;\n\n // List all files recursively\n const files = await this.list(from, { recursive: true });\n const filesToCopy = files.filter((f) => !f.isDirectory);\n\n // Copy files in batches for efficiency\n let copied = 0;\n for (let i = 0; i < filesToCopy.length; i += concurrency) {\n const batch = filesToCopy.slice(i, i + concurrency);\n await Promise.all(\n batch.map(async (file) => {\n // Calculate relative path and new destination\n const relativePath = file.path.substring(from.length).replace(/^\\//, \"\");\n const newPath = `${to}/${relativePath}`;\n await this.copy(file.path, newPath);\n copied++;\n }),\n );\n }\n\n return copied;\n }\n\n /**\n * Move an entire directory recursively\n *\n * Moves all files from the source directory to the destination directory,\n * then deletes the source directory.\n *\n * @param from - Source directory path\n * @param to - Destination directory path\n * @param options - Optional concurrency control\n * @returns Number of files moved\n *\n * @example\n * ```typescript\n * const count = await storage.moveDirectory(\"uploads/temp\", \"uploads/final\");\n * console.log(`Moved ${count} files`);\n * ```\n */\n public async moveDirectory(\n from: string,\n to: string,\n options?: { concurrency?: number },\n ): Promise<number> {\n // Copy all files first\n const count = await this.copyDirectory(from, to, options);\n\n // Delete source directory\n await this.deleteDirectory(from);\n\n return count;\n }\n\n /**\n * Upload a local filesystem directory into storage\n *\n * Recursively walks the local directory, applies an optional filter, then\n * streams each file into storage. Uploads run in concurrent batches for\n * efficiency. Failures are collected — a single failed file never aborts\n * the entire operation (mirrors the contract of `deleteMany`).\n *\n * @param localDirPath - Absolute path of the local directory to upload\n * @param destination - Target prefix in storage (e.g. \"uploads/assets\")\n * @param options - Concurrency, filter, progress callback, put options\n * @returns - { uploaded, failed, total }\n *\n * @example\n * ```typescript\n * const result = await storage.putDirectory(\"./public/assets\", \"cdn/assets\", {\n * concurrency: 10,\n * filter: (_, rel) => !rel.startsWith(\".\"),\n * onProgress: (done, total) => console.log(`${done}/${total}`),\n * });\n *\n * console.log(`Uploaded: ${result.uploaded.length}, Failed: ${result.failed.length}`);\n * ```\n */\n public async putDirectory(\n localDirPath: string,\n destination: string,\n options?: PutDirectoryOptions,\n ): Promise<PutDirectoryResult> {\n const concurrency = options?.concurrency ?? 5;\n\n // Collect all local file paths recursively\n const localFiles = await this.walkLocalDirectory(localDirPath);\n\n // Apply the user-supplied filter if any\n const filteredFiles = options?.filter\n ? localFiles.filter(({ absolute, relative }) => options.filter!(absolute, relative))\n : localFiles;\n\n const total = filteredFiles.length;\n const uploaded: StorageFile[] = [];\n const failed: Array<{ localPath: string; error: Error }> = [];\n let doneCount = 0;\n\n // Upload in concurrent batches\n for (let i = 0; i < filteredFiles.length; i += concurrency) {\n const batch = filteredFiles.slice(i, i + concurrency);\n\n await Promise.all(\n batch.map(async ({ absolute, relative }) => {\n const storagePath = `${destination.replace(/\\/$/, \"\")}/${relative}`;\n\n try {\n const stream = createReadStream(absolute);\n const file = await this.putStream(stream, storagePath, options?.putOptions);\n uploaded.push(file);\n doneCount++;\n options?.onProgress?.(doneCount, total, file);\n } catch (err) {\n failed.push({\n localPath: absolute,\n error: err instanceof Error ? err : new Error(String(err)),\n });\n }\n }),\n );\n }\n\n return { uploaded, failed, total };\n }\n\n /**\n * Walk a local directory recursively and return all file paths\n *\n * @param dirPath - Absolute local directory path\n * @returns Array of { absolute, relative } file path pairs\n * @internal\n */\n private async walkLocalDirectory(\n dirPath: string,\n baseDir?: string,\n ): Promise<Array<{ absolute: string; relative: string }>> {\n const root = baseDir ?? dirPath;\n const entries = await fs.readdir(dirPath, { withFileTypes: true });\n const results: Array<{ absolute: string; relative: string }> = [];\n\n for (const entry of entries) {\n const absolute = path.join(dirPath, entry.name);\n const relative = path.relative(root, absolute).replace(/\\\\/g, \"/\");\n\n if (entry.isDirectory()) {\n const nested = await this.walkLocalDirectory(absolute, root);\n results.push(...nested);\n } else if (entry.isFile()) {\n results.push({ absolute, relative });\n }\n // Symlinks are intentionally skipped\n }\n\n return results;\n }\n\n /**\n * Empty a directory without deleting the directory itself\n *\n * Deletes all files within the directory but preserves the directory structure.\n *\n * @param path - Directory path to empty\n * @returns Number of files deleted\n *\n * @example\n * ```typescript\n * const count = await storage.emptyDirectory(\"uploads/temp\");\n * console.log(`Deleted ${count} files`);\n * ```\n */\n public async emptyDirectory(path: string): Promise<number> {\n // List all files in directory\n const files = await this.list(path, { recursive: true });\n const filePaths = files.filter((f) => !f.isDirectory).map((f) => f.path);\n\n if (filePaths.length === 0) {\n return 0;\n }\n\n // Delete all files\n await this.deleteMany(filePaths);\n\n return filePaths.length;\n }\n\n /**\n * List files in a directory\n *\n * Returns file information for all files in the specified directory.\n * Supports recursive listing and pagination.\n *\n * @param directory - Directory path (defaults to root)\n * @param options - List options (recursive, limit, cursor)\n * @returns Array of file information objects\n *\n * @example\n * ```typescript\n * // List all files in uploads\n * const files = await storage.list(\"uploads\");\n *\n * // Recursive listing with limit\n * const files = await storage.list(\"uploads\", {\n * recursive: true,\n * limit: 100\n * });\n * ```\n */\n public async list(directory?: string, options?: ListOptions): Promise<StorageFileInfo[]> {\n return this.activeDriver.list(directory || \"\", options);\n }\n\n // ============================================================\n // URL Operations\n // ============================================================\n\n /**\n * Get the public URL for a file\n *\n * Returns the URL where the file can be accessed. For local storage,\n * this is typically a path prefix. For cloud storage, this is the\n * bucket URL or CDN URL.\n *\n * @param location - File path\n * @returns Public URL string\n *\n * @example\n * ```typescript\n * const url = storage.url(\"images/photo.jpg\");\n * // Local: \"/uploads/images/photo.jpg\"\n * // S3: \"https://bucket.s3.amazonaws.com/images/photo.jpg\"\n * ```\n */\n public url(location: string): string {\n return this.activeDriver.url(location);\n }\n\n /**\n * Get a temporary signed URL with expiration\n *\n * Creates a URL that provides temporary access to the file.\n * For cloud storage, this uses presigned URLs.\n * For local storage, this uses HMAC-signed tokens.\n *\n * @param location - File path\n * @param expiresIn - Seconds until URL expires (default: 3600)\n * @returns Signed URL string\n *\n * @example\n * ```typescript\n * // URL valid for 1 hour\n * const url = await storage.temporaryUrl(\"private/document.pdf\");\n *\n * // URL valid for 24 hours\n * const url = await storage.temporaryUrl(\"private/document.pdf\", 86400);\n * ```\n */\n public async temporaryUrl(location: string, expiresIn?: number): Promise<string> {\n return this.activeDriver.temporaryUrl(location, expiresIn);\n }\n\n // ============================================================\n // Metadata Operations\n // ============================================================\n\n /**\n * Get file metadata without downloading the file\n *\n * Retrieves information about a file including size, last modified date,\n * and MIME type without downloading the file contents.\n *\n * @param location - File path\n * @returns File information object\n * @throws Error if file not found\n *\n * @example\n * ```typescript\n * const info = await storage.metadata(\"documents/report.pdf\");\n * console.log(`Size: ${info.size} bytes`);\n * console.log(`Type: ${info.mimeType}`);\n * console.log(`Modified: ${info.lastModified}`);\n * ```\n */\n public async metadata(location: string): Promise<StorageFileInfo> {\n return this.activeDriver.metadata(location);\n }\n\n /**\n * Get file size in bytes\n *\n * Shortcut for `metadata(location).size`.\n *\n * @param location - File path\n * @returns File size in bytes\n * @throws Error if file not found\n */\n public async size(location: string): Promise<number> {\n return this.activeDriver.size(location);\n }\n\n /**\n * Get a StorageFile instance for OOP-style operations\n *\n * Creates a `StorageFile` wrapper for the specified path,\n * allowing fluent method chaining for file operations.\n *\n * @param location - File path\n * @returns StorageFile instance\n *\n * @example\n * ```typescript\n * const file = await storage.file(\"uploads/image.jpg\");\n *\n * // Properties\n * console.log(file.name); // \"image.jpg\"\n * console.log(file.extension); // \"jpg\"\n *\n * // Operations\n * await file.copy(\"backup/image.jpg\");\n * await file.delete();\n * ```\n */\n public file(location: string): StorageFile {\n return new StorageFile(location, this.activeDriver);\n }\n\n // ============================================================\n // Utilities\n // ============================================================\n\n /**\n * Convert various input types to Buffer\n *\n * @param file - Input file in various formats\n * @returns Buffer containing file contents\n * @internal\n */\n protected async toBuffer(file: UploadedFile | Buffer | string | Readable): Promise<Buffer> {\n // Already a buffer\n if (Buffer.isBuffer(file)) {\n return file;\n }\n\n // Readable stream - collect into buffer\n if (this.isReadable(file)) {\n return this.streamToBuffer(file as Readable);\n }\n\n // String content\n if (typeof file === \"string\") {\n if (await fileExistsAsync(file)) {\n return fs.readFile(file);\n }\n\n return Buffer.from(file);\n }\n\n // UploadedFile\n return (file as UploadedFile).buffer();\n }\n\n /**\n * Check if value is a Readable stream\n *\n * @param value - Value to check\n * @returns True if value is a Readable stream\n * @internal\n */\n protected isReadable(value: unknown): value is Readable {\n return (\n typeof value === \"object\" &&\n value !== null &&\n \"pipe\" in value &&\n typeof (value as Readable).pipe === \"function\"\n );\n }\n\n /**\n * Convert a Readable stream to Buffer\n *\n * @param stream - Readable stream\n * @returns Buffer containing stream contents\n * @internal\n */\n protected async streamToBuffer(stream: Readable): Promise<Buffer> {\n const chunks: Buffer[] = [];\n for await (const chunk of stream) {\n chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));\n }\n return Buffer.concat(chunks as unknown as Uint8Array[]);\n }\n\n /**\n * Prepend a prefix to a location path\n *\n * Useful for organizing files into directories.\n *\n * @param prefix - Prefix to add (e.g., \"uploads\")\n * @param location - Original location path\n * @returns Combined path with prefix\n *\n * @example\n * ```typescript\n * storage.prepend(\"uploads\", \"image.jpg\"); // \"uploads/image.jpg\"\n * storage.prepend(\"uploads/\", \"/image.jpg\"); // \"uploads/image.jpg\"\n * ```\n */\n public prepend(prefix: string, location: string): string {\n return `${prefix.replace(/\\/$/, \"\")}/${location.replace(/^\\//, \"\")}`;\n }\n\n /**\n * Append a suffix to a location path (before extension)\n *\n * Useful for creating variants of files (thumbnails, etc.).\n *\n * @param location - Original location path\n * @param suffix - Suffix to add before extension\n * @returns Path with suffix added before extension\n *\n * @example\n * ```typescript\n * storage.append(\"image.jpg\", \"_thumb\"); // \"image_thumb.jpg\"\n * storage.append(\"document.pdf\", \"_v2\"); // \"document_v2.pdf\"\n * ```\n */\n public append(location: string, suffix: string): string {\n const lastDot = location.lastIndexOf(\".\");\n if (lastDot === -1) {\n return `${location}${suffix}`;\n }\n return `${location.substring(0, lastDot)}${suffix}${location.substring(lastDot)}`;\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"scoped-storage.mjs","names":["fs"],"sources":["../../../../../../../core/src/storage/scoped-storage.ts"],"sourcesContent":["import { fileExistsAsync } from \"@warlock.js/fs\";\nimport { createReadStream } from \"fs\";\nimport fs from \"fs/promises\";\nimport path from \"path\";\nimport type { Readable } from \"stream\";\nimport type { UploadedFile } from \"../http\";\nimport { StorageFile } from \"./storage-file\";\nimport type {\n DeleteManyResult,\n ListOptions,\n PutDirectoryOptions,\n PutDirectoryResult,\n PutFromUrlOptions,\n PutOptions,\n ScopedStorageContract,\n StorageDriverContract,\n StorageDriverType,\n StorageFileInfo,\n} from \"./types\";\nimport { safeFetchToBuffer } from \"./utils/safe-fetch\";\n\n/**\n * ScopedStorage - Base class for storage operations\n *\n * Wraps a storage driver and provides a consistent, developer-friendly API\n * that returns `StorageFile` instances instead of raw data objects.\n *\n * This class serves as the base for both direct driver usage and the\n * full `Storage` manager class.\n *\n * @example\n * ```typescript\n * // Using via storage.use()\n * const s3Storage = storage.use(\"s3\");\n * const file = await s3Storage.put(buffer, \"images/photo.jpg\");\n *\n * // file is a StorageFile instance with rich API\n * console.log(file.name); // \"photo.jpg\"\n * console.log(file.url); // \"https://...\"\n * await file.copy(\"backup/photo.jpg\");\n * ```\n */\nexport class ScopedStorage implements ScopedStorageContract {\n /**\n * The underlying storage driver instance\n * @internal\n */\n protected _driver: StorageDriverContract;\n\n /**\n * Create a new ScopedStorage instance\n *\n * @param driver - The storage driver to wrap\n */\n public constructor(driver: StorageDriverContract) {\n this._driver = driver;\n }\n\n // ============================================================\n // Properties\n // ============================================================\n\n /**\n * Get the driver name\n *\n * @returns The name identifier of the underlying driver (e.g., \"local\", \"s3\", \"r2\")\n */\n public get name(): StorageDriverType {\n return this.activeDriver.name;\n }\n\n /**\n * Get the default driver instance\n *\n * Use this for advanced operations that require direct driver access.\n *\n * @returns The raw storage driver\n */\n public get defaultDriver(): StorageDriverContract {\n return this._driver;\n }\n\n /**\n * Get the currently active driver\n *\n * Returns the driver being used for storage operations.\n * Can be overridden in subclasses for dynamic driver resolution (e.g., multi-tenant contexts).\n *\n * @returns The active storage driver\n */\n public get activeDriver(): StorageDriverContract {\n return this._driver;\n }\n\n // ============================================================\n // File Operations\n // ============================================================\n\n /**\n * Store a file in storage\n *\n * Accepts multiple input types and stores the file at the specified location.\n * Returns a `StorageFile` instance for further operations.\n *\n * @param file - File content as Buffer, string path, UploadedFile, or Readable stream\n * @param location - Destination path in storage (e.g., \"uploads/images/photo.jpg\")\n * @param options - Optional storage options\n * @returns StorageFile instance with cached metadata\n *\n * @example\n * ```typescript\n * // From buffer\n * const file = await storage.put(buffer, \"documents/report.pdf\");\n *\n * // From uploaded file\n * const file = await storage.put(uploadedFile, \"avatars/user-123.jpg\");\n *\n * // With options\n * const file = await storage.put(buffer, \"images/photo.jpg\", {\n * mimeType: \"image/jpeg\",\n * cacheControl: \"max-age=31536000\"\n * });\n * ```\n */\n public async put(\n file: UploadedFile | Buffer | string | Readable,\n location: string,\n options?: PutOptions,\n ): Promise<StorageFile> {\n const buffer = await this.toBuffer(file);\n const data = await this.activeDriver.put(buffer, location, options);\n return StorageFile.fromData(data, this.activeDriver);\n }\n\n /**\n * Store a file from a readable stream\n *\n * Optimized for large files - streams data directly without full buffering.\n * Ideal for file uploads, remote file fetching, or processing pipelines.\n *\n * @param stream - Readable stream of file content\n * @param location - Destination path in storage\n * @param options - Optional storage options\n * @returns StorageFile instance with cached metadata\n *\n * @example\n * ```typescript\n * import { createReadStream } from \"fs\";\n *\n * const stream = createReadStream(\"./large-video.mp4\");\n * const file = await storage.putStream(stream, \"videos/upload.mp4\");\n * ```\n */\n public async putStream(\n stream: Readable,\n location: string,\n options?: PutOptions,\n ): Promise<StorageFile> {\n const data = await this.activeDriver.putStream(stream, location, options);\n return StorageFile.fromData(data, this.activeDriver);\n }\n\n /**\n * Store a file from a URL\n *\n * Downloads the file from the URL and stores it. The download is\n * SSRF-guarded by default: the URL scheme must be https/http, the host\n * must not resolve to a private / loopback / link-local / cloud-metadata\n * address, the body is capped, and the request times out. Tune or relax\n * via the {@link PutFromUrlOptions} guard fields.\n *\n * @param url - URL to download from\n * @param location - Destination path in storage\n * @param options - Storage + outbound-download guard options\n * @returns StorageFile instance\n *\n * @example\n * ```typescript\n * const file = await storage.putFromUrl(\n * \"https://example.com/image.jpg\",\n * \"images/downloaded.jpg\"\n * );\n * ```\n */\n public async putFromUrl(\n url: string,\n location: string,\n options?: PutFromUrlOptions,\n ): Promise<StorageFile> {\n const { allowPrivateHosts, maxBytes, timeoutMs, allowedSchemes, ...putOptions } =\n options ?? {};\n\n const result = await safeFetchToBuffer(url, {\n allowPrivateHosts,\n maxBytes,\n timeoutMs,\n allowedSchemes,\n });\n\n if (!result.ok) {\n throw new Error(`Failed to fetch file from ${url}: ${result.statusText}`);\n }\n\n if (!result.contentType) {\n throw new Error(`Failed to fetch file from ${url}: missing content-type header`);\n }\n\n const mimeType = putOptions.mimeType || result.contentType;\n\n return this.put(result.buffer, location, { ...putOptions, mimeType });\n }\n\n /**\n * Store a file from base64 data URL\n *\n * @param dataUrl - Data URL (data:image/png;base64,iVBORw0KG...)\n * @param location - Destination path in storage\n * @param options - Optional storage options\n * @returns StorageFile instance\n *\n * @example\n * ```typescript\n * const file = await storage.putFromBase64(\n * \"data:image/png;base64,iVBORw0KGgoAAAANS...\",\n * \"images/upload.png\"\n * );\n * ```\n */\n public async putFromBase64(\n dataUrl: string,\n location: string,\n options?: PutOptions,\n ): Promise<StorageFile> {\n // Parse data URL: data:image/png;base64,iVBORw0KG...\n const matches = dataUrl.match(/^data:([^;]+);base64,(.+)$/);\n\n if (!matches) {\n throw new Error(\"Invalid base64 data URL format. Expected: data:mime/type;base64,<data>\");\n }\n\n const [, mimeType, base64Data] = matches;\n const buffer = Buffer.from(base64Data, \"base64\");\n\n return this.put(buffer, location, {\n ...options,\n mimeType: options?.mimeType || mimeType,\n });\n }\n\n /**\n * Retrieve file contents as a Buffer\n *\n * Downloads the entire file into memory. For large files,\n * consider using `getStream()` instead.\n *\n * @param location - Path to the file in storage\n * @returns Buffer containing file contents\n * @throws Error if file not found\n *\n * @example\n * ```typescript\n * const buffer = await storage.get(\"documents/report.pdf\");\n * const content = buffer.toString(\"utf-8\");\n * ```\n */\n public async get(location: string): Promise<Buffer> {\n return this.activeDriver.get(location);\n }\n\n /**\n * Retrieve file contents as a readable stream\n *\n * Streams file data without loading entire file into memory.\n * Ideal for large files or when piping to a response.\n *\n * @param location - Path to the file in storage\n * @returns Readable stream of file contents\n * @throws Error if file not found\n *\n * @example\n * ```typescript\n * const stream = await storage.getStream(\"videos/large.mp4\");\n * stream.pipe(response.raw);\n * ```\n */\n public async getStream(location: string): Promise<Readable> {\n return this.activeDriver.getStream(location);\n }\n\n /**\n * Delete a file from storage\n *\n * @param location - Path to the file, or a StorageFile instance\n * @returns `true` if deleted, `false` if file not found\n *\n * @example\n * ```typescript\n * // By path\n * await storage.delete(\"temp/old-file.txt\");\n *\n * // From StorageFile instance\n * const file = await storage.put(buffer, \"temp/file.txt\");\n * await storage.delete(file);\n * ```\n */\n public async delete(location: string | StorageFile): Promise<boolean> {\n const path = typeof location === \"string\" ? location : location.path;\n return this.activeDriver.delete(path);\n }\n\n /**\n * Delete multiple files at once\n *\n * Performs batch deletion for efficiency. Returns results for each file\n * including success/failure status.\n *\n * @param locations - Array of file paths to delete\n * @returns Array of delete results with status for each file\n *\n * @example\n * ```typescript\n * const results = await storage.deleteMany([\n * \"temp/file1.txt\",\n * \"temp/file2.txt\",\n * \"temp/file3.txt\"\n * ]);\n *\n * for (const result of results) {\n * console.log(`${result.location}: ${result.deleted ? \"deleted\" : result.error}`);\n * }\n * ```\n */\n public async deleteMany(locations: string[]): Promise<DeleteManyResult[]> {\n return this.activeDriver.deleteMany(locations);\n }\n\n /**\n * Delete a directory\n *\n * @param directoryPath - Path to the directory\n */\n public async deleteDirectory(directoryPath: string): Promise<boolean> {\n return await this.activeDriver.deleteDirectory(directoryPath);\n }\n\n /**\n * Check if a file exists in storage\n *\n * @param location - Path to check\n * @returns `true` if file exists, `false` otherwise\n *\n * @example\n * ```typescript\n * if (await storage.exists(\"config/settings.json\")) {\n * const config = await storage.get(\"config/settings.json\");\n * }\n * ```\n */\n public async exists(location: string): Promise<boolean> {\n return this.activeDriver.exists(location);\n }\n\n /**\n * Copy a file to a new location\n *\n * Creates a copy of the file at the destination path.\n * The original file remains unchanged.\n *\n * @param from - Source path or StorageFile instance\n * @param to - Destination path\n * @returns StorageFile instance at the new location\n *\n * @example\n * ```typescript\n * // Copy by path\n * const backup = await storage.copy(\"documents/report.pdf\", \"backups/report.pdf\");\n *\n * // Copy from StorageFile\n * const original = await storage.file(\"documents/report.pdf\");\n * const backup = await storage.copy(original, \"backups/report.pdf\");\n * ```\n */\n public async copy(from: string | StorageFile, to: string): Promise<StorageFile> {\n const fromPath = typeof from === \"string\" ? from : from.path;\n const data = await this.activeDriver.copy(fromPath, to);\n return StorageFile.fromData(data, this.activeDriver);\n }\n\n /**\n * Move a file to a new location\n *\n * Moves the file to the destination path. The original file\n * is deleted after successful copy.\n *\n * @param from - Source path or StorageFile instance\n * @param to - Destination path\n * @returns StorageFile instance at the new location\n *\n * @example\n * ```typescript\n * // Move by path\n * const file = await storage.move(\"uploads/temp.jpg\", \"images/photo.jpg\");\n *\n * // Move from StorageFile\n * const temp = await storage.file(\"uploads/temp.jpg\");\n * const final = await storage.move(temp, \"images/photo.jpg\");\n * ```\n */\n public async move(from: string | StorageFile, to: string): Promise<StorageFile> {\n const fromPath = typeof from === \"string\" ? from : from.path;\n const data = await this.activeDriver.move(fromPath, to);\n return StorageFile.fromData(data, this.activeDriver);\n }\n\n /**\n * Copy an entire directory recursively\n *\n * Copies all files from the source directory to the destination directory,\n * preserving the directory structure.\n *\n * @param from - Source directory path\n * @param to - Destination directory path\n * @param options - Optional concurrency control\n * @returns Number of files copied\n *\n * @example\n * ```typescript\n * // Copy entire directory\n * const count = await storage.copyDirectory(\"uploads/temp\", \"uploads/final\");\n * console.log(`Copied ${count} files`);\n *\n * // With concurrency limit\n * const count = await storage.copyDirectory(\"large-dir\", \"backup\", {\n * concurrency: 10\n * });\n * ```\n */\n public async copyDirectory(\n from: string,\n to: string,\n options?: { concurrency?: number },\n ): Promise<number> {\n const concurrency = options?.concurrency || 5;\n\n // List all files recursively\n const files = await this.list(from, { recursive: true });\n const filesToCopy = files.filter((f) => !f.isDirectory);\n\n // Copy files in batches for efficiency\n let copied = 0;\n for (let i = 0; i < filesToCopy.length; i += concurrency) {\n const batch = filesToCopy.slice(i, i + concurrency);\n await Promise.all(\n batch.map(async (file) => {\n // Calculate relative path and new destination\n const relativePath = file.path.substring(from.length).replace(/^\\//, \"\");\n const newPath = `${to}/${relativePath}`;\n await this.copy(file.path, newPath);\n copied++;\n }),\n );\n }\n\n return copied;\n }\n\n /**\n * Move an entire directory recursively\n *\n * Moves all files from the source directory to the destination directory,\n * then deletes the source directory.\n *\n * @param from - Source directory path\n * @param to - Destination directory path\n * @param options - Optional concurrency control\n * @returns Number of files moved\n *\n * @example\n * ```typescript\n * const count = await storage.moveDirectory(\"uploads/temp\", \"uploads/final\");\n * console.log(`Moved ${count} files`);\n * ```\n */\n public async moveDirectory(\n from: string,\n to: string,\n options?: { concurrency?: number },\n ): Promise<number> {\n // Copy all files first\n const count = await this.copyDirectory(from, to, options);\n\n // Delete source directory\n await this.deleteDirectory(from);\n\n return count;\n }\n\n /**\n * Upload a local filesystem directory into storage\n *\n * Recursively walks the local directory, applies an optional filter, then\n * streams each file into storage. Uploads run in concurrent batches for\n * efficiency. Failures are collected — a single failed file never aborts\n * the entire operation (mirrors the contract of `deleteMany`).\n *\n * @param localDirPath - Absolute path of the local directory to upload\n * @param destination - Target prefix in storage (e.g. \"uploads/assets\")\n * @param options - Concurrency, filter, progress callback, put options\n * @returns - { uploaded, failed, total }\n *\n * @example\n * ```typescript\n * const result = await storage.putDirectory(\"./public/assets\", \"cdn/assets\", {\n * concurrency: 10,\n * filter: (_, rel) => !rel.startsWith(\".\"),\n * onProgress: (done, total) => console.log(`${done}/${total}`),\n * });\n *\n * console.log(`Uploaded: ${result.uploaded.length}, Failed: ${result.failed.length}`);\n * ```\n */\n public async putDirectory(\n localDirPath: string,\n destination: string,\n options?: PutDirectoryOptions,\n ): Promise<PutDirectoryResult> {\n const concurrency = options?.concurrency ?? 5;\n\n // Collect all local file paths recursively\n const localFiles = await this.walkLocalDirectory(localDirPath);\n\n // Apply the user-supplied filter if any\n const filteredFiles = options?.filter\n ? localFiles.filter(({ absolute, relative }) => options.filter!(absolute, relative))\n : localFiles;\n\n const total = filteredFiles.length;\n const uploaded: StorageFile[] = [];\n const failed: Array<{ localPath: string; error: Error }> = [];\n let doneCount = 0;\n\n // Upload in concurrent batches\n for (let i = 0; i < filteredFiles.length; i += concurrency) {\n const batch = filteredFiles.slice(i, i + concurrency);\n\n await Promise.all(\n batch.map(async ({ absolute, relative }) => {\n const storagePath = `${destination.replace(/\\/$/, \"\")}/${relative}`;\n\n try {\n const stream = createReadStream(absolute);\n const file = await this.putStream(stream, storagePath, options?.putOptions);\n uploaded.push(file);\n doneCount++;\n options?.onProgress?.(doneCount, total, file);\n } catch (err) {\n failed.push({\n localPath: absolute,\n error: err instanceof Error ? err : new Error(String(err)),\n });\n }\n }),\n );\n }\n\n return { uploaded, failed, total };\n }\n\n /**\n * Walk a local directory recursively and return all file paths\n *\n * @param dirPath - Absolute local directory path\n * @returns Array of { absolute, relative } file path pairs\n * @internal\n */\n private async walkLocalDirectory(\n dirPath: string,\n baseDir?: string,\n ): Promise<Array<{ absolute: string; relative: string }>> {\n const root = baseDir ?? dirPath;\n const entries = await fs.readdir(dirPath, { withFileTypes: true });\n const results: Array<{ absolute: string; relative: string }> = [];\n\n for (const entry of entries) {\n const absolute = path.join(dirPath, entry.name);\n const relative = path.relative(root, absolute).replace(/\\\\/g, \"/\");\n\n if (entry.isDirectory()) {\n const nested = await this.walkLocalDirectory(absolute, root);\n results.push(...nested);\n } else if (entry.isFile()) {\n results.push({ absolute, relative });\n }\n // Symlinks are intentionally skipped\n }\n\n return results;\n }\n\n /**\n * Empty a directory without deleting the directory itself\n *\n * Deletes all files within the directory but preserves the directory structure.\n *\n * @param path - Directory path to empty\n * @returns Number of files deleted\n *\n * @example\n * ```typescript\n * const count = await storage.emptyDirectory(\"uploads/temp\");\n * console.log(`Deleted ${count} files`);\n * ```\n */\n public async emptyDirectory(path: string): Promise<number> {\n // List all files in directory\n const files = await this.list(path, { recursive: true });\n const filePaths = files.filter((f) => !f.isDirectory).map((f) => f.path);\n\n if (filePaths.length === 0) {\n return 0;\n }\n\n // Delete all files\n await this.deleteMany(filePaths);\n\n return filePaths.length;\n }\n\n /**\n * List files in a directory\n *\n * Returns file information for all files in the specified directory.\n * Supports recursive listing and pagination.\n *\n * @param directory - Directory path (defaults to root)\n * @param options - List options (recursive, limit, cursor)\n * @returns Array of file information objects\n *\n * @example\n * ```typescript\n * // List all files in uploads\n * const files = await storage.list(\"uploads\");\n *\n * // Recursive listing with limit\n * const files = await storage.list(\"uploads\", {\n * recursive: true,\n * limit: 100\n * });\n * ```\n */\n public async list(directory?: string, options?: ListOptions): Promise<StorageFileInfo[]> {\n return this.activeDriver.list(directory || \"\", options);\n }\n\n // ============================================================\n // URL Operations\n // ============================================================\n\n /**\n * Get the public URL for a file\n *\n * Returns the URL where the file can be accessed. For local storage,\n * this is typically a path prefix. For cloud storage, this is the\n * bucket URL or CDN URL.\n *\n * @param location - File path\n * @returns Public URL string\n *\n * @example\n * ```typescript\n * const url = storage.url(\"images/photo.jpg\");\n * // Local: \"/uploads/images/photo.jpg\"\n * // S3: \"https://bucket.s3.amazonaws.com/images/photo.jpg\"\n * ```\n */\n public url(location: string): string {\n return this.activeDriver.url(location);\n }\n\n /**\n * Get a temporary signed URL with expiration\n *\n * Creates a URL that provides temporary access to the file.\n * For cloud storage, this uses presigned URLs.\n * For local storage, this uses HMAC-signed tokens.\n *\n * @param location - File path\n * @param expiresIn - Seconds until URL expires (default: 3600)\n * @returns Signed URL string\n *\n * @example\n * ```typescript\n * // URL valid for 1 hour\n * const url = await storage.temporaryUrl(\"private/document.pdf\");\n *\n * // URL valid for 24 hours\n * const url = await storage.temporaryUrl(\"private/document.pdf\", 86400);\n * ```\n */\n public async temporaryUrl(location: string, expiresIn?: number): Promise<string> {\n return this.activeDriver.temporaryUrl(location, expiresIn);\n }\n\n // ============================================================\n // Metadata Operations\n // ============================================================\n\n /**\n * Get file metadata without downloading the file\n *\n * Retrieves information about a file including size, last modified date,\n * and MIME type without downloading the file contents.\n *\n * @param location - File path\n * @returns File information object\n * @throws Error if file not found\n *\n * @example\n * ```typescript\n * const info = await storage.metadata(\"documents/report.pdf\");\n * console.log(`Size: ${info.size} bytes`);\n * console.log(`Type: ${info.mimeType}`);\n * console.log(`Modified: ${info.lastModified}`);\n * ```\n */\n public async metadata(location: string): Promise<StorageFileInfo> {\n return this.activeDriver.metadata(location);\n }\n\n /**\n * Get file size in bytes\n *\n * Shortcut for `metadata(location).size`.\n *\n * @param location - File path\n * @returns File size in bytes\n * @throws Error if file not found\n */\n public async size(location: string): Promise<number> {\n return this.activeDriver.size(location);\n }\n\n /**\n * Get a StorageFile instance for OOP-style operations\n *\n * Creates a `StorageFile` wrapper for the specified path,\n * allowing fluent method chaining for file operations.\n *\n * @param location - File path\n * @returns StorageFile instance\n *\n * @example\n * ```typescript\n * const file = await storage.file(\"uploads/image.jpg\");\n *\n * // Properties\n * console.log(file.name); // \"image.jpg\"\n * console.log(file.extension); // \"jpg\"\n *\n * // Operations\n * await file.copy(\"backup/image.jpg\");\n * await file.delete();\n * ```\n */\n public file(location: string): StorageFile {\n return new StorageFile(location, this.activeDriver);\n }\n\n // ============================================================\n // Utilities\n // ============================================================\n\n /**\n * Convert various input types to Buffer\n *\n * @param file - Input file in various formats\n * @returns Buffer containing file contents\n * @internal\n */\n protected async toBuffer(file: UploadedFile | Buffer | string | Readable): Promise<Buffer> {\n // Already a buffer\n if (Buffer.isBuffer(file)) {\n return file;\n }\n\n // Readable stream - collect into buffer\n if (this.isReadable(file)) {\n return this.streamToBuffer(file as Readable);\n }\n\n // String content\n if (typeof file === \"string\") {\n if (await fileExistsAsync(file)) {\n return fs.readFile(file);\n }\n\n return Buffer.from(file);\n }\n\n // UploadedFile\n return (file as UploadedFile).buffer();\n }\n\n /**\n * Check if value is a Readable stream\n *\n * @param value - Value to check\n * @returns True if value is a Readable stream\n * @internal\n */\n protected isReadable(value: unknown): value is Readable {\n return (\n typeof value === \"object\" &&\n value !== null &&\n \"pipe\" in value &&\n typeof (value as Readable).pipe === \"function\"\n );\n }\n\n /**\n * Convert a Readable stream to Buffer\n *\n * @param stream - Readable stream\n * @returns Buffer containing stream contents\n * @internal\n */\n protected async streamToBuffer(stream: Readable): Promise<Buffer> {\n const chunks: Buffer[] = [];\n for await (const chunk of stream) {\n chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));\n }\n return Buffer.concat(chunks as unknown as Uint8Array[]);\n }\n\n /**\n * Prepend a prefix to a location path\n *\n * Useful for organizing files into directories.\n *\n * @param prefix - Prefix to add (e.g., \"uploads\")\n * @param location - Original location path\n * @returns Combined path with prefix\n *\n * @example\n * ```typescript\n * storage.prepend(\"uploads\", \"image.jpg\"); // \"uploads/image.jpg\"\n * storage.prepend(\"uploads/\", \"/image.jpg\"); // \"uploads/image.jpg\"\n * ```\n */\n public prepend(prefix: string, location: string): string {\n return `${prefix.replace(/\\/$/, \"\")}/${location.replace(/^\\//, \"\")}`;\n }\n\n /**\n * Append a suffix to a location path (before extension)\n *\n * Useful for creating variants of files (thumbnails, etc.).\n *\n * @param location - Original location path\n * @param suffix - Suffix to add before extension\n * @returns Path with suffix added before extension\n *\n * @example\n * ```typescript\n * storage.append(\"image.jpg\", \"_thumb\"); // \"image_thumb.jpg\"\n * storage.append(\"document.pdf\", \"_v2\"); // \"document_v2.pdf\"\n * ```\n */\n public append(location: string, suffix: string): string {\n const lastDot = location.lastIndexOf(\".\");\n if (lastDot === -1) {\n return `${location}${suffix}`;\n }\n return `${location.substring(0, lastDot)}${suffix}${location.substring(lastDot)}`;\n }\n}\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"storage-file.d.mts","names":[],"sources":["../../../../../../../core/src/storage/storage-file.ts"],"mappings":";;;;;;AAqCA;;;;;;;;;;;;;;;;;;;;;;;;cAAa,WAAA;EA6P6B;;;EAAA,UAzP9B,KAAA;EAkS8C;;;EAAA,UA7R9C,OAAA,EAAS,qBAAA;EA4VX;;;EAAA,UAvVE,KAAA,GAAQ,eAAA;EAgWe;;;EAAA,UA3VvB,QAAA;EAmXQ;;;;;;;cA1WC,IAAA,UAAc,MAAA,EAAQ,qBAAA,EAAuB,IAAA,GAAO,eAAA;EAnB7D;;;EAAA,IAgCC,IAAA,CAAA;EAtBD;;;EAAA,IA6BC,IAAA,CAAA;EApBsB;;;EAAA,IA2BtB,SAAA,CAAA;EAPA;;;EAAA,IAcA,SAAA,CAAA;EAcA;;;EAAA,IAPA,MAAA,CAAA;EA6CE;;;EAAA,IAtCF,SAAA,CAAA;EA0DU;;;EAAA,IAnDV,GAAA,CAAA;EAmEkB;;;EAAA,IA3DlB,YAAA,CAAA;EAiFE;;;EAAA,IArEF,IAAA,CAAA;EA6EY;;;EAlEV,IAAA,CAAA,GAAQ,OAAA,CAAQ,eAAA;EAkFhB;;;EA9DA,IAAA,CAAA,GAAQ,OAAA;EAoFR;;;EA5EA,QAAA,CAAA,GAAY,OAAA;EAwFF;;;EAhFV,YAAA,CAAA,GAAgB,OAAA,CAAQ,IAAA;EA2FW;;;EAlFnC,IAAA,CAAA,GAAQ,OAAA;EA4GR;;;EA/FA,QAAA,CAAA,GAAY,OAAA,CAAQ,MAAA;EAyGV;;;EAjGV,MAAA,CAAA,GAAU,OAAA,CAAQ,QAAA;EAkHyB;;;EA1G3C,IAAA,CAAA,GAAQ,OAAA;EA0IR;;;EAlIA,MAAA,CAAA,GAAU,OAAA;EAgKT;;;EAxJD,OAAA,CAAA,GAAW,OAAA;EA0Jd;;;;;EA5IG,YAAA,CAAa,SAAA,YAAmB,OAAA;EA4JhC;;;EAhJA,MAAA,CAAA,GAAU,OAAA;EAgKV;;;;;;EArJA,IAAA,CAAK,WAAA,WAAsB,OAAA,CAAQ,WAAA;EAsL5B;;;;;;EA1KP,IAAA,CAAK,WAAA,WAAsB,OAAA;EA8LtC;;;;;;EAhLW,MAAA,CAAO,OAAA,WAAkB,OAAA;EAqMvB;;;;;EA3LF,MAAA,CAAA,GAAU,OAAA;;;;;;;EAiBV,aAAA,CAAc,UAAA,EAAY,cAAA,GAAiB,OAAA;;;;;;EAgB3C,aAAA,CAAA,GAAiB,OAAA,CAAQ,cAAA;;;;;;;EAgBzB,eAAA,CAAgB,YAAA,WAAuB,OAAA;;;;YAkB1C,gBAAA,CAAA;;;;;;;SAYI,QAAA,CACZ,IAAA,EAAM,eAAA,GAAkB,oBAAA,EACxB,MAAA,EAAQ,qBAAA,GACP,WAAA;;;;EAOU,QAAA,CAAA,GAAY,OAAA,CAAQ,eAAA;;;;EAQpB,OAAA,CAAA,GAAO,OAAA;;;;EAQP,UAAA,CAAA,GAAU,OAAA;;;;EAQV,KAAA,CAAA,GAAK,OAAA;;;;EAQL,OAAA,CAAA,GAAO,OAAA;;;;EAYP,KAAA,CAAA,GAAK,OAAA;;;;EAaL,OAAA,CAAA,GAAO,OAAA;;;;EAQP,OAAA,CAAA,GAAO,OAAA;;;;EAQb,MAAA,CAAA;IACL,IAAA;IACA,IAAA;IACA,SAAA;IACA,MAAA;IACA,GAAA;IACA,IAAA;IACA,IAAA;IACA,QAAA;EAAA;;;;EAiBK,QAAA,CAAA;AAAA"}
1
+ {"version":3,"file":"storage-file.d.mts","names":[],"sources":["../../../../../../../core/src/storage/storage-file.ts"],"mappings":";;;;;;AAqCA;;;;;;;;;;;;;;;;;;;;;;;;cAAa,WAAA;EA6P6B;;;EAAA,UAzP9B,KAAA;EAkS8C;;;EAAA,UA7R9C,OAAA,EAAS,qBAAA;EA4VX;;;EAAA,UAvVE,KAAA,GAAQ,eAAA;EAgWe;;;EAAA,UA3VvB,QAAA;EAmXQ;;;;;;;cA1WC,IAAA,UAAc,MAAA,EAAQ,qBAAA,EAAuB,IAAA,GAAO,eAAA;EAnB7D;;;EAAA,IAgCC,IAAA;EAtBD;;;EAAA,IA6BC,IAAA;EApBsB;;;EAAA,IA2BtB,SAAA;EAPA;;;EAAA,IAcA,SAAA;EAcA;;;EAAA,IAPA,MAAA;EA6CE;;;EAAA,IAtCF,SAAA;EA0DU;;;EAAA,IAnDV,GAAA;EAmEkB;;;EAAA,IA3DlB,YAAA;EAiFE;;;EAAA,IArEF,IAAA;EA6EY;;;EAlEV,IAAA,IAAQ,OAAA,CAAQ,eAAA;EAkFhB;;;EA9DA,IAAA,IAAQ,OAAA;EAoFR;;;EA5EA,QAAA,IAAY,OAAA;EAwFF;;;EAhFV,YAAA,IAAgB,OAAA,CAAQ,IAAA;EA2FW;;;EAlFnC,IAAA,IAAQ,OAAA;EA4GR;;;EA/FA,QAAA,IAAY,OAAA,CAAQ,MAAA;EAyGV;;;EAjGV,MAAA,IAAU,OAAA,CAAQ,QAAA;EAkHyB;;;EA1G3C,IAAA,IAAQ,OAAA;EA0IR;;;EAlIA,MAAA,IAAU,OAAA;EAgKT;;;EAxJD,OAAA,IAAW,OAAA;EA0Jd;;;;;EA5IG,YAAA,CAAa,SAAA,YAAmB,OAAA;EA4JhC;;;EAhJA,MAAA,IAAU,OAAA;EAgKV;;;;;;EArJA,IAAA,CAAK,WAAA,WAAsB,OAAA,CAAQ,WAAA;EAsL5B;;;;;;EA1KP,IAAA,CAAK,WAAA,WAAsB,OAAA;EA8LtC;;;;;;EAhLW,MAAA,CAAO,OAAA,WAAkB,OAAA;EAqMvB;;;;;EA3LF,MAAA,IAAU,OAAA;;;;;;;EAiBV,aAAA,CAAc,UAAA,EAAY,cAAA,GAAiB,OAAA;;;;;;EAgB3C,aAAA,IAAiB,OAAA,CAAQ,cAAA;;;;;;;EAgBzB,eAAA,CAAgB,YAAA,WAAuB,OAAA;;;;YAkB1C,gBAAA;;;;;;;SAYI,QAAA,CACZ,IAAA,EAAM,eAAA,GAAkB,oBAAA,EACxB,MAAA,EAAQ,qBAAA,GACP,WAAA;;;;EAOU,QAAA,IAAY,OAAA,CAAQ,eAAA;;;;EAQpB,OAAA,IAAO,OAAA;;;;EAQP,UAAA,IAAU,OAAA;;;;EAQV,KAAA,IAAK,OAAA;;;;EAQL,OAAA,IAAO,OAAA;;;;EAYP,KAAA,IAAK,OAAA;;;;EAaL,OAAA,IAAO,OAAA;;;;EAQP,OAAA,IAAO,OAAA;;;;EAQb,MAAA;IACL,IAAA;IACA,IAAA;IACA,SAAA;IACA,MAAA;IACA,GAAA;IACA,IAAA;IACA,IAAA;IACA,QAAA;EAAA;;;;EAiBK,QAAA;AAAA"}