@effect/platform 0.36.0 → 0.37.1

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 (43) hide show
  1. package/dist/cjs/Http/Router.js.map +1 -1
  2. package/dist/cjs/Transferable.js +70 -2
  3. package/dist/cjs/Transferable.js.map +1 -1
  4. package/dist/cjs/Worker.js.map +1 -1
  5. package/dist/cjs/WorkerRunner.js.map +1 -1
  6. package/dist/cjs/internal/http/router.js +7 -15
  7. package/dist/cjs/internal/http/router.js.map +1 -1
  8. package/dist/cjs/internal/worker.js +12 -5
  9. package/dist/cjs/internal/worker.js.map +1 -1
  10. package/dist/cjs/internal/workerRunner.js +12 -8
  11. package/dist/cjs/internal/workerRunner.js.map +1 -1
  12. package/dist/dts/Http/Router.d.ts +31 -26
  13. package/dist/dts/Http/Router.d.ts.map +1 -1
  14. package/dist/dts/Transferable.d.ts +19 -0
  15. package/dist/dts/Transferable.d.ts.map +1 -1
  16. package/dist/dts/Worker.d.ts +4 -1
  17. package/dist/dts/Worker.d.ts.map +1 -1
  18. package/dist/dts/WorkerError.d.ts +2 -2
  19. package/dist/dts/WorkerError.d.ts.map +1 -1
  20. package/dist/dts/WorkerRunner.d.ts +5 -4
  21. package/dist/dts/WorkerRunner.d.ts.map +1 -1
  22. package/dist/dts/internal/http/router.d.ts.map +1 -1
  23. package/dist/esm/Http/Router.js.map +1 -1
  24. package/dist/esm/Transferable.js +41 -1
  25. package/dist/esm/Transferable.js.map +1 -1
  26. package/dist/esm/Worker.js.map +1 -1
  27. package/dist/esm/WorkerRunner.js.map +1 -1
  28. package/dist/esm/internal/http/router.js +7 -10
  29. package/dist/esm/internal/http/router.js.map +1 -1
  30. package/dist/esm/internal/worker.js +12 -5
  31. package/dist/esm/internal/worker.js.map +1 -1
  32. package/dist/esm/internal/workerRunner.js +12 -8
  33. package/dist/esm/internal/workerRunner.js.map +1 -1
  34. package/package.json +2 -2
  35. package/src/Http/Router.ts +34 -27
  36. package/src/Transferable.ts +80 -2
  37. package/src/Worker.ts +4 -1
  38. package/src/WorkerError.ts +2 -2
  39. package/src/WorkerRunner.ts +5 -4
  40. package/src/internal/command.ts +1 -1
  41. package/src/internal/http/router.ts +24 -26
  42. package/src/internal/worker.ts +31 -18
  43. package/src/internal/workerRunner.ts +28 -9
@@ -23,7 +23,7 @@ export type WorkerErrorTypeId = typeof WorkerErrorTypeId
23
23
  export interface WorkerError extends Data.Case {
24
24
  readonly [WorkerErrorTypeId]: WorkerErrorTypeId
25
25
  readonly _tag: "WorkerError"
26
- readonly reason: "spawn" | "decode" | "send" | "unknown"
26
+ readonly reason: "spawn" | "decode" | "send" | "unknown" | "encode"
27
27
  readonly error: unknown
28
28
  readonly stack?: string
29
29
  }
@@ -33,7 +33,7 @@ export interface WorkerError extends Data.Case {
33
33
  * @category errors
34
34
  */
35
35
  export const WorkerError: (
36
- reason: "spawn" | "decode" | "send" | "unknown",
36
+ reason: "spawn" | "decode" | "send" | "unknown" | "encode",
37
37
  error: unknown,
38
38
  stack?: string
39
39
  ) => WorkerError = internal.WorkerError
@@ -70,9 +70,10 @@ export declare namespace Runner {
70
70
  * @since 1.0.0
71
71
  * @category models
72
72
  */
73
- export interface Options<O> {
74
- readonly encode?: (message: O) => unknown
75
- readonly transfers?: (message: O) => ReadonlyArray<unknown>
73
+ export interface Options<E, O> {
74
+ readonly encodeOutput?: (message: O) => Effect.Effect<never, WorkerError, unknown>
75
+ readonly encodeError?: (message: E) => Effect.Effect<never, WorkerError, unknown>
76
+ readonly transfers?: (message: O | E) => ReadonlyArray<unknown>
76
77
  }
77
78
  }
78
79
 
@@ -82,7 +83,7 @@ export declare namespace Runner {
82
83
  */
83
84
  export const make: <I, R, E, O>(
84
85
  process: (request: I) => Stream.Stream<R, E, O> | Effect.Effect<R, E, O>,
85
- options?: Runner.Options<O> | undefined
86
+ options?: Runner.Options<E, O> | undefined
86
87
  ) => Effect.Effect<Scope.Scope | R | PlatformRunner, WorkerError, never> = internal.make
87
88
 
88
89
  /**
@@ -4,7 +4,7 @@ import { dual } from "effect/Function"
4
4
  import * as HashMap from "effect/HashMap"
5
5
  import * as Option from "effect/Option"
6
6
  import { pipeArguments } from "effect/Pipeable"
7
- import type ReadonlyArray from "effect/ReadonlyArray"
7
+ import type * as ReadonlyArray from "effect/ReadonlyArray"
8
8
  import type { Scope } from "effect/Scope"
9
9
  import * as Stream from "effect/Stream"
10
10
  import type * as Command from "../Command.js"
@@ -7,8 +7,7 @@ import * as Effectable from "effect/Effectable"
7
7
  import { dual } from "effect/Function"
8
8
  import * as Inspectable from "effect/Inspectable"
9
9
  import * as Option from "effect/Option"
10
- import type { HTTPMethod } from "find-my-way"
11
- import FindMyWay from "find-my-way"
10
+ import * as FindMyWay from "find-my-way-ts"
12
11
  import type * as App from "../../Http/App.js"
13
12
  import type * as Method from "../../Http/Method.js"
14
13
  import type * as Router from "../../Http/Router.js"
@@ -95,17 +94,14 @@ class RouterImpl<R, E> extends Effectable.StructuralClass<
95
94
  const toHttpApp = <R, E>(
96
95
  self: Router.Router<R, E>
97
96
  ): App.Default<Router.Router.ExcludeProvided<R>, E | Error.RouteNotFound> => {
98
- const router = FindMyWay()
97
+ const router = FindMyWay.make<Router.Route<R, E>>()
99
98
  const mounts = Chunk.toReadonlyArray(self.mounts)
100
99
  const mountsLen = mounts.length
101
100
  Chunk.forEach(self.routes, (route) => {
102
- function fn() {
103
- return route
104
- }
105
101
  if (route.method === "*") {
106
- router.all(route.path, fn)
102
+ router.all(route.path, route)
107
103
  } else {
108
- router.on(route.method, route.path, fn)
104
+ router.on(route.method, route.path, route)
109
105
  }
110
106
  })
111
107
  return Effect.flatMap(
@@ -124,14 +120,14 @@ const toHttpApp = <R, E>(
124
120
  }
125
121
  }
126
122
 
127
- let result = router.find(request.method as HTTPMethod, request.url)
128
- if (result === null && request.method === "HEAD") {
123
+ let result = router.find(request.method, request.url)
124
+ if (result === undefined && request.method === "HEAD") {
129
125
  result = router.find("GET", request.url)
130
126
  }
131
- if (result === null) {
127
+ if (result === undefined) {
132
128
  return Effect.fail(Error.RouteNotFound({ request }))
133
129
  }
134
- const route = (result.handler as any)() as Router.Route<R, E>
130
+ const route = result.handler
135
131
  if (route.prefix._tag === "Some") {
136
132
  request = sliceRequestUrl(request, route.prefix.value)
137
133
  }
@@ -157,7 +153,7 @@ class RouteImpl<R, E> implements Router.Route<R, E> {
157
153
  readonly [RouteTypeId]: Router.RouteTypeId
158
154
  constructor(
159
155
  readonly method: Method.Method | "*",
160
- readonly path: string,
156
+ readonly path: Router.PathInput,
161
157
  readonly handler: Router.Route.Handler<R, E>,
162
158
  readonly prefix = Option.none<string>()
163
159
  ) {
@@ -186,7 +182,7 @@ export const fromIterable = <R, E>(
186
182
  /** @internal */
187
183
  export const makeRoute = <R, E>(
188
184
  method: Method.Method,
189
- path: string,
185
+ path: Router.PathInput,
190
186
  handler: Router.Route.Handler<R, E>,
191
187
  prefix: Option.Option<string> = Option.none()
192
188
  ): Router.Route<R, E> => new RouteImpl(method, path, handler, prefix)
@@ -197,12 +193,14 @@ export const concat = dual<
197
193
  <R, E, R1, E1>(self: Router.Router<R, E>, that: Router.Router<R1, E1>) => Router.Router<R | R1, E | E1>
198
194
  >(2, (self, that) => new RouterImpl(Chunk.appendAll(self.routes, that.routes) as any, self.mounts))
199
195
 
200
- const removeTrailingSlash = (path: string) => (path.endsWith("/") ? path.slice(0, -1) : path)
196
+ const removeTrailingSlash = (
197
+ path: Router.PathInput
198
+ ): Router.PathInput => (path.endsWith("/") ? path.slice(0, -1) : path) as any
201
199
 
202
200
  /** @internal */
203
201
  export const prefixAll = dual<
204
- (prefix: string) => <R, E>(self: Router.Router<R, E>) => Router.Router<R, E>,
205
- <R, E>(self: Router.Router<R, E>, prefix: string) => Router.Router<R, E>
202
+ (prefix: Router.PathInput) => <R, E>(self: Router.Router<R, E>) => Router.Router<R, E>,
203
+ <R, E>(self: Router.Router<R, E>, prefix: Router.PathInput) => Router.Router<R, E>
206
204
  >(
207
205
  2,
208
206
  (self, prefix) => {
@@ -211,7 +209,7 @@ export const prefixAll = dual<
211
209
  Chunk.map(self.routes, (route) =>
212
210
  new RouteImpl(
213
211
  route.method,
214
- route.path === "/" ? prefix : prefix + route.path,
212
+ route.path === "/" ? prefix : prefix + route.path as Router.PathInput,
215
213
  route.handler,
216
214
  Option.orElse(
217
215
  Option.map(route.prefix, (_) => prefix + _),
@@ -226,12 +224,12 @@ export const prefixAll = dual<
226
224
  /** @internal */
227
225
  export const mount = dual<
228
226
  <R1, E1>(
229
- path: string,
227
+ path: `/${string}`,
230
228
  that: Router.Router<R1, E1>
231
229
  ) => <R, E>(self: Router.Router<R, E>) => Router.Router<R | R1, E | E1>,
232
230
  <R, E, R1, E1>(
233
231
  self: Router.Router<R, E>,
234
- path: string,
232
+ path: `/${string}`,
235
233
  that: Router.Router<R1, E1>
236
234
  ) => Router.Router<R | R1, E | E1>
237
235
  >(
@@ -242,14 +240,14 @@ export const mount = dual<
242
240
  /** @internal */
243
241
  export const mountApp = dual<
244
242
  <R1, E1>(
245
- path: string,
243
+ path: `/${string}`,
246
244
  that: App.Default<R1, E1>
247
245
  ) => <R, E>(
248
246
  self: Router.Router<R, E>
249
247
  ) => Router.Router<Router.Router.ExcludeProvided<R | R1>, E | E1>,
250
248
  <R, E, R1, E1>(
251
249
  self: Router.Router<R, E>,
252
- path: string,
250
+ path: `/${string}`,
253
251
  that: App.Default<R1, E1>
254
252
  ) => Router.Router<Router.Router.ExcludeProvided<R | R1>, E | E1>
255
253
  >(
@@ -261,27 +259,27 @@ export const mountApp = dual<
261
259
  /** @internal */
262
260
  export const route = (method: Method.Method | "*"): {
263
261
  <R1, E1>(
264
- path: string,
262
+ path: Router.PathInput,
265
263
  handler: Router.Route.Handler<R1, E1>
266
264
  ): <R, E>(
267
265
  self: Router.Router<R, E>
268
266
  ) => Router.Router<Router.Router.ExcludeProvided<R | R1>, E1 | E>
269
267
  <R, E, R1, E1>(
270
268
  self: Router.Router<R, E>,
271
- path: string,
269
+ path: Router.PathInput,
272
270
  handler: Router.Route.Handler<R1, E1>
273
271
  ): Router.Router<Router.Router.ExcludeProvided<R | R1>, E1 | E>
274
272
  } =>
275
273
  dual<
276
274
  <R1, E1>(
277
- path: string,
275
+ path: Router.PathInput,
278
276
  handler: Router.Route.Handler<R1, E1>
279
277
  ) => <R, E>(
280
278
  self: Router.Router<R, E>
281
279
  ) => Router.Router<Router.Router.ExcludeProvided<R | R1>, E | E1>,
282
280
  <R, E, R1, E1>(
283
281
  self: Router.Router<R, E>,
284
- path: string,
282
+ path: Router.PathInput,
285
283
  handler: Router.Route.Handler<R1, E1>
286
284
  ) => Router.Router<Router.Router.ExcludeProvided<R | R1>, E | E1>
287
285
  >(3, (self, path, handler) =>
@@ -16,7 +16,7 @@ import type * as Scope from "effect/Scope"
16
16
  import * as Stream from "effect/Stream"
17
17
  import * as Transferable from "../Transferable.js"
18
18
  import type * as Worker from "../Worker.js"
19
- import type { WorkerError } from "../WorkerError.js"
19
+ import { WorkerError } from "../WorkerError.js"
20
20
 
21
21
  /** @internal */
22
22
  export const defaultQueue = <I>() =>
@@ -55,7 +55,14 @@ export const makeManager = Effect.gen(function*(_) {
55
55
  let idCounter = 0
56
56
  return WorkerManager.of({
57
57
  [WorkerManagerTypeId]: WorkerManagerTypeId,
58
- spawn<I, E, O>({ encode, permits = 1, queue, spawn, transfers = (_) => [] }: Worker.Worker.Options<I>) {
58
+ spawn<I, E, O>({
59
+ encode,
60
+ initialMessage,
61
+ permits = 1,
62
+ queue,
63
+ spawn,
64
+ transfers = (_) => []
65
+ }: Worker.Worker.Options<I>) {
59
66
  return Effect.gen(function*(_) {
60
67
  const id = idCounter++
61
68
  let requestIdCounter = 0
@@ -194,13 +201,13 @@ export const makeManager = Effect.gen(function*(_) {
194
201
  const result = requestMap.get(id)
195
202
  if (!result) return Effect.unit
196
203
  const transferables = transfers(request)
197
- const payload = encode ? encode(request) : request
198
- return Effect.zipRight(
199
- Effect.catchAllCause(
200
- backing.send([id, 0, payload], transferables),
201
- (cause) => Queue.offer(result[0], Exit.failCause(cause))
204
+ return pipe(
205
+ Effect.flatMap(
206
+ encode ? encode(request) : Effect.succeed(request),
207
+ (payload) => backing.send([id, 0, payload], transferables)
202
208
  ),
203
- Deferred.await(result[1])
209
+ Effect.catchAllCause((cause) => Queue.offer(result[0], Exit.failCause(cause))),
210
+ Effect.zipRight(Deferred.await(result[1]))
204
211
  )
205
212
  }),
206
213
  Effect.ensuring(semaphore.release(1)),
@@ -222,6 +229,14 @@ export const makeManager = Effect.gen(function*(_) {
222
229
  never
223
230
  >
224
231
 
232
+ if (initialMessage) {
233
+ yield* _(
234
+ Effect.sync(initialMessage),
235
+ Effect.flatMap(executeEffect),
236
+ Effect.mapError((error) => WorkerError("spawn", error))
237
+ )
238
+ }
239
+
225
240
  return { id, join, execute, executeEffect }
226
241
  }).pipe(Effect.parallelFinalizers)
227
242
  }
@@ -303,6 +318,9 @@ export const makeSerialized = <
303
318
  ...options,
304
319
  transfers(message) {
305
320
  return Transferable.get(message)
321
+ },
322
+ encode(message) {
323
+ return Effect.mapError(Serializable.serialize(message), (error) => WorkerError("encode", error))
306
324
  }
307
325
  })
308
326
  )
@@ -310,8 +328,7 @@ export const makeSerialized = <
310
328
  const parseSuccess = Schema.decode(Serializable.successSchema(message as any))
311
329
  const parseFailure = Schema.decode(Serializable.failureSchema(message as any))
312
330
  return pipe(
313
- Serializable.serialize(message),
314
- Stream.flatMap((message) => backing.execute(message)),
331
+ backing.execute(message),
315
332
  Stream.catchAll((error) => Effect.flatMap(parseFailure(error), Effect.fail)),
316
333
  Stream.mapEffect(parseSuccess)
317
334
  )
@@ -319,14 +336,10 @@ export const makeSerialized = <
319
336
  const executeEffect = <Req extends I>(message: Req) => {
320
337
  const parseSuccess = Schema.decode(Serializable.successSchema(message as any))
321
338
  const parseFailure = Schema.decode(Serializable.failureSchema(message as any))
322
- return pipe(
323
- Serializable.serialize(message),
324
- Effect.flatMap((message) => backing.executeEffect(message)),
325
- Effect.matchEffect({
326
- onFailure: (error) => Effect.flatMap(parseFailure(error), Effect.fail),
327
- onSuccess: parseSuccess
328
- })
329
- )
339
+ return Effect.matchEffect(backing.executeEffect(message), {
340
+ onFailure: (error) => Effect.flatMap(parseFailure(error), Effect.fail),
341
+ onSuccess: parseSuccess
342
+ })
330
343
  }
331
344
  return identity<Worker.SerializedWorker<I>>({
332
345
  id: backing.id,
@@ -28,7 +28,7 @@ export const PlatformRunner = Context.Tag<WorkerRunner.PlatformRunner>(
28
28
  /** @internal */
29
29
  export const make = <I, R, E, O>(
30
30
  process: (request: I) => Stream.Stream<R, E, O> | Effect.Effect<R, E, O>,
31
- options?: WorkerRunner.Runner.Options<O>
31
+ options?: WorkerRunner.Runner.Options<E, O>
32
32
  ) =>
33
33
  Effect.gen(function*(_) {
34
34
  const platform = yield* _(PlatformRunner)
@@ -51,27 +51,46 @@ export const make = <I, R, E, O>(
51
51
  Effect.matchCauseEffect(stream, {
52
52
  onFailure: (cause) =>
53
53
  Either.match(Cause.failureOrCause(cause), {
54
- onLeft: (error) => backing.send([id, 2, error]),
54
+ onLeft: (error) => {
55
+ const transfers = options?.transfers ? options.transfers(error) : undefined
56
+ return pipe(
57
+ options?.encodeError ? options.encodeError(error) : Effect.succeed(error),
58
+ Effect.flatMap((payload) => backing.send([id, 2, payload as any], transfers)),
59
+ Effect.catchAllCause((cause) => backing.send([id, 3, Cause.squash(cause)]))
60
+ )
61
+ },
55
62
  onRight: (cause) => backing.send([id, 3, Cause.squash(cause)])
56
63
  }),
57
64
  onSuccess: (data) => {
58
65
  const transfers = options?.transfers ? options.transfers(data) : undefined
59
- const payload = options?.encode ? options.encode(data) : data
60
- return backing.send([id, 1, payload], transfers)
66
+ return pipe(
67
+ options?.encodeOutput ? options.encodeOutput(data) : Effect.succeed(data),
68
+ Effect.flatMap((payload) => backing.send([id, 0, payload], transfers)),
69
+ Effect.catchAllCause((cause) => backing.send([id, 3, Cause.squash(cause)]))
70
+ )
61
71
  }
62
72
  }) :
63
73
  pipe(
64
74
  stream,
65
- Stream.tap((item) => {
66
- const transfers = options?.transfers ? options.transfers(item) : undefined
67
- const payload = options?.encode ? options.encode(item) : item
68
- return backing.send([id, 0, payload], transfers)
75
+ Stream.tap((data) => {
76
+ const transfers = options?.transfers ? options.transfers(data) : undefined
77
+ return Effect.flatMap(
78
+ options?.encodeOutput ? Effect.orDie(options.encodeOutput(data)) : Effect.succeed(data),
79
+ (payload) => backing.send([id, 0, payload], transfers)
80
+ )
69
81
  }),
70
82
  Stream.runDrain,
71
83
  Effect.matchCauseEffect({
72
84
  onFailure: (cause) =>
73
85
  Either.match(Cause.failureOrCause(cause), {
74
- onLeft: (error) => backing.send([id, 2, error]),
86
+ onLeft: (error) => {
87
+ const transfers = options?.transfers ? options.transfers(error) : undefined
88
+ return pipe(
89
+ options?.encodeError ? options.encodeError(error) : Effect.succeed(error),
90
+ Effect.flatMap((payload) => backing.send([id, 2, payload as any], transfers)),
91
+ Effect.catchAllCause((cause) => backing.send([id, 3, Cause.squash(cause)]))
92
+ )
93
+ },
75
94
  onRight: (cause) => backing.send([id, 3, Cause.squash(cause)])
76
95
  }),
77
96
  onSuccess: () => backing.send([id, 1])