@opengeni/core 3.0.1 → 3.1.2
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 +4 -4
- package/dist/access/index.d.ts +131 -7
- package/dist/access/service-initiator.d.ts +3 -0
- package/dist/application/archived-session-imports.d.ts +6 -0
- package/dist/application/composer-submit.d.ts +1 -1
- package/dist/application/connect-operation.d.ts +6 -0
- package/dist/application/external-workspace-members.d.ts +13 -1
- package/dist/application/modal-native-live-declaration-join.d.ts +37 -0
- package/dist/application/modal-native-original-configuration.d.ts +79 -0
- package/dist/application/modal-native-worker-host-transport.d.ts +297 -0
- package/dist/application/new-session-drafts.d.ts +29 -2
- package/dist/application/organization-privacy.d.ts +57 -0
- package/dist/application/prepared-mcp-connection.d.ts +31 -0
- package/dist/application/sandbox-recovery.d.ts +58 -0
- package/dist/application/session-commands.d.ts +3 -0
- package/dist/application/session-tenancy.d.ts +13 -4
- package/dist/billing/agent-run-admission.d.ts +21 -0
- package/dist/billing/limits.d.ts +27 -1
- package/dist/billing/model-call-admission.d.ts +34 -0
- package/dist/billing/model-usage-settlement.d.ts +112 -0
- package/dist/canonical-human-identities.js +1 -1
- package/dist/{chunk-VCZFFEPB.js → chunk-7T2SZ7BI.js} +16 -2
- package/dist/chunk-7T2SZ7BI.js.map +1 -0
- package/dist/{chunk-ZYCNLYGH.js → chunk-OMJFIIWK.js} +178 -12
- package/dist/chunk-OMJFIIWK.js.map +1 -0
- package/dist/{chunk-H7X52RI2.js → chunk-QI2M2B2K.js} +83 -8
- package/dist/chunk-QI2M2B2K.js.map +1 -0
- package/dist/{chunk-OF65T3PM.js → chunk-TTWTXQB2.js} +94 -6
- package/dist/chunk-TTWTXQB2.js.map +1 -0
- package/dist/codex-model-availability.d.ts +55 -0
- package/dist/default-session-model.d.ts +192 -0
- package/dist/dependencies.d.ts +41 -7
- package/dist/developer-setup-credential-ceiling.d.ts +10 -0
- package/dist/domain/agent-config-resolution.d.ts +49 -0
- package/dist/domain/automations.d.ts +8 -1
- package/dist/domain/capabilities.d.ts +112 -8
- package/dist/domain/connection-account-selection-error.d.ts +8 -0
- package/dist/domain/connector-tool-permissions.d.ts +62 -0
- package/dist/domain/direct-model-provider.d.ts +3 -0
- package/dist/domain/editable-artifacts/agent-application.d.ts +10 -1
- package/dist/domain/editable-artifacts/durable-export.d.ts +22 -1
- package/dist/domain/editable-artifacts/ports.d.ts +10 -0
- package/dist/domain/editable-artifacts/service.d.ts +3 -1
- package/dist/domain/editable-artifacts/types.d.ts +1 -1
- package/dist/domain/encryption-key.d.ts +12 -0
- package/dist/domain/insights-timing.d.ts +16 -0
- package/dist/domain/insights-usage.d.ts +27 -0
- package/dist/domain/insights.d.ts +21 -3
- package/dist/domain/knowledge-files.d.ts +1 -1
- package/dist/domain/knowledge-preparation.d.ts +10 -0
- package/dist/domain/knowledge-preparation.test.d.ts +1 -0
- package/dist/domain/knowledge-search.d.ts +15 -76
- package/dist/domain/mcp-account-bindings.d.ts +17 -0
- package/dist/domain/mcp-account-routes.d.ts +21 -0
- package/dist/domain/native-mcp-connection-admission.d.ts +3 -0
- package/dist/domain/organization-integration-catalog.d.ts +15 -0
- package/dist/domain/personal-connection-delegations.d.ts +73 -12
- package/dist/domain/pr-review.d.ts +121 -6
- package/dist/domain/realtime-voice-billing.d.ts +103 -0
- package/dist/domain/resources.d.ts +17 -1
- package/dist/domain/scheduled-task-access.d.ts +265 -0
- package/dist/domain/scheduled-task-account-audit.d.ts +27 -0
- package/dist/domain/scheduled-task-audience.d.ts +70 -0
- package/dist/domain/scheduled-tasks.d.ts +61 -18
- package/dist/domain/session-connection-accounts.d.ts +53 -0
- package/dist/domain/session-file-access.d.ts +4 -0
- package/dist/domain/session-native-connection-replacement.d.ts +14 -0
- package/dist/domain/session-start-timing.d.ts +7 -0
- package/dist/domain/session-tool-policy.d.ts +102 -4
- package/dist/domain/sessions.d.ts +179 -15
- package/dist/domain/site-audience.d.ts +52 -0
- package/dist/domain/skills.d.ts +29 -1
- package/dist/domain/slack-bot.d.ts +46 -1
- package/dist/domain/slack-publication-secret-safety.d.ts +1 -1
- package/dist/domain/vaults/index.d.ts +7 -0
- package/dist/domain/vaults/mapping.d.ts +25 -0
- package/dist/domain/vaults/provider-registry.d.ts +72 -0
- package/dist/domain/vaults/provider-sync.d.ts +176 -0
- package/dist/domain/vaults/provider-writes.d.ts +57 -0
- package/dist/domain/vaults/secret-resolver.d.ts +34 -0
- package/dist/domain/vaults/types.d.ts +24 -0
- package/dist/domain/vaults/vault-service.d.ts +35 -0
- package/dist/domain/voice-input-billing.d.ts +77 -0
- package/dist/domain/web-search-billing.d.ts +51 -0
- package/dist/domain/workspace-credits.d.ts +7 -0
- package/dist/editable-artifact-live/application.d.ts +2 -1
- package/dist/editable-artifact-live/server.d.ts +5 -1
- package/dist/editable-artifact-live/ticket.d.ts +2 -1
- package/dist/editable-artifact-live/types.d.ts +9 -0
- package/dist/editable-artifact-live.js +2 -2
- package/dist/editable-artifacts.js +10 -2
- package/dist/goal-admission.d.ts +627 -0
- package/dist/host-session-usage-limit.d.ts +15 -0
- package/dist/index.d.ts +43 -8
- package/dist/index.js +22682 -11743
- package/dist/index.js.map +1 -1
- package/dist/managed-session.d.ts +110 -7
- package/dist/model-call.d.ts +58 -0
- package/dist/model-catalog.d.ts +29 -3
- package/dist/model-provider-credentials.d.ts +43 -0
- package/dist/product-usage-metrics.d.ts +30 -0
- package/dist/rigs/index.d.ts +1 -13
- package/dist/sandbox/fleet.d.ts +58 -4
- package/dist/sandbox/routing.d.ts +42 -2
- package/dist/sandbox/runtime-settings.d.ts +27 -17
- package/dist/session-authorization.d.ts +10 -0
- package/dist/session-usage-limit-metrics.d.ts +60 -0
- package/dist/session-usage-limits.d.ts +89 -0
- package/dist/site-agent-clamp.d.ts +71 -0
- package/dist/site-session-origin.d.ts +39 -2
- package/dist/transcription.d.ts +120 -3
- package/dist/turn-surface.d.ts +20 -0
- package/dist/user-presence.d.ts +32 -0
- package/dist/workflow-wake-contract.d.ts +13 -1
- package/package.json +15 -22
- package/src/access/index.ts +961 -38
- package/src/access/service-initiator.ts +50 -0
- package/src/application/api-integration-servers.ts +9 -0
- package/src/application/archived-session-imports.ts +161 -0
- package/src/application/composer-submit.ts +3 -2
- package/src/application/connect-authority.ts +3 -3
- package/src/application/connect-operation.ts +37 -3
- package/src/application/external-continuation.ts +20 -3
- package/src/application/external-link-work-admission.ts +3 -0
- package/src/application/external-workspace-members.ts +51 -3
- package/src/application/modal-native-live-declaration-join.ts +196 -0
- package/src/application/modal-native-original-configuration.ts +261 -0
- package/src/application/modal-native-worker-host-transport.ts +263 -0
- package/src/application/new-session-drafts.ts +172 -55
- package/src/application/organization-privacy.ts +161 -0
- package/src/application/prepared-mcp-connection.ts +133 -0
- package/src/application/sandbox-recovery.ts +78 -0
- package/src/application/session-commands.ts +73 -1
- package/src/application/session-mcp-credential-rotation.ts +61 -18
- package/src/application/session-tenancy.ts +262 -44
- package/src/application/user-resource-grants.ts +1 -29
- package/src/billing/agent-run-admission.ts +117 -0
- package/src/billing/limits.ts +138 -14
- package/src/billing/model-call-admission.ts +118 -0
- package/src/billing/model-usage-settlement.ts +472 -0
- package/src/codex-model-availability.ts +264 -0
- package/src/default-session-model.ts +692 -0
- package/src/dependencies.ts +48 -6
- package/src/developer-setup-credential-ceiling.ts +60 -0
- package/src/domain/agent-config-resolution.ts +148 -0
- package/src/domain/automations.ts +76 -2
- package/src/domain/capabilities.ts +830 -181
- package/src/domain/connection-account-selection-error.ts +19 -0
- package/src/domain/connector-tool-permissions.ts +572 -0
- package/src/domain/direct-model-provider.ts +62 -0
- package/src/domain/editable-artifacts/agent-application.ts +44 -6
- package/src/domain/editable-artifacts/durable-export.ts +100 -5
- package/src/domain/editable-artifacts/in-memory.ts +6 -0
- package/src/domain/editable-artifacts/ports.ts +11 -0
- package/src/domain/editable-artifacts/service.ts +20 -0
- package/src/domain/editable-artifacts/types.ts +1 -1
- package/src/domain/encryption-key.ts +26 -0
- package/src/domain/file-owner.ts +16 -1
- package/src/domain/github-action-policies.ts +1 -1
- package/src/domain/github-skill-source.ts +3 -1
- package/src/domain/insights-timing.ts +95 -0
- package/src/domain/insights-usage.ts +67 -0
- package/src/domain/insights.ts +167 -43
- package/src/domain/knowledge-files.ts +10 -3
- package/src/domain/knowledge-messages.ts +1 -0
- package/src/domain/knowledge-preparation.test.ts +276 -0
- package/src/domain/knowledge-preparation.ts +147 -0
- package/src/domain/knowledge-search.test.ts +617 -5
- package/src/domain/knowledge-search.ts +240 -23
- package/src/domain/mcp-account-bindings.ts +169 -0
- package/src/domain/mcp-account-routes.ts +152 -0
- package/src/domain/native-mcp-connection-admission.ts +14 -0
- package/src/domain/organization-integration-catalog.ts +88 -0
- package/src/domain/personal-connection-delegations.ts +399 -257
- package/src/domain/pr-review.ts +24 -8
- package/src/domain/realtime-voice-billing.ts +425 -0
- package/src/domain/resources.ts +50 -4
- package/src/domain/scheduled-task-access.ts +1089 -0
- package/src/domain/scheduled-task-account-audit.ts +90 -0
- package/src/domain/scheduled-task-audience.ts +249 -0
- package/src/domain/scheduled-tasks.ts +1313 -374
- package/src/domain/session-connection-accounts.ts +239 -0
- package/src/domain/session-file-access.ts +47 -0
- package/src/domain/session-native-connection-replacement.ts +64 -0
- package/src/domain/session-start-timing.ts +60 -0
- package/src/domain/session-tool-policy.ts +489 -14
- package/src/domain/sessions.ts +2254 -717
- package/src/domain/site-audience.ts +130 -0
- package/src/domain/skills.ts +9 -0
- package/src/domain/slack-bot.ts +141 -4
- package/src/domain/slack-publication-secret-safety.ts +1 -1
- package/src/domain/vaults/index.ts +19 -0
- package/src/domain/vaults/mapping.ts +190 -0
- package/src/domain/vaults/provider-registry.ts +201 -0
- package/src/domain/vaults/provider-sync.ts +531 -0
- package/src/domain/vaults/provider-writes.ts +288 -0
- package/src/domain/vaults/secret-resolver.ts +464 -0
- package/src/domain/vaults/types.ts +26 -0
- package/src/domain/vaults/vault-service.ts +1316 -0
- package/src/domain/voice-input-billing.ts +330 -0
- package/src/domain/web-search-billing.ts +169 -0
- package/src/domain/workspace-credits.ts +13 -0
- package/src/editable-artifact-live/application.ts +8 -1
- package/src/editable-artifact-live/server.ts +154 -6
- package/src/editable-artifact-live/ticket.ts +86 -1
- package/src/editable-artifact-live/types.ts +10 -0
- package/src/goal-admission.ts +220 -0
- package/src/host-session-usage-limit.ts +25 -0
- package/src/index.ts +75 -11
- package/src/managed-session.ts +137 -6
- package/src/model-call.ts +79 -0
- package/src/model-catalog.ts +345 -91
- package/src/model-provider-credentials.ts +394 -0
- package/src/product-usage-metrics.ts +101 -0
- package/src/rigs/index.ts +23 -111
- package/src/sandbox/fleet.ts +253 -28
- package/src/sandbox/routing.ts +204 -43
- package/src/sandbox/runtime-settings.ts +159 -85
- package/src/session-authorization.ts +172 -23
- package/src/session-usage-limit-metrics.ts +95 -0
- package/src/session-usage-limits.ts +415 -0
- package/src/site-agent-clamp.ts +226 -0
- package/src/site-session-origin.ts +84 -5
- package/src/transcription.ts +123 -4
- package/src/turn-surface.ts +47 -0
- package/src/user-presence.ts +134 -0
- package/src/workflow-wake-contract.ts +14 -1
- package/dist/application/host-mcp-owner.d.ts +0 -6
- package/dist/application/host-mcp-resolvers.d.ts +0 -13
- package/dist/chunk-5WZYFL45.js +0 -266
- package/dist/chunk-5WZYFL45.js.map +0 -1
- package/dist/chunk-H7X52RI2.js.map +0 -1
- package/dist/chunk-OF65T3PM.js.map +0 -1
- package/dist/chunk-VCZFFEPB.js.map +0 -1
- package/dist/chunk-ZYCNLYGH.js.map +0 -1
- package/dist/domain/connection-authority.d.ts +0 -97
- package/dist/domain/connection-authority.js +0 -169
- package/dist/domain/connection-authority.js.map +0 -1
- package/dist/domain/environments.d.ts +0 -33
- package/dist/domain/host-mcp-authority-source-admission.d.ts +0 -10
- package/dist/domain/host-mcp-task-admission.d.ts +0 -18
- package/dist/domain/packs.d.ts +0 -59
- package/dist/domain/product-integration-pack.d.ts +0 -44
- package/dist/domain/product-integration-skill.gen.d.ts +0 -5
- package/dist/remote-mcp-credentials.d.ts +0 -23
- package/dist/remote-mcp-credentials.js +0 -11
- package/dist/remote-mcp-credentials.js.map +0 -1
- package/src/application/host-mcp-owner.ts +0 -41
- package/src/application/host-mcp-resolvers.ts +0 -84
- package/src/domain/connection-authority.ts +0 -329
- package/src/domain/environments.ts +0 -120
- package/src/domain/host-mcp-authority-source-admission.ts +0 -25
- package/src/domain/host-mcp-task-admission.ts +0 -121
- package/src/domain/packs.ts +0 -699
- package/src/domain/product-integration-pack.ts +0 -42
- package/src/domain/product-integration-skill.gen.ts +0 -52
- package/src/remote-mcp-credentials.ts +0 -361
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
import { recordUserActivityPresence, type Database } from "@opengeni/db";
|
|
2
|
+
import type { Observability } from "@opengeni/observability";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Throttled, batched server-side presence for managed humans.
|
|
6
|
+
*
|
|
7
|
+
* `touch` is called on the request path, so it only does an in-memory map
|
|
8
|
+
* check: each person is queued at most once per throttle window per process,
|
|
9
|
+
* and queued people are written in one batched database call after a short
|
|
10
|
+
* delay, never awaited by the request. API keys, services and embedded-host
|
|
11
|
+
* subjects are never passed here; anything outside the opaque `user:` shape is
|
|
12
|
+
* ignored. The database turns a new UTC day into the `user.active` lifecycle
|
|
13
|
+
* fact, and control workers read windowed counts for `opengeni_active_users`.
|
|
14
|
+
*/
|
|
15
|
+
export type UserPresenceRecorder = {
|
|
16
|
+
/** Note authenticated activity for one managed human. Never throws. */
|
|
17
|
+
touch(subjectId: string): void;
|
|
18
|
+
/** Write everything queued now. Resolves even when the write fails. */
|
|
19
|
+
flush(): Promise<void>;
|
|
20
|
+
/** Flush and stop scheduling further writes. */
|
|
21
|
+
close(): Promise<void>;
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
export const USER_PRESENCE_THROTTLE_MS = 60_000;
|
|
25
|
+
export const USER_PRESENCE_FLUSH_DELAY_MS = 5_000;
|
|
26
|
+
const USER_PRESENCE_MAX_TRACKED = 50_000;
|
|
27
|
+
const USER_PRESENCE_SUBJECT = /^user:[A-Za-z0-9_-]{8,128}$/;
|
|
28
|
+
|
|
29
|
+
const PRESENCE_FLUSH_METRIC = {
|
|
30
|
+
name: "opengeni_user_presence_flushes_total",
|
|
31
|
+
help: "Batched user presence writes from this API process by outcome.",
|
|
32
|
+
} as const;
|
|
33
|
+
|
|
34
|
+
export function createUserPresenceRecorder(options: {
|
|
35
|
+
db: Database;
|
|
36
|
+
observability?: Pick<Observability, "incrementCounter" | "warn"> | undefined;
|
|
37
|
+
throttleMs?: number;
|
|
38
|
+
flushDelayMs?: number;
|
|
39
|
+
maxTracked?: number;
|
|
40
|
+
now?: () => number;
|
|
41
|
+
record?: (db: Database, subjectIds: readonly string[]) => Promise<number>;
|
|
42
|
+
}): UserPresenceRecorder {
|
|
43
|
+
const throttleMs = options.throttleMs ?? USER_PRESENCE_THROTTLE_MS;
|
|
44
|
+
const flushDelayMs = options.flushDelayMs ?? USER_PRESENCE_FLUSH_DELAY_MS;
|
|
45
|
+
const maxTracked = options.maxTracked ?? USER_PRESENCE_MAX_TRACKED;
|
|
46
|
+
const now = options.now ?? Date.now;
|
|
47
|
+
const record = options.record ?? recordUserActivityPresence;
|
|
48
|
+
const lastQueuedAt = new Map<string, number>();
|
|
49
|
+
const pending = new Set<string>();
|
|
50
|
+
let timer: ReturnType<typeof setTimeout> | null = null;
|
|
51
|
+
let closed = false;
|
|
52
|
+
let lastWarningAt = 0;
|
|
53
|
+
let tail: Promise<void> = Promise.resolve();
|
|
54
|
+
|
|
55
|
+
const count = (outcome: "ok" | "failed") => {
|
|
56
|
+
try {
|
|
57
|
+
options.observability?.incrementCounter({ ...PRESENCE_FLUSH_METRIC, labels: { outcome } });
|
|
58
|
+
} catch {
|
|
59
|
+
// Telemetry only.
|
|
60
|
+
}
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
const prune = (at: number) => {
|
|
64
|
+
for (const [subject, queuedAt] of lastQueuedAt) {
|
|
65
|
+
if (at - queuedAt >= throttleMs && !pending.has(subject)) lastQueuedAt.delete(subject);
|
|
66
|
+
}
|
|
67
|
+
// Still over the bound: forget the oldest entries; at worst a person is
|
|
68
|
+
// written once more than the throttle would allow.
|
|
69
|
+
if (lastQueuedAt.size > maxTracked) {
|
|
70
|
+
const excess = lastQueuedAt.size - maxTracked;
|
|
71
|
+
let removed = 0;
|
|
72
|
+
for (const subject of lastQueuedAt.keys()) {
|
|
73
|
+
if (removed >= excess) break;
|
|
74
|
+
if (pending.has(subject)) continue;
|
|
75
|
+
lastQueuedAt.delete(subject);
|
|
76
|
+
removed += 1;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
};
|
|
80
|
+
|
|
81
|
+
const writeBatch = async (): Promise<void> => {
|
|
82
|
+
if (pending.size === 0) return;
|
|
83
|
+
const batch = [...pending];
|
|
84
|
+
pending.clear();
|
|
85
|
+
try {
|
|
86
|
+
await record(options.db, batch);
|
|
87
|
+
count("ok");
|
|
88
|
+
} catch (error) {
|
|
89
|
+
// Let the next touch retry these people instead of waiting a window.
|
|
90
|
+
for (const subject of batch) lastQueuedAt.delete(subject);
|
|
91
|
+
count("failed");
|
|
92
|
+
const at = now();
|
|
93
|
+
if (at - lastWarningAt >= throttleMs) {
|
|
94
|
+
lastWarningAt = at;
|
|
95
|
+
options.observability?.warn("user presence write failed", {
|
|
96
|
+
errorClass: error instanceof Error ? error.name : "UnknownError",
|
|
97
|
+
});
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
};
|
|
101
|
+
|
|
102
|
+
const flush = (): Promise<void> => {
|
|
103
|
+
if (timer) {
|
|
104
|
+
clearTimeout(timer);
|
|
105
|
+
timer = null;
|
|
106
|
+
}
|
|
107
|
+
tail = tail.then(writeBatch, writeBatch);
|
|
108
|
+
return tail;
|
|
109
|
+
};
|
|
110
|
+
|
|
111
|
+
return {
|
|
112
|
+
touch(subjectId) {
|
|
113
|
+
if (closed || !USER_PRESENCE_SUBJECT.test(subjectId)) return;
|
|
114
|
+
const at = now();
|
|
115
|
+
const previous = lastQueuedAt.get(subjectId);
|
|
116
|
+
if (previous !== undefined && at - previous < throttleMs) return;
|
|
117
|
+
lastQueuedAt.set(subjectId, at);
|
|
118
|
+
pending.add(subjectId);
|
|
119
|
+
if (lastQueuedAt.size > maxTracked) prune(at);
|
|
120
|
+
if (!timer) {
|
|
121
|
+
timer = setTimeout(() => {
|
|
122
|
+
timer = null;
|
|
123
|
+
void flush();
|
|
124
|
+
}, flushDelayMs);
|
|
125
|
+
(timer as ReturnType<typeof setTimeout> & { unref?: () => void }).unref?.();
|
|
126
|
+
}
|
|
127
|
+
},
|
|
128
|
+
flush,
|
|
129
|
+
async close() {
|
|
130
|
+
closed = true;
|
|
131
|
+
await flush();
|
|
132
|
+
},
|
|
133
|
+
};
|
|
134
|
+
}
|
|
@@ -1,8 +1,21 @@
|
|
|
1
|
-
/**
|
|
1
|
+
/**
|
|
2
|
+
* Legacy id of the Temporal Schedule that used to start the dispatcher every
|
|
3
|
+
* period whether or not anything was due. Current control workers delete it at
|
|
4
|
+
* startup; older releases recreate it, so a rollback keeps its repair cadence.
|
|
5
|
+
*/
|
|
2
6
|
export const SESSION_WORKFLOW_WAKE_DISPATCHER_SCHEDULE_ID =
|
|
3
7
|
"opengeni-session-workflow-wake-dispatcher";
|
|
4
8
|
export const SESSION_WORKFLOW_WAKE_DISPATCHER_WORKFLOW_TYPE =
|
|
5
9
|
"sessionWorkflowWakeDispatcherWorkflow";
|
|
10
|
+
/**
|
|
11
|
+
* The single dispatcher execution. Immediate triggers and the control
|
|
12
|
+
* worker's repair cadence signal-with-start this id, so a request that lands
|
|
13
|
+
* while a sweep is running buffers exactly one more sweep instead of starting
|
|
14
|
+
* a second execution.
|
|
15
|
+
*/
|
|
16
|
+
export const SESSION_WORKFLOW_WAKE_DISPATCHER_WORKFLOW_ID =
|
|
17
|
+
"opengeni-session-workflow-wake-dispatcher";
|
|
18
|
+
export const SESSION_WORKFLOW_WAKE_DISPATCH_REQUESTED_SIGNAL = "dispatchRequested";
|
|
6
19
|
export const SESSION_WORKFLOW_WAKE_DISPATCHER_PERIOD_MS = 10_000;
|
|
7
20
|
|
|
8
21
|
/**
|
|
@@ -1,6 +0,0 @@
|
|
|
1
|
-
import { type Database } from "@opengeni/db";
|
|
2
|
-
import { type AccessGrantAuthorization } from "../access/index.js";
|
|
3
|
-
/** Direct user admission only. Agents inherit exact accepted snapshots instead.
|
|
4
|
-
* Native and externally represented users share owner semantics; service keys
|
|
5
|
-
* cannot impersonate a human owner merely by naming a subject. */
|
|
6
|
-
export declare function prepareHostMcpOwnerAuthorization(authorization: AccessGrantAuthorization, workspaceId: string, permission: "connections:read" | "connections:write"): (tx: Database) => Promise<import("@opengeni/db").HostMcpBindingOwner>;
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
import type { Context } from "hono";
|
|
2
|
-
import { type AccessDeps } from "../access/index.js";
|
|
3
|
-
export declare function hostMcpResolverForRequest(context: Context, deps: AccessDeps, organizationId: string, source: string, method: "get" | "put" | "revoke", raw?: unknown): Promise<{
|
|
4
|
-
id: string;
|
|
5
|
-
organizationId: string;
|
|
6
|
-
externalSource: string;
|
|
7
|
-
url: string;
|
|
8
|
-
timeoutMs: number;
|
|
9
|
-
generation: number;
|
|
10
|
-
status: "active" | "revoked";
|
|
11
|
-
createdAt: string;
|
|
12
|
-
updatedAt: string;
|
|
13
|
-
}>;
|
package/dist/chunk-5WZYFL45.js
DELETED
|
@@ -1,266 +0,0 @@
|
|
|
1
|
-
// src/remote-mcp-credentials.ts
|
|
2
|
-
import { environmentsEncryptionKeyBytes } from "@opengeni/config";
|
|
3
|
-
import {
|
|
4
|
-
resolveHostMcpResolverRoute,
|
|
5
|
-
hostMcpResolverRouteIsCurrent
|
|
6
|
-
} from "@opengeni/db";
|
|
7
|
-
import {
|
|
8
|
-
McpConnectionResourceScope,
|
|
9
|
-
hostMcpCredentialUseGuard
|
|
10
|
-
} from "@opengeni/contracts";
|
|
11
|
-
import { pinnedFetch, readResponseJsonBounded, validateHttpUrl } from "@opengeni/network";
|
|
12
|
-
import { z } from "zod";
|
|
13
|
-
var configuration = z.array(
|
|
14
|
-
z.object({
|
|
15
|
-
accountId: z.string().uuid(),
|
|
16
|
-
url: z.string().max(2048),
|
|
17
|
-
bearerToken: z.string().min(1).max(8192).regex(/^[^\r\n]+$/),
|
|
18
|
-
timeoutMs: z.number().int().min(100).max(3e4).default(1e4)
|
|
19
|
-
}).strict()
|
|
20
|
-
).max(128);
|
|
21
|
-
var scope = {
|
|
22
|
-
accountId: z.string(),
|
|
23
|
-
workspaceId: z.string(),
|
|
24
|
-
sessionId: z.string(),
|
|
25
|
-
providerDomain: z.string(),
|
|
26
|
-
provider: z.string().optional(),
|
|
27
|
-
scopes: z.array(z.string()).max(256).optional(),
|
|
28
|
-
resource: z.string().optional(),
|
|
29
|
-
selectedResources: z.array(McpConnectionResourceScope).max(256).optional()
|
|
30
|
-
};
|
|
31
|
-
var resolution = z.discriminatedUnion("status", [
|
|
32
|
-
z.object({
|
|
33
|
-
...scope,
|
|
34
|
-
status: z.literal("ok"),
|
|
35
|
-
connectionId: z.string().min(1),
|
|
36
|
-
headers: z.record(z.string(), z.string()),
|
|
37
|
-
placements: z.array(
|
|
38
|
-
z.object({
|
|
39
|
-
carrier: z.enum(["header", "query", "cookie"]),
|
|
40
|
-
name: z.string(),
|
|
41
|
-
value: z.string(),
|
|
42
|
-
prefix: z.string().optional()
|
|
43
|
-
}).strict()
|
|
44
|
-
).max(64).optional(),
|
|
45
|
-
expiresAt: z.string().datetime({ offset: true })
|
|
46
|
-
}).strict(),
|
|
47
|
-
z.object({
|
|
48
|
-
...scope,
|
|
49
|
-
status: z.literal("auth_needed"),
|
|
50
|
-
connectionId: z.string().optional(),
|
|
51
|
-
reason: z.enum([
|
|
52
|
-
"missing_connection",
|
|
53
|
-
"expired",
|
|
54
|
-
"insufficient_scope",
|
|
55
|
-
"refresh_failed",
|
|
56
|
-
"personal_authority_unavailable",
|
|
57
|
-
"unsupported_auth",
|
|
58
|
-
"resource_scope_unavailable"
|
|
59
|
-
]),
|
|
60
|
-
authorizationUrl: z.string().optional()
|
|
61
|
-
}).strict()
|
|
62
|
-
]);
|
|
63
|
-
var gatewayResolution = z.discriminatedUnion("status", [
|
|
64
|
-
resolution.options[0].omit({ sessionId: true }).extend({ requestId: z.string().uuid() }),
|
|
65
|
-
resolution.options[1].omit({ sessionId: true }).extend({ requestId: z.string().uuid() })
|
|
66
|
-
]);
|
|
67
|
-
var responseEnvelope = z.object({
|
|
68
|
-
version: z.literal(1),
|
|
69
|
-
requestId: z.string().uuid(),
|
|
70
|
-
destinationUrl: z.string(),
|
|
71
|
-
resolution: z.union([resolution, gatewayResolution])
|
|
72
|
-
}).strict();
|
|
73
|
-
function normalizeResolution(value) {
|
|
74
|
-
const common = {
|
|
75
|
-
accountId: value.accountId,
|
|
76
|
-
workspaceId: value.workspaceId,
|
|
77
|
-
..."sessionId" in value ? { sessionId: value.sessionId } : { requestId: value.requestId },
|
|
78
|
-
providerDomain: value.providerDomain,
|
|
79
|
-
...value.provider !== void 0 ? { provider: value.provider } : {},
|
|
80
|
-
...value.scopes !== void 0 ? { scopes: value.scopes } : {},
|
|
81
|
-
...value.resource !== void 0 ? { resource: value.resource } : {},
|
|
82
|
-
...value.selectedResources !== void 0 ? { selectedResources: value.selectedResources } : {}
|
|
83
|
-
};
|
|
84
|
-
if (value.status === "auth_needed")
|
|
85
|
-
return {
|
|
86
|
-
...common,
|
|
87
|
-
status: "auth_needed",
|
|
88
|
-
reason: value.reason,
|
|
89
|
-
...value.connectionId !== void 0 ? { connectionId: value.connectionId } : {},
|
|
90
|
-
...value.authorizationUrl !== void 0 ? { authorizationUrl: value.authorizationUrl } : {}
|
|
91
|
-
};
|
|
92
|
-
return {
|
|
93
|
-
...common,
|
|
94
|
-
status: "ok",
|
|
95
|
-
connectionId: value.connectionId,
|
|
96
|
-
headers: value.headers,
|
|
97
|
-
expiresAt: value.expiresAt,
|
|
98
|
-
...value.placements !== void 0 ? {
|
|
99
|
-
placements: value.placements.map((placement) => ({
|
|
100
|
-
carrier: placement.carrier,
|
|
101
|
-
name: placement.name,
|
|
102
|
-
value: placement.value,
|
|
103
|
-
...placement.prefix !== void 0 ? { prefix: placement.prefix } : {}
|
|
104
|
-
}))
|
|
105
|
-
} : {}
|
|
106
|
-
};
|
|
107
|
-
}
|
|
108
|
-
function createRemoteMcpCredentialsPort(settings, transport = pinnedFetch, routes) {
|
|
109
|
-
if (!settings.hostMcpCredentialResolversJson && !routes) return {};
|
|
110
|
-
let entries;
|
|
111
|
-
try {
|
|
112
|
-
entries = configuration.parse(JSON.parse(settings.hostMcpCredentialResolversJson || "[]"));
|
|
113
|
-
for (const entry of entries) validateHttpUrl(entry.url);
|
|
114
|
-
if (new Set(entries.map((entry) => entry.accountId)).size !== entries.length) throw new Error();
|
|
115
|
-
} catch {
|
|
116
|
-
throw new Error("Invalid host MCP credential resolver configuration");
|
|
117
|
-
}
|
|
118
|
-
const byAccount = new Map(entries.map((entry) => [entry.accountId, entry]));
|
|
119
|
-
const active = /* @__PURE__ */ new Map();
|
|
120
|
-
let physicalRequests = 0;
|
|
121
|
-
const resolveRemote = async (input) => {
|
|
122
|
-
const serialized = JSON.stringify(input);
|
|
123
|
-
const request = JSON.parse(serialized);
|
|
124
|
-
const unavailable = (reason) => ({
|
|
125
|
-
status: "auth_needed",
|
|
126
|
-
accountId: request.accountId,
|
|
127
|
-
workspaceId: request.workspaceId,
|
|
128
|
-
..."sessionId" in request ? { sessionId: request.sessionId } : { requestId: request.requestId },
|
|
129
|
-
providerDomain: request.connectionRef.providerDomain,
|
|
130
|
-
...request.connectionRef.provider !== void 0 ? { provider: request.connectionRef.provider } : {},
|
|
131
|
-
...request.connectionRef.connectionId !== void 0 ? { connectionId: request.connectionRef.connectionId } : {},
|
|
132
|
-
...request.connectionRef.scopes !== void 0 ? { scopes: request.connectionRef.scopes } : {},
|
|
133
|
-
...request.connectionRef.resource !== void 0 ? { resource: request.connectionRef.resource } : {},
|
|
134
|
-
...request.connectionRef.selectedResources !== void 0 ? { selectedResources: request.connectionRef.selectedResources } : {},
|
|
135
|
-
reason
|
|
136
|
-
});
|
|
137
|
-
let route = { mode: "legacy" };
|
|
138
|
-
try {
|
|
139
|
-
if (routes) route = await routes.resolve(request);
|
|
140
|
-
} catch {
|
|
141
|
-
return unavailable("refresh_failed");
|
|
142
|
-
}
|
|
143
|
-
if (route.mode === "denied") return unavailable("unsupported_auth");
|
|
144
|
-
const config = route.mode === "namespace" ? route : byAccount.get(request.accountId);
|
|
145
|
-
if (!config || request.connectionRef.authoritySource !== "host")
|
|
146
|
-
return unavailable("unsupported_auth");
|
|
147
|
-
const current = async () => {
|
|
148
|
-
try {
|
|
149
|
-
return routes ? await routes.isCurrent(request, route) : true;
|
|
150
|
-
} catch {
|
|
151
|
-
return false;
|
|
152
|
-
}
|
|
153
|
-
};
|
|
154
|
-
const finish = async (value) => {
|
|
155
|
-
if (!await current()) return unavailable("refresh_failed");
|
|
156
|
-
const result = structuredClone(value);
|
|
157
|
-
if (result.status === "ok" && routes) result[hostMcpCredentialUseGuard] = current;
|
|
158
|
-
return result;
|
|
159
|
-
};
|
|
160
|
-
if (new TextEncoder().encode(serialized).byteLength > 65536)
|
|
161
|
-
return unavailable("refresh_failed");
|
|
162
|
-
const activeKey = JSON.stringify([
|
|
163
|
-
route.mode === "namespace" ? [route.id, route.generation] : "legacy",
|
|
164
|
-
serialized
|
|
165
|
-
]);
|
|
166
|
-
const pending = active.get(activeKey);
|
|
167
|
-
if (pending) return finish(await pending);
|
|
168
|
-
if (physicalRequests >= 128) return unavailable("refresh_failed");
|
|
169
|
-
const run = async () => {
|
|
170
|
-
const requestId = crypto.randomUUID();
|
|
171
|
-
const controller = new AbortController();
|
|
172
|
-
let timer;
|
|
173
|
-
const deadline = new Promise((_, reject) => {
|
|
174
|
-
timer = setTimeout(() => {
|
|
175
|
-
controller.abort();
|
|
176
|
-
reject(new Error("Host resolver deadline"));
|
|
177
|
-
}, config.timeoutMs);
|
|
178
|
-
});
|
|
179
|
-
try {
|
|
180
|
-
physicalRequests++;
|
|
181
|
-
return await Promise.race([
|
|
182
|
-
deadline,
|
|
183
|
-
(async () => {
|
|
184
|
-
if (!await current()) return unavailable("refresh_failed");
|
|
185
|
-
const response = await transport(
|
|
186
|
-
config.url,
|
|
187
|
-
{
|
|
188
|
-
method: "POST",
|
|
189
|
-
redirect: "manual",
|
|
190
|
-
signal: controller.signal,
|
|
191
|
-
headers: {
|
|
192
|
-
Authorization: `Bearer ${config.bearerToken}`,
|
|
193
|
-
"Content-Type": "application/json"
|
|
194
|
-
},
|
|
195
|
-
body: JSON.stringify({ version: 1, requestId, request })
|
|
196
|
-
},
|
|
197
|
-
settings,
|
|
198
|
-
{ requireHttpsOutsideLocalTest: true, label: "Host MCP credential resolver" }
|
|
199
|
-
);
|
|
200
|
-
if (!response.ok) {
|
|
201
|
-
await response.body?.cancel();
|
|
202
|
-
return unavailable("refresh_failed");
|
|
203
|
-
}
|
|
204
|
-
const parsed = responseEnvelope.parse(
|
|
205
|
-
await readResponseJsonBounded(response, 65536, "Host MCP credential resolver", {
|
|
206
|
-
signal: controller.signal
|
|
207
|
-
})
|
|
208
|
-
);
|
|
209
|
-
if (parsed.requestId !== requestId || parsed.destinationUrl !== request.destinationUrl || parsed.resolution.accountId !== request.accountId || parsed.resolution.workspaceId !== request.workspaceId || ("sessionId" in request ? !("sessionId" in parsed.resolution) || parsed.resolution.sessionId !== request.sessionId : !("requestId" in parsed.resolution) || parsed.resolution.requestId !== request.requestId))
|
|
210
|
-
return unavailable("refresh_failed");
|
|
211
|
-
if (parsed.resolution.status === "ok" && (Date.parse(parsed.resolution.expiresAt) <= Date.now() + 5e3 || Date.parse(parsed.resolution.expiresAt) > Date.now() + 9e5)) {
|
|
212
|
-
return unavailable("refresh_failed");
|
|
213
|
-
}
|
|
214
|
-
return normalizeResolution(parsed.resolution);
|
|
215
|
-
})().finally(() => {
|
|
216
|
-
physicalRequests--;
|
|
217
|
-
})
|
|
218
|
-
]);
|
|
219
|
-
} catch {
|
|
220
|
-
return unavailable("refresh_failed");
|
|
221
|
-
} finally {
|
|
222
|
-
clearTimeout(timer);
|
|
223
|
-
}
|
|
224
|
-
};
|
|
225
|
-
const task = run();
|
|
226
|
-
active.set(activeKey, task);
|
|
227
|
-
try {
|
|
228
|
-
return finish(await task);
|
|
229
|
-
} finally {
|
|
230
|
-
if (active.get(activeKey) === task) active.delete(activeKey);
|
|
231
|
-
}
|
|
232
|
-
};
|
|
233
|
-
return {
|
|
234
|
-
mcpAuthoritySource: "host",
|
|
235
|
-
async mcpCredentials(input) {
|
|
236
|
-
const result = await resolveRemote(input);
|
|
237
|
-
if (!("sessionId" in result)) throw new Error("Invalid host turn credential scope");
|
|
238
|
-
return result;
|
|
239
|
-
},
|
|
240
|
-
async mcpGatewayCredentials(input) {
|
|
241
|
-
const result = await resolveRemote(input);
|
|
242
|
-
if (!("requestId" in result)) throw new Error("Invalid host gateway credential scope");
|
|
243
|
-
return result;
|
|
244
|
-
}
|
|
245
|
-
};
|
|
246
|
-
}
|
|
247
|
-
function createNativeRemoteMcpCredentialsPort(settings, db, transport = pinnedFetch) {
|
|
248
|
-
return createRemoteMcpCredentialsPort(settings, transport, {
|
|
249
|
-
resolve: (request) => resolveHostMcpResolverRoute(db, request, environmentsEncryptionKeyBytes(settings)),
|
|
250
|
-
isCurrent: (request, route) => hostMcpResolverRouteIsCurrent(db, request, route)
|
|
251
|
-
});
|
|
252
|
-
}
|
|
253
|
-
function hasLegacyHostMcpResolver(settings, accountId) {
|
|
254
|
-
try {
|
|
255
|
-
return configuration.parse(JSON.parse(settings.hostMcpCredentialResolversJson || "[]")).some((entry) => entry.accountId === accountId);
|
|
256
|
-
} catch {
|
|
257
|
-
throw new Error("Invalid host MCP credential resolver configuration");
|
|
258
|
-
}
|
|
259
|
-
}
|
|
260
|
-
|
|
261
|
-
export {
|
|
262
|
-
createRemoteMcpCredentialsPort,
|
|
263
|
-
createNativeRemoteMcpCredentialsPort,
|
|
264
|
-
hasLegacyHostMcpResolver
|
|
265
|
-
};
|
|
266
|
-
//# sourceMappingURL=chunk-5WZYFL45.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/remote-mcp-credentials.ts"],"sourcesContent":["import type { Settings } from \"@opengeni/config\";\nimport { environmentsEncryptionKeyBytes } from \"@opengeni/config\";\nimport {\n resolveHostMcpResolverRoute,\n hostMcpResolverRouteIsCurrent,\n type Database,\n type HostMcpResolverRoute,\n} from \"@opengeni/db\";\nimport {\n McpConnectionResourceScope,\n hostMcpCredentialUseGuard,\n type ConnectionCredentialsPort,\n type McpCredentialsRequest,\n type McpCredentialResolution,\n type McpGatewayCredentialsRequest,\n type McpGatewayCredentialResolution,\n} from \"@opengeni/contracts\";\nimport { pinnedFetch, readResponseJsonBounded, validateHttpUrl } from \"@opengeni/network\";\nimport { z } from \"zod\";\n\nconst configuration = z\n .array(\n z\n .object({\n accountId: z.string().uuid(),\n url: z.string().max(2048),\n bearerToken: z\n .string()\n .min(1)\n .max(8192)\n .regex(/^[^\\r\\n]+$/),\n timeoutMs: z.number().int().min(100).max(30_000).default(10_000),\n })\n .strict(),\n )\n .max(128);\n\nconst scope = {\n accountId: z.string(),\n workspaceId: z.string(),\n sessionId: z.string(),\n providerDomain: z.string(),\n provider: z.string().optional(),\n scopes: z.array(z.string()).max(256).optional(),\n resource: z.string().optional(),\n selectedResources: z.array(McpConnectionResourceScope).max(256).optional(),\n};\nconst resolution = z.discriminatedUnion(\"status\", [\n z\n .object({\n ...scope,\n status: z.literal(\"ok\"),\n connectionId: z.string().min(1),\n headers: z.record(z.string(), z.string()),\n placements: z\n .array(\n z\n .object({\n carrier: z.enum([\"header\", \"query\", \"cookie\"]),\n name: z.string(),\n value: z.string(),\n prefix: z.string().optional(),\n })\n .strict(),\n )\n .max(64)\n .optional(),\n expiresAt: z.string().datetime({ offset: true }),\n })\n .strict(),\n z\n .object({\n ...scope,\n status: z.literal(\"auth_needed\"),\n connectionId: z.string().optional(),\n reason: z.enum([\n \"missing_connection\",\n \"expired\",\n \"insufficient_scope\",\n \"refresh_failed\",\n \"personal_authority_unavailable\",\n \"unsupported_auth\",\n \"resource_scope_unavailable\",\n ]),\n authorizationUrl: z.string().optional(),\n })\n .strict(),\n]);\nconst gatewayResolution = z.discriminatedUnion(\"status\", [\n resolution.options[0].omit({ sessionId: true }).extend({ requestId: z.string().uuid() }),\n resolution.options[1].omit({ sessionId: true }).extend({ requestId: z.string().uuid() }),\n]);\nconst responseEnvelope = z\n .object({\n version: z.literal(1),\n requestId: z.string().uuid(),\n destinationUrl: z.string(),\n resolution: z.union([resolution, gatewayResolution]),\n })\n .strict();\n\ntype RemoteResolution = McpCredentialResolution | McpGatewayCredentialResolution;\nfunction normalizeResolution(\n value: z.infer<typeof resolution> | z.infer<typeof gatewayResolution>,\n): RemoteResolution {\n const common = {\n accountId: value.accountId,\n workspaceId: value.workspaceId,\n ...(\"sessionId\" in value ? { sessionId: value.sessionId } : { requestId: value.requestId }),\n providerDomain: value.providerDomain,\n ...(value.provider !== undefined ? { provider: value.provider } : {}),\n ...(value.scopes !== undefined ? { scopes: value.scopes } : {}),\n ...(value.resource !== undefined ? { resource: value.resource } : {}),\n ...(value.selectedResources !== undefined\n ? { selectedResources: value.selectedResources }\n : {}),\n };\n if (value.status === \"auth_needed\")\n return {\n ...common,\n status: \"auth_needed\",\n reason: value.reason,\n ...(value.connectionId !== undefined ? { connectionId: value.connectionId } : {}),\n ...(value.authorizationUrl !== undefined ? { authorizationUrl: value.authorizationUrl } : {}),\n };\n return {\n ...common,\n status: \"ok\",\n connectionId: value.connectionId,\n headers: value.headers,\n expiresAt: value.expiresAt,\n ...(value.placements !== undefined\n ? {\n placements: value.placements.map((placement) => ({\n carrier: placement.carrier,\n name: placement.name,\n value: placement.value,\n ...(placement.prefix !== undefined ? { prefix: placement.prefix } : {}),\n })),\n }\n : {}),\n };\n}\n\n/** Optional standalone transport for the existing request-time host port.\n * No successful credential is cached or persisted. The host must authorize\n * every immutable request context, including revocation and binding generation.\n */\nexport function createRemoteMcpCredentialsPort(\n settings: Pick<\n Settings,\n \"hostMcpCredentialResolversJson\" | \"environment\" | \"integrationsAllowPrivateNetworkTargets\"\n >,\n transport: typeof pinnedFetch = pinnedFetch,\n routes?: {\n resolve: (input: { accountId: string; workspaceId: string }) => Promise<HostMcpResolverRoute>;\n isCurrent: (\n input: { accountId: string; workspaceId: string },\n route: HostMcpResolverRoute,\n ) => Promise<boolean>;\n },\n): ConnectionCredentialsPort {\n if (!settings.hostMcpCredentialResolversJson && !routes) return {};\n let entries: z.infer<typeof configuration>;\n try {\n entries = configuration.parse(JSON.parse(settings.hostMcpCredentialResolversJson || \"[]\"));\n for (const entry of entries) validateHttpUrl(entry.url);\n if (new Set(entries.map((entry) => entry.accountId)).size !== entries.length) throw new Error();\n } catch {\n // Configuration includes credentials: never return parser input or causes.\n throw new Error(\"Invalid host MCP credential resolver configuration\");\n }\n const byAccount = new Map(entries.map((entry) => [entry.accountId, entry]));\n const active = new Map<string, Promise<RemoteResolution>>();\n let physicalRequests = 0;\n const resolveRemote = async (\n input: McpCredentialsRequest | McpGatewayCredentialsRequest,\n ): Promise<RemoteResolution> => {\n const serialized = JSON.stringify(input);\n const request: McpCredentialsRequest | McpGatewayCredentialsRequest = JSON.parse(serialized);\n const unavailable = (reason: \"unsupported_auth\" | \"refresh_failed\"): RemoteResolution => ({\n status: \"auth_needed\",\n accountId: request.accountId,\n workspaceId: request.workspaceId,\n ...(\"sessionId\" in request\n ? { sessionId: request.sessionId }\n : { requestId: request.requestId }),\n providerDomain: request.connectionRef.providerDomain,\n ...(request.connectionRef.provider !== undefined\n ? { provider: request.connectionRef.provider }\n : {}),\n ...(request.connectionRef.connectionId !== undefined\n ? { connectionId: request.connectionRef.connectionId }\n : {}),\n ...(request.connectionRef.scopes !== undefined\n ? { scopes: request.connectionRef.scopes }\n : {}),\n ...(request.connectionRef.resource !== undefined\n ? { resource: request.connectionRef.resource }\n : {}),\n ...(request.connectionRef.selectedResources !== undefined\n ? { selectedResources: request.connectionRef.selectedResources }\n : {}),\n reason,\n });\n let route: HostMcpResolverRoute = { mode: \"legacy\" };\n try {\n if (routes) route = await routes.resolve(request);\n } catch {\n return unavailable(\"refresh_failed\");\n }\n if (route.mode === \"denied\") return unavailable(\"unsupported_auth\");\n const config = route.mode === \"namespace\" ? route : byAccount.get(request.accountId);\n if (!config || request.connectionRef.authoritySource !== \"host\")\n return unavailable(\"unsupported_auth\");\n const current = async () => {\n try {\n return routes ? await routes.isCurrent(request, route) : true;\n } catch {\n return false;\n }\n };\n const finish = async (value: RemoteResolution): Promise<RemoteResolution> => {\n if (!(await current())) return unavailable(\"refresh_failed\");\n const result = structuredClone(value);\n if (result.status === \"ok\" && routes) result[hostMcpCredentialUseGuard] = current;\n return result;\n };\n // Snapshot before any asynchronous operation; never retain mutable caller\n // objects as the authority for a delayed response.\n if (new TextEncoder().encode(serialized).byteLength > 65_536)\n return unavailable(\"refresh_failed\");\n const activeKey = JSON.stringify([\n route.mode === \"namespace\" ? [route.id, route.generation] : \"legacy\",\n serialized,\n ]);\n const pending = active.get(activeKey);\n if (pending) return finish(await pending);\n if (physicalRequests >= 128) return unavailable(\"refresh_failed\");\n const run = async (): Promise<RemoteResolution> => {\n const requestId = crypto.randomUUID();\n const controller = new AbortController();\n let timer: ReturnType<typeof setTimeout> | undefined;\n const deadline = new Promise<never>((_, reject) => {\n timer = setTimeout(() => {\n controller.abort();\n reject(new Error(\"Host resolver deadline\"));\n }, config.timeoutMs);\n });\n try {\n physicalRequests++;\n return await Promise.race([\n deadline,\n (async () => {\n if (!(await current())) return unavailable(\"refresh_failed\");\n const response = await transport(\n config.url,\n {\n method: \"POST\",\n redirect: \"manual\",\n signal: controller.signal,\n headers: {\n Authorization: `Bearer ${config.bearerToken}`,\n \"Content-Type\": \"application/json\",\n },\n body: JSON.stringify({ version: 1, requestId, request }),\n },\n settings,\n { requireHttpsOutsideLocalTest: true, label: \"Host MCP credential resolver\" },\n );\n if (!response.ok) {\n await response.body?.cancel();\n return unavailable(\"refresh_failed\");\n }\n const parsed = responseEnvelope.parse(\n await readResponseJsonBounded(response, 65_536, \"Host MCP credential resolver\", {\n signal: controller.signal,\n }),\n );\n if (\n parsed.requestId !== requestId ||\n parsed.destinationUrl !== request.destinationUrl ||\n parsed.resolution.accountId !== request.accountId ||\n parsed.resolution.workspaceId !== request.workspaceId ||\n (\"sessionId\" in request\n ? !(\"sessionId\" in parsed.resolution) ||\n parsed.resolution.sessionId !== request.sessionId\n : !(\"requestId\" in parsed.resolution) ||\n parsed.resolution.requestId !== request.requestId)\n )\n return unavailable(\"refresh_failed\");\n if (\n parsed.resolution.status === \"ok\" &&\n (Date.parse(parsed.resolution.expiresAt) <= Date.now() + 5_000 ||\n Date.parse(parsed.resolution.expiresAt) > Date.now() + 900_000)\n ) {\n return unavailable(\"refresh_failed\");\n }\n // Existing buildHostConnectionTokenResolver validates the precise\n // connection, provider, scopes, resources and credential placements.\n return normalizeResolution(parsed.resolution);\n })().finally(() => {\n physicalRequests--;\n }),\n ]);\n } catch {\n return unavailable(\"refresh_failed\");\n } finally {\n clearTimeout(timer);\n }\n };\n const task = run();\n active.set(activeKey, task);\n try {\n return finish(await task);\n } finally {\n if (active.get(activeKey) === task) active.delete(activeKey);\n }\n };\n return {\n mcpAuthoritySource: \"host\",\n async mcpCredentials(input) {\n const result = await resolveRemote(input);\n if (!(\"sessionId\" in result)) throw new Error(\"Invalid host turn credential scope\");\n return result;\n },\n async mcpGatewayCredentials(input) {\n const result = await resolveRemote(input);\n if (!(\"requestId\" in result)) throw new Error(\"Invalid host gateway credential scope\");\n return result;\n },\n };\n}\n\n/** Native standalone transport; the database remains authoritative on every\n * resolution/use. Embedded in-process ports retain their existing precedence. */\nexport function createNativeRemoteMcpCredentialsPort(\n settings: Settings,\n db: Database,\n transport: typeof pinnedFetch = pinnedFetch,\n): ConnectionCredentialsPort {\n return createRemoteMcpCredentialsPort(settings, transport, {\n resolve: (request) =>\n resolveHostMcpResolverRoute(db, request, environmentsEncryptionKeyBytes(settings)),\n isCurrent: (request, route) => hostMcpResolverRouteIsCurrent(db, request, route),\n });\n}\n\n/** Parses only server configuration; never return parser errors containing secrets. */\nexport function hasLegacyHostMcpResolver(\n settings: Pick<Settings, \"hostMcpCredentialResolversJson\">,\n accountId: string,\n): boolean {\n try {\n return configuration\n .parse(JSON.parse(settings.hostMcpCredentialResolversJson || \"[]\"))\n .some((entry) => entry.accountId === accountId);\n } catch {\n throw new Error(\"Invalid host MCP credential resolver configuration\");\n }\n}\n"],"mappings":"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","names":[]}
|