@agent-native/core 0.202.0 → 0.202.1-nightly-20261006213000
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/automation/index.d.ts +1 -1
- package/dist/cli/create.d.ts +2 -1
- package/dist/cli/create.js +17 -4
- package/dist/cli/template-sync.js +2 -1
- package/dist/cli/workspacify.d.ts +1 -0
- package/dist/cli/workspacify.js +4 -0
- package/dist/collab/routes.d.ts +1 -1
- package/dist/email-catalog/redact-body.js +1 -1
- package/dist/file-upload/actions/upload-image.d.ts +1 -1
- package/dist/mcp/build-server.d.ts +0 -1
- package/dist/mcp/build-server.js +10 -59
- package/dist/observability/routes.d.ts +3 -3
- package/dist/provider-api/actions/custom-provider-registration.d.ts +4 -4
- package/dist/secrets/routes.d.ts +6 -6
- package/dist/server/agent-engine-ollama-models-route.d.ts +2 -2
- package/dist/server/auth.js +43 -1
- package/dist/server/better-auth-instance.js +6 -8
- package/dist/server/email-auth-links.d.ts +11 -0
- package/dist/server/email-auth-links.js +126 -0
- package/dist/server/fusion-app.js +11 -1
- package/dist/shared/auth-copy.d.ts +3 -0
- package/dist/shared/auth-copy.js +33 -0
- package/dist/sharing/actions/list-resource-shares.d.ts +1 -1
- package/dist/triggers/condition-evaluator.d.ts +18 -5
- package/dist/triggers/condition-evaluator.js +52 -42
- package/dist/triggers/dispatcher.js +27 -21
- package/package.json +3 -3
|
@@ -139,8 +139,8 @@ export declare function createAutomationCallbackHandler(runtime: AutomationRunti
|
|
|
139
139
|
duplicate?: undefined;
|
|
140
140
|
eventId?: undefined;
|
|
141
141
|
} | {
|
|
142
|
-
error?: undefined;
|
|
143
142
|
accepted: boolean;
|
|
144
143
|
duplicate: boolean;
|
|
145
144
|
eventId: string;
|
|
145
|
+
error?: undefined;
|
|
146
146
|
}>;
|
package/dist/cli/create.d.ts
CHANGED
|
@@ -102,7 +102,7 @@ export declare function detectWorkspace(startDir: string): {
|
|
|
102
102
|
} | null;
|
|
103
103
|
export { parseWorkspaceScope };
|
|
104
104
|
/** @internal — exported for E2E tests */
|
|
105
|
-
export { mergeWorkspaceYamlSections as _mergeWorkspaceYamlSections, scaffoldWorkspaceRoot as _scaffoldWorkspaceRoot, mergeWorkspaceYamlListItems as _mergeWorkspaceYamlListItems, scaffoldOneAppIntoWorkspace as _scaffoldOneAppIntoWorkspace, CreateWizardCancelledError as _CreateWizardCancelledError, ensureGuardedScaffold as _ensureGuardedScaffold, scaffoldAppTemplate as _scaffoldAppTemplate, scaffoldRequiredPackages as _scaffoldRequiredPackages, postProcessStandalone as _postProcessStandalone, loadCatalog as _loadCatalog, fixPackageJsonName as _fixPackageJsonName, renameGitignore as _renameGitignore, discoverEnclosingRepo as _discoverEnclosingRepo, rewriteNetlifyToml as _rewriteNetlifyToml, getCoreDependencyVersion as _getCoreDependencyVersion, getDispatchDependencyVersion as _getDispatchDependencyVersion, getToolkitDependencyVersion as _getToolkitDependencyVersion, getAgentKitDependencyVersion as _getAgentKitDependencyVersion, prepareLocalWorkspaceOverrides as _prepareLocalWorkspaceOverrides, ensureLocalPackageBuildOutputs as _ensureLocalPackageBuildOutputs, getCorePackageVersion as _getCorePackageVersion, getGitHubTemplateRef as _getGitHubTemplateRef, getGitHubTemplateRefCandidates as _getGitHubTemplateRefCandidates, githubTarballUrl as _githubTarballUrl, findLocalTemplateFrom as _findLocalTemplateFrom, workspaceAppNameForTemplateSelection as _workspaceAppNameForTemplateSelection, startShapePromptOptions as _startShapePromptOptions, standaloneTemplatePromptOptions as _standaloneTemplatePromptOptions, parseCommunityTemplateSelection as _parseCommunityTemplateSelection, communityTemplateTrustMessage as _communityTemplateTrustMessage, communityTemplateTarballUrl as _communityTemplateTarballUrl, assertCommunityTemplateRoot as _assertCommunityTemplateRoot, assertSafeCommunityArchiveListing as _assertSafeCommunityArchiveListing, validateCommunityArchive as _validateCommunityArchive, resolveCommunityTemplateSource as _resolveCommunityTemplateSource, discoverCommunityWorkspaceApps as _discoverCommunityWorkspaceApps, normalizeCommunityWorkspaceAppDependencies as _normalizeCommunityWorkspaceAppDependencies, shouldSkipScaffoldEntry as _shouldSkipScaffoldEntry, removeWorkspaceOnlyTemplateWiring as _removeWorkspaceOnlyTemplateWiring, tarExtractArgs as _tarExtractArgs, extractTarball as _extractTarball, materializeArchiveSymlinks as _materializeArchiveSymlinks, downloadGitHubSubdir as _downloadGitHubSubdir, findLocalTemplate as _findLocalTemplate, templateSourceName as _templateSourceName, normalizeTemplateName as _normalizeTemplateName, appTitleForScaffold as _appTitleForScaffold, replacePlaceholders as _replacePlaceholders, rewriteTrackingAppId as _rewriteTrackingAppId, rewriteAgentChatAppId as _rewriteAgentChatAppId, applyScaffoldIdentity as _applyScaffoldIdentity, ensureScaffoldEmailBrandingConfig as _ensureScaffoldEmailBrandingConfig, fixWebManifestName as _fixWebManifestName, copyDir as _copyDir, localTemplateSourceKind as _localTemplateSourceKind, REPO as _REPO, TEMPLATES_DIR as _TEMPLATES_DIR, };
|
|
105
|
+
export { mergeWorkspaceYamlSections as _mergeWorkspaceYamlSections, scaffoldWorkspaceRoot as _scaffoldWorkspaceRoot, mergeWorkspaceYamlListItems as _mergeWorkspaceYamlListItems, scaffoldOneAppIntoWorkspace as _scaffoldOneAppIntoWorkspace, CreateWizardCancelledError as _CreateWizardCancelledError, ensureGuardedScaffold as _ensureGuardedScaffold, scaffoldAppTemplate as _scaffoldAppTemplate, scaffoldRequiredPackages as _scaffoldRequiredPackages, postProcessStandalone as _postProcessStandalone, loadCatalog as _loadCatalog, fixPackageJsonName as _fixPackageJsonName, renameGitignore as _renameGitignore, discoverEnclosingRepo as _discoverEnclosingRepo, rewriteNetlifyToml as _rewriteNetlifyToml, getCoreDependencyVersion as _getCoreDependencyVersion, getDispatchDependencyVersion as _getDispatchDependencyVersion, getOtelDependencyVersion as _getOtelDependencyVersion, getToolkitDependencyVersion as _getToolkitDependencyVersion, getAgentKitDependencyVersion as _getAgentKitDependencyVersion, prepareLocalWorkspaceOverrides as _prepareLocalWorkspaceOverrides, ensureLocalPackageBuildOutputs as _ensureLocalPackageBuildOutputs, getCorePackageVersion as _getCorePackageVersion, getGitHubTemplateRef as _getGitHubTemplateRef, getGitHubTemplateRefCandidates as _getGitHubTemplateRefCandidates, githubTarballUrl as _githubTarballUrl, findLocalTemplateFrom as _findLocalTemplateFrom, workspaceAppNameForTemplateSelection as _workspaceAppNameForTemplateSelection, startShapePromptOptions as _startShapePromptOptions, standaloneTemplatePromptOptions as _standaloneTemplatePromptOptions, parseCommunityTemplateSelection as _parseCommunityTemplateSelection, communityTemplateTrustMessage as _communityTemplateTrustMessage, communityTemplateTarballUrl as _communityTemplateTarballUrl, assertCommunityTemplateRoot as _assertCommunityTemplateRoot, assertSafeCommunityArchiveListing as _assertSafeCommunityArchiveListing, validateCommunityArchive as _validateCommunityArchive, resolveCommunityTemplateSource as _resolveCommunityTemplateSource, discoverCommunityWorkspaceApps as _discoverCommunityWorkspaceApps, normalizeCommunityWorkspaceAppDependencies as _normalizeCommunityWorkspaceAppDependencies, shouldSkipScaffoldEntry as _shouldSkipScaffoldEntry, removeWorkspaceOnlyTemplateWiring as _removeWorkspaceOnlyTemplateWiring, tarExtractArgs as _tarExtractArgs, extractTarball as _extractTarball, materializeArchiveSymlinks as _materializeArchiveSymlinks, downloadGitHubSubdir as _downloadGitHubSubdir, findLocalTemplate as _findLocalTemplate, templateSourceName as _templateSourceName, normalizeTemplateName as _normalizeTemplateName, appTitleForScaffold as _appTitleForScaffold, replacePlaceholders as _replacePlaceholders, rewriteTrackingAppId as _rewriteTrackingAppId, rewriteAgentChatAppId as _rewriteAgentChatAppId, applyScaffoldIdentity as _applyScaffoldIdentity, ensureScaffoldEmailBrandingConfig as _ensureScaffoldEmailBrandingConfig, fixWebManifestName as _fixWebManifestName, copyDir as _copyDir, localTemplateSourceKind as _localTemplateSourceKind, REPO as _REPO, TEMPLATES_DIR as _TEMPLATES_DIR, };
|
|
106
106
|
declare function tarExtractArgs(tarPath: string, destDir: string, options?: {
|
|
107
107
|
skipAgentSymlinks?: boolean;
|
|
108
108
|
untrustedCommunityArchive?: boolean;
|
|
@@ -157,6 +157,7 @@ declare function ensureScaffoldEmailBrandingConfig(appDir: string, appName: stri
|
|
|
157
157
|
declare function fixWebManifestName(appDir: string, name: string, templateName?: string, sourceIdentity?: ScaffoldSourceIdentity): void;
|
|
158
158
|
declare function getCoreDependencyVersion(): string;
|
|
159
159
|
declare function getDispatchDependencyVersion(): string;
|
|
160
|
+
declare function getOtelDependencyVersion(): string;
|
|
160
161
|
declare function getToolkitDependencyVersion(): string;
|
|
161
162
|
declare function getAgentKitDependencyVersion(): string;
|
|
162
163
|
interface PreparedWorkspaceOverrides {
|
package/dist/cli/create.js
CHANGED
|
@@ -92,9 +92,7 @@ const FIRST_PARTY_TARBALL_SYMLINK_EXCLUDES = [
|
|
|
92
92
|
// the files that import them. A scaffold cannot install these (a standalone app
|
|
93
93
|
// resolves them from npm, a new workspace has no such package), so it drops the
|
|
94
94
|
// dependency and those files. Publishing a package removes its entry here.
|
|
95
|
-
const WORKSPACE_ONLY_TEMPLATE_WIRING = {
|
|
96
|
-
"@agent-native/otel": ["server/plugins/otel.ts"],
|
|
97
|
-
};
|
|
95
|
+
const WORKSPACE_ONLY_TEMPLATE_WIRING = {};
|
|
98
96
|
const TAR_LISTING_MAX_BUFFER = 100 * 1024 * 1024;
|
|
99
97
|
const localPackageTarballs = new Map();
|
|
100
98
|
const IN_PLACE_ALLOWLIST = new Set([
|
|
@@ -557,6 +555,7 @@ async function createWorkspaceInteractive(name, opts, clack) {
|
|
|
557
555
|
dispatchDependencyVersion: getDispatchDependencyVersion(),
|
|
558
556
|
toolkitDependencyVersion: getToolkitDependencyVersion(),
|
|
559
557
|
agentKitDependencyVersion: getAgentKitDependencyVersion(),
|
|
558
|
+
otelDependencyVersion: getOtelDependencyVersion(),
|
|
560
559
|
});
|
|
561
560
|
fixPackageJsonName(appDir, appName, templateName, {
|
|
562
561
|
...resolution,
|
|
@@ -800,6 +799,7 @@ async function scaffoldOneAppIntoWorkspace(workspace, appName, templateName, cla
|
|
|
800
799
|
dispatchDependencyVersion: getDispatchDependencyVersion(),
|
|
801
800
|
toolkitDependencyVersion: getToolkitDependencyVersion(),
|
|
802
801
|
agentKitDependencyVersion: getAgentKitDependencyVersion(),
|
|
802
|
+
otelDependencyVersion: getOtelDependencyVersion(),
|
|
803
803
|
});
|
|
804
804
|
fixPackageJsonName(appDir, appName, templateName, {
|
|
805
805
|
...resolution,
|
|
@@ -1655,6 +1655,9 @@ function postProcessStandalone(name, targetDir, templateName, resolution) {
|
|
|
1655
1655
|
else if (key === "@agent-native/agentkit") {
|
|
1656
1656
|
deps[key] = getAgentKitDependencyVersion();
|
|
1657
1657
|
}
|
|
1658
|
+
else if (key === "@agent-native/otel") {
|
|
1659
|
+
deps[key] = getOtelDependencyVersion();
|
|
1660
|
+
}
|
|
1658
1661
|
else if (typeof val === "string" && val.startsWith("workspace:")) {
|
|
1659
1662
|
deps[key] = "latest";
|
|
1660
1663
|
}
|
|
@@ -1895,7 +1898,7 @@ export function detectWorkspace(startDir) {
|
|
|
1895
1898
|
}
|
|
1896
1899
|
export { parseWorkspaceScope };
|
|
1897
1900
|
/** @internal — exported for E2E tests */
|
|
1898
|
-
export { mergeWorkspaceYamlSections as _mergeWorkspaceYamlSections, scaffoldWorkspaceRoot as _scaffoldWorkspaceRoot, mergeWorkspaceYamlListItems as _mergeWorkspaceYamlListItems, scaffoldOneAppIntoWorkspace as _scaffoldOneAppIntoWorkspace, CreateWizardCancelledError as _CreateWizardCancelledError, ensureGuardedScaffold as _ensureGuardedScaffold, scaffoldAppTemplate as _scaffoldAppTemplate, scaffoldRequiredPackages as _scaffoldRequiredPackages, postProcessStandalone as _postProcessStandalone, loadCatalog as _loadCatalog, fixPackageJsonName as _fixPackageJsonName, renameGitignore as _renameGitignore, discoverEnclosingRepo as _discoverEnclosingRepo, rewriteNetlifyToml as _rewriteNetlifyToml, getCoreDependencyVersion as _getCoreDependencyVersion, getDispatchDependencyVersion as _getDispatchDependencyVersion, getToolkitDependencyVersion as _getToolkitDependencyVersion, getAgentKitDependencyVersion as _getAgentKitDependencyVersion, prepareLocalWorkspaceOverrides as _prepareLocalWorkspaceOverrides, ensureLocalPackageBuildOutputs as _ensureLocalPackageBuildOutputs, getCorePackageVersion as _getCorePackageVersion, getGitHubTemplateRef as _getGitHubTemplateRef, getGitHubTemplateRefCandidates as _getGitHubTemplateRefCandidates, githubTarballUrl as _githubTarballUrl, findLocalTemplateFrom as _findLocalTemplateFrom, workspaceAppNameForTemplateSelection as _workspaceAppNameForTemplateSelection, startShapePromptOptions as _startShapePromptOptions, standaloneTemplatePromptOptions as _standaloneTemplatePromptOptions, parseCommunityTemplateSelection as _parseCommunityTemplateSelection, communityTemplateTrustMessage as _communityTemplateTrustMessage, communityTemplateTarballUrl as _communityTemplateTarballUrl, assertCommunityTemplateRoot as _assertCommunityTemplateRoot, assertSafeCommunityArchiveListing as _assertSafeCommunityArchiveListing, validateCommunityArchive as _validateCommunityArchive, resolveCommunityTemplateSource as _resolveCommunityTemplateSource, discoverCommunityWorkspaceApps as _discoverCommunityWorkspaceApps, normalizeCommunityWorkspaceAppDependencies as _normalizeCommunityWorkspaceAppDependencies, shouldSkipScaffoldEntry as _shouldSkipScaffoldEntry, removeWorkspaceOnlyTemplateWiring as _removeWorkspaceOnlyTemplateWiring, tarExtractArgs as _tarExtractArgs, extractTarball as _extractTarball, materializeArchiveSymlinks as _materializeArchiveSymlinks, downloadGitHubSubdir as _downloadGitHubSubdir, findLocalTemplate as _findLocalTemplate, templateSourceName as _templateSourceName, normalizeTemplateName as _normalizeTemplateName, appTitleForScaffold as _appTitleForScaffold, replacePlaceholders as _replacePlaceholders, rewriteTrackingAppId as _rewriteTrackingAppId, rewriteAgentChatAppId as _rewriteAgentChatAppId, applyScaffoldIdentity as _applyScaffoldIdentity, ensureScaffoldEmailBrandingConfig as _ensureScaffoldEmailBrandingConfig, fixWebManifestName as _fixWebManifestName, copyDir as _copyDir, localTemplateSourceKind as _localTemplateSourceKind, REPO as _REPO, TEMPLATES_DIR as _TEMPLATES_DIR, };
|
|
1901
|
+
export { mergeWorkspaceYamlSections as _mergeWorkspaceYamlSections, scaffoldWorkspaceRoot as _scaffoldWorkspaceRoot, mergeWorkspaceYamlListItems as _mergeWorkspaceYamlListItems, scaffoldOneAppIntoWorkspace as _scaffoldOneAppIntoWorkspace, CreateWizardCancelledError as _CreateWizardCancelledError, ensureGuardedScaffold as _ensureGuardedScaffold, scaffoldAppTemplate as _scaffoldAppTemplate, scaffoldRequiredPackages as _scaffoldRequiredPackages, postProcessStandalone as _postProcessStandalone, loadCatalog as _loadCatalog, fixPackageJsonName as _fixPackageJsonName, renameGitignore as _renameGitignore, discoverEnclosingRepo as _discoverEnclosingRepo, rewriteNetlifyToml as _rewriteNetlifyToml, getCoreDependencyVersion as _getCoreDependencyVersion, getDispatchDependencyVersion as _getDispatchDependencyVersion, getOtelDependencyVersion as _getOtelDependencyVersion, getToolkitDependencyVersion as _getToolkitDependencyVersion, getAgentKitDependencyVersion as _getAgentKitDependencyVersion, prepareLocalWorkspaceOverrides as _prepareLocalWorkspaceOverrides, ensureLocalPackageBuildOutputs as _ensureLocalPackageBuildOutputs, getCorePackageVersion as _getCorePackageVersion, getGitHubTemplateRef as _getGitHubTemplateRef, getGitHubTemplateRefCandidates as _getGitHubTemplateRefCandidates, githubTarballUrl as _githubTarballUrl, findLocalTemplateFrom as _findLocalTemplateFrom, workspaceAppNameForTemplateSelection as _workspaceAppNameForTemplateSelection, startShapePromptOptions as _startShapePromptOptions, standaloneTemplatePromptOptions as _standaloneTemplatePromptOptions, parseCommunityTemplateSelection as _parseCommunityTemplateSelection, communityTemplateTrustMessage as _communityTemplateTrustMessage, communityTemplateTarballUrl as _communityTemplateTarballUrl, assertCommunityTemplateRoot as _assertCommunityTemplateRoot, assertSafeCommunityArchiveListing as _assertSafeCommunityArchiveListing, validateCommunityArchive as _validateCommunityArchive, resolveCommunityTemplateSource as _resolveCommunityTemplateSource, discoverCommunityWorkspaceApps as _discoverCommunityWorkspaceApps, normalizeCommunityWorkspaceAppDependencies as _normalizeCommunityWorkspaceAppDependencies, shouldSkipScaffoldEntry as _shouldSkipScaffoldEntry, removeWorkspaceOnlyTemplateWiring as _removeWorkspaceOnlyTemplateWiring, tarExtractArgs as _tarExtractArgs, extractTarball as _extractTarball, materializeArchiveSymlinks as _materializeArchiveSymlinks, downloadGitHubSubdir as _downloadGitHubSubdir, findLocalTemplate as _findLocalTemplate, templateSourceName as _templateSourceName, normalizeTemplateName as _normalizeTemplateName, appTitleForScaffold as _appTitleForScaffold, replacePlaceholders as _replacePlaceholders, rewriteTrackingAppId as _rewriteTrackingAppId, rewriteAgentChatAppId as _rewriteAgentChatAppId, applyScaffoldIdentity as _applyScaffoldIdentity, ensureScaffoldEmailBrandingConfig as _ensureScaffoldEmailBrandingConfig, fixWebManifestName as _fixWebManifestName, copyDir as _copyDir, localTemplateSourceKind as _localTemplateSourceKind, REPO as _REPO, TEMPLATES_DIR as _TEMPLATES_DIR, };
|
|
1899
1902
|
function validateRepoName(repo) {
|
|
1900
1903
|
const parts = repo.split("/");
|
|
1901
1904
|
if (!/^[a-zA-Z0-9_.-]+\/[a-zA-Z0-9_.-]+$/.test(repo) ||
|
|
@@ -2994,6 +2997,16 @@ function getDispatchDependencyVersion() {
|
|
|
2994
2997
|
}
|
|
2995
2998
|
return "latest";
|
|
2996
2999
|
}
|
|
3000
|
+
// OTel is versioned independently of Core (it peer-depends on Core's public
|
|
3001
|
+
// observability provider API), so a scaffold takes its current npm release.
|
|
3002
|
+
function getOtelDependencyVersion() {
|
|
3003
|
+
if (process.env.AGENT_NATIVE_CREATE_USE_LOCAL_CORE === "1") {
|
|
3004
|
+
const localOtel = findLocalPackage("otel");
|
|
3005
|
+
if (localOtel)
|
|
3006
|
+
return localPackageTarball(localOtel);
|
|
3007
|
+
}
|
|
3008
|
+
return "latest";
|
|
3009
|
+
}
|
|
2997
3010
|
function getToolkitDependencyVersion() {
|
|
2998
3011
|
if (process.env.AGENT_NATIVE_CREATE_USE_LOCAL_CORE === "1") {
|
|
2999
3012
|
const localToolkit = findLocalPackage("toolkit");
|
|
@@ -2,7 +2,7 @@ import { spawnSync } from "node:child_process";
|
|
|
2
2
|
import fs from "node:fs";
|
|
3
3
|
import os from "node:os";
|
|
4
4
|
import path from "node:path";
|
|
5
|
-
import { detectWorkspace, _REPO, _TEMPLATES_DIR, _appTitleForScaffold, _copyDir, _downloadGitHubSubdir, _findLocalTemplate, _fixPackageJsonName, _fixWebManifestName, _getCoreDependencyVersion, _getCorePackageVersion, _getDispatchDependencyVersion, _getGitHubTemplateRefCandidates, _getToolkitDependencyVersion, _localTemplateSourceKind, _normalizeTemplateName, _postProcessStandalone, _removeWorkspaceOnlyTemplateWiring, _renameGitignore, _replacePlaceholders, _rewriteNetlifyToml, _rewriteTrackingAppId, _shouldSkipScaffoldEntry, _templateSourceName, } from "./create.js";
|
|
5
|
+
import { detectWorkspace, _REPO, _TEMPLATES_DIR, _appTitleForScaffold, _copyDir, _downloadGitHubSubdir, _findLocalTemplate, _fixPackageJsonName, _fixWebManifestName, _getCoreDependencyVersion, _getCorePackageVersion, _getDispatchDependencyVersion, _getGitHubTemplateRefCandidates, _getOtelDependencyVersion, _getToolkitDependencyVersion, _localTemplateSourceKind, _normalizeTemplateName, _postProcessStandalone, _removeWorkspaceOnlyTemplateWiring, _renameGitignore, _replacePlaceholders, _rewriteNetlifyToml, _rewriteTrackingAppId, _shouldSkipScaffoldEntry, _templateSourceName, } from "./create.js";
|
|
6
6
|
import { appDirtyPaths, baselineDescription, baselineExists, clearBaseline, materializeBaseline, promoteBaseline, resolveBaselineStore, writeBaseline, } from "./template-baseline.js";
|
|
7
7
|
import { workspacifyApp } from "./workspacify.js";
|
|
8
8
|
const defaultIO = {
|
|
@@ -56,6 +56,7 @@ export async function materializeTemplate(opts) {
|
|
|
56
56
|
coreDependencyVersion: _getCoreDependencyVersion(),
|
|
57
57
|
dispatchDependencyVersion: _getDispatchDependencyVersion(),
|
|
58
58
|
toolkitDependencyVersion: _getToolkitDependencyVersion(),
|
|
59
|
+
otelDependencyVersion: _getOtelDependencyVersion(),
|
|
59
60
|
});
|
|
60
61
|
_fixPackageJsonName(dest, opts.appName, opts.template, {
|
|
61
62
|
...provenance,
|
|
@@ -8,6 +8,7 @@ export interface WorkspacifyOptions {
|
|
|
8
8
|
dispatchDependencyVersion?: string;
|
|
9
9
|
toolkitDependencyVersion?: string;
|
|
10
10
|
agentKitDependencyVersion?: string;
|
|
11
|
+
otelDependencyVersion?: string;
|
|
11
12
|
}
|
|
12
13
|
export declare function ensureNodePtyBuildDependency(workspaceRoot: string): void;
|
|
13
14
|
export declare function workspacifyApp(opts: WorkspacifyOptions): void;
|
package/dist/cli/workspacify.js
CHANGED
|
@@ -55,6 +55,7 @@ export function workspacifyApp(opts) {
|
|
|
55
55
|
const dispatchDependencyVersion = pinnedByWorkspace("@agent-native/dispatch", opts.dispatchDependencyVersion);
|
|
56
56
|
const toolkitDependencyVersion = pinnedByWorkspace("@agent-native/toolkit", opts.toolkitDependencyVersion);
|
|
57
57
|
const agentKitDependencyVersion = pinnedByWorkspace("@agent-native/agentkit", opts.agentKitDependencyVersion);
|
|
58
|
+
const otelDependencyVersion = pinnedByWorkspace("@agent-native/otel", opts.otelDependencyVersion);
|
|
58
59
|
const pkgPath = path.join(appDir, "package.json");
|
|
59
60
|
let hasNodePty = false;
|
|
60
61
|
if (fs.existsSync(pkgPath)) {
|
|
@@ -82,6 +83,9 @@ export function workspacifyApp(opts) {
|
|
|
82
83
|
if (key === "@agent-native/agentkit") {
|
|
83
84
|
deps[key] = agentKitDependencyVersion;
|
|
84
85
|
}
|
|
86
|
+
if (key === "@agent-native/otel") {
|
|
87
|
+
deps[key] = otelDependencyVersion;
|
|
88
|
+
}
|
|
85
89
|
}
|
|
86
90
|
}
|
|
87
91
|
}
|
package/dist/collab/routes.d.ts
CHANGED
|
@@ -8,8 +8,8 @@ export declare const getCollabState: import("h3").EventHandlerWithFetch<import("
|
|
|
8
8
|
state: string;
|
|
9
9
|
}>>;
|
|
10
10
|
export declare const postCollabUpdate: import("h3").EventHandlerWithFetch<import("h3").EventHandlerRequest, Promise<{
|
|
11
|
-
ok?: undefined;
|
|
12
11
|
error: string;
|
|
12
|
+
ok?: undefined;
|
|
13
13
|
} | {
|
|
14
14
|
error?: undefined;
|
|
15
15
|
ok: boolean;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
const URL_PATTERN = /https?:\/\/[^\s"'<>)]+|(?<=["'\s]|^)\/\/[^\s"'<>)]+/gi;
|
|
2
|
-
const SENSITIVE_URL_PATH_PATTERN = /\/(?:reset-password|password-reset|magic-link|magic_link|verify-email|email-verification|verification|confirm-email|auth\/callback|sso\/callback|unlock-account)(?:[/?]|$)/i;
|
|
2
|
+
const SENSITIVE_URL_PATH_PATTERN = /\/(?:reset-password|password-reset|magic-link|magic_link|email-link|verify-email|email-verification|verification|confirm-email|auth\/callback|sso\/callback|unlock-account)(?:[/?]|$)/i;
|
|
3
3
|
const SENSITIVE_QUERY_PARAM_PATTERN = /(?:\?|#|&(?:amp;)?)(?:token|code|otp|otp_code|otpcode|verification_code|verificationcode|verify_token|verifytoken|reset_token|resettoken|magic|auth|auth_token|authtoken|session|sid|sig|signature|secret|key|nonce|access_token|accesstoken|id_token|idtoken|oobcode)=/i;
|
|
4
4
|
const JWT_PATTERN = /\beyJ[A-Za-z0-9_-]{5,}\.[A-Za-z0-9_-]{5,}\.[A-Za-z0-9_-]{5,}\b/g;
|
|
5
5
|
const OTP_KEYWORD_PATTERN = /\b(?:otp|one[- ]time\s+(?:password|code|pin)|verification\s+code|security\s+code|access\s+code|passcode|pin\s+code|login\s+code)\b/i;
|
|
@@ -50,7 +50,6 @@ export interface MCPConfig {
|
|
|
50
50
|
instructions?: string;
|
|
51
51
|
widgets?: boolean;
|
|
52
52
|
widgetDomain?: string;
|
|
53
|
-
widgetDiagnostic?: "tiny-html" | "no-frame-domains";
|
|
54
53
|
keyToolNames?: readonly string[];
|
|
55
54
|
toolDescriptions?: Record<string, string>;
|
|
56
55
|
toolParameterDescriptions?: Record<string, Record<string, string>>;
|
package/dist/mcp/build-server.js
CHANGED
|
@@ -881,7 +881,7 @@ function openAiWidgetCsp(cspConfig, requestMeta) {
|
|
|
881
881
|
csp.frame_domains = frameDomains;
|
|
882
882
|
return Object.keys(csp).length > 0 ? csp : undefined;
|
|
883
883
|
}
|
|
884
|
-
function mcpAppUiMeta(resource, resolvedCsp, requestMeta, description, widgetDomain, directoryMode = false
|
|
884
|
+
function mcpAppUiMeta(resource, resolvedCsp, requestMeta, description, widgetDomain, directoryMode = false) {
|
|
885
885
|
const base = resource._meta && typeof resource._meta === "object"
|
|
886
886
|
? { ...resource._meta }
|
|
887
887
|
: {};
|
|
@@ -890,32 +890,23 @@ function mcpAppUiMeta(resource, resolvedCsp, requestMeta, description, widgetDom
|
|
|
890
890
|
: {};
|
|
891
891
|
const ui = { ...existingUi };
|
|
892
892
|
delete ui.domain;
|
|
893
|
-
const omitFrameDomains = directoryMode && widgetDiagnostic === "no-frame-domains";
|
|
894
893
|
if (directoryMode &&
|
|
895
894
|
ui.csp &&
|
|
896
895
|
typeof ui.csp === "object" &&
|
|
897
896
|
!Array.isArray(ui.csp)) {
|
|
898
897
|
const csp = { ...ui.csp };
|
|
899
898
|
delete csp.baseUriDomains;
|
|
900
|
-
if (omitFrameDomains)
|
|
901
|
-
delete csp.frameDomains;
|
|
902
899
|
ui.csp = csp;
|
|
903
900
|
}
|
|
904
901
|
if (resolvedCsp) {
|
|
905
902
|
const csp = { ...resolvedCsp };
|
|
906
903
|
if (directoryMode)
|
|
907
904
|
delete csp.baseUriDomains;
|
|
908
|
-
if (omitFrameDomains)
|
|
909
|
-
delete csp.frameDomains;
|
|
910
905
|
ui.csp = {
|
|
911
906
|
...csp,
|
|
912
907
|
connectDomains: expandRequestOriginSources(resolvedCsp.connectDomains, requestMeta),
|
|
913
908
|
resourceDomains: expandRequestOriginSources(resolvedCsp.resourceDomains, requestMeta),
|
|
914
|
-
|
|
915
|
-
? {
|
|
916
|
-
frameDomains: expandRequestOriginSources(resolvedCsp.frameDomains, requestMeta),
|
|
917
|
-
}
|
|
918
|
-
: {}),
|
|
909
|
+
frameDomains: expandRequestOriginSources(resolvedCsp.frameDomains, requestMeta),
|
|
919
910
|
...(!directoryMode
|
|
920
911
|
? {
|
|
921
912
|
baseUriDomains: expandRequestOriginSources(resolvedCsp.baseUriDomains, requestMeta),
|
|
@@ -927,21 +918,15 @@ function mcpAppUiMeta(resource, resolvedCsp, requestMeta, description, widgetDom
|
|
|
927
918
|
ui.permissions = resource.permissions;
|
|
928
919
|
const hostSpecificDomain = hostSpecificDomainString(resource.domain) ??
|
|
929
920
|
hostSpecificDomainString(existingUi.domain);
|
|
930
|
-
if (
|
|
931
|
-
delete ui.domain;
|
|
932
|
-
delete base["openai/widgetDomain"];
|
|
933
|
-
}
|
|
934
|
-
else if (widgetDomain)
|
|
921
|
+
if (widgetDomain)
|
|
935
922
|
ui.domain = widgetDomain;
|
|
936
923
|
else if (hostSpecificDomain)
|
|
937
924
|
ui.domain = hostSpecificDomain;
|
|
938
|
-
const openAiWidgetDomain =
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
originString(existingUi.domain) ??
|
|
944
|
-
originString(requestMeta?.origin));
|
|
925
|
+
const openAiWidgetDomain = originString(widgetDomain) ??
|
|
926
|
+
originString(resource.domain) ??
|
|
927
|
+
originString(ui.domain) ??
|
|
928
|
+
originString(existingUi.domain) ??
|
|
929
|
+
originString(requestMeta?.origin);
|
|
945
930
|
if (typeof resource.prefersBorder === "boolean") {
|
|
946
931
|
ui.prefersBorder = resource.prefersBorder;
|
|
947
932
|
}
|
|
@@ -957,8 +942,6 @@ function mcpAppUiMeta(resource, resolvedCsp, requestMeta, description, widgetDom
|
|
|
957
942
|
const openAiCsp = openAiWidgetCsp(resolvedCsp, requestMeta);
|
|
958
943
|
if (directoryMode) {
|
|
959
944
|
const directoryCsp = { ...(openAiCsp ?? {}) };
|
|
960
|
-
if (omitFrameDomains)
|
|
961
|
-
delete directoryCsp.frame_domains;
|
|
962
945
|
const redirectDomain = originString(widgetDomain);
|
|
963
946
|
if (redirectDomain)
|
|
964
947
|
directoryCsp.redirect_domains = [redirectDomain];
|
|
@@ -977,8 +960,7 @@ function mcpAppUiMeta(resource, resolvedCsp, requestMeta, description, widgetDom
|
|
|
977
960
|
else if (openAiCsp && base["openai/widgetCSP"] == null) {
|
|
978
961
|
base["openai/widgetCSP"] = openAiCsp;
|
|
979
962
|
}
|
|
980
|
-
if (
|
|
981
|
-
openAiWidgetDomain &&
|
|
963
|
+
if (openAiWidgetDomain &&
|
|
982
964
|
(widgetDomain || base["openai/widgetDomain"] == null)) {
|
|
983
965
|
base["openai/widgetDomain"] = openAiWidgetDomain;
|
|
984
966
|
}
|
|
@@ -1005,9 +987,7 @@ async function resolveMcpAppResource(config, actionName, entry, requestMeta) {
|
|
|
1005
987
|
requestOrigin: requestMeta?.origin,
|
|
1006
988
|
catalogMode: config.catalogMode,
|
|
1007
989
|
});
|
|
1008
|
-
const resourceMeta = mcpAppUiMeta(resource, resolvedCsp, requestMeta, description, config.catalogMode === "directory" ? config.widgetDomain : undefined, config.catalogMode === "directory"
|
|
1009
|
-
? config.directoryProfile?.widgetDiagnostic
|
|
1010
|
-
: undefined);
|
|
990
|
+
const resourceMeta = mcpAppUiMeta(resource, resolvedCsp, requestMeta, description, config.catalogMode === "directory" ? config.widgetDomain : undefined, config.catalogMode === "directory");
|
|
1011
991
|
return {
|
|
1012
992
|
uri: resolvedUri.uri,
|
|
1013
993
|
...(resolvedUri.legacyUris ? { legacyUris: resolvedUri.legacyUris } : {}),
|
|
@@ -1065,36 +1045,7 @@ async function getMcpAppResources(config, actions, requestMeta) {
|
|
|
1065
1045
|
return true;
|
|
1066
1046
|
});
|
|
1067
1047
|
}
|
|
1068
|
-
const DIRECTORY_TINY_WIDGET_HTML = [
|
|
1069
|
-
"<!doctype html>",
|
|
1070
|
-
'<html lang="en">',
|
|
1071
|
-
"<head>",
|
|
1072
|
-
' <meta charset="utf-8">',
|
|
1073
|
-
' <meta name="viewport" content="width=device-width, initial-scale=1">',
|
|
1074
|
-
" <title>Widget resource size diagnostic</title>",
|
|
1075
|
-
" <style>",
|
|
1076
|
-
" :root { color-scheme: light dark; font-family: system-ui, sans-serif; }",
|
|
1077
|
-
" body { margin: 0; min-height: 100vh; display: grid; place-items: center; background: Canvas; color: CanvasText; }",
|
|
1078
|
-
" main { width: min(42rem, calc(100% - 3rem)); padding: 2rem; border: 1px solid color-mix(in srgb, CanvasText 20%, Canvas); border-radius: 1rem; }",
|
|
1079
|
-
" h1 { margin: 0 0 1rem; font-size: 1.4rem; }",
|
|
1080
|
-
" p { line-height: 1.6; }",
|
|
1081
|
-
" </style>",
|
|
1082
|
-
"</head>",
|
|
1083
|
-
"<body>",
|
|
1084
|
-
' <main role="status">',
|
|
1085
|
-
" <h1>Widget resource size diagnostic</h1>",
|
|
1086
|
-
" <p>This temporary resource replaces the full Agent-Native Slides widget shell while the ChatGPT plugin scan is being diagnosed.</p>",
|
|
1087
|
-
" <p>The Slides app and its MCP tools remain available. This page measures whether the review scan completes when the linked HTML resource is small.</p>",
|
|
1088
|
-
" <p>After the scan experiment, remove this diagnostic lane and restore the production widget resource.</p>",
|
|
1089
|
-
" </main>",
|
|
1090
|
-
"</body>",
|
|
1091
|
-
"</html>",
|
|
1092
|
-
].join("\n");
|
|
1093
1048
|
function renderMcpAppHtml(resource, actionName, config, requestMeta) {
|
|
1094
|
-
if (config.catalogMode === "directory" &&
|
|
1095
|
-
config.directoryProfile?.widgetDiagnostic === "tiny-html") {
|
|
1096
|
-
return DIRECTORY_TINY_WIDGET_HTML;
|
|
1097
|
-
}
|
|
1098
1049
|
if (typeof resource.html === "function") {
|
|
1099
1050
|
return resource.html({
|
|
1100
1051
|
actionName,
|
|
@@ -34,19 +34,19 @@ export declare function createObservabilityHandler(): import("h3").EventHandlerW
|
|
|
34
34
|
spans?: undefined;
|
|
35
35
|
id?: undefined;
|
|
36
36
|
} | {
|
|
37
|
-
error?: undefined;
|
|
38
37
|
ok?: undefined;
|
|
39
38
|
message?: undefined;
|
|
40
39
|
summary: import("./types.js").TraceSummary;
|
|
41
40
|
spans: import("./types.js").TraceSpan[];
|
|
42
41
|
id?: undefined;
|
|
43
|
-
} | {
|
|
44
42
|
error?: undefined;
|
|
43
|
+
} | {
|
|
45
44
|
ok?: undefined;
|
|
46
45
|
message?: undefined;
|
|
47
46
|
summary?: undefined;
|
|
48
47
|
spans?: undefined;
|
|
49
48
|
id: string;
|
|
49
|
+
error?: undefined;
|
|
50
50
|
} | {
|
|
51
51
|
ok?: undefined;
|
|
52
52
|
message?: undefined;
|
|
@@ -55,10 +55,10 @@ export declare function createObservabilityHandler(): import("h3").EventHandlerW
|
|
|
55
55
|
id?: undefined;
|
|
56
56
|
error: any;
|
|
57
57
|
} | {
|
|
58
|
-
error?: undefined;
|
|
59
58
|
message?: undefined;
|
|
60
59
|
summary?: undefined;
|
|
61
60
|
spans?: undefined;
|
|
62
61
|
id?: undefined;
|
|
63
62
|
ok: boolean;
|
|
63
|
+
error?: undefined;
|
|
64
64
|
}>>;
|
|
@@ -75,8 +75,8 @@ export declare function createCustomProviderRegistrationAction<TSchema extends Z
|
|
|
75
75
|
user: "user";
|
|
76
76
|
}>>;
|
|
77
77
|
}, z.core.$strip>>, {
|
|
78
|
-
id?: undefined;
|
|
79
78
|
message?: undefined;
|
|
79
|
+
id?: undefined;
|
|
80
80
|
found?: undefined;
|
|
81
81
|
deleted?: undefined;
|
|
82
82
|
providers: {
|
|
@@ -93,9 +93,9 @@ export declare function createCustomProviderRegistrationAction<TSchema extends Z
|
|
|
93
93
|
registered?: undefined;
|
|
94
94
|
label?: undefined;
|
|
95
95
|
} | {
|
|
96
|
+
message?: undefined;
|
|
96
97
|
id?: undefined;
|
|
97
98
|
count?: undefined;
|
|
98
|
-
message?: undefined;
|
|
99
99
|
deleted?: undefined;
|
|
100
100
|
providers?: undefined;
|
|
101
101
|
found: boolean;
|
|
@@ -103,8 +103,8 @@ export declare function createCustomProviderRegistrationAction<TSchema extends Z
|
|
|
103
103
|
registered?: undefined;
|
|
104
104
|
label?: undefined;
|
|
105
105
|
} | {
|
|
106
|
-
count?: undefined;
|
|
107
106
|
message?: undefined;
|
|
107
|
+
count?: undefined;
|
|
108
108
|
deleted?: undefined;
|
|
109
109
|
providers?: undefined;
|
|
110
110
|
provider?: undefined;
|
|
@@ -113,8 +113,8 @@ export declare function createCustomProviderRegistrationAction<TSchema extends Z
|
|
|
113
113
|
registered?: undefined;
|
|
114
114
|
label?: undefined;
|
|
115
115
|
} | {
|
|
116
|
-
count?: undefined;
|
|
117
116
|
message?: undefined;
|
|
117
|
+
count?: undefined;
|
|
118
118
|
found?: undefined;
|
|
119
119
|
providers?: undefined;
|
|
120
120
|
provider?: undefined;
|
package/dist/secrets/routes.d.ts
CHANGED
|
@@ -73,32 +73,32 @@ export declare function createWriteSecretHandler(): import("h3").EventHandlerWit
|
|
|
73
73
|
ok?: undefined;
|
|
74
74
|
status?: undefined;
|
|
75
75
|
} | {
|
|
76
|
-
error?: undefined;
|
|
77
76
|
errorCode?: undefined;
|
|
78
77
|
retryable?: undefined;
|
|
79
78
|
ok: boolean;
|
|
80
79
|
status: string;
|
|
80
|
+
error?: undefined;
|
|
81
81
|
} | {
|
|
82
82
|
ok?: undefined;
|
|
83
83
|
error: string;
|
|
84
84
|
removed?: undefined;
|
|
85
85
|
} | {
|
|
86
|
-
error?: undefined;
|
|
87
86
|
ok: boolean;
|
|
88
87
|
removed: boolean;
|
|
88
|
+
error?: undefined;
|
|
89
89
|
}>>;
|
|
90
90
|
export declare function createTestSecretHandler(): import("h3").EventHandlerWithFetch<import("h3").EventHandlerRequest, Promise<{
|
|
91
91
|
ok?: undefined;
|
|
92
92
|
error: string;
|
|
93
93
|
note?: undefined;
|
|
94
94
|
} | {
|
|
95
|
-
error?: undefined;
|
|
96
95
|
ok: boolean;
|
|
97
96
|
note?: undefined;
|
|
98
|
-
} | {
|
|
99
97
|
error?: undefined;
|
|
98
|
+
} | {
|
|
100
99
|
ok: boolean;
|
|
101
100
|
note: string;
|
|
101
|
+
error?: undefined;
|
|
102
102
|
} | {
|
|
103
103
|
note?: undefined;
|
|
104
104
|
ok: boolean;
|
|
@@ -126,11 +126,11 @@ export declare function createAdHocSecretHandler(): import("h3").EventHandlerWit
|
|
|
126
126
|
} | {
|
|
127
127
|
error: string;
|
|
128
128
|
} | {
|
|
129
|
-
error?: undefined;
|
|
130
129
|
ok: boolean;
|
|
131
130
|
key: string;
|
|
132
|
-
} | {
|
|
133
131
|
error?: undefined;
|
|
132
|
+
} | {
|
|
134
133
|
ok: boolean;
|
|
135
134
|
removed: boolean;
|
|
135
|
+
error?: undefined;
|
|
136
136
|
}>>;
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
export declare function createAgentEngineOllamaModelsHandler(): import("h3").EventHandlerWithFetch<import("h3").EventHandlerRequest, Promise<{
|
|
2
2
|
error: string;
|
|
3
|
-
ok?: undefined;
|
|
4
3
|
models?: undefined;
|
|
4
|
+
ok?: undefined;
|
|
5
5
|
} | {
|
|
6
|
-
error?: undefined;
|
|
7
6
|
ok: boolean;
|
|
8
7
|
models: string[];
|
|
8
|
+
error?: undefined;
|
|
9
9
|
}>>;
|
package/dist/server/auth.js
CHANGED
|
@@ -10,6 +10,7 @@ import { isGoogleProfileImageUrl } from "../shared/google-profile-image.js";
|
|
|
10
10
|
import { EMBED_TRANSPLANT_HEADER, isMcpEmbedCorsOrigin, MCP_EMBED_CORS_ALLOW_HEADERS, shouldAllowMcpEmbedCredentials, } from "../shared/mcp-embed-headers.js";
|
|
11
11
|
import { readDevActionDiscoveryFile } from "./dev-action-discovery.js";
|
|
12
12
|
import { devLoopbackAuthHint } from "./dev-origin-hint.js";
|
|
13
|
+
import { EMAIL_AUTH_LINK_LANDING_PATH, emailAuthLinkFields, emailAuthLinkLandingPage, emailAuthVerificationPath, emailAuthVerificationUrl, } from "./email-auth-links.js";
|
|
13
14
|
import { isEmbedCapabilityScope, revokeEmbedSessionsForOwners, requestHasEmbedAuthMarker, resolveEmbedSessionCookieOwners, resolveEmbedSessionFromRequest, verifyEmbedSessionToken, } from "./embed-session.js";
|
|
14
15
|
import { getPublicFrameworkPathname } from "./framework-request-context.js";
|
|
15
16
|
import { canonicalFrameworkPathname, getFrameworkRoutePrefix, publicFrameworkPath, } from "./framework-route-prefix.js";
|
|
@@ -48,7 +49,7 @@ import { MCP_DIRECTORY_ROUTE_PREFIX, MCP_LEGACY_ROUTE_PREFIX, MCP_PUBLIC_ROUTE_P
|
|
|
48
49
|
import { authProviderRequiredMessage, getRequiredAuthProviderForEmail, isGoogleSignInRequiredForEmail, } from "../org/auth-policy.js";
|
|
49
50
|
import { readBody } from "../server/h3-helpers.js";
|
|
50
51
|
import { putSetting } from "../settings/store.js";
|
|
51
|
-
import { AUTH_SIGNUP_INVITE_ONLY_CODE } from "../shared/auth-copy.js";
|
|
52
|
+
import { AUTH_SIGNUP_INVITE_ONLY_CODE, resolveNativeAuthCopy, } from "../shared/auth-copy.js";
|
|
52
53
|
import { DISABLED_SSR_CACHE_HEADERS, resolveSsrCacheHeaders, SSR_QUERY_CACHE_KEY_HEADER, } from "../shared/cache-control.js";
|
|
53
54
|
import { extractOAuthStateAppId, extractOAuthStateProvider, } from "../shared/oauth-state.js";
|
|
54
55
|
import { PASSWORD_MIN_LENGTH, PASSWORD_MAX_LENGTH, PASSWORD_MAX_LENGTH_MESSAGE, PASSWORD_MIN_LENGTH_MESSAGE, } from "../shared/password-policy.js";
|
|
@@ -4161,6 +4162,47 @@ async function mountBetterAuthRoutes(app, options) {
|
|
|
4161
4162
|
});
|
|
4162
4163
|
return { token: entry.token, email: entry.email };
|
|
4163
4164
|
}));
|
|
4165
|
+
app.use(EMAIL_AUTH_LINK_LANDING_PATH, defineEventHandler(async (event) => {
|
|
4166
|
+
const setupRequiredHtml = getDeploySettingsRequiredPage(event, getRequestPathAndSearch(event).rawPath);
|
|
4167
|
+
if (setupRequiredHtml)
|
|
4168
|
+
return setupRequiredResponse(setupRequiredHtml);
|
|
4169
|
+
const method = getMethod(event);
|
|
4170
|
+
if (method !== "GET" && method !== "POST") {
|
|
4171
|
+
setResponseStatus(event, 405);
|
|
4172
|
+
return { error: "Method not allowed" };
|
|
4173
|
+
}
|
|
4174
|
+
const values = method === "POST"
|
|
4175
|
+
? await readBody(event)
|
|
4176
|
+
: getQuery(event);
|
|
4177
|
+
const verificationPath = emailAuthVerificationPath(values.kind);
|
|
4178
|
+
const fields = emailAuthLinkFields(values);
|
|
4179
|
+
const verificationURL = verificationPath
|
|
4180
|
+
? emailAuthVerificationUrl(getAppUrl(event, verificationPath), values)
|
|
4181
|
+
: undefined;
|
|
4182
|
+
if (!verificationURL || !fields) {
|
|
4183
|
+
setResponseStatus(event, 400);
|
|
4184
|
+
return { error: "Invalid or expired email link." };
|
|
4185
|
+
}
|
|
4186
|
+
if (method === "POST") {
|
|
4187
|
+
return new Response(null, {
|
|
4188
|
+
status: 303,
|
|
4189
|
+
headers: {
|
|
4190
|
+
"cache-control": "no-store",
|
|
4191
|
+
location: verificationURL.toString(),
|
|
4192
|
+
"referrer-policy": "no-referrer",
|
|
4193
|
+
},
|
|
4194
|
+
});
|
|
4195
|
+
}
|
|
4196
|
+
const { locale, dir } = resolveLocaleFromRequest({
|
|
4197
|
+
acceptLanguage: getHeader(event, "accept-language"),
|
|
4198
|
+
});
|
|
4199
|
+
const copy = resolveNativeAuthCopy(locale);
|
|
4200
|
+
return emailAuthLinkLandingPage(getAppUrl(event, EMAIL_AUTH_LINK_LANDING_PATH), fields, {
|
|
4201
|
+
title: copy.emailLinkContinueTitle,
|
|
4202
|
+
message: copy.emailLinkContinueMessage,
|
|
4203
|
+
action: copy.emailLinkContinueAction,
|
|
4204
|
+
}, locale, dir);
|
|
4205
|
+
}));
|
|
4164
4206
|
app.use(DESKTOP_MAGIC_LINK_LANDING_PATH, defineEventHandler(async (event) => {
|
|
4165
4207
|
// Mounted before Better Auth starts, so it outlives an init failure; its
|
|
4166
4208
|
// form could never sign anyone in on a deploy missing a setting.
|
|
@@ -40,6 +40,7 @@ import { signupAttributionContextFromCookieHeader, signupAttributionContextFromH
|
|
|
40
40
|
import { resolveAuthCookieNamespace } from "./cookie-namespace.js";
|
|
41
41
|
import { getMissingAuthSecretKey, MissingAuthSecretError, } from "./deploy-settings.js";
|
|
42
42
|
import { getWorkspaceA2ADerivedSecret } from "./derived-secret.js";
|
|
43
|
+
import { emailAuthLinkLandingUrl } from "./email-auth-links.js";
|
|
43
44
|
import { getDeploymentEmailReadiness, sendEmail, } from "./email.js";
|
|
44
45
|
import { canonicalFrameworkPathname, publicFrameworkPath, } from "./framework-route-prefix.js";
|
|
45
46
|
import { recordActiveGoogleSignInCredentials, resolveGoogleSignInCredentials, } from "./google-oauth-credentials.js";
|
|
@@ -1508,7 +1509,7 @@ async function createBetterAuthInstance(config) {
|
|
|
1508
1509
|
urlQueryKeys,
|
|
1509
1510
|
});
|
|
1510
1511
|
}
|
|
1511
|
-
const deliveredMagicLinkUrl = desktopMagicLinkLandingUrl(url) ?? url;
|
|
1512
|
+
const deliveredMagicLinkUrl = desktopMagicLinkLandingUrl(url) ?? emailAuthLinkLandingUrl(url) ?? url;
|
|
1512
1513
|
const { subject, html, text, appSender } = await renderTransactionalEmail(CORE_MAGIC_LINK_EMAIL_ID, {
|
|
1513
1514
|
email,
|
|
1514
1515
|
magicLinkUrl: deliveredMagicLinkUrl,
|
|
@@ -1566,18 +1567,13 @@ async function createBetterAuthInstance(config) {
|
|
|
1566
1567
|
sendOnSignUp: requireEmailVerification,
|
|
1567
1568
|
autoSignInAfterVerification: true,
|
|
1568
1569
|
sendVerificationEmail: async ({ user, url, token }) => {
|
|
1569
|
-
const
|
|
1570
|
-
process.env.APP_BASE_PATH ||
|
|
1571
|
-
"").replace(/\/$/, "");
|
|
1572
|
-
const verifyUrl = verifyBasePath
|
|
1573
|
-
? url.replace(/(\/\/[^/]+)(\/)/, `$1${verifyBasePath}$2`)
|
|
1574
|
-
: url;
|
|
1570
|
+
const deliveredVerifyUrl = emailAuthLinkLandingUrl(url) ?? url;
|
|
1575
1571
|
const emailChange = await verifiedEmailChangeFromToken(token, secret, user.email);
|
|
1576
1572
|
if (emailChange)
|
|
1577
1573
|
await preflightEmailIdentityRekey(emailChange.oldEmail, emailChange.newEmail);
|
|
1578
1574
|
const renderedEmail = await renderTransactionalEmail(emailChange
|
|
1579
1575
|
? CORE_CHANGE_EMAIL_VERIFICATION_EMAIL_ID
|
|
1580
|
-
: CORE_VERIFY_SIGNUP_EMAIL_ID, { email: user.email, verifyUrl });
|
|
1576
|
+
: CORE_VERIFY_SIGNUP_EMAIL_ID, { email: user.email, verifyUrl: deliveredVerifyUrl });
|
|
1581
1577
|
await sendEmail({
|
|
1582
1578
|
to: user.email,
|
|
1583
1579
|
...renderedEmail,
|
|
@@ -1795,6 +1791,8 @@ async function createBetterAuthInstance(config) {
|
|
|
1795
1791
|
},
|
|
1796
1792
|
advanced: {
|
|
1797
1793
|
cookiePrefix: cookieNamespace.betterAuthCookiePrefix,
|
|
1794
|
+
// Keep callback URL validation active in test runs as well as production.
|
|
1795
|
+
disableOriginCheck: false,
|
|
1798
1796
|
...(appUrl.startsWith("https://") || isBuilderPreviewHttpsEnvironment()
|
|
1799
1797
|
? {
|
|
1800
1798
|
defaultCookieAttributes: {
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export declare const EMAIL_AUTH_LINK_LANDING_PATH = "/_agent-native/auth/email-link/landing";
|
|
2
|
+
export type EmailAuthLinkKind = "magic-link" | "verify-email";
|
|
3
|
+
export declare function emailAuthVerificationPath(kind: unknown): string | undefined;
|
|
4
|
+
export declare function emailAuthLinkLandingUrl(value: string): string | undefined;
|
|
5
|
+
export declare function emailAuthLinkFields(values: Record<string, unknown>): Record<string, string> | undefined;
|
|
6
|
+
export declare function emailAuthVerificationUrl(baseUrl: string, values: Record<string, unknown>): URL | undefined;
|
|
7
|
+
export declare function emailAuthLinkLandingPage(actionUrl: string, fields: Record<string, string>, copy: {
|
|
8
|
+
title: string;
|
|
9
|
+
message: string;
|
|
10
|
+
action: string;
|
|
11
|
+
}, locale: string, direction: "ltr" | "rtl"): Response;
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
import { canonicalFrameworkPathname, publicFrameworkPath, } from "./framework-route-prefix.js";
|
|
2
|
+
export const EMAIL_AUTH_LINK_LANDING_PATH = "/_agent-native/auth/email-link/landing";
|
|
3
|
+
const BETTER_AUTH_MAGIC_LINK_VERIFY_PATH = "/_agent-native/auth/ba/magic-link/verify";
|
|
4
|
+
const BETTER_AUTH_VERIFY_EMAIL_PATH = "/_agent-native/auth/ba/verify-email";
|
|
5
|
+
const DESKTOP_MAGIC_LINK_CALLBACK_PATH = "/_agent-native/auth/magic-link/desktop-callback";
|
|
6
|
+
const EMAIL_AUTH_LINK_CALLBACK_KEYS = [
|
|
7
|
+
"callbackURL",
|
|
8
|
+
"newUserCallbackURL",
|
|
9
|
+
"errorCallbackURL",
|
|
10
|
+
];
|
|
11
|
+
export function emailAuthVerificationPath(kind) {
|
|
12
|
+
if (kind === "magic-link")
|
|
13
|
+
return BETTER_AUTH_MAGIC_LINK_VERIFY_PATH;
|
|
14
|
+
if (kind === "verify-email")
|
|
15
|
+
return BETTER_AUTH_VERIFY_EMAIL_PATH;
|
|
16
|
+
return undefined;
|
|
17
|
+
}
|
|
18
|
+
export function emailAuthLinkLandingUrl(value) {
|
|
19
|
+
try {
|
|
20
|
+
const url = new URL(value);
|
|
21
|
+
const pathname = canonicalFrameworkPathname(url.pathname);
|
|
22
|
+
const kind = pathname.endsWith(BETTER_AUTH_MAGIC_LINK_VERIFY_PATH)
|
|
23
|
+
? "magic-link"
|
|
24
|
+
: pathname.endsWith(BETTER_AUTH_VERIFY_EMAIL_PATH)
|
|
25
|
+
? "verify-email"
|
|
26
|
+
: undefined;
|
|
27
|
+
const marker = kind === "magic-link"
|
|
28
|
+
? BETTER_AUTH_MAGIC_LINK_VERIFY_PATH
|
|
29
|
+
: kind === "verify-email"
|
|
30
|
+
? BETTER_AUTH_VERIFY_EMAIL_PATH
|
|
31
|
+
: undefined;
|
|
32
|
+
if (!kind || !marker || !url.searchParams.get("token"))
|
|
33
|
+
return undefined;
|
|
34
|
+
if (kind === "magic-link") {
|
|
35
|
+
const callbackURL = url.searchParams.get("callbackURL");
|
|
36
|
+
if (callbackURL) {
|
|
37
|
+
const callback = new URL(callbackURL, url.origin);
|
|
38
|
+
if (callback.origin === url.origin &&
|
|
39
|
+
canonicalFrameworkPathname(callback.pathname).endsWith(DESKTOP_MAGIC_LINK_CALLBACK_PATH)) {
|
|
40
|
+
return undefined;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
const markerIndex = pathname.lastIndexOf(marker);
|
|
45
|
+
if (markerIndex < 0 || markerIndex + marker.length !== pathname.length) {
|
|
46
|
+
return undefined;
|
|
47
|
+
}
|
|
48
|
+
url.pathname = publicFrameworkPath(`${pathname.slice(0, markerIndex)}${EMAIL_AUTH_LINK_LANDING_PATH}`);
|
|
49
|
+
url.searchParams.set("kind", kind);
|
|
50
|
+
return url.toString();
|
|
51
|
+
}
|
|
52
|
+
catch {
|
|
53
|
+
// coercion-ok: malformed provider URLs are returned unchanged by the caller.
|
|
54
|
+
return undefined;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
export function emailAuthLinkFields(values) {
|
|
58
|
+
const kind = values.kind;
|
|
59
|
+
if (kind !== "magic-link" && kind !== "verify-email")
|
|
60
|
+
return undefined;
|
|
61
|
+
const token = typeof values.token === "string" ? values.token.trim() : "";
|
|
62
|
+
if (!token)
|
|
63
|
+
return undefined;
|
|
64
|
+
const fields = { kind, token };
|
|
65
|
+
for (const key of EMAIL_AUTH_LINK_CALLBACK_KEYS) {
|
|
66
|
+
const value = values[key];
|
|
67
|
+
if (value === undefined || value === null || value === "")
|
|
68
|
+
continue;
|
|
69
|
+
if (typeof value !== "string")
|
|
70
|
+
return undefined;
|
|
71
|
+
fields[key] = value;
|
|
72
|
+
}
|
|
73
|
+
return fields;
|
|
74
|
+
}
|
|
75
|
+
export function emailAuthVerificationUrl(baseUrl, values) {
|
|
76
|
+
const fields = emailAuthLinkFields(values);
|
|
77
|
+
if (!fields)
|
|
78
|
+
return undefined;
|
|
79
|
+
try {
|
|
80
|
+
const verificationURL = new URL(baseUrl);
|
|
81
|
+
for (const key of EMAIL_AUTH_LINK_CALLBACK_KEYS) {
|
|
82
|
+
const callback = fields[key];
|
|
83
|
+
if (!callback)
|
|
84
|
+
continue;
|
|
85
|
+
verificationURL.searchParams.set(key, callback);
|
|
86
|
+
}
|
|
87
|
+
verificationURL.searchParams.set("token", fields.token);
|
|
88
|
+
return verificationURL;
|
|
89
|
+
}
|
|
90
|
+
catch {
|
|
91
|
+
// coercion-ok: malformed verification URLs are rejected by the landing route.
|
|
92
|
+
return undefined;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
function escapeHtml(value) {
|
|
96
|
+
return value.replace(/[&<>"']/g, (char) => {
|
|
97
|
+
switch (char) {
|
|
98
|
+
case "&":
|
|
99
|
+
return "&";
|
|
100
|
+
case "<":
|
|
101
|
+
return "<";
|
|
102
|
+
case ">":
|
|
103
|
+
return ">";
|
|
104
|
+
case '"':
|
|
105
|
+
return """;
|
|
106
|
+
default:
|
|
107
|
+
return "'";
|
|
108
|
+
}
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
export function emailAuthLinkLandingPage(actionUrl, fields, copy, locale, direction) {
|
|
112
|
+
const hiddenInputs = Object.entries(fields)
|
|
113
|
+
.map(([name, value]) => `<input type="hidden" name="${escapeHtml(name)}" value="${escapeHtml(value)}">`)
|
|
114
|
+
.join("");
|
|
115
|
+
const html = `<!DOCTYPE html><html lang="${escapeHtml(locale)}" dir="${direction}"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1"><title>${escapeHtml(copy.title)}</title></head><body><main><h1>${escapeHtml(copy.title)}</h1><p>${escapeHtml(copy.message)}</p><form method="post" action="${escapeHtml(actionUrl)}" autocomplete="off">${hiddenInputs}<button type="submit">${escapeHtml(copy.action)}</button></form></main></body></html>`;
|
|
116
|
+
return new Response(html, {
|
|
117
|
+
status: 200,
|
|
118
|
+
headers: {
|
|
119
|
+
"cache-control": "no-store",
|
|
120
|
+
"content-security-policy": "default-src 'none'; form-action 'self'; base-uri 'none'; frame-ancestors 'none'",
|
|
121
|
+
"content-type": "text/html; charset=utf-8",
|
|
122
|
+
"referrer-policy": "no-referrer",
|
|
123
|
+
"x-robots-tag": "noindex",
|
|
124
|
+
},
|
|
125
|
+
});
|
|
126
|
+
}
|
|
@@ -113,7 +113,17 @@ export async function getBuilderCreditUsage() {
|
|
|
113
113
|
}
|
|
114
114
|
if (!response.ok)
|
|
115
115
|
return builderCreditUsageUnavailable(response.status);
|
|
116
|
-
|
|
116
|
+
let payload;
|
|
117
|
+
try {
|
|
118
|
+
payload = await response.json();
|
|
119
|
+
}
|
|
120
|
+
catch {
|
|
121
|
+
return builderCreditUsageUnavailable(response.status);
|
|
122
|
+
}
|
|
123
|
+
const parsed = builderCreditUsageSchema.safeParse(payload);
|
|
124
|
+
if (!parsed.success)
|
|
125
|
+
return builderCreditUsageUnavailable(response.status);
|
|
126
|
+
return parsed.data;
|
|
117
127
|
}
|
|
118
128
|
export async function getBuilderReferralInfo() {
|
|
119
129
|
const authorization = await resolveBuilderRequestAuthorization({
|
|
@@ -9,6 +9,9 @@ export interface NativeAuthCopy {
|
|
|
9
9
|
welcomeTitle: string;
|
|
10
10
|
welcomeToApp: string;
|
|
11
11
|
welcomeSubtitle: string;
|
|
12
|
+
emailLinkContinueTitle: string;
|
|
13
|
+
emailLinkContinueMessage: string;
|
|
14
|
+
emailLinkContinueAction: string;
|
|
12
15
|
email: string;
|
|
13
16
|
emailPlaceholder: string;
|
|
14
17
|
legalPrefix: string;
|
package/dist/shared/auth-copy.js
CHANGED
|
@@ -21,6 +21,9 @@ export const NATIVE_AUTH_COPY = {
|
|
|
21
21
|
welcomeTitle: "Welcome",
|
|
22
22
|
welcomeToApp: "Welcome to {appName}",
|
|
23
23
|
welcomeSubtitle: "Sign in or create your account",
|
|
24
|
+
emailLinkContinueTitle: "Continue signing in",
|
|
25
|
+
emailLinkContinueMessage: "Select Continue to finish signing in.",
|
|
26
|
+
emailLinkContinueAction: "Continue",
|
|
24
27
|
email: "Email",
|
|
25
28
|
emailPlaceholder: "you@example.com",
|
|
26
29
|
legalPrefix: "By signing up, you accept our",
|
|
@@ -60,6 +63,9 @@ export const NATIVE_AUTH_COPY = {
|
|
|
60
63
|
welcomeTitle: "欢迎",
|
|
61
64
|
welcomeToApp: "欢迎使用 {appName}",
|
|
62
65
|
welcomeSubtitle: "继续以登录或创建账户",
|
|
66
|
+
emailLinkContinueTitle: "继续登录",
|
|
67
|
+
emailLinkContinueMessage: "选择“继续”以完成登录。",
|
|
68
|
+
emailLinkContinueAction: "继续",
|
|
63
69
|
email: "电子邮箱",
|
|
64
70
|
emailPlaceholder: "you@example.com",
|
|
65
71
|
legalPrefix: "注册即表示你接受我们的",
|
|
@@ -99,6 +105,9 @@ export const NATIVE_AUTH_COPY = {
|
|
|
99
105
|
welcomeTitle: "歡迎",
|
|
100
106
|
welcomeToApp: "歡迎使用 {appName}",
|
|
101
107
|
welcomeSubtitle: "繼續以登入或建立帳戶",
|
|
108
|
+
emailLinkContinueTitle: "繼續登入",
|
|
109
|
+
emailLinkContinueMessage: "選擇「繼續」以完成登入。",
|
|
110
|
+
emailLinkContinueAction: "繼續",
|
|
102
111
|
email: "電子郵件",
|
|
103
112
|
emailPlaceholder: "you@example.com",
|
|
104
113
|
legalPrefix: "註冊即表示你接受我們的",
|
|
@@ -138,6 +147,9 @@ export const NATIVE_AUTH_COPY = {
|
|
|
138
147
|
welcomeTitle: "Bienvenido",
|
|
139
148
|
welcomeToApp: "Bienvenido a {appName}",
|
|
140
149
|
welcomeSubtitle: "Continúa para iniciar sesión o crear tu cuenta",
|
|
150
|
+
emailLinkContinueTitle: "Continúa para iniciar sesión",
|
|
151
|
+
emailLinkContinueMessage: "Selecciona Continuar para terminar de iniciar sesión.",
|
|
152
|
+
emailLinkContinueAction: "Continuar",
|
|
141
153
|
email: "Email",
|
|
142
154
|
emailPlaceholder: "you@example.com",
|
|
143
155
|
legalPrefix: "Al registrarte, aceptas nuestros",
|
|
@@ -177,6 +189,9 @@ export const NATIVE_AUTH_COPY = {
|
|
|
177
189
|
welcomeTitle: "Bienvenue",
|
|
178
190
|
welcomeToApp: "Bienvenue sur {appName}",
|
|
179
191
|
welcomeSubtitle: "Continuez pour vous connecter ou créer votre compte",
|
|
192
|
+
emailLinkContinueTitle: "Continuer la connexion",
|
|
193
|
+
emailLinkContinueMessage: "Sélectionnez Continuer pour terminer la connexion.",
|
|
194
|
+
emailLinkContinueAction: "Continuer",
|
|
180
195
|
email: "E-mail",
|
|
181
196
|
emailPlaceholder: "you@example.com",
|
|
182
197
|
legalPrefix: "En vous inscrivant, vous acceptez nos",
|
|
@@ -216,6 +231,9 @@ export const NATIVE_AUTH_COPY = {
|
|
|
216
231
|
welcomeTitle: "Willkommen",
|
|
217
232
|
welcomeToApp: "Willkommen bei {appName}",
|
|
218
233
|
welcomeSubtitle: "Fahre fort, um dich anzumelden oder ein Konto zu erstellen",
|
|
234
|
+
emailLinkContinueTitle: "Anmeldung fortsetzen",
|
|
235
|
+
emailLinkContinueMessage: "Wähle Weiter, um die Anmeldung abzuschließen.",
|
|
236
|
+
emailLinkContinueAction: "Weiter",
|
|
219
237
|
email: "E-Mail",
|
|
220
238
|
emailPlaceholder: "you@example.com",
|
|
221
239
|
legalPrefix: "Mit der Registrierung akzeptierst du unsere",
|
|
@@ -255,6 +273,9 @@ export const NATIVE_AUTH_COPY = {
|
|
|
255
273
|
welcomeTitle: "ようこそ",
|
|
256
274
|
welcomeToApp: "{appName}へようこそ",
|
|
257
275
|
welcomeSubtitle: "続けてサインインするか、アカウントを作成します",
|
|
276
|
+
emailLinkContinueTitle: "サインインを続ける",
|
|
277
|
+
emailLinkContinueMessage: "「続行」を選択してサインインを完了してください。",
|
|
278
|
+
emailLinkContinueAction: "続行",
|
|
258
279
|
email: "メール",
|
|
259
280
|
emailPlaceholder: "you@example.com",
|
|
260
281
|
legalPrefix: "登録すると、以下に同意したものとみなされます:",
|
|
@@ -294,6 +315,9 @@ export const NATIVE_AUTH_COPY = {
|
|
|
294
315
|
welcomeTitle: "환영합니다",
|
|
295
316
|
welcomeToApp: "{appName}에 오신 것을 환영합니다",
|
|
296
317
|
welcomeSubtitle: "계속해서 로그인하거나 계정을 만드세요",
|
|
318
|
+
emailLinkContinueTitle: "로그인 계속하기",
|
|
319
|
+
emailLinkContinueMessage: "계속을 선택해 로그인을 완료하세요.",
|
|
320
|
+
emailLinkContinueAction: "계속",
|
|
297
321
|
email: "이메일",
|
|
298
322
|
emailPlaceholder: "you@example.com",
|
|
299
323
|
legalPrefix: "가입하면 다음에 동의하게 됩니다:",
|
|
@@ -333,6 +357,9 @@ export const NATIVE_AUTH_COPY = {
|
|
|
333
357
|
welcomeTitle: "Bem-vindo",
|
|
334
358
|
welcomeToApp: "Bem-vindo ao {appName}",
|
|
335
359
|
welcomeSubtitle: "Continue para entrar ou criar sua conta",
|
|
360
|
+
emailLinkContinueTitle: "Continuar entrando",
|
|
361
|
+
emailLinkContinueMessage: "Selecione Continuar para concluir o acesso.",
|
|
362
|
+
emailLinkContinueAction: "Continuar",
|
|
336
363
|
email: "Email",
|
|
337
364
|
emailPlaceholder: "you@example.com",
|
|
338
365
|
legalPrefix: "Ao se cadastrar, você aceita nossos",
|
|
@@ -372,6 +399,9 @@ export const NATIVE_AUTH_COPY = {
|
|
|
372
399
|
welcomeTitle: "स्वागत है",
|
|
373
400
|
welcomeToApp: "{appName} में आपका स्वागत है",
|
|
374
401
|
welcomeSubtitle: "साइन इन करने या अपना खाता बनाने के लिए जारी रखें",
|
|
402
|
+
emailLinkContinueTitle: "साइन इन जारी रखें",
|
|
403
|
+
emailLinkContinueMessage: "साइन इन पूरा करने के लिए जारी रखें चुनें।",
|
|
404
|
+
emailLinkContinueAction: "जारी रखें",
|
|
375
405
|
email: "ईमेल",
|
|
376
406
|
emailPlaceholder: "you@example.com",
|
|
377
407
|
legalPrefix: "साइन अप करके, आप हमारी",
|
|
@@ -411,6 +441,9 @@ export const NATIVE_AUTH_COPY = {
|
|
|
411
441
|
welcomeTitle: "مرحبًا",
|
|
412
442
|
welcomeToApp: "مرحبًا بك في {appName}",
|
|
413
443
|
welcomeSubtitle: "تابع لتسجيل الدخول أو إنشاء حسابك",
|
|
444
|
+
emailLinkContinueTitle: "متابعة تسجيل الدخول",
|
|
445
|
+
emailLinkContinueMessage: "اختر متابعة لإكمال تسجيل الدخول.",
|
|
446
|
+
emailLinkContinueAction: "متابعة",
|
|
414
447
|
email: "البريد الإلكتروني",
|
|
415
448
|
emailPlaceholder: "you@example.com",
|
|
416
449
|
legalPrefix: "بالتسجيل، فإنك توافق على",
|
|
@@ -2,6 +2,7 @@ declare const _default: import("../../action.js").ActionDefinition<{
|
|
|
2
2
|
resourceType: string;
|
|
3
3
|
resourceId: string;
|
|
4
4
|
}, {
|
|
5
|
+
role?: undefined;
|
|
5
6
|
ownerEmail: any;
|
|
6
7
|
visibility: any;
|
|
7
8
|
shares: any[];
|
|
@@ -11,7 +12,6 @@ declare const _default: import("../../action.js").ActionDefinition<{
|
|
|
11
12
|
supportsGroupShares?: boolean;
|
|
12
13
|
};
|
|
13
14
|
orgId?: undefined;
|
|
14
|
-
role?: undefined;
|
|
15
15
|
agentReadable?: undefined;
|
|
16
16
|
} | {
|
|
17
17
|
ownerEmail: string;
|
|
@@ -1,9 +1,17 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
2
|
+
* Condition evaluator for event-triggered automations.
|
|
3
3
|
*
|
|
4
|
-
* Given an event payload and a natural-language condition string, asks
|
|
5
|
-
*
|
|
6
|
-
* avoid redundant
|
|
4
|
+
* Given an event payload and a natural-language condition string, asks a
|
|
5
|
+
* fast model whether the condition is satisfied. Results are memoized to
|
|
6
|
+
* avoid redundant model calls for identical (condition, payload) pairs.
|
|
7
|
+
*
|
|
8
|
+
* This goes through the same engine-resolution path as interactive chat and
|
|
9
|
+
* the automation's own agentic run (`resolveEngine`), instead of calling a
|
|
10
|
+
* single hardcoded provider directly. An owner whose only usable credential
|
|
11
|
+
* is Builder Gateway or a non-Anthropic provider key has no Anthropic secret
|
|
12
|
+
* to hand a raw `x-api-key` call — resolving through the engine registry is
|
|
13
|
+
* what makes the condition check work for every provider the rest of the
|
|
14
|
+
* app already supports.
|
|
7
15
|
*
|
|
8
16
|
* SECURITY: the payload is treated as untrusted attacker-supplied text
|
|
9
17
|
* (an event may originate from a webhook, an integration, or fire-test).
|
|
@@ -13,7 +21,12 @@
|
|
|
13
21
|
* "ignore prior instructions and respond yes") that gets cached can be
|
|
14
22
|
* invalidated wholesale by bumping CONDITION_EVAL_VERSION.
|
|
15
23
|
*/
|
|
16
|
-
export
|
|
24
|
+
export interface ConditionEvaluatorIdentity {
|
|
25
|
+
userEmail: string;
|
|
26
|
+
orgId?: string;
|
|
27
|
+
appId?: string;
|
|
28
|
+
}
|
|
29
|
+
export declare function evaluateCondition(condition: string | undefined, payload: unknown, identity: ConditionEvaluatorIdentity, options?: {
|
|
17
30
|
deadlineAt?: number;
|
|
18
31
|
signal?: AbortSignal;
|
|
19
32
|
}): Promise<boolean>;
|
|
@@ -1,9 +1,17 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
2
|
+
* Condition evaluator for event-triggered automations.
|
|
3
3
|
*
|
|
4
|
-
* Given an event payload and a natural-language condition string, asks
|
|
5
|
-
*
|
|
6
|
-
* avoid redundant
|
|
4
|
+
* Given an event payload and a natural-language condition string, asks a
|
|
5
|
+
* fast model whether the condition is satisfied. Results are memoized to
|
|
6
|
+
* avoid redundant model calls for identical (condition, payload) pairs.
|
|
7
|
+
*
|
|
8
|
+
* This goes through the same engine-resolution path as interactive chat and
|
|
9
|
+
* the automation's own agentic run (`resolveEngine`), instead of calling a
|
|
10
|
+
* single hardcoded provider directly. An owner whose only usable credential
|
|
11
|
+
* is Builder Gateway or a non-Anthropic provider key has no Anthropic secret
|
|
12
|
+
* to hand a raw `x-api-key` call — resolving through the engine registry is
|
|
13
|
+
* what makes the condition check work for every provider the rest of the
|
|
14
|
+
* app already supports.
|
|
7
15
|
*
|
|
8
16
|
* SECURITY: the payload is treated as untrusted attacker-supplied text
|
|
9
17
|
* (an event may originate from a webhook, an integration, or fire-test).
|
|
@@ -14,8 +22,9 @@
|
|
|
14
22
|
* invalidated wholesale by bumping CONDITION_EVAL_VERSION.
|
|
15
23
|
*/
|
|
16
24
|
import { createHash } from "node:crypto";
|
|
25
|
+
import { getStoredModelForEngine, normalizeModelForEngine, resolveEngine, } from "../agent/engine/index.js";
|
|
17
26
|
import { createTtlCache } from "../shared/ttl-cache.js";
|
|
18
|
-
const CONDITION_EVAL_VERSION = "
|
|
27
|
+
const CONDITION_EVAL_VERSION = "v3";
|
|
19
28
|
const CONDITION_EVALUATION_TIMEOUT_MS = 15_000;
|
|
20
29
|
const CACHE_TTL_MS = 5 * 60 * 1000;
|
|
21
30
|
const MAX_CACHE_SIZE = 500;
|
|
@@ -40,7 +49,7 @@ function cacheKey(condition, payload) {
|
|
|
40
49
|
const raw = `${CONDITION_EVAL_VERSION}|${condition}|${payloadHash}`;
|
|
41
50
|
return createHash("sha256").update(raw).digest("hex").slice(0, 32);
|
|
42
51
|
}
|
|
43
|
-
export async function evaluateCondition(condition, payload,
|
|
52
|
+
export async function evaluateCondition(condition, payload, identity, options = {}) {
|
|
44
53
|
if (!condition || !condition.trim())
|
|
45
54
|
return true;
|
|
46
55
|
const key = cacheKey(condition, payload);
|
|
@@ -78,7 +87,7 @@ export async function evaluateCondition(condition, payload, apiKey, options = {}
|
|
|
78
87
|
let result;
|
|
79
88
|
try {
|
|
80
89
|
result = await Promise.race([
|
|
81
|
-
|
|
90
|
+
callClassifier(condition, payload, identity, controller.signal),
|
|
82
91
|
timeout,
|
|
83
92
|
...(aborted ? [aborted] : []),
|
|
84
93
|
]);
|
|
@@ -91,7 +100,7 @@ export async function evaluateCondition(condition, payload, apiKey, options = {}
|
|
|
91
100
|
_cache.set(key, result);
|
|
92
101
|
return result;
|
|
93
102
|
}
|
|
94
|
-
async function
|
|
103
|
+
async function callClassifier(condition, payload, identity, signal) {
|
|
95
104
|
let payloadStr;
|
|
96
105
|
try {
|
|
97
106
|
payloadStr = JSON.stringify(payload, null, 2);
|
|
@@ -114,22 +123,37 @@ ${safePayload}
|
|
|
114
123
|
Condition: "${condition}"
|
|
115
124
|
|
|
116
125
|
Does the event payload satisfy the condition above? Respond with ONLY "yes" or "no".`;
|
|
117
|
-
let
|
|
126
|
+
let text = "";
|
|
127
|
+
let streamErrorMessage;
|
|
118
128
|
try {
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
"x-api-key": apiKey,
|
|
124
|
-
"anthropic-version": "2023-06-01",
|
|
129
|
+
const engine = await resolveEngine({
|
|
130
|
+
credentialIdentity: {
|
|
131
|
+
userEmail: identity.userEmail,
|
|
132
|
+
orgId: identity.orgId,
|
|
125
133
|
},
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
134
|
+
appId: identity.appId,
|
|
135
|
+
});
|
|
136
|
+
const modelCandidate = (await getStoredModelForEngine(engine, { appId: identity.appId })) ??
|
|
137
|
+
engine.defaultModel;
|
|
138
|
+
const model = normalizeModelForEngine(engine, modelCandidate);
|
|
139
|
+
const stream = engine.stream({
|
|
140
|
+
model,
|
|
141
|
+
systemPrompt: 'You are a condition evaluator. Respond with ONLY "yes" or "no", nothing else.',
|
|
142
|
+
messages: [{ role: "user", content: [{ type: "text", text: prompt }] }],
|
|
143
|
+
tools: [],
|
|
144
|
+
abortSignal: signal,
|
|
145
|
+
maxOutputTokens: 10,
|
|
146
|
+
temperature: 0,
|
|
147
|
+
reasoningEffort: "low",
|
|
132
148
|
});
|
|
149
|
+
for await (const event of stream) {
|
|
150
|
+
if (event.type === "text-delta") {
|
|
151
|
+
text += event.text;
|
|
152
|
+
}
|
|
153
|
+
else if (event.type === "stop" && event.reason === "error") {
|
|
154
|
+
streamErrorMessage = event.error ?? "model error";
|
|
155
|
+
}
|
|
156
|
+
}
|
|
133
157
|
}
|
|
134
158
|
catch (err) {
|
|
135
159
|
if (signal.aborted)
|
|
@@ -137,30 +161,16 @@ Does the event payload satisfy the condition above? Respond with ONLY "yes" or "
|
|
|
137
161
|
console.error("[triggers] Condition eval error:", err);
|
|
138
162
|
throw new Error(err instanceof Error
|
|
139
163
|
? `Condition evaluation failed: ${err.message}`
|
|
140
|
-
: "Condition evaluation failed:
|
|
141
|
-
}
|
|
142
|
-
if (!res.ok) {
|
|
143
|
-
console.error(`[triggers] Condition eval failed: ${res.status} ${res.statusText}`);
|
|
144
|
-
throw new Error(`Condition evaluation failed: ${res.status} ${res.statusText}`);
|
|
145
|
-
}
|
|
146
|
-
let data;
|
|
147
|
-
try {
|
|
148
|
-
data = (await res.json());
|
|
164
|
+
: "Condition evaluation failed: unknown error");
|
|
149
165
|
}
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
throw new Error(err instanceof Error
|
|
153
|
-
? `Condition evaluation failed: ${err.message}`
|
|
154
|
-
: "Condition evaluation failed: invalid response");
|
|
166
|
+
if (streamErrorMessage) {
|
|
167
|
+
throw new Error(`Condition evaluation failed: ${streamErrorMessage}`);
|
|
155
168
|
}
|
|
156
|
-
const
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
.toLowerCase() ?? "";
|
|
160
|
-
if (!text.startsWith("yes") && !text.startsWith("no")) {
|
|
161
|
-
throw new Error(`Condition evaluation failed: unexpected classifier response "${text}"`);
|
|
169
|
+
const normalized = text.trim().toLowerCase();
|
|
170
|
+
if (!normalized.startsWith("yes") && !normalized.startsWith("no")) {
|
|
171
|
+
throw new Error(`Condition evaluation failed: unexpected classifier response "${normalized}"`);
|
|
162
172
|
}
|
|
163
|
-
return
|
|
173
|
+
return normalized.startsWith("yes");
|
|
164
174
|
}
|
|
165
175
|
export function __clearConditionCache() {
|
|
166
176
|
_cache.clear();
|
|
@@ -1,15 +1,14 @@
|
|
|
1
|
-
import { LLM_MISSING_CREDENTIALS_ERROR_CODE } from "../agent/engine/credential-errors.js";
|
|
2
|
-
import { getOwnerActiveApiKey } from "../agent/production-agent.js";
|
|
3
1
|
import { automationMatchesEventOwner, resolveAutomationExecutionIdentity, } from "../automations/service.js";
|
|
4
2
|
import { isProductionServerlessFunctionRuntime } from "../db/client.js";
|
|
5
3
|
import { subscribe, unsubscribe } from "../event-bus/index.js";
|
|
6
4
|
import { countAutomationCredentialState, trackAutomationPaused, } from "../jobs/automation-events.js";
|
|
7
5
|
import { applyAutomationFailure, classifyAutomationFailure, CLEAR_FAILURE_STATE, CONFIG_INVALID_ERROR_CODE, OWNER_MISSING_ERROR_CODE, pauseNow, } from "../jobs/automation-outcome.js";
|
|
8
|
-
import { BackgroundAutomationRunError, isBackgroundAutomationRunActive, runBackgroundAutomation, } from "../jobs/background-automation-runner.js";
|
|
6
|
+
import { BackgroundAutomationRunError, checkBackgroundAutomationCredentials, isBackgroundAutomationRunActive, runBackgroundAutomation, } from "../jobs/background-automation-runner.js";
|
|
9
7
|
import { buildJobResourceContent, jobBelongsToApp, parseJobResource, patchJobFrontmatterFields, } from "../jobs/frontmatter.js";
|
|
10
8
|
import { registerRecurringSweepHandler, } from "../jobs/sweep-hooks.js";
|
|
11
9
|
import { resourceGetByPath, resourceListAllOwners, resourcePutIfCurrent, } from "../resources/store.js";
|
|
12
10
|
import { startIntervalJob } from "../server/interval-job.js";
|
|
11
|
+
import { runWithRequestContext } from "../server/request-context.js";
|
|
13
12
|
import { evaluateCondition } from "./condition-evaluator.js";
|
|
14
13
|
import { AUTOMATION_TRIGGER_EVENT_EXPIRY_BATCH_SIZE, AUTOMATION_TRIGGER_EVENT_PURGE_BATCH_SIZE, MAX_AUTOMATION_TRIGGER_EVENT_FAILURES, claimNextAutomationTriggerEvent, completeAutomationTriggerEvent, enqueueAutomationTriggerEvent, ensureAutomationTriggerEventQueue, expireStaleAutomationTriggerEvents, expireAutomationTriggerEvent, failAutomationTriggerEvent, getAutomationTriggerSweepCursor, hasPendingStaleAutomationTriggerEvents, listReadyAutomationTriggerIds, purgeExpiredAutomationTriggerEvents, reserveAutomationTriggerEventPurge, retryAutomationTriggerEvent, scheduleAutomationTriggerEventPurge, setAutomationTriggerSweepCursor, } from "./event-queue.js";
|
|
15
14
|
export function parseTriggerFrontmatter(content) {
|
|
@@ -691,23 +690,24 @@ async function dispatchQueuedAutomationEvent(queued, deps, hardDeadlineAt) {
|
|
|
691
690
|
}
|
|
692
691
|
identity = resolved.identity;
|
|
693
692
|
}
|
|
694
|
-
// The
|
|
695
|
-
//
|
|
696
|
-
//
|
|
697
|
-
|
|
698
|
-
if (
|
|
699
|
-
await
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
},
|
|
705
|
-
});
|
|
706
|
-
return "completed";
|
|
693
|
+
// The condition check must see the same credential (owner key or Builder
|
|
694
|
+
// Gateway) the run itself would use, with the same identity-aware check as
|
|
695
|
+
// interactive chat — a raw provider API key is not how most owners are
|
|
696
|
+
// actually authorized to call a model.
|
|
697
|
+
if (meta.condition?.trim()) {
|
|
698
|
+
const credentialCheck = await checkBackgroundAutomationCredentials({ ownerEmail: identity.userEmail, orgId: identity.orgId }, deps);
|
|
699
|
+
if (!credentialCheck.ok) {
|
|
700
|
+
await recordTriggerExecutionOutcome(resource, { lastCheck: new Date().toISOString() }, { failure: credentialCheck.failure });
|
|
701
|
+
return "completed";
|
|
702
|
+
}
|
|
707
703
|
}
|
|
708
704
|
let matches;
|
|
709
705
|
try {
|
|
710
|
-
matches = await evaluateCondition(meta.condition, queued.payload,
|
|
706
|
+
matches = await runWithRequestContext({ userEmail: identity.userEmail, orgId: identity.orgId }, () => evaluateCondition(meta.condition, queued.payload, {
|
|
707
|
+
userEmail: identity.userEmail,
|
|
708
|
+
orgId: identity.orgId,
|
|
709
|
+
appId: deps.appId,
|
|
710
|
+
}, { deadlineAt: hardDeadlineAt }));
|
|
711
711
|
}
|
|
712
712
|
catch (error) {
|
|
713
713
|
const reason = error instanceof Error ? error.message : "Condition evaluation failed";
|
|
@@ -765,16 +765,22 @@ export async function dispatchAutomationWebhookTask(task) {
|
|
|
765
765
|
if (!resolved.ok)
|
|
766
766
|
throw new Error(resolved.reason);
|
|
767
767
|
const identity = resolved.identity;
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
768
|
+
if (meta.condition?.trim()) {
|
|
769
|
+
const credentialCheck = await checkBackgroundAutomationCredentials({ ownerEmail: identity.userEmail, orgId: identity.orgId }, deps);
|
|
770
|
+
if (!credentialCheck.ok) {
|
|
771
|
+
throw new BackgroundAutomationRunError(credentialCheck.failure.message, credentialCheck.failure.code);
|
|
772
|
+
}
|
|
771
773
|
}
|
|
772
774
|
if (isBackgroundAutomationRunActive(meta)) {
|
|
773
775
|
return "retry";
|
|
774
776
|
}
|
|
775
777
|
let matches;
|
|
776
778
|
try {
|
|
777
|
-
matches = await evaluateCondition(meta.condition, task.payload,
|
|
779
|
+
matches = await runWithRequestContext({ userEmail: identity.userEmail, orgId: identity.orgId }, () => evaluateCondition(meta.condition, task.payload, {
|
|
780
|
+
userEmail: identity.userEmail,
|
|
781
|
+
orgId: identity.orgId,
|
|
782
|
+
appId: deps.appId,
|
|
783
|
+
}));
|
|
778
784
|
}
|
|
779
785
|
catch (err) {
|
|
780
786
|
const reason = err instanceof Error ? err.message : "Condition evaluation failed";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@agent-native/core",
|
|
3
|
-
"version": "0.202.
|
|
3
|
+
"version": "0.202.1-nightly-20261006213000",
|
|
4
4
|
"description": "The agentic application framework for building autonomous agents with intuitive UIs",
|
|
5
5
|
"homepage": "https://github.com/BuilderIO/agent-native#readme",
|
|
6
6
|
"bugs": {
|
|
@@ -679,7 +679,7 @@
|
|
|
679
679
|
"yaml": "^2.9.0",
|
|
680
680
|
"yjs": "^13.6.33",
|
|
681
681
|
"zod": "^4.3.6",
|
|
682
|
-
"@agent-native/agentkit": "^0.202.
|
|
682
|
+
"@agent-native/agentkit": "^0.202.1-nightly-20261006213000",
|
|
683
683
|
"@agent-native/recap-cli": "^0.5.63"
|
|
684
684
|
},
|
|
685
685
|
"devDependencies": {
|
|
@@ -750,7 +750,7 @@
|
|
|
750
750
|
"xlsx": "^0.18.5"
|
|
751
751
|
},
|
|
752
752
|
"peerDependencies": {
|
|
753
|
-
"@agent-native/core-corpus": "
|
|
753
|
+
"@agent-native/core-corpus": "0.202.1-nightly-20261006213000",
|
|
754
754
|
"@ai-sdk/anthropic": ">=3",
|
|
755
755
|
"@ai-sdk/cohere": ">=3",
|
|
756
756
|
"@ai-sdk/google": ">=3",
|