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 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 > workerBuilt + 60_000) {
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 }, { label: `upload ${t.path}` });
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "shiply-cli",
3
- "version": "0.27.0",
3
+ "version": "0.27.2",
4
4
  "description": "Publish static sites to shiply.now from the command line \u00e2\u20ac\u201d instant web hosting for agents.",
5
5
  "license": "MIT",
6
6
  "type": "module",