@effect/platform 0.69.13 → 0.69.14

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.
package/src/Socket.ts CHANGED
@@ -189,46 +189,40 @@ export const toChannelMap = <IE, A>(
189
189
  void,
190
190
  unknown
191
191
  > =>
192
- Effect.scope.pipe(
193
- Effect.bindTo("scope"),
194
- Effect.bind("mailbox", () => Mailbox.make<A, SocketError | IE>()),
195
- Effect.bind("writeScope", ({ scope }) => Scope.fork(scope, ExecutionStrategy.sequential)),
196
- Effect.bind("write", ({ writeScope }) => Scope.extend(self.writer, writeScope)),
197
- Effect.let(
198
- "input",
199
- (
200
- { mailbox, write, writeScope }
201
- ): AsyncProducer.AsyncInputProducer<IE, Chunk.Chunk<Uint8Array | string | CloseEvent>, unknown> => ({
202
- awaitRead: () => Effect.void,
203
- emit(chunk) {
204
- return Effect.catchAllCause(
205
- Effect.forEach(chunk, write, { discard: true }),
206
- (cause) => mailbox.failCause(cause)
207
- )
208
- },
209
- error(error) {
210
- return Effect.zipRight(
211
- Scope.close(writeScope, Exit.void),
212
- mailbox.failCause(error)
213
- )
214
- },
215
- done() {
216
- return Scope.close(writeScope, Exit.void)
217
- }
218
- })
219
- ),
220
- Effect.tap(({ mailbox, scope }) =>
221
- self.runRaw((data) => {
222
- mailbox.unsafeOffer(f(data))
223
- }).pipe(
224
- Mailbox.into(mailbox),
225
- Effect.forkIn(scope),
226
- Effect.interruptible
227
- )
228
- ),
229
- Effect.map(({ input, mailbox }) => Channel.embedInput(Mailbox.toChannel(mailbox), input)),
230
- Channel.unwrapScoped
231
- )
192
+ Effect.gen(function*() {
193
+ const scope = yield* Effect.scope
194
+ const mailbox = yield* Mailbox.make<A, SocketError | IE>()
195
+ const writeScope = yield* Scope.fork(scope, ExecutionStrategy.sequential)
196
+ const write = yield* Scope.extend(self.writer, writeScope)
197
+ const input: AsyncProducer.AsyncInputProducer<IE, Chunk.Chunk<Uint8Array | string | CloseEvent>, unknown> = {
198
+ awaitRead: () => Effect.void,
199
+ emit(chunk) {
200
+ return Effect.catchAllCause(
201
+ Effect.forEach(chunk, write, { discard: true }),
202
+ (cause) => mailbox.failCause(cause)
203
+ )
204
+ },
205
+ error(error) {
206
+ return Effect.zipRight(
207
+ Scope.close(writeScope, Exit.void),
208
+ mailbox.failCause(error)
209
+ )
210
+ },
211
+ done() {
212
+ return Scope.close(writeScope, Exit.void)
213
+ }
214
+ }
215
+
216
+ yield* self.runRaw((data) => {
217
+ mailbox.unsafeOffer(f(data))
218
+ }).pipe(
219
+ Mailbox.into(mailbox),
220
+ Effect.forkIn(scope),
221
+ Effect.interruptible
222
+ )
223
+
224
+ return Channel.embedInput(Mailbox.toChannel(mailbox), input)
225
+ }).pipe(Channel.unwrapScoped)
232
226
 
233
227
  /**
234
228
  * @since 1.0.0
@@ -393,139 +387,132 @@ export const makeWebSocket = (url: string | Effect.Effect<string>, options?: {
393
387
  * @since 1.0.0
394
388
  * @category constructors
395
389
  */
396
- export const fromWebSocket = <R>(
397
- acquire: Effect.Effect<globalThis.WebSocket, SocketError, R>,
390
+ export const fromWebSocket = <RO>(
391
+ acquire: Effect.Effect<globalThis.WebSocket, SocketError, RO>,
398
392
  options?: {
399
393
  readonly closeCodeIsError?: (code: number) => boolean
400
394
  readonly openTimeout?: DurationInput
401
395
  }
402
- ): Effect.Effect<Socket, never, Exclude<R, Scope.Scope>> =>
403
- Effect.withFiberRuntime<Socket, never, Exclude<R, Scope.Scope>>((fiber) =>
404
- Effect.map(
405
- Queue.dropping<Uint8Array | string | CloseEvent>(fiber.getFiberRef(currentSendQueueCapacity)),
406
- (sendQueue) => {
407
- const acquireContext = fiber.getFiberRef(FiberRef.currentContext) as Context.Context<R>
408
- const closeCodeIsError = options?.closeCodeIsError ?? defaultCloseCodeIsError
409
- const runRaw = <_, E, R>(handler: (_: string | Uint8Array) => Effect.Effect<_, E, R> | void) =>
410
- acquire.pipe(
411
- Effect.bindTo("ws"),
412
- Effect.bind("fiberSet", () => FiberSet.make<any, E | SocketError>()),
413
- Effect.bind("run", ({ fiberSet, ws }) =>
414
- Effect.provideService(FiberSet.runtime(fiberSet)<R>(), WebSocket, ws)),
415
- Effect.tap(({ fiberSet, run, ws }) => {
416
- let open = false
417
-
418
- function onMessage(event: MessageEvent) {
419
- if (event.data instanceof Blob) {
420
- return Effect.promise(() =>
421
- event.data.arrayBuffer() as Promise<ArrayBuffer>
422
- ).pipe(
423
- Effect.andThen((buffer) => handler(new Uint8Array(buffer))),
424
- run
425
- )
426
- }
427
- const result = handler(event.data)
428
- if (Effect.isEffect(result)) {
429
- run(result)
430
- }
431
- }
432
- function onError(cause: Event) {
433
- ws.removeEventListener("message", onMessage)
434
- ws.removeEventListener("close", onClose)
435
- Deferred.unsafeDone(
436
- fiberSet.deferred,
437
- Effect.fail(new SocketGenericError({ reason: open ? "Read" : "Open", cause }))
438
- )
439
- }
440
- function onClose(event: globalThis.CloseEvent) {
441
- ws.removeEventListener("message", onMessage)
442
- ws.removeEventListener("error", onError)
443
- Deferred.unsafeDone(
444
- fiberSet.deferred,
445
- Effect.fail(
446
- new SocketCloseError({
447
- reason: "Close",
448
- code: event.code,
449
- closeReason: event.reason
450
- })
451
- )
452
- )
453
- }
454
-
455
- ws.addEventListener("close", onClose, { once: true })
456
- ws.addEventListener("error", onError, { once: true })
457
- ws.addEventListener("message", onMessage)
458
-
459
- if (ws.readyState !== 1) {
460
- const openDeferred = Deferred.unsafeMake<void>(fiber.id())
461
- ws.addEventListener("open", () => {
462
- open = true
463
- Deferred.unsafeDone(openDeferred, Effect.void)
464
- }, { once: true })
465
- return Deferred.await(openDeferred).pipe(
466
- Effect.timeoutFail({
467
- duration: options?.openTimeout ?? 10000,
468
- onTimeout: () =>
469
- new SocketGenericError({ reason: "OpenTimeout", cause: "timeout waiting for \"open\"" })
470
- }),
471
- Effect.raceFirst(FiberSet.join(fiberSet))
472
- )
473
- }
474
- open = true
475
- return Effect.void
476
- }),
477
- Effect.tap(({ fiberSet, ws }) =>
478
- Queue.take(sendQueue).pipe(
479
- Effect.tap((chunk) =>
480
- isCloseEvent(chunk) ?
481
- Effect.failSync(() => {
482
- ws.close(chunk.code, chunk.reason)
483
- return new SocketCloseError({
484
- reason: "Close",
485
- code: chunk.code,
486
- closeReason: chunk.reason
487
- })
488
- }) :
489
- Effect.try({
490
- try: () => ws.send(chunk),
491
- catch: (cause) => new SocketGenericError({ reason: "Write", cause })
492
- })
493
- ),
494
- Effect.forever,
495
- FiberSet.run(fiberSet)
396
+ ): Effect.Effect<Socket, never, Exclude<RO, Scope.Scope>> =>
397
+ Effect.withFiberRuntime<Socket, never, Exclude<RO, Scope.Scope>>((fiber) =>
398
+ Effect.gen(function*() {
399
+ const sendQueue = yield* Queue.dropping<Uint8Array | string | CloseEvent>(
400
+ fiber.getFiberRef(currentSendQueueCapacity)
401
+ )
402
+ const acquireContext = fiber.currentContext as Context.Context<RO>
403
+ const closeCodeIsError = options?.closeCodeIsError ?? defaultCloseCodeIsError
404
+
405
+ const runRaw = <_, E, R>(handler: (_: string | Uint8Array) => Effect.Effect<_, E, R> | void) =>
406
+ Effect.gen(function*() {
407
+ const fiberSet = yield* FiberSet.make<any, E | SocketError>()
408
+ const ws = yield* acquire
409
+ const run = yield* Effect.provideService(FiberSet.runtime(fiberSet)<R>(), WebSocket, ws)
410
+ let open = false
411
+
412
+ function onMessage(event: MessageEvent) {
413
+ if (event.data instanceof Blob) {
414
+ return Effect.promise(() => event.data.arrayBuffer() as Promise<ArrayBuffer>).pipe(
415
+ Effect.andThen((buffer) => handler(new Uint8Array(buffer))),
416
+ run
496
417
  )
497
- ),
498
- Effect.tap(({ fiberSet }) =>
499
- Effect.catchIf(
500
- FiberSet.join(fiberSet),
501
- SocketCloseError.isClean((_) => !closeCodeIsError(_)),
502
- (_) => Effect.void
418
+ }
419
+ const result = handler(event.data)
420
+ if (Effect.isEffect(result)) {
421
+ run(result)
422
+ }
423
+ }
424
+ function onError(cause: Event) {
425
+ ws.removeEventListener("message", onMessage)
426
+ ws.removeEventListener("close", onClose)
427
+ Deferred.unsafeDone(
428
+ fiberSet.deferred,
429
+ Effect.fail(new SocketGenericError({ reason: open ? "Read" : "Open", cause }))
430
+ )
431
+ }
432
+ function onClose(event: globalThis.CloseEvent) {
433
+ ws.removeEventListener("message", onMessage)
434
+ ws.removeEventListener("error", onError)
435
+ Deferred.unsafeDone(
436
+ fiberSet.deferred,
437
+ Effect.fail(
438
+ new SocketCloseError({
439
+ reason: "Close",
440
+ code: event.code,
441
+ closeReason: event.reason
442
+ })
503
443
  )
444
+ )
445
+ }
446
+
447
+ ws.addEventListener("close", onClose, { once: true })
448
+ ws.addEventListener("error", onError, { once: true })
449
+ ws.addEventListener("message", onMessage)
450
+
451
+ if (ws.readyState !== 1) {
452
+ const openDeferred = Deferred.unsafeMake<void>(fiber.id())
453
+ ws.addEventListener("open", () => {
454
+ open = true
455
+ Deferred.unsafeDone(openDeferred, Effect.void)
456
+ }, { once: true })
457
+ yield* Deferred.await(openDeferred).pipe(
458
+ Effect.timeoutFail({
459
+ duration: options?.openTimeout ?? 10000,
460
+ onTimeout: () =>
461
+ new SocketGenericError({ reason: "OpenTimeout", cause: "timeout waiting for \"open\"" })
462
+ }),
463
+ Effect.raceFirst(FiberSet.join(fiberSet))
464
+ )
465
+ }
466
+ open = true
467
+ yield* Queue.take(sendQueue).pipe(
468
+ Effect.tap((chunk) =>
469
+ isCloseEvent(chunk) ?
470
+ Effect.failSync(() => {
471
+ ws.close(chunk.code, chunk.reason)
472
+ return new SocketCloseError({
473
+ reason: "Close",
474
+ code: chunk.code,
475
+ closeReason: chunk.reason
476
+ })
477
+ }) :
478
+ Effect.try({
479
+ try: () => ws.send(chunk),
480
+ catch: (cause) => new SocketGenericError({ reason: "Write", cause })
481
+ })
504
482
  ),
505
- Effect.mapInputContext((input: Context.Context<R | Scope.Scope>) => Context.merge(acquireContext, input)),
506
- Effect.scoped,
507
- Effect.interruptible
483
+ Effect.forever,
484
+ FiberSet.run(fiberSet)
508
485
  )
509
-
510
- const encoder = new TextEncoder()
511
- const run = <_, E, R>(handler: (_: Uint8Array) => Effect.Effect<_, E, R> | void) =>
512
- runRaw((data) =>
513
- typeof data === "string"
514
- ? handler(encoder.encode(data))
515
- : handler(data)
486
+ return yield* FiberSet.join(fiberSet).pipe(
487
+ Effect.catchIf(
488
+ SocketCloseError.isClean((_) => !closeCodeIsError(_)),
489
+ (_) => Effect.void
490
+ )
516
491
  )
492
+ }).pipe(
493
+ Effect.mapInputContext((input: Context.Context<R | Scope.Scope>) => Context.merge(acquireContext, input)),
494
+ Effect.scoped,
495
+ Effect.interruptible
496
+ )
517
497
 
518
- const write = (chunk: Uint8Array | string | CloseEvent) => Queue.offer(sendQueue, chunk)
519
- const writer = Effect.succeed(write)
498
+ const encoder = new TextEncoder()
499
+ const run = <_, E, R>(handler: (_: Uint8Array) => Effect.Effect<_, E, R> | void) =>
500
+ runRaw((data) =>
501
+ typeof data === "string"
502
+ ? handler(encoder.encode(data))
503
+ : handler(data)
504
+ )
520
505
 
521
- return Socket.of({
522
- [TypeId]: TypeId,
523
- run,
524
- runRaw,
525
- writer
526
- })
527
- }
528
- )
506
+ const write = (chunk: Uint8Array | string | CloseEvent) => Queue.offer(sendQueue, chunk)
507
+ const writer = Effect.succeed(write)
508
+
509
+ return Socket.of({
510
+ [TypeId]: TypeId,
511
+ run,
512
+ runRaw,
513
+ writer
514
+ })
515
+ })
529
516
  )
530
517
 
531
518
  /**
@@ -586,115 +573,110 @@ export interface InputTransformStream {
586
573
  */
587
574
  export const fromTransformStream = <R>(acquire: Effect.Effect<InputTransformStream, SocketError, R>, options?: {
588
575
  readonly closeCodeIsError?: (code: number) => boolean
589
- }): Effect.Effect<Socket, never, Exclude<R, Scope.Scope>> => {
590
- const EOF = Symbol()
591
- return Effect.withFiberRuntime<Socket, never, Exclude<R, Scope.Scope>>((fiber) =>
592
- Effect.map(
593
- Queue.dropping<Uint8Array | string | CloseEvent | typeof EOF>(fiber.getFiberRef(currentSendQueueCapacity)),
594
- (sendQueue) => {
595
- const acquireContext = fiber.getFiberRef(FiberRef.currentContext) as Context.Context<R>
596
- const closeCodeIsError = options?.closeCodeIsError ?? defaultCloseCodeIsError
597
- const runRaw = <_, E, R>(handler: (_: string | Uint8Array) => Effect.Effect<_, E, R> | void) =>
598
- acquire.pipe(
599
- Effect.bindTo("stream"),
600
- Effect.bind("reader", ({ stream }) =>
601
- Effect.acquireRelease(
602
- Effect.sync(() => stream.readable.getReader()),
603
- (reader) =>
604
- Effect.promise(() => reader.cancel()).pipe(
605
- Effect.tap(() => {
606
- reader.releaseLock()
576
+ }): Effect.Effect<Socket, never, Exclude<R, Scope.Scope>> =>
577
+ Effect.withFiberRuntime<Socket, never, Exclude<R, Scope.Scope>>((fiber) =>
578
+ Effect.gen(function*() {
579
+ const EOF = Symbol()
580
+ const sendQueue = yield* Queue.dropping<Uint8Array | string | CloseEvent | typeof EOF>(
581
+ fiber.getFiberRef(currentSendQueueCapacity)
582
+ )
583
+ const acquireContext = fiber.currentContext as Context.Context<R>
584
+ const closeCodeIsError = options?.closeCodeIsError ?? defaultCloseCodeIsError
585
+ const runRaw = <_, E, R>(handler: (_: string | Uint8Array) => Effect.Effect<_, E, R> | void) =>
586
+ Effect.gen(function*() {
587
+ const stream = yield* acquire
588
+ const reader = yield* Effect.acquireRelease(
589
+ Effect.sync(() => stream.readable.getReader()),
590
+ (reader) =>
591
+ Effect.promise(() => reader.cancel()).pipe(
592
+ Effect.tap(() => {
593
+ reader.releaseLock()
594
+ })
595
+ )
596
+ )
597
+ const writer = yield* Effect.acquireRelease(
598
+ Effect.sync(() => stream.writable.getWriter()),
599
+ (reader) => Effect.sync(() => reader.releaseLock())
600
+ )
601
+ const fiberSet = yield* FiberSet.make<any, E | SocketError>()
602
+ const encoder = new TextEncoder()
603
+ yield* Queue.take(sendQueue).pipe(
604
+ Effect.tap((chunk) => {
605
+ if (
606
+ chunk === EOF ||
607
+ isCloseEvent(chunk)
608
+ ) {
609
+ return Effect.zipRight(
610
+ Effect.promise(() => writer.close()),
611
+ chunk === EOF ? Effect.interrupt : Effect.fail(
612
+ new SocketCloseError({
613
+ reason: "Close",
614
+ code: chunk.code,
615
+ closeReason: chunk.reason
607
616
  })
608
617
  )
609
- )),
610
- Effect.bind("writer", ({ stream }) =>
611
- Effect.acquireRelease(
612
- Effect.sync(() => stream.writable.getWriter()),
613
- (reader) => Effect.sync(() => reader.releaseLock())
614
- )),
615
- Effect.bind("fiberSet", () => FiberSet.make<any, E | SocketError>()),
616
- Effect.tap(({ fiberSet, writer }) => {
617
- const encoder = new TextEncoder()
618
- return Queue.take(sendQueue).pipe(
619
- Effect.tap((chunk) => {
620
- if (
621
- chunk === EOF ||
622
- isCloseEvent(chunk)
623
- ) {
624
- return Effect.zipRight(
625
- Effect.promise(() => writer.close()),
626
- chunk === EOF ? Effect.interrupt : Effect.fail(
627
- new SocketCloseError({
628
- reason: "Close",
629
- code: chunk.code,
630
- closeReason: chunk.reason
631
- })
632
- )
633
- )
618
+ )
619
+ }
620
+ return Effect.try({
621
+ try: () => {
622
+ if (typeof chunk === "string") {
623
+ writer.write(encoder.encode(chunk))
624
+ } else {
625
+ writer.write(chunk)
634
626
  }
635
- return Effect.try({
636
- try: () => {
637
- if (typeof chunk === "string") {
638
- writer.write(encoder.encode(chunk))
639
- } else {
640
- writer.write(chunk)
641
- }
642
- },
643
- catch: (cause) => new SocketGenericError({ reason: "Write", cause })
644
- })
645
- }),
646
- Effect.forever,
647
- FiberSet.run(fiberSet)
648
- )
627
+ },
628
+ catch: (cause) => new SocketGenericError({ reason: "Write", cause })
629
+ })
649
630
  }),
650
- Effect.tap(({ fiberSet, reader }) =>
651
- Effect.tryPromise({
652
- try: () => reader.read(),
653
- catch: (cause) => new SocketGenericError({ reason: "Read", cause })
654
- }).pipe(
655
- Effect.tap((result) => {
656
- if (result.done) {
657
- return Effect.fail(new SocketCloseError({ reason: "Close", code: 1000 }))
658
- }
659
- return handler(result.value)
660
- }),
661
- Effect.forever,
662
- FiberSet.run(fiberSet)
663
- )
664
- ),
665
- Effect.tap(({ fiberSet }) =>
666
- Effect.catchIf(
667
- FiberSet.join(fiberSet),
668
- SocketCloseError.isClean((_) => !closeCodeIsError(_)),
669
- (_) => Effect.void
670
- )
671
- ),
672
- Effect.mapInputContext((input: Context.Context<R | Scope.Scope>) => Context.merge(acquireContext, input)),
673
- Effect.scoped,
674
- Effect.interruptible
631
+ Effect.forever,
632
+ FiberSet.run(fiberSet)
675
633
  )
676
634
 
677
- const encoder = new TextEncoder()
678
- const run = <_, E, R>(handler: (_: Uint8Array) => Effect.Effect<_, E, R> | void) =>
679
- runRaw((data) =>
680
- typeof data === "string"
681
- ? handler(encoder.encode(data))
682
- : handler(data)
635
+ yield* Effect.tryPromise({
636
+ try: () => reader.read(),
637
+ catch: (cause) => new SocketGenericError({ reason: "Read", cause })
638
+ }).pipe(
639
+ Effect.tap((result) => {
640
+ if (result.done) {
641
+ return Effect.fail(new SocketCloseError({ reason: "Close", code: 1000 }))
642
+ }
643
+ return handler(result.value)
644
+ }),
645
+ Effect.forever,
646
+ FiberSet.run(fiberSet)
683
647
  )
684
648
 
685
- const write = (chunk: Uint8Array | string | CloseEvent) => Queue.offer(sendQueue, chunk)
686
- const writer = Effect.acquireRelease(
687
- Effect.succeed(write),
688
- () => Queue.offer(sendQueue, EOF)
649
+ return yield* FiberSet.join(fiberSet).pipe(
650
+ Effect.catchIf(
651
+ SocketCloseError.isClean((_) => !closeCodeIsError(_)),
652
+ (_) => Effect.void
653
+ )
654
+ )
655
+ }).pipe(
656
+ Effect.mapInputContext((input: Context.Context<R | Scope.Scope>) => Context.merge(acquireContext, input)),
657
+ Effect.scoped,
658
+ Effect.interruptible
689
659
  )
690
660
 
691
- return Socket.of({
692
- [TypeId]: TypeId,
693
- run,
694
- runRaw,
695
- writer
696
- })
697
- }
698
- )
661
+ const encoder = new TextEncoder()
662
+ const run = <_, E, R>(handler: (_: Uint8Array) => Effect.Effect<_, E, R> | void) =>
663
+ runRaw((data) =>
664
+ typeof data === "string"
665
+ ? handler(encoder.encode(data))
666
+ : handler(data)
667
+ )
668
+
669
+ const write = (chunk: Uint8Array | string | CloseEvent) => Queue.offer(sendQueue, chunk)
670
+ const writer = Effect.acquireRelease(
671
+ Effect.succeed(write),
672
+ () => Queue.offer(sendQueue, EOF)
673
+ )
674
+
675
+ return Socket.of({
676
+ [TypeId]: TypeId,
677
+ run,
678
+ runRaw,
679
+ writer
680
+ })
681
+ })
699
682
  )
700
- }