@flowrensic/node 0.1.2 → 0.2.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/README.md CHANGED
@@ -3,35 +3,58 @@
3
3
  Replay the histories your workflows already produced, against the code you are
4
4
  about to ship.
5
5
 
6
- Flowrensic keeps what a Temporal server recorded. This package fetches a set and
7
- replays it through Temporal's own replayer, in your tests, against your
8
- checkout. Histories in a repo go stale on the next deploy and nobody can say
9
- which are still safe to delete.
6
+ Flowrensic keeps what a Temporal server recorded. This package fetches a set to
7
+ disk and reports back what your replay found. The replay itself stays yours:
8
+ call Temporal's replayer directly, in your suite, with your own bundler options.
9
+ Histories in a repo go stale on the next deploy and nobody can say which are
10
+ still safe to delete.
10
11
 
11
12
  Server: `flowrensic/flowrensic` on Docker Hub. Temporal is the supported engine.
12
13
 
13
14
  ## Replay
14
15
 
15
- docker run --rm -v "$PWD/replay-set:/out" --entrypoint /flowrensic \
16
- flowrensic/flowrensic replay fetch \
17
- --server http://flowrensic:8080 --workflow-type OrderWorkflow --out /out
18
-
19
16
  ```ts
20
- import { replayFetchedSet } from '@flowrensic/node';
17
+ import { fetchReplaySet, publishVerdicts, readReplaySet } from '@flowrensic/node';
18
+ import { historyFromJSON } from '@temporalio/common/lib/proto-utils.js';
19
+ import { Worker } from '@temporalio/worker';
21
20
 
22
- const report = await replayFetchedSet({
23
- dir: 'replay-set',
24
- workflowsPath: require.resolve('./workflows'),
25
- codeVersion: process.env.GIT_SHA,
21
+ await fetchReplaySet({
26
22
  baseUrl: 'http://flowrensic:8080',
23
+ workflowType: 'OrderWorkflow',
24
+ dir: 'replay-set',
27
25
  });
28
26
 
29
- if (report.failed > 0) throw new Error(`${report.failed} histories no longer replay`);
27
+ const set = await readReplaySet('replay-set');
28
+ const histories = await Promise.all(
29
+ set.histories.map(async (entry) => ({
30
+ workflowId: entry.run_id,
31
+ history: historyFromJSON(JSON.parse(await readFile(join('replay-set', entry.file), 'utf8'))),
32
+ })),
33
+ );
34
+
35
+ const verdicts = [];
36
+ for await (const result of Worker.runReplayHistories({ workflowsPath }, histories)) {
37
+ verdicts.push({
38
+ runId: result.workflowId,
39
+ workflowType: set.workflow_type,
40
+ passed: result.error === undefined,
41
+ error: result.error?.message,
42
+ });
43
+ }
44
+
45
+ await publishVerdicts({
46
+ baseUrl: 'http://flowrensic:8080',
47
+ codeVersion: process.env.GIT_SHA,
48
+ verdicts,
49
+ });
30
50
  ```
31
51
 
32
52
  Verdicts go back against the run and the version, so a break points at the
33
53
  change that caused it.
34
54
 
55
+ `flowrensic replay fetch` in the CLI writes the same directory and the same
56
+ manifest, for a pipeline that would rather fetch in a step than in a test.
57
+
35
58
  The server picks the set: recent histories, versions still running somewhere,
36
59
  outcomes that differ. Newest-ten on a healthy workflow type is ten completions
37
60
  and not one failure.
@@ -59,4 +82,5 @@ never fail the activity it measures.
59
82
  ## Peers
60
83
 
61
84
  `@temporalio/worker`, `@temporalio/common`, `@temporalio/activity`, 1.24 or
62
- newer. The replay has to run on the same SDK your workers do.
85
+ newer, for the interceptor. The replay runs on your SDK, not on one this
86
+ package pins.
package/dist/index.d.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  export { createAttemptSink, type AttemptSink, type SinkOptions } from './sink.js';
2
2
  export { FlowrensicActivityInterceptor, flowrensicInterceptor } from './interceptor.js';
3
3
  export { createFlowrensicClient, type FlowrensicClient } from './client.js';
4
- export { replayFetchedSet, readReplaySet, listHistoryFiles, INDEX_NAME, type ReplayOptions, type ReplayReport, type ReplayVerdict, type ReplaySet, type ReplaySetEntry, } from './replay.js';
4
+ export { fetchReplaySet, readReplaySet, listHistoryFiles, publishVerdicts, INDEX_NAME, type FetchOptions, type PublishOptions, type ReplayVerdict, type ReplaySet, type ReplaySetEntry, } from './replay.js';
5
5
  export type { ActivityAttempt, ActivityStats, } from './gen/flowrensic/v1/activity_metrics_pb.js';
6
6
  export { Outcome } from './gen/flowrensic/v1/activity_metrics_pb.js';
7
7
  export type { EngineMetric } from './gen/flowrensic/v1/activity_metrics_pb.js';
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,KAAK,WAAW,EAAE,KAAK,WAAW,EAAE,MAAM,WAAW,CAAC;AAClF,OAAO,EAAE,6BAA6B,EAAE,qBAAqB,EAAE,MAAM,kBAAkB,CAAC;AACxF,OAAO,EAAE,sBAAsB,EAAE,KAAK,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAC5E,OAAO,EACL,gBAAgB,EAChB,aAAa,EACb,gBAAgB,EAChB,UAAU,EACV,KAAK,aAAa,EAClB,KAAK,YAAY,EACjB,KAAK,aAAa,EAClB,KAAK,SAAS,EACd,KAAK,cAAc,GACpB,MAAM,aAAa,CAAC;AAErB,YAAY,EACV,eAAe,EACf,aAAa,GACd,MAAM,4CAA4C,CAAC;AACpD,OAAO,EAAE,OAAO,EAAE,MAAM,4CAA4C,CAAC;AACrE,YAAY,EAAE,YAAY,EAAE,MAAM,4CAA4C,CAAC;AAC/E,YAAY,EAAE,SAAS,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,mCAAmC,CAAC;AACtF,YAAY,EAAE,OAAO,EAAE,MAAM,4CAA4C,CAAC;AAC1E,YAAY,EAAE,OAAO,EAAE,MAAM,mCAAmC,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,KAAK,WAAW,EAAE,KAAK,WAAW,EAAE,MAAM,WAAW,CAAC;AAClF,OAAO,EAAE,6BAA6B,EAAE,qBAAqB,EAAE,MAAM,kBAAkB,CAAC;AACxF,OAAO,EAAE,sBAAsB,EAAE,KAAK,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAC5E,OAAO,EACL,cAAc,EACd,aAAa,EACb,gBAAgB,EAChB,eAAe,EACf,UAAU,EACV,KAAK,YAAY,EACjB,KAAK,cAAc,EACnB,KAAK,aAAa,EAClB,KAAK,SAAS,EACd,KAAK,cAAc,GACpB,MAAM,aAAa,CAAC;AAErB,YAAY,EACV,eAAe,EACf,aAAa,GACd,MAAM,4CAA4C,CAAC;AACpD,OAAO,EAAE,OAAO,EAAE,MAAM,4CAA4C,CAAC;AACrE,YAAY,EAAE,YAAY,EAAE,MAAM,4CAA4C,CAAC;AAC/E,YAAY,EAAE,SAAS,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,mCAAmC,CAAC;AACtF,YAAY,EAAE,OAAO,EAAE,MAAM,4CAA4C,CAAC;AAC1E,YAAY,EAAE,OAAO,EAAE,MAAM,mCAAmC,CAAC"}
package/dist/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  export { createAttemptSink } from './sink.js';
2
2
  export { FlowrensicActivityInterceptor, flowrensicInterceptor } from './interceptor.js';
3
3
  export { createFlowrensicClient } from './client.js';
4
- export { replayFetchedSet, readReplaySet, listHistoryFiles, INDEX_NAME, } from './replay.js';
4
+ export { fetchReplaySet, readReplaySet, listHistoryFiles, publishVerdicts, INDEX_NAME, } from './replay.js';
5
5
  export { Outcome } from './gen/flowrensic/v1/activity_metrics_pb.js';
6
6
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAsC,MAAM,WAAW,CAAC;AAClF,OAAO,EAAE,6BAA6B,EAAE,qBAAqB,EAAE,MAAM,kBAAkB,CAAC;AACxF,OAAO,EAAE,sBAAsB,EAAyB,MAAM,aAAa,CAAC;AAC5E,OAAO,EACL,gBAAgB,EAChB,aAAa,EACb,gBAAgB,EAChB,UAAU,GAMX,MAAM,aAAa,CAAC;AAMrB,OAAO,EAAE,OAAO,EAAE,MAAM,4CAA4C,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAsC,MAAM,WAAW,CAAC;AAClF,OAAO,EAAE,6BAA6B,EAAE,qBAAqB,EAAE,MAAM,kBAAkB,CAAC;AACxF,OAAO,EAAE,sBAAsB,EAAyB,MAAM,aAAa,CAAC;AAC5E,OAAO,EACL,cAAc,EACd,aAAa,EACb,gBAAgB,EAChB,eAAe,EACf,UAAU,GAMX,MAAM,aAAa,CAAC;AAMrB,OAAO,EAAE,OAAO,EAAE,MAAM,4CAA4C,CAAC"}
package/dist/replay.d.ts CHANGED
@@ -1,6 +1,6 @@
1
- /** Manifest the CLI writes beside the histories it fetched. */
1
+ /** Manifest written beside the histories, the same one the CLI writes. */
2
2
  export declare const INDEX_NAME = "replay-set.json";
3
- /** One history on disk, as `flowrensic replay fetch` recorded it. */
3
+ /** One history on disk, with the metadata the server chose it by. */
4
4
  export interface ReplaySetEntry {
5
5
  readonly run_id: string;
6
6
  readonly file: string;
@@ -17,6 +17,18 @@ export interface ReplaySet {
17
17
  readonly server: string;
18
18
  readonly histories: readonly ReplaySetEntry[];
19
19
  }
20
+ export interface FetchOptions {
21
+ /** Flowrensic base URL, e.g. `http://flowrensic:8080`. */
22
+ baseUrl: string;
23
+ /** A set spans one workflow type, because that is what a replayer is built for. */
24
+ workflowType: string;
25
+ /** Directory to write the histories and the manifest into. */
26
+ dir: string;
27
+ /** Left out, the set spans every environment. */
28
+ deployEnv?: string;
29
+ /** Left out, the server picks how many. */
30
+ limit?: number;
31
+ }
20
32
  /** What one history did when replayed against the checkout under test. */
21
33
  export interface ReplayVerdict {
22
34
  readonly runId: string;
@@ -25,39 +37,33 @@ export interface ReplayVerdict {
25
37
  /** The replayer's own message, kept verbatim: it names what diverged. */
26
38
  readonly error?: string;
27
39
  }
28
- export interface ReplayReport {
29
- readonly total: number;
30
- readonly failed: number;
31
- readonly verdicts: readonly ReplayVerdict[];
32
- }
33
- export interface ReplayOptions {
34
- /** Directory `flowrensic replay fetch --out` wrote. */
35
- dir: string;
36
- /** The checkout's workflows, the same path a worker would be given. */
37
- workflowsPath: string;
40
+ export interface PublishOptions {
41
+ baseUrl: string;
38
42
  /**
39
- * The commit, tag or build under test. Only the pipeline knows it, and a
43
+ * The commit, tag or build replayed. Only the pipeline knows it, and a
40
44
  * verdict without one cannot be attributed to a change.
41
45
  */
42
46
  codeVersion: string;
43
- /**
44
- * Flowrensic server to report to. Left out, the replay still runs and the
45
- * report is returned but published nowhere.
46
- */
47
- baseUrl?: string;
48
- /** Extra worker options, for a project that needs its own data converter. */
49
- bundlerOptions?: Record<string, unknown>;
47
+ verdicts: readonly ReplayVerdict[];
50
48
  }
51
- export declare function readReplaySet(dir: string): Promise<ReplaySet>;
52
49
  /**
53
- * Replays every history in a fetched set against the workflows in this
54
- * checkout, and reports the verdicts.
50
+ * Fetches the set the server picks for a workflow type and writes it to disk.
51
+ *
52
+ * Which histories are worth replaying is the server's call, not the caller's.
53
+ * What comes down is the engine's own history, verbatim, so a replayer reads
54
+ * it the way the engine wrote it.
55
55
  *
56
- * The replay happens here, in the customer's own SDK, because that is the only
57
- * place the workflow code and its bundler exist. Flowrensic supplies the
58
- * histories and takes back what happened.
56
+ * Nothing here runs a workflow. Replay belongs to the suite that owns the
57
+ * code, through its own SDK, and `publishVerdicts` takes the outcome back.
59
58
  */
60
- export declare function replayFetchedSet(options: ReplayOptions): Promise<ReplayReport>;
59
+ export declare function fetchReplaySet(options: FetchOptions): Promise<ReplaySet>;
60
+ /** Reads a manifest a fetch left behind, the CLI's or this package's. */
61
+ export declare function readReplaySet(dir: string): Promise<ReplaySet>;
61
62
  /** Histories in a directory, for a caller that wants them without the index. */
62
63
  export declare function listHistoryFiles(dir: string): Promise<string[]>;
64
+ /**
65
+ * Reports what a replay found, against the history and the version replayed,
66
+ * so a break is attributed to a code change rather than to a failing test.
67
+ */
68
+ export declare function publishVerdicts(options: PublishOptions): Promise<void>;
63
69
  //# sourceMappingURL=replay.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"replay.d.ts","sourceRoot":"","sources":["../src/replay.ts"],"names":[],"mappings":"AAUA,+DAA+D;AAC/D,eAAO,MAAM,UAAU,oBAAoB,CAAC;AAE5C,qEAAqE;AACrE,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;CAC7B;AAED,MAAM,WAAW,SAAS;IACxB,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;IAC/B,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,SAAS,EAAE,SAAS,cAAc,EAAE,CAAC;CAC/C;AAED,0EAA0E;AAC1E,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC;IACzB,yEAAyE;IACzE,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;CACzB;AAED,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,QAAQ,EAAE,SAAS,aAAa,EAAE,CAAC;CAC7C;AAED,MAAM,WAAW,aAAa;IAC5B,uDAAuD;IACvD,GAAG,EAAE,MAAM,CAAC;IACZ,uEAAuE;IACvE,aAAa,EAAE,MAAM,CAAC;IACtB;;;OAGG;IACH,WAAW,EAAE,MAAM,CAAC;IACpB;;;OAGG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,6EAA6E;IAC7E,cAAc,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAC1C;AAQD,wBAAsB,aAAa,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,CAAC,CAOnE;AA+BD;;;;;;;GAOG;AACH,wBAAsB,gBAAgB,CAAC,OAAO,EAAE,aAAa,GAAG,OAAO,CAAC,YAAY,CAAC,CAoCpF;AAED,gFAAgF;AAChF,wBAAsB,gBAAgB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAGrE"}
1
+ {"version":3,"file":"replay.d.ts","sourceRoot":"","sources":["../src/replay.ts"],"names":[],"mappings":"AAQA,0EAA0E;AAC1E,eAAO,MAAM,UAAU,oBAAoB,CAAC;AAE5C,qEAAqE;AACrE,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;CAC7B;AAED,MAAM,WAAW,SAAS;IACxB,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;IAC/B,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,SAAS,EAAE,SAAS,cAAc,EAAE,CAAC;CAC/C;AAED,MAAM,WAAW,YAAY;IAC3B,0DAA0D;IAC1D,OAAO,EAAE,MAAM,CAAC;IAChB,mFAAmF;IACnF,YAAY,EAAE,MAAM,CAAC;IACrB,8DAA8D;IAC9D,GAAG,EAAE,MAAM,CAAC;IACZ,iDAAiD;IACjD,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,2CAA2C;IAC3C,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,0EAA0E;AAC1E,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC;IACzB,yEAAyE;IACzE,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;CACzB;AAED,MAAM,WAAW,cAAc;IAC7B,OAAO,EAAE,MAAM,CAAC;IAChB;;;OAGG;IACH,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,SAAS,aAAa,EAAE,CAAC;CACpC;AAqBD;;;;;;;;;GASG;AACH,wBAAsB,cAAc,CAAC,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC,SAAS,CAAC,CAmD9E;AAQD,yEAAyE;AACzE,wBAAsB,aAAa,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,CAAC,CAOnE;AAED,gFAAgF;AAChF,wBAAsB,gBAAgB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAGrE;AAED;;;GAGG;AACH,wBAAsB,eAAe,CAAC,OAAO,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC,CAiB5E"}
package/dist/replay.js CHANGED
@@ -1,12 +1,81 @@
1
- import { readFile, readdir } from 'node:fs/promises';
1
+ import { mkdir, readFile, readdir, rename, writeFile } from 'node:fs/promises';
2
2
  import { join } from 'node:path';
3
- // Node ESM needs the extension on a subpath of a package that declares no
4
- // `exports`, and `historyFromJSON` is not on the package's own entry point.
5
- import { historyFromJSON } from '@temporalio/common/lib/proto-utils.js';
6
- import { Worker } from '@temporalio/worker';
3
+ import { timestampDate, timestampFromDate } from '@bufbuild/protobuf/wkt';
7
4
  import { createFlowrensicClient } from './client.js';
8
- /** Manifest the CLI writes beside the histories it fetched. */
5
+ import { RunStatus } from './gen/flowrensic/v1/replay_pb.js';
6
+ /** Manifest written beside the histories, the same one the CLI writes. */
9
7
  export const INDEX_NAME = 'replay-set.json';
8
+ // A manifest reads `completed`, the same label the CLI writes. A table rather
9
+ // than a reverse enum lookup, so adding a status is a compile error here.
10
+ const STATUS_LABELS = {
11
+ [RunStatus.UNSPECIFIED]: 'unspecified',
12
+ [RunStatus.RUNNING]: 'running',
13
+ [RunStatus.COMPLETED]: 'completed',
14
+ [RunStatus.FAILED]: 'failed',
15
+ [RunStatus.CANCELED]: 'canceled',
16
+ [RunStatus.TERMINATED]: 'terminated',
17
+ [RunStatus.TIMED_OUT]: 'timed_out',
18
+ [RunStatus.CONTINUED_AS_NEW]: 'continued_as_new',
19
+ [RunStatus.PAUSED]: 'paused',
20
+ };
21
+ function historyUrl(baseUrl, path) {
22
+ const base = baseUrl.endsWith('/') ? baseUrl : `${baseUrl}/`;
23
+ return new URL(path.replace(/^\//, ''), base);
24
+ }
25
+ /**
26
+ * Fetches the set the server picks for a workflow type and writes it to disk.
27
+ *
28
+ * Which histories are worth replaying is the server's call, not the caller's.
29
+ * What comes down is the engine's own history, verbatim, so a replayer reads
30
+ * it the way the engine wrote it.
31
+ *
32
+ * Nothing here runs a workflow. Replay belongs to the suite that owns the
33
+ * code, through its own SDK, and `publishVerdicts` takes the outcome back.
34
+ */
35
+ export async function fetchReplaySet(options) {
36
+ const { baseUrl, workflowType, dir, deployEnv, limit } = options;
37
+ const client = createFlowrensicClient(baseUrl);
38
+ const found = await client.query.listReplayHistories({
39
+ workflowType,
40
+ deployEnv: deployEnv ?? '',
41
+ limit: limit ?? 0,
42
+ });
43
+ // An empty set is not an error: a workflow type with no runs yet is a normal
44
+ // state on a new pipeline, and the caller decides what to do about it.
45
+ await mkdir(dir, { recursive: true, mode: 0o750 });
46
+ const histories = [];
47
+ for (const history of found.histories) {
48
+ const file = `${history.runId}.json`;
49
+ const response = await fetch(historyUrl(baseUrl, history.url));
50
+ if (!response.ok) {
51
+ const body = (await response.text()).slice(0, 512).trim();
52
+ throw new Error(`history ${history.runId}: status ${String(response.status)}: ${body}`);
53
+ }
54
+ // Written and renamed, so a failed fetch never leaves a half history for a
55
+ // replayer to read as a non-determinism report.
56
+ const temp = join(dir, `.fetch-${history.runId}`);
57
+ await writeFile(temp, Buffer.from(await response.arrayBuffer()), { mode: 0o600 });
58
+ await rename(temp, join(dir, file));
59
+ histories.push({
60
+ run_id: history.runId,
61
+ file,
62
+ status: STATUS_LABELS[history.status],
63
+ ...(history.deployEnv === '' ? {} : { deploy_env: history.deployEnv }),
64
+ events: history.events,
65
+ started_at: (history.startedAt ? timestampDate(history.startedAt) : new Date(0)).toISOString(),
66
+ ...(history.closedAt ? { closed_at: timestampDate(history.closedAt).toISOString() } : {}),
67
+ });
68
+ }
69
+ const set = {
70
+ workflow_type: workflowType,
71
+ ...(deployEnv === undefined || deployEnv === '' ? {} : { deploy_env: deployEnv }),
72
+ fetched_at: new Date().toISOString(),
73
+ server: baseUrl,
74
+ histories,
75
+ };
76
+ await writeFile(join(dir, INDEX_NAME), `${JSON.stringify(set, null, 2)}\n`, { mode: 0o600 });
77
+ return set;
78
+ }
10
79
  function isReplaySet(value) {
11
80
  if (typeof value !== 'object' || value === null)
12
81
  return false;
@@ -14,6 +83,7 @@ function isReplaySet(value) {
14
83
  return false;
15
84
  return 'histories' in value && Array.isArray(value.histories);
16
85
  }
86
+ /** Reads a manifest a fetch left behind, the CLI's or this package's. */
17
87
  export async function readReplaySet(dir) {
18
88
  const path = join(dir, INDEX_NAME);
19
89
  const parsed = JSON.parse(await readFile(path, 'utf8'));
@@ -22,17 +92,21 @@ export async function readReplaySet(dir) {
22
92
  }
23
93
  return parsed;
24
94
  }
25
- /** protobuf Timestamp, which connect-es takes as seconds plus nanos. */
26
- function timestampFrom(at) {
27
- const ms = at.getTime();
28
- return {
29
- seconds: BigInt(Math.floor(ms / 1000)),
30
- nanos: (ms % 1000) * 1_000_000,
31
- };
95
+ /** Histories in a directory, for a caller that wants them without the index. */
96
+ export async function listHistoryFiles(dir) {
97
+ const names = await readdir(dir);
98
+ return names.filter((n) => n.endsWith('.json') && n !== INDEX_NAME).sort();
32
99
  }
33
- async function publishVerdicts(baseUrl, codeVersion, verdicts) {
100
+ /**
101
+ * Reports what a replay found, against the history and the version replayed,
102
+ * so a break is attributed to a code change rather than to a failing test.
103
+ */
104
+ export async function publishVerdicts(options) {
105
+ const { baseUrl, codeVersion, verdicts } = options;
106
+ if (verdicts.length === 0)
107
+ return;
34
108
  const client = createFlowrensicClient(baseUrl);
35
- const replayedAt = new Date();
109
+ const replayedAt = timestampFromDate(new Date());
36
110
  await client.ingest.ingestReplayResults({
37
111
  results: verdicts.map((v) => ({
38
112
  runId: v.runId,
@@ -40,54 +114,8 @@ async function publishVerdicts(baseUrl, codeVersion, verdicts) {
40
114
  workflowType: v.workflowType,
41
115
  passed: v.passed,
42
116
  error: v.error ?? '',
43
- replayedAt: timestampFrom(replayedAt),
117
+ replayedAt,
44
118
  })),
45
119
  });
46
120
  }
47
- /**
48
- * Replays every history in a fetched set against the workflows in this
49
- * checkout, and reports the verdicts.
50
- *
51
- * The replay happens here, in the customer's own SDK, because that is the only
52
- * place the workflow code and its bundler exist. Flowrensic supplies the
53
- * histories and takes back what happened.
54
- */
55
- export async function replayFetchedSet(options) {
56
- const { dir, workflowsPath, codeVersion, baseUrl, bundlerOptions } = options;
57
- const set = await readReplaySet(dir);
58
- const verdicts = [];
59
- for (const entry of set.histories) {
60
- const parsed = JSON.parse(await readFile(join(dir, entry.file), 'utf8'));
61
- const history = historyFromJSON(parsed);
62
- try {
63
- await Worker.runReplayHistory({ workflowsPath, ...bundlerOptions }, history, entry.run_id);
64
- verdicts.push({ runId: entry.run_id, workflowType: set.workflow_type, passed: true });
65
- }
66
- catch (err) {
67
- // Any throw is a failed replay. The replayer distinguishes determinism
68
- // violations from other errors, but both mean this history no longer
69
- // runs on this code, which is the thing CI needs told.
70
- verdicts.push({
71
- runId: entry.run_id,
72
- workflowType: set.workflow_type,
73
- passed: false,
74
- error: err instanceof Error ? err.message : String(err),
75
- });
76
- }
77
- }
78
- const report = {
79
- total: verdicts.length,
80
- failed: verdicts.filter((v) => !v.passed).length,
81
- verdicts,
82
- };
83
- if (baseUrl !== undefined && verdicts.length > 0) {
84
- await publishVerdicts(baseUrl, codeVersion, verdicts);
85
- }
86
- return report;
87
- }
88
- /** Histories in a directory, for a caller that wants them without the index. */
89
- export async function listHistoryFiles(dir) {
90
- const names = await readdir(dir);
91
- return names.filter((n) => n.endsWith('.json') && n !== INDEX_NAME).sort();
92
- }
93
121
  //# sourceMappingURL=replay.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"replay.js","sourceRoot":"","sources":["../src/replay.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"replay.js","sourceRoot":"","sources":["../src/replay.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@flowrensic/node",
3
- "version": "0.1.2",
4
- "description": "Replay runner and activity interceptor for Temporal workers, for use with Flowrensic.",
3
+ "version": "0.2.0",
4
+ "description": "Replay history fetch and activity interceptor for Temporal workers, for use with Flowrensic.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
7
7
  "exports": {