shiply-cli 0.27.0 → 0.27.2
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/preflight.js +7 -2
- package/dist/publish.js +12 -3
- package/package.json +1 -1
package/dist/preflight.js
CHANGED
|
@@ -106,7 +106,11 @@ export async function runNextPreflight(dir) {
|
|
|
106
106
|
}
|
|
107
107
|
// -- missing-build / stale-build-state: never publish raw Next SOURCE as a
|
|
108
108
|
// static site (today's silent worst case), and warn when the app was
|
|
109
|
-
// rebuilt but the worker bundle wasn't.
|
|
109
|
+
// rebuilt but the worker bundle wasn't. Presence-check worker.js, but
|
|
110
|
+
// compare freshness against handler.mjs — worker.js is a TEMPLATE the
|
|
111
|
+
// OpenNext build copies with its package-install mtime preserved
|
|
112
|
+
// (observed 26h stale on a fresh build); handler.mjs is genuinely
|
|
113
|
+
// regenerated every bundling run.
|
|
110
114
|
const workerBuilt = await mtimeMs(join(dir, '.open-next', 'worker.js'));
|
|
111
115
|
if (!isStaticExport) {
|
|
112
116
|
if (workerBuilt === null) {
|
|
@@ -119,8 +123,9 @@ export async function runNextPreflight(dir) {
|
|
|
119
123
|
});
|
|
120
124
|
}
|
|
121
125
|
else {
|
|
126
|
+
const bundled = await mtimeMs(join(dir, '.open-next', 'server-functions', 'default', 'handler.mjs'));
|
|
122
127
|
const appBuilt = await mtimeMs(join(dir, '.next', 'BUILD_ID'));
|
|
123
|
-
if (appBuilt !== null && appBuilt >
|
|
128
|
+
if (bundled !== null && appBuilt !== null && appBuilt > bundled + 60_000) {
|
|
124
129
|
findings.push({
|
|
125
130
|
id: 'stale-build-state',
|
|
126
131
|
level: 'warn',
|
package/dist/publish.js
CHANGED
|
@@ -21,11 +21,17 @@ const sleep = (ms) => new Promise((r) => setTimeout(r, ms));
|
|
|
21
21
|
const backoffMs = (attempt) => Math.min(8000, 500 * 2 ** attempt) + Math.floor(Math.random() * 250);
|
|
22
22
|
/** fetch() with a per-attempt timeout + retry-with-backoff on transient failures
|
|
23
23
|
* (network errors, aborts/timeouts, and 5xx gateway statuses). Bodies here are
|
|
24
|
-
* strings/Buffers, so re-sending on retry is safe.
|
|
24
|
+
* strings/Buffers, so re-sending on retry is safe.
|
|
25
|
+
*
|
|
26
|
+
* `alsoRetry`: extra statuses the CALLER knows are safe to retry. The global
|
|
27
|
+
* set excludes 500 to protect non-idempotent creates — but an idempotent
|
|
28
|
+
* presigned PUT (upload) SHOULD retry a 500 (observed: R2 throws transient
|
|
29
|
+
* 500s mid-publish; without this, one blip failed the whole publish). */
|
|
25
30
|
export async function fetchWithRetry(url, init, opts = {}) {
|
|
26
31
|
const attempts = opts.attempts ?? 4;
|
|
27
32
|
const timeoutMs = opts.timeoutMs ?? 60_000;
|
|
28
33
|
const label = opts.label ?? url;
|
|
34
|
+
const alsoRetry = new Set(opts.alsoRetry ?? []);
|
|
29
35
|
let lastErr;
|
|
30
36
|
for (let i = 0; i < attempts; i++) {
|
|
31
37
|
const ac = new AbortController();
|
|
@@ -33,7 +39,7 @@ export async function fetchWithRetry(url, init, opts = {}) {
|
|
|
33
39
|
try {
|
|
34
40
|
const res = await fetch(url, { ...init, signal: ac.signal });
|
|
35
41
|
clearTimeout(timer);
|
|
36
|
-
if (TRANSIENT_STATUS.has(res.status) && i < attempts - 1) {
|
|
42
|
+
if ((TRANSIENT_STATUS.has(res.status) || alsoRetry.has(res.status)) && i < attempts - 1) {
|
|
37
43
|
process.stderr.write(` ↻ ${label} returned ${res.status} — retrying (${i + 2}/${attempts})…\n`);
|
|
38
44
|
await sleep(backoffMs(i));
|
|
39
45
|
continue;
|
|
@@ -235,7 +241,10 @@ async function uploadAll(dir, targets) {
|
|
|
235
241
|
while (next < targets.length) {
|
|
236
242
|
const t = targets[next++];
|
|
237
243
|
const body = await readFile(join(dir, t.path));
|
|
238
|
-
const res = await fetchWithRetry(t.url, { method: t.method, headers: t.headers, body },
|
|
244
|
+
const res = await fetchWithRetry(t.url, { method: t.method, headers: t.headers, body },
|
|
245
|
+
// Presigned object PUT = idempotent → a transient 500 (R2 does throw
|
|
246
|
+
// them) must be retried, not fail the whole publish.
|
|
247
|
+
{ label: `upload ${t.path}`, alsoRetry: [500] });
|
|
239
248
|
if (!res.ok) {
|
|
240
249
|
if (res.status === 403) {
|
|
241
250
|
throw new Error(`upload failed for ${t.path}: HTTP 403 — presigned URLs likely expired ` +
|
package/package.json
CHANGED