@codemem/server 0.46.0-rc.1 → 0.46.0-rc.3
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 +149 -15
- package/dist/index.js.map +1 -1
- package/dist/routes/device-rename.d.ts +77 -0
- package/dist/routes/device-rename.d.ts.map +1 -0
- package/dist/routes/diagnostics.d.ts +1 -1
- package/dist/routes/diagnostics.d.ts.map +1 -1
- package/dist/routes/sync.d.ts.map +1 -1
- package/package.json +2 -2
- package/static/app.js +28 -28
- package/static/app.js.br +0 -0
- package/static/app.js.gz +0 -0
- package/static/index.html +33 -1
package/dist/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { existsSync, readFileSync } from "node:fs";
|
|
2
2
|
import { dirname, isAbsolute, join, posix, resolve, win32 } from "node:path";
|
|
3
|
-
import { ACCESS_CLEANUP_OP_TYPE, CodememConfigMutationError, CoordinatorReciprocalApprovalRequestChangedError, DEFAULT_TIME_WINDOW_S, LEGACY_SHARED_REVIEW_SCOPE_ID, LOCAL_DEFAULT_SCOPE_ID, LOCAL_SYNC_CAPABILITY, LOCAL_SYNC_FEATURES, LegacyTeamSetupAdditiveConvergenceError, LegacyTeamSetupRosterCapacityError, MEMORY_FILTER_FIELD_TYPES, MEMORY_FILTER_NAMES, MEMORY_KIND_DESCRIPTIONS, MemoryStore, ObserverClient, PROMPT_TRANSPORT_PROTOCOL_RANGE, REMEMBER_MEMORY_KINDS, RawEventIngestValidationError, RecipientPolicyEdgeRequestError, RecipientPolicyTeamRenameError, RemoteCoordinatorRequestError, SCOPE_MEMBERSHIP_REVOCATION_LIMITATION, SYNC_AUTHORIZATION_REFRESH_HEADER, SYNC_CAPABILITY_HEADER, SYNC_FEATURES_HEADER, SYNC_SCOPE_QUERY_PARAM, VERSION, VERSION as VERSION$1, VIEWER_IDENTITY_TARGET_KEYS, VIEWER_SERVICE_DISCRIMINATOR, addSyncScopeToBoundary, analyzeProjectScopeMappingChangeGuardrails, analyzeProjectScopeMappingChangesGuardrails, analyzeProjectScopeMappingDeletionGuardrails, applyLegacyTeamSetupCompletionManifest, applyLegacyTeamSetupCompletionManifestAndReturnActivation, applyReplicationOps, areLegacyTeamSetupCompletionPolicyFactsAdditivelyCompatible, automaticRecallHealth, buildAuthHeaders, buildBaseUrl, buildDirectPeerAuthHeaders, buildDistillReport, buildFilterClausesWithContext, buildPiFlushSignalFromEvent, buildRawEventEnvelopeFromCodexHook, buildRawEventEnvelopeFromHook, buildRawEventEnvelopeFromPiEvent, buildViewerIdentityTarget, canonicalCoordinatorLegacyTeamCompletionManifestJson, canonicalMemoryKind, canonicalRepositoryProjectIdentity, canonicalWorkspaceIdentity, claimRecipientPolicyActorMutations, claimRecipientPolicyPublicationMutation, cleanupNonces, clearLegacyTeamSetupDeviceDecision, clonePromptPackAttempt, coerceObserverCommand, commitDeviceIdentityBindings, commitRecipientPolicyEdges, containLegacyTeamSetupCompletionConflict, coordinatorArchiveGroupAction, coordinatorCreateAddDeviceInviteAction, coordinatorCreateGroupAction, coordinatorCreateInviteAction, coordinatorCreateLegacyTeamCompletionAction, coordinatorCreateScopeAction, coordinatorDisableDeviceAction, coordinatorEnableDeviceAction, coordinatorGetLegacyTeamCompletionAction, coordinatorGrantScopeMembershipAction, coordinatorImportInviteAction, coordinatorListBootstrapGrantsAction, coordinatorListConsumedTeamInvitesAction, coordinatorListDevicesAction, coordinatorListGroupsAction, coordinatorListJoinRequestsAction, coordinatorListLegacyTeamCompletionsAction, coordinatorListReviewedRecipientInviteEvidenceAction, coordinatorListScopeMembershipsAction, coordinatorListScopesAction, coordinatorRemoveDeviceAction, coordinatorRenameDeviceAction, coordinatorRenameGroupAction, coordinatorReviewJoinRequestAction, coordinatorRevokeBootstrapGrantAction, coordinatorRevokeScopeMembershipAction, coordinatorStatusSnapshot, coordinatorUnarchiveGroupAction, coordinatorUpdateScopeAction, countShareableProjectMemories, createCoordinatorReciprocalApproval, decodeInvitePayload, dedupeOrderedIds, defaultSpaceScopeIdForGroup, deleteProjectScopeSettingsMapping, deriveLegacyTeamSetupCompletionManifest, detectInstallKind, deterministicPolicyTeamId, diagnoseStalePeerReceivedRows, discoverLegacyTeamCandidates, ensureDeviceIdentity, executeShareProvisioning, extractInvitePayload, extractReplicationOps, filterReplicationOpsForSyncWithStatus, fingerprintPublicKey, formatHostPort, friendlyDeviceName, fromJson, getCodememConfigPath, getCodememEnvOverrideValues, getCodememEnvOverrides, getCoordinatorEnrollmentReconciliationIssueSummary, getCoordinatorGroupPreference, getLegacyTeamSetupDraft, getRecipientPolicyAuthorityState, getSemanticIndexDiagnostics, getSyncResetState, getUpdateStatus, ingestRawEvents, inspectFreshLegacyTeamSetupActivation, inspectLegacyTeamSetupActivation, inviteTokenDigest, isAutomaticRecallMeasurement, isLegacyTeamCandidateSelectable, isLegacyTeamSetupProjectMappingIdentity, isPeerTrustBindingCompatible, isProjectSyncEnablementError, isScopedSyncCapability, judgeDistillReport, legacyTeamCandidateId, legacyTeamCandidateProjectInventory, legacyTeamCanonicalProjectRef, legacyTeamDeviceRef, legacyTeamResolvedProjectRef, legacyTeamSetupApiErrorCode, listAuthorizedScopesForPeer, listCoordinatorJoinRequests, listDeviceIdentityInventory, listInboundScopeRejections, listLegacyRecipientPolicyProjections, listMaintenanceJobs, listObserverProviderOptions, listPerPeerScopeSyncState, listProjectScopeCandidates, listProjectScopeInventory, listProjectScopeSettingsMappings, listRecipientPolicyIntent, listRecipientPolicyReview, listSharingDomainSettingsScopes, loadMemorySnapshotPageForPeer, loadReplicationOpsForPeer, lookupCoordinatorPeers, memoryFilterValueMatchesType, mergeAddresses, migrateRecipientPolicyIntent, mutateCodememConfigFile, negotiateSyncCapability, normalizeAddress, normalizeHumanPresentationName, normalizeSyncCapability, normalizeSyncFeatures, normalizeTeammateName, parseAcceptedProjectIntent, parsePositiveMemoryId, parseReassignScopePayload, parseRecipientPolicyEdgeCommitRequest, parseStrictInteger, parseSyncScopeRequest, persistShareOperation, personalScopeGrantStatusForPeer, planShareOperation, previewDeviceIdentityBindings, previewLegacyTeamSetupActivation, previewRecipientPolicyEdges, previewRecipientPolicyOnboarding, previewRecipientPolicyOnboardingFromReviewedIntent, probeAvailableCredentials, projectMatchesFilter, projectShareLifecycle, promptPackArtifactFingerprint, readCodememConfigFile, readCoordinatorSyncConfig, reassignProjectScopeInventoryProject, recipientInviteAuthoritativeIdentityId, recipientPolicyDigest, recipientReviewedIntentDigest, reconcileCoordinatorEnrollmentSnapshot, reconcileRecipientPolicyProject, reconcileShareOperationAcceptance, reconstructLegacyTeamSetupCompletionManifest, recordAutomaticRecall, recordHighestObservedDirectSignatureVersion, recordNonce, recordPromptPackArtifacts, recordPromptPackTerminal, refreshAuthorizedCoordinatorPeerTrust, refreshConfiguredScopeMembershipCache, refreshLegacyTeamCandidate, rejectInboundScopeFailures, renameRecipientPolicyTeam, replayLegacyTeamSetupActivation, repositoryIdentitiesByWorkspace, repositoryIdentityForWorkspace, requestJson, requireLegacyTeamSetupAccessDeltaWithinLimit, resolveDbPath, resolveObserverRuntime, resolveProject, resolveProjectRoot, resolveRecipientPolicyReview, resolveRecipientPolicyReviewBulk, runSyncPass, schema, serializeRecipientPolicyCoordinatorGroupMutation, serializeRecipientPolicyPublicationMutation, serializeRecipientPolicyTeamMutation, setLegacyTeamSetupDeviceAssignment, setLegacyTeamSetupDeviceDecision, setLegacyTeamSetupProjectMapping, storeVectors, summarizeInboundScopeRejections, summaryLikeSqlPredicate, supportsSyncFeature, syncScopeResetRequiredPayload, toJson, tryUpdateRetrievalDelivery, updatePeerAddresses, upsertCoordinatorGroupPreference, upsertProjectScopeSettingsMappings, validateLegacyTeamSetupCompletionManifest, validateLegacyTeamSetupCompletionManifestBinding, validateRawEvents, verifyDirectPeerSignature, verifyRecipientReviewedIntent, verifySignature, wakeRecipientPoliciesForIdentities, wakeRecipientPoliciesForProjectIdentities } from "@codemem/core";
|
|
3
|
+
import { ACCESS_CLEANUP_OP_TYPE, CodememConfigMutationError, CoordinatorReciprocalApprovalRequestChangedError, DEFAULT_TIME_WINDOW_S, LEGACY_SHARED_REVIEW_SCOPE_ID, LOCAL_DEFAULT_SCOPE_ID, LOCAL_SYNC_CAPABILITY, LOCAL_SYNC_FEATURES, LegacyTeamSetupAdditiveConvergenceError, LegacyTeamSetupRosterCapacityError, MEMORY_FILTER_FIELD_TYPES, MEMORY_FILTER_NAMES, MEMORY_KIND_DESCRIPTIONS, MemoryStore, ObserverClient, PROMPT_TRANSPORT_PROTOCOL_RANGE, REMEMBER_MEMORY_KINDS, RawEventIngestValidationError, RecipientPolicyEdgeRequestError, RecipientPolicyTeamRenameError, RemoteCoordinatorRequestError, SCOPE_MEMBERSHIP_REVOCATION_LIMITATION, SYNC_AUTHORIZATION_REFRESH_HEADER, SYNC_CAPABILITY_HEADER, SYNC_FEATURES_HEADER, SYNC_SCOPE_QUERY_PARAM, VERSION, VERSION as VERSION$1, VIEWER_IDENTITY_TARGET_KEYS, VIEWER_SERVICE_DISCRIMINATOR, addSyncScopeToBoundary, analyzeProjectScopeMappingChangeGuardrails, analyzeProjectScopeMappingChangesGuardrails, analyzeProjectScopeMappingDeletionGuardrails, applyLegacyTeamSetupCompletionManifest, applyLegacyTeamSetupCompletionManifestAndReturnActivation, applyReplicationOps, areLegacyTeamSetupCompletionPolicyFactsAdditivelyCompatible, automaticRecallHealth, buildAuthHeaders, buildBaseUrl, buildDirectPeerAuthHeaders, buildDistillReport, buildFilterClausesWithContext, buildPiFlushSignalFromEvent, buildRawEventEnvelopeFromCodexHook, buildRawEventEnvelopeFromHook, buildRawEventEnvelopeFromPiEvent, buildViewerIdentityTarget, canonicalCoordinatorLegacyTeamCompletionManifestJson, canonicalMemoryKind, canonicalRepositoryProjectIdentity, canonicalWorkspaceIdentity, claimRecipientPolicyActorMutations, claimRecipientPolicyPublicationMutation, classifyRecordedSyncFailure, cleanupNonces, clearLegacyTeamSetupDeviceDecision, clonePromptPackAttempt, coerceObserverCommand, commitDeviceIdentityBindings, commitRecipientPolicyEdges, containLegacyTeamSetupCompletionConflict, coordinatorArchiveGroupAction, coordinatorCreateAddDeviceInviteAction, coordinatorCreateGroupAction, coordinatorCreateInviteAction, coordinatorCreateLegacyTeamCompletionAction, coordinatorCreateScopeAction, coordinatorDisableDeviceAction, coordinatorEnableDeviceAction, coordinatorGetLegacyTeamCompletionAction, coordinatorGrantScopeMembershipAction, coordinatorImportInviteAction, coordinatorListBootstrapGrantsAction, coordinatorListConsumedTeamInvitesAction, coordinatorListDevicesAction, coordinatorListGroupsAction, coordinatorListJoinRequestsAction, coordinatorListLegacyTeamCompletionsAction, coordinatorListReviewedRecipientInviteEvidenceAction, coordinatorListScopeMembershipsAction, coordinatorListScopesAction, coordinatorRemoveDeviceAction, coordinatorRenameDeviceAction, coordinatorRenameGroupAction, coordinatorReviewJoinRequestAction, coordinatorRevokeBootstrapGrantAction, coordinatorRevokeScopeMembershipAction, coordinatorStatusSnapshot, coordinatorUnarchiveGroupAction, coordinatorUpdateScopeAction, countShareableProjectMemories, createCoordinatorReciprocalApproval, decodeInvitePayload, dedupeOrderedIds, defaultSpaceScopeIdForGroup, deleteProjectScopeSettingsMapping, deriveLegacyTeamSetupCompletionManifest, detectInstallKind, deterministicPolicyTeamId, diagnoseStalePeerReceivedRows, discoverLegacyTeamCandidates, ensureDeviceIdentity, executeShareProvisioning, extractInvitePayload, extractReplicationOps, filterReplicationOpsForSyncWithStatus, fingerprintPublicKey, formatHostPort, friendlyDeviceName, fromJson, getCodememConfigPath, getCodememEnvOverrideValues, getCodememEnvOverrides, getCoordinatorEnrollmentReconciliationIssueSummary, getCoordinatorGroupPreference, getLegacyTeamSetupDraft, getRecipientPolicyAuthorityState, getSemanticIndexDiagnostics, getSyncResetState, getUpdateStatus, ingestRawEvents, inspectFreshLegacyTeamSetupActivation, inspectLegacyTeamSetupActivation, inviteTokenDigest, isAutomaticRecallMeasurement, isLegacyTeamCandidateSelectable, isLegacyTeamSetupProjectMappingIdentity, isPeerTrustBindingCompatible, isProjectSyncEnablementError, isScopedSyncCapability, judgeDistillReport, legacyTeamCandidateId, legacyTeamCandidateProjectInventory, legacyTeamCanonicalProjectRef, legacyTeamDeviceRef, legacyTeamResolvedProjectRef, legacyTeamSetupApiErrorCode, listAuthorizedScopesForPeer, listCoordinatorJoinRequests, listDeviceIdentityInventory, listInboundScopeRejections, listLegacyRecipientPolicyProjections, listMaintenanceJobs, listObserverProviderOptions, listPerPeerScopeSyncState, listProjectScopeCandidates, listProjectScopeInventory, listProjectScopeSettingsMappings, listRecipientPolicyIntent, listRecipientPolicyReview, listSharingDomainSettingsScopes, loadMemorySnapshotPageForPeer, loadReplicationOpsForPeer, lookupCoordinatorPeers, memoryFilterValueMatchesType, mergeAddresses, migrateRecipientPolicyIntent, mutateCodememConfigFile, negotiateSyncCapability, normalizeAddress, normalizeHumanPresentationName, normalizeSyncCapability, normalizeSyncFeatures, normalizeTeammateName, parseAcceptedProjectIntent, parsePositiveMemoryId, parseReassignScopePayload, parseRecipientPolicyEdgeCommitRequest, parseStrictInteger, parseSyncScopeRequest, persistShareOperation, personalScopeGrantStatusForPeer, planShareOperation, previewDeviceIdentityBindings, previewLegacyTeamSetupActivation, previewRecipientPolicyEdges, previewRecipientPolicyOnboarding, previewRecipientPolicyOnboardingFromReviewedIntent, probeAvailableCredentials, projectMatchesFilter, projectShareLifecycle, promptPackArtifactFingerprint, readCodememConfigFile, readCoordinatorSyncConfig, reassignProjectScopeInventoryProject, recipientInviteAuthoritativeIdentityId, recipientPolicyDigest, recipientReviewedIntentDigest, reconcileCoordinatorEnrollmentSnapshot, reconcileRecipientPolicyProject, reconcileShareOperationAcceptance, reconstructLegacyTeamSetupCompletionManifest, recordAutomaticRecall, recordHighestObservedDirectSignatureVersion, recordNonce, recordPromptPackArtifacts, recordPromptPackTerminal, refreshAuthorizedCoordinatorPeerTrust, refreshConfiguredScopeMembershipCache, refreshLegacyTeamCandidate, rejectInboundScopeFailures, renameRecipientPolicyTeam, replayLegacyTeamSetupActivation, repositoryIdentitiesByWorkspace, repositoryIdentityForWorkspace, requestJson, requireLegacyTeamSetupAccessDeltaWithinLimit, resolveDbPath, resolveObserverRuntime, resolveProject, resolveProjectRoot, resolveRecipientPolicyReview, resolveRecipientPolicyReviewBulk, runSyncPass, schema, serializeRecipientPolicyCoordinatorGroupMutation, serializeRecipientPolicyPublicationMutation, serializeRecipientPolicyTeamMutation, setLegacyTeamSetupDeviceAssignment, setLegacyTeamSetupDeviceDecision, setLegacyTeamSetupProjectMapping, storeVectors, summarizeInboundScopeRejections, summaryLikeSqlPredicate, supportsSyncFeature, syncScopeResetRequiredPayload, toJson, tryUpdateRetrievalDelivery, updatePeerAddresses, upsertCoordinatorGroupPreference, upsertProjectScopeSettingsMappings, validateLegacyTeamSetupCompletionManifest, validateLegacyTeamSetupCompletionManifestBinding, validateRawEvents, verifyDirectPeerSignature, verifyRecipientReviewedIntent, verifySignature, wakeRecipientPoliciesForIdentities, wakeRecipientPoliciesForProjectIdentities } 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";
|
|
@@ -671,14 +671,9 @@ function syncSelect(options) {
|
|
|
671
671
|
${SYNC_OCCURRED_AT_SQL} AS occurred_at,
|
|
672
672
|
CASE WHEN ok <> 0 THEN 'succeeded' ELSE 'failed' END AS status,
|
|
673
673
|
ops_in AS metric_a, ops_out AS metric_b,
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
WHEN lower(error) LIKE '%version%' OR lower(error) LIKE '%capability%' THEN 'compatibility'
|
|
678
|
-
WHEN lower(error) LIKE '%connect%' OR lower(error) LIKE '%network%'
|
|
679
|
-
OR lower(error) LIKE '%dns%' THEN 'connectivity'
|
|
680
|
-
ELSE 'unspecified'
|
|
681
|
-
END AS category
|
|
674
|
+
-- Raw error text; syncEvent classifies it server-side and never returns it.
|
|
675
|
+
error AS category,
|
|
676
|
+
failure_category AS stored_category
|
|
682
677
|
FROM sync_attempts ${predicates.length ? `WHERE ${predicates.join(" AND ")}` : ""}
|
|
683
678
|
ORDER BY ${SYNC_OCCURRED_AT_SQL} DESC, id DESC
|
|
684
679
|
LIMIT @sourceLimit`;
|
|
@@ -712,7 +707,8 @@ function observerSelect(options) {
|
|
|
712
707
|
WHEN lower(COALESCE(observer_error_code, error_type)) LIKE '%schema%'
|
|
713
708
|
OR lower(COALESCE(observer_error_code, error_type)) LIKE '%parse%' THEN 'response format'
|
|
714
709
|
ELSE 'unspecified'
|
|
715
|
-
END AS category
|
|
710
|
+
END AS category,
|
|
711
|
+
NULL AS stored_category
|
|
716
712
|
FROM raw_event_flush_batches
|
|
717
713
|
WHERE status = '${status}' ${providerFilter} ${cursorFilter}
|
|
718
714
|
ORDER BY updated_at DESC, id DESC
|
|
@@ -729,7 +725,7 @@ function maintenanceSelect(options) {
|
|
|
729
725
|
return `SELECT 'maintenance' AS source_type, kind AS source_id,
|
|
730
726
|
'm:' || hex(kind) AS order_key, updated_at AS occurred_at,
|
|
731
727
|
status, progress_current AS metric_a, progress_total AS metric_b,
|
|
732
|
-
NULL AS category
|
|
728
|
+
NULL AS category, NULL AS stored_category
|
|
733
729
|
FROM maintenance_jobs WHERE status IN (${statuses.join(", ")})`;
|
|
734
730
|
}
|
|
735
731
|
function backlogSelect(options) {
|
|
@@ -763,7 +759,8 @@ function backlogSelect(options) {
|
|
|
763
759
|
'b:' || printf('%020d', 0) AS order_key, occurred_at,
|
|
764
760
|
CASE WHEN pending >= 1000 THEN 'error' ELSE 'warning' END AS status,
|
|
765
761
|
pending AS metric_a, sessions AS metric_b,
|
|
766
|
-
CASE WHEN candidate_count > 1000 THEN 'capped' ELSE NULL END AS category
|
|
762
|
+
CASE WHEN candidate_count > 1000 THEN 'capped' ELSE NULL END AS category,
|
|
763
|
+
NULL AS stored_category
|
|
767
764
|
FROM (
|
|
768
765
|
SELECT MAX(updated_at) AS occurred_at,
|
|
769
766
|
SUM(pending) AS pending,
|
|
@@ -805,11 +802,28 @@ function loadSourceRows(store, options) {
|
|
|
805
802
|
ORDER BY occurred_at DESC, order_key DESC
|
|
806
803
|
LIMIT @resultLimit`).all(params);
|
|
807
804
|
}
|
|
805
|
+
var SYNC_FAILURE_MESSAGES = {
|
|
806
|
+
connectivity: "Sync could not reach a paired device, or the device did not respond in time.",
|
|
807
|
+
trust: "Sync stopped because the pairing or identity check between two devices failed.",
|
|
808
|
+
scope: "Sync stopped because two devices disagree about access to a shared Space.",
|
|
809
|
+
compatibility: "Sync stopped because two devices run incompatible Codemem versions."
|
|
810
|
+
};
|
|
811
|
+
var SPECIFIC_STORED_SYNC_CATEGORIES = /* @__PURE__ */ new Set([
|
|
812
|
+
"trust",
|
|
813
|
+
"scope",
|
|
814
|
+
"connectivity",
|
|
815
|
+
"compatibility"
|
|
816
|
+
]);
|
|
817
|
+
function syncFailureCategory(row) {
|
|
818
|
+
const stored = row.stored_category;
|
|
819
|
+
if (stored && SPECIFIC_STORED_SYNC_CATEGORIES.has(stored)) return stored;
|
|
820
|
+
return classifyRecordedSyncFailure(row.category);
|
|
821
|
+
}
|
|
808
822
|
function syncEvent(row, includeTechnical) {
|
|
809
823
|
const succeeded = row.status === "succeeded";
|
|
810
824
|
const opsIn = Number(row.metric_a ?? 0);
|
|
811
825
|
const opsOut = Number(row.metric_b ?? 0);
|
|
812
|
-
const category =
|
|
826
|
+
const category = succeeded ? "other" : syncFailureCategory(row);
|
|
813
827
|
return {
|
|
814
828
|
id: opaqueId("sync-attempt", row.source_id),
|
|
815
829
|
orderKey: row.order_key,
|
|
@@ -817,7 +831,7 @@ function syncEvent(row, includeTechnical) {
|
|
|
817
831
|
severity: succeeded ? "info" : "error",
|
|
818
832
|
subsystem: "sync",
|
|
819
833
|
code: succeeded ? "sync_attempt_succeeded" : "sync_attempt_failed",
|
|
820
|
-
message: succeeded ? "A sync attempt completed." : "A sync attempt failed before all work completed.",
|
|
834
|
+
message: succeeded ? "A sync attempt completed." : SYNC_FAILURE_MESSAGES[category] ?? "A sync attempt failed before all work completed.",
|
|
821
835
|
recovery: succeeded ? void 0 : {
|
|
822
836
|
label: "Open advanced sync diagnostics",
|
|
823
837
|
href: "#advanced/sync/diagnostics"
|
|
@@ -4496,6 +4510,126 @@ function snapshotPageRequest(query, localDeviceId) {
|
|
|
4496
4510
|
};
|
|
4497
4511
|
}
|
|
4498
4512
|
//#endregion
|
|
4513
|
+
//#region src/routes/device-rename.ts
|
|
4514
|
+
async function enrolledGroups(config, deviceId) {
|
|
4515
|
+
const remoteUrl = config.syncCoordinatorUrl || null;
|
|
4516
|
+
const adminSecret = config.syncCoordinatorAdminSecret || null;
|
|
4517
|
+
if (!remoteUrl || !adminSecret) throw new Error("coordinator_unavailable");
|
|
4518
|
+
const groups = await coordinatorListGroupsAction({
|
|
4519
|
+
remoteUrl,
|
|
4520
|
+
adminSecret
|
|
4521
|
+
});
|
|
4522
|
+
if (groups.length > 25) throw new Error("coordinator_evidence_too_large");
|
|
4523
|
+
const devices = (await Promise.all(groups.map((group) => coordinatorListDevicesAction({
|
|
4524
|
+
groupId: group.group_id,
|
|
4525
|
+
includeDisabled: true,
|
|
4526
|
+
remoteUrl,
|
|
4527
|
+
adminSecret
|
|
4528
|
+
})))).flat();
|
|
4529
|
+
if (devices.length > 500) throw new Error("coordinator_evidence_too_large");
|
|
4530
|
+
const matches = devices.filter((device) => device.device_id === deviceId);
|
|
4531
|
+
if (new Set(matches.map((device) => `${device.public_key}:${device.fingerprint}`)).size > 1) throw new Error("device_enrollment_conflict");
|
|
4532
|
+
return [...new Set(matches.map((device) => device.group_id))].sort();
|
|
4533
|
+
}
|
|
4534
|
+
async function renameEnrolledGroups(config, groups, deviceId, name) {
|
|
4535
|
+
let renamed = 0;
|
|
4536
|
+
for (const groupId of groups) try {
|
|
4537
|
+
if (!await coordinatorRenameDeviceAction({
|
|
4538
|
+
groupId,
|
|
4539
|
+
deviceId,
|
|
4540
|
+
displayName: name,
|
|
4541
|
+
remoteUrl: config.syncCoordinatorUrl || null,
|
|
4542
|
+
adminSecret: config.syncCoordinatorAdminSecret || null
|
|
4543
|
+
})) break;
|
|
4544
|
+
renamed += 1;
|
|
4545
|
+
} catch {
|
|
4546
|
+
break;
|
|
4547
|
+
}
|
|
4548
|
+
return renamed;
|
|
4549
|
+
}
|
|
4550
|
+
async function renameDevice(store, deviceId, name, provenance) {
|
|
4551
|
+
const config = readCoordinatorSyncConfig();
|
|
4552
|
+
if (provenance === "coordinator_enrollment" && !config.syncCoordinatorUrl) return {
|
|
4553
|
+
ok: false,
|
|
4554
|
+
error: "coordinator_device_names_unavailable",
|
|
4555
|
+
status: 503
|
|
4556
|
+
};
|
|
4557
|
+
let groups = [];
|
|
4558
|
+
if (config.syncCoordinatorUrl) {
|
|
4559
|
+
try {
|
|
4560
|
+
groups = await enrolledGroups(config, deviceId);
|
|
4561
|
+
} catch (error) {
|
|
4562
|
+
if (error instanceof Error && error.message === "device_enrollment_conflict") return {
|
|
4563
|
+
ok: false,
|
|
4564
|
+
error: "device_enrollment_conflict",
|
|
4565
|
+
status: 409
|
|
4566
|
+
};
|
|
4567
|
+
return {
|
|
4568
|
+
ok: false,
|
|
4569
|
+
error: "coordinator_device_names_unavailable",
|
|
4570
|
+
status: 503
|
|
4571
|
+
};
|
|
4572
|
+
}
|
|
4573
|
+
if (provenance === "coordinator_enrollment" && groups.length === 0) return {
|
|
4574
|
+
ok: false,
|
|
4575
|
+
error: "device_enrollment_unavailable",
|
|
4576
|
+
status: 409
|
|
4577
|
+
};
|
|
4578
|
+
}
|
|
4579
|
+
const renamedGroupCount = await renameEnrolledGroups(config, groups, deviceId, name);
|
|
4580
|
+
if (renamedGroupCount !== groups.length) return {
|
|
4581
|
+
ok: false,
|
|
4582
|
+
error: "coordinator_device_rename_incomplete",
|
|
4583
|
+
status: 503,
|
|
4584
|
+
renamedGroupCount
|
|
4585
|
+
};
|
|
4586
|
+
if (!store.db.transaction(() => {
|
|
4587
|
+
const result = store.db.prepare("UPDATE identity_devices SET display_name = ?, updated_at = ? WHERE device_id = ? AND status = 'active'").run(name, (/* @__PURE__ */ new Date()).toISOString(), deviceId);
|
|
4588
|
+
if (result.changes) store.db.prepare("UPDATE sync_peers SET name = ? WHERE peer_device_id = ?").run(name, deviceId);
|
|
4589
|
+
return result.changes;
|
|
4590
|
+
})()) return {
|
|
4591
|
+
ok: false,
|
|
4592
|
+
error: "device_not_found",
|
|
4593
|
+
status: 409
|
|
4594
|
+
};
|
|
4595
|
+
return {
|
|
4596
|
+
ok: true,
|
|
4597
|
+
display_name: name
|
|
4598
|
+
};
|
|
4599
|
+
}
|
|
4600
|
+
function deviceRenameRoutes(getStore) {
|
|
4601
|
+
const pendingDevices = /* @__PURE__ */ new Set();
|
|
4602
|
+
return new Hono().post("/api/sync/recipient-policy/v1/devices/:device_id/rename", async (c) => {
|
|
4603
|
+
const store = getStore();
|
|
4604
|
+
const deviceId = String(c.req.param("device_id") ?? "").trim();
|
|
4605
|
+
const binding = store.db.prepare("SELECT provenance FROM identity_devices WHERE device_id = ? AND status = 'active'").get(deviceId);
|
|
4606
|
+
if (!binding) return c.json({ error: "device_not_found" }, 404);
|
|
4607
|
+
let body;
|
|
4608
|
+
try {
|
|
4609
|
+
body = await c.req.json();
|
|
4610
|
+
} catch {
|
|
4611
|
+
return c.json({ error: "invalid_json" }, 400);
|
|
4612
|
+
}
|
|
4613
|
+
let name;
|
|
4614
|
+
try {
|
|
4615
|
+
name = normalizeHumanPresentationName(String(body.display_name ?? ""), "display_name");
|
|
4616
|
+
} catch {
|
|
4617
|
+
return c.json({ error: "display_name_invalid" }, 400);
|
|
4618
|
+
}
|
|
4619
|
+
if (pendingDevices.has(deviceId)) return c.json({ error: "device_rename_busy" }, 409);
|
|
4620
|
+
pendingDevices.add(deviceId);
|
|
4621
|
+
try {
|
|
4622
|
+
const result = await renameDevice(store, deviceId, name, binding.provenance);
|
|
4623
|
+
if (!result.ok) return c.json(result, result.status);
|
|
4624
|
+
return c.json(result);
|
|
4625
|
+
} catch {
|
|
4626
|
+
return c.json({ error: "device_rename_failed" }, 503);
|
|
4627
|
+
} finally {
|
|
4628
|
+
pendingDevices.delete(deviceId);
|
|
4629
|
+
}
|
|
4630
|
+
});
|
|
4631
|
+
}
|
|
4632
|
+
//#endregion
|
|
4499
4633
|
//#region src/routes/team-setup-view.ts
|
|
4500
4634
|
var enabled = {
|
|
4501
4635
|
enabled: true,
|
|
@@ -10008,7 +10142,7 @@ function syncRoutes(getStore, getSyncRuntimeStatus, options = {}) {
|
|
|
10008
10142
|
localDeviceId: store.deviceId
|
|
10009
10143
|
}));
|
|
10010
10144
|
});
|
|
10011
|
-
app.get("/api/sync/recipient-policy/v1/intent", (c) => {
|
|
10145
|
+
app.route("/", deviceRenameRoutes(getStore)).get("/api/sync/recipient-policy/v1/intent", (c) => {
|
|
10012
10146
|
const store = getStore();
|
|
10013
10147
|
return c.json(listRecipientPolicyIntent(store.db));
|
|
10014
10148
|
});
|