pipework 0.72.1 → 0.73.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/CHANGELOG.md CHANGED
@@ -1,5 +1,9 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.73.0
4
+
5
+ - **Changed: `pipework run` runs the script in the same flow a job gets.** The script is traced (a `job` trace, job type `script` unless `--job-type` is given), its `@flow_step` functions are recorded and its `@touches` writes are audited. With `--tenant`, the default database's transaction is bound to the flow with the tenant session variables set, and the script runs in one transaction: it commits when the script returns, and a script that throws has all its writes rolled back. Without `--tenant` nothing changes except the trace. Every command that loads TypeScript in-process from the built package now applies `@flow_step` (#497).
6
+
3
7
  ## 0.72.1
4
8
 
5
9
  - **Fixed: under `pipework serve` and `pipework dev`, `@flow_step` functions are now traced and their `@touches` writes audited.** Config discovery registered its own loader over the one that applies `@flow_step`, so request traces had no steps and no audit records were written (#486).
@@ -0,0 +1,17 @@
1
+ import type { Manifold } from '../../core/pipework.js';
2
+ export interface RunScriptOptions {
3
+ tenant?: string | null;
4
+ auth?: unknown;
5
+ jobType?: string;
6
+ }
7
+ /**
8
+ * Runs an operator script in the flow a job gets: a trace (entry kind `job`) that
9
+ * is closed `closed` or `error`, and, with a tenant, the default database's
10
+ * transaction bound to the flow with the tenant session variables set. The
11
+ * transaction commits when `fn` returns and rolls back when it throws. Without a
12
+ * tenant nothing is bound, as for a tenantless job.
13
+ *
14
+ * The trace close is awaited, so the row is written before the caller closes the pool.
15
+ */
16
+ export declare function runScript<T>(instance: Manifold, fn: () => T | Promise<T>, options?: RunScriptOptions): Promise<T>;
17
+ //# sourceMappingURL=run-script.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"run-script.d.ts","sourceRoot":"","sources":["../../../src/async/jobs/run-script.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,wBAAwB,CAAA;AAWtD,MAAM,WAAW,gBAAgB;IAC/B,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IACtB,IAAI,CAAC,EAAE,OAAO,CAAA;IACd,OAAO,CAAC,EAAE,MAAM,CAAA;CACjB;AAED;;;;;;;;GAQG;AACH,wBAAsB,SAAS,CAAC,CAAC,EAC/B,QAAQ,EAAE,QAAQ,EAClB,EAAE,EAAE,MAAM,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,EACxB,OAAO,GAAE,gBAAqB,GAC7B,OAAO,CAAC,CAAC,CAAC,CA8BZ"}
@@ -0,0 +1,48 @@
1
+ import { runInContext } from '../../request/context/store.js';
2
+ import { createJobContext } from '../../request/context/create.js';
3
+ import { executeInTransaction } from '../../request/context/run-in-transaction.js';
4
+ import { isTracingEnabled } from '../../trace/entry/tracing-enabled.js';
5
+ import { openTrace } from '../../trace/entry/open-trace.js';
6
+ import { parentTraceRef } from '../../trace/entry/parent-trace.js';
7
+ import { closeTrace } from '../../trace/entry/close-trace.js';
8
+ const SCRIPT_TRANSACTION_TIMEOUT_MS = 5000;
9
+ /**
10
+ * Runs an operator script in the flow a job gets: a trace (entry kind `job`) that
11
+ * is closed `closed` or `error`, and, with a tenant, the default database's
12
+ * transaction bound to the flow with the tenant session variables set. The
13
+ * transaction commits when `fn` returns and rolls back when it throws. Without a
14
+ * tenant nothing is bound, as for a tenantless job.
15
+ *
16
+ * The trace close is awaited, so the row is written before the caller closes the pool.
17
+ */
18
+ export async function runScript(instance, fn, options = {}) {
19
+ const tenant = options.tenant ?? null;
20
+ const auth = options.auth ?? null;
21
+ const jobType = options.jobType ?? 'script';
22
+ const databases = tenant === null ? [] : [instance.config.defaultDatabaseName()];
23
+ const trace = isTracingEnabled(instance)
24
+ ? openTrace({
25
+ instance,
26
+ entryKind: 'job',
27
+ parent: parentTraceRef(),
28
+ tenant,
29
+ auth,
30
+ requestId: null,
31
+ sessionId: null,
32
+ })
33
+ : null;
34
+ const ctx = createJobContext({ instance, jobType, auth, tenant, ...(trace !== null ? { trace } : {}) });
35
+ const run = async () => fn();
36
+ try {
37
+ const result = tenant === null
38
+ ? await runInContext(ctx, run)
39
+ : await executeInTransaction(ctx, databases, null, SCRIPT_TRANSACTION_TIMEOUT_MS, run);
40
+ await closeTrace(instance, trace, 'closed');
41
+ return result;
42
+ }
43
+ catch (err) {
44
+ await closeTrace(instance, trace, 'error');
45
+ throw err;
46
+ }
47
+ }
48
+ //# sourceMappingURL=run-script.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"run-script.js","sourceRoot":"","sources":["../../../src/async/jobs/run-script.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,YAAY,EAAE,MAAM,gCAAgC,CAAA;AAC7D,OAAO,EAAE,gBAAgB,EAAE,MAAM,iCAAiC,CAAA;AAClE,OAAO,EAAE,oBAAoB,EAAE,MAAM,6CAA6C,CAAA;AAClF,OAAO,EAAE,gBAAgB,EAAE,MAAM,sCAAsC,CAAA;AACvE,OAAO,EAAE,SAAS,EAAE,MAAM,iCAAiC,CAAA;AAC3D,OAAO,EAAE,cAAc,EAAE,MAAM,mCAAmC,CAAA;AAClE,OAAO,EAAE,UAAU,EAAE,MAAM,kCAAkC,CAAA;AAE7D,MAAM,6BAA6B,GAAG,IAAI,CAAA;AAQ1C;;;;;;;;GAQG;AACH,MAAM,CAAC,KAAK,UAAU,SAAS,CAC7B,QAAkB,EAClB,EAAwB,EACxB,UAA4B,EAAE;IAE9B,MAAM,MAAM,GAAG,OAAO,CAAC,MAAM,IAAI,IAAI,CAAA;IACrC,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,IAAI,IAAI,CAAA;IACjC,MAAM,OAAO,GAAG,OAAO,CAAC,OAAO,IAAI,QAAQ,CAAA;IAC3C,MAAM,SAAS,GAAG,MAAM,KAAK,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,mBAAmB,EAAE,CAAC,CAAA;IAChF,MAAM,KAAK,GAAG,gBAAgB,CAAC,QAAQ,CAAC;QACtC,CAAC,CAAC,SAAS,CAAC;YACV,QAAQ;YACR,SAAS,EAAE,KAAK;YAChB,MAAM,EAAE,cAAc,EAAE;YACxB,MAAM;YACN,IAAI;YACJ,SAAS,EAAE,IAAI;YACf,SAAS,EAAE,IAAI;SAChB,CAAC;QACF,CAAC,CAAC,IAAI,CAAA;IAER,MAAM,GAAG,GAAG,gBAAgB,CAAC,EAAE,QAAQ,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,GAAG,CAAC,KAAK,KAAK,IAAI,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAA;IACvG,MAAM,GAAG,GAAG,KAAK,IAAgB,EAAE,CAAC,EAAE,EAAE,CAAA;IAExC,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,MAAM,KAAK,IAAI;YAC5B,CAAC,CAAC,MAAM,YAAY,CAAC,GAAG,EAAE,GAAG,CAAC;YAC9B,CAAC,CAAC,MAAM,oBAAoB,CAAC,GAAG,EAAE,SAAS,EAAE,IAAI,EAAE,6BAA6B,EAAE,GAAG,CAAC,CAAA;QACxF,MAAM,UAAU,CAAC,QAAQ,EAAE,KAAK,EAAE,QAAQ,CAAC,CAAA;QAC3C,OAAO,MAAM,CAAA;IACf,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,MAAM,UAAU,CAAC,QAAQ,EAAE,KAAK,EAAE,OAAO,CAAC,CAAA;QAC1C,MAAM,GAAG,CAAA;IACX,CAAC;AACH,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"run.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/run.ts"],"names":[],"mappings":"AAKA,MAAM,WAAW,iBAAiB;IAChC,MAAM,EAAE,MAAM,CAAA;IACd,GAAG,EAAE,MAAM,CAAA;IACX,MAAM,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;IAC3B,OAAO,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;CAC7B;AAED,wBAAsB,GAAG,CAAC,OAAO,EAAE,iBAAiB,GAAG,OAAO,CAAC,IAAI,CAAC,CA0BnE"}
1
+ {"version":3,"file":"run.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/run.ts"],"names":[],"mappings":"AAMA,MAAM,WAAW,iBAAiB;IAChC,MAAM,EAAE,MAAM,CAAA;IACd,GAAG,EAAE,MAAM,CAAA;IACX,MAAM,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;IAC3B,OAAO,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;CAC7B;AAED,wBAAsB,GAAG,CAAC,OAAO,EAAE,iBAAiB,GAAG,OAAO,CAAC,IAAI,CAAC,CA0BnE"}
@@ -1,6 +1,7 @@
1
1
  import { resolve } from 'node:path';
2
2
  import { existsSync } from 'node:fs';
3
3
  import { pathToFileURL } from 'node:url';
4
+ import { runScript } from '../../async/jobs/run-script.js';
4
5
  import { bold, success } from '../output.js';
5
6
  export async function run(options) {
6
7
  const scriptPath = resolve(options.cwd, options.script);
@@ -12,7 +13,7 @@ export async function run(options) {
12
13
  const { discoverInstance } = await import('../../core/config/discover.js');
13
14
  const instance = await discoverInstance(options.cwd);
14
15
  try {
15
- await instance.seed(async () => {
16
+ await runScript(instance, async () => {
16
17
  await import(pathToFileURL(scriptPath).href);
17
18
  }, {
18
19
  jobType: options.jobType ?? 'script',
@@ -1 +1 @@
1
- {"version":3,"file":"run.js","sourceRoot":"","sources":["../../../src/cli/commands/run.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AACnC,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAA;AACpC,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAA;AACxC,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,cAAc,CAAA;AAS5C,MAAM,CAAC,KAAK,UAAU,GAAG,CAAC,OAA0B;IAClD,MAAM,UAAU,GAAG,OAAO,CAAC,OAAO,CAAC,GAAG,EAAE,OAAO,CAAC,MAAM,CAAC,CAAA;IAEvD,IAAI,CAAC,UAAU,CAAC,UAAU,CAAC,EAAE,CAAC;QAC5B,MAAM,IAAI,KAAK,CACb,qBAAqB,OAAO,CAAC,MAAM,MAAM;YACzC,kDAAkD;YAClD,cAAc,IAAI,CAAC,gCAAgC,CAAC,IAAI,CACzD,CAAA;IACH,CAAC;IAED,MAAM,EAAE,gBAAgB,EAAE,GAAG,MAAM,MAAM,CAAC,+BAA+B,CAAC,CAAA;IAE1E,MAAM,QAAQ,GAAG,MAAM,gBAAgB,CAAC,OAAO,CAAC,GAAG,CAAC,CAAA;IAEpD,IAAI,CAAC;QACH,MAAM,QAAQ,CAAC,IAAI,CAAC,KAAK,IAAI,EAAE;YAC7B,MAAM,MAAM,CAAC,aAAa,CAAC,UAAU,CAAC,CAAC,IAAI,CAAC,CAAA;QAC9C,CAAC,EAAE;YACD,OAAO,EAAE,OAAO,CAAC,OAAO,IAAI,QAAQ;YACpC,MAAM,EAAE,OAAO,CAAC,MAAM,IAAI,IAAI;SAC/B,CAAC,CAAA;QACF,OAAO,CAAC,qBAAqB,OAAO,CAAC,MAAM,EAAE,CAAC,CAAA;IAChD,CAAC;YAAS,CAAC;QACT,MAAM,QAAQ,CAAC,IAAI,CAAC,QAAQ,EAAE,CAAA;IAChC,CAAC;AACH,CAAC"}
1
+ {"version":3,"file":"run.js","sourceRoot":"","sources":["../../../src/cli/commands/run.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AACnC,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAA;AACpC,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAA;AACxC,OAAO,EAAE,SAAS,EAAE,MAAM,gCAAgC,CAAA;AAC1D,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,cAAc,CAAA;AAS5C,MAAM,CAAC,KAAK,UAAU,GAAG,CAAC,OAA0B;IAClD,MAAM,UAAU,GAAG,OAAO,CAAC,OAAO,CAAC,GAAG,EAAE,OAAO,CAAC,MAAM,CAAC,CAAA;IAEvD,IAAI,CAAC,UAAU,CAAC,UAAU,CAAC,EAAE,CAAC;QAC5B,MAAM,IAAI,KAAK,CACb,qBAAqB,OAAO,CAAC,MAAM,MAAM;YACzC,kDAAkD;YAClD,cAAc,IAAI,CAAC,gCAAgC,CAAC,IAAI,CACzD,CAAA;IACH,CAAC;IAED,MAAM,EAAE,gBAAgB,EAAE,GAAG,MAAM,MAAM,CAAC,+BAA+B,CAAC,CAAA;IAE1E,MAAM,QAAQ,GAAG,MAAM,gBAAgB,CAAC,OAAO,CAAC,GAAG,CAAC,CAAA;IAEpD,IAAI,CAAC;QACH,MAAM,SAAS,CAAC,QAAQ,EAAE,KAAK,IAAI,EAAE;YACnC,MAAM,MAAM,CAAC,aAAa,CAAC,UAAU,CAAC,CAAC,IAAI,CAAC,CAAA;QAC9C,CAAC,EAAE;YACD,OAAO,EAAE,OAAO,CAAC,OAAO,IAAI,QAAQ;YACpC,MAAM,EAAE,OAAO,CAAC,MAAM,IAAI,IAAI;SAC/B,CAAC,CAAA;QACF,OAAO,CAAC,qBAAqB,OAAO,CAAC,MAAM,EAAE,CAAC,CAAA;IAChD,CAAC;YAAS,CAAC;QACT,MAAM,QAAQ,CAAC,IAAI,CAAC,QAAQ,EAAE,CAAA;IAChC,CAAC;AACH,CAAC"}
package/dist/cli/index.js CHANGED
@@ -14,7 +14,7 @@ ${bold('Commands:')}
14
14
  remove <pkg> Remove dependency from config, sync, and install
15
15
  generate Generate SQL migrations from Drizzle schema changes
16
16
  migrate Run pending migrations for all databases
17
- run <script> Execute a script with database context
17
+ run <script> Execute a script as a traced, audited flow (with --tenant: one transaction, rolled back if it throws)
18
18
  test Run tests with automatic database setup
19
19
  check Type-check, lint, and boundary enforcement
20
20
  codemod Fill missing @downstream cardinality across the corpus
@@ -27,7 +27,7 @@ ${bold('Options:')}
27
27
  --version, -v Show version
28
28
  --name Migration name (used with generate)
29
29
  --confirm Required for production migrations
30
- --tenant Tenant ID for tenant-scoped scripts
30
+ --tenant Tenant ID; the script runs in one transaction on the default database
31
31
  --job-type Override job type (default: "script")
32
32
 
33
33
  ${bold('Scoping (check, test):')}
@@ -1 +1 @@
1
- {"version":3,"file":"ts-inline-hooks.d.ts","sourceRoot":"","sources":["../../../src/core/config/ts-inline-hooks.ts"],"names":[],"mappings":"AAEA,eAAO,MAAM,QAAQ,eAAiC,CAAA;AAEtD,wBAAgB,sBAAsB,IAAI,IAAI,CA4D7C"}
1
+ {"version":3,"file":"ts-inline-hooks.d.ts","sourceRoot":"","sources":["../../../src/core/config/ts-inline-hooks.ts"],"names":[],"mappings":"AAGA,eAAO,MAAM,QAAQ,eAAiC,CAAA;AAEtD,wBAAgB,sBAAsB,IAAI,IAAI,CAqE7C"}
@@ -1,13 +1,23 @@
1
1
  import { register } from 'node:module';
2
+ import { existsSync } from 'node:fs';
2
3
  export const TS_HOOKS = Symbol.for('pipework.tsHooks');
3
4
  export function registerTsResolveHooks() {
4
5
  if (Reflect.get(globalThis, TS_HOOKS) !== undefined)
5
6
  return;
7
+ // Built package: the compiled transforming hook sits beside this file, so every
8
+ // in-process CLI path (run, seed, ...) applies @flow_step like serve and dev do.
9
+ if (existsSync(new URL('./ts-resolve-hooks.js', import.meta.url))) {
10
+ register('./ts-resolve-hooks.js', import.meta.url);
11
+ Reflect.set(globalThis, TS_HOOKS, 'transforming');
12
+ return;
13
+ }
6
14
  {
7
- // Marker contract: ts-register.js sets globalThis[Symbol.for('pipework.tsHooks')]
8
- // to 'transforming' when it installs the @flow_step-applying loader; this
9
- // function then installs nothing, since a hook registered later would run first
10
- // and shadow it. Otherwise it installs one hook and marks 'inline'.
15
+ // Marker contract: globalThis[Symbol.for('pipework.tsHooks')] is 'transforming'
16
+ // once the @flow_step-applying loader is installed (by ts-register.js, or by this
17
+ // function when the built ts-resolve-hooks.js sits beside it); a hook registered
18
+ // later would run first and shadow it, so then nothing more is installed.
19
+ // Source-mode runs, where the compiled hook does not exist, install one inline
20
+ // hook and mark 'inline'.
11
21
  // Self-contained mirror of ts-resolve-hooks.ts, registered as a `data:` URL so
12
22
  // it works during pipework's own source-mode runs where the compiled
13
23
  // ts-resolve-hooks.js does not exist yet. `resolve` maps a relative specifier
@@ -1 +1 @@
1
- {"version":3,"file":"ts-inline-hooks.js","sourceRoot":"","sources":["../../../src/core/config/ts-inline-hooks.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAA;AAEtC,MAAM,CAAC,MAAM,QAAQ,GAAG,MAAM,CAAC,GAAG,CAAC,kBAAkB,CAAC,CAAA;AAEtD,MAAM,UAAU,sBAAsB;IACpC,IAAI,OAAO,CAAC,GAAG,CAAC,UAAU,EAAE,QAAQ,CAAC,KAAK,SAAS;QAAE,OAAM;IAC3D,CAAC;QACC,kFAAkF;QAClF,0EAA0E;QAC1E,gFAAgF;QAChF,oEAAoE;QACpE,+EAA+E;QAC/E,qEAAqE;QACrE,8EAA8E;QAC9E,+EAA+E;QAC/E,+DAA+D;QAC/D,gFAAgF;QAChF,sHAAsH;QACtH,MAAM,IAAI,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;KA0CZ,CAAA;QACD,QAAQ,CAAC,wBAAwB,kBAAkB,CAAC,IAAI,CAAC,EAAE,CAAC,CAAA;QAC5D,OAAO,CAAC,GAAG,CAAC,UAAU,EAAE,QAAQ,EAAE,QAAQ,CAAC,CAAA;IAC7C,CAAC;AACH,CAAC"}
1
+ {"version":3,"file":"ts-inline-hooks.js","sourceRoot":"","sources":["../../../src/core/config/ts-inline-hooks.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAA;AACtC,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAA;AAEpC,MAAM,CAAC,MAAM,QAAQ,GAAG,MAAM,CAAC,GAAG,CAAC,kBAAkB,CAAC,CAAA;AAEtD,MAAM,UAAU,sBAAsB;IACpC,IAAI,OAAO,CAAC,GAAG,CAAC,UAAU,EAAE,QAAQ,CAAC,KAAK,SAAS;QAAE,OAAM;IAC3D,gFAAgF;IAChF,iFAAiF;IACjF,IAAI,UAAU,CAAC,IAAI,GAAG,CAAC,uBAAuB,EAAE,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC;QAClE,QAAQ,CAAC,uBAAuB,EAAE,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAA;QAClD,OAAO,CAAC,GAAG,CAAC,UAAU,EAAE,QAAQ,EAAE,cAAc,CAAC,CAAA;QACjD,OAAM;IACR,CAAC;IACD,CAAC;QACC,gFAAgF;QAChF,kFAAkF;QAClF,iFAAiF;QACjF,0EAA0E;QAC1E,+EAA+E;QAC/E,0BAA0B;QAC1B,+EAA+E;QAC/E,qEAAqE;QACrE,8EAA8E;QAC9E,+EAA+E;QAC/E,+DAA+D;QAC/D,gFAAgF;QAChF,sHAAsH;QACtH,MAAM,IAAI,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;KA0CZ,CAAA;QACD,QAAQ,CAAC,wBAAwB,kBAAkB,CAAC,IAAI,CAAC,EAAE,CAAC,CAAA;QAC5D,OAAO,CAAC,GAAG,CAAC,UAAU,EAAE,QAAQ,EAAE,QAAQ,CAAC,CAAA;IAC7C,CAAC;AACH,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pipework",
3
- "version": "0.72.1",
3
+ "version": "0.73.0",
4
4
  "description": "TypeScript framework for multi-tenant SaaS applications. PostgreSQL-only.",
5
5
  "type": "module",
6
6
  "license": "MIT",