@flow-as-code/cli 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (120) hide show
  1. package/LICENSE +202 -0
  2. package/README.md +446 -0
  3. package/dist/aws.d.ts +28 -0
  4. package/dist/aws.d.ts.map +1 -0
  5. package/dist/aws.js +104 -0
  6. package/dist/aws.js.map +1 -0
  7. package/dist/bin.d.ts +3 -0
  8. package/dist/bin.d.ts.map +1 -0
  9. package/dist/bin.js +132 -0
  10. package/dist/bin.js.map +1 -0
  11. package/dist/bridge/exportFiles.d.ts +16 -0
  12. package/dist/bridge/exportFiles.d.ts.map +1 -0
  13. package/dist/bridge/exportFiles.js +95 -0
  14. package/dist/bridge/exportFiles.js.map +1 -0
  15. package/dist/bridge/pair.d.ts +103 -0
  16. package/dist/bridge/pair.d.ts.map +1 -0
  17. package/dist/bridge/pair.js +219 -0
  18. package/dist/bridge/pair.js.map +1 -0
  19. package/dist/bridge/protocol.d.ts +187 -0
  20. package/dist/bridge/protocol.d.ts.map +1 -0
  21. package/dist/bridge/protocol.js +132 -0
  22. package/dist/bridge/protocol.js.map +1 -0
  23. package/dist/bridge/server.d.ts +95 -0
  24. package/dist/bridge/server.d.ts.map +1 -0
  25. package/dist/bridge/server.js +669 -0
  26. package/dist/bridge/server.js.map +1 -0
  27. package/dist/cdk-scaffold.d.ts +16 -0
  28. package/dist/cdk-scaffold.d.ts.map +1 -0
  29. package/dist/cdk-scaffold.js +28 -0
  30. package/dist/cdk-scaffold.js.map +1 -0
  31. package/dist/codegen.d.ts +5 -0
  32. package/dist/codegen.d.ts.map +1 -0
  33. package/dist/codegen.js +27 -0
  34. package/dist/codegen.js.map +1 -0
  35. package/dist/diff.d.ts +33 -0
  36. package/dist/diff.d.ts.map +1 -0
  37. package/dist/diff.js +225 -0
  38. package/dist/diff.js.map +1 -0
  39. package/dist/docs.d.ts +46 -0
  40. package/dist/docs.d.ts.map +1 -0
  41. package/dist/docs.js +223 -0
  42. package/dist/docs.js.map +1 -0
  43. package/dist/emit.d.ts +8 -0
  44. package/dist/emit.d.ts.map +1 -0
  45. package/dist/emit.js +55 -0
  46. package/dist/emit.js.map +1 -0
  47. package/dist/errors.d.ts +12 -0
  48. package/dist/errors.d.ts.map +1 -0
  49. package/dist/errors.js +25 -0
  50. package/dist/errors.js.map +1 -0
  51. package/dist/export.d.ts +27 -0
  52. package/dist/export.d.ts.map +1 -0
  53. package/dist/export.js +126 -0
  54. package/dist/export.js.map +1 -0
  55. package/dist/index.d.ts +4 -0
  56. package/dist/index.d.ts.map +1 -0
  57. package/dist/index.js +23 -0
  58. package/dist/index.js.map +1 -0
  59. package/dist/lint.d.ts +6 -0
  60. package/dist/lint.d.ts.map +1 -0
  61. package/dist/lint.js +31 -0
  62. package/dist/lint.js.map +1 -0
  63. package/dist/render.d.ts +6 -0
  64. package/dist/render.d.ts.map +1 -0
  65. package/dist/render.js +49 -0
  66. package/dist/render.js.map +1 -0
  67. package/dist/run.d.ts +13 -0
  68. package/dist/run.d.ts.map +1 -0
  69. package/dist/run.js +38 -0
  70. package/dist/run.js.map +1 -0
  71. package/dist/simulate.d.ts +35 -0
  72. package/dist/simulate.d.ts.map +1 -0
  73. package/dist/simulate.js +194 -0
  74. package/dist/simulate.js.map +1 -0
  75. package/dist/studio.d.ts +23 -0
  76. package/dist/studio.d.ts.map +1 -0
  77. package/dist/studio.js +120 -0
  78. package/dist/studio.js.map +1 -0
  79. package/dist/synth-resolve-hook.d.ts +19 -0
  80. package/dist/synth-resolve-hook.d.ts.map +1 -0
  81. package/dist/synth-resolve-hook.js +127 -0
  82. package/dist/synth-resolve-hook.js.map +1 -0
  83. package/dist/synth-runner.d.ts +12 -0
  84. package/dist/synth-runner.d.ts.map +1 -0
  85. package/dist/synth-runner.js +145 -0
  86. package/dist/synth-runner.js.map +1 -0
  87. package/dist/synth.d.ts +55 -0
  88. package/dist/synth.d.ts.map +1 -0
  89. package/dist/synth.js +327 -0
  90. package/dist/synth.js.map +1 -0
  91. package/dist/watch.d.ts +66 -0
  92. package/dist/watch.d.ts.map +1 -0
  93. package/dist/watch.js +293 -0
  94. package/dist/watch.js.map +1 -0
  95. package/package.json +85 -0
  96. package/schema/flowdoc-0.1.schema.json +669 -0
  97. package/schema/scenario-0.1.schema.json +318 -0
  98. package/src/aws.ts +149 -0
  99. package/src/bin.ts +179 -0
  100. package/src/bridge/exportFiles.ts +116 -0
  101. package/src/bridge/pair.ts +312 -0
  102. package/src/bridge/protocol.ts +289 -0
  103. package/src/bridge/server.ts +827 -0
  104. package/src/cdk-scaffold.ts +41 -0
  105. package/src/codegen.ts +36 -0
  106. package/src/diff.ts +279 -0
  107. package/src/docs.ts +249 -0
  108. package/src/emit.ts +69 -0
  109. package/src/errors.ts +27 -0
  110. package/src/export.ts +167 -0
  111. package/src/index.ts +27 -0
  112. package/src/lint.ts +42 -0
  113. package/src/render.ts +58 -0
  114. package/src/run.ts +42 -0
  115. package/src/simulate.ts +244 -0
  116. package/src/studio.ts +143 -0
  117. package/src/synth-resolve-hook.ts +152 -0
  118. package/src/synth-runner.ts +157 -0
  119. package/src/synth.ts +380 -0
  120. package/src/watch.ts +388 -0
package/dist/synth.js ADDED
@@ -0,0 +1,327 @@
1
+ /*
2
+ * Copyright 2026 The flow-as-code Authors
3
+ * SPDX-License-Identifier: Apache-2.0
4
+ */
5
+ // `flow-cli synth`: execute a TypeScript builder file in a sandboxed child
6
+ // process and turn its exported flows into FlowDoc JSON.
7
+ //
8
+ // The builder file NEVER runs in the CLI process. It runs in a spawned node
9
+ // with tsx registered via --import, a stripped environment, cwd set to the
10
+ // source file's directory, and (where the runtime supports it) Node's
11
+ // permission model enabled.
12
+ //
13
+ // What the sandbox does and does not enforce, verified on node 25.9.0
14
+ // (https://nodejs.org/api/permissions.html):
15
+ //
16
+ // - File WRITES are denied everywhere except a private temp directory the
17
+ // parent creates for tsx's own cache/pipe files (tsx honors TMPDIR). The
18
+ // child never writes FlowDocs; it prints them on stdout and the parent
19
+ // writes the files.
20
+ // - child_process and cluster are denied (--allow-child-process not passed).
21
+ // - Worker threads ARE allowed (--allow-worker): tsx registers its module
22
+ // hooks on a loader thread, which the permission model counts as a worker.
23
+ // Node warns that this weakens the model; the workers a builder file could
24
+ // start still inherit the same fs restrictions.
25
+ // - File READS are NOT jailed. Scoped --allow-fs-read breaks tsx: its
26
+ // tsconfig discovery walks every ancestor directory and probes
27
+ // case-variant paths on macOS, each of which the permission model treats
28
+ // as a distinct denied resource. We therefore pass --allow-fs-read=* and
29
+ // a builder file can read anything the invoking user can.
30
+ // - NETWORK: the permission model on Node 22/24 does not cover network
31
+ // access at all (https://nodejs.org/api/permissions.html), so no network
32
+ // jail exists there. Newer runtimes (observed on node 25.9.0) deny network
33
+ // by default under --permission because a net permission exists and we do
34
+ // not grant it. Do not rely on the sandbox to block exfiltration on the
35
+ // CI-supported Node 22/24.
36
+ // - On runtimes without the stable --permission flag (Node < 22.13, which
37
+ // includes 22.12, the engines.node floor), the permission model is not
38
+ // applied at all; the sandbox is then only the stripped environment, the
39
+ // pinned cwd, and process isolation. If a spawn still fails with "bad
40
+ // option" we retry once without the permission flags and remember that for
41
+ // the process lifetime.
42
+ import { spawn } from "node:child_process";
43
+ import { createHash } from "node:crypto";
44
+ import { existsSync, realpathSync } from "node:fs";
45
+ import { mkdir, mkdtemp, readFile, rm, writeFile } from "node:fs/promises";
46
+ import { createRequire } from "node:module";
47
+ import { tmpdir } from "node:os";
48
+ import { dirname, join, resolve } from "node:path";
49
+ import { fileURLToPath } from "node:url";
50
+ import { SLUG_PATTERN, serialize } from "@flow-as-code/core";
51
+ /** Recorded in meta.generator of every FlowDoc this CLI writes. */
52
+ export const GENERATOR = "cli@0.0.1";
53
+ const SENTINEL = "__FLOW_CLI_SYNTH_ENVELOPE_V1__";
54
+ /** A synth failure with a message meant for the terminal. */
55
+ export class SynthError extends Error {
56
+ }
57
+ /**
58
+ * Where a stack frame points, with the `:line:column` suffix taken off.
59
+ *
60
+ * V8 writes a frame as `at <name> (<location>)` when it has a function name to
61
+ * report and as `at <location>` when it does not, so the location is the last
62
+ * parenthesised run of the line or, failing that, everything after `at `. The
63
+ * result is a path, a `file:` URL, a `node:` specifier, or (for the nameless
64
+ * `at Object.<anonymous>` form) something that is none of those.
65
+ */
66
+ function frameLocation(line) {
67
+ const parenthesised = /\(([^()]*)\)\s*$/.exec(line)?.[1];
68
+ const location = parenthesised ?? line.replace(/^\s*at\s+/, "");
69
+ return location.replace(/:\d+:\d+$/, "");
70
+ }
71
+ /** Whether a location has `node_modules` as a whole path segment. */
72
+ function underNodeModules(location) {
73
+ // Both separators: a Windows stack reads `at fn (C:\w\node_modules\x\y.js:1:1)`.
74
+ return location.split(/[/\\]/).includes("node_modules");
75
+ }
76
+ /**
77
+ * A frame location as one comparable path, or undefined when it names no file.
78
+ *
79
+ * A stack spells the same file three ways: the plain path a compiled frame
80
+ * carries, the `file:` URL the ESM loader produces, and either separator
81
+ * depending on the platform. Symlinks are the fourth: the loader reports the
82
+ * real path, while a caller holding the path the user typed may still be
83
+ * looking at the link (on macOS `/tmp/x` is really `/private/tmp/x`). So both
84
+ * sides go through realpath, and a path that does not resolve (a stack from
85
+ * another machine, a fixture) falls back to itself rather than throwing.
86
+ */
87
+ function comparablePath(location) {
88
+ let asPath = location;
89
+ if (/^file:/i.test(asPath)) {
90
+ try {
91
+ asPath = fileURLToPath(asPath);
92
+ }
93
+ catch {
94
+ return undefined;
95
+ }
96
+ }
97
+ let real = asPath;
98
+ try {
99
+ real = realpathSync(asPath);
100
+ }
101
+ catch {
102
+ // Not a path on this machine; compare the literal text instead.
103
+ }
104
+ return real.replace(/\\/g, "/");
105
+ }
106
+ /**
107
+ * The frames of a thrown value's stack that point at the user's own code.
108
+ *
109
+ * A syntax error in a builder file used to print the actionable line and then
110
+ * ten frames of esbuild and node stream internals under it
111
+ * (`at failureErrorWithLog (.../node_modules/esbuild/lib/main.js:1752:15)`,
112
+ * `at Pipe.onStreamRead (node:internal/stream_base_commons:191:23)`), which buries
113
+ * the file, line and column that the message above already names. The studio's
114
+ * badge shows only the first line for the same reason; the terminal now matches
115
+ * that intent.
116
+ *
117
+ * Frames inside node_modules and node's own internals are dropped, and so are
118
+ * the header lines the stack repeats from the message that is printed above it.
119
+ * A frame in the builder file or anywhere else the user wrote survives, because
120
+ * that is the one a runtime error in a flow needs. There is no verbose flag or
121
+ * env var in this CLI to hide the full stack behind, so what is dropped here is
122
+ * dropped: the retained frames plus the message carry the location.
123
+ *
124
+ * `builderPath` is the file being synthesized. Its own frames are kept even
125
+ * when it sits under a directory named node_modules, which a vendored or
126
+ * linked builder file legitimately does: the node_modules rule is about
127
+ * dependency code, and the file the user asked to run is never that. Without
128
+ * the exemption such a file reports a throw with no line or column at all.
129
+ */
130
+ export function actionableFrames(stack, builderPath) {
131
+ if (stack === undefined)
132
+ return [];
133
+ const builder = builderPath === undefined ? undefined : comparablePath(resolve(builderPath));
134
+ return (stack
135
+ .split("\n")
136
+ .filter((line) => /^\s*at /.test(line))
137
+ // Vendor frames go by where the frame points, not by the text of the
138
+ // whole line. A substring test over the line drops a frame whose
139
+ // function name happens to read `loadNodeModules` or whose builder file
140
+ // sits in a directory called `node_modules-sandbox`, and those are the
141
+ // frames this function exists to keep. The segment test is what makes
142
+ // `node_modules` mean the dependency tree rather than eleven characters.
143
+ // The builder file itself is exempt: it is the user's own code wherever
144
+ // it lives.
145
+ .filter((line) => {
146
+ const location = frameLocation(line);
147
+ if (!underNodeModules(location))
148
+ return true;
149
+ return builder !== undefined && comparablePath(location) === builder;
150
+ })
151
+ // What is left must name a file on disk. That drops node's own frames,
152
+ // whose location is a `node:internal/...` specifier rather than a path
153
+ // (`at addChunk (node:internal/streams/readable:559:12)`), and the bare
154
+ // `at Object.<anonymous>` form that carries no location at all. Neither
155
+ // says anything about the user's flow.
156
+ .filter((line) => /[(\s](\/|[A-Za-z]:\\|file:)/.test(line)));
157
+ }
158
+ export function sha256Hex(bytes) {
159
+ return createHash("sha256").update(bytes).digest("hex");
160
+ }
161
+ function resolveSibling(base) {
162
+ // Compiled layout: dist/<base>.js next to dist/synth.js. Under vitest this
163
+ // module runs from src/, where only the .ts exists; the child runs under
164
+ // tsx either way, so both are executable.
165
+ const here = dirname(fileURLToPath(import.meta.url));
166
+ const js = join(here, `${base}.js`);
167
+ if (existsSync(js))
168
+ return js;
169
+ const ts = join(here, `${base}.ts`);
170
+ if (existsSync(ts))
171
+ return ts;
172
+ throw new SynthError(`flow-cli is broken: ${base} not found next to ${here}`);
173
+ }
174
+ function resolveTsxLoader() {
175
+ // tsx's package export "." is dist/loader.mjs, the --import registration.
176
+ return createRequire(import.meta.url).resolve("tsx");
177
+ }
178
+ function supportsStablePermissionFlag() {
179
+ // --permission is stable from Node 23.5 and was backported to 22.13.
180
+ // https://nodejs.org/api/permissions.html
181
+ const [major = 0, minor = 0] = process.versions.node.split(".").map(Number);
182
+ return major >= 23 || (major === 22 && minor >= 13);
183
+ }
184
+ /** Set after a sandbox retry so we do not pay the failed spawn twice. */
185
+ let permissionFlagsUnsupported = false;
186
+ /**
187
+ * True when the sandbox stopped the child before our runner produced anything.
188
+ *
189
+ * A denial raised by the USER's flow code must not trigger the retry: that
190
+ * would silently drop the sandbox for exactly the input it is protecting
191
+ * against. So this only matches a failure with no envelope on stdout, meaning
192
+ * the runner never got far enough to report.
193
+ */
194
+ function sandboxRefusedToStart(result) {
195
+ if (parseEnvelope(result.stdout) !== undefined)
196
+ return false;
197
+ if (result.code === 9 && result.stderr.includes("bad option"))
198
+ return true;
199
+ return (result.stderr.includes("ERR_ACCESS_DENIED") || result.stderr.includes("ERR_DLOPEN_DISABLED"));
200
+ }
201
+ function runChild(args, cwd, env) {
202
+ return new Promise((resolveP, rejectP) => {
203
+ const child = spawn(process.execPath, args, { cwd, env, stdio: ["ignore", "pipe", "pipe"] });
204
+ let stdout = "";
205
+ let stderr = "";
206
+ child.stdout.on("data", (d) => (stdout += d.toString("utf8")));
207
+ child.stderr.on("data", (d) => (stderr += d.toString("utf8")));
208
+ child.on("error", rejectP);
209
+ child.on("close", (code) => resolveP({ code, stdout, stderr }));
210
+ });
211
+ }
212
+ function parseEnvelope(stdout) {
213
+ // The envelope is the last sentinel-prefixed line; user code writing to
214
+ // stdout during module evaluation cannot fake or corrupt it earlier.
215
+ const lines = stdout.split("\n");
216
+ for (let i = lines.length - 1; i >= 0; i--) {
217
+ const line = lines[i];
218
+ if (line !== undefined && line.startsWith(SENTINEL)) {
219
+ return JSON.parse(line.slice(SENTINEL.length));
220
+ }
221
+ }
222
+ return undefined;
223
+ }
224
+ /**
225
+ * Evaluates the builder file in the sandboxed child and returns its flows.
226
+ * Throws SynthError with an actionable message on any failure.
227
+ */
228
+ export async function synthFile(sourcePath) {
229
+ const absPath = resolve(sourcePath);
230
+ let sourceBytes;
231
+ try {
232
+ sourceBytes = await readFile(absPath);
233
+ }
234
+ catch {
235
+ throw new SynthError(`Cannot read ${absPath}: no such file. Pass the path of a .flow.ts builder file.`);
236
+ }
237
+ const sourceHash = `sha256:${sha256Hex(sourceBytes)}`;
238
+ const runner = resolveSibling("synth-runner");
239
+ const resolveHook = resolveSibling("synth-resolve-hook");
240
+ const loader = resolveTsxLoader();
241
+ const sourceDir = dirname(absPath);
242
+ // Private scratch dir for tsx (it writes a cache and an IPC pipe under
243
+ // os.tmpdir(), which honors TMPDIR/TEMP/TMP). This is the only path the
244
+ // permission model allows the child to write.
245
+ const scratch = await mkdtemp(join(tmpdir(), "flow-cli-synth-"));
246
+ const permissionArgs = supportsStablePermissionFlag() && !permissionFlagsUnsupported
247
+ ? ["--permission", "--allow-fs-read=*", `--allow-fs-write=${scratch}/`, "--allow-worker"]
248
+ : [];
249
+ // argv after the runner: the builder file, the resolution hook the runner
250
+ // registers before importing it, and the module URL that hook falls back to
251
+ // when the builder's own directory cannot resolve @flow-as-code/core. See
252
+ // synth-resolve-hook.ts.
253
+ const baseArgs = ["--import", loader, runner, absPath, resolveHook, import.meta.url];
254
+ const env = {
255
+ // Minimum the child needs: PATH for anything resolving binaries plus the
256
+ // temp override for tsx. Deliberately no NODE_OPTIONS, no AWS_*, no
257
+ // HOME-derived config.
258
+ PATH: process.env.PATH,
259
+ TMPDIR: scratch,
260
+ TEMP: scratch,
261
+ TMP: scratch,
262
+ };
263
+ try {
264
+ let result = await runChild([...permissionArgs, ...baseArgs], sourceDir, env);
265
+ if (permissionArgs.length > 0 && sandboxRefusedToStart(result)) {
266
+ // Two ways the permission model can stop the child from ever running our
267
+ // code: the runtime does not know the flags, or the TypeScript loader
268
+ // needs a capability we withheld (some versions shell out to compile).
269
+ // Both are environment problems rather than problems with the user's
270
+ // flow, so we retry unsandboxed rather than failing outright, and say so.
271
+ permissionFlagsUnsupported = true;
272
+ process.emitWarning("flow-cli synth: this runtime's permission model rejected the sandbox, " +
273
+ "so the builder file is being evaluated WITHOUT it. Environment stripping " +
274
+ "and the pinned working directory still apply. Upgrade Node to restore the sandbox.");
275
+ result = await runChild(baseArgs, sourceDir, env);
276
+ }
277
+ const envelope = parseEnvelope(result.stdout);
278
+ if (envelope === undefined) {
279
+ const detail = result.stderr.trim();
280
+ throw new SynthError(`Evaluating ${absPath} failed (exit code ${result.code ?? "unknown"}).` +
281
+ (detail === "" ? "" : `\n${detail}`));
282
+ }
283
+ if (envelope.error !== undefined) {
284
+ const frames = actionableFrames(envelope.error.stack, absPath);
285
+ throw new SynthError(`Evaluating ${absPath} threw: ${envelope.error.message}` +
286
+ (frames.length === 0 ? "" : `\n${frames.join("\n")}`));
287
+ }
288
+ const flows = envelope.flows ?? [];
289
+ if (flows.length === 0) {
290
+ throw new SynthError(`No flows exported from ${absPath}. Export a Flow instance or a zero-argument ` +
291
+ `function returning one (e.g. "export function myLine(): Flow { ... }").`);
292
+ }
293
+ return { flows, sourceHash };
294
+ }
295
+ finally {
296
+ await rm(scratch, { recursive: true, force: true });
297
+ }
298
+ }
299
+ /** Serializes a doc with the meta this CLI stamps. Byte-stable. */
300
+ export function serializeWithMeta(doc, sourceHash) {
301
+ return serialize({ ...doc, meta: { generator: GENERATOR, sourceHash } });
302
+ }
303
+ /**
304
+ * The `flow-cli synth` command body: synth every flow the file exports and
305
+ * write <flow.name>.flowdoc.json into outDir (default: the source file's
306
+ * directory). Returns the written paths in write order.
307
+ */
308
+ export async function synthToFiles(sourcePath, outDir) {
309
+ const absPath = resolve(sourcePath);
310
+ const dir = outDir === undefined ? dirname(absPath) : resolve(outDir);
311
+ const { flows, sourceHash } = await synthFile(absPath);
312
+ await mkdir(dir, { recursive: true });
313
+ const written = [];
314
+ for (const { name, doc } of flows) {
315
+ // The Flow constructor already rejects non-slug names, but the child
316
+ // process output is untrusted (a hostile module can fake a duck-typed
317
+ // Flow), so the name is re-checked here before it becomes a file path.
318
+ if (!SLUG_PATTERN.test(name)) {
319
+ throw new Error(`Refusing to write flow named "${name}": names must be lowercase words separated by single hyphens.`);
320
+ }
321
+ const docPath = join(dir, `${name}.flowdoc.json`);
322
+ await writeFile(docPath, serializeWithMeta(doc, sourceHash), "utf8");
323
+ written.push(docPath);
324
+ }
325
+ return written;
326
+ }
327
+ //# sourceMappingURL=synth.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"synth.js","sourceRoot":"","sources":["../src/synth.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,66 @@
1
+ import type { FlowDoc } from "@flow-as-code/core";
2
+ export interface SyncedEvent {
3
+ tsPath: string;
4
+ docPath: string;
5
+ name: string;
6
+ }
7
+ export interface ConflictEvent {
8
+ tsPath: string;
9
+ docPath: string;
10
+ name: string;
11
+ reason: string;
12
+ }
13
+ export interface ErrorEvent {
14
+ path: string;
15
+ message: string;
16
+ }
17
+ export interface WatcherEvents {
18
+ synced: SyncedEvent;
19
+ conflict: ConflictEvent;
20
+ error: ErrorEvent;
21
+ /** Initial scan finished and every startup synth settled. Not part of the
22
+ * A04 event contract; a convenience for consumers and tests. */
23
+ ready: Record<string, never>;
24
+ }
25
+ export interface FlowWatcher {
26
+ on<K extends keyof WatcherEvents>(event: K, listener: (payload: WatcherEvents[K]) => void): this;
27
+ off<K extends keyof WatcherEvents>(event: K, listener: (payload: WatcherEvents[K]) => void): this;
28
+ once<K extends keyof WatcherEvents>(event: K, listener: (payload: WatcherEvents[K]) => void): this;
29
+ /**
30
+ * Records a pair another part of this process just wrote as the clean
31
+ * baseline, so the watcher recognizes the write as its own instead of
32
+ * treating it as an external edit.
33
+ *
34
+ * The studio bridge (A11) writes both halves of a pair when the canvas
35
+ * saves: the FlowDoc and the regenerated builder source. Without this the
36
+ * watcher would see a ts change whose doc "changed externally" and emit a
37
+ * conflict for an edit the same process just made.
38
+ *
39
+ * Pass the exact bytes written. Call it AFTER both files are on disk:
40
+ * chokidar's awaitWriteFinish window (50 ms) is orders of magnitude longer
41
+ * than the gap between the writes and this call, so no event can be routed
42
+ * against a half-updated ledger. Contents that are not passed leave that
43
+ * half of the ledger alone.
44
+ */
45
+ noteWrite(name: string, contents: {
46
+ tsContent?: string;
47
+ docContent?: string;
48
+ }): void;
49
+ close(): Promise<void>;
50
+ }
51
+ /**
52
+ * The flow whose name matches the file base name, else a lone export. Exported
53
+ * so the studio bridge pairs a builder file with its FlowDoc by exactly the
54
+ * rule the watcher uses, rather than a second one that could disagree.
55
+ */
56
+ export declare function pickDoc(flows: {
57
+ name: string;
58
+ doc: FlowDoc;
59
+ }[], name: string): FlowDoc | undefined;
60
+ /**
61
+ * Watches `dir` (non-recursive) and keeps every <name>.flow.ts /
62
+ * <name>.flowdoc.json pair in sync, ts -> doc, with the sourceHash dirty
63
+ * guard described at the top of this file.
64
+ */
65
+ export declare function createWatcher(dir: string): FlowWatcher;
66
+ //# sourceMappingURL=watch.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"watch.d.ts","sourceRoot":"","sources":["../src/watch.ts"],"names":[],"mappings":"AA6BA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,oBAAoB,CAAC;AAMlD,MAAM,WAAW,WAAW;IAC1B,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,aAAa;IAC5B,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,aAAa;IAC5B,MAAM,EAAE,WAAW,CAAC;IACpB,QAAQ,EAAE,aAAa,CAAC;IACxB,KAAK,EAAE,UAAU,CAAC;IAClB;oEACgE;IAChE,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC;CAC9B;AAED,MAAM,WAAW,WAAW;IAC1B,EAAE,CAAC,CAAC,SAAS,MAAM,aAAa,EAAE,KAAK,EAAE,CAAC,EAAE,QAAQ,EAAE,CAAC,OAAO,EAAE,aAAa,CAAC,CAAC,CAAC,KAAK,IAAI,GAAG,IAAI,CAAC;IACjG,GAAG,CAAC,CAAC,SAAS,MAAM,aAAa,EAAE,KAAK,EAAE,CAAC,EAAE,QAAQ,EAAE,CAAC,OAAO,EAAE,aAAa,CAAC,CAAC,CAAC,KAAK,IAAI,GAAG,IAAI,CAAC;IAClG,IAAI,CAAC,CAAC,SAAS,MAAM,aAAa,EAChC,KAAK,EAAE,CAAC,EACR,QAAQ,EAAE,CAAC,OAAO,EAAE,aAAa,CAAC,CAAC,CAAC,KAAK,IAAI,GAC5C,IAAI,CAAC;IACR;;;;;;;;;;;;;;;OAeG;IACH,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE;QAAE,SAAS,CAAC,EAAE,MAAM,CAAC;QAAC,UAAU,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAC;IACrF,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CACxB;AA4QD;;;;GAIG;AACH,wBAAgB,OAAO,CACrB,KAAK,EAAE;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,OAAO,CAAA;CAAE,EAAE,EACvC,IAAI,EAAE,MAAM,GACX,OAAO,GAAG,SAAS,CAKrB;AAYD;;;;GAIG;AACH,wBAAgB,aAAa,CAAC,GAAG,EAAE,MAAM,GAAG,WAAW,CAEtD"}