instar 1.3.253 → 1.3.254
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/tunnel/CloudflareQuickProvider.d.ts +9 -0
- package/dist/tunnel/CloudflareQuickProvider.d.ts.map +1 -1
- package/dist/tunnel/CloudflareQuickProvider.js +34 -14
- package/dist/tunnel/CloudflareQuickProvider.js.map +1 -1
- package/package.json +1 -1
- package/src/data/builtin-manifest.json +2 -2
- package/upgrades/1.3.254.md +42 -0
- package/upgrades/side-effects/quick-tunnel-stderr-capture.md +63 -0
|
@@ -32,6 +32,15 @@ export interface CloudflareQuickProviderOptions {
|
|
|
32
32
|
/** Start timeout in milliseconds (default: 30_000). */
|
|
33
33
|
startTimeoutMs?: number;
|
|
34
34
|
}
|
|
35
|
+
/**
|
|
36
|
+
* Classify a cloudflared quick-tunnel failure into a fixed-substring reason the
|
|
37
|
+
* TunnelManager parses to a ProviderFailureReason. Pure + exported so the
|
|
38
|
+
* decision boundary (esp. the Cloudflare 429/1015 rate-limit detection) is
|
|
39
|
+
* unit-testable. Depends on the caller having captured cloudflared's real stderr
|
|
40
|
+
* (the 'stderr' event) into `stderr` — otherwise the rate-limit text never
|
|
41
|
+
* reaches the haystack and the classification falls through to generic.
|
|
42
|
+
*/
|
|
43
|
+
export declare function classifyQuickTunnelError(msg: string, stderr: string): Error;
|
|
35
44
|
export declare class CloudflareQuickProvider implements TunnelProvider {
|
|
36
45
|
readonly name: ProviderName;
|
|
37
46
|
readonly tier: ProviderTier;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CloudflareQuickProvider.d.ts","sourceRoot":"","sources":["../../src/tunnel/CloudflareQuickProvider.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AAKH,OAAO,KAAK,EACV,cAAc,EACd,oBAAoB,EACpB,YAAY,EACZ,YAAY,EACb,MAAM,qBAAqB,CAAC;AAE7B,MAAM,WAAW,8BAA8B;IAC7C,4BAA4B;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,kEAAkE;IAClE,QAAQ,EAAE,MAAM,CAAC;IACjB,uDAAuD;IACvD,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAED,qBAAa,uBAAwB,YAAW,cAAc;IAC5D,QAAQ,CAAC,IAAI,EAAE,YAAY,CAAsB;IACjD,QAAQ,CAAC,IAAI,EAAE,YAAY,CAAK;IAEhC,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAS;IAC9B,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAS;IAClC,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAS;gBAE5B,IAAI,EAAE,8BAA8B;IAM1C,WAAW,IAAI,OAAO,CAAC,OAAO,CAAC;IAQrC,KAAK,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,oBAAoB,CAAC;YASzC,UAAU;
|
|
1
|
+
{"version":3,"file":"CloudflareQuickProvider.d.ts","sourceRoot":"","sources":["../../src/tunnel/CloudflareQuickProvider.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AAKH,OAAO,KAAK,EACV,cAAc,EACd,oBAAoB,EACpB,YAAY,EACZ,YAAY,EACb,MAAM,qBAAqB,CAAC;AAE7B,MAAM,WAAW,8BAA8B;IAC7C,4BAA4B;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,kEAAkE;IAClE,QAAQ,EAAE,MAAM,CAAC;IACjB,uDAAuD;IACvD,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAED;;;;;;;GAOG;AACH,wBAAgB,wBAAwB,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,KAAK,CAc3E;AAED,qBAAa,uBAAwB,YAAW,cAAc;IAC5D,QAAQ,CAAC,IAAI,EAAE,YAAY,CAAsB;IACjD,QAAQ,CAAC,IAAI,EAAE,YAAY,CAAK;IAEhC,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAS;IAC9B,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAS;IAClC,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAS;gBAE5B,IAAI,EAAE,8BAA8B;IAM1C,WAAW,IAAI,OAAO,CAAC,OAAO,CAAC;IAQrC,KAAK,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,oBAAoB,CAAC;YASzC,UAAU;IAwGxB,OAAO,CAAC,aAAa;YAIP,UAAU;CAmCzB"}
|
|
@@ -26,6 +26,29 @@
|
|
|
26
26
|
import fs from 'node:fs';
|
|
27
27
|
import path from 'node:path';
|
|
28
28
|
import { bin, install, Tunnel } from 'cloudflared';
|
|
29
|
+
/**
|
|
30
|
+
* Classify a cloudflared quick-tunnel failure into a fixed-substring reason the
|
|
31
|
+
* TunnelManager parses to a ProviderFailureReason. Pure + exported so the
|
|
32
|
+
* decision boundary (esp. the Cloudflare 429/1015 rate-limit detection) is
|
|
33
|
+
* unit-testable. Depends on the caller having captured cloudflared's real stderr
|
|
34
|
+
* (the 'stderr' event) into `stderr` — otherwise the rate-limit text never
|
|
35
|
+
* reaches the haystack and the classification falls through to generic.
|
|
36
|
+
*/
|
|
37
|
+
export function classifyQuickTunnelError(msg, stderr) {
|
|
38
|
+
const haystack = `${msg} ${stderr}`.toLowerCase();
|
|
39
|
+
// Cloudflare's quick-tunnel rate-limit surfaces as 429 / error 1015.
|
|
40
|
+
if (haystack.includes('429') || haystack.includes('1015') || haystack.includes('rate limit') || haystack.includes('too many requests')) {
|
|
41
|
+
return new Error(`rate-limited: cloudflared quick-tunnel rate-limited (${msg})`);
|
|
42
|
+
}
|
|
43
|
+
if (haystack.includes('enoent') || haystack.includes('not found') || haystack.includes('binary-missing')) {
|
|
44
|
+
return new Error(`binary-missing: ${msg}`);
|
|
45
|
+
}
|
|
46
|
+
if (haystack.includes('dns') || haystack.includes('eai_again') || haystack.includes('econnrefused') || haystack.includes('network')) {
|
|
47
|
+
return new Error(`network: ${msg}`);
|
|
48
|
+
}
|
|
49
|
+
// Preserve as-is so the manager's classifier sees the original prefix.
|
|
50
|
+
return new Error(msg);
|
|
51
|
+
}
|
|
29
52
|
export class CloudflareQuickProvider {
|
|
30
53
|
name = 'cloudflare-quick';
|
|
31
54
|
tier = 1;
|
|
@@ -100,6 +123,16 @@ export class CloudflareQuickProvider {
|
|
|
100
123
|
reject(new Error('timeout: cloudflared quick tunnel did not emit a URL within the start budget'));
|
|
101
124
|
}
|
|
102
125
|
}, this.startTimeoutMs);
|
|
126
|
+
// Capture cloudflared's REAL stderr. The `cloudflared` wrapper emits a
|
|
127
|
+
// 'stderr' event per child stderr line (incl. the "429 Too Many Requests /
|
|
128
|
+
// error code 1015" rate-limit line). Without listening here, stderrTail
|
|
129
|
+
// stayed empty → 'exit' logged "no stderr captured" → classifyError's
|
|
130
|
+
// 429/1015 detection was DEAD for the exit path, so the manager could never
|
|
131
|
+
// recognize (or back off on) a Cloudflare rate-limit. (Found live 2026-05-31:
|
|
132
|
+
// a quick tunnel 429'd but surfaced only as opaque "process-exit code 1".)
|
|
133
|
+
tunnel.on('stderr', (data) => {
|
|
134
|
+
stderrTail = (stderrTail + ' ' + data).slice(-2000);
|
|
135
|
+
});
|
|
103
136
|
tunnel.once('url', (url) => {
|
|
104
137
|
if (resolved)
|
|
105
138
|
return;
|
|
@@ -140,20 +173,7 @@ export class CloudflareQuickProvider {
|
|
|
140
173
|
void urlEmitted;
|
|
141
174
|
}
|
|
142
175
|
classifyError(msg, stderr) {
|
|
143
|
-
|
|
144
|
-
// Cloudflare's quick-tunnel rate-limit surfaces as 429 / error 1015.
|
|
145
|
-
// Both substrings appear in cloudflared's stderr on rate-limit.
|
|
146
|
-
if (haystack.includes('429') || haystack.includes('1015') || haystack.includes('rate limit') || haystack.includes('too many requests')) {
|
|
147
|
-
return new Error(`rate-limited: cloudflared quick-tunnel rate-limited (${msg})`);
|
|
148
|
-
}
|
|
149
|
-
if (haystack.includes('enoent') || haystack.includes('not found') || haystack.includes('binary-missing')) {
|
|
150
|
-
return new Error(`binary-missing: ${msg}`);
|
|
151
|
-
}
|
|
152
|
-
if (haystack.includes('dns') || haystack.includes('eai_again') || haystack.includes('econnrefused') || haystack.includes('network')) {
|
|
153
|
-
return new Error(`network: ${msg}`);
|
|
154
|
-
}
|
|
155
|
-
// Preserve as-is so the manager's classifier sees the original prefix.
|
|
156
|
-
return new Error(msg);
|
|
176
|
+
return classifyQuickTunnelError(msg, stderr);
|
|
157
177
|
}
|
|
158
178
|
async stopHandle(tunnel) {
|
|
159
179
|
// Force-stop with PID escalation, mirroring TunnelManager.forceStop's
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CloudflareQuickProvider.js","sourceRoot":"","sources":["../../src/tunnel/CloudflareQuickProvider.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"CloudflareQuickProvider.js","sourceRoot":"","sources":["../../src/tunnel/CloudflareQuickProvider.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"$schema": "./builtin-manifest.schema.json",
|
|
3
3
|
"schemaVersion": 1,
|
|
4
|
-
"generatedAt": "2026-06-04T23:
|
|
5
|
-
"instarVersion": "1.3.
|
|
4
|
+
"generatedAt": "2026-06-04T23:23:29.388Z",
|
|
5
|
+
"instarVersion": "1.3.254",
|
|
6
6
|
"entryCount": 198,
|
|
7
7
|
"entries": {
|
|
8
8
|
"hook:session-start": {
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
# Upgrade Guide — vNEXT
|
|
2
|
+
|
|
3
|
+
<!-- assembled-by: assemble-next-md -->
|
|
4
|
+
<!-- bump: patch -->
|
|
5
|
+
|
|
6
|
+
## What Changed
|
|
7
|
+
|
|
8
|
+
**Quick tunnels now correctly recognize when Cloudflare is rate-limiting them.**
|
|
9
|
+
When the zero-config quick tunnel failed because Cloudflare's free tunnel service
|
|
10
|
+
returned "429 Too Many Requests", instar only saw an opaque "process exited" with
|
|
11
|
+
no detail — it couldn't tell a rate-limit apart from any other failure, so it
|
|
12
|
+
couldn't react appropriately. The provider now captures cloudflared's real error
|
|
13
|
+
output, so a rate-limit is identified as exactly that and handed to the tunnel
|
|
14
|
+
manager's failure handling with the right reason.
|
|
15
|
+
|
|
16
|
+
## What to Tell Your User
|
|
17
|
+
|
|
18
|
+
Nothing to configure. If your quick tunnel ever gets rate-limited by Cloudflare,
|
|
19
|
+
instar now recognizes it as a rate-limit (instead of a generic failure), which
|
|
20
|
+
lets it respond more sensibly under that degraded condition. Named tunnels and
|
|
21
|
+
the healthy path are unaffected.
|
|
22
|
+
|
|
23
|
+
## Summary of New Capabilities
|
|
24
|
+
|
|
25
|
+
- `classifyQuickTunnelError(msg, stderr)` — pure, exported, unit-tested
|
|
26
|
+
classifier mapping a cloudflared failure to a fixed reason
|
|
27
|
+
(rate-limited / binary-missing / network / passthrough).
|
|
28
|
+
- `CloudflareQuickProvider` now listens to the cloudflared wrapper's `stderr`
|
|
29
|
+
event, so the rate-limit text actually reaches the classifier (it never did
|
|
30
|
+
before, which made the 429 detection dead on the process-exit path).
|
|
31
|
+
|
|
32
|
+
## Evidence
|
|
33
|
+
|
|
34
|
+
- Found live (2026-05-31): a quick tunnel hit Cloudflare 429, but instar
|
|
35
|
+
surfaced only "process-exit code 1: no stderr captured"; the 429 was visible
|
|
36
|
+
only by running cloudflared directly.
|
|
37
|
+
- Tests: `tests/unit/CloudflareQuickProvider.test.ts` (6) — the classifier
|
|
38
|
+
across all reason branches, plus a mock-cloudflared test proving the new
|
|
39
|
+
stderr listener feeds a 429 line into the classifier so start() rejects with
|
|
40
|
+
rate-limited. `tsc --noEmit` clean.
|
|
41
|
+
- Spec: tunnel-failure-resilience (the manager's single-owner failure handling
|
|
42
|
+
this classification feeds).
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
# Side effects — quick-tunnel captures cloudflared stderr (429 detection)
|
|
2
|
+
|
|
3
|
+
## What was broken
|
|
4
|
+
|
|
5
|
+
`CloudflareQuickProvider` (the Tier-1 zero-config quick tunnel) classified
|
|
6
|
+
failures via `classifyError(msg, stderr)`, whose rate-limit branch checks the
|
|
7
|
+
text for `429` / `1015` / "rate limit" / "too many requests". But the provider
|
|
8
|
+
listened only to the cloudflared wrapper's `url` / `error` / `exit` events — it
|
|
9
|
+
**never listened to the wrapper's `stderr` event**, which is the only place
|
|
10
|
+
cloudflared's real stderr (including the `429 Too Many Requests` / `error code
|
|
11
|
+
1015` rate-limit line) is delivered. So `stderrTail` stayed empty, `exit` logged
|
|
12
|
+
the opaque `process-exit code 1: no stderr captured`, and the 429 branch was
|
|
13
|
+
**dead code on the exit path** — the manager could never recognize (or back off
|
|
14
|
+
on / surface) a Cloudflare rate-limit.
|
|
15
|
+
|
|
16
|
+
Found live (2026-05-31): a quick-tunnel start hit Cloudflare 429, but instar
|
|
17
|
+
surfaced only "process-exit code 1: no stderr captured"; the 429 was visible
|
|
18
|
+
only by running `cloudflared tunnel --url` directly.
|
|
19
|
+
|
|
20
|
+
## The fix
|
|
21
|
+
|
|
22
|
+
1. `CloudflareQuickProvider.startInner` now registers
|
|
23
|
+
`tunnel.on('stderr', (data) => { stderrTail = (stderrTail + ' ' + data).slice(-2000); })`,
|
|
24
|
+
capturing cloudflared's real stderr (bounded to the last 2000 chars). The
|
|
25
|
+
existing `error`/`exit` handlers already feed `stderrTail` into the
|
|
26
|
+
classifier, so the 429/1015 text now reaches it.
|
|
27
|
+
2. The classification logic is extracted to a pure, exported
|
|
28
|
+
`classifyQuickTunnelError(msg, stderr)` (unchanged behavior), so the
|
|
29
|
+
decision boundary is unit-testable.
|
|
30
|
+
|
|
31
|
+
## Who is affected
|
|
32
|
+
|
|
33
|
+
- **Any agent with a quick tunnel that hits Cloudflare 429** (the free
|
|
34
|
+
trycloudflare service rate-limits under load): the failure is now classified
|
|
35
|
+
`rate-limited:` instead of opaque `process-exit`, so the TunnelManager's
|
|
36
|
+
failure handling (per the tunnel-failure-resilience spec) acts on the correct
|
|
37
|
+
reason. No behavior change on the success path or for non-rate-limited
|
|
38
|
+
failures (those classify exactly as before).
|
|
39
|
+
|
|
40
|
+
## Blast radius
|
|
41
|
+
|
|
42
|
+
- 1 source file: `src/tunnel/CloudflareQuickProvider.ts` (one added event
|
|
43
|
+
listener + a pure-function extraction). No config, no schema, no migration —
|
|
44
|
+
picked up by existing agents on the normal dist update. The TunnelManager,
|
|
45
|
+
other providers, and the success path are untouched.
|
|
46
|
+
|
|
47
|
+
## Failure modes considered
|
|
48
|
+
|
|
49
|
+
- **Listener fires after resolution?** Harmless — it only appends to a bounded
|
|
50
|
+
buffer; once `url` resolves, the buffer is unused.
|
|
51
|
+
- **stderr never arrives (true silent exit)?** Behavior is exactly as before:
|
|
52
|
+
`stderrTail` empty → `exit` logs "no stderr captured" → classified generic.
|
|
53
|
+
The fix can only ADD signal, never remove it.
|
|
54
|
+
- **Buffer growth?** Bounded to the last 2000 chars via `.slice(-2000)`.
|
|
55
|
+
|
|
56
|
+
## Tests
|
|
57
|
+
|
|
58
|
+
`tests/unit/CloudflareQuickProvider.test.ts` (6): `classifyQuickTunnelError`
|
|
59
|
+
across 429/1015/"too many requests"/"rate limit", ENOENT→binary-missing,
|
|
60
|
+
DNS/ECONNREFUSED→network, and unrecognized→preserved; plus a mock-`cloudflared`
|
|
61
|
+
test proving the new `stderr` listener feeds a 429 stderr line into the
|
|
62
|
+
classifier so `start()` rejects `rate-limited` (rather than the opaque
|
|
63
|
+
`process-exit`). `tsc --noEmit` clean.
|