cms-field-vocabulary 1.0.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/CHANGELOG.md +10 -0
- package/LICENSE +21 -0
- package/OPERATING.md +214 -0
- package/README.md +162 -0
- package/SECURITY.md +49 -0
- package/bin/cms-field-vocabulary.mjs +108 -0
- package/catalog/catalog.json +21542 -0
- package/catalog/profiles/contentful.cma.saas.json +1141 -0
- package/catalog/profiles/contentstack.cma.saas.json +1119 -0
- package/catalog/profiles/optimizely-paas.cms12-model.json +1391 -0
- package/catalog/profiles/optimizely-paas.cms12-property-data-type.json +1129 -0
- package/catalog/profiles/optimizely-paas.cms13-admin.json +1948 -0
- package/catalog/profiles/optimizely-paas.cms13-model.json +1386 -0
- package/catalog/profiles/optimizely-saas.cms-api-v1.json +1196 -0
- package/catalog/profiles/optimizely-saas.sdk-2.json +1575 -0
- package/catalog/profiles/sitecore-ai.authoring.current.json +2025 -0
- package/catalog/profiles/sitecore-ai.content-sdk2.json +2787 -0
- package/catalog/profiles/sitecore-on-prem.headless22.json +1200 -0
- package/catalog/profiles/sitecore-on-prem.xp104-authoring.json +2299 -0
- package/catalog/profiles/wordpress.core71-block-attribute-source.json +475 -0
- package/catalog/profiles/wordpress.core71-block-attributes.json +650 -0
- package/catalog/profiles/wordpress.core71-meta.json +559 -0
- package/catalog/profiles/wordpress.core71-rest-schema.json +646 -0
- package/definitions/rendering-operations.json +61 -0
- package/dist/chunk-T6XGVORR.js +95 -0
- package/dist/definitions-Bhny9prs.d.cts +291 -0
- package/dist/definitions-Bhny9prs.d.ts +291 -0
- package/dist/definitions.cjs +125 -0
- package/dist/definitions.d.cts +1 -0
- package/dist/definitions.d.ts +1 -0
- package/dist/definitions.js +18 -0
- package/dist/index.cjs +22498 -0
- package/dist/index.d.cts +32 -0
- package/dist/index.d.ts +32 -0
- package/dist/index.js +22373 -0
- package/docs/platforms/INDEX.md +20 -0
- package/docs/platforms/contentful.cma.saas.md +23 -0
- package/docs/platforms/contentstack.cma.saas.md +23 -0
- package/docs/platforms/optimizely-paas.cms12-model.md +26 -0
- package/docs/platforms/optimizely-paas.cms12-property-data-type.md +24 -0
- package/docs/platforms/optimizely-paas.cms13-admin.md +33 -0
- package/docs/platforms/optimizely-paas.cms13-model.md +26 -0
- package/docs/platforms/optimizely-saas.cms-api-v1.md +24 -0
- package/docs/platforms/optimizely-saas.sdk-2.md +25 -0
- package/docs/platforms/sitecore-ai.authoring.current.md +45 -0
- package/docs/platforms/sitecore-ai.content-sdk2.md +49 -0
- package/docs/platforms/sitecore-on-prem.headless22.md +22 -0
- package/docs/platforms/sitecore-on-prem.xp104-authoring.md +50 -0
- package/docs/platforms/wordpress.core71-block-attribute-source.md +16 -0
- package/docs/platforms/wordpress.core71-block-attributes.md +18 -0
- package/docs/platforms/wordpress.core71-meta.md +17 -0
- package/docs/platforms/wordpress.core71-rest-schema.md +18 -0
- package/package.json +139 -0
- package/profiles/agent/generic.json +22 -0
- package/profiles/agent/react-nextjs.json +112 -0
- package/profiles/consumers/ai-orchestration.json +16 -0
- package/profiles/consumers/cos.json +15 -0
- package/profiles/consumers/generic.json +16 -0
- package/profiles/context-budget.json +36 -0
- package/schemas/agent-profile.schema.json +32 -0
- package/schemas/catalog.schema.json +26 -0
- package/schemas/consumer-config.schema.json +15 -0
- package/schemas/consumer-profile.schema.json +38 -0
- package/schemas/evidence-locators.schema.json +41 -0
- package/schemas/official-data-projection.schema.json +81 -0
- package/schemas/official-source.schema.json +6 -0
- package/schemas/profile.schema.json +286 -0
- package/schemas/projection-manifest.schema.json +32 -0
- package/schemas/rendering-definitions.schema.json +30 -0
- package/schemas/selected-contract.schema.json +82 -0
- package/schemas/source-manifest.schema.json +141 -0
- package/schemas/source-profile.schema.json +207 -0
- package/schemas/sources-lock.schema.json +222 -0
- package/sources/evidence-locators.json +312 -0
- package/sources/official-sources.json +957 -0
- package/sources.lock.json +4733 -0
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
## 1.0.0 (2026-09-02)
|
|
2
|
+
|
|
3
|
+
### Features
|
|
4
|
+
|
|
5
|
+
* **catalog:** add CMS field vocabulary [skip release] ([3e6885e](https://github.com/JFusco/cms-field-vocabulary/commit/3e6885ece8aa7cdc2a419e56d84da8703225f55c))
|
|
6
|
+
* **release:** publish cms vocabulary ([d16ab56](https://github.com/JFusco/cms-field-vocabulary/commit/d16ab568514c80e9904c5923303f399912b42805))
|
|
7
|
+
|
|
8
|
+
# Changelog
|
|
9
|
+
|
|
10
|
+
All notable changes are published by semantic-release.
|
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Joe Fusco
|
|
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/OPERATING.md
ADDED
|
@@ -0,0 +1,214 @@
|
|
|
1
|
+
# Operating cms-field-vocabulary
|
|
2
|
+
|
|
3
|
+
This runbook is for maintainers responsible for official-source review, generated catalog integrity, consumer projections, and releases.
|
|
4
|
+
|
|
5
|
+
## Operating invariants
|
|
6
|
+
|
|
7
|
+
- `sources/profiles/*.json` is the only human-authored vendor vocabulary.
|
|
8
|
+
- Every documented claim resolves to an official source ID and locator in `sources/official-sources.json`.
|
|
9
|
+
- `sources.lock.json` records a reviewed observation; a scanner cannot accept or update it.
|
|
10
|
+
- Product versions and authoring, management, storage, delivery, and SDK surfaces remain distinct.
|
|
11
|
+
- Framework behavior is consumer policy, not vendor authority.
|
|
12
|
+
- Generated catalogs, platform pages, distributions, and consumer projections are reproducible and never hand-edited.
|
|
13
|
+
- Coding agents receive selected contracts, not the full catalog or duplicated prose.
|
|
14
|
+
- Publication runs only through the authorized `main` release workflow. npm trusted publishing with GitHub OIDC is the normal credential path; a one-time granular token is permitted only to bootstrap the first unscoped package release.
|
|
15
|
+
|
|
16
|
+
## Routine quality operation
|
|
17
|
+
|
|
18
|
+
Use the pinned toolchain:
|
|
19
|
+
|
|
20
|
+
```sh
|
|
21
|
+
corepack enable
|
|
22
|
+
corepack prepare pnpm@11.1.1 --activate
|
|
23
|
+
pnpm install --frozen-lockfile
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
Before merge:
|
|
27
|
+
|
|
28
|
+
```sh
|
|
29
|
+
pnpm run verify:ci
|
|
30
|
+
pnpm run test:packed
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
The pull-request `Quality` workflow runs the complete non-fixing gate. `Commit message lint` validates the pull-request title and every commit. The packed-consumer test is also part of release readiness and must pass before publication.
|
|
34
|
+
|
|
35
|
+
Generated drift is repaired from source:
|
|
36
|
+
|
|
37
|
+
```sh
|
|
38
|
+
pnpm run catalog:build
|
|
39
|
+
pnpm run types:build
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
Never repair `catalog/`, `docs/platforms/`, or `dist/` directly.
|
|
43
|
+
|
|
44
|
+
## Vendor-documentation freshness
|
|
45
|
+
|
|
46
|
+
The `Vendor documentation freshness` workflow runs an index scan daily at 13:17 UTC and runs an index scan plus the full official-source scan every Monday at 13:47 UTC. A manual dispatch can select either depth. It has read-only repository access plus permission to open or update issues.
|
|
47
|
+
|
|
48
|
+
The workflow:
|
|
49
|
+
|
|
50
|
+
1. checks out the repository without persisted credentials;
|
|
51
|
+
2. runs the release-index scan, adding the full official-source scan on the weekly schedule or a manual `full` dispatch;
|
|
52
|
+
3. verifies that the scanner did not mutate the checkout;
|
|
53
|
+
4. uploads logs and evidence for 30 days;
|
|
54
|
+
5. opens or updates a source-specific attention issue when either scan reports drift or retrieval fails, and uses a scanner-integrity issue when the checkout changes.
|
|
55
|
+
|
|
56
|
+
It does not edit source, update `sources.lock.json`, open a vocabulary pull request, or publish.
|
|
57
|
+
|
|
58
|
+
### Triage an attention issue
|
|
59
|
+
|
|
60
|
+
1. Open the linked workflow run and download the artifact.
|
|
61
|
+
2. Inspect `index.log`, `full.log`, and `worktree-status.txt`.
|
|
62
|
+
3. Identify each observation that is not `unchanged`.
|
|
63
|
+
4. Open the registered official URL and review the exact locator in `sources/official-sources.json`.
|
|
64
|
+
5. Check the page's product/version context and whether the source is `exhaustive` or `supplemental`.
|
|
65
|
+
6. Compare every field and claim in the affected source profile.
|
|
66
|
+
|
|
67
|
+
Use these dispositions:
|
|
68
|
+
|
|
69
|
+
| Condition | Action |
|
|
70
|
+
| --- | --- |
|
|
71
|
+
| Transient/unreachable | Retry later; do not change claims or the reviewed lock |
|
|
72
|
+
| Cosmetic document change | Retain it in the scan artifact; it does not create an attention issue or require a lock refresh by itself |
|
|
73
|
+
| Claim-changing | The bounded observed token set is unchanged but claim content moved; update only supported structured claims and evidence, then rebuild |
|
|
74
|
+
| Enumeration-changing | The independent observed token set changed, required tokens disappeared, or discovery could not safely run; audit the entire surface, exact casing, extension boundary, and consumer impact |
|
|
75
|
+
| Version-changing | Add or migrate a versioned profile; do not silently widen a pinned profile |
|
|
76
|
+
| Removed/moved page | Locate an official replacement, update the manifest and locators, and retain review evidence in the pull request |
|
|
77
|
+
|
|
78
|
+
After review, update only the affected observations:
|
|
79
|
+
|
|
80
|
+
```sh
|
|
81
|
+
pnpm sources:review -- <source-id> [<source-id>...]
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
Then run:
|
|
85
|
+
|
|
86
|
+
```sh
|
|
87
|
+
pnpm run catalog:build
|
|
88
|
+
pnpm run verify:ci
|
|
89
|
+
pnpm run test:packed
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
`pnpm sources:review -- --all` is reserved for an intentional complete-lock refresh. `--allow-manual` is an exception for an independently reviewed official source that automation cannot retrieve; the pull request must explain the failure and review method, and the reviewer must manually verify every required token. It cannot override a fetched observation that reports missing tokens or establish a new independent enumeration baseline.
|
|
93
|
+
|
|
94
|
+
Close the attention issue only after the reviewed pull request is merged or the evidence establishes a transient false alarm. Link the issue to the reviewing pull request.
|
|
95
|
+
|
|
96
|
+
## Review and release impact
|
|
97
|
+
|
|
98
|
+
The source entry's `reviewOwner` reviews vendor meaning. A second maintainer should review changes that alter any of the following:
|
|
99
|
+
|
|
100
|
+
- an exhaustive enumeration;
|
|
101
|
+
- canonical field IDs;
|
|
102
|
+
- value, storage, or delivery shapes;
|
|
103
|
+
- official or contract-derived rendering operations;
|
|
104
|
+
- agent-policy rules or renderer bindings;
|
|
105
|
+
- consumer adapter routing;
|
|
106
|
+
- schema versions or public exports;
|
|
107
|
+
- source-lock or projection digest behavior.
|
|
108
|
+
|
|
109
|
+
Treat canonical-ID removals or renames, profile removal, incompatible schema changes, changed selected-contract meaning, and incompatible public API changes as breaking. Additive native facts are normally minor after `1.0.0`; corrected evidence or prose that does not change a contract is normally patch. Confirm the actual semantic-release result with a dry run.
|
|
110
|
+
|
|
111
|
+
## Release model
|
|
112
|
+
|
|
113
|
+
`semantic-release` owns versions, tags, release notes, the changelog, npm publication, and the release commit. Do not run `npm version`, edit the package version manually, create the release tag manually, or reuse an existing version.
|
|
114
|
+
|
|
115
|
+
Configured analysis rules are:
|
|
116
|
+
|
|
117
|
+
| Conventional change | Release after `1.0.0` |
|
|
118
|
+
| --- | --- |
|
|
119
|
+
| `feat:` | Minor |
|
|
120
|
+
| `type!:` or `type(scope)!:` | Major |
|
|
121
|
+
| `fix:`, `docs:`, `chore:`, `ci:`, `refactor:`, `test:`, and other configured non-feature types | Patch |
|
|
122
|
+
|
|
123
|
+
The initial semantic-release publication, when no prior release tag exists, is `1.0.0`. The repository remains `0.0.0-development` until that authorized publication.
|
|
124
|
+
|
|
125
|
+
Release preflight rejects `BREAKING CHANGE:` bodies because aggregated release bodies can cause accidental majors. Use `!` in the conventional subject for an intentional breaking change.
|
|
126
|
+
|
|
127
|
+
The literal commit marker `[skip release]` skips only the release job on a push; other quality and wiki workflows still run. Reserve it for a verified non-package follow-up such as recording durable wiki evidence for a release that has already completed. Do not use it to bypass publication for a contract or package change.
|
|
128
|
+
|
|
129
|
+
## Trusted publication boundary
|
|
130
|
+
|
|
131
|
+
`.github/workflows/release.yml` is the only publisher. On an authorized `main` push or dispatch it:
|
|
132
|
+
|
|
133
|
+
- validates release commits;
|
|
134
|
+
- runs the complete quality gate;
|
|
135
|
+
- packs and clean-installs the tarball;
|
|
136
|
+
- performs an npm publish dry run;
|
|
137
|
+
- invokes `semantic-release` to assign the version, update the changelog, publish npm with provenance, create the immutable `v${version}` tag, push the release commit, and publish the GitHub Release.
|
|
138
|
+
|
|
139
|
+
The workflow grants `contents: write` for the release commit, tag, and GitHub Release, and `id-token: write` for npm trusted publishing and provenance. Bind the npm trusted publisher to `JFusco/cms-field-vocabulary` and `.github/workflows/release.yml`; use a protected GitHub environment when the npm binding requires one.
|
|
140
|
+
|
|
141
|
+
If npm does not allow the trusted publisher to be attached before the unscoped package exists, create a least-privileged one-time granular access token that can create and publish `cms-field-vocabulary`, store it temporarily as the repository secret `NPM_TOKEN`, and run the same release workflow. `@semantic-release/npm` attempts OIDC first and uses the token only as a fallback. Immediately after `1.0.0` exists, bind the trusted publisher, delete the GitHub secret, and revoke the token. Do not retain a long-lived npm token for later releases.
|
|
142
|
+
|
|
143
|
+
## First release: 1.0.0
|
|
144
|
+
|
|
145
|
+
Use this checklist after the trusted publication path is approved:
|
|
146
|
+
|
|
147
|
+
1. Confirm the npm package name belongs to the project and bind the trusted publisher if npm already permits it.
|
|
148
|
+
2. Confirm branch protection and required checks are active on `main`.
|
|
149
|
+
3. Confirm there is no existing `v1.0.0` tag or published `cms-field-vocabulary@1.0.0`.
|
|
150
|
+
4. Resolve every vendor-freshness attention issue that affects shipped claims.
|
|
151
|
+
5. Confirm `sources.lock.json` contains every registered source and that all generated output is current.
|
|
152
|
+
6. Run locally from a clean checkout:
|
|
153
|
+
|
|
154
|
+
```sh
|
|
155
|
+
pnpm install --frozen-lockfile
|
|
156
|
+
pnpm run verify:ci
|
|
157
|
+
pnpm run test:packed
|
|
158
|
+
pnpm run release:dry
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
7. Inspect the dry-run release notes and packed file list. Confirm the proposed version is exactly `1.0.0`.
|
|
162
|
+
8. If the new package cannot yet accept a trusted-publisher binding, install the one-time `NPM_TOKEN` repository secret described above.
|
|
163
|
+
9. Dispatch or allow the release job from `main`.
|
|
164
|
+
10. After a token-bootstrap release, bind the trusted publisher, delete the GitHub secret, and revoke the token before any later release.
|
|
165
|
+
11. Do not retry blindly if the job becomes uncertain after npm publication. Check npm, GitHub Releases, and tags first.
|
|
166
|
+
12. Promote the Phase 1 wiki archive from `partial` to `implemented`, record the npm/tag/GitHub Release evidence, verify the wiki locally, and push that documentation-only commit with `[skip release]` so it cannot create an unintended `1.0.1`.
|
|
167
|
+
|
|
168
|
+
### Verify 1.0.0
|
|
169
|
+
|
|
170
|
+
After publication, verify all release outputs:
|
|
171
|
+
|
|
172
|
+
```sh
|
|
173
|
+
npm view cms-field-vocabulary@1.0.0 version dist.integrity dist.tarball dist.attestations --json
|
|
174
|
+
npm view cms-field-vocabulary@1.0.0 --json
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
Confirm:
|
|
178
|
+
|
|
179
|
+
- npm reports version `1.0.0` and provenance;
|
|
180
|
+
- GitHub contains immutable tag `v1.0.0` and the corresponding release notes;
|
|
181
|
+
- `CHANGELOG.md` and `package.json` contain the semantic-release update on `main`;
|
|
182
|
+
- a clean consumer can install `1.0.0`, run `sync`, `check`, and `resolve`;
|
|
183
|
+
- the tarball contains the catalog, profile projections, schemas, source manifest, reviewed source lock, runtime distribution, CLI, and operator documentation, but not repository workflows, tests, environment files, or wiki internals.
|
|
184
|
+
|
|
185
|
+
## Subsequent releases
|
|
186
|
+
|
|
187
|
+
For each later release:
|
|
188
|
+
|
|
189
|
+
1. Review commits since the last `vX.Y.Z` tag.
|
|
190
|
+
2. Run release preflight and dry run.
|
|
191
|
+
3. Confirm freshness review and generated projections are current.
|
|
192
|
+
4. Confirm the proposed semantic version matches contract impact.
|
|
193
|
+
5. Publish only from the trusted `main` workflow.
|
|
194
|
+
6. Verify npm provenance, tag, GitHub release, release commit, and clean-consumer behavior.
|
|
195
|
+
|
|
196
|
+
## Failed or harmful release
|
|
197
|
+
|
|
198
|
+
Do not rewrite a GitHub tag, overwrite an npm version, or force-push release history.
|
|
199
|
+
|
|
200
|
+
For a non-security defect, deprecate the affected npm version with a concise migration message and publish a fixed higher version. For a suspected compromise, stop publication, disable or rotate affected credentials and trusted-publisher access, preserve workflow evidence, follow [SECURITY.md](./SECURITY.md), deprecate the affected version, and release from a newly verified clean commit.
|
|
201
|
+
|
|
202
|
+
If semantic-release fails after one external side effect, inspect npm, GitHub tags, GitHub Releases, and `main` before rerunning. Resume only after determining which operations completed.
|
|
203
|
+
|
|
204
|
+
## Consumer incident response
|
|
205
|
+
|
|
206
|
+
If a selected contract is wrong but official evidence has not changed:
|
|
207
|
+
|
|
208
|
+
1. identify whether the defect is canonical vendor data, a contract-derived operation, agent policy, or consumer routing;
|
|
209
|
+
2. fix the owning structured layer only;
|
|
210
|
+
3. add a regression test for both compiled catalog and selected output;
|
|
211
|
+
4. publish the appropriate higher version;
|
|
212
|
+
5. have consumers update the exact dependency, run `sync`, and commit or verify the regenerated projection according to their repository policy.
|
|
213
|
+
|
|
214
|
+
Do not patch generated consumer files or copy corrected prose into adapters as a workaround.
|
package/README.md
ADDED
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
# cms-field-vocabulary
|
|
2
|
+
|
|
3
|
+
[](https://www.npmjs.com/package/cms-field-vocabulary)
|
|
4
|
+
|
|
5
|
+
`cms-field-vocabulary` is an official-source-backed catalog of native CMS field types and a deterministic contract generator for coding agents. It keeps vendor nomenclature, value shapes, rendering implications, and consumer-specific policy in one structured package without copying the same vocabulary prose into every adapter repository.
|
|
6
|
+
|
|
7
|
+
Stable publication begins at `1.0.0` and is owned by `semantic-release`. Source checkouts can retain the development placeholder until the release job assigns a version.
|
|
8
|
+
|
|
9
|
+
## What this package guarantees
|
|
10
|
+
|
|
11
|
+
- Native field tokens come from official vendor documentation or official vendor repositories recorded in `sources/official-sources.json`.
|
|
12
|
+
- Every documented claim carries a source ID and stable locator. A claim that official evidence does not support compiles as `undocumented`; it is not inferred or filled in.
|
|
13
|
+
- Product versions and schema surfaces stay separate. An authoring label, management-schema token, storage type, delivery type, and SDK type are not treated as synonyms.
|
|
14
|
+
- Consumer output is deterministic for an exact package version, configuration, profile, and selected set of canonical field IDs.
|
|
15
|
+
- Framework guidance is labeled separately from vendor authority. Consumer policy cannot masquerade as an official claim.
|
|
16
|
+
|
|
17
|
+
This package does not define a cross-CMS universal field enum, promise that open CMS installations cannot add custom types, or replace the vendor documentation linked by each claim.
|
|
18
|
+
|
|
19
|
+
## Authority and generated output
|
|
20
|
+
|
|
21
|
+
The repository has one vocabulary-authoring path:
|
|
22
|
+
|
|
23
|
+
1. `sources/official-sources.json` registers official evidence, its version mode, completeness, locator, expected tokens, allowed hosts, and review owner.
|
|
24
|
+
2. `sources/profiles/*.json` is the canonical human-authored vocabulary. Each file covers one product version, surface, and transport.
|
|
25
|
+
3. `profiles/agent/*.json` contains framework or coding-agent policy. It is not vendor evidence.
|
|
26
|
+
4. `profiles/consumers/*.json` routes a consumer's adapter names to exact vocabulary profiles.
|
|
27
|
+
5. `catalog/`, `docs/platforms/`, `dist/`, and consumer projections are generated from those inputs.
|
|
28
|
+
|
|
29
|
+
Generated Markdown is a readable view, not another source of truth. Do not edit generated files or reproduce their field tables in adapter rules, skills, or application documentation. Consumers should resolve the contracts they need from the installed package.
|
|
30
|
+
|
|
31
|
+
## Included profiles
|
|
32
|
+
|
|
33
|
+
Seven CMS identities are represented by sixteen versioned surface profiles:
|
|
34
|
+
|
|
35
|
+
| Platform | Profile | Surface | Version boundary |
|
|
36
|
+
| --- | --- | --- | --- |
|
|
37
|
+
| Contentful | `contentful.cma.saas` | Management | SaaS snapshot observed 2026-09-01 |
|
|
38
|
+
| Contentstack | `contentstack.cma.saas` | Management | SaaS snapshot observed 2026-09-01 |
|
|
39
|
+
| Optimizely SaaS | `optimizely-saas.cms-api-v1` | Management | CMS SaaS API v1 |
|
|
40
|
+
| Optimizely SaaS | `optimizely-saas.sdk-2` | SDK | `@optimizely/cms-sdk` 2.x contract snapshot |
|
|
41
|
+
| Optimizely PaaS | `optimizely-paas.cms12-model` | SDK/model | CMS 12 model and editor surface |
|
|
42
|
+
| Optimizely PaaS | `optimizely-paas.cms12-property-data-type` | Storage | `EPiServer.dll` 12.0.3 enum |
|
|
43
|
+
| Optimizely PaaS | `optimizely-paas.cms13-admin` | Authoring | CMS 13 admin labels |
|
|
44
|
+
| Optimizely PaaS | `optimizely-paas.cms13-model` | SDK/model | CMS 13 .NET content model types |
|
|
45
|
+
| SitecoreAI | `sitecore-ai.authoring.current` | Authoring | Rolling SitecoreAI snapshot observed 2026-09-01 |
|
|
46
|
+
| SitecoreAI | `sitecore-ai.content-sdk2` | SDK | Rolling SitecoreAI delivery with Content SDK 2.x |
|
|
47
|
+
| Sitecore XP | `sitecore-on-prem.xp104-authoring` | Authoring | XP 10.4 editor vocabulary |
|
|
48
|
+
| Sitecore XP | `sitecore-on-prem.headless22` | SDK | XP 10.4 with Headless Services 22 |
|
|
49
|
+
| WordPress | `wordpress.core71-meta` | Storage | Core 7.1 `register_meta` |
|
|
50
|
+
| WordPress | `wordpress.core71-rest-schema` | Delivery | Core 7.1 REST JSON Schema |
|
|
51
|
+
| WordPress | `wordpress.core71-block-attributes` | Storage | Core 7.1 block attribute `type` |
|
|
52
|
+
| WordPress | `wordpress.core71-block-attribute-source` | Storage | Core 7.1 block attribute `source` |
|
|
53
|
+
|
|
54
|
+
The `extensibility` value on each profile tells consumers whether the documented vocabulary is closed at that exact profile, discoverable, or open. It does not change the evidence threshold for adding native types.
|
|
55
|
+
|
|
56
|
+
## Requirements and installation
|
|
57
|
+
|
|
58
|
+
- Node.js 24.14.0 or newer
|
|
59
|
+
- pnpm 11.1.1 for repository development
|
|
60
|
+
|
|
61
|
+
After `1.0.0` is published:
|
|
62
|
+
|
|
63
|
+
```sh
|
|
64
|
+
pnpm add cms-field-vocabulary
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
Create `cms-field-vocabulary.config.json` in the consuming repository:
|
|
68
|
+
|
|
69
|
+
```json
|
|
70
|
+
{
|
|
71
|
+
"$schema": "./node_modules/cms-field-vocabulary/schemas/consumer-config.schema.json",
|
|
72
|
+
"packageName": "cms-field-vocabulary",
|
|
73
|
+
"profile": "generic",
|
|
74
|
+
"adapter": "contentful",
|
|
75
|
+
"target": "generated/cms-field-vocabulary"
|
|
76
|
+
}
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
The available consumer profiles are `generic`, `ai-orchestration`, and `cos`. They may use different adapter names while routing to the same canonical vendor profiles. `generic` and `ai-orchestration` emit coding-agent contracts. The future-facing `cos` profile emits compact official-data shards containing only profile identity plus field `canonicalId`, exact `nativeToken`, optional `displayName`, `valueShape`, and `formats`; it contains no rendering operations, agent profile, renderer bindings, consumer policy, evidence, or descriptive claim prose.
|
|
80
|
+
|
|
81
|
+
## Synchronize and verify a consumer projection
|
|
82
|
+
|
|
83
|
+
Synchronize the exact installed package into the configured target:
|
|
84
|
+
|
|
85
|
+
```sh
|
|
86
|
+
pnpm exec cms-field-vocabulary sync --config cms-field-vocabulary.config.json --if-needed
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
Verify it in CI without accepting drift:
|
|
90
|
+
|
|
91
|
+
```sh
|
|
92
|
+
pnpm exec cms-field-vocabulary check --config cms-field-vocabulary.config.json
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
The target contains:
|
|
96
|
+
|
|
97
|
+
- a generated ownership marker;
|
|
98
|
+
- package, catalog, and source-lock identity in `source.json`;
|
|
99
|
+
- exact adapter-to-profile routing in `adapters.json`;
|
|
100
|
+
- deterministic adapter contracts under `contracts/`;
|
|
101
|
+
- a SHA-256 projection manifest.
|
|
102
|
+
|
|
103
|
+
Synchronization accepts relative config paths and absolute config paths that remain inside the consumer root. It refuses absolute or escaping targets, config paths outside the consumer root, symlink traversal, unmarked directories, unexpected files, and locally modified generated files. Replacement is staged and renamed atomically. Treat the entire target as generated and never edit it manually.
|
|
104
|
+
|
|
105
|
+
## Resolve only the fields needed by an agent
|
|
106
|
+
|
|
107
|
+
Agent context should contain selected contracts, not the whole catalog. Resolve one or more canonical field IDs from one exact CMS profile:
|
|
108
|
+
|
|
109
|
+
```sh
|
|
110
|
+
pnpm exec cms-field-vocabulary resolve \
|
|
111
|
+
--config cms-field-vocabulary.config.json \
|
|
112
|
+
--field-id optimizely-saas.sdk-2.contentReference \
|
|
113
|
+
--rendering-selection optimizely-saas.sdk-2.contentReference:content-reference-usage=media \
|
|
114
|
+
--output artifacts/cms-fields/component-contract.json
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
Each repeatable `--rendering-selection` uses the exact closed syntax `<field-id>:<discriminator>=<value>`. `resolve` first verifies the installed projection, rejects field IDs from different profiles, applies only the configured consumer's agent policy, sorts and deduplicates the requested IDs, and writes a deterministic selected contract. A selected field with mutually exclusive rendering branches fails closed until its discriminator is supplied. Unknown, duplicate, unrequested, and unsupported selections also fail before output is written. Claim provenance stays in the catalog for audit and review; it is intentionally omitted from normal agent context.
|
|
118
|
+
|
|
119
|
+
The CLI requires at least one `--field-id`. The programmatic file resolver treats an explicitly empty field list as a successful no-op, returns `null`, and creates no output file.
|
|
120
|
+
|
|
121
|
+
A consuming adapter should identify the field IDs required by the current component and load that selected artifact. It should not paste field definitions or rendering prose from this repository into its own permanent rules.
|
|
122
|
+
|
|
123
|
+
Selected-contract size is guarded by committed byte and deterministic token-estimate ceilings in `profiles/context-budget.json`. `pnpm run context:check` rejects growth; maintainers use `pnpm run context:update` only after reviewing an intentional contract expansion.
|
|
124
|
+
|
|
125
|
+
## Programmatic API
|
|
126
|
+
|
|
127
|
+
```ts
|
|
128
|
+
import {
|
|
129
|
+
getProfile,
|
|
130
|
+
resolveFieldContracts,
|
|
131
|
+
} from 'cms-field-vocabulary';
|
|
132
|
+
|
|
133
|
+
const profile = getProfile('optimizely-saas.sdk-2');
|
|
134
|
+
const selected = resolveFieldContracts({
|
|
135
|
+
profileId: profile.id,
|
|
136
|
+
fieldIds: [
|
|
137
|
+
'optimizely-saas.sdk-2.contentReference',
|
|
138
|
+
],
|
|
139
|
+
agentProfile: 'react-nextjs',
|
|
140
|
+
renderingSelections: [{
|
|
141
|
+
fieldId: 'optimizely-saas.sdk-2.contentReference',
|
|
142
|
+
discriminator: 'content-reference-usage',
|
|
143
|
+
value: 'media',
|
|
144
|
+
}],
|
|
145
|
+
});
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
Selection-gated operations carry a closed discriminator in the contract. Supplying `renderingSelections` projects only the matching branch; an unknown, duplicate, unrequested, or unsupported choice fails closed.
|
|
149
|
+
|
|
150
|
+
`resolveFieldContracts` returns `null` immediately when `fieldIds` is empty. Callers should omit `inputs.cmsFieldContracts` in that case so a CMS-free job receives no CMS profile, agent, renderer, or contract metadata.
|
|
151
|
+
|
|
152
|
+
The root export also provides catalog lookup and projection functions. Package subpath exports expose the generated catalog, JSON Schemas, and consumer profiles. The published tarball also includes the official source manifest and reviewed source lock for filesystem-based audit tooling.
|
|
153
|
+
|
|
154
|
+
## Freshness is reviewed, not auto-authored
|
|
155
|
+
|
|
156
|
+
A scheduled, read-only workflow checks registered official release/version indexes daily and runs a full official-source scan weekly. It normalizes fetched documents, compares reviewed hashes, verifies required evidence tokens, and independently extracts complete token sets from structurally bounded official-source regions. The required-token check proves approved facts still have evidence; the independent observed-token hash detects native types added or removed without first adding them to the manifest. Claim text drift is classified separately when the observed enumeration is unchanged. Raw-only cosmetic churn remains visible in the uploaded report but does not create an attention issue.
|
|
157
|
+
|
|
158
|
+
The scanner never edits vocabulary source, updates the reviewed lock, opens a vocabulary pull request, or publishes a package. A maintainer must inspect the official source at the recorded locator, update structured claims when warranted, run the explicit source-review command, and pass the full quality gate. See [CONTRIBUTING.md](./CONTRIBUTING.md) for evidence rules and [OPERATING.md](./OPERATING.md) for the freshness and release runbooks.
|
|
159
|
+
|
|
160
|
+
## License and security
|
|
161
|
+
|
|
162
|
+
The package is available under the [MIT License](./LICENSE). Report security issues according to [SECURITY.md](./SECURITY.md).
|
package/SECURITY.md
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
# Security policy
|
|
2
|
+
|
|
3
|
+
## Supported versions
|
|
4
|
+
|
|
5
|
+
The first public release is `1.0.0`. After release, security fixes are provided for the latest `1.x` release. Development snapshots such as `0.0.0-development` and older minors are not supported distribution channels.
|
|
6
|
+
|
|
7
|
+
| Version | Supported |
|
|
8
|
+
| --- | --- |
|
|
9
|
+
| Latest `1.x` | Yes |
|
|
10
|
+
| Development snapshots | No |
|
|
11
|
+
| Older major versions | No |
|
|
12
|
+
|
|
13
|
+
Support here means the maintainers will assess a report and, when warranted, publish a fixed release. No response-time or remediation-time guarantee is made.
|
|
14
|
+
|
|
15
|
+
## Report a vulnerability privately
|
|
16
|
+
|
|
17
|
+
Use [GitHub private vulnerability reporting](https://github.com/JFusco/cms-field-vocabulary/security/advisories/new). Include:
|
|
18
|
+
|
|
19
|
+
- affected package version and entry point;
|
|
20
|
+
- reproduction steps or a minimal proof of concept;
|
|
21
|
+
- security impact and required preconditions;
|
|
22
|
+
- whether the issue affects the CLI, programmatic API, source scanner, generated projection, packed artifact, or release process;
|
|
23
|
+
- any suggested mitigation.
|
|
24
|
+
|
|
25
|
+
Do not open a public issue with exploit details, tokens, private repository paths, or unpublished vendor information. If private vulnerability reporting is unavailable, open a minimal public issue asking the maintainer to establish a private channel, without describing the vulnerability.
|
|
26
|
+
|
|
27
|
+
Normal corrections to a public CMS field token, description, source locator, or freshness observation are data-quality issues and can use the public issue tracker. Treat one as a security report when crafted catalog data or vendor content can cause code execution, path traversal, credential disclosure, package compromise, or another security boundary failure.
|
|
28
|
+
|
|
29
|
+
## Security boundaries
|
|
30
|
+
|
|
31
|
+
Official vendor pages are evidence, but fetched page content is still untrusted input. The freshness scanner:
|
|
32
|
+
|
|
33
|
+
- follows only HTTPS sources and checks every redirect against each source's host allowlist;
|
|
34
|
+
- limits redirects, retries, response time, and fetch concurrency;
|
|
35
|
+
- normalizes documents and compares hashes and declared tokens;
|
|
36
|
+
- writes reports only;
|
|
37
|
+
- does not update canonical profiles, accept a new source lock, create a vocabulary pull request, or publish a package.
|
|
38
|
+
|
|
39
|
+
Human review remains required before `sources.lock.json` or canonical vocabulary source changes.
|
|
40
|
+
|
|
41
|
+
Consumer projection code rejects absolute or escaping target paths, symlink traversal, unmarked targets, unexpected files, and modified generated files. It writes into a staging directory and replaces a verified target by rename. A vulnerability that bypasses any of those checks is in scope.
|
|
42
|
+
|
|
43
|
+
Published packages are configured for public npm provenance. Packed-artifact verification checks the expected file boundary, installs the tarball into clean consumers, and scans packed content for known credential and local-path patterns. These controls reduce risk but do not make vendor documentation or generated coding guidance a security warranty.
|
|
44
|
+
|
|
45
|
+
## Maintainer response
|
|
46
|
+
|
|
47
|
+
Maintainers should acknowledge the report privately, reproduce it in an isolated environment, determine affected versions, and coordinate a fix and advisory before public disclosure. For a compromised release, pause publication, revoke affected credentials or trusted-publisher access, deprecate the affected npm version, and publish a clean higher version. Do not overwrite an existing npm version or move an existing release tag.
|
|
48
|
+
|
|
49
|
+
Never request or accept production CMS credentials, npm tokens, GitHub tokens, or customer content as part of a reproduction.
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import {
|
|
4
|
+
checkProjection,
|
|
5
|
+
resolveProjectionFields,
|
|
6
|
+
syncProjection,
|
|
7
|
+
} from '../dist/index.js';
|
|
8
|
+
|
|
9
|
+
function usage() {
|
|
10
|
+
console.error([
|
|
11
|
+
'Usage:',
|
|
12
|
+
' cms-field-vocabulary sync --config <path> [--if-needed]',
|
|
13
|
+
' cms-field-vocabulary check --config <path>',
|
|
14
|
+
' cms-field-vocabulary resolve --config <path> --field-id <id>... [--rendering-selection <field-id>:<discriminator>=<value>]... --output <path>',
|
|
15
|
+
].join('\n'));
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
function parseRenderingSelection(value) {
|
|
19
|
+
const match = /^([^:]+):([^=]+)=([^=]+)$/.exec(value);
|
|
20
|
+
if (!match) {
|
|
21
|
+
throw new Error('--rendering-selection must use <field-id>:<discriminator>=<value>');
|
|
22
|
+
}
|
|
23
|
+
return { fieldId: match[1], discriminator: match[2], value: match[3] };
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function parseArguments(argv) {
|
|
27
|
+
const [command, ...rest] = argv;
|
|
28
|
+
const options = {
|
|
29
|
+
command,
|
|
30
|
+
config: null,
|
|
31
|
+
output: null,
|
|
32
|
+
fieldIds: [],
|
|
33
|
+
renderingSelections: [],
|
|
34
|
+
ifNeeded: false,
|
|
35
|
+
seen: new Set(),
|
|
36
|
+
};
|
|
37
|
+
function readValue(index, flag) {
|
|
38
|
+
const value = rest[index + 1];
|
|
39
|
+
if (!value || value.startsWith('--')) throw new Error(`${flag} requires a value`);
|
|
40
|
+
return value;
|
|
41
|
+
}
|
|
42
|
+
for (let index = 0; index < rest.length; index += 1) {
|
|
43
|
+
const argument = rest[index];
|
|
44
|
+
if (argument === '--if-needed') {
|
|
45
|
+
if (options.seen.has(argument)) throw new Error(`Duplicate option: ${argument}`);
|
|
46
|
+
options.seen.add(argument);
|
|
47
|
+
options.ifNeeded = true;
|
|
48
|
+
}
|
|
49
|
+
else if (argument === '--config' || argument === '--output') {
|
|
50
|
+
if (options.seen.has(argument)) throw new Error(`Duplicate option: ${argument}`);
|
|
51
|
+
options.seen.add(argument);
|
|
52
|
+
const value = readValue(index, argument);
|
|
53
|
+
if (argument === '--config') options.config = value;
|
|
54
|
+
else options.output = value;
|
|
55
|
+
index += 1;
|
|
56
|
+
}
|
|
57
|
+
else if (argument === '--field-id') {
|
|
58
|
+
options.seen.add(argument);
|
|
59
|
+
options.fieldIds.push(readValue(index, argument));
|
|
60
|
+
index += 1;
|
|
61
|
+
}
|
|
62
|
+
else if (argument === '--rendering-selection') {
|
|
63
|
+
options.seen.add(argument);
|
|
64
|
+
options.renderingSelections.push(parseRenderingSelection(readValue(index, argument)));
|
|
65
|
+
index += 1;
|
|
66
|
+
}
|
|
67
|
+
else throw new Error(`Unknown argument: ${argument}`);
|
|
68
|
+
}
|
|
69
|
+
return options;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
function rejectOptions(options, command, flags) {
|
|
73
|
+
for (const flag of flags) {
|
|
74
|
+
if (options.seen.has(flag)) throw new Error(`${flag} is not valid for ${command}`);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
try {
|
|
79
|
+
const options = parseArguments(process.argv.slice(2));
|
|
80
|
+
if (!options.config) throw new Error('--config is required');
|
|
81
|
+
if (options.command === 'sync') {
|
|
82
|
+
rejectOptions(options, 'sync', ['--output', '--field-id', '--rendering-selection']);
|
|
83
|
+
const status = await syncProjection({ configPath: options.config, ifNeeded: options.ifNeeded });
|
|
84
|
+
console.log(status === 'current' ? 'CMS field projection is current.' : 'CMS field projection synchronized.');
|
|
85
|
+
} else if (options.command === 'check') {
|
|
86
|
+
rejectOptions(options, 'check', ['--if-needed', '--output', '--field-id', '--rendering-selection']);
|
|
87
|
+
await checkProjection({ configPath: options.config });
|
|
88
|
+
console.log('CMS field projection is current.');
|
|
89
|
+
} else if (options.command === 'resolve') {
|
|
90
|
+
rejectOptions(options, 'resolve', ['--if-needed']);
|
|
91
|
+
if (!options.output) throw new Error('--output is required');
|
|
92
|
+
if (options.fieldIds.length === 0) throw new Error('resolve requires at least one --field-id');
|
|
93
|
+
const selected = await resolveProjectionFields({
|
|
94
|
+
configPath: options.config,
|
|
95
|
+
fieldIds: options.fieldIds,
|
|
96
|
+
renderingSelections: options.renderingSelections,
|
|
97
|
+
output: options.output,
|
|
98
|
+
});
|
|
99
|
+
console.log(`Resolved ${selected?.contracts.length || 0} selected CMS field contract(s).`);
|
|
100
|
+
} else {
|
|
101
|
+
usage();
|
|
102
|
+
process.exitCode = 2;
|
|
103
|
+
}
|
|
104
|
+
} catch (error) {
|
|
105
|
+
console.error(error instanceof Error ? error.message : String(error));
|
|
106
|
+
usage();
|
|
107
|
+
process.exitCode = 1;
|
|
108
|
+
}
|