@uploadista/core 0.0.12 → 0.0.13-beta.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (100) hide show
  1. package/dist/{checksum-Do_Vh-tB.mjs → checksum-P9C2JlRk.mjs} +2 -2
  2. package/dist/checksum-P9C2JlRk.mjs.map +1 -0
  3. package/dist/{checksum-DgutVB-2.cjs → checksum-jmKtZ9W8.cjs} +1 -1
  4. package/dist/errors/index.cjs +1 -1
  5. package/dist/errors/index.d.cts +1 -1
  6. package/dist/errors/index.d.mts +1 -1
  7. package/dist/errors/index.mjs +1 -1
  8. package/dist/flow/index.cjs +1 -1
  9. package/dist/flow/index.d.cts +5 -5
  10. package/dist/flow/index.d.mts +5 -5
  11. package/dist/flow/index.mjs +1 -1
  12. package/dist/{flow-CpDQ8dgf.mjs → flow-CmDU90LK.mjs} +2 -2
  13. package/dist/flow-CmDU90LK.mjs.map +1 -0
  14. package/dist/{flow-wZzF8vml.cjs → flow-mOCq3uEl.cjs} +1 -1
  15. package/dist/{index-6oHIyVO9.d.cts → index-BPBI84iT.d.mts} +2 -2
  16. package/dist/{index-6oHIyVO9.d.cts.map → index-BPBI84iT.d.mts.map} +1 -1
  17. package/dist/{index-C2nrn_49.d.mts → index-BteFEg-c.d.mts} +2 -2
  18. package/dist/index-BteFEg-c.d.mts.map +1 -0
  19. package/dist/{index-DdT18SQi.d.mts → index-CyxM7UiT.d.mts} +163 -10
  20. package/dist/index-CyxM7UiT.d.mts.map +1 -0
  21. package/dist/{index-CsLVxsad.d.mts → index-DMfADSSJ.d.cts} +2 -2
  22. package/dist/{index-CsLVxsad.d.mts.map → index-DMfADSSJ.d.cts.map} +1 -1
  23. package/dist/{index-DHOYyzYt.d.cts → index-DpnmoaRn.d.cts} +165 -12
  24. package/dist/index-DpnmoaRn.d.cts.map +1 -0
  25. package/dist/{index-eLYBkDBH.d.cts → index-DubOIur4.d.cts} +2 -2
  26. package/dist/index-DubOIur4.d.cts.map +1 -0
  27. package/dist/index.cjs +1 -1
  28. package/dist/index.d.cts +5 -5
  29. package/dist/index.d.mts +5 -5
  30. package/dist/index.mjs +1 -1
  31. package/dist/{stream-limiter-Bj_iImMm.cjs → stream-limiter-D9rrsvAT.cjs} +1 -1
  32. package/dist/{stream-limiter-CEpDLQVB.mjs → stream-limiter-DFtRZczp.mjs} +2 -2
  33. package/dist/{stream-limiter-CEpDLQVB.mjs.map → stream-limiter-DFtRZczp.mjs.map} +1 -1
  34. package/dist/streams/index.cjs +1 -1
  35. package/dist/streams/index.d.cts +2 -2
  36. package/dist/streams/index.d.mts +2 -2
  37. package/dist/streams/index.mjs +1 -1
  38. package/dist/types/index.cjs +1 -1
  39. package/dist/types/index.d.cts +4 -4
  40. package/dist/types/index.d.mts +4 -4
  41. package/dist/types/index.mjs +1 -1
  42. package/dist/{types-BYfvxhhG.mjs → types-DGZ892my.mjs} +2 -2
  43. package/dist/{types-BYfvxhhG.mjs.map → types-DGZ892my.mjs.map} +1 -1
  44. package/dist/{types-C80hlY_o.cjs → types-f08UsX4E.cjs} +1 -1
  45. package/dist/upload/index.cjs +1 -1
  46. package/dist/upload/index.d.cts +4 -4
  47. package/dist/upload/index.d.mts +4 -4
  48. package/dist/upload/index.mjs +1 -1
  49. package/dist/{upload-IZuHoQqL.cjs → upload-D-eiOIVG.cjs} +1 -1
  50. package/dist/{upload-CcmxSO5u.mjs → upload-DJTptYqV.mjs} +2 -2
  51. package/dist/upload-DJTptYqV.mjs.map +1 -0
  52. package/dist/{uploadista-error-DHajuvP1.d.mts → uploadista-error-9yLWP7TC.d.cts} +3 -3
  53. package/dist/uploadista-error-9yLWP7TC.d.cts.map +1 -0
  54. package/dist/{uploadista-error-CQ1ADme7.cjs → uploadista-error-B-n8Kfyh.cjs} +6 -1
  55. package/dist/{uploadista-error-B4dn0Ch6.d.cts → uploadista-error-CBkvsyZ3.d.mts} +3 -3
  56. package/dist/uploadista-error-CBkvsyZ3.d.mts.map +1 -0
  57. package/dist/{uploadista-error-U9YxwNtM.mjs → uploadista-error-nZ_q-EZy.mjs} +6 -1
  58. package/dist/uploadista-error-nZ_q-EZy.mjs.map +1 -0
  59. package/dist/utils/index.cjs +1 -1
  60. package/dist/utils/index.d.cts +2 -2
  61. package/dist/utils/index.d.mts +2 -2
  62. package/dist/utils/index.mjs +1 -1
  63. package/dist/{utils-C6k-Fs99.mjs → utils-BicUw_lt.mjs} +2 -2
  64. package/dist/{utils-C6k-Fs99.mjs.map → utils-BicUw_lt.mjs.map} +1 -1
  65. package/dist/{utils-DzDTNMnq.cjs → utils-_StwBtxT.cjs} +1 -1
  66. package/package.json +3 -3
  67. package/src/errors/__tests__/uploadista-error.test.ts +1 -2
  68. package/src/errors/uploadista-error.ts +28 -3
  69. package/src/flow/flow.ts +40 -33
  70. package/src/flow/index.ts +1 -0
  71. package/src/flow/nodes/input-node.ts +8 -8
  72. package/src/flow/nodes/storage-node.ts +7 -7
  73. package/src/flow/nodes/transform-node.ts +3 -3
  74. package/src/flow/plugins/plugins.ts +3 -0
  75. package/src/flow/plugins/types/resize-node.ts +1 -1
  76. package/src/flow/plugins/video-plugin.ts +181 -0
  77. package/src/flow/typed-flow.ts +52 -52
  78. package/src/flow/types/index.ts +1 -3
  79. package/src/flow/utils/resolve-upload-metadata.ts +2 -2
  80. package/src/types/upload-event.ts +7 -5
  81. package/src/types/upload-file.ts +19 -11
  82. package/src/upload/convert-to-stream.ts +1 -1
  83. package/src/upload/create-upload.ts +11 -11
  84. package/src/upload/mime.ts +12 -13
  85. package/src/upload/upload-chunk.ts +13 -13
  86. package/src/upload/upload-strategy-negotiator.ts +15 -15
  87. package/src/upload/upload-url.ts +14 -14
  88. package/src/upload/write-to-store.ts +10 -10
  89. package/src/utils/checksum.ts +5 -2
  90. package/vitest.config.ts +16 -10
  91. package/dist/checksum-Do_Vh-tB.mjs.map +0 -1
  92. package/dist/flow-CpDQ8dgf.mjs.map +0 -1
  93. package/dist/index-C2nrn_49.d.mts.map +0 -1
  94. package/dist/index-DHOYyzYt.d.cts.map +0 -1
  95. package/dist/index-DdT18SQi.d.mts.map +0 -1
  96. package/dist/index-eLYBkDBH.d.cts.map +0 -1
  97. package/dist/upload-CcmxSO5u.mjs.map +0 -1
  98. package/dist/uploadista-error-B4dn0Ch6.d.cts.map +0 -1
  99. package/dist/uploadista-error-DHajuvP1.d.mts.map +0 -1
  100. package/dist/uploadista-error-U9YxwNtM.mjs.map +0 -1
@@ -77,7 +77,7 @@ export class UploadStrategyNegotiator {
77
77
  */
78
78
  constructor(
79
79
  private capabilities: DataStoreCapabilities,
80
- private validateUploadStrategy: (strategy: UploadStrategy) => boolean
80
+ private validateUploadStrategy: (strategy: UploadStrategy) => boolean,
81
81
  ) {}
82
82
 
83
83
  /**
@@ -128,7 +128,7 @@ export class UploadStrategyNegotiator {
128
128
  if (options.preferredStrategy) {
129
129
  if (!this.validateUploadStrategy(options.preferredStrategy)) {
130
130
  warnings.push(
131
- `Preferred strategy '${options.preferredStrategy}' not supported by data store, falling back`
131
+ `Preferred strategy '${options.preferredStrategy}' not supported by data store, falling back`,
132
132
  );
133
133
  } else {
134
134
  strategy = options.preferredStrategy;
@@ -147,14 +147,14 @@ export class UploadStrategyNegotiator {
147
147
  ) {
148
148
  strategy = "parallel";
149
149
  reasoning.push(
150
- `Selected parallel upload for large file (${options.fileSize} bytes)`
150
+ `Selected parallel upload for large file (${options.fileSize} bytes)`,
151
151
  );
152
152
  } else {
153
153
  strategy = "single";
154
154
  reasoning.push(
155
155
  this.capabilities.supportsParallelUploads
156
156
  ? `Selected single upload for small file (${options.fileSize} bytes)`
157
- : "Selected single upload (parallel not supported by data store)"
157
+ : "Selected single upload (parallel not supported by data store)",
158
158
  );
159
159
  }
160
160
  }
@@ -165,7 +165,7 @@ export class UploadStrategyNegotiator {
165
165
  chunkSize < this.capabilities.minChunkSize
166
166
  ) {
167
167
  warnings.push(
168
- `Chunk size ${chunkSize} below minimum ${this.capabilities.minChunkSize}, adjusting`
168
+ `Chunk size ${chunkSize} below minimum ${this.capabilities.minChunkSize}, adjusting`,
169
169
  );
170
170
  chunkSize = this.capabilities.minChunkSize;
171
171
  }
@@ -175,7 +175,7 @@ export class UploadStrategyNegotiator {
175
175
  chunkSize > this.capabilities.maxChunkSize
176
176
  ) {
177
177
  warnings.push(
178
- `Chunk size ${chunkSize} above maximum ${this.capabilities.maxChunkSize}, adjusting`
178
+ `Chunk size ${chunkSize} above maximum ${this.capabilities.maxChunkSize}, adjusting`,
179
179
  );
180
180
  chunkSize = this.capabilities.maxChunkSize;
181
181
  }
@@ -187,7 +187,7 @@ export class UploadStrategyNegotiator {
187
187
  parallelUploads > this.capabilities.maxConcurrentUploads
188
188
  ) {
189
189
  warnings.push(
190
- `Parallel uploads ${parallelUploads} exceeds maximum ${this.capabilities.maxConcurrentUploads}, adjusting`
190
+ `Parallel uploads ${parallelUploads} exceeds maximum ${this.capabilities.maxConcurrentUploads}, adjusting`,
191
191
  );
192
192
  parallelUploads = this.capabilities.maxConcurrentUploads;
193
193
  }
@@ -197,10 +197,10 @@ export class UploadStrategyNegotiator {
197
197
  const estimatedParts = Math.ceil(options.fileSize / chunkSize);
198
198
  if (estimatedParts > this.capabilities.maxParts) {
199
199
  const minChunkForParts = Math.ceil(
200
- options.fileSize / this.capabilities.maxParts
200
+ options.fileSize / this.capabilities.maxParts,
201
201
  );
202
202
  warnings.push(
203
- `Estimated parts ${estimatedParts} exceeds maximum ${this.capabilities.maxParts}, increasing chunk size`
203
+ `Estimated parts ${estimatedParts} exceeds maximum ${this.capabilities.maxParts}, increasing chunk size`,
204
204
  );
205
205
  chunkSize = Math.max(chunkSize, minChunkForParts);
206
206
  }
@@ -210,7 +210,7 @@ export class UploadStrategyNegotiator {
210
210
  // Final validation - ensure strategy is still valid after adjustments
211
211
  if (!this.validateUploadStrategy(strategy)) {
212
212
  warnings.push(
213
- `Final strategy validation failed, falling back to single upload`
213
+ `Final strategy validation failed, falling back to single upload`,
214
214
  );
215
215
  strategy = "single";
216
216
  parallelUploads = 1;
@@ -218,7 +218,7 @@ export class UploadStrategyNegotiator {
218
218
 
219
219
  // Add capability information to reasoning
220
220
  reasoning.push(
221
- `Data store capabilities: parallel=${this.capabilities.supportsParallelUploads}, concatenation=${this.capabilities.supportsConcatenation}, resumable=${this.capabilities.supportsResumableUploads}`
221
+ `Data store capabilities: parallel=${this.capabilities.supportsParallelUploads}, concatenation=${this.capabilities.supportsConcatenation}, resumable=${this.capabilities.supportsResumableUploads}`,
222
222
  );
223
223
 
224
224
  return {
@@ -275,7 +275,7 @@ export class UploadStrategyNegotiator {
275
275
  !this.validateUploadStrategy(options.preferredStrategy)
276
276
  ) {
277
277
  errors.push(
278
- `Preferred strategy '${options.preferredStrategy}' not supported by data store`
278
+ `Preferred strategy '${options.preferredStrategy}' not supported by data store`,
279
279
  );
280
280
  }
281
281
 
@@ -285,7 +285,7 @@ export class UploadStrategyNegotiator {
285
285
  options.preferredChunkSize < this.capabilities.minChunkSize
286
286
  ) {
287
287
  errors.push(
288
- `Chunk size ${options.preferredChunkSize} below data store minimum ${this.capabilities.minChunkSize}`
288
+ `Chunk size ${options.preferredChunkSize} below data store minimum ${this.capabilities.minChunkSize}`,
289
289
  );
290
290
  }
291
291
  if (
@@ -293,7 +293,7 @@ export class UploadStrategyNegotiator {
293
293
  options.preferredChunkSize > this.capabilities.maxChunkSize
294
294
  ) {
295
295
  errors.push(
296
- `Chunk size ${options.preferredChunkSize} above data store maximum ${this.capabilities.maxChunkSize}`
296
+ `Chunk size ${options.preferredChunkSize} above data store maximum ${this.capabilities.maxChunkSize}`,
297
297
  );
298
298
  }
299
299
  }
@@ -304,7 +304,7 @@ export class UploadStrategyNegotiator {
304
304
  options.parallelUploads > this.capabilities.maxConcurrentUploads
305
305
  ) {
306
306
  errors.push(
307
- `Parallel uploads ${options.parallelUploads} exceeds data store maximum ${this.capabilities.maxConcurrentUploads}`
307
+ `Parallel uploads ${options.parallelUploads} exceeds data store maximum ${this.capabilities.maxConcurrentUploads}`,
308
308
  );
309
309
  }
310
310
 
@@ -59,7 +59,7 @@ export const fetchFile = (url: string) => {
59
59
  yield* Metric.increment(
60
60
  Metric.counter("upload_from_url_total", {
61
61
  description: "Total number of URL-based uploads",
62
- })
62
+ }),
63
63
  );
64
64
 
65
65
  // Track success/failure
@@ -67,10 +67,10 @@ export const fetchFile = (url: string) => {
67
67
  yield* Metric.increment(
68
68
  Metric.counter("upload_from_url_success_total", {
69
69
  description: "Total number of successful URL-based uploads",
70
- })
70
+ }),
71
71
  );
72
72
  }
73
- })
73
+ }),
74
74
  ),
75
75
  // Add structured logging
76
76
  Effect.tap((response) =>
@@ -81,8 +81,8 @@ export const fetchFile = (url: string) => {
81
81
  "response.ok": response.ok.toString(),
82
82
  "response.content_length":
83
83
  response.headers.get("content-length") ?? "unknown",
84
- })
85
- )
84
+ }),
85
+ ),
86
86
  ),
87
87
  // Handle errors with logging and metrics
88
88
  Effect.tapError((error) =>
@@ -91,7 +91,7 @@ export const fetchFile = (url: string) => {
91
91
  yield* Metric.increment(
92
92
  Metric.counter("upload_from_url_failed_total", {
93
93
  description: "Total number of failed URL-based uploads",
94
- })
94
+ }),
95
95
  );
96
96
 
97
97
  // Log error
@@ -99,10 +99,10 @@ export const fetchFile = (url: string) => {
99
99
  Effect.annotateLogs({
100
100
  "upload.url": url,
101
101
  error: String(error),
102
- })
102
+ }),
103
103
  );
104
- })
105
- )
104
+ }),
105
+ ),
106
106
  );
107
107
  };
108
108
 
@@ -158,16 +158,16 @@ export const arrayBuffer = (response: Response) => {
158
158
  Effect.logDebug("Response converted to array buffer").pipe(
159
159
  Effect.annotateLogs({
160
160
  "buffer.size": buffer.byteLength.toString(),
161
- })
162
- )
161
+ }),
162
+ ),
163
163
  ),
164
164
  // Handle errors with logging
165
165
  Effect.tapError((error) =>
166
166
  Effect.logError("Failed to convert response to array buffer").pipe(
167
167
  Effect.annotateLogs({
168
168
  error: String(error),
169
- })
170
- )
171
- )
169
+ }),
170
+ ),
171
+ ),
172
172
  );
173
173
  };
@@ -149,13 +149,13 @@ export function writeToStore({
149
149
  }
150
150
  return Effect.void;
151
151
  }),
152
- Effect.runPromise
152
+ Effect.runPromise,
153
153
  )
154
154
  .catch(() => {
155
155
  // Ignore errors during progress emission
156
156
  });
157
157
  },
158
- }
158
+ },
159
159
  );
160
160
 
161
161
  return offset;
@@ -168,14 +168,14 @@ export function writeToStore({
168
168
  return Effect.fail(error);
169
169
  }
170
170
  return Effect.fail(
171
- UploadistaError.fromCode("FILE_WRITE_ERROR", { cause: error })
171
+ UploadistaError.fromCode("FILE_WRITE_ERROR", { cause: error }),
172
172
  );
173
- })
173
+ }),
174
174
  ),
175
175
  ({ onAbort }) =>
176
176
  Effect.sync(() => {
177
177
  controller.signal.removeEventListener("abort", onAbort);
178
- })
178
+ }),
179
179
  );
180
180
  }).pipe(
181
181
  // Add tracing span for write operation
@@ -194,8 +194,8 @@ export function writeToStore({
194
194
  "upload.id": upload.id,
195
195
  "write.offset": offset.toString(),
196
196
  "write.bytes_written": (offset - upload.offset).toString(),
197
- })
198
- )
197
+ }),
198
+ ),
199
199
  ),
200
200
  // Handle errors with logging
201
201
  Effect.tapError((error) =>
@@ -204,8 +204,8 @@ export function writeToStore({
204
204
  "upload.id": upload.id,
205
205
  "upload.offset": upload.offset.toString(),
206
206
  error: error instanceof UploadistaError ? error.code : String(error),
207
- })
208
- )
209
- )
207
+ }),
208
+ ),
209
+ ),
210
210
  );
211
211
  }
@@ -10,7 +10,9 @@ export type ChecksumAlgorithm = (typeof SUPPORTED_ALGORITHMS)[number];
10
10
  /**
11
11
  * Check if a checksum algorithm is supported
12
12
  */
13
- export function isSupportedAlgorithm(algorithm: string): algorithm is ChecksumAlgorithm {
13
+ export function isSupportedAlgorithm(
14
+ algorithm: string,
15
+ ): algorithm is ChecksumAlgorithm {
14
16
  return SUPPORTED_ALGORITHMS.includes(algorithm as ChecksumAlgorithm);
15
17
  }
16
18
 
@@ -41,7 +43,8 @@ export function computeChecksum(
41
43
  // Compute hash using Web Crypto API (available in browsers, Node.js 15+, Deno, Bun, Cloudflare Workers)
42
44
  // Pass Uint8Array directly - it's a valid BufferSource
43
45
  const hashBuffer = yield* Effect.tryPromise({
44
- try: () => crypto.subtle.digest(webCryptoAlgorithm, bytes as BufferSource),
46
+ try: () =>
47
+ crypto.subtle.digest(webCryptoAlgorithm, bytes as BufferSource),
45
48
  catch: (error) =>
46
49
  UploadistaError.fromCode("UNKNOWN_ERROR", {
47
50
  body: `Failed to compute checksum: ${error instanceof Error ? error.message : "Unknown error"}`,
package/vitest.config.ts CHANGED
@@ -1,15 +1,21 @@
1
- import { defineConfig } from 'vitest/config';
1
+ import { defineConfig } from "vitest/config";
2
2
 
3
3
  export default defineConfig({
4
4
  test: {
5
5
  globals: true,
6
- environment: 'node',
7
- include: ['src/**/*.{test,spec}.{js,mjs,cjs,ts,mts,cts,jsx,tsx}'],
8
- exclude: ['node_modules', 'dist'],
6
+ environment: "node",
7
+ include: ["src/**/*.{test,spec}.{js,mjs,cjs,ts,mts,cts,jsx,tsx}"],
8
+ exclude: ["node_modules", "dist"],
9
9
  coverage: {
10
- provider: 'v8',
11
- reporter: ['text', 'json', 'html'],
12
- exclude: ['node_modules/', 'dist/', '**/*.d.ts', '**/*.test.ts', '**/*.spec.ts']
13
- }
14
- }
15
- });
10
+ provider: "v8",
11
+ reporter: ["text", "json", "html"],
12
+ exclude: [
13
+ "node_modules/",
14
+ "dist/",
15
+ "**/*.d.ts",
16
+ "**/*.test.ts",
17
+ "**/*.spec.ts",
18
+ ],
19
+ },
20
+ },
21
+ });
@@ -1 +0,0 @@
1
- {"version":3,"file":"checksum-Do_Vh-tB.mjs","names":[],"sources":["../src/utils/generate-id.ts","../src/utils/checksum.ts"],"sourcesContent":["import { Context, Effect, Layer } from \"effect\";\n\nexport type GenerateIdShape = {\n generateId: () => Effect.Effect<string>;\n};\n\n// Declaring a tag for a service that generates random id\nexport class GenerateId extends Context.Tag(\"UploadistaGenerateIdService\")<\n GenerateId,\n { readonly generateId: () => Effect.Effect<string> }\n>() {}\n\n/**\n * Effect-based ID generation services\n */\nexport const GenerateIdService = GenerateId.Service;\n\n/**\n * Generates a random UUID using Effect\n * @returns Effect that produces a random UUID string\n */\nexport const GenerateIdRandom = GenerateId.of({\n generateId: () => Effect.succeed(crypto.randomUUID()),\n});\n\nexport const GenerateIdLive = Layer.succeed(GenerateId, GenerateIdRandom);\n\n/**\n * Generates a timestamp-based ID using Effect\n * @returns Effect that produces a timestamp-based ID\n */\nexport const GenerateIdTimestamp = GenerateId.of({\n generateId: () =>\n Effect.succeed(`${Date.now()}-${Math.random().toString(36).slice(2, 11)}`),\n});\n","import { Effect } from \"effect\";\nimport { UploadistaError } from \"../errors/uploadista-error\";\n\n/**\n * Supported checksum algorithms\n */\nconst SUPPORTED_ALGORITHMS = [\"sha256\"] as const;\nexport type ChecksumAlgorithm = (typeof SUPPORTED_ALGORITHMS)[number];\n\n/**\n * Check if a checksum algorithm is supported\n */\nexport function isSupportedAlgorithm(algorithm: string): algorithm is ChecksumAlgorithm {\n return SUPPORTED_ALGORITHMS.includes(algorithm as ChecksumAlgorithm);\n}\n\n/**\n * Compute checksum of file bytes using the Web Crypto API.\n * This works across all modern platforms: browsers, Node.js 15+, Deno, Bun, and Cloudflare Workers.\n *\n * @param bytes - File content as Uint8Array\n * @param algorithm - Hashing algorithm to use (currently only 'sha256' is supported)\n * @returns Effect that resolves to hex-encoded checksum string\n */\nexport function computeChecksum(\n bytes: Uint8Array,\n algorithm: string,\n): Effect.Effect<string, UploadistaError> {\n return Effect.gen(function* () {\n // Validate algorithm is supported\n if (!isSupportedAlgorithm(algorithm)) {\n return yield* UploadistaError.fromCode(\"UNSUPPORTED_CHECKSUM_ALGORITHM\", {\n body: `Checksum algorithm '${algorithm}' is not supported. Supported algorithms: ${SUPPORTED_ALGORITHMS.join(\", \")}`,\n details: { algorithm, supportedAlgorithms: SUPPORTED_ALGORITHMS },\n }).toEffect();\n }\n\n // Map algorithm name to Web Crypto API algorithm name\n const webCryptoAlgorithm = algorithm.toUpperCase().replace(/\\d+/, \"-$&\"); // \"sha256\" -> \"SHA-256\"\n\n // Compute hash using Web Crypto API (available in browsers, Node.js 15+, Deno, Bun, Cloudflare Workers)\n // Pass Uint8Array directly - it's a valid BufferSource\n const hashBuffer = yield* Effect.tryPromise({\n try: () => crypto.subtle.digest(webCryptoAlgorithm, bytes as BufferSource),\n catch: (error) =>\n UploadistaError.fromCode(\"UNKNOWN_ERROR\", {\n body: `Failed to compute checksum: ${error instanceof Error ? error.message : \"Unknown error\"}`,\n cause: error,\n details: { algorithm },\n }),\n });\n\n // Convert ArrayBuffer to hex string\n const hashArray = Array.from(new Uint8Array(hashBuffer));\n const hashHex = hashArray\n .map((byte) => byte.toString(16).padStart(2, \"0\"))\n .join(\"\");\n\n return hashHex;\n });\n}\n"],"mappings":"4GAOA,IAAa,EAAb,cAAgC,EAAQ,IAAI,8BAA8B,EAGvE,AAAC,GAKJ,MAAa,EAAoB,EAAW,QAM/B,EAAmB,EAAW,GAAG,CAC5C,eAAkB,EAAO,QAAQ,OAAO,YAAY,CAAC,CACtD,CAAC,CAEW,EAAiB,EAAM,QAAQ,EAAY,EAAiB,CAM5D,EAAsB,EAAW,GAAG,CAC/C,eACE,EAAO,QAAQ,GAAG,KAAK,KAAK,CAAC,GAAG,KAAK,QAAQ,CAAC,SAAS,GAAG,CAAC,MAAM,EAAG,GAAG,GAAG,CAC7E,CAAC,CC5BI,EAAuB,CAAC,SAAS,CAMvC,SAAgB,EAAqB,EAAmD,CACtF,OAAO,EAAqB,SAAS,EAA+B,CAWtE,SAAgB,EACd,EACA,EACwC,CACxC,OAAO,EAAO,IAAI,WAAa,CAE7B,GAAI,CAAC,EAAqB,EAAU,CAClC,OAAO,MAAO,EAAgB,SAAS,iCAAkC,CACvE,KAAM,uBAAuB,EAAU,4CAA4C,EAAqB,KAAK,KAAK,GAClH,QAAS,CAAE,YAAW,oBAAqB,EAAsB,CAClE,CAAC,CAAC,UAAU,CAIf,IAAM,EAAqB,EAAU,aAAa,CAAC,QAAQ,MAAO,MAAM,CAIlE,EAAa,MAAO,EAAO,WAAW,CAC1C,QAAW,OAAO,OAAO,OAAO,EAAoB,EAAsB,CAC1E,MAAQ,GACN,EAAgB,SAAS,gBAAiB,CACxC,KAAM,+BAA+B,aAAiB,MAAQ,EAAM,QAAU,kBAC9E,MAAO,EACP,QAAS,CAAE,YAAW,CACvB,CAAC,CACL,CAAC,CAQF,OALkB,MAAM,KAAK,IAAI,WAAW,EAAW,CAAC,CAErD,IAAK,GAAS,EAAK,SAAS,GAAG,CAAC,SAAS,EAAG,IAAI,CAAC,CACjD,KAAK,GAAG,EAGX"}