@codemem/server 0.22.3 → 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.
package/dist/index.js CHANGED
@@ -6,7 +6,7 @@ import { Hono } from "hono";
6
6
  import { createMiddleware } from "hono/factory";
7
7
  import { RateLimiter } from "limiter";
8
8
  import { homedir } from "node:os";
9
- import { count, desc, eq, inArray, isNotNull, max, ne } from "drizzle-orm";
9
+ import { and, count, desc, eq, inArray, isNotNull, max, ne } from "drizzle-orm";
10
10
  import { drizzle } from "drizzle-orm/better-sqlite3";
11
11
  import { createHash, randomUUID } from "node:crypto";
12
12
  import net from "node:net";
@@ -1880,7 +1880,7 @@ function syncProtocolRoutes(getStore, opts = {}) {
1880
1880
  const baselineCursor = c.req.query("baseline_cursor") ?? null;
1881
1881
  const pageToken = c.req.query("page_token") ?? null;
1882
1882
  const rawLimit = Number.parseInt(c.req.query("limit") ?? "200", 10);
1883
- const limit = Number.isFinite(rawLimit) ? Math.max(1, Math.min(rawLimit, 1e3)) : 200;
1883
+ const limit = Number.isFinite(rawLimit) ? Math.max(1, Math.min(rawLimit, 5e3)) : 200;
1884
1884
  if (generation == null || !Number.isFinite(generation)) return c.json({ error: "missing_generation" }, 400);
1885
1885
  if (!snapshotId) return c.json({ error: "missing_snapshot_id" }, 400);
1886
1886
  const result = loadMemorySnapshotPageForPeer(store.db, {
@@ -2036,7 +2036,7 @@ function syncRoutes(getStore, getSyncRuntimeStatus) {
2036
2036
  });
2037
2037
  const peersMap = {};
2038
2038
  for (const peer of peersItems) peersMap[String(peer.peer_device_id)] = peer.status;
2039
- const attemptsItems = d.select({
2039
+ const attemptRows = d.select({
2040
2040
  peer_device_id: schema.syncAttempts.peer_device_id,
2041
2041
  ok: schema.syncAttempts.ok,
2042
2042
  error: schema.syncAttempts.error,
@@ -2044,11 +2044,20 @@ function syncRoutes(getStore, getSyncRuntimeStatus) {
2044
2044
  finished_at: schema.syncAttempts.finished_at,
2045
2045
  ops_in: schema.syncAttempts.ops_in,
2046
2046
  ops_out: schema.syncAttempts.ops_out
2047
- }).from(schema.syncAttempts).orderBy(desc(schema.syncAttempts.finished_at)).limit(25).all().map((row) => ({
2048
- ...row,
2049
- status: attemptStatus(row),
2050
- address: null
2051
- }));
2047
+ }).from(schema.syncAttempts).orderBy(desc(schema.syncAttempts.finished_at)).limit(25).all();
2048
+ const peerAddressMap = /* @__PURE__ */ new Map();
2049
+ store.db.prepare("SELECT peer_device_id, addresses_json FROM sync_peers").all().forEach((peerRow) => {
2050
+ const addrs = safeJsonList(peerRow.addresses_json);
2051
+ if (addrs.length) peerAddressMap.set(String(peerRow.peer_device_id ?? ""), addrs);
2052
+ });
2053
+ const attemptsItems = attemptRows.map((row) => {
2054
+ const addrs = showDiag ? peerAddressMap.get(String(row.peer_device_id ?? "")) : void 0;
2055
+ return {
2056
+ ...row,
2057
+ status: attemptStatus(row),
2058
+ address: addrs?.length ? addrs[0] : null
2059
+ };
2060
+ });
2052
2061
  const latestAttemptError = String(attemptsItems[0]?.error || "").trim();
2053
2062
  const statusBlock = {
2054
2063
  ...statusPayload,
@@ -2118,7 +2127,7 @@ function syncRoutes(getStore, getSyncRuntimeStatus) {
2118
2127
  const d = drizzle(store.db, { schema });
2119
2128
  const includeMerged = queryBool(c.req.query("includeMerged"));
2120
2129
  const query = d.select().from(schema.actors);
2121
- const rows = includeMerged ? query.orderBy(schema.actors.display_name).all() : query.where(ne(schema.actors.status, "merged")).orderBy(schema.actors.display_name).all();
2130
+ const rows = includeMerged ? query.orderBy(schema.actors.display_name).all() : query.where(and(ne(schema.actors.status, "merged"), ne(schema.actors.status, "deactivated"))).orderBy(schema.actors.display_name).all();
2122
2131
  return c.json({ items: rows });
2123
2132
  }
2124
2133
  });
@@ -2371,7 +2380,7 @@ function syncRoutes(getStore, getSyncRuntimeStatus) {
2371
2380
  if (!primary || !secondary) return c.json({ error: "actor not found" }, 404);
2372
2381
  if (primary.status !== "active") return c.json({ error: "primary actor not active" }, 409);
2373
2382
  if (secondary.status !== "active") return c.json({ error: "secondary actor not active" }, 409);
2374
- if (secondary.is_local) return c.json({ error: "cannot merge local actor" }, 409);
2383
+ if (secondary.is_local && secondary.actor_id === store.actorId) return c.json({ error: "cannot merge this device's own local actor" }, 409);
2375
2384
  const now = (/* @__PURE__ */ new Date()).toISOString();
2376
2385
  const mergedCount = store.db.transaction(() => {
2377
2386
  const peerUpdate = d.update(schema.syncPeers).set({ actor_id: primaryActorId }).where(eq(schema.syncPeers.actor_id, secondaryActorId)).run();
@@ -2385,6 +2394,29 @@ function syncRoutes(getStore, getSyncRuntimeStatus) {
2385
2394
  })();
2386
2395
  return c.json({ merged_count: mergedCount });
2387
2396
  });
2397
+ app.post("/api/sync/actors/deactivate", async (c) => {
2398
+ const store = getStore();
2399
+ let body;
2400
+ try {
2401
+ body = await c.req.json();
2402
+ } catch {
2403
+ return c.json({ error: "invalid json" }, 400);
2404
+ }
2405
+ const actorId = String(body.actor_id ?? "").trim();
2406
+ if (!actorId) return c.json({ error: "actor_id required" }, 400);
2407
+ if (actorId === store.actorId) return c.json({ error: "cannot deactivate this device's own local actor" }, 409);
2408
+ const d = drizzle(store.db, { schema });
2409
+ const actor = d.select().from(schema.actors).where(eq(schema.actors.actor_id, actorId)).get();
2410
+ if (!actor) return c.json({ error: "actor not found" }, 404);
2411
+ if (actor.status !== "active") return c.json({ error: "actor not active" }, 409);
2412
+ const now = (/* @__PURE__ */ new Date()).toISOString();
2413
+ d.update(schema.actors).set({
2414
+ status: "deactivated",
2415
+ updated_at: now
2416
+ }).where(eq(schema.actors.actor_id, actorId)).run();
2417
+ d.update(schema.syncPeers).set({ actor_id: null }).where(eq(schema.syncPeers.actor_id, actorId)).run();
2418
+ return c.json({ ok: true });
2419
+ });
2388
2420
  app.post("/api/sync/legacy-devices/claim", async (c) => {
2389
2421
  const store = getStore();
2390
2422
  let body;