@notionhq/workers 0.0.82

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 (73) hide show
  1. package/README.md +22 -0
  2. package/dist/block.d.ts +321 -0
  3. package/dist/block.d.ts.map +1 -0
  4. package/dist/block.js +0 -0
  5. package/dist/builder.d.ts +117 -0
  6. package/dist/builder.d.ts.map +1 -0
  7. package/dist/builder.js +168 -0
  8. package/dist/capabilities/automation.d.ts +91 -0
  9. package/dist/capabilities/automation.d.ts.map +1 -0
  10. package/dist/capabilities/automation.js +40 -0
  11. package/dist/capabilities/automation.test.d.ts +2 -0
  12. package/dist/capabilities/automation.test.d.ts.map +1 -0
  13. package/dist/capabilities/context.d.ts +7 -0
  14. package/dist/capabilities/context.d.ts.map +1 -0
  15. package/dist/capabilities/context.js +15 -0
  16. package/dist/capabilities/oauth.d.ts +120 -0
  17. package/dist/capabilities/oauth.d.ts.map +1 -0
  18. package/dist/capabilities/oauth.js +55 -0
  19. package/dist/capabilities/oauth.test.d.ts +2 -0
  20. package/dist/capabilities/oauth.test.d.ts.map +1 -0
  21. package/dist/capabilities/sync.d.ts +180 -0
  22. package/dist/capabilities/sync.d.ts.map +1 -0
  23. package/dist/capabilities/sync.js +84 -0
  24. package/dist/capabilities/sync.test.d.ts +2 -0
  25. package/dist/capabilities/sync.test.d.ts.map +1 -0
  26. package/dist/capabilities/tool.d.ts +68 -0
  27. package/dist/capabilities/tool.d.ts.map +1 -0
  28. package/dist/capabilities/tool.js +174 -0
  29. package/dist/capabilities/tool.test.d.ts +2 -0
  30. package/dist/capabilities/tool.test.d.ts.map +1 -0
  31. package/dist/error.d.ts +12 -0
  32. package/dist/error.d.ts.map +1 -0
  33. package/dist/error.js +15 -0
  34. package/dist/icon-names.d.ts +6 -0
  35. package/dist/icon-names.d.ts.map +1 -0
  36. package/dist/icon-names.js +0 -0
  37. package/dist/index.d.ts +10 -0
  38. package/dist/index.d.ts.map +1 -0
  39. package/dist/index.js +9 -0
  40. package/dist/json-schema.d.ts +117 -0
  41. package/dist/json-schema.d.ts.map +1 -0
  42. package/dist/json-schema.js +0 -0
  43. package/dist/json-schema.test.d.ts +2 -0
  44. package/dist/json-schema.test.d.ts.map +1 -0
  45. package/dist/schema.d.ts +178 -0
  46. package/dist/schema.d.ts.map +1 -0
  47. package/dist/schema.js +66 -0
  48. package/dist/types.d.ts +206 -0
  49. package/dist/types.d.ts.map +1 -0
  50. package/dist/types.js +0 -0
  51. package/dist/worker.d.ts +177 -0
  52. package/dist/worker.d.ts.map +1 -0
  53. package/dist/worker.js +219 -0
  54. package/package.json +68 -0
  55. package/src/block.ts +529 -0
  56. package/src/builder.ts +299 -0
  57. package/src/capabilities/automation.test.ts +152 -0
  58. package/src/capabilities/automation.ts +130 -0
  59. package/src/capabilities/context.ts +23 -0
  60. package/src/capabilities/oauth.test.ts +52 -0
  61. package/src/capabilities/oauth.ts +157 -0
  62. package/src/capabilities/sync.test.ts +104 -0
  63. package/src/capabilities/sync.ts +311 -0
  64. package/src/capabilities/tool.test.ts +351 -0
  65. package/src/capabilities/tool.ts +279 -0
  66. package/src/error.ts +19 -0
  67. package/src/icon-names.ts +890 -0
  68. package/src/index.ts +34 -0
  69. package/src/json-schema.test.ts +719 -0
  70. package/src/json-schema.ts +179 -0
  71. package/src/schema.ts +241 -0
  72. package/src/types.ts +272 -0
  73. package/src/worker.ts +285 -0
@@ -0,0 +1,719 @@
1
+ /**
2
+ * Type-level invariant tests for JSONSchema.
3
+ *
4
+ * Most assertions here are compile-time: a `satisfies` proves a schema is
5
+ * accepted, and `@ts-expect-error` proves an invalid schema is rejected.
6
+ * The runtime `it()` blocks exist only to give structure and make vitest
7
+ * report each invariant by name.
8
+ *
9
+ * For negative tests with multi-line object literals, we use two patterns:
10
+ * 1. Place `@ts-expect-error` directly above the offending property line.
11
+ * 2. Construct the bad value first, then assign on a single line.
12
+ * This ensures tsc sees the error on the line immediately after the directive.
13
+ */
14
+ import { describe, expect, it } from "vitest";
15
+ import type {
16
+ AnyJSONSchema,
17
+ JSONSchema,
18
+ JSONSchemaAnyOfDef,
19
+ JSONSchemaArrayDef,
20
+ JSONSchemaBooleanDef,
21
+ JSONSchemaNullDef,
22
+ JSONSchemaNumberDef,
23
+ JSONSchemaObjectDef,
24
+ JSONSchemaRefDef,
25
+ JSONSchemaStringDef,
26
+ JSONSchemaStringFormat,
27
+ } from "./json-schema.js";
28
+
29
+ // ---------------------------------------------------------------------------
30
+ // Helpers
31
+ // ---------------------------------------------------------------------------
32
+
33
+ /** Compile-time assertion that U is assignable to T. */
34
+ type Assert<_T, _U extends _T> = true;
35
+
36
+ /** Compile-time assertion that U is NOT assignable to T. */
37
+ type AssertNot<_T, _U> = _U extends _T ? never : true;
38
+
39
+ // Suppress "unused" warnings — these are compile-time only.
40
+ type _UseAssert = Assert<unknown, unknown>;
41
+ type _UseAssertNot = AssertNot<never, unknown>;
42
+
43
+ // ---------------------------------------------------------------------------
44
+ // 1. Primitive schemas resolve correctly
45
+ // ---------------------------------------------------------------------------
46
+
47
+ describe("JSONSchema — primitive resolution", () => {
48
+ it("string → JSONSchemaStringDef", () => {
49
+ const _s = {
50
+ type: "string",
51
+ } as const satisfies JSONSchema<string>;
52
+
53
+ // Ref is always acceptable in any position
54
+ const _r = { $ref: "#/$defs/Name" } as const satisfies JSONSchema<string>;
55
+ });
56
+
57
+ it("string with format", () => {
58
+ const _s = {
59
+ type: "string",
60
+ format: "date-time",
61
+ } as const satisfies JSONSchema<string>;
62
+
63
+ const _s2 = {
64
+ type: "string",
65
+ format: "uuid",
66
+ } as const satisfies JSONSchema<string>;
67
+ });
68
+
69
+ it("string with enum", () => {
70
+ const _s = {
71
+ type: "string",
72
+ enum: ["a", "b", "c"] as const,
73
+ } as const satisfies JSONSchema<"a" | "b" | "c">;
74
+ });
75
+
76
+ it("number → JSONSchemaNumberDef", () => {
77
+ const _n = {
78
+ type: "number",
79
+ } as const satisfies JSONSchema<number>;
80
+
81
+ const _i = {
82
+ type: "integer",
83
+ } as const satisfies JSONSchema<number>;
84
+ });
85
+
86
+ it("number with enum", () => {
87
+ const _n = {
88
+ type: "number",
89
+ enum: [1, 2, 3] as const,
90
+ } as const satisfies JSONSchema<1 | 2 | 3>;
91
+ });
92
+
93
+ it("boolean → JSONSchemaBooleanDef", () => {
94
+ const _b = {
95
+ type: "boolean",
96
+ } as const satisfies JSONSchema<boolean>;
97
+ });
98
+
99
+ it("null → JSONSchemaNullDef", () => {
100
+ const _n = {
101
+ type: "null",
102
+ } as const satisfies AnyJSONSchema;
103
+ });
104
+ });
105
+
106
+ // ---------------------------------------------------------------------------
107
+ // 2. Object schemas enforce structural invariants
108
+ // ---------------------------------------------------------------------------
109
+
110
+ describe("JSONSchema — object invariants", () => {
111
+ it("valid object schema compiles", () => {
112
+ const _o = {
113
+ type: "object",
114
+ properties: {
115
+ name: { type: "string" },
116
+ age: { type: "number" },
117
+ },
118
+ required: ["name", "age"],
119
+ additionalProperties: false,
120
+ } as const satisfies JSONSchema<{ name: string; age: number }>;
121
+ });
122
+
123
+ it("object with nested object compiles", () => {
124
+ const _o = {
125
+ type: "object",
126
+ properties: {
127
+ address: {
128
+ type: "object",
129
+ properties: {
130
+ street: { type: "string" },
131
+ zip: { type: "string" },
132
+ },
133
+ required: ["street", "zip"],
134
+ additionalProperties: false,
135
+ },
136
+ },
137
+ required: ["address"],
138
+ additionalProperties: false,
139
+ } as const satisfies JSONSchema<{
140
+ address: { street: string; zip: string };
141
+ }>;
142
+ });
143
+
144
+ it("object with $defs compiles", () => {
145
+ const _o = {
146
+ type: "object",
147
+ properties: {
148
+ name: { $ref: "#/$defs/Name" },
149
+ },
150
+ required: ["name"],
151
+ additionalProperties: false,
152
+ $defs: {
153
+ Name: { type: "string" },
154
+ },
155
+ } as const satisfies JSONSchema<{ name: string }>;
156
+ });
157
+
158
+ it("empty object compiles", () => {
159
+ const _o = {
160
+ type: "object",
161
+ properties: {},
162
+ required: [],
163
+ additionalProperties: false,
164
+ } as const satisfies JSONSchema<Record<string, never>>;
165
+ });
166
+
167
+ it("rejects object without additionalProperties: false", () => {
168
+ const bad = {
169
+ type: "object",
170
+ properties: { name: { type: "string" } },
171
+ required: ["name"],
172
+ } as const;
173
+ // @ts-expect-error — additionalProperties is missing
174
+ const _: JSONSchema<{ name: string }> = bad;
175
+ });
176
+
177
+ it("rejects object with additionalProperties: true", () => {
178
+ const bad = {
179
+ type: "object",
180
+ properties: { name: { type: "string" } },
181
+ required: ["name"],
182
+ additionalProperties: true,
183
+ } as const;
184
+ // @ts-expect-error — additionalProperties must be literally `false`
185
+ const _: JSONSchema<{ name: string }> = bad;
186
+ });
187
+
188
+ it("rejects missing property in properties", () => {
189
+ const bad = {
190
+ type: "object",
191
+ properties: { name: { type: "string" } },
192
+ required: ["name"],
193
+ additionalProperties: false,
194
+ } as const;
195
+ // @ts-expect-error — properties must include all keys of T
196
+ const _: JSONSchema<{ name: string; age: number }> = bad;
197
+ });
198
+
199
+ it("rejects wrong schema type for a property", () => {
200
+ const bad = {
201
+ type: "object",
202
+ properties: { name: { type: "number" } },
203
+ required: ["name"],
204
+ additionalProperties: false,
205
+ } as const;
206
+ // @ts-expect-error — `name` should be string schema, not number
207
+ const _: JSONSchema<{ name: string }> = bad;
208
+ });
209
+ });
210
+
211
+ // ---------------------------------------------------------------------------
212
+ // 3. Nullable types use anyOf pattern
213
+ // ---------------------------------------------------------------------------
214
+
215
+ describe("JSONSchema — nullable types", () => {
216
+ it("string | null → anyOf with null", () => {
217
+ const _s = {
218
+ anyOf: [{ type: "string" }, { type: "null" }],
219
+ } as const satisfies JSONSchema<string | null>;
220
+ });
221
+
222
+ it("number | null → anyOf with null", () => {
223
+ const _n = {
224
+ anyOf: [{ type: "number" }, { type: "null" }],
225
+ } as const satisfies JSONSchema<number | null>;
226
+ });
227
+
228
+ it("object | null → anyOf with null", () => {
229
+ const _o = {
230
+ anyOf: [
231
+ {
232
+ type: "object",
233
+ properties: { id: { type: "number" } },
234
+ required: ["id"],
235
+ additionalProperties: false,
236
+ },
237
+ { type: "null" },
238
+ ],
239
+ } as const satisfies JSONSchema<{ id: number } | null>;
240
+ });
241
+
242
+ it("rejects bare type for nullable", () => {
243
+ // @ts-expect-error — string | null must use anyOf pattern, not bare string
244
+ const _bad: JSONSchema<string | null> = { type: "string" };
245
+ });
246
+ });
247
+
248
+ // ---------------------------------------------------------------------------
249
+ // 4. Array schemas
250
+ // ---------------------------------------------------------------------------
251
+
252
+ describe("JSONSchema — array schemas", () => {
253
+ it("string[] compiles", () => {
254
+ const _a = {
255
+ type: "array",
256
+ items: { type: "string" },
257
+ } as const satisfies JSONSchema<string[]>;
258
+ });
259
+
260
+ it("number[] compiles", () => {
261
+ const _a = {
262
+ type: "array",
263
+ items: { type: "number" },
264
+ } as const satisfies JSONSchema<number[]>;
265
+ });
266
+
267
+ it("object[] compiles", () => {
268
+ const _a = {
269
+ type: "array",
270
+ items: {
271
+ type: "object",
272
+ properties: { name: { type: "string" } },
273
+ required: ["name"],
274
+ additionalProperties: false,
275
+ },
276
+ } as const satisfies JSONSchema<{ name: string }[]>;
277
+ });
278
+
279
+ it("minItems 0 or 1 compiles", () => {
280
+ const _a0 = {
281
+ type: "array",
282
+ items: { type: "string" },
283
+ minItems: 0,
284
+ } as const satisfies JSONSchema<string[]>;
285
+
286
+ const _a1 = {
287
+ type: "array",
288
+ items: { type: "string" },
289
+ minItems: 1,
290
+ } as const satisfies JSONSchema<string[]>;
291
+ });
292
+
293
+ it("rejects minItems > 1", () => {
294
+ const bad = {
295
+ type: "array",
296
+ items: { type: "string" },
297
+ minItems: 2,
298
+ } as const;
299
+ // @ts-expect-error — minItems can only be 0 or 1
300
+ const _: JSONSchema<string[]> = bad;
301
+ });
302
+
303
+ it("rejects wrong item type", () => {
304
+ const bad = { type: "array", items: { type: "number" } } as const;
305
+ // @ts-expect-error — items should be string schema for string[]
306
+ const _: JSONSchema<string[]> = bad;
307
+ });
308
+ });
309
+
310
+ // ---------------------------------------------------------------------------
311
+ // 5. Forbidden composition keywords
312
+ // ---------------------------------------------------------------------------
313
+
314
+ describe("JSONSchema — forbidden composition keywords", () => {
315
+ it("rejects allOf on string def", () => {
316
+ const _bad: JSONSchemaStringDef = {
317
+ type: "string",
318
+ // @ts-expect-error — allOf is forbidden
319
+ allOf: [{ type: "string" }],
320
+ };
321
+ });
322
+
323
+ it("rejects not on number def", () => {
324
+ const _bad: JSONSchemaNumberDef = {
325
+ type: "number",
326
+ // @ts-expect-error — not is forbidden
327
+ not: { type: "string" },
328
+ };
329
+ });
330
+
331
+ it("rejects if/then/else on boolean def", () => {
332
+ const _bad: JSONSchemaBooleanDef = {
333
+ type: "boolean",
334
+ // @ts-expect-error — if is forbidden
335
+ if: { type: "string" },
336
+ };
337
+ });
338
+
339
+ it("rejects allOf on object def", () => {
340
+ const _bad: JSONSchemaObjectDef<{ x: number }> = {
341
+ type: "object",
342
+ properties: { x: { type: "number" } },
343
+ required: ["x"],
344
+ additionalProperties: false,
345
+ // @ts-expect-error — allOf is forbidden
346
+ allOf: [],
347
+ };
348
+ });
349
+
350
+ it("rejects anyOf on concrete string def", () => {
351
+ const _bad: JSONSchemaStringDef = {
352
+ type: "string",
353
+ // @ts-expect-error — anyOf is forbidden on concrete defs
354
+ anyOf: [{ type: "string" }],
355
+ };
356
+ });
357
+
358
+ it("rejects allOf on array def", () => {
359
+ const _bad: JSONSchemaArrayDef = {
360
+ type: "array",
361
+ items: { type: "string" },
362
+ // @ts-expect-error — allOf is forbidden
363
+ allOf: [],
364
+ };
365
+ });
366
+
367
+ it("rejects allOf on null def", () => {
368
+ const _bad: JSONSchemaNullDef = {
369
+ type: "null",
370
+ // @ts-expect-error — allOf is forbidden
371
+ allOf: [],
372
+ };
373
+ });
374
+
375
+ it("rejects allOf on ref def", () => {
376
+ const _bad: JSONSchemaRefDef = {
377
+ $ref: "#/$defs/Foo",
378
+ // @ts-expect-error — allOf is forbidden
379
+ allOf: [],
380
+ };
381
+ });
382
+ });
383
+
384
+ // ---------------------------------------------------------------------------
385
+ // 6. String format is restricted
386
+ // ---------------------------------------------------------------------------
387
+
388
+ describe("JSONSchema — string format restrictions", () => {
389
+ it("accepts all valid formats", () => {
390
+ const formats: JSONSchemaStringFormat[] = [
391
+ "date-time",
392
+ "time",
393
+ "date",
394
+ "duration",
395
+ "email",
396
+ "hostname",
397
+ "ipv4",
398
+ "ipv6",
399
+ "uuid",
400
+ ];
401
+ expect(formats).toHaveLength(9);
402
+ });
403
+
404
+ it("rejects invalid formats", () => {
405
+ // @ts-expect-error — "uri" is not a supported format
406
+ const _bad: JSONSchemaStringDef = { type: "string", format: "uri" };
407
+ });
408
+
409
+ it("rejects uri-reference format", () => {
410
+ const _bad: JSONSchemaStringDef = {
411
+ type: "string",
412
+ // @ts-expect-error — "uri-reference" is not supported
413
+ format: "uri-reference",
414
+ };
415
+ });
416
+ });
417
+
418
+ // ---------------------------------------------------------------------------
419
+ // 7. Cross-kind type mismatches are rejected
420
+ // ---------------------------------------------------------------------------
421
+
422
+ describe("JSONSchema — cross-kind type mismatches", () => {
423
+ it("rejects number schema for string type", () => {
424
+ // @ts-expect-error — cannot use number schema for string
425
+ const _bad: JSONSchema<string> = { type: "number" };
426
+ });
427
+
428
+ it("rejects string schema for number type", () => {
429
+ // @ts-expect-error — cannot use string schema for number
430
+ const _bad: JSONSchema<number> = { type: "string" };
431
+ });
432
+
433
+ it("rejects boolean schema for string type", () => {
434
+ // @ts-expect-error — cannot use boolean schema for string
435
+ const _bad: JSONSchema<string> = { type: "boolean" };
436
+ });
437
+
438
+ it("rejects object schema for string type", () => {
439
+ const bad = {
440
+ type: "object",
441
+ properties: {},
442
+ required: [],
443
+ additionalProperties: false,
444
+ } as const;
445
+ // @ts-expect-error — cannot use object schema for string
446
+ const _: JSONSchema<string> = bad;
447
+ });
448
+
449
+ it("rejects array schema for number type", () => {
450
+ const bad = { type: "array", items: { type: "string" } } as const;
451
+ // @ts-expect-error — cannot use array schema for number
452
+ const _: JSONSchema<number> = bad;
453
+ });
454
+
455
+ it("rejects string schema for object type", () => {
456
+ // @ts-expect-error — cannot use string schema for object
457
+ const _bad: JSONSchema<{ x: number }> = { type: "string" };
458
+ });
459
+
460
+ it("rejects string schema for array type", () => {
461
+ // @ts-expect-error — cannot use string schema for string[]
462
+ const _bad: JSONSchema<string[]> = { type: "string" };
463
+ });
464
+ });
465
+
466
+ // ---------------------------------------------------------------------------
467
+ // 8. $ref is valid in any position
468
+ // ---------------------------------------------------------------------------
469
+
470
+ describe("JSONSchema — $ref universality", () => {
471
+ it("$ref satisfies string schema", () => {
472
+ const _r = {
473
+ $ref: "#/$defs/Foo",
474
+ } as const satisfies JSONSchema<string>;
475
+ });
476
+
477
+ it("$ref satisfies number schema", () => {
478
+ const _r = {
479
+ $ref: "#/$defs/Foo",
480
+ } as const satisfies JSONSchema<number>;
481
+ });
482
+
483
+ it("$ref satisfies boolean schema", () => {
484
+ const _r = {
485
+ $ref: "#/$defs/Foo",
486
+ } as const satisfies JSONSchema<boolean>;
487
+ });
488
+
489
+ it("$ref satisfies object schema", () => {
490
+ const _r = {
491
+ $ref: "#/$defs/Foo",
492
+ } as const satisfies JSONSchema<{ x: number }>;
493
+ });
494
+
495
+ it("$ref satisfies array schema", () => {
496
+ const _r = {
497
+ $ref: "#/$defs/Foo",
498
+ } as const satisfies JSONSchema<string[]>;
499
+ });
500
+
501
+ it("$ref with description compiles", () => {
502
+ const _r = {
503
+ $ref: "#/$defs/Foo",
504
+ description: "A reference",
505
+ } as const satisfies JSONSchema<string>;
506
+ });
507
+ });
508
+
509
+ // ---------------------------------------------------------------------------
510
+ // 9. AnyJSONSchema (T = unknown) accepts all valid forms
511
+ // ---------------------------------------------------------------------------
512
+
513
+ describe("JSONSchema — unknown/AnyJSONSchema", () => {
514
+ it("accepts all primitive schemas", () => {
515
+ const schemas: AnyJSONSchema[] = [
516
+ { type: "string" },
517
+ { type: "number" },
518
+ { type: "integer" },
519
+ { type: "boolean" },
520
+ { type: "null" },
521
+ ];
522
+ expect(schemas).toHaveLength(5);
523
+ });
524
+
525
+ it("accepts ref schema", () => {
526
+ const _r: AnyJSONSchema = { $ref: "#/$defs/Foo" };
527
+ });
528
+
529
+ it("accepts anyOf schema", () => {
530
+ const _a: AnyJSONSchema = {
531
+ anyOf: [{ type: "string" }, { type: "null" }],
532
+ };
533
+ });
534
+
535
+ it("accepts array schema", () => {
536
+ const _a: AnyJSONSchema = {
537
+ type: "array",
538
+ items: { type: "string" },
539
+ };
540
+ });
541
+
542
+ it("accepts object schema", () => {
543
+ const _o: AnyJSONSchema = {
544
+ type: "object",
545
+ properties: { x: { type: "number" } },
546
+ required: ["x"],
547
+ additionalProperties: false,
548
+ };
549
+ });
550
+
551
+ it("JSONSchema<unknown> equals AnyJSONSchema", () => {
552
+ type _A = Assert<JSONSchema<unknown>, AnyJSONSchema>;
553
+ type _B = Assert<AnyJSONSchema, JSONSchema<unknown>>;
554
+ });
555
+ });
556
+
557
+ // ---------------------------------------------------------------------------
558
+ // 10. Complex / edge-case schemas
559
+ // ---------------------------------------------------------------------------
560
+
561
+ describe("JSONSchema — complex schemas", () => {
562
+ it("deeply nested objects", () => {
563
+ type Deep = {
564
+ level1: {
565
+ level2: {
566
+ value: string;
567
+ };
568
+ };
569
+ };
570
+
571
+ const _d = {
572
+ type: "object",
573
+ properties: {
574
+ level1: {
575
+ type: "object",
576
+ properties: {
577
+ level2: {
578
+ type: "object",
579
+ properties: {
580
+ value: { type: "string" },
581
+ },
582
+ required: ["value"],
583
+ additionalProperties: false,
584
+ },
585
+ },
586
+ required: ["level2"],
587
+ additionalProperties: false,
588
+ },
589
+ },
590
+ required: ["level1"],
591
+ additionalProperties: false,
592
+ } as const satisfies JSONSchema<Deep>;
593
+ });
594
+
595
+ it("object with array property", () => {
596
+ type WithArray = { tags: string[] };
597
+
598
+ const _s = {
599
+ type: "object",
600
+ properties: {
601
+ tags: {
602
+ type: "array",
603
+ items: { type: "string" },
604
+ },
605
+ },
606
+ required: ["tags"],
607
+ additionalProperties: false,
608
+ } as const satisfies JSONSchema<WithArray>;
609
+ });
610
+
611
+ it("object with nullable property", () => {
612
+ type WithNullable = { name: string; nickname: string | null };
613
+
614
+ const _s = {
615
+ type: "object",
616
+ properties: {
617
+ name: { type: "string" },
618
+ nickname: {
619
+ anyOf: [{ type: "string" }, { type: "null" }],
620
+ },
621
+ },
622
+ required: ["name", "nickname"],
623
+ additionalProperties: false,
624
+ } as const satisfies JSONSchema<WithNullable>;
625
+ });
626
+
627
+ it("object with enum property", () => {
628
+ type WithEnum = { status: "active" | "inactive" };
629
+
630
+ const _s = {
631
+ type: "object",
632
+ properties: {
633
+ status: {
634
+ type: "string",
635
+ enum: ["active", "inactive"],
636
+ },
637
+ },
638
+ required: ["status"],
639
+ additionalProperties: false,
640
+ } as const satisfies JSONSchema<WithEnum>;
641
+ });
642
+
643
+ it("object with boolean and number properties", () => {
644
+ type Mixed = { enabled: boolean; count: number };
645
+
646
+ const _s = {
647
+ type: "object",
648
+ properties: {
649
+ enabled: { type: "boolean" },
650
+ count: { type: "number" },
651
+ },
652
+ required: ["enabled", "count"],
653
+ additionalProperties: false,
654
+ } as const satisfies JSONSchema<Mixed>;
655
+ });
656
+
657
+ it("array of arrays", () => {
658
+ const _a = {
659
+ type: "array",
660
+ items: {
661
+ type: "array",
662
+ items: { type: "number" },
663
+ },
664
+ } as const satisfies JSONSchema<number[][]>;
665
+ });
666
+ });
667
+
668
+ // ---------------------------------------------------------------------------
669
+ // 11. Type-level assertions (no runtime, purely structural)
670
+ // ---------------------------------------------------------------------------
671
+
672
+ describe("JSONSchema — structural type assertions", () => {
673
+ it("JSONSchemaObjectDef requires additionalProperties to be false", () => {
674
+ type _Proof = Assert<
675
+ JSONSchemaObjectDef<{ x: number }>["additionalProperties"],
676
+ false
677
+ >;
678
+ });
679
+
680
+ it("JSONSchemaArrayDef minItems is restricted to 0 | 1", () => {
681
+ type MinItems = NonNullable<JSONSchemaArrayDef["minItems"]>;
682
+ type _Proof = Assert<MinItems, 0 | 1>;
683
+ // And the reverse — 0 | 1 is exactly MinItems
684
+ type _Reverse = Assert<0 | 1, MinItems>;
685
+ });
686
+
687
+ it("JSONSchemaStringFormat covers exactly 9 formats", () => {
688
+ type _1 = Assert<JSONSchemaStringFormat, "date-time">;
689
+ type _2 = Assert<JSONSchemaStringFormat, "time">;
690
+ type _3 = Assert<JSONSchemaStringFormat, "date">;
691
+ type _4 = Assert<JSONSchemaStringFormat, "duration">;
692
+ type _5 = Assert<JSONSchemaStringFormat, "email">;
693
+ type _6 = Assert<JSONSchemaStringFormat, "hostname">;
694
+ type _7 = Assert<JSONSchemaStringFormat, "ipv4">;
695
+ type _8 = Assert<JSONSchemaStringFormat, "ipv6">;
696
+ type _9 = Assert<JSONSchemaStringFormat, "uuid">;
697
+ });
698
+
699
+ it("JSONSchemaAnyOfDef does not extend ForbiddenCompositionKeywords", () => {
700
+ const _a: JSONSchemaAnyOfDef = {
701
+ anyOf: [{ type: "string" }],
702
+ };
703
+ const _b: JSONSchemaAnyOfDef = {
704
+ anyOf: [{ type: "string" }],
705
+ description: "test",
706
+ };
707
+ });
708
+
709
+ it("JSONSchemaRefDef requires $ref string", () => {
710
+ type _Proof = Assert<JSONSchemaRefDef["$ref"], string>;
711
+ });
712
+
713
+ it("JSONSchemaObjectDef properties keys match T keys", () => {
714
+ type Schema = JSONSchemaObjectDef<{ a: string; b: number }>;
715
+ type PropKeys = keyof Schema["properties"];
716
+ type _Proof = Assert<PropKeys, "a" | "b">;
717
+ type _Reverse = Assert<"a" | "b", PropKeys>;
718
+ });
719
+ });