@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,193 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Vendored copy of Sentinel's reflection table for local-fallback display.
|
|
4
|
+
*
|
|
5
|
+
* ## Why vendored?
|
|
6
|
+
*
|
|
7
|
+
* The Sentinel seed agent (`Public Agents/seed-sentinel/src/reflections.ts`)
|
|
8
|
+
* is the canonical source of these one-liners — when a buyer hits Sentinel
|
|
9
|
+
* via `actp test`, the AIP-16 delivery channel returns the day's reflection
|
|
10
|
+
* inside `result.payload.reflection`. That is the happy path and remains
|
|
11
|
+
* the source of truth at runtime.
|
|
12
|
+
*
|
|
13
|
+
* This file is a **byte-equivalent vendored copy** kept inside the SDK so
|
|
14
|
+
* the CLI can render a local reflection when the channel delivery is
|
|
15
|
+
* dormant (envelope subscription missed, relay was slow, decoding failed,
|
|
16
|
+
* or the buyer ran offline against a cached state). The intent: even when
|
|
17
|
+
* the delivery surface is silent, the buyer's "wow moment" still lands —
|
|
18
|
+
* a quiet quote in their terminal instead of a blank receipt.
|
|
19
|
+
*
|
|
20
|
+
* ## Determinism contract
|
|
21
|
+
*
|
|
22
|
+
* Selection is deterministic per UTC day. `todaysReflection(now)` returns
|
|
23
|
+
* the same entry for any `now` that falls inside the same UTC calendar
|
|
24
|
+
* day, across the SDK and Sentinel, because both use the same:
|
|
25
|
+
* - djb2-style hash (Bernstein) of `YYYY-MM-DD`
|
|
26
|
+
* - modulo over the same 76-entry table in the same order
|
|
27
|
+
*
|
|
28
|
+
* This means a buyer who sees a local-fallback reflection on day D and
|
|
29
|
+
* then re-runs `actp test` later that same day (after the channel
|
|
30
|
+
* recovers) will receive **the same** quote from Sentinel. No
|
|
31
|
+
* synchronicity is broken by the fallback.
|
|
32
|
+
*
|
|
33
|
+
* ## Sync policy
|
|
34
|
+
*
|
|
35
|
+
* Last synced: 2026-06-09 (against `Public Agents/seed-sentinel/src/reflections.ts`).
|
|
36
|
+
*
|
|
37
|
+
* When the upstream Sentinel table changes in a meaningful way (entries
|
|
38
|
+
* added, removed, reworded, or reordered), port those changes here and
|
|
39
|
+
* bump the "Last synced" date. The two tables MUST stay byte-identical
|
|
40
|
+
* for the determinism contract to hold — if they diverge, buyers will
|
|
41
|
+
* see one quote in fallback and a different quote on retry.
|
|
42
|
+
*
|
|
43
|
+
* The fallback path is the safety net, not the canonical render. If you
|
|
44
|
+
* find yourself wanting to add SDK-only reflections here that are NOT in
|
|
45
|
+
* Sentinel, stop: add them to Sentinel first, then port.
|
|
46
|
+
*
|
|
47
|
+
* @module cli/lib/sentinelReflections
|
|
48
|
+
*/
|
|
49
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
50
|
+
exports.todaysReflection = exports.utcDateKey = exports.djb2hash = exports.REFLECTIONS = void 0;
|
|
51
|
+
/**
|
|
52
|
+
* The curated table. 76 entries.
|
|
53
|
+
*
|
|
54
|
+
* Byte-equivalent to the upstream Sentinel table. Do not reorder, edit
|
|
55
|
+
* text, or drop entries without porting the same change to Sentinel
|
|
56
|
+
* first — both tables drive the same `hashDateKey(YYYY-MM-DD) % 76`
|
|
57
|
+
* selection, so any divergence yields different reflections on the same
|
|
58
|
+
* day.
|
|
59
|
+
*/
|
|
60
|
+
exports.REFLECTIONS = Object.freeze([
|
|
61
|
+
{ id: 1, text: 'Nothing I see means anything.' },
|
|
62
|
+
{ id: 2, text: 'I have given everything I see all the meaning that it has for me.' },
|
|
63
|
+
{ id: 3, text: 'I do not understand anything I see.' },
|
|
64
|
+
{ id: 9, text: 'I see nothing as it is now.' },
|
|
65
|
+
{ id: 15, text: 'My thoughts are images which I have made.' },
|
|
66
|
+
{ id: 16, text: 'I have no neutral thoughts.' },
|
|
67
|
+
{ id: 17, text: 'I see no neutral things.' },
|
|
68
|
+
{ id: 18, text: 'I am not alone in experiencing the effects of my seeing.' },
|
|
69
|
+
{ id: 19, text: 'I am not alone in experiencing the effects of my thoughts.' },
|
|
70
|
+
{ id: 21, text: 'I am determined to see things differently.' },
|
|
71
|
+
{ id: 25, text: 'I do not know what anything is for.' },
|
|
72
|
+
{ id: 28, text: 'Above all else, I want to see things differently.' },
|
|
73
|
+
{ id: 31, text: 'I am not the victim of the world I see.' },
|
|
74
|
+
{ id: 32, text: 'I have invented the world I see.' },
|
|
75
|
+
{ id: 33, text: 'There is another way of looking at the world.' },
|
|
76
|
+
{ id: 66, text: 'My happiness and my function are one.' },
|
|
77
|
+
{ id: 68, text: 'Love holds no grievances.' },
|
|
78
|
+
{ id: 80, text: 'Let me recognize my problems have been solved.' },
|
|
79
|
+
{ id: 93, text: 'Light and joy and peace abide within me.' },
|
|
80
|
+
{ id: 104, text: 'I seek but what belongs to me in truth.' },
|
|
81
|
+
{ id: 106, text: 'Let me be still and listen to the truth.' },
|
|
82
|
+
{ id: 107, text: 'Truth will correct the errors in my mind.' },
|
|
83
|
+
{ id: 108, text: 'To give and to receive are one in truth.' },
|
|
84
|
+
{ id: 121, text: 'Forgiveness is the key to happiness.' },
|
|
85
|
+
{ id: 122, text: 'Forgiveness offers everything I want.' },
|
|
86
|
+
{ id: 126, text: 'All that I give is given to myself.' },
|
|
87
|
+
{ id: 128, text: 'The world I see holds nothing that I want.' },
|
|
88
|
+
{ id: 129, text: 'Beyond this world there is a world I want.' },
|
|
89
|
+
{ id: 130, text: 'It is impossible to see two worlds.' },
|
|
90
|
+
{ id: 131, text: 'No one can fail who seeks to reach the truth.' },
|
|
91
|
+
{ id: 132, text: 'I loose the world from all I thought it was.' },
|
|
92
|
+
{ id: 133, text: 'I will not value what is valueless.' },
|
|
93
|
+
{ id: 135, text: 'If I defend myself I am attacked.' },
|
|
94
|
+
{ id: 152, text: 'The power of decision is my own.' },
|
|
95
|
+
{ id: 153, text: 'In my defenselessness my safety lies.' },
|
|
96
|
+
{ id: 158, text: 'Today I learn to give as I receive.' },
|
|
97
|
+
{ id: 195, text: 'Love is the way I walk in gratitude.' },
|
|
98
|
+
{ id: 198, text: 'Only my condemnation injures me.' },
|
|
99
|
+
{ id: 221, text: 'Peace to my mind. Let all my thoughts be still.' },
|
|
100
|
+
{ id: 236, text: 'I rule my mind, which I alone must rule.' },
|
|
101
|
+
{ id: 240, text: 'Fear is not justified in any form.' },
|
|
102
|
+
{ id: 243, text: 'Today I will judge nothing that occurs.' },
|
|
103
|
+
{ id: 249, text: 'Forgiveness ends all suffering and loss.' },
|
|
104
|
+
{ id: 250, text: 'Let me not see myself as limited.' },
|
|
105
|
+
{ id: 251, text: 'I am in need of nothing but the truth.' },
|
|
106
|
+
{ id: 255, text: 'This day I choose to spend in perfect peace.' },
|
|
107
|
+
{ id: 257, text: 'Let me remember what my purpose is.' },
|
|
108
|
+
{ id: 262, text: 'Let me perceive no differences today.' },
|
|
109
|
+
{ id: 268, text: 'Let all things be exactly as they are.' },
|
|
110
|
+
{ id: 281, text: 'I can be hurt by nothing but my thoughts.' },
|
|
111
|
+
{ id: 282, text: 'I will not be afraid of love today.' },
|
|
112
|
+
{ id: 284, text: 'I can elect to change all thoughts that hurt.' },
|
|
113
|
+
{ id: 289, text: 'The past is over. It can touch me not.' },
|
|
114
|
+
{ id: 290, text: 'My present happiness is all I see.' },
|
|
115
|
+
{ id: 291, text: 'This is a day of stillness and of peace.' },
|
|
116
|
+
{ id: 292, text: 'A happy outcome to all things is sure.' },
|
|
117
|
+
{ id: 293, text: 'All fear is past, and only love is here.' },
|
|
118
|
+
{ id: 300, text: 'Only an instant does this world endure.' },
|
|
119
|
+
{ id: 307, text: 'Conflicting wishes cannot be my will.' },
|
|
120
|
+
{ id: 308, text: 'This instant is the only time there is.' },
|
|
121
|
+
{ id: 309, text: 'I will not fear to look within today.' },
|
|
122
|
+
{ id: 310, text: 'In fearlessness and love I spend today.' },
|
|
123
|
+
{ id: 311, text: 'I judge all things as I would have them be.' },
|
|
124
|
+
{ id: 312, text: 'I see all things as I would have them be.' },
|
|
125
|
+
{ id: 313, text: 'Now let a new perception come to me.' },
|
|
126
|
+
{ id: 314, text: 'I seek a future different from the past.' },
|
|
127
|
+
{ id: 322, text: 'I can give up what was never real.' },
|
|
128
|
+
{ id: 323, text: 'I gladly make the sacrifice of fear.' },
|
|
129
|
+
{ id: 325, text: 'All things I think I see reflect ideas.' },
|
|
130
|
+
{ id: 332, text: 'Fear binds the world. Forgiveness sets it free.' },
|
|
131
|
+
{ id: 334, text: 'Today I claim the gifts forgiveness gives.' },
|
|
132
|
+
{ id: 336, text: 'Forgiveness lets me know that minds are joined.' },
|
|
133
|
+
{ id: 338, text: 'I am affected only by my thoughts.' },
|
|
134
|
+
{ id: 339, text: 'I will receive what I request.' },
|
|
135
|
+
{ id: 340, text: 'I can be free of suffering today.' },
|
|
136
|
+
{ id: 345, text: 'I offer only miracles today.' },
|
|
137
|
+
]);
|
|
138
|
+
/**
|
|
139
|
+
* djb2-style additive hash over a string. Matches Sentinel's
|
|
140
|
+
* implementation exactly: shift-subtract loop with `|= 0` to coerce back
|
|
141
|
+
* to int32, then `Math.abs` to drop the sign. Two different inputs
|
|
142
|
+
* yielding the same hash are vanishingly rare across YYYY-MM-DD keys
|
|
143
|
+
* over the next 1000 years, so this is fine for the deterministic
|
|
144
|
+
* "quote of the day" use case (NOT for cryptographic purposes).
|
|
145
|
+
*
|
|
146
|
+
* Exported for tests (the determinism contract is observable, not
|
|
147
|
+
* hidden) and so callers verifying "same key → same hash" don't have to
|
|
148
|
+
* reimplement it.
|
|
149
|
+
*/
|
|
150
|
+
function djb2hash(key) {
|
|
151
|
+
let h = 0;
|
|
152
|
+
for (let i = 0; i < key.length; i++) {
|
|
153
|
+
h = ((h << 5) - h) + key.charCodeAt(i);
|
|
154
|
+
h |= 0;
|
|
155
|
+
}
|
|
156
|
+
return Math.abs(h);
|
|
157
|
+
}
|
|
158
|
+
exports.djb2hash = djb2hash;
|
|
159
|
+
/**
|
|
160
|
+
* Format `YYYY-MM-DD` in **UTC**.
|
|
161
|
+
*
|
|
162
|
+
* UTC matters here: if we used local-tz date, two callers running the
|
|
163
|
+
* same `actp test` at the same wall-clock instant from Zagreb and San
|
|
164
|
+
* Francisco might land on different dates near midnight and see
|
|
165
|
+
* different reflections — breaking the "everyone onboarding today shares
|
|
166
|
+
* the same quote" property.
|
|
167
|
+
*
|
|
168
|
+
* Exported so tests can assert the slicing format directly.
|
|
169
|
+
*/
|
|
170
|
+
function utcDateKey(d) {
|
|
171
|
+
return d.toISOString().slice(0, 10);
|
|
172
|
+
}
|
|
173
|
+
exports.utcDateKey = utcDateKey;
|
|
174
|
+
/**
|
|
175
|
+
* Select today's reflection. Deterministic per UTC day.
|
|
176
|
+
*
|
|
177
|
+
* Matches Sentinel's `todaysReflection(now)` exactly: hash the UTC
|
|
178
|
+
* YYYY-MM-DD key, modulo over the table length, return the entry. Same
|
|
179
|
+
* day, same entry — across Sentinel and the local fallback.
|
|
180
|
+
*
|
|
181
|
+
* @param now - Defaults to `new Date()`. Tests pass a fixed Date.
|
|
182
|
+
* Per project rules: timing is injected, never inlined as
|
|
183
|
+
* a wall-clock primitive at a call site that needs to be
|
|
184
|
+
* deterministic — callers should pass an explicit Date when
|
|
185
|
+
* the result is being asserted.
|
|
186
|
+
*/
|
|
187
|
+
function todaysReflection(now = new Date()) {
|
|
188
|
+
const key = utcDateKey(now);
|
|
189
|
+
const idx = djb2hash(key) % exports.REFLECTIONS.length;
|
|
190
|
+
return exports.REFLECTIONS[idx];
|
|
191
|
+
}
|
|
192
|
+
exports.todaysReflection = todaysReflection;
|
|
193
|
+
//# sourceMappingURL=sentinelReflections.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sentinelReflections.js","sourceRoot":"","sources":["../../../src/cli/lib/sentinelReflections.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,208 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AIP-16 Delivery Surface — MockDeliveryChannel (Phase 2b)
|
|
3
|
+
* =========================================================
|
|
4
|
+
*
|
|
5
|
+
* In-process loopback {@link DeliveryChannel} implementation used by
|
|
6
|
+
* unit tests and `MockRuntime` flows. Both parties of an AIP-16
|
|
7
|
+
* delivery exchange share a single MockDeliveryChannel instance and
|
|
8
|
+
* exchange already-signed wire objects without any network transport.
|
|
9
|
+
*
|
|
10
|
+
* Verification is performed in-channel — the same builder `verify()`
|
|
11
|
+
* methods that `RelayDeliveryChannel` consumers run on read — so
|
|
12
|
+
* security regression tests using the mock exercise the same code
|
|
13
|
+
* paths as production deployments.
|
|
14
|
+
*
|
|
15
|
+
* ## Critical security invariants (mirror MockChannel / RelayChannel)
|
|
16
|
+
*
|
|
17
|
+
* 1. **Dedup AFTER verify.** A signature is added to a txId's dedup
|
|
18
|
+
* set ONLY after the signature has been verified. Otherwise an
|
|
19
|
+
* attacker who replays a malformed payload with a stolen signature
|
|
20
|
+
* could poison the dedup set — the later legitimate signed object
|
|
21
|
+
* would be silently dropped because its identifier was already
|
|
22
|
+
* "seen". This is identical to the ordering used in
|
|
23
|
+
* `src/negotiation/MockChannel.ts` ~line 189.
|
|
24
|
+
*
|
|
25
|
+
* 2. **Subscriber error isolation.** Subscriber callbacks may throw
|
|
26
|
+
* synchronously or asynchronously. Every invocation is wrapped in
|
|
27
|
+
* `Promise.resolve(...).catch(...)` so one bad subscriber can never
|
|
28
|
+
* halt fan-out to peer subscribers and cannot propagate up into
|
|
29
|
+
* the channel's publish loop.
|
|
30
|
+
*
|
|
31
|
+
* 3. **Replay on subscribe.** Subscribers receive the FULL historical
|
|
32
|
+
* set of already-published wire objects for the subscribed `txId`
|
|
33
|
+
* before any future objects fire. This matches the test-ergonomic
|
|
34
|
+
* behavior of `MockChannel`: tests can publish first then subscribe
|
|
35
|
+
* and still see what was posted. Each callback maintains its own
|
|
36
|
+
* per-subscription `delivered` set so a replay does not double-fire
|
|
37
|
+
* and so a slow subscriber can stagger its consumption without
|
|
38
|
+
* missing messages.
|
|
39
|
+
*
|
|
40
|
+
* 4. **Address comparison case-insensitivity.** All comparisons that
|
|
41
|
+
* touch addresses (none directly in this file — verification is
|
|
42
|
+
* delegated to builders which already lowercase both sides) are
|
|
43
|
+
* case-insensitive by construction.
|
|
44
|
+
*
|
|
45
|
+
* ## Verification opts derivation
|
|
46
|
+
*
|
|
47
|
+
* Verification calls `DeliverySetupBuilder.verify` / `DeliveryEnvelopeBuilder.verify`
|
|
48
|
+
* with `{ expectedKernelAddress, expectedChainId, now }`. The resolution
|
|
49
|
+
* order is:
|
|
50
|
+
*
|
|
51
|
+
* - `expectedKernelAddress`: `opts.expectedKernelAddress` if set, else
|
|
52
|
+
* `signed.kernelAddress` (the wire's self-asserted kernel).
|
|
53
|
+
* - `expectedChainId`: `opts.expectedChainId` if set, else
|
|
54
|
+
* `signed.chainId`.
|
|
55
|
+
* - `now`: `opts.now?.()` if set, else the builder's default (which
|
|
56
|
+
* reads its own injectable clock).
|
|
57
|
+
*
|
|
58
|
+
* Using the wire's self-asserted values is intentional for the *mock*
|
|
59
|
+
* — tests typically don't care to plumb an explicit kernel address per
|
|
60
|
+
* channel instance and want the channel to "just accept" whatever the
|
|
61
|
+
* test signed. Tests that DO want allowlist enforcement pass
|
|
62
|
+
* `expectedKernelAddress` / `expectedChainId` explicitly.
|
|
63
|
+
*
|
|
64
|
+
* @module delivery/MockDeliveryChannel
|
|
65
|
+
* @see {@link DeliveryChannel}
|
|
66
|
+
* @see {@link DeliverySetupBuilder.verify}
|
|
67
|
+
* @see {@link DeliveryEnvelopeBuilder.verify}
|
|
68
|
+
*/
|
|
69
|
+
import type { DeliveryChannel, DeliverySubscription, SetupCallback, EnvelopeCallback } from './channel';
|
|
70
|
+
import type { DeliverySetupWireV1, DeliveryEnvelopeWireV1 } from './types';
|
|
71
|
+
import { type LogFn } from './channelLog';
|
|
72
|
+
/**
|
|
73
|
+
* Construction options for {@link MockDeliveryChannel}.
|
|
74
|
+
*
|
|
75
|
+
* All fields are optional. Defaults are tuned for the most common case
|
|
76
|
+
* (unit tests that publish locally-signed wire objects and expect them
|
|
77
|
+
* to round-trip without configuration).
|
|
78
|
+
*/
|
|
79
|
+
export interface MockDeliveryChannelOptions {
|
|
80
|
+
/**
|
|
81
|
+
* Pluggable logger. Defaults to {@link noopLog} (silent).
|
|
82
|
+
*
|
|
83
|
+
* Channels log at `warn` when:
|
|
84
|
+
* - a publish is rejected because verification failed (one record
|
|
85
|
+
* per rejected publish, with the structured error code),
|
|
86
|
+
* - a subscriber callback threw and was swallowed (per security
|
|
87
|
+
* invariant #2).
|
|
88
|
+
*/
|
|
89
|
+
log?: LogFn;
|
|
90
|
+
/**
|
|
91
|
+
* If `true`, skip signature verification on publish. The channel will
|
|
92
|
+
* still compute the dedup hash and fan out, but it will accept
|
|
93
|
+
* malformed or tampered wires.
|
|
94
|
+
*
|
|
95
|
+
* Used by tests that need to inject poisoned signatures to exercise
|
|
96
|
+
* dedup-after-verify behavior, channel-level rejection paths, or
|
|
97
|
+
* subscriber error isolation under malformed input. Defaults to
|
|
98
|
+
* `false`.
|
|
99
|
+
*/
|
|
100
|
+
skipVerifyForTests?: boolean;
|
|
101
|
+
/**
|
|
102
|
+
* Allowlisted kernel address. When set, verification enforces this
|
|
103
|
+
* value (matches the production posture). When unset, verification
|
|
104
|
+
* falls back to `signed.kernelAddress` (the wire's self-asserted
|
|
105
|
+
* kernel), which is the convenient default for tests that have
|
|
106
|
+
* already signed under an arbitrary kernel and just want it accepted.
|
|
107
|
+
*/
|
|
108
|
+
expectedKernelAddress?: string;
|
|
109
|
+
/**
|
|
110
|
+
* Allowlisted chainId. Same fallback semantics as
|
|
111
|
+
* {@link expectedKernelAddress} — when unset, defaults to
|
|
112
|
+
* `signed.chainId`.
|
|
113
|
+
*/
|
|
114
|
+
expectedChainId?: number;
|
|
115
|
+
/**
|
|
116
|
+
* Injectable wall clock returning Unix seconds. When set, passed
|
|
117
|
+
* through to the underlying builder `verify()` calls so timestamp
|
|
118
|
+
* skew and expiry checks are deterministic across tests.
|
|
119
|
+
*/
|
|
120
|
+
now?: () => number;
|
|
121
|
+
}
|
|
122
|
+
/**
|
|
123
|
+
* In-process loopback delivery channel.
|
|
124
|
+
*
|
|
125
|
+
* Two parties (or any number) share a single instance and exchange
|
|
126
|
+
* wire objects via `publishSetup` / `publishEnvelope` / `subscribe*`.
|
|
127
|
+
* No network transport.
|
|
128
|
+
*
|
|
129
|
+
* @example
|
|
130
|
+
* ```typescript
|
|
131
|
+
* const channel = new MockDeliveryChannel();
|
|
132
|
+
*
|
|
133
|
+
* // Provider subscribes for setups on a txId.
|
|
134
|
+
* const sub = await channel.subscribeSetups(txId, async (wire) => {
|
|
135
|
+
* // wire has already been verified by the channel.
|
|
136
|
+
* await onSetup(wire);
|
|
137
|
+
* });
|
|
138
|
+
*
|
|
139
|
+
* // Requester publishes the setup.
|
|
140
|
+
* await channel.publishSetup(setupWire);
|
|
141
|
+
*
|
|
142
|
+
* // …later
|
|
143
|
+
* await sub.close();
|
|
144
|
+
* channel.close();
|
|
145
|
+
* ```
|
|
146
|
+
*/
|
|
147
|
+
export declare class MockDeliveryChannel implements DeliveryChannel {
|
|
148
|
+
private readonly log;
|
|
149
|
+
private readonly skipVerifyForTests;
|
|
150
|
+
private readonly expectedKernelAddress?;
|
|
151
|
+
private readonly expectedChainId?;
|
|
152
|
+
private readonly nowFn?;
|
|
153
|
+
private readonly setupStoreByTxId;
|
|
154
|
+
private readonly envelopeStoreByTxId;
|
|
155
|
+
private readonly setupSubscribersByTxId;
|
|
156
|
+
private readonly envelopeSubscribersByTxId;
|
|
157
|
+
private closed;
|
|
158
|
+
constructor(opts?: MockDeliveryChannelOptions);
|
|
159
|
+
publishSetup(setup: DeliverySetupWireV1): Promise<void>;
|
|
160
|
+
publishEnvelope(envelope: DeliveryEnvelopeWireV1): Promise<void>;
|
|
161
|
+
subscribeSetups(txId: `0x${string}`, callback: SetupCallback): Promise<DeliverySubscription>;
|
|
162
|
+
subscribeEnvelopes(txId: `0x${string}`, callback: EnvelopeCallback): Promise<DeliverySubscription>;
|
|
163
|
+
getSetups(txId?: `0x${string}`): Promise<DeliverySetupWireV1[]>;
|
|
164
|
+
getEnvelopes(txId?: `0x${string}`): Promise<DeliveryEnvelopeWireV1[]>;
|
|
165
|
+
/**
|
|
166
|
+
* Synchronous snapshot of all setups currently stored for `txId`,
|
|
167
|
+
* or all setups across every txId when `txId` is omitted. Returns a
|
|
168
|
+
* defensive copy.
|
|
169
|
+
*/
|
|
170
|
+
getAllSetups(txId?: string): DeliverySetupWireV1[];
|
|
171
|
+
/**
|
|
172
|
+
* Synchronous snapshot of all envelopes currently stored for `txId`,
|
|
173
|
+
* or all envelopes across every txId when `txId` is omitted. Returns
|
|
174
|
+
* a defensive copy.
|
|
175
|
+
*/
|
|
176
|
+
getAllEnvelopes(txId?: string): DeliveryEnvelopeWireV1[];
|
|
177
|
+
/**
|
|
178
|
+
* Count of currently-active subscriptions (setup + envelope combined).
|
|
179
|
+
* Useful for leak tests.
|
|
180
|
+
*/
|
|
181
|
+
activeSubscriptionCount(): number;
|
|
182
|
+
/**
|
|
183
|
+
* Reset all stored state. Does NOT touch subscriber lists — existing
|
|
184
|
+
* subscribers remain registered for future publishes.
|
|
185
|
+
*/
|
|
186
|
+
clear(): void;
|
|
187
|
+
/**
|
|
188
|
+
* Mark all current subscriptions cancelled and drop them. Storage is
|
|
189
|
+
* preserved so tests can still assert on what was published. Future
|
|
190
|
+
* `publish*` / `subscribe*` calls reject with a closed-channel error.
|
|
191
|
+
*/
|
|
192
|
+
close(): void;
|
|
193
|
+
private fanoutSetup;
|
|
194
|
+
private fanoutEnvelope;
|
|
195
|
+
/**
|
|
196
|
+
* Deliver a setup to a single subscriber, honoring per-subscription
|
|
197
|
+
* dedup and isolating subscriber errors.
|
|
198
|
+
*
|
|
199
|
+
* NOTE on dedup ordering: the channel-wide dedup happens at publish
|
|
200
|
+
* time AFTER verify; the per-subscription dedup here is purely to
|
|
201
|
+
* prevent double-fire when replay-on-subscribe races with a live
|
|
202
|
+
* fanout for the same wire. It does NOT defend against signature
|
|
203
|
+
* poisoning — that's handled at publish time.
|
|
204
|
+
*/
|
|
205
|
+
private deliverSetup;
|
|
206
|
+
private deliverEnvelope;
|
|
207
|
+
}
|
|
208
|
+
//# sourceMappingURL=MockDeliveryChannel.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"MockDeliveryChannel.d.ts","sourceRoot":"","sources":["../../src/delivery/MockDeliveryChannel.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmEG;AAEH,OAAO,KAAK,EACV,eAAe,EACf,oBAAoB,EACpB,aAAa,EACb,gBAAgB,EACjB,MAAM,WAAW,CAAC;AACnB,OAAO,KAAK,EACV,mBAAmB,EACnB,sBAAsB,EACvB,MAAM,SAAS,CAAC;AAGjB,OAAO,EAAE,KAAK,KAAK,EAAW,MAAM,cAAc,CAAC;AAMnD;;;;;;GAMG;AACH,MAAM,WAAW,0BAA0B;IACzC;;;;;;;;OAQG;IACH,GAAG,CAAC,EAAE,KAAK,CAAC;IAEZ;;;;;;;;;OASG;IACH,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAE7B;;;;;;OAMG;IACH,qBAAqB,CAAC,EAAE,MAAM,CAAC;IAE/B;;;;OAIG;IACH,eAAe,CAAC,EAAE,MAAM,CAAC;IAEzB;;;;OAIG;IACH,GAAG,CAAC,EAAE,MAAM,MAAM,CAAC;CACpB;AAsCD;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,qBAAa,mBAAoB,YAAW,eAAe;IACzD,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAQ;IAC5B,OAAO,CAAC,QAAQ,CAAC,kBAAkB,CAAU;IAC7C,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,gBAAgB,CAAiC;IAClE,OAAO,CAAC,QAAQ,CAAC,mBAAmB,CAAoC;IACxE,OAAO,CAAC,QAAQ,CAAC,sBAAsB,CAA2C;IAClF,OAAO,CAAC,QAAQ,CAAC,yBAAyB,CAA8C;IAExF,OAAO,CAAC,MAAM,CAAS;gBAEX,IAAI,GAAE,0BAA+B;IAY3C,YAAY,CAAC,KAAK,EAAE,mBAAmB,GAAG,OAAO,CAAC,IAAI,CAAC;IAqDvD,eAAe,CAAC,QAAQ,EAAE,sBAAsB,GAAG,OAAO,CAAC,IAAI,CAAC;IAiDhE,eAAe,CACnB,IAAI,EAAE,KAAK,MAAM,EAAE,EACnB,QAAQ,EAAE,aAAa,GACtB,OAAO,CAAC,oBAAoB,CAAC;IAiD1B,kBAAkB,CACtB,IAAI,EAAE,KAAK,MAAM,EAAE,EACnB,QAAQ,EAAE,gBAAgB,GACzB,OAAO,CAAC,oBAAoB,CAAC;IAiD1B,SAAS,CAAC,IAAI,CAAC,EAAE,KAAK,MAAM,EAAE,GAAG,OAAO,CAAC,mBAAmB,EAAE,CAAC;IAI/D,YAAY,CAAC,IAAI,CAAC,EAAE,KAAK,MAAM,EAAE,GAAG,OAAO,CAAC,sBAAsB,EAAE,CAAC;IAQ3E;;;;OAIG;IACH,YAAY,CAAC,IAAI,CAAC,EAAE,MAAM,GAAG,mBAAmB,EAAE;IAYlD;;;;OAIG;IACH,eAAe,CAAC,IAAI,CAAC,EAAE,MAAM,GAAG,sBAAsB,EAAE;IAYxD;;;OAGG;IACH,uBAAuB,IAAI,MAAM;IAOjC;;;OAGG;IACH,KAAK,IAAI,IAAI;IAKb;;;;OAIG;IACH,KAAK,IAAI,IAAI;IAiBb,OAAO,CAAC,WAAW;IAcnB,OAAO,CAAC,cAAc;IAYtB;;;;;;;;;OASG;IACH,OAAO,CAAC,YAAY;IAgBpB,OAAO,CAAC,eAAe;CAkBxB"}
|