@ripplo/testing 0.0.7 → 0.0.8

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.
@@ -83,7 +83,7 @@ function compileSteps(steps, accessedKeys, requiresKeys) {
83
83
  variables[key] = { default: `test-${key}`, type: "string" };
84
84
  });
85
85
  const variableNamespaces = { ...requiresKeys };
86
- return { entryNode: "step-0", nodes, variableNamespaces, variables, version: 2 };
86
+ return { entryNode: "step-0", nodes, variableNamespaces, variables };
87
87
  }
88
88
  function compileNode(step, id, next) {
89
89
  const { label, node: raw } = readStep(step);
@@ -116,7 +116,7 @@ function compileGraph(preconditionDefs, testDefs) {
116
116
  workflow: def.id
117
117
  });
118
118
  });
119
- return { edges, preconditions, states, version: 3 };
119
+ return { edges, preconditions, states };
120
120
  }
121
121
  function resolveDependencyChain(requires, preconditionDefs) {
122
122
  const defsByName = new Map(preconditionDefs.map((d) => [d.name, d]));
package/dist/compiler.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  compile
3
- } from "./chunk-GTHRSFXF.js";
3
+ } from "./chunk-AQ52MYXE.js";
4
4
  import "./chunk-MGATMMCZ.js";
5
5
  export {
6
6
  compile
package/dist/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  compile
3
- } from "./chunk-GTHRSFXF.js";
3
+ } from "./chunk-AQ52MYXE.js";
4
4
  import "./chunk-MGATMMCZ.js";
5
5
  import {
6
6
  buildSetCookieHeader,
@@ -1,12 +1,11 @@
1
+ import { Codec } from '@ripplo/spec';
1
2
  import { z } from 'zod';
2
3
  import { CompileResult } from './compiler.js';
3
- import '@ripplo/spec';
4
4
  import './builder-DTWMrbuv.js';
5
5
  import './step-DLfkKI3V.js';
6
6
 
7
- declare const LOCKFILE_VERSION = 1;
8
7
  declare const LOCKFILE_RELATIVE_PATH = ".ripplo/ripplo.lock";
9
- declare const lockfileSchema: z.ZodObject<{
8
+ declare const lockfileBodySchema: z.ZodObject<{
10
9
  graph: z.ZodObject<{
11
10
  edges: z.ZodArray<z.ZodObject<{
12
11
  from: z.ZodString;
@@ -23,11 +22,8 @@ declare const lockfileSchema: z.ZodObject<{
23
22
  preconditions: z.ZodArray<z.ZodString>;
24
23
  route: z.ZodString;
25
24
  }, z.core.$strip>>;
26
- version: z.ZodLiteral<3>;
27
25
  }, z.core.$strip>;
28
- lockfileVersion: z.ZodNumber;
29
26
  tests: z.ZodArray<z.ZodObject<{
30
- additionalChecks: z.ZodArray<z.ZodString>;
31
27
  description: z.ZodString;
32
28
  expectedOutcome: z.ZodString;
33
29
  implemented: z.ZodBoolean;
@@ -696,12 +692,11 @@ declare const lockfileSchema: z.ZodObject<{
696
692
  key: z.ZodString;
697
693
  type: z.ZodLiteral<"env">;
698
694
  }, z.core.$strip>], "type">>>;
699
- version: z.ZodLiteral<2>;
700
695
  }, z.core.$strip>;
701
- warnings: z.ZodArray<z.ZodString>;
702
696
  }, z.core.$strip>>;
703
697
  }, z.core.$strip>;
704
- type Lockfile = z.infer<typeof lockfileSchema>;
698
+ type Lockfile = z.infer<typeof lockfileBodySchema>;
699
+ declare const lockfileCodec: Codec<Lockfile>;
705
700
  declare function compileResultToLockfile(result: CompileResult): Lockfile;
706
701
  declare function serializeLockfile(lockfile: Lockfile): string;
707
702
  interface ReadLockfileParams {
@@ -720,4 +715,4 @@ interface CompareLockfileParams {
720
715
  }
721
716
  declare function compareCompileToLockfile({ compiled, existing, }: CompareLockfileParams): LockfileComparison;
722
717
 
723
- export { type CompareLockfileParams, LOCKFILE_RELATIVE_PATH, LOCKFILE_VERSION, type Lockfile, type LockfileComparison, type ReadLockfileParams, type WriteLockfileParams, compareCompileToLockfile, compileResultToLockfile, lockfileSchema, readLockfile, serializeLockfile, writeLockfile };
718
+ export { type CompareLockfileParams, LOCKFILE_RELATIVE_PATH, type Lockfile, type LockfileComparison, type ReadLockfileParams, type WriteLockfileParams, compareCompileToLockfile, compileResultToLockfile, lockfileCodec, readLockfile, serializeLockfile, writeLockfile };
package/dist/lockfile.js CHANGED
@@ -2,39 +2,163 @@
2
2
  import fs from "fs/promises";
3
3
  import path from "path";
4
4
 
5
- // ../spec/src/edge.ts
5
+ // ../spec/src/codec.ts
6
6
  import { z } from "zod";
7
- var edgeSchema = z.object({
8
- from: z.string().min(1).describe("Key of the source state in the states record"),
9
- requiresKeys: z.record(z.string(), z.string()).optional().describe(
7
+ var envelopeSchema = z.object({
8
+ __codec: z.string().min(1),
9
+ data: z.unknown(),
10
+ version: z.number().int().positive()
11
+ });
12
+ var CodecVersionError = class extends Error {
13
+ codec;
14
+ currentVersion;
15
+ gotVersion;
16
+ constructor(params) {
17
+ super(
18
+ `Unsupported ${params.codec} version ${String(params.gotVersion)} (current ${String(params.currentVersion)}). Upgrade Ripplo or rebuild with a compatible CLI.`
19
+ );
20
+ this.name = "CodecVersionError";
21
+ this.codec = params.codec;
22
+ this.currentVersion = params.currentVersion;
23
+ this.gotVersion = params.gotVersion;
24
+ }
25
+ };
26
+ var CodecMismatchError = class extends Error {
27
+ constructor(params) {
28
+ super(`Codec mismatch: expected "${params.expected}", got "${params.got}"`);
29
+ this.name = "CodecMismatchError";
30
+ }
31
+ };
32
+ function defineCodec(name) {
33
+ return makeInitial({ legacy: void 0, migrators: [], name, schemas: [] });
34
+ }
35
+ function decodeJson(codec, raw) {
36
+ const parsed = JSON.parse(raw);
37
+ return codec.decode(parsed);
38
+ }
39
+ function makeInitial(state) {
40
+ return {
41
+ initial: (schema) => makeBuilder(schema, { ...state, schemas: [schema] }),
42
+ legacy: (adapter) => makeInitial({ ...state, legacy: adapter })
43
+ };
44
+ }
45
+ function makeBuilder(latestSchema, state) {
46
+ return {
47
+ build: () => buildCodec(latestSchema, state),
48
+ legacy: (adapter) => makeBuilder(latestSchema, { ...state, legacy: adapter }),
49
+ upgrade: (schema, up) => {
50
+ const erased = up;
51
+ return makeBuilder(schema, {
52
+ ...state,
53
+ migrators: [...state.migrators, erased],
54
+ schemas: [...state.schemas, schema]
55
+ });
56
+ }
57
+ };
58
+ }
59
+ function buildCodec(latestSchema, state) {
60
+ const currentVersion = state.schemas.length;
61
+ return {
62
+ currentVersion,
63
+ name: state.name,
64
+ decode: (raw) => decodeWith(latestSchema, state, raw),
65
+ encode: (value) => ({
66
+ __codec: state.name,
67
+ data: value,
68
+ version: currentVersion
69
+ })
70
+ };
71
+ }
72
+ function decodeWith(latestSchema, state, raw) {
73
+ const { data, version } = unwrapEnvelope(state, raw);
74
+ const migrated = migrateStep(state, data, version);
75
+ return latestSchema.parse(migrated);
76
+ }
77
+ function unwrapEnvelope(state, raw) {
78
+ const envelopeResult = envelopeSchema.safeParse(raw);
79
+ if (envelopeResult.success) {
80
+ if (envelopeResult.data.__codec !== state.name) {
81
+ throw new CodecMismatchError({
82
+ expected: state.name,
83
+ got: envelopeResult.data.__codec
84
+ });
85
+ }
86
+ return {
87
+ data: envelopeResult.data.data,
88
+ version: envelopeResult.data.version
89
+ };
90
+ }
91
+ if (state.legacy != null && state.legacy.detect(raw)) {
92
+ return { data: raw, version: state.legacy.assumedVersion };
93
+ }
94
+ throw new Error(
95
+ `Cannot decode "${state.name}": value is not a codec envelope and no legacy detector matched.`
96
+ );
97
+ }
98
+ function migrateStep(state, data, version) {
99
+ const currentVersion = state.schemas.length;
100
+ if (version > currentVersion) {
101
+ throw new CodecVersionError({
102
+ codec: state.name,
103
+ currentVersion,
104
+ gotVersion: version
105
+ });
106
+ }
107
+ if (version === currentVersion) {
108
+ return data;
109
+ }
110
+ const sourceSchema = state.schemas[version - 1];
111
+ if (sourceSchema == null) {
112
+ throw new Error(
113
+ `Codec "${state.name}" missing schema for v${String(version)}; cannot migrate.`
114
+ );
115
+ }
116
+ const validated = sourceSchema.parse(data);
117
+ const migrator = state.migrators[version - 1];
118
+ if (migrator == null) {
119
+ throw new Error(
120
+ `Codec "${state.name}" missing migrator v${String(version)} \u2192 v${String(version + 1)}.`
121
+ );
122
+ }
123
+ return migrateStep(state, migrator(validated), version + 1);
124
+ }
125
+
126
+ // ../spec/src/codecs.ts
127
+ import { z as z11 } from "zod";
128
+
129
+ // ../spec/src/graph.ts
130
+ import { z as z5 } from "zod";
131
+
132
+ // ../spec/src/edge.ts
133
+ import { z as z2 } from "zod";
134
+ var edgeSchema = z2.object({
135
+ from: z2.string().min(1).describe("Key of the source state in the states record"),
136
+ requiresKeys: z2.record(z2.string(), z2.string()).optional().describe(
10
137
  "Maps workflow variable namespace to precondition name. Used by the runtime to namespace batch precondition data into dot-namespaced variables (e.g. { project: 'data:project' } maps projectId \u2192 project.projectId)."
11
138
  ),
12
- to: z.string().min(1).describe("Key of the target state in the states record"),
13
- workflow: z.string().min(1).describe(
139
+ to: z2.string().min(1).describe("Key of the target state in the states record"),
140
+ workflow: z2.string().min(1).describe(
14
141
  "Filename (without .json) of the workflow in .ripplo/workflows/ that executes this edge"
15
142
  )
16
143
  }).describe("A directed edge between two states, executed by a workflow");
17
144
 
18
- // ../spec/src/graph.ts
19
- import { z as z4 } from "zod";
20
-
21
145
  // ../spec/src/precondition.ts
22
- import { z as z2 } from "zod";
23
- var preconditionSchema = z2.object({
24
- depends: z2.array(z2.string().min(1)).optional().describe(
146
+ import { z as z3 } from "zod";
147
+ var preconditionSchema = z3.object({
148
+ depends: z3.array(z3.string().min(1)).optional().describe(
25
149
  "Names of other preconditions that must be satisfied first. Resolved via topological sort; cycles are rejected at validation time."
26
150
  ),
27
- description: z2.string().min(1).describe("Human-readable description of what this precondition ensures"),
28
- returns: z2.array(z2.string().min(1)).optional().describe(
151
+ description: z3.string().min(1).describe("Human-readable description of what this precondition ensures"),
152
+ returns: z3.array(z3.string().min(1)).optional().describe(
29
153
  "Keys that the execute response's data field will contain. e.g. ['projectId', 'workflowId']. These are used for route param interpolation ({{projectId}}) and workflow variables. Declared here so generated types are strongly typed per precondition."
30
154
  )
31
155
  }).describe("A named precondition declared at the graph level. States reference these by name.");
32
156
 
33
157
  // ../spec/src/state.ts
34
- import { z as z3 } from "zod";
35
- var stateNodeSchema = z3.object({
36
- preconditions: z3.array(z3.string().min(1)).describe("Ordered list of precondition names to satisfy before entering this state"),
37
- route: z3.string().min(1).describe(
158
+ import { z as z4 } from "zod";
159
+ var stateNodeSchema = z4.object({
160
+ preconditions: z4.array(z4.string().min(1)).describe("Ordered list of precondition names to satisfy before entering this state"),
161
+ route: z4.string().min(1).describe(
38
162
  "URL pattern with {{placeholders}} for dynamic segments, e.g. '/projects/{{projectId}}/settings'"
39
163
  )
40
164
  }).describe(
@@ -42,36 +166,42 @@ var stateNodeSchema = z3.object({
42
166
  );
43
167
 
44
168
  // ../spec/src/graph.ts
45
- var stateGraphSchema = z4.object({
46
- edges: z4.array(edgeSchema).describe("Directed edges between states, each executed by a workflow"),
47
- preconditions: z4.record(z4.string(), preconditionSchema).describe(
169
+ var MAX_STATES = 1e3;
170
+ var MAX_EDGES = 5e3;
171
+ var MAX_PRECONDITIONS = 500;
172
+ var stateGraphSchema = z5.object({
173
+ edges: z5.array(edgeSchema).max(MAX_EDGES).describe("Directed edges between states, each executed by a workflow"),
174
+ preconditions: z5.record(z5.string().max(200), preconditionSchema).refine(
175
+ (obj) => Object.keys(obj).length <= MAX_PRECONDITIONS,
176
+ `Graph has more than ${String(MAX_PRECONDITIONS)} preconditions`
177
+ ).describe(
48
178
  "Named preconditions keyed by name (e.g. 'auth:admin', 'data:three-projects'). States reference these by name."
49
179
  ),
50
- states: z4.record(z4.string(), stateNodeSchema).describe("States keyed by stable ID (kebab-case)"),
51
- version: z4.literal(3).describe("Schema version, always 3")
52
- }).describe(
53
- "Ripplo State Graph v3 \u2014 models application states, edges, and executable preconditions"
54
- );
180
+ states: z5.record(z5.string().max(200), stateNodeSchema).refine(
181
+ (obj) => Object.keys(obj).length <= MAX_STATES,
182
+ `Graph has more than ${String(MAX_STATES)} states`
183
+ ).describe("States keyed by stable ID (kebab-case)")
184
+ }).describe("Ripplo State Graph \u2014 models application states, edges, and executable preconditions");
55
185
 
56
186
  // ../spec/src/schema.ts
57
- import { z as z9 } from "zod";
187
+ import { z as z10 } from "zod";
58
188
 
59
189
  // ../spec/src/locators.ts
60
- import { z as z5 } from "zod";
61
- var testIdLocator = z5.object({
62
- by: z5.literal("testId"),
63
- value: z5.string().min(1)
190
+ import { z as z6 } from "zod";
191
+ var testIdLocator = z6.object({
192
+ by: z6.literal("testId"),
193
+ value: z6.string().min(1)
64
194
  });
65
- var roleLocator = z5.object({
66
- by: z5.literal("role"),
67
- name: z5.string().optional(),
68
- role: z5.string().min(1)
195
+ var roleLocator = z6.object({
196
+ by: z6.literal("role"),
197
+ name: z6.string().optional(),
198
+ role: z6.string().min(1)
69
199
  });
70
- var locatorSchema = z5.discriminatedUnion("by", [testIdLocator, roleLocator]);
200
+ var locatorSchema = z6.discriminatedUnion("by", [testIdLocator, roleLocator]);
71
201
 
72
202
  // ../spec/src/operators.ts
73
- import { z as z6 } from "zod";
74
- var comparisonOperator = z6.enum([
203
+ import { z as z7 } from "zod";
204
+ var comparisonOperator = z7.enum([
75
205
  "equals",
76
206
  "notEquals",
77
207
  "contains",
@@ -79,7 +209,7 @@ var comparisonOperator = z6.enum([
79
209
  "endsWith",
80
210
  "matches"
81
211
  ]);
82
- var numericOperator = z6.enum([
212
+ var numericOperator = z7.enum([
83
213
  "equals",
84
214
  "notEquals",
85
215
  "greaterThan",
@@ -89,240 +219,241 @@ var numericOperator = z6.enum([
89
219
  ]);
90
220
 
91
221
  // ../spec/src/value-ref.ts
92
- import { z as z7 } from "zod";
93
- var staticValueSchema = z7.object({
94
- type: z7.literal("static"),
95
- value: z7.union([z7.string(), z7.number(), z7.boolean()])
222
+ import { z as z8 } from "zod";
223
+ var staticValueSchema = z8.object({
224
+ type: z8.literal("static"),
225
+ value: z8.union([z8.string(), z8.number(), z8.boolean()])
96
226
  });
97
- var variableRefSchema = z7.object({
98
- name: z7.string().min(1),
99
- type: z7.literal("variable")
227
+ var variableRefSchema = z8.object({
228
+ name: z8.string().min(1),
229
+ type: z8.literal("variable")
100
230
  });
101
- var valueRefSchema = z7.discriminatedUnion("type", [staticValueSchema, variableRefSchema]);
102
- var stringValueRefSchema = z7.discriminatedUnion("type", [
103
- z7.object({ type: z7.literal("static"), value: z7.string() }),
231
+ var valueRefSchema = z8.discriminatedUnion("type", [staticValueSchema, variableRefSchema]);
232
+ var stringValueRefSchema = z8.discriminatedUnion("type", [
233
+ z8.object({ type: z8.literal("static"), value: z8.string() }),
104
234
  variableRefSchema
105
235
  ]);
106
- var numericValueRefSchema = z7.discriminatedUnion("type", [
107
- z7.object({ type: z7.literal("static"), value: z7.number().int().nonnegative() }),
236
+ var numericValueRefSchema = z8.discriminatedUnion("type", [
237
+ z8.object({ type: z8.literal("static"), value: z8.number().int().nonnegative() }),
108
238
  variableRefSchema
109
239
  ]);
110
240
 
111
241
  // ../spec/src/variables.ts
112
- import { z as z8 } from "zod";
113
- var variableDefSchema = z8.discriminatedUnion("type", [
114
- z8.object({
115
- default: z8.string().optional(),
116
- type: z8.literal("string")
242
+ import { z as z9 } from "zod";
243
+ var variableDefSchema = z9.discriminatedUnion("type", [
244
+ z9.object({
245
+ default: z9.string().optional(),
246
+ type: z9.literal("string")
117
247
  }),
118
- z8.object({
119
- default: z8.number().optional(),
120
- type: z8.literal("number")
248
+ z9.object({
249
+ default: z9.number().optional(),
250
+ type: z9.literal("number")
121
251
  }),
122
- z8.object({
123
- default: z8.boolean().optional(),
124
- type: z8.literal("boolean")
252
+ z9.object({
253
+ default: z9.boolean().optional(),
254
+ type: z9.literal("boolean")
125
255
  }),
126
- z8.object({
127
- key: z8.string().min(1),
128
- type: z8.literal("env")
256
+ z9.object({
257
+ key: z9.string().min(1),
258
+ type: z9.literal("env")
129
259
  })
130
260
  ]);
131
261
 
132
262
  // ../spec/src/schema.ts
133
263
  var nodeBase = {
134
- comment: z9.string().optional(),
135
- id: z9.string().min(1),
136
- label: z9.string().optional(),
137
- next: z9.string().optional(),
138
- timeout: z9.number().int().positive().optional()
264
+ comment: z10.string().max(2e3).optional(),
265
+ id: z10.string().min(1).max(200),
266
+ label: z10.string().max(500).optional(),
267
+ next: z10.string().max(200).optional(),
268
+ timeout: z10.number().int().positive().optional()
139
269
  };
140
- var gotoNode = z9.object({
270
+ var MAX_NODES_PER_WORKFLOW = 500;
271
+ var gotoNode = z10.object({
141
272
  ...nodeBase,
142
- type: z9.literal("goto"),
273
+ type: z10.literal("goto"),
143
274
  url: stringValueRefSchema
144
275
  });
145
- var clickNode = z9.object({ ...nodeBase, locator: locatorSchema, type: z9.literal("click") });
146
- var fillNode = z9.object({
276
+ var clickNode = z10.object({ ...nodeBase, locator: locatorSchema, type: z10.literal("click") });
277
+ var fillNode = z10.object({
147
278
  ...nodeBase,
148
279
  locator: locatorSchema,
149
- type: z9.literal("fill"),
280
+ type: z10.literal("fill"),
150
281
  value: stringValueRefSchema
151
282
  });
152
- var selectNode = z9.object({
283
+ var selectNode = z10.object({
153
284
  ...nodeBase,
154
285
  locator: locatorSchema,
155
- type: z9.literal("select"),
286
+ type: z10.literal("select"),
156
287
  value: stringValueRefSchema
157
288
  });
158
- var hoverNode = z9.object({ ...nodeBase, locator: locatorSchema, type: z9.literal("hover") });
159
- var pressNode = z9.object({
289
+ var hoverNode = z10.object({ ...nodeBase, locator: locatorSchema, type: z10.literal("hover") });
290
+ var pressNode = z10.object({
160
291
  ...nodeBase,
161
- key: z9.string().min(1),
292
+ key: z10.string().min(1),
162
293
  locator: locatorSchema.optional(),
163
- type: z9.literal("press")
294
+ type: z10.literal("press")
164
295
  });
165
- var checkNode = z9.object({ ...nodeBase, locator: locatorSchema, type: z9.literal("check") });
166
- var uncheckNode = z9.object({ ...nodeBase, locator: locatorSchema, type: z9.literal("uncheck") });
167
- var setViewportNode = z9.object({
296
+ var checkNode = z10.object({ ...nodeBase, locator: locatorSchema, type: z10.literal("check") });
297
+ var uncheckNode = z10.object({ ...nodeBase, locator: locatorSchema, type: z10.literal("uncheck") });
298
+ var setViewportNode = z10.object({
168
299
  ...nodeBase,
169
- height: z9.number().int().positive(),
170
- type: z9.literal("setViewport"),
171
- width: z9.number().int().positive()
300
+ height: z10.number().int().positive(),
301
+ type: z10.literal("setViewport"),
302
+ width: z10.number().int().positive()
172
303
  });
173
- var failNode = z9.object({ ...nodeBase, message: z9.string().min(1), type: z9.literal("fail") });
174
- var setVariableNode = z9.object({
304
+ var failNode = z10.object({ ...nodeBase, message: z10.string().min(1), type: z10.literal("fail") });
305
+ var setVariableNode = z10.object({
175
306
  ...nodeBase,
176
- type: z9.literal("setVariable"),
307
+ type: z10.literal("setVariable"),
177
308
  value: valueRefSchema,
178
- variable: z9.string().min(1)
309
+ variable: z10.string().min(1)
179
310
  });
180
- var extractTextNode = z9.object({
311
+ var extractTextNode = z10.object({
181
312
  ...nodeBase,
182
313
  locator: locatorSchema,
183
- type: z9.literal("extractText"),
184
- variable: z9.string().min(1)
314
+ type: z10.literal("extractText"),
315
+ variable: z10.string().min(1)
185
316
  });
186
- var uploadNode = z9.object({
317
+ var uploadNode = z10.object({
187
318
  ...nodeBase,
188
- files: z9.array(z9.string()).min(1),
319
+ files: z10.array(z10.string()).min(1),
189
320
  locator: locatorSchema,
190
- type: z9.literal("upload")
321
+ type: z10.literal("upload")
191
322
  });
192
- var dblclickNode = z9.object({
323
+ var dblclickNode = z10.object({
193
324
  ...nodeBase,
194
325
  locator: locatorSchema,
195
- type: z9.literal("dblclick")
326
+ type: z10.literal("dblclick")
196
327
  });
197
- var dragNode = z9.object({
328
+ var dragNode = z10.object({
198
329
  ...nodeBase,
199
330
  source: locatorSchema,
200
331
  target: locatorSchema,
201
- type: z9.literal("drag")
332
+ type: z10.literal("drag")
202
333
  });
203
- var scrollIntoViewNode = z9.object({
334
+ var scrollIntoViewNode = z10.object({
204
335
  ...nodeBase,
205
336
  locator: locatorSchema,
206
- type: z9.literal("scrollIntoView")
337
+ type: z10.literal("scrollIntoView")
207
338
  });
208
- var typeNode = z9.object({
339
+ var typeNode = z10.object({
209
340
  ...nodeBase,
210
341
  locator: locatorSchema,
211
- type: z9.literal("type"),
342
+ type: z10.literal("type"),
212
343
  value: stringValueRefSchema
213
344
  });
214
- var focusNode = z9.object({
345
+ var focusNode = z10.object({
215
346
  ...nodeBase,
216
347
  locator: locatorSchema,
217
- type: z9.literal("focus")
348
+ type: z10.literal("focus")
218
349
  });
219
- var clearNode = z9.object({ ...nodeBase, locator: locatorSchema, type: z9.literal("clear") });
220
- var rightClickNode = z9.object({
350
+ var clearNode = z10.object({ ...nodeBase, locator: locatorSchema, type: z10.literal("clear") });
351
+ var rightClickNode = z10.object({
221
352
  ...nodeBase,
222
353
  locator: locatorSchema,
223
- type: z9.literal("rightClick")
354
+ type: z10.literal("rightClick")
224
355
  });
225
- var handleDialogNode = z9.object({
356
+ var handleDialogNode = z10.object({
226
357
  ...nodeBase,
227
- action: z9.enum(["accept", "dismiss"]),
228
- promptText: z9.string().optional(),
229
- type: z9.literal("handleDialog")
358
+ action: z10.enum(["accept", "dismiss"]),
359
+ promptText: z10.string().optional(),
360
+ type: z10.literal("handleDialog")
230
361
  });
231
- var clipboardNode = z9.object({
362
+ var clipboardNode = z10.object({
232
363
  ...nodeBase,
233
- action: z9.enum(["read", "write"]),
234
- type: z9.literal("clipboard"),
364
+ action: z10.enum(["read", "write"]),
365
+ type: z10.literal("clipboard"),
235
366
  value: stringValueRefSchema.optional(),
236
- variable: z9.string().min(1).optional()
367
+ variable: z10.string().min(1).optional()
237
368
  });
238
- var setPermissionNode = z9.object({
369
+ var setPermissionNode = z10.object({
239
370
  ...nodeBase,
240
- permission: z9.string().min(1),
241
- state: z9.enum(["granted", "prompt"]),
242
- type: z9.literal("setPermission")
371
+ permission: z10.string().min(1),
372
+ state: z10.enum(["granted", "prompt"]),
373
+ type: z10.literal("setPermission")
243
374
  });
244
- var assertVisibleNode = z9.object({
375
+ var assertVisibleNode = z10.object({
245
376
  ...nodeBase,
246
377
  locator: locatorSchema,
247
- type: z9.literal("assertVisible")
378
+ type: z10.literal("assertVisible")
248
379
  });
249
- var assertNotVisibleNode = z9.object({
380
+ var assertNotVisibleNode = z10.object({
250
381
  ...nodeBase,
251
382
  locator: locatorSchema,
252
- type: z9.literal("assertNotVisible")
383
+ type: z10.literal("assertNotVisible")
253
384
  });
254
- var assertTextNode = z9.object({
385
+ var assertTextNode = z10.object({
255
386
  ...nodeBase,
256
387
  expected: stringValueRefSchema,
257
388
  locator: locatorSchema,
258
389
  operator: comparisonOperator,
259
- type: z9.literal("assertText")
390
+ type: z10.literal("assertText")
260
391
  });
261
- var assertUrlNode = z9.object({
392
+ var assertUrlNode = z10.object({
262
393
  ...nodeBase,
263
394
  expected: stringValueRefSchema,
264
395
  operator: comparisonOperator,
265
- type: z9.literal("assertUrl")
396
+ type: z10.literal("assertUrl")
266
397
  });
267
- var assertCountNode = z9.object({
398
+ var assertCountNode = z10.object({
268
399
  ...nodeBase,
269
400
  expected: numericValueRefSchema,
270
401
  locator: locatorSchema,
271
402
  operator: numericOperator,
272
- type: z9.literal("assertCount")
403
+ type: z10.literal("assertCount")
273
404
  });
274
- var assertValueNode = z9.object({
405
+ var assertValueNode = z10.object({
275
406
  ...nodeBase,
276
407
  expected: stringValueRefSchema,
277
408
  locator: locatorSchema,
278
409
  operator: comparisonOperator,
279
- type: z9.literal("assertValue")
410
+ type: z10.literal("assertValue")
280
411
  });
281
- var assertAttributeNode = z9.object({
412
+ var assertAttributeNode = z10.object({
282
413
  ...nodeBase,
283
- attribute: z9.string().min(1),
414
+ attribute: z10.string().min(1),
284
415
  expected: stringValueRefSchema,
285
416
  locator: locatorSchema,
286
417
  operator: comparisonOperator,
287
- type: z9.literal("assertAttribute")
418
+ type: z10.literal("assertAttribute")
288
419
  });
289
- var assertEnabledNode = z9.object({
420
+ var assertEnabledNode = z10.object({
290
421
  ...nodeBase,
291
422
  locator: locatorSchema,
292
- type: z9.literal("assertEnabled")
423
+ type: z10.literal("assertEnabled")
293
424
  });
294
- var assertDisabledNode = z9.object({
425
+ var assertDisabledNode = z10.object({
295
426
  ...nodeBase,
296
427
  locator: locatorSchema,
297
- type: z9.literal("assertDisabled")
428
+ type: z10.literal("assertDisabled")
298
429
  });
299
- var assertTitleNode = z9.object({
430
+ var assertTitleNode = z10.object({
300
431
  ...nodeBase,
301
432
  expected: stringValueRefSchema,
302
433
  operator: comparisonOperator,
303
- type: z9.literal("assertTitle")
434
+ type: z10.literal("assertTitle")
304
435
  });
305
- var assertCheckedNode = z9.object({
436
+ var assertCheckedNode = z10.object({
306
437
  ...nodeBase,
307
438
  locator: locatorSchema,
308
- type: z9.literal("assertChecked")
439
+ type: z10.literal("assertChecked")
309
440
  });
310
- var assertNotCheckedNode = z9.object({
441
+ var assertNotCheckedNode = z10.object({
311
442
  ...nodeBase,
312
443
  locator: locatorSchema,
313
- type: z9.literal("assertNotChecked")
444
+ type: z10.literal("assertNotChecked")
314
445
  });
315
- var assertFocusedNode = z9.object({
446
+ var assertFocusedNode = z10.object({
316
447
  ...nodeBase,
317
448
  locator: locatorSchema,
318
- type: z9.literal("assertFocused")
449
+ type: z10.literal("assertFocused")
319
450
  });
320
- var assertNotFocusedNode = z9.object({
451
+ var assertNotFocusedNode = z10.object({
321
452
  ...nodeBase,
322
453
  locator: locatorSchema,
323
- type: z9.literal("assertNotFocused")
454
+ type: z10.literal("assertNotFocused")
324
455
  });
325
- var specNodeSchema = z9.discriminatedUnion("type", [
456
+ var specNodeSchema = z10.discriminatedUnion("type", [
326
457
  gotoNode,
327
458
  clickNode,
328
459
  fillNode,
@@ -361,51 +492,67 @@ var specNodeSchema = z9.discriminatedUnion("type", [
361
492
  assertFocusedNode,
362
493
  assertNotFocusedNode
363
494
  ]);
364
- var workflowSpecSchema = z9.object({
365
- entryNode: z9.string().min(1),
366
- nodes: z9.record(z9.string(), specNodeSchema),
367
- variableNamespaces: z9.record(z9.string(), z9.string()).optional(),
368
- variables: z9.record(z9.string(), variableDefSchema).optional(),
369
- version: z9.literal(2)
495
+ var workflowSpecSchema = z10.object({
496
+ entryNode: z10.string().min(1).max(200),
497
+ nodes: z10.record(z10.string().max(200), specNodeSchema).refine(
498
+ (nodes) => Object.keys(nodes).length <= MAX_NODES_PER_WORKFLOW,
499
+ `Workflow has more than ${String(MAX_NODES_PER_WORKFLOW)} nodes`
500
+ ),
501
+ variableNamespaces: z10.record(z10.string().max(200), z10.string().max(500)).optional(),
502
+ variables: z10.record(z10.string().max(200), variableDefSchema).optional()
370
503
  });
371
504
 
505
+ // ../spec/src/codecs.ts
506
+ var preconditionMapSchema = z11.record(z11.string().max(200), preconditionSchema);
507
+ var looksLikeWorkflowSpec = {
508
+ assumedVersion: 1,
509
+ detect: (raw) => typeof raw === "object" && raw !== null && "entryNode" in raw && "nodes" in raw
510
+ };
511
+ var looksLikeStateGraph = {
512
+ assumedVersion: 1,
513
+ detect: (raw) => typeof raw === "object" && raw !== null && "edges" in raw && "states" in raw && "preconditions" in raw
514
+ };
515
+ var looksLikePreconditionMap = {
516
+ assumedVersion: 1,
517
+ detect: (raw) => typeof raw === "object" && raw !== null && !Array.isArray(raw) && !("__codec" in raw)
518
+ };
519
+ var workflowSpecCodec = defineCodec("workflow-spec").legacy(looksLikeWorkflowSpec).initial(workflowSpecSchema).build();
520
+ var stateGraphCodec = defineCodec("state-graph").legacy(looksLikeStateGraph).initial(stateGraphSchema).build();
521
+ var preconditionMapCodec = defineCodec("precondition-map").legacy(looksLikePreconditionMap).initial(preconditionMapSchema).build();
522
+
372
523
  // src/lockfile.ts
373
- import { z as z10 } from "zod";
374
- var LOCKFILE_VERSION = 1;
524
+ import { z as z12 } from "zod";
375
525
  var LOCKFILE_RELATIVE_PATH = ".ripplo/ripplo.lock";
376
- var compiledTestSchema = z10.object({
377
- additionalChecks: z10.array(z10.string()),
378
- description: z10.string(),
379
- expectedOutcome: z10.string(),
380
- implemented: z10.boolean(),
381
- name: z10.string(),
382
- slug: z10.string(),
383
- spec: workflowSpecSchema,
384
- warnings: z10.array(z10.string())
385
- });
386
- var lockfileSchema = z10.object({
526
+ var MAX_TESTS = 5e3;
527
+ var compiledTestSchema = z12.object({
528
+ description: z12.string().max(2e3),
529
+ expectedOutcome: z12.string().max(2e3),
530
+ implemented: z12.boolean(),
531
+ name: z12.string().max(200),
532
+ slug: z12.string().max(200),
533
+ spec: workflowSpecSchema
534
+ });
535
+ var lockfileBodySchema = z12.object({
387
536
  graph: stateGraphSchema,
388
- lockfileVersion: z10.number().int().positive(),
389
- tests: z10.array(compiledTestSchema)
537
+ tests: z12.array(compiledTestSchema).max(MAX_TESTS)
390
538
  });
539
+ var lockfileCodec = defineCodec("ripplo-lockfile").initial(lockfileBodySchema).build();
391
540
  function compileResultToLockfile(result) {
392
541
  return {
393
542
  graph: result.graph,
394
- lockfileVersion: LOCKFILE_VERSION,
395
543
  tests: result.tests.map((test) => ({
396
- additionalChecks: [...test.additionalChecks],
397
544
  description: test.description,
398
545
  expectedOutcome: test.expectedOutcome,
399
546
  implemented: test.implemented,
400
547
  name: test.name,
401
548
  slug: test.slug,
402
- spec: test.spec,
403
- warnings: [...test.warnings]
549
+ spec: test.spec
404
550
  }))
405
551
  };
406
552
  }
407
553
  function serializeLockfile(lockfile) {
408
- return `${JSON.stringify(lockfile, sortedReplacer(lockfile), 2)}
554
+ const envelope = lockfileCodec.encode(lockfile);
555
+ return `${JSON.stringify(envelope, sortedReplacer(envelope), 2)}
409
556
  `;
410
557
  }
411
558
  async function readLockfile({ cwd }) {
@@ -414,8 +561,7 @@ async function readLockfile({ cwd }) {
414
561
  if (raw == null) {
415
562
  return null;
416
563
  }
417
- const parsed = JSON.parse(raw);
418
- return lockfileSchema.parse(parsed);
564
+ return decodeJson(lockfileCodec, raw);
419
565
  }
420
566
  async function writeLockfile({ cwd, result }) {
421
567
  const lockfile = compileResultToLockfile(result);
@@ -460,10 +606,9 @@ function isPlainObject(value) {
460
606
  }
461
607
  export {
462
608
  LOCKFILE_RELATIVE_PATH,
463
- LOCKFILE_VERSION,
464
609
  compareCompileToLockfile,
465
610
  compileResultToLockfile,
466
- lockfileSchema,
611
+ lockfileCodec,
467
612
  readLockfile,
468
613
  serializeLockfile,
469
614
  writeLockfile
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@ripplo/testing",
3
3
  "description": "TypeScript DSL for defining and running Ripplo e2e workflow tests",
4
- "version": "0.0.7",
4
+ "version": "0.0.8",
5
5
  "type": "module",
6
6
  "files": [
7
7
  "dist"
@@ -60,7 +60,7 @@
60
60
  },
61
61
  "dependencies": {
62
62
  "standardwebhooks": "^1.0.0",
63
- "zod": "catalog:"
63
+ "zod": "^4.3.6"
64
64
  },
65
65
  "devDependencies": {
66
66
  "@types/express": "^5.0.2",