@rightkit/release 0.2.129 → 0.2.131
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/package.json +1 -1
- package/rightkit-sync.mjs +88 -21
- package/rightkit-versions.json +14 -8
package/package.json
CHANGED
package/rightkit-sync.mjs
CHANGED
|
@@ -35,13 +35,71 @@ export function rightkitPublishables(root = rightkitRoot) {
|
|
|
35
35
|
return { crates, packages };
|
|
36
36
|
}
|
|
37
37
|
|
|
38
|
+
const SEMVER = /^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-((?:0|[1-9]\d*|\d*[A-Za-z-][0-9A-Za-z-]*)(?:\.(?:0|[1-9]\d*|\d*[A-Za-z-][0-9A-Za-z-]*))*))?(?:\+[0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*)?$/;
|
|
39
|
+
|
|
38
40
|
export function compareVersions(left, right) {
|
|
39
|
-
const
|
|
40
|
-
|
|
41
|
-
|
|
41
|
+
const a = String(left).match(SEMVER); const b = String(right).match(SEMVER);
|
|
42
|
+
if (!a || !b) throw new Error(`invalid semver: ${!a ? left : right}`);
|
|
43
|
+
const compare = (x, y) => x < y ? -1 : x > y ? 1 : 0;
|
|
44
|
+
for (let i = 1; i <= 3; i += 1) {
|
|
45
|
+
const order = compare(BigInt(a[i]), BigInt(b[i]));
|
|
46
|
+
if (order) return order;
|
|
47
|
+
}
|
|
48
|
+
if (!a[4] || !b[4]) return compare(Boolean(b[4]), Boolean(a[4]));
|
|
49
|
+
const ap = a[4].split("."); const bp = b[4].split(".");
|
|
50
|
+
for (let i = 0; i < Math.max(ap.length, bp.length); i += 1) {
|
|
51
|
+
if (ap[i] === undefined || bp[i] === undefined) return compare(ap.length, bp.length);
|
|
52
|
+
const an = /^\d+$/.test(ap[i]); const bn = /^\d+$/.test(bp[i]);
|
|
53
|
+
const order = an && bn ? compare(BigInt(ap[i]), BigInt(bp[i]))
|
|
54
|
+
: an !== bn ? (an ? -1 : 1) : compare(ap[i], bp[i]);
|
|
55
|
+
if (order) return order;
|
|
56
|
+
}
|
|
42
57
|
return 0;
|
|
43
58
|
}
|
|
44
59
|
|
|
60
|
+
const versionKeys = (registry) => {
|
|
61
|
+
if (!["npm", "cargo"].includes(registry)) throw new Error(`unknown registry: ${registry}; expected npm or cargo`);
|
|
62
|
+
return registry === "npm" ? ["stagedNpm", "legacyNpm"] : ["stagedCargo", "legacyCargo"];
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
// Use publication evidence captured before replacing registry[name], never staging alone.
|
|
66
|
+
function retainPublished(versions, { registry, name, version }, candidates, latest) {
|
|
67
|
+
const [, legacyKey] = versionKeys(registry);
|
|
68
|
+
const recorded = versions.registry?.[registry]?.[name];
|
|
69
|
+
const eligible = candidates.filter((previous) => previous && compareVersions(previous, version) < 0
|
|
70
|
+
&& (previous === recorded || previous === latest));
|
|
71
|
+
if (!eligible.length) return;
|
|
72
|
+
versions[legacyKey] ??= {};
|
|
73
|
+
versions[legacyKey][name] = [...new Set([...(versions[legacyKey][name] ?? []), ...eligible])].sort(compareVersions);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/** Stage a rollout while preserving published pins, then refresh consumer copies. */
|
|
77
|
+
export async function stageVersion({ registry, name, version }, { file = VERSIONS_FILE, root = rightkitRoot, log = (line) => process.stdout.write(`${line}\n`), fetchImpl = fetch } = {}) {
|
|
78
|
+
const [stagedKey] = versionKeys(registry);
|
|
79
|
+
if (typeof name !== "string" || !name.trim()) throw new Error("stage requires a package or crate name");
|
|
80
|
+
if (typeof version !== "string" || !SEMVER.test(version)) throw new Error(`invalid semver: ${version}`);
|
|
81
|
+
const versions = JSON.parse(readFileSync(file, "utf8"));
|
|
82
|
+
const current = versions[stagedKey]?.[name] ?? versions[registry]?.[name] ?? null;
|
|
83
|
+
if (current && compareVersions(version, current) < 0) throw new Error(`refusing to stage ${name} ${version} below ${current}`);
|
|
84
|
+
const next = structuredClone(versions);
|
|
85
|
+
const recorded = next.registry?.[registry]?.[name];
|
|
86
|
+
let latest;
|
|
87
|
+
if (current && compareVersions(current, version) < 0 && current !== recorded) {
|
|
88
|
+
const [result] = await registryLatest({ crates: registry === "cargo" ? [name] : [], packages: registry === "npm" ? [name] : [] }, { fetchImpl });
|
|
89
|
+
latest = result.version;
|
|
90
|
+
}
|
|
91
|
+
retainPublished(next, { registry, name, version }, [current, recorded], latest);
|
|
92
|
+
next[stagedKey] ??= {};
|
|
93
|
+
next[stagedKey][name] = version;
|
|
94
|
+
next[stagedKey] = Object.fromEntries(Object.entries(next[stagedKey]).sort(([a], [b]) => a.localeCompare(b)));
|
|
95
|
+
const written = JSON.stringify(next) !== JSON.stringify(versions);
|
|
96
|
+
if (written) writeFileSync(file, `${JSON.stringify(next, null, 2)}\n`);
|
|
97
|
+
const copies = syncConsumerCopies(root);
|
|
98
|
+
log(`${registry} ${name}: ${current ?? "unlisted"} -> ${version}`);
|
|
99
|
+
for (const copy of copies) log(`refreshed ${copy}`);
|
|
100
|
+
return { changes: current !== version ? [{ registry, name, from: current, to: version }] : [], copies, written };
|
|
101
|
+
}
|
|
102
|
+
|
|
45
103
|
async function fetchJson(fetchImpl, url) {
|
|
46
104
|
const response = await fetchImpl(url, { headers: { "user-agent": USER_AGENT, accept: "application/json" }, signal: AbortSignal.timeout(15_000) });
|
|
47
105
|
if (response.status === 404) return null;
|
|
@@ -71,20 +129,19 @@ export function applyRegistryLatest(versions, latest) {
|
|
|
71
129
|
const next = structuredClone(versions); const changes = []; let verified = 0;
|
|
72
130
|
for (const { registry, name, version } of latest) {
|
|
73
131
|
if (!version) continue;
|
|
132
|
+
const [stagedKey] = versionKeys(registry);
|
|
133
|
+
const current = next[stagedKey]?.[name] ?? next[registry]?.[name] ?? null;
|
|
134
|
+
const recorded = next.registry?.[registry]?.[name];
|
|
135
|
+
retainPublished(next, { registry, name, version }, [current, recorded], version);
|
|
136
|
+
// A registry can lag an unpublished staged rollout: its published pin still stays allowed.
|
|
137
|
+
if (current && compareVersions(version, current) < 0) {
|
|
138
|
+
retainPublished(next, { registry, name, version: current }, [recorded, version], version);
|
|
139
|
+
}
|
|
74
140
|
// What the registry serves: the only versions adoption recommends (staged may still be unpublished).
|
|
75
141
|
next.registry ??= { cargo: {}, npm: {} }; next.registry[registry] ??= {};
|
|
76
142
|
if (next.registry[registry][name] !== version) { next.registry[registry][name] = version; verified += 1; }
|
|
77
|
-
const stagedKey = registry === "cargo" ? "stagedCargo" : "stagedNpm";
|
|
78
|
-
const legacyKey = registry === "cargo" ? "legacyCargo" : "legacyNpm";
|
|
79
|
-
const current = next[stagedKey]?.[name] ?? next[registry]?.[name] ?? null;
|
|
80
143
|
if (current && compareVersions(version, current) <= 0) continue;
|
|
81
144
|
next[stagedKey] ??= {};
|
|
82
|
-
const previous = next[stagedKey][name];
|
|
83
|
-
if (previous && previous !== next[registry]?.[name]) {
|
|
84
|
-
next[legacyKey] ??= {};
|
|
85
|
-
const legacy = new Set(next[legacyKey][name] ?? []); legacy.add(previous);
|
|
86
|
-
next[legacyKey][name] = [...legacy].sort(compareVersions);
|
|
87
|
-
}
|
|
88
145
|
next[stagedKey][name] = version;
|
|
89
146
|
next[stagedKey] = Object.fromEntries(Object.entries(next[stagedKey]).sort(([a], [b]) => a.localeCompare(b)));
|
|
90
147
|
changes.push({ registry, name, from: current, to: version });
|
|
@@ -96,24 +153,26 @@ export function applyRegistryLatest(versions, latest) {
|
|
|
96
153
|
export async function syncRightkitVersions({ check = false, fetchImpl = fetch, file = VERSIONS_FILE, root = rightkitRoot, log = (line) => process.stdout.write(`${line}\n`) } = {}) {
|
|
97
154
|
const versions = JSON.parse(readFileSync(file, "utf8"));
|
|
98
155
|
const latest = await registryLatest(rightkitPublishables(root), { fetchImpl });
|
|
99
|
-
const { versions: next, changes
|
|
156
|
+
const { versions: next, changes } = applyRegistryLatest(versions, latest);
|
|
100
157
|
for (const change of changes) log(`${change.registry} ${change.name}: ${change.from ?? "unlisted"} -> ${change.to}`);
|
|
101
158
|
const unpublished = latest.filter((item) => !item.version).map((item) => `${item.registry}:${item.name}`);
|
|
102
159
|
if (unpublished.length) log(`never published: ${unpublished.join(", ")}`);
|
|
103
160
|
if (!changes.length) log("rightkit-versions.json matches the registries");
|
|
104
161
|
if (check) return { changes, unpublished, copies: [], written: false };
|
|
105
|
-
|
|
162
|
+
const written = JSON.stringify(next) !== JSON.stringify(versions);
|
|
163
|
+
if (written) writeFileSync(file, `${JSON.stringify(next, null, 2)}\n`);
|
|
106
164
|
const copies = syncConsumerCopies(root);
|
|
107
165
|
for (const copy of copies) log(`refreshed ${copy}`);
|
|
108
|
-
return { changes, unpublished, copies, written
|
|
166
|
+
return { changes, unpublished, copies, written };
|
|
109
167
|
}
|
|
110
168
|
|
|
111
169
|
/** Record one just-published version (the registry index can lag the upload) and refresh the copies.
|
|
112
170
|
* Called by right-release after a verified cargo or npm publish; never fails the publish itself. */
|
|
113
171
|
export function recordPublished({ registry, name, version }, { file = VERSIONS_FILE, root = rightkitRoot, log = (line) => process.stdout.write(`${line}\n`) } = {}) {
|
|
114
172
|
try {
|
|
115
|
-
const
|
|
116
|
-
|
|
173
|
+
const versions = JSON.parse(readFileSync(file, "utf8"));
|
|
174
|
+
const { versions: next, changes } = applyRegistryLatest(versions, [{ registry, name, version }]);
|
|
175
|
+
if (JSON.stringify(next) !== JSON.stringify(versions)) writeFileSync(file, `${JSON.stringify(next, null, 2)}\n`);
|
|
117
176
|
const copies = syncConsumerCopies(root);
|
|
118
177
|
log(`[right-release] release feed: ${name} ${version} ${changes.length ? "staged" : "already current"}${copies.length ? `; refreshed ${copies.length} copies` : ""}; commit rightkit-versions.json and its copies`);
|
|
119
178
|
} catch (error) { log(`[right-release] release feed not updated (${error.message}); run node rightkit-sync.mjs`); }
|
|
@@ -143,8 +202,16 @@ export function syncConsumerCopies(root = rightkitRoot) {
|
|
|
143
202
|
}
|
|
144
203
|
|
|
145
204
|
if (process.argv[1] && path.resolve(process.argv[1]) === fileURLToPath(import.meta.url)) {
|
|
146
|
-
const
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
205
|
+
const main = async () => {
|
|
206
|
+
const args = process.argv.slice(2);
|
|
207
|
+
if (args[0] === "stage") {
|
|
208
|
+
if (args.length !== 4) throw new Error("usage: node rightkit-sync.mjs stage <npm|cargo> <name> <version>");
|
|
209
|
+
await stageVersion({ registry: args[1], name: args[2], version: args[3] });
|
|
210
|
+
return;
|
|
211
|
+
}
|
|
212
|
+
const check = args.includes("--check");
|
|
213
|
+
const { changes } = await syncRightkitVersions({ check });
|
|
214
|
+
if (check && changes.length) process.exitCode = 1;
|
|
215
|
+
};
|
|
216
|
+
main().catch((error) => { process.stderr.write(`rightkit-sync: ${error.message}\n`); process.exitCode = 1; });
|
|
150
217
|
}
|
package/rightkit-versions.json
CHANGED
|
@@ -29,7 +29,7 @@
|
|
|
29
29
|
"@rightkit/platform-ui": "0.1.2",
|
|
30
30
|
"@rightkit/qa": "0.3.0",
|
|
31
31
|
"@rightkit/qa-chrome": "0.1.3",
|
|
32
|
-
"@rightkit/release": "0.2.
|
|
32
|
+
"@rightkit/release": "0.2.131",
|
|
33
33
|
"@rightkit/settings-ui": "0.2.7",
|
|
34
34
|
"@rightkit/shell": "0.1.0",
|
|
35
35
|
"@rightkit/tauri": "0.1.1",
|
|
@@ -152,7 +152,9 @@
|
|
|
152
152
|
"0.2.125",
|
|
153
153
|
"0.2.126",
|
|
154
154
|
"0.2.127",
|
|
155
|
-
"0.2.128"
|
|
155
|
+
"0.2.128",
|
|
156
|
+
"0.2.129",
|
|
157
|
+
"0.2.130"
|
|
156
158
|
],
|
|
157
159
|
"@rightkit/qa": [
|
|
158
160
|
"0.1.0",
|
|
@@ -234,7 +236,7 @@
|
|
|
234
236
|
"rightkit-automation": "0.1.0",
|
|
235
237
|
"rightkit-browser": "0.2.2",
|
|
236
238
|
"rightkit-cache": "0.1.0",
|
|
237
|
-
"rightkit-control": "0.1.
|
|
239
|
+
"rightkit-control": "0.1.7",
|
|
238
240
|
"rightkit-crash": "0.1.0",
|
|
239
241
|
"rightkit-db": "0.3.0",
|
|
240
242
|
"rightkit-embed": "0.2.2",
|
|
@@ -252,7 +254,7 @@
|
|
|
252
254
|
"rightkit-pdf": "0.1.0",
|
|
253
255
|
"rightkit-playback": "0.1.1",
|
|
254
256
|
"rightkit-process": "0.3.0",
|
|
255
|
-
"rightkit-qa": "0.2.
|
|
257
|
+
"rightkit-qa": "0.2.9",
|
|
256
258
|
"rightkit-qts": "0.2.1",
|
|
257
259
|
"rightkit-qts-ggml": "0.1.0",
|
|
258
260
|
"rightkit-qts-ggml-sys": "0.1.0",
|
|
@@ -284,7 +286,7 @@
|
|
|
284
286
|
"rightkit-audio": "0.1.1",
|
|
285
287
|
"rightkit-browser": "0.2.2",
|
|
286
288
|
"rightkit-cache": "0.1.0",
|
|
287
|
-
"rightkit-control": "0.1.
|
|
289
|
+
"rightkit-control": "0.1.7",
|
|
288
290
|
"rightkit-crash": "0.1.0",
|
|
289
291
|
"rightkit-db": "0.3.0",
|
|
290
292
|
"rightkit-embed": "0.2.2",
|
|
@@ -302,7 +304,7 @@
|
|
|
302
304
|
"rightkit-pdf": "0.1.0",
|
|
303
305
|
"rightkit-playback": "0.1.1",
|
|
304
306
|
"rightkit-process": "0.3.0",
|
|
305
|
-
"rightkit-qa": "0.2.
|
|
307
|
+
"rightkit-qa": "0.2.9",
|
|
306
308
|
"rightkit-qts": "0.2.1",
|
|
307
309
|
"rightkit-qts-ggml": "0.1.0",
|
|
308
310
|
"rightkit-qts-ggml-sys": "0.1.0",
|
|
@@ -333,7 +335,7 @@
|
|
|
333
335
|
"@rightkit/platform-ui": "0.1.2",
|
|
334
336
|
"@rightkit/qa": "0.3.0",
|
|
335
337
|
"@rightkit/qa-chrome": "0.1.3",
|
|
336
|
-
"@rightkit/release": "0.2.
|
|
338
|
+
"@rightkit/release": "0.2.130",
|
|
337
339
|
"@rightkit/settings-ui": "0.2.7",
|
|
338
340
|
"@rightkit/shell": "0.1.0",
|
|
339
341
|
"@rightkit/tauri": "0.1.1",
|
|
@@ -381,7 +383,8 @@
|
|
|
381
383
|
"0.2.1"
|
|
382
384
|
],
|
|
383
385
|
"rightkit-qa": [
|
|
384
|
-
"0.2.7"
|
|
386
|
+
"0.2.7",
|
|
387
|
+
"0.2.8"
|
|
385
388
|
],
|
|
386
389
|
"rightkit-sandbox": [
|
|
387
390
|
"0.1.0",
|
|
@@ -397,6 +400,9 @@
|
|
|
397
400
|
],
|
|
398
401
|
"rightkit-qts": [
|
|
399
402
|
"0.2.0"
|
|
403
|
+
],
|
|
404
|
+
"rightkit-control": [
|
|
405
|
+
"0.1.6"
|
|
400
406
|
]
|
|
401
407
|
}
|
|
402
408
|
}
|