instar 1.3.931 → 1.3.932
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/messaging/slack/SlackApiClient.d.ts +8 -0
- package/dist/messaging/slack/SlackApiClient.d.ts.map +1 -1
- package/dist/messaging/slack/SlackApiClient.js +44 -2
- package/dist/messaging/slack/SlackApiClient.js.map +1 -1
- package/package.json +2 -1
- package/src/data/builtin-manifest.json +2 -2
- package/upgrades/1.3.932.md +29 -0
- package/upgrades/side-effects/slack-outbound-transport-recovery.md +14 -0
|
@@ -26,6 +26,8 @@ export interface SlackApiResponse {
|
|
|
26
26
|
export declare class SlackApiClient {
|
|
27
27
|
private botToken;
|
|
28
28
|
private appToken;
|
|
29
|
+
private consecutiveFetchFailures;
|
|
30
|
+
private dispatcher;
|
|
29
31
|
constructor(botToken: string, appToken?: string);
|
|
30
32
|
/**
|
|
31
33
|
* Call a Slack Web API method.
|
|
@@ -40,6 +42,12 @@ export declare class SlackApiClient {
|
|
|
40
42
|
/** Get the rate limit tier for a method. */
|
|
41
43
|
getTier(method: string): RateLimitTier;
|
|
42
44
|
private _callWithRetry;
|
|
45
|
+
/**
|
|
46
|
+
* Rebuild undici's connection pool after repeated network failures. A Wi‑Fi
|
|
47
|
+
* interface/DNS change can leave keep-alive sockets pinned to the old route;
|
|
48
|
+
* retrying through that pool otherwise fails for the whole outage window.
|
|
49
|
+
*/
|
|
50
|
+
private resetHttpTransport;
|
|
43
51
|
}
|
|
44
52
|
/** Typed error for Slack API failures. */
|
|
45
53
|
export declare class SlackApiError extends Error {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SlackApiClient.d.ts","sourceRoot":"","sources":["../../../src/messaging/slack/SlackApiClient.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAW,KAAK,aAAa,EAAE,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"SlackApiClient.d.ts","sourceRoot":"","sources":["../../../src/messaging/slack/SlackApiClient.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAW,KAAK,aAAa,EAAE,MAAM,YAAY,CAAC;AAIzD,MAAM,WAAW,eAAe;IAC9B,+CAA+C;IAC/C,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,6CAA6C;IAC7C,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,gBAAgB;IAC/B,EAAE,EAAE,OAAO,CAAC;IACZ,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,iBAAiB,CAAC,EAAE;QAClB,WAAW,CAAC,EAAE,MAAM,CAAC;QACrB,WAAW,CAAC,EAAE,MAAM,CAAC;KACtB,CAAC;IACF,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB;AAgBD,qBAAa,cAAc;IACzB,OAAO,CAAC,QAAQ,CAAS;IACzB,OAAO,CAAC,QAAQ,CAAgB;IAChC,OAAO,CAAC,wBAAwB,CAAK;IACrC,OAAO,CAAC,UAAU,CAAQ;gBAEd,QAAQ,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM;IAU/C;;;;;;;;OAQG;IACG,IAAI,CACR,MAAM,EAAE,MAAM,EACd,MAAM,GAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAM,EACpC,OAAO,GAAE,eAAoB,GAC5B,OAAO,CAAC,gBAAgB,CAAC;IAU5B,4CAA4C;IAC5C,OAAO,CAAC,MAAM,EAAE,MAAM,GAAG,aAAa;YAIxB,cAAc;IAgE5B;;;;OAIG;IACH,OAAO,CAAC,kBAAkB;CAU3B;AAED,0CAA0C;AAC1C,qBAAa,aAAc,SAAQ,KAAK;IACtC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,SAAS,EAAE,OAAO,CAAC;gBAEhB,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,SAAS,EAAE,OAAO;CAOpF"}
|
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
*/
|
|
10
10
|
import { getTier } from './types.js';
|
|
11
11
|
import { redactToken } from './sanitize.js';
|
|
12
|
+
import { Agent } from 'undici';
|
|
12
13
|
/** Errors that indicate the token is permanently invalid. */
|
|
13
14
|
const PERMANENT_ERRORS = new Set([
|
|
14
15
|
'invalid_auth',
|
|
@@ -20,12 +21,20 @@ const PERMANENT_ERRORS = new Set([
|
|
|
20
21
|
'missing_scope',
|
|
21
22
|
'not_authed',
|
|
22
23
|
]);
|
|
24
|
+
const FETCH_FAILURES_BEFORE_TRANSPORT_RESET = 3;
|
|
23
25
|
export class SlackApiClient {
|
|
24
26
|
botToken;
|
|
25
27
|
appToken;
|
|
28
|
+
consecutiveFetchFailures = 0;
|
|
29
|
+
dispatcher;
|
|
26
30
|
constructor(botToken, appToken) {
|
|
27
31
|
this.botToken = botToken;
|
|
28
32
|
this.appToken = appToken ?? null;
|
|
33
|
+
this.dispatcher = new Agent({
|
|
34
|
+
connections: 10,
|
|
35
|
+
keepAliveTimeout: 10_000,
|
|
36
|
+
keepAliveMaxTimeout: 30_000,
|
|
37
|
+
});
|
|
29
38
|
}
|
|
30
39
|
/**
|
|
31
40
|
* Call a Slack Web API method.
|
|
@@ -49,14 +58,32 @@ export class SlackApiClient {
|
|
|
49
58
|
return getTier(method);
|
|
50
59
|
}
|
|
51
60
|
async _callWithRetry(method, params, token, attempt, maxRetries) {
|
|
52
|
-
|
|
61
|
+
let response;
|
|
62
|
+
// Keep the recovery pool scoped to Slack requests. Rebuilding a
|
|
63
|
+
// process-global dispatcher could disrupt unrelated HTTP clients. Node's
|
|
64
|
+
// fetch honors the undici `dispatcher` init option, but the DOM-typed
|
|
65
|
+
// RequestInit doesn't declare it — declare the init with the extended type
|
|
66
|
+
// instead of casting the literal.
|
|
67
|
+
const init = {
|
|
53
68
|
method: 'POST',
|
|
54
69
|
headers: {
|
|
55
70
|
'Authorization': `Bearer ${token}`,
|
|
56
71
|
'Content-Type': 'application/json; charset=utf-8',
|
|
57
72
|
},
|
|
58
73
|
body: JSON.stringify(params),
|
|
59
|
-
}
|
|
74
|
+
};
|
|
75
|
+
init.dispatcher = this.dispatcher;
|
|
76
|
+
try {
|
|
77
|
+
response = await fetch(`https://slack.com/api/${method}`, init);
|
|
78
|
+
this.consecutiveFetchFailures = 0;
|
|
79
|
+
}
|
|
80
|
+
catch (error) {
|
|
81
|
+
this.consecutiveFetchFailures++;
|
|
82
|
+
if (this.consecutiveFetchFailures >= FETCH_FAILURES_BEFORE_TRANSPORT_RESET) {
|
|
83
|
+
this.resetHttpTransport();
|
|
84
|
+
}
|
|
85
|
+
throw error;
|
|
86
|
+
}
|
|
60
87
|
const data = (await response.json());
|
|
61
88
|
// Rate limit handling
|
|
62
89
|
if (data.error === 'ratelimited' && attempt < maxRetries) {
|
|
@@ -77,6 +104,21 @@ export class SlackApiClient {
|
|
|
77
104
|
}
|
|
78
105
|
return data;
|
|
79
106
|
}
|
|
107
|
+
/**
|
|
108
|
+
* Rebuild undici's connection pool after repeated network failures. A Wi‑Fi
|
|
109
|
+
* interface/DNS change can leave keep-alive sockets pinned to the old route;
|
|
110
|
+
* retrying through that pool otherwise fails for the whole outage window.
|
|
111
|
+
*/
|
|
112
|
+
resetHttpTransport() {
|
|
113
|
+
this.consecutiveFetchFailures = 0;
|
|
114
|
+
this.dispatcher.close().catch(() => { });
|
|
115
|
+
this.dispatcher = new Agent({
|
|
116
|
+
connections: 10,
|
|
117
|
+
keepAliveTimeout: 10_000,
|
|
118
|
+
keepAliveMaxTimeout: 30_000,
|
|
119
|
+
});
|
|
120
|
+
console.warn('[slack-api] Rebuilt HTTP transport after repeated fetch failures');
|
|
121
|
+
}
|
|
80
122
|
}
|
|
81
123
|
/** Typed error for Slack API failures. */
|
|
82
124
|
export class SlackApiError extends Error {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SlackApiClient.js","sourceRoot":"","sources":["../../../src/messaging/slack/SlackApiClient.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAE,OAAO,EAAsB,MAAM,YAAY,CAAC;AACzD,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;
|
|
1
|
+
{"version":3,"file":"SlackApiClient.js","sourceRoot":"","sources":["../../../src/messaging/slack/SlackApiClient.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAE,OAAO,EAAsB,MAAM,YAAY,CAAC;AACzD,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAC5C,OAAO,EAAE,KAAK,EAAE,MAAM,QAAQ,CAAC;AAmB/B,6DAA6D;AAC7D,MAAM,gBAAgB,GAAG,IAAI,GAAG,CAAC;IAC/B,cAAc;IACd,kBAAkB;IAClB,eAAe;IACf,eAAe;IACf,oBAAoB;IACpB,mBAAmB;IACnB,eAAe;IACf,YAAY;CACb,CAAC,CAAC;AAEH,MAAM,qCAAqC,GAAG,CAAC,CAAC;AAEhD,MAAM,OAAO,cAAc;IACjB,QAAQ,CAAS;IACjB,QAAQ,CAAgB;IACxB,wBAAwB,GAAG,CAAC,CAAC;IAC7B,UAAU,CAAQ;IAE1B,YAAY,QAAgB,EAAE,QAAiB;QAC7C,IAAI,CAAC,QAAQ,GAAG,QAAQ,CAAC;QACzB,IAAI,CAAC,QAAQ,GAAG,QAAQ,IAAI,IAAI,CAAC;QACjC,IAAI,CAAC,UAAU,GAAG,IAAI,KAAK,CAAC;YAC1B,WAAW,EAAE,EAAE;YACf,gBAAgB,EAAE,MAAM;YACxB,mBAAmB,EAAE,MAAM;SAC5B,CAAC,CAAC;IACL,CAAC;IAED;;;;;;;;OAQG;IACH,KAAK,CAAC,IAAI,CACR,MAAc,EACd,SAAkC,EAAE,EACpC,UAA2B,EAAE;QAE7B,MAAM,KAAK,GAAG,OAAO,CAAC,WAAW,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC;QAClE,IAAI,CAAC,KAAK,EAAE,CAAC;YACX,MAAM,IAAI,KAAK,CAAC,kBAAkB,OAAO,CAAC,WAAW,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,mBAAmB,CAAC,CAAC;QAC5F,CAAC;QAED,MAAM,UAAU,GAAG,OAAO,CAAC,UAAU,IAAI,CAAC,CAAC;QAC3C,OAAO,IAAI,CAAC,cAAc,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,EAAE,UAAU,CAAC,CAAC;IACnE,CAAC;IAED,4CAA4C;IAC5C,OAAO,CAAC,MAAc;QACpB,OAAO,OAAO,CAAC,MAAM,CAAC,CAAC;IACzB,CAAC;IAEO,KAAK,CAAC,cAAc,CAC1B,MAAc,EACd,MAA+B,EAC/B,KAAa,EACb,OAAe,EACf,UAAkB;QAElB,IAAI,QAAkB,CAAC;QACvB,gEAAgE;QAChE,yEAAyE;QACzE,sEAAsE;QACtE,2EAA2E;QAC3E,kCAAkC;QAClC,MAAM,IAAI,GAAyC;YACjD,MAAM,EAAE,MAAM;YACd,OAAO,EAAE;gBACP,eAAe,EAAE,UAAU,KAAK,EAAE;gBAClC,cAAc,EAAE,iCAAiC;aAClD;YACD,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC;SAC7B,CAAC;QACF,IAAI,CAAC,UAAU,GAAG,IAAI,CAAC,UAAU,CAAC;QAClC,IAAI,CAAC;YACH,QAAQ,GAAG,MAAM,KAAK,CAAC,yBAAyB,MAAM,EAAE,EAAE,IAAI,CAAC,CAAC;YAChE,IAAI,CAAC,wBAAwB,GAAG,CAAC,CAAC;QACpC,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,IAAI,CAAC,wBAAwB,EAAE,CAAC;YAChC,IAAI,IAAI,CAAC,wBAAwB,IAAI,qCAAqC,EAAE,CAAC;gBAC3E,IAAI,CAAC,kBAAkB,EAAE,CAAC;YAC5B,CAAC;YACD,MAAM,KAAK,CAAC;QACd,CAAC;QAED,MAAM,IAAI,GAAG,CAAC,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAqB,CAAC;QAEzD,sBAAsB;QACtB,IAAI,IAAI,CAAC,KAAK,KAAK,aAAa,IAAI,OAAO,GAAG,UAAU,EAAE,CAAC;YACzD,MAAM,UAAU,GAAG,QAAQ,CAAC,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,aAAa,CAAC,IAAI,GAAG,EAAE,EAAE,CAAC,CAAC;YAC5E,MAAM,IAAI,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;YAC7B,OAAO,CAAC,IAAI,CACV,+BAA+B,MAAM,UAAU,IAAI,eAAe,UAAU,cAAc,OAAO,GAAG,CAAC,IAAI,UAAU,GAAG,CACvH,CAAC;YACF,MAAM,IAAI,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,UAAU,CAAC,CAAC,EAAE,UAAU,GAAG,IAAI,CAAC,CAAC,CAAC;YACzD,OAAO,IAAI,CAAC,cAAc,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,GAAG,CAAC,EAAE,UAAU,CAAC,CAAC;QAC7E,CAAC;QAED,IAAI,CAAC,IAAI,CAAC,EAAE,EAAE,CAAC;YACb,MAAM,WAAW,GAAG,gBAAgB,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,IAAI,EAAE,CAAC,CAAC;YAC3D,MAAM,QAAQ,GAAG,WAAW,CAAC,KAAK,CAAC,CAAC;YACpC,MAAM,GAAG,GAAG,IAAI,aAAa,CAC3B,aAAa,MAAM,YAAY,IAAI,CAAC,KAAK,EAAE,EAC3C,MAAM,EACN,IAAI,CAAC,KAAK,IAAI,SAAS,EACvB,WAAW,CACZ,CAAC;YACF,IAAI,WAAW,EAAE,CAAC;gBAChB,OAAO,CAAC,KAAK,CAAC,kCAAkC,MAAM,KAAK,IAAI,CAAC,KAAK,YAAY,QAAQ,GAAG,CAAC,CAAC;YAChG,CAAC;YACD,MAAM,GAAG,CAAC;QACZ,CAAC;QAED,OAAO,IAAI,CAAC;IACd,CAAC;IAED;;;;OAIG;IACK,kBAAkB;QACxB,IAAI,CAAC,wBAAwB,GAAG,CAAC,CAAC;QAClC,IAAI,CAAC,UAAU,CAAC,KAAK,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC;QACxC,IAAI,CAAC,UAAU,GAAG,IAAI,KAAK,CAAC;YAC1B,WAAW,EAAE,EAAE;YACf,gBAAgB,EAAE,MAAM;YACxB,mBAAmB,EAAE,MAAM;SAC5B,CAAC,CAAC;QACH,OAAO,CAAC,IAAI,CAAC,kEAAkE,CAAC,CAAC;IACnF,CAAC;CACF;AAED,0CAA0C;AAC1C,MAAM,OAAO,aAAc,SAAQ,KAAK;IAC7B,MAAM,CAAS;IACf,UAAU,CAAS;IACnB,SAAS,CAAU;IAE5B,YAAY,OAAe,EAAE,MAAc,EAAE,UAAkB,EAAE,SAAkB;QACjF,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,eAAe,CAAC;QAC5B,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;QACrB,IAAI,CAAC,UAAU,GAAG,UAAU,CAAC;QAC7B,IAAI,CAAC,SAAS,GAAG,SAAS,CAAC;IAC7B,CAAC;CACF"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "instar",
|
|
3
|
-
"version": "1.3.
|
|
3
|
+
"version": "1.3.932",
|
|
4
4
|
"description": "Coherence infrastructure for self-evolving AI agents — on the Claude Code or Codex subscription you already have.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -129,6 +129,7 @@
|
|
|
129
129
|
"proper-lockfile": "^4.1.2",
|
|
130
130
|
"ssh2": "1.17.0",
|
|
131
131
|
"telegram": "^2.26.22",
|
|
132
|
+
"undici": "^6.27.0",
|
|
132
133
|
"ws": "^8.19.0",
|
|
133
134
|
"zod": "^4.3.6"
|
|
134
135
|
},
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"$schema": "./builtin-manifest.schema.json",
|
|
3
3
|
"schemaVersion": 1,
|
|
4
|
-
"generatedAt": "2026-07-
|
|
5
|
-
"instarVersion": "1.3.
|
|
4
|
+
"generatedAt": "2026-07-24T12:48:31.254Z",
|
|
5
|
+
"instarVersion": "1.3.932",
|
|
6
6
|
"entryCount": 202,
|
|
7
7
|
"entries": {
|
|
8
8
|
"hook:session-start": {
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# Upgrade Guide — vNEXT
|
|
2
|
+
|
|
3
|
+
<!-- assembled-by: assemble-next-md -->
|
|
4
|
+
<!-- bump: patch -->
|
|
5
|
+
|
|
6
|
+
## What Changed
|
|
7
|
+
|
|
8
|
+
After three consecutive network-level `fetch failed` errors, the Slack API
|
|
9
|
+
client replaces its own undici dispatcher and retries through a fresh
|
|
10
|
+
connection pool. Successful calls reset the failure streak. The recovery pool
|
|
11
|
+
is scoped to Slack requests only — unrelated HTTP clients are not affected.
|
|
12
|
+
`undici` is now a declared dependency (it was previously imported as a
|
|
13
|
+
transitive package).
|
|
14
|
+
|
|
15
|
+
## What to Tell Your User
|
|
16
|
+
|
|
17
|
+
After a laptop network change (new Wi-Fi, hotspot, VPN flip), outbound Slack
|
|
18
|
+
delivery now recovers on its own within a few failed attempts instead of
|
|
19
|
+
staying dead until a server restart. Nothing to configure.
|
|
20
|
+
|
|
21
|
+
## Summary of New Capabilities
|
|
22
|
+
|
|
23
|
+
- Slack outbound transport self-heals after network interface changes.
|
|
24
|
+
- Recovery is scoped to the Slack client's own connection pool.
|
|
25
|
+
|
|
26
|
+
## Verification
|
|
27
|
+
|
|
28
|
+
Tier 1 focused evidence: `tests/unit/slack-socket-reconnect.test.ts` — 17/17
|
|
29
|
+
passing. Slack API response and retry semantics are unchanged.
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
# Side-effects Review — Slack outbound transport recovery
|
|
2
|
+
|
|
3
|
+
## Class review
|
|
4
|
+
|
|
5
|
+
The missing standard was transport recovery after interface changes: retrying the same undici pool was not evidence of a fresh network path. The process gap was no focused fault-injection check for repeated `fetch failed` across a Wi-Fi transition.
|
|
6
|
+
|
|
7
|
+
## Decision
|
|
8
|
+
|
|
9
|
+
The client keeps normal API retry behavior. On three consecutive network fetch failures it destroys and replaces a Slack-client-owned undici dispatcher supplied per request; unrelated HTTP clients are not affected. Successful calls clear the streak.
|
|
10
|
+
|
|
11
|
+
## Evidence
|
|
12
|
+
|
|
13
|
+
- Tier 1 focused Socket Mode reconnect suite: 17/17 passing.
|
|
14
|
+
- ELI16: stale sockets are thrown away after three failed tries; the next try gets a fresh network path.
|