@miragon/pulse-engine-client 0.0.0-stage → 0.25.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/LICENSE +21 -0
- package/README.md +109 -2
- package/dist/client.d.ts +65 -0
- package/dist/client.d.ts.map +1 -0
- package/dist/client.js +144 -0
- package/dist/client.js.map +1 -0
- package/dist/engine-contract/batches.d.ts +41 -0
- package/dist/engine-contract/batches.d.ts.map +1 -0
- package/dist/engine-contract/batches.js +39 -0
- package/dist/engine-contract/batches.js.map +1 -0
- package/dist/engine-contract/index.d.ts +11 -0
- package/dist/engine-contract/index.d.ts.map +1 -0
- package/dist/engine-contract/index.js +11 -0
- package/dist/engine-contract/index.js.map +1 -0
- package/dist/engine-contract/reads.d.ts +43 -0
- package/dist/engine-contract/reads.d.ts.map +1 -0
- package/dist/engine-contract/reads.js +86 -0
- package/dist/engine-contract/reads.js.map +1 -0
- package/dist/engine-error.d.ts +73 -0
- package/dist/engine-error.d.ts.map +1 -0
- package/dist/engine-error.js +231 -0
- package/dist/engine-error.js.map +1 -0
- package/dist/generated/client/client.gen.d.ts +3 -0
- package/dist/generated/client/client.gen.d.ts.map +1 -0
- package/dist/generated/client/client.gen.js +217 -0
- package/dist/generated/client/client.gen.js.map +1 -0
- package/dist/generated/client/index.d.ts +11 -0
- package/dist/generated/client/index.d.ts.map +1 -0
- package/dist/generated/client/index.js +7 -0
- package/dist/generated/client/index.js.map +1 -0
- package/dist/generated/client/types.gen.d.ts +121 -0
- package/dist/generated/client/types.gen.d.ts.map +1 -0
- package/dist/generated/client/types.gen.js +3 -0
- package/dist/generated/client/types.gen.js.map +1 -0
- package/dist/generated/client/utils.gen.d.ts +38 -0
- package/dist/generated/client/utils.gen.d.ts.map +1 -0
- package/dist/generated/client/utils.gen.js +229 -0
- package/dist/generated/client/utils.gen.js.map +1 -0
- package/dist/generated/client.gen.d.ts +13 -0
- package/dist/generated/client.gen.d.ts.map +1 -0
- package/dist/generated/client.gen.js +5 -0
- package/dist/generated/client.gen.js.map +1 -0
- package/dist/generated/core/auth.gen.d.ts +26 -0
- package/dist/generated/core/auth.gen.d.ts.map +1 -0
- package/dist/generated/core/auth.gen.js +15 -0
- package/dist/generated/core/auth.gen.js.map +1 -0
- package/dist/generated/core/bodySerializer.gen.d.ts +26 -0
- package/dist/generated/core/bodySerializer.gen.d.ts.map +1 -0
- package/dist/generated/core/bodySerializer.gen.js +58 -0
- package/dist/generated/core/bodySerializer.gen.js.map +1 -0
- package/dist/generated/core/params.gen.d.ts +44 -0
- package/dist/generated/core/params.gen.d.ts.map +1 -0
- package/dist/generated/core/params.gen.js +110 -0
- package/dist/generated/core/params.gen.js.map +1 -0
- package/dist/generated/core/pathSerializer.gen.d.ts +34 -0
- package/dist/generated/core/pathSerializer.gen.d.ts.map +1 -0
- package/dist/generated/core/pathSerializer.gen.js +107 -0
- package/dist/generated/core/pathSerializer.gen.js.map +1 -0
- package/dist/generated/core/queryKeySerializer.gen.d.ts +19 -0
- package/dist/generated/core/queryKeySerializer.gen.d.ts.map +1 -0
- package/dist/generated/core/queryKeySerializer.gen.js +93 -0
- package/dist/generated/core/queryKeySerializer.gen.js.map +1 -0
- package/dist/generated/core/serverSentEvents.gen.d.ts +72 -0
- package/dist/generated/core/serverSentEvents.gen.d.ts.map +1 -0
- package/dist/generated/core/serverSentEvents.gen.js +133 -0
- package/dist/generated/core/serverSentEvents.gen.js.map +1 -0
- package/dist/generated/core/types.gen.d.ts +84 -0
- package/dist/generated/core/types.gen.d.ts.map +1 -0
- package/dist/generated/core/types.gen.js +3 -0
- package/dist/generated/core/types.gen.js.map +1 -0
- package/dist/generated/core/utils.gen.d.ts +20 -0
- package/dist/generated/core/utils.gen.d.ts.map +1 -0
- package/dist/generated/core/utils.gen.js +88 -0
- package/dist/generated/core/utils.gen.js.map +1 -0
- package/dist/generated/index.d.ts +3 -0
- package/dist/generated/index.d.ts.map +1 -0
- package/dist/generated/index.js +3 -0
- package/dist/generated/index.js.map +1 -0
- package/dist/generated/sdk.gen.d.ts +3207 -0
- package/dist/generated/sdk.gen.d.ts.map +1 -0
- package/dist/generated/sdk.gen.js +5794 -0
- package/dist/generated/sdk.gen.js.map +1 -0
- package/dist/generated/types.gen.d.ts +27591 -0
- package/dist/generated/types.gen.d.ts.map +1 -0
- package/dist/generated/types.gen.js +3 -0
- package/dist/generated/types.gen.js.map +1 -0
- package/dist/hey-api.d.ts +10 -0
- package/dist/hey-api.d.ts.map +1 -0
- package/dist/hey-api.js +27 -0
- package/dist/hey-api.js.map +1 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +4 -0
- package/dist/index.js.map +1 -0
- package/package.json +63 -3
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Miragon GmbH
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,3 +1,110 @@
|
|
|
1
|
-
#
|
|
1
|
+
# @miragon/pulse-engine-client
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
[](https://www.npmjs.com/package/@miragon/pulse-engine-client)
|
|
4
|
+
[](https://github.com/Miragon/pulse/actions/workflows/ci.yml)
|
|
5
|
+
[](https://miragon.github.io/pulse/)
|
|
6
|
+
|
|
7
|
+
A typed TypeScript client for the REST API of Camunda 7, CIB seven and Operaton.
|
|
8
|
+
|
|
9
|
+
## Install
|
|
10
|
+
|
|
11
|
+
```sh
|
|
12
|
+
npm install @miragon/pulse-engine-client
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
## Overview
|
|
16
|
+
|
|
17
|
+
TypeScript client for the [CIB seven](https://cibseven.org/) REST API: an SDK
|
|
18
|
+
generated with [`@hey-api/openapi-ts`](https://heyapi.dev/), a client factory
|
|
19
|
+
with deadlines and engine errors, and the reads whose REST contract the SDK
|
|
20
|
+
defaults miss. There is no official TypeScript client for CIB seven; this
|
|
21
|
+
package fills that gap for Pulse and is usable by any CIB seven / Camunda 7
|
|
22
|
+
project. It has no runtime dependency. The pure engine REST rules (dates,
|
|
23
|
+
filters, sorting, variable writes, incident recovery) live in
|
|
24
|
+
[`@miragon/pulse-engine-core`](../engine-core/README.md), which this package
|
|
25
|
+
does not import.
|
|
26
|
+
|
|
27
|
+
## Exports
|
|
28
|
+
|
|
29
|
+
| Subpath | Contents |
|
|
30
|
+
| --------- | ----------------------------------------------------------------------------------------- |
|
|
31
|
+
| `.` | `createEngineClient` factory, `EngineRequestError`, the SDK-bound reads and batch reports |
|
|
32
|
+
| `./sdk` | Generated SDK, one typed function per REST operation |
|
|
33
|
+
| `./types` | Generated request/response types |
|
|
34
|
+
|
|
35
|
+
These three subpaths are the public API. The internal layout of the generated
|
|
36
|
+
output (`dist/generated/**`) is not: it may change with any `@hey-api/openapi-ts`
|
|
37
|
+
upgrade, so deep imports are deliberately not exported.
|
|
38
|
+
|
|
39
|
+
## Client behavior
|
|
40
|
+
|
|
41
|
+
SDK functions return the response payload directly (`responseStyle: "data"`)
|
|
42
|
+
and reject on HTTP error responses (`throwOnError: true`). Both options are
|
|
43
|
+
declared once in the generator config (`openapi-ts.config.ts`) and applied at
|
|
44
|
+
runtime through `createClientConfig` (`src/hey-api.ts`), which the generated
|
|
45
|
+
default client and `createEngineClient` share, so generated types and runtime
|
|
46
|
+
behavior always agree.
|
|
47
|
+
|
|
48
|
+
```ts
|
|
49
|
+
import { createEngineClient } from "@miragon/pulse-engine-client"
|
|
50
|
+
import { getProcessDefinitions } from "@miragon/pulse-engine-client/sdk"
|
|
51
|
+
|
|
52
|
+
const client = createEngineClient({
|
|
53
|
+
baseUrl: "http://localhost:8410/engine-rest",
|
|
54
|
+
authType: "basic",
|
|
55
|
+
username: "demo",
|
|
56
|
+
password: "demo",
|
|
57
|
+
})
|
|
58
|
+
const definitions = await getProcessDefinitions({ client, query: { latestVersion: true } })
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
Every `createEngineClient` client, whatever its auth type, rejects with an
|
|
62
|
+
`EngineRequestError` (an `Error` with `kind`, `httpStatus`, `type`,
|
|
63
|
+
`engineMessage`, `engineCode`, `engineId`) instead of the raw error body, with
|
|
64
|
+
a message that is safe and useful to show a model (engine text truncated, the
|
|
65
|
+
request's credentials masked):
|
|
66
|
+
`[404 InvalidRequestException] Process instance with id x does not exist (engine prod-a)`,
|
|
67
|
+
`engine prod-a unreachable (ECONNREFUSED)` (no connection: the engine never
|
|
68
|
+
saw the request), `connection to engine prod-a failed (ECONNRESET)` (dropped
|
|
69
|
+
mid-request; a write adds that it may still have been applied), or
|
|
70
|
+
`engine prod-a did not respond within 30000 ms (timeout)`. Pass `engineId` to
|
|
71
|
+
name the engine in those messages and `timeoutMs` to change the per-request
|
|
72
|
+
deadline (default 30 000 ms). `withCallerSignal(client, signal)` returns a view
|
|
73
|
+
whose reads (`GET`/`HEAD`/`OPTIONS`) also abort with the caller's signal;
|
|
74
|
+
writes never do, since aborting a started write cannot undo it.
|
|
75
|
+
|
|
76
|
+
The deadline lives in the client's `fetch`, so it binds each request after
|
|
77
|
+
every request interceptor. A custom `fetch` (per call or via `setConfig`)
|
|
78
|
+
replaces it, so wrap `client.getConfig().fetch` instead. Request interceptors
|
|
79
|
+
should mutate the request (`request.headers.set(…)`): one that returns a new
|
|
80
|
+
`Request` keeps the deadline, but can detach the caller's signal.
|
|
81
|
+
|
|
82
|
+
## OpenAPI spec: origin & refresh
|
|
83
|
+
|
|
84
|
+
The spec is checked in as `cibseven-open-api-doc.json` (currently reporting
|
|
85
|
+
`info.version` **2.1.2**). It originates from the engine's published OpenAPI
|
|
86
|
+
artifact `org.cibseven.bpm:cibseven-engine-rest-openapi` (a jar containing
|
|
87
|
+
`openapi.json`); Maven Central publishes the minor releases (2.1.0, 2.2.0, …).
|
|
88
|
+
The running engine does not serve its spec over HTTP, so the artifact is the
|
|
89
|
+
canonical source.
|
|
90
|
+
|
|
91
|
+
To refresh:
|
|
92
|
+
|
|
93
|
+
```bash
|
|
94
|
+
pnpm spec:refresh <version> # downloads + extracts the spec, e.g. pnpm spec:refresh 2.2.0
|
|
95
|
+
pnpm generate # regenerate src/generated from the new spec
|
|
96
|
+
git diff # review spec + SDK changes, run the repo verification suite
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
Commit the spec and the regenerated output together: `src/generated/` is
|
|
100
|
+
checked in and CI assumes it matches the spec.
|
|
101
|
+
|
|
102
|
+
## The SDK-bound reads
|
|
103
|
+
|
|
104
|
+
`src/engine-contract/` holds the reads whose REST contract differs from the SDK
|
|
105
|
+
defaults: the `text/plain`-only stacktrace and error-details endpoints
|
|
106
|
+
(`fetchJobStacktrace`, `fetchExternalTaskErrorDetails`, `null` on a 404),
|
|
107
|
+
variable reads with `deserializeValues=false` (`readProcessInstanceVariables`,
|
|
108
|
+
`readTaskVariables`) and `readBatch`, which falls back from the runtime
|
|
109
|
+
statistics to the history record. The MCP tools' input schemas live in
|
|
110
|
+
`@miragon/pulse-engine-connector` next to its tools.
|
package/dist/client.d.ts
ADDED
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import type { Client } from "./generated/client/types.gen.js";
|
|
2
|
+
export type { Client };
|
|
3
|
+
export type EngineAuthType = "basic" | "bearer" | "passthrough" | "none";
|
|
4
|
+
/** Default per-request deadline for engine calls (`timeoutMs`). */
|
|
5
|
+
export declare const DEFAULT_ENGINE_TIMEOUT_MS = 30000;
|
|
6
|
+
export interface EngineClientOptions {
|
|
7
|
+
baseUrl: string;
|
|
8
|
+
/**
|
|
9
|
+
* Id of the configured engine this client talks to. Carried into every
|
|
10
|
+
* error message (`… (engine prod-a)`) so the model can tell WHICH engine
|
|
11
|
+
* failed in a multi-engine fleet; left out of the message when unset.
|
|
12
|
+
*/
|
|
13
|
+
engineId?: string;
|
|
14
|
+
/**
|
|
15
|
+
* Per-request deadline in ms (default {@link DEFAULT_ENGINE_TIMEOUT_MS}),
|
|
16
|
+
* covering connect, headers and body. A hung engine then fails the call
|
|
17
|
+
* with a timeout error instead of holding it for undici's minutes-long
|
|
18
|
+
* defaults.
|
|
19
|
+
*/
|
|
20
|
+
timeoutMs?: number;
|
|
21
|
+
authType?: EngineAuthType;
|
|
22
|
+
username?: string;
|
|
23
|
+
password?: string;
|
|
24
|
+
token?: string;
|
|
25
|
+
/**
|
|
26
|
+
* Token source for `authType: "passthrough"`, called on every request; the
|
|
27
|
+
* returned bearer token (without the `Bearer ` scheme prefix) is sent as
|
|
28
|
+
* the `Authorization` header. When it returns `undefined` (or no provider
|
|
29
|
+
* is given), the request is sent without auth, like `authType: "none"`;
|
|
30
|
+
* an engine with REST auth enabled then answers 401.
|
|
31
|
+
*/
|
|
32
|
+
tokenProvider?: () => string | undefined;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Per-engine client factory. All defaults (JSON content negotiation headers,
|
|
36
|
+
* `throwOnError`, `responseStyle`) come from `createClientConfig` in
|
|
37
|
+
* src/hey-api.ts (the same function the generated default client uses), so
|
|
38
|
+
* runtime behavior and the generated SDK types stay in sync.
|
|
39
|
+
*
|
|
40
|
+
* Every client, whatever its auth type, carries a per-request deadline in its
|
|
41
|
+
* `fetch` (combined with a caller `signal`, see {@link withCallerSignal}) and
|
|
42
|
+
* an error interceptor that maps every failure to an `EngineRequestError`
|
|
43
|
+
* (status, exception type, engine message, engine id; credentials masked).
|
|
44
|
+
*
|
|
45
|
+
* The deadline binds the request as it LEAVES (after every request
|
|
46
|
+
* interceptor), so an interceptor that returns a new `Request` can neither
|
|
47
|
+
* detach it nor disguise it as a cancellation. A custom `fetch` (per call or
|
|
48
|
+
* via `setConfig`) replaces the deadline with it: wrap
|
|
49
|
+
* `client.getConfig().fetch` instead. Request interceptors should mutate the
|
|
50
|
+
* request (`request.headers.set(…)`); one that returns a new `Request` keeps
|
|
51
|
+
* the deadline, but the caller's signal reaches the new request only through
|
|
52
|
+
* the dropped one (undici follows signals via a `WeakRef`), so after a
|
|
53
|
+
* garbage collection a cancelled call runs on until the deadline.
|
|
54
|
+
*/
|
|
55
|
+
export declare function createEngineClient(options: EngineClientOptions): Client;
|
|
56
|
+
/**
|
|
57
|
+
* A view of `client` whose READS honor the caller's `signal` (an MCP
|
|
58
|
+
* request's `ctx.signal`, aborted when the MCP client cancels or
|
|
59
|
+
* disconnects), on top of the client's own deadline. Writes never see it:
|
|
60
|
+
* aborting a started write cannot roll it back on the engine, it only turns
|
|
61
|
+
* a known outcome into an unknown one. An explicit per-call `signal` wins.
|
|
62
|
+
* Without a signal the client itself is returned.
|
|
63
|
+
*/
|
|
64
|
+
export declare function withCallerSignal(client: Client, signal: AbortSignal | undefined): Client;
|
|
65
|
+
//# sourceMappingURL=client.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,iCAAiC,CAAA;AAI7D,YAAY,EAAE,MAAM,EAAE,CAAA;AAEtB,MAAM,MAAM,cAAc,GAAG,OAAO,GAAG,QAAQ,GAAG,aAAa,GAAG,MAAM,CAAA;AAExE,mEAAmE;AACnE,eAAO,MAAM,yBAAyB,QAAS,CAAA;AAK/C,MAAM,WAAW,mBAAmB;IAClC,OAAO,EAAE,MAAM,CAAA;IACf;;;;OAIG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB;;;;;OAKG;IACH,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,QAAQ,CAAC,EAAE,cAAc,CAAA;IACzB,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,KAAK,CAAC,EAAE,MAAM,CAAA;IACd;;;;;;OAMG;IACH,aAAa,CAAC,EAAE,MAAM,MAAM,GAAG,SAAS,CAAA;CACzC;AAsDD;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,mBAAmB,GAAG,MAAM,CAsDvE;AAKD;;;;;;;GAOG;AACH,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,WAAW,GAAG,SAAS,GAAG,MAAM,CASxF"}
|
package/dist/client.js
ADDED
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
import { createClient } from "./generated/client/client.gen.js";
|
|
2
|
+
import { createClientConfig } from "./hey-api.js";
|
|
3
|
+
import { toEngineRequestError } from "./engine-error.js";
|
|
4
|
+
/** Default per-request deadline for engine calls (`timeoutMs`). */
|
|
5
|
+
export const DEFAULT_ENGINE_TIMEOUT_MS = 30_000;
|
|
6
|
+
/** The largest delay a Node timer holds; a longer one would fire immediately. */
|
|
7
|
+
const MAX_TIMEOUT_MS = 2_147_483_647;
|
|
8
|
+
function buildAuthHeader(options) {
|
|
9
|
+
const { authType = "none", username, password, token } = options;
|
|
10
|
+
if (authType === "basic" && username && password) {
|
|
11
|
+
const encoded = typeof btoa === "function"
|
|
12
|
+
? btoa(`${username}:${password}`)
|
|
13
|
+
: Buffer.from(`${username}:${password}`).toString("base64");
|
|
14
|
+
return { Authorization: `Basic ${encoded}` };
|
|
15
|
+
}
|
|
16
|
+
if (authType === "bearer" && token) {
|
|
17
|
+
return { Authorization: `Bearer ${token}` };
|
|
18
|
+
}
|
|
19
|
+
// "passthrough" deliberately sets no static header: the per-request
|
|
20
|
+
// interceptor below owns the Authorization header instead.
|
|
21
|
+
return {};
|
|
22
|
+
}
|
|
23
|
+
/** The remedy a 401 message names: it depends on where the credential came from. */
|
|
24
|
+
function unauthorizedHint(options) {
|
|
25
|
+
switch (options.authType ?? "none") {
|
|
26
|
+
case "passthrough":
|
|
27
|
+
return options.tokenProvider?.()
|
|
28
|
+
? "The engine rejected the forwarded bearer token."
|
|
29
|
+
: "The MCP request carried no bearer token to pass through.";
|
|
30
|
+
case "none":
|
|
31
|
+
return "The engine requires authentication, but none is configured.";
|
|
32
|
+
default:
|
|
33
|
+
return "The engine rejected the configured credentials.";
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
function resolveTimeout(timeoutMs) {
|
|
37
|
+
if (timeoutMs === undefined)
|
|
38
|
+
return DEFAULT_ENGINE_TIMEOUT_MS;
|
|
39
|
+
if (!Number.isInteger(timeoutMs) || timeoutMs <= 0 || timeoutMs > MAX_TIMEOUT_MS) {
|
|
40
|
+
throw new RangeError(`Engine request timeout must be a positive integer of at most ${MAX_TIMEOUT_MS} ms, got ${timeoutMs}`);
|
|
41
|
+
}
|
|
42
|
+
return timeoutMs;
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* The credentials a request carried, for masking in error text (an engine or
|
|
46
|
+
* proxy may quote them back): the configured password/token and whatever the
|
|
47
|
+
* request's own `Authorization` header holds (the Basic value, a static or a
|
|
48
|
+
* passed-through bearer token).
|
|
49
|
+
*/
|
|
50
|
+
function credentialsOf(options, request) {
|
|
51
|
+
const authorization = request?.headers.get("Authorization") ?? undefined;
|
|
52
|
+
return [options.password, options.token, authorization?.replace(/^\S+\s+/, "")];
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Per-engine client factory. All defaults (JSON content negotiation headers,
|
|
56
|
+
* `throwOnError`, `responseStyle`) come from `createClientConfig` in
|
|
57
|
+
* src/hey-api.ts (the same function the generated default client uses), so
|
|
58
|
+
* runtime behavior and the generated SDK types stay in sync.
|
|
59
|
+
*
|
|
60
|
+
* Every client, whatever its auth type, carries a per-request deadline in its
|
|
61
|
+
* `fetch` (combined with a caller `signal`, see {@link withCallerSignal}) and
|
|
62
|
+
* an error interceptor that maps every failure to an `EngineRequestError`
|
|
63
|
+
* (status, exception type, engine message, engine id; credentials masked).
|
|
64
|
+
*
|
|
65
|
+
* The deadline binds the request as it LEAVES (after every request
|
|
66
|
+
* interceptor), so an interceptor that returns a new `Request` can neither
|
|
67
|
+
* detach it nor disguise it as a cancellation. A custom `fetch` (per call or
|
|
68
|
+
* via `setConfig`) replaces the deadline with it: wrap
|
|
69
|
+
* `client.getConfig().fetch` instead. Request interceptors should mutate the
|
|
70
|
+
* request (`request.headers.set(…)`); one that returns a new `Request` keeps
|
|
71
|
+
* the deadline, but the caller's signal reaches the new request only through
|
|
72
|
+
* the dropped one (undici follows signals via a `WeakRef`), so after a
|
|
73
|
+
* garbage collection a cancelled call runs on until the deadline.
|
|
74
|
+
*/
|
|
75
|
+
export function createEngineClient(options) {
|
|
76
|
+
const timeoutMs = resolveTimeout(options.timeoutMs);
|
|
77
|
+
// Keyed by the request hey-api sends, i.e. the one its error interceptors
|
|
78
|
+
// receive: tells OUR deadline from a caller's cancellation, and keeps the
|
|
79
|
+
// timer alive exactly as long as hey-api holds that request (body read
|
|
80
|
+
// included).
|
|
81
|
+
const deadlines = new WeakMap();
|
|
82
|
+
const fetchWithDeadline = (request) => {
|
|
83
|
+
const deadline = AbortSignal.timeout(timeoutMs);
|
|
84
|
+
deadlines.set(request, deadline);
|
|
85
|
+
return fetch(request, { signal: AbortSignal.any([request.signal, deadline]) });
|
|
86
|
+
};
|
|
87
|
+
const client = createClient(createClientConfig({
|
|
88
|
+
baseUrl: options.baseUrl,
|
|
89
|
+
headers: buildAuthHeader(options),
|
|
90
|
+
// hey-api calls its `fetch` with the finished Request only.
|
|
91
|
+
fetch: fetchWithDeadline,
|
|
92
|
+
// Redirects are FOLLOWED, hey-api's own default, stated so the difference shows: the CLI
|
|
93
|
+
// and the VS Code extension send `redirect: "manual"` (a followed 302/303 turns a write
|
|
94
|
+
// into a GET). One policy for all three is a behaviour change of its own.
|
|
95
|
+
redirect: "follow",
|
|
96
|
+
}));
|
|
97
|
+
if (options.authType === "passthrough" && options.tokenProvider) {
|
|
98
|
+
const { tokenProvider } = options;
|
|
99
|
+
// Not the hey-api `auth` option: the generated operations all declare the
|
|
100
|
+
// `basic` security scheme, so `auth` would base64-mangle a bearer token.
|
|
101
|
+
// The interceptor must only ever touch Authorization: the multipart
|
|
102
|
+
// operations rely on an absent Content-Type for the boundary parameter.
|
|
103
|
+
client.interceptors.request.use((request) => {
|
|
104
|
+
const token = tokenProvider();
|
|
105
|
+
if (token) {
|
|
106
|
+
request.headers.set("Authorization", `Bearer ${token}`);
|
|
107
|
+
}
|
|
108
|
+
return request;
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
// Always on: hey-api throws the parsed error BODY (an ExceptionDto object,
|
|
112
|
+
// the text, or `{}`), which the model would read as "[object Object]".
|
|
113
|
+
client.interceptors.error.use((error, response, request) => toEngineRequestError(error, {
|
|
114
|
+
response,
|
|
115
|
+
request,
|
|
116
|
+
engineId: options.engineId,
|
|
117
|
+
timeoutMs,
|
|
118
|
+
timedOut: request ? deadlines.get(request)?.aborted === true : false,
|
|
119
|
+
unauthorizedHint: response?.status === 401 ? unauthorizedHint(options) : undefined,
|
|
120
|
+
secrets: credentialsOf(options, request),
|
|
121
|
+
}));
|
|
122
|
+
return client;
|
|
123
|
+
}
|
|
124
|
+
/** The methods a caller's cancellation may abort: reads, never writes. */
|
|
125
|
+
const CANCELLABLE_METHODS = ["get", "head", "options"];
|
|
126
|
+
/**
|
|
127
|
+
* A view of `client` whose READS honor the caller's `signal` (an MCP
|
|
128
|
+
* request's `ctx.signal`, aborted when the MCP client cancels or
|
|
129
|
+
* disconnects), on top of the client's own deadline. Writes never see it:
|
|
130
|
+
* aborting a started write cannot roll it back on the engine, it only turns
|
|
131
|
+
* a known outcome into an unknown one. An explicit per-call `signal` wins.
|
|
132
|
+
* Without a signal the client itself is returned.
|
|
133
|
+
*/
|
|
134
|
+
export function withCallerSignal(client, signal) {
|
|
135
|
+
if (!signal)
|
|
136
|
+
return client;
|
|
137
|
+
const bound = { ...client };
|
|
138
|
+
for (const method of CANCELLABLE_METHODS) {
|
|
139
|
+
const call = client[method];
|
|
140
|
+
bound[method] = ((callOptions) => call({ ...callOptions, signal: callOptions.signal ?? signal }));
|
|
141
|
+
}
|
|
142
|
+
return bound;
|
|
143
|
+
}
|
|
144
|
+
//# sourceMappingURL=client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Batches. A batch write (`POST /job/retries`, `POST /migration/executeAsync`)
|
|
3
|
+
* returns as soon as the engine has QUEUED the batch: the work and its
|
|
4
|
+
* failures happen later, in batch jobs. A tool must therefore never report
|
|
5
|
+
* the queued batch as done: it hands back the batch id with status `queued`,
|
|
6
|
+
* and `engine_get_batch` reports what became of it.
|
|
7
|
+
*/
|
|
8
|
+
import type { BatchDto, BatchStatisticsDto, HistoricBatchDto } from "../generated/types.gen.js";
|
|
9
|
+
/** What a batch write returns: the id to follow up on, never a success flag. */
|
|
10
|
+
export interface QueuedBatch {
|
|
11
|
+
batchId: string;
|
|
12
|
+
status: "queued";
|
|
13
|
+
/** Engine batch type, e.g. `set-job-retries`, `instance-migration`. */
|
|
14
|
+
type: string | null;
|
|
15
|
+
totalJobs: number | null;
|
|
16
|
+
}
|
|
17
|
+
export declare function queuedBatch(batch: BatchDto): QueuedBatch;
|
|
18
|
+
/**
|
|
19
|
+
* - `running`: batch jobs are still being created or executed;
|
|
20
|
+
* - `failing`: some batch jobs ran out of retries, so the batch cannot finish
|
|
21
|
+
* until they are retried or the batch is deleted;
|
|
22
|
+
* - `suspended`: suspended, nothing executes;
|
|
23
|
+
* - `completed`: the batch ended (all jobs done, or it was deleted).
|
|
24
|
+
*/
|
|
25
|
+
export type BatchStatus = "running" | "failing" | "suspended" | "completed";
|
|
26
|
+
export interface BatchReport {
|
|
27
|
+
batchId: string;
|
|
28
|
+
type: string | null;
|
|
29
|
+
status: BatchStatus;
|
|
30
|
+
totalJobs: number | null;
|
|
31
|
+
/** Runtime counts, null once the batch has ended. */
|
|
32
|
+
remainingJobs: number | null;
|
|
33
|
+
completedJobs: number | null;
|
|
34
|
+
failedJobs: number | null;
|
|
35
|
+
startTime: string | null;
|
|
36
|
+
endTime: string | null;
|
|
37
|
+
}
|
|
38
|
+
export declare function runningBatchReport(stats: BatchStatisticsDto): BatchReport;
|
|
39
|
+
/** A batch the runtime no longer holds, from its history record. */
|
|
40
|
+
export declare function endedBatchReport(batch: HistoricBatchDto): BatchReport;
|
|
41
|
+
//# sourceMappingURL=batches.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"batches.d.ts","sourceRoot":"","sources":["../../src/engine-contract/batches.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,OAAO,KAAK,EAAE,QAAQ,EAAE,kBAAkB,EAAE,gBAAgB,EAAE,MAAM,2BAA2B,CAAA;AAE/F,gFAAgF;AAChF,MAAM,WAAW,WAAW;IAC1B,OAAO,EAAE,MAAM,CAAA;IACf,MAAM,EAAE,QAAQ,CAAA;IAChB,uEAAuE;IACvE,IAAI,EAAE,MAAM,GAAG,IAAI,CAAA;IACnB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAA;CACzB;AAED,wBAAgB,WAAW,CAAC,KAAK,EAAE,QAAQ,GAAG,WAAW,CAOxD;AAED;;;;;;GAMG;AACH,MAAM,MAAM,WAAW,GAAG,SAAS,GAAG,SAAS,GAAG,WAAW,GAAG,WAAW,CAAA;AAE3E,MAAM,WAAW,WAAW;IAC1B,OAAO,EAAE,MAAM,CAAA;IACf,IAAI,EAAE,MAAM,GAAG,IAAI,CAAA;IACnB,MAAM,EAAE,WAAW,CAAA;IACnB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAA;IACxB,qDAAqD;IACrD,aAAa,EAAE,MAAM,GAAG,IAAI,CAAA;IAC5B,aAAa,EAAE,MAAM,GAAG,IAAI,CAAA;IAC5B,UAAU,EAAE,MAAM,GAAG,IAAI,CAAA;IACzB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAA;IACxB,OAAO,EAAE,MAAM,GAAG,IAAI,CAAA;CACvB;AAED,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,kBAAkB,GAAG,WAAW,CAczE;AAED,oEAAoE;AACpE,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,gBAAgB,GAAG,WAAW,CAarE"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
export function queuedBatch(batch) {
|
|
2
|
+
return {
|
|
3
|
+
batchId: batch.id ?? "",
|
|
4
|
+
status: "queued",
|
|
5
|
+
type: batch.type ?? null,
|
|
6
|
+
totalJobs: batch.totalJobs ?? null,
|
|
7
|
+
};
|
|
8
|
+
}
|
|
9
|
+
export function runningBatchReport(stats) {
|
|
10
|
+
const failedJobs = stats.failedJobs ?? 0;
|
|
11
|
+
const status = stats.suspended ? "suspended" : failedJobs > 0 ? "failing" : "running";
|
|
12
|
+
return {
|
|
13
|
+
batchId: stats.id ?? "",
|
|
14
|
+
type: stats.type ?? null,
|
|
15
|
+
status,
|
|
16
|
+
totalJobs: stats.totalJobs ?? null,
|
|
17
|
+
remainingJobs: stats.remainingJobs ?? null,
|
|
18
|
+
completedJobs: stats.completedJobs ?? null,
|
|
19
|
+
failedJobs,
|
|
20
|
+
startTime: stats.startTime ?? null,
|
|
21
|
+
endTime: null,
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
/** A batch the runtime no longer holds, from its history record. */
|
|
25
|
+
export function endedBatchReport(batch) {
|
|
26
|
+
return {
|
|
27
|
+
batchId: batch.id ?? "",
|
|
28
|
+
type: batch.type ?? null,
|
|
29
|
+
// A historic batch without endTime is one the runtime query just missed.
|
|
30
|
+
status: batch.endTime ? "completed" : "running",
|
|
31
|
+
totalJobs: batch.totalJobs ?? null,
|
|
32
|
+
remainingJobs: null,
|
|
33
|
+
completedJobs: null,
|
|
34
|
+
failedJobs: null,
|
|
35
|
+
startTime: batch.startTime ?? null,
|
|
36
|
+
endTime: batch.endTime ?? null,
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
//# sourceMappingURL=batches.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"batches.js","sourceRoot":"","sources":["../../src/engine-contract/batches.ts"],"names":[],"mappings":"AAkBA,MAAM,UAAU,WAAW,CAAC,KAAe;IACzC,OAAO;QACL,OAAO,EAAE,KAAK,CAAC,EAAE,IAAI,EAAE;QACvB,MAAM,EAAE,QAAQ;QAChB,IAAI,EAAE,KAAK,CAAC,IAAI,IAAI,IAAI;QACxB,SAAS,EAAE,KAAK,CAAC,SAAS,IAAI,IAAI;KACnC,CAAA;AACH,CAAC;AAwBD,MAAM,UAAU,kBAAkB,CAAC,KAAyB;IAC1D,MAAM,UAAU,GAAG,KAAK,CAAC,UAAU,IAAI,CAAC,CAAA;IACxC,MAAM,MAAM,GAAgB,KAAK,CAAC,SAAS,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,UAAU,GAAG,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,SAAS,CAAA;IAClG,OAAO;QACL,OAAO,EAAE,KAAK,CAAC,EAAE,IAAI,EAAE;QACvB,IAAI,EAAE,KAAK,CAAC,IAAI,IAAI,IAAI;QACxB,MAAM;QACN,SAAS,EAAE,KAAK,CAAC,SAAS,IAAI,IAAI;QAClC,aAAa,EAAE,KAAK,CAAC,aAAa,IAAI,IAAI;QAC1C,aAAa,EAAE,KAAK,CAAC,aAAa,IAAI,IAAI;QAC1C,UAAU;QACV,SAAS,EAAE,KAAK,CAAC,SAAS,IAAI,IAAI;QAClC,OAAO,EAAE,IAAI;KACd,CAAA;AACH,CAAC;AAED,oEAAoE;AACpE,MAAM,UAAU,gBAAgB,CAAC,KAAuB;IACtD,OAAO;QACL,OAAO,EAAE,KAAK,CAAC,EAAE,IAAI,EAAE;QACvB,IAAI,EAAE,KAAK,CAAC,IAAI,IAAI,IAAI;QACxB,yEAAyE;QACzE,MAAM,EAAE,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,SAAS;QAC/C,SAAS,EAAE,KAAK,CAAC,SAAS,IAAI,IAAI;QAClC,aAAa,EAAE,IAAI;QACnB,aAAa,EAAE,IAAI;QACnB,UAAU,EAAE,IAAI;QAChB,SAAS,EAAE,KAAK,CAAC,SAAS,IAAI,IAAI;QAClC,OAAO,EAAE,KAAK,CAAC,OAAO,IAAI,IAAI;KAC/B,CAAA;AACH,CAAC"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The engine contract's SDK-bound half: the reads whose REST contract differs from the client
|
|
3
|
+
* defaults (text-only endpoints, raw variable reads, the batch fallback) and the batch status.
|
|
4
|
+
* The pure rules (dates, filters, sorting, variable writes, incident recovery) live in
|
|
5
|
+
* `@miragon/pulse-engine-core`; this package stays a leaf and does not import it. The engine
|
|
6
|
+
* module's tools (`tools/`) and widget feeds (`data/`) take both from there (CLAUDE.md
|
|
7
|
+
* invariant 7).
|
|
8
|
+
*/
|
|
9
|
+
export { endedBatchReport, queuedBatch, runningBatchReport, type BatchReport, type BatchStatus, type QueuedBatch, } from "./batches.js";
|
|
10
|
+
export { fetchExternalTaskErrorDetails, fetchJobStacktrace, readBatch, readProcessInstanceVariables, readTaskVariables, type VariableMap, } from "./reads.js";
|
|
11
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/engine-contract/index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,OAAO,EACL,gBAAgB,EAChB,WAAW,EACX,kBAAkB,EAClB,KAAK,WAAW,EAChB,KAAK,WAAW,EAChB,KAAK,WAAW,GACjB,MAAM,cAAc,CAAA;AACrB,OAAO,EACL,6BAA6B,EAC7B,kBAAkB,EAClB,SAAS,EACT,4BAA4B,EAC5B,iBAAiB,EACjB,KAAK,WAAW,GACjB,MAAM,YAAY,CAAA"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The engine contract's SDK-bound half: the reads whose REST contract differs from the client
|
|
3
|
+
* defaults (text-only endpoints, raw variable reads, the batch fallback) and the batch status.
|
|
4
|
+
* The pure rules (dates, filters, sorting, variable writes, incident recovery) live in
|
|
5
|
+
* `@miragon/pulse-engine-core`; this package stays a leaf and does not import it. The engine
|
|
6
|
+
* module's tools (`tools/`) and widget feeds (`data/`) take both from there (CLAUDE.md
|
|
7
|
+
* invariant 7).
|
|
8
|
+
*/
|
|
9
|
+
export { endedBatchReport, queuedBatch, runningBatchReport, } from "./batches.js";
|
|
10
|
+
export { fetchExternalTaskErrorDetails, fetchJobStacktrace, readBatch, readProcessInstanceVariables, readTaskVariables, } from "./reads.js";
|
|
11
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/engine-contract/index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,OAAO,EACL,gBAAgB,EAChB,WAAW,EACX,kBAAkB,GAInB,MAAM,cAAc,CAAA;AACrB,OAAO,EACL,6BAA6B,EAC7B,kBAAkB,EAClB,SAAS,EACT,4BAA4B,EAC5B,iBAAiB,GAElB,MAAM,YAAY,CAAA"}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Engine reads whose REST contract differs from the client defaults, the
|
|
3
|
+
* ONE place `tools/` and `data/` take them from, so no call site can forget
|
|
4
|
+
* the override:
|
|
5
|
+
*
|
|
6
|
+
* - Text endpoints (`/job/{id}/stacktrace`, `/external-task/{id}/errorDetails`)
|
|
7
|
+
* produce ONLY `text/plain` and answer the client's default
|
|
8
|
+
* `Accept: application/json` with a 406 before the resource runs.
|
|
9
|
+
* - Runtime variable reads default to `deserializeValues=true`: the engine
|
|
10
|
+
* then deserializes every Object variable eagerly (one class missing on its
|
|
11
|
+
* classpath fails the WHOLE read with a 500) and renders Json variables as
|
|
12
|
+
* Jackson's view of the Spin node instead of their JSON. With `false`,
|
|
13
|
+
* Object/Json/Xml values come back as their serialized string + `valueInfo`,
|
|
14
|
+
* exactly the shape a variable write takes back.
|
|
15
|
+
*/
|
|
16
|
+
import type { Client } from "../generated/client/types.gen.js";
|
|
17
|
+
import type { VariableValueDto } from "../generated/types.gen.js";
|
|
18
|
+
import { type BatchReport } from "./batches.js";
|
|
19
|
+
export type VariableMap = Record<string, VariableValueDto>;
|
|
20
|
+
/**
|
|
21
|
+
* The exception stacktrace of a job; `null` when the job has none or no
|
|
22
|
+
* longer exists (404). Every other failure throws: the caller decides
|
|
23
|
+
* whether a missing stacktrace may degrade.
|
|
24
|
+
*/
|
|
25
|
+
export declare function fetchJobStacktrace(client: Client, jobId: string): Promise<string | null>;
|
|
26
|
+
/**
|
|
27
|
+
* The error details a worker reported for an external task (its
|
|
28
|
+
* `failedExternalTask` stacktrace); `null` when there are none or the task no
|
|
29
|
+
* longer exists (404). Every other failure throws.
|
|
30
|
+
*/
|
|
31
|
+
export declare function fetchExternalTaskErrorDetails(client: Client, externalTaskId: string): Promise<string | null>;
|
|
32
|
+
/** All variables of a process instance, serialized (see the module doc). */
|
|
33
|
+
export declare function readProcessInstanceVariables(client: Client, processInstanceId: string): Promise<VariableMap>;
|
|
34
|
+
/** All variables visible from a task, serialized (see the module doc). */
|
|
35
|
+
export declare function readTaskVariables(client: Client, taskId: string): Promise<VariableMap>;
|
|
36
|
+
/**
|
|
37
|
+
* Where a batch stands: the runtime statistics while it exists (counts incl.
|
|
38
|
+
* failed batch jobs), its history record once it ended. A batch neither
|
|
39
|
+
* holds is reported as an error: it never existed, or ended on an engine
|
|
40
|
+
* without batch history.
|
|
41
|
+
*/
|
|
42
|
+
export declare function readBatch(client: Client, batchId: string): Promise<BatchReport>;
|
|
43
|
+
//# sourceMappingURL=reads.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"reads.d.ts","sourceRoot":"","sources":["../../src/engine-contract/reads.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AACH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,kCAAkC,CAAA;AAS9D,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,2BAA2B,CAAA;AAEjE,OAAO,EAAwC,KAAK,WAAW,EAAE,MAAM,cAAc,CAAA;AAYrF,MAAM,MAAM,WAAW,GAAG,MAAM,CAAC,MAAM,EAAE,gBAAgB,CAAC,CAAA;AAiB1D;;;;GAIG;AACH,wBAAsB,kBAAkB,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAO9F;AAED;;;;GAIG;AACH,wBAAsB,6BAA6B,CACjD,MAAM,EAAE,MAAM,EACd,cAAc,EAAE,MAAM,GACrB,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CASxB;AAED,4EAA4E;AAC5E,wBAAgB,4BAA4B,CAC1C,MAAM,EAAE,MAAM,EACd,iBAAiB,EAAE,MAAM,GACxB,OAAO,CAAC,WAAW,CAAC,CAMtB;AAED,0EAA0E;AAC1E,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC,CAEtF;AAED;;;;;GAKG;AACH,wBAAsB,SAAS,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC,CAYrF"}
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import { getBatchStatistics, getExternalTaskErrorDetails, getHistoricBatch, getProcessInstanceVariables, getStacktrace, getTaskVariables, } from "../generated/sdk.gen.js";
|
|
2
|
+
import { EngineRequestError } from "../engine-error.js";
|
|
3
|
+
import { endedBatchReport, runningBatchReport } from "./batches.js";
|
|
4
|
+
/** Request options for a `text/plain`-only endpoint. */
|
|
5
|
+
const TEXT_PLAIN = { parseAs: "text", headers: { Accept: "text/plain" } };
|
|
6
|
+
/**
|
|
7
|
+
* The query the variable reads send. The rule's home is engine-core's `RAW_VARIABLES`; this leaf
|
|
8
|
+
* does not import engine-core, so its SDK reads restate the flag (the engine connector's wire
|
|
9
|
+
* tests hold every variable read to `deserializeValues=false`).
|
|
10
|
+
*/
|
|
11
|
+
const RAW_VARIABLES = { deserializeValues: false };
|
|
12
|
+
/**
|
|
13
|
+
* The client's "missing" rule: EVERY 404. Broader than engine-core's `isMissing`, which leaves
|
|
14
|
+
* out a 404 of the JAX-RS `NotFoundException` (no such endpoint: a wrong REST root) and of
|
|
15
|
+
* `QueryParamException`; so here a wrong REST root reads as "none". Kept as it is in a refactor:
|
|
16
|
+
* one rule for both is a behaviour change of its own.
|
|
17
|
+
*/
|
|
18
|
+
function isAnyNotFound(error) {
|
|
19
|
+
return error instanceof EngineRequestError && error.httpStatus === 404;
|
|
20
|
+
}
|
|
21
|
+
/** Engine text, `null` for an empty body (204, or a resource without one). */
|
|
22
|
+
function textOrNull(text) {
|
|
23
|
+
return typeof text === "string" && text.length > 0 ? text : null;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* The exception stacktrace of a job; `null` when the job has none or no
|
|
27
|
+
* longer exists (404). Every other failure throws: the caller decides
|
|
28
|
+
* whether a missing stacktrace may degrade.
|
|
29
|
+
*/
|
|
30
|
+
export async function fetchJobStacktrace(client, jobId) {
|
|
31
|
+
try {
|
|
32
|
+
return textOrNull(await getStacktrace({ client, path: { id: jobId }, ...TEXT_PLAIN }));
|
|
33
|
+
}
|
|
34
|
+
catch (error) {
|
|
35
|
+
if (isAnyNotFound(error))
|
|
36
|
+
return null;
|
|
37
|
+
throw error;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* The error details a worker reported for an external task (its
|
|
42
|
+
* `failedExternalTask` stacktrace); `null` when there are none or the task no
|
|
43
|
+
* longer exists (404). Every other failure throws.
|
|
44
|
+
*/
|
|
45
|
+
export async function fetchExternalTaskErrorDetails(client, externalTaskId) {
|
|
46
|
+
try {
|
|
47
|
+
return textOrNull(await getExternalTaskErrorDetails({ client, path: { id: externalTaskId }, ...TEXT_PLAIN }));
|
|
48
|
+
}
|
|
49
|
+
catch (error) {
|
|
50
|
+
if (isAnyNotFound(error))
|
|
51
|
+
return null;
|
|
52
|
+
throw error;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
/** All variables of a process instance, serialized (see the module doc). */
|
|
56
|
+
export function readProcessInstanceVariables(client, processInstanceId) {
|
|
57
|
+
return getProcessInstanceVariables({
|
|
58
|
+
client,
|
|
59
|
+
path: { id: processInstanceId },
|
|
60
|
+
query: RAW_VARIABLES,
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
/** All variables visible from a task, serialized (see the module doc). */
|
|
64
|
+
export function readTaskVariables(client, taskId) {
|
|
65
|
+
return getTaskVariables({ client, path: { id: taskId }, query: RAW_VARIABLES });
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Where a batch stands: the runtime statistics while it exists (counts incl.
|
|
69
|
+
* failed batch jobs), its history record once it ended. A batch neither
|
|
70
|
+
* holds is reported as an error: it never existed, or ended on an engine
|
|
71
|
+
* without batch history.
|
|
72
|
+
*/
|
|
73
|
+
export async function readBatch(client, batchId) {
|
|
74
|
+
const running = await getBatchStatistics({ client, query: { batchId } });
|
|
75
|
+
if (Array.isArray(running) && running[0])
|
|
76
|
+
return runningBatchReport(running[0]);
|
|
77
|
+
try {
|
|
78
|
+
return endedBatchReport(await getHistoricBatch({ client, path: { id: batchId } }));
|
|
79
|
+
}
|
|
80
|
+
catch (error) {
|
|
81
|
+
if (!isAnyNotFound(error))
|
|
82
|
+
throw error;
|
|
83
|
+
throw new Error(`Batch ${batchId} not found: no running batch has this id and the engine history holds no record of it`, { cause: error });
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
//# sourceMappingURL=reads.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"reads.js","sourceRoot":"","sources":["../../src/engine-contract/reads.ts"],"names":[],"mappings":"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"}
|