@patronage/factory-ci 1.0.0-alpha.34 → 1.0.0-alpha.35

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.
@@ -1,8 +1,8 @@
1
- import { i as isLocalPreviewStage, n as executeAlchemyEntry, r as resolveAlchemyChildCwd, s as ALCHEMY_BASELINE } from "../execute-alchemy-entry-BZpk0eOQ.js";
1
+ import { i as isLocalPreviewStage, n as executeAlchemyEntry, r as resolveAlchemyChildCwd, s as ALCHEMY_BASELINE } from "../execute-alchemy-entry-CZ7Knz4q.js";
2
2
  import { createRequire } from "node:module";
3
3
  import path from "node:path";
4
4
  import { createHash } from "node:crypto";
5
- import { readFileSync } from "node:fs";
5
+ import { appendFileSync, closeSync, openSync, readFileSync } from "node:fs";
6
6
  import * as Alchemy from "alchemy";
7
7
  import * as Output from "alchemy/Output";
8
8
  import { tryFindProviderByType } from "alchemy/Provider";
@@ -176,10 +176,11 @@ const assertRetainedIdentities = ({ after, before, markers }) => {
176
176
  * repeat is the account, the permission list, the resource scope, and where
177
177
  * the credential comes from, so every one of those is an input.
178
178
  *
179
- * **No credential value is ever printed.** Errors name environment variables,
180
- * permission groups, and resource identifiers. They never carry a token, a
181
- * policy document, or any part of one. The result carries the token id, which
182
- * Cloudflare's own verification endpoint returns and which is not a secret.
179
+ * **No credential value is ever printed.** Errors name environment variables and
180
+ * missing groups from the caller-owned permission requirements. Untrusted API
181
+ * status, receipt group names, and resource identifiers are never reflected.
182
+ * The result carries the token id, which Cloudflare's own verification endpoint
183
+ * returns and which is not a secret.
183
184
  */
184
185
  const CLOUDFLARE_API = "https://api.cloudflare.com/client/v4";
185
186
  /**
@@ -253,8 +254,8 @@ const permissionGroupsFromPolicies = (policies, resourcesFor) => {
253
254
  if (!permission?.name) throw new Error("Cloudflare token has an unnamed permission group.");
254
255
  found.push(permission.name);
255
256
  const expected = new Set(resourcesFor(permission.name));
256
- if (expected.size === 0) throw new Error(`Cloudflare ${permission.name} policy has no expected resource scope.`);
257
- if (scope.size !== expected.size || [...scope].some((resource) => !expected.has(resource))) throw new Error(`Cloudflare ${permission.name} policy has an unexpected resource scope.`);
257
+ if (expected.size === 0) throw new Error("Cloudflare token policy has no expected resource scope.");
258
+ if (scope.size !== expected.size || [...scope].some((resource) => !expected.has(resource))) throw new Error("Cloudflare token policy has an unexpected resource scope.");
258
259
  }
259
260
  }
260
261
  return found;
@@ -265,7 +266,7 @@ const assertExactPermissionGroups = (found, required) => {
265
266
  const missing = [...expected].filter((name) => !received.has(name));
266
267
  const extra = [...received].filter((name) => !expected.has(name));
267
268
  const duplicates = found.filter((name, index) => found.indexOf(name) !== index);
268
- if (missing.length > 0 || extra.length > 0 || duplicates.length > 0) throw new Error(`Cloudflare permission mismatch; missing: ${missing.join(", ") || "none"}; extra: ${extra.join(", ") || "none"}; duplicates: ${duplicates.join(", ") || "none"}`);
269
+ if (missing.length > 0 || extra.length > 0 || duplicates.length > 0) throw new Error(`Cloudflare permission mismatch; missing: ${missing.join(", ") || "none"}; extra count: ${extra.length}; duplicate count: ${duplicates.length}`);
269
270
  };
270
271
  const assertRequiredPermissionGroups = (required) => {
271
272
  if (required.some((name) => !name.trim())) throw new Error("Credential preflight requires named permission groups; a blank name matches nothing.");
@@ -307,7 +308,8 @@ const resolveResolvedCredential = async (resolveCredential, environment) => {
307
308
  * Cloudflare could not be asked; every other error means the credential is
308
309
  * wrong. Nothing it throws, and nothing it returns, carries a secret value.
309
310
  */
310
- const credentialPreflight = async ({ accountId, environment, fetchImplementation = fetch, requiredPermissionGroups, resolveCredential, resourcesFor, source }) => {
311
+ const credentialPreflight = async ({ accountId, environment, fetchImplementation = fetch, requiredPermissionGroups, resolveCredential, resourcesFor, source, tokenKind = "account" }) => {
312
+ if (tokenKind !== "account" && tokenKind !== "user") throw new Error("Credential preflight has an unknown token kind.");
311
313
  if (!accountId.trim()) throw new Error("Credential preflight requires a Cloudflare account id.");
312
314
  if (requiredPermissionGroups.length === 0) throw new Error("Credential preflight requires at least one permission group; an empty list would admit any token.");
313
315
  assertRequiredPermissionGroups(requiredPermissionGroups);
@@ -317,8 +319,8 @@ const credentialPreflight = async ({ accountId, environment, fetchImplementation
317
319
  const credential = await resolveResolvedCredential(resolveCredential, environment);
318
320
  if (!(credential.token.trim() && credential.policyJson.trim())) throw new Error("Credential preflight resolved an empty credential.");
319
321
  if (source === "hosted" && credential.token.trim() !== environment.CLOUDFLARE_API_TOKEN?.trim()) throw new Error("Hosted credential preflight resolved a token that is not the environment token.");
320
- const verification = await cloudflareJson(`${CLOUDFLARE_API}/accounts/${accountId}/tokens/verify`, credential.token, fetchImplementation);
321
- if (verification.status !== "active") throw new Error(`Cloudflare token is ${verification.status}, not active.`);
322
+ const verification = await cloudflareJson(tokenKind === "user" ? `${CLOUDFLARE_API}/user/tokens/verify` : `${CLOUDFLARE_API}/accounts/${accountId}/tokens/verify`, credential.token, fetchImplementation);
323
+ if (verification.status !== "active") throw new Error("Cloudflare token is not active.");
322
324
  const reviewed = parseReviewedTokenPolicy(credential.policyJson);
323
325
  if (reviewed.tokenId !== verification.id) throw new Error("Cloudflare token policy metadata does not describe the live token.");
324
326
  const found = permissionGroupsFromPolicies(reviewed.policies, scopeFor);
@@ -1211,6 +1213,7 @@ const secretNamePolicy = ({ names, values }) => {
1211
1213
  const LIFECYCLE_FAILURE_MESSAGES = {
1212
1214
  AMBIGUOUS_RESOURCE: "The plan prints one resource id for more than one resource.",
1213
1215
  AMBIGUOUS_STAGE: "The stage table declares the stage both protected and disposable.",
1216
+ CHILD_DIAGNOSTICS_UNWRITABLE: "The requested child diagnostics file could not be written.",
1214
1217
  CHILD_FAILED: "The Alchemy child did not exit successfully.",
1215
1218
  DEPLOY_INCOMPLETE: "The deploy completed without the persisted state its plan described.",
1216
1219
  DESTROY_RESIDUE: "The destroy left persisted state registered for the stage.",
@@ -1236,6 +1239,7 @@ const LIFECYCLE_FAILURE_MESSAGES = {
1236
1239
  };
1237
1240
  /** A sanitized lifecycle failure. See the module comment. */
1238
1241
  var AlchemyLifecycleError = class extends Error {
1242
+ childDiagnosticsPath;
1239
1243
  code;
1240
1244
  mutation;
1241
1245
  operation;
@@ -1248,11 +1252,13 @@ var AlchemyLifecycleError = class extends Error {
1248
1252
  this.mutation = fields.mutation;
1249
1253
  this.operation = fields.operation;
1250
1254
  this.phase = fields.phase;
1255
+ if (fields.childDiagnosticsPath !== void 0) this.childDiagnosticsPath = fields.childDiagnosticsPath;
1251
1256
  if (fields.planHash !== void 0) this.planHash = fields.planHash;
1252
1257
  }
1253
1258
  /** The fields an evidence sink prints. Fixed shape, fixed words. */
1254
1259
  toJSON() {
1255
1260
  return {
1261
+ ...this.childDiagnosticsPath === void 0 ? {} : { childDiagnosticsPath: this.childDiagnosticsPath },
1256
1262
  code: this.code,
1257
1263
  message: this.message,
1258
1264
  mutation: this.mutation,
@@ -1368,6 +1374,81 @@ const deleteStageRows = async (state, target) => {
1368
1374
  }));
1369
1375
  };
1370
1376
  //#endregion
1377
+ //#region src/alchemy/child-diagnostics.ts
1378
+ /**
1379
+ * The optional record of what an Alchemy child printed (#1260).
1380
+ *
1381
+ * `runAlchemyLifecycle` reports a failed child as `CHILD_FAILED` and nothing
1382
+ * else: the child's output is parsed and dropped, so no secret in it can
1383
+ * reach a job log or an evidence file through the operation. That is the
1384
+ * right default and it stays the default. It also leaves an operator with a
1385
+ * failure code and no record of what failed, which twice cost a paitronage
1386
+ * investigation its evidence.
1387
+ *
1388
+ * This is the opt-in other half: a consumer that names a file gets every
1389
+ * child's streams appended to it, each stream passed whole through the
1390
+ * consumer's own redactor, under a header naming the child. The consumer chooses the path
1391
+ * and owns the redactor; this module never picks either, and nothing here
1392
+ * changes what the lifecycle decides.
1393
+ *
1394
+ * The file is opened, and the header written, **before** the child starts,
1395
+ * so an unwritable path is known before anything runs and a parent that dies
1396
+ * mid-child still leaves the marker for the child that was in flight. The
1397
+ * streams themselves arrive after the child exits, because the child is
1398
+ * captured (`spawnSync`), not streamed.
1399
+ *
1400
+ * Nothing here throws into the lifecycle's control flow once the handle is
1401
+ * open. A write failure is retained and reported by the caller under its own
1402
+ * failure code, because a record that could not be written is a different
1403
+ * fact from a child that failed, and reporting it as the second one would
1404
+ * put a false cause in front of the operator this file exists for. When the
1405
+ * caller reports it — up front, or only after the operation has run to the
1406
+ * end — is the caller's rule, not this module's; see `runAlchemyLifecycle`.
1407
+ */
1408
+ const streamSection = (label, text, redact) => {
1409
+ if (text === null || text === "") return `--- ${label}: empty ---\n`;
1410
+ const body = redact(text);
1411
+ return `--- ${label} ---\n${body.endsWith("\n") ? body : `${body}\n`}`;
1412
+ };
1413
+ /**
1414
+ * Open the record for one child and write its header.
1415
+ *
1416
+ * Throws when the file cannot be opened or the header cannot be written.
1417
+ * That throw happens before the child is launched, so a caller that has not
1418
+ * yet mutated anything can refuse the run with the stage still untouched.
1419
+ */
1420
+ const openChildDiagnostics = ({ child, diagnostics, operation, stack, stage }) => {
1421
+ const handle = openSync(diagnostics.path, "a");
1422
+ let retained;
1423
+ const guard = (write) => {
1424
+ try {
1425
+ write();
1426
+ } catch (error) {
1427
+ retained ??= error instanceof Error ? error : new Error(String(error));
1428
+ }
1429
+ };
1430
+ try {
1431
+ appendFileSync(handle, `\n===== ${operation} ${child} child — ${stack}/${stage} — ${(/* @__PURE__ */ new Date()).toISOString()} =====\n`);
1432
+ } catch (error) {
1433
+ closeSync(handle);
1434
+ throw error;
1435
+ }
1436
+ return {
1437
+ append: ({ stderr, stdout }) => {
1438
+ guard(() => {
1439
+ appendFileSync(handle, streamSection("stdout", stdout, diagnostics.redact));
1440
+ appendFileSync(handle, streamSection("stderr", stderr, diagnostics.redact));
1441
+ });
1442
+ },
1443
+ close: () => {
1444
+ guard(() => {
1445
+ closeSync(handle);
1446
+ });
1447
+ },
1448
+ failure: () => retained
1449
+ };
1450
+ };
1451
+ //#endregion
1371
1452
  //#region src/alchemy/lifecycle.ts
1372
1453
  /**
1373
1454
  * The shared Alchemy lifecycle operation (#1077).
@@ -1480,6 +1561,12 @@ var LifecycleRun = class {
1480
1561
  policy;
1481
1562
  state;
1482
1563
  entry;
1564
+ childDiagnostics;
1565
+ /**
1566
+ * A diagnostics write that failed after a mutating child had started, held
1567
+ * until the operation has run to its end. See `noteDiagnosticsFailure`.
1568
+ */
1569
+ diagnosticsUnwritable = false;
1483
1570
  bundledEntry;
1484
1571
  /** What the run has done to the stage so far. Only children advance it. */
1485
1572
  certainty = "not-started";
@@ -1488,9 +1575,13 @@ var LifecycleRun = class {
1488
1575
  this.policy = options.policy;
1489
1576
  this.state = options.state;
1490
1577
  this.entry = options.entry;
1578
+ this.childDiagnostics = options.childDiagnostics;
1491
1579
  }
1492
- fail(code, phase, planHash) {
1580
+ fail(code, phase, extra = {}) {
1581
+ const { namesDiagnostics, planHash } = extra;
1582
+ const diagnosticsPath = namesDiagnostics === true ? this.childDiagnostics?.path : void 0;
1493
1583
  return new AlchemyLifecycleError({
1584
+ ...diagnosticsPath === void 0 ? {} : { childDiagnosticsPath: diagnosticsPath },
1494
1585
  code,
1495
1586
  mutation: this.certainty,
1496
1587
  operation: this.request.operation,
@@ -1661,22 +1752,75 @@ var LifecycleRun = class {
1661
1752
  return ["--stage", this.request.stage];
1662
1753
  }
1663
1754
  /**
1664
- * Run one child under `lease` and return its stdout for parsing. The output
1665
- * is written nowhere else. The child's environment carries the lease, so
1666
- * the adapter in the child adopts it rather than taking its own: there is
1667
- * no child without a lease, and a child that writes outside this lease is
1668
- * refused by the store, not by this module. A `plan` child leaves the
1669
- * certainty where it is unless it is the first child; a mutating child
1670
- * advances it before it starts.
1755
+ * Where a diagnostics write failure is reported.
1756
+ *
1757
+ * Before any mutating child has started, it is reported here and now: the
1758
+ * operator asked for a record, the record cannot be kept, and nothing has
1759
+ * been changed yet, so refusing costs nothing.
1760
+ *
1761
+ * Once a deploy or destroy child has started, it is **retained** and
1762
+ * reported only after the operation has run to its end, the way a failed
1763
+ * lease release is. The apply succeeded; failing here would abandon the
1764
+ * convergence check on a good deploy and invite an operator to destroy and
1765
+ * retry a stage that is fine. A missing record is not a reason to treat a
1766
+ * successful mutation as a failed one, and the run still ends in
1767
+ * `CHILD_DIAGNOSTICS_UNWRITABLE` — after the postconditions have run, with
1768
+ * the mutation certainty the operation actually reached.
1769
+ */
1770
+ noteDiagnosticsFailure(failed) {
1771
+ if (!failed) return;
1772
+ this.diagnosticsUnwritable = true;
1773
+ if (this.certainty !== "mutation-may-have-occurred") throw this.fail("CHILD_DIAGNOSTICS_UNWRITABLE", "execution", { namesDiagnostics: true });
1774
+ }
1775
+ /**
1776
+ * The retained record failure, once the operation itself is complete. The
1777
+ * operation's own failures are reported ahead of it, as they are for a
1778
+ * failed lease release.
1779
+ */
1780
+ assertDiagnosticsWritten() {
1781
+ if (this.diagnosticsUnwritable) throw this.fail("CHILD_DIAGNOSTICS_UNWRITABLE", "execution", { namesDiagnostics: true });
1782
+ }
1783
+ /**
1784
+ * The diagnostics section for one child, opened and headed before the
1785
+ * child starts. A path that cannot be opened refuses the run while nothing
1786
+ * has been mutated; after that it is retained and the child runs without a
1787
+ * record rather than a good apply being abandoned over one.
1788
+ */
1789
+ openDiagnostics(child) {
1790
+ if (this.childDiagnostics === void 0) return;
1791
+ try {
1792
+ return openChildDiagnostics({
1793
+ child,
1794
+ diagnostics: this.childDiagnostics,
1795
+ operation: this.request.operation,
1796
+ stack: this.request.stack,
1797
+ stage: this.request.stage
1798
+ });
1799
+ } catch {
1800
+ this.noteDiagnosticsFailure(true);
1801
+ return;
1802
+ }
1803
+ }
1804
+ /**
1805
+ * Run one child under `lease` and return its stdout for parsing. Its output
1806
+ * goes nowhere else unless the consumer asked for `childDiagnostics`, which
1807
+ * writes a redacted copy and never touches what is returned here. The
1808
+ * child's environment carries the lease, so the adapter in the child adopts
1809
+ * it rather than taking its own: there is no child without a lease, and a
1810
+ * child that writes outside this lease is refused by the store, not by this
1811
+ * module. A `plan` child leaves the certainty where it is unless it is the
1812
+ * first child; a mutating child advances it before it starts.
1671
1813
  */
1672
1814
  async runChild(child, args, lease) {
1673
1815
  if (this.bundledEntry === void 0) throw this.fail("PREPARATION_FAILED", "admission");
1816
+ const record = this.openDiagnostics(child);
1674
1817
  if (child !== "plan") this.certainty = "mutation-may-have-occurred";
1675
1818
  else if (this.certainty === "not-started") this.certainty = "read-only-started";
1676
1819
  const { env, from } = this.entry;
1820
+ let stdout;
1677
1821
  try {
1678
- return (await executeAlchemyEntry({
1679
- args,
1822
+ stdout = (await executeAlchemyEntry({
1823
+ args: [...args, ...this.entry.envFile === void 0 ? [] : ["--env-file", this.entry.envFile]],
1680
1824
  bundledEntry: this.bundledEntry,
1681
1825
  cwd: resolveAlchemyChildCwd(this.entry),
1682
1826
  env: {
@@ -1685,11 +1829,16 @@ var LifecycleRun = class {
1685
1829
  },
1686
1830
  from,
1687
1831
  maxBuffer: 67108864,
1832
+ ...record === void 0 ? {} : { onCaptured: record.append },
1688
1833
  stdio: "pipe"
1689
1834
  })).stdout ?? "";
1690
1835
  } catch {
1691
- throw this.fail("CHILD_FAILED", "execution");
1836
+ stdout = void 0;
1692
1837
  }
1838
+ record?.close();
1839
+ if (stdout === void 0) throw this.fail("CHILD_FAILED", "execution", { namesDiagnostics: true });
1840
+ this.noteDiagnosticsFailure(record?.failure() !== void 0);
1841
+ return stdout;
1693
1842
  }
1694
1843
  effectsOf(output, phase) {
1695
1844
  let effects;
@@ -1782,7 +1931,7 @@ var LifecycleRun = class {
1782
1931
  stage: this.request.stage
1783
1932
  });
1784
1933
  } catch {
1785
- throw this.fail("FIRST_DEPLOY_UNAUTHORIZED", "admission", planHash);
1934
+ throw this.fail("FIRST_DEPLOY_UNAUTHORIZED", "admission", { planHash });
1786
1935
  }
1787
1936
  }
1788
1937
  retainedMarkers() {
@@ -1942,6 +2091,15 @@ var LifecycleRun = class {
1942
2091
  *
1943
2092
  * Every failure is an `AlchemyLifecycleError`. After a deploy or destroy
1944
2093
  * child was started, no failure reports `not-started`.
2094
+ *
2095
+ * `childDiagnostics` is the one opt-in that keeps what the children printed:
2096
+ * both streams of every child, each passed whole through the consumer's own
2097
+ * redactor, are appended to the consumer's own file under a per-child
2098
+ * header, and a `CHILD_FAILED` then names that path so an operator knows
2099
+ * where to look. Nothing about the operation changes otherwise: a record
2100
+ * that cannot be written refuses the run only while nothing has been
2101
+ * mutated, and after that is reported as `CHILD_DIAGNOSTICS_UNWRITABLE` once
2102
+ * the operation has finished, never in place of its postconditions.
1945
2103
  */
1946
2104
  const runAlchemyLifecycle = async (options) => {
1947
2105
  const run = new LifecycleRun(options);
@@ -1949,11 +2107,15 @@ const runAlchemyLifecycle = async (options) => {
1949
2107
  const { isProtected } = run.admitStage();
1950
2108
  const alchemyVersion = run.installedAlchemyVersion();
1951
2109
  await run.prepareEntry();
1952
- switch (options.request.operation) {
1953
- case "plan": return await run.plan(alchemyVersion, isProtected);
1954
- case "deploy": return await run.deploy(alchemyVersion, isProtected);
1955
- default: return await run.destroy(alchemyVersion);
1956
- }
2110
+ const result = await (async () => {
2111
+ switch (options.request.operation) {
2112
+ case "plan": return await run.plan(alchemyVersion, isProtected);
2113
+ case "deploy": return await run.deploy(alchemyVersion, isProtected);
2114
+ default: return await run.destroy(alchemyVersion);
2115
+ }
2116
+ })();
2117
+ run.assertDiagnosticsWritten();
2118
+ return result;
1957
2119
  };
1958
2120
  //#endregion
1959
2121
  //#region src/alchemy/index.ts
@@ -70,6 +70,23 @@ interface ExecuteAlchemyEntryCommon {
70
70
  * pass `EXECUTE_ALCHEMY_ENTRY_MAX_BUFFER` or another explicit value.
71
71
  */
72
72
  readonly maxBuffer?: number;
73
+ /**
74
+ * Called once with the child's captured streams, after the child exits and
75
+ * **before its exit status is judged**, so a caller keeping a diagnostic
76
+ * record still receives the output of a child that failed. Unused when
77
+ * stdio is `"inherit"`.
78
+ *
79
+ * The text handed over is the raw capture: `redact` is not applied to it,
80
+ * because `redact` shapes what this function returns and a record is not a
81
+ * return value. A caller that writes this anywhere owns its own redaction.
82
+ *
83
+ * It must not throw. Its work is a side record, and a throw from it would
84
+ * be indistinguishable here from the child's own failure.
85
+ */
86
+ readonly onCaptured?: (captured: {
87
+ readonly stdout: string | null;
88
+ readonly stderr: string | null;
89
+ }) => void;
73
90
  /**
74
91
  * Applied to captured stdout and stderr before they are returned. Unused
75
92
  * when stdio is `"inherit"`. This package does not supply a secret-name
@@ -106,7 +123,8 @@ interface ExecuteAlchemyEntryResult {
106
123
  * Options carry exactly one entry source: `bundle` to bundle now, or
107
124
  * `bundledEntry` to reuse an already-bundled path. Captured stdout and stderr (`stdio: "pipe"`) can be redacted through
108
125
  * `redact` before they are returned; `stdio: "inherit"` still streams the
109
- * child unredacted.
126
+ * child unredacted. `onCaptured` receives the raw streams of every piped
127
+ * child, including one that then fails.
110
128
  *
111
129
  * Deploy/destroy/plan selection, stage admission, credentials, and every
112
130
  * convergence or destructive-change policy remain the caller's responsibility.
@@ -123,7 +123,8 @@ const captured = (text, redact) => {
123
123
  * Options carry exactly one entry source: `bundle` to bundle now, or
124
124
  * `bundledEntry` to reuse an already-bundled path. Captured stdout and stderr (`stdio: "pipe"`) can be redacted through
125
125
  * `redact` before they are returned; `stdio: "inherit"` still streams the
126
- * child unredacted.
126
+ * child unredacted. `onCaptured` receives the raw streams of every piped
127
+ * child, including one that then fails.
127
128
  *
128
129
  * Deploy/destroy/plan selection, stage admission, credentials, and every
129
130
  * convergence or destructive-change policy remain the caller's responsibility.
@@ -142,6 +143,10 @@ const executeAlchemyEntry = async (options) => {
142
143
  ...options.maxBuffer === void 0 ? {} : { maxBuffer: options.maxBuffer },
143
144
  stdio: options.stdio ?? "inherit"
144
145
  });
146
+ options.onCaptured?.({
147
+ stderr: result.stderr,
148
+ stdout: result.stdout
149
+ });
145
150
  if (result.error) throw new Error("Failed to start the Alchemy CLI.");
146
151
  if (result.signal) throw new Error(`Alchemy CLI terminated by signal ${result.signal}.`);
147
152
  if (result.status !== 0) throw new Error(result.status === null ? "Alchemy CLI exited without reporting a status." : `Alchemy CLI exited with status ${result.status}.`);
package/dist/index.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { a as BundleAlchemyEntryOptions, i as executeAlchemyEntry, n as ExecuteAlchemyEntryOptions, o as bundleAlchemyEntry, r as ExecuteAlchemyEntryResult, t as EXECUTE_ALCHEMY_ENTRY_MAX_BUFFER } from "./execute-alchemy-entry-DB8fFZTu.js";
1
+ import { a as BundleAlchemyEntryOptions, i as executeAlchemyEntry, n as ExecuteAlchemyEntryOptions, o as bundleAlchemyEntry, r as ExecuteAlchemyEntryResult, t as EXECUTE_ALCHEMY_ENTRY_MAX_BUFFER } from "./execute-alchemy-entry-B397GSk5.js";
2
2
  import { StdioOptions } from "node:child_process";
3
3
 
4
4
  //#region src/alchemy-baseline.d.ts
@@ -1203,6 +1203,30 @@ declare const previewCleanupDestroyJobId: (stack: string) => string;
1203
1203
  */
1204
1204
  declare const factoryPreviewCleanupTopology: (options: FactoryPreviewCleanupTopologyOptions) => FactoryPreviewCleanupTopology;
1205
1205
  //#endregion
1206
+ //#region src/preview-receipt-workflow.d.ts
1207
+ interface FactoryPreviewReceiptWorkflowOptions {
1208
+ readonly target: string;
1209
+ readonly cli?: string;
1210
+ /** Caller-owned PR number expression, passed through the environment. */
1211
+ readonly pr?: string;
1212
+ }
1213
+ interface FactoryPreviewReceiptWorkflow {
1214
+ /** Place before the selected target's first mutation, under its selection guard. */
1215
+ readonly beginStep: WorkflowStep;
1216
+ /** Append after consumer deploy and required smoke steps. Never rename the bind step. */
1217
+ readonly completionSteps: readonly WorkflowStep[];
1218
+ /** Place before cleanup, including cleanup of a failed/unregistered deployment. */
1219
+ readonly invalidateStep: WorkflowStep;
1220
+ readonly permissions: Readonly<{
1221
+ actions: "read";
1222
+ contents: "read";
1223
+ deployments: "write";
1224
+ "pull-requests": "read";
1225
+ }>;
1226
+ }
1227
+ /** Receipt transport only. The consumer owns selection, lifecycle, smoke, and freshness. */
1228
+ declare const factoryPreviewReceiptWorkflow: (options: FactoryPreviewReceiptWorkflowOptions) => FactoryPreviewReceiptWorkflow;
1229
+ //#endregion
1206
1230
  //#region src/production-impact-workflow.d.ts
1207
1231
  declare const FACTORY_PRODUCTION_IMPACT_STEP_ID = "production_impact";
1208
1232
  declare const FACTORY_PRODUCTION_IMPACT_DECISION_OUTPUT = "decision";
@@ -1645,4 +1669,4 @@ declare const assertWorkflowShellParses: (yaml: string, options: {
1645
1669
  readonly source: string;
1646
1670
  }) => void;
1647
1671
  //#endregion
1648
- export { ALCHEMY_BASELINE, type AlchemyBaselinePackageJson, type AssertAlchemyBaselineInput, type BundleAlchemyEntryOptions, type CheckoutStepOptions, EXECUTE_ALCHEMY_ENTRY_MAX_BUFFER, type ExecuteAlchemyEntryOptions, type ExecuteAlchemyEntryResult, FACTORY_APP_BROKER_ORIGIN, FACTORY_APP_BROKER_PATH, FACTORY_APP_BROKER_TOKEN_PERMISSIONS, FACTORY_CANDIDATE_IMPACT_BASIS_OUTPUT, FACTORY_CANDIDATE_IMPACT_DECISION_OUTPUT, FACTORY_CANDIDATE_IMPACT_INERT_OUTPUT, FACTORY_CANDIDATE_IMPACT_STEP_ID, FACTORY_CANDIDATE_IMPACT_UNSUBSCRIBED_OUTPUT, FACTORY_CANDIDATE_PULL_REQUEST_TYPES, FACTORY_CURSOR_OIDC_AUDIENCE, FACTORY_CURSOR_OIDC_ISSUER, FACTORY_CURSOR_OIDC_JWKS_URL, FACTORY_CURSOR_OIDC_MANAGED_RUNTIME, FACTORY_LIFECYCLE_CONTRACT_JOB_ID, FACTORY_LIFECYCLE_CONTRACT_JOB_NAME, FACTORY_MERGE_FREEZE_APP_TOKEN_STEP_ID, FACTORY_MERGE_FREEZE_CHECK_NAME, FACTORY_MERGE_FREEZE_IF, FACTORY_MERGE_FREEZE_JOB_ID, FACTORY_MERGE_FREEZE_JOB_NAME, FACTORY_MERGE_FREEZE_PERMISSIONS, FACTORY_MERGE_FREEZE_VERIFY_RESULT_EXPRESSION, FACTORY_MERGE_TARGET_REF_CONDITION, FACTORY_PREVIEW_CLEANUP_AUDIT_JOB_ID, FACTORY_PREVIEW_CLEANUP_AUDIT_JOB_NAME, FACTORY_PRODUCTION_IMPACT_BASIS_OUTPUT, FACTORY_PRODUCTION_IMPACT_DECISION_OUTPUT, FACTORY_PRODUCTION_IMPACT_STEP_ID, FACTORY_PRODUCTION_IMPACT_UNSUBSCRIBED_OUTPUT, FACTORY_PROOF_GATE_APP_ID, FACTORY_PROOF_GATE_CHECK_NAME, FACTORY_PROOF_GATE_GUARD, FACTORY_PROOF_GATE_IF, FACTORY_PROOF_GATE_MODE_OUTPUT, FACTORY_PROOF_GATE_OUTPUT, FACTORY_PROOF_GATE_REASONS, FACTORY_PROOF_GATE_REASON_OUTPUT, FACTORY_PROOF_GATE_SHELL, FACTORY_PROOF_GATE_SOURCE_URL_OUTPUT, FACTORY_PROOF_GATE_STEP_ID, FACTORY_PROOF_GATE_STEP_NAME, FACTORY_PR_STATUS_HUD_APP_TOKEN_STEP_ID, FACTORY_PR_STATUS_HUD_CONCURRENCY, FACTORY_PR_STATUS_HUD_IF, FACTORY_PR_STATUS_HUD_JOB_ID, FACTORY_PR_STATUS_HUD_JOB_NAME, FACTORY_PR_STATUS_HUD_PERMISSIONS, FACTORY_PR_STATUS_HUD_PLAN_PATH, FACTORY_PUSH_IDENTITY_SCHEMA_VERSION, type FactoryCandidateImpactWorkflow, type FactoryCandidateImpactWorkflowOptions, type FactoryLifecycleContractLane, type FactoryLifecycleContractLaneOptions, type FactoryMergeFreezeJob, type FactoryMergeFreezeJobOptions, type FactoryPrStatusHudWorkflow, type FactoryPrStatusHudWorkflowOptions, type FactoryPreviewCleanupAuditJob, type FactoryPreviewCleanupDestroyJob, type FactoryPreviewCleanupTopology, type FactoryPreviewCleanupTopologyOptions, type FactoryProductionImpactWorkflow, type FactoryProductionImpactWorkflowOptions, type FactoryProofGateOptions, type FactoryProofGateReason, type FactoryProofGateStep, type FactoryProofReusePresentationOptions, type FactoryProofReuseSummaryStep, type FactoryProofTimingStartStep, type FactoryPushIdentityConsumer, type FactoryPushIdentityConsumerOptions, type FactoryPushIdentityDisposition, type FactoryPushIdentityEnvelope, type FactoryPushIdentityProducer, type FactoryPushIdentityProducerOptions, type FactoryRunnerDecision, type FactoryRunnerHome, type FactoryRunnerKind, type FactoryRunnerOverride, type FactoryVerifyRunner, type FactoryVerifyRunnerMismatch, type FactoryVerifyRunnerPolicyInput, type FactoryVerifyRunnerPolicyReport, type FactoryVerifyRunnerTable, type FactoryWorkflowArtifact, type FactoryWorkflowOptions, type FactoryWorkflowSetupOptions, GitHubApiError, GitHubAppTokenTransportError, type GithubAppCredentials, type GithubAppInstallationPermissions, type GithubAppTokenOptions, type InstallStepOptions, type LocalPreviewStage, type LocalPreviewStageOptions, NODE_PNPM_ACTION_FAMILY_NODE24, type NodePnpmActionFamily, PREVIEW_PROOF_INVENTORY_CHECK_NAME, PREVIEW_PROOF_INVENTORY_LIST_PERMISSIONS, type ParseLocalPreviewStageExpected, type ParsedLocalPreviewStage, type PinnedAction, type PreviewProofCandidate, type PreviewProofCleanupOutcome, type PreviewProofCleanupStatus, type PreviewProofEnvelopeEvidence, type PreviewProofInventoryAccess, type PreviewProofInventoryCleanupInput, type PreviewProofInventoryListInput, type PreviewProofInventoryPersistInput, type PreviewProofInventoryStore, type PreviewProofInventoryTransport, type PreviewProofLifecycleEvent, type PreviewProofLifecycleState, type PreviewProofRegistration, type PreviewProofResolveQuery, PreviewProofTransportError, type ProofReuseCommand, type ProofReuseCoverageInput, type ProofReuseCoverageReport, SETUP_STEP_ROLES, type SetupNodeStepOptions, type SetupStepRole, UPLOAD_ARTIFACT, VITEST_PROFILE_SCHEMA_VERSION, VITEST_PROFILE_TOOL, type VitestJsonReport, type VitestProfile, type VitestProfileDependencies, type VitestProfileDurationSummary, type VitestProfileEnvironment, VitestProfileError, type VitestProfileOptions, type VitestProfileReadResult, type VitestProfileSample, type VitestProfileSampleExecution, type VitestTestStatus, type WorkflowShellParseFailure, type WorkflowStep, assertAlchemyBaseline, assertProofReuseCoverage, assertVerifyRunnerPolicy, assertWorkflowShellParses, bundleAlchemyEntry, captureVitestProfileEnvironment, executeAlchemyEntry, factoryCandidateImpactWorkflow, factoryCandidateOrPushCondition, factoryLifecycleContractLane, factoryMergeFreezeJob, factoryMergeFreezeScript, factoryPrStatusHudWorkflow, factoryPreviewCleanupTopology, factoryProductionImpactWorkflow, factoryProofGateScript, factoryProofGateStep, factoryProofReuseSummaryStep, factoryProofTimingStartStep, factoryPushIdentityConsumer, factoryPushIdentityProducer, factoryVerifyRunner, factoryWorkflow, githubAppJwt, isLocalPreviewStage, localPreviewStage, mintInstallationToken, normalizeVitestProfileSample, parseLocalPreviewStage, previewCleanupDestroyJobId, previewProofInventory, previewProofLifecycle, productionImpactTargetOutput, proofReuseCoverage, proofReuseRequiredCommands, readVitestProfileDocument, resolveProofReuseCommands, runVitestProfile, setupStepsForRoles, verifyRunnerPolicy, workflowRunBlocks, workflowShellParseFailures, writeVitestProfile };
1672
+ export { ALCHEMY_BASELINE, type AlchemyBaselinePackageJson, type AssertAlchemyBaselineInput, type BundleAlchemyEntryOptions, type CheckoutStepOptions, EXECUTE_ALCHEMY_ENTRY_MAX_BUFFER, type ExecuteAlchemyEntryOptions, type ExecuteAlchemyEntryResult, FACTORY_APP_BROKER_ORIGIN, FACTORY_APP_BROKER_PATH, FACTORY_APP_BROKER_TOKEN_PERMISSIONS, FACTORY_CANDIDATE_IMPACT_BASIS_OUTPUT, FACTORY_CANDIDATE_IMPACT_DECISION_OUTPUT, FACTORY_CANDIDATE_IMPACT_INERT_OUTPUT, FACTORY_CANDIDATE_IMPACT_STEP_ID, FACTORY_CANDIDATE_IMPACT_UNSUBSCRIBED_OUTPUT, FACTORY_CANDIDATE_PULL_REQUEST_TYPES, FACTORY_CURSOR_OIDC_AUDIENCE, FACTORY_CURSOR_OIDC_ISSUER, FACTORY_CURSOR_OIDC_JWKS_URL, FACTORY_CURSOR_OIDC_MANAGED_RUNTIME, FACTORY_LIFECYCLE_CONTRACT_JOB_ID, FACTORY_LIFECYCLE_CONTRACT_JOB_NAME, FACTORY_MERGE_FREEZE_APP_TOKEN_STEP_ID, FACTORY_MERGE_FREEZE_CHECK_NAME, FACTORY_MERGE_FREEZE_IF, FACTORY_MERGE_FREEZE_JOB_ID, FACTORY_MERGE_FREEZE_JOB_NAME, FACTORY_MERGE_FREEZE_PERMISSIONS, FACTORY_MERGE_FREEZE_VERIFY_RESULT_EXPRESSION, FACTORY_MERGE_TARGET_REF_CONDITION, FACTORY_PREVIEW_CLEANUP_AUDIT_JOB_ID, FACTORY_PREVIEW_CLEANUP_AUDIT_JOB_NAME, FACTORY_PRODUCTION_IMPACT_BASIS_OUTPUT, FACTORY_PRODUCTION_IMPACT_DECISION_OUTPUT, FACTORY_PRODUCTION_IMPACT_STEP_ID, FACTORY_PRODUCTION_IMPACT_UNSUBSCRIBED_OUTPUT, FACTORY_PROOF_GATE_APP_ID, FACTORY_PROOF_GATE_CHECK_NAME, FACTORY_PROOF_GATE_GUARD, FACTORY_PROOF_GATE_IF, FACTORY_PROOF_GATE_MODE_OUTPUT, FACTORY_PROOF_GATE_OUTPUT, FACTORY_PROOF_GATE_REASONS, FACTORY_PROOF_GATE_REASON_OUTPUT, FACTORY_PROOF_GATE_SHELL, FACTORY_PROOF_GATE_SOURCE_URL_OUTPUT, FACTORY_PROOF_GATE_STEP_ID, FACTORY_PROOF_GATE_STEP_NAME, FACTORY_PR_STATUS_HUD_APP_TOKEN_STEP_ID, FACTORY_PR_STATUS_HUD_CONCURRENCY, FACTORY_PR_STATUS_HUD_IF, FACTORY_PR_STATUS_HUD_JOB_ID, FACTORY_PR_STATUS_HUD_JOB_NAME, FACTORY_PR_STATUS_HUD_PERMISSIONS, FACTORY_PR_STATUS_HUD_PLAN_PATH, FACTORY_PUSH_IDENTITY_SCHEMA_VERSION, type FactoryCandidateImpactWorkflow, type FactoryCandidateImpactWorkflowOptions, type FactoryLifecycleContractLane, type FactoryLifecycleContractLaneOptions, type FactoryMergeFreezeJob, type FactoryMergeFreezeJobOptions, type FactoryPrStatusHudWorkflow, type FactoryPrStatusHudWorkflowOptions, type FactoryPreviewCleanupAuditJob, type FactoryPreviewCleanupDestroyJob, type FactoryPreviewCleanupTopology, type FactoryPreviewCleanupTopologyOptions, type FactoryPreviewReceiptWorkflow, type FactoryPreviewReceiptWorkflowOptions, type FactoryProductionImpactWorkflow, type FactoryProductionImpactWorkflowOptions, type FactoryProofGateOptions, type FactoryProofGateReason, type FactoryProofGateStep, type FactoryProofReusePresentationOptions, type FactoryProofReuseSummaryStep, type FactoryProofTimingStartStep, type FactoryPushIdentityConsumer, type FactoryPushIdentityConsumerOptions, type FactoryPushIdentityDisposition, type FactoryPushIdentityEnvelope, type FactoryPushIdentityProducer, type FactoryPushIdentityProducerOptions, type FactoryRunnerDecision, type FactoryRunnerHome, type FactoryRunnerKind, type FactoryRunnerOverride, type FactoryVerifyRunner, type FactoryVerifyRunnerMismatch, type FactoryVerifyRunnerPolicyInput, type FactoryVerifyRunnerPolicyReport, type FactoryVerifyRunnerTable, type FactoryWorkflowArtifact, type FactoryWorkflowOptions, type FactoryWorkflowSetupOptions, GitHubApiError, GitHubAppTokenTransportError, type GithubAppCredentials, type GithubAppInstallationPermissions, type GithubAppTokenOptions, type InstallStepOptions, type LocalPreviewStage, type LocalPreviewStageOptions, NODE_PNPM_ACTION_FAMILY_NODE24, type NodePnpmActionFamily, PREVIEW_PROOF_INVENTORY_CHECK_NAME, PREVIEW_PROOF_INVENTORY_LIST_PERMISSIONS, type ParseLocalPreviewStageExpected, type ParsedLocalPreviewStage, type PinnedAction, type PreviewProofCandidate, type PreviewProofCleanupOutcome, type PreviewProofCleanupStatus, type PreviewProofEnvelopeEvidence, type PreviewProofInventoryAccess, type PreviewProofInventoryCleanupInput, type PreviewProofInventoryListInput, type PreviewProofInventoryPersistInput, type PreviewProofInventoryStore, type PreviewProofInventoryTransport, type PreviewProofLifecycleEvent, type PreviewProofLifecycleState, type PreviewProofRegistration, type PreviewProofResolveQuery, PreviewProofTransportError, type ProofReuseCommand, type ProofReuseCoverageInput, type ProofReuseCoverageReport, SETUP_STEP_ROLES, type SetupNodeStepOptions, type SetupStepRole, UPLOAD_ARTIFACT, VITEST_PROFILE_SCHEMA_VERSION, VITEST_PROFILE_TOOL, type VitestJsonReport, type VitestProfile, type VitestProfileDependencies, type VitestProfileDurationSummary, type VitestProfileEnvironment, VitestProfileError, type VitestProfileOptions, type VitestProfileReadResult, type VitestProfileSample, type VitestProfileSampleExecution, type VitestTestStatus, type WorkflowShellParseFailure, type WorkflowStep, assertAlchemyBaseline, assertProofReuseCoverage, assertVerifyRunnerPolicy, assertWorkflowShellParses, bundleAlchemyEntry, captureVitestProfileEnvironment, executeAlchemyEntry, factoryCandidateImpactWorkflow, factoryCandidateOrPushCondition, factoryLifecycleContractLane, factoryMergeFreezeJob, factoryMergeFreezeScript, factoryPrStatusHudWorkflow, factoryPreviewCleanupTopology, factoryPreviewReceiptWorkflow, factoryProductionImpactWorkflow, factoryProofGateScript, factoryProofGateStep, factoryProofReuseSummaryStep, factoryProofTimingStartStep, factoryPushIdentityConsumer, factoryPushIdentityProducer, factoryVerifyRunner, factoryWorkflow, githubAppJwt, isLocalPreviewStage, localPreviewStage, mintInstallationToken, normalizeVitestProfileSample, parseLocalPreviewStage, previewCleanupDestroyJobId, previewProofInventory, previewProofLifecycle, productionImpactTargetOutput, proofReuseCoverage, proofReuseRequiredCommands, readVitestProfileDocument, resolveProofReuseCommands, runVitestProfile, setupStepsForRoles, verifyRunnerPolicy, workflowRunBlocks, workflowShellParseFailures, writeVitestProfile };
package/dist/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import { t as bundleAlchemyEntry } from "./bundle-alchemy-entry-CT5hCphA.js";
2
- import { a as localPreviewStage, c as assertAlchemyBaseline, i as isLocalPreviewStage, n as executeAlchemyEntry, o as parseLocalPreviewStage, s as ALCHEMY_BASELINE, t as EXECUTE_ALCHEMY_ENTRY_MAX_BUFFER } from "./execute-alchemy-entry-BZpk0eOQ.js";
2
+ import { a as localPreviewStage, c as assertAlchemyBaseline, i as isLocalPreviewStage, n as executeAlchemyEntry, o as parseLocalPreviewStage, s as ALCHEMY_BASELINE, t as EXECUTE_ALCHEMY_ENTRY_MAX_BUFFER } from "./execute-alchemy-entry-CZ7Knz4q.js";
3
3
  import { createRequire } from "node:module";
4
4
  import { mkdir, readFile, rename, writeFile } from "node:fs/promises";
5
5
  import path from "node:path";
@@ -2337,6 +2337,67 @@ const factoryPreviewCleanupTopology = (options) => {
2337
2337
  });
2338
2338
  };
2339
2339
  //#endregion
2340
+ //#region src/preview-receipt-workflow.ts
2341
+ /** Receipt transport only. The consumer owns selection, lifecycle, smoke, and freshness. */
2342
+ const factoryPreviewReceiptWorkflow = (options) => {
2343
+ if (!/^preview:[a-z][a-z0-9-]*$/u.test(options.target)) throw new Error("Preview receipts require a declared preview target name.");
2344
+ const cli = options.cli ?? "pnpm exec psf";
2345
+ assertRunnableCli("cli", cli);
2346
+ const id = `preview_intent_${options.target.slice(8).replaceAll("-", "_")}`;
2347
+ const deploymentId = `\${{ steps.${id}.outputs.deployment_id }}`;
2348
+ const hasIntent = `steps.${id}.outputs.deployment_id != ''`;
2349
+ const env = {
2350
+ FACTORY_PREVIEW_PR: options.pr ?? `\${{ github.event.pull_request.number }}`,
2351
+ GH_TOKEN: `\${{ github.token }}`
2352
+ };
2353
+ const command = `${cli} preview:receipt --pr "$FACTORY_PREVIEW_PR" --target '${options.target}'`;
2354
+ return Object.freeze({
2355
+ beginStep: Object.freeze({
2356
+ env,
2357
+ id,
2358
+ name: `Record preview intent for ${options.target}`,
2359
+ run: `${command} --action begin --github-output "$GITHUB_OUTPUT"`
2360
+ }),
2361
+ completionSteps: Object.freeze([
2362
+ Object.freeze({
2363
+ env: {
2364
+ ...env,
2365
+ FACTORY_DEPLOYMENT_ID: deploymentId
2366
+ },
2367
+ if: `success() && ${hasIntent}`,
2368
+ name: `Complete preview receipt for ${options.target}`,
2369
+ run: `${command} --action complete --deployment-id "$FACTORY_DEPLOYMENT_ID" --outcome success`
2370
+ }),
2371
+ Object.freeze({
2372
+ env: { FACTORY_DEPLOYMENT_ID: deploymentId },
2373
+ if: `success() && ${hasIntent}`,
2374
+ name: `Bind deployment receipt ${deploymentId}`,
2375
+ run: "test -n \"$FACTORY_DEPLOYMENT_ID\""
2376
+ }),
2377
+ Object.freeze({
2378
+ env: {
2379
+ ...env,
2380
+ FACTORY_DEPLOYMENT_ID: deploymentId
2381
+ },
2382
+ if: `failure() && ${hasIntent}`,
2383
+ name: `Fail preview receipt for ${options.target}`,
2384
+ run: `${command} --action complete --deployment-id "$FACTORY_DEPLOYMENT_ID" --outcome failure`
2385
+ })
2386
+ ]),
2387
+ invalidateStep: Object.freeze({
2388
+ env,
2389
+ name: `Invalidate preview receipts for ${options.target}`,
2390
+ run: `${command} --action invalidate`
2391
+ }),
2392
+ permissions: Object.freeze({
2393
+ actions: "read",
2394
+ contents: "read",
2395
+ deployments: "write",
2396
+ "pull-requests": "read"
2397
+ })
2398
+ });
2399
+ };
2400
+ //#endregion
2340
2401
  //#region src/push-identity-workflow.ts
2341
2402
  /** `owner/repo` slice of the catalog's `UPLOAD_ARTIFACT` pin, derived rather
2342
2403
  * than repeated as a literal, so a repository rename here cannot drift from
@@ -3530,4 +3591,4 @@ const assertWorkflowShellParses = (yaml, options) => {
3530
3591
  throw new Error(`${options.source} emits shell bash cannot parse; the runner would treat it as a no-op:\n${detail}`);
3531
3592
  };
3532
3593
  //#endregion
3533
- export { ALCHEMY_BASELINE, EXECUTE_ALCHEMY_ENTRY_MAX_BUFFER, FACTORY_APP_BROKER_ORIGIN, FACTORY_APP_BROKER_PATH, FACTORY_APP_BROKER_TOKEN_PERMISSIONS, FACTORY_CANDIDATE_IMPACT_BASIS_OUTPUT, FACTORY_CANDIDATE_IMPACT_DECISION_OUTPUT, FACTORY_CANDIDATE_IMPACT_INERT_OUTPUT, FACTORY_CANDIDATE_IMPACT_STEP_ID, FACTORY_CANDIDATE_IMPACT_UNSUBSCRIBED_OUTPUT, FACTORY_CANDIDATE_PULL_REQUEST_TYPES, FACTORY_CURSOR_OIDC_AUDIENCE, FACTORY_CURSOR_OIDC_ISSUER, FACTORY_CURSOR_OIDC_JWKS_URL, FACTORY_CURSOR_OIDC_MANAGED_RUNTIME, FACTORY_LIFECYCLE_CONTRACT_JOB_ID, FACTORY_LIFECYCLE_CONTRACT_JOB_NAME, FACTORY_MERGE_FREEZE_APP_TOKEN_STEP_ID, FACTORY_MERGE_FREEZE_CHECK_NAME, FACTORY_MERGE_FREEZE_IF, FACTORY_MERGE_FREEZE_JOB_ID, FACTORY_MERGE_FREEZE_JOB_NAME, FACTORY_MERGE_FREEZE_PERMISSIONS, FACTORY_MERGE_FREEZE_VERIFY_RESULT_EXPRESSION, FACTORY_MERGE_TARGET_REF_CONDITION, FACTORY_PREVIEW_CLEANUP_AUDIT_JOB_ID, FACTORY_PREVIEW_CLEANUP_AUDIT_JOB_NAME, FACTORY_PRODUCTION_IMPACT_BASIS_OUTPUT, FACTORY_PRODUCTION_IMPACT_DECISION_OUTPUT, FACTORY_PRODUCTION_IMPACT_STEP_ID, FACTORY_PRODUCTION_IMPACT_UNSUBSCRIBED_OUTPUT, FACTORY_PROOF_GATE_APP_ID, FACTORY_PROOF_GATE_CHECK_NAME, FACTORY_PROOF_GATE_GUARD, FACTORY_PROOF_GATE_IF, FACTORY_PROOF_GATE_MODE_OUTPUT, FACTORY_PROOF_GATE_OUTPUT, FACTORY_PROOF_GATE_REASONS, FACTORY_PROOF_GATE_REASON_OUTPUT, FACTORY_PROOF_GATE_SHELL, FACTORY_PROOF_GATE_SOURCE_URL_OUTPUT, FACTORY_PROOF_GATE_STEP_ID, FACTORY_PROOF_GATE_STEP_NAME, FACTORY_PR_STATUS_HUD_APP_TOKEN_STEP_ID, FACTORY_PR_STATUS_HUD_CONCURRENCY, FACTORY_PR_STATUS_HUD_IF, FACTORY_PR_STATUS_HUD_JOB_ID, FACTORY_PR_STATUS_HUD_JOB_NAME, FACTORY_PR_STATUS_HUD_PERMISSIONS, FACTORY_PR_STATUS_HUD_PLAN_PATH, FACTORY_PUSH_IDENTITY_SCHEMA_VERSION, GitHubApiError, GitHubAppTokenTransportError, NODE_PNPM_ACTION_FAMILY_NODE24, PREVIEW_PROOF_INVENTORY_CHECK_NAME, PREVIEW_PROOF_INVENTORY_LIST_PERMISSIONS, PreviewProofTransportError, SETUP_STEP_ROLES, UPLOAD_ARTIFACT, VITEST_PROFILE_SCHEMA_VERSION, VITEST_PROFILE_TOOL, VitestProfileError, assertAlchemyBaseline, assertProofReuseCoverage, assertVerifyRunnerPolicy, assertWorkflowShellParses, bundleAlchemyEntry, captureVitestProfileEnvironment, executeAlchemyEntry, factoryCandidateImpactWorkflow, factoryCandidateOrPushCondition, factoryLifecycleContractLane, factoryMergeFreezeJob, factoryMergeFreezeScript, factoryPrStatusHudWorkflow, factoryPreviewCleanupTopology, factoryProductionImpactWorkflow, factoryProofGateScript, factoryProofGateStep, factoryProofReuseSummaryStep, factoryProofTimingStartStep, factoryPushIdentityConsumer, factoryPushIdentityProducer, factoryVerifyRunner, factoryWorkflow, githubAppJwt, isLocalPreviewStage, localPreviewStage, mintInstallationToken, normalizeVitestProfileSample, parseLocalPreviewStage, previewCleanupDestroyJobId, previewProofInventory, previewProofLifecycle, productionImpactTargetOutput, proofReuseCoverage, proofReuseRequiredCommands, readVitestProfileDocument, resolveProofReuseCommands, runVitestProfile, setupStepsForRoles, verifyRunnerPolicy, workflowRunBlocks, workflowShellParseFailures, writeVitestProfile };
3594
+ export { ALCHEMY_BASELINE, EXECUTE_ALCHEMY_ENTRY_MAX_BUFFER, FACTORY_APP_BROKER_ORIGIN, FACTORY_APP_BROKER_PATH, FACTORY_APP_BROKER_TOKEN_PERMISSIONS, FACTORY_CANDIDATE_IMPACT_BASIS_OUTPUT, FACTORY_CANDIDATE_IMPACT_DECISION_OUTPUT, FACTORY_CANDIDATE_IMPACT_INERT_OUTPUT, FACTORY_CANDIDATE_IMPACT_STEP_ID, FACTORY_CANDIDATE_IMPACT_UNSUBSCRIBED_OUTPUT, FACTORY_CANDIDATE_PULL_REQUEST_TYPES, FACTORY_CURSOR_OIDC_AUDIENCE, FACTORY_CURSOR_OIDC_ISSUER, FACTORY_CURSOR_OIDC_JWKS_URL, FACTORY_CURSOR_OIDC_MANAGED_RUNTIME, FACTORY_LIFECYCLE_CONTRACT_JOB_ID, FACTORY_LIFECYCLE_CONTRACT_JOB_NAME, FACTORY_MERGE_FREEZE_APP_TOKEN_STEP_ID, FACTORY_MERGE_FREEZE_CHECK_NAME, FACTORY_MERGE_FREEZE_IF, FACTORY_MERGE_FREEZE_JOB_ID, FACTORY_MERGE_FREEZE_JOB_NAME, FACTORY_MERGE_FREEZE_PERMISSIONS, FACTORY_MERGE_FREEZE_VERIFY_RESULT_EXPRESSION, FACTORY_MERGE_TARGET_REF_CONDITION, FACTORY_PREVIEW_CLEANUP_AUDIT_JOB_ID, FACTORY_PREVIEW_CLEANUP_AUDIT_JOB_NAME, FACTORY_PRODUCTION_IMPACT_BASIS_OUTPUT, FACTORY_PRODUCTION_IMPACT_DECISION_OUTPUT, FACTORY_PRODUCTION_IMPACT_STEP_ID, FACTORY_PRODUCTION_IMPACT_UNSUBSCRIBED_OUTPUT, FACTORY_PROOF_GATE_APP_ID, FACTORY_PROOF_GATE_CHECK_NAME, FACTORY_PROOF_GATE_GUARD, FACTORY_PROOF_GATE_IF, FACTORY_PROOF_GATE_MODE_OUTPUT, FACTORY_PROOF_GATE_OUTPUT, FACTORY_PROOF_GATE_REASONS, FACTORY_PROOF_GATE_REASON_OUTPUT, FACTORY_PROOF_GATE_SHELL, FACTORY_PROOF_GATE_SOURCE_URL_OUTPUT, FACTORY_PROOF_GATE_STEP_ID, FACTORY_PROOF_GATE_STEP_NAME, FACTORY_PR_STATUS_HUD_APP_TOKEN_STEP_ID, FACTORY_PR_STATUS_HUD_CONCURRENCY, FACTORY_PR_STATUS_HUD_IF, FACTORY_PR_STATUS_HUD_JOB_ID, FACTORY_PR_STATUS_HUD_JOB_NAME, FACTORY_PR_STATUS_HUD_PERMISSIONS, FACTORY_PR_STATUS_HUD_PLAN_PATH, FACTORY_PUSH_IDENTITY_SCHEMA_VERSION, GitHubApiError, GitHubAppTokenTransportError, NODE_PNPM_ACTION_FAMILY_NODE24, PREVIEW_PROOF_INVENTORY_CHECK_NAME, PREVIEW_PROOF_INVENTORY_LIST_PERMISSIONS, PreviewProofTransportError, SETUP_STEP_ROLES, UPLOAD_ARTIFACT, VITEST_PROFILE_SCHEMA_VERSION, VITEST_PROFILE_TOOL, VitestProfileError, assertAlchemyBaseline, assertProofReuseCoverage, assertVerifyRunnerPolicy, assertWorkflowShellParses, bundleAlchemyEntry, captureVitestProfileEnvironment, executeAlchemyEntry, factoryCandidateImpactWorkflow, factoryCandidateOrPushCondition, factoryLifecycleContractLane, factoryMergeFreezeJob, factoryMergeFreezeScript, factoryPrStatusHudWorkflow, factoryPreviewCleanupTopology, factoryPreviewReceiptWorkflow, factoryProductionImpactWorkflow, factoryProofGateScript, factoryProofGateStep, factoryProofReuseSummaryStep, factoryProofTimingStartStep, factoryPushIdentityConsumer, factoryPushIdentityProducer, factoryVerifyRunner, factoryWorkflow, githubAppJwt, isLocalPreviewStage, localPreviewStage, mintInstallationToken, normalizeVitestProfileSample, parseLocalPreviewStage, previewCleanupDestroyJobId, previewProofInventory, previewProofLifecycle, productionImpactTargetOutput, proofReuseCoverage, proofReuseRequiredCommands, readVitestProfileDocument, resolveProofReuseCommands, runVitestProfile, setupStepsForRoles, verifyRunnerPolicy, workflowRunBlocks, workflowShellParseFailures, writeVitestProfile };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@patronage/factory-ci",
3
- "version": "1.0.0-alpha.34",
3
+ "version": "1.0.0-alpha.35",
4
4
  "description": "Deep CI and deploy building blocks for Patronage factory projects: workflow source artifacts, hosted diff classification, Alchemy entry execution, and disposable-stage semantics",
5
5
  "keywords": [
6
6
  "alchemy",
@@ -49,7 +49,7 @@
49
49
  "typescript": "5.9.3",
50
50
  "ultracite": "7.10.5",
51
51
  "vitest": "4.1.10",
52
- "@patronage/alchemy-d1-state": "0.3.0"
52
+ "@patronage/alchemy-d1-state": "0.4.0"
53
53
  },
54
54
  "peerDependencies": {
55
55
  "alchemy": ">=2.0.0-beta.63 <3",