@nativemason/contracts 0.0.0-stage → 0.3.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,44 @@
1
+ import { z } from 'zod';
2
+ import { SpatialSnapshotSchema } from './graph.js';
3
+ import { ConstraintResultSchema } from './constraints.js';
4
+ import { CommitReceiptSchema } from './source.js';
5
+ /** Public CI reports exclude physical-target evidence by construction. */
6
+ export const VisualEvidenceRunSchema = z.object({
7
+ id: z.string().regex(/^[A-Za-z0-9_-]+$/), title: z.string(),
8
+ target: z.enum(['web', 'android-emulator', 'ios-simulator']),
9
+ before: SpatialSnapshotSchema, after: SpatialSnapshotSchema,
10
+ results: z.array(ConstraintResultSchema), receipt: CommitReceiptSchema.optional(),
11
+ nativeStatus: z.enum(['passed', 'failed', 'pending', 'unavailable']), notes: z.array(z.string()),
12
+ }).strict().superRefine((run, ctx) => {
13
+ const platform = run.target === 'android-emulator' ? 'android' : run.target === 'ios-simulator' ? 'ios' : 'web';
14
+ for (const snapshot of [run.before, run.after]) {
15
+ if (snapshot.platform !== platform)
16
+ ctx.addIssue({ code: 'custom', message: 'Evidence target and measured platform disagree' });
17
+ if (snapshot.nativeTarget?.kind === 'physical')
18
+ ctx.addIssue({ code: 'custom', message: 'Physical-target evidence is not public report input' });
19
+ if (platform !== 'web' && snapshot.nativeTarget?.kind !== (platform === 'android' ? 'emulator' : 'simulator'))
20
+ ctx.addIssue({ code: 'custom', message: 'Native CI report requires explicit simulator/emulator identity' });
21
+ }
22
+ if (run.before.scenarioId !== run.after.scenarioId)
23
+ ctx.addIssue({ code: 'custom', message: 'Comparison scenarios must match' });
24
+ if (platform !== 'web' && run.before.nativeTarget?.targetId !== run.after.nativeTarget?.targetId)
25
+ ctx.addIssue({ code: 'custom', message: 'Comparison native targets must match' });
26
+ if (run.nativeStatus === 'passed') {
27
+ if (platform === 'web' || run.after.status !== 'stable' || !run.results.length || run.results.some(result => result.status !== 'pass') || run.receipt?.nativeStatus !== 'passed')
28
+ ctx.addIssue({ code: 'custom', message: 'Native pass requires stable native measurements, passing constraints, and a verified receipt' });
29
+ const measuredIds = new Set(run.after.nodes.map(node => node.id));
30
+ if (run.results.some(result => result.elementIds.some(id => !measuredIds.has(id))))
31
+ ctx.addIssue({ code: 'custom', message: 'Passing constraint evidence references an unmeasured element' });
32
+ for (const file of (run.receipt?.files?.length ? run.receipt.files : (run.receipt ? [run.receipt] : [])))
33
+ if (run.after.revisions[file.path] !== file.newHash)
34
+ ctx.addIssue({ code: 'custom', message: 'Native evidence revisions do not match the verified receipt' });
35
+ }
36
+ });
37
+ export const VisualEvidenceReportSchema = z.object({
38
+ schemaVersion: z.literal(1), repository: z.string().regex(/^[A-Za-z0-9_.-]+\/[A-Za-z0-9_.-]+$/),
39
+ revision: z.string().regex(/^[a-f0-9]{40,64}$/), pullRequest: z.number().int().positive().optional(),
40
+ runs: z.array(VisualEvidenceRunSchema).max(20), notes: z.array(z.string()),
41
+ }).strict();
42
+ export const EvidenceInputsSchema = VisualEvidenceReportSchema.pick({ repository: true, revision: true, pullRequest: true }).extend({
43
+ webFile: z.string().min(1).optional(), androidDirectory: z.string().min(1).optional(), iosDirectory: z.string().min(1).optional(),
44
+ }).strict();
@@ -0,0 +1,39 @@
1
+ import { z } from 'zod';
2
+ export declare const RectSchema: z.ZodObject<{
3
+ x: z.ZodNumber;
4
+ y: z.ZodNumber;
5
+ width: z.ZodNumber;
6
+ height: z.ZodNumber;
7
+ }, z.core.$strict>;
8
+ export type Rect = z.infer<typeof RectSchema>;
9
+ export declare const InsetsSchema: z.ZodObject<{
10
+ top: z.ZodNumber;
11
+ right: z.ZodNumber;
12
+ bottom: z.ZodNumber;
13
+ left: z.ZodNumber;
14
+ }, z.core.$strict>;
15
+ export declare const DeviceProfileSchema: z.ZodObject<{
16
+ window: z.ZodObject<{
17
+ width: z.ZodNumber;
18
+ height: z.ZodNumber;
19
+ }, z.core.$strict>;
20
+ pixelRatio: z.ZodNumber;
21
+ fontScale: z.ZodNumber;
22
+ insets: z.ZodObject<{
23
+ top: z.ZodNumber;
24
+ right: z.ZodNumber;
25
+ bottom: z.ZodNumber;
26
+ left: z.ZodNumber;
27
+ }, z.core.$strict>;
28
+ root: z.ZodObject<{
29
+ x: z.ZodNumber;
30
+ y: z.ZodNumber;
31
+ width: z.ZodNumber;
32
+ height: z.ZodNumber;
33
+ }, z.core.$strict>;
34
+ orientation: z.ZodEnum<{
35
+ portrait: "portrait";
36
+ landscape: "landscape";
37
+ }>;
38
+ }, z.core.$strict>;
39
+ export type DeviceProfile = z.infer<typeof DeviceProfileSchema>;
@@ -0,0 +1,4 @@
1
+ import { z } from 'zod';
2
+ export const RectSchema = z.object({ x: z.number().finite(), y: z.number().finite(), width: z.number().finite().nonnegative(), height: z.number().finite().nonnegative() }).strict();
3
+ export const InsetsSchema = z.object({ top: z.number().finite().nonnegative(), right: z.number().finite().nonnegative(), bottom: z.number().finite().nonnegative(), left: z.number().finite().nonnegative() }).strict();
4
+ export const DeviceProfileSchema = z.object({ window: z.object({ width: z.number().finite().positive(), height: z.number().finite().positive() }).strict(), pixelRatio: z.number().finite().positive(), fontScale: z.number().finite().positive(), insets: InsetsSchema, root: RectSchema, orientation: z.enum(['portrait', 'landscape']) }).strict();
@@ -0,0 +1,456 @@
1
+ import { type LayoutMutation } from './workflow.js';
2
+ import { z } from 'zod';
3
+ import { DeviceProfileSchema } from './geometry.js';
4
+ import { SourceRevisionsSchema } from './source.js';
5
+ import { RnStylePatchSchema } from './styles.js';
6
+ export declare const AuthoredTextPropsSchema: z.ZodObject<{
7
+ fontSize: z.ZodOptional<z.ZodNumber>;
8
+ lineHeight: z.ZodOptional<z.ZodNumber>;
9
+ numberOfLines: z.ZodOptional<z.ZodNumber>;
10
+ allowFontScaling: z.ZodOptional<z.ZodBoolean>;
11
+ ellipsizeMode: z.ZodOptional<z.ZodEnum<{
12
+ head: "head";
13
+ middle: "middle";
14
+ tail: "tail";
15
+ clip: "clip";
16
+ }>>;
17
+ }, z.core.$strict>;
18
+ export declare const TextMetricsSchema: z.ZodObject<{
19
+ lineCount: z.ZodNumber;
20
+ }, z.core.$strict>;
21
+ export declare const DiagnosticEvidenceSchema: z.ZodEnum<{
22
+ unknown: "unknown";
23
+ confirmed: "confirmed";
24
+ clear: "clear";
25
+ }>;
26
+ export declare const WebNodeDiagnosticsSchema: z.ZodObject<{
27
+ clipping: z.ZodEnum<{
28
+ unknown: "unknown";
29
+ confirmed: "confirmed";
30
+ clear: "clear";
31
+ }>;
32
+ centerHitTest: z.ZodEnum<{
33
+ unknown: "unknown";
34
+ confirmed: "confirmed";
35
+ clear: "clear";
36
+ }>;
37
+ scrollOverflow: z.ZodObject<{
38
+ horizontal: z.ZodBoolean;
39
+ vertical: z.ZodBoolean;
40
+ }, z.core.$strict>;
41
+ paintOrder: z.ZodNullable<z.ZodNumber>;
42
+ fonts: z.ZodArray<z.ZodObject<{
43
+ family: z.ZodString;
44
+ glyphCount: z.ZodNumber;
45
+ isCustom: z.ZodNullable<z.ZodBoolean>;
46
+ }, z.core.$strict>>;
47
+ lineBoxCount: z.ZodNullable<z.ZodNumber>;
48
+ }, z.core.$strict>;
49
+ export declare const WebDiagnosticsSchema: z.ZodObject<{
50
+ nodes: z.ZodRecord<z.ZodString, z.ZodObject<{
51
+ clipping: z.ZodEnum<{
52
+ unknown: "unknown";
53
+ confirmed: "confirmed";
54
+ clear: "clear";
55
+ }>;
56
+ centerHitTest: z.ZodEnum<{
57
+ unknown: "unknown";
58
+ confirmed: "confirmed";
59
+ clear: "clear";
60
+ }>;
61
+ scrollOverflow: z.ZodObject<{
62
+ horizontal: z.ZodBoolean;
63
+ vertical: z.ZodBoolean;
64
+ }, z.core.$strict>;
65
+ paintOrder: z.ZodNullable<z.ZodNumber>;
66
+ fonts: z.ZodArray<z.ZodObject<{
67
+ family: z.ZodString;
68
+ glyphCount: z.ZodNumber;
69
+ isCustom: z.ZodNullable<z.ZodBoolean>;
70
+ }, z.core.$strict>>;
71
+ lineBoxCount: z.ZodNullable<z.ZodNumber>;
72
+ }, z.core.$strict>>;
73
+ warnings: z.ZodArray<z.ZodObject<{
74
+ elementId: z.ZodString;
75
+ code: z.ZodEnum<{
76
+ CLIPPED: "CLIPPED";
77
+ OCCLUDED: "OCCLUDED";
78
+ FONT_LOAD_FAILED: "FONT_LOAD_FAILED";
79
+ EVIDENCE_UNAVAILABLE: "EVIDENCE_UNAVAILABLE";
80
+ }>;
81
+ severity: z.ZodEnum<{
82
+ confirmed: "confirmed";
83
+ uncertain: "uncertain";
84
+ }>;
85
+ message: z.ZodString;
86
+ }, z.core.$strict>>;
87
+ }, z.core.$strict>;
88
+ export type WebDiagnostics = z.infer<typeof WebDiagnosticsSchema>;
89
+ export declare const SpatialNodeSchema: z.ZodObject<{
90
+ id: z.ZodString;
91
+ parentId: z.ZodNullable<z.ZodString>;
92
+ kind: z.ZodEnum<{
93
+ View: "View";
94
+ Text: "Text";
95
+ Pressable: "Pressable";
96
+ TextInput: "TextInput";
97
+ ScrollView: "ScrollView";
98
+ Image: "Image";
99
+ }>;
100
+ role: z.ZodNullable<z.ZodString>;
101
+ rect: z.ZodObject<{
102
+ x: z.ZodNumber;
103
+ y: z.ZodNumber;
104
+ width: z.ZodNumber;
105
+ height: z.ZodNumber;
106
+ }, z.core.$strict>;
107
+ styles: z.ZodRecord<z.ZodString, z.ZodUnknown>;
108
+ source: z.ZodNullable<z.ZodObject<{
109
+ path: z.ZodString;
110
+ styleForm: z.ZodOptional<z.ZodLiteral<"pressable-state">>;
111
+ dependencies: z.ZodOptional<z.ZodArray<z.ZodString>>;
112
+ hash: z.ZodString;
113
+ start: z.ZodNumber;
114
+ end: z.ZodNumber;
115
+ line: z.ZodNumber;
116
+ column: z.ZodNumber;
117
+ }, z.core.$strict>>;
118
+ editable: z.ZodBoolean;
119
+ editReason: z.ZodNullable<z.ZodString>;
120
+ pressableState: z.ZodOptional<z.ZodEnum<{
121
+ pressed: "pressed";
122
+ rest: "rest";
123
+ }>>;
124
+ accessibility: z.ZodOptional<z.ZodObject<{
125
+ authoredLabel: z.ZodOptional<z.ZodString>;
126
+ authoredHint: z.ZodOptional<z.ZodString>;
127
+ accessible: z.ZodOptional<z.ZodBoolean>;
128
+ focusable: z.ZodOptional<z.ZodBoolean>;
129
+ hidden: z.ZodOptional<z.ZodBoolean>;
130
+ disabled: z.ZodOptional<z.ZodBoolean>;
131
+ direction: z.ZodEnum<{
132
+ unknown: "unknown";
133
+ ltr: "ltr";
134
+ rtl: "rtl";
135
+ }>;
136
+ directionSource: z.ZodOptional<z.ZodEnum<{
137
+ unknown: "unknown";
138
+ authored: "authored";
139
+ "native-global": "native-global";
140
+ "browser-computed": "browser-computed";
141
+ }>>;
142
+ browser: z.ZodOptional<z.ZodObject<{
143
+ name: z.ZodNullable<z.ZodString>;
144
+ focusOrder: z.ZodNullable<z.ZodNumber>;
145
+ focusOrderSource: z.ZodLiteral<"dom-sequential-estimate">;
146
+ contrast: z.ZodObject<{
147
+ status: z.ZodEnum<{
148
+ measured: "measured";
149
+ unavailable: "unavailable";
150
+ }>;
151
+ ratio: z.ZodOptional<z.ZodNumber>;
152
+ requiredRatio: z.ZodOptional<z.ZodNumber>;
153
+ reason: z.ZodOptional<z.ZodString>;
154
+ }, z.core.$strict>;
155
+ }, z.core.$strict>>;
156
+ }, z.core.$strict>>;
157
+ textFit: z.ZodOptional<z.ZodObject<{
158
+ status: z.ZodEnum<{
159
+ unavailable: "unavailable";
160
+ supported: "supported";
161
+ }>;
162
+ fullLineCount: z.ZodOptional<z.ZodNumber>;
163
+ limitedLineCount: z.ZodOptional<z.ZodNumber>;
164
+ fullHeight: z.ZodOptional<z.ZodNumber>;
165
+ availableHeight: z.ZodOptional<z.ZodNumber>;
166
+ reason: z.ZodOptional<z.ZodString>;
167
+ }, z.core.$strict>>;
168
+ authoredTextProps: z.ZodOptional<z.ZodObject<{
169
+ fontSize: z.ZodOptional<z.ZodNumber>;
170
+ lineHeight: z.ZodOptional<z.ZodNumber>;
171
+ numberOfLines: z.ZodOptional<z.ZodNumber>;
172
+ allowFontScaling: z.ZodOptional<z.ZodBoolean>;
173
+ ellipsizeMode: z.ZodOptional<z.ZodEnum<{
174
+ head: "head";
175
+ middle: "middle";
176
+ tail: "tail";
177
+ clip: "clip";
178
+ }>>;
179
+ }, z.core.$strict>>;
180
+ measuredLineCount: z.ZodOptional<z.ZodNumber>;
181
+ }, z.core.$strict>;
182
+ export type SpatialNode = z.infer<typeof SpatialNodeSchema>;
183
+ export declare const SpatialSnapshotSchema: z.ZodObject<{
184
+ schemaVersion: z.ZodLiteral<1>;
185
+ sessionId: z.ZodString;
186
+ snapshotId: z.ZodString;
187
+ platform: z.ZodEnum<{
188
+ web: "web";
189
+ android: "android";
190
+ ios: "ios";
191
+ }>;
192
+ scenarioId: z.ZodString;
193
+ profile: z.ZodObject<{
194
+ window: z.ZodObject<{
195
+ width: z.ZodNumber;
196
+ height: z.ZodNumber;
197
+ }, z.core.$strict>;
198
+ pixelRatio: z.ZodNumber;
199
+ fontScale: z.ZodNumber;
200
+ insets: z.ZodObject<{
201
+ top: z.ZodNumber;
202
+ right: z.ZodNumber;
203
+ bottom: z.ZodNumber;
204
+ left: z.ZodNumber;
205
+ }, z.core.$strict>;
206
+ root: z.ZodObject<{
207
+ x: z.ZodNumber;
208
+ y: z.ZodNumber;
209
+ width: z.ZodNumber;
210
+ height: z.ZodNumber;
211
+ }, z.core.$strict>;
212
+ orientation: z.ZodEnum<{
213
+ portrait: "portrait";
214
+ landscape: "landscape";
215
+ }>;
216
+ }, z.core.$strict>;
217
+ revisions: z.ZodRecord<z.ZodString, z.ZodString>;
218
+ nodes: z.ZodArray<z.ZodObject<{
219
+ id: z.ZodString;
220
+ parentId: z.ZodNullable<z.ZodString>;
221
+ kind: z.ZodEnum<{
222
+ View: "View";
223
+ Text: "Text";
224
+ Pressable: "Pressable";
225
+ TextInput: "TextInput";
226
+ ScrollView: "ScrollView";
227
+ Image: "Image";
228
+ }>;
229
+ role: z.ZodNullable<z.ZodString>;
230
+ rect: z.ZodObject<{
231
+ x: z.ZodNumber;
232
+ y: z.ZodNumber;
233
+ width: z.ZodNumber;
234
+ height: z.ZodNumber;
235
+ }, z.core.$strict>;
236
+ styles: z.ZodRecord<z.ZodString, z.ZodUnknown>;
237
+ source: z.ZodNullable<z.ZodObject<{
238
+ path: z.ZodString;
239
+ styleForm: z.ZodOptional<z.ZodLiteral<"pressable-state">>;
240
+ dependencies: z.ZodOptional<z.ZodArray<z.ZodString>>;
241
+ hash: z.ZodString;
242
+ start: z.ZodNumber;
243
+ end: z.ZodNumber;
244
+ line: z.ZodNumber;
245
+ column: z.ZodNumber;
246
+ }, z.core.$strict>>;
247
+ editable: z.ZodBoolean;
248
+ editReason: z.ZodNullable<z.ZodString>;
249
+ pressableState: z.ZodOptional<z.ZodEnum<{
250
+ pressed: "pressed";
251
+ rest: "rest";
252
+ }>>;
253
+ accessibility: z.ZodOptional<z.ZodObject<{
254
+ authoredLabel: z.ZodOptional<z.ZodString>;
255
+ authoredHint: z.ZodOptional<z.ZodString>;
256
+ accessible: z.ZodOptional<z.ZodBoolean>;
257
+ focusable: z.ZodOptional<z.ZodBoolean>;
258
+ hidden: z.ZodOptional<z.ZodBoolean>;
259
+ disabled: z.ZodOptional<z.ZodBoolean>;
260
+ direction: z.ZodEnum<{
261
+ unknown: "unknown";
262
+ ltr: "ltr";
263
+ rtl: "rtl";
264
+ }>;
265
+ directionSource: z.ZodOptional<z.ZodEnum<{
266
+ unknown: "unknown";
267
+ authored: "authored";
268
+ "native-global": "native-global";
269
+ "browser-computed": "browser-computed";
270
+ }>>;
271
+ browser: z.ZodOptional<z.ZodObject<{
272
+ name: z.ZodNullable<z.ZodString>;
273
+ focusOrder: z.ZodNullable<z.ZodNumber>;
274
+ focusOrderSource: z.ZodLiteral<"dom-sequential-estimate">;
275
+ contrast: z.ZodObject<{
276
+ status: z.ZodEnum<{
277
+ measured: "measured";
278
+ unavailable: "unavailable";
279
+ }>;
280
+ ratio: z.ZodOptional<z.ZodNumber>;
281
+ requiredRatio: z.ZodOptional<z.ZodNumber>;
282
+ reason: z.ZodOptional<z.ZodString>;
283
+ }, z.core.$strict>;
284
+ }, z.core.$strict>>;
285
+ }, z.core.$strict>>;
286
+ textFit: z.ZodOptional<z.ZodObject<{
287
+ status: z.ZodEnum<{
288
+ unavailable: "unavailable";
289
+ supported: "supported";
290
+ }>;
291
+ fullLineCount: z.ZodOptional<z.ZodNumber>;
292
+ limitedLineCount: z.ZodOptional<z.ZodNumber>;
293
+ fullHeight: z.ZodOptional<z.ZodNumber>;
294
+ availableHeight: z.ZodOptional<z.ZodNumber>;
295
+ reason: z.ZodOptional<z.ZodString>;
296
+ }, z.core.$strict>>;
297
+ authoredTextProps: z.ZodOptional<z.ZodObject<{
298
+ fontSize: z.ZodOptional<z.ZodNumber>;
299
+ lineHeight: z.ZodOptional<z.ZodNumber>;
300
+ numberOfLines: z.ZodOptional<z.ZodNumber>;
301
+ allowFontScaling: z.ZodOptional<z.ZodBoolean>;
302
+ ellipsizeMode: z.ZodOptional<z.ZodEnum<{
303
+ head: "head";
304
+ middle: "middle";
305
+ tail: "tail";
306
+ clip: "clip";
307
+ }>>;
308
+ }, z.core.$strict>>;
309
+ measuredLineCount: z.ZodOptional<z.ZodNumber>;
310
+ }, z.core.$strict>>;
311
+ status: z.ZodEnum<{
312
+ stable: "stable";
313
+ unstable: "unstable";
314
+ }>;
315
+ generation: z.ZodNumber;
316
+ nativeTarget: z.ZodOptional<z.ZodObject<{
317
+ targetId: z.ZodString;
318
+ platform: z.ZodEnum<{
319
+ android: "android";
320
+ ios: "ios";
321
+ }>;
322
+ kind: z.ZodEnum<{
323
+ physical: "physical";
324
+ emulator: "emulator";
325
+ simulator: "simulator";
326
+ }>;
327
+ }, z.core.$strict>>;
328
+ webDiagnostics: z.ZodOptional<z.ZodObject<{
329
+ nodes: z.ZodRecord<z.ZodString, z.ZodObject<{
330
+ clipping: z.ZodEnum<{
331
+ unknown: "unknown";
332
+ confirmed: "confirmed";
333
+ clear: "clear";
334
+ }>;
335
+ centerHitTest: z.ZodEnum<{
336
+ unknown: "unknown";
337
+ confirmed: "confirmed";
338
+ clear: "clear";
339
+ }>;
340
+ scrollOverflow: z.ZodObject<{
341
+ horizontal: z.ZodBoolean;
342
+ vertical: z.ZodBoolean;
343
+ }, z.core.$strict>;
344
+ paintOrder: z.ZodNullable<z.ZodNumber>;
345
+ fonts: z.ZodArray<z.ZodObject<{
346
+ family: z.ZodString;
347
+ glyphCount: z.ZodNumber;
348
+ isCustom: z.ZodNullable<z.ZodBoolean>;
349
+ }, z.core.$strict>>;
350
+ lineBoxCount: z.ZodNullable<z.ZodNumber>;
351
+ }, z.core.$strict>>;
352
+ warnings: z.ZodArray<z.ZodObject<{
353
+ elementId: z.ZodString;
354
+ code: z.ZodEnum<{
355
+ CLIPPED: "CLIPPED";
356
+ OCCLUDED: "OCCLUDED";
357
+ FONT_LOAD_FAILED: "FONT_LOAD_FAILED";
358
+ EVIDENCE_UNAVAILABLE: "EVIDENCE_UNAVAILABLE";
359
+ }>;
360
+ severity: z.ZodEnum<{
361
+ confirmed: "confirmed";
362
+ uncertain: "uncertain";
363
+ }>;
364
+ message: z.ZodString;
365
+ }, z.core.$strict>>;
366
+ }, z.core.$strict>>;
367
+ }, z.core.$strict>;
368
+ export type SpatialSnapshot = z.infer<typeof SpatialSnapshotSchema>;
369
+ export declare const SpatialDeltaSchema: z.ZodObject<{
370
+ added: z.ZodArray<z.ZodString>;
371
+ removed: z.ZodArray<z.ZodString>;
372
+ changed: z.ZodArray<z.ZodObject<{
373
+ id: z.ZodString;
374
+ before: z.ZodObject<{
375
+ x: z.ZodNumber;
376
+ y: z.ZodNumber;
377
+ width: z.ZodNumber;
378
+ height: z.ZodNumber;
379
+ }, z.core.$strict>;
380
+ after: z.ZodObject<{
381
+ x: z.ZodNumber;
382
+ y: z.ZodNumber;
383
+ width: z.ZodNumber;
384
+ height: z.ZodNumber;
385
+ }, z.core.$strict>;
386
+ delta: z.ZodObject<{
387
+ x: z.ZodNumber;
388
+ y: z.ZodNumber;
389
+ width: z.ZodNumber;
390
+ height: z.ZodNumber;
391
+ }, z.core.$strict>;
392
+ }, z.core.$strip>>;
393
+ }, z.core.$strip>;
394
+ export type SpatialDelta = z.infer<typeof SpatialDeltaSchema>;
395
+ export interface BrowserPort {
396
+ captureAccessibility?(): Promise<SpatialSnapshot>;
397
+ runScenario?(script: import('./workflow.js').ScenarioScript): Promise<void>;
398
+ trialBatch?(mutations: readonly LayoutMutation[], profileOverrides?: z.infer<typeof ProfileOverridesSchema>): Promise<SpatialSnapshot>;
399
+ capture(profileOverrides?: z.infer<typeof ProfileOverridesSchema>): Promise<SpatialSnapshot>;
400
+ trial(elementId: string, patch: z.infer<typeof RnStylePatchSchema>, profileOverrides?: z.infer<typeof ProfileOverridesSchema>): Promise<SpatialSnapshot>;
401
+ resetTrial(): Promise<void>;
402
+ screenshot(): Promise<Uint8Array>;
403
+ close(): Promise<void>;
404
+ }
405
+ export interface NativePort {
406
+ runHook?(name: string, value?: unknown): Promise<void>;
407
+ capture(expectedRevisions: z.infer<typeof SourceRevisionsSchema>): Promise<SpatialSnapshot>;
408
+ }
409
+ export declare const OverlaySceneSchema: z.ZodObject<{
410
+ width: z.ZodNumber;
411
+ height: z.ZodNumber;
412
+ marks: z.ZodArray<z.ZodObject<{
413
+ label: z.ZodNumber;
414
+ id: z.ZodString;
415
+ rect: z.ZodObject<{
416
+ x: z.ZodNumber;
417
+ y: z.ZodNumber;
418
+ width: z.ZodNumber;
419
+ height: z.ZodNumber;
420
+ }, z.core.$strict>;
421
+ }, z.core.$strip>>;
422
+ targets: z.ZodArray<z.ZodObject<{
423
+ id: z.ZodString;
424
+ rect: z.ZodObject<{
425
+ x: z.ZodNumber;
426
+ y: z.ZodNumber;
427
+ width: z.ZodNumber;
428
+ height: z.ZodNumber;
429
+ }, z.core.$strict>;
430
+ }, z.core.$strip>>;
431
+ }, z.core.$strip>;
432
+ export type OverlayScene = z.infer<typeof OverlaySceneSchema>;
433
+ export declare const ProfileOverridesSchema: z.ZodObject<{
434
+ fontScale: z.ZodOptional<z.ZodNumber>;
435
+ orientation: z.ZodOptional<z.ZodEnum<{
436
+ portrait: "portrait";
437
+ landscape: "landscape";
438
+ }>>;
439
+ }, z.core.$strict>;
440
+ export type ProfileOverrides = z.infer<typeof ProfileOverridesSchema>;
441
+ export interface BrowserRuntime {
442
+ runHook?(name: string, value?: unknown): Promise<void>;
443
+ applyTrialBatch?(mutations: readonly LayoutMutation[]): Promise<void>;
444
+ configure(input: {
445
+ sessionId: string;
446
+ scenarioId: string;
447
+ profile: z.infer<typeof DeviceProfileSchema>;
448
+ }): void;
449
+ capture(): Promise<SpatialSnapshot>;
450
+ applyTrial(id: string, patch: z.infer<typeof RnStylePatchSchema>): Promise<void>;
451
+ resetTrial(): Promise<void>;
452
+ getDiagnosticTargets(): readonly {
453
+ id: string;
454
+ element: unknown;
455
+ }[];
456
+ }
package/dist/graph.js ADDED
@@ -0,0 +1,36 @@
1
+ import { AccessibilityEvidenceSchema } from './accessibility.js';
2
+ import { TextFitEvidenceSchema, NativeTargetSchema } from './workflow.js';
3
+ import { z } from 'zod';
4
+ import { DeviceProfileSchema, RectSchema } from './geometry.js';
5
+ import { SourceRefSchema, SourceRevisionsSchema } from './source.js';
6
+ export const AuthoredTextPropsSchema = z.object({ fontSize: z.number().nonnegative().optional(), lineHeight: z.number().nonnegative().optional(), numberOfLines: z.number().int().positive().optional(), allowFontScaling: z.boolean().optional(), ellipsizeMode: z.enum(['head', 'middle', 'tail', 'clip']).optional() }).strict();
7
+ export const TextMetricsSchema = z.object({ lineCount: z.number().int().nonnegative() }).strict();
8
+ export const DiagnosticEvidenceSchema = z.enum(['confirmed', 'clear', 'unknown']);
9
+ export const WebNodeDiagnosticsSchema = z.object({
10
+ clipping: DiagnosticEvidenceSchema,
11
+ centerHitTest: DiagnosticEvidenceSchema,
12
+ scrollOverflow: z.object({ horizontal: z.boolean(), vertical: z.boolean() }).strict(),
13
+ paintOrder: z.number().int().nullable(),
14
+ fonts: z.array(z.object({ family: z.string(), glyphCount: z.number().int().nonnegative(), isCustom: z.boolean().nullable() }).strict()),
15
+ lineBoxCount: z.number().int().nonnegative().nullable(),
16
+ }).strict();
17
+ export const WebDiagnosticsSchema = z.object({ nodes: z.record(z.string(), WebNodeDiagnosticsSchema), warnings: z.array(z.object({ elementId: z.string(), code: z.enum(['CLIPPED', 'OCCLUDED', 'FONT_LOAD_FAILED', 'EVIDENCE_UNAVAILABLE']), severity: z.enum(['confirmed', 'uncertain']), message: z.string() }).strict()) }).strict();
18
+ export const SpatialNodeSchema = z.object({ id: z.string().min(1), parentId: z.string().nullable(), kind: z.enum(['View', 'Text', 'Pressable', 'TextInput', 'ScrollView', 'Image']), role: z.string().nullable(), rect: RectSchema, styles: z.record(z.string(), z.unknown()), source: SourceRefSchema.nullable(), editable: z.boolean(), editReason: z.string().nullable(), pressableState: z.enum(['pressed', 'rest']).optional(), accessibility: AccessibilityEvidenceSchema.optional(), textFit: TextFitEvidenceSchema.optional(), authoredTextProps: AuthoredTextPropsSchema.optional(), measuredLineCount: z.number().int().nonnegative().optional() }).strict();
19
+ export const SpatialSnapshotSchema = z.object({ schemaVersion: z.literal(1), sessionId: z.string(), snapshotId: z.string(), platform: z.enum(['web', 'android', 'ios']), scenarioId: z.string(), profile: DeviceProfileSchema, revisions: SourceRevisionsSchema, nodes: z.array(SpatialNodeSchema), status: z.enum(['stable', 'unstable']), generation: z.number().int().nonnegative(), nativeTarget: NativeTargetSchema.optional(), webDiagnostics: WebDiagnosticsSchema.optional() }).strict().superRefine((snapshot, ctx) => {
20
+ if (snapshot.platform !== 'web' && snapshot.webDiagnostics)
21
+ ctx.addIssue({ code: 'custom', message: 'Web diagnostics cannot appear in Android snapshots', path: ['webDiagnostics'] });
22
+ snapshot.nodes.forEach((node, i) => {
23
+ if (snapshot.platform !== 'web' && node.accessibility?.directionSource === 'browser-computed')
24
+ ctx.addIssue({ code: 'custom', message: 'Browser direction evidence cannot appear in native snapshots', path: ['nodes', i, 'accessibility', 'directionSource'] });
25
+ if (snapshot.platform !== 'web' && node.accessibility?.browser)
26
+ ctx.addIssue({ code: 'custom', message: 'Browser accessibility evidence cannot appear in native snapshots', path: ['nodes', i, 'accessibility', 'browser'] });
27
+ for (const dependency of node.source?.dependencies ?? [])
28
+ if (!snapshot.revisions[dependency])
29
+ ctx.addIssue({ code: 'custom', message: 'Required style dependency revision is missing', path: ['nodes', i, 'source', 'dependencies'], params: { bridgeCode: 'STALE_SOURCE' } });
30
+ if (node.source && snapshot.revisions[node.source.path] !== node.source.hash)
31
+ ctx.addIssue({ code: 'custom', message: 'Node source hash disagrees with snapshot revisions', path: ['nodes', i, 'source', 'hash'], params: { bridgeCode: 'STALE_SOURCE' } });
32
+ });
33
+ });
34
+ export const SpatialDeltaSchema = z.object({ added: z.array(z.string()), removed: z.array(z.string()), changed: z.array(z.object({ id: z.string(), before: RectSchema, after: RectSchema, delta: RectSchema.extend({ width: z.number(), height: z.number() }) })) });
35
+ export const OverlaySceneSchema = z.object({ width: z.number(), height: z.number(), marks: z.array(z.object({ label: z.number(), id: z.string(), rect: RectSchema })), targets: z.array(z.object({ id: z.string(), rect: RectSchema })) });
36
+ export const ProfileOverridesSchema = z.object({ fontScale: z.number().positive().optional(), orientation: z.enum(['portrait', 'landscape']).optional() }).strict().refine(value => Object.keys(value).length > 0, 'Profile override must set a value');
@@ -0,0 +1,12 @@
1
+ export * from './geometry.js';
2
+ export * from './styles.js';
3
+ export * from './source.js';
4
+ export * from './graph.js';
5
+ export * from './constraints.js';
6
+ export * from './native-protocol.js';
7
+ export * from './tools.js';
8
+ export * from './workflow.js';
9
+ export * from './diagnostics.js';
10
+ export * from './design.js';
11
+ export * from './accessibility.js';
12
+ export * from './evidence.js';
package/dist/index.js ADDED
@@ -0,0 +1,12 @@
1
+ export * from './geometry.js';
2
+ export * from './styles.js';
3
+ export * from './source.js';
4
+ export * from './graph.js';
5
+ export * from './constraints.js';
6
+ export * from './native-protocol.js';
7
+ export * from './tools.js';
8
+ export * from './workflow.js';
9
+ export * from './diagnostics.js';
10
+ export * from './design.js';
11
+ export * from './accessibility.js';
12
+ export * from './evidence.js';