@dotobokuri/fleet-cli 1.10.1 → 1.11.0
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 +192 -0
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -81620,6 +81620,170 @@ function resolvedWorkspaceSnapshot(resolveWorkspace, tenantId) {
|
|
|
81620
81620
|
tenantLabel: tenantId
|
|
81621
81621
|
};
|
|
81622
81622
|
}
|
|
81623
|
+
var RELEASE_NOTE_HEADINGS = ["Added", "Changed", "Fixed", "Removed", "Breaking Changes"];
|
|
81624
|
+
var VERSION_HEADER_PATTERN = /^## \[([^\]]+)\](?: - ([0-9]{4}-[0-9]{2}-[0-9]{2}))?$/;
|
|
81625
|
+
var SECTION_HEADER_PATTERN = /^### (Added|Changed|Fixed|Removed|Breaking Changes)$/;
|
|
81626
|
+
var BULLET_PATTERN = /^- (.+)$/;
|
|
81627
|
+
var PACKAGE_TAG_PATTERN = /^\[([^\]]+)\]/;
|
|
81628
|
+
function parseConsoleReleaseNotes(changelog) {
|
|
81629
|
+
const lines = changelog.split(/\r?\n/);
|
|
81630
|
+
const notes = [];
|
|
81631
|
+
for (let index = 0; index < lines.length; index += 1) {
|
|
81632
|
+
const match = VERSION_HEADER_PATTERN.exec(lines[index] ?? "");
|
|
81633
|
+
if (match === null) continue;
|
|
81634
|
+
const block = [];
|
|
81635
|
+
for (let cursor = index + 1; cursor < lines.length; cursor += 1) {
|
|
81636
|
+
if ((lines[cursor] ?? "").startsWith("## ")) break;
|
|
81637
|
+
block.push(lines[cursor] ?? "");
|
|
81638
|
+
}
|
|
81639
|
+
const sections = collectSections(block);
|
|
81640
|
+
if (sections.length === 0) continue;
|
|
81641
|
+
notes.push({ version: match[1] ?? "", date: match[2] ?? null, sections });
|
|
81642
|
+
}
|
|
81643
|
+
return notes;
|
|
81644
|
+
}
|
|
81645
|
+
function collectSections(lines) {
|
|
81646
|
+
const sections = [];
|
|
81647
|
+
let current = null;
|
|
81648
|
+
for (const line of lines) {
|
|
81649
|
+
const sectionMatch = SECTION_HEADER_PATTERN.exec(line);
|
|
81650
|
+
if (sectionMatch !== null) {
|
|
81651
|
+
current = { heading: sectionMatch[1], items: [] };
|
|
81652
|
+
sections.push(current);
|
|
81653
|
+
continue;
|
|
81654
|
+
}
|
|
81655
|
+
if (current === null) continue;
|
|
81656
|
+
if (line.startsWith("### ")) {
|
|
81657
|
+
current = null;
|
|
81658
|
+
continue;
|
|
81659
|
+
}
|
|
81660
|
+
const bulletMatch = BULLET_PATTERN.exec(line);
|
|
81661
|
+
if (bulletMatch !== null) current.items.push(parseReleaseNoteItem(bulletMatch[1] ?? ""));
|
|
81662
|
+
}
|
|
81663
|
+
return RELEASE_NOTE_HEADINGS.map((heading) => sections.find((section22) => section22.heading === heading)).filter((section22) => Boolean(section22 && section22.items.length > 0));
|
|
81664
|
+
}
|
|
81665
|
+
function parseReleaseNoteItem(rawText) {
|
|
81666
|
+
const packageTags = [];
|
|
81667
|
+
let text = rawText.trim();
|
|
81668
|
+
while (true) {
|
|
81669
|
+
const match = PACKAGE_TAG_PATTERN.exec(text);
|
|
81670
|
+
if (match === null) break;
|
|
81671
|
+
packageTags.push(match[1] ?? "");
|
|
81672
|
+
text = text.slice(match[0].length).trimStart();
|
|
81673
|
+
}
|
|
81674
|
+
return { packageTags, text: text.trim() };
|
|
81675
|
+
}
|
|
81676
|
+
var ConsoleReleaseNotesUnavailableError = class extends Error {
|
|
81677
|
+
reason;
|
|
81678
|
+
constructor(reason) {
|
|
81679
|
+
super("Console release notes are unavailable");
|
|
81680
|
+
this.name = "ConsoleReleaseNotesUnavailableError";
|
|
81681
|
+
this.reason = reason;
|
|
81682
|
+
}
|
|
81683
|
+
};
|
|
81684
|
+
var RAW_CHANGELOG_URL = "https://raw.githubusercontent.com/sbluemin/fleet-harness/main/CHANGELOG.md";
|
|
81685
|
+
var SOURCE_REF = "main";
|
|
81686
|
+
var FETCH_TIMEOUT_MS = 3e3;
|
|
81687
|
+
var MAX_CHANGELOG_BYTES = 1024 * 1024;
|
|
81688
|
+
var SUCCESS_TTL_MS = 60 * 60 * 1e3;
|
|
81689
|
+
var NEGATIVE_TTL_MS = 30 * 1e3;
|
|
81690
|
+
function createConsoleReleaseNotesService(deps = {}) {
|
|
81691
|
+
const fetchImpl = deps.fetchImpl ?? fetch;
|
|
81692
|
+
const now = deps.now ?? (() => Date.now());
|
|
81693
|
+
const setTimer = deps.setTimeout ?? setTimeout;
|
|
81694
|
+
const clearTimer = deps.clearTimeout ?? clearTimeout;
|
|
81695
|
+
let lastSuccess = null;
|
|
81696
|
+
let lastFailureAt = 0;
|
|
81697
|
+
let inFlight = null;
|
|
81698
|
+
let forceInFlight = null;
|
|
81699
|
+
async function refresh(options2 = {}) {
|
|
81700
|
+
const currentTime = now();
|
|
81701
|
+
if (options2.force) {
|
|
81702
|
+
if (forceInFlight) return forceInFlight;
|
|
81703
|
+
const pending2 = runFetch().finally(() => {
|
|
81704
|
+
if (forceInFlight === pending2) forceInFlight = null;
|
|
81705
|
+
});
|
|
81706
|
+
forceInFlight = pending2;
|
|
81707
|
+
return pending2;
|
|
81708
|
+
}
|
|
81709
|
+
if (lastSuccess && currentTime - lastSuccess.fetchedAt < SUCCESS_TTL_MS) return lastSuccess;
|
|
81710
|
+
if (lastFailureAt > 0 && currentTime - lastFailureAt < NEGATIVE_TTL_MS) {
|
|
81711
|
+
if (lastSuccess) return { ...lastSuccess, stale: true };
|
|
81712
|
+
throw new ConsoleReleaseNotesUnavailableError("negative_cache");
|
|
81713
|
+
}
|
|
81714
|
+
if (inFlight) return inFlight;
|
|
81715
|
+
const pending = runFetch().finally(() => {
|
|
81716
|
+
if (inFlight === pending) inFlight = null;
|
|
81717
|
+
});
|
|
81718
|
+
inFlight = pending;
|
|
81719
|
+
return pending;
|
|
81720
|
+
}
|
|
81721
|
+
function runFetch() {
|
|
81722
|
+
return fetchReleaseNotes().then((result) => {
|
|
81723
|
+
lastSuccess = result;
|
|
81724
|
+
lastFailureAt = 0;
|
|
81725
|
+
return result;
|
|
81726
|
+
}).catch((error512) => {
|
|
81727
|
+
lastFailureAt = now();
|
|
81728
|
+
if (lastSuccess) return { ...lastSuccess, stale: true };
|
|
81729
|
+
if (error512 instanceof ConsoleReleaseNotesUnavailableError) throw error512;
|
|
81730
|
+
throw new ConsoleReleaseNotesUnavailableError("cold_unavailable");
|
|
81731
|
+
});
|
|
81732
|
+
}
|
|
81733
|
+
async function fetchReleaseNotes() {
|
|
81734
|
+
const controller = new AbortController();
|
|
81735
|
+
const timer = setTimer(() => controller.abort(), FETCH_TIMEOUT_MS);
|
|
81736
|
+
timer.unref?.();
|
|
81737
|
+
try {
|
|
81738
|
+
const response = await fetchImpl(RAW_CHANGELOG_URL, {
|
|
81739
|
+
headers: { Accept: "text/plain; charset=utf-8" },
|
|
81740
|
+
signal: controller.signal
|
|
81741
|
+
});
|
|
81742
|
+
if (!response.ok) throw new ConsoleReleaseNotesUnavailableError("cold_unavailable");
|
|
81743
|
+
const text = await readTextWithByteLimit(response, controller);
|
|
81744
|
+
return {
|
|
81745
|
+
notes: parseConsoleReleaseNotes(text),
|
|
81746
|
+
sourceRef: SOURCE_REF,
|
|
81747
|
+
fetchedAt: now(),
|
|
81748
|
+
stale: false
|
|
81749
|
+
};
|
|
81750
|
+
} finally {
|
|
81751
|
+
clearTimer(timer);
|
|
81752
|
+
}
|
|
81753
|
+
}
|
|
81754
|
+
return { refresh };
|
|
81755
|
+
}
|
|
81756
|
+
async function readTextWithByteLimit(response, controller) {
|
|
81757
|
+
const body = response.body;
|
|
81758
|
+
if (body === null) return await response.text();
|
|
81759
|
+
const reader = body.getReader();
|
|
81760
|
+
const chunks = [];
|
|
81761
|
+
let totalBytes = 0;
|
|
81762
|
+
try {
|
|
81763
|
+
while (true) {
|
|
81764
|
+
const { done, value } = await reader.read();
|
|
81765
|
+
if (done) break;
|
|
81766
|
+
totalBytes += value.byteLength;
|
|
81767
|
+
if (totalBytes > MAX_CHANGELOG_BYTES) {
|
|
81768
|
+
controller.abort();
|
|
81769
|
+
throw new ConsoleReleaseNotesUnavailableError("cold_unavailable");
|
|
81770
|
+
}
|
|
81771
|
+
chunks.push(value);
|
|
81772
|
+
}
|
|
81773
|
+
return new TextDecoder().decode(joinChunks22(chunks, totalBytes));
|
|
81774
|
+
} finally {
|
|
81775
|
+
reader.releaseLock();
|
|
81776
|
+
}
|
|
81777
|
+
}
|
|
81778
|
+
function joinChunks22(chunks, totalBytes) {
|
|
81779
|
+
const joined = new Uint8Array(totalBytes);
|
|
81780
|
+
let offset = 0;
|
|
81781
|
+
for (const chunk of chunks) {
|
|
81782
|
+
joined.set(chunk, offset);
|
|
81783
|
+
offset += chunk.byteLength;
|
|
81784
|
+
}
|
|
81785
|
+
return joined;
|
|
81786
|
+
}
|
|
81623
81787
|
var TENANT_EVENT_LIMIT = 1e3;
|
|
81624
81788
|
var TENANT_FINALIZED_JOB_LIMIT = 100;
|
|
81625
81789
|
var TENANT_JOB_LIMIT = 200;
|
|
@@ -83540,6 +83704,13 @@ var SERVER_API_CATALOG = [
|
|
|
83540
83704
|
category: "Observer",
|
|
83541
83705
|
gate: "loopback"
|
|
83542
83706
|
},
|
|
83707
|
+
{
|
|
83708
|
+
method: "GET",
|
|
83709
|
+
path: "/observer/release-notes",
|
|
83710
|
+
summary: "Get the console release notes.",
|
|
83711
|
+
category: "Update",
|
|
83712
|
+
gate: "loopback"
|
|
83713
|
+
},
|
|
83543
83714
|
{
|
|
83544
83715
|
method: "GET",
|
|
83545
83716
|
path: "/observer/tenants",
|
|
@@ -83691,6 +83862,7 @@ function createConsoleServer(deps = {}) {
|
|
|
83691
83862
|
registerDefaultCarriers2(carrierRegistry);
|
|
83692
83863
|
const lock = createConsoleLock({ hostname: () => host });
|
|
83693
83864
|
const observability = createConsoleObservabilityStore();
|
|
83865
|
+
const releaseNotes = deps.releaseNotes ?? createConsoleReleaseNotesService();
|
|
83694
83866
|
const updateCheck = deps.updateCheck ?? createConsoleUpdateCheckService();
|
|
83695
83867
|
const updateApply = deps.updateApply ?? createConsoleUpdateApplyService();
|
|
83696
83868
|
const theaters = new TheaterRegistry();
|
|
@@ -83885,6 +84057,10 @@ function createConsoleServer(deps = {}) {
|
|
|
83885
84057
|
handleObserverApiCatalog(req, res);
|
|
83886
84058
|
return;
|
|
83887
84059
|
}
|
|
84060
|
+
if (pathname === "/observer/release-notes") {
|
|
84061
|
+
runAsyncHandler(handleObserverReleaseNotes(req, res), res);
|
|
84062
|
+
return;
|
|
84063
|
+
}
|
|
83888
84064
|
if (pathname === "/update/apply") {
|
|
83889
84065
|
runAsyncHandler(handleUpdateApply(req, res), res);
|
|
83890
84066
|
return;
|
|
@@ -84335,6 +84511,22 @@ function createConsoleServer(deps = {}) {
|
|
|
84335
84511
|
function handleObserverApiCatalog(_req, res) {
|
|
84336
84512
|
writeJson(res, 200, { version: version22, routes: buildApiCatalog() });
|
|
84337
84513
|
}
|
|
84514
|
+
async function handleObserverReleaseNotes(req, res) {
|
|
84515
|
+
if (req.method !== "GET") {
|
|
84516
|
+
writeJson(res, 405, { error: "Method not allowed" });
|
|
84517
|
+
return;
|
|
84518
|
+
}
|
|
84519
|
+
try {
|
|
84520
|
+
const force = readUrl(req).searchParams.get("force") === "true";
|
|
84521
|
+
writeJson(res, 200, await releaseNotes.refresh({ force }));
|
|
84522
|
+
} catch (error512) {
|
|
84523
|
+
if (error512 instanceof ConsoleReleaseNotesUnavailableError) {
|
|
84524
|
+
writeJson(res, 503, { error: "release_notes_unavailable" });
|
|
84525
|
+
return;
|
|
84526
|
+
}
|
|
84527
|
+
throw error512;
|
|
84528
|
+
}
|
|
84529
|
+
}
|
|
84338
84530
|
async function handleUpdateApply(req, res) {
|
|
84339
84531
|
if (req.method !== "POST") {
|
|
84340
84532
|
writeJson(res, 405, { error: "Method not allowed" });
|