@tranquilload/core 0.1.0 → 0.1.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 (55) hide show
  1. package/.turbo/turbo-build.log +68 -68
  2. package/CHANGELOG.md +67 -0
  3. package/dist/errors.cjs +3 -1
  4. package/dist/errors.d.cts +2 -2
  5. package/dist/errors.d.mts +2 -2
  6. package/dist/errors.mjs +2 -2
  7. package/dist/index-BaeUV_fj.d.cts +139 -0
  8. package/dist/index-BaeUV_fj.d.cts.map +1 -0
  9. package/dist/index-bpWq6tje.d.mts +139 -0
  10. package/dist/index-bpWq6tje.d.mts.map +1 -0
  11. package/dist/multipart.cjs +80 -12
  12. package/dist/multipart.cjs.map +1 -1
  13. package/dist/multipart.d.cts +2 -2
  14. package/dist/multipart.d.mts +2 -2
  15. package/dist/multipart.mjs +80 -12
  16. package/dist/multipart.mjs.map +1 -1
  17. package/dist/{normalize-callback-BNBZZ1jT.cjs → normalize-callback-BdLtk9jb.cjs} +2 -2
  18. package/dist/{normalize-callback-BNBZZ1jT.cjs.map → normalize-callback-BdLtk9jb.cjs.map} +1 -1
  19. package/dist/{normalize-callback-DQ6C4gaV.mjs → normalize-callback-tcZ_nyq5.mjs} +2 -2
  20. package/dist/{normalize-callback-DQ6C4gaV.mjs.map → normalize-callback-tcZ_nyq5.mjs.map} +1 -1
  21. package/dist/oneshot.cjs +2 -2
  22. package/dist/oneshot.d.cts +2 -2
  23. package/dist/oneshot.d.mts +2 -2
  24. package/dist/oneshot.mjs +2 -2
  25. package/dist/progress.d.cts +2 -2
  26. package/dist/progress.d.mts +2 -2
  27. package/dist/{upload-error-BUexBh08.cjs → upload-error-BG1dOOl3.cjs} +26 -1
  28. package/dist/upload-error-BG1dOOl3.cjs.map +1 -0
  29. package/dist/{upload-error-B2ISUc_k.d.cts → upload-error-DTYVNlaJ.d.cts} +19 -3
  30. package/dist/{upload-error-B2ISUc_k.d.cts.map → upload-error-DTYVNlaJ.d.cts.map} +1 -1
  31. package/dist/{upload-error-zDvpxT9X.mjs → upload-error-Dbz_9j81.mjs} +21 -2
  32. package/dist/upload-error-Dbz_9j81.mjs.map +1 -0
  33. package/dist/{upload-error-jol-eoDW.d.mts → upload-error-jBco270d.d.mts} +19 -3
  34. package/dist/{upload-error-jol-eoDW.d.mts.map → upload-error-jBco270d.d.mts.map} +1 -1
  35. package/dist/{upload-event-C9TOVp5l.d.mts → upload-event-BT_nXgM9.d.cts} +7 -1
  36. package/dist/upload-event-BT_nXgM9.d.cts.map +1 -0
  37. package/dist/{upload-event-D77olieX.d.cts → upload-event-DOGbegxa.d.mts} +7 -1
  38. package/dist/upload-event-DOGbegxa.d.mts.map +1 -0
  39. package/package.json +1 -1
  40. package/src/errors/index.ts +2 -0
  41. package/src/errors/upload-error.test.ts +35 -0
  42. package/src/errors/upload-error.ts +27 -0
  43. package/src/multipart/index.test.ts +164 -1
  44. package/src/multipart/index.ts +96 -5
  45. package/src/multipart/upload-stream.test.ts +201 -2
  46. package/src/multipart/upload-stream.ts +160 -16
  47. package/src/progress/upload-event.ts +6 -0
  48. package/dist/index-Ch8xM6Xt.d.cts +0 -60
  49. package/dist/index-Ch8xM6Xt.d.cts.map +0 -1
  50. package/dist/index-DBGtgXEd.d.mts +0 -60
  51. package/dist/index-DBGtgXEd.d.mts.map +0 -1
  52. package/dist/upload-error-BUexBh08.cjs.map +0 -1
  53. package/dist/upload-error-zDvpxT9X.mjs.map +0 -1
  54. package/dist/upload-event-C9TOVp5l.d.mts.map +0 -1
  55. package/dist/upload-event-D77olieX.d.cts.map +0 -1
@@ -1,6 +1,6 @@
1
1
  import { Cause, Effect, Exit, Option, Ref, Schedule, Stream } from "effect"
2
2
  import type { UploadError } from "../errors/upload-error.js"
3
- import { CircuitOpenError, CompleteUploadError, InitiateUploadError, MaxRetriesExceededError, PartUploadError, ReconcileError } from "../errors/upload-error.js"
3
+ import { CircuitOpenError, CompleteUploadError, InitiateUploadError, MaxRetriesExceededError, PartUploadError, ReconcileError, ResumeMismatchError } from "../errors/upload-error.js"
4
4
  import type { CircuitOpen, PartCompleted, ProgressTick, UploadCompleted, UploadEvent, UploadInitiated } from "../progress/upload-event.js"
5
5
  import { LoggerService } from "../services/logger-service.js"
6
6
  import { fromAbortSignal } from "../utils/abort-interop.js"
@@ -13,6 +13,35 @@ export interface CompletedPart {
13
13
  readonly etag: string
14
14
  }
15
15
 
16
+ /**
17
+ * Opaque resume metadata returned by `uploadMultipart` and persisted by the
18
+ * caller (typically `JSON.stringify` → localStorage). Pass it back as
19
+ * `resumeFrom` on the next session.
20
+ *
21
+ * The lib validates `version`, `chunkSize`, `pipelineIdentity`, and the content
22
+ * digest before any byte is uploaded. A mismatch fails the upload with a typed
23
+ * `ResumeMismatchError` — preventing the silent-corruption classes documented
24
+ * in the v0.2.x release notes.
25
+ *
26
+ * **Schema versioning.** The `version: 1` literal is a tripwire for schema
27
+ * evolution: future v2 schemas widen this union, and a persisted v1 state
28
+ * passed to a future v2 lib will fail with `ResumeMismatchError("version_mismatch")`
29
+ * rather than silently misinterpreting old fields.
30
+ */
31
+ export interface ResumeState {
32
+ readonly version: 1
33
+ readonly uploadId: string
34
+ readonly chunkSize: number
35
+ readonly pipelineIdentity?: string
36
+ readonly contentDigest?: string
37
+ /**
38
+ * True if the original session captured a digest. Detects persistence layers
39
+ * that drop the `contentDigest` field (which would otherwise silently bypass
40
+ * content-mismatch validation).
41
+ */
42
+ readonly contentDigestCaptured: boolean
43
+ }
44
+
16
45
  export interface UploadMultipartOptions {
17
46
  readonly stream: ReadableStream<Uint8Array>
18
47
  readonly chunkSize: number
@@ -32,6 +61,59 @@ export interface UploadMultipartOptions {
32
61
  | ReadonlyArray<CompletedPart>
33
62
  | Promise<ReadonlyArray<CompletedPart>>
34
63
  | Effect.Effect<ReadonlyArray<CompletedPart>, UploadError>
64
+ /**
65
+ * Resume metadata persisted from a previous session. When set, the lib skips
66
+ * the `initiate` callback (the `uploadId` is read from `resumeFrom`) and
67
+ * validates `version`, `chunkSize`, `pipelineIdentity`, and `contentDigest`
68
+ * before any byte is uploaded. A mismatch fails the upload with
69
+ * `ResumeMismatchError`.
70
+ *
71
+ * Synchronous (pre-flight) validation happens at `uploadMultipart()` call
72
+ * time — `TypeError` for an empty `uploadId`, `ResumeMismatchError` for the
73
+ * rest. The asynchronous content-digest *value* match is verified inside
74
+ * the Effect once the upload stream is consumed.
75
+ */
76
+ readonly resumeFrom?: ResumeState
77
+ /**
78
+ * Called once on fresh initiate to capture a digest of the source content.
79
+ * On a subsequent resume session, called again and compared to
80
+ * `resumeFrom.contentDigest`; a mismatch fails the upload with
81
+ * `ResumeMismatchError("content_mismatch")` before any byte is uploaded.
82
+ *
83
+ * **MUST be lightweight and stable across sessions.** Suggested patterns:
84
+ * - Browser `File`: `` `${name}|${size}|${lastModified}` ``
85
+ * - Node `Readable` from a file: `` `${path}|${stat.size}|${stat.mtimeMs}` ``
86
+ * - Synchronous strings; avoid full-file crypto hashes on the synchronous path.
87
+ *
88
+ * **MUST NOT consume bytes from the source stream** (passed in
89
+ * `options.stream`). The lib calls `getContentDigest` before any chunk is
90
+ * pulled from the source; consuming from the source here will produce a
91
+ * zero-byte upload because no bytes remain for `chunkStream`.
92
+ */
93
+ readonly getContentDigest?: () =>
94
+ | string
95
+ | Promise<string>
96
+ | Effect.Effect<string, UploadError>
97
+ /**
98
+ * An opaque, stable identifier for the upstream pipeline composition.
99
+ * Captured in `ResumeState` and validated strict-equality on resume.
100
+ * **You own keeping this stable** — if you configure `compress("deflate-raw")`
101
+ * in session A, you must pass the same `pipelineIdentity` on resume.
102
+ *
103
+ * **Strict equality limitation:** a pipeline that is logically identical but
104
+ * produces different identifier strings (e.g. tag bumps, version-stamped
105
+ * strings) triggers `ResumeMismatchError("pipeline_mismatch")`. Pick a stable
106
+ * string (e.g. `"deflate-raw-v1"`) and only change it when the pipeline's
107
+ * *byte-level output* changes.
108
+ *
109
+ * **Compression non-determinism caveat:** even with identical
110
+ * `pipelineIdentity`, a non-deterministic pipeline (e.g. gzip with `mtime`
111
+ * headers, encryption with random salt) produces different bytes per run.
112
+ * Resume against the same uploaded parts only works if the pipeline is
113
+ * byte-deterministic. Verify your pipeline's determinism before relying on
114
+ * this.
115
+ */
116
+ readonly pipelineIdentity?: string
35
117
  readonly maxConcurrency?: number
36
118
  readonly signal?: AbortSignal
37
119
  readonly retrySchedule?: Schedule.Schedule<unknown, PartUploadError>
@@ -55,11 +137,43 @@ export const uploadMultipartEffect = (
55
137
  completeUpload,
56
138
  initiate,
57
139
  reconcileCompletedParts,
140
+ resumeFrom,
141
+ getContentDigest,
142
+ pipelineIdentity,
58
143
  maxConcurrency = DEFAULT_MAX_CONCURRENCY,
59
144
  signal,
60
145
  retrySchedule = DEFAULT_RETRY_SCHEDULE,
61
146
  } = options
62
147
 
148
+ if (!Number.isFinite(chunkSize) || chunkSize <= 0) {
149
+ throw new TypeError(
150
+ `uploadMultipart: chunkSize must be a positive finite number, got ${chunkSize}`
151
+ )
152
+ }
153
+
154
+ if (resumeFrom !== undefined) {
155
+ if (typeof resumeFrom.uploadId !== "string" || resumeFrom.uploadId === "") {
156
+ throw new TypeError(
157
+ "uploadMultipart: ResumeState.uploadId must be a non-empty string"
158
+ )
159
+ }
160
+ if (resumeFrom.version !== 1) {
161
+ throw new ResumeMismatchError("version_mismatch")
162
+ }
163
+ if (resumeFrom.chunkSize !== chunkSize) {
164
+ throw new ResumeMismatchError("chunksize_mismatch")
165
+ }
166
+ if (resumeFrom.pipelineIdentity !== pipelineIdentity) {
167
+ throw new ResumeMismatchError("pipeline_mismatch")
168
+ }
169
+ if (
170
+ resumeFrom.contentDigestCaptured === true &&
171
+ resumeFrom.contentDigest === undefined
172
+ ) {
173
+ throw new ResumeMismatchError("content_mismatch")
174
+ }
175
+ }
176
+
63
177
  return Stream.unwrap(
64
178
  Effect.gen(function* () {
65
179
  const logger = yield* LoggerService
@@ -67,6 +181,7 @@ export const uploadMultipartEffect = (
67
181
  const refParts = yield* Ref.make<CompletedPart[]>([])
68
182
  const refBytesUploaded = yield* Ref.make(0)
69
183
  const refUploadId = yield* Ref.make("")
184
+ const refDigest = yield* Ref.make<Option.Option<string>>(Option.none())
70
185
  const breaker = options.circuitBreaker
71
186
  ? yield* makeCircuitBreaker(options.circuitBreaker)
72
187
  : null
@@ -79,22 +194,51 @@ export const uploadMultipartEffect = (
79
194
  )
80
195
  : new Map()
81
196
 
82
- const initiateStream: Stream.Stream<UploadEvent, UploadError, never> = initiate
83
- ? Stream.fromEffect(
84
- normalizeCallback(initiate).pipe(
85
- Effect.mapError((cause): UploadError => new InitiateUploadError(cause)),
86
- Effect.flatMap(({ uploadId }) =>
87
- Ref.set(refUploadId, uploadId).pipe(
88
- Effect.as({
89
- _tag: "UploadInitiated" as const,
90
- uploadId,
91
- timestamp: Date.now(),
92
- } satisfies UploadInitiated)
93
- )
94
- )
197
+ const runFreshInit: Effect.Effect<UploadInitiated, UploadError> = Effect.gen(
198
+ function* () {
199
+ const { uploadId } = yield* normalizeCallback(initiate!).pipe(
200
+ Effect.mapError((cause): UploadError => new InitiateUploadError(cause))
201
+ )
202
+ yield* Ref.set(refUploadId, uploadId)
203
+ if (getContentDigest !== undefined) {
204
+ const digest = yield* normalizeCallback(getContentDigest).pipe(
205
+ Effect.mapError((cause): UploadError => new InitiateUploadError(cause))
206
+ )
207
+ yield* Ref.set(refDigest, Option.some(digest))
208
+ }
209
+ const capturedDigest = yield* Ref.get(refDigest)
210
+ return {
211
+ _tag: "UploadInitiated" as const,
212
+ uploadId,
213
+ contentDigest: Option.getOrUndefined(capturedDigest),
214
+ timestamp: Date.now(),
215
+ } satisfies UploadInitiated
216
+ }
217
+ )
218
+
219
+ const runResumeSetup: Effect.Effect<void, UploadError> = Effect.gen(function* () {
220
+ // `resumeFrom` is non-undefined here (checked by setupStream selector below).
221
+ const rf = resumeFrom!
222
+ if (rf.contentDigest !== undefined && getContentDigest !== undefined) {
223
+ const digest = yield* normalizeCallback(getContentDigest).pipe(
224
+ Effect.mapError(
225
+ (cause): UploadError => new ResumeMismatchError("content_mismatch", cause)
95
226
  )
96
227
  )
97
- : Stream.empty
228
+ if (digest !== rf.contentDigest) {
229
+ return yield* Effect.fail(new ResumeMismatchError("content_mismatch"))
230
+ }
231
+ yield* Ref.set(refDigest, Option.some(digest))
232
+ }
233
+ yield* Ref.set(refUploadId, rf.uploadId)
234
+ })
235
+
236
+ const setupStream: Stream.Stream<UploadEvent, UploadError, never> =
237
+ resumeFrom !== undefined
238
+ ? Stream.fromEffect(runResumeSetup).pipe(Stream.drain)
239
+ : initiate !== undefined
240
+ ? Stream.fromEffect(runFreshInit)
241
+ : Stream.empty
98
242
 
99
243
  const makeUploadOne = (
100
244
  partNumber: number,
@@ -240,7 +384,7 @@ export const uploadMultipartEffect = (
240
384
  }
241
385
  )
242
386
 
243
- return Stream.concat(initiateStream, partsStream.pipe(Stream.concat(Stream.fromEffect(finalEffect))))
387
+ return Stream.concat(setupStream, partsStream.pipe(Stream.concat(Stream.fromEffect(finalEffect))))
244
388
  })
245
389
  )
246
390
  }
@@ -3,6 +3,12 @@ import { Option } from "effect"
3
3
  export interface UploadInitiated {
4
4
  readonly _tag: "UploadInitiated"
5
5
  readonly uploadId: string
6
+ /**
7
+ * Populated when `getContentDigest` was provided on the fresh-init path.
8
+ * Carried on the event so the public wrapper can build a complete `ResumeState`
9
+ * without needing access to the internal digest Ref.
10
+ */
11
+ readonly contentDigest?: string
6
12
  readonly timestamp: number
7
13
  }
8
14
 
@@ -1,60 +0,0 @@
1
- import { a as PartUploadError, c as UploadError } from "./upload-error-B2ISUc_k.cjs";
2
- import { n as LoggerService } from "./logger-service-CbN12RhO.cjs";
3
- import { a as UploadEvent, i as UploadCompleted } from "./upload-event-D77olieX.cjs";
4
- import { t as Transform } from "./middleware-CYcctmlY.cjs";
5
- import { Effect, Option, Schedule, Stream } from "effect";
6
-
7
- //#region src/multipart/circuit-breaker.d.ts
8
- interface CircuitBreakerConfig {
9
- readonly threshold: number;
10
- readonly cooldown: number;
11
- }
12
- //#endregion
13
- //#region src/multipart/upload-stream.d.ts
14
- interface CompletedPart {
15
- readonly partNumber: number;
16
- readonly etag: string;
17
- }
18
- interface UploadMultipartOptions {
19
- readonly stream: ReadableStream<Uint8Array>;
20
- readonly chunkSize: number;
21
- readonly uploadPart: (partNumber: number, chunk: Uint8Array) => string | Promise<string> | Effect.Effect<string, UploadError>;
22
- readonly completeUpload: (uploadId: string, parts: ReadonlyArray<CompletedPart>) => void | Promise<void> | Effect.Effect<void, UploadError>;
23
- readonly initiate?: () => {
24
- uploadId: string;
25
- } | Promise<{
26
- uploadId: string;
27
- }> | Effect.Effect<{
28
- uploadId: string;
29
- }, UploadError>;
30
- readonly reconcileCompletedParts?: () => ReadonlyArray<CompletedPart> | Promise<ReadonlyArray<CompletedPart>> | Effect.Effect<ReadonlyArray<CompletedPart>, UploadError>;
31
- readonly maxConcurrency?: number;
32
- readonly signal?: AbortSignal;
33
- readonly retrySchedule?: Schedule.Schedule<unknown, PartUploadError>;
34
- readonly circuitBreaker?: CircuitBreakerConfig;
35
- }
36
- //#endregion
37
- //#region src/multipart/index.d.ts
38
- type UploadResult = UploadCompleted;
39
- interface Progress {
40
- readonly bytesUploaded: number;
41
- readonly totalBytes: Option.Option<number>;
42
- }
43
- interface MultipartPublicOptions extends UploadMultipartOptions {
44
- readonly totalBytes?: number;
45
- readonly pipeline?: Transform | Effect.Effect<Transform, unknown, unknown>;
46
- }
47
- declare const uploadMultipart: {
48
- (options: MultipartPublicOptions): {
49
- events: ReadableStream<UploadEvent>;
50
- result: Promise<UploadResult>;
51
- getProgress: (() => Promise<Progress>) & {
52
- effect: Effect.Effect<Progress>;
53
- };
54
- uploadId: Promise<string>;
55
- };
56
- effect: (options: UploadMultipartOptions) => Stream.Stream<UploadEvent, UploadError, LoggerService>;
57
- };
58
- //#endregion
59
- export { CompletedPart as a, uploadMultipart as i, Progress as n, UploadMultipartOptions as o, UploadResult as r, MultipartPublicOptions as t };
60
- //# sourceMappingURL=index-Ch8xM6Xt.d.cts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"index-Ch8xM6Xt.d.cts","names":[],"sources":["../src/multipart/circuit-breaker.ts","../src/multipart/upload-stream.ts","../src/multipart/index.ts"],"mappings":";;;;;;;UAIiB,oBAAA;EAAA,SACN,SAAA;EAAA,SACA,QAAA;AAAA;;;UCIM,aAAA;EAAA,SACN,UAAA;EAAA,SACA,IAAA;AAAA;AAAA,UAGM,sBAAA;EAAA,SACN,MAAA,EAAQ,cAAA,CAAe,UAAA;EAAA,SACvB,SAAA;EAAA,SACA,UAAA,GACP,UAAA,UACA,KAAA,EAAO,UAAA,cACK,OAAA,WAAkB,MAAA,CAAO,MAAA,SAAe,WAAA;EAAA,SAC7C,cAAA,GACP,QAAA,UACA,KAAA,EAAO,aAAA,CAAc,aAAA,aACX,OAAA,SAAgB,MAAA,CAAO,MAAA,OAAa,WAAA;EAAA,SACvC,QAAA;IACH,QAAA;EAAA,IACF,OAAA;IAAU,QAAA;EAAA,KACV,MAAA,CAAO,MAAA;IAAS,QAAA;EAAA,GAAoB,WAAA;EAAA,SAC/B,uBAAA,SACL,aAAA,CAAc,aAAA,IACd,OAAA,CAAQ,aAAA,CAAc,aAAA,KACtB,MAAA,CAAO,MAAA,CAAO,aAAA,CAAc,aAAA,GAAgB,WAAA;EAAA,SACvC,cAAA;EAAA,SACA,MAAA,GAAS,WAAA;EAAA,SACT,aAAA,GAAgB,QAAA,CAAS,QAAA,UAAkB,eAAA;EAAA,SAC3C,cAAA,GAAiB,oBAAA;AAAA;;;KC9BhB,YAAA,GAAe,eAAA;AAAA,UAGV,QAAA;EAAA,SACN,aAAA;EAAA,SACA,UAAA,EAAY,MAAA,CAAO,MAAA;AAAA;AAAA,UAGb,sBAAA,SAA+B,sBAAA;EAAA,SACrC,UAAA;EAAA,SACA,QAAA,GAAW,SAAA,GAAY,MAAA,CAAO,MAAA,CAAO,SAAA;AAAA;AAAA,cAGnC,eAAA;EAAA,UACF,sBAAA;IAET,MAAA,EAAQ,cAAA,CAAe,WAAA;IACvB,MAAA,EAAQ,OAAA,CAAQ,YAAA;IAChB,WAAA,SAAoB,OAAA,CAAQ,QAAA;MAAe,MAAA,EAAQ,MAAA,CAAO,MAAA,CAAO,QAAA;IAAA;IACjE,QAAA,EAAU,OAAA;EAAA"}
@@ -1,60 +0,0 @@
1
- import { a as PartUploadError, c as UploadError } from "./upload-error-jol-eoDW.mjs";
2
- import { n as LoggerService } from "./logger-service-BF2pZOHN.mjs";
3
- import { a as UploadEvent, i as UploadCompleted } from "./upload-event-C9TOVp5l.mjs";
4
- import { t as Transform } from "./middleware-CAI0cnW2.mjs";
5
- import { Effect, Option, Schedule, Stream } from "effect";
6
-
7
- //#region src/multipart/circuit-breaker.d.ts
8
- interface CircuitBreakerConfig {
9
- readonly threshold: number;
10
- readonly cooldown: number;
11
- }
12
- //#endregion
13
- //#region src/multipart/upload-stream.d.ts
14
- interface CompletedPart {
15
- readonly partNumber: number;
16
- readonly etag: string;
17
- }
18
- interface UploadMultipartOptions {
19
- readonly stream: ReadableStream<Uint8Array>;
20
- readonly chunkSize: number;
21
- readonly uploadPart: (partNumber: number, chunk: Uint8Array) => string | Promise<string> | Effect.Effect<string, UploadError>;
22
- readonly completeUpload: (uploadId: string, parts: ReadonlyArray<CompletedPart>) => void | Promise<void> | Effect.Effect<void, UploadError>;
23
- readonly initiate?: () => {
24
- uploadId: string;
25
- } | Promise<{
26
- uploadId: string;
27
- }> | Effect.Effect<{
28
- uploadId: string;
29
- }, UploadError>;
30
- readonly reconcileCompletedParts?: () => ReadonlyArray<CompletedPart> | Promise<ReadonlyArray<CompletedPart>> | Effect.Effect<ReadonlyArray<CompletedPart>, UploadError>;
31
- readonly maxConcurrency?: number;
32
- readonly signal?: AbortSignal;
33
- readonly retrySchedule?: Schedule.Schedule<unknown, PartUploadError>;
34
- readonly circuitBreaker?: CircuitBreakerConfig;
35
- }
36
- //#endregion
37
- //#region src/multipart/index.d.ts
38
- type UploadResult = UploadCompleted;
39
- interface Progress {
40
- readonly bytesUploaded: number;
41
- readonly totalBytes: Option.Option<number>;
42
- }
43
- interface MultipartPublicOptions extends UploadMultipartOptions {
44
- readonly totalBytes?: number;
45
- readonly pipeline?: Transform | Effect.Effect<Transform, unknown, unknown>;
46
- }
47
- declare const uploadMultipart: {
48
- (options: MultipartPublicOptions): {
49
- events: ReadableStream<UploadEvent>;
50
- result: Promise<UploadResult>;
51
- getProgress: (() => Promise<Progress>) & {
52
- effect: Effect.Effect<Progress>;
53
- };
54
- uploadId: Promise<string>;
55
- };
56
- effect: (options: UploadMultipartOptions) => Stream.Stream<UploadEvent, UploadError, LoggerService>;
57
- };
58
- //#endregion
59
- export { CompletedPart as a, uploadMultipart as i, Progress as n, UploadMultipartOptions as o, UploadResult as r, MultipartPublicOptions as t };
60
- //# sourceMappingURL=index-DBGtgXEd.d.mts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"index-DBGtgXEd.d.mts","names":[],"sources":["../src/multipart/circuit-breaker.ts","../src/multipart/upload-stream.ts","../src/multipart/index.ts"],"mappings":";;;;;;;UAIiB,oBAAA;EAAA,SACN,SAAA;EAAA,SACA,QAAA;AAAA;;;UCIM,aAAA;EAAA,SACN,UAAA;EAAA,SACA,IAAA;AAAA;AAAA,UAGM,sBAAA;EAAA,SACN,MAAA,EAAQ,cAAA,CAAe,UAAA;EAAA,SACvB,SAAA;EAAA,SACA,UAAA,GACP,UAAA,UACA,KAAA,EAAO,UAAA,cACK,OAAA,WAAkB,MAAA,CAAO,MAAA,SAAe,WAAA;EAAA,SAC7C,cAAA,GACP,QAAA,UACA,KAAA,EAAO,aAAA,CAAc,aAAA,aACX,OAAA,SAAgB,MAAA,CAAO,MAAA,OAAa,WAAA;EAAA,SACvC,QAAA;IACH,QAAA;EAAA,IACF,OAAA;IAAU,QAAA;EAAA,KACV,MAAA,CAAO,MAAA;IAAS,QAAA;EAAA,GAAoB,WAAA;EAAA,SAC/B,uBAAA,SACL,aAAA,CAAc,aAAA,IACd,OAAA,CAAQ,aAAA,CAAc,aAAA,KACtB,MAAA,CAAO,MAAA,CAAO,aAAA,CAAc,aAAA,GAAgB,WAAA;EAAA,SACvC,cAAA;EAAA,SACA,MAAA,GAAS,WAAA;EAAA,SACT,aAAA,GAAgB,QAAA,CAAS,QAAA,UAAkB,eAAA;EAAA,SAC3C,cAAA,GAAiB,oBAAA;AAAA;;;KC9BhB,YAAA,GAAe,eAAA;AAAA,UAGV,QAAA;EAAA,SACN,aAAA;EAAA,SACA,UAAA,EAAY,MAAA,CAAO,MAAA;AAAA;AAAA,UAGb,sBAAA,SAA+B,sBAAA;EAAA,SACrC,UAAA;EAAA,SACA,QAAA,GAAW,SAAA,GAAY,MAAA,CAAO,MAAA,CAAO,SAAA;AAAA;AAAA,cAGnC,eAAA;EAAA,UACF,sBAAA;IAET,MAAA,EAAQ,cAAA,CAAe,WAAA;IACvB,MAAA,EAAQ,OAAA,CAAQ,YAAA;IAChB,WAAA,SAAoB,OAAA,CAAQ,QAAA;MAAe,MAAA,EAAQ,MAAA,CAAO,MAAA,CAAO,QAAA;IAAA;IACjE,QAAA,EAAU,OAAA;EAAA"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"upload-error-BUexBh08.cjs","names":[],"sources":["../src/errors/upload-error.ts"],"sourcesContent":["export class PartUploadError extends Error {\n readonly _tag = \"PartUploadError\" as const\n\n constructor(\n readonly partNumber: number,\n readonly attempt: number,\n override readonly cause: unknown\n ) {\n super(`Part ${partNumber} failed on attempt ${attempt}`)\n this.name = \"PartUploadError\"\n }\n}\n\nexport class MaxRetriesExceededError extends Error {\n readonly _tag = \"MaxRetriesExceededError\" as const\n\n constructor(\n readonly partNumber: number,\n readonly totalAttempts: number,\n override readonly cause: unknown\n ) {\n super(`Part ${partNumber} failed after ${totalAttempts} attempts`)\n this.name = \"MaxRetriesExceededError\"\n }\n}\n\nexport class PresignedUrlError extends Error {\n readonly _tag = \"PresignedUrlError\" as const\n\n constructor(override readonly cause: unknown) {\n super(\"Failed to obtain pre-signed URL\")\n this.name = \"PresignedUrlError\"\n }\n}\n\nexport class InitiateUploadError extends Error {\n readonly _tag = \"InitiateUploadError\" as const\n\n constructor(override readonly cause: unknown) {\n super(\"Failed to initiate multipart upload\")\n this.name = \"InitiateUploadError\"\n }\n}\n\nexport class ReconcileError extends Error {\n readonly _tag = \"ReconcileError\" as const\n\n constructor(override readonly cause: unknown) {\n super(\"Failed to reconcile completed parts\")\n this.name = \"ReconcileError\"\n }\n}\n\nexport class CompleteUploadError extends Error {\n readonly _tag = \"CompleteUploadError\" as const\n\n constructor(override readonly cause: unknown) {\n super(\"Failed to complete multipart upload\")\n this.name = \"CompleteUploadError\"\n }\n}\n\nexport class AbortError extends Error {\n readonly _tag = \"AbortError\" as const\n\n constructor() {\n super(\"Upload aborted\")\n this.name = \"AbortError\"\n }\n}\n\nexport class CircuitOpenError extends Error {\n readonly _tag = \"CircuitOpenError\" as const\n\n constructor(readonly failedParts: number) {\n super(`Circuit breaker opened after ${failedParts} consecutive part failures`)\n this.name = \"CircuitOpenError\"\n }\n}\n\nexport type UploadError =\n | PartUploadError\n | MaxRetriesExceededError\n | PresignedUrlError\n | InitiateUploadError\n | ReconcileError\n | CompleteUploadError\n | AbortError\n | CircuitOpenError\n"],"mappings":";AAAA,IAAa,kBAAb,cAAqC,MAAM;CACzC,OAAgB;CAEhB,YACE,YACA,SACA,OACA;AACA,QAAM,QAAQ,WAAW,qBAAqB,UAAU;AAJ/C,OAAA,aAAA;AACA,OAAA,UAAA;AACS,OAAA,QAAA;AAGlB,OAAK,OAAO;;;AAIhB,IAAa,0BAAb,cAA6C,MAAM;CACjD,OAAgB;CAEhB,YACE,YACA,eACA,OACA;AACA,QAAM,QAAQ,WAAW,gBAAgB,cAAc,WAAW;AAJzD,OAAA,aAAA;AACA,OAAA,gBAAA;AACS,OAAA,QAAA;AAGlB,OAAK,OAAO;;;AAIhB,IAAa,oBAAb,cAAuC,MAAM;CAC3C,OAAgB;CAEhB,YAAY,OAAkC;AAC5C,QAAM,kCAAkC;AADZ,OAAA,QAAA;AAE5B,OAAK,OAAO;;;AAIhB,IAAa,sBAAb,cAAyC,MAAM;CAC7C,OAAgB;CAEhB,YAAY,OAAkC;AAC5C,QAAM,sCAAsC;AADhB,OAAA,QAAA;AAE5B,OAAK,OAAO;;;AAIhB,IAAa,iBAAb,cAAoC,MAAM;CACxC,OAAgB;CAEhB,YAAY,OAAkC;AAC5C,QAAM,sCAAsC;AADhB,OAAA,QAAA;AAE5B,OAAK,OAAO;;;AAIhB,IAAa,sBAAb,cAAyC,MAAM;CAC7C,OAAgB;CAEhB,YAAY,OAAkC;AAC5C,QAAM,sCAAsC;AADhB,OAAA,QAAA;AAE5B,OAAK,OAAO;;;AAIhB,IAAa,aAAb,cAAgC,MAAM;CACpC,OAAgB;CAEhB,cAAc;AACZ,QAAM,iBAAiB;AACvB,OAAK,OAAO;;;AAIhB,IAAa,mBAAb,cAAsC,MAAM;CAC1C,OAAgB;CAEhB,YAAY,aAA8B;AACxC,QAAM,gCAAgC,YAAY,4BAA4B;AAD3D,OAAA,cAAA;AAEnB,OAAK,OAAO"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"upload-error-zDvpxT9X.mjs","names":[],"sources":["../src/errors/upload-error.ts"],"sourcesContent":["export class PartUploadError extends Error {\n readonly _tag = \"PartUploadError\" as const\n\n constructor(\n readonly partNumber: number,\n readonly attempt: number,\n override readonly cause: unknown\n ) {\n super(`Part ${partNumber} failed on attempt ${attempt}`)\n this.name = \"PartUploadError\"\n }\n}\n\nexport class MaxRetriesExceededError extends Error {\n readonly _tag = \"MaxRetriesExceededError\" as const\n\n constructor(\n readonly partNumber: number,\n readonly totalAttempts: number,\n override readonly cause: unknown\n ) {\n super(`Part ${partNumber} failed after ${totalAttempts} attempts`)\n this.name = \"MaxRetriesExceededError\"\n }\n}\n\nexport class PresignedUrlError extends Error {\n readonly _tag = \"PresignedUrlError\" as const\n\n constructor(override readonly cause: unknown) {\n super(\"Failed to obtain pre-signed URL\")\n this.name = \"PresignedUrlError\"\n }\n}\n\nexport class InitiateUploadError extends Error {\n readonly _tag = \"InitiateUploadError\" as const\n\n constructor(override readonly cause: unknown) {\n super(\"Failed to initiate multipart upload\")\n this.name = \"InitiateUploadError\"\n }\n}\n\nexport class ReconcileError extends Error {\n readonly _tag = \"ReconcileError\" as const\n\n constructor(override readonly cause: unknown) {\n super(\"Failed to reconcile completed parts\")\n this.name = \"ReconcileError\"\n }\n}\n\nexport class CompleteUploadError extends Error {\n readonly _tag = \"CompleteUploadError\" as const\n\n constructor(override readonly cause: unknown) {\n super(\"Failed to complete multipart upload\")\n this.name = \"CompleteUploadError\"\n }\n}\n\nexport class AbortError extends Error {\n readonly _tag = \"AbortError\" as const\n\n constructor() {\n super(\"Upload aborted\")\n this.name = \"AbortError\"\n }\n}\n\nexport class CircuitOpenError extends Error {\n readonly _tag = \"CircuitOpenError\" as const\n\n constructor(readonly failedParts: number) {\n super(`Circuit breaker opened after ${failedParts} consecutive part failures`)\n this.name = \"CircuitOpenError\"\n }\n}\n\nexport type UploadError =\n | PartUploadError\n | MaxRetriesExceededError\n | PresignedUrlError\n | InitiateUploadError\n | ReconcileError\n | CompleteUploadError\n | AbortError\n | CircuitOpenError\n"],"mappings":";AAAA,IAAa,kBAAb,cAAqC,MAAM;CACzC,OAAgB;CAEhB,YACE,YACA,SACA,OACA;AACA,QAAM,QAAQ,WAAW,qBAAqB,UAAU;AAJ/C,OAAA,aAAA;AACA,OAAA,UAAA;AACS,OAAA,QAAA;AAGlB,OAAK,OAAO;;;AAIhB,IAAa,0BAAb,cAA6C,MAAM;CACjD,OAAgB;CAEhB,YACE,YACA,eACA,OACA;AACA,QAAM,QAAQ,WAAW,gBAAgB,cAAc,WAAW;AAJzD,OAAA,aAAA;AACA,OAAA,gBAAA;AACS,OAAA,QAAA;AAGlB,OAAK,OAAO;;;AAIhB,IAAa,oBAAb,cAAuC,MAAM;CAC3C,OAAgB;CAEhB,YAAY,OAAkC;AAC5C,QAAM,kCAAkC;AADZ,OAAA,QAAA;AAE5B,OAAK,OAAO;;;AAIhB,IAAa,sBAAb,cAAyC,MAAM;CAC7C,OAAgB;CAEhB,YAAY,OAAkC;AAC5C,QAAM,sCAAsC;AADhB,OAAA,QAAA;AAE5B,OAAK,OAAO;;;AAIhB,IAAa,iBAAb,cAAoC,MAAM;CACxC,OAAgB;CAEhB,YAAY,OAAkC;AAC5C,QAAM,sCAAsC;AADhB,OAAA,QAAA;AAE5B,OAAK,OAAO;;;AAIhB,IAAa,sBAAb,cAAyC,MAAM;CAC7C,OAAgB;CAEhB,YAAY,OAAkC;AAC5C,QAAM,sCAAsC;AADhB,OAAA,QAAA;AAE5B,OAAK,OAAO;;;AAIhB,IAAa,aAAb,cAAgC,MAAM;CACpC,OAAgB;CAEhB,cAAc;AACZ,QAAM,iBAAiB;AACvB,OAAK,OAAO;;;AAIhB,IAAa,mBAAb,cAAsC,MAAM;CAC1C,OAAgB;CAEhB,YAAY,aAA8B;AACxC,QAAM,gCAAgC,YAAY,4BAA4B;AAD3D,OAAA,cAAA;AAEnB,OAAK,OAAO"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"upload-event-C9TOVp5l.d.mts","names":[],"sources":["../src/progress/upload-event.ts"],"mappings":";;;UAEiB,eAAA;EAAA,SACN,IAAA;EAAA,SACA,QAAA;EAAA,SACA,SAAA;AAAA;AAAA,UAGM,eAAA;EAAA,SACN,IAAA;EAAA,SACA,QAAA;EAAA,SACA,UAAA;EAAA,SACA,SAAA;AAAA;AAAA,UAGM,aAAA;EAAA,SACN,IAAA;EAAA,SACA,UAAA;EAAA,SACA,IAAA;EAAA,SACA,aAAA;EAAA,SACA,SAAA;AAAA;AAAA,UAGM,WAAA;EAAA,SACN,IAAA;EAAA,SACA,WAAA;EAAA,SACA,SAAA;AAAA;AAAA,UAGM,YAAA;EAAA,SACN,IAAA;EAAA,SACA,aAAA;EAAA,SACA,UAAA,EAAY,MAAA,CAAO,MAAA;EAAA,SACnB,SAAA;AAAA;AAAA,KAGC,WAAA,GAAc,eAAA,GAAkB,eAAA,GAAkB,aAAA,GAAgB,YAAA,GAAe,WAAA"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"upload-event-D77olieX.d.cts","names":[],"sources":["../src/progress/upload-event.ts"],"mappings":";;;UAEiB,eAAA;EAAA,SACN,IAAA;EAAA,SACA,QAAA;EAAA,SACA,SAAA;AAAA;AAAA,UAGM,eAAA;EAAA,SACN,IAAA;EAAA,SACA,QAAA;EAAA,SACA,UAAA;EAAA,SACA,SAAA;AAAA;AAAA,UAGM,aAAA;EAAA,SACN,IAAA;EAAA,SACA,UAAA;EAAA,SACA,IAAA;EAAA,SACA,aAAA;EAAA,SACA,SAAA;AAAA;AAAA,UAGM,WAAA;EAAA,SACN,IAAA;EAAA,SACA,WAAA;EAAA,SACA,SAAA;AAAA;AAAA,UAGM,YAAA;EAAA,SACN,IAAA;EAAA,SACA,aAAA;EAAA,SACA,UAAA,EAAY,MAAA,CAAO,MAAA;EAAA,SACnB,SAAA;AAAA;AAAA,KAGC,WAAA,GAAc,eAAA,GAAkB,eAAA,GAAkB,aAAA,GAAgB,YAAA,GAAe,WAAA"}