effect 4.0.0-beta.92 → 4.0.0-beta.94

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 (162) hide show
  1. package/dist/Cause.d.ts +3 -1
  2. package/dist/Cause.d.ts.map +1 -1
  3. package/dist/Cause.js.map +1 -1
  4. package/dist/Config.d.ts +1 -1
  5. package/dist/Config.d.ts.map +1 -1
  6. package/dist/Config.js.map +1 -1
  7. package/dist/Effect.d.ts +130 -0
  8. package/dist/Effect.d.ts.map +1 -1
  9. package/dist/Effect.js +43 -0
  10. package/dist/Effect.js.map +1 -1
  11. package/dist/FileSystem.d.ts +7 -0
  12. package/dist/FileSystem.d.ts.map +1 -1
  13. package/dist/FileSystem.js +3 -0
  14. package/dist/FileSystem.js.map +1 -1
  15. package/dist/Layer.d.ts +1 -1
  16. package/dist/Layer.d.ts.map +1 -1
  17. package/dist/Layer.js +6 -3
  18. package/dist/Layer.js.map +1 -1
  19. package/dist/LayerMap.js +1 -1
  20. package/dist/LayerMap.js.map +1 -1
  21. package/dist/LayerRef.d.ts +252 -0
  22. package/dist/LayerRef.d.ts.map +1 -0
  23. package/dist/LayerRef.js +171 -0
  24. package/dist/LayerRef.js.map +1 -0
  25. package/dist/Schema.d.ts +74 -30
  26. package/dist/Schema.d.ts.map +1 -1
  27. package/dist/Schema.js +3 -0
  28. package/dist/Schema.js.map +1 -1
  29. package/dist/SchemaParser.d.ts +1 -1
  30. package/dist/SchemaParser.d.ts.map +1 -1
  31. package/dist/SchemaParser.js.map +1 -1
  32. package/dist/internal/core.js +1 -1
  33. package/dist/internal/effect.js +10 -6
  34. package/dist/internal/effect.js.map +1 -1
  35. package/dist/testing/TestSchema.d.ts +2 -2
  36. package/dist/testing/TestSchema.d.ts.map +1 -1
  37. package/dist/testing/TestSchema.js.map +1 -1
  38. package/dist/unstable/ai/Chat.d.ts +1 -1
  39. package/dist/unstable/ai/Chat.d.ts.map +1 -1
  40. package/dist/unstable/ai/LanguageModel.d.ts +2 -2
  41. package/dist/unstable/ai/LanguageModel.d.ts.map +1 -1
  42. package/dist/unstable/cli/Argument.d.ts +2 -2
  43. package/dist/unstable/cli/Argument.d.ts.map +1 -1
  44. package/dist/unstable/cli/Argument.js.map +1 -1
  45. package/dist/unstable/cli/Flag.d.ts +2 -2
  46. package/dist/unstable/cli/Flag.d.ts.map +1 -1
  47. package/dist/unstable/cli/Flag.js.map +1 -1
  48. package/dist/unstable/cli/Param.d.ts +2 -2
  49. package/dist/unstable/cli/Param.d.ts.map +1 -1
  50. package/dist/unstable/cli/Param.js.map +1 -1
  51. package/dist/unstable/cli/Primitive.js.map +1 -1
  52. package/dist/unstable/cluster/ClusterWorkflowEngine.d.ts.map +1 -1
  53. package/dist/unstable/cluster/ClusterWorkflowEngine.js +1 -0
  54. package/dist/unstable/cluster/ClusterWorkflowEngine.js.map +1 -1
  55. package/dist/unstable/cluster/Entity.d.ts.map +1 -1
  56. package/dist/unstable/cluster/Entity.js +5 -3
  57. package/dist/unstable/cluster/Entity.js.map +1 -1
  58. package/dist/unstable/cluster/Sharding.d.ts.map +1 -1
  59. package/dist/unstable/cluster/Sharding.js +3 -1
  60. package/dist/unstable/cluster/Sharding.js.map +1 -1
  61. package/dist/unstable/cluster/internal/entityManager.js +3 -2
  62. package/dist/unstable/cluster/internal/entityManager.js.map +1 -1
  63. package/dist/unstable/cluster/internal/resourceMap.js +39 -14
  64. package/dist/unstable/cluster/internal/resourceMap.js.map +1 -1
  65. package/dist/unstable/encoding/Sse.d.ts +2 -2
  66. package/dist/unstable/encoding/Sse.d.ts.map +1 -1
  67. package/dist/unstable/http/HttpBody.d.ts +1 -1
  68. package/dist/unstable/http/HttpBody.d.ts.map +1 -1
  69. package/dist/unstable/http/HttpBody.js +1 -1
  70. package/dist/unstable/http/HttpBody.js.map +1 -1
  71. package/dist/unstable/http/HttpClient.js +2 -2
  72. package/dist/unstable/http/HttpClient.js.map +1 -1
  73. package/dist/unstable/http/HttpClientRequest.d.ts +5 -4
  74. package/dist/unstable/http/HttpClientRequest.d.ts.map +1 -1
  75. package/dist/unstable/http/HttpClientRequest.js +5 -4
  76. package/dist/unstable/http/HttpClientRequest.js.map +1 -1
  77. package/dist/unstable/http/HttpClientResponse.d.ts +1 -1
  78. package/dist/unstable/http/HttpClientResponse.d.ts.map +1 -1
  79. package/dist/unstable/http/HttpClientResponse.js.map +1 -1
  80. package/dist/unstable/http/HttpIncomingMessage.d.ts +2 -2
  81. package/dist/unstable/http/HttpIncomingMessage.d.ts.map +1 -1
  82. package/dist/unstable/http/HttpIncomingMessage.js.map +1 -1
  83. package/dist/unstable/http/HttpRouter.d.ts +4 -4
  84. package/dist/unstable/http/HttpRouter.d.ts.map +1 -1
  85. package/dist/unstable/http/HttpRouter.js.map +1 -1
  86. package/dist/unstable/http/HttpServerRequest.d.ts +8 -8
  87. package/dist/unstable/http/HttpServerRequest.d.ts.map +1 -1
  88. package/dist/unstable/http/HttpServerRequest.js.map +1 -1
  89. package/dist/unstable/http/HttpServerResponse.d.ts +1 -1
  90. package/dist/unstable/http/HttpServerResponse.d.ts.map +1 -1
  91. package/dist/unstable/http/HttpServerResponse.js.map +1 -1
  92. package/dist/unstable/http/Multipart.d.ts +2 -2
  93. package/dist/unstable/http/Multipart.d.ts.map +1 -1
  94. package/dist/unstable/http/Multipart.js.map +1 -1
  95. package/dist/unstable/http/Url.d.ts +29 -4
  96. package/dist/unstable/http/Url.d.ts.map +1 -1
  97. package/dist/unstable/http/Url.js +44 -2
  98. package/dist/unstable/http/Url.js.map +1 -1
  99. package/dist/unstable/http/UrlParams.d.ts +2 -28
  100. package/dist/unstable/http/UrlParams.d.ts.map +1 -1
  101. package/dist/unstable/http/UrlParams.js +4 -46
  102. package/dist/unstable/http/UrlParams.js.map +1 -1
  103. package/dist/unstable/httpapi/HttpApi.d.ts.map +1 -1
  104. package/dist/unstable/httpapi/HttpApi.js +2 -4
  105. package/dist/unstable/httpapi/HttpApi.js.map +1 -1
  106. package/dist/unstable/httpapi/HttpApiBuilder.d.ts.map +1 -1
  107. package/dist/unstable/httpapi/HttpApiBuilder.js +30 -15
  108. package/dist/unstable/httpapi/HttpApiBuilder.js.map +1 -1
  109. package/dist/unstable/httpapi/HttpApiClient.js.map +1 -1
  110. package/dist/unstable/httpapi/HttpApiEndpoint.d.ts +7 -7
  111. package/dist/unstable/httpapi/HttpApiEndpoint.d.ts.map +1 -1
  112. package/dist/unstable/httpapi/HttpApiSchema.d.ts +1 -1
  113. package/dist/unstable/httpapi/HttpApiSchema.d.ts.map +1 -1
  114. package/dist/unstable/observability/OtlpTracer.d.ts.map +1 -1
  115. package/dist/unstable/observability/OtlpTracer.js +4 -3
  116. package/dist/unstable/observability/OtlpTracer.js.map +1 -1
  117. package/dist/unstable/reactivity/Atom.d.ts +4 -4
  118. package/dist/unstable/reactivity/Atom.d.ts.map +1 -1
  119. package/dist/unstable/reactivity/Atom.js.map +1 -1
  120. package/package.json +1 -1
  121. package/src/Cause.ts +3 -1
  122. package/src/Config.ts +1 -1
  123. package/src/Effect.ts +131 -0
  124. package/src/FileSystem.ts +13 -0
  125. package/src/Layer.ts +6 -6
  126. package/src/LayerMap.ts +1 -1
  127. package/src/LayerRef.ts +379 -0
  128. package/src/Schema.ts +83 -33
  129. package/src/SchemaParser.ts +2 -2
  130. package/src/internal/core.ts +1 -1
  131. package/src/internal/effect.ts +33 -6
  132. package/src/testing/TestSchema.ts +2 -2
  133. package/src/unstable/ai/Chat.ts +1 -1
  134. package/src/unstable/ai/LanguageModel.ts +3 -3
  135. package/src/unstable/cli/Argument.ts +14 -7
  136. package/src/unstable/cli/Flag.ts +6 -3
  137. package/src/unstable/cli/Param.ts +6 -3
  138. package/src/unstable/cli/Primitive.ts +2 -2
  139. package/src/unstable/cluster/ClusterWorkflowEngine.ts +1 -0
  140. package/src/unstable/cluster/Entity.ts +13 -14
  141. package/src/unstable/cluster/Sharding.ts +134 -131
  142. package/src/unstable/cluster/internal/entityManager.ts +11 -9
  143. package/src/unstable/cluster/internal/resourceMap.ts +59 -25
  144. package/src/unstable/encoding/Sse.ts +3 -3
  145. package/src/unstable/http/HttpBody.ts +2 -2
  146. package/src/unstable/http/HttpClient.ts +2 -2
  147. package/src/unstable/http/HttpClientRequest.ts +8 -7
  148. package/src/unstable/http/HttpClientResponse.ts +2 -3
  149. package/src/unstable/http/HttpIncomingMessage.ts +4 -5
  150. package/src/unstable/http/HttpRouter.ts +8 -10
  151. package/src/unstable/http/HttpServerRequest.ts +20 -19
  152. package/src/unstable/http/HttpServerResponse.ts +2 -2
  153. package/src/unstable/http/Multipart.ts +3 -3
  154. package/src/unstable/http/Url.ts +62 -7
  155. package/src/unstable/http/UrlParams.ts +5 -58
  156. package/src/unstable/httpapi/HttpApi.ts +2 -4
  157. package/src/unstable/httpapi/HttpApiBuilder.ts +33 -21
  158. package/src/unstable/httpapi/HttpApiClient.ts +2 -2
  159. package/src/unstable/httpapi/HttpApiEndpoint.ts +7 -7
  160. package/src/unstable/httpapi/HttpApiSchema.ts +1 -1
  161. package/src/unstable/observability/OtlpTracer.ts +4 -3
  162. package/src/unstable/reactivity/Atom.ts +10 -7
@@ -124,7 +124,7 @@ export interface Service {
124
124
  */
125
125
  readonly generateObject: <
126
126
  ObjectEncoded extends Record<string, any>,
127
- StructuredOutputSchema extends Schema.Codec<unknown, ObjectEncoded, unknown, unknown>,
127
+ StructuredOutputSchema extends Schema.Encoder<ObjectEncoded, unknown>,
128
128
  Options extends NoExcessProperties<
129
129
  GenerateObjectOptions<any, StructuredOutputSchema>,
130
130
  Options
@@ -835,7 +835,7 @@ export const make: (params: {
835
835
 
836
836
  const generateObject = <
837
837
  ObjectEncoded extends Record<string, any>,
838
- StructuredOutputSchema extends Schema.Codec<unknown, ObjectEncoded, unknown, unknown>,
838
+ StructuredOutputSchema extends Schema.Encoder<ObjectEncoded, unknown>,
839
839
  Options extends NoExcessProperties<
840
840
  GenerateObjectOptions<any, StructuredOutputSchema>,
841
841
  Options
@@ -1691,7 +1691,7 @@ export const generateText: {
1691
1691
  */
1692
1692
  export const generateObject = <
1693
1693
  ObjectEncoded extends Record<string, any>,
1694
- StructuredOutputSchema extends Schema.Codec<unknown, ObjectEncoded, unknown, unknown>,
1694
+ StructuredOutputSchema extends Schema.Encoder<ObjectEncoded, unknown>,
1695
1695
  Options extends NoExcessProperties<
1696
1696
  GenerateObjectOptions<any, StructuredOutputSchema>,
1697
1697
  Options
@@ -401,8 +401,8 @@ export const withDefault: {
401
401
  * @since 4.0.0
402
402
  */
403
403
  <A, const B>(
404
- self: Argument<A>,
405
- defaultValue: B | Effect.Effect<B, CliError.CliError, Environment>
404
+ self: Argument<A>,
405
+ defaultValue: B | Effect.Effect<B, CliError.CliError, Environment>
406
406
  ): Argument<A | B>
407
407
  } = Param.withDefault
408
408
 
@@ -729,8 +729,8 @@ export const mapEffect: {
729
729
  * @since 4.0.0
730
730
  */
731
731
  <A, B>(
732
- self: Argument<A>,
733
- f: (a: A) => Effect.Effect<B, CliError.CliError, Environment>
732
+ self: Argument<A>,
733
+ f: (a: A) => Effect.Effect<B, CliError.CliError, Environment>
734
734
  ): Argument<B>
735
735
  } = dual(2, <A, B>(
736
736
  self: Argument<A>,
@@ -982,7 +982,7 @@ export const withSchema: {
982
982
  * @category combinators
983
983
  * @since 4.0.0
984
984
  */
985
- <A, B>(schema: Schema.Codec<B, A, Environment, Environment>): (self: Argument<A>) => Argument<B>
985
+ <A, B>(schema: Schema.ConstraintCodec<B, A, Environment, unknown>): (self: Argument<A>) => Argument<B>
986
986
  /**
987
987
  * Validates parsed values against a Schema.
988
988
  *
@@ -1000,8 +1000,15 @@ export const withSchema: {
1000
1000
  * @category combinators
1001
1001
  * @since 4.0.0
1002
1002
  */
1003
- <A, B>(self: Argument<A>, schema: Schema.Codec<B, A, Environment, Environment>): Argument<B>
1004
- } = dual(2, <A, B>(self: Argument<A>, schema: Schema.Codec<B, A>) => Param.withSchema(self, schema))
1003
+ <A, B>(
1004
+ self: Argument<A>,
1005
+ schema: Schema.ConstraintCodec<B, A, Environment, unknown>
1006
+ ): Argument<B>
1007
+ } = dual(
1008
+ 2,
1009
+ <A, B>(self: Argument<A>, schema: Schema.ConstraintCodec<B, A, Environment, unknown>): Argument<B> =>
1010
+ Param.withSchema(self, schema)
1011
+ )
1005
1012
 
1006
1013
  /**
1007
1014
  * Creates a positional choice argument with custom value mapping.
@@ -1782,7 +1782,7 @@ export const withSchema: {
1782
1782
  * @category schemas
1783
1783
  * @since 4.0.0
1784
1784
  */
1785
- <A, B>(schema: Schema.Codec<B, A, Environment, Environment>): (self: Flag<A>) => Flag<B>
1785
+ <A, B>(schema: Schema.ConstraintCodec<B, A, Environment, unknown>): (self: Flag<A>) => Flag<B>
1786
1786
  /**
1787
1787
  * Validates and transforms a flag value using a Schema codec.
1788
1788
  *
@@ -1820,5 +1820,8 @@ export const withSchema: {
1820
1820
  * @category schemas
1821
1821
  * @since 4.0.0
1822
1822
  */
1823
- <A, B>(self: Flag<A>, schema: Schema.Codec<B, A, Environment, Environment>): Flag<B>
1824
- } = dual(2, <A, B>(self: Flag<A>, schema: Schema.Codec<B, A>) => Param.withSchema(self, schema))
1823
+ <A, B>(self: Flag<A>, schema: Schema.ConstraintCodec<B, A, Environment, unknown>): Flag<B>
1824
+ } = dual(
1825
+ 2,
1826
+ <A, B>(self: Flag<A>, schema: Schema.ConstraintCodec<B, A, Environment, unknown>) => Param.withSchema(self, schema)
1827
+ )
@@ -2430,7 +2430,7 @@ export const withSchema: {
2430
2430
  * @category combinators
2431
2431
  * @since 4.0.0
2432
2432
  */
2433
- <A, B>(schema: Schema.Codec<B, A, Environment, Environment>): <Kind extends ParamKind>(
2433
+ <A, B>(schema: Schema.ConstraintCodec<B, A, Environment, unknown>): <Kind extends ParamKind>(
2434
2434
  self: Param<Kind, A>
2435
2435
  ) => Param<Kind, B>
2436
2436
  /**
@@ -2455,10 +2455,13 @@ export const withSchema: {
2455
2455
  * @category combinators
2456
2456
  * @since 4.0.0
2457
2457
  */
2458
- <Kind extends ParamKind, A, B>(self: Param<Kind, A>, schema: Schema.Codec<B, A, Environment, Environment>): Param<Kind, B>
2458
+ <Kind extends ParamKind, A, B>(
2459
+ self: Param<Kind, A>,
2460
+ schema: Schema.ConstraintCodec<B, A, Environment, unknown>
2461
+ ): Param<Kind, B>
2459
2462
  } = dual(2, <Kind extends ParamKind, A, B>(
2460
2463
  self: Param<Kind, A>,
2461
- schema: Schema.Codec<B, A>
2464
+ schema: Schema.ConstraintCodec<B, A, Environment, unknown>
2462
2465
  ) => {
2463
2466
  const decodeParam = Schema.decodeUnknownEffect(schema)
2464
2467
  return mapEffect(self, (value) =>
@@ -105,9 +105,9 @@ const makePrimitive = <A>(
105
105
  parse
106
106
  })
107
107
 
108
- const makeSchemaPrimitive = <T, E>(
108
+ const makeSchemaPrimitive = <T>(
109
109
  tag: string,
110
- schema: Schema.Codec<T, E, Environment, Environment>
110
+ schema: Schema.ConstraintDecoder<T, Environment>
111
111
  ): Primitive<T> => {
112
112
  const toCodecStringTree = Schema.toCodecStringTree(schema)
113
113
  const decode = Schema.decodeUnknownEffect(toCodecStringTree)
@@ -133,6 +133,7 @@ export const make = Effect.gen(function*() {
133
133
  if (!entity) {
134
134
  return yield* Effect.die(`Workflow ${workflowName} not registered`)
135
135
  }
136
+ yield* RcMap.invalidate(clientsPartial, workflowName)
136
137
  return yield* entity.client
137
138
  }),
138
139
  idleTimeToLive: "5 minutes"
@@ -618,11 +618,7 @@ export const makeTestClient: <Type extends string, Rpcs extends Rpc.Any, LA, LE,
618
618
  Rpc.ServicesClient<Rpcs> | Rpc.ServicesServer<Rpcs> | Rpc.Middleware<Rpcs> | LR
619
619
  >
620
620
  readonly concurrency: number | "unbounded"
621
- readonly build: Effect.Effect<
622
- Context.Context<Rpc.ToHandler<Rpcs>>,
623
- never,
624
- Scope | CurrentAddress
625
- >
621
+ readonly build: Effect.Effect<Context.Context<Rpc.ToHandler<Rpcs>>>
626
622
  }>()
627
623
  const sharding = shardingTag.of({
628
624
  ...({} as Sharding["Service"]),
@@ -631,13 +627,7 @@ export const makeTestClient: <Type extends string, Rpcs extends Rpc.Any, LA, LE,
631
627
  entityMap.set(entity.type, {
632
628
  context: context as any,
633
629
  concurrency: options?.concurrency ?? 1,
634
- build: entity.protocol.toHandlers(handlers as any).pipe(
635
- Effect.provideContext(Context.mutate(context, (context) =>
636
- context.pipe(
637
- Context.add(CurrentRunnerAddress, runnerAddress),
638
- Context.omit(Scope)
639
- )))
640
- ) as any
630
+ build: entity.protocol.toHandlers(handlers as any) as any
641
631
  })
642
632
  return Effect.void
643
633
  })
@@ -654,8 +644,15 @@ export const makeTestClient: <Type extends string, Rpcs extends Rpc.Any, LA, LE,
654
644
  entityId: entityId as EntityId,
655
645
  shardId: makeShardId(entityId)
656
646
  })
647
+ const scope = yield* Effect.scope
648
+ const handlerContext = Context.mutate(entityEntry.context, (context) =>
649
+ context.pipe(
650
+ Context.add(CurrentRunnerAddress, runnerAddress),
651
+ Context.add(CurrentAddress, address),
652
+ Context.add(Scope, scope)
653
+ ))
657
654
  const handlers = yield* entityEntry.build.pipe(
658
- Effect.provideService(CurrentAddress, address)
655
+ Effect.setContext(handlerContext as Context.Context<any>)
659
656
  )
660
657
 
661
658
  // oxlint-disable-next-line prefer-const
@@ -665,7 +662,9 @@ export const makeTestClient: <Type extends string, Rpcs extends Rpc.Any, LA, LE,
665
662
  onFromServer(response) {
666
663
  return client.write(response)
667
664
  }
668
- }).pipe(Effect.provide(handlers))
665
+ }).pipe(
666
+ Effect.setContext(Context.merge(handlerContext, handlers))
667
+ )
669
668
 
670
669
  client = yield* RpcClient.makeNoSerialization(entity.protocol, {
671
670
  supportsAck: true,
@@ -1034,148 +1034,151 @@ const make = Effect.gen(function*() {
1034
1034
  MailboxFull | AlreadyProcessingMessage
1035
1035
  >,
1036
1036
  never
1037
- > = yield* ResourceMap.make(Effect.fnUntraced(function*(entity: Entity<string, any>) {
1038
- const client = yield* RpcClient.makeNoSerialization(entity.protocol, {
1039
- spanPrefix: `${entity.type}.client`,
1040
- disableTracing: !Context.get(entity.protocol.annotations, ClusterSchema.ClientTracingEnabled),
1041
- supportsAck: true,
1042
- generateRequestId: () => RequestId(snowflakeGen.nextUnsafe()),
1043
- flatten: true,
1044
- onFromClient(options): Effect.Effect<
1045
- void,
1046
- MailboxFull | AlreadyProcessingMessage | PersistenceError
1047
- > {
1048
- const address = Context.getUnsafe(options.context, ClientAddressTag)
1049
- switch (options.message._tag) {
1050
- case "Request": {
1051
- const fiber = Fiber.getCurrent()!
1052
- const id = Snowflake.Snowflake(options.message.id)
1053
- const rpc = entity.protocol.requests.get(options.message.tag)!
1054
- let respond: (reply: Reply.Reply<any>) => Effect.Effect<void>
1055
- const envelope = Envelope.makeRequest<any>({
1056
- requestId: id,
1057
- address,
1058
- tag: options.message.tag,
1059
- payload: options.message.payload,
1060
- headers: options.message.headers,
1061
- traceId: options.message.traceId,
1062
- spanId: options.message.spanId,
1063
- sampled: options.message.sampled
1064
- })
1065
- const message = new Message.OutgoingRequest({
1066
- envelope,
1067
- lastReceivedReply: Option.none(),
1068
- rpc,
1069
- context: fiber.context as Context.Context<any>,
1070
- respond: (reply) => respond(reply),
1071
- annotations: Context.get(rpc.annotations, ClusterSchema.Dynamic)(
1072
- rpc.annotations,
1073
- envelope as any
1074
- )
1075
- })
1076
- if (!options.discard) {
1077
- const entry: ClientRequestEntry = {
1078
- rpc: rpc as any,
1079
- context: fiber.currentContext,
1080
- message
1037
+ > = yield* ResourceMap.make(
1038
+ Effect.fnUntraced(function*(entity: Entity<string, any>) {
1039
+ const client = yield* RpcClient.makeNoSerialization(entity.protocol, {
1040
+ spanPrefix: `${entity.type}.client`,
1041
+ disableTracing: !Context.get(entity.protocol.annotations, ClusterSchema.ClientTracingEnabled),
1042
+ supportsAck: true,
1043
+ generateRequestId: () => RequestId(snowflakeGen.nextUnsafe()),
1044
+ flatten: true,
1045
+ onFromClient(options): Effect.Effect<
1046
+ void,
1047
+ MailboxFull | AlreadyProcessingMessage | PersistenceError
1048
+ > {
1049
+ const address = Context.getUnsafe(options.context, ClientAddressTag)
1050
+ switch (options.message._tag) {
1051
+ case "Request": {
1052
+ const fiber = Fiber.getCurrent()!
1053
+ const id = Snowflake.Snowflake(options.message.id)
1054
+ const rpc = entity.protocol.requests.get(options.message.tag)!
1055
+ let respond: (reply: Reply.Reply<any>) => Effect.Effect<void>
1056
+ const envelope = Envelope.makeRequest<any>({
1057
+ requestId: id,
1058
+ address,
1059
+ tag: options.message.tag,
1060
+ payload: options.message.payload,
1061
+ headers: options.message.headers,
1062
+ traceId: options.message.traceId,
1063
+ spanId: options.message.spanId,
1064
+ sampled: options.message.sampled
1065
+ })
1066
+ const message = new Message.OutgoingRequest({
1067
+ envelope,
1068
+ lastReceivedReply: Option.none(),
1069
+ rpc,
1070
+ context: fiber.context as Context.Context<any>,
1071
+ respond: (reply) => respond(reply),
1072
+ annotations: Context.get(rpc.annotations, ClusterSchema.Dynamic)(
1073
+ rpc.annotations,
1074
+ envelope as any
1075
+ )
1076
+ })
1077
+ if (!options.discard) {
1078
+ const entry: ClientRequestEntry = {
1079
+ rpc: rpc as any,
1080
+ context: fiber.currentContext,
1081
+ message
1082
+ }
1083
+ clientRequests.set(id, entry)
1084
+ respond = makeClientRespond(entry, client.write)
1085
+ } else {
1086
+ respond = clientRespondDiscard
1081
1087
  }
1082
- clientRequests.set(id, entry)
1083
- respond = makeClientRespond(entry, client.write)
1084
- } else {
1085
- respond = clientRespondDiscard
1088
+ return sendOutgoing(message, options.discard)
1086
1089
  }
1087
- return sendOutgoing(message, options.discard)
1088
- }
1089
- case "Ack": {
1090
- const requestId = Snowflake.Snowflake(options.message.requestId)
1091
- const entry = clientRequests.get(requestId)
1092
- if (!entry) return Effect.void
1093
- return sendOutgoing(
1094
- new Message.OutgoingEnvelope({
1095
- envelope: new Envelope.AckChunk({
1096
- id: snowflakeGen.nextUnsafe(),
1097
- address,
1098
- requestId,
1099
- replyId: entry.lastChunkId!
1090
+ case "Ack": {
1091
+ const requestId = Snowflake.Snowflake(options.message.requestId)
1092
+ const entry = clientRequests.get(requestId)
1093
+ if (!entry) return Effect.void
1094
+ return sendOutgoing(
1095
+ new Message.OutgoingEnvelope({
1096
+ envelope: new Envelope.AckChunk({
1097
+ id: snowflakeGen.nextUnsafe(),
1098
+ address,
1099
+ requestId,
1100
+ replyId: entry.lastChunkId!
1101
+ }),
1102
+ rpc: entry.rpc
1100
1103
  }),
1101
- rpc: entry.rpc
1102
- }),
1103
- false
1104
- )
1105
- }
1106
- case "Interrupt": {
1107
- const requestId = Snowflake.Snowflake(options.message.requestId)
1108
- const entry = clientRequests.get(requestId)!
1109
- if (!entry) return Effect.void
1110
- clientRequests.delete(requestId)
1111
- if (ClusterSchema.isUninterruptibleForClient(entry.message.annotations)) {
1112
- return Effect.void
1113
- }
1114
- // for durable messages, we ignore interrupts on shutdown or as a
1115
- // result of a shard being resassigned
1116
- const isTransientInterrupt = MutableRef.get(isShutdown) ||
1117
- options.message.interruptors.some((id) => internalInterruptors.has(id))
1118
- if (isTransientInterrupt && Context.get(entry.message.annotations, Persisted)) {
1119
- return Effect.void
1104
+ false
1105
+ )
1120
1106
  }
1121
- return Effect.ignore(sendOutgoing(
1122
- new Message.OutgoingEnvelope({
1123
- envelope: new Envelope.Interrupt({
1124
- id: snowflakeGen.nextUnsafe(),
1125
- address,
1126
- requestId
1107
+ case "Interrupt": {
1108
+ const requestId = Snowflake.Snowflake(options.message.requestId)
1109
+ const entry = clientRequests.get(requestId)!
1110
+ if (!entry) return Effect.void
1111
+ clientRequests.delete(requestId)
1112
+ if (ClusterSchema.isUninterruptibleForClient(entry.message.annotations)) {
1113
+ return Effect.void
1114
+ }
1115
+ // for durable messages, we ignore interrupts on shutdown or as a
1116
+ // result of a shard being resassigned
1117
+ const isTransientInterrupt = MutableRef.get(isShutdown) ||
1118
+ options.message.interruptors.some((id) => internalInterruptors.has(id))
1119
+ if (isTransientInterrupt && Context.get(entry.message.annotations, Persisted)) {
1120
+ return Effect.void
1121
+ }
1122
+ return Effect.ignore(sendOutgoing(
1123
+ new Message.OutgoingEnvelope({
1124
+ envelope: new Envelope.Interrupt({
1125
+ id: snowflakeGen.nextUnsafe(),
1126
+ address,
1127
+ requestId
1128
+ }),
1129
+ rpc: entry.rpc
1127
1130
  }),
1128
- rpc: entry.rpc
1129
- }),
1130
- false,
1131
- 3
1132
- ))
1131
+ false,
1132
+ 3
1133
+ ))
1134
+ }
1133
1135
  }
1136
+ return Effect.void
1134
1137
  }
1135
- return Effect.void
1136
- }
1137
- })
1138
-
1139
- yield* Scope.addFinalizer(
1140
- yield* Effect.scope,
1141
- Effect.withFiber((fiber) => {
1142
- internalInterruptors.add(fiber.id)
1143
- return Effect.void
1144
1138
  })
1145
- )
1146
1139
 
1147
- return (entityId: string) => {
1148
- const id = makeEntityId(entityId)
1149
- const address = ClientAddressTag.context(makeEntityAddress({
1150
- shardId: getShardId(id, entity.getShardGroup(entityId as EntityId)),
1151
- entityId: id,
1152
- entityType: entity.type
1153
- }))
1154
- const clientFn = function(tag: string, payload: any, options?: {
1155
- readonly context?: Context.Context<never>
1156
- }) {
1157
- const context = options?.context ? Context.merge(options.context, address) : address
1158
- return client.client(tag, payload, {
1159
- ...options,
1160
- context
1140
+ yield* Scope.addFinalizer(
1141
+ yield* Effect.scope,
1142
+ Effect.withFiber((fiber) => {
1143
+ internalInterruptors.add(fiber.id)
1144
+ return Effect.void
1161
1145
  })
1162
- }
1163
- const proxyClient: any = {}
1164
- return new Proxy(proxyClient, {
1165
- has(_, p) {
1166
- return entity.protocol.requests.has(p as string)
1167
- },
1168
- get(target, p) {
1169
- if (p in target) {
1170
- return target[p]
1171
- } else if (!entity.protocol.requests.has(p as string)) {
1172
- return undefined
1173
- }
1174
- return target[p] = (payload: any, options?: {}) => clientFn(p as string, payload, options)
1146
+ )
1147
+
1148
+ return (entityId: string) => {
1149
+ const id = makeEntityId(entityId)
1150
+ const address = ClientAddressTag.context(makeEntityAddress({
1151
+ shardId: getShardId(id, entity.getShardGroup(entityId as EntityId)),
1152
+ entityId: id,
1153
+ entityType: entity.type
1154
+ }))
1155
+ const clientFn = function(tag: string, payload: any, options?: {
1156
+ readonly context?: Context.Context<never>
1157
+ }) {
1158
+ const context = options?.context ? Context.merge(options.context, address) : address
1159
+ return client.client(tag, payload, {
1160
+ ...options,
1161
+ context
1162
+ })
1175
1163
  }
1176
- })
1177
- }
1178
- }))
1164
+ const proxyClient: any = {}
1165
+ return new Proxy(proxyClient, {
1166
+ has(_, p) {
1167
+ return entity.protocol.requests.has(p as string)
1168
+ },
1169
+ get(target, p) {
1170
+ if (p in target) {
1171
+ return target[p]
1172
+ } else if (!entity.protocol.requests.has(p as string)) {
1173
+ return undefined
1174
+ }
1175
+ return target[p] = (payload: any, options?: {}) => clientFn(p as string, payload, options)
1176
+ }
1177
+ })
1178
+ }
1179
+ }),
1180
+ { referential: true }
1181
+ )
1179
1182
 
1180
1183
  const makeClient = <Type extends string, Rpcs extends Rpc.Any>(entity: Entity<Type, Rpcs>): Effect.Effect<
1181
1184
  (
@@ -155,16 +155,18 @@ export const make = Effect.fnUntraced(function*<
155
155
  Effect.fnUntraced(function*(scope) {
156
156
  let isShuttingDown = false
157
157
 
158
+ const handlerContext = Context.mutate(context, (context) =>
159
+ context.pipe(
160
+ Context.add(CurrentAddress, address),
161
+ Context.add(CurrentRunnerAddress, options.runnerAddress),
162
+ Context.add(KeepAliveLatch, keepAliveLatch),
163
+ Context.add(Scope.Scope, scope),
164
+ Context.add(CurrentLogAnnotations, {})
165
+ ))
166
+
158
167
  // Initiate the behavior for the entity
159
168
  const handlers = yield* (entity.protocol.toHandlers(buildHandlers as any).pipe(
160
- Effect.provideService(CurrentLogAnnotations, {}),
161
- Effect.provideContext(Context.mutate(context, (context) =>
162
- context.pipe(
163
- Context.add(CurrentAddress, address),
164
- Context.add(CurrentRunnerAddress, options.runnerAddress),
165
- Context.add(KeepAliveLatch, keepAliveLatch),
166
- Context.add(Scope.Scope, scope)
167
- ))),
169
+ Effect.setContext(handlerContext as Context.Context<any>),
168
170
  Effect.sandbox,
169
171
  Effect.tapError((cause) => Effect.logError("Defect building entity handlers", cause)),
170
172
  Effect.retry(defectRetryPolicy)
@@ -280,7 +282,7 @@ export const make = Effect.fnUntraced(function*<
280
282
  }
281
283
  }).pipe(
282
284
  Scope.provide(scope),
283
- Effect.provideContext(handlers)
285
+ Effect.setContext(Context.merge(handlerContext, handlers))
284
286
  )
285
287
 
286
288
  yield* Scope.addFinalizer(
@@ -4,23 +4,16 @@ import * as Effect from "../../../Effect.ts"
4
4
  import * as Exit from "../../../Exit.ts"
5
5
  import * as MutableHashMap from "../../../MutableHashMap.ts"
6
6
  import * as MutableRef from "../../../MutableRef.ts"
7
- import * as Option from "../../../Option.ts"
8
7
  import * as Scope from "../../../Scope.ts"
9
8
 
10
9
  /** @internal */
11
10
  export class ResourceMap<K, A, E> {
12
11
  readonly lookup: (key: K, scope: Scope.Scope) => Effect.Effect<A, E>
13
- readonly entries: MutableHashMap.MutableHashMap<K, {
14
- readonly scope: Scope.Closeable
15
- readonly deferred: Deferred.Deferred<A, E>
16
- }>
12
+ readonly entries: BackingMap<K, A, E>
17
13
  readonly isClosed: MutableRef.MutableRef<boolean>
18
14
  constructor(
19
15
  lookup: (key: K, scope: Scope.Scope) => Effect.Effect<A, E>,
20
- entries: MutableHashMap.MutableHashMap<K, {
21
- readonly scope: Scope.Closeable
22
- readonly deferred: Deferred.Deferred<A, E>
23
- }>,
16
+ entries: BackingMap<K, A, E>,
24
17
  isClosed: MutableRef.MutableRef<boolean>
25
18
  ) {
26
19
  this.lookup = lookup
@@ -28,22 +21,29 @@ export class ResourceMap<K, A, E> {
28
21
  this.isClosed = isClosed
29
22
  }
30
23
 
31
- static make = Effect.fnUntraced(function*<K, A, E, R>(lookup: (key: K) => Effect.Effect<A, E, R>) {
24
+ static make = Effect.fnUntraced(function*<K, A, E, R>(lookup: (key: K) => Effect.Effect<A, E, R>, options?: {
25
+ readonly referential?: boolean | undefined
26
+ }) {
32
27
  const scope = yield* Effect.scope
33
28
  const services = yield* Effect.context<R>()
34
29
  const isClosed = MutableRef.make(false)
35
30
 
36
- const entries = MutableHashMap.empty<K, {
37
- scope: Scope.Closeable
38
- deferred: Deferred.Deferred<A, E>
39
- }>()
31
+ const entries: BackingMap<K, A, E> = options?.referential ?
32
+ {
33
+ _tag: "Referential",
34
+ map: new Map()
35
+ } :
36
+ {
37
+ _tag: "Equal",
38
+ map: MutableHashMap.empty()
39
+ }
40
40
 
41
41
  yield* Scope.addFinalizerExit(
42
42
  scope,
43
43
  (exit) => {
44
44
  MutableRef.set(isClosed, true)
45
- return Effect.forEach(entries, ([key, { scope }]) => {
46
- MutableHashMap.remove(entries, key)
45
+ return Effect.forEach(entries.map, ([key, { scope }]) => {
46
+ backingDelete(entries, key)
47
47
  return Effect.exit(Scope.close(scope, exit))
48
48
  }, { concurrency: "unbounded", discard: true })
49
49
  }
@@ -61,18 +61,18 @@ export class ResourceMap<K, A, E> {
61
61
  if (MutableRef.get(this.isClosed)) {
62
62
  return Effect.interrupt
63
63
  }
64
- const existing = MutableHashMap.get(this.entries, key)
65
- if (Option.isSome(existing)) {
66
- return Deferred.await(existing.value.deferred)
64
+ const existing = backingGet(this.entries, key)
65
+ if (existing) {
66
+ return Deferred.await(existing.deferred)
67
67
  }
68
68
  const scope = Effect.runSync(Scope.make())
69
69
  const deferred = Deferred.makeUnsafe<A, E>()
70
- MutableHashMap.set(this.entries, key, { scope, deferred })
70
+ backingSet(this.entries, key, { scope, deferred })
71
71
  return Effect.onExit(this.lookup(key, scope), (exit) => {
72
72
  if (exit._tag === "Success") {
73
73
  return Deferred.done(deferred, exit)
74
74
  }
75
- MutableHashMap.remove(this.entries, key)
75
+ backingDelete(this.entries, key)
76
76
  return Deferred.done(deferred, exit)
77
77
  })
78
78
  })
@@ -80,12 +80,12 @@ export class ResourceMap<K, A, E> {
80
80
 
81
81
  remove(key: K): Effect.Effect<void> {
82
82
  return Effect.suspend(() => {
83
- const entry = MutableHashMap.get(this.entries, key)
84
- if (Option.isNone(entry)) {
83
+ const entry = backingGet(this.entries, key)
84
+ if (!entry) {
85
85
  return Effect.void
86
86
  }
87
- MutableHashMap.remove(this.entries, key)
88
- return Scope.close(entry.value.scope, Exit.void)
87
+ backingDelete(this.entries, key)
88
+ return Scope.close(entry.scope, Exit.void)
89
89
  })
90
90
  }
91
91
 
@@ -98,3 +98,37 @@ export class ResourceMap<K, A, E> {
98
98
  }))
99
99
  }
100
100
  }
101
+
102
+ type BackingMap<K, A, E> = {
103
+ readonly _tag: "Equal"
104
+ readonly map: MutableHashMap.MutableHashMap<K, Entry<A, E>>
105
+ } | {
106
+ readonly _tag: "Referential"
107
+ readonly map: Map<K, Entry<A, E>>
108
+ }
109
+
110
+ type Entry<A, E> = {
111
+ readonly scope: Scope.Closeable
112
+ readonly deferred: Deferred.Deferred<A, E>
113
+ }
114
+
115
+ const backingGet = <K, A, E>(map: BackingMap<K, A, E>, key: K): Entry<A, E> | undefined => {
116
+ if (map._tag === "Equal") {
117
+ return MutableHashMap.get(map.map, key).valueOrUndefined
118
+ }
119
+ return map.map.get(key)
120
+ }
121
+ const backingSet = <K, A, E>(map: BackingMap<K, A, E>, key: K, entry: Entry<A, E>): void => {
122
+ if (map._tag === "Equal") {
123
+ MutableHashMap.set(map.map, key, entry)
124
+ } else {
125
+ map.map.set(key, entry)
126
+ }
127
+ }
128
+ const backingDelete = <K, A, E>(map: BackingMap<K, A, E>, key: K): void => {
129
+ if (map._tag === "Equal") {
130
+ MutableHashMap.remove(map.map, key)
131
+ } else {
132
+ map.map.delete(key)
133
+ }
134
+ }