@nanobpm/urban 0.79.0 → 0.81.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/dist/runtime/core/manifest.d.ts +44 -11
- package/dist/runtime/core/modules/cancel.d.ts +13 -8
- package/dist/runtime/core/modules/cancel.js +40 -21
- package/dist/runtime/core/modules/datasource.js +7 -4
- package/dist/runtime/core/modules/formjs.gen.d.ts +1 -0
- package/dist/runtime/core/modules/formjs.gen.js +5 -0
- package/dist/runtime/core/modules/forms.d.ts +22 -0
- package/dist/runtime/core/modules/forms.js +59 -0
- package/dist/runtime/core/modules/gateway.js +5 -4
- package/dist/runtime/core/modules/instance-status-read-model.d.ts +56 -0
- package/dist/runtime/core/modules/instance-status-read-model.js +127 -0
- package/dist/runtime/core/modules/instance-tracking.d.ts +47 -19
- package/dist/runtime/core/modules/instance-tracking.js +451 -123
- package/dist/runtime/core/modules/open-user-tasks-store.d.ts +5 -0
- package/dist/runtime/core/modules/open-user-tasks-store.js +8 -0
- package/dist/runtime/core/modules/pages.js +42 -4
- package/dist/runtime/core/modules/runtime.gen.js +1 -1
- package/dist/runtime/core/modules/surfaces.js +18 -124
- package/dist/runtime/core/read-model.d.ts +28 -0
- package/dist/runtime/core/read-model.js +44 -4
- package/dist/runtime/core/validate.js +192 -0
- package/dist/runtime/index.d.ts +2 -1
- package/dist/runtime/index.js +5 -0
- package/package.json +1 -1
- package/src/runtime/browser/fake-dom.test-utils.ts +114 -0
- package/src/runtime/browser/formjs.browser.js +192 -0
- package/src/runtime/browser/formjs.browser.test.ts +136 -0
- package/src/runtime/browser/runtime.browser.js +101 -1
- package/src/runtime/browser/runtime.engineform.test.ts +158 -0
- package/src/runtime/core/manifest.ts +44 -11
- package/src/runtime/core/modules/cancel.test.ts +112 -38
- package/src/runtime/core/modules/cancel.ts +42 -22
- package/src/runtime/core/modules/datasource.ts +7 -4
- package/src/runtime/core/modules/formjs.gen.ts +6 -0
- package/src/runtime/core/modules/forms.test.ts +122 -0
- package/src/runtime/core/modules/forms.ts +67 -0
- package/src/runtime/core/modules/gateway.ts +7 -4
- package/src/runtime/core/modules/gen-artifacts.test.ts +41 -0
- package/src/runtime/core/modules/instance-status-read-model.ts +156 -0
- package/src/runtime/core/modules/instance-tracking.test.ts +589 -60
- package/src/runtime/core/modules/instance-tracking.ts +469 -126
- package/src/runtime/core/modules/open-user-tasks-store.test.ts +11 -0
- package/src/runtime/core/modules/open-user-tasks-store.ts +11 -0
- package/src/runtime/core/modules/pages.test.ts +99 -0
- package/src/runtime/core/modules/pages.ts +44 -5
- package/src/runtime/core/modules/runtime.gen.ts +1 -1
- package/src/runtime/core/modules/surfaces.ts +19 -121
- package/src/runtime/core/read-model.test.ts +69 -0
- package/src/runtime/core/read-model.ts +43 -4
- package/src/runtime/core/validate.test.ts +341 -0
- package/src/runtime/core/validate.ts +188 -0
- package/src/runtime/index.ts +15 -0
|
@@ -56,6 +56,11 @@ export declare class OpenUserTasksStore {
|
|
|
56
56
|
syncInstance(processInstanceKey: string, openTasks: readonly UserTaskSummary[]): void;
|
|
57
57
|
/** Retire every projected open task for an instance (e.g. it terminated). Idempotent. */
|
|
58
58
|
clearInstance(processInstanceKey: string): void;
|
|
59
|
+
/** Every distinct instance key currently projected as having ≥1 open user task. Used by the
|
|
60
|
+
* reconciler to re-probe (and, when answered, RETIRE) keys that have dropped out of a binding's
|
|
61
|
+
* `activeStatuses` allow-list — a projected row must be retired independently of the base-row
|
|
62
|
+
* selector, or an answered escalation's row would linger and the derived edge tear (ADR 0065). */
|
|
63
|
+
instanceKeys(): string[];
|
|
59
64
|
/** True iff the instance currently has any open user task — the "parked on a human" predicate. */
|
|
60
65
|
hasOpenTask(processInstanceKey: string): boolean;
|
|
61
66
|
/** The projected open tasks for an instance, in insertion order. */
|
|
@@ -113,6 +113,14 @@ export class OpenUserTasksStore {
|
|
|
113
113
|
return;
|
|
114
114
|
this.#db.run(`DELETE FROM ${OPEN_USER_TASKS_TABLE} WHERE process_instance_key = ?`, [processInstanceKey]);
|
|
115
115
|
}
|
|
116
|
+
/** Every distinct instance key currently projected as having ≥1 open user task. Used by the
|
|
117
|
+
* reconciler to re-probe (and, when answered, RETIRE) keys that have dropped out of a binding's
|
|
118
|
+
* `activeStatuses` allow-list — a projected row must be retired independently of the base-row
|
|
119
|
+
* selector, or an answered escalation's row would linger and the derived edge tear (ADR 0065). */
|
|
120
|
+
instanceKeys() {
|
|
121
|
+
const rows = this.#db.all(`SELECT DISTINCT process_instance_key FROM ${OPEN_USER_TASKS_TABLE}`);
|
|
122
|
+
return rows.map((r) => r.process_instance_key);
|
|
123
|
+
}
|
|
116
124
|
/** True iff the instance currently has any open user task — the "parked on a human" predicate. */
|
|
117
125
|
hasOpenTask(processInstanceKey) {
|
|
118
126
|
if (!processInstanceKey)
|
|
@@ -28,8 +28,11 @@ import { errorMessage, isRecord } from "../guards.js";
|
|
|
28
28
|
import { html, json } from "../router.js";
|
|
29
29
|
import { cancelInstanceReconciling } from "./cancel.js";
|
|
30
30
|
import { apiDocsPath } from "./api.js";
|
|
31
|
+
import { FORMJS_JS } from "./formjs.gen.js";
|
|
32
|
+
import { completeUserTaskResponse, resolveFormResponse } from "./forms.js";
|
|
31
33
|
import { quoteIdent } from "./gateway.js";
|
|
32
34
|
import { RENDERER_JS } from "./runtime.gen.js";
|
|
35
|
+
import { isSqlIdentifier } from "../read-model.js";
|
|
33
36
|
/** A JavaScript-body response (the renderer module served at the fingerprinted
|
|
34
37
|
* `/app/runtime.<hash>.js`, and its `/app/runtime.js` back-compat route). */
|
|
35
38
|
function javascript(body, status = 200, extraHeaders) {
|
|
@@ -116,9 +119,10 @@ async function serveAsset(read, filePath) {
|
|
|
116
119
|
return { status: 404, headers: { "content-type": "text/plain; charset=utf-8" }, body: "not found" };
|
|
117
120
|
}
|
|
118
121
|
}
|
|
119
|
-
/** A
|
|
120
|
-
* (checked against `schema()`), so `/app/data/:table` can never inject
|
|
121
|
-
|
|
122
|
+
/** A table name must be a bare SQL identifier ({@link isSqlIdentifier}, the runtime-wide single source
|
|
123
|
+
* of truth) *and* a known table (checked against `schema()`), so `/app/data/:table` can never inject
|
|
124
|
+
* SQL. Reusing the shared guard (rather than a private regex) keeps this surface from drifting from
|
|
125
|
+
* manifest / read-model / data-source identifier validation. */
|
|
122
126
|
// A query flag (e.g. ?count=1) is "on" when present and not one of the falsy
|
|
123
127
|
// spellings. A bare `?count` (empty string) still counts as on, so a caller can
|
|
124
128
|
// opt in without inventing a value.
|
|
@@ -297,7 +301,7 @@ export function createPagesRoutes(opts, deps) {
|
|
|
297
301
|
// source is rejected rather than silently served off the default.
|
|
298
302
|
if (source !== sourceName)
|
|
299
303
|
return json({ error: `unknown datasource "${source}"` }, 404);
|
|
300
|
-
if (!
|
|
304
|
+
if (!isSqlIdentifier(table))
|
|
301
305
|
return json({ error: "invalid table name" }, 400);
|
|
302
306
|
let tables;
|
|
303
307
|
try {
|
|
@@ -489,6 +493,26 @@ export function createPagesRoutes(opts, deps) {
|
|
|
489
493
|
}
|
|
490
494
|
},
|
|
491
495
|
});
|
|
496
|
+
// ── GET /app/actions/form & POST /app/actions/complete (ADR 0026, #457) ───
|
|
497
|
+
// Engine-declared forms in a `dataGrid` detail drawer. A grid whose `detail`
|
|
498
|
+
// opts into `engineForm` resolves the selected row's `form_key` here and
|
|
499
|
+
// completes the row's user task here — the SAME two seams the `taskInbox`
|
|
500
|
+
// surface uses, reused (not forked) via `forms.ts` so the resolution gate and
|
|
501
|
+
// the completion contract can't drift between the two surfaces. This closes the
|
|
502
|
+
// form-duplication drift class: the grid renders the authoritative deployed
|
|
503
|
+
// `.form` rather than a hand-authored page-local `detail.form` copy.
|
|
504
|
+
routes.push({
|
|
505
|
+
method: "GET",
|
|
506
|
+
path: "/app/actions/form",
|
|
507
|
+
source: "surface:pages",
|
|
508
|
+
handler: (req) => resolveFormResponse(engine, req.query.get("formKey") ?? undefined, req.query.get("formId") ?? undefined),
|
|
509
|
+
});
|
|
510
|
+
routes.push({
|
|
511
|
+
method: "POST",
|
|
512
|
+
path: "/app/actions/complete",
|
|
513
|
+
source: "surface:pages",
|
|
514
|
+
handler: async (req) => completeUserTaskResponse(engine, await req.text()),
|
|
515
|
+
});
|
|
492
516
|
// ── nested (multi-appView) sidecars (#442) ──────────────────────────────
|
|
493
517
|
// An app with more than one `appView` cannot share the four FLAT sidecar names above:
|
|
494
518
|
// each view ships its own SUBDIR sidecar — e.g. `pages/cockpit.page.json` →
|
|
@@ -603,6 +627,7 @@ function rendererShell(homePage, apiDocsPath) {
|
|
|
603
627
|
</head>
|
|
604
628
|
<body>${apiDocsBadge}
|
|
605
629
|
<main id="page" data-home="${escapeAttr(homePage)}"><p class="pc-empty">Loading…</p></main>
|
|
630
|
+
<script>${FORMJS_JS}</script>
|
|
606
631
|
<script type="module" src=".${RUNTIME_JS_PATH}"></script>
|
|
607
632
|
</body>
|
|
608
633
|
</html>`;
|
|
@@ -669,6 +694,19 @@ body { margin:0; font:15px/1.5 system-ui,sans-serif; padding:2rem; max-width:64r
|
|
|
669
694
|
.pc-field-check input { width:auto; padding:0; accent-color:var(--nano-accent); cursor:pointer; }
|
|
670
695
|
.pc-btn { padding:.5rem .9rem; border:0; border-radius:.4rem; background:var(--nano-accent); color:var(--nano-on-accent); font:inherit; cursor:pointer; }
|
|
671
696
|
.pc-btn:disabled { opacity:.5; cursor:default; }
|
|
697
|
+
/* The shared engine-form renderer (NanoFormJs, ADR 0026/#457) styled to match the
|
|
698
|
+
page runtime's native detail controls. njf-* are its stable class names; both
|
|
699
|
+
this surface and the taskInbox page style the same renderer output. */
|
|
700
|
+
.njf-form { display:flex; flex-direction:column; gap:.4rem; margin-top:.5rem; }
|
|
701
|
+
.njf-heading { font-size:1rem; margin:0 0 .25rem; }
|
|
702
|
+
.njf-text { color:var(--nano-text-muted); margin:.25rem 0; }
|
|
703
|
+
.njf-field { display:flex; flex-direction:column; gap:.25rem; }
|
|
704
|
+
.njf-field label { font-size:.8rem; color:var(--nano-text-muted); }
|
|
705
|
+
.njf-field input:not([type=checkbox]):not([type=radio]), .njf-field textarea, .njf-field select { padding:.5rem .6rem; border:1px solid var(--nano-edge); border-radius:.4rem; font:inherit; background:var(--nano-inset); color:var(--nano-text); max-width:24rem; }
|
|
706
|
+
.njf-actions { display:flex; gap:.5rem; margin-top:.4rem; }
|
|
707
|
+
.njf-actions button { padding:.5rem .9rem; border:0; border-radius:.4rem; background:var(--nano-accent); color:var(--nano-on-accent); font:inherit; cursor:pointer; }
|
|
708
|
+
.njf-msg { font-size:.85rem; margin-top:.35rem; }
|
|
709
|
+
.njf-msg.err { color:var(--nano-danger); }
|
|
672
710
|
.pc-msg { font-size:.85rem; margin-top:.5rem; min-height:1.2em; }
|
|
673
711
|
.pc-msg.err { color:var(--nano-danger); }
|
|
674
712
|
.pc-msg.ok { color:var(--nano-ok); }
|