@ontrails/schema 1.0.0-beta.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 @@
1
+ $ tsc -b
@@ -0,0 +1,3 @@
1
+ $ oxlint ./src
2
+ Found 0 warnings and 0 errors.
3
+ Finished in 109ms on 10 files with 93 rules using 24 threads.
@@ -0,0 +1 @@
1
+ $ tsc --noEmit
package/CHANGELOG.md ADDED
@@ -0,0 +1,20 @@
1
+ # @ontrails/schema
2
+
3
+ ## 1.0.0-beta.0
4
+
5
+ ### Minor Changes
6
+
7
+ - Initial v1 beta release of the Trails framework.
8
+
9
+ - **@ontrails/core** — Result type, error taxonomy, trail/hike/event/topo, validateTopo, validateInput/Output, deriveFields, patterns, redaction, branded types, resilience
10
+ - **@ontrails/cli** — CLI surface adapter, Commander integration, flag derivation, layers
11
+ - **@ontrails/mcp** — MCP surface adapter, tool generation, annotations, progress bridge
12
+ - **@ontrails/logging** — Structured logging, sinks, formatters, LogTape adapter
13
+ - **@ontrails/testing** — testAll, testExamples, testTrail, testHike, testContracts, testDetours, surface harnesses
14
+ - **@ontrails/warden** — AST-based code convention rules via oxc-parser, drift detection, CI formatters
15
+ - **@ontrails/schema** — Surface map generation, hashing, semantic diffing
16
+
17
+ ### Patch Changes
18
+
19
+ - Updated dependencies
20
+ - @ontrails/core@1.0.0-beta.0
package/README.md ADDED
@@ -0,0 +1,139 @@
1
+ # @ontrails/schema
2
+
3
+ Surface maps, diffing, and lock files for Trails. The machine-readable contract for CI and governance.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ bun add -d @ontrails/schema
9
+ ```
10
+
11
+ Peer dependencies: `@ontrails/core`, `zod`.
12
+
13
+ ## Quick Start
14
+
15
+ ```typescript
16
+ import {
17
+ generateSurfaceMap,
18
+ hashSurfaceMap,
19
+ diffSurfaceMaps,
20
+ } from '@ontrails/schema';
21
+
22
+ // Generate the surface map from the topo
23
+ const surfaceMap = generateSurfaceMap(app);
24
+
25
+ // Hash it for the lock file
26
+ const hash = hashSurfaceMap(surfaceMap);
27
+
28
+ // Diff two surface maps
29
+ const diff = diffSurfaceMaps(previousMap, surfaceMap);
30
+ if (diff.hasBreaking) {
31
+ console.error('Breaking changes detected:', diff.breaking);
32
+ }
33
+ ```
34
+
35
+ ## API Overview
36
+
37
+ ### `generateSurfaceMap(topo)`
38
+
39
+ Produces a deterministic manifest of every trail in the topo. Entries are sorted alphabetically by ID. Input and output schemas are converted to JSON Schema via `zodToJsonSchema()`.
40
+
41
+ ```typescript
42
+ const map = generateSurfaceMap(app);
43
+ // {
44
+ // version: "1.0",
45
+ // generatedAt: "2026-03-25T10:00:00.000Z",
46
+ // entries: [
47
+ // { id: "entity.show", kind: "trail", input: {...}, readOnly: true, exampleCount: 2 },
48
+ // { id: "search", kind: "trail", input: {...}, exampleCount: 1 },
49
+ // ]
50
+ // }
51
+ ```
52
+
53
+ Each `SurfaceMapEntry` includes:
54
+
55
+ - `id`, `kind` (`"trail"` | `"hike"` | `"event"`)
56
+ - `input` and `output` as JSON Schema
57
+ - Safety markers: `readOnly`, `destructive`, `idempotent`
58
+ - `deprecated`, `replacedBy`
59
+ - `follows` (for hikes), `detours`
60
+ - `exampleCount`, `description`
61
+
62
+ ### `hashSurfaceMap(surfaceMap)`
63
+
64
+ SHA-256 hash of the surface map content. Excludes `generatedAt` so the same topo always produces the same hash byte-for-byte.
65
+
66
+ ```typescript
67
+ const hash = hashSurfaceMap(map); // "a1b2c3d4..."
68
+ ```
69
+
70
+ ### `diffSurfaceMaps(prev, curr)`
71
+
72
+ Semantic diff between two surface maps. Classifies every change by severity instead of producing raw JSON diffs.
73
+
74
+ ```typescript
75
+ const diff = diffSurfaceMaps(previousMap, currentMap);
76
+
77
+ diff.entries; // All changes
78
+ diff.breaking; // Breaking changes only
79
+ diff.warnings; // Warnings only
80
+ diff.info; // Informational changes
81
+ diff.hasBreaking; // Quick check
82
+ ```
83
+
84
+ **Breaking change detection:**
85
+
86
+ | Change | Severity |
87
+ | -------------------------- | -------- |
88
+ | Trail removed | breaking |
89
+ | Required input field added | breaking |
90
+ | Input field removed | breaking |
91
+ | Output field removed | breaking |
92
+ | Output field type changed | breaking |
93
+ | Surface removed | breaking |
94
+ | Safety marker changed | warning |
95
+ | Trail deprecated | warning |
96
+ | Follows changed | warning |
97
+ | Trail added | info |
98
+ | Optional input field added | info |
99
+ | Output field added | info |
100
+ | Surface added | info |
101
+
102
+ ### Lock File I/O
103
+
104
+ ```typescript
105
+ import {
106
+ writeSurfaceMap, // .trails/_surface.json (gitignored detail file)
107
+ readSurfaceMap, // Read it back
108
+ writeSurfaceLock, // surface.lock (committed, single hash line)
109
+ readSurfaceLock, // Read the lock hash
110
+ } from '@ontrails/schema';
111
+ ```
112
+
113
+ Default directory: `.trails/`. Override with `{ dir: "./custom" }`.
114
+
115
+ - `_surface.json` -- Full surface map, gitignored. For local inspection and debugging.
116
+ - `surface.lock` -- Single-line SHA-256 hash, committed to the repo. Source of truth for drift detection.
117
+
118
+ ## Usage with Warden
119
+
120
+ ```typescript
121
+ import {
122
+ generateSurfaceMap,
123
+ hashSurfaceMap,
124
+ readSurfaceLock,
125
+ } from '@ontrails/schema';
126
+
127
+ const map = generateSurfaceMap(app);
128
+ const current = hashSurfaceMap(map);
129
+ const committed = await readSurfaceLock();
130
+
131
+ if (committed !== current) {
132
+ // surface.lock is stale -- topo has changed
133
+ }
134
+ ```
135
+
136
+ ## Further Reading
137
+
138
+ - [Architecture](../../docs/architecture.md)
139
+ - [Testing Guide](../../docs/testing.md)
package/dist/diff.d.ts ADDED
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Semantic diffing of surface maps.
3
+ */
4
+ import type { DiffResult, SurfaceMap } from './types.js';
5
+ export declare const diffSurfaceMaps: (prev: SurfaceMap, curr: SurfaceMap) => DiffResult;
6
+ //# sourceMappingURL=diff.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"diff.d.ts","sourceRoot":"","sources":["../src/diff.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAEV,UAAU,EAEV,UAAU,EAEX,MAAM,YAAY,CAAC;AA8WpB,eAAO,MAAM,eAAe,GAC1B,MAAM,UAAU,EAChB,MAAM,UAAU,KACf,UAkBF,CAAC"}
package/dist/diff.js ADDED
@@ -0,0 +1,243 @@
1
+ /**
2
+ * Semantic diffing of surface maps.
3
+ */
4
+ const escalate = (acc, severity) => {
5
+ const rank = { breaking: 2, info: 0, warning: 1 };
6
+ if (rank[severity] > rank[acc.severity]) {
7
+ acc.severity = severity;
8
+ }
9
+ };
10
+ const addDetail = (acc, severity, message) => {
11
+ acc.details.push(message);
12
+ escalate(acc, severity);
13
+ };
14
+ // ---------------------------------------------------------------------------
15
+ // Utility
16
+ // ---------------------------------------------------------------------------
17
+ const capitalize = (s) => `${s.charAt(0).toUpperCase()}${s.slice(1)}`;
18
+ const getProperties = (schema) => {
19
+ if (!schema) {
20
+ return {};
21
+ }
22
+ const props = schema.properties;
23
+ return props ? { ...props } : {};
24
+ };
25
+ const getRequired = (schema) => {
26
+ if (!schema) {
27
+ return new Set();
28
+ }
29
+ const req = schema.required;
30
+ return new Set(req);
31
+ };
32
+ const inferSchemaType = (schema) => {
33
+ if (typeof schema['type'] === 'string') {
34
+ return schema['type'];
35
+ }
36
+ if (schema['const'] !== undefined) {
37
+ return `const(${String(schema['const'])})`;
38
+ }
39
+ if (schema['anyOf']) {
40
+ return 'union';
41
+ }
42
+ if (schema['enum']) {
43
+ return 'enum';
44
+ }
45
+ return 'unknown';
46
+ };
47
+ const getType = (schema) => schema ? inferSchemaType(schema) : 'unknown';
48
+ /** Diff a single field that was added. */
49
+ const diffAddedField = (acc, direction, key, currRequired) => {
50
+ if (direction === 'input' && currRequired.has(key)) {
51
+ addDetail(acc, 'breaking', `Required ${direction} field "${key}" added`);
52
+ }
53
+ else {
54
+ const label = direction === 'input' ? `Optional ${direction}` : 'Output';
55
+ addDetail(acc, 'info', `${label} field "${key}" added`);
56
+ }
57
+ };
58
+ /** Diff a single field present in both prev and curr. */
59
+ const diffModifiedField = (acc, direction, key, prevProps, currProps, prevRequired, currRequired) => {
60
+ const prevType = getType(prevProps[key]);
61
+ const currType = getType(currProps[key]);
62
+ if (prevType !== currType) {
63
+ addDetail(acc, 'breaking', `${capitalize(direction)} field "${key}" type changed: ${prevType} -> ${currType}`);
64
+ }
65
+ if (direction === 'input' &&
66
+ !prevRequired.has(key) &&
67
+ currRequired.has(key)) {
68
+ addDetail(acc, 'breaking', `Input field "${key}" changed from optional to required`);
69
+ }
70
+ };
71
+ /** Diff a single key across prev/curr schemas. */
72
+ const diffKey = (acc, direction, key, prevProps, currProps, prevRequired, currRequired) => {
73
+ const inPrev = key in prevProps;
74
+ const inCurr = key in currProps;
75
+ if (!inPrev && inCurr) {
76
+ diffAddedField(acc, direction, key, currRequired);
77
+ }
78
+ else if (inPrev && !inCurr) {
79
+ addDetail(acc, 'breaking', `${capitalize(direction)} field "${key}" removed`);
80
+ }
81
+ else if (inPrev && inCurr) {
82
+ diffModifiedField(acc, direction, key, prevProps, currProps, prevRequired, currRequired);
83
+ }
84
+ };
85
+ const diffSchemaFields = (acc, direction, prev, curr) => {
86
+ const prevProps = getProperties(prev);
87
+ const currProps = getProperties(curr);
88
+ const prevRequired = getRequired(prev);
89
+ const currRequired = getRequired(curr);
90
+ const allKeys = new Set([
91
+ ...Object.keys(prevProps),
92
+ ...Object.keys(currProps),
93
+ ]);
94
+ for (const key of [...allKeys].toSorted()) {
95
+ diffKey(acc, direction, key, prevProps, currProps, prevRequired, currRequired);
96
+ }
97
+ };
98
+ // ---------------------------------------------------------------------------
99
+ // Per-entry diffing
100
+ // ---------------------------------------------------------------------------
101
+ /** Diff surface additions and removals. */
102
+ const diffSurfaces = (acc, prev, curr) => {
103
+ const prevSurfaces = new Set(prev.surfaces);
104
+ const currSurfaces = new Set(curr.surfaces);
105
+ for (const s of [...currSurfaces].toSorted()) {
106
+ if (!prevSurfaces.has(s)) {
107
+ addDetail(acc, 'info', `Surface "${s}" added`);
108
+ }
109
+ }
110
+ for (const s of [...prevSurfaces].toSorted()) {
111
+ if (!currSurfaces.has(s)) {
112
+ addDetail(acc, 'breaking', `Surface "${s}" removed`);
113
+ }
114
+ }
115
+ };
116
+ /** Diff safety markers, description, and deprecation. */
117
+ const diffMetadata = (acc, prev, curr) => {
118
+ for (const marker of ['readOnly', 'destructive', 'idempotent']) {
119
+ if (prev[marker] !== curr[marker]) {
120
+ addDetail(acc, 'warning', `${marker} changed: ${String(prev[marker] ?? false)} -> ${String(curr[marker] ?? false)}`);
121
+ }
122
+ }
123
+ if (prev.description !== curr.description) {
124
+ addDetail(acc, 'info', 'Description updated');
125
+ }
126
+ if (!prev.deprecated && curr.deprecated) {
127
+ const msg = curr.replacedBy
128
+ ? `Deprecated (replaced by ${curr.replacedBy})`
129
+ : 'Deprecated';
130
+ addDetail(acc, 'warning', msg);
131
+ }
132
+ else if (prev.deprecated && !curr.deprecated) {
133
+ addDetail(acc, 'info', 'Undeprecated');
134
+ }
135
+ };
136
+ /** Build a follows-changed description from added/removed arrays. */
137
+ const buildFollowsMessage = (added, removed) => {
138
+ const parts = [];
139
+ if (added.length > 0) {
140
+ parts.push(`added "${added.join('", "')}"`);
141
+ }
142
+ if (removed.length > 0) {
143
+ parts.push(`removed "${removed.join('", "')}"`);
144
+ }
145
+ return `Follows changed: ${parts.join(', ')}`;
146
+ };
147
+ /** Diff follows arrays. */
148
+ const diffFollows = (acc, prev, curr) => {
149
+ const prevFollows = new Set(prev.follows);
150
+ const currFollows = new Set(curr.follows);
151
+ const added = [...currFollows].filter((f) => !prevFollows.has(f)).toSorted();
152
+ const removed = [...prevFollows]
153
+ .filter((f) => !currFollows.has(f))
154
+ .toSorted();
155
+ if (added.length > 0 || removed.length > 0) {
156
+ addDetail(acc, 'warning', buildFollowsMessage(added, removed));
157
+ }
158
+ };
159
+ const diffEntry = (prev, curr) => {
160
+ const acc = { details: [], severity: 'info' };
161
+ diffSchemaFields(acc, 'input', prev.input, curr.input);
162
+ diffSchemaFields(acc, 'output', prev.output, curr.output);
163
+ diffSurfaces(acc, prev, curr);
164
+ diffMetadata(acc, prev, curr);
165
+ diffFollows(acc, prev, curr);
166
+ if (acc.details.length === 0) {
167
+ return undefined;
168
+ }
169
+ return {
170
+ change: 'modified',
171
+ details: acc.details,
172
+ id: curr.id,
173
+ kind: curr.kind,
174
+ severity: acc.severity,
175
+ };
176
+ };
177
+ // ---------------------------------------------------------------------------
178
+ // Public API
179
+ // ---------------------------------------------------------------------------
180
+ /**
181
+ * Compute a semantic diff between two surface maps.
182
+ *
183
+ * Classifies each change with a severity:
184
+ * - `info`: new trail, optional field added, output field added, description change
185
+ * - `warning`: safety marker change, deprecation, follows change
186
+ * - `breaking`: trail removed, required input added, field removed, type change, surface removed
187
+ */
188
+ /** Find entries added in curr that don't exist in prev. */
189
+ const findAdded = (prevById, currById) => [...currById.entries()]
190
+ .filter(([id]) => !prevById.has(id))
191
+ .map(([id, entry]) => ({
192
+ change: 'added',
193
+ details: [`Trail "${id}" added`],
194
+ id,
195
+ kind: entry.kind,
196
+ severity: 'info',
197
+ }));
198
+ /** Find entries removed from prev that don't exist in curr. */
199
+ const findRemoved = (prevById, currById) => [...prevById.entries()]
200
+ .filter(([id]) => !currById.has(id))
201
+ .map(([id, entry]) => ({
202
+ change: 'removed',
203
+ details: [`Trail "${id}" removed`],
204
+ id,
205
+ kind: entry.kind,
206
+ severity: 'breaking',
207
+ }));
208
+ /** Find entries modified between prev and curr. */
209
+ const findModified = (prevById, currById) => {
210
+ const results = [];
211
+ for (const [id, currEntry] of currById) {
212
+ const prevEntry = prevById.get(id);
213
+ if (prevEntry) {
214
+ const diff = diffEntry(prevEntry, currEntry);
215
+ if (diff) {
216
+ results.push(diff);
217
+ }
218
+ }
219
+ }
220
+ return results;
221
+ };
222
+ /** Collect all diff entries (added, removed, modified) between two maps. */
223
+ const collectDiffEntries = (prevById, currById) => [
224
+ ...findAdded(prevById, currById),
225
+ ...findRemoved(prevById, currById),
226
+ ...findModified(prevById, currById),
227
+ ];
228
+ export const diffSurfaceMaps = (prev, curr) => {
229
+ const prevById = new Map(prev.entries.map((e) => [e.id, e]));
230
+ const currById = new Map(curr.entries.map((e) => [e.id, e]));
231
+ const sorted = collectDiffEntries(prevById, currById).toSorted((a, b) => a.id.localeCompare(b.id));
232
+ const breaking = sorted.filter((e) => e.severity === 'breaking');
233
+ const warnings = sorted.filter((e) => e.severity === 'warning');
234
+ const info = sorted.filter((e) => e.severity === 'info');
235
+ return {
236
+ breaking,
237
+ entries: sorted,
238
+ hasBreaking: breaking.length > 0,
239
+ info,
240
+ warnings,
241
+ };
242
+ };
243
+ //# sourceMappingURL=diff.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"diff.js","sourceRoot":"","sources":["../src/diff.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Generate a deterministic surface map from a Topo.
3
+ */
4
+ import type { Topo } from '@ontrails/core';
5
+ import type { SurfaceMap } from './types.js';
6
+ /**
7
+ * Generate a deterministic surface map from a Topo.
8
+ *
9
+ * Entries are sorted alphabetically by id. Object keys within each entry
10
+ * are sorted lexicographically for stable serialization.
11
+ */
12
+ export declare const generateSurfaceMap: (topo: Topo) => SurfaceMap;
13
+ //# sourceMappingURL=generate.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"generate.d.ts","sourceRoot":"","sources":["../src/generate.ts"],"names":[],"mappings":"AAAA;;GAEG;AAGH,OAAO,KAAK,EAAe,IAAI,EAAS,MAAM,gBAAgB,CAAC;AAE/D,OAAO,KAAK,EAAc,UAAU,EAAmB,MAAM,YAAY,CAAC;AAmL1E;;;;;GAKG;AACH,eAAO,MAAM,kBAAkB,GAAI,MAAM,IAAI,KAAG,UA0B/C,CAAC"}
@@ -0,0 +1,171 @@
1
+ /**
2
+ * Generate a deterministic surface map from a Topo.
3
+ */
4
+ import { zodToJsonSchema } from '@ontrails/core';
5
+ // ---------------------------------------------------------------------------
6
+ // Helpers
7
+ // ---------------------------------------------------------------------------
8
+ /** Sort object keys lexicographically (shallow). */
9
+ const sortKeys = (obj) => {
10
+ const sorted = {};
11
+ for (const key of Object.keys(obj).toSorted()) {
12
+ sorted[key] = obj[key];
13
+ }
14
+ return sorted;
15
+ };
16
+ /** Sort object keys recursively for deterministic JSON Schema output. */
17
+ const deepSortKeys = (value) => {
18
+ if (Array.isArray(value)) {
19
+ return value.map(deepSortKeys);
20
+ }
21
+ if (value !== null && typeof value === 'object') {
22
+ const sorted = {};
23
+ for (const key of Object.keys(value).toSorted()) {
24
+ sorted[key] = deepSortKeys(value[key]);
25
+ }
26
+ return sorted;
27
+ }
28
+ return value;
29
+ };
30
+ /** Convert a Zod schema to a deterministically-keyed JSON Schema. */
31
+ const toSortedJsonSchema = (schema) => {
32
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
33
+ const raw = zodToJsonSchema(schema);
34
+ return deepSortKeys(raw);
35
+ };
36
+ // ---------------------------------------------------------------------------
37
+ // Entry builders
38
+ // ---------------------------------------------------------------------------
39
+ /** Extract surfaces from a raw object. */
40
+ const extractSurfaces = (raw) => Array.isArray(raw['surfaces'])
41
+ ? raw['surfaces'].toSorted()
42
+ : [];
43
+ /** Add optional schemas to an entry. */
44
+ const addSchemas = (entry, t) => {
45
+ if (t.input) {
46
+ entry['input'] = toSortedJsonSchema(t.input);
47
+ }
48
+ if (t.output) {
49
+ entry['output'] = toSortedJsonSchema(t.output);
50
+ }
51
+ };
52
+ /** Add safety markers to an entry. */
53
+ const addSafetyMarkers = (entry, t) => {
54
+ if (t.readOnly === true) {
55
+ entry['readOnly'] = true;
56
+ }
57
+ if (t.destructive === true) {
58
+ entry['destructive'] = true;
59
+ }
60
+ if (t.idempotent === true) {
61
+ entry['idempotent'] = true;
62
+ }
63
+ };
64
+ /** Add deprecation and detours to an entry. */
65
+ const addExtendedMetadata = (entry, t, raw) => {
66
+ if (raw['deprecated'] === true) {
67
+ entry['deprecated'] = true;
68
+ }
69
+ if (typeof raw['replacedBy'] === 'string') {
70
+ entry['replacedBy'] = raw['replacedBy'];
71
+ }
72
+ if (t.detours) {
73
+ const detoursSorted = {};
74
+ for (const key of Object.keys(t.detours).toSorted()) {
75
+ detoursSorted[key] = (t.detours[key] ?? []).toSorted();
76
+ }
77
+ entry['detours'] = detoursSorted;
78
+ }
79
+ };
80
+ /** Add optional metadata fields to an entry. */
81
+ const addMetadata = (entry, t, raw) => {
82
+ if (t.description !== undefined) {
83
+ entry['description'] = t.description;
84
+ }
85
+ addSafetyMarkers(entry, t);
86
+ addExtendedMetadata(entry, t, raw);
87
+ };
88
+ const trailToEntry = (t) => {
89
+ const raw = t;
90
+ const entry = {
91
+ exampleCount: Array.isArray(t.examples) ? t.examples.length : 0,
92
+ id: t.id,
93
+ kind: t.kind,
94
+ surfaces: extractSurfaces(raw),
95
+ };
96
+ addSchemas(entry, t);
97
+ addMetadata(entry, t, raw);
98
+ return sortKeys(entry);
99
+ };
100
+ const hikeToEntry = (r) => {
101
+ const base = trailToEntry(r);
102
+ const raw = r;
103
+ const entry = {
104
+ ...base,
105
+ follows: r.follows.toSorted(),
106
+ kind: 'hike',
107
+ };
108
+ // Re-check surfaces on the route itself
109
+ if (Array.isArray(raw['surfaces'])) {
110
+ entry['surfaces'] = raw['surfaces'].toSorted();
111
+ }
112
+ return sortKeys(entry);
113
+ };
114
+ /** Add optional event-specific fields. */
115
+ const addEventFields = (entry, e, raw) => {
116
+ if (e.payload) {
117
+ entry['input'] = toSortedJsonSchema(e.payload);
118
+ }
119
+ if (e.description !== undefined) {
120
+ entry['description'] = e.description;
121
+ }
122
+ if (raw['deprecated'] === true) {
123
+ entry['deprecated'] = true;
124
+ }
125
+ if (typeof raw['replacedBy'] === 'string') {
126
+ entry['replacedBy'] = raw['replacedBy'];
127
+ }
128
+ };
129
+ const eventToEntry = (e) => {
130
+ const raw = e;
131
+ const entry = {
132
+ exampleCount: 0,
133
+ id: e.id,
134
+ kind: 'event',
135
+ surfaces: extractSurfaces(raw),
136
+ };
137
+ addEventFields(entry, e, raw);
138
+ return sortKeys(entry);
139
+ };
140
+ // ---------------------------------------------------------------------------
141
+ // Public API
142
+ // ---------------------------------------------------------------------------
143
+ /**
144
+ * Generate a deterministic surface map from a Topo.
145
+ *
146
+ * Entries are sorted alphabetically by id. Object keys within each entry
147
+ * are sorted lexicographically for stable serialization.
148
+ */
149
+ export const generateSurfaceMap = (topo) => {
150
+ const entries = [];
151
+ // Collect all trails
152
+ for (const t of topo.trails.values()) {
153
+ entries.push(trailToEntry(t));
154
+ }
155
+ // Collect all hikes
156
+ for (const r of topo.hikes.values()) {
157
+ entries.push(hikeToEntry(r));
158
+ }
159
+ // Collect all events
160
+ for (const e of topo.events.values()) {
161
+ entries.push(eventToEntry(e));
162
+ }
163
+ // Sort alphabetically by id
164
+ const sorted = entries.toSorted((a, b) => a.id.localeCompare(b.id));
165
+ return {
166
+ entries: sorted,
167
+ generatedAt: new Date().toISOString(),
168
+ version: '1.0',
169
+ };
170
+ };
171
+ //# sourceMappingURL=generate.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"generate.js","sourceRoot":"","sources":["../src/generate.ts"],"names":[],"mappings":"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"}
package/dist/hash.d.ts ADDED
@@ -0,0 +1,14 @@
1
+ /**
2
+ * SHA-256 hashing for surface maps.
3
+ *
4
+ * Uses Bun.CryptoHasher for native hashing.
5
+ */
6
+ import type { SurfaceMap } from './types.js';
7
+ /**
8
+ * Compute a SHA-256 hash of a surface map.
9
+ *
10
+ * The `generatedAt` field is excluded so that identical topos always
11
+ * produce the same hash regardless of when they were generated.
12
+ */
13
+ export declare const hashSurfaceMap: (surfaceMap: SurfaceMap) => string;
14
+ //# sourceMappingURL=hash.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hash.d.ts","sourceRoot":"","sources":["../src/hash.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AA4B7C;;;;;GAKG;AACH,eAAO,MAAM,cAAc,GAAI,YAAY,UAAU,KAAG,MAUvD,CAAC"}