@rathnasgala2/schemas 2.22.0 → 3.1.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 (118) hide show
  1. package/README.md +39 -42
  2. package/THIRD_PARTY_LICENSES.json +3 -3
  3. package/diagnostics/diagnostic-map.json +2701 -1449
  4. package/docs/catalogs/app-components.json +435 -1
  5. package/docs/catalogs/app-routes.json +152 -2
  6. package/docs/catalogs/schema-inventory.json +17 -7
  7. package/examples/valid/artifact-manifest/rules.json +2 -2
  8. package/examples/valid/build-input/rules.json +391 -1
  9. package/examples/valid/build-provenance/rules.json +2 -2
  10. package/examples/valid/interactions-config/canonical.json +18 -0
  11. package/examples/valid/interactions-config/rules.json +529 -0
  12. package/examples/valid/publication/rules.json +48 -0
  13. package/examples/valid/theme-contract/canonical.json +355 -19
  14. package/examples/valid/theme-contract/default-3.0.json +660 -0
  15. package/examples/valid/theme-contract/rules.json +3456 -552
  16. package/fixtures/boundary/artifact-manifest/rules.json +2 -2
  17. package/fixtures/boundary/build-input/rules.json +463 -9
  18. package/fixtures/boundary/build-provenance/rules.json +2 -2
  19. package/fixtures/boundary/interactions-config/root.json +18 -0
  20. package/fixtures/boundary/interactions-config/rules.json +725 -0
  21. package/fixtures/boundary/publication/rules.json +53 -0
  22. package/fixtures/boundary/theme-contract/root.json +355 -19
  23. package/fixtures/boundary/theme-contract/rules.json +4158 -1226
  24. package/fixtures/invalid/artifact-manifest/SCHEMA_CONSTANT_INVALID/cases.json +0 -11
  25. package/fixtures/invalid/artifact-manifest/SCHEMA_TYPE_INVALID/cases.json +11 -0
  26. package/fixtures/invalid/build-input/GRAPHEME_LENGTH_INVALID/cases.json +22 -0
  27. package/fixtures/invalid/build-input/HTTPS_URL_INVALID/cases.json +29 -0
  28. package/fixtures/invalid/build-input/REQUEST_FIELD_UNKNOWN/cases.json +168 -0
  29. package/fixtures/invalid/build-input/SCHEMA_ARRAY_TOO_LONG/cases.json +15 -0
  30. package/fixtures/invalid/build-input/SCHEMA_CONSTANT_INVALID/cases.json +20 -0
  31. package/fixtures/invalid/build-input/SCHEMA_ENUM_INVALID/cases.json +22 -0
  32. package/fixtures/invalid/build-input/SCHEMA_NEGATED_RULE_MATCHED/cases.json +9 -0
  33. package/fixtures/invalid/build-input/SCHEMA_NUMBER_TOO_LARGE/cases.json +22 -0
  34. package/fixtures/invalid/build-input/SCHEMA_NUMBER_TOO_SMALL/cases.json +22 -0
  35. package/fixtures/invalid/build-input/SCHEMA_OBJECT_TOO_LARGE/cases.json +0 -15
  36. package/fixtures/invalid/build-input/SCHEMA_PATTERN_INVALID/cases.json +9 -0
  37. package/fixtures/invalid/build-input/SCHEMA_REQUIRED_FIELD_MISSING/cases.json +429 -0
  38. package/fixtures/invalid/build-input/SCHEMA_TYPE_INVALID/cases.json +212 -0
  39. package/fixtures/invalid/build-input/SCHEMA_VERSION_UNSUPPORTED/cases.json +22 -0
  40. package/fixtures/invalid/build-provenance/SCHEMA_CONSTANT_INVALID/cases.json +0 -11
  41. package/fixtures/invalid/build-provenance/SCHEMA_TYPE_INVALID/cases.json +11 -0
  42. package/fixtures/invalid/interactions-config/BCP47_INVALID/cases.json +58 -0
  43. package/fixtures/invalid/interactions-config/CANONICAL_ROUTE_INVALID/cases.json +38 -0
  44. package/fixtures/invalid/interactions-config/DIGEST_INVALID/cases.json +20 -0
  45. package/fixtures/invalid/interactions-config/EXTENSION_KEY_INVALID/cases.json +20 -0
  46. package/fixtures/invalid/interactions-config/GIT_OBJECT_ID_INVALID/cases.json +20 -0
  47. package/fixtures/invalid/interactions-config/GRAPHEME_LENGTH_INVALID/cases.json +13 -0
  48. package/fixtures/invalid/interactions-config/HTTPS_URL_INVALID/cases.json +29 -0
  49. package/fixtures/invalid/interactions-config/ISO_COUNTRY_INVALID/cases.json +20 -0
  50. package/fixtures/invalid/interactions-config/PACKAGE_EXACT_INVALID/cases.json +38 -0
  51. package/fixtures/invalid/interactions-config/PACKAGE_RANGE_INVALID/cases.json +38 -0
  52. package/fixtures/invalid/interactions-config/PASSIVE_VISUAL_TOKEN_INVALID/cases.json +11 -0
  53. package/fixtures/invalid/interactions-config/PLAIN_LABEL_INVALID/cases.json +31 -0
  54. package/fixtures/invalid/interactions-config/PLAIN_TEXT_INVALID/cases.json +20 -0
  55. package/fixtures/invalid/interactions-config/REPOSITORY_GLOB_INVALID/cases.json +49 -0
  56. package/fixtures/invalid/interactions-config/REPOSITORY_PATH_INVALID/cases.json +62 -0
  57. package/fixtures/invalid/interactions-config/REQUEST_FIELD_UNKNOWN/cases.json +108 -0
  58. package/fixtures/invalid/interactions-config/RFC3339_INVALID/cases.json +29 -0
  59. package/fixtures/invalid/interactions-config/SCHEMA_ARRAY_TOO_LONG/cases.json +17 -0
  60. package/fixtures/invalid/interactions-config/SCHEMA_CONSTANT_INVALID/cases.json +22 -0
  61. package/fixtures/invalid/interactions-config/SCHEMA_ENUM_INVALID/cases.json +13 -0
  62. package/fixtures/invalid/interactions-config/SCHEMA_NEGATED_RULE_MATCHED/cases.json +11 -0
  63. package/fixtures/invalid/interactions-config/SCHEMA_NUMBER_TOO_LARGE/cases.json +24 -0
  64. package/fixtures/invalid/interactions-config/SCHEMA_NUMBER_TOO_SMALL/cases.json +24 -0
  65. package/fixtures/invalid/interactions-config/SCHEMA_PATTERN_INVALID/cases.json +11 -0
  66. package/fixtures/invalid/interactions-config/SCHEMA_REQUIRED_FIELD_MISSING/cases.json +305 -0
  67. package/fixtures/invalid/interactions-config/SCHEMA_TYPE_INVALID/cases.json +175 -0
  68. package/fixtures/invalid/interactions-config/SCHEMA_VERSION_UNSUPPORTED/cases.json +20 -0
  69. package/fixtures/invalid/interactions-config/SEMVER_INVALID/cases.json +20 -0
  70. package/fixtures/invalid/interactions-config/SEMVER_RANGE_INVALID/cases.json +38 -0
  71. package/fixtures/invalid/interactions-config/SLUG_INVALID/cases.json +38 -0
  72. package/fixtures/invalid/interactions-config/STABLE_ID_INVALID/cases.json +20 -0
  73. package/fixtures/invalid/interactions-config/URN_INVALID/cases.json +38 -0
  74. package/fixtures/invalid/publication/GRAPHEME_LENGTH_INVALID/cases.json +11 -0
  75. package/fixtures/invalid/publication/REQUEST_FIELD_UNKNOWN/cases.json +23 -0
  76. package/fixtures/invalid/publication/SCHEMA_ENUM_INVALID/cases.json +9 -0
  77. package/fixtures/invalid/publication/SCHEMA_REQUIRED_FIELD_MISSING/cases.json +42 -0
  78. package/fixtures/invalid/publication/SCHEMA_TYPE_INVALID/cases.json +18 -0
  79. package/fixtures/invalid/theme-contract/REQUEST_FIELD_UNKNOWN/cases.json +421 -20
  80. package/fixtures/invalid/theme-contract/SCHEMA_ARRAY_TOO_LONG/cases.json +2 -2
  81. package/fixtures/invalid/theme-contract/SCHEMA_ARRAY_TOO_SHORT/cases.json +1 -1
  82. package/fixtures/invalid/theme-contract/SCHEMA_CONSTANT_INVALID/cases.json +2155 -296
  83. package/fixtures/invalid/theme-contract/SCHEMA_ENUM_INVALID/cases.json +229 -9
  84. package/fixtures/invalid/theme-contract/SCHEMA_PATTERN_INVALID/cases.json +176 -0
  85. package/fixtures/invalid/theme-contract/SCHEMA_REQUIRED_FIELD_MISSING/cases.json +8812 -1517
  86. package/fixtures/invalid/theme-contract/SCHEMA_STRING_TOO_LONG/cases.json +22 -0
  87. package/fixtures/manifest.json +21925 -12282
  88. package/fixtures/s2/empty-modules-placements.json +233 -3
  89. package/fixtures/s2/manifest.json +2 -1
  90. package/fixtures/s2/theme-contracts-digest-cycle.json +888 -36
  91. package/fixtures/unknown-field/artifact-manifest/rules.json +1 -1
  92. package/fixtures/unknown-field/build-input/rules.json +233 -1
  93. package/fixtures/unknown-field/build-provenance/rules.json +1 -1
  94. package/fixtures/unknown-field/interactions-config/root.json +19 -0
  95. package/fixtures/unknown-field/interactions-config/rules.json +227 -0
  96. package/fixtures/unknown-field/publication/rules.json +35 -0
  97. package/fixtures/unknown-field/theme-contract/root.json +355 -19
  98. package/fixtures/unknown-field/theme-contract/rules.json +637 -22
  99. package/generated/browser/validator-core.mjs +4 -3
  100. package/generated/typescript/contracts/artifact-manifest.d.ts +1 -1
  101. package/generated/typescript/contracts/build-input.d.ts +66 -1
  102. package/generated/typescript/contracts/build-provenance.d.ts +1 -1
  103. package/generated/typescript/contracts/interactions-config.d.ts +91 -0
  104. package/generated/typescript/contracts/publication.d.ts +12 -0
  105. package/generated/typescript/contracts/theme-contract.d.ts +529 -9
  106. package/generated/typescript/index.d.ts +4 -0
  107. package/generated/typescript/index.js +14 -0
  108. package/openapi/http-catalog.json +230 -2
  109. package/openapi/openapi.yaml +5941 -1509
  110. package/package.json +2 -1
  111. package/sbom.cdx.json +23 -23
  112. package/schemas/artifact-manifest.schema.json +1 -1
  113. package/schemas/build-input.schema.json +136 -2
  114. package/schemas/build-provenance.schema.json +1 -1
  115. package/schemas/interactions-config.schema.json +222 -0
  116. package/schemas/publication.schema.json +21 -0
  117. package/schemas/theme-contract.schema.json +1178 -83
  118. package/src/internal/schema-validator.js +3 -0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rathnasgala2/schemas",
3
- "version": "2.22.0",
3
+ "version": "3.1.0",
4
4
  "description": "Executable JSON Schema and OpenAPI contracts for Galascribe",
5
5
  "type": "module",
6
6
  "license": "Apache-2.0",
@@ -40,6 +40,7 @@
40
40
  "./schemas/deployment-observation.schema.json": "./schemas/deployment-observation.schema.json",
41
41
  "./schemas/deployment-receipt.schema.json": "./schemas/deployment-receipt.schema.json",
42
42
  "./schemas/event-envelope.schema.json": "./schemas/event-envelope.schema.json",
43
+ "./schemas/interactions-config.schema.json": "./schemas/interactions-config.schema.json",
43
44
  "./schemas/lock.schema.json": "./schemas/lock.schema.json",
44
45
  "./schemas/navigation.schema.json": "./schemas/navigation.schema.json",
45
46
  "./schemas/problem.schema.json": "./schemas/problem.schema.json",
package/sbom.cdx.json CHANGED
@@ -97,8 +97,8 @@
97
97
  "type": "library",
98
98
  "name": "schemas",
99
99
  "group": "@rathnasgala2",
100
- "version": "2.22.0",
101
- "bom-ref": "@rathnasgala2/schemas@2.22.0",
100
+ "version": "3.1.0",
101
+ "bom-ref": "@rathnasgala2/schemas@3.1.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@2.22.0?vcs_url=git%2Bhttps%3A%2F%2Fgithub.com%2Frathnasgala2%2Fschema.git",
111
+ "purl": "pkg:npm/%40rathnasgala2/schemas@3.1.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@2.22.0|ajv-formats@3.0.1",
156
+ "bom-ref": "@rathnasgala2/schemas@3.1.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@2.22.0|ajv@8.20.0",
190
+ "bom-ref": "@rathnasgala2/schemas@3.1.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@2.22.0|fast-deep-equal@3.1.3",
224
+ "bom-ref": "@rathnasgala2/schemas@3.1.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@2.22.0|fast-uri@3.1.8",
258
+ "bom-ref": "@rathnasgala2/schemas@3.1.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@2.22.0|json-schema-traverse@1.0.0",
292
+ "bom-ref": "@rathnasgala2/schemas@3.1.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@2.22.0|require-from-string@2.0.2",
326
+ "bom-ref": "@rathnasgala2/schemas@3.1.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@2.22.0",
1067
+ "ref": "@rathnasgala2/schemas@3.1.0",
1068
1068
  "dependsOn": [
1069
- "@rathnasgala2/schemas@2.22.0|ajv-formats@3.0.1",
1070
- "@rathnasgala2/schemas@2.22.0|ajv@8.20.0",
1069
+ "@rathnasgala2/schemas@3.1.0|ajv-formats@3.0.1",
1070
+ "@rathnasgala2/schemas@3.1.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@2.22.0|ajv-formats@3.0.1",
1092
+ "ref": "@rathnasgala2/schemas@3.1.0|ajv-formats@3.0.1",
1093
1093
  "dependsOn": [
1094
- "@rathnasgala2/schemas@2.22.0|ajv@8.20.0"
1094
+ "@rathnasgala2/schemas@3.1.0|ajv@8.20.0"
1095
1095
  ]
1096
1096
  },
1097
1097
  {
1098
- "ref": "@rathnasgala2/schemas@2.22.0|ajv@8.20.0",
1098
+ "ref": "@rathnasgala2/schemas@3.1.0|ajv@8.20.0",
1099
1099
  "dependsOn": [
1100
- "@rathnasgala2/schemas@2.22.0|fast-deep-equal@3.1.3",
1101
- "@rathnasgala2/schemas@2.22.0|fast-uri@3.1.8",
1102
- "@rathnasgala2/schemas@2.22.0|json-schema-traverse@1.0.0",
1103
- "@rathnasgala2/schemas@2.22.0|require-from-string@2.0.2"
1100
+ "@rathnasgala2/schemas@3.1.0|fast-deep-equal@3.1.3",
1101
+ "@rathnasgala2/schemas@3.1.0|fast-uri@3.1.8",
1102
+ "@rathnasgala2/schemas@3.1.0|json-schema-traverse@1.0.0",
1103
+ "@rathnasgala2/schemas@3.1.0|require-from-string@2.0.2"
1104
1104
  ]
1105
1105
  },
1106
1106
  {
1107
- "ref": "@rathnasgala2/schemas@2.22.0|fast-deep-equal@3.1.3"
1107
+ "ref": "@rathnasgala2/schemas@3.1.0|fast-deep-equal@3.1.3"
1108
1108
  },
1109
1109
  {
1110
- "ref": "@rathnasgala2/schemas@2.22.0|fast-uri@3.1.8"
1110
+ "ref": "@rathnasgala2/schemas@3.1.0|fast-uri@3.1.8"
1111
1111
  },
1112
1112
  {
1113
- "ref": "@rathnasgala2/schemas@2.22.0|json-schema-traverse@1.0.0"
1113
+ "ref": "@rathnasgala2/schemas@3.1.0|json-schema-traverse@1.0.0"
1114
1114
  },
1115
1115
  {
1116
- "ref": "@rathnasgala2/schemas@2.22.0|require-from-string@2.0.2"
1116
+ "ref": "@rathnasgala2/schemas@3.1.0|require-from-string@2.0.2"
1117
1117
  },
1118
1118
  {
1119
1119
  "ref": "pkg:npm/semver@7.8.5"
@@ -587,7 +587,7 @@
587
587
  "routeClass": { "enum": ["html", "feed", "sitemap", "asset", "error"] },
588
588
  "stableContentId": { "$ref": "#/$defs/stableId" },
589
589
  "sourceRevision": { "$ref": "#/$defs/gitObjectId" },
590
- "interactionBearing": { "const": false }
590
+ "interactionBearing": { "type": "boolean" }
591
591
  },
592
592
  "additionalProperties": false
593
593
  },
@@ -506,6 +506,25 @@
506
506
  },
507
507
  "additionalProperties": false
508
508
  },
509
+ "crawlers": {
510
+ "type": "object",
511
+ "required": ["ai"],
512
+ "properties": { "ai": { "enum": ["allow", "block"] } },
513
+ "additionalProperties": false
514
+ },
515
+ "newsletter": {
516
+ "type": "object",
517
+ "required": ["url", "title", "text"],
518
+ "properties": {
519
+ "url": { "$ref": "#/$defs/urlHttps" },
520
+ "title": { "$ref": "#/$defs/plainLabel" },
521
+ "text": {
522
+ "$ref": "#/$defs/plainText",
523
+ "x-gala-graphemeLength": { "minimum": 1, "maximum": 300 }
524
+ }
525
+ },
526
+ "additionalProperties": false
527
+ },
509
528
  "sourcePath": { "$ref": "#/$defs/repoRelativePath" },
510
529
  "sourceDigest": { "$ref": "#/$defs/digest" }
511
530
  },
@@ -913,9 +932,124 @@
913
932
  "moduleBuildSelection": {
914
933
  "type": "object",
915
934
  "required": [],
916
- "properties": {},
935
+ "properties": {
936
+ "interactions": {
937
+ "type": "object",
938
+ "required": ["config", "apiOrigin", "appOrigin"],
939
+ "properties": {
940
+ "config": { "$ref": "#/$defs/interactionsConfig" },
941
+ "apiOrigin": { "$ref": "#/$defs/interactionsServiceOrigin" },
942
+ "appOrigin": { "$ref": "#/$defs/interactionsServiceOrigin" }
943
+ },
944
+ "additionalProperties": false
945
+ }
946
+ },
947
+ "additionalProperties": false
948
+ },
949
+ "interactionsConfig": {
950
+ "type": "object",
951
+ "required": [
952
+ "schemaId",
953
+ "schemaVersion",
954
+ "reactions",
955
+ "comments",
956
+ "publicCounts"
957
+ ],
958
+ "properties": {
959
+ "schemaId": { "const": "urn:gala:schema:interactions-config:2.0.0" },
960
+ "schemaVersion": { "const": "2.0.0" },
961
+ "reactions": {
962
+ "type": "object",
963
+ "required": ["enabled", "definitions"],
964
+ "properties": {
965
+ "enabled": { "type": "boolean" },
966
+ "definitions": {
967
+ "type": "array",
968
+ "items": { "$ref": "#/$defs/reactionDefinition" },
969
+ "minItems": 0,
970
+ "maxItems": 16
971
+ }
972
+ },
973
+ "additionalProperties": false
974
+ },
975
+ "comments": {
976
+ "type": "object",
977
+ "required": ["enabled", "allowReplies", "maxDepth"],
978
+ "properties": {
979
+ "enabled": { "type": "boolean" },
980
+ "allowReplies": { "type": "boolean" },
981
+ "maxDepth": { "type": "integer", "minimum": 1, "maximum": 4 }
982
+ },
983
+ "additionalProperties": false
984
+ },
985
+ "publicCounts": {
986
+ "type": "object",
987
+ "required": ["reactions", "comments"],
988
+ "properties": {
989
+ "reactions": { "type": "boolean" },
990
+ "comments": { "type": "boolean" }
991
+ },
992
+ "additionalProperties": false
993
+ }
994
+ },
917
995
  "additionalProperties": false,
918
- "maxProperties": 0
996
+ "$comment": "JSON Schema cannot express two rules; consumers enforce them: reaction keys are unique within definitions, and reaction orders are unique within definitions."
997
+ },
998
+ "reactionKey": {
999
+ "type": "string",
1000
+ "pattern": "^[a-z][a-z0-9-]{1,31}$",
1001
+ "not": { "const": "like" },
1002
+ "description": "Stable reaction key. \"like\" is reserved: Like is implicit whenever reactions are enabled."
1003
+ },
1004
+ "reactionVisual": {
1005
+ "type": "object",
1006
+ "required": ["kind", "token"],
1007
+ "properties": {
1008
+ "kind": { "const": "emoji" },
1009
+ "token": {
1010
+ "enum": [
1011
+ "👍",
1012
+ "❤️",
1013
+ "💡",
1014
+ "🎉",
1015
+ "😂",
1016
+ "🤯",
1017
+ "🙏",
1018
+ "🔥",
1019
+ "👏",
1020
+ "😮",
1021
+ "😢",
1022
+ "🤔",
1023
+ "✨",
1024
+ "🚀",
1025
+ "💯",
1026
+ "👀"
1027
+ ]
1028
+ }
1029
+ },
1030
+ "additionalProperties": false
1031
+ },
1032
+ "reactionDefinition": {
1033
+ "type": "object",
1034
+ "required": ["key", "label", "visual", "order", "enabled"],
1035
+ "properties": {
1036
+ "key": { "$ref": "#/$defs/reactionKey" },
1037
+ "label": {
1038
+ "allOf": [{ "$ref": "#/$defs/plainLabel" }],
1039
+ "type": "string",
1040
+ "x-gala-graphemeLength": { "minimum": 1, "maximum": 32 }
1041
+ },
1042
+ "visual": { "$ref": "#/$defs/reactionVisual" },
1043
+ "order": { "type": "integer", "minimum": 1, "maximum": 16 },
1044
+ "enabled": { "type": "boolean" }
1045
+ },
1046
+ "additionalProperties": false
1047
+ },
1048
+ "interactionsServiceOrigin": {
1049
+ "type": "string",
1050
+ "maxLength": 255,
1051
+ "pattern": "^(?:https://[^/?#@\\s]+|http://(?:localhost|127\\.0\\.0\\.1)(?::[0-9]{1,5})?)$",
1052
+ "description": "Credential-free service origin with no path, query or fragment: HTTPS, or http on localhost or 127.0.0.1 for the local runtime profile."
919
1053
  },
920
1054
  "authoredAdapterIdentity": {
921
1055
  "type": "object",
@@ -627,7 +627,7 @@
627
627
  "routeClass": { "enum": ["html", "feed", "sitemap", "asset", "error"] },
628
628
  "stableContentId": { "$ref": "#/$defs/stableId" },
629
629
  "sourceRevision": { "$ref": "#/$defs/gitObjectId" },
630
- "interactionBearing": { "const": false }
630
+ "interactionBearing": { "type": "boolean" }
631
631
  },
632
632
  "additionalProperties": false
633
633
  },
@@ -0,0 +1,222 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "$id": "urn:gala:schema:interactions-config:2.0.0",
4
+ "title": "Gala interactions-config contract",
5
+ "type": "object",
6
+ "required": [
7
+ "schemaId",
8
+ "schemaVersion",
9
+ "reactions",
10
+ "comments",
11
+ "publicCounts"
12
+ ],
13
+ "properties": {
14
+ "schemaId": { "const": "urn:gala:schema:interactions-config:2.0.0" },
15
+ "schemaVersion": { "const": "2.0.0" },
16
+ "reactions": {
17
+ "type": "object",
18
+ "required": ["enabled", "definitions"],
19
+ "properties": {
20
+ "enabled": { "type": "boolean" },
21
+ "definitions": {
22
+ "type": "array",
23
+ "items": { "$ref": "#/$defs/reactionDefinition" },
24
+ "minItems": 0,
25
+ "maxItems": 16
26
+ }
27
+ },
28
+ "additionalProperties": false
29
+ },
30
+ "comments": {
31
+ "type": "object",
32
+ "required": ["enabled", "allowReplies", "maxDepth"],
33
+ "properties": {
34
+ "enabled": { "type": "boolean" },
35
+ "allowReplies": { "type": "boolean" },
36
+ "maxDepth": { "type": "integer", "minimum": 1, "maximum": 4 }
37
+ },
38
+ "additionalProperties": false
39
+ },
40
+ "publicCounts": {
41
+ "type": "object",
42
+ "required": ["reactions", "comments"],
43
+ "properties": {
44
+ "reactions": { "type": "boolean" },
45
+ "comments": { "type": "boolean" }
46
+ },
47
+ "additionalProperties": false
48
+ }
49
+ },
50
+ "additionalProperties": false,
51
+ "$defs": {
52
+ "stableId": {
53
+ "type": "string",
54
+ "pattern": "^[0-9a-f]{8}-[0-9a-f]{4}-7[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$",
55
+ "description": "Lowercase canonical UUIDv7. Once published, it is immutable; its time ordering conveys neither chronology nor authority."
56
+ },
57
+ "slug": {
58
+ "type": "string",
59
+ "minLength": 1,
60
+ "maxLength": 80,
61
+ "pattern": "^[a-z0-9]+(?:-[a-z0-9]+)*$"
62
+ },
63
+ "repoRelativePath": {
64
+ "type": "string",
65
+ "minLength": 1,
66
+ "maxLength": 512,
67
+ "pattern": "^(?!/)(?!.*\\\\)(?!.*\\u0000).+$",
68
+ "format": "gala-repository-relative-path",
69
+ "x-gala-utf8ByteLength": { "maximum": 512 },
70
+ "description": "NFC UTF-8 repository-relative path using slash separators, with no leading slash, dot segment, NUL, backslash, or percent-decoded traversal."
71
+ },
72
+ "canonicalRoute": {
73
+ "type": "string",
74
+ "minLength": 1,
75
+ "pattern": "^/(?!/)(?!.*//)(?!.*[?#]).*$",
76
+ "format": "gala-canonical-route",
77
+ "description": "Absolute normalized route with no query, fragment, dot segment, double slash, or non-normalized percent encoding."
78
+ },
79
+ "gitObjectId": {
80
+ "type": "string",
81
+ "pattern": "^(?:sha1:[0-9a-f]{40}|sha256:[0-9a-f]{64})$"
82
+ },
83
+ "digest": { "type": "string", "pattern": "^sha256:[0-9a-f]{64}$" },
84
+ "urlHttps": {
85
+ "type": "string",
86
+ "format": "uri",
87
+ "pattern": "^https://(?![^/?#]*@)",
88
+ "description": "Absolute HTTPS URL without embedded credentials."
89
+ },
90
+ "bcp47": {
91
+ "type": "string",
92
+ "minLength": 1,
93
+ "maxLength": 255,
94
+ "pattern": "^[A-Za-z0-9-]+$",
95
+ "format": "gala-bcp47",
96
+ "x-gala-utf8ByteLength": { "minimum": 1, "maximum": 255 },
97
+ "description": "Structurally valid canonical BCP-47 language tag."
98
+ },
99
+ "isoCountry": {
100
+ "type": "string",
101
+ "pattern": "^[A-Z]{2}$",
102
+ "format": "gala-iso-country",
103
+ "description": "ISO 3166-1 alpha-2 country code; admission remains subject to the active policy profile."
104
+ },
105
+ "plainLabel": {
106
+ "type": "string",
107
+ "format": "gala-plain-label",
108
+ "x-gala-graphemeLength": { "minimum": 1, "maximum": 80 },
109
+ "description": "Normalized Unicode plain text without markup, controls, or bidi overrides."
110
+ },
111
+ "plainText": {
112
+ "type": "string",
113
+ "format": "gala-plain-text",
114
+ "description": "NFC Unicode text without disallowed C0/C1 controls or bidi override/isolate controls."
115
+ },
116
+ "rfc3339": {
117
+ "type": "string",
118
+ "format": "date-time",
119
+ "pattern": "^[0-9]{4}-(?:0[1-9]|1[0-2])-(?:0[1-9]|[12][0-9]|3[01])T(?:[01][0-9]|2[0-3]):[0-5][0-9]:[0-5][0-9]\\.[0-9]{3}Z$",
120
+ "description": "Canonical Gala UTC millisecond subset of RFC 3339."
121
+ },
122
+ "semver": {
123
+ "type": "string",
124
+ "pattern": "^(?:0|[1-9]\\d*)\\.(?:0|[1-9]\\d*)\\.(?:0|[1-9]\\d*)(?:-(?:0|[1-9]\\d*|\\d*[A-Za-z-][0-9A-Za-z-]*)(?:\\.(?:0|[1-9]\\d*|\\d*[A-Za-z-][0-9A-Za-z-]*))*)?$",
125
+ "description": "Canonical SemVer 2.0.0 without build metadata."
126
+ },
127
+ "semverRange": {
128
+ "type": "string",
129
+ "minLength": 1,
130
+ "pattern": "^(?:\\S+|\\S+ \\S+)$",
131
+ "format": "gala-semver-range",
132
+ "description": "Whitespace-free npm-compatible exact, caret, or bounded comparator-set range; tags and URLs are invalid."
133
+ },
134
+ "packageRange": {
135
+ "type": "string",
136
+ "minLength": 3,
137
+ "pattern": "^(?:@[a-z0-9](?:[a-z0-9._-]*[a-z0-9])?/[a-z0-9](?:[a-z0-9._-]*[a-z0-9])?|[a-z0-9](?:[a-z0-9._-]*[a-z0-9])?)@(?:\\S+|\\S+ \\S+)$",
138
+ "format": "gala-package-range",
139
+ "description": "Lowercase npm package identity and admitted semver range; Git, file, URL, and alias sources are invalid."
140
+ },
141
+ "packageExact": {
142
+ "type": "string",
143
+ "minLength": 3,
144
+ "pattern": "^(?:@[a-z0-9](?:[a-z0-9._-]*[a-z0-9])?/[a-z0-9](?:[a-z0-9._-]*[a-z0-9])?|[a-z0-9](?:[a-z0-9._-]*[a-z0-9])?)@\\S+$",
145
+ "format": "gala-package-exact",
146
+ "description": "Lowercase npm package identity and exact canonical semantic version; aliases are invalid."
147
+ },
148
+ "urn": {
149
+ "type": "string",
150
+ "minLength": 10,
151
+ "maxLength": 255,
152
+ "format": "uri",
153
+ "pattern": "^urn:gala:[\\x21-\\x7E]+$",
154
+ "description": "Absolute ASCII URN in the schema-declared Gala namespace."
155
+ },
156
+ "glob": {
157
+ "type": "string",
158
+ "minLength": 1,
159
+ "maxLength": 256,
160
+ "format": "gala-repository-glob",
161
+ "x-gala-utf8ByteLength": { "maximum": 256 },
162
+ "description": "Repository-relative POSIX glob using only star, globstar, and question-mark operators; braces, extglobs, negation, absolute paths, and parent traversal are invalid."
163
+ },
164
+ "passiveVisualToken": false,
165
+ "extensionKey": {
166
+ "type": "string",
167
+ "format": "gala-extension-key",
168
+ "description": "Reverse-DNS extension namespace that cannot shadow a core key."
169
+ },
170
+ "reactionKey": {
171
+ "type": "string",
172
+ "pattern": "^[a-z][a-z0-9-]{1,31}$",
173
+ "not": { "const": "like" },
174
+ "description": "Stable reaction key. \"like\" is reserved: Like is implicit whenever reactions are enabled."
175
+ },
176
+ "reactionVisual": {
177
+ "type": "object",
178
+ "required": ["kind", "token"],
179
+ "properties": {
180
+ "kind": { "const": "emoji" },
181
+ "token": {
182
+ "enum": [
183
+ "👍",
184
+ "❤️",
185
+ "💡",
186
+ "🎉",
187
+ "😂",
188
+ "🤯",
189
+ "🙏",
190
+ "🔥",
191
+ "👏",
192
+ "😮",
193
+ "😢",
194
+ "🤔",
195
+ "✨",
196
+ "🚀",
197
+ "💯",
198
+ "👀"
199
+ ]
200
+ }
201
+ },
202
+ "additionalProperties": false
203
+ },
204
+ "reactionDefinition": {
205
+ "type": "object",
206
+ "required": ["key", "label", "visual", "order", "enabled"],
207
+ "properties": {
208
+ "key": { "$ref": "#/$defs/reactionKey" },
209
+ "label": {
210
+ "allOf": [{ "$ref": "#/$defs/plainLabel" }],
211
+ "type": "string",
212
+ "x-gala-graphemeLength": { "minimum": 1, "maximum": 32 }
213
+ },
214
+ "visual": { "$ref": "#/$defs/reactionVisual" },
215
+ "order": { "type": "integer", "minimum": 1, "maximum": 16 },
216
+ "enabled": { "type": "boolean" }
217
+ },
218
+ "additionalProperties": false
219
+ }
220
+ },
221
+ "$comment": "JSON Schema cannot express two rules; consumers enforce them: reaction keys are unique within definitions, and reaction orders are unique within definitions."
222
+ }
@@ -47,6 +47,8 @@
47
47
  "defaultImageRef": { "$ref": "#/$defs/repoRelativePath" },
48
48
  "profile": { "$ref": "#/$defs/publicationProfile" },
49
49
  "footerCard": { "$ref": "#/$defs/footerCard" },
50
+ "newsletter": { "$ref": "#/$defs/newsletter" },
51
+ "crawlers": { "$ref": "#/$defs/crawlers" },
50
52
  "extensions": { "$ref": "#/$defs/extensionMap" }
51
53
  },
52
54
  "additionalProperties": false,
@@ -237,6 +239,25 @@
237
239
  },
238
240
  "additionalProperties": false
239
241
  },
242
+ "newsletter": {
243
+ "type": "object",
244
+ "required": ["url", "title", "text"],
245
+ "properties": {
246
+ "url": { "$ref": "#/$defs/urlHttps" },
247
+ "title": { "$ref": "#/$defs/plainLabel" },
248
+ "text": {
249
+ "$ref": "#/$defs/plainText",
250
+ "x-gala-graphemeLength": { "minimum": 1, "maximum": 300 }
251
+ }
252
+ },
253
+ "additionalProperties": false
254
+ },
255
+ "crawlers": {
256
+ "type": "object",
257
+ "required": ["ai"],
258
+ "properties": { "ai": { "enum": ["allow", "block"] } },
259
+ "additionalProperties": false
260
+ },
240
261
  "extensionMap": {
241
262
  "type": "object",
242
263
  "maxProperties": 32,