@livestore/common-cf 0.4.0-dev.5 → 0.4.0-dev.7

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.
@@ -8,24 +8,29 @@ import {
8
8
  RpcSerialization,
9
9
  Stream,
10
10
  } from '@livestore/utils/effect'
11
- import { startWranglerDevServerPromise } from '@livestore/utils-dev/node'
11
+ import { PlatformNode } from '@livestore/utils/node'
12
+ import { WranglerDevServerService } from '@livestore/utils-dev/node'
12
13
  import { Vitest } from '@livestore/utils-dev/node-vitest'
13
- import { beforeAll, expect } from 'vitest'
14
+ import { expect } from 'vitest'
14
15
  import { TestRpcs } from './test-fixtures/rpc-schema.ts'
15
16
 
16
- let port: number
17
+ const testTimeout = 60_000
17
18
 
18
- beforeAll(async () => {
19
- const { port: wranglerPort } = await startWranglerDevServerPromise({
20
- cwd: `${import.meta.dirname}/test-fixtures`,
21
- })
22
- port = wranglerPort
19
+ const withWranglerTest = Vitest.makeWithTestCtx({
20
+ timeout: testTimeout,
21
+ makeLayer: () =>
22
+ WranglerDevServerService.Default({
23
+ cwd: `${import.meta.dirname}/test-fixtures`,
24
+ }).pipe(Layer.provide(PlatformNode.NodeContext.layer), Layer.provide(FetchHttpClient.layer)),
23
25
  })
24
26
 
25
27
  const ProtocolLive = Layer.suspend(() =>
26
- RpcClient.layerProtocolHttp({
27
- url: `http://localhost:${port}/rpc`,
28
- }).pipe(Layer.provide([FetchHttpClient.layer, RpcSerialization.layerJson])),
28
+ Effect.gen(function* () {
29
+ const server = yield* WranglerDevServerService
30
+ return RpcClient.layerProtocolHttp({
31
+ url: `${server.url}/rpc`,
32
+ }).pipe(Layer.provide([FetchHttpClient.layer, RpcSerialization.layerJson]))
33
+ }).pipe(Layer.unwrapEffect),
29
34
  )
30
35
 
31
36
  /**
@@ -46,38 +51,34 @@ const ProtocolLive = Layer.suspend(() =>
46
51
  * Test Path: Test → Worker /rpc → Server DO (HTTP RPC)
47
52
  */
48
53
 
49
- Vitest.describe('Durable Object RPC', { timeout: 5000 }, () => {
54
+ Vitest.describe('Durable Object RPC', { timeout: testTimeout }, () => {
50
55
  // Direct HTTP RPC client tests
51
- Vitest.scopedLive(
52
- 'should call ping method',
53
- Effect.fn(function* () {
56
+ Vitest.scopedLive('should call ping method', (test) =>
57
+ Effect.gen(function* () {
54
58
  const client = yield* RpcClient.make(TestRpcs)
55
59
  const result = yield* client.Ping({ message: 'Hello HTTP RPC' })
56
60
  expect(result).toEqual({ response: 'Pong: Hello HTTP RPC' })
57
- }, Effect.provide(ProtocolLive)),
61
+ }).pipe(Effect.provide(ProtocolLive), withWranglerTest(test)),
58
62
  )
59
63
 
60
- Vitest.scopedLive(
61
- 'should call echo method',
62
- Effect.fn(function* () {
64
+ Vitest.scopedLive('should call echo method', (test) =>
65
+ Effect.gen(function* () {
63
66
  const client = yield* RpcClient.make(TestRpcs)
64
67
  const result = yield* client.Echo({ text: 'Echo' })
65
68
  expect(result).toEqual({ echo: 'Echo: Echo' })
66
- }, Effect.provide(ProtocolLive)),
69
+ }).pipe(Effect.provide(ProtocolLive), withWranglerTest(test)),
67
70
  )
68
71
 
69
- Vitest.scopedLive(
70
- 'should call add method',
71
- Effect.fn(function* () {
72
+ Vitest.scopedLive('should call add method', (test) =>
73
+ Effect.gen(function* () {
72
74
  const client = yield* RpcClient.make(TestRpcs)
73
75
  const result = yield* client.Add({ a: 15, b: 25 })
74
76
  expect(result).toEqual({ result: 40 })
75
- }, Effect.provide(ProtocolLive)),
77
+ }).pipe(Effect.provide(ProtocolLive), withWranglerTest(test)),
76
78
  )
77
79
 
78
- Vitest.scopedLive(
79
- 'should handle RPC fail method',
80
- Effect.fn(function* () {
80
+ Vitest.scopedLive('should handle RPC fail method', (test) =>
81
+ Effect.gen(function* () {
81
82
  const client = yield* RpcClient.make(TestRpcs)
82
83
  const error = yield* client.Fail({ message: 'test http failure' }).pipe(Effect.exit)
83
84
  expect(error.toString()).toMatchInlineSnapshot(`
@@ -91,12 +92,11 @@ Vitest.describe('Durable Object RPC', { timeout: 5000 }, () => {
91
92
  }
92
93
  }"
93
94
  `)
94
- }, Effect.provide(ProtocolLive)),
95
+ }).pipe(Effect.provide(ProtocolLive), withWranglerTest(test)),
95
96
  )
96
97
 
97
- Vitest.scopedLive(
98
- 'should handle defect method',
99
- Effect.fn(function* () {
98
+ Vitest.scopedLive('should handle defect method', (test) =>
99
+ Effect.gen(function* () {
100
100
  const client = yield* RpcClient.make(TestRpcs)
101
101
  const error = yield* client.Defect({ message: 'test http defect' }).pipe(Effect.exit)
102
102
  expect(error.toString()).toMatchInlineSnapshot(`
@@ -110,12 +110,11 @@ Vitest.describe('Durable Object RPC', { timeout: 5000 }, () => {
110
110
  }
111
111
  }"
112
112
  `)
113
- }, Effect.provide(ProtocolLive)),
113
+ }).pipe(Effect.provide(ProtocolLive), withWranglerTest(test)),
114
114
  )
115
115
 
116
- Vitest.scopedLive(
117
- 'should handle streaming RPC via HTTP',
118
- Effect.fn(function* () {
116
+ Vitest.scopedLive('should handle streaming RPC via HTTP', (test) =>
117
+ Effect.gen(function* () {
119
118
  const client = yield* RpcClient.make(TestRpcs)
120
119
  const stream = client.Stream({}).pipe(
121
120
  Stream.take(4),
@@ -123,12 +122,11 @@ Vitest.describe('Durable Object RPC', { timeout: 5000 }, () => {
123
122
  )
124
123
  const chunks = yield* Stream.runCollect(stream)
125
124
  expect(Chunk.toReadonlyArray(chunks)).toEqual([1, 4, 9, 16]) // squares of 1,2,3,4
126
- }, Effect.provide(ProtocolLive)),
125
+ }).pipe(Effect.provide(ProtocolLive), withWranglerTest(test)),
127
126
  )
128
127
 
129
- Vitest.scopedLive(
130
- 'should handle streaming RPC with error via HTTP',
131
- Effect.fn(function* () {
128
+ Vitest.scopedLive('should handle streaming RPC with error via HTTP', (test) =>
129
+ Effect.gen(function* () {
132
130
  const client = yield* RpcClient.make(TestRpcs)
133
131
  const stream = client.StreamError({ count: 5, errorAfter: 4 })
134
132
  const error = yield* Stream.runCollect(stream).pipe(Effect.exit)
@@ -143,12 +141,11 @@ Vitest.describe('Durable Object RPC', { timeout: 5000 }, () => {
143
141
  }
144
142
  }"
145
143
  `)
146
- }, Effect.provide(ProtocolLive)),
144
+ }).pipe(Effect.provide(ProtocolLive), withWranglerTest(test)),
147
145
  )
148
146
 
149
- Vitest.scopedLive(
150
- 'should handle streaming RPC with defect via HTTP',
151
- Effect.fn(function* () {
147
+ Vitest.scopedLive('should handle streaming RPC with defect via HTTP', (test) =>
148
+ Effect.gen(function* () {
152
149
  const client = yield* RpcClient.make(TestRpcs)
153
150
  const stream = client.StreamDefect({ count: 4, defectAfter: 1 })
154
151
  const error = yield* Stream.runCollect(stream).pipe(Effect.exit)
@@ -163,23 +160,21 @@ Vitest.describe('Durable Object RPC', { timeout: 5000 }, () => {
163
160
  }
164
161
  }"
165
162
  `)
166
- }, Effect.provide(ProtocolLive)),
163
+ }).pipe(Effect.provide(ProtocolLive), withWranglerTest(test)),
167
164
  )
168
165
 
169
- Vitest.scopedLive(
170
- 'should handle stream interruption via HTTP',
171
- Effect.fn(function* () {
166
+ Vitest.scopedLive('should handle stream interruption via HTTP', (test) =>
167
+ Effect.gen(function* () {
172
168
  const client = yield* RpcClient.make(TestRpcs)
173
169
  const stream = client.StreamInterruptible({ delay: 50, interruptAfterCount: 3 }).pipe(Stream.take(3))
174
170
  const chunks = yield* Stream.runCollect(stream)
175
171
  expect(Chunk.toReadonlyArray(chunks)).toEqual([1, 2, 3])
176
- }, Effect.provide(ProtocolLive)),
172
+ }).pipe(Effect.provide(ProtocolLive), withWranglerTest(test)),
177
173
  )
178
174
 
179
175
  // TODO @IMax153
180
- Vitest.scopedLive.skip(
181
- 'should handle streaming RPC bug scenario',
182
- Effect.fn(function* () {
176
+ Vitest.scopedLive.skip('should handle streaming RPC bug scenario', (test) =>
177
+ Effect.gen(function* () {
183
178
  const client = yield* RpcClient.make(TestRpcs)
184
179
  yield* client.StreamBugScenarioDoClient({})
185
180
  /*
@@ -230,6 +225,6 @@ Vitest.describe('Durable Object RPC', { timeout: 5000 }, () => {
230
225
  ```
231
226
 
232
227
  */
233
- }, Effect.provide(ProtocolLive)),
228
+ }).pipe(Effect.provide(ProtocolLive), withWranglerTest(test)),
234
229
  )
235
230
  })
@@ -15,7 +15,7 @@
15
15
  * @see {@link https://developers.cloudflare.com/durable-objects/best-practices/websockets/ Cloudflare WebSocket Best Practices}
16
16
  */
17
17
 
18
- import { notYetImplemented } from '@livestore/utils'
18
+ import { notYetImplemented, omitUndefineds } from '@livestore/utils'
19
19
  import {
20
20
  constVoid,
21
21
  Effect,
@@ -147,7 +147,7 @@ export const setupDurableObjectWebSocketRpc = ({
147
147
  const ProtocolLive = layerRpcServerWebsocket({
148
148
  ws,
149
149
  incomingQueue,
150
- onMessage,
150
+ ...omitUndefineds({ onMessage }),
151
151
  }).pipe(Layer.provide(RpcSerialization.layerJson))
152
152
 
153
153
  const ServerLive = rpcLayer.pipe(Layer.provide(ProtocolLive))
@@ -1,58 +1,69 @@
1
- import { Chunk, Effect, Layer, Option, RpcClient, RpcSerialization, Socket, Stream } from '@livestore/utils/effect'
2
- import { startWranglerDevServerPromise } from '@livestore/utils-dev/node'
1
+ import {
2
+ Chunk,
3
+ Effect,
4
+ FetchHttpClient,
5
+ Layer,
6
+ Option,
7
+ RpcClient,
8
+ RpcSerialization,
9
+ Socket,
10
+ Stream,
11
+ } from '@livestore/utils/effect'
12
+ import { PlatformNode } from '@livestore/utils/node'
13
+ import { WranglerDevServerService } from '@livestore/utils-dev/node'
3
14
  import { Vitest } from '@livestore/utils-dev/node-vitest'
4
- import { beforeAll, expect } from 'vitest'
15
+ import { expect } from 'vitest'
5
16
  import { TestRpcs } from './test-fixtures/rpc-schema.ts'
6
17
 
7
- let port: number
18
+ const testTimeout = 60_000
8
19
 
9
- beforeAll(async () => {
10
- const { port: wranglerPort } = await startWranglerDevServerPromise({
11
- cwd: `${import.meta.dirname}/test-fixtures`,
12
- })
13
- port = wranglerPort
20
+ const withWranglerTest = Vitest.makeWithTestCtx({
21
+ timeout: testTimeout,
22
+ makeLayer: () =>
23
+ WranglerDevServerService.Default({
24
+ cwd: `${import.meta.dirname}/test-fixtures`,
25
+ }).pipe(Layer.provide(PlatformNode.NodeContext.layer), Layer.provide(FetchHttpClient.layer)),
14
26
  })
15
27
 
16
28
  const ProtocolLive = Layer.suspend(() =>
17
- RpcClient.layerProtocolSocket().pipe(
18
- Layer.provide(Socket.layerWebSocket(`ws://localhost:${port}`)),
19
- Layer.provide(Socket.layerWebSocketConstructorGlobal),
20
- Layer.provide(RpcSerialization.layerJson),
21
- ),
29
+ Effect.gen(function* () {
30
+ const server = yield* WranglerDevServerService
31
+ return RpcClient.layerProtocolSocket().pipe(
32
+ Layer.provide(Socket.layerWebSocket(`ws://localhost:${server.port}`)),
33
+ Layer.provide(Socket.layerWebSocketConstructorGlobal),
34
+ Layer.provide(RpcSerialization.layerJson),
35
+ )
36
+ }).pipe(Layer.unwrapEffect),
22
37
  )
23
38
 
24
- Vitest.describe('Durable Object WebSocket RPC', { timeout: 5000 }, () => {
39
+ Vitest.describe('Durable Object WebSocket RPC', { timeout: testTimeout }, () => {
25
40
  // Direct HTTP RPC client tests
26
- Vitest.scopedLive(
27
- 'should call ping method',
28
- Effect.fn(function* () {
41
+ Vitest.scopedLive('should call ping method', (test) =>
42
+ Effect.gen(function* () {
29
43
  const client = yield* RpcClient.make(TestRpcs)
30
44
  const result = yield* client.Ping({ message: 'Hello HTTP RPC' })
31
45
  expect(result).toEqual({ response: 'Pong: Hello HTTP RPC' })
32
- }, Effect.provide(ProtocolLive)),
46
+ }).pipe(Effect.provide(ProtocolLive), withWranglerTest(test)),
33
47
  )
34
48
 
35
- Vitest.scopedLive(
36
- 'should call echo method',
37
- Effect.fn(function* () {
49
+ Vitest.scopedLive('should call echo method', (test) =>
50
+ Effect.gen(function* () {
38
51
  const client = yield* RpcClient.make(TestRpcs)
39
52
  const result = yield* client.Echo({ text: 'Echo' })
40
53
  expect(result).toEqual({ echo: 'Echo: Echo' })
41
- }, Effect.provide(ProtocolLive)),
54
+ }).pipe(Effect.provide(ProtocolLive), withWranglerTest(test)),
42
55
  )
43
56
 
44
- Vitest.scopedLive(
45
- 'should call add method',
46
- Effect.fn(function* () {
57
+ Vitest.scopedLive('should call add method', (test) =>
58
+ Effect.gen(function* () {
47
59
  const client = yield* RpcClient.make(TestRpcs)
48
60
  const result = yield* client.Add({ a: 15, b: 25 })
49
61
  expect(result).toEqual({ result: 40 })
50
- }, Effect.provide(ProtocolLive)),
62
+ }).pipe(Effect.provide(ProtocolLive), withWranglerTest(test)),
51
63
  )
52
64
 
53
- Vitest.scopedLive(
54
- 'should handle RPC fail method',
55
- Effect.fn(function* () {
65
+ Vitest.scopedLive('should handle RPC fail method', (test) =>
66
+ Effect.gen(function* () {
56
67
  const client = yield* RpcClient.make(TestRpcs)
57
68
  const error = yield* client.Fail({ message: 'test http failure' }).pipe(Effect.exit)
58
69
  expect(error.toString()).toMatchInlineSnapshot(`
@@ -66,12 +77,11 @@ Vitest.describe('Durable Object WebSocket RPC', { timeout: 5000 }, () => {
66
77
  }
67
78
  }"
68
79
  `)
69
- }, Effect.provide(ProtocolLive)),
80
+ }).pipe(Effect.provide(ProtocolLive), withWranglerTest(test)),
70
81
  )
71
82
 
72
- Vitest.scopedLive(
73
- 'should handle defect method',
74
- Effect.fn(function* () {
83
+ Vitest.scopedLive('should handle defect method', (test) =>
84
+ Effect.gen(function* () {
75
85
  const client = yield* RpcClient.make(TestRpcs)
76
86
  const error = yield* client.Defect({ message: 'test http defect' }).pipe(Effect.exit)
77
87
  expect(error.toString()).toMatchInlineSnapshot(`
@@ -85,12 +95,11 @@ Vitest.describe('Durable Object WebSocket RPC', { timeout: 5000 }, () => {
85
95
  }
86
96
  }"
87
97
  `)
88
- }, Effect.provide(ProtocolLive)),
98
+ }).pipe(Effect.provide(ProtocolLive), withWranglerTest(test)),
89
99
  )
90
100
 
91
- Vitest.scopedLive(
92
- 'should handle streaming RPC via HTTP',
93
- Effect.fn(function* () {
101
+ Vitest.scopedLive('should handle streaming RPC via HTTP', (test) =>
102
+ Effect.gen(function* () {
94
103
  const client = yield* RpcClient.make(TestRpcs)
95
104
  const stream = client.Stream({}).pipe(
96
105
  Stream.take(4),
@@ -98,12 +107,11 @@ Vitest.describe('Durable Object WebSocket RPC', { timeout: 5000 }, () => {
98
107
  )
99
108
  const chunks = yield* Stream.runCollect(stream)
100
109
  expect(Chunk.toReadonlyArray(chunks)).toEqual([1, 4, 9, 16]) // squares of 1,2,3,4
101
- }, Effect.provide(ProtocolLive)),
110
+ }).pipe(Effect.provide(ProtocolLive), withWranglerTest(test)),
102
111
  )
103
112
 
104
- Vitest.scopedLive(
105
- 'should handle streaming RPC with error via HTTP',
106
- Effect.fn(function* () {
113
+ Vitest.scopedLive('should handle streaming RPC with error via HTTP', (test) =>
114
+ Effect.gen(function* () {
107
115
  const client = yield* RpcClient.make(TestRpcs)
108
116
  const stream = client.StreamError({ count: 5, errorAfter: 4 })
109
117
  const error = yield* Stream.runCollect(stream).pipe(Effect.exit)
@@ -118,12 +126,11 @@ Vitest.describe('Durable Object WebSocket RPC', { timeout: 5000 }, () => {
118
126
  }
119
127
  }"
120
128
  `)
121
- }, Effect.provide(ProtocolLive)),
129
+ }).pipe(Effect.provide(ProtocolLive), withWranglerTest(test)),
122
130
  )
123
131
 
124
- Vitest.scopedLive(
125
- 'should handle streaming RPC with defect via HTTP',
126
- Effect.fn(function* () {
132
+ Vitest.scopedLive('should handle streaming RPC with defect via HTTP', (test) =>
133
+ Effect.gen(function* () {
127
134
  const client = yield* RpcClient.make(TestRpcs)
128
135
  const stream = client.StreamDefect({ count: 4, defectAfter: 1 })
129
136
  const error = yield* Stream.runCollect(stream).pipe(Effect.exit)
@@ -138,24 +145,22 @@ Vitest.describe('Durable Object WebSocket RPC', { timeout: 5000 }, () => {
138
145
  }
139
146
  }"
140
147
  `)
141
- }, Effect.provide(ProtocolLive)),
148
+ }).pipe(Effect.provide(ProtocolLive), withWranglerTest(test)),
142
149
  )
143
150
 
144
- Vitest.scopedLive(
145
- 'should handle stream interruption via HTTP',
146
- Effect.fn(function* () {
151
+ Vitest.scopedLive('should handle stream interruption via HTTP', (test) =>
152
+ Effect.gen(function* () {
147
153
  const client = yield* RpcClient.make(TestRpcs)
148
154
  const stream = client.StreamInterruptible({ delay: 50, interruptAfterCount: 3 }).pipe(Stream.take(3))
149
155
  const chunks = yield* Stream.runCollect(stream)
150
156
  expect(Chunk.toReadonlyArray(chunks)).toEqual([1, 2, 3])
151
- }, Effect.provide(ProtocolLive)),
157
+ }).pipe(Effect.provide(ProtocolLive), withWranglerTest(test)),
152
158
  )
153
159
  })
154
160
 
155
161
  Vitest.describe('Hibernation Tests', { timeout: 25000 }, () => {
156
- Vitest.scopedLive(
157
- 'should maintain RPC functionality after hibernation',
158
- Effect.fn(function* () {
162
+ Vitest.scopedLive('should maintain RPC functionality after hibernation', (test) =>
163
+ Effect.gen(function* () {
159
164
  console.log('🧪 Testing RPC server persistence across hibernation...')
160
165
 
161
166
  // Step 1: Create client and test initial functionality
@@ -214,12 +219,11 @@ Vitest.describe('Hibernation Tests', { timeout: 25000 }, () => {
214
219
  console.log('✅ Streaming after hibernation successful')
215
220
 
216
221
  console.log('🎉 All RPC operations successful after hibernation!')
217
- }, Effect.provide(ProtocolLive)),
222
+ }).pipe(Effect.provide(ProtocolLive), withWranglerTest(test)),
218
223
  )
219
224
 
220
- Vitest.scopedLive(
221
- 'should handle rapid operations after hibernation',
222
- Effect.fn(function* () {
225
+ Vitest.scopedLive('should handle rapid operations after hibernation', (test) =>
226
+ Effect.gen(function* () {
223
227
  console.log('🧪 Testing rapid operations after hibernation...')
224
228
 
225
229
  console.log('Step 1: Establishing initial connection...')
@@ -266,6 +270,6 @@ Vitest.describe('Hibernation Tests', { timeout: 25000 }, () => {
266
270
  results.map((r) => r.operation),
267
271
  )
268
272
  console.log('🎉 Rapid operations work correctly after hibernation!')
269
- }, Effect.provide(ProtocolLive)),
273
+ }).pipe(Effect.provide(ProtocolLive), withWranglerTest(test)),
270
274
  )
271
275
  })