@agenticprimitives/fabric 0.0.0-alpha.1
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/CLAUDE.md +67 -0
- package/LICENSE +21 -0
- package/README.md +21 -0
- package/dist/case-machine.d.ts +76 -0
- package/dist/case-machine.d.ts.map +1 -0
- package/dist/case-machine.js +83 -0
- package/dist/case-machine.js.map +1 -0
- package/dist/client/index.d.ts +114 -0
- package/dist/client/index.d.ts.map +1 -0
- package/dist/client/index.js +76 -0
- package/dist/client/index.js.map +1 -0
- package/dist/cloudflare/authority-verdict-cache.d.ts +27 -0
- package/dist/cloudflare/authority-verdict-cache.d.ts.map +1 -0
- package/dist/cloudflare/authority-verdict-cache.js +66 -0
- package/dist/cloudflare/authority-verdict-cache.js.map +1 -0
- package/dist/cloudflare/channel-store.d.ts +61 -0
- package/dist/cloudflare/channel-store.d.ts.map +1 -0
- package/dist/cloudflare/channel-store.js +124 -0
- package/dist/cloudflare/channel-store.js.map +1 -0
- package/dist/cloudflare/exchange-store.d.ts +16 -0
- package/dist/cloudflare/exchange-store.d.ts.map +1 -0
- package/dist/cloudflare/exchange-store.js +45 -0
- package/dist/cloudflare/exchange-store.js.map +1 -0
- package/dist/cloudflare/gateway-tools.d.ts +28 -0
- package/dist/cloudflare/gateway-tools.d.ts.map +1 -0
- package/dist/cloudflare/gateway-tools.js +45 -0
- package/dist/cloudflare/gateway-tools.js.map +1 -0
- package/dist/cloudflare/index.d.ts +13 -0
- package/dist/cloudflare/index.d.ts.map +1 -0
- package/dist/cloudflare/index.js +20 -0
- package/dist/cloudflare/index.js.map +1 -0
- package/dist/cloudflare/orchestration-runtime.d.ts +28 -0
- package/dist/cloudflare/orchestration-runtime.d.ts.map +1 -0
- package/dist/cloudflare/orchestration-runtime.js +35 -0
- package/dist/cloudflare/orchestration-runtime.js.map +1 -0
- package/dist/cloudflare/outbox-store.d.ts +24 -0
- package/dist/cloudflare/outbox-store.d.ts.map +1 -0
- package/dist/cloudflare/outbox-store.js +42 -0
- package/dist/cloudflare/outbox-store.js.map +1 -0
- package/dist/cloudflare/principal-gateway-do.d.ts +234 -0
- package/dist/cloudflare/principal-gateway-do.d.ts.map +1 -0
- package/dist/cloudflare/principal-gateway-do.js +369 -0
- package/dist/cloudflare/principal-gateway-do.js.map +1 -0
- package/dist/cloudflare/provenance-store.d.ts +9 -0
- package/dist/cloudflare/provenance-store.d.ts.map +1 -0
- package/dist/cloudflare/provenance-store.js +36 -0
- package/dist/cloudflare/provenance-store.js.map +1 -0
- package/dist/cloudflare/receipt-signer.d.ts +26 -0
- package/dist/cloudflare/receipt-signer.d.ts.map +1 -0
- package/dist/cloudflare/receipt-signer.js +69 -0
- package/dist/cloudflare/receipt-signer.js.map +1 -0
- package/dist/cloudflare/request-id-ledger.d.ts +13 -0
- package/dist/cloudflare/request-id-ledger.d.ts.map +1 -0
- package/dist/cloudflare/request-id-ledger.js +38 -0
- package/dist/cloudflare/request-id-ledger.js.map +1 -0
- package/dist/cloudflare/sql-vault.d.ts +10 -0
- package/dist/cloudflare/sql-vault.d.ts.map +1 -0
- package/dist/cloudflare/sql-vault.js +98 -0
- package/dist/cloudflare/sql-vault.js.map +1 -0
- package/dist/communicative-act.d.ts +47 -0
- package/dist/communicative-act.d.ts.map +1 -0
- package/dist/communicative-act.js +36 -0
- package/dist/communicative-act.js.map +1 -0
- package/dist/delivery-envelope.d.ts +38 -0
- package/dist/delivery-envelope.d.ts.map +1 -0
- package/dist/delivery-envelope.js +43 -0
- package/dist/delivery-envelope.js.map +1 -0
- package/dist/exchange-record.d.ts +131 -0
- package/dist/exchange-record.d.ts.map +1 -0
- package/dist/exchange-record.js +25 -0
- package/dist/exchange-record.js.map +1 -0
- package/dist/exchange-reducer.d.ts +25 -0
- package/dist/exchange-reducer.d.ts.map +1 -0
- package/dist/exchange-reducer.js +108 -0
- package/dist/exchange-reducer.js.map +1 -0
- package/dist/exchange-state.d.ts +56 -0
- package/dist/exchange-state.d.ts.map +1 -0
- package/dist/exchange-state.js +81 -0
- package/dist/exchange-state.js.map +1 -0
- package/dist/gateway-surface.d.ts +24 -0
- package/dist/gateway-surface.d.ts.map +1 -0
- package/dist/gateway-surface.js +33 -0
- package/dist/gateway-surface.js.map +1 -0
- package/dist/inbox-doc.d.ts +32 -0
- package/dist/inbox-doc.d.ts.map +1 -0
- package/dist/inbox-doc.js +57 -0
- package/dist/inbox-doc.js.map +1 -0
- package/dist/inbox-projection.d.ts +15 -0
- package/dist/inbox-projection.d.ts.map +1 -0
- package/dist/inbox-projection.js +28 -0
- package/dist/inbox-projection.js.map +1 -0
- package/dist/index.d.ts +19 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +30 -0
- package/dist/index.js.map +1 -0
- package/dist/interactions/audited.d.ts +12 -0
- package/dist/interactions/audited.d.ts.map +1 -0
- package/dist/interactions/audited.js +67 -0
- package/dist/interactions/audited.js.map +1 -0
- package/dist/interactions/builders.d.ts +24 -0
- package/dist/interactions/builders.d.ts.map +1 -0
- package/dist/interactions/builders.js +48 -0
- package/dist/interactions/builders.js.map +1 -0
- package/dist/interactions/cards.d.ts +32 -0
- package/dist/interactions/cards.d.ts.map +1 -0
- package/dist/interactions/cards.js +20 -0
- package/dist/interactions/cards.js.map +1 -0
- package/dist/interactions/index.d.ts +15 -0
- package/dist/interactions/index.d.ts.map +1 -0
- package/dist/interactions/index.js +23 -0
- package/dist/interactions/index.js.map +1 -0
- package/dist/interactions/machine.d.ts +19 -0
- package/dist/interactions/machine.d.ts.map +1 -0
- package/dist/interactions/machine.js +31 -0
- package/dist/interactions/machine.js.map +1 -0
- package/dist/interactions/mandates.d.ts +64 -0
- package/dist/interactions/mandates.d.ts.map +1 -0
- package/dist/interactions/mandates.js +62 -0
- package/dist/interactions/mandates.js.map +1 -0
- package/dist/interactions/relationship.d.ts +29 -0
- package/dist/interactions/relationship.d.ts.map +1 -0
- package/dist/interactions/relationship.js +31 -0
- package/dist/interactions/relationship.js.map +1 -0
- package/dist/interactions/risk.d.ts +39 -0
- package/dist/interactions/risk.d.ts.map +1 -0
- package/dist/interactions/risk.js +49 -0
- package/dist/interactions/risk.js.map +1 -0
- package/dist/interactions/runs.d.ts +26 -0
- package/dist/interactions/runs.d.ts.map +1 -0
- package/dist/interactions/runs.js +80 -0
- package/dist/interactions/runs.js.map +1 -0
- package/dist/interactions/store.d.ts +20 -0
- package/dist/interactions/store.d.ts.map +1 -0
- package/dist/interactions/store.js +68 -0
- package/dist/interactions/store.js.map +1 -0
- package/dist/interactions/tickets.d.ts +68 -0
- package/dist/interactions/tickets.d.ts.map +1 -0
- package/dist/interactions/tickets.js +49 -0
- package/dist/interactions/tickets.js.map +1 -0
- package/dist/interactions/types.d.ts +160 -0
- package/dist/interactions/types.d.ts.map +1 -0
- package/dist/interactions/types.js +7 -0
- package/dist/interactions/types.js.map +1 -0
- package/dist/messaging/board.d.ts +54 -0
- package/dist/messaging/board.d.ts.map +1 -0
- package/dist/messaging/board.js +90 -0
- package/dist/messaging/board.js.map +1 -0
- package/dist/messaging/conversation.d.ts +35 -0
- package/dist/messaging/conversation.d.ts.map +1 -0
- package/dist/messaging/conversation.js +72 -0
- package/dist/messaging/conversation.js.map +1 -0
- package/dist/messaging/delivery.d.ts +19 -0
- package/dist/messaging/delivery.d.ts.map +1 -0
- package/dist/messaging/delivery.js +56 -0
- package/dist/messaging/delivery.js.map +1 -0
- package/dist/messaging/directory.d.ts +32 -0
- package/dist/messaging/directory.d.ts.map +1 -0
- package/dist/messaging/directory.js +35 -0
- package/dist/messaging/directory.js.map +1 -0
- package/dist/messaging/envelope.d.ts +14 -0
- package/dist/messaging/envelope.d.ts.map +1 -0
- package/dist/messaging/envelope.js +71 -0
- package/dist/messaging/envelope.js.map +1 -0
- package/dist/messaging/hash.d.ts +19 -0
- package/dist/messaging/hash.d.ts.map +1 -0
- package/dist/messaging/hash.js +36 -0
- package/dist/messaging/hash.js.map +1 -0
- package/dist/messaging/index.d.ts +16 -0
- package/dist/messaging/index.d.ts.map +1 -0
- package/dist/messaging/index.js +29 -0
- package/dist/messaging/index.js.map +1 -0
- package/dist/messaging/projector.d.ts +58 -0
- package/dist/messaging/projector.d.ts.map +1 -0
- package/dist/messaging/projector.js +103 -0
- package/dist/messaging/projector.js.map +1 -0
- package/dist/messaging/receipts.d.ts +5 -0
- package/dist/messaging/receipts.d.ts.map +1 -0
- package/dist/messaging/receipts.js +19 -0
- package/dist/messaging/receipts.js.map +1 -0
- package/dist/messaging/rules.d.ts +84 -0
- package/dist/messaging/rules.d.ts.map +1 -0
- package/dist/messaging/rules.js +109 -0
- package/dist/messaging/rules.js.map +1 -0
- package/dist/messaging/store.d.ts +24 -0
- package/dist/messaging/store.d.ts.map +1 -0
- package/dist/messaging/store.js +120 -0
- package/dist/messaging/store.js.map +1 -0
- package/dist/messaging/types.d.ts +166 -0
- package/dist/messaging/types.d.ts.map +1 -0
- package/dist/messaging/types.js +7 -0
- package/dist/messaging/types.js.map +1 -0
- package/dist/messaging/vault-store.d.ts +37 -0
- package/dist/messaging/vault-store.d.ts.map +1 -0
- package/dist/messaging/vault-store.js +62 -0
- package/dist/messaging/vault-store.js.map +1 -0
- package/dist/record-catalog.d.ts +22 -0
- package/dist/record-catalog.d.ts.map +1 -0
- package/dist/record-catalog.js +35 -0
- package/dist/record-catalog.js.map +1 -0
- package/package.json +82 -0
- package/spec.md +15 -0
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
import type { MessageEnvelopeV1, MessageKind, MessageEventType, MessageId, Hex32, ContextRefV1 } from './messaging/index.js';
|
|
2
|
+
import { hashMessageEnvelope } from './messaging/index.js';
|
|
3
|
+
import type { AuthorityRef } from './interactions/index.js';
|
|
4
|
+
import type { AuthorityTier } from '@agenticprimitives/tool-policy';
|
|
5
|
+
import type { CanonicalAgentId } from '@agenticprimitives/types';
|
|
6
|
+
import type { VaultRef } from '@agenticprimitives/vault';
|
|
7
|
+
import type { ExecState, CaseState } from './exchange-state.js';
|
|
8
|
+
import type { CaseTransition } from './case-machine.js';
|
|
9
|
+
/** The exchange spine id — replaces today's `taskId` / `int_`+`run_` / `conv_`+`msg_` id families. */
|
|
10
|
+
export type ExchangeId = `xch_${string}`;
|
|
11
|
+
/**
|
|
12
|
+
* The signed wire object (spec §b + spec 324 §9). Absorbs `MessageEnvelopeV1` + the A2A message. A
|
|
13
|
+
* communication envelope carries none of the execution fields, so it canonicalizes byte-for-byte as a
|
|
14
|
+
* `MessageEnvelopeV1` (zero wire change). `ExchangeEnvelopeV1` is the canonical name — not every envelope
|
|
15
|
+
* carries an Intent — with `MessageEnvelopeV1` as the communication-profile subtype and the execution profile
|
|
16
|
+
* (`skill`/`argsRef`/`argsHash` set) as the execution subtype.
|
|
17
|
+
*/
|
|
18
|
+
export interface ExchangeEnvelopeV1 extends MessageEnvelopeV1 {
|
|
19
|
+
/** Execution-tier only: the invoked skill NAME. The gate server-computes the selector from this
|
|
20
|
+
* (`computeSkillSelector`) and never trusts a client-supplied selector. Absent on communication. */
|
|
21
|
+
skill?: string;
|
|
22
|
+
/** Execution-tier only: vault-ref to the canonical invocation args (hash-bound like `body`). Absent on
|
|
23
|
+
* communication. */
|
|
24
|
+
argsRef?: VaultRef;
|
|
25
|
+
/** Execution-tier only: SHA-256 over the canonical args, bound into the single-use requestId (spec §3a). */
|
|
26
|
+
argsHash?: Hex32;
|
|
27
|
+
}
|
|
28
|
+
/** @deprecated Use {@link ExchangeEnvelopeV1} — structurally identical (`ap.message.v1`), retained for
|
|
29
|
+
* callers; not every envelope carries an Intent (spec 324 §9). */
|
|
30
|
+
export type IntentEnvelopeV1 = ExchangeEnvelopeV1;
|
|
31
|
+
/** Reuses `messaging.hashMessageEnvelope` byte-for-byte so absorbed signatures/receipts stay valid (spec §b) —
|
|
32
|
+
* ZERO wire change across the W5 rename. For an execution envelope the extra fields participate in the
|
|
33
|
+
* canonical hash (a distinct signing domain). */
|
|
34
|
+
export declare const hashExchangeEnvelope: typeof hashMessageEnvelope;
|
|
35
|
+
/** @deprecated Use {@link hashExchangeEnvelope} — identical function (spec 324 §9). */
|
|
36
|
+
export declare const hashIntentEnvelope: typeof hashMessageEnvelope;
|
|
37
|
+
/** A vault-resident, hash-bound artifact produced by an exchange (result, file, generated credential, …). */
|
|
38
|
+
export interface ArtifactRef {
|
|
39
|
+
ref: VaultRef;
|
|
40
|
+
hash: Hex32;
|
|
41
|
+
contentType?: string;
|
|
42
|
+
}
|
|
43
|
+
/** Common fields of every fabric event. Single-writer (the gateway DO), seq-numbered, idempotency-keyed,
|
|
44
|
+
* hash-bound into the per-conversation causal chain (spec 306). */
|
|
45
|
+
export interface ExchangeEventBase {
|
|
46
|
+
seq: number;
|
|
47
|
+
at: string;
|
|
48
|
+
/** Replayed event with the same key is a no-op (no second row). */
|
|
49
|
+
idempotencyKey?: string;
|
|
50
|
+
/** Hash binding this event into the spec-306 causal chain. */
|
|
51
|
+
entryHash?: Hex32;
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* The append-only fabric event stream element (spec §b) — the UNIFIED union that absorbs messaging's
|
|
55
|
+
* `MessageEventV1` (`kind:'message'`), the interaction transition (`kind:'case'`), artifact production
|
|
56
|
+
* (`kind:'artifact'`), and pure-transport exec moves driven by the T2 runtime (`kind:'transport'`).
|
|
57
|
+
* - `message` events are INBOX read-receipt/lifecycle facts — they update the inbox projection, NOT exec/case.
|
|
58
|
+
* - `case` events drive the case machine; `exec` follows by PROJECTION (`expectedExecForCase`).
|
|
59
|
+
* - `transport` events are the only ones validated against `fulfillment`'s task-edge graph (`canTaskTransition`).
|
|
60
|
+
*/
|
|
61
|
+
export type ExchangeEventV1 = (ExchangeEventBase & {
|
|
62
|
+
kind: 'message';
|
|
63
|
+
eventType: MessageEventType;
|
|
64
|
+
actor: CanonicalAgentId;
|
|
65
|
+
messageId: MessageId;
|
|
66
|
+
evidenceRef?: VaultRef;
|
|
67
|
+
}) | (ExchangeEventBase & {
|
|
68
|
+
kind: 'case';
|
|
69
|
+
transition: CaseTransition;
|
|
70
|
+
actor: CanonicalAgentId;
|
|
71
|
+
messageId?: MessageId;
|
|
72
|
+
evidenceRef?: VaultRef;
|
|
73
|
+
authorityRef?: AuthorityRef;
|
|
74
|
+
}) | (ExchangeEventBase & {
|
|
75
|
+
kind: 'artifact';
|
|
76
|
+
artifact: ArtifactRef;
|
|
77
|
+
}) | (ExchangeEventBase & {
|
|
78
|
+
kind: 'transport';
|
|
79
|
+
toExec: ExecState;
|
|
80
|
+
});
|
|
81
|
+
/**
|
|
82
|
+
* The ONE canonical exchange record (spec §b). Two-level FSM: `exec` (transport, always present) + `case`
|
|
83
|
+
* (business substate, execution-tier only). Authority is referenced, never satisfied here — approving a case
|
|
84
|
+
* advances `case`, it never unlocks a resource (ADR-0041).
|
|
85
|
+
*/
|
|
86
|
+
export interface ExchangeRecordV1 {
|
|
87
|
+
version: 'ap.exchange.v1';
|
|
88
|
+
exchangeId: ExchangeId;
|
|
89
|
+
/** Projection hint only — the authority TIER is server-classified from the skill selector, never `kind`. */
|
|
90
|
+
kind: MessageKind;
|
|
91
|
+
/** Server-classified ONCE at ingress (never client-asserted). */
|
|
92
|
+
tier: AuthorityTier;
|
|
93
|
+
/** The delegator / gateway owner SA — on whose behalf the exchange runs. Also the case RESPONDER by
|
|
94
|
+
* convention (the gateway owner triages/approves inbound requests) — see `caseViewFromRecord`. */
|
|
95
|
+
principal: CanonicalAgentId;
|
|
96
|
+
/** WHO performed the acting move (spec 324 §9) — `actor == principal` unless a service agent acts for the
|
|
97
|
+
* principal under delegation (the authorizing delegation is in `authorityRefs`). Optional for wire-compat;
|
|
98
|
+
* absent ⇒ `principal` (use `actorOf`). The acting agent is never erased from provenance nor conflated with
|
|
99
|
+
* the principal. */
|
|
100
|
+
actor?: CanonicalAgentId;
|
|
101
|
+
parties: {
|
|
102
|
+
from: CanonicalAgentId;
|
|
103
|
+
to: CanonicalAgentId[];
|
|
104
|
+
cc?: CanonicalAgentId[];
|
|
105
|
+
};
|
|
106
|
+
/** The case RESOURCE-OWNER, only when it differs from `principal` (e.g. the principal brokers for another
|
|
107
|
+
* SA's resource). The ONE case role not derivable from `parties`/`principal`; defaults to `principal`. */
|
|
108
|
+
resourceOwner?: CanonicalAgentId;
|
|
109
|
+
/** Transport envelope state (always present). */
|
|
110
|
+
exec: ExecState;
|
|
111
|
+
/** Business substate — execution-tier only; `undefined` for a T0 communication exchange. */
|
|
112
|
+
case?: CaseState;
|
|
113
|
+
/** The signed wire objects (deliveries, responses, decisions). */
|
|
114
|
+
envelopes: ExchangeEnvelopeV1[];
|
|
115
|
+
/** The single append-only event stream (single-writer in the DO). */
|
|
116
|
+
events: ExchangeEventV1[];
|
|
117
|
+
/** By-hash pointers at delegation/entitlement/VC/receipt — never inline authority. */
|
|
118
|
+
authorityRefs?: AuthorityRef[];
|
|
119
|
+
/** Vault-resident, hash-bound outputs. */
|
|
120
|
+
artifacts?: ArtifactRef[];
|
|
121
|
+
/** Entities this exchange is ABOUT (spec 312) — carried through from the envelope. */
|
|
122
|
+
contextRefs?: ContextRefV1[];
|
|
123
|
+
/** Monotonic revision for the inbox-projection cursor. */
|
|
124
|
+
rev: number;
|
|
125
|
+
updatedAt: string;
|
|
126
|
+
expiresAt?: string;
|
|
127
|
+
}
|
|
128
|
+
/** The acting agent of a record (spec 324 §9): the explicit `actor` if present, else the `principal`
|
|
129
|
+
* (`actor == principal` unless a delegated service agent acted). Provenance never loses the actor. */
|
|
130
|
+
export declare function actorOf(record: Pick<ExchangeRecordV1, 'actor' | 'principal'>): CanonicalAgentId;
|
|
131
|
+
//# sourceMappingURL=exchange-record.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"exchange-record.d.ts","sourceRoot":"","sources":["../src/exchange-record.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
// The canonical exchange object (spec 316 §b). Everything a principal handles — a chat line, an approval
|
|
2
|
+
// request, a credential delivery, a multi-step orchestrated task — is ONE `ExchangeRecordV1`, a deliberately
|
|
3
|
+
// TWO-LEVEL object: an `ExecState` transport envelope carrying an optional `CaseState` business substate.
|
|
4
|
+
//
|
|
5
|
+
// `IntentEnvelopeV1` is the signed wire object; for the communication profile it is byte-for-byte a
|
|
6
|
+
// `MessageEnvelopeV1`, so `hashIntentEnvelope` REUSES `hashMessageEnvelope` and every existing signature +
|
|
7
|
+
// receipt digest stays valid across the absorption (spec §b). Execution-tier envelopes add the invoked skill
|
|
8
|
+
// + a vault-ref to the canonical args; those fields are absent on communication envelopes, so a communication
|
|
9
|
+
// `IntentEnvelopeV1` canonicalizes identically to today's `MessageEnvelopeV1`.
|
|
10
|
+
//
|
|
11
|
+
// NOTE (Wave 1, in progress): the append-only `ExchangeEventV1` stream + the case reducer are absorbed from
|
|
12
|
+
// messaging/interactions in the next Wave-1 step; `ExchangeEventV1` here is the minimal seed union.
|
|
13
|
+
import { hashMessageEnvelope } from './messaging/index.js';
|
|
14
|
+
/** Reuses `messaging.hashMessageEnvelope` byte-for-byte so absorbed signatures/receipts stay valid (spec §b) —
|
|
15
|
+
* ZERO wire change across the W5 rename. For an execution envelope the extra fields participate in the
|
|
16
|
+
* canonical hash (a distinct signing domain). */
|
|
17
|
+
export const hashExchangeEnvelope = hashMessageEnvelope;
|
|
18
|
+
/** @deprecated Use {@link hashExchangeEnvelope} — identical function (spec 324 §9). */
|
|
19
|
+
export const hashIntentEnvelope = hashMessageEnvelope;
|
|
20
|
+
/** The acting agent of a record (spec 324 §9): the explicit `actor` if present, else the `principal`
|
|
21
|
+
* (`actor == principal` unless a delegated service agent acted). Provenance never loses the actor. */
|
|
22
|
+
export function actorOf(record) {
|
|
23
|
+
return record.actor ?? record.principal;
|
|
24
|
+
}
|
|
25
|
+
//# sourceMappingURL=exchange-record.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"exchange-record.js","sourceRoot":"","sources":["../src/exchange-record.ts"],"names":[],"mappings":"AAAA,yGAAyG;AACzG,6GAA6G;AAC7G,0GAA0G;AAC1G,EAAE;AACF,oGAAoG;AACpG,2GAA2G;AAC3G,6GAA6G;AAC7G,8GAA8G;AAC9G,+EAA+E;AAC/E,EAAE;AACF,4GAA4G;AAC5G,oGAAoG;AAGpG,OAAO,EAAE,mBAAmB,EAAE,MAAM,sBAAsB,CAAC;AAiC3D;;kDAEkD;AAClD,MAAM,CAAC,MAAM,oBAAoB,GAAG,mBAAmB,CAAC;AACxD,uFAAuF;AACvF,MAAM,CAAC,MAAM,kBAAkB,GAAG,mBAAmB,CAAC;AA8EtD;uGACuG;AACvG,MAAM,UAAU,OAAO,CAAC,MAAqD;IAC3E,OAAO,MAAM,CAAC,KAAK,IAAI,MAAM,CAAC,SAAS,CAAC;AAC1C,CAAC"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { type CaseFsmFields } from './case-machine.js';
|
|
2
|
+
import type { ExchangeRecordV1, ExchangeEventV1 } from './exchange-record.js';
|
|
3
|
+
export type ExchangeApplyResult = {
|
|
4
|
+
ok: true;
|
|
5
|
+
record: ExchangeRecordV1;
|
|
6
|
+
changed: boolean;
|
|
7
|
+
} | {
|
|
8
|
+
ok: false;
|
|
9
|
+
reason: string;
|
|
10
|
+
};
|
|
11
|
+
/**
|
|
12
|
+
* Derive the transient case FSM view from a lean `ExchangeRecordV1` (option (a) — the record stays the lean
|
|
13
|
+
* spine; the case view is constructed only when applying a transition). Role convention: `requester` = the
|
|
14
|
+
* sender (`parties.from`); `responder` = the gateway owner (`principal`, who triages/approves inbound
|
|
15
|
+
* requests); `resource-owner` = `record.resourceOwner ?? principal` (the ONE role not derivable). Returns
|
|
16
|
+
* `null` for a case-less (T0) exchange.
|
|
17
|
+
*/
|
|
18
|
+
export declare function caseViewFromRecord(record: ExchangeRecordV1): CaseFsmFields | null;
|
|
19
|
+
/**
|
|
20
|
+
* Apply one event to an exchange record. Single-writer semantics (the gateway DO): `event.seq` must be the
|
|
21
|
+
* next slot (`record.events.length`). Returns the next record (`changed: true`), a no-op for an idempotent
|
|
22
|
+
* replay (`changed: false`), or a typed rejection.
|
|
23
|
+
*/
|
|
24
|
+
export declare function applyExchangeEvent(record: ExchangeRecordV1, event: ExchangeEventV1): ExchangeApplyResult;
|
|
25
|
+
//# sourceMappingURL=exchange-reducer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"exchange-reducer.d.ts","sourceRoot":"","sources":["../src/exchange-reducer.ts"],"names":[],"mappings":"AAiBA,OAAO,EAAuB,KAAK,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAC5E,OAAO,KAAK,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AAE9E,MAAM,MAAM,mBAAmB,GAC3B;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,MAAM,EAAE,gBAAgB,CAAC;IAAC,OAAO,EAAE,OAAO,CAAA;CAAE,GACxD;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC;AAElC;;;;;;GAMG;AACH,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,gBAAgB,GAAG,aAAa,GAAG,IAAI,CAajF;AAED;;;;GAIG;AACH,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,gBAAgB,EAAE,KAAK,EAAE,eAAe,GAAG,mBAAmB,CAiExG"}
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
// The unified exchange-event reducer (spec 316 §b/§2) — ONE append-only stream, ONE reducer over the
|
|
2
|
+
// canonical `ExchangeRecordV1`. This is the capstone of absorbing messaging (inbox events) + interactions
|
|
3
|
+
// (case transitions) into the fabric. Two-layer coupling (the load-bearing design decision):
|
|
4
|
+
//
|
|
5
|
+
// - `case` events drive the absorbed case machine; `exec` follows by PROJECTION (`expectedExecForCase`).
|
|
6
|
+
// The case FSM is the AUTHORITY, so the case-driven `exec` is NOT re-validated against `fulfillment`'s
|
|
7
|
+
// task-edge graph — that is exactly what lets `denied→rejected` and the `needs-info` loop couple cleanly
|
|
8
|
+
// without illegal task edges (e.g. `submitted→input-required`).
|
|
9
|
+
// - `message` events are inbox read-receipt / lifecycle FACTS — they append to the stream (and drive the
|
|
10
|
+
// inbox projection elsewhere), never `exec`/`case`.
|
|
11
|
+
// - `transport` events (a T2 runtime task step / an interrupt) are the ONLY `exec` moves validated against
|
|
12
|
+
// `canTaskTransition`, and must keep the `(exec, case)` pair coupling-consistent (`isExecCaseConsistent`).
|
|
13
|
+
//
|
|
14
|
+
// Fail-closed: an illegal case transition, an inconsistent transport move, or a seq gap is a typed rejection,
|
|
15
|
+
// never a silent state change. Idempotent: a replayed event (same `idempotencyKey`) is a no-op.
|
|
16
|
+
import { canTaskTransition, expectedExecForCase, isExecCaseConsistent } from './exchange-state.js';
|
|
17
|
+
import { applyCaseTransition } from './case-machine.js';
|
|
18
|
+
/**
|
|
19
|
+
* Derive the transient case FSM view from a lean `ExchangeRecordV1` (option (a) — the record stays the lean
|
|
20
|
+
* spine; the case view is constructed only when applying a transition). Role convention: `requester` = the
|
|
21
|
+
* sender (`parties.from`); `responder` = the gateway owner (`principal`, who triages/approves inbound
|
|
22
|
+
* requests); `resource-owner` = `record.resourceOwner ?? principal` (the ONE role not derivable). Returns
|
|
23
|
+
* `null` for a case-less (T0) exchange.
|
|
24
|
+
*/
|
|
25
|
+
export function caseViewFromRecord(record) {
|
|
26
|
+
if (record.case === undefined)
|
|
27
|
+
return null;
|
|
28
|
+
return {
|
|
29
|
+
id: record.exchangeId,
|
|
30
|
+
state: record.case,
|
|
31
|
+
requester: record.parties.from,
|
|
32
|
+
responder: record.principal,
|
|
33
|
+
resourceOwner: record.resourceOwner ?? record.principal,
|
|
34
|
+
expiresAt: record.expiresAt,
|
|
35
|
+
updatedAt: record.updatedAt,
|
|
36
|
+
evidenceRefs: [],
|
|
37
|
+
authorityRefs: record.authorityRefs ?? [],
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Apply one event to an exchange record. Single-writer semantics (the gateway DO): `event.seq` must be the
|
|
42
|
+
* next slot (`record.events.length`). Returns the next record (`changed: true`), a no-op for an idempotent
|
|
43
|
+
* replay (`changed: false`), or a typed rejection.
|
|
44
|
+
*/
|
|
45
|
+
export function applyExchangeEvent(record, event) {
|
|
46
|
+
// Idempotent replay — a matching key already in the stream is a no-op (no second row).
|
|
47
|
+
if (event.idempotencyKey && record.events.some((e) => e.idempotencyKey === event.idempotencyKey)) {
|
|
48
|
+
return { ok: true, record, changed: false };
|
|
49
|
+
}
|
|
50
|
+
// Single-writer seq: the event must fill the next slot (no gaps, no out-of-order).
|
|
51
|
+
if (event.seq !== record.events.length) {
|
|
52
|
+
return { ok: false, reason: `seq-gap:expected ${record.events.length} got ${event.seq}` };
|
|
53
|
+
}
|
|
54
|
+
const appended = {
|
|
55
|
+
...record,
|
|
56
|
+
events: [...record.events, event],
|
|
57
|
+
rev: record.rev + 1,
|
|
58
|
+
updatedAt: event.at,
|
|
59
|
+
};
|
|
60
|
+
switch (event.kind) {
|
|
61
|
+
case 'message':
|
|
62
|
+
// Inbox read-receipt / lifecycle fact — appended to the stream; the inbox projection reflects it.
|
|
63
|
+
// Never changes exec/case (a T0 message stays exec=submitted).
|
|
64
|
+
return { ok: true, record: appended, changed: true };
|
|
65
|
+
case 'artifact':
|
|
66
|
+
return { ok: true, changed: true, record: { ...appended, artifacts: [...(record.artifacts ?? []), event.artifact] } };
|
|
67
|
+
case 'case': {
|
|
68
|
+
const view = caseViewFromRecord(record);
|
|
69
|
+
if (!view)
|
|
70
|
+
return { ok: false, reason: 'no-case:case event on a case-less exchange' };
|
|
71
|
+
const res = applyCaseTransition(view, {
|
|
72
|
+
version: 'ap.case.event.v1',
|
|
73
|
+
caseId: record.exchangeId,
|
|
74
|
+
transition: event.transition,
|
|
75
|
+
actor: event.actor,
|
|
76
|
+
at: event.at,
|
|
77
|
+
messageId: event.messageId,
|
|
78
|
+
evidenceRef: event.evidenceRef,
|
|
79
|
+
authorityRef: event.authorityRef,
|
|
80
|
+
});
|
|
81
|
+
if (!res.ok)
|
|
82
|
+
return { ok: false, reason: `case:${res.reason}` };
|
|
83
|
+
const nextCase = res.case.state;
|
|
84
|
+
return {
|
|
85
|
+
ok: true,
|
|
86
|
+
changed: true,
|
|
87
|
+
record: {
|
|
88
|
+
...appended,
|
|
89
|
+
case: nextCase,
|
|
90
|
+
exec: expectedExecForCase(nextCase), // projection — the case FSM is the authority
|
|
91
|
+
authorityRefs: res.case.authorityRefs,
|
|
92
|
+
},
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
case 'transport': {
|
|
96
|
+
// Pure-transport exec move (T2 runtime step / interrupt) — the ONLY exec change validated against the
|
|
97
|
+
// task-edge graph, and it must keep the (exec, case) pair coupling-consistent.
|
|
98
|
+
if (!canTaskTransition(record.exec, event.toExec)) {
|
|
99
|
+
return { ok: false, reason: `transport:illegal-exec ${record.exec}->${event.toExec}` };
|
|
100
|
+
}
|
|
101
|
+
if (!isExecCaseConsistent(event.toExec, record.case)) {
|
|
102
|
+
return { ok: false, reason: 'transport:coupling-inconsistent' };
|
|
103
|
+
}
|
|
104
|
+
return { ok: true, changed: true, record: { ...appended, exec: event.toExec } };
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
//# sourceMappingURL=exchange-reducer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"exchange-reducer.js","sourceRoot":"","sources":["../src/exchange-reducer.ts"],"names":[],"mappings":"AAAA,qGAAqG;AACrG,0GAA0G;AAC1G,6FAA6F;AAC7F,EAAE;AACF,2GAA2G;AAC3G,2GAA2G;AAC3G,6GAA6G;AAC7G,oEAAoE;AACpE,2GAA2G;AAC3G,wDAAwD;AACxD,6GAA6G;AAC7G,+GAA+G;AAC/G,EAAE;AACF,8GAA8G;AAC9G,gGAAgG;AAEhG,OAAO,EAAE,iBAAiB,EAAE,mBAAmB,EAAE,oBAAoB,EAAE,MAAM,qBAAqB,CAAC;AACnG,OAAO,EAAE,mBAAmB,EAAsB,MAAM,mBAAmB,CAAC;AAO5E;;;;;;GAMG;AACH,MAAM,UAAU,kBAAkB,CAAC,MAAwB;IACzD,IAAI,MAAM,CAAC,IAAI,KAAK,SAAS;QAAE,OAAO,IAAI,CAAC;IAC3C,OAAO;QACL,EAAE,EAAE,MAAM,CAAC,UAAU;QACrB,KAAK,EAAE,MAAM,CAAC,IAAI;QAClB,SAAS,EAAE,MAAM,CAAC,OAAO,CAAC,IAAI;QAC9B,SAAS,EAAE,MAAM,CAAC,SAAS;QAC3B,aAAa,EAAE,MAAM,CAAC,aAAa,IAAI,MAAM,CAAC,SAAS;QACvD,SAAS,EAAE,MAAM,CAAC,SAAS;QAC3B,SAAS,EAAE,MAAM,CAAC,SAAS;QAC3B,YAAY,EAAE,EAAE;QAChB,aAAa,EAAE,MAAM,CAAC,aAAa,IAAI,EAAE;KAC1C,CAAC;AACJ,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,kBAAkB,CAAC,MAAwB,EAAE,KAAsB;IACjF,uFAAuF;IACvF,IAAI,KAAK,CAAC,cAAc,IAAI,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,cAAc,KAAK,KAAK,CAAC,cAAc,CAAC,EAAE,CAAC;QACjG,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC;IAC9C,CAAC;IACD,mFAAmF;IACnF,IAAI,KAAK,CAAC,GAAG,KAAK,MAAM,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC;QACvC,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,oBAAoB,MAAM,CAAC,MAAM,CAAC,MAAM,QAAQ,KAAK,CAAC,GAAG,EAAE,EAAE,CAAC;IAC5F,CAAC;IAED,MAAM,QAAQ,GAAqB;QACjC,GAAG,MAAM;QACT,MAAM,EAAE,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,KAAK,CAAC;QACjC,GAAG,EAAE,MAAM,CAAC,GAAG,GAAG,CAAC;QACnB,SAAS,EAAE,KAAK,CAAC,EAAE;KACpB,CAAC;IAEF,QAAQ,KAAK,CAAC,IAAI,EAAE,CAAC;QACnB,KAAK,SAAS;YACZ,kGAAkG;YAClG,+DAA+D;YAC/D,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;QAEvD,KAAK,UAAU;YACb,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,GAAG,QAAQ,EAAE,SAAS,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,SAAS,IAAI,EAAE,CAAC,EAAE,KAAK,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;QAExH,KAAK,MAAM,CAAC,CAAC,CAAC;YACZ,MAAM,IAAI,GAAG,kBAAkB,CAAC,MAAM,CAAC,CAAC;YACxC,IAAI,CAAC,IAAI;gBAAE,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,4CAA4C,EAAE,CAAC;YACtF,MAAM,GAAG,GAAG,mBAAmB,CAAC,IAAI,EAAE;gBACpC,OAAO,EAAE,kBAAkB;gBAC3B,MAAM,EAAE,MAAM,CAAC,UAAU;gBACzB,UAAU,EAAE,KAAK,CAAC,UAAU;gBAC5B,KAAK,EAAE,KAAK,CAAC,KAAK;gBAClB,EAAE,EAAE,KAAK,CAAC,EAAE;gBACZ,SAAS,EAAE,KAAK,CAAC,SAAS;gBAC1B,WAAW,EAAE,KAAK,CAAC,WAAW;gBAC9B,YAAY,EAAE,KAAK,CAAC,YAAY;aACjC,CAAC,CAAC;YACH,IAAI,CAAC,GAAG,CAAC,EAAE;gBAAE,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,QAAQ,GAAG,CAAC,MAAM,EAAE,EAAE,CAAC;YAChE,MAAM,QAAQ,GAAG,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC;YAChC,OAAO;gBACL,EAAE,EAAE,IAAI;gBACR,OAAO,EAAE,IAAI;gBACb,MAAM,EAAE;oBACN,GAAG,QAAQ;oBACX,IAAI,EAAE,QAAQ;oBACd,IAAI,EAAE,mBAAmB,CAAC,QAAQ,CAAC,EAAE,6CAA6C;oBAClF,aAAa,EAAE,GAAG,CAAC,IAAI,CAAC,aAAa;iBACtC;aACF,CAAC;QACJ,CAAC;QAED,KAAK,WAAW,CAAC,CAAC,CAAC;YACjB,sGAAsG;YACtG,+EAA+E;YAC/E,IAAI,CAAC,iBAAiB,CAAC,MAAM,CAAC,IAAI,EAAE,KAAK,CAAC,MAAM,CAAC,EAAE,CAAC;gBAClD,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,0BAA0B,MAAM,CAAC,IAAI,KAAK,KAAK,CAAC,MAAM,EAAE,EAAE,CAAC;YACzF,CAAC;YACD,IAAI,CAAC,oBAAoB,CAAC,KAAK,CAAC,MAAM,EAAE,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC;gBACrD,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,iCAAiC,EAAE,CAAC;YAClE,CAAC;YACD,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,GAAG,QAAQ,EAAE,IAAI,EAAE,KAAK,CAAC,MAAM,EAAE,EAAE,CAAC;QAClF,CAAC;IACH,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { canTaskTransition, type TaskState } from '@agenticprimitives/fulfillment';
|
|
2
|
+
/** The transport/execution envelope state — reused from `fulfillment` (kept a pure leaf, unmodified). */
|
|
3
|
+
export type ExecState = TaskState;
|
|
4
|
+
export { canTaskTransition };
|
|
5
|
+
/** All 8 transport `ExecState`s (mirrors `fulfillment` `TaskState`), for coverage assertions. */
|
|
6
|
+
export declare const EXEC_STATES: readonly ExecState[];
|
|
7
|
+
/** The business/interaction substate (spec 316 §2), 11 states. `delivered`/`seen` were REMOVED (Blocker 6):
|
|
8
|
+
* they are inbox read-receipt facts, not lifecycle transitions. */
|
|
9
|
+
export type CaseState = 'draft' | 'submitted' | 'triaged' | 'needs-info' | 'approved' | 'denied' | 'issued' | 'completed' | 'expired' | 'revoked' | 'failed';
|
|
10
|
+
export declare const CASE_STATES: readonly CaseState[];
|
|
11
|
+
/**
|
|
12
|
+
* EXEC_CASE_COUPLING (spec 316 §2) — the canonical `ExecState` each `CaseState` maps to. Exhaustive over all
|
|
13
|
+
* 11 `CaseState`. Rationale per row:
|
|
14
|
+
* - `draft`/`submitted` → `submitted` : case created, pre-triage/local — accepted, not yet worked.
|
|
15
|
+
* - `triaged`/`approved` → `working` : responder actively working the request.
|
|
16
|
+
* - `needs-info` → `input-required` : the ONLY case → `input-required` (blocked awaiting requester;
|
|
17
|
+
* A2A `input-required` = blocked on the SENDER, so `triaged` must NOT map here).
|
|
18
|
+
* - `issued`/`completed` → `completed`.
|
|
19
|
+
* - `denied` → `rejected` : a rejected request is distinct from a failed task.
|
|
20
|
+
* - `expired`/`revoked`/`failed` → `failed` (canonical; `canceled` is the transport-set alternative).
|
|
21
|
+
*/
|
|
22
|
+
export declare const EXEC_CASE_COUPLING: Record<CaseState, ExecState>;
|
|
23
|
+
/**
|
|
24
|
+
* `ExecState`s set by the TRANSPORT/run layer, NOT derived from a `CaseState`:
|
|
25
|
+
* - `auth-required` — raised by a step-up/authority interrupt (`raiseInterrupt`) on an in-flight execution
|
|
26
|
+
* case; resolves back to `working`/`input-required` on `resume`.
|
|
27
|
+
* - `canceled` — an explicit withdrawal of a not-yet-terminal exchange, or a terminal for
|
|
28
|
+
* `expired`/`revoked`/`failed` cases.
|
|
29
|
+
* Both are consistent on any in-flight execution case (one with a defined `CaseState`); they are NOT
|
|
30
|
+
* "unmapped ⇒ reject". Together with the 6 case-derived exec values they cover all 8 `ExecState`s.
|
|
31
|
+
*/
|
|
32
|
+
export declare const TRANSPORT_SET_EXEC: readonly ExecState[];
|
|
33
|
+
/** The exec envelope state expected for a given case. `undefined` case (T0 / pre-case delivery) ⇒ `submitted`. */
|
|
34
|
+
export declare function expectedExecForCase(caseState: CaseState | undefined): ExecState;
|
|
35
|
+
/**
|
|
36
|
+
* True when an `(exec, case)` pair is coupling-consistent (spec 316 §2, fail-closed):
|
|
37
|
+
* - a transport-set exec (`auth-required`/`canceled`) is valid on any in-flight execution case (case defined),
|
|
38
|
+
* never on a case-less T0 exchange;
|
|
39
|
+
* - otherwise the case must map to EXACTLY this exec via `EXEC_CASE_COUPLING` (or `submitted` for no case).
|
|
40
|
+
* Any other pairing is inconsistent → the caller rejects (never silently drops).
|
|
41
|
+
*/
|
|
42
|
+
export declare function isExecCaseConsistent(exec: ExecState, caseState: CaseState | undefined): boolean;
|
|
43
|
+
/**
|
|
44
|
+
* `canExchangeTransition = canTaskTransition(exec) ∧ isExecCaseConsistent(to)` (spec 316 §2). NOTE: the case
|
|
45
|
+
* LIFECYCLE validity (e.g. `draft → submitted` legal, `completed → triaged` illegal) is enforced by the
|
|
46
|
+
* absorbed interactions case reducer, composed at the fabric level; this function enforces the transport
|
|
47
|
+
* transition + the exec/case coupling invariant. A `false` here is always a fail-closed rejection.
|
|
48
|
+
*/
|
|
49
|
+
export declare function canExchangeTransition(from: {
|
|
50
|
+
exec: ExecState;
|
|
51
|
+
case?: CaseState;
|
|
52
|
+
}, to: {
|
|
53
|
+
exec: ExecState;
|
|
54
|
+
case?: CaseState;
|
|
55
|
+
}): boolean;
|
|
56
|
+
//# sourceMappingURL=exchange-state.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"exchange-state.d.ts","sourceRoot":"","sources":["../src/exchange-state.ts"],"names":[],"mappings":"AASA,OAAO,EAAE,iBAAiB,EAAE,KAAK,SAAS,EAAE,MAAM,gCAAgC,CAAC;AAEnF,yGAAyG;AACzG,MAAM,MAAM,SAAS,GAAG,SAAS,CAAC;AAClC,OAAO,EAAE,iBAAiB,EAAE,CAAC;AAE7B,iGAAiG;AACjG,eAAO,MAAM,WAAW,EAAE,SAAS,SAAS,EAElC,CAAC;AAEX;oEACoE;AACpE,MAAM,MAAM,SAAS,GACjB,OAAO,GAAG,WAAW,GAAG,SAAS,GAAG,YAAY,GAChD,UAAU,GAAG,QAAQ,GAAG,QAAQ,GAAG,WAAW,GAC9C,SAAS,GAAG,SAAS,GAAG,QAAQ,CAAC;AAErC,eAAO,MAAM,WAAW,EAAE,SAAS,SAAS,EAElC,CAAC;AAEX;;;;;;;;;;GAUG;AACH,eAAO,MAAM,kBAAkB,EAAE,MAAM,CAAC,SAAS,EAAE,SAAS,CAY3D,CAAC;AAEF;;;;;;;;GAQG;AACH,eAAO,MAAM,kBAAkB,EAAE,SAAS,SAAS,EAA2C,CAAC;AAE/F,kHAAkH;AAClH,wBAAgB,mBAAmB,CAAC,SAAS,EAAE,SAAS,GAAG,SAAS,GAAG,SAAS,CAG/E;AAED;;;;;;GAMG;AACH,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,SAAS,EAAE,SAAS,EAAE,SAAS,GAAG,SAAS,GAAG,OAAO,CAG/F;AAED;;;;;GAKG;AACH,wBAAgB,qBAAqB,CACnC,IAAI,EAAE;IAAE,IAAI,EAAE,SAAS,CAAC;IAAC,IAAI,CAAC,EAAE,SAAS,CAAA;CAAE,EAC3C,EAAE,EAAE;IAAE,IAAI,EAAE,SAAS,CAAC;IAAC,IAAI,CAAC,EAAE,SAAS,CAAA;CAAE,GACxC,OAAO,CAGT"}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
// The two-level exchange state machine (spec 316 §1/§2). Every `ExchangeRecordV1` carries an **ExecState**
|
|
2
|
+
// (the transport/execution envelope, reused verbatim from `@agenticprimitives/fulfillment` as a pure leaf)
|
|
3
|
+
// and — on execution-tier exchanges only — a **CaseState** (the business/interaction substate absorbed from
|
|
4
|
+
// `@agenticprimitives/interactions`). The two are coupled by an exhaustively-enumerated, fail-closed table:
|
|
5
|
+
// an (exec, case) pair with no mapping is a typed rejection, never a silent drop (the convergence-critic gate).
|
|
6
|
+
//
|
|
7
|
+
// Communication (T0) exchanges carry NO case (`case === undefined`) and are always `exec === 'submitted'`;
|
|
8
|
+
// `delivered`/`seen` are NOT case states — they are read-receipt facts on the inbox projection (Blocker 6).
|
|
9
|
+
import { canTaskTransition } from '@agenticprimitives/fulfillment';
|
|
10
|
+
export { canTaskTransition };
|
|
11
|
+
/** All 8 transport `ExecState`s (mirrors `fulfillment` `TaskState`), for coverage assertions. */
|
|
12
|
+
export const EXEC_STATES = [
|
|
13
|
+
'submitted', 'working', 'completed', 'failed', 'canceled', 'input-required', 'rejected', 'auth-required',
|
|
14
|
+
];
|
|
15
|
+
export const CASE_STATES = [
|
|
16
|
+
'draft', 'submitted', 'triaged', 'needs-info', 'approved', 'denied', 'issued', 'completed', 'expired', 'revoked', 'failed',
|
|
17
|
+
];
|
|
18
|
+
/**
|
|
19
|
+
* EXEC_CASE_COUPLING (spec 316 §2) — the canonical `ExecState` each `CaseState` maps to. Exhaustive over all
|
|
20
|
+
* 11 `CaseState`. Rationale per row:
|
|
21
|
+
* - `draft`/`submitted` → `submitted` : case created, pre-triage/local — accepted, not yet worked.
|
|
22
|
+
* - `triaged`/`approved` → `working` : responder actively working the request.
|
|
23
|
+
* - `needs-info` → `input-required` : the ONLY case → `input-required` (blocked awaiting requester;
|
|
24
|
+
* A2A `input-required` = blocked on the SENDER, so `triaged` must NOT map here).
|
|
25
|
+
* - `issued`/`completed` → `completed`.
|
|
26
|
+
* - `denied` → `rejected` : a rejected request is distinct from a failed task.
|
|
27
|
+
* - `expired`/`revoked`/`failed` → `failed` (canonical; `canceled` is the transport-set alternative).
|
|
28
|
+
*/
|
|
29
|
+
export const EXEC_CASE_COUPLING = {
|
|
30
|
+
draft: 'submitted',
|
|
31
|
+
submitted: 'submitted',
|
|
32
|
+
triaged: 'working',
|
|
33
|
+
'needs-info': 'input-required',
|
|
34
|
+
approved: 'working',
|
|
35
|
+
issued: 'completed',
|
|
36
|
+
completed: 'completed',
|
|
37
|
+
denied: 'rejected',
|
|
38
|
+
expired: 'failed',
|
|
39
|
+
revoked: 'failed',
|
|
40
|
+
failed: 'failed',
|
|
41
|
+
};
|
|
42
|
+
/**
|
|
43
|
+
* `ExecState`s set by the TRANSPORT/run layer, NOT derived from a `CaseState`:
|
|
44
|
+
* - `auth-required` — raised by a step-up/authority interrupt (`raiseInterrupt`) on an in-flight execution
|
|
45
|
+
* case; resolves back to `working`/`input-required` on `resume`.
|
|
46
|
+
* - `canceled` — an explicit withdrawal of a not-yet-terminal exchange, or a terminal for
|
|
47
|
+
* `expired`/`revoked`/`failed` cases.
|
|
48
|
+
* Both are consistent on any in-flight execution case (one with a defined `CaseState`); they are NOT
|
|
49
|
+
* "unmapped ⇒ reject". Together with the 6 case-derived exec values they cover all 8 `ExecState`s.
|
|
50
|
+
*/
|
|
51
|
+
export const TRANSPORT_SET_EXEC = ['auth-required', 'canceled'];
|
|
52
|
+
/** The exec envelope state expected for a given case. `undefined` case (T0 / pre-case delivery) ⇒ `submitted`. */
|
|
53
|
+
export function expectedExecForCase(caseState) {
|
|
54
|
+
if (caseState === undefined)
|
|
55
|
+
return 'submitted';
|
|
56
|
+
return EXEC_CASE_COUPLING[caseState];
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* True when an `(exec, case)` pair is coupling-consistent (spec 316 §2, fail-closed):
|
|
60
|
+
* - a transport-set exec (`auth-required`/`canceled`) is valid on any in-flight execution case (case defined),
|
|
61
|
+
* never on a case-less T0 exchange;
|
|
62
|
+
* - otherwise the case must map to EXACTLY this exec via `EXEC_CASE_COUPLING` (or `submitted` for no case).
|
|
63
|
+
* Any other pairing is inconsistent → the caller rejects (never silently drops).
|
|
64
|
+
*/
|
|
65
|
+
export function isExecCaseConsistent(exec, caseState) {
|
|
66
|
+
if (TRANSPORT_SET_EXEC.includes(exec))
|
|
67
|
+
return caseState !== undefined;
|
|
68
|
+
return expectedExecForCase(caseState) === exec;
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* `canExchangeTransition = canTaskTransition(exec) ∧ isExecCaseConsistent(to)` (spec 316 §2). NOTE: the case
|
|
72
|
+
* LIFECYCLE validity (e.g. `draft → submitted` legal, `completed → triaged` illegal) is enforced by the
|
|
73
|
+
* absorbed interactions case reducer, composed at the fabric level; this function enforces the transport
|
|
74
|
+
* transition + the exec/case coupling invariant. A `false` here is always a fail-closed rejection.
|
|
75
|
+
*/
|
|
76
|
+
export function canExchangeTransition(from, to) {
|
|
77
|
+
if (!canTaskTransition(from.exec, to.exec))
|
|
78
|
+
return false;
|
|
79
|
+
return isExecCaseConsistent(to.exec, to.case);
|
|
80
|
+
}
|
|
81
|
+
//# sourceMappingURL=exchange-state.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"exchange-state.js","sourceRoot":"","sources":["../src/exchange-state.ts"],"names":[],"mappings":"AAAA,2GAA2G;AAC3G,2GAA2G;AAC3G,4GAA4G;AAC5G,4GAA4G;AAC5G,gHAAgH;AAChH,EAAE;AACF,2GAA2G;AAC3G,4GAA4G;AAE5G,OAAO,EAAE,iBAAiB,EAAkB,MAAM,gCAAgC,CAAC;AAInF,OAAO,EAAE,iBAAiB,EAAE,CAAC;AAE7B,iGAAiG;AACjG,MAAM,CAAC,MAAM,WAAW,GAAyB;IAC/C,WAAW,EAAE,SAAS,EAAE,WAAW,EAAE,QAAQ,EAAE,UAAU,EAAE,gBAAgB,EAAE,UAAU,EAAE,eAAe;CAChG,CAAC;AASX,MAAM,CAAC,MAAM,WAAW,GAAyB;IAC/C,OAAO,EAAE,WAAW,EAAE,SAAS,EAAE,YAAY,EAAE,UAAU,EAAE,QAAQ,EAAE,QAAQ,EAAE,WAAW,EAAE,SAAS,EAAE,SAAS,EAAE,QAAQ;CAClH,CAAC;AAEX;;;;;;;;;;GAUG;AACH,MAAM,CAAC,MAAM,kBAAkB,GAAiC;IAC9D,KAAK,EAAE,WAAW;IAClB,SAAS,EAAE,WAAW;IACtB,OAAO,EAAE,SAAS;IAClB,YAAY,EAAE,gBAAgB;IAC9B,QAAQ,EAAE,SAAS;IACnB,MAAM,EAAE,WAAW;IACnB,SAAS,EAAE,WAAW;IACtB,MAAM,EAAE,UAAU;IAClB,OAAO,EAAE,QAAQ;IACjB,OAAO,EAAE,QAAQ;IACjB,MAAM,EAAE,QAAQ;CACjB,CAAC;AAEF;;;;;;;;GAQG;AACH,MAAM,CAAC,MAAM,kBAAkB,GAAyB,CAAC,eAAe,EAAE,UAAU,CAAU,CAAC;AAE/F,kHAAkH;AAClH,MAAM,UAAU,mBAAmB,CAAC,SAAgC;IAClE,IAAI,SAAS,KAAK,SAAS;QAAE,OAAO,WAAW,CAAC;IAChD,OAAO,kBAAkB,CAAC,SAAS,CAAC,CAAC;AACvC,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,oBAAoB,CAAC,IAAe,EAAE,SAAgC;IACpF,IAAI,kBAAkB,CAAC,QAAQ,CAAC,IAAI,CAAC;QAAE,OAAO,SAAS,KAAK,SAAS,CAAC;IACtE,OAAO,mBAAmB,CAAC,SAAS,CAAC,KAAK,IAAI,CAAC;AACjD,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,qBAAqB,CACnC,IAA2C,EAC3C,EAAyC;IAEzC,IAAI,CAAC,iBAAiB,CAAC,IAAI,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC;QAAE,OAAO,KAAK,CAAC;IACzD,OAAO,oBAAoB,CAAC,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,CAAC;AAChD,CAAC"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import type { CanonicalAgentId, Hex32 } from '@agenticprimitives/types';
|
|
2
|
+
import type { AuthorityTier } from '@agenticprimitives/tool-policy';
|
|
3
|
+
export interface GatewaySurfaceCommitmentV1 {
|
|
4
|
+
version: 'ap.gateway-surface.v1';
|
|
5
|
+
/** The gateway owner SA — the principal this surface serves. */
|
|
6
|
+
principal: CanonicalAgentId;
|
|
7
|
+
/** The origin serving this principal's gateway. Any origin ⇒ self-hostable (L1); the single-operator demo
|
|
8
|
+
* is a labeled convenience, not architecture. */
|
|
9
|
+
gatewayOrigin: string;
|
|
10
|
+
/** The DO-local delivery-receipt attestation pubkey (so peers can verify receipts before/without a fetch). */
|
|
11
|
+
receiptPubkey: string;
|
|
12
|
+
/** The authority tiers this gateway serves (communication / execution-fast / execution-orchestrated). */
|
|
13
|
+
tiers: AuthorityTier[];
|
|
14
|
+
/** Deployment epoch (spec 311) — a stale-surface guard; a peer rejects a commitment on a superseded epoch. */
|
|
15
|
+
epoch: string;
|
|
16
|
+
updatedAt: string;
|
|
17
|
+
}
|
|
18
|
+
export declare function buildGatewaySurfaceCommitment(input: Omit<GatewaySurfaceCommitmentV1, 'version'>): GatewaySurfaceCommitmentV1;
|
|
19
|
+
/** The `atl:gatewayRoot` value committed on-chain: sha256 of the canonical commitment (tiers sorted so order
|
|
20
|
+
* is not significant). This is the ONE on-chain point-read discovery anchor (§4.1). */
|
|
21
|
+
export declare function hashGatewaySurfaceCommitment(c: GatewaySurfaceCommitmentV1): Promise<Hex32>;
|
|
22
|
+
/** Verify a fetched commitment against the on-chain `gatewayRoot` (hash match). Fail-closed on any error. */
|
|
23
|
+
export declare function verifyGatewaySurfaceCommitment(c: GatewaySurfaceCommitmentV1, onchainGatewayRoot: Hex32): Promise<boolean>;
|
|
24
|
+
//# sourceMappingURL=gateway-surface.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"gateway-surface.d.ts","sourceRoot":"","sources":["../src/gateway-surface.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAAE,gBAAgB,EAAE,KAAK,EAAE,MAAM,0BAA0B,CAAC;AAExE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,gCAAgC,CAAC;AAGpE,MAAM,WAAW,0BAA0B;IACzC,OAAO,EAAE,uBAAuB,CAAC;IACjC,gEAAgE;IAChE,SAAS,EAAE,gBAAgB,CAAC;IAC5B;sDACkD;IAClD,aAAa,EAAE,MAAM,CAAC;IACtB,8GAA8G;IAC9G,aAAa,EAAE,MAAM,CAAC;IACtB,yGAAyG;IACzG,KAAK,EAAE,aAAa,EAAE,CAAC;IACvB,8GAA8G;IAC9G,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,wBAAgB,6BAA6B,CAC3C,KAAK,EAAE,IAAI,CAAC,0BAA0B,EAAE,SAAS,CAAC,GACjD,0BAA0B,CAM5B;AAED;wFACwF;AACxF,wBAAsB,4BAA4B,CAAC,CAAC,EAAE,0BAA0B,GAAG,OAAO,CAAC,KAAK,CAAC,CAYhG;AAED,6GAA6G;AAC7G,wBAAsB,8BAA8B,CAClD,CAAC,EAAE,0BAA0B,EAC7B,kBAAkB,EAAE,KAAK,GACxB,OAAO,CAAC,OAAO,CAAC,CAMlB"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { canonicalizeJson } from '@agenticprimitives/types';
|
|
2
|
+
import { sha256Hex32 } from './messaging/hash.js';
|
|
3
|
+
export function buildGatewaySurfaceCommitment(input) {
|
|
4
|
+
if (!input.principal || !input.gatewayOrigin) {
|
|
5
|
+
throw new Error('buildGatewaySurfaceCommitment: principal + gatewayOrigin required');
|
|
6
|
+
}
|
|
7
|
+
if (input.tiers.length === 0)
|
|
8
|
+
throw new Error('buildGatewaySurfaceCommitment: at least one tier required');
|
|
9
|
+
return { version: 'ap.gateway-surface.v1', ...input };
|
|
10
|
+
}
|
|
11
|
+
/** The `atl:gatewayRoot` value committed on-chain: sha256 of the canonical commitment (tiers sorted so order
|
|
12
|
+
* is not significant). This is the ONE on-chain point-read discovery anchor (§4.1). */
|
|
13
|
+
export async function hashGatewaySurfaceCommitment(c) {
|
|
14
|
+
return sha256Hex32(canonicalizeJson({
|
|
15
|
+
version: c.version,
|
|
16
|
+
principal: c.principal,
|
|
17
|
+
gatewayOrigin: c.gatewayOrigin,
|
|
18
|
+
receiptPubkey: c.receiptPubkey,
|
|
19
|
+
tiers: [...c.tiers].sort(),
|
|
20
|
+
epoch: c.epoch,
|
|
21
|
+
updatedAt: c.updatedAt,
|
|
22
|
+
}));
|
|
23
|
+
}
|
|
24
|
+
/** Verify a fetched commitment against the on-chain `gatewayRoot` (hash match). Fail-closed on any error. */
|
|
25
|
+
export async function verifyGatewaySurfaceCommitment(c, onchainGatewayRoot) {
|
|
26
|
+
try {
|
|
27
|
+
return (await hashGatewaySurfaceCommitment(c)) === onchainGatewayRoot;
|
|
28
|
+
}
|
|
29
|
+
catch {
|
|
30
|
+
return false;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
//# sourceMappingURL=gateway-surface.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"gateway-surface.js","sourceRoot":"","sources":["../src/gateway-surface.ts"],"names":[],"mappings":"AAWA,OAAO,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAC;AAE5D,OAAO,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAkBlD,MAAM,UAAU,6BAA6B,CAC3C,KAAkD;IAElD,IAAI,CAAC,KAAK,CAAC,SAAS,IAAI,CAAC,KAAK,CAAC,aAAa,EAAE,CAAC;QAC7C,MAAM,IAAI,KAAK,CAAC,mEAAmE,CAAC,CAAC;IACvF,CAAC;IACD,IAAI,KAAK,CAAC,KAAK,CAAC,MAAM,KAAK,CAAC;QAAE,MAAM,IAAI,KAAK,CAAC,2DAA2D,CAAC,CAAC;IAC3G,OAAO,EAAE,OAAO,EAAE,uBAAuB,EAAE,GAAG,KAAK,EAAE,CAAC;AACxD,CAAC;AAED;wFACwF;AACxF,MAAM,CAAC,KAAK,UAAU,4BAA4B,CAAC,CAA6B;IAC9E,OAAO,WAAW,CAChB,gBAAgB,CAAC;QACf,OAAO,EAAE,CAAC,CAAC,OAAO;QAClB,SAAS,EAAE,CAAC,CAAC,SAAS;QACtB,aAAa,EAAE,CAAC,CAAC,aAAa;QAC9B,aAAa,EAAE,CAAC,CAAC,aAAa;QAC9B,KAAK,EAAE,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,IAAI,EAAE;QAC1B,KAAK,EAAE,CAAC,CAAC,KAAK;QACd,SAAS,EAAE,CAAC,CAAC,SAAS;KACvB,CAAC,CACH,CAAC;AACJ,CAAC;AAED,6GAA6G;AAC7G,MAAM,CAAC,KAAK,UAAU,8BAA8B,CAClD,CAA6B,EAC7B,kBAAyB;IAEzB,IAAI,CAAC;QACH,OAAO,CAAC,MAAM,4BAA4B,CAAC,CAAC,CAAC,CAAC,KAAK,kBAAkB,CAAC;IACxE,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { type ContextRefV1, type ConversationDescriptorV1, type InboxProjector, type MessageEnvelopeV1, type MessageEventV1 } from './messaging/index.js';
|
|
2
|
+
import { type ActionCardV1, type InteractionCaseV1, type InteractionMandateV1, type InteractionStore, type InteractionTransitionEventV1 } from './interactions/index.js';
|
|
3
|
+
export interface InboxDataV1 {
|
|
4
|
+
version: 1;
|
|
5
|
+
envelopes: MessageEnvelopeV1[];
|
|
6
|
+
events: MessageEventV1[];
|
|
7
|
+
/** Cases as they entered (draft) — current state is replayed from caseEvents. */
|
|
8
|
+
draftCases: InteractionCaseV1[];
|
|
9
|
+
caseEvents: InteractionTransitionEventV1[];
|
|
10
|
+
/** interactionId → sender-proposed transport card (render half is the app's). */
|
|
11
|
+
cards: Record<string, ActionCardV1>;
|
|
12
|
+
/** interactionId → the signed mandate the owner issued on approve (spec 310 W5). */
|
|
13
|
+
mandates?: Record<string, InteractionMandateV1>;
|
|
14
|
+
/** Owner-side conversation descriptors (spec 312) — this side's copies. */
|
|
15
|
+
conversations?: ConversationDescriptorV1[];
|
|
16
|
+
}
|
|
17
|
+
export declare function emptyInboxData(): InboxDataV1;
|
|
18
|
+
/** Parse a persisted doc, dropping the legacy pre-cutover `bodies` key (dead storage, never re-read). */
|
|
19
|
+
export declare function parseInboxData(raw: string): InboxDataV1;
|
|
20
|
+
/** Rebuild the in-memory stores by replay — same events, same projection, any app. */
|
|
21
|
+
export declare function hydrateInboxStores(streamId: string, doc: InboxDataV1): {
|
|
22
|
+
projector: InboxProjector;
|
|
23
|
+
interactions: InteractionStore;
|
|
24
|
+
};
|
|
25
|
+
/** Union `refs` into the descriptor's contextRefs by `kind:id`. Returns true when anything was added.
|
|
26
|
+
* This is what keeps a long-running thread honest: a NEW context (e.g. a second org's invite) is
|
|
27
|
+
* appended, never dropped and never allowed to overwrite the first. */
|
|
28
|
+
export declare function mergeContextRefs(descriptor: ConversationDescriptorV1, refs: ContextRefV1[] | undefined): boolean;
|
|
29
|
+
/** Insert the owner's copy of a conversation descriptor: first descriptor WINS for this owner
|
|
30
|
+
* (later proposals never overwrite) — except contextRefs, which union (see mergeContextRefs). */
|
|
31
|
+
export declare function upsertConversation(doc: InboxDataV1, descriptor: ConversationDescriptorV1): void;
|
|
32
|
+
//# sourceMappingURL=inbox-doc.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"inbox-doc.d.ts","sourceRoot":"","sources":["../src/inbox-doc.ts"],"names":[],"mappings":"AAKA,OAAO,EAEL,KAAK,YAAY,EACjB,KAAK,wBAAwB,EAC7B,KAAK,cAAc,EACnB,KAAK,iBAAiB,EACtB,KAAK,cAAc,EACpB,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EAEL,KAAK,YAAY,EACjB,KAAK,iBAAiB,EACtB,KAAK,oBAAoB,EACzB,KAAK,gBAAgB,EACrB,KAAK,4BAA4B,EAClC,MAAM,yBAAyB,CAAC;AAEjC,MAAM,WAAW,WAAW;IAC1B,OAAO,EAAE,CAAC,CAAC;IACX,SAAS,EAAE,iBAAiB,EAAE,CAAC;IAC/B,MAAM,EAAE,cAAc,EAAE,CAAC;IACzB,iFAAiF;IACjF,UAAU,EAAE,iBAAiB,EAAE,CAAC;IAChC,UAAU,EAAE,4BAA4B,EAAE,CAAC;IAC3C,iFAAiF;IACjF,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC;IACpC,oFAAoF;IACpF,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,oBAAoB,CAAC,CAAC;IAChD,2EAA2E;IAC3E,aAAa,CAAC,EAAE,wBAAwB,EAAE,CAAC;CAE5C;AAED,wBAAgB,cAAc,IAAI,WAAW,CAE5C;AAED,yGAAyG;AACzG,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,GAAG,WAAW,CAGvD;AAED,sFAAsF;AACtF,wBAAgB,kBAAkB,CAAC,QAAQ,EAAE,MAAM,EAAE,GAAG,EAAE,WAAW,GAAG;IAAE,SAAS,EAAE,cAAc,CAAC;IAAC,YAAY,EAAE,gBAAgB,CAAA;CAAE,CAYpI;AAED;;wEAEwE;AACxE,wBAAgB,gBAAgB,CAAC,UAAU,EAAE,wBAAwB,EAAE,IAAI,EAAE,YAAY,EAAE,GAAG,SAAS,GAAG,OAAO,CAOhH;AAED;kGACkG;AAClG,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,WAAW,EAAE,UAAU,EAAE,wBAAwB,GAAG,IAAI,CAQ/F"}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
// The event-sourced INBOX DOCUMENT (spec 322 W1) — the one JSON record an owner's inbox persists to
|
|
2
|
+
// (`inbox.data` in the owner's vault). Extracted from the Home app so EVERY app renders/mutates the
|
|
3
|
+
// same doc through the same pure operations: the Home is one client of this substrate, never its
|
|
4
|
+
// definition. Storage (which vault/KV, which key) and side effects (audit, body stores) stay with the
|
|
5
|
+
// caller — this module is pure shape + replay + mutation.
|
|
6
|
+
import { createInMemoryInboxProjector, } from './messaging/index.js';
|
|
7
|
+
import { createInMemoryInteractionStore, } from './interactions/index.js';
|
|
8
|
+
export function emptyInboxData() {
|
|
9
|
+
return { version: 1, envelopes: [], events: [], draftCases: [], caseEvents: [], cards: {} };
|
|
10
|
+
}
|
|
11
|
+
/** Parse a persisted doc, dropping the legacy pre-cutover `bodies` key (dead storage, never re-read). */
|
|
12
|
+
export function parseInboxData(raw) {
|
|
13
|
+
const { bodies: _legacyBodies, ...doc } = JSON.parse(raw);
|
|
14
|
+
return doc;
|
|
15
|
+
}
|
|
16
|
+
/** Rebuild the in-memory stores by replay — same events, same projection, any app. */
|
|
17
|
+
export function hydrateInboxStores(streamId, doc) {
|
|
18
|
+
const projector = createInMemoryInboxProjector({ streamId });
|
|
19
|
+
for (const envelope of doc.envelopes)
|
|
20
|
+
projector.putMessage(envelope);
|
|
21
|
+
for (const event of doc.events)
|
|
22
|
+
projector.appendEvent(event);
|
|
23
|
+
const interactions = createInMemoryInteractionStore();
|
|
24
|
+
for (const c of doc.draftCases)
|
|
25
|
+
interactions.putCase(c);
|
|
26
|
+
for (const e of doc.caseEvents) {
|
|
27
|
+
const r = interactions.applyEvent(e);
|
|
28
|
+
if (!r.ok)
|
|
29
|
+
throw new Error(`inbox replay diverged for ${e.interactionId}: ${r.reason}`);
|
|
30
|
+
}
|
|
31
|
+
return { projector, interactions };
|
|
32
|
+
}
|
|
33
|
+
/** Union `refs` into the descriptor's contextRefs by `kind:id`. Returns true when anything was added.
|
|
34
|
+
* This is what keeps a long-running thread honest: a NEW context (e.g. a second org's invite) is
|
|
35
|
+
* appended, never dropped and never allowed to overwrite the first. */
|
|
36
|
+
export function mergeContextRefs(descriptor, refs) {
|
|
37
|
+
if (!refs?.length)
|
|
38
|
+
return false;
|
|
39
|
+
const seen = new Set((descriptor.contextRefs ?? []).map((r) => `${r.kind}:${r.id}`));
|
|
40
|
+
const fresh = refs.filter((r) => !seen.has(`${r.kind}:${r.id}`));
|
|
41
|
+
if (!fresh.length)
|
|
42
|
+
return false;
|
|
43
|
+
descriptor.contextRefs = [...(descriptor.contextRefs ?? []), ...fresh];
|
|
44
|
+
return true;
|
|
45
|
+
}
|
|
46
|
+
/** Insert the owner's copy of a conversation descriptor: first descriptor WINS for this owner
|
|
47
|
+
* (later proposals never overwrite) — except contextRefs, which union (see mergeContextRefs). */
|
|
48
|
+
export function upsertConversation(doc, descriptor) {
|
|
49
|
+
const existing = doc.conversations ?? [];
|
|
50
|
+
const prior = existing.find((d) => d.id === descriptor.id);
|
|
51
|
+
if (!prior) {
|
|
52
|
+
doc.conversations = [...existing, descriptor];
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
55
|
+
mergeContextRefs(prior, descriptor.contextRefs);
|
|
56
|
+
}
|
|
57
|
+
//# sourceMappingURL=inbox-doc.js.map
|