@abraca/dabra 1.6.0 → 1.8.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/dist/abracadabra-provider.cjs +355 -8
- package/dist/abracadabra-provider.cjs.map +1 -1
- package/dist/abracadabra-provider.esm.js +354 -9
- package/dist/abracadabra-provider.esm.js.map +1 -1
- package/dist/index.d.ts +208 -4
- package/package.json +1 -1
- package/src/AbracadabraProvider.ts +10 -0
- package/src/AbracadabraWS.ts +10 -2
- package/src/ChatClient.ts +234 -0
- package/src/IdentityDoc.ts +11 -0
- package/src/NotificationsClient.ts +185 -0
- package/src/index.ts +16 -0
- package/src/types.ts +86 -0
- package/src/webrtc/DevicePairingChannel.ts +18 -6
|
@@ -2840,6 +2840,7 @@ var AbracadabraProvider = class AbracadabraProvider extends AbracadabraBaseProvi
|
|
|
2840
2840
|
this.childAccessTimes = /* @__PURE__ */ new Map();
|
|
2841
2841
|
this.pinnedChildren = /* @__PURE__ */ new Set();
|
|
2842
2842
|
this.boundHandleYSubdocsChange = this.handleYSubdocsChange.bind(this);
|
|
2843
|
+
this.hasCachedContent = false;
|
|
2843
2844
|
this._client = client;
|
|
2844
2845
|
this.abracadabraConfig = configuration;
|
|
2845
2846
|
this.subdocLoading = configuration.subdocLoading ?? "lazy";
|
|
@@ -2877,8 +2878,14 @@ var AbracadabraProvider = class AbracadabraProvider extends AbracadabraBaseProvi
|
|
|
2877
2878
|
async _initFromOfflineStore() {
|
|
2878
2879
|
if (!this.offlineStore) return;
|
|
2879
2880
|
const [snapshot, pending] = await Promise.all([this.offlineStore.getDocSnapshot().catch(() => null), this.offlineStore.getPendingUpdates().catch(() => [])]);
|
|
2880
|
-
if (snapshot)
|
|
2881
|
-
|
|
2881
|
+
if (snapshot) {
|
|
2882
|
+
yjs.applyUpdate(this.document, snapshot, this.offlineStore);
|
|
2883
|
+
this.hasCachedContent = true;
|
|
2884
|
+
}
|
|
2885
|
+
for (const update of pending) {
|
|
2886
|
+
yjs.applyUpdate(this.document, update, this.offlineStore);
|
|
2887
|
+
this.hasCachedContent = true;
|
|
2888
|
+
}
|
|
2882
2889
|
}
|
|
2883
2890
|
authenticatedHandler(scope) {
|
|
2884
2891
|
super.authenticatedHandler(scope);
|
|
@@ -13191,8 +13198,12 @@ var DevicePairingChannel = class DevicePairingChannel extends EventEmitter {
|
|
|
13191
13198
|
/**
|
|
13192
13199
|
* Approve the pending pairing request. Calls `client.addKey()` to
|
|
13193
13200
|
* register Device B's public key, then notifies Device B.
|
|
13201
|
+
*
|
|
13202
|
+
* @param client Authenticated REST client.
|
|
13203
|
+
* @param masterPublicKey Approver's account-level Ed25519 public key (base64url).
|
|
13204
|
+
* Sent to Device B so it can adopt the master's identity doc.
|
|
13194
13205
|
*/
|
|
13195
|
-
async approve(client) {
|
|
13206
|
+
async approve(client, masterPublicKey) {
|
|
13196
13207
|
if (this.role !== "approver") return {
|
|
13197
13208
|
success: false,
|
|
13198
13209
|
error: "Only the approver can approve"
|
|
@@ -13212,7 +13223,10 @@ var DevicePairingChannel = class DevicePairingChannel extends EventEmitter {
|
|
|
13212
13223
|
deviceName: req.deviceName,
|
|
13213
13224
|
x25519Key: req.x25519Key
|
|
13214
13225
|
});
|
|
13215
|
-
this.sendMessage({
|
|
13226
|
+
this.sendMessage({
|
|
13227
|
+
type: "pair-approved",
|
|
13228
|
+
masterPublicKey
|
|
13229
|
+
});
|
|
13216
13230
|
this._pendingRequest = null;
|
|
13217
13231
|
this.emit("pairingComplete", { success: true });
|
|
13218
13232
|
return { success: true };
|
|
@@ -13235,8 +13249,12 @@ var DevicePairingChannel = class DevicePairingChannel extends EventEmitter {
|
|
|
13235
13249
|
* Approve via server-side device invite. Creates a single-use invite code
|
|
13236
13250
|
* and sends it to Device B over the E2EE channel. Device B redeems it
|
|
13237
13251
|
* independently via HTTP — Device A can go offline after this.
|
|
13252
|
+
*
|
|
13253
|
+
* @param client Authenticated REST client.
|
|
13254
|
+
* @param masterPublicKey Approver's account-level Ed25519 public key (base64url).
|
|
13255
|
+
* Sent to Device B so it can adopt the master's identity doc.
|
|
13238
13256
|
*/
|
|
13239
|
-
async approveWithInvite(client) {
|
|
13257
|
+
async approveWithInvite(client, masterPublicKey) {
|
|
13240
13258
|
if (this.role !== "approver") return {
|
|
13241
13259
|
success: false,
|
|
13242
13260
|
error: "Only the approver can approve"
|
|
@@ -13253,7 +13271,8 @@ var DevicePairingChannel = class DevicePairingChannel extends EventEmitter {
|
|
|
13253
13271
|
const { code } = await client.createDeviceInvite();
|
|
13254
13272
|
this.sendMessage({
|
|
13255
13273
|
type: "pair-invite-code",
|
|
13256
|
-
code
|
|
13274
|
+
code,
|
|
13275
|
+
masterPublicKey
|
|
13257
13276
|
});
|
|
13258
13277
|
this._pendingRequest = null;
|
|
13259
13278
|
this.emit("pairingComplete", { success: true });
|
|
@@ -13424,7 +13443,7 @@ var DevicePairingChannel = class DevicePairingChannel extends EventEmitter {
|
|
|
13424
13443
|
break;
|
|
13425
13444
|
case "pair-approved":
|
|
13426
13445
|
if (this.role !== "requester") return;
|
|
13427
|
-
this.emit("approved");
|
|
13446
|
+
this.emit("approved", { masterPublicKey: msg.masterPublicKey });
|
|
13428
13447
|
this.emit("pairingComplete", { success: true });
|
|
13429
13448
|
break;
|
|
13430
13449
|
case "pair-rejected":
|
|
@@ -13437,7 +13456,7 @@ var DevicePairingChannel = class DevicePairingChannel extends EventEmitter {
|
|
|
13437
13456
|
break;
|
|
13438
13457
|
case "pair-invite-code":
|
|
13439
13458
|
if (this.role !== "requester") return;
|
|
13440
|
-
this.emit("inviteCode", msg.code);
|
|
13459
|
+
this.emit("inviteCode", msg.code, msg.masterPublicKey);
|
|
13441
13460
|
break;
|
|
13442
13461
|
}
|
|
13443
13462
|
}
|
|
@@ -13964,6 +13983,19 @@ var IdentityDocProvider = class extends EventEmitter {
|
|
|
13964
13983
|
return this.profileMap.size === 0 && this.serversMap.size === 0;
|
|
13965
13984
|
}
|
|
13966
13985
|
/**
|
|
13986
|
+
* Enable WebRTC P2P sync at runtime.
|
|
13987
|
+
* Use this for claimed/passkey users where E2EE identity derivation
|
|
13988
|
+
* was deferred to avoid biometric prompts on page load.
|
|
13989
|
+
*/
|
|
13990
|
+
enableWebRTC(webrtcConfig) {
|
|
13991
|
+
if (this._destroyed || this.webrtc) return;
|
|
13992
|
+
this.config = {
|
|
13993
|
+
...this.config,
|
|
13994
|
+
webrtc: webrtcConfig
|
|
13995
|
+
};
|
|
13996
|
+
this._connectWebRTC();
|
|
13997
|
+
}
|
|
13998
|
+
/**
|
|
13967
13999
|
* Update the sync server URL at runtime (e.g. when user changes their
|
|
13968
14000
|
* designated sync server in settings).
|
|
13969
14001
|
*/
|
|
@@ -14150,6 +14182,319 @@ var DeviceRegistrationService = class {
|
|
|
14150
14182
|
}
|
|
14151
14183
|
};
|
|
14152
14184
|
|
|
14185
|
+
//#endregion
|
|
14186
|
+
//#region packages/provider/src/ChatClient.ts
|
|
14187
|
+
const DEFAULT_TIMEOUT_MS$1 = 1e4;
|
|
14188
|
+
/**
|
|
14189
|
+
* Typed client for the Abracadabra chat feature.
|
|
14190
|
+
*
|
|
14191
|
+
* Wraps a connected provider (or base provider) and translates JSON envelopes
|
|
14192
|
+
* on the stateless channel into typed method calls and events.
|
|
14193
|
+
*
|
|
14194
|
+
* Events emitted:
|
|
14195
|
+
* - `message` → ChatMessage (new message broadcast)
|
|
14196
|
+
* - `typing` → ChatTypingEvent (typing indicator broadcast)
|
|
14197
|
+
* - `readReceipt` → ChatReadReceipt (mark_read broadcast)
|
|
14198
|
+
*/
|
|
14199
|
+
var ChatClient = class extends EventEmitter {
|
|
14200
|
+
constructor(provider, options) {
|
|
14201
|
+
super();
|
|
14202
|
+
this.pending = /* @__PURE__ */ new Map();
|
|
14203
|
+
this.provider = provider;
|
|
14204
|
+
this.responseTimeoutMs = options?.responseTimeoutMs ?? DEFAULT_TIMEOUT_MS$1;
|
|
14205
|
+
this.boundOnStateless = (data) => this.handleStateless(data.payload);
|
|
14206
|
+
this.provider.on("stateless", this.boundOnStateless);
|
|
14207
|
+
}
|
|
14208
|
+
/** Stop listening for chat messages. Does not disconnect the underlying provider. */
|
|
14209
|
+
destroy() {
|
|
14210
|
+
this.provider.off("stateless", this.boundOnStateless);
|
|
14211
|
+
for (const queue of this.pending.values()) for (const p of queue) {
|
|
14212
|
+
clearTimeout(p.timer);
|
|
14213
|
+
p.reject(/* @__PURE__ */ new Error("ChatClient destroyed"));
|
|
14214
|
+
}
|
|
14215
|
+
this.pending.clear();
|
|
14216
|
+
this.removeAllListeners();
|
|
14217
|
+
}
|
|
14218
|
+
/** Send a chat message on a channel. Fire-and-forget (the server broadcasts). */
|
|
14219
|
+
sendMessage(input) {
|
|
14220
|
+
this.provider.sendStateless(JSON.stringify({
|
|
14221
|
+
type: "chat:send",
|
|
14222
|
+
channel: input.channel,
|
|
14223
|
+
content: input.content,
|
|
14224
|
+
...input.sender_name !== void 0 ? { sender_name: input.sender_name } : {}
|
|
14225
|
+
}));
|
|
14226
|
+
}
|
|
14227
|
+
/** Fetch historical messages for a channel. Resolves with the server response. */
|
|
14228
|
+
getHistory(input) {
|
|
14229
|
+
const promise = this.enqueue("chat:history");
|
|
14230
|
+
this.provider.sendStateless(JSON.stringify({
|
|
14231
|
+
type: "chat:history",
|
|
14232
|
+
channel: input.channel,
|
|
14233
|
+
...input.before !== void 0 ? { before: input.before } : {},
|
|
14234
|
+
...input.limit !== void 0 ? { limit: input.limit } : {}
|
|
14235
|
+
}));
|
|
14236
|
+
return promise;
|
|
14237
|
+
}
|
|
14238
|
+
/** Broadcast a typing indicator on a channel. */
|
|
14239
|
+
sendTyping(channel) {
|
|
14240
|
+
this.provider.sendStateless(JSON.stringify({
|
|
14241
|
+
type: "chat:typing",
|
|
14242
|
+
channel
|
|
14243
|
+
}));
|
|
14244
|
+
}
|
|
14245
|
+
/** List the current user's channels (ordered by last activity). */
|
|
14246
|
+
listChannels() {
|
|
14247
|
+
const promise = this.enqueue("chat:channels");
|
|
14248
|
+
this.provider.sendStateless(JSON.stringify({ type: "chat:channels" }));
|
|
14249
|
+
return promise;
|
|
14250
|
+
}
|
|
14251
|
+
/** Mark a channel read up to `timestamp` (unix ms). */
|
|
14252
|
+
markRead(channel, timestamp) {
|
|
14253
|
+
this.provider.sendStateless(JSON.stringify({
|
|
14254
|
+
type: "chat:mark_read",
|
|
14255
|
+
channel,
|
|
14256
|
+
timestamp
|
|
14257
|
+
}));
|
|
14258
|
+
}
|
|
14259
|
+
/** Fetch per-user read cursors for a channel. */
|
|
14260
|
+
getReadCursors(channel) {
|
|
14261
|
+
const promise = this.enqueue("chat:read_cursors");
|
|
14262
|
+
this.provider.sendStateless(JSON.stringify({
|
|
14263
|
+
type: "chat:read_cursors",
|
|
14264
|
+
channel
|
|
14265
|
+
}));
|
|
14266
|
+
return promise;
|
|
14267
|
+
}
|
|
14268
|
+
onMessage(fn) {
|
|
14269
|
+
return this.on("message", fn);
|
|
14270
|
+
}
|
|
14271
|
+
onTyping(fn) {
|
|
14272
|
+
return this.on("typing", fn);
|
|
14273
|
+
}
|
|
14274
|
+
onReadReceipt(fn) {
|
|
14275
|
+
return this.on("readReceipt", fn);
|
|
14276
|
+
}
|
|
14277
|
+
enqueue(type) {
|
|
14278
|
+
return new Promise((resolve, reject) => {
|
|
14279
|
+
const entry = {
|
|
14280
|
+
resolve,
|
|
14281
|
+
reject,
|
|
14282
|
+
timer: setTimeout(() => {
|
|
14283
|
+
this.removePending(type, entry);
|
|
14284
|
+
reject(/* @__PURE__ */ new Error(`ChatClient: timeout waiting for ${type} response`));
|
|
14285
|
+
}, this.responseTimeoutMs)
|
|
14286
|
+
};
|
|
14287
|
+
const queue = this.pending.get(type) ?? [];
|
|
14288
|
+
queue.push(entry);
|
|
14289
|
+
this.pending.set(type, queue);
|
|
14290
|
+
});
|
|
14291
|
+
}
|
|
14292
|
+
removePending(type, entry) {
|
|
14293
|
+
const queue = this.pending.get(type);
|
|
14294
|
+
if (!queue) return;
|
|
14295
|
+
const idx = queue.indexOf(entry);
|
|
14296
|
+
if (idx >= 0) queue.splice(idx, 1);
|
|
14297
|
+
if (queue.length === 0) this.pending.delete(type);
|
|
14298
|
+
}
|
|
14299
|
+
resolveNext(type, value) {
|
|
14300
|
+
const queue = this.pending.get(type);
|
|
14301
|
+
if (!queue || queue.length === 0) return false;
|
|
14302
|
+
const next = queue.shift();
|
|
14303
|
+
if (queue.length === 0) this.pending.delete(type);
|
|
14304
|
+
clearTimeout(next.timer);
|
|
14305
|
+
next.resolve(value);
|
|
14306
|
+
return true;
|
|
14307
|
+
}
|
|
14308
|
+
handleStateless(payload) {
|
|
14309
|
+
let parsed;
|
|
14310
|
+
try {
|
|
14311
|
+
parsed = JSON.parse(payload);
|
|
14312
|
+
} catch {
|
|
14313
|
+
return;
|
|
14314
|
+
}
|
|
14315
|
+
const type = parsed?.type;
|
|
14316
|
+
if (typeof type !== "string" || !type.startsWith("chat:")) return;
|
|
14317
|
+
switch (type) {
|
|
14318
|
+
case "chat:message": {
|
|
14319
|
+
const { type: _t, ...rest } = parsed;
|
|
14320
|
+
this.emit("message", rest);
|
|
14321
|
+
break;
|
|
14322
|
+
}
|
|
14323
|
+
case "chat:history":
|
|
14324
|
+
this.resolveNext("chat:history", {
|
|
14325
|
+
channel: parsed.channel,
|
|
14326
|
+
messages: parsed.messages ?? []
|
|
14327
|
+
});
|
|
14328
|
+
break;
|
|
14329
|
+
case "chat:channels":
|
|
14330
|
+
this.resolveNext("chat:channels", { channels: parsed.channels ?? [] });
|
|
14331
|
+
break;
|
|
14332
|
+
case "chat:typing":
|
|
14333
|
+
this.emit("typing", {
|
|
14334
|
+
channel: parsed.channel,
|
|
14335
|
+
sender_id: parsed.sender_id,
|
|
14336
|
+
sender_name: parsed.sender_name ?? null
|
|
14337
|
+
});
|
|
14338
|
+
break;
|
|
14339
|
+
case "chat:read_receipt":
|
|
14340
|
+
this.emit("readReceipt", {
|
|
14341
|
+
channel: parsed.channel,
|
|
14342
|
+
user_id: parsed.user_id,
|
|
14343
|
+
last_read_at: parsed.last_read_at
|
|
14344
|
+
});
|
|
14345
|
+
break;
|
|
14346
|
+
case "chat:read_cursors":
|
|
14347
|
+
this.resolveNext("chat:read_cursors", {
|
|
14348
|
+
channel: parsed.channel,
|
|
14349
|
+
cursors: parsed.cursors ?? []
|
|
14350
|
+
});
|
|
14351
|
+
break;
|
|
14352
|
+
default: break;
|
|
14353
|
+
}
|
|
14354
|
+
}
|
|
14355
|
+
};
|
|
14356
|
+
|
|
14357
|
+
//#endregion
|
|
14358
|
+
//#region packages/provider/src/NotificationsClient.ts
|
|
14359
|
+
const DEFAULT_TIMEOUT_MS = 1e4;
|
|
14360
|
+
/**
|
|
14361
|
+
* Typed client for the Abracadabra notifications feature.
|
|
14362
|
+
*
|
|
14363
|
+
* Emits:
|
|
14364
|
+
* - `new` → NotificationRecord (incoming notify:new broadcast)
|
|
14365
|
+
* - `readUpdate` → NotificationReadUpdate (broadcast after mark_read / mark_all_read)
|
|
14366
|
+
*/
|
|
14367
|
+
var NotificationsClient = class extends EventEmitter {
|
|
14368
|
+
constructor(provider, options) {
|
|
14369
|
+
super();
|
|
14370
|
+
this.pending = /* @__PURE__ */ new Map();
|
|
14371
|
+
this.provider = provider;
|
|
14372
|
+
this.responseTimeoutMs = options?.responseTimeoutMs ?? DEFAULT_TIMEOUT_MS;
|
|
14373
|
+
this.boundOnStateless = (data) => this.handleStateless(data.payload);
|
|
14374
|
+
this.provider.on("stateless", this.boundOnStateless);
|
|
14375
|
+
}
|
|
14376
|
+
destroy() {
|
|
14377
|
+
this.provider.off("stateless", this.boundOnStateless);
|
|
14378
|
+
for (const queue of this.pending.values()) for (const p of queue) {
|
|
14379
|
+
clearTimeout(p.timer);
|
|
14380
|
+
p.reject(/* @__PURE__ */ new Error("NotificationsClient destroyed"));
|
|
14381
|
+
}
|
|
14382
|
+
this.pending.clear();
|
|
14383
|
+
this.removeAllListeners();
|
|
14384
|
+
}
|
|
14385
|
+
/**
|
|
14386
|
+
* Create a notification targeting a specific recipient. Requires elevated role
|
|
14387
|
+
* (service or admin); a `server:error` event with code `forbidden` is emitted
|
|
14388
|
+
* by the underlying provider if the caller lacks permission.
|
|
14389
|
+
*/
|
|
14390
|
+
create(input) {
|
|
14391
|
+
this.provider.sendStateless(JSON.stringify({
|
|
14392
|
+
type: "notify:create",
|
|
14393
|
+
recipient_id: input.recipient_id,
|
|
14394
|
+
...input.notification_type !== void 0 ? { notification_type: input.notification_type } : {},
|
|
14395
|
+
title: input.title,
|
|
14396
|
+
...input.body !== void 0 ? { body: input.body } : {},
|
|
14397
|
+
...input.icon !== void 0 ? { icon: input.icon } : {},
|
|
14398
|
+
...input.link !== void 0 ? { link: input.link } : {},
|
|
14399
|
+
...input.source_id !== void 0 ? { source_id: input.source_id } : {}
|
|
14400
|
+
}));
|
|
14401
|
+
}
|
|
14402
|
+
/** Fetch notification history for the current user. */
|
|
14403
|
+
fetch(input = {}) {
|
|
14404
|
+
const promise = this.enqueue("notify:history");
|
|
14405
|
+
this.provider.sendStateless(JSON.stringify({
|
|
14406
|
+
type: "notify:fetch",
|
|
14407
|
+
...input.before !== void 0 ? { before: input.before } : {},
|
|
14408
|
+
...input.limit !== void 0 ? { limit: input.limit } : {},
|
|
14409
|
+
...input.unread_only !== void 0 ? { unread_only: input.unread_only } : {}
|
|
14410
|
+
}));
|
|
14411
|
+
return promise;
|
|
14412
|
+
}
|
|
14413
|
+
/** Mark a single notification, or a batch, as read. */
|
|
14414
|
+
markRead(target) {
|
|
14415
|
+
const body = { type: "notify:mark_read" };
|
|
14416
|
+
if ("id" in target) body.id = target.id;
|
|
14417
|
+
else body.ids = target.ids;
|
|
14418
|
+
this.provider.sendStateless(JSON.stringify(body));
|
|
14419
|
+
}
|
|
14420
|
+
/** Mark every notification for the current user as read. */
|
|
14421
|
+
markAllRead() {
|
|
14422
|
+
this.provider.sendStateless(JSON.stringify({ type: "notify:mark_all_read" }));
|
|
14423
|
+
}
|
|
14424
|
+
/** Mark all notifications generated by the given source (e.g. a chat channel) as read. */
|
|
14425
|
+
markReadBySource(sourceId) {
|
|
14426
|
+
this.provider.sendStateless(JSON.stringify({
|
|
14427
|
+
type: "notify:mark_read_by_source",
|
|
14428
|
+
source_id: sourceId
|
|
14429
|
+
}));
|
|
14430
|
+
}
|
|
14431
|
+
onNew(fn) {
|
|
14432
|
+
return this.on("new", fn);
|
|
14433
|
+
}
|
|
14434
|
+
onReadUpdate(fn) {
|
|
14435
|
+
return this.on("readUpdate", fn);
|
|
14436
|
+
}
|
|
14437
|
+
enqueue(type) {
|
|
14438
|
+
return new Promise((resolve, reject) => {
|
|
14439
|
+
const entry = {
|
|
14440
|
+
resolve,
|
|
14441
|
+
reject,
|
|
14442
|
+
timer: setTimeout(() => {
|
|
14443
|
+
this.removePending(type, entry);
|
|
14444
|
+
reject(/* @__PURE__ */ new Error(`NotificationsClient: timeout waiting for ${type} response`));
|
|
14445
|
+
}, this.responseTimeoutMs)
|
|
14446
|
+
};
|
|
14447
|
+
const queue = this.pending.get(type) ?? [];
|
|
14448
|
+
queue.push(entry);
|
|
14449
|
+
this.pending.set(type, queue);
|
|
14450
|
+
});
|
|
14451
|
+
}
|
|
14452
|
+
removePending(type, entry) {
|
|
14453
|
+
const queue = this.pending.get(type);
|
|
14454
|
+
if (!queue) return;
|
|
14455
|
+
const idx = queue.indexOf(entry);
|
|
14456
|
+
if (idx >= 0) queue.splice(idx, 1);
|
|
14457
|
+
if (queue.length === 0) this.pending.delete(type);
|
|
14458
|
+
}
|
|
14459
|
+
resolveNext(type, value) {
|
|
14460
|
+
const queue = this.pending.get(type);
|
|
14461
|
+
if (!queue || queue.length === 0) return false;
|
|
14462
|
+
const next = queue.shift();
|
|
14463
|
+
if (queue.length === 0) this.pending.delete(type);
|
|
14464
|
+
clearTimeout(next.timer);
|
|
14465
|
+
next.resolve(value);
|
|
14466
|
+
return true;
|
|
14467
|
+
}
|
|
14468
|
+
handleStateless(payload) {
|
|
14469
|
+
let parsed;
|
|
14470
|
+
try {
|
|
14471
|
+
parsed = JSON.parse(payload);
|
|
14472
|
+
} catch {
|
|
14473
|
+
return;
|
|
14474
|
+
}
|
|
14475
|
+
const type = parsed?.type;
|
|
14476
|
+
if (typeof type !== "string" || !type.startsWith("notify:")) return;
|
|
14477
|
+
switch (type) {
|
|
14478
|
+
case "notify:new": {
|
|
14479
|
+
const { type: _t, ...rest } = parsed;
|
|
14480
|
+
this.emit("new", rest);
|
|
14481
|
+
break;
|
|
14482
|
+
}
|
|
14483
|
+
case "notify:history":
|
|
14484
|
+
this.resolveNext("notify:history", { notifications: parsed.notifications ?? [] });
|
|
14485
|
+
break;
|
|
14486
|
+
case "notify:read_update": {
|
|
14487
|
+
const update = { recipient_id: parsed.recipient_id };
|
|
14488
|
+
if (parsed.ids !== void 0) update.ids = parsed.ids;
|
|
14489
|
+
if (parsed.all !== void 0) update.all = parsed.all;
|
|
14490
|
+
this.emit("readUpdate", update);
|
|
14491
|
+
break;
|
|
14492
|
+
}
|
|
14493
|
+
default: break;
|
|
14494
|
+
}
|
|
14495
|
+
}
|
|
14496
|
+
};
|
|
14497
|
+
|
|
14153
14498
|
//#endregion
|
|
14154
14499
|
exports.AbracadabraBaseProvider = AbracadabraBaseProvider;
|
|
14155
14500
|
exports.AbracadabraClient = AbracadabraClient;
|
|
@@ -14162,6 +14507,7 @@ exports.BackgroundSyncManager = BackgroundSyncManager;
|
|
|
14162
14507
|
exports.BackgroundSyncPersistence = BackgroundSyncPersistence;
|
|
14163
14508
|
exports.BroadcastChannelSync = BroadcastChannelSync;
|
|
14164
14509
|
exports.CHANNEL_NAMES = CHANNEL_NAMES;
|
|
14510
|
+
exports.ChatClient = ChatClient;
|
|
14165
14511
|
exports.ConnectionTimeout = ConnectionTimeout;
|
|
14166
14512
|
exports.CryptoIdentityKeystore = CryptoIdentityKeystore;
|
|
14167
14513
|
exports.DEFAULT_FILE_CHUNK_SIZE = DEFAULT_FILE_CHUNK_SIZE;
|
|
@@ -14187,6 +14533,7 @@ exports.KEY_EXCHANGE_CHANNEL = KEY_EXCHANGE_CHANNEL;
|
|
|
14187
14533
|
exports.ManualSignaling = ManualSignaling;
|
|
14188
14534
|
exports.MessageTooBig = MessageTooBig;
|
|
14189
14535
|
exports.MessageType = MessageType;
|
|
14536
|
+
exports.NotificationsClient = NotificationsClient;
|
|
14190
14537
|
exports.OfflineStore = OfflineStore;
|
|
14191
14538
|
exports.PeerConnection = PeerConnection;
|
|
14192
14539
|
exports.ResetConnection = ResetConnection;
|