@livestore/utils-dev 0.0.0-snapshot-e5a7caabcf7660aefa55568a44ed0fe306d00597 → 0.0.0-snapshot-9d8807d2c51c95b4df3556744702cea55dc7ded3
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.json +1 -1
- package/dist/node/mod.d.ts +13 -5
- package/dist/node/mod.d.ts.map +1 -1
- package/dist/node/mod.js +42 -67
- package/dist/node/mod.js.map +1 -1
- package/dist/node-vitest/mod.d.ts +1 -2
- package/dist/node-vitest/mod.d.ts.map +1 -1
- package/dist/node-vitest/mod.js +1 -2
- package/dist/node-vitest/mod.js.map +1 -1
- package/dist/node-vitest/polyfill.d.ts +2 -0
- package/dist/node-vitest/polyfill.d.ts.map +1 -0
- package/dist/node-vitest/{global.js → polyfill.js} +1 -1
- package/dist/node-vitest/polyfill.js.map +1 -0
- package/package.json +22 -16
- package/src/node/mod.ts +82 -81
- package/src/node-vitest/mod.ts +1 -3
- package/dist/node/DockerComposeService/DockerComposeService.d.ts +0 -58
- package/dist/node/DockerComposeService/DockerComposeService.d.ts.map +0 -1
- package/dist/node/DockerComposeService/DockerComposeService.js +0 -144
- package/dist/node/DockerComposeService/DockerComposeService.js.map +0 -1
- package/dist/node/DockerComposeService/DockerComposeService.test.d.ts +0 -2
- package/dist/node/DockerComposeService/DockerComposeService.test.d.ts.map +0 -1
- package/dist/node/DockerComposeService/DockerComposeService.test.js +0 -64
- package/dist/node/DockerComposeService/DockerComposeService.test.js.map +0 -1
- package/dist/node/FileLogger.d.ts +0 -14
- package/dist/node/FileLogger.d.ts.map +0 -1
- package/dist/node/FileLogger.js +0 -151
- package/dist/node/FileLogger.js.map +0 -1
- package/dist/node/cmd-log.d.ts +0 -21
- package/dist/node/cmd-log.d.ts.map +0 -1
- package/dist/node/cmd-log.js +0 -50
- package/dist/node/cmd-log.js.map +0 -1
- package/dist/node/cmd.d.ts +0 -36
- package/dist/node/cmd.d.ts.map +0 -1
- package/dist/node/cmd.js +0 -234
- package/dist/node/cmd.js.map +0 -1
- package/dist/node/cmd.test.d.ts +0 -2
- package/dist/node/cmd.test.d.ts.map +0 -1
- package/dist/node/cmd.test.js +0 -101
- package/dist/node/cmd.test.js.map +0 -1
- package/dist/node-vitest/Vitest.d.ts +0 -52
- package/dist/node-vitest/Vitest.d.ts.map +0 -1
- package/dist/node-vitest/Vitest.js +0 -98
- package/dist/node-vitest/Vitest.js.map +0 -1
- package/dist/node-vitest/Vitest.test.d.ts +0 -2
- package/dist/node-vitest/Vitest.test.d.ts.map +0 -1
- package/dist/node-vitest/Vitest.test.js +0 -70
- package/dist/node-vitest/Vitest.test.js.map +0 -1
- package/dist/node-vitest/global.d.ts +0 -2
- package/dist/node-vitest/global.d.ts.map +0 -1
- package/dist/node-vitest/global.js.map +0 -1
- package/dist/wrangler/WranglerDevServer.d.ts +0 -52
- package/dist/wrangler/WranglerDevServer.d.ts.map +0 -1
- package/dist/wrangler/WranglerDevServer.js +0 -90
- package/dist/wrangler/WranglerDevServer.js.map +0 -1
- package/dist/wrangler/WranglerDevServer.test.d.ts +0 -2
- package/dist/wrangler/WranglerDevServer.test.d.ts.map +0 -1
- package/dist/wrangler/WranglerDevServer.test.js +0 -77
- package/dist/wrangler/WranglerDevServer.test.js.map +0 -1
- package/dist/wrangler/fixtures/cf-worker.d.ts +0 -8
- package/dist/wrangler/fixtures/cf-worker.d.ts.map +0 -1
- package/dist/wrangler/fixtures/cf-worker.js +0 -11
- package/dist/wrangler/fixtures/cf-worker.js.map +0 -1
- package/dist/wrangler/mod.d.ts +0 -2
- package/dist/wrangler/mod.d.ts.map +0 -1
- package/dist/wrangler/mod.js +0 -2
- package/dist/wrangler/mod.js.map +0 -1
- package/src/node/DockerComposeService/DockerComposeService.test.ts +0 -91
- package/src/node/DockerComposeService/DockerComposeService.ts +0 -328
- package/src/node/DockerComposeService/test-fixtures/docker-compose.yml +0 -4
- package/src/node/FileLogger.ts +0 -206
- package/src/node/cmd-log.ts +0 -92
- package/src/node/cmd.test.ts +0 -129
- package/src/node/cmd.ts +0 -419
- package/src/node-vitest/Vitest.test.ts +0 -112
- package/src/node-vitest/Vitest.ts +0 -238
- package/src/wrangler/WranglerDevServer.test.ts +0 -133
- package/src/wrangler/WranglerDevServer.ts +0 -180
- package/src/wrangler/fixtures/cf-worker.ts +0 -11
- package/src/wrangler/fixtures/wrangler.toml +0 -11
- package/src/wrangler/mod.ts +0 -6
- /package/src/node-vitest/{global.ts → polyfill.ts} +0 -0
|
@@ -1,238 +0,0 @@
|
|
|
1
|
-
import * as inspector from 'node:inspector'
|
|
2
|
-
import type * as Vitest from '@effect/vitest'
|
|
3
|
-
import { IS_CI } from '@livestore/utils'
|
|
4
|
-
import {
|
|
5
|
-
type Cause,
|
|
6
|
-
Duration,
|
|
7
|
-
Effect,
|
|
8
|
-
type FastCheck as FC,
|
|
9
|
-
identity,
|
|
10
|
-
Layer,
|
|
11
|
-
type OtelTracer,
|
|
12
|
-
Predicate,
|
|
13
|
-
type Schema,
|
|
14
|
-
type Scope,
|
|
15
|
-
} from '@livestore/utils/effect'
|
|
16
|
-
import { OtelLiveDummy } from '@livestore/utils/node'
|
|
17
|
-
import { OtelLiveHttp } from '../node/mod.ts'
|
|
18
|
-
|
|
19
|
-
export * from '@effect/vitest'
|
|
20
|
-
|
|
21
|
-
export const DEBUGGER_ACTIVE = Boolean(process.env.DEBUGGER_ACTIVE ?? inspector.url() !== undefined)
|
|
22
|
-
|
|
23
|
-
export const makeWithTestCtx: <ROut = never, E1 = never, RIn = never>(
|
|
24
|
-
ctxParams: WithTestCtxParams<ROut, E1, RIn>,
|
|
25
|
-
) => (testContext: Vitest.TestContext) => <A, E, R>(
|
|
26
|
-
self: Effect.Effect<A, E, R>,
|
|
27
|
-
) => Effect.Effect<
|
|
28
|
-
A,
|
|
29
|
-
E | E1 | Cause.TimeoutException,
|
|
30
|
-
// Exclude dependencies provided by `withTestCtx` from the layer dependencies
|
|
31
|
-
| Exclude<RIn, OtelTracer.OtelTracer | Scope.Scope>
|
|
32
|
-
// Exclude dependencies provided by `withTestCtx` **and** dependencies produced
|
|
33
|
-
// by the layer from the effect dependencies
|
|
34
|
-
| Exclude<R, ROut | OtelTracer.OtelTracer | Scope.Scope>
|
|
35
|
-
> = (ctxParams) => (testContext: Vitest.TestContext) => withTestCtx(testContext, ctxParams)
|
|
36
|
-
|
|
37
|
-
export type WithTestCtxParams<ROut, E1, RIn> = {
|
|
38
|
-
suffix?: string
|
|
39
|
-
makeLayer?: (testContext: Vitest.TestContext) => Layer.Layer<ROut, E1, RIn | Scope.Scope>
|
|
40
|
-
timeout?: Duration.DurationInput
|
|
41
|
-
forceOtel?: boolean
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
export const withTestCtx =
|
|
45
|
-
<ROut = never, E1 = never, RIn = never>(
|
|
46
|
-
testContext: Vitest.TestContext,
|
|
47
|
-
{
|
|
48
|
-
suffix,
|
|
49
|
-
makeLayer,
|
|
50
|
-
timeout = IS_CI ? 60_000 : 10_000,
|
|
51
|
-
forceOtel = false,
|
|
52
|
-
}: {
|
|
53
|
-
suffix?: string
|
|
54
|
-
makeLayer?: (testContext: Vitest.TestContext) => Layer.Layer<ROut, E1, RIn>
|
|
55
|
-
timeout?: Duration.DurationInput
|
|
56
|
-
forceOtel?: boolean
|
|
57
|
-
} = {},
|
|
58
|
-
) =>
|
|
59
|
-
<A, E, R>(
|
|
60
|
-
self: Effect.Effect<A, E, R>,
|
|
61
|
-
): Effect.Effect<
|
|
62
|
-
A,
|
|
63
|
-
E | E1 | Cause.TimeoutException,
|
|
64
|
-
// Exclude dependencies provided internally from the provided layer's dependencies
|
|
65
|
-
| Exclude<RIn, OtelTracer.OtelTracer | Scope.Scope>
|
|
66
|
-
// Exclude dependencies provided internally **and** dependencies produced by the
|
|
67
|
-
// provided layer from the effect dependencies
|
|
68
|
-
| Exclude<R, ROut | OtelTracer.OtelTracer | Scope.Scope>
|
|
69
|
-
> => {
|
|
70
|
-
const spanName = `${testContext.task.suite?.name}:${testContext.task.name}${suffix ? `:${suffix}` : ''}`
|
|
71
|
-
const layer = makeLayer?.(testContext) ?? Layer.empty
|
|
72
|
-
|
|
73
|
-
const otelLayer =
|
|
74
|
-
DEBUGGER_ACTIVE || forceOtel
|
|
75
|
-
? OtelLiveHttp({ rootSpanName: spanName, serviceName: 'vitest-runner', skipLogUrl: false })
|
|
76
|
-
: OtelLiveDummy
|
|
77
|
-
|
|
78
|
-
const combinedLayer = layer.pipe(Layer.provideMerge(otelLayer))
|
|
79
|
-
|
|
80
|
-
return self.pipe(
|
|
81
|
-
DEBUGGER_ACTIVE
|
|
82
|
-
? identity
|
|
83
|
-
: Effect.logWarnIfTakesLongerThan({
|
|
84
|
-
duration: Duration.toMillis(timeout) * 0.8,
|
|
85
|
-
label: `${spanName} approaching timeout (timeout: ${Duration.format(timeout)})`,
|
|
86
|
-
}),
|
|
87
|
-
DEBUGGER_ACTIVE ? identity : Effect.timeout(timeout),
|
|
88
|
-
Effect.provide(combinedLayer),
|
|
89
|
-
Effect.scoped, // We need to scope the effect manually here because otherwise the span is not closed
|
|
90
|
-
Effect.annotateLogs({ suffix }),
|
|
91
|
-
) as any
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
/**
|
|
95
|
-
* Shared properties for all enhanced test context phases
|
|
96
|
-
*/
|
|
97
|
-
export interface EnhancedTestContextBase {
|
|
98
|
-
numRuns: number
|
|
99
|
-
/** 0-based index */
|
|
100
|
-
runIndex: number
|
|
101
|
-
/** Total number of executions including initial runs and shrinking attempts */
|
|
102
|
-
totalExecutions: number
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
/**
|
|
106
|
-
* Enhanced context for property-based tests that includes shrinking phase information
|
|
107
|
-
*/
|
|
108
|
-
export type EnhancedTestContext =
|
|
109
|
-
| (EnhancedTestContextBase & {
|
|
110
|
-
_tag: 'initial'
|
|
111
|
-
})
|
|
112
|
-
| (EnhancedTestContextBase & {
|
|
113
|
-
_tag: 'shrinking'
|
|
114
|
-
/** Number of shrinking attempts */
|
|
115
|
-
shrinkAttempt: number
|
|
116
|
-
})
|
|
117
|
-
|
|
118
|
-
/**
|
|
119
|
-
* Normalizes propOptions to ensure @effect/vitest receives correct fastCheck structure
|
|
120
|
-
*/
|
|
121
|
-
const normalizePropOptions = <Arbs extends Vitest.Vitest.Arbitraries>(
|
|
122
|
-
propOptions:
|
|
123
|
-
| number
|
|
124
|
-
| (Vitest.TestOptions & {
|
|
125
|
-
fastCheck?: FC.Parameters<{
|
|
126
|
-
[K in keyof Arbs]: Arbs[K] extends FC.Arbitrary<infer T> ? T : Schema.Schema.Type<Arbs[K]>
|
|
127
|
-
}>
|
|
128
|
-
}),
|
|
129
|
-
): Vitest.TestOptions & {
|
|
130
|
-
fastCheck?: FC.Parameters<{
|
|
131
|
-
[K in keyof Arbs]: Arbs[K] extends FC.Arbitrary<infer T> ? T : Schema.Schema.Type<Arbs[K]>
|
|
132
|
-
}>
|
|
133
|
-
} => {
|
|
134
|
-
// If it's a number, treat as timeout and add our default fastCheck
|
|
135
|
-
if (!Predicate.isObject(propOptions)) {
|
|
136
|
-
return {
|
|
137
|
-
timeout: propOptions,
|
|
138
|
-
fastCheck: { numRuns: 100 },
|
|
139
|
-
}
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
// If no fastCheck property, add it with our default numRuns
|
|
143
|
-
if (!propOptions.fastCheck) {
|
|
144
|
-
return {
|
|
145
|
-
...propOptions,
|
|
146
|
-
fastCheck: { numRuns: 100 },
|
|
147
|
-
}
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
// If fastCheck exists but no numRuns, add our default
|
|
151
|
-
if (propOptions.fastCheck && !propOptions.fastCheck.numRuns) {
|
|
152
|
-
return {
|
|
153
|
-
...propOptions,
|
|
154
|
-
fastCheck: {
|
|
155
|
-
...propOptions.fastCheck,
|
|
156
|
-
numRuns: 100,
|
|
157
|
-
},
|
|
158
|
-
}
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
// If everything is properly structured, pass through
|
|
162
|
-
return propOptions
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
/**
|
|
166
|
-
* Equivalent to Vitest.prop but provides enhanced context including shrinking progress visibility
|
|
167
|
-
*
|
|
168
|
-
* This function enhances the standard property-based testing by providing clear information about
|
|
169
|
-
* whether FastCheck is in the initial testing phase or the shrinking phase, solving the confusion
|
|
170
|
-
* where tests show "Run 26/6" when FastCheck's shrinking algorithm is active.
|
|
171
|
-
*
|
|
172
|
-
* TODO: allow for upper timelimit instead of / additional to `numRuns`
|
|
173
|
-
*
|
|
174
|
-
* TODO: Upstream to Effect
|
|
175
|
-
*/
|
|
176
|
-
export const asProp = <Arbs extends Vitest.Vitest.Arbitraries, A, E, R>(
|
|
177
|
-
api: Vitest.Vitest.Tester<R>,
|
|
178
|
-
name: string,
|
|
179
|
-
arbitraries: Arbs,
|
|
180
|
-
test: Vitest.Vitest.TestFunction<
|
|
181
|
-
A,
|
|
182
|
-
E,
|
|
183
|
-
R,
|
|
184
|
-
[
|
|
185
|
-
{ [K in keyof Arbs]: Arbs[K] extends FC.Arbitrary<infer T> ? T : Schema.Schema.Type<Arbs[K]> },
|
|
186
|
-
Vitest.TestContext,
|
|
187
|
-
EnhancedTestContext,
|
|
188
|
-
]
|
|
189
|
-
>,
|
|
190
|
-
propOptions:
|
|
191
|
-
| number
|
|
192
|
-
| (Vitest.TestOptions & {
|
|
193
|
-
fastCheck?: FC.Parameters<{
|
|
194
|
-
[K in keyof Arbs]: Arbs[K] extends FC.Arbitrary<infer T> ? T : Schema.Schema.Type<Arbs[K]>
|
|
195
|
-
}>
|
|
196
|
-
}),
|
|
197
|
-
) => {
|
|
198
|
-
const normalizedPropOptions = normalizePropOptions(propOptions)
|
|
199
|
-
const numRuns = normalizedPropOptions.fastCheck?.numRuns ?? 100
|
|
200
|
-
let runIndex = 0
|
|
201
|
-
let shrinkAttempts = 0
|
|
202
|
-
let totalExecutions = 0
|
|
203
|
-
|
|
204
|
-
return api.prop(
|
|
205
|
-
name,
|
|
206
|
-
arbitraries,
|
|
207
|
-
(properties, ctx) => {
|
|
208
|
-
if (ctx.signal.aborted) {
|
|
209
|
-
return ctx.skip('Test aborted')
|
|
210
|
-
}
|
|
211
|
-
|
|
212
|
-
totalExecutions++
|
|
213
|
-
const isInShrinkingPhase = runIndex >= numRuns
|
|
214
|
-
|
|
215
|
-
if (isInShrinkingPhase) {
|
|
216
|
-
shrinkAttempts++
|
|
217
|
-
}
|
|
218
|
-
|
|
219
|
-
const enhancedContext: EnhancedTestContext = isInShrinkingPhase
|
|
220
|
-
? {
|
|
221
|
-
_tag: 'shrinking',
|
|
222
|
-
numRuns,
|
|
223
|
-
runIndex: runIndex++,
|
|
224
|
-
shrinkAttempt: shrinkAttempts,
|
|
225
|
-
totalExecutions,
|
|
226
|
-
}
|
|
227
|
-
: {
|
|
228
|
-
_tag: 'initial',
|
|
229
|
-
numRuns,
|
|
230
|
-
runIndex: runIndex++,
|
|
231
|
-
totalExecutions,
|
|
232
|
-
}
|
|
233
|
-
|
|
234
|
-
return test(properties, ctx, enhancedContext)
|
|
235
|
-
},
|
|
236
|
-
normalizedPropOptions,
|
|
237
|
-
)
|
|
238
|
-
}
|
|
@@ -1,133 +0,0 @@
|
|
|
1
|
-
import { Effect, FetchHttpClient, Layer } from '@livestore/utils/effect'
|
|
2
|
-
import { getFreePort, PlatformNode } from '@livestore/utils/node'
|
|
3
|
-
import { Vitest } from '@livestore/utils-dev/node-vitest'
|
|
4
|
-
import { expect } from 'vitest'
|
|
5
|
-
import {
|
|
6
|
-
type StartWranglerDevServerArgs,
|
|
7
|
-
WranglerDevServerError,
|
|
8
|
-
WranglerDevServerService,
|
|
9
|
-
} from './WranglerDevServer.ts'
|
|
10
|
-
|
|
11
|
-
const testTimeout = 60_000
|
|
12
|
-
|
|
13
|
-
const WranglerDevServerTest = (args: Partial<StartWranglerDevServerArgs> = {}) =>
|
|
14
|
-
WranglerDevServerService.Default({
|
|
15
|
-
cwd: `${import.meta.dirname}/fixtures`,
|
|
16
|
-
...args,
|
|
17
|
-
}).pipe(Layer.provide(FetchHttpClient.layer))
|
|
18
|
-
|
|
19
|
-
Vitest.describe('WranglerDevServer', { timeout: testTimeout }, () => {
|
|
20
|
-
Vitest.describe('Basic Operations', () => {
|
|
21
|
-
const withBasicTest = (args: Partial<StartWranglerDevServerArgs> = {}) =>
|
|
22
|
-
Vitest.makeWithTestCtx({
|
|
23
|
-
timeout: testTimeout,
|
|
24
|
-
makeLayer: () => WranglerDevServerTest(args).pipe(Layer.provide(PlatformNode.NodeContext.layer)),
|
|
25
|
-
})
|
|
26
|
-
|
|
27
|
-
Vitest.scopedLive('should start wrangler dev server and return port', (test) =>
|
|
28
|
-
Effect.gen(function* () {
|
|
29
|
-
const server = yield* WranglerDevServerService
|
|
30
|
-
|
|
31
|
-
expect(server.port).toBeGreaterThan(0)
|
|
32
|
-
expect(server.url).toMatch(/http:\/\/127.0.0.1:\d+/)
|
|
33
|
-
}).pipe(withBasicTest()(test)),
|
|
34
|
-
)
|
|
35
|
-
|
|
36
|
-
Vitest.scopedLive('should use specified port when provided', (test) =>
|
|
37
|
-
Effect.andThen(getFreePort, (port) =>
|
|
38
|
-
Effect.gen(function* () {
|
|
39
|
-
const server = yield* WranglerDevServerService
|
|
40
|
-
|
|
41
|
-
expect(server.port).toBe(port)
|
|
42
|
-
expect(server.url).toBe(`http://127.0.0.1:${port}`)
|
|
43
|
-
}).pipe(withBasicTest({ preferredPort: port })(test)),
|
|
44
|
-
),
|
|
45
|
-
)
|
|
46
|
-
})
|
|
47
|
-
|
|
48
|
-
Vitest.describe('Error Handling', () => {
|
|
49
|
-
const withErrorTest = (args: Partial<StartWranglerDevServerArgs> = {}) =>
|
|
50
|
-
Vitest.makeWithTestCtx({
|
|
51
|
-
timeout: testTimeout,
|
|
52
|
-
makeLayer: () => WranglerDevServerTest(args).pipe(Layer.provide(PlatformNode.NodeContext.layer)),
|
|
53
|
-
})
|
|
54
|
-
|
|
55
|
-
Vitest.scopedLive('should handle missing wrangler.toml but should timeout', (test) =>
|
|
56
|
-
Effect.gen(function* () {
|
|
57
|
-
const error = yield* WranglerDevServerService.pipe(
|
|
58
|
-
Effect.provide(
|
|
59
|
-
WranglerDevServerTest({
|
|
60
|
-
cwd: '/tmp',
|
|
61
|
-
wranglerConfigPath: '/dev/null',
|
|
62
|
-
connectTimeout: '500 millis',
|
|
63
|
-
}).pipe(Layer.provide(PlatformNode.NodeContext.layer)),
|
|
64
|
-
),
|
|
65
|
-
Effect.flip,
|
|
66
|
-
)
|
|
67
|
-
|
|
68
|
-
expect(error).toBeInstanceOf(WranglerDevServerError)
|
|
69
|
-
}).pipe(Vitest.withTestCtx(test)),
|
|
70
|
-
)
|
|
71
|
-
|
|
72
|
-
Vitest.scopedLive('should handle invalid working directory', (test) =>
|
|
73
|
-
Effect.gen(function* () {
|
|
74
|
-
const result = yield* WranglerDevServerService.pipe(
|
|
75
|
-
Effect.provide(
|
|
76
|
-
WranglerDevServerTest({
|
|
77
|
-
cwd: '/completely/nonexistent/directory',
|
|
78
|
-
}).pipe(Layer.provide(PlatformNode.NodeContext.layer)),
|
|
79
|
-
),
|
|
80
|
-
Effect.either,
|
|
81
|
-
)
|
|
82
|
-
|
|
83
|
-
expect(result._tag).toBe('Left')
|
|
84
|
-
if (result._tag === 'Left') {
|
|
85
|
-
expect(result.left).toBeInstanceOf(WranglerDevServerError)
|
|
86
|
-
}
|
|
87
|
-
}).pipe(Vitest.withTestCtx(test)),
|
|
88
|
-
)
|
|
89
|
-
|
|
90
|
-
Vitest.scopedLive('should timeout if server fails to start', (test) =>
|
|
91
|
-
Effect.gen(function* () {
|
|
92
|
-
// Create a command that will never output "Ready on"
|
|
93
|
-
const result = yield* WranglerDevServerService.pipe(
|
|
94
|
-
// Override the timeout for this test to be shorter
|
|
95
|
-
Effect.timeout('5 seconds'),
|
|
96
|
-
Effect.either,
|
|
97
|
-
)
|
|
98
|
-
|
|
99
|
-
// This might succeed or fail depending on actual wrangler behavior
|
|
100
|
-
// The main point is testing timeout functionality
|
|
101
|
-
expect(['Left', 'Right']).toContain(result._tag)
|
|
102
|
-
}).pipe(withErrorTest()(test)),
|
|
103
|
-
)
|
|
104
|
-
})
|
|
105
|
-
|
|
106
|
-
Vitest.describe('Service Pattern', () => {
|
|
107
|
-
const withServiceTest = (args: Partial<StartWranglerDevServerArgs> = {}) =>
|
|
108
|
-
Vitest.makeWithTestCtx({
|
|
109
|
-
timeout: testTimeout,
|
|
110
|
-
makeLayer: () => WranglerDevServerTest(args).pipe(Layer.provide(PlatformNode.NodeContext.layer)),
|
|
111
|
-
})
|
|
112
|
-
|
|
113
|
-
Vitest.scopedLive('should work with service pattern', (test) =>
|
|
114
|
-
Effect.gen(function* () {
|
|
115
|
-
const server = yield* WranglerDevServerService
|
|
116
|
-
|
|
117
|
-
expect(server.port).toBeGreaterThan(0)
|
|
118
|
-
expect(server.url).toMatch(/http:\/\/127.0.0.1:\d+/)
|
|
119
|
-
}).pipe(withServiceTest()(test)),
|
|
120
|
-
)
|
|
121
|
-
|
|
122
|
-
Vitest.scopedLive('should work with custom port via service', (test) =>
|
|
123
|
-
Effect.andThen(getFreePort, (port) =>
|
|
124
|
-
Effect.gen(function* () {
|
|
125
|
-
const server = yield* WranglerDevServerService
|
|
126
|
-
|
|
127
|
-
expect(server.port).toBe(port)
|
|
128
|
-
expect(server.url).toBe(`http://127.0.0.1:${port}`)
|
|
129
|
-
}).pipe(withServiceTest({ preferredPort: port })(test)),
|
|
130
|
-
),
|
|
131
|
-
)
|
|
132
|
-
})
|
|
133
|
-
})
|
|
@@ -1,180 +0,0 @@
|
|
|
1
|
-
import * as path from 'node:path'
|
|
2
|
-
import * as Toml from '@iarna/toml'
|
|
3
|
-
import { IS_CI } from '@livestore/utils'
|
|
4
|
-
import { Cause, Duration, Effect, FileSystem, HttpClient, Schedule, Schema } from '@livestore/utils/effect'
|
|
5
|
-
import { getFreePort } from '@livestore/utils/node'
|
|
6
|
-
import * as wrangler from 'wrangler'
|
|
7
|
-
|
|
8
|
-
/**
|
|
9
|
-
* Error type for WranglerDevServer operations
|
|
10
|
-
*/
|
|
11
|
-
export class WranglerDevServerError extends Schema.TaggedError<WranglerDevServerError>()('WranglerDevServerError', {
|
|
12
|
-
cause: Schema.Unknown,
|
|
13
|
-
message: Schema.String,
|
|
14
|
-
port: Schema.Number,
|
|
15
|
-
}) {}
|
|
16
|
-
|
|
17
|
-
/**
|
|
18
|
-
* WranglerDevServer instance interface
|
|
19
|
-
*/
|
|
20
|
-
export interface WranglerDevServer {
|
|
21
|
-
readonly port: number
|
|
22
|
-
readonly url: string
|
|
23
|
-
// readonly processId: number
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
/**
|
|
27
|
-
* Configuration for starting WranglerDevServer
|
|
28
|
-
*/
|
|
29
|
-
export interface StartWranglerDevServerArgs {
|
|
30
|
-
wranglerConfigPath?: string
|
|
31
|
-
cwd: string
|
|
32
|
-
/** The port to try first. The dev server may bind a different port if unavailable. */
|
|
33
|
-
preferredPort?: number
|
|
34
|
-
/** @default false */
|
|
35
|
-
showLogs?: boolean
|
|
36
|
-
inspectorPort?: number
|
|
37
|
-
connectTimeout?: Duration.DurationInput
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
/**
|
|
41
|
-
* WranglerDevServer as an Effect.Service.
|
|
42
|
-
*
|
|
43
|
-
* This service provides the WranglerDevServer properties and can be accessed
|
|
44
|
-
* directly to get port and url.
|
|
45
|
-
*
|
|
46
|
-
* TODO: Allow for config to be passed in via code instead of `wrangler.toml` file
|
|
47
|
-
* (would need to be placed in temporary file as wrangler only accepts files as config)
|
|
48
|
-
*/
|
|
49
|
-
export class WranglerDevServerService extends Effect.Service<WranglerDevServerService>()('WranglerDevServerService', {
|
|
50
|
-
scoped: (args: StartWranglerDevServerArgs) =>
|
|
51
|
-
Effect.gen(function* () {
|
|
52
|
-
const showLogs = args.showLogs ?? false
|
|
53
|
-
|
|
54
|
-
// Allocate preferred port (Wrangler may bind a different one if unavailable)
|
|
55
|
-
const preferredPort =
|
|
56
|
-
args.preferredPort ??
|
|
57
|
-
(yield* getFreePort.pipe(
|
|
58
|
-
Effect.mapError(
|
|
59
|
-
(cause) => new WranglerDevServerError({ cause, message: 'Failed to get free port', port: -1 }),
|
|
60
|
-
),
|
|
61
|
-
))
|
|
62
|
-
|
|
63
|
-
yield* Effect.annotateCurrentSpan({ preferredPort })
|
|
64
|
-
|
|
65
|
-
const configPath = path.resolve(args.wranglerConfigPath ?? path.join(args.cwd, 'wrangler.toml'))
|
|
66
|
-
|
|
67
|
-
const fs = yield* FileSystem.FileSystem
|
|
68
|
-
const configContent = yield* fs.readFileString(configPath)
|
|
69
|
-
const parsedConfig = yield* Effect.try(() => Toml.parse(configContent)).pipe(
|
|
70
|
-
Effect.andThen(Schema.decodeUnknown(Schema.Struct({ main: Schema.String }))),
|
|
71
|
-
Effect.mapError(
|
|
72
|
-
(error) => new WranglerDevServerError({ cause: error, message: 'Failed to parse wrangler config', port: -1 }),
|
|
73
|
-
),
|
|
74
|
-
)
|
|
75
|
-
const resolvedMainPath = yield* Effect.try(() => path.resolve(args.cwd, parsedConfig.main))
|
|
76
|
-
|
|
77
|
-
const devServer = yield* Effect.promise(() =>
|
|
78
|
-
wrangler.unstable_dev(resolvedMainPath, {
|
|
79
|
-
config: configPath,
|
|
80
|
-
port: preferredPort,
|
|
81
|
-
inspectorPort: args.inspectorPort ?? 0,
|
|
82
|
-
persistTo: path.join(args.cwd, '.wrangler/state'),
|
|
83
|
-
logLevel: showLogs ? 'debug' : 'none',
|
|
84
|
-
experimental: {
|
|
85
|
-
disableExperimentalWarning: true,
|
|
86
|
-
},
|
|
87
|
-
}),
|
|
88
|
-
)
|
|
89
|
-
|
|
90
|
-
yield* Effect.addFinalizer(
|
|
91
|
-
Effect.fn(
|
|
92
|
-
function* (exit) {
|
|
93
|
-
if (exit._tag === 'Failure' && Cause.isInterruptedOnly(exit.cause) === false) {
|
|
94
|
-
yield* Effect.logError('Closing wrangler dev server on failure', exit.cause)
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
yield* Effect.tryPromise(async () => {
|
|
98
|
-
await devServer.stop()
|
|
99
|
-
// TODO investigate whether we need to wait until exit (see workers-sdk repo/talk to Cloudflare team)
|
|
100
|
-
// await devServer.waitUntilExit()
|
|
101
|
-
})
|
|
102
|
-
},
|
|
103
|
-
Effect.timeout('5 seconds'),
|
|
104
|
-
Effect.orDie,
|
|
105
|
-
Effect.tapCauseLogPretty,
|
|
106
|
-
Effect.withSpan('WranglerDevServerService:stopDevServer'),
|
|
107
|
-
),
|
|
108
|
-
)
|
|
109
|
-
|
|
110
|
-
const actualPort = devServer.port
|
|
111
|
-
const actualHost = devServer.address
|
|
112
|
-
const url = `http://${actualHost}:${actualPort}`
|
|
113
|
-
|
|
114
|
-
// Use longer timeout in CI environments to account for slower startup times
|
|
115
|
-
const defaultTimeout = Duration.seconds(IS_CI ? 30 : 5)
|
|
116
|
-
|
|
117
|
-
yield* verifyHttpConnectivity({ url, showLogs, connectTimeout: args.connectTimeout ?? defaultTimeout })
|
|
118
|
-
|
|
119
|
-
if (showLogs) {
|
|
120
|
-
yield* Effect.logDebug(
|
|
121
|
-
`Wrangler dev server ready and accepting connections on port ${actualPort} (preferred: ${preferredPort})`,
|
|
122
|
-
)
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
return {
|
|
126
|
-
port: actualPort,
|
|
127
|
-
url,
|
|
128
|
-
} satisfies WranglerDevServer
|
|
129
|
-
}).pipe(
|
|
130
|
-
Effect.mapError(
|
|
131
|
-
(error) =>
|
|
132
|
-
new WranglerDevServerError({ cause: error, message: 'Failed to start wrangler dev server', port: -1 }),
|
|
133
|
-
),
|
|
134
|
-
Effect.withSpan('WranglerDevServerService', {
|
|
135
|
-
attributes: { preferredPort: args.preferredPort ?? 'auto', cwd: args.cwd },
|
|
136
|
-
}),
|
|
137
|
-
),
|
|
138
|
-
}) {}
|
|
139
|
-
|
|
140
|
-
/**
|
|
141
|
-
* Verifies the server is actually accepting HTTP connections by making a test request
|
|
142
|
-
*/
|
|
143
|
-
const verifyHttpConnectivity = ({
|
|
144
|
-
url,
|
|
145
|
-
showLogs,
|
|
146
|
-
connectTimeout,
|
|
147
|
-
}: {
|
|
148
|
-
url: string
|
|
149
|
-
showLogs: boolean
|
|
150
|
-
connectTimeout: Duration.DurationInput
|
|
151
|
-
}): Effect.Effect<void, WranglerDevServerError, HttpClient.HttpClient> =>
|
|
152
|
-
Effect.gen(function* () {
|
|
153
|
-
const client = yield* HttpClient.HttpClient
|
|
154
|
-
|
|
155
|
-
if (showLogs) {
|
|
156
|
-
yield* Effect.logDebug(`Verifying HTTP connectivity to ${url}`)
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
// Try to connect with retries using exponential backoff
|
|
160
|
-
yield* client.get(url).pipe(
|
|
161
|
-
Effect.retryOrElse(
|
|
162
|
-
Schedule.exponential('50 millis', 2).pipe(
|
|
163
|
-
Schedule.jittered,
|
|
164
|
-
Schedule.intersect(Schedule.elapsed.pipe(Schedule.whileOutput(Duration.lessThanOrEqualTo(connectTimeout)))),
|
|
165
|
-
Schedule.compose(Schedule.count),
|
|
166
|
-
),
|
|
167
|
-
(error, attemptCount) =>
|
|
168
|
-
Effect.fail(
|
|
169
|
-
new WranglerDevServerError({
|
|
170
|
-
cause: error,
|
|
171
|
-
message: `Failed to establish HTTP connection to Wrangler server at ${url} after ${attemptCount} attempts (timeout: ${Duration.toMillis(connectTimeout)}ms)`,
|
|
172
|
-
port: 0,
|
|
173
|
-
}),
|
|
174
|
-
),
|
|
175
|
-
),
|
|
176
|
-
Effect.tap(() => (showLogs ? Effect.logDebug(`HTTP connectivity verified for ${url}`) : Effect.void)),
|
|
177
|
-
Effect.asVoid,
|
|
178
|
-
Effect.withSpan('verifyHttpConnectivity'),
|
|
179
|
-
)
|
|
180
|
-
})
|
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
export default {
|
|
2
|
-
async fetch(_request: Request): Promise<Response> {
|
|
3
|
-
return new Response('Hello from Wrangler Dev Server test worker!')
|
|
4
|
-
},
|
|
5
|
-
}
|
|
6
|
-
|
|
7
|
-
export class TestDO {
|
|
8
|
-
async fetch(_request: Request): Promise<Response> {
|
|
9
|
-
return new Response('Hello from Test Durable Object!')
|
|
10
|
-
}
|
|
11
|
-
}
|
package/src/wrangler/mod.ts
DELETED
|
File without changes
|