@cero-base/core 1.8.1 → 1.9.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.
- package/package.json +1 -1
- package/src/pairing/index.js +67 -3
- package/types/pairing/index.d.ts +31 -1
package/package.json
CHANGED
package/src/pairing/index.js
CHANGED
|
@@ -69,7 +69,8 @@ export class Pairing extends ReadyResource {
|
|
|
69
69
|
host = true,
|
|
70
70
|
inviteEncoding = null,
|
|
71
71
|
joinerEncoding = null,
|
|
72
|
-
onerror = safetyCatch
|
|
72
|
+
onerror = safetyCatch,
|
|
73
|
+
onconsume = null
|
|
73
74
|
} = {}) {
|
|
74
75
|
super()
|
|
75
76
|
if (!network) throw CeroError.REQUIRED('network')
|
|
@@ -82,6 +83,9 @@ export class Pairing extends ReadyResource {
|
|
|
82
83
|
this.inviteEncoding = inviteEncoding
|
|
83
84
|
this.joinerEncoding = joinerEncoding
|
|
84
85
|
this._onerror = onerror
|
|
86
|
+
// Fired with an invite's hex id when this instance stops serving it
|
|
87
|
+
// (single-use settled, or expired) — lets the owner drop its persisted row.
|
|
88
|
+
this.onconsume = onconsume
|
|
85
89
|
|
|
86
90
|
this._blind = null
|
|
87
91
|
this._member = null
|
|
@@ -168,12 +172,68 @@ export class Pairing extends ReadyResource {
|
|
|
168
172
|
seed: blind.seed,
|
|
169
173
|
publicKey: blind.publicKey,
|
|
170
174
|
invite,
|
|
171
|
-
reuse
|
|
175
|
+
reuse,
|
|
176
|
+
// minted here and possibly not yet persisted/replicated — syncRows must
|
|
177
|
+
// never drop it for being absent from the store
|
|
178
|
+
local: true
|
|
172
179
|
})
|
|
173
180
|
|
|
174
181
|
return invite.toString()
|
|
175
182
|
}
|
|
176
183
|
|
|
184
|
+
/**
|
|
185
|
+
* Look up the in-memory record for a minted invite by its string form.
|
|
186
|
+
*
|
|
187
|
+
* @param {string} inviteStr
|
|
188
|
+
* @returns {{ id: Uint8Array, seed: Uint8Array, publicKey: Uint8Array, invite: import('./invite.js').Invite, reuse: boolean } | null}
|
|
189
|
+
*/
|
|
190
|
+
recordOf(inviteStr) {
|
|
191
|
+
for (const record of this._invites.values()) {
|
|
192
|
+
if (record.invite.toString() === inviteStr) return record
|
|
193
|
+
}
|
|
194
|
+
return null
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
/**
|
|
198
|
+
* Reconcile the served-invite set with persisted rows (the room's `invites`
|
|
199
|
+
* collection). Adds unknown rows so ANY member replica can serve them across
|
|
200
|
+
* restarts; drops replicated records whose row disappeared (revoked or
|
|
201
|
+
* consumed elsewhere). Locally-minted records not yet visible as rows are
|
|
202
|
+
* kept.
|
|
203
|
+
*
|
|
204
|
+
* @param {Array<{ id: string, invite: Uint8Array, publicKey: Uint8Array, seed: Uint8Array, reuse?: boolean }>} rows
|
|
205
|
+
*/
|
|
206
|
+
syncRows(rows) {
|
|
207
|
+
const seen = new Set()
|
|
208
|
+
for (const row of rows) {
|
|
209
|
+
if (!row?.id || !row.invite || !row.publicKey || !row.seed) continue
|
|
210
|
+
seen.add(row.id)
|
|
211
|
+
const existing = this._invites.get(row.id)
|
|
212
|
+
if (existing) {
|
|
213
|
+
existing.local = false
|
|
214
|
+
continue
|
|
215
|
+
}
|
|
216
|
+
let invite
|
|
217
|
+
try {
|
|
218
|
+
invite = Invite.parse(b4a.toString(row.invite))
|
|
219
|
+
} catch {
|
|
220
|
+
continue
|
|
221
|
+
}
|
|
222
|
+
if (invite.expired) continue
|
|
223
|
+
this._invites.set(row.id, {
|
|
224
|
+
id: b4a.from(row.id, 'hex'),
|
|
225
|
+
seed: row.seed,
|
|
226
|
+
publicKey: row.publicKey,
|
|
227
|
+
invite,
|
|
228
|
+
reuse: !!row.reuse,
|
|
229
|
+
local: false
|
|
230
|
+
})
|
|
231
|
+
}
|
|
232
|
+
for (const [id, record] of this._invites) {
|
|
233
|
+
if (!seen.has(id) && !record.local) this._invites.delete(id)
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
|
|
177
237
|
/**
|
|
178
238
|
* Forget a previously-minted invite. New candidates carrying it will be
|
|
179
239
|
* dropped silently.
|
|
@@ -273,6 +333,7 @@ export class Pairing extends ReadyResource {
|
|
|
273
333
|
if (!record) return
|
|
274
334
|
if (record.invite.expired) {
|
|
275
335
|
this._invites.delete(id)
|
|
336
|
+
this.onconsume?.(id)
|
|
276
337
|
return
|
|
277
338
|
}
|
|
278
339
|
|
|
@@ -292,7 +353,10 @@ export class Pairing extends ReadyResource {
|
|
|
292
353
|
seed: record.seed,
|
|
293
354
|
userData,
|
|
294
355
|
onsettle: () => {
|
|
295
|
-
if (!record.reuse)
|
|
356
|
+
if (!record.reuse) {
|
|
357
|
+
this._invites.delete(id)
|
|
358
|
+
this.onconsume?.(id)
|
|
359
|
+
}
|
|
296
360
|
}
|
|
297
361
|
})
|
|
298
362
|
|
package/types/pairing/index.d.ts
CHANGED
|
@@ -57,7 +57,7 @@ export class Pairing extends ReadyResource {
|
|
|
57
57
|
*/
|
|
58
58
|
static isInvite(str: unknown): boolean;
|
|
59
59
|
/** @param {PairingOpts} [opts] */
|
|
60
|
-
constructor({ network, identity, topic, host, inviteEncoding, joinerEncoding, onerror }?: PairingOpts);
|
|
60
|
+
constructor({ network, identity, topic, host, inviteEncoding, joinerEncoding, onerror, onconsume }?: PairingOpts);
|
|
61
61
|
network: import("../index.js").Network;
|
|
62
62
|
identity: import("../index.js").Identity;
|
|
63
63
|
topic: Uint8Array<ArrayBufferLike>;
|
|
@@ -65,6 +65,7 @@ export class Pairing extends ReadyResource {
|
|
|
65
65
|
inviteEncoding: any;
|
|
66
66
|
joinerEncoding: any;
|
|
67
67
|
_onerror: (err: Error) => void;
|
|
68
|
+
onconsume: any;
|
|
68
69
|
_blind: any;
|
|
69
70
|
_member: any;
|
|
70
71
|
_invites: Map<any, any>;
|
|
@@ -76,6 +77,35 @@ export class Pairing extends ReadyResource {
|
|
|
76
77
|
* @returns {Promise<string>}
|
|
77
78
|
*/
|
|
78
79
|
createInvite({ role, expiresIn, data, reuse }?: CreateInviteOpts): Promise<string>;
|
|
80
|
+
/**
|
|
81
|
+
* Look up the in-memory record for a minted invite by its string form.
|
|
82
|
+
*
|
|
83
|
+
* @param {string} inviteStr
|
|
84
|
+
* @returns {{ id: Uint8Array, seed: Uint8Array, publicKey: Uint8Array, invite: import('./invite.js').Invite, reuse: boolean } | null}
|
|
85
|
+
*/
|
|
86
|
+
recordOf(inviteStr: string): {
|
|
87
|
+
id: Uint8Array;
|
|
88
|
+
seed: Uint8Array;
|
|
89
|
+
publicKey: Uint8Array;
|
|
90
|
+
invite: import("./invite.js").Invite;
|
|
91
|
+
reuse: boolean;
|
|
92
|
+
} | null;
|
|
93
|
+
/**
|
|
94
|
+
* Reconcile the served-invite set with persisted rows (the room's `invites`
|
|
95
|
+
* collection). Adds unknown rows so ANY member replica can serve them across
|
|
96
|
+
* restarts; drops replicated records whose row disappeared (revoked or
|
|
97
|
+
* consumed elsewhere). Locally-minted records not yet visible as rows are
|
|
98
|
+
* kept.
|
|
99
|
+
*
|
|
100
|
+
* @param {Array<{ id: string, invite: Uint8Array, publicKey: Uint8Array, seed: Uint8Array, reuse?: boolean }>} rows
|
|
101
|
+
*/
|
|
102
|
+
syncRows(rows: Array<{
|
|
103
|
+
id: string;
|
|
104
|
+
invite: Uint8Array;
|
|
105
|
+
publicKey: Uint8Array;
|
|
106
|
+
seed: Uint8Array;
|
|
107
|
+
reuse?: boolean;
|
|
108
|
+
}>): void;
|
|
79
109
|
/**
|
|
80
110
|
* Forget a previously-minted invite. New candidates carrying it will be
|
|
81
111
|
* dropped silently.
|