@inhuman.tools/plexus-expectations 0.0.0-stage → 0.2.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.md +7 -0
- package/README.md +144 -2
- package/dist/driver/ExpectationActor.d.ts +56 -0
- package/dist/driver/ExpectationActor.d.ts.map +1 -0
- package/dist/driver/ExpectationActor.js +210 -0
- package/dist/driver/ExpectationActor.js.map +1 -0
- package/dist/driver/PEWDriver.d.ts +144 -0
- package/dist/driver/PEWDriver.d.ts.map +1 -0
- package/dist/driver/PEWDriver.js +303 -0
- package/dist/driver/PEWDriver.js.map +1 -0
- package/dist/driver/actor-machine.d.ts +28 -0
- package/dist/driver/actor-machine.d.ts.map +1 -0
- package/dist/driver/actor-machine.js +50 -0
- package/dist/driver/actor-machine.js.map +1 -0
- package/dist/driver/connection-miss.d.ts +9 -0
- package/dist/driver/connection-miss.d.ts.map +1 -0
- package/dist/driver/connection-miss.js +13 -0
- package/dist/driver/connection-miss.js.map +1 -0
- package/dist/driver/index.d.ts +6 -0
- package/dist/driver/index.d.ts.map +1 -0
- package/dist/driver/index.js +5 -0
- package/dist/driver/index.js.map +1 -0
- package/dist/executor/index.d.ts +4 -0
- package/dist/executor/index.d.ts.map +1 -0
- package/dist/executor/index.js +4 -0
- package/dist/executor/index.js.map +1 -0
- package/dist/executor/kernel-intern.d.ts +16 -0
- package/dist/executor/kernel-intern.d.ts.map +1 -0
- package/dist/executor/kernel-intern.js +98 -0
- package/dist/executor/kernel-intern.js.map +1 -0
- package/dist/executor/orchestrator.d.ts +97 -0
- package/dist/executor/orchestrator.d.ts.map +1 -0
- package/dist/executor/orchestrator.js +465 -0
- package/dist/executor/orchestrator.js.map +1 -0
- package/dist/executor/types.d.ts +8 -0
- package/dist/executor/types.d.ts.map +1 -0
- package/dist/executor/types.js +2 -0
- package/dist/executor/types.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -0
- package/dist/schemas/connection.d.ts +4 -0
- package/dist/schemas/connection.d.ts.map +1 -0
- package/dist/schemas/connection.js +4 -0
- package/dist/schemas/connection.js.map +1 -0
- package/dist/schemas/index.d.ts +2 -0
- package/dist/schemas/index.d.ts.map +1 -0
- package/dist/schemas/index.js +2 -0
- package/dist/schemas/index.js.map +1 -0
- package/dist/shared/control.d.ts +4 -0
- package/dist/shared/control.d.ts.map +1 -0
- package/dist/shared/control.js +2 -0
- package/dist/shared/control.js.map +1 -0
- package/dist/shared/index.d.ts +7 -0
- package/dist/shared/index.d.ts.map +1 -0
- package/dist/shared/index.js +7 -0
- package/dist/shared/index.js.map +1 -0
- package/dist/shared/map-field-awareness.d.ts +19 -0
- package/dist/shared/map-field-awareness.d.ts.map +1 -0
- package/dist/shared/map-field-awareness.js +58 -0
- package/dist/shared/map-field-awareness.js.map +1 -0
- package/dist/shared/models/ConnectionSpec.d.ts +44 -0
- package/dist/shared/models/ConnectionSpec.d.ts.map +1 -0
- package/dist/shared/models/ConnectionSpec.js +180 -0
- package/dist/shared/models/ConnectionSpec.js.map +1 -0
- package/dist/shared/models/DriverSpec.d.ts +45 -0
- package/dist/shared/models/DriverSpec.d.ts.map +1 -0
- package/dist/shared/models/DriverSpec.js +221 -0
- package/dist/shared/models/DriverSpec.js.map +1 -0
- package/dist/shared/models/Job.d.ts +85 -0
- package/dist/shared/models/Job.d.ts.map +1 -0
- package/dist/shared/models/Job.js +261 -0
- package/dist/shared/models/Job.js.map +1 -0
- package/dist/shared/models/WorkContainer.d.ts +36 -0
- package/dist/shared/models/WorkContainer.d.ts.map +1 -0
- package/dist/shared/models/WorkContainer.js +140 -0
- package/dist/shared/models/WorkContainer.js.map +1 -0
- package/dist/shared/models/WorkExpectation.d.ts +63 -0
- package/dist/shared/models/WorkExpectation.d.ts.map +1 -0
- package/dist/shared/models/WorkExpectation.js +290 -0
- package/dist/shared/models/WorkExpectation.js.map +1 -0
- package/dist/shared/models/index.d.ts +7 -0
- package/dist/shared/models/index.d.ts.map +1 -0
- package/dist/shared/models/index.js +6 -0
- package/dist/shared/models/index.js.map +1 -0
- package/dist/shared/models/jsonRecord.d.ts +14 -0
- package/dist/shared/models/jsonRecord.d.ts.map +1 -0
- package/dist/shared/models/jsonRecord.js +46 -0
- package/dist/shared/models/jsonRecord.js.map +1 -0
- package/dist/shared/revalidation-demand.d.ts +27 -0
- package/dist/shared/revalidation-demand.d.ts.map +1 -0
- package/dist/shared/revalidation-demand.js +116 -0
- package/dist/shared/revalidation-demand.js.map +1 -0
- package/dist/shared/role.d.ts +12 -0
- package/dist/shared/role.d.ts.map +1 -0
- package/dist/shared/role.js +21 -0
- package/dist/shared/role.js.map +1 -0
- package/dist/shared/types.d.ts +43 -0
- package/dist/shared/types.d.ts.map +1 -0
- package/dist/shared/types.js +12 -0
- package/dist/shared/types.js.map +1 -0
- package/package.json +79 -3
- package/src/driver/ExpectationActor.ts +244 -0
- package/src/driver/PEWDriver.ts +302 -0
- package/src/driver/actor-machine.ts +54 -0
- package/src/driver/connection-miss.ts +13 -0
- package/src/driver/index.ts +5 -0
- package/src/executor/index.ts +3 -0
- package/src/executor/kernel-intern.ts +121 -0
- package/src/executor/orchestrator.ts +463 -0
- package/src/executor/types.ts +3 -0
- package/src/index.ts +1 -0
- package/src/schemas/connection.ts +4 -0
- package/src/schemas/index.ts +1 -0
- package/src/shared/control.ts +4 -0
- package/src/shared/index.ts +6 -0
- package/src/shared/map-field-awareness.ts +65 -0
- package/src/shared/models/ConnectionSpec.ts +84 -0
- package/src/shared/models/DriverSpec.ts +102 -0
- package/src/shared/models/Job.ts +192 -0
- package/src/shared/models/WorkContainer.ts +90 -0
- package/src/shared/models/WorkExpectation.ts +229 -0
- package/src/shared/models/index.ts +6 -0
- package/src/shared/models/jsonRecord.ts +49 -0
- package/src/shared/revalidation-demand.ts +121 -0
- package/src/shared/role.ts +32 -0
- package/src/shared/types.ts +57 -0
package/LICENSE.md
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
Copyright 2026 Merkle Bonsai
|
|
2
|
+
|
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
|
4
|
+
|
|
5
|
+
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
|
6
|
+
|
|
7
|
+
THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,3 +1,145 @@
|
|
|
1
|
-
#
|
|
1
|
+
# PEW — Plexus Expectation Workflow
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
**Package:** `@inhuman.tools/plexus-expectations`
|
|
4
|
+
|
|
5
|
+
Durable work on Plexus documents. One noun for open work — **Expectation** (harness docs: **PEW/Expectation**) — demand with an
|
|
6
|
+
outcome. The entity itself is the whole API: the claim-owner host writes PEW/Expectation bodies (Client queues the named action);
|
|
7
|
+
observers read it; Actors honor it; the process holding the live PEW/Connection starts or declines it.
|
|
8
|
+
|
|
9
|
+
This README is the contract.
|
|
10
|
+
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
## Three entry points, three roles
|
|
14
|
+
|
|
15
|
+
| Import | Role | Contents |
|
|
16
|
+
| ------------------------------------ | ------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------- |
|
|
17
|
+
| `@inhuman.tools/plexus-expectations` | **Vocabulary** — any process holding the doc (claim-owner host, observers, UIs) | `WorkExpectation`, `Job`, `WorkContainer`, `ConnectionSpec`, `DriverSpec`, outcome type |
|
|
18
|
+
| `…/driver` | **Fulfillment** — PEW/Driver packages | `PEWDriver`, `ExpectationActor`, bootstrap contexts |
|
|
19
|
+
| `…/executor` | **Supervision** — the process that has the live connections | `Orchestrator` (PEW honor + Job executors; plus everything in `/driver`) |
|
|
20
|
+
|
|
21
|
+
Observers and claim-owner hosts never import `/executor`; driver packages never need it either.
|
|
22
|
+
|
|
23
|
+
---
|
|
24
|
+
|
|
25
|
+
## The entity is the API
|
|
26
|
+
|
|
27
|
+
Live `report` is the scan; settlement is the `outcome` / `outcomeReport` write on the entity; the next read is instant.
|
|
28
|
+
|
|
29
|
+
Everything scoped to a unit of work lives on the `Expectation` model — there is no client
|
|
30
|
+
object, no session parameter, and a cross-session mistake is unrepresentable (the entity locates
|
|
31
|
+
its own document, plexus, and PEW/Awareness):
|
|
32
|
+
|
|
33
|
+
| Face | Surface |
|
|
34
|
+
| ----------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
35
|
+
| **Author** (claim-owner host, not Client) | `new Kind({ …fields })` — the subclass fields ARE the request |
|
|
36
|
+
| **Observer** | `await E` (settles with `"successful"` / `"failed"` when `isDone`; `failed` fulfills), `E.outcome` (`null` / `successful` / `failed`), `E.workerPresent`, `E.report` (outcome frame or live awareness), `E.endCause` / `E.endDetail`; catalog liveness is process-local on the spec entities' `.readyState` / `.live` |
|
|
37
|
+
| **Actor** | `this.expectation` (the request), `this.signal`, `admitTermination()`, `report()` / `complete()` / `fail()`; `ConnectionNotReady` / `DemandIncomplete` from `run()` settle fail, not crash |
|
|
38
|
+
| **Connection** | leftover attach PEW is honored; new work is kicked from origin (`complete` / Job BODY interned methods); catalog drivers load themselves; `PEWDriver.handle` remains the leftover door |
|
|
39
|
+
|
|
40
|
+
Role occupancy is one `role:expectations` map keyed by uuid. A role write requires a
|
|
41
|
+
doc-homed entity — occupancy not propagated over awareness is no occupancy, so
|
|
42
|
+
touching the role map on an unhomed entity throws loudly rather than publishing
|
|
43
|
+
into the void.
|
|
44
|
+
|
|
45
|
+
### Outcome
|
|
46
|
+
|
|
47
|
+
```text
|
|
48
|
+
null = not done
|
|
49
|
+
successful = done as expected
|
|
50
|
+
failed = done otherwise (error, crash, cancel)
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
There is no expectation state machine and no durable `running`. "Someone is working
|
|
54
|
+
to satisfy this" is actor presence (`workerPresent` / the role map), gone when the
|
|
55
|
+
teller goes. Last progress this process saw stays on `progressAwareness` after the
|
|
56
|
+
uuid retracts. The writers `succeed` / `fail` are first-writer-wins (`fail` with
|
|
57
|
+
`endCause: cancel` is how cancel is recorded). `connection` on the expectation and
|
|
58
|
+
`driver` on the connection are required — a missing field is a host bug, not an
|
|
59
|
+
outcome. Every ending carries `endCause` (`settled` | `cancel` | `crash`) and
|
|
60
|
+
`outcomeReport`.
|
|
61
|
+
|
|
62
|
+
Cancel is host-owned: `admitTermination()` on a live actor, or `fail("cancel", …)` when
|
|
63
|
+
nobody is working. No acks, no epochs, no kernel hop.
|
|
64
|
+
|
|
65
|
+
### Endings are observed, never imposed
|
|
66
|
+
|
|
67
|
+
There is no fold. Endings are `succeed` / `fail` writes — the actor on its own settlement,
|
|
68
|
+
or host `admitTermination` (a settlement captured before admission outranks the cancel).
|
|
69
|
+
The actor keeps one reaction on its entity's `isDone`: however the ending arrived — local
|
|
70
|
+
settlement, admitted cancel, a peer's write — the process duties are identical: abort the
|
|
71
|
+
signal, leave. Children of a done parent are skipped by honor (`isTreeOrphan`), not ended
|
|
72
|
+
by a cascade from the parent's stack frame.
|
|
73
|
+
|
|
74
|
+
---
|
|
75
|
+
|
|
76
|
+
## Extending: kinds and drivers
|
|
77
|
+
|
|
78
|
+
**Work vocabulary is global.** A product ships `Expectation` subclasses; the `@syncing` registry
|
|
79
|
+
tag IS the kind — derived, never declared. The subclass is the single type carrier:
|
|
80
|
+
|
|
81
|
+
```ts
|
|
82
|
+
@syncing("myapp:tool_call")
|
|
83
|
+
class ToolCallExpectation extends Expectation<ToolResult, ToolReport> {
|
|
84
|
+
@syncing accessor name = "";
|
|
85
|
+
@syncing accessor argsJson = "{}";
|
|
86
|
+
|
|
87
|
+
override applySettlement(result: ToolResult): void {
|
|
88
|
+
/* typed product-field writes */
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
`ResultOf` / `ReportOf` extract the shapes.
|
|
94
|
+
|
|
95
|
+
**PEW/Driver is claim, not invent — and the claim lives on the catalog, never on code.**
|
|
96
|
+
`DriverSpec.can: string[]` is the durable claim surface ("this driver handles these
|
|
97
|
+
kinds") — expectation model names, elevated through the process-global `@syncing` class registry.
|
|
98
|
+
Dynamically loaded driver code does not get to declare its own authority.
|
|
99
|
+
|
|
100
|
+
**The loaded class is `PEWDriver`. The instance is the connection.** `DriverSpec` and `ConnectionSpec` stay the inventory rows. A driver module's default export is
|
|
101
|
+
a `PEWDriver` subclass: the static side is code identity (`pewBrand`, `offers`),
|
|
102
|
+
each instance is one live connection (its own gated `bootstrap()`), and `resolve(expectation)`
|
|
103
|
+
mints the actor — which may be a connection-specialized `ExpectationActor` subclass holding the
|
|
104
|
+
live runtime directly:
|
|
105
|
+
|
|
106
|
+
```ts
|
|
107
|
+
export default class MyDriverConnection extends PEWDriver<ToolCallExpectation> {
|
|
108
|
+
static override configurationSchema = z.object({ token: z.string() });
|
|
109
|
+
static offers = [];
|
|
110
|
+
|
|
111
|
+
override async bootstrap() {
|
|
112
|
+
/* per-connection load */
|
|
113
|
+
}
|
|
114
|
+
protected override resolve(expectation: ToolCallExpectation) {
|
|
115
|
+
return new MyActor(expectation, this /* live runtime */);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
Process facts are `readyState` / `error` / `offers`. Driver extras live on `state`
|
|
121
|
+
(`@observable.shallow override accessor state = { … }`); the orchestrator mirrors
|
|
122
|
+
them onto `spec.live`. Clients render. A concrete class that should not share the
|
|
123
|
+
base extras object declares its own `static state`. Reporting only (no machinery
|
|
124
|
+
branches on it; instance bootstrap truth is the gate); `ensureBootstrapStarted` /
|
|
125
|
+
`failReady` write the token and siblings.
|
|
126
|
+
|
|
127
|
+
Settings enter through `configurationSchema` (Zod), secrets through
|
|
128
|
+
`secretsSchema`. The constructor takes them as separate arguments;
|
|
129
|
+
`parseConfiguration` / `parseSecrets` are the same doors without `new`.
|
|
130
|
+
The live `secrets` view may be replaced after construct (reauth).
|
|
131
|
+
|
|
132
|
+
Bootstrap contexts stay minimal (`{signal, secrets}`); a host hands drivers more by extending
|
|
133
|
+
the context object structurally — there is no ports registry.
|
|
134
|
+
|
|
135
|
+
**The seam.** `Orchestrator` is the boundary between the plexus plane and execution: it notices
|
|
136
|
+
open work, maps the expectation's connection to a catalog row ensures the row's driver class and connection instance
|
|
137
|
+
(memoized; a rejected memo IS the sticky failure), and hands the expectation to
|
|
138
|
+
`connection.handle` — where
|
|
139
|
+
everything about executing it lives. Mint is not a claim: `resolve()` throwing
|
|
140
|
+
breaks the connection (the work stays unspawned). The actor machine still
|
|
141
|
+
requires `START` before `run()`; that is process-local, not a durable claim.
|
|
142
|
+
|
|
143
|
+
## License
|
|
144
|
+
|
|
145
|
+
[MIT](./LICENSE.md).
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { ErrorWithInvariant } from "@inhuman.tools/error-with-invariant";
|
|
2
|
+
import type { PEWDriver } from "./PEWDriver.js";
|
|
3
|
+
import type { Settlement } from "../executor/types.js";
|
|
4
|
+
import { type AnyWorkExpectation, type ReportOf, type ResultOf } from "../shared/models/WorkExpectation.js";
|
|
5
|
+
/**
|
|
6
|
+
* Thrown from `run()` — `start()` settles the work as fail, not crash.
|
|
7
|
+
*
|
|
8
|
+
* Two kinds: {@link ConnectionNotReady} (fulfiller not live), {@link DemandIncomplete}
|
|
9
|
+
* (required field missing on the expectation). Not this family: cancel, applySettlement,
|
|
10
|
+
* report JSON crash, HTTP/tool `fail(reason)`.
|
|
11
|
+
*/
|
|
12
|
+
export declare abstract class ExpectationInvariant extends ErrorWithInvariant {
|
|
13
|
+
name: string;
|
|
14
|
+
constructor(message: string);
|
|
15
|
+
}
|
|
16
|
+
/** Honor started; the fulfiller is not live. */
|
|
17
|
+
export declare class ConnectionNotReady extends ExpectationInvariant {
|
|
18
|
+
readonly connection: string;
|
|
19
|
+
constructor(connection: string);
|
|
20
|
+
}
|
|
21
|
+
/** Required field missing on the expectation body. */
|
|
22
|
+
export declare class DemandIncomplete extends ExpectationInvariant {
|
|
23
|
+
readonly field: string;
|
|
24
|
+
constructor(field: string);
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* One execution of one expectation, bound to the process that has the live connection.
|
|
28
|
+
*
|
|
29
|
+
* ENDINGS ARE OBSERVED, NOT IMPOSED. The actor writes durable endings only at
|
|
30
|
+
* two authority points — its own settlement (`#settle` / `#crash`) and host
|
|
31
|
+
* admission (`admitTermination`). Everything that must happen BECAUSE the
|
|
32
|
+
* work ended (abort the signal, leave) runs in the done reaction — so an
|
|
33
|
+
* ending that arrives from anywhere (a peer's write synced in, host policy)
|
|
34
|
+
* stops this actor exactly like its own. Child endings are supervision's
|
|
35
|
+
* job (the tree-orphan rule), never a cascade from here.
|
|
36
|
+
*/
|
|
37
|
+
export declare abstract class ExpectationActor<E extends AnyWorkExpectation = AnyWorkExpectation> {
|
|
38
|
+
#private;
|
|
39
|
+
readonly expectation: E;
|
|
40
|
+
readonly driverConnection: PEWDriver<E>;
|
|
41
|
+
readonly signal: AbortSignal;
|
|
42
|
+
readonly settled: Promise<Settlement<ResultOf<E>>>;
|
|
43
|
+
constructor(expectation: E, driverConnection: PEWDriver<E>);
|
|
44
|
+
get started(): boolean;
|
|
45
|
+
get done(): boolean;
|
|
46
|
+
start(): void;
|
|
47
|
+
protected abstract run(): void | Promise<void>;
|
|
48
|
+
abort(reason?: unknown): void;
|
|
49
|
+
protected report(frame: ReportOf<E>): void;
|
|
50
|
+
protected complete(result: ResultOf<E>): void;
|
|
51
|
+
protected fail(reason: unknown): void;
|
|
52
|
+
/** Host cancel. A settlement captured while running outranks the cancel. */
|
|
53
|
+
admitTermination(): void;
|
|
54
|
+
leave(): void;
|
|
55
|
+
}
|
|
56
|
+
//# sourceMappingURL=ExpectationActor.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ExpectationActor.d.ts","sourceRoot":"","sources":["../../src/driver/ExpectationActor.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,kBAAkB,EAAE,MAAM,qCAAqC,CAAC;AAMzE,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAChD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AAEvD,OAAO,EACL,KAAK,kBAAkB,EACvB,KAAK,QAAQ,EACb,KAAK,QAAQ,EAEd,MAAM,qCAAqC,CAAC;AAG7C;;;;;;GAMG;AACH,8BAAsB,oBAAqB,SAAQ,kBAAkB;IAC1D,IAAI,SAAyB;gBAE1B,OAAO,EAAE,MAAM;CAG5B;AAED,gDAAgD;AAChD,qBAAa,kBAAmB,SAAQ,oBAAoB;IAC9C,QAAQ,CAAC,UAAU,EAAE,MAAM;gBAAlB,UAAU,EAAE,MAAM;CAGxC;AAED,sDAAsD;AACtD,qBAAa,gBAAiB,SAAQ,oBAAoB;IAC5C,QAAQ,CAAC,KAAK,EAAE,MAAM;gBAAb,KAAK,EAAE,MAAM;CAGnC;AAED;;;;;;;;;;GAUG;AACH,8BAAsB,gBAAgB,CAAC,CAAC,SAAS,kBAAkB,GAAG,kBAAkB;;aAcpE,WAAW,EAAE,CAAC;aACd,gBAAgB,EAAE,SAAS,CAAC,CAAC,CAAC;IAZhD,QAAQ,CAAC,MAAM,EAAE,WAAW,CAA2B;IAKvD,SAAgB,OAAO,EAAE,OAAO,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;gBAMxC,WAAW,EAAE,CAAC,EACd,gBAAgB,EAAE,SAAS,CAAC,CAAC,CAAC;IAgChD,IAAI,OAAO,IAAI,OAAO,CAErB;IAED,IAAI,IAAI,IAAI,OAAO,CAElB;IAED,KAAK,IAAI,IAAI;IAsCb,SAAS,CAAC,QAAQ,CAAC,GAAG,IAAI,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC;IAE9C,KAAK,CAAC,MAAM,CAAC,EAAE,OAAO,GAAG,IAAI;IAI7B,SAAS,CAAC,MAAM,CAAC,KAAK,EAAE,QAAQ,CAAC,CAAC,CAAC,GAAG,IAAI;IAa1C,SAAS,CAAC,QAAQ,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC,CAAC,GAAG,IAAI;IAI7C,SAAS,CAAC,IAAI,CAAC,MAAM,EAAE,OAAO,GAAG,IAAI;IAmDrC,4EAA4E;IAC5E,gBAAgB,IAAI,IAAI;IAQxB,KAAK,IAAI,IAAI;CASd"}
|
|
@@ -0,0 +1,210 @@
|
|
|
1
|
+
import { ErrorWithInvariant } from "@inhuman.tools/error-with-invariant";
|
|
2
|
+
import { reaction, runInAction } from "mobx";
|
|
3
|
+
import invariant from "tiny-invariant";
|
|
4
|
+
import { createActor } from "xstate";
|
|
5
|
+
import { expectationActorMachine } from "./actor-machine.js";
|
|
6
|
+
import { ROLE_LANE_OCCUPIED, } from "../shared/models/WorkExpectation.js";
|
|
7
|
+
import { reportRole, retractRole } from "../shared/role.js";
|
|
8
|
+
/**
|
|
9
|
+
* Thrown from `run()` — `start()` settles the work as fail, not crash.
|
|
10
|
+
*
|
|
11
|
+
* Two kinds: {@link ConnectionNotReady} (fulfiller not live), {@link DemandIncomplete}
|
|
12
|
+
* (required field missing on the expectation). Not this family: cancel, applySettlement,
|
|
13
|
+
* report JSON crash, HTTP/tool `fail(reason)`.
|
|
14
|
+
*/
|
|
15
|
+
export class ExpectationInvariant extends ErrorWithInvariant {
|
|
16
|
+
name = this.constructor.name;
|
|
17
|
+
constructor(message) {
|
|
18
|
+
super(message);
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
/** Honor started; the fulfiller is not live. */
|
|
22
|
+
export class ConnectionNotReady extends ExpectationInvariant {
|
|
23
|
+
connection;
|
|
24
|
+
constructor(connection) {
|
|
25
|
+
super(`${connection} connection not ready`);
|
|
26
|
+
this.connection = connection;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
/** Required field missing on the expectation body. */
|
|
30
|
+
export class DemandIncomplete extends ExpectationInvariant {
|
|
31
|
+
field;
|
|
32
|
+
constructor(field) {
|
|
33
|
+
super(`demand missing ${field}`);
|
|
34
|
+
this.field = field;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* One execution of one expectation, bound to the process that has the live connection.
|
|
39
|
+
*
|
|
40
|
+
* ENDINGS ARE OBSERVED, NOT IMPOSED. The actor writes durable endings only at
|
|
41
|
+
* two authority points — its own settlement (`#settle` / `#crash`) and host
|
|
42
|
+
* admission (`admitTermination`). Everything that must happen BECAUSE the
|
|
43
|
+
* work ended (abort the signal, leave) runs in the done reaction — so an
|
|
44
|
+
* ending that arrives from anywhere (a peer's write synced in, host policy)
|
|
45
|
+
* stops this actor exactly like its own. Child endings are supervision's
|
|
46
|
+
* job (the tree-orphan rule), never a cascade from here.
|
|
47
|
+
*/
|
|
48
|
+
export class ExpectationActor {
|
|
49
|
+
expectation;
|
|
50
|
+
driverConnection;
|
|
51
|
+
#hub;
|
|
52
|
+
#controller = new AbortController();
|
|
53
|
+
signal = this.#controller.signal;
|
|
54
|
+
#lastReportJson = null;
|
|
55
|
+
#settlement = null;
|
|
56
|
+
#resolveSettled;
|
|
57
|
+
#rejectSettled;
|
|
58
|
+
settled;
|
|
59
|
+
#phase = createActor(expectationActorMachine).start();
|
|
60
|
+
#laneDisposers = [];
|
|
61
|
+
#left = false;
|
|
62
|
+
constructor(expectation, driverConnection) {
|
|
63
|
+
this.expectation = expectation;
|
|
64
|
+
this.driverConnection = driverConnection;
|
|
65
|
+
this.settled = new Promise((resolve, reject) => {
|
|
66
|
+
this.#resolveSettled = resolve;
|
|
67
|
+
this.#rejectSettled = reject;
|
|
68
|
+
});
|
|
69
|
+
void this.settled.catch(() => { });
|
|
70
|
+
this.signal.addEventListener("abort", () => {
|
|
71
|
+
this.#send("ABORT");
|
|
72
|
+
}, { once: true });
|
|
73
|
+
invariant(expectation.plexus != null, "ExpectationActor requires the expectation to be on a session plexus");
|
|
74
|
+
this.#hub = expectation.plexus.awareness;
|
|
75
|
+
this.#laneDisposers.push(reaction(() => this.expectation.isDone, (done) => {
|
|
76
|
+
if (!done)
|
|
77
|
+
return;
|
|
78
|
+
this.abort("done");
|
|
79
|
+
this.#send("RELEASE");
|
|
80
|
+
this.leave();
|
|
81
|
+
}, { fireImmediately: true }));
|
|
82
|
+
}
|
|
83
|
+
get started() {
|
|
84
|
+
return !this.#phase.getSnapshot().can({ type: "START" });
|
|
85
|
+
}
|
|
86
|
+
get done() {
|
|
87
|
+
return this.#phase.getSnapshot().status === "done";
|
|
88
|
+
}
|
|
89
|
+
start() {
|
|
90
|
+
invariant(this.#phase.getSnapshot().can({ type: "START" }), "double-start attempt");
|
|
91
|
+
this.#send("START");
|
|
92
|
+
runInAction(() => {
|
|
93
|
+
this.expectation.markStarted();
|
|
94
|
+
});
|
|
95
|
+
this.#occupyRoleLane();
|
|
96
|
+
try {
|
|
97
|
+
const result = this.run();
|
|
98
|
+
if (result != null && typeof result.then === "function") {
|
|
99
|
+
result.catch((error) => this.#onRunError(error));
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
catch (error) {
|
|
103
|
+
this.#onRunError(error);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
#onRunError(error) {
|
|
107
|
+
if (error instanceof ExpectationInvariant) {
|
|
108
|
+
this.fail(error);
|
|
109
|
+
return;
|
|
110
|
+
}
|
|
111
|
+
this.#crash(error);
|
|
112
|
+
}
|
|
113
|
+
#matches(phase) {
|
|
114
|
+
return this.#phase.getSnapshot().matches(phase);
|
|
115
|
+
}
|
|
116
|
+
#send(type) {
|
|
117
|
+
if (!this.#phase.getSnapshot().can({ type }))
|
|
118
|
+
return;
|
|
119
|
+
this.#phase.send({ type });
|
|
120
|
+
}
|
|
121
|
+
#occupyRoleLane() {
|
|
122
|
+
reportRole(this.#hub, this.expectation.uuid, ROLE_LANE_OCCUPIED);
|
|
123
|
+
}
|
|
124
|
+
abort(reason) {
|
|
125
|
+
this.#controller.abort(reason);
|
|
126
|
+
}
|
|
127
|
+
report(frame) {
|
|
128
|
+
if (!this.#matches("running"))
|
|
129
|
+
return;
|
|
130
|
+
let json;
|
|
131
|
+
try {
|
|
132
|
+
json = JSON.stringify(frame ?? null);
|
|
133
|
+
}
|
|
134
|
+
catch (error) {
|
|
135
|
+
this.#crash(error);
|
|
136
|
+
return;
|
|
137
|
+
}
|
|
138
|
+
this.#lastReportJson = json;
|
|
139
|
+
reportRole(this.#hub, this.expectation.uuid, JSON.parse(json));
|
|
140
|
+
}
|
|
141
|
+
complete(result) {
|
|
142
|
+
this.#settle({ outcome: "complete", result });
|
|
143
|
+
}
|
|
144
|
+
fail(reason) {
|
|
145
|
+
this.#settle({ outcome: "fail", reason });
|
|
146
|
+
}
|
|
147
|
+
#settle(settlement) {
|
|
148
|
+
if (this.done || !this.#phase.getSnapshot().can({ type: "SETTLE" }))
|
|
149
|
+
return;
|
|
150
|
+
const wasRunning = this.#matches("running");
|
|
151
|
+
this.#settlement = settlement;
|
|
152
|
+
this.#resolveSettled(settlement);
|
|
153
|
+
this.#send("SETTLE");
|
|
154
|
+
this.#commitEnding("settle", wasRunning);
|
|
155
|
+
}
|
|
156
|
+
#crash(reason) {
|
|
157
|
+
if (this.done || !this.#phase.getSnapshot().can({ type: "CRASH" }))
|
|
158
|
+
return;
|
|
159
|
+
const wasRunning = this.#matches("running");
|
|
160
|
+
this.#rejectSettled(reason);
|
|
161
|
+
this.#send("CRASH");
|
|
162
|
+
this.#commitEnding("crash", wasRunning, String(reason));
|
|
163
|
+
}
|
|
164
|
+
/**
|
|
165
|
+
* ENDING PRECEDES ABORT. A settlement captured while running (or consulted
|
|
166
|
+
* when admitting cancel) wins. A complete/fail flushed from an abort listener
|
|
167
|
+
* is stored on `#settlement` but not written here.
|
|
168
|
+
*/
|
|
169
|
+
#commitEnding(kind, wasRunning, crashDetail) {
|
|
170
|
+
if (this.expectation.isDone)
|
|
171
|
+
return;
|
|
172
|
+
if (this.#settlement !== null && (wasRunning || kind === "cancel")) {
|
|
173
|
+
const settlement = this.#settlement;
|
|
174
|
+
if (settlement.outcome === "complete") {
|
|
175
|
+
this.expectation.succeed("settled", "", this.#frameJson(), { result: settlement.result });
|
|
176
|
+
}
|
|
177
|
+
else {
|
|
178
|
+
this.expectation.fail("settled", settlement.reason instanceof Error ? settlement.reason.message : String(settlement.reason), this.#frameJson());
|
|
179
|
+
}
|
|
180
|
+
return;
|
|
181
|
+
}
|
|
182
|
+
if (kind === "cancel") {
|
|
183
|
+
this.expectation.fail("cancel", "terminate", this.#frameJson());
|
|
184
|
+
return;
|
|
185
|
+
}
|
|
186
|
+
if (!wasRunning)
|
|
187
|
+
return;
|
|
188
|
+
if (kind === "crash") {
|
|
189
|
+
this.expectation.fail("crash", crashDetail ?? "", this.#frameJson());
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
/** Host cancel. A settlement captured while running outranks the cancel. */
|
|
193
|
+
admitTermination() {
|
|
194
|
+
this.#commitEnding("cancel", this.#matches("running"));
|
|
195
|
+
}
|
|
196
|
+
#frameJson() {
|
|
197
|
+
return this.#lastReportJson ?? "null";
|
|
198
|
+
}
|
|
199
|
+
leave() {
|
|
200
|
+
if (!this.#left) {
|
|
201
|
+
this.#left = true;
|
|
202
|
+
for (const dispose of this.#laneDisposers)
|
|
203
|
+
dispose();
|
|
204
|
+
this.#laneDisposers = [];
|
|
205
|
+
retractRole(this.#hub, this.expectation.uuid);
|
|
206
|
+
}
|
|
207
|
+
this.driverConnection.release(this.expectation);
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
//# sourceMappingURL=ExpectationActor.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ExpectationActor.js","sourceRoot":"","sources":["../../src/driver/ExpectationActor.ts"],"names":[],"mappings":"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","sourcesContent":["import { type PlexusAwareness } from \"@here.build/plexus\";\nimport { ErrorWithInvariant } from \"@inhuman.tools/error-with-invariant\";\nimport { reaction, runInAction } from \"mobx\";\nimport invariant from \"tiny-invariant\";\nimport { createActor } from \"xstate\";\n\nimport { type ActorPhase, type ActorPhaseEvent, expectationActorMachine } from \"./actor-machine.js\";\nimport type { PEWDriver } from \"./PEWDriver.js\";\nimport type { Settlement } from \"../executor/types.js\";\nimport type { SessionAwareness } from \"../shared/index.js\";\nimport {\n type AnyWorkExpectation,\n type ReportOf,\n type ResultOf,\n ROLE_LANE_OCCUPIED,\n} from \"../shared/models/WorkExpectation.js\";\nimport { reportRole, retractRole } from \"../shared/role.js\";\n\n/**\n * Thrown from `run()` — `start()` settles the work as fail, not crash.\n *\n * Two kinds: {@link ConnectionNotReady} (fulfiller not live), {@link DemandIncomplete}\n * (required field missing on the expectation). Not this family: cancel, applySettlement,\n * report JSON crash, HTTP/tool `fail(reason)`.\n */\nexport abstract class ExpectationInvariant extends ErrorWithInvariant {\n override name = this.constructor.name;\n\n constructor(message: string) {\n super(message);\n }\n}\n\n/** Honor started; the fulfiller is not live. */\nexport class ConnectionNotReady extends ExpectationInvariant {\n constructor(readonly connection: string) {\n super(`${connection} connection not ready`);\n }\n}\n\n/** Required field missing on the expectation body. */\nexport class DemandIncomplete extends ExpectationInvariant {\n constructor(readonly field: string) {\n super(`demand missing ${field}`);\n }\n}\n\n/**\n * One execution of one expectation, bound to the process that has the live connection.\n *\n * ENDINGS ARE OBSERVED, NOT IMPOSED. The actor writes durable endings only at\n * two authority points — its own settlement (`#settle` / `#crash`) and host\n * admission (`admitTermination`). Everything that must happen BECAUSE the\n * work ended (abort the signal, leave) runs in the done reaction — so an\n * ending that arrives from anywhere (a peer's write synced in, host policy)\n * stops this actor exactly like its own. Child endings are supervision's\n * job (the tree-orphan rule), never a cascade from here.\n */\nexport abstract class ExpectationActor<E extends AnyWorkExpectation = AnyWorkExpectation> {\n readonly #hub: PlexusAwareness<SessionAwareness>;\n readonly #controller = new AbortController();\n readonly signal: AbortSignal = this.#controller.signal;\n #lastReportJson: string | null = null;\n #settlement: Settlement<ResultOf<E>> | null = null;\n #resolveSettled!: (settlement: Settlement<ResultOf<E>>) => void;\n #rejectSettled!: (reason: unknown) => void;\n public readonly settled: Promise<Settlement<ResultOf<E>>>;\n readonly #phase = createActor(expectationActorMachine).start();\n #laneDisposers: Array<() => void> = [];\n #left = false;\n\n constructor(\n public readonly expectation: E,\n public readonly driverConnection: PEWDriver<E>,\n ) {\n this.settled = new Promise<Settlement<ResultOf<E>>>((resolve, reject) => {\n this.#resolveSettled = resolve;\n this.#rejectSettled = reject;\n });\n void this.settled.catch(() => {});\n\n this.signal.addEventListener(\n \"abort\",\n () => {\n this.#send(\"ABORT\");\n },\n { once: true },\n );\n\n invariant(expectation.plexus != null, \"ExpectationActor requires the expectation to be on a session plexus\");\n this.#hub = expectation.plexus.awareness as PlexusAwareness<SessionAwareness>;\n this.#laneDisposers.push(\n reaction(\n () => this.expectation.isDone,\n (done) => {\n if (!done) return;\n this.abort(\"done\");\n this.#send(\"RELEASE\");\n this.leave();\n },\n { fireImmediately: true },\n ),\n );\n }\n\n get started(): boolean {\n return !this.#phase.getSnapshot().can({ type: \"START\" });\n }\n\n get done(): boolean {\n return this.#phase.getSnapshot().status === \"done\";\n }\n\n start(): void {\n invariant(this.#phase.getSnapshot().can({ type: \"START\" }), \"double-start attempt\");\n this.#send(\"START\");\n runInAction(() => {\n this.expectation.markStarted();\n });\n this.#occupyRoleLane();\n try {\n const result = this.run();\n if (result != null && typeof (result as Promise<void>).then === \"function\") {\n (result as Promise<void>).catch((error) => this.#onRunError(error));\n }\n } catch (error) {\n this.#onRunError(error);\n }\n }\n\n #onRunError(error: unknown): void {\n if (error instanceof ExpectationInvariant) {\n this.fail(error);\n return;\n }\n this.#crash(error);\n }\n\n #matches(phase: ActorPhase): boolean {\n return this.#phase.getSnapshot().matches(phase);\n }\n\n #send(type: ActorPhaseEvent[\"type\"]): void {\n if (!this.#phase.getSnapshot().can({ type })) return;\n this.#phase.send({ type });\n }\n\n #occupyRoleLane(): void {\n reportRole(this.#hub, this.expectation.uuid, ROLE_LANE_OCCUPIED);\n }\n\n protected abstract run(): void | Promise<void>;\n\n abort(reason?: unknown): void {\n this.#controller.abort(reason);\n }\n\n protected report(frame: ReportOf<E>): void {\n if (!this.#matches(\"running\")) return;\n let json: string;\n try {\n json = JSON.stringify(frame ?? null);\n } catch (error) {\n this.#crash(error);\n return;\n }\n this.#lastReportJson = json;\n reportRole(this.#hub, this.expectation.uuid, JSON.parse(json));\n }\n\n protected complete(result: ResultOf<E>): void {\n this.#settle({ outcome: \"complete\", result });\n }\n\n protected fail(reason: unknown): void {\n this.#settle({ outcome: \"fail\", reason });\n }\n\n #settle(settlement: Settlement<ResultOf<E>>): void {\n if (this.done || !this.#phase.getSnapshot().can({ type: \"SETTLE\" })) return;\n const wasRunning = this.#matches(\"running\");\n this.#settlement = settlement;\n this.#resolveSettled(settlement);\n this.#send(\"SETTLE\");\n this.#commitEnding(\"settle\", wasRunning);\n }\n\n #crash(reason: unknown): void {\n if (this.done || !this.#phase.getSnapshot().can({ type: \"CRASH\" })) return;\n const wasRunning = this.#matches(\"running\");\n this.#rejectSettled(reason);\n this.#send(\"CRASH\");\n this.#commitEnding(\"crash\", wasRunning, String(reason));\n }\n\n /**\n * ENDING PRECEDES ABORT. A settlement captured while running (or consulted\n * when admitting cancel) wins. A complete/fail flushed from an abort listener\n * is stored on `#settlement` but not written here.\n */\n #commitEnding(kind: \"settle\" | \"crash\" | \"cancel\", wasRunning: boolean, crashDetail?: string): void {\n if (this.expectation.isDone) return;\n if (this.#settlement !== null && (wasRunning || kind === \"cancel\")) {\n const settlement = this.#settlement;\n if (settlement.outcome === \"complete\") {\n this.expectation.succeed(\"settled\", \"\", this.#frameJson(), { result: settlement.result });\n } else {\n this.expectation.fail(\n \"settled\",\n settlement.reason instanceof Error ? settlement.reason.message : String(settlement.reason),\n this.#frameJson(),\n );\n }\n return;\n }\n if (kind === \"cancel\") {\n this.expectation.fail(\"cancel\", \"terminate\", this.#frameJson());\n return;\n }\n if (!wasRunning) return;\n if (kind === \"crash\") {\n this.expectation.fail(\"crash\", crashDetail ?? \"\", this.#frameJson());\n }\n }\n\n /** Host cancel. A settlement captured while running outranks the cancel. */\n admitTermination(): void {\n this.#commitEnding(\"cancel\", this.#matches(\"running\"));\n }\n\n #frameJson(): string {\n return this.#lastReportJson ?? \"null\";\n }\n\n leave(): void {\n if (!this.#left) {\n this.#left = true;\n for (const dispose of this.#laneDisposers) dispose();\n this.#laneDisposers = [];\n retractRole(this.#hub, this.expectation.uuid);\n }\n this.driverConnection.release(this.expectation);\n }\n}\n"]}
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
import type { PlexusAwareness } from "@here.build/plexus";
|
|
2
|
+
import type { ExpectationActor } from "./ExpectationActor.js";
|
|
3
|
+
import type { AnyWorkExpectation, WorkExpectation } from "../shared/models/WorkExpectation.js";
|
|
4
|
+
import { type RevalidationDemand } from "../shared/revalidation-demand.js";
|
|
5
|
+
import type { ReadyState } from "../shared/types.js";
|
|
6
|
+
/** Duck-typed — drivers may ship a different Zod major than this package. */
|
|
7
|
+
export type ConfigurationSchema = {
|
|
8
|
+
safeParse(data: unknown): {
|
|
9
|
+
readonly success: true;
|
|
10
|
+
readonly data: unknown;
|
|
11
|
+
} | {
|
|
12
|
+
readonly success: false;
|
|
13
|
+
readonly error: {
|
|
14
|
+
readonly issues: ReadonlyArray<{
|
|
15
|
+
readonly message?: string;
|
|
16
|
+
}>;
|
|
17
|
+
};
|
|
18
|
+
};
|
|
19
|
+
};
|
|
20
|
+
/** Process-local. Secrets are never a Plexus field. */
|
|
21
|
+
export type ConnectionSecretsView = {
|
|
22
|
+
readonly revision?: number;
|
|
23
|
+
get(field: string): unknown | undefined;
|
|
24
|
+
/** MCP env_* enumerates deposited fields. */
|
|
25
|
+
all?(): Readonly<Record<string, unknown>> | undefined;
|
|
26
|
+
/** Hosts that persist a refreshed session (reauth) implement this. */
|
|
27
|
+
replace?(secrets: Readonly<Record<string, string>>): void;
|
|
28
|
+
};
|
|
29
|
+
/** Module-graph duplication breaks instanceof; the elevation gate checks this brand too. */
|
|
30
|
+
export declare const PEW_DRIVER_BRAND = "@inhuman.tools/plexus-expectations:PEWDriver@1";
|
|
31
|
+
/** A connection construction the driver already knows will work. */
|
|
32
|
+
export type DriverOffer = {
|
|
33
|
+
readonly name: string;
|
|
34
|
+
readonly description: string;
|
|
35
|
+
readonly live: boolean;
|
|
36
|
+
readonly adoptable: boolean;
|
|
37
|
+
readonly settings: Readonly<Record<string, unknown>>;
|
|
38
|
+
};
|
|
39
|
+
/**
|
|
40
|
+
* Driver extras the orchestrator mirrors onto `spec.live`.
|
|
41
|
+
* Core process facts live on `readyState` / `error` / `offers`.
|
|
42
|
+
*/
|
|
43
|
+
export declare function extraLiveFromState(state: object): Record<string, unknown>;
|
|
44
|
+
/**
|
|
45
|
+
* The CLASS is the driver (one loaded module per driver name).
|
|
46
|
+
* The INSTANCE is a live connection (one per connection id).
|
|
47
|
+
*
|
|
48
|
+
* CLAIM DOES NOT LIVE HERE. Which WorkExpectation classes this driver handles
|
|
49
|
+
* lives on the advertised driver record (`can`): dynamically loaded code does
|
|
50
|
+
* not get to declare its own authority.
|
|
51
|
+
*
|
|
52
|
+
* Live state is report only — no machinery branches on it. Instance bootstrap
|
|
53
|
+
* truth is `bootstrapDone` / `bootstrapPending`. Drivers read {@link attention}
|
|
54
|
+
* as the reduced token, never clientIds.
|
|
55
|
+
*
|
|
56
|
+
* YAML doors ({@link configurationSchema} / {@link secretsSchema}) parse
|
|
57
|
+
* without `new`. Secrets stay a live view — the host may replace it (reauth).
|
|
58
|
+
*/
|
|
59
|
+
export declare abstract class PEWDriver<E extends AnyWorkExpectation = AnyWorkExpectation, C = Readonly<Record<string, unknown>>> implements AsyncDisposable {
|
|
60
|
+
readonly connectionId: string;
|
|
61
|
+
static readonly pewBrand: string;
|
|
62
|
+
/**
|
|
63
|
+
* YAML settings shape. Default is a passthrough record — subclasses replace
|
|
64
|
+
* this with a real object schema (transforms included). First issue message
|
|
65
|
+
* is what construct / parse throw.
|
|
66
|
+
*/
|
|
67
|
+
static readonly configurationSchema: ConfigurationSchema;
|
|
68
|
+
static readonly configurationLabel: string;
|
|
69
|
+
static configurationError(message: string): string;
|
|
70
|
+
/** YAML settings door. Does not construct an instance. */
|
|
71
|
+
static parseConfiguration(settings?: unknown): unknown;
|
|
72
|
+
static readonly secretsSchema: ConfigurationSchema;
|
|
73
|
+
static secretsError(message: string): string;
|
|
74
|
+
/** YAML secrets door. Does not construct an instance. */
|
|
75
|
+
static parseSecrets(secrets?: unknown): unknown;
|
|
76
|
+
/** Shared on the prototype chain — own extras per subclass. */
|
|
77
|
+
static readonly state: Record<string, unknown>;
|
|
78
|
+
/**
|
|
79
|
+
* A plain list, or a getter over observable state when the driver keeps its
|
|
80
|
+
* offers fresh (local detection). The orchestrator mirrors it onto
|
|
81
|
+
* `DriverSpec.offers` with a reaction, which is also what observes it.
|
|
82
|
+
*/
|
|
83
|
+
static readonly offers: readonly DriverOffer[];
|
|
84
|
+
/** Kernel-plane occupancy hub. Orchestrator assignment is own-per-class. */
|
|
85
|
+
static awareness: PlexusAwareness | undefined;
|
|
86
|
+
static driverName: string;
|
|
87
|
+
/**
|
|
88
|
+
* A getter, not `@computed` — MobX: the decorator's initializer pins to the
|
|
89
|
+
* declaring class, so subclasses would share one computed.
|
|
90
|
+
*/
|
|
91
|
+
static get revalidationDemand(): RevalidationDemand;
|
|
92
|
+
accessor readyState: ReadyState;
|
|
93
|
+
accessor error: string;
|
|
94
|
+
/**
|
|
95
|
+
* MobX: shallow — extras (models, tools, account) are replaced wholesale.
|
|
96
|
+
* Override the accessor with a wider literal to add driver facts.
|
|
97
|
+
*/
|
|
98
|
+
accessor state: Record<string, unknown>;
|
|
99
|
+
accessor awareness: PlexusAwareness | undefined;
|
|
100
|
+
get revalidationDemand(): RevalidationDemand;
|
|
101
|
+
constructor(connectionId: string, settings?: unknown, secrets?: ConnectionSecretsView | Readonly<Record<string, unknown>>);
|
|
102
|
+
readonly settings: C;
|
|
103
|
+
/** Live view. The host may replace it (reauth). */
|
|
104
|
+
secrets: ConnectionSecretsView;
|
|
105
|
+
/**
|
|
106
|
+
* Host binds the disk writer for this connection's settings bag.
|
|
107
|
+
* Parsed settings stay readonly; a driver that learns a value overrides this.
|
|
108
|
+
*/
|
|
109
|
+
bindSettingsWriter(_write: (patch: Readonly<Record<string, unknown>>) => void): void;
|
|
110
|
+
abstract bootstrap(): Promise<void>;
|
|
111
|
+
bootstrapDone: boolean;
|
|
112
|
+
bootstrapPending: Promise<void> | null;
|
|
113
|
+
/** `resolve()` threw — the connection is broken, not the work. */
|
|
114
|
+
broken: boolean;
|
|
115
|
+
/** Concurrent callers share one promise. Async settlement is its own MobX action. */
|
|
116
|
+
ensureBootstrapStarted(): Promise<void>;
|
|
117
|
+
failReady(error: unknown): void;
|
|
118
|
+
protected abstract resolve(expectation: E): ExpectationActor<E>;
|
|
119
|
+
/** Nothing in PEW calls this; hosts or tests may. */
|
|
120
|
+
[Symbol.asyncDispose](): Promise<void>;
|
|
121
|
+
private readonly actors;
|
|
122
|
+
private readonly liveActors;
|
|
123
|
+
has(expectation: WorkExpectation): boolean;
|
|
124
|
+
resolveExpectation<T extends AnyWorkExpectation>(expectation: T): ExpectationActor<T>;
|
|
125
|
+
release(expectation: WorkExpectation): void;
|
|
126
|
+
/**
|
|
127
|
+
* Logout/drop aborts interned work. Not park. Subclasses abort `#inflight`.
|
|
128
|
+
*/
|
|
129
|
+
abortOnDrop(reason: unknown): void;
|
|
130
|
+
/**
|
|
131
|
+
* Honor one demand.
|
|
132
|
+
* `resolve()` throwing is a broken connection, not a failed expectation.
|
|
133
|
+
*/
|
|
134
|
+
handle(expectation: WorkExpectation): void;
|
|
135
|
+
}
|
|
136
|
+
/**
|
|
137
|
+
* A concrete `PEWDriver` subclass — constructable, not abstract.
|
|
138
|
+
* `loadDriverModule` returns `unknown`; {@link isDriverConnectionClass} is the gate.
|
|
139
|
+
*/
|
|
140
|
+
export type DriverConnectionClass = {
|
|
141
|
+
[K in keyof typeof PEWDriver]: (typeof PEWDriver)[K];
|
|
142
|
+
} & (new (...args: ConstructorParameters<typeof PEWDriver>) => PEWDriver);
|
|
143
|
+
export declare function isDriverConnectionClass(value: unknown): value is DriverConnectionClass;
|
|
144
|
+
//# sourceMappingURL=PEWDriver.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"PEWDriver.d.ts","sourceRoot":"","sources":["../../src/driver/PEWDriver.ts"],"names":[],"mappings":"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"}
|