effect 4.0.0-beta.49 → 4.0.0-beta.50

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 (33) hide show
  1. package/dist/Deferred.d.ts +5 -0
  2. package/dist/Deferred.d.ts.map +1 -1
  3. package/dist/Deferred.js +6 -0
  4. package/dist/Deferred.js.map +1 -1
  5. package/dist/unstable/ai/McpServer.js.map +1 -1
  6. package/dist/unstable/cluster/Entity.d.ts +1 -1
  7. package/dist/unstable/cluster/Entity.d.ts.map +1 -1
  8. package/dist/unstable/eventlog/EventLogServer.js +2 -2
  9. package/dist/unstable/eventlog/EventLogServer.js.map +1 -1
  10. package/dist/unstable/reactivity/AtomHttpApi.d.ts +1 -0
  11. package/dist/unstable/reactivity/AtomHttpApi.d.ts.map +1 -1
  12. package/dist/unstable/reactivity/AtomHttpApi.js +17 -15
  13. package/dist/unstable/reactivity/AtomHttpApi.js.map +1 -1
  14. package/dist/unstable/reactivity/AtomRpc.d.ts +1 -0
  15. package/dist/unstable/reactivity/AtomRpc.d.ts.map +1 -1
  16. package/dist/unstable/reactivity/AtomRpc.js +13 -11
  17. package/dist/unstable/reactivity/AtomRpc.js.map +1 -1
  18. package/dist/unstable/rpc/Rpc.d.ts +8 -2
  19. package/dist/unstable/rpc/Rpc.d.ts.map +1 -1
  20. package/dist/unstable/rpc/Rpc.js +5 -0
  21. package/dist/unstable/rpc/Rpc.js.map +1 -1
  22. package/dist/unstable/rpc/RpcServer.d.ts.map +1 -1
  23. package/dist/unstable/rpc/RpcServer.js +38 -8
  24. package/dist/unstable/rpc/RpcServer.js.map +1 -1
  25. package/package.json +1 -1
  26. package/src/Deferred.ts +7 -0
  27. package/src/unstable/ai/McpServer.ts +1 -1
  28. package/src/unstable/cluster/Entity.ts +1 -1
  29. package/src/unstable/eventlog/EventLogServer.ts +2 -2
  30. package/src/unstable/reactivity/AtomHttpApi.ts +14 -13
  31. package/src/unstable/reactivity/AtomRpc.ts +15 -12
  32. package/src/unstable/rpc/Rpc.ts +9 -2
  33. package/src/unstable/rpc/RpcServer.ts +43 -13
@@ -4,7 +4,6 @@
4
4
  import * as Context from "../../Context.ts"
5
5
  import * as Duration from "../../Duration.ts"
6
6
  import * as Effect from "../../Effect.ts"
7
- import * as Hash from "../../Hash.ts"
8
7
  import * as Layer from "../../Layer.ts"
9
8
  import type { ReadonlyRecord } from "../../Record.ts"
10
9
  import * as Schema from "../../Schema.ts"
@@ -105,6 +104,7 @@ export interface AtomHttpApiClient<Self, Id extends string, Groups extends HttpA
105
104
  | ReadonlyRecord<string, ReadonlyArray<unknown>>
106
105
  | undefined
107
106
  readonly timeToLive?: Duration.Input | undefined
107
+ readonly serializationKey?: string | undefined
108
108
  }
109
109
  >
110
110
  : never
@@ -239,10 +239,10 @@ export const Service = <Self>() =>
239
239
  HttpClientError.HttpClientError | SchemaError
240
240
  >)
241
241
  }))
242
- if (opts.responseMode === "decoded-only") {
242
+ if (opts.responseMode === "decoded-only" && opts.serializationKey) {
243
243
  const endpoint = options.api.groups[opts.group]!.endpoints[opts.endpoint]! as HttpApiEndpoint.AnyWithProps
244
244
  atom = Atom.serializable(atom, {
245
- key: makeSerializableKey(opts),
245
+ key: `AtomHttpApi:${opts.group}:${opts.endpoint}:${opts.serializationKey}`,
246
246
  schema: AsyncResult.Schema({
247
247
  success: Schema.Union(HttpApiEndpoint.getSuccessSchemas(endpoint)),
248
248
  error: Schema.Union(HttpApiEndpoint.getErrorSchemas(endpoint))
@@ -270,9 +270,10 @@ export const Service = <Self>() =>
270
270
  readonly responseMode?: HttpApiEndpoint.ClientResponseMode
271
271
  readonly reactivityKeys?: ReadonlyArray<unknown> | ReadonlyRecord<string, ReadonlyArray<unknown>> | undefined
272
272
  readonly timeToLive?: Duration.Input | undefined
273
+ readonly serializationKey?: string | undefined
273
274
  }
274
- ) =>
275
- queryFamily({
275
+ ) => {
276
+ const key: QueryKey = {
276
277
  group,
277
278
  endpoint,
278
279
  params: request.params,
@@ -283,8 +284,11 @@ export const Service = <Self>() =>
283
284
  reactivityKeys: request.reactivityKeys,
284
285
  timeToLive: request.timeToLive
285
286
  ? Duration.fromInputUnsafe(request.timeToLive)
286
- : undefined
287
- })) as any
287
+ : undefined,
288
+ serializationKey: request.serializationKey
289
+ }
290
+ return queryFamily(key)
291
+ }) as any
288
292
 
289
293
  return self as AtomHttpApiClient<Self, Id, Groups>
290
294
  }
@@ -303,15 +307,12 @@ interface QueryKey {
303
307
  headers: any
304
308
  payload: any
305
309
  responseMode: HttpApiEndpoint.ClientResponseMode
306
- reactivityKeys?: ReadonlyArray<unknown> | ReadonlyRecord<string, ReadonlyArray<unknown>> | undefined
307
- timeToLive?: Duration.Duration | undefined
310
+ reactivityKeys: ReadonlyArray<unknown> | ReadonlyRecord<string, ReadonlyArray<unknown>> | undefined
311
+ timeToLive: Duration.Duration | undefined
312
+ serializationKey: string | undefined
308
313
  }
309
314
 
310
315
  type ResponseByMode<Success, ResponseMode extends HttpApiEndpoint.ClientResponseMode> = [ResponseMode] extends
311
316
  ["decoded-and-response"] ? [Success, HttpClientResponse]
312
317
  : [ResponseMode] extends ["response-only"] ? HttpClientResponse
313
318
  : Success
314
-
315
- const makeSerializableKey = (
316
- key: QueryKey
317
- ): string => `AtomHttpApi:${key.group}:${key.endpoint}:${Hash.hash(key)}`
@@ -4,7 +4,6 @@
4
4
  import * as Context from "../../Context.ts"
5
5
  import * as Duration from "../../Duration.ts"
6
6
  import * as Effect from "../../Effect.ts"
7
- import * as Hash from "../../Hash.ts"
8
7
  import * as Layer from "../../Layer.ts"
9
8
  import type { ReadonlyRecord } from "../../Record.ts"
10
9
  import * as Schema from "../../Schema.ts"
@@ -73,6 +72,7 @@ export interface AtomRpcClient<Self, Id extends string, Rpcs extends Rpc.Any> ex
73
72
  | ReadonlyRecord<string, ReadonlyArray<unknown>>
74
73
  | undefined
75
74
  readonly timeToLive?: Duration.Input | undefined
75
+ readonly serializationKey?: string | undefined
76
76
  }
77
77
  ) => Rpc.ExtractTag<Rpcs, Tag> extends Rpc.Rpc<
78
78
  infer _Tag,
@@ -212,9 +212,9 @@ export const Service = <Self>() =>
212
212
  : self.runtime.atom(
213
213
  self.use((client) => client(tag, payload, { headers } as any)) as any
214
214
  )
215
- if (!isStream) {
215
+ if (!isStream && key.serializationKey) {
216
216
  atom = Atom.serializable(atom, {
217
- key: makeSerializableKey(key),
217
+ key: `AtomRpc:${key.tag}:${key.serializationKey}`,
218
218
  schema: AsyncResult.Schema({
219
219
  success: rpc.successSchema,
220
220
  error: makeErrorSchema(rpc)
@@ -242,9 +242,10 @@ export const Service = <Self>() =>
242
242
  | ReadonlyRecord<string, ReadonlyArray<unknown>>
243
243
  | undefined
244
244
  readonly timeToLive?: Duration.Input | undefined
245
+ readonly serializationKey?: string | undefined
245
246
  }
246
- ) =>
247
- queryFamily({
247
+ ) => {
248
+ const key: QueryKey = {
248
249
  tag,
249
250
  payload,
250
251
  headers: options?.headers
@@ -253,8 +254,11 @@ export const Service = <Self>() =>
253
254
  reactivityKeys: options?.reactivityKeys,
254
255
  timeToLive: options?.timeToLive
255
256
  ? Duration.fromInputUnsafe(options.timeToLive)
256
- : undefined
257
- }) as any
257
+ : undefined,
258
+ serializationKey: options?.serializationKey
259
+ }
260
+ return queryFamily(key) as any
261
+ }
258
262
 
259
263
  return self as AtomRpcClient<Self, Id, Rpcs>
260
264
  }
@@ -262,12 +266,13 @@ export const Service = <Self>() =>
262
266
  interface QueryKey {
263
267
  tag: string
264
268
  payload: any
265
- headers?: Headers.Headers | undefined
266
- reactivityKeys?:
269
+ headers: Headers.Headers | undefined
270
+ reactivityKeys:
267
271
  | ReadonlyArray<unknown>
268
272
  | ReadonlyRecord<string, ReadonlyArray<unknown>>
269
273
  | undefined
270
- timeToLive?: Duration.Duration | undefined
274
+ timeToLive: Duration.Duration | undefined
275
+ serializationKey: string | undefined
271
276
  }
272
277
 
273
278
  const makeErrorSchema = (rpc: Rpc.AnyWithProps): Schema.Top =>
@@ -276,5 +281,3 @@ const makeErrorSchema = (rpc: Rpc.AnyWithProps): Schema.Top =>
276
281
  ...Array.from(rpc.middlewares, (middleware) => middleware.error),
277
282
  RpcClientError
278
283
  ])
279
-
280
- const makeSerializableKey = (key: QueryKey): string => `AtomRpc:${key.tag}:${Hash.hash(key)}`
@@ -3,6 +3,7 @@
3
3
  */
4
4
  import type * as Cause from "../../Cause.ts"
5
5
  import * as Context from "../../Context.ts"
6
+ import type { Deferred } from "../../Deferred.ts"
6
7
  import type { Effect } from "../../Effect.ts"
7
8
  import type { Exit as Exit_ } from "../../Exit.ts"
8
9
  import * as Option from "../../Option.ts"
@@ -180,7 +181,7 @@ export interface Handler<Tag extends string> {
180
181
  readonly requestId: RequestId
181
182
  readonly headers: Headers
182
183
  readonly rpc: Any
183
- }) => Effect<any, any> | Stream<any, any>
184
+ }) => Effect<{} | Deferred<any, any>, any> | Stream<any, any>
184
185
  readonly context: Context.Context<never>
185
186
  }
186
187
 
@@ -591,7 +592,7 @@ export type ResultFrom<R extends Any, Services> = R extends Rpc<
591
592
  Services
592
593
  > :
593
594
  Effect<
594
- _Success["Type"],
595
+ _Success["Type"] | Deferred<_Success["Type"], _Error["Type"]>,
595
596
  _Error["Type"],
596
597
  Services
597
598
  > :
@@ -866,6 +867,12 @@ export const wrap = (options: {
866
867
  uninterruptible: options.uninterruptible ?? false
867
868
  }
868
869
 
870
+ /**
871
+ * @since 4.0.0
872
+ * @category Wrapper
873
+ */
874
+ export const unwrap = <A extends object>(value: WrapperOr<A>): A => isWrapper(value) ? value.value : value
875
+
869
876
  /**
870
877
  * @since 4.0.0
871
878
  * @category Wrapper
@@ -252,28 +252,45 @@ export const makeNoSerialization: <Rpcs extends Rpc.Any>(
252
252
  // unwrap the fork data type
253
253
  const streamOrEffect = isWrapper ? result.value : result
254
254
  const handler = isStream
255
- ? (streamEffect(client, request, streamOrEffect) as Effect.Effect<any>)
256
- : (streamOrEffect as Effect.Effect<any>)
255
+ ? (streamEffect(client, request, streamOrEffect) as Effect.Effect<{} | Deferred.Deferred<any, any>>)
256
+ : (streamOrEffect as Effect.Effect<{} | Deferred.Deferred<any, any>>)
257
257
 
258
258
  const withMiddleware = rpc.middlewares.size > 0
259
259
  ? applyMiddleware(services, handler, metadata)
260
260
  : handler
261
261
  let responded = false
262
262
  const scope = Scope.makeUnsafe()
263
+ let deferred: Deferred.Deferred<unknown, unknown> | undefined = undefined
263
264
  let effect = Effect.onExit(withMiddleware, (exit) => {
264
265
  responded = true
265
- const close = Scope.closeUnsafe(scope, exit)
266
- const write = exit._tag === "Failure" &&
267
- !disableFatalDefects &&
268
- Cause.hasDies(exit.cause) &&
269
- !Cause.hasInterrupts(exit.cause)
270
- ? sendDefect(client, Cause.squash(exit.cause))
271
- : options.onFromServer({
266
+ let write: Effect.Effect<void>
267
+ if (exit._tag === "Success") {
268
+ if (Deferred.isDeferred(exit.value)) {
269
+ deferred = exit.value
270
+ write = Effect.void
271
+ } else {
272
+ write = options.onFromServer({
273
+ _tag: "Exit",
274
+ clientId: client.id,
275
+ requestId: request.id,
276
+ exit: exit as any
277
+ })
278
+ }
279
+ } else if (
280
+ !disableFatalDefects &&
281
+ Cause.hasDies(exit.cause) &&
282
+ !Cause.hasInterrupts(exit.cause)
283
+ ) {
284
+ write = sendDefect(client, Cause.squash(exit.cause))
285
+ } else {
286
+ write = options.onFromServer({
272
287
  _tag: "Exit",
273
288
  clientId: client.id,
274
289
  requestId: request.id,
275
- exit
290
+ exit: exit as any
276
291
  })
292
+ }
293
+ const close = Scope.closeUnsafe(scope, exit)
277
294
  if (exit._tag === "Failure") {
278
295
  reportCauseUnsafe(Fiber.getCurrent()!, exit.cause)
279
296
  }
@@ -304,7 +321,7 @@ export const makeNoSerialization: <Rpcs extends Rpc.Any>(
304
321
  })
305
322
  }
306
323
  if (!isFork && concurrencySemaphore) {
307
- effect = concurrencySemaphore.withPermits(1)(effect)
324
+ effect = concurrencySemaphore.withPermit(effect)
308
325
  }
309
326
  const context = new Map(entry.context.mapUnsafe)
310
327
  requestFiber.context.mapUnsafe.forEach((value, key) => context.set(key, value))
@@ -317,7 +334,20 @@ export const makeNoSerialization: <Rpcs extends Rpc.Any>(
317
334
  )
318
335
  )
319
336
  client.fibers.set(request.id, fiber)
320
- fiber.addObserver((exit) => {
337
+ fiber.addObserver(function onExit(exit: Exit.Exit<any, any>): void {
338
+ if (deferred) {
339
+ const fiber = trackFiber(runFork(Effect.onExit(Deferred.await(deferred), (exit) =>
340
+ options.onFromServer({
341
+ _tag: "Exit",
342
+ clientId: client.id,
343
+ requestId: request.id,
344
+ exit: exit as any
345
+ }))))
346
+ client.fibers.set(request.id, fiber)
347
+ deferred = undefined
348
+ fiber.addObserver(onExit)
349
+ return
350
+ }
321
351
  if (!responded && exit._tag === "Failure") {
322
352
  trackFiber(
323
353
  runFork(
@@ -415,7 +445,7 @@ const applyMiddleware = <A, E, R>(
415
445
  readonly client: Rpc.ServerClient
416
446
  readonly requestId: RequestId
417
447
  readonly headers: Headers.Headers
418
- readonly payload: A
448
+ readonly payload: unknown
419
449
  }
420
450
  ) => {
421
451
  for (const service of options.rpc.middlewares) {