@tinycloudlabs/sdk-services 1.0.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.
Files changed (57) hide show
  1. package/dist/base/BaseService.d.ts +151 -0
  2. package/dist/base/BaseService.d.ts.map +1 -0
  3. package/dist/base/BaseService.js +221 -0
  4. package/dist/base/BaseService.js.map +1 -0
  5. package/dist/base/index.d.ts +6 -0
  6. package/dist/base/index.d.ts.map +1 -0
  7. package/dist/base/index.js +6 -0
  8. package/dist/base/index.js.map +1 -0
  9. package/dist/base/types.d.ts +36 -0
  10. package/dist/base/types.d.ts.map +1 -0
  11. package/dist/base/types.js +7 -0
  12. package/dist/base/types.js.map +1 -0
  13. package/dist/context.d.ts +142 -0
  14. package/dist/context.d.ts.map +1 -0
  15. package/dist/context.js +218 -0
  16. package/dist/context.js.map +1 -0
  17. package/dist/errors.d.ts +43 -0
  18. package/dist/errors.d.ts.map +1 -0
  19. package/dist/errors.js +111 -0
  20. package/dist/errors.js.map +1 -0
  21. package/dist/index.d.ts +47 -0
  22. package/dist/index.d.ts.map +1 -0
  23. package/dist/index.js +53 -0
  24. package/dist/index.js.map +1 -0
  25. package/dist/kv/IKVService.d.ts +148 -0
  26. package/dist/kv/IKVService.d.ts.map +1 -0
  27. package/dist/kv/IKVService.js +8 -0
  28. package/dist/kv/IKVService.js.map +1 -0
  29. package/dist/kv/KVService.d.ts +153 -0
  30. package/dist/kv/KVService.d.ts.map +1 -0
  31. package/dist/kv/KVService.js +337 -0
  32. package/dist/kv/KVService.js.map +1 -0
  33. package/dist/kv/PrefixedKVService.d.ts +246 -0
  34. package/dist/kv/PrefixedKVService.d.ts.map +1 -0
  35. package/dist/kv/PrefixedKVService.js +145 -0
  36. package/dist/kv/PrefixedKVService.js.map +1 -0
  37. package/dist/kv/index.d.ts +10 -0
  38. package/dist/kv/index.d.ts.map +1 -0
  39. package/dist/kv/index.js +12 -0
  40. package/dist/kv/index.js.map +1 -0
  41. package/dist/kv/types.d.ts +204 -0
  42. package/dist/kv/types.d.ts.map +1 -0
  43. package/dist/kv/types.js +16 -0
  44. package/dist/kv/types.js.map +1 -0
  45. package/dist/types.d.ts +259 -0
  46. package/dist/types.d.ts.map +1 -0
  47. package/dist/types.js +72 -0
  48. package/dist/types.js.map +1 -0
  49. package/dist/types.schema.d.ts +652 -0
  50. package/dist/types.schema.d.ts.map +1 -0
  51. package/dist/types.schema.js +342 -0
  52. package/dist/types.schema.js.map +1 -0
  53. package/dist/types.schema.test.d.ts +5 -0
  54. package/dist/types.schema.test.d.ts.map +1 -0
  55. package/dist/types.schema.test.js +677 -0
  56. package/dist/types.schema.test.js.map +1 -0
  57. package/package.json +42 -0
@@ -0,0 +1,677 @@
1
+ /**
2
+ * Tests for types.schema.ts Zod schemas.
3
+ */
4
+ import { describe, expect, it } from "bun:test";
5
+ import { ServiceErrorSchema, KVResponseHeadersSchema, KVListResponseSchema, ServiceRequestEventSchema, ServiceResponseEventSchema, ServiceErrorEventSchema, ServiceRetryEventSchema, RetryPolicySchema, ServiceSessionSchema, GenericResultSchema, createResultSchema, createKVResponseSchema, validateServiceError, validateKVListResponse, validateKVResponseHeaders, validateServiceSession, validateRetryPolicy, validateServiceRequestEvent, validateServiceResponseEvent, } from "./types.schema";
6
+ import { z } from "zod";
7
+ // =============================================================================
8
+ // Test Fixtures
9
+ // =============================================================================
10
+ const validServiceError = {
11
+ code: "KV_NOT_FOUND",
12
+ message: "Key not found",
13
+ service: "kv",
14
+ };
15
+ const validServiceErrorWithMeta = {
16
+ ...validServiceError,
17
+ meta: { key: "test-key", path: "/data" },
18
+ };
19
+ const validKVResponseHeaders = {
20
+ etag: '"abc123"',
21
+ contentType: "application/json",
22
+ lastModified: "2026-02-01T12:00:00Z",
23
+ contentLength: 1024,
24
+ };
25
+ const validKVListResponse = {
26
+ keys: ["key1", "key2", "key3"],
27
+ };
28
+ const validServiceRequestEvent = {
29
+ service: "kv",
30
+ action: "tinycloud.kv/get",
31
+ key: "test-key",
32
+ timestamp: 1706832000000,
33
+ };
34
+ const validServiceResponseEvent = {
35
+ service: "kv",
36
+ action: "tinycloud.kv/get",
37
+ ok: true,
38
+ duration: 150,
39
+ status: 200,
40
+ };
41
+ const validRetryPolicy = {
42
+ maxAttempts: 3,
43
+ backoff: "exponential",
44
+ baseDelayMs: 1000,
45
+ maxDelayMs: 10000,
46
+ retryableErrors: ["NETWORK_ERROR", "TIMEOUT"],
47
+ };
48
+ const validServiceSession = {
49
+ delegationHeader: { Authorization: "Bearer token123" },
50
+ delegationCid: "bafybeigdyrzt5sfp7udm7hu76uh7y26nf3efuylqabf3oclgtqy55fbzdi",
51
+ spaceId: "space123",
52
+ verificationMethod: "did:key:z6MkhaXgBZDvotDkL5257faiztiGiC2QtKLGpbnnEGta2doK",
53
+ jwk: { kty: "EC", crv: "P-256" },
54
+ };
55
+ // =============================================================================
56
+ // ServiceErrorSchema Tests
57
+ // =============================================================================
58
+ describe("ServiceErrorSchema", () => {
59
+ it("accepts valid service error with required fields", () => {
60
+ const result = ServiceErrorSchema.safeParse(validServiceError);
61
+ expect(result.success).toBe(true);
62
+ if (result.success) {
63
+ expect(result.data.code).toBe("KV_NOT_FOUND");
64
+ expect(result.data.service).toBe("kv");
65
+ }
66
+ });
67
+ it("accepts service error with meta", () => {
68
+ const result = ServiceErrorSchema.safeParse(validServiceErrorWithMeta);
69
+ expect(result.success).toBe(true);
70
+ if (result.success) {
71
+ expect(result.data.meta).toEqual({ key: "test-key", path: "/data" });
72
+ }
73
+ });
74
+ it("accepts service error with cause", () => {
75
+ const data = {
76
+ ...validServiceError,
77
+ cause: new Error("Original error"),
78
+ };
79
+ const result = ServiceErrorSchema.safeParse(data);
80
+ expect(result.success).toBe(true);
81
+ });
82
+ it("rejects missing code", () => {
83
+ const data = { message: "Error", service: "kv" };
84
+ const result = ServiceErrorSchema.safeParse(data);
85
+ expect(result.success).toBe(false);
86
+ });
87
+ it("rejects missing message", () => {
88
+ const data = { code: "ERROR", service: "kv" };
89
+ const result = ServiceErrorSchema.safeParse(data);
90
+ expect(result.success).toBe(false);
91
+ });
92
+ it("rejects missing service", () => {
93
+ const data = { code: "ERROR", message: "Error" };
94
+ const result = ServiceErrorSchema.safeParse(data);
95
+ expect(result.success).toBe(false);
96
+ });
97
+ it("rejects empty object", () => {
98
+ const result = ServiceErrorSchema.safeParse({});
99
+ expect(result.success).toBe(false);
100
+ });
101
+ it("rejects null", () => {
102
+ const result = ServiceErrorSchema.safeParse(null);
103
+ expect(result.success).toBe(false);
104
+ });
105
+ });
106
+ // =============================================================================
107
+ // KVResponseHeadersSchema Tests
108
+ // =============================================================================
109
+ describe("KVResponseHeadersSchema", () => {
110
+ it("accepts valid headers with all fields", () => {
111
+ const result = KVResponseHeadersSchema.safeParse(validKVResponseHeaders);
112
+ expect(result.success).toBe(true);
113
+ if (result.success) {
114
+ expect(result.data.etag).toBe('"abc123"');
115
+ expect(result.data.contentLength).toBe(1024);
116
+ }
117
+ });
118
+ it("accepts empty object (all fields optional)", () => {
119
+ const result = KVResponseHeadersSchema.safeParse({});
120
+ expect(result.success).toBe(true);
121
+ });
122
+ it("accepts partial headers", () => {
123
+ const result = KVResponseHeadersSchema.safeParse({
124
+ etag: '"xyz789"',
125
+ });
126
+ expect(result.success).toBe(true);
127
+ if (result.success) {
128
+ expect(result.data.etag).toBe('"xyz789"');
129
+ expect(result.data.contentType).toBeUndefined();
130
+ }
131
+ });
132
+ it("rejects invalid contentLength type", () => {
133
+ const data = {
134
+ ...validKVResponseHeaders,
135
+ contentLength: "1024",
136
+ };
137
+ const result = KVResponseHeadersSchema.safeParse(data);
138
+ expect(result.success).toBe(false);
139
+ });
140
+ it("rejects null", () => {
141
+ const result = KVResponseHeadersSchema.safeParse(null);
142
+ expect(result.success).toBe(false);
143
+ });
144
+ });
145
+ // =============================================================================
146
+ // KVListResponseSchema Tests
147
+ // =============================================================================
148
+ describe("KVListResponseSchema", () => {
149
+ it("accepts valid list response", () => {
150
+ const result = KVListResponseSchema.safeParse(validKVListResponse);
151
+ expect(result.success).toBe(true);
152
+ if (result.success) {
153
+ expect(result.data.keys).toEqual(["key1", "key2", "key3"]);
154
+ }
155
+ });
156
+ it("accepts empty keys array", () => {
157
+ const result = KVListResponseSchema.safeParse({ keys: [] });
158
+ expect(result.success).toBe(true);
159
+ if (result.success) {
160
+ expect(result.data.keys).toEqual([]);
161
+ }
162
+ });
163
+ it("rejects missing keys", () => {
164
+ const result = KVListResponseSchema.safeParse({});
165
+ expect(result.success).toBe(false);
166
+ });
167
+ it("rejects keys with non-string elements", () => {
168
+ const result = KVListResponseSchema.safeParse({
169
+ keys: ["key1", 123, "key3"],
170
+ });
171
+ expect(result.success).toBe(false);
172
+ });
173
+ it("rejects non-array keys", () => {
174
+ const result = KVListResponseSchema.safeParse({
175
+ keys: "key1",
176
+ });
177
+ expect(result.success).toBe(false);
178
+ });
179
+ it("rejects null", () => {
180
+ const result = KVListResponseSchema.safeParse(null);
181
+ expect(result.success).toBe(false);
182
+ });
183
+ });
184
+ // =============================================================================
185
+ // createResultSchema Tests
186
+ // =============================================================================
187
+ describe("createResultSchema", () => {
188
+ it("creates schema that accepts success result", () => {
189
+ const StringResultSchema = createResultSchema(z.string());
190
+ const result = StringResultSchema.safeParse({
191
+ ok: true,
192
+ data: "hello",
193
+ });
194
+ expect(result.success).toBe(true);
195
+ if (result.success && result.data.ok) {
196
+ expect(result.data.data).toBe("hello");
197
+ }
198
+ });
199
+ it("creates schema that accepts error result", () => {
200
+ const StringResultSchema = createResultSchema(z.string());
201
+ const result = StringResultSchema.safeParse({
202
+ ok: false,
203
+ error: validServiceError,
204
+ });
205
+ expect(result.success).toBe(true);
206
+ if (result.success && !result.data.ok) {
207
+ expect(result.data.error.code).toBe("KV_NOT_FOUND");
208
+ }
209
+ });
210
+ it("rejects result with wrong data type for success", () => {
211
+ const NumberResultSchema = createResultSchema(z.number());
212
+ const result = NumberResultSchema.safeParse({
213
+ ok: true,
214
+ data: "not a number",
215
+ });
216
+ expect(result.success).toBe(false);
217
+ });
218
+ it("rejects result without ok discriminator", () => {
219
+ const StringResultSchema = createResultSchema(z.string());
220
+ const result = StringResultSchema.safeParse({
221
+ data: "hello",
222
+ });
223
+ expect(result.success).toBe(false);
224
+ });
225
+ it("works with complex nested schemas", () => {
226
+ const UserSchema = z.object({
227
+ id: z.string(),
228
+ name: z.string(),
229
+ });
230
+ const UserResultSchema = createResultSchema(UserSchema);
231
+ const result = UserResultSchema.safeParse({
232
+ ok: true,
233
+ data: { id: "123", name: "John" },
234
+ });
235
+ expect(result.success).toBe(true);
236
+ });
237
+ });
238
+ // =============================================================================
239
+ // GenericResultSchema Tests
240
+ // =============================================================================
241
+ describe("GenericResultSchema", () => {
242
+ it("accepts success result with any data", () => {
243
+ const cases = [
244
+ { ok: true, data: "string" },
245
+ { ok: true, data: 123 },
246
+ { ok: true, data: { nested: "object" } },
247
+ { ok: true, data: [1, 2, 3] },
248
+ { ok: true, data: null },
249
+ ];
250
+ for (const testCase of cases) {
251
+ const result = GenericResultSchema.safeParse(testCase);
252
+ expect(result.success).toBe(true);
253
+ }
254
+ });
255
+ it("accepts error result", () => {
256
+ const result = GenericResultSchema.safeParse({
257
+ ok: false,
258
+ error: validServiceError,
259
+ });
260
+ expect(result.success).toBe(true);
261
+ });
262
+ });
263
+ // =============================================================================
264
+ // createKVResponseSchema Tests
265
+ // =============================================================================
266
+ describe("createKVResponseSchema", () => {
267
+ it("creates schema that accepts valid KV response", () => {
268
+ const StringResponseSchema = createKVResponseSchema(z.string());
269
+ const result = StringResponseSchema.safeParse({
270
+ data: "hello",
271
+ headers: validKVResponseHeaders,
272
+ });
273
+ expect(result.success).toBe(true);
274
+ if (result.success) {
275
+ expect(result.data.data).toBe("hello");
276
+ expect(result.data.headers.etag).toBe('"abc123"');
277
+ }
278
+ });
279
+ it("accepts KV response with empty headers", () => {
280
+ const StringResponseSchema = createKVResponseSchema(z.string());
281
+ const result = StringResponseSchema.safeParse({
282
+ data: "hello",
283
+ headers: {},
284
+ });
285
+ expect(result.success).toBe(true);
286
+ });
287
+ it("rejects wrong data type", () => {
288
+ const NumberResponseSchema = createKVResponseSchema(z.number());
289
+ const result = NumberResponseSchema.safeParse({
290
+ data: "not a number",
291
+ headers: {},
292
+ });
293
+ expect(result.success).toBe(false);
294
+ });
295
+ it("rejects missing headers", () => {
296
+ const StringResponseSchema = createKVResponseSchema(z.string());
297
+ const result = StringResponseSchema.safeParse({
298
+ data: "hello",
299
+ });
300
+ expect(result.success).toBe(false);
301
+ });
302
+ });
303
+ // =============================================================================
304
+ // ServiceRequestEventSchema Tests
305
+ // =============================================================================
306
+ describe("ServiceRequestEventSchema", () => {
307
+ it("accepts valid request event with all fields", () => {
308
+ const result = ServiceRequestEventSchema.safeParse(validServiceRequestEvent);
309
+ expect(result.success).toBe(true);
310
+ if (result.success) {
311
+ expect(result.data.service).toBe("kv");
312
+ expect(result.data.action).toBe("tinycloud.kv/get");
313
+ }
314
+ });
315
+ it("accepts request event without optional key", () => {
316
+ const { key, ...withoutKey } = validServiceRequestEvent;
317
+ const result = ServiceRequestEventSchema.safeParse(withoutKey);
318
+ expect(result.success).toBe(true);
319
+ });
320
+ it("rejects missing timestamp", () => {
321
+ const { timestamp, ...withoutTimestamp } = validServiceRequestEvent;
322
+ const result = ServiceRequestEventSchema.safeParse(withoutTimestamp);
323
+ expect(result.success).toBe(false);
324
+ });
325
+ it("rejects non-number timestamp", () => {
326
+ const result = ServiceRequestEventSchema.safeParse({
327
+ ...validServiceRequestEvent,
328
+ timestamp: "2026-02-01",
329
+ });
330
+ expect(result.success).toBe(false);
331
+ });
332
+ });
333
+ // =============================================================================
334
+ // ServiceResponseEventSchema Tests
335
+ // =============================================================================
336
+ describe("ServiceResponseEventSchema", () => {
337
+ it("accepts valid response event", () => {
338
+ const result = ServiceResponseEventSchema.safeParse(validServiceResponseEvent);
339
+ expect(result.success).toBe(true);
340
+ if (result.success) {
341
+ expect(result.data.ok).toBe(true);
342
+ expect(result.data.duration).toBe(150);
343
+ }
344
+ });
345
+ it("accepts response event without optional status", () => {
346
+ const { status, ...withoutStatus } = validServiceResponseEvent;
347
+ const result = ServiceResponseEventSchema.safeParse(withoutStatus);
348
+ expect(result.success).toBe(true);
349
+ });
350
+ it("accepts response event with ok: false", () => {
351
+ const result = ServiceResponseEventSchema.safeParse({
352
+ ...validServiceResponseEvent,
353
+ ok: false,
354
+ status: 404,
355
+ });
356
+ expect(result.success).toBe(true);
357
+ if (result.success) {
358
+ expect(result.data.ok).toBe(false);
359
+ }
360
+ });
361
+ it("rejects missing duration", () => {
362
+ const { duration, ...withoutDuration } = validServiceResponseEvent;
363
+ const result = ServiceResponseEventSchema.safeParse(withoutDuration);
364
+ expect(result.success).toBe(false);
365
+ });
366
+ });
367
+ // =============================================================================
368
+ // ServiceErrorEventSchema Tests
369
+ // =============================================================================
370
+ describe("ServiceErrorEventSchema", () => {
371
+ it("accepts valid error event", () => {
372
+ const result = ServiceErrorEventSchema.safeParse({
373
+ service: "kv",
374
+ error: validServiceError,
375
+ });
376
+ expect(result.success).toBe(true);
377
+ if (result.success) {
378
+ expect(result.data.error.code).toBe("KV_NOT_FOUND");
379
+ }
380
+ });
381
+ it("rejects missing error", () => {
382
+ const result = ServiceErrorEventSchema.safeParse({
383
+ service: "kv",
384
+ });
385
+ expect(result.success).toBe(false);
386
+ });
387
+ it("rejects invalid error structure", () => {
388
+ const result = ServiceErrorEventSchema.safeParse({
389
+ service: "kv",
390
+ error: { invalid: "structure" },
391
+ });
392
+ expect(result.success).toBe(false);
393
+ });
394
+ });
395
+ // =============================================================================
396
+ // ServiceRetryEventSchema Tests
397
+ // =============================================================================
398
+ describe("ServiceRetryEventSchema", () => {
399
+ it("accepts valid retry event", () => {
400
+ const result = ServiceRetryEventSchema.safeParse({
401
+ service: "kv",
402
+ attempt: 2,
403
+ maxAttempts: 3,
404
+ error: validServiceError,
405
+ });
406
+ expect(result.success).toBe(true);
407
+ if (result.success) {
408
+ expect(result.data.attempt).toBe(2);
409
+ }
410
+ });
411
+ it("rejects zero attempt", () => {
412
+ const result = ServiceRetryEventSchema.safeParse({
413
+ service: "kv",
414
+ attempt: 0,
415
+ maxAttempts: 3,
416
+ error: validServiceError,
417
+ });
418
+ expect(result.success).toBe(false);
419
+ });
420
+ it("rejects negative attempt", () => {
421
+ const result = ServiceRetryEventSchema.safeParse({
422
+ service: "kv",
423
+ attempt: -1,
424
+ maxAttempts: 3,
425
+ error: validServiceError,
426
+ });
427
+ expect(result.success).toBe(false);
428
+ });
429
+ it("rejects non-integer attempt", () => {
430
+ const result = ServiceRetryEventSchema.safeParse({
431
+ service: "kv",
432
+ attempt: 1.5,
433
+ maxAttempts: 3,
434
+ error: validServiceError,
435
+ });
436
+ expect(result.success).toBe(false);
437
+ });
438
+ });
439
+ // =============================================================================
440
+ // RetryPolicySchema Tests
441
+ // =============================================================================
442
+ describe("RetryPolicySchema", () => {
443
+ it("accepts valid retry policy", () => {
444
+ const result = RetryPolicySchema.safeParse(validRetryPolicy);
445
+ expect(result.success).toBe(true);
446
+ if (result.success) {
447
+ expect(result.data.backoff).toBe("exponential");
448
+ }
449
+ });
450
+ it("accepts all backoff strategies", () => {
451
+ const strategies = ["none", "linear", "exponential"];
452
+ for (const backoff of strategies) {
453
+ const result = RetryPolicySchema.safeParse({
454
+ ...validRetryPolicy,
455
+ backoff,
456
+ });
457
+ expect(result.success).toBe(true);
458
+ }
459
+ });
460
+ it("rejects invalid backoff strategy", () => {
461
+ const result = RetryPolicySchema.safeParse({
462
+ ...validRetryPolicy,
463
+ backoff: "invalid",
464
+ });
465
+ expect(result.success).toBe(false);
466
+ });
467
+ it("rejects negative maxAttempts", () => {
468
+ const result = RetryPolicySchema.safeParse({
469
+ ...validRetryPolicy,
470
+ maxAttempts: -1,
471
+ });
472
+ expect(result.success).toBe(false);
473
+ });
474
+ it("rejects zero maxAttempts", () => {
475
+ const result = RetryPolicySchema.safeParse({
476
+ ...validRetryPolicy,
477
+ maxAttempts: 0,
478
+ });
479
+ expect(result.success).toBe(false);
480
+ });
481
+ it("rejects negative baseDelayMs", () => {
482
+ const result = RetryPolicySchema.safeParse({
483
+ ...validRetryPolicy,
484
+ baseDelayMs: -100,
485
+ });
486
+ expect(result.success).toBe(false);
487
+ });
488
+ it("accepts zero baseDelayMs", () => {
489
+ const result = RetryPolicySchema.safeParse({
490
+ ...validRetryPolicy,
491
+ baseDelayMs: 0,
492
+ });
493
+ expect(result.success).toBe(true);
494
+ });
495
+ it("accepts empty retryableErrors array", () => {
496
+ const result = RetryPolicySchema.safeParse({
497
+ ...validRetryPolicy,
498
+ retryableErrors: [],
499
+ });
500
+ expect(result.success).toBe(true);
501
+ });
502
+ });
503
+ // =============================================================================
504
+ // ServiceSessionSchema Tests
505
+ // =============================================================================
506
+ describe("ServiceSessionSchema", () => {
507
+ it("accepts valid service session", () => {
508
+ const result = ServiceSessionSchema.safeParse(validServiceSession);
509
+ expect(result.success).toBe(true);
510
+ if (result.success) {
511
+ expect(result.data.spaceId).toBe("space123");
512
+ }
513
+ });
514
+ it("rejects missing delegationHeader", () => {
515
+ const { delegationHeader, ...withoutHeader } = validServiceSession;
516
+ const result = ServiceSessionSchema.safeParse(withoutHeader);
517
+ expect(result.success).toBe(false);
518
+ });
519
+ it("rejects invalid delegationHeader structure", () => {
520
+ const result = ServiceSessionSchema.safeParse({
521
+ ...validServiceSession,
522
+ delegationHeader: { InvalidKey: "value" },
523
+ });
524
+ expect(result.success).toBe(false);
525
+ });
526
+ it("rejects missing spaceId", () => {
527
+ const { spaceId, ...withoutSpaceId } = validServiceSession;
528
+ const result = ServiceSessionSchema.safeParse(withoutSpaceId);
529
+ expect(result.success).toBe(false);
530
+ });
531
+ it("rejects missing jwk", () => {
532
+ const { jwk, ...withoutJwk } = validServiceSession;
533
+ const result = ServiceSessionSchema.safeParse(withoutJwk);
534
+ expect(result.success).toBe(false);
535
+ });
536
+ it("accepts jwk with various structures", () => {
537
+ const jwks = [
538
+ { kty: "EC", crv: "P-256" },
539
+ { kty: "OKP", crv: "Ed25519", x: "abc" },
540
+ { kty: "RSA", n: "...", e: "AQAB" },
541
+ ];
542
+ for (const jwk of jwks) {
543
+ const result = ServiceSessionSchema.safeParse({
544
+ ...validServiceSession,
545
+ jwk,
546
+ });
547
+ expect(result.success).toBe(true);
548
+ }
549
+ });
550
+ });
551
+ // =============================================================================
552
+ // Validation Function Tests
553
+ // =============================================================================
554
+ describe("validateServiceError", () => {
555
+ it("returns ok result for valid data", () => {
556
+ const result = validateServiceError(validServiceError);
557
+ expect(result.ok).toBe(true);
558
+ if (result.ok) {
559
+ expect(result.data.code).toBe("KV_NOT_FOUND");
560
+ }
561
+ });
562
+ it("returns error result for invalid data", () => {
563
+ const result = validateServiceError({});
564
+ expect(result.ok).toBe(false);
565
+ if (!result.ok) {
566
+ expect(result.error.code).toBe("VALIDATION_ERROR");
567
+ expect(result.error.service).toBe("validation");
568
+ expect(result.error.meta?.issues).toBeDefined();
569
+ }
570
+ });
571
+ });
572
+ describe("validateKVListResponse", () => {
573
+ it("returns ok result for valid data", () => {
574
+ const result = validateKVListResponse(validKVListResponse);
575
+ expect(result.ok).toBe(true);
576
+ if (result.ok) {
577
+ expect(result.data.keys).toEqual(["key1", "key2", "key3"]);
578
+ }
579
+ });
580
+ it("returns error result for invalid data", () => {
581
+ const result = validateKVListResponse({ keys: "not-an-array" });
582
+ expect(result.ok).toBe(false);
583
+ if (!result.ok) {
584
+ expect(result.error.code).toBe("VALIDATION_ERROR");
585
+ expect(result.error.service).toBe("kv");
586
+ }
587
+ });
588
+ });
589
+ describe("validateKVResponseHeaders", () => {
590
+ it("returns ok result for valid data", () => {
591
+ const result = validateKVResponseHeaders(validKVResponseHeaders);
592
+ expect(result.ok).toBe(true);
593
+ if (result.ok) {
594
+ expect(result.data.etag).toBe('"abc123"');
595
+ }
596
+ });
597
+ it("returns ok result for empty object", () => {
598
+ const result = validateKVResponseHeaders({});
599
+ expect(result.ok).toBe(true);
600
+ });
601
+ it("returns error result for null", () => {
602
+ const result = validateKVResponseHeaders(null);
603
+ expect(result.ok).toBe(false);
604
+ });
605
+ });
606
+ describe("validateServiceSession", () => {
607
+ it("returns ok result for valid data", () => {
608
+ const result = validateServiceSession(validServiceSession);
609
+ expect(result.ok).toBe(true);
610
+ if (result.ok) {
611
+ expect(result.data.spaceId).toBe("space123");
612
+ }
613
+ });
614
+ it("returns error result for invalid data", () => {
615
+ const result = validateServiceSession({});
616
+ expect(result.ok).toBe(false);
617
+ if (!result.ok) {
618
+ expect(result.error.code).toBe("VALIDATION_ERROR");
619
+ expect(result.error.service).toBe("session");
620
+ }
621
+ });
622
+ });
623
+ describe("validateRetryPolicy", () => {
624
+ it("returns ok result for valid data", () => {
625
+ const result = validateRetryPolicy(validRetryPolicy);
626
+ expect(result.ok).toBe(true);
627
+ if (result.ok) {
628
+ expect(result.data.maxAttempts).toBe(3);
629
+ }
630
+ });
631
+ it("returns error result for invalid backoff", () => {
632
+ const result = validateRetryPolicy({
633
+ ...validRetryPolicy,
634
+ backoff: "invalid",
635
+ });
636
+ expect(result.ok).toBe(false);
637
+ if (!result.ok) {
638
+ expect(result.error.code).toBe("VALIDATION_ERROR");
639
+ expect(result.error.service).toBe("config");
640
+ }
641
+ });
642
+ });
643
+ describe("validateServiceRequestEvent", () => {
644
+ it("returns ok result for valid data", () => {
645
+ const result = validateServiceRequestEvent(validServiceRequestEvent);
646
+ expect(result.ok).toBe(true);
647
+ if (result.ok) {
648
+ expect(result.data.action).toBe("tinycloud.kv/get");
649
+ }
650
+ });
651
+ it("returns error result for missing timestamp", () => {
652
+ const { timestamp, ...withoutTimestamp } = validServiceRequestEvent;
653
+ const result = validateServiceRequestEvent(withoutTimestamp);
654
+ expect(result.ok).toBe(false);
655
+ if (!result.ok) {
656
+ expect(result.error.service).toBe("telemetry");
657
+ }
658
+ });
659
+ });
660
+ describe("validateServiceResponseEvent", () => {
661
+ it("returns ok result for valid data", () => {
662
+ const result = validateServiceResponseEvent(validServiceResponseEvent);
663
+ expect(result.ok).toBe(true);
664
+ if (result.ok) {
665
+ expect(result.data.duration).toBe(150);
666
+ }
667
+ });
668
+ it("returns error result for missing ok", () => {
669
+ const { ok, ...withoutOk } = validServiceResponseEvent;
670
+ const result = validateServiceResponseEvent(withoutOk);
671
+ expect(result.ok).toBe(false);
672
+ if (!result.ok) {
673
+ expect(result.error.service).toBe("telemetry");
674
+ }
675
+ });
676
+ });
677
+ //# sourceMappingURL=types.schema.test.js.map