@ours.network/messenger-server 1.0.31-nightly.18 → 1.0.31-nightly.19

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/README.md CHANGED
@@ -435,3 +435,5 @@ server contact, and well-formed workspace/host/nonce identifiers. An optional
435
435
  three-field replacement challenge is forwarded unchanged. The account service
436
436
  owns retirement authorization and cleanup; this route only sends the signed
437
437
  command and acknowledges submission.
438
+
439
+ Conversation notifications use `/fleet/chats/contacts/:contactId`, escaping the ID once and preserving the matching message anchor. Contact retirement matches canonical contact identity independent of filters and anchors. Deploy the app, notification service, and producers together: old query-based conversation links are intentionally unsupported. Previously frozen delivery URLs replay unchanged for idempotency, and unsupported persisted cleanup URLs remain pending without being sent or blocking canonical cleanup. Contact lifecycle authorization and inventory checks still apply.
@@ -38,7 +38,7 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
38
38
  var define_MESSENGER_BUILD_INFO_default;
39
39
  var init_define_MESSENGER_BUILD_INFO = __esm({
40
40
  "<define:__MESSENGER_BUILD_INFO__>"() {
41
- define_MESSENGER_BUILD_INFO_default = { name: "@ours.network/messenger-server", version: "1.0.31-nightly.18", sha: "634d1f59d24384e10618c737984067617739550e", dirty: true };
41
+ define_MESSENGER_BUILD_INFO_default = { name: "@ours.network/messenger-server", version: "1.0.31-nightly.19", sha: "7a5580f5b499aa98d37440492a1611dcb7fc5efb", dirty: true };
42
42
  }
43
43
  });
44
44
 
@@ -10,7 +10,7 @@ import {
10
10
  publicEngineError,
11
11
  publicInternalError,
12
12
  reportFailure
13
- } from "./chunk-5YTZQ5NK.js";
13
+ } from "./chunk-SM3QJOAM.js";
14
14
 
15
15
  // node_modules/bn.js/lib/bn.js
16
16
  var require_bn = __commonJS({
@@ -11212,10 +11212,22 @@ var NotificationOutbox = class {
11212
11212
  });
11213
11213
  }
11214
11214
  async drainOnce() {
11215
- for (const entry of [...this.entries].slice(0, 32)) {
11215
+ let attempts = 0;
11216
+ for (const entry of [...this.entries]) {
11217
+ if (attempts >= 32) break;
11216
11218
  try {
11217
11219
  if (!this.entries.some((current) => current.id === entry.id)) continue;
11218
- const value = entry.operation === "delete-target" ? this.shouldRetire && !await this.shouldRetire(entry.value.url) ? void 0 : entry.value : entry.payload ?? await this.project(entry.value, entry.id);
11220
+ if (entry.operation === "delete-target" && this.shouldRetire) {
11221
+ const retire = await this.shouldRetire(entry.value.url);
11222
+ if (retire === void 0) continue;
11223
+ if (!retire) {
11224
+ attempts++;
11225
+ this.persist(this.entries.filter((current) => current.id !== entry.id));
11226
+ continue;
11227
+ }
11228
+ }
11229
+ attempts++;
11230
+ const value = entry.operation === "delete-target" ? entry.value : entry.payload ?? await this.project(entry.value, entry.id);
11219
11231
  if (!this.entries.some((current) => current.id === entry.id)) continue;
11220
11232
  if (value === void 0) {
11221
11233
  this.persist(this.entries.filter((current) => current.id !== entry.id));
@@ -11666,6 +11678,19 @@ var PushDeliveryQueue = class {
11666
11678
  };
11667
11679
 
11668
11680
  // src/notification-producer.ts
11681
+ function contactTargetId(path2) {
11682
+ try {
11683
+ if (typeof path2 !== "string" || /[\\\x00-\x20]|%(?:2f|5c|00|0[ad])/i.test(path2)) return null;
11684
+ const match2 = /^\/fleet\/chats\/contacts\/([^/?#]+)(?:[?#]|$)/.exec(path2);
11685
+ if (!match2) return null;
11686
+ const url = new URL(path2, "https://ours.invalid");
11687
+ if (["source", "chat", "task", "detail"].some((key) => url.searchParams.has(key))) return null;
11688
+ const id = decodeURIComponent(match2[1]);
11689
+ return id && id !== "." && id !== ".." && !/[\x00-\x1f\x7f]/.test(id) ? id : null;
11690
+ } catch {
11691
+ return null;
11692
+ }
11693
+ }
11669
11694
  var MessengerNotificationProducer = class {
11670
11695
  constructor(stateDir, config, identityCid, client, warn) {
11671
11696
  this.identityCid = identityCid;
@@ -11688,9 +11713,13 @@ var MessengerNotificationProducer = class {
11688
11713
  eventId,
11689
11714
  title: event.title.slice(0, 160),
11690
11715
  body: event.body.slice(0, 512) || "New message",
11691
- url: `/fleet/chats?source=messenger&chat=${encodeURIComponent(record.sender_id)}&detail=1#chat-message-${encodeURIComponent(record.wire_id)}`
11716
+ url: `/fleet/chats/contacts/${encodeURIComponent(record.sender_id)}#chat-message-${encodeURIComponent(record.wire_id)}`
11692
11717
  };
11693
- }, warn, async (url) => await knownContact(new URL(url, "https://ours.invalid").searchParams.get("chat")) !== true);
11718
+ }, warn, async (url) => {
11719
+ const cid = contactTargetId(url);
11720
+ if (!cid) return void 0;
11721
+ return await knownContact(cid) !== true;
11722
+ });
11694
11723
  }
11695
11724
  outbox;
11696
11725
  admit(record) {
@@ -11704,17 +11733,12 @@ var MessengerNotificationProducer = class {
11704
11733
  return { status: admitted ? "queued" : "saturated" };
11705
11734
  }
11706
11735
  retireContact(cid) {
11707
- const url = `/fleet/chats?source=messenger&chat=${encodeURIComponent(cid)}`;
11736
+ const url = `/fleet/chats/contacts/${encodeURIComponent(cid)}`;
11708
11737
  this.outbox.retireTarget(url, (value, payload) => {
11709
11738
  const record = value;
11710
11739
  if (typeof record?.sender_id === "string" && record.sender_id.toLowerCase() === cid.toLowerCase()) return true;
11711
11740
  if (!payload) return false;
11712
- try {
11713
- const target = new URL(payload.url, "https://ours.invalid");
11714
- return target.pathname === "/fleet/chats" && target.searchParams.get("source") === "messenger" && target.searchParams.get("chat")?.toLowerCase() === cid.toLowerCase();
11715
- } catch {
11716
- return false;
11717
- }
11741
+ return contactTargetId(payload.url)?.toLowerCase() === cid.toLowerCase();
11718
11742
  });
11719
11743
  void this.outbox.drain();
11720
11744
  }
package/dist/cli.js CHANGED
@@ -7,7 +7,7 @@ import {
7
7
  normalizeBasePath,
8
8
  operatorError,
9
9
  reportFailure
10
- } from "./chunks/chunk-5YTZQ5NK.js";
10
+ } from "./chunks/chunk-SM3QJOAM.js";
11
11
 
12
12
  // src/cli.ts
13
13
  init_define_MESSENGER_BUILD_INFO();
@@ -131,7 +131,7 @@ async function main() {
131
131
  }
132
132
  if (process.argv.length !== 3) throw new ConfigurationError("serve does not accept command-line options");
133
133
  const cfg = loadConfig();
134
- const { start } = await import("./chunks/server-MKIXAIM7.js");
134
+ const { start } = await import("./chunks/server-DJOMSROR.js");
135
135
  const handle = await start(cfg, BUILD_INFO);
136
136
  let closing = false;
137
137
  const shutdown = (signal) => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ours.network/messenger-server",
3
- "version": "1.0.31-nightly.18",
3
+ "version": "1.0.31-nightly.19",
4
4
  "description": "Self-hosted Messenger REST/SSE backend for one identity on a shared Ours daemon.",
5
5
  "type": "module",
6
6
  "license": "FSL-1.1-Apache-2.0",