@codemem/server 0.27.0 → 0.28.0
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 +82 -6
- package/dist/index.js.map +1 -1
- package/dist/routes/sync.d.ts.map +1 -1
- package/package.json +2 -2
- package/static/app.js +14918 -12421
- package/static/favicon.svg +4 -14
- package/static/index.html +833 -369
package/dist/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { existsSync, readFileSync } from "node:fs";
|
|
2
2
|
import { dirname, join } from "node:path";
|
|
3
|
-
import { CODEMEM_CONFIG_ENV_OVERRIDES, DEFAULT_TIME_WINDOW_S, MemoryStore, VERSION, VERSION as VERSION$1, applyReplicationOps, buildBaseUrl, buildFilterClausesWithContext, buildRawEventEnvelopeFromHook, canonicalMemoryKind, cleanupNonces, coordinatorArchiveGroupAction, coordinatorCreateGroupAction, coordinatorCreateInviteAction, coordinatorDisableDeviceAction, coordinatorImportInviteAction, coordinatorListBootstrapGrantsAction, coordinatorListDevicesAction, coordinatorListGroupsAction, coordinatorListJoinRequestsAction, coordinatorRemoveDeviceAction, coordinatorRenameDeviceAction, coordinatorRenameGroupAction, coordinatorReviewJoinRequestAction, coordinatorRevokeBootstrapGrantAction, coordinatorStatusSnapshot, coordinatorUnarchiveGroupAction, createCoordinatorReciprocalApproval, ensureDeviceIdentity, extractReplicationOps, fingerprintPublicKey, fromJson, getCodememConfigPath, getCodememEnvOverrides, getSemanticIndexDiagnostics, getSyncResetState, isSummaryLikeMemory, listCoordinatorJoinRequests, listMaintenanceJobs, listObserverProviderOptions, loadMemorySnapshotPageForPeer, loadReplicationOpsForPeer, lookupCoordinatorPeers, mergeAddresses, parseStrictInteger, probeAvailableCredentials, readCodememConfigFile, readCoordinatorSyncConfig, recordNonce, requestJson, resolveDbPath, runSyncPass, schema, stripJsonComments, stripPrivateObj, stripTrailingCommas, syncProjectAllowedByFilters, syncVisibilityAllowed, verifySignature, writeCodememConfigFile } from "@codemem/core";
|
|
3
|
+
import { CODEMEM_CONFIG_ENV_OVERRIDES, DEFAULT_TIME_WINDOW_S, MemoryStore, VERSION, VERSION as VERSION$1, applyReplicationOps, buildBaseUrl, buildFilterClausesWithContext, buildRawEventEnvelopeFromHook, canonicalMemoryKind, cleanupNonces, coordinatorArchiveGroupAction, coordinatorCreateGroupAction, coordinatorCreateInviteAction, coordinatorDisableDeviceAction, coordinatorEnableDeviceAction, coordinatorImportInviteAction, coordinatorListBootstrapGrantsAction, coordinatorListDevicesAction, coordinatorListGroupsAction, coordinatorListJoinRequestsAction, coordinatorRemoveDeviceAction, coordinatorRenameDeviceAction, coordinatorRenameGroupAction, coordinatorReviewJoinRequestAction, coordinatorRevokeBootstrapGrantAction, coordinatorStatusSnapshot, coordinatorUnarchiveGroupAction, createCoordinatorReciprocalApproval, ensureDeviceIdentity, extractReplicationOps, fingerprintPublicKey, fromJson, getCodememConfigPath, getCodememEnvOverrides, getSemanticIndexDiagnostics, getSyncResetState, isSummaryLikeMemory, listCoordinatorJoinRequests, listMaintenanceJobs, listObserverProviderOptions, loadMemorySnapshotPageForPeer, loadReplicationOpsForPeer, lookupCoordinatorPeers, mergeAddresses, parseStrictInteger, probeAvailableCredentials, readCodememConfigFile, readCoordinatorSyncConfig, recordNonce, requestJson, resolveDbPath, runSyncPass, schema, stripJsonComments, stripPrivateObj, stripTrailingCommas, syncProjectAllowedByFilters, syncVisibilityAllowed, verifySignature, writeCodememConfigFile } from "@codemem/core";
|
|
4
4
|
import { serveStatic } from "@hono/node-server/serve-static";
|
|
5
5
|
import { Hono } from "hono";
|
|
6
6
|
import { createMiddleware } from "hono/factory";
|
|
@@ -1975,7 +1975,12 @@ function filterOpsForPeer(store, peerDeviceId, ops) {
|
|
|
1975
1975
|
* When showDiag is false, sensitive fields (fingerprint, last_error, addresses)
|
|
1976
1976
|
* are redacted.
|
|
1977
1977
|
*/
|
|
1978
|
-
function mapPeerRow(store, row, showDiag) {
|
|
1978
|
+
function mapPeerRow(store, row, showDiag, recentOpsByPeer) {
|
|
1979
|
+
const peerId = String(row.peer_device_id ?? "");
|
|
1980
|
+
const recentOps = recentOpsByPeer?.get(peerId) ?? {
|
|
1981
|
+
in: 0,
|
|
1982
|
+
out: 0
|
|
1983
|
+
};
|
|
1979
1984
|
return {
|
|
1980
1985
|
peer_device_id: row.peer_device_id,
|
|
1981
1986
|
name: row.name,
|
|
@@ -1989,9 +1994,33 @@ function mapPeerRow(store, row, showDiag) {
|
|
|
1989
1994
|
claimed_local_actor: Boolean(row.claimed_local_actor),
|
|
1990
1995
|
actor_id: row.actor_id ?? null,
|
|
1991
1996
|
actor_display_name: row.actor_display_name ?? null,
|
|
1992
|
-
project_scope: { ...currentProjectScope(row, readPeerProjectFilters(store, String(row.peer_device_id ?? ""))) }
|
|
1997
|
+
project_scope: { ...currentProjectScope(row, readPeerProjectFilters(store, String(row.peer_device_id ?? ""))) },
|
|
1998
|
+
recent_ops: {
|
|
1999
|
+
in: recentOps.in,
|
|
2000
|
+
out: recentOps.out
|
|
2001
|
+
}
|
|
1993
2002
|
};
|
|
1994
2003
|
}
|
|
2004
|
+
var SYNC_DIRECTION_WINDOW_SECONDS = 1440 * 60;
|
|
2005
|
+
function recentPeerOps(store) {
|
|
2006
|
+
const cutoff = (/* @__PURE__ */ new Date(Date.now() - SYNC_DIRECTION_WINDOW_SECONDS * 1e3)).toISOString();
|
|
2007
|
+
const rows = store.db.prepare(`SELECT peer_device_id,
|
|
2008
|
+
COALESCE(SUM(ops_in), 0) AS ops_in,
|
|
2009
|
+
COALESCE(SUM(ops_out), 0) AS ops_out
|
|
2010
|
+
FROM sync_attempts
|
|
2011
|
+
WHERE ok = 1 AND finished_at IS NOT NULL AND finished_at >= ?
|
|
2012
|
+
GROUP BY peer_device_id`).all(cutoff);
|
|
2013
|
+
const map = /* @__PURE__ */ new Map();
|
|
2014
|
+
for (const row of rows) {
|
|
2015
|
+
const id = String(row.peer_device_id ?? "").trim();
|
|
2016
|
+
if (!id) continue;
|
|
2017
|
+
map.set(id, {
|
|
2018
|
+
in: Number(row.ops_in ?? 0),
|
|
2019
|
+
out: Number(row.ops_out ?? 0)
|
|
2020
|
+
});
|
|
2021
|
+
}
|
|
2022
|
+
return map;
|
|
2023
|
+
}
|
|
1995
2024
|
function isRecentIso(value, windowS = SYNC_STALE_AFTER_SECONDS) {
|
|
1996
2025
|
const raw = String(value ?? "").trim();
|
|
1997
2026
|
if (!raw) return false;
|
|
@@ -2361,8 +2390,10 @@ function syncRoutes(getStore, getSyncRuntimeStatus) {
|
|
|
2361
2390
|
statusPayload.daemon_running = runtimeStatus.phase === "starting" || daemonRunning;
|
|
2362
2391
|
statusPayload.daemon_detail = runtimeStatus.detail ?? daemonDetail;
|
|
2363
2392
|
}
|
|
2364
|
-
const
|
|
2365
|
-
|
|
2393
|
+
const peerRows = traceSync("peerRows", () => store.db.prepare(PEERS_QUERY).all());
|
|
2394
|
+
const recentOpsByPeer = traceSync("recentPeerOps", () => recentPeerOps(store));
|
|
2395
|
+
const peersItems = peerRows.map((row) => {
|
|
2396
|
+
const peer = mapPeerRow(store, row, showDiag, recentOpsByPeer);
|
|
2366
2397
|
peer.status = peerStatus(peer);
|
|
2367
2398
|
return peer;
|
|
2368
2399
|
});
|
|
@@ -2447,7 +2478,9 @@ function syncRoutes(getStore, getSyncRuntimeStatus) {
|
|
|
2447
2478
|
const store = getStore();
|
|
2448
2479
|
{
|
|
2449
2480
|
const showDiag = queryBool(c.req.query("includeDiagnostics"));
|
|
2450
|
-
const
|
|
2481
|
+
const rows = store.db.prepare(PEERS_QUERY).all();
|
|
2482
|
+
const recentOpsByPeer = recentPeerOps(store);
|
|
2483
|
+
const peers = rows.map((row) => mapPeerRow(store, row, showDiag, recentOpsByPeer));
|
|
2451
2484
|
return c.json({
|
|
2452
2485
|
items: peers,
|
|
2453
2486
|
redacted: !showDiag
|
|
@@ -3381,6 +3414,49 @@ function syncRoutes(getStore, getSyncRuntimeStatus) {
|
|
|
3381
3414
|
}, 400);
|
|
3382
3415
|
}
|
|
3383
3416
|
});
|
|
3417
|
+
app.post("/api/coordinator/admin/devices/:device_id/enable", async (c) => {
|
|
3418
|
+
const config = readCoordinatorSyncConfig();
|
|
3419
|
+
const status = coordinatorAdminStatusPayload(config);
|
|
3420
|
+
if (status.readiness === "not_configured") return c.json({
|
|
3421
|
+
error: "coordinator_not_configured",
|
|
3422
|
+
status
|
|
3423
|
+
}, 400);
|
|
3424
|
+
if (!status.has_admin_secret) return c.json({
|
|
3425
|
+
error: "coordinator_admin_secret_missing",
|
|
3426
|
+
status
|
|
3427
|
+
}, 400);
|
|
3428
|
+
const deviceId = String(c.req.param("device_id") ?? "").trim();
|
|
3429
|
+
if (!deviceId) return c.json({
|
|
3430
|
+
error: "device_id required",
|
|
3431
|
+
status
|
|
3432
|
+
}, 400);
|
|
3433
|
+
const groupId = resolveCoordinatorAdminGroup(c.req.query("group_id"), status);
|
|
3434
|
+
if (!groupId) return c.json({
|
|
3435
|
+
error: "group_id required",
|
|
3436
|
+
status
|
|
3437
|
+
}, 400);
|
|
3438
|
+
try {
|
|
3439
|
+
if (!await coordinatorEnableDeviceAction({
|
|
3440
|
+
groupId,
|
|
3441
|
+
deviceId,
|
|
3442
|
+
remoteUrl: config.syncCoordinatorUrl || null,
|
|
3443
|
+
adminSecret: config.syncCoordinatorAdminSecret || null
|
|
3444
|
+
})) return c.json({
|
|
3445
|
+
error: "device_not_found",
|
|
3446
|
+
status
|
|
3447
|
+
}, 404);
|
|
3448
|
+
return c.json({
|
|
3449
|
+
ok: true,
|
|
3450
|
+
device_id: deviceId,
|
|
3451
|
+
status
|
|
3452
|
+
});
|
|
3453
|
+
} catch (error) {
|
|
3454
|
+
return c.json({
|
|
3455
|
+
error: error instanceof Error ? error.message : String(error),
|
|
3456
|
+
status
|
|
3457
|
+
}, 400);
|
|
3458
|
+
}
|
|
3459
|
+
});
|
|
3384
3460
|
app.post("/api/coordinator/admin/devices/:device_id/remove", async (c) => {
|
|
3385
3461
|
const config = readCoordinatorSyncConfig();
|
|
3386
3462
|
const status = coordinatorAdminStatusPayload(config);
|