mnfst-publish 0.1.9 → 0.1.11
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/manifest.publish.mjs +30 -4
- package/package.json +1 -1
package/manifest.publish.mjs
CHANGED
|
@@ -301,7 +301,15 @@ export function collectFiles(root, outputDir) {
|
|
|
301
301
|
// .manifestignore applies ON TOP of gitignore, so a versioned file can still be
|
|
302
302
|
// kept out of the published bundle.
|
|
303
303
|
const publishIgnored = loadPublishIgnore(root);
|
|
304
|
-
return rels
|
|
304
|
+
return rels
|
|
305
|
+
.filter((r) => !isExcludedPath(r) && !publishIgnored(r))
|
|
306
|
+
// `git ls-files -c` reports paths from the index, not the working tree — a file
|
|
307
|
+
// committed once (e.g. an old build's <locale>/docs/** output) then deleted on
|
|
308
|
+
// disk without `git rm` still shows up here. Ship what's actually there; a
|
|
309
|
+
// stale tracked-but-missing path would otherwise crash buildZip with ENOENT
|
|
310
|
+
// (seen with mnfst-publish --no-render after a re-render dropped locale
|
|
311
|
+
// variants under an excluded route prefix).
|
|
312
|
+
.filter((r) => existsSync(join(root, r)));
|
|
305
313
|
}
|
|
306
314
|
|
|
307
315
|
// --- Upload + publish status ------------------------------------------------
|
|
@@ -313,8 +321,12 @@ export function collectFiles(root, outputDir) {
|
|
|
313
321
|
// A server that predates this ignores the header and answers synchronously with
|
|
314
322
|
// {ok:true}; both are handled below.
|
|
315
323
|
const POLL_FIRST_MS = 1000;
|
|
316
|
-
const POLL_MAX_MS =
|
|
324
|
+
const POLL_MAX_MS = 2000;
|
|
317
325
|
const POLL_TOTAL_MS = 10 * 60 * 1000;
|
|
326
|
+
/* Ingest advances a bounded slice per status poll, so polls that observe the
|
|
327
|
+
`written` counter climbing must never give up: the overall cap applies only
|
|
328
|
+
while NO progress is being made. */
|
|
329
|
+
const NO_PROGRESS_MS = 10 * 60 * 1000;
|
|
318
330
|
// A status read that stays "pending" this long means the bundle never actually
|
|
319
331
|
// arrived. The grace matters because the server's token record is eventually
|
|
320
332
|
// consistent, so a brief stale "pending" right after an upload is normal.
|
|
@@ -353,6 +365,8 @@ export async function pollPublishStatus(statusUrl, opts = {}) {
|
|
|
353
365
|
const started = now();
|
|
354
366
|
let delay = POLL_FIRST_MS;
|
|
355
367
|
let lastProgress = started;
|
|
368
|
+
let lastWritten = -1;
|
|
369
|
+
let lastAdvance = started;
|
|
356
370
|
|
|
357
371
|
for (;;) {
|
|
358
372
|
let status = 0;
|
|
@@ -380,11 +394,22 @@ export async function pollPublishStatus(statusUrl, opts = {}) {
|
|
|
380
394
|
if (json && json.status === 'pending' && now() - started >= pendingGraceMs) {
|
|
381
395
|
return { state: 'pending', body: json };
|
|
382
396
|
}
|
|
397
|
+
// An HTTP error body that skips the {status:'error'} tag entirely (a plain
|
|
398
|
+
// {error, message} shape, same as an upload-time rejection) is still a
|
|
399
|
+
// settled failure, not a blip — UNLESS it's 429 (rate limited) or a 5xx,
|
|
400
|
+
// both of which are expected to be transient and worth retrying.
|
|
401
|
+
if (json && json.error && !json.status && status >= 400 && status !== 429 && status < 500) {
|
|
402
|
+
return { state: 'error', body: json };
|
|
403
|
+
}
|
|
383
404
|
// Anything else (ingesting, pending inside the grace, 429, 5xx, a blip) —
|
|
384
405
|
// keep waiting.
|
|
385
406
|
|
|
386
407
|
const elapsed = now() - started;
|
|
387
|
-
if (
|
|
408
|
+
if (json && typeof json.written === 'number' && json.written > lastWritten) {
|
|
409
|
+
lastWritten = json.written;
|
|
410
|
+
lastAdvance = now();
|
|
411
|
+
}
|
|
412
|
+
if (now() - lastAdvance >= Math.min(totalMs, NO_PROGRESS_MS)) return { state: 'timeout' };
|
|
388
413
|
if (elapsed - (lastProgress - started) >= PROGRESS_EVERY_MS) {
|
|
389
414
|
lastProgress = now();
|
|
390
415
|
logFn(` still publishing… (${Math.round(elapsed / 1000)}s)`);
|
|
@@ -399,7 +424,8 @@ function settledPayload(res) {
|
|
|
399
424
|
if (res.state === 'done') return res.body;
|
|
400
425
|
if (res.state === 'error') {
|
|
401
426
|
const b = res.body || {};
|
|
402
|
-
|
|
427
|
+
const retrySafe = b.error === 'retry_upload' ? ' Re-running the same command is safe and cheap — nothing was double-charged or double-shipped.' : '';
|
|
428
|
+
throw new Error(`publish failed${b.error ? ` (${b.error})` : ''}: ${b.message || 'the server rejected the upload.'}${retrySafe}`);
|
|
403
429
|
}
|
|
404
430
|
if (res.state === 'unknown') {
|
|
405
431
|
throw new Error('this publish link expired before the upload finished. Run the publish again.');
|