@codemem/server 0.31.3 → 0.32.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 +141 -8
- package/dist/index.js.map +1 -1
- package/dist/routes/sync.d.ts.map +1 -1
- package/package.json +3 -3
- package/static/app.js +402 -128
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, LEGACY_SHARED_REVIEW_SCOPE_ID, LOCAL_DEFAULT_SCOPE_ID, LOCAL_SYNC_CAPABILITY, MemoryStore, SYNC_SCOPE_QUERY_PARAM, VERSION, VERSION as VERSION$1, addSyncScopeToBoundary, analyzeProjectScopeMappingChangeGuardrails, applyReplicationOps, buildBaseUrl, buildFilterClausesWithContext, buildRawEventEnvelopeFromHook, canonicalMemoryKind, canonicalWorkspaceIdentity, cleanupNonces, coordinatorArchiveGroupAction, coordinatorCreateGroupAction, coordinatorCreateInviteAction, coordinatorCreateScopeAction, coordinatorDisableDeviceAction, coordinatorEnableDeviceAction, coordinatorGrantScopeMembershipAction, coordinatorImportInviteAction, coordinatorListBootstrapGrantsAction, coordinatorListDevicesAction, coordinatorListGroupsAction, coordinatorListJoinRequestsAction, coordinatorListScopeMembershipsAction, coordinatorListScopesAction, coordinatorRemoveDeviceAction, coordinatorRenameDeviceAction, coordinatorRenameGroupAction, coordinatorReviewJoinRequestAction, coordinatorRevokeBootstrapGrantAction, coordinatorRevokeScopeMembershipAction, coordinatorStatusSnapshot, coordinatorUnarchiveGroupAction, coordinatorUpdateScopeAction, createCoordinatorReciprocalApproval, deleteProjectScopeSettingsMapping, ensureDeviceIdentity, extractReplicationOps, filterReplicationOpsForSyncWithStatus, fingerprintPublicKey, fromJson, getCodememConfigPath, getCodememEnvOverrides, getCoordinatorGroupPreference, getSemanticIndexDiagnostics, getSyncResetState, isSummaryLikeMemory, listCoordinatorJoinRequests, listInboundScopeRejections, listMaintenanceJobs, listObserverProviderOptions, listProjectScopeCandidates, listProjectScopeInventory, listProjectScopeSettingsMappings, listSharingDomainSettingsScopes, loadMemorySnapshotPageForPeer, loadReplicationOpsForPeer, lookupCoordinatorPeers, mergeAddresses, negotiateSyncCapability, normalizeSyncCapability, parseStrictInteger, parseSyncScopeRequest, personalScopeGrantStatusForPeer, probeAvailableCredentials, readCodememConfigFile, readCoordinatorSyncConfig, reassignProjectScopeInventoryProject, recordNonce, rejectInboundScopeFailures, requestJson, resolveDbPath, runSyncPass, schema, stripJsonComments, stripPrivateObj, stripTrailingCommas, summarizeInboundScopeRejections, syncScopeResetRequiredPayload, updatePeerAddresses, upsertCoordinatorGroupPreference, upsertProjectScopeSettingsMapping, verifySignature, writeCodememConfigFile } from "@codemem/core";
|
|
3
|
+
import { CODEMEM_CONFIG_ENV_OVERRIDES, DEFAULT_TIME_WINDOW_S, LEGACY_SHARED_REVIEW_SCOPE_ID, LOCAL_DEFAULT_SCOPE_ID, LOCAL_SYNC_CAPABILITY, MemoryStore, SYNC_SCOPE_QUERY_PARAM, VERSION, VERSION as VERSION$1, addSyncScopeToBoundary, analyzeProjectScopeMappingChangeGuardrails, applyReplicationOps, buildBaseUrl, buildFilterClausesWithContext, buildRawEventEnvelopeFromHook, canonicalMemoryKind, canonicalWorkspaceIdentity, cleanupNonces, coordinatorArchiveGroupAction, coordinatorCreateGroupAction, coordinatorCreateInviteAction, coordinatorCreateScopeAction, coordinatorDisableDeviceAction, coordinatorEnableDeviceAction, coordinatorGrantScopeMembershipAction, coordinatorImportInviteAction, coordinatorListBootstrapGrantsAction, coordinatorListDevicesAction, coordinatorListGroupsAction, coordinatorListJoinRequestsAction, coordinatorListScopeMembershipsAction, coordinatorListScopesAction, coordinatorRemoveDeviceAction, coordinatorRenameDeviceAction, coordinatorRenameGroupAction, coordinatorReviewJoinRequestAction, coordinatorRevokeBootstrapGrantAction, coordinatorRevokeScopeMembershipAction, coordinatorStatusSnapshot, coordinatorUnarchiveGroupAction, coordinatorUpdateScopeAction, createCoordinatorReciprocalApproval, defaultSpaceScopeIdForGroup, deleteProjectScopeSettingsMapping, ensureDeviceIdentity, extractReplicationOps, filterReplicationOpsForSyncWithStatus, fingerprintPublicKey, fromJson, getCodememConfigPath, getCodememEnvOverrides, getCoordinatorGroupPreference, getSemanticIndexDiagnostics, getSyncResetState, isSummaryLikeMemory, listCoordinatorJoinRequests, listInboundScopeRejections, listMaintenanceJobs, listObserverProviderOptions, listProjectScopeCandidates, listProjectScopeInventory, listProjectScopeSettingsMappings, listSharingDomainSettingsScopes, loadMemorySnapshotPageForPeer, loadReplicationOpsForPeer, lookupCoordinatorPeers, mergeAddresses, negotiateSyncCapability, normalizeSyncCapability, parseStrictInteger, parseSyncScopeRequest, personalScopeGrantStatusForPeer, probeAvailableCredentials, readCodememConfigFile, readCoordinatorSyncConfig, reassignProjectScopeInventoryProject, recordNonce, rejectInboundScopeFailures, requestJson, resolveDbPath, runSyncPass, schema, stripJsonComments, stripPrivateObj, stripTrailingCommas, summarizeInboundScopeRejections, syncScopeResetRequiredPayload, updatePeerAddresses, upsertCoordinatorGroupPreference, upsertProjectScopeSettingsMapping, 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";
|
|
@@ -1707,6 +1707,89 @@ function coordinatorAdminStatusPayload(config = readCoordinatorSyncConfig()) {
|
|
|
1707
1707
|
has_groups: hasGroups
|
|
1708
1708
|
};
|
|
1709
1709
|
}
|
|
1710
|
+
async function ensureDefaultSpaceForTeam(opts) {
|
|
1711
|
+
const coordinatorId = opts.config.syncCoordinatorUrl || null;
|
|
1712
|
+
if (!coordinatorId) throw new Error("coordinator_not_configured");
|
|
1713
|
+
const scopeId = defaultSpaceScopeIdForGroup(opts.groupId);
|
|
1714
|
+
const label = opts.displayName || opts.groupId;
|
|
1715
|
+
const scope = (await coordinatorListScopesAction({
|
|
1716
|
+
groupId: opts.groupId,
|
|
1717
|
+
includeInactive: false,
|
|
1718
|
+
remoteUrl: opts.config.syncCoordinatorUrl || null,
|
|
1719
|
+
adminSecret: opts.config.syncCoordinatorAdminSecret || null
|
|
1720
|
+
})).find((scope) => scope.scope_id === scopeId) ?? null ?? await coordinatorCreateScopeAction({
|
|
1721
|
+
groupId: opts.groupId,
|
|
1722
|
+
scopeId,
|
|
1723
|
+
label,
|
|
1724
|
+
kind: "team_default",
|
|
1725
|
+
authorityType: "coordinator",
|
|
1726
|
+
coordinatorId,
|
|
1727
|
+
membershipEpoch: 1,
|
|
1728
|
+
status: "active",
|
|
1729
|
+
remoteUrl: opts.config.syncCoordinatorUrl || null,
|
|
1730
|
+
adminSecret: opts.config.syncCoordinatorAdminSecret || null
|
|
1731
|
+
});
|
|
1732
|
+
const [deviceId] = ensureDeviceIdentity(opts.store.db);
|
|
1733
|
+
return {
|
|
1734
|
+
scope,
|
|
1735
|
+
membership: await coordinatorGrantScopeMembershipAction({
|
|
1736
|
+
groupId: opts.groupId,
|
|
1737
|
+
scopeId,
|
|
1738
|
+
deviceId,
|
|
1739
|
+
role: "admin",
|
|
1740
|
+
membershipEpoch: 1,
|
|
1741
|
+
coordinatorId,
|
|
1742
|
+
remoteUrl: opts.config.syncCoordinatorUrl || null,
|
|
1743
|
+
adminSecret: opts.config.syncCoordinatorAdminSecret || null
|
|
1744
|
+
}),
|
|
1745
|
+
preferences: upsertCoordinatorGroupPreference(opts.store.db, {
|
|
1746
|
+
coordinator_id: coordinatorId,
|
|
1747
|
+
group_id: opts.groupId,
|
|
1748
|
+
default_space_scope_id: scopeId,
|
|
1749
|
+
auto_grant_default_space_on_join: true
|
|
1750
|
+
})
|
|
1751
|
+
};
|
|
1752
|
+
}
|
|
1753
|
+
async function maybeGrantDefaultSpaceOnJoin(opts) {
|
|
1754
|
+
const coordinatorId = opts.config.syncCoordinatorUrl || null;
|
|
1755
|
+
if (!coordinatorId) return null;
|
|
1756
|
+
const preferences = getCoordinatorGroupPreference(opts.store.db, coordinatorId, opts.groupId);
|
|
1757
|
+
if (!preferences?.auto_grant_default_space_on_join) return null;
|
|
1758
|
+
const scopeId = preferences.default_space_scope_id?.trim();
|
|
1759
|
+
if (!scopeId) return null;
|
|
1760
|
+
if (scopeId !== defaultSpaceScopeIdForGroup(opts.groupId)) return null;
|
|
1761
|
+
const defaultScope = (await coordinatorListScopesAction({
|
|
1762
|
+
groupId: opts.groupId,
|
|
1763
|
+
includeInactive: false,
|
|
1764
|
+
remoteUrl: opts.config.syncCoordinatorUrl || null,
|
|
1765
|
+
adminSecret: opts.config.syncCoordinatorAdminSecret || null
|
|
1766
|
+
})).find((scope) => scope.scope_id === scopeId) ?? null;
|
|
1767
|
+
if (!defaultScope || defaultScope.kind !== "team_default") return null;
|
|
1768
|
+
return await coordinatorGrantScopeMembershipAction({
|
|
1769
|
+
groupId: opts.groupId,
|
|
1770
|
+
scopeId,
|
|
1771
|
+
deviceId: opts.deviceId,
|
|
1772
|
+
role: "member",
|
|
1773
|
+
membershipEpoch: 1,
|
|
1774
|
+
coordinatorId,
|
|
1775
|
+
remoteUrl: opts.config.syncCoordinatorUrl || null,
|
|
1776
|
+
adminSecret: opts.config.syncCoordinatorAdminSecret || null
|
|
1777
|
+
});
|
|
1778
|
+
}
|
|
1779
|
+
function removeConfiguredCoordinatorGroup(groupId) {
|
|
1780
|
+
const targetGroup = groupId.trim();
|
|
1781
|
+
if (!targetGroup) return [];
|
|
1782
|
+
const config = readCodememConfigFile();
|
|
1783
|
+
const rawGroups = config.sync_coordinator_groups;
|
|
1784
|
+
const groups = Array.isArray(rawGroups) ? rawGroups.map((group) => String(group).trim()).filter(Boolean) : typeof rawGroups === "string" ? rawGroups.split(",").map((group) => group.trim()).filter(Boolean) : typeof config.sync_coordinator_group === "string" && config.sync_coordinator_group.trim() ? [config.sync_coordinator_group.trim()] : [];
|
|
1785
|
+
const nextGroups = groups.filter((group) => group !== targetGroup);
|
|
1786
|
+
if (nextGroups.length === groups.length) return groups;
|
|
1787
|
+
config.sync_coordinator_groups = nextGroups;
|
|
1788
|
+
if (nextGroups.length) config.sync_coordinator_group = nextGroups[0];
|
|
1789
|
+
else delete config.sync_coordinator_group;
|
|
1790
|
+
writeCodememConfigFile(config);
|
|
1791
|
+
return nextGroups;
|
|
1792
|
+
}
|
|
1710
1793
|
function coordinatorAdminUnavailable(status) {
|
|
1711
1794
|
if (status.readiness === "not_configured") return {
|
|
1712
1795
|
body: {
|
|
@@ -3907,11 +3990,31 @@ function syncRoutes(getStore, getSyncRuntimeStatus) {
|
|
|
3907
3990
|
remoteUrl: config.syncCoordinatorUrl || null,
|
|
3908
3991
|
adminSecret: config.syncCoordinatorAdminSecret || null
|
|
3909
3992
|
});
|
|
3910
|
-
|
|
3911
|
-
|
|
3912
|
-
|
|
3913
|
-
|
|
3914
|
-
|
|
3993
|
+
try {
|
|
3994
|
+
const defaultSpace = await ensureDefaultSpaceForTeam({
|
|
3995
|
+
store: getStore(),
|
|
3996
|
+
config,
|
|
3997
|
+
groupId,
|
|
3998
|
+
displayName: displayName || group.display_name || null
|
|
3999
|
+
});
|
|
4000
|
+
return c.json({
|
|
4001
|
+
ok: true,
|
|
4002
|
+
group,
|
|
4003
|
+
default_space: defaultSpace,
|
|
4004
|
+
status
|
|
4005
|
+
});
|
|
4006
|
+
} catch (setupError) {
|
|
4007
|
+
return c.json({
|
|
4008
|
+
ok: true,
|
|
4009
|
+
group,
|
|
4010
|
+
default_space: null,
|
|
4011
|
+
setup_warning: {
|
|
4012
|
+
step: "default_space",
|
|
4013
|
+
error: setupError instanceof Error ? setupError.message : String(setupError)
|
|
4014
|
+
},
|
|
4015
|
+
status
|
|
4016
|
+
});
|
|
4017
|
+
}
|
|
3915
4018
|
} catch (error) {
|
|
3916
4019
|
return c.json({
|
|
3917
4020
|
error: error instanceof Error ? error.message : String(error),
|
|
@@ -3998,10 +4101,13 @@ function syncRoutes(getStore, getSyncRuntimeStatus) {
|
|
|
3998
4101
|
error: "group_not_found_or_already_archived",
|
|
3999
4102
|
status
|
|
4000
4103
|
}, 404);
|
|
4104
|
+
const groups = removeConfiguredCoordinatorGroup(groupId);
|
|
4001
4105
|
return c.json({
|
|
4002
4106
|
ok: true,
|
|
4003
4107
|
group,
|
|
4004
|
-
status
|
|
4108
|
+
status: coordinatorAdminStatusPayload(),
|
|
4109
|
+
disconnected_group_id: groupId,
|
|
4110
|
+
groups
|
|
4005
4111
|
});
|
|
4006
4112
|
} catch (error) {
|
|
4007
4113
|
return c.json({
|
|
@@ -4470,9 +4576,26 @@ function syncRoutes(getStore, getSyncRuntimeStatus) {
|
|
|
4470
4576
|
error: "join request not found",
|
|
4471
4577
|
status
|
|
4472
4578
|
}, 404);
|
|
4579
|
+
let defaultSpaceMembership = null;
|
|
4580
|
+
let setupWarning = null;
|
|
4581
|
+
try {
|
|
4582
|
+
defaultSpaceMembership = await maybeGrantDefaultSpaceOnJoin({
|
|
4583
|
+
store: getStore(),
|
|
4584
|
+
config,
|
|
4585
|
+
groupId: result.group_id,
|
|
4586
|
+
deviceId: result.device_id
|
|
4587
|
+
});
|
|
4588
|
+
} catch (grantError) {
|
|
4589
|
+
setupWarning = {
|
|
4590
|
+
step: "default_space_grant",
|
|
4591
|
+
error: grantError instanceof Error ? grantError.message : String(grantError)
|
|
4592
|
+
};
|
|
4593
|
+
}
|
|
4473
4594
|
return c.json({
|
|
4474
4595
|
ok: true,
|
|
4475
4596
|
request: result,
|
|
4597
|
+
default_space_membership: defaultSpaceMembership,
|
|
4598
|
+
setup_warning: setupWarning,
|
|
4476
4599
|
status
|
|
4477
4600
|
});
|
|
4478
4601
|
} catch (error) {
|
|
@@ -4842,6 +4965,8 @@ function syncRoutes(getStore, getSyncRuntimeStatus) {
|
|
|
4842
4965
|
projects_include: null,
|
|
4843
4966
|
projects_exclude: null,
|
|
4844
4967
|
auto_seed_scope: true,
|
|
4968
|
+
default_space_scope_id: null,
|
|
4969
|
+
auto_grant_default_space_on_join: false,
|
|
4845
4970
|
updated_at: null
|
|
4846
4971
|
},
|
|
4847
4972
|
status
|
|
@@ -4880,6 +5005,12 @@ function syncRoutes(getStore, getSyncRuntimeStatus) {
|
|
|
4880
5005
|
return cleaned.length === 0 ? null : cleaned;
|
|
4881
5006
|
};
|
|
4882
5007
|
const autoSeed = typeof body.auto_seed_scope === "boolean" ? body.auto_seed_scope : void 0;
|
|
5008
|
+
const autoGrantDefaultSpace = typeof body.auto_grant_default_space_on_join === "boolean" ? body.auto_grant_default_space_on_join : void 0;
|
|
5009
|
+
const defaultSpaceScopeId = body.default_space_scope_id === void 0 ? void 0 : optionalViewerString(body, "default_space_scope_id");
|
|
5010
|
+
if (autoGrantDefaultSpace === true && !defaultSpaceScopeId) return c.json({
|
|
5011
|
+
error: "default_space_scope_id_required_for_auto_grant",
|
|
5012
|
+
status
|
|
5013
|
+
}, 400);
|
|
4883
5014
|
const store = getStore();
|
|
4884
5015
|
try {
|
|
4885
5016
|
const preferences = upsertCoordinatorGroupPreference(store.db, {
|
|
@@ -4887,7 +5018,9 @@ function syncRoutes(getStore, getSyncRuntimeStatus) {
|
|
|
4887
5018
|
group_id: groupId,
|
|
4888
5019
|
projects_include: normalizeList(body.projects_include),
|
|
4889
5020
|
projects_exclude: normalizeList(body.projects_exclude),
|
|
4890
|
-
auto_seed_scope: autoSeed
|
|
5021
|
+
auto_seed_scope: autoSeed,
|
|
5022
|
+
default_space_scope_id: defaultSpaceScopeId,
|
|
5023
|
+
auto_grant_default_space_on_join: autoGrantDefaultSpace
|
|
4891
5024
|
});
|
|
4892
5025
|
return c.json({
|
|
4893
5026
|
preferences,
|