@minnovate/shadow-publisher 0.10.1 → 0.10.3
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.
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "git-publisher",
|
|
3
3
|
"displayName": "Git Publisher",
|
|
4
|
-
"version": "0.10.
|
|
4
|
+
"version": "0.10.3",
|
|
5
5
|
"description": "Publish an app folder's Git history to the serverless Git publishing backend and keep it updated (\"publish my app\", \"update my app\", \"fetch the engineered version\").",
|
|
6
6
|
"author": { "name": "git-publisher project" },
|
|
7
7
|
"keywords": ["git", "publish", "deploy", "serverless"]
|
|
@@ -102,8 +102,8 @@ the message in the user's words ("Add a contact page"), not git's.
|
|
|
102
102
|
A published app runs with no internet access: **it may not load anything from other sites** — no
|
|
103
103
|
CDN scripts, web fonts or remote images. When you write or change an app, keep every file it needs
|
|
104
104
|
in its folder. The checks refuse an app that does not (see "When the checks find something").
|
|
105
|
-
Keep it small too: each file at most
|
|
106
|
-
a larger app is refused before it is checked,
|
|
105
|
+
Keep it small too: each file at most 4 MB, the whole app at most 10 MB, at most 500 files —
|
|
106
|
+
a larger app is refused before it is checked, and the refusal names the file or the limit it broke.
|
|
107
107
|
|
|
108
108
|
## 4. Telling them how it goes, step by step
|
|
109
109
|
|
|
@@ -177,7 +177,7 @@ sentence, and `progress.next.action` is `"fix"`. Then:
|
|
|
177
177
|
2. Fix every finding in the app folder, by its `kind`:
|
|
178
178
|
- `external-resource`: the app loads `url` from another site (a CDN script, Google Fonts, an
|
|
179
179
|
image). **Apps may not load anything from other sites.** Download the file into the app
|
|
180
|
-
folder and point to it with a relative path — only if it is at most
|
|
180
|
+
folder and point to it with a relative path — only if it is at most 4 MB; a charting
|
|
181
181
|
library usually is not (Chart.js is 201 KB). Otherwise replace it with code of your own: a
|
|
182
182
|
font falls back to a system font stack, a chart is drawn as inline SVG. Never keep the
|
|
183
183
|
external address.
|
package/dist/publisher.cjs
CHANGED
|
@@ -3269,7 +3269,7 @@ async function runGit(args, opts = {}) {
|
|
|
3269
3269
|
function startWatchdog(child, opts, kill, isClosed) {
|
|
3270
3270
|
if (opts.maxMemoryBytes === void 0 && opts.maxDiskBytes === void 0) return { stop: () => void 0, done: Promise.resolve() };
|
|
3271
3271
|
const sampler = opts.sampler ?? defaultResourceSampler;
|
|
3272
|
-
const
|
|
3272
|
+
const interval2 = Math.max(10, opts.sampleIntervalMs ?? 500);
|
|
3273
3273
|
const sampleBoundMs = opts.cleanupBoundMs ?? CLEANUP_BOUND_MS;
|
|
3274
3274
|
const pgid = child.pid;
|
|
3275
3275
|
let stopped = false;
|
|
@@ -3299,7 +3299,7 @@ function startWatchdog(child, opts, kill, isClosed) {
|
|
|
3299
3299
|
}
|
|
3300
3300
|
let tick = 0;
|
|
3301
3301
|
while (!stopped) {
|
|
3302
|
-
await sleep2(
|
|
3302
|
+
await sleep2(interval2);
|
|
3303
3303
|
if (stopped) return;
|
|
3304
3304
|
if (opts.maxMemoryBytes !== void 0) {
|
|
3305
3305
|
const rss = await sample("memory", (signal) => sampler.groupRss(pgid, signal));
|
|
@@ -4712,7 +4712,7 @@ async function followRun(input, opts) {
|
|
|
4712
4712
|
const fetchImpl = opts.fetch ?? fetch;
|
|
4713
4713
|
const sleep2 = opts.sleep ?? sleep;
|
|
4714
4714
|
const now = opts.now ?? Date.now;
|
|
4715
|
-
const
|
|
4715
|
+
const interval2 = opts.intervalMs ?? POLL_INTERVAL_MS;
|
|
4716
4716
|
const deadline = now() + (opts.timeoutMs ?? FOLLOW_TIMEOUT_MS);
|
|
4717
4717
|
const query = new URLSearchParams({ publication: input.publicationId, ref: input.ref, commit: input.commit });
|
|
4718
4718
|
const url2 = `${input.portal.replace(/\/+$/, "")}/api/v1/terminal/repositories/${encodeURIComponent(input.repoId)}/runs?${query}`;
|
|
@@ -4758,8 +4758,8 @@ async function followRun(input, opts) {
|
|
|
4758
4758
|
} else {
|
|
4759
4759
|
lastError = answer.status === 0 ? "the portal could not be reached" : `the portal answered ${answer.status}`;
|
|
4760
4760
|
}
|
|
4761
|
-
if (now() +
|
|
4762
|
-
await sleep2(
|
|
4761
|
+
if (now() + interval2 > deadline) return { kind: "timed-out", stages: last, lastError };
|
|
4762
|
+
await sleep2(interval2);
|
|
4763
4763
|
}
|
|
4764
4764
|
}
|
|
4765
4765
|
function soleRun(body) {
|
|
@@ -5911,6 +5911,93 @@ function gitSupported(version2) {
|
|
|
5911
5911
|
return compareVersions(version2, CLIENT_GIT_MINIMUM) >= 0;
|
|
5912
5912
|
}
|
|
5913
5913
|
|
|
5914
|
+
// src/progress.ts
|
|
5915
|
+
var SAYS = {
|
|
5916
|
+
received: { doing: "Shadow is picking up your changes", done: "Shadow has your changes", still: "still picking up your changes" },
|
|
5917
|
+
running: { doing: "checking that everything still works", done: "everything still works", still: "still checking" },
|
|
5918
|
+
deploying: { doing: "putting the new version in place; the current one stays up meanwhile", done: "the new version is in place", still: "still putting it in place" },
|
|
5919
|
+
live: { doing: "going live", done: "everyone sees the new version", still: "still going live" }
|
|
5920
|
+
};
|
|
5921
|
+
var HEARTBEAT_MS = 3e4;
|
|
5922
|
+
var SPINNER = ["\u280B", "\u2819", "\u2839", "\u2838", "\u283C", "\u2834", "\u2826", "\u2827", "\u2807", "\u280F"];
|
|
5923
|
+
function took(ms) {
|
|
5924
|
+
const seconds = Math.max(0, Math.floor(ms / 1e3));
|
|
5925
|
+
if (seconds < 60) return `${seconds} s`;
|
|
5926
|
+
const minutes = Math.floor(seconds / 60);
|
|
5927
|
+
return minutes >= 10 ? `${minutes} min` : `${minutes} min ${String(seconds % 60).padStart(2, "0")} s`;
|
|
5928
|
+
}
|
|
5929
|
+
function interval(fn, ms) {
|
|
5930
|
+
const timer = setInterval(fn, ms);
|
|
5931
|
+
timer.unref();
|
|
5932
|
+
return { stop: () => clearInterval(timer) };
|
|
5933
|
+
}
|
|
5934
|
+
function settledLine(e, total) {
|
|
5935
|
+
const word = e.word.padEnd(10);
|
|
5936
|
+
switch (e.state) {
|
|
5937
|
+
case "done":
|
|
5938
|
+
return ` \u2713 ${word} ${SAYS[e.stage].done}${total}
|
|
5939
|
+
`;
|
|
5940
|
+
case "failed":
|
|
5941
|
+
return ` \u2717 ${word} it stopped here
|
|
5942
|
+
`;
|
|
5943
|
+
case "skipped":
|
|
5944
|
+
return ` \u2013 ${word} skipped
|
|
5945
|
+
`;
|
|
5946
|
+
default:
|
|
5947
|
+
return null;
|
|
5948
|
+
}
|
|
5949
|
+
}
|
|
5950
|
+
function stageReporter(io) {
|
|
5951
|
+
const now = io.now ?? Date.now;
|
|
5952
|
+
const every = io.every ?? interval;
|
|
5953
|
+
let ticking = null;
|
|
5954
|
+
let drawn = false;
|
|
5955
|
+
let receivedAt = null;
|
|
5956
|
+
const clear = () => {
|
|
5957
|
+
if (drawn) io.write("\r\x1B[2K");
|
|
5958
|
+
drawn = false;
|
|
5959
|
+
};
|
|
5960
|
+
const stopTicking = () => {
|
|
5961
|
+
ticking?.timer.stop();
|
|
5962
|
+
ticking = null;
|
|
5963
|
+
clear();
|
|
5964
|
+
};
|
|
5965
|
+
const since = (e) => {
|
|
5966
|
+
const at = e.at === null ? NaN : Date.parse(e.at);
|
|
5967
|
+
return Number.isFinite(at) ? Math.min(at, now()) : now();
|
|
5968
|
+
};
|
|
5969
|
+
return {
|
|
5970
|
+
onStage(e) {
|
|
5971
|
+
if (e.state === "in-progress" || ticking?.stage === e.stage) stopTicking();
|
|
5972
|
+
else clear();
|
|
5973
|
+
const says = SAYS[e.stage];
|
|
5974
|
+
if (e.stage === "received" && e.at !== null) receivedAt = since(e);
|
|
5975
|
+
if (e.state !== "in-progress") {
|
|
5976
|
+
const total = e.stage === "live" && e.state === "done" && receivedAt !== null ? ` (${took(since(e) - receivedAt)} after Shadow received it)` : "";
|
|
5977
|
+
const line = settledLine(e, total);
|
|
5978
|
+
if (line !== null) io.write(line);
|
|
5979
|
+
return;
|
|
5980
|
+
}
|
|
5981
|
+
io.write(` \u2026 ${e.word.padEnd(10)} ${says.doing}
|
|
5982
|
+
`);
|
|
5983
|
+
const from = since(e);
|
|
5984
|
+
if (io.isTTY) {
|
|
5985
|
+
let frame = 0;
|
|
5986
|
+
const draw = () => {
|
|
5987
|
+
io.write(`\r\x1B[2K ${SPINNER[frame++ % SPINNER.length]} ${says.still} \xB7 ${took(now() - from)}`);
|
|
5988
|
+
drawn = true;
|
|
5989
|
+
};
|
|
5990
|
+
draw();
|
|
5991
|
+
ticking = { stage: e.stage, timer: every(draw, 1e3) };
|
|
5992
|
+
} else {
|
|
5993
|
+
ticking = { stage: e.stage, timer: every(() => io.write(` ${says.still} (${took(now() - from)} so far)
|
|
5994
|
+
`), HEARTBEAT_MS) };
|
|
5995
|
+
}
|
|
5996
|
+
},
|
|
5997
|
+
stop: stopTicking
|
|
5998
|
+
};
|
|
5999
|
+
}
|
|
6000
|
+
|
|
5914
6001
|
// src/follow.ts
|
|
5915
6002
|
async function followPublication(p, endpoint, o, opts) {
|
|
5916
6003
|
const derived = portalForEndpoint(endpoint);
|
|
@@ -5925,11 +6012,11 @@ async function followPublication(p, endpoint, o, opts) {
|
|
|
5925
6012
|
const refs = Object.entries(o.refs ?? {});
|
|
5926
6013
|
if (refs.length !== 1) return elsewhere("several-refs");
|
|
5927
6014
|
const [ref, commit] = refs[0];
|
|
5928
|
-
opts.log("Following it: received -> checked -> going live -> live. Ctrl-C stops watching; the publication is
|
|
6015
|
+
opts.log("Following it to live: received -> checked -> going live -> live. Ctrl-C stops watching; the publication is saved and carries on without you.");
|
|
5929
6016
|
const outcome = await p.followRun(
|
|
5930
6017
|
{ portal, repoId: o.repoId, publicationId: o.publicationId, ref, commit },
|
|
5931
6018
|
{ onStage: opts.onStage, ...opts.timeoutMs === void 0 ? {} : { timeoutMs: opts.timeoutMs }, ...opts.untilChange === true ? { untilChange: true } : {} }
|
|
5932
|
-
);
|
|
6019
|
+
).finally(() => opts.stopStages?.());
|
|
5933
6020
|
const answerable = confirmed.terminal.includes(PREPARATION);
|
|
5934
6021
|
const dir = shellWord(opts.dir);
|
|
5935
6022
|
const next = outcome.kind === "timed-out" || outcome.kind === "moving" ? { action: "follow", command: `publisher follow ${dir} --publication ${o.publicationId}${opts.untilChange === true ? " --until-change" : ""} --json` } : outcome.kind === "waiting" && answerable ? { action: "question", command: `publisher question ${dir} --json` } : void 0;
|
|
@@ -5965,13 +6052,15 @@ function shellWord(path) {
|
|
|
5965
6052
|
return /^[A-Za-z0-9_./-]+$/.test(path) ? path : `'${path.replace(/'/g, `'\\''`)}'`;
|
|
5966
6053
|
}
|
|
5967
6054
|
function stageEmitter(json, quiet) {
|
|
5968
|
-
|
|
5969
|
-
if (json) process.stdout.write(stageLine(e, true) + "\n");
|
|
5970
|
-
else if (!quiet) process.stderr.write(stageLine(e, false) + "\n");
|
|
6055
|
+
const nothing = () => {
|
|
5971
6056
|
};
|
|
6057
|
+
if (json) return { onStage: (e) => process.stdout.write(stageLine(e) + "\n"), stopStages: nothing };
|
|
6058
|
+
if (quiet) return { onStage: nothing, stopStages: nothing };
|
|
6059
|
+
const { onStage, stop } = stageReporter({ write: (s) => process.stderr.write(s), isTTY: process.stderr.isTTY === true });
|
|
6060
|
+
return { onStage, stopStages: stop };
|
|
5972
6061
|
}
|
|
5973
|
-
function stageLine(e
|
|
5974
|
-
return
|
|
6062
|
+
function stageLine(e) {
|
|
6063
|
+
return JSON.stringify({ event: "stage", stage: e.stage, word: e.word, state: e.state, at: e.at });
|
|
5975
6064
|
}
|
|
5976
6065
|
function inPortal(portal, lead, verb) {
|
|
5977
6066
|
return `${lead} ${verb} in the portal${portal === null ? "" : `: ${portal}`}.`;
|
|
@@ -5993,7 +6082,7 @@ function progressHint(r, portal, answerable = false) {
|
|
|
5993
6082
|
}
|
|
5994
6083
|
break;
|
|
5995
6084
|
case "moving": {
|
|
5996
|
-
const now = r.stages.
|
|
6085
|
+
const now = r.stages.filter((s) => s.state === "in-progress").at(-1) ?? r.stages.filter((s) => s.state !== "pending").at(-1);
|
|
5997
6086
|
return `Now: ${now?.word ?? "received"}. Run next.command to wait for the next step.`;
|
|
5998
6087
|
}
|
|
5999
6088
|
case "timed-out":
|
|
@@ -6367,7 +6456,7 @@ async function main(argv) {
|
|
|
6367
6456
|
if (e.phase === "done") process.stderr.write("\n");
|
|
6368
6457
|
};
|
|
6369
6458
|
const dirArg = (i) => (0, import_node_path8.resolve)(cmd[i] ?? ".");
|
|
6370
|
-
const following = {
|
|
6459
|
+
const following = { ...stageEmitter(json, quiet), log, untilChange: flags["until-change"] === true };
|
|
6371
6460
|
const resolutionInput = async (dir) => {
|
|
6372
6461
|
let association;
|
|
6373
6462
|
if (dir && await isGitRepo(dir)) association = (await readAssociation(dir))?.endpoint;
|