@ontrails/topography 1.0.0-beta.41

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/src/forces.ts ADDED
@@ -0,0 +1,125 @@
1
+ import type {
2
+ DiffEntry,
3
+ TopoGraph,
4
+ TopoGraphEntry,
5
+ TopoGraphForceEntry,
6
+ } from './types.js';
7
+
8
+ export interface TopoGraphForceOptions {
9
+ readonly acceptedAt?: string | undefined;
10
+ readonly reason?: string | undefined;
11
+ }
12
+
13
+ type ForceableDiffEntry = DiffEntry & {
14
+ readonly kind: TopoGraphForceEntry['kind'];
15
+ };
16
+
17
+ const isForceableDiffEntry = (diff: DiffEntry): diff is ForceableDiffEntry =>
18
+ diff.kind !== 'trailhead';
19
+
20
+ const toForceEntry = (
21
+ diff: ForceableDiffEntry,
22
+ detail: string,
23
+ acceptedAt: string,
24
+ reason?: string | undefined
25
+ ): TopoGraphForceEntry => ({
26
+ acceptedAt,
27
+ change: diff.change === 'removed' ? 'removed' : 'modified',
28
+ detail,
29
+ id: diff.id,
30
+ kind: diff.kind,
31
+ ...(reason === undefined ? {} : { reason }),
32
+ severity: 'breaking',
33
+ source: 'trails compile --force',
34
+ });
35
+
36
+ export const deriveTopoGraphForceEntries = (
37
+ diff: DiffEntry,
38
+ options?: TopoGraphForceOptions
39
+ ): readonly TopoGraphForceEntry[] => {
40
+ if (diff.severity !== 'breaking' || !isForceableDiffEntry(diff)) {
41
+ return [];
42
+ }
43
+
44
+ const acceptedAt = options?.acceptedAt ?? new Date().toISOString();
45
+ return diff.details.map((detail) =>
46
+ toForceEntry(diff, detail, acceptedAt, options?.reason)
47
+ );
48
+ };
49
+
50
+ export const annotateTopoGraphForces = (
51
+ graph: TopoGraph,
52
+ breaking: readonly DiffEntry[],
53
+ options?: TopoGraphForceOptions
54
+ ): TopoGraph => {
55
+ if (breaking.length === 0) {
56
+ return graph;
57
+ }
58
+
59
+ const removedForces = breaking
60
+ .filter((entry) => entry.change === 'removed')
61
+ .flatMap((entry) => deriveTopoGraphForceEntries(entry, options));
62
+ const byId = new Map(
63
+ breaking
64
+ .filter((entry) => entry.change !== 'removed')
65
+ .map((entry) => [entry.id, entry])
66
+ );
67
+ const entries: TopoGraphEntry[] = graph.entries.map((entry) => {
68
+ const diff = byId.get(entry.id);
69
+ if (diff === undefined) {
70
+ return entry;
71
+ }
72
+
73
+ const forces = deriveTopoGraphForceEntries(diff, options);
74
+ return forces.length === 0
75
+ ? entry
76
+ : { ...entry, forces: [...(entry.forces ?? []), ...forces] };
77
+ });
78
+
79
+ return {
80
+ ...graph,
81
+ entries,
82
+ ...(removedForces.length === 0
83
+ ? {}
84
+ : { forces: [...(graph.forces ?? []), ...removedForces] }),
85
+ };
86
+ };
87
+
88
+ export const carryForwardTopoGraphForces = (
89
+ previous: TopoGraph,
90
+ next: TopoGraph
91
+ ): TopoGraph => {
92
+ const previousEntryForces = new Map(
93
+ previous.entries
94
+ .filter((entry) => entry.forces !== undefined && entry.forces.length > 0)
95
+ .map((entry) => [entry.id, entry.forces ?? []])
96
+ );
97
+ const entries = next.entries.map((entry) => {
98
+ const carriedForces = previousEntryForces.get(entry.id);
99
+ if (carriedForces === undefined || carriedForces.length === 0) {
100
+ return entry;
101
+ }
102
+ return {
103
+ ...entry,
104
+ forces: [...carriedForces, ...(entry.forces ?? [])],
105
+ };
106
+ });
107
+ return {
108
+ ...next,
109
+ entries,
110
+ ...(previous.forces === undefined || previous.forces.length === 0
111
+ ? {}
112
+ : { forces: [...previous.forces, ...(next.forces ?? [])] }),
113
+ };
114
+ };
115
+
116
+ export const stripTopoGraphForces = (graph: TopoGraph): TopoGraph => {
117
+ const { forces: _graphForces, ...rest } = graph;
118
+ return {
119
+ ...rest,
120
+ entries: graph.entries.map((entry) => {
121
+ const { forces: _entryForces, ...entryRest } = entry;
122
+ return entryRest;
123
+ }),
124
+ };
125
+ };
package/src/hash.ts ADDED
@@ -0,0 +1,55 @@
1
+ /**
2
+ * SHA-256 hashing for topo graphs.
3
+ *
4
+ * Uses Bun.CryptoHasher for native hashing.
5
+ */
6
+
7
+ import type { TopoGraph } from './types.js';
8
+
9
+ // ---------------------------------------------------------------------------
10
+ // Helpers
11
+ // ---------------------------------------------------------------------------
12
+
13
+ /**
14
+ * Recursively sort all object keys for deterministic JSON serialization.
15
+ * Arrays preserve order; primitives pass through.
16
+ */
17
+ const canonicalize = (value: unknown): unknown => {
18
+ if (Array.isArray(value)) {
19
+ return value.map(canonicalize);
20
+ }
21
+ if (value !== null && typeof value === 'object') {
22
+ const sorted: Record<string, unknown> = {};
23
+ for (const key of Object.keys(value).toSorted()) {
24
+ sorted[key] = canonicalize((value as Record<string, unknown>)[key]);
25
+ }
26
+ return sorted;
27
+ }
28
+ return value;
29
+ };
30
+
31
+ // ---------------------------------------------------------------------------
32
+ // Public API
33
+ // ---------------------------------------------------------------------------
34
+
35
+ /**
36
+ * Compute a SHA-256 hash of a topo graph.
37
+ *
38
+ * The `generatedAt` field is excluded so that identical topos always
39
+ * produce the same hash regardless of when they were generated.
40
+ */
41
+ export const deriveStableHash = (value: unknown): string => {
42
+ const canonical = canonicalize(value);
43
+ const json = JSON.stringify(canonical);
44
+
45
+ const hasher = new Bun.CryptoHasher('sha256');
46
+ hasher.update(json);
47
+ return hasher.digest('hex');
48
+ };
49
+
50
+ export const deriveTopoGraphHash = (topoGraph: TopoGraph): string => {
51
+ // Strip generatedAt before hashing
52
+ const { generatedAt: _unused, ...rest } = topoGraph;
53
+
54
+ return deriveStableHash(rest);
55
+ };
package/src/index.ts ADDED
@@ -0,0 +1,272 @@
1
+ // `@ontrails/topography` owns durable graph artifacts derived from the
2
+ // resolved graph (per ADR-0042). Wayfind reads those artifacts through
3
+ // graph-read trails exported from this package.
4
+
5
+ // Derivation
6
+ export { deriveTopoGraph } from './derive.js';
7
+ export {
8
+ deriveActivationGraph,
9
+ deriveDeclaredTrailActivation,
10
+ deriveSignalActivationRelations,
11
+ } from './activation-report.js';
12
+ export type {
13
+ ActivationChainReport,
14
+ ActivationEdgeReport,
15
+ ActivationGraphReport,
16
+ ActivationOverviewReport,
17
+ ActivationSourceReport,
18
+ SignalActivationRelations,
19
+ TrailActivationReport,
20
+ } from './activation-report.js';
21
+ export { deriveTopoGraphHash } from './hash.js';
22
+ export { collectTopoGraphOverlays } from './overlays.js';
23
+ export { deriveSourceFingerprint } from './source-fingerprint.js';
24
+ export { deriveTopoGraphDiff } from './diff.js';
25
+ export {
26
+ annotateTopoGraphForces,
27
+ carryForwardTopoGraphForces,
28
+ deriveTopoGraphForceEntries,
29
+ stripTopoGraphForces,
30
+ } from './forces.js';
31
+ export type { TopoGraphForceOptions } from './forces.js';
32
+ export {
33
+ collectTopoGraphVersionMarkers,
34
+ deriveTopoGraphVersionMarkerRecords,
35
+ resolveTopoGraphVersionReference,
36
+ } from './versioning.js';
37
+ export type {
38
+ TopoGraphVersionMarkerRecord,
39
+ TopoGraphVersionMarkerResolution,
40
+ } from './versioning.js';
41
+
42
+ // File I/O
43
+ export {
44
+ writeTopoGraph,
45
+ readTopoGraph,
46
+ isTopoArtifactRegenerationError,
47
+ writeLockManifest,
48
+ readLockManifest,
49
+ writeTrailsLock,
50
+ readTrailsLock,
51
+ readWorkspaceTopoMetadata,
52
+ readWorkspaceTrailIndex,
53
+ readWorkspaceLock,
54
+ } from './io.js';
55
+ export {
56
+ lockManifestArtifactSchema,
57
+ lockManifestSchema,
58
+ lockManifestSummarySchema,
59
+ LOCK_MANIFEST_SCHEMA_VERSION,
60
+ TOPO_GRAPH_SCHEMA_VERSION,
61
+ TRAILS_LOCK_SCHEMA_VERSION,
62
+ trailsLockSchema,
63
+ topoGraphTrailheadEntrySchema,
64
+ topoGraphLibraryProjectionSchema,
65
+ workspaceTopoMetadataSchema,
66
+ workspaceTrailCollisionSchema,
67
+ workspaceTrailEntrySchema,
68
+ workspaceTrailIndexSchema,
69
+ } from './types.js';
70
+
71
+ // Workspace-wide trail-id index (compose-app resolution for `trails run <id>`).
72
+ export {
73
+ buildWorkspaceTrailIndex,
74
+ defaultLoadTopo,
75
+ isAppManifest,
76
+ isRootManifest,
77
+ readAppManifest,
78
+ readWorkspacesGlobs,
79
+ } from './workspace-topos.js';
80
+ export type {
81
+ AppManifest,
82
+ BuildWorkspaceTrailIndexOptions,
83
+ RootManifest,
84
+ WorkspaceTopoLoader,
85
+ WorkspaceTrailIndexResult,
86
+ } from './workspace-topos.js';
87
+
88
+ // Types
89
+ export type {
90
+ TopoGraph,
91
+ TopoGraphEntry,
92
+ TopoGraphTrailheadEntry,
93
+ TopoGraphForceEntry,
94
+ TopoGraphFieldOverride,
95
+ TopoGraphFieldOverrideKey,
96
+ TopoGraphLibraryCollision,
97
+ TopoGraphLibraryExclusion,
98
+ TopoGraphLibraryExclusionReason,
99
+ TopoGraphLibraryExport,
100
+ TopoGraphLibraryExportSource,
101
+ TopoGraphLibraryProjection,
102
+ TopoGraphLayerReference,
103
+ TopoGraphOverlayRegistration,
104
+ TopoGraphOverlays,
105
+ DeriveTopoGraphOptions,
106
+ TopoGraphVersionDetour,
107
+ TopoGraphVersionEntry,
108
+ LockManifest,
109
+ LockManifestArtifact,
110
+ LockManifestSummary,
111
+ TrailsLock,
112
+ WorkspaceTopoMetadata,
113
+ WorkspaceTrailCollision,
114
+ WorkspaceTrailEntry,
115
+ WorkspaceTrailIndex,
116
+ DiffEntry,
117
+ DiffResult,
118
+ JsonSchema,
119
+ TopoGraphEntityReference,
120
+ TopoGraphActivationEdge,
121
+ TopoGraphActivationEntry,
122
+ TopoGraphActivationSource,
123
+ WriteOptions,
124
+ ReadOptions,
125
+ } from './types.js';
126
+
127
+ // Topo-store public API. Persistence layer for the resolved topo graph; relies
128
+ // on `@ontrails/core` for primitive types and the generic `trails-db` helpers.
129
+ // See ADR-0042 for the core/topography boundary doctrine.
130
+ export {
131
+ createTopoSnapshot,
132
+ createMockTopoStore,
133
+ createTopoStore,
134
+ listTopoSnapshots,
135
+ pinTopoSnapshot,
136
+ topoStore,
137
+ TOPO_STORE_SCHEMA_VERSION,
138
+ unpinTopoSnapshot,
139
+ } from './topo-store.js';
140
+ export type {
141
+ CreateTopoSnapshotInput,
142
+ ListTopoSnapshotsOptions,
143
+ MockTopoStoreSeed,
144
+ ReadOnlyTopoStore,
145
+ TopoSnapshot,
146
+ TopoStoreActivationContextRecord,
147
+ TopoStoreEntityRecord,
148
+ TopoStoreEntryKind,
149
+ TopoStoreExportRecord,
150
+ TopoStoreResourceRecord,
151
+ TopoStoreRef,
152
+ TopoStoreSignalDetailRecord,
153
+ TopoStoreSignalRecord,
154
+ TopoStoreSurfaceProjectionRecord,
155
+ TopoStoreTopoGraphEntryRecord,
156
+ TopoStoreTopoGraphRecord,
157
+ TopoStoreTrailDetailRecord,
158
+ TopoStoreTrailRecord,
159
+ } from './topo-store.js';
160
+
161
+ // Wayfind graph-read APIs. The product, trail IDs, and public type names remain
162
+ // Wayfinder/wayfind even though the package owner is now Topography.
163
+ export { deriveTrailErrorFacts } from './wayfind/error-facts.js';
164
+ export type {
165
+ TrailErrorEvidenceInput,
166
+ TrailErrorFact,
167
+ TrailErrorFactKind,
168
+ TrailErrorFactProvenance,
169
+ TrailErrorFacts,
170
+ TrailErrorFactsCompleteness,
171
+ TrailErrorFactsOptions,
172
+ TrailErrorTaxonomyProjection,
173
+ } from './wayfind/error-facts.js';
174
+ export {
175
+ createWayfinderEntityPredicate,
176
+ createWayfinderFilterContext,
177
+ createWayfinderGraphEntityPredicate,
178
+ filterWayfinderEntityRefs,
179
+ listWayfinderEntityRefs,
180
+ wayfinderEntityFilterSchema,
181
+ wayfinderEntityKindSchema,
182
+ wayfinderIntentSchema,
183
+ } from './wayfind/filters.js';
184
+ export type {
185
+ WayfinderEntityFilterInput,
186
+ WayfinderEntityFilters,
187
+ WayfinderEntityKind,
188
+ WayfinderEntityRef,
189
+ WayfinderFilterContext,
190
+ WayfinderIntent,
191
+ } from './wayfind/filters.js';
192
+ export {
193
+ loadWayfinderArtifacts,
194
+ wayfinderTopoGraphSource,
195
+ wayfinderTopoStoreSource,
196
+ } from './wayfind/loader.js';
197
+ export type {
198
+ WayfinderArtifactLoad,
199
+ WayfinderArtifactLoaderOptions,
200
+ WayfinderTopoStoreLoad,
201
+ } from './wayfind/loader.js';
202
+ export {
203
+ resolveWayfinderPopulation,
204
+ resolveWayfinderRelations,
205
+ wayfinderDriftStatusSchema,
206
+ wayfinderIncludeSchema,
207
+ wayfinderNavigationPlanSchema,
208
+ wayfinderRelationModeSchema,
209
+ wayfinderResolverSchema,
210
+ wayfinderSourceModeSchema,
211
+ wayfinderViewSchema,
212
+ } from './wayfind/navigation.js';
213
+ export type {
214
+ WayfinderDriftStatus,
215
+ WayfinderInclude,
216
+ WayfinderNavigationPlan,
217
+ WayfinderPopulationInput,
218
+ WayfinderRelationMode,
219
+ WayfinderRelationResolver,
220
+ WayfinderResolvedRelationInput,
221
+ WayfinderResolvedRelations,
222
+ WayfinderResolver,
223
+ WayfinderSourceMode,
224
+ WayfinderView,
225
+ } from './wayfind/navigation.js';
226
+ export {
227
+ wayfindAdaptersTrail,
228
+ wayfindContractTrail,
229
+ wayfindDescribeTrail,
230
+ wayfindDiffTrail,
231
+ wayfindEntitiesTrail,
232
+ wayfindErrorsTrail,
233
+ wayfindExamplesTrail,
234
+ wayfindImpactTrail,
235
+ wayfindNearbyTrail,
236
+ wayfindOverlayTrail,
237
+ wayfindOverviewTrail,
238
+ wayfindResourcesTrail,
239
+ wayfindSearchTrail,
240
+ wayfindSignalsTrail,
241
+ wayfindSurfacesTrail,
242
+ wayfindTrailheadsTrail,
243
+ wayfindTrailsTrail,
244
+ wayfindVersionsTrail,
245
+ wayfinderTopo,
246
+ } from './wayfind/queries.js';
247
+ export {
248
+ wayfinderDriftFromArtifactStatus,
249
+ wayfinderDriftFromFreshness,
250
+ wayfinderFact,
251
+ } from './wayfind/provenance.js';
252
+ export type {
253
+ WayfinderArtifactKind,
254
+ WayfinderArtifactSource,
255
+ WayfinderArtifactStatus,
256
+ WayfinderArtifactStatusFresh,
257
+ WayfinderArtifactStatusMissing,
258
+ WayfinderArtifactStatusSchemaVersionDrift,
259
+ WayfinderArtifactStatusStale,
260
+ WayfinderContractRef,
261
+ WayfinderFact,
262
+ WayfinderFactCategory,
263
+ WayfinderFactDrift,
264
+ WayfinderFactDriftStatus,
265
+ WayfinderFactInput,
266
+ WayfinderFreshness,
267
+ WayfinderFreshnessFresh,
268
+ WayfinderFreshnessMissing,
269
+ WayfinderFreshnessSchemaVersionDrift,
270
+ WayfinderFreshnessStale,
271
+ WayfinderStaleReason,
272
+ } from './wayfind/provenance.js';