effect 4.0.0-beta.50 → 4.0.0-beta.52

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 (135) hide show
  1. package/dist/BigDecimal.d.ts.map +1 -1
  2. package/dist/BigDecimal.js +18 -14
  3. package/dist/BigDecimal.js.map +1 -1
  4. package/dist/BigInt.d.ts.map +1 -1
  5. package/dist/BigInt.js +4 -4
  6. package/dist/BigInt.js.map +1 -1
  7. package/dist/Brand.d.ts +2 -4
  8. package/dist/Brand.d.ts.map +1 -1
  9. package/dist/Brand.js.map +1 -1
  10. package/dist/Data.js +2 -2
  11. package/dist/Data.js.map +1 -1
  12. package/dist/Duration.js +1 -1
  13. package/dist/Duration.js.map +1 -1
  14. package/dist/Schema.d.ts +77 -10
  15. package/dist/Schema.d.ts.map +1 -1
  16. package/dist/Schema.js +119 -18
  17. package/dist/Schema.js.map +1 -1
  18. package/dist/SchemaAST.d.ts +6 -0
  19. package/dist/SchemaAST.d.ts.map +1 -1
  20. package/dist/SchemaAST.js +216 -229
  21. package/dist/SchemaAST.js.map +1 -1
  22. package/dist/SchemaGetter.d.ts +3 -5
  23. package/dist/SchemaGetter.d.ts.map +1 -1
  24. package/dist/SchemaGetter.js +3 -2
  25. package/dist/SchemaGetter.js.map +1 -1
  26. package/dist/SchemaIssue.d.ts.map +1 -1
  27. package/dist/SchemaIssue.js +29 -11
  28. package/dist/SchemaIssue.js.map +1 -1
  29. package/dist/SchemaParser.js +14 -2
  30. package/dist/SchemaParser.js.map +1 -1
  31. package/dist/index.d.ts +3 -0
  32. package/dist/index.d.ts.map +1 -1
  33. package/dist/index.js +3 -0
  34. package/dist/index.js.map +1 -1
  35. package/dist/internal/effect.js +142 -65
  36. package/dist/internal/effect.js.map +1 -1
  37. package/dist/internal/schema/representation.js +1 -2
  38. package/dist/internal/schema/representation.js.map +1 -1
  39. package/dist/internal/schema/schema.d.ts.map +1 -1
  40. package/dist/internal/schema/schema.js +37 -0
  41. package/dist/internal/schema/schema.js.map +1 -1
  42. package/dist/unstable/ai/McpServer.d.ts.map +1 -1
  43. package/dist/unstable/ai/McpServer.js +7 -0
  44. package/dist/unstable/ai/McpServer.js.map +1 -1
  45. package/dist/unstable/cli/index.d.ts +2 -0
  46. package/dist/unstable/cli/index.d.ts.map +1 -1
  47. package/dist/unstable/cli/index.js +2 -0
  48. package/dist/unstable/cli/index.js.map +1 -1
  49. package/dist/unstable/cluster/Runners.d.ts.map +1 -1
  50. package/dist/unstable/cluster/Runners.js +3 -2
  51. package/dist/unstable/cluster/Runners.js.map +1 -1
  52. package/dist/unstable/cluster/SqlMessageStorage.d.ts.map +1 -1
  53. package/dist/unstable/cluster/SqlMessageStorage.js +1 -0
  54. package/dist/unstable/cluster/SqlMessageStorage.js.map +1 -1
  55. package/dist/unstable/cluster/SqlRunnerStorage.d.ts.map +1 -1
  56. package/dist/unstable/cluster/SqlRunnerStorage.js +6 -6
  57. package/dist/unstable/cluster/SqlRunnerStorage.js.map +1 -1
  58. package/dist/unstable/eventlog/SqlEventJournal.d.ts.map +1 -1
  59. package/dist/unstable/eventlog/SqlEventJournal.js +9 -8
  60. package/dist/unstable/eventlog/SqlEventJournal.js.map +1 -1
  61. package/dist/unstable/eventlog/SqlEventLogServerEncrypted.d.ts.map +1 -1
  62. package/dist/unstable/eventlog/SqlEventLogServerEncrypted.js +6 -5
  63. package/dist/unstable/eventlog/SqlEventLogServerEncrypted.js.map +1 -1
  64. package/dist/unstable/eventlog/SqlEventLogServerUnencrypted.d.ts.map +1 -1
  65. package/dist/unstable/eventlog/SqlEventLogServerUnencrypted.js +6 -5
  66. package/dist/unstable/eventlog/SqlEventLogServerUnencrypted.js.map +1 -1
  67. package/dist/unstable/httpapi/HttpApi.js.map +1 -1
  68. package/dist/unstable/httpapi/HttpApiBuilder.d.ts.map +1 -1
  69. package/dist/unstable/httpapi/HttpApiBuilder.js +11 -6
  70. package/dist/unstable/httpapi/HttpApiBuilder.js.map +1 -1
  71. package/dist/unstable/httpapi/HttpApiClient.d.ts +5 -6
  72. package/dist/unstable/httpapi/HttpApiClient.d.ts.map +1 -1
  73. package/dist/unstable/httpapi/HttpApiClient.js.map +1 -1
  74. package/dist/unstable/httpapi/HttpApiEndpoint.d.ts +17 -18
  75. package/dist/unstable/httpapi/HttpApiEndpoint.d.ts.map +1 -1
  76. package/dist/unstable/httpapi/HttpApiEndpoint.js +1 -2
  77. package/dist/unstable/httpapi/HttpApiEndpoint.js.map +1 -1
  78. package/dist/unstable/httpapi/HttpApiError.d.ts +28 -8
  79. package/dist/unstable/httpapi/HttpApiError.d.ts.map +1 -1
  80. package/dist/unstable/httpapi/HttpApiError.js +28 -15
  81. package/dist/unstable/httpapi/HttpApiError.js.map +1 -1
  82. package/dist/unstable/httpapi/HttpApiMiddleware.d.ts +4 -3
  83. package/dist/unstable/httpapi/HttpApiMiddleware.d.ts.map +1 -1
  84. package/dist/unstable/httpapi/HttpApiMiddleware.js +2 -2
  85. package/dist/unstable/httpapi/HttpApiMiddleware.js.map +1 -1
  86. package/dist/unstable/httpapi/OpenApi.d.ts +1 -10
  87. package/dist/unstable/httpapi/OpenApi.d.ts.map +1 -1
  88. package/dist/unstable/httpapi/OpenApi.js +2 -11
  89. package/dist/unstable/httpapi/OpenApi.js.map +1 -1
  90. package/dist/unstable/observability/OtlpMetrics.js +1 -1
  91. package/dist/unstable/observability/OtlpMetrics.js.map +1 -1
  92. package/dist/unstable/observability/internal/protobuf.js +4 -4
  93. package/dist/unstable/observability/internal/protobuf.js.map +1 -1
  94. package/dist/unstable/rpc/RpcSerialization.d.ts +11 -0
  95. package/dist/unstable/rpc/RpcSerialization.d.ts.map +1 -1
  96. package/dist/unstable/rpc/RpcSerialization.js +14 -9
  97. package/dist/unstable/rpc/RpcSerialization.js.map +1 -1
  98. package/package.json +1 -1
  99. package/src/BigDecimal.ts +20 -16
  100. package/src/BigInt.ts +4 -4
  101. package/src/Brand.ts +2 -4
  102. package/src/Data.ts +1 -1
  103. package/src/Duration.ts +1 -1
  104. package/src/Schema.ts +183 -23
  105. package/src/SchemaAST.ts +315 -267
  106. package/src/SchemaGetter.ts +4 -6
  107. package/src/SchemaIssue.ts +28 -15
  108. package/src/SchemaParser.ts +8 -2
  109. package/src/index.ts +3 -0
  110. package/src/internal/effect.ts +196 -69
  111. package/src/internal/schema/representation.ts +1 -2
  112. package/src/internal/schema/schema.ts +43 -0
  113. package/src/unstable/ai/McpServer.ts +8 -0
  114. package/src/unstable/cli/index.ts +2 -0
  115. package/src/unstable/cluster/Runners.ts +8 -5
  116. package/src/unstable/cluster/SqlMessageStorage.ts +1 -0
  117. package/src/unstable/cluster/SqlRunnerStorage.ts +12 -6
  118. package/src/unstable/eventlog/SqlEventJournal.ts +10 -2
  119. package/src/unstable/eventlog/SqlEventLogServerEncrypted.ts +8 -3
  120. package/src/unstable/eventlog/SqlEventLogServerUnencrypted.ts +9 -3
  121. package/src/unstable/httpapi/HttpApi.ts +1 -1
  122. package/src/unstable/httpapi/HttpApiBuilder.ts +13 -6
  123. package/src/unstable/httpapi/HttpApiClient.ts +5 -6
  124. package/src/unstable/httpapi/HttpApiEndpoint.ts +6 -7
  125. package/src/unstable/httpapi/HttpApiError.ts +43 -22
  126. package/src/unstable/httpapi/HttpApiMiddleware.ts +6 -5
  127. package/src/unstable/httpapi/OpenApi.ts +3 -15
  128. package/src/unstable/observability/OtlpMetrics.ts +1 -1
  129. package/src/unstable/observability/internal/protobuf.ts +4 -4
  130. package/src/unstable/rpc/RpcSerialization.ts +41 -36
  131. package/dist/internal/schema/to-codec.d.ts +0 -2
  132. package/dist/internal/schema/to-codec.d.ts.map +0 -1
  133. package/dist/internal/schema/to-codec.js +0 -126
  134. package/dist/internal/schema/to-codec.js.map +0 -1
  135. package/src/internal/schema/to-codec.ts +0 -138
package/src/BigDecimal.ts CHANGED
@@ -142,6 +142,10 @@ export const makeNormalizedUnsafe = (value: bigint, scale: number): BigDecimal =
142
142
 
143
143
  const bigint0 = BigInt(0)
144
144
  const bigint1 = BigInt(1)
145
+ const bigint_1 = BigInt(-1)
146
+ const bigint2 = BigInt(2)
147
+ const bigint5 = BigInt(5)
148
+ const bigint_5 = BigInt(-5)
145
149
  const bigint10 = BigInt(10)
146
150
  const zero = makeNormalizedUnsafe(bigint0, 0)
147
151
  const one = makeNormalizedUnsafe(bigint1, 0)
@@ -2320,32 +2324,32 @@ export const round: {
2320
2324
  return (isPositive(self) ? ceil(self, scale) : floor(self, scale))
2321
2325
 
2322
2326
  case "half-ceil":
2323
- return floor(sum(self, make(5n, scale + 1)), scale)
2327
+ return floor(sum(self, make(bigint5, scale + 1)), scale)
2324
2328
 
2325
2329
  case "half-floor":
2326
- return ceil(sum(self, make(-5n, scale + 1)), scale)
2330
+ return ceil(sum(self, make(bigint_5, scale + 1)), scale)
2327
2331
 
2328
2332
  case "half-to-zero":
2329
2333
  return isNegative(self)
2330
- ? floor(sum(self, make(5n, scale + 1)), scale)
2331
- : ceil(sum(self, make(-5n, scale + 1)), scale)
2334
+ ? floor(sum(self, make(bigint5, scale + 1)), scale)
2335
+ : ceil(sum(self, make(bigint_5, scale + 1)), scale)
2332
2336
 
2333
2337
  case "half-from-zero":
2334
2338
  return isNegative(self)
2335
- ? ceil(sum(self, make(-5n, scale + 1)), scale)
2336
- : floor(sum(self, make(5n, scale + 1)), scale)
2339
+ ? ceil(sum(self, make(bigint_5, scale + 1)), scale)
2340
+ : floor(sum(self, make(bigint5, scale + 1)), scale)
2337
2341
  }
2338
2342
 
2339
- const halfCeil = floor(sum(self, make(5n, scale + 1)), scale)
2340
- const halfFloor = ceil(sum(self, make(-5n, scale + 1)), scale)
2343
+ const halfCeil = floor(sum(self, make(bigint5, scale + 1)), scale)
2344
+ const halfFloor = ceil(sum(self, make(bigint_5, scale + 1)), scale)
2341
2345
  const digit = digitAt(halfCeil, scale)
2342
2346
 
2343
2347
  switch (mode) {
2344
2348
  case "half-even":
2345
- return equals(halfCeil, halfFloor) ? halfCeil : (digit % 2n === 0n) ? halfCeil : halfFloor
2349
+ return equals(halfCeil, halfFloor) ? halfCeil : (digit % bigint2 === bigint0) ? halfCeil : halfFloor
2346
2350
 
2347
2351
  case "half-odd":
2348
- return equals(halfCeil, halfFloor) ? halfCeil : (digit % 2n === 0n) ? halfFloor : halfCeil
2352
+ return equals(halfCeil, halfFloor) ? halfCeil : (digit % bigint2 === bigint0) ? halfFloor : halfCeil
2349
2353
  }
2350
2354
  })
2351
2355
 
@@ -2421,7 +2425,7 @@ export const truncate: {
2421
2425
  }
2422
2426
 
2423
2427
  // BigInt division truncates towards zero
2424
- return make(self.value / (10n ** BigInt(self.scale - scale)), scale)
2428
+ return make(self.value / (bigint10 ** BigInt(self.scale - scale)), scale)
2425
2429
  })
2426
2430
 
2427
2431
  /**
@@ -2485,7 +2489,7 @@ export const ceil: {
2485
2489
  const truncated = truncate(self, scale)
2486
2490
 
2487
2491
  if (isPositive(self) && isLessThan(truncated, self)) {
2488
- return sum(truncated, make(1n, scale))
2492
+ return sum(truncated, make(bigint1, scale))
2489
2493
  }
2490
2494
 
2491
2495
  return truncated
@@ -2517,11 +2521,11 @@ export const digitAt: {
2517
2521
  (self: BigDecimal, scale: number): bigint
2518
2522
  } = dual(2, (self: BigDecimal, scale: number): bigint => {
2519
2523
  if (self.scale < scale) {
2520
- return 0n
2524
+ return bigint0
2521
2525
  }
2522
2526
 
2523
- const scaled = self.value / (10n ** BigInt(self.scale - scale))
2524
- return scaled % 10n
2527
+ const scaled = self.value / (bigint10 ** BigInt(self.scale - scale))
2528
+ return scaled % bigint10
2525
2529
  })
2526
2530
 
2527
2531
  /**
@@ -2594,7 +2598,7 @@ export const floor: {
2594
2598
  const truncated = truncate(self, scale)
2595
2599
 
2596
2600
  if (isNegative(self) && isGreaterThan(truncated, self)) {
2597
- return sum(truncated, make(-1n, scale))
2601
+ return sum(truncated, make(bigint_1, scale))
2598
2602
  }
2599
2603
 
2600
2604
  return truncated
package/src/BigInt.ts CHANGED
@@ -1248,17 +1248,17 @@ export const remainder: {
1248
1248
  *
1249
1249
  * @since 4.0.0
1250
1250
  */
1251
- export const ReducerSum: Reducer.Reducer<bigint> = Reducer.make((a, b) => a + b, 0n)
1251
+ export const ReducerSum: Reducer.Reducer<bigint> = Reducer.make((a, b) => a + b, bigint0)
1252
1252
 
1253
1253
  /**
1254
1254
  * A `Reducer` for combining `bigint`s using multiplication.
1255
1255
  *
1256
1256
  * @since 4.0.0
1257
1257
  */
1258
- export const ReducerMultiply: Reducer.Reducer<bigint> = Reducer.make((a, b) => a * b, 1n, (collection) => {
1259
- let acc = 1n
1258
+ export const ReducerMultiply: Reducer.Reducer<bigint> = Reducer.make((a, b) => a * b, bigint1, (collection) => {
1259
+ let acc = bigint1
1260
1260
  for (const n of collection) {
1261
- if (n === 0n) return 0n
1261
+ if (n === bigint0) return bigint0
1262
1262
  acc *= n
1263
1263
  }
1264
1264
  return acc
package/src/Brand.ts CHANGED
@@ -8,6 +8,7 @@
8
8
  import * as Arr from "./Array.ts"
9
9
  import * as Option from "./Option.ts"
10
10
  import * as Result from "./Result.ts"
11
+ import type * as Schema from "./Schema.ts"
11
12
  import * as AST from "./SchemaAST.ts"
12
13
  import type * as Issue from "./SchemaIssue.ts"
13
14
  import type * as Types from "./Types.ts"
@@ -192,10 +193,7 @@ export function nominal<A extends Brand<any>>(): Constructor<A> {
192
193
  * @since 2.0.0
193
194
  */
194
195
  export function make<A extends Brand<any>>(
195
- filter: (unbranded: Brand.Unbranded<A>) => undefined | boolean | string | Issue.Issue | {
196
- readonly path: ReadonlyArray<PropertyKey>
197
- readonly message: string
198
- }
196
+ filter: (unbranded: Brand.Unbranded<A>) => Schema.FilterOutput
199
197
  ): Constructor<A> {
200
198
  return check(AST.makeFilter(filter))
201
199
  }
package/src/Data.ts CHANGED
@@ -962,7 +962,7 @@ export const taggedEnum: {
962
962
  } else if (tag === "$match") {
963
963
  return taggedMatch
964
964
  }
965
- return (props: any) => ({ _tag: tag, ...props })
965
+ return (props: any) => ({ ...props, _tag: tag })
966
966
  }
967
967
  }
968
968
  ) as any
package/src/Duration.ts CHANGED
@@ -864,7 +864,7 @@ export const toHrTime = (self: Duration): [seconds: number, nanos: number] => {
864
864
  return [-Infinity, 0]
865
865
  case "Nanos": {
866
866
  const n = self.value.nanos
867
- const sign = n < bigint0 ? -1n : 1n
867
+ const sign = n < bigint0 ? -BigInt(1) : BigInt(1)
868
868
  const a = n < bigint0 ? -n : n
869
869
  return [
870
870
  Number(sign * (a / bigint1e9)),
package/src/Schema.ts CHANGED
@@ -103,7 +103,7 @@ import * as Equivalence from "./Equivalence.ts"
103
103
  import * as Exit_ from "./Exit.ts"
104
104
  import type { Formatter } from "./Formatter.ts"
105
105
  import { format, formatPropertyKey } from "./Formatter.ts"
106
- import { identity } from "./Function.ts"
106
+ import { identity, memoize } from "./Function.ts"
107
107
  import * as HashMap_ from "./HashMap.ts"
108
108
  import * as HashSet_ from "./HashSet.ts"
109
109
  import * as core from "./internal/core.ts"
@@ -113,7 +113,6 @@ import * as InternalEquivalence from "./internal/schema/equivalence.ts"
113
113
  import * as InternalStandard from "./internal/schema/representation.ts"
114
114
  import * as InternalSchema from "./internal/schema/schema.ts"
115
115
  import { SchemaError } from "./internal/schema/schema.ts"
116
- import * as InternalToCodec from "./internal/schema/to-codec.ts"
117
116
  import * as JsonPatch from "./JsonPatch.ts"
118
117
  import * as JsonSchema from "./JsonSchema.ts"
119
118
  import { remainder } from "./Number.ts"
@@ -4930,9 +4929,8 @@ export function instanceOf<C extends abstract new(...args: any) => any, Iso = In
4930
4929
  * Used when building low-level AST transformations that bridge two schema types.
4931
4930
  *
4932
4931
  * @since 4.0.0
4933
- * @experimental
4934
4932
  */
4935
- export function link<T>() { // TODO: better name
4933
+ export function link<T>() {
4936
4934
  return <To extends Top>(
4937
4935
  encodeTo: To,
4938
4936
  transformation: {
@@ -4951,32 +4949,106 @@ export function link<T>() { // TODO: better name
4951
4949
  /**
4952
4950
  * Creates a custom filter check from a predicate function. The predicate
4953
4951
  * receives the input value, the schema's AST, and parse options, and returns
4954
- * `true`/`undefined` on success or a failure description on error.
4952
+ * a value of type {@link FilterOutput}.
4953
+ *
4954
+ * **Example** (Failure at a nested path)
4955
4955
  *
4956
- * **Example** (Custom filter check)
4957
4956
  * ```ts
4958
4957
  * import { Schema } from "effect"
4959
4958
  *
4960
- * // Check that a number is even
4961
- * const isEven = Schema.makeFilter(
4962
- * (n: number) => n % 2 === 0 || "expected an even number"
4959
+ * const schema = Schema.Struct({ password: Schema.String, confirmPassword: Schema.String }).check(
4960
+ * Schema.makeFilter((o) =>
4961
+ * o.password === o.confirmPassword
4962
+ * ? undefined
4963
+ * : { path: ["password"], issue: "password and confirmPassword must match" }
4964
+ * )
4965
+ * )
4966
+ *
4967
+ * console.log(String(Schema.decodeUnknownExit(schema)({ password: "123456", confirmPassword: "1234567" })))
4968
+ * // Failure(Cause([Fail(SchemaError: password and confirmPassword must match
4969
+ * // at ["password"])]))
4970
+ * ```
4971
+ *
4972
+ * **Example** (Reporting multiple failures at once)
4973
+ *
4974
+ * ```ts
4975
+ * import { Schema } from "effect"
4976
+ *
4977
+ * const schema = Schema.Struct({ a: Schema.Finite, b: Schema.Finite, c: Schema.Finite }).check(
4978
+ * Schema.makeFilter((o) => {
4979
+ * const issues: Array<Schema.FilterIssue> = []
4980
+ * if (o.a > 0) {
4981
+ * if (o.b <= 0) issues.push({ path: ["b"], issue: "b must be greater than 0" })
4982
+ * if (o.c <= 0) issues.push({ path: ["c"], issue: "c must be greater than 0" })
4983
+ * }
4984
+ * return issues
4985
+ * })
4963
4986
  * )
4964
4987
  *
4965
- * const EvenNumber = Schema.Number.check(isEven)
4988
+ * console.log(String(Schema.decodeUnknownExit(schema)({ a: 1, b: 0, c: 0 })))
4989
+ * // Failure(Cause([Fail(SchemaError: b must be greater than 0
4990
+ * // at ["b"]
4991
+ * // c must be greater than 0
4992
+ * // at ["c"])]))
4966
4993
  * ```
4967
4994
  *
4968
4995
  * @category Checks Constructors
4969
4996
  * @since 4.0.0
4970
4997
  */
4971
4998
  export const makeFilter: <T>(
4972
- filter: (input: T, ast: AST.AST, options: AST.ParseOptions) => undefined | boolean | string | Issue.Issue | {
4973
- readonly path: ReadonlyArray<PropertyKey>
4974
- readonly message: string
4975
- },
4999
+ filter: (input: T, ast: AST.AST, options: AST.ParseOptions) => FilterOutput,
4976
5000
  annotations?: Annotations.Filter | undefined,
4977
5001
  abort?: boolean
4978
5002
  ) => AST.Filter<T> = AST.makeFilter
4979
5003
 
5004
+ /**
5005
+ * A single failure reported by a filter predicate. Used as the element type
5006
+ * of the array arm of {@link FilterOutput}, and also accepted on its own.
5007
+ *
5008
+ * - `string`: failure with that string as the message. Produces an
5009
+ * {@link Issue.InvalidValue} wrapping the input, with the string used as
5010
+ * the issue's `message` annotation.
5011
+ * - {@link Issue.Issue}: a fully-formed issue, returned as-is.
5012
+ * - `{ path, issue }`: failure attached to a nested path. `issue` is either
5013
+ * a `string` (wrapped in an {@link Issue.InvalidValue}) or a full
5014
+ * {@link Issue.Issue}; the result is wrapped in an {@link Issue.Pointer}
5015
+ * at the given `path`.
5016
+ *
5017
+ * @category model
5018
+ * @since 4.0.0
5019
+ */
5020
+ export type FilterIssue = string | Issue.Issue | {
5021
+ readonly path: ReadonlyArray<PropertyKey>
5022
+ readonly issue: string | Issue.Issue
5023
+ }
5024
+
5025
+ /**
5026
+ * The value a filter predicate (see {@link makeFilter}) may return.
5027
+ *
5028
+ * Each shape is normalized into an {@link Issue.Issue} (or `undefined` for
5029
+ * success) before being attached to the parse result:
5030
+ *
5031
+ * - `undefined`: success. The input satisfies the filter.
5032
+ * - `true`: success. Equivalent to `undefined`, useful when the predicate is
5033
+ * a plain boolean expression.
5034
+ * - `false`: generic failure. Produces an {@link Issue.InvalidValue} wrapping
5035
+ * the input, with no custom message.
5036
+ * - {@link FilterIssue}: a single failure. See {@link FilterIssue} for the
5037
+ * shapes (`string`, {@link Issue.Issue}, or `{ path, issue }`).
5038
+ * - `ReadonlyArray<FilterIssue>`: several failures reported together. An
5039
+ * empty array is treated as success; a single-element array is equivalent
5040
+ * to returning that element directly; otherwise the entries are grouped
5041
+ * into an {@link Issue.Composite}.
5042
+ *
5043
+ * @category model
5044
+ * @since 4.0.0
5045
+ */
5046
+ export type FilterOutput =
5047
+ | undefined
5048
+ | boolean
5049
+ | FilterIssue
5050
+ | ReadonlyArray<FilterIssue>
5051
+
4980
5052
  /**
4981
5053
  * Groups multiple checks into a single {@link AST.FilterGroup}, applying
4982
5054
  * optional shared annotations to the group as a whole.
@@ -8794,6 +8866,8 @@ export interface DurationFromNanos extends decodeTo<Duration, BigInt> {
8794
8866
  readonly "Rebuild": DurationFromNanos
8795
8867
  }
8796
8868
 
8869
+ const bigint0 = globalThis.BigInt(0)
8870
+
8797
8871
  /**
8798
8872
  * A transformation schema that decodes a non-negative `bigint` into a
8799
8873
  * `Duration`, treating the `bigint` value as the duration in nanoseconds.
@@ -8807,7 +8881,7 @@ export interface DurationFromNanos extends decodeTo<Duration, BigInt> {
8807
8881
  * @category Duration
8808
8882
  * @since 4.0.0
8809
8883
  */
8810
- export const DurationFromNanos: DurationFromNanos = BigInt.check(isGreaterThanOrEqualToBigInt(0n)).pipe(
8884
+ export const DurationFromNanos: DurationFromNanos = BigInt.check(isGreaterThanOrEqualToBigInt(bigint0)).pipe(
8811
8885
  decodeTo(Duration, Transformation.durationFromNanos)
8812
8886
  )
8813
8887
 
@@ -11420,7 +11494,66 @@ export function toJsonSchemaDocument(schema: Top, options?: ToJsonSchemaOptions)
11420
11494
  * @since 4.0.0
11421
11495
  */
11422
11496
  export function toCodecJson<T, E, RD, RE>(schema: Codec<T, E, RD, RE>): Codec<T, Json, RD, RE> {
11423
- return make(InternalToCodec.toCodecJson(schema.ast))
11497
+ return make(toCodecJsonTop(schema.ast))
11498
+ }
11499
+
11500
+ const toCodecJsonTop = AST.toCodec((ast) => {
11501
+ const out = toCodecJsonBase(ast, toCodecJsonTop)
11502
+ return out !== ast && AST.isOptional(ast) ? AST.optionalKeyLastLink(out) : out
11503
+ })
11504
+
11505
+ function toCodecJsonBase(ast: AST.AST, recur: (ast: AST.AST) => AST.AST): AST.AST {
11506
+ switch (ast._tag) {
11507
+ case "Declaration": {
11508
+ const getLink = ast.annotations?.toCodecJson ?? ast.annotations?.toCodec
11509
+ if (Predicate.isFunction(getLink)) {
11510
+ const tps = AST.isDeclaration(ast)
11511
+ ? ast.typeParameters.map((tp) => InternalSchema.make(AST.toEncoded(tp)))
11512
+ : []
11513
+ const link = getLink(tps)
11514
+ const to = recur(link.to)
11515
+ return AST.replaceEncoding(ast, to === link.to ? [link] : [new AST.Link(to, link.transformation)])
11516
+ }
11517
+ return AST.replaceEncoding(ast, [AST.unknownToNull])
11518
+ }
11519
+ case "Unknown":
11520
+ case "ObjectKeyword":
11521
+ return AST.replaceEncoding(ast, [AST.unknownToJson])
11522
+ case "Undefined":
11523
+ case "Void":
11524
+ case "Literal":
11525
+ case "Number":
11526
+ return ast.toCodecJson()
11527
+ case "UniqueSymbol":
11528
+ case "Symbol":
11529
+ case "BigInt":
11530
+ return ast.toCodecStringTree()
11531
+ case "Objects": {
11532
+ if (ast.propertySignatures.some((ps) => typeof ps.name !== "string")) {
11533
+ throw new globalThis.Error("Objects property names must be strings", { cause: ast })
11534
+ }
11535
+ return ast.recur(recur)
11536
+ }
11537
+ case "Union": {
11538
+ const sortedTypes = InternalSchema.jsonReorder(ast.types)
11539
+ if (sortedTypes !== ast.types) {
11540
+ return new AST.Union(
11541
+ sortedTypes,
11542
+ ast.mode,
11543
+ ast.annotations,
11544
+ ast.checks,
11545
+ ast.encoding,
11546
+ ast.context
11547
+ ).recur(recur)
11548
+ }
11549
+ return ast.recur(recur)
11550
+ }
11551
+ case "Arrays":
11552
+ case "Suspend":
11553
+ return ast.recur(recur)
11554
+ }
11555
+ // `Schema.Any` is used as an escape hatch
11556
+ return ast
11424
11557
  }
11425
11558
 
11426
11559
  /**
@@ -11431,7 +11564,32 @@ export function toCodecJson<T, E, RD, RE>(schema: Codec<T, E, RD, RE>): Codec<T,
11431
11564
  * @since 4.0.0
11432
11565
  */
11433
11566
  export function toCodecIso<S extends Top>(schema: S): Codec<S["Type"], S["Iso"]> {
11434
- return make(InternalToCodec.toCodecIso(AST.toType(schema.ast)))
11567
+ return make(toCodecIsoTop(AST.toType(schema.ast)))
11568
+ }
11569
+
11570
+ const toCodecIsoTop = memoize((ast: AST.AST): AST.AST => {
11571
+ const out = toCodecIsoBase(ast, toCodecIsoTop)
11572
+ return out !== ast && AST.isOptional(ast) ? AST.optionalKeyLastLink(out) : out
11573
+ })
11574
+
11575
+ function toCodecIsoBase(ast: AST.AST, recur: (ast: AST.AST) => AST.AST): AST.AST {
11576
+ switch (ast._tag) {
11577
+ case "Declaration": {
11578
+ const getLink = ast.annotations?.toCodecIso ?? ast.annotations?.toCodec
11579
+ if (Predicate.isFunction(getLink)) {
11580
+ const link = getLink(ast.typeParameters.map((tp) => InternalSchema.make(tp)))
11581
+ const to = recur(link.to)
11582
+ return AST.replaceEncoding(ast, to === link.to ? [link] : [new AST.Link(to, link.transformation)])
11583
+ }
11584
+ return ast
11585
+ }
11586
+ case "Arrays":
11587
+ case "Objects":
11588
+ case "Union":
11589
+ case "Suspend":
11590
+ return ast.recur(recur)
11591
+ }
11592
+ return ast
11435
11593
  }
11436
11594
 
11437
11595
  /**
@@ -11470,11 +11628,13 @@ export function toCodecStringTree<T, E, RD, RE>(
11470
11628
  schema: Codec<T, E, RD, RE>,
11471
11629
  options?: { readonly keepDeclarations?: boolean | undefined }
11472
11630
  ): Codec<T, unknown, RD, RE> {
11473
- if (options?.keepDeclarations === true) {
11474
- return make(toCodecEnsureArray(serializerStringTreeKeepDeclarations(schema.ast)))
11475
- } else {
11476
- return make(toCodecEnsureArray(serializerStringTree(schema.ast)))
11477
- }
11631
+ return make(
11632
+ toCodecEnsureArray(
11633
+ options?.keepDeclarations === true
11634
+ ? serializerStringTreeKeepDeclarations(schema.ast)
11635
+ : serializerStringTree(schema.ast)
11636
+ )
11637
+ )
11478
11638
  }
11479
11639
 
11480
11640
  type XmlEncoderOptions = {
@@ -11607,7 +11767,7 @@ function getStringTreePriority(ast: AST.AST): number {
11607
11767
  }
11608
11768
  }
11609
11769
 
11610
- const treeReorder = InternalToCodec.makeReorder(getStringTreePriority)
11770
+ const treeReorder = InternalSchema.makeReorder(getStringTreePriority)
11611
11771
 
11612
11772
  function serializerTree(
11613
11773
  ast: AST.AST,