catelog 1.0.1 → 1.0.3
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/DECISION.md +183 -183
- package/README.md +98 -74
- package/USAGE.md +958 -0
- package/dist/adapters.d.ts +114 -0
- package/dist/adapters.d.ts.map +1 -0
- package/dist/adapters.js +347 -0
- package/dist/adapters.js.map +1 -0
- package/dist/agent.d.ts +73 -13
- package/dist/agent.d.ts.map +1 -1
- package/dist/agent.js +373 -154
- package/dist/agent.js.map +1 -1
- package/dist/banner.d.ts +6 -3
- package/dist/banner.d.ts.map +1 -1
- package/dist/banner.js +29 -18
- package/dist/banner.js.map +1 -1
- package/dist/context.d.ts +18 -0
- package/dist/context.d.ts.map +1 -0
- package/dist/context.js +82 -0
- package/dist/context.js.map +1 -0
- package/dist/index.d.ts +9 -6
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +24 -6
- package/dist/index.js.map +1 -1
- package/dist/security.d.ts +25 -16
- package/dist/security.d.ts.map +1 -1
- package/dist/security.js +132 -55
- package/dist/security.js.map +1 -1
- package/dist/server.d.ts +2 -2
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +8 -3
- package/dist/server.js.map +1 -1
- package/dist/sse.d.ts +31 -7
- package/dist/sse.d.ts.map +1 -1
- package/dist/sse.js +94 -26
- package/dist/sse.js.map +1 -1
- package/dist/telemetry.d.ts +41 -0
- package/dist/telemetry.d.ts.map +1 -0
- package/dist/telemetry.js +93 -0
- package/dist/telemetry.js.map +1 -0
- package/dist/types.d.ts +115 -27
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +4 -0
- package/dist/types.js.map +1 -1
- package/package.json +2 -1
package/dist/security.js
CHANGED
|
@@ -1,4 +1,7 @@
|
|
|
1
|
-
import { createHash, createHmac, timingSafeEqual } from "node:crypto";
|
|
1
|
+
import { createHash, createHmac, timingSafeEqual, randomUUID } from "node:crypto";
|
|
2
|
+
// ─────────────────────────────────────────────────
|
|
3
|
+
// Errors
|
|
4
|
+
// ─────────────────────────────────────────────────
|
|
2
5
|
export class SecurityVerificationError extends Error {
|
|
3
6
|
code;
|
|
4
7
|
statusCode;
|
|
@@ -9,82 +12,150 @@ export class SecurityVerificationError extends Error {
|
|
|
9
12
|
this.name = "SecurityVerificationError";
|
|
10
13
|
}
|
|
11
14
|
}
|
|
15
|
+
// ─────────────────────────────────────────────────
|
|
16
|
+
// SecurityManager
|
|
17
|
+
// ─────────────────────────────────────────────────
|
|
12
18
|
export class SecurityManager {
|
|
13
19
|
secret;
|
|
20
|
+
publicKey;
|
|
14
21
|
maxTimestampDriftMs;
|
|
15
22
|
nonceTtlMs;
|
|
16
23
|
seenNonces = new Map();
|
|
17
24
|
activeRunIds = new Set();
|
|
18
25
|
completedRunIds = new Map();
|
|
19
26
|
constructor(options = {}) {
|
|
20
|
-
|
|
27
|
+
// Auto-discover keys from environment if not provided
|
|
28
|
+
this.secret = options.secret || process.env.CATELOG_SECRET_KEY;
|
|
29
|
+
this.publicKey = options.publicKey || process.env.CATELOG_PUBLIC_KEY;
|
|
21
30
|
this.maxTimestampDriftMs = options.maxTimestampDriftMs ?? 300_000; // 5 minutes
|
|
22
|
-
this.nonceTtlMs = options.nonceTtlMs ?? 300_000;
|
|
23
|
-
}
|
|
24
|
-
setSecret(secret) {
|
|
25
|
-
this.secret = secret;
|
|
31
|
+
this.nonceTtlMs = options.nonceTtlMs ?? 300_000;
|
|
26
32
|
}
|
|
27
33
|
getSecret() {
|
|
28
34
|
return this.secret;
|
|
29
35
|
}
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
*/
|
|
33
|
-
computeBodyHash(rawBody) {
|
|
34
|
-
return createHash("sha256").update(rawBody).digest("hex");
|
|
36
|
+
getPublicKey() {
|
|
37
|
+
return this.publicKey;
|
|
35
38
|
}
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
* METHOD\nPATH\nTIMESTAMP\nNONCE\nRUN_ID\nBodyHash
|
|
39
|
-
*/
|
|
40
|
-
buildCanonicalString(method, path, timestamp, nonce, runId, bodyHash) {
|
|
41
|
-
const normalizedMethod = method.toUpperCase();
|
|
42
|
-
const normalizedPath = path.split("?")[0] || "/";
|
|
43
|
-
return `${normalizedMethod}\n${normalizedPath}\n${timestamp}\n${nonce}\n${runId}\n${bodyHash}`;
|
|
39
|
+
setSecret(secret) {
|
|
40
|
+
this.secret = secret;
|
|
44
41
|
}
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
return
|
|
42
|
+
setPublicKey(publicKey) {
|
|
43
|
+
this.publicKey = publicKey;
|
|
44
|
+
}
|
|
45
|
+
isDevMode() {
|
|
46
|
+
return !this.secret && process.env.NODE_ENV !== "production";
|
|
50
47
|
}
|
|
48
|
+
// ─────────────────────────────────────────────
|
|
49
|
+
// Dual-Mode Auth: Detects Bearer vs HMAC vs Dev
|
|
50
|
+
// ─────────────────────────────────────────────
|
|
51
51
|
/**
|
|
52
|
-
*
|
|
52
|
+
* Authenticates an incoming request using the best available method:
|
|
53
|
+
*
|
|
54
|
+
* 1. HMAC headers present → full HMAC-SHA256 verification (Gateway traffic)
|
|
55
|
+
* 2. Authorization: Bearer cat_sec_... → simple secret key match (curl/Postman)
|
|
56
|
+
* 3. Authorization: Bearer cat_pub_... → public key match (read-only allowed)
|
|
57
|
+
* 4. No auth + dev mode → permissive pass-through with warning
|
|
58
|
+
* 5. No auth + production → rejected
|
|
53
59
|
*/
|
|
54
|
-
|
|
60
|
+
authenticateRequest(params) {
|
|
55
61
|
this.cleanupOldEntries();
|
|
56
|
-
|
|
62
|
+
const headers = params.headers;
|
|
63
|
+
// ── Check for HMAC headers first (Gateway mode) ──
|
|
64
|
+
const signatureHeader = headers["x-marketplace-signature"];
|
|
65
|
+
if (signatureHeader) {
|
|
66
|
+
return this.verifyHmac(params, signatureHeader);
|
|
67
|
+
}
|
|
68
|
+
// ── Check for Bearer token (simple auth) ──
|
|
69
|
+
const authHeader = (headers["authorization"] || headers["Authorization"]);
|
|
70
|
+
if (authHeader) {
|
|
71
|
+
return this.verifyBearer(authHeader, headers);
|
|
72
|
+
}
|
|
73
|
+
// ── No auth provided ──
|
|
74
|
+
if (this.isDevMode()) {
|
|
75
|
+
const runId = headers["x-marketplace-run-id"] || `dev-${randomUUID().slice(0, 8)}`;
|
|
76
|
+
const nonce = headers["x-marketplace-nonce"] || `dev-${randomUUID().slice(0, 8)}`;
|
|
77
|
+
if (process.env.NODE_ENV !== "test") {
|
|
78
|
+
console.warn("\x1b[33m⚠ [catelog] Running in dev mode — no authentication required. " +
|
|
79
|
+
"Set CATELOG_SECRET_KEY in production.\x1b[0m");
|
|
80
|
+
}
|
|
81
|
+
return { runId, nonce, timestamp: Date.now(), authMode: "dev" };
|
|
82
|
+
}
|
|
83
|
+
// Production with no auth → reject
|
|
84
|
+
throw new SecurityVerificationError("AUTH_MISSING_KEY", "No authentication provided. Supply Authorization: Bearer <key> or HMAC signature headers.", 401);
|
|
85
|
+
}
|
|
86
|
+
// ── Bearer Token Verification ──
|
|
87
|
+
verifyBearer(authHeader, headers) {
|
|
88
|
+
const token = authHeader.replace(/^Bearer\s+/i, "").trim();
|
|
89
|
+
if (!token) {
|
|
90
|
+
throw new SecurityVerificationError("AUTH_INVALID_KEY", "Empty Bearer token", 401);
|
|
91
|
+
}
|
|
92
|
+
// Check secret key (cat_sec_live_...)
|
|
93
|
+
if (token.startsWith("cat_sec_") && this.secret) {
|
|
94
|
+
// Constant-time comparison
|
|
95
|
+
const tokenBuf = Buffer.from(token, "utf8");
|
|
96
|
+
const secretBuf = Buffer.from(this.secret, "utf8");
|
|
97
|
+
if (tokenBuf.length !== secretBuf.length || !timingSafeEqual(tokenBuf, secretBuf)) {
|
|
98
|
+
throw new SecurityVerificationError("AUTH_INVALID_KEY", "Invalid secret key", 401);
|
|
99
|
+
}
|
|
100
|
+
const runId = headers["x-marketplace-run-id"] || `run-${randomUUID().slice(0, 8)}`;
|
|
101
|
+
const nonce = headers["x-marketplace-nonce"] || `nonce-${randomUUID().slice(0, 8)}`;
|
|
102
|
+
return { runId, nonce, timestamp: Date.now(), authMode: "bearer" };
|
|
103
|
+
}
|
|
104
|
+
// Check public key (cat_pub_live_...)
|
|
105
|
+
if (token.startsWith("cat_pub_") && this.publicKey) {
|
|
106
|
+
const tokenBuf = Buffer.from(token, "utf8");
|
|
107
|
+
const pubBuf = Buffer.from(this.publicKey, "utf8");
|
|
108
|
+
if (tokenBuf.length !== pubBuf.length || !timingSafeEqual(tokenBuf, pubBuf)) {
|
|
109
|
+
throw new SecurityVerificationError("AUTH_INVALID_KEY", "Invalid public key", 401);
|
|
110
|
+
}
|
|
111
|
+
const runId = headers["x-marketplace-run-id"] || `pub-${randomUUID().slice(0, 8)}`;
|
|
112
|
+
const nonce = headers["x-marketplace-nonce"] || `pub-${randomUUID().slice(0, 8)}`;
|
|
113
|
+
return { runId, nonce, timestamp: Date.now(), authMode: "public" };
|
|
114
|
+
}
|
|
115
|
+
// Dev mode fallback for any token
|
|
116
|
+
if (this.isDevMode()) {
|
|
117
|
+
const runId = headers["x-marketplace-run-id"] || `dev-${randomUUID().slice(0, 8)}`;
|
|
118
|
+
const nonce = headers["x-marketplace-nonce"] || `dev-${randomUUID().slice(0, 8)}`;
|
|
119
|
+
return { runId, nonce, timestamp: Date.now(), authMode: "dev" };
|
|
120
|
+
}
|
|
121
|
+
throw new SecurityVerificationError("AUTH_INVALID_KEY", "Invalid API key format or key mismatch", 401);
|
|
122
|
+
}
|
|
123
|
+
// ── HMAC-SHA256 Verification (Gateway traffic) ──
|
|
124
|
+
verifyHmac(params, signatureHeader) {
|
|
57
125
|
if (!this.secret) {
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
const
|
|
67
|
-
|
|
68
|
-
|
|
126
|
+
// Dev mode: skip HMAC but warn
|
|
127
|
+
if (this.isDevMode()) {
|
|
128
|
+
const runId = params.headers["x-marketplace-run-id"] || `dev-${randomUUID().slice(0, 8)}`;
|
|
129
|
+
const nonce = params.headers["x-marketplace-nonce"] || `dev-${randomUUID().slice(0, 8)}`;
|
|
130
|
+
return { runId, nonce, timestamp: Date.now(), authMode: "dev" };
|
|
131
|
+
}
|
|
132
|
+
throw new SecurityVerificationError("AUTH_MISSING_KEY", "HMAC signature provided but no secret key configured", 401);
|
|
133
|
+
}
|
|
134
|
+
const headers = params.headers;
|
|
135
|
+
const timestampHeader = headers["x-marketplace-timestamp"];
|
|
136
|
+
const nonceHeader = headers["x-marketplace-nonce"];
|
|
137
|
+
const runIdHeader = headers["x-marketplace-run-id"];
|
|
138
|
+
if (!timestampHeader || !nonceHeader || !runIdHeader) {
|
|
139
|
+
throw new SecurityVerificationError("AUTH_INVALID_SIGNATURE", "Missing required HMAC headers (timestamp, nonce, run-id)", 401);
|
|
69
140
|
}
|
|
70
141
|
const timestamp = Number.parseInt(timestampHeader, 10);
|
|
71
142
|
if (Number.isNaN(timestamp)) {
|
|
72
143
|
throw new SecurityVerificationError("AUTH_TIMESTAMP_OUT_OF_BOUNDS", "Malformed X-Marketplace-Timestamp header", 401);
|
|
73
144
|
}
|
|
74
|
-
// 1. Timestamp
|
|
145
|
+
// 1. Timestamp bounds
|
|
75
146
|
const now = Date.now();
|
|
76
147
|
if (Math.abs(now - timestamp) > this.maxTimestampDriftMs) {
|
|
77
|
-
throw new SecurityVerificationError("AUTH_TIMESTAMP_OUT_OF_BOUNDS", `Timestamp
|
|
148
|
+
throw new SecurityVerificationError("AUTH_TIMESTAMP_OUT_OF_BOUNDS", `Timestamp drift exceeds ${this.maxTimestampDriftMs}ms`, 401);
|
|
78
149
|
}
|
|
79
|
-
// 2. Nonce
|
|
150
|
+
// 2. Nonce uniqueness
|
|
80
151
|
if (this.seenNonces.has(nonceHeader)) {
|
|
81
|
-
throw new SecurityVerificationError("AUTH_REPLAY_DETECTED", "Duplicate nonce
|
|
152
|
+
throw new SecurityVerificationError("AUTH_REPLAY_DETECTED", "Duplicate nonce (replay guard)", 401);
|
|
82
153
|
}
|
|
83
|
-
// 3. Run ID
|
|
154
|
+
// 3. Run ID idempotency
|
|
84
155
|
if (this.activeRunIds.has(runIdHeader) || this.completedRunIds.has(runIdHeader)) {
|
|
85
|
-
throw new SecurityVerificationError("AUTH_REPLAY_DETECTED", `Run ID ${runIdHeader}
|
|
156
|
+
throw new SecurityVerificationError("AUTH_REPLAY_DETECTED", `Run ID ${runIdHeader} already active or completed`, 401);
|
|
86
157
|
}
|
|
87
|
-
// 4. Verify
|
|
158
|
+
// 4. Verify signature
|
|
88
159
|
const bodyHash = this.computeBodyHash(params.rawBody);
|
|
89
160
|
const canonicalString = this.buildCanonicalString(params.method, params.path, timestampHeader, nonceHeader, runIdHeader, bodyHash);
|
|
90
161
|
const expectedSignature = this.calculateSignature(canonicalString, this.secret);
|
|
@@ -93,13 +164,21 @@ export class SecurityManager {
|
|
|
93
164
|
if (sigBuf.length !== expBuf.length || !timingSafeEqual(sigBuf, expBuf)) {
|
|
94
165
|
throw new SecurityVerificationError("AUTH_INVALID_SIGNATURE", "HMAC-SHA256 signature verification failed", 401);
|
|
95
166
|
}
|
|
96
|
-
// Mark nonce
|
|
167
|
+
// Mark nonce seen
|
|
97
168
|
this.seenNonces.set(nonceHeader, now);
|
|
98
|
-
return {
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
169
|
+
return { runId: runIdHeader, nonce: nonceHeader, timestamp, authMode: "hmac" };
|
|
170
|
+
}
|
|
171
|
+
// ── Public helpers ──
|
|
172
|
+
computeBodyHash(rawBody) {
|
|
173
|
+
return createHash("sha256").update(rawBody).digest("hex");
|
|
174
|
+
}
|
|
175
|
+
buildCanonicalString(method, path, timestamp, nonce, runId, bodyHash) {
|
|
176
|
+
const normalizedMethod = method.toUpperCase();
|
|
177
|
+
const normalizedPath = path.split("?")[0] || "/";
|
|
178
|
+
return `${normalizedMethod}\n${normalizedPath}\n${timestamp}\n${nonce}\n${runId}\n${bodyHash}`;
|
|
179
|
+
}
|
|
180
|
+
calculateSignature(canonicalString, secret) {
|
|
181
|
+
return createHmac("sha256", secret).update(canonicalString).digest("hex");
|
|
103
182
|
}
|
|
104
183
|
markRunStarted(runId) {
|
|
105
184
|
this.activeRunIds.add(runId);
|
|
@@ -112,14 +191,12 @@ export class SecurityManager {
|
|
|
112
191
|
const now = Date.now();
|
|
113
192
|
const expiry = now - this.nonceTtlMs;
|
|
114
193
|
for (const [nonce, time] of this.seenNonces.entries()) {
|
|
115
|
-
if (time < expiry)
|
|
194
|
+
if (time < expiry)
|
|
116
195
|
this.seenNonces.delete(nonce);
|
|
117
|
-
}
|
|
118
196
|
}
|
|
119
197
|
for (const [runId, time] of this.completedRunIds.entries()) {
|
|
120
|
-
if (time < expiry)
|
|
198
|
+
if (time < expiry)
|
|
121
199
|
this.completedRunIds.delete(runId);
|
|
122
|
-
}
|
|
123
200
|
}
|
|
124
201
|
}
|
|
125
202
|
}
|
package/dist/security.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"security.js","sourceRoot":"","sources":["../src/security.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,UAAU,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"security.js","sourceRoot":"","sources":["../src/security.ts"],"names":[],"mappings":"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"}
|
package/dist/server.d.ts
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { type Server } from "node:http";
|
|
2
|
-
import type {
|
|
2
|
+
import type { CatelogAgent } from "./agent.js";
|
|
3
3
|
export interface ServerOptions {
|
|
4
4
|
port?: number;
|
|
5
5
|
host?: string;
|
|
6
6
|
silent?: boolean;
|
|
7
7
|
onListening?: (url: string) => void;
|
|
8
8
|
}
|
|
9
|
-
export declare function startAgentServer(agent:
|
|
9
|
+
export declare function startAgentServer(agent: CatelogAgent<any, any>, options?: ServerOptions): Server;
|
|
10
10
|
//# sourceMappingURL=server.d.ts.map
|
package/dist/server.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAgB,KAAK,MAAM,EAA6C,MAAM,WAAW,CAAC;AACjG,OAAO,KAAK,EAAE,
|
|
1
|
+
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAgB,KAAK,MAAM,EAA6C,MAAM,WAAW,CAAC;AACjG,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAG/C,MAAM,WAAW,aAAa;IAC5B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,WAAW,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;CACrC;AAED,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,YAAY,CAAC,GAAG,EAAE,GAAG,CAAC,EAAE,OAAO,GAAE,aAAkB,GAAG,MAAM,CA6BnG"}
|
package/dist/server.js
CHANGED
|
@@ -5,10 +5,10 @@ export function startAgentServer(agent, options = {}) {
|
|
|
5
5
|
const host = options.host ?? "0.0.0.0";
|
|
6
6
|
const server = createServer((req, res) => {
|
|
7
7
|
agent.handleRequest(req, res).catch((err) => {
|
|
8
|
-
console.error("[catelog
|
|
8
|
+
console.error("[catelog] Unhandled error:", err);
|
|
9
9
|
if (!res.writableEnded) {
|
|
10
10
|
res.writeHead(500, { "Content-Type": "application/json" });
|
|
11
|
-
res.end(JSON.stringify({ error: { code: "INTERNAL_CRASH", message: "
|
|
11
|
+
res.end(JSON.stringify({ error: { code: "INTERNAL_CRASH", message: "Unhandled server error" } }));
|
|
12
12
|
}
|
|
13
13
|
});
|
|
14
14
|
});
|
|
@@ -18,7 +18,12 @@ export function startAgentServer(agent, options = {}) {
|
|
|
18
18
|
options.onListening(url);
|
|
19
19
|
}
|
|
20
20
|
else if (!options.silent) {
|
|
21
|
-
renderBanner("startup", {
|
|
21
|
+
renderBanner("startup", {
|
|
22
|
+
name: agent.name,
|
|
23
|
+
url,
|
|
24
|
+
mode: agent.mode,
|
|
25
|
+
authConfigured: !!agent.security.getSecret(),
|
|
26
|
+
});
|
|
22
27
|
}
|
|
23
28
|
});
|
|
24
29
|
return server;
|
package/dist/server.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAA0D,MAAM,WAAW,CAAC;AAEjG,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAS3C,MAAM,UAAU,gBAAgB,CAAC,
|
|
1
|
+
{"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAA0D,MAAM,WAAW,CAAC;AAEjG,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAS3C,MAAM,UAAU,gBAAgB,CAAC,KAA6B,EAAE,UAAyB,EAAE;IACzF,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;IAC/F,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,IAAI,SAAS,CAAC;IAEvC,MAAM,MAAM,GAAG,YAAY,CAAC,CAAC,GAAoB,EAAE,GAAmB,EAAE,EAAE;QACxE,KAAK,CAAC,aAAa,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,GAAG,EAAE,EAAE;YAC1C,OAAO,CAAC,KAAK,CAAC,4BAA4B,EAAE,GAAG,CAAC,CAAC;YACjD,IAAI,CAAC,GAAG,CAAC,aAAa,EAAE,CAAC;gBACvB,GAAG,CAAC,SAAS,CAAC,GAAG,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE,CAAC,CAAC;gBAC3D,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,KAAK,EAAE,EAAE,IAAI,EAAE,gBAAgB,EAAE,OAAO,EAAE,wBAAwB,EAAE,EAAE,CAAC,CAAC,CAAC;YACpG,CAAC;QACH,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,IAAI,EAAE,GAAG,EAAE;QAC7B,MAAM,GAAG,GAAG,UAAU,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,IAAI,IAAI,IAAI,EAAE,CAAC;QACxE,IAAI,OAAO,CAAC,WAAW,EAAE,CAAC;YACxB,OAAO,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC;QAC3B,CAAC;aAAM,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,CAAC;YAC3B,YAAY,CAAC,SAAS,EAAE;gBACtB,IAAI,EAAE,KAAK,CAAC,IAAI;gBAChB,GAAG;gBACH,IAAI,EAAE,KAAK,CAAC,IAAI;gBAChB,cAAc,EAAE,CAAC,CAAC,KAAK,CAAC,QAAQ,CAAC,SAAS,EAAE;aAC7C,CAAC,CAAC;QACL,CAAC;IACH,CAAC,CAAC,CAAC;IAEH,OAAO,MAAM,CAAC;AAChB,CAAC"}
|
package/dist/sse.d.ts
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import type { ServerResponse } from "node:http";
|
|
2
|
-
import type { AgentStream, StructuredError, TelemetryData } from "./types.js";
|
|
2
|
+
import type { AgentStream, StructuredError, TelemetryData, TaskState } from "./types.js";
|
|
3
3
|
export interface SSEWriterOptions {
|
|
4
|
+
/** Heartbeat interval in ms (default: 15s) */
|
|
4
5
|
heartbeatIntervalMs?: number;
|
|
6
|
+
/** Callback on client disconnect */
|
|
5
7
|
onClientDisconnect?: () => void;
|
|
6
8
|
}
|
|
7
9
|
export declare class SSEWriter implements AgentStream {
|
|
@@ -12,21 +14,43 @@ export declare class SSEWriter implements AgentStream {
|
|
|
12
14
|
private deltaIndex;
|
|
13
15
|
private closed;
|
|
14
16
|
private abortController;
|
|
17
|
+
chunksStreamed: number;
|
|
15
18
|
constructor(runId: string, res: ServerResponse, options?: SSEWriterOptions);
|
|
16
19
|
get signal(): AbortSignal;
|
|
17
20
|
isClosed(): boolean;
|
|
18
|
-
/**
|
|
19
|
-
* Generic raw event sender adhering to SSE framing:
|
|
20
|
-
* event: <EVENT_TYPE>\ndata: <JSON_STRING>\n\n
|
|
21
|
-
*/
|
|
22
21
|
sendEvent(eventType: string, data: unknown): void;
|
|
23
|
-
|
|
24
|
-
|
|
22
|
+
/** Emit task.status = "working" on execution start */
|
|
23
|
+
sendTaskStatus(status: TaskState): void;
|
|
24
|
+
/** Progress tick (0-100). Does NOT complete the task. */
|
|
25
|
+
progress(percent: number, message?: string): void;
|
|
26
|
+
/** Stream a text/token delta. Does NOT complete the task. */
|
|
25
27
|
delta(content: string, delta_type?: "text" | "json_patch"): void;
|
|
28
|
+
/** Named activity event (tool_call, search, etc.) */
|
|
29
|
+
activity(type: string, data?: Record<string, unknown>): void;
|
|
30
|
+
/** Legacy step (maps to progress internally) */
|
|
31
|
+
step(label: string): void;
|
|
32
|
+
/** Convenience alias for delta */
|
|
33
|
+
write(text: string): void;
|
|
34
|
+
/** Raw event emitter */
|
|
26
35
|
emit(event: string, data: unknown): void;
|
|
36
|
+
sendTaskCompleted<TOutput>(output: TOutput, durationMs: number, telemetry?: TelemetryData): void;
|
|
37
|
+
sendTaskFailed(error: StructuredError, durationMs: number): void;
|
|
38
|
+
sendTaskInputRequired(prompt: string, resumeToken: string, inputSchema?: Record<string, unknown>): void;
|
|
39
|
+
sendTaskCanceled(durationMs: number): void;
|
|
40
|
+
sendRunStarted(): void;
|
|
27
41
|
sendRunSucceeded<TOutput>(output: TOutput, durationMs: number, telemetry?: TelemetryData): void;
|
|
28
42
|
sendRunFailed(error: StructuredError, durationMs: number): void;
|
|
29
43
|
close(): void;
|
|
30
44
|
private clearHeartbeat;
|
|
31
45
|
}
|
|
46
|
+
export declare class NoopStream implements AgentStream {
|
|
47
|
+
chunksStreamed: number;
|
|
48
|
+
progress(_percent: number, _message?: string): void;
|
|
49
|
+
delta(_content: string, _type?: "text" | "json_patch"): void;
|
|
50
|
+
activity(_type: string, _data?: Record<string, unknown>): void;
|
|
51
|
+
step(_label: string): void;
|
|
52
|
+
emit(_event: string, _data: unknown): void;
|
|
53
|
+
write(text: string): void;
|
|
54
|
+
isClosed(): boolean;
|
|
55
|
+
}
|
|
32
56
|
//# sourceMappingURL=sse.d.ts.map
|
package/dist/sse.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sse.d.ts","sourceRoot":"","sources":["../src/sse.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AAChD,OAAO,KAAK,EACV,WAAW,
|
|
1
|
+
{"version":3,"file":"sse.d.ts","sourceRoot":"","sources":["../src/sse.ts"],"names":[],"mappings":"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"}
|
package/dist/sse.js
CHANGED
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
// ─────────────────────────────────────────────────
|
|
2
|
+
// SSEWriter — streams canonical task lifecycle events
|
|
3
|
+
// ─────────────────────────────────────────────────
|
|
1
4
|
export class SSEWriter {
|
|
2
5
|
runId;
|
|
3
6
|
res;
|
|
@@ -6,6 +9,7 @@ export class SSEWriter {
|
|
|
6
9
|
deltaIndex = 0;
|
|
7
10
|
closed = false;
|
|
8
11
|
abortController;
|
|
12
|
+
chunksStreamed = 0;
|
|
9
13
|
constructor(runId, res, options = {}) {
|
|
10
14
|
this.runId = runId;
|
|
11
15
|
this.res = res;
|
|
@@ -17,7 +21,6 @@ export class SSEWriter {
|
|
|
17
21
|
Connection: "keep-alive",
|
|
18
22
|
"X-Accel-Buffering": "no",
|
|
19
23
|
});
|
|
20
|
-
// Flush headers if supported
|
|
21
24
|
if (typeof this.res.flushHeaders === "function") {
|
|
22
25
|
this.res.flushHeaders();
|
|
23
26
|
}
|
|
@@ -30,14 +33,11 @@ export class SSEWriter {
|
|
|
30
33
|
options.onClientDisconnect?.();
|
|
31
34
|
}
|
|
32
35
|
});
|
|
33
|
-
//
|
|
36
|
+
// 15-second heartbeat
|
|
34
37
|
const interval = options.heartbeatIntervalMs ?? 15_000;
|
|
35
38
|
this.heartbeatTimer = setInterval(() => {
|
|
36
39
|
if (!this.closed) {
|
|
37
|
-
this.sendEvent("heartbeat", {
|
|
38
|
-
event: "heartbeat",
|
|
39
|
-
timestamp: Date.now(),
|
|
40
|
-
});
|
|
40
|
+
this.sendEvent("heartbeat", { event: "heartbeat", timestamp: Date.now() });
|
|
41
41
|
}
|
|
42
42
|
}, interval);
|
|
43
43
|
}
|
|
@@ -47,10 +47,7 @@ export class SSEWriter {
|
|
|
47
47
|
isClosed() {
|
|
48
48
|
return this.closed;
|
|
49
49
|
}
|
|
50
|
-
|
|
51
|
-
* Generic raw event sender adhering to SSE framing:
|
|
52
|
-
* event: <EVENT_TYPE>\ndata: <JSON_STRING>\n\n
|
|
53
|
-
*/
|
|
50
|
+
// ── Raw SSE sender ──
|
|
54
51
|
sendEvent(eventType, data) {
|
|
55
52
|
if (this.closed)
|
|
56
53
|
return;
|
|
@@ -62,63 +59,119 @@ export class SSEWriter {
|
|
|
62
59
|
this.clearHeartbeat();
|
|
63
60
|
}
|
|
64
61
|
}
|
|
65
|
-
|
|
62
|
+
// ── Task Lifecycle Events ──
|
|
63
|
+
/** Emit task.status = "working" on execution start */
|
|
64
|
+
sendTaskStatus(status) {
|
|
66
65
|
const payload = {
|
|
67
|
-
event: "
|
|
66
|
+
event: "task.status",
|
|
68
67
|
run_id: this.runId,
|
|
68
|
+
status,
|
|
69
69
|
timestamp: Date.now(),
|
|
70
70
|
};
|
|
71
|
-
this.sendEvent("
|
|
71
|
+
this.sendEvent("task.status", payload);
|
|
72
72
|
}
|
|
73
|
-
|
|
73
|
+
/** Progress tick (0-100). Does NOT complete the task. */
|
|
74
|
+
progress(percent, message) {
|
|
74
75
|
this.stepIndex += 1;
|
|
75
76
|
const payload = {
|
|
76
|
-
event: "
|
|
77
|
+
event: "task.progress",
|
|
77
78
|
run_id: this.runId,
|
|
78
|
-
|
|
79
|
-
|
|
79
|
+
percent: Math.min(100, Math.max(0, percent)),
|
|
80
|
+
message,
|
|
81
|
+
step: this.stepIndex,
|
|
80
82
|
timestamp: Date.now(),
|
|
81
83
|
};
|
|
82
|
-
this.sendEvent("
|
|
84
|
+
this.sendEvent("task.progress", payload);
|
|
83
85
|
}
|
|
86
|
+
/** Stream a text/token delta. Does NOT complete the task. */
|
|
84
87
|
delta(content, delta_type = "text") {
|
|
88
|
+
this.chunksStreamed++;
|
|
85
89
|
const payload = {
|
|
86
|
-
event: "
|
|
90
|
+
event: "task.delta",
|
|
87
91
|
run_id: this.runId,
|
|
88
92
|
index: this.deltaIndex++,
|
|
89
93
|
delta_type,
|
|
90
94
|
content,
|
|
91
95
|
};
|
|
92
|
-
this.sendEvent("
|
|
96
|
+
this.sendEvent("task.delta", payload);
|
|
97
|
+
}
|
|
98
|
+
/** Named activity event (tool_call, search, etc.) */
|
|
99
|
+
activity(type, data) {
|
|
100
|
+
const payload = {
|
|
101
|
+
event: "task.activity",
|
|
102
|
+
run_id: this.runId,
|
|
103
|
+
activity_type: type,
|
|
104
|
+
data,
|
|
105
|
+
timestamp: Date.now(),
|
|
106
|
+
};
|
|
107
|
+
this.sendEvent("task.activity", payload);
|
|
93
108
|
}
|
|
109
|
+
/** Legacy step (maps to progress internally) */
|
|
110
|
+
step(label) {
|
|
111
|
+
this.progress(0, label);
|
|
112
|
+
}
|
|
113
|
+
/** Convenience alias for delta */
|
|
114
|
+
write(text) {
|
|
115
|
+
this.delta(text, "text");
|
|
116
|
+
}
|
|
117
|
+
/** Raw event emitter */
|
|
94
118
|
emit(event, data) {
|
|
95
119
|
this.sendEvent(event, data);
|
|
96
120
|
}
|
|
97
|
-
|
|
121
|
+
// ── Terminal Events ──
|
|
122
|
+
sendTaskCompleted(output, durationMs, telemetry) {
|
|
98
123
|
if (this.closed)
|
|
99
124
|
return;
|
|
100
125
|
const payload = {
|
|
101
|
-
event: "
|
|
126
|
+
event: "task.completed",
|
|
102
127
|
run_id: this.runId,
|
|
103
128
|
duration_ms: durationMs,
|
|
104
129
|
output,
|
|
105
130
|
telemetry,
|
|
106
131
|
};
|
|
107
|
-
this.sendEvent("
|
|
132
|
+
this.sendEvent("task.completed", payload);
|
|
108
133
|
this.close();
|
|
109
134
|
}
|
|
110
|
-
|
|
135
|
+
sendTaskFailed(error, durationMs) {
|
|
111
136
|
if (this.closed)
|
|
112
137
|
return;
|
|
113
138
|
const payload = {
|
|
114
|
-
event: "
|
|
139
|
+
event: "task.failed",
|
|
115
140
|
run_id: this.runId,
|
|
116
141
|
duration_ms: durationMs,
|
|
117
142
|
error,
|
|
118
143
|
};
|
|
119
|
-
this.sendEvent("
|
|
144
|
+
this.sendEvent("task.failed", payload);
|
|
120
145
|
this.close();
|
|
121
146
|
}
|
|
147
|
+
sendTaskInputRequired(prompt, resumeToken, inputSchema) {
|
|
148
|
+
if (this.closed)
|
|
149
|
+
return;
|
|
150
|
+
const payload = {
|
|
151
|
+
event: "task.input_required",
|
|
152
|
+
run_id: this.runId,
|
|
153
|
+
prompt,
|
|
154
|
+
input_schema: inputSchema,
|
|
155
|
+
resume_token: resumeToken,
|
|
156
|
+
timestamp: Date.now(),
|
|
157
|
+
};
|
|
158
|
+
this.sendEvent("task.input_required", payload);
|
|
159
|
+
this.close();
|
|
160
|
+
}
|
|
161
|
+
sendTaskCanceled(durationMs) {
|
|
162
|
+
this.sendTaskFailed({ code: "TASK_CANCELED", message: "Execution was canceled", retryable: false }, durationMs);
|
|
163
|
+
}
|
|
164
|
+
// ── Backward compat wrappers ──
|
|
165
|
+
sendRunStarted() {
|
|
166
|
+
this.sendTaskStatus("working");
|
|
167
|
+
}
|
|
168
|
+
sendRunSucceeded(output, durationMs, telemetry) {
|
|
169
|
+
this.sendTaskCompleted(output, durationMs, telemetry);
|
|
170
|
+
}
|
|
171
|
+
sendRunFailed(error, durationMs) {
|
|
172
|
+
this.sendTaskFailed(error, durationMs);
|
|
173
|
+
}
|
|
174
|
+
// ── Lifecycle ──
|
|
122
175
|
close() {
|
|
123
176
|
if (this.closed)
|
|
124
177
|
return;
|
|
@@ -138,4 +191,19 @@ export class SSEWriter {
|
|
|
138
191
|
}
|
|
139
192
|
}
|
|
140
193
|
}
|
|
194
|
+
// ─────────────────────────────────────────────────
|
|
195
|
+
// NoopStream — for batch JSON (non-SSE) mode
|
|
196
|
+
// ─────────────────────────────────────────────────
|
|
197
|
+
export class NoopStream {
|
|
198
|
+
chunksStreamed = 0;
|
|
199
|
+
progress(_percent, _message) { }
|
|
200
|
+
delta(_content, _type) {
|
|
201
|
+
this.chunksStreamed++;
|
|
202
|
+
}
|
|
203
|
+
activity(_type, _data) { }
|
|
204
|
+
step(_label) { }
|
|
205
|
+
emit(_event, _data) { }
|
|
206
|
+
write(text) { this.delta(text); }
|
|
207
|
+
isClosed() { return false; }
|
|
208
|
+
}
|
|
141
209
|
//# sourceMappingURL=sse.js.map
|