@codemem/server 0.44.0-alpha.1 → 0.44.0-beta.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.
- package/dist/index.js +177 -9
- package/dist/index.js.map +1 -1
- package/dist/routes/team-setup-view.d.ts +2 -1
- package/dist/routes/team-setup-view.d.ts.map +1 -1
- package/dist/routes/team-setup.d.ts +20 -1
- package/dist/routes/team-setup.d.ts.map +1 -1
- package/package.json +2 -2
- package/static/app.js +25 -25
- package/static/app.js.br +0 -0
- package/static/app.js.gz +0 -0
- package/static/index.html +3 -3
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, CODEMEM_CONFIG_ENV_OVERRIDES, CoordinatorReciprocalApprovalRequestChangedError, DEFAULT_TIME_WINDOW_S, LEGACY_SHARED_REVIEW_SCOPE_ID, LOCAL_DEFAULT_SCOPE_ID, LOCAL_SYNC_CAPABILITY, LOCAL_SYNC_FEATURES, LegacyTeamSetupAdditiveConvergenceError, MemoryStore, PROMPT_TRANSPORT_PROTOCOL_RANGE, RawEventIngestValidationError, RecipientPolicyEdgeRequestError, RecipientPolicyTeamRenameError, 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, applyLegacyTeamSetupCompletionManifest, applyLegacyTeamSetupCompletionManifestAndReturnActivation, applyReplicationOps, areLegacyTeamSetupCompletionPolicyFactsAdditivelyCompatible, buildAuthHeaders, buildBaseUrl, buildDirectPeerAuthHeaders, buildFilterClausesWithContext, buildRawEventEnvelopeFromCodexHook, buildRawEventEnvelopeFromHook, buildViewerIdentityTarget, canonicalCoordinatorLegacyTeamCompletionManifestJson, canonicalMemoryKind, 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, defaultSpaceScopeIdForGroup, deleteProjectScopeSettingsMapping, deriveLegacyTeamSetupCompletionManifest, detectInstallKind, deterministicPolicyTeamId, diagnoseStalePeerReceivedRows, discoverLegacyTeamCandidates, ensureDeviceIdentity, executeShareProvisioning, extractInvitePayload, extractReplicationOps, filterReplicationOpsForSyncWithStatus, fingerprintPublicKey, formatHostPort, friendlyDeviceName, fromJson, getCodememConfigPath, getCodememEnvOverrides, getCoordinatorEnrollmentReconciliationIssueSummary, getCoordinatorGroupPreference, getLegacyTeamSetupDraft, getRecipientPolicyAuthorityState, getSemanticIndexDiagnostics, getSyncResetState, getUpdateStatus, ingestRawEvents, inspectFreshLegacyTeamSetupActivation, inspectLegacyTeamSetupActivation, inviteTokenDigest, isLegacyTeamCandidateSelectable, isLegacyTeamSetupProjectMappingIdentity, isPeerTrustBindingCompatible, isProjectSyncEnablementError, isScopedSyncCapability, legacyTeamCandidateId, legacyTeamCandidateProjectInventory, legacyTeamCanonicalProjectRef, legacyTeamDeviceRef, legacyTeamResolvedProjectRef, legacyTeamSetupApiErrorCode, listAuthorizedScopesForPeer, listCoordinatorJoinRequests, listDeviceIdentityInventory, listInboundScopeRejections, listLegacyRecipientPolicyProjections, listMaintenanceJobs, listObserverProviderOptions, listPerPeerScopeSyncState, listProjectScopeCandidates, listProjectScopeInventory, listProjectScopeSettingsMappings, listRecipientPolicyIntent, listRecipientPolicyReview, listSharingDomainSettingsScopes, loadMemorySnapshotPageForPeer, loadReplicationOpsForPeer, lookupCoordinatorPeers, mergeAddresses, migrateRecipientPolicyIntent, negotiateSyncCapability, normalizeAddress, normalizeHumanPresentationName, normalizeSyncCapability, normalizeSyncFeatures, normalizeTeammateName, parseAcceptedProjectIntent, parsePositiveMemoryId, parseReassignScopePayload, parseRecipientPolicyEdgeCommitRequest, parseStrictInteger, parseSyncScopeRequest, persistShareOperation, personalScopeGrantStatusForPeer, planShareOperation, previewDeviceIdentityBindings, previewLegacyTeamSetupActivation, previewRecipientPolicyEdges, previewRecipientPolicyOnboarding, previewRecipientPolicyOnboardingFromReviewedIntent, probeAvailableCredentials, projectShareLifecycle, promptPackArtifactFingerprint, readCodememConfigFile, readCoordinatorSyncConfig, reassignProjectScopeInventoryProject, recipientInviteAuthoritativeIdentityId, recipientPolicyDigest, recipientReviewedIntentDigest, reconcileCoordinatorEnrollmentSnapshot, reconcileRecipientPolicyProject, reconcileShareOperationAcceptance, reconstructLegacyTeamSetupCompletionManifest, recordHighestObservedDirectSignatureVersion, recordNonce, recordPromptPackArtifacts, recordPromptPackTerminal, refreshAuthorizedCoordinatorPeerTrust, refreshConfiguredScopeMembershipCache, refreshLegacyTeamCandidate, rejectInboundScopeFailures, renameRecipientPolicyTeam, replayLegacyTeamSetupActivation, requestJson, requireLegacyTeamSetupAccessDeltaWithinLimit, resolveDbPath, resolveProject, resolveRecipientPolicyReview, resolveRecipientPolicyReviewBulk, runSyncPass, schema, serializeRecipientPolicyCoordinatorGroupMutation, serializeRecipientPolicyPublicationMutation, serializeRecipientPolicyTeamMutation, setLegacyTeamSetupDeviceAssignment, setLegacyTeamSetupDeviceDecision, setLegacyTeamSetupProjectMapping, summarizeInboundScopeRejections, supportsSyncFeature, syncScopeResetRequiredPayload, tryUpdateRetrievalDelivery, updatePeerAddresses, upsertCoordinatorGroupPreference, upsertProjectScopeSettingsMapping, validateLegacyTeamSetupCompletionManifest, validateLegacyTeamSetupCompletionManifestBinding, verifyDirectPeerSignature, verifyRecipientReviewedIntent, verifySignature, writeCodememConfigFile } from "@codemem/core";
|
|
3
|
+
import { ACCESS_CLEANUP_OP_TYPE, CODEMEM_CONFIG_ENV_OVERRIDES, CoordinatorReciprocalApprovalRequestChangedError, DEFAULT_TIME_WINDOW_S, LEGACY_SHARED_REVIEW_SCOPE_ID, LOCAL_DEFAULT_SCOPE_ID, LOCAL_SYNC_CAPABILITY, LOCAL_SYNC_FEATURES, LegacyTeamSetupAdditiveConvergenceError, LegacyTeamSetupRosterCapacityError, MemoryStore, PROMPT_TRANSPORT_PROTOCOL_RANGE, 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, applyLegacyTeamSetupCompletionManifest, applyLegacyTeamSetupCompletionManifestAndReturnActivation, applyReplicationOps, areLegacyTeamSetupCompletionPolicyFactsAdditivelyCompatible, buildAuthHeaders, buildBaseUrl, buildDirectPeerAuthHeaders, buildFilterClausesWithContext, buildRawEventEnvelopeFromCodexHook, buildRawEventEnvelopeFromHook, buildViewerIdentityTarget, canonicalCoordinatorLegacyTeamCompletionManifestJson, canonicalMemoryKind, 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, defaultSpaceScopeIdForGroup, deleteProjectScopeSettingsMapping, deriveLegacyTeamSetupCompletionManifest, detectInstallKind, deterministicPolicyTeamId, diagnoseStalePeerReceivedRows, discoverLegacyTeamCandidates, ensureDeviceIdentity, executeShareProvisioning, extractInvitePayload, extractReplicationOps, filterReplicationOpsForSyncWithStatus, fingerprintPublicKey, formatHostPort, friendlyDeviceName, fromJson, getCodememConfigPath, getCodememEnvOverrides, getCoordinatorEnrollmentReconciliationIssueSummary, getCoordinatorGroupPreference, getLegacyTeamSetupDraft, getRecipientPolicyAuthorityState, getSemanticIndexDiagnostics, getSyncResetState, getUpdateStatus, ingestRawEvents, inspectFreshLegacyTeamSetupActivation, inspectLegacyTeamSetupActivation, inviteTokenDigest, isLegacyTeamCandidateSelectable, isLegacyTeamSetupProjectMappingIdentity, isPeerTrustBindingCompatible, isProjectSyncEnablementError, isScopedSyncCapability, legacyTeamCandidateId, legacyTeamCandidateProjectInventory, legacyTeamCanonicalProjectRef, legacyTeamDeviceRef, legacyTeamResolvedProjectRef, legacyTeamSetupApiErrorCode, listAuthorizedScopesForPeer, listCoordinatorJoinRequests, listDeviceIdentityInventory, listInboundScopeRejections, listLegacyRecipientPolicyProjections, listMaintenanceJobs, listObserverProviderOptions, listPerPeerScopeSyncState, listProjectScopeCandidates, listProjectScopeInventory, listProjectScopeSettingsMappings, listRecipientPolicyIntent, listRecipientPolicyReview, listSharingDomainSettingsScopes, loadMemorySnapshotPageForPeer, loadReplicationOpsForPeer, lookupCoordinatorPeers, mergeAddresses, migrateRecipientPolicyIntent, negotiateSyncCapability, normalizeAddress, normalizeHumanPresentationName, normalizeSyncCapability, normalizeSyncFeatures, normalizeTeammateName, parseAcceptedProjectIntent, parsePositiveMemoryId, parseReassignScopePayload, parseRecipientPolicyEdgeCommitRequest, parseStrictInteger, parseSyncScopeRequest, persistShareOperation, personalScopeGrantStatusForPeer, planShareOperation, previewDeviceIdentityBindings, previewLegacyTeamSetupActivation, previewRecipientPolicyEdges, previewRecipientPolicyOnboarding, previewRecipientPolicyOnboardingFromReviewedIntent, probeAvailableCredentials, projectShareLifecycle, promptPackArtifactFingerprint, readCodememConfigFile, readCoordinatorSyncConfig, reassignProjectScopeInventoryProject, recipientInviteAuthoritativeIdentityId, recipientPolicyDigest, recipientReviewedIntentDigest, reconcileCoordinatorEnrollmentSnapshot, reconcileRecipientPolicyProject, reconcileShareOperationAcceptance, reconstructLegacyTeamSetupCompletionManifest, recordHighestObservedDirectSignatureVersion, recordNonce, recordPromptPackArtifacts, recordPromptPackTerminal, refreshAuthorizedCoordinatorPeerTrust, refreshConfiguredScopeMembershipCache, refreshLegacyTeamCandidate, rejectInboundScopeFailures, renameRecipientPolicyTeam, replayLegacyTeamSetupActivation, requestJson, requireLegacyTeamSetupAccessDeltaWithinLimit, resolveDbPath, resolveProject, resolveRecipientPolicyReview, resolveRecipientPolicyReviewBulk, runSyncPass, schema, serializeRecipientPolicyCoordinatorGroupMutation, serializeRecipientPolicyPublicationMutation, serializeRecipientPolicyTeamMutation, setLegacyTeamSetupDeviceAssignment, setLegacyTeamSetupDeviceDecision, setLegacyTeamSetupProjectMapping, summarizeInboundScopeRejections, supportsSyncFeature, syncScopeResetRequiredPayload, tryUpdateRetrievalDelivery, updatePeerAddresses, upsertCoordinatorGroupPreference, upsertProjectScopeSettingsMapping, validateLegacyTeamSetupCompletionManifest, validateLegacyTeamSetupCompletionManifestBinding, verifyDirectPeerSignature, verifyRecipientReviewedIntent, 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";
|
|
@@ -2922,10 +2922,10 @@ function projectMappingChoices(store) {
|
|
|
2922
2922
|
excludePeerReceived: true
|
|
2923
2923
|
}).filter((candidate) => !candidate.read_only && isLegacyTeamSetupProjectMappingIdentity(candidate.workspace_identity, store.db));
|
|
2924
2924
|
} catch (error) {
|
|
2925
|
-
if (error instanceof Error && (error.message === "project_scope_candidate_scan_too_large" || error.message === "project_scope_candidate_metadata_too_large")) throw new
|
|
2925
|
+
if (error instanceof Error && (error.message === "project_scope_candidate_scan_too_large" || error.message === "project_scope_candidate_metadata_too_large")) throw new LocalProjectScanBudgetError(error);
|
|
2926
2926
|
throw error;
|
|
2927
2927
|
}
|
|
2928
|
-
if (candidates.length > MAX_PROJECT_MAPPING_CHOICES) throw new
|
|
2928
|
+
if (candidates.length > MAX_PROJECT_MAPPING_CHOICES) throw new LocalProjectScanBudgetError();
|
|
2929
2929
|
return candidates.map((candidate) => ({
|
|
2930
2930
|
projectIdentity: candidate.workspace_identity,
|
|
2931
2931
|
sourceDisplayName: candidate.display_project
|
|
@@ -3001,6 +3001,156 @@ function completionApiError(error) {
|
|
|
3001
3001
|
const code = legacyTeamSetupApiErrorCode(error);
|
|
3002
3002
|
return code === "team_setup_failed" ? "team_setup_completion_unavailable" : code;
|
|
3003
3003
|
}
|
|
3004
|
+
var TeamSetupFinishError = class extends Error {
|
|
3005
|
+
reason;
|
|
3006
|
+
alreadyLogged;
|
|
3007
|
+
constructor(code, reason, alreadyLogged, cause) {
|
|
3008
|
+
super(code, cause === void 0 ? void 0 : { cause });
|
|
3009
|
+
this.reason = reason;
|
|
3010
|
+
this.alreadyLogged = alreadyLogged;
|
|
3011
|
+
this.name = "TeamSetupFinishError";
|
|
3012
|
+
}
|
|
3013
|
+
};
|
|
3014
|
+
/**
|
|
3015
|
+
* The generic `legacy_team_setup_roster_too_large` string is thrown by ten
|
|
3016
|
+
* sites for unrelated limits (coordinator roster size, draft device count,
|
|
3017
|
+
* local project choices). Only the local project-candidate scan is a
|
|
3018
|
+
* "this device's history is too large" condition, so it carries a distinct
|
|
3019
|
+
* type. The message is kept identical so the frozen API-code mapping and every
|
|
3020
|
+
* existing caller that matches on it are unchanged.
|
|
3021
|
+
*/
|
|
3022
|
+
var LocalProjectScanBudgetError = class extends Error {
|
|
3023
|
+
constructor(cause) {
|
|
3024
|
+
super("legacy_team_setup_roster_too_large", cause === void 0 ? void 0 : { cause });
|
|
3025
|
+
this.name = "LocalProjectScanBudgetError";
|
|
3026
|
+
}
|
|
3027
|
+
};
|
|
3028
|
+
/**
|
|
3029
|
+
* Remote error codes the finish path can legitimately receive from the
|
|
3030
|
+
* coordinator. Anything else — including identifier-shaped values, which a
|
|
3031
|
+
* hostile or misconfigured upstream could use to smuggle a credential through
|
|
3032
|
+
* a JSON `error` field — is reduced to a fixed classification before logging.
|
|
3033
|
+
* A shape check is not an allowlist; only this set is echoed verbatim.
|
|
3034
|
+
*/
|
|
3035
|
+
var LOGGABLE_REMOTE_ERROR_CODES = /* @__PURE__ */ new Set([
|
|
3036
|
+
"body_too_large",
|
|
3037
|
+
"completion_manifest_invalid",
|
|
3038
|
+
"completion_manifest_unavailable",
|
|
3039
|
+
"completion_not_found",
|
|
3040
|
+
"completion_query_invalid",
|
|
3041
|
+
"group_archived",
|
|
3042
|
+
"group_id_and_candidate_ref_required",
|
|
3043
|
+
"group_not_found",
|
|
3044
|
+
"invalid_json",
|
|
3045
|
+
"missing_admin_header",
|
|
3046
|
+
"not_found",
|
|
3047
|
+
"rate_limited",
|
|
3048
|
+
"response_too_large",
|
|
3049
|
+
"unauthorized"
|
|
3050
|
+
]);
|
|
3051
|
+
function loggableRemoteCode(code) {
|
|
3052
|
+
if (LOGGABLE_REMOTE_ERROR_CODES.has(code)) return code;
|
|
3053
|
+
if (code.startsWith("non_json_response")) return "non_json_response";
|
|
3054
|
+
return "unclassified_remote_error";
|
|
3055
|
+
}
|
|
3056
|
+
/**
|
|
3057
|
+
* Local causes the finish path can produce. Same allowlist discipline as
|
|
3058
|
+
* remote codes: everything else, including transport messages that embed the
|
|
3059
|
+
* target URL, is classified rather than echoed.
|
|
3060
|
+
*/
|
|
3061
|
+
var LOGGABLE_LOCAL_CAUSES = /* @__PURE__ */ new Set([
|
|
3062
|
+
"completion_conflict",
|
|
3063
|
+
"legacy_team_setup_roster_too_large",
|
|
3064
|
+
"project_scope_candidate_metadata_too_large",
|
|
3065
|
+
"project_scope_candidate_scan_too_large",
|
|
3066
|
+
"team_setup_completion_conflict",
|
|
3067
|
+
"team_setup_completion_invalid",
|
|
3068
|
+
"team_setup_completion_unavailable",
|
|
3069
|
+
"team_setup_confirmation_stale",
|
|
3070
|
+
"team_setup_roster_unavailable"
|
|
3071
|
+
]);
|
|
3072
|
+
function loggableLocalCause(error) {
|
|
3073
|
+
if (LOGGABLE_LOCAL_CAUSES.has(error.message)) return error.message;
|
|
3074
|
+
if (error.name === "AbortError" || error.name === "TimeoutError") return error.name;
|
|
3075
|
+
if (/fetch failed/iu.test(error.message)) return "fetch_failed";
|
|
3076
|
+
if (/timed out|timeout/iu.test(error.message)) return "timed_out";
|
|
3077
|
+
return `unclassified_error:${error.name || "Error"}`;
|
|
3078
|
+
}
|
|
3079
|
+
function errorChain(error) {
|
|
3080
|
+
const chain = [];
|
|
3081
|
+
let current = error;
|
|
3082
|
+
while (current && !chain.includes(current)) {
|
|
3083
|
+
chain.push(current);
|
|
3084
|
+
current = current instanceof Error ? current.cause : void 0;
|
|
3085
|
+
}
|
|
3086
|
+
return chain;
|
|
3087
|
+
}
|
|
3088
|
+
function remoteFailureReason(remote, fallback) {
|
|
3089
|
+
if (remote.status === 404 && (remote.code === "not_found" || remote.code.startsWith("non_json"))) return "coordinator_route_missing";
|
|
3090
|
+
if (remote.status === 400 && remote.code === "completion_manifest_invalid") return "coordinator_rejected_manifest";
|
|
3091
|
+
return fallback;
|
|
3092
|
+
}
|
|
3093
|
+
function teamSetupFinishFailureDetails(error) {
|
|
3094
|
+
const chain = errorChain(error);
|
|
3095
|
+
const wrapper = chain.find((item) => item instanceof TeamSetupFinishError);
|
|
3096
|
+
const remote = chain.find((item) => item instanceof RemoteCoordinatorRequestError);
|
|
3097
|
+
if (remote) {
|
|
3098
|
+
const reason = remoteFailureReason(remote, wrapper?.reason);
|
|
3099
|
+
return {
|
|
3100
|
+
...reason ? { reason } : {},
|
|
3101
|
+
cause: "remote coordinator request failed",
|
|
3102
|
+
status: remote.status,
|
|
3103
|
+
code: loggableRemoteCode(remote.code)
|
|
3104
|
+
};
|
|
3105
|
+
}
|
|
3106
|
+
if (chain.some((item) => item instanceof LegacyTeamSetupRosterCapacityError || item instanceof LocalProjectScanBudgetError)) return {
|
|
3107
|
+
reason: "local_candidate_scan_budget_exceeded",
|
|
3108
|
+
cause: "local project candidate scan exceeded budget"
|
|
3109
|
+
};
|
|
3110
|
+
const errorCause = chain.find((item) => item instanceof Error && !(item instanceof TeamSetupFinishError));
|
|
3111
|
+
const cause = errorCause ? loggableLocalCause(errorCause) : "unclassified_non_error";
|
|
3112
|
+
if (wrapper?.reason) return {
|
|
3113
|
+
reason: wrapper.reason,
|
|
3114
|
+
cause
|
|
3115
|
+
};
|
|
3116
|
+
if (errorCause && (errorCause.name === "AbortError" || errorCause.name === "TimeoutError" || /fetch failed|timed out|timeout/iu.test(errorCause.message))) return {
|
|
3117
|
+
reason: "coordinator_unreachable",
|
|
3118
|
+
cause
|
|
3119
|
+
};
|
|
3120
|
+
return { cause };
|
|
3121
|
+
}
|
|
3122
|
+
function warnTeamSetupFinishFailure(error, details, context) {
|
|
3123
|
+
if (errorChain(error).some((item) => item instanceof TeamSetupFinishError && item.alreadyLogged)) return;
|
|
3124
|
+
const safe = (value) => {
|
|
3125
|
+
let sanitized = String(value).replace(/[\r\n\t]+/gu, " ");
|
|
3126
|
+
for (const secret of context.redactValues ?? []) if (secret) sanitized = sanitized.replaceAll(secret, "[redacted]");
|
|
3127
|
+
return sanitized.replace(/https?:\/\/[^\s]+/giu, (value) => {
|
|
3128
|
+
try {
|
|
3129
|
+
const url = new URL(value);
|
|
3130
|
+
return `${url.protocol}//${url.host}`;
|
|
3131
|
+
} catch {
|
|
3132
|
+
return "[redacted-url]";
|
|
3133
|
+
}
|
|
3134
|
+
});
|
|
3135
|
+
};
|
|
3136
|
+
const fields = [
|
|
3137
|
+
`candidateRef=${safe(context.candidateRef)}`,
|
|
3138
|
+
`attemptId=${safe(context.attemptId)}`,
|
|
3139
|
+
`apiCode=${safe(context.apiCode)}`,
|
|
3140
|
+
`cause=${safe(details.cause)}`,
|
|
3141
|
+
...details.reason ? [`reason=${safe(details.reason)}`] : [],
|
|
3142
|
+
...details.status == null ? [] : [`status=${safe(details.status)}`],
|
|
3143
|
+
...details.code == null ? [] : [`code=${safe(details.code)}`]
|
|
3144
|
+
];
|
|
3145
|
+
console.warn(`[team-setup finish] ${fields.join(" ")}`);
|
|
3146
|
+
}
|
|
3147
|
+
function finishErrorResponse(code, details) {
|
|
3148
|
+
const reason = details.reason;
|
|
3149
|
+
return reason ? {
|
|
3150
|
+
error: code,
|
|
3151
|
+
reason
|
|
3152
|
+
} : { error: code };
|
|
3153
|
+
}
|
|
3004
3154
|
async function parseBoundedJsonObject(c) {
|
|
3005
3155
|
if (c.req.header("content-type")?.split(";", 1)[0]?.trim().toLowerCase() !== "application/json") return { ok: false };
|
|
3006
3156
|
const lengthHeader = c.req.header("content-length");
|
|
@@ -3741,6 +3891,7 @@ function teamSetupRoutes(options) {
|
|
|
3741
3891
|
let releaseMutation;
|
|
3742
3892
|
let releasePublicationMutation;
|
|
3743
3893
|
let releaseActorMutations;
|
|
3894
|
+
let finishLogRedactValues = [];
|
|
3744
3895
|
try {
|
|
3745
3896
|
const store = options.getStore();
|
|
3746
3897
|
const draft = getLegacyTeamSetupDraft(store.db, candidateRef);
|
|
@@ -3803,8 +3954,9 @@ function teamSetupRoutes(options) {
|
|
|
3803
3954
|
if (!completionDependencies || !authorization) throw new Error("team_setup_completion_unavailable");
|
|
3804
3955
|
if (!authorizesGroup(authorization, group)) throw new Error("team_setup_completion_invalid");
|
|
3805
3956
|
const { config, remoteUrl } = authorization;
|
|
3957
|
+
finishLogRedactValues = [config.syncCoordinatorAdminSecret];
|
|
3806
3958
|
const freshGroup = await loadFreshGroupSnapshot(group, remoteUrl, publicationDeadlineMs);
|
|
3807
|
-
if (!freshGroup) throw new
|
|
3959
|
+
if (!freshGroup) throw new TeamSetupFinishError("team_setup_roster_unavailable", "coordinator_roster_unavailable", false, /* @__PURE__ */ new Error("coordinator roster unavailable"));
|
|
3808
3960
|
if (!stillAuthorizesGroup(authorization, group)) throw new Error("team_setup_completion_invalid");
|
|
3809
3961
|
const projectInventory = legacyTeamCandidateProjectInventory(store.db, projectionOptions(store), candidateRef);
|
|
3810
3962
|
const freshPreview = inspectFreshLegacyTeamSetupActivation(store.db, {
|
|
@@ -3845,8 +3997,17 @@ function teamSetupRoutes(options) {
|
|
|
3845
3997
|
if (canonicalCoordinatorLegacyTeamCompletionManifestJson(canonicalManifest) !== canonicalCoordinatorLegacyTeamCompletionManifestJson(proposedManifest)) throw new Error("team_setup_completion_conflict");
|
|
3846
3998
|
} catch (error) {
|
|
3847
3999
|
const code = completionApiError(error);
|
|
4000
|
+
const details = teamSetupFinishFailureDetails(error);
|
|
3848
4001
|
const getCompletion = completionDependencies.get;
|
|
3849
|
-
if (code !== "team_setup_completion_conflict" || !getCompletion)
|
|
4002
|
+
if (code !== "team_setup_completion_conflict" || !getCompletion) {
|
|
4003
|
+
warnTeamSetupFinishFailure(error, details, {
|
|
4004
|
+
candidateRef,
|
|
4005
|
+
attemptId,
|
|
4006
|
+
apiCode: code,
|
|
4007
|
+
redactValues: finishLogRedactValues
|
|
4008
|
+
});
|
|
4009
|
+
throw new TeamSetupFinishError(code, details.reason, true, error);
|
|
4010
|
+
}
|
|
3850
4011
|
try {
|
|
3851
4012
|
const existing = await retryTransientCoordinatorRead((attemptTimeoutS) => getCompletion({
|
|
3852
4013
|
groupId: group.groupId,
|
|
@@ -3862,17 +4023,17 @@ function teamSetupRoutes(options) {
|
|
|
3862
4023
|
});
|
|
3863
4024
|
if (canonicalManifest.finish_digest !== proposedManifest.finish_digest) throw new Error("team_setup_completion_conflict");
|
|
3864
4025
|
} catch (recoveryError) {
|
|
3865
|
-
throw new
|
|
4026
|
+
throw new TeamSetupFinishError(completionApiError(recoveryError), teamSetupFinishFailureDetails(recoveryError).reason, false, recoveryError);
|
|
3866
4027
|
}
|
|
3867
4028
|
}
|
|
3868
4029
|
let postPublicationGroup;
|
|
3869
4030
|
try {
|
|
3870
4031
|
postPublicationGroup = await loadFreshGroupSnapshot(group, remoteUrl, publicationDeadlineMs);
|
|
3871
4032
|
} catch (error) {
|
|
3872
|
-
if (legacyTeamSetupApiErrorCode(error) === "team_setup_completion_invalid") throw new
|
|
4033
|
+
if (legacyTeamSetupApiErrorCode(error) === "team_setup_completion_invalid") throw new TeamSetupFinishError("team_setup_roster_unavailable", "coordinator_roster_unavailable", false, error);
|
|
3873
4034
|
throw error;
|
|
3874
4035
|
}
|
|
3875
|
-
if (!postPublicationGroup) throw new
|
|
4036
|
+
if (!postPublicationGroup) throw new TeamSetupFinishError("team_setup_roster_unavailable", "coordinator_roster_unavailable", false, /* @__PURE__ */ new Error("coordinator roster unavailable"));
|
|
3876
4037
|
const result = await applyLegacyTeamSetupCompletionManifestAndReturnActivation(store.db, {
|
|
3877
4038
|
coordinatorId: group.coordinatorId,
|
|
3878
4039
|
groupId: group.groupId,
|
|
@@ -3889,7 +4050,14 @@ function teamSetupRoutes(options) {
|
|
|
3889
4050
|
}));
|
|
3890
4051
|
} catch (error) {
|
|
3891
4052
|
const code = apiErrorCode(error);
|
|
3892
|
-
|
|
4053
|
+
const details = teamSetupFinishFailureDetails(error);
|
|
4054
|
+
warnTeamSetupFinishFailure(error, details, {
|
|
4055
|
+
candidateRef,
|
|
4056
|
+
attemptId,
|
|
4057
|
+
apiCode: code,
|
|
4058
|
+
redactValues: finishLogRedactValues
|
|
4059
|
+
});
|
|
4060
|
+
return c.json(finishErrorResponse(code, details), errorStatus$1(code));
|
|
3893
4061
|
} finally {
|
|
3894
4062
|
releaseActorMutations?.();
|
|
3895
4063
|
releasePublicationMutation?.();
|