@nanobpm/urban 0.82.0 → 0.83.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,97 @@ 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
+ }
230
321
  /**
231
322
  * A deployed form's form-js schema plus its identifying metadata, as
232
323
  * {@link EngineClient.getForm} returns it. `schema` is the parsed form-js document
@@ -327,6 +418,35 @@ export interface EngineClient {
327
418
  processInstanceKeys?: string[];
328
419
  state?: ProcessInstanceState;
329
420
  }): Promise<ProcessInstanceSnapshot[]>;
421
+ /**
422
+ * Search element instances ("tokens") by process instance, element, and/or lifecycle state
423
+ * (`POST /v2/element-instances/search`). Where {@link searchProcessInstances} answers "is
424
+ * this instance still running" and {@link searchUserTasks} answers "what user tasks are
425
+ * open", this answers "what element has a token reached" — including the active
426
+ * *non-user-task* elements (a service task, a gateway, a catch event) that a user-task
427
+ * search cannot see, i.e. "the furthest element reached". An eventually consistent
428
+ * (zero-wait) read; each {@link ElementInstanceSummary} carries the element instance's key,
429
+ * its `elementId`/`elementType`, the owning process instance, and its `state`.
430
+ */
431
+ searchElementInstances(filter?: ElementInstanceFilter): Promise<ElementInstanceSummary[]>;
432
+ /**
433
+ * Search the *wait states* of element instances
434
+ * (`POST /v2/element-instances/wait-states/search`) — every park, not only user tasks. A
435
+ * `JOB` park (a service task awaiting a worker), a `MESSAGE` park (an event awaiting
436
+ * correlation), a `TIMER`/`SIGNAL`/`CONDITION`, plus `USER_TASK`. A zero-wait read; each
437
+ * result is discriminated by `waitStateType` (see {@link ElementInstanceWaitState}), so a
438
+ * consumer can read the job/message parks a {@link searchUserTasks} cannot surface.
439
+ */
440
+ searchElementInstanceWaitStates(filter?: ElementInstanceWaitStateFilter): Promise<ElementInstanceWaitState[]>;
441
+ /**
442
+ * Fetch a single element instance by its key (`GET /v2/element-instances/{elementInstanceKey}`),
443
+ * or `null` when it cannot be resolved — the key is blank, no such element instance exists
444
+ * (a 404), or the fetch otherwise fails. A read is treated as absence rather than propagating
445
+ * (mirroring {@link getForm}), so a caller distinguishes "have it" from "don't" without a
446
+ * try/catch. A zero-wait read returning the same {@link ElementInstanceSummary} shape as
447
+ * {@link searchElementInstances}.
448
+ */
449
+ getElementInstance(elementInstanceKey: string): Promise<ElementInstanceSummary | null>;
330
450
  /** Register a push worker for a job type. Draining is handled by the adapter. */
331
451
  registerWorker(jobType: string, handler: JobHandler, options?: {
332
452
  workerName?: string;
@@ -350,4 +470,4 @@ export interface EngineClient {
350
470
  * and `getForm` before it) that a purely structural `implements EngineClient` check no
351
471
  * longer catches once the fake is published/compiled against an older `@nanobpm/urban`.
352
472
  */
353
- export declare const ENGINE_CLIENT_METHODS: readonly ["deployResources", "createInstance", "cancelInstance", "publishMessage", "searchUserTasks", "openUserTasks", "getForm", "completeUserTask", "searchProcessInstances", "registerWorker", "close"];
473
+ export declare const ENGINE_CLIENT_METHODS: readonly ["deployResources", "createInstance", "cancelInstance", "publishMessage", "searchUserTasks", "openUserTasks", "getForm", "completeUserTask", "searchProcessInstances", "searchElementInstances", "searchElementInstanceWaitStates", "getElementInstance", "registerWorker", "close"];
@@ -66,6 +66,9 @@ export const ENGINE_CLIENT_METHODS = [
66
66
  "getForm",
67
67
  "completeUserTask",
68
68
  "searchProcessInstances",
69
+ "searchElementInstances",
70
+ "searchElementInstanceWaitStates",
71
+ "getElementInstance",
69
72
  "registerWorker",
70
73
  "close",
71
74
  ];
@@ -837,6 +837,11 @@ table.pc-grid th { font-weight:600; color:var(--nano-text-muted); }
837
837
  .pc-appview-frame { display:block; width:100%; min-height:24rem; border:1px solid var(--nano-edge); border-radius:.6rem; background:var(--nano-inset); }
838
838
  .pc-appview-fill { display:flex; flex-direction:column; min-height:min(80vh,48rem); }
839
839
  .pc-appview-fill .pc-appview-frame { flex:1 1 auto; min-height:0; }
840
+ /* When a fill appView is ALSO collapsible, makeCollapsible reparents the iframe into a
841
+ .pc-card-body, so the frame is no longer a direct flex child of .pc-appview-fill and its
842
+ flex:1 above stops taking effect (the panel loses its height). Make the collapse body a flex
843
+ item that grows AND a flex column, so fill propagates through it to the frame. */
844
+ .pc-appview-fill .pc-card-body { flex:1 1 auto; min-height:0; display:flex; flex-direction:column; }
840
845
  /* A standalone button node + the modal it opens (e.g. a copy-pasteable prompt). */
841
846
  .pc-buttonrow { margin:1rem 0; }
842
847
  .pc-btn-ghost { background:transparent; color:var(--nano-text-muted); border:1px solid var(--nano-edge); }