@livestore/utils 0.4.0 → 0.5.0-dev.0
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 -1
- package/dist/NoopTracer.d.ts +7 -8
- package/dist/NoopTracer.d.ts.map +1 -1
- package/dist/NoopTracer.js +3 -18
- package/dist/NoopTracer.js.map +1 -1
- package/dist/NoopTracer.test.d.ts +2 -0
- package/dist/NoopTracer.test.d.ts.map +1 -0
- package/dist/NoopTracer.test.js +17 -0
- package/dist/NoopTracer.test.js.map +1 -0
- package/dist/browser/Opfs/Opfs.d.ts +179 -29
- package/dist/browser/Opfs/Opfs.d.ts.map +1 -1
- package/dist/browser/Opfs/Opfs.js +132 -307
- 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 +5 -4
- package/dist/browser/Opfs/debug-utils.js.map +1 -1
- package/dist/browser/Opfs/utils.d.ts +8 -8
- package/dist/browser/Opfs/utils.d.ts.map +1 -1
- package/dist/browser/Opfs/utils.js +35 -26
- package/dist/browser/Opfs/utils.js.map +1 -1
- package/dist/browser/QuotaExceededError.d.ts +10 -9
- package/dist/browser/QuotaExceededError.d.ts.map +1 -1
- package/dist/browser/WebChannelBrowser.d.ts.map +1 -1
- package/dist/browser/WebChannelBrowser.js +21 -10
- package/dist/browser/WebChannelBrowser.js.map +1 -1
- package/dist/browser/WebError.d.ts +54 -86
- package/dist/browser/WebError.d.ts.map +1 -1
- package/dist/browser/WebError.js +91 -84
- package/dist/browser/WebError.js.map +1 -1
- package/dist/browser/WebError.test.js +6 -6
- package/dist/browser/WebError.test.js.map +1 -1
- package/dist/browser/WebLock.d.ts.map +1 -1
- package/dist/browser/WebLock.js +13 -13
- package/dist/browser/WebLock.js.map +1 -1
- package/dist/effect/Debug.d.ts +4 -7
- package/dist/effect/Debug.d.ts.map +1 -1
- package/dist/effect/Debug.js +32 -36
- package/dist/effect/Debug.js.map +1 -1
- package/dist/effect/Effect.d.ts +31 -22
- package/dist/effect/Effect.d.ts.map +1 -1
- package/dist/effect/Effect.js +51 -47
- package/dist/effect/Effect.js.map +1 -1
- package/dist/effect/Effect.test.d.ts +2 -0
- package/dist/effect/Effect.test.d.ts.map +1 -0
- package/dist/effect/Effect.test.js +72 -0
- package/dist/effect/Effect.test.js.map +1 -0
- package/dist/effect/Error.d.ts +4 -6
- package/dist/effect/Error.d.ts.map +1 -1
- package/dist/effect/Logger.d.ts +0 -6
- package/dist/effect/Logger.d.ts.map +1 -1
- package/dist/effect/Logger.js +0 -32
- package/dist/effect/Logger.js.map +1 -1
- package/dist/effect/OtelTracer.d.ts +1 -1
- package/dist/effect/OtelTracer.d.ts.map +1 -1
- package/dist/effect/OtelTracer.js +2 -3
- package/dist/effect/OtelTracer.js.map +1 -1
- package/dist/effect/RpcClient.d.ts +7 -7
- package/dist/effect/RpcClient.d.ts.map +1 -1
- package/dist/effect/RpcClient.js +72 -52
- package/dist/effect/RpcClient.js.map +1 -1
- package/dist/effect/Schedule.d.ts +1 -1
- package/dist/effect/Schedule.d.ts.map +1 -1
- package/dist/effect/Schedule.js +2 -2
- package/dist/effect/Schedule.js.map +1 -1
- package/dist/effect/Schema/debug-diff.d.ts +1 -1
- package/dist/effect/Schema/debug-diff.d.ts.map +1 -1
- package/dist/effect/Schema/debug-diff.js +5 -7
- package/dist/effect/Schema/debug-diff.js.map +1 -1
- package/dist/effect/Schema/debug-diff.test.js +7 -4
- package/dist/effect/Schema/debug-diff.test.js.map +1 -1
- package/dist/effect/Schema/index.d.ts +28 -20
- package/dist/effect/Schema/index.d.ts.map +1 -1
- package/dist/effect/Schema/index.js +55 -28
- package/dist/effect/Schema/index.js.map +1 -1
- package/dist/effect/Stream.d.ts +13 -5
- package/dist/effect/Stream.d.ts.map +1 -1
- package/dist/effect/Stream.js +19 -12
- package/dist/effect/Stream.js.map +1 -1
- package/dist/effect/Stream.test.js +9 -9
- package/dist/effect/Stream.test.js.map +1 -1
- package/dist/effect/Subscribable.d.ts +9 -3
- package/dist/effect/Subscribable.d.ts.map +1 -1
- package/dist/effect/Subscribable.js +20 -35
- package/dist/effect/Subscribable.js.map +1 -1
- package/dist/effect/SubscriptionRef.d.ts +5 -6
- package/dist/effect/SubscriptionRef.d.ts.map +1 -1
- package/dist/effect/SubscriptionRef.js +2 -3
- package/dist/effect/SubscriptionRef.js.map +1 -1
- package/dist/effect/TaskTracing.d.ts +1 -1
- package/dist/effect/TaskTracing.d.ts.map +1 -1
- package/dist/effect/TaskTracing.js +12 -16
- package/dist/effect/TaskTracing.js.map +1 -1
- package/dist/effect/WebChannel/WebChannel.d.ts +7 -7
- package/dist/effect/WebChannel/WebChannel.d.ts.map +1 -1
- package/dist/effect/WebChannel/WebChannel.js +64 -43
- package/dist/effect/WebChannel/WebChannel.js.map +1 -1
- package/dist/effect/WebChannel/WebChannel.test.js +15 -15
- package/dist/effect/WebChannel/WebChannel.test.js.map +1 -1
- package/dist/effect/WebChannel/broadcastChannelWithAck.d.ts.map +1 -1
- package/dist/effect/WebChannel/broadcastChannelWithAck.js +16 -9
- package/dist/effect/WebChannel/broadcastChannelWithAck.js.map +1 -1
- package/dist/effect/WebChannel/common.d.ts +16 -17
- package/dist/effect/WebChannel/common.d.ts.map +1 -1
- package/dist/effect/WebChannel/common.js +6 -6
- package/dist/effect/WebChannel/common.js.map +1 -1
- package/dist/effect/WebSocket.d.ts +4 -6
- package/dist/effect/WebSocket.d.ts.map +1 -1
- package/dist/effect/WebSocket.js +4 -4
- package/dist/effect/WebSocket.js.map +1 -1
- package/dist/effect/WebSocket.test.js +2 -2
- package/dist/effect/WebSocket.test.js.map +1 -1
- package/dist/effect/mod.browser-build.test.d.ts +2 -0
- package/dist/effect/mod.browser-build.test.d.ts.map +1 -0
- package/dist/effect/mod.browser-build.test.js +18 -0
- package/dist/effect/mod.browser-build.test.js.map +1 -0
- package/dist/effect/mod.d.ts +13 -15
- package/dist/effect/mod.d.ts.map +1 -1
- package/dist/effect/mod.js +13 -18
- package/dist/effect/mod.js.map +1 -1
- package/dist/effect/spanEvent.d.ts.map +1 -1
- package/dist/effect/spanEvent.js +2 -2
- package/dist/effect/spanEvent.js.map +1 -1
- package/dist/effect/spanEvent.test.js +10 -13
- package/dist/effect/spanEvent.test.js.map +1 -1
- package/dist/fast-deep-equal.d.ts.map +1 -1
- package/dist/fast-deep-equal.js +1 -2
- package/dist/fast-deep-equal.js.map +1 -1
- package/dist/misc.js +2 -2
- package/dist/misc.js.map +1 -1
- package/dist/mod.d.ts +0 -35
- package/dist/mod.d.ts.map +1 -1
- package/dist/mod.js +0 -8
- package/dist/mod.js.map +1 -1
- package/dist/node/mod.d.ts +17 -11
- package/dist/node/mod.d.ts.map +1 -1
- package/dist/node/mod.js +23 -16
- package/dist/node/mod.js.map +1 -1
- package/dist/object/index.d.ts +0 -9
- package/dist/object/index.d.ts.map +1 -1
- package/dist/object/index.js +0 -9
- package/dist/object/index.js.map +1 -1
- package/dist/string.d.ts +0 -2
- package/dist/string.d.ts.map +1 -1
- package/dist/string.js +0 -2
- package/dist/string.js.map +1 -1
- package/package.json +18 -36
- package/src/NoopTracer.test.ts +20 -0
- package/src/NoopTracer.ts +18 -41
- package/src/browser/Opfs/Opfs.ts +304 -277
- package/src/browser/Opfs/debug-utils.ts +7 -6
- package/src/browser/Opfs/utils.ts +36 -26
- package/src/browser/QuotaExceededError.ts +13 -10
- package/src/browser/WebChannelBrowser.ts +25 -11
- package/src/browser/WebError.test.ts +6 -6
- package/src/browser/WebError.ts +107 -133
- package/src/browser/WebLock.ts +13 -14
- package/src/effect/Debug.ts +66 -59
- package/src/effect/Effect.test.ts +117 -0
- package/src/effect/Effect.ts +84 -71
- package/src/effect/Logger.ts +0 -48
- package/src/effect/OtelTracer.ts +2 -3
- package/src/effect/RpcClient.ts +80 -61
- package/src/effect/Schedule.ts +4 -5
- package/src/effect/Schema/debug-diff.test.ts +6 -6
- package/src/effect/Schema/debug-diff.ts +6 -8
- package/src/effect/Schema/index.ts +122 -61
- package/src/effect/Stream.test.ts +9 -9
- package/src/effect/Stream.ts +23 -16
- package/src/effect/Subscribable.ts +31 -42
- package/src/effect/SubscriptionRef.ts +8 -12
- package/src/effect/TaskTracing.ts +13 -16
- package/src/effect/WebChannel/WebChannel.test.ts +23 -23
- package/src/effect/WebChannel/WebChannel.ts +87 -55
- package/src/effect/WebChannel/broadcastChannelWithAck.ts +21 -11
- package/src/effect/WebChannel/common.ts +14 -15
- package/src/effect/WebSocket.test.ts +2 -2
- package/src/effect/WebSocket.ts +9 -6
- package/src/effect/mod.browser-build.test.ts +19 -0
- package/src/effect/mod.ts +35 -69
- package/src/effect/spanEvent.test.ts +10 -13
- package/src/effect/spanEvent.ts +5 -3
- package/src/fast-deep-equal.ts +1 -2
- package/src/misc.ts +2 -2
- package/src/mod.ts +0 -36
- package/src/node/mod.ts +26 -20
- package/src/object/index.ts +0 -24
- package/src/string.ts +0 -3
- package/dist/effect/BucketQueue.d.ts +0 -20
- package/dist/effect/BucketQueue.d.ts.map +0 -1
- package/dist/effect/BucketQueue.js +0 -34
- package/dist/effect/BucketQueue.js.map +0 -1
- package/dist/effect/Scheduler.d.ts +0 -4
- package/dist/effect/Scheduler.d.ts.map +0 -1
- package/dist/effect/Scheduler.js +0 -9
- package/dist/effect/Scheduler.js.map +0 -1
- package/dist/effect/ServiceContext.d.ts +0 -37
- package/dist/effect/ServiceContext.d.ts.map +0 -1
- package/dist/effect/ServiceContext.js +0 -55
- package/dist/effect/ServiceContext.js.map +0 -1
- package/dist/guards.d.ts +0 -20
- package/dist/guards.d.ts.map +0 -1
- package/dist/guards.js +0 -20
- package/dist/guards.js.map +0 -1
- package/dist/node/ChildProcessRunner/ChildProcessRunner.d.ts +0 -4
- package/dist/node/ChildProcessRunner/ChildProcessRunner.d.ts.map +0 -1
- package/dist/node/ChildProcessRunner/ChildProcessRunner.js +0 -128
- package/dist/node/ChildProcessRunner/ChildProcessRunner.js.map +0 -1
- package/dist/node/ChildProcessRunner/ChildProcessRunnerTest/ChildProcessRunner.test.d.ts +0 -10
- package/dist/node/ChildProcessRunner/ChildProcessRunnerTest/ChildProcessRunner.test.d.ts.map +0 -1
- package/dist/node/ChildProcessRunner/ChildProcessRunnerTest/ChildProcessRunner.test.js +0 -217
- package/dist/node/ChildProcessRunner/ChildProcessRunnerTest/ChildProcessRunner.test.js.map +0 -1
- package/dist/node/ChildProcessRunner/ChildProcessRunnerTest/schema.d.ts +0 -84
- package/dist/node/ChildProcessRunner/ChildProcessRunnerTest/schema.d.ts.map +0 -1
- package/dist/node/ChildProcessRunner/ChildProcessRunnerTest/schema.js +0 -68
- package/dist/node/ChildProcessRunner/ChildProcessRunnerTest/schema.js.map +0 -1
- package/dist/node/ChildProcessRunner/ChildProcessRunnerTest/serializedWorker.d.ts +0 -2
- package/dist/node/ChildProcessRunner/ChildProcessRunnerTest/serializedWorker.d.ts.map +0 -1
- package/dist/node/ChildProcessRunner/ChildProcessRunnerTest/serializedWorker.js +0 -52
- package/dist/node/ChildProcessRunner/ChildProcessRunnerTest/serializedWorker.js.map +0 -1
- package/dist/node/ChildProcessRunner/ChildProcessWorker.d.ts +0 -23
- package/dist/node/ChildProcessRunner/ChildProcessWorker.d.ts.map +0 -1
- package/dist/node/ChildProcessRunner/ChildProcessWorker.js +0 -138
- package/dist/node/ChildProcessRunner/ChildProcessWorker.js.map +0 -1
- package/dist/object/omit.d.ts +0 -3
- package/dist/object/omit.d.ts.map +0 -1
- package/dist/object/omit.js +0 -14
- package/dist/object/omit.js.map +0 -1
- package/dist/object/pick.d.ts +0 -14
- package/dist/object/pick.d.ts.map +0 -1
- package/dist/object/pick.js +0 -17
- package/dist/object/pick.js.map +0 -1
- package/dist/time.d.ts +0 -12
- package/dist/time.d.ts.map +0 -1
- package/dist/time.js +0 -22
- package/dist/time.js.map +0 -1
- package/src/effect/BucketQueue.ts +0 -49
- package/src/effect/Scheduler.ts +0 -13
- package/src/effect/ServiceContext.ts +0 -108
- package/src/guards.ts +0 -23
- package/src/node/ChildProcessRunner/ChildProcessRunner.ts +0 -148
- package/src/node/ChildProcessRunner/ChildProcessRunnerTest/ChildProcessRunner.test.ts +0 -311
- package/src/node/ChildProcessRunner/ChildProcessRunnerTest/schema.ts +0 -78
- package/src/node/ChildProcessRunner/ChildProcessRunnerTest/serializedWorker.ts +0 -65
- package/src/node/ChildProcessRunner/ChildProcessWorker.ts +0 -169
- package/src/object/omit.ts +0 -17
- package/src/object/pick.ts +0 -27
- package/src/time.ts +0 -25
|
@@ -8,7 +8,7 @@ import { Effect, Stream } from 'effect'
|
|
|
8
8
|
import prettyBytes from 'pretty-bytes'
|
|
9
9
|
|
|
10
10
|
import type * as WebError from '../WebError.ts'
|
|
11
|
-
import
|
|
11
|
+
import * as Opfs from './Opfs.ts'
|
|
12
12
|
import { getDirectoryHandleByPath, getMetadata, remove } from './utils.ts'
|
|
13
13
|
|
|
14
14
|
/**
|
|
@@ -33,14 +33,15 @@ const ROOT_NAME = '/'
|
|
|
33
33
|
* Materialize the entire OPFS tree starting from the origin root.
|
|
34
34
|
*/
|
|
35
35
|
const buildTree = Effect.fn('@livestore/utils:Opfs.buildTree')(function* () {
|
|
36
|
-
const
|
|
36
|
+
const opfs = yield* Opfs.Opfs
|
|
37
|
+
const rootHandle = yield* opfs.getRootDirectoryHandle
|
|
37
38
|
|
|
38
39
|
const collectDirectory = (
|
|
39
40
|
handle: FileSystemDirectoryHandle,
|
|
40
41
|
pathSegments: ReadonlyArray<string>,
|
|
41
|
-
): Effect.Effect<OpfsTreeNode, WebError.WebError, Opfs> =>
|
|
42
|
+
): Effect.Effect<OpfsTreeNode, WebError.WebError, Opfs.Opfs> =>
|
|
42
43
|
Effect.gen(function* () {
|
|
43
|
-
const handlesStream =
|
|
44
|
+
const handlesStream = opfs.values(handle)
|
|
44
45
|
const handles = yield* handlesStream.pipe(
|
|
45
46
|
Stream.runCollect,
|
|
46
47
|
Effect.map((chunk) => Array.from(chunk).sort((a, b) => a.name.localeCompare(b.name))),
|
|
@@ -134,8 +135,8 @@ const resetTree = remove('/')
|
|
|
134
135
|
|
|
135
136
|
const getDirHandle = (path: string, options?: FileSystemGetDirectoryOptions) => getDirectoryHandleByPath(path, options)
|
|
136
137
|
|
|
137
|
-
const runOpfsEffect = <A, E>(effect: Effect.Effect<A, E, Opfs>) =>
|
|
138
|
-
effect.pipe(Effect.provide(Opfs.
|
|
138
|
+
const runOpfsEffect = <A, E>(effect: Effect.Effect<A, E, Opfs.Opfs>) =>
|
|
139
|
+
effect.pipe(Effect.provide(Opfs.layer), Effect.runPromise)
|
|
139
140
|
|
|
140
141
|
export const debugUtils = {
|
|
141
142
|
/**
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Effect, Stream } from 'effect'
|
|
2
2
|
|
|
3
|
-
import
|
|
3
|
+
import * as Opfs from './Opfs.ts'
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
6
|
* Set of path segments that are forbidden by the File System specification.
|
|
@@ -25,14 +25,14 @@ const parsePathSegments = (path: string) =>
|
|
|
25
25
|
const segments = path.split('/').filter((segment) => segment.length > 0)
|
|
26
26
|
|
|
27
27
|
if (segments.length === 0) {
|
|
28
|
-
return yield* new OpfsError({
|
|
28
|
+
return yield* new Opfs.OpfsError({
|
|
29
29
|
message: `Invalid OPFS path '${path}': path must contain at least one non-empty segment`,
|
|
30
30
|
})
|
|
31
31
|
}
|
|
32
32
|
|
|
33
33
|
for (const segment of segments) {
|
|
34
34
|
if (DISALLOWED_SEGMENTS.has(segment) === true) {
|
|
35
|
-
return yield* new OpfsError({
|
|
35
|
+
return yield* new Opfs.OpfsError({
|
|
36
36
|
message: `Invalid OPFS path '${path}': segment '${segment}' is not supported`,
|
|
37
37
|
})
|
|
38
38
|
}
|
|
@@ -65,11 +65,12 @@ const splitPathSegments = (segments: ReadonlyArray<string>) => ({
|
|
|
65
65
|
*/
|
|
66
66
|
const traverseDirectoryPath = (segments: ReadonlyArray<string>, options?: FileSystemGetDirectoryOptions) =>
|
|
67
67
|
Effect.gen(function* () {
|
|
68
|
-
|
|
68
|
+
const opfs = yield* Opfs.Opfs
|
|
69
|
+
let currentDirHandle = yield* opfs.getRootDirectoryHandle
|
|
69
70
|
|
|
70
71
|
for (let index = 0; index < segments.length; index++) {
|
|
71
72
|
const segment = segments[index]!
|
|
72
|
-
currentDirHandle = yield*
|
|
73
|
+
currentDirHandle = yield* opfs.getDirectoryHandle(currentDirHandle, segment, options)
|
|
73
74
|
}
|
|
74
75
|
|
|
75
76
|
return currentDirHandle
|
|
@@ -83,14 +84,15 @@ const traverseDirectoryPath = (segments: ReadonlyArray<string>, options?: FileSy
|
|
|
83
84
|
*/
|
|
84
85
|
const ensureDirectoryPath = (segments: ReadonlyArray<string>, options: { readonly recursive: boolean }) =>
|
|
85
86
|
Effect.gen(function* () {
|
|
86
|
-
|
|
87
|
+
const opfs = yield* Opfs.Opfs
|
|
88
|
+
let currentDirHandle = yield* opfs.getRootDirectoryHandle
|
|
87
89
|
|
|
88
90
|
for (let index = 0; index < segments.length; index++) {
|
|
89
91
|
const segment = segments[index]!
|
|
90
92
|
const isLast = index === segments.length - 1
|
|
91
93
|
const shouldCreate = options.recursive || isLast
|
|
92
94
|
|
|
93
|
-
currentDirHandle = yield*
|
|
95
|
+
currentDirHandle = yield* opfs.getDirectoryHandle(
|
|
94
96
|
currentDirHandle,
|
|
95
97
|
segment,
|
|
96
98
|
shouldCreate === true ? { create: true } : undefined,
|
|
@@ -111,7 +113,10 @@ export const getDirectoryHandleByPath = Effect.fn('@livestore/utils:Opfs.getDire
|
|
|
111
113
|
path: string,
|
|
112
114
|
options?: FileSystemGetDirectoryOptions,
|
|
113
115
|
) {
|
|
114
|
-
if (isRootPath(path) === true)
|
|
116
|
+
if (isRootPath(path) === true) {
|
|
117
|
+
const opfs = yield* Opfs.Opfs
|
|
118
|
+
return yield* opfs.getRootDirectoryHandle
|
|
119
|
+
}
|
|
115
120
|
|
|
116
121
|
const pathSegments = yield* parsePathSegments(path)
|
|
117
122
|
return yield* traverseDirectoryPath(pathSegments, options)
|
|
@@ -128,12 +133,13 @@ export const remove = Effect.fn('@livestore/utils:Opfs.remove')(function* (
|
|
|
128
133
|
options?: { readonly recursive?: boolean },
|
|
129
134
|
) {
|
|
130
135
|
const recursive = options?.recursive ?? false
|
|
136
|
+
const opfs = yield* Opfs.Opfs
|
|
131
137
|
|
|
132
138
|
if (isRootPath(path) === true) {
|
|
133
|
-
const rootHandle = yield*
|
|
134
|
-
const handlesStream =
|
|
139
|
+
const rootHandle = yield* opfs.getRootDirectoryHandle
|
|
140
|
+
const handlesStream = opfs.values(rootHandle)
|
|
135
141
|
yield* handlesStream.pipe(
|
|
136
|
-
Stream.runForEach((handle) =>
|
|
142
|
+
Stream.runForEach((handle) => opfs.removeEntry(rootHandle, handle.name, { recursive: true })),
|
|
137
143
|
)
|
|
138
144
|
return
|
|
139
145
|
}
|
|
@@ -142,7 +148,7 @@ export const remove = Effect.fn('@livestore/utils:Opfs.remove')(function* (
|
|
|
142
148
|
const { parentSegments, leafSegment: targetName } = splitPathSegments(pathSegments)
|
|
143
149
|
const parentDirHandle = yield* traverseDirectoryPath(parentSegments)
|
|
144
150
|
|
|
145
|
-
yield*
|
|
151
|
+
yield* opfs.removeEntry(parentDirHandle, targetName, { recursive })
|
|
146
152
|
})
|
|
147
153
|
|
|
148
154
|
/**
|
|
@@ -158,13 +164,14 @@ export const exists = Effect.fn('@livestore/utils:Opfs.exists')(function* (path:
|
|
|
158
164
|
const { parentSegments, leafSegment: targetName } = splitPathSegments(pathSegments)
|
|
159
165
|
|
|
160
166
|
const parentDirHandle = yield* traverseDirectoryPath(parentSegments, { create: false }).pipe(
|
|
161
|
-
Effect.catchTag('NotFoundError', () => Effect.
|
|
167
|
+
Effect.catchTag('NotFoundError', () => Effect.void),
|
|
162
168
|
)
|
|
163
169
|
|
|
164
170
|
if (parentDirHandle === undefined) return false
|
|
165
171
|
|
|
166
|
-
|
|
167
|
-
|
|
172
|
+
const opfs = yield* Opfs.Opfs
|
|
173
|
+
return yield* opfs.getFileHandle(parentDirHandle, targetName).pipe(
|
|
174
|
+
Effect.catch(() => opfs.getDirectoryHandle(parentDirHandle, targetName, { create: false })),
|
|
168
175
|
Effect.as(true),
|
|
169
176
|
Effect.catchTag('NotFoundError', () => Effect.succeed(false)),
|
|
170
177
|
)
|
|
@@ -196,7 +203,8 @@ export const makeDirectory = Effect.fn('@livestore/utils:Opfs.makeDirectory')(fu
|
|
|
196
203
|
* @returns Object containing name, size, MIME type, and last modification timestamp.
|
|
197
204
|
*/
|
|
198
205
|
export const getMetadata = Effect.fn('@livestore/utils:Opfs.getMetadata')(function* (handle: FileSystemFileHandle) {
|
|
199
|
-
|
|
206
|
+
const opfs = yield* Opfs.Opfs
|
|
207
|
+
return yield* opfs.getFile(handle).pipe(
|
|
200
208
|
Effect.map((file) => ({
|
|
201
209
|
name: file.name,
|
|
202
210
|
size: file.size,
|
|
@@ -217,7 +225,7 @@ export const getMetadata = Effect.fn('@livestore/utils:Opfs.getMetadata')(functi
|
|
|
217
225
|
*/
|
|
218
226
|
export const writeFile = Effect.fn('@livestore/utils:Opfs.writeFile')(function* (path: string, data: Uint8Array) {
|
|
219
227
|
if (isRootPath(path) === true) {
|
|
220
|
-
return yield* new OpfsError({
|
|
228
|
+
return yield* new Opfs.OpfsError({
|
|
221
229
|
message: `Invalid OPFS path '${path}': cannot write file directly to the OPFS root`,
|
|
222
230
|
})
|
|
223
231
|
}
|
|
@@ -228,9 +236,10 @@ export const writeFile = Effect.fn('@livestore/utils:Opfs.writeFile')(function*
|
|
|
228
236
|
return yield* Effect.scoped(
|
|
229
237
|
Effect.gen(function* () {
|
|
230
238
|
const parentDirHandle = yield* traverseDirectoryPath(parentSegments)
|
|
231
|
-
const
|
|
239
|
+
const opfs = yield* Opfs.Opfs
|
|
240
|
+
const fileHandle = yield* opfs.getFileHandle(parentDirHandle, fileName, { create: true })
|
|
232
241
|
|
|
233
|
-
yield*
|
|
242
|
+
yield* opfs.writeFile(fileHandle, new Uint8Array(data), {
|
|
234
243
|
keepExistingData: false,
|
|
235
244
|
})
|
|
236
245
|
}),
|
|
@@ -254,7 +263,7 @@ export const syncWriteFile = Effect.fn('@livestore/utils:Opfs.syncWriteFile')(fu
|
|
|
254
263
|
data: Uint8Array,
|
|
255
264
|
) {
|
|
256
265
|
if (isRootPath(path) === true) {
|
|
257
|
-
return yield* new OpfsError({
|
|
266
|
+
return yield* new Opfs.OpfsError({
|
|
258
267
|
message: `Invalid OPFS path '${path}': cannot write file directly to the OPFS root`,
|
|
259
268
|
})
|
|
260
269
|
}
|
|
@@ -265,23 +274,24 @@ export const syncWriteFile = Effect.fn('@livestore/utils:Opfs.syncWriteFile')(fu
|
|
|
265
274
|
return yield* Effect.scoped(
|
|
266
275
|
Effect.gen(function* () {
|
|
267
276
|
const parentDirHandle = yield* traverseDirectoryPath(parentSegments)
|
|
268
|
-
const
|
|
269
|
-
const
|
|
277
|
+
const opfs = yield* Opfs.Opfs
|
|
278
|
+
const fileHandle = yield* opfs.getFileHandle(parentDirHandle, fileName, { create: true })
|
|
279
|
+
const syncHandle = yield* opfs.createSyncAccessHandle(fileHandle)
|
|
270
280
|
|
|
271
|
-
yield*
|
|
281
|
+
yield* opfs.syncTruncate(syncHandle, 0)
|
|
272
282
|
|
|
273
283
|
let offset = 0
|
|
274
284
|
while (offset < data.byteLength) {
|
|
275
|
-
const wrote = yield*
|
|
285
|
+
const wrote = yield* opfs.syncWrite(syncHandle, data.subarray(offset), { at: offset })
|
|
276
286
|
if (wrote === 0) {
|
|
277
|
-
return yield* new OpfsError({
|
|
287
|
+
return yield* new Opfs.OpfsError({
|
|
278
288
|
message: `Short write: wrote ${offset} of ${data.byteLength} bytes.`,
|
|
279
289
|
})
|
|
280
290
|
}
|
|
281
291
|
offset += Number(wrote)
|
|
282
292
|
}
|
|
283
293
|
|
|
284
|
-
yield*
|
|
294
|
+
yield* opfs.syncFlush(syncHandle)
|
|
285
295
|
}),
|
|
286
296
|
)
|
|
287
297
|
})
|
|
@@ -26,17 +26,22 @@ declare global {
|
|
|
26
26
|
*/
|
|
27
27
|
readonly message: string
|
|
28
28
|
/**
|
|
29
|
-
* A number representing the quota limit in bytes, or
|
|
29
|
+
* A number representing the quota limit in bytes, or null.
|
|
30
30
|
*
|
|
31
31
|
* [MDN Reference](https://developer.mozilla.org/en-US/docs/Web/API/QuotaExceededError/quota)
|
|
32
32
|
*/
|
|
33
|
-
readonly quota
|
|
33
|
+
readonly quota: number | null
|
|
34
34
|
/**
|
|
35
|
-
* A number representing the requested amount of storage in bytes, or
|
|
35
|
+
* A number representing the requested amount of storage in bytes, or null.
|
|
36
36
|
*
|
|
37
37
|
* [MDN Reference](https://developer.mozilla.org/en-US/docs/Web/API/QuotaExceededError/requested)
|
|
38
38
|
*/
|
|
39
|
-
readonly requested
|
|
39
|
+
readonly requested: number | null
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
interface QuotaExceededErrorOptions {
|
|
43
|
+
quota?: number
|
|
44
|
+
requested?: number
|
|
40
45
|
}
|
|
41
46
|
|
|
42
47
|
/**
|
|
@@ -48,10 +53,8 @@ declare global {
|
|
|
48
53
|
*
|
|
49
54
|
* [MDN Reference](https://developer.mozilla.org/en-US/docs/Web/API/QuotaExceededError)
|
|
50
55
|
*/
|
|
51
|
-
var QuotaExceededError:
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
}
|
|
56
|
-
| undefined
|
|
56
|
+
var QuotaExceededError: {
|
|
57
|
+
prototype: QuotaExceededError
|
|
58
|
+
new (message?: string, options?: QuotaExceededErrorOptions): QuotaExceededError
|
|
59
|
+
}
|
|
57
60
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Deferred, Exit, Scope } from 'effect'
|
|
1
|
+
import { Cause, Deferred, Exit, Queue, Scope } from 'effect'
|
|
2
2
|
|
|
3
3
|
import * as Effect from '../effect/Effect.ts'
|
|
4
4
|
import * as Schema from '../effect/Schema/index.ts'
|
|
@@ -25,21 +25,26 @@ export const broadcastChannel = <MsgListen, MsgSend, MsgListenEncoded, MsgSendEn
|
|
|
25
25
|
|
|
26
26
|
const channel = new BroadcastChannel(channelName)
|
|
27
27
|
|
|
28
|
-
yield* Effect.addFinalizer(() =>
|
|
28
|
+
yield* Effect.addFinalizer(() =>
|
|
29
|
+
Effect.try({
|
|
30
|
+
try: () => channel.close(),
|
|
31
|
+
catch: (cause) => new Cause.UnknownError(cause),
|
|
32
|
+
}).pipe(Effect.ignore),
|
|
33
|
+
)
|
|
29
34
|
|
|
30
35
|
const send = (message: MsgSend) =>
|
|
31
36
|
Effect.gen(function* () {
|
|
32
|
-
const messageEncoded = yield* Schema.
|
|
37
|
+
const messageEncoded = yield* Schema.encodeEffect(schema.send)(message)
|
|
33
38
|
channel.postMessage(messageEncoded)
|
|
34
39
|
})
|
|
35
40
|
|
|
36
41
|
// TODO also listen to `messageerror` in parallel
|
|
37
42
|
const listen = Stream.fromEventListener<MessageEvent>(channel, 'message').pipe(
|
|
38
|
-
Stream.map((_) => Schema.
|
|
43
|
+
Stream.map((_) => Schema.decodeResult(schema.listen)(_.data)),
|
|
39
44
|
listenToDebugPing(channelName),
|
|
40
45
|
)
|
|
41
46
|
|
|
42
|
-
const closedDeferred = yield* Deferred.make<void>()
|
|
47
|
+
const closedDeferred = yield* Effect.acquireRelease(Deferred.make<void>(), Deferred.done(Exit.void))
|
|
43
48
|
const supportsTransferables = false
|
|
44
49
|
|
|
45
50
|
return {
|
|
@@ -85,13 +90,22 @@ export const windowChannel = <MsgListen, MsgSend, MsgListenEncoded, MsgSendEncod
|
|
|
85
90
|
message: schema.listen,
|
|
86
91
|
from: Schema.Literal(ids.other),
|
|
87
92
|
to: Schema.Literal(ids.own),
|
|
88
|
-
}).
|
|
93
|
+
}).annotate({ title: 'webmesh.WindowMessageListen' })
|
|
89
94
|
|
|
90
95
|
const WindowMessageSend = Schema.Struct({
|
|
91
96
|
message: schema.send,
|
|
92
97
|
from: Schema.Literal(ids.own),
|
|
93
98
|
to: Schema.Literal(ids.other),
|
|
94
|
-
}).
|
|
99
|
+
}).annotate({ title: 'webmesh.WindowMessageSend' })
|
|
100
|
+
|
|
101
|
+
// `window.postMessage` can fire before a lazily-started stream has installed its listener.
|
|
102
|
+
// Buffer events from channel construction time so Effect v4 scheduling cannot drop them.
|
|
103
|
+
const messageQueue = yield* Effect.acquireRelease(Queue.unbounded<MessageEvent>(), Queue.shutdown)
|
|
104
|
+
const handler = (event: MessageEvent) => {
|
|
105
|
+
Queue.offerUnsafe(messageQueue, event)
|
|
106
|
+
}
|
|
107
|
+
listenWindow.addEventListener('message', handler)
|
|
108
|
+
yield* Effect.addFinalizer(() => Effect.sync(() => listenWindow.removeEventListener('message', handler)))
|
|
95
109
|
|
|
96
110
|
const send = (message: MsgSend) =>
|
|
97
111
|
Effect.gen(function* () {
|
|
@@ -105,16 +119,16 @@ export const windowChannel = <MsgListen, MsgSend, MsgListenEncoded, MsgSendEncod
|
|
|
105
119
|
sendWindow.postMessage(messageEncoded, targetOrigin, transferables)
|
|
106
120
|
})
|
|
107
121
|
|
|
108
|
-
const listen = Stream.
|
|
109
|
-
Stream.filter((_) => Schema.is(Schema.
|
|
122
|
+
const listen = Stream.fromQueue(messageQueue).pipe(
|
|
123
|
+
Stream.filter((_) => Schema.is(Schema.toEncoded(WindowMessageListen))(_.data)),
|
|
110
124
|
Stream.map((_) => {
|
|
111
125
|
debugInfo.listenTotal++
|
|
112
|
-
return Schema.
|
|
126
|
+
return Schema.decodeResult(schema.listen)(_.data.message)
|
|
113
127
|
}),
|
|
114
128
|
listenToDebugPing('window'),
|
|
115
129
|
)
|
|
116
130
|
|
|
117
|
-
const closedDeferred = yield* Deferred.make<void>()
|
|
131
|
+
const closedDeferred = yield* Effect.acquireRelease(Deferred.make<void>(), Deferred.done(Exit.void))
|
|
118
132
|
const supportsTransferables = true
|
|
119
133
|
|
|
120
134
|
return {
|
|
@@ -7,7 +7,7 @@ Vitest.describe('parseWebError', () => {
|
|
|
7
7
|
const domException = new DOMException('missing node', 'NotFoundError')
|
|
8
8
|
const webError = new WebError.NotFoundError({ cause: domException })
|
|
9
9
|
|
|
10
|
-
const result = WebError.
|
|
10
|
+
const result = WebError.classifyWebError(webError)
|
|
11
11
|
|
|
12
12
|
Vitest.expect(result).toBeInstanceOf(WebError.NotFoundError)
|
|
13
13
|
Vitest.expect(result.cause).toBe(domException)
|
|
@@ -16,7 +16,7 @@ Vitest.describe('parseWebError', () => {
|
|
|
16
16
|
Vitest.it('maps native errors to the corresponding WebError when expected', () => {
|
|
17
17
|
const nativeError = new globalThis.TypeError('unsupported type')
|
|
18
18
|
|
|
19
|
-
const result = WebError.
|
|
19
|
+
const result = WebError.classifyWebError(nativeError, [WebError.TypeError])
|
|
20
20
|
|
|
21
21
|
Vitest.expect(result).toBeInstanceOf(WebError.TypeError)
|
|
22
22
|
Vitest.expect(result.cause).toBe(nativeError)
|
|
@@ -25,7 +25,7 @@ Vitest.describe('parseWebError', () => {
|
|
|
25
25
|
Vitest.it('wraps parsed errors that are not in the expected list in UnknownError', () => {
|
|
26
26
|
const nativeError = new globalThis.RangeError('value out of range')
|
|
27
27
|
|
|
28
|
-
const result = WebError.
|
|
28
|
+
const result = WebError.classifyWebError(nativeError, [WebError.TypeError])
|
|
29
29
|
|
|
30
30
|
Vitest.expect(result).toBeInstanceOf(WebError.UnknownError)
|
|
31
31
|
Vitest.expect(result.cause).toBeInstanceOf(WebError.RangeError)
|
|
@@ -34,7 +34,7 @@ Vitest.describe('parseWebError', () => {
|
|
|
34
34
|
Vitest.it('translates DOMException names into the matching WebError variant', () => {
|
|
35
35
|
const domException = new DOMException('permission denied', 'NotAllowedError')
|
|
36
36
|
|
|
37
|
-
const result = WebError.
|
|
37
|
+
const result = WebError.classifyWebError(domException, [WebError.NotAllowedError])
|
|
38
38
|
|
|
39
39
|
Vitest.expect(result).toBeInstanceOf(WebError.NotAllowedError)
|
|
40
40
|
Vitest.expect(result.cause).toBe(domException)
|
|
@@ -43,7 +43,7 @@ Vitest.describe('parseWebError', () => {
|
|
|
43
43
|
Vitest.it('produces UnknownError for non-error values with the default message', () => {
|
|
44
44
|
const value = { reason: 'unexpected' }
|
|
45
45
|
|
|
46
|
-
const result = WebError.
|
|
46
|
+
const result = WebError.classifyWebError(value)
|
|
47
47
|
|
|
48
48
|
Vitest.expect(result).toBeInstanceOf(WebError.UnknownError)
|
|
49
49
|
Vitest.expect(result.cause).toBeDefined()
|
|
@@ -53,7 +53,7 @@ Vitest.describe('parseWebError', () => {
|
|
|
53
53
|
Vitest.it('returns UnknownError instances without altering their payload when expectations are provided', () => {
|
|
54
54
|
const existing = new WebError.UnknownError({ description: 'pre-parsed' })
|
|
55
55
|
|
|
56
|
-
const result = WebError.
|
|
56
|
+
const result = WebError.classifyWebError(existing, [WebError.TypeError])
|
|
57
57
|
|
|
58
58
|
Vitest.expect(result).toBeInstanceOf(WebError.UnknownError)
|
|
59
59
|
|