@agirails/sdk 4.4.9 → 4.5.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/builders/DeliveryProofBuilder.d.ts +224 -13
- package/dist/builders/DeliveryProofBuilder.d.ts.map +1 -1
- package/dist/builders/DeliveryProofBuilder.js +247 -13
- package/dist/builders/DeliveryProofBuilder.js.map +1 -1
- package/dist/cli/agirails.d.ts +85 -1
- package/dist/cli/agirails.d.ts.map +1 -1
- package/dist/cli/agirails.js +429 -154
- package/dist/cli/agirails.js.map +1 -1
- package/dist/cli/commands/init.d.ts +54 -0
- package/dist/cli/commands/init.d.ts.map +1 -1
- package/dist/cli/commands/init.js +193 -1
- package/dist/cli/commands/init.js.map +1 -1
- package/dist/cli/commands/receipt.d.ts +70 -2
- package/dist/cli/commands/receipt.d.ts.map +1 -1
- package/dist/cli/commands/receipt.js +218 -3
- package/dist/cli/commands/receipt.js.map +1 -1
- package/dist/cli/commands/test.d.ts +77 -1
- package/dist/cli/commands/test.d.ts.map +1 -1
- package/dist/cli/commands/test.js +264 -2
- package/dist/cli/commands/test.js.map +1 -1
- package/dist/cli/lib/runRequest.d.ts +90 -0
- package/dist/cli/lib/runRequest.d.ts.map +1 -1
- package/dist/cli/lib/runRequest.js +300 -9
- package/dist/cli/lib/runRequest.js.map +1 -1
- package/dist/cli/lib/sentinelReflections.d.ts +111 -0
- package/dist/cli/lib/sentinelReflections.d.ts.map +1 -0
- package/dist/cli/lib/sentinelReflections.js +193 -0
- package/dist/cli/lib/sentinelReflections.js.map +1 -0
- package/dist/delivery/MockDeliveryChannel.d.ts +208 -0
- package/dist/delivery/MockDeliveryChannel.d.ts.map +1 -0
- package/dist/delivery/MockDeliveryChannel.js +445 -0
- package/dist/delivery/MockDeliveryChannel.js.map +1 -0
- package/dist/delivery/RelayDeliveryChannel.d.ts +176 -0
- package/dist/delivery/RelayDeliveryChannel.d.ts.map +1 -0
- package/dist/delivery/RelayDeliveryChannel.js +377 -0
- package/dist/delivery/RelayDeliveryChannel.js.map +1 -0
- package/dist/delivery/channel.d.ts +282 -0
- package/dist/delivery/channel.d.ts.map +1 -0
- package/dist/delivery/channel.js +76 -0
- package/dist/delivery/channel.js.map +1 -0
- package/dist/delivery/channelLog.d.ts +115 -0
- package/dist/delivery/channelLog.d.ts.map +1 -0
- package/dist/delivery/channelLog.js +94 -0
- package/dist/delivery/channelLog.js.map +1 -0
- package/dist/delivery/crypto.d.ts +312 -0
- package/dist/delivery/crypto.d.ts.map +1 -0
- package/dist/delivery/crypto.js +495 -0
- package/dist/delivery/crypto.js.map +1 -0
- package/dist/delivery/eip712.d.ts +248 -0
- package/dist/delivery/eip712.d.ts.map +1 -0
- package/dist/delivery/eip712.js +397 -0
- package/dist/delivery/eip712.js.map +1 -0
- package/dist/delivery/envelopeBuilder.d.ts +531 -0
- package/dist/delivery/envelopeBuilder.d.ts.map +1 -0
- package/dist/delivery/envelopeBuilder.js +832 -0
- package/dist/delivery/envelopeBuilder.js.map +1 -0
- package/dist/delivery/index.d.ts +53 -0
- package/dist/delivery/index.d.ts.map +1 -0
- package/dist/delivery/index.js +143 -0
- package/dist/delivery/index.js.map +1 -0
- package/dist/delivery/keys.d.ts +344 -0
- package/dist/delivery/keys.d.ts.map +1 -0
- package/dist/delivery/keys.js +513 -0
- package/dist/delivery/keys.js.map +1 -0
- package/dist/delivery/nonce-keys.d.ts +93 -0
- package/dist/delivery/nonce-keys.d.ts.map +1 -0
- package/dist/delivery/nonce-keys.js +88 -0
- package/dist/delivery/nonce-keys.js.map +1 -0
- package/dist/delivery/setupBuilder.d.ts +403 -0
- package/dist/delivery/setupBuilder.d.ts.map +1 -0
- package/dist/delivery/setupBuilder.js +554 -0
- package/dist/delivery/setupBuilder.js.map +1 -0
- package/dist/delivery/types.d.ts +722 -0
- package/dist/delivery/types.d.ts.map +1 -0
- package/dist/delivery/types.js +150 -0
- package/dist/delivery/types.js.map +1 -0
- package/dist/delivery/validate.d.ts +288 -0
- package/dist/delivery/validate.d.ts.map +1 -0
- package/dist/delivery/validate.js +648 -0
- package/dist/delivery/validate.js.map +1 -0
- package/dist/level1/Agent.d.ts +130 -0
- package/dist/level1/Agent.d.ts.map +1 -1
- package/dist/level1/Agent.js +248 -0
- package/dist/level1/Agent.js.map +1 -1
- package/dist/level1/types/Options.d.ts +62 -0
- package/dist/level1/types/Options.d.ts.map +1 -1
- package/dist/level1/types/Options.js +22 -0
- package/dist/level1/types/Options.js.map +1 -1
- package/dist/runtime/MockRuntime.d.ts +32 -0
- package/dist/runtime/MockRuntime.d.ts.map +1 -1
- package/dist/runtime/MockRuntime.js +44 -0
- package/dist/runtime/MockRuntime.js.map +1 -1
- package/package.json +6 -1
|
@@ -0,0 +1,445 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* AIP-16 Delivery Surface — MockDeliveryChannel (Phase 2b)
|
|
4
|
+
* =========================================================
|
|
5
|
+
*
|
|
6
|
+
* In-process loopback {@link DeliveryChannel} implementation used by
|
|
7
|
+
* unit tests and `MockRuntime` flows. Both parties of an AIP-16
|
|
8
|
+
* delivery exchange share a single MockDeliveryChannel instance and
|
|
9
|
+
* exchange already-signed wire objects without any network transport.
|
|
10
|
+
*
|
|
11
|
+
* Verification is performed in-channel — the same builder `verify()`
|
|
12
|
+
* methods that `RelayDeliveryChannel` consumers run on read — so
|
|
13
|
+
* security regression tests using the mock exercise the same code
|
|
14
|
+
* paths as production deployments.
|
|
15
|
+
*
|
|
16
|
+
* ## Critical security invariants (mirror MockChannel / RelayChannel)
|
|
17
|
+
*
|
|
18
|
+
* 1. **Dedup AFTER verify.** A signature is added to a txId's dedup
|
|
19
|
+
* set ONLY after the signature has been verified. Otherwise an
|
|
20
|
+
* attacker who replays a malformed payload with a stolen signature
|
|
21
|
+
* could poison the dedup set — the later legitimate signed object
|
|
22
|
+
* would be silently dropped because its identifier was already
|
|
23
|
+
* "seen". This is identical to the ordering used in
|
|
24
|
+
* `src/negotiation/MockChannel.ts` ~line 189.
|
|
25
|
+
*
|
|
26
|
+
* 2. **Subscriber error isolation.** Subscriber callbacks may throw
|
|
27
|
+
* synchronously or asynchronously. Every invocation is wrapped in
|
|
28
|
+
* `Promise.resolve(...).catch(...)` so one bad subscriber can never
|
|
29
|
+
* halt fan-out to peer subscribers and cannot propagate up into
|
|
30
|
+
* the channel's publish loop.
|
|
31
|
+
*
|
|
32
|
+
* 3. **Replay on subscribe.** Subscribers receive the FULL historical
|
|
33
|
+
* set of already-published wire objects for the subscribed `txId`
|
|
34
|
+
* before any future objects fire. This matches the test-ergonomic
|
|
35
|
+
* behavior of `MockChannel`: tests can publish first then subscribe
|
|
36
|
+
* and still see what was posted. Each callback maintains its own
|
|
37
|
+
* per-subscription `delivered` set so a replay does not double-fire
|
|
38
|
+
* and so a slow subscriber can stagger its consumption without
|
|
39
|
+
* missing messages.
|
|
40
|
+
*
|
|
41
|
+
* 4. **Address comparison case-insensitivity.** All comparisons that
|
|
42
|
+
* touch addresses (none directly in this file — verification is
|
|
43
|
+
* delegated to builders which already lowercase both sides) are
|
|
44
|
+
* case-insensitive by construction.
|
|
45
|
+
*
|
|
46
|
+
* ## Verification opts derivation
|
|
47
|
+
*
|
|
48
|
+
* Verification calls `DeliverySetupBuilder.verify` / `DeliveryEnvelopeBuilder.verify`
|
|
49
|
+
* with `{ expectedKernelAddress, expectedChainId, now }`. The resolution
|
|
50
|
+
* order is:
|
|
51
|
+
*
|
|
52
|
+
* - `expectedKernelAddress`: `opts.expectedKernelAddress` if set, else
|
|
53
|
+
* `signed.kernelAddress` (the wire's self-asserted kernel).
|
|
54
|
+
* - `expectedChainId`: `opts.expectedChainId` if set, else
|
|
55
|
+
* `signed.chainId`.
|
|
56
|
+
* - `now`: `opts.now?.()` if set, else the builder's default (which
|
|
57
|
+
* reads its own injectable clock).
|
|
58
|
+
*
|
|
59
|
+
* Using the wire's self-asserted values is intentional for the *mock*
|
|
60
|
+
* — tests typically don't care to plumb an explicit kernel address per
|
|
61
|
+
* channel instance and want the channel to "just accept" whatever the
|
|
62
|
+
* test signed. Tests that DO want allowlist enforcement pass
|
|
63
|
+
* `expectedKernelAddress` / `expectedChainId` explicitly.
|
|
64
|
+
*
|
|
65
|
+
* @module delivery/MockDeliveryChannel
|
|
66
|
+
* @see {@link DeliveryChannel}
|
|
67
|
+
* @see {@link DeliverySetupBuilder.verify}
|
|
68
|
+
* @see {@link DeliveryEnvelopeBuilder.verify}
|
|
69
|
+
*/
|
|
70
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
71
|
+
exports.MockDeliveryChannel = void 0;
|
|
72
|
+
const setupBuilder_1 = require("./setupBuilder");
|
|
73
|
+
const envelopeBuilder_1 = require("./envelopeBuilder");
|
|
74
|
+
const channelLog_1 = require("./channelLog");
|
|
75
|
+
// ============================================================================
|
|
76
|
+
// MockDeliveryChannel
|
|
77
|
+
// ============================================================================
|
|
78
|
+
/**
|
|
79
|
+
* In-process loopback delivery channel.
|
|
80
|
+
*
|
|
81
|
+
* Two parties (or any number) share a single instance and exchange
|
|
82
|
+
* wire objects via `publishSetup` / `publishEnvelope` / `subscribe*`.
|
|
83
|
+
* No network transport.
|
|
84
|
+
*
|
|
85
|
+
* @example
|
|
86
|
+
* ```typescript
|
|
87
|
+
* const channel = new MockDeliveryChannel();
|
|
88
|
+
*
|
|
89
|
+
* // Provider subscribes for setups on a txId.
|
|
90
|
+
* const sub = await channel.subscribeSetups(txId, async (wire) => {
|
|
91
|
+
* // wire has already been verified by the channel.
|
|
92
|
+
* await onSetup(wire);
|
|
93
|
+
* });
|
|
94
|
+
*
|
|
95
|
+
* // Requester publishes the setup.
|
|
96
|
+
* await channel.publishSetup(setupWire);
|
|
97
|
+
*
|
|
98
|
+
* // …later
|
|
99
|
+
* await sub.close();
|
|
100
|
+
* channel.close();
|
|
101
|
+
* ```
|
|
102
|
+
*/
|
|
103
|
+
class MockDeliveryChannel {
|
|
104
|
+
constructor(opts = {}) {
|
|
105
|
+
this.setupStoreByTxId = new Map();
|
|
106
|
+
this.envelopeStoreByTxId = new Map();
|
|
107
|
+
this.setupSubscribersByTxId = new Map();
|
|
108
|
+
this.envelopeSubscribersByTxId = new Map();
|
|
109
|
+
this.closed = false;
|
|
110
|
+
this.log = opts.log ?? channelLog_1.noopLog;
|
|
111
|
+
this.skipVerifyForTests = opts.skipVerifyForTests ?? false;
|
|
112
|
+
this.expectedKernelAddress = opts.expectedKernelAddress;
|
|
113
|
+
this.expectedChainId = opts.expectedChainId;
|
|
114
|
+
this.nowFn = opts.now;
|
|
115
|
+
}
|
|
116
|
+
// --------------------------------------------------------------------------
|
|
117
|
+
// publish
|
|
118
|
+
// --------------------------------------------------------------------------
|
|
119
|
+
async publishSetup(setup) {
|
|
120
|
+
if (this.closed) {
|
|
121
|
+
throw new Error('MockDeliveryChannel: channel is closed');
|
|
122
|
+
}
|
|
123
|
+
// Step 1: verify (unless explicitly disabled for tests).
|
|
124
|
+
if (!this.skipVerifyForTests) {
|
|
125
|
+
const verifyResult = setupBuilder_1.DeliverySetupBuilder.verify(setup, {
|
|
126
|
+
expectedKernelAddress: this.expectedKernelAddress ?? setup.signed.kernelAddress,
|
|
127
|
+
expectedChainId: this.expectedChainId ?? setup.signed.chainId,
|
|
128
|
+
now: this.nowFn?.(),
|
|
129
|
+
});
|
|
130
|
+
if (!verifyResult.ok) {
|
|
131
|
+
this.log('warn', 'MockDeliveryChannel: setup verify failed', {
|
|
132
|
+
code: verifyResult.code,
|
|
133
|
+
error: verifyResult.error,
|
|
134
|
+
txId: setup.signed.txId,
|
|
135
|
+
});
|
|
136
|
+
const err = new Error(`MockDeliveryChannel: setup verify failed: ${verifyResult.code}: ${verifyResult.error}`);
|
|
137
|
+
err.code = verifyResult.code;
|
|
138
|
+
throw err;
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
// Step 2: dedup hash (computed AFTER verify succeeded — see security
|
|
142
|
+
// invariant #1 in the module header).
|
|
143
|
+
const hash = setupBuilder_1.DeliverySetupBuilder.computeHash(setup);
|
|
144
|
+
const txId = setup.signed.txId.toLowerCase();
|
|
145
|
+
let store = this.setupStoreByTxId.get(txId);
|
|
146
|
+
if (!store) {
|
|
147
|
+
store = { setups: [], dedup: new Set() };
|
|
148
|
+
this.setupStoreByTxId.set(txId, store);
|
|
149
|
+
}
|
|
150
|
+
if (store.dedup.has(hash)) {
|
|
151
|
+
// Idempotent: re-publishing the same wire is a no-op. Not a
|
|
152
|
+
// warning — duplicate publish under retry semantics is normal.
|
|
153
|
+
return;
|
|
154
|
+
}
|
|
155
|
+
store.dedup.add(hash);
|
|
156
|
+
store.setups.push(setup);
|
|
157
|
+
// Step 3: fan out asynchronously so publish() resolves before any
|
|
158
|
+
// subscriber callback runs (mirrors RelayChannel's poll-tick
|
|
159
|
+
// boundary). Errors thrown by subscribers are isolated.
|
|
160
|
+
this.fanoutSetup(txId, setup);
|
|
161
|
+
}
|
|
162
|
+
async publishEnvelope(envelope) {
|
|
163
|
+
if (this.closed) {
|
|
164
|
+
throw new Error('MockDeliveryChannel: channel is closed');
|
|
165
|
+
}
|
|
166
|
+
if (!this.skipVerifyForTests) {
|
|
167
|
+
const verifyResult = envelopeBuilder_1.DeliveryEnvelopeBuilder.verify(envelope, {
|
|
168
|
+
expectedKernelAddress: this.expectedKernelAddress ?? envelope.signed.kernelAddress,
|
|
169
|
+
expectedChainId: this.expectedChainId ?? envelope.signed.chainId,
|
|
170
|
+
now: this.nowFn?.(),
|
|
171
|
+
});
|
|
172
|
+
if (!verifyResult.ok) {
|
|
173
|
+
this.log('warn', 'MockDeliveryChannel: envelope verify failed', {
|
|
174
|
+
code: verifyResult.code,
|
|
175
|
+
error: verifyResult.error,
|
|
176
|
+
txId: envelope.signed.txId,
|
|
177
|
+
});
|
|
178
|
+
const err = new Error(`MockDeliveryChannel: envelope verify failed: ${verifyResult.code}: ${verifyResult.error}`);
|
|
179
|
+
err.code = verifyResult.code;
|
|
180
|
+
throw err;
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
const hash = envelopeBuilder_1.DeliveryEnvelopeBuilder.computeHash(envelope);
|
|
184
|
+
const txId = envelope.signed.txId.toLowerCase();
|
|
185
|
+
let store = this.envelopeStoreByTxId.get(txId);
|
|
186
|
+
if (!store) {
|
|
187
|
+
store = { envelopes: [], dedup: new Set() };
|
|
188
|
+
this.envelopeStoreByTxId.set(txId, store);
|
|
189
|
+
}
|
|
190
|
+
if (store.dedup.has(hash)) {
|
|
191
|
+
return;
|
|
192
|
+
}
|
|
193
|
+
store.dedup.add(hash);
|
|
194
|
+
store.envelopes.push(envelope);
|
|
195
|
+
this.fanoutEnvelope(txId, envelope);
|
|
196
|
+
}
|
|
197
|
+
// --------------------------------------------------------------------------
|
|
198
|
+
// subscribe
|
|
199
|
+
// --------------------------------------------------------------------------
|
|
200
|
+
async subscribeSetups(txId, callback) {
|
|
201
|
+
if (this.closed) {
|
|
202
|
+
throw new Error('MockDeliveryChannel: channel is closed');
|
|
203
|
+
}
|
|
204
|
+
const txIdLc = txId.toLowerCase();
|
|
205
|
+
const sub = {
|
|
206
|
+
callback,
|
|
207
|
+
delivered: new Set(),
|
|
208
|
+
cancelled: false,
|
|
209
|
+
};
|
|
210
|
+
let subs = this.setupSubscribersByTxId.get(txIdLc);
|
|
211
|
+
if (!subs) {
|
|
212
|
+
subs = new Set();
|
|
213
|
+
this.setupSubscribersByTxId.set(txIdLc, subs);
|
|
214
|
+
}
|
|
215
|
+
subs.add(sub);
|
|
216
|
+
// Replay-on-subscribe: schedule on next microtask so subscribe()
|
|
217
|
+
// returns the handle BEFORE any callback fires (mirrors MockChannel
|
|
218
|
+
// semantics — callers can rely on `const s = await subscribe(...);
|
|
219
|
+
// s.close()` being effective for messages they haven't yet processed).
|
|
220
|
+
const store = this.setupStoreByTxId.get(txIdLc);
|
|
221
|
+
if (store) {
|
|
222
|
+
const snapshot = store.setups.slice();
|
|
223
|
+
queueMicrotask(() => {
|
|
224
|
+
if (sub.cancelled)
|
|
225
|
+
return;
|
|
226
|
+
for (const wire of snapshot) {
|
|
227
|
+
if (sub.cancelled)
|
|
228
|
+
break;
|
|
229
|
+
this.deliverSetup(sub, wire);
|
|
230
|
+
}
|
|
231
|
+
});
|
|
232
|
+
}
|
|
233
|
+
return {
|
|
234
|
+
close: () => {
|
|
235
|
+
sub.cancelled = true;
|
|
236
|
+
const currentSubs = this.setupSubscribersByTxId.get(txIdLc);
|
|
237
|
+
if (currentSubs) {
|
|
238
|
+
currentSubs.delete(sub);
|
|
239
|
+
if (currentSubs.size === 0) {
|
|
240
|
+
this.setupSubscribersByTxId.delete(txIdLc);
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
},
|
|
244
|
+
};
|
|
245
|
+
}
|
|
246
|
+
async subscribeEnvelopes(txId, callback) {
|
|
247
|
+
if (this.closed) {
|
|
248
|
+
throw new Error('MockDeliveryChannel: channel is closed');
|
|
249
|
+
}
|
|
250
|
+
const txIdLc = txId.toLowerCase();
|
|
251
|
+
const sub = {
|
|
252
|
+
callback,
|
|
253
|
+
delivered: new Set(),
|
|
254
|
+
cancelled: false,
|
|
255
|
+
};
|
|
256
|
+
let subs = this.envelopeSubscribersByTxId.get(txIdLc);
|
|
257
|
+
if (!subs) {
|
|
258
|
+
subs = new Set();
|
|
259
|
+
this.envelopeSubscribersByTxId.set(txIdLc, subs);
|
|
260
|
+
}
|
|
261
|
+
subs.add(sub);
|
|
262
|
+
const store = this.envelopeStoreByTxId.get(txIdLc);
|
|
263
|
+
if (store) {
|
|
264
|
+
const snapshot = store.envelopes.slice();
|
|
265
|
+
queueMicrotask(() => {
|
|
266
|
+
if (sub.cancelled)
|
|
267
|
+
return;
|
|
268
|
+
for (const wire of snapshot) {
|
|
269
|
+
if (sub.cancelled)
|
|
270
|
+
break;
|
|
271
|
+
this.deliverEnvelope(sub, wire);
|
|
272
|
+
}
|
|
273
|
+
});
|
|
274
|
+
}
|
|
275
|
+
return {
|
|
276
|
+
close: () => {
|
|
277
|
+
sub.cancelled = true;
|
|
278
|
+
const currentSubs = this.envelopeSubscribersByTxId.get(txIdLc);
|
|
279
|
+
if (currentSubs) {
|
|
280
|
+
currentSubs.delete(sub);
|
|
281
|
+
if (currentSubs.size === 0) {
|
|
282
|
+
this.envelopeSubscribersByTxId.delete(txIdLc);
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
},
|
|
286
|
+
};
|
|
287
|
+
}
|
|
288
|
+
// --------------------------------------------------------------------------
|
|
289
|
+
// Snapshot accessors (DeliveryChannel interface)
|
|
290
|
+
// --------------------------------------------------------------------------
|
|
291
|
+
async getSetups(txId) {
|
|
292
|
+
return this.getAllSetups(txId);
|
|
293
|
+
}
|
|
294
|
+
async getEnvelopes(txId) {
|
|
295
|
+
return this.getAllEnvelopes(txId);
|
|
296
|
+
}
|
|
297
|
+
// --------------------------------------------------------------------------
|
|
298
|
+
// Test helpers (NOT part of DeliveryChannel)
|
|
299
|
+
// --------------------------------------------------------------------------
|
|
300
|
+
/**
|
|
301
|
+
* Synchronous snapshot of all setups currently stored for `txId`,
|
|
302
|
+
* or all setups across every txId when `txId` is omitted. Returns a
|
|
303
|
+
* defensive copy.
|
|
304
|
+
*/
|
|
305
|
+
getAllSetups(txId) {
|
|
306
|
+
if (txId === undefined) {
|
|
307
|
+
const out = [];
|
|
308
|
+
for (const store of this.setupStoreByTxId.values()) {
|
|
309
|
+
out.push(...store.setups);
|
|
310
|
+
}
|
|
311
|
+
return out;
|
|
312
|
+
}
|
|
313
|
+
const store = this.setupStoreByTxId.get(txId.toLowerCase());
|
|
314
|
+
return store ? store.setups.slice() : [];
|
|
315
|
+
}
|
|
316
|
+
/**
|
|
317
|
+
* Synchronous snapshot of all envelopes currently stored for `txId`,
|
|
318
|
+
* or all envelopes across every txId when `txId` is omitted. Returns
|
|
319
|
+
* a defensive copy.
|
|
320
|
+
*/
|
|
321
|
+
getAllEnvelopes(txId) {
|
|
322
|
+
if (txId === undefined) {
|
|
323
|
+
const out = [];
|
|
324
|
+
for (const store of this.envelopeStoreByTxId.values()) {
|
|
325
|
+
out.push(...store.envelopes);
|
|
326
|
+
}
|
|
327
|
+
return out;
|
|
328
|
+
}
|
|
329
|
+
const store = this.envelopeStoreByTxId.get(txId.toLowerCase());
|
|
330
|
+
return store ? store.envelopes.slice() : [];
|
|
331
|
+
}
|
|
332
|
+
/**
|
|
333
|
+
* Count of currently-active subscriptions (setup + envelope combined).
|
|
334
|
+
* Useful for leak tests.
|
|
335
|
+
*/
|
|
336
|
+
activeSubscriptionCount() {
|
|
337
|
+
let n = 0;
|
|
338
|
+
for (const subs of this.setupSubscribersByTxId.values())
|
|
339
|
+
n += subs.size;
|
|
340
|
+
for (const subs of this.envelopeSubscribersByTxId.values())
|
|
341
|
+
n += subs.size;
|
|
342
|
+
return n;
|
|
343
|
+
}
|
|
344
|
+
/**
|
|
345
|
+
* Reset all stored state. Does NOT touch subscriber lists — existing
|
|
346
|
+
* subscribers remain registered for future publishes.
|
|
347
|
+
*/
|
|
348
|
+
clear() {
|
|
349
|
+
this.setupStoreByTxId.clear();
|
|
350
|
+
this.envelopeStoreByTxId.clear();
|
|
351
|
+
}
|
|
352
|
+
/**
|
|
353
|
+
* Mark all current subscriptions cancelled and drop them. Storage is
|
|
354
|
+
* preserved so tests can still assert on what was published. Future
|
|
355
|
+
* `publish*` / `subscribe*` calls reject with a closed-channel error.
|
|
356
|
+
*/
|
|
357
|
+
close() {
|
|
358
|
+
if (this.closed)
|
|
359
|
+
return;
|
|
360
|
+
this.closed = true;
|
|
361
|
+
for (const subs of this.setupSubscribersByTxId.values()) {
|
|
362
|
+
for (const s of subs)
|
|
363
|
+
s.cancelled = true;
|
|
364
|
+
}
|
|
365
|
+
for (const subs of this.envelopeSubscribersByTxId.values()) {
|
|
366
|
+
for (const s of subs)
|
|
367
|
+
s.cancelled = true;
|
|
368
|
+
}
|
|
369
|
+
this.setupSubscribersByTxId.clear();
|
|
370
|
+
this.envelopeSubscribersByTxId.clear();
|
|
371
|
+
}
|
|
372
|
+
// --------------------------------------------------------------------------
|
|
373
|
+
// Internals — fan-out
|
|
374
|
+
// --------------------------------------------------------------------------
|
|
375
|
+
fanoutSetup(txIdLc, wire) {
|
|
376
|
+
const subs = this.setupSubscribersByTxId.get(txIdLc);
|
|
377
|
+
if (!subs || subs.size === 0)
|
|
378
|
+
return;
|
|
379
|
+
// Snapshot to defend against subscribers mutating the set (close()
|
|
380
|
+
// during fan-out).
|
|
381
|
+
const snapshot = Array.from(subs);
|
|
382
|
+
queueMicrotask(() => {
|
|
383
|
+
for (const sub of snapshot) {
|
|
384
|
+
if (sub.cancelled)
|
|
385
|
+
continue;
|
|
386
|
+
this.deliverSetup(sub, wire);
|
|
387
|
+
}
|
|
388
|
+
});
|
|
389
|
+
}
|
|
390
|
+
fanoutEnvelope(txIdLc, wire) {
|
|
391
|
+
const subs = this.envelopeSubscribersByTxId.get(txIdLc);
|
|
392
|
+
if (!subs || subs.size === 0)
|
|
393
|
+
return;
|
|
394
|
+
const snapshot = Array.from(subs);
|
|
395
|
+
queueMicrotask(() => {
|
|
396
|
+
for (const sub of snapshot) {
|
|
397
|
+
if (sub.cancelled)
|
|
398
|
+
continue;
|
|
399
|
+
this.deliverEnvelope(sub, wire);
|
|
400
|
+
}
|
|
401
|
+
});
|
|
402
|
+
}
|
|
403
|
+
/**
|
|
404
|
+
* Deliver a setup to a single subscriber, honoring per-subscription
|
|
405
|
+
* dedup and isolating subscriber errors.
|
|
406
|
+
*
|
|
407
|
+
* NOTE on dedup ordering: the channel-wide dedup happens at publish
|
|
408
|
+
* time AFTER verify; the per-subscription dedup here is purely to
|
|
409
|
+
* prevent double-fire when replay-on-subscribe races with a live
|
|
410
|
+
* fanout for the same wire. It does NOT defend against signature
|
|
411
|
+
* poisoning — that's handled at publish time.
|
|
412
|
+
*/
|
|
413
|
+
deliverSetup(sub, wire) {
|
|
414
|
+
const sig = wire.requesterSig;
|
|
415
|
+
if (sub.delivered.has(sig))
|
|
416
|
+
return;
|
|
417
|
+
sub.delivered.add(sig);
|
|
418
|
+
Promise.resolve()
|
|
419
|
+
.then(() => sub.callback(wire))
|
|
420
|
+
.catch((e) => {
|
|
421
|
+
const msg = e instanceof Error ? e.message : String(e);
|
|
422
|
+
this.log('warn', 'MockDeliveryChannel: setup subscriber threw', {
|
|
423
|
+
error: msg,
|
|
424
|
+
txId: wire.signed.txId,
|
|
425
|
+
});
|
|
426
|
+
});
|
|
427
|
+
}
|
|
428
|
+
deliverEnvelope(sub, wire) {
|
|
429
|
+
const sig = wire.providerSig;
|
|
430
|
+
if (sub.delivered.has(sig))
|
|
431
|
+
return;
|
|
432
|
+
sub.delivered.add(sig);
|
|
433
|
+
Promise.resolve()
|
|
434
|
+
.then(() => sub.callback(wire))
|
|
435
|
+
.catch((e) => {
|
|
436
|
+
const msg = e instanceof Error ? e.message : String(e);
|
|
437
|
+
this.log('warn', 'MockDeliveryChannel: envelope subscriber threw', {
|
|
438
|
+
error: msg,
|
|
439
|
+
txId: wire.signed.txId,
|
|
440
|
+
});
|
|
441
|
+
});
|
|
442
|
+
}
|
|
443
|
+
}
|
|
444
|
+
exports.MockDeliveryChannel = MockDeliveryChannel;
|
|
445
|
+
//# sourceMappingURL=MockDeliveryChannel.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"MockDeliveryChannel.js","sourceRoot":"","sources":["../../src/delivery/MockDeliveryChannel.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AIP-16 Delivery Surface — RelayDeliveryChannel (Phase 2b)
|
|
3
|
+
* ===========================================================
|
|
4
|
+
*
|
|
5
|
+
* HTTP-backed {@link DeliveryChannel} implementation that talks to the
|
|
6
|
+
* AGIRAILS relay (or any compatible relay implementing the same REST
|
|
7
|
+
* surface) for posting and observing delivery setup + envelope wire
|
|
8
|
+
* objects.
|
|
9
|
+
*
|
|
10
|
+
* Mirrors the design of `src/negotiation/RelayChannel.ts`:
|
|
11
|
+
*
|
|
12
|
+
* - POST / GET endpoints follow the same `/api/v1/delivery/...` shape
|
|
13
|
+
* as the negotiation relay's `/api/v1/negotiations/...` endpoints.
|
|
14
|
+
* - Subscriptions poll on a fixed interval (1000ms by default — slightly
|
|
15
|
+
* faster than negotiation since delivery is the final-mile step the
|
|
16
|
+
* requester is actively waiting on).
|
|
17
|
+
* - Cursor pagination on GETs so a polling subscriber only sees new
|
|
18
|
+
* items per tick.
|
|
19
|
+
* - SSRF guard on `baseUrl` so a misconfigured agent cannot be steered
|
|
20
|
+
* at cloud-metadata services, RFC1918 hosts, or loopback addresses
|
|
21
|
+
* in production. `allowPrivateHosts: true` bypasses for dev / tests.
|
|
22
|
+
* - 8-second timeout on every POST + GET via AbortController so a
|
|
23
|
+
* hung relay cannot wedge the SDK indefinitely.
|
|
24
|
+
* - Dedup-after-verify on read: each item is verified BEFORE its
|
|
25
|
+
* identifier is added to the dedup set. An attacker who posts a
|
|
26
|
+
* valid-looking-but-malformed wire to the relay cannot poison the
|
|
27
|
+
* dedup set and suppress later legitimate items.
|
|
28
|
+
* - Subscriber errors are caught + logged so one bad subscriber cannot
|
|
29
|
+
* halt the polling loop.
|
|
30
|
+
*
|
|
31
|
+
* @module delivery/RelayDeliveryChannel
|
|
32
|
+
* @see {@link DeliveryChannel}
|
|
33
|
+
* @see ../negotiation/RelayChannel — reference pattern this mirrors.
|
|
34
|
+
*/
|
|
35
|
+
import type { DeliveryChannel, DeliverySubscription, SetupCallback, EnvelopeCallback } from './channel';
|
|
36
|
+
import { type LogFn } from './channelLog';
|
|
37
|
+
import type { DeliverySetupWireV1, DeliveryEnvelopeWireV1 } from './types';
|
|
38
|
+
/**
|
|
39
|
+
* Default polling cadence for `subscribeSetups` / `subscribeEnvelopes`,
|
|
40
|
+
* in milliseconds. 1000ms balances snappy delivery (p95 latency below 1s
|
|
41
|
+
* per round trip) against poll-amplification cost when many parallel
|
|
42
|
+
* subscriptions are armed.
|
|
43
|
+
*/
|
|
44
|
+
export declare const POLL_INTERVAL_MS = 1000;
|
|
45
|
+
/**
|
|
46
|
+
* Default request timeout for POSTs and GETs to the relay, in milliseconds.
|
|
47
|
+
* 8000ms is short enough that a hung relay surfaces quickly but long
|
|
48
|
+
* enough that genuinely slow networks (mobile, satellite) don't
|
|
49
|
+
* spurious-abort under normal load.
|
|
50
|
+
*/
|
|
51
|
+
export declare const REQUEST_TIMEOUT_MS = 8000;
|
|
52
|
+
/**
|
|
53
|
+
* Construction options for {@link RelayDeliveryChannel}.
|
|
54
|
+
*
|
|
55
|
+
* `baseUrl` defaults to the production AGIRAILS relay. All other fields
|
|
56
|
+
* are pure tuning / observability knobs.
|
|
57
|
+
*/
|
|
58
|
+
export interface RelayDeliveryChannelOptions {
|
|
59
|
+
/**
|
|
60
|
+
* Base URL of the relay. Defaults to `https://agirails.app`.
|
|
61
|
+
* Trailing slash is stripped; the channel will append the
|
|
62
|
+
* `/api/v1/delivery/...` path as needed.
|
|
63
|
+
*/
|
|
64
|
+
baseUrl?: string;
|
|
65
|
+
/**
|
|
66
|
+
* Polling interval for subscribers, in milliseconds. Defaults to
|
|
67
|
+
* {@link POLL_INTERVAL_MS} (1000). Tests typically pass a much
|
|
68
|
+
* smaller value (e.g. 25ms) so they can verify polling behavior
|
|
69
|
+
* without blowing through Jest's default timeouts.
|
|
70
|
+
*/
|
|
71
|
+
pollIntervalMs?: number;
|
|
72
|
+
/**
|
|
73
|
+
* Request timeout for POSTs and GETs, in milliseconds. Defaults to
|
|
74
|
+
* {@link REQUEST_TIMEOUT_MS} (8000). Implemented via
|
|
75
|
+
* `AbortController` so the underlying `fetch` can be cancelled.
|
|
76
|
+
*/
|
|
77
|
+
requestTimeoutMs?: number;
|
|
78
|
+
/**
|
|
79
|
+
* `fetch` implementation. Defaults to the global `fetch` (Node 18+
|
|
80
|
+
* has it built in). Tests inject a mock here to assert on the
|
|
81
|
+
* request shape and to short-circuit network IO.
|
|
82
|
+
*/
|
|
83
|
+
fetchImpl?: typeof fetch;
|
|
84
|
+
/**
|
|
85
|
+
* Pluggable logger. Defaults to {@link noopLog} (silent).
|
|
86
|
+
*
|
|
87
|
+
* Logged events:
|
|
88
|
+
* - `warn`: poll loop error, item dropped after verify failure,
|
|
89
|
+
* subscriber callback threw and was swallowed.
|
|
90
|
+
* - `error`: POST returned non-2xx (also propagated as a rejected
|
|
91
|
+
* Promise to the caller).
|
|
92
|
+
*/
|
|
93
|
+
log?: LogFn;
|
|
94
|
+
/**
|
|
95
|
+
* If `true`, allow the SSRF guard to accept loopback / RFC1918 /
|
|
96
|
+
* link-local hosts. ONLY for local development and test setups
|
|
97
|
+
* against a Vitest / Jest in-process server. Defaults to `false`.
|
|
98
|
+
*/
|
|
99
|
+
allowPrivateHosts?: boolean;
|
|
100
|
+
/**
|
|
101
|
+
* Allowlisted kernel address for verification. When set, verification
|
|
102
|
+
* enforces this value (production posture). When unset, falls back
|
|
103
|
+
* to the wire's self-asserted `signed.kernelAddress`.
|
|
104
|
+
*/
|
|
105
|
+
expectedKernelAddress?: string;
|
|
106
|
+
/**
|
|
107
|
+
* Allowlisted chainId for verification. Same fallback semantics as
|
|
108
|
+
* {@link expectedKernelAddress}.
|
|
109
|
+
*/
|
|
110
|
+
expectedChainId?: number;
|
|
111
|
+
/**
|
|
112
|
+
* Injectable wall clock returning Unix seconds. Passed to the
|
|
113
|
+
* underlying `verify()` calls so timestamp skew / expiry checks are
|
|
114
|
+
* deterministic in tests.
|
|
115
|
+
*/
|
|
116
|
+
now?: () => number;
|
|
117
|
+
}
|
|
118
|
+
/**
|
|
119
|
+
* HTTP relay-backed delivery channel. Production transport for AIP-16
|
|
120
|
+
* setups + envelopes.
|
|
121
|
+
*
|
|
122
|
+
* @example
|
|
123
|
+
* ```typescript
|
|
124
|
+
* const channel = new RelayDeliveryChannel({
|
|
125
|
+
* baseUrl: 'https://agirails.app',
|
|
126
|
+
* });
|
|
127
|
+
* await channel.publishSetup(setupWire);
|
|
128
|
+
* const sub = await channel.subscribeEnvelopes(txId, async (env) => {
|
|
129
|
+
* await processEnvelope(env);
|
|
130
|
+
* });
|
|
131
|
+
* // …later
|
|
132
|
+
* await sub.close();
|
|
133
|
+
* await channel.close();
|
|
134
|
+
* ```
|
|
135
|
+
*/
|
|
136
|
+
export declare class RelayDeliveryChannel implements DeliveryChannel {
|
|
137
|
+
private readonly baseUrl;
|
|
138
|
+
private readonly pollIntervalMs;
|
|
139
|
+
private readonly requestTimeoutMs;
|
|
140
|
+
private readonly fetchImpl;
|
|
141
|
+
private readonly log;
|
|
142
|
+
private readonly expectedKernelAddress?;
|
|
143
|
+
private readonly expectedChainId?;
|
|
144
|
+
private readonly nowFn?;
|
|
145
|
+
private readonly pollStates;
|
|
146
|
+
private closed;
|
|
147
|
+
constructor(opts?: RelayDeliveryChannelOptions);
|
|
148
|
+
publishSetup(setup: DeliverySetupWireV1): Promise<void>;
|
|
149
|
+
publishEnvelope(envelope: DeliveryEnvelopeWireV1): Promise<void>;
|
|
150
|
+
getSetups(txId: `0x${string}`, after?: string): Promise<DeliverySetupWireV1[]>;
|
|
151
|
+
getEnvelopes(txId: `0x${string}`, after?: string): Promise<DeliveryEnvelopeWireV1[]>;
|
|
152
|
+
subscribeSetups(txId: `0x${string}`, callback: SetupCallback): Promise<DeliverySubscription>;
|
|
153
|
+
subscribeEnvelopes(txId: `0x${string}`, callback: EnvelopeCallback): Promise<DeliverySubscription>;
|
|
154
|
+
close(): Promise<void>;
|
|
155
|
+
/**
|
|
156
|
+
* Deliver a single setup item — verify, dedup-after-verify, isolate
|
|
157
|
+
* subscriber errors.
|
|
158
|
+
*/
|
|
159
|
+
private deliverSetup;
|
|
160
|
+
/**
|
|
161
|
+
* Deliver a single envelope item — verify, dedup-after-verify, isolate
|
|
162
|
+
* subscriber errors.
|
|
163
|
+
*/
|
|
164
|
+
private deliverEnvelope;
|
|
165
|
+
/**
|
|
166
|
+
* Issue a POST with JSON body and an AbortController-driven timeout.
|
|
167
|
+
* Resolves on 2xx, rejects on non-2xx with the response body as the
|
|
168
|
+
* error message.
|
|
169
|
+
*/
|
|
170
|
+
private postJson;
|
|
171
|
+
/**
|
|
172
|
+
* Issue a GET and decode JSON, with an AbortController-driven timeout.
|
|
173
|
+
*/
|
|
174
|
+
private getJson;
|
|
175
|
+
}
|
|
176
|
+
//# sourceMappingURL=RelayDeliveryChannel.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"RelayDeliveryChannel.d.ts","sourceRoot":"","sources":["../../src/delivery/RelayDeliveryChannel.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AAIH,OAAO,KAAK,EACV,eAAe,EACf,oBAAoB,EACpB,aAAa,EACb,gBAAgB,EACjB,MAAM,WAAW,CAAC;AACnB,OAAO,EAAE,KAAK,KAAK,EAAW,MAAM,cAAc,CAAC;AAGnD,OAAO,KAAK,EACV,mBAAmB,EACnB,sBAAsB,EACvB,MAAM,SAAS,CAAC;AAMjB;;;;;GAKG;AACH,eAAO,MAAM,gBAAgB,OAAO,CAAC;AAErC;;;;;GAKG;AACH,eAAO,MAAM,kBAAkB,OAAO,CAAC;AASvC;;;;;GAKG;AACH,MAAM,WAAW,2BAA2B;IAC1C;;;;OAIG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;IAEjB;;;;;OAKG;IACH,cAAc,CAAC,EAAE,MAAM,CAAC;IAExB;;;;OAIG;IACH,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAE1B;;;;OAIG;IACH,SAAS,CAAC,EAAE,OAAO,KAAK,CAAC;IAEzB;;;;;;;;OAQG;IACH,GAAG,CAAC,EAAE,KAAK,CAAC;IAEZ;;;;OAIG;IACH,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAE5B;;;;OAIG;IACH,qBAAqB,CAAC,EAAE,MAAM,CAAC;IAE/B;;;OAGG;IACH,eAAe,CAAC,EAAE,MAAM,CAAC;IAEzB;;;;OAIG;IACH,GAAG,CAAC,EAAE,MAAM,MAAM,CAAC;CACpB;AAoCD;;;;;;;;;;;;;;;;;GAiBG;AACH,qBAAa,oBAAqB,YAAW,eAAe;IAC1D,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAS;IACjC,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAS;IACxC,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAS;IAC1C,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAe;IACzC,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAQ;IAC5B,OAAO,CAAC,QAAQ,CAAC,qBAAqB,CAAC,CAAS;IAChD,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAC,CAAS;IAC1C,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAe;IAEtC,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAwB;IACnD,OAAO,CAAC,MAAM,CAAS;gBAEX,IAAI,GAAE,2BAAgC;IAgB5C,YAAY,CAAC,KAAK,EAAE,mBAAmB,GAAG,OAAO,CAAC,IAAI,CAAC;IAQvD,eAAe,CAAC,QAAQ,EAAE,sBAAsB,GAAG,OAAO,CAAC,IAAI,CAAC;IAYhE,SAAS,CACb,IAAI,EAAE,KAAK,MAAM,EAAE,EACnB,KAAK,CAAC,EAAE,MAAM,GACb,OAAO,CAAC,mBAAmB,EAAE,CAAC;IAW3B,YAAY,CAChB,IAAI,EAAE,KAAK,MAAM,EAAE,EACnB,KAAK,CAAC,EAAE,MAAM,GACb,OAAO,CAAC,sBAAsB,EAAE,CAAC;IAe9B,eAAe,CACnB,IAAI,EAAE,KAAK,MAAM,EAAE,EACnB,QAAQ,EAAE,aAAa,GACtB,OAAO,CAAC,oBAAoB,CAAC;IAsD1B,kBAAkB,CACtB,IAAI,EAAE,KAAK,MAAM,EAAE,EACnB,QAAQ,EAAE,gBAAgB,GACzB,OAAO,CAAC,oBAAoB,CAAC;IAyD1B,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAa5B;;;OAGG;YACW,YAAY;IAqC1B;;;OAGG;YACW,eAAe;IAmC7B;;;;OAIG;YACW,QAAQ;IA0BtB;;OAEG;YACW,OAAO;CAmBtB"}
|