@livestore/utils 0.0.54-dev.26 → 0.0.54-dev.28

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 (122) hide show
  1. package/dist/.tsbuildinfo.json +1 -1
  2. package/dist/Deferred.d.ts.map +1 -1
  3. package/dist/NoopTracer.d.ts.map +1 -1
  4. package/dist/effect/Effect.d.ts.map +1 -1
  5. package/dist/effect/Effect.js +13 -8
  6. package/dist/effect/Effect.js.map +1 -1
  7. package/dist/effect/Scheduler.d.ts +4 -0
  8. package/dist/effect/Scheduler.d.ts.map +1 -0
  9. package/dist/effect/Scheduler.js +10 -0
  10. package/dist/effect/Scheduler.js.map +1 -0
  11. package/dist/effect/Schema/debug-diff.d.ts +13 -0
  12. package/dist/effect/Schema/debug-diff.d.ts.map +1 -0
  13. package/dist/effect/Schema/debug-diff.js +51 -0
  14. package/dist/effect/Schema/debug-diff.js.map +1 -0
  15. package/dist/effect/Schema/debug-diff.test.d.ts +2 -0
  16. package/dist/effect/Schema/debug-diff.test.d.ts.map +1 -0
  17. package/dist/effect/Schema/debug-diff.test.js +91 -0
  18. package/dist/effect/Schema/debug-diff.test.js.map +1 -0
  19. package/dist/effect/{Schema.d.ts → Schema/index.d.ts} +2 -1
  20. package/dist/effect/Schema/index.d.ts.map +1 -0
  21. package/dist/effect/{Schema.js → Schema/index.js} +3 -2
  22. package/dist/effect/Schema/index.js.map +1 -0
  23. package/dist/effect/ServiceContext.d.ts.map +1 -1
  24. package/dist/effect/Stream.d.ts.map +1 -1
  25. package/dist/effect/SubscriptionRef.d.ts.map +1 -1
  26. package/dist/effect/WebLock.d.ts +1 -1
  27. package/dist/effect/WebLock.d.ts.map +1 -1
  28. package/dist/effect/WebLock.js +18 -7
  29. package/dist/effect/WebLock.js.map +1 -1
  30. package/dist/effect/browser-worker-tmp/BrowserWorker.d.ts +21 -0
  31. package/dist/effect/browser-worker-tmp/BrowserWorker.d.ts.map +1 -0
  32. package/dist/effect/browser-worker-tmp/BrowserWorker.js +17 -0
  33. package/dist/effect/browser-worker-tmp/BrowserWorker.js.map +1 -0
  34. package/dist/effect/browser-worker-tmp/BrowserWorkerRunner.d.ts +12 -0
  35. package/dist/effect/browser-worker-tmp/BrowserWorkerRunner.d.ts.map +1 -0
  36. package/dist/effect/browser-worker-tmp/BrowserWorkerRunner.js +8 -0
  37. package/dist/effect/browser-worker-tmp/BrowserWorkerRunner.js.map +1 -0
  38. package/dist/effect/browser-worker-tmp/internal/worker.d.ts +9 -0
  39. package/dist/effect/browser-worker-tmp/internal/worker.d.ts.map +1 -0
  40. package/dist/effect/browser-worker-tmp/internal/worker.js +56 -0
  41. package/dist/effect/browser-worker-tmp/internal/worker.js.map +1 -0
  42. package/dist/effect/browser-worker-tmp/internal/workerRunner.d.ts +5 -0
  43. package/dist/effect/browser-worker-tmp/internal/workerRunner.d.ts.map +1 -0
  44. package/dist/effect/browser-worker-tmp/internal/workerRunner.js +100 -0
  45. package/dist/effect/browser-worker-tmp/internal/workerRunner.js.map +1 -0
  46. package/dist/effect/browser-worker-tmp/port-platform-runner.d.ts +5 -0
  47. package/dist/effect/browser-worker-tmp/port-platform-runner.d.ts.map +1 -0
  48. package/dist/effect/{port-platform-runner.js → browser-worker-tmp/port-platform-runner.js} +3 -3
  49. package/dist/effect/browser-worker-tmp/port-platform-runner.js.map +1 -0
  50. package/dist/effect/index.d.ts +9 -5
  51. package/dist/effect/index.d.ts.map +1 -1
  52. package/dist/effect/index.js +11 -5
  53. package/dist/effect/index.js.map +1 -1
  54. package/dist/effect/platform-worker.d.ts +2 -0
  55. package/dist/effect/platform-worker.d.ts.map +1 -0
  56. package/dist/effect/platform-worker.js +2 -0
  57. package/dist/effect/platform-worker.js.map +1 -0
  58. package/dist/effect/worker-tmp/Worker.d.ts +290 -0
  59. package/dist/effect/worker-tmp/Worker.d.ts.map +1 -0
  60. package/dist/effect/worker-tmp/Worker.js +62 -0
  61. package/dist/effect/worker-tmp/Worker.js.map +1 -0
  62. package/dist/effect/worker-tmp/WorkerError.d.ts +63 -0
  63. package/dist/effect/worker-tmp/WorkerError.d.ts.map +1 -0
  64. package/dist/effect/worker-tmp/WorkerError.js +54 -0
  65. package/dist/effect/worker-tmp/WorkerError.js.map +1 -0
  66. package/dist/effect/worker-tmp/WorkerRunner.d.ts +119 -0
  67. package/dist/effect/worker-tmp/WorkerRunner.d.ts.map +1 -0
  68. package/dist/effect/worker-tmp/WorkerRunner.js +32 -0
  69. package/dist/effect/worker-tmp/WorkerRunner.js.map +1 -0
  70. package/dist/effect/worker-tmp/internal/worker.d.ts +36 -0
  71. package/dist/effect/worker-tmp/internal/worker.d.ts.map +1 -0
  72. package/dist/effect/worker-tmp/internal/worker.js +242 -0
  73. package/dist/effect/worker-tmp/internal/worker.js.map +1 -0
  74. package/dist/effect/worker-tmp/internal/workerError.d.ts +4 -0
  75. package/dist/effect/worker-tmp/internal/workerError.d.ts.map +1 -0
  76. package/dist/effect/worker-tmp/internal/workerError.js +3 -0
  77. package/dist/effect/worker-tmp/internal/workerError.js.map +1 -0
  78. package/dist/effect/worker-tmp/internal/workerRunner.d.ts +21 -0
  79. package/dist/effect/worker-tmp/internal/workerRunner.d.ts.map +1 -0
  80. package/dist/effect/worker-tmp/internal/workerRunner.js +136 -0
  81. package/dist/effect/worker-tmp/internal/workerRunner.js.map +1 -0
  82. package/dist/fast-deep-equal.d.ts +2 -0
  83. package/dist/fast-deep-equal.d.ts.map +1 -0
  84. package/dist/fast-deep-equal.js +79 -0
  85. package/dist/fast-deep-equal.js.map +1 -0
  86. package/dist/guards.d.ts.map +1 -1
  87. package/dist/index.d.ts +2 -1
  88. package/dist/index.d.ts.map +1 -1
  89. package/dist/index.js +13 -1
  90. package/dist/index.js.map +1 -1
  91. package/dist/object/index.d.ts.map +1 -1
  92. package/dist/object/omit.d.ts.map +1 -1
  93. package/dist/object/pick.d.ts +1 -1
  94. package/dist/object/pick.d.ts.map +1 -1
  95. package/dist/promise.d.ts.map +1 -1
  96. package/dist/set.d.ts.map +1 -1
  97. package/package.json +17 -16
  98. package/src/effect/Effect.ts +13 -11
  99. package/src/effect/Scheduler.ts +14 -0
  100. package/src/effect/Schema/debug-diff.test.ts +102 -0
  101. package/src/effect/Schema/debug-diff.ts +59 -0
  102. package/src/effect/{Schema.ts → Schema/index.ts} +2 -1
  103. package/src/effect/WebLock.ts +36 -26
  104. package/src/effect/browser-worker-tmp/BrowserWorker.ts +26 -0
  105. package/src/effect/browser-worker-tmp/BrowserWorkerRunner.ts +14 -0
  106. package/src/effect/browser-worker-tmp/internal/worker.ts +71 -0
  107. package/src/effect/browser-worker-tmp/internal/workerRunner.ts +119 -0
  108. package/src/effect/{port-platform-runner.ts → browser-worker-tmp/port-platform-runner.ts} +4 -3
  109. package/src/effect/index.ts +10 -5
  110. package/src/effect/worker-tmp/Worker.ts +374 -0
  111. package/src/effect/worker-tmp/WorkerError.ts +80 -0
  112. package/src/effect/worker-tmp/WorkerRunner.ts +181 -0
  113. package/src/effect/worker-tmp/internal/worker.ts +415 -0
  114. package/src/effect/worker-tmp/internal/workerError.ts +6 -0
  115. package/src/effect/worker-tmp/internal/workerRunner.ts +236 -0
  116. package/src/fast-deep-equal.ts +72 -0
  117. package/src/index.ts +12 -1
  118. package/dist/effect/Schema.d.ts.map +0 -1
  119. package/dist/effect/Schema.js.map +0 -1
  120. package/dist/effect/port-platform-runner.d.ts +0 -5
  121. package/dist/effect/port-platform-runner.d.ts.map +0 -1
  122. package/dist/effect/port-platform-runner.js.map +0 -1
@@ -0,0 +1,102 @@
1
+ import { Schema } from '@effect/schema'
2
+ import { describe, expect, test } from 'vitest'
3
+
4
+ import type { DiffItem } from './debug-diff.js'
5
+ import { debugDiff } from './debug-diff.js'
6
+
7
+ describe('debug-diff', () => {
8
+ test('simple object', () => {
9
+ const schema = Schema.Struct({
10
+ a: Schema.String,
11
+ b: Schema.Number,
12
+ })
13
+
14
+ const a = { a: 'hello', b: 1 }
15
+ const b = { a: 'world', b: 2 }
16
+
17
+ const diff = debugDiff(schema)(a, b)
18
+ expect(trimAst(diff)).toMatchInlineSnapshot(`
19
+ [
20
+ {
21
+ "a": "hello",
22
+ "b": "world",
23
+ "path": ".a",
24
+ },
25
+ {
26
+ "a": 1,
27
+ "b": 2,
28
+ "path": ".b",
29
+ },
30
+ ]
31
+ `)
32
+ })
33
+
34
+ test('simple object with nested object', () => {
35
+ const schema = Schema.Struct({
36
+ a: Schema.String,
37
+ b: Schema.Struct({
38
+ c: Schema.Number,
39
+ }),
40
+ })
41
+ const a = { a: 'hello', b: { c: 1 } }
42
+ const b = { a: 'world', b: { c: 2 } }
43
+ const diff = debugDiff(schema)(a, b)
44
+ expect(trimAst(diff)).toMatchInlineSnapshot(`
45
+ [
46
+ {
47
+ "a": "hello",
48
+ "b": "world",
49
+ "path": ".a",
50
+ },
51
+ {
52
+ "a": 1,
53
+ "b": 2,
54
+ "path": ".b.c",
55
+ },
56
+ ]
57
+ `)
58
+ })
59
+
60
+ test('union', () => {
61
+ const schema = Schema.Union(Schema.String, Schema.Number)
62
+ const a = 'hello'
63
+ const b = 1
64
+ const diff = debugDiff(schema)(a, b)
65
+ expect(trimAst(diff)).toMatchInlineSnapshot(`
66
+ [
67
+ {
68
+ "a": "hello",
69
+ "b": 1,
70
+ "path": "",
71
+ },
72
+ ]
73
+ `)
74
+ })
75
+
76
+ test('tagged union', () => {
77
+ const schema = Schema.Union(
78
+ Schema.Struct({ _tag: Schema.Literal('a'), a: Schema.String }),
79
+ Schema.Struct({ _tag: Schema.Literal('b'), b: Schema.Number }),
80
+ )
81
+ const a = { _tag: 'a', a: 'hello' } as const
82
+ const b = { _tag: 'b', b: 1 } as const
83
+ const diff = debugDiff(schema)(a, b)
84
+ expect(trimAst(diff)).toMatchInlineSnapshot(`
85
+ [
86
+ {
87
+ "a": {
88
+ "_tag": "a",
89
+ "a": "hello",
90
+ },
91
+ "b": {
92
+ "_tag": "b",
93
+ "b": 1,
94
+ },
95
+ "path": "",
96
+ },
97
+ ]
98
+ `)
99
+ })
100
+ })
101
+
102
+ const trimAst = (diffItems: DiffItem[]) => diffItems.map(({ ast: _ast, ...rest }) => rest)
@@ -0,0 +1,59 @@
1
+ import type { Schema } from '@effect/schema'
2
+ import { AST, Equivalence } from '@effect/schema'
3
+
4
+ export type DiffItem = {
5
+ path: string
6
+ a: any
7
+ b: any
8
+ ast: AST.AST
9
+ }
10
+
11
+ /**
12
+ * Diffs two values for a given schema and traverses downwards and returns a list of differences.
13
+ */
14
+ export const debugDiff =
15
+ <A, I, R>(base: Schema.Schema<A, I, R>) =>
16
+ (a: A, b: A): DiffItem[] => {
17
+ const bag = [] as DiffItem[]
18
+ debugDiffImpl(base.ast, a, b, '', bag)
19
+ return bag
20
+ }
21
+
22
+ const debugDiffImpl = (ast: AST.AST, a: any, b: any, path: string, bag: DiffItem[]) => {
23
+ const eq = Equivalence.make({ ast } as any)
24
+ if (eq(a, b) === false) {
25
+ // bag.push({ path, a, b, ast })
26
+
27
+ if (AST.isUnion(ast)) {
28
+ if (isTaggedUnion(ast)) {
29
+ bag.push({ path, a, b, ast })
30
+ return
31
+ } else {
32
+ for (const type of ast.types) {
33
+ try {
34
+ debugDiffImpl(type, a, b, path, bag)
35
+ return
36
+ } catch {}
37
+ }
38
+ }
39
+ } else if (AST.isTypeLiteral(ast)) {
40
+ const props = AST.getPropertySignatures(ast)
41
+ for (const prop of props) {
42
+ debugDiffImpl(prop.type, a[prop.name], b[prop.name], `${path}.${prop.name.toString()}`, bag)
43
+ }
44
+ } else {
45
+ // debugger
46
+ bag.push({ path, a, b, ast })
47
+ }
48
+ }
49
+ }
50
+
51
+ const isTaggedUnion = (ast: AST.AST) => {
52
+ if (AST.isUnion(ast)) {
53
+ return ast.types.every((type) => {
54
+ if (AST.isTypeLiteral(type) === false) return false
55
+ const props = AST.getPropertySignatures(type)
56
+ return props.some((prop) => prop.name.toString() === '_tag')
57
+ })
58
+ }
59
+ }
@@ -4,9 +4,10 @@ import type { ParseOptions } from '@effect/schema/AST'
4
4
  import type { ParseError } from '@effect/schema/ParseResult'
5
5
  import { Effect, Hash } from 'effect'
6
6
 
7
- import { objectToString } from '../misc.js'
7
+ import { objectToString } from '../../misc.js'
8
8
 
9
9
  export * from '@effect/schema/Schema'
10
+ export * from './debug-diff.js'
10
11
 
11
12
  // NOTE this is a temporary workaround until Effect schema has a better way to hash schemas
12
13
  // https://github.com/Effect-TS/effect/issues/2719
@@ -13,37 +13,35 @@ export const withLock =
13
13
  options?: Omit<LockOptions, 'signal'>
14
14
  }) =>
15
15
  <Ctx, E, A>(eff: Effect.Effect<A, E, Ctx>): Effect.Effect<A | void, E | E2, Ctx> =>
16
- Effect.gen(function* ($) {
17
- const runtime = yield* $(Effect.runtime<Ctx>())
16
+ Effect.gen(function* () {
17
+ const runtime = yield* Effect.runtime<Ctx>()
18
18
 
19
- const exit = yield* $(
20
- Effect.tryPromise<Exit.Exit<A, E>, E | E2>({
21
- try: (signal) => {
22
- if (signal.aborted) return 'aborted' as never
19
+ const exit = yield* Effect.tryPromise<Exit.Exit<A, E>, E | E2>({
20
+ try: (signal) => {
21
+ if (signal.aborted) return 'aborted' as never
23
22
 
24
- // NOTE The 'signal' and 'ifAvailable' options cannot be used together.
25
- const requestOptions = options?.ifAvailable === true ? options : { ...options, signal }
26
- return navigator.locks.request(lockName, requestOptions, async (lock) => {
27
- if (lock === null) {
28
- if (onTaken) {
29
- const exit = await Runtime.runPromiseExit(runtime)(onTaken)
30
- if (exit._tag === 'Failure') {
31
- return exit
32
- }
23
+ // NOTE The 'signal' and 'ifAvailable' options cannot be used together.
24
+ const requestOptions = options?.ifAvailable === true ? options : { ...options, signal }
25
+ return navigator.locks.request(lockName, requestOptions, async (lock) => {
26
+ if (lock === null) {
27
+ if (onTaken) {
28
+ const exit = await Runtime.runPromiseExit(runtime)(onTaken)
29
+ if (exit._tag === 'Failure') {
30
+ return exit
33
31
  }
34
- return
35
32
  }
33
+ return
34
+ }
36
35
 
37
- // TODO also propagate Effect interruption to the execution
38
- return Runtime.runPromiseExit(runtime)(eff)
39
- })
40
- },
41
- catch: (err) => err as any as E,
42
- }),
43
- )
36
+ // TODO also propagate Effect interruption to the execution
37
+ return Runtime.runPromiseExit(runtime)(eff)
38
+ })
39
+ },
40
+ catch: (err) => err as any as E,
41
+ })
44
42
 
45
43
  if (exit._tag === 'Failure') {
46
- return yield* $(Effect.failCause(exit.cause))
44
+ return yield* Effect.failCause(exit.cause)
47
45
  } else {
48
46
  return exit.value
49
47
  }
@@ -73,13 +71,25 @@ export const waitForDeferredLock = (deferred: Deferred.Deferred<void>, lockName:
73
71
  })
74
72
 
75
73
  export const tryGetDeferredLock = (deferred: Deferred.Deferred<void>, lockName: string) =>
76
- Effect.async<boolean>((cb) => {
74
+ Effect.async<boolean>((cb, signal) => {
77
75
  navigator.locks.request(lockName, { mode: 'exclusive', ifAvailable: true }, (lock) => {
78
76
  cb(Effect.succeed(lock !== null))
79
77
 
80
78
  // the code below is still running
81
79
 
80
+ const abortPromise = new Promise<void>((resolve) => {
81
+ signal.addEventListener('abort', () => {
82
+ resolve()
83
+ })
84
+ })
85
+
82
86
  // holding lock until deferred is resolved
83
- return Effect.runPromise(Deferred.await(deferred))
87
+ return Promise.race([
88
+ Effect.runPromise(Deferred.await(deferred)),
89
+ // .finally(() =>
90
+ // console.log('[@livestore/utils:WebLock] tryGetDeferredLock. finally', lockName),
91
+ // ),
92
+ abortPromise,
93
+ ])
84
94
  })
85
95
  })
@@ -0,0 +1,26 @@
1
+ /**
2
+ * @since 1.0.0
3
+ */
4
+ import type * as Layer from 'effect/Layer'
5
+
6
+ import type * as Worker from '../worker-tmp/Worker.js'
7
+ import * as internal from './internal/worker.js'
8
+ /**
9
+ * @since 1.0.0
10
+ * @category layers
11
+ */
12
+ export const layerManager: Layer.Layer<Worker.WorkerManager> = internal.layerManager
13
+
14
+ /**
15
+ * @since 1.0.0
16
+ * @category layers
17
+ */
18
+ export const layerWorker: Layer.Layer<Worker.PlatformWorker> = internal.layerWorker
19
+
20
+ /**
21
+ * @since 1.0.0
22
+ * @category layers
23
+ */
24
+ export const layer: (
25
+ spawn: (id: number) => Worker | SharedWorker | MessagePort,
26
+ ) => Layer.Layer<Worker.WorkerManager | Worker.Spawner, never, never> = internal.layer
@@ -0,0 +1,14 @@
1
+ /**
2
+ * @since 1.0.0
3
+ */
4
+ import type * as Layer from 'effect/Layer'
5
+
6
+ import type * as Runner from '../worker-tmp/WorkerRunner.js'
7
+ import * as internal from './internal/workerRunner.js'
8
+
9
+ /**
10
+ * @since 1.0.0
11
+ * @category layers
12
+ */
13
+ export const layer: Layer.Layer<Runner.PlatformRunner> = internal.layer
14
+ export { layerMessagePort } from './port-platform-runner.js'
@@ -0,0 +1,71 @@
1
+ /* eslint-disable prefer-arrow/prefer-arrow-functions */
2
+ import * as Deferred from 'effect/Deferred'
3
+ import * as Effect from 'effect/Effect'
4
+ import * as Layer from 'effect/Layer'
5
+ import * as Queue from 'effect/Queue'
6
+
7
+ import * as Worker from '../../worker-tmp/Worker.js'
8
+ import { WorkerError } from '../../worker-tmp/WorkerError.js'
9
+
10
+ const platformWorkerImpl = Worker.PlatformWorker.of({
11
+ [Worker.PlatformWorkerTypeId]: Worker.PlatformWorkerTypeId,
12
+ spawn<I, O>(worker_: unknown) {
13
+ return Effect.gen(function* (_) {
14
+ const worker = worker_ as globalThis.SharedWorker | globalThis.Worker | MessagePort
15
+ let port: globalThis.Worker | MessagePort
16
+ if ('port' in worker) {
17
+ port = worker.port
18
+ } else {
19
+ port = worker
20
+ }
21
+
22
+ yield* _(Effect.addFinalizer(() => Effect.sync(() => port.postMessage([1]))))
23
+
24
+ const queue = yield* _(Queue.unbounded<Worker.BackingWorker.Message<O>>())
25
+ const latch = yield* Deferred.make<void>()
26
+
27
+ const fiber = yield* _(
28
+ Effect.async<never, WorkerError, never>((resume) => {
29
+ function onMessage(event: MessageEvent) {
30
+ queue.unsafeOffer((event as MessageEvent).data)
31
+ }
32
+ function onError(event: ErrorEvent) {
33
+ resume(new WorkerError({ reason: 'unknown', error: event.error ?? event.message }))
34
+ }
35
+ port.addEventListener('message', onMessage as any)
36
+ port.addEventListener('error', onError as any)
37
+ Deferred.unsafeDone(latch, Effect.void)
38
+ return Effect.sync(() => {
39
+ port.removeEventListener('message', onMessage as any)
40
+ port.removeEventListener('error', onError as any)
41
+ })
42
+ }),
43
+ Effect.interruptible,
44
+ Effect.forkScoped,
45
+ )
46
+ yield* Deferred.await(latch)
47
+
48
+ if ('start' in port) {
49
+ port.start()
50
+ }
51
+
52
+ const send = (message: I, transfers?: ReadonlyArray<unknown>) =>
53
+ Effect.try({
54
+ try: () => port.postMessage([0, message], transfers as any),
55
+ catch: (error) => new WorkerError({ reason: 'send', error }),
56
+ })
57
+
58
+ return { fiber, queue, send }
59
+ })
60
+ },
61
+ })
62
+
63
+ /** @internal */
64
+ export const layerWorker = Layer.succeed(Worker.PlatformWorker, platformWorkerImpl)
65
+
66
+ /** @internal */
67
+ export const layerManager = Layer.provide(Worker.layerManager, layerWorker)
68
+
69
+ /** @internal */
70
+ export const layer = (spawn: (id: number) => globalThis.Worker | globalThis.SharedWorker | MessagePort) =>
71
+ Layer.merge(layerManager, Worker.layerSpawner(spawn))
@@ -0,0 +1,119 @@
1
+ /// <reference lib="webworker" />
2
+ /* eslint-disable prefer-arrow/prefer-arrow-functions */
3
+ import * as Cause from 'effect/Cause'
4
+ import * as Effect from 'effect/Effect'
5
+ import * as FiberSet from 'effect/FiberSet'
6
+ import { globalValue } from 'effect/GlobalValue'
7
+ import * as Layer from 'effect/Layer'
8
+ import * as Queue from 'effect/Queue'
9
+ import * as Schedule from 'effect/Schedule'
10
+
11
+ import { WorkerError } from '../../worker-tmp/WorkerError.js'
12
+ import * as WorkerRunner from '../../worker-tmp/WorkerRunner.js'
13
+
14
+ const cachedPorts = globalValue('@effect/platform-browser/Worker/cachedPorts', () => new Set<MessagePort>())
15
+ function globalHandleConnect(event: MessageEvent) {
16
+ cachedPorts.add((event as MessageEvent).ports[0]!)
17
+ }
18
+ if (typeof self !== 'undefined' && 'onconnect' in self) {
19
+ // @ts-expect-error TODO
20
+ self.addEventListener('connect', globalHandleConnect)
21
+ }
22
+
23
+ const platformRunnerImpl = WorkerRunner.PlatformRunner.of({
24
+ [WorkerRunner.PlatformRunnerTypeId]: WorkerRunner.PlatformRunnerTypeId,
25
+ start<I, O>(shutdown: Effect.Effect<void>) {
26
+ return Effect.gen(function* () {
27
+ let currentPortId = 0
28
+
29
+ yield* Effect.addFinalizer(() => Effect.sync(() => self.close()))
30
+
31
+ const queue = yield* Queue.unbounded<readonly [portId: number, message: I]>()
32
+ const runFork = yield* FiberSet.makeRuntime<never>()
33
+ const ports = new Map<number, MessagePort>()
34
+ const send = (portId: number, message: O, transfer?: ReadonlyArray<unknown>) =>
35
+ Effect.sync(() => {
36
+ ports.get(portId)?.postMessage([1, message], {
37
+ transfer: transfer as any,
38
+ })
39
+ })
40
+
41
+ function handlePort(port: MessagePort, sharedWorker: boolean) {
42
+ const portId = currentPortId++
43
+ ports.set(portId, port)
44
+
45
+ Effect.async<never, WorkerError, never>((resume) => {
46
+ function onMessage(event: MessageEvent) {
47
+ const message = (event as MessageEvent).data as WorkerRunner.BackingRunner.Message<I>
48
+ if (message[0] === 0) {
49
+ queue.unsafeOffer([portId, message[1]])
50
+ } else if (sharedWorker && ports.size > 1) {
51
+ resume(Effect.interrupt)
52
+ } else {
53
+ Effect.runFork(shutdown)
54
+ }
55
+ }
56
+ function onMessageError(error: ErrorEvent) {
57
+ resume(new WorkerError({ reason: 'decode', error: error.error ?? error.message }))
58
+ }
59
+ function onError(error: ErrorEvent) {
60
+ resume(new WorkerError({ reason: 'unknown', error: error.error ?? error.message }))
61
+ }
62
+ port.addEventListener('message', onMessage as any)
63
+ port.addEventListener('messageerror', onMessageError as any)
64
+ port.addEventListener('error', onError as any)
65
+
66
+ // ready
67
+ if ('start' in port) {
68
+ port.start()
69
+ }
70
+ port.postMessage([0])
71
+
72
+ return Effect.sync(() => {
73
+ port.removeEventListener('message', onMessage as any)
74
+ port.removeEventListener('messageerror', onMessageError as any)
75
+ port.removeEventListener('error', onError as any)
76
+ })
77
+ }).pipe(
78
+ Effect.tapErrorCause((cause) => (Cause.isInterruptedOnly(cause) ? Effect.void : Effect.logDebug(cause))),
79
+ Effect.retry(Schedule.forever),
80
+ Effect.annotateLogs({
81
+ package: '@effect/platform-browser',
82
+ module: 'WorkerRunner',
83
+ }),
84
+ Effect.ensuring(
85
+ Effect.sync(() => {
86
+ ports.delete(portId)
87
+ }),
88
+ ),
89
+ Effect.interruptible,
90
+ runFork,
91
+ )
92
+ }
93
+
94
+ if ('onconnect' in self) {
95
+ // @ts-expect-error TODO
96
+ self.addEventListener('connect', (event: MessageEvent) => {
97
+ const port = (event as MessageEvent).ports[0]
98
+ handlePort(port!, true)
99
+ })
100
+ yield* Effect.addFinalizer(() =>
101
+ Effect.sync(() => {
102
+ ;(self as any).addEventListener('connect', globalHandleConnect)
103
+ }),
104
+ )
105
+ for (const port of cachedPorts) {
106
+ handlePort(port, true)
107
+ }
108
+ cachedPorts.clear()
109
+ } else {
110
+ handlePort(self as any, false)
111
+ }
112
+
113
+ return { queue, send }
114
+ })
115
+ },
116
+ })
117
+
118
+ /** @internal */
119
+ export const layer = Layer.succeed(WorkerRunner.PlatformRunner, platformRunnerImpl)
@@ -1,5 +1,3 @@
1
- import { WorkerError } from '@effect/platform/WorkerError'
2
- import * as Runner from '@effect/platform/WorkerRunner'
3
1
  import { Deferred } from 'effect'
4
2
  import * as Cause from 'effect/Cause'
5
3
  import * as Effect from 'effect/Effect'
@@ -7,6 +5,9 @@ import * as Layer from 'effect/Layer'
7
5
  import * as Queue from 'effect/Queue'
8
6
  import * as Schedule from 'effect/Schedule'
9
7
 
8
+ import { WorkerError } from '../worker-tmp/WorkerError.js'
9
+ import * as Runner from '../worker-tmp/WorkerRunner.js'
10
+
10
11
  const platformRunnerImpl = (port: MessagePort) =>
11
12
  Runner.PlatformRunner.of({
12
13
  [Runner.PlatformRunnerTypeId]: Runner.PlatformRunnerTypeId,
@@ -70,4 +71,4 @@ const platformRunnerImpl = (port: MessagePort) =>
70
71
  })
71
72
 
72
73
  /** @internal */
73
- export const layer = (port: MessagePort) => Layer.succeed(Runner.PlatformRunner, platformRunnerImpl(port))
74
+ export const layerMessagePort = (port: MessagePort) => Layer.succeed(Runner.PlatformRunner, platformRunnerImpl(port))
@@ -12,7 +12,6 @@ export {
12
12
  Exit,
13
13
  Cause,
14
14
  Runtime,
15
- Scheduler,
16
15
  FiberRef,
17
16
  FiberRefs,
18
17
  FiberRefsPatch,
@@ -62,15 +61,21 @@ export {
62
61
  JSONSchema,
63
62
  ParseResult,
64
63
  } from '@effect/schema'
65
- export * as Schema from './Schema.js'
64
+ export * as Schema from './Schema/index.js'
66
65
  export * as OtelTracer from '@effect/opentelemetry/Tracer'
67
66
 
68
- export { Transferable, FileSystem, Worker, WorkerError, WorkerRunner, Terminal, HttpServer } from '@effect/platform'
69
- export { BrowserWorker, BrowserWorkerRunner } from '@effect/platform-browser'
70
- export * as PortPlatformRunner from './port-platform-runner.js'
67
+ // export { Transferable, FileSystem, Worker, WorkerError, WorkerRunner, Terminal, HttpServer } from '@effect/platform'
68
+ // export { BrowserWorker, BrowserWorkerRunner } from '@effect/platform-browser'
69
+ export { Transferable, FileSystem, Terminal, HttpServer } from '@effect/platform'
70
+ export * as Worker from './worker-tmp/Worker.js'
71
+ export * as WorkerError from './worker-tmp/WorkerError.js'
72
+ export * as WorkerRunner from './worker-tmp/WorkerRunner.js'
73
+ export * as BrowserWorker from './browser-worker-tmp/BrowserWorker.js'
74
+ export * as BrowserWorkerRunner from './browser-worker-tmp/BrowserWorkerRunner.js'
71
75
 
72
76
  export * as Effect from './Effect.js'
73
77
  export * as Schedule from './Schedule.js'
78
+ export * as Scheduler from './Scheduler.js'
74
79
  export * from './Error.js'
75
80
  export * as ServiceContext from './ServiceContext.js'
76
81
  export * as WebLock from './WebLock.js'