@codemem/server 0.22.2 → 0.22.4

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.
@@ -1 +1 @@
1
- {"version":3,"file":"sync.d.ts","sourceRoot":"","sources":["../../src/routes/sync.ts"],"names":[],"mappings":"AAAA;;GAEG;AAMH,OAAO,KAAK,EAAE,WAAW,EAAiB,MAAM,eAAe,CAAC;AA2BhE,OAAO,EAAgB,IAAI,EAAE,MAAM,MAAM,CAAC;AAE1C,OAAO,KAAK,EAAE,0BAA0B,EAAE,MAAM,0BAA0B,CAAC;AAE3E,KAAK,YAAY,GAAG,MAAM,WAAW,CAAC;AACtC,KAAK,iBAAiB,GAAG;IACxB,KAAK,EACF,UAAU,GACV,SAAS,GACT,UAAU,GACV,OAAO,GACP,UAAU,GACV,iBAAiB,GACjB,iBAAiB,GACjB,IAAI,CAAC;IACR,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CACvB,CAAC;AAEF,UAAU,wBAAwB;IACjC,cAAc,CAAC,EAAE;QAChB,OAAO,EAAE,0BAA0B,CAAC;QACpC,SAAS,EAAE,MAAM,CAAC;QAClB,aAAa,EAAE,MAAM,CAAC;QACtB,wBAAwB,EAAE,MAAM,CAAC;QACjC,4BAA4B,EAAE,MAAM,CAAC;KACrC,CAAC;CACF;AA8pBD;;;;;;GAMG;AACH,wBAAgB,kBAAkB,CAAC,QAAQ,EAAE,YAAY,EAAE,IAAI,GAAE,wBAA6B,8EA+O7F;AAED;;;;;;GAMG;AACH,wBAAgB,UAAU,CACzB,QAAQ,EAAE,YAAY,EACtB,oBAAoB,CAAC,EAAE,MAAM,iBAAiB,GAAG,IAAI,8EAyzBrD"}
1
+ {"version":3,"file":"sync.d.ts","sourceRoot":"","sources":["../../src/routes/sync.ts"],"names":[],"mappings":"AAAA;;GAEG;AAMH,OAAO,KAAK,EAAE,WAAW,EAAiB,MAAM,eAAe,CAAC;AA2BhE,OAAO,EAAgB,IAAI,EAAE,MAAM,MAAM,CAAC;AAE1C,OAAO,KAAK,EAAE,0BAA0B,EAAE,MAAM,0BAA0B,CAAC;AAE3E,KAAK,YAAY,GAAG,MAAM,WAAW,CAAC;AACtC,KAAK,iBAAiB,GAAG;IACxB,KAAK,EACF,UAAU,GACV,SAAS,GACT,UAAU,GACV,OAAO,GACP,UAAU,GACV,iBAAiB,GACjB,iBAAiB,GACjB,IAAI,CAAC;IACR,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CACvB,CAAC;AAEF,UAAU,wBAAwB;IACjC,cAAc,CAAC,EAAE;QAChB,OAAO,EAAE,0BAA0B,CAAC;QACpC,SAAS,EAAE,MAAM,CAAC;QAClB,aAAa,EAAE,MAAM,CAAC;QACtB,wBAAwB,EAAE,MAAM,CAAC;QACjC,4BAA4B,EAAE,MAAM,CAAC;KACrC,CAAC;CACF;AA8pBD;;;;;;GAMG;AACH,wBAAgB,kBAAkB,CAAC,QAAQ,EAAE,YAAY,EAAE,IAAI,GAAE,wBAA6B,8EAgP7F;AAED;;;;;;GAMG;AACH,wBAAgB,UAAU,CACzB,QAAQ,EAAE,YAAY,EACtB,oBAAoB,CAAC,EAAE,MAAM,iBAAiB,GAAG,IAAI,8EAs2BrD"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@codemem/server",
3
- "version": "0.22.2",
3
+ "version": "0.22.4",
4
4
  "type": "module",
5
5
  "types": "./dist/index.d.ts",
6
6
  "exports": {
@@ -19,7 +19,7 @@
19
19
  "drizzle-orm": "^0.45.1",
20
20
  "hono": "^4.7.10",
21
21
  "limiter": "^3.0.0",
22
- "@codemem/core": "^0.22.2"
22
+ "@codemem/core": "^0.22.4"
23
23
  },
24
24
  "devDependencies": {
25
25
  "@types/better-sqlite3": "^7.6.13",
@@ -41,7 +41,7 @@
41
41
  },
42
42
  "scripts": {
43
43
  "clean": "rm -rf dist tsconfig.tsbuildinfo",
44
- "build": "pnpm exec vite build --ssr src/index.ts --outDir dist && pnpm exec tsc --build --force",
44
+ "build": "pnpm exec vite build --ssr src/index.ts --outDir dist && pnpm exec tsc --build",
45
45
  "typecheck": "pnpm exec tsc --noEmit"
46
46
  }
47
47
  }
package/static/app.js CHANGED
@@ -481,6 +481,16 @@
481
481
  if (!resp.ok) throw new Error(payloadError(payload) || text || "request failed");
482
482
  return payload;
483
483
  }
484
+ async function deactivateActor(actorId) {
485
+ const resp = await fetch("/api/sync/actors/deactivate", {
486
+ method: "POST",
487
+ headers: { "Content-Type": "application/json" },
488
+ body: JSON.stringify({ actor_id: actorId })
489
+ });
490
+ const { text, payload } = await readJsonPayload(resp);
491
+ if (!resp.ok) throw new Error(payloadError(payload) || text || "request failed");
492
+ return payload;
493
+ }
484
494
  async function claimLegacyDeviceIdentity(originDeviceId) {
485
495
  const resp = await fetch("/api/sync/legacy-devices/claim", {
486
496
  method: "POST",
@@ -4052,15 +4062,19 @@
4052
4062
  class: "diag-line",
4053
4063
  children: [/* @__PURE__ */ u("div", {
4054
4064
  class: "left",
4055
- children: [/* @__PURE__ */ u("div", { children: attempt.status }), /* @__PURE__ */ u("div", {
4065
+ children: [/* @__PURE__ */ u("div", { children: [
4066
+ attempt.peerLabel,
4067
+ " — ",
4068
+ attempt.status
4069
+ ] }), attempt.detail ? /* @__PURE__ */ u("div", {
4056
4070
  class: "small",
4057
- children: attempt.address
4058
- })]
4071
+ children: attempt.detail
4072
+ }) : null]
4059
4073
  }), /* @__PURE__ */ u("div", {
4060
4074
  class: "right",
4061
4075
  children: attempt.startedAt
4062
4076
  })]
4063
- }, `${attempt.startedAt}-${attempt.address}-${index}`)) });
4077
+ }, `${attempt.startedAt}-${attempt.peerLabel}-${index}`)) });
4064
4078
  }
4065
4079
  function PairingText({ text }) {
4066
4080
  return /* @__PURE__ */ u(k$2, { children: text });
@@ -4532,9 +4546,18 @@
4532
4546
  }
4533
4547
  renderAttemptsList(syncAttempts, attempts.slice(0, 5).map((attempt) => {
4534
4548
  const time = attempt.started_at || attempt.started_at_utc || "";
4549
+ const peerId = String(attempt.peer_device_id || "").trim();
4550
+ const matchedPeer = Array.isArray(state.lastSyncPeers) ? state.lastSyncPeers.find((p) => String(p?.peer_device_id || "") === peerId) : null;
4551
+ const peerLabel = String(matchedPeer?.name || "").trim() || (peerId ? peerId.slice(0, 8) : "unknown");
4552
+ const isError = attempt.status === "error";
4553
+ const detailParts = [];
4554
+ if (isError && attempt.error) detailParts.push(String(attempt.error));
4555
+ if (!isError && (attempt.ops_in || attempt.ops_out)) detailParts.push(`${attempt.ops_in ?? 0} in · ${attempt.ops_out ?? 0} out`);
4556
+ if (!isSyncRedactionEnabled() && attempt.address) detailParts.push(attempt.address);
4535
4557
  return {
4536
4558
  status: attempt.status || "unknown",
4537
- address: isSyncRedactionEnabled() ? redactAddress(attempt.address) : attempt.address || "n/a",
4559
+ peerLabel,
4560
+ detail: detailParts.join(" · "),
4538
4561
  startedAt: time ? formatTimestamp(time) : ""
4539
4562
  };
4540
4563
  }));
@@ -10337,18 +10360,29 @@ For more information, see https://radix-ui.com/primitives/docs/components/${titl
10337
10360
  displayName: String(request.display_name || request.device_id || "Pending device"),
10338
10361
  requestId: String(request.request_id || "")
10339
10362
  }));
10340
- const discoveredActionableCount = discoveredRows.filter((row) => row.mode === "accept" || row.mode === "scope-pending").length;
10363
+ const visibleDiscoveredRows = discoveredRows.filter((row) => row.mode !== "paired" && row.mode !== "none");
10364
+ const discoveredActionableCount = visibleDiscoveredRows.filter((row) => row.mode === "accept" || row.mode === "scope-pending").length;
10341
10365
  const actionableCount = attentionItems.length + pendingJoinRequests.length + discoveredActionableCount;
10366
+ const attentionParts = [];
10367
+ if (attentionItems.length > 0) {
10368
+ const deviceItems = attentionItems.filter((item) => item.kind !== "possible-duplicate-person");
10369
+ const duplicateItems = attentionItems.filter((item) => item.kind === "possible-duplicate-person");
10370
+ if (deviceItems.length > 0) attentionParts.push(`${deviceItems.length} device${deviceItems.length === 1 ? "" : "s"}`);
10371
+ if (duplicateItems.length > 0) attentionParts.push(`${duplicateItems.length} duplicate${duplicateItems.length === 1 ? "" : "s"}`);
10372
+ }
10373
+ if (pendingJoinRequests.length > 0) attentionParts.push(`${pendingJoinRequests.length} join request${pendingJoinRequests.length === 1 ? "" : "s"}`);
10374
+ if (discoveredActionableCount > 0) attentionParts.push(`${discoveredActionableCount} discovered`);
10375
+ const attentionDetail = attentionParts.join(", ");
10342
10376
  const teamLabel = (coordinator.groups || []).join(", ") || "none";
10343
10377
  const statusSummary = {
10344
10378
  badgeClassName: `pill ${presenceStatus === "posted" ? "pill-success" : presenceStatus === "not_enrolled" ? "pill-warning" : "pill-error"}`,
10345
- headline: presenceStatus === "posted" ? actionableCount > 0 ? `${actionableCount} item${actionableCount === 1 ? "" : "s"} need attention` : "Everything is healthy" : presenceStatus === "not_enrolled" ? "This device is not enrolled in the team yet" : "Sync needs attention",
10379
+ headline: presenceStatus === "posted" ? actionableCount > 0 ? `${attentionDetail} need${actionableCount === 1 ? "s" : ""} attention` : "Everything is healthy" : presenceStatus === "not_enrolled" ? "This device is not enrolled in the team yet" : "Sync needs attention",
10346
10380
  metricsText: metricParts.join(" · "),
10347
10381
  presenceLabel
10348
10382
  };
10349
10383
  meta.textContent = presenceStatus === "posted" ? actionableCount > 0 ? `Team: ${teamLabel}. Start with the next step below, then scan the current team status.` : `Team: ${teamLabel}. Team status and device details are below.` : presenceStatus === "not_enrolled" ? `Team: ${teamLabel}. Enroll this device first, then return here to review the rest of the team.` : `Team: ${teamLabel}. Fix the current sync issue first, then use the rest of this card to verify the team state.`;
10350
- if (discoveredPanel) discoveredPanel.hidden = discoveredRows.length === 0 && !state.syncDiscoveredFeedback;
10351
- if (discoveredMeta) discoveredMeta.textContent = discoveredRows.length ? "Review anything here that still needs trust, repair, or approval." : "";
10384
+ if (discoveredPanel) discoveredPanel.hidden = visibleDiscoveredRows.length === 0 && !state.syncDiscoveredFeedback;
10385
+ if (discoveredMeta) discoveredMeta.textContent = visibleDiscoveredRows.length ? "Review anything here that still needs trust, repair, or approval." : "";
10352
10386
  if (joinRequests) joinRequests.hidden = pendingJoinRequests.length === 0 && !state.syncJoinRequestsFeedback;
10353
10387
  teardownTeamSyncRender(actions, [
10354
10388
  list,
@@ -10376,7 +10410,7 @@ For more information, see https://radix-ui.com/primitives/docs/components/${titl
10376
10410
  presenceStatus
10377
10411
  }),
10378
10412
  discoveredListMount: discoveredList,
10379
- discoveredRows,
10413
+ discoveredRows: visibleDiscoveredRows,
10380
10414
  joinRequestsMount: joinRequests,
10381
10415
  listMount: list,
10382
10416
  onApproveJoinRequest: async (request) => {
@@ -10642,7 +10676,7 @@ For more information, see https://radix-ui.com/primitives/docs/components/${titl
10642
10676
  if (hiddenLocalDuplicateCount <= 0) return "Represents you across your devices.";
10643
10677
  return `Represents you across your devices. ${hiddenLocalDuplicateCount} unresolved duplicate ${hiddenLocalDuplicateCount === 1 ? "entry is" : "entries are"} hidden until reviewed in Needs attention.`;
10644
10678
  }
10645
- function SyncActorRow({ actor, hiddenLocalDuplicateCount, onRename, onMerge }) {
10679
+ function SyncActorRow({ actor, hiddenLocalDuplicateCount, onRename, onMerge, onDeactivate }) {
10646
10680
  const actorId = String(actor.actor_id || "");
10647
10681
  const label = actorLabel(actor);
10648
10682
  const count = assignedActorCount(actorId);
@@ -10775,12 +10809,26 @@ For more information, see https://radix-ui.com/primitives/docs/components/${titl
10775
10809
  /* @__PURE__ */ u("div", {
10776
10810
  className: "peer-meta actor-merge-note",
10777
10811
  children: mergeNote
10812
+ }),
10813
+ /* @__PURE__ */ u("button", {
10814
+ className: "settings-button",
10815
+ disabled: renameBusy || mergeBusy,
10816
+ onClick: async () => {
10817
+ if (await openSyncConfirmDialog({
10818
+ title: `Remove ${label}?`,
10819
+ description: "This deactivates the person and unassigns their devices. Existing memories keep their current attribution.",
10820
+ confirmLabel: "Remove person",
10821
+ cancelLabel: "Keep",
10822
+ tone: "danger"
10823
+ })) await onDeactivate(actorId);
10824
+ },
10825
+ children: "Remove person"
10778
10826
  })
10779
10827
  ] })
10780
10828
  })]
10781
10829
  });
10782
10830
  }
10783
- function SyncActorsList({ actors, hiddenLocalDuplicateCount, onRename, onMerge }) {
10831
+ function SyncActorsList({ actors, hiddenLocalDuplicateCount, onRename, onMerge, onDeactivate }) {
10784
10832
  if (!actors.length) return /* @__PURE__ */ u("div", {
10785
10833
  className: "sync-empty-state",
10786
10834
  children: [/* @__PURE__ */ u("strong", { children: "No people yet." }), /* @__PURE__ */ u("span", { children: "Create a named person here, then assign each device below to keep sync ownership readable." })]
@@ -10791,7 +10839,8 @@ For more information, see https://radix-ui.com/primitives/docs/components/${titl
10791
10839
  actor,
10792
10840
  hiddenLocalDuplicateCount,
10793
10841
  onRename,
10794
- onMerge
10842
+ onMerge,
10843
+ onDeactivate
10795
10844
  }, actorId);
10796
10845
  }) });
10797
10846
  }
@@ -11286,6 +11335,16 @@ For more information, see https://radix-ui.com/primitives/docs/components/${titl
11286
11335
  showGlobalNotice(friendlyError(error, "Failed to combine people."), "warning");
11287
11336
  throw error;
11288
11337
  }
11338
+ },
11339
+ onDeactivate: async (actorId) => {
11340
+ try {
11341
+ await deactivateActor(actorId);
11342
+ showGlobalNotice("Person removed. Assigned devices have been unassigned.");
11343
+ await _loadSyncData();
11344
+ } catch (error) {
11345
+ showGlobalNotice(friendlyError(error, "Failed to remove person."), "warning");
11346
+ throw error;
11347
+ }
11289
11348
  }
11290
11349
  });
11291
11350
  }
@@ -13294,7 +13353,7 @@ For more information, see https://radix-ui.com/primitives/docs/components/${titl
13294
13353
  try {
13295
13354
  const runtime = await loadRuntimeInfo();
13296
13355
  if (!runtime?.version) return;
13297
- setRuntimeLabel(runtime.version, "692076f");
13356
+ setRuntimeLabel(runtime.version, "23ef706");
13298
13357
  } catch {}
13299
13358
  }
13300
13359
  var lastAnnouncedRefreshState = null;