@byteplus-iga-pages/agent 0.0.0-stage → 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/LICENSE +20 -0
- package/README.md +84 -2
- package/dist/cjs/261.js +77 -0
- package/dist/cjs/341.js +43 -0
- package/dist/cjs/401.js +3632 -0
- package/dist/cjs/419.js +854 -0
- package/dist/cjs/504.js +760 -0
- package/dist/cjs/521.js +242 -0
- package/dist/cjs/594.js +79 -0
- package/dist/cjs/647.js +1367 -0
- package/dist/cjs/808.js +322 -0
- package/dist/cjs/82.js +10089 -0
- package/dist/cjs/893.js +17720 -0
- package/dist/cjs/893.js.LICENSE.txt +13 -0
- package/dist/cjs/951.js +59 -0
- package/dist/cjs/package.json +3 -0
- package/dist/cjs/runtime.js +79 -0
- package/dist/cjs/sandbox/host.js +125 -0
- package/dist/cjs/sandbox/index.js +286 -0
- package/dist/cjs/store/claude.js +209 -0
- package/dist/cjs/store/host.js +92 -0
- package/dist/cjs/store/index.js +43 -0
- package/dist/cjs/store/langgraph.js +581 -0
- package/dist/cjs/store/openai.js +118 -0
- package/dist/cjs/tools/claude.js +59 -0
- package/dist/cjs/tools/index.js +37 -0
- package/dist/cjs/tools/langchain.js +52 -0
- package/dist/cjs/tools/openai-agents.js +43 -0
- package/dist/cjs/tools/openai.js +43 -0
- package/dist/esm/128.js +10381 -0
- package/dist/esm/261.js +67 -0
- package/dist/esm/341.js +30 -0
- package/dist/esm/392.js +4453 -0
- package/dist/esm/417.js +704 -0
- package/dist/esm/521.js +230 -0
- package/dist/esm/594.js +67 -0
- package/dist/esm/613.js +19042 -0
- package/dist/esm/613.js.LICENSE.txt +13 -0
- package/dist/esm/951.js +44 -0
- package/dist/esm/package.json +3 -0
- package/dist/esm/runtime.js +39 -0
- package/dist/esm/sandbox/host.js +1 -0
- package/dist/esm/sandbox/index.js +183 -0
- package/dist/esm/store/claude.js +172 -0
- package/dist/esm/store/host.js +46 -0
- package/dist/esm/store/index.js +2 -0
- package/dist/esm/store/langgraph.js +542 -0
- package/dist/esm/store/openai.js +81 -0
- package/dist/esm/tools/claude.js +22 -0
- package/dist/esm/tools/index.js +1 -0
- package/dist/esm/tools/langchain.js +16 -0
- package/dist/esm/tools/openai-agents.js +6 -0
- package/dist/esm/tools/openai.js +6 -0
- package/dist/types/_internal/data-plane/control-plane-request.d.ts +12 -0
- package/dist/types/_internal/data-plane/control-plane.d.ts +3 -0
- package/dist/types/_internal/data-plane/credential-provider.d.ts +25 -0
- package/dist/types/_internal/data-plane/errors.d.ts +19 -0
- package/dist/types/_internal/data-plane/index.d.ts +11 -0
- package/dist/types/_internal/data-plane/supabase-client.d.ts +12 -0
- package/dist/types/_internal/data-plane/token-client.d.ts +23 -0
- package/dist/types/sandbox/api-client.d.ts +37 -0
- package/dist/types/sandbox/api-types.d.ts +81 -0
- package/dist/types/sandbox/binding-repository.d.ts +62 -0
- package/dist/types/sandbox/error.d.ts +22 -0
- package/dist/types/sandbox/expiry.d.ts +11 -0
- package/dist/types/sandbox/host.d.ts +6 -0
- package/dist/types/sandbox/iga-sandbox.d.ts +208 -0
- package/dist/types/sandbox/index.d.ts +8 -0
- package/dist/types/sandbox/public-surface.d.ts +19 -0
- package/dist/types/sandbox/runtime-sandbox.d.ts +32 -0
- package/dist/types/sandbox/types.d.ts +238 -0
- package/dist/types/store/append.d.ts +41 -0
- package/dist/types/store/claude-repository.d.ts +36 -0
- package/dist/types/store/claude.d.ts +3 -0
- package/dist/types/store/control-plane-request.d.ts +2 -0
- package/dist/types/store/credential-error.d.ts +2 -0
- package/dist/types/store/credential-provider.d.ts +29 -0
- package/dist/types/store/errors.d.ts +29 -0
- package/dist/types/store/factory.d.ts +31 -0
- package/dist/types/store/host.d.ts +5 -0
- package/dist/types/store/index.d.ts +6 -0
- package/dist/types/store/json.d.ts +7 -0
- package/dist/types/store/langgraph-repository.d.ts +98 -0
- package/dist/types/store/langgraph.d.ts +43 -0
- package/dist/types/store/openai.d.ts +12 -0
- package/dist/types/store/pagination.d.ts +27 -0
- package/dist/types/store/runtime-data-plane.d.ts +8 -0
- package/dist/types/store/runtime-provider.d.ts +1 -0
- package/dist/types/store/runtime-store.d.ts +20 -0
- package/dist/types/store/store.d.ts +240 -0
- package/dist/types/store/supabase-transport.d.ts +43 -0
- package/dist/types/store/token-client.d.ts +7 -0
- package/dist/types/tools/adapters.d.ts +5 -0
- package/dist/types/tools/claude.d.ts +4 -0
- package/dist/types/tools/index.d.ts +2 -0
- package/dist/types/tools/langchain.d.ts +16 -0
- package/dist/types/tools/model-output.d.ts +8 -0
- package/dist/types/tools/openai-agents.d.ts +4 -0
- package/dist/types/tools/openai.d.ts +5 -0
- package/dist/types/tools/registry.d.ts +16 -0
- package/dist/types/tools/result.d.ts +17 -0
- package/dist/types/tools/sandbox-result-mappers.d.ts +10 -0
- package/dist/types/tools/sandbox-tools.d.ts +17 -0
- package/dist/types/tools/types.d.ts +307 -0
- package/package.json +136 -4
package/dist/cjs/647.js
ADDED
|
@@ -0,0 +1,1367 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
exports.ids = [
|
|
3
|
+
"647"
|
|
4
|
+
];
|
|
5
|
+
exports.modules = {
|
|
6
|
+
"../sandbox/src/api-client.ts" (__unused_rspack_module, __webpack_exports__, __webpack_require__) {
|
|
7
|
+
__webpack_require__.d(__webpack_exports__, {
|
|
8
|
+
K: ()=>SandboxApi,
|
|
9
|
+
SW: ()=>createSandboxApi,
|
|
10
|
+
ip: ()=>isConfirmedMissingInstanceResponse
|
|
11
|
+
});
|
|
12
|
+
var node_https__rspack_import_0 = __webpack_require__("node:https");
|
|
13
|
+
var node_https__rspack_import_0_default = /*#__PURE__*/ __webpack_require__.n(node_https__rspack_import_0);
|
|
14
|
+
var _iga_pages_data_plane__rspack_import_1 = __webpack_require__("../data-plane/dist/esm/index.js");
|
|
15
|
+
var axios__rspack_import_4 = __webpack_require__("../../node_modules/.pnpm/axios@1.20.0/node_modules/axios/lib/axios.js");
|
|
16
|
+
var _error_js__rspack_import_3 = __webpack_require__("../sandbox/src/error.ts");
|
|
17
|
+
var _agent_infra_sandbox__rspack_import_2 = __webpack_require__("../../node_modules/.pnpm/@agent-infra+sandbox@1.0.17/node_modules/@agent-infra/sandbox/dist/esm/index.mjs");
|
|
18
|
+
function createSandboxApi(opts) {
|
|
19
|
+
return new SandboxApi(opts.apiBaseUrl, opts.apiToken);
|
|
20
|
+
}
|
|
21
|
+
class SandboxApi {
|
|
22
|
+
resolveBaseUrl() {
|
|
23
|
+
if (this.baseUrl) return this.baseUrl.replace(/\/+$/, "");
|
|
24
|
+
throw new _error_js__rspack_import_3.ES("Sandbox API base URL is not configured. Pass apiBaseUrl in createSandbox options.");
|
|
25
|
+
}
|
|
26
|
+
async getToken(opts = {}) {
|
|
27
|
+
const url = `${this.resolveBaseUrl()}/pages/v1/api/sandbox-token`;
|
|
28
|
+
const raw = await this.postJson(url, opts, {});
|
|
29
|
+
if (!raw.ApiKey) throw new _error_js__rspack_import_3.ES("Sandbox credentials could not be initialized.");
|
|
30
|
+
return {
|
|
31
|
+
apiKey: raw.ApiKey,
|
|
32
|
+
sandboxAppId: raw.SandboxAppID,
|
|
33
|
+
url: raw.Url,
|
|
34
|
+
tokenType: raw.TokenType,
|
|
35
|
+
tokenHeader: raw.TokenHeader
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
async create(opts) {
|
|
39
|
+
const url = `${this.resolveBaseUrl()}/pages/v1/api/sandbox/create`;
|
|
40
|
+
const raw = await this.postJson(url, opts, {
|
|
41
|
+
ProjectID: opts.projectId
|
|
42
|
+
});
|
|
43
|
+
if (!raw.SandboxId) throw new _error_js__rspack_import_3.ES("The sandbox could not be created because the service returned an invalid response.");
|
|
44
|
+
return {
|
|
45
|
+
sandboxId: raw.SandboxId
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
async destroy(opts) {
|
|
49
|
+
const url = `${this.resolveBaseUrl()}/pages/v1/api/sandbox/destroy`;
|
|
50
|
+
await this.postJson(url, opts, {
|
|
51
|
+
ProjectID: opts.projectId,
|
|
52
|
+
SandboxID: opts.sandboxId
|
|
53
|
+
});
|
|
54
|
+
return {
|
|
55
|
+
ok: true
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
async getInstance(opts) {
|
|
59
|
+
const url = `${this.resolveBaseUrl()}/pages/v1/api/sandbox/instance`;
|
|
60
|
+
let raw;
|
|
61
|
+
try {
|
|
62
|
+
raw = await this.postJson(url, opts, {
|
|
63
|
+
ProjectID: opts.projectId,
|
|
64
|
+
SandboxID: opts.sandboxId
|
|
65
|
+
});
|
|
66
|
+
} catch (error) {
|
|
67
|
+
if (error instanceof _error_js__rspack_import_3.ES && 200 === error.status && await this.confirmMissingViaDataPlane(opts)) throw new _error_js__rspack_import_3.YA("The sandbox was not found.", {
|
|
68
|
+
status: 404
|
|
69
|
+
});
|
|
70
|
+
if (opts.signal?.aborted) throw new _error_js__rspack_import_3.sX("The sandbox request was cancelled.");
|
|
71
|
+
throw error;
|
|
72
|
+
}
|
|
73
|
+
if (!raw || "object" != typeof raw || "string" != typeof raw.SandboxID) throw new _error_js__rspack_import_3.ES("Sandbox instance query returned an invalid response.");
|
|
74
|
+
return {
|
|
75
|
+
sandboxId: raw.SandboxID ?? "",
|
|
76
|
+
expireAt: raw.ExpireAt,
|
|
77
|
+
createdAt: raw.CreatedAt,
|
|
78
|
+
status: normalizeInstanceStatus(raw.Status)
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
async confirmInstanceExists(opts) {
|
|
82
|
+
const info = await this.getInstance(opts);
|
|
83
|
+
if (!info.sandboxId) throw sandboxNotFoundError();
|
|
84
|
+
if (info.sandboxId !== opts.sandboxId) throw new _error_js__rspack_import_3.ES("Sandbox instance query returned a different instance.");
|
|
85
|
+
if ("Failed" === info.status || "Terminating" === info.status) throw sandboxNotFoundError();
|
|
86
|
+
}
|
|
87
|
+
async confirmMissingViaDataPlane(opts) {
|
|
88
|
+
try {
|
|
89
|
+
const token = await this.getToken({
|
|
90
|
+
signal: opts.signal
|
|
91
|
+
});
|
|
92
|
+
if (!token.url) return false;
|
|
93
|
+
const client = new _agent_infra_sandbox__rspack_import_2.VF({
|
|
94
|
+
environment: token.url,
|
|
95
|
+
timeoutInSeconds: 10,
|
|
96
|
+
headers: {
|
|
97
|
+
[token.tokenHeader ?? "Authorization"]: `${token.tokenType ?? "Bearer"} ${token.apiKey}`,
|
|
98
|
+
"x-faas-instance-name": opts.sandboxId
|
|
99
|
+
}
|
|
100
|
+
});
|
|
101
|
+
const result = await client.file.listPath({
|
|
102
|
+
path: "/"
|
|
103
|
+
}, {
|
|
104
|
+
abortSignal: opts.signal
|
|
105
|
+
});
|
|
106
|
+
return isConfirmedMissingInstanceResponse(result);
|
|
107
|
+
} catch {
|
|
108
|
+
return false;
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
async updateInstanceTimeout(opts) {
|
|
112
|
+
const url = `${this.resolveBaseUrl()}/pages/v1/api/sandbox/instance/update`;
|
|
113
|
+
let raw;
|
|
114
|
+
try {
|
|
115
|
+
raw = await this.postJson(url, opts, {
|
|
116
|
+
ProjectID: opts.projectId,
|
|
117
|
+
SandboxID: opts.sandboxId,
|
|
118
|
+
Time: opts.timeoutInMinutes
|
|
119
|
+
});
|
|
120
|
+
} catch (error) {
|
|
121
|
+
if (error instanceof _error_js__rspack_import_3.ES && 200 === error.status) try {
|
|
122
|
+
await this.confirmInstanceExists(opts);
|
|
123
|
+
} catch (confirmation) {
|
|
124
|
+
if (confirmation instanceof _error_js__rspack_import_3.YA) throw confirmation;
|
|
125
|
+
}
|
|
126
|
+
if (opts.signal?.aborted) throw new _error_js__rspack_import_3.sX("The sandbox request was cancelled.");
|
|
127
|
+
throw error;
|
|
128
|
+
}
|
|
129
|
+
return {
|
|
130
|
+
sandboxId: raw.SandboxID ?? "",
|
|
131
|
+
expireAt: raw.ExpireAt,
|
|
132
|
+
createdAt: raw.CreatedAt,
|
|
133
|
+
status: normalizeInstanceStatus(raw.Status)
|
|
134
|
+
};
|
|
135
|
+
}
|
|
136
|
+
async postJson(url, opts, body) {
|
|
137
|
+
if (!this.token) throw new _error_js__rspack_import_3.ES("Sandbox API token is not configured.");
|
|
138
|
+
const timestamp = String(this.now());
|
|
139
|
+
const endpoint = new URL(url);
|
|
140
|
+
endpoint.searchParams.set("timestamp", timestamp);
|
|
141
|
+
endpoint.searchParams.set("token", this.token);
|
|
142
|
+
const requestUrl = endpoint.toString();
|
|
143
|
+
let resp;
|
|
144
|
+
try {
|
|
145
|
+
resp = await this.http.post(requestUrl, body, {
|
|
146
|
+
signal: opts.signal,
|
|
147
|
+
headers: (0, _iga_pages_data_plane__rspack_import_1.uQ)()
|
|
148
|
+
});
|
|
149
|
+
} catch (err) {
|
|
150
|
+
if (axios__rspack_import_4.A.isCancel(err) || err?.name === "CanceledError") throw new _error_js__rspack_import_3.sX("The sandbox request was cancelled.");
|
|
151
|
+
const response = err && "object" == typeof err ? err.response : void 0;
|
|
152
|
+
throw new _error_js__rspack_import_3.ES("The sandbox service is temporarily unavailable.", {
|
|
153
|
+
status: response?.status
|
|
154
|
+
});
|
|
155
|
+
}
|
|
156
|
+
if (resp.status < 200 || resp.status >= 300) throw controlPlaneHttpError({
|
|
157
|
+
status: resp.status,
|
|
158
|
+
responseBody: resp.data,
|
|
159
|
+
token: this.token,
|
|
160
|
+
instanceEndpoint: isInstanceQueryEndpoint(url)
|
|
161
|
+
});
|
|
162
|
+
return unwrapEnvelope(resp.data, {
|
|
163
|
+
status: resp.status,
|
|
164
|
+
token: this.token
|
|
165
|
+
});
|
|
166
|
+
}
|
|
167
|
+
constructor(baseUrl, token, now = Date.now){
|
|
168
|
+
this.baseUrl = baseUrl;
|
|
169
|
+
this.token = token;
|
|
170
|
+
this.now = now;
|
|
171
|
+
this.http = axios__rspack_import_4.A.create({
|
|
172
|
+
headers: {
|
|
173
|
+
"Content-Type": "application/json"
|
|
174
|
+
},
|
|
175
|
+
timeout: 30000,
|
|
176
|
+
validateStatus: ()=>true,
|
|
177
|
+
httpsAgent: new (node_https__rspack_import_0_default()).Agent({
|
|
178
|
+
keepAlive: true,
|
|
179
|
+
timeout: 30000
|
|
180
|
+
})
|
|
181
|
+
});
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
function isInstanceQueryEndpoint(url) {
|
|
185
|
+
return /\/pages\/v1\/api\/sandbox\/(instance|destroy)/.test(url);
|
|
186
|
+
}
|
|
187
|
+
function normalizeInstanceStatus(value) {
|
|
188
|
+
if ("Starting" === value || "Ready" === value || "Failed" === value || "Terminating" === value) return value;
|
|
189
|
+
if (void 0 !== value) throw new _error_js__rspack_import_3.ES("Sandbox returned an unknown instance status.");
|
|
190
|
+
}
|
|
191
|
+
function unwrapEnvelope(data, context) {
|
|
192
|
+
if (data && "object" == typeof data && "code" in data) {
|
|
193
|
+
const envelope = data;
|
|
194
|
+
if ("number" == typeof envelope.code || "string" == typeof envelope.code) {
|
|
195
|
+
if (0 !== envelope.code && "0" !== envelope.code) throw new _error_js__rspack_import_3.ES(controlPlaneMessage(data, context.token), {
|
|
196
|
+
status: context.status
|
|
197
|
+
});
|
|
198
|
+
if (void 0 !== envelope.data) return envelope.data;
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
return data;
|
|
202
|
+
}
|
|
203
|
+
function controlPlaneHttpError(input) {
|
|
204
|
+
const options = {
|
|
205
|
+
status: input.status
|
|
206
|
+
};
|
|
207
|
+
const message = controlPlaneMessage(input.responseBody, input.token);
|
|
208
|
+
if ((404 === input.status || 410 === input.status) && input.instanceEndpoint) return new _error_js__rspack_import_3.YA(message, options);
|
|
209
|
+
return new _error_js__rspack_import_3.ES(message, options);
|
|
210
|
+
}
|
|
211
|
+
function controlPlaneMessage(body, token) {
|
|
212
|
+
const record = body && "object" == typeof body ? body : void 0;
|
|
213
|
+
const value = "string" == typeof record?.message && record.message.trim() ? record.message : "string" == typeof record?.error && record.error.trim() ? record.error : "The sandbox request could not be completed.";
|
|
214
|
+
let message = token ? value.split(token).join("[redacted]") : value;
|
|
215
|
+
message = message.replace(/\bBearer\s+[A-Za-z0-9._~+\/-]+=*/gi, "Bearer [redacted]").replace(/\beyJ[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+\b/g, "[redacted]").replace(/([?&](?:access[_-]?token|api[_-]?key|key|token|signature|credential|auth|password|secret)\s*=)[^&#\s]*/gi, "$1[redacted]").replace(/([a-z][a-z0-9+.-]*:\/\/)[^@\s/]+@/gi, "$1[redacted]@").replace(/\b(token|authorization|password|secret|api[_-]?key|credential|signature)\b\s*[:=]\s*(?:"[^"]*"|'[^']*'|[^\s,;]+)/gi, "$1=[redacted]");
|
|
216
|
+
return message;
|
|
217
|
+
}
|
|
218
|
+
function sandboxNotFoundError() {
|
|
219
|
+
return new _error_js__rspack_import_3.YA("The sandbox was not found.");
|
|
220
|
+
}
|
|
221
|
+
function isConfirmedMissingInstanceResponse(value) {
|
|
222
|
+
if (!value || "object" != typeof value) return false;
|
|
223
|
+
const result = value;
|
|
224
|
+
const content = result.error?.content;
|
|
225
|
+
return false === result.ok && content?.reason === "status-code" && 404 === content.statusCode && content.body?.error_code === "instance_not_found";
|
|
226
|
+
}
|
|
227
|
+
},
|
|
228
|
+
"../sandbox/src/binding-repository.ts" (__unused_rspack_module, __webpack_exports__, __webpack_require__) {
|
|
229
|
+
__webpack_require__.d(__webpack_exports__, {
|
|
230
|
+
P: ()=>createRuntimeSandboxBindingRepository,
|
|
231
|
+
t: ()=>SupabaseSandboxBindingRepository
|
|
232
|
+
});
|
|
233
|
+
var node_crypto__rspack_import_0 = __webpack_require__("node:crypto");
|
|
234
|
+
var _iga_pages_data_plane__rspack_import_1 = __webpack_require__("../data-plane/dist/esm/index.js");
|
|
235
|
+
var _error_js__rspack_import_2 = __webpack_require__("../sandbox/src/error.ts");
|
|
236
|
+
function unavailable(_operation, _requestId, status) {
|
|
237
|
+
return new _error_js__rspack_import_2.ES("Sandbox session persistence is temporarily unavailable.", {
|
|
238
|
+
status
|
|
239
|
+
});
|
|
240
|
+
}
|
|
241
|
+
function asRecord(value, operation) {
|
|
242
|
+
const normalized = Array.isArray(value) && 1 === value.length ? value[0] : value;
|
|
243
|
+
if (!normalized || "object" != typeof normalized || Array.isArray(normalized)) throw new _error_js__rspack_import_2.ES("Sandbox persistence returned an invalid response.");
|
|
244
|
+
return normalized;
|
|
245
|
+
}
|
|
246
|
+
function requiredString(record, key, operation) {
|
|
247
|
+
const value = record[key];
|
|
248
|
+
if ("string" != typeof value || !value) throw new _error_js__rspack_import_2.ES("Sandbox persistence returned an invalid response.");
|
|
249
|
+
return value;
|
|
250
|
+
}
|
|
251
|
+
function requiredGeneration(record, operation) {
|
|
252
|
+
const value = Number(record.generation);
|
|
253
|
+
if (!Number.isSafeInteger(value) || value < 1) throw new _error_js__rspack_import_2.ES("Sandbox persistence returned an invalid response.");
|
|
254
|
+
return value;
|
|
255
|
+
}
|
|
256
|
+
class SupabaseSandboxBindingRepository {
|
|
257
|
+
async acquire(conversationId, leaseToken, signal) {
|
|
258
|
+
const operation = "sandbox.binding.acquire";
|
|
259
|
+
const record = asRecord(await this.rpc("sandbox_binding_acquire", {
|
|
260
|
+
p_conversation_id: conversationId,
|
|
261
|
+
p_lease_token: leaseToken,
|
|
262
|
+
p_lease_seconds: this.leaseSeconds
|
|
263
|
+
}, operation, signal), operation);
|
|
264
|
+
const action = requiredString(record, "action", operation);
|
|
265
|
+
const generation = requiredGeneration(record, operation);
|
|
266
|
+
if ("attach" === action) return {
|
|
267
|
+
action,
|
|
268
|
+
generation,
|
|
269
|
+
sandboxId: requiredString(record, "sandbox_id", operation)
|
|
270
|
+
};
|
|
271
|
+
if ("create" === action || "wait" === action) return {
|
|
272
|
+
action,
|
|
273
|
+
generation,
|
|
274
|
+
leaseExpiresAt: requiredString(record, "lease_expires_at", operation)
|
|
275
|
+
};
|
|
276
|
+
throw new _error_js__rspack_import_2.ES("Sandbox persistence returned an invalid response.");
|
|
277
|
+
}
|
|
278
|
+
async publish(conversationId, generation, leaseToken, sandboxId, signal) {
|
|
279
|
+
return this.booleanRpc("sandbox_binding_publish", {
|
|
280
|
+
p_conversation_id: conversationId,
|
|
281
|
+
p_generation: generation,
|
|
282
|
+
p_lease_token: leaseToken,
|
|
283
|
+
p_sandbox_id: sandboxId
|
|
284
|
+
}, "sandbox.binding.publish", signal);
|
|
285
|
+
}
|
|
286
|
+
async release(conversationId, generation, leaseToken, signal) {
|
|
287
|
+
await this.booleanRpc("sandbox_binding_release", {
|
|
288
|
+
p_conversation_id: conversationId,
|
|
289
|
+
p_generation: generation,
|
|
290
|
+
p_lease_token: leaseToken
|
|
291
|
+
}, "sandbox.binding.release", signal);
|
|
292
|
+
}
|
|
293
|
+
invalidate(conversationId, generation, sandboxId, signal) {
|
|
294
|
+
return this.booleanRpc("sandbox_binding_invalidate", {
|
|
295
|
+
p_conversation_id: conversationId,
|
|
296
|
+
p_generation: generation,
|
|
297
|
+
p_sandbox_id: sandboxId
|
|
298
|
+
}, "sandbox.binding.invalidate", signal);
|
|
299
|
+
}
|
|
300
|
+
async beginDestroy(conversationId, leaseToken, signal) {
|
|
301
|
+
const operation = "sandbox.binding.beginDestroy";
|
|
302
|
+
const record = asRecord(await this.rpc("sandbox_binding_begin_destroy", {
|
|
303
|
+
p_conversation_id: conversationId,
|
|
304
|
+
p_lease_token: leaseToken,
|
|
305
|
+
p_lease_seconds: this.leaseSeconds
|
|
306
|
+
}, operation, signal), operation);
|
|
307
|
+
const action = requiredString(record, "action", operation);
|
|
308
|
+
if ("none" === action) return {
|
|
309
|
+
action
|
|
310
|
+
};
|
|
311
|
+
if ("wait" === action) return {
|
|
312
|
+
action,
|
|
313
|
+
leaseExpiresAt: requiredString(record, "lease_expires_at", operation)
|
|
314
|
+
};
|
|
315
|
+
if ("destroy" === action) return {
|
|
316
|
+
action,
|
|
317
|
+
generation: requiredGeneration(record, operation),
|
|
318
|
+
sandboxId: requiredString(record, "sandbox_id", operation)
|
|
319
|
+
};
|
|
320
|
+
throw new _error_js__rspack_import_2.ES("Sandbox persistence returned an invalid response.");
|
|
321
|
+
}
|
|
322
|
+
async finishDestroy(conversationId, generation, leaseToken, signal) {
|
|
323
|
+
await this.booleanRpc("sandbox_binding_finish_destroy", {
|
|
324
|
+
p_conversation_id: conversationId,
|
|
325
|
+
p_generation: generation,
|
|
326
|
+
p_lease_token: leaseToken
|
|
327
|
+
}, "sandbox.binding.finishDestroy", signal);
|
|
328
|
+
}
|
|
329
|
+
async restore(conversationId, generation, leaseToken, signal) {
|
|
330
|
+
await this.booleanRpc("sandbox_binding_restore", {
|
|
331
|
+
p_conversation_id: conversationId,
|
|
332
|
+
p_generation: generation,
|
|
333
|
+
p_lease_token: leaseToken
|
|
334
|
+
}, "sandbox.binding.restore", signal);
|
|
335
|
+
}
|
|
336
|
+
async booleanRpc(name, params, operation, signal) {
|
|
337
|
+
const data = await this.rpc(name, params, operation, signal);
|
|
338
|
+
if ("boolean" != typeof data) throw new _error_js__rspack_import_2.ES("Sandbox persistence returned an invalid response.");
|
|
339
|
+
return data;
|
|
340
|
+
}
|
|
341
|
+
async rpc(name, params, operation, signal) {
|
|
342
|
+
const requestId = this.generateUuid();
|
|
343
|
+
for(let attempt = 0; attempt < 2; attempt += 1){
|
|
344
|
+
if (signal?.aborted) throw new _error_js__rspack_import_2.sX("The sandbox operation was cancelled.");
|
|
345
|
+
let credentials;
|
|
346
|
+
try {
|
|
347
|
+
credentials = await this.credentialProvider.getValidCredentials(signal);
|
|
348
|
+
} catch (error) {
|
|
349
|
+
if (error instanceof _iga_pages_data_plane__rspack_import_1.d && "aborted" === error.code) throw new _error_js__rspack_import_2.sX("The sandbox operation was cancelled.");
|
|
350
|
+
if (error instanceof _iga_pages_data_plane__rspack_import_1.d) throw new _error_js__rspack_import_2.ES(error.message, {
|
|
351
|
+
status: error.status
|
|
352
|
+
});
|
|
353
|
+
break;
|
|
354
|
+
}
|
|
355
|
+
const client = (0, _iga_pages_data_plane__rspack_import_1.Ju)({
|
|
356
|
+
credentials,
|
|
357
|
+
requestId,
|
|
358
|
+
signal,
|
|
359
|
+
fetch: this.fetch,
|
|
360
|
+
createClient: this.createClient,
|
|
361
|
+
realtimeError: ()=>new _error_js__rspack_import_2.ES("Sandbox persistence does not support Realtime.")
|
|
362
|
+
});
|
|
363
|
+
let result;
|
|
364
|
+
try {
|
|
365
|
+
result = await client.rpc(name, params);
|
|
366
|
+
} catch {
|
|
367
|
+
if (signal?.aborted) throw new _error_js__rspack_import_2.sX("The sandbox operation was cancelled.");
|
|
368
|
+
if (0 === attempt) continue;
|
|
369
|
+
break;
|
|
370
|
+
}
|
|
371
|
+
if (401 === result.status && 0 === attempt) {
|
|
372
|
+
this.credentialProvider.invalidate(credentials.jwt);
|
|
373
|
+
continue;
|
|
374
|
+
}
|
|
375
|
+
if (result.error || result.status < 200 || result.status >= 300) throw unavailable(operation, requestId, result.status);
|
|
376
|
+
return result.data;
|
|
377
|
+
}
|
|
378
|
+
throw unavailable(operation, requestId);
|
|
379
|
+
}
|
|
380
|
+
constructor(options){
|
|
381
|
+
this.credentialProvider = options.credentialProvider;
|
|
382
|
+
this.fetch = options.fetch;
|
|
383
|
+
this.createClient = options.createClient;
|
|
384
|
+
this.generateUuid = options.generateUuid ?? node_crypto__rspack_import_0.randomUUID;
|
|
385
|
+
this.leaseSeconds = options.leaseSeconds ?? 60;
|
|
386
|
+
}
|
|
387
|
+
}
|
|
388
|
+
function createRuntimeSandboxBindingRepository(options) {
|
|
389
|
+
const credentialProvider = new _iga_pages_data_plane__rspack_import_1.ZQ({
|
|
390
|
+
fetchCredentials: ()=>(0, _iga_pages_data_plane__rspack_import_1.FM)({
|
|
391
|
+
token: options.token,
|
|
392
|
+
fetch: options.fetch
|
|
393
|
+
})
|
|
394
|
+
});
|
|
395
|
+
return new SupabaseSandboxBindingRepository({
|
|
396
|
+
credentialProvider,
|
|
397
|
+
fetch: options.fetch,
|
|
398
|
+
createClient: options.createClient
|
|
399
|
+
});
|
|
400
|
+
}
|
|
401
|
+
},
|
|
402
|
+
"../sandbox/src/iga-sandbox.ts" (__unused_rspack_module, __webpack_exports__, __webpack_require__) {
|
|
403
|
+
__webpack_require__.d(__webpack_exports__, {
|
|
404
|
+
rG: ()=>__clearSandboxCacheForTests,
|
|
405
|
+
_i: ()=>createSandbox,
|
|
406
|
+
CT: ()=>createDetachedSandbox,
|
|
407
|
+
gk: ()=>isInstanceGoneResponse,
|
|
408
|
+
RN: ()=>IgaSandbox,
|
|
409
|
+
R9: ()=>attachSandbox,
|
|
410
|
+
pf: ()=>__getEntryForTests
|
|
411
|
+
});
|
|
412
|
+
var external_node_crypto_ = __webpack_require__("node:crypto");
|
|
413
|
+
var esm = __webpack_require__("../../node_modules/.pnpm/@agent-infra+sandbox@1.0.17/node_modules/@agent-infra/sandbox/dist/esm/index.mjs");
|
|
414
|
+
var src_error = __webpack_require__("../sandbox/src/error.ts");
|
|
415
|
+
var api_client = __webpack_require__("../sandbox/src/api-client.ts");
|
|
416
|
+
function parseExpireAtMs(value) {
|
|
417
|
+
if (!value) return;
|
|
418
|
+
const normalized = value.replace(/([+-]\d{2}):?(\d{2})/, "$1:$2").replace(/\s+[A-Za-z]{2,5}$/, "");
|
|
419
|
+
const ms = Date.parse(normalized);
|
|
420
|
+
return Number.isFinite(ms) ? ms : void 0;
|
|
421
|
+
}
|
|
422
|
+
const cache = new Map();
|
|
423
|
+
function __clearSandboxCacheForTests() {
|
|
424
|
+
for (const entry of cache.values())entry.inflight?.controller.abort();
|
|
425
|
+
cache.clear();
|
|
426
|
+
}
|
|
427
|
+
function __getEntryForTests(projectId, conversationId) {
|
|
428
|
+
return cache.get(JSON.stringify([
|
|
429
|
+
projectId,
|
|
430
|
+
conversationId
|
|
431
|
+
]));
|
|
432
|
+
}
|
|
433
|
+
const AUTO_EXTEND_THRESHOLD_MS = 300000;
|
|
434
|
+
const AUTO_EXTEND_MINUTES = 30;
|
|
435
|
+
function isInstanceGoneResponse(result) {
|
|
436
|
+
if (!result || "object" != typeof result) return false;
|
|
437
|
+
const failed = result;
|
|
438
|
+
if (false !== failed.ok) return false;
|
|
439
|
+
if (failed.error?.statusCode === 422) return false;
|
|
440
|
+
const content = failed.error?.content;
|
|
441
|
+
if (!content || "status-code" !== content.reason) return false;
|
|
442
|
+
return 404 === content.statusCode || 410 === content.statusCode;
|
|
443
|
+
}
|
|
444
|
+
async function extendIfExpiring(entry, opts) {
|
|
445
|
+
if (void 0 === entry.instanceExpireAt) return;
|
|
446
|
+
if (entry.instanceExpireAt - AUTO_EXTEND_THRESHOLD_MS > Date.now()) return;
|
|
447
|
+
if (void 0 === entry.sandboxId) return;
|
|
448
|
+
if (entry.extendingInflight) return entry.extendingInflight;
|
|
449
|
+
const generation = entry.generation;
|
|
450
|
+
const sandboxId = entry.sandboxId;
|
|
451
|
+
const flight = Promise.resolve().then(async ()=>{
|
|
452
|
+
try {
|
|
453
|
+
const updated = await entry.api.updateInstanceTimeout({
|
|
454
|
+
...opts,
|
|
455
|
+
sandboxId,
|
|
456
|
+
timeoutInMinutes: AUTO_EXTEND_MINUTES
|
|
457
|
+
});
|
|
458
|
+
const expireAt = parseExpireAtMs(updated.expireAt);
|
|
459
|
+
if (void 0 !== expireAt && entry.generation === generation && entry.sandboxId === sandboxId && updated.sandboxId === sandboxId) entry.instanceExpireAt = expireAt;
|
|
460
|
+
} catch (error) {
|
|
461
|
+
if (entry.generation === generation && entry.sandboxId === sandboxId && (error instanceof src_error.YA || void 0 !== entry.instanceExpireAt && entry.instanceExpireAt <= Date.now())) throw normalizeLifecycleError(error, "extendTimeout");
|
|
462
|
+
} finally{
|
|
463
|
+
if (entry.extendingInflight === flight) entry.extendingInflight = void 0;
|
|
464
|
+
}
|
|
465
|
+
});
|
|
466
|
+
entry.extendingInflight = flight;
|
|
467
|
+
return flight;
|
|
468
|
+
}
|
|
469
|
+
const CLIENT_SUBMODULE_KEYS = (()=>{
|
|
470
|
+
const descs = Object.getOwnPropertyDescriptors(esm.VF.prototype);
|
|
471
|
+
return Object.keys(descs).filter((k)=>"constructor" !== k && "function" == typeof descs[k].get);
|
|
472
|
+
})();
|
|
473
|
+
function isDetachedOptions(options) {
|
|
474
|
+
return "detached" === options.mode;
|
|
475
|
+
}
|
|
476
|
+
function isAttachOptions(options) {
|
|
477
|
+
return "attach" === options.mode;
|
|
478
|
+
}
|
|
479
|
+
class IgaSandbox {
|
|
480
|
+
installLazyGetters() {
|
|
481
|
+
for (const key of CLIENT_SUBMODULE_KEYS)if (!Object.prototype.hasOwnProperty.call(this, key)) Object.defineProperty(this, key, {
|
|
482
|
+
enumerable: true,
|
|
483
|
+
configurable: true,
|
|
484
|
+
get: ()=>this.getLazySubmodule(key)
|
|
485
|
+
});
|
|
486
|
+
}
|
|
487
|
+
getLazySubmodule(key) {
|
|
488
|
+
const cached = this.submoduleCache.get(key);
|
|
489
|
+
if (void 0 !== cached) return cached;
|
|
490
|
+
const self = this;
|
|
491
|
+
const proxy = new Proxy({}, {
|
|
492
|
+
get (_t, method) {
|
|
493
|
+
if ("string" != typeof method) return;
|
|
494
|
+
return async function(...args) {
|
|
495
|
+
const abortSignal = requestAbortSignal(args);
|
|
496
|
+
const invocation = {
|
|
497
|
+
generation: self.entry.generation
|
|
498
|
+
};
|
|
499
|
+
const invoke = async ()=>{
|
|
500
|
+
let raw = await self.ensureInstance({
|
|
501
|
+
abortSignal
|
|
502
|
+
});
|
|
503
|
+
while(self.entry.destroyingInflight || self.entry.recoveryInflight || self.rawGeneration !== self.entry.generation)raw = await self.ensureInstance({
|
|
504
|
+
abortSignal
|
|
505
|
+
});
|
|
506
|
+
const sub = raw[key];
|
|
507
|
+
const fn = sub[method];
|
|
508
|
+
if ("function" != typeof fn) throw new TypeError(`sandbox.${key}.${String(method)} is not a function`);
|
|
509
|
+
invocation.generation = self.entry.generation;
|
|
510
|
+
const operation = Promise.resolve().then(()=>fn.apply(sub, args));
|
|
511
|
+
const active = self.entry.activeOperations ??= new Set();
|
|
512
|
+
active.add(operation);
|
|
513
|
+
const renewal = setInterval(()=>{
|
|
514
|
+
if (self.entry.generation === invocation.generation) extendIfExpiring(self.entry, self.managementCallOpts()).catch(()=>{});
|
|
515
|
+
}, 60000);
|
|
516
|
+
renewal.unref();
|
|
517
|
+
try {
|
|
518
|
+
return await operation;
|
|
519
|
+
} finally{
|
|
520
|
+
clearInterval(renewal);
|
|
521
|
+
active.delete(operation);
|
|
522
|
+
}
|
|
523
|
+
};
|
|
524
|
+
return self.callWithRecreate(invoke, invocation, abortSignal);
|
|
525
|
+
};
|
|
526
|
+
}
|
|
527
|
+
});
|
|
528
|
+
this.submoduleCache.set(key, proxy);
|
|
529
|
+
return proxy;
|
|
530
|
+
}
|
|
531
|
+
async callWithRecreate(invoke, invocation, abortSignal) {
|
|
532
|
+
const result = await invoke();
|
|
533
|
+
if ("conversation" !== this.mode) return result;
|
|
534
|
+
if (!isInstanceGoneResponse(result)) return result;
|
|
535
|
+
const generation = invocation.generation;
|
|
536
|
+
if (this.entry.generation !== generation || this.entry.destroyingInflight) return result;
|
|
537
|
+
const confirmed = await this.confirmDestroyed(abortSignal);
|
|
538
|
+
if (!confirmed || this.entry.generation !== generation || this.entry.destroyingInflight) return result;
|
|
539
|
+
await this.recreateInstance(generation, abortSignal);
|
|
540
|
+
if (this.entry.destroyingInflight || this.entry.generation !== generation + 1) return result;
|
|
541
|
+
await this.ensureInstance({
|
|
542
|
+
abortSignal
|
|
543
|
+
});
|
|
544
|
+
if (!(0, api_client.ip)(result)) return result;
|
|
545
|
+
return invoke();
|
|
546
|
+
}
|
|
547
|
+
async confirmDestroyed(abortSignal) {
|
|
548
|
+
const entry = this.entry;
|
|
549
|
+
const sandboxId = entry.sandboxId;
|
|
550
|
+
if (!sandboxId) return false;
|
|
551
|
+
if (!entry.recreateInflight) {
|
|
552
|
+
const flight = Promise.resolve().then(async ()=>{
|
|
553
|
+
try {
|
|
554
|
+
await entry.api.confirmInstanceExists({
|
|
555
|
+
...this.managementCallOpts(),
|
|
556
|
+
sandboxId
|
|
557
|
+
});
|
|
558
|
+
return false;
|
|
559
|
+
} catch (err) {
|
|
560
|
+
if (err instanceof src_error.YA) return true;
|
|
561
|
+
return false;
|
|
562
|
+
} finally{
|
|
563
|
+
if (entry.recreateInflight === flight) entry.recreateInflight = void 0;
|
|
564
|
+
}
|
|
565
|
+
});
|
|
566
|
+
entry.recreateInflight = flight;
|
|
567
|
+
}
|
|
568
|
+
const inflight = entry.recreateInflight;
|
|
569
|
+
return waitForOperation(inflight, abortSignal);
|
|
570
|
+
}
|
|
571
|
+
async recreateInstance(expectedGeneration, abortSignal) {
|
|
572
|
+
throwIfOperationAborted(abortSignal);
|
|
573
|
+
const entry = this.entry;
|
|
574
|
+
if (entry.destroyingInflight) return void await waitForOperation(entry.destroyingInflight, abortSignal);
|
|
575
|
+
if (entry.recoveryInflight) return waitForOperation(entry.recoveryInflight, abortSignal);
|
|
576
|
+
if (entry.generation !== expectedGeneration) return;
|
|
577
|
+
const flight = Promise.resolve().then(()=>this.performRecreation(expectedGeneration)).finally(()=>{
|
|
578
|
+
if (entry.recoveryInflight === flight) entry.recoveryInflight = void 0;
|
|
579
|
+
});
|
|
580
|
+
entry.recoveryInflight = flight;
|
|
581
|
+
return waitForOperation(flight, abortSignal);
|
|
582
|
+
}
|
|
583
|
+
async performRecreation(expectedGeneration) {
|
|
584
|
+
const entry = this.entry;
|
|
585
|
+
const abortSignal = void 0;
|
|
586
|
+
if (entry.generation !== expectedGeneration) return;
|
|
587
|
+
const sandboxId = entry.sandboxId;
|
|
588
|
+
if (entry.bindingRepository && this.conversationId && void 0 !== entry.bindingGeneration && sandboxId) await entry.bindingRepository.invalidate(this.conversationId, entry.bindingGeneration, sandboxId, abortSignal);
|
|
589
|
+
if (entry.generation !== expectedGeneration) return;
|
|
590
|
+
entry.inflight?.controller.abort();
|
|
591
|
+
entry.generation += 1;
|
|
592
|
+
this.raw = void 0;
|
|
593
|
+
this.rawGeneration = -1;
|
|
594
|
+
entry.inflight = void 0;
|
|
595
|
+
entry.sandboxId = void 0;
|
|
596
|
+
entry.apiKey = void 0;
|
|
597
|
+
entry.environment = void 0;
|
|
598
|
+
entry.headers = void 0;
|
|
599
|
+
entry.instanceExpireAt = void 0;
|
|
600
|
+
entry.bindingGeneration = void 0;
|
|
601
|
+
entry.extendingInflight = void 0;
|
|
602
|
+
entry.recreateInflight = void 0;
|
|
603
|
+
this.submoduleCache.clear();
|
|
604
|
+
if (!sandboxId) return;
|
|
605
|
+
try {
|
|
606
|
+
await entry.api.destroy({
|
|
607
|
+
...this.managementCallOpts(),
|
|
608
|
+
sandboxId
|
|
609
|
+
});
|
|
610
|
+
} catch {}
|
|
611
|
+
}
|
|
612
|
+
async getClient(options) {
|
|
613
|
+
return this.ensureInstance({
|
|
614
|
+
abortSignal: options?.abortSignal
|
|
615
|
+
});
|
|
616
|
+
}
|
|
617
|
+
async ensureReady(options) {
|
|
618
|
+
await this.ensureInstance({
|
|
619
|
+
abortSignal: options?.abortSignal
|
|
620
|
+
});
|
|
621
|
+
}
|
|
622
|
+
async ensureInstance(opts = {}) {
|
|
623
|
+
const entry = this.entry;
|
|
624
|
+
for(;;){
|
|
625
|
+
throwIfOperationAborted(opts.abortSignal);
|
|
626
|
+
const lifecycle = entry.destroyingInflight ?? entry.recoveryInflight;
|
|
627
|
+
if (lifecycle) {
|
|
628
|
+
await waitForOperation(lifecycle, opts.abortSignal);
|
|
629
|
+
continue;
|
|
630
|
+
}
|
|
631
|
+
const generation = entry.generation;
|
|
632
|
+
if (isEntryReady(entry)) {
|
|
633
|
+
if (!opts.skipAutoExtend) try {
|
|
634
|
+
await waitForOperation(extendIfExpiring(entry, this.managementCallOpts()), opts.abortSignal);
|
|
635
|
+
} catch (error) {
|
|
636
|
+
if ("conversation" !== this.mode || !(error instanceof src_error.YA)) throw error;
|
|
637
|
+
await this.recreateInstance(generation, opts.abortSignal);
|
|
638
|
+
continue;
|
|
639
|
+
}
|
|
640
|
+
if (entry.generation !== generation || entry.destroyingInflight || entry.recoveryInflight || !isEntryReady(entry)) continue;
|
|
641
|
+
if (this.raw && this.rawGeneration === generation) return this.raw;
|
|
642
|
+
return this.createClient(entry);
|
|
643
|
+
}
|
|
644
|
+
this.raw = void 0;
|
|
645
|
+
const flight = entry.inflight ?? this.startInitialization(entry);
|
|
646
|
+
try {
|
|
647
|
+
await this.waitForInitialization(flight, opts.abortSignal);
|
|
648
|
+
} catch (error) {
|
|
649
|
+
throwIfOperationAborted(opts.abortSignal);
|
|
650
|
+
throw error;
|
|
651
|
+
}
|
|
652
|
+
if (entry.generation === generation && !entry.destroyingInflight && !entry.recoveryInflight) {
|
|
653
|
+
if (!isEntryReady(entry)) throw sandboxUnavailableError("sandbox.initialize");
|
|
654
|
+
return this.createClient(entry);
|
|
655
|
+
}
|
|
656
|
+
}
|
|
657
|
+
}
|
|
658
|
+
startInitialization(entry) {
|
|
659
|
+
const controller = new AbortController();
|
|
660
|
+
const generation = entry.generation;
|
|
661
|
+
const flight = {};
|
|
662
|
+
flight.controller = controller;
|
|
663
|
+
flight.result = this.initializeEntry(entry, controller.signal, generation).then(()=>({
|
|
664
|
+
ok: true,
|
|
665
|
+
value: void 0
|
|
666
|
+
}), (error)=>({
|
|
667
|
+
ok: false,
|
|
668
|
+
error
|
|
669
|
+
}));
|
|
670
|
+
entry.inflight = flight;
|
|
671
|
+
flight.result.then(()=>{
|
|
672
|
+
if (entry.inflight === flight) entry.inflight = void 0;
|
|
673
|
+
});
|
|
674
|
+
return flight;
|
|
675
|
+
}
|
|
676
|
+
async waitForInitialization(flight, abortSignal) {
|
|
677
|
+
const result = await waitForOperation(flight.result, abortSignal);
|
|
678
|
+
if (!result.ok) throw result.error;
|
|
679
|
+
}
|
|
680
|
+
async initializeEntry(entry, signal, generation) {
|
|
681
|
+
if ("attach" === this.mode) return void await this.initializeAttach(entry, signal, generation);
|
|
682
|
+
if ("conversation" === this.mode && entry.bindingRepository) return void await this.initializePersistentConversation(entry, signal, generation);
|
|
683
|
+
const conversationCallOpts = {
|
|
684
|
+
projectId: this.projectId,
|
|
685
|
+
conversationId: this.conversationId,
|
|
686
|
+
signal
|
|
687
|
+
};
|
|
688
|
+
const callOpts = "detached" === this.mode ? {
|
|
689
|
+
projectId: this.projectId,
|
|
690
|
+
conversationId: "",
|
|
691
|
+
signal
|
|
692
|
+
} : conversationCallOpts;
|
|
693
|
+
let token;
|
|
694
|
+
try {
|
|
695
|
+
token = await entry.api.getToken({
|
|
696
|
+
signal: callOpts.signal
|
|
697
|
+
});
|
|
698
|
+
} catch (err) {
|
|
699
|
+
throw normalizeLifecycleError(err, "authenticate");
|
|
700
|
+
}
|
|
701
|
+
assertInitializationCurrent(entry, generation, signal);
|
|
702
|
+
let created;
|
|
703
|
+
try {
|
|
704
|
+
created = await entry.api.create(callOpts);
|
|
705
|
+
} catch (err) {
|
|
706
|
+
throw normalizeLifecycleError(err, "create");
|
|
707
|
+
}
|
|
708
|
+
if (signal.aborted || entry.generation !== generation) {
|
|
709
|
+
await bestEffortDestroy(entry, {
|
|
710
|
+
projectId: this.projectId,
|
|
711
|
+
conversationId: callOpts.conversationId,
|
|
712
|
+
sandboxId: created.sandboxId
|
|
713
|
+
});
|
|
714
|
+
assertInitializationCurrent(entry, generation, signal);
|
|
715
|
+
}
|
|
716
|
+
const environment = token.url;
|
|
717
|
+
if (!environment) {
|
|
718
|
+
await bestEffortDestroy(entry, {
|
|
719
|
+
projectId: this.projectId,
|
|
720
|
+
conversationId: callOpts.conversationId,
|
|
721
|
+
sandboxId: created.sandboxId
|
|
722
|
+
});
|
|
723
|
+
throw new src_error.ES("Sandbox credentials could not be initialized.");
|
|
724
|
+
}
|
|
725
|
+
const headerName = token.tokenHeader ?? "Authorization";
|
|
726
|
+
const headerValue = `${token.tokenType ?? "Bearer"} ${token.apiKey}`;
|
|
727
|
+
const headers = {
|
|
728
|
+
[headerName]: headerValue
|
|
729
|
+
};
|
|
730
|
+
headers["x-faas-instance-name"] = created.sandboxId;
|
|
731
|
+
entry.apiKey = token.apiKey;
|
|
732
|
+
entry.sandboxId = created.sandboxId;
|
|
733
|
+
entry.environment = environment;
|
|
734
|
+
entry.headers = headers;
|
|
735
|
+
entry.instanceExpireAt = void 0;
|
|
736
|
+
if ("detached" === this.mode) this.sandboxId = created.sandboxId;
|
|
737
|
+
try {
|
|
738
|
+
const info = await entry.api.getInstance({
|
|
739
|
+
...callOpts,
|
|
740
|
+
sandboxId: created.sandboxId
|
|
741
|
+
});
|
|
742
|
+
if (entry.generation === generation && entry.sandboxId === created.sandboxId && info.sandboxId === created.sandboxId) entry.instanceExpireAt = parseExpireAtMs(info.expireAt);
|
|
743
|
+
} catch {}
|
|
744
|
+
}
|
|
745
|
+
async queryUsableInstance(entry, opts) {
|
|
746
|
+
const deadline = Date.now() + 30000;
|
|
747
|
+
for(;;){
|
|
748
|
+
const info = await entry.api.getInstance(opts);
|
|
749
|
+
if (!info.sandboxId) throw new src_error.YA("The sandbox was not found.");
|
|
750
|
+
if (info.sandboxId !== opts.sandboxId) throw new src_error.ES("Sandbox instance query returned a different instance.");
|
|
751
|
+
if ("Failed" === info.status || "Terminating" === info.status) throw new src_error.YA("The sandbox is not available.");
|
|
752
|
+
if ("Starting" !== info.status) return info;
|
|
753
|
+
if (Date.now() >= deadline) throw new src_error.ES("Sandbox startup timed out.", {
|
|
754
|
+
status: 504
|
|
755
|
+
});
|
|
756
|
+
await waitForDelay(500, opts.signal);
|
|
757
|
+
}
|
|
758
|
+
}
|
|
759
|
+
async initializePersistentConversation(entry, signal, generation) {
|
|
760
|
+
const repository = entry.bindingRepository;
|
|
761
|
+
const conversationId = this.conversationId;
|
|
762
|
+
const leaseToken = (0, external_node_crypto_.randomUUID)();
|
|
763
|
+
const waitDeadline = Date.now() + 90000;
|
|
764
|
+
const callOpts = {
|
|
765
|
+
projectId: this.projectId,
|
|
766
|
+
conversationId,
|
|
767
|
+
signal
|
|
768
|
+
};
|
|
769
|
+
for(;;){
|
|
770
|
+
assertInitializationCurrent(entry, generation, signal);
|
|
771
|
+
if (Date.now() >= waitDeadline) throw new src_error.ES("Sandbox session initialization timed out.", {
|
|
772
|
+
status: 504
|
|
773
|
+
});
|
|
774
|
+
const binding = await repository.acquire(conversationId, leaseToken, signal);
|
|
775
|
+
if ("wait" === binding.action) {
|
|
776
|
+
if (Date.now() >= waitDeadline) throw new src_error.ES("Sandbox session initialization is still in progress.");
|
|
777
|
+
const leaseDeadline = Date.parse(binding.leaseExpiresAt);
|
|
778
|
+
const remaining = Number.isFinite(leaseDeadline) ? Math.max(100, leaseDeadline - Date.now()) : 500;
|
|
779
|
+
await waitForDelay(Math.min(500, remaining), signal);
|
|
780
|
+
continue;
|
|
781
|
+
}
|
|
782
|
+
if ("attach" === binding.action) {
|
|
783
|
+
let info;
|
|
784
|
+
try {
|
|
785
|
+
info = await this.queryUsableInstance(entry, {
|
|
786
|
+
...callOpts,
|
|
787
|
+
sandboxId: binding.sandboxId
|
|
788
|
+
});
|
|
789
|
+
} catch (error) {
|
|
790
|
+
if (error instanceof src_error.YA) {
|
|
791
|
+
assertInitializationCurrent(entry, generation, signal);
|
|
792
|
+
await repository.invalidate(conversationId, binding.generation, binding.sandboxId, signal);
|
|
793
|
+
continue;
|
|
794
|
+
}
|
|
795
|
+
throw normalizeLifecycleError(error, "getInfo");
|
|
796
|
+
}
|
|
797
|
+
assertInitializationCurrent(entry, generation, signal);
|
|
798
|
+
if (isUnavailableInstance(info)) {
|
|
799
|
+
await repository.invalidate(conversationId, binding.generation, binding.sandboxId, signal);
|
|
800
|
+
continue;
|
|
801
|
+
}
|
|
802
|
+
const expiry = parseExpireAtMs(info.expireAt);
|
|
803
|
+
if (void 0 !== expiry && expiry <= Date.now() + AUTO_EXTEND_THRESHOLD_MS) {
|
|
804
|
+
try {
|
|
805
|
+
info = await entry.api.updateInstanceTimeout({
|
|
806
|
+
...callOpts,
|
|
807
|
+
sandboxId: binding.sandboxId,
|
|
808
|
+
timeoutInMinutes: AUTO_EXTEND_MINUTES
|
|
809
|
+
});
|
|
810
|
+
} catch (error) {
|
|
811
|
+
if (!(error instanceof src_error.YA)) throw error;
|
|
812
|
+
await repository.invalidate(conversationId, binding.generation, binding.sandboxId, signal);
|
|
813
|
+
continue;
|
|
814
|
+
}
|
|
815
|
+
assertInitializationCurrent(entry, generation, signal);
|
|
816
|
+
if (info.sandboxId !== binding.sandboxId) throw new src_error.ES("Sandbox renewal returned a different instance.");
|
|
817
|
+
}
|
|
818
|
+
let token;
|
|
819
|
+
try {
|
|
820
|
+
token = await entry.api.getToken({
|
|
821
|
+
signal: callOpts.signal
|
|
822
|
+
});
|
|
823
|
+
} catch (error) {
|
|
824
|
+
throw normalizeLifecycleError(error, "authenticate");
|
|
825
|
+
}
|
|
826
|
+
assertInitializationCurrent(entry, generation, signal);
|
|
827
|
+
this.commitInitializedEntry(entry, generation, binding.generation, binding.sandboxId, token, info.expireAt, signal);
|
|
828
|
+
return;
|
|
829
|
+
}
|
|
830
|
+
let token;
|
|
831
|
+
try {
|
|
832
|
+
token = await entry.api.getToken({
|
|
833
|
+
signal: callOpts.signal
|
|
834
|
+
});
|
|
835
|
+
} catch (error) {
|
|
836
|
+
await repository.release(conversationId, binding.generation, leaseToken, signal);
|
|
837
|
+
throw normalizeLifecycleError(error, "authenticate");
|
|
838
|
+
}
|
|
839
|
+
assertInitializationCurrent(entry, generation, signal);
|
|
840
|
+
if (!token.url) {
|
|
841
|
+
await repository.release(conversationId, binding.generation, leaseToken, signal);
|
|
842
|
+
throw new src_error.ES("Sandbox credentials could not be initialized.");
|
|
843
|
+
}
|
|
844
|
+
let created;
|
|
845
|
+
try {
|
|
846
|
+
created = await entry.api.create(callOpts);
|
|
847
|
+
} catch (error) {
|
|
848
|
+
throw normalizeLifecycleError(error, "create");
|
|
849
|
+
}
|
|
850
|
+
if (signal.aborted || entry.generation !== generation) {
|
|
851
|
+
await bestEffortDestroy(entry, {
|
|
852
|
+
projectId: this.projectId,
|
|
853
|
+
conversationId,
|
|
854
|
+
sandboxId: created.sandboxId
|
|
855
|
+
});
|
|
856
|
+
assertInitializationCurrent(entry, generation, signal);
|
|
857
|
+
}
|
|
858
|
+
let info;
|
|
859
|
+
try {
|
|
860
|
+
info = await this.queryUsableInstance(entry, {
|
|
861
|
+
...callOpts,
|
|
862
|
+
sandboxId: created.sandboxId
|
|
863
|
+
});
|
|
864
|
+
} catch (error) {
|
|
865
|
+
await bestEffortDestroy(entry, {
|
|
866
|
+
...callOpts,
|
|
867
|
+
sandboxId: created.sandboxId
|
|
868
|
+
});
|
|
869
|
+
await repository.release(conversationId, binding.generation, leaseToken, signal);
|
|
870
|
+
throw error;
|
|
871
|
+
}
|
|
872
|
+
let published;
|
|
873
|
+
try {
|
|
874
|
+
published = await repository.publish(conversationId, binding.generation, leaseToken, created.sandboxId, signal);
|
|
875
|
+
} catch (error) {
|
|
876
|
+
await bestEffortDestroy(entry, {
|
|
877
|
+
projectId: this.projectId,
|
|
878
|
+
conversationId,
|
|
879
|
+
sandboxId: created.sandboxId
|
|
880
|
+
});
|
|
881
|
+
throw error;
|
|
882
|
+
}
|
|
883
|
+
if (!published) {
|
|
884
|
+
await bestEffortDestroy(entry, {
|
|
885
|
+
projectId: this.projectId,
|
|
886
|
+
conversationId,
|
|
887
|
+
sandboxId: created.sandboxId
|
|
888
|
+
});
|
|
889
|
+
continue;
|
|
890
|
+
}
|
|
891
|
+
try {
|
|
892
|
+
this.commitInitializedEntry(entry, generation, binding.generation, created.sandboxId, token, info?.expireAt, signal);
|
|
893
|
+
} catch (error) {
|
|
894
|
+
await bestEffortDestroy(entry, {
|
|
895
|
+
projectId: this.projectId,
|
|
896
|
+
conversationId,
|
|
897
|
+
sandboxId: created.sandboxId
|
|
898
|
+
});
|
|
899
|
+
await repository.invalidate(conversationId, binding.generation, created.sandboxId, signal);
|
|
900
|
+
throw error;
|
|
901
|
+
}
|
|
902
|
+
return;
|
|
903
|
+
}
|
|
904
|
+
}
|
|
905
|
+
commitInitializedEntry(entry, generation, bindingGeneration, sandboxId, token, expireAt, signal) {
|
|
906
|
+
if (!token.url) throw new src_error.ES("Sandbox credentials could not be initialized.");
|
|
907
|
+
assertInitializationCurrent(entry, generation, signal ?? new AbortController().signal);
|
|
908
|
+
const headerName = token.tokenHeader ?? "Authorization";
|
|
909
|
+
entry.apiKey = token.apiKey;
|
|
910
|
+
entry.sandboxId = sandboxId;
|
|
911
|
+
entry.environment = token.url;
|
|
912
|
+
entry.headers = {
|
|
913
|
+
[headerName]: `${token.tokenType ?? "Bearer"} ${token.apiKey}`,
|
|
914
|
+
"x-faas-instance-name": sandboxId
|
|
915
|
+
};
|
|
916
|
+
entry.instanceExpireAt = parseExpireAtMs(expireAt);
|
|
917
|
+
entry.bindingGeneration = bindingGeneration;
|
|
918
|
+
}
|
|
919
|
+
async initializeAttach(entry, signal, generation) {
|
|
920
|
+
const sandboxId = this.sandboxId;
|
|
921
|
+
const callOpts = {
|
|
922
|
+
projectId: this.projectId,
|
|
923
|
+
conversationId: "",
|
|
924
|
+
signal
|
|
925
|
+
};
|
|
926
|
+
let token;
|
|
927
|
+
try {
|
|
928
|
+
token = await entry.api.getToken({
|
|
929
|
+
signal: callOpts.signal
|
|
930
|
+
});
|
|
931
|
+
} catch (err) {
|
|
932
|
+
throw normalizeLifecycleError(err, "authenticate");
|
|
933
|
+
}
|
|
934
|
+
assertInitializationCurrent(entry, generation, signal);
|
|
935
|
+
let info;
|
|
936
|
+
try {
|
|
937
|
+
info = await this.queryUsableInstance(entry, {
|
|
938
|
+
...callOpts,
|
|
939
|
+
sandboxId
|
|
940
|
+
});
|
|
941
|
+
} catch (err) {
|
|
942
|
+
throw normalizeLifecycleError(err, "getInfo");
|
|
943
|
+
}
|
|
944
|
+
assertInitializationCurrent(entry, generation, signal);
|
|
945
|
+
if (!info.sandboxId || "Failed" === info.status || "Terminating" === info.status) throw new src_error.YA("The sandbox was not found.");
|
|
946
|
+
const expireAt = parseExpireAtMs(info.expireAt);
|
|
947
|
+
if (void 0 !== expireAt && expireAt <= Date.now()) {
|
|
948
|
+
let renewed;
|
|
949
|
+
try {
|
|
950
|
+
renewed = await entry.api.updateInstanceTimeout({
|
|
951
|
+
...callOpts,
|
|
952
|
+
sandboxId,
|
|
953
|
+
timeoutInMinutes: AUTO_EXTEND_MINUTES
|
|
954
|
+
});
|
|
955
|
+
} catch (err) {
|
|
956
|
+
throw normalizeLifecycleError(err, "extendTimeout");
|
|
957
|
+
}
|
|
958
|
+
assertInitializationCurrent(entry, generation, signal);
|
|
959
|
+
if (renewed.sandboxId !== sandboxId) throw new src_error.ES("Sandbox renewal returned a different instance.");
|
|
960
|
+
entry.instanceExpireAt = parseExpireAtMs(renewed.expireAt);
|
|
961
|
+
} else entry.instanceExpireAt = expireAt;
|
|
962
|
+
const environment = token.url;
|
|
963
|
+
if (!environment) throw new src_error.ES("Sandbox credentials could not be initialized.");
|
|
964
|
+
const headerName = token.tokenHeader ?? "Authorization";
|
|
965
|
+
const headerValue = `${token.tokenType ?? "Bearer"} ${token.apiKey}`;
|
|
966
|
+
const headers = {
|
|
967
|
+
[headerName]: headerValue
|
|
968
|
+
};
|
|
969
|
+
headers["x-faas-instance-name"] = sandboxId;
|
|
970
|
+
entry.apiKey = token.apiKey;
|
|
971
|
+
entry.sandboxId = sandboxId;
|
|
972
|
+
entry.environment = environment;
|
|
973
|
+
entry.headers = headers;
|
|
974
|
+
}
|
|
975
|
+
managementCallOpts() {
|
|
976
|
+
return {
|
|
977
|
+
projectId: this.projectId,
|
|
978
|
+
conversationId: this.conversationId ?? ""
|
|
979
|
+
};
|
|
980
|
+
}
|
|
981
|
+
createClient(entry) {
|
|
982
|
+
if (!isEntryReady(entry)) throw sandboxUnavailableError("sandbox.initialize");
|
|
983
|
+
this.raw = new esm.VF({
|
|
984
|
+
environment: entry.environment,
|
|
985
|
+
timeoutInSeconds: this.timeoutInSeconds ?? 60,
|
|
986
|
+
maxRetries: 0,
|
|
987
|
+
headers: entry.headers
|
|
988
|
+
});
|
|
989
|
+
this.rawGeneration = entry.generation;
|
|
990
|
+
return this.raw;
|
|
991
|
+
}
|
|
992
|
+
async getInfo(options) {
|
|
993
|
+
const abortSignal = options?.abortSignal;
|
|
994
|
+
const invoke = async ()=>{
|
|
995
|
+
await this.ensureInstance({
|
|
996
|
+
abortSignal
|
|
997
|
+
});
|
|
998
|
+
const sandboxId = this.entry.sandboxId;
|
|
999
|
+
if (!sandboxId) throw sandboxUnavailableError("sandbox.getInfo");
|
|
1000
|
+
const generation = this.entry.generation;
|
|
1001
|
+
try {
|
|
1002
|
+
const info = await this.api.getInstance({
|
|
1003
|
+
projectId: this.projectId,
|
|
1004
|
+
conversationId: this.conversationId ?? "",
|
|
1005
|
+
sandboxId,
|
|
1006
|
+
signal: abortSignal
|
|
1007
|
+
});
|
|
1008
|
+
if (!info.sandboxId) throw new src_error.YA("The sandbox was not found.");
|
|
1009
|
+
if (info.sandboxId !== sandboxId) throw new src_error.ES("Sandbox instance query returned a different instance.");
|
|
1010
|
+
if ("Failed" === info.status || "Terminating" === info.status) throw new src_error.YA("The sandbox is not available.");
|
|
1011
|
+
if (this.entry.generation === generation && this.entry.sandboxId === sandboxId && info.sandboxId === sandboxId) this.entry.instanceExpireAt = parseExpireAtMs(info.expireAt);
|
|
1012
|
+
return info;
|
|
1013
|
+
} catch (err) {
|
|
1014
|
+
throw normalizeLifecycleError(err, "getInfo");
|
|
1015
|
+
}
|
|
1016
|
+
};
|
|
1017
|
+
return this.managementCallWithRecreate(invoke, abortSignal);
|
|
1018
|
+
}
|
|
1019
|
+
async extendTimeout(timeoutInMinutes, options) {
|
|
1020
|
+
const abortSignal = options?.abortSignal;
|
|
1021
|
+
const invoke = async ()=>{
|
|
1022
|
+
await this.ensureInstance({
|
|
1023
|
+
skipAutoExtend: true,
|
|
1024
|
+
abortSignal
|
|
1025
|
+
});
|
|
1026
|
+
const sandboxId = this.entry.sandboxId;
|
|
1027
|
+
if (!sandboxId) throw sandboxUnavailableError("sandbox.extendTimeout");
|
|
1028
|
+
const generation = this.entry.generation;
|
|
1029
|
+
try {
|
|
1030
|
+
const updated = await this.api.updateInstanceTimeout({
|
|
1031
|
+
projectId: this.projectId,
|
|
1032
|
+
conversationId: this.conversationId ?? "",
|
|
1033
|
+
sandboxId,
|
|
1034
|
+
timeoutInMinutes,
|
|
1035
|
+
signal: abortSignal
|
|
1036
|
+
});
|
|
1037
|
+
if (this.entry.generation === generation && this.entry.sandboxId === sandboxId && updated.sandboxId === sandboxId) this.entry.instanceExpireAt = parseExpireAtMs(updated.expireAt);
|
|
1038
|
+
return updated;
|
|
1039
|
+
} catch (err) {
|
|
1040
|
+
throw normalizeLifecycleError(err, "extendTimeout");
|
|
1041
|
+
}
|
|
1042
|
+
};
|
|
1043
|
+
return this.managementCallWithRecreate(invoke, abortSignal);
|
|
1044
|
+
}
|
|
1045
|
+
async managementCallWithRecreate(invoke, abortSignal) {
|
|
1046
|
+
const generation = this.entry.generation;
|
|
1047
|
+
try {
|
|
1048
|
+
return await invoke();
|
|
1049
|
+
} catch (err) {
|
|
1050
|
+
if ("conversation" !== this.mode) throw err;
|
|
1051
|
+
if (!(err instanceof src_error.YA)) throw err;
|
|
1052
|
+
await this.recreateInstance(generation, abortSignal);
|
|
1053
|
+
return invoke();
|
|
1054
|
+
}
|
|
1055
|
+
}
|
|
1056
|
+
async destroy(options) {
|
|
1057
|
+
const abortSignal = options?.abortSignal;
|
|
1058
|
+
throwIfOperationAborted(abortSignal);
|
|
1059
|
+
const entry = this.entry;
|
|
1060
|
+
if (entry.destroyingInflight) return waitForOperation(entry.destroyingInflight, abortSignal);
|
|
1061
|
+
const flight = Promise.resolve().then(async ()=>{
|
|
1062
|
+
await entry.recoveryInflight;
|
|
1063
|
+
await Promise.allSettled([
|
|
1064
|
+
...entry.activeOperations ?? []
|
|
1065
|
+
]);
|
|
1066
|
+
await this.performDestroy();
|
|
1067
|
+
}).finally(()=>{
|
|
1068
|
+
if (entry.destroyingInflight === flight) entry.destroyingInflight = void 0;
|
|
1069
|
+
});
|
|
1070
|
+
entry.destroyingInflight = flight;
|
|
1071
|
+
return waitForOperation(flight, abortSignal);
|
|
1072
|
+
}
|
|
1073
|
+
async performDestroy() {
|
|
1074
|
+
const entry = this.entry;
|
|
1075
|
+
const abortSignal = void 0;
|
|
1076
|
+
if ("conversation" === this.mode && this.conversationId && entry.bindingRepository) {
|
|
1077
|
+
const initialization = entry.inflight;
|
|
1078
|
+
initialization?.controller.abort();
|
|
1079
|
+
if (initialization) await waitForOperation(initialization.result, abortSignal);
|
|
1080
|
+
await this.destroyPersistentBinding(entry.bindingRepository, this.conversationId, abortSignal);
|
|
1081
|
+
entry.generation += 1;
|
|
1082
|
+
this.raw = void 0;
|
|
1083
|
+
this.rawGeneration = -1;
|
|
1084
|
+
entry.inflight = void 0;
|
|
1085
|
+
entry.sandboxId = void 0;
|
|
1086
|
+
entry.apiKey = void 0;
|
|
1087
|
+
entry.environment = void 0;
|
|
1088
|
+
entry.headers = void 0;
|
|
1089
|
+
entry.instanceExpireAt = void 0;
|
|
1090
|
+
entry.bindingGeneration = void 0;
|
|
1091
|
+
entry.extendingInflight = void 0;
|
|
1092
|
+
entry.recreateInflight = void 0;
|
|
1093
|
+
this.submoduleCache.clear();
|
|
1094
|
+
return;
|
|
1095
|
+
}
|
|
1096
|
+
await this.destroyStandalone(entry);
|
|
1097
|
+
}
|
|
1098
|
+
async destroyStandalone(entry, abortSignal) {
|
|
1099
|
+
const sandboxId = entry.sandboxId;
|
|
1100
|
+
const initialization = entry.inflight;
|
|
1101
|
+
initialization?.controller.abort();
|
|
1102
|
+
if (initialization) await waitForOperation(initialization.result, abortSignal);
|
|
1103
|
+
if (sandboxId) try {
|
|
1104
|
+
await entry.api.destroy({
|
|
1105
|
+
projectId: this.projectId,
|
|
1106
|
+
conversationId: this.conversationId ?? "",
|
|
1107
|
+
sandboxId,
|
|
1108
|
+
signal: abortSignal
|
|
1109
|
+
});
|
|
1110
|
+
} catch (err) {
|
|
1111
|
+
let confirmedGone = false;
|
|
1112
|
+
try {
|
|
1113
|
+
await entry.api.confirmInstanceExists({
|
|
1114
|
+
projectId: this.projectId,
|
|
1115
|
+
conversationId: this.conversationId ?? "",
|
|
1116
|
+
sandboxId,
|
|
1117
|
+
signal: abortSignal
|
|
1118
|
+
});
|
|
1119
|
+
} catch (confirmError) {
|
|
1120
|
+
confirmedGone = confirmError instanceof src_error.YA;
|
|
1121
|
+
}
|
|
1122
|
+
if (!confirmedGone) throw normalizeLifecycleError(err, "destroy");
|
|
1123
|
+
}
|
|
1124
|
+
entry.generation += 1;
|
|
1125
|
+
this.raw = void 0;
|
|
1126
|
+
this.rawGeneration = -1;
|
|
1127
|
+
entry.inflight = void 0;
|
|
1128
|
+
entry.sandboxId = void 0;
|
|
1129
|
+
entry.apiKey = void 0;
|
|
1130
|
+
entry.environment = void 0;
|
|
1131
|
+
entry.headers = void 0;
|
|
1132
|
+
entry.instanceExpireAt = void 0;
|
|
1133
|
+
this.submoduleCache.clear();
|
|
1134
|
+
}
|
|
1135
|
+
async destroyPersistentBinding(repository, conversationId, abortSignal) {
|
|
1136
|
+
const leaseToken = (0, external_node_crypto_.randomUUID)();
|
|
1137
|
+
const deadline = Date.now() + 90000;
|
|
1138
|
+
for(;;){
|
|
1139
|
+
throwIfOperationAborted(abortSignal);
|
|
1140
|
+
const binding = await repository.beginDestroy(conversationId, leaseToken, abortSignal);
|
|
1141
|
+
if ("none" === binding.action) return;
|
|
1142
|
+
if ("wait" === binding.action) {
|
|
1143
|
+
if (Date.now() >= deadline) throw new src_error.ES("Sandbox session destruction is still in progress.");
|
|
1144
|
+
const leaseDeadline = Date.parse(binding.leaseExpiresAt);
|
|
1145
|
+
const remaining = Number.isFinite(leaseDeadline) ? Math.max(100, leaseDeadline - Date.now()) : 500;
|
|
1146
|
+
await waitForAbortableDelay(Math.min(500, remaining), abortSignal);
|
|
1147
|
+
continue;
|
|
1148
|
+
}
|
|
1149
|
+
try {
|
|
1150
|
+
await this.api.destroy({
|
|
1151
|
+
projectId: this.projectId,
|
|
1152
|
+
conversationId,
|
|
1153
|
+
sandboxId: binding.sandboxId,
|
|
1154
|
+
signal: abortSignal
|
|
1155
|
+
});
|
|
1156
|
+
} catch (destroyError) {
|
|
1157
|
+
try {
|
|
1158
|
+
await this.api.confirmInstanceExists({
|
|
1159
|
+
projectId: this.projectId,
|
|
1160
|
+
conversationId,
|
|
1161
|
+
sandboxId: binding.sandboxId,
|
|
1162
|
+
signal: abortSignal
|
|
1163
|
+
});
|
|
1164
|
+
await repository.restore(conversationId, binding.generation, leaseToken, abortSignal);
|
|
1165
|
+
} catch (confirmError) {
|
|
1166
|
+
if (confirmError instanceof src_error.YA) return void await repository.finishDestroy(conversationId, binding.generation, leaseToken, abortSignal);
|
|
1167
|
+
}
|
|
1168
|
+
throw normalizeLifecycleError(destroyError, "destroy");
|
|
1169
|
+
}
|
|
1170
|
+
await repository.finishDestroy(conversationId, binding.generation, leaseToken, abortSignal);
|
|
1171
|
+
return;
|
|
1172
|
+
}
|
|
1173
|
+
}
|
|
1174
|
+
constructor(options){
|
|
1175
|
+
this.rawGeneration = -1;
|
|
1176
|
+
this.submoduleCache = new Map();
|
|
1177
|
+
this.projectId = options.projectId;
|
|
1178
|
+
this.timeoutInSeconds = options.timeoutInSeconds;
|
|
1179
|
+
if (isDetachedOptions(options)) {
|
|
1180
|
+
this.mode = "detached";
|
|
1181
|
+
this.conversationId = void 0;
|
|
1182
|
+
this.sandboxId = void 0;
|
|
1183
|
+
this.entry = createStandaloneEntry(options);
|
|
1184
|
+
this.api = this.entry.api;
|
|
1185
|
+
} else if (isAttachOptions(options)) {
|
|
1186
|
+
this.mode = "attach";
|
|
1187
|
+
this.conversationId = void 0;
|
|
1188
|
+
this.sandboxId = options.sandboxId;
|
|
1189
|
+
const entry = createStandaloneEntry(options);
|
|
1190
|
+
entry.sandboxId = options.sandboxId;
|
|
1191
|
+
this.entry = entry;
|
|
1192
|
+
this.api = entry.api;
|
|
1193
|
+
} else {
|
|
1194
|
+
this.mode = "conversation";
|
|
1195
|
+
this.conversationId = options.conversationId;
|
|
1196
|
+
this.sandboxId = void 0;
|
|
1197
|
+
const cacheKey = JSON.stringify([
|
|
1198
|
+
options.projectId,
|
|
1199
|
+
options.conversationId
|
|
1200
|
+
]);
|
|
1201
|
+
let entry = cache.get(cacheKey);
|
|
1202
|
+
if (!entry) {
|
|
1203
|
+
const api = options.api ?? (0, api_client.SW)({
|
|
1204
|
+
apiBaseUrl: options.apiBaseUrl,
|
|
1205
|
+
apiToken: options.apiToken
|
|
1206
|
+
});
|
|
1207
|
+
entry = {
|
|
1208
|
+
api,
|
|
1209
|
+
bindingRepository: options.bindingRepository,
|
|
1210
|
+
generation: 0
|
|
1211
|
+
};
|
|
1212
|
+
cache.set(cacheKey, entry);
|
|
1213
|
+
}
|
|
1214
|
+
this.entry = entry;
|
|
1215
|
+
this.api = entry.api;
|
|
1216
|
+
}
|
|
1217
|
+
this.installLazyGetters();
|
|
1218
|
+
}
|
|
1219
|
+
}
|
|
1220
|
+
const PUBLIC_SANDBOX_KEYS = [
|
|
1221
|
+
"conversationId",
|
|
1222
|
+
"sandboxId",
|
|
1223
|
+
"getClient",
|
|
1224
|
+
"ensureReady",
|
|
1225
|
+
"getInfo",
|
|
1226
|
+
"extendTimeout",
|
|
1227
|
+
"destroy"
|
|
1228
|
+
];
|
|
1229
|
+
function createSandboxProxy(target) {
|
|
1230
|
+
const publicKeys = new Set([
|
|
1231
|
+
...CLIENT_SUBMODULE_KEYS,
|
|
1232
|
+
...PUBLIC_SANDBOX_KEYS
|
|
1233
|
+
]);
|
|
1234
|
+
return new Proxy(target, {
|
|
1235
|
+
get (current, property) {
|
|
1236
|
+
if ("symbol" != typeof property && !publicKeys.has(property)) return;
|
|
1237
|
+
const value = Reflect.get(current, property, current);
|
|
1238
|
+
return "function" == typeof value ? value.bind(current) : value;
|
|
1239
|
+
},
|
|
1240
|
+
has (_current, property) {
|
|
1241
|
+
return publicKeys.has(property);
|
|
1242
|
+
},
|
|
1243
|
+
ownKeys (current) {
|
|
1244
|
+
return Reflect.ownKeys(current).filter((property)=>publicKeys.has(property));
|
|
1245
|
+
},
|
|
1246
|
+
getOwnPropertyDescriptor (current, property) {
|
|
1247
|
+
if (!publicKeys.has(property)) return;
|
|
1248
|
+
return Reflect.getOwnPropertyDescriptor(current, property);
|
|
1249
|
+
},
|
|
1250
|
+
set () {
|
|
1251
|
+
return false;
|
|
1252
|
+
},
|
|
1253
|
+
defineProperty () {
|
|
1254
|
+
return false;
|
|
1255
|
+
},
|
|
1256
|
+
deleteProperty () {
|
|
1257
|
+
return false;
|
|
1258
|
+
},
|
|
1259
|
+
preventExtensions () {
|
|
1260
|
+
return false;
|
|
1261
|
+
}
|
|
1262
|
+
});
|
|
1263
|
+
}
|
|
1264
|
+
function createSandbox(options) {
|
|
1265
|
+
return createSandboxProxy(new IgaSandbox(options));
|
|
1266
|
+
}
|
|
1267
|
+
function createDetachedSandbox(options) {
|
|
1268
|
+
return createSandboxProxy(new IgaSandbox({
|
|
1269
|
+
...options,
|
|
1270
|
+
mode: "detached"
|
|
1271
|
+
}));
|
|
1272
|
+
}
|
|
1273
|
+
function attachSandbox(options) {
|
|
1274
|
+
return createSandboxProxy(new IgaSandbox({
|
|
1275
|
+
...options,
|
|
1276
|
+
mode: "attach"
|
|
1277
|
+
}));
|
|
1278
|
+
}
|
|
1279
|
+
function createStandaloneEntry(options) {
|
|
1280
|
+
const api = options.api ?? (0, api_client.SW)({
|
|
1281
|
+
apiBaseUrl: options.apiBaseUrl,
|
|
1282
|
+
apiToken: options.apiToken
|
|
1283
|
+
});
|
|
1284
|
+
return {
|
|
1285
|
+
api,
|
|
1286
|
+
generation: 0
|
|
1287
|
+
};
|
|
1288
|
+
}
|
|
1289
|
+
function requestAbortSignal(args) {
|
|
1290
|
+
const last = args.at(-1);
|
|
1291
|
+
if (!last || "object" != typeof last) return;
|
|
1292
|
+
const signal = last.abortSignal;
|
|
1293
|
+
return isAbortSignal(signal) ? signal : void 0;
|
|
1294
|
+
}
|
|
1295
|
+
function isAbortSignal(value) {
|
|
1296
|
+
return Boolean(value && "object" == typeof value && "boolean" == typeof value.aborted && "function" == typeof value.addEventListener && "function" == typeof value.removeEventListener);
|
|
1297
|
+
}
|
|
1298
|
+
function throwIfOperationAborted(signal) {
|
|
1299
|
+
if (!signal?.aborted) return;
|
|
1300
|
+
throw new src_error.sX("The sandbox operation was cancelled.");
|
|
1301
|
+
}
|
|
1302
|
+
function waitForOperation(promise, signal) {
|
|
1303
|
+
if (!signal) return promise;
|
|
1304
|
+
throwIfOperationAborted(signal);
|
|
1305
|
+
return new Promise((resolve, reject)=>{
|
|
1306
|
+
const cleanup = ()=>signal.removeEventListener("abort", onAbort);
|
|
1307
|
+
const onAbort = ()=>{
|
|
1308
|
+
cleanup();
|
|
1309
|
+
reject(new src_error.sX("The sandbox operation was cancelled."));
|
|
1310
|
+
};
|
|
1311
|
+
signal.addEventListener("abort", onAbort, {
|
|
1312
|
+
once: true
|
|
1313
|
+
});
|
|
1314
|
+
promise.then((value)=>{
|
|
1315
|
+
cleanup();
|
|
1316
|
+
resolve(value);
|
|
1317
|
+
}, (error)=>{
|
|
1318
|
+
cleanup();
|
|
1319
|
+
reject(error);
|
|
1320
|
+
});
|
|
1321
|
+
});
|
|
1322
|
+
}
|
|
1323
|
+
function waitForDelay(delayMs, signal) {
|
|
1324
|
+
if (signal.aborted) return Promise.reject(new src_error.sX("Sandbox initialization was cancelled."));
|
|
1325
|
+
return new Promise((resolve, reject)=>{
|
|
1326
|
+
const timer = setTimeout(()=>{
|
|
1327
|
+
signal.removeEventListener("abort", onAbort);
|
|
1328
|
+
resolve();
|
|
1329
|
+
}, delayMs);
|
|
1330
|
+
const onAbort = ()=>{
|
|
1331
|
+
clearTimeout(timer);
|
|
1332
|
+
reject(new src_error.sX("Sandbox initialization was cancelled."));
|
|
1333
|
+
};
|
|
1334
|
+
signal.addEventListener("abort", onAbort, {
|
|
1335
|
+
once: true
|
|
1336
|
+
});
|
|
1337
|
+
});
|
|
1338
|
+
}
|
|
1339
|
+
function waitForAbortableDelay(delayMs, signal) {
|
|
1340
|
+
if (!signal) return new Promise((resolve)=>setTimeout(resolve, delayMs));
|
|
1341
|
+
return waitForDelay(delayMs, signal);
|
|
1342
|
+
}
|
|
1343
|
+
function isUnavailableInstance(info) {
|
|
1344
|
+
return !info.sandboxId || "Failed" === info.status || "Terminating" === info.status;
|
|
1345
|
+
}
|
|
1346
|
+
function assertInitializationCurrent(entry, generation, signal) {
|
|
1347
|
+
if (!signal.aborted && entry.generation === generation) return;
|
|
1348
|
+
throw new src_error.sX("Sandbox initialization was cancelled.");
|
|
1349
|
+
}
|
|
1350
|
+
async function bestEffortDestroy(entry, opts) {
|
|
1351
|
+
try {
|
|
1352
|
+
await entry.api.destroy(opts);
|
|
1353
|
+
} catch {}
|
|
1354
|
+
}
|
|
1355
|
+
function isEntryReady(entry) {
|
|
1356
|
+
return Boolean(entry.sandboxId && entry.apiKey && entry.environment && entry.headers);
|
|
1357
|
+
}
|
|
1358
|
+
function normalizeLifecycleError(err, _phase) {
|
|
1359
|
+
if (err instanceof src_error.ES) return err;
|
|
1360
|
+
if ((0, src_error.zf)(err)) return new src_error.sX("The sandbox operation was cancelled.");
|
|
1361
|
+
return new src_error.ES("The sandbox service is temporarily unavailable.");
|
|
1362
|
+
}
|
|
1363
|
+
function sandboxUnavailableError(_operation) {
|
|
1364
|
+
return new src_error.ES("The sandbox is temporarily unavailable.");
|
|
1365
|
+
}
|
|
1366
|
+
}
|
|
1367
|
+
};
|