lynkeus-protocol 0.3.0 → 0.5.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,47 @@
1
+ /**
2
+ * The fixtures protocol: how a case prepares and reads a backend through a server the project writes. lynkeus starts
3
+ * the command `cases.fixtures` names and speaks JSON lines to it, one request and one answer per line.
4
+ * The full contract is docs/FIXTURES.md.
5
+ */
6
+ export declare const FIXTURES_PROTOCOL = 1;
7
+ /** One step, as lynkeus sends it: `params` as the case wrote them, `env` the same flattened to upper-case strings. */
8
+ export type FixtureRequest = {
9
+ command: string;
10
+ params: Record<string, unknown>;
11
+ env: Record<string, string>;
12
+ };
13
+ /** Any JSON object; `ok: false` with an `error` when the step failed. */
14
+ export type FixtureAnswer = {
15
+ ok?: boolean;
16
+ error?: string;
17
+ } & Record<string, unknown>;
18
+ /** A parameter a command takes, for authors and models choosing a setup. */
19
+ export type FixtureParam = {
20
+ type?: 'string' | 'number' | 'boolean' | 'object' | 'array';
21
+ summary?: string;
22
+ /** The values it takes, when they are few. */
23
+ values?: (string | number | boolean)[];
24
+ default?: unknown;
25
+ required?: boolean;
26
+ };
27
+ /** What a command does, for authors and models: what state it makes or reads, its parameters, one example. */
28
+ export type FixtureCommand = {
29
+ name: string;
30
+ summary?: string;
31
+ params?: Record<string, FixtureParam>;
32
+ /** The params of one call that works, as a case would write them. */
33
+ example?: Record<string, unknown>;
34
+ /** What its answer carries that a later step reads (`user_id`, `api_key`…). */
35
+ answers?: string[];
36
+ /** `false` for a command that only reads: safe to call while checking a server. */
37
+ changes?: boolean;
38
+ };
39
+ /**
40
+ * The answer to `lynkeus.describe`. `commands` lists names, or descriptions, or both; a server from before
41
+ * descriptions answers names only, and that stays valid. `down` says the server runs but cannot serve.
42
+ */
43
+ export type FixturesDescription = {
44
+ protocol?: number;
45
+ commands: (string | FixtureCommand)[];
46
+ down?: string;
47
+ };
@@ -0,0 +1,6 @@
1
+ /**
2
+ * The fixtures protocol: how a case prepares and reads a backend through a server the project writes. lynkeus starts
3
+ * the command `cases.fixtures` names and speaks JSON lines to it, one request and one answer per line.
4
+ * The full contract is docs/FIXTURES.md.
5
+ */
6
+ export const FIXTURES_PROTOCOL = 1;
package/lib/index.d.ts CHANGED
@@ -122,6 +122,11 @@ export type WaitForParams = {
122
122
  /** Swipe the nearest scrolling container towards the target until it is in the window. */
123
123
  scroll?: boolean;
124
124
  timeoutMs?: number;
125
+ /**
126
+ * A trace mark (`trace().last`): a `route` the app reached after it counts as arrived, even if the app has
127
+ * already left it. A screen that closes itself (a success screen) can come and go while a step's frame settles.
128
+ */
129
+ since?: number;
125
130
  };
126
131
  export type TraceEvent = {
127
132
  seq: number;
@@ -180,6 +185,12 @@ export type TraceEvent = {
180
185
  stack?: string;
181
186
  route?: string;
182
187
  });
188
+ /** One side of a request: its headers and body, sensitive values replaced by `…`, a long body cut. */
189
+ export type Exchange = {
190
+ headers?: Record<string, string>;
191
+ body?: string;
192
+ truncated?: boolean;
193
+ };
183
194
  export type RequestRecord = {
184
195
  id: number;
185
196
  method: string;
@@ -188,6 +199,9 @@ export type RequestRecord = {
188
199
  startedAt: number;
189
200
  ms?: number;
190
201
  error?: string;
202
+ /** Only while a driver asked for bodies (`networkBodies`). */
203
+ request?: Exchange;
204
+ response?: Exchange;
191
205
  };
192
206
  /** Every method the core answers. Apps add their own through `qa.register`. */
193
207
  export type CoreMethods = {
@@ -262,7 +276,8 @@ export type CoreMethods = {
262
276
  result: {
263
277
  route?: string;
264
278
  matched?: Target;
265
- waitedMs: number;
279
+ waitedMs: number /** The route was reached after `since` and left again. */;
280
+ passed?: boolean;
266
281
  };
267
282
  };
268
283
  idle: {
@@ -358,3 +373,4 @@ export type AuthEvent = {
358
373
  };
359
374
  export type AgentEvent = HelloEvent | NavigationEvent;
360
375
  export * from './run.js';
376
+ export * from './fixtures.js';
package/lib/index.js CHANGED
@@ -1,3 +1,4 @@
1
1
  /** JSON-RPC-shaped messages over a WebSocket the app opens towards the driver; docs/PROTOCOL.md has the prose. */
2
2
  export const PROTOCOL_VERSION = 1;
3
3
  export * from './run.js';
4
+ export * from './fixtures.js';
package/lib/run.d.ts CHANGED
@@ -1,3 +1,4 @@
1
+ import type { RequestRecord } from './index.js';
1
2
  /**
2
3
  * What a run of cases leaves behind: a directory anything can read without
3
4
  * knowing how the run was made.
@@ -62,11 +63,31 @@ export type RunStep = {
62
63
  videoS?: number;
63
64
  /** What the backend did for it, when the backend exports traces to the run. */
64
65
  backend?: RunBackendSpan[];
66
+ /** The requests the app sent while it ran, with headers and bodies whose secrets are hidden. */
67
+ requests?: RequestRecord[];
68
+ /** What the app printed while it ran: its console, the errors it did not catch, its native log. */
69
+ logs?: RunLogLine[];
70
+ };
71
+ /** A printed line: `at` in ms since the epoch; `source` is `js`, `native` or `host`. */
72
+ export type RunLogLine = {
73
+ at: number;
74
+ level: 'debug' | 'info' | 'warn' | 'error';
75
+ source: string;
76
+ text: string;
77
+ stack?: string;
65
78
  };
66
79
  export type RunCase = {
67
80
  id: string;
68
81
  title?: string;
69
82
  description?: string;
83
+ /** What the case says about itself: why it matters, what is true when it starts, its ticket and expected outcome. */
84
+ about?: {
85
+ description?: string;
86
+ why?: string;
87
+ given?: string;
88
+ ticket?: string;
89
+ expected?: string;
90
+ };
70
91
  /** The case file, relative to where the run was started. */
71
92
  file: string;
72
93
  /** 1 for the first try; a case that failed and ran again has a line for each. */
@@ -99,9 +120,23 @@ export type RunManifest = {
99
120
  /** Whether the app ran on a device or simulator (true) or hosted without one. */
100
121
  native?: boolean;
101
122
  /** Where the run was made from, when it was a git checkout. */
123
+ /** `remote`: the repository's web address (no credentials); `changed`: files with changes no commit has (at most 20 of `changedCount`). */
124
+ /**
125
+ * `pushed`: what of it the remote has, as the clone knew when the run began (its remote-tracking refs, not a
126
+ * request): the branch, and the commit on any remote branch. A report links only what is there. A branch only this
127
+ * machine has is replaced by the remote branch that holds the commit, and `localBranch` keeps its name.
128
+ */
102
129
  git?: {
103
130
  branch?: string;
131
+ localBranch?: string;
104
132
  commit?: string;
133
+ remote?: string;
134
+ changed?: string[];
135
+ changedCount?: number;
136
+ pushed?: {
137
+ branch: boolean;
138
+ commit: boolean;
139
+ };
105
140
  };
106
141
  /** Cases by their last attempt. */
107
142
  totals?: {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lynkeus-protocol",
3
- "version": "0.3.0",
3
+ "version": "0.5.0",
4
4
  "description": "Wire contract between an app running lynkeus-agent and whatever drives it.",
5
5
  "type": "module",
6
6
  "main": "./lib/index.js",
@@ -0,0 +1,41 @@
1
+ /**
2
+ * The fixtures protocol: how a case prepares and reads a backend through a server the project writes. lynkeus starts
3
+ * the command `cases.fixtures` names and speaks JSON lines to it, one request and one answer per line.
4
+ * The full contract is docs/FIXTURES.md.
5
+ */
6
+ export const FIXTURES_PROTOCOL = 1;
7
+
8
+ /** One step, as lynkeus sends it: `params` as the case wrote them, `env` the same flattened to upper-case strings. */
9
+ export type FixtureRequest = { command: string; params: Record<string, unknown>; env: Record<string, string> };
10
+
11
+ /** Any JSON object; `ok: false` with an `error` when the step failed. */
12
+ export type FixtureAnswer = { ok?: boolean; error?: string } & Record<string, unknown>;
13
+
14
+ /** A parameter a command takes, for authors and models choosing a setup. */
15
+ export type FixtureParam = {
16
+ type?: 'string' | 'number' | 'boolean' | 'object' | 'array';
17
+ summary?: string;
18
+ /** The values it takes, when they are few. */
19
+ values?: (string | number | boolean)[];
20
+ default?: unknown;
21
+ required?: boolean;
22
+ };
23
+
24
+ /** What a command does, for authors and models: what state it makes or reads, its parameters, one example. */
25
+ export type FixtureCommand = {
26
+ name: string;
27
+ summary?: string;
28
+ params?: Record<string, FixtureParam>;
29
+ /** The params of one call that works, as a case would write them. */
30
+ example?: Record<string, unknown>;
31
+ /** What its answer carries that a later step reads (`user_id`, `api_key`…). */
32
+ answers?: string[];
33
+ /** `false` for a command that only reads: safe to call while checking a server. */
34
+ changes?: boolean;
35
+ };
36
+
37
+ /**
38
+ * The answer to `lynkeus.describe`. `commands` lists names, or descriptions, or both; a server from before
39
+ * descriptions answers names only, and that stays valid. `down` says the server runs but cannot serve.
40
+ */
41
+ export type FixturesDescription = { protocol?: number; commands: (string | FixtureCommand)[]; down?: string };
package/src/index.ts CHANGED
@@ -97,6 +97,11 @@ export type WaitForParams = {
97
97
  /** Swipe the nearest scrolling container towards the target until it is in the window. */
98
98
  scroll?: boolean;
99
99
  timeoutMs?: number;
100
+ /**
101
+ * A trace mark (`trace().last`): a `route` the app reached after it counts as arrived, even if the app has
102
+ * already left it. A screen that closes itself (a success screen) can come and go while a step's frame settles.
103
+ */
104
+ since?: number;
100
105
  };
101
106
 
102
107
  export type TraceEvent = { seq: number; t: number } & (
@@ -114,6 +119,9 @@ export type TraceEvent = { seq: number; t: number } & (
114
119
  | { kind: 'crash'; message: string; stack?: string; route?: string }
115
120
  );
116
121
 
122
+ /** One side of a request: its headers and body, sensitive values replaced by `…`, a long body cut. */
123
+ export type Exchange = { headers?: Record<string, string>; body?: string; truncated?: boolean };
124
+
117
125
  export type RequestRecord = {
118
126
  id: number;
119
127
  method: string;
@@ -122,6 +130,9 @@ export type RequestRecord = {
122
130
  startedAt: number;
123
131
  ms?: number;
124
132
  error?: string;
133
+ /** Only while a driver asked for bodies (`networkBodies`). */
134
+ request?: Exchange;
135
+ response?: Exchange;
125
136
  };
126
137
 
127
138
  /** Every method the core answers. Apps add their own through `qa.register`. */
@@ -151,7 +162,7 @@ export type CoreMethods = {
151
162
  back: { params: undefined; result: { route?: string } };
152
163
  waitFor: {
153
164
  params: WaitForParams;
154
- result: { route?: string; matched?: Target; waitedMs: number };
165
+ result: { route?: string; matched?: Target; waitedMs: number /** The route was reached after `since` and left again. */; passed?: boolean };
155
166
  };
156
167
  idle: {
157
168
  /** `after`: a commit count from before the awaited change; quiet only counts once the app has committed past it. */
@@ -195,3 +206,4 @@ export type AuthEvent = { event: 'auth'; session: string; token?: string };
195
206
  export type AgentEvent = HelloEvent | NavigationEvent;
196
207
 
197
208
  export * from './run.js';
209
+ export * from './fixtures.js';
package/src/run.ts CHANGED
@@ -1,3 +1,4 @@
1
+ import type { RequestRecord } from './index.js';
1
2
  /**
2
3
  * What a run of cases leaves behind: a directory anything can read without
3
4
  * knowing how the run was made.
@@ -67,12 +68,21 @@ export type RunStep = {
67
68
  videoS?: number;
68
69
  /** What the backend did for it, when the backend exports traces to the run. */
69
70
  backend?: RunBackendSpan[];
71
+ /** The requests the app sent while it ran, with headers and bodies whose secrets are hidden. */
72
+ requests?: RequestRecord[];
73
+ /** What the app printed while it ran: its console, the errors it did not catch, its native log. */
74
+ logs?: RunLogLine[];
70
75
  };
71
76
 
77
+ /** A printed line: `at` in ms since the epoch; `source` is `js`, `native` or `host`. */
78
+ export type RunLogLine = { at: number; level: 'debug' | 'info' | 'warn' | 'error'; source: string; text: string; stack?: string };
79
+
72
80
  export type RunCase = {
73
81
  id: string;
74
82
  title?: string;
75
83
  description?: string;
84
+ /** What the case says about itself: why it matters, what is true when it starts, its ticket and expected outcome. */
85
+ about?: { description?: string; why?: string; given?: string; ticket?: string; expected?: string };
76
86
  /** The case file, relative to where the run was started. */
77
87
  file: string;
78
88
  /** 1 for the first try; a case that failed and ran again has a line for each. */
@@ -102,7 +112,21 @@ export type RunManifest = {
102
112
  /** Whether the app ran on a device or simulator (true) or hosted without one. */
103
113
  native?: boolean;
104
114
  /** Where the run was made from, when it was a git checkout. */
105
- git?: { branch?: string; commit?: string };
115
+ /** `remote`: the repository's web address (no credentials); `changed`: files with changes no commit has (at most 20 of `changedCount`). */
116
+ /**
117
+ * `pushed`: what of it the remote has, as the clone knew when the run began (its remote-tracking refs, not a
118
+ * request): the branch, and the commit on any remote branch. A report links only what is there. A branch only this
119
+ * machine has is replaced by the remote branch that holds the commit, and `localBranch` keeps its name.
120
+ */
121
+ git?: {
122
+ branch?: string;
123
+ localBranch?: string;
124
+ commit?: string;
125
+ remote?: string;
126
+ changed?: string[];
127
+ changedCount?: number;
128
+ pushed?: { branch: boolean; commit: boolean };
129
+ };
106
130
  /** Cases by their last attempt. */
107
131
  totals?: { cases: number; passed: number; failed: number; unsupported: number; retried: number };
108
132
  };