@uploadista/server 0.0.13-beta.4 → 0.0.13

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.
@@ -14,7 +14,7 @@ import { describe, expect, it } from "vitest";
14
14
  describe("Deprecated plugins-typing module", () => {
15
15
  it("should still be importable", async () => {
16
16
  // Import from deprecated module - should not throw
17
- const pluginsTyping = await import("../plugins-typing");
17
+ const pluginsTyping = await import("../src/plugins-typing");
18
18
 
19
19
  // Module should exist
20
20
  expect(pluginsTyping).toBeDefined();
@@ -40,21 +40,21 @@ describe("Deprecated plugins-typing module", () => {
40
40
 
41
41
  describe("Deprecated createTypeSafeServer", () => {
42
42
  it("should still be exported from core module", async () => {
43
- const coreModule = await import("../core");
43
+ const coreModule = await import("../src/core");
44
44
 
45
45
  expect(coreModule).toHaveProperty("createTypeSafeServer");
46
46
  expect(typeof coreModule.createTypeSafeServer).toBe("function");
47
47
  });
48
48
 
49
49
  it("should be exported from create-type-safe-server module", async () => {
50
- const module = await import("../core/create-type-safe-server");
50
+ const module = await import("../src/core/create-type-safe-server");
51
51
 
52
52
  expect(module).toHaveProperty("createTypeSafeServer");
53
53
  expect(typeof module.createTypeSafeServer).toBe("function");
54
54
  });
55
55
 
56
56
  it("should export helper functions", async () => {
57
- const module = await import("../core/create-type-safe-server");
57
+ const module = await import("../src/core/create-type-safe-server");
58
58
 
59
59
  expect(module).toHaveProperty("defineFlow");
60
60
  expect(module).toHaveProperty("defineSimpleFlow");
@@ -69,7 +69,7 @@ describe("Deprecated createTypeSafeServer", () => {
69
69
 
70
70
  describe("New module exports", () => {
71
71
  it("should export runtime utilities from core module", async () => {
72
- const coreModule = await import("../core");
72
+ const coreModule = await import("../src/core");
73
73
 
74
74
  // Runtime validation (these are actual runtime functions)
75
75
  expect(coreModule).toHaveProperty("validatePluginRequirements");
@@ -86,7 +86,7 @@ describe("New module exports", () => {
86
86
  });
87
87
 
88
88
  it("should export plugin validation utilities", async () => {
89
- const validationModule = await import("../core/plugin-validation");
89
+ const validationModule = await import("../src/core/plugin-validation");
90
90
 
91
91
  expect(validationModule).toHaveProperty("validatePluginRequirements");
92
92
  expect(validationModule).toHaveProperty("formatPluginValidationError");
@@ -107,7 +107,7 @@ describe("New module exports", () => {
107
107
  });
108
108
 
109
109
  it("should export plugin types module", async () => {
110
- const pluginTypesModule = await import("../core/plugin-types");
110
+ const pluginTypesModule = await import("../src/core/plugin-types");
111
111
 
112
112
  // Module should exist and be importable
113
113
  expect(pluginTypesModule).toBeDefined();
@@ -129,7 +129,7 @@ describe("New module exports", () => {
129
129
 
130
130
  describe("Import path compatibility", () => {
131
131
  it("should support importing from main core module", async () => {
132
- const exports = await import("../core");
132
+ const exports = await import("../src/core");
133
133
 
134
134
  // Old APIs
135
135
  expect(exports.createTypeSafeServer).toBeDefined();
@@ -144,7 +144,7 @@ describe("Import path compatibility", () => {
144
144
  });
145
145
 
146
146
  it("should support importing deprecated module directly", async () => {
147
- const exports = await import("../plugins-typing");
147
+ const exports = await import("../src/plugins-typing");
148
148
 
149
149
  // Module should be importable
150
150
  expect(exports).toBeDefined();
@@ -152,9 +152,9 @@ describe("Import path compatibility", () => {
152
152
  });
153
153
 
154
154
  it("should support importing new modules directly", async () => {
155
- const pluginTypes = await import("../core/plugin-types");
156
- const pluginValidation = await import("../core/plugin-validation");
157
- const server = await import("../core/server");
155
+ const pluginTypes = await import("../src/core/plugin-types");
156
+ const pluginValidation = await import("../src/core/plugin-validation");
157
+ const server = await import("../src/core/server");
158
158
 
159
159
  // Modules should be importable
160
160
  expect(pluginTypes).toBeDefined();
@@ -169,7 +169,7 @@ describe("Import path compatibility", () => {
169
169
 
170
170
  describe("Helper functions compatibility", () => {
171
171
  it("should support defineFlow helper", async () => {
172
- const { defineFlow } = await import("../core/create-type-safe-server");
172
+ const { defineFlow } = await import("../src/core/create-type-safe-server");
173
173
  const { Effect } = await import("effect");
174
174
 
175
175
  // Should be able to use defineFlow
@@ -180,7 +180,7 @@ describe("Helper functions compatibility", () => {
180
180
 
181
181
  it("should support defineSimpleFlow helper", async () => {
182
182
  const { defineSimpleFlow } = await import(
183
- "../core/create-type-safe-server"
183
+ "../src/core/create-type-safe-server"
184
184
  );
185
185
  const { Effect } = await import("effect");
186
186
 
@@ -213,21 +213,21 @@ describe("Type availability", () => {
213
213
  it("should have TypeSafeServerConfig type available", async () => {
214
214
  // This is a compile-time check that the type exists
215
215
  // At runtime, we just verify the module exports
216
- const module = await import("../core/create-type-safe-server");
216
+ const module = await import("../src/core/create-type-safe-server");
217
217
 
218
218
  expect(module).toBeDefined();
219
219
  // Type would be checked at compile time
220
220
  });
221
221
 
222
222
  it("should have plugin validation types available", async () => {
223
- const module = await import("../core/plugin-validation");
223
+ const module = await import("../src/core/plugin-validation");
224
224
 
225
225
  expect(module).toBeDefined();
226
226
  // Types like PluginValidationResult would be checked at compile time
227
227
  });
228
228
 
229
229
  it("should have plugin types available", async () => {
230
- const module = await import("../core/plugin-types");
230
+ const module = await import("../src/core/plugin-types");
231
231
 
232
232
  expect(module).toBeDefined();
233
233
  // Types like ValidatePlugins, PluginServices would be checked at compile time
@@ -242,7 +242,7 @@ describe("Migration scenarios", () => {
242
242
  it("should support old createTypeSafeServer imports", async () => {
243
243
  // Old code pattern
244
244
  const { createTypeSafeServer } = await import(
245
- "../core/create-type-safe-server"
245
+ "../src/core/create-type-safe-server"
246
246
  );
247
247
 
248
248
  expect(createTypeSafeServer).toBeDefined();
@@ -251,7 +251,7 @@ describe("Migration scenarios", () => {
251
251
 
252
252
  it("should support new createUploadistaServer imports", async () => {
253
253
  // New code pattern
254
- const { createUploadistaServer } = await import("../core/server");
254
+ const { createUploadistaServer } = await import("../src/core/server");
255
255
 
256
256
  expect(createUploadistaServer).toBeDefined();
257
257
  expect(typeof createUploadistaServer).toBe("function");
@@ -259,7 +259,7 @@ describe("Migration scenarios", () => {
259
259
 
260
260
  it("should support old plugin typing imports", async () => {
261
261
  // Old code pattern - module should be importable
262
- const oldModule = await import("../plugins-typing");
262
+ const oldModule = await import("../src/plugins-typing");
263
263
 
264
264
  expect(oldModule).toBeDefined();
265
265
  // All exports are type-only (LayerSuccessUnion, FlowRequirementsOf, etc.)
@@ -267,7 +267,7 @@ describe("Migration scenarios", () => {
267
267
 
268
268
  it("should support new plugin typing imports", async () => {
269
269
  // New code pattern - module should be importable
270
- const newModule = await import("../core/plugin-types");
270
+ const newModule = await import("../src/core/plugin-types");
271
271
 
272
272
  expect(newModule).toBeDefined();
273
273
  // All exports are type-only (ExtractFlowPluginRequirements, ValidatePlugins, etc.)
@@ -275,8 +275,8 @@ describe("Migration scenarios", () => {
275
275
 
276
276
  it("should support importing both old and new modules", async () => {
277
277
  // Both modules should be importable without conflicts
278
- const oldModule = await import("../plugins-typing");
279
- const newModule = await import("../core/plugin-types");
278
+ const oldModule = await import("../src/plugins-typing");
279
+ const newModule = await import("../src/core/plugin-types");
280
280
 
281
281
  expect(oldModule).toBeDefined();
282
282
  expect(newModule).toBeDefined();
@@ -4,8 +4,8 @@ import {
4
4
  AuthCacheService,
5
5
  AuthCacheServiceLive,
6
6
  NoAuthCacheServiceLive,
7
- } from "./cache";
8
- import type { AuthContext } from "./types";
7
+ } from "../src/cache";
8
+ import type { AuthContext } from "../src/types";
9
9
 
10
10
  describe("AuthCacheService", () => {
11
11
  describe("AuthCacheServiceLive", () => {
@@ -0,0 +1,495 @@
1
+ /**
2
+ * Tests for HTTP Flow Handlers
3
+ *
4
+ * Covers:
5
+ * - Flow data retrieval
6
+ * - Flow execution and job management
7
+ * - Job status tracking
8
+ * - Flow control (pause, resume, cancel)
9
+ * - Auth context handling and caching
10
+ * - HTTP request/response handling
11
+ * - Error handling and status codes
12
+ */
13
+
14
+ import { it } from "@effect/vitest";
15
+ import type { FlowData, FlowJob } from "@uploadista/core";
16
+ import { FlowServer } from "@uploadista/core/flow";
17
+ import { Effect, Layer } from "effect";
18
+ import { describe, expect } from "vitest";
19
+ import { AuthCacheServiceLive, AuthContextServiceLive } from "../../../src";
20
+ import {
21
+ handleCancelFlow,
22
+ handleGetFlow,
23
+ handleJobStatus,
24
+ handlePauseFlow,
25
+ handleResumeFlow,
26
+ handleRunFlow,
27
+ } from "../../../src/core/http-handlers/flow-http-handlers";
28
+
29
+ // Mock FlowServer implementation for testing
30
+ const mockFlowServerMethods = {
31
+ getFlowData: (flowId: string, _clientId: string | null) =>
32
+ Effect.succeed<FlowData>({
33
+ id: flowId,
34
+ name: `Flow ${flowId}`,
35
+ nodes: [],
36
+ edges: [],
37
+ }),
38
+
39
+ runFlow: ({
40
+ flowId,
41
+ storageId,
42
+ clientId,
43
+ }: {
44
+ flowId: string;
45
+ storageId: string;
46
+ clientId: string | null;
47
+ inputs: Record<string, unknown>;
48
+ }) =>
49
+ Effect.succeed<FlowJob>({
50
+ id: `job-${flowId}-${Date.now()}`,
51
+ flowId,
52
+ storageId,
53
+ clientId,
54
+ status: "running",
55
+ tasks: [],
56
+ createdAt: new Date(),
57
+ updatedAt: new Date(),
58
+ }),
59
+
60
+ getJobStatus: (jobId: string) =>
61
+ Effect.succeed<FlowJob>({
62
+ id: jobId,
63
+ flowId: "flow-123",
64
+ status: "running",
65
+ clientId: null,
66
+ storageId: "storage-1",
67
+ tasks: [],
68
+ createdAt: new Date(),
69
+ updatedAt: new Date(),
70
+ }),
71
+
72
+ resumeFlow: ({
73
+ jobId,
74
+ clientId,
75
+ }: {
76
+ jobId: string;
77
+ nodeId: string;
78
+ newData: unknown;
79
+ clientId: string | null;
80
+ }) =>
81
+ Effect.succeed<FlowJob>({
82
+ id: jobId,
83
+ flowId: "flow-123",
84
+ status: "running",
85
+ clientId,
86
+ storageId: "storage-1",
87
+ tasks: [],
88
+ createdAt: new Date(),
89
+ updatedAt: new Date(),
90
+ }),
91
+
92
+ pauseFlow: (jobId: string, clientId: string | null) =>
93
+ Effect.succeed<FlowJob>({
94
+ id: jobId,
95
+ flowId: "flow-123",
96
+ status: "paused",
97
+ clientId,
98
+ storageId: "storage-1",
99
+ tasks: [],
100
+ createdAt: new Date(),
101
+ updatedAt: new Date(),
102
+ }),
103
+
104
+ cancelFlow: (jobId: string, clientId: string | null) =>
105
+ Effect.succeed<FlowJob>({
106
+ id: jobId,
107
+ flowId: "flow-123",
108
+ status: "cancelled",
109
+ clientId,
110
+ storageId: "storage-1",
111
+ tasks: [],
112
+ createdAt: new Date(),
113
+ updatedAt: new Date(),
114
+ }),
115
+
116
+ // Mock methods required by FlowServerShape but not used in tests
117
+ getFlow: () => Effect.die("getFlow not implemented in test"),
118
+ subscribeToFlowEvents: () => Effect.void,
119
+ unsubscribeFromFlowEvents: () => Effect.void,
120
+ };
121
+
122
+ const FlowServerTest = Layer.succeed(FlowServer, mockFlowServerMethods);
123
+
124
+ describe("HTTP Flow Handlers", () => {
125
+ describe("handleGetFlow", () => {
126
+ it.effect("should retrieve flow data without auth", () =>
127
+ Effect.gen(function* () {
128
+ const result = yield* handleGetFlow({
129
+ type: "get-flow",
130
+ flowId: "flow-123",
131
+ });
132
+
133
+ expect(result.status).toBe(200);
134
+ expect(result.body.id).toBe("flow-123");
135
+ expect(result.body.name).toBe("Flow flow-123");
136
+ }).pipe(
137
+ Effect.provide(FlowServerTest),
138
+ Effect.provide(AuthCacheServiceLive()),
139
+ Effect.provide(AuthContextServiceLive(null)),
140
+ ),
141
+ );
142
+
143
+ it.effect("should retrieve flow data with auth context", () =>
144
+ Effect.gen(function* () {
145
+ const result = yield* handleGetFlow({
146
+ type: "get-flow",
147
+ flowId: "flow-456",
148
+ });
149
+
150
+ expect(result.status).toBe(200);
151
+ expect(result.body.id).toBe("flow-456");
152
+ }).pipe(
153
+ Effect.provide(FlowServerTest),
154
+ Effect.provide(AuthCacheServiceLive()),
155
+ Effect.provide(
156
+ AuthContextServiceLive({
157
+ clientId: "user-123",
158
+ metadata: { role: "admin" },
159
+ }),
160
+ ),
161
+ ),
162
+ );
163
+
164
+ it.effect("should include flow metadata in response", () =>
165
+ Effect.gen(function* () {
166
+ const result = yield* handleGetFlow({
167
+ type: "get-flow",
168
+ flowId: "flow-789",
169
+ });
170
+
171
+ expect(result.status).toBe(200);
172
+ expect(result.body).toHaveProperty("id");
173
+ expect(result.body).toHaveProperty("name");
174
+ expect(result.body).toHaveProperty("nodes");
175
+ expect(result.body).toHaveProperty("edges");
176
+ expect(result.body.id).toBe("flow-789");
177
+ }).pipe(
178
+ Effect.provide(FlowServerTest),
179
+ Effect.provide(AuthCacheServiceLive()),
180
+ Effect.provide(AuthContextServiceLive(null)),
181
+ ),
182
+ );
183
+ });
184
+
185
+ describe("handleRunFlow", () => {
186
+ it.effect("should execute flow without auth", () =>
187
+ Effect.gen(function* () {
188
+ const result = yield* handleRunFlow<never>({
189
+ type: "run-flow",
190
+ flowId: "flow-123",
191
+ storageId: "storage-1",
192
+ inputs: { key: "value" },
193
+ });
194
+
195
+ expect(result.status).toBe(200);
196
+ expect(result.body).toHaveProperty("id");
197
+ expect(result.body.flowId).toBe("flow-123");
198
+ expect(result.body.storageId).toBe("storage-1");
199
+ expect(result.body.status).toBe("running");
200
+ }).pipe(
201
+ Effect.provide(FlowServerTest),
202
+ Effect.provide(AuthCacheServiceLive()),
203
+ Effect.provide(AuthContextServiceLive(null)),
204
+ ),
205
+ );
206
+
207
+ it.effect("should execute flow with auth context", () =>
208
+ Effect.gen(function* () {
209
+ const result = yield* handleRunFlow<never>({
210
+ type: "run-flow",
211
+ flowId: "flow-456",
212
+ storageId: "storage-2",
213
+ inputs: { data: "test" },
214
+ });
215
+
216
+ expect(result.status).toBe(200);
217
+ expect(result.body.clientId).toBe("user-123");
218
+ // Auth context is cached internally by the handler
219
+ }).pipe(
220
+ Effect.provide(FlowServerTest),
221
+ Effect.provide(AuthCacheServiceLive()),
222
+ Effect.provide(
223
+ AuthContextServiceLive({
224
+ clientId: "user-123",
225
+ metadata: { plan: "premium" },
226
+ }),
227
+ ),
228
+ ),
229
+ );
230
+
231
+ it.effect("should not cache auth context when no auth present", () =>
232
+ Effect.gen(function* () {
233
+ const result = yield* handleRunFlow<never>({
234
+ type: "run-flow",
235
+ flowId: "flow-789",
236
+ storageId: "storage-3",
237
+ inputs: {},
238
+ });
239
+
240
+ expect(result.status).toBe(200);
241
+ expect(result.body.clientId).toBeNull();
242
+ }).pipe(
243
+ Effect.provide(FlowServerTest),
244
+ Effect.provide(AuthCacheServiceLive()),
245
+ Effect.provide(AuthContextServiceLive(null)),
246
+ ),
247
+ );
248
+
249
+ it.effect("should return job ID immediately", () =>
250
+ Effect.gen(function* () {
251
+ const result = yield* handleRunFlow<never>({
252
+ type: "run-flow",
253
+ flowId: "flow-async",
254
+ storageId: "storage-4",
255
+ inputs: { async: true },
256
+ });
257
+
258
+ expect(result.status).toBe(200);
259
+ expect(result.body.id).toContain("job-");
260
+ expect(result.body.status).toBe("running");
261
+ }).pipe(
262
+ Effect.provide(FlowServerTest),
263
+ Effect.provide(AuthCacheServiceLive()),
264
+ Effect.provide(AuthContextServiceLive(null)),
265
+ ),
266
+ );
267
+ });
268
+
269
+ describe("handleJobStatus", () => {
270
+ it.effect("should get job status", () =>
271
+ Effect.gen(function* () {
272
+ const result = yield* handleJobStatus({
273
+ type: "job-status",
274
+ jobId: "job-123",
275
+ });
276
+
277
+ expect(result.status).toBe(200);
278
+ expect(result.body.id).toBe("job-123");
279
+ expect(result.body.flowId).toBe("flow-123");
280
+ expect(result.body).toHaveProperty("status");
281
+ }).pipe(
282
+ Effect.provide(FlowServerTest),
283
+ Effect.provide(AuthCacheServiceLive()),
284
+ Effect.provide(AuthContextServiceLive(null)),
285
+ ),
286
+ );
287
+
288
+ it.effect("should clear cache when flow completes", () =>
289
+ Effect.gen(function* () {
290
+ // Create FlowServer that returns completed status
291
+ const completedMethods = {
292
+ ...mockFlowServerMethods,
293
+ getJobStatus: (jobId: string) =>
294
+ Effect.succeed<FlowJob>({
295
+ id: jobId,
296
+ flowId: "flow-123",
297
+ status: "completed",
298
+ clientId: null,
299
+ storageId: "storage-1",
300
+ tasks: [],
301
+ createdAt: new Date(),
302
+ updatedAt: new Date(),
303
+ }),
304
+ };
305
+
306
+ const result = yield* handleJobStatus({
307
+ type: "job-status",
308
+ jobId: "job-completed",
309
+ }).pipe(
310
+ Effect.provide(Layer.succeed(FlowServer, completedMethods)),
311
+ Effect.provide(AuthCacheServiceLive()),
312
+ Effect.provide(AuthContextServiceLive(null)),
313
+ );
314
+
315
+ expect(result.status).toBe(200);
316
+ expect(result.body.status).toBe("completed");
317
+ }),
318
+ );
319
+
320
+ it.effect("should not clear cache for running jobs", () =>
321
+ Effect.gen(function* () {
322
+ const result = yield* handleJobStatus({
323
+ type: "job-status",
324
+ jobId: "job-running",
325
+ });
326
+
327
+ expect(result.status).toBe(200);
328
+ expect(result.body.status).toBe("running");
329
+ }).pipe(
330
+ Effect.provide(FlowServerTest),
331
+ Effect.provide(AuthCacheServiceLive()),
332
+ Effect.provide(AuthContextServiceLive(null)),
333
+ ),
334
+ );
335
+ });
336
+
337
+ describe("handleResumeFlow", () => {
338
+ it.effect("should resume flow with current auth", () =>
339
+ Effect.gen(function* () {
340
+ const result = yield* handleResumeFlow<never>({
341
+ type: "resume-flow",
342
+ jobId: "job-cached",
343
+ nodeId: "node-2",
344
+ newData: { selection: "yes" },
345
+ });
346
+
347
+ expect(result.status).toBe(200);
348
+ expect(result.body.id).toBe("job-cached");
349
+ }).pipe(
350
+ Effect.provide(FlowServerTest),
351
+ Effect.provide(AuthCacheServiceLive()),
352
+ Effect.provide(AuthContextServiceLive(null)),
353
+ ),
354
+ );
355
+ });
356
+
357
+ describe("handlePauseFlow", () => {
358
+ it.effect("should pause flow", () =>
359
+ Effect.gen(function* () {
360
+ const result = yield* handlePauseFlow({
361
+ type: "pause-flow",
362
+ jobId: "job-pause",
363
+ });
364
+
365
+ expect(result.status).toBe(200);
366
+ expect(result.body.id).toBe("job-pause");
367
+ expect(result.body.status).toBe("paused");
368
+ }).pipe(
369
+ Effect.provide(FlowServerTest),
370
+ Effect.provide(AuthCacheServiceLive()),
371
+ Effect.provide(AuthContextServiceLive(null)),
372
+ ),
373
+ );
374
+
375
+ it.effect("should pause flow with auth context", () =>
376
+ Effect.gen(function* () {
377
+ const result = yield* handlePauseFlow({
378
+ type: "pause-flow",
379
+ jobId: "job-pause-auth",
380
+ });
381
+
382
+ expect(result.status).toBe(200);
383
+ expect(result.body.status).toBe("paused");
384
+ expect(result.body.clientId).toBe("user-pause");
385
+ }).pipe(
386
+ Effect.provide(FlowServerTest),
387
+ Effect.provide(AuthCacheServiceLive()),
388
+ Effect.provide(AuthContextServiceLive({ clientId: "user-pause" })),
389
+ ),
390
+ );
391
+ });
392
+
393
+ describe("handleCancelFlow", () => {
394
+ it.effect("should cancel flow", () =>
395
+ Effect.gen(function* () {
396
+ const result = yield* handleCancelFlow({
397
+ type: "cancel-flow",
398
+ jobId: "job-cancel",
399
+ });
400
+
401
+ expect(result.status).toBe(200);
402
+ expect(result.body.id).toBe("job-cancel");
403
+ expect(result.body.status).toBe("cancelled");
404
+ }).pipe(
405
+ Effect.provide(FlowServerTest),
406
+ Effect.provide(AuthCacheServiceLive()),
407
+ Effect.provide(AuthContextServiceLive(null)),
408
+ ),
409
+ );
410
+
411
+ it.effect("should cancel flow with current auth", () =>
412
+ Effect.gen(function* () {
413
+ const result = yield* handleCancelFlow({
414
+ type: "cancel-flow",
415
+ jobId: "job-cancel-auth",
416
+ });
417
+
418
+ expect(result.status).toBe(200);
419
+ expect(result.body.status).toBe("cancelled");
420
+ expect(result.body.clientId).toBe("user-cancel-auth");
421
+ }).pipe(
422
+ Effect.provide(FlowServerTest),
423
+ Effect.provide(AuthCacheServiceLive()),
424
+ Effect.provide(
425
+ AuthContextServiceLive({
426
+ clientId: "user-cancel-auth",
427
+ metadata: { reason: "manual" },
428
+ }),
429
+ ),
430
+ ),
431
+ );
432
+ });
433
+
434
+ describe("HTTP Status Codes", () => {
435
+ it.effect("should return 200 OK for successful operations", () =>
436
+ Effect.gen(function* () {
437
+ const getFlowResult = yield* handleGetFlow({
438
+ type: "get-flow",
439
+ flowId: "flow-200",
440
+ });
441
+ expect(getFlowResult.status).toBe(200);
442
+
443
+ const runFlowResult = yield* handleRunFlow<never>({
444
+ type: "run-flow",
445
+ flowId: "flow-200",
446
+ storageId: "storage-1",
447
+ inputs: {},
448
+ });
449
+ expect(runFlowResult.status).toBe(200);
450
+
451
+ const statusResult = yield* handleJobStatus({
452
+ type: "job-status",
453
+ jobId: "job-200",
454
+ });
455
+ expect(statusResult.status).toBe(200);
456
+ }).pipe(
457
+ Effect.provide(FlowServerTest),
458
+ Effect.provide(AuthCacheServiceLive()),
459
+ Effect.provide(AuthContextServiceLive(null)),
460
+ ),
461
+ );
462
+ });
463
+
464
+ describe("Auth Context Integration", () => {
465
+ it.effect("should handle unauthenticated flow operations", () =>
466
+ Effect.gen(function* () {
467
+ // All operations should work without auth
468
+ const getResult = yield* handleGetFlow({
469
+ type: "get-flow",
470
+ flowId: "flow-unauth",
471
+ });
472
+ expect(getResult.status).toBe(200);
473
+
474
+ const runResult = yield* handleRunFlow<never>({
475
+ type: "run-flow",
476
+ flowId: "flow-unauth",
477
+ storageId: "storage-1",
478
+ inputs: {},
479
+ });
480
+ expect(runResult.status).toBe(200);
481
+ expect(runResult.body.clientId).toBeNull();
482
+
483
+ const statusResult = yield* handleJobStatus({
484
+ type: "job-status",
485
+ jobId: "job-unauth",
486
+ });
487
+ expect(statusResult.status).toBe(200);
488
+ }).pipe(
489
+ Effect.provide(FlowServerTest),
490
+ Effect.provide(AuthCacheServiceLive()),
491
+ Effect.provide(AuthContextServiceLive(null)),
492
+ ),
493
+ );
494
+ });
495
+ });