@lostgradient/weft 0.16.0 → 0.18.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 (119) hide show
  1. package/README.md +1 -1
  2. package/dist/alerting/alert-manager.d.ts +5 -5
  3. package/dist/alerting/alert-manager.js +24 -6
  4. package/dist/alerting/index.d.ts +1 -1
  5. package/dist/alerting/types.d.ts +17 -13
  6. package/dist/alerting/types.js +5 -0
  7. package/dist/cli/generated/operation-catalog.snapshot.json +73 -0
  8. package/dist/cli/generated/operation-client.generated.d.ts +11 -2
  9. package/dist/cli/generated/operation-client.generated.js +2 -0
  10. package/dist/core/engine/disposal.js +7 -0
  11. package/dist/core/engine/engine-runtime-helpers.d.ts +3 -1
  12. package/dist/core/engine/engine-runtime-helpers.js +2 -2
  13. package/dist/core/engine/errors.d.ts +20 -0
  14. package/dist/core/engine/errors.js +8 -0
  15. package/dist/core/engine/index.d.ts +39 -17
  16. package/dist/core/engine/index.js +81 -9
  17. package/dist/core/engine/inline-launch-queue.d.ts +6 -2
  18. package/dist/core/engine/inline-launch-queue.js +41 -6
  19. package/dist/core/engine/internals.d.ts +2 -0
  20. package/dist/core/engine/lease-manager.d.ts +3 -2
  21. package/dist/core/engine/lease-manager.js +7 -3
  22. package/dist/core/engine/operations-time.js +6 -0
  23. package/dist/core/execution-strategy.d.ts +8 -0
  24. package/dist/core/inline-execution-strategy.d.ts +1 -0
  25. package/dist/core/inline-execution-strategy.js +33 -20
  26. package/dist/core/weft-error.d.ts +1 -1
  27. package/dist/core/weft-error.js +1 -0
  28. package/dist/core/worker-execution-strategy.d.ts +2 -0
  29. package/dist/core/worker-execution-strategy.js +7 -2
  30. package/dist/core/worker-turn-watchdog.d.ts +4 -1
  31. package/dist/core/worker-turn-watchdog.js +9 -4
  32. package/dist/index.d.ts +2 -2
  33. package/dist/index.js +1 -0
  34. package/dist/indexeddb.js +1 -1
  35. package/dist/json-schema.js +1 -1
  36. package/dist/mcp/tools.js +1 -3
  37. package/dist/server/authorization-scope.d.ts +32 -2
  38. package/dist/server/dashboard-assets.d.ts +12 -1
  39. package/dist/server/dashboard-assets.js +145 -31
  40. package/dist/server/index.d.ts +2 -0
  41. package/dist/server/index.js +4 -0
  42. package/dist/server/operations/aggregate-workflows.js +0 -7
  43. package/dist/server/operations/async-activity.js +5 -24
  44. package/dist/server/operations/bulk-cancel-workflows.js +3 -8
  45. package/dist/server/operations/bulk-delete-workflows.js +3 -8
  46. package/dist/server/operations/bulk-mutate-workflow-tags.js +3 -8
  47. package/dist/server/operations/bulk-operation-helpers.d.ts +2 -10
  48. package/dist/server/operations/bulk-operation-helpers.js +0 -6
  49. package/dist/server/operations/bulk-retry-failed-workflows.js +3 -8
  50. package/dist/server/operations/bulk-signal-workflows.js +3 -8
  51. package/dist/server/operations/cancel-schedule.js +1 -3
  52. package/dist/server/operations/cancel-workflow.js +1 -3
  53. package/dist/server/operations/create-schedule.js +2 -3
  54. package/dist/server/operations/fork-workflow.js +2 -3
  55. package/dist/server/operations/get-checkpoint-at.js +1 -6
  56. package/dist/server/operations/get-principal.d.ts +75 -0
  57. package/dist/server/operations/get-principal.js +41 -0
  58. package/dist/server/operations/get-registry.js +1 -7
  59. package/dist/server/operations/get-retention-overview.js +2 -15
  60. package/dist/server/operations/get-review.js +2 -15
  61. package/dist/server/operations/get-schedule.js +2 -8
  62. package/dist/server/operations/get-stream-chunks.js +2 -6
  63. package/dist/server/operations/get-system-lease.js +1 -7
  64. package/dist/server/operations/get-system-metrics.js +0 -4
  65. package/dist/server/operations/get-task-diagnostics.js +2 -13
  66. package/dist/server/operations/get-update-result.js +1 -6
  67. package/dist/server/operations/get-workflow-attributes.js +2 -15
  68. package/dist/server/operations/get-workflow-events.js +2 -15
  69. package/dist/server/operations/get-workflow-observability.js +2 -5
  70. package/dist/server/operations/get-workflow-result.js +0 -7
  71. package/dist/server/operations/get-workflow-timeline.js +1 -6
  72. package/dist/server/operations/get-workflow.d.ts +3 -6
  73. package/dist/server/operations/get-workflow.js +2 -12
  74. package/dist/server/operations/list-alerts.d.ts +5 -2
  75. package/dist/server/operations/list-alerts.js +2 -9
  76. package/dist/server/operations/list-checkpoints.js +1 -6
  77. package/dist/server/operations/list-reviews.js +0 -7
  78. package/dist/server/operations/list-schedules.js +3 -8
  79. package/dist/server/operations/list-task-queues.js +0 -4
  80. package/dist/server/operations/list-workers.js +0 -4
  81. package/dist/server/operations/list-workflows.js +0 -7
  82. package/dist/server/operations/pause-schedule.js +1 -3
  83. package/dist/server/operations/purge-workflows.js +2 -5
  84. package/dist/server/operations/query-workflow.js +4 -15
  85. package/dist/server/operations/replay-workflow.js +2 -6
  86. package/dist/server/operations/resume-schedule.js +1 -3
  87. package/dist/server/operations/resume-workflow.js +1 -3
  88. package/dist/server/operations/set-workflow-attributes.js +3 -15
  89. package/dist/server/operations/signal-workflow.js +3 -12
  90. package/dist/server/operations/single-workflow-tag-mutation.js +0 -7
  91. package/dist/server/operations/start-or-signal-workflow.js +2 -3
  92. package/dist/server/operations/start-workflow.js +2 -3
  93. package/dist/server/operations/static-registrations.d.ts +28 -0
  94. package/dist/server/operations/static-registrations.js +263 -0
  95. package/dist/server/operations/storage-capabilities.js +1 -3
  96. package/dist/server/operations/storage.js +7 -13
  97. package/dist/server/operations/submit-review-decision.js +3 -12
  98. package/dist/server/operations/suspend-workflow.js +1 -3
  99. package/dist/server/operations/timeout-workflow.js +1 -3
  100. package/dist/server/operations/update-schedule.js +1 -3
  101. package/dist/server/operations/update-workflow.js +2 -3
  102. package/dist/server/operations/worker-drain.js +0 -8
  103. package/dist/server/rest-binding.d.ts +3 -2
  104. package/dist/server/rest-bindings.d.ts +5 -0
  105. package/dist/server/rest-bindings.js +4 -312
  106. package/dist/server/route-model.d.ts +2 -0
  107. package/dist/server/route-model.js +1 -1
  108. package/dist/server/runtime/task-reconciliation.d.ts +10 -1
  109. package/dist/server/runtime/task-reconciliation.js +26 -2
  110. package/dist/server/serve-internals.js +12 -6
  111. package/dist/storage/indexeddb.js +28 -48
  112. package/dist/storage/testing.d.ts +6 -3
  113. package/dist/storage/testing.js +1 -1
  114. package/dist/version.d.ts +1 -1
  115. package/dist/version.js +1 -1
  116. package/dist/worker/protocol-schemas.d.ts +2 -2
  117. package/dist/worker/protocol-schemas.js +2 -2
  118. package/dist/worker/protocol.js +1 -1
  119. package/package.json +1 -1
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # Weft
2
2
 
3
- A Bun-native durable execution engine. Current release: `0.16.0`.
3
+ A Bun-native durable execution engine. Current release: `0.18.0`.
4
4
 
5
5
  Install the library from npm as `@lostgradient/weft`:
6
6
 
@@ -5,7 +5,7 @@
5
5
  *
6
6
  * @module alerting/alert-manager
7
7
  */
8
- import type { AlertState, AlertingOptions } from './types';
8
+ import type { AlertStateSnapshot, AlertingOptions } from './types';
9
9
  /**
10
10
  * Event-driven alert manager that evaluates metric-based rules against sliding
11
11
  * time windows and fires `alert:fired` / `alert:resolved` lifecycle events.
@@ -38,9 +38,9 @@ export declare class AlertManager implements Disposable {
38
38
  constructor(target: EventTarget, options: AlertingOptions, getNow?: () => number, startBackgroundTick?: boolean);
39
39
  /** Re-evaluate every rule once, for hosts that drive maintenance explicitly. */
40
40
  tick(): void;
41
- /** Get current state of all alert rules (for debugging/testing). */
42
- get states(): readonly AlertState[];
43
- /** Get the alert rules that are currently firing. */
44
- get activeStates(): readonly AlertState[];
41
+ /** Get a detached snapshot of all alert rules (for debugging/testing). */
42
+ get states(): readonly AlertStateSnapshot[];
43
+ /** Get detached snapshots of the alert rules that are currently firing. */
44
+ get activeStates(): readonly AlertStateSnapshot[];
45
45
  [Symbol.dispose](): void;
46
46
  }
@@ -7,6 +7,15 @@ import {
7
7
  import { parseDuration } from "../core/scheduler.js";
8
8
  import { CounterWindow, HistogramWindow } from "./sliding-window.js";
9
9
  const TICK_INTERVAL_MS = 1e4;
10
+ function snapshotAlertState(state) {
11
+ return {
12
+ rule: { ...state.rule },
13
+ status: state.status,
14
+ currentValue: state.currentValue,
15
+ ...state.lastFiredAt === void 0 ? {} : { lastFiredAt: state.lastFiredAt },
16
+ ...state.lastResolvedAt === void 0 ? {} : { lastResolvedAt: state.lastResolvedAt }
17
+ };
18
+ }
10
19
 
11
20
  export class AlertManager {
12
21
  #target;
@@ -20,21 +29,30 @@ export class AlertManager {
20
29
  #tickInterval;
21
30
  constructor(target, options, getNow = Date.now, startBackgroundTick = !0) {
22
31
  this.#target = target;
23
- this.#options = options;
32
+ this.#options = {
33
+ ...options,
34
+ rules: options.rules.map((rule) => ({ ...rule })),
35
+ ...options.webhooks === void 0 ? {} : {
36
+ webhooks: options.webhooks.map((webhook) => ({
37
+ ...webhook,
38
+ events: [...webhook.events]
39
+ }))
40
+ }
41
+ };
24
42
  this.#getNow = getNow;
25
43
  this.#latestStorageSize = 0;
26
44
  this.#pendingWebhooks = new Set;
27
45
  this.#listeners = [];
28
46
  this.#states = [];
29
- for (const rule of options.rules)
47
+ for (const rule of this.#options.rules)
30
48
  this.#states.push({
31
49
  rule,
32
50
  status: "idle",
33
51
  currentValue: 0
34
52
  });
35
53
  this.#windows = new Map;
36
- for (let i = 0;i < options.rules.length; i++) {
37
- const rule = options.rules[i], windowMs = rule.window ? parseDuration(rule.window) : 60000;
54
+ for (let i = 0;i < this.#options.rules.length; i++) {
55
+ const rule = this.#options.rules[i], windowMs = rule.window ? parseDuration(rule.window) : 60000;
38
56
  if (rule.metric === "workflow.failure_rate")
39
57
  this.#windows.set(i, new CounterWindow(windowMs));
40
58
  else if (rule.metric === "activity.p99_duration")
@@ -153,10 +171,10 @@ export class AlertManager {
153
171
  }
154
172
  }
155
173
  get states() {
156
- return this.#states;
174
+ return this.#states.map(snapshotAlertState);
157
175
  }
158
176
  get activeStates() {
159
- return this.#states.filter((state) => state.status === "firing");
177
+ return this.#states.filter((state) => state.status === "firing").map(snapshotAlertState);
160
178
  }
161
179
  [Symbol.dispose]() {
162
180
  if (this.#tickInterval !== null) {
@@ -1,2 +1,2 @@
1
1
  export { AlertManager } from './alert-manager';
2
- export type { AlertAction, AlertMetric, AlertRule, AlertState, AlertStatus, AlertingOptions, WebhookTarget, } from './types';
2
+ export type { AlertAction, AlertMetric, AlertRule, AlertStateSnapshot, AlertStatus, AlertingOptions, WebhookTarget, } from './types';
@@ -6,6 +6,8 @@
6
6
  * {@link WebhookTarget} URLs.
7
7
  */
8
8
  export type AlertAction = 'log' | 'webhook';
9
+ /** Runtime vocabulary shared by alerting types and operation schemas. */
10
+ export declare const ALERT_METRICS: readonly ["workflow.failure_rate", "activity.p99_duration", "storage.size"];
9
11
  /**
10
12
  * Which built-in metric an {@link AlertRule} monitors.
11
13
  *
@@ -30,7 +32,7 @@ export type AlertAction = 'log' | 'webhook';
30
32
  * void rule;
31
33
  * ```
32
34
  */
33
- export type AlertMetric = 'workflow.failure_rate' | 'activity.p99_duration' | 'storage.size';
35
+ export type AlertMetric = (typeof ALERT_METRICS)[number];
34
36
  /**
35
37
  * Defines a single alerting threshold applied to a named metric.
36
38
  *
@@ -124,7 +126,8 @@ export type AlertingOptions = {
124
126
  *
125
127
  * Transitions from `'idle'` to `'firing'` when the metric exceeds the
126
128
  * threshold and back to `'idle'` once the metric drops below it again.
127
- * Read this off an {@link AlertState} object to see the current state of a rule.
129
+ * Read this off an {@link AlertStateSnapshot} object to see the current state
130
+ * of a rule.
128
131
  *
129
132
  * @example
130
133
  * ```ts
@@ -141,17 +144,18 @@ export type AlertingOptions = {
141
144
  */
142
145
  export type AlertStatus = 'idle' | 'firing';
143
146
  /**
144
- * Runtime tracking state for a single {@link AlertRule} managed by
145
- * {@link AlertManager}.
147
+ * Detached, deeply read-only observation of a single alert rule's runtime
148
+ * state. The manager returns a fresh snapshot for every getter call, so
149
+ * changing it cannot affect alert evaluation.
146
150
  *
147
- * Users observe this shape via `AlertManager.states` to see the current
148
- * metric value, firing status, and timestamps of the last transition. It is
149
- * created and owned by the manager — callers do not construct it directly.
151
+ * Users observe this shape via `AlertManager.states` or
152
+ * `Engine.getActiveAlerts()` to see the current metric value, firing status,
153
+ * and timestamps of the last transition.
150
154
  */
151
- export type AlertState = {
152
- rule: AlertRule;
153
- status: AlertStatus;
154
- currentValue: number;
155
- lastFiredAt?: number;
156
- lastResolvedAt?: number;
155
+ export type AlertStateSnapshot = {
156
+ readonly rule: Readonly<AlertRule>;
157
+ readonly status: AlertStatus;
158
+ readonly currentValue: number;
159
+ readonly lastFiredAt?: number;
160
+ readonly lastResolvedAt?: number;
157
161
  };
@@ -0,0 +1,5 @@
1
+ export const ALERT_METRICS = [
2
+ "workflow.failure_rate",
3
+ "activity.p99_duration",
4
+ "storage.size"
5
+ ];
@@ -1403,6 +1403,79 @@
1403
1403
  },
1404
1404
  "outputSchema": {}
1405
1405
  },
1406
+ {
1407
+ "name": "weft.system.principal",
1408
+ "kind": "unary",
1409
+ "summary": "Report the caller's resolved principal and granted scopes",
1410
+ "description": "Report the caller's own resolved principal: the authentication method ('jwt', 'api-key', 'mtls', 'stdio-local', or 'unauthenticated'), the normalized subject when one exists, and the granted authorization scopes, sorted. Public access: an unauthenticated caller receives method 'unauthenticated' with an empty scope list rather than an error, so clients can distinguish \"no credential\" from \"credential with few scopes\" without probing other operations. Reflects only the request credential — never server auth configuration.",
1411
+ "tags": ["System"],
1412
+ "destructive": false,
1413
+ "access": {
1414
+ "kind": "public"
1415
+ },
1416
+ "transports": {
1417
+ "http": true,
1418
+ "jsonRpcHttp": true,
1419
+ "jsonRpcWebSocket": true,
1420
+ "jsonRpcStdio": true
1421
+ },
1422
+ "producibleFaults": [],
1423
+ "inputSchema": {
1424
+ "additionalProperties": false,
1425
+ "properties": {},
1426
+ "type": "object"
1427
+ },
1428
+ "outputSchema": {
1429
+ "additionalProperties": false,
1430
+ "properties": {
1431
+ "method": {
1432
+ "enum": ["jwt", "api-key", "mtls", "stdio-local", "unauthenticated"],
1433
+ "type": "string"
1434
+ },
1435
+ "scopes": {
1436
+ "items": {
1437
+ "enum": [
1438
+ "workflows:read",
1439
+ "workflows:write",
1440
+ "workflows:admin",
1441
+ "schedules:read",
1442
+ "schedules:write",
1443
+ "signals:write",
1444
+ "updates:write",
1445
+ "queries:read",
1446
+ "reviews:read",
1447
+ "reviews:write",
1448
+ "attributes:read",
1449
+ "attributes:write",
1450
+ "tags:write",
1451
+ "streams:read",
1452
+ "events:read",
1453
+ "storage:read",
1454
+ "storage:write",
1455
+ "storage:admin",
1456
+ "workers:write",
1457
+ "system:read",
1458
+ "system:admin"
1459
+ ],
1460
+ "type": "string"
1461
+ },
1462
+ "type": "array"
1463
+ },
1464
+ "subject": {
1465
+ "anyOf": [
1466
+ {
1467
+ "type": "string"
1468
+ },
1469
+ {
1470
+ "type": "null"
1471
+ }
1472
+ ]
1473
+ }
1474
+ },
1475
+ "required": ["method", "subject", "scopes"],
1476
+ "type": "object"
1477
+ }
1478
+ },
1406
1479
  {
1407
1480
  "name": "weft.system.registry",
1408
1481
  "kind": "unary",
@@ -1,7 +1,7 @@
1
1
  import { type CatalogWeftClient, type WeftClientConnection } from '../operation-client-runtime.ts';
2
- export declare const CATALOG_OPERATION_NAMES: readonly ["weft.activities.complete", "weft.activities.fail", "weft.alerts.list", "weft.recover.all", "weft.retention.get", "weft.reviews.decision.submit", "weft.reviews.get", "weft.reviews.list", "weft.schedules.cancel", "weft.schedules.create", "weft.schedules.get", "weft.schedules.list", "weft.schedules.pause", "weft.schedules.resume", "weft.schedules.update", "weft.storage.capabilities", "weft.system.lease", "weft.system.metrics", "weft.system.registry", "weft.task.queues.list", "weft.tasks.diagnostics", "weft.updates.result.get", "weft.worker.deployments.drain", "weft.worker.deployments.resume", "weft.workers.drain", "weft.workers.list", "weft.workers.resume", "weft.workflows.activities.pending.list", "weft.workflows.aggregate", "weft.workflows.attributes.get", "weft.workflows.attributes.set", "weft.workflows.bulk.cancel", "weft.workflows.bulk.delete", "weft.workflows.bulk.retryfailed", "weft.workflows.bulk.signal", "weft.workflows.bulk.tags", "weft.workflows.cancel", "weft.workflows.checkpoints.get", "weft.workflows.checkpoints.list", "weft.workflows.events.list", "weft.workflows.finalizer.get", "weft.workflows.fork", "weft.workflows.get", "weft.workflows.list", "weft.workflows.purge", "weft.workflows.query", "weft.workflows.replay", "weft.workflows.result.get", "weft.workflows.resume", "weft.workflows.scheduleprovenance.get", "weft.workflows.signal", "weft.workflows.start", "weft.workflows.startorsignal", "weft.workflows.streams.chunks", "weft.workflows.suspend", "weft.workflows.tags.add", "weft.workflows.tags.remove", "weft.workflows.timeline.get", "weft.workflows.timeout", "weft.workflows.update"];
2
+ export declare const CATALOG_OPERATION_NAMES: readonly ["weft.activities.complete", "weft.activities.fail", "weft.alerts.list", "weft.recover.all", "weft.retention.get", "weft.reviews.decision.submit", "weft.reviews.get", "weft.reviews.list", "weft.schedules.cancel", "weft.schedules.create", "weft.schedules.get", "weft.schedules.list", "weft.schedules.pause", "weft.schedules.resume", "weft.schedules.update", "weft.storage.capabilities", "weft.system.lease", "weft.system.metrics", "weft.system.principal", "weft.system.registry", "weft.task.queues.list", "weft.tasks.diagnostics", "weft.updates.result.get", "weft.worker.deployments.drain", "weft.worker.deployments.resume", "weft.workers.drain", "weft.workers.list", "weft.workers.resume", "weft.workflows.activities.pending.list", "weft.workflows.aggregate", "weft.workflows.attributes.get", "weft.workflows.attributes.set", "weft.workflows.bulk.cancel", "weft.workflows.bulk.delete", "weft.workflows.bulk.retryfailed", "weft.workflows.bulk.signal", "weft.workflows.bulk.tags", "weft.workflows.cancel", "weft.workflows.checkpoints.get", "weft.workflows.checkpoints.list", "weft.workflows.events.list", "weft.workflows.finalizer.get", "weft.workflows.fork", "weft.workflows.get", "weft.workflows.list", "weft.workflows.purge", "weft.workflows.query", "weft.workflows.replay", "weft.workflows.result.get", "weft.workflows.resume", "weft.workflows.scheduleprovenance.get", "weft.workflows.signal", "weft.workflows.start", "weft.workflows.startorsignal", "weft.workflows.streams.chunks", "weft.workflows.suspend", "weft.workflows.tags.add", "weft.workflows.tags.remove", "weft.workflows.timeline.get", "weft.workflows.timeout", "weft.workflows.update"];
3
3
  export type CatalogOperationName = (typeof CATALOG_OPERATION_NAMES)[number];
4
- export declare const CLIENT_OPERATION_NAMES: readonly ["weft.activities.complete", "weft.activities.fail", "weft.alerts.list", "weft.recover.all", "weft.retention.get", "weft.reviews.decision.submit", "weft.reviews.get", "weft.reviews.list", "weft.schedules.cancel", "weft.schedules.create", "weft.schedules.get", "weft.schedules.list", "weft.schedules.pause", "weft.schedules.resume", "weft.schedules.update", "weft.storage.capabilities", "weft.system.lease", "weft.system.metrics", "weft.system.registry", "weft.task.queues.list", "weft.tasks.diagnostics", "weft.tasks.diagnostics.deadletters.clear", "weft.updates.result.get", "weft.worker.deployments.drain", "weft.worker.deployments.resume", "weft.workers.drain", "weft.workers.list", "weft.workers.resume", "weft.workflows.activities.pending.list", "weft.workflows.aggregate", "weft.workflows.attributes.get", "weft.workflows.attributes.set", "weft.workflows.bulk.cancel", "weft.workflows.bulk.delete", "weft.workflows.bulk.retryfailed", "weft.workflows.bulk.signal", "weft.workflows.bulk.tags", "weft.workflows.cancel", "weft.workflows.checkpoints.get", "weft.workflows.checkpoints.list", "weft.workflows.events.list", "weft.workflows.finalizer.get", "weft.workflows.fork", "weft.workflows.get", "weft.workflows.list", "weft.workflows.purge", "weft.workflows.query", "weft.workflows.replay", "weft.workflows.result.get", "weft.workflows.resume", "weft.workflows.scheduleprovenance.get", "weft.workflows.signal", "weft.workflows.start", "weft.workflows.startorsignal", "weft.workflows.streams.chunks", "weft.workflows.suspend", "weft.workflows.tags.add", "weft.workflows.tags.remove", "weft.workflows.timeline.get", "weft.workflows.timeout", "weft.workflows.update"];
4
+ export declare const CLIENT_OPERATION_NAMES: readonly ["weft.activities.complete", "weft.activities.fail", "weft.alerts.list", "weft.recover.all", "weft.retention.get", "weft.reviews.decision.submit", "weft.reviews.get", "weft.reviews.list", "weft.schedules.cancel", "weft.schedules.create", "weft.schedules.get", "weft.schedules.list", "weft.schedules.pause", "weft.schedules.resume", "weft.schedules.update", "weft.storage.capabilities", "weft.system.lease", "weft.system.metrics", "weft.system.principal", "weft.system.registry", "weft.task.queues.list", "weft.tasks.diagnostics", "weft.tasks.diagnostics.deadletters.clear", "weft.updates.result.get", "weft.worker.deployments.drain", "weft.worker.deployments.resume", "weft.workers.drain", "weft.workers.list", "weft.workers.resume", "weft.workflows.activities.pending.list", "weft.workflows.aggregate", "weft.workflows.attributes.get", "weft.workflows.attributes.set", "weft.workflows.bulk.cancel", "weft.workflows.bulk.delete", "weft.workflows.bulk.retryfailed", "weft.workflows.bulk.signal", "weft.workflows.bulk.tags", "weft.workflows.cancel", "weft.workflows.checkpoints.get", "weft.workflows.checkpoints.list", "weft.workflows.events.list", "weft.workflows.finalizer.get", "weft.workflows.fork", "weft.workflows.get", "weft.workflows.list", "weft.workflows.purge", "weft.workflows.query", "weft.workflows.replay", "weft.workflows.result.get", "weft.workflows.resume", "weft.workflows.scheduleprovenance.get", "weft.workflows.signal", "weft.workflows.start", "weft.workflows.startorsignal", "weft.workflows.streams.chunks", "weft.workflows.suspend", "weft.workflows.tags.add", "weft.workflows.tags.remove", "weft.workflows.timeline.get", "weft.workflows.timeout", "weft.workflows.update"];
5
5
  export type ClientOperationName = (typeof CLIENT_OPERATION_NAMES)[number];
6
6
  export declare const CLIENT_REST_OPERATION_BINDINGS: {
7
7
  readonly 'weft.tasks.diagnostics.deadletters.clear': {
@@ -251,6 +251,15 @@ export type ClientOperationTypes = {
251
251
  readonly output: unknown;
252
252
  readonly faults: never;
253
253
  };
254
+ 'weft.system.principal': {
255
+ readonly input: {};
256
+ readonly output: {
257
+ readonly method: 'jwt' | 'api-key' | 'mtls' | 'stdio-local' | 'unauthenticated';
258
+ readonly scopes: ReadonlyArray<'workflows:read' | 'workflows:write' | 'workflows:admin' | 'schedules:read' | 'schedules:write' | 'signals:write' | 'updates:write' | 'queries:read' | 'reviews:read' | 'reviews:write' | 'attributes:read' | 'attributes:write' | 'tags:write' | 'streams:read' | 'events:read' | 'storage:read' | 'storage:write' | 'storage:admin' | 'workers:write' | 'system:read' | 'system:admin'>;
259
+ readonly subject: unknown;
260
+ };
261
+ readonly faults: never;
262
+ };
254
263
  'weft.system.registry': {
255
264
  readonly input: {};
256
265
  readonly output: {
@@ -21,6 +21,7 @@ export const CATALOG_OPERATION_NAMES = [
21
21
  "weft.storage.capabilities",
22
22
  "weft.system.lease",
23
23
  "weft.system.metrics",
24
+ "weft.system.principal",
24
25
  "weft.system.registry",
25
26
  "weft.task.queues.list",
26
27
  "weft.tasks.diagnostics",
@@ -82,6 +83,7 @@ export const CATALOG_OPERATION_NAMES = [
82
83
  "weft.storage.capabilities",
83
84
  "weft.system.lease",
84
85
  "weft.system.metrics",
86
+ "weft.system.principal",
85
87
  "weft.system.registry",
86
88
  "weft.task.queues.list",
87
89
  "weft.tasks.diagnostics",
@@ -2,6 +2,12 @@ import { disposeEngineCleanupInterval } from "./engine-runtime-helpers.js";
2
2
  import { EngineDisposedError } from "./errors.js";
3
3
  import { disposeQueuedInlineWorkflowStarts } from "./inline-launch-queue.js";
4
4
  import { rejectAllSleepTimerAcknowledgements } from "./sleep-timer-acknowledgements.js";
5
+ function settleSleepResolverReadyWaitersForTesting(internals) {
6
+ for (const waiters of internals.sleepResolverReadyWaitersForTesting?.values() ?? [])
7
+ for (const notifyReady of waiters)
8
+ notifyReady();
9
+ internals.sleepResolverReadyWaitersForTesting?.clear();
10
+ }
5
11
  export function disposeEngine(internals) {
6
12
  internals.disposed = !0;
7
13
  internals.alertManager?.[Symbol.dispose]();
@@ -48,6 +54,7 @@ export function disposeEngine(internals) {
48
54
  internals.pendingWebhooks.clear();
49
55
  internals.sleepResolvers.clear();
50
56
  internals.sleepResolversByWorkflow.clear();
57
+ settleSleepResolverReadyWaitersForTesting(internals);
51
58
  internals.sleepTimerAcknowledgementWaiters.clear();
52
59
  internals.durableInlineOperations.clear();
53
60
  internals.sleepTimersFiredWithoutResolver.clear();
@@ -19,7 +19,9 @@ export declare function createQueuedInlineWorkflowStartHandler<TWorkflows extend
19
19
  * `[Symbol.asyncDispose]` ahead of synchronous disposal (which aborts the signal
20
20
  * and would otherwise discard the queue).
21
21
  */
22
- export declare function drainQueuedInlineWorkflowStartsForEngine<TWorkflows extends object, TActivities extends object>(engine: Engine<TWorkflows, TActivities>): Promise<void>;
22
+ export declare function drainQueuedInlineWorkflowStartsForEngine<TWorkflows extends object, TActivities extends object>(engine: Engine<TWorkflows, TActivities>, options?: {
23
+ abortStartedWorkflows?: boolean;
24
+ }): Promise<void>;
23
25
  export declare function createCleanupIntervalTick<TWorkflows extends object, TActivities extends object>(weakEngine: WeakRef<Engine<TWorkflows, TActivities>>, tracker: EngineCleanupIntervalDisposalTracker): () => void;
24
26
  /**
25
27
  * Build the resolver the second-instance detection interval uses to find its live
@@ -40,8 +40,8 @@ export function createQueuedInlineWorkflowStartHandler(weakEngine, channel) {
40
40
  swallowPromiseRejection(flushQueuedInlineWorkflowStarts(getInternals(engine), inlineLaunchQueueCallbacksForEngine(engine)));
41
41
  };
42
42
  }
43
- export async function drainQueuedInlineWorkflowStartsForEngine(engine) {
44
- await drainQueuedInlineWorkflowStarts(getInternals(engine), inlineLaunchQueueCallbacksForEngine(engine));
43
+ export async function drainQueuedInlineWorkflowStartsForEngine(engine, options) {
44
+ await drainQueuedInlineWorkflowStarts(getInternals(engine), inlineLaunchQueueCallbacksForEngine(engine), options);
45
45
  }
46
46
  export function createCleanupIntervalTick(weakEngine, tracker) {
47
47
  return function cleanupExpiredResponsesForLiveEngine() {
@@ -163,6 +163,26 @@ export declare class EngineCreateNameMismatchError extends WeftError<'EngineCrea
163
163
  export declare class EngineDisposedError extends WeftError<'EngineDisposedError'> {
164
164
  constructor();
165
165
  }
166
+ /**
167
+ * Thrown when queued inline workflow draining fails during asynchronous engine
168
+ * disposal. The engine is still fully torn down, and `leaseReleased` reports
169
+ * whether the final fenced lease delete committed. The original drain failure
170
+ * is available as `cause`.
171
+ *
172
+ * @example
173
+ * ```ts
174
+ * import { EngineDisposalError } from '@lostgradient/weft';
175
+ *
176
+ * function releaseSucceeded(error: unknown): boolean {
177
+ * return error instanceof EngineDisposalError && error.leaseReleased;
178
+ * }
179
+ * void releaseSucceeded;
180
+ * ```
181
+ */
182
+ export declare class EngineDisposalError extends WeftError<'EngineDisposalError'> {
183
+ readonly leaseReleased: boolean;
184
+ constructor(cause: unknown, leaseReleased: boolean);
185
+ }
166
186
  /**
167
187
  * Thrown by engine APIs that need a workflow to be present in storage but
168
188
  * cannot find one with the given ID. Inspect `workflowId` to identify the
@@ -70,6 +70,14 @@ export class EngineDisposedError extends WeftError {
70
70
  }
71
71
  }
72
72
 
73
+ export class EngineDisposalError extends WeftError {
74
+ leaseReleased;
75
+ constructor(cause, leaseReleased) {
76
+ super("EngineDisposalError", "Engine disposal failed while draining queued work", { cause });
77
+ this.leaseReleased = leaseReleased;
78
+ }
79
+ }
80
+
73
81
  export class WorkflowNotFoundError extends WeftError {
74
82
  workflowId;
75
83
  constructor(workflowId) {
@@ -1,4 +1,4 @@
1
- import type { AlertState } from '../../alerting/types.ts';
1
+ import type { AlertStateSnapshot } from '../../alerting/types.ts';
2
2
  import { type Storage as WeftStorage } from '../../storage/interface.ts';
3
3
  import { type ActivityMetadata, type ActivityRegistrationOptions, type RegisteredActivityFunction } from '../activity-registry.ts';
4
4
  import type { StoredStreamChunk } from '../context.ts';
@@ -25,7 +25,7 @@ export { ActivityReconciliationCapabilityError, ActivityReconciliationConflictEr
25
25
  export { AsyncActivityTokenNotFoundError } from './async-activity-completion.ts';
26
26
  export type { PendingAsyncActivity } from './async-activity-records.ts';
27
27
  export type { PendingTimelineEntry, RegistrationEntry, ResolvedOptions, TrackedWaiterKeys, WorkflowResultWaiter, } from './engine-internal-types.ts';
28
- export { ActivityResolutionError, BulkDeleteRequiresTerminalWorkflowsError, BulkOperationConfirmationError, EngineCreateNameMismatchError, EngineDisposedError, IdempotencyKeyPurgedError, PersistedDataIncompatibleError, StartOrSignalConflictError, WorkflowAlreadyExistsError, WorkflowConcurrencyLimitExceededError, WorkflowNotFoundError, WorkflowNotRegisteredError, WorkflowSuspendNotSupportedError, WorkflowTeardownPendingError, WorkflowTypeNotRegisteredForRecoveryError, } from './errors.ts';
28
+ export { ActivityResolutionError, BulkDeleteRequiresTerminalWorkflowsError, BulkOperationConfirmationError, EngineCreateNameMismatchError, EngineDisposalError, EngineDisposedError, IdempotencyKeyPurgedError, PersistedDataIncompatibleError, StartOrSignalConflictError, WorkflowAlreadyExistsError, WorkflowConcurrencyLimitExceededError, WorkflowNotFoundError, WorkflowNotRegisteredError, WorkflowSuspendNotSupportedError, WorkflowTeardownPendingError, WorkflowTypeNotRegisteredForRecoveryError, } from './errors.ts';
29
29
  export { HANDLE_RESULT_PROMISE, WorkflowHandle } from './handles.ts';
30
30
  export { EngineLeaseAcquisitionTimeoutError, EngineLeaseCorruptedError, EngineLeaseNotHeldError, } from './lease-errors.ts';
31
31
  export type { EngineLeaseHealth, LeaseLostReason } from './lease-health.ts';
@@ -39,6 +39,30 @@ export { assertCompatiblePersistedDataVersion };
39
39
  export declare const ENGINE_PARKED_WORKFLOW_COUNT_FOR_TESTING: unique symbol;
40
40
  export declare const ENGINE_SIGNAL_WAITER_COUNT_FOR_TESTING: unique symbol;
41
41
  export declare const ENGINE_SLEEP_RESOLVER_COUNT_FOR_TESTING: unique symbol;
42
+ export declare const ENGINE_WAIT_FOR_SLEEP_RESOLVER_FOR_TESTING: unique symbol;
43
+ export declare const ENGINE_SET_WORKER_TURN_TIMEOUT_RESOLVER_FOR_TESTING: unique symbol;
44
+ /**
45
+ * Bound for `ENGINE_WAIT_FOR_SLEEP_RESOLVER_FOR_TESTING`.
46
+ *
47
+ * The only production-adjacent consumer awaits that hook inside the
48
+ * `weft:test:periodic-sync` Service Worker message handler in
49
+ * service-worker-browser.test.ts, and that file bounds each message round trip
50
+ * at 5s (`sendWorkerMessage`), each phase at 15s or whatever remains of the
51
+ * test budget, and each test at 30s. This bound has to be strictly tighter than
52
+ * the innermost of those — at 5s it would tie with the message bound and the
53
+ * generic "Service Worker message timed out" could win the race, hiding the
54
+ * diagnostic this bound exists to produce. 3s expires first, and the handler
55
+ * posts the rejection back over the port so the workflow-naming error is what
56
+ * reaches CI.
57
+ *
58
+ * The ordering holds whenever the phase bound is the 15s ceiling. It cannot
59
+ * hold once a test has burned all but a few seconds of its 30s budget, because
60
+ * no inner window survives an outer bound shorter than itself. That case is
61
+ * reported rather than papered over: the phase error says the bound was
62
+ * shortened by the remaining budget and that a nested timeout may have been
63
+ * preempted, which points at the earlier phases that actually consumed it.
64
+ */
65
+ export declare const SLEEP_RESOLVER_READY_WAIT_TIMEOUT_MS_FOR_TESTING = 3000;
42
66
  /**
43
67
  * The `name` of the `process` warning emitted when a lease-owning engine is
44
68
  * disposed through the synchronous `[Symbol.dispose]()` path. Sync disposal can
@@ -146,8 +170,8 @@ export declare class Engine<TWorkflows extends object = DefaultWorkflowRegistry,
146
170
  removeEventListener<K extends Extract<keyof WeftEventMap, string>>(type: K, listener: (event: WeftEventMap[K]) => void, options?: boolean | EventListenerOptions): void;
147
171
  removeEventListener(type: string, listener: EventListenerOrEventListenerObject | null, options?: boolean | EventListenerOptions): void;
148
172
  get state(): EngineStateNamespace;
149
- /** Return the alert rules that are currently firing. */
150
- getActiveAlerts(): readonly AlertState[];
173
+ /** Return detached snapshots of the alert rules that are currently firing. */
174
+ getActiveAlerts(): readonly AlertStateSnapshot[];
151
175
  /**
152
176
  * Register a workflow by name or definition, or register an activity
153
177
  * definition. Definition overloads return this same engine with the
@@ -314,6 +338,11 @@ export declare class Engine<TWorkflows extends object = DefaultWorkflowRegistry,
314
338
  [ENGINE_PARKED_WORKFLOW_COUNT_FOR_TESTING](): number;
315
339
  [ENGINE_SIGNAL_WAITER_COUNT_FOR_TESTING](): number;
316
340
  [ENGINE_SLEEP_RESOLVER_COUNT_FOR_TESTING](): number;
341
+ [ENGINE_WAIT_FOR_SLEEP_RESOLVER_FOR_TESTING](workflowId: string): Promise<void>;
342
+ [ENGINE_SET_WORKER_TURN_TIMEOUT_RESOLVER_FOR_TESTING](resolver: (turn: {
343
+ workflowId: string;
344
+ kind: 'run' | 'resume';
345
+ }) => number): void;
317
346
  signal(workflowId: string, name: SignalDefinition): Promise<void>;
318
347
  signal<TInput>(workflowId: string, name: SignalDefinition<TInput>, payload: TInput, options?: SignalDeliveryOptions): Promise<void>;
319
348
  signal(workflowId: string, name: string, payload?: unknown, options?: SignalDeliveryOptions): Promise<void>;
@@ -480,11 +509,13 @@ export declare class Engine<TWorkflows extends object = DefaultWorkflowRegistry,
480
509
  *
481
510
  * Under `ownership: 'lease'`, this is the explicit prompt-handoff primitive:
482
511
  * it drains queued inline starts, tears down in-memory write paths, and awaits
483
- * lease release before resolving. Synchronous disposal remains immediate and
484
- * can make the next engine wait for `leaseTtl` if the process exits before its
485
- * background release completes.
512
+ * lease release before resolving. The returned boolean is `true` when no lease
513
+ * needed release or the holder delete committed, and `false` when the delete
514
+ * did not commit. Synchronous disposal remains immediate and can make the next
515
+ * engine wait for `leaseTtl` if the process exits before its background release
516
+ * completes.
486
517
  */
487
- shutdown(): Promise<void>;
518
+ shutdown(): Promise<boolean>;
488
519
  /**
489
520
  * Synchronous teardown (`using engine = ...`). Pending inline launches that
490
521
  * have not yet run are **discarded**, not executed. When you need queued
@@ -493,15 +524,6 @@ export declare class Engine<TWorkflows extends object = DefaultWorkflowRegistry,
493
524
  * via `await using`.
494
525
  */
495
526
  [Symbol.dispose](): void;
496
- /**
497
- * Async teardown (`await using engine = ...`). Drains pending inline launches
498
- * so each queued workflow completes its first turn before disposal, leaving no
499
- * deferred-launch macrotask to fire against torn-down state. The drain is
500
- * bounded (a pass cap and the abort signal); in the pathological case where it
501
- * cannot converge, anything still queued is discarded by the synchronous
502
- * teardown that always follows. Prefer this over the synchronous
503
- * {@link Engine[Symbol.dispose]} in async contexts and tests.
504
- */
505
527
  [Symbol.asyncDispose](): Promise<void>;
506
528
  get storage(): WeftStorage;
507
529
  get scheduler(): Scheduler;