@cosmic-labs/content-contract 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.
@@ -0,0 +1,91 @@
1
+ import { z } from 'zod';
2
+
3
+ /** A migration recorded after it has been safely applied to one site's content. */
4
+ declare const MigrationLedgerEntrySchema: z.ZodObject<{
5
+ id: z.ZodString;
6
+ appliedAt: z.ZodString;
7
+ note: z.ZodString;
8
+ }, "strict", z.ZodTypeAny, {
9
+ id: string;
10
+ appliedAt: string;
11
+ note: string;
12
+ }, {
13
+ id: string;
14
+ appliedAt: string;
15
+ note: string;
16
+ }>;
17
+ /**
18
+ * Checked-in intent for a site. Production truth is established separately by a
19
+ * deploy attestation; this manifest deliberately contains no credentials.
20
+ */
21
+ declare const CapabilityManifestSchema: z.ZodObject<{
22
+ contractVersion: z.ZodString;
23
+ requestedCapabilities: z.ZodArray<z.ZodString, "many">;
24
+ projectId: z.ZodString;
25
+ dataset: z.ZodString;
26
+ envName: z.ZodString;
27
+ migrationLedger: z.ZodArray<z.ZodObject<{
28
+ id: z.ZodString;
29
+ appliedAt: z.ZodString;
30
+ note: z.ZodString;
31
+ }, "strict", z.ZodTypeAny, {
32
+ id: string;
33
+ appliedAt: string;
34
+ note: string;
35
+ }, {
36
+ id: string;
37
+ appliedAt: string;
38
+ note: string;
39
+ }>, "many">;
40
+ }, "strict", z.ZodTypeAny, {
41
+ contractVersion: string;
42
+ requestedCapabilities: string[];
43
+ projectId: string;
44
+ dataset: string;
45
+ envName: string;
46
+ migrationLedger: {
47
+ id: string;
48
+ appliedAt: string;
49
+ note: string;
50
+ }[];
51
+ }, {
52
+ contractVersion: string;
53
+ requestedCapabilities: string[];
54
+ projectId: string;
55
+ dataset: string;
56
+ envName: string;
57
+ migrationLedger: {
58
+ id: string;
59
+ appliedAt: string;
60
+ note: string;
61
+ }[];
62
+ }>;
63
+ type MigrationLedgerEntry = z.infer<typeof MigrationLedgerEntrySchema>;
64
+ type CapabilityManifest = z.infer<typeof CapabilityManifestSchema>;
65
+ /** Metadata shape for the append-only registry; registry data is intentionally site-governed. */
66
+ type BlockRegistryEntry = {
67
+ type: string;
68
+ introducedIn: string;
69
+ /** Present only for Portable Text object types rendered by Atlas. */
70
+ rendererCapability?: string;
71
+ migrationChain: string[];
72
+ retirementState: 'active' | 'deprecated' | 'retired';
73
+ examplesRef?: string;
74
+ };
75
+ /**
76
+ * Append-only registry for blocks shipped by Atlas. Removing an entry would
77
+ * erase the compatibility history that sites need to safely render old content.
78
+ */
79
+ declare const blockRegistry: readonly BlockRegistryEntry[];
80
+ /**
81
+ * Canonical JSON serializer for JSON-compatible values. Object keys are sorted
82
+ * by code point so its output does not depend on insertion order or runtime locale.
83
+ */
84
+ declare function canonicalizeJson(value: unknown): string;
85
+ /**
86
+ * Hash an unordered renderer capability set. Duplicate values and input order do
87
+ * not affect the SHA-256 hex result, making it safe to compare in attestations.
88
+ */
89
+ declare function capabilityHash(capabilities: readonly string[]): string;
90
+
91
+ export { type BlockRegistryEntry, type CapabilityManifest, CapabilityManifestSchema, type MigrationLedgerEntry, MigrationLedgerEntrySchema, blockRegistry, canonicalizeJson, capabilityHash };
package/dist/index.js ADDED
@@ -0,0 +1,118 @@
1
+ // src/capabilities.ts
2
+ import { createHash } from "crypto";
3
+ import { z } from "zod";
4
+ var MigrationLedgerEntrySchema = z.object({
5
+ id: z.string().min(1),
6
+ appliedAt: z.string().datetime(),
7
+ note: z.string().min(1)
8
+ }).strict();
9
+ var CapabilityManifestSchema = z.object({
10
+ contractVersion: z.string().min(1),
11
+ requestedCapabilities: z.array(z.string().min(1)),
12
+ projectId: z.string().min(1),
13
+ dataset: z.string().min(1),
14
+ envName: z.string().min(1),
15
+ migrationLedger: z.array(MigrationLedgerEntrySchema)
16
+ }).strict();
17
+ var blockRegistry = [
18
+ {
19
+ type: "statCallout",
20
+ introducedIn: "0.1.0",
21
+ rendererCapability: "statCallout",
22
+ migrationChain: [],
23
+ retirementState: "active"
24
+ },
25
+ {
26
+ type: "comparisonTable",
27
+ introducedIn: "0.1.0",
28
+ rendererCapability: "comparisonTable",
29
+ migrationChain: [],
30
+ retirementState: "active"
31
+ },
32
+ {
33
+ type: "editorialQuote",
34
+ introducedIn: "0.1.0",
35
+ rendererCapability: "editorialQuote",
36
+ migrationChain: [],
37
+ retirementState: "active"
38
+ },
39
+ {
40
+ type: "definitionBox",
41
+ introducedIn: "0.1.0",
42
+ rendererCapability: "definitionBox",
43
+ migrationChain: [],
44
+ retirementState: "active"
45
+ },
46
+ {
47
+ type: "checklistBox",
48
+ introducedIn: "0.1.0",
49
+ rendererCapability: "checklistBox",
50
+ migrationChain: [],
51
+ retirementState: "active"
52
+ },
53
+ {
54
+ type: "captionedImage",
55
+ introducedIn: "0.1.0",
56
+ rendererCapability: "captionedImage",
57
+ migrationChain: [],
58
+ retirementState: "active"
59
+ },
60
+ {
61
+ type: "botanicalDivider",
62
+ introducedIn: "0.1.0",
63
+ rendererCapability: "botanicalDivider",
64
+ migrationChain: [],
65
+ retirementState: "active"
66
+ },
67
+ {
68
+ type: "videoEmbed",
69
+ introducedIn: "0.1.0",
70
+ rendererCapability: "videoEmbed",
71
+ migrationChain: [],
72
+ retirementState: "active"
73
+ },
74
+ {
75
+ type: "fact",
76
+ introducedIn: "0.1.0",
77
+ migrationChain: [],
78
+ retirementState: "active"
79
+ }
80
+ ];
81
+ function compareCodePoints(left, right) {
82
+ return left < right ? -1 : left > right ? 1 : 0;
83
+ }
84
+ function canonicalizeJson(value) {
85
+ if (value === null || typeof value === "boolean" || typeof value === "string") {
86
+ return JSON.stringify(value);
87
+ }
88
+ if (typeof value === "number") {
89
+ if (!Number.isFinite(value)) {
90
+ throw new TypeError("Canonical JSON does not support non-finite numbers.");
91
+ }
92
+ return JSON.stringify(value);
93
+ }
94
+ if (Array.isArray(value)) {
95
+ return `[${value.map(canonicalizeJson).join(",")}]`;
96
+ }
97
+ if (typeof value === "object") {
98
+ const record = value;
99
+ return `{${Object.keys(record).sort(compareCodePoints).map((key) => `${JSON.stringify(key)}:${canonicalizeJson(record[key])}`).join(",")}}`;
100
+ }
101
+ throw new TypeError(`Canonical JSON does not support ${typeof value} values.`);
102
+ }
103
+ function capabilityHash(capabilities) {
104
+ const normalized = [...new Set(capabilities.map((capability) => {
105
+ if (!capability) {
106
+ throw new TypeError("Capabilities must be non-empty strings.");
107
+ }
108
+ return capability;
109
+ }))].sort(compareCodePoints);
110
+ return createHash("sha256").update(canonicalizeJson(normalized), "utf8").digest("hex");
111
+ }
112
+ export {
113
+ CapabilityManifestSchema,
114
+ MigrationLedgerEntrySchema,
115
+ blockRegistry,
116
+ canonicalizeJson,
117
+ capabilityHash
118
+ };
package/package.json ADDED
@@ -0,0 +1,38 @@
1
+ {
2
+ "name": "@cosmic-labs/content-contract",
3
+ "version": "0.1.0",
4
+ "description": "Versioned content contracts and capability manifests for Cosmic Atlas sites.",
5
+ "license": "UNLICENSED",
6
+ "type": "module",
7
+ "main": "./dist/index.js",
8
+ "types": "./dist/index.d.ts",
9
+ "exports": {
10
+ ".": {
11
+ "types": "./dist/index.d.ts",
12
+ "import": "./dist/index.js"
13
+ }
14
+ },
15
+ "files": [
16
+ "dist"
17
+ ],
18
+ "publishConfig": {
19
+ "access": "restricted"
20
+ },
21
+ "dependencies": {
22
+ "zod": "^3.24.1"
23
+ },
24
+ "devDependencies": {
25
+ "@types/node": "^22.10.1",
26
+ "tsup": "^8.3.5",
27
+ "typescript": "^5.7.2",
28
+ "vitest": "^3.0.0"
29
+ },
30
+ "engines": {
31
+ "node": ">=22.14"
32
+ },
33
+ "scripts": {
34
+ "build": "tsup src/index.ts --format esm --dts --clean --target es2022",
35
+ "test": "vitest run --root ../.. --project content-contract --passWithNoTests",
36
+ "lint": "tsc --noEmit"
37
+ }
38
+ }