@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,377 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* AIP-16 Delivery Surface — RelayDeliveryChannel (Phase 2b)
|
|
4
|
+
* ===========================================================
|
|
5
|
+
*
|
|
6
|
+
* HTTP-backed {@link DeliveryChannel} implementation that talks to the
|
|
7
|
+
* AGIRAILS relay (or any compatible relay implementing the same REST
|
|
8
|
+
* surface) for posting and observing delivery setup + envelope wire
|
|
9
|
+
* objects.
|
|
10
|
+
*
|
|
11
|
+
* Mirrors the design of `src/negotiation/RelayChannel.ts`:
|
|
12
|
+
*
|
|
13
|
+
* - POST / GET endpoints follow the same `/api/v1/delivery/...` shape
|
|
14
|
+
* as the negotiation relay's `/api/v1/negotiations/...` endpoints.
|
|
15
|
+
* - Subscriptions poll on a fixed interval (1000ms by default — slightly
|
|
16
|
+
* faster than negotiation since delivery is the final-mile step the
|
|
17
|
+
* requester is actively waiting on).
|
|
18
|
+
* - Cursor pagination on GETs so a polling subscriber only sees new
|
|
19
|
+
* items per tick.
|
|
20
|
+
* - SSRF guard on `baseUrl` so a misconfigured agent cannot be steered
|
|
21
|
+
* at cloud-metadata services, RFC1918 hosts, or loopback addresses
|
|
22
|
+
* in production. `allowPrivateHosts: true` bypasses for dev / tests.
|
|
23
|
+
* - 8-second timeout on every POST + GET via AbortController so a
|
|
24
|
+
* hung relay cannot wedge the SDK indefinitely.
|
|
25
|
+
* - Dedup-after-verify on read: each item is verified BEFORE its
|
|
26
|
+
* identifier is added to the dedup set. An attacker who posts a
|
|
27
|
+
* valid-looking-but-malformed wire to the relay cannot poison the
|
|
28
|
+
* dedup set and suppress later legitimate items.
|
|
29
|
+
* - Subscriber errors are caught + logged so one bad subscriber cannot
|
|
30
|
+
* halt the polling loop.
|
|
31
|
+
*
|
|
32
|
+
* @module delivery/RelayDeliveryChannel
|
|
33
|
+
* @see {@link DeliveryChannel}
|
|
34
|
+
* @see ../negotiation/RelayChannel — reference pattern this mirrors.
|
|
35
|
+
*/
|
|
36
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
37
|
+
exports.RelayDeliveryChannel = exports.REQUEST_TIMEOUT_MS = exports.POLL_INTERVAL_MS = void 0;
|
|
38
|
+
const QuoteChannel_1 = require("../transport/QuoteChannel");
|
|
39
|
+
const channelLog_1 = require("./channelLog");
|
|
40
|
+
const envelopeBuilder_1 = require("./envelopeBuilder");
|
|
41
|
+
const setupBuilder_1 = require("./setupBuilder");
|
|
42
|
+
// ============================================================================
|
|
43
|
+
// Constants
|
|
44
|
+
// ============================================================================
|
|
45
|
+
/**
|
|
46
|
+
* Default polling cadence for `subscribeSetups` / `subscribeEnvelopes`,
|
|
47
|
+
* in milliseconds. 1000ms balances snappy delivery (p95 latency below 1s
|
|
48
|
+
* per round trip) against poll-amplification cost when many parallel
|
|
49
|
+
* subscriptions are armed.
|
|
50
|
+
*/
|
|
51
|
+
exports.POLL_INTERVAL_MS = 1000;
|
|
52
|
+
/**
|
|
53
|
+
* Default request timeout for POSTs and GETs to the relay, in milliseconds.
|
|
54
|
+
* 8000ms is short enough that a hung relay surfaces quickly but long
|
|
55
|
+
* enough that genuinely slow networks (mobile, satellite) don't
|
|
56
|
+
* spurious-abort under normal load.
|
|
57
|
+
*/
|
|
58
|
+
exports.REQUEST_TIMEOUT_MS = 8000;
|
|
59
|
+
/** Default base URL — production AGIRAILS relay. */
|
|
60
|
+
const DEFAULT_BASE_URL = 'https://agirails.app';
|
|
61
|
+
// ============================================================================
|
|
62
|
+
// RelayDeliveryChannel
|
|
63
|
+
// ============================================================================
|
|
64
|
+
/**
|
|
65
|
+
* HTTP relay-backed delivery channel. Production transport for AIP-16
|
|
66
|
+
* setups + envelopes.
|
|
67
|
+
*
|
|
68
|
+
* @example
|
|
69
|
+
* ```typescript
|
|
70
|
+
* const channel = new RelayDeliveryChannel({
|
|
71
|
+
* baseUrl: 'https://agirails.app',
|
|
72
|
+
* });
|
|
73
|
+
* await channel.publishSetup(setupWire);
|
|
74
|
+
* const sub = await channel.subscribeEnvelopes(txId, async (env) => {
|
|
75
|
+
* await processEnvelope(env);
|
|
76
|
+
* });
|
|
77
|
+
* // …later
|
|
78
|
+
* await sub.close();
|
|
79
|
+
* await channel.close();
|
|
80
|
+
* ```
|
|
81
|
+
*/
|
|
82
|
+
class RelayDeliveryChannel {
|
|
83
|
+
constructor(opts = {}) {
|
|
84
|
+
this.pollStates = new Set();
|
|
85
|
+
this.closed = false;
|
|
86
|
+
this.baseUrl = (opts.baseUrl ?? DEFAULT_BASE_URL).replace(/\/+$/, '');
|
|
87
|
+
(0, QuoteChannel_1.assertSafePeerUrl)(this.baseUrl, opts.allowPrivateHosts ?? false);
|
|
88
|
+
this.pollIntervalMs = opts.pollIntervalMs ?? exports.POLL_INTERVAL_MS;
|
|
89
|
+
this.requestTimeoutMs = opts.requestTimeoutMs ?? exports.REQUEST_TIMEOUT_MS;
|
|
90
|
+
this.fetchImpl = opts.fetchImpl ?? fetch;
|
|
91
|
+
this.log = opts.log ?? channelLog_1.noopLog;
|
|
92
|
+
this.expectedKernelAddress = opts.expectedKernelAddress;
|
|
93
|
+
this.expectedChainId = opts.expectedChainId;
|
|
94
|
+
this.nowFn = opts.now;
|
|
95
|
+
}
|
|
96
|
+
// --------------------------------------------------------------------------
|
|
97
|
+
// publish
|
|
98
|
+
// --------------------------------------------------------------------------
|
|
99
|
+
async publishSetup(setup) {
|
|
100
|
+
if (this.closed) {
|
|
101
|
+
throw new Error('RelayDeliveryChannel: channel is closed');
|
|
102
|
+
}
|
|
103
|
+
const url = `${this.baseUrl}/api/v1/delivery/setup`;
|
|
104
|
+
await this.postJson(url, setup);
|
|
105
|
+
}
|
|
106
|
+
async publishEnvelope(envelope) {
|
|
107
|
+
if (this.closed) {
|
|
108
|
+
throw new Error('RelayDeliveryChannel: channel is closed');
|
|
109
|
+
}
|
|
110
|
+
const url = `${this.baseUrl}/api/v1/delivery`;
|
|
111
|
+
await this.postJson(url, envelope);
|
|
112
|
+
}
|
|
113
|
+
// --------------------------------------------------------------------------
|
|
114
|
+
// get
|
|
115
|
+
// --------------------------------------------------------------------------
|
|
116
|
+
async getSetups(txId, after) {
|
|
117
|
+
const url = new URL(`${this.baseUrl}/api/v1/delivery/setup/${encodeURIComponent(txId)}`);
|
|
118
|
+
if (after) {
|
|
119
|
+
url.searchParams.set('after', after);
|
|
120
|
+
}
|
|
121
|
+
const items = await this.getJson(url.toString());
|
|
122
|
+
return (items.items ?? []).map((item) => item.wire);
|
|
123
|
+
}
|
|
124
|
+
async getEnvelopes(txId, after) {
|
|
125
|
+
const url = new URL(`${this.baseUrl}/api/v1/delivery/${encodeURIComponent(txId)}`);
|
|
126
|
+
if (after) {
|
|
127
|
+
url.searchParams.set('after', after);
|
|
128
|
+
}
|
|
129
|
+
const items = await this.getJson(url.toString());
|
|
130
|
+
return (items.items ?? []).map((item) => item.wire);
|
|
131
|
+
}
|
|
132
|
+
// --------------------------------------------------------------------------
|
|
133
|
+
// subscribe
|
|
134
|
+
// --------------------------------------------------------------------------
|
|
135
|
+
async subscribeSetups(txId, callback) {
|
|
136
|
+
if (this.closed) {
|
|
137
|
+
throw new Error('RelayDeliveryChannel: channel is closed');
|
|
138
|
+
}
|
|
139
|
+
const state = {
|
|
140
|
+
cursor: null,
|
|
141
|
+
delivered: new Set(),
|
|
142
|
+
cancelled: false,
|
|
143
|
+
};
|
|
144
|
+
this.pollStates.add(state);
|
|
145
|
+
const pollOnce = async () => {
|
|
146
|
+
if (state.cancelled)
|
|
147
|
+
return;
|
|
148
|
+
try {
|
|
149
|
+
const url = new URL(`${this.baseUrl}/api/v1/delivery/setup/${encodeURIComponent(txId)}`);
|
|
150
|
+
if (state.cursor) {
|
|
151
|
+
url.searchParams.set('after', state.cursor);
|
|
152
|
+
}
|
|
153
|
+
const body = await this.getJson(url.toString());
|
|
154
|
+
for (const item of body.items ?? []) {
|
|
155
|
+
if (state.cancelled)
|
|
156
|
+
break;
|
|
157
|
+
await this.deliverSetup(item, state, callback);
|
|
158
|
+
state.cursor = item.cursor;
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
catch (err) {
|
|
162
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
163
|
+
this.log('warn', 'RelayDeliveryChannel: setup poll error', {
|
|
164
|
+
txId,
|
|
165
|
+
error: msg,
|
|
166
|
+
});
|
|
167
|
+
}
|
|
168
|
+
if (!state.cancelled) {
|
|
169
|
+
state.timer = setTimeout(pollOnce, this.pollIntervalMs);
|
|
170
|
+
// Allow process to exit even if subscription is still armed.
|
|
171
|
+
const t = state.timer;
|
|
172
|
+
if (typeof t.unref === 'function')
|
|
173
|
+
t.unref();
|
|
174
|
+
}
|
|
175
|
+
};
|
|
176
|
+
state.timer = setTimeout(pollOnce, 0);
|
|
177
|
+
const t = state.timer;
|
|
178
|
+
if (typeof t.unref === 'function')
|
|
179
|
+
t.unref();
|
|
180
|
+
return {
|
|
181
|
+
close: () => {
|
|
182
|
+
state.cancelled = true;
|
|
183
|
+
if (state.timer)
|
|
184
|
+
clearTimeout(state.timer);
|
|
185
|
+
this.pollStates.delete(state);
|
|
186
|
+
},
|
|
187
|
+
};
|
|
188
|
+
}
|
|
189
|
+
async subscribeEnvelopes(txId, callback) {
|
|
190
|
+
if (this.closed) {
|
|
191
|
+
throw new Error('RelayDeliveryChannel: channel is closed');
|
|
192
|
+
}
|
|
193
|
+
const state = {
|
|
194
|
+
cursor: null,
|
|
195
|
+
delivered: new Set(),
|
|
196
|
+
cancelled: false,
|
|
197
|
+
};
|
|
198
|
+
this.pollStates.add(state);
|
|
199
|
+
const pollOnce = async () => {
|
|
200
|
+
if (state.cancelled)
|
|
201
|
+
return;
|
|
202
|
+
try {
|
|
203
|
+
const url = new URL(`${this.baseUrl}/api/v1/delivery/${encodeURIComponent(txId)}`);
|
|
204
|
+
if (state.cursor) {
|
|
205
|
+
url.searchParams.set('after', state.cursor);
|
|
206
|
+
}
|
|
207
|
+
const body = await this.getJson(url.toString());
|
|
208
|
+
for (const item of body.items ?? []) {
|
|
209
|
+
if (state.cancelled)
|
|
210
|
+
break;
|
|
211
|
+
await this.deliverEnvelope(item, state, callback);
|
|
212
|
+
state.cursor = item.cursor;
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
catch (err) {
|
|
216
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
217
|
+
this.log('warn', 'RelayDeliveryChannel: envelope poll error', {
|
|
218
|
+
txId,
|
|
219
|
+
error: msg,
|
|
220
|
+
});
|
|
221
|
+
}
|
|
222
|
+
if (!state.cancelled) {
|
|
223
|
+
state.timer = setTimeout(pollOnce, this.pollIntervalMs);
|
|
224
|
+
const t = state.timer;
|
|
225
|
+
if (typeof t.unref === 'function')
|
|
226
|
+
t.unref();
|
|
227
|
+
}
|
|
228
|
+
};
|
|
229
|
+
state.timer = setTimeout(pollOnce, 0);
|
|
230
|
+
const t = state.timer;
|
|
231
|
+
if (typeof t.unref === 'function')
|
|
232
|
+
t.unref();
|
|
233
|
+
return {
|
|
234
|
+
close: () => {
|
|
235
|
+
state.cancelled = true;
|
|
236
|
+
if (state.timer)
|
|
237
|
+
clearTimeout(state.timer);
|
|
238
|
+
this.pollStates.delete(state);
|
|
239
|
+
},
|
|
240
|
+
};
|
|
241
|
+
}
|
|
242
|
+
// --------------------------------------------------------------------------
|
|
243
|
+
// close
|
|
244
|
+
// --------------------------------------------------------------------------
|
|
245
|
+
async close() {
|
|
246
|
+
this.closed = true;
|
|
247
|
+
for (const state of this.pollStates) {
|
|
248
|
+
state.cancelled = true;
|
|
249
|
+
if (state.timer)
|
|
250
|
+
clearTimeout(state.timer);
|
|
251
|
+
}
|
|
252
|
+
this.pollStates.clear();
|
|
253
|
+
}
|
|
254
|
+
// --------------------------------------------------------------------------
|
|
255
|
+
// Internals
|
|
256
|
+
// --------------------------------------------------------------------------
|
|
257
|
+
/**
|
|
258
|
+
* Deliver a single setup item — verify, dedup-after-verify, isolate
|
|
259
|
+
* subscriber errors.
|
|
260
|
+
*/
|
|
261
|
+
async deliverSetup(item, state, callback) {
|
|
262
|
+
// Verify FIRST — dedup AFTER verify so a malformed sig cannot
|
|
263
|
+
// poison the dedup set.
|
|
264
|
+
const verifyResult = setupBuilder_1.DeliverySetupBuilder.verify(item.wire, {
|
|
265
|
+
expectedKernelAddress: this.expectedKernelAddress ?? item.wire.signed.kernelAddress,
|
|
266
|
+
expectedChainId: this.expectedChainId ?? item.wire.signed.chainId,
|
|
267
|
+
now: this.nowFn?.(),
|
|
268
|
+
});
|
|
269
|
+
if (!verifyResult.ok) {
|
|
270
|
+
this.log('warn', 'RelayDeliveryChannel: dropping unverified setup', {
|
|
271
|
+
code: verifyResult.code,
|
|
272
|
+
error: verifyResult.error,
|
|
273
|
+
txId: item.wire.signed.txId,
|
|
274
|
+
});
|
|
275
|
+
return;
|
|
276
|
+
}
|
|
277
|
+
const hash = setupBuilder_1.DeliverySetupBuilder.computeHash(item.wire);
|
|
278
|
+
if (state.delivered.has(hash))
|
|
279
|
+
return;
|
|
280
|
+
state.delivered.add(hash);
|
|
281
|
+
try {
|
|
282
|
+
await callback(item.wire);
|
|
283
|
+
}
|
|
284
|
+
catch (err) {
|
|
285
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
286
|
+
this.log('warn', 'RelayDeliveryChannel: setup subscriber threw', {
|
|
287
|
+
error: msg,
|
|
288
|
+
txId: item.wire.signed.txId,
|
|
289
|
+
});
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
/**
|
|
293
|
+
* Deliver a single envelope item — verify, dedup-after-verify, isolate
|
|
294
|
+
* subscriber errors.
|
|
295
|
+
*/
|
|
296
|
+
async deliverEnvelope(item, state, callback) {
|
|
297
|
+
const verifyResult = envelopeBuilder_1.DeliveryEnvelopeBuilder.verify(item.wire, {
|
|
298
|
+
expectedKernelAddress: this.expectedKernelAddress ?? item.wire.signed.kernelAddress,
|
|
299
|
+
expectedChainId: this.expectedChainId ?? item.wire.signed.chainId,
|
|
300
|
+
now: this.nowFn?.(),
|
|
301
|
+
});
|
|
302
|
+
if (!verifyResult.ok) {
|
|
303
|
+
this.log('warn', 'RelayDeliveryChannel: dropping unverified envelope', {
|
|
304
|
+
code: verifyResult.code,
|
|
305
|
+
error: verifyResult.error,
|
|
306
|
+
txId: item.wire.signed.txId,
|
|
307
|
+
});
|
|
308
|
+
return;
|
|
309
|
+
}
|
|
310
|
+
const hash = envelopeBuilder_1.DeliveryEnvelopeBuilder.computeHash(item.wire);
|
|
311
|
+
if (state.delivered.has(hash))
|
|
312
|
+
return;
|
|
313
|
+
state.delivered.add(hash);
|
|
314
|
+
try {
|
|
315
|
+
await callback(item.wire);
|
|
316
|
+
}
|
|
317
|
+
catch (err) {
|
|
318
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
319
|
+
this.log('warn', 'RelayDeliveryChannel: envelope subscriber threw', {
|
|
320
|
+
error: msg,
|
|
321
|
+
txId: item.wire.signed.txId,
|
|
322
|
+
});
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
/**
|
|
326
|
+
* Issue a POST with JSON body and an AbortController-driven timeout.
|
|
327
|
+
* Resolves on 2xx, rejects on non-2xx with the response body as the
|
|
328
|
+
* error message.
|
|
329
|
+
*/
|
|
330
|
+
async postJson(url, body) {
|
|
331
|
+
const controller = new AbortController();
|
|
332
|
+
const timer = setTimeout(() => controller.abort(), this.requestTimeoutMs);
|
|
333
|
+
try {
|
|
334
|
+
const res = await this.fetchImpl(url, {
|
|
335
|
+
method: 'POST',
|
|
336
|
+
headers: { 'Content-Type': 'application/json' },
|
|
337
|
+
body: JSON.stringify(body),
|
|
338
|
+
signal: controller.signal,
|
|
339
|
+
});
|
|
340
|
+
if (!res.ok) {
|
|
341
|
+
const text = await res.text().catch(() => '');
|
|
342
|
+
this.log('warn', 'RelayDeliveryChannel: POST non-2xx', {
|
|
343
|
+
url,
|
|
344
|
+
status: res.status,
|
|
345
|
+
body: text.slice(0, 256),
|
|
346
|
+
});
|
|
347
|
+
throw new Error(`RelayDeliveryChannel POST ${res.status}: ${text.slice(0, 200)}`);
|
|
348
|
+
}
|
|
349
|
+
}
|
|
350
|
+
finally {
|
|
351
|
+
clearTimeout(timer);
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
/**
|
|
355
|
+
* Issue a GET and decode JSON, with an AbortController-driven timeout.
|
|
356
|
+
*/
|
|
357
|
+
async getJson(url) {
|
|
358
|
+
const controller = new AbortController();
|
|
359
|
+
const timer = setTimeout(() => controller.abort(), this.requestTimeoutMs);
|
|
360
|
+
try {
|
|
361
|
+
const res = await this.fetchImpl(url, {
|
|
362
|
+
method: 'GET',
|
|
363
|
+
signal: controller.signal,
|
|
364
|
+
});
|
|
365
|
+
if (!res.ok) {
|
|
366
|
+
const text = await res.text().catch(() => '');
|
|
367
|
+
throw new Error(`RelayDeliveryChannel GET ${res.status}: ${text.slice(0, 200)}`);
|
|
368
|
+
}
|
|
369
|
+
return (await res.json());
|
|
370
|
+
}
|
|
371
|
+
finally {
|
|
372
|
+
clearTimeout(timer);
|
|
373
|
+
}
|
|
374
|
+
}
|
|
375
|
+
}
|
|
376
|
+
exports.RelayDeliveryChannel = RelayDeliveryChannel;
|
|
377
|
+
//# sourceMappingURL=RelayDeliveryChannel.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"RelayDeliveryChannel.js","sourceRoot":"","sources":["../../src/delivery/RelayDeliveryChannel.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,282 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AIP-16 Delivery Surface — Channel Abstraction (Phase 2b)
|
|
3
|
+
* =========================================================
|
|
4
|
+
*
|
|
5
|
+
* Transport-agnostic interface for posting and observing delivery
|
|
6
|
+
* setup + envelope wire objects between requester and provider.
|
|
7
|
+
*
|
|
8
|
+
* The delivery channel is the wire-level boundary between the two
|
|
9
|
+
* participants of an AIP-16 delivery exchange. It does NOT participate
|
|
10
|
+
* in any cryptographic verification — its only job is to transport
|
|
11
|
+
* already-signed {@link DeliverySetupWireV1} and {@link DeliveryEnvelopeWireV1}
|
|
12
|
+
* objects between participants.
|
|
13
|
+
*
|
|
14
|
+
* ## Concrete implementations
|
|
15
|
+
*
|
|
16
|
+
* - **MockDeliveryChannel** — in-process loopback used by tests and
|
|
17
|
+
* MockRuntime flows. Implements dedup-after-verify on the read side
|
|
18
|
+
* (see {@link MockChannel} in `src/negotiation/` for the reference
|
|
19
|
+
* pattern). Useful for end-to-end tests without network setup.
|
|
20
|
+
* - **RelayDeliveryChannel** — HTTP client against the AGIRAILS relay
|
|
21
|
+
* (or any compatible relay implementing the same REST surface). Uses
|
|
22
|
+
* cursor pagination, polling at `POLL_INTERVAL_MS = 1000`, and an
|
|
23
|
+
* SSRF guard on the relay URL (see {@link RelayChannel} in
|
|
24
|
+
* `src/negotiation/` for the reference pattern).
|
|
25
|
+
*
|
|
26
|
+
* ## Security invariants (binding on ALL implementations)
|
|
27
|
+
*
|
|
28
|
+
* 1. **Dedup AFTER verify.** Implementations that deduplicate
|
|
29
|
+
* incoming setups/envelopes MUST verify signatures BEFORE adding any
|
|
30
|
+
* identifier (txId, sig hash, etc.) to a dedup set. Otherwise an
|
|
31
|
+
* attacker can post malformed signatures to permanently suppress
|
|
32
|
+
* the legitimate signed object that arrives later.
|
|
33
|
+
*
|
|
34
|
+
* 2. **Subscriber error isolation.** Subscriber callbacks may throw
|
|
35
|
+
* arbitrary errors (consumer code is not the channel's problem).
|
|
36
|
+
* Implementations MUST catch and silently swallow callback errors —
|
|
37
|
+
* NEVER propagate them into the channel's read loop, since one bad
|
|
38
|
+
* subscriber would otherwise halt delivery for all other subscribers
|
|
39
|
+
* sharing the same channel.
|
|
40
|
+
*
|
|
41
|
+
* 3. **No verification at the channel layer.** Channels do NOT call
|
|
42
|
+
* `recoverSetupSigner` / `recoverEnvelopeSigner` or any other
|
|
43
|
+
* cryptographic check. Verification is the consumer's responsibility
|
|
44
|
+
* (typically via {@link DeliverySetupBuilder.verify} /
|
|
45
|
+
* {@link DeliveryEnvelopeBuilder.verify}). The channel is a dumb pipe.
|
|
46
|
+
*
|
|
47
|
+
* 4. **Address comparison case-insensitivity.** Where addresses appear
|
|
48
|
+
* in dedup keys (e.g. `signerAddress`), implementations MUST normalize
|
|
49
|
+
* to lowercase on both sides of any comparison.
|
|
50
|
+
*
|
|
51
|
+
* ## Subscription semantics
|
|
52
|
+
*
|
|
53
|
+
* - `subscribeSetups` / `subscribeEnvelopes` are scoped to a single
|
|
54
|
+
* `txId`. A subscription begins emitting from "now" — that is, from
|
|
55
|
+
* objects that are NOT already known to the channel at subscribe time
|
|
56
|
+
* are guaranteed to be delivered; objects that ARE already known MAY
|
|
57
|
+
* or MAY NOT be re-delivered depending on the implementation. Code
|
|
58
|
+
* that needs the full historical set should call the optional
|
|
59
|
+
* `getSetups` / `getEnvelopes` methods.
|
|
60
|
+
*
|
|
61
|
+
* - Returning a {@link DeliverySubscription} whose `close()` is invoked
|
|
62
|
+
* MUST stop further callbacks from firing on that subscription. It
|
|
63
|
+
* SHOULD also free any underlying transport (polling timer, HTTP
|
|
64
|
+
* connection, etc.).
|
|
65
|
+
*
|
|
66
|
+
* - Multiple subscribers on the same `txId` MUST each receive all
|
|
67
|
+
* matching objects (fan-out, not steal). One subscriber's `close()`
|
|
68
|
+
* MUST NOT affect other subscribers.
|
|
69
|
+
*
|
|
70
|
+
* @module delivery/channel
|
|
71
|
+
* @see {@link DeliverySetupWireV1}
|
|
72
|
+
* @see {@link DeliveryEnvelopeWireV1}
|
|
73
|
+
*/
|
|
74
|
+
import type { DeliverySetupWireV1, DeliveryEnvelopeWireV1 } from './types';
|
|
75
|
+
/**
|
|
76
|
+
* Handle returned from a `subscribe*` call. Calling `close()` cancels
|
|
77
|
+
* the subscription — the corresponding callback will not fire again.
|
|
78
|
+
*
|
|
79
|
+
* `close()` is idempotent: calling it multiple times is safe and a no-op
|
|
80
|
+
* after the first call. It MAY return a Promise (e.g. when the
|
|
81
|
+
* implementation needs to await an in-flight HTTP request); callers
|
|
82
|
+
* SHOULD `await` it when they need to confirm teardown completed
|
|
83
|
+
* before, e.g., asserting that no further callbacks fire.
|
|
84
|
+
*
|
|
85
|
+
* @example
|
|
86
|
+
* ```typescript
|
|
87
|
+
* const sub = await channel.subscribeEnvelopes(txId, async (env) => {
|
|
88
|
+
* await processEnvelope(env);
|
|
89
|
+
* });
|
|
90
|
+
* // …later
|
|
91
|
+
* await sub.close();
|
|
92
|
+
* ```
|
|
93
|
+
*/
|
|
94
|
+
export interface DeliverySubscription {
|
|
95
|
+
/**
|
|
96
|
+
* Cancel this subscription. Idempotent. MAY return a Promise that
|
|
97
|
+
* resolves once the underlying transport (polling timer, HTTP
|
|
98
|
+
* connection) has been torn down.
|
|
99
|
+
*/
|
|
100
|
+
close(): void | Promise<void>;
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* Callback fired for each verified-then-deduped setup observed on the
|
|
104
|
+
* channel for the subscribed `txId`.
|
|
105
|
+
*
|
|
106
|
+
* NOTE: "verified-then-deduped" is the dedup-after-verify ordering
|
|
107
|
+
* invariant — implementations call this callback only for setups whose
|
|
108
|
+
* signature has been verified (and which have not already been delivered
|
|
109
|
+
* to this subscriber).
|
|
110
|
+
*
|
|
111
|
+
* The callback MAY be async. Errors thrown from the callback (sync or
|
|
112
|
+
* async) MUST be caught and swallowed by the channel implementation —
|
|
113
|
+
* see security invariant #2 in the module-level JSDoc.
|
|
114
|
+
*/
|
|
115
|
+
export type SetupCallback = (setup: DeliverySetupWireV1) => void | Promise<void>;
|
|
116
|
+
/**
|
|
117
|
+
* Callback fired for each verified-then-deduped envelope observed on
|
|
118
|
+
* the channel for the subscribed `txId`.
|
|
119
|
+
*
|
|
120
|
+
* Same semantics as {@link SetupCallback}: dedup-after-verify ordering,
|
|
121
|
+
* may be async, errors are isolated by the channel.
|
|
122
|
+
*/
|
|
123
|
+
export type EnvelopeCallback = (envelope: DeliveryEnvelopeWireV1) => void | Promise<void>;
|
|
124
|
+
/**
|
|
125
|
+
* Transport-agnostic delivery channel.
|
|
126
|
+
*
|
|
127
|
+
* Implementations are responsible for transporting already-signed
|
|
128
|
+
* setup and envelope wire objects between requester and provider. The
|
|
129
|
+
* channel does NOT verify signatures, hashes, or schemes; that is the
|
|
130
|
+
* caller's responsibility (see the builder `verify()` methods).
|
|
131
|
+
*
|
|
132
|
+
* ## Contract summary
|
|
133
|
+
*
|
|
134
|
+
* - `publishSetup` / `publishEnvelope` post a wire object to the
|
|
135
|
+
* channel. Implementations MAY perform best-effort validation (e.g.
|
|
136
|
+
* rejecting obviously malformed `txId` strings) but MUST NOT make
|
|
137
|
+
* cryptographic verification a precondition of publish — the channel
|
|
138
|
+
* is dumb on the write side, just as it is on the read side.
|
|
139
|
+
*
|
|
140
|
+
* - `subscribeSetups` / `subscribeEnvelopes` register a callback that
|
|
141
|
+
* fires for each verified-then-deduped object observed on the
|
|
142
|
+
* channel for the given `txId`. Returns a {@link DeliverySubscription}
|
|
143
|
+
* whose `close()` cancels the subscription.
|
|
144
|
+
*
|
|
145
|
+
* - `getSetups` / `getEnvelopes` (optional) return the full set of
|
|
146
|
+
* objects the channel currently knows about for a given `txId`.
|
|
147
|
+
* Useful for "catch up to current state" flows where a participant
|
|
148
|
+
* starts late and needs to see what was already posted. Implementations
|
|
149
|
+
* that cannot enumerate prior state (e.g. fire-and-forget transports)
|
|
150
|
+
* MAY omit these methods.
|
|
151
|
+
*
|
|
152
|
+
* - `close()` (optional) releases all channel-level resources (e.g.
|
|
153
|
+
* open HTTP connections, polling timers shared across subscriptions).
|
|
154
|
+
* Implementations that have no global state MAY omit it.
|
|
155
|
+
*
|
|
156
|
+
* @example In-process loopback (MockRuntime tests)
|
|
157
|
+
* ```typescript
|
|
158
|
+
* const channel: DeliveryChannel = new MockDeliveryChannel();
|
|
159
|
+
*
|
|
160
|
+
* await channel.publishSetup(setupWire);
|
|
161
|
+
* const sub = await channel.subscribeEnvelopes(txId, async (env) => {
|
|
162
|
+
* const result = await envelopeBuilder.verify(env);
|
|
163
|
+
* if (result.valid) await consumeEnvelope(env);
|
|
164
|
+
* });
|
|
165
|
+
* // …later
|
|
166
|
+
* await sub.close();
|
|
167
|
+
* ```
|
|
168
|
+
*
|
|
169
|
+
* @example HTTP relay
|
|
170
|
+
* ```typescript
|
|
171
|
+
* const channel: DeliveryChannel = new RelayDeliveryChannel({
|
|
172
|
+
* baseUrl: 'https://relay.agirails.io',
|
|
173
|
+
* relayId: 'agirails-relay-v1',
|
|
174
|
+
* });
|
|
175
|
+
* await channel.publishEnvelope(envelopeWire);
|
|
176
|
+
* await channel.close?.();
|
|
177
|
+
* ```
|
|
178
|
+
*/
|
|
179
|
+
export interface DeliveryChannel {
|
|
180
|
+
/**
|
|
181
|
+
* Post a fully-signed {@link DeliverySetupWireV1} to the channel.
|
|
182
|
+
*
|
|
183
|
+
* Implementations SHOULD:
|
|
184
|
+
* - Perform shape validation (txId is a 32-byte hex, signature is
|
|
185
|
+
* 65 bytes, etc.) and reject early on obvious malformations.
|
|
186
|
+
* - NOT perform cryptographic verification — that is the verifier's
|
|
187
|
+
* job, and pushing it down into the channel layer would tie the
|
|
188
|
+
* transport to a specific kernel address / chainId universe.
|
|
189
|
+
* - Surface transport-level errors as rejected Promises with a
|
|
190
|
+
* structured `DeliveryError` of code `channel_post_failed` or
|
|
191
|
+
* `channel_unreachable`, depending on the failure class.
|
|
192
|
+
*
|
|
193
|
+
* @param setup The setup wire object to publish.
|
|
194
|
+
* @returns A Promise that resolves once the channel has accepted
|
|
195
|
+
* the publish (in a relay-backed implementation, after the relay
|
|
196
|
+
* acknowledges the POST; in a loopback implementation, after the
|
|
197
|
+
* in-memory write completes).
|
|
198
|
+
*/
|
|
199
|
+
publishSetup(setup: DeliverySetupWireV1): Promise<void>;
|
|
200
|
+
/**
|
|
201
|
+
* Post a fully-signed {@link DeliveryEnvelopeWireV1} to the channel.
|
|
202
|
+
*
|
|
203
|
+
* Same contract as {@link publishSetup} — shape validation OK,
|
|
204
|
+
* crypto verification NOT permitted at this layer, transport errors
|
|
205
|
+
* surfaced as rejected Promises.
|
|
206
|
+
*
|
|
207
|
+
* @param envelope The envelope wire object to publish.
|
|
208
|
+
* @returns A Promise that resolves once the channel has accepted
|
|
209
|
+
* the publish.
|
|
210
|
+
*/
|
|
211
|
+
publishEnvelope(envelope: DeliveryEnvelopeWireV1): Promise<void>;
|
|
212
|
+
/**
|
|
213
|
+
* Subscribe to setups observed on the channel for a given `txId`.
|
|
214
|
+
*
|
|
215
|
+
* The callback fires once per verified-then-deduped setup
|
|
216
|
+
* (dedup-after-verify ordering, see module JSDoc). Multiple
|
|
217
|
+
* subscriptions on the same `txId` each receive all matching
|
|
218
|
+
* setups (fan-out).
|
|
219
|
+
*
|
|
220
|
+
* Callback errors are isolated per security invariant #2 — the
|
|
221
|
+
* channel MUST catch and swallow them, never propagating into its
|
|
222
|
+
* own read loop or affecting other subscribers.
|
|
223
|
+
*
|
|
224
|
+
* @param txId The transaction id to scope the subscription to,
|
|
225
|
+
* as a `bytes32` hex-encoded string (`0x` + 64 hex chars).
|
|
226
|
+
* @param callback Invoked for each setup observed.
|
|
227
|
+
* @returns A {@link DeliverySubscription} whose `close()` cancels.
|
|
228
|
+
*/
|
|
229
|
+
subscribeSetups(txId: `0x${string}`, callback: SetupCallback): Promise<DeliverySubscription>;
|
|
230
|
+
/**
|
|
231
|
+
* Subscribe to envelopes observed on the channel for a given `txId`.
|
|
232
|
+
*
|
|
233
|
+
* Same semantics as {@link subscribeSetups}.
|
|
234
|
+
*
|
|
235
|
+
* @param txId The transaction id to scope the subscription to.
|
|
236
|
+
* @param callback Invoked for each envelope observed.
|
|
237
|
+
* @returns A {@link DeliverySubscription} whose `close()` cancels.
|
|
238
|
+
*/
|
|
239
|
+
subscribeEnvelopes(txId: `0x${string}`, callback: EnvelopeCallback): Promise<DeliverySubscription>;
|
|
240
|
+
/**
|
|
241
|
+
* Optional: return all setups the channel currently knows about for
|
|
242
|
+
* a given `txId`.
|
|
243
|
+
*
|
|
244
|
+
* Useful when a participant joins late and needs to see historical
|
|
245
|
+
* state. The returned array MUST be ordered by channel-observation
|
|
246
|
+
* order (oldest first) so callers can implement "process all then
|
|
247
|
+
* subscribe to new" flows deterministically.
|
|
248
|
+
*
|
|
249
|
+
* Implementations that cannot enumerate prior state (e.g.
|
|
250
|
+
* fire-and-forget transports, transports without server-side
|
|
251
|
+
* storage) MAY omit this method. Consumers MUST check for its
|
|
252
|
+
* presence (`if (channel.getSetups)`).
|
|
253
|
+
*
|
|
254
|
+
* @param txId The transaction id to fetch setups for.
|
|
255
|
+
* @returns All known setups for `txId`, oldest first.
|
|
256
|
+
*/
|
|
257
|
+
getSetups?(txId: `0x${string}`): Promise<DeliverySetupWireV1[]>;
|
|
258
|
+
/**
|
|
259
|
+
* Optional: return all envelopes the channel currently knows about
|
|
260
|
+
* for a given `txId`. Same contract as {@link getSetups}.
|
|
261
|
+
*
|
|
262
|
+
* @param txId The transaction id to fetch envelopes for.
|
|
263
|
+
* @returns All known envelopes for `txId`, oldest first.
|
|
264
|
+
*/
|
|
265
|
+
getEnvelopes?(txId: `0x${string}`): Promise<DeliveryEnvelopeWireV1[]>;
|
|
266
|
+
/**
|
|
267
|
+
* Optional: release any channel-level resources (HTTP connections,
|
|
268
|
+
* polling timers shared across subscriptions, etc.).
|
|
269
|
+
*
|
|
270
|
+
* After `close()` resolves, the channel MUST NOT fire any further
|
|
271
|
+
* subscriber callbacks and SHOULD reject any subsequent `publish*`
|
|
272
|
+
* call with `channel_unreachable`.
|
|
273
|
+
*
|
|
274
|
+
* Implementations with no global state (e.g. a pure in-memory
|
|
275
|
+
* loopback that closes per-subscription only) MAY omit this method.
|
|
276
|
+
*
|
|
277
|
+
* `close()` is idempotent: calling it multiple times is safe and
|
|
278
|
+
* a no-op after the first call.
|
|
279
|
+
*/
|
|
280
|
+
close?(): void | Promise<void>;
|
|
281
|
+
}
|
|
282
|
+
//# sourceMappingURL=channel.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"channel.d.ts","sourceRoot":"","sources":["../../src/delivery/channel.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAwEG;AAEH,OAAO,KAAK,EACV,mBAAmB,EACnB,sBAAsB,EACvB,MAAM,SAAS,CAAC;AAMjB;;;;;;;;;;;;;;;;;;GAkBG;AACH,MAAM,WAAW,oBAAoB;IACnC;;;;OAIG;IACH,KAAK,IAAI,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CAC/B;AAMD;;;;;;;;;;;;GAYG;AACH,MAAM,MAAM,aAAa,GAAG,CAAC,KAAK,EAAE,mBAAmB,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;AAEjF;;;;;;GAMG;AACH,MAAM,MAAM,gBAAgB,GAAG,CAAC,QAAQ,EAAE,sBAAsB,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;AAM1F;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsDG;AACH,MAAM,WAAW,eAAe;IAC9B;;;;;;;;;;;;;;;;;;OAkBG;IACH,YAAY,CAAC,KAAK,EAAE,mBAAmB,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAExD;;;;;;;;;;OAUG;IACH,eAAe,CAAC,QAAQ,EAAE,sBAAsB,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAEjE;;;;;;;;;;;;;;;;OAgBG;IACH,eAAe,CACb,IAAI,EAAE,KAAK,MAAM,EAAE,EACnB,QAAQ,EAAE,aAAa,GACtB,OAAO,CAAC,oBAAoB,CAAC,CAAC;IAEjC;;;;;;;;OAQG;IACH,kBAAkB,CAChB,IAAI,EAAE,KAAK,MAAM,EAAE,EACnB,QAAQ,EAAE,gBAAgB,GACzB,OAAO,CAAC,oBAAoB,CAAC,CAAC;IAEjC;;;;;;;;;;;;;;;;OAgBG;IACH,SAAS,CAAC,CAAC,IAAI,EAAE,KAAK,MAAM,EAAE,GAAG,OAAO,CAAC,mBAAmB,EAAE,CAAC,CAAC;IAEhE;;;;;;OAMG;IACH,YAAY,CAAC,CAAC,IAAI,EAAE,KAAK,MAAM,EAAE,GAAG,OAAO,CAAC,sBAAsB,EAAE,CAAC,CAAC;IAEtE;;;;;;;;;;;;;OAaG;IACH,KAAK,CAAC,IAAI,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CAChC"}
|