@livestore/utils 0.4.0-dev.22 → 0.4.0-dev.23
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/dist/.tsbuildinfo +1 -0
- package/dist/NoopTracer.d.ts.map +1 -1
- package/dist/NoopTracer.js +11 -3
- package/dist/NoopTracer.js.map +1 -1
- package/dist/binary.js +1 -1
- package/dist/binary.js.map +1 -1
- package/dist/browser/Opfs/Opfs.d.ts +3 -3
- package/dist/browser/Opfs/Opfs.d.ts.map +1 -1
- package/dist/browser/Opfs/Opfs.js +1 -1
- package/dist/browser/Opfs/Opfs.js.map +1 -1
- package/dist/browser/Opfs/debug-utils.d.ts.map +1 -1
- package/dist/browser/Opfs/debug-utils.js +2 -2
- package/dist/browser/Opfs/debug-utils.js.map +1 -1
- package/dist/browser/Opfs/utils.d.ts.map +1 -1
- package/dist/browser/Opfs/utils.js +10 -10
- package/dist/browser/Opfs/utils.js.map +1 -1
- package/dist/browser/QuotaExceededError.d.ts.map +1 -1
- package/dist/browser/QuotaExceededError.js.map +1 -1
- package/dist/browser/WebChannelBrowser.d.ts +1 -1
- package/dist/browser/WebChannelBrowser.d.ts.map +1 -1
- package/dist/browser/WebError.d.ts +50 -54
- package/dist/browser/WebError.d.ts.map +1 -1
- package/dist/browser/WebError.js +25 -23
- package/dist/browser/WebError.js.map +1 -1
- package/dist/browser/WebLock.js +9 -9
- package/dist/browser/WebLock.js.map +1 -1
- package/dist/browser/detect.js +6 -6
- package/dist/browser/detect.js.map +1 -1
- package/dist/cuid/cuid.browser.js +1 -1
- package/dist/cuid/cuid.browser.js.map +1 -1
- package/dist/cuid/cuid.node.js +1 -1
- package/dist/cuid/cuid.node.js.map +1 -1
- package/dist/effect/BucketQueue.d.ts +1 -1
- package/dist/effect/BucketQueue.d.ts.map +1 -1
- package/dist/effect/BucketQueue.js.map +1 -1
- package/dist/effect/Debug.d.ts +2 -2
- package/dist/effect/Debug.d.ts.map +1 -1
- package/dist/effect/Debug.js +69 -61
- package/dist/effect/Debug.js.map +1 -1
- package/dist/effect/Effect.d.ts +72 -12
- package/dist/effect/Effect.d.ts.map +1 -1
- package/dist/effect/Effect.js +96 -12
- package/dist/effect/Effect.js.map +1 -1
- package/dist/effect/Error.js +1 -1
- package/dist/effect/Error.js.map +1 -1
- package/dist/effect/Logger.js +2 -2
- package/dist/effect/Logger.js.map +1 -1
- package/dist/effect/RpcClient.d.ts.map +1 -1
- package/dist/effect/RpcClient.js +4 -4
- package/dist/effect/RpcClient.js.map +1 -1
- package/dist/effect/Schema/debug-diff.js +5 -4
- package/dist/effect/Schema/debug-diff.js.map +1 -1
- package/dist/effect/Schema/index.d.ts +5 -3
- package/dist/effect/Schema/index.d.ts.map +1 -1
- package/dist/effect/Schema/index.js +1 -1
- package/dist/effect/Schema/index.js.map +1 -1
- package/dist/effect/ServiceContext.js +6 -6
- package/dist/effect/ServiceContext.js.map +1 -1
- package/dist/effect/Stream.test.js +3 -3
- package/dist/effect/Stream.test.js.map +1 -1
- package/dist/effect/SubscriptionRef.d.ts +4 -4
- package/dist/effect/SubscriptionRef.d.ts.map +1 -1
- package/dist/effect/WebChannel/WebChannel.d.ts +2 -2
- package/dist/effect/WebChannel/WebChannel.d.ts.map +1 -1
- package/dist/effect/WebChannel/WebChannel.js +4 -4
- package/dist/effect/WebChannel/WebChannel.js.map +1 -1
- package/dist/effect/WebChannel/broadcastChannelWithAck.js +4 -4
- package/dist/effect/WebChannel/broadcastChannelWithAck.js.map +1 -1
- package/dist/effect/WebChannel/common.d.ts +1 -1
- package/dist/effect/WebChannel/common.d.ts.map +1 -1
- package/dist/effect/WebChannel/common.js +2 -2
- package/dist/effect/WebChannel/common.js.map +1 -1
- package/dist/effect/WebSocket.js +3 -3
- package/dist/effect/WebSocket.js.map +1 -1
- package/dist/effect/mod.d.ts +1 -1
- package/dist/effect/mod.d.ts.map +1 -1
- package/dist/effect/mod.js +1 -1
- package/dist/effect/mod.js.map +1 -1
- package/dist/effect/spanEvent.d.ts +12 -0
- package/dist/effect/spanEvent.d.ts.map +1 -0
- package/dist/effect/spanEvent.js +12 -0
- package/dist/effect/spanEvent.js.map +1 -0
- package/dist/effect/spanEvent.test.d.ts +2 -0
- package/dist/effect/spanEvent.test.d.ts.map +1 -0
- package/dist/effect/spanEvent.test.js +82 -0
- package/dist/effect/spanEvent.test.js.map +1 -0
- package/dist/env.d.ts.map +1 -1
- package/dist/env.js +1 -1
- package/dist/env.js.map +1 -1
- package/dist/fast-deep-equal.js +9 -9
- package/dist/fast-deep-equal.js.map +1 -1
- package/dist/global.d.ts.map +1 -1
- package/dist/global.js.map +1 -1
- package/dist/misc.d.ts +9 -1
- package/dist/misc.d.ts.map +1 -1
- package/dist/misc.js +11 -3
- package/dist/misc.js.map +1 -1
- package/dist/mod.d.ts +1 -1
- package/dist/mod.d.ts.map +1 -1
- package/dist/mod.js +12 -12
- package/dist/mod.js.map +1 -1
- package/dist/node/ChildProcessRunner/ChildProcessRunner.d.ts.map +1 -1
- package/dist/node/ChildProcessRunner/ChildProcessRunner.js +15 -9
- package/dist/node/ChildProcessRunner/ChildProcessRunner.js.map +1 -1
- package/dist/node/ChildProcessRunner/ChildProcessRunnerTest/ChildProcessRunner.test.d.ts +8 -0
- package/dist/node/ChildProcessRunner/ChildProcessRunnerTest/ChildProcessRunner.test.d.ts.map +1 -1
- package/dist/node/ChildProcessRunner/ChildProcessRunnerTest/ChildProcessRunner.test.js +10 -6
- package/dist/node/ChildProcessRunner/ChildProcessRunnerTest/ChildProcessRunner.test.js.map +1 -1
- package/dist/node/ChildProcessRunner/ChildProcessRunnerTest/serializedWorker.js +2 -2
- package/dist/node/ChildProcessRunner/ChildProcessRunnerTest/serializedWorker.js.map +1 -1
- package/dist/node/ChildProcessRunner/ChildProcessWorker.d.ts.map +1 -1
- package/dist/node/ChildProcessRunner/ChildProcessWorker.js +4 -4
- package/dist/node/ChildProcessRunner/ChildProcessWorker.js.map +1 -1
- package/dist/node/mod.d.ts.map +1 -1
- package/dist/node/mod.js +1 -1
- package/dist/node/mod.js.map +1 -1
- package/dist/object/index.d.ts.map +1 -1
- package/dist/object/index.js.map +1 -1
- package/dist/object/omit.js +1 -1
- package/dist/object/omit.js.map +1 -1
- package/dist/object/stringify-object.js +2 -2
- package/dist/object/stringify-object.js.map +1 -1
- package/dist/object/stringify-object.test.js.map +1 -1
- package/dist/qr.js +11 -11
- package/dist/qr.js.map +1 -1
- package/dist/set.js +1 -1
- package/dist/set.js.map +1 -1
- package/dist/time.js +1 -1
- package/dist/time.js.map +1 -1
- package/package.json +65 -51
- package/src/NoopTracer.ts +17 -8
- package/src/binary.ts +1 -1
- package/src/browser/Opfs/Opfs.ts +12 -4
- package/src/browser/Opfs/debug-utils.ts +8 -6
- package/src/browser/Opfs/utils.ts +11 -10
- package/src/browser/QuotaExceededError.ts +0 -2
- package/src/browser/WebChannelBrowser.ts +1 -1
- package/src/browser/WebError.ts +100 -86
- package/src/browser/WebLock.ts +15 -15
- package/src/browser/detect.ts +6 -6
- package/src/cuid/cuid.browser.ts +1 -1
- package/src/cuid/cuid.node.ts +1 -1
- package/src/effect/BucketQueue.ts +1 -1
- package/src/effect/Debug.ts +67 -55
- package/src/effect/Effect.ts +118 -36
- package/src/effect/Error.ts +1 -1
- package/src/effect/Logger.ts +2 -2
- package/src/effect/RpcClient.ts +7 -6
- package/src/effect/Schema/debug-diff.ts +6 -5
- package/src/effect/Schema/index.ts +9 -6
- package/src/effect/ServiceContext.ts +6 -6
- package/src/effect/Stream.test.ts +5 -4
- package/src/effect/SubscriptionRef.ts +5 -5
- package/src/effect/WebChannel/WebChannel.ts +6 -6
- package/src/effect/WebChannel/broadcastChannelWithAck.ts +4 -4
- package/src/effect/WebChannel/common.ts +4 -4
- package/src/effect/WebSocket.ts +3 -3
- package/src/effect/mod.ts +1 -0
- package/src/effect/spanEvent.test.ts +95 -0
- package/src/effect/spanEvent.ts +15 -0
- package/src/env.ts +2 -1
- package/src/fast-deep-equal.ts +9 -9
- package/src/global.ts +0 -2
- package/src/misc.ts +12 -4
- package/src/mod.ts +11 -11
- package/src/node/ChildProcessRunner/ChildProcessRunner.ts +23 -10
- package/src/node/ChildProcessRunner/ChildProcessRunnerTest/ChildProcessRunner.test.ts +11 -7
- package/src/node/ChildProcessRunner/ChildProcessRunnerTest/serializedWorker.ts +10 -11
- package/src/node/ChildProcessRunner/ChildProcessWorker.ts +5 -4
- package/src/node/mod.ts +3 -1
- package/src/object/index.ts +1 -1
- package/src/object/omit.ts +1 -1
- package/src/object/stringify-object.test.ts +1 -0
- package/src/object/stringify-object.ts +2 -2
- package/src/qr.ts +11 -11
- package/src/set.ts +1 -1
- package/src/time.ts +1 -1
- package/dist/.tsbuildinfo.json +0 -1
package/src/effect/RpcClient.ts
CHANGED
|
@@ -6,6 +6,7 @@ import { Protocol } from '@effect/rpc/RpcClient'
|
|
|
6
6
|
import { constPing, type FromServerEncoded } from '@effect/rpc/RpcMessage'
|
|
7
7
|
import { Cause, Deferred, Effect, Layer, Option, Schedule, type Scope } from 'effect'
|
|
8
8
|
import { constVoid, identity } from 'effect/Function'
|
|
9
|
+
|
|
9
10
|
import * as SubscriptionRef from './SubscriptionRef.ts'
|
|
10
11
|
|
|
11
12
|
// This is based on `makeProtocolSocket` / `layerProtocolSocket` from `@effect/rpc` in order to:
|
|
@@ -119,8 +120,8 @@ export const makeProtocolSocketWithIsConnected = (options: {
|
|
|
119
120
|
|
|
120
121
|
const error = Cause.failureOption(cause)
|
|
121
122
|
if (
|
|
122
|
-
options?.retryTransientErrors &&
|
|
123
|
-
Option.isSome(error) &&
|
|
123
|
+
options?.retryTransientErrors !== undefined &&
|
|
124
|
+
Option.isSome(error) === true &&
|
|
124
125
|
(error.value.reason === 'Open' || error.value.reason === 'OpenTimeout')
|
|
125
126
|
) {
|
|
126
127
|
return
|
|
@@ -137,7 +138,7 @@ export const makeProtocolSocketWithIsConnected = (options: {
|
|
|
137
138
|
}),
|
|
138
139
|
),
|
|
139
140
|
// CHANGED: make configurable via schedule
|
|
140
|
-
options?.retryTransientErrors ? Effect.retry(options.retryTransientErrors) : identity,
|
|
141
|
+
options?.retryTransientErrors !== undefined ? Effect.retry(options.retryTransientErrors) : identity,
|
|
141
142
|
Effect.annotateLogs({
|
|
142
143
|
module: 'RpcClient',
|
|
143
144
|
method: 'makeProtocolSocket',
|
|
@@ -171,7 +172,7 @@ const makePinger = Effect.fnUntraced(function* <A, E, R>(
|
|
|
171
172
|
pingSchedule: Schedule.Schedule<unknown> = Schedule.spaced(10000).pipe(Schedule.addDelay(() => 5000)),
|
|
172
173
|
) {
|
|
173
174
|
// CHANGED: add manual ping deferreds
|
|
174
|
-
const manualPingDeferreds = new Set<Deferred.Deferred<void
|
|
175
|
+
const manualPingDeferreds = new Set<Deferred.Deferred<void>>()
|
|
175
176
|
|
|
176
177
|
let recievedPong = true
|
|
177
178
|
const latch = Effect.unsafeMakeLatch()
|
|
@@ -188,7 +189,7 @@ const makePinger = Effect.fnUntraced(function* <A, E, R>(
|
|
|
188
189
|
}
|
|
189
190
|
yield* Effect.suspend(() => {
|
|
190
191
|
// Starting new ping
|
|
191
|
-
if (
|
|
192
|
+
if (recievedPong === false) return latch.open
|
|
192
193
|
recievedPong = false
|
|
193
194
|
return writePing
|
|
194
195
|
}).pipe(
|
|
@@ -202,7 +203,7 @@ const makePinger = Effect.fnUntraced(function* <A, E, R>(
|
|
|
202
203
|
|
|
203
204
|
// CHANGED: add manual ping
|
|
204
205
|
const ping = Effect.gen(function* () {
|
|
205
|
-
const deferred = yield* Deferred.make<void
|
|
206
|
+
const deferred = yield* Deferred.make<void>()
|
|
206
207
|
manualPingDeferreds.add(deferred)
|
|
207
208
|
yield* deferred
|
|
208
209
|
manualPingDeferreds.delete(deferred)
|
|
@@ -23,8 +23,8 @@ const debugDiffImpl = (ast: SchemaAST.AST, a: any, b: any, path: string, bag: Di
|
|
|
23
23
|
if (eq(a, b) === false) {
|
|
24
24
|
// bag.push({ path, a, b, ast })
|
|
25
25
|
|
|
26
|
-
if (SchemaAST.isUnion(ast)) {
|
|
27
|
-
if (isTaggedUnion(ast)) {
|
|
26
|
+
if (SchemaAST.isUnion(ast) === true) {
|
|
27
|
+
if (isTaggedUnion(ast) === true) {
|
|
28
28
|
bag.push({ path, a, b, ast })
|
|
29
29
|
return
|
|
30
30
|
} else {
|
|
@@ -35,7 +35,7 @@ const debugDiffImpl = (ast: SchemaAST.AST, a: any, b: any, path: string, bag: Di
|
|
|
35
35
|
} catch {}
|
|
36
36
|
}
|
|
37
37
|
}
|
|
38
|
-
} else if (SchemaAST.isTypeLiteral(ast)) {
|
|
38
|
+
} else if (SchemaAST.isTypeLiteral(ast) === true) {
|
|
39
39
|
const props = SchemaAST.getPropertySignatures(ast)
|
|
40
40
|
for (const prop of props) {
|
|
41
41
|
debugDiffImpl(prop.type, a[prop.name], b[prop.name], `${path}.${prop.name.toString()}`, bag)
|
|
@@ -47,12 +47,13 @@ const debugDiffImpl = (ast: SchemaAST.AST, a: any, b: any, path: string, bag: Di
|
|
|
47
47
|
}
|
|
48
48
|
}
|
|
49
49
|
|
|
50
|
-
const isTaggedUnion = (ast: SchemaAST.AST) => {
|
|
51
|
-
if (SchemaAST.isUnion(ast)) {
|
|
50
|
+
const isTaggedUnion = (ast: SchemaAST.AST): boolean => {
|
|
51
|
+
if (SchemaAST.isUnion(ast) === true) {
|
|
52
52
|
return ast.types.every((type) => {
|
|
53
53
|
if (SchemaAST.isTypeLiteral(type) === false) return false
|
|
54
54
|
const props = SchemaAST.getPropertySignatures(type)
|
|
55
55
|
return props.some((prop) => prop.name.toString() === '_tag')
|
|
56
56
|
})
|
|
57
57
|
}
|
|
58
|
+
return false
|
|
58
59
|
}
|
|
@@ -24,7 +24,7 @@ export const hash = (schema: Schema.Schema<any>) => {
|
|
|
24
24
|
}
|
|
25
25
|
|
|
26
26
|
const resolveStructAst = (ast: SchemaAST.AST): SchemaAST.AST => {
|
|
27
|
-
if (SchemaAST.isTransformation(ast)) {
|
|
27
|
+
if (SchemaAST.isTransformation(ast) === true) {
|
|
28
28
|
return resolveStructAst(ast.from)
|
|
29
29
|
}
|
|
30
30
|
|
|
@@ -38,9 +38,12 @@ export const getResolvedPropertySignatures = (
|
|
|
38
38
|
return SchemaAST.getPropertySignatures(resolvedAst)
|
|
39
39
|
}
|
|
40
40
|
|
|
41
|
+
/** Objects that can be transferred between contexts (workers, etc.) */
|
|
42
|
+
type TransferableObject = ArrayBuffer | MessagePort
|
|
43
|
+
|
|
41
44
|
export const encodeWithTransferables =
|
|
42
|
-
<A, I, R>(schema: Schema.Schema<A, I, R>, options?: ParseOptions
|
|
43
|
-
(a: A, overrideOptions?: ParseOptions
|
|
45
|
+
<A, I, R>(schema: Schema.Schema<A, I, R>, options?: ParseOptions) =>
|
|
46
|
+
(a: A, overrideOptions?: ParseOptions): Effect.Effect<[I, TransferableObject[]], ParseError, R> =>
|
|
44
47
|
Effect.gen(function* () {
|
|
45
48
|
const collector = yield* Transferable.makeCollector
|
|
46
49
|
|
|
@@ -48,11 +51,11 @@ export const encodeWithTransferables =
|
|
|
48
51
|
Effect.provideService(Transferable.Collector, collector),
|
|
49
52
|
)
|
|
50
53
|
|
|
51
|
-
return [encoded, collector.unsafeRead() as
|
|
54
|
+
return [encoded, collector.unsafeRead() as TransferableObject[]]
|
|
52
55
|
})
|
|
53
56
|
|
|
54
57
|
export const decodeSyncDebug: <A, I>(
|
|
55
|
-
schema: Schema.Schema<A, I
|
|
58
|
+
schema: Schema.Schema<A, I>,
|
|
56
59
|
options?: SchemaAST.ParseOptions,
|
|
57
60
|
) => (i: I, overrideOptions?: SchemaAST.ParseOptions) => A = (schema, options) => (input, overrideOptions) => {
|
|
58
61
|
const res = Schema.decodeEither(schema, options)(input, overrideOptions)
|
|
@@ -64,7 +67,7 @@ export const decodeSyncDebug: <A, I>(
|
|
|
64
67
|
}
|
|
65
68
|
|
|
66
69
|
export const encodeSyncDebug: <A, I>(
|
|
67
|
-
schema: Schema.Schema<A, I
|
|
70
|
+
schema: Schema.Schema<A, I>,
|
|
68
71
|
options?: SchemaAST.ParseOptions,
|
|
69
72
|
) => (a: A, overrideOptions?: SchemaAST.ParseOptions) => I = (schema, options) => (input, overrideOptions) => {
|
|
70
73
|
const res = Schema.encodeEither(schema, options)(input, overrideOptions)
|
|
@@ -24,13 +24,13 @@ export const make = <TStaticData, Ctx>(
|
|
|
24
24
|
close: Effect.Effect<void> = Effect.dieMessage('close not implemented'),
|
|
25
25
|
): ServiceContext<Ctx, TStaticData> => {
|
|
26
26
|
return {
|
|
27
|
-
provide: (self) => Effect.provide(runtime)
|
|
28
|
-
runWithErrorLog: <E, A>(self: Effect.Effect<A, E, Ctx>) => runWithErrorLog(Effect.provide(runtime)
|
|
29
|
-
runSync: <E, A>(self: Effect.Effect<A, E, Ctx>) => Effect.runSync(Effect.provide(runtime)
|
|
27
|
+
provide: (self) => self.pipe(Effect.provide(runtime)),
|
|
28
|
+
runWithErrorLog: <E, A>(self: Effect.Effect<A, E, Ctx>) => runWithErrorLog(self.pipe(Effect.provide(runtime))),
|
|
29
|
+
runSync: <E, A>(self: Effect.Effect<A, E, Ctx>) => Effect.runSync(self.pipe(Effect.provide(runtime))),
|
|
30
30
|
runPromiseWithErrorLog: <E, A>(self: Effect.Effect<A, E, Ctx>) =>
|
|
31
|
-
runPromiseWithErrorLog(Effect.provide(runtime)
|
|
32
|
-
runPromiseExit: <E, A>(self: Effect.Effect<A, E, Ctx>) => Effect.runPromiseExit(Effect.provide(runtime)
|
|
33
|
-
runPromise: <E, A>(self: Effect.Effect<A, E, Ctx>) => Effect.runPromise(Effect.provide(runtime)
|
|
31
|
+
runPromiseWithErrorLog(self.pipe(Effect.provide(runtime))),
|
|
32
|
+
runPromiseExit: <E, A>(self: Effect.Effect<A, E, Ctx>) => Effect.runPromiseExit(self.pipe(Effect.provide(runtime))),
|
|
33
|
+
runPromise: <E, A>(self: Effect.Effect<A, E, Ctx>) => Effect.runPromise(self.pipe(Effect.provide(runtime))),
|
|
34
34
|
withRuntime: (fn) => fn(runtime),
|
|
35
35
|
close: close,
|
|
36
36
|
closePromise: () => Effect.runPromise(close),
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { Effect, Option, Stream } from 'effect'
|
|
2
2
|
import { describe, expect, it } from 'vitest'
|
|
3
|
+
|
|
3
4
|
import { concatWithLastElement, runCollectReadonlyArray } from './Stream.ts'
|
|
4
5
|
|
|
5
6
|
describe('concatWithLastElement', () => {
|
|
@@ -9,7 +10,7 @@ describe('concatWithLastElement', () => {
|
|
|
9
10
|
lastElement.pipe(
|
|
10
11
|
Option.match({
|
|
11
12
|
onNone: () => Stream.make('no-previous'),
|
|
12
|
-
onSome: (last) => Stream.make(`last-was-${last}`, 'continuing'),
|
|
13
|
+
onSome: (last) => Stream.make(`last-was-${String(last)}`, 'continuing'),
|
|
13
14
|
}),
|
|
14
15
|
),
|
|
15
16
|
)
|
|
@@ -24,7 +25,7 @@ describe('concatWithLastElement', () => {
|
|
|
24
25
|
lastElement.pipe(
|
|
25
26
|
Option.match({
|
|
26
27
|
onNone: () => Stream.make('no-previous-element'),
|
|
27
|
-
onSome: (last) => Stream.make(`last-was-${last}`),
|
|
28
|
+
onSome: (last) => Stream.make(`last-was-${String(last)}`),
|
|
28
29
|
}),
|
|
29
30
|
),
|
|
30
31
|
)
|
|
@@ -39,7 +40,7 @@ describe('concatWithLastElement', () => {
|
|
|
39
40
|
lastElement.pipe(
|
|
40
41
|
Option.match({
|
|
41
42
|
onNone: () => Stream.make('unexpected'),
|
|
42
|
-
onSome: (last) => Stream.make(`after-${last}`),
|
|
43
|
+
onSome: (last) => Stream.make(`after-${String(last)}`),
|
|
43
44
|
}),
|
|
44
45
|
),
|
|
45
46
|
)
|
|
@@ -83,7 +84,7 @@ describe('concatWithLastElement', () => {
|
|
|
83
84
|
const result = concatWithLastElement(stream1, (lastElement) =>
|
|
84
85
|
lastElement.pipe(
|
|
85
86
|
Option.match({
|
|
86
|
-
onNone: () => Stream.make('no-number') as Stream.Stream<number | string
|
|
87
|
+
onNone: () => Stream.make('no-number') as Stream.Stream<number | string>,
|
|
87
88
|
onSome: (last) => Stream.make(last * 10, last * 100),
|
|
88
89
|
}),
|
|
89
90
|
),
|
|
@@ -5,17 +5,17 @@ import type { Predicate, Refinement } from 'effect/Predicate'
|
|
|
5
5
|
export * from 'effect/SubscriptionRef'
|
|
6
6
|
|
|
7
7
|
export const waitUntil: {
|
|
8
|
-
|
|
8
|
+
<A, B extends A>(
|
|
9
9
|
refinement: Refinement<NoInfer<A>, B>,
|
|
10
|
-
): (sref: SubscriptionRef.SubscriptionRef<A>) => Effect.Effect<B
|
|
10
|
+
): (sref: SubscriptionRef.SubscriptionRef<A>) => Effect.Effect<B>
|
|
11
11
|
<A, B extends A>(
|
|
12
12
|
predicate: Predicate<B>,
|
|
13
|
-
): (sref: SubscriptionRef.SubscriptionRef<A>) => Effect.Effect<A
|
|
13
|
+
): (sref: SubscriptionRef.SubscriptionRef<A>) => Effect.Effect<A>
|
|
14
14
|
<A, B extends A>(
|
|
15
15
|
sref: SubscriptionRef.SubscriptionRef<A>,
|
|
16
16
|
refinement: Refinement<NoInfer<A>, B>,
|
|
17
|
-
): Effect.Effect<B
|
|
18
|
-
<A, B extends A>(sref: SubscriptionRef.SubscriptionRef<A>, predicate: Predicate<B>): Effect.Effect<A
|
|
17
|
+
): Effect.Effect<B>
|
|
18
|
+
<A, B extends A>(sref: SubscriptionRef.SubscriptionRef<A>, predicate: Predicate<B>): Effect.Effect<A>
|
|
19
19
|
} = dual(2, <A>(sref: SubscriptionRef.SubscriptionRef<A>, predicate: (a: A) => boolean) =>
|
|
20
20
|
pipe(sref.changes, Stream.filter(predicate), Stream.take(1), Stream.runCollect, Effect.map(Chunk.unsafeHead)),
|
|
21
21
|
)
|
|
@@ -41,7 +41,7 @@ export const noopChannel = <MsgListen, MsgSend>(): Effect.Effect<WebChannel<MsgL
|
|
|
41
41
|
export const messagePortChannel: <MsgListen, MsgSend, MsgListenEncoded, MsgSendEncoded>(args: {
|
|
42
42
|
port: MessagePort
|
|
43
43
|
schema: InputSchema<MsgListen, MsgSend, MsgListenEncoded, MsgSendEncoded>
|
|
44
|
-
debugId?: string | number
|
|
44
|
+
debugId?: string | number | undefined
|
|
45
45
|
}) => Effect.Effect<WebChannel<MsgListen, MsgSend>, never, Scope.Scope> = ({ port, schema: inputSchema, debugId }) =>
|
|
46
46
|
Effect.scopeWithCloseable((scope) =>
|
|
47
47
|
Effect.gen(function* () {
|
|
@@ -125,7 +125,7 @@ export const sameThreadChannel = <MsgListen, MsgSend, MsgListenEncoded, MsgSendE
|
|
|
125
125
|
export const messagePortChannelWithAck: <MsgListen, MsgSend, MsgListenEncoded, MsgSendEncoded>(args: {
|
|
126
126
|
port: MessagePort
|
|
127
127
|
schema: InputSchema<MsgListen, MsgSend, MsgListenEncoded, MsgSendEncoded>
|
|
128
|
-
debugId?: string | number
|
|
128
|
+
debugId?: string | number | undefined
|
|
129
129
|
}) => Effect.Effect<WebChannel<MsgListen, MsgSend>, never, Scope.Scope> = ({ port, schema: inputSchema, debugId }) =>
|
|
130
130
|
Effect.scopeWithCloseable((scope) =>
|
|
131
131
|
Effect.gen(function* () {
|
|
@@ -191,7 +191,7 @@ export const messagePortChannelWithAck: <MsgListen, MsgSend, MsgListenEncoded, M
|
|
|
191
191
|
yield* Deferred.succeed(requestAckMap.get(msg.right.reqId)!, void 0)
|
|
192
192
|
} else if (msg.right._tag === 'ChannelRequest') {
|
|
193
193
|
debugInfo.listenTotal++
|
|
194
|
-
port.postMessage(Schema.
|
|
194
|
+
port.postMessage(yield* Schema.encode(ChannelMessage)({ _tag: 'ChannelRequestAck', reqId: msg.right.id }))
|
|
195
195
|
}
|
|
196
196
|
}
|
|
197
197
|
}),
|
|
@@ -311,10 +311,10 @@ export const toOpenChannel = <MsgListen, MsgSend>(
|
|
|
311
311
|
|
|
312
312
|
yield* channel.listen.pipe(
|
|
313
313
|
// TODO implement this on the "chunk" level for better performance
|
|
314
|
-
options?.heartbeat
|
|
314
|
+
options?.heartbeat !== undefined
|
|
315
315
|
? Stream.filterEffect(
|
|
316
316
|
Effect.fn(function* (msg) {
|
|
317
|
-
if (msg._tag === 'Right' && Schema.is(WebChannelHeartbeat)(msg.right)) {
|
|
317
|
+
if (msg._tag === 'Right' && Schema.is(WebChannelHeartbeat)(msg.right) === true) {
|
|
318
318
|
if (msg.right._tag === 'WebChannel.Ping') {
|
|
319
319
|
yield* heartbeatChannel.send(WebChannelPong.make({ requestId: msg.right.requestId }))
|
|
320
320
|
} else {
|
|
@@ -336,7 +336,7 @@ export const toOpenChannel = <MsgListen, MsgSend>(
|
|
|
336
336
|
Effect.forkScoped,
|
|
337
337
|
)
|
|
338
338
|
|
|
339
|
-
if (options?.heartbeat) {
|
|
339
|
+
if (options?.heartbeat !== undefined) {
|
|
340
340
|
const { interval, timeout } = options.heartbeat
|
|
341
341
|
yield* Effect.gen(function* () {
|
|
342
342
|
while (true) {
|
|
@@ -69,7 +69,7 @@ export const broadcastChannelWithAck = <MsgListen, MsgSend, MsgListenEncoded, Ms
|
|
|
69
69
|
peerIdRef.current = data.from
|
|
70
70
|
postMessage(ConnectAckMessage.make({ from: connectionId, to: data.from }))
|
|
71
71
|
yield* connectedLatch.open
|
|
72
|
-
|
|
72
|
+
return undefined
|
|
73
73
|
}
|
|
74
74
|
// Case: other side sends connect-ack message (because otherside was already online when this side connected)
|
|
75
75
|
case 'ConnectAckMessage': {
|
|
@@ -77,7 +77,7 @@ export const broadcastChannelWithAck = <MsgListen, MsgSend, MsgListenEncoded, Ms
|
|
|
77
77
|
peerIdRef.current = data.from
|
|
78
78
|
yield* connectedLatch.open
|
|
79
79
|
}
|
|
80
|
-
|
|
80
|
+
return undefined
|
|
81
81
|
}
|
|
82
82
|
case 'DisconnectMessage': {
|
|
83
83
|
if (data.from === peerIdRef.current) {
|
|
@@ -85,13 +85,13 @@ export const broadcastChannelWithAck = <MsgListen, MsgSend, MsgListenEncoded, Ms
|
|
|
85
85
|
yield* connectedLatch.close
|
|
86
86
|
yield* establishConnection
|
|
87
87
|
}
|
|
88
|
-
|
|
88
|
+
return undefined
|
|
89
89
|
}
|
|
90
90
|
case 'PayloadMessage': {
|
|
91
91
|
if (data.to === connectionId) {
|
|
92
92
|
return Schema.decodeEither(schema.listen)(data.payload)
|
|
93
93
|
}
|
|
94
|
-
|
|
94
|
+
return undefined
|
|
95
95
|
}
|
|
96
96
|
}
|
|
97
97
|
}),
|
|
@@ -54,19 +54,19 @@ export type OutputSchema<MsgListen, MsgSend, MsgListenEncoded, MsgSendEncoded> =
|
|
|
54
54
|
export const mapSchema = <MsgListen, MsgSend, MsgListenEncoded, MsgSendEncoded>(
|
|
55
55
|
schema: InputSchema<MsgListen, MsgSend, MsgListenEncoded, MsgSendEncoded>,
|
|
56
56
|
): OutputSchema<MsgListen, MsgSend, MsgListenEncoded, MsgSendEncoded> =>
|
|
57
|
-
Predicate.hasProperty(schema, 'send') && Predicate.hasProperty(schema, 'listen')
|
|
57
|
+
Predicate.hasProperty(schema, 'send') === true && Predicate.hasProperty(schema, 'listen') === true
|
|
58
58
|
? (schemaWithWebChannelMessages(schema) as any)
|
|
59
59
|
: (schemaWithWebChannelMessages({ send: schema, listen: schema }) as any)
|
|
60
60
|
|
|
61
61
|
export const listenToDebugPing =
|
|
62
62
|
(channelName: string) =>
|
|
63
63
|
<MsgListen>(
|
|
64
|
-
stream: Stream.Stream<Either.Either<MsgListen, ParseResult.ParseError
|
|
65
|
-
): Stream.Stream<Either.Either<MsgListen, ParseResult.ParseError
|
|
64
|
+
stream: Stream.Stream<Either.Either<MsgListen, ParseResult.ParseError>>,
|
|
65
|
+
): Stream.Stream<Either.Either<MsgListen, ParseResult.ParseError>> =>
|
|
66
66
|
stream.pipe(
|
|
67
67
|
Stream.filterEffect(
|
|
68
68
|
Effect.fn(function* (msg) {
|
|
69
|
-
if (msg._tag === 'Right' && Schema.is(DebugPingMessage)(msg.right)) {
|
|
69
|
+
if (msg._tag === 'Right' && Schema.is(DebugPingMessage)(msg.right) === true) {
|
|
70
70
|
yield* Effect.logDebug(`WebChannel:ping [${channelName}] ${msg.right.message}`, msg.right.payload)
|
|
71
71
|
return false
|
|
72
72
|
}
|
package/src/effect/WebSocket.ts
CHANGED
|
@@ -2,7 +2,7 @@ import { HttpClient } from '@effect/platform'
|
|
|
2
2
|
import type { Schedule, Scope } from 'effect'
|
|
3
3
|
import { Effect, Exit, identity, Schema } from 'effect'
|
|
4
4
|
|
|
5
|
-
export class WebSocketError extends Schema.TaggedError<WebSocketError>()('WebSocketError', {
|
|
5
|
+
export class WebSocketError extends Schema.TaggedError<WebSocketError>('~@livestore/utils/WebSocketError')('WebSocketError', {
|
|
6
6
|
cause: Schema.Defect,
|
|
7
7
|
}) {}
|
|
8
8
|
|
|
@@ -63,7 +63,7 @@ export const makeWebSocket = ({
|
|
|
63
63
|
}
|
|
64
64
|
}).pipe(
|
|
65
65
|
Effect.tapErrorTag('WebSocketError', () => tryLogWebsocketConnectError(url)),
|
|
66
|
-
reconnect ? Effect.retry(reconnect) : identity,
|
|
66
|
+
reconnect !== undefined ? Effect.retry(reconnect) : identity,
|
|
67
67
|
)
|
|
68
68
|
|
|
69
69
|
/**
|
|
@@ -83,7 +83,7 @@ export const makeWebSocket = ({
|
|
|
83
83
|
Effect.fn(function* (exit) {
|
|
84
84
|
yield* Effect.try({
|
|
85
85
|
try: () => {
|
|
86
|
-
if (Exit.isFailure(exit)) {
|
|
86
|
+
if (Exit.isFailure(exit) === true) {
|
|
87
87
|
socket.close(3000)
|
|
88
88
|
} else {
|
|
89
89
|
socket.close(1000)
|
package/src/effect/mod.ts
CHANGED
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import { it, describe, expect } from '@effect/vitest'
|
|
2
|
+
import { Effect, Tracer } from 'effect'
|
|
3
|
+
|
|
4
|
+
import { spanEvent } from './spanEvent.ts'
|
|
5
|
+
|
|
6
|
+
type RecordedEvent = { name: string; attributes: Record<string, unknown> | undefined }
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Creates a test tracer that captures span events for assertion,
|
|
10
|
+
* using only the public `Tracer` API (no internal NativeSpan access).
|
|
11
|
+
* Each span records its own events, retrievable by span name.
|
|
12
|
+
*/
|
|
13
|
+
const makeTestTracer = () => {
|
|
14
|
+
const spanEvents = new Map<string, Array<RecordedEvent>>()
|
|
15
|
+
|
|
16
|
+
const tracer = Tracer.make({
|
|
17
|
+
span(name, parent, context, links, startTime, kind) {
|
|
18
|
+
const events: Array<RecordedEvent> = []
|
|
19
|
+
spanEvents.set(name, events)
|
|
20
|
+
const attributes = new Map<string, unknown>()
|
|
21
|
+
return {
|
|
22
|
+
_tag: 'Span' as const,
|
|
23
|
+
name,
|
|
24
|
+
spanId: `test-${name}`,
|
|
25
|
+
traceId: 'test-trace',
|
|
26
|
+
parent,
|
|
27
|
+
context,
|
|
28
|
+
status: { _tag: 'Started' as const, startTime },
|
|
29
|
+
attributes,
|
|
30
|
+
links: [...links],
|
|
31
|
+
sampled: true,
|
|
32
|
+
kind,
|
|
33
|
+
end() {},
|
|
34
|
+
attribute(key: string, value: unknown) {
|
|
35
|
+
attributes.set(key, value)
|
|
36
|
+
},
|
|
37
|
+
event(eventName: string, _startTime: bigint, attrs?: Record<string, unknown>) {
|
|
38
|
+
events.push({ name: eventName, attributes: attrs })
|
|
39
|
+
},
|
|
40
|
+
addLinks() {},
|
|
41
|
+
}
|
|
42
|
+
},
|
|
43
|
+
context(f) {
|
|
44
|
+
return f()
|
|
45
|
+
},
|
|
46
|
+
})
|
|
47
|
+
|
|
48
|
+
return {
|
|
49
|
+
tracer,
|
|
50
|
+
getEvents: (spanName: string): Array<RecordedEvent> => spanEvents.get(spanName) ?? [],
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
describe('spanEvent', () => {
|
|
55
|
+
it.effect('should emit a span event with the given message', () => {
|
|
56
|
+
const { tracer, getEvents } = makeTestTracer()
|
|
57
|
+
return Effect.gen(function* () {
|
|
58
|
+
yield* spanEvent('test-event')
|
|
59
|
+
const events = getEvents('test-span')
|
|
60
|
+
expect(events).toHaveLength(1)
|
|
61
|
+
expect(events[0]!.name).toBe('test-event')
|
|
62
|
+
}).pipe(Effect.withSpan('test-span'), Effect.withTracer(tracer))
|
|
63
|
+
})
|
|
64
|
+
|
|
65
|
+
it.effect('should emit a span event with attributes', () => {
|
|
66
|
+
const { tracer, getEvents } = makeTestTracer()
|
|
67
|
+
return Effect.gen(function* () {
|
|
68
|
+
yield* spanEvent('event-with-attrs', { key1: 'value1', key2: 42 })
|
|
69
|
+
const events = getEvents('test-span')
|
|
70
|
+
expect(events).toHaveLength(1)
|
|
71
|
+
expect(events[0]!.name).toBe('event-with-attrs')
|
|
72
|
+
expect(events[0]!.attributes).toMatchObject({ key1: 'value1', key2: 42 })
|
|
73
|
+
}).pipe(Effect.withSpan('test-span'), Effect.withTracer(tracer))
|
|
74
|
+
})
|
|
75
|
+
|
|
76
|
+
it.effect('should emit to the nearest enclosing span', () => {
|
|
77
|
+
const { tracer, getEvents } = makeTestTracer()
|
|
78
|
+
return Effect.gen(function* () {
|
|
79
|
+
yield* spanEvent('outer-event')
|
|
80
|
+
|
|
81
|
+
yield* spanEvent('inner-event').pipe(Effect.withSpan('inner-span'))
|
|
82
|
+
|
|
83
|
+
const outerEvents = getEvents('outer-span')
|
|
84
|
+
const innerEvents = getEvents('inner-span')
|
|
85
|
+
|
|
86
|
+
expect(outerEvents).toHaveLength(1)
|
|
87
|
+
expect(outerEvents[0]!.name).toBe('outer-event')
|
|
88
|
+
|
|
89
|
+
expect(innerEvents).toHaveLength(1)
|
|
90
|
+
expect(innerEvents[0]!.name).toBe('inner-event')
|
|
91
|
+
}).pipe(Effect.withSpan('outer-span'), Effect.withTracer(tracer))
|
|
92
|
+
})
|
|
93
|
+
|
|
94
|
+
it.effect('should be a no-op when no span is in context', () => spanEvent('orphan-event'))
|
|
95
|
+
})
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { Effect, FiberRef, HashSet, Logger } from 'effect'
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Emits a span event on the current Effect span via the tracer logger.
|
|
5
|
+
*
|
|
6
|
+
* @remarks
|
|
7
|
+
*
|
|
8
|
+
* Unlike raw `otelSpan.addEvent`, this doesn't require manual span threading —
|
|
9
|
+
* it automatically targets the nearest enclosing `Effect.withSpan`. If no span
|
|
10
|
+
* is in context, the call is a no-op.
|
|
11
|
+
*/
|
|
12
|
+
export const spanEvent = (message: any, attributes?: Record<string, unknown>) =>
|
|
13
|
+
Effect.locallyWith(Effect.log(message).pipe(Effect.annotateLogs(attributes ?? {})), FiberRef.currentLoggers, () =>
|
|
14
|
+
HashSet.make(Logger.tracerLogger),
|
|
15
|
+
)
|
package/src/env.ts
CHANGED
|
@@ -26,4 +26,5 @@ export const IS_CI = envTruish(env('CI'))
|
|
|
26
26
|
|
|
27
27
|
export const IS_BUN = typeof Bun !== 'undefined'
|
|
28
28
|
|
|
29
|
-
export const IS_REACT_NATIVE =
|
|
29
|
+
export const IS_REACT_NATIVE =
|
|
30
|
+
typeof navigator !== 'undefined' && (navigator as unknown as Record<string, unknown>)['product'] === 'ReactNative'
|
package/src/fast-deep-equal.ts
CHANGED
|
@@ -4,36 +4,36 @@
|
|
|
4
4
|
export const deepEqual = <T>(a: T, b: T): boolean => {
|
|
5
5
|
if (a === b) return true
|
|
6
6
|
|
|
7
|
-
if (a && b && typeof a === 'object' && typeof b === 'object') {
|
|
7
|
+
if (a != null && b != null && typeof a === 'object' && typeof b === 'object') {
|
|
8
8
|
if (a.constructor !== b.constructor) return false
|
|
9
9
|
|
|
10
10
|
let length: number
|
|
11
11
|
let i: any
|
|
12
12
|
let keys: any
|
|
13
|
-
if (Array.isArray(a)) {
|
|
13
|
+
if (Array.isArray(a) === true) {
|
|
14
14
|
length = a.length
|
|
15
15
|
// @ts-expect-error ...
|
|
16
16
|
if (length !== b.length) return false
|
|
17
17
|
for (i = length; i-- !== 0; )
|
|
18
18
|
// @ts-expect-error ...
|
|
19
|
-
if (
|
|
19
|
+
if (deepEqual(a[i], b[i]) === false) return false
|
|
20
20
|
return true
|
|
21
21
|
}
|
|
22
22
|
|
|
23
23
|
if (a instanceof Map && b instanceof Map) {
|
|
24
24
|
if (a.size !== b.size) return false
|
|
25
|
-
for (i of a.entries()) if (
|
|
26
|
-
for (i of a.entries()) if (
|
|
25
|
+
for (i of a.entries()) if (b.has(i[0]) === false) return false
|
|
26
|
+
for (i of a.entries()) if (deepEqual(i[1], b.get(i[0])) === false) return false
|
|
27
27
|
return true
|
|
28
28
|
}
|
|
29
29
|
|
|
30
30
|
if (a instanceof Set && b instanceof Set) {
|
|
31
31
|
if (a.size !== b.size) return false
|
|
32
|
-
for (i of a.entries()) if (
|
|
32
|
+
for (i of a.entries()) if (b.has(i[0]) === false) return false
|
|
33
33
|
return true
|
|
34
34
|
}
|
|
35
35
|
|
|
36
|
-
if (ArrayBuffer.isView(a) && ArrayBuffer.isView(b)) {
|
|
36
|
+
if (ArrayBuffer.isView(a) === true && ArrayBuffer.isView(b) === true) {
|
|
37
37
|
// @ts-expect-error ...
|
|
38
38
|
length = a.length
|
|
39
39
|
// @ts-expect-error ...
|
|
@@ -53,13 +53,13 @@ export const deepEqual = <T>(a: T, b: T): boolean => {
|
|
|
53
53
|
length = keys.length
|
|
54
54
|
if (length !== Object.keys(b).length) return false
|
|
55
55
|
|
|
56
|
-
for (i = length; i-- !== 0; ) if (
|
|
56
|
+
for (i = length; i-- !== 0; ) if (Object.prototype.hasOwnProperty.call(b, keys[i]) === false) return false
|
|
57
57
|
|
|
58
58
|
for (i = length; i-- !== 0; ) {
|
|
59
59
|
const key = keys[i]
|
|
60
60
|
|
|
61
61
|
// @ts-expect-error ...
|
|
62
|
-
if (
|
|
62
|
+
if (deepEqual(a[key], b[key]) === false) return false
|
|
63
63
|
}
|
|
64
64
|
|
|
65
65
|
return true
|
package/src/global.ts
CHANGED
package/src/misc.ts
CHANGED
|
@@ -10,7 +10,7 @@ export const isDevEnv = () => {
|
|
|
10
10
|
}
|
|
11
11
|
|
|
12
12
|
// @ts-expect-error Only exists in Expo / RN
|
|
13
|
-
if (globalThis?.__DEV__) {
|
|
13
|
+
if (globalThis?.__DEV__ === true) {
|
|
14
14
|
return true
|
|
15
15
|
}
|
|
16
16
|
|
|
@@ -46,10 +46,18 @@ export const tryAsFunctionAndNew = <TArg, TResult>(
|
|
|
46
46
|
export const envTruish = (env: string | undefined) =>
|
|
47
47
|
env !== undefined && env.toLowerCase() !== 'false' && env.toLowerCase() !== '0'
|
|
48
48
|
|
|
49
|
-
|
|
49
|
+
/**
|
|
50
|
+
* Logs and throws for impossible states, pausing at a breakpoint in development.
|
|
51
|
+
*
|
|
52
|
+
* @param msg - The error message to log and pass to the error.
|
|
53
|
+
* @param args - Arbitrary arguments to include in the log.
|
|
54
|
+
*
|
|
55
|
+
* @see {@link dieDebugger} for the Effect equivalent.
|
|
56
|
+
*/
|
|
57
|
+
export const shouldNeverHappen = (msg?: string, ...args: ReadonlyArray<unknown>): never => {
|
|
50
58
|
console.error(msg, ...args)
|
|
51
|
-
if (isDevEnv()) {
|
|
52
|
-
//
|
|
59
|
+
if (isDevEnv() === true) {
|
|
60
|
+
// oxlint-disable-next-line eslint(no-debugger) -- intentional breakpoint during development
|
|
53
61
|
debugger
|
|
54
62
|
}
|
|
55
63
|
|