@gate-forge/pack-playwright 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.
- package/LICENSE +202 -0
- package/bin/gateforge-witness.js +40 -0
- package/dist/attestation/proxy.d.ts +40 -0
- package/dist/attestation/proxy.d.ts.map +1 -0
- package/dist/attestation/proxy.js +78 -0
- package/dist/attestation/proxy.js.map +1 -0
- package/dist/constants.d.ts +130 -0
- package/dist/constants.d.ts.map +1 -0
- package/dist/constants.js +138 -0
- package/dist/constants.js.map +1 -0
- package/dist/discovery/adapters.d.ts +167 -0
- package/dist/discovery/adapters.d.ts.map +1 -0
- package/dist/discovery/adapters.js +276 -0
- package/dist/discovery/adapters.js.map +1 -0
- package/dist/discovery/discover.d.ts +57 -0
- package/dist/discovery/discover.d.ts.map +1 -0
- package/dist/discovery/discover.js +544 -0
- package/dist/discovery/discover.js.map +1 -0
- package/dist/discovery/index.d.ts +15 -0
- package/dist/discovery/index.d.ts.map +1 -0
- package/dist/discovery/index.js +15 -0
- package/dist/discovery/index.js.map +1 -0
- package/dist/discovery/inference.d.ts +63 -0
- package/dist/discovery/inference.d.ts.map +1 -0
- package/dist/discovery/inference.js +173 -0
- package/dist/discovery/inference.js.map +1 -0
- package/dist/discovery/pytest-adapter.d.ts +205 -0
- package/dist/discovery/pytest-adapter.d.ts.map +1 -0
- package/dist/discovery/pytest-adapter.js +548 -0
- package/dist/discovery/pytest-adapter.js.map +1 -0
- package/dist/discovery/reconcile.d.ts +106 -0
- package/dist/discovery/reconcile.d.ts.map +1 -0
- package/dist/discovery/reconcile.js +268 -0
- package/dist/discovery/reconcile.js.map +1 -0
- package/dist/discovery/runner-env.d.ts +80 -0
- package/dist/discovery/runner-env.d.ts.map +1 -0
- package/dist/discovery/runner-env.js +139 -0
- package/dist/discovery/runner-env.js.map +1 -0
- package/dist/discovery/static-discovery.d.ts +121 -0
- package/dist/discovery/static-discovery.d.ts.map +1 -0
- package/dist/discovery/static-discovery.js +1028 -0
- package/dist/discovery/static-discovery.js.map +1 -0
- package/dist/discovery/supervised-run.d.ts +110 -0
- package/dist/discovery/supervised-run.d.ts.map +1 -0
- package/dist/discovery/supervised-run.js +328 -0
- package/dist/discovery/supervised-run.js.map +1 -0
- package/dist/discovery/trusted-config.d.ts +103 -0
- package/dist/discovery/trusted-config.d.ts.map +1 -0
- package/dist/discovery/trusted-config.js +117 -0
- package/dist/discovery/trusted-config.js.map +1 -0
- package/dist/fixture/evidence.d.ts +191 -0
- package/dist/fixture/evidence.d.ts.map +1 -0
- package/dist/fixture/evidence.js +366 -0
- package/dist/fixture/evidence.js.map +1 -0
- package/dist/fixture/fixture.d.ts +37 -0
- package/dist/fixture/fixture.d.ts.map +1 -0
- package/dist/fixture/fixture.js +38 -0
- package/dist/fixture/fixture.js.map +1 -0
- package/dist/fixture/witness-client.d.ts +164 -0
- package/dist/fixture/witness-client.d.ts.map +1 -0
- package/dist/fixture/witness-client.js +253 -0
- package/dist/fixture/witness-client.js.map +1 -0
- package/dist/index.d.ts +64 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +55 -0
- package/dist/index.js.map +1 -0
- package/dist/json.d.ts +16 -0
- package/dist/json.d.ts.map +1 -0
- package/dist/json.js +21 -0
- package/dist/json.js.map +1 -0
- package/dist/reporter/ledger.d.ts +105 -0
- package/dist/reporter/ledger.d.ts.map +1 -0
- package/dist/reporter/ledger.js +197 -0
- package/dist/reporter/ledger.js.map +1 -0
- package/dist/reporter/reporter.cjs +105 -0
- package/dist/reporter/reporter.cjs.map +1 -0
- package/dist/reporter/reporter.d.cts +35 -0
- package/dist/reporter/reporter.d.cts.map +1 -0
- package/dist/reporter/reporter.d.ts +167 -0
- package/dist/reporter/reporter.d.ts.map +1 -0
- package/dist/reporter/reporter.js +673 -0
- package/dist/reporter/reporter.js.map +1 -0
- package/dist/setup.d.ts +49 -0
- package/dist/setup.d.ts.map +1 -0
- package/dist/setup.js +167 -0
- package/dist/setup.js.map +1 -0
- package/dist/supervisor/client.d.ts +73 -0
- package/dist/supervisor/client.d.ts.map +1 -0
- package/dist/supervisor/client.js +164 -0
- package/dist/supervisor/client.js.map +1 -0
- package/dist/supervisor/drain.d.ts +45 -0
- package/dist/supervisor/drain.d.ts.map +1 -0
- package/dist/supervisor/drain.js +235 -0
- package/dist/supervisor/drain.js.map +1 -0
- package/dist/supervisor/index.d.ts +16 -0
- package/dist/supervisor/index.d.ts.map +1 -0
- package/dist/supervisor/index.js +13 -0
- package/dist/supervisor/index.js.map +1 -0
- package/dist/supervisor/spool.d.ts +137 -0
- package/dist/supervisor/spool.d.ts.map +1 -0
- package/dist/supervisor/spool.js +263 -0
- package/dist/supervisor/spool.js.map +1 -0
- package/dist/surface.d.ts +134 -0
- package/dist/surface.d.ts.map +1 -0
- package/dist/surface.js +139 -0
- package/dist/surface.js.map +1 -0
- package/dist/witness/adapter-registry.d.ts +38 -0
- package/dist/witness/adapter-registry.d.ts.map +1 -0
- package/dist/witness/adapter-registry.js +158 -0
- package/dist/witness/adapter-registry.js.map +1 -0
- package/dist/witness/bin.d.ts +21 -0
- package/dist/witness/bin.d.ts.map +1 -0
- package/dist/witness/bin.js +172 -0
- package/dist/witness/bin.js.map +1 -0
- package/dist/witness/browser.d.ts +173 -0
- package/dist/witness/browser.d.ts.map +1 -0
- package/dist/witness/browser.js +580 -0
- package/dist/witness/browser.js.map +1 -0
- package/dist/witness/classifications.d.ts +42 -0
- package/dist/witness/classifications.d.ts.map +1 -0
- package/dist/witness/classifications.js +87 -0
- package/dist/witness/classifications.js.map +1 -0
- package/dist/witness/env-attestation.d.ts +98 -0
- package/dist/witness/env-attestation.d.ts.map +1 -0
- package/dist/witness/env-attestation.js +202 -0
- package/dist/witness/env-attestation.js.map +1 -0
- package/dist/witness/loopback-pins.d.ts +79 -0
- package/dist/witness/loopback-pins.d.ts.map +1 -0
- package/dist/witness/loopback-pins.js +244 -0
- package/dist/witness/loopback-pins.js.map +1 -0
- package/dist/witness/server.d.ts +34 -0
- package/dist/witness/server.d.ts.map +1 -0
- package/dist/witness/server.js +2539 -0
- package/dist/witness/server.js.map +1 -0
- package/dist/witness/types.d.ts +643 -0
- package/dist/witness/types.d.ts.map +1 -0
- package/dist/witness/types.js +2 -0
- package/dist/witness/types.js.map +1 -0
- package/package.json +64 -0
- package/python/gateforge_persistence_intents.py +100 -0
|
@@ -0,0 +1,263 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The runner-side lifecycle SPOOL (enforcement-review fix 3): the
|
|
3
|
+
* untrusted runner child cannot call the witness's supervisor surface,
|
|
4
|
+
* so the gateforge reporter instead writes test lifecycle events
|
|
5
|
+
* (testBegin / testEnd with the observed outcome) as NUL-safe JSON lines
|
|
6
|
+
* into the run-state spool. The TRUSTED CLI drains this spool while the
|
|
7
|
+
* suite runs and performs the witness's supervisor calls (session
|
|
8
|
+
* open/close) with credentials (run token + verifier key) that exist
|
|
9
|
+
* ONLY in the CLI process. The spool file itself carries no secrets —
|
|
10
|
+
* test identities and outcomes only.
|
|
11
|
+
*
|
|
12
|
+
* Protocol: one JSON object per line, canonical JSON (control characters
|
|
13
|
+
* — NUL included — are escaped, so the format is NUL-safe), terminated
|
|
14
|
+
* by '\n'. Consumers only treat a line as complete once its '\n' has
|
|
15
|
+
* been written, which makes partial writes impossible to misparse.
|
|
16
|
+
*/
|
|
17
|
+
import { mkdirSync, openSync, closeSync, writeSync, readFileSync, statSync } from 'node:fs';
|
|
18
|
+
import { join } from 'node:path';
|
|
19
|
+
import { canonicalOf } from '../json.js';
|
|
20
|
+
import { SPOOL_DIR_NAME, SPOOL_EVENTS_FILE, SPOOL_INTENTS_FILE } from '../constants.js';
|
|
21
|
+
/**
|
|
22
|
+
* Resolves the spool events file for one run.
|
|
23
|
+
*
|
|
24
|
+
* Args:
|
|
25
|
+
* stateDir: absolute run-state directory.
|
|
26
|
+
* runId: the run identity both sides agree on (env-carried).
|
|
27
|
+
*
|
|
28
|
+
* Returns:
|
|
29
|
+
* string: absolute `<stateDir>/spool/<runId>/events.jsonl` path.
|
|
30
|
+
*/
|
|
31
|
+
export function spoolPathFor(stateDir, runId) {
|
|
32
|
+
return join(stateDir, SPOOL_DIR_NAME, runId, SPOOL_EVENTS_FILE);
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Appends one lifecycle event to the run's spool (runner-side; the
|
|
36
|
+
* reporter calls this). The event is sanitized: string fields are
|
|
37
|
+
* coerced/validated, unknown statuses ride as strings, and canonical
|
|
38
|
+
* JSON escapes every control character (NUL included) — the line is
|
|
39
|
+
* NUL-safe by construction. A failed append never crashes the run: the
|
|
40
|
+
* CLI drain then simply never opens that session and the witness
|
|
41
|
+
* rejects the suite's submissions fail-closed.
|
|
42
|
+
*
|
|
43
|
+
* Args:
|
|
44
|
+
* spoolFile: absolute spool events file (see {@link spoolPathFor}).
|
|
45
|
+
* event: the lifecycle event to append.
|
|
46
|
+
*/
|
|
47
|
+
export function appendSpoolEvent(spoolFile, event) {
|
|
48
|
+
try {
|
|
49
|
+
const clean = {
|
|
50
|
+
kind: event.kind,
|
|
51
|
+
testId: String(event.testId),
|
|
52
|
+
workerIndex: Number.isInteger(event.workerIndex) && event.workerIndex >= 0 ? event.workerIndex : 0,
|
|
53
|
+
file: typeof event.file === 'string' ? event.file : null,
|
|
54
|
+
titlePath: Array.isArray(event.titlePath) ? event.titlePath.map((part) => String(part)) : [],
|
|
55
|
+
project: typeof event.project === 'string' ? event.project : null,
|
|
56
|
+
...(event.kind === 'testEnd'
|
|
57
|
+
? {
|
|
58
|
+
// Omitted (never null) when the runner reported no string
|
|
59
|
+
// outcome: `undefined` reads as "outcome unknown" end to end,
|
|
60
|
+
// and the drain seals the session WITHOUT an outcome — which
|
|
61
|
+
// the trace grades not-passed.
|
|
62
|
+
...(typeof event.outcome === 'string' ? { outcome: event.outcome } : {}),
|
|
63
|
+
attempt: Number.isInteger(event.attempt) && event.attempt >= 1 ? event.attempt : 1,
|
|
64
|
+
}
|
|
65
|
+
: {}),
|
|
66
|
+
...(Array.isArray(event.claims) && event.claims.length > 0
|
|
67
|
+
? { claims: event.claims.map((claim) => String(claim)) }
|
|
68
|
+
: {}),
|
|
69
|
+
};
|
|
70
|
+
mkdirSync(join(spoolFile, '..'), { recursive: true });
|
|
71
|
+
const line = `${canonicalOf(clean)}\n`;
|
|
72
|
+
const fd = openSync(spoolFile, 'a');
|
|
73
|
+
try {
|
|
74
|
+
writeSync(fd, line, undefined, 'utf8');
|
|
75
|
+
}
|
|
76
|
+
finally {
|
|
77
|
+
closeSync(fd);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
catch (error) {
|
|
81
|
+
console.warn(`[gateforge] cannot append to the lifecycle spool: ${error.message}`);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Reads every COMPLETE spool line past the given byte offset (CLI-side
|
|
86
|
+
* drain). A trailing fragment without its terminating newline is left
|
|
87
|
+
* for the next poll — partial writes are never parsed.
|
|
88
|
+
*
|
|
89
|
+
* Args:
|
|
90
|
+
* spoolFile: absolute spool events file.
|
|
91
|
+
* offset: byte offset to read from (0 = from the start).
|
|
92
|
+
*
|
|
93
|
+
* Returns:
|
|
94
|
+
* {events, nextOffset}: parsed events in file order and the offset to
|
|
95
|
+
* resume from (equal to `offset` when nothing complete was added).
|
|
96
|
+
*/
|
|
97
|
+
export function readSpoolEvents(spoolFile, offset) {
|
|
98
|
+
let size;
|
|
99
|
+
try {
|
|
100
|
+
size = statSync(spoolFile).size;
|
|
101
|
+
}
|
|
102
|
+
catch {
|
|
103
|
+
return { events: [], nextOffset: offset };
|
|
104
|
+
}
|
|
105
|
+
if (size <= offset)
|
|
106
|
+
return { events: [], nextOffset: offset };
|
|
107
|
+
let raw;
|
|
108
|
+
try {
|
|
109
|
+
raw = readFileSync(spoolFile, 'utf8');
|
|
110
|
+
}
|
|
111
|
+
catch {
|
|
112
|
+
return { events: [], nextOffset: offset };
|
|
113
|
+
}
|
|
114
|
+
// Byte offsets are only tracked for complete lines; converting the
|
|
115
|
+
// whole file each poll is bounded by the spool's lifetime size.
|
|
116
|
+
const events = [];
|
|
117
|
+
let consumed = 0;
|
|
118
|
+
const lines = raw.split('\n');
|
|
119
|
+
for (const line of lines) {
|
|
120
|
+
const lineBytes = Buffer.byteLength(line, 'utf8') + 1; // + '\n'
|
|
121
|
+
const start = consumed;
|
|
122
|
+
consumed += lineBytes;
|
|
123
|
+
if (start < offset)
|
|
124
|
+
continue;
|
|
125
|
+
if (line.trim().length === 0)
|
|
126
|
+
continue;
|
|
127
|
+
let parsed;
|
|
128
|
+
try {
|
|
129
|
+
parsed = JSON.parse(line);
|
|
130
|
+
}
|
|
131
|
+
catch {
|
|
132
|
+
continue; // never crash the drain on a corrupt line
|
|
133
|
+
}
|
|
134
|
+
if (typeof parsed !== 'object' || parsed === null)
|
|
135
|
+
continue;
|
|
136
|
+
const row = parsed;
|
|
137
|
+
if (typeof row['kind'] !== 'string' || typeof row['testId'] !== 'string')
|
|
138
|
+
continue;
|
|
139
|
+
events.push(parsed);
|
|
140
|
+
}
|
|
141
|
+
const trailing = lines[lines.length - 1] ?? '';
|
|
142
|
+
const completeBytes = raw.endsWith('\n') ? size : size - Buffer.byteLength(trailing, 'utf8');
|
|
143
|
+
return { events, nextOffset: Math.max(offset, completeBytes) };
|
|
144
|
+
}
|
|
145
|
+
/** Resolves the intents spool file for one run (`<stateDir>/spool/<runId>/persistence-intents.jsonl`). */
|
|
146
|
+
export function persistenceIntentsPathFor(stateDir, runId) {
|
|
147
|
+
return join(stateDir, SPOOL_DIR_NAME, runId, SPOOL_INTENTS_FILE);
|
|
148
|
+
}
|
|
149
|
+
/**
|
|
150
|
+
* Appends one persistence intent to the run's intents spool (test-side
|
|
151
|
+
* helper; the CONTRACT is the JSONL line, this writer only keeps it
|
|
152
|
+
* canonical and NUL-safe). A failed append never crashes the test: the
|
|
153
|
+
* drain then simply never forwards the intent and the claim grades
|
|
154
|
+
* fail-closed without its witnessed record.
|
|
155
|
+
*
|
|
156
|
+
* Args:
|
|
157
|
+
* intentsFile: absolute intents spool file (see {@link persistenceIntentsPathFor}).
|
|
158
|
+
* intent: the claim intent to append.
|
|
159
|
+
*/
|
|
160
|
+
export function appendPersistenceIntent(intentsFile, intent) {
|
|
161
|
+
try {
|
|
162
|
+
const clean = {
|
|
163
|
+
entity: String(intent.entity),
|
|
164
|
+
operation: intent.operation,
|
|
165
|
+
phase: intent.phase,
|
|
166
|
+
intent: intent.intent,
|
|
167
|
+
key: intent.key,
|
|
168
|
+
claimId: String(intent.claimId),
|
|
169
|
+
testId: String(intent.testId),
|
|
170
|
+
sequence: Number.isInteger(intent.sequence) && intent.sequence >= 1 ? intent.sequence : 1,
|
|
171
|
+
};
|
|
172
|
+
mkdirSync(join(intentsFile, '..'), { recursive: true });
|
|
173
|
+
const line = `${canonicalOf(clean)}\n`;
|
|
174
|
+
const fd = openSync(intentsFile, 'a');
|
|
175
|
+
try {
|
|
176
|
+
writeSync(fd, line, undefined, 'utf8');
|
|
177
|
+
}
|
|
178
|
+
finally {
|
|
179
|
+
closeSync(fd);
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
catch (error) {
|
|
183
|
+
console.warn(`[gateforge] cannot append to the persistence-intents spool: ${error.message}`);
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
/** Minimal structural validation for one drained intent line. */
|
|
187
|
+
function isPersistenceIntent(value) {
|
|
188
|
+
if (typeof value !== 'object' || value === null)
|
|
189
|
+
return false;
|
|
190
|
+
const row = value;
|
|
191
|
+
return (typeof row['entity'] === 'string' &&
|
|
192
|
+
(row['operation'] === 'create' ||
|
|
193
|
+
row['operation'] === 'read' ||
|
|
194
|
+
row['operation'] === 'update' ||
|
|
195
|
+
row['operation'] === 'delete') &&
|
|
196
|
+
(row['phase'] === 'pre' || row['phase'] === 'post') &&
|
|
197
|
+
(row['intent'] === 'expect-present' || row['intent'] === 'expect-absent') &&
|
|
198
|
+
(typeof row['key'] === 'string' ||
|
|
199
|
+
typeof row['key'] === 'number' ||
|
|
200
|
+
typeof row['key'] === 'boolean' ||
|
|
201
|
+
(typeof row['key'] === 'object' && row['key'] !== null && !Array.isArray(row['key']))) &&
|
|
202
|
+
typeof row['claimId'] === 'string' &&
|
|
203
|
+
typeof row['testId'] === 'string' &&
|
|
204
|
+
typeof row['sequence'] === 'number' &&
|
|
205
|
+
Number.isInteger(row['sequence']));
|
|
206
|
+
}
|
|
207
|
+
/**
|
|
208
|
+
* Reads every COMPLETE intent line past the given byte offset (CLI-side
|
|
209
|
+
* drain). Trailing fragments without their newline are left for the next
|
|
210
|
+
* poll; structurally invalid lines are skipped (the claim simply never
|
|
211
|
+
* resolves — fail closed, never crash the drain).
|
|
212
|
+
*
|
|
213
|
+
* Args:
|
|
214
|
+
* intentsFile: absolute intents spool file.
|
|
215
|
+
* offset: byte offset to read from (0 = from the start).
|
|
216
|
+
*
|
|
217
|
+
* Returns:
|
|
218
|
+
* {intents, nextOffset}: parsed intents in file order and the offset to
|
|
219
|
+
* resume from.
|
|
220
|
+
*/
|
|
221
|
+
export function readPersistenceIntents(intentsFile, offset) {
|
|
222
|
+
let size;
|
|
223
|
+
try {
|
|
224
|
+
size = statSync(intentsFile).size;
|
|
225
|
+
}
|
|
226
|
+
catch {
|
|
227
|
+
return { intents: [], nextOffset: offset };
|
|
228
|
+
}
|
|
229
|
+
if (size <= offset)
|
|
230
|
+
return { intents: [], nextOffset: offset };
|
|
231
|
+
let raw;
|
|
232
|
+
try {
|
|
233
|
+
raw = readFileSync(intentsFile, 'utf8');
|
|
234
|
+
}
|
|
235
|
+
catch {
|
|
236
|
+
return { intents: [], nextOffset: offset };
|
|
237
|
+
}
|
|
238
|
+
const intents = [];
|
|
239
|
+
let consumed = 0;
|
|
240
|
+
const lines = raw.split('\n');
|
|
241
|
+
for (const line of lines) {
|
|
242
|
+
const lineBytes = Buffer.byteLength(line, 'utf8') + 1; // + '\n'
|
|
243
|
+
const start = consumed;
|
|
244
|
+
consumed += lineBytes;
|
|
245
|
+
if (start < offset)
|
|
246
|
+
continue;
|
|
247
|
+
if (line.trim().length === 0)
|
|
248
|
+
continue;
|
|
249
|
+
let parsed;
|
|
250
|
+
try {
|
|
251
|
+
parsed = JSON.parse(line);
|
|
252
|
+
}
|
|
253
|
+
catch {
|
|
254
|
+
continue; // never crash the drain on a corrupt line
|
|
255
|
+
}
|
|
256
|
+
if (isPersistenceIntent(parsed))
|
|
257
|
+
intents.push(parsed);
|
|
258
|
+
}
|
|
259
|
+
const trailing = lines[lines.length - 1] ?? '';
|
|
260
|
+
const completeBytes = raw.endsWith('\n') ? size : size - Buffer.byteLength(trailing, 'utf8');
|
|
261
|
+
return { intents, nextOffset: Math.max(offset, completeBytes) };
|
|
262
|
+
}
|
|
263
|
+
//# sourceMappingURL=spool.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"spool.js","sourceRoot":"","sources":["../../src/supervisor/spool.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The consumer-declared surface descriptor (plan Phase 1 item 7): the
|
|
3
|
+
* APPLICATION-SPECIFIC half of evidence — how the rendered UI is
|
|
4
|
+
* observed and driven (list page, rows and field cells, form templates,
|
|
5
|
+
* archive control, status values). The pack ships selectors for NO
|
|
6
|
+
* application; the consumer declares its own.
|
|
7
|
+
*
|
|
8
|
+
* OWNERSHIP: the descriptor's selectors are LOCATORS, never proof. The
|
|
9
|
+
* engine-owned browser (witness `browser.ts`) drives the rendered app
|
|
10
|
+
* with them and verifies navigation, the application request, the
|
|
11
|
+
* visible outcome, and persistence itself — a lying descriptor fails
|
|
12
|
+
* closed (elements never match) instead of manufacturing proof.
|
|
13
|
+
*/
|
|
14
|
+
/**
|
|
15
|
+
* The surface-descriptor contract version this pack speaks. Consumers
|
|
16
|
+
* must declare `schemaVersion: SURFACE_DESCRIPTOR_VERSION` in their
|
|
17
|
+
* descriptor; a different version fails closed with a precise error
|
|
18
|
+
* instead of silently misreading selectors.
|
|
19
|
+
*/
|
|
20
|
+
export declare const SURFACE_DESCRIPTOR_VERSION = 1;
|
|
21
|
+
/** How the rendered LIST page is observed (rows and their cells). */
|
|
22
|
+
export interface SurfaceList {
|
|
23
|
+
/** List page path relative to the app base (e.g. `/`). */
|
|
24
|
+
path: string;
|
|
25
|
+
/** Selector proving the list page rendered (e.g. the page heading). */
|
|
26
|
+
readySelector: string;
|
|
27
|
+
/** Selector matching one entity row inside the list. */
|
|
28
|
+
rowSelector: string;
|
|
29
|
+
/** Index of the row cell carrying the entity id (0-based). */
|
|
30
|
+
idCellIndex: number;
|
|
31
|
+
/** Field name → 0-based row-cell index, for reading rendered fields. */
|
|
32
|
+
fieldCellIndexes: Record<string, number>;
|
|
33
|
+
}
|
|
34
|
+
/** How the CREATE form is driven. */
|
|
35
|
+
export interface SurfaceCreate {
|
|
36
|
+
/** Create-form page path relative to the app base. */
|
|
37
|
+
formPath: string;
|
|
38
|
+
/** Selector proving the create form rendered. */
|
|
39
|
+
formReadySelector: string;
|
|
40
|
+
/** Field name → input selector on the create form. */
|
|
41
|
+
fields: Record<string, string>;
|
|
42
|
+
/** Submit control selector on the create form. */
|
|
43
|
+
submitSelector: string;
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* How the EDIT form is reached and driven. `{id}` templates are
|
|
47
|
+
* substituted with the entity id; the edit link is located INSIDE the
|
|
48
|
+
* entity's row.
|
|
49
|
+
*/
|
|
50
|
+
export interface SurfaceEdit {
|
|
51
|
+
/** Row-scoped selector of the control navigating to the edit form. */
|
|
52
|
+
linkSelector: string;
|
|
53
|
+
/** `{id}`-templated selector proving the edit form rendered. */
|
|
54
|
+
formReadySelectorTemplate: string;
|
|
55
|
+
/** Field name → input selector on the edit form. */
|
|
56
|
+
fields: Record<string, string>;
|
|
57
|
+
/** `{id}`-templated page-scoped selector of the edit SAVE control. */
|
|
58
|
+
saveSelectorTemplate: string;
|
|
59
|
+
}
|
|
60
|
+
/** How the archive/delete control is located (row-scoped, `{id}`-templated). */
|
|
61
|
+
export interface SurfaceArchive {
|
|
62
|
+
/** `{id}`-templated row-scoped selector of the archive/delete control. */
|
|
63
|
+
controlSelectorTemplate: string;
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Rendered-status observations the primitives assert after create and
|
|
67
|
+
* archive (fail-closed visible postconditions).
|
|
68
|
+
*/
|
|
69
|
+
export interface SurfaceStatus {
|
|
70
|
+
/** Field name the status renders under (must be a row field). */
|
|
71
|
+
field: string;
|
|
72
|
+
/** Expected rendered value right after a create (e.g. `'active'`). */
|
|
73
|
+
createdValue?: string;
|
|
74
|
+
/** Expected rendered value after archive (e.g. `'archived'`). */
|
|
75
|
+
archivedValue?: string;
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* The declarative, consumer-owned description of the application
|
|
79
|
+
* surface the evidence primitives observe (plan Phase 1 item 7): the
|
|
80
|
+
* pack ships selectors for NO application — the consumer declares its
|
|
81
|
+
* own. Selector/path strings containing `{id}` are substituted with the
|
|
82
|
+
* entity id before use.
|
|
83
|
+
*/
|
|
84
|
+
export interface SurfaceDescriptor {
|
|
85
|
+
/** Must equal {@link SURFACE_DESCRIPTOR_VERSION} (fail-closed otherwise). */
|
|
86
|
+
schemaVersion: number;
|
|
87
|
+
list: SurfaceList;
|
|
88
|
+
create: SurfaceCreate;
|
|
89
|
+
edit: SurfaceEdit;
|
|
90
|
+
archive: SurfaceArchive;
|
|
91
|
+
status: SurfaceStatus;
|
|
92
|
+
/**
|
|
93
|
+
* Where the browser lands after a successful mutation (the rendered
|
|
94
|
+
* result page); `path` is the expected `location.pathname`.
|
|
95
|
+
*/
|
|
96
|
+
afterAction: {
|
|
97
|
+
path: string;
|
|
98
|
+
};
|
|
99
|
+
/**
|
|
100
|
+
* Fields recorded on a delete/archive `ui.action` record (the
|
|
101
|
+
* owner-declared archived state the journey drove, e.g.
|
|
102
|
+
* `{status: 'archived'}`).
|
|
103
|
+
*/
|
|
104
|
+
deleteFields: Record<string, string>;
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* Substitutes `{id}` in a consumer-declared selector/path template with
|
|
108
|
+
* the entity id. Fail closed on ids that could break selector context
|
|
109
|
+
* (quotes/control characters) — a malformed id must error here, not
|
|
110
|
+
* silently match a different element.
|
|
111
|
+
*/
|
|
112
|
+
export declare function renderSurfaceTemplate(template: string, entityId: string): string;
|
|
113
|
+
/**
|
|
114
|
+
* Structural validation of the consumer-declared surface descriptor
|
|
115
|
+
* (fail closed with the EXACT missing piece — a misdeclared surface must
|
|
116
|
+
* never surface later as a confusing selector timeout).
|
|
117
|
+
*
|
|
118
|
+
* Args:
|
|
119
|
+
* surface: the candidate descriptor.
|
|
120
|
+
*
|
|
121
|
+
* Returns:
|
|
122
|
+
* SurfaceDescriptor: the same descriptor, validated.
|
|
123
|
+
*
|
|
124
|
+
* Throws:
|
|
125
|
+
* Error: naming the first structural problem found.
|
|
126
|
+
*/
|
|
127
|
+
export declare function validateSurface(surface: SurfaceDescriptor): SurfaceDescriptor;
|
|
128
|
+
/**
|
|
129
|
+
* Fills descriptor input fields exactly: every declared key must be a
|
|
130
|
+
* selector-known field with a string value (fail closed — the engine
|
|
131
|
+
* never invents form fields the consumer did not declare).
|
|
132
|
+
*/
|
|
133
|
+
export declare function declaredSurfaceFields(where: string, input: Record<string, string>, known: Record<string, string>): Record<string, string>;
|
|
134
|
+
//# sourceMappingURL=surface.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"surface.d.ts","sourceRoot":"","sources":["../src/surface.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH;;;;;GAKG;AACH,eAAO,MAAM,0BAA0B,IAAI,CAAC;AAE5C,qEAAqE;AACrE,MAAM,WAAW,WAAW;IAC1B,0DAA0D;IAC1D,IAAI,EAAE,MAAM,CAAC;IACb,uEAAuE;IACvE,aAAa,EAAE,MAAM,CAAC;IACtB,wDAAwD;IACxD,WAAW,EAAE,MAAM,CAAC;IACpB,8DAA8D;IAC9D,WAAW,EAAE,MAAM,CAAC;IACpB,wEAAwE;IACxE,gBAAgB,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAC1C;AAED,qCAAqC;AACrC,MAAM,WAAW,aAAa;IAC5B,sDAAsD;IACtD,QAAQ,EAAE,MAAM,CAAC;IACjB,iDAAiD;IACjD,iBAAiB,EAAE,MAAM,CAAC;IAC1B,sDAAsD;IACtD,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC/B,kDAAkD;IAClD,cAAc,EAAE,MAAM,CAAC;CACxB;AAED;;;;GAIG;AACH,MAAM,WAAW,WAAW;IAC1B,sEAAsE;IACtE,YAAY,EAAE,MAAM,CAAC;IACrB,gEAAgE;IAChE,yBAAyB,EAAE,MAAM,CAAC;IAClC,oDAAoD;IACpD,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC/B,sEAAsE;IACtE,oBAAoB,EAAE,MAAM,CAAC;CAC9B;AAED,gFAAgF;AAChF,MAAM,WAAW,cAAc;IAC7B,0EAA0E;IAC1E,uBAAuB,EAAE,MAAM,CAAC;CACjC;AAED;;;GAGG;AACH,MAAM,WAAW,aAAa;IAC5B,iEAAiE;IACjE,KAAK,EAAE,MAAM,CAAC;IACd,sEAAsE;IACtE,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,iEAAiE;IACjE,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAED;;;;;;GAMG;AACH,MAAM,WAAW,iBAAiB;IAChC,6EAA6E;IAC7E,aAAa,EAAE,MAAM,CAAC;IACtB,IAAI,EAAE,WAAW,CAAC;IAClB,MAAM,EAAE,aAAa,CAAC;IACtB,IAAI,EAAE,WAAW,CAAC;IAClB,OAAO,EAAE,cAAc,CAAC;IACxB,MAAM,EAAE,aAAa,CAAC;IACtB;;;OAGG;IACH,WAAW,EAAE;QAAE,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC;IAC9B;;;;OAIG;IACH,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACtC;AAED;;;;;GAKG;AACH,wBAAgB,qBAAqB,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAQhF;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,eAAe,CAAC,OAAO,EAAE,iBAAiB,GAAG,iBAAiB,CAuE7E;AAED;;;;GAIG;AACH,wBAAgB,qBAAqB,CACnC,KAAK,EAAE,MAAM,EACb,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EAC7B,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAC5B,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAmBxB"}
|
package/dist/surface.js
ADDED
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The consumer-declared surface descriptor (plan Phase 1 item 7): the
|
|
3
|
+
* APPLICATION-SPECIFIC half of evidence — how the rendered UI is
|
|
4
|
+
* observed and driven (list page, rows and field cells, form templates,
|
|
5
|
+
* archive control, status values). The pack ships selectors for NO
|
|
6
|
+
* application; the consumer declares its own.
|
|
7
|
+
*
|
|
8
|
+
* OWNERSHIP: the descriptor's selectors are LOCATORS, never proof. The
|
|
9
|
+
* engine-owned browser (witness `browser.ts`) drives the rendered app
|
|
10
|
+
* with them and verifies navigation, the application request, the
|
|
11
|
+
* visible outcome, and persistence itself — a lying descriptor fails
|
|
12
|
+
* closed (elements never match) instead of manufacturing proof.
|
|
13
|
+
*/
|
|
14
|
+
/**
|
|
15
|
+
* The surface-descriptor contract version this pack speaks. Consumers
|
|
16
|
+
* must declare `schemaVersion: SURFACE_DESCRIPTOR_VERSION` in their
|
|
17
|
+
* descriptor; a different version fails closed with a precise error
|
|
18
|
+
* instead of silently misreading selectors.
|
|
19
|
+
*/
|
|
20
|
+
export const SURFACE_DESCRIPTOR_VERSION = 1;
|
|
21
|
+
/**
|
|
22
|
+
* Substitutes `{id}` in a consumer-declared selector/path template with
|
|
23
|
+
* the entity id. Fail closed on ids that could break selector context
|
|
24
|
+
* (quotes/control characters) — a malformed id must error here, not
|
|
25
|
+
* silently match a different element.
|
|
26
|
+
*/
|
|
27
|
+
export function renderSurfaceTemplate(template, entityId) {
|
|
28
|
+
if (/['"\r\n\\]/.test(entityId)) {
|
|
29
|
+
throw new Error(`surface template '${template}' cannot be rendered for entity id ${JSON.stringify(entityId)}: ` +
|
|
30
|
+
'ids carrying quotes or control characters are rejected fail-closed');
|
|
31
|
+
}
|
|
32
|
+
return template.replaceAll('{id}', entityId);
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Structural validation of the consumer-declared surface descriptor
|
|
36
|
+
* (fail closed with the EXACT missing piece — a misdeclared surface must
|
|
37
|
+
* never surface later as a confusing selector timeout).
|
|
38
|
+
*
|
|
39
|
+
* Args:
|
|
40
|
+
* surface: the candidate descriptor.
|
|
41
|
+
*
|
|
42
|
+
* Returns:
|
|
43
|
+
* SurfaceDescriptor: the same descriptor, validated.
|
|
44
|
+
*
|
|
45
|
+
* Throws:
|
|
46
|
+
* Error: naming the first structural problem found.
|
|
47
|
+
*/
|
|
48
|
+
export function validateSurface(surface) {
|
|
49
|
+
const requireSelectorMap = (where, map) => {
|
|
50
|
+
if (typeof map !== 'object' || map === null || Array.isArray(map)) {
|
|
51
|
+
throw new Error(`surface.${where} must be a record of field name → selector`);
|
|
52
|
+
}
|
|
53
|
+
for (const [field, selector] of Object.entries(map)) {
|
|
54
|
+
if (typeof selector !== 'string' || selector.length === 0) {
|
|
55
|
+
throw new Error(`surface.${where}.${field} must be a non-empty selector string`);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
};
|
|
59
|
+
const requireIndexMap = (where, map) => {
|
|
60
|
+
if (typeof map !== 'object' || map === null || Array.isArray(map)) {
|
|
61
|
+
throw new Error(`surface.${where} must be a record of field name → cell index`);
|
|
62
|
+
}
|
|
63
|
+
for (const [field, index] of Object.entries(map)) {
|
|
64
|
+
if (!Number.isInteger(index) || index < 0) {
|
|
65
|
+
throw new Error(`surface.${where}.${field} must be a non-negative integer cell index`);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
};
|
|
69
|
+
if (typeof surface !== 'object' || surface === null || Array.isArray(surface)) {
|
|
70
|
+
throw new Error('surface must be a SurfaceDescriptor object declared by the consumer');
|
|
71
|
+
}
|
|
72
|
+
if (surface.schemaVersion !== SURFACE_DESCRIPTOR_VERSION) {
|
|
73
|
+
throw new Error(`surface.schemaVersion ${String(surface.schemaVersion)} is not supported: this pack speaks ` +
|
|
74
|
+
`surface-descriptor version ${String(SURFACE_DESCRIPTOR_VERSION)} — redeclare the surface ` +
|
|
75
|
+
'against the current version');
|
|
76
|
+
}
|
|
77
|
+
for (const section of ['list', 'create', 'edit', 'archive', 'status', 'afterAction']) {
|
|
78
|
+
if (typeof surface[section] !== 'object' || surface[section] === null) {
|
|
79
|
+
throw new Error(`surface.${section} is required by the surface descriptor`);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
for (const key of ['path', 'readySelector', 'rowSelector']) {
|
|
83
|
+
if (typeof surface.list[key] !== 'string' || surface.list[key].length === 0) {
|
|
84
|
+
throw new Error(`surface.list.${key} must be a non-empty string`);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
if (!Number.isInteger(surface.list.idCellIndex) || surface.list.idCellIndex < 0) {
|
|
88
|
+
throw new Error('surface.list.idCellIndex must be a non-negative integer');
|
|
89
|
+
}
|
|
90
|
+
requireIndexMap('list.fieldCellIndexes', surface.list.fieldCellIndexes);
|
|
91
|
+
for (const key of ['formPath', 'formReadySelector', 'submitSelector']) {
|
|
92
|
+
if (typeof surface.create[key] !== 'string' || surface.create[key].length === 0) {
|
|
93
|
+
throw new Error(`surface.create.${key} must be a non-empty string`);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
requireSelectorMap('create.fields', surface.create.fields);
|
|
97
|
+
for (const key of ['linkSelector', 'formReadySelectorTemplate', 'saveSelectorTemplate']) {
|
|
98
|
+
if (typeof surface.edit[key] !== 'string' || surface.edit[key].length === 0) {
|
|
99
|
+
throw new Error(`surface.edit.${key} must be a non-empty string`);
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
requireSelectorMap('edit.fields', surface.edit.fields);
|
|
103
|
+
if (typeof surface.archive.controlSelectorTemplate !== 'string' ||
|
|
104
|
+
surface.archive.controlSelectorTemplate.length === 0) {
|
|
105
|
+
throw new Error('surface.archive.controlSelectorTemplate must be a non-empty string');
|
|
106
|
+
}
|
|
107
|
+
if (typeof surface.status.field !== 'string' || surface.status.field.length === 0) {
|
|
108
|
+
throw new Error('surface.status.field must be a non-empty field name');
|
|
109
|
+
}
|
|
110
|
+
if (typeof surface.afterAction.path !== 'string' || surface.afterAction.path.length === 0) {
|
|
111
|
+
throw new Error('surface.afterAction.path must be a non-empty path string');
|
|
112
|
+
}
|
|
113
|
+
requireSelectorMap('deleteFields', surface.deleteFields);
|
|
114
|
+
return surface;
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* Fills descriptor input fields exactly: every declared key must be a
|
|
118
|
+
* selector-known field with a string value (fail closed — the engine
|
|
119
|
+
* never invents form fields the consumer did not declare).
|
|
120
|
+
*/
|
|
121
|
+
export function declaredSurfaceFields(where, input, known) {
|
|
122
|
+
const entries = Object.entries(input ?? {});
|
|
123
|
+
if (entries.length === 0) {
|
|
124
|
+
throw new Error(`${where} requires at least one input field the journey enters in the UI`);
|
|
125
|
+
}
|
|
126
|
+
const declared = {};
|
|
127
|
+
for (const [field, value] of entries) {
|
|
128
|
+
if (!(field in known)) {
|
|
129
|
+
throw new Error(`${where} declares field '${field}' which the consumer's surface descriptor does not ` +
|
|
130
|
+
`declare a selector for (declared fields: ${Object.keys(known).sort().join(', ')})`);
|
|
131
|
+
}
|
|
132
|
+
if (typeof value !== 'string') {
|
|
133
|
+
throw new Error(`${where}.${field} must be a string (form inputs are text)`);
|
|
134
|
+
}
|
|
135
|
+
declared[field] = value;
|
|
136
|
+
}
|
|
137
|
+
return declared;
|
|
138
|
+
}
|
|
139
|
+
//# sourceMappingURL=surface.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"surface.js","sourceRoot":"","sources":["../src/surface.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import type { AdapterContext, EvidenceAdapter } from './types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Loads every `.mjs` adapter in `dir` into a frozen registry.
|
|
4
|
+
*
|
|
5
|
+
* Args:
|
|
6
|
+
* dir: the configured adapters directory (absolute).
|
|
7
|
+
*
|
|
8
|
+
* Returns:
|
|
9
|
+
* Map<string, EvidenceAdapter>: keyed by the file basename sans `.mjs`.
|
|
10
|
+
*
|
|
11
|
+
* Throws:
|
|
12
|
+
* AdapterRegistryError: fail-closed load problems — unreadable dir,
|
|
13
|
+
* unimportable module, or a module missing any contract member.
|
|
14
|
+
*/
|
|
15
|
+
export declare function loadAdapters(dir: string): Promise<Map<string, EvidenceAdapter>>;
|
|
16
|
+
/**
|
|
17
|
+
* Validates one adapter module against the pin-#8 contract.
|
|
18
|
+
*
|
|
19
|
+
* Args:
|
|
20
|
+
* module: the default export of the adapter file.
|
|
21
|
+
* name: adapter name, used in diagnostics.
|
|
22
|
+
*
|
|
23
|
+
* Returns:
|
|
24
|
+
* EvidenceAdapter: the validated adapter.
|
|
25
|
+
*
|
|
26
|
+
* Throws:
|
|
27
|
+
* AdapterRegistryError: when any required member is missing or shaped
|
|
28
|
+
* wrong. Optional `baseUrl` (a string) overrides the witness's
|
|
29
|
+
* configured adapter base for this adapter.
|
|
30
|
+
*/
|
|
31
|
+
export declare function validateAdapter(module: unknown, name: string): EvidenceAdapter;
|
|
32
|
+
/** Fail-closed adapter-loading error (witness startup aborts). */
|
|
33
|
+
export declare class AdapterRegistryError extends Error {
|
|
34
|
+
constructor(message: string);
|
|
35
|
+
}
|
|
36
|
+
/** The transport the witness hands to adapter `read` calls (GET-only). */
|
|
37
|
+
export declare function makeAdapterContext(baseUrl: string, resourceId: string, get: AdapterContext['get'], headers?: Record<string, string>): AdapterContext;
|
|
38
|
+
//# sourceMappingURL=adapter-registry.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"adapter-registry.d.ts","sourceRoot":"","sources":["../../src/witness/adapter-registry.ts"],"names":[],"mappings":"AA8BA,OAAO,KAAK,EAAE,cAAc,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAElE;;;;;;;;;;;;GAYG;AACH,wBAAsB,YAAY,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,eAAe,CAAC,CAAC,CA6BrF;AAqBD;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,eAAe,CAAC,MAAM,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,GAAG,eAAe,CAkD9E;AAED,kEAAkE;AAClE,qBAAa,oBAAqB,SAAQ,KAAK;gBACjC,OAAO,EAAE,MAAM;CAI5B;AAED,0EAA0E;AAC1E,wBAAgB,kBAAkB,CAChC,OAAO,EAAE,MAAM,EACf,UAAU,EAAE,MAAM,EAClB,GAAG,EAAE,cAAc,CAAC,KAAK,CAAC,EAC1B,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAC/B,cAAc,CAEhB"}
|