@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
|
@@ -7,6 +7,14 @@ import {
|
|
|
7
7
|
} from "./chunk-QO5GVFFO.js";
|
|
8
8
|
|
|
9
9
|
// src/managed-session.ts
|
|
10
|
+
import { AsyncLocalStorage } from "async_hooks";
|
|
11
|
+
import { createHmac } from "crypto";
|
|
12
|
+
import { managedUserEmailAllowed } from "@opengeni/config";
|
|
13
|
+
import {
|
|
14
|
+
DatabaseUnavailableError,
|
|
15
|
+
isDatabaseConnectionLoss,
|
|
16
|
+
isRetryableDatabaseTransportFailure
|
|
17
|
+
} from "@opengeni/db";
|
|
10
18
|
import {
|
|
11
19
|
acquireManagedAuthActorMutationLease,
|
|
12
20
|
getManagedAuthAdoptedSessionSnapshot,
|
|
@@ -18,6 +26,36 @@ import {
|
|
|
18
26
|
} from "@opengeni/db/managed-auth-session-sets";
|
|
19
27
|
import { validateCanonicalHumanSession } from "@opengeni/db/canonical-human-identities";
|
|
20
28
|
import { HTTPException } from "hono/http-exception";
|
|
29
|
+
var managedAuthLookupFailures = new AsyncLocalStorage();
|
|
30
|
+
var MANAGED_AUTH_LOOKUP_FAILURE_LIMIT = 8;
|
|
31
|
+
function recordManagedAuthLoggedFailure(args) {
|
|
32
|
+
const store = managedAuthLookupFailures.getStore();
|
|
33
|
+
if (!store) return;
|
|
34
|
+
for (const value of args) {
|
|
35
|
+
if (store.errors.length >= MANAGED_AUTH_LOOKUP_FAILURE_LIMIT) return;
|
|
36
|
+
if (value && typeof value === "object") store.errors.push(value);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
function isBetterAuthInternalServerError(error) {
|
|
40
|
+
if (!error || typeof error !== "object") return false;
|
|
41
|
+
const candidate = error;
|
|
42
|
+
return candidate.status === "INTERNAL_SERVER_ERROR" || candidate.statusCode === 500;
|
|
43
|
+
}
|
|
44
|
+
async function withManagedAuthSessionLookup(lookup) {
|
|
45
|
+
const store = { errors: [] };
|
|
46
|
+
try {
|
|
47
|
+
return await managedAuthLookupFailures.run(store, lookup);
|
|
48
|
+
} catch (error) {
|
|
49
|
+
if (isBetterAuthInternalServerError(error) && store.errors.some(
|
|
50
|
+
(logged) => isDatabaseConnectionLoss(logged) || isRetryableDatabaseTransportFailure(logged)
|
|
51
|
+
)) {
|
|
52
|
+
throw new DatabaseUnavailableError("managed auth session store unavailable", {
|
|
53
|
+
cause: error
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
throw error;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
21
59
|
var ACTOR_MUTATION_LEASE_SECONDS = 15 * 60;
|
|
22
60
|
var ACTOR_MUTATION_LEASE_REFRESH_MS = 5 * 60 * 1e3;
|
|
23
61
|
var ACTOR_MUTATION_HANDLER_DEADLINE_MS = 10 * 60 * 1e3;
|
|
@@ -35,7 +73,49 @@ var actorMutationLeaseRuntime = productionActorMutationLeaseRuntime;
|
|
|
35
73
|
var actorMutationLeaseByRequest = /* @__PURE__ */ new WeakMap();
|
|
36
74
|
var managedActorEpochByRequest = /* @__PURE__ */ new WeakMap();
|
|
37
75
|
var managedActorAdmissionByRequest = /* @__PURE__ */ new WeakMap();
|
|
38
|
-
|
|
76
|
+
var managedUserAllowlists = /* @__PURE__ */ new WeakMap();
|
|
77
|
+
function configureManagedUserAdmission(auth, emails) {
|
|
78
|
+
if (emails === void 0) managedUserAllowlists.delete(auth);
|
|
79
|
+
else managedUserAllowlists.set(auth, [...emails]);
|
|
80
|
+
}
|
|
81
|
+
async function getManagedSession(...args) {
|
|
82
|
+
const session = await resolveManagedSession(...args);
|
|
83
|
+
assertManagedUserAdmission(args[1], session?.user);
|
|
84
|
+
return session;
|
|
85
|
+
}
|
|
86
|
+
var NATIVE_APP_CREDENTIAL_PREFIX = "ogapp_";
|
|
87
|
+
async function getNativeAppManagedSession(auth, credential, db) {
|
|
88
|
+
if (!credential.startsWith(NATIVE_APP_CREDENTIAL_PREFIX)) return null;
|
|
89
|
+
const token = credential.slice(NATIVE_APP_CREDENTIAL_PREFIX.length);
|
|
90
|
+
if (!/^[A-Za-z0-9]{16,128}$/u.test(token)) return null;
|
|
91
|
+
const context = await auth.$context;
|
|
92
|
+
const signed = encodeURIComponent(
|
|
93
|
+
`${token}.${createHmac("sha256", context.secret).update(token, "utf8").digest("base64")}`
|
|
94
|
+
);
|
|
95
|
+
const session = await withManagedAuthSessionLookup(
|
|
96
|
+
() => auth.api.getSession({
|
|
97
|
+
headers: new Headers({ cookie: `${context.authCookies.sessionToken.name}=${signed}` }),
|
|
98
|
+
// Never serve a cached cookie snapshot: the app's session row is authoritative.
|
|
99
|
+
query: { disableCookieCache: true }
|
|
100
|
+
})
|
|
101
|
+
);
|
|
102
|
+
if (!session?.user) return null;
|
|
103
|
+
assertManagedUserAdmission(auth, session.user);
|
|
104
|
+
if (!db) return session;
|
|
105
|
+
const authSessionId = session.session?.id;
|
|
106
|
+
if (typeof authSessionId !== "string") return null;
|
|
107
|
+
const valid = await validateCanonicalHumanSession(db, {
|
|
108
|
+
authSessionId,
|
|
109
|
+
authUserId: session.user.id
|
|
110
|
+
});
|
|
111
|
+
return valid ? session : null;
|
|
112
|
+
}
|
|
113
|
+
function assertManagedUserAdmission(auth, user) {
|
|
114
|
+
const emails = managedUserAllowlists.get(auth);
|
|
115
|
+
if (user && emails !== void 0 && (!user.emailVerified || !managedUserEmailAllowed(emails, user.email)))
|
|
116
|
+
throw new HTTPException(403, { message: "Account is not permitted on this deployment" });
|
|
117
|
+
}
|
|
118
|
+
async function resolveManagedSession(c, auth, options) {
|
|
39
119
|
const sessionSetMode = options?.sessionSetMode ?? "legacy";
|
|
40
120
|
if (sessionSetMode !== "legacy" && options?.db && options.sessionAdapter) {
|
|
41
121
|
const authority = requestCookie(c.req.raw, MANAGED_AUTH_SESSION_SET_COOKIE);
|
|
@@ -149,10 +229,12 @@ async function getManagedSession(c, auth, options) {
|
|
|
149
229
|
throw error;
|
|
150
230
|
}
|
|
151
231
|
}
|
|
152
|
-
const result = await
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
232
|
+
const result = await withManagedAuthSessionLookup(
|
|
233
|
+
() => auth.api.getSession({
|
|
234
|
+
headers: c.req.raw.headers,
|
|
235
|
+
returnHeaders: true
|
|
236
|
+
})
|
|
237
|
+
);
|
|
156
238
|
for (const cookie of setCookieHeaders(result.headers)) {
|
|
157
239
|
c.header("set-cookie", cookie, { append: true });
|
|
158
240
|
}
|
|
@@ -356,7 +438,13 @@ function setCookieHeaders(headers) {
|
|
|
356
438
|
}
|
|
357
439
|
|
|
358
440
|
export {
|
|
441
|
+
recordManagedAuthLoggedFailure,
|
|
442
|
+
withManagedAuthSessionLookup,
|
|
443
|
+
configureManagedUserAdmission,
|
|
359
444
|
getManagedSession,
|
|
445
|
+
NATIVE_APP_CREDENTIAL_PREFIX,
|
|
446
|
+
getNativeAppManagedSession,
|
|
447
|
+
assertManagedUserAdmission,
|
|
360
448
|
getManagedAuthRequestActorEpoch,
|
|
361
449
|
releaseManagedAuthRequestActorLease,
|
|
362
450
|
getManagedAuthRequestActorAbortSignal,
|
|
@@ -366,4 +454,4 @@ export {
|
|
|
366
454
|
getManagedAuthRequestActorAdmissionStamp,
|
|
367
455
|
getManagedAuthRequestActorLeaseStamp
|
|
368
456
|
};
|
|
369
|
-
//# sourceMappingURL=chunk-
|
|
457
|
+
//# sourceMappingURL=chunk-TTWTXQB2.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/managed-session.ts"],"sourcesContent":["import { AsyncLocalStorage } from \"node:async_hooks\";\nimport { createHmac } from \"node:crypto\";\nimport { managedUserEmailAllowed } from \"@opengeni/config\";\nimport type { Context } from \"hono\";\nimport type { ManagedAuth } from \"./managed-auth-type\";\nimport {\n DatabaseUnavailableError,\n isDatabaseConnectionLoss,\n isRetryableDatabaseTransportFailure,\n type Database,\n} from \"@opengeni/db\";\nimport {\n acquireManagedAuthActorMutationLease,\n getManagedAuthAdoptedSessionSnapshot,\n getManagedAuthSessionSetSnapshot,\n ManagedAuthSessionSetAuthorityError,\n ManagedAuthSessionSetGenerationConflictError,\n releaseManagedAuthActorMutationLease,\n validateManagedAuthActorMutationLease,\n} from \"@opengeni/db/managed-auth-session-sets\";\nimport { validateCanonicalHumanSession } from \"@opengeni/db/canonical-human-identities\";\nimport type { ManagedAuthSessionSetMode } from \"@opengeni/contracts/managed-auth-session-sets\";\nimport { HTTPException } from \"hono/http-exception\";\nimport {\n MANAGED_AUTH_ACTOR_EPOCH_HEADER,\n MANAGED_AUTH_SESSION_SET_COOKIE,\n ManagedAuthActorChangeError,\n managedAuthSha256,\n resolveManagedAuthSelectedSession,\n type ManagedAuthSessionAdapter,\n} from \"./managed-auth-session-sets\";\n\n/**\n * Better Auth's session endpoint replaces every non-API failure with a generic\n * INTERNAL_SERVER_ERROR and passes the original only to its logger. A lookup run\n * through `withManagedAuthSessionLookup` collects what the logger saw, so a lost\n * database connection is reported as a retryable outage instead of an opaque 500.\n */\nconst managedAuthLookupFailures = new AsyncLocalStorage<{ errors: unknown[] }>();\nconst MANAGED_AUTH_LOOKUP_FAILURE_LIMIT = 8;\n\n/** Better Auth `logger.log` sink; a no-op outside a managed-auth session lookup. */\nexport function recordManagedAuthLoggedFailure(args: readonly unknown[]): void {\n const store = managedAuthLookupFailures.getStore();\n if (!store) return;\n for (const value of args) {\n if (store.errors.length >= MANAGED_AUTH_LOOKUP_FAILURE_LIMIT) return;\n if (value && typeof value === \"object\") store.errors.push(value);\n }\n}\n\nfunction isBetterAuthInternalServerError(error: unknown): boolean {\n if (!error || typeof error !== \"object\") return false;\n const candidate = error as { status?: unknown; statusCode?: unknown };\n return candidate.status === \"INTERNAL_SERVER_ERROR\" || candidate.statusCode === 500;\n}\n\nexport async function withManagedAuthSessionLookup<T>(lookup: () => Promise<T>): Promise<T> {\n const store = { errors: [] as unknown[] };\n try {\n return await managedAuthLookupFailures.run(store, lookup);\n } catch (error) {\n // Better Auth's session endpoint only reads its database adapter, so a\n // socket failure it logged is that adapter's connection, not another service.\n if (\n isBetterAuthInternalServerError(error) &&\n store.errors.some(\n (logged) => isDatabaseConnectionLoss(logged) || isRetryableDatabaseTransportFailure(logged),\n )\n ) {\n throw new DatabaseUnavailableError(\"managed auth session store unavailable\", {\n cause: error,\n });\n }\n throw error;\n }\n}\n\nconst ACTOR_MUTATION_LEASE_SECONDS = 15 * 60;\nconst ACTOR_MUTATION_LEASE_REFRESH_MS = 5 * 60 * 1_000;\nconst ACTOR_MUTATION_HANDLER_DEADLINE_MS = 10 * 60 * 1_000;\nconst ACTOR_MUTATION_FATAL_SAFETY_MS = 5_000;\ntype ActorMutationLeaseRuntime = {\n monotonicNow: () => number;\n schedule: (callback: () => void, delayMs: number) => ReturnType<typeof setTimeout>;\n cancel: (timer: ReturnType<typeof setTimeout>) => void;\n terminate: () => void;\n};\nconst productionActorMutationLeaseRuntime: ActorMutationLeaseRuntime = {\n monotonicNow: () => performance.now(),\n schedule: (callback, delayMs) => unrefTimer(setTimeout(callback, delayMs)),\n cancel: (timer) => clearTimeout(timer),\n terminate: () => {\n process.stderr.write(\"fatal: managed actor mutation outlived its durable lease\\n\");\n process.exit(1);\n },\n};\nlet actorMutationLeaseRuntime = productionActorMutationLeaseRuntime;\ntype ActorMutationLease = {\n db: Database;\n authorityHash: string;\n actorEpoch: string;\n requestId: string;\n refreshTimer: ReturnType<typeof setTimeout> | null;\n deadlineTimer: ReturnType<typeof setTimeout> | null;\n fatalTimer: ReturnType<typeof setTimeout> | null;\n expiresAt: Date;\n localFatalDeadlineMonotonicMs: number;\n runtime: ActorMutationLeaseRuntime;\n abortController: AbortController;\n poisoned: unknown | null;\n actorTransitionApplied: boolean;\n};\nconst actorMutationLeaseByRequest = new WeakMap<Request, ActorMutationLease>();\nconst managedActorEpochByRequest = new WeakMap<Request, string>();\nconst managedActorAdmissionByRequest = new WeakMap<Request, ManagedAuthActorAdmissionStamp>();\n\n/**\n * Read a Better Auth session without bypassing its sliding-cookie renewal.\n *\n * Better Auth can refresh the durable session while resolving `getSession`.\n * Programmatic callers must explicitly request and forward the returned cookie\n * headers; the HTTP handler does this automatically, but direct API calls do not.\n */\nconst managedUserAllowlists = new WeakMap<ManagedAuth, readonly string[]>();\n\n/** Bind admission to this auth instance, including all session-set modes. */\nexport function configureManagedUserAdmission(\n auth: ManagedAuth,\n emails: readonly string[] | undefined,\n): void {\n if (emails === undefined) managedUserAllowlists.delete(auth);\n else managedUserAllowlists.set(auth, [...emails]);\n}\n\nexport async function getManagedSession(...args: Parameters<typeof resolveManagedSession>) {\n const session = await resolveManagedSession(...args);\n assertManagedUserAdmission(args[1], session?.user);\n return session;\n}\n\n/**\n * Bearer prefix of a native app credential. The credential is a dedicated\n * Better Auth session the person approved from a signed-in browser (see the\n * native app sign-in route); the prefix only routes it to this resolver.\n */\nexport const NATIVE_APP_CREDENTIAL_PREFIX = \"ogapp_\";\n\n/**\n * Resolve a native app credential exactly as the legacy managed cookie path\n * resolves a browser session: Better Auth validates expiry and renews the\n * durable session, then the canonical human session must still be valid. A\n * native credential never reads or selects a browser session set; each app\n * account holds its own independently revocable session.\n */\nexport async function getNativeAppManagedSession(\n auth: ManagedAuth,\n credential: string,\n db: Database | undefined,\n) {\n if (!credential.startsWith(NATIVE_APP_CREDENTIAL_PREFIX)) return null;\n const token = credential.slice(NATIVE_APP_CREDENTIAL_PREFIX.length);\n if (!/^[A-Za-z0-9]{16,128}$/u.test(token)) return null;\n const context = await auth.$context;\n const signed = encodeURIComponent(\n `${token}.${createHmac(\"sha256\", context.secret).update(token, \"utf8\").digest(\"base64\")}`,\n );\n const session = await withManagedAuthSessionLookup(() =>\n auth.api.getSession({\n headers: new Headers({ cookie: `${context.authCookies.sessionToken.name}=${signed}` }),\n // Never serve a cached cookie snapshot: the app's session row is authoritative.\n query: { disableCookieCache: true },\n }),\n );\n if (!session?.user) return null;\n assertManagedUserAdmission(auth, session.user);\n if (!db) return session;\n const authSessionId = session.session?.id;\n if (typeof authSessionId !== \"string\") return null;\n const valid = await validateCanonicalHumanSession(db, {\n authSessionId,\n authUserId: session.user.id,\n });\n return valid ? session : null;\n}\n\nexport function assertManagedUserAdmission(\n auth: ManagedAuth,\n user: { email: string; emailVerified: boolean } | null | undefined,\n): void {\n const emails = managedUserAllowlists.get(auth);\n if (\n user &&\n emails !== undefined &&\n (!user.emailVerified || !managedUserEmailAllowed(emails, user.email))\n )\n throw new HTTPException(403, { message: \"Account is not permitted on this deployment\" });\n}\n\nasync function resolveManagedSession(\n c: Context,\n auth: ManagedAuth,\n options?: {\n db?: Database | undefined;\n allowIdentityRecovery?: boolean | undefined;\n sessionSetMode?: ManagedAuthSessionSetMode | undefined;\n sessionAdapter?: ManagedAuthSessionAdapter | null | undefined;\n },\n) {\n const sessionSetMode = options?.sessionSetMode ?? \"legacy\";\n if (sessionSetMode !== \"legacy\" && options?.db && options.sessionAdapter) {\n const authority = requestCookie(c.req.raw, MANAGED_AUTH_SESSION_SET_COOKIE);\n if (authority) {\n try {\n // A long-lived response reuses this exact Request for periodic\n // authorization. Once admitted, the server-owned stamp is the actor\n // fence: a client may omit the header on its initial GET, but a later\n // reauthorization must not follow a newly selected actor.\n const admittedActorEpoch = managedActorEpochByRequest.get(c.req.raw) ?? null;\n const expectedActorEpoch =\n admittedActorEpoch ?? c.req.header(MANAGED_AUTH_ACTOR_EPOCH_HEADER) ?? null;\n const legacyAmbient =\n sessionSetMode === \"dual\" && expectedActorEpoch === null\n ? await options.sessionAdapter.resolveAmbientSession(c.req.raw.headers)\n : null;\n const selected = await resolveManagedAuthSelectedSession({\n db: options.db,\n adapter: options.sessionAdapter,\n authority,\n mode: sessionSetMode,\n expectedActorEpoch,\n legacyAmbientSessionId:\n typeof legacyAmbient?.session?.id === \"string\" ? legacyAmbient.session.id : null,\n allowRecovery: options.allowIdentityRecovery ?? false,\n });\n if (selected) {\n // The actor epoch is both an admission fence and response provenance.\n // A browser must ignore a late finite response after another tab has\n // advanced selection, even when the request itself was read-only.\n if (admittedActorEpoch === null) {\n c.header(MANAGED_AUTH_ACTOR_EPOCH_HEADER, selected.projection.actorEpoch);\n managedActorEpochByRequest.set(c.req.raw, selected.projection.actorEpoch);\n }\n managedActorAdmissionByRequest.set(c.req.raw, {\n authorityHash: managedAuthSha256(authority),\n actorEpoch: selected.projection.actorEpoch,\n });\n }\n if (selected && !selected.session) return null;\n if (selected?.session) {\n let resolvedSession = selected.session;\n if (requestNeedsActorMutationLease(c.req.method)) {\n await ensureActorMutationLease(\n c.req.raw,\n options.db,\n authority,\n selected.projection.actorEpoch,\n );\n const selectedSlot = await selectedSlotForAuthority(\n options.db,\n authority,\n sessionSetMode,\n options.allowIdentityRecovery ?? false,\n );\n if (!selectedSlot) throw new ManagedAuthActorChangeError();\n const refreshed = await options.sessionAdapter.refreshSelectedSession(selectedSlot);\n if (\n !refreshed ||\n refreshed.session.id !== selectedSlot.authSessionId ||\n refreshed.user.id !== selectedSlot.authUserId\n ) {\n throw new ManagedAuthActorChangeError();\n }\n resolvedSession = refreshed;\n }\n return resolvedSession;\n }\n // Once a browser presents a session-set authority it is authoritative.\n // An absent/expired/rekeyed authority must never fall through to an\n // ambient Better Auth cookie in dual mode: that would bypass the actor\n // epoch and mutation-lease fences after another tab transitions.\n return null;\n } catch (error) {\n if (error instanceof ManagedAuthActorChangeError) {\n // Response headers are immutable after an SSE body starts. The\n // original response already carries its actor epoch; reauthorization\n // closes that stream through the thrown conflict instead.\n if (!managedActorEpochByRequest.has(c.req.raw)) {\n c.header(\"x-opengeni-actor-state\", \"changed\");\n }\n throw new HTTPException(409, { message: error.code, cause: error });\n }\n throw error;\n }\n }\n if (sessionSetMode === \"broker\") return null;\n const ambient = await options.sessionAdapter.resolveAmbientSession(c.req.raw.headers);\n if (ambient?.session?.id)\n try {\n const adopted = await getManagedAuthAdoptedSessionSnapshot(options.db, ambient.session.id);\n if (adopted) {\n const admittedActorEpoch = managedActorEpochByRequest.get(c.req.raw) ?? null;\n if (\n adopted.actorEpoch !== \"1\" ||\n (admittedActorEpoch !== null && adopted.actorEpoch !== admittedActorEpoch) ||\n !adopted.selected ||\n adopted.selected.authSessionId !== ambient.session.id ||\n adopted.selected.authUserId !== ambient.user.id\n ) {\n throw new ManagedAuthActorChangeError();\n }\n if (admittedActorEpoch === null) {\n c.header(MANAGED_AUTH_ACTOR_EPOCH_HEADER, adopted.actorEpoch);\n managedActorEpochByRequest.set(c.req.raw, adopted.actorEpoch);\n }\n managedActorAdmissionByRequest.set(c.req.raw, {\n authorityHash: adopted.authorityHash,\n actorEpoch: adopted.actorEpoch,\n });\n if (requestNeedsActorMutationLease(c.req.method)) {\n await ensureActorMutationLeaseForHash(\n c.req.raw,\n options.db,\n adopted.authorityHash,\n adopted.actorEpoch,\n );\n const current = await getManagedAuthAdoptedSessionSnapshot(\n options.db,\n ambient.session.id,\n );\n if (\n current?.authorityHash !== adopted.authorityHash ||\n current.actorEpoch !== adopted.actorEpoch ||\n !current.selected ||\n current.selected.authSessionId !== ambient.session.id\n ) {\n throw new ManagedAuthActorChangeError();\n }\n const refreshed = await options.sessionAdapter.refreshSelectedSession(current.selected);\n if (\n !refreshed ||\n refreshed.session.id !== ambient.session.id ||\n refreshed.user.id !== ambient.user.id\n ) {\n throw new ManagedAuthActorChangeError();\n }\n return refreshed;\n }\n return ambient;\n }\n } catch (error) {\n if (error instanceof ManagedAuthActorChangeError) {\n if (!managedActorEpochByRequest.has(c.req.raw)) {\n c.header(\"x-opengeni-actor-state\", \"changed\");\n }\n throw new HTTPException(409, { message: error.code, cause: error });\n }\n throw error;\n }\n }\n const result = await withManagedAuthSessionLookup(() =>\n auth.api.getSession({\n headers: c.req.raw.headers,\n returnHeaders: true,\n }),\n );\n\n for (const cookie of setCookieHeaders(result.headers)) {\n c.header(\"set-cookie\", cookie, { append: true });\n }\n\n const session = result.response;\n if (!session?.user || !options?.db) return session;\n const authSessionId = session.session?.id;\n if (typeof authSessionId !== \"string\") return null;\n const valid = await validateCanonicalHumanSession(options.db, {\n authSessionId,\n authUserId: session.user.id,\n ...(options.allowIdentityRecovery === undefined\n ? {}\n : { allowRecovery: options.allowIdentityRecovery }),\n });\n return valid ? session : null;\n}\n\n/** Safe response provenance for a request authenticated through session-set authority. */\nexport function getManagedAuthRequestActorEpoch(request: Request): string | null {\n return managedActorEpochByRequest.get(request) ?? null;\n}\n\nfunction selectedSlotForAuthority(\n db: Database,\n authority: string,\n mode: ManagedAuthSessionSetMode,\n allowRecovery: boolean,\n) {\n return getManagedAuthSessionSetSnapshot(db, {\n authorityHash: managedAuthSha256(authority),\n mode,\n includeInternal: true,\n allowRecovery,\n readOnly: true,\n }).then((snapshot) => snapshot?.selected ?? null);\n}\n\n/** Release the multi-replica actor fence after the outer HTTP handler settles. */\nexport async function releaseManagedAuthRequestActorLease(request: Request): Promise<void> {\n const lease = actorMutationLeaseByRequest.get(request);\n if (!lease) return;\n actorMutationLeaseByRequest.delete(request);\n if (lease.refreshTimer) lease.runtime.cancel(lease.refreshTimer);\n if (lease.deadlineTimer) lease.runtime.cancel(lease.deadlineTimer);\n if (lease.fatalTimer) lease.runtime.cancel(lease.fatalTimer);\n await releaseManagedAuthActorMutationLease(lease.db, {\n authorityHash: lease.authorityHash,\n requestId: lease.requestId,\n });\n}\n\n/** Cooperative cancellation signal for actor-scoped provider/external I/O. */\nexport function getManagedAuthRequestActorAbortSignal(request: Request): AbortSignal | null {\n return actorMutationLeaseByRequest.get(request)?.abortController.signal ?? null;\n}\n\n/** @internal Deterministic lease-clock seam used only by direct lifecycle tests. */\nexport function installManagedAuthActorLeaseRuntimeForTest(\n overrides: Partial<ActorMutationLeaseRuntime>,\n): () => void {\n const previous = actorMutationLeaseRuntime;\n actorMutationLeaseRuntime = {\n ...productionActorMutationLeaseRuntime,\n ...overrides,\n };\n return () => {\n actorMutationLeaseRuntime = previous;\n };\n}\n\n/**\n * Exact post-handler fence. A finite unsafe response is not released unless\n * its request-owned lease is still live at the same actor epoch.\n */\nexport async function validateManagedAuthRequestActorLease(request: Request): Promise<void> {\n const lease = actorMutationLeaseByRequest.get(request);\n if (!lease) return;\n if (lease.actorTransitionApplied) return;\n if (lease.poisoned !== null) {\n throw new ManagedAuthActorLeaseOutcomeUnknownError({\n cause: lease.poisoned,\n });\n }\n const valid = await validateManagedAuthActorMutationLease(lease.db, {\n authorityHash: lease.authorityHash,\n actorEpoch: lease.actorEpoch,\n requestId: lease.requestId,\n });\n if (!valid) throw new ManagedAuthActorChangeError();\n}\n\nexport class ManagedAuthActorLeaseOutcomeUnknownError extends Error {\n readonly name = \"ManagedAuthActorLeaseOutcomeUnknownError\";\n readonly code = \"operation_outcome_unknown\";\n constructor(options?: ErrorOptions) {\n super(\"The actor-scoped request outcome is unknown after its durable lease was lost\", options);\n }\n}\n\n/** A known-applied same-request canonical transition intentionally consumes its lease. */\nexport function markManagedAuthRequestActorTransitionApplied(request: Request): void {\n const lease = actorMutationLeaseByRequest.get(request);\n if (lease) lease.actorTransitionApplied = true;\n}\n\nexport type ManagedAuthActorMutationLeaseStamp = {\n authorityHash: string;\n actorEpoch: string;\n requestId: string;\n};\n\nexport type ManagedAuthActorAdmissionStamp = {\n authorityHash: string;\n actorEpoch: string;\n};\n\n/** Verified server-owned actor evidence available to both reads and mutations. */\nexport function getManagedAuthRequestActorAdmissionStamp(\n request: Request,\n): ManagedAuthActorAdmissionStamp | null {\n return managedActorAdmissionByRequest.get(request) ?? null;\n}\n\n/** Exact request-owned fence passed into a same-transaction actor transition. */\nexport function getManagedAuthRequestActorLeaseStamp(\n request: Request,\n): ManagedAuthActorMutationLeaseStamp | null {\n const lease = actorMutationLeaseByRequest.get(request);\n return lease\n ? {\n authorityHash: lease.authorityHash,\n actorEpoch: lease.actorEpoch,\n requestId: lease.requestId,\n }\n : null;\n}\n\nfunction requestNeedsActorMutationLease(method: string): boolean {\n return method !== \"GET\" && method !== \"HEAD\" && method !== \"OPTIONS\";\n}\n\nasync function ensureActorMutationLease(\n request: Request,\n db: Database,\n authority: string,\n actorEpoch: string,\n): Promise<void> {\n const authorityHash = managedAuthSha256(authority);\n await ensureActorMutationLeaseForHash(request, db, authorityHash, actorEpoch);\n}\n\nasync function ensureActorMutationLeaseForHash(\n request: Request,\n db: Database,\n authorityHash: string,\n actorEpoch: string,\n): Promise<void> {\n const existing = actorMutationLeaseByRequest.get(request);\n if (existing) {\n if (existing.authorityHash !== authorityHash || existing.actorEpoch !== actorEpoch) {\n throw new ManagedAuthActorChangeError();\n }\n return;\n }\n const lease: ActorMutationLease = {\n db,\n authorityHash,\n actorEpoch,\n requestId: crypto.randomUUID(),\n refreshTimer: null,\n deadlineTimer: null,\n fatalTimer: null,\n expiresAt: new Date(0),\n localFatalDeadlineMonotonicMs: 0,\n runtime: actorMutationLeaseRuntime,\n abortController: new AbortController(),\n poisoned: null,\n actorTransitionApplied: false,\n };\n const acquireStartedAtMonotonicMs = lease.runtime.monotonicNow();\n try {\n lease.expiresAt = await acquireManagedAuthActorMutationLease(db, {\n authorityHash,\n actorEpoch,\n requestId: lease.requestId,\n leaseSeconds: ACTOR_MUTATION_LEASE_SECONDS,\n });\n } catch (error) {\n if (\n error instanceof ManagedAuthSessionSetGenerationConflictError ||\n error instanceof ManagedAuthSessionSetAuthorityError\n ) {\n throw new ManagedAuthActorChangeError();\n }\n throw error;\n }\n lease.localFatalDeadlineMonotonicMs =\n acquireStartedAtMonotonicMs +\n ACTOR_MUTATION_LEASE_SECONDS * 1_000 -\n ACTOR_MUTATION_FATAL_SAFETY_MS;\n actorMutationLeaseByRequest.set(request, lease);\n scheduleActorMutationLeaseRefresh(request, lease);\n lease.deadlineTimer = lease.runtime.schedule(() => {\n poisonActorMutationLease(\n request,\n lease,\n new Error(\"managed actor mutation handler exceeded its bounded lifetime\"),\n );\n }, ACTOR_MUTATION_HANDLER_DEADLINE_MS);\n}\n\nfunction scheduleActorMutationLeaseRefresh(request: Request, lease: ActorMutationLease): void {\n const timer = lease.runtime.schedule(() => {\n if (actorMutationLeaseByRequest.get(request) !== lease) return;\n const refreshStartedAtMonotonicMs = lease.runtime.monotonicNow();\n void acquireManagedAuthActorMutationLease(lease.db, {\n authorityHash: lease.authorityHash,\n actorEpoch: lease.actorEpoch,\n requestId: lease.requestId,\n leaseSeconds: ACTOR_MUTATION_LEASE_SECONDS,\n })\n .then(async (expiresAt) => {\n if (actorMutationLeaseByRequest.get(request) !== lease) {\n // Release may have won while this pooled acquire statement was in\n // flight. Converge the just-renewed row immediately; never resurrect\n // a request-owned fence after the outer handler has settled.\n await releaseManagedAuthActorMutationLease(lease.db, {\n authorityHash: lease.authorityHash,\n requestId: lease.requestId,\n });\n return;\n }\n lease.expiresAt = expiresAt;\n lease.localFatalDeadlineMonotonicMs =\n refreshStartedAtMonotonicMs +\n ACTOR_MUTATION_LEASE_SECONDS * 1_000 -\n ACTOR_MUTATION_FATAL_SAFETY_MS;\n scheduleActorMutationLeaseRefresh(request, lease);\n })\n .catch((error) => poisonActorMutationLease(request, lease, error));\n }, ACTOR_MUTATION_LEASE_REFRESH_MS);\n lease.refreshTimer = timer;\n}\n\nfunction poisonActorMutationLease(\n request: Request,\n lease: ActorMutationLease,\n error: unknown,\n): void {\n if (actorMutationLeaseByRequest.get(request) !== lease || lease.poisoned !== null) return;\n lease.poisoned = error;\n if (lease.refreshTimer) lease.runtime.cancel(lease.refreshTimer);\n lease.refreshTimer = null;\n lease.abortController.abort(error);\n const fatalAfterMs = Math.max(\n 0,\n lease.localFatalDeadlineMonotonicMs - lease.runtime.monotonicNow(),\n );\n lease.fatalTimer = lease.runtime.schedule(() => {\n if (actorMutationLeaseByRequest.get(request) !== lease) return;\n // A handler that ignored cooperative cancellation must not outlive the\n // durable fence and resume under a later actor. Terminate this API\n // instance before PostgreSQL can expire the lease; process death is the\n // final multi-replica-safe cancellation boundary.\n lease.runtime.terminate();\n }, fatalAfterMs);\n}\n\nfunction unrefTimer<T extends ReturnType<typeof setTimeout>>(timer: T): T {\n (timer as T & { unref?: () => void }).unref?.();\n return timer;\n}\n\nfunction requestCookie(request: Request, name: string): string | null {\n const header = request.headers.get(\"cookie\");\n if (!header) return null;\n for (const part of header.split(\";\")) {\n const separator = part.indexOf(\"=\");\n if (separator < 0 || part.slice(0, separator).trim() !== name) continue;\n const value = part.slice(separator + 1).trim();\n if (!value || value.length > 512) return null;\n try {\n return decodeURIComponent(value);\n } catch {\n return null;\n }\n }\n return null;\n}\n\nfunction setCookieHeaders(headers: Headers): string[] {\n const getSetCookie = (\n headers as Headers & {\n getSetCookie?: () => string[];\n }\n ).getSetCookie;\n if (getSetCookie) {\n return getSetCookie.call(headers);\n }\n\n const cookie = headers.get(\"set-cookie\");\n return cookie ? [cookie] : [];\n}\n"],"mappings":";;;;;;;;;AAAA,SAAS,yBAAyB;AAClC,SAAS,kBAAkB;AAC3B,SAAS,+BAA+B;AAGxC;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,OAEK;AACP;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AACP,SAAS,qCAAqC;AAE9C,SAAS,qBAAqB;AAgB9B,IAAM,4BAA4B,IAAI,kBAAyC;AAC/E,IAAM,oCAAoC;AAGnC,SAAS,+BAA+B,MAAgC;AAC7E,QAAM,QAAQ,0BAA0B,SAAS;AACjD,MAAI,CAAC,MAAO;AACZ,aAAW,SAAS,MAAM;AACxB,QAAI,MAAM,OAAO,UAAU,kCAAmC;AAC9D,QAAI,SAAS,OAAO,UAAU,SAAU,OAAM,OAAO,KAAK,KAAK;AAAA,EACjE;AACF;AAEA,SAAS,gCAAgC,OAAyB;AAChE,MAAI,CAAC,SAAS,OAAO,UAAU,SAAU,QAAO;AAChD,QAAM,YAAY;AAClB,SAAO,UAAU,WAAW,2BAA2B,UAAU,eAAe;AAClF;AAEA,eAAsB,6BAAgC,QAAsC;AAC1F,QAAM,QAAQ,EAAE,QAAQ,CAAC,EAAe;AACxC,MAAI;AACF,WAAO,MAAM,0BAA0B,IAAI,OAAO,MAAM;AAAA,EAC1D,SAAS,OAAO;AAGd,QACE,gCAAgC,KAAK,KACrC,MAAM,OAAO;AAAA,MACX,CAAC,WAAW,yBAAyB,MAAM,KAAK,oCAAoC,MAAM;AAAA,IAC5F,GACA;AACA,YAAM,IAAI,yBAAyB,0CAA0C;AAAA,QAC3E,OAAO;AAAA,MACT,CAAC;AAAA,IACH;AACA,UAAM;AAAA,EACR;AACF;AAEA,IAAM,+BAA+B,KAAK;AAC1C,IAAM,kCAAkC,IAAI,KAAK;AACjD,IAAM,qCAAqC,KAAK,KAAK;AACrD,IAAM,iCAAiC;AAOvC,IAAM,sCAAiE;AAAA,EACrE,cAAc,MAAM,YAAY,IAAI;AAAA,EACpC,UAAU,CAAC,UAAU,YAAY,WAAW,WAAW,UAAU,OAAO,CAAC;AAAA,EACzE,QAAQ,CAAC,UAAU,aAAa,KAAK;AAAA,EACrC,WAAW,MAAM;AACf,YAAQ,OAAO,MAAM,4DAA4D;AACjF,YAAQ,KAAK,CAAC;AAAA,EAChB;AACF;AACA,IAAI,4BAA4B;AAgBhC,IAAM,8BAA8B,oBAAI,QAAqC;AAC7E,IAAM,6BAA6B,oBAAI,QAAyB;AAChE,IAAM,iCAAiC,oBAAI,QAAiD;AAS5F,IAAM,wBAAwB,oBAAI,QAAwC;AAGnE,SAAS,8BACd,MACA,QACM;AACN,MAAI,WAAW,OAAW,uBAAsB,OAAO,IAAI;AAAA,MACtD,uBAAsB,IAAI,MAAM,CAAC,GAAG,MAAM,CAAC;AAClD;AAEA,eAAsB,qBAAqB,MAAgD;AACzF,QAAM,UAAU,MAAM,sBAAsB,GAAG,IAAI;AACnD,6BAA2B,KAAK,CAAC,GAAG,SAAS,IAAI;AACjD,SAAO;AACT;AAOO,IAAM,+BAA+B;AAS5C,eAAsB,2BACpB,MACA,YACA,IACA;AACA,MAAI,CAAC,WAAW,WAAW,4BAA4B,EAAG,QAAO;AACjE,QAAM,QAAQ,WAAW,MAAM,6BAA6B,MAAM;AAClE,MAAI,CAAC,yBAAyB,KAAK,KAAK,EAAG,QAAO;AAClD,QAAM,UAAU,MAAM,KAAK;AAC3B,QAAM,SAAS;AAAA,IACb,GAAG,KAAK,IAAI,WAAW,UAAU,QAAQ,MAAM,EAAE,OAAO,OAAO,MAAM,EAAE,OAAO,QAAQ,CAAC;AAAA,EACzF;AACA,QAAM,UAAU,MAAM;AAAA,IAA6B,MACjD,KAAK,IAAI,WAAW;AAAA,MAClB,SAAS,IAAI,QAAQ,EAAE,QAAQ,GAAG,QAAQ,YAAY,aAAa,IAAI,IAAI,MAAM,GAAG,CAAC;AAAA;AAAA,MAErF,OAAO,EAAE,oBAAoB,KAAK;AAAA,IACpC,CAAC;AAAA,EACH;AACA,MAAI,CAAC,SAAS,KAAM,QAAO;AAC3B,6BAA2B,MAAM,QAAQ,IAAI;AAC7C,MAAI,CAAC,GAAI,QAAO;AAChB,QAAM,gBAAgB,QAAQ,SAAS;AACvC,MAAI,OAAO,kBAAkB,SAAU,QAAO;AAC9C,QAAM,QAAQ,MAAM,8BAA8B,IAAI;AAAA,IACpD;AAAA,IACA,YAAY,QAAQ,KAAK;AAAA,EAC3B,CAAC;AACD,SAAO,QAAQ,UAAU;AAC3B;AAEO,SAAS,2BACd,MACA,MACM;AACN,QAAM,SAAS,sBAAsB,IAAI,IAAI;AAC7C,MACE,QACA,WAAW,WACV,CAAC,KAAK,iBAAiB,CAAC,wBAAwB,QAAQ,KAAK,KAAK;AAEnE,UAAM,IAAI,cAAc,KAAK,EAAE,SAAS,8CAA8C,CAAC;AAC3F;AAEA,eAAe,sBACb,GACA,MACA,SAMA;AACA,QAAM,iBAAiB,SAAS,kBAAkB;AAClD,MAAI,mBAAmB,YAAY,SAAS,MAAM,QAAQ,gBAAgB;AACxE,UAAM,YAAY,cAAc,EAAE,IAAI,KAAK,+BAA+B;AAC1E,QAAI,WAAW;AACb,UAAI;AAKF,cAAM,qBAAqB,2BAA2B,IAAI,EAAE,IAAI,GAAG,KAAK;AACxE,cAAM,qBACJ,sBAAsB,EAAE,IAAI,OAAO,+BAA+B,KAAK;AACzE,cAAM,gBACJ,mBAAmB,UAAU,uBAAuB,OAChD,MAAM,QAAQ,eAAe,sBAAsB,EAAE,IAAI,IAAI,OAAO,IACpE;AACN,cAAM,WAAW,MAAM,kCAAkC;AAAA,UACvD,IAAI,QAAQ;AAAA,UACZ,SAAS,QAAQ;AAAA,UACjB;AAAA,UACA,MAAM;AAAA,UACN;AAAA,UACA,wBACE,OAAO,eAAe,SAAS,OAAO,WAAW,cAAc,QAAQ,KAAK;AAAA,UAC9E,eAAe,QAAQ,yBAAyB;AAAA,QAClD,CAAC;AACD,YAAI,UAAU;AAIZ,cAAI,uBAAuB,MAAM;AAC/B,cAAE,OAAO,iCAAiC,SAAS,WAAW,UAAU;AACxE,uCAA2B,IAAI,EAAE,IAAI,KAAK,SAAS,WAAW,UAAU;AAAA,UAC1E;AACA,yCAA+B,IAAI,EAAE,IAAI,KAAK;AAAA,YAC5C,eAAe,kBAAkB,SAAS;AAAA,YAC1C,YAAY,SAAS,WAAW;AAAA,UAClC,CAAC;AAAA,QACH;AACA,YAAI,YAAY,CAAC,SAAS,QAAS,QAAO;AAC1C,YAAI,UAAU,SAAS;AACrB,cAAI,kBAAkB,SAAS;AAC/B,cAAI,+BAA+B,EAAE,IAAI,MAAM,GAAG;AAChD,kBAAM;AAAA,cACJ,EAAE,IAAI;AAAA,cACN,QAAQ;AAAA,cACR;AAAA,cACA,SAAS,WAAW;AAAA,YACtB;AACA,kBAAM,eAAe,MAAM;AAAA,cACzB,QAAQ;AAAA,cACR;AAAA,cACA;AAAA,cACA,QAAQ,yBAAyB;AAAA,YACnC;AACA,gBAAI,CAAC,aAAc,OAAM,IAAI,4BAA4B;AACzD,kBAAM,YAAY,MAAM,QAAQ,eAAe,uBAAuB,YAAY;AAClF,gBACE,CAAC,aACD,UAAU,QAAQ,OAAO,aAAa,iBACtC,UAAU,KAAK,OAAO,aAAa,YACnC;AACA,oBAAM,IAAI,4BAA4B;AAAA,YACxC;AACA,8BAAkB;AAAA,UACpB;AACA,iBAAO;AAAA,QACT;AAKA,eAAO;AAAA,MACT,SAAS,OAAO;AACd,YAAI,iBAAiB,6BAA6B;AAIhD,cAAI,CAAC,2BAA2B,IAAI,EAAE,IAAI,GAAG,GAAG;AAC9C,cAAE,OAAO,0BAA0B,SAAS;AAAA,UAC9C;AACA,gBAAM,IAAI,cAAc,KAAK,EAAE,SAAS,MAAM,MAAM,OAAO,MAAM,CAAC;AAAA,QACpE;AACA,cAAM;AAAA,MACR;AAAA,IACF;AACA,QAAI,mBAAmB,SAAU,QAAO;AACxC,UAAM,UAAU,MAAM,QAAQ,eAAe,sBAAsB,EAAE,IAAI,IAAI,OAAO;AACpF,QAAI,SAAS,SAAS;AACpB,UAAI;AACF,cAAM,UAAU,MAAM,qCAAqC,QAAQ,IAAI,QAAQ,QAAQ,EAAE;AACzF,YAAI,SAAS;AACX,gBAAM,qBAAqB,2BAA2B,IAAI,EAAE,IAAI,GAAG,KAAK;AACxE,cACE,QAAQ,eAAe,OACtB,uBAAuB,QAAQ,QAAQ,eAAe,sBACvD,CAAC,QAAQ,YACT,QAAQ,SAAS,kBAAkB,QAAQ,QAAQ,MACnD,QAAQ,SAAS,eAAe,QAAQ,KAAK,IAC7C;AACA,kBAAM,IAAI,4BAA4B;AAAA,UACxC;AACA,cAAI,uBAAuB,MAAM;AAC/B,cAAE,OAAO,iCAAiC,QAAQ,UAAU;AAC5D,uCAA2B,IAAI,EAAE,IAAI,KAAK,QAAQ,UAAU;AAAA,UAC9D;AACA,yCAA+B,IAAI,EAAE,IAAI,KAAK;AAAA,YAC5C,eAAe,QAAQ;AAAA,YACvB,YAAY,QAAQ;AAAA,UACtB,CAAC;AACD,cAAI,+BAA+B,EAAE,IAAI,MAAM,GAAG;AAChD,kBAAM;AAAA,cACJ,EAAE,IAAI;AAAA,cACN,QAAQ;AAAA,cACR,QAAQ;AAAA,cACR,QAAQ;AAAA,YACV;AACA,kBAAM,UAAU,MAAM;AAAA,cACpB,QAAQ;AAAA,cACR,QAAQ,QAAQ;AAAA,YAClB;AACA,gBACE,SAAS,kBAAkB,QAAQ,iBACnC,QAAQ,eAAe,QAAQ,cAC/B,CAAC,QAAQ,YACT,QAAQ,SAAS,kBAAkB,QAAQ,QAAQ,IACnD;AACA,oBAAM,IAAI,4BAA4B;AAAA,YACxC;AACA,kBAAM,YAAY,MAAM,QAAQ,eAAe,uBAAuB,QAAQ,QAAQ;AACtF,gBACE,CAAC,aACD,UAAU,QAAQ,OAAO,QAAQ,QAAQ,MACzC,UAAU,KAAK,OAAO,QAAQ,KAAK,IACnC;AACA,oBAAM,IAAI,4BAA4B;AAAA,YACxC;AACA,mBAAO;AAAA,UACT;AACA,iBAAO;AAAA,QACT;AAAA,MACF,SAAS,OAAO;AACd,YAAI,iBAAiB,6BAA6B;AAChD,cAAI,CAAC,2BAA2B,IAAI,EAAE,IAAI,GAAG,GAAG;AAC9C,cAAE,OAAO,0BAA0B,SAAS;AAAA,UAC9C;AACA,gBAAM,IAAI,cAAc,KAAK,EAAE,SAAS,MAAM,MAAM,OAAO,MAAM,CAAC;AAAA,QACpE;AACA,cAAM;AAAA,MACR;AAAA,EACJ;AACA,QAAM,SAAS,MAAM;AAAA,IAA6B,MAChD,KAAK,IAAI,WAAW;AAAA,MAClB,SAAS,EAAE,IAAI,IAAI;AAAA,MACnB,eAAe;AAAA,IACjB,CAAC;AAAA,EACH;AAEA,aAAW,UAAU,iBAAiB,OAAO,OAAO,GAAG;AACrD,MAAE,OAAO,cAAc,QAAQ,EAAE,QAAQ,KAAK,CAAC;AAAA,EACjD;AAEA,QAAM,UAAU,OAAO;AACvB,MAAI,CAAC,SAAS,QAAQ,CAAC,SAAS,GAAI,QAAO;AAC3C,QAAM,gBAAgB,QAAQ,SAAS;AACvC,MAAI,OAAO,kBAAkB,SAAU,QAAO;AAC9C,QAAM,QAAQ,MAAM,8BAA8B,QAAQ,IAAI;AAAA,IAC5D;AAAA,IACA,YAAY,QAAQ,KAAK;AAAA,IACzB,GAAI,QAAQ,0BAA0B,SAClC,CAAC,IACD,EAAE,eAAe,QAAQ,sBAAsB;AAAA,EACrD,CAAC;AACD,SAAO,QAAQ,UAAU;AAC3B;AAGO,SAAS,gCAAgC,SAAiC;AAC/E,SAAO,2BAA2B,IAAI,OAAO,KAAK;AACpD;AAEA,SAAS,yBACP,IACA,WACA,MACA,eACA;AACA,SAAO,iCAAiC,IAAI;AAAA,IAC1C,eAAe,kBAAkB,SAAS;AAAA,IAC1C;AAAA,IACA,iBAAiB;AAAA,IACjB;AAAA,IACA,UAAU;AAAA,EACZ,CAAC,EAAE,KAAK,CAAC,aAAa,UAAU,YAAY,IAAI;AAClD;AAGA,eAAsB,oCAAoC,SAAiC;AACzF,QAAM,QAAQ,4BAA4B,IAAI,OAAO;AACrD,MAAI,CAAC,MAAO;AACZ,8BAA4B,OAAO,OAAO;AAC1C,MAAI,MAAM,aAAc,OAAM,QAAQ,OAAO,MAAM,YAAY;AAC/D,MAAI,MAAM,cAAe,OAAM,QAAQ,OAAO,MAAM,aAAa;AACjE,MAAI,MAAM,WAAY,OAAM,QAAQ,OAAO,MAAM,UAAU;AAC3D,QAAM,qCAAqC,MAAM,IAAI;AAAA,IACnD,eAAe,MAAM;AAAA,IACrB,WAAW,MAAM;AAAA,EACnB,CAAC;AACH;AAGO,SAAS,sCAAsC,SAAsC;AAC1F,SAAO,4BAA4B,IAAI,OAAO,GAAG,gBAAgB,UAAU;AAC7E;AAoBA,eAAsB,qCAAqC,SAAiC;AAC1F,QAAM,QAAQ,4BAA4B,IAAI,OAAO;AACrD,MAAI,CAAC,MAAO;AACZ,MAAI,MAAM,uBAAwB;AAClC,MAAI,MAAM,aAAa,MAAM;AAC3B,UAAM,IAAI,yCAAyC;AAAA,MACjD,OAAO,MAAM;AAAA,IACf,CAAC;AAAA,EACH;AACA,QAAM,QAAQ,MAAM,sCAAsC,MAAM,IAAI;AAAA,IAClE,eAAe,MAAM;AAAA,IACrB,YAAY,MAAM;AAAA,IAClB,WAAW,MAAM;AAAA,EACnB,CAAC;AACD,MAAI,CAAC,MAAO,OAAM,IAAI,4BAA4B;AACpD;AAEO,IAAM,2CAAN,cAAuD,MAAM;AAAA,EACzD,OAAO;AAAA,EACP,OAAO;AAAA,EAChB,YAAY,SAAwB;AAClC,UAAM,gFAAgF,OAAO;AAAA,EAC/F;AACF;AAGO,SAAS,6CAA6C,SAAwB;AACnF,QAAM,QAAQ,4BAA4B,IAAI,OAAO;AACrD,MAAI,MAAO,OAAM,yBAAyB;AAC5C;AAcO,SAAS,yCACd,SACuC;AACvC,SAAO,+BAA+B,IAAI,OAAO,KAAK;AACxD;AAGO,SAAS,qCACd,SAC2C;AAC3C,QAAM,QAAQ,4BAA4B,IAAI,OAAO;AACrD,SAAO,QACH;AAAA,IACE,eAAe,MAAM;AAAA,IACrB,YAAY,MAAM;AAAA,IAClB,WAAW,MAAM;AAAA,EACnB,IACA;AACN;AAEA,SAAS,+BAA+B,QAAyB;AAC/D,SAAO,WAAW,SAAS,WAAW,UAAU,WAAW;AAC7D;AAEA,eAAe,yBACb,SACA,IACA,WACA,YACe;AACf,QAAM,gBAAgB,kBAAkB,SAAS;AACjD,QAAM,gCAAgC,SAAS,IAAI,eAAe,UAAU;AAC9E;AAEA,eAAe,gCACb,SACA,IACA,eACA,YACe;AACf,QAAM,WAAW,4BAA4B,IAAI,OAAO;AACxD,MAAI,UAAU;AACZ,QAAI,SAAS,kBAAkB,iBAAiB,SAAS,eAAe,YAAY;AAClF,YAAM,IAAI,4BAA4B;AAAA,IACxC;AACA;AAAA,EACF;AACA,QAAM,QAA4B;AAAA,IAChC;AAAA,IACA;AAAA,IACA;AAAA,IACA,WAAW,OAAO,WAAW;AAAA,IAC7B,cAAc;AAAA,IACd,eAAe;AAAA,IACf,YAAY;AAAA,IACZ,WAAW,oBAAI,KAAK,CAAC;AAAA,IACrB,+BAA+B;AAAA,IAC/B,SAAS;AAAA,IACT,iBAAiB,IAAI,gBAAgB;AAAA,IACrC,UAAU;AAAA,IACV,wBAAwB;AAAA,EAC1B;AACA,QAAM,8BAA8B,MAAM,QAAQ,aAAa;AAC/D,MAAI;AACF,UAAM,YAAY,MAAM,qCAAqC,IAAI;AAAA,MAC/D;AAAA,MACA;AAAA,MACA,WAAW,MAAM;AAAA,MACjB,cAAc;AAAA,IAChB,CAAC;AAAA,EACH,SAAS,OAAO;AACd,QACE,iBAAiB,gDACjB,iBAAiB,qCACjB;AACA,YAAM,IAAI,4BAA4B;AAAA,IACxC;AACA,UAAM;AAAA,EACR;AACA,QAAM,gCACJ,8BACA,+BAA+B,MAC/B;AACF,8BAA4B,IAAI,SAAS,KAAK;AAC9C,oCAAkC,SAAS,KAAK;AAChD,QAAM,gBAAgB,MAAM,QAAQ,SAAS,MAAM;AACjD;AAAA,MACE;AAAA,MACA;AAAA,MACA,IAAI,MAAM,8DAA8D;AAAA,IAC1E;AAAA,EACF,GAAG,kCAAkC;AACvC;AAEA,SAAS,kCAAkC,SAAkB,OAAiC;AAC5F,QAAM,QAAQ,MAAM,QAAQ,SAAS,MAAM;AACzC,QAAI,4BAA4B,IAAI,OAAO,MAAM,MAAO;AACxD,UAAM,8BAA8B,MAAM,QAAQ,aAAa;AAC/D,SAAK,qCAAqC,MAAM,IAAI;AAAA,MAClD,eAAe,MAAM;AAAA,MACrB,YAAY,MAAM;AAAA,MAClB,WAAW,MAAM;AAAA,MACjB,cAAc;AAAA,IAChB,CAAC,EACE,KAAK,OAAO,cAAc;AACzB,UAAI,4BAA4B,IAAI,OAAO,MAAM,OAAO;AAItD,cAAM,qCAAqC,MAAM,IAAI;AAAA,UACnD,eAAe,MAAM;AAAA,UACrB,WAAW,MAAM;AAAA,QACnB,CAAC;AACD;AAAA,MACF;AACA,YAAM,YAAY;AAClB,YAAM,gCACJ,8BACA,+BAA+B,MAC/B;AACF,wCAAkC,SAAS,KAAK;AAAA,IAClD,CAAC,EACA,MAAM,CAAC,UAAU,yBAAyB,SAAS,OAAO,KAAK,CAAC;AAAA,EACrE,GAAG,+BAA+B;AAClC,QAAM,eAAe;AACvB;AAEA,SAAS,yBACP,SACA,OACA,OACM;AACN,MAAI,4BAA4B,IAAI,OAAO,MAAM,SAAS,MAAM,aAAa,KAAM;AACnF,QAAM,WAAW;AACjB,MAAI,MAAM,aAAc,OAAM,QAAQ,OAAO,MAAM,YAAY;AAC/D,QAAM,eAAe;AACrB,QAAM,gBAAgB,MAAM,KAAK;AACjC,QAAM,eAAe,KAAK;AAAA,IACxB;AAAA,IACA,MAAM,gCAAgC,MAAM,QAAQ,aAAa;AAAA,EACnE;AACA,QAAM,aAAa,MAAM,QAAQ,SAAS,MAAM;AAC9C,QAAI,4BAA4B,IAAI,OAAO,MAAM,MAAO;AAKxD,UAAM,QAAQ,UAAU;AAAA,EAC1B,GAAG,YAAY;AACjB;AAEA,SAAS,WAAoD,OAAa;AACxE,EAAC,MAAqC,QAAQ;AAC9C,SAAO;AACT;AAEA,SAAS,cAAc,SAAkB,MAA6B;AACpE,QAAM,SAAS,QAAQ,QAAQ,IAAI,QAAQ;AAC3C,MAAI,CAAC,OAAQ,QAAO;AACpB,aAAW,QAAQ,OAAO,MAAM,GAAG,GAAG;AACpC,UAAM,YAAY,KAAK,QAAQ,GAAG;AAClC,QAAI,YAAY,KAAK,KAAK,MAAM,GAAG,SAAS,EAAE,KAAK,MAAM,KAAM;AAC/D,UAAM,QAAQ,KAAK,MAAM,YAAY,CAAC,EAAE,KAAK;AAC7C,QAAI,CAAC,SAAS,MAAM,SAAS,IAAK,QAAO;AACzC,QAAI;AACF,aAAO,mBAAmB,KAAK;AAAA,IACjC,QAAQ;AACN,aAAO;AAAA,IACT;AAAA,EACF;AACA,SAAO;AACT;AAEA,SAAS,iBAAiB,SAA4B;AACpD,QAAM,eACJ,QAGA;AACF,MAAI,cAAc;AAChB,WAAO,aAAa,KAAK,OAAO;AAAA,EAClC;AAEA,QAAM,SAAS,QAAQ,IAAI,YAAY;AACvC,SAAO,SAAS,CAAC,MAAM,IAAI,CAAC;AAC9B;","names":[]}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { fetchCodexModels } from "@opengeni/codex";
|
|
2
|
+
import { type Settings } from "@opengeni/config";
|
|
3
|
+
import { listSubscriptionCoreCodexServingConnections, readCodexCutoverDisposition, recordSubscriptionCoreCodexModelCatalog, type CodexCredentialTokenSnapshot, type Database } from "@opengeni/db";
|
|
4
|
+
import type { ModelAvailabilityObservation } from "./model-catalog.js";
|
|
5
|
+
/** The workspace, organization and acting subject of a Codex catalog read. */
|
|
6
|
+
export type WorkspaceCodexCatalogContext = {
|
|
7
|
+
accountId: string;
|
|
8
|
+
workspaceId: string;
|
|
9
|
+
/**
|
|
10
|
+
* The person whose new work the catalog describes: the authenticated
|
|
11
|
+
* caller, or a scheduled task's execution owner. Their own personal
|
|
12
|
+
* connection counts only in their own Personal workspace; null or a
|
|
13
|
+
* non-human subject sees shared capacity only.
|
|
14
|
+
*/
|
|
15
|
+
subjectId: string | null;
|
|
16
|
+
};
|
|
17
|
+
export type WorkspaceCodexCatalogReadiness = {
|
|
18
|
+
/** Codex models are ready in this workspace (the catalog's connection readiness). */
|
|
19
|
+
active: boolean;
|
|
20
|
+
/** Live per-model availability, keyed by model definition version. */
|
|
21
|
+
observations: Record<string, ModelAvailabilityObservation>;
|
|
22
|
+
};
|
|
23
|
+
type CatalogDependencies = {
|
|
24
|
+
recordModels: typeof recordSubscriptionCoreCodexModelCatalog;
|
|
25
|
+
disposition: typeof readCodexCutoverDisposition;
|
|
26
|
+
listServing: typeof listSubscriptionCoreCodexServingConnections;
|
|
27
|
+
fetchModels: typeof fetchCodexModels;
|
|
28
|
+
getCoreToken: (db: Database, settings: Settings, context: WorkspaceCodexCatalogContext, connectionId: string) => Promise<CodexCredentialTokenSnapshot>;
|
|
29
|
+
};
|
|
30
|
+
/**
|
|
31
|
+
* Placement consumes the same per-account catalog facts as the picker, never
|
|
32
|
+
* the union of another account's entitlements. Failed reads remain unknown.
|
|
33
|
+
* Personal credentials require an accepted-turn lease and are not probed by
|
|
34
|
+
* this workspace reader; their proven refusals remain model cooldowns.
|
|
35
|
+
*/
|
|
36
|
+
export declare function refreshCoreCodexModelEntitlements(db: Database, settings: Settings, context: WorkspaceCodexCatalogContext, deps?: CatalogDependencies): Promise<void>;
|
|
37
|
+
/**
|
|
38
|
+
* Codex readiness and live model availability for a workspace catalog,
|
|
39
|
+
* default-model or picker read, by the organization's Codex cutover row:
|
|
40
|
+
*
|
|
41
|
+
* - a missing or disabled row (maintenance): Codex is not ready and no legacy Codex
|
|
42
|
+
* table is read;
|
|
43
|
+
* - an enabled row (`core`): the core connections that can serve new work of
|
|
44
|
+
* `context.subjectId` here. A shared connection's live model list is read
|
|
45
|
+
* through the connection-level core seam. A personal connection's list
|
|
46
|
+
* cannot be read outside an exact accepted turn, so a model it permits and
|
|
47
|
+
* has not been refused for (no live model cooldown) is reported without an
|
|
48
|
+
* observation (selectable, status unknown); placement still decides.
|
|
49
|
+
*/
|
|
50
|
+
export declare function loadWorkspaceCodexCatalogReadiness(db: Database, settings: Settings, context: WorkspaceCodexCatalogContext, options?: {
|
|
51
|
+
observeAvailability?: boolean;
|
|
52
|
+
/** Deployment-level readiness settings, when different from the model catalog. */
|
|
53
|
+
activeSettings?: Pick<Settings, "codexSubscriptionEnabled">;
|
|
54
|
+
}, deps?: CatalogDependencies): Promise<WorkspaceCodexCatalogReadiness>;
|
|
55
|
+
export {};
|
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
import { type ConfiguredModel, type Settings } from "@opengeni/config";
|
|
2
|
+
import { type DefaultModelSelection, type ReasoningEffort, type ScheduledTask, type WorkspaceSessionDefaults, type ClaudeProviderAccountAuthoritySnapshotV1, type BillingBalance, type OrganizationModelDefaults } from "@opengeni/contracts";
|
|
3
|
+
import { type SubscriptionCoreClaudeCatalogReadiness, type ConnectionModelRestrictions, type Database } from "@opengeni/db";
|
|
4
|
+
import { type WorkspaceModelSelection, type WorkspaceModelSelectionInput } from "./model-catalog.js";
|
|
5
|
+
/** The model's own default effort, matching the web picker's choice. */
|
|
6
|
+
export declare function defaultReasoningEffortForConfiguredModel(model: ConfiguredModel, fallback: ReasoningEffort): ReasoningEffort;
|
|
7
|
+
/** The highest supported effort at or below `preferred`. */
|
|
8
|
+
export declare function clampReasoningEffortForConfiguredModel(model: ConfiguredModel, preferred: ReasoningEffort, fallback: ReasoningEffort): ReasoningEffort;
|
|
9
|
+
export type DefaultSessionModelInput = {
|
|
10
|
+
/** Catalog-resolved settings: `openaiModel` is the deployment default. */
|
|
11
|
+
settings: Settings;
|
|
12
|
+
/** This workspace's selection, in operator catalog order. */
|
|
13
|
+
selections: readonly WorkspaceModelSelection[];
|
|
14
|
+
workspaceDefaults: WorkspaceSessionDefaults | null;
|
|
15
|
+
/** The organization's default every workspace follows until it saves its own. */
|
|
16
|
+
organizationDefaults?: WorkspaceSessionDefaults | null | undefined;
|
|
17
|
+
/**
|
|
18
|
+
* True while the organization holds a positive Opengeni credit balance from
|
|
19
|
+
* any source, the verified-signup trial grant included (see
|
|
20
|
+
* `organizationHoldsCredits`).
|
|
21
|
+
*/
|
|
22
|
+
creditsAvailable: boolean;
|
|
23
|
+
creditBalance?: BillingBalance;
|
|
24
|
+
};
|
|
25
|
+
/**
|
|
26
|
+
* Default model policy for a new chat or scheduled task that names no model.
|
|
27
|
+
*
|
|
28
|
+
* Precedence, first match wins:
|
|
29
|
+
*
|
|
30
|
+
* 1. `workspace`: the saved workspace default (`settings.sessionDefaults`)
|
|
31
|
+
* while it is selectable in this workspace, its saved effort clamped to
|
|
32
|
+
* what the model supports today.
|
|
33
|
+
* 1b. `organization`: the organization's default, the same way, for a
|
|
34
|
+
* workspace that saved none (or whose own default can't run here).
|
|
35
|
+
* 2. `subscription`: the first selectable connected-subscription model
|
|
36
|
+
* (ChatGPT/Codex, then SuperGrok) in operator catalog order. The
|
|
37
|
+
* deployment default wins inside this step when it is itself a selectable
|
|
38
|
+
* subscription model.
|
|
39
|
+
* 3. `credits`: while the organization holds a positive Opengeni credit
|
|
40
|
+
* balance (a purchase, a grant, or the verified-signup trial grant), the
|
|
41
|
+
* configured credits default (`OPENGENI_CREDITS_DEFAULT_MODEL`, effort
|
|
42
|
+
* clamped to what the model supports), or the first selectable
|
|
43
|
+
* credits-billed model when that one is not selectable. When the
|
|
44
|
+
* deployment default is already a funded, selectable credits-billed model it
|
|
45
|
+
* keeps the deployment effort, except that it takes the
|
|
46
|
+
* credits default effort when it is the credits default model itself.
|
|
47
|
+
* 4. `deployment`: the deployment default with the deployment reasoning effort
|
|
48
|
+
* when stably admissible; otherwise the first stably admissible catalog
|
|
49
|
+
* model with its own default effort. With no admitted models, retain the
|
|
50
|
+
* deployment hint and let fresh creation refuse it.
|
|
51
|
+
*
|
|
52
|
+
* An explicit model on the request, the scheduled task, or the person's
|
|
53
|
+
* new-chat draft is never passed through this function.
|
|
54
|
+
*/
|
|
55
|
+
export declare function selectDefaultSessionModel(input: DefaultSessionModelInput): DefaultModelSelection;
|
|
56
|
+
/**
|
|
57
|
+
* The default this workspace would use while its organization holds a
|
|
58
|
+
* positive Opengeni credit balance. Null when the deployment does not bill
|
|
59
|
+
* credits.
|
|
60
|
+
*/
|
|
61
|
+
export declare function creditsDefaultSessionModel(input: {
|
|
62
|
+
settings: Settings;
|
|
63
|
+
selections: readonly WorkspaceModelSelection[];
|
|
64
|
+
workspaceSettings: unknown;
|
|
65
|
+
organizationDefaults?: Pick<OrganizationModelDefaults, "sessionDefaults"> | null;
|
|
66
|
+
creditBalance?: BillingBalance;
|
|
67
|
+
}): DefaultModelSelection | null;
|
|
68
|
+
/**
|
|
69
|
+
* Resolve the default for an already-loaded workspace selection. The credit
|
|
70
|
+
* ledger is read only when it can change the answer.
|
|
71
|
+
*/
|
|
72
|
+
export declare function resolveDefaultSessionModelForSelections(db: Database, input: {
|
|
73
|
+
settings: Settings;
|
|
74
|
+
accountId: string;
|
|
75
|
+
workspaceSettings: unknown;
|
|
76
|
+
selections: readonly WorkspaceModelSelection[];
|
|
77
|
+
/** Already-read organization defaults; read here when omitted. */
|
|
78
|
+
organizationDefaults?: Pick<OrganizationModelDefaults, "sessionDefaults"> | null;
|
|
79
|
+
}): Promise<DefaultModelSelection>;
|
|
80
|
+
export type WorkspaceModelSelectionContext = {
|
|
81
|
+
accountId: string;
|
|
82
|
+
workspaceId: string;
|
|
83
|
+
/**
|
|
84
|
+
* The subject whose connected-subscription authority applies: the
|
|
85
|
+
* authenticated caller for direct creates, or a scheduled task's immutable
|
|
86
|
+
* execution owner. Never another member.
|
|
87
|
+
*/
|
|
88
|
+
subjectId: string;
|
|
89
|
+
/** Already accepted Claude pool; never replace it with current selection. */
|
|
90
|
+
claudeAuthoritySnapshot?: ClaudeProviderAccountAuthoritySnapshotV1 | undefined;
|
|
91
|
+
};
|
|
92
|
+
/**
|
|
93
|
+
* SuperGrok readiness and its `supergrok/` model restriction on the shared
|
|
94
|
+
* core once its provider route is `core` (design 5.3, SuperGrok track X1a,
|
|
95
|
+
* EP-T18/EP-S25/EP-N26): the core eligibility projection for the subject
|
|
96
|
+
* (shared pools; their own personal connection only in their own Personal
|
|
97
|
+
* workspace). Null when the route is not `core` (maintenance, or no receipt,
|
|
98
|
+
* which this binary's readiness check refuses) and when the deployment
|
|
99
|
+
* disables SuperGrok (no read): the caller then treats SuperGrok as not ready
|
|
100
|
+
* with no selectable model.
|
|
101
|
+
*/
|
|
102
|
+
export declare function loadCoreRoutedXaiCatalogReadiness(db: Database, settings: Pick<Settings, "supergrokSubscriptionEnabled">, context: {
|
|
103
|
+
accountId: string;
|
|
104
|
+
workspaceId: string;
|
|
105
|
+
subjectId: string | null;
|
|
106
|
+
}): Promise<{
|
|
107
|
+
ready: boolean;
|
|
108
|
+
allowedModelIds: string[] | null;
|
|
109
|
+
} | null>;
|
|
110
|
+
/** The connection restrictions with SuperGrok's replaced by the core's answer. */
|
|
111
|
+
export declare function withCoreRoutedXaiRestriction(restrictions: ConnectionModelRestrictions, core: {
|
|
112
|
+
allowedModelIds: string[] | null;
|
|
113
|
+
}): ConnectionModelRestrictions;
|
|
114
|
+
/**
|
|
115
|
+
* Claude readiness and its two model restrictions on the shared core once
|
|
116
|
+
* Claude's provider route is `core` (design 5.3, Claude track C2a,
|
|
117
|
+
* EP-T18/EP-S25/EP-N26): the core eligibility projection for the subject
|
|
118
|
+
* split by the legacy prefixes (`organization-claude-subscription/` from the
|
|
119
|
+
* organization inference pool; `workspace-claude-subscription/` from the
|
|
120
|
+
* workspace pool or the subject's own personal connection in their own
|
|
121
|
+
* Personal workspace). Not ready under maintenance. Null on the legacy route
|
|
122
|
+
* (one receipt read) and when the deployment disables Claude subscriptions
|
|
123
|
+
* (no read), so the caller keeps its legacy answer. Frozen v1 Claude
|
|
124
|
+
* snapshots are not read on the core route.
|
|
125
|
+
*/
|
|
126
|
+
export declare function loadCoreRoutedClaudeCatalogReadiness(db: Database, settings: Pick<Settings, "claudeSubscriptionEnabled">, context: {
|
|
127
|
+
accountId: string;
|
|
128
|
+
workspaceId: string;
|
|
129
|
+
subjectId: string | null;
|
|
130
|
+
}): Promise<SubscriptionCoreClaudeCatalogReadiness | null>;
|
|
131
|
+
/**
|
|
132
|
+
* Readiness for the subject's current or already accepted Claude pool observes
|
|
133
|
+
* metadata only; quota is handled by the runtime allocator. This is not an
|
|
134
|
+
* authorization: callers must supply their authenticated or frozen subject.
|
|
135
|
+
*/
|
|
136
|
+
export declare function loadWorkspaceClaudeSubscriptionReadiness(db: Database, settings: Settings, context: WorkspaceModelSelectionContext,
|
|
137
|
+
/**
|
|
138
|
+
* Claude's core readiness when the caller already read it for this
|
|
139
|
+
* request (`loadCoreRoutedClaudeCatalogReadiness`; null on the legacy
|
|
140
|
+
* route), so the route is read once per request. Read here when absent.
|
|
141
|
+
*/
|
|
142
|
+
claudeCoreReadiness?: SubscriptionCoreClaudeCatalogReadiness | null): Promise<{
|
|
143
|
+
workspace: boolean;
|
|
144
|
+
organization: boolean;
|
|
145
|
+
}>;
|
|
146
|
+
/** Load the same inputs the workspace model catalog route evaluates. */
|
|
147
|
+
export declare function loadWorkspaceModelSelectionInput(db: Database, settings: Settings, context: WorkspaceModelSelectionContext, options?: {
|
|
148
|
+
observeAvailability?: boolean;
|
|
149
|
+
}): Promise<WorkspaceModelSelectionInput>;
|
|
150
|
+
/**
|
|
151
|
+
* Caller-scoped stable fresh admission; never re-admit already accepted work.
|
|
152
|
+
* Live discovery is opt-in: its token refresh can mutate connection readiness,
|
|
153
|
+
* so a health hint must not change the billing rail of an explicit create.
|
|
154
|
+
*/
|
|
155
|
+
export declare function resolveCallerWorkspaceModelSelections(db: Database, settings: Settings, context: WorkspaceModelSelectionContext, options?: {
|
|
156
|
+
observeAvailability?: boolean;
|
|
157
|
+
}): Promise<WorkspaceModelSelection[]>;
|
|
158
|
+
/**
|
|
159
|
+
* Catalog membership only: true while the workspace still lists the model,
|
|
160
|
+
* selectable or not. Retired and removed models are not listed.
|
|
161
|
+
*/
|
|
162
|
+
export declare function workspaceCatalogListsModel(selections: readonly WorkspaceModelSelection[], modelId: string): boolean;
|
|
163
|
+
/** Transient selectability for existing consumers; not fresh-create admission. */
|
|
164
|
+
export declare function selectableWorkspaceModel(selections: readonly WorkspaceModelSelection[], modelId: string): WorkspaceModelSelection | undefined;
|
|
165
|
+
/** Same stable decision used by client config and direct fresh session creation. */
|
|
166
|
+
export declare function admissibleWorkspaceModel(selections: readonly WorkspaceModelSelection[], modelId: string): WorkspaceModelSelection | undefined;
|
|
167
|
+
/**
|
|
168
|
+
* Server-side default for new work that names no model: API and Slack session
|
|
169
|
+
* creates, new-chat drafts that follow the default, and scheduled-task
|
|
170
|
+
* occurrences. The result is resolved once and then frozen by the accepted
|
|
171
|
+
* session or occurrence like any other model choice.
|
|
172
|
+
*/
|
|
173
|
+
export declare function resolveDefaultSessionModel(db: Database, settings: Settings, context: WorkspaceModelSelectionContext & {
|
|
174
|
+
workspaceSettings?: unknown;
|
|
175
|
+
}): Promise<DefaultModelSelection>;
|
|
176
|
+
/**
|
|
177
|
+
* The default a scheduled occurrence uses when its task names no model and the
|
|
178
|
+
* occurrence creates its own session: resolved under the task's immutable
|
|
179
|
+
* execution owner (or its creator for a workspace/service task) and the task's
|
|
180
|
+
* frozen Claude authority, never another member's. The worker stamps the
|
|
181
|
+
* result onto the accepted execution, so retries and recovery replay it; the
|
|
182
|
+
* API's manual-trigger limit check uses the same resolution so it gates the
|
|
183
|
+
* model that will run.
|
|
184
|
+
*/
|
|
185
|
+
export declare function resolveScheduledTaskDefaultModel(db: Database, settings: Settings, task: Pick<ScheduledTask, "id" | "accountId" | "workspaceId" | "ownerSubjectId" | "createdBy">): Promise<DefaultModelSelection>;
|
|
186
|
+
/**
|
|
187
|
+
* The model a manual trigger's limit pre-check evaluates, matching what the
|
|
188
|
+
* occurrence will run: the task's explicit model, else the target or reusable
|
|
189
|
+
* session's model when that session exists, else the resolved scheduled
|
|
190
|
+
* default. The worker still resolves authoritatively at dispatch.
|
|
191
|
+
*/
|
|
192
|
+
export declare function resolveScheduledTaskPreflightModel(db: Database, settings: Settings, task: Pick<ScheduledTask, "id" | "accountId" | "workspaceId" | "ownerSubjectId" | "createdBy" | "agentConfig" | "runMode" | "targetSessionId" | "reusableSessionId">): Promise<string>;
|
package/dist/dependencies.d.ts
CHANGED
|
@@ -1,14 +1,18 @@
|
|
|
1
1
|
import type { Settings } from "@opengeni/config";
|
|
2
|
-
import type {
|
|
2
|
+
import type { Document, DocumentAuthorityKind, EntitlementsPort, GitHubAppApiPort, ScheduledTask, ScheduledTaskTriggerType, SessionAuthorizationPort, TurnInitiator } from "@opengeni/contracts";
|
|
3
3
|
import type { Database, SessionWorkflowWakeDeliveryResult } from "@opengeni/db";
|
|
4
|
+
import type { VaultConnectionCredentialsPort } from "@opengeni/vaults";
|
|
5
|
+
import type { OnePasswordVaultProviderFactory } from "./domain/vaults/provider-registry.js";
|
|
4
6
|
import type { DocumentServices } from "@opengeni/documents";
|
|
5
7
|
import type { EventBus } from "@opengeni/events";
|
|
6
8
|
import type { Observability } from "@opengeni/observability";
|
|
9
|
+
import type { UserPresenceRecorder } from "./user-presence.js";
|
|
7
10
|
import type { createObjectStorage } from "@opengeni/storage";
|
|
8
11
|
import type { ManagedAuth } from "./managed-auth-type.js";
|
|
9
12
|
import type { ManagedAuthSessionAdapter } from "./managed-auth-session-sets.js";
|
|
10
13
|
import type { ApiSandboxClient, ResumeBoxByIdInput, ResumedSandboxSession } from "./sandbox-types.js";
|
|
11
14
|
import type { TranscriptionSegmenter, TranscriptionService } from "./transcription.js";
|
|
15
|
+
import type { ModelCallService } from "./model-call.js";
|
|
12
16
|
import type { EditableArtifactApplicationPort } from "./editable-artifact-live.js";
|
|
13
17
|
import type { ResolvedCatalogSettings } from "./model-catalog.js";
|
|
14
18
|
import type { EditableArtifactAgentApplication, EditableArtifactDurableExportService, EditableArtifactOfficeImportPort } from "./editable-artifacts.js";
|
|
@@ -52,7 +56,13 @@ export type SessionWorkflowClient = {
|
|
|
52
56
|
workflowWakeRevision: number;
|
|
53
57
|
}) => Promise<void>;
|
|
54
58
|
syncScheduledTask: (input: {
|
|
55
|
-
task: ScheduledTask
|
|
59
|
+
task: Pick<ScheduledTask, "id" | "workspaceId" | "temporalScheduleId">;
|
|
60
|
+
/**
|
|
61
|
+
* Compensate under the same per-schedule writer lock. Return the error to
|
|
62
|
+
* throw only after this transaction commits; lock/commit failures bypass
|
|
63
|
+
* that receipt. A failing compensation must roll back its own savepoint.
|
|
64
|
+
*/
|
|
65
|
+
onFailure?: (tx: Database, error: unknown) => Promise<Error>;
|
|
56
66
|
}) => Promise<void>;
|
|
57
67
|
deleteScheduledTaskSchedule: (input: {
|
|
58
68
|
temporalScheduleId: string;
|
|
@@ -62,6 +72,8 @@ export type SessionWorkflowClient = {
|
|
|
62
72
|
agentRunUsageIdempotencyKey: string;
|
|
63
73
|
triggerWorkflowId: string;
|
|
64
74
|
initiator: TurnInitiator;
|
|
75
|
+
/** Server-frozen caller ceiling for this run, independent of task ownership. */
|
|
76
|
+
credentialRestriction?: "developer_setup";
|
|
65
77
|
triggerType?: Extract<ScheduledTaskTriggerType, "manual" | "initial" | "provider_event" | "retry" | "repair">;
|
|
66
78
|
}) => Promise<void>;
|
|
67
79
|
startRigVerification: (input: {
|
|
@@ -83,7 +95,7 @@ export type DocumentIndexClient = {
|
|
|
83
95
|
}) => Promise<Document | void>;
|
|
84
96
|
};
|
|
85
97
|
export type ManagedEmailMessage = {
|
|
86
|
-
kind: "email_verification" | "password_reset" | "organization_user_setup";
|
|
98
|
+
kind: "email_verification" | "password_reset" | "organization_user_setup" | "sign_in_method_changed" | "site_abuse_notice";
|
|
87
99
|
from: string;
|
|
88
100
|
to: string;
|
|
89
101
|
subject: string;
|
|
@@ -125,6 +137,8 @@ export type AppDependencies = {
|
|
|
125
137
|
*/
|
|
126
138
|
catalogSourceSettings?: Settings;
|
|
127
139
|
db: Database;
|
|
140
|
+
/** Read-only host funding admission; unset uses the standalone billing ledger. */
|
|
141
|
+
entitlements?: EntitlementsPort | null;
|
|
128
142
|
/**
|
|
129
143
|
* Host-composed editable artifact engine. Standalone startup binds the same
|
|
130
144
|
* native kernel/DB/object-store implementation; embedded hosts may inject an
|
|
@@ -150,6 +164,11 @@ export type AppDependencies = {
|
|
|
150
164
|
documentIndexer?: DocumentIndexClient;
|
|
151
165
|
documentServices?: DocumentServices;
|
|
152
166
|
observability?: Observability;
|
|
167
|
+
/**
|
|
168
|
+
* Throttled server-side presence for canonical managed browser sessions
|
|
169
|
+
* (`createUserPresenceRecorder`). Analytics only; never an authorization input.
|
|
170
|
+
*/
|
|
171
|
+
userPresence?: UserPresenceRecorder | null;
|
|
153
172
|
readinessChecks?: Partial<Record<"db" | "nats" | "temporal", () => Promise<void> | void>>;
|
|
154
173
|
githubStateSecret?: string;
|
|
155
174
|
/**
|
|
@@ -158,14 +177,21 @@ export type AppDependencies = {
|
|
|
158
177
|
* App credentials; standalone deployments fall back to @opengeni/github.
|
|
159
178
|
*/
|
|
160
179
|
githubAppApi?: GitHubAppApiPort;
|
|
161
|
-
/** Optional provider seam for the separately registered
|
|
180
|
+
/** Optional provider seam for the separately registered Opengeni Lens App. */
|
|
162
181
|
prReviewGithubAppApi?: GitHubAppApiPort;
|
|
163
182
|
/**
|
|
164
183
|
* Optional host-owned connection credential seam. API-side consumers use
|
|
165
184
|
* the MCP leg for Codemode/Code Mode; worker consumers bind the same port
|
|
166
|
-
* for model MCP, Git, and
|
|
185
|
+
* for model MCP, Git, and run credentials. `vaultProvider` is the host's
|
|
186
|
+
* password manager, linked as vaults with `source: "host"` (OP-6).
|
|
187
|
+
*/
|
|
188
|
+
connectionCredentials?: VaultConnectionCredentialsPort | null;
|
|
189
|
+
/**
|
|
190
|
+
* Builds 1Password providers for linked vaults. apps/api and apps/worker
|
|
191
|
+
* bind it to a dynamic `import("@opengeni/vaults-onepassword")`; unset means
|
|
192
|
+
* 1Password vaults report `provider_unavailable`.
|
|
167
193
|
*/
|
|
168
|
-
|
|
194
|
+
onePasswordVaultProvider?: OnePasswordVaultProviderFactory | null;
|
|
169
195
|
/**
|
|
170
196
|
* Optional embedding-host session ACL. Unset preserves standalone workspace
|
|
171
197
|
* authorization; once bound, every session-addressed surface fails closed on
|
|
@@ -179,12 +205,16 @@ export type AppDependencies = {
|
|
|
179
205
|
managedEmailTransport?: ManagedEmailTransport;
|
|
180
206
|
/** Injectable Codex HTTP transport for deterministic API/provider tests. */
|
|
181
207
|
codexFetch?: typeof fetch;
|
|
208
|
+
/** Injectable transport for customer OpenAI/Azure connection checks. */
|
|
209
|
+
directModelFetch?: typeof fetch;
|
|
182
210
|
/** Injectable GitHub transport for deterministic personal-OAuth tests. */
|
|
183
211
|
githubPersonalFetch?: typeof fetch;
|
|
184
212
|
/** Injectable credential-free GitHub transport for public repository verification tests. */
|
|
185
213
|
githubAnonymousFetch?: typeof fetch;
|
|
186
214
|
/** Injectable xAI OAuth/subscription transport for deterministic API/provider tests. */
|
|
187
215
|
xaiFetch?: typeof fetch;
|
|
216
|
+
/** Injectable Claude usage transport on the shared core, for deterministic API tests. */
|
|
217
|
+
claudeFetch?: typeof fetch;
|
|
188
218
|
/** Injectable Slack Web API transport for deterministic bot-connection tests. */
|
|
189
219
|
slackFetch?: typeof fetch;
|
|
190
220
|
/** Injectable Google OAuth/Drive transport for deterministic connector tests. */
|
|
@@ -195,6 +225,8 @@ export type AppDependencies = {
|
|
|
195
225
|
apiIntegrationOAuthFetch?: typeof fetch;
|
|
196
226
|
/** Injectable specification/introspection transport, still network-policy checked. */
|
|
197
227
|
apiIntegrationSourceFetch?: typeof fetch;
|
|
228
|
+
/** Injectable bounded MCP initialization/tools-list probe for Connect tests. */
|
|
229
|
+
mcpCapabilityProbe?: import("./domain/capabilities.js").McpCapabilityProbe;
|
|
198
230
|
atlassianFetch?: typeof fetch;
|
|
199
231
|
/** Injectable MCP OAuth setup deadline for deterministic stalled-provider tests. */
|
|
200
232
|
oauthStartDeadlineMs?: number;
|
|
@@ -204,6 +236,8 @@ export type AppDependencies = {
|
|
|
204
236
|
transcription?: TranscriptionService | null;
|
|
205
237
|
/** Optional host-owned long-form audio normalization/segmentation service. */
|
|
206
238
|
transcriptionSegmenter?: TranscriptionSegmenter | null;
|
|
239
|
+
/** Stateless single model calls (chat completions); built from settings when omitted. */
|
|
240
|
+
modelCalls?: ModelCallService | null;
|
|
207
241
|
sandboxClient?: ApiSandboxClient;
|
|
208
242
|
/**
|
|
209
243
|
* Resume a box by id from a serialized resume_state envelope (the lease's
|
|
@@ -231,7 +265,7 @@ export type ApiRouteDeps = AppDependencies & {
|
|
|
231
265
|
* the canonical admission path without constructing unrelated HTTP, document,
|
|
232
266
|
* or sandbox services. The public API still passes its `ApiRouteDeps` superset.
|
|
233
267
|
*/
|
|
234
|
-
export type AcceptSessionUserMessageDependencies = Pick<AppDependencies, "settings" | "catalogSourceSettings" | "db" | "bus" | "sessionAuthorization" | "schedulePromptPostCommit"> & {
|
|
268
|
+
export type AcceptSessionUserMessageDependencies = Pick<AppDependencies, "settings" | "catalogSourceSettings" | "db" | "bus" | "sessionAuthorization" | "schedulePromptPostCommit" | "observability"> & {
|
|
235
269
|
workflowClient: Pick<SessionWorkflowClient, "wakeSessionWorkflow">;
|
|
236
270
|
objectStorage: ObjectStorageDependency;
|
|
237
271
|
};
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { type AccessGrant, type Permission, type TurnExecutionPolicyV1 } from "@opengeni/contracts";
|
|
2
|
+
import { type AccessGrantAuthorization } from "./access/index.js";
|
|
3
|
+
/** The policy must be server-frozen, never supplied as request metadata. */
|
|
4
|
+
export declare function requireDeveloperSetupDelegatedPermissions(policy: TurnExecutionPolicyV1, permissions: readonly Permission[] | undefined): void;
|
|
5
|
+
/** Only pass server-owned persisted session/turn metadata, never request JSON. */
|
|
6
|
+
export declare function withDeveloperSetupCredentialRestriction(policy: TurnExecutionPolicyV1, source: {
|
|
7
|
+
grant?: AccessGrant;
|
|
8
|
+
authorization?: AccessGrantAuthorization | undefined;
|
|
9
|
+
trustedMetadata?: readonly unknown[];
|
|
10
|
+
}): TurnExecutionPolicyV1;
|