@gjsify/cli 0.64.3-next.261 → 0.64.4

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.
@@ -0,0 +1,72 @@
1
+ // Bounded retry for npm-side TRANSIENT failures, shared by the publish PUT and the OIDC exchange.
2
+ //
3
+ // THE INCIDENT (release run 39737673761, v0.64.3). During an npm incident the registry answered
4
+ // the FIRST PUT of the sweep (`@gjsify/adwaita-core`) with `503 {"error":"Service Unavailable"}`.
5
+ // `gjsify publish` retried only the OTP challenge, so it exited 1, `foreach --exec` threw on the
6
+ // non-zero child, and the sweep stopped with 0 of 232 packages published. The OIDC exchange
7
+ // already retried a 503 (v0.7.3, `@gjsify/process`); the PUT never did.
8
+ //
9
+ // A 5xx after a PUT may still have LANDED, so a retry is only safe because the caller treats the
10
+ // answer to the retried PUT idempotently (409 / 403 "previously published" → the republish path).
11
+ /** HTTP statuses worth retrying — npm-side transient/overload conditions. */
12
+ export const TRANSIENT_STATUSES = new Set([408, 425, 429, 500, 502, 503, 504]);
13
+ export const isTransientStatus = (status) => TRANSIENT_STATUSES.has(status);
14
+ /** Longest single wait, whether it came from the backoff or from a `Retry-After`. */
15
+ export const MAX_RETRY_DELAY_MS = 30_000;
16
+ /**
17
+ * Milliseconds a `Retry-After` header asks for: delta-seconds or an HTTP date. `undefined` when
18
+ * absent or unparseable.
19
+ */
20
+ export function parseRetryAfter(value, now = Date.now()) {
21
+ if (!value)
22
+ return undefined;
23
+ const trimmed = value.trim();
24
+ if (/^\d+(?:\.\d+)?$/.test(trimmed))
25
+ return Math.round(Number(trimmed) * 1000);
26
+ const at = Date.parse(trimmed);
27
+ return Number.isNaN(at) ? undefined : Math.max(0, at - now);
28
+ }
29
+ /** The wait before retry `attempt` (0-based): `Retry-After` if the server sent one, else doubling backoff; capped. */
30
+ export function retryDelayMs(attempt, baseMs, retryAfter) {
31
+ const asked = parseRetryAfter(retryAfter);
32
+ return Math.min(asked ?? baseMs * 2 ** attempt, MAX_RETRY_DELAY_MS);
33
+ }
34
+ /**
35
+ * Five retries at 2/4/8/16/30 s: ~60 s of patience per package. Long enough to ride out a blip,
36
+ * short enough that a real outage fails the sweep in a minute instead of stalling 232 packages
37
+ * behind it — the failure is then a red job, recovered by a re-run (`--tolerate-republish`).
38
+ */
39
+ export const DEFAULT_TRANSIENT_RETRIES = 5;
40
+ export const DEFAULT_TRANSIENT_BASE_MS = 2000;
41
+ /**
42
+ * Run `doFetch`, retrying a thrown network error or a transient status. Returns the last response
43
+ * once the budget is spent (the caller interprets the 5xx); rethrows the last network error.
44
+ */
45
+ export async function fetchWithTransientRetry(doFetch, opts = {}) {
46
+ const retries = opts.retries ?? DEFAULT_TRANSIENT_RETRIES;
47
+ const baseMs = opts.baseMs ?? DEFAULT_TRANSIENT_BASE_MS;
48
+ const sleep = opts.sleep ?? ((ms) => new Promise((r) => setTimeout(r, ms)));
49
+ for (let attempt = 0;; attempt++) {
50
+ let response;
51
+ let failure;
52
+ try {
53
+ response = await doFetch();
54
+ }
55
+ catch (err) {
56
+ failure = err;
57
+ }
58
+ if (response && !isTransientStatus(response.status))
59
+ return { response, retried: attempt };
60
+ if (attempt >= retries) {
61
+ if (response)
62
+ return { response, retried: attempt };
63
+ throw failure;
64
+ }
65
+ const delay = retryDelayMs(attempt, baseMs, response?.headers.get('retry-after'));
66
+ const what = response
67
+ ? `${response.status} ${response.statusText}`
68
+ : `network error: ${failure instanceof Error ? failure.message : String(failure)}`;
69
+ opts.log?.(`transient ${what} (attempt ${attempt + 1}/${retries + 1}), retrying in ${delay}ms`);
70
+ await sleep(delay);
71
+ }
72
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gjsify/cli",
3
- "version": "0.64.3-next.261",
3
+ "version": "0.64.4",
4
4
  "description": "CLI for Gjsify",
5
5
  "type": "module",
6
6
  "main": "lib/index.js",
@@ -142,22 +142,22 @@
142
142
  "cli"
143
143
  ],
144
144
  "dependencies": {
145
- "@gjsify/blueprint": "0.64.3-next.261",
146
- "@gjsify/buffer": "0.64.3-next.261",
147
- "@gjsify/create-app": "0.64.3-next.261",
148
- "@gjsify/node-globals": "0.64.3-next.261",
149
- "@gjsify/node-polyfills": "0.64.3-next.261",
150
- "@gjsify/npm-registry": "0.64.3-next.261",
151
- "@gjsify/resolve-npm": "0.64.3-next.261",
152
- "@gjsify/rolldown-plugin-gjsify": "0.64.3-next.261",
153
- "@gjsify/vite-plugin-blueprint": "0.64.3-next.261",
154
- "@gjsify/rolldown-plugin-pnp": "0.64.3-next.261",
155
- "@gjsify/semver": "0.64.3-next.261",
156
- "@gjsify/tar": "0.64.3-next.261",
157
- "@gjsify/tsc": "0.64.3-next.261",
158
- "@gjsify/utils": "0.64.3-next.261",
159
- "@gjsify/web-polyfills": "0.64.3-next.261",
160
- "@gjsify/workspace": "0.64.3-next.261",
145
+ "@gjsify/blueprint": "^0.64.4",
146
+ "@gjsify/buffer": "^0.64.4",
147
+ "@gjsify/create-app": "^0.64.4",
148
+ "@gjsify/node-globals": "^0.64.4",
149
+ "@gjsify/node-polyfills": "^0.64.4",
150
+ "@gjsify/npm-registry": "^0.64.4",
151
+ "@gjsify/resolve-npm": "^0.64.4",
152
+ "@gjsify/rolldown-plugin-gjsify": "^0.64.4",
153
+ "@gjsify/vite-plugin-blueprint": "^0.64.4",
154
+ "@gjsify/rolldown-plugin-pnp": "^0.64.4",
155
+ "@gjsify/semver": "^0.64.4",
156
+ "@gjsify/tar": "^0.64.4",
157
+ "@gjsify/tsc": "^0.64.4",
158
+ "@gjsify/utils": "^0.64.4",
159
+ "@gjsify/web-polyfills": "^0.64.4",
160
+ "@gjsify/workspace": "^0.64.4",
161
161
  "acorn": "^8.17.0",
162
162
  "cosmiconfig": "^9.0.2",
163
163
  "get-tsconfig": "^4.14.0",
@@ -166,13 +166,13 @@
166
166
  "yargs": "^18.0.0"
167
167
  },
168
168
  "devDependencies": {
169
- "@gjsify/unit": "0.64.3-next.261",
169
+ "@gjsify/unit": "^0.64.4",
170
170
  "@types/yargs": "^17.0.35",
171
171
  "typescript": "^6.0.3"
172
172
  },
173
173
  "peerDependencies": {
174
- "@gjsify/oxfmt-native": "0.64.3-next.261",
175
- "@gjsify/rolldown-native": "0.64.3-next.261"
174
+ "@gjsify/oxfmt-native": "^0.64.4",
175
+ "@gjsify/rolldown-native": "^0.64.4"
176
176
  },
177
177
  "peerDependenciesMeta": {
178
178
  "@gjsify/oxfmt-native": {
@@ -191,6 +191,5 @@
191
191
  "bugs": {
192
192
  "url": "https://github.com/gjsify/gjsify/issues"
193
193
  },
194
- "homepage": "https://github.com/gjsify/gjsify/tree/main/packages/infra/cli#readme",
195
- "gitHead": "886de21be840429ce043cdbf8195172530e230d4"
194
+ "homepage": "https://github.com/gjsify/gjsify/tree/main/packages/infra/cli#readme"
196
195
  }