effect 4.0.0-beta.106 → 4.0.0-beta.107

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 (62) hide show
  1. package/dist/Channel.d.ts +26 -0
  2. package/dist/Channel.d.ts.map +1 -1
  3. package/dist/Channel.js +47 -0
  4. package/dist/Channel.js.map +1 -1
  5. package/dist/Duration.d.ts.map +1 -1
  6. package/dist/Duration.js +13 -1
  7. package/dist/Duration.js.map +1 -1
  8. package/dist/SchemaRepresentation.d.ts +29 -4
  9. package/dist/SchemaRepresentation.d.ts.map +1 -1
  10. package/dist/SchemaRepresentation.js +7 -2
  11. package/dist/SchemaRepresentation.js.map +1 -1
  12. package/dist/Stream.d.ts +10 -0
  13. package/dist/Stream.d.ts.map +1 -1
  14. package/dist/Stream.js +12 -23
  15. package/dist/Stream.js.map +1 -1
  16. package/dist/internal/schema/fromJsonSchemaDocument.js +22 -10
  17. package/dist/internal/schema/fromJsonSchemaDocument.js.map +1 -1
  18. package/dist/unstable/ai/McpSchema.d.ts +88 -88
  19. package/dist/unstable/ai/McpSchema.d.ts.map +1 -1
  20. package/dist/unstable/cli/Argument.d.ts +6 -3
  21. package/dist/unstable/cli/Argument.d.ts.map +1 -1
  22. package/dist/unstable/cli/Argument.js +2 -1
  23. package/dist/unstable/cli/Argument.js.map +1 -1
  24. package/dist/unstable/cli/CliError.d.ts +20 -1
  25. package/dist/unstable/cli/CliError.d.ts.map +1 -1
  26. package/dist/unstable/cli/CliError.js +26 -2
  27. package/dist/unstable/cli/CliError.js.map +1 -1
  28. package/dist/unstable/cli/Command.d.ts +23 -0
  29. package/dist/unstable/cli/Command.d.ts.map +1 -1
  30. package/dist/unstable/cli/Command.js +23 -4
  31. package/dist/unstable/cli/Command.js.map +1 -1
  32. package/dist/unstable/http/Multipart.d.ts +2 -0
  33. package/dist/unstable/http/Multipart.d.ts.map +1 -1
  34. package/dist/unstable/http/Multipart.js +4 -12
  35. package/dist/unstable/http/Multipart.js.map +1 -1
  36. package/dist/unstable/http/MultipartParser/internal/headers.d.ts.map +1 -1
  37. package/dist/unstable/http/MultipartParser/internal/headers.js +16 -2
  38. package/dist/unstable/http/MultipartParser/internal/headers.js.map +1 -1
  39. package/dist/unstable/http/MultipartParser/internal/multipart.d.ts.map +1 -1
  40. package/dist/unstable/http/MultipartParser/internal/multipart.js +13 -10
  41. package/dist/unstable/http/MultipartParser/internal/multipart.js.map +1 -1
  42. package/dist/unstable/process/ChildProcess.d.ts +8 -0
  43. package/dist/unstable/process/ChildProcess.d.ts.map +1 -1
  44. package/dist/unstable/process/ChildProcess.js.map +1 -1
  45. package/dist/unstable/sql/Migrator.d.ts +9 -1
  46. package/dist/unstable/sql/Migrator.d.ts.map +1 -1
  47. package/dist/unstable/sql/Migrator.js +15 -2
  48. package/dist/unstable/sql/Migrator.js.map +1 -1
  49. package/package.json +1 -1
  50. package/src/Channel.ts +58 -0
  51. package/src/Duration.ts +12 -1
  52. package/src/SchemaRepresentation.ts +29 -4
  53. package/src/Stream.ts +12 -30
  54. package/src/internal/schema/fromJsonSchemaDocument.ts +17 -4
  55. package/src/unstable/cli/Argument.ts +6 -3
  56. package/src/unstable/cli/CliError.ts +28 -2
  57. package/src/unstable/cli/Command.ts +44 -4
  58. package/src/unstable/http/Multipart.ts +4 -13
  59. package/src/unstable/http/MultipartParser/internal/headers.ts +16 -387
  60. package/src/unstable/http/MultipartParser/internal/multipart.ts +14 -10
  61. package/src/unstable/process/ChildProcess.ts +8 -0
  62. package/src/unstable/sql/Migrator.ts +22 -9
@@ -606,17 +606,37 @@ export const makeFilterGroupReviver: <P>(
606
606
  *
607
607
  * **When to use**
608
608
  *
609
- * Use when each JSON Schema node must be transformed before it is translated.
609
+ * Use when you need to configure pattern handling or transform each JSON Schema node before translation.
610
+ *
611
+ * **Details**
612
+ *
613
+ * `patterns` controls pattern constraints reached during best-effort translation, including `pattern`, the keys of
614
+ * `patternProperties`, and patterns nested in `propertyNames`:
615
+ *
616
+ * - `"error"` rejects the document and is the default.
617
+ * - `"ignore"` skips the constraint.
618
+ * - `"apply"` compiles and enforces the constraint with the runtime's native regular expression engine.
610
619
  *
611
620
  * **Gotchas**
612
621
  *
613
- * `onEnter` must return a JSON Schema object. Its result is used directly, and exceptions raised by the callback pass through unchanged.
622
+ * Use `patterns: "apply"` only for trusted documents because regular expression evaluation may block for an unbounded
623
+ * amount of time. `patterns: "ignore"` weakens validation by accepting values that the source document may reject.
624
+ * Ignoring `patternProperties` also skips its value constraints and `additionalProperties`, because matching keys cannot
625
+ * be determined without evaluating the patterns.
626
+ * `onEnter` must return a JSON Schema object. Its result is used directly, and exceptions raised by the callback pass
627
+ * through unchanged.
614
628
  *
615
629
  * @category models
616
630
  * @since 4.0.0
617
631
  */
618
632
  export interface FromJsonSchemaOptions {
619
633
  readonly onEnter?: ((schema: JsonSchema.JsonSchema) => JsonSchema.JsonSchema) | undefined
634
+ /**
635
+ * Controls how reached JSON Schema regular expression patterns are imported.
636
+ *
637
+ * @default "error"
638
+ */
639
+ readonly patterns?: "error" | "ignore" | "apply" | undefined
620
640
  }
621
641
 
622
642
  /**
@@ -1160,7 +1180,10 @@ export function fromRepresentations(
1160
1180
  *
1161
1181
  * **Gotchas**
1162
1182
  *
1163
- * Import is best-effort. Built-in declarations and checks are reconstructed with importer-owned revivers. Callback results are used directly, and exceptions raised by a callback pass through unchanged.
1183
+ * Import is best-effort. Built-in declarations and checks are reconstructed with importer-owned revivers. Pattern
1184
+ * constraints reached during translation cause an error by default. Use `patterns: "apply"` only for trusted documents,
1185
+ * or `patterns: "ignore"` to weaken validation explicitly. Callback results are used directly, and exceptions raised by a
1186
+ * callback pass through unchanged.
1164
1187
  *
1165
1188
  * @see {@link fromJsonSchemaMultiDocument} for multiple roots sharing definitions
1166
1189
  * @see {@link toRepresentation} for converting the result to a representation document
@@ -1184,7 +1207,9 @@ export function fromJsonSchemaDocument(
1184
1207
  *
1185
1208
  * **Gotchas**
1186
1209
  *
1187
- * Only definitions reachable from a root are translated. Callback results are used directly, and exceptions raised by a callback pass through unchanged.
1210
+ * Only definitions reachable from a root are translated. Pattern constraints reached during translation cause an error
1211
+ * by default. Use `patterns: "apply"` only for trusted documents, or `patterns: "ignore"` to weaken validation explicitly.
1212
+ * Callback results are used directly, and exceptions raised by a callback pass through unchanged.
1188
1213
  *
1189
1214
  * @see {@link fromJsonSchemaDocument} for a single root
1190
1215
  * @see {@link toRepresentations} for converting the returned schema ASTs to a representation document
package/src/Stream.ts CHANGED
@@ -19270,39 +19270,16 @@ export const mkString = <E, R>(self: Stream<string, E, R>): Effect.Effect<string
19270
19270
  * await Effect.runPromise(program) // => [1, 2, 3, 4]
19271
19271
  * ```
19272
19272
  *
19273
+ * **Gotchas**
19274
+ *
19275
+ * This materializes the full content in memory. The source stream must not
19276
+ * reuse or mutate emitted buffers, which are retained until collection completes.
19277
+ *
19273
19278
  * @category destructors
19274
19279
  * @since 4.0.0
19275
19280
  */
19276
19281
  export const mkArrayBuffer = <E, R>(self: Stream<Uint8Array, E, R>): Effect.Effect<ArrayBuffer, E, R> =>
19277
- Effect.map(
19278
- Channel.runFold(
19279
- self.channel,
19280
- (): {
19281
- bytes: number
19282
- readonly arrays: Array<Uint8Array>
19283
- } => ({
19284
- bytes: 0,
19285
- arrays: []
19286
- }),
19287
- (acc, chunk) => {
19288
- for (let i = 0; i < chunk.length; i++) {
19289
- acc.bytes += chunk[i].length
19290
- acc.arrays.push(chunk[i])
19291
- }
19292
- return acc
19293
- }
19294
- ),
19295
- ({ arrays, bytes }) => {
19296
- const result = new Uint8Array(bytes)
19297
- let offset = 0
19298
- for (let i = 0; i < arrays.length; i++) {
19299
- const array = arrays[i]
19300
- result.set(array, offset)
19301
- offset += array.length
19302
- }
19303
- return result.buffer
19304
- }
19305
- )
19282
+ Effect.map(Channel.mkUint8Array(self.channel), (bytes) => bytes.buffer)
19306
19283
 
19307
19284
  /**
19308
19285
  * Concatenates the stream's `Uint8Array` chunks into a single `Uint8Array`.
@@ -19321,11 +19298,16 @@ export const mkArrayBuffer = <E, R>(self: Stream<Uint8Array, E, R>): Effect.Effe
19321
19298
  * await Effect.runPromise(program)
19322
19299
  * ```
19323
19300
  *
19301
+ * **Gotchas**
19302
+ *
19303
+ * This materializes the full content in memory. The source stream must not
19304
+ * reuse or mutate emitted buffers, which are retained until collection completes.
19305
+ *
19324
19306
  * @category destructors
19325
19307
  * @since 4.0.0
19326
19308
  */
19327
19309
  export const mkUint8Array = <E, R>(self: Stream<Uint8Array, E, R>): Effect.Effect<Uint8Array, E, R> =>
19328
- Effect.map(mkArrayBuffer(self), (buffer) => new Uint8Array(buffer))
19310
+ Channel.mkUint8Array(self.channel)
19329
19311
 
19330
19312
  /**
19331
19313
  * Converts the stream to a `ReadableStream` using the provided services.
@@ -743,7 +743,7 @@ function translateJsonSchemaMultiDocument(
743
743
  case "string":
744
744
  return {
745
745
  _tag: "String",
746
- checks: collectStringChecks(schema)
746
+ checks: collectStringChecks(schema, path)
747
747
  }
748
748
  case "number":
749
749
  case "integer":
@@ -791,12 +791,23 @@ function translateJsonSchemaMultiDocument(
791
791
  }
792
792
  }
793
793
 
794
- function collectStringChecks(schema: JsonSchema.JsonSchema): Array<Check> {
794
+ function importPatternChecks(pattern: string, path: Path): Array<Check> {
795
+ switch (options?.patterns ?? "error") {
796
+ case "error":
797
+ throw errorWithPath(`Pattern encountered while patterns is set to "error"`, path)
798
+ case "ignore":
799
+ return []
800
+ case "apply":
801
+ return [jsonSchemaFilter("effect/schema/isPattern", { source: pattern, flags: "" })]
802
+ }
803
+ }
804
+
805
+ function collectStringChecks(schema: JsonSchema.JsonSchema, path: Path): Array<Check> {
795
806
  const checks: Array<Check> = []
796
807
  addNumberCheck(checks, schema.minLength, "effect/schema/isMinLength", "minLength")
797
808
  addNumberCheck(checks, schema.maxLength, "effect/schema/isMaxLength", "maxLength")
798
809
  if (typeof schema.pattern === "string") {
799
- checks.push(jsonSchemaFilter("effect/schema/isPattern", { source: schema.pattern, flags: "" }))
810
+ checks.push(...importPatternChecks(schema.pattern, [...path, "pattern"]))
800
811
  }
801
812
  return checks
802
813
  }
@@ -856,10 +867,12 @@ function translateJsonSchemaMultiDocument(
856
867
  !Array.isArray(schema.patternProperties)
857
868
  ) {
858
869
  for (const [pattern, value] of Object.entries(schema.patternProperties)) {
870
+ const checks = importPatternChecks(pattern, [...path, "patternProperties", pattern])
871
+ if (checks.length === 0) return [{ parameter: string, type: unknown }]
859
872
  signatures.push({
860
873
  parameter: {
861
874
  _tag: "String",
862
- checks: [jsonSchemaFilter("effect/schema/isPattern", { source: pattern, flags: "" })]
875
+ checks
863
876
  },
864
877
  type: recur(value, [...path, "patternProperties", pattern])
865
878
  })
@@ -719,7 +719,8 @@ export const map: {
719
719
  * ? Effect.succeed(file)
720
720
  * : Effect.fail(
721
721
  * new CliError.UserError({
722
- * cause: new Error("Only .txt files allowed")
722
+ * cause: new Error(`Unsupported file extension: ${file}`),
723
+ * userMessage: "Only .txt files allowed"
723
724
  * })
724
725
  * )
725
726
  * )
@@ -768,7 +769,8 @@ export const mapEffect: {
768
769
  * ? Effect.succeed(file)
769
770
  * : Effect.fail(
770
771
  * new CliError.UserError({
771
- * cause: new Error("Only .txt files allowed")
772
+ * cause: new Error(`Unsupported file extension: ${file}`),
773
+ * userMessage: "Only .txt files allowed"
772
774
  * })
773
775
  * )
774
776
  * )
@@ -817,7 +819,8 @@ export const mapEffect: {
817
819
  * ? Effect.succeed(file)
818
820
  * : Effect.fail(
819
821
  * new CliError.UserError({
820
- * cause: new Error("Only .txt files allowed")
822
+ * cause: new Error(`Unsupported file extension: ${file}`),
823
+ * userMessage: "Only .txt files allowed"
821
824
  * })
822
825
  * )
823
826
  * )
@@ -478,6 +478,10 @@ export class UnknownSubcommand extends Schema.TaggedError<UnknownSubcommand>(
478
478
  /**
479
479
  * Error wrapper for user handler failures in the CLI error channel.
480
480
  *
481
+ * `userMessage` can provide safe, user-facing text independently of the
482
+ * underlying cause. When omitted or empty, `message` uses a non-empty string
483
+ * cause or `Error.message`, then falls back to `"An error occurred"`.
484
+ *
481
485
  * **Example** (Wrapping user errors)
482
486
  *
483
487
  * ```ts import.meta.vitest
@@ -486,7 +490,8 @@ export class UnknownSubcommand extends Schema.TaggedError<UnknownSubcommand>(
486
490
  *
487
491
  * // Wrapping user errors
488
492
  * const userError = new CliError.UserError({
489
- * cause: new Error("Database connection failed")
493
+ * cause: new Error("Database connection failed for postgres://localhost"),
494
+ * userMessage: "Could not connect to the database"
490
495
  * })
491
496
  *
492
497
  * // In command handler
@@ -516,7 +521,8 @@ export class UnknownSubcommand extends Schema.TaggedError<UnknownSubcommand>(
516
521
  export class UserError extends Schema.TaggedError<UserError>(
517
522
  `${TypeId}/UserError`
518
523
  )("UserError", {
519
- cause: Schema.Defect()
524
+ cause: Schema.Defect(),
525
+ userMessage: Schema.optionalKey(Schema.String)
520
526
  }) {
521
527
  /**
522
528
  * Marks this value as a user handler error for runtime guards.
@@ -524,6 +530,26 @@ export class UserError extends Schema.TaggedError<UserError>(
524
530
  * @since 4.0.0
525
531
  */
526
532
  readonly [TypeId] = TypeId
533
+
534
+ /**
535
+ * Controls whether the runtime logger should report this error. The CLI
536
+ * runner sets this to `false` after rendering the error itself.
537
+ *
538
+ * @since 4.0.0
539
+ */
540
+ override [Runtime.errorReported] = true
541
+
542
+ /**
543
+ * Returns the explicit user-facing message or a safe fallback from `cause`.
544
+ *
545
+ * @since 4.0.0
546
+ */
547
+ override get message() {
548
+ if (this.userMessage) return this.userMessage
549
+ if (typeof this.cause === "string" && this.cause) return this.cause
550
+ if (this.cause instanceof Error && this.cause.message) return this.cause.message
551
+ return "An error occurred"
552
+ }
527
553
  }
528
554
 
529
555
  /**
@@ -22,6 +22,7 @@ import type * as Path from "../../Path.ts"
22
22
  import * as Predicate from "../../Predicate.ts"
23
23
  import * as References from "../../References.ts"
24
24
  import * as Result from "../../Result.ts"
25
+ import * as Runtime from "../../Runtime.ts"
25
26
  import * as Stdio from "../../Stdio.ts"
26
27
  import * as Terminal from "../../Terminal.ts"
27
28
  import type { Contravariant, Covariant, NoInfer, Simplify } from "../../Types.ts"
@@ -2669,18 +2670,26 @@ const getOutOfScopeGlobalFlagErrors = (
2669
2670
 
2670
2671
  const showHelp = <Name extends string, Input, E, R, ContextInput>(
2671
2672
  command: Command<Name, Input, ContextInput, E, R>,
2672
- error: CliError.ShowHelp
2673
+ error: CliError.ShowHelp,
2674
+ renderErrors: boolean
2673
2675
  ): Effect.Effect<void, CliError.CliError, Environment> =>
2674
2676
  Effect.gen(function*() {
2675
2677
  const { builtIns } = yield* CliConfig.CliConfig
2676
2678
  const formatter = yield* CliOutput.Formatter
2677
2679
  const helpDoc = yield* getHelpForCommandPath(command, error.commandPath, builtIns)
2678
2680
  yield* Console.log(formatter.formatHelpDoc(helpDoc))
2679
- if (error.errors.length > 0) {
2681
+ if (renderErrors && error.errors.length > 0) {
2680
2682
  yield* Console.error(formatter.formatErrors(error.errors as any))
2681
2683
  }
2682
2684
  })
2683
2685
 
2686
+ const showUserError = (error: CliError.UserError): Effect.Effect<void> =>
2687
+ Effect.gen(function*() {
2688
+ const formatter = yield* CliOutput.Formatter
2689
+ yield* Console.error(formatter.formatError(error))
2690
+ error[Runtime.errorReported] = false
2691
+ })
2692
+
2684
2693
  /**
2685
2694
  * Runs a command using the arguments supplied by the `Stdio` service.
2686
2695
  *
@@ -2689,6 +2698,11 @@ const showHelp = <Name extends string, Input, E, R, ContextInput>(
2689
2698
  * Use when command-line arguments should come from `Stdio` at the application
2690
2699
  * entry point.
2691
2700
  *
2701
+ * Help documents are always rendered. By default, parse error details and
2702
+ * `CliError.UserError` failures are also rendered with the installed
2703
+ * `CliOutput.Formatter` before the error is rethrown. Set `renderErrors` to
2704
+ * `false` when the host application owns error rendering.
2705
+ *
2692
2706
  * **Example** (Running commands with standard input)
2693
2707
  *
2694
2708
  * ```ts import.meta.vitest
@@ -2746,6 +2760,11 @@ export const run: {
2746
2760
  * Use when command-line arguments should come from `Stdio` at the application
2747
2761
  * entry point.
2748
2762
  *
2763
+ * Help documents are always rendered. By default, parse error details and
2764
+ * `CliError.UserError` failures are also rendered with the installed
2765
+ * `CliOutput.Formatter` before the error is rethrown. Set `renderErrors` to
2766
+ * `false` when the host application owns error rendering.
2767
+ *
2749
2768
  * **Example** (Running commands with standard input)
2750
2769
  *
2751
2770
  * ```ts import.meta.vitest
@@ -2797,6 +2816,7 @@ export const run: {
2797
2816
  (
2798
2817
  config: {
2799
2818
  readonly version: string
2819
+ readonly renderErrors?: boolean | undefined
2800
2820
  }
2801
2821
  ): <Name extends string, Input, E, R, ContextInput>(
2802
2822
  command: Command<Name, Input, ContextInput, E, R>
@@ -2809,6 +2829,11 @@ export const run: {
2809
2829
  * Use when command-line arguments should come from `Stdio` at the application
2810
2830
  * entry point.
2811
2831
  *
2832
+ * Help documents are always rendered. By default, parse error details and
2833
+ * `CliError.UserError` failures are also rendered with the installed
2834
+ * `CliOutput.Formatter` before the error is rethrown. Set `renderErrors` to
2835
+ * `false` when the host application owns error rendering.
2836
+ *
2812
2837
  * **Example** (Running commands with standard input)
2813
2838
  *
2814
2839
  * ```ts import.meta.vitest
@@ -2861,12 +2886,14 @@ export const run: {
2861
2886
  command: Command<Name, Input, ContextInput, E, R>,
2862
2887
  config: {
2863
2888
  readonly version: string
2889
+ readonly renderErrors?: boolean | undefined
2864
2890
  }
2865
2891
  ): Effect.Effect<void, E | CliError.CliError, R | Environment>
2866
2892
  } = dual(2, <Name extends string, Input, E, R, ContextInput>(
2867
2893
  command: Command<Name, Input, ContextInput, E, R>,
2868
2894
  config: {
2869
2895
  readonly version: string
2896
+ readonly renderErrors?: boolean | undefined
2870
2897
  }
2871
2898
  ) =>
2872
2899
  Stdio.Stdio.use(({ args }) =>
@@ -2884,6 +2911,11 @@ export const run: {
2884
2911
  * Use when you need to test CLI applications or programmatically execute
2885
2912
  * commands with specific arguments.
2886
2913
  *
2914
+ * Help documents are always rendered. By default, parse error details and
2915
+ * `CliError.UserError` failures are also rendered with the installed
2916
+ * `CliOutput.Formatter` before the error is rethrown. Set `renderErrors` to
2917
+ * `false` when the host application owns error rendering.
2918
+ *
2887
2919
  * **Example** (Running commands with explicit arguments)
2888
2920
  *
2889
2921
  * ```ts import.meta.vitest
@@ -2937,6 +2969,7 @@ export const runWith = <const Name extends string, Input, E, R, ContextInput>(
2937
2969
  command: Command<Name, Input, ContextInput, E, R>,
2938
2970
  config: {
2939
2971
  readonly version: string
2972
+ readonly renderErrors?: boolean | undefined
2940
2973
  }
2941
2974
  ): (
2942
2975
  input: ReadonlyArray<string>
@@ -3003,7 +3036,7 @@ export const runWith = <const Name extends string, Input, E, R, ContextInput>(
3003
3036
  }))
3004
3037
  if (shouldRun) {
3005
3038
  yield* Console.log()
3006
- yield* runWith(command, config)(wizardArgs.slice(1))
3039
+ yield* runWith(command, { ...config, renderErrors: false })(wizardArgs.slice(1))
3007
3040
  }
3008
3041
  }).pipe(
3009
3042
  Effect.catchTag("QuitError", () => Console.log(Wizard.renderQuit()))
@@ -3051,7 +3084,14 @@ export const runWith = <const Name extends string, Input, E, R, ContextInput>(
3051
3084
  CliError.isCliError(error) && error._tag === "ShowHelp"
3052
3085
  ? Result.succeed(error)
3053
3086
  : Result.fail(error),
3054
- (error) => Effect.andThen(showHelp(command, error), Effect.fail(error))
3087
+ (error) => Effect.andThen(showHelp(command, error, config.renderErrors !== false), Effect.fail(error))
3088
+ ),
3089
+ Effect.catchFilter(
3090
+ (error) =>
3091
+ config.renderErrors !== false && CliError.isCliError(error) && error._tag === "UserError"
3092
+ ? Result.succeed(error)
3093
+ : Result.fail(error),
3094
+ (error) => Effect.andThen(showUserError(error), Effect.fail(error))
3055
3095
  ),
3056
3096
  Effect.catchFilter(
3057
3097
  (e) =>
@@ -602,7 +602,7 @@ class FileImpl extends PartBase implements File {
602
602
  this.contentType = info.contentType
603
603
  this.content = Stream.fromChannel(channel)
604
604
  this.contentEffect = channel.pipe(
605
- collectUint8Array,
605
+ Channel.mkUint8Array,
606
606
  Effect.mapError((cause) => MultipartError.fromReason("InternalError", cause))
607
607
  )
608
608
  }
@@ -635,24 +635,15 @@ const defaultWriteFile = (path: string, file: File) =>
635
635
  * **Gotchas**
636
636
  *
637
637
  * This materializes the full content in memory.
638
+ * The source channel must not reuse or mutate emitted buffers, which are retained
639
+ * until collection completes.
638
640
  *
639
641
  * @category converting
640
642
  * @since 4.0.0
641
643
  */
642
644
  export const collectUint8Array = <OE, OD, R>(
643
645
  self: Channel.Channel<Arr.NonEmptyReadonlyArray<Uint8Array>, OE, OD, unknown, unknown, unknown, R>
644
- ): Effect.Effect<Uint8Array<ArrayBuffer>, OE, R> =>
645
- Channel.runFold(self, constant(new Uint8Array(0)), (accumulator, chunk) => {
646
- const totalLength = chunk.reduce((sum, element) => sum + element.length, accumulator.length)
647
- const newAccumulator = new Uint8Array(totalLength)
648
- newAccumulator.set(accumulator, 0)
649
- let offset = accumulator.length
650
- for (const element of chunk) {
651
- newAccumulator.set(element, offset)
652
- offset += element.length
653
- }
654
- return newAccumulator
655
- })
646
+ ): Effect.Effect<Uint8Array<ArrayBuffer>, OE, R> => Channel.mkUint8Array(self)
656
647
 
657
648
  /**
658
649
  * Persists a stream of multipart parts into a record.