@ontrails/core 1.0.0-beta.13 → 1.0.0-beta.15
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/.turbo/turbo-lint.log +1 -1
- package/CHANGELOG.md +17 -0
- package/README.md +19 -14
- package/dist/branded.d.ts +1 -1
- package/dist/branded.d.ts.map +1 -1
- package/dist/branded.js +1 -1
- package/dist/branded.js.map +1 -1
- package/dist/context.d.ts +13 -1
- package/dist/context.d.ts.map +1 -1
- package/dist/context.js +19 -3
- package/dist/context.js.map +1 -1
- package/dist/contour.d.ts +81 -0
- package/dist/contour.d.ts.map +1 -0
- package/dist/contour.js +176 -0
- package/dist/contour.js.map +1 -0
- package/dist/cross-schema.d.ts +18 -0
- package/dist/cross-schema.d.ts.map +1 -0
- package/dist/cross-schema.js +29 -0
- package/dist/cross-schema.js.map +1 -0
- package/dist/derive.d.ts +6 -0
- package/dist/derive.d.ts.map +1 -1
- package/dist/derive.js +29 -5
- package/dist/derive.js.map +1 -1
- package/dist/draft.d.ts +28 -0
- package/dist/draft.d.ts.map +1 -0
- package/dist/draft.js +157 -0
- package/dist/draft.js.map +1 -0
- package/dist/errors.d.ts +62 -4
- package/dist/errors.d.ts.map +1 -1
- package/dist/errors.js +44 -1
- package/dist/errors.js.map +1 -1
- package/dist/execute.d.ts +26 -9
- package/dist/execute.d.ts.map +1 -1
- package/dist/execute.js +441 -20
- package/dist/execute.js.map +1 -1
- package/dist/fire.d.ts +43 -0
- package/dist/fire.d.ts.map +1 -0
- package/dist/fire.js +185 -0
- package/dist/fire.js.map +1 -0
- package/dist/index.d.ts +33 -17
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +26 -12
- package/dist/index.js.map +1 -1
- package/dist/internal/cross-batch.d.ts +44 -0
- package/dist/internal/cross-batch.d.ts.map +1 -0
- package/dist/internal/cross-batch.js +58 -0
- package/dist/internal/cross-batch.js.map +1 -0
- package/dist/internal/fork-ctx.d.ts +41 -0
- package/dist/internal/fork-ctx.d.ts.map +1 -0
- package/dist/internal/fork-ctx.js +47 -0
- package/dist/internal/fork-ctx.js.map +1 -0
- package/dist/internal/signal-ref.d.ts +15 -0
- package/dist/internal/signal-ref.d.ts.map +1 -0
- package/dist/internal/signal-ref.js +41 -0
- package/dist/internal/signal-ref.js.map +1 -0
- package/dist/internal/topo-saves.d.ts +53 -0
- package/dist/internal/topo-saves.d.ts.map +1 -0
- package/dist/internal/topo-saves.js +449 -0
- package/dist/internal/topo-saves.js.map +1 -0
- package/dist/internal/topo-snapshots.d.ts +57 -0
- package/dist/internal/topo-snapshots.d.ts.map +1 -0
- package/dist/internal/topo-snapshots.js +372 -0
- package/dist/internal/topo-snapshots.js.map +1 -0
- package/dist/internal/topo-store-read.d.ts +70 -0
- package/dist/internal/topo-store-read.d.ts.map +1 -0
- package/dist/internal/topo-store-read.js +221 -0
- package/dist/internal/topo-store-read.js.map +1 -0
- package/dist/internal/topo-store.d.ts +26 -0
- package/dist/internal/topo-store.d.ts.map +1 -0
- package/dist/internal/topo-store.js +621 -0
- package/dist/internal/topo-store.js.map +1 -0
- package/dist/internal/tracing.d.ts +98 -0
- package/dist/internal/tracing.d.ts.map +1 -0
- package/dist/internal/tracing.js +102 -0
- package/dist/internal/tracing.js.map +1 -0
- package/dist/internal/trails-db.d.ts +16 -0
- package/dist/internal/trails-db.d.ts.map +1 -0
- package/dist/internal/trails-db.js +118 -0
- package/dist/internal/trails-db.js.map +1 -0
- package/dist/internal/zod-wrappers.d.ts +40 -0
- package/dist/internal/zod-wrappers.d.ts.map +1 -0
- package/dist/internal/zod-wrappers.js +59 -0
- package/dist/internal/zod-wrappers.js.map +1 -0
- package/dist/layer.d.ts +22 -5
- package/dist/layer.d.ts.map +1 -1
- package/dist/layer.js +20 -3
- package/dist/layer.js.map +1 -1
- package/dist/path-security.d.ts +1 -1
- package/dist/path-security.d.ts.map +1 -1
- package/dist/path-security.js +1 -1
- package/dist/path-security.js.map +1 -1
- package/dist/resilience.d.ts +1 -1
- package/dist/resilience.d.ts.map +1 -1
- package/dist/resilience.js +3 -3
- package/dist/resilience.js.map +1 -1
- package/dist/resource-config.d.ts +22 -0
- package/dist/resource-config.d.ts.map +1 -0
- package/dist/resource-config.js +210 -0
- package/dist/resource-config.js.map +1 -0
- package/dist/resource.d.ts +74 -0
- package/dist/resource.d.ts.map +1 -0
- package/dist/resource.js +61 -0
- package/dist/resource.js.map +1 -0
- package/dist/run.d.ts +4 -3
- package/dist/run.d.ts.map +1 -1
- package/dist/run.js +5 -4
- package/dist/run.js.map +1 -1
- package/dist/serialization.d.ts.map +1 -1
- package/dist/serialization.js +2 -1
- package/dist/serialization.js.map +1 -1
- package/dist/store/accessor-protocol.d.ts +51 -0
- package/dist/store/accessor-protocol.d.ts.map +1 -0
- package/dist/store/accessor-protocol.js +2 -0
- package/dist/store/accessor-protocol.js.map +1 -0
- package/dist/store/index.d.ts +2 -0
- package/dist/store/index.d.ts.map +1 -0
- package/dist/store/index.js +2 -0
- package/dist/store/index.js.map +1 -0
- package/dist/surface-filter.d.ts +13 -0
- package/dist/surface-filter.d.ts.map +1 -0
- package/dist/surface-filter.js +76 -0
- package/dist/surface-filter.js.map +1 -0
- package/dist/topo-store.d.ts +62 -0
- package/dist/topo-store.d.ts.map +1 -0
- package/dist/topo-store.js +319 -0
- package/dist/topo-store.js.map +1 -0
- package/dist/topo.d.ts +23 -9
- package/dist/topo.d.ts.map +1 -1
- package/dist/topo.js +175 -46
- package/dist/topo.js.map +1 -1
- package/dist/trail.d.ts +86 -19
- package/dist/trail.d.ts.map +1 -1
- package/dist/trail.js +59 -4
- package/dist/trail.js.map +1 -1
- package/dist/trails/derive-trail.d.ts +66 -0
- package/dist/trails/derive-trail.d.ts.map +1 -0
- package/dist/trails/derive-trail.js +378 -0
- package/dist/trails/derive-trail.js.map +1 -0
- package/dist/trails/index.d.ts +5 -0
- package/dist/trails/index.d.ts.map +1 -0
- package/dist/trails/index.js +3 -0
- package/dist/trails/index.js.map +1 -0
- package/dist/trails/ingest.d.ts +24 -0
- package/dist/trails/ingest.d.ts.map +1 -0
- package/dist/trails/ingest.js +63 -0
- package/dist/trails/ingest.js.map +1 -0
- package/dist/transport-error-map.d.ts +106 -0
- package/dist/transport-error-map.d.ts.map +1 -0
- package/dist/transport-error-map.js +24 -0
- package/dist/transport-error-map.js.map +1 -0
- package/dist/type-checks.test-d.d.ts +71 -0
- package/dist/type-checks.test-d.d.ts.map +1 -0
- package/dist/type-checks.test-d.js +12 -0
- package/dist/type-checks.test-d.js.map +1 -0
- package/dist/type-utils.d.ts +11 -2
- package/dist/type-utils.d.ts.map +1 -1
- package/dist/type-utils.js.map +1 -1
- package/dist/types.d.ts +113 -7
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- package/dist/validate-established-topo.d.ts +76 -0
- package/dist/validate-established-topo.d.ts.map +1 -0
- package/dist/validate-established-topo.js +43 -0
- package/dist/validate-established-topo.js.map +1 -0
- package/dist/validate-topo.d.ts.map +1 -1
- package/dist/validate-topo.js +27 -8
- package/dist/validate-topo.js.map +1 -1
- package/dist/workspace.d.ts +1 -1
- package/dist/workspace.d.ts.map +1 -1
- package/dist/workspace.js +1 -1
- package/dist/workspace.js.map +1 -1
- package/package.json +10 -1
- package/src/__tests__/branded.test.ts +5 -5
- package/src/__tests__/context.test.ts +3 -3
- package/src/__tests__/contour.test.ts +263 -0
- package/src/__tests__/derive-trail.test.ts +668 -0
- package/src/__tests__/derive.test.ts +58 -1
- package/src/__tests__/errors.test.ts +118 -0
- package/src/__tests__/execute.test.ts +1179 -141
- package/src/__tests__/fire.test.ts +1056 -0
- package/src/__tests__/fork-ctx.test.ts +83 -0
- package/src/__tests__/ingest.test.ts +191 -0
- package/src/__tests__/{gate.test.ts → layer.test.ts} +21 -21
- package/src/__tests__/path-security.test.ts +7 -7
- package/src/__tests__/resilience.test.ts +8 -8
- package/src/__tests__/resource.test.ts +204 -0
- package/src/__tests__/run.test.ts +13 -13
- package/src/__tests__/service-config.test.ts +28 -32
- package/src/__tests__/surface-filter.test.ts +196 -0
- package/src/__tests__/topo-store-read.test.ts +256 -0
- package/src/__tests__/topo-store.test.ts +869 -0
- package/src/__tests__/topo.test.ts +350 -54
- package/src/__tests__/trail.test.ts +189 -24
- package/src/__tests__/trails-db.test.ts +198 -0
- package/src/__tests__/transport-error-map.test.ts +82 -0
- package/src/__tests__/type-utils.test.ts +29 -1
- package/src/__tests__/validate-topo.test.ts +305 -16
- package/src/__tests__/workspace.test.ts +6 -6
- package/src/__tests__/zod-wrappers.test.ts +62 -0
- package/src/branded.ts +1 -1
- package/src/context.ts +24 -4
- package/src/contour.ts +344 -0
- package/src/cross-schema.ts +36 -0
- package/src/derive.ts +39 -8
- package/src/draft.ts +338 -0
- package/src/errors.ts +62 -18
- package/src/execute.ts +840 -29
- package/src/fire.ts +295 -0
- package/src/index.ts +142 -26
- package/src/internal/cross-batch.ts +77 -0
- package/src/internal/fork-ctx.ts +69 -0
- package/src/internal/signal-ref.ts +87 -0
- package/src/internal/topo-snapshots.ts +517 -0
- package/src/internal/topo-store-read.ts +481 -0
- package/src/internal/topo-store.ts +1192 -0
- package/src/internal/tracing.ts +187 -0
- package/src/internal/trails-db.ts +187 -0
- package/src/internal/zod-wrappers.ts +78 -0
- package/src/layer.ts +50 -0
- package/src/path-security.ts +1 -1
- package/src/resilience.ts +3 -3
- package/src/{provision-config.ts → resource-config.ts} +109 -123
- package/src/resource.ts +155 -0
- package/src/run.ts +5 -4
- package/src/serialization.ts +2 -0
- package/src/store/accessor-protocol.ts +56 -0
- package/src/store/index.ts +4 -0
- package/src/surface-filter.ts +182 -0
- package/src/topo-store.ts +510 -0
- package/src/topo.ts +328 -57
- package/src/trail.ts +199 -31
- package/src/trails/derive-trail.ts +842 -0
- package/src/trails/index.ts +9 -0
- package/src/trails/ingest.ts +146 -0
- package/src/transport-error-map.ts +56 -0
- package/src/type-checks.test-d.ts +106 -0
- package/src/type-utils.ts +17 -2
- package/src/types.ts +148 -11
- package/src/validate-established-topo.ts +63 -0
- package/src/validate-topo.ts +37 -9
- package/src/workspace.ts +1 -1
- package/tsconfig.tests.json +10 -0
- package/tsconfig.tsbuildinfo +1 -1
- package/dist/adapters.d.ts +0 -39
- package/dist/adapters.d.ts.map +0 -1
- package/dist/adapters.js +0 -2
- package/dist/adapters.js.map +0 -1
- package/dist/dispatch.d.ts +0 -27
- package/dist/dispatch.d.ts.map +0 -1
- package/dist/dispatch.js +0 -34
- package/dist/dispatch.js.map +0 -1
- package/dist/event.d.ts +0 -8
- package/dist/event.d.ts.map +0 -1
- package/dist/event.js +0 -7
- package/dist/event.js.map +0 -1
- package/dist/gate.d.ts +0 -17
- package/dist/gate.d.ts.map +0 -1
- package/dist/gate.js +0 -21
- package/dist/gate.js.map +0 -1
- package/dist/health.d.ts +0 -18
- package/dist/health.d.ts.map +0 -1
- package/dist/health.js +0 -5
- package/dist/health.js.map +0 -1
- package/dist/job.d.ts +0 -24
- package/dist/job.d.ts.map +0 -1
- package/dist/job.js +0 -17
- package/dist/job.js.map +0 -1
- package/dist/provision-config.d.ts +0 -22
- package/dist/provision-config.d.ts.map +0 -1
- package/dist/provision-config.js +0 -210
- package/dist/provision-config.js.map +0 -1
- package/dist/provision.d.ts +0 -71
- package/dist/provision.d.ts.map +0 -1
- package/dist/provision.js +0 -56
- package/dist/provision.js.map +0 -1
- package/dist/service-config.d.ts +0 -22
- package/dist/service-config.d.ts.map +0 -1
- package/dist/service-config.js +0 -210
- package/dist/service-config.js.map +0 -1
- package/dist/service.d.ts +0 -71
- package/dist/service.d.ts.map +0 -1
- package/dist/service.js +0 -56
- package/dist/service.js.map +0 -1
- package/src/__tests__/service.test.ts +0 -197
- package/src/event.ts +0 -15
- package/src/gate.ts +0 -44
- package/src/provision.ts +0 -148
|
@@ -0,0 +1,481 @@
|
|
|
1
|
+
import type { Database, SQLQueryBindings } from 'bun:sqlite';
|
|
2
|
+
|
|
3
|
+
import { ValidationError } from '../errors.js';
|
|
4
|
+
import type {
|
|
5
|
+
ListTopoSnapshotsOptions,
|
|
6
|
+
TopoSnapshot,
|
|
7
|
+
} from './topo-snapshots.js';
|
|
8
|
+
import {
|
|
9
|
+
listTopoSnapshots,
|
|
10
|
+
readPinnedTopoSnapshot,
|
|
11
|
+
readTopoSnapshot,
|
|
12
|
+
} from './topo-snapshots.js';
|
|
13
|
+
import type { StoredTopoExport } from './topo-store.js';
|
|
14
|
+
import { getStoredTopoExport } from './topo-store.js';
|
|
15
|
+
|
|
16
|
+
export interface TopoStoreRef {
|
|
17
|
+
readonly pin?: string;
|
|
18
|
+
readonly snapshotId?: string;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export interface TopoStoreTrailRecord {
|
|
22
|
+
readonly description: string | null;
|
|
23
|
+
readonly exampleCount: number;
|
|
24
|
+
readonly hasExamples: boolean;
|
|
25
|
+
readonly hasOutput: boolean;
|
|
26
|
+
readonly id: string;
|
|
27
|
+
readonly idempotent: boolean;
|
|
28
|
+
readonly intent: 'destroy' | 'read' | 'write';
|
|
29
|
+
readonly kind: 'trail';
|
|
30
|
+
readonly meta: Readonly<Record<string, unknown>> | null;
|
|
31
|
+
readonly pattern: string | null;
|
|
32
|
+
readonly safety: '-' | 'destroy' | 'read' | 'write';
|
|
33
|
+
readonly snapshotId: string;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export interface TopoStoreExampleRecord {
|
|
37
|
+
readonly description: string | null;
|
|
38
|
+
readonly error: string | null;
|
|
39
|
+
readonly expected: unknown;
|
|
40
|
+
readonly input: unknown;
|
|
41
|
+
readonly name: string;
|
|
42
|
+
readonly ordinal: number;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export interface TopoStoreTrailDetailRecord extends TopoStoreTrailRecord {
|
|
46
|
+
readonly crosses: readonly string[];
|
|
47
|
+
readonly detours:
|
|
48
|
+
| readonly { readonly on: string; readonly maxAttempts: number }[]
|
|
49
|
+
| null;
|
|
50
|
+
readonly examples: readonly TopoStoreExampleRecord[];
|
|
51
|
+
readonly resources: readonly string[];
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
export interface TopoStoreResourceRecord {
|
|
55
|
+
readonly description: string | null;
|
|
56
|
+
readonly hasHealth: boolean;
|
|
57
|
+
readonly hasMock: boolean;
|
|
58
|
+
readonly health: 'available' | 'none';
|
|
59
|
+
readonly id: string;
|
|
60
|
+
readonly kind: 'resource';
|
|
61
|
+
readonly lifetime: 'singleton';
|
|
62
|
+
readonly snapshotId: string;
|
|
63
|
+
readonly usedBy: readonly string[];
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
export interface TopoStoreExportRecord extends StoredTopoExport {
|
|
67
|
+
readonly snapshot: TopoSnapshot;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
interface TopoTrailRow {
|
|
71
|
+
readonly description: string | null;
|
|
72
|
+
readonly example_count: number;
|
|
73
|
+
readonly has_examples: number;
|
|
74
|
+
readonly has_output: number;
|
|
75
|
+
readonly id: string;
|
|
76
|
+
readonly idempotent: number;
|
|
77
|
+
readonly intent: string | null;
|
|
78
|
+
readonly meta: string | null;
|
|
79
|
+
readonly pattern: string | null;
|
|
80
|
+
readonly snapshot_id: string;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
interface TopoCrossingRow {
|
|
84
|
+
readonly target_id: string;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
interface TopoTrailResourceRow {
|
|
88
|
+
readonly resource_id: string;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
interface TopoExampleRow {
|
|
92
|
+
readonly description: string | null;
|
|
93
|
+
readonly error: string | null;
|
|
94
|
+
readonly expected: string | null;
|
|
95
|
+
readonly input: string;
|
|
96
|
+
readonly name: string;
|
|
97
|
+
readonly ordinal: number;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
interface TopoResourceRow {
|
|
101
|
+
readonly has_health: number;
|
|
102
|
+
readonly has_mock: number;
|
|
103
|
+
readonly id: string;
|
|
104
|
+
readonly snapshot_id: string;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
interface StoredSurfaceMapEntry {
|
|
108
|
+
readonly description?: string;
|
|
109
|
+
readonly detours?: readonly {
|
|
110
|
+
readonly on: string;
|
|
111
|
+
readonly maxAttempts: number;
|
|
112
|
+
}[];
|
|
113
|
+
readonly healthcheck?: boolean;
|
|
114
|
+
readonly id: string;
|
|
115
|
+
readonly kind: 'contour' | 'resource' | 'signal' | 'trail';
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
interface StoredSurfaceMap {
|
|
119
|
+
readonly entries: readonly StoredSurfaceMapEntry[];
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
const ensureSingleRefSelector = (ref?: TopoStoreRef): void => {
|
|
123
|
+
if (ref?.pin !== undefined && ref.snapshotId !== undefined) {
|
|
124
|
+
throw new ValidationError(
|
|
125
|
+
'Topo store references may use pin or snapshotId, not both'
|
|
126
|
+
);
|
|
127
|
+
}
|
|
128
|
+
};
|
|
129
|
+
|
|
130
|
+
const normalizeIntent = (
|
|
131
|
+
intent: string | null
|
|
132
|
+
): TopoStoreTrailRecord['intent'] => {
|
|
133
|
+
if (intent === 'destroy' || intent === 'read') {
|
|
134
|
+
return intent;
|
|
135
|
+
}
|
|
136
|
+
return 'write';
|
|
137
|
+
};
|
|
138
|
+
|
|
139
|
+
const safetyForIntent = (
|
|
140
|
+
intent: TopoStoreTrailRecord['intent']
|
|
141
|
+
): TopoStoreTrailRecord['safety'] => {
|
|
142
|
+
if (intent === 'destroy') {
|
|
143
|
+
return 'destroy';
|
|
144
|
+
}
|
|
145
|
+
if (intent === 'read') {
|
|
146
|
+
return 'read';
|
|
147
|
+
}
|
|
148
|
+
return 'write';
|
|
149
|
+
};
|
|
150
|
+
|
|
151
|
+
const parseMeta = (
|
|
152
|
+
value: string | null
|
|
153
|
+
): Readonly<Record<string, unknown>> | null =>
|
|
154
|
+
value === null
|
|
155
|
+
? null
|
|
156
|
+
: (JSON.parse(value) as Readonly<Record<string, unknown>>);
|
|
157
|
+
|
|
158
|
+
const parseJson = (value: string): unknown => JSON.parse(value) as unknown;
|
|
159
|
+
|
|
160
|
+
const readSnapshotRef = (
|
|
161
|
+
db: Database,
|
|
162
|
+
ref?: TopoStoreRef
|
|
163
|
+
): TopoSnapshot | undefined => {
|
|
164
|
+
ensureSingleRefSelector(ref);
|
|
165
|
+
|
|
166
|
+
if (ref?.snapshotId !== undefined) {
|
|
167
|
+
return readTopoSnapshot(db, ref.snapshotId);
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
if (ref?.pin !== undefined) {
|
|
171
|
+
return readPinnedTopoSnapshot(db, ref.pin);
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
return listTopoSnapshots(db, { limit: 1 })[0];
|
|
175
|
+
};
|
|
176
|
+
|
|
177
|
+
const readStoredEntry = (
|
|
178
|
+
db: Database,
|
|
179
|
+
snapshotId: string,
|
|
180
|
+
kind: StoredSurfaceMapEntry['kind'],
|
|
181
|
+
id: string
|
|
182
|
+
): StoredSurfaceMapEntry | undefined => {
|
|
183
|
+
const stored = getStoredTopoExport(db, snapshotId);
|
|
184
|
+
if (stored === undefined) {
|
|
185
|
+
return undefined;
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
const map = JSON.parse(stored.surfaceMapJson) as StoredSurfaceMap;
|
|
189
|
+
return map.entries.find((entry) => entry.id === id && entry.kind === kind);
|
|
190
|
+
};
|
|
191
|
+
|
|
192
|
+
const mapTrailRow = (row: TopoTrailRow): TopoStoreTrailRecord => {
|
|
193
|
+
const intent = normalizeIntent(row.intent);
|
|
194
|
+
|
|
195
|
+
return {
|
|
196
|
+
description: row.description,
|
|
197
|
+
exampleCount: row.example_count,
|
|
198
|
+
hasExamples: row.has_examples === 1,
|
|
199
|
+
hasOutput: row.has_output === 1,
|
|
200
|
+
id: row.id,
|
|
201
|
+
idempotent: row.idempotent === 1,
|
|
202
|
+
intent,
|
|
203
|
+
kind: 'trail',
|
|
204
|
+
meta: parseMeta(row.meta),
|
|
205
|
+
pattern: row.pattern,
|
|
206
|
+
safety: safetyForIntent(intent),
|
|
207
|
+
snapshotId: row.snapshot_id,
|
|
208
|
+
};
|
|
209
|
+
};
|
|
210
|
+
|
|
211
|
+
const readTrailCrossings = (
|
|
212
|
+
db: Database,
|
|
213
|
+
snapshotId: string,
|
|
214
|
+
trailId: string
|
|
215
|
+
): readonly string[] =>
|
|
216
|
+
db
|
|
217
|
+
.query<TopoCrossingRow, [string, string]>(
|
|
218
|
+
`SELECT target_id
|
|
219
|
+
FROM topo_crossings
|
|
220
|
+
WHERE snapshot_id = ? AND source_id = ?
|
|
221
|
+
ORDER BY target_id ASC`
|
|
222
|
+
)
|
|
223
|
+
.all(snapshotId, trailId)
|
|
224
|
+
.map((row) => row.target_id);
|
|
225
|
+
|
|
226
|
+
const readTrailResourceIds = (
|
|
227
|
+
db: Database,
|
|
228
|
+
snapshotId: string,
|
|
229
|
+
trailId: string
|
|
230
|
+
): readonly string[] =>
|
|
231
|
+
db
|
|
232
|
+
.query<TopoTrailResourceRow, [string, string]>(
|
|
233
|
+
`SELECT resource_id
|
|
234
|
+
FROM topo_trail_resources
|
|
235
|
+
WHERE snapshot_id = ? AND trail_id = ?
|
|
236
|
+
ORDER BY resource_id ASC`
|
|
237
|
+
)
|
|
238
|
+
.all(snapshotId, trailId)
|
|
239
|
+
.map((row) => row.resource_id);
|
|
240
|
+
|
|
241
|
+
const readTrailExamples = (
|
|
242
|
+
db: Database,
|
|
243
|
+
snapshotId: string,
|
|
244
|
+
trailId: string
|
|
245
|
+
): readonly TopoStoreExampleRecord[] =>
|
|
246
|
+
db
|
|
247
|
+
.query<TopoExampleRow, [string, string]>(
|
|
248
|
+
`SELECT ordinal, name, description, input, expected, error
|
|
249
|
+
FROM topo_examples
|
|
250
|
+
WHERE snapshot_id = ? AND trail_id = ?
|
|
251
|
+
ORDER BY ordinal ASC`
|
|
252
|
+
)
|
|
253
|
+
.all(snapshotId, trailId)
|
|
254
|
+
.map((row) => ({
|
|
255
|
+
description: row.description,
|
|
256
|
+
error: row.error,
|
|
257
|
+
expected: row.expected === null ? null : parseJson(row.expected),
|
|
258
|
+
input: parseJson(row.input),
|
|
259
|
+
name: row.name,
|
|
260
|
+
ordinal: row.ordinal,
|
|
261
|
+
}));
|
|
262
|
+
|
|
263
|
+
const readResourceUsage = (
|
|
264
|
+
db: Database,
|
|
265
|
+
snapshotId: string
|
|
266
|
+
): ReadonlyMap<string, readonly string[]> => {
|
|
267
|
+
const rows = db
|
|
268
|
+
.query<{ resource_id: string; trail_id: string }, [string]>(
|
|
269
|
+
`SELECT resource_id, trail_id
|
|
270
|
+
FROM topo_trail_resources
|
|
271
|
+
WHERE snapshot_id = ?
|
|
272
|
+
ORDER BY resource_id ASC, trail_id ASC`
|
|
273
|
+
)
|
|
274
|
+
.all(snapshotId);
|
|
275
|
+
|
|
276
|
+
const usage = new Map<string, string[]>();
|
|
277
|
+
for (const row of rows) {
|
|
278
|
+
const trails = usage.get(row.resource_id) ?? [];
|
|
279
|
+
trails.push(row.trail_id);
|
|
280
|
+
usage.set(row.resource_id, trails);
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
return new Map(
|
|
284
|
+
[...usage.entries()].map(([id, trails]) => [id, trails] as const)
|
|
285
|
+
);
|
|
286
|
+
};
|
|
287
|
+
|
|
288
|
+
export const readTopoStoreSnapshot = (
|
|
289
|
+
db: Database,
|
|
290
|
+
ref?: TopoStoreRef
|
|
291
|
+
): TopoSnapshot | undefined => readSnapshotRef(db, ref);
|
|
292
|
+
|
|
293
|
+
export const listTopoStoreSnapshots = (
|
|
294
|
+
db: Database,
|
|
295
|
+
options?: ListTopoSnapshotsOptions
|
|
296
|
+
): readonly TopoSnapshot[] => listTopoSnapshots(db, options);
|
|
297
|
+
|
|
298
|
+
export const getTopoStoreExport = (
|
|
299
|
+
db: Database,
|
|
300
|
+
ref?: TopoStoreRef
|
|
301
|
+
): TopoStoreExportRecord | undefined => {
|
|
302
|
+
const snapshot = readSnapshotRef(db, ref);
|
|
303
|
+
if (snapshot === undefined) {
|
|
304
|
+
return undefined;
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
const stored = getStoredTopoExport(db, snapshot.id);
|
|
308
|
+
if (stored === undefined) {
|
|
309
|
+
return undefined;
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
return {
|
|
313
|
+
...stored,
|
|
314
|
+
snapshot,
|
|
315
|
+
};
|
|
316
|
+
};
|
|
317
|
+
|
|
318
|
+
export const listTopoStoreTrails = (
|
|
319
|
+
db: Database,
|
|
320
|
+
options?: {
|
|
321
|
+
readonly intent?: TopoStoreTrailRecord['intent'];
|
|
322
|
+
readonly snapshot?: TopoStoreRef;
|
|
323
|
+
}
|
|
324
|
+
): readonly TopoStoreTrailRecord[] => {
|
|
325
|
+
const snapshot = readSnapshotRef(db, options?.snapshot);
|
|
326
|
+
if (snapshot === undefined) {
|
|
327
|
+
return [];
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
const baseQuery = `SELECT id, intent, idempotent, has_output, has_examples, example_count, description, pattern, meta, snapshot_id
|
|
331
|
+
FROM topo_trails`;
|
|
332
|
+
|
|
333
|
+
let rows: TopoTrailRow[];
|
|
334
|
+
if (options?.intent === undefined) {
|
|
335
|
+
rows = db
|
|
336
|
+
.query<TopoTrailRow, [string]>(
|
|
337
|
+
`${baseQuery} WHERE snapshot_id = ? ORDER BY id ASC`
|
|
338
|
+
)
|
|
339
|
+
.all(snapshot.id);
|
|
340
|
+
} else if (options.intent === 'write') {
|
|
341
|
+
rows = db
|
|
342
|
+
.query<TopoTrailRow, [string]>(
|
|
343
|
+
`${baseQuery} WHERE snapshot_id = ? AND intent = 'write' ORDER BY id ASC`
|
|
344
|
+
)
|
|
345
|
+
.all(snapshot.id);
|
|
346
|
+
} else {
|
|
347
|
+
rows = db
|
|
348
|
+
.query<TopoTrailRow, [string, string]>(
|
|
349
|
+
`${baseQuery} WHERE snapshot_id = ? AND intent = ? ORDER BY id ASC`
|
|
350
|
+
)
|
|
351
|
+
.all(snapshot.id, options.intent);
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
return rows.map(mapTrailRow);
|
|
355
|
+
};
|
|
356
|
+
|
|
357
|
+
export const getTopoStoreTrail = (
|
|
358
|
+
db: Database,
|
|
359
|
+
trailId: string,
|
|
360
|
+
options?: { readonly snapshot?: TopoStoreRef }
|
|
361
|
+
): TopoStoreTrailDetailRecord | undefined => {
|
|
362
|
+
const snapshot = readSnapshotRef(db, options?.snapshot);
|
|
363
|
+
if (snapshot === undefined) {
|
|
364
|
+
return undefined;
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
const row = db
|
|
368
|
+
.query<TopoTrailRow, [string, string]>(
|
|
369
|
+
`SELECT id, intent, idempotent, has_output, has_examples, example_count, description, pattern, meta, snapshot_id
|
|
370
|
+
FROM topo_trails
|
|
371
|
+
WHERE snapshot_id = ? AND id = ?
|
|
372
|
+
LIMIT 1`
|
|
373
|
+
)
|
|
374
|
+
.get(snapshot.id, trailId);
|
|
375
|
+
|
|
376
|
+
if (row === null || row === undefined) {
|
|
377
|
+
return undefined;
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
const storedEntry = readStoredEntry(db, snapshot.id, 'trail', trailId);
|
|
381
|
+
|
|
382
|
+
return {
|
|
383
|
+
...mapTrailRow(row),
|
|
384
|
+
crosses: readTrailCrossings(db, snapshot.id, trailId),
|
|
385
|
+
detours: storedEntry?.detours ?? null,
|
|
386
|
+
examples: readTrailExamples(db, snapshot.id, trailId),
|
|
387
|
+
resources: readTrailResourceIds(db, snapshot.id, trailId),
|
|
388
|
+
};
|
|
389
|
+
};
|
|
390
|
+
|
|
391
|
+
const mapResourceRow = (
|
|
392
|
+
row: TopoResourceRow,
|
|
393
|
+
usedBy: readonly string[],
|
|
394
|
+
storedEntry?: StoredSurfaceMapEntry
|
|
395
|
+
): TopoStoreResourceRecord => ({
|
|
396
|
+
description: storedEntry?.description ?? null,
|
|
397
|
+
hasHealth: row.has_health === 1,
|
|
398
|
+
hasMock: row.has_mock === 1,
|
|
399
|
+
health:
|
|
400
|
+
row.has_health === 1 || storedEntry?.healthcheck === true
|
|
401
|
+
? 'available'
|
|
402
|
+
: 'none',
|
|
403
|
+
id: row.id,
|
|
404
|
+
kind: 'resource',
|
|
405
|
+
lifetime: 'singleton',
|
|
406
|
+
snapshotId: row.snapshot_id,
|
|
407
|
+
usedBy,
|
|
408
|
+
});
|
|
409
|
+
|
|
410
|
+
export const listTopoStoreResources = (
|
|
411
|
+
db: Database,
|
|
412
|
+
options?: { readonly snapshot?: TopoStoreRef }
|
|
413
|
+
): readonly TopoStoreResourceRecord[] => {
|
|
414
|
+
const snapshot = readSnapshotRef(db, options?.snapshot);
|
|
415
|
+
if (snapshot === undefined) {
|
|
416
|
+
return [];
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
const usage = readResourceUsage(db, snapshot.id);
|
|
420
|
+
const rows = db
|
|
421
|
+
.query<TopoResourceRow, [string]>(
|
|
422
|
+
`SELECT id, has_mock, has_health, snapshot_id
|
|
423
|
+
FROM topo_resources
|
|
424
|
+
WHERE snapshot_id = ?
|
|
425
|
+
ORDER BY id ASC`
|
|
426
|
+
)
|
|
427
|
+
.all(snapshot.id);
|
|
428
|
+
|
|
429
|
+
const stored = getStoredTopoExport(db, snapshot.id);
|
|
430
|
+
const entries = stored
|
|
431
|
+
? (JSON.parse(stored.surfaceMapJson) as StoredSurfaceMap).entries
|
|
432
|
+
: [];
|
|
433
|
+
|
|
434
|
+
return rows.map((row) =>
|
|
435
|
+
mapResourceRow(
|
|
436
|
+
row,
|
|
437
|
+
usage.get(row.id) ?? [],
|
|
438
|
+
entries.find((entry) => entry.id === row.id && entry.kind === 'resource')
|
|
439
|
+
)
|
|
440
|
+
);
|
|
441
|
+
};
|
|
442
|
+
|
|
443
|
+
export const getTopoStoreResource = (
|
|
444
|
+
db: Database,
|
|
445
|
+
resourceId: string,
|
|
446
|
+
options?: { readonly snapshot?: TopoStoreRef }
|
|
447
|
+
): TopoStoreResourceRecord | undefined => {
|
|
448
|
+
const snapshot = readSnapshotRef(db, options?.snapshot);
|
|
449
|
+
if (snapshot === undefined) {
|
|
450
|
+
return undefined;
|
|
451
|
+
}
|
|
452
|
+
|
|
453
|
+
const row = db
|
|
454
|
+
.query<TopoResourceRow, [string, string]>(
|
|
455
|
+
`SELECT id, has_mock, has_health, snapshot_id
|
|
456
|
+
FROM topo_resources
|
|
457
|
+
WHERE snapshot_id = ? AND id = ?
|
|
458
|
+
LIMIT 1`
|
|
459
|
+
)
|
|
460
|
+
.get(snapshot.id, resourceId);
|
|
461
|
+
|
|
462
|
+
if (row === null || row === undefined) {
|
|
463
|
+
return undefined;
|
|
464
|
+
}
|
|
465
|
+
|
|
466
|
+
const usage = readResourceUsage(db, snapshot.id);
|
|
467
|
+
return mapResourceRow(
|
|
468
|
+
row,
|
|
469
|
+
usage.get(resourceId) ?? [],
|
|
470
|
+
readStoredEntry(db, snapshot.id, 'resource', resourceId)
|
|
471
|
+
);
|
|
472
|
+
};
|
|
473
|
+
|
|
474
|
+
export const queryTopoStore = <TRow extends Record<string, unknown>>(
|
|
475
|
+
db: Database,
|
|
476
|
+
sql: string,
|
|
477
|
+
bindings?: readonly SQLQueryBindings[]
|
|
478
|
+
): readonly TRow[] =>
|
|
479
|
+
db
|
|
480
|
+
.query<TRow, SQLQueryBindings[]>(sql)
|
|
481
|
+
.all(...(bindings === undefined ? [] : [...bindings]));
|