@remixhq/core 0.1.33 → 0.1.34
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/collab.js +144 -2
- package/package.json +1 -1
package/dist/collab.js
CHANGED
|
@@ -509,6 +509,13 @@ import path3 from "path";
|
|
|
509
509
|
function getBaselinePath(params) {
|
|
510
510
|
return path3.join(getBaselinesRoot(), `${buildLaneStateKey(params)}.json`);
|
|
511
511
|
}
|
|
512
|
+
function normalizeNullableString(value) {
|
|
513
|
+
const normalized = String(value ?? "").trim();
|
|
514
|
+
return normalized || null;
|
|
515
|
+
}
|
|
516
|
+
function isSameBaselineIdentity(left, right) {
|
|
517
|
+
return left.repoRoot === right.repoRoot && (left.repoFingerprint ?? null) === (right.repoFingerprint ?? null) && (left.laneId ?? null) === (right.laneId ?? null) && left.currentAppId === right.currentAppId && (left.branchName ?? null) === (right.branchName ?? null);
|
|
518
|
+
}
|
|
512
519
|
async function readLocalBaseline(params) {
|
|
513
520
|
try {
|
|
514
521
|
const raw = await fs2.readFile(getBaselinePath(params), "utf8");
|
|
@@ -558,6 +565,105 @@ async function writeLocalBaseline(baseline) {
|
|
|
558
565
|
await writeJsonAtomic(getBaselinePath(baseline), normalized);
|
|
559
566
|
return normalized;
|
|
560
567
|
}
|
|
568
|
+
async function readAllLocalBaselines() {
|
|
569
|
+
let entries;
|
|
570
|
+
try {
|
|
571
|
+
entries = await fs2.readdir(getBaselinesRoot());
|
|
572
|
+
} catch (error) {
|
|
573
|
+
if (error?.code === "ENOENT") return [];
|
|
574
|
+
throw error;
|
|
575
|
+
}
|
|
576
|
+
const baselines = [];
|
|
577
|
+
for (const entry of entries) {
|
|
578
|
+
if (!entry.endsWith(".json")) continue;
|
|
579
|
+
try {
|
|
580
|
+
const raw = await fs2.readFile(path3.join(getBaselinesRoot(), entry), "utf8");
|
|
581
|
+
const parsed = JSON.parse(raw);
|
|
582
|
+
if (!parsed || typeof parsed !== "object") continue;
|
|
583
|
+
if (![1, 2].includes(Number(parsed.schemaVersion)) || typeof parsed.key !== "string" || typeof parsed.repoRoot !== "string") {
|
|
584
|
+
continue;
|
|
585
|
+
}
|
|
586
|
+
baselines.push({
|
|
587
|
+
schemaVersion: Number(parsed.schemaVersion) === 2 ? 2 : 1,
|
|
588
|
+
key: parsed.key,
|
|
589
|
+
repoRoot: parsed.repoRoot,
|
|
590
|
+
repoFingerprint: parsed.repoFingerprint ?? null,
|
|
591
|
+
laneId: parsed.laneId ?? null,
|
|
592
|
+
currentAppId: String(parsed.currentAppId ?? ""),
|
|
593
|
+
branchName: parsed.branchName ?? null,
|
|
594
|
+
lastSnapshotId: parsed.lastSnapshotId ?? null,
|
|
595
|
+
lastSnapshotHash: parsed.lastSnapshotHash ?? null,
|
|
596
|
+
lastServerRevisionId: parsed.lastServerRevisionId ?? null,
|
|
597
|
+
lastServerTreeHash: parsed.lastServerTreeHash ?? null,
|
|
598
|
+
lastServerHeadHash: parsed.lastServerHeadHash ?? null,
|
|
599
|
+
lastSeenLocalCommitHash: parsed.lastSeenLocalCommitHash ?? null,
|
|
600
|
+
updatedAt: String(parsed.updatedAt ?? "")
|
|
601
|
+
});
|
|
602
|
+
} catch {
|
|
603
|
+
continue;
|
|
604
|
+
}
|
|
605
|
+
}
|
|
606
|
+
return baselines;
|
|
607
|
+
}
|
|
608
|
+
async function migrateLocalBaselineForLaneChange(params) {
|
|
609
|
+
if ((params.fromLaneId ?? null) === (params.toLaneId ?? null)) {
|
|
610
|
+
return { status: "same_lane" };
|
|
611
|
+
}
|
|
612
|
+
const target = await readLocalBaseline({
|
|
613
|
+
repoRoot: params.repoRoot,
|
|
614
|
+
repoFingerprint: params.repoFingerprint,
|
|
615
|
+
laneId: params.toLaneId
|
|
616
|
+
});
|
|
617
|
+
if (target) {
|
|
618
|
+
return { status: "target_exists" };
|
|
619
|
+
}
|
|
620
|
+
const source = await readLocalBaseline({
|
|
621
|
+
repoRoot: params.repoRoot,
|
|
622
|
+
repoFingerprint: params.repoFingerprint,
|
|
623
|
+
laneId: params.fromLaneId
|
|
624
|
+
});
|
|
625
|
+
if (!source) {
|
|
626
|
+
return { status: "source_missing" };
|
|
627
|
+
}
|
|
628
|
+
const expectedSource = {
|
|
629
|
+
repoRoot: params.repoRoot,
|
|
630
|
+
repoFingerprint: params.repoFingerprint,
|
|
631
|
+
laneId: params.fromLaneId,
|
|
632
|
+
currentAppId: params.currentAppId,
|
|
633
|
+
branchName: params.branchName
|
|
634
|
+
};
|
|
635
|
+
const actualSource = {
|
|
636
|
+
repoRoot: source.repoRoot,
|
|
637
|
+
repoFingerprint: source.repoFingerprint,
|
|
638
|
+
laneId: source.laneId,
|
|
639
|
+
currentAppId: source.currentAppId,
|
|
640
|
+
branchName: source.branchName
|
|
641
|
+
};
|
|
642
|
+
if (!isSameBaselineIdentity(actualSource, expectedSource)) {
|
|
643
|
+
return { status: "source_missing" };
|
|
644
|
+
}
|
|
645
|
+
const baseline = await writeLocalBaseline({
|
|
646
|
+
...source,
|
|
647
|
+
laneId: params.toLaneId
|
|
648
|
+
});
|
|
649
|
+
return { status: "migrated", baseline };
|
|
650
|
+
}
|
|
651
|
+
async function findCompatibleLocalBaseline(params) {
|
|
652
|
+
const targetKey = buildLaneStateKey(params);
|
|
653
|
+
const branchName = normalizeNullableString(params.branchName);
|
|
654
|
+
const candidates = (await readAllLocalBaselines()).filter((baseline) => {
|
|
655
|
+
if (baseline.key === targetKey) return false;
|
|
656
|
+
if (baseline.repoRoot !== params.repoRoot) return false;
|
|
657
|
+
if ((baseline.repoFingerprint ?? null) !== (params.repoFingerprint ?? null)) return false;
|
|
658
|
+
if (baseline.currentAppId !== params.currentAppId) return false;
|
|
659
|
+
return true;
|
|
660
|
+
});
|
|
661
|
+
const branchMatches = candidates.filter((baseline) => normalizeNullableString(baseline.branchName) === branchName);
|
|
662
|
+
const compatible = branchMatches.length > 0 ? branchMatches : candidates.filter((baseline) => normalizeNullableString(baseline.branchName) === null);
|
|
663
|
+
if (compatible.length === 0) return { status: "none", candidateCount: 0 };
|
|
664
|
+
if (compatible.length > 1) return { status: "ambiguous", candidateCount: compatible.length };
|
|
665
|
+
return { status: "found", baseline: compatible[0] };
|
|
666
|
+
}
|
|
561
667
|
async function clearLocalBaseline(params) {
|
|
562
668
|
try {
|
|
563
669
|
await fs2.unlink(getBaselinePath(params));
|
|
@@ -1500,6 +1606,7 @@ function resolveLaneLookupProjectId(params) {
|
|
|
1500
1606
|
return params.explicitRootProjectId ?? (params.requireRemoteLane ? void 0 : localProjectId ?? params.fallbackProjectId ?? void 0);
|
|
1501
1607
|
}
|
|
1502
1608
|
async function persistResolvedLane(repoRoot, binding) {
|
|
1609
|
+
const previousBinding = await readCollabBinding(repoRoot);
|
|
1503
1610
|
await writeCollabBinding(repoRoot, {
|
|
1504
1611
|
projectId: binding.projectId,
|
|
1505
1612
|
currentAppId: binding.currentAppId,
|
|
@@ -1512,6 +1619,16 @@ async function persistResolvedLane(repoRoot, binding) {
|
|
|
1512
1619
|
branchName: binding.branchName,
|
|
1513
1620
|
bindingMode: binding.bindingMode
|
|
1514
1621
|
});
|
|
1622
|
+
if (previousBinding && (previousBinding.laneId ?? null) !== (binding.laneId ?? null)) {
|
|
1623
|
+
await migrateLocalBaselineForLaneChange({
|
|
1624
|
+
repoRoot,
|
|
1625
|
+
repoFingerprint: binding.repoFingerprint,
|
|
1626
|
+
currentAppId: binding.currentAppId,
|
|
1627
|
+
branchName: binding.branchName,
|
|
1628
|
+
fromLaneId: previousBinding.laneId,
|
|
1629
|
+
toLaneId: binding.laneId
|
|
1630
|
+
});
|
|
1631
|
+
}
|
|
1515
1632
|
return readCollabBinding(repoRoot);
|
|
1516
1633
|
}
|
|
1517
1634
|
function buildAmbiguousResolution(params) {
|
|
@@ -1911,11 +2028,36 @@ async function collabDetectRepoState(params) {
|
|
|
1911
2028
|
return detected;
|
|
1912
2029
|
}
|
|
1913
2030
|
try {
|
|
1914
|
-
|
|
2031
|
+
let baseline = await readLocalBaseline({
|
|
1915
2032
|
repoFingerprint: binding.repoFingerprint,
|
|
1916
2033
|
laneId: binding.laneId,
|
|
1917
2034
|
repoRoot
|
|
1918
2035
|
});
|
|
2036
|
+
let ambiguousBaselineCandidateCount = null;
|
|
2037
|
+
if (!baseline) {
|
|
2038
|
+
const compatibleBaseline = await findCompatibleLocalBaseline({
|
|
2039
|
+
repoRoot,
|
|
2040
|
+
repoFingerprint: binding.repoFingerprint,
|
|
2041
|
+
laneId: binding.laneId,
|
|
2042
|
+
currentAppId: binding.currentAppId,
|
|
2043
|
+
branchName: binding.branchName
|
|
2044
|
+
});
|
|
2045
|
+
if (compatibleBaseline.status === "found") {
|
|
2046
|
+
baseline = await writeLocalBaseline({
|
|
2047
|
+
...compatibleBaseline.baseline,
|
|
2048
|
+
repoRoot,
|
|
2049
|
+
repoFingerprint: binding.repoFingerprint,
|
|
2050
|
+
laneId: binding.laneId,
|
|
2051
|
+
currentAppId: binding.currentAppId,
|
|
2052
|
+
branchName: binding.branchName
|
|
2053
|
+
});
|
|
2054
|
+
detected.warnings.push(
|
|
2055
|
+
`Recovered local Remix baseline after lane id changed from ${compatibleBaseline.baseline.laneId ?? "null"} to ${binding.laneId ?? "null"} for app ${binding.currentAppId} on branch ${binding.branchName ?? "(unknown)"}.`
|
|
2056
|
+
);
|
|
2057
|
+
} else if (compatibleBaseline.status === "ambiguous") {
|
|
2058
|
+
ambiguousBaselineCandidateCount = compatibleBaseline.candidateCount;
|
|
2059
|
+
}
|
|
2060
|
+
}
|
|
1919
2061
|
const hasFullBaseline = Boolean(baseline?.lastSnapshotHash && baseline?.lastServerHeadHash);
|
|
1920
2062
|
const metadataIdentityPromise = hasFullBaseline ? getAppDeltaCached(params.api, binding.currentAppId, {
|
|
1921
2063
|
baseHeadHash: baseline.lastServerHeadHash,
|
|
@@ -1988,7 +2130,7 @@ async function collabDetectRepoState(params) {
|
|
|
1988
2130
|
}
|
|
1989
2131
|
}
|
|
1990
2132
|
detected.repoState = "external_local_base_changed";
|
|
1991
|
-
detected.hint = "No local Remix revision baseline exists for this lane yet. Run `remix collab init` or sync this lane to seed the baseline.";
|
|
2133
|
+
detected.hint = ambiguousBaselineCandidateCount !== null ? `No local Remix revision baseline exists for this lane, and multiple compatible local baselines were found (${ambiguousBaselineCandidateCount}). Run \`remix collab status\` or sync this lane to seed an unambiguous baseline.` : "No local Remix revision baseline exists for this lane yet. Run `remix collab init` or sync this lane to seed the baseline.";
|
|
1992
2134
|
return detected;
|
|
1993
2135
|
}
|
|
1994
2136
|
const localHeadMovedSinceBaseline = Boolean(baseline.lastSeenLocalCommitHash) && localCommitHash !== baseline.lastSeenLocalCommitHash;
|