@real-life/trust-protocol 0.6.0 → 0.6.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +47 -0
- package/README.md +19 -1
- package/dist/engine.d.ts +4 -1
- package/dist/engine.d.ts.map +1 -1
- package/dist/engine.js +104 -8
- package/dist/engine.js.map +1 -1
- package/dist/holder-api.d.ts +7 -1
- package/dist/holder-api.d.ts.map +1 -1
- package/dist/holder-api.js +15 -0
- package/dist/holder-api.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js.map +1 -1
- package/dist/results.d.ts +37 -2
- package/dist/results.d.ts.map +1 -1
- package/dist/results.js.map +1 -1
- package/package.json +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,52 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.6.1
|
|
4
|
+
|
|
5
|
+
One actId, one result.
|
|
6
|
+
|
|
7
|
+
- **`replay(actId, when)`**: the journaled result of a human act without
|
|
8
|
+
the act — `{ok: true, result: {actId, commitSeq, at, events, outbound}}`,
|
|
9
|
+
each document of the act with `live` (whether a repeat at `when` would
|
|
10
|
+
hand it out), or `{ok: false, code: 'unknown-act'}` (`actid-missing` for
|
|
11
|
+
an empty id). For `sendMessage` the `message.sent` event carries the
|
|
12
|
+
`mid` and the `digest`; `at` is the commit time the message's `sentAt`
|
|
13
|
+
was taken from. A pure read in the holder's queue: nothing runs, nothing
|
|
14
|
+
is given up, nothing commits, lastWhen included; no key is used, so it
|
|
15
|
+
answers on an opening whose keys are locked. New types `ReplayResult`,
|
|
16
|
+
`ActReplay`, `ReplayOutbound`.
|
|
17
|
+
- **The rule, stated and tested** (it held before; the engine takes one
|
|
18
|
+
path for every human act, and the tests cover `sendMessage`, `show`,
|
|
19
|
+
`scan`, `setProfile`, `foundGroup`, `block`, `unblock` and `trust`): a repeat under a journaled actId answers the
|
|
20
|
+
journaled events — for `sendMessage` the same `mid` — whatever the clock
|
|
21
|
+
says (ahead, set back), across `close()` and a new opening, with keys
|
|
22
|
+
that answer nothing, and after a commit whose outcome was unknown; it
|
|
23
|
+
never mints a second `mid`. Another input under the same actId stays
|
|
24
|
+
`actid-conflict`.
|
|
25
|
+
- **The journal keeps an act as long as its documents' completion**: the
|
|
26
|
+
retention max(P90D, the retry horizon) now runs from the act's commit
|
|
27
|
+
and from the last step of each of its documents (delivered or failed),
|
|
28
|
+
whichever is later; a document not yet terminal keeps the act. Before,
|
|
29
|
+
it ran from the commit alone, so an act delivered late left the journal
|
|
30
|
+
while its delivery status stayed. The bound is in holder time and of
|
|
31
|
+
time, not of count: one entry per human act, removed by the tick that is
|
|
32
|
+
due. A clock set ahead by more than the retention ends it early in real time; `replay` then answers `unknown-act`, and
|
|
33
|
+
a repeat under that actId would be a new act. An app asks `replay`
|
|
34
|
+
instead of repeating an act blind.
|
|
35
|
+
- **Fixes**: a tick that drops journal entries keeps an entry whose actId
|
|
36
|
+
is `__proto__` as an own member (it set the prototype of the kept
|
|
37
|
+
journal, and the commit failed the codec); the settling after an
|
|
38
|
+
`unknown-commit-outcome` counts the act as landed only when the journal
|
|
39
|
+
holds it with the same events, not another opening's commit of the same
|
|
40
|
+
actId at the same commitSeq; an act that issues documents names in
|
|
41
|
+
`nextDueAt` each one's first retry or send deadline, whichever comes
|
|
42
|
+
first (a repeat names its live documents' the same way), so a holder
|
|
43
|
+
whose timer had run out reaches the retries, the give-up and the
|
|
44
|
+
journal's end on the timers alone. An act without documents names no
|
|
45
|
+
journal deadline; the next `resume` names its entry's end, a `tick`
|
|
46
|
+
does not.
|
|
47
|
+
- The state and codec 3 are unchanged: the journal was already part of the
|
|
48
|
+
stored state.
|
|
49
|
+
|
|
3
50
|
## 0.6.0
|
|
4
51
|
|
|
5
52
|
Takes up Delivery Contract 0.83: the holder keeps custody of what waits
|
package/README.md
CHANGED
|
@@ -118,7 +118,25 @@ consent to an introduction), `trust`, `untrust`, `pauseTrust`, `setClass`,
|
|
|
118
118
|
`addDevice`, `revokeDevice`. Not
|
|
119
119
|
human: `receive`, `report`, `resume`, `tick`, `recover`, `takeMessages`.
|
|
120
120
|
Reads: `contacts`, `contact`, `groups`, `profile`, `prompts`, `inbox`,
|
|
121
|
-
`deliveryStatus`, `deviceKey`, `snapshot`, `subscribe`.
|
|
121
|
+
`deliveryStatus`, `deviceKey`, `replay`, `snapshot`, `subscribe`.
|
|
122
|
+
|
|
123
|
+
One actId, one result: every human act is journaled under its actId with
|
|
124
|
+
its result. A repeat under the same actId answers the journaled events
|
|
125
|
+
(for `sendMessage` the same `mid`) at any clock and across a lock and a
|
|
126
|
+
new opening; it never runs the act again, and another input under the
|
|
127
|
+
same actId is `actid-conflict`. `replay(actId, when)` reads that result
|
|
128
|
+
without the act: `{ok: true, result: {actId, commitSeq, at, events,
|
|
129
|
+
outbound}}` (each document with `live`: whether a repeat at `when` would
|
|
130
|
+
hand it out), or `{ok: false, code: 'unknown-act'}`. It commits nothing and
|
|
131
|
+
needs no keys. The journal keeps an act for max(P90D, the retry horizon)
|
|
132
|
+
after its commit and after the last step of each of its documents
|
|
133
|
+
(delivered or failed; one not yet terminal keeps it), counted in holder
|
|
134
|
+
time and removed by the tick that is due (an act without documents
|
|
135
|
+
names no deadline of its own; the next `resume` names it, a `tick`
|
|
136
|
+
does not); after that its actId is unknown. An app that does not know whether an act committed (a crash, an
|
|
137
|
+
`unknown-commit-outcome`, a lock) asks `replay` and does not repeat the act
|
|
138
|
+
blind: `unknown-act` means the act did not commit or has left the
|
|
139
|
+
journal, and acting anew is the human's decision. Custody:
|
|
122
140
|
`pendingTransport`, `handOver`, `mayHandOver`, `close`, `closed`.
|
|
123
141
|
|
|
124
142
|
## What the root exports
|
package/dist/engine.d.ts
CHANGED
|
@@ -2,7 +2,7 @@ import type { Dec, Duty, HolderState, Millis, Prompt, PromptChoice, PromptKind }
|
|
|
2
2
|
import type { Access, DeliveryReport, KeyProvider, KeyRelease, Log, Outbound, PreTransportReason, Recipient, RetryPolicy, Store } from './ports.js';
|
|
3
3
|
import type { Envelope } from './delivery.js';
|
|
4
4
|
import type { HolderEvent } from './events.js';
|
|
5
|
-
import type { ActError, ActResult, ReceiveResult, ResumeResult } from './results.js';
|
|
5
|
+
import type { ActError, ActResult, ReceiveResult, ReplayResult, ResumeResult } from './results.js';
|
|
6
6
|
import type { Entropy, PlatformRandom } from './entropy.js';
|
|
7
7
|
import type { Arrival, Channel, ReceivedDocument, TaskDiscarded, TaskRefusal } from './receive.js';
|
|
8
8
|
import type { CommitOp } from './invariants.js';
|
|
@@ -283,6 +283,9 @@ export interface Engine {
|
|
|
283
283
|
receive(env: unknown, when: Millis): Promise<ReceiveResult>;
|
|
284
284
|
subscribe(listener: CommitListener): () => void;
|
|
285
285
|
snapshot(): Promise<EngineSnapshot>;
|
|
286
|
+
/** the journaled result of the human act `actId`, or `unknown-act`: a
|
|
287
|
+
* pure read in the queue — never runs, gives up or commits anything */
|
|
288
|
+
replay(actId: string, when: Millis): Promise<ReplayResult>;
|
|
286
289
|
/** what the holder keeps for transport at `when` (Delivery RLTP-DEL-6120):
|
|
287
290
|
* refused until a resume of this engine has completed */
|
|
288
291
|
pendingTransport(when: Millis): Promise<TransportView | TransportRefusal>;
|
package/dist/engine.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"engine.d.ts","sourceRoot":"","sources":["../src/engine.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"engine.d.ts","sourceRoot":"","sources":["../src/engine.ts"],"names":[],"mappings":"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"}
|
package/dist/engine.js
CHANGED
|
@@ -42,7 +42,12 @@
|
|
|
42
42
|
// that give-up runs first as an operation of its own on the one commit
|
|
43
43
|
// path (resume's CommitOp, its timer carried to the replay's answer)
|
|
44
44
|
// - outbound of an act starts at attempt 1 with nextAttemptAt =
|
|
45
|
-
// when + ceil(backoff(1));
|
|
45
|
+
// when + ceil(backoff(1)); the act names that or the document's send
|
|
46
|
+
// deadline, whichever is first, in nextDueAt (a repeat names its live
|
|
47
|
+
// documents' the same way), so an idle holder's timer reaches the
|
|
48
|
+
// retries, the give-up and the journal's end. An act without documents
|
|
49
|
+
// names no journal deadline: the next resume names the end of its entry
|
|
50
|
+
// (a tick does not); resume() re-emits only items that are due
|
|
46
51
|
// and pauses re-emission while the last step is awaiting-transport
|
|
47
52
|
// (the adapter holds the item) and never re-emits an accepted one. It
|
|
48
53
|
// gives up every non-terminal item (submitted, held or accepted) at
|
|
@@ -58,7 +63,24 @@
|
|
|
58
63
|
// due for the give-up, at their current attempt; one due for it is
|
|
59
64
|
// given up in a commit of its own first (6115: never handed out again). Idempotency is bounded by the journal's retention:
|
|
60
65
|
// max(P90D, retry.horizonMs), the key-retention of Delivery §7 that
|
|
61
|
-
// bounds effects and their acks
|
|
66
|
+
// bounds effects and their acks, counted from the act's commit and
|
|
67
|
+
// from the last step of each of its documents, whichever is later (a
|
|
68
|
+
// document not yet terminal keeps the act): the act's result stays as
|
|
69
|
+
// long as its documents' completion does; after it the same actId is
|
|
70
|
+
// a new act. The retention runs in holder time (an entry leaves at the
|
|
71
|
+
// tick at or after its end, `when` raised to lastWhen): a clock set
|
|
72
|
+
// ahead by more than the retention ends it early in real time. The
|
|
73
|
+
// bound is one of time, not of count: one entry per human act (its
|
|
74
|
+
// events and document digests, the documents themselves kept beside
|
|
75
|
+
// it), removed by the tick that is due. A replay
|
|
76
|
+
// answers from the journal alone, before any preparation: no key, no
|
|
77
|
+
// entropy, no new document; the time it reads at changes nothing in it
|
|
78
|
+
// - replay(actId, when) is the journal read without the act: in the
|
|
79
|
+
// queue (after the settling of an unsettled commit), on the stored
|
|
80
|
+
// state, committing nothing, lastWhen included; it names which of the
|
|
81
|
+
// act's documents a repeat at max(when, lastWhen) would hand out, and
|
|
82
|
+
// gives none up. unknown-act: no entry under the id (never committed,
|
|
83
|
+
// or past the retention)
|
|
62
84
|
// - KeyProvider, Log and Access rejections inside a preparation become
|
|
63
85
|
// InfraError('key-provider' | 'log' | 'access') with the cause. Known
|
|
64
86
|
// limitation: a provider's argument errors (a module passing a label
|
|
@@ -659,8 +681,11 @@ class HolderEngine {
|
|
|
659
681
|
if (!u)
|
|
660
682
|
return;
|
|
661
683
|
const { state } = await this.#read();
|
|
684
|
+
// the journal entry at that commitSeq with these very events: another
|
|
685
|
+
// opening's commit of the same act at the same commitSeq is not this one
|
|
662
686
|
const landed = jcs(state) === u.text ||
|
|
663
|
-
(u.actId !== undefined && Object.hasOwn(state.acts, u.actId) && state.acts[u.actId].commitSeq === u.commitSeq
|
|
687
|
+
(u.actId !== undefined && Object.hasOwn(state.acts, u.actId) && state.acts[u.actId].commitSeq === u.commitSeq &&
|
|
688
|
+
jcs(state.acts[u.actId].events) === jcs(u.events));
|
|
664
689
|
this.#unsettled = null;
|
|
665
690
|
if (landed)
|
|
666
691
|
this.#announce(u.commitSeq, u.events);
|
|
@@ -720,6 +745,15 @@ class HolderEngine {
|
|
|
720
745
|
attempt--;
|
|
721
746
|
continue;
|
|
722
747
|
}
|
|
748
|
+
// the timer as the act named it: the next attempt of its live documents
|
|
749
|
+
// (and a give-up's own timer), so a repeat answers as the act did
|
|
750
|
+
const soon = (t) => { if (t !== undefined && t !== null)
|
|
751
|
+
replayWake = replayWake === undefined ? t : Math.min(replayWake, t); };
|
|
752
|
+
for (const d of live) {
|
|
753
|
+
const it = this.#itemOf(state, d);
|
|
754
|
+
soon(it.nextAttemptAt);
|
|
755
|
+
soon(notAfterOf(it, this.#policy.horizonMs));
|
|
756
|
+
}
|
|
723
757
|
return { ok: true, outbound: live.map((d) => this.#outboundOf(state, d)), events: freezeDeep(events), ...(replayWake !== undefined ? { nextDueAt: replayWake } : {}) };
|
|
724
758
|
}
|
|
725
759
|
// 2 — prepare, bound to this snapshot
|
|
@@ -798,6 +832,20 @@ class HolderEngine {
|
|
|
798
832
|
const effects = r.renames?.length ? renameAcks(r.state.effects, r.renames) : r.state.effects;
|
|
799
833
|
const next = { ...r.state, effects, commitSeq: seq, lastWhen: at, outbox, duties, acts };
|
|
800
834
|
const text = encodeState(next); // validates; an invalid next state is a programming error
|
|
835
|
+
// the timer for the documents this commit issues: each one's first
|
|
836
|
+
// retry or its send deadline, whichever comes first, beside the duty
|
|
837
|
+
// work the module's state opened
|
|
838
|
+
let full = wake;
|
|
839
|
+
if (r.nextDueAt === undefined && def !== this.#builtins.resume) {
|
|
840
|
+
const soon = (t) => { if (t !== undefined && t !== null)
|
|
841
|
+
full = full === undefined ? t : Math.min(full, t); };
|
|
842
|
+
// each document's first retry or its send deadline, whichever comes first
|
|
843
|
+
for (const o of outbound) {
|
|
844
|
+
soon(outbox[o.digest].nextAttemptAt);
|
|
845
|
+
soon(notAfterOf(outbox[o.digest], this.#policy.horizonMs));
|
|
846
|
+
}
|
|
847
|
+
}
|
|
848
|
+
const fullExtra = { ...(full !== undefined ? { nextDueAt: full } : {}), ...(r.detail !== undefined ? { detail: r.detail } : {}) };
|
|
801
849
|
if (this.#check) {
|
|
802
850
|
const d = (r.detail ?? {});
|
|
803
851
|
const pick = (k) => (d[k] !== undefined ? { [k]: d[k] } : {});
|
|
@@ -817,7 +865,7 @@ class HolderEngine {
|
|
|
817
865
|
continue;
|
|
818
866
|
// 4 — release
|
|
819
867
|
this.#announce(seq, events);
|
|
820
|
-
return { ok: true, outbound: [...emit, ...release, ...outbound], events, ...
|
|
868
|
+
return { ok: true, outbound: [...emit, ...release, ...outbound], events, ...fullExtra };
|
|
821
869
|
}
|
|
822
870
|
throw new InfraError('commit-conflict', `no commit after ${this.#policy.commitAttempts} attempts`);
|
|
823
871
|
}
|
|
@@ -833,8 +881,11 @@ class HolderEngine {
|
|
|
833
881
|
out.push(p.expiresAt);
|
|
834
882
|
for (const e of Object.values(state.effects))
|
|
835
883
|
out.push(e.expiresAt);
|
|
836
|
-
for (const a of Object.values(state.acts))
|
|
837
|
-
|
|
884
|
+
for (const a of Object.values(state.acts)) {
|
|
885
|
+
const end = actEnd(state, a, retention);
|
|
886
|
+
if (end !== Infinity)
|
|
887
|
+
out.push(end);
|
|
888
|
+
}
|
|
838
889
|
for (const it of Object.values(state.outbox)) {
|
|
839
890
|
const t = triasOf(it);
|
|
840
891
|
if ((t === 'delivered' || t === 'failed') && it.history.length)
|
|
@@ -983,9 +1034,10 @@ class HolderEngine {
|
|
|
983
1034
|
let dropped = false;
|
|
984
1035
|
const keep = (rec, live) => {
|
|
985
1036
|
const out = {};
|
|
1037
|
+
// defined, not assigned: a key such as `__proto__` (an app's actId) stays an own member
|
|
986
1038
|
for (const [k, v] of Object.entries(rec)) {
|
|
987
1039
|
if (live(v, k))
|
|
988
|
-
out
|
|
1040
|
+
Object.defineProperty(out, k, { value: v, enumerable: true, writable: true, configurable: true });
|
|
989
1041
|
else
|
|
990
1042
|
dropped = true;
|
|
991
1043
|
}
|
|
@@ -995,7 +1047,7 @@ class HolderEngine {
|
|
|
995
1047
|
// act journal after the retention
|
|
996
1048
|
const effects = keep(state.effects, (x) => x.expiresAt > when);
|
|
997
1049
|
const prompts = keep(state.prompts, (x) => x.expiresAt === undefined || x.expiresAt > when);
|
|
998
|
-
const acts = keep(state.acts, (x) => x
|
|
1050
|
+
const acts = keep(state.acts, (x) => actEnd(state, x, retention) > when);
|
|
999
1051
|
// terminal outbox items, the retention after their last step, unless a
|
|
1000
1052
|
// kept journal entry still answers with them (replay needs the item)
|
|
1001
1053
|
const journaled = new Set(Object.values(acts).flatMap((a) => a.outboundDigests));
|
|
@@ -1589,6 +1641,31 @@ class HolderEngine {
|
|
|
1589
1641
|
return Object.freeze({ state, commitSeq: state.commitSeq });
|
|
1590
1642
|
});
|
|
1591
1643
|
}
|
|
1644
|
+
replay(actId, when) {
|
|
1645
|
+
try {
|
|
1646
|
+
checkWhen(when);
|
|
1647
|
+
}
|
|
1648
|
+
catch (e) {
|
|
1649
|
+
return Promise.reject(e);
|
|
1650
|
+
}
|
|
1651
|
+
if (typeof actId !== 'string' || actId === '')
|
|
1652
|
+
return Promise.resolve(Object.freeze({ ok: false, code: 'actid-missing' }));
|
|
1653
|
+
return this.#enqueue(async () => {
|
|
1654
|
+
const { state } = await this.#read();
|
|
1655
|
+
if (!Object.hasOwn(state.acts, actId))
|
|
1656
|
+
return Object.freeze({ ok: false, code: 'unknown-act' });
|
|
1657
|
+
const rec = state.acts[actId];
|
|
1658
|
+
// as a repeat of the act would see them at max(when, lastWhen), without
|
|
1659
|
+
// the give-up it would commit first: a pure read
|
|
1660
|
+
const at = Math.max(when, state.lastWhen);
|
|
1661
|
+
const outbound = rec.outboundDigests.map((digest) => {
|
|
1662
|
+
const it = Object.hasOwn(state.outbox, digest) ? state.outbox[digest] : undefined;
|
|
1663
|
+
const t = it ? triasOf(it) : undefined;
|
|
1664
|
+
return { digest, live: it !== undefined && t !== 'delivered' && t !== 'failed' && this.#giveUp(it, at) === null };
|
|
1665
|
+
});
|
|
1666
|
+
return freezeDeep({ ok: true, result: { actId: rec.actId, commitSeq: rec.commitSeq, at: rec.at, events: structuredClone(rec.events), outbound } });
|
|
1667
|
+
});
|
|
1668
|
+
}
|
|
1592
1669
|
pendingTransport(when) {
|
|
1593
1670
|
try {
|
|
1594
1671
|
checkWhen(when);
|
|
@@ -1684,6 +1761,25 @@ class HolderEngine {
|
|
|
1684
1761
|
}
|
|
1685
1762
|
get closed() { return this.#closed; }
|
|
1686
1763
|
}
|
|
1764
|
+
/** When the journal entry of an act may leave (tick): the retention after
|
|
1765
|
+
* its commit and after the last step of each of its documents that is
|
|
1766
|
+
* terminal — the act's result stays as long as the completion of its
|
|
1767
|
+
* documents does; Infinity while one of them is not terminal yet (its
|
|
1768
|
+
* give-up makes it terminal, and the deadline follows then). */
|
|
1769
|
+
const actEnd = (state, a, retention) => {
|
|
1770
|
+
let end = a.at;
|
|
1771
|
+
for (const d of a.outboundDigests) {
|
|
1772
|
+
if (!Object.hasOwn(state.outbox, d))
|
|
1773
|
+
continue;
|
|
1774
|
+
const it = state.outbox[d];
|
|
1775
|
+
const t = triasOf(it);
|
|
1776
|
+
if (t !== 'delivered' && t !== 'failed')
|
|
1777
|
+
return Infinity;
|
|
1778
|
+
if (it.history.length)
|
|
1779
|
+
end = Math.max(end, it.history[it.history.length - 1].at);
|
|
1780
|
+
}
|
|
1781
|
+
return end + retention;
|
|
1782
|
+
};
|
|
1687
1783
|
/** The send deadline of an outbox item: the horizon from its first
|
|
1688
1784
|
* submission, or the sender lifetime its type declared if that is
|
|
1689
1785
|
* earlier (#giveUp's two bounds as one instant). */
|