@serfab/cadre-core 1.7.0 → 1.8.0

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.
Files changed (162) hide show
  1. package/README.md +8 -6
  2. package/dist/cadre-node.d.ts +386 -114
  3. package/dist/cadre-node.js +887 -359
  4. package/dist/cadre-node.js.map +1 -1
  5. package/dist/control-authorization.d.ts +2 -2
  6. package/dist/control-authorization.js +1 -0
  7. package/dist/control-authorization.js.map +1 -1
  8. package/dist/control-cohort.d.ts +6 -0
  9. package/dist/control-cohort.js +6 -0
  10. package/dist/control-cohort.js.map +1 -1
  11. package/dist/control-database.d.ts +46 -8
  12. package/dist/control-database.js +97 -18
  13. package/dist/control-database.js.map +1 -1
  14. package/dist/control-formation-recorder.d.ts +37 -14
  15. package/dist/control-formation-recorder.js +60 -10
  16. package/dist/control-formation-recorder.js.map +1 -1
  17. package/dist/control-read-retry.d.ts +13 -12
  18. package/dist/control-read-retry.js +14 -12
  19. package/dist/control-read-retry.js.map +1 -1
  20. package/dist/control-schema.d.ts +1 -1
  21. package/dist/control-schema.js +67 -5
  22. package/dist/control-schema.js.map +1 -1
  23. package/dist/control-stream.d.ts +9 -1
  24. package/dist/control-stream.js +24 -1
  25. package/dist/control-stream.js.map +1 -1
  26. package/dist/control-write-retry.d.ts +12 -2
  27. package/dist/control-write-retry.js +13 -2
  28. package/dist/control-write-retry.js.map +1 -1
  29. package/dist/delegate-admission.d.ts +11 -8
  30. package/dist/delegate-admission.js +19 -11
  31. package/dist/delegate-admission.js.map +1 -1
  32. package/dist/diagnostics/connection-path.d.ts +0 -7
  33. package/dist/diagnostics/connection-path.js +0 -7
  34. package/dist/diagnostics/connection-path.js.map +1 -1
  35. package/dist/formation-approval.d.ts +7 -0
  36. package/dist/formation-approval.js +9 -3
  37. package/dist/formation-approval.js.map +1 -1
  38. package/dist/fs-atomic.d.ts +11 -2
  39. package/dist/fs-atomic.js +13 -3
  40. package/dist/fs-atomic.js.map +1 -1
  41. package/dist/hibernation-manager.d.ts +111 -8
  42. package/dist/hibernation-manager.js +234 -49
  43. package/dist/hibernation-manager.js.map +1 -1
  44. package/dist/index.d.ts +8 -6
  45. package/dist/index.js +15 -9
  46. package/dist/index.js.map +1 -1
  47. package/dist/joined-strand-store.d.ts +90 -25
  48. package/dist/joined-strand-store.js +223 -55
  49. package/dist/joined-strand-store.js.map +1 -1
  50. package/dist/key-store-file.js +14 -5
  51. package/dist/key-store-file.js.map +1 -1
  52. package/dist/link-budget.d.ts +367 -69
  53. package/dist/link-budget.js +375 -72
  54. package/dist/link-budget.js.map +1 -1
  55. package/dist/membership-connection-gater.d.ts +30 -43
  56. package/dist/membership-connection-gater.js +31 -42
  57. package/dist/membership-connection-gater.js.map +1 -1
  58. package/dist/peer-dial.d.ts +24 -4
  59. package/dist/peer-dial.js +74 -5
  60. package/dist/peer-dial.js.map +1 -1
  61. package/dist/peer-join-backfill.d.ts +2 -1
  62. package/dist/peer-join-backfill.js +6 -5
  63. package/dist/peer-join-backfill.js.map +1 -1
  64. package/dist/push-fanout.d.ts +6 -0
  65. package/dist/push-fanout.js +6 -0
  66. package/dist/push-fanout.js.map +1 -1
  67. package/dist/relay-reservation.d.ts +3 -1
  68. package/dist/relay-reservation.js +3 -1
  69. package/dist/relay-reservation.js.map +1 -1
  70. package/dist/relay-server.d.ts +79 -0
  71. package/dist/relay-server.js +74 -0
  72. package/dist/relay-server.js.map +1 -0
  73. package/dist/seed-bootstrap.d.ts +57 -4
  74. package/dist/seed-bootstrap.js +107 -83
  75. package/dist/seed-bootstrap.js.map +1 -1
  76. package/dist/storage-scope.d.ts +33 -17
  77. package/dist/storage-scope.js +44 -23
  78. package/dist/storage-scope.js.map +1 -1
  79. package/dist/strand-addr-protocol.d.ts +58 -21
  80. package/dist/strand-addr-protocol.js +133 -85
  81. package/dist/strand-addr-protocol.js.map +1 -1
  82. package/dist/strand-database.d.ts +20 -2
  83. package/dist/strand-database.js +42 -5
  84. package/dist/strand-database.js.map +1 -1
  85. package/dist/strand-first-sync-gate.d.ts +59 -21
  86. package/dist/strand-first-sync-gate.js +58 -19
  87. package/dist/strand-first-sync-gate.js.map +1 -1
  88. package/dist/strand-formation-deadlines.d.ts +151 -0
  89. package/dist/strand-formation-deadlines.js +171 -0
  90. package/dist/strand-formation-deadlines.js.map +1 -0
  91. package/dist/strand-formation-manager.d.ts +63 -30
  92. package/dist/strand-formation-manager.js +67 -41
  93. package/dist/strand-formation-manager.js.map +1 -1
  94. package/dist/strand-formation-protocol.d.ts +45 -35
  95. package/dist/strand-formation-protocol.js +59 -122
  96. package/dist/strand-formation-protocol.js.map +1 -1
  97. package/dist/strand-instance-manager.d.ts +113 -6
  98. package/dist/strand-instance-manager.js +257 -41
  99. package/dist/strand-instance-manager.js.map +1 -1
  100. package/dist/strand-membership-writer.d.ts +6 -0
  101. package/dist/strand-membership-writer.js +11 -0
  102. package/dist/strand-membership-writer.js.map +1 -1
  103. package/dist/strand-peer-book-protocol.d.ts +13 -4
  104. package/dist/strand-peer-book-protocol.js +3 -7
  105. package/dist/strand-peer-book-protocol.js.map +1 -1
  106. package/dist/strand-peer-book.d.ts +1 -1
  107. package/dist/strand-peer-book.js +8 -1
  108. package/dist/strand-peer-book.js.map +1 -1
  109. package/dist/strand-peer-observer.js +1 -1
  110. package/dist/strand-revocation-enforcer.js +2 -1
  111. package/dist/strand-revocation-enforcer.js.map +1 -1
  112. package/dist/strand-solicitation.d.ts +36 -20
  113. package/dist/strand-solicitation.js +4 -4
  114. package/dist/strand-solicitation.js.map +1 -1
  115. package/dist/strand-wake-protocol.d.ts +80 -23
  116. package/dist/strand-wake-protocol.js +89 -64
  117. package/dist/strand-wake-protocol.js.map +1 -1
  118. package/dist/types.d.ts +128 -38
  119. package/dist/types.js +4 -3
  120. package/dist/types.js.map +1 -1
  121. package/package.json +7 -7
  122. package/src/cadre-node.ts +8367 -7776
  123. package/src/control-authorization.ts +2 -1
  124. package/src/control-cohort.ts +6 -0
  125. package/src/control-database.ts +122 -18
  126. package/src/control-formation-recorder.ts +354 -305
  127. package/src/control-read-retry.ts +14 -12
  128. package/src/control-schema.ts +67 -5
  129. package/src/control-stream.ts +25 -1
  130. package/src/control-write-retry.ts +13 -2
  131. package/src/delegate-admission.ts +23 -13
  132. package/src/diagnostics/connection-path.ts +0 -7
  133. package/src/formation-approval.ts +610 -604
  134. package/src/fs-atomic.ts +14 -4
  135. package/src/hibernation-manager.ts +638 -437
  136. package/src/index.ts +28 -10
  137. package/src/joined-strand-store.ts +247 -57
  138. package/src/key-store-file.ts +14 -5
  139. package/src/link-budget.ts +393 -74
  140. package/src/membership-connection-gater.ts +31 -45
  141. package/src/peer-dial.ts +81 -7
  142. package/src/peer-join-backfill.ts +8 -6
  143. package/src/push-fanout.ts +6 -0
  144. package/src/relay-reservation.ts +3 -1
  145. package/src/relay-server.ts +98 -0
  146. package/src/seed-bootstrap.ts +133 -91
  147. package/src/storage-scope.ts +44 -23
  148. package/src/strand-addr-protocol.ts +547 -458
  149. package/src/strand-database.ts +287 -242
  150. package/src/strand-first-sync-gate.ts +58 -19
  151. package/src/strand-formation-deadlines.ts +227 -0
  152. package/src/strand-formation-manager.ts +700 -647
  153. package/src/strand-formation-protocol.ts +103 -150
  154. package/src/strand-instance-manager.ts +287 -44
  155. package/src/strand-membership-writer.ts +12 -0
  156. package/src/strand-peer-book-protocol.ts +16 -13
  157. package/src/strand-peer-book.ts +8 -1
  158. package/src/strand-peer-observer.ts +1 -1
  159. package/src/strand-revocation-enforcer.ts +2 -1
  160. package/src/strand-solicitation.ts +519 -500
  161. package/src/strand-wake-protocol.ts +401 -355
  162. package/src/types.ts +130 -38
@@ -1,6 +1,6 @@
1
1
  import type { KeyStore } from './key-store.js';
2
2
  import type { StrandRow } from './types.js';
3
- /** One strand this node joined from ANOTHER party — nothing in this party's control DB names it. */
3
+ /** One strand this node joined from ANOTHER party and has not yet published party-wide. */
4
4
  export interface JoinedStrandRecord {
5
5
  /** The strand id (a valid scope key, see storage-scope.ts). */
6
6
  Id: string;
@@ -74,39 +74,104 @@ export declare class KeyStoreJoinedStrandStore implements JoinedStrandStore {
74
74
  private loaded;
75
75
  }
76
76
  /**
77
- * What the strand watcher sees of the joined-strand store: the control rows plus one row per
78
- * remembered join, which is how a join comes back as `strand:discovered` (or auto-launches)
79
- * after a restart with no second offer path. One instance per node session.
77
+ * The party-wide joined-strand table (`CadreControl.JoinedStrand`), as the node's control
78
+ * database exposes it. `CadreNode` builds it over `ControlDatabase` and the owner signing
79
+ * key; this module sees only the seam, so it stays free of the runtime.
80
+ */
81
+ export interface PartyJoinedStrandLedger {
82
+ /** Every party-wide join, as offerable rows (`FounderOwnerKey: null`). */
83
+ list(): Promise<StrandRow[]>;
84
+ /** Whether this party's control database names `strandId`, as its own strand or as a party-wide join. */
85
+ names(strandId: string): Promise<boolean>;
86
+ /** Whether this machine can sign {@link publish} and {@link remove}: it holds an owner key the party enrolls. */
87
+ canSign(): Promise<boolean>;
88
+ /** Owner-signed insert. Resolves when the row landed or a sibling's join already holds the id. */
89
+ publish(record: JoinedStrandRecord): Promise<void>;
90
+ /** Owner-signed delete + tombstone; false when there is no row. Throws when a row exists and this machine cannot sign. */
91
+ remove(strandId: string): Promise<boolean>;
92
+ }
93
+ /**
94
+ * One node session's joined strands: what the strand watcher sees of the two records, and
95
+ * the moves between them. Rebuilt at every start, which is what ends the per-session state
96
+ * below.
80
97
  *
81
- * Holds the two pieces of state a plain union would get wrong, both of which would otherwise
82
- * make the watcher detach running strands, since a joined row missing from a poll reads to it
83
- * as a removal:
84
- * - the last list the store answered, reused when a later list fails, so a read failure is
85
- * not "every join was forgotten";
86
- * - joins forgotten because this party was removed from the strand
87
- * ({@link forgetAfterThisSession}): gone from the store, so the next start does not
88
- * re-attach them, but still offered until this session ends, because `strand:revoked`
89
- * promises that nothing is torn down for the app.
98
+ * The watcher reads a row missing from a poll as a removal and detaches the strand, so this
99
+ * holds the state a plain union would get wrong:
100
+ * - the last list each record answered, reused when a later read fails, so a failed read
101
+ * is not "every join was forgotten";
102
+ * - joins this party was removed from ({@link forgetAfterThisSession}): offered until this
103
+ * session ends, because `strand:revoked` promises that nothing is torn down for the app,
104
+ * and queued for party-wide removal so the next start does not re-attach them.
90
105
  */
91
- export declare class JoinedStrandRows {
106
+ export declare class JoinedStrandSession {
92
107
  private readonly store;
93
- private lastListed;
108
+ private readonly ledger;
109
+ private lastUnpublished;
110
+ private lastPartyWide;
94
111
  private readonly keptForSession;
95
- constructor(store: JoinedStrandStore);
112
+ /** Strands whose party-wide row {@link syncWithParty} removes, queued by a self-revocation. */
113
+ private readonly pendingRemovals;
96
114
  /**
97
- * `control` plus a row for every remembered join. A control row wins an id collision: the
98
- * strand is this party's own now (its founding party enrolled this machine, say), the
99
- * control database remembers it, and the record is stale — so it is forgotten here.
115
+ * Tail of the moves that must not interleave ({@link serialized}): a publish that found no
116
+ * party-wide row, then a {@link leave} that removed nothing, then the publish's insert
117
+ * would leave the party holding a strand the app just left.
118
+ */
119
+ private exclusive;
120
+ constructor(store: JoinedStrandStore, ledger: PartyJoinedStrandLedger);
121
+ /**
122
+ * `control` plus every join, one row per id, in this precedence: the control rows (the
123
+ * party's own strands), then the party-wide joins, then this machine's unpublished joins
124
+ * and the joins kept for this session. A local record named by either of the first two in
125
+ * a read that succeeded this poll is stale — published, or the strand is the party's own
126
+ * now — so it is forgotten here; this also cleans up after a crash between a publish and
127
+ * its local forget. One named only by the last-good party-wide list is kept: that list may
128
+ * predate a leave the record re-joined after.
100
129
  */
101
130
  withControlRows(control: readonly StrandRow[]): Promise<StrandRow[]>;
102
- /** Forget a join for good: the app is leaving the strand. */
103
- forget(strandId: string): Promise<void>;
131
+ /** Record a join `formStrand` just made. A re-join also cancels a removal a revocation queued. */
132
+ remember(record: JoinedStrandRecord): Promise<void>;
133
+ /**
134
+ * Record `row`, joined by `addStrand`, unless this party's control database already names
135
+ * it (its own strand, or a join already published) or an identical record is already here
136
+ * (an app re-claiming a remembered join on every start). Keeps the first `joinedAt`. Like
137
+ * {@link remember}, cancels a queued removal.
138
+ */
139
+ rememberForeign(row: StrandRow): Promise<void>;
140
+ /**
141
+ * Leave a join for the whole party: remove the party-wide row, then this machine's record.
142
+ * Throws, keeping both, when a party-wide row exists and this machine cannot sign.
143
+ */
144
+ leave(strandId: string): Promise<void>;
104
145
  /**
105
- * Forget a join durably, but keep offering it until this session ends. For a strand this
106
- * party was removed from: it must not re-attach on every launch, and it must not be torn
107
- * down underneath the app either. A no-op for a strand with no record.
146
+ * For a strand this party was removed from: keep offering it until this session ends, and
147
+ * queue its party-wide row for removal by {@link syncWithParty}, so it does not re-attach
148
+ * on every start of every machine. A no-op for a strand with neither record (one of the
149
+ * party's own). The queue is in memory: if the process dies first, the next start
150
+ * relaunches the strand, the revoked-peer gate raises `strand:revoked` again, and this
151
+ * runs again.
108
152
  */
109
153
  forgetAfterThisSession(strandId: string): Promise<void>;
110
- private listed;
154
+ /**
155
+ * The owner machine's half, run by the node's connected reconcile pass: publish every
156
+ * unpublished join party-wide, then remove the party-wide rows queued by
157
+ * {@link forgetAfterThisSession}. Does nothing on a machine that cannot sign, whose joins
158
+ * stay machine-local. Per strand, a failure is logged and kept for the next pass; a
159
+ * failure to list the store or to check the signer throws.
160
+ */
161
+ syncWithParty(): Promise<void>;
162
+ private publish;
163
+ private removeQueued;
164
+ /** The party-wide joins; `fresh` is false when this read failed and the last list it answered stands in. */
165
+ private partyWide;
166
+ /**
167
+ * {@link PartyJoinedStrandLedger.names}, answering false when the control database cannot
168
+ * be read (a machine cut off from its party before it received the `JoinedStrand` block).
169
+ * Recording is the safe side: a local record the party turns out to name is forgotten by
170
+ * the next poll that reads it, while a join with no record is not offered after a restart.
171
+ */
172
+ private namedByParty;
173
+ /** Run `work` after every earlier serialized move settles; see {@link exclusive}. */
174
+ private serialized;
175
+ private unpublished;
111
176
  private forgetSuperseded;
112
177
  }
@@ -1,18 +1,25 @@
1
1
  /**
2
- * Node-local record of the strands this node joined from ANOTHER party.
2
+ * The strands this party joined from ANOTHER party, held in two records.
3
3
  *
4
4
  * A party's own strands come back after a restart through its control database: the
5
5
  * `Strand` table holds their rows, the strand watcher polls it, and each row no sApp
6
6
  * config claims is offered as `strand:discovered`. A strand joined through formation with
7
- * another party (`CadreNode.formStrand`) has no row there — the other party's control
8
- * database holds it — so nothing re-offered it after a restart, and every embedding app
9
- * kept its own list of joins, read secret included (gotchoices/sereus#18).
7
+ * another party (`CadreNode.formStrand`) has its `Strand` row in the OTHER party's control
8
+ * database, so it needs a record of its own (gotchoices/sereus#18):
10
9
  *
11
- * `CadreNode` records each such join here, hands the records to its strand watcher beside
12
- * the control rows ({@link JoinedStrandRows}), and forgets one on `forgetJoinedStrand` or
13
- * when this party is removed from the strand.
10
+ * - the PARTY-WIDE record, a `CadreControl.JoinedStrand` row ({@link PartyJoinedStrandLedger}).
11
+ * Once it exists it is the authority: every machine of the party offers it, a storage
12
+ * replica host launches it, and removing it is how the party leaves the strand;
13
+ * - the MACHINE-LOCAL record ({@link JoinedStrandStore}, below), a queue of joins this
14
+ * machine made that the party does not know about yet. A join is recorded here first,
15
+ * published by an owner machine's connected reconcile pass, and forgotten as soon as the
16
+ * party-wide row is visible, so a local record always means "joined here, not yet
17
+ * published". A machine that is not an owner never publishes; its joins stay here.
14
18
  *
15
- * Two implementations:
19
+ * {@link JoinedStrandSession} moves joins between the two and is what the strand watcher
20
+ * polls beside the control rows.
21
+ *
22
+ * Two store implementations:
16
23
  * - {@link MemoryJoinedStrandStore} — joins die with the process. The default only for a
17
24
  * node configured with no `keyStore`.
18
25
  * - {@link KeyStoreJoinedStrandStore} — one {@link KeyStore} slot per join. A record holds
@@ -178,82 +185,243 @@ function parseRecord(strandId, bytes) {
178
185
  return { Id: strandId, Type: Type, MemberPrivateKey: MemberPrivateKey, joinedAt: joinedAt };
179
186
  }
180
187
  /**
181
- * What the strand watcher sees of the joined-strand store: the control rows plus one row per
182
- * remembered join, which is how a join comes back as `strand:discovered` (or auto-launches)
183
- * after a restart with no second offer path. One instance per node session.
188
+ * One node session's joined strands: what the strand watcher sees of the two records, and
189
+ * the moves between them. Rebuilt at every start, which is what ends the per-session state
190
+ * below.
184
191
  *
185
- * Holds the two pieces of state a plain union would get wrong, both of which would otherwise
186
- * make the watcher detach running strands, since a joined row missing from a poll reads to it
187
- * as a removal:
188
- * - the last list the store answered, reused when a later list fails, so a read failure is
189
- * not "every join was forgotten";
190
- * - joins forgotten because this party was removed from the strand
191
- * ({@link forgetAfterThisSession}): gone from the store, so the next start does not
192
- * re-attach them, but still offered until this session ends, because `strand:revoked`
193
- * promises that nothing is torn down for the app.
192
+ * The watcher reads a row missing from a poll as a removal and detaches the strand, so this
193
+ * holds the state a plain union would get wrong:
194
+ * - the last list each record answered, reused when a later read fails, so a failed read
195
+ * is not "every join was forgotten";
196
+ * - joins this party was removed from ({@link forgetAfterThisSession}): offered until this
197
+ * session ends, because `strand:revoked` promises that nothing is torn down for the app,
198
+ * and queued for party-wide removal so the next start does not re-attach them.
194
199
  */
195
- export class JoinedStrandRows {
196
- constructor(store) {
200
+ export class JoinedStrandSession {
201
+ constructor(store, ledger) {
197
202
  this.store = store;
198
- this.lastListed = [];
203
+ this.ledger = ledger;
204
+ this.lastUnpublished = [];
205
+ this.lastPartyWide = [];
199
206
  this.keptForSession = new Map();
207
+ /** Strands whose party-wide row {@link syncWithParty} removes, queued by a self-revocation. */
208
+ this.pendingRemovals = new Set();
209
+ /**
210
+ * Tail of the moves that must not interleave ({@link serialized}): a publish that found no
211
+ * party-wide row, then a {@link leave} that removed nothing, then the publish's insert
212
+ * would leave the party holding a strand the app just left.
213
+ */
214
+ this.exclusive = Promise.resolve();
200
215
  }
201
216
  /**
202
- * `control` plus a row for every remembered join. A control row wins an id collision: the
203
- * strand is this party's own now (its founding party enrolled this machine, say), the
204
- * control database remembers it, and the record is stale — so it is forgotten here.
217
+ * `control` plus every join, one row per id, in this precedence: the control rows (the
218
+ * party's own strands), then the party-wide joins, then this machine's unpublished joins
219
+ * and the joins kept for this session. A local record named by either of the first two in
220
+ * a read that succeeded this poll is stale — published, or the strand is the party's own
221
+ * now — so it is forgotten here; this also cleans up after a crash between a publish and
222
+ * its local forget. One named only by the last-good party-wide list is kept: that list may
223
+ * predate a leave the record re-joined after.
205
224
  */
206
225
  async withControlRows(control) {
207
226
  const controlIds = new Set(control.map((row) => row.Id));
208
- const joined = new Map(this.keptForSession);
209
- for (const record of await this.listed()) {
210
- joined.set(record.Id, record);
227
+ const named = new Set(controlIds);
228
+ const offered = new Map(control.map((row) => [row.Id, row]));
229
+ const partyWide = await this.partyWide();
230
+ // NOTE: a party-wide join whose id the party's own `Strand` table also holds (the party
231
+ // founded AND joined it — contrived) is shadowed here, not deleted: a watcher poll must
232
+ // not make owner-signed writes. If the party later unpublishes its own row the join row
233
+ // resurfaces; if that is ever seen, remove the join row inside `unpublishStrand`.
234
+ for (const row of partyWide.rows) {
235
+ if (!offered.has(row.Id)) {
236
+ offered.set(row.Id, row);
237
+ }
238
+ if (partyWide.fresh) {
239
+ named.add(row.Id);
240
+ }
211
241
  }
212
- const rows = [...control];
213
- for (const record of joined.values()) {
214
- if (controlIds.has(record.Id)) {
242
+ for (const record of await this.unpublished()) {
243
+ if (named.has(record.Id)) {
215
244
  await this.forgetSuperseded(record.Id);
216
245
  }
217
- else {
218
- rows.push(joinedStrandRow(record));
246
+ else if (!offered.has(record.Id)) {
247
+ offered.set(record.Id, joinedStrandRow(record));
219
248
  }
220
249
  }
221
- return rows;
250
+ for (const [strandId, row] of this.keptForSession) {
251
+ if (controlIds.has(strandId)) {
252
+ this.keptForSession.delete(strandId);
253
+ }
254
+ else if (!offered.has(strandId)) {
255
+ offered.set(strandId, row);
256
+ }
257
+ }
258
+ return [...offered.values()];
222
259
  }
223
- /** Forget a join for good: the app is leaving the strand. */
224
- async forget(strandId) {
225
- this.keptForSession.delete(strandId);
226
- await this.store.forget(strandId);
260
+ /** Record a join `formStrand` just made. A re-join also cancels a removal a revocation queued. */
261
+ async remember(record) {
262
+ this.pendingRemovals.delete(record.Id);
263
+ await this.store.record(record);
227
264
  }
228
265
  /**
229
- * Forget a join durably, but keep offering it until this session ends. For a strand this
230
- * party was removed from: it must not re-attach on every launch, and it must not be torn
231
- * down underneath the app either. A no-op for a strand with no record.
266
+ * Record `row`, joined by `addStrand`, unless this party's control database already names
267
+ * it (its own strand, or a join already published) or an identical record is already here
268
+ * (an app re-claiming a remembered join on every start). Keeps the first `joinedAt`. Like
269
+ * {@link remember}, cancels a queued removal.
232
270
  */
233
- async forgetAfterThisSession(strandId) {
234
- const record = (await this.listed()).find((listed) => listed.Id === strandId);
235
- if (!record) {
271
+ async rememberForeign(row) {
272
+ this.pendingRemovals.delete(row.Id);
273
+ if (await this.namedByParty(row.Id)) {
236
274
  return;
237
275
  }
238
- // Kept BEFORE the store forgets, so no poll can list the store without it and union
239
- // without the kept copy.
240
- this.keptForSession.set(strandId, record);
241
- await this.store.forget(strandId);
276
+ const existing = (await this.store.list()).find((record) => record.Id === row.Id);
277
+ if (existing?.Type === row.Type && existing.MemberPrivateKey === row.MemberPrivateKey) {
278
+ return;
279
+ }
280
+ await this.store.record({
281
+ Id: row.Id,
282
+ Type: row.Type,
283
+ MemberPrivateKey: row.MemberPrivateKey,
284
+ joinedAt: existing?.joinedAt ?? Date.now()
285
+ });
286
+ }
287
+ /**
288
+ * Leave a join for the whole party: remove the party-wide row, then this machine's record.
289
+ * Throws, keeping both, when a party-wide row exists and this machine cannot sign.
290
+ */
291
+ leave(strandId) {
292
+ return this.serialized(async () => {
293
+ await this.ledger.remove(strandId);
294
+ this.pendingRemovals.delete(strandId);
295
+ this.keptForSession.delete(strandId);
296
+ this.lastPartyWide = this.lastPartyWide.filter((row) => row.Id !== strandId);
297
+ await this.store.forget(strandId);
298
+ });
299
+ }
300
+ /**
301
+ * For a strand this party was removed from: keep offering it until this session ends, and
302
+ * queue its party-wide row for removal by {@link syncWithParty}, so it does not re-attach
303
+ * on every start of every machine. A no-op for a strand with neither record (one of the
304
+ * party's own). The queue is in memory: if the process dies first, the next start
305
+ * relaunches the strand, the revoked-peer gate raises `strand:revoked` again, and this
306
+ * runs again.
307
+ */
308
+ forgetAfterThisSession(strandId) {
309
+ return this.serialized(async () => {
310
+ const local = (await this.unpublished()).find((record) => record.Id === strandId);
311
+ const row = local ? joinedStrandRow(local) : this.lastPartyWide.find((listed) => listed.Id === strandId);
312
+ if (!row) {
313
+ return;
314
+ }
315
+ // Kept BEFORE the store forgets, so no poll can union without it. Queued even for a
316
+ // local-only join, which a sibling may have published already.
317
+ this.keptForSession.set(strandId, row);
318
+ this.pendingRemovals.add(strandId);
319
+ if (local) {
320
+ await this.store.forget(strandId);
321
+ }
322
+ });
323
+ }
324
+ /**
325
+ * The owner machine's half, run by the node's connected reconcile pass: publish every
326
+ * unpublished join party-wide, then remove the party-wide rows queued by
327
+ * {@link forgetAfterThisSession}. Does nothing on a machine that cannot sign, whose joins
328
+ * stay machine-local. Per strand, a failure is logged and kept for the next pass; a
329
+ * failure to list the store or to check the signer throws.
330
+ */
331
+ syncWithParty() {
332
+ return this.serialized(async () => {
333
+ // Straight from the store, never the last-good list: a stale list could republish a
334
+ // join that was left since.
335
+ const unpublished = await this.store.list();
336
+ if (unpublished.length === 0 && this.pendingRemovals.size === 0) {
337
+ return;
338
+ }
339
+ if (!(await this.ledger.canSign())) {
340
+ return;
341
+ }
342
+ for (const record of unpublished) {
343
+ await this.publish(record);
344
+ }
345
+ for (const strandId of [...this.pendingRemovals]) {
346
+ await this.removeQueued(strandId);
347
+ }
348
+ });
349
+ }
350
+ // NOTE: a sibling that joined the same strand and has not yet published publishes it after
351
+ // a leave, bringing the strand back party-wide. Needs two devices joining one strand within
352
+ // a reconcile interval of the leave; if it is ever seen, check the strand's `Revocation`
353
+ // tombstone before publishing.
354
+ async publish(record) {
355
+ try {
356
+ if (!(await this.ledger.names(record.Id))) {
357
+ await this.ledger.publish(record);
358
+ // Into the last-good list too: its local record goes next, so a party-wide read that
359
+ // fails before one succeeds would otherwise drop the strand from the poll and hide it
360
+ // from a self-revocation.
361
+ this.lastPartyWide = [...this.lastPartyWide.filter((row) => row.Id !== record.Id), joinedStrandRow(record)];
362
+ log('joined strand %s published party-wide (party=%s)', record.Id, this.store.partyId);
363
+ }
364
+ await this.store.forget(record.Id);
365
+ }
366
+ catch (error) {
367
+ log('joined strand %s: publishing party-wide failed; kept for the next pass: %o', record.Id, error);
368
+ }
369
+ }
370
+ async removeQueued(strandId) {
371
+ try {
372
+ const removed = await this.ledger.remove(strandId);
373
+ this.pendingRemovals.delete(strandId);
374
+ log('joined strand %s: party-wide row %s after this party was removed from it', strandId, removed ? 'removed' : 'already absent');
375
+ }
376
+ catch (error) {
377
+ log('joined strand %s: removing the party-wide row failed; queued for the next pass: %o', strandId, error);
378
+ }
379
+ }
380
+ /** The party-wide joins; `fresh` is false when this read failed and the last list it answered stands in. */
381
+ async partyWide() {
382
+ try {
383
+ this.lastPartyWide = await this.ledger.list();
384
+ return { rows: this.lastPartyWide, fresh: true };
385
+ }
386
+ catch (error) {
387
+ log('party-wide joined-strand read failed; offering the last list it answered (%d join(s)): %o', this.lastPartyWide.length, error);
388
+ return { rows: this.lastPartyWide, fresh: false };
389
+ }
390
+ }
391
+ /**
392
+ * {@link PartyJoinedStrandLedger.names}, answering false when the control database cannot
393
+ * be read (a machine cut off from its party before it received the `JoinedStrand` block).
394
+ * Recording is the safe side: a local record the party turns out to name is forgotten by
395
+ * the next poll that reads it, while a join with no record is not offered after a restart.
396
+ */
397
+ async namedByParty(strandId) {
398
+ try {
399
+ return await this.ledger.names(strandId);
400
+ }
401
+ catch (error) {
402
+ log('joined strand %s: could not read whether the control database names it; recording it locally: %o', strandId, error);
403
+ return false;
404
+ }
405
+ }
406
+ /** Run `work` after every earlier serialized move settles; see {@link exclusive}. */
407
+ serialized(work) {
408
+ const result = this.exclusive.then(work);
409
+ this.exclusive = result.catch(() => undefined);
410
+ return result;
242
411
  }
243
- async listed() {
412
+ async unpublished() {
244
413
  try {
245
- this.lastListed = await this.store.list();
414
+ this.lastUnpublished = await this.store.list();
246
415
  }
247
416
  catch (error) {
248
- log('joined-strand store list failed; offering the last list it answered (%d join(s)): %o', this.lastListed.length, error);
417
+ log('joined-strand store list failed; offering the last list it answered (%d join(s)): %o', this.lastUnpublished.length, error);
249
418
  }
250
- return this.lastListed;
419
+ return this.lastUnpublished;
251
420
  }
252
421
  async forgetSuperseded(strandId) {
253
- this.keptForSession.delete(strandId);
254
422
  try {
255
423
  await this.store.forget(strandId);
256
- log('joined strand %s now has a control row — record forgotten', strandId);
424
+ log('joined strand %s is named by this party\'s control database — local record forgotten', strandId);
257
425
  }
258
426
  catch (error) {
259
427
  log('forgetting superseded joined strand %s failed; the next poll retries: %o', strandId, error);
@@ -1 +1 @@
1
- {"version":3,"file":"joined-strand-store.js","sourceRoot":"","sources":["../src/joined-strand-store.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAE,QAAQ,IAAI,kBAAkB,EAAE,UAAU,IAAI,oBAAoB,EAAE,MAAM,aAAa,CAAC;AAEjG,OAAO,EAAE,oBAAoB,EAAE,qBAAqB,EAAE,MAAM,oBAAoB,CAAC;AAGjF,MAAM,GAAG,GAAG,KAAK,CAAC,kCAAkC,CAAC,CAAC;AA2BtD;;;;GAIG;AACH,MAAM,UAAU,eAAe,CAAC,MAA0B;IACzD,OAAO,EAAE,EAAE,EAAE,MAAM,CAAC,EAAE,EAAE,IAAI,EAAE,MAAM,CAAC,IAAI,EAAE,gBAAgB,EAAE,MAAM,CAAC,gBAAgB,EAAE,eAAe,EAAE,IAAI,EAAE,CAAC;AAC/G,CAAC;AAED;;;;;GAKG;AACH,MAAM,OAAO,uBAAuB;IAInC,YAAqB,OAAe;QAAf,YAAO,GAAP,OAAO,CAAQ;QAHnB,YAAO,GAAG,IAAI,GAAG,EAA8B,CAAC;QACzD,WAAM,GAAG,KAAK,CAAC;IAEgB,CAAC;IAExC,KAAK,CAAC,IAAI;QACT,OAAO,CAAC,GAAG,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC;IACnC,CAAC;IAED,KAAK,CAAC,MAAM,CAAC,MAA0B;QACtC,IAAI,CAAC,QAAQ,EAAE,CAAC;QAChB,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,EAAE,EAAE,GAAG,MAAM,EAAE,CAAC,CAAC;IAC5C,CAAC;IAED,KAAK,CAAC,MAAM,CAAC,QAAgB;QAC5B,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;IAC/B,CAAC;IAEO,QAAQ;QACf,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC;YACjB,OAAO;QACR,CAAC;QACD,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC;QACnB,OAAO,CAAC,IAAI,CACX,6FAA6F;YAC7F,kGAAkG;YAClG,mGAAmG,CACnG,CAAC;IACH,CAAC;CACD;AAED,iGAAiG;AACjG,MAAM,WAAW,GAAG,sBAAsB,CAAC;AAE3C;;;;;;;;;;;;;GAaG;AACH,MAAM,OAAO,yBAAyB;IAOrC,YAA6B,QAAkB,EAAW,OAAe;QAA5C,aAAQ,GAAR,QAAQ,CAAU;QAAW,YAAO,GAAP,OAAO,CAAQ;QALzE,sDAAsD;QAC9C,YAAO,GAA2C,IAAI,CAAC;QAC/D,0FAA0F;QAClF,UAAK,GAAqB,OAAO,CAAC,OAAO,EAAE,CAAC;QAGnD,IAAI,CAAC,UAAU,GAAG,WAAW,GAAG,kBAAkB,CAAC,oBAAoB,CAAC,OAAO,EAAE,MAAM,CAAC,EAAE,WAAW,CAAC,GAAG,GAAG,CAAC;IAC9G,CAAC;IAED,IAAI;QACH,OAAO,IAAI,CAAC,OAAO,CAAC,KAAK,IAAI,EAAE,CAAC,CAAC,GAAG,CAAC,MAAM,IAAI,CAAC,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC;IACtE,CAAC;IAED,sGAAsG;IACtG,MAAM,CAAC,MAA0B;QAChC,oBAAoB,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;QAChC,MAAM,MAAM,GAAuB,EAAE,GAAG,MAAM,EAAE,CAAC;QACjD,OAAO,IAAI,CAAC,OAAO,CAAC,KAAK,IAAI,EAAE;YAC9B,MAAM,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,EAAE,CAAC,EAAE,oBAAoB,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC,CAAC,CAAC;YACtG,IAAI,CAAC,OAAO,EAAE,GAAG,CAAC,MAAM,CAAC,EAAE,EAAE,MAAM,CAAC,CAAC;YACrC,GAAG,CAAC,yDAAyD,EAAE,IAAI,CAAC,OAAO,EAAE,MAAM,CAAC,EAAE,EAAE,MAAM,CAAC,IAAI,CAAC,CAAC;QACtG,CAAC,CAAC,CAAC;IACJ,CAAC;IAED,MAAM,CAAC,QAAgB;QACtB,OAAO,IAAI,CAAC,OAAO,CAAC,KAAK,IAAI,EAAE;YAC9B,MAAM,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC;YAClD,IAAI,CAAC,OAAO,EAAE,MAAM,CAAC,QAAQ,CAAC,CAAC;YAC/B,GAAG,CAAC,+CAA+C,EAAE,IAAI,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC;QAC9E,CAAC,CAAC,CAAC;IACJ,CAAC;IAEO,MAAM,CAAC,QAAgB;QAC9B,OAAO,IAAI,CAAC,UAAU,GAAG,QAAQ,CAAC;IACnC,CAAC;IAEO,OAAO,CAAI,EAAoB;QACtC,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QACnC,6FAA6F;QAC7F,IAAI,CAAC,KAAK,GAAG,MAAM,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,SAAS,CAAC,CAAC;QAC3C,OAAO,MAAM,CAAC;IACf,CAAC;IAED,yFAAyF;IACzF,yFAAyF;IACzF,0FAA0F;IAC1F,uFAAuF;IACvF,sBAAsB;IACd,KAAK,CAAC,MAAM;QACnB,IAAI,IAAI,CAAC,OAAO,EAAE,CAAC;YAClB,OAAO,IAAI,CAAC,OAAO,CAAC;QACrB,CAAC;QACD,MAAM,OAAO,GAAG,IAAI,GAAG,EAA8B,CAAC;QACtD,KAAK,MAAM,IAAI,IAAI,MAAM,IAAI,CAAC,QAAQ,CAAC,IAAI,EAAE,EAAE,CAAC;YAC/C,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,UAAU,CAAC,EAAE,CAAC;gBACvC,SAAS;YACV,CAAC;YACD,MAAM,QAAQ,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC;YACpD,MAAM,KAAK,GAAG,MAAM,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;YAC5C,IAAI,CAAC,KAAK,EAAE,CAAC;gBACZ,SAAS;YACV,CAAC;YACD,MAAM,MAAM,GAAG,WAAW,CAAC,QAAQ,EAAE,KAAK,CAAC,CAAC;YAC5C,IAAI,MAAM,EAAE,CAAC;gBACZ,OAAO,CAAC,GAAG,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;YAC/B,CAAC;QACF,CAAC;QACD,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC;QACvB,GAAG,CAAC,4CAA4C,EAAE,IAAI,CAAC,OAAO,EAAE,OAAO,CAAC,IAAI,CAAC,CAAC;QAC9E,OAAO,OAAO,CAAC;IAChB,CAAC;CACD;AAED,wFAAwF;AACxF,SAAS,WAAW,CAAC,QAAgB,EAAE,KAAiB;IACvD,IAAI,MAAe,CAAC;IACpB,IAAI,CAAC;QACJ,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,kBAAkB,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC,CAAC;IACxD,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QAChB,GAAG,CAAC,mDAAmD,EAAE,QAAQ,EAAE,KAAK,CAAC,CAAC;QAC1E,OAAO,SAAS,CAAC;IAClB,CAAC;IACD,MAAM,EAAE,EAAE,EAAE,IAAI,EAAE,gBAAgB,EAAE,QAAQ,EAAE,GAAG,CAAC,OAAO,MAAM,KAAK,QAAQ,IAAI,MAAM,KAAK,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAA4B,CAAC;IAC1I,MAAM,KAAK,GAAG,EAAE,KAAK,QAAQ;WACzB,qBAAqB,CAAC,QAAQ,CAAC;WAC/B,CAAC,IAAI,KAAK,GAAG,IAAI,IAAI,KAAK,GAAG,CAAC;WAC9B,CAAC,gBAAgB,KAAK,IAAI,IAAI,OAAO,gBAAgB,KAAK,QAAQ,CAAC;WACnE,OAAO,QAAQ,KAAK,QAAQ,CAAC;IACjC,IAAI,CAAC,KAAK,EAAE,CAAC;QACZ,GAAG,CAAC,4EAA4E,EAAE,QAAQ,CAAC,CAAC;QAC5F,OAAO,SAAS,CAAC;IAClB,CAAC;IACD,OAAO,EAAE,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,IAAiB,EAAE,gBAAgB,EAAE,gBAAiC,EAAE,QAAQ,EAAE,QAAkB,EAAE,CAAC;AACrI,CAAC;AAED;;;;;;;;;;;;;;GAcG;AACH,MAAM,OAAO,gBAAgB;IAI5B,YAA6B,KAAwB;QAAxB,UAAK,GAAL,KAAK,CAAmB;QAH7C,eAAU,GAAyB,EAAE,CAAC;QAC7B,mBAAc,GAAG,IAAI,GAAG,EAA8B,CAAC;IAEhB,CAAC;IAEzD;;;;OAIG;IACH,KAAK,CAAC,eAAe,CAAC,OAA6B;QAClD,MAAM,UAAU,GAAG,IAAI,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC;QACzD,MAAM,MAAM,GAAG,IAAI,GAAG,CAA6B,IAAI,CAAC,cAAc,CAAC,CAAC;QACxE,KAAK,MAAM,MAAM,IAAI,MAAM,IAAI,CAAC,MAAM,EAAE,EAAE,CAAC;YAC1C,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,EAAE,MAAM,CAAC,CAAC;QAC/B,CAAC;QACD,MAAM,IAAI,GAAG,CAAC,GAAG,OAAO,CAAC,CAAC;QAC1B,KAAK,MAAM,MAAM,IAAI,MAAM,CAAC,MAAM,EAAE,EAAE,CAAC;YACtC,IAAI,UAAU,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,EAAE,CAAC;gBAC/B,MAAM,IAAI,CAAC,gBAAgB,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;YACxC,CAAC;iBAAM,CAAC;gBACP,IAAI,CAAC,IAAI,CAAC,eAAe,CAAC,MAAM,CAAC,CAAC,CAAC;YACpC,CAAC;QACF,CAAC;QACD,OAAO,IAAI,CAAC;IACb,CAAC;IAED,6DAA6D;IAC7D,KAAK,CAAC,MAAM,CAAC,QAAgB;QAC5B,IAAI,CAAC,cAAc,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;QACrC,MAAM,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;IACnC,CAAC;IAED;;;;OAIG;IACH,KAAK,CAAC,sBAAsB,CAAC,QAAgB;QAC5C,MAAM,MAAM,GAAG,CAAC,MAAM,IAAI,CAAC,MAAM,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,EAAE,KAAK,QAAQ,CAAC,CAAC;QAC9E,IAAI,CAAC,MAAM,EAAE,CAAC;YACb,OAAO;QACR,CAAC;QACD,oFAAoF;QACpF,yBAAyB;QACzB,IAAI,CAAC,cAAc,CAAC,GAAG,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;QAC1C,MAAM,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;IACnC,CAAC;IAEO,KAAK,CAAC,MAAM;QACnB,IAAI,CAAC;YACJ,IAAI,CAAC,UAAU,GAAG,MAAM,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC;QAC3C,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YAChB,GAAG,CAAC,sFAAsF,EACzF,IAAI,CAAC,UAAU,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC;QACjC,CAAC;QACD,OAAO,IAAI,CAAC,UAAU,CAAC;IACxB,CAAC;IAEO,KAAK,CAAC,gBAAgB,CAAC,QAAgB;QAC9C,IAAI,CAAC,cAAc,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;QACrC,IAAI,CAAC;YACJ,MAAM,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;YAClC,GAAG,CAAC,2DAA2D,EAAE,QAAQ,CAAC,CAAC;QAC5E,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YAChB,GAAG,CAAC,0EAA0E,EAAE,QAAQ,EAAE,KAAK,CAAC,CAAC;QAClG,CAAC;IACF,CAAC;CACD"}
1
+ {"version":3,"file":"joined-strand-store.js","sourceRoot":"","sources":["../src/joined-strand-store.ts"],"names":[],"mappings":"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"}
@@ -39,20 +39,29 @@ function encodeKeyId(keyId) {
39
39
  }
40
40
  /**
41
41
  * Reverse {@link encodeKeyId}: strip the slot suffix and percent-decode. Returns
42
- * `undefined` for a `.key` filename this store did not write (a foreign file
43
- * with an invalid percent-sequence), so {@link FileKeyStore.list} can skip it
44
- * rather than letting one undecodable entry throw and break enumeration of every
45
- * real slot.
42
+ * `undefined` for a `.key` filename this store did not write, so
43
+ * {@link FileKeyStore.list} can skip it rather than letting one undecodable
44
+ * entry throw and break enumeration of every real slot. That includes a name
45
+ * that decodes but is not the one {@link encodeKeyId} produces for the result
46
+ * (e.g. a slot written before uppercase letters were escaped):
47
+ * {@link FileKeyStore.get} looks only at the canonical name, so listing it
48
+ * would name a key id that reads back as absent.
46
49
  */
47
50
  function decodeKeyId(fileName) {
48
51
  const encoded = fileName.slice(0, -SLOT_SUFFIX.length);
52
+ let keyId;
49
53
  try {
50
- return decodeURIComponent(encoded);
54
+ keyId = decodeURIComponent(encoded);
51
55
  }
52
56
  catch (error) {
53
57
  log('FileKeyStore: skipping undecodable slot filename %s: %o', fileName, error);
54
58
  return undefined;
55
59
  }
60
+ if (encodeKeyId(keyId) !== encoded) {
61
+ log('FileKeyStore: skipping non-canonical slot filename %s', fileName);
62
+ return undefined;
63
+ }
64
+ return keyId;
56
65
  }
57
66
  /**
58
67
  * File-backed {@link KeyStore}. Each slot is `<dir>/<encoded keyId>.key`
@@ -1 +1 @@
1
- {"version":3,"file":"key-store-file.js","sourceRoot":"","sources":["../src/key-store-file.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"key-store-file.js","sourceRoot":"","sources":["../src/key-store-file.ts"],"names":[],"mappings":"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"}