@superblocksteam/gateway 2.0.177-next.0 → 2.0.178-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/README.md +52 -19
- package/dist/agents/hosted-boundary.d.ts +36 -0
- package/dist/agents/hosted-boundary.d.ts.map +1 -0
- package/dist/agents/hosted-boundary.js +66 -0
- package/dist/agents/hosted-boundary.js.map +1 -0
- package/dist/agents/resolve-orchestrator-url.d.ts +8 -0
- package/dist/agents/resolve-orchestrator-url.d.ts.map +1 -1
- package/dist/agents/resolve-orchestrator-url.js +5 -0
- package/dist/agents/resolve-orchestrator-url.js.map +1 -1
- package/dist/capabilities/integration-metadata.d.ts.map +1 -1
- package/dist/capabilities/integration-metadata.js +12 -1
- package/dist/capabilities/integration-metadata.js.map +1 -1
- package/dist/capabilities/lifecycle.d.ts +1 -6
- package/dist/capabilities/lifecycle.d.ts.map +1 -1
- package/dist/capabilities/lifecycle.js +339 -21
- package/dist/capabilities/lifecycle.js.map +1 -1
- package/dist/capabilities/live-state-attaches.d.ts +28 -0
- package/dist/capabilities/live-state-attaches.d.ts.map +1 -1
- package/dist/capabilities/live-state-attaches.js +33 -0
- package/dist/capabilities/live-state-attaches.js.map +1 -1
- package/dist/capabilities/query-integration.d.ts.map +1 -1
- package/dist/capabilities/query-integration.js +12 -1
- package/dist/capabilities/query-integration.js.map +1 -1
- package/dist/capabilities/tool-permission-reply.d.ts.map +1 -1
- package/dist/capabilities/tool-permission-reply.js.map +1 -1
- package/dist/capabilities/types.d.ts +3 -4
- package/dist/capabilities/types.d.ts.map +1 -1
- package/dist/capabilities/types.js.map +1 -1
- package/dist/capture/browser-contract.d.ts +1 -18
- package/dist/capture/browser-contract.d.ts.map +1 -1
- package/dist/capture/browser-contract.js +1 -13
- package/dist/capture/browser-contract.js.map +1 -1
- package/dist/capture/browser-instructions.d.ts +3 -3
- package/dist/capture/browser-instructions.d.ts.map +1 -1
- package/dist/capture/browser-instructions.js +4 -5
- package/dist/capture/browser-instructions.js.map +1 -1
- package/dist/capture/capture-library-probe.d.ts +0 -1
- package/dist/capture/capture-library-probe.d.ts.map +1 -1
- package/dist/capture/capture-library-probe.js +1 -1
- package/dist/capture/capture-library-probe.js.map +1 -1
- package/dist/capture/capture-library.d.ts +2 -1
- package/dist/capture/capture-library.d.ts.map +1 -1
- package/dist/capture/classify-library-paint.d.ts +2 -1
- package/dist/capture/classify-library-paint.d.ts.map +1 -1
- package/dist/capture/library-parent-script.d.ts +3 -2
- package/dist/capture/library-parent-script.d.ts.map +1 -1
- package/dist/capture/mode.d.ts +2 -3
- package/dist/capture/mode.d.ts.map +1 -1
- package/dist/capture/mode.js +2 -3
- package/dist/capture/mode.js.map +1 -1
- package/dist/config.d.ts +21 -1
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +3 -0
- package/dist/config.js.map +1 -1
- package/dist/debug.js.map +1 -1
- package/dist/deps.d.ts +3 -3
- package/dist/health/readiness.d.ts +2 -1
- package/dist/health/readiness.d.ts.map +1 -1
- package/dist/http/main.d.ts +3 -0
- package/dist/http/main.d.ts.map +1 -0
- package/dist/http/main.js +11 -0
- package/dist/http/main.js.map +1 -0
- package/dist/http/serve.d.ts +26 -0
- package/dist/http/serve.d.ts.map +1 -0
- package/dist/http/serve.js +298 -0
- package/dist/http/serve.js.map +1 -0
- package/dist/integrations/filters.d.ts.map +1 -1
- package/dist/integrations/filters.js +1 -16
- package/dist/integrations/filters.js.map +1 -1
- package/dist/integrations/map.d.ts +0 -5
- package/dist/integrations/map.d.ts.map +1 -1
- package/dist/integrations/map.js +1 -1
- package/dist/integrations/map.js.map +1 -1
- package/dist/internal-ingress.d.ts +47 -0
- package/dist/internal-ingress.d.ts.map +1 -0
- package/dist/internal-ingress.js +90 -0
- package/dist/internal-ingress.js.map +1 -0
- package/dist/orchestrator/client.d.ts +11 -5
- package/dist/orchestrator/client.d.ts.map +1 -1
- package/dist/orchestrator/client.js +14 -3
- package/dist/orchestrator/client.js.map +1 -1
- package/dist/playwright/ensure-chromium.js.map +1 -1
- package/dist/preview/capture-screenshot.d.ts +2 -2
- package/dist/preview/capture-screenshot.d.ts.map +1 -1
- package/dist/preview/capture-screenshot.js +2 -2
- package/dist/preview/capture-screenshot.js.map +1 -1
- package/dist/process/fault-barrier.d.ts +4 -3
- package/dist/process/fault-barrier.d.ts.map +1 -1
- package/dist/sabs/app-state.d.ts +2 -13
- package/dist/sabs/app-state.d.ts.map +1 -1
- package/dist/sabs/app-state.js +7 -2
- package/dist/sabs/app-state.js.map +1 -1
- package/dist/sabs/awaited-decision.d.ts.map +1 -1
- package/dist/sabs/browser-context.d.ts +4 -1
- package/dist/sabs/browser-context.d.ts.map +1 -1
- package/dist/sabs/browser-context.js +1 -0
- package/dist/sabs/browser-context.js.map +1 -1
- package/dist/sabs/editor-client-methods.d.ts.map +1 -1
- package/dist/sabs/editor-client-methods.js +1 -1
- package/dist/sabs/editor-client-methods.js.map +1 -1
- package/dist/sabs/editor-socket.d.ts.map +1 -1
- package/dist/sabs/editor-socket.js.map +1 -1
- package/dist/sabs/session-peer.d.ts +13 -1
- package/dist/sabs/session-peer.d.ts.map +1 -1
- package/dist/sabs/session-peer.js.map +1 -1
- package/dist/sabs/streamed-reply.d.ts.map +1 -1
- package/dist/sabs/streamed-reply.js.map +1 -1
- package/dist/sabs/turn-collector.d.ts.map +1 -1
- package/dist/sabs/turn-collector.js.map +1 -1
- package/dist/sabs/websocket-session-peer.d.ts +17 -1
- package/dist/sabs/websocket-session-peer.d.ts.map +1 -1
- package/dist/sabs/websocket-session-peer.js +89 -15
- package/dist/sabs/websocket-session-peer.js.map +1 -1
- package/dist/server/client.d.ts +48 -0
- package/dist/server/client.d.ts.map +1 -1
- package/dist/server/client.js +91 -173
- package/dist/server/client.js.map +1 -1
- package/dist/server/identity-reads.d.ts +5 -3
- package/dist/server/identity-reads.d.ts.map +1 -1
- package/dist/server/identity-reads.js +31 -4
- package/dist/server/identity-reads.js.map +1 -1
- package/dist/start.d.ts +5 -1
- package/dist/start.d.ts.map +1 -1
- package/dist/start.js +23 -9
- package/dist/start.js.map +1 -1
- package/dist/stores/memory.d.ts.map +1 -1
- package/dist/stores/types.d.ts +2 -1
- package/dist/stores/types.d.ts.map +1 -1
- package/dist/telemetry/mcp-client.d.ts +2 -1
- package/dist/telemetry/mcp-client.d.ts.map +1 -1
- package/dist/telemetry/mcp-client.js.map +1 -1
- package/dist/telemetry/mcp-usage.d.ts +22 -0
- package/dist/telemetry/mcp-usage.d.ts.map +1 -0
- package/dist/telemetry/mcp-usage.js +102 -0
- package/dist/telemetry/mcp-usage.js.map +1 -0
- package/dist/telemetry/metrics.d.ts +9 -0
- package/dist/telemetry/metrics.d.ts.map +1 -1
- package/dist/telemetry/metrics.js +21 -0
- package/dist/telemetry/metrics.js.map +1 -1
- package/dist/telemetry/runtime.d.ts +2 -1
- package/dist/telemetry/runtime.d.ts.map +1 -1
- package/dist/telemetry/runtime.js +18 -5
- package/dist/telemetry/runtime.js.map +1 -1
- package/dist/transports/mcp/admin-tools.d.ts +3 -7
- package/dist/transports/mcp/admin-tools.d.ts.map +1 -1
- package/dist/transports/mcp/admin-tools.js +9 -82
- package/dist/transports/mcp/admin-tools.js.map +1 -1
- package/dist/transports/mcp/app-status-html.d.ts +2 -2
- package/dist/transports/mcp/app-status-html.d.ts.map +1 -1
- package/dist/transports/mcp/app-status-html.js +1 -27
- package/dist/transports/mcp/app-status-html.js.map +1 -1
- package/dist/transports/mcp/client-presentation.d.ts +10 -13
- package/dist/transports/mcp/client-presentation.d.ts.map +1 -1
- package/dist/transports/mcp/client-presentation.js +2 -14
- package/dist/transports/mcp/client-presentation.js.map +1 -1
- package/dist/transports/mcp/decision-elicitation.js +23 -1
- package/dist/transports/mcp/decision-elicitation.js.map +1 -1
- package/dist/transports/mcp/dispatch-probe.js.map +1 -1
- package/dist/transports/mcp/editor-document-probe.js.map +1 -1
- package/dist/transports/mcp/editor-integration-setup-url.d.ts +0 -1
- package/dist/transports/mcp/editor-integration-setup-url.d.ts.map +1 -1
- package/dist/transports/mcp/editor-integration-setup-url.js +0 -3
- package/dist/transports/mcp/editor-integration-setup-url.js.map +1 -1
- package/dist/transports/mcp/format-tool-content.js +1 -1
- package/dist/transports/mcp/format-tool-content.js.map +1 -1
- package/dist/transports/mcp/instructions/tools/build-app.d.ts +2 -3
- package/dist/transports/mcp/instructions/tools/build-app.d.ts.map +1 -1
- package/dist/transports/mcp/instructions/tools/build-app.js +5 -11
- package/dist/transports/mcp/instructions/tools/build-app.js.map +1 -1
- package/dist/transports/mcp/instructions/tools/check-app-progress.d.ts.map +1 -1
- package/dist/transports/mcp/instructions/tools/check-app-progress.js +1 -25
- package/dist/transports/mcp/instructions/tools/check-app-progress.js.map +1 -1
- package/dist/transports/mcp/instructions/tools/check-publish-progress.d.ts +1 -2
- package/dist/transports/mcp/instructions/tools/check-publish-progress.d.ts.map +1 -1
- package/dist/transports/mcp/instructions/tools/check-publish-progress.js +2 -11
- package/dist/transports/mcp/instructions/tools/check-publish-progress.js.map +1 -1
- package/dist/transports/mcp/instructions/tools/copy.d.ts +1 -8
- package/dist/transports/mcp/instructions/tools/copy.d.ts.map +1 -1
- package/dist/transports/mcp/instructions/tools/copy.js +4 -28
- package/dist/transports/mcp/instructions/tools/copy.js.map +1 -1
- package/dist/transports/mcp/instructions/tools/create-integration.d.ts +1 -2
- package/dist/transports/mcp/instructions/tools/create-integration.d.ts.map +1 -1
- package/dist/transports/mcp/instructions/tools/create-integration.js +4 -8
- package/dist/transports/mcp/instructions/tools/create-integration.js.map +1 -1
- package/dist/transports/mcp/instructions/tools/edit-app.js +2 -2
- package/dist/transports/mcp/instructions/tools/edit-app.js.map +1 -1
- package/dist/transports/mcp/instructions/tools/get-app.d.ts.map +1 -1
- package/dist/transports/mcp/instructions/tools/get-app.js +1 -23
- package/dist/transports/mcp/instructions/tools/get-app.js.map +1 -1
- package/dist/transports/mcp/instructions/tools/index.d.ts.map +1 -1
- package/dist/transports/mcp/instructions/tools/index.js +0 -4
- package/dist/transports/mcp/instructions/tools/index.js.map +1 -1
- package/dist/transports/mcp/instructions/tools/publish-app.d.ts +1 -2
- package/dist/transports/mcp/instructions/tools/publish-app.d.ts.map +1 -1
- package/dist/transports/mcp/instructions/tools/publish-app.js +1 -10
- package/dist/transports/mcp/instructions/tools/publish-app.js.map +1 -1
- package/dist/transports/mcp/instructions/tools/start-app.d.ts +1 -2
- package/dist/transports/mcp/instructions/tools/start-app.d.ts.map +1 -1
- package/dist/transports/mcp/instructions/tools/start-app.js +3 -3
- package/dist/transports/mcp/instructions/tools/start-app.js.map +1 -1
- package/dist/transports/mcp/mount.d.ts +8 -15
- package/dist/transports/mcp/mount.d.ts.map +1 -1
- package/dist/transports/mcp/mount.js +233 -206
- package/dist/transports/mcp/mount.js.map +1 -1
- package/dist/transports/mcp/plan-approval.d.ts.map +1 -1
- package/dist/transports/mcp/plan-approval.js.map +1 -1
- package/dist/transports/mcp/tool-permissions.d.ts +30 -0
- package/dist/transports/mcp/tool-permissions.d.ts.map +1 -0
- package/dist/transports/mcp/tool-permissions.js +39 -0
- package/dist/transports/mcp/tool-permissions.js.map +1 -0
- package/package.json +28 -22
- package/skills/superblocks-import/SKILL.md +5 -3
- package/dist/capture/cowork-editor-url.d.ts +0 -7
- package/dist/capture/cowork-editor-url.d.ts.map +0 -1
- package/dist/capture/cowork-editor-url.js +0 -12
- package/dist/capture/cowork-editor-url.js.map +0 -1
- package/dist/transports/mcp/native-browser-presence.d.ts +0 -46
- package/dist/transports/mcp/native-browser-presence.d.ts.map +0 -1
- package/dist/transports/mcp/native-browser-presence.js +0 -158
- package/dist/transports/mcp/native-browser-presence.js.map +0 -1
- package/skills/superblocks-build/SKILL.md +0 -59
package/dist/server/client.js
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import { llmConfigFromFlags, } from "@superblocksteam/library-shared/types";
|
|
2
|
-
import {
|
|
2
|
+
import { errorCode, isLostConnection, isRequestNotSent, isTransientHttpStatus, MIN_RETRY_ATTEMPT_MS, ReadRetrySchedule, } from "@superblocksteam/mcp-server/read-retry";
|
|
3
|
+
import { PlatformMcpServerRequest, uploadAttachmentToServerApi, } from "@superblocksteam/shared";
|
|
4
|
+
import { internalIngress } from "../internal-ingress.js";
|
|
3
5
|
import { recordFactsFlagBootstrapOutcome, recordIdentityReadOutcome, recordServerReadRetryOutcome, } from "../telemetry/metrics.js";
|
|
4
6
|
import { withGuardedIdentityReads, } from "./identity-reads.js";
|
|
5
7
|
const MAX_DETAIL_LENGTH = 300;
|
|
@@ -54,51 +56,6 @@ export class ServerTimeoutError extends Error {
|
|
|
54
56
|
this.name = "ServerTimeoutError";
|
|
55
57
|
}
|
|
56
58
|
}
|
|
57
|
-
const RETRYABLE_TRANSPORT_CODES = new Set([
|
|
58
|
-
"EAI_AGAIN",
|
|
59
|
-
"ECONNABORTED",
|
|
60
|
-
"ECONNREFUSED",
|
|
61
|
-
"ECONNRESET",
|
|
62
|
-
"EHOSTUNREACH",
|
|
63
|
-
"ENETDOWN",
|
|
64
|
-
"ENETUNREACH",
|
|
65
|
-
"EPIPE",
|
|
66
|
-
"ETIMEDOUT",
|
|
67
|
-
"UND_ERR_BODY_TIMEOUT",
|
|
68
|
-
"UND_ERR_CONNECT_TIMEOUT",
|
|
69
|
-
"UND_ERR_HEADERS_TIMEOUT",
|
|
70
|
-
"UND_ERR_SOCKET",
|
|
71
|
-
]);
|
|
72
|
-
const UNSENT_TRANSPORT_CODES = new Set([
|
|
73
|
-
"EAI_AGAIN",
|
|
74
|
-
"ECONNREFUSED",
|
|
75
|
-
"EHOSTUNREACH",
|
|
76
|
-
"ENETDOWN",
|
|
77
|
-
"ENETUNREACH",
|
|
78
|
-
"UND_ERR_CONNECT_TIMEOUT",
|
|
79
|
-
]);
|
|
80
|
-
function errorCode(error, depth = 0) {
|
|
81
|
-
if (depth >= 4 || !error || typeof error !== "object") {
|
|
82
|
-
return undefined;
|
|
83
|
-
}
|
|
84
|
-
const { cause, code } = error;
|
|
85
|
-
if (typeof code === "string") {
|
|
86
|
-
return code;
|
|
87
|
-
}
|
|
88
|
-
const causeCode = errorCode(cause, depth + 1);
|
|
89
|
-
if (causeCode) {
|
|
90
|
-
return causeCode;
|
|
91
|
-
}
|
|
92
|
-
if (error instanceof AggregateError) {
|
|
93
|
-
for (const nested of error.errors) {
|
|
94
|
-
const nestedCode = errorCode(nested, depth + 1);
|
|
95
|
-
if (nestedCode) {
|
|
96
|
-
return nestedCode;
|
|
97
|
-
}
|
|
98
|
-
}
|
|
99
|
-
}
|
|
100
|
-
return undefined;
|
|
101
|
-
}
|
|
102
59
|
/**
|
|
103
60
|
* The connection failed: refused, reset, or dropped before the answer was
|
|
104
61
|
* complete. Named so a retry can cover it without also covering a response
|
|
@@ -118,10 +75,8 @@ export class ServerTransportError extends Error {
|
|
|
118
75
|
this.name = "ServerTransportError";
|
|
119
76
|
this.code = code;
|
|
120
77
|
this.requestNotSent =
|
|
121
|
-
options.requestNotSent === true &&
|
|
122
|
-
|
|
123
|
-
UNSENT_TRANSPORT_CODES.has(code);
|
|
124
|
-
this.retryable = code !== undefined && RETRYABLE_TRANSPORT_CODES.has(code);
|
|
78
|
+
options.requestNotSent === true && isRequestNotSent(options.cause);
|
|
79
|
+
this.retryable = isLostConnection(options.cause);
|
|
125
80
|
}
|
|
126
81
|
}
|
|
127
82
|
/**
|
|
@@ -144,6 +99,10 @@ const DEFAULT_TIMEOUT_MS = 120_000;
|
|
|
144
99
|
* rather than never can still finish and fill the cache.
|
|
145
100
|
*/
|
|
146
101
|
const DEFAULT_IDENTITY_TIMEOUT_MS = 30_000;
|
|
102
|
+
/** The live-edit connect route, on the branch when there is one. */
|
|
103
|
+
const liveEditConnectRequest = (applicationId, branch) => branch
|
|
104
|
+
? PlatformMcpServerRequest.to("GET /api/v3/applications/*/branches/*/connect", applicationId, branch)
|
|
105
|
+
: PlatformMcpServerRequest.to("GET /api/v3/applications/*/connect", applicationId);
|
|
147
106
|
/**
|
|
148
107
|
* Whether a failed identity read means the endpoint is unhealthy rather than
|
|
149
108
|
* that this one credential is bad.
|
|
@@ -162,72 +121,15 @@ const DEFAULT_IDENTITY_TIMEOUT_MS = 30_000;
|
|
|
162
121
|
function identityEndpointUnhealthy(error) {
|
|
163
122
|
return !(error instanceof ServerHttpError && !isTransientHttpStatus(error.status));
|
|
164
123
|
}
|
|
165
|
-
function isTransientHttpStatus(status) {
|
|
166
|
-
return status >= 500 || status === 429;
|
|
167
|
-
}
|
|
168
124
|
/**
|
|
169
|
-
*
|
|
170
|
-
*
|
|
171
|
-
* Only reads are retried, and only because the call sites that leave `retry`
|
|
172
|
-
* on are pure lookups: a repeat of one changes nothing. A failed POST may well
|
|
173
|
-
* have taken effect, and re-sending one can deploy or commit twice; a read
|
|
174
|
-
* that provisions, or that already sits in its own poll loop, opts out.
|
|
175
|
-
*
|
|
176
|
-
* A transient status is a fast answer from a route that is up, so a short
|
|
177
|
-
* pause is enough. 429 counts as transient alongside 5xx: it is the route
|
|
178
|
-
* reporting its own capacity, and backing off is the whole point of it.
|
|
179
|
-
* Retry-After replaces that pause when it is at most five seconds; a longer
|
|
180
|
-
* server window is surfaced immediately rather than parking a tool call.
|
|
181
|
-
*
|
|
182
|
-
* A lost connection is usually a deployment rolling through the API, which
|
|
183
|
-
* refuses and resets connections for a few seconds. This schedule waits that
|
|
184
|
-
* out, and still finishes well inside the ten seconds a tool call waits on
|
|
185
|
-
* identity. A timeout is never retried: that attempt already spent its whole
|
|
186
|
-
* bound, and sending it again spends another.
|
|
187
|
-
*
|
|
188
|
-
* Each delay is one retry: transient statuses get two, lost connections get
|
|
189
|
-
* four.
|
|
125
|
+
* What failed one attempt, in the terms {@link ReadRetrySchedule} judges.
|
|
126
|
+
* Anything else, such as an answer that did not parse, is never retried.
|
|
190
127
|
*/
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
return Math.ceil(delayMs * (0.75 + Math.random() * 0.25));
|
|
197
|
-
}
|
|
198
|
-
function jitterAfterMinimum(delayMs) {
|
|
199
|
-
return Math.ceil(delayMs * (1 + Math.random() * 0.25));
|
|
200
|
-
}
|
|
201
|
-
class ReadRetrySchedule {
|
|
202
|
-
lostConnections = 0;
|
|
203
|
-
transientStatuses = 0;
|
|
204
|
-
next(error) {
|
|
205
|
-
if (error instanceof ServerHttpError) {
|
|
206
|
-
if (!isTransientHttpStatus(error.status)) {
|
|
207
|
-
return undefined;
|
|
208
|
-
}
|
|
209
|
-
const delayMs = TRANSIENT_STATUS_RETRY_DELAYS_MS[this.transientStatuses++];
|
|
210
|
-
if (delayMs === undefined) {
|
|
211
|
-
return "exhausted";
|
|
212
|
-
}
|
|
213
|
-
if (error.retryAfterMs === undefined) {
|
|
214
|
-
return { cause: "http", waitMs: jitter(delayMs) };
|
|
215
|
-
}
|
|
216
|
-
return error.retryAfterMs > MAX_RETRY_AFTER_MS
|
|
217
|
-
? undefined
|
|
218
|
-
: {
|
|
219
|
-
cause: "http",
|
|
220
|
-
waitMs: jitterAfterMinimum(Math.max(delayMs, error.retryAfterMs)),
|
|
221
|
-
};
|
|
222
|
-
}
|
|
223
|
-
if (error instanceof ServerTransportError && error.retryable) {
|
|
224
|
-
const delayMs = LOST_CONNECTION_RETRY_DELAYS_MS[this.lostConnections++];
|
|
225
|
-
return delayMs === undefined
|
|
226
|
-
? "exhausted"
|
|
227
|
-
: { cause: "transport", waitMs: jitter(delayMs) };
|
|
228
|
-
}
|
|
229
|
-
return undefined;
|
|
230
|
-
}
|
|
128
|
+
function readFailure(error) {
|
|
129
|
+
return error instanceof ServerHttpError ||
|
|
130
|
+
error instanceof ServerTransportError
|
|
131
|
+
? error
|
|
132
|
+
: undefined;
|
|
231
133
|
}
|
|
232
134
|
function parseRetryAfterMs(value) {
|
|
233
135
|
const retryAfter = value?.trim();
|
|
@@ -379,6 +281,14 @@ export class HttpSuperblocksServerClient {
|
|
|
379
281
|
...options.identityReads,
|
|
380
282
|
});
|
|
381
283
|
}
|
|
284
|
+
async reportMcpUsage(input) {
|
|
285
|
+
await this.request(PlatformMcpServerRequest.to("POST /api/v1/builder-usage"), {
|
|
286
|
+
apiKey: input.apiKey,
|
|
287
|
+
body: JSON.stringify(input.event),
|
|
288
|
+
retry: false,
|
|
289
|
+
timeoutMs: 1000,
|
|
290
|
+
});
|
|
291
|
+
}
|
|
382
292
|
baseUrl() {
|
|
383
293
|
return this.serverUrl.replace(/\/$/, "");
|
|
384
294
|
}
|
|
@@ -390,10 +300,10 @@ export class HttpSuperblocksServerClient {
|
|
|
390
300
|
* every field, which is indistinguishable from a legitimately empty response
|
|
391
301
|
* — so this is deliberately strict rather than falling back to the raw body.
|
|
392
302
|
*/
|
|
393
|
-
async requestData(
|
|
394
|
-
const body = await this.request(
|
|
303
|
+
async requestData(target, init) {
|
|
304
|
+
const body = await this.request(target, init);
|
|
395
305
|
if (body?.data === undefined) {
|
|
396
|
-
throw new Error(`Server ${path} returned no data field; expected a { responseMeta, data } envelope`);
|
|
306
|
+
throw new Error(`Server ${target.path} returned no data field; expected a { responseMeta, data } envelope`);
|
|
397
307
|
}
|
|
398
308
|
return body.data;
|
|
399
309
|
}
|
|
@@ -408,8 +318,9 @@ export class HttpSuperblocksServerClient {
|
|
|
408
318
|
* lost connection used to fail on first sight, which is how a build's poll
|
|
409
319
|
* loop lost its caller's identity while a deployment rolled through the API.
|
|
410
320
|
*/
|
|
411
|
-
async request(
|
|
412
|
-
const
|
|
321
|
+
async request(target, { query, ...init }) {
|
|
322
|
+
const path = query ? `${target.path}?${query}` : target.path;
|
|
323
|
+
const method = target.method;
|
|
413
324
|
const repeatSafe = init.retry ?? method === "GET";
|
|
414
325
|
const retries = new ReadRetrySchedule();
|
|
415
326
|
const timeoutMs = init.timeoutMs ?? this.timeoutMs;
|
|
@@ -431,6 +342,7 @@ export class HttpSuperblocksServerClient {
|
|
|
431
342
|
try {
|
|
432
343
|
const result = await this.send(path, {
|
|
433
344
|
...init,
|
|
345
|
+
method,
|
|
434
346
|
timeoutMs: remainingMs,
|
|
435
347
|
});
|
|
436
348
|
if (retryCause) {
|
|
@@ -455,7 +367,7 @@ export class HttpSuperblocksServerClient {
|
|
|
455
367
|
(method === "GET" &&
|
|
456
368
|
error instanceof ServerTransportError &&
|
|
457
369
|
error.requestNotSent)
|
|
458
|
-
? retries.next(error)
|
|
370
|
+
? retries.next(readFailure(error))
|
|
459
371
|
: undefined;
|
|
460
372
|
if (retry === undefined || retry === "exhausted") {
|
|
461
373
|
retryExhausted = retryCause !== undefined && retry === "exhausted";
|
|
@@ -558,9 +470,8 @@ export class HttpSuperblocksServerClient {
|
|
|
558
470
|
/** The unguarded read behind {@link validateApiKey}. */
|
|
559
471
|
async readIdentityFromServer(apiKey) {
|
|
560
472
|
try {
|
|
561
|
-
const data = await this.requestData("/api/v1/users/me", {
|
|
473
|
+
const data = await this.requestData(PlatformMcpServerRequest.to("GET /api/v1/users/me"), {
|
|
562
474
|
apiKey,
|
|
563
|
-
method: "GET",
|
|
564
475
|
operation: "identity",
|
|
565
476
|
timeoutMs: this.identityTimeoutMs,
|
|
566
477
|
});
|
|
@@ -586,9 +497,8 @@ export class HttpSuperblocksServerClient {
|
|
|
586
497
|
}
|
|
587
498
|
}
|
|
588
499
|
async getAgentInventory(input) {
|
|
589
|
-
const data = await this.requestData("/api/v1/users/me", {
|
|
500
|
+
const data = await this.requestData(PlatformMcpServerRequest.to("GET /api/v1/users/me"), {
|
|
590
501
|
apiKey: input.apiKey,
|
|
591
|
-
method: "GET",
|
|
592
502
|
operation: "identity",
|
|
593
503
|
// Same route, so the same bound. This one runs on the build path rather
|
|
594
504
|
// than per tool call, and left at the sandbox timeout a wedged
|
|
@@ -631,7 +541,7 @@ export class HttpSuperblocksServerClient {
|
|
|
631
541
|
};
|
|
632
542
|
}
|
|
633
543
|
async createApplication(input) {
|
|
634
|
-
return this.requestData("/api/v2/applications/", {
|
|
544
|
+
return this.requestData(PlatformMcpServerRequest.to("POST /api/v2/applications/"), {
|
|
635
545
|
apiKey: input.apiKey,
|
|
636
546
|
// Live edit only attaches to code-mode apps; without this the server
|
|
637
547
|
// builds a legacy DSL app and `connect` rejects it.
|
|
@@ -641,7 +551,6 @@ export class HttpSuperblocksServerClient {
|
|
|
641
551
|
organizationId: input.organizationId,
|
|
642
552
|
...(input.templateName ? { templateName: input.templateName } : {}),
|
|
643
553
|
}),
|
|
644
|
-
method: "POST",
|
|
645
554
|
...(input.signal ? { signal: input.signal } : {}),
|
|
646
555
|
...(input.timeoutMs === undefined
|
|
647
556
|
? {}
|
|
@@ -678,10 +587,7 @@ export class HttpSuperblocksServerClient {
|
|
|
678
587
|
}
|
|
679
588
|
async connectLiveEdit(input) {
|
|
680
589
|
const deadlineAtMs = Date.now() + this.timeoutMs;
|
|
681
|
-
const
|
|
682
|
-
? `/branches/${encodeURIComponent(input.branch)}`
|
|
683
|
-
: "";
|
|
684
|
-
const path = `/api/v3/applications/${input.applicationId}${branchSegment}/connect`;
|
|
590
|
+
const connect = liveEditConnectRequest(input.applicationId, input.branch);
|
|
685
591
|
let liveEditId = "session";
|
|
686
592
|
const deadlineError = () => new Error(`Live edit ${liveEditId} did not become active within ${this.timeoutMs}ms`);
|
|
687
593
|
const requestBeforeDeadline = async (query) => {
|
|
@@ -689,9 +595,9 @@ export class HttpSuperblocksServerClient {
|
|
|
689
595
|
throw deadlineError();
|
|
690
596
|
}
|
|
691
597
|
try {
|
|
692
|
-
return await this.requestData(
|
|
598
|
+
return await this.requestData(connect, {
|
|
693
599
|
apiKey: input.apiKey,
|
|
694
|
-
|
|
600
|
+
query,
|
|
695
601
|
operation: "live_edit",
|
|
696
602
|
retry: false,
|
|
697
603
|
timeoutMs: Math.max(1, deadlineAtMs - Date.now()),
|
|
@@ -704,7 +610,7 @@ export class HttpSuperblocksServerClient {
|
|
|
704
610
|
throw error;
|
|
705
611
|
}
|
|
706
612
|
};
|
|
707
|
-
let data = await requestBeforeDeadline("
|
|
613
|
+
let data = await requestBeforeDeadline("returnBeforeReady=true");
|
|
708
614
|
let polled = false;
|
|
709
615
|
for (;;) {
|
|
710
616
|
const session = data.sandboxStartData;
|
|
@@ -716,11 +622,13 @@ export class HttpSuperblocksServerClient {
|
|
|
716
622
|
const status = liveEditStatus(session.status);
|
|
717
623
|
if (session.pitcherURL &&
|
|
718
624
|
(session.status === undefined || status === "active")) {
|
|
625
|
+
internalIngress.route(session.pitcherURL);
|
|
719
626
|
return {
|
|
720
627
|
liveEditId: session.sandboxId,
|
|
721
628
|
liveEditUrl: session.pitcherURL,
|
|
722
629
|
pitcherToken: session.pitcherToken,
|
|
723
630
|
pitcherURL: session.pitcherURL,
|
|
631
|
+
...(data.targetBranch ? { targetBranch: data.targetBranch } : {}),
|
|
724
632
|
};
|
|
725
633
|
}
|
|
726
634
|
if (status !== "starting") {
|
|
@@ -733,18 +641,14 @@ export class HttpSuperblocksServerClient {
|
|
|
733
641
|
throw deadlineError();
|
|
734
642
|
}
|
|
735
643
|
polled = true;
|
|
736
|
-
data = await requestBeforeDeadline(
|
|
644
|
+
data = await requestBeforeDeadline(`liveEditId=${encodeURIComponent(session.sandboxId)}`);
|
|
737
645
|
}
|
|
738
646
|
}
|
|
739
647
|
async getLiveEditStatus(input) {
|
|
740
|
-
const branchSegment = input.branch
|
|
741
|
-
? `/branches/${encodeURIComponent(input.branch)}`
|
|
742
|
-
: "";
|
|
743
|
-
const path = `/api/v3/applications/${input.applicationId}${branchSegment}/connect?liveEditId=${encodeURIComponent(input.liveEditId)}`;
|
|
744
648
|
try {
|
|
745
|
-
const data = await this.requestData(
|
|
649
|
+
const data = await this.requestData(liveEditConnectRequest(input.applicationId, input.branch), {
|
|
746
650
|
apiKey: input.apiKey,
|
|
747
|
-
|
|
651
|
+
query: `liveEditId=${encodeURIComponent(input.liveEditId)}`,
|
|
748
652
|
retry: false,
|
|
749
653
|
signal: input.signal,
|
|
750
654
|
});
|
|
@@ -790,10 +694,9 @@ export class HttpSuperblocksServerClient {
|
|
|
790
694
|
}
|
|
791
695
|
body.commitId = input.commitId;
|
|
792
696
|
}
|
|
793
|
-
const data = await this.request("/api/v1/token/scoped", {
|
|
697
|
+
const data = await this.request(PlatformMcpServerRequest.to("POST /api/v1/token/scoped"), {
|
|
794
698
|
apiKey: input.apiKey,
|
|
795
699
|
body: JSON.stringify(body),
|
|
796
|
-
method: "POST",
|
|
797
700
|
});
|
|
798
701
|
if (!data?.access_token) {
|
|
799
702
|
throw new Error("Server /api/v1/token/scoped returned no access_token; the live-edit session has nothing to verify");
|
|
@@ -811,16 +714,16 @@ export class HttpSuperblocksServerClient {
|
|
|
811
714
|
if (input.applicationId) {
|
|
812
715
|
params.set("applicationId", input.applicationId);
|
|
813
716
|
}
|
|
814
|
-
const data = await this.requestData(
|
|
717
|
+
const data = await this.requestData(PlatformMcpServerRequest.to("GET /api/v1/integrations/superset"), {
|
|
815
718
|
apiKey: input.apiKey,
|
|
816
|
-
|
|
719
|
+
query: params.toString(),
|
|
817
720
|
operation: "superset_integrations",
|
|
818
721
|
});
|
|
819
722
|
return Array.isArray(data) ? data : [];
|
|
820
723
|
}
|
|
821
724
|
async getIntegration(input) {
|
|
822
725
|
try {
|
|
823
|
-
return await this.requestData(
|
|
726
|
+
return await this.requestData(PlatformMcpServerRequest.to("GET /api/v1/integrations/*", input.integrationId), { apiKey: input.apiKey, operation: "integration" });
|
|
824
727
|
}
|
|
825
728
|
catch (error) {
|
|
826
729
|
if (error instanceof ServerHttpError && error.status === 404) {
|
|
@@ -831,7 +734,7 @@ export class HttpSuperblocksServerClient {
|
|
|
831
734
|
}
|
|
832
735
|
async getApplicationEnvironment(input) {
|
|
833
736
|
try {
|
|
834
|
-
const data = await this.requestData(
|
|
737
|
+
const data = await this.requestData(PlatformMcpServerRequest.to("GET /api/v2/applications/*/environments", input.applicationId), { apiKey: input.apiKey });
|
|
835
738
|
const editor = data?.profiles?.editor;
|
|
836
739
|
const availableProfileIds = Array.isArray(editor?.availableProfileIds)
|
|
837
740
|
? editor.availableProfileIds.filter((id) => typeof id === "string")
|
|
@@ -862,9 +765,8 @@ export class HttpSuperblocksServerClient {
|
|
|
862
765
|
}
|
|
863
766
|
}
|
|
864
767
|
async getOrganizationProfiles(input) {
|
|
865
|
-
const data = await this.requestData(
|
|
768
|
+
const data = await this.requestData(PlatformMcpServerRequest.to("GET /api/v1/organizations/*/profiles", input.organizationId), {
|
|
866
769
|
apiKey: input.apiKey,
|
|
867
|
-
method: "GET",
|
|
868
770
|
operation: "organization_profiles",
|
|
869
771
|
});
|
|
870
772
|
if (!Array.isArray(data)) {
|
|
@@ -884,6 +786,29 @@ export class HttpSuperblocksServerClient {
|
|
|
884
786
|
key: row.key,
|
|
885
787
|
}));
|
|
886
788
|
}
|
|
789
|
+
async getBranchStatus(input) {
|
|
790
|
+
const data = await this.requestData(PlatformMcpServerRequest.to("GET /api/v2/applications/*/branch/status", input.applicationId), {
|
|
791
|
+
apiKey: input.apiKey,
|
|
792
|
+
...(input.signal ? { signal: input.signal } : {}),
|
|
793
|
+
...(input.timeoutMs !== undefined
|
|
794
|
+
? { timeoutMs: input.timeoutMs }
|
|
795
|
+
: {}),
|
|
796
|
+
});
|
|
797
|
+
return { branch: data.branch, mainHead: data.mainHead, mode: data.mode };
|
|
798
|
+
}
|
|
799
|
+
async landBranch(input) {
|
|
800
|
+
return this.requestData(PlatformMcpServerRequest.to("POST /api/v2/applications/*/branch/land", input.applicationId), {
|
|
801
|
+
apiKey: input.apiKey,
|
|
802
|
+
body: JSON.stringify({
|
|
803
|
+
publish: true,
|
|
804
|
+
retryFailedMigrations: input.retryFailedMigrations,
|
|
805
|
+
}),
|
|
806
|
+
...(input.signal ? { signal: input.signal } : {}),
|
|
807
|
+
...(input.timeoutMs !== undefined
|
|
808
|
+
? { timeoutMs: input.timeoutMs }
|
|
809
|
+
: {}),
|
|
810
|
+
});
|
|
811
|
+
}
|
|
887
812
|
/**
|
|
888
813
|
* Snapshots the application's current live-edit state as a commit.
|
|
889
814
|
*
|
|
@@ -892,10 +817,9 @@ export class HttpSuperblocksServerClient {
|
|
|
892
817
|
* editor's publish flow does.
|
|
893
818
|
*/
|
|
894
819
|
async createCommit(input) {
|
|
895
|
-
const
|
|
896
|
-
?
|
|
897
|
-
: ""
|
|
898
|
-
const data = await this.requestData(`/api/v2/applications/${input.applicationId}${branchSegment}/commit`, {
|
|
820
|
+
const data = await this.requestData(input.branch
|
|
821
|
+
? PlatformMcpServerRequest.to("POST /api/v2/applications/*/branches/*/commit", input.applicationId, input.branch)
|
|
822
|
+
: PlatformMcpServerRequest.to("POST /api/v2/applications/*/commit", input.applicationId), {
|
|
899
823
|
apiKey: input.apiKey,
|
|
900
824
|
body: JSON.stringify({
|
|
901
825
|
commitMessage: input.message,
|
|
@@ -903,9 +827,10 @@ export class HttpSuperblocksServerClient {
|
|
|
903
827
|
// a commit racing an editor that has moved on since.
|
|
904
828
|
lastSuccessfulWrite: Date.now(),
|
|
905
829
|
}),
|
|
906
|
-
method: "POST",
|
|
907
830
|
...(input.signal ? { signal: input.signal } : {}),
|
|
908
|
-
...(input.timeoutMs !== undefined
|
|
831
|
+
...(input.timeoutMs !== undefined
|
|
832
|
+
? { timeoutMs: input.timeoutMs }
|
|
833
|
+
: {}),
|
|
909
834
|
});
|
|
910
835
|
return {
|
|
911
836
|
commitId: data.commitId,
|
|
@@ -923,20 +848,18 @@ export class HttpSuperblocksServerClient {
|
|
|
923
848
|
* same content end up watching one build instead of racing two.
|
|
924
849
|
*/
|
|
925
850
|
async createBuild(input) {
|
|
926
|
-
await this.request(
|
|
851
|
+
await this.request(PlatformMcpServerRequest.to("POST /api/v3/applications/*/*/builds", input.applicationId, input.directoryHash), {
|
|
927
852
|
apiKey: input.apiKey,
|
|
928
853
|
body: JSON.stringify({ commitId: input.commitId }),
|
|
929
|
-
method: "POST",
|
|
930
854
|
});
|
|
931
855
|
}
|
|
932
856
|
async getBuildProgress(input) {
|
|
933
|
-
const
|
|
857
|
+
const target = PlatformMcpServerRequest.to("POST /api/v3/applications/*/build-bulk-status", input.applicationId);
|
|
934
858
|
// POST because the hashes go in the body, but it is a read: the server
|
|
935
859
|
// asks SABS for status and changes nothing.
|
|
936
|
-
const data = await this.requestData(
|
|
860
|
+
const data = await this.requestData(target, {
|
|
937
861
|
apiKey: input.apiKey,
|
|
938
862
|
body: JSON.stringify({ directoryHashes: [input.directoryHash] }),
|
|
939
|
-
method: "POST",
|
|
940
863
|
operation: "build_progress",
|
|
941
864
|
retry: true,
|
|
942
865
|
...(input.signal ? { signal: input.signal } : {}),
|
|
@@ -947,14 +870,13 @@ export class HttpSuperblocksServerClient {
|
|
|
947
870
|
return buildProgress(data.directoryHashToStatus?.[input.directoryHash]?.status);
|
|
948
871
|
}
|
|
949
872
|
async deployApplication(input) {
|
|
950
|
-
const
|
|
951
|
-
const body = await this.request(
|
|
873
|
+
const target = PlatformMcpServerRequest.to("POST /api/v2/applications/*/deployments", input.applicationId);
|
|
874
|
+
const body = await this.request(target, {
|
|
952
875
|
apiKey: input.apiKey,
|
|
953
876
|
// PostApplicationDeployRequestBody rejects unknown properties, so this
|
|
954
877
|
// body carries the commit and nothing else — the branch is already
|
|
955
878
|
// fixed by the commit being deployed.
|
|
956
879
|
body: JSON.stringify({ commitId: input.commitId }),
|
|
957
|
-
method: "POST",
|
|
958
880
|
...(input.signal ? { signal: input.signal } : {}),
|
|
959
881
|
...(input.timeoutMs !== undefined ? { timeoutMs: input.timeoutMs } : {}),
|
|
960
882
|
});
|
|
@@ -966,16 +888,15 @@ export class HttpSuperblocksServerClient {
|
|
|
966
888
|
}
|
|
967
889
|
// Neither shape. Guessing "it worked" here would report a publish that
|
|
968
890
|
// never happened as a success.
|
|
969
|
-
throw new Error(`Server ${path} returned neither a deployment nor a deploy status`);
|
|
891
|
+
throw new Error(`Server ${target.path} returned neither a deployment nor a deploy status`);
|
|
970
892
|
}
|
|
971
893
|
/**
|
|
972
894
|
* Polls the deploy queue for a commit the UI watches after a queued publish.
|
|
973
895
|
*/
|
|
974
896
|
async getDeployStatus(input) {
|
|
975
|
-
const
|
|
976
|
-
const body = await this.request(
|
|
897
|
+
const target = PlatformMcpServerRequest.to("GET /api/v2/applications/*/deploy-status/*", input.applicationId, input.commitId);
|
|
898
|
+
const body = await this.request(target, {
|
|
977
899
|
apiKey: input.apiKey,
|
|
978
|
-
method: "GET",
|
|
979
900
|
retry: false,
|
|
980
901
|
...(input.signal ? { signal: input.signal } : {}),
|
|
981
902
|
...(input.timeoutMs !== undefined ? { timeoutMs: input.timeoutMs } : {}),
|
|
@@ -993,7 +914,7 @@ export class HttpSuperblocksServerClient {
|
|
|
993
914
|
status,
|
|
994
915
|
};
|
|
995
916
|
}
|
|
996
|
-
throw new Error(`Server ${path} returned an unknown deploy status`);
|
|
917
|
+
throw new Error(`Server ${target.path} returned an unknown deploy status`);
|
|
997
918
|
}
|
|
998
919
|
/**
|
|
999
920
|
* Asks Clark for an app name, the same way the editor header does after a
|
|
@@ -1001,13 +922,12 @@ export class HttpSuperblocksServerClient {
|
|
|
1001
922
|
*/
|
|
1002
923
|
async generateAppName(input) {
|
|
1003
924
|
// Another bare body rather than the `{ responseMeta, data }` envelope.
|
|
1004
|
-
const data = await this.request("/api/v1/ai/generate-app-name", {
|
|
925
|
+
const data = await this.request(PlatformMcpServerRequest.to("POST /api/v1/ai/generate-app-name"), {
|
|
1005
926
|
apiKey: input.apiKey,
|
|
1006
927
|
body: JSON.stringify({
|
|
1007
928
|
applicationId: input.applicationId,
|
|
1008
929
|
prompt: input.prompt,
|
|
1009
930
|
}),
|
|
1010
|
-
method: "POST",
|
|
1011
931
|
});
|
|
1012
932
|
if (!data?.name?.trim()) {
|
|
1013
933
|
throw new Error("Server /api/v1/ai/generate-app-name returned no name");
|
|
@@ -1023,21 +943,19 @@ export class HttpSuperblocksServerClient {
|
|
|
1023
943
|
* why nothing on a hot path should call it.
|
|
1024
944
|
*/
|
|
1025
945
|
async getApplicationName(input) {
|
|
1026
|
-
const body = await this.request("/api/v2/applications", {
|
|
946
|
+
const body = await this.request(PlatformMcpServerRequest.to("GET /api/v2/applications"), {
|
|
1027
947
|
apiKey: input.apiKey,
|
|
1028
|
-
method: "GET",
|
|
1029
948
|
operation: "applications",
|
|
1030
949
|
});
|
|
1031
950
|
const found = body?.data?.applications?.find((application) => application?.id === input.applicationId);
|
|
1032
951
|
return found?.name?.trim() || undefined;
|
|
1033
952
|
}
|
|
1034
953
|
async renameApplication(input) {
|
|
1035
|
-
await this.request(
|
|
954
|
+
await this.request(PlatformMcpServerRequest.to("PUT /api/v2/applications/*/metadata", input.applicationId), {
|
|
1036
955
|
apiKey: input.apiKey,
|
|
1037
956
|
// PutApplicationMetadataUpdateRequestBody accepts exactly one of name,
|
|
1038
957
|
// folderId, or isPublic — sending more than one fails validation.
|
|
1039
958
|
body: JSON.stringify({ name: input.name }),
|
|
1040
|
-
method: "PUT",
|
|
1041
959
|
});
|
|
1042
960
|
}
|
|
1043
961
|
}
|