@superblocksteam/gateway 2.0.155-next.0
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/LICENSE.txt +87 -0
- package/README.md +170 -0
- package/dist/agents/resolve-orchestrator-url.d.ts +22 -0
- package/dist/agents/resolve-orchestrator-url.js +38 -0
- package/dist/agents/resolve-orchestrator-url.js.map +1 -0
- package/dist/capabilities/import-prompt.d.ts +11 -0
- package/dist/capabilities/import-prompt.js +96 -0
- package/dist/capabilities/import-prompt.js.map +1 -0
- package/dist/capabilities/lifecycle.d.ts +73 -0
- package/dist/capabilities/lifecycle.js +2531 -0
- package/dist/capabilities/lifecycle.js.map +1 -0
- package/dist/capabilities/persisted-progress.d.ts +46 -0
- package/dist/capabilities/persisted-progress.js +246 -0
- package/dist/capabilities/persisted-progress.js.map +1 -0
- package/dist/capabilities/types.d.ts +446 -0
- package/dist/capabilities/types.js +47 -0
- package/dist/capabilities/types.js.map +1 -0
- package/dist/capture/browser-contract.d.ts +36 -0
- package/dist/capture/browser-contract.js +24 -0
- package/dist/capture/browser-contract.js.map +1 -0
- package/dist/capture/browser-instructions.d.ts +9 -0
- package/dist/capture/browser-instructions.js +17 -0
- package/dist/capture/browser-instructions.js.map +1 -0
- package/dist/capture/capture-library-probe.d.ts +55 -0
- package/dist/capture/capture-library-probe.js +177 -0
- package/dist/capture/capture-library-probe.js.map +1 -0
- package/dist/capture/capture-library.d.ts +52 -0
- package/dist/capture/capture-library.js +249 -0
- package/dist/capture/capture-library.js.map +1 -0
- package/dist/capture/classify-library-paint.d.ts +21 -0
- package/dist/capture/classify-library-paint.js +13 -0
- package/dist/capture/classify-library-paint.js.map +1 -0
- package/dist/capture/host-mcp-scan.d.ts +16 -0
- package/dist/capture/host-mcp-scan.js +64 -0
- package/dist/capture/host-mcp-scan.js.map +1 -0
- package/dist/capture/library-parent-script.d.ts +34 -0
- package/dist/capture/library-parent-script.js +82 -0
- package/dist/capture/library-parent-script.js.map +1 -0
- package/dist/capture/mode.d.ts +22 -0
- package/dist/capture/mode.js +45 -0
- package/dist/capture/mode.js.map +1 -0
- package/dist/config.d.ts +141 -0
- package/dist/config.js +109 -0
- package/dist/config.js.map +1 -0
- package/dist/debug.d.ts +2 -0
- package/dist/debug.js +9 -0
- package/dist/debug.js.map +1 -0
- package/dist/deps.d.ts +36 -0
- package/dist/deps.js +2 -0
- package/dist/deps.js.map +1 -0
- package/dist/events/cursor.d.ts +43 -0
- package/dist/events/cursor.js +78 -0
- package/dist/events/cursor.js.map +1 -0
- package/dist/events/memory-event-store.d.ts +34 -0
- package/dist/events/memory-event-store.js +110 -0
- package/dist/events/memory-event-store.js.map +1 -0
- package/dist/events/merge.d.ts +23 -0
- package/dist/events/merge.js +97 -0
- package/dist/events/merge.js.map +1 -0
- package/dist/events/normalized-collector.d.ts +62 -0
- package/dist/events/normalized-collector.js +156 -0
- package/dist/events/normalized-collector.js.map +1 -0
- package/dist/events/schema.d.ts +9 -0
- package/dist/events/schema.js +93 -0
- package/dist/events/schema.js.map +1 -0
- package/dist/events/snapshot.d.ts +32 -0
- package/dist/events/snapshot.js +57 -0
- package/dist/events/snapshot.js.map +1 -0
- package/dist/events/stream-key.d.ts +2 -0
- package/dist/events/stream-key.js +31 -0
- package/dist/events/stream-key.js.map +1 -0
- package/dist/events/types.d.ts +179 -0
- package/dist/events/types.js +66 -0
- package/dist/events/types.js.map +1 -0
- package/dist/health/readiness.d.ts +99 -0
- package/dist/health/readiness.js +202 -0
- package/dist/health/readiness.js.map +1 -0
- package/dist/index.d.ts +10 -0
- package/dist/index.js +10 -0
- package/dist/index.js.map +1 -0
- package/dist/integrations/filters.d.ts +8 -0
- package/dist/integrations/filters.js +40 -0
- package/dist/integrations/filters.js.map +1 -0
- package/dist/integrations/map.d.ts +26 -0
- package/dist/integrations/map.js +43 -0
- package/dist/integrations/map.js.map +1 -0
- package/dist/integrations/profile-key.d.ts +19 -0
- package/dist/integrations/profile-key.js +35 -0
- package/dist/integrations/profile-key.js.map +1 -0
- package/dist/main.d.ts +2 -0
- package/dist/main.js +5 -0
- package/dist/main.js.map +1 -0
- package/dist/orchestrator/client.d.ts +62 -0
- package/dist/orchestrator/client.js +160 -0
- package/dist/orchestrator/client.js.map +1 -0
- package/dist/playwright/ensure-chromium.d.ts +26 -0
- package/dist/playwright/ensure-chromium.js +60 -0
- package/dist/playwright/ensure-chromium.js.map +1 -0
- package/dist/preview/capture-screenshot.d.ts +52 -0
- package/dist/preview/capture-screenshot.js +158 -0
- package/dist/preview/capture-screenshot.js.map +1 -0
- package/dist/preview/viewer-url.d.ts +82 -0
- package/dist/preview/viewer-url.js +128 -0
- package/dist/preview/viewer-url.js.map +1 -0
- package/dist/process/fault-barrier.d.ts +55 -0
- package/dist/process/fault-barrier.js +113 -0
- package/dist/process/fault-barrier.js.map +1 -0
- package/dist/resume/memory-progress-store.d.ts +39 -0
- package/dist/resume/memory-progress-store.js +82 -0
- package/dist/resume/memory-progress-store.js.map +1 -0
- package/dist/resume/memory-recent-app-store.d.ts +14 -0
- package/dist/resume/memory-recent-app-store.js +27 -0
- package/dist/resume/memory-recent-app-store.js.map +1 -0
- package/dist/resume/memory-turn-store.d.ts +18 -0
- package/dist/resume/memory-turn-store.js +73 -0
- package/dist/resume/memory-turn-store.js.map +1 -0
- package/dist/resume/progress-key.d.ts +21 -0
- package/dist/resume/progress-key.js +58 -0
- package/dist/resume/progress-key.js.map +1 -0
- package/dist/resume/stores.d.ts +14 -0
- package/dist/resume/stores.js +18 -0
- package/dist/resume/stores.js.map +1 -0
- package/dist/resume/types.d.ts +124 -0
- package/dist/resume/types.js +13 -0
- package/dist/resume/types.js.map +1 -0
- package/dist/sabs/agent-facing-text.d.ts +33 -0
- package/dist/sabs/agent-facing-text.js +125 -0
- package/dist/sabs/agent-facing-text.js.map +1 -0
- package/dist/sabs/browser-context.d.ts +53 -0
- package/dist/sabs/browser-context.js +91 -0
- package/dist/sabs/browser-context.js.map +1 -0
- package/dist/sabs/editor-client-methods.d.ts +147 -0
- package/dist/sabs/editor-client-methods.js +715 -0
- package/dist/sabs/editor-client-methods.js.map +1 -0
- package/dist/sabs/recent-tool-runs.d.ts +14 -0
- package/dist/sabs/recent-tool-runs.js +61 -0
- package/dist/sabs/recent-tool-runs.js.map +1 -0
- package/dist/sabs/session-peer.d.ts +351 -0
- package/dist/sabs/session-peer.js +2 -0
- package/dist/sabs/session-peer.js.map +1 -0
- package/dist/sabs/turn-collector.d.ts +152 -0
- package/dist/sabs/turn-collector.js +573 -0
- package/dist/sabs/turn-collector.js.map +1 -0
- package/dist/sabs/websocket-session-peer.d.ts +514 -0
- package/dist/sabs/websocket-session-peer.js +2487 -0
- package/dist/sabs/websocket-session-peer.js.map +1 -0
- package/dist/security/constant-time.d.ts +9 -0
- package/dist/security/constant-time.js +13 -0
- package/dist/security/constant-time.js.map +1 -0
- package/dist/server/client.d.ts +371 -0
- package/dist/server/client.js +572 -0
- package/dist/server/client.js.map +1 -0
- package/dist/server/identity-reads.d.ts +76 -0
- package/dist/server/identity-reads.js +209 -0
- package/dist/server/identity-reads.js.map +1 -0
- package/dist/start.d.ts +14 -0
- package/dist/start.js +75 -0
- package/dist/start.js.map +1 -0
- package/dist/telemetry/metrics.d.ts +32 -0
- package/dist/telemetry/metrics.js +57 -0
- package/dist/telemetry/metrics.js.map +1 -0
- package/dist/transports/mcp/admin-tools.d.ts +47 -0
- package/dist/transports/mcp/admin-tools.js +164 -0
- package/dist/transports/mcp/admin-tools.js.map +1 -0
- package/dist/transports/mcp/app-status-html.d.ts +15 -0
- package/dist/transports/mcp/app-status-html.js +563 -0
- package/dist/transports/mcp/app-status-html.js.map +1 -0
- package/dist/transports/mcp/decision-elicitation.d.ts +74 -0
- package/dist/transports/mcp/decision-elicitation.js +233 -0
- package/dist/transports/mcp/decision-elicitation.js.map +1 -0
- package/dist/transports/mcp/dispatch-probe.d.ts +24 -0
- package/dist/transports/mcp/dispatch-probe.js +48 -0
- package/dist/transports/mcp/dispatch-probe.js.map +1 -0
- package/dist/transports/mcp/format-tool-content.d.ts +25 -0
- package/dist/transports/mcp/format-tool-content.js +48 -0
- package/dist/transports/mcp/format-tool-content.js.map +1 -0
- package/dist/transports/mcp/mount.d.ts +9 -0
- package/dist/transports/mcp/mount.js +469 -0
- package/dist/transports/mcp/mount.js.map +1 -0
- package/dist/transports/mcp/progress-notifier.d.ts +39 -0
- package/dist/transports/mcp/progress-notifier.js +52 -0
- package/dist/transports/mcp/progress-notifier.js.map +1 -0
- package/package.json +72 -0
|
@@ -0,0 +1,572 @@
|
|
|
1
|
+
import { uploadAttachmentToServerApi } from "@superblocksteam/shared";
|
|
2
|
+
import { recordIdentityReadOutcome } from "../telemetry/metrics.js";
|
|
3
|
+
import { withGuardedIdentityReads, } from "./identity-reads.js";
|
|
4
|
+
const MAX_DETAIL_LENGTH = 300;
|
|
5
|
+
/**
|
|
6
|
+
* Pulls the server's own explanation out of an error body.
|
|
7
|
+
*
|
|
8
|
+
* Bounded because the body is attacker-influenced in principle and ends up in
|
|
9
|
+
* logs and in tool output the caller sees.
|
|
10
|
+
*/
|
|
11
|
+
function detailSuffix(body) {
|
|
12
|
+
if (!body.trim()) {
|
|
13
|
+
return "";
|
|
14
|
+
}
|
|
15
|
+
let detail = body;
|
|
16
|
+
try {
|
|
17
|
+
const parsed = JSON.parse(body);
|
|
18
|
+
if (parsed && typeof parsed === "object") {
|
|
19
|
+
const record = parsed;
|
|
20
|
+
const message = record.responseMeta?.message ?? record.message ?? record.error;
|
|
21
|
+
if (typeof message === "string" && message.trim()) {
|
|
22
|
+
detail = message;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
catch {
|
|
27
|
+
// Not JSON — fall back to the raw body.
|
|
28
|
+
}
|
|
29
|
+
const trimmed = detail.trim().slice(0, MAX_DETAIL_LENGTH);
|
|
30
|
+
return ` — ${trimmed}`;
|
|
31
|
+
}
|
|
32
|
+
export class ServerHttpError extends Error {
|
|
33
|
+
status;
|
|
34
|
+
constructor(message, status) {
|
|
35
|
+
super(message);
|
|
36
|
+
this.status = status;
|
|
37
|
+
this.name = "ServerHttpError";
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Generous enough for a sandbox start.
|
|
42
|
+
*
|
|
43
|
+
* It is not short enough to keep a tool call from hanging, which is what this
|
|
44
|
+
* used to claim: a tool call waits on the identity read, and that one is bounded
|
|
45
|
+
* by {@link DEFAULT_IDENTITY_TIMEOUT_MS} instead.
|
|
46
|
+
*/
|
|
47
|
+
const DEFAULT_TIMEOUT_MS = 120_000;
|
|
48
|
+
/**
|
|
49
|
+
* The identity read gets its own, much tighter bound.
|
|
50
|
+
*
|
|
51
|
+
* {@link DEFAULT_TIMEOUT_MS} is sized for starting a sandbox. Nothing waits on
|
|
52
|
+
* that; every tool call waits on `/users/me`. Giving the two the same budget is
|
|
53
|
+
* what let a single wedged route hold each call for two minutes.
|
|
54
|
+
*
|
|
55
|
+
* Still well above the ~10s a caller waits (see
|
|
56
|
+
* {@link withGuardedIdentityReads}) so that an endpoint which answers slowly
|
|
57
|
+
* rather than never can still finish and fill the cache.
|
|
58
|
+
*/
|
|
59
|
+
const DEFAULT_IDENTITY_TIMEOUT_MS = 30_000;
|
|
60
|
+
/**
|
|
61
|
+
* Whether a failed identity read means the endpoint is unhealthy rather than
|
|
62
|
+
* that this one credential is bad.
|
|
63
|
+
*
|
|
64
|
+
* A 4xx is a definite answer about a single caller, so it must not trip the
|
|
65
|
+
* breaker and start failing everyone else fast. A 5xx, a timeout or a
|
|
66
|
+
* transport error says nothing about the credential and everything about the
|
|
67
|
+
* route.
|
|
68
|
+
*
|
|
69
|
+
* 429 is the exception on the 4xx side: a shared rate limit is a statement
|
|
70
|
+
* about the route's capacity, not about this credential, and it is exactly the
|
|
71
|
+
* case where hammering on is worst. Treating it as the caller's fault left it
|
|
72
|
+
* neither retried (only >= 500 is) nor able to open the breaker, so every call
|
|
73
|
+
* kept going straight at an endpoint already asking for less load.
|
|
74
|
+
*/
|
|
75
|
+
function identityEndpointUnhealthy(error) {
|
|
76
|
+
return !(error instanceof ServerHttpError &&
|
|
77
|
+
error.status < 500 &&
|
|
78
|
+
error.status !== 429);
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Extra attempts for reads that failed with a server-side error.
|
|
82
|
+
*
|
|
83
|
+
* Only GETs are retried: they carry no side effects, so a repeat is free. A
|
|
84
|
+
* failed POST may well have taken effect, and re-sending one can deploy or
|
|
85
|
+
* commit twice.
|
|
86
|
+
*/
|
|
87
|
+
const READ_RETRY_ATTEMPTS = 2;
|
|
88
|
+
const READ_RETRY_BASE_DELAY_MS = 100;
|
|
89
|
+
function delay(ms) {
|
|
90
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
91
|
+
}
|
|
92
|
+
const DEPLOY_STATUSES = [
|
|
93
|
+
"awaiting_ack",
|
|
94
|
+
"deployed",
|
|
95
|
+
"failed",
|
|
96
|
+
"queued",
|
|
97
|
+
];
|
|
98
|
+
function isDeployStatus(value) {
|
|
99
|
+
return DEPLOY_STATUSES.includes(value);
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* SABS's build status as this client's own vocabulary.
|
|
103
|
+
*
|
|
104
|
+
* It answers with `BUILD_STATUS_*` strings through the server, and with the
|
|
105
|
+
* matching protobuf ordinals when the response is not re-serialized on the way
|
|
106
|
+
* — the editor's own client normalizes both, and so does this.
|
|
107
|
+
*/
|
|
108
|
+
const BUILD_PROGRESS_BY_ORDINAL = {
|
|
109
|
+
0: "none",
|
|
110
|
+
1: "running",
|
|
111
|
+
2: "success",
|
|
112
|
+
3: "failed",
|
|
113
|
+
4: "timed_out",
|
|
114
|
+
};
|
|
115
|
+
const BUILD_PROGRESS_BY_NAME = {
|
|
116
|
+
FAILED: "failed",
|
|
117
|
+
RUNNING: "running",
|
|
118
|
+
SUCCESS: "success",
|
|
119
|
+
TIMED_OUT: "timed_out",
|
|
120
|
+
UNSPECIFIED: "none",
|
|
121
|
+
};
|
|
122
|
+
function buildProgress(status) {
|
|
123
|
+
if (typeof status === "number") {
|
|
124
|
+
return BUILD_PROGRESS_BY_ORDINAL[status] ?? "none";
|
|
125
|
+
}
|
|
126
|
+
if (typeof status !== "string") {
|
|
127
|
+
return "none";
|
|
128
|
+
}
|
|
129
|
+
const name = status
|
|
130
|
+
.trim()
|
|
131
|
+
.toUpperCase()
|
|
132
|
+
.replace(/^BUILD_STATUS_/, "");
|
|
133
|
+
return BUILD_PROGRESS_BY_NAME[name] ?? "none";
|
|
134
|
+
}
|
|
135
|
+
export class HttpSuperblocksServerClient {
|
|
136
|
+
identityTimeoutMs;
|
|
137
|
+
readIdentity;
|
|
138
|
+
serverUrl;
|
|
139
|
+
timeoutMs;
|
|
140
|
+
constructor(serverUrl, options = {}) {
|
|
141
|
+
this.serverUrl = serverUrl;
|
|
142
|
+
this.timeoutMs = options.timeoutMs ?? DEFAULT_TIMEOUT_MS;
|
|
143
|
+
this.identityTimeoutMs =
|
|
144
|
+
options.identityTimeoutMs ?? DEFAULT_IDENTITY_TIMEOUT_MS;
|
|
145
|
+
this.readIdentity = withGuardedIdentityReads((apiKey) => this.readIdentityFromServer(apiKey), {
|
|
146
|
+
onOutcome: recordIdentityReadOutcome,
|
|
147
|
+
opensBreaker: identityEndpointUnhealthy,
|
|
148
|
+
...options.identityReads,
|
|
149
|
+
});
|
|
150
|
+
}
|
|
151
|
+
baseUrl() {
|
|
152
|
+
return this.serverUrl.replace(/\/$/, "");
|
|
153
|
+
}
|
|
154
|
+
/**
|
|
155
|
+
* Unwraps the Superblocks `ResponseDto` envelope.
|
|
156
|
+
*
|
|
157
|
+
* Every v1/v2/v3 route the gateway calls replies with
|
|
158
|
+
* `{ responseMeta, data }`. Reading the body directly yields `undefined` for
|
|
159
|
+
* every field, which is indistinguishable from a legitimately empty response
|
|
160
|
+
* — so this is deliberately strict rather than falling back to the raw body.
|
|
161
|
+
*/
|
|
162
|
+
async requestData(path, init) {
|
|
163
|
+
const body = await this.request(path, init);
|
|
164
|
+
if (body?.data === undefined) {
|
|
165
|
+
throw new Error(`Server ${path} returned no data field; expected a { responseMeta, data } envelope`);
|
|
166
|
+
}
|
|
167
|
+
return body.data;
|
|
168
|
+
}
|
|
169
|
+
/**
|
|
170
|
+
* Issues the request, retrying a transient status when the verb makes that
|
|
171
|
+
* safe.
|
|
172
|
+
*
|
|
173
|
+
* A transient failure on the identity lookup used to fail the whole tool call
|
|
174
|
+
* and leave the caller guessing whether their account was broken.
|
|
175
|
+
*
|
|
176
|
+
* 429 counts as transient alongside 5xx: it is the route reporting its own
|
|
177
|
+
* capacity, and backing off is the whole point of it.
|
|
178
|
+
*/
|
|
179
|
+
async request(path, init) {
|
|
180
|
+
const retryable = (init.method ?? "GET").toUpperCase() === "GET";
|
|
181
|
+
let lastError;
|
|
182
|
+
for (let attempt = 0; attempt <= (retryable ? READ_RETRY_ATTEMPTS : 0);) {
|
|
183
|
+
try {
|
|
184
|
+
return await this.send(path, init);
|
|
185
|
+
}
|
|
186
|
+
catch (error) {
|
|
187
|
+
lastError = error;
|
|
188
|
+
const transient = error instanceof ServerHttpError &&
|
|
189
|
+
(error.status >= 500 || error.status === 429);
|
|
190
|
+
attempt += 1;
|
|
191
|
+
if (!retryable || !transient || attempt > READ_RETRY_ATTEMPTS) {
|
|
192
|
+
throw error;
|
|
193
|
+
}
|
|
194
|
+
await delay(READ_RETRY_BASE_DELAY_MS * attempt);
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
throw lastError;
|
|
198
|
+
}
|
|
199
|
+
async send(path, init) {
|
|
200
|
+
const { apiKey, headers: callerHeaders, timeoutMs, ...rest } = init;
|
|
201
|
+
const bound = timeoutMs ?? this.timeoutMs;
|
|
202
|
+
const mergedHeaders = new Headers(callerHeaders);
|
|
203
|
+
// Auth and content-type are owned by this client — never override from callers.
|
|
204
|
+
mergedHeaders.set("Authorization", `Bearer ${apiKey}`);
|
|
205
|
+
if (!mergedHeaders.has("Content-Type")) {
|
|
206
|
+
mergedHeaders.set("Content-Type", "application/json");
|
|
207
|
+
}
|
|
208
|
+
let response;
|
|
209
|
+
try {
|
|
210
|
+
response = await fetch(`${this.baseUrl()}${path}`, {
|
|
211
|
+
...rest,
|
|
212
|
+
headers: mergedHeaders,
|
|
213
|
+
signal: AbortSignal.timeout(bound),
|
|
214
|
+
});
|
|
215
|
+
}
|
|
216
|
+
catch (error) {
|
|
217
|
+
if (error instanceof Error && error.name === "TimeoutError") {
|
|
218
|
+
throw new Error(`Server ${path} timed out after ${bound}ms`);
|
|
219
|
+
}
|
|
220
|
+
throw error;
|
|
221
|
+
}
|
|
222
|
+
if (!response.ok) {
|
|
223
|
+
throw new ServerHttpError(`Server ${path} failed: ${response.status}${detailSuffix(await response.text().catch(() => ""))}`, response.status);
|
|
224
|
+
}
|
|
225
|
+
return (await response.json());
|
|
226
|
+
}
|
|
227
|
+
/**
|
|
228
|
+
* The Superblocks user behind a downstream credential.
|
|
229
|
+
*
|
|
230
|
+
* Cached, collapsed, deadlined and circuit-broken: this is the first thing
|
|
231
|
+
* every MCP tool call does, so reading it straight through coupled the whole
|
|
232
|
+
* tool surface to the health of one route.
|
|
233
|
+
*/
|
|
234
|
+
async validateApiKey(apiKey) {
|
|
235
|
+
return this.readIdentity(apiKey);
|
|
236
|
+
}
|
|
237
|
+
/** The unguarded read behind {@link validateApiKey}. */
|
|
238
|
+
async readIdentityFromServer(apiKey) {
|
|
239
|
+
try {
|
|
240
|
+
const data = await this.requestData("/api/v1/users/me", {
|
|
241
|
+
apiKey,
|
|
242
|
+
method: "GET",
|
|
243
|
+
timeoutMs: this.identityTimeoutMs,
|
|
244
|
+
});
|
|
245
|
+
const user = data.user;
|
|
246
|
+
const organizationId = user?.currentOrganizationId ?? data.organizations?.[0]?.id;
|
|
247
|
+
if (!user || !organizationId) {
|
|
248
|
+
return undefined;
|
|
249
|
+
}
|
|
250
|
+
return {
|
|
251
|
+
email: user.email,
|
|
252
|
+
organizationId,
|
|
253
|
+
userId: user.id,
|
|
254
|
+
};
|
|
255
|
+
}
|
|
256
|
+
catch (error) {
|
|
257
|
+
// Auth failures → undefined (caller elicits login). Transport errors rethrow.
|
|
258
|
+
if (error instanceof ServerHttpError && error.status === 401) {
|
|
259
|
+
return undefined;
|
|
260
|
+
}
|
|
261
|
+
throw error;
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
async getAgentInventory(input) {
|
|
265
|
+
const data = await this.requestData("/api/v1/users/me", {
|
|
266
|
+
apiKey: input.apiKey,
|
|
267
|
+
method: "GET",
|
|
268
|
+
// Same route, so the same bound. This one runs on the build path rather
|
|
269
|
+
// than per tool call, and left at the sandbox timeout a wedged
|
|
270
|
+
// /users/me held a start_app open for two minutes here instead.
|
|
271
|
+
timeoutMs: this.identityTimeoutMs,
|
|
272
|
+
});
|
|
273
|
+
const organization = data.organizations?.find((org) => org.id === input.organizationId) ??
|
|
274
|
+
data.organizations?.find((org) => org.id === data.user?.currentOrganizationId) ??
|
|
275
|
+
data.organizations?.[0];
|
|
276
|
+
if (organization?.agentType === undefined) {
|
|
277
|
+
throw new Error(`Server /api/v1/users/me returned no agentType for organization ${input.organizationId}`);
|
|
278
|
+
}
|
|
279
|
+
const agents = [];
|
|
280
|
+
for (const raw of data.agents ?? []) {
|
|
281
|
+
if (typeof raw.url !== "string" ||
|
|
282
|
+
!raw.url ||
|
|
283
|
+
typeof raw.type !== "number" ||
|
|
284
|
+
typeof raw.status !== "string") {
|
|
285
|
+
continue;
|
|
286
|
+
}
|
|
287
|
+
agents.push({
|
|
288
|
+
status: raw.status,
|
|
289
|
+
tags: raw.tags ?? {},
|
|
290
|
+
type: raw.type,
|
|
291
|
+
url: raw.url,
|
|
292
|
+
});
|
|
293
|
+
}
|
|
294
|
+
return {
|
|
295
|
+
agentType: organization.agentType,
|
|
296
|
+
agents,
|
|
297
|
+
};
|
|
298
|
+
}
|
|
299
|
+
async createApplication(input) {
|
|
300
|
+
return this.requestData("/api/v2/applications/", {
|
|
301
|
+
apiKey: input.apiKey,
|
|
302
|
+
// Live edit only attaches to code-mode apps; without this the server
|
|
303
|
+
// builds a legacy DSL app and `connect` rejects it.
|
|
304
|
+
body: JSON.stringify({
|
|
305
|
+
createUsingReact: true,
|
|
306
|
+
name: input.name,
|
|
307
|
+
organizationId: input.organizationId,
|
|
308
|
+
...(input.templateName ? { templateName: input.templateName } : {}),
|
|
309
|
+
}),
|
|
310
|
+
method: "POST",
|
|
311
|
+
});
|
|
312
|
+
}
|
|
313
|
+
async uploadAttachment(input) {
|
|
314
|
+
const mimeType = input.mimeType ?? "application/zip";
|
|
315
|
+
// Multipart must not go through {@link send}: that helper forces
|
|
316
|
+
// application/json and would break the boundary.
|
|
317
|
+
const response = await uploadAttachmentToServerApi({
|
|
318
|
+
applicationId: input.applicationId,
|
|
319
|
+
authorization: `Bearer ${input.apiKey}`,
|
|
320
|
+
baseUrl: this.baseUrl(),
|
|
321
|
+
descriptor: {
|
|
322
|
+
blob: new Blob([Buffer.from(input.bytes)], { type: mimeType }),
|
|
323
|
+
fileName: input.fileName,
|
|
324
|
+
mimeType,
|
|
325
|
+
},
|
|
326
|
+
prefix: "message-attachment",
|
|
327
|
+
purpose: "attachment",
|
|
328
|
+
scopeType: "app",
|
|
329
|
+
});
|
|
330
|
+
return {
|
|
331
|
+
applicationId: response.applicationId,
|
|
332
|
+
attachmentId: response.attachmentId,
|
|
333
|
+
contentUrl: response.contentUrl,
|
|
334
|
+
fileName: response.fileName,
|
|
335
|
+
mimeType: response.mimeType,
|
|
336
|
+
signedUrl: response.signedUrl,
|
|
337
|
+
signedUrlExpiresAt: response.signedUrlExpiresAt,
|
|
338
|
+
storageKey: response.storageKey,
|
|
339
|
+
};
|
|
340
|
+
}
|
|
341
|
+
async connectLiveEdit(input) {
|
|
342
|
+
const branchSegment = input.branch
|
|
343
|
+
? `/branches/${encodeURIComponent(input.branch)}`
|
|
344
|
+
: "";
|
|
345
|
+
const data = await this.requestData(`/api/v3/applications/${input.applicationId}${branchSegment}/connect`, {
|
|
346
|
+
apiKey: input.apiKey,
|
|
347
|
+
method: "GET",
|
|
348
|
+
});
|
|
349
|
+
if (!data.sandboxStartData) {
|
|
350
|
+
// Absent for a LOCAL lock — there is no remote sandbox to drive.
|
|
351
|
+
throw new Error("Server returned no live edit session for this application");
|
|
352
|
+
}
|
|
353
|
+
return {
|
|
354
|
+
liveEditId: data.sandboxStartData.sandboxId,
|
|
355
|
+
liveEditUrl: data.sandboxStartData.pitcherURL,
|
|
356
|
+
pitcherToken: data.sandboxStartData.pitcherToken,
|
|
357
|
+
pitcherURL: data.sandboxStartData.pitcherURL,
|
|
358
|
+
};
|
|
359
|
+
}
|
|
360
|
+
/**
|
|
361
|
+
* Mints the credential the live-edit session accepts. Connect's
|
|
362
|
+
* `pitcherToken` is a placeholder in the local sandbox path, so the editor
|
|
363
|
+
* mints this separately and so must anything else driving a session.
|
|
364
|
+
*/
|
|
365
|
+
async issueScopedToken(input) {
|
|
366
|
+
// Alone among the routes here, this one answers with a bare OAuth-shaped
|
|
367
|
+
// body rather than the `{ responseMeta, data }` envelope.
|
|
368
|
+
const scope = input.scope ?? "apps:update";
|
|
369
|
+
const body = {
|
|
370
|
+
applicationId: input.applicationId,
|
|
371
|
+
scope,
|
|
372
|
+
};
|
|
373
|
+
if (scope === "apps:preview") {
|
|
374
|
+
if (!input.commitId?.trim()) {
|
|
375
|
+
throw new Error("apps:preview scoped tokens require a commitId so the viewer can load that commit");
|
|
376
|
+
}
|
|
377
|
+
body.commitId = input.commitId;
|
|
378
|
+
}
|
|
379
|
+
const data = await this.request("/api/v1/token/scoped", {
|
|
380
|
+
apiKey: input.apiKey,
|
|
381
|
+
body: JSON.stringify(body),
|
|
382
|
+
method: "POST",
|
|
383
|
+
});
|
|
384
|
+
if (!data?.access_token) {
|
|
385
|
+
throw new Error("Server /api/v1/token/scoped returned no access_token; the live-edit session has nothing to verify");
|
|
386
|
+
}
|
|
387
|
+
return data.access_token;
|
|
388
|
+
}
|
|
389
|
+
async getSupersetIntegrations(input) {
|
|
390
|
+
const params = new URLSearchParams({
|
|
391
|
+
// The endpoint rejects a request without `kind` (400 "Kind must be
|
|
392
|
+
// provided."); PLUGIN is what the editor asks for when it builds the
|
|
393
|
+
// integration list Clark sees.
|
|
394
|
+
kind: "PLUGIN",
|
|
395
|
+
organizationId: input.organizationId,
|
|
396
|
+
});
|
|
397
|
+
if (input.applicationId) {
|
|
398
|
+
params.set("applicationId", input.applicationId);
|
|
399
|
+
}
|
|
400
|
+
const data = await this.requestData(`/api/v1/integrations/superset?${params.toString()}`, { apiKey: input.apiKey, method: "GET" });
|
|
401
|
+
return Array.isArray(data) ? data : [];
|
|
402
|
+
}
|
|
403
|
+
async getIntegration(input) {
|
|
404
|
+
try {
|
|
405
|
+
return await this.requestData(`/api/v1/integrations/${encodeURIComponent(input.integrationId)}`, { apiKey: input.apiKey, method: "GET" });
|
|
406
|
+
}
|
|
407
|
+
catch (error) {
|
|
408
|
+
if (error instanceof ServerHttpError && error.status === 404) {
|
|
409
|
+
return undefined;
|
|
410
|
+
}
|
|
411
|
+
throw error;
|
|
412
|
+
}
|
|
413
|
+
}
|
|
414
|
+
async getOrganizationProfiles(input) {
|
|
415
|
+
const data = await this.requestData(`/api/v1/organizations/${encodeURIComponent(input.organizationId)}/profiles`, { apiKey: input.apiKey, method: "GET" });
|
|
416
|
+
if (!Array.isArray(data)) {
|
|
417
|
+
return [];
|
|
418
|
+
}
|
|
419
|
+
return data
|
|
420
|
+
.filter((row) => typeof row?.key === "string" && row.key.length > 0)
|
|
421
|
+
.map((row) => ({
|
|
422
|
+
...(row.allowedInEditor !== undefined
|
|
423
|
+
? { allowedInEditor: row.allowedInEditor }
|
|
424
|
+
: {}),
|
|
425
|
+
...(row.displayName ? { displayName: row.displayName } : {}),
|
|
426
|
+
...(row.id ? { id: row.id } : {}),
|
|
427
|
+
key: row.key,
|
|
428
|
+
}));
|
|
429
|
+
}
|
|
430
|
+
/**
|
|
431
|
+
* Snapshots the application's current live-edit state as a commit.
|
|
432
|
+
*
|
|
433
|
+
* Deploys address a commit, never a branch head, so anything publishing work
|
|
434
|
+
* that has not been committed yet has to make one first — the same thing the
|
|
435
|
+
* editor's publish flow does.
|
|
436
|
+
*/
|
|
437
|
+
async createCommit(input) {
|
|
438
|
+
const branchSegment = input.branch
|
|
439
|
+
? `/branches/${encodeURIComponent(input.branch)}`
|
|
440
|
+
: "";
|
|
441
|
+
const data = await this.requestData(`/api/v2/applications/${input.applicationId}${branchSegment}/commit`, {
|
|
442
|
+
apiKey: input.apiKey,
|
|
443
|
+
body: JSON.stringify({
|
|
444
|
+
commitMessage: input.message,
|
|
445
|
+
// The server compares this against the last live-edit write to catch
|
|
446
|
+
// a commit racing an editor that has moved on since.
|
|
447
|
+
lastSuccessfulWrite: Date.now(),
|
|
448
|
+
}),
|
|
449
|
+
method: "POST",
|
|
450
|
+
});
|
|
451
|
+
return {
|
|
452
|
+
commitId: data.commitId,
|
|
453
|
+
...(data.directoryContentsHash
|
|
454
|
+
? { directoryHash: data.directoryContentsHash }
|
|
455
|
+
: {}),
|
|
456
|
+
};
|
|
457
|
+
}
|
|
458
|
+
/**
|
|
459
|
+
* Starts a SABS build of a commit's content, the same call the editor makes
|
|
460
|
+
* behind Preview and behind a publish.
|
|
461
|
+
*
|
|
462
|
+
* The response carries a build id this caller has no use for: progress is
|
|
463
|
+
* observed by content hash, which is also how a preview and a publish of the
|
|
464
|
+
* same content end up watching one build instead of racing two.
|
|
465
|
+
*/
|
|
466
|
+
async createBuild(input) {
|
|
467
|
+
await this.request(`/api/v3/applications/${input.applicationId}/${encodeURIComponent(input.directoryHash)}/builds`, {
|
|
468
|
+
apiKey: input.apiKey,
|
|
469
|
+
body: JSON.stringify({ commitId: input.commitId }),
|
|
470
|
+
method: "POST",
|
|
471
|
+
});
|
|
472
|
+
}
|
|
473
|
+
async getBuildProgress(input) {
|
|
474
|
+
const path = `/api/v3/applications/${input.applicationId}/build-bulk-status`;
|
|
475
|
+
// POST because the hashes go in the body, but it is a read: the server
|
|
476
|
+
// asks SABS for status and changes nothing.
|
|
477
|
+
const data = await this.requestData(path, {
|
|
478
|
+
apiKey: input.apiKey,
|
|
479
|
+
body: JSON.stringify({ directoryHashes: [input.directoryHash] }),
|
|
480
|
+
method: "POST",
|
|
481
|
+
});
|
|
482
|
+
// Absent for content SABS has never built. Same meaning as UNSPECIFIED:
|
|
483
|
+
// there is no build to wait for.
|
|
484
|
+
return buildProgress(data.directoryHashToStatus?.[input.directoryHash]?.status);
|
|
485
|
+
}
|
|
486
|
+
async deployApplication(input) {
|
|
487
|
+
const path = `/api/v2/applications/${input.applicationId}/deployments`;
|
|
488
|
+
const body = await this.request(path, {
|
|
489
|
+
apiKey: input.apiKey,
|
|
490
|
+
// PostApplicationDeployRequestBody rejects unknown properties, so this
|
|
491
|
+
// body carries the commit and nothing else — the branch is already
|
|
492
|
+
// fixed by the commit being deployed.
|
|
493
|
+
body: JSON.stringify({ commitId: input.commitId }),
|
|
494
|
+
method: "POST",
|
|
495
|
+
});
|
|
496
|
+
if (body?.data?.deploymentId) {
|
|
497
|
+
return { deploymentId: body.data.deploymentId, status: "deployed" };
|
|
498
|
+
}
|
|
499
|
+
if (isDeployStatus(body?.status)) {
|
|
500
|
+
return { message: body?.message, status: body.status };
|
|
501
|
+
}
|
|
502
|
+
// Neither shape. Guessing "it worked" here would report a publish that
|
|
503
|
+
// never happened as a success.
|
|
504
|
+
throw new Error(`Server ${path} returned neither a deployment nor a deploy status`);
|
|
505
|
+
}
|
|
506
|
+
/**
|
|
507
|
+
* Polls the deploy queue for a commit the UI watches after a queued publish.
|
|
508
|
+
*/
|
|
509
|
+
async getDeployStatus(input) {
|
|
510
|
+
const path = `/api/v2/applications/${input.applicationId}/deploy-status/${encodeURIComponent(input.commitId)}`;
|
|
511
|
+
const body = await this.request(path, {
|
|
512
|
+
apiKey: input.apiKey,
|
|
513
|
+
method: "GET",
|
|
514
|
+
});
|
|
515
|
+
const status = body?.status;
|
|
516
|
+
if (status === "none" ||
|
|
517
|
+
status === "QUEUED" ||
|
|
518
|
+
status === "DEPLOYING" ||
|
|
519
|
+
status === "DEPLOYED" ||
|
|
520
|
+
status === "FAILED" ||
|
|
521
|
+
status === "AWAITING_ACK") {
|
|
522
|
+
return {
|
|
523
|
+
error: typeof body?.error === "string" ? body.error : undefined,
|
|
524
|
+
isLive: typeof body?.isLive === "boolean" ? body.isLive : undefined,
|
|
525
|
+
status,
|
|
526
|
+
};
|
|
527
|
+
}
|
|
528
|
+
throw new Error(`Server ${path} returned an unknown deploy status`);
|
|
529
|
+
}
|
|
530
|
+
/**
|
|
531
|
+
* Asks Clark for an app name, the same way the editor header does after a
|
|
532
|
+
* prompt-created app loads.
|
|
533
|
+
*/
|
|
534
|
+
async generateAppName(input) {
|
|
535
|
+
// Another bare body rather than the `{ responseMeta, data }` envelope.
|
|
536
|
+
const data = await this.request("/api/v1/ai/generate-app-name", {
|
|
537
|
+
apiKey: input.apiKey,
|
|
538
|
+
body: JSON.stringify({
|
|
539
|
+
applicationId: input.applicationId,
|
|
540
|
+
prompt: input.prompt,
|
|
541
|
+
}),
|
|
542
|
+
method: "POST",
|
|
543
|
+
});
|
|
544
|
+
if (!data?.name?.trim()) {
|
|
545
|
+
throw new Error("Server /api/v1/ai/generate-app-name returned no name");
|
|
546
|
+
}
|
|
547
|
+
return data.name.trim();
|
|
548
|
+
}
|
|
549
|
+
/**
|
|
550
|
+
* Looks a name up in the org-wide application listing.
|
|
551
|
+
*
|
|
552
|
+
* The API exposes no single-application GET that carries a name — only this
|
|
553
|
+
* listing and the metadata PUT — so one label costs a list read. That is
|
|
554
|
+
* affordable where it is used (alongside a build and a screenshot) and is
|
|
555
|
+
* why nothing on a hot path should call it.
|
|
556
|
+
*/
|
|
557
|
+
async getApplicationName(input) {
|
|
558
|
+
const body = await this.request("/api/v2/applications", { apiKey: input.apiKey, method: "GET" });
|
|
559
|
+
const found = body?.data?.applications?.find((application) => application?.id === input.applicationId);
|
|
560
|
+
return found?.name?.trim() || undefined;
|
|
561
|
+
}
|
|
562
|
+
async renameApplication(input) {
|
|
563
|
+
await this.request(`/api/v2/applications/${input.applicationId}/metadata`, {
|
|
564
|
+
apiKey: input.apiKey,
|
|
565
|
+
// PutApplicationMetadataUpdateRequestBody accepts exactly one of name,
|
|
566
|
+
// folderId, or isPublic — sending more than one fails validation.
|
|
567
|
+
body: JSON.stringify({ name: input.name }),
|
|
568
|
+
method: "PUT",
|
|
569
|
+
});
|
|
570
|
+
}
|
|
571
|
+
}
|
|
572
|
+
//# sourceMappingURL=client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.js","sourceRoot":"","sources":["../../src/server/client.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Why an identity lookup produced no answer.
|
|
3
|
+
*
|
|
4
|
+
* `caller_timeout` and `read_failed` need telling apart: the first means the
|
|
5
|
+
* endpoint is slow and the cache is about to fill, the second means it is down.
|
|
6
|
+
*/
|
|
7
|
+
export type IdentityUnavailableReason = "breaker_open" | "caller_timeout" | "read_failed";
|
|
8
|
+
/**
|
|
9
|
+
* The identity lookup did not produce an answer this caller can act on.
|
|
10
|
+
*
|
|
11
|
+
* Distinct from "the credential was refused": nothing is known about the
|
|
12
|
+
* caller's account, so the right response is to try again rather than to
|
|
13
|
+
* re-link. Capabilities map this to `downstream_unavailable`.
|
|
14
|
+
*/
|
|
15
|
+
export declare class IdentityUnavailableError extends Error {
|
|
16
|
+
readonly reason: IdentityUnavailableReason;
|
|
17
|
+
constructor(message: string, options?: {
|
|
18
|
+
cause?: unknown;
|
|
19
|
+
reason?: IdentityUnavailableReason;
|
|
20
|
+
});
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* What one guarded call cost. A closed set because it becomes a metric label.
|
|
24
|
+
*/
|
|
25
|
+
export type IdentityReadOutcome = "breaker_open" | "cached" | "caller_timeout"
|
|
26
|
+
/**
|
|
27
|
+
* The read failed in a way that says something about this one credential
|
|
28
|
+
* rather than about the endpoint — the errors `opensBreaker` rejects.
|
|
29
|
+
* Separate from `outage` so a client looping on a revoked key cannot make a
|
|
30
|
+
* healthy endpoint look like it is failing.
|
|
31
|
+
*/
|
|
32
|
+
| "credential_error" | "outage" | "refused" | "resolved";
|
|
33
|
+
/** Resolves the identity behind a downstream credential, or refuses it. */
|
|
34
|
+
export type IdentityRead<T> = (apiKey: string) => Promise<T | undefined>;
|
|
35
|
+
export type GuardedIdentityReadOptions = {
|
|
36
|
+
/** How long a resolved identity is trusted before the API is asked again. */
|
|
37
|
+
cacheTtlMs?: number;
|
|
38
|
+
/** How long one caller waits for a read before it gives up on this call. */
|
|
39
|
+
callerWaitMs?: number;
|
|
40
|
+
/** How long reads fail fast after the API failed to answer one. */
|
|
41
|
+
cooldownMs?: number;
|
|
42
|
+
now?: () => number;
|
|
43
|
+
/** Reports what one call cost. Wired to a counter in the HTTP client. */
|
|
44
|
+
onOutcome?: (outcome: IdentityReadOutcome) => void;
|
|
45
|
+
/**
|
|
46
|
+
* Whether a failed read means the endpoint is unhealthy, rather than that
|
|
47
|
+
* this one credential was refused. Only the former opens the breaker: a
|
|
48
|
+
* single bad credential must not fail every other caller fast.
|
|
49
|
+
*/
|
|
50
|
+
opensBreaker?: (error: unknown) => boolean;
|
|
51
|
+
};
|
|
52
|
+
/**
|
|
53
|
+
* Makes the identity lookup that every tool call gates on cheap and bounded.
|
|
54
|
+
*
|
|
55
|
+
* `GET /api/v1/users/me` is the first thing every capability does and the
|
|
56
|
+
* slowest endpoint the Superblocks API exposes. Read straight through, one
|
|
57
|
+
* wedged upstream took down the whole tool surface: each call waited out the
|
|
58
|
+
* full client timeout, a burst of callers multiplied the load on the endpoint
|
|
59
|
+
* that was already stuck, and nothing remembered that the last twenty calls
|
|
60
|
+
* had just failed the same way.
|
|
61
|
+
*
|
|
62
|
+
* Four things fix that, and they have to work together:
|
|
63
|
+
*
|
|
64
|
+
* - **Cache.** Identity does not change between polls, so a poll loop spends
|
|
65
|
+
* one read per TTL instead of one per call.
|
|
66
|
+
* - **Collapse.** Concurrent callers on a cold cache join one read rather than
|
|
67
|
+
* each starting their own.
|
|
68
|
+
* - **Caller deadline.** A tool call stops waiting at the window its own
|
|
69
|
+
* contract advertises. The read keeps running, so an endpoint that answers
|
|
70
|
+
* slowly still fills the cache and the next call is served from it — the
|
|
71
|
+
* reason this is a deadline on the wait and not a shorter timeout on the
|
|
72
|
+
* read.
|
|
73
|
+
* - **Breaker.** Once a read fails, later calls fail fast for a cooldown
|
|
74
|
+
* instead of each discovering the same outage the slow way.
|
|
75
|
+
*/
|
|
76
|
+
export declare function withGuardedIdentityReads<T>(read: IdentityRead<T>, options?: GuardedIdentityReadOptions): IdentityRead<T>;
|