effect 4.0.0-beta.44 → 4.0.0-beta.46

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 (151) hide show
  1. package/dist/Equal.d.ts.map +1 -1
  2. package/dist/Equal.js +16 -0
  3. package/dist/Equal.js.map +1 -1
  4. package/dist/Hash.js +1 -1
  5. package/dist/Hash.js.map +1 -1
  6. package/dist/Semaphore.d.ts +1 -1
  7. package/dist/Semaphore.d.ts.map +1 -1
  8. package/dist/Semaphore.js +1 -3
  9. package/dist/Semaphore.js.map +1 -1
  10. package/dist/unstable/ai/McpServer.d.ts.map +1 -1
  11. package/dist/unstable/ai/McpServer.js +24 -21
  12. package/dist/unstable/ai/McpServer.js.map +1 -1
  13. package/dist/unstable/eventlog/Event.d.ts +0 -6
  14. package/dist/unstable/eventlog/Event.d.ts.map +1 -1
  15. package/dist/unstable/eventlog/Event.js +0 -5
  16. package/dist/unstable/eventlog/Event.js.map +1 -1
  17. package/dist/unstable/eventlog/EventGroup.d.ts +0 -2
  18. package/dist/unstable/eventlog/EventGroup.d.ts.map +1 -1
  19. package/dist/unstable/eventlog/EventGroup.js +0 -2
  20. package/dist/unstable/eventlog/EventGroup.js.map +1 -1
  21. package/dist/unstable/eventlog/EventJournal.d.ts +22 -5
  22. package/dist/unstable/eventlog/EventJournal.d.ts.map +1 -1
  23. package/dist/unstable/eventlog/EventJournal.js +126 -67
  24. package/dist/unstable/eventlog/EventJournal.js.map +1 -1
  25. package/dist/unstable/eventlog/EventLog.d.ts +88 -34
  26. package/dist/unstable/eventlog/EventLog.d.ts.map +1 -1
  27. package/dist/unstable/eventlog/EventLog.js +215 -141
  28. package/dist/unstable/eventlog/EventLog.js.map +1 -1
  29. package/dist/unstable/eventlog/EventLogEncryption.d.ts +9 -7
  30. package/dist/unstable/eventlog/EventLogEncryption.d.ts.map +1 -1
  31. package/dist/unstable/eventlog/EventLogEncryption.js +13 -15
  32. package/dist/unstable/eventlog/EventLogEncryption.js.map +1 -1
  33. package/dist/unstable/eventlog/EventLogMessage.d.ts +228 -0
  34. package/dist/unstable/eventlog/EventLogMessage.d.ts.map +1 -0
  35. package/dist/unstable/eventlog/EventLogMessage.js +214 -0
  36. package/dist/unstable/eventlog/EventLogMessage.js.map +1 -0
  37. package/dist/unstable/eventlog/EventLogRemote.d.ts +109 -194
  38. package/dist/unstable/eventlog/EventLogRemote.d.ts.map +1 -1
  39. package/dist/unstable/eventlog/EventLogRemote.js +165 -320
  40. package/dist/unstable/eventlog/EventLogRemote.js.map +1 -1
  41. package/dist/unstable/eventlog/EventLogServer.d.ts +25 -47
  42. package/dist/unstable/eventlog/EventLogServer.d.ts.map +1 -1
  43. package/dist/unstable/eventlog/EventLogServer.js +127 -198
  44. package/dist/unstable/eventlog/EventLogServer.js.map +1 -1
  45. package/dist/unstable/eventlog/EventLogServerEncrypted.d.ts +60 -0
  46. package/dist/unstable/eventlog/EventLogServerEncrypted.d.ts.map +1 -0
  47. package/dist/unstable/eventlog/EventLogServerEncrypted.js +166 -0
  48. package/dist/unstable/eventlog/EventLogServerEncrypted.js.map +1 -0
  49. package/dist/unstable/eventlog/EventLogServerUnencrypted.d.ts +183 -0
  50. package/dist/unstable/eventlog/EventLogServerUnencrypted.d.ts.map +1 -0
  51. package/dist/unstable/eventlog/EventLogServerUnencrypted.js +461 -0
  52. package/dist/unstable/eventlog/EventLogServerUnencrypted.js.map +1 -0
  53. package/dist/unstable/eventlog/EventLogSessionAuth.d.ts +117 -0
  54. package/dist/unstable/eventlog/EventLogSessionAuth.d.ts.map +1 -0
  55. package/dist/unstable/eventlog/EventLogSessionAuth.js +284 -0
  56. package/dist/unstable/eventlog/EventLogSessionAuth.js.map +1 -0
  57. package/dist/unstable/eventlog/{SqlEventLogJournal.d.ts → SqlEventJournal.d.ts} +2 -2
  58. package/dist/unstable/eventlog/SqlEventJournal.d.ts.map +1 -0
  59. package/dist/unstable/eventlog/{SqlEventLogJournal.js → SqlEventJournal.js} +20 -14
  60. package/dist/unstable/eventlog/SqlEventJournal.js.map +1 -0
  61. package/dist/unstable/eventlog/{SqlEventLogServer.d.ts → SqlEventLogServerEncrypted.d.ts} +5 -5
  62. package/dist/unstable/eventlog/SqlEventLogServerEncrypted.d.ts.map +1 -0
  63. package/dist/unstable/eventlog/{SqlEventLogServer.js → SqlEventLogServerEncrypted.js} +65 -24
  64. package/dist/unstable/eventlog/SqlEventLogServerEncrypted.js.map +1 -0
  65. package/dist/unstable/eventlog/SqlEventLogServerUnencrypted.d.ts +25 -0
  66. package/dist/unstable/eventlog/SqlEventLogServerUnencrypted.d.ts.map +1 -0
  67. package/dist/unstable/eventlog/SqlEventLogServerUnencrypted.js +354 -0
  68. package/dist/unstable/eventlog/SqlEventLogServerUnencrypted.js.map +1 -0
  69. package/dist/unstable/eventlog/index.d.ts +22 -2
  70. package/dist/unstable/eventlog/index.d.ts.map +1 -1
  71. package/dist/unstable/eventlog/index.js +22 -2
  72. package/dist/unstable/eventlog/index.js.map +1 -1
  73. package/dist/unstable/eventlog/internal/identityRootSecretDerivation.d.ts +2 -0
  74. package/dist/unstable/eventlog/internal/identityRootSecretDerivation.d.ts.map +1 -0
  75. package/dist/unstable/eventlog/internal/identityRootSecretDerivation.js +89 -0
  76. package/dist/unstable/eventlog/internal/identityRootSecretDerivation.js.map +1 -0
  77. package/dist/unstable/reactivity/AtomHttpApi.d.ts +1 -2
  78. package/dist/unstable/reactivity/AtomHttpApi.d.ts.map +1 -1
  79. package/dist/unstable/reactivity/AtomHttpApi.js +2 -2
  80. package/dist/unstable/reactivity/AtomHttpApi.js.map +1 -1
  81. package/dist/unstable/reactivity/AtomRpc.d.ts +1 -2
  82. package/dist/unstable/reactivity/AtomRpc.d.ts.map +1 -1
  83. package/dist/unstable/reactivity/AtomRpc.js +3 -3
  84. package/dist/unstable/reactivity/AtomRpc.js.map +1 -1
  85. package/dist/unstable/rpc/Rpc.d.ts +25 -4
  86. package/dist/unstable/rpc/Rpc.d.ts.map +1 -1
  87. package/dist/unstable/rpc/Rpc.js +26 -0
  88. package/dist/unstable/rpc/Rpc.js.map +1 -1
  89. package/dist/unstable/rpc/RpcClient.d.ts +3 -13
  90. package/dist/unstable/rpc/RpcClient.d.ts.map +1 -1
  91. package/dist/unstable/rpc/RpcClient.js +47 -23
  92. package/dist/unstable/rpc/RpcClient.js.map +1 -1
  93. package/dist/unstable/rpc/RpcGroup.d.ts +1 -1
  94. package/dist/unstable/rpc/RpcGroup.d.ts.map +1 -1
  95. package/dist/unstable/rpc/RpcMiddleware.d.ts +2 -2
  96. package/dist/unstable/rpc/RpcMiddleware.d.ts.map +1 -1
  97. package/dist/unstable/rpc/RpcServer.d.ts.map +1 -1
  98. package/dist/unstable/rpc/RpcServer.js +3 -2
  99. package/dist/unstable/rpc/RpcServer.js.map +1 -1
  100. package/dist/unstable/rpc/Utils.d.ts +6 -0
  101. package/dist/unstable/rpc/Utils.d.ts.map +1 -1
  102. package/dist/unstable/rpc/Utils.js +44 -0
  103. package/dist/unstable/rpc/Utils.js.map +1 -1
  104. package/dist/unstable/schema/Model.d.ts +2 -2
  105. package/dist/unstable/schema/Model.d.ts.map +1 -1
  106. package/dist/unstable/schema/Model.js +2 -4
  107. package/dist/unstable/schema/Model.js.map +1 -1
  108. package/dist/unstable/schema/VariantSchema.d.ts +1 -1
  109. package/dist/unstable/schema/VariantSchema.d.ts.map +1 -1
  110. package/dist/unstable/schema/VariantSchema.js +1 -12
  111. package/dist/unstable/schema/VariantSchema.js.map +1 -1
  112. package/dist/unstable/workers/Transferable.d.ts +1 -1
  113. package/dist/unstable/workers/Transferable.d.ts.map +1 -1
  114. package/dist/unstable/workers/Transferable.js +1 -1
  115. package/dist/unstable/workers/Transferable.js.map +1 -1
  116. package/package.json +1 -1
  117. package/src/Equal.ts +17 -0
  118. package/src/Hash.ts +2 -2
  119. package/src/Semaphore.ts +2 -4
  120. package/src/unstable/ai/McpServer.ts +24 -22
  121. package/src/unstable/eventlog/Event.ts +0 -8
  122. package/src/unstable/eventlog/EventGroup.ts +0 -4
  123. package/src/unstable/eventlog/EventJournal.ts +144 -76
  124. package/src/unstable/eventlog/EventLog.ts +342 -221
  125. package/src/unstable/eventlog/EventLogEncryption.ts +16 -30
  126. package/src/unstable/eventlog/EventLogMessage.ts +277 -0
  127. package/src/unstable/eventlog/EventLogRemote.ts +261 -408
  128. package/src/unstable/eventlog/EventLogServer.ts +182 -274
  129. package/src/unstable/eventlog/EventLogServerEncrypted.ts +206 -0
  130. package/src/unstable/eventlog/EventLogServerUnencrypted.ts +749 -0
  131. package/src/unstable/eventlog/EventLogSessionAuth.ts +437 -0
  132. package/src/unstable/eventlog/{SqlEventLogJournal.ts → SqlEventJournal.ts} +26 -18
  133. package/src/unstable/eventlog/{SqlEventLogServer.ts → SqlEventLogServerEncrypted.ts} +102 -40
  134. package/src/unstable/eventlog/SqlEventLogServerUnencrypted.ts +500 -0
  135. package/src/unstable/eventlog/index.ts +27 -2
  136. package/src/unstable/eventlog/internal/identityRootSecretDerivation.ts +153 -0
  137. package/src/unstable/reactivity/AtomHttpApi.ts +23 -8
  138. package/src/unstable/reactivity/AtomRpc.ts +16 -5
  139. package/src/unstable/rpc/Rpc.ts +42 -4
  140. package/src/unstable/rpc/RpcClient.ts +59 -24
  141. package/src/unstable/rpc/RpcGroup.ts +1 -1
  142. package/src/unstable/rpc/RpcMiddleware.ts +2 -2
  143. package/src/unstable/rpc/RpcServer.ts +5 -3
  144. package/src/unstable/rpc/Utils.ts +59 -0
  145. package/src/unstable/schema/Model.ts +4 -6
  146. package/src/unstable/schema/VariantSchema.ts +4 -17
  147. package/src/unstable/workers/Transferable.ts +9 -11
  148. package/dist/unstable/eventlog/SqlEventLogJournal.d.ts.map +0 -1
  149. package/dist/unstable/eventlog/SqlEventLogJournal.js.map +0 -1
  150. package/dist/unstable/eventlog/SqlEventLogServer.d.ts.map +0 -1
  151. package/dist/unstable/eventlog/SqlEventLogServer.js.map +0 -1
@@ -30,7 +30,6 @@ export interface AtomHttpApiClient<Self, Id extends string, Groups extends HttpA
30
30
  {
31
31
  new(_: never): Context.ServiceClass.Shape<Id, HttpApiClient.Client<Groups, never, never>>
32
32
 
33
- readonly layer: Layer.Layer<Self>
34
33
  readonly runtime: Atom.AtomRuntime<Self>
35
34
 
36
35
  readonly mutation: <
@@ -147,10 +146,15 @@ export const Service = <Self>() =>
147
146
  id: Id,
148
147
  options: {
149
148
  readonly api: HttpApi.HttpApi<ApiId, Groups>
150
- readonly httpClient: Layer.Layer<
151
- | HttpApiGroup.ClientServices<Groups>
152
- | HttpClient.HttpClient
153
- >
149
+ readonly httpClient:
150
+ | Layer.Layer<
151
+ | HttpApiGroup.ClientServices<Groups>
152
+ | HttpClient.HttpClient
153
+ >
154
+ | ((get: Atom.AtomContext) => Layer.Layer<
155
+ | HttpApiGroup.ClientServices<Groups>
156
+ | HttpClient.HttpClient
157
+ >)
154
158
  readonly transformClient?: ((client: HttpClient.HttpClient) => HttpClient.HttpClient) | undefined
155
159
  readonly transformResponse?:
156
160
  | ((effect: Effect.Effect<unknown, unknown, unknown>) => Effect.Effect<unknown, unknown, unknown>)
@@ -164,12 +168,23 @@ export const Service = <Self>() =>
164
168
  HttpApiClient.Client<Groups, never, never>
165
169
  >()(id) as any
166
170
 
167
- self.layer = Layer.effect(
171
+ const layer = Layer.effect(
168
172
  self,
169
173
  HttpApiClient.make(options.api, options)
170
- ).pipe(Layer.provide(options.httpClient)) as Layer.Layer<Self>
174
+ )
171
175
  const runtimeFactory = options.runtime ?? Atom.runtime
172
- self.runtime = runtimeFactory(self.layer)
176
+ self.runtime = runtimeFactory(
177
+ typeof options.httpClient === "function" ?
178
+ (get) =>
179
+ Layer.provide(
180
+ layer,
181
+ (options.httpClient as (get: Atom.AtomContext) => Layer.Layer<
182
+ | HttpApiGroup.ClientServices<Groups>
183
+ | HttpClient.HttpClient
184
+ >)(get)
185
+ ) as Layer.Layer<Self> :
186
+ Layer.provide(layer, options.httpClient) as Layer.Layer<Self>
187
+ )
173
188
 
174
189
  const catchErrors = Effect.catch((e: unknown) =>
175
190
  Schema.isSchemaError(e) || HttpClientError.isHttpClientError(e) ? Effect.die(e) : Effect.fail(e)
@@ -37,7 +37,6 @@ export interface AtomRpcClient<Self, Id extends string, Rpcs extends Rpc.Any> ex
37
37
  RpcClient.RpcClient.Flat<Rpcs, RpcClientError>
38
38
  >
39
39
 
40
- readonly layer: Layer.Layer<Self>
41
40
  readonly runtime: Atom.AtomRuntime<Self>
42
41
 
43
42
  readonly mutation: <Tag extends Rpc.Tag<Rpcs>>(
@@ -120,7 +119,9 @@ export const Service = <Self>() =>
120
119
  id: Id,
121
120
  options: {
122
121
  readonly group: RpcGroup.RpcGroup<Rpcs>
123
- readonly protocol: Layer.Layer<Exclude<NoInfer<RM>, Scope>, ER>
122
+ readonly protocol:
123
+ | Layer.Layer<Exclude<NoInfer<RM>, Scope>, ER>
124
+ | ((get: Atom.AtomContext) => Layer.Layer<Exclude<NoInfer<RM>, Scope>, ER>)
124
125
  readonly spanPrefix?: string | undefined
125
126
  readonly spanAttributes?: Record<string, unknown> | undefined
126
127
  readonly generateRequestId?: (() => RequestId) | undefined
@@ -140,7 +141,7 @@ export const Service = <Self>() =>
140
141
  RpcClient.RpcClient.Flat<Rpcs, RpcClientError>
141
142
  >()(id) as any
142
143
 
143
- self.layer = Layer.effect(
144
+ const layer = Layer.effect(
144
145
  self,
145
146
  options.makeEffect ??
146
147
  (RpcClient.make(options.group, {
@@ -151,9 +152,19 @@ export const Service = <Self>() =>
151
152
  never,
152
153
  RM
153
154
  >)
154
- ).pipe(Layer.provide(Layer.orDie(options.protocol)))
155
+ )
155
156
  const runtimeFactory = options.runtime ?? Atom.runtime
156
- self.runtime = runtimeFactory(self.layer)
157
+ self.runtime = runtimeFactory(
158
+ typeof options.protocol === "function" ?
159
+ (get) =>
160
+ Layer.provide(
161
+ layer,
162
+ Layer.orDie(
163
+ (options.protocol as ((get: Atom.AtomContext) => Layer.Layer<Exclude<NoInfer<RM>, Scope>, ER>))(get)
164
+ )
165
+ ) :
166
+ Layer.provide(layer, Layer.orDie(options.protocol))
167
+ )
157
168
 
158
169
  self.mutation = Atom.family(<Tag extends Rpc.Tag<Rpcs>>(tag: Tag) => {
159
170
  const rpc = options.group.requests.get(tag)! as any as Rpc.AnyWithProps
@@ -13,6 +13,7 @@ import type * as Queue from "../../Queue.ts"
13
13
  import * as Schema from "../../Schema.ts"
14
14
  import type { Stream } from "../../Stream.ts"
15
15
  import type * as Struct from "../../Struct.ts"
16
+ import type { NoInfer } from "../../Types.ts"
16
17
  import type { Headers } from "../http/Headers.ts"
17
18
  import type { RequestId } from "./RpcMessage.ts"
18
19
  import type * as RpcMiddleware from "./RpcMiddleware.ts"
@@ -134,7 +135,7 @@ export interface Rpc<
134
135
  */
135
136
  annotate<I, S>(
136
137
  tag: Context.Key<I, S>,
137
- value: S
138
+ value: NoInfer<S>
138
139
  ): Rpc<Tag, Payload, Success, Error, Middleware, Requires>
139
140
 
140
141
  /**
@@ -145,6 +146,26 @@ export interface Rpc<
145
146
  ): Rpc<Tag, Payload, Success, Error, Middleware, Requires>
146
147
  }
147
148
 
149
+ /**
150
+ * @since 4.0.0
151
+ * @category models
152
+ */
153
+ export class ServerClient {
154
+ readonly id: number
155
+ annotations: Context.Context<never>
156
+ constructor(id: number) {
157
+ this.id = id
158
+ this.annotations = Context.empty()
159
+ }
160
+ annotate<I, S>(
161
+ tag: Context.Key<I, S>,
162
+ value: NoInfer<S>
163
+ ): ServerClient {
164
+ this.annotations = Context.add(this.annotations, tag, value)
165
+ return this
166
+ }
167
+ }
168
+
148
169
  /**
149
170
  * Represents an implemented rpc.
150
171
  *
@@ -155,7 +176,7 @@ export interface Handler<Tag extends string> {
155
176
  readonly _: unique symbol
156
177
  readonly tag: Tag
157
178
  readonly handler: (request: any, options: {
158
- readonly clientId: number
179
+ readonly client: ServerClient
159
180
  readonly requestId: RequestId
160
181
  readonly headers: Headers
161
182
  readonly rpc: Any
@@ -475,12 +496,12 @@ export type ToHandler<R extends Any> = R extends Rpc<
475
496
  export type ToHandlerFn<Current extends Any, R = any> = (
476
497
  payload: Payload<Current>,
477
498
  options: {
478
- readonly clientId: number
499
+ readonly client: ServerClient
479
500
  readonly requestId: RequestId
480
501
  readonly headers: Headers
481
502
  readonly rpc: Current
482
503
  }
483
- ) => ResultFrom<Current, R> | Wrapper<ResultFrom<Current, R>>
504
+ ) => WrapperOr<ResultFrom<Current, R>>
484
505
 
485
506
  /**
486
507
  * @since 4.0.0
@@ -810,6 +831,12 @@ export interface Wrapper<A> {
810
831
  readonly uninterruptible: boolean
811
832
  }
812
833
 
834
+ /**
835
+ * @since 4.0.0
836
+ * @category Wrapper
837
+ */
838
+ export type WrapperOr<A> = A | Wrapper<A>
839
+
813
840
  /**
814
841
  * @since 4.0.0
815
842
  * @category Wrapper
@@ -839,6 +866,17 @@ export const wrap = (options: {
839
866
  uninterruptible: options.uninterruptible ?? false
840
867
  }
841
868
 
869
+ /**
870
+ * @since 4.0.0
871
+ * @category Wrapper
872
+ */
873
+ export const wrapMap = <A extends object, B extends object>(self: WrapperOr<A>, f: (value: A) => B): WrapperOr<B> => {
874
+ if (isWrapper(self)) {
875
+ return wrap(self)(f(self.value))
876
+ }
877
+ return f(self)
878
+ }
879
+
842
880
  /**
843
881
  * You can use `fork` to wrap a response Effect or Stream, to ensure that the
844
882
  * response is executed concurrently regardless of the RpcServer concurrency
@@ -39,7 +39,7 @@ import type * as RpcMiddleware from "./RpcMiddleware.ts"
39
39
  import * as RpcSchema from "./RpcSchema.ts"
40
40
  import * as RpcSerialization from "./RpcSerialization.ts"
41
41
  import * as RpcWorker from "./RpcWorker.ts"
42
- import { withRun } from "./Utils.ts"
42
+ import { withRunClient } from "./Utils.ts"
43
43
 
44
44
  /**
45
45
  * @since 4.0.0
@@ -587,6 +587,8 @@ export const makeNoSerialization: <Rpcs extends Rpc.Any, E, const Flatten extend
587
587
  return { client, write } as const
588
588
  })
589
589
 
590
+ let clientIdCounter = 0
591
+
590
592
  /**
591
593
  * @since 4.0.0
592
594
  * @category client
@@ -614,6 +616,7 @@ export const make: <Rpcs extends Rpc.Any, const Flatten extends boolean = false>
614
616
  readonly flatten?: Flatten | undefined
615
617
  } | undefined
616
618
  ) {
619
+ const clientId = clientIdCounter++
617
620
  const { run, send, supportsAck, supportsTransferables } = yield* Protocol
618
621
 
619
622
  type ClientEntry = {
@@ -645,7 +648,7 @@ export const make: <Rpcs extends Rpc.Any, const Flatten extends boolean = false>
645
648
  Effect.provideContext(entry.context),
646
649
  Effect.orDie,
647
650
  Effect.flatMap((payload) =>
648
- send({
651
+ send(clientId, {
649
652
  ...message,
650
653
  id: String(message.id),
651
654
  payload,
@@ -657,7 +660,7 @@ export const make: <Rpcs extends Rpc.Any, const Flatten extends boolean = false>
657
660
  case "Ack": {
658
661
  const entry = entries.get(message.requestId)
659
662
  if (!entry) return Effect.void
660
- return send({
663
+ return send(clientId, {
661
664
  _tag: "Ack",
662
665
  requestId: String(message.requestId)
663
666
  }) as Effect.Effect<void, RpcClientError>
@@ -666,7 +669,7 @@ export const make: <Rpcs extends Rpc.Any, const Flatten extends boolean = false>
666
669
  const entry = entries.get(message.requestId)
667
670
  if (!entry) return Effect.void
668
671
  entries.delete(message.requestId)
669
- return send({
672
+ return send(clientId, {
670
673
  _tag: "Interrupt",
671
674
  requestId: String(message.requestId)
672
675
  }) as Effect.Effect<void, RpcClientError>
@@ -678,7 +681,7 @@ export const make: <Rpcs extends Rpc.Any, const Flatten extends boolean = false>
678
681
  }
679
682
  })
680
683
 
681
- yield* run((message) => {
684
+ yield* run(clientId, (message) => {
682
685
  switch (message._tag) {
683
686
  case "Chunk": {
684
687
  const requestId = RequestId(message.requestId)
@@ -798,9 +801,11 @@ export const withHeaders: {
798
801
  */
799
802
  export class Protocol extends Context.Service<Protocol, {
800
803
  readonly run: (
804
+ clientId: number,
801
805
  f: (data: FromServerEncoded) => Effect.Effect<void>
802
806
  ) => Effect.Effect<never>
803
807
  readonly send: (
808
+ clientId: number,
804
809
  request: FromClientEncoded,
805
810
  transferables?: ReadonlyArray<globalThis.Transferable>
806
811
  ) => Effect.Effect<void, RpcClientError>
@@ -810,7 +815,7 @@ export class Protocol extends Context.Service<Protocol, {
810
815
  /**
811
816
  * @since 4.0.0
812
817
  */
813
- static make = withRun<Protocol["Service"]>()
818
+ static make = withRunClient
814
819
  }
815
820
 
816
821
  /**
@@ -836,7 +841,7 @@ export const makeProtocolHttp = (client: HttpClient.HttpClient): Effect.Effect<
836
841
  const emptyResponseError = (request: FromClientEncoded) =>
837
842
  protocolDefect("Received empty HTTP response from RPC server", request)
838
843
 
839
- const send = Effect.fnUntraced(function*(request: FromClientEncoded) {
844
+ const send = Effect.fnUntraced(function*(clientId: number, request: FromClientEncoded) {
840
845
  if (request._tag !== "Request") {
841
846
  return
842
847
  }
@@ -857,15 +862,15 @@ export const makeProtocolHttp = (client: HttpClient.HttpClient): Effect.Effect<
857
862
  catch: (cause) => protocolDefect("Error decoding HTTP response", cause)
858
863
  })
859
864
  if (!Array.isArray(responses)) {
860
- return yield* Effect.fail(protocolDefect("Expected an array of responses", responses))
865
+ return yield* protocolDefect("Expected an array of responses", responses)
861
866
  }
862
867
  if (responses.length === 0) {
863
- return yield* Effect.fail(emptyResponseError(request))
868
+ return yield* emptyResponseError(request)
864
869
  }
865
870
  let i = 0
866
871
  return yield* Effect.whileLoop({
867
872
  while: () => i < responses.length,
868
- body: () => writeResponse(responses[i++]),
873
+ body: () => writeResponse(clientId, responses[i++]),
869
874
  step: constVoid
870
875
  })
871
876
  }
@@ -882,7 +887,7 @@ export const makeProtocolHttp = (client: HttpClient.HttpClient): Effect.Effect<
882
887
  let i = 0
883
888
  return Effect.whileLoop({
884
889
  while: () => i < responses.length,
885
- body: () => writeResponse(responses[i++]),
890
+ body: () => writeResponse(clientId, responses[i++]),
886
891
  step: constVoid
887
892
  })
888
893
  })
@@ -890,7 +895,7 @@ export const makeProtocolHttp = (client: HttpClient.HttpClient): Effect.Effect<
890
895
  Effect.mapError((cause) => cause instanceof RpcClientError ? cause : httpClientError(cause))
891
896
  )
892
897
  if (!hasResponse) {
893
- return yield* Effect.fail(emptyResponseError(request))
898
+ return yield* emptyResponseError(request)
894
899
  }
895
900
  })
896
901
 
@@ -931,10 +936,11 @@ export const makeProtocolSocket = (options?: {
931
936
  never,
932
937
  Scope.Scope | RpcSerialization.RpcSerialization | Socket.Socket
933
938
  > =>
934
- Protocol.make(Effect.fnUntraced(function*(writeResponse) {
939
+ Protocol.make(Effect.fnUntraced(function*(writeResponse, clientIds) {
935
940
  const socket = yield* Socket.Socket
936
941
  const serialization = yield* RpcSerialization.RpcSerialization
937
942
  const hooks = yield* Effect.serviceOption(ConnectionHooks)
943
+ const requestClientMap = new Map<string, number>()
938
944
 
939
945
  const write = yield* socket.writer
940
946
 
@@ -947,6 +953,9 @@ export const makeProtocolSocket = (options?: {
947
953
  return Option.isSome(hooks) ? hooks.value.onConnect : Effect.void
948
954
  })
949
955
 
956
+ const broadcast = (response: FromServerEncoded) =>
957
+ Effect.forEach(clientIds, (clientId) => writeResponse(clientId, response))
958
+
950
959
  yield* Effect.suspend(() => {
951
960
  parser = serialization.makeUnsafe()
952
961
  pinger.reset()
@@ -961,13 +970,23 @@ export const makeProtocolSocket = (options?: {
961
970
  const response = responses[i++]
962
971
  if (response._tag === "Pong") {
963
972
  pinger.onPong()
973
+ return Effect.void
964
974
  }
965
- return writeResponse(response)
975
+ if ("requestId" in response) {
976
+ const clientId = requestClientMap.get(response.requestId)
977
+ if (clientId !== undefined) {
978
+ if (response._tag === "Exit") {
979
+ requestClientMap.delete(response.requestId)
980
+ }
981
+ return writeResponse(clientId, response)
982
+ }
983
+ }
984
+ return broadcast(response)
966
985
  },
967
986
  step: constVoid
968
987
  })
969
988
  } catch (defect) {
970
- return writeResponse({
989
+ return broadcast({
971
990
  _tag: "ClientProtocolError",
972
991
  error: new RpcClientError({
973
992
  reason: new RpcClientDefect({
@@ -1011,7 +1030,7 @@ export const makeProtocolSocket = (options?: {
1011
1030
  cause: Cause.squash(cause)
1012
1031
  })
1013
1032
  })
1014
- return writeResponse({
1033
+ return broadcast({
1015
1034
  _tag: "ClientProtocolError",
1016
1035
  error: currentError
1017
1036
  })
@@ -1025,10 +1044,13 @@ export const makeProtocolSocket = (options?: {
1025
1044
  )
1026
1045
 
1027
1046
  return {
1028
- send(request) {
1047
+ send(clientId, request) {
1029
1048
  if (currentError) {
1030
1049
  return Effect.fail(currentError)
1031
1050
  }
1051
+ if (request._tag === "Request") {
1052
+ requestClientMap.set(request.id, clientId)
1053
+ }
1032
1054
  const encoded = parser.encode(request)
1033
1055
  if (encoded === undefined) return Effect.void
1034
1056
  return Effect.orDie(write(encoded))
@@ -1099,7 +1121,7 @@ export const makeProtocolWorker = (
1099
1121
  WorkerError,
1100
1122
  Scope.Scope | Worker.WorkerPlatform | Worker.Spawner
1101
1123
  > =>
1102
- Protocol.make(Effect.fnUntraced(function*(writeResponse) {
1124
+ Protocol.make(Effect.fnUntraced(function*(writeResponse, clientIds) {
1103
1125
  const worker = yield* Worker.WorkerPlatform
1104
1126
  const scope = yield* Effect.scope
1105
1127
  let workerId = 0
@@ -1107,10 +1129,14 @@ export const makeProtocolWorker = (
1107
1129
  const hooks = yield* Effect.serviceOption(ConnectionHooks)
1108
1130
 
1109
1131
  const entries = new Map<string, {
1132
+ readonly clientId: number
1110
1133
  readonly worker: Worker.Worker<FromServerEncoded, FromClientEncoded | RpcWorker.InitialMessage.Encoded>
1111
1134
  readonly latch: Latch.Latch
1112
1135
  }>()
1113
1136
 
1137
+ const broadcast = (response: FromServerEncoded) =>
1138
+ Effect.forEach(clientIds, (clientId) => writeResponse(clientId, response))
1139
+
1114
1140
  const acquire = Effect.gen(function*() {
1115
1141
  const id = workerId++
1116
1142
  const backing = yield* worker.spawn<FromServerEncoded, FromClientEncoded | RpcWorker.InitialMessage.Encoded>(id)
@@ -1121,16 +1147,21 @@ export const makeProtocolWorker = (
1121
1147
  if (entry) {
1122
1148
  entries.delete(response.requestId)
1123
1149
  entry.latch.openUnsafe()
1124
- return writeResponse(response)
1150
+ return writeResponse(entry.clientId, response)
1125
1151
  }
1126
1152
  } else if (response._tag === "Defect") {
1127
1153
  for (const [requestId, entry] of entries) {
1128
1154
  entries.delete(requestId)
1129
1155
  entry.latch.openUnsafe()
1130
1156
  }
1131
- return writeResponse(response)
1157
+ return broadcast(response)
1158
+ } else if ("requestId" in response) {
1159
+ const entry = entries.get(response.requestId)
1160
+ if (entry) {
1161
+ return writeResponse(entry.clientId, response)
1162
+ }
1132
1163
  }
1133
- return writeResponse(response)
1164
+ return broadcast(response)
1134
1165
  }, {
1135
1166
  onSpawn: Option.isSome(initialMessage) ?
1136
1167
  Effect.flatMap(
@@ -1141,7 +1172,7 @@ export const makeProtocolWorker = (
1141
1172
  }).pipe(
1142
1173
  Effect.tapCause((cause) => {
1143
1174
  const error = Cause.findError(cause)
1144
- return writeResponse({
1175
+ return broadcast({
1145
1176
  _tag: "ClientProtocolError",
1146
1177
  error: new RpcClientError({
1147
1178
  reason: Result.isSuccess(error) ? error.success.reason : new RpcClientDefect({
@@ -1189,13 +1220,17 @@ export const makeProtocolWorker = (
1189
1220
  })
1190
1221
  )
1191
1222
 
1192
- const send = (request: FromClientEncoded, transferables?: ReadonlyArray<globalThis.Transferable>) => {
1223
+ const send = (
1224
+ clientId: number,
1225
+ request: FromClientEncoded,
1226
+ transferables?: ReadonlyArray<globalThis.Transferable>
1227
+ ) => {
1193
1228
  switch (request._tag) {
1194
1229
  case "Request": {
1195
1230
  return Pool.get(pool).pipe(
1196
1231
  Effect.flatMap((worker) => {
1197
1232
  const latch = Latch.makeUnsafe(false)
1198
- entries.set(request.id, { worker, latch })
1233
+ entries.set(request.id, { clientId, worker, latch })
1199
1234
  return Effect.flatMap(worker.send(request, transferables), () => latch.await)
1200
1235
  }),
1201
1236
  Effect.scoped,
@@ -119,7 +119,7 @@ export interface RpcGroup<in out R extends Rpc.Any> extends Pipeable {
119
119
  (
120
120
  payload: Rpc.Payload<Extract<R, { readonly _tag: Tag }>>,
121
121
  options: {
122
- readonly clientId: number
122
+ readonly client: Rpc.ServerClient
123
123
  readonly requestId: RequestId
124
124
  readonly headers: Headers
125
125
  }
@@ -31,7 +31,7 @@ export interface RpcMiddleware<Provides, E, Requires> {
31
31
  (
32
32
  effect: Effect.Effect<SuccessValue, E | unhandled, Provides>,
33
33
  options: {
34
- readonly clientId: number
34
+ readonly client: Rpc.ServerClient
35
35
  readonly requestId: RequestId
36
36
  readonly rpc: Rpc.AnyWithProps
37
37
  readonly payload: unknown
@@ -77,7 +77,7 @@ export interface Any {
77
77
  (
78
78
  effect: Effect.Effect<SuccessValue, any, any>,
79
79
  options: {
80
- readonly clientId: number
80
+ readonly client: Rpc.ServerClient
81
81
  readonly requestId: RequestId
82
82
  readonly rpc: Rpc.AnyWithProps
83
83
  readonly payload: unknown
@@ -109,6 +109,7 @@ export const makeNoSerialization: <Rpcs extends Rpc.Any>(
109
109
  readonly id: number
110
110
  readonly latches: Map<RequestId, Latch.Latch>
111
111
  readonly fibers: Map<RequestId, Fiber.Fiber<unknown, any>>
112
+ readonly serverClient: Rpc.ServerClient
112
113
  ended: boolean
113
114
  }
114
115
 
@@ -157,7 +158,8 @@ export const makeNoSerialization: <Rpcs extends Rpc.Any>(
157
158
  id: clientId,
158
159
  latches: new Map(),
159
160
  fibers: new Map(),
160
- ended: false
161
+ ended: false,
162
+ serverClient: new Rpc.ServerClient(clientId)
161
163
  }
162
164
  clients.set(clientId, client)
163
165
  } else if (client.ended) {
@@ -236,7 +238,7 @@ export const makeNoSerialization: <Rpcs extends Rpc.Any>(
236
238
  const isStream = RpcSchema.isStreamSchema(rpc.successSchema)
237
239
  const metadata = {
238
240
  rpc,
239
- clientId: client.id,
241
+ client: client.serverClient,
240
242
  requestId: request.id,
241
243
  headers: request.headers,
242
244
  payload: request.payload
@@ -410,7 +412,7 @@ const applyMiddleware = <A, E, R>(
410
412
  handler: Effect.Effect<A, E, R>,
411
413
  options: {
412
414
  readonly rpc: Rpc.AnyWithProps
413
- readonly clientId: number
415
+ readonly client: Rpc.ServerClient
414
416
  readonly requestId: RequestId
415
417
  readonly headers: Headers.Headers
416
418
  readonly payload: A
@@ -4,6 +4,8 @@
4
4
  import type * as Context from "../../Context.ts"
5
5
  import * as Effect from "../../Effect.ts"
6
6
  import * as Semaphore from "../../Semaphore.ts"
7
+ import type { Protocol } from "./RpcClient.ts"
8
+ import type { FromServerEncoded } from "./RpcMessage.ts"
7
9
 
8
10
  /**
9
11
  * @since 4.0.0
@@ -42,3 +44,60 @@ export const withRun = <
42
44
  }
43
45
  } as A))
44
46
  })
47
+
48
+ /**
49
+ * @since 4.0.0
50
+ */
51
+ export const withRunClient = <EX, RX>(
52
+ f: (
53
+ write: (clientId: number, response: FromServerEncoded) => Effect.Effect<void>,
54
+ clientIds: ReadonlySet<number>
55
+ ) => Effect.Effect<Omit<Protocol["Service"], "run">, EX, RX>
56
+ ): Effect.Effect<Protocol["Service"], EX, RX> =>
57
+ Effect.suspend(() => {
58
+ const clientIds = new Set<number>()
59
+ const clientBuffers = new Map<number, Array<[FromServerEncoded, Context.Context<never>]>>()
60
+ const clientWrites = new Map<number, (data: FromServerEncoded) => Effect.Effect<void>>()
61
+ let write = (clientId: number, data: FromServerEncoded): Effect.Effect<void> =>
62
+ Effect.contextWith((context) => {
63
+ let buffer = clientBuffers.get(clientId)
64
+ if (!buffer) {
65
+ buffer = []
66
+ clientBuffers.set(clientId, buffer)
67
+ }
68
+ buffer.push([data, context])
69
+ return Effect.void
70
+ })
71
+ return Effect.map(
72
+ f((clientId, data) => {
73
+ const clientWrite = clientWrites.get(clientId)
74
+ if (clientWrite) {
75
+ return clientWrite(data)
76
+ }
77
+ return write(clientId, data)
78
+ }, clientIds),
79
+ (a) => ({
80
+ ...a,
81
+ run(clientId, f) {
82
+ return Effect.gen(function*() {
83
+ clientIds.add(clientId)
84
+ clientWrites.set(clientId, f)
85
+
86
+ const buffer = clientBuffers.get(clientId)
87
+ if (buffer) {
88
+ clientBuffers.delete(clientId)
89
+ for (const [args, context] of buffer) {
90
+ yield* Effect.provideContext(Effect.suspend(() => f(args)), context)
91
+ }
92
+ }
93
+
94
+ return yield* Effect.onExit(Effect.never, () => {
95
+ clientIds.delete(clientId)
96
+ clientWrites.delete(clientId)
97
+ return Effect.void
98
+ })
99
+ })
100
+ }
101
+ } satisfies Protocol["Service"])
102
+ )
103
+ })
@@ -581,7 +581,7 @@ export interface JsonFromString<S extends Schema.Top> extends
581
581
  export const JsonFromString = <S extends Schema.Top>(
582
582
  schema: S
583
583
  ): JsonFromString<S> => {
584
- const parsed = Schema.fromJsonString(schema)
584
+ const parsed = Schema.fromJsonString(Schema.toCodecJson(schema)) as any
585
585
  return Field({
586
586
  select: parsed,
587
587
  insert: parsed,
@@ -599,7 +599,7 @@ export const JsonFromString = <S extends Schema.Top>(
599
599
  export interface UuidV4Insert<B extends string> extends
600
600
  VariantSchema.Field<{
601
601
  readonly select: Schema.brand<Schema.instanceOf<Uint8Array<ArrayBuffer>>, B>
602
- readonly insert: VariantSchema.Overrideable<Schema.brand<Schema.instanceOf<Uint8Array<ArrayBuffer>>, B>>
602
+ readonly insert: Schema.withConstructorDefault<Schema.brand<Schema.instanceOf<Uint8Array<ArrayBuffer>>, B>>
603
603
  readonly update: Schema.brand<Schema.instanceOf<Uint8Array<ArrayBuffer>>, B>
604
604
  readonly json: Schema.brand<Schema.instanceOf<Uint8Array<ArrayBuffer>>, B>
605
605
  }>
@@ -619,10 +619,8 @@ export const Uint8Array: Schema.instanceOf<Uint8Array<ArrayBuffer>> = Schema.Uin
619
619
  */
620
620
  export const UuidV4WithGenerate = <B extends string>(
621
621
  schema: Schema.brand<Schema.instanceOf<Uint8Array<ArrayBuffer>>, B>
622
- ): VariantSchema.Overrideable<Schema.brand<Schema.instanceOf<Uint8Array<ArrayBuffer>>, B>> =>
623
- VariantSchema.Overrideable(schema, {
624
- defaultValue: Effect.sync(() => Uuid.v4({}, new globalThis.Uint8Array(16)))
625
- })
622
+ ): Schema.withConstructorDefault<Schema.brand<Schema.instanceOf<Uint8Array<ArrayBuffer>>, B>> =>
623
+ schema.pipe(Schema.withConstructorDefault(Effect.sync(() => Uuid.v4({}, new globalThis.Uint8Array(16)))))
626
624
 
627
625
  /**
628
626
  * A field that represents a binary UUID v4 that is generated on inserts.