veryfront 0.1.511 → 0.1.513
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 +46 -5
- package/esm/deno.d.ts +0 -4
- package/esm/deno.js +1 -5
- package/esm/src/agent/agent-service-config.d.ts +54 -0
- package/esm/src/agent/agent-service-config.d.ts.map +1 -1
- package/esm/src/agent/agent-service-config.js +24 -0
- package/esm/src/agent/agent-service-registration.d.ts +110 -0
- package/esm/src/agent/agent-service-registration.d.ts.map +1 -0
- package/esm/src/agent/agent-service-registration.js +228 -0
- package/esm/src/agent/agent-service-runtime.d.ts +3 -1
- package/esm/src/agent/agent-service-runtime.d.ts.map +1 -1
- package/esm/src/agent/agent-service-runtime.js +17 -2
- package/esm/src/agent/index.d.ts +1 -0
- package/esm/src/agent/index.d.ts.map +1 -1
- package/esm/src/agent/index.js +1 -0
- package/esm/src/agent/runtime-agent-definition-files.d.ts +5 -0
- package/esm/src/agent/runtime-agent-definition-files.d.ts.map +1 -1
- package/esm/src/agent/runtime-agent-definition-files.js +37 -9
- package/esm/src/agent/veryfront-cloud-agent-service.d.ts +6 -1
- package/esm/src/agent/veryfront-cloud-agent-service.d.ts.map +1 -1
- package/esm/src/agent/veryfront-cloud-agent-service.js +144 -37
- package/esm/src/oauth/providers/base.d.ts +10 -0
- package/esm/src/oauth/providers/base.d.ts.map +1 -1
- package/esm/src/oauth/providers/base.js +32 -1
- package/esm/src/utils/version-constant.d.ts +1 -1
- package/esm/src/utils/version-constant.js +1 -1
- package/package.json +1 -1
- package/src/deno.js +1 -5
- package/src/src/agent/agent-service-config.ts +23 -0
- package/src/src/agent/agent-service-registration.ts +320 -0
- package/src/src/agent/agent-service-runtime.ts +25 -2
- package/src/src/agent/index.ts +15 -0
- package/src/src/agent/runtime-agent-definition-files.ts +52 -9
- package/src/src/agent/veryfront-cloud-agent-service.ts +194 -42
- package/src/src/oauth/providers/base.ts +33 -1
- package/src/src/utils/version-constant.ts +1 -1
|
@@ -40,7 +40,10 @@ import {
|
|
|
40
40
|
} from "./agent-service-bootstrap.js";
|
|
41
41
|
import { loadAgentServiceEnvFiles } from "./agent-service-env-files.js";
|
|
42
42
|
import { createHostedFormInputTool } from "./hosted-form-input-tool.js";
|
|
43
|
-
import {
|
|
43
|
+
import {
|
|
44
|
+
createHostedAgentProjectSteering,
|
|
45
|
+
type HostedAgentProjectSteering,
|
|
46
|
+
} from "./hosted-agent-project-steering.js";
|
|
44
47
|
import { type HostedChatRuntimeCreationResult } from "./hosted-chat-runtime-contract.js";
|
|
45
48
|
import type { HostedConversationRootRunContext } from "./conversation-root-run-lifecycle.js";
|
|
46
49
|
import { type AgentRuntimeMessage } from "./agent-runtime-message-adapter.js";
|
|
@@ -65,10 +68,7 @@ import type { AgentServiceMcpServerConfig } from "./agent-service-mcp-server-con
|
|
|
65
68
|
import type { RuntimeLoadSkillToolContext } from "./runtime-load-skill-tool.js";
|
|
66
69
|
import type { RuntimeProjectSteeringLookup } from "./runtime-project-skill-catalog.js";
|
|
67
70
|
import type { RuntimeSkillDefinition } from "./runtime-skill-metadata.js";
|
|
68
|
-
import {
|
|
69
|
-
loadRuntimeAgentMarkdownDefinitionFromFile,
|
|
70
|
-
resolveRuntimeAgentDefinitionsDir,
|
|
71
|
-
} from "./runtime-agent-definition-files.js";
|
|
71
|
+
import { listRuntimeAgentMarkdownDefinitionIds } from "./runtime-agent-definition-files.js";
|
|
72
72
|
import type { RuntimeAgentMarkdownDefinition } from "./runtime-agent-definition.js";
|
|
73
73
|
import {
|
|
74
74
|
buildVeryfrontCloudRuntimeInstructions,
|
|
@@ -86,6 +86,11 @@ import {
|
|
|
86
86
|
startNodeAgentService,
|
|
87
87
|
type StartNodeAgentServiceResult,
|
|
88
88
|
} from "./agent-service-runtime.js";
|
|
89
|
+
import type { AgentServiceServerLifecycle } from "./agent-service-server.js";
|
|
90
|
+
import {
|
|
91
|
+
createAgentServiceRegistrationLifecycle,
|
|
92
|
+
resolveAgentServiceRegistrationInput,
|
|
93
|
+
} from "./agent-service-registration.js";
|
|
89
94
|
import { createDetachedRunTracker } from "./detached-run-tracker.js";
|
|
90
95
|
import type { AgUiResumeValue } from "./ag-ui-tool-shared.js";
|
|
91
96
|
import type { ParsedHostedChatRequest } from "./hosted-chat-request-parser.js";
|
|
@@ -132,7 +137,11 @@ type AgentServicePathOption = string | URL;
|
|
|
132
137
|
|
|
133
138
|
export type NodeVeryfrontCloudAgentServiceOptions = {
|
|
134
139
|
serviceName: string;
|
|
135
|
-
|
|
140
|
+
/**
|
|
141
|
+
* Default agent served by requests that do not provide an agent id. When
|
|
142
|
+
* omitted, the service selects the only discovered code or markdown agent.
|
|
143
|
+
*/
|
|
144
|
+
agentId?: string;
|
|
136
145
|
/**
|
|
137
146
|
* Project/discovery root. Defaults to the process cwd when neither baseDir
|
|
138
147
|
* nor an entrypoint URL is provided.
|
|
@@ -155,6 +164,7 @@ export type NodeVeryfrontCloudAgentServiceOptions = {
|
|
|
155
164
|
processTarget?: NodeVeryfrontCloudAgentServiceProcessTarget;
|
|
156
165
|
drainTimeoutMs?: number;
|
|
157
166
|
hardShutdownTimeoutMs?: number;
|
|
167
|
+
signals?: readonly NodeJS.Signals[];
|
|
158
168
|
};
|
|
159
169
|
|
|
160
170
|
export type VeryfrontCloudAgentServiceOptions = NodeVeryfrontCloudAgentServiceOptions;
|
|
@@ -310,13 +320,6 @@ function createNodeVeryfrontCloudAgentServiceContext(
|
|
|
310
320
|
): TResult | Promise<TResult> {
|
|
311
321
|
return infrastructure.tracer.trace(operationName, operation);
|
|
312
322
|
}
|
|
313
|
-
const projectSteering = createHostedAgentProjectSteering({
|
|
314
|
-
baseDir: resolveBaseDir(options),
|
|
315
|
-
agentId: options.agentId,
|
|
316
|
-
getApiUrl: () => infrastructure.getConfig().VERYFRONT_API_URL,
|
|
317
|
-
logger: infrastructure.logger,
|
|
318
|
-
trace,
|
|
319
|
-
});
|
|
320
323
|
|
|
321
324
|
return {
|
|
322
325
|
options,
|
|
@@ -324,7 +327,8 @@ function createNodeVeryfrontCloudAgentServiceContext(
|
|
|
324
327
|
projectDir: resolveProjectDir(options),
|
|
325
328
|
infrastructure,
|
|
326
329
|
trace,
|
|
327
|
-
|
|
330
|
+
defaultAgentId: null as string | null,
|
|
331
|
+
projectSteeringByAgentId: new Map<string, HostedAgentProjectSteering>(),
|
|
328
332
|
tracker: createDetachedRunTracker<AgUiResumeValue>(),
|
|
329
333
|
discoveryResult: null as DiscoveryResult | null,
|
|
330
334
|
agentConfig: null as RuntimeAgentMarkdownDefinition | null,
|
|
@@ -351,27 +355,16 @@ async function createRuntimeAgentDefinitionFromCodeAgent(
|
|
|
351
355
|
|
|
352
356
|
function getMarkdownAgentConfig(
|
|
353
357
|
context: NodeVeryfrontCloudAgentServiceContext,
|
|
358
|
+
agentId: string,
|
|
354
359
|
): RuntimeAgentMarkdownDefinition {
|
|
355
|
-
return context.
|
|
360
|
+
return getProjectSteering(context, agentId).getAgentConfig();
|
|
356
361
|
}
|
|
357
362
|
|
|
358
363
|
function loadMarkdownAgentConfig(
|
|
359
364
|
context: NodeVeryfrontCloudAgentServiceContext,
|
|
360
365
|
agentId: string,
|
|
361
366
|
): RuntimeAgentMarkdownDefinition {
|
|
362
|
-
|
|
363
|
-
return getMarkdownAgentConfig(context);
|
|
364
|
-
}
|
|
365
|
-
|
|
366
|
-
const agentsDir = resolveRuntimeAgentDefinitionsDir({
|
|
367
|
-
baseDir: resolveBaseDir(context.options),
|
|
368
|
-
id: agentId,
|
|
369
|
-
});
|
|
370
|
-
|
|
371
|
-
return loadRuntimeAgentMarkdownDefinitionFromFile({
|
|
372
|
-
agentsDir,
|
|
373
|
-
id: agentId,
|
|
374
|
-
});
|
|
367
|
+
return getMarkdownAgentConfig(context, agentId);
|
|
375
368
|
}
|
|
376
369
|
|
|
377
370
|
async function resolveAgentConfig(
|
|
@@ -427,11 +420,102 @@ async function discoverProjectPrimitives(
|
|
|
427
420
|
context.discoveryResult = await discoverAll(discoveryOptions);
|
|
428
421
|
}
|
|
429
422
|
|
|
423
|
+
function getDiscoveredCodeAgentIds(context: NodeVeryfrontCloudAgentServiceContext): string[] {
|
|
424
|
+
return [...(context.discoveryResult?.agents.keys() ?? [])].sort((left, right) =>
|
|
425
|
+
left.localeCompare(right)
|
|
426
|
+
);
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
function getDiscoveredMarkdownAgentIds(context: NodeVeryfrontCloudAgentServiceContext): string[] {
|
|
430
|
+
return listRuntimeAgentMarkdownDefinitionIds({
|
|
431
|
+
baseDir: resolveBaseDir(context.options),
|
|
432
|
+
});
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
function describeAgentIdCandidates(input: {
|
|
436
|
+
codeAgentIds: string[];
|
|
437
|
+
markdownAgentIds: string[];
|
|
438
|
+
}): string {
|
|
439
|
+
const ids = [...new Set([...input.codeAgentIds, ...input.markdownAgentIds])]
|
|
440
|
+
.sort((left, right) => left.localeCompare(right));
|
|
441
|
+
|
|
442
|
+
return ids.length > 0 ? ids.join(", ") : "none";
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
function resolveSingleAgentId(input: {
|
|
446
|
+
codeAgentIds: string[];
|
|
447
|
+
markdownAgentIds: string[];
|
|
448
|
+
source: NodeVeryfrontCloudAgentServiceAgentSource;
|
|
449
|
+
}): string | null {
|
|
450
|
+
if (input.source === "code") {
|
|
451
|
+
return input.codeAgentIds.length === 1 ? input.codeAgentIds[0] ?? null : null;
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
if (input.source === "markdown") {
|
|
455
|
+
return input.markdownAgentIds.length === 1 ? input.markdownAgentIds[0] ?? null : null;
|
|
456
|
+
}
|
|
457
|
+
|
|
458
|
+
const candidateIds = [...new Set([...input.codeAgentIds, ...input.markdownAgentIds])];
|
|
459
|
+
return candidateIds.length === 1 ? candidateIds[0] ?? null : null;
|
|
460
|
+
}
|
|
461
|
+
|
|
462
|
+
function resolveDefaultAgentId(context: NodeVeryfrontCloudAgentServiceContext): string {
|
|
463
|
+
if (context.options.agentId) {
|
|
464
|
+
return context.options.agentId;
|
|
465
|
+
}
|
|
466
|
+
|
|
467
|
+
const source = context.options.agentSource ?? "auto";
|
|
468
|
+
const codeAgentIds = getDiscoveredCodeAgentIds(context);
|
|
469
|
+
const markdownAgentIds = getDiscoveredMarkdownAgentIds(context);
|
|
470
|
+
const agentId = resolveSingleAgentId({ codeAgentIds, markdownAgentIds, source });
|
|
471
|
+
|
|
472
|
+
if (agentId) {
|
|
473
|
+
return agentId;
|
|
474
|
+
}
|
|
475
|
+
|
|
476
|
+
throw new Error(
|
|
477
|
+
[
|
|
478
|
+
"agentId is required when agent discovery does not resolve to exactly one agent.",
|
|
479
|
+
`Discovered agents: ${describeAgentIdCandidates({ codeAgentIds, markdownAgentIds })}.`,
|
|
480
|
+
].join(" "),
|
|
481
|
+
);
|
|
482
|
+
}
|
|
483
|
+
|
|
430
484
|
async function initializeNodeVeryfrontCloudAgentServiceContext(
|
|
431
485
|
context: NodeVeryfrontCloudAgentServiceContext,
|
|
432
486
|
): Promise<void> {
|
|
433
487
|
await discoverProjectPrimitives(context);
|
|
434
|
-
context.
|
|
488
|
+
context.defaultAgentId = resolveDefaultAgentId(context);
|
|
489
|
+
context.agentConfig = await resolveAgentConfig(context, context.defaultAgentId);
|
|
490
|
+
}
|
|
491
|
+
|
|
492
|
+
function getDefaultAgentId(context: NodeVeryfrontCloudAgentServiceContext): string {
|
|
493
|
+
if (!context.defaultAgentId) {
|
|
494
|
+
throw new Error("Agent service context has not been initialized.");
|
|
495
|
+
}
|
|
496
|
+
|
|
497
|
+
return context.defaultAgentId;
|
|
498
|
+
}
|
|
499
|
+
|
|
500
|
+
function getProjectSteering(
|
|
501
|
+
context: NodeVeryfrontCloudAgentServiceContext,
|
|
502
|
+
agentId: string = getDefaultAgentId(context),
|
|
503
|
+
): HostedAgentProjectSteering {
|
|
504
|
+
const cachedProjectSteering = context.projectSteeringByAgentId.get(agentId);
|
|
505
|
+
if (cachedProjectSteering) {
|
|
506
|
+
return cachedProjectSteering;
|
|
507
|
+
}
|
|
508
|
+
|
|
509
|
+
const projectSteering = createHostedAgentProjectSteering({
|
|
510
|
+
baseDir: resolveBaseDir(context.options),
|
|
511
|
+
agentId,
|
|
512
|
+
getApiUrl: () => context.infrastructure.getConfig().VERYFRONT_API_URL,
|
|
513
|
+
logger: context.infrastructure.logger,
|
|
514
|
+
trace: context.trace,
|
|
515
|
+
});
|
|
516
|
+
|
|
517
|
+
context.projectSteeringByAgentId.set(agentId, projectSteering);
|
|
518
|
+
return projectSteering;
|
|
435
519
|
}
|
|
436
520
|
|
|
437
521
|
function getDiscoveredHostTools(): HostToolSet {
|
|
@@ -445,7 +529,7 @@ function getProjectInstructions(
|
|
|
445
529
|
lookup: RuntimeProjectSteeringLookup,
|
|
446
530
|
): Promise<string> {
|
|
447
531
|
return context.trace("chat.getProjectInstructions", async () => {
|
|
448
|
-
return await context.
|
|
532
|
+
return await getProjectSteering(context).getProjectInstructions(lookup);
|
|
449
533
|
});
|
|
450
534
|
}
|
|
451
535
|
|
|
@@ -454,7 +538,7 @@ function getSkillsConfig(
|
|
|
454
538
|
lookup: RuntimeProjectSteeringLookup,
|
|
455
539
|
): Promise<RuntimeSkillDefinition[]> {
|
|
456
540
|
return context.trace("chat.getSkillsConfig", async () => {
|
|
457
|
-
return await context.
|
|
541
|
+
return await getProjectSteering(context).getSkillsConfig(lookup);
|
|
458
542
|
});
|
|
459
543
|
}
|
|
460
544
|
|
|
@@ -462,14 +546,14 @@ function createLoadSkillTool(
|
|
|
462
546
|
context: NodeVeryfrontCloudAgentServiceContext,
|
|
463
547
|
toolContext: RuntimeLoadSkillToolContext,
|
|
464
548
|
) {
|
|
465
|
-
return context.
|
|
549
|
+
return getProjectSteering(context).createLoadSkillTool(toolContext);
|
|
466
550
|
}
|
|
467
551
|
|
|
468
552
|
async function refreshProjectSkillIds(
|
|
469
553
|
context: NodeVeryfrontCloudAgentServiceContext,
|
|
470
554
|
skillContext: HostedProjectSkillIdsContext,
|
|
471
555
|
): Promise<void> {
|
|
472
|
-
await context.
|
|
556
|
+
await getProjectSteering(context).refreshProjectSkillIds(skillContext);
|
|
473
557
|
}
|
|
474
558
|
|
|
475
559
|
function setFilteredTraceAttributes(
|
|
@@ -683,7 +767,7 @@ async function prepareChatExecution(
|
|
|
683
767
|
|
|
684
768
|
setPrepareChatExecutionStartAttributes(context, { projectId, userId });
|
|
685
769
|
|
|
686
|
-
const agentConfig = await resolveAgentConfig(context, req.agentId ?? context
|
|
770
|
+
const agentConfig = await resolveAgentConfig(context, req.agentId ?? getDefaultAgentId(context));
|
|
687
771
|
const {
|
|
688
772
|
effectiveMessages,
|
|
689
773
|
rootRunContext,
|
|
@@ -760,6 +844,58 @@ function createPreparedExecutionRuntimeOptions(
|
|
|
760
844
|
});
|
|
761
845
|
}
|
|
762
846
|
|
|
847
|
+
function resolveAgentServiceRuntimeName(): string {
|
|
848
|
+
if (Reflect.get(dntShim.dntGlobalThis, "Bun")) {
|
|
849
|
+
return "bun";
|
|
850
|
+
}
|
|
851
|
+
if (Reflect.get(dntShim.dntGlobalThis, "Deno")) {
|
|
852
|
+
return "deno";
|
|
853
|
+
}
|
|
854
|
+
return "node";
|
|
855
|
+
}
|
|
856
|
+
|
|
857
|
+
function getAgentServiceVersion(
|
|
858
|
+
context: NodeVeryfrontCloudAgentServiceContext,
|
|
859
|
+
): string | undefined {
|
|
860
|
+
return context.options.env?.npm_package_version;
|
|
861
|
+
}
|
|
862
|
+
|
|
863
|
+
async function createControlPlaneRegistrationLifecycle(
|
|
864
|
+
context: NodeVeryfrontCloudAgentServiceContext,
|
|
865
|
+
): Promise<AgentServiceServerLifecycle | undefined> {
|
|
866
|
+
const config = context.infrastructure.getConfig();
|
|
867
|
+
const registrationInput = await resolveAgentServiceRegistrationInput({
|
|
868
|
+
config,
|
|
869
|
+
serviceName: context.options.serviceName,
|
|
870
|
+
agentId: getDefaultAgentId(context),
|
|
871
|
+
version: getAgentServiceVersion(context),
|
|
872
|
+
runtime: resolveAgentServiceRuntimeName(),
|
|
873
|
+
});
|
|
874
|
+
|
|
875
|
+
if (!registrationInput) {
|
|
876
|
+
return undefined;
|
|
877
|
+
}
|
|
878
|
+
|
|
879
|
+
try {
|
|
880
|
+
const lifecycle = await createAgentServiceRegistrationLifecycle({
|
|
881
|
+
...registrationInput,
|
|
882
|
+
logger: context.infrastructure.logger,
|
|
883
|
+
});
|
|
884
|
+
return {
|
|
885
|
+
stop: () => lifecycle.stop(),
|
|
886
|
+
};
|
|
887
|
+
} catch (error) {
|
|
888
|
+
if (config.VERYFRONT_AGENT_SERVICE_REGISTRATION === "enabled") {
|
|
889
|
+
throw error;
|
|
890
|
+
}
|
|
891
|
+
|
|
892
|
+
context.infrastructure.logger.warn("Agent service registration skipped", {
|
|
893
|
+
error: error instanceof Error ? error.message : String(error),
|
|
894
|
+
});
|
|
895
|
+
return undefined;
|
|
896
|
+
}
|
|
897
|
+
}
|
|
898
|
+
|
|
763
899
|
function createNodeVeryfrontCloudAgentServiceRuntimeOptions(
|
|
764
900
|
context: NodeVeryfrontCloudAgentServiceContext,
|
|
765
901
|
): CreateAgentServiceRuntimeOptions<NodeVeryfrontCloudAgentServicePreparedExecution> {
|
|
@@ -818,10 +954,18 @@ export async function startNodeVeryfrontCloudAgentService(
|
|
|
818
954
|
const resolvedOptions = await resolveNodeVeryfrontCloudAgentServiceOptions(options);
|
|
819
955
|
const context = createNodeVeryfrontCloudAgentServiceContext(resolvedOptions);
|
|
820
956
|
await initializeNodeVeryfrontCloudAgentServiceContext(context);
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
957
|
+
const registrationLifecycle = await createControlPlaneRegistrationLifecycle(context);
|
|
958
|
+
try {
|
|
959
|
+
return await startNodeAgentService({
|
|
960
|
+
...createNodeVeryfrontCloudAgentServiceRuntimeOptions(context),
|
|
961
|
+
lifecycle: registrationLifecycle,
|
|
962
|
+
signals: options.signals,
|
|
963
|
+
hardShutdownTimeoutMs: options.hardShutdownTimeoutMs ?? DEFAULT_HARD_SHUTDOWN_TIMEOUT_MS,
|
|
964
|
+
});
|
|
965
|
+
} catch (error) {
|
|
966
|
+
await registrationLifecycle?.stop?.();
|
|
967
|
+
throw error;
|
|
968
|
+
}
|
|
825
969
|
}
|
|
826
970
|
|
|
827
971
|
export async function startAgentService(
|
|
@@ -856,10 +1000,18 @@ export async function startAgentService(
|
|
|
856
1000
|
__registerTraceContextGetter(getter);
|
|
857
1001
|
},
|
|
858
1002
|
start: async () => {
|
|
859
|
-
await
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
1003
|
+
const registrationLifecycle = await createControlPlaneRegistrationLifecycle(context);
|
|
1004
|
+
try {
|
|
1005
|
+
await startAgentServiceRuntime({
|
|
1006
|
+
...createNodeVeryfrontCloudAgentServiceRuntimeOptions(context),
|
|
1007
|
+
lifecycle: registrationLifecycle,
|
|
1008
|
+
signals: options.signals,
|
|
1009
|
+
hardShutdownTimeoutMs: options.hardShutdownTimeoutMs ?? DEFAULT_HARD_SHUTDOWN_TIMEOUT_MS,
|
|
1010
|
+
});
|
|
1011
|
+
} catch (error) {
|
|
1012
|
+
await registrationLifecycle?.stop?.();
|
|
1013
|
+
throw error;
|
|
1014
|
+
}
|
|
863
1015
|
},
|
|
864
1016
|
onStartupError: (error) => {
|
|
865
1017
|
console.error("Error in server startup:", error);
|
|
@@ -341,6 +341,38 @@ export class OAuthService extends OAuthProvider {
|
|
|
341
341
|
return result.tokens.accessToken;
|
|
342
342
|
}
|
|
343
343
|
|
|
344
|
+
/**
|
|
345
|
+
* Resolve `endpoint` against `apiBaseUrl`, validating that absolute URLs
|
|
346
|
+
* share the configured origin.
|
|
347
|
+
*
|
|
348
|
+
* Without this check, a caller that forwards user-controlled data as
|
|
349
|
+
* `endpoint` could cause `fetch()` to issue requests to arbitrary hosts
|
|
350
|
+
* (including cloud metadata services and internal infrastructure). See
|
|
351
|
+
* SEC-003 in the security audit.
|
|
352
|
+
*/
|
|
353
|
+
private resolveEndpointUrl(endpoint: string): string {
|
|
354
|
+
if (!endpoint.startsWith("http")) {
|
|
355
|
+
return `${this.apiBaseUrl}${endpoint}`;
|
|
356
|
+
}
|
|
357
|
+
let target: URL;
|
|
358
|
+
let allowed: URL;
|
|
359
|
+
try {
|
|
360
|
+
target = new URL(endpoint);
|
|
361
|
+
allowed = new URL(this.apiBaseUrl);
|
|
362
|
+
} catch {
|
|
363
|
+
throw INVALID_ARGUMENT.create({
|
|
364
|
+
detail: `Invalid OAuth endpoint URL`,
|
|
365
|
+
});
|
|
366
|
+
}
|
|
367
|
+
if (target.origin !== allowed.origin) {
|
|
368
|
+
throw INVALID_ARGUMENT.create({
|
|
369
|
+
detail:
|
|
370
|
+
`OAuth endpoint origin ${target.origin} does not match configured ${allowed.origin}`,
|
|
371
|
+
});
|
|
372
|
+
}
|
|
373
|
+
return endpoint;
|
|
374
|
+
}
|
|
375
|
+
|
|
344
376
|
async fetch<T>(userId: string, endpoint: string, options: RequestInit = {}): Promise<T> {
|
|
345
377
|
const token = await this.getAccessToken(userId);
|
|
346
378
|
if (!token) {
|
|
@@ -349,7 +381,7 @@ export class OAuthService extends OAuthProvider {
|
|
|
349
381
|
});
|
|
350
382
|
}
|
|
351
383
|
|
|
352
|
-
const url =
|
|
384
|
+
const url = this.resolveEndpointUrl(endpoint);
|
|
353
385
|
|
|
354
386
|
const response = await fetch(url, {
|
|
355
387
|
...options,
|