@camunda8/orchestration-cluster-api 10.0.0-alpha.30 → 10.0.0-alpha.32
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/CHANGELOG.md +21 -0
- package/README.md +153 -67
- package/dist/{index-CIGXnFfe.d.ts → CamundaClient-BRj4omSA.d.ts} +2094 -2204
- package/dist/{index-Cv5fK0gZ.d.cts → CamundaClient-D9CRR7D0.d.cts} +2094 -2204
- package/dist/{chunk-SHE5T54L.js → chunk-WHBUDCPU.js} +10 -140
- package/dist/chunk-WHBUDCPU.js.map +1 -0
- package/dist/{fp → effect}/index.cjs +309 -117
- package/dist/effect/index.cjs.map +1 -0
- package/dist/effect/index.d.cts +258 -0
- package/dist/effect/index.d.ts +258 -0
- package/dist/effect/index.js +330 -0
- package/dist/effect/index.js.map +1 -0
- package/dist/index.cjs +9 -61
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +85 -20
- package/dist/index.d.ts +85 -20
- package/dist/index.js +2 -8
- package/dist/index.js.map +1 -1
- package/dist/{zod.gen-CGU4FBRF.js → zod.gen-2LVIU5XR.js} +2 -2
- package/dist/{zod.gen-CGU4FBRF.js.map → zod.gen-2LVIU5XR.js.map} +1 -1
- package/package.json +11 -11
- package/dist/chunk-SHE5T54L.js.map +0 -1
- package/dist/fp/index.cjs.map +0 -1
- package/dist/fp/index.d.cts +0 -3
- package/dist/fp/index.d.ts +0 -3
- package/dist/fp/index.js +0 -23
- package/dist/fp/index.js.map +0 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,24 @@
|
|
|
1
|
+
# [10.0.0-alpha.32](https://github.com/camunda/orchestration-cluster-api-js/compare/v10.0.0-alpha.31...v10.0.0-alpha.32) (2026-08-20)
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
### Features
|
|
5
|
+
|
|
6
|
+
* **effect:** Effect-native job-worker surface ([#444](https://github.com/camunda/orchestration-cluster-api-js/issues/444)) ([754c096](https://github.com/camunda/orchestration-cluster-api-js/commit/754c09625a930ff6507e7a5f0e6f0a050f80175e)), closes [#437](https://github.com/camunda/orchestration-cluster-api-js/issues/437) [#438](https://github.com/camunda/orchestration-cluster-api-js/issues/438)
|
|
7
|
+
|
|
8
|
+
# [10.0.0-alpha.31](https://github.com/camunda/orchestration-cluster-api-js/compare/v10.0.0-alpha.30...v10.0.0-alpha.31) (2026-08-20)
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
### Features
|
|
12
|
+
|
|
13
|
+
* **effect:** first-class Effect v4 surface, clean cut from experimental /fp ([#440](https://github.com/camunda/orchestration-cluster-api-js/issues/440)) ([04d2bd1](https://github.com/camunda/orchestration-cluster-api-js/commit/04d2bd1452e9196fb337deb2ecf50b3c5d179bf4)), closes [#437](https://github.com/camunda/orchestration-cluster-api-js/issues/437) [#437](https://github.com/camunda/orchestration-cluster-api-js/issues/437)
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
### BREAKING CHANGES
|
|
17
|
+
|
|
18
|
+
* **effect:** the experimental `/fp` subpath and its `fp-ts` optional peer are
|
|
19
|
+
removed. Migrate to `./effect` and install the optional `effect` (v4) peer; the
|
|
20
|
+
main `.` entry and its Promise-based API are unchanged.
|
|
21
|
+
|
|
1
22
|
# [10.0.0-alpha.30](https://github.com/camunda/orchestration-cluster-api-js/compare/v10.0.0-alpha.29...v10.0.0-alpha.30) (2026-08-20)
|
|
2
23
|
|
|
3
24
|
|
package/README.md
CHANGED
|
@@ -1250,67 +1250,164 @@ Notes:
|
|
|
1250
1250
|
- Cancellation classification runs first so aborted fetches are never downgraded to generic network errors.
|
|
1251
1251
|
- Abort is immediate and idempotent; underlying fetch is signalled.
|
|
1252
1252
|
|
|
1253
|
-
##
|
|
1253
|
+
## Effect Surface (Opt-In Subpath)
|
|
1254
1254
|
|
|
1255
|
-
|
|
1255
|
+
The main entry stays Promise-based and pulls in **zero** Effect at runtime. Opt in to a
|
|
1256
|
+
first-class [Effect](https://effect.website) surface — a client whose every method returns an
|
|
1257
|
+
`Effect`, tagged domain errors, and Effect-native combinators — by importing the dedicated
|
|
1258
|
+
`./effect` subpath.
|
|
1256
1259
|
|
|
1257
|
-
> **Peer dependency:** `
|
|
1258
|
-
>
|
|
1260
|
+
> **Peer dependency:** `effect` is an **optional peer dependency** (Effect **v4**). The `./effect`
|
|
1261
|
+
> subpath requires it; install it alongside the SDK:
|
|
1259
1262
|
> ```sh
|
|
1260
|
-
> npm install
|
|
1263
|
+
> npm install effect
|
|
1261
1264
|
> ```
|
|
1262
|
-
> The
|
|
1263
|
-
>
|
|
1264
|
-
|
|
1265
|
-
|
|
1265
|
+
> The main `.` entry never imports `effect`, so Promise-first users are never forced to adopt it.
|
|
1266
|
+
>
|
|
1267
|
+
> **Module resolution:** Effect v4 ships as an `exports`-map-only package (no legacy
|
|
1268
|
+
> `main`/`types`), so consuming the `./effect` types requires a modern TypeScript module
|
|
1269
|
+
> resolution — set `"moduleResolution": "bundler"` (or `"node16"`/`"nodenext"`) in your
|
|
1270
|
+
> `tsconfig.json`. The Promise-first `.` entry is unaffected.
|
|
1266
1271
|
|
|
1267
|
-
<!-- snippet-exempt: uses SDK /
|
|
1272
|
+
<!-- snippet-exempt: uses SDK /effect subpath + optional effect peer not available in examples project -->
|
|
1268
1273
|
```ts
|
|
1274
|
+
import { Effect } from 'effect';
|
|
1269
1275
|
import {
|
|
1270
|
-
|
|
1271
|
-
|
|
1272
|
-
|
|
1273
|
-
|
|
1274
|
-
|
|
1275
|
-
|
|
1276
|
-
|
|
1277
|
-
const
|
|
1278
|
-
const
|
|
1279
|
-
const
|
|
1280
|
-
|
|
1276
|
+
createCamundaEffectClient,
|
|
1277
|
+
eventually,
|
|
1278
|
+
EventualConsistencyTimeout,
|
|
1279
|
+
} from '@camunda8/orchestration-cluster-api/effect';
|
|
1280
|
+
|
|
1281
|
+
const camunda = createCamundaEffectClient();
|
|
1282
|
+
|
|
1283
|
+
const program = Effect.gen(function* () {
|
|
1284
|
+
const deployment = yield* camunda.deployResourcesFromFiles(['./bpmn/process.bpmn']);
|
|
1285
|
+
const { processInstanceKey } = yield* camunda.createProcessInstance({
|
|
1286
|
+
processDefinitionKey: deployment.processes[0].processDefinitionKey,
|
|
1287
|
+
});
|
|
1288
|
+
// Poll on the Effect Clock until the instance is searchable, timing out deterministically.
|
|
1289
|
+
// waitUpToMs: 0 asks the SDK for the latest available state without its own wall-clock
|
|
1290
|
+
// wait, so the Effect `eventually` combinator owns the predicate + timeout horizon —
|
|
1291
|
+
// making the eventual-consistency wait deterministic under TestClock.
|
|
1292
|
+
const search = yield* eventually(
|
|
1293
|
+
camunda.searchProcessInstances(
|
|
1294
|
+
{ filter: { processInstanceKey } },
|
|
1295
|
+
{ consistency: { waitUpToMs: 0 } }
|
|
1296
|
+
),
|
|
1297
|
+
(s) => s.items.some((i) => i.processInstanceKey === processInstanceKey),
|
|
1298
|
+
{ waitUpTo: '30 seconds', interval: '750 millis' }
|
|
1299
|
+
);
|
|
1300
|
+
return { processInstanceKey, search };
|
|
1301
|
+
}).pipe(
|
|
1302
|
+
// Tagged errors → discriminate with catchTag / catchTags instead of a manual switch.
|
|
1303
|
+
Effect.catchTag('EventualConsistencyTimeout', (e: EventualConsistencyTimeout) =>
|
|
1304
|
+
Effect.logError(`Timed out: ${e.message}`).pipe(Effect.andThen(Effect.fail(e)))
|
|
1305
|
+
)
|
|
1306
|
+
);
|
|
1281
1307
|
|
|
1282
|
-
|
|
1283
|
-
// import { pipe } from 'fp-ts/function'; import * as TE from 'fp-ts/TaskEither';
|
|
1308
|
+
const result = await Effect.runPromise(program);
|
|
1284
1309
|
```
|
|
1285
1310
|
|
|
1286
1311
|
Why a subpath?
|
|
1287
1312
|
|
|
1288
|
-
- Keeps base bundle lean for the 80% use case.
|
|
1289
|
-
- No
|
|
1290
|
-
-
|
|
1313
|
+
- Keeps the base bundle lean for the Promise-first 80% use case.
|
|
1314
|
+
- No dependency on `effect` at runtime unless you opt in; it is an **optional** peer.
|
|
1315
|
+
- Unlocks the Effect ecosystem (typed errors, `Schedule`, `Layer`/`Context`, `TestClock`).
|
|
1316
|
+
|
|
1317
|
+
Exports available from `.../effect`:
|
|
1318
|
+
|
|
1319
|
+
- `createCamundaEffectClient(options?)` – a `Proxy` client where every method returns
|
|
1320
|
+
`Effect.Effect<Awaited<R>, DomainError, never>`; the throwing client is reachable via `.inner`.
|
|
1321
|
+
- Tagged errors (`Data.TaggedError`): `CamundaValidationError`, `EventualConsistencyTimeout`,
|
|
1322
|
+
`HttpError`, `CamundaGenericError` — together the `DomainError` union. Discriminate with
|
|
1323
|
+
`Effect.catchTag` / `Effect.catchTags`.
|
|
1324
|
+
- Combinators: `retryWithBackoff` (`Effect.retry` + `Schedule.exponential` + jitter), `withTimeout`
|
|
1325
|
+
(`Effect.timeoutOrElse` with real interruption), `eventually` (a recursive `Effect.sleep` poll on
|
|
1326
|
+
the Effect `Clock`, timing out to `EventualConsistencyTimeout`).
|
|
1327
|
+
- Dependency injection: `CamundaEffect` (`Context.Service`) + `layer(options?)` (`Layer`) so worker /
|
|
1328
|
+
orchestration code composes via `Layer` and swaps a test double trivially.
|
|
1329
|
+
|
|
1330
|
+
**Clock-class win:** `eventually` / `withTimeout` run on the Effect `Clock`, so `TestClock.adjust`
|
|
1331
|
+
advances eventual/timeout deterministically in tests — no real-clock burn.
|
|
1332
|
+
|
|
1333
|
+
### Effect Job Workers
|
|
1334
|
+
|
|
1335
|
+
The same subpath also exposes an **Effect-native job worker** — the long-running
|
|
1336
|
+
`activateJobs` → handle → `completeJob`/`failJob` loop, modelled as Effect. A handler is
|
|
1337
|
+
`(job) => Effect.Effect<CompleteVars, JobError, R>` with a **typed failure channel**: a
|
|
1338
|
+
`RetryableJobError` becomes `failJob` with `retries - 1` (plus an optional server-side backoff),
|
|
1339
|
+
and a `TerminalJobError` becomes `throwJobError` (caught by a BPMN error boundary, or an incident if
|
|
1340
|
+
uncaught). Success completes the job with the returned variables. It composes over the same
|
|
1341
|
+
activation/backpressure runtime the Promise worker uses — it does not reimplement activation.
|
|
1342
|
+
|
|
1343
|
+
<!-- snippet-exempt: uses SDK /effect subpath + optional effect peer not available in examples project -->
|
|
1344
|
+
```ts
|
|
1345
|
+
import { Effect, Schedule } from 'effect';
|
|
1346
|
+
import {
|
|
1347
|
+
createCamundaEffectWorker,
|
|
1348
|
+
layer,
|
|
1349
|
+
RetryableJobError,
|
|
1350
|
+
TerminalJobError,
|
|
1351
|
+
} from '@camunda8/orchestration-cluster-api/effect';
|
|
1352
|
+
|
|
1353
|
+
const program = Effect.gen(function* () {
|
|
1354
|
+
// Forked into the current Scope: interrupted (with a best-effort lease release) when
|
|
1355
|
+
// the scope closes.
|
|
1356
|
+
yield* createCamundaEffectWorker<{ ok: boolean }>({
|
|
1357
|
+
type: 'payment-processing',
|
|
1358
|
+
maxJobsToActivate: 10, // activation batch size
|
|
1359
|
+
concurrency: 10, // max jobs handled in parallel (backpressure)
|
|
1360
|
+
pollInterval: '1 second', // between empty polls, on the Effect Clock
|
|
1361
|
+
// Optional: retry the handler in-process on a RetryableJobError before failing the job.
|
|
1362
|
+
handlerRetrySchedule: Schedule.spaced('2 seconds'),
|
|
1363
|
+
handler: (job) =>
|
|
1364
|
+
Effect.gen(function* () {
|
|
1365
|
+
if (!job.variables.amount) {
|
|
1366
|
+
// Terminal → raise a BPMN error / incident.
|
|
1367
|
+
return yield* Effect.fail(
|
|
1368
|
+
new TerminalJobError({ code: 'INVALID_INPUT', message: 'amount is required' })
|
|
1369
|
+
);
|
|
1370
|
+
}
|
|
1371
|
+
if (yield* isServiceDown()) {
|
|
1372
|
+
// Retryable → failJob(retries - 1) with a re-activation backoff.
|
|
1373
|
+
return yield* Effect.fail(
|
|
1374
|
+
new RetryableJobError({ message: 'downstream unavailable', retryBackoff: '5 seconds' })
|
|
1375
|
+
);
|
|
1376
|
+
}
|
|
1377
|
+
return { ok: true }; // success → completeJob(variables)
|
|
1378
|
+
}),
|
|
1379
|
+
});
|
|
1380
|
+
|
|
1381
|
+
// ... the worker runs for the lifetime of this scope.
|
|
1382
|
+
yield* Effect.never;
|
|
1383
|
+
}).pipe(
|
|
1384
|
+
Effect.scoped,
|
|
1385
|
+
Effect.provide(layer()) // provides the `/effect` client the worker depends on
|
|
1386
|
+
);
|
|
1291
1387
|
|
|
1292
|
-
|
|
1388
|
+
void program;
|
|
1389
|
+
```
|
|
1293
1390
|
|
|
1294
|
-
|
|
1295
|
-
- Type guards: `isLeft`, `isRight`.
|
|
1296
|
-
- Error / type aliases: `DomainError`, `TaskEither`, `Either`, `Left`, `Right`, `Fpify`.
|
|
1297
|
-
- Combinators: `retryTE`, `withTimeoutTE`, `eventuallyTE`.
|
|
1391
|
+
Worker exports from `.../effect`:
|
|
1298
1392
|
|
|
1299
|
-
|
|
1393
|
+
- `createCamundaEffectWorker(config)` – forks the worker into the current `Scope` and returns a
|
|
1394
|
+
handle (`{ type, join, interrupt }`); provide the client `layer()` as its dependency.
|
|
1395
|
+
- `activateJobsStream(type, options)` – the lower-level `Stream.Stream<Job, DomainError, …>` of
|
|
1396
|
+
activated jobs, polling on the Effect `Clock`.
|
|
1397
|
+
- `workerLayer(config)` – a `Layer` that runs a worker for the layer's lifetime.
|
|
1398
|
+
- Tagged job failures: `RetryableJobError` (→ `failJob`), `TerminalJobError` (→ `throwJobError`),
|
|
1399
|
+
together the `JobError` channel.
|
|
1300
1400
|
|
|
1301
|
-
- `
|
|
1302
|
-
|
|
1303
|
-
|
|
1304
|
-
- Generic `Error`
|
|
1305
|
-
|
|
1306
|
-
You can refine left-channel typing later by mapping HTTP status codes or discriminator fields.
|
|
1401
|
+
**Clock-class win:** the activation poll interval and the handler-retry `Schedule` run on the Effect
|
|
1402
|
+
`Clock`, so `TestClock.adjust` bounds activation/retry timing in virtual time — the whole loop is
|
|
1403
|
+
deterministic in tests, with no real-clock burn.
|
|
1307
1404
|
|
|
1308
1405
|
## Eventual Consistency Polling
|
|
1309
1406
|
|
|
1310
1407
|
Some endpoints accept consistency management options. Pass a `consistency` block (where supported) with `waitUpToMs` and optional `pollIntervalMs` (default 500). If the condition is not met within timeout an `EventualConsistencyTimeoutError` is thrown.
|
|
1311
1408
|
|
|
1312
1409
|
To consume eventual polling in a non‑throwing fashion set the client error mode before invoking an eventually consistent method:
|
|
1313
|
-
At present the canonical client operates in throwing mode. Non‑throwing adaptation (Result /
|
|
1410
|
+
At present the canonical client operates in throwing mode. Non‑throwing adaptation (Result / Effect) is achieved via the functional wrappers rather than mutating the base client.
|
|
1314
1411
|
|
|
1315
1412
|
### Options
|
|
1316
1413
|
|
|
@@ -1589,43 +1686,32 @@ When to use:
|
|
|
1589
1686
|
- Avoiding try/catch nesting in larger orchestration flows.
|
|
1590
1687
|
- Converting to libraries expecting an Either/Result pattern.
|
|
1591
1688
|
|
|
1592
|
-
###
|
|
1593
|
-
|
|
1594
|
-
_Note that this feature is experimental and subject to change._
|
|
1689
|
+
### Effect Adapter
|
|
1595
1690
|
|
|
1596
|
-
For projects
|
|
1691
|
+
For Effect-based projects, wrap the throwing client in an Effect-flavoured facade whose every method
|
|
1692
|
+
returns an `Effect` with a typed `DomainError` channel:
|
|
1597
1693
|
|
|
1598
|
-
<!-- snippet-exempt: requires
|
|
1694
|
+
<!-- snippet-exempt: requires optional effect peer dependency -->
|
|
1599
1695
|
```ts
|
|
1600
|
-
import {
|
|
1601
|
-
import {
|
|
1602
|
-
import * as TE from 'fp-ts/TaskEither';
|
|
1603
|
-
|
|
1604
|
-
const fp = createCamundaFpClient();
|
|
1696
|
+
import { Effect } from 'effect';
|
|
1697
|
+
import { createCamundaEffectClient } from '@camunda8/orchestration-cluster-api/effect';
|
|
1605
1698
|
|
|
1606
|
-
const
|
|
1699
|
+
const camunda = createCamundaEffectClient();
|
|
1607
1700
|
|
|
1608
|
-
|
|
1609
|
-
|
|
1610
|
-
(then) => then // typical usage would use TE.match / TE.fold; shown expanded for clarity
|
|
1701
|
+
const deployment = await Effect.runPromise(
|
|
1702
|
+
camunda.createDeployment({ resources: [file] })
|
|
1611
1703
|
);
|
|
1612
|
-
|
|
1613
|
-
// With helpers
|
|
1614
|
-
const task = fp.createDeployment({ resources: [file] });
|
|
1615
|
-
const either = await task();
|
|
1616
|
-
if (either._tag === 'Right') {
|
|
1617
|
-
console.log(either.right.deployments.length);
|
|
1618
|
-
} else {
|
|
1619
|
-
console.error('Error', either.left);
|
|
1620
|
-
}
|
|
1704
|
+
console.log(deployment.deployments.length);
|
|
1621
1705
|
```
|
|
1622
1706
|
|
|
1707
|
+
See [Effect Surface (Opt-In Subpath)](#effect-surface-opt-in-subpath) above for the full surface —
|
|
1708
|
+
tagged errors, `retryWithBackoff` / `withTimeout` / `eventually`, and `Layer`/`Context` DI.
|
|
1709
|
+
|
|
1623
1710
|
Notes:
|
|
1624
1711
|
|
|
1625
|
-
-
|
|
1626
|
-
- Each method
|
|
1627
|
-
-
|
|
1628
|
-
- For richer interop, you can map the returned factory to `TE.tryCatch` in userland.
|
|
1712
|
+
- `effect` is an **optional peer dependency**; only the `./effect` subpath imports it.
|
|
1713
|
+
- Each method returns `Effect.Effect<Awaited<R>, DomainError, never>`; the throwing client is reachable via `.inner`.
|
|
1714
|
+
- Failures are narrowed into tagged errors so you discriminate with `Effect.catchTag` / `catchTags`.
|
|
1629
1715
|
|
|
1630
1716
|
## Pagination
|
|
1631
1717
|
|
|
@@ -1748,7 +1834,7 @@ Generate an HTML API reference site with TypeDoc (public entry points only):
|
|
|
1748
1834
|
npm run docs:api
|
|
1749
1835
|
```
|
|
1750
1836
|
|
|
1751
|
-
Output: static site in `docs/api` (open `docs/api/index.html` in a browser or serve the folder, e.g. `npx http-server docs/api`). Entry points: `src/index.ts`, `src/logger.ts`, `src/
|
|
1837
|
+
Output: static site in `docs/api` (open `docs/api/index.html` in a browser or serve the folder, e.g. `npx http-server docs/api`). Entry points: `src/index.ts`, `src/logger.ts`, `src/effect/index.ts`. Internal generated code, scripts, tests are excluded and private / protected members are filtered. Regenerate after changing public exports.
|
|
1752
1838
|
|
|
1753
1839
|
## Contributing
|
|
1754
1840
|
|