@agent-native/core 0.205.0 → 0.206.0-nightly-20261009011246
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/dist/a2a/client.d.ts +2 -2
- package/dist/agent/engine/anthropic-engine.d.ts +1 -1
- package/dist/agent/engine/builder-engine.d.ts +1 -1
- package/dist/agent/engine/builder-engine.js +23 -8
- package/dist/agent/engine/error-telemetry.d.ts +5 -0
- package/dist/agent/engine/error-telemetry.js +41 -0
- package/dist/agent/engine/registry.d.ts +1 -6
- package/dist/agent/engine/registry.js +2 -31
- package/dist/agent/model-config.d.ts +26 -14
- package/dist/agent/model-config.js +131 -8
- package/dist/agent/model-version.d.ts +19 -0
- package/dist/agent/model-version.js +153 -0
- package/dist/agent/production-agent.d.ts +1 -0
- package/dist/agent/production-agent.js +24 -6
- package/dist/agent/provider-model-selection.js +6 -4
- package/dist/agent/run-manager.js +5 -11
- package/dist/agent/thread-data-builder.js +14 -6
- package/dist/authorization/check-action.js +8 -4
- package/dist/chat-threads/store.js +22 -9
- package/dist/client/analytics.d.ts +1 -0
- package/dist/client/analytics.js +10 -2
- package/dist/client/chat/runtime.js +18 -0
- package/dist/client/chat-model-groups.d.ts +3 -0
- package/dist/client/error-format.js +10 -7
- package/dist/client/onboarding/use-onboarding.d.ts +12 -0
- package/dist/client/onboarding/use-onboarding.js +491 -4
- package/dist/client/session-replay-privacy.d.ts +8 -0
- package/dist/client/session-replay-privacy.js +8 -0
- package/dist/client/session-replay.d.ts +1 -0
- package/dist/client/session-replay.js +18 -9
- package/dist/client/sse-event-processor.js +10 -6
- package/dist/client/use-chat-models.d.ts +5 -0
- package/dist/client/use-chat-models.js +51 -5
- package/dist/client/use-session.d.ts +8 -1
- package/dist/client/use-session.js +20 -1
- package/dist/collab/struct-routes.d.ts +1 -1
- package/dist/deploy/build.js +353 -3
- package/dist/file-upload/actions/upload-image.d.ts +2 -2
- package/dist/jobs/backfill-run-history-ownership.d.ts +12 -0
- package/dist/jobs/backfill-run-history-ownership.js +87 -0
- package/dist/jobs/background-automation-runner.js +3 -9
- package/dist/jobs/remote-execution.js +3 -9
- package/dist/jobs/run-history-ownership.d.ts +5 -0
- package/dist/jobs/run-history-ownership.js +16 -0
- package/dist/jobs/run-now.js +2 -3
- package/dist/localization/agent-resources-messages.d.ts +3 -0
- package/dist/localization/agent-resources-messages.js +33 -0
- package/dist/mcp/actions/create-org-service-token.js +5 -7
- package/dist/mcp/build-server.d.ts +23 -18
- package/dist/mcp/build-server.js +220 -212
- package/dist/mcp/connect-route.d.ts +11 -2
- package/dist/mcp/connect-route.js +34 -24
- package/dist/mcp/connect-store.d.ts +9 -13
- package/dist/mcp/connect-store.js +11 -24
- package/dist/mcp/credential-membership.js +17 -6
- package/dist/mcp/oauth-route.d.ts +11 -1
- package/dist/mcp/oauth-route.js +28 -6
- package/dist/mcp/oauth-token.d.ts +12 -2
- package/dist/mcp/oauth-token.js +15 -4
- package/dist/mcp/server.js +9 -5
- package/dist/notifications/routes.d.ts +2 -2
- package/dist/observability/posthog-ai.d.ts +1 -0
- package/dist/observability/posthog-ai.js +20 -8
- package/dist/observability/routes.d.ts +6 -6
- package/dist/observability/traces.js +61 -39
- package/dist/org/app-roles.d.ts +8 -1
- package/dist/org/app-roles.js +29 -9
- package/dist/org/context.js +24 -8
- package/dist/org/index.d.ts +2 -2
- package/dist/org/workspace-app-identity.d.ts +1 -0
- package/dist/org/workspace-app-identity.js +25 -0
- package/dist/progress/routes.d.ts +1 -1
- package/dist/provider-api/actions/custom-provider-registration.d.ts +11 -11
- package/dist/provider-api/actions/provider-api.d.ts +3 -3
- package/dist/provider-api/corpus-jobs.d.ts +2 -2
- package/dist/scripts/agent-engines/list-agent-engines.js +1 -0
- package/dist/server/action-routes.js +8 -1
- package/dist/server/agent-chat-plugin.js +1 -0
- package/dist/server/agent-engine-default-model-route.d.ts +1 -1
- package/dist/server/auth.js +33 -17
- package/dist/server/bearer-credential-refusal.d.ts +23 -0
- package/dist/server/bearer-credential-refusal.js +67 -0
- package/dist/server/better-auth-instance.js +13 -6
- package/dist/server/builder-browser.d.ts +2 -0
- package/dist/server/builder-browser.js +16 -3
- package/dist/server/capture-error.d.ts +1 -0
- package/dist/server/capture-error.js +28 -4
- package/dist/server/complete-text.js +16 -3
- package/dist/server/core-routes-plugin.js +2 -0
- package/dist/server/dev-action-bridge.js +7 -1
- package/dist/server/google-oauth.js +6 -3
- package/dist/server/index.d.ts +1 -1
- package/dist/server/index.js +1 -1
- package/dist/server/realtime-token.d.ts +1 -1
- package/dist/server/recap-image-route.js +4 -0
- package/dist/server/request-context.d.ts +16 -0
- package/dist/server/request-context.js +17 -0
- package/dist/shared/agent-chat-context.d.ts +1 -0
- package/dist/shared/agent-chat-context.js +26 -0
- package/dist/shared/index.d.ts +1 -1
- package/dist/shared/index.js +1 -1
- package/dist/shared/reasoning-effort.js +10 -1
- package/dist/shared/ssr-session-bootstrap.d.ts +7 -0
- package/dist/shared/ssr-session-bootstrap.js +21 -0
- package/dist/sharing/access.js +86 -5
- package/dist/templates/builder-code-starter/server/routes/index.get.ts +2 -0
- package/dist/triggers/routes.js +2 -1
- package/docs/content/automation-connectors.mdx +5 -3
- package/docs/content/automations.mdx +78 -49
- package/docs/content/observability.mdx +16 -5
- package/docs/content/organizations-teams-permissions.mdx +44 -2
- package/docs/content/recurring-jobs.mdx +4 -8
- package/docs/content/template-forms.mdx +6 -0
- package/package.json +5 -4
- package/src/templates/builder-code-starter/server/routes/index.get.ts +2 -0
|
@@ -73,7 +73,6 @@ export declare function createProviderCorpusJobAction(options: CreateProviderCor
|
|
|
73
73
|
offset?: unknown;
|
|
74
74
|
limit?: unknown;
|
|
75
75
|
}, {
|
|
76
|
-
deleted?: undefined;
|
|
77
76
|
jobs: {
|
|
78
77
|
id: string;
|
|
79
78
|
name: string;
|
|
@@ -84,6 +83,7 @@ export declare function createProviderCorpusJobAction(options: CreateProviderCor
|
|
|
84
83
|
updatedAt: string;
|
|
85
84
|
}[];
|
|
86
85
|
total: number;
|
|
86
|
+
deleted?: undefined;
|
|
87
87
|
jobId?: undefined;
|
|
88
88
|
} | {
|
|
89
89
|
jobs?: undefined;
|
|
@@ -91,9 +91,9 @@ export declare function createProviderCorpusJobAction(options: CreateProviderCor
|
|
|
91
91
|
deleted: boolean;
|
|
92
92
|
jobId: string;
|
|
93
93
|
} | {
|
|
94
|
-
deleted?: undefined;
|
|
95
94
|
jobs?: undefined;
|
|
96
95
|
total?: undefined;
|
|
96
|
+
deleted?: undefined;
|
|
97
97
|
jobId?: undefined;
|
|
98
98
|
hits: Record<string, unknown>[];
|
|
99
99
|
offset: number;
|
|
@@ -201,6 +201,7 @@ export async function run(args = {}) {
|
|
|
201
201
|
label: e.label,
|
|
202
202
|
description: e.description,
|
|
203
203
|
defaultModel: e.defaultModel,
|
|
204
|
+
runtimeSupportedModels: e.supportedModels,
|
|
204
205
|
supportedModels: e.name === CHATGPT_SUBSCRIPTION_ENGINE_NAME
|
|
205
206
|
? (chatGPTCatalog?.models ?? [])
|
|
206
207
|
: applyProviderModelSelection(e.supportedModels, modelSelection),
|
|
@@ -43,7 +43,7 @@ function currentBuildId() {
|
|
|
43
43
|
}
|
|
44
44
|
import { isLoopbackRequest, registerAuthPublicPaths } from "./auth.js";
|
|
45
45
|
import { getH3App } from "./framework-request-handler.js";
|
|
46
|
-
import { getRequestIdentityAuthenticatedAtMs, getRequestIdentitySessionToken, hasExplicitPersonalOrgScope, markExplicitPersonalOrgScope, runWithRequestContext, } from "./request-context.js";
|
|
46
|
+
import { getVerifiedServiceIdentityFromEvent, getRequestIdentityAuthenticatedAtMs, getRequestIdentitySessionToken, hasExplicitPersonalOrgScope, markExplicitPersonalOrgScope, runWithRequestContext, } from "./request-context.js";
|
|
47
47
|
const ROUTE_PREFIX = "/_agent-native/actions";
|
|
48
48
|
const WEBMCP_ACTION_ROUTE_PREFIX = "/_agent-native/webmcp/actions";
|
|
49
49
|
const MAX_MCP_DIRECTORY_WIDGET_SCHEMA_ARGUMENT_BYTES = 32 * 1024;
|
|
@@ -640,8 +640,15 @@ function mountActionRoutesInternal(nitroApp, actions, options) {
|
|
|
640
640
|
const identitySessionToken = userEmail
|
|
641
641
|
? getRequestIdentitySessionToken(event, userEmail)
|
|
642
642
|
: undefined;
|
|
643
|
+
const verifiedServiceIdentity = getVerifiedServiceIdentityFromEvent(event);
|
|
643
644
|
return runWithRequestContext({
|
|
644
645
|
userEmail,
|
|
646
|
+
...(verifiedServiceIdentity &&
|
|
647
|
+
verifiedServiceIdentity.userEmail.trim().toLowerCase() ===
|
|
648
|
+
userEmail?.trim().toLowerCase() &&
|
|
649
|
+
verifiedServiceIdentity.orgId === orgId
|
|
650
|
+
? { verifiedServiceIdentity }
|
|
651
|
+
: {}),
|
|
645
652
|
...(identityAuthenticatedAtMs !== undefined
|
|
646
653
|
? { identityAuthenticatedAtMs }
|
|
647
654
|
: {}),
|
|
@@ -4063,6 +4063,7 @@ Non-code requests are still fine on this surface: read data, navigate the UI, su
|
|
|
4063
4063
|
label: entry.label,
|
|
4064
4064
|
description: entry.description,
|
|
4065
4065
|
defaultModel: entry.defaultModel,
|
|
4066
|
+
runtimeSupportedModels: entry.supportedModels,
|
|
4066
4067
|
...(await modelsFor(entry)),
|
|
4067
4068
|
requiredEnvVars: entry.requiredEnvVars,
|
|
4068
4069
|
installPackage: entry.installPackage,
|
|
@@ -8,8 +8,8 @@ export declare const AGENT_ENGINE_API_KEY_ACTION_NAME = "agent-engine-api-key";
|
|
|
8
8
|
* resolveEngine's credential detection.
|
|
9
9
|
*/
|
|
10
10
|
export declare function createAgentEngineDisconnectHandler(): import("h3").EventHandlerWithFetch<import("h3").EventHandlerRequest, Promise<{
|
|
11
|
-
error: string;
|
|
12
11
|
ok?: undefined;
|
|
12
|
+
error: string;
|
|
13
13
|
scope?: undefined;
|
|
14
14
|
} | {
|
|
15
15
|
ok: boolean;
|
package/dist/server/auth.js
CHANGED
|
@@ -4,6 +4,7 @@ import { getAppConfig, resolveAppHomePath } from "../app-config/index.js";
|
|
|
4
4
|
import { acceptPendingInvitationsForEmail } from "../org/accept-pending.js";
|
|
5
5
|
import { newOrgSelection, ORG_SELECTION_COOKIE, } from "../org/request-org-cache.js";
|
|
6
6
|
import { isWorkspaceAppAccessAllowed, WORKSPACE_APP_ACCESS_UNAVAILABLE, WORKSPACE_APP_ACCESS_UNAVAILABLE_MESSAGE, } from "../org/workspace-app-access.js";
|
|
7
|
+
import { resolveWorkspaceAccessAppId } from "../org/workspace-app-identity.js";
|
|
7
8
|
import { EMBED_SESSION_COOKIE, EMBED_START_PATH, EMBED_TARGET_HEADER, isMcpDirectoryWidgetReadCapabilityScope, } from "../shared/embed-auth.js";
|
|
8
9
|
import { FIRST_RUN_ONBOARDING_COOKIE, FIRST_RUN_ONBOARDING_MAX_AGE, } from "../shared/first-run-onboarding.js";
|
|
9
10
|
import { isGoogleProfileImageUrl } from "../shared/google-profile-image.js";
|
|
@@ -65,6 +66,7 @@ import { getAppOriginClientConfigScript } from "./app-origin-config.js";
|
|
|
65
66
|
import { getAppProductionUrl } from "./app-url.js";
|
|
66
67
|
import { addSignupAttributionHeader, readAnalyticsAnonymousId, signupAttributionContextFromCookieHeader, signupAttributionFromCookieHeader, } from "./attribution.js";
|
|
67
68
|
import { getAuthLoginMode } from "./auth-login-mode.js";
|
|
69
|
+
import { markBearerCredentialRefused, respondBearerCredentialRefused, } from "./bearer-credential-refusal.js";
|
|
68
70
|
import { injectBetaOptOutPersistence } from "./beta-opt-out-html.js";
|
|
69
71
|
import { createBetterAuthSessionForEmail, ensureGoogleAuthIdentity, getBetterAuthInternalAdapter, getBetterAuthUserIdForEmail, getAuthSecret, getBetterAuth, getBetterAuthSync, isDeployPreview, } from "./better-auth-instance.js";
|
|
70
72
|
import { BUILDER_CONNECT_PARAM, BUILDER_RELAY_PATH, BUILDER_RELAY_STATE_PARAM, verifyBuilderConnectTokenAndGetOwner, verifyBuilderPreviewRelayStateForCallback, } from "./builder-browser.js";
|
|
@@ -86,7 +88,7 @@ import { encodeMagicLinkSignupAttribution, MAGIC_LINK_ATTRIBUTION_PARAM, } from
|
|
|
86
88
|
import { safeOAuthReturnUrl } from "./oauth-return-url.js";
|
|
87
89
|
import { getDeploySettingsRequiredHtml, getOnboardingHtml, getResetPasswordHtml, } from "./onboarding-html.js";
|
|
88
90
|
import { queryEchoSafeRedirect } from "./query-echo-safe-redirect.js";
|
|
89
|
-
import { getRequestContext, markRequestIdentityAuthenticatedAtMs, hasContinuationLocalRequestContext, hasExplicitPersonalOrgScope, markExplicitPersonalOrgScope, runWithRequestContext, } from "./request-context.js";
|
|
91
|
+
import { getRequestContext, markRequestIdentityAuthenticatedAtMs, markVerifiedServiceIdentityForEvent, hasContinuationLocalRequestContext, hasExplicitPersonalOrgScope, markExplicitPersonalOrgScope, runWithRequestContext, } from "./request-context.js";
|
|
90
92
|
import { captureAuthError } from "./sentry.js";
|
|
91
93
|
import { isTestIdentity } from "./test-identity.js";
|
|
92
94
|
import { isWorkspaceOAuthCallbackRelayEnabled } from "./workspace-oauth.js";
|
|
@@ -773,7 +775,7 @@ export async function getMcpOAuthBearerSession(event) {
|
|
|
773
775
|
if (!bearerToken)
|
|
774
776
|
return null;
|
|
775
777
|
try {
|
|
776
|
-
const [{ getMcpOAuthAudiences }, { verifyAuth, resolveMcpIdentityOrgId }] = await Promise.all([
|
|
778
|
+
const [{ getMcpConnectUrl, getMcpOAuthAudiences }, { verifyAuth, resolveMcpIdentityOrgId },] = await Promise.all([
|
|
777
779
|
import("../mcp/oauth-route.js"),
|
|
778
780
|
import("../mcp/build-server.js"),
|
|
779
781
|
]);
|
|
@@ -786,12 +788,26 @@ export async function getMcpOAuthBearerSession(event) {
|
|
|
786
788
|
markCredentialMembershipUnavailable(event);
|
|
787
789
|
return null;
|
|
788
790
|
}
|
|
789
|
-
|
|
791
|
+
if (!result.authed) {
|
|
792
|
+
if (result.refusal) {
|
|
793
|
+
markBearerCredentialRefused(event, result.refusal, getMcpConnectUrl(event));
|
|
794
|
+
}
|
|
795
|
+
return null;
|
|
796
|
+
}
|
|
797
|
+
const identity = result.identity;
|
|
790
798
|
if (!identity?.userEmail)
|
|
791
799
|
return null;
|
|
792
800
|
if (identity.orgId === null)
|
|
793
801
|
markExplicitPersonalOrgScope(event);
|
|
794
802
|
const orgId = await resolveMcpIdentityOrgId(identity);
|
|
803
|
+
if (identity.identityAssurance === "service" &&
|
|
804
|
+
identity.orgId &&
|
|
805
|
+
orgId === identity.orgId) {
|
|
806
|
+
markVerifiedServiceIdentityForEvent(event, {
|
|
807
|
+
userEmail: identity.userEmail,
|
|
808
|
+
orgId: identity.orgId,
|
|
809
|
+
});
|
|
810
|
+
}
|
|
795
811
|
return {
|
|
796
812
|
email: identity.userEmail,
|
|
797
813
|
token: bearerToken,
|
|
@@ -2682,20 +2698,6 @@ function loginHtmlResponse(config, event, requestPath, options = {}) {
|
|
|
2682
2698
|
},
|
|
2683
2699
|
});
|
|
2684
2700
|
}
|
|
2685
|
-
function resolveWorkspaceAccessAppId() {
|
|
2686
|
-
const app = getAppConfig().app;
|
|
2687
|
-
const workspaceId = app.workspaceId?.trim();
|
|
2688
|
-
if (workspaceId)
|
|
2689
|
-
return workspaceId;
|
|
2690
|
-
const isDispatch = [
|
|
2691
|
-
app.id,
|
|
2692
|
-
app.legacyId,
|
|
2693
|
-
app.template,
|
|
2694
|
-
app.slug,
|
|
2695
|
-
app.packageName,
|
|
2696
|
-
].some((value) => value?.trim().toLowerCase() === "dispatch");
|
|
2697
|
-
return isDispatch ? "dispatch" : "";
|
|
2698
|
-
}
|
|
2699
2701
|
function isHtmlDocumentRequest(event, pathname) {
|
|
2700
2702
|
if (!isReadMethod(event))
|
|
2701
2703
|
return false;
|
|
@@ -3049,6 +3051,9 @@ function createAuthGuardFn(app) {
|
|
|
3049
3051
|
if (isCredentialMembershipUnavailable(event)) {
|
|
3050
3052
|
return respondCredentialMembershipUnavailable(event);
|
|
3051
3053
|
}
|
|
3054
|
+
const refused = respondBearerCredentialRefused(event);
|
|
3055
|
+
if (refused)
|
|
3056
|
+
return refused;
|
|
3052
3057
|
if (p.startsWith("/api/") || p.startsWith("/_agent-native/")) {
|
|
3053
3058
|
setResponseStatus(event, 401);
|
|
3054
3059
|
// Dev-only breadcrumb for the loopback origin-label trap: the session
|
|
@@ -3615,6 +3620,17 @@ function normalizePath(path) {
|
|
|
3615
3620
|
function matchesPathList(path, paths) {
|
|
3616
3621
|
return paths.some((candidate) => {
|
|
3617
3622
|
const normalized = normalizePath(candidate);
|
|
3623
|
+
if (normalized.includes("/:")) {
|
|
3624
|
+
const expectedSegments = normalized.split("/");
|
|
3625
|
+
const actualSegments = path.split("/");
|
|
3626
|
+
return (expectedSegments.length === actualSegments.length &&
|
|
3627
|
+
expectedSegments.every((segment, index) => {
|
|
3628
|
+
if (/^:[A-Za-z][A-Za-z0-9_]*$/.test(segment)) {
|
|
3629
|
+
return Boolean(actualSegments[index]);
|
|
3630
|
+
}
|
|
3631
|
+
return segment === actualSegments[index];
|
|
3632
|
+
}));
|
|
3633
|
+
}
|
|
3618
3634
|
return path === normalized || path.startsWith(normalized + "/");
|
|
3619
3635
|
});
|
|
3620
3636
|
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { type H3Event } from "h3";
|
|
2
|
+
/**
|
|
3
|
+
* Why a presented bearer token was refused. `invalid` covers every token
|
|
4
|
+
* nothing here could verify. The others describe a credential this app issued
|
|
5
|
+
* and verified, so its holder has proven possession and can act on the reason.
|
|
6
|
+
*/
|
|
7
|
+
export type BearerCredentialRefusal = "invalid" | "revoked" | "unknown-connect-token" | "identity-mismatch" | "not-member" | "email-retired" | "service-principal-inactive";
|
|
8
|
+
/**
|
|
9
|
+
* One sentence naming the refusal. It travels in a `WWW-Authenticate`
|
|
10
|
+
* `error_description`, so it must stay printable ASCII without `"` or `\`.
|
|
11
|
+
*/
|
|
12
|
+
export declare function describeBearerCredentialRefusal(refusal: BearerCredentialRefusal): string;
|
|
13
|
+
export declare function describeBearerCredentialRefusalWithRecovery(refusal: BearerCredentialRefusal, connectUrl: string | undefined): string;
|
|
14
|
+
/**
|
|
15
|
+
* Records why this request's bearer token was refused, so the auth guard's
|
|
16
|
+
* 401 says why instead of a bare `Unauthorized`.
|
|
17
|
+
*/
|
|
18
|
+
export declare function markBearerCredentialRefused(event: H3Event, refusal: BearerCredentialRefusal, connectUrl: string | undefined): void;
|
|
19
|
+
export declare function respondBearerCredentialRefused(event: H3Event): {
|
|
20
|
+
error: string;
|
|
21
|
+
reason: BearerCredentialRefusal;
|
|
22
|
+
message: string;
|
|
23
|
+
} | null;
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { setResponseStatus } from "h3";
|
|
2
|
+
const CONTEXT_KEY = "__anBearerCredentialRefusal";
|
|
3
|
+
/**
|
|
4
|
+
* One sentence naming the refusal. It travels in a `WWW-Authenticate`
|
|
5
|
+
* `error_description`, so it must stay printable ASCII without `"` or `\`.
|
|
6
|
+
*/
|
|
7
|
+
export function describeBearerCredentialRefusal(refusal) {
|
|
8
|
+
switch (refusal) {
|
|
9
|
+
case "revoked":
|
|
10
|
+
return "This token was revoked.";
|
|
11
|
+
case "unknown-connect-token":
|
|
12
|
+
return "This app has no record of this connect token: another deployment minted it, or its record was deleted.";
|
|
13
|
+
case "identity-mismatch":
|
|
14
|
+
return "This connect token does not match the account it was issued to.";
|
|
15
|
+
case "not-member":
|
|
16
|
+
return "This token's account is no longer a member of the organization it was issued for.";
|
|
17
|
+
case "email-retired":
|
|
18
|
+
return "This token was issued to an email address the account no longer uses.";
|
|
19
|
+
case "service-principal-inactive":
|
|
20
|
+
return "This token belongs to a service principal an organization admin suspended or retired; only an admin can resume a suspended one.";
|
|
21
|
+
case "invalid":
|
|
22
|
+
return "This bearer token could not be verified: it is malformed, expired, issued for another app, or older than a required reconnect.";
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
/** RFC 6750 `error_description` characters: printable ASCII except `"` and `\`. */
|
|
26
|
+
const ERROR_DESCRIPTION_CHARACTERS = /^[\x20\x21\x23-\x5B\x5D-\x7E]*$/;
|
|
27
|
+
/**
|
|
28
|
+
* The connect URL serialized as an ASCII URL, or undefined when it still could
|
|
29
|
+
* not travel in an `error_description`. Its host comes from request headers
|
|
30
|
+
* and its base path from configuration, so neither is trusted to be safe.
|
|
31
|
+
*/
|
|
32
|
+
function headerSafeUrl(url) {
|
|
33
|
+
if (!url)
|
|
34
|
+
return undefined;
|
|
35
|
+
let href;
|
|
36
|
+
try {
|
|
37
|
+
href = new URL(url).href;
|
|
38
|
+
}
|
|
39
|
+
catch {
|
|
40
|
+
// coercion-ok: an unparseable connect URL is left out of the hint, which then names no URL.
|
|
41
|
+
return undefined;
|
|
42
|
+
}
|
|
43
|
+
return ERROR_DESCRIPTION_CHARACTERS.test(href) ? href : undefined;
|
|
44
|
+
}
|
|
45
|
+
export function describeBearerCredentialRefusalWithRecovery(refusal, connectUrl) {
|
|
46
|
+
const url = headerSafeUrl(connectUrl);
|
|
47
|
+
const recovery = url ? `Reconnect at ${url}.` : "Reconnect this connector.";
|
|
48
|
+
return `${describeBearerCredentialRefusal(refusal)} ${recovery}`;
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Records why this request's bearer token was refused, so the auth guard's
|
|
52
|
+
* 401 says why instead of a bare `Unauthorized`.
|
|
53
|
+
*/
|
|
54
|
+
export function markBearerCredentialRefused(event, refusal, connectUrl) {
|
|
55
|
+
const holder = event;
|
|
56
|
+
(holder.context ??= {})[CONTEXT_KEY] = {
|
|
57
|
+
reason: refusal,
|
|
58
|
+
message: describeBearerCredentialRefusalWithRecovery(refusal, connectUrl),
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
export function respondBearerCredentialRefused(event) {
|
|
62
|
+
const refused = event.context?.[CONTEXT_KEY];
|
|
63
|
+
if (!refused)
|
|
64
|
+
return null;
|
|
65
|
+
setResponseStatus(event, 401);
|
|
66
|
+
return { error: "Unauthorized", ...refused };
|
|
67
|
+
}
|
|
@@ -28,6 +28,7 @@ import { getAuthEmailForUserId, getRequiredAuthProviderForEmail, } from "../org/
|
|
|
28
28
|
import { autoJoinDomainMatchingOrgs } from "../org/auto-join-domain.js";
|
|
29
29
|
import { createFrameworkSCIMIdentity, frameworkOrgBridgePlugin, } from "../org/scim-provisioning.js";
|
|
30
30
|
import { enforceSignupAdmission, isBootstrapAdmin, } from "../org/signup-admission.js";
|
|
31
|
+
import { normalizeAnalyticsSessionId } from "../shared/analytics-session-id.js";
|
|
31
32
|
import { isGoogleProfileImageUrl } from "../shared/google-profile-image.js";
|
|
32
33
|
import { loadOptionalPeer } from "../shared/optional-peer.js";
|
|
33
34
|
import { PASSWORD_MAX_LENGTH, PASSWORD_MIN_LENGTH, } from "../shared/password-policy.js";
|
|
@@ -131,6 +132,7 @@ export async function emitSignupEventForCreatedUser(user, context) {
|
|
|
131
132
|
const requestHeaders = context?.headers ?? context?.request?.headers ?? null;
|
|
132
133
|
if (!requestHeaders)
|
|
133
134
|
return;
|
|
135
|
+
const requestSessionId = normalizeAnalyticsSessionId(requestHeaders.get("x-agent-native-session-id"));
|
|
134
136
|
const scoped = hasContinuationLocalRequestContext()
|
|
135
137
|
? getRequestContext()
|
|
136
138
|
: undefined;
|
|
@@ -146,7 +148,8 @@ export async function emitSignupEventForCreatedUser(user, context) {
|
|
|
146
148
|
signupAttributionContextFromCookieHeader(requestHeaders.get("cookie"));
|
|
147
149
|
attribution = browser?.attribution;
|
|
148
150
|
anonymousId = browser?.anonymousId;
|
|
149
|
-
sessionId =
|
|
151
|
+
sessionId =
|
|
152
|
+
normalizeAnalyticsSessionId(browser?.sessionId) ?? requestSessionId;
|
|
150
153
|
}
|
|
151
154
|
catch (err) {
|
|
152
155
|
console.error("[auth] failed to derive signup attribution", err);
|
|
@@ -155,9 +158,13 @@ export async function emitSignupEventForCreatedUser(user, context) {
|
|
|
155
158
|
// so an account created by another signed-in user (admin or API creation)
|
|
156
159
|
// must not inherit it.
|
|
157
160
|
const actingUserId = context?.context?.session?.user?.id;
|
|
158
|
-
|
|
161
|
+
const ownsSignupAttribution = !actingUserId || actingUserId === user.id;
|
|
162
|
+
const eventAttribution = ownsSignupAttribution ? attribution : undefined;
|
|
163
|
+
const eventAnonymousId = ownsSignupAttribution ? anonymousId : undefined;
|
|
164
|
+
const eventSessionId = ownsSignupAttribution ? sessionId : undefined;
|
|
165
|
+
if (user.id && eventAttribution) {
|
|
159
166
|
try {
|
|
160
|
-
await persistUserFirstTouchAttribution(user.id,
|
|
167
|
+
await persistUserFirstTouchAttribution(user.id, eventAttribution);
|
|
161
168
|
}
|
|
162
169
|
catch (err) {
|
|
163
170
|
// The signup itself already succeeded; the event below still carries
|
|
@@ -177,9 +184,9 @@ export async function emitSignupEventForCreatedUser(user, context) {
|
|
|
177
184
|
authUserId: user.id,
|
|
178
185
|
email,
|
|
179
186
|
name: user.name,
|
|
180
|
-
attribution,
|
|
181
|
-
anonymousId,
|
|
182
|
-
sessionId,
|
|
187
|
+
attribution: eventAttribution,
|
|
188
|
+
anonymousId: eventAnonymousId,
|
|
189
|
+
sessionId: eventSessionId,
|
|
183
190
|
});
|
|
184
191
|
}
|
|
185
192
|
export async function hasGoogleAuthIdentity(email) {
|
|
@@ -302,6 +302,8 @@ export declare function isBuilderAccountProvisioningEnabled(): boolean;
|
|
|
302
302
|
export declare function provisionBuilderAccount(input: {
|
|
303
303
|
email: string;
|
|
304
304
|
name?: string;
|
|
305
|
+
agentNativeApp?: string;
|
|
306
|
+
agentNativeTemplate?: string;
|
|
305
307
|
}): Promise<BuilderRelayCredentials>;
|
|
306
308
|
/** @deprecated Repository-backed Builder projects are retained for compatibility. */
|
|
307
309
|
export declare function findBuilderProjectForRepo(args: BuilderProjectLookupArgs): Promise<BuilderProjectResult | null>;
|
|
@@ -1819,14 +1819,22 @@ export async function provisionBuilderAccount(input) {
|
|
|
1819
1819
|
throw new Error("Builder account provisioning requires a valid email.");
|
|
1820
1820
|
}
|
|
1821
1821
|
const name = input.name?.trim().slice(0, 120) || email.slice(0, email.indexOf("@"));
|
|
1822
|
+
const agentNativeApp = cleanTrackingParam(input.agentNativeApp);
|
|
1823
|
+
const agentNativeTemplate = cleanTrackingParam(input.agentNativeTemplate);
|
|
1824
|
+
const version = agentNativeApp || agentNativeTemplate
|
|
1825
|
+
? "agent-native-account-v2"
|
|
1826
|
+
: "agent-native-account-v1";
|
|
1822
1827
|
const timestamp = String(Date.now());
|
|
1823
1828
|
const requestId = randomBytes(32).toString("base64url");
|
|
1824
1829
|
const signaturePayload = [
|
|
1825
|
-
|
|
1830
|
+
version,
|
|
1826
1831
|
timestamp,
|
|
1827
1832
|
requestId,
|
|
1828
1833
|
email,
|
|
1829
1834
|
name,
|
|
1835
|
+
...(version === "agent-native-account-v2"
|
|
1836
|
+
? [agentNativeApp ?? "", agentNativeTemplate ?? ""]
|
|
1837
|
+
: []),
|
|
1830
1838
|
].join("\n");
|
|
1831
1839
|
const signature = createHmac("sha256", builderAccountProvisioningSecret())
|
|
1832
1840
|
.update(signaturePayload)
|
|
@@ -1835,12 +1843,17 @@ export async function provisionBuilderAccount(input) {
|
|
|
1835
1843
|
method: "POST",
|
|
1836
1844
|
headers: {
|
|
1837
1845
|
"Content-Type": "application/json",
|
|
1838
|
-
"x-agent-native-account-version":
|
|
1846
|
+
"x-agent-native-account-version": version,
|
|
1839
1847
|
"x-agent-native-account-timestamp": timestamp,
|
|
1840
1848
|
"x-agent-native-account-request-id": requestId,
|
|
1841
1849
|
"x-agent-native-account-signature": signature,
|
|
1842
1850
|
},
|
|
1843
|
-
body: JSON.stringify({
|
|
1851
|
+
body: JSON.stringify({
|
|
1852
|
+
email,
|
|
1853
|
+
name,
|
|
1854
|
+
...(agentNativeApp ? { agentNativeApp } : {}),
|
|
1855
|
+
...(agentNativeTemplate ? { agentNativeTemplate } : {}),
|
|
1856
|
+
}),
|
|
1844
1857
|
}, "account provisioning");
|
|
1845
1858
|
const parsed = await readBuilderApiObject(response, "account provisioning");
|
|
1846
1859
|
if (!response.ok) {
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { runErrorTelemetryProperties, runTelemetryException, } from "../agent/engine/error-telemetry.js";
|
|
1
2
|
import { isTransientDatabaseError } from "../db/client.js";
|
|
2
3
|
import { withFailureContext } from "../observability/failure-context.js";
|
|
3
4
|
import { classifyError } from "./error-noise-filter.js";
|
|
@@ -106,9 +107,11 @@ function emit(error, context) {
|
|
|
106
107
|
return eventId;
|
|
107
108
|
}
|
|
108
109
|
function errorLabel(error) {
|
|
109
|
-
const { name, message } = (error ?? {});
|
|
110
|
+
const { name, message, errorCode } = (error ?? {});
|
|
110
111
|
const text = typeof message === "string" ? message : String(error);
|
|
111
|
-
|
|
112
|
+
// An omitted run failure's message is fixed text, so its code is what tells it apart.
|
|
113
|
+
const code = typeof errorCode === "string" ? ` [${errorCode}]` : "";
|
|
114
|
+
return `${typeof name === "string" ? name : "Error"}${code}: ${text}`.slice(0, 120);
|
|
112
115
|
}
|
|
113
116
|
function recordSuppressed(state, error) {
|
|
114
117
|
state.suppressed += 1;
|
|
@@ -255,6 +258,7 @@ export function captureError(error, callerContext = {}) {
|
|
|
255
258
|
}
|
|
256
259
|
: callerContext;
|
|
257
260
|
let outgoing = context;
|
|
261
|
+
let reportedError = error;
|
|
258
262
|
try {
|
|
259
263
|
const verdict = classifyError(error, { tags: context.tags });
|
|
260
264
|
if (verdict.drop) {
|
|
@@ -266,10 +270,23 @@ export function captureError(error, callerContext = {}) {
|
|
|
266
270
|
if (errorCode && context.tags?.errorCode === undefined) {
|
|
267
271
|
outgoing = { ...context, tags: { ...context.tags, errorCode } };
|
|
268
272
|
}
|
|
273
|
+
// The failure packet copies the code tag, so it must be sanitized first.
|
|
274
|
+
if (context.errorMessagePolicy === "omit") {
|
|
275
|
+
const properties = runErrorTelemetryProperties(outgoing.tags?.errorCode, error instanceof Error ? error.message : undefined);
|
|
276
|
+
reportedError = runTelemetryException(error, properties.error_code);
|
|
277
|
+
outgoing = {
|
|
278
|
+
...outgoing,
|
|
279
|
+
tags: {
|
|
280
|
+
...outgoing.tags,
|
|
281
|
+
errorCode: properties.error_code,
|
|
282
|
+
errorCause: properties.error_cause,
|
|
283
|
+
},
|
|
284
|
+
};
|
|
285
|
+
}
|
|
269
286
|
const cls = classifyFloodClass(error, outgoing);
|
|
270
287
|
outgoing = withPacket(outgoing, { errorCode, failureClass: cls });
|
|
271
288
|
if (cls) {
|
|
272
|
-
const admitted = admitFloodEvent(cls,
|
|
289
|
+
const admitted = admitFloodEvent(cls, reportedError, outgoing);
|
|
273
290
|
if (!admitted)
|
|
274
291
|
return undefined;
|
|
275
292
|
outgoing = admitted;
|
|
@@ -278,7 +295,14 @@ export function captureError(error, callerContext = {}) {
|
|
|
278
295
|
}
|
|
279
296
|
catch {
|
|
280
297
|
outgoing = context;
|
|
298
|
+
if (context.errorMessagePolicy === "omit") {
|
|
299
|
+
reportedError = runTelemetryException(error, "unknown");
|
|
300
|
+
outgoing = {
|
|
301
|
+
...context,
|
|
302
|
+
tags: { ...context.tags, errorCode: "unknown" },
|
|
303
|
+
};
|
|
304
|
+
}
|
|
281
305
|
}
|
|
282
|
-
return emit(
|
|
306
|
+
return emit(reportedError, outgoing);
|
|
283
307
|
}
|
|
284
308
|
export const captureServerError = captureError;
|
|
@@ -32,6 +32,7 @@ function contentText(parts) {
|
|
|
32
32
|
function createCompletionAbortSignal(signal, timeoutMs) {
|
|
33
33
|
const controller = new AbortController();
|
|
34
34
|
const cleanupFns = [];
|
|
35
|
+
let timeoutError;
|
|
35
36
|
if (signal) {
|
|
36
37
|
if (signal.aborted) {
|
|
37
38
|
controller.abort(signal.reason);
|
|
@@ -44,12 +45,14 @@ function createCompletionAbortSignal(signal, timeoutMs) {
|
|
|
44
45
|
}
|
|
45
46
|
if (timeoutMs !== undefined) {
|
|
46
47
|
const timeout = setTimeout(() => {
|
|
47
|
-
|
|
48
|
+
timeoutError = new EngineError(`completeText timed out after ${timeoutMs}ms`, { errorCode: "complete_text_timeout" });
|
|
49
|
+
controller.abort(timeoutError);
|
|
48
50
|
}, timeoutMs);
|
|
49
51
|
cleanupFns.push(() => clearTimeout(timeout));
|
|
50
52
|
}
|
|
51
53
|
return {
|
|
52
54
|
signal: controller.signal,
|
|
55
|
+
getTimeoutError: () => timeoutError,
|
|
53
56
|
cleanup: () => {
|
|
54
57
|
for (const cleanup of cleanupFns)
|
|
55
58
|
cleanup();
|
|
@@ -85,7 +88,8 @@ export async function completeText(options) {
|
|
|
85
88
|
(await getStoredModelForEngine(engine, { appId: options.appId })) ??
|
|
86
89
|
engine.defaultModel;
|
|
87
90
|
const model = normalizeModelForEngine(engine, modelCandidate);
|
|
88
|
-
const
|
|
91
|
+
const completionAbort = createCompletionAbortSignal(options.signal, options.timeoutMs);
|
|
92
|
+
const { signal } = completionAbort;
|
|
89
93
|
let streamedText = "";
|
|
90
94
|
let finalContent;
|
|
91
95
|
let usage;
|
|
@@ -131,9 +135,18 @@ export async function completeText(options) {
|
|
|
131
135
|
}
|
|
132
136
|
}
|
|
133
137
|
}
|
|
138
|
+
catch (error) {
|
|
139
|
+
const timeoutError = completionAbort.getTimeoutError();
|
|
140
|
+
if (timeoutError)
|
|
141
|
+
throw timeoutError;
|
|
142
|
+
throw error;
|
|
143
|
+
}
|
|
134
144
|
finally {
|
|
135
|
-
cleanup();
|
|
145
|
+
completionAbort.cleanup();
|
|
136
146
|
}
|
|
147
|
+
const timeoutError = completionAbort.getTimeoutError();
|
|
148
|
+
if (timeoutError)
|
|
149
|
+
throw timeoutError;
|
|
137
150
|
const content = finalContent ?? [{ type: "text", text: streamedText }];
|
|
138
151
|
return {
|
|
139
152
|
text: contentText(content) || streamedText,
|
|
@@ -1480,6 +1480,8 @@ export async function activateBuilderAccount(event, input) {
|
|
|
1480
1480
|
const credentials = await provisionBuilderAccount({
|
|
1481
1481
|
email: ownerEmail,
|
|
1482
1482
|
name: session.name,
|
|
1483
|
+
agentNativeApp: input.tracking.agentNativeApp,
|
|
1484
|
+
agentNativeTemplate: input.tracking.agentNativeTemplate,
|
|
1483
1485
|
});
|
|
1484
1486
|
const { writeBuilderCredentials } = await import("./credential-provider.js");
|
|
1485
1487
|
const written = await writeBuilderCredentials(ownerEmail, credentials, activationOrg ?? undefined);
|
|
@@ -33,6 +33,7 @@ import { resolveDeployEnvironment } from "./deploy-environment.js";
|
|
|
33
33
|
import { DEV_ACTION_DISCOVERY_PATH, readDevActionDiscoveryFile, } from "./dev-action-discovery.js";
|
|
34
34
|
import { getH3App } from "./framework-request-handler.js";
|
|
35
35
|
import { getRequestOrgId, getRequestUserEmail, runWithRequestContext, } from "./request-context.js";
|
|
36
|
+
import { getForwardedRequestOrigin } from "./request-origin.js";
|
|
36
37
|
export const DEV_ACTION_ROUTE = "/_agent-native/dev/action";
|
|
37
38
|
export const DEV_DB_QUERY_ROUTE = "/_agent-native/dev/db-query";
|
|
38
39
|
export const DEV_ACTION_TOKEN_HEADER = "x-agent-native-dev-token";
|
|
@@ -231,7 +232,12 @@ export function mountDevActionForwardRoute(nitroApp, actions, options) {
|
|
|
231
232
|
const userEmail = getHeader(event, DEV_ACTION_USER_HEADER) ||
|
|
232
233
|
(await resolveDevUserEmail());
|
|
233
234
|
const orgId = getHeader(event, DEV_ACTION_ORG_HEADER) || undefined;
|
|
234
|
-
|
|
235
|
+
const context = {
|
|
236
|
+
userEmail,
|
|
237
|
+
orgId,
|
|
238
|
+
requestOrigin: getForwardedRequestOrigin(event),
|
|
239
|
+
};
|
|
240
|
+
return runWithRequestContext(context, async () => {
|
|
235
241
|
try {
|
|
236
242
|
const ctx = {
|
|
237
243
|
userEmail: getRequestUserEmail(),
|
|
@@ -4,7 +4,7 @@ import { getAppConfig } from "../app-config/index.js";
|
|
|
4
4
|
import { normalizeAnalyticsAnonymousId } from "../shared/analytics-anonymous-id.js";
|
|
5
5
|
import { normalizeAppPath } from "../shared/sign-in-journey.js";
|
|
6
6
|
import { getAppBasePathFromViteEnv } from "./app-base-path.js";
|
|
7
|
-
import { readAnalyticsAnonymousId, signupAttributionFromCookieHeader, } from "./attribution.js";
|
|
7
|
+
import { readAnalyticsAnonymousId, readAnalyticsSessionId, signupAttributionFromCookieHeader, } from "./attribution.js";
|
|
8
8
|
import { getBetterAuthUserIdForEmail, hasBetterAuthUserEmail, trackSignupEvent, } from "./better-auth-instance.js";
|
|
9
9
|
import { getWorkspaceA2ADerivedSecret } from "./derived-secret.js";
|
|
10
10
|
import { writeDesktopSso } from "./desktop-sso.js";
|
|
@@ -575,10 +575,12 @@ export async function createOAuthSession(event, email, opts) {
|
|
|
575
575
|
setFirstRunOnboardingCookie(event);
|
|
576
576
|
}
|
|
577
577
|
if (shouldTrackSignup && opts.trackSignup) {
|
|
578
|
+
const signupCookieHeader = getHeader(event, "cookie") ?? null;
|
|
578
579
|
const attribution = opts.trackSignup.attribution ??
|
|
579
|
-
signupAttributionFromCookieHeader(
|
|
580
|
+
signupAttributionFromCookieHeader(signupCookieHeader);
|
|
580
581
|
const anonymousId = opts.trackSignup.signupAnonymousId ??
|
|
581
|
-
readAnalyticsAnonymousId(
|
|
582
|
+
readAnalyticsAnonymousId(signupCookieHeader);
|
|
583
|
+
const sessionId = readAnalyticsSessionId(signupCookieHeader);
|
|
582
584
|
const authUserId = (await getBetterAuthUserIdForEmail(email)) ??
|
|
583
585
|
opts.trackSignup.canonicalAuthUserId;
|
|
584
586
|
await trackSignupEvent({
|
|
@@ -590,6 +592,7 @@ export async function createOAuthSession(event, email, opts) {
|
|
|
590
592
|
name: opts.trackSignup.name,
|
|
591
593
|
attribution,
|
|
592
594
|
anonymousId,
|
|
595
|
+
sessionId,
|
|
593
596
|
});
|
|
594
597
|
}
|
|
595
598
|
// Desktop SSO: record this session in the home-dir broker file so
|
package/dist/server/index.d.ts
CHANGED
|
@@ -79,7 +79,7 @@ export { attachToolSearch, createToolSearchEntry, searchToolRegistry, TOOL_SEARC
|
|
|
79
79
|
export { filterFrameworkToolGroups, frameworkGroupEnabled, resolveFrameworkTools, FRAMEWORK_TOOL_GROUPS, type FrameworkToolGroup, type FrameworkToolsConfig, type FrameworkToolsOption, type ResolvedFrameworkTools, } from "../framework-tools.js";
|
|
80
80
|
export { buildCompactSkillsSummary, registerPromptContextProvider, type PromptContextProvider, type PromptContextProviderContext, type PromptContextProviderContribution, } from "./agent-chat/prompt-resources.js";
|
|
81
81
|
export { mountActionRoutes, type MountActionRoutesOptions, type ActionRouteAuthAdapter, type ActionRouteResolvedCaller, } from "./action-routes.js";
|
|
82
|
-
export { AGENT_RUN_OWNER_CONTEXT_KEY, seedAgentRunOwnerContext, type AgentRunOwnerContext, } from "./agent-run-context.js";
|
|
82
|
+
export { AGENT_RUN_OWNER_CONTEXT_KEY, readBrowserSessionIdHeader, seedAgentRunOwnerContext, type AgentRunOwnerContext, } from "./agent-run-context.js";
|
|
83
83
|
export { runWithRequestContext, hasRequestContext, hasRequestBoundary, getRequestContext, getRequestUserEmail, getRequestUserName, getRequestOrgId, getAmbientUserEmail, getAmbientOrgId, getRequestTimezone, getRequestRunContext, getCredentialContext, isIntegrationCallerRequest, type RequestContext, type RequestRunContext, } from "./request-context.js";
|
|
84
84
|
export { formatDateInTimezone, todayInTimezone } from "./date-utils.js";
|
|
85
85
|
export { createOnboardingPlugin, defaultOnboardingPlugin, } from "../onboarding/plugin.js";
|
package/dist/server/index.js
CHANGED
|
@@ -74,7 +74,7 @@ export { attachToolSearch, createToolSearchEntry, searchToolRegistry, TOOL_SEARC
|
|
|
74
74
|
export { filterFrameworkToolGroups, frameworkGroupEnabled, resolveFrameworkTools, FRAMEWORK_TOOL_GROUPS, } from "../framework-tools.js";
|
|
75
75
|
export { buildCompactSkillsSummary, registerPromptContextProvider, } from "./agent-chat/prompt-resources.js";
|
|
76
76
|
export { mountActionRoutes, } from "./action-routes.js";
|
|
77
|
-
export { AGENT_RUN_OWNER_CONTEXT_KEY, seedAgentRunOwnerContext, } from "./agent-run-context.js";
|
|
77
|
+
export { AGENT_RUN_OWNER_CONTEXT_KEY, readBrowserSessionIdHeader, seedAgentRunOwnerContext, } from "./agent-run-context.js";
|
|
78
78
|
export { runWithRequestContext, hasRequestContext, hasRequestBoundary, getRequestContext, getRequestUserEmail, getRequestUserName, getRequestOrgId, getAmbientUserEmail, getAmbientOrgId, getRequestTimezone, getRequestRunContext, getCredentialContext, isIntegrationCallerRequest, } from "./request-context.js";
|
|
79
79
|
export { formatDateInTimezone, todayInTimezone } from "./date-utils.js";
|
|
80
80
|
export { createOnboardingPlugin, defaultOnboardingPlugin, } from "../onboarding/plugin.js";
|
|
@@ -54,8 +54,8 @@ export declare function createRealtimeTokenHandler(): import("h3").EventHandlerW
|
|
|
54
54
|
expiresAt?: undefined;
|
|
55
55
|
ttlSeconds?: undefined;
|
|
56
56
|
} | {
|
|
57
|
-
error?: undefined;
|
|
58
57
|
token: string;
|
|
59
58
|
expiresAt: string;
|
|
60
59
|
ttlSeconds: number;
|
|
60
|
+
error?: undefined;
|
|
61
61
|
}>>;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { defineEventHandler, getHeader, getMethod, readRawBody, setResponseHeader, setResponseStatus, } from "h3";
|
|
2
2
|
import { getMcpOAuthBearerSession, getSession, } from "./auth.js";
|
|
3
|
+
import { respondBearerCredentialRefused } from "./bearer-credential-refusal.js";
|
|
3
4
|
import { isCredentialMembershipUnavailable, respondCredentialMembershipUnavailable, } from "./credential-membership-unavailable.js";
|
|
4
5
|
import { getAppUrl } from "./google-oauth.js";
|
|
5
6
|
import { RECAP_IMAGE_CONTENT_TYPE, RECAP_IMAGE_MAX_BYTES, getRecapImage, isValidRecapImageToken, saveRecapImage, } from "./recap-image-store.js";
|
|
@@ -55,6 +56,9 @@ async function handleUpload(event) {
|
|
|
55
56
|
return respondCredentialMembershipUnavailable(event);
|
|
56
57
|
}
|
|
57
58
|
if (!session?.email) {
|
|
59
|
+
const refused = respondBearerCredentialRefused(event);
|
|
60
|
+
if (refused)
|
|
61
|
+
return refused;
|
|
58
62
|
setResponseStatus(event, 401);
|
|
59
63
|
return { error: "Authentication required" };
|
|
60
64
|
}
|