@agents24/node 0.4.0 → 0.5.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 +26 -2
- package/compatibility.json +6 -6
- package/dist/bff.cjs +468 -51
- package/dist/bff.cjs.map +1 -1
- package/dist/bff.d.cts +23 -4
- package/dist/bff.d.ts +23 -4
- package/dist/bff.js +468 -51
- package/dist/bff.js.map +1 -1
- package/dist/{client-C5ui84wi.d.cts → client-xWr_OGEe.d.cts} +285 -86
- package/dist/{client-C5ui84wi.d.ts → client-xWr_OGEe.d.ts} +285 -86
- package/dist/index.cjs +177 -65
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +177 -65
- package/dist/index.js.map +1 -1
- package/dist/types/bff-agent-resolution.d.ts +41 -0
- package/dist/types/bff-agent-resolution.d.ts.map +1 -0
- package/dist/types/bff-errors.d.ts +3 -0
- package/dist/types/bff-errors.d.ts.map +1 -0
- package/dist/types/bff.d.ts +6 -20
- package/dist/types/bff.d.ts.map +1 -1
- package/dist/types/client.d.ts +2 -2
- package/dist/types/client.d.ts.map +1 -1
- package/dist/types/embed.d.ts +7 -1
- package/dist/types/embed.d.ts.map +1 -1
- package/dist/types/generated/customerProfiles.d.ts +11 -0
- package/dist/types/generated/customerProfiles.d.ts.map +1 -0
- package/dist/types/generated/manifest.d.ts +1 -1
- package/dist/types/generated/manifest.d.ts.map +1 -1
- package/dist/types/generated/resourceInstallations.d.ts +6 -2
- package/dist/types/generated/resourceInstallations.d.ts.map +1 -1
- package/dist/types/generated/resourcePackages.d.ts +7 -3
- package/dist/types/generated/resourcePackages.d.ts.map +1 -1
- package/dist/types/generated/resourcePolicies.d.ts +3 -3
- package/dist/types/generated/resourcePolicies.d.ts.map +1 -1
- package/dist/types/types.d.ts +255 -69
- package/dist/types/types.d.ts.map +1 -1
- package/package.json +2 -2
- package/dist/types/generated/resourceBundles.d.ts +0 -12
- package/dist/types/generated/resourceBundles.d.ts.map +0 -1
package/dist/bff.cjs
CHANGED
|
@@ -2,7 +2,46 @@
|
|
|
2
2
|
|
|
3
3
|
var crypto = require('crypto');
|
|
4
4
|
|
|
5
|
-
// src/bff.ts
|
|
5
|
+
// src/bff-agent-resolution.ts
|
|
6
|
+
function clean(value) {
|
|
7
|
+
const result = typeof value === "string" ? value.trim() : "";
|
|
8
|
+
return result || void 0;
|
|
9
|
+
}
|
|
10
|
+
function required(value, field) {
|
|
11
|
+
const result = clean(value);
|
|
12
|
+
if (!result || /[\r\n\0]/.test(result)) throw new Error(`${field} is required.`);
|
|
13
|
+
return result;
|
|
14
|
+
}
|
|
15
|
+
function prepareAgents24BffAgentResolution(options) {
|
|
16
|
+
if (!options.agents.length || options.agents.length > 50) {
|
|
17
|
+
throw new Error("agents must contain between one and 50 Agents.");
|
|
18
|
+
}
|
|
19
|
+
const configured = options.agents.map((item) => {
|
|
20
|
+
const agentId = clean(item.agentId);
|
|
21
|
+
const agentAlias = clean(item.agentAlias);
|
|
22
|
+
if (Boolean(agentId) === Boolean(agentAlias)) {
|
|
23
|
+
throw new Error("Each Agent requires exactly one of agentId or agentAlias.");
|
|
24
|
+
}
|
|
25
|
+
return { agentId, agentAlias, agentVersionId: clean(item.agentVersionId) };
|
|
26
|
+
});
|
|
27
|
+
return async () => {
|
|
28
|
+
const agents = await Promise.all(configured.map(async (item) => {
|
|
29
|
+
if (item.agentAlias) {
|
|
30
|
+
const resolution = await options.client.embed.resolveAgentAlias(item.agentAlias);
|
|
31
|
+
return {
|
|
32
|
+
agentId: required(resolution.agent_id, "agentId"),
|
|
33
|
+
agentAlias: required(item.agentAlias, "agentAlias"),
|
|
34
|
+
agentVersionId: item.agentVersionId
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
return { agentId: required(item.agentId, "agentId"), agentVersionId: item.agentVersionId };
|
|
38
|
+
}));
|
|
39
|
+
if (new Set(agents.map((item) => item.agentId)).size !== agents.length) {
|
|
40
|
+
throw new Error("Configured Agent selectors must resolve to unique Agents.");
|
|
41
|
+
}
|
|
42
|
+
return agents;
|
|
43
|
+
};
|
|
44
|
+
}
|
|
6
45
|
|
|
7
46
|
// src/errors.ts
|
|
8
47
|
var Agents24SDKError = class extends Error {
|
|
@@ -41,29 +80,7 @@ var Agents24SDKError = class extends Error {
|
|
|
41
80
|
}
|
|
42
81
|
};
|
|
43
82
|
|
|
44
|
-
// src/bff.ts
|
|
45
|
-
var JSON_LIMIT_BYTES = 1048576;
|
|
46
|
-
function normalized(value, field) {
|
|
47
|
-
const result = String(value || "").trim();
|
|
48
|
-
if (!result || /[\r\n\0]/.test(result)) throw new Error(`${field} is required.`);
|
|
49
|
-
return result;
|
|
50
|
-
}
|
|
51
|
-
function normalizeBasePath(value) {
|
|
52
|
-
const path = String(value || "/api/agents24").trim().replace(/\/+$/, "");
|
|
53
|
-
if (!path.startsWith("/") || /[\r\n\0?#]/.test(path)) throw new Error("basePath must be an absolute path.");
|
|
54
|
-
return path;
|
|
55
|
-
}
|
|
56
|
-
function browserRequestIsSameOrigin(request) {
|
|
57
|
-
const fetchSite = String(request.headers.get("sec-fetch-site") || "").trim().toLowerCase();
|
|
58
|
-
if (fetchSite) return fetchSite === "same-origin";
|
|
59
|
-
const rawOrigin = String(request.headers.get("origin") || "").trim();
|
|
60
|
-
if (!rawOrigin) return true;
|
|
61
|
-
try {
|
|
62
|
-
return rawOrigin !== "null" && new URL(rawOrigin).origin === new URL(request.url).origin;
|
|
63
|
-
} catch {
|
|
64
|
-
return false;
|
|
65
|
-
}
|
|
66
|
-
}
|
|
83
|
+
// src/bff-errors.ts
|
|
67
84
|
function publicError(status, code, message, retryable = false, violations) {
|
|
68
85
|
const category = status === 401 ? "authentication" : status === 403 ? "authorization" : status === 404 ? "not_found" : status === 409 ? "conflict" : status === 429 ? "rate_limit" : status >= 500 ? "internal" : "validation";
|
|
69
86
|
return Response.json({
|
|
@@ -142,13 +159,79 @@ function errorResponse(error) {
|
|
|
142
159
|
const sdkError = error;
|
|
143
160
|
const status = sdkError.status && sdkError.status >= 400 && sdkError.status <= 599 ? sdkError.status : 502;
|
|
144
161
|
const policyError = safeResourcePolicyError(sdkError.failure);
|
|
145
|
-
if (policyError)
|
|
146
|
-
return resourcePolicyFailureResponse(status, policyError);
|
|
147
|
-
}
|
|
162
|
+
if (policyError) return resourcePolicyFailureResponse(status, policyError);
|
|
148
163
|
return publicError(status, `UPSTREAM_${status}`, "The Agent request failed.", status >= 500);
|
|
149
164
|
}
|
|
150
165
|
return publicError(500, "BFF_REQUEST_FAILED", "The Agent request could not be completed.", true);
|
|
151
166
|
}
|
|
167
|
+
|
|
168
|
+
// src/bff.ts
|
|
169
|
+
var JSON_LIMIT_BYTES = 1048576;
|
|
170
|
+
var MAX_INPUT_LENGTH = 2e5;
|
|
171
|
+
var MAX_ATTACHMENTS = 10;
|
|
172
|
+
var MAX_ATTACHMENT_BYTES = 25 * 1024 * 1024;
|
|
173
|
+
var HITL_ACTIONS = /* @__PURE__ */ new Set(["approve", "reject", "connect", "skip", "respond"]);
|
|
174
|
+
var CUSTOMER_IDENTITY_CACHE_TTL_MS = 6e4;
|
|
175
|
+
var CUSTOMER_IDENTITY_CACHE_MAX_ENTRIES = 1024;
|
|
176
|
+
function createCustomerIdentityResolver(embed, integrationId, integrationName) {
|
|
177
|
+
const cache = /* @__PURE__ */ new Map();
|
|
178
|
+
return async (principal) => {
|
|
179
|
+
const profile = {
|
|
180
|
+
display_name: principal.displayName,
|
|
181
|
+
email: principal.email,
|
|
182
|
+
avatar_url: principal.avatarUrl
|
|
183
|
+
};
|
|
184
|
+
const profileFields = Object.fromEntries(Object.entries(profile).filter(([, value2]) => value2 !== void 0));
|
|
185
|
+
const key = JSON.stringify([integrationId, principal.issuer, principal.subject, profileFields]);
|
|
186
|
+
const now = Date.now();
|
|
187
|
+
const cached = cache.get(key);
|
|
188
|
+
if (cached && cached.expiresAt > now) {
|
|
189
|
+
cache.delete(key);
|
|
190
|
+
cache.set(key, cached);
|
|
191
|
+
return cached.value;
|
|
192
|
+
}
|
|
193
|
+
if (cached) cache.delete(key);
|
|
194
|
+
const value = embed.resolveCustomerPrincipal({
|
|
195
|
+
integration_id: integrationId,
|
|
196
|
+
...integrationName ? { integration_name: integrationName } : {},
|
|
197
|
+
...principal.issuer ? { issuer: principal.issuer } : {},
|
|
198
|
+
subject: principal.subject,
|
|
199
|
+
...Object.keys(profileFields).length ? { profile: profileFields } : {}
|
|
200
|
+
}).then((result) => normalized(result.customer_principal_ref, "customer_principal_ref"));
|
|
201
|
+
const entry = { expiresAt: now + CUSTOMER_IDENTITY_CACHE_TTL_MS, value };
|
|
202
|
+
cache.set(key, entry);
|
|
203
|
+
while (cache.size > CUSTOMER_IDENTITY_CACHE_MAX_ENTRIES) {
|
|
204
|
+
const oldest = cache.keys().next().value;
|
|
205
|
+
if (oldest === void 0) break;
|
|
206
|
+
cache.delete(oldest);
|
|
207
|
+
}
|
|
208
|
+
void value.catch(() => {
|
|
209
|
+
if (cache.get(key) === entry) cache.delete(key);
|
|
210
|
+
});
|
|
211
|
+
return value;
|
|
212
|
+
};
|
|
213
|
+
}
|
|
214
|
+
function normalized(value, field) {
|
|
215
|
+
const result = String(value || "").trim();
|
|
216
|
+
if (!result || /[\r\n\0]/.test(result)) throw new Error(`${field} is required.`);
|
|
217
|
+
return result;
|
|
218
|
+
}
|
|
219
|
+
function normalizeBasePath(value) {
|
|
220
|
+
const path = String(value || "/api/agents24").trim().replace(/\/+$/, "");
|
|
221
|
+
if (!path.startsWith("/") || /[\r\n\0?#]/.test(path)) throw new Error("basePath must be an absolute path.");
|
|
222
|
+
return path;
|
|
223
|
+
}
|
|
224
|
+
function browserRequestIsSameOrigin(request) {
|
|
225
|
+
const fetchSite = String(request.headers.get("sec-fetch-site") || "").trim().toLowerCase();
|
|
226
|
+
if (fetchSite) return fetchSite === "same-origin";
|
|
227
|
+
const rawOrigin = String(request.headers.get("origin") || "").trim();
|
|
228
|
+
if (!rawOrigin) return true;
|
|
229
|
+
try {
|
|
230
|
+
return rawOrigin !== "null" && new URL(rawOrigin).origin === new URL(request.url).origin;
|
|
231
|
+
} catch {
|
|
232
|
+
return false;
|
|
233
|
+
}
|
|
234
|
+
}
|
|
152
235
|
function mergeHeaders(response, additional) {
|
|
153
236
|
if (!additional) return response;
|
|
154
237
|
const headers = new Headers(response.headers);
|
|
@@ -206,7 +289,7 @@ function sseHeaders(headers) {
|
|
|
206
289
|
result.set("X-Accel-Buffering", "no");
|
|
207
290
|
return result;
|
|
208
291
|
}
|
|
209
|
-
function sseResponse(execute, headers) {
|
|
292
|
+
function sseResponse(execute, headers, failurePayload) {
|
|
210
293
|
const stream = new TransformStream();
|
|
211
294
|
const writer = stream.writable.getWriter();
|
|
212
295
|
const encoder = new TextEncoder();
|
|
@@ -214,6 +297,10 @@ function sseResponse(execute, headers) {
|
|
|
214
297
|
|
|
215
298
|
`));
|
|
216
299
|
void execute(write).catch(async (error) => {
|
|
300
|
+
if (failurePayload) {
|
|
301
|
+
await write(failurePayload(error)).catch(() => void 0);
|
|
302
|
+
return;
|
|
303
|
+
}
|
|
217
304
|
const message = "The Agent stream failed.";
|
|
218
305
|
const event = {
|
|
219
306
|
version: "run-stream.v3",
|
|
@@ -237,7 +324,7 @@ function bootstrapDocument(raw, agentVersionId) {
|
|
|
237
324
|
version: String(raw.version || "agents24.embed.bootstrap.v1"),
|
|
238
325
|
deployment: {
|
|
239
326
|
id: "server-embed",
|
|
240
|
-
name: String(raw.agent_name || "
|
|
327
|
+
name: normalized(String(raw.agent_name || ""), "agent_name"),
|
|
241
328
|
version_policy: agentVersionId ? { mode: "pinned", version_id: agentVersionId } : { mode: "latest_published" },
|
|
242
329
|
resolved_agent_version_id: resolvedVersionId,
|
|
243
330
|
resolved_agent_version_number: Number.isFinite(versionNumber) ? versionNumber : 0,
|
|
@@ -249,10 +336,11 @@ function bootstrapDocument(raw, agentVersionId) {
|
|
|
249
336
|
native_profiles: []
|
|
250
337
|
};
|
|
251
338
|
}
|
|
252
|
-
function
|
|
339
|
+
function createAgents24BffHandlerWithResolver(options, resolveCustomerIdentity) {
|
|
253
340
|
const agentId = normalized(options.agentId, "agentId");
|
|
254
341
|
const agentVersionId = stringValue(options.agentVersionId);
|
|
255
342
|
const runtimeTarget = options.runtimeTarget || "published";
|
|
343
|
+
const integrationId = normalized(options.integrationId, "integrationId");
|
|
256
344
|
if (runtimeTarget === "draft" && agentVersionId) throw new Error("agentVersionId cannot be used with draft runtimeTarget.");
|
|
257
345
|
const basePath = normalizeBasePath(options.basePath);
|
|
258
346
|
const embed = options.client.embed;
|
|
@@ -278,16 +366,7 @@ function createAgents24BffHandler(options) {
|
|
|
278
366
|
const principal = resolution.principal;
|
|
279
367
|
const idempotencyKey = stringValue(request.headers.get("idempotency-key"));
|
|
280
368
|
try {
|
|
281
|
-
|
|
282
|
-
if (!(request.method === "GET" && (path === "/bootstrap" || path === "/resource-policy"))) {
|
|
283
|
-
const entitlement = await embed.getResourcePolicy(agentId, {
|
|
284
|
-
external_user_id: principal.subject,
|
|
285
|
-
...principal.issuer ? { external_user_issuer: principal.issuer } : {},
|
|
286
|
-
...agentVersionId ? { agent_version_id: agentVersionId } : {},
|
|
287
|
-
runtime_target: runtimeTarget
|
|
288
|
-
});
|
|
289
|
-
customerPrincipalRef = stringValue(entitlement.customer_principal_ref) || principal.subject;
|
|
290
|
-
}
|
|
369
|
+
const customerPrincipalRef = await resolveCustomerIdentity(principal);
|
|
291
370
|
const identity = {
|
|
292
371
|
external_user_id: customerPrincipalRef,
|
|
293
372
|
...principal.externalSessionId ? { external_session_id: principal.externalSessionId } : {}
|
|
@@ -303,8 +382,8 @@ function createAgents24BffHandler(options) {
|
|
|
303
382
|
response = json(bootstrapDocument(raw, agentVersionId));
|
|
304
383
|
} else if (request.method === "GET" && path === "/resource-policy") {
|
|
305
384
|
response = json(await embed.getResourcePolicy(agentId, {
|
|
306
|
-
external_user_id:
|
|
307
|
-
|
|
385
|
+
external_user_id: customerPrincipalRef,
|
|
386
|
+
integration_id: integrationId,
|
|
308
387
|
...agentVersionId ? { agent_version_id: agentVersionId } : {},
|
|
309
388
|
runtime_target: runtimeTarget
|
|
310
389
|
}));
|
|
@@ -313,9 +392,16 @@ function createAgents24BffHandler(options) {
|
|
|
313
392
|
const input = stringValue(body.input);
|
|
314
393
|
const attachmentIds = stringList(body.attachmentIds);
|
|
315
394
|
if (!input && attachmentIds.length === 0) throw new BffInputError(400, "INPUT_REQUIRED", "A message or attachment is required.");
|
|
395
|
+
if (input && input.length > MAX_INPUT_LENGTH) {
|
|
396
|
+
throw new BffInputError(413, "INPUT_TOO_LARGE", "The message is too large.");
|
|
397
|
+
}
|
|
398
|
+
if (attachmentIds.length > MAX_ATTACHMENTS) {
|
|
399
|
+
throw new BffInputError(400, "TOO_MANY_ATTACHMENTS", `At most ${MAX_ATTACHMENTS} attachments are allowed.`);
|
|
400
|
+
}
|
|
316
401
|
response = sseResponse(async (write) => {
|
|
317
402
|
await embed.streamAgent(agentId, {
|
|
318
403
|
...identity,
|
|
404
|
+
integration_id: integrationId,
|
|
319
405
|
...agentVersionId ? { agent_version_id: agentVersionId } : {},
|
|
320
406
|
runtime_target: runtimeTarget,
|
|
321
407
|
...input ? { input } : {},
|
|
@@ -338,6 +424,7 @@ function createAgents24BffHandler(options) {
|
|
|
338
424
|
await embed.attachAgentRun(agentId, runId, {
|
|
339
425
|
...identity,
|
|
340
426
|
runtime_target: runtimeTarget,
|
|
427
|
+
integration_id: integrationId,
|
|
341
428
|
...cursor === void 0 ? {} : { cursor: Number(cursor) }
|
|
342
429
|
}, (event) => write(event), {
|
|
343
430
|
idempotencyKey,
|
|
@@ -346,7 +433,10 @@ function createAgents24BffHandler(options) {
|
|
|
346
433
|
});
|
|
347
434
|
} else if (request.method === "POST" && /^\/runs\/[^/]+\/cancel$/.test(path)) {
|
|
348
435
|
const runId = routeId(path, /^\/runs\/([^/]+)\/cancel$/, "runId");
|
|
349
|
-
response = json(await embed.cancelAgentRun(agentId, runId,
|
|
436
|
+
response = json(await embed.cancelAgentRun(agentId, runId, {
|
|
437
|
+
...threadIdentity,
|
|
438
|
+
integrationId
|
|
439
|
+
}, { idempotencyKey }));
|
|
350
440
|
} else if (request.method === "PUT" && /^\/runs\/[^/]+\/feedback$/.test(path)) {
|
|
351
441
|
const runId = routeId(path, /^\/runs\/([^/]+)\/feedback$/, "runId");
|
|
352
442
|
const body = await requestJson(request);
|
|
@@ -366,6 +456,7 @@ function createAgents24BffHandler(options) {
|
|
|
366
456
|
response = json(await embed.setAgentRunFeedback(agentId, runId, {
|
|
367
457
|
...identity,
|
|
368
458
|
runtime_target: runtimeTarget,
|
|
459
|
+
integration_id: integrationId,
|
|
369
460
|
rating,
|
|
370
461
|
...rating === "dislike" && reason ? { reason } : {},
|
|
371
462
|
...rating === "dislike" && comment ? { comment } : {}
|
|
@@ -373,44 +464,71 @@ function createAgents24BffHandler(options) {
|
|
|
373
464
|
} else if (request.method === "GET" && path === "/threads") {
|
|
374
465
|
const skip = Number(url.searchParams.get("skip") || 0);
|
|
375
466
|
const limit = Number(url.searchParams.get("limit") || 20);
|
|
467
|
+
if (!Number.isInteger(skip) || skip < 0 || !Number.isInteger(limit) || limit < 1 || limit > 100) {
|
|
468
|
+
throw new BffInputError(400, "INVALID_PAGINATION", "skip must be non-negative and limit must be between 1 and 100.");
|
|
469
|
+
}
|
|
376
470
|
response = json(await embed.listAgentThreads(agentId, {
|
|
377
471
|
...threadIdentity,
|
|
472
|
+
integrationId,
|
|
378
473
|
runtimeTarget,
|
|
379
|
-
skip
|
|
380
|
-
limit
|
|
474
|
+
skip,
|
|
475
|
+
limit
|
|
381
476
|
}));
|
|
382
477
|
} else if (request.method === "GET" && path === "/threads/events") {
|
|
383
478
|
const rawCursor = url.searchParams.get("cursor");
|
|
384
479
|
const cursor = rawCursor === null ? void 0 : Number(rawCursor);
|
|
480
|
+
if (cursor !== void 0 && (!Number.isInteger(cursor) || cursor < 0)) {
|
|
481
|
+
throw new BffInputError(400, "INVALID_CURSOR", "cursor must be a non-negative integer.");
|
|
482
|
+
}
|
|
385
483
|
response = sseResponse(async (write) => {
|
|
386
484
|
await embed.subscribeAgentThreadEvents(agentId, {
|
|
387
485
|
...threadIdentity,
|
|
388
|
-
|
|
486
|
+
integrationId,
|
|
487
|
+
...cursor !== void 0 ? { cursor } : {},
|
|
389
488
|
signal: request.signal
|
|
390
489
|
}, (event) => write(event));
|
|
391
|
-
})
|
|
490
|
+
}, void 0, () => ({
|
|
491
|
+
schema_version: "agents24.thread_summary_event.v1",
|
|
492
|
+
event: "snapshot_required",
|
|
493
|
+
cursor,
|
|
494
|
+
reason: "stream_failed"
|
|
495
|
+
}));
|
|
392
496
|
} else if (/^\/threads\/[^/]+$/.test(path) && request.method === "GET") {
|
|
393
497
|
const threadId = routeId(path, /^\/threads\/([^/]+)$/, "threadId");
|
|
394
498
|
const rawBefore = url.searchParams.get("before_turn_index");
|
|
395
499
|
const rawLimit = url.searchParams.get("limit");
|
|
396
500
|
const before = rawBefore === null ? void 0 : Number(rawBefore);
|
|
397
501
|
const limit = rawLimit === null ? void 0 : Number(rawLimit);
|
|
502
|
+
if (before !== void 0 && (!Number.isInteger(before) || before < 0)) {
|
|
503
|
+
throw new BffInputError(400, "INVALID_PAGINATION", "before_turn_index is invalid.");
|
|
504
|
+
}
|
|
505
|
+
if (limit !== void 0 && (!Number.isInteger(limit) || limit < 1 || limit > 100)) {
|
|
506
|
+
throw new BffInputError(400, "INVALID_PAGINATION", "limit must be between 1 and 100.");
|
|
507
|
+
}
|
|
398
508
|
response = json(await embed.getAgentThread(agentId, threadId, {
|
|
399
509
|
...threadIdentity,
|
|
400
|
-
|
|
401
|
-
...
|
|
510
|
+
integrationId,
|
|
511
|
+
...before !== void 0 ? { beforeTurnIndex: before } : {},
|
|
512
|
+
...limit !== void 0 ? { limit } : {}
|
|
402
513
|
}));
|
|
403
514
|
} else if (/^\/threads\/[^/]+$/.test(path) && request.method === "DELETE") {
|
|
404
515
|
const threadId = routeId(path, /^\/threads\/([^/]+)$/, "threadId");
|
|
405
|
-
response = json(await embed.deleteAgentThread(agentId, threadId, threadIdentity, { idempotencyKey }));
|
|
516
|
+
response = json(await embed.deleteAgentThread(agentId, threadId, { ...threadIdentity, integrationId }, { idempotencyKey }));
|
|
406
517
|
} else if (request.method === "POST" && path === "/attachments/upload") {
|
|
407
518
|
const form = await request.formData();
|
|
408
519
|
const files = form.getAll("files").filter((entry) => entry instanceof File);
|
|
409
520
|
if (files.length === 0) throw new BffInputError(400, "ATTACHMENT_REQUIRED", "At least one attachment is required.");
|
|
521
|
+
if (files.length > MAX_ATTACHMENTS) {
|
|
522
|
+
throw new BffInputError(400, "TOO_MANY_ATTACHMENTS", `At most ${MAX_ATTACHMENTS} attachments are allowed.`);
|
|
523
|
+
}
|
|
524
|
+
if (files.some((file) => file.size > MAX_ATTACHMENT_BYTES)) {
|
|
525
|
+
throw new BffInputError(413, "ATTACHMENT_TOO_LARGE", "An attachment exceeds the allowed size.");
|
|
526
|
+
}
|
|
410
527
|
response = json(await embed.uploadAgentAttachments(agentId, {
|
|
411
528
|
...threadIdentity,
|
|
412
529
|
files,
|
|
413
530
|
...stringValue(form.get("thread_id")) ? { threadId: stringValue(form.get("thread_id")) } : {},
|
|
531
|
+
integrationId,
|
|
414
532
|
idempotencyKey
|
|
415
533
|
}));
|
|
416
534
|
} else if (request.method === "POST" && /^\/attachments\/[^/]+\/content-access$/.test(path)) {
|
|
@@ -424,6 +542,7 @@ function createAgents24BffHandler(options) {
|
|
|
424
542
|
external_user_id: threadIdentity.externalUserId,
|
|
425
543
|
...threadIdentity.externalSessionId ? { external_session_id: threadIdentity.externalSessionId } : {},
|
|
426
544
|
runtime_target: runtimeTarget,
|
|
545
|
+
integration_id: integrationId,
|
|
427
546
|
disposition
|
|
428
547
|
}));
|
|
429
548
|
} else if (request.method === "POST" && /^\/runs\/[^/]+\/hitl\/[^/]+\/resume$/.test(path)) {
|
|
@@ -431,12 +550,17 @@ function createAgents24BffHandler(options) {
|
|
|
431
550
|
const runId = routeId(path, /^\/runs\/([^/]+)\/hitl\//, "runId");
|
|
432
551
|
const interruptId = match?.[2] ? decodeURIComponent(match[2]) : "";
|
|
433
552
|
const body = await requestJson(request);
|
|
553
|
+
const action = stringValue(body.action);
|
|
554
|
+
if (!action || !HITL_ACTIONS.has(action)) {
|
|
555
|
+
throw new BffInputError(400, "INVALID_HITL_ACTION", "The HITL action is invalid.");
|
|
556
|
+
}
|
|
434
557
|
response = json(await embed.resumeAgentRun(agentId, runId, {
|
|
435
558
|
...identity,
|
|
436
559
|
runtime_target: runtimeTarget,
|
|
560
|
+
integration_id: integrationId,
|
|
437
561
|
schema_version: "agents24.hitl.resume.v2",
|
|
438
562
|
interrupt_id: normalized(interruptId, "interruptId"),
|
|
439
|
-
action
|
|
563
|
+
action,
|
|
440
564
|
...stringValue(body.comment) ? { comment: stringValue(body.comment) } : {},
|
|
441
565
|
...Array.isArray(body.answers) ? { answers: body.answers } : {}
|
|
442
566
|
}, { idempotencyKey }));
|
|
@@ -449,6 +573,7 @@ function createAgents24BffHandler(options) {
|
|
|
449
573
|
response = json(await embed.startAgentRunMcpAuth(agentId, normalized(runId, "runId"), normalized(serverId, "serverId"), {
|
|
450
574
|
...identity,
|
|
451
575
|
runtime_target: runtimeTarget,
|
|
576
|
+
integration_id: integrationId,
|
|
452
577
|
interrupt_id: normalized(String(body.interruptId || ""), "interruptId"),
|
|
453
578
|
callback_origin: callbackOrigin,
|
|
454
579
|
popup_nonce: normalized(String(body.popupNonce || ""), "popupNonce")
|
|
@@ -470,6 +595,298 @@ function createAgents24BffHandler(options) {
|
|
|
470
595
|
}
|
|
471
596
|
};
|
|
472
597
|
}
|
|
598
|
+
function createResolvedAgents24BffHandler(options) {
|
|
599
|
+
const runtimeTarget = options.runtimeTarget || "published";
|
|
600
|
+
const basePath = normalizeBasePath(options.basePath);
|
|
601
|
+
const integrationId = normalized(options.integrationId, "integrationId");
|
|
602
|
+
const agents = options.agents.map((item) => ({
|
|
603
|
+
agentId: normalized(item.agentId, "agentId"),
|
|
604
|
+
agentAlias: stringValue(item.agentAlias),
|
|
605
|
+
agentVersionId: stringValue(item.agentVersionId)
|
|
606
|
+
}));
|
|
607
|
+
if (!agents.length || agents.length > 50) throw new Error("agents must contain between one and 50 Agents.");
|
|
608
|
+
if (new Set(agents.map((agent) => agent.agentId)).size !== agents.length) throw new Error("agents must contain unique Agent IDs.");
|
|
609
|
+
if (runtimeTarget === "draft" && agents.some((agent) => agent.agentVersionId)) {
|
|
610
|
+
throw new Error("agentVersionId cannot be used with draft runtimeTarget.");
|
|
611
|
+
}
|
|
612
|
+
const resolveCustomerIdentity = createCustomerIdentityResolver(
|
|
613
|
+
options.client.embed,
|
|
614
|
+
integrationId,
|
|
615
|
+
stringValue(options.integrationName)
|
|
616
|
+
);
|
|
617
|
+
const scopedHandlers = new Map(agents.map((agent) => [
|
|
618
|
+
agent.agentId,
|
|
619
|
+
createAgents24BffHandlerWithResolver({
|
|
620
|
+
client: options.client,
|
|
621
|
+
agentId: agent.agentId,
|
|
622
|
+
agentVersionId: agent.agentVersionId,
|
|
623
|
+
runtimeTarget,
|
|
624
|
+
integrationId,
|
|
625
|
+
integrationName: options.integrationName,
|
|
626
|
+
basePath: `${basePath}/agents/${encodeURIComponent(agent.agentId)}`,
|
|
627
|
+
resolvePrincipal: options.resolvePrincipal,
|
|
628
|
+
revokePrincipal: options.revokePrincipal
|
|
629
|
+
}, resolveCustomerIdentity)
|
|
630
|
+
]));
|
|
631
|
+
const agentBySelector = /* @__PURE__ */ new Map();
|
|
632
|
+
for (const agent of agents) {
|
|
633
|
+
agentBySelector.set(agent.agentId, agent);
|
|
634
|
+
if (agent.agentAlias) agentBySelector.set(agent.agentAlias, agent);
|
|
635
|
+
}
|
|
636
|
+
return async (request) => {
|
|
637
|
+
const url = new URL(request.url);
|
|
638
|
+
if (url.pathname !== basePath && !url.pathname.startsWith(`${basePath}/`)) {
|
|
639
|
+
return publicError(404, "NOT_FOUND", "The requested BFF route does not exist.");
|
|
640
|
+
}
|
|
641
|
+
if (!browserRequestIsSameOrigin(request)) {
|
|
642
|
+
return publicError(403, "BFF_ORIGIN_DENIED", "The BFF accepts same-origin browser requests only.");
|
|
643
|
+
}
|
|
644
|
+
const path = url.pathname.slice(basePath.length) || "/";
|
|
645
|
+
let resolution;
|
|
646
|
+
try {
|
|
647
|
+
resolution = await options.resolvePrincipal(request);
|
|
648
|
+
resolution.principal.subject = normalized(resolution.principal.subject, "subject");
|
|
649
|
+
if (resolution.principal.issuer !== void 0) resolution.principal.issuer = normalized(resolution.principal.issuer, "issuer");
|
|
650
|
+
} catch {
|
|
651
|
+
return publicError(401, "PRINCIPAL_REQUIRED", "A valid application session is required.");
|
|
652
|
+
}
|
|
653
|
+
try {
|
|
654
|
+
const externalUserId = await resolveCustomerIdentity(resolution.principal);
|
|
655
|
+
const identity = {
|
|
656
|
+
external_user_id: externalUserId,
|
|
657
|
+
...resolution.principal.externalSessionId ? { external_session_id: resolution.principal.externalSessionId } : {}
|
|
658
|
+
};
|
|
659
|
+
const requestedAgent = (value) => {
|
|
660
|
+
const agentId = stringValue(value) || agents[0].agentId;
|
|
661
|
+
const configured = agentBySelector.get(agentId);
|
|
662
|
+
if (!configured) throw new BffInputError(404, "AGENT_NOT_CONFIGURED", "The requested Agent is not available.");
|
|
663
|
+
return configured;
|
|
664
|
+
};
|
|
665
|
+
const dispatchToAgent = async (agentId) => {
|
|
666
|
+
const handler = scopedHandlers.get(agentId);
|
|
667
|
+
if (!handler) throw new BffInputError(404, "NOT_FOUND", "The requested resource does not exist.");
|
|
668
|
+
const target = new URL(request.url);
|
|
669
|
+
target.pathname = `${basePath}/agents/${encodeURIComponent(agentId)}${path}`;
|
|
670
|
+
const body = request.method === "GET" || request.method === "HEAD" ? void 0 : await request.arrayBuffer();
|
|
671
|
+
return handler(new Request(target, {
|
|
672
|
+
method: request.method,
|
|
673
|
+
headers: request.headers,
|
|
674
|
+
body,
|
|
675
|
+
signal: request.signal
|
|
676
|
+
}));
|
|
677
|
+
};
|
|
678
|
+
const resolveRunAgent = async (runId) => {
|
|
679
|
+
const result = await options.client.embed.resolveConversationRun(runId, {
|
|
680
|
+
agent_ids: agents.map((agent) => agent.agentId),
|
|
681
|
+
...identity,
|
|
682
|
+
integration_id: integrationId,
|
|
683
|
+
runtime_target: runtimeTarget
|
|
684
|
+
});
|
|
685
|
+
return requestedAgent(result.agent_id).agentId;
|
|
686
|
+
};
|
|
687
|
+
if (request.method === "GET" && path === "/bootstrap") {
|
|
688
|
+
const candidates = await Promise.all(agents.map(async (agent) => {
|
|
689
|
+
const [raw, policy] = await Promise.all([
|
|
690
|
+
options.client.embed.getRuntimeBootstrap(agent.agentId, agent.agentVersionId, runtimeTarget),
|
|
691
|
+
options.client.embed.getResourcePolicy(agent.agentId, {
|
|
692
|
+
external_user_id: externalUserId,
|
|
693
|
+
integration_id: integrationId,
|
|
694
|
+
...agent.agentVersionId ? { agent_version_id: agent.agentVersionId } : {},
|
|
695
|
+
runtime_target: runtimeTarget
|
|
696
|
+
})
|
|
697
|
+
]);
|
|
698
|
+
const alias = normalized(String(raw.agent_alias || ""), "agent_alias");
|
|
699
|
+
agent.agentAlias = alias;
|
|
700
|
+
agentBySelector.set(alias, agent);
|
|
701
|
+
for (const item of stringList(raw.agent_aliases)) agentBySelector.set(item, agent);
|
|
702
|
+
return { agent, raw, policy };
|
|
703
|
+
}));
|
|
704
|
+
const selected = requestedAgent(url.searchParams.get("agent_id"));
|
|
705
|
+
const allowed = candidates.filter((candidate) => candidate.policy.agent_access_allowed !== false);
|
|
706
|
+
const selectedCandidate = allowed.find((candidate) => candidate.agent.agentId === selected.agentId) || allowed[0];
|
|
707
|
+
if (!selectedCandidate) throw new BffInputError(403, "RESOURCE_POLICY_ACCESS_DENIED", "No configured Agent is available.");
|
|
708
|
+
const document = bootstrapDocument(selectedCandidate.raw, selectedCandidate.agent.agentVersionId);
|
|
709
|
+
const features = objectValue(document.features);
|
|
710
|
+
features.models = selectedCandidate.policy.model_selection;
|
|
711
|
+
features.agents = {
|
|
712
|
+
selectable: allowed.length > 1,
|
|
713
|
+
default_id: normalized(String(allowed[0].raw.agent_alias || ""), "agent_alias"),
|
|
714
|
+
options: allowed.map((candidate) => ({
|
|
715
|
+
id: normalized(String(candidate.raw.agent_alias || ""), "agent_alias"),
|
|
716
|
+
label: normalized(String(candidate.raw.agent_name || ""), "agent_name")
|
|
717
|
+
}))
|
|
718
|
+
};
|
|
719
|
+
document.features = features;
|
|
720
|
+
document.capabilities = [
|
|
721
|
+
.../* @__PURE__ */ new Set([
|
|
722
|
+
...document.capabilities || [],
|
|
723
|
+
...allowed.length > 1 ? ["agents.select"] : [],
|
|
724
|
+
...selectedCandidate.policy.model_selection.selectable ? ["models.select"] : []
|
|
725
|
+
])
|
|
726
|
+
];
|
|
727
|
+
return mergeHeaders(json(document), resolution.responseHeaders);
|
|
728
|
+
}
|
|
729
|
+
if (request.method === "POST" && path === "/chat/stream") {
|
|
730
|
+
const body = await requestJson(request);
|
|
731
|
+
const selected = requestedAgent(body.requestedAgentId);
|
|
732
|
+
const input = stringValue(body.input);
|
|
733
|
+
const attachmentIds = stringList(body.attachmentIds);
|
|
734
|
+
if (!input && attachmentIds.length === 0) throw new BffInputError(400, "INPUT_REQUIRED", "A message or attachment is required.");
|
|
735
|
+
if (input && input.length > MAX_INPUT_LENGTH) throw new BffInputError(413, "INPUT_TOO_LARGE", "The message is too large.");
|
|
736
|
+
if (attachmentIds.length > MAX_ATTACHMENTS) throw new BffInputError(400, "TOO_MANY_ATTACHMENTS", `At most ${MAX_ATTACHMENTS} attachments are allowed.`);
|
|
737
|
+
return mergeHeaders(sseResponse(async (write) => {
|
|
738
|
+
await options.client.embed.streamAgent(selected.agentId, {
|
|
739
|
+
...identity,
|
|
740
|
+
...selected.agentVersionId ? { agent_version_id: selected.agentVersionId } : {},
|
|
741
|
+
runtime_target: runtimeTarget,
|
|
742
|
+
integration_id: integrationId,
|
|
743
|
+
...input ? { input } : {},
|
|
744
|
+
attachment_ids: attachmentIds,
|
|
745
|
+
...stringValue(body.threadId) ? { thread_id: stringValue(body.threadId) } : {},
|
|
746
|
+
...stringValue(body.requestedModelId) ? { requested_model_id: stringValue(body.requestedModelId) } : {},
|
|
747
|
+
tool_inputs: objectValue(body.toolInputs),
|
|
748
|
+
metadata: objectValue(body.metadata),
|
|
749
|
+
client: objectValue(body.client)
|
|
750
|
+
}, (event) => write(event), { idempotencyKey: stringValue(request.headers.get("idempotency-key")), signal: request.signal });
|
|
751
|
+
}), resolution.responseHeaders);
|
|
752
|
+
}
|
|
753
|
+
if (request.method === "GET" && path === "/threads") {
|
|
754
|
+
const skip = Number(url.searchParams.get("skip") || 0);
|
|
755
|
+
const limit = Number(url.searchParams.get("limit") || 20);
|
|
756
|
+
if (!Number.isInteger(skip) || skip < 0 || !Number.isInteger(limit) || limit < 1 || limit > 100) {
|
|
757
|
+
throw new BffInputError(400, "INVALID_PAGINATION", "skip must be non-negative and limit must be between 1 and 100.");
|
|
758
|
+
}
|
|
759
|
+
return mergeHeaders(json(await options.client.embed.listAgentThreadsMulti({
|
|
760
|
+
agent_ids: agents.map((agent) => agent.agentId),
|
|
761
|
+
external_user_id: externalUserId,
|
|
762
|
+
...resolution.principal.externalSessionId ? { external_session_id: resolution.principal.externalSessionId } : {},
|
|
763
|
+
runtime_target: runtimeTarget,
|
|
764
|
+
integration_id: integrationId,
|
|
765
|
+
skip,
|
|
766
|
+
limit
|
|
767
|
+
})), resolution.responseHeaders);
|
|
768
|
+
}
|
|
769
|
+
if (request.method === "GET" && path === "/threads/events") {
|
|
770
|
+
const rawCursor = url.searchParams.get("cursor");
|
|
771
|
+
const cursor = rawCursor === null ? void 0 : Number(rawCursor);
|
|
772
|
+
if (cursor !== void 0 && (!Number.isInteger(cursor) || cursor < 0)) {
|
|
773
|
+
throw new BffInputError(400, "INVALID_CURSOR", "cursor must be a non-negative integer.");
|
|
774
|
+
}
|
|
775
|
+
return mergeHeaders(sseResponse(async (write) => {
|
|
776
|
+
await options.client.embed.subscribeAgentThreadEventsMulti({
|
|
777
|
+
agentIds: agents.map((agent) => agent.agentId),
|
|
778
|
+
externalUserId,
|
|
779
|
+
...resolution.principal.externalSessionId ? { externalSessionId: resolution.principal.externalSessionId } : {},
|
|
780
|
+
...cursor === void 0 ? {} : { cursor },
|
|
781
|
+
runtimeTarget,
|
|
782
|
+
integrationId,
|
|
783
|
+
signal: request.signal
|
|
784
|
+
}, (event) => write(event));
|
|
785
|
+
}, void 0, () => ({
|
|
786
|
+
schema_version: "agents24.thread_summary_event.v1",
|
|
787
|
+
event: "snapshot_required",
|
|
788
|
+
cursor,
|
|
789
|
+
reason: "stream_failed"
|
|
790
|
+
})), resolution.responseHeaders);
|
|
791
|
+
}
|
|
792
|
+
if (/^\/threads\/[^/]+$/.test(path) && request.method === "GET") {
|
|
793
|
+
const threadId = routeId(path, /^\/threads\/([^/]+)$/, "threadId");
|
|
794
|
+
const rawBefore = url.searchParams.get("before_turn_index");
|
|
795
|
+
const rawLimit = url.searchParams.get("limit");
|
|
796
|
+
const beforeTurnIndex = rawBefore === null ? void 0 : Number(rawBefore);
|
|
797
|
+
const detailLimit = rawLimit === null ? void 0 : Number(rawLimit);
|
|
798
|
+
if (beforeTurnIndex !== void 0 && (!Number.isInteger(beforeTurnIndex) || beforeTurnIndex < 0)) {
|
|
799
|
+
throw new BffInputError(400, "INVALID_PAGINATION", "before_turn_index is invalid.");
|
|
800
|
+
}
|
|
801
|
+
if (detailLimit !== void 0 && (!Number.isInteger(detailLimit) || detailLimit < 1 || detailLimit > 100)) {
|
|
802
|
+
throw new BffInputError(400, "INVALID_PAGINATION", "limit must be between 1 and 100.");
|
|
803
|
+
}
|
|
804
|
+
return mergeHeaders(json(await options.client.embed.getConversationThread(threadId, {
|
|
805
|
+
agentIds: agents.map((agent) => agent.agentId),
|
|
806
|
+
externalUserId,
|
|
807
|
+
...resolution.principal.externalSessionId ? { externalSessionId: resolution.principal.externalSessionId } : {},
|
|
808
|
+
integrationId,
|
|
809
|
+
runtimeTarget,
|
|
810
|
+
beforeTurnIndex,
|
|
811
|
+
limit: detailLimit
|
|
812
|
+
})), resolution.responseHeaders);
|
|
813
|
+
}
|
|
814
|
+
if (/^\/threads\/[^/]+\/runtime-selection$/.test(path) && request.method === "PATCH") {
|
|
815
|
+
const threadId = routeId(path, /^\/threads\/([^/]+)\//, "threadId");
|
|
816
|
+
const body = await requestJson(request);
|
|
817
|
+
const selected = requestedAgent(body.preferredAgentId);
|
|
818
|
+
return mergeHeaders(json(await options.client.embed.setConversationRuntimeSelection(threadId, {
|
|
819
|
+
agent_ids: agents.map((agent) => agent.agentId),
|
|
820
|
+
preferred_agent_id: selected.agentId,
|
|
821
|
+
...stringValue(body.preferredModelId) ? { preferred_model_id: stringValue(body.preferredModelId) } : {},
|
|
822
|
+
...identity,
|
|
823
|
+
integration_id: integrationId,
|
|
824
|
+
runtime_target: runtimeTarget
|
|
825
|
+
})), resolution.responseHeaders);
|
|
826
|
+
}
|
|
827
|
+
if (/^\/threads\/[^/]+$/.test(path) && request.method === "DELETE") {
|
|
828
|
+
const threadId = routeId(path, /^\/threads\/([^/]+)$/, "threadId");
|
|
829
|
+
return mergeHeaders(json(await options.client.embed.deleteConversationThread(threadId, {
|
|
830
|
+
agentIds: agents.map((agent) => agent.agentId),
|
|
831
|
+
externalUserId,
|
|
832
|
+
...resolution.principal.externalSessionId ? { externalSessionId: resolution.principal.externalSessionId } : {},
|
|
833
|
+
integrationId,
|
|
834
|
+
runtimeTarget
|
|
835
|
+
}, { idempotencyKey: stringValue(request.headers.get("idempotency-key")) })), resolution.responseHeaders);
|
|
836
|
+
}
|
|
837
|
+
if (request.method === "POST" && path === "/attachments/upload") {
|
|
838
|
+
const form = await request.clone().formData();
|
|
839
|
+
const selected = requestedAgent(form.get("requested_agent_id"));
|
|
840
|
+
const policy = await options.client.embed.getResourcePolicy(selected.agentId, {
|
|
841
|
+
external_user_id: externalUserId,
|
|
842
|
+
integration_id: integrationId,
|
|
843
|
+
...selected.agentVersionId ? { agent_version_id: selected.agentVersionId } : {},
|
|
844
|
+
runtime_target: runtimeTarget
|
|
845
|
+
});
|
|
846
|
+
if (policy.agent_access_allowed === false) throw new BffInputError(403, "RESOURCE_POLICY_ACCESS_DENIED", "The requested Agent is not available.");
|
|
847
|
+
return dispatchToAgent(selected.agentId);
|
|
848
|
+
}
|
|
849
|
+
if (request.method === "POST" && /^\/attachments\/[^/]+\/content-access$/.test(path)) {
|
|
850
|
+
return dispatchToAgent(agents[0].agentId);
|
|
851
|
+
}
|
|
852
|
+
if (/^\/runs\/[^/]+\/(?:attach|cancel|feedback)$/.test(path) || /^\/runs\/[^/]+\/hitl\/[^/]+\/resume$/.test(path) || /^\/runs\/[^/]+\/mcp\/servers\/[^/]+\/auth\/start$/.test(path)) {
|
|
853
|
+
const runId = routeId(path, /^\/runs\/([^/]+)\//, "runId");
|
|
854
|
+
return dispatchToAgent(await resolveRunAgent(runId));
|
|
855
|
+
}
|
|
856
|
+
if (request.method === "POST" && path === "/mcp/callback/redeem") {
|
|
857
|
+
throw new BffInputError(409, "MCP_CALLBACK_DIRECT", "Server-embed MCP callbacks complete in the authorization popup.");
|
|
858
|
+
}
|
|
859
|
+
if (request.method === "POST" && path === "/session/revoke") {
|
|
860
|
+
const headers = await options.revokePrincipal?.(request, resolution.principal);
|
|
861
|
+
return mergeHeaders(new Response(null, { status: 204, ...headers ? { headers } : {} }), resolution.responseHeaders);
|
|
862
|
+
}
|
|
863
|
+
return mergeHeaders(publicError(404, "NOT_FOUND", "The requested BFF route does not exist."), resolution.responseHeaders);
|
|
864
|
+
} catch (error) {
|
|
865
|
+
if (error instanceof BffInputError) return mergeHeaders(publicError(error.status, error.code, error.message), resolution.responseHeaders);
|
|
866
|
+
return mergeHeaders(errorResponse(error), resolution.responseHeaders);
|
|
867
|
+
}
|
|
868
|
+
};
|
|
869
|
+
}
|
|
870
|
+
function createAgents24BffHandler(options) {
|
|
871
|
+
const resolveAgents = prepareAgents24BffAgentResolution(options);
|
|
872
|
+
let resolvedHandler;
|
|
873
|
+
const resolve = async () => {
|
|
874
|
+
const agents = await resolveAgents();
|
|
875
|
+
return createResolvedAgents24BffHandler({ ...options, agents });
|
|
876
|
+
};
|
|
877
|
+
return async (request) => {
|
|
878
|
+
if (!browserRequestIsSameOrigin(request)) {
|
|
879
|
+
return publicError(403, "BFF_ORIGIN_DENIED", "The BFF accepts same-origin browser requests only.");
|
|
880
|
+
}
|
|
881
|
+
resolvedHandler ||= resolve();
|
|
882
|
+
try {
|
|
883
|
+
return (await resolvedHandler)(request);
|
|
884
|
+
} catch (error) {
|
|
885
|
+
resolvedHandler = void 0;
|
|
886
|
+
return errorResponse(error);
|
|
887
|
+
}
|
|
888
|
+
};
|
|
889
|
+
}
|
|
473
890
|
|
|
474
891
|
exports.createAgents24BffHandler = createAgents24BffHandler;
|
|
475
892
|
//# sourceMappingURL=bff.cjs.map
|