@nanobpm/urban 0.82.1 → 0.84.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.
@@ -227,6 +227,142 @@ export interface UserTaskFilter {
227
227
  assignee?: string;
228
228
  candidateGroup?: string;
229
229
  }
230
+ /**
231
+ * An element instance's lifecycle state, as the engine reports it on a
232
+ * `/v2/element-instances/search` result. Mirrors the engine's `ElementInstanceStateEnum`:
233
+ * `ACTIVE` (a token is currently *at* this element), `COMPLETED` (the token has left it), or
234
+ * `TERMINATED` (the element was interrupted). Structurally the same state set as
235
+ * {@link ProcessInstanceState} (one active state plus the `COMPLETED`/`TERMINATED` terminals),
236
+ * but a distinct concept — element instances are the tokens *within* a process instance — so it
237
+ * is kept as its own type rather than aliased.
238
+ */
239
+ export type ElementInstanceState = "ACTIVE" | "COMPLETED" | "TERMINATED";
240
+ /**
241
+ * A single element instance ("token") as {@link EngineClient.searchElementInstances} and
242
+ * {@link EngineClient.getElementInstance} report it — the finest-grained "how far has this
243
+ * process instance progressed" signal, below the process-instance lifecycle
244
+ * ({@link ProcessInstanceSnapshot}) and independent of whether the element is a user task
245
+ * ({@link UserTaskSummary}). It surfaces active *non-user-task* elements (a service task, a
246
+ * gateway, a catch event) a user-task search cannot see — "the furthest element reached".
247
+ * Carries the element instance's own key, its identity (`elementId`, its BPMN `elementType`
248
+ * when the engine reports it), the owning process instance, and its lifecycle `state`.
249
+ */
250
+ export interface ElementInstanceSummary {
251
+ readonly elementInstanceKey: string;
252
+ readonly processInstanceKey: string;
253
+ readonly elementId: string;
254
+ /** The BPMN element type (e.g. `"SERVICE_TASK"`, `"USER_TASK"`,
255
+ * `"INTERMEDIATE_CATCH_EVENT"`), when the engine reports it. Kept transport-agnostic (a
256
+ * bare string) so a new BPMN element type on the engine flows through without having to be
257
+ * enumerated here. Absent when the adapter's read model does not carry it. */
258
+ readonly elementType?: string;
259
+ readonly state: ElementInstanceState;
260
+ }
261
+ /**
262
+ * The kind of wait an element instance is parked in, as a
263
+ * `/v2/element-instances/wait-states/search` result reports it. Unlike a user-task search,
264
+ * this surfaces *every* park — a `JOB` (a service task awaiting a worker), a `MESSAGE`
265
+ * (an event awaiting correlation), a `TIMER`, a `SIGNAL`, a `CONDITION`, as well as a
266
+ * `USER_TASK` — so a consumer can read "what is this instance blocked on" beyond user tasks.
267
+ */
268
+ export type WaitStateType = "JOB" | "MESSAGE" | "USER_TASK" | "TIMER" | "SIGNAL" | "CONDITION";
269
+ /**
270
+ * A single parked (waiting) element instance as
271
+ * {@link EngineClient.searchElementInstanceWaitStates} reports it. Every variant carries the
272
+ * element instance's identity; the `waitStateType` discriminates the park-specific fields — a
273
+ * `JOB` carries the `jobType`/`jobKey` it is parked on, a `MESSAGE` the awaited
274
+ * `messageName`/`correlationKey`, a `USER_TASK` the `userTaskKey`, a `SIGNAL` the
275
+ * `signalName` — so a caller narrows on `waitStateType` to reach them type-safely rather than
276
+ * probing a flat optional-field bag.
277
+ */
278
+ export type ElementInstanceWaitState = {
279
+ readonly elementInstanceKey: string;
280
+ readonly processInstanceKey: string;
281
+ readonly elementId: string;
282
+ readonly elementType?: string;
283
+ } & ({
284
+ readonly waitStateType: "JOB";
285
+ readonly jobType: string;
286
+ readonly jobKey?: string;
287
+ } | {
288
+ readonly waitStateType: "MESSAGE";
289
+ readonly messageName: string;
290
+ readonly correlationKey?: string;
291
+ } | {
292
+ readonly waitStateType: "USER_TASK";
293
+ readonly userTaskKey: string;
294
+ } | {
295
+ readonly waitStateType: "TIMER";
296
+ } | {
297
+ readonly waitStateType: "SIGNAL";
298
+ readonly signalName: string;
299
+ } | {
300
+ readonly waitStateType: "CONDITION";
301
+ });
302
+ /**
303
+ * Selectors for an element-instance search: which process instance, element, and/or lifecycle
304
+ * state to match. Used by {@link EngineClient.searchElementInstances}.
305
+ */
306
+ export interface ElementInstanceFilter {
307
+ processInstanceKey?: string;
308
+ elementId?: string;
309
+ state?: ElementInstanceState;
310
+ }
311
+ /**
312
+ * Selectors for an element-instance *wait-state* search: which process instance, element,
313
+ * and/or kind of wait to match. Used by {@link EngineClient.searchElementInstanceWaitStates}.
314
+ * There is deliberately no lifecycle-`state` selector — a wait state is always an active park.
315
+ */
316
+ export interface ElementInstanceWaitStateFilter {
317
+ processInstanceKey?: string;
318
+ elementId?: string;
319
+ waitStateType?: WaitStateType;
320
+ }
321
+ /**
322
+ * The engine's own incident-state enum — the lifecycle states an engine actually reports and
323
+ * that are valid as a search selector. An `ACTIVE` incident is an open fault a human/agent can
324
+ * act on (resolve/retry); the other values are terminal or transitional. This is the single
325
+ * source of truth for real engine states; {@link IncidentState} derives from it.
326
+ */
327
+ export type EngineIncidentState = "ACTIVE" | "MIGRATED" | "PENDING" | "RESOLVED";
328
+ /**
329
+ * The lifecycle state of an incident, as {@link EngineClient.searchIncidents} reports it.
330
+ * Extends {@link EngineIncidentState} with the client-side `"UNKNOWN"` sentinel — a fallback
331
+ * used when the engine returns an unrecognized/absent value, so an incident is surfaced rather
332
+ * than dropped for an odd state. Because `"UNKNOWN"` is not a real engine state, it is not a
333
+ * valid {@link IncidentFilter} selector. A caller narrows on this union rather than probing a
334
+ * raw string.
335
+ */
336
+ export type IncidentState = EngineIncidentState | "UNKNOWN";
337
+ /**
338
+ * Selectors for an incident search: which process instance and/or lifecycle state to match.
339
+ * Used by {@link EngineClient.searchIncidents}. An eventually consistent (zero-wait) read; an
340
+ * unset selector matches every incident.
341
+ */
342
+ export interface IncidentFilter {
343
+ processInstanceKey?: string;
344
+ state?: EngineIncidentState;
345
+ }
346
+ /**
347
+ * A single incident (a stuck token — a job out of retries, an unhandled error, a failed
348
+ * gateway evaluation) as {@link EngineClient.searchIncidents} reports it. Carries the
349
+ * `incidentKey` a caller passes to {@link EngineClient.resolveIncident}, the owning
350
+ * `processInstanceKey`, and — when the incident is job-backed — the `jobKey` a caller passes
351
+ * to {@link EngineClient.updateJobRetries} to make the job retriable before resolving.
352
+ * `errorType`/`errorMessage` are the engine's fault description; they are free-form across
353
+ * engines (the live SDK reports a Camunda error-type enum, the in-process engine a coarser
354
+ * `kind`), so treat them as diagnostic text, not a stable taxonomy.
355
+ */
356
+ export interface IncidentSummary {
357
+ readonly incidentKey: string;
358
+ readonly processInstanceKey: string;
359
+ readonly elementId?: string;
360
+ readonly elementInstanceKey?: string;
361
+ readonly jobKey?: string;
362
+ readonly errorType?: string;
363
+ readonly errorMessage?: string;
364
+ readonly state: IncidentState;
365
+ }
230
366
  /**
231
367
  * A deployed form's form-js schema plus its identifying metadata, as
232
368
  * {@link EngineClient.getForm} returns it. `schema` is the parsed form-js document
@@ -327,6 +463,76 @@ export interface EngineClient {
327
463
  processInstanceKeys?: string[];
328
464
  state?: ProcessInstanceState;
329
465
  }): Promise<ProcessInstanceSnapshot[]>;
466
+ /**
467
+ * Search element instances ("tokens") by process instance, element, and/or lifecycle state
468
+ * (`POST /v2/element-instances/search`). Where {@link searchProcessInstances} answers "is
469
+ * this instance still running" and {@link searchUserTasks} answers "what user tasks are
470
+ * open", this answers "what element has a token reached" — including the active
471
+ * *non-user-task* elements (a service task, a gateway, a catch event) that a user-task
472
+ * search cannot see, i.e. "the furthest element reached". An eventually consistent
473
+ * (zero-wait) read; each {@link ElementInstanceSummary} carries the element instance's key,
474
+ * its `elementId`/`elementType`, the owning process instance, and its `state`.
475
+ */
476
+ searchElementInstances(filter?: ElementInstanceFilter): Promise<ElementInstanceSummary[]>;
477
+ /**
478
+ * Search the *wait states* of element instances
479
+ * (`POST /v2/element-instances/wait-states/search`) — every park, not only user tasks. A
480
+ * `JOB` park (a service task awaiting a worker), a `MESSAGE` park (an event awaiting
481
+ * correlation), a `TIMER`/`SIGNAL`/`CONDITION`, plus `USER_TASK`. A zero-wait read; each
482
+ * result is discriminated by `waitStateType` (see {@link ElementInstanceWaitState}), so a
483
+ * consumer can read the job/message parks a {@link searchUserTasks} cannot surface.
484
+ */
485
+ searchElementInstanceWaitStates(filter?: ElementInstanceWaitStateFilter): Promise<ElementInstanceWaitState[]>;
486
+ /**
487
+ * Fetch a single element instance by its key (`GET /v2/element-instances/{elementInstanceKey}`),
488
+ * or `null` when it cannot be resolved — the key is blank, no such element instance exists
489
+ * (a 404), or the fetch otherwise fails. A read is treated as absence rather than propagating
490
+ * (mirroring {@link getForm}), so a caller distinguishes "have it" from "don't" without a
491
+ * try/catch. A zero-wait read returning the same {@link ElementInstanceSummary} shape as
492
+ * {@link searchElementInstances}.
493
+ */
494
+ getElementInstance(elementInstanceKey: string): Promise<ElementInstanceSummary | null>;
495
+ /**
496
+ * Search incidents by owning process instance and/or lifecycle state
497
+ * (`POST /v2/incidents/search`) — the open faults blocking one or more instances (a job out
498
+ * of retries, an unhandled error, a failed gateway evaluation). An eventually consistent
499
+ * (zero-wait) read; each {@link IncidentSummary} carries the `incidentKey` to pass to
500
+ * {@link resolveIncident} and, for a job-backed incident, the `jobKey` to pass to
501
+ * {@link updateJobRetries}. The debugging counterpart to the read accessors above: where
502
+ * they answer "how far has this instance progressed", this answers "why is it stuck".
503
+ */
504
+ searchIncidents(filter?: IncidentFilter): Promise<IncidentSummary[]>;
505
+ /**
506
+ * Resolve an open incident by key (`POST /v2/incidents/{incidentKey}/resolution`), unblocking
507
+ * the parked token: a job incident returns the job to the activatable pool (so it must have
508
+ * retries left first — see {@link updateJobRetries}), a gateway incident re-evaluates, an
509
+ * uncaught-error incident re-creates the service-task job. A mutating operation.
510
+ */
511
+ resolveIncident(input: {
512
+ incidentKey: string;
513
+ }): Promise<void>;
514
+ /**
515
+ * Update the remaining retries of a job (`PATCH /v2/jobs/{jobKey}`) — the "retry a failed
516
+ * job" operation. Setting a failed job's retries back above zero makes it activatable again;
517
+ * paired with {@link resolveIncident}, this is how a stuck `jobNoRetries` incident is cleared
518
+ * (bump retries, then resolve). A mutating operation.
519
+ */
520
+ updateJobRetries(input: {
521
+ jobKey: string;
522
+ retries: number;
523
+ }): Promise<void>;
524
+ /**
525
+ * Set (merge) variables into a scope (`PUT /v2/element-instances/{scopeKey}/variables`).
526
+ * `scopeKey` is a process-instance key or an element-instance key; when `local` is `true` the
527
+ * variables are merged strictly into that local scope, otherwise (the default) they propagate
528
+ * to the outermost scope. A mutating operation used to repair state before resolving an
529
+ * incident or to steer an instance during debugging.
530
+ */
531
+ setVariables(input: {
532
+ scopeKey: string;
533
+ variables: Record<string, unknown>;
534
+ local?: boolean;
535
+ }): Promise<void>;
330
536
  /** Register a push worker for a job type. Draining is handled by the adapter. */
331
537
  registerWorker(jobType: string, handler: JobHandler, options?: {
332
538
  workerName?: string;
@@ -350,4 +556,4 @@ export interface EngineClient {
350
556
  * and `getForm` before it) that a purely structural `implements EngineClient` check no
351
557
  * longer catches once the fake is published/compiled against an older `@nanobpm/urban`.
352
558
  */
353
- export declare const ENGINE_CLIENT_METHODS: readonly ["deployResources", "createInstance", "cancelInstance", "publishMessage", "searchUserTasks", "openUserTasks", "getForm", "completeUserTask", "searchProcessInstances", "registerWorker", "close"];
559
+ export declare const ENGINE_CLIENT_METHODS: readonly ["deployResources", "createInstance", "cancelInstance", "publishMessage", "searchUserTasks", "openUserTasks", "getForm", "completeUserTask", "searchProcessInstances", "searchElementInstances", "searchElementInstanceWaitStates", "getElementInstance", "searchIncidents", "resolveIncident", "updateJobRetries", "setVariables", "registerWorker", "close"];
@@ -66,6 +66,13 @@ export const ENGINE_CLIENT_METHODS = [
66
66
  "getForm",
67
67
  "completeUserTask",
68
68
  "searchProcessInstances",
69
+ "searchElementInstances",
70
+ "searchElementInstanceWaitStates",
71
+ "getElementInstance",
72
+ "searchIncidents",
73
+ "resolveIncident",
74
+ "updateJobRetries",
75
+ "setVariables",
69
76
  "registerWorker",
70
77
  "close",
71
78
  ];
@@ -1,4 +1,4 @@
1
- import type { EngineClient, FormSchema, JobHandler, ProcessInstanceSnapshot, ProcessInstanceState, UserTaskState, UserTaskSummary, UserTaskFilter, WorkerSubscription } from "../core/host.ts";
1
+ import type { EngineClient, ElementInstanceState, ElementInstanceSummary, ElementInstanceFilter, ElementInstanceWaitState, ElementInstanceWaitStateFilter, WaitStateType, FormSchema, IncidentFilter, IncidentState, IncidentSummary, JobHandler, ProcessInstanceSnapshot, ProcessInstanceState, UserTaskState, UserTaskSummary, UserTaskFilter, WorkerSubscription } from "../core/host.ts";
2
2
  import type { EngineSdkClient } from "./sdk.ts";
3
3
  /** Coerce an engine response's process-instance key to a non-empty string, or
4
4
  * throw — a missing key means a malformed/partial response, not a real instance. */
@@ -8,6 +8,38 @@ export declare function requireProcessInstanceKey(key: string | number | null |
8
8
  * (which the caller skips rather than mis-reconciling). Case-insensitive so a
9
9
  * future casing tweak on the engine side doesn't silently drop instances. */
10
10
  export declare function normalizeProcessInstanceState(raw: unknown): ProcessInstanceState | undefined;
11
+ /** Map the engine's element-instance `state` onto the transport-agnostic
12
+ * {@link ElementInstanceState} union, or `undefined` for an unrecognized value (which the
13
+ * caller skips rather than surfacing a malformed row). Case-insensitive so a future casing
14
+ * tweak on the engine side doesn't silently drop element instances. Kept separate from
15
+ * {@link normalizeProcessInstanceState} — the two model distinct engine enums that only
16
+ * coincide today — so element and process state can diverge without a hidden coupling. */
17
+ export declare function normalizeElementInstanceState(raw: unknown): ElementInstanceState | undefined;
18
+ /** Map the engine's wait-state `waitStateType` onto the transport-agnostic
19
+ * {@link WaitStateType} union, or `undefined` for an unrecognized value. Case-insensitive
20
+ * so a casing tweak doesn't silently drop parks. */
21
+ export declare function normalizeWaitStateType(raw: unknown): WaitStateType | undefined;
22
+ /** Map the engine's incident `state` onto the transport-agnostic {@link IncidentState} union,
23
+ * falling back to `"UNKNOWN"` for an unrecognized/absent value (an incident is never dropped
24
+ * for an odd state — unlike element/process rows, whose state is a hard identity field — so a
25
+ * caller still sees the fault). Case-insensitive so a casing tweak doesn't mis-map. */
26
+ export declare function normalizeIncidentState(raw: unknown): IncidentState;
27
+ /** Map one engine element-instance row onto an {@link ElementInstanceSummary}, or `undefined`
28
+ * when the row is malformed (missing key/elementId/process instance, or an unrecognized
29
+ * state). The single source of truth both `searchElementInstances` and `getElementInstance`
30
+ * extract through, so the two cannot drift. */
31
+ export declare function mapElementInstanceRow(row: Record<string, unknown>, log: Log): ElementInstanceSummary | undefined;
32
+ /** Map one engine wait-state row onto an {@link ElementInstanceWaitState}, or `undefined`
33
+ * when the row is malformed (missing identity, or an unrecognized `waitStateType`). The
34
+ * Camunda SDK nests the park-specific fields under `details`; a plain REST body may inline
35
+ * them — read `details` first, then fall back to the row itself, so both wire shapes map. */
36
+ export declare function mapElementInstanceWaitStateRow(row: Record<string, unknown>, log: Log): ElementInstanceWaitState | undefined;
37
+ /** Map one engine incident row onto an {@link IncidentSummary}, or `undefined` when the row is
38
+ * malformed (missing the `incidentKey` or the owning `processInstanceKey` — the two identity
39
+ * fields a caller needs to resolve/act on it). `jobKey`/`elementInstanceKey`/`errorType`/
40
+ * `errorMessage` are best-effort diagnostics: present when the engine reports them, omitted
41
+ * otherwise. The single source of truth `searchIncidents` extracts through. */
42
+ export declare function mapIncidentRow(row: Record<string, unknown>, log: Log): IncidentSummary | undefined;
11
43
  /** A job as delivered to a nano-sdk job handler: the frame fields plus the
12
44
  * acknowledgement actions the handler must call. */
13
45
  export interface NanoSdkActivatedJob {
@@ -88,6 +120,33 @@ export interface NanoSdkClient {
88
120
  filter?: Record<string, unknown>;
89
121
  page?: Record<string, unknown>;
90
122
  }, consistency?: unknown, options?: unknown): Promise<Record<string, unknown>>;
123
+ searchElementInstances(input: {
124
+ filter?: Record<string, unknown>;
125
+ page?: Record<string, unknown>;
126
+ }, consistency?: unknown, options?: unknown): Promise<Record<string, unknown>>;
127
+ searchElementInstanceWaitStates(input: {
128
+ filter?: Record<string, unknown>;
129
+ page?: Record<string, unknown>;
130
+ }, consistency?: unknown, options?: unknown): Promise<Record<string, unknown>>;
131
+ getElementInstance(input: {
132
+ elementInstanceKey: string;
133
+ }, consistency?: unknown, options?: unknown): Promise<Record<string, unknown>>;
134
+ searchIncidents(input: {
135
+ filter?: Record<string, unknown>;
136
+ page?: Record<string, unknown>;
137
+ }, consistency?: unknown, options?: unknown): Promise<Record<string, unknown>>;
138
+ resolveIncident(input: {
139
+ incidentKey: string;
140
+ }, options?: unknown): Promise<unknown>;
141
+ updateJob(input: {
142
+ jobKey: string;
143
+ changeset: Record<string, unknown>;
144
+ }, options?: unknown): Promise<unknown>;
145
+ createElementInstanceVariables(input: {
146
+ elementInstanceKey: string;
147
+ variables: Record<string, unknown>;
148
+ local?: boolean;
149
+ }, options?: unknown): Promise<unknown>;
91
150
  createJobWorker(cfg: NanoSdkJobWorkerConfig): NanoSdkJobWorker;
92
151
  /** Stop every worker created on this client. Used on teardown to also drain a
93
152
  * REST-fallback worker, whose handle the `createJobWorker` proxy starts internally
@@ -152,6 +211,22 @@ export declare class SdkEngineClient implements EngineClient {
152
211
  processInstanceKeys?: string[];
153
212
  state?: ProcessInstanceState;
154
213
  }): Promise<ProcessInstanceSnapshot[]>;
214
+ searchElementInstances(filter?: ElementInstanceFilter): Promise<ElementInstanceSummary[]>;
215
+ searchElementInstanceWaitStates(filter?: ElementInstanceWaitStateFilter): Promise<ElementInstanceWaitState[]>;
216
+ getElementInstance(elementInstanceKey: string): Promise<ElementInstanceSummary | null>;
217
+ searchIncidents(filter?: IncidentFilter): Promise<IncidentSummary[]>;
218
+ resolveIncident(input: {
219
+ incidentKey: string;
220
+ }): Promise<void>;
221
+ updateJobRetries(input: {
222
+ jobKey: string;
223
+ retries: number;
224
+ }): Promise<void>;
225
+ setVariables(input: {
226
+ scopeKey: string;
227
+ variables: Record<string, unknown>;
228
+ local?: boolean;
229
+ }): Promise<void>;
155
230
  registerWorker(jobType: string, handler: JobHandler, options?: {
156
231
  workerName?: string;
157
232
  maxParallelJobs?: number;