@ricsam/r5d-worker 0.0.93 → 0.0.95
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/cjs/main.cjs +171 -33
- package/dist/cjs/package.json +1 -1
- package/dist/cjs/project-mirror-fetch-policy.cjs +41 -0
- package/dist/cjs/project-mirror-refs-token.cjs +51 -0
- package/dist/cjs/project-worktrees.cjs +158 -49
- package/dist/mjs/main.mjs +172 -33
- package/dist/mjs/package.json +1 -1
- package/dist/mjs/project-mirror-fetch-policy.mjs +16 -0
- package/dist/mjs/project-mirror-refs-token.mjs +24 -0
- package/dist/mjs/project-worktrees.mjs +162 -49
- package/dist/types/main.d.ts +9 -0
- package/dist/types/project-mirror-fetch-policy.d.ts +29 -0
- package/dist/types/project-mirror-refs-token.d.ts +19 -0
- package/dist/types/project-worktrees.d.ts +30 -1
- package/package.json +1 -1
package/dist/mjs/main.mjs
CHANGED
|
@@ -58,6 +58,7 @@ import { assertDisjointManagedRoots, managedProjectRoot, validateManagedBranchNa
|
|
|
58
58
|
import {
|
|
59
59
|
applyObservedProjectMirrorHeads,
|
|
60
60
|
assertProjectMirrorHeadsPushed,
|
|
61
|
+
computeLocalProjectMirrorRefsToken,
|
|
61
62
|
createOrRetryLinkedProjectBranch,
|
|
62
63
|
deleteLinkedProjectBranch,
|
|
63
64
|
deleteProjectMirrorBranch,
|
|
@@ -70,6 +71,7 @@ import {
|
|
|
70
71
|
pushProjectMirrorHeads,
|
|
71
72
|
removeProjectWorktrees
|
|
72
73
|
} from "./project-worktrees.mjs";
|
|
74
|
+
import { projectMirrorFetchDecision } from "./project-mirror-fetch-policy.mjs";
|
|
73
75
|
import {
|
|
74
76
|
PROJECT_SNAPSHOT_RECOVERY_HELPER_COMMAND,
|
|
75
77
|
recoverProjectSnapshotsInChild,
|
|
@@ -119,6 +121,7 @@ const DEFAULT_READ_MAX_BYTES = 5e4;
|
|
|
119
121
|
const MAX_LINE_LENGTH = 2e3;
|
|
120
122
|
const WORKSPACE_GIT_QUIET_MS = 5e3;
|
|
121
123
|
const WORKSPACE_GIT_PERIODIC_MS = 6e4;
|
|
124
|
+
const PROJECT_MIRROR_OBSERVE_CONCURRENCY = 6;
|
|
122
125
|
const WORKSPACE_INCIDENT_CONFIG_REFRESH_TIMEOUT_MS = 6e4;
|
|
123
126
|
const PTY_INPUT_BUSY_GRACE_MS = 3e3;
|
|
124
127
|
const PTY_FOREGROUND_POLL_MS = 1e3;
|
|
@@ -1009,6 +1012,21 @@ function resolveWorkerFilePath(branchPath, inputPath, builtInPaths) {
|
|
|
1009
1012
|
function canonicalProjectRemoteUrl(baseUrl, projectId) {
|
|
1010
1013
|
return new URL(`/git/${projectId}.git`, baseUrl).toString();
|
|
1011
1014
|
}
|
|
1015
|
+
async function mapWithConcurrencyLimit(items, limit, task) {
|
|
1016
|
+
const results = new Array(items.length);
|
|
1017
|
+
let nextIndex = 0;
|
|
1018
|
+
await Promise.all(
|
|
1019
|
+
Array.from({ length: Math.max(1, Math.min(limit, items.length)) }, async () => {
|
|
1020
|
+
while (true) {
|
|
1021
|
+
const index = nextIndex;
|
|
1022
|
+
nextIndex += 1;
|
|
1023
|
+
if (index >= items.length) return;
|
|
1024
|
+
results[index] = await task(items[index], index);
|
|
1025
|
+
}
|
|
1026
|
+
})
|
|
1027
|
+
);
|
|
1028
|
+
return results;
|
|
1029
|
+
}
|
|
1012
1030
|
function shellQuote(value) {
|
|
1013
1031
|
return `'${value.replace(/'/g, "'\\''")}'`;
|
|
1014
1032
|
}
|
|
@@ -3468,6 +3486,10 @@ async function startWorker(options) {
|
|
|
3468
3486
|
const readyProjectIds = /* @__PURE__ */ new Set();
|
|
3469
3487
|
const reconciledProjectConfigFingerprints = /* @__PURE__ */ new Map();
|
|
3470
3488
|
const lastObservedProjectHeads = /* @__PURE__ */ new Map();
|
|
3489
|
+
const advertisedProjectMirrorRefsTokens = /* @__PURE__ */ new Map();
|
|
3490
|
+
const fetchedProjectMirrorRefsTokens = /* @__PURE__ */ new Map();
|
|
3491
|
+
const lastProjectMirrorFetchAtMs = /* @__PURE__ */ new Map();
|
|
3492
|
+
const projectMirrorFetchSkippingEnabled = process.env.R5D_PROJECT_MIRROR_FETCH_SKIP !== "0";
|
|
3471
3493
|
const pendingMirrorDeletes = /* @__PURE__ */ new Map();
|
|
3472
3494
|
let workspaceRemoteUrl = null;
|
|
3473
3495
|
let workspaceCredentialHelper = null;
|
|
@@ -3485,6 +3507,7 @@ async function startWorker(options) {
|
|
|
3485
3507
|
let automaticSyncInFlight = false;
|
|
3486
3508
|
let terminalReplayTimer;
|
|
3487
3509
|
let workspaceSyncRequestsInFlight = 0;
|
|
3510
|
+
let lastWorkspaceSyncMirrorObservationMs = 0;
|
|
3488
3511
|
let sessionArtifactSyncRequestsInFlight = 0;
|
|
3489
3512
|
let cliUpdateInProgress = false;
|
|
3490
3513
|
let reloadAfterClose = false;
|
|
@@ -4073,7 +4096,7 @@ async function startWorker(options) {
|
|
|
4073
4096
|
}
|
|
4074
4097
|
return heads;
|
|
4075
4098
|
};
|
|
4076
|
-
const pushChangedProjectHeads = async (activeMountIds, publishedHead, publicationHeads, suppressedMountIds = /* @__PURE__ */ new Set()) => {
|
|
4099
|
+
const pushChangedProjectHeads = async (activeMountIds, publishedHead, publicationHeads, expectedMirrorHeads, suppressedMountIds = /* @__PURE__ */ new Set()) => {
|
|
4077
4100
|
const active = new Set(activeMountIds);
|
|
4078
4101
|
for (const project of projectConfigById.values()) {
|
|
4079
4102
|
if (!readyProjectIds.has(project.projectId) || !repositoryMirrorWritesAllowed(project)) continue;
|
|
@@ -4088,6 +4111,12 @@ async function startWorker(options) {
|
|
|
4088
4111
|
}
|
|
4089
4112
|
}
|
|
4090
4113
|
if (changed.size === 0) continue;
|
|
4114
|
+
const branchLeases = /* @__PURE__ */ new Map();
|
|
4115
|
+
for (const branchName of changed.keys()) {
|
|
4116
|
+
const mountId = projectMountId(project.projectId, branchName);
|
|
4117
|
+
if (!expectedMirrorHeads.has(mountId)) throw new Error(`Missing observed hidden-mirror lease for active project mount ${mountId}`);
|
|
4118
|
+
branchLeases.set(branchName, expectedMirrorHeads.get(mountId) ?? null);
|
|
4119
|
+
}
|
|
4091
4120
|
const connection = projectConnection(project);
|
|
4092
4121
|
const results = await pushProjectMirrorHeads({
|
|
4093
4122
|
projectRoot: configuredProjectRoot(projectsRoot, project),
|
|
@@ -4096,12 +4125,25 @@ async function startWorker(options) {
|
|
|
4096
4125
|
credentialHelper: connection.credentialHelper,
|
|
4097
4126
|
credentialUsername: connection.mirrorCredentialUsername,
|
|
4098
4127
|
onlyBranches: new Set(changed.keys()),
|
|
4099
|
-
publicationHeads: changed
|
|
4128
|
+
publicationHeads: changed,
|
|
4129
|
+
expectedMirrorHeads: branchLeases,
|
|
4130
|
+
branchIds: new Map(project.branches.map(({ branchId, branchName }) => [branchName, branchId]))
|
|
4100
4131
|
});
|
|
4101
4132
|
assertProjectMirrorHeadsPushed(results);
|
|
4102
4133
|
for (const result of results) {
|
|
4103
4134
|
lastObservedProjectHeads.set(projectBranchKey(project.projectId, result.branchName), result.head);
|
|
4104
4135
|
}
|
|
4136
|
+
try {
|
|
4137
|
+
fetchedProjectMirrorRefsTokens.set(
|
|
4138
|
+
project.projectId,
|
|
4139
|
+
await computeLocalProjectMirrorRefsToken({
|
|
4140
|
+
projectRoot: configuredProjectRoot(projectsRoot, project),
|
|
4141
|
+
primaryBranchName: primaryProjectBranch(project)
|
|
4142
|
+
})
|
|
4143
|
+
);
|
|
4144
|
+
} catch {
|
|
4145
|
+
fetchedProjectMirrorRefsTokens.delete(project.projectId);
|
|
4146
|
+
}
|
|
4105
4147
|
}
|
|
4106
4148
|
const publishedTombstoneIds = [
|
|
4107
4149
|
...new Set(
|
|
@@ -4127,6 +4169,7 @@ async function startWorker(options) {
|
|
|
4127
4169
|
credentialHelper: deletion.credentialHelper,
|
|
4128
4170
|
credentialUsername: deletion.credentialUsername
|
|
4129
4171
|
});
|
|
4172
|
+
fetchedProjectMirrorRefsTokens.delete(deletion.projectId);
|
|
4130
4173
|
}
|
|
4131
4174
|
if (deletion.tombstoneId && !deletion.projectDeleted) {
|
|
4132
4175
|
projectWorkspaceState = projectWorkspaceStateStore.recordMirrorRefDeletion({
|
|
@@ -4137,43 +4180,103 @@ async function startWorker(options) {
|
|
|
4137
4180
|
pendingMirrorDeletes.delete(key);
|
|
4138
4181
|
if (deletion.projectDeleted && !projectConfigById.has(deletion.projectId) && ![...pendingMirrorDeletes.values()].some((pending) => pending.projectId === deletion.projectId)) {
|
|
4139
4182
|
removeProjectCredentialStore(deletion.projectId);
|
|
4183
|
+
advertisedProjectMirrorRefsTokens.delete(deletion.projectId);
|
|
4184
|
+
fetchedProjectMirrorRefsTokens.delete(deletion.projectId);
|
|
4185
|
+
lastProjectMirrorFetchAtMs.delete(deletion.projectId);
|
|
4140
4186
|
}
|
|
4141
4187
|
lastObservedProjectHeads.delete(key);
|
|
4142
4188
|
}
|
|
4143
4189
|
};
|
|
4190
|
+
const observeSingleProjectMirrorBundle = async (project, options2) => {
|
|
4191
|
+
const connection = projectConnection(project);
|
|
4192
|
+
const projectRoot = configuredProjectRoot(projectsRoot, project);
|
|
4193
|
+
const primaryBranchName = primaryProjectBranch(project);
|
|
4194
|
+
if (options2.refreshRemote) {
|
|
4195
|
+
const advertisedBeforeFetch = advertisedProjectMirrorRefsTokens.get(project.projectId);
|
|
4196
|
+
const observations = await observeProjectMirrorHeads({
|
|
4197
|
+
projectRoot,
|
|
4198
|
+
primaryBranchName,
|
|
4199
|
+
branchNames: project.branches.map(({ branchName }) => branchName),
|
|
4200
|
+
mirrorUrl: connection.mirrorUrl,
|
|
4201
|
+
credentialHelper: connection.credentialHelper,
|
|
4202
|
+
credentialUsername: connection.mirrorCredentialUsername,
|
|
4203
|
+
allowNonFastForward: options2.allowNonFastForward,
|
|
4204
|
+
branchIds: new Map(project.branches.map(({ branchId, branchName }) => [branchName, branchId]))
|
|
4205
|
+
});
|
|
4206
|
+
if (advertisedBeforeFetch === void 0) fetchedProjectMirrorRefsTokens.delete(project.projectId);
|
|
4207
|
+
else fetchedProjectMirrorRefsTokens.set(project.projectId, advertisedBeforeFetch);
|
|
4208
|
+
lastProjectMirrorFetchAtMs.set(project.projectId, Date.now());
|
|
4209
|
+
return { projectId: project.projectId, projectRoot, primaryBranchName, observations };
|
|
4210
|
+
}
|
|
4211
|
+
return {
|
|
4212
|
+
projectId: project.projectId,
|
|
4213
|
+
projectRoot,
|
|
4214
|
+
primaryBranchName,
|
|
4215
|
+
observations: await observeProjectMirrorHeads({
|
|
4216
|
+
projectRoot,
|
|
4217
|
+
primaryBranchName,
|
|
4218
|
+
branchNames: project.branches.map(({ branchName }) => branchName),
|
|
4219
|
+
mirrorUrl: connection.mirrorUrl,
|
|
4220
|
+
credentialHelper: connection.credentialHelper,
|
|
4221
|
+
credentialUsername: connection.mirrorCredentialUsername,
|
|
4222
|
+
allowNonFastForward: options2.allowNonFastForward,
|
|
4223
|
+
branchIds: new Map(project.branches.map(({ branchId, branchName }) => [branchName, branchId])),
|
|
4224
|
+
refreshRemote: false
|
|
4225
|
+
})
|
|
4226
|
+
};
|
|
4227
|
+
};
|
|
4144
4228
|
const observeProjectHeadsBeforeOuterWorkspace = async (input) => {
|
|
4145
|
-
const
|
|
4146
|
-
|
|
4147
|
-
|
|
4148
|
-
|
|
4149
|
-
|
|
4150
|
-
|
|
4151
|
-
const
|
|
4152
|
-
|
|
4153
|
-
|
|
4154
|
-
|
|
4155
|
-
|
|
4156
|
-
|
|
4157
|
-
|
|
4158
|
-
|
|
4159
|
-
|
|
4160
|
-
|
|
4161
|
-
|
|
4162
|
-
|
|
4163
|
-
|
|
4164
|
-
|
|
4165
|
-
|
|
4166
|
-
|
|
4167
|
-
|
|
4229
|
+
const observationStartedAt = Date.now();
|
|
4230
|
+
const eligibleProjects = [...projectConfigById.values()].filter(
|
|
4231
|
+
(project) => !project.executionDisabled && readyProjectIds.has(project.projectId) && project.branches.length > 0
|
|
4232
|
+
);
|
|
4233
|
+
try {
|
|
4234
|
+
if (input.failClosed) {
|
|
4235
|
+
const bundles2 = [];
|
|
4236
|
+
for (const project of eligibleProjects) {
|
|
4237
|
+
bundles2.push(await observeSingleProjectMirrorBundle(project, { allowNonFastForward: input.allowNonFastForward, refreshRemote: true }));
|
|
4238
|
+
}
|
|
4239
|
+
return bundles2;
|
|
4240
|
+
}
|
|
4241
|
+
let fetchedCount = 0;
|
|
4242
|
+
const bundles = await mapWithConcurrencyLimit(
|
|
4243
|
+
eligibleProjects,
|
|
4244
|
+
PROJECT_MIRROR_OBSERVE_CONCURRENCY,
|
|
4245
|
+
async (project) => {
|
|
4246
|
+
try {
|
|
4247
|
+
const decision = projectMirrorFetchDecision({
|
|
4248
|
+
advertisedToken: advertisedProjectMirrorRefsTokens.get(project.projectId),
|
|
4249
|
+
fetchedToken: fetchedProjectMirrorRefsTokens.get(project.projectId),
|
|
4250
|
+
lastFetchAtMs: lastProjectMirrorFetchAtMs.get(project.projectId),
|
|
4251
|
+
nowMs: Date.now(),
|
|
4252
|
+
skippingEnabled: projectMirrorFetchSkippingEnabled
|
|
4253
|
+
});
|
|
4254
|
+
if (decision.fetch) fetchedCount += 1;
|
|
4255
|
+
return await observeSingleProjectMirrorBundle(project, {
|
|
4256
|
+
allowNonFastForward: input.allowNonFastForward,
|
|
4257
|
+
refreshRemote: decision.fetch
|
|
4258
|
+
});
|
|
4259
|
+
} catch (error) {
|
|
4260
|
+
process.stderr.write(
|
|
4261
|
+
`[r5d-worker] failed to observe project mirror heads before workspace update: ${error instanceof Error ? error.message : String(error)}
|
|
4262
|
+
`
|
|
4263
|
+
);
|
|
4264
|
+
return null;
|
|
4265
|
+
}
|
|
4266
|
+
}
|
|
4267
|
+
);
|
|
4268
|
+
if (fetchedCount > 0) {
|
|
4168
4269
|
process.stderr.write(
|
|
4169
|
-
`[r5d-worker]
|
|
4270
|
+
`[r5d-worker] project mirror observation fetched ${fetchedCount} of ${eligibleProjects.length} mirror(s)
|
|
4170
4271
|
`
|
|
4171
4272
|
);
|
|
4172
4273
|
}
|
|
4274
|
+
return bundles.filter((bundle) => bundle !== null);
|
|
4275
|
+
} finally {
|
|
4276
|
+
lastWorkspaceSyncMirrorObservationMs = Date.now() - observationStartedAt;
|
|
4173
4277
|
}
|
|
4174
|
-
return bundles;
|
|
4175
4278
|
};
|
|
4176
|
-
const applyObservedProjectHeadsAfterInboundWorkspace = async (bundles, activeMountIds, requireObservedHeads) => {
|
|
4279
|
+
const applyObservedProjectHeadsAfterInboundWorkspace = async (bundles, activeMountIds, requireObservedHeads, integratedWorkspaceHead) => {
|
|
4177
4280
|
const active = new Set(activeMountIds);
|
|
4178
4281
|
for (const bundle of bundles) {
|
|
4179
4282
|
const project = projectConfigById.get(bundle.projectId);
|
|
@@ -4185,7 +4288,16 @@ async function startWorker(options) {
|
|
|
4185
4288
|
projectRoot: bundle.projectRoot,
|
|
4186
4289
|
primaryBranchName: bundle.primaryBranchName,
|
|
4187
4290
|
observations,
|
|
4188
|
-
branchMutationAllowed: (branchName, checkoutPath) => !projectBranchMountBusy(project.projectId, branchName, checkoutPath)
|
|
4291
|
+
branchMutationAllowed: (branchName, checkoutPath) => !projectBranchMountBusy(project.projectId, branchName, checkoutPath),
|
|
4292
|
+
serverSyncedWorkspaceCovered: async (observation) => {
|
|
4293
|
+
if (!integratedWorkspaceHead) return false;
|
|
4294
|
+
for (const workspaceHead of observation.serverSyncedWorkspaceHeads) {
|
|
4295
|
+
if (await tryGitAsync(["merge-base", "--is-ancestor", workspaceHead, integratedWorkspaceHead], { cwd: workspaceShadowRoot })) {
|
|
4296
|
+
return true;
|
|
4297
|
+
}
|
|
4298
|
+
}
|
|
4299
|
+
return false;
|
|
4300
|
+
}
|
|
4189
4301
|
});
|
|
4190
4302
|
if (requireObservedHeads) {
|
|
4191
4303
|
for (const observation of observations) {
|
|
@@ -4310,6 +4422,12 @@ async function startWorker(options) {
|
|
|
4310
4422
|
const outerRemediation = input.trigger.type === "remediation" || input.trigger.type === "remediation_confirm";
|
|
4311
4423
|
const mounts = outerRemediation ? workspaceGitMountsForRemediation(configuredMounts) : configuredMounts;
|
|
4312
4424
|
const observedProjectHeads = outerRemediation ? [] : await observeProjectHeadsBeforeOuterWorkspace({ allowNonFastForward: false, failClosed: false });
|
|
4425
|
+
const expectedMirrorHeads = /* @__PURE__ */ new Map();
|
|
4426
|
+
for (const bundle of observedProjectHeads) {
|
|
4427
|
+
for (const observation of bundle.observations) {
|
|
4428
|
+
expectedMirrorHeads.set(projectMountId(bundle.projectId, observation.branchName), observation.mirrorHead);
|
|
4429
|
+
}
|
|
4430
|
+
}
|
|
4313
4431
|
const inboundMoveMountIds = new Set(
|
|
4314
4432
|
observedProjectHeads.flatMap(
|
|
4315
4433
|
({ projectId, observations }) => observations.filter(({ shouldMove }) => shouldMove).map(({ branchName }) => projectMountId(projectId, branchName))
|
|
@@ -4331,12 +4449,17 @@ async function startWorker(options) {
|
|
|
4331
4449
|
requiredAncestorHeads: input.requiredAncestorHeads,
|
|
4332
4450
|
assertStillAdmitted: input.assertStillAdmitted,
|
|
4333
4451
|
afterWorkspacePublished: outerRemediation ? void 0 : async ({ activeMountIds, publishedHead }) => {
|
|
4334
|
-
await pushChangedProjectHeads(activeMountIds, publishedHead, publicationHeads, inboundMoveMountIds);
|
|
4452
|
+
await pushChangedProjectHeads(activeMountIds, publishedHead, publicationHeads, expectedMirrorHeads, inboundMoveMountIds);
|
|
4335
4453
|
}
|
|
4336
4454
|
});
|
|
4337
4455
|
input.assertStillAdmitted?.();
|
|
4338
4456
|
if (["no_change", "updated", "pushed"].includes(result.outcome) && !outerRemediation) {
|
|
4339
|
-
await applyObservedProjectHeadsAfterInboundWorkspace(
|
|
4457
|
+
await applyObservedProjectHeadsAfterInboundWorkspace(
|
|
4458
|
+
observedProjectHeads,
|
|
4459
|
+
result.activeMountIds,
|
|
4460
|
+
false,
|
|
4461
|
+
result.localHead ?? result.remoteHead
|
|
4462
|
+
);
|
|
4340
4463
|
}
|
|
4341
4464
|
return mapWorkspaceGitResult(input.attemptId, input.trigger, result);
|
|
4342
4465
|
};
|
|
@@ -4420,6 +4543,7 @@ async function startWorker(options) {
|
|
|
4420
4543
|
result = await workspaceSyncSingleFlight.runExclusive(async () => {
|
|
4421
4544
|
queueEnteredAt = Date.now();
|
|
4422
4545
|
syncStartedAt = Date.now();
|
|
4546
|
+
lastWorkspaceSyncMirrorObservationMs = 0;
|
|
4423
4547
|
if (!deferredWorkspaceSyncTriggerIsAllowed(deferredWorkspaceConfiguration, activeWorkspaceIncidentId, input.trigger)) {
|
|
4424
4548
|
return await failedWorkspaceSyncResult(
|
|
4425
4549
|
attemptId,
|
|
@@ -4504,7 +4628,9 @@ async function startWorker(options) {
|
|
|
4504
4628
|
telemetry: {
|
|
4505
4629
|
totalMs: finishedAt - requestedAt,
|
|
4506
4630
|
queueMs: queueEnteredAt - requestedAt,
|
|
4507
|
-
|
|
4631
|
+
// Duration of the pre-outer mirror-head observation phase; near zero
|
|
4632
|
+
// on a cycle whose token-gated observation skipped every fetch.
|
|
4633
|
+
prepareMs: lastWorkspaceSyncMirrorObservationMs,
|
|
4508
4634
|
synchronizeMs: finishedAt - syncStartedAt
|
|
4509
4635
|
}
|
|
4510
4636
|
};
|
|
@@ -5221,7 +5347,9 @@ async function startWorker(options) {
|
|
|
5221
5347
|
workspaceRemediationAncestorGuardV1: true,
|
|
5222
5348
|
workspaceIncidentConfigDeferralV1: true,
|
|
5223
5349
|
workspaceConfigResetToCanonicalV1: true,
|
|
5224
|
-
projectBranchDeletionFastAckV1: true
|
|
5350
|
+
projectBranchDeletionFastAckV1: true,
|
|
5351
|
+
projectMirrorLeaseV1: true,
|
|
5352
|
+
projectMirrorRefsTokensV1: true
|
|
5225
5353
|
},
|
|
5226
5354
|
projectRoot: projectsRoot,
|
|
5227
5355
|
artifactRoot,
|
|
@@ -5259,6 +5387,17 @@ async function startWorker(options) {
|
|
|
5259
5387
|
if (message.type === "connected") {
|
|
5260
5388
|
return;
|
|
5261
5389
|
}
|
|
5390
|
+
if (message.type === "project_mirror_refs_tokens") {
|
|
5391
|
+
advertisedProjectMirrorRefsTokens.clear();
|
|
5392
|
+
if (message.tokens && typeof message.tokens === "object") {
|
|
5393
|
+
for (const [projectId, token2] of Object.entries(message.tokens)) {
|
|
5394
|
+
if (typeof token2 === "string" && /^[0-9a-f]{64}$/.test(token2)) {
|
|
5395
|
+
advertisedProjectMirrorRefsTokens.set(projectId, token2);
|
|
5396
|
+
}
|
|
5397
|
+
}
|
|
5398
|
+
}
|
|
5399
|
+
return;
|
|
5400
|
+
}
|
|
5262
5401
|
if (message.type === "workspace_config") {
|
|
5263
5402
|
const receiptGeneration = ++workspaceConfigurationReceiptGeneration;
|
|
5264
5403
|
const refreshesDeferredConfiguration = deferredWorkspaceConfiguration !== null && activeWorkspaceIncidentId === null && message.deferWorkspaceSyncForIncidentId === void 0;
|
package/dist/mjs/package.json
CHANGED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
const PROJECT_MIRROR_FETCH_BACKSTOP_MS = 10 * 6e4;
|
|
2
|
+
function projectMirrorFetchDecision(input) {
|
|
3
|
+
if (!input.skippingEnabled) return { fetch: true, reason: "skipping_disabled" };
|
|
4
|
+
if (input.advertisedToken === void 0) return { fetch: true, reason: "no_advertised_token" };
|
|
5
|
+
if (input.fetchedToken === void 0) return { fetch: true, reason: "never_fetched" };
|
|
6
|
+
if (input.advertisedToken !== input.fetchedToken) return { fetch: true, reason: "token_changed" };
|
|
7
|
+
const backstopMs = input.backstopMs ?? PROJECT_MIRROR_FETCH_BACKSTOP_MS;
|
|
8
|
+
if (input.lastFetchAtMs === void 0 || input.nowMs - input.lastFetchAtMs >= backstopMs) {
|
|
9
|
+
return { fetch: true, reason: "backstop_elapsed" };
|
|
10
|
+
}
|
|
11
|
+
return { fetch: false, reason: "token_match" };
|
|
12
|
+
}
|
|
13
|
+
export {
|
|
14
|
+
PROJECT_MIRROR_FETCH_BACKSTOP_MS,
|
|
15
|
+
projectMirrorFetchDecision
|
|
16
|
+
};
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { createHash } from "node:crypto";
|
|
2
|
+
const PROJECT_MIRROR_REF_PREFIX = "refs/r5d/mirror/";
|
|
3
|
+
const PROJECT_SERVER_SYNCED_REF_PREFIX = "refs/r5d/server-synced/";
|
|
4
|
+
function hashProjectMirrorRefs(refs) {
|
|
5
|
+
const lines = refs.map(({ objectName, refname }) => `${objectName} ${refname}`).sort((left, right) => left < right ? -1 : left > right ? 1 : 0);
|
|
6
|
+
return createHash("sha256").update(lines.join("\n")).digest("hex");
|
|
7
|
+
}
|
|
8
|
+
function canonicalizeLocalProjectMirrorRefs(refs) {
|
|
9
|
+
const canonical = [];
|
|
10
|
+
for (const { refname, objectName } of refs) {
|
|
11
|
+
if (refname.startsWith(PROJECT_MIRROR_REF_PREFIX)) {
|
|
12
|
+
canonical.push({ refname: `refs/heads/${refname.slice(PROJECT_MIRROR_REF_PREFIX.length)}`, objectName });
|
|
13
|
+
} else if (refname.startsWith(PROJECT_SERVER_SYNCED_REF_PREFIX)) {
|
|
14
|
+
canonical.push({ refname, objectName });
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
return canonical;
|
|
18
|
+
}
|
|
19
|
+
export {
|
|
20
|
+
PROJECT_MIRROR_REF_PREFIX,
|
|
21
|
+
PROJECT_SERVER_SYNCED_REF_PREFIX,
|
|
22
|
+
canonicalizeLocalProjectMirrorRefs,
|
|
23
|
+
hashProjectMirrorRefs
|
|
24
|
+
};
|