@voyantjs/workflow-runs 0.107.8 → 0.107.9

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
@@ -77,9 +77,27 @@ workflowRunnerRegistry.register({
77
77
 
78
78
  mountWorkflowRunsAdminRoutes(hono, {
79
79
  runners: workflowRunnerRegistry,
80
+ adminSurface: process.env.VOYANT_WORKFLOW_ADMIN_SURFACE as
81
+ | "tenant"
82
+ | "cloud"
83
+ | "disabled"
84
+ | undefined,
80
85
  })
81
86
  ```
82
87
 
88
+ `adminSurface` controls tenant-admin workflow management actions:
89
+
90
+ - `tenant` keeps local/self-host trigger, rerun, and resume routes available.
91
+ - `cloud` keeps read routes available but rejects tenant-admin trigger, rerun,
92
+ and resume routes because the Voyant Cloud dashboard is the workflow control
93
+ plane for managed deployments.
94
+ - `disabled` keeps read routes available and disables tenant-admin management
95
+ actions completely.
96
+
97
+ When omitted, the package reads `VOYANT_WORKFLOW_ADMIN_SURFACE`. If that is
98
+ unset but managed Cloud workflow env is present, the default is `cloud`;
99
+ otherwise the default is `tenant` for local/self-host compatibility.
100
+
83
101
  Triggerable workflows must opt in by implementing `trigger(...)` on their registered runner. This keeps rerun/resume-only workflows closed to arbitrary admin dispatch while still allowing operators, cron jobs, queues, and API keys with `workflows:trigger` permission to call:
84
102
 
85
103
  ```http
package/dist/index.d.ts CHANGED
@@ -17,7 +17,7 @@
17
17
  * separate worker process.
18
18
  */
19
19
  export { type BeginWorkflowRunInput, beginWorkflowRun, type WorkflowRunRecorder, } from "./recorder.js";
20
- export { mountWorkflowRunsAdminRoutes } from "./routes.js";
20
+ export { mountWorkflowRunsAdminRoutes, resolveWorkflowAdminSurface, type WorkflowAdminSurface, } from "./routes.js";
21
21
  export { type WorkflowIdempotency, type WorkflowRerunContext, type WorkflowResumeContext, type WorkflowRunner, WorkflowRunnerRegistry, type WorkflowTriggerContext, } from "./runner.js";
22
22
  export { type NewWorkflowRun, type NewWorkflowRunStep, type WorkflowRun, type WorkflowRunErrorPayload, type WorkflowRunStep, workflowRunStatusEnum, workflowRunStepStatusEnum, workflowRunSteps, workflowRuns, } from "./schema.js";
23
23
  export { type ListWorkflowRunsQuery, type ListWorkflowRunsResult, workflowRunsService, } from "./service.js";
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAEH,OAAO,EACL,KAAK,qBAAqB,EAC1B,gBAAgB,EAChB,KAAK,mBAAmB,GACzB,MAAM,eAAe,CAAA;AACtB,OAAO,EAAE,4BAA4B,EAAE,MAAM,aAAa,CAAA;AAC1D,OAAO,EACL,KAAK,mBAAmB,EACxB,KAAK,oBAAoB,EACzB,KAAK,qBAAqB,EAC1B,KAAK,cAAc,EACnB,sBAAsB,EACtB,KAAK,sBAAsB,GAC5B,MAAM,aAAa,CAAA;AACpB,OAAO,EACL,KAAK,cAAc,EACnB,KAAK,kBAAkB,EACvB,KAAK,WAAW,EAChB,KAAK,uBAAuB,EAC5B,KAAK,eAAe,EACpB,qBAAqB,EACrB,yBAAyB,EACzB,gBAAgB,EAChB,YAAY,GACb,MAAM,aAAa,CAAA;AACpB,OAAO,EACL,KAAK,qBAAqB,EAC1B,KAAK,sBAAsB,EAC3B,mBAAmB,GACpB,MAAM,cAAc,CAAA;AACrB,OAAO,EACL,KAAK,uBAAuB,EAC5B,KAAK,6BAA6B,EAClC,KAAK,0BAA0B,EAC/B,gBAAgB,GACjB,MAAM,gBAAgB,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAEH,OAAO,EACL,KAAK,qBAAqB,EAC1B,gBAAgB,EAChB,KAAK,mBAAmB,GACzB,MAAM,eAAe,CAAA;AACtB,OAAO,EACL,4BAA4B,EAC5B,2BAA2B,EAC3B,KAAK,oBAAoB,GAC1B,MAAM,aAAa,CAAA;AACpB,OAAO,EACL,KAAK,mBAAmB,EACxB,KAAK,oBAAoB,EACzB,KAAK,qBAAqB,EAC1B,KAAK,cAAc,EACnB,sBAAsB,EACtB,KAAK,sBAAsB,GAC5B,MAAM,aAAa,CAAA;AACpB,OAAO,EACL,KAAK,cAAc,EACnB,KAAK,kBAAkB,EACvB,KAAK,WAAW,EAChB,KAAK,uBAAuB,EAC5B,KAAK,eAAe,EACpB,qBAAqB,EACrB,yBAAyB,EACzB,gBAAgB,EAChB,YAAY,GACb,MAAM,aAAa,CAAA;AACpB,OAAO,EACL,KAAK,qBAAqB,EAC1B,KAAK,sBAAsB,EAC3B,mBAAmB,GACpB,MAAM,cAAc,CAAA;AACrB,OAAO,EACL,KAAK,uBAAuB,EAC5B,KAAK,6BAA6B,EAClC,KAAK,0BAA0B,EAC/B,gBAAgB,GACjB,MAAM,gBAAgB,CAAA"}
package/dist/index.js CHANGED
@@ -17,7 +17,7 @@
17
17
  * separate worker process.
18
18
  */
19
19
  export { beginWorkflowRun, } from "./recorder.js";
20
- export { mountWorkflowRunsAdminRoutes } from "./routes.js";
20
+ export { mountWorkflowRunsAdminRoutes, resolveWorkflowAdminSurface, } from "./routes.js";
21
21
  export { WorkflowRunnerRegistry, } from "./runner.js";
22
22
  export { workflowRunStatusEnum, workflowRunStepStatusEnum, workflowRunSteps, workflowRuns, } from "./schema.js";
23
23
  export { workflowRunsService, } from "./service.js";
package/dist/routes.d.ts CHANGED
@@ -16,6 +16,8 @@
16
16
  */
17
17
  import type { Hono } from "hono";
18
18
  import type { WorkflowRunnerRegistry } from "./runner.js";
19
+ export type WorkflowAdminSurface = "tenant" | "cloud" | "disabled";
20
+ export declare function resolveWorkflowAdminSurface(value: string | undefined): WorkflowAdminSurface;
19
21
  export interface MountWorkflowRunsAdminRoutesOptions {
20
22
  /**
21
23
  * Registry of executable runners keyed by workflow name. Required
@@ -29,6 +31,13 @@ export interface MountWorkflowRunsAdminRoutesOptions {
29
31
  * are recorded without an actor.
30
32
  */
31
33
  resolveUserId?: (c: unknown) => string | null;
34
+ /**
35
+ * Controls whether tenant-admin workflow management actions are exposed.
36
+ * `tenant` preserves local/self-host behavior. `cloud` and `disabled`
37
+ * reject tenant-admin trigger/rerun/resume routes server-side while leaving
38
+ * read paths mounted for observability consumers that still need them.
39
+ */
40
+ adminSurface?: WorkflowAdminSurface;
32
41
  }
33
42
  export declare function mountWorkflowRunsAdminRoutes(hono: Hono, opts?: MountWorkflowRunsAdminRoutesOptions): void;
34
43
  //# sourceMappingURL=routes.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"routes.d.ts","sourceRoot":"","sources":["../src/routes.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAGH,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,MAAM,CAAA;AAGhC,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,aAAa,CAAA;AA2CzD,MAAM,WAAW,mCAAmC;IAClD;;;;OAIG;IACH,OAAO,CAAC,EAAE,sBAAsB,CAAA;IAChC;;;;OAIG;IACH,aAAa,CAAC,EAAE,CAAC,CAAC,EAAE,OAAO,KAAK,MAAM,GAAG,IAAI,CAAA;CAC9C;AAED,wBAAgB,4BAA4B,CAC1C,IAAI,EAAE,IAAI,EACV,IAAI,GAAE,mCAAwC,GAC7C,IAAI,CAsRN"}
1
+ {"version":3,"file":"routes.d.ts","sourceRoot":"","sources":["../src/routes.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAGH,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,MAAM,CAAA;AAGhC,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,aAAa,CAAA;AA0BzD,MAAM,MAAM,oBAAoB,GAAG,QAAQ,GAAG,OAAO,GAAG,UAAU,CAAA;AAElE,wBAAgB,2BAA2B,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,GAAG,oBAAoB,CAQ3F;AAmBD,MAAM,WAAW,mCAAmC;IAClD;;;;OAIG;IACH,OAAO,CAAC,EAAE,sBAAsB,CAAA;IAChC;;;;OAIG;IACH,aAAa,CAAC,EAAE,CAAC,CAAC,EAAE,OAAO,KAAK,MAAM,GAAG,IAAI,CAAA;IAC7C;;;;;OAKG;IACH,YAAY,CAAC,EAAE,oBAAoB,CAAA;CACpC;AAED,wBAAgB,4BAA4B,CAC1C,IAAI,EAAE,IAAI,EACV,IAAI,GAAE,mCAAwC,GAC7C,IAAI,CAiSN"}
package/dist/routes.js CHANGED
@@ -37,6 +37,14 @@ const triggerWorkflowBodySchema = z
37
37
  tags: z.array(z.string().trim().min(1).max(128)).max(50).optional(),
38
38
  })
39
39
  .strict();
40
+ export function resolveWorkflowAdminSurface(value) {
41
+ if (value === "tenant" || value === "cloud" || value === "disabled")
42
+ return value;
43
+ if (value !== undefined && value.trim().length > 0) {
44
+ throw new Error(`Invalid workflow admin surface "${value}". Expected tenant, cloud, or disabled.`);
45
+ }
46
+ return "tenant";
47
+ }
40
48
  function hasWorkflowTriggerScope(scopes) {
41
49
  if (!Array.isArray(scopes) || !scopes.every((scope) => typeof scope === "string")) {
42
50
  return false;
@@ -51,6 +59,7 @@ function hasWorkflowTriggerScope(scopes) {
51
59
  });
52
60
  }
53
61
  export function mountWorkflowRunsAdminRoutes(hono, opts = {}) {
62
+ const adminSurface = opts.adminSurface ?? defaultWorkflowAdminSurface();
54
63
  hono.get("/v1/admin/workflow-runs", async (c) => {
55
64
  const params = Object.fromEntries(new URL(c.req.url).searchParams);
56
65
  const parsed = listQuerySchema.safeParse(params);
@@ -95,6 +104,9 @@ export function mountWorkflowRunsAdminRoutes(hono, opts = {}) {
95
104
  }
96
105
  });
97
106
  hono.post("/v1/admin/workflows/:name/runs", async (c) => {
107
+ const blocked = rejectWorkflowAdminAction(adminSurface, c);
108
+ if (blocked)
109
+ return blocked;
98
110
  if (!opts.runners) {
99
111
  return c.json({ error: "trigger_not_configured", detail: "no WorkflowRunnerRegistry mounted" }, 501);
100
112
  }
@@ -140,6 +152,9 @@ export function mountWorkflowRunsAdminRoutes(hono, opts = {}) {
140
152
  }
141
153
  });
142
154
  hono.post("/v1/admin/workflow-runs/:id/rerun", async (c) => {
155
+ const blocked = rejectWorkflowAdminAction(adminSurface, c);
156
+ if (blocked)
157
+ return blocked;
143
158
  // biome-ignore lint/suspicious/noExplicitAny: Hono's c.var.db is loosely typed -- owner: workflow-runs; existing suppression is intentional pending typed cleanup.
144
159
  const db = c.var.db;
145
160
  if (!db)
@@ -200,6 +215,9 @@ export function mountWorkflowRunsAdminRoutes(hono, opts = {}) {
200
215
  }
201
216
  });
202
217
  hono.post("/v1/admin/workflow-runs/:id/resume", async (c) => {
218
+ const blocked = rejectWorkflowAdminAction(adminSurface, c);
219
+ if (blocked)
220
+ return blocked;
203
221
  // biome-ignore lint/suspicious/noExplicitAny: Hono's c.var.db is loosely typed -- owner: workflow-runs; existing suppression is intentional pending typed cleanup.
204
222
  const db = c.var.db;
205
223
  if (!db)
@@ -271,3 +289,23 @@ export function mountWorkflowRunsAdminRoutes(hono, opts = {}) {
271
289
  }
272
290
  });
273
291
  }
292
+ function rejectWorkflowAdminAction(surface, c) {
293
+ if (surface === "tenant")
294
+ return undefined;
295
+ return c.json({
296
+ error: "workflow_admin_surface_restricted",
297
+ detail: surface === "cloud"
298
+ ? "Workflow management actions are owned by Voyant Cloud for this deployment."
299
+ : "Workflow management actions are disabled for this deployment.",
300
+ surface,
301
+ }, 403);
302
+ }
303
+ function defaultWorkflowAdminSurface() {
304
+ const env = globalThis.process?.env;
305
+ if (env?.VOYANT_WORKFLOW_ADMIN_SURFACE !== undefined) {
306
+ return resolveWorkflowAdminSurface(env.VOYANT_WORKFLOW_ADMIN_SURFACE);
307
+ }
308
+ if (env?.VOYANT_CLOUD_WORKFLOWS_URL || env?.VOYANT_CLOUD_APP_SLUG)
309
+ return "cloud";
310
+ return "tenant";
311
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@voyantjs/workflow-runs",
3
- "version": "0.107.8",
3
+ "version": "0.107.9",
4
4
  "description": "Workflow run recording, admin routes, and rerun/resume dispatch primitives for Voyant operator apps.",
5
5
  "license": "Apache-2.0",
6
6
  "type": "module",
@@ -49,13 +49,13 @@
49
49
  "@voyantjs/core": "^0.109.0",
50
50
  "@voyantjs/db": "^0.108.0",
51
51
  "@voyantjs/hono": "^0.109.1",
52
- "@voyantjs/workflows": "^0.107.8"
52
+ "@voyantjs/workflows": "^0.107.9"
53
53
  },
54
54
  "devDependencies": {
55
55
  "typescript": "^6.0.2",
56
56
  "vitest": "^4.1.2",
57
- "@voyantjs/voyant-typescript-config": "^0.1.0",
58
- "@voyantjs/workflows-orchestrator": "^0.107.8"
57
+ "@voyantjs/workflows-orchestrator": "^0.107.9",
58
+ "@voyantjs/voyant-typescript-config": "^0.1.0"
59
59
  },
60
60
  "files": [
61
61
  "dist"