@comity-dev/schemas 0.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.
- package/LICENSE +21 -0
- package/README.md +59 -0
- package/dist/ajv-instance.d.ts +7 -0
- package/dist/ajv-instance.js +17 -0
- package/dist/constants.d.ts +44 -0
- package/dist/constants.js +54 -0
- package/dist/index.d.ts +9 -0
- package/dist/index.js +6 -0
- package/dist/schemas/adr-008-register-data.d.ts +11 -0
- package/dist/schemas/adr-008-register-data.js +184 -0
- package/dist/schemas/adr-008-register.d.ts +79 -0
- package/dist/schemas/adr-008-register.js +71 -0
- package/dist/schemas/comity-config.d.ts +163 -0
- package/dist/schemas/comity-config.js +122 -0
- package/dist/schemas/index.d.ts +6 -0
- package/dist/schemas/index.js +3 -0
- package/dist/schemas/package-metadata.d.ts +157 -0
- package/dist/schemas/package-metadata.js +147 -0
- package/package.json +41 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Filippo Bovo and contributors
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
# @comity-dev/schemas
|
|
2
|
+
|
|
3
|
+
## Purpose
|
|
4
|
+
|
|
5
|
+
Canonical, machine-readable JSON Schema definitions for Comity package metadata, the ADR-008 register, and `comity.config.json`. These schemas are the authoritative source for Comity-wide metadata policy.
|
|
6
|
+
|
|
7
|
+
## Scope
|
|
8
|
+
|
|
9
|
+
- `package-metadata.v1.json` — required fields and types for every `@comity/*` package's `package.json` (`name`, `version`, `type`, `license`, `engines`, `exports`, `comity.layer`, `comity.implements`).
|
|
10
|
+
- ADR-008 register schema — machine-readable composition exception register.
|
|
11
|
+
- `comity-config.json` schema — repository-level configuration shape.
|
|
12
|
+
|
|
13
|
+
## Ownership
|
|
14
|
+
|
|
15
|
+
Owned by `comity-development`. Consumed by `@comity-dev/validate` (in-process) and indirectly by every Comity repository via the validator.
|
|
16
|
+
|
|
17
|
+
## Public API
|
|
18
|
+
|
|
19
|
+
```ts
|
|
20
|
+
import {
|
|
21
|
+
packageMetadataSchema,
|
|
22
|
+
validatePackageMetadata,
|
|
23
|
+
comityConfigSchema,
|
|
24
|
+
validateComityConfig,
|
|
25
|
+
adr008RegisterSchema,
|
|
26
|
+
validateAdr008Register,
|
|
27
|
+
createAjvInstance,
|
|
28
|
+
PACKAGE_NAME_PATTERN,
|
|
29
|
+
VALID_LAYERS,
|
|
30
|
+
MIN_NODE_VERSION,
|
|
31
|
+
} from "@comity-dev/schemas";
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
A consolidated subpath exposes every schema and its validator for
|
|
35
|
+
finer-grained consumers:
|
|
36
|
+
|
|
37
|
+
```ts
|
|
38
|
+
import {
|
|
39
|
+
packageMetadataSchema,
|
|
40
|
+
validatePackageMetadata,
|
|
41
|
+
comityConfigSchema,
|
|
42
|
+
validateComityConfig,
|
|
43
|
+
adr008RegisterSchema,
|
|
44
|
+
validateAdr008Register,
|
|
45
|
+
} from "@comity-dev/schemas";
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
## Relationship to Comity Standards
|
|
49
|
+
|
|
50
|
+
- `layering-policy.md` §2.1 — layer enum source.
|
|
51
|
+
- `ADR-026` — authoritative package classification.
|
|
52
|
+
- `architecture-validation.md` §8 — package metadata, naming, engines.
|
|
53
|
+
|
|
54
|
+
## Development
|
|
55
|
+
|
|
56
|
+
```bash
|
|
57
|
+
pnpm build
|
|
58
|
+
pnpm test
|
|
59
|
+
```
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import Ajv from "ajv";
|
|
2
|
+
import addFormats from "ajv-formats";
|
|
3
|
+
/**
|
|
4
|
+
* Creates a fresh Ajv instance with strict settings and standard formats.
|
|
5
|
+
*
|
|
6
|
+
* @returns Configured Ajv instance
|
|
7
|
+
*/
|
|
8
|
+
export function createAjvInstance() {
|
|
9
|
+
const ajv = new Ajv({
|
|
10
|
+
allErrors: true,
|
|
11
|
+
strict: false,
|
|
12
|
+
strictTypes: false,
|
|
13
|
+
verbose: true,
|
|
14
|
+
});
|
|
15
|
+
addFormats(ajv);
|
|
16
|
+
return ajv;
|
|
17
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Canonical Comity constants.
|
|
3
|
+
*
|
|
4
|
+
* These values are derived from the authoritative Comity Standards
|
|
5
|
+
* (layering-policy.md, ADR-026). They MUST be kept in sync with those
|
|
6
|
+
* documents; updating them here implies updating the standards.
|
|
7
|
+
*
|
|
8
|
+
* @see layering-policy.md §2.1 / ADR-026 (package classification)
|
|
9
|
+
*
|
|
10
|
+
* ADR-026 defines `comity.layer` as the architecture classification of
|
|
11
|
+
* Comity RUNTIME packages (`@comity/*`). The six runtime layers are:
|
|
12
|
+
*
|
|
13
|
+
* primitives, kernel, composition, core,
|
|
14
|
+
* technology-adapter, integration-adapter
|
|
15
|
+
*
|
|
16
|
+
* `dev-tooling` is a reserved Development-side extension for
|
|
17
|
+
* `@comity-dev/*` packages only. It is NOT a seventh runtime layer
|
|
18
|
+
* and MUST NOT be used by `@comity/*` packages. The name-scope ↔
|
|
19
|
+
* layer boundary is enforced by the package-metadata JSON Schema
|
|
20
|
+
* (`schemas/package-metadata.ts`).
|
|
21
|
+
*
|
|
22
|
+
* Rationale for the extension: Development tooling packages
|
|
23
|
+
* legitimately use Node APIs, `process.env`, and other patterns that
|
|
24
|
+
* the runtime Semgrep and ESLint rules forbid. Declaring `dev-tooling`
|
|
25
|
+
* on these packages lets the validator engines (semgrep, depcruise,
|
|
26
|
+
* eslint, adapter-peers) scope those rules away from them. The
|
|
27
|
+
* runtime six-layer model is unchanged.
|
|
28
|
+
*/
|
|
29
|
+
export declare const RUNTIME_LAYERS: readonly string[];
|
|
30
|
+
/**
|
|
31
|
+
* All layer values accepted by `comity.layer`. The boundary between
|
|
32
|
+
* runtime and development layers is enforced by the schema, not by
|
|
33
|
+
* this list alone.
|
|
34
|
+
*/
|
|
35
|
+
export declare const VALID_LAYERS: readonly string[];
|
|
36
|
+
/**
|
|
37
|
+
* @see ADR-026 (package naming)
|
|
38
|
+
* architecture-validation.md §8
|
|
39
|
+
*/
|
|
40
|
+
export declare const PACKAGE_NAME_PATTERN = "^@comity(-dev)?/[a-z0-9]+(?:-[a-z0-9]+)*$";
|
|
41
|
+
/**
|
|
42
|
+
* @see architecture-validation.md §8 (metadata — engines.node minimum)
|
|
43
|
+
*/
|
|
44
|
+
export declare const MIN_NODE_VERSION = "24.0.0";
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Canonical Comity constants.
|
|
3
|
+
*
|
|
4
|
+
* These values are derived from the authoritative Comity Standards
|
|
5
|
+
* (layering-policy.md, ADR-026). They MUST be kept in sync with those
|
|
6
|
+
* documents; updating them here implies updating the standards.
|
|
7
|
+
*
|
|
8
|
+
* @see layering-policy.md §2.1 / ADR-026 (package classification)
|
|
9
|
+
*
|
|
10
|
+
* ADR-026 defines `comity.layer` as the architecture classification of
|
|
11
|
+
* Comity RUNTIME packages (`@comity/*`). The six runtime layers are:
|
|
12
|
+
*
|
|
13
|
+
* primitives, kernel, composition, core,
|
|
14
|
+
* technology-adapter, integration-adapter
|
|
15
|
+
*
|
|
16
|
+
* `dev-tooling` is a reserved Development-side extension for
|
|
17
|
+
* `@comity-dev/*` packages only. It is NOT a seventh runtime layer
|
|
18
|
+
* and MUST NOT be used by `@comity/*` packages. The name-scope ↔
|
|
19
|
+
* layer boundary is enforced by the package-metadata JSON Schema
|
|
20
|
+
* (`schemas/package-metadata.ts`).
|
|
21
|
+
*
|
|
22
|
+
* Rationale for the extension: Development tooling packages
|
|
23
|
+
* legitimately use Node APIs, `process.env`, and other patterns that
|
|
24
|
+
* the runtime Semgrep and ESLint rules forbid. Declaring `dev-tooling`
|
|
25
|
+
* on these packages lets the validator engines (semgrep, depcruise,
|
|
26
|
+
* eslint, adapter-peers) scope those rules away from them. The
|
|
27
|
+
* runtime six-layer model is unchanged.
|
|
28
|
+
*/
|
|
29
|
+
export const RUNTIME_LAYERS = Object.freeze([
|
|
30
|
+
"primitives",
|
|
31
|
+
"kernel",
|
|
32
|
+
"composition",
|
|
33
|
+
"core",
|
|
34
|
+
"technology-adapter",
|
|
35
|
+
"integration-adapter",
|
|
36
|
+
]);
|
|
37
|
+
/**
|
|
38
|
+
* All layer values accepted by `comity.layer`. The boundary between
|
|
39
|
+
* runtime and development layers is enforced by the schema, not by
|
|
40
|
+
* this list alone.
|
|
41
|
+
*/
|
|
42
|
+
export const VALID_LAYERS = Object.freeze([
|
|
43
|
+
...RUNTIME_LAYERS,
|
|
44
|
+
"dev-tooling",
|
|
45
|
+
]);
|
|
46
|
+
/**
|
|
47
|
+
* @see ADR-026 (package naming)
|
|
48
|
+
* architecture-validation.md §8
|
|
49
|
+
*/
|
|
50
|
+
export const PACKAGE_NAME_PATTERN = "^@comity(-dev)?/[a-z0-9]+(?:-[a-z0-9]+)*$";
|
|
51
|
+
/**
|
|
52
|
+
* @see architecture-validation.md §8 (metadata — engines.node minimum)
|
|
53
|
+
*/
|
|
54
|
+
export const MIN_NODE_VERSION = "24.0.0";
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export type { Adr008Register } from "./schemas/adr-008-register.js";
|
|
2
|
+
export type { ComityConfig } from "./schemas/comity-config.js";
|
|
3
|
+
export type { PackageMetadata, ValidationResult, } from "./schemas/package-metadata.js";
|
|
4
|
+
export { createAjvInstance } from "./ajv-instance.js";
|
|
5
|
+
export { MIN_NODE_VERSION, PACKAGE_NAME_PATTERN, RUNTIME_LAYERS, VALID_LAYERS, } from "./constants.js";
|
|
6
|
+
export { adr008CoreExceptionRegister, } from "./schemas/adr-008-register-data.js";
|
|
7
|
+
export { adr008RegisterSchema, validateAdr008Register, } from "./schemas/adr-008-register.js";
|
|
8
|
+
export { comityConfigSchema, validateComityConfig, } from "./schemas/comity-config.js";
|
|
9
|
+
export { packageMetadataSchema, validatePackageMetadata, } from "./schemas/package-metadata.js";
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export { createAjvInstance } from "./ajv-instance.js";
|
|
2
|
+
export { MIN_NODE_VERSION, PACKAGE_NAME_PATTERN, RUNTIME_LAYERS, VALID_LAYERS, } from "./constants.js";
|
|
3
|
+
export { adr008CoreExceptionRegister, } from "./schemas/adr-008-register-data.js";
|
|
4
|
+
export { adr008RegisterSchema, validateAdr008Register, } from "./schemas/adr-008-register.js";
|
|
5
|
+
export { comityConfigSchema, validateComityConfig, } from "./schemas/comity-config.js";
|
|
6
|
+
export { packageMetadataSchema, validatePackageMetadata, } from "./schemas/package-metadata.js";
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { Adr008Register } from "./adr-008-register.js";
|
|
2
|
+
/**
|
|
3
|
+
* Canonical ADR-008 Core Exception Register.
|
|
4
|
+
*
|
|
5
|
+
* This is the authoritative machine-readable representation of the
|
|
6
|
+
* ADR-008 closed register of Core-to-Core dependency exceptions.
|
|
7
|
+
*
|
|
8
|
+
* @see ADR-008 — Explicit Core Module Composition Exceptions
|
|
9
|
+
* @see ADR-009 — Machine-Readable Core Exception Register
|
|
10
|
+
*/
|
|
11
|
+
export declare const adr008CoreExceptionRegister: Adr008Register;
|
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Canonical ADR-008 Core Exception Register.
|
|
3
|
+
*
|
|
4
|
+
* This is the authoritative machine-readable representation of the
|
|
5
|
+
* ADR-008 closed register of Core-to-Core dependency exceptions.
|
|
6
|
+
*
|
|
7
|
+
* @see ADR-008 — Explicit Core Module Composition Exceptions
|
|
8
|
+
* @see ADR-009 — Machine-Readable Core Exception Register
|
|
9
|
+
*/
|
|
10
|
+
export const adr008CoreExceptionRegister = {
|
|
11
|
+
version: "1",
|
|
12
|
+
edges: [
|
|
13
|
+
{
|
|
14
|
+
from: "@comity/storefront",
|
|
15
|
+
to: "@comity/catalog",
|
|
16
|
+
layer: "core-to-core",
|
|
17
|
+
categories: ["capability"],
|
|
18
|
+
importKind: "type-only",
|
|
19
|
+
lifecycle: "approved",
|
|
20
|
+
justification: "Storefront page composition references catalog domain contracts and models.",
|
|
21
|
+
adrReference: "ADR-008 — Dependency Register, Capability Exceptions",
|
|
22
|
+
},
|
|
23
|
+
{
|
|
24
|
+
from: "@comity/storefront",
|
|
25
|
+
to: "@comity/taxonomy",
|
|
26
|
+
layer: "core-to-core",
|
|
27
|
+
categories: ["capability"],
|
|
28
|
+
importKind: "type-only",
|
|
29
|
+
lifecycle: "approved",
|
|
30
|
+
justification: "Storefront category page composition references taxonomy domain contracts and models.",
|
|
31
|
+
adrReference: "ADR-008 — Dependency Register, Capability Exceptions",
|
|
32
|
+
},
|
|
33
|
+
{
|
|
34
|
+
from: "@comity/storefront",
|
|
35
|
+
to: "@comity/content",
|
|
36
|
+
layer: "core-to-core",
|
|
37
|
+
categories: ["capability"],
|
|
38
|
+
importKind: "type-only",
|
|
39
|
+
lifecycle: "approved",
|
|
40
|
+
justification: "Storefront content page composer references content domain models.",
|
|
41
|
+
adrReference: "ADR-008 — Dependency Register, Capability Exceptions",
|
|
42
|
+
},
|
|
43
|
+
{
|
|
44
|
+
from: "@comity/storefront",
|
|
45
|
+
to: "@comity/search",
|
|
46
|
+
layer: "core-to-core",
|
|
47
|
+
categories: ["capability"],
|
|
48
|
+
importKind: "type-only",
|
|
49
|
+
lifecycle: "approved",
|
|
50
|
+
justification: "Storefront search page contract references SearchResultModel.",
|
|
51
|
+
adrReference: "ADR-008 — Dependency Register, Capability Exceptions",
|
|
52
|
+
},
|
|
53
|
+
{
|
|
54
|
+
from: "@comity/catalog",
|
|
55
|
+
to: "@comity/media",
|
|
56
|
+
layer: "core-to-core",
|
|
57
|
+
categories: ["capability"],
|
|
58
|
+
importKind: "type-only",
|
|
59
|
+
lifecycle: "approved",
|
|
60
|
+
justification: "Catalog projections reference MediaModel for product/brand media.",
|
|
61
|
+
adrReference: "ADR-008 — Dependency Register, Capability Exceptions",
|
|
62
|
+
},
|
|
63
|
+
{
|
|
64
|
+
from: "@comity/content",
|
|
65
|
+
to: "@comity/media",
|
|
66
|
+
layer: "core-to-core",
|
|
67
|
+
categories: ["capability"],
|
|
68
|
+
importKind: "type-only",
|
|
69
|
+
lifecycle: "approved",
|
|
70
|
+
justification: "Content blocks/pages reference MediaModel.",
|
|
71
|
+
adrReference: "ADR-008 — Dependency Register, Capability Exceptions",
|
|
72
|
+
},
|
|
73
|
+
{
|
|
74
|
+
from: "@comity/content",
|
|
75
|
+
to: "@comity/seo",
|
|
76
|
+
layer: "core-to-core",
|
|
77
|
+
categories: ["capability"],
|
|
78
|
+
importKind: "type-only",
|
|
79
|
+
lifecycle: "approved",
|
|
80
|
+
justification: "Content pages reference SeoModel.",
|
|
81
|
+
adrReference: "ADR-008 — Dependency Register, Capability Exceptions",
|
|
82
|
+
},
|
|
83
|
+
{
|
|
84
|
+
from: "@comity/taxonomy",
|
|
85
|
+
to: "@comity/media",
|
|
86
|
+
layer: "core-to-core",
|
|
87
|
+
categories: ["capability"],
|
|
88
|
+
importKind: "type-only",
|
|
89
|
+
lifecycle: "approved",
|
|
90
|
+
justification: "Taxonomy models reference MediaModel for category image.",
|
|
91
|
+
adrReference: "ADR-008 — Dependency Register, Capability Exceptions",
|
|
92
|
+
},
|
|
93
|
+
{
|
|
94
|
+
from: "@comity/order",
|
|
95
|
+
to: "@comity/pricing",
|
|
96
|
+
layer: "core-to-core",
|
|
97
|
+
categories: ["capability"],
|
|
98
|
+
importKind: "type-only",
|
|
99
|
+
lifecycle: "approved",
|
|
100
|
+
justification: "Order items reference Price / PriceModifier.",
|
|
101
|
+
adrReference: "ADR-008 — Dependency Register, Capability Exceptions",
|
|
102
|
+
},
|
|
103
|
+
{
|
|
104
|
+
from: "@comity/order",
|
|
105
|
+
to: "@comity/organization",
|
|
106
|
+
layer: "core-to-core",
|
|
107
|
+
categories: ["capability"],
|
|
108
|
+
importKind: "type-only",
|
|
109
|
+
lifecycle: "approved",
|
|
110
|
+
justification: "Order contracts reference ChannelId for commercial channel scoping.",
|
|
111
|
+
adrReference: "ADR-008 — Dependency Register, Capability Exceptions",
|
|
112
|
+
},
|
|
113
|
+
{
|
|
114
|
+
from: "@comity/customer",
|
|
115
|
+
to: "@comity/validation",
|
|
116
|
+
layer: "core-to-core",
|
|
117
|
+
categories: ["capability"],
|
|
118
|
+
importKind: "type-only",
|
|
119
|
+
lifecycle: "approved",
|
|
120
|
+
justification: "Customer validator consumes the shared Validator contract.",
|
|
121
|
+
adrReference: "ADR-008 — Dependency Register, Capability Exceptions",
|
|
122
|
+
},
|
|
123
|
+
{
|
|
124
|
+
from: "@comity/customer",
|
|
125
|
+
to: "@comity/organization",
|
|
126
|
+
layer: "core-to-core",
|
|
127
|
+
categories: ["capability"],
|
|
128
|
+
importKind: "type-only",
|
|
129
|
+
lifecycle: "approved",
|
|
130
|
+
justification: "Customer repository requires TenantId for multi-tenant isolation.",
|
|
131
|
+
adrReference: "ADR-008 — Dependency Register, Capability Exceptions",
|
|
132
|
+
},
|
|
133
|
+
{
|
|
134
|
+
from: "@comity/address",
|
|
135
|
+
to: "@comity/validation",
|
|
136
|
+
layer: "core-to-core",
|
|
137
|
+
categories: ["capability"],
|
|
138
|
+
importKind: "type-only",
|
|
139
|
+
lifecycle: "approved",
|
|
140
|
+
justification: "Address validator consumes the shared Validator contract.",
|
|
141
|
+
adrReference: "ADR-008 — Dependency Register, Capability Exceptions",
|
|
142
|
+
},
|
|
143
|
+
{
|
|
144
|
+
from: "@comity/identity",
|
|
145
|
+
to: "@comity/validation",
|
|
146
|
+
layer: "core-to-core",
|
|
147
|
+
categories: ["capability"],
|
|
148
|
+
importKind: "type-only",
|
|
149
|
+
lifecycle: "approved",
|
|
150
|
+
justification: "Identity validator consumes the shared Validator contract.",
|
|
151
|
+
adrReference: "ADR-008 — Dependency Register, Capability Exceptions",
|
|
152
|
+
},
|
|
153
|
+
{
|
|
154
|
+
from: "@comity/auth-tokens",
|
|
155
|
+
to: "@comity/auth",
|
|
156
|
+
layer: "core-to-core",
|
|
157
|
+
categories: ["value-import"],
|
|
158
|
+
importKind: "mixed",
|
|
159
|
+
lifecycle: "approved",
|
|
160
|
+
justification: "Token facade error surface normalizes AuthError at runtime. @comity/auth owns authentication error semantics; direction is intentional and non-cyclic.",
|
|
161
|
+
adrReference: "ADR-008 — Dependency Register, Value-Import Exceptions",
|
|
162
|
+
},
|
|
163
|
+
{
|
|
164
|
+
from: "@comity/router",
|
|
165
|
+
to: "@comity/http",
|
|
166
|
+
layer: "core-to-core",
|
|
167
|
+
categories: ["infrastructure-contract"],
|
|
168
|
+
importKind: "type-only",
|
|
169
|
+
lifecycle: "deprecated",
|
|
170
|
+
justification: "Router contracts reference HttpContext, HttpHandler, HttpMethod. Compatibility exception; extraction candidate.",
|
|
171
|
+
adrReference: "ADR-008 — Dependency Register, Infrastructure Contract Exceptions",
|
|
172
|
+
},
|
|
173
|
+
{
|
|
174
|
+
from: "@comity/payment",
|
|
175
|
+
to: "@comity/pricing",
|
|
176
|
+
layer: "core-to-core",
|
|
177
|
+
categories: ["capability"],
|
|
178
|
+
importKind: "type-only",
|
|
179
|
+
lifecycle: "approved",
|
|
180
|
+
justification: "Payment module uses Money value object from pricing for amount representation in PaymentRequest and PaymentOutcome.",
|
|
181
|
+
adrReference: "ADR-008 — Dependency Register, Capability Exceptions",
|
|
182
|
+
},
|
|
183
|
+
],
|
|
184
|
+
};
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import type { Ajv, ErrorObject } from "ajv";
|
|
2
|
+
/**
|
|
3
|
+
* Canonical schema for the ADR-008 Core Exception Register.
|
|
4
|
+
*
|
|
5
|
+
* @see ADR-008 — Explicit Core Module Composition Exceptions
|
|
6
|
+
* @see ADR-009 — Machine-Readable Core Exception Register
|
|
7
|
+
*
|
|
8
|
+
* Each repository owns its own register instance; the schema is shared
|
|
9
|
+
* Development tooling. The register enumerates Core-to-Core dependency
|
|
10
|
+
* edges that are explicitly permitted despite the default prohibition.
|
|
11
|
+
*/
|
|
12
|
+
export declare const adr008RegisterSchema: {
|
|
13
|
+
$id: string;
|
|
14
|
+
type: string;
|
|
15
|
+
required: string[];
|
|
16
|
+
additionalProperties: boolean;
|
|
17
|
+
properties: {
|
|
18
|
+
version: {
|
|
19
|
+
type: string;
|
|
20
|
+
const: string;
|
|
21
|
+
description: string;
|
|
22
|
+
};
|
|
23
|
+
edges: {
|
|
24
|
+
type: string;
|
|
25
|
+
uniqueItems: boolean;
|
|
26
|
+
items: {
|
|
27
|
+
type: string;
|
|
28
|
+
required: string[];
|
|
29
|
+
additionalProperties: boolean;
|
|
30
|
+
properties: {
|
|
31
|
+
from: {
|
|
32
|
+
type: string;
|
|
33
|
+
pattern: string;
|
|
34
|
+
description: string;
|
|
35
|
+
};
|
|
36
|
+
to: {
|
|
37
|
+
type: string;
|
|
38
|
+
pattern: string;
|
|
39
|
+
description: string;
|
|
40
|
+
};
|
|
41
|
+
adr: {
|
|
42
|
+
type: string;
|
|
43
|
+
pattern: string;
|
|
44
|
+
description: string;
|
|
45
|
+
};
|
|
46
|
+
rationale: {
|
|
47
|
+
type: string;
|
|
48
|
+
minLength: number;
|
|
49
|
+
description: string;
|
|
50
|
+
};
|
|
51
|
+
};
|
|
52
|
+
};
|
|
53
|
+
};
|
|
54
|
+
};
|
|
55
|
+
};
|
|
56
|
+
/**
|
|
57
|
+
* Validates a parsed ADR-008 register document.
|
|
58
|
+
*
|
|
59
|
+
* @param document — parsed ADR-008 register
|
|
60
|
+
* @param ajv — optional pre-built Ajv instance
|
|
61
|
+
* @returns validation result
|
|
62
|
+
*/
|
|
63
|
+
export declare function validateAdr008Register(document: unknown, ajv?: Ajv): {
|
|
64
|
+
valid: boolean;
|
|
65
|
+
errors: ErrorObject[];
|
|
66
|
+
};
|
|
67
|
+
export interface Adr008Register {
|
|
68
|
+
version: "1";
|
|
69
|
+
edges: Array<{
|
|
70
|
+
from: string;
|
|
71
|
+
to: string;
|
|
72
|
+
layer: string;
|
|
73
|
+
categories: string[];
|
|
74
|
+
importKind: string;
|
|
75
|
+
lifecycle: string;
|
|
76
|
+
justification: string;
|
|
77
|
+
adrReference: string;
|
|
78
|
+
}>;
|
|
79
|
+
}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { createAjvInstance } from "../ajv-instance.js";
|
|
2
|
+
import { PACKAGE_NAME_PATTERN } from "../constants.js";
|
|
3
|
+
/**
|
|
4
|
+
* Canonical schema for the ADR-008 Core Exception Register.
|
|
5
|
+
*
|
|
6
|
+
* @see ADR-008 — Explicit Core Module Composition Exceptions
|
|
7
|
+
* @see ADR-009 — Machine-Readable Core Exception Register
|
|
8
|
+
*
|
|
9
|
+
* Each repository owns its own register instance; the schema is shared
|
|
10
|
+
* Development tooling. The register enumerates Core-to-Core dependency
|
|
11
|
+
* edges that are explicitly permitted despite the default prohibition.
|
|
12
|
+
*/
|
|
13
|
+
export const adr008RegisterSchema = {
|
|
14
|
+
$id: "https://comityjs.dev/schemas/adr-008-register.v1.json",
|
|
15
|
+
type: "object",
|
|
16
|
+
required: ["version", "edges"],
|
|
17
|
+
additionalProperties: false,
|
|
18
|
+
properties: {
|
|
19
|
+
version: {
|
|
20
|
+
type: "string",
|
|
21
|
+
const: "1",
|
|
22
|
+
description: "Schema version of the register document.",
|
|
23
|
+
},
|
|
24
|
+
edges: {
|
|
25
|
+
type: "array",
|
|
26
|
+
uniqueItems: true,
|
|
27
|
+
items: {
|
|
28
|
+
type: "object",
|
|
29
|
+
required: ["from", "to", "adr", "rationale"],
|
|
30
|
+
additionalProperties: false,
|
|
31
|
+
properties: {
|
|
32
|
+
from: {
|
|
33
|
+
type: "string",
|
|
34
|
+
pattern: PACKAGE_NAME_PATTERN,
|
|
35
|
+
description: "Source Core Module package name.",
|
|
36
|
+
},
|
|
37
|
+
to: {
|
|
38
|
+
type: "string",
|
|
39
|
+
pattern: PACKAGE_NAME_PATTERN,
|
|
40
|
+
description: "Target Core Module package name.",
|
|
41
|
+
},
|
|
42
|
+
adr: {
|
|
43
|
+
type: "string",
|
|
44
|
+
pattern: "^ADR-[0-9]{3,4}.*$",
|
|
45
|
+
description: "ADR reference approving this exception.",
|
|
46
|
+
},
|
|
47
|
+
rationale: {
|
|
48
|
+
type: "string",
|
|
49
|
+
minLength: 1,
|
|
50
|
+
description: "Why this Core-to-Core edge is permitted.",
|
|
51
|
+
},
|
|
52
|
+
},
|
|
53
|
+
},
|
|
54
|
+
},
|
|
55
|
+
},
|
|
56
|
+
};
|
|
57
|
+
/**
|
|
58
|
+
* Validates a parsed ADR-008 register document.
|
|
59
|
+
*
|
|
60
|
+
* @param document — parsed ADR-008 register
|
|
61
|
+
* @param ajv — optional pre-built Ajv instance
|
|
62
|
+
* @returns validation result
|
|
63
|
+
*/
|
|
64
|
+
export function validateAdr008Register(document, ajv = createAjvInstance()) {
|
|
65
|
+
const validate = ajv.compile(adr008RegisterSchema);
|
|
66
|
+
const valid = validate(document);
|
|
67
|
+
return {
|
|
68
|
+
valid: Boolean(valid),
|
|
69
|
+
errors: valid ? [] : (validate.errors ?? []),
|
|
70
|
+
};
|
|
71
|
+
}
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
import type { Ajv, ErrorObject } from "ajv";
|
|
2
|
+
/**
|
|
3
|
+
* Canonical schema for repository `comity.config.json`.
|
|
4
|
+
*
|
|
5
|
+
* The configuration holds REPOSITORY FACTS — package locations, repository
|
|
6
|
+
* type, declared exceptions. It MUST NOT silently redefine Comity-wide
|
|
7
|
+
* policy; policy belongs in the Standards and is enforced by shared tools.
|
|
8
|
+
*
|
|
9
|
+
* @see layering-policy.md (policy owner)
|
|
10
|
+
* @see ADR-007 (integration-adapter vs technology-adapter categorization)
|
|
11
|
+
*/
|
|
12
|
+
export declare const comityConfigSchema: {
|
|
13
|
+
$id: string;
|
|
14
|
+
type: string;
|
|
15
|
+
additionalProperties: boolean;
|
|
16
|
+
required: string[];
|
|
17
|
+
properties: {
|
|
18
|
+
repository: {
|
|
19
|
+
type: string;
|
|
20
|
+
required: string[];
|
|
21
|
+
additionalProperties: boolean;
|
|
22
|
+
properties: {
|
|
23
|
+
name: {
|
|
24
|
+
type: string;
|
|
25
|
+
minLength: number;
|
|
26
|
+
description: string;
|
|
27
|
+
};
|
|
28
|
+
type: {
|
|
29
|
+
type: string;
|
|
30
|
+
enum: string[];
|
|
31
|
+
description: string;
|
|
32
|
+
};
|
|
33
|
+
};
|
|
34
|
+
};
|
|
35
|
+
packages: {
|
|
36
|
+
type: string;
|
|
37
|
+
required: string[];
|
|
38
|
+
additionalProperties: boolean;
|
|
39
|
+
properties: {
|
|
40
|
+
roots: {
|
|
41
|
+
type: string;
|
|
42
|
+
items: {
|
|
43
|
+
type: string;
|
|
44
|
+
minLength: number;
|
|
45
|
+
};
|
|
46
|
+
minItems: number;
|
|
47
|
+
description: string;
|
|
48
|
+
};
|
|
49
|
+
exclude: {
|
|
50
|
+
type: string;
|
|
51
|
+
items: {
|
|
52
|
+
type: string;
|
|
53
|
+
minLength: number;
|
|
54
|
+
};
|
|
55
|
+
description: string;
|
|
56
|
+
};
|
|
57
|
+
};
|
|
58
|
+
};
|
|
59
|
+
validation: {
|
|
60
|
+
type: string;
|
|
61
|
+
additionalProperties: boolean;
|
|
62
|
+
properties: {
|
|
63
|
+
rules: {
|
|
64
|
+
type: string;
|
|
65
|
+
description: string;
|
|
66
|
+
additionalProperties: {
|
|
67
|
+
type: string;
|
|
68
|
+
};
|
|
69
|
+
};
|
|
70
|
+
exceptions: {
|
|
71
|
+
type: string;
|
|
72
|
+
additionalProperties: boolean;
|
|
73
|
+
properties: {
|
|
74
|
+
dependencyEdges: {
|
|
75
|
+
type: string;
|
|
76
|
+
description: string;
|
|
77
|
+
items: {
|
|
78
|
+
type: string;
|
|
79
|
+
required: string[];
|
|
80
|
+
properties: {
|
|
81
|
+
from: {
|
|
82
|
+
type: string;
|
|
83
|
+
};
|
|
84
|
+
to: {
|
|
85
|
+
type: string;
|
|
86
|
+
};
|
|
87
|
+
adr: {
|
|
88
|
+
type: string;
|
|
89
|
+
};
|
|
90
|
+
rationale: {
|
|
91
|
+
type: string;
|
|
92
|
+
};
|
|
93
|
+
};
|
|
94
|
+
additionalProperties: boolean;
|
|
95
|
+
};
|
|
96
|
+
};
|
|
97
|
+
layerOverrides: {
|
|
98
|
+
type: string;
|
|
99
|
+
description: string;
|
|
100
|
+
items: {
|
|
101
|
+
type: string;
|
|
102
|
+
required: string[];
|
|
103
|
+
properties: {
|
|
104
|
+
package: {
|
|
105
|
+
type: string;
|
|
106
|
+
};
|
|
107
|
+
layer: {
|
|
108
|
+
type: string;
|
|
109
|
+
};
|
|
110
|
+
adr: {
|
|
111
|
+
type: string;
|
|
112
|
+
};
|
|
113
|
+
rationale: {
|
|
114
|
+
type: string;
|
|
115
|
+
};
|
|
116
|
+
};
|
|
117
|
+
additionalProperties: boolean;
|
|
118
|
+
};
|
|
119
|
+
};
|
|
120
|
+
};
|
|
121
|
+
};
|
|
122
|
+
};
|
|
123
|
+
};
|
|
124
|
+
};
|
|
125
|
+
};
|
|
126
|
+
/**
|
|
127
|
+
* Validates a parsed comity.config.json document.
|
|
128
|
+
*
|
|
129
|
+
* @param document — parsed comity.config.json
|
|
130
|
+
* @param ajv — optional pre-built Ajv instance
|
|
131
|
+
* @returns validation result
|
|
132
|
+
*/
|
|
133
|
+
export declare function validateComityConfig(document: unknown, ajv?: Ajv): {
|
|
134
|
+
valid: boolean;
|
|
135
|
+
errors: ErrorObject[];
|
|
136
|
+
};
|
|
137
|
+
export interface ComityConfig {
|
|
138
|
+
repository: {
|
|
139
|
+
name: string;
|
|
140
|
+
type: string;
|
|
141
|
+
};
|
|
142
|
+
packages: {
|
|
143
|
+
roots: string[];
|
|
144
|
+
exclude?: string[];
|
|
145
|
+
};
|
|
146
|
+
validation?: {
|
|
147
|
+
rules?: Record<string, boolean>;
|
|
148
|
+
exceptions?: {
|
|
149
|
+
dependencyEdges?: Array<{
|
|
150
|
+
from: string;
|
|
151
|
+
to: string;
|
|
152
|
+
adr: string;
|
|
153
|
+
rationale?: string;
|
|
154
|
+
}>;
|
|
155
|
+
layerOverrides?: Array<{
|
|
156
|
+
package: string;
|
|
157
|
+
layer: string;
|
|
158
|
+
adr: string;
|
|
159
|
+
rationale?: string;
|
|
160
|
+
}>;
|
|
161
|
+
};
|
|
162
|
+
};
|
|
163
|
+
}
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
import { createAjvInstance } from "../ajv-instance.js";
|
|
2
|
+
/**
|
|
3
|
+
* Canonical schema for repository `comity.config.json`.
|
|
4
|
+
*
|
|
5
|
+
* The configuration holds REPOSITORY FACTS — package locations, repository
|
|
6
|
+
* type, declared exceptions. It MUST NOT silently redefine Comity-wide
|
|
7
|
+
* policy; policy belongs in the Standards and is enforced by shared tools.
|
|
8
|
+
*
|
|
9
|
+
* @see layering-policy.md (policy owner)
|
|
10
|
+
* @see ADR-007 (integration-adapter vs technology-adapter categorization)
|
|
11
|
+
*/
|
|
12
|
+
export const comityConfigSchema = {
|
|
13
|
+
$id: "https://comityjs.dev/schemas/comity-config.v1.json",
|
|
14
|
+
type: "object",
|
|
15
|
+
additionalProperties: false,
|
|
16
|
+
required: ["repository", "packages"],
|
|
17
|
+
properties: {
|
|
18
|
+
repository: {
|
|
19
|
+
type: "object",
|
|
20
|
+
required: ["name", "type"],
|
|
21
|
+
additionalProperties: false,
|
|
22
|
+
properties: {
|
|
23
|
+
name: {
|
|
24
|
+
type: "string",
|
|
25
|
+
minLength: 1,
|
|
26
|
+
description: "Logical name of the repository.",
|
|
27
|
+
},
|
|
28
|
+
type: {
|
|
29
|
+
type: "string",
|
|
30
|
+
enum: [
|
|
31
|
+
"development",
|
|
32
|
+
"community",
|
|
33
|
+
"enterprise",
|
|
34
|
+
"third-party",
|
|
35
|
+
"fixture",
|
|
36
|
+
],
|
|
37
|
+
description: "Repository category.",
|
|
38
|
+
},
|
|
39
|
+
},
|
|
40
|
+
},
|
|
41
|
+
packages: {
|
|
42
|
+
type: "object",
|
|
43
|
+
required: ["roots"],
|
|
44
|
+
additionalProperties: false,
|
|
45
|
+
properties: {
|
|
46
|
+
roots: {
|
|
47
|
+
type: "array",
|
|
48
|
+
items: { type: "string", minLength: 1 },
|
|
49
|
+
minItems: 1,
|
|
50
|
+
description: "Workspace package roots, relative to the repository root.",
|
|
51
|
+
},
|
|
52
|
+
exclude: {
|
|
53
|
+
type: "array",
|
|
54
|
+
items: { type: "string", minLength: 1 },
|
|
55
|
+
description: "Package path patterns to exclude from validation.",
|
|
56
|
+
},
|
|
57
|
+
},
|
|
58
|
+
},
|
|
59
|
+
validation: {
|
|
60
|
+
type: "object",
|
|
61
|
+
additionalProperties: false,
|
|
62
|
+
properties: {
|
|
63
|
+
rules: {
|
|
64
|
+
type: "object",
|
|
65
|
+
description: "Repository-specific rule selection. Allowed keys: metadata, dependencies, eslint, semgrep, orchestrator.",
|
|
66
|
+
additionalProperties: { type: "boolean" },
|
|
67
|
+
},
|
|
68
|
+
exceptions: {
|
|
69
|
+
type: "object",
|
|
70
|
+
additionalProperties: false,
|
|
71
|
+
properties: {
|
|
72
|
+
dependencyEdges: {
|
|
73
|
+
type: "array",
|
|
74
|
+
description: "Locally-permitted dependency edges. Each entry MUST reference an ADR.",
|
|
75
|
+
items: {
|
|
76
|
+
type: "object",
|
|
77
|
+
required: ["from", "to", "adr"],
|
|
78
|
+
properties: {
|
|
79
|
+
from: { type: "string" },
|
|
80
|
+
to: { type: "string" },
|
|
81
|
+
adr: { type: "string" },
|
|
82
|
+
rationale: { type: "string" },
|
|
83
|
+
},
|
|
84
|
+
additionalProperties: false,
|
|
85
|
+
},
|
|
86
|
+
},
|
|
87
|
+
layerOverrides: {
|
|
88
|
+
type: "array",
|
|
89
|
+
description: "Layer classification overrides — for transitional packages only.",
|
|
90
|
+
items: {
|
|
91
|
+
type: "object",
|
|
92
|
+
required: ["package", "layer", "adr"],
|
|
93
|
+
properties: {
|
|
94
|
+
package: { type: "string" },
|
|
95
|
+
layer: { type: "string" },
|
|
96
|
+
adr: { type: "string" },
|
|
97
|
+
rationale: { type: "string" },
|
|
98
|
+
},
|
|
99
|
+
additionalProperties: false,
|
|
100
|
+
},
|
|
101
|
+
},
|
|
102
|
+
},
|
|
103
|
+
},
|
|
104
|
+
},
|
|
105
|
+
},
|
|
106
|
+
},
|
|
107
|
+
};
|
|
108
|
+
/**
|
|
109
|
+
* Validates a parsed comity.config.json document.
|
|
110
|
+
*
|
|
111
|
+
* @param document — parsed comity.config.json
|
|
112
|
+
* @param ajv — optional pre-built Ajv instance
|
|
113
|
+
* @returns validation result
|
|
114
|
+
*/
|
|
115
|
+
export function validateComityConfig(document, ajv = createAjvInstance()) {
|
|
116
|
+
const validate = ajv.compile(comityConfigSchema);
|
|
117
|
+
const valid = validate(document);
|
|
118
|
+
return {
|
|
119
|
+
valid: Boolean(valid),
|
|
120
|
+
errors: valid ? [] : (validate.errors ?? []),
|
|
121
|
+
};
|
|
122
|
+
}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export type { Adr008Register } from "./adr-008-register.js";
|
|
2
|
+
export type { ComityConfig } from "./comity-config.js";
|
|
3
|
+
export type { PackageMetadata, ValidationResult } from "./package-metadata.js";
|
|
4
|
+
export { adr008RegisterSchema, validateAdr008Register, } from "./adr-008-register.js";
|
|
5
|
+
export { comityConfigSchema, validateComityConfig } from "./comity-config.js";
|
|
6
|
+
export { packageMetadataSchema, validatePackageMetadata, } from "./package-metadata.js";
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
import type { Ajv, ErrorObject } from "ajv";
|
|
2
|
+
/**
|
|
3
|
+
* Canonical schema for Comity package metadata.
|
|
4
|
+
*
|
|
5
|
+
* Covers both namespaces, with a name-scope ↔ layer boundary:
|
|
6
|
+
* - `@comity/*` (runtime) → `comity.layer` MUST be one of the six
|
|
7
|
+
* runtime layers (ADR-026).
|
|
8
|
+
* - `@comity-dev/*` (tooling) → `comity.layer` MUST be `dev-tooling`.
|
|
9
|
+
*
|
|
10
|
+
* The boundary is enforced by the `if/then/else` clause on `comity.layer`.
|
|
11
|
+
*
|
|
12
|
+
* @see ADR-026 — Architecture Validator Authoritative Classification
|
|
13
|
+
* @see layering-policy.md §2.1
|
|
14
|
+
* @see architecture-validation.md §8 (package naming, type, engines.node)
|
|
15
|
+
* @see public-api.md §3 (exports subpath rules)
|
|
16
|
+
*
|
|
17
|
+
* This schema is the authoritative machine-readable definition of what every
|
|
18
|
+
* Comity package manifest MUST contain. Repositories consume this schema via
|
|
19
|
+
* the shared `comity-validate` orchestrator; they do not redefine it.
|
|
20
|
+
*/
|
|
21
|
+
export declare const packageMetadataSchema: {
|
|
22
|
+
$id: string;
|
|
23
|
+
type: string;
|
|
24
|
+
required: string[];
|
|
25
|
+
additionalProperties: boolean;
|
|
26
|
+
properties: {
|
|
27
|
+
name: {
|
|
28
|
+
type: string;
|
|
29
|
+
pattern: string;
|
|
30
|
+
description: string;
|
|
31
|
+
};
|
|
32
|
+
version: {
|
|
33
|
+
type: string;
|
|
34
|
+
pattern: string;
|
|
35
|
+
description: string;
|
|
36
|
+
};
|
|
37
|
+
type: {
|
|
38
|
+
const: string;
|
|
39
|
+
description: string;
|
|
40
|
+
};
|
|
41
|
+
license: {
|
|
42
|
+
type: string;
|
|
43
|
+
minLength: number;
|
|
44
|
+
description: string;
|
|
45
|
+
};
|
|
46
|
+
engines: {
|
|
47
|
+
type: string;
|
|
48
|
+
required: string[];
|
|
49
|
+
properties: {
|
|
50
|
+
node: {
|
|
51
|
+
type: string;
|
|
52
|
+
pattern: string;
|
|
53
|
+
description: string;
|
|
54
|
+
};
|
|
55
|
+
};
|
|
56
|
+
additionalProperties: boolean;
|
|
57
|
+
};
|
|
58
|
+
comity: {
|
|
59
|
+
type: string;
|
|
60
|
+
description: string;
|
|
61
|
+
required: string[];
|
|
62
|
+
properties: {
|
|
63
|
+
layer: {
|
|
64
|
+
type: string;
|
|
65
|
+
enum: string[];
|
|
66
|
+
description: string;
|
|
67
|
+
};
|
|
68
|
+
implements: {
|
|
69
|
+
type: string;
|
|
70
|
+
pattern: string;
|
|
71
|
+
description: string;
|
|
72
|
+
};
|
|
73
|
+
};
|
|
74
|
+
additionalProperties: boolean;
|
|
75
|
+
};
|
|
76
|
+
exports: {
|
|
77
|
+
type: string;
|
|
78
|
+
description: string;
|
|
79
|
+
additionalProperties: boolean;
|
|
80
|
+
};
|
|
81
|
+
typesVersions: {
|
|
82
|
+
type: string;
|
|
83
|
+
description: string;
|
|
84
|
+
additionalProperties: boolean;
|
|
85
|
+
};
|
|
86
|
+
};
|
|
87
|
+
allOf: ({
|
|
88
|
+
if: {
|
|
89
|
+
properties: {
|
|
90
|
+
name: {
|
|
91
|
+
pattern: string;
|
|
92
|
+
};
|
|
93
|
+
};
|
|
94
|
+
required: string[];
|
|
95
|
+
};
|
|
96
|
+
then: {
|
|
97
|
+
properties: {
|
|
98
|
+
comity: {
|
|
99
|
+
properties: {
|
|
100
|
+
layer: {
|
|
101
|
+
enum: string[];
|
|
102
|
+
const?: never;
|
|
103
|
+
};
|
|
104
|
+
};
|
|
105
|
+
};
|
|
106
|
+
};
|
|
107
|
+
};
|
|
108
|
+
} | {
|
|
109
|
+
if: {
|
|
110
|
+
properties: {
|
|
111
|
+
name: {
|
|
112
|
+
pattern: string;
|
|
113
|
+
};
|
|
114
|
+
};
|
|
115
|
+
required: string[];
|
|
116
|
+
};
|
|
117
|
+
then: {
|
|
118
|
+
properties: {
|
|
119
|
+
comity: {
|
|
120
|
+
properties: {
|
|
121
|
+
layer: {
|
|
122
|
+
const: string;
|
|
123
|
+
enum?: never;
|
|
124
|
+
};
|
|
125
|
+
};
|
|
126
|
+
};
|
|
127
|
+
};
|
|
128
|
+
};
|
|
129
|
+
})[];
|
|
130
|
+
};
|
|
131
|
+
/**
|
|
132
|
+
* Validates a parsed package.json against the canonical schema.
|
|
133
|
+
*
|
|
134
|
+
* @param manifest — parsed package.json object
|
|
135
|
+
* @param ajv — optional pre-built Ajv instance
|
|
136
|
+
* @returns validation result
|
|
137
|
+
*/
|
|
138
|
+
export declare function validatePackageMetadata(manifest: unknown, ajv?: Ajv): ValidationResult;
|
|
139
|
+
export interface PackageMetadata {
|
|
140
|
+
name: string;
|
|
141
|
+
version: string;
|
|
142
|
+
type: "module";
|
|
143
|
+
license: string;
|
|
144
|
+
engines: {
|
|
145
|
+
node: string;
|
|
146
|
+
};
|
|
147
|
+
comity?: {
|
|
148
|
+
layer: string;
|
|
149
|
+
implements?: string;
|
|
150
|
+
};
|
|
151
|
+
exports: Record<string, unknown>;
|
|
152
|
+
typesVersions?: Record<string, unknown>;
|
|
153
|
+
}
|
|
154
|
+
export interface ValidationResult {
|
|
155
|
+
valid: boolean;
|
|
156
|
+
errors: ErrorObject[];
|
|
157
|
+
}
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
import { createAjvInstance } from "../ajv-instance.js";
|
|
2
|
+
import { MIN_NODE_VERSION, PACKAGE_NAME_PATTERN, RUNTIME_LAYERS, VALID_LAYERS, } from "../constants.js";
|
|
3
|
+
/**
|
|
4
|
+
* Canonical schema for Comity package metadata.
|
|
5
|
+
*
|
|
6
|
+
* Covers both namespaces, with a name-scope ↔ layer boundary:
|
|
7
|
+
* - `@comity/*` (runtime) → `comity.layer` MUST be one of the six
|
|
8
|
+
* runtime layers (ADR-026).
|
|
9
|
+
* - `@comity-dev/*` (tooling) → `comity.layer` MUST be `dev-tooling`.
|
|
10
|
+
*
|
|
11
|
+
* The boundary is enforced by the `if/then/else` clause on `comity.layer`.
|
|
12
|
+
*
|
|
13
|
+
* @see ADR-026 — Architecture Validator Authoritative Classification
|
|
14
|
+
* @see layering-policy.md §2.1
|
|
15
|
+
* @see architecture-validation.md §8 (package naming, type, engines.node)
|
|
16
|
+
* @see public-api.md §3 (exports subpath rules)
|
|
17
|
+
*
|
|
18
|
+
* This schema is the authoritative machine-readable definition of what every
|
|
19
|
+
* Comity package manifest MUST contain. Repositories consume this schema via
|
|
20
|
+
* the shared `comity-validate` orchestrator; they do not redefine it.
|
|
21
|
+
*/
|
|
22
|
+
export const packageMetadataSchema = {
|
|
23
|
+
$id: "https://comityjs.dev/schemas/package-metadata.v1.json",
|
|
24
|
+
type: "object",
|
|
25
|
+
required: ["name", "version", "type", "license", "engines", "exports"],
|
|
26
|
+
additionalProperties: true,
|
|
27
|
+
properties: {
|
|
28
|
+
name: {
|
|
29
|
+
type: "string",
|
|
30
|
+
pattern: PACKAGE_NAME_PATTERN,
|
|
31
|
+
description: "Package name MUST follow the `@comity/<kebab-case-name>` or `@comity-dev/<kebab-case-name>` convention.",
|
|
32
|
+
},
|
|
33
|
+
version: {
|
|
34
|
+
type: "string",
|
|
35
|
+
pattern: "^[0-9]+\\.[0-9]+\\.[0-9]+",
|
|
36
|
+
description: "Semantic version of the package.",
|
|
37
|
+
},
|
|
38
|
+
type: {
|
|
39
|
+
const: "module",
|
|
40
|
+
description: "Package type MUST be `module` (ESM).",
|
|
41
|
+
},
|
|
42
|
+
license: {
|
|
43
|
+
type: "string",
|
|
44
|
+
minLength: 1,
|
|
45
|
+
description: "Package license MUST be declared.",
|
|
46
|
+
},
|
|
47
|
+
engines: {
|
|
48
|
+
type: "object",
|
|
49
|
+
required: ["node"],
|
|
50
|
+
properties: {
|
|
51
|
+
node: {
|
|
52
|
+
type: "string",
|
|
53
|
+
pattern: `>=${MIN_NODE_VERSION}`,
|
|
54
|
+
description: `Node.js engine MUST be >= ${MIN_NODE_VERSION}.`,
|
|
55
|
+
},
|
|
56
|
+
},
|
|
57
|
+
additionalProperties: true,
|
|
58
|
+
},
|
|
59
|
+
comity: {
|
|
60
|
+
type: "object",
|
|
61
|
+
description: "Comity metadata — authoritative source of package classification.",
|
|
62
|
+
required: ["layer"],
|
|
63
|
+
properties: {
|
|
64
|
+
layer: {
|
|
65
|
+
type: "string",
|
|
66
|
+
enum: [...VALID_LAYERS],
|
|
67
|
+
description: "Architectural layer. Runtime `@comity/*` packages MUST use one of the six runtime layers (primitives, kernel, composition, core, technology-adapter, integration-adapter). Development `@comity-dev/*` packages MUST use `dev-tooling`.",
|
|
68
|
+
},
|
|
69
|
+
implements: {
|
|
70
|
+
// Per ADR-026, `implements` is a single Core Module name. The
|
|
71
|
+
// legacy validator reports a violation when this is an array;
|
|
72
|
+
// we keep the schema strict and surface the violation through
|
|
73
|
+
// the metadata check.
|
|
74
|
+
type: "string",
|
|
75
|
+
pattern: PACKAGE_NAME_PATTERN,
|
|
76
|
+
description: "Single Core Module that this Adapter implements (technology-adapter and integration-adapter).",
|
|
77
|
+
},
|
|
78
|
+
},
|
|
79
|
+
additionalProperties: false,
|
|
80
|
+
},
|
|
81
|
+
exports: {
|
|
82
|
+
type: "object",
|
|
83
|
+
description: "Declared public subpaths. Forbidden subpaths (utils, helpers, shared, internal, lazy) are validated by ESLint.",
|
|
84
|
+
additionalProperties: true,
|
|
85
|
+
},
|
|
86
|
+
typesVersions: {
|
|
87
|
+
type: "object",
|
|
88
|
+
description: "TypeScript typesVersions MUST be consistent with declared exports.",
|
|
89
|
+
additionalProperties: true,
|
|
90
|
+
},
|
|
91
|
+
},
|
|
92
|
+
// Name-scope ↔ layer boundary. The runtime six-layer model is
|
|
93
|
+
// preserved; `dev-tooling` is reserved for `@comity-dev/*`.
|
|
94
|
+
// Implemented at the manifest level so `name` and `comity.layer`
|
|
95
|
+
// can be evaluated as siblings.
|
|
96
|
+
allOf: [
|
|
97
|
+
{
|
|
98
|
+
if: {
|
|
99
|
+
properties: {
|
|
100
|
+
name: { pattern: "^@comity/" },
|
|
101
|
+
},
|
|
102
|
+
required: ["name"],
|
|
103
|
+
},
|
|
104
|
+
then: {
|
|
105
|
+
properties: {
|
|
106
|
+
comity: {
|
|
107
|
+
properties: {
|
|
108
|
+
layer: { enum: [...RUNTIME_LAYERS] },
|
|
109
|
+
},
|
|
110
|
+
},
|
|
111
|
+
},
|
|
112
|
+
},
|
|
113
|
+
},
|
|
114
|
+
{
|
|
115
|
+
if: {
|
|
116
|
+
properties: {
|
|
117
|
+
name: { pattern: "^@comity-dev/" },
|
|
118
|
+
},
|
|
119
|
+
required: ["name"],
|
|
120
|
+
},
|
|
121
|
+
then: {
|
|
122
|
+
properties: {
|
|
123
|
+
comity: {
|
|
124
|
+
properties: {
|
|
125
|
+
layer: { const: "dev-tooling" },
|
|
126
|
+
},
|
|
127
|
+
},
|
|
128
|
+
},
|
|
129
|
+
},
|
|
130
|
+
},
|
|
131
|
+
],
|
|
132
|
+
};
|
|
133
|
+
/**
|
|
134
|
+
* Validates a parsed package.json against the canonical schema.
|
|
135
|
+
*
|
|
136
|
+
* @param manifest — parsed package.json object
|
|
137
|
+
* @param ajv — optional pre-built Ajv instance
|
|
138
|
+
* @returns validation result
|
|
139
|
+
*/
|
|
140
|
+
export function validatePackageMetadata(manifest, ajv = createAjvInstance()) {
|
|
141
|
+
const validate = ajv.compile(packageMetadataSchema);
|
|
142
|
+
const valid = validate(manifest);
|
|
143
|
+
return {
|
|
144
|
+
valid: Boolean(valid),
|
|
145
|
+
errors: valid ? [] : (validate.errors ?? []),
|
|
146
|
+
};
|
|
147
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@comity-dev/schemas",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Reusable JSON Schema definitions for Comity package metadata, ADR-008 register, and repository configuration. Development tooling.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"private": false,
|
|
7
|
+
"license": "MIT",
|
|
8
|
+
"comity": {
|
|
9
|
+
"layer": "dev-tooling"
|
|
10
|
+
},
|
|
11
|
+
"engines": {
|
|
12
|
+
"node": ">=24.0.0"
|
|
13
|
+
},
|
|
14
|
+
"main": "./dist/index.js",
|
|
15
|
+
"types": "./dist/index.d.ts",
|
|
16
|
+
"exports": {
|
|
17
|
+
".": {
|
|
18
|
+
"types": "./dist/index.d.ts",
|
|
19
|
+
"default": "./dist/index.js"
|
|
20
|
+
},
|
|
21
|
+
"./schemas": {
|
|
22
|
+
"types": "./dist/schemas/index.d.ts",
|
|
23
|
+
"default": "./dist/schemas/index.js"
|
|
24
|
+
}
|
|
25
|
+
},
|
|
26
|
+
"files": [
|
|
27
|
+
"./dist"
|
|
28
|
+
],
|
|
29
|
+
"dependencies": {
|
|
30
|
+
"ajv": "^8.17.1",
|
|
31
|
+
"ajv-formats": "^3.0.1"
|
|
32
|
+
},
|
|
33
|
+
"devDependencies": {
|
|
34
|
+
"@types/node": "^24.13.3",
|
|
35
|
+
"typescript": "^5.9.3"
|
|
36
|
+
},
|
|
37
|
+
"scripts": {
|
|
38
|
+
"build": "tsc -p tsconfig.json",
|
|
39
|
+
"test": "vitest run"
|
|
40
|
+
}
|
|
41
|
+
}
|