@jxsuite/starters 1.2.2 → 1.6.1

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 (82) hide show
  1. package/README.md +196 -0
  2. package/package.json +4 -2
  3. package/registry.json +16 -0
  4. package/sites/blog/document.schema.json +633 -115
  5. package/sites/blog/package.json +3 -3
  6. package/sites/blog/project.schema.json +523 -24
  7. package/sites/course/document.schema.json +633 -115
  8. package/sites/course/package.json +3 -3
  9. package/sites/course/project.schema.json +523 -24
  10. package/sites/event/document.schema.json +633 -115
  11. package/sites/event/package.json +3 -3
  12. package/sites/event/project.schema.json +523 -24
  13. package/sites/fitness-studio/document.schema.json +633 -115
  14. package/sites/fitness-studio/package.json +3 -3
  15. package/sites/fitness-studio/project.schema.json +523 -24
  16. package/sites/home-services/document.schema.json +633 -115
  17. package/sites/home-services/package.json +3 -3
  18. package/sites/home-services/project.schema.json +523 -24
  19. package/sites/museum/components/mu-band.json +92 -0
  20. package/sites/museum/components/mu-cta.json +101 -0
  21. package/sites/museum/components/mu-exhibition-card.json +191 -0
  22. package/sites/museum/components/mu-exhibition-row.json +237 -0
  23. package/sites/museum/components/mu-fact.json +64 -0
  24. package/sites/museum/components/mu-footer.json +256 -0
  25. package/sites/museum/components/mu-hero.json +236 -0
  26. package/sites/museum/components/mu-more.json +63 -0
  27. package/sites/museum/components/mu-oculus.json +44 -0
  28. package/sites/museum/components/mu-pagehead.json +105 -0
  29. package/sites/museum/components/mu-quote.json +49 -0
  30. package/sites/museum/content/exhibitions/ar/clay-salt-thread.md +18 -0
  31. package/sites/museum/content/exhibitions/ar/harbour-and-crane.md +18 -0
  32. package/sites/museum/content/exhibitions/ar/the-cartographers-room.md +18 -0
  33. package/sites/museum/content/exhibitions/en/clay-salt-thread.md +19 -0
  34. package/sites/museum/content/exhibitions/en/harbour-and-crane.md +19 -0
  35. package/sites/museum/content/exhibitions/en/the-cartographers-room.md +19 -0
  36. package/sites/museum/content/exhibitions/fr-CA/clay-salt-thread.md +18 -0
  37. package/sites/museum/content/exhibitions/fr-CA/harbour-and-crane.md +18 -0
  38. package/sites/museum/content/exhibitions/fr-CA/the-cartographers-room.md +18 -0
  39. package/sites/museum/document.schema.json +23513 -0
  40. package/sites/museum/layouts/ar.json +29 -0
  41. package/sites/museum/layouts/base.json +329 -0
  42. package/sites/museum/layouts/fr-ca.json +28 -0
  43. package/sites/museum/package.json +18 -0
  44. package/sites/museum/pages/about.json +378 -0
  45. package/sites/museum/pages/ar/about.json +314 -0
  46. package/sites/museum/pages/ar/exhibitions/[slug].json +211 -0
  47. package/sites/museum/pages/ar/exhibitions/index.json +103 -0
  48. package/sites/museum/pages/ar/index.json +246 -0
  49. package/sites/museum/pages/ar/visit.json +327 -0
  50. package/sites/museum/pages/exhibitions/[slug].json +200 -0
  51. package/sites/museum/pages/exhibitions/index.json +93 -0
  52. package/sites/museum/pages/fr-ca/a-propos.json +313 -0
  53. package/sites/museum/pages/fr-ca/expositions/[slug].json +215 -0
  54. package/sites/museum/pages/fr-ca/expositions/index.json +104 -0
  55. package/sites/museum/pages/fr-ca/index.json +246 -0
  56. package/sites/museum/pages/fr-ca/visite.json +328 -0
  57. package/sites/museum/pages/index.json +236 -0
  58. package/sites/museum/pages/visit.json +317 -0
  59. package/sites/museum/project.json +179 -0
  60. package/sites/museum/project.schema.json +996 -0
  61. package/sites/museum/public/favicon.svg +8 -0
  62. package/sites/nonprofit/document.schema.json +633 -115
  63. package/sites/nonprofit/package.json +3 -3
  64. package/sites/nonprofit/project.schema.json +523 -24
  65. package/sites/portfolio/document.schema.json +633 -115
  66. package/sites/portfolio/package.json +3 -3
  67. package/sites/portfolio/project.schema.json +523 -24
  68. package/sites/professional-firm/document.schema.json +633 -115
  69. package/sites/professional-firm/package.json +3 -3
  70. package/sites/professional-firm/project.schema.json +523 -24
  71. package/sites/real-estate/document.schema.json +633 -115
  72. package/sites/real-estate/package.json +3 -3
  73. package/sites/real-estate/project.schema.json +523 -24
  74. package/sites/restaurant/document.schema.json +633 -115
  75. package/sites/restaurant/package.json +3 -3
  76. package/sites/restaurant/project.schema.json +523 -24
  77. package/sites/saas/document.schema.json +633 -115
  78. package/sites/saas/package.json +3 -3
  79. package/sites/saas/project.schema.json +523 -24
  80. package/sites/shop/document.schema.json +633 -115
  81. package/sites/shop/package.json +3 -3
  82. package/sites/shop/project.schema.json +523 -24
@@ -28,6 +28,10 @@
28
28
  "optimize": {
29
29
  "type": "boolean"
30
30
  },
31
+ "picture": {
32
+ "description": "Wrap a multi-format image in a <picture> with one <source> per format (default true). With it off the <img> carries a srcset in the preferred format alone, which browsers that cannot decode that format will still select from.",
33
+ "type": "boolean"
34
+ },
31
35
  "quality": {
32
36
  "properties": {
33
37
  "avif": {
@@ -54,7 +58,10 @@
54
58
  },
55
59
  "service": {
56
60
  "description": "How images are optimized: \"build\" runs Sharp at build time; \"cloudflare\" emits /cdn-cgi/image transform URLs served by Cloudflare Image Transformations (requires the feature to be enabled on the serving zone).",
57
- "enum": ["build", "cloudflare"],
61
+ "enum": [
62
+ "build",
63
+ "cloudflare"
64
+ ],
58
65
  "type": "string"
59
66
  },
60
67
  "sizes": {
@@ -98,11 +105,20 @@
98
105
  "type": "array"
99
106
  },
100
107
  "type": {
101
- "enum": ["string", "number", "integer", "boolean", "array", "object"],
108
+ "enum": [
109
+ "string",
110
+ "number",
111
+ "integer",
112
+ "boolean",
113
+ "array",
114
+ "object"
115
+ ],
102
116
  "type": "string"
103
117
  }
104
118
  },
105
- "required": ["type"],
119
+ "required": [
120
+ "type"
121
+ ],
106
122
  "type": "object"
107
123
  },
108
124
  "RelationshipRef": {
@@ -116,7 +132,9 @@
116
132
  "type": "string"
117
133
  }
118
134
  },
119
- "required": ["$ref"],
135
+ "required": [
136
+ "$ref"
137
+ ],
120
138
  "type": "object"
121
139
  },
122
140
  "StyleObject": {
@@ -156,7 +174,9 @@
156
174
  "type": "string"
157
175
  }
158
176
  },
159
- "required": ["$ref"],
177
+ "required": [
178
+ "$ref"
179
+ ],
160
180
  "type": "object"
161
181
  },
162
182
  {
@@ -226,7 +246,13 @@
226
246
  "properties": {
227
247
  "adapter": {
228
248
  "description": "Platform adapter for deployment-specific output.",
229
- "enum": ["static", "cloudflare-pages", "cloudflare-workers", "node", "bun"],
249
+ "enum": [
250
+ "static",
251
+ "cloudflare-pages",
252
+ "cloudflare-workers",
253
+ "node",
254
+ "bun"
255
+ ],
230
256
  "type": "string"
231
257
  },
232
258
  "deploy": {
@@ -248,17 +274,26 @@
248
274
  },
249
275
  "provider": {
250
276
  "description": "Hosting provider the project is connected to.",
251
- "enum": ["cloudflare-pages"],
277
+ "enum": [
278
+ "cloudflare-pages"
279
+ ],
252
280
  "type": "string"
253
281
  }
254
282
  },
255
- "required": ["provider", "accountId", "projectName"],
283
+ "required": [
284
+ "provider",
285
+ "accountId",
286
+ "projectName"
287
+ ],
256
288
  "type": "object"
257
289
  },
258
290
  "format": {
259
291
  "default": "directory",
260
292
  "description": "Reserved; currently unused. Accepted for forward compatibility with single-file output (desktop single-file mode) — the build emits per-route directories regardless.",
261
- "enum": ["directory", "single"],
293
+ "enum": [
294
+ "directory",
295
+ "single"
296
+ ],
262
297
  "type": "string"
263
298
  },
264
299
  "outDir": {
@@ -266,6 +301,167 @@
266
301
  "description": "Output directory for compiled site.",
267
302
  "type": "string"
268
303
  },
304
+ "headers": {
305
+ "additionalProperties": false,
306
+ "description": "Emit dist/_headers — the response headers only the build can know. Honored by Cloudflare Pages/Workers assets and Netlify; on the node/bun adapters the file documents what a reverse proxy in front of them must send.",
307
+ "properties": {
308
+ "cache": {
309
+ "default": "auto",
310
+ "description": "\"auto\" marks the content-addressed image variants immutable (RFC 8246) and revalidates everything else (RFC 9111). \"off\" emits no Cache-Control at all.",
311
+ "enum": [
312
+ "auto",
313
+ "off"
314
+ ],
315
+ "type": "string"
316
+ },
317
+ "enabled": {
318
+ "default": true,
319
+ "type": "boolean"
320
+ },
321
+ "rules": {
322
+ "additionalProperties": {
323
+ "additionalProperties": {
324
+ "type": "string"
325
+ },
326
+ "type": "object"
327
+ },
328
+ "description": "Verbatim rules, merged after the generated block.",
329
+ "propertyNames": {
330
+ "pattern": "^/"
331
+ },
332
+ "type": "object"
333
+ },
334
+ "security": {
335
+ "additionalProperties": false,
336
+ "properties": {
337
+ "contentTypeOptions": {
338
+ "default": true,
339
+ "type": "boolean"
340
+ },
341
+ "csp": {
342
+ "default": false,
343
+ "description": "CSP Level 3. Off by default: unlike the other security headers this one governs code the build cannot see — a third-party script that loads a second script, a widget that opens a frame — so turning it on is a change to verify in the browser console, not a safe default. `script-src` is derived from the inline scripts and external origins the build emitted; `style-src` keeps 'unsafe-inline', because per-page <style> blocks and per-element style attributes have no site-wide hash.",
344
+ "oneOf": [
345
+ {
346
+ "type": "boolean"
347
+ },
348
+ {
349
+ "const": "report-only"
350
+ },
351
+ {
352
+ "additionalProperties": false,
353
+ "properties": {
354
+ "directives": {
355
+ "additionalProperties": {
356
+ "oneOf": [
357
+ {
358
+ "type": "string"
359
+ },
360
+ {
361
+ "const": false
362
+ }
363
+ ]
364
+ },
365
+ "description": "Replace (string) or remove (false) a computed directive. A replacement is wholesale, so an addition restates the defaults.",
366
+ "type": "object"
367
+ },
368
+ "mode": {
369
+ "default": "enforce",
370
+ "enum": [
371
+ "enforce",
372
+ "report-only"
373
+ ]
374
+ },
375
+ "reportUri": {
376
+ "format": "uri-reference",
377
+ "type": "string"
378
+ }
379
+ },
380
+ "type": "object"
381
+ }
382
+ ]
383
+ },
384
+ "frameOptions": {
385
+ "default": "SAMEORIGIN",
386
+ "oneOf": [
387
+ {
388
+ "enum": [
389
+ "DENY",
390
+ "SAMEORIGIN"
391
+ ],
392
+ "type": "string"
393
+ },
394
+ {
395
+ "const": false
396
+ }
397
+ ]
398
+ },
399
+ "hsts": {
400
+ "default": false,
401
+ "description": "RFC 6797. Off by default: a wrong max-age locks the apex domain to HTTPS for that long, and the mistake is invisible until a certificate lapses. `preload` requires `includeSubDomains` and is a build error without it.",
402
+ "oneOf": [
403
+ {
404
+ "type": "boolean"
405
+ },
406
+ {
407
+ "additionalProperties": false,
408
+ "properties": {
409
+ "includeSubDomains": {
410
+ "default": true,
411
+ "type": "boolean"
412
+ },
413
+ "maxAge": {
414
+ "default": 31536000,
415
+ "minimum": 0,
416
+ "type": "integer"
417
+ },
418
+ "preload": {
419
+ "default": false,
420
+ "type": "boolean"
421
+ }
422
+ },
423
+ "type": "object"
424
+ }
425
+ ]
426
+ },
427
+ "permissionsPolicy": {
428
+ "default": "camera=(), microphone=(), geolocation=()",
429
+ "oneOf": [
430
+ {
431
+ "type": "string"
432
+ },
433
+ {
434
+ "const": false
435
+ }
436
+ ]
437
+ },
438
+ "referrerPolicy": {
439
+ "default": "strict-origin-when-cross-origin",
440
+ "oneOf": [
441
+ {
442
+ "enum": [
443
+ "no-referrer",
444
+ "no-referrer-when-downgrade",
445
+ "origin",
446
+ "origin-when-cross-origin",
447
+ "same-origin",
448
+ "strict-origin",
449
+ "strict-origin-when-cross-origin",
450
+ "unsafe-url"
451
+ ],
452
+ "type": "string"
453
+ },
454
+ {
455
+ "const": false
456
+ }
457
+ ]
458
+ }
459
+ },
460
+ "type": "object"
461
+ }
462
+ },
463
+ "type": "object"
464
+ },
269
465
  "sitemap": {
270
466
  "default": true,
271
467
  "description": "Generate sitemap.xml from the route table (requires `url`). Set false to disable.",
@@ -274,7 +470,11 @@
274
470
  "trailingSlash": {
275
471
  "default": "always",
276
472
  "description": "Trailing slash behavior for generated URLs.",
277
- "enum": ["always", "never", "ignore"],
473
+ "enum": [
474
+ "always",
475
+ "never",
476
+ "ignore"
477
+ ],
278
478
  "type": "string"
279
479
  }
280
480
  },
@@ -295,15 +495,26 @@
295
495
  "description": "Default charset for the page.",
296
496
  "type": "string"
297
497
  },
498
+ "dir": {
499
+ "description": "Base direction for the <html> element. Omitted when unset — a page's `$dir` overrides it. Right-to-left content renders left-to-right without this.",
500
+ "enum": [
501
+ "ltr",
502
+ "rtl",
503
+ "auto"
504
+ ],
505
+ "type": "string"
506
+ },
298
507
  "lang": {
299
508
  "default": "en",
300
- "description": "Default lang attribute for the <html> element.",
509
+ "description": "Default lang attribute for the <html> element. A page's `$lang` overrides it.",
301
510
  "type": "string"
302
511
  },
303
512
  "layout": {
304
513
  "default": null,
305
514
  "description": "Default layout file path applied to all pages. Set to null to render pages without a layout.",
306
- "examples": ["./layouts/base.json"],
515
+ "examples": [
516
+ "./layouts/base.json"
517
+ ],
307
518
  "oneOf": [
308
519
  {
309
520
  "type": "string"
@@ -312,37 +523,255 @@
312
523
  "type": "null"
313
524
  }
314
525
  ]
526
+ },
527
+ "shadow": {
528
+ "default": false,
529
+ "description": "Default shadow-DOM mode for every component (spec.md §16.6). Off unless set: a shadow root isolates component styles from the page and replaces the <slot> emulation with real slot distribution. A component's own `$shadow` overrides this in both directions.",
530
+ "oneOf": [
531
+ {
532
+ "enum": [
533
+ "open",
534
+ "closed"
535
+ ],
536
+ "type": "string"
537
+ },
538
+ {
539
+ "const": false,
540
+ "type": "boolean"
541
+ }
542
+ ]
315
543
  }
316
544
  },
317
545
  "type": "object"
318
546
  },
319
547
  "extensions": {
320
548
  "description": "Extension packages: bare package names (resolved project-first through the package exports map) or relative paths. Each must export jx-extension.json.",
321
- "examples": [["@jxsuite/parser"]],
549
+ "examples": [
550
+ [
551
+ "@jxsuite/parser"
552
+ ]
553
+ ],
322
554
  "items": {
323
555
  "type": "string"
324
556
  },
325
557
  "type": "array"
326
558
  },
559
+ "manifest": {
560
+ "additionalProperties": false,
561
+ "description": "W3C Web App Manifest, emitted as manifest.webmanifest with a <link rel=\"manifest\"> on every page. Absent means no manifest: it is a claim that a site is meant to be installed, and most are not.",
562
+ "properties": {
563
+ "backgroundColor": {
564
+ "type": "string"
565
+ },
566
+ "categories": {
567
+ "items": {
568
+ "type": "string"
569
+ },
570
+ "type": "array"
571
+ },
572
+ "description": {
573
+ "type": "string"
574
+ },
575
+ "dir": {
576
+ "enum": [
577
+ "ltr",
578
+ "rtl",
579
+ "auto"
580
+ ],
581
+ "type": "string"
582
+ },
583
+ "display": {
584
+ "default": "standalone",
585
+ "enum": [
586
+ "fullscreen",
587
+ "standalone",
588
+ "minimal-ui",
589
+ "browser"
590
+ ],
591
+ "type": "string"
592
+ },
593
+ "enabled": {
594
+ "default": true,
595
+ "type": "boolean"
596
+ },
597
+ "icons": {
598
+ "description": "Icons at 192px and 512px are what browsers require before offering to install the site; the build warns when either is missing.",
599
+ "items": {
600
+ "additionalProperties": false,
601
+ "properties": {
602
+ "purpose": {
603
+ "type": "string"
604
+ },
605
+ "sizes": {
606
+ "examples": [
607
+ "192x192"
608
+ ],
609
+ "type": "string"
610
+ },
611
+ "src": {
612
+ "type": "string"
613
+ },
614
+ "type": {
615
+ "type": "string"
616
+ }
617
+ },
618
+ "required": [
619
+ "src"
620
+ ],
621
+ "type": "object"
622
+ },
623
+ "type": "array"
624
+ },
625
+ "lang": {
626
+ "type": "string"
627
+ },
628
+ "name": {
629
+ "description": "Defaults to the project name.",
630
+ "type": "string"
631
+ },
632
+ "orientation": {
633
+ "type": "string"
634
+ },
635
+ "scope": {
636
+ "type": "string"
637
+ },
638
+ "shortName": {
639
+ "type": "string"
640
+ },
641
+ "startUrl": {
642
+ "default": "/",
643
+ "type": "string"
644
+ },
645
+ "themeColor": {
646
+ "type": "string"
647
+ }
648
+ },
649
+ "type": "object"
650
+ },
651
+ "serviceWorker": {
652
+ "default": false,
653
+ "description": "W3C Service Worker, emitted as sw.js. Off unless declared — a worker is sticky, so it is the one output that can keep breaking visitors after a deploy tries to fix them. **Turning it off means `false`, not deleting the key**: `false` emits a tombstone at the same URL that unregisters the old worker and clears its caches, and a 404 there is not an instruction to stop. HTML is always network-first; only the content-addressed /images/_optimized/* is served cache-first.",
654
+ "oneOf": [
655
+ {
656
+ "type": "boolean"
657
+ },
658
+ {
659
+ "additionalProperties": false,
660
+ "properties": {
661
+ "enabled": {
662
+ "default": true,
663
+ "type": "boolean"
664
+ },
665
+ "offlineFallback": {
666
+ "description": "Page served for a failed navigation. Added to `precache` if not already there.",
667
+ "type": "string"
668
+ },
669
+ "precache": {
670
+ "description": "Site-absolute URLs fetched at install time. Each must be a file this build produces; one that is not fails the build, because a single unreachable entry stops the worker installing at all.",
671
+ "items": {
672
+ "pattern": "^/",
673
+ "type": "string"
674
+ },
675
+ "type": "array"
676
+ },
677
+ "scope": {
678
+ "default": "/",
679
+ "type": "string"
680
+ }
681
+ },
682
+ "type": "object"
683
+ }
684
+ ]
685
+ },
686
+ "securityTxt": {
687
+ "additionalProperties": false,
688
+ "description": "RFC 9116 security.txt, emitted at .well-known/security.txt. `expires` is required by §2.5.5 and an absent or past value is a build error — an expired file advertises a reporting channel while telling the reporter not to trust it. A hand-placed public/.well-known/security.txt shadows this, which is how a clearsigned file ships.",
689
+ "properties": {
690
+ "acknowledgments": {
691
+ "items": {
692
+ "type": "string"
693
+ },
694
+ "type": "array"
695
+ },
696
+ "canonical": {
697
+ "type": "string"
698
+ },
699
+ "contact": {
700
+ "description": "At least one mailto:, https: or tel: URI (§2.5.3).",
701
+ "items": {
702
+ "type": "string"
703
+ },
704
+ "type": "array"
705
+ },
706
+ "enabled": {
707
+ "default": true,
708
+ "type": "boolean"
709
+ },
710
+ "encryption": {
711
+ "items": {
712
+ "type": "string"
713
+ },
714
+ "type": "array"
715
+ },
716
+ "expires": {
717
+ "format": "date-time",
718
+ "type": "string"
719
+ },
720
+ "hiring": {
721
+ "items": {
722
+ "type": "string"
723
+ },
724
+ "type": "array"
725
+ },
726
+ "policy": {
727
+ "items": {
728
+ "type": "string"
729
+ },
730
+ "type": "array"
731
+ },
732
+ "preferredLanguages": {
733
+ "description": "BCP 47 tags, validated and canonicalized like i18n.locales.",
734
+ "items": {
735
+ "pattern": "^[A-Za-z]{2,8}(-[A-Za-z0-9]{1,8})*$",
736
+ "type": "string"
737
+ },
738
+ "type": "array"
739
+ }
740
+ },
741
+ "type": "object"
742
+ },
327
743
  "i18n": {
328
744
  "description": "Internationalization configuration.",
329
745
  "properties": {
330
746
  "defaultLocale": {
331
- "description": "Default locale code.",
332
- "examples": ["en"],
747
+ "description": "Default locale, as a BCP 47 language tag. The pattern catches shape errors (`en_US`, `en--US`); the build is the authority on well-formedness.",
748
+ "examples": [
749
+ "en"
750
+ ],
751
+ "pattern": "^[A-Za-z]{2,8}(-[A-Za-z0-9]{1,8})*$",
333
752
  "type": "string"
334
753
  },
335
754
  "locales": {
336
- "description": "Available locale codes.",
337
- "examples": [["en", "fr", "de"]],
755
+ "description": "Available locales, as BCP 47 language tags.",
756
+ "examples": [
757
+ [
758
+ "en",
759
+ "fr",
760
+ "de"
761
+ ]
762
+ ],
338
763
  "items": {
764
+ "pattern": "^[A-Za-z]{2,8}(-[A-Za-z0-9]{1,8})*$",
339
765
  "type": "string"
340
766
  },
341
767
  "type": "array"
342
768
  },
343
769
  "routing": {
344
770
  "description": "Locale routing strategy.",
345
- "enum": ["prefix-except-default", "prefix-always"],
771
+ "enum": [
772
+ "prefix-except-default",
773
+ "prefix-always"
774
+ ],
346
775
  "type": "string"
347
776
  }
348
777
  },
@@ -367,19 +796,81 @@
367
796
  "name": {
368
797
  "default": "Jx Site",
369
798
  "description": "Human-readable project name.",
370
- "examples": ["My Portfolio", "Jx Example Site"],
799
+ "examples": [
800
+ "My Portfolio",
801
+ "Jx Example Site"
802
+ ],
371
803
  "type": "string"
372
804
  },
373
805
  "redirects": {
374
806
  "additionalProperties": {
375
- "type": "string"
807
+ "oneOf": [
808
+ {
809
+ "description": "Destination path or URL; implies a 301.",
810
+ "type": "string"
811
+ },
812
+ {
813
+ "additionalProperties": false,
814
+ "description": "A redirect with an explicit RFC 9110 §15.4 status.",
815
+ "properties": {
816
+ "destination": {
817
+ "type": "string"
818
+ },
819
+ "status": {
820
+ "default": 301,
821
+ "description": "RFC 9110 §15.4 redirection status. 307 and 308 preserve the request method; 301 and 302 historically do not.",
822
+ "enum": [
823
+ 301,
824
+ 302,
825
+ 303,
826
+ 307,
827
+ 308
828
+ ],
829
+ "type": "integer"
830
+ }
831
+ },
832
+ "required": [
833
+ "destination"
834
+ ],
835
+ "type": "object"
836
+ },
837
+ {
838
+ "additionalProperties": false,
839
+ "description": "A rewrite (proxy): the destination's content is served AT the source URL, with no redirect. Emitted as status 200 in `_redirects`, which is the host convention — not an HTTP redirection status.",
840
+ "properties": {
841
+ "destination": {
842
+ "type": "string"
843
+ },
844
+ "rewrite": {
845
+ "const": true,
846
+ "type": "boolean"
847
+ }
848
+ },
849
+ "required": [
850
+ "destination",
851
+ "rewrite"
852
+ ],
853
+ "type": "object"
854
+ }
855
+ ]
376
856
  },
377
- "description": "Static redirect rules. Maps source paths to destination paths.",
857
+ "description": "Static redirect and rewrite rules. Keys are source paths in URLPattern pathname syntax.",
378
858
  "examples": [
379
859
  {
860
+ "/api/*": {
861
+ "destination": "https://api.example.com/*",
862
+ "rewrite": true
863
+ },
864
+ "/legacy/*": {
865
+ "destination": "/archive/*",
866
+ "status": 308
867
+ },
380
868
  "/old-about": "/about"
381
869
  }
382
870
  ],
871
+ "propertyNames": {
872
+ "pattern": "^/"
873
+ },
383
874
  "type": "object"
384
875
  },
385
876
  "state": {
@@ -405,7 +896,10 @@
405
896
  },
406
897
  "url": {
407
898
  "description": "Production URL of the deployed site.",
408
- "examples": ["https://example.com", "https://jxsuite.com"],
899
+ "examples": [
900
+ "https://example.com",
901
+ "https://jxsuite.com"
902
+ ],
409
903
  "type": "string"
410
904
  }
411
905
  },
@@ -437,7 +931,9 @@
437
931
  "type": "string"
438
932
  }
439
933
  },
440
- "required": ["$ref"]
934
+ "required": [
935
+ "$ref"
936
+ ]
441
937
  },
442
938
  {
443
939
  "type": "string"
@@ -474,7 +970,10 @@
474
970
  },
475
971
  "source": {
476
972
  "description": "Path to the content directory relative to the project root.",
477
- "examples": ["./content/blog/", "./content/docs/"],
973
+ "examples": [
974
+ "./content/blog/",
975
+ "./content/docs/"
976
+ ],
478
977
  "type": "string"
479
978
  }
480
979
  }