@codemem/server 0.46.0-beta.2 → 0.46.0-rc.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.
@@ -34,6 +34,13 @@ export interface SyncStatusInput {
34
34
  getSyncRuntimeStatus?: () => SyncRuntimeStatus | null;
35
35
  operations: SyncStatusOperations;
36
36
  }
37
+ interface PeerStatusReadModel {
38
+ items: Record<string, unknown>[];
39
+ byId: Record<string, unknown>;
40
+ }
41
+ export declare function safeDaemonIssueCode(state: string, lastError: string | null | undefined): "coordinator_timeout" | "coordinator_error" | null;
42
+ export declare function latestFailedPeerIds(store: MemoryStore, activePeerIds: Set<string>, isRecentIso: (value: unknown) => boolean): Set<string>;
43
+ export declare function degradedDaemonState(peers: PeerStatusReadModel, failedPeerIds: Set<string>): string;
37
44
  export declare function buildSyncStatusResponse(input: SyncStatusInput): Promise<Record<string, unknown>>;
38
45
  export {};
39
46
  //# sourceMappingURL=sync-status.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"sync-status.d.ts","sourceRoot":"","sources":["../../src/application/sync-status.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"sync-status.d.ts","sourceRoot":"","sources":["../../src/application/sync-status.ts"],"names":[],"mappings":"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"}
package/dist/index.js CHANGED
@@ -4151,6 +4151,14 @@ async function reconcileRecipientPolicyProjectsOperation(store, options) {
4151
4151
  }
4152
4152
  //#endregion
4153
4153
  //#region src/application/sync-status.ts
4154
+ var SAFE_RUNTIME_DETAILS = {
4155
+ starting: "Running initial sync in background",
4156
+ stopping: "Stopping sync daemon",
4157
+ error: "Background sync failed. Open diagnostics for details.",
4158
+ rebootstrapping: "Restoring sync baseline",
4159
+ needs_attention: "Sync needs attention",
4160
+ disabled: "Sync is off"
4161
+ };
4154
4162
  function traceSync(label, operation) {
4155
4163
  if (process.env.CODEMEM_TRACE_SYNC_STATUS !== "1") return operation();
4156
4164
  const startedAt = Date.now();
@@ -4215,6 +4223,10 @@ function initialDaemonState(config, rows, daemonRunning) {
4215
4223
  if (!daemonRunning) return "stopped";
4216
4224
  return "ok";
4217
4225
  }
4226
+ function safeDaemonIssueCode(state, lastError) {
4227
+ if (state !== "error" || !lastError?.includes("coordinator enrollment maintenance failed")) return null;
4228
+ return lastError.includes(":request_timeout") || lastError.endsWith(" (coordinator_timeout)") ? "coordinator_timeout" : "coordinator_error";
4229
+ }
4218
4230
  function retentionPayload(config, rows, retainedFloor) {
4219
4231
  const state = rows.retention;
4220
4232
  return {
@@ -4282,8 +4294,9 @@ function readBaseStatus(input) {
4282
4294
  state = runtime.phase;
4283
4295
  statusPayload.daemon_state = state;
4284
4296
  statusPayload.daemon_running = runtime.phase === "starting" || running;
4285
- statusPayload.daemon_detail = runtime.detail ?? detail;
4297
+ statusPayload.daemon_detail = input.showDiagnostics ? runtime.detail ?? detail : SAFE_RUNTIME_DETAILS[runtime.phase] ?? null;
4286
4298
  }
4299
+ statusPayload.daemon_issue_code = safeDaemonIssueCode(state, runtime?.phase === "error" ? null : rows.daemon?.last_error);
4287
4300
  return {
4288
4301
  config,
4289
4302
  localDeviceId: rows.device?.device_id ?? null,
@@ -4340,16 +4353,35 @@ function readAttemptStatus(input) {
4340
4353
  latestError: String(rows[0]?.error || "").trim()
4341
4354
  };
4342
4355
  }
4356
+ function latestFailedPeerIds(store, activePeerIds, isRecentIso) {
4357
+ const cutoff = (/* @__PURE__ */ new Date(Date.now() - 6e5)).toISOString();
4358
+ const now = (/* @__PURE__ */ new Date()).toISOString();
4359
+ return traceSync("recentPeerFailures", () => {
4360
+ const rows = store.db.prepare(`SELECT peer_device_id, ok, error, finished_at
4361
+ FROM sync_attempts
4362
+ WHERE (CASE WHEN finished_at IS NULL THEN started_at ELSE finished_at END) BETWEEN ? AND ?
4363
+ ORDER BY (CASE WHEN finished_at IS NULL THEN started_at ELSE finished_at END) DESC, id DESC`).iterate(cutoff, now);
4364
+ const seen = /* @__PURE__ */ new Set();
4365
+ const failed = /* @__PURE__ */ new Set();
4366
+ for (const row of rows) {
4367
+ if (!activePeerIds.has(row.peer_device_id) || seen.has(row.peer_device_id)) continue;
4368
+ if (!isRecentIso(row.finished_at)) continue;
4369
+ seen.add(row.peer_device_id);
4370
+ if (!row.ok && row.error) failed.add(row.peer_device_id);
4371
+ }
4372
+ return failed;
4373
+ });
4374
+ }
4343
4375
  function peerStates(peers) {
4344
4376
  return new Set(peers.items.map((peer) => String(peer.status?.peer_state ?? "")));
4345
4377
  }
4346
4378
  function allPeersOffline(peers) {
4347
4379
  return peers.items.length > 0 && peers.items.every((peer) => String(peer.status?.peer_state ?? "") === "offline");
4348
4380
  }
4349
- function degradedDaemonState(input, peers, attempts) {
4381
+ function degradedDaemonState(peers, failedPeerIds) {
4350
4382
  const states = peerStates(peers);
4351
4383
  const allOffline = allPeersOffline(peers);
4352
- if (Boolean(attempts.items[0] && attempts.items[0].status === "error" && input.operations.isRecentIso(attempts.items[0].finished_at))) {
4384
+ if (failedPeerIds.size > 0) {
4353
4385
  if (states.has("online") || states.has("degraded")) return "degraded";
4354
4386
  if (allOffline) return "offline-peers";
4355
4387
  if (peers.items.length > 0) return "stale";
@@ -4359,14 +4391,14 @@ function degradedDaemonState(input, peers, attempts) {
4359
4391
  if (peers.items.length > 0 && !states.has("online")) return "stale";
4360
4392
  return "ok";
4361
4393
  }
4362
- function applyDerivedDaemonState(input, base, peers, attempts, statusBlock) {
4394
+ function applyDerivedDaemonState(base, peers, attempts, failedPeerIds, statusBlock) {
4363
4395
  let state = base.daemonState;
4364
4396
  if (state === "ok" && attempts.latestError.startsWith("needs_attention:")) {
4365
4397
  state = "needs_attention";
4366
4398
  const detail = attempts.latestError.replace(/^needs_attention:/, "");
4367
4399
  base.statusPayload.daemon_detail = detail;
4368
4400
  statusBlock.daemon_detail = detail;
4369
- } else if (state === "ok") state = degradedDaemonState(input, peers, attempts);
4401
+ } else if (state === "ok") state = degradedDaemonState(peers, failedPeerIds);
4370
4402
  base.statusPayload.daemon_state = state;
4371
4403
  statusBlock.daemon_state = state;
4372
4404
  }
@@ -4384,6 +4416,12 @@ async function buildSyncStatusResponse(input) {
4384
4416
  const coordinator = traceSync("coordinator", () => input.operations.redactCoordinatorStatus(coordinatorSnapshot, input.showDiagnostics));
4385
4417
  const peers = readPeerStatus(input, base.localDeviceId);
4386
4418
  const attempts = readAttemptStatus(input);
4419
+ const activePeerIds = new Set(peers.items.map((peer) => String(peer.peer_device_id ?? "")));
4420
+ const failedPeerIds = latestFailedPeerIds(input.store, activePeerIds, input.operations.isRecentIso);
4421
+ for (const peer of peers.items) {
4422
+ const status = peer.status;
4423
+ status.recent_failed_attempt = failedPeerIds.has(String(peer.peer_device_id ?? ""));
4424
+ }
4387
4425
  const statusBlock = {
4388
4426
  ...base.statusPayload,
4389
4427
  background_maintenance: input.operations.summarizeMaintenanceJobs(listMaintenanceJobs(input.store.db), input.showDiagnostics),
@@ -4397,7 +4435,7 @@ async function buildSyncStatusResponse(input) {
4397
4435
  const sharingReview = traceSync("sharingReview", () => input.store.sharingReviewSummary(input.project));
4398
4436
  const recipientPolicyReconciliation = traceSync("recipientPolicyReconciliation", () => input.operations.listRecipientPolicyReconciliationStatus(input.store));
4399
4437
  const joinRequests = await readJoinRequests(input, base.config);
4400
- applyDerivedDaemonState(input, base, peers, attempts, statusBlock);
4438
+ applyDerivedDaemonState(base, peers, attempts, failedPeerIds, statusBlock);
4401
4439
  const response = {
4402
4440
  ...base.statusPayload,
4403
4441
  status: statusBlock,
@@ -7429,6 +7467,21 @@ function recipientPolicyPresenceCapabilityExpiresAt(enrollment, observedAt) {
7429
7467
  function recipientPolicyEnrollmentValueIsValid(value) {
7430
7468
  return typeof value === "string" && value.length > 0 && value === value.trim();
7431
7469
  }
7470
+ function recipientPolicyPresenceCapabilityExpiries(enrollments, observedAt) {
7471
+ return new Map(enrollments.map((enrollment) => [enrollment.device_id, recipientPolicyPresenceCapabilityExpiresAt(enrollment, observedAt)]));
7472
+ }
7473
+ function recipientPolicySnapshotUnavailable(stage, error) {
7474
+ console.warn(`[sync] recipient policy coordinator snapshot failed: stage=${stage} code=${coordinatorEnrollmentFailureCode(error)}`);
7475
+ throw new Error("recipient_policy_snapshot_not_fresh");
7476
+ }
7477
+ async function readRecipientPolicyCoordinatorSnapshot(read) {
7478
+ for (let attempt = 0;; attempt++) try {
7479
+ return await read();
7480
+ } catch (error) {
7481
+ if (!(error instanceof RemoteCoordinatorRequestError) || error.status !== 429 || attempt >= 2) throw error;
7482
+ await new Promise((resolve) => setTimeout(resolve, (attempt + 1) * 1e3));
7483
+ }
7484
+ }
7432
7485
  function createRecipientPolicyReconcilerEffects(store, options = {}) {
7433
7486
  const config = options.config ?? readCoordinatorSyncConfig();
7434
7487
  const now = options.now ?? (() => (/* @__PURE__ */ new Date()).toISOString());
@@ -7470,15 +7523,13 @@ function createRecipientPolicyReconcilerEffects(store, options = {}) {
7470
7523
  now,
7471
7524
  snapshot: async ({ scopeId }) => {
7472
7525
  const targetOptions = coordinatorOptions(scopeId);
7473
- const snapshotMemberships = (await coordinatorListScopeMembershipsAction({
7526
+ const snapshotMemberships = (await readRecipientPolicyCoordinatorSnapshot(() => coordinatorListScopeMembershipsAction({
7474
7527
  groupId: targetOptions.groupId,
7475
7528
  scopeId,
7476
7529
  includeRevoked: true,
7477
7530
  remoteUrl: targetOptions.remoteUrl,
7478
7531
  adminSecret: targetOptions.adminSecret
7479
- }).catch(() => {
7480
- throw new Error("recipient_policy_snapshot_not_fresh");
7481
- })).map((membership) => {
7532
+ })).catch((error) => recipientPolicySnapshotUnavailable("scope_memberships", error))).map((membership) => {
7482
7533
  if (typeof membership.device_id !== "string" || membership.status !== "active" && membership.status !== "revoked") throw new Error("recipient_policy_snapshot_invalid");
7483
7534
  const status = membership.status;
7484
7535
  return {
@@ -7499,15 +7550,13 @@ function createRecipientPolicyReconcilerEffects(store, options = {}) {
7499
7550
  listBoundaryEnrollments: async ({ scopeId }) => {
7500
7551
  const targetOptions = coordinatorOptions(scopeId);
7501
7552
  const observedAt = now();
7502
- const enrollments = await listDevices({
7553
+ const enrollments = await readRecipientPolicyCoordinatorSnapshot(() => listDevices({
7503
7554
  groupId: targetOptions.groupId,
7504
7555
  includeDisabled: true,
7505
7556
  remoteUrl: targetOptions.remoteUrl,
7506
7557
  adminSecret: targetOptions.adminSecret
7507
- }).catch(() => {
7508
- throw new Error("recipient_policy_snapshot_not_fresh");
7509
- });
7510
- const presenceCapabilityExpiries = new Map(enrollments.map((enrollment) => [enrollment.device_id, recipientPolicyPresenceCapabilityExpiresAt(enrollment, observedAt)]));
7558
+ })).catch((error) => recipientPolicySnapshotUnavailable("device_enrollments", error));
7559
+ const presenceCapabilityExpiries = recipientPolicyPresenceCapabilityExpiries(enrollments, observedAt);
7511
7560
  const mapped = enrollments.map((enrollment) => {
7512
7561
  if (enrollment.group_id !== targetOptions.groupId || !recipientPolicyEnrollmentValueIsValid(enrollment.device_id) || !recipientPolicyEnrollmentValueIsValid(enrollment.public_key) || !recipientPolicyEnrollmentValueIsValid(enrollment.fingerprint) || fingerprintPublicKey(enrollment.public_key) !== enrollment.fingerprint || enrollment.enabled !== 0 && enrollment.enabled !== 1 || enrollment.identity_id !== null && !recipientPolicyEnrollmentValueIsValid(enrollment.identity_id)) throw new Error("recipient_policy_snapshot_invalid");
7513
7562
  return {