@rathnasgala2/schemas 3.25.1 → 3.27.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 (46) hide show
  1. package/THIRD_PARTY_LICENSES.json +1 -1
  2. package/diagnostics/diagnostic-map.json +132 -0
  3. package/docs/catalogs/app-routes.json +3 -1
  4. package/docs/catalogs/schema-inventory.json +5 -5
  5. package/examples/valid/build-input/rules.json +147 -0
  6. package/examples/valid/content-frontmatter/rules.json +76 -0
  7. package/examples/valid/publication/rules.json +20 -0
  8. package/fixtures/boundary/build-input/rules.json +165 -0
  9. package/fixtures/boundary/content-frontmatter/rules.json +85 -0
  10. package/fixtures/boundary/publication/rules.json +20 -0
  11. package/fixtures/invalid/build-input/REQUEST_FIELD_UNKNOWN/cases.json +45 -0
  12. package/fixtures/invalid/build-input/SCHEMA_CONSTANT_INVALID/cases.json +11 -0
  13. package/fixtures/invalid/build-input/SCHEMA_ENUM_INVALID/cases.json +22 -0
  14. package/fixtures/invalid/build-input/SCHEMA_NUMBER_TOO_LARGE/cases.json +22 -0
  15. package/fixtures/invalid/build-input/SCHEMA_NUMBER_TOO_SMALL/cases.json +22 -0
  16. package/fixtures/invalid/build-input/SCHEMA_PATTERN_INVALID/cases.json +11 -0
  17. package/fixtures/invalid/build-input/SCHEMA_REQUIRED_FIELD_MISSING/cases.json +132 -0
  18. package/fixtures/invalid/build-input/SCHEMA_TYPE_INVALID/cases.json +56 -0
  19. package/fixtures/invalid/content-frontmatter/REQUEST_FIELD_UNKNOWN/cases.json +16 -0
  20. package/fixtures/invalid/content-frontmatter/SCHEMA_CONSTANT_INVALID/cases.json +11 -0
  21. package/fixtures/invalid/content-frontmatter/SCHEMA_ENUM_INVALID/cases.json +11 -0
  22. package/fixtures/invalid/content-frontmatter/SCHEMA_NUMBER_TOO_LARGE/cases.json +11 -0
  23. package/fixtures/invalid/content-frontmatter/SCHEMA_NUMBER_TOO_SMALL/cases.json +11 -0
  24. package/fixtures/invalid/content-frontmatter/SCHEMA_PATTERN_INVALID/cases.json +11 -0
  25. package/fixtures/invalid/content-frontmatter/SCHEMA_REQUIRED_FIELD_MISSING/cases.json +54 -0
  26. package/fixtures/invalid/content-frontmatter/SCHEMA_TYPE_INVALID/cases.json +20 -0
  27. package/fixtures/invalid/publication/REQUEST_FIELD_UNKNOWN/cases.json +9 -0
  28. package/fixtures/invalid/publication/SCHEMA_REQUIRED_FIELD_MISSING/cases.json +9 -0
  29. package/fixtures/invalid/publication/SCHEMA_TYPE_INVALID/cases.json +18 -0
  30. package/fixtures/manifest.json +1018 -6
  31. package/fixtures/s2/manifest.json +16 -1
  32. package/fixtures/s2/normalized-inputs.json +3225 -0
  33. package/fixtures/unknown-field/build-input/rules.json +73 -0
  34. package/fixtures/unknown-field/content-frontmatter/rules.json +28 -0
  35. package/fixtures/unknown-field/publication/rules.json +14 -0
  36. package/generated/browser/validator-core.mjs +3 -3
  37. package/generated/typescript/contracts/build-input.d.ts +19 -0
  38. package/generated/typescript/contracts/content-frontmatter.d.ts +7 -0
  39. package/generated/typescript/contracts/publication.d.ts +5 -0
  40. package/openapi/http-catalog.json +28 -2
  41. package/openapi/openapi.yaml +523 -10
  42. package/package.json +1 -1
  43. package/sbom.cdx.json +23 -23
  44. package/schemas/build-input.schema.json +62 -1
  45. package/schemas/content-frontmatter.schema.json +31 -0
  46. package/schemas/publication.schema.json +8 -0
package/sbom.cdx.json CHANGED
@@ -97,8 +97,8 @@
97
97
  "type": "library",
98
98
  "name": "schemas",
99
99
  "group": "@rathnasgala2",
100
- "version": "3.25.1",
101
- "bom-ref": "@rathnasgala2/schemas@3.25.1",
100
+ "version": "3.27.0",
101
+ "bom-ref": "@rathnasgala2/schemas@3.27.0",
102
102
  "description": "Executable JSON Schema and OpenAPI contracts for Galascribe",
103
103
  "licenses": [
104
104
  {
@@ -108,7 +108,7 @@
108
108
  }
109
109
  }
110
110
  ],
111
- "purl": "pkg:npm/%40rathnasgala2/schemas@3.25.1?vcs_url=git%2Bhttps%3A%2F%2Fgithub.com%2Frathnasgala2%2Fschema.git",
111
+ "purl": "pkg:npm/%40rathnasgala2/schemas@3.27.0?vcs_url=git%2Bhttps%3A%2F%2Fgithub.com%2Frathnasgala2%2Fschema.git",
112
112
  "externalReferences": [
113
113
  {
114
114
  "url": "https://github.com/rathnasgala2/schema/issues",
@@ -153,7 +153,7 @@
153
153
  "type": "library",
154
154
  "name": "ajv-formats",
155
155
  "version": "3.0.1",
156
- "bom-ref": "@rathnasgala2/schemas@3.25.1|ajv-formats@3.0.1",
156
+ "bom-ref": "@rathnasgala2/schemas@3.27.0|ajv-formats@3.0.1",
157
157
  "licenses": [
158
158
  {
159
159
  "license": {
@@ -187,7 +187,7 @@
187
187
  "type": "library",
188
188
  "name": "ajv",
189
189
  "version": "8.20.0",
190
- "bom-ref": "@rathnasgala2/schemas@3.25.1|ajv@8.20.0",
190
+ "bom-ref": "@rathnasgala2/schemas@3.27.0|ajv@8.20.0",
191
191
  "licenses": [
192
192
  {
193
193
  "license": {
@@ -221,7 +221,7 @@
221
221
  "type": "library",
222
222
  "name": "fast-deep-equal",
223
223
  "version": "3.1.3",
224
- "bom-ref": "@rathnasgala2/schemas@3.25.1|fast-deep-equal@3.1.3",
224
+ "bom-ref": "@rathnasgala2/schemas@3.27.0|fast-deep-equal@3.1.3",
225
225
  "licenses": [
226
226
  {
227
227
  "license": {
@@ -255,7 +255,7 @@
255
255
  "type": "library",
256
256
  "name": "fast-uri",
257
257
  "version": "3.1.8",
258
- "bom-ref": "@rathnasgala2/schemas@3.25.1|fast-uri@3.1.8",
258
+ "bom-ref": "@rathnasgala2/schemas@3.27.0|fast-uri@3.1.8",
259
259
  "licenses": [
260
260
  {
261
261
  "license": {
@@ -289,7 +289,7 @@
289
289
  "type": "library",
290
290
  "name": "json-schema-traverse",
291
291
  "version": "1.0.0",
292
- "bom-ref": "@rathnasgala2/schemas@3.25.1|json-schema-traverse@1.0.0",
292
+ "bom-ref": "@rathnasgala2/schemas@3.27.0|json-schema-traverse@1.0.0",
293
293
  "licenses": [
294
294
  {
295
295
  "license": {
@@ -323,7 +323,7 @@
323
323
  "type": "library",
324
324
  "name": "require-from-string",
325
325
  "version": "2.0.2",
326
- "bom-ref": "@rathnasgala2/schemas@3.25.1|require-from-string@2.0.2",
326
+ "bom-ref": "@rathnasgala2/schemas@3.27.0|require-from-string@2.0.2",
327
327
  "licenses": [
328
328
  {
329
329
  "license": {
@@ -1064,10 +1064,10 @@
1064
1064
  ],
1065
1065
  "dependencies": [
1066
1066
  {
1067
- "ref": "@rathnasgala2/schemas@3.25.1",
1067
+ "ref": "@rathnasgala2/schemas@3.27.0",
1068
1068
  "dependsOn": [
1069
- "@rathnasgala2/schemas@3.25.1|ajv-formats@3.0.1",
1070
- "@rathnasgala2/schemas@3.25.1|ajv@8.20.0",
1069
+ "@rathnasgala2/schemas@3.27.0|ajv-formats@3.0.1",
1070
+ "@rathnasgala2/schemas@3.27.0|ajv@8.20.0",
1071
1071
  "pkg:npm/semver@7.8.5",
1072
1072
  "urn:gala:source-data:iana-ipv4-special-registry",
1073
1073
  "urn:gala:source-data:iana-ipv6-special-registry",
@@ -1089,31 +1089,31 @@
1089
1089
  ]
1090
1090
  },
1091
1091
  {
1092
- "ref": "@rathnasgala2/schemas@3.25.1|ajv-formats@3.0.1",
1092
+ "ref": "@rathnasgala2/schemas@3.27.0|ajv-formats@3.0.1",
1093
1093
  "dependsOn": [
1094
- "@rathnasgala2/schemas@3.25.1|ajv@8.20.0"
1094
+ "@rathnasgala2/schemas@3.27.0|ajv@8.20.0"
1095
1095
  ]
1096
1096
  },
1097
1097
  {
1098
- "ref": "@rathnasgala2/schemas@3.25.1|ajv@8.20.0",
1098
+ "ref": "@rathnasgala2/schemas@3.27.0|ajv@8.20.0",
1099
1099
  "dependsOn": [
1100
- "@rathnasgala2/schemas@3.25.1|fast-deep-equal@3.1.3",
1101
- "@rathnasgala2/schemas@3.25.1|fast-uri@3.1.8",
1102
- "@rathnasgala2/schemas@3.25.1|json-schema-traverse@1.0.0",
1103
- "@rathnasgala2/schemas@3.25.1|require-from-string@2.0.2"
1100
+ "@rathnasgala2/schemas@3.27.0|fast-deep-equal@3.1.3",
1101
+ "@rathnasgala2/schemas@3.27.0|fast-uri@3.1.8",
1102
+ "@rathnasgala2/schemas@3.27.0|json-schema-traverse@1.0.0",
1103
+ "@rathnasgala2/schemas@3.27.0|require-from-string@2.0.2"
1104
1104
  ]
1105
1105
  },
1106
1106
  {
1107
- "ref": "@rathnasgala2/schemas@3.25.1|fast-deep-equal@3.1.3"
1107
+ "ref": "@rathnasgala2/schemas@3.27.0|fast-deep-equal@3.1.3"
1108
1108
  },
1109
1109
  {
1110
- "ref": "@rathnasgala2/schemas@3.25.1|fast-uri@3.1.8"
1110
+ "ref": "@rathnasgala2/schemas@3.27.0|fast-uri@3.1.8"
1111
1111
  },
1112
1112
  {
1113
- "ref": "@rathnasgala2/schemas@3.25.1|json-schema-traverse@1.0.0"
1113
+ "ref": "@rathnasgala2/schemas@3.27.0|json-schema-traverse@1.0.0"
1114
1114
  },
1115
1115
  {
1116
- "ref": "@rathnasgala2/schemas@3.25.1|require-from-string@2.0.2"
1116
+ "ref": "@rathnasgala2/schemas@3.27.0|require-from-string@2.0.2"
1117
1117
  },
1118
1118
  {
1119
1119
  "ref": "pkg:npm/semver@7.8.5"
@@ -520,6 +520,10 @@
520
520
  "newsletter": { "$ref": "#/$defs/newsletter" },
521
521
  "sharing": { "$ref": "#/$defs/sharing" },
522
522
  "contactForm": { "$ref": "#/$defs/contactFormNormalized" },
523
+ "listen": {
524
+ "$ref": "#/$defs/listen",
525
+ "description": "SCHEMA-3.26.0: the toolchain always writes this member, `enabled: false` when the site sets none; a build input without it is read as off, so every 3.25 build input still validates."
526
+ },
523
527
  "sourcePath": { "$ref": "#/$defs/repoRelativePath" },
524
528
  "sourceDigest": { "$ref": "#/$defs/digest" }
525
529
  },
@@ -658,6 +662,55 @@
658
662
  "additionalProperties": false,
659
663
  "description": "SCHEMA-3.22.0: the normalized contact form. `intro` is the rendered body of the optional `gala/theme-pages/contact.md`, absent when the file is absent (the template then shows its default intro). The template renders the `/contact/` page only when `enabled` is true."
660
664
  },
665
+ "listen": {
666
+ "type": "object",
667
+ "required": ["enabled"],
668
+ "properties": { "enabled": { "type": "boolean" } },
669
+ "additionalProperties": false,
670
+ "description": "SCHEMA-3.26.0: the site's Listen setting. `enabled: true` offers the audio version of the posts that have one: the template adds a Listen button to the top bar, a small invitation on each post with audio and a playlist on the home page, and ships its script only while at least one published article carries a `listen` member. An absent `listen` means off. The API, not the schema, limits turning it on to the Pro and Business plans."
671
+ },
672
+ "listenAudio": {
673
+ "type": "object",
674
+ "required": ["sourcePath", "mediaType", "bytes", "sha256"],
675
+ "properties": {
676
+ "sourcePath": {
677
+ "$ref": "#/$defs/repoRelativePath",
678
+ "pattern": "^.+\\.(?:mp3|m4a)$"
679
+ },
680
+ "mediaType": {
681
+ "enum": ["audio/mpeg", "audio/mp4"],
682
+ "description": "What the toolchain sniffed: `audio/mpeg` for an MP3 file, `audio/mp4` for an M4A file."
683
+ },
684
+ "bytes": {
685
+ "type": "integer",
686
+ "minimum": 1,
687
+ "maximum": 26214400,
688
+ "description": "Size of the file in bytes, 1 to 26214400 (25 MiB), which must equal the size of the file in the source tree."
689
+ },
690
+ "sha256": { "$ref": "#/$defs/digest" }
691
+ },
692
+ "additionalProperties": false,
693
+ "description": "SCHEMA-3.26.0: one resolved audio file. `sha256` is the digest of the file bytes and must equal the file digest in the source tree; the file belongs to the source closure like any other asset."
694
+ },
695
+ "contentListenNormalized": {
696
+ "type": "object",
697
+ "required": ["audio", "durationSeconds", "format"],
698
+ "properties": {
699
+ "audio": { "$ref": "#/$defs/listenAudio" },
700
+ "durationSeconds": {
701
+ "type": "integer",
702
+ "minimum": 1,
703
+ "maximum": 10800,
704
+ "description": "Length of the episode in whole seconds, 1 to 10800 (three hours)."
705
+ },
706
+ "format": {
707
+ "enum": ["conversation", "narration", "debate", "skit"],
708
+ "description": "What the episode is: `conversation` (two voices talking the post over), `narration` (one voice reading it), `debate` (two voices taking sides) or `skit` (a scripted scene). The template words its invitation by format."
709
+ }
710
+ },
711
+ "additionalProperties": false,
712
+ "description": "SCHEMA-3.26.0: the normalized audio version of an article. It appears only on a `kind: article` record and is absent when the article has none."
713
+ },
661
714
  "policyPageNormalized": {
662
715
  "type": "object",
663
716
  "required": ["title", "body"],
@@ -1021,7 +1074,8 @@
1021
1074
  "translationOf": {
1022
1075
  "$ref": "#/$defs/slug",
1023
1076
  "description": "SCHEMA-3.21.0: the slug of the article this document translates. The group is that article (the primary, in the publication's default language) plus every document naming it. The target must exist in the same content root, be `kind: article`, carry a different `language`, and must not itself carry `translationOf`; at most one document per language per group. A translation's default route is `/<language lowercased>/<primary slug>/` unless `route` is set. The API enforces the cross-document rules; the schema only fixes the shape: `translationOf` is allowed only when `kind` is `article` and never together with `edition`."
1024
- }
1077
+ },
1078
+ "listen": { "$ref": "#/$defs/contentListenNormalized" }
1025
1079
  },
1026
1080
  "additionalProperties": false,
1027
1081
  "dependentRequired": { "seriesOrder": ["series"] },
@@ -1041,6 +1095,13 @@
1041
1095
  "required": ["kind"],
1042
1096
  "not": { "required": ["edition"] }
1043
1097
  }
1098
+ },
1099
+ {
1100
+ "if": { "required": ["listen"] },
1101
+ "then": {
1102
+ "properties": { "kind": { "const": "article" } },
1103
+ "required": ["kind"]
1104
+ }
1044
1105
  }
1045
1106
  ],
1046
1107
  "$comment": "Timestamp ordering, canonical set ordering, route derivation, and route/redirect collision rules are enforced semantically."
@@ -71,6 +71,7 @@
71
71
  "$ref": "#/$defs/slug",
72
72
  "description": "SCHEMA-3.21.0: the slug of the article this document translates. The group is that article (the primary, in the publication's default language) plus every document naming it. The target must exist in the same content root, be `kind: article`, carry a different `language`, and must not itself carry `translationOf`; at most one document per language per group. A translation's default route is `/<language lowercased>/<primary slug>/` unless `route` is set. The API enforces the cross-document rules; the schema only fixes the shape: `translationOf` is allowed only when `kind` is `article` and never together with `edition`."
73
73
  },
74
+ "listen": { "$ref": "#/$defs/contentListen" },
74
75
  "extensions": { "$ref": "#/$defs/extensionMap" }
75
76
  },
76
77
  "additionalProperties": false,
@@ -228,6 +229,29 @@
228
229
  "pattern": "^\\d{4}-\\d{2}-\\d{2}$",
229
230
  "description": "SCHEMA-3.25.0: the calendar date (`YYYY-MM-DD`, day precision, read in the publication's staggered-release timezone) on or after which Galascribe removes this article from the published site: it leaves every listing, feed, sitemap and search index and its route renders a removed-post notice. Same format as `publishAfter`; it must be later than `publishAfter` and `date` when both exist. The API enforces that rule; the schema only fixes the shape."
230
231
  },
232
+ "contentListen": {
233
+ "type": "object",
234
+ "required": ["audio", "durationSeconds", "format"],
235
+ "properties": {
236
+ "audio": {
237
+ "$ref": "#/$defs/repoRelativePath",
238
+ "pattern": "^.+\\.(?:mp3|m4a)$",
239
+ "description": "Repository-relative path of the audio file: an `.mp3` or `.m4a` file that sits under one of the repository `assetRoots`. The schema fixes the shape and the extension; the publish toolchain checks the asset root, that the file exists and is a regular file, that it sniffs as MP3 or M4A and the size limits."
240
+ },
241
+ "durationSeconds": {
242
+ "type": "integer",
243
+ "minimum": 1,
244
+ "maximum": 10800,
245
+ "description": "Length of the episode in whole seconds, 1 to 10800 (three hours)."
246
+ },
247
+ "format": {
248
+ "enum": ["conversation", "narration", "debate", "skit"],
249
+ "description": "What the episode is: `conversation` (two voices talking the post over), `narration` (one voice reading it), `debate` (two voices taking sides) or `skit` (a scripted scene). The template words its invitation by format."
250
+ }
251
+ },
252
+ "additionalProperties": false,
253
+ "description": "SCHEMA-3.26.0: the audio version of this article. All three members are required. `listen` is allowed only when `kind` is `article`. It has an effect only while the publication has `listen.enabled` true."
254
+ },
231
255
  "contentEdition": {
232
256
  "type": "object",
233
257
  "required": ["of", "kind", "sourceDigest", "generation", "approvedAt"],
@@ -309,6 +333,13 @@
309
333
  "required": ["kind"],
310
334
  "not": { "required": ["edition"] }
311
335
  }
336
+ },
337
+ {
338
+ "if": { "required": ["listen"] },
339
+ "then": {
340
+ "properties": { "kind": { "const": "article" } },
341
+ "required": ["kind"]
342
+ }
312
343
  }
313
344
  ],
314
345
  "$comment": "The content validator enforces canonical set ordering, timestamp ordering, root-kind agreement, and route/redirect collision checks."
@@ -55,6 +55,7 @@
55
55
  "listing": { "$ref": "#/$defs/listing" },
56
56
  "aiRights": { "$ref": "#/$defs/aiRights" },
57
57
  "performance": { "$ref": "#/$defs/performance" },
58
+ "listen": { "$ref": "#/$defs/listen" },
58
59
  "extensions": { "$ref": "#/$defs/extensionMap" }
59
60
  },
60
61
  "additionalProperties": false,
@@ -399,6 +400,13 @@
399
400
  "additionalProperties": false,
400
401
  "description": "SCHEMA-3.25.0: size budgets in bytes, each at least 1024 and optional. `htmlBytes` bounds a page's HTML, `cssBytes` and `jsBytes` bound the sum of the same-origin stylesheets and scripts a page links. A page over budget is reported; a budget never fails a build."
401
402
  },
403
+ "listen": {
404
+ "type": "object",
405
+ "required": ["enabled"],
406
+ "properties": { "enabled": { "type": "boolean" } },
407
+ "additionalProperties": false,
408
+ "description": "SCHEMA-3.26.0: the site's Listen setting. `enabled: true` offers the audio version of the posts that have one: the template adds a Listen button to the top bar, a small invitation on each post with audio and a playlist on the home page, and ships its script only while at least one published article carries a `listen` member. An absent `listen` means off. The API, not the schema, limits turning it on to the Pro and Business plans."
409
+ },
402
410
  "extensionMap": {
403
411
  "type": "object",
404
412
  "maxProperties": 32,