effect 4.0.0-rc.113 → 4.0.0-rc.115

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 (76) hide show
  1. package/dist/Effect.d.ts +268 -7
  2. package/dist/Effect.d.ts.map +1 -1
  3. package/dist/Effect.js +33 -2
  4. package/dist/Effect.js.map +1 -1
  5. package/dist/Effectable.d.ts +1 -2
  6. package/dist/Effectable.d.ts.map +1 -1
  7. package/dist/Effectable.js.map +1 -1
  8. package/dist/FileSystem.d.ts +3 -4
  9. package/dist/FileSystem.d.ts.map +1 -1
  10. package/dist/FileSystem.js.map +1 -1
  11. package/dist/Match.d.ts +1 -14
  12. package/dist/Match.d.ts.map +1 -1
  13. package/dist/Schema.d.ts +4 -4
  14. package/dist/Schema.d.ts.map +1 -1
  15. package/dist/SchemaAST.d.ts.map +1 -1
  16. package/dist/SchemaAST.js +43 -23
  17. package/dist/SchemaAST.js.map +1 -1
  18. package/dist/SchemaParser.d.ts.map +1 -1
  19. package/dist/SchemaParser.js +3 -2
  20. package/dist/SchemaParser.js.map +1 -1
  21. package/dist/SchemaRepresentation.d.ts +39 -24
  22. package/dist/SchemaRepresentation.d.ts.map +1 -1
  23. package/dist/SchemaRepresentation.js +37 -23
  24. package/dist/SchemaRepresentation.js.map +1 -1
  25. package/dist/internal/arbitrary/schema.js.map +1 -1
  26. package/dist/internal/effect.js +16 -8
  27. package/dist/internal/effect.js.map +1 -1
  28. package/dist/internal/schema/fromJsonSchemaDocument.js +221 -230
  29. package/dist/internal/schema/fromJsonSchemaDocument.js.map +1 -1
  30. package/dist/internal/schema/make.js +8 -3
  31. package/dist/internal/schema/make.js.map +1 -1
  32. package/dist/internal/schema/toCodeDocument.js +4 -4
  33. package/dist/internal/schema/toCodeDocument.js.map +1 -1
  34. package/dist/internal/schema/toEquivalence.js +2 -2
  35. package/dist/internal/schema/toEquivalence.js.map +1 -1
  36. package/dist/internal/schema/toFormatter.js +2 -2
  37. package/dist/internal/schema/toFormatter.js.map +1 -1
  38. package/dist/unstable/cli/Prompt.d.ts +6 -2
  39. package/dist/unstable/cli/Prompt.d.ts.map +1 -1
  40. package/dist/unstable/cli/Prompt.js +8 -7
  41. package/dist/unstable/cli/Prompt.js.map +1 -1
  42. package/dist/unstable/cli/internal/command.d.ts +1 -6
  43. package/dist/unstable/cli/internal/command.d.ts.map +1 -1
  44. package/dist/unstable/cli/internal/command.js +2 -0
  45. package/dist/unstable/cli/internal/command.js.map +1 -1
  46. package/dist/unstable/http/HttpEffect.d.ts.map +1 -1
  47. package/dist/unstable/http/HttpEffect.js +6 -2
  48. package/dist/unstable/http/HttpEffect.js.map +1 -1
  49. package/dist/unstable/http/HttpServerResponse.d.ts +13 -2
  50. package/dist/unstable/http/HttpServerResponse.d.ts.map +1 -1
  51. package/dist/unstable/http/HttpServerResponse.js +19 -5
  52. package/dist/unstable/http/HttpServerResponse.js.map +1 -1
  53. package/dist/unstable/persistence/Persistence.d.ts.map +1 -1
  54. package/dist/unstable/persistence/Persistence.js +2 -10
  55. package/dist/unstable/persistence/Persistence.js.map +1 -1
  56. package/package.json +2 -2
  57. package/src/Effect.ts +271 -7
  58. package/src/Effectable.ts +2 -2
  59. package/src/FileSystem.ts +3 -4
  60. package/src/Match.ts +1 -1
  61. package/src/Schema.ts +4 -7
  62. package/src/SchemaAST.ts +48 -25
  63. package/src/SchemaParser.ts +3 -2
  64. package/src/SchemaRepresentation.ts +39 -24
  65. package/src/internal/arbitrary/schema.ts +16 -16
  66. package/src/internal/effect.ts +34 -11
  67. package/src/internal/schema/fromJsonSchemaDocument.ts +294 -268
  68. package/src/internal/schema/make.ts +9 -4
  69. package/src/internal/schema/toCodeDocument.ts +4 -4
  70. package/src/internal/schema/toEquivalence.ts +2 -2
  71. package/src/internal/schema/toFormatter.ts +2 -2
  72. package/src/unstable/cli/Prompt.ts +22 -11
  73. package/src/unstable/cli/internal/command.ts +2 -0
  74. package/src/unstable/http/HttpEffect.ts +5 -2
  75. package/src/unstable/http/HttpServerResponse.ts +21 -5
  76. package/src/unstable/persistence/Persistence.ts +6 -16
@@ -2175,7 +2175,8 @@ const jsonSchemaRevivers: ReadonlyArray<AnyReviver> = [
2175
2175
  * **Gotchas**
2176
2176
  *
2177
2177
  * Use `patterns: "apply"` only for trusted documents because regular expression evaluation may block for an unbounded
2178
- * amount of time. `patterns: "ignore"` weakens validation by accepting values that the source document may reject.
2178
+ * amount of time. `patterns: "ignore"` can admit values the source rejects, but can also reject previously valid
2179
+ * values inside `oneOf` when removing constraints makes multiple branches match.
2179
2180
  * Ignoring `patternProperties` also skips its value constraints and `additionalProperties`, because matching keys cannot
2180
2181
  * be determined without evaluating the patterns.
2181
2182
  * `onEnter` must return a JSON Schema object. Its result is used directly, and exceptions raised by the callback pass
@@ -2835,30 +2836,39 @@ export function fromRepresentations(
2835
2836
  *
2836
2837
  * **Details**
2837
2838
  *
2838
- * For the Draft 2020-12 subset translated exactly by this importer, compiling the imported schema through
2839
- * {@link toRepresentation} and {@link toJsonSchemaDocument} produces a document that accepts the same JSON values as
2840
- * the input. This is a semantic round-trip guarantee; keyword layout, definitions, and annotations may be normalized.
2839
+ * Translates a Draft 2020-12 subset using Effect schemas and built-in checks. Validation follows those checks and the
2840
+ * decoder's parse options, so import and re-export do not guarantee identical accepted values or a lossless round trip.
2841
+ * Import errors explain the unsupported constraint or reference and include its source path.
2841
2842
  *
2842
2843
  * **Gotchas**
2843
2844
  *
2844
- * - `$dynamicRef`, `contains`, `dependentRequired`, `dependentSchemas`, `not`, active `if` / `then` / `else`,
2845
- * `unevaluatedItems`, and `unevaluatedProperties` throw an `Unsupported JSON Schema keyword` error. Inactive
2845
+ * - `{ not: {} }` imports as `Never`. Other uses of `not` are unsupported.
2846
+ * - When `additionalProperties` is `true`, `{}`, or omitted, additional values use `Schema.Json` and are retained.
2847
+ * Closed objects normally strip excess properties by default; pass `onExcessProperty: "error"` to reject them.
2848
+ * Closed empty objects instead use `Schema.Record(Schema.String, Schema.Never)` and reject string-keyed entries
2849
+ * regardless of that option.
2850
+ * Object keyword scopes still constrain declared properties in intersections. Combinations requiring index
2851
+ * signatures that exclude explicit properties or patterned keys are rejected with an explanation of the limitation.
2852
+ * - Property count and name checks run on the decoded object, after excess properties have been stripped.
2853
+ * - String length checks count UTF-16 code units. `integer` uses `Schema.isInt`, which requires safe integers.
2854
+ * Applied patterns use `Schema.isPattern` without adding a Unicode flag.
2855
+ * - `$dynamicRef`, `contains`, `dependentRequired`, `dependentSchemas`, active `if` / `then` / `else`,
2856
+ * `unevaluatedItems`, and `unevaluatedProperties` are rejected with an error identifying the unsupported keyword. Inactive
2846
2857
  * conditional keywords and `minContains` / `maxContains` without `contains` have no validation effect and are ignored.
2847
- * - Objects and arrays used as `const` values or `enum` members throw an `Unsupported structured JSON Schema value`
2848
- * error.
2858
+ * - Objects and arrays used as `const` values or `enum` members are rejected. Only strings, numbers, booleans, and null
2859
+ * are supported.
2849
2860
  * - Intersections of overlapping unions are limited to disjoint root-type partitions and finite primitive `anyOf`
2850
- * literal sets. Other union intersections, including cases that would duplicate a nested choice, throw an
2851
- * `Unsupported intersection of overlapping unions` error.
2861
+ * literal sets. Other union intersections, including cases that would duplicate a nested choice, are rejected.
2852
2862
  * - Unknown extension keywords are ignored and their semantics are not enforced.
2853
2863
  * - Only direct local references to top-level definitions in the form `#/$defs/<escaped-token>` are supported. Root
2854
- * references, external references, and pointers below a definition throw an `Unsupported reference` error. A direct
2855
- * reference to a missing definition throws an `Invalid reference` error.
2864
+ * references, external references, and pointers below a definition are rejected with the supported reference format.
2865
+ * Missing definitions are reported by name. References reached inside nested schema
2866
+ * resources introduced by `$id` are rejected instead of resolved against the top-level definitions.
2856
2867
  * - Built-in declarations and checks are reconstructed with importer-owned revivers.
2857
2868
  * - Pattern constraints reached during translation cause an error by default. Use `patterns: "apply"` only for trusted
2858
- * documents, or `patterns: "ignore"` to weaken validation explicitly; ignored patterns are outside the round-trip
2859
- * guarantee.
2860
- * - `onEnter` results replace the corresponding input nodes, so the round-trip guarantee applies to the rewritten
2861
- * document.
2869
+ * documents, or `patterns: "ignore"` to skip them. Ignoring patterns can both admit invalid values and reject valid
2870
+ * values when `oneOf` branches start overlapping.
2871
+ * - `onEnter` results replace the corresponding input nodes before translation.
2862
2872
  * - Callback results are used directly, and exceptions raised by a callback pass through unchanged.
2863
2873
  *
2864
2874
  * @see {@link fromJsonSchemaMultiDocument} for multiple roots sharing definitions
@@ -2881,21 +2891,26 @@ export function fromJsonSchemaDocument(
2881
2891
  *
2882
2892
  * Use when multiple imported roots share reachable definitions, aliases, or recursion.
2883
2893
  *
2894
+ * **Details**
2895
+ *
2896
+ * Uses the same best-effort translation, built-in checks, and excess-property behavior as {@link fromJsonSchemaDocument}.
2897
+ *
2884
2898
  * **Gotchas**
2885
2899
  *
2886
2900
  * - Only definitions reachable from a root are translated.
2887
- * - Unsupported standard validation and applicator keywords throw an `Unsupported JSON Schema keyword` error. Unknown
2901
+ * - Unsupported standard validation and applicator keywords are rejected with an error identifying the keyword. Unknown
2888
2902
  * extension keywords are ignored and their semantics are not enforced.
2889
- * - Objects and arrays used as `const` values or `enum` members throw an `Unsupported structured JSON Schema value`
2890
- * error.
2903
+ * - Objects and arrays used as `const` values or `enum` members are rejected. Only strings, numbers, booleans, and null
2904
+ * are supported.
2891
2905
  * - Intersections of overlapping unions are limited to disjoint root-type partitions and finite primitive `anyOf`
2892
- * literal sets. Other union intersections, including cases that would duplicate a nested choice, throw an
2893
- * `Unsupported intersection of overlapping unions` error.
2906
+ * literal sets. Other union intersections, including cases that would duplicate a nested choice, are rejected.
2894
2907
  * - Only direct local references to top-level definitions in the form `#/$defs/<escaped-token>` are supported. Root
2895
- * references, external references, and pointers below a definition throw an `Unsupported reference` error. A direct
2896
- * reference to a missing definition throws an `Invalid reference` error.
2908
+ * references, external references, and pointers below a definition are rejected with the supported reference format.
2909
+ * Missing definitions are reported by name. References reached inside nested schema
2910
+ * resources introduced by `$id` are rejected instead of resolved against the top-level definitions.
2897
2911
  * - Pattern constraints reached during translation cause an error by default. Use `patterns: "apply"` only for trusted
2898
- * documents, or `patterns: "ignore"` to weaken validation explicitly.
2912
+ * documents, or `patterns: "ignore"` to skip them. Ignoring patterns can both admit invalid values and reject valid
2913
+ * values when `oneOf` branches start overlapping.
2899
2914
  * - Callback results are used directly, and exceptions raised by a callback pass through unchanged.
2900
2915
  *
2901
2916
  * @see {@link fromJsonSchemaDocument} for a single root
@@ -14,16 +14,16 @@ import * as InternalRecord from "../record.ts"
14
14
  import * as Model from "./model.ts"
15
15
  import * as Regexp from "./regexp.ts"
16
16
 
17
- type Constraint = Schema.Annotations.ToArbitrary.Constraint<any>
17
+ type FilterConstraint = Schema.Annotations.ToArbitrary.FilterConstraint<any>
18
18
  type GenerationConstraint = Schema.Annotations.ToArbitrary.GenerationConstraint<any>
19
19
 
20
20
  interface Checks {
21
- readonly constraint: Constraint | undefined
21
+ readonly constraint: FilterConstraint | undefined
22
22
  readonly filters: ReadonlyArray<SchemaAST.Filter<any>>
23
23
  }
24
24
 
25
25
  const infinity = Number.POSITIVE_INFINITY
26
- const finiteNumberConstraint: Constraint = { number: "finite" }
26
+ const finiteNumberConstraint: FilterConstraint = { number: "finite" }
27
27
  const optionMatch = { onFailure: Option.none, onSuccess: Option.some }
28
28
 
29
29
  const optionComputation = <A, E, R>(self: Effect.Effect<A, E, R>): Model.Computation<Option.Option<A>> => {
@@ -79,7 +79,7 @@ function mergeMaximum(self: number | undefined, that: number | undefined): numbe
79
79
  return self === undefined ? that : that === undefined ? self : Math.min(self, that)
80
80
  }
81
81
 
82
- function mergeConstraint(self: Constraint | undefined, that: Constraint): Constraint {
82
+ function mergeConstraint(self: FilterConstraint | undefined, that: FilterConstraint): FilterConstraint {
83
83
  const order = that.order ?? self?.order
84
84
  if (self?.order !== undefined && that.order !== undefined && self.order !== that.order) {
85
85
  throw new Error("Cannot merge ordered arbitrary constraints with different Order instances")
@@ -142,7 +142,7 @@ function mergeConstraint(self: Constraint | undefined, that: Constraint): Constr
142
142
  }
143
143
  }
144
144
 
145
- function collectChecks(checks: SchemaAST.Checks | undefined, inherited: Constraint | undefined): Checks {
145
+ function collectChecks(checks: SchemaAST.Checks | undefined, inherited: FilterConstraint | undefined): Checks {
146
146
  let constraint = inherited
147
147
  const filters: Array<SchemaAST.Filter<any>> = []
148
148
  const visit = (check: SchemaAST.Check<any>): void => {
@@ -180,7 +180,7 @@ function applyFilters(
180
180
  })
181
181
  }
182
182
 
183
- function validateConstraint(constraint: Constraint | undefined, path: ReadonlyArray<PropertyKey>): void {
183
+ function validateConstraint(constraint: FilterConstraint | undefined, path: ReadonlyArray<PropertyKey>): void {
184
184
  if (constraint === undefined) return
185
185
  const cardinalities = [
186
186
  [constraint.minLength, constraint.maxLength],
@@ -207,7 +207,7 @@ function validateConstraint(constraint: Constraint | undefined, path: ReadonlyAr
207
207
  }
208
208
  }
209
209
 
210
- function withoutOrder(constraint: Constraint | undefined): GenerationConstraint | undefined {
210
+ function withoutOrder(constraint: FilterConstraint | undefined): GenerationConstraint | undefined {
211
211
  if (constraint === undefined) return undefined
212
212
  const { order: _, ...out } = constraint
213
213
  return Object.keys(out).length === 0 ? undefined : out
@@ -352,7 +352,7 @@ function builtInDeclarationLink(
352
352
  }
353
353
 
354
354
  function lengthBounds(
355
- constraint: Constraint | undefined,
355
+ constraint: FilterConstraint | undefined,
356
356
  keys: readonly [
357
357
  minimum: "minLength" | "minSize" | "minProperties",
358
358
  maximum: "maxLength" | "maxSize" | "maxProperties"
@@ -801,7 +801,7 @@ function randomString(state: Model.GenerationState, minimum: number, maximum: nu
801
801
  return value
802
802
  }
803
803
 
804
- function numberBounds(constraint: Constraint | undefined, integer: boolean, path: ReadonlyArray<PropertyKey>) {
804
+ function numberBounds(constraint: FilterConstraint | undefined, integer: boolean, path: ReadonlyArray<PropertyKey>) {
805
805
  const ordered = constraint?.order === Order.Number ? constraint : undefined
806
806
  let minimum = ordered?.minimum as number | undefined
807
807
  let maximum = ordered?.maximum as number | undefined
@@ -1027,14 +1027,14 @@ function bigIntSample(
1027
1027
  /** @internal */
1028
1028
  export function compile<S extends Schema.Constraint>(schema: S): Model.Compiled<S["Type"]> {
1029
1029
  const rootAst = SchemaAST.toType(schema.ast)
1030
- const cache = new WeakMap<SchemaAST.AST, Map<Constraint | undefined, Model.Compiled<any>>>()
1030
+ const cache = new WeakMap<SchemaAST.AST, Map<FilterConstraint | undefined, Model.Compiled<any>>>()
1031
1031
  const nodes: Array<Model.Compiled<any>> = []
1032
1032
  const suspendBodies = new Map<Model.Compiled<any>, Model.Compiled<any>>()
1033
1033
  const pending: Array<() => void> = []
1034
1034
  const recur = (
1035
1035
  ast: SchemaAST.AST,
1036
1036
  path: ReadonlyArray<PropertyKey>,
1037
- inherited?: Constraint
1037
+ inherited?: FilterConstraint
1038
1038
  ): Model.Compiled<any> => {
1039
1039
  let entries = cache.get(ast)
1040
1040
  const cached = entries?.get(inherited)
@@ -1079,7 +1079,7 @@ export function compile<S extends Schema.Constraint>(schema: S): Model.Compiled<
1079
1079
  const compileBase = (
1080
1080
  ast: SchemaAST.AST,
1081
1081
  path: ReadonlyArray<PropertyKey>,
1082
- constraint: Constraint | undefined
1082
+ constraint: FilterConstraint | undefined
1083
1083
  ): Model.Compiled<any> => {
1084
1084
  switch (ast._tag) {
1085
1085
  case "Never":
@@ -1336,7 +1336,7 @@ export function compile<S extends Schema.Constraint>(schema: S): Model.Compiled<
1336
1336
  const compileArrays = (
1337
1337
  ast: SchemaAST.Arrays,
1338
1338
  path: ReadonlyArray<PropertyKey>,
1339
- constraint: Constraint | undefined
1339
+ constraint: FilterConstraint | undefined
1340
1340
  ): Model.Compiled<ReadonlyArray<any>> => {
1341
1341
  const uniqueBy = constraint?.uniqueBy
1342
1342
  const elements = ast.elements.map((element, index) => ({
@@ -1492,7 +1492,7 @@ export function compile<S extends Schema.Constraint>(schema: S): Model.Compiled<
1492
1492
  const compileObjects = (
1493
1493
  ast: SchemaAST.Objects,
1494
1494
  path: ReadonlyArray<PropertyKey>,
1495
- constraint: Constraint | undefined
1495
+ constraint: FilterConstraint | undefined
1496
1496
  ): Model.Compiled<Record<PropertyKey, any>> => {
1497
1497
  const constrainedIndexes = ast.indexSignatures.flatMap((index, position) => {
1498
1498
  const constraint = collectChecks(index.type.checks, undefined).constraint
@@ -1517,7 +1517,7 @@ export function compile<S extends Schema.Constraint>(schema: S): Model.Compiled<
1517
1517
  if (cached !== undefined) return cached
1518
1518
  let specialized = compiled
1519
1519
  try {
1520
- let inherited: Constraint | undefined
1520
+ let inherited: FilterConstraint | undefined
1521
1521
  for (const match of matching) inherited = mergeConstraint(inherited, match.constraint)
1522
1522
  const checks = collectChecks(type.checks, inherited)
1523
1523
  specialized = compileBase(type, path, checks.constraint)
@@ -1668,7 +1668,7 @@ export function compile<S extends Schema.Constraint>(schema: S): Model.Compiled<
1668
1668
  const compileDeclaration = (
1669
1669
  ast: SchemaAST.Declaration,
1670
1670
  path: ReadonlyArray<PropertyKey>,
1671
- constraint: Constraint | undefined
1671
+ constraint: FilterConstraint | undefined
1672
1672
  ): Model.Compiled<any> => {
1673
1673
  validateConstraint(constraint, path)
1674
1674
  const typeParameters = ast.typeParameters.map((parameter, index) => recur(parameter, [...path, index]))
@@ -50,6 +50,7 @@ import type { Primitive } from "./core.ts"
50
50
  import {
51
51
  args,
52
52
  causeAnnotate,
53
+ causeDie,
53
54
  causeEmpty,
54
55
  causeFromReasons,
55
56
  CauseImpl,
@@ -4371,20 +4372,27 @@ export const acquireDisposable = <A extends AsyncDisposable | Disposable, E, R>(
4371
4372
 
4372
4373
  /** @internal */
4373
4374
  export const cachedInvalidateWithTTL: {
4375
+ <A, E>(timeToLive: (exit: Exit.Exit<A, E>) => Duration.Input): <R>(
4376
+ self: Effect.Effect<A, E, R>
4377
+ ) => Effect.Effect<[Effect.Effect<A, E, R>, Effect.Effect<void>]>
4374
4378
  (timeToLive: Duration.Input): <A, E, R>(
4375
4379
  self: Effect.Effect<A, E, R>
4376
4380
  ) => Effect.Effect<[Effect.Effect<A, E, R>, Effect.Effect<void>]>
4381
+ <A, E>(timeToLive: Duration.Input | ((exit: Exit.Exit<A, E>) => Duration.Input)): <R>(
4382
+ self: Effect.Effect<A, E, R>
4383
+ ) => Effect.Effect<[Effect.Effect<A, E, R>, Effect.Effect<void>]>
4377
4384
  <A, E, R>(
4378
4385
  self: Effect.Effect<A, E, R>,
4379
- timeToLive: Duration.Input
4386
+ timeToLive: Duration.Input | ((exit: Exit.Exit<A, E>) => Duration.Input)
4380
4387
  ): Effect.Effect<[Effect.Effect<A, E, R>, Effect.Effect<void>]>
4381
4388
  } = dual(2, <A, E, R>(
4382
4389
  self: Effect.Effect<A, E, R>,
4383
- ttl: Duration.Input
4390
+ ttl: Duration.Input | ((exit: Exit.Exit<A, E>) => Duration.Input)
4384
4391
  ): Effect.Effect<[Effect.Effect<A, E, R>, Effect.Effect<void>]> =>
4385
4392
  sync(() => {
4386
- const ttlMillis = Duration.toMillis(Duration.fromInputUnsafe(ttl))
4387
- const isFinite = Number.isFinite(ttlMillis)
4393
+ const ttlMillis = typeof ttl === "function"
4394
+ ? (exit: Exit.Exit<A, E>) => Duration.toMillis(Duration.fromInputUnsafe(ttl(exit)))
4395
+ : constant(Duration.toMillis(Duration.fromInputUnsafe(ttl)))
4388
4396
  const latch = makeLatchUnsafe(false)
4389
4397
  let expiresAt = 0
4390
4398
  let running = false
@@ -4393,17 +4401,26 @@ export const cachedInvalidateWithTTL: {
4393
4401
  return [
4394
4402
  withFiber((fiber) => {
4395
4403
  const clock = fiber.getRef(ClockRef)
4396
- const now = isFinite ? clock.currentTimeMillisUnsafe() : 0
4404
+ const now = expiresAt === Infinity ? 0 : clock.currentTimeMillisUnsafe()
4397
4405
  if (running || now < expiresAt) return exit ?? wait
4398
4406
  running = true
4399
4407
  latch.closeUnsafe()
4400
4408
  exit = undefined
4401
4409
  return onExit(self, (exit_) =>
4402
4410
  sync(() => {
4403
- running = false
4404
- expiresAt = clock.currentTimeMillisUnsafe() + ttlMillis
4405
- exit = exit_
4406
- latch.openUnsafe()
4411
+ try {
4412
+ const duration = ttlMillis(exit_)
4413
+ expiresAt = clock.currentTimeMillisUnsafe() + duration
4414
+ exit = exit_
4415
+ } catch (error) {
4416
+ const cause = causeDie(error)
4417
+ // Publish the same combined cause that onExit returns to the owner.
4418
+ exit = exitFailCause(exitIsFailure(exit_) ? causeCombine(exit_.cause, cause) : cause)
4419
+ throw error
4420
+ } finally {
4421
+ running = false
4422
+ latch.openUnsafe()
4423
+ }
4407
4424
  }))
4408
4425
  }),
4409
4426
  sync(() => {
@@ -4416,18 +4433,24 @@ export const cachedInvalidateWithTTL: {
4416
4433
 
4417
4434
  /** @internal */
4418
4435
  export const cachedWithTTL: {
4436
+ <A, E>(
4437
+ timeToLive: (exit: Exit.Exit<A, E>) => Duration.Input
4438
+ ): <R>(self: Effect.Effect<A, E, R>) => Effect.Effect<Effect.Effect<A, E, R>>
4419
4439
  (
4420
4440
  timeToLive: Duration.Input
4421
4441
  ): <A, E, R>(self: Effect.Effect<A, E, R>) => Effect.Effect<Effect.Effect<A, E, R>>
4442
+ <A, E>(
4443
+ timeToLive: Duration.Input | ((exit: Exit.Exit<A, E>) => Duration.Input)
4444
+ ): <R>(self: Effect.Effect<A, E, R>) => Effect.Effect<Effect.Effect<A, E, R>>
4422
4445
  <A, E, R>(
4423
4446
  self: Effect.Effect<A, E, R>,
4424
- timeToLive: Duration.Input
4447
+ timeToLive: Duration.Input | ((exit: Exit.Exit<A, E>) => Duration.Input)
4425
4448
  ): Effect.Effect<Effect.Effect<A, E, R>>
4426
4449
  } = dual(
4427
4450
  2,
4428
4451
  <A, E, R>(
4429
4452
  self: Effect.Effect<A, E, R>,
4430
- timeToLive: Duration.Input
4453
+ timeToLive: Duration.Input | ((exit: Exit.Exit<A, E>) => Duration.Input)
4431
4454
  ): Effect.Effect<Effect.Effect<A, E, R>> => map(cachedInvalidateWithTTL(self, timeToLive), (tuple) => tuple[0])
4432
4455
  )
4433
4456