@agent-native/core 0.136.5 → 0.137.0
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/corpus/README.md +1 -1
- package/corpus/templates/clips/app/components/import-menu.tsx +109 -0
- package/corpus/templates/clips/app/components/library/library-grid.tsx +8 -18
- package/corpus/templates/clips/app/components/library/library-layout.tsx +14 -50
- package/corpus/templates/clips/app/components/library/sort-menu.tsx +20 -6
- package/corpus/templates/clips/app/components/recorder/pre-record-panel.tsx +10 -34
- package/corpus/templates/clips/app/routes/_app.library._index.tsx +0 -2
- package/corpus/templates/clips/changelog/2026-08-04-cleaner-library-controls-with-an-icon-only-sort-button.md +6 -0
- package/corpus/templates/clips/changelog/2026-08-04-upload-and-loom-imports-now-live-under-one-import-menu.md +6 -0
- package/corpus/templates/content/actions/_database-utils.ts +6 -0
- package/corpus/templates/content/actions/bind-content-database-source-field.ts +273 -97
- package/corpus/templates/content/actions/change-content-database-source-role.ts +65 -29
- package/corpus/templates/content/actions/configure-document-property.ts +113 -32
- package/corpus/templates/content/actions/delete-content-database.ts +5 -7
- package/corpus/templates/content/actions/delete-document-property.ts +109 -62
- package/corpus/templates/content/actions/delete-document.ts +178 -36
- package/corpus/templates/content/actions/duplicate-database-item.ts +27 -0
- package/corpus/templates/content/actions/duplicate-database-items.ts +31 -1
- package/corpus/templates/content/actions/permanently-delete-document.ts +4 -6
- package/corpus/templates/content/actions/remove-database-items.ts +13 -0
- package/corpus/templates/content/actions/set-document-property.ts +69 -1
- package/corpus/templates/content/actions/upsert-database-item-by-key.ts +814 -0
- package/corpus/templates/content/parity/matrix.md +1 -1
- package/corpus/templates/content/parity/matrix.ts +1 -0
- package/corpus/templates/content/server/db/schema.ts +27 -0
- package/corpus/templates/content/server/plugins/db.ts +24 -0
- package/corpus/templates/design/app/components/design/BreakpointBar.tsx +122 -114
- package/corpus/templates/design/app/components/design/CanvasContextMenu.tsx +2 -2
- package/corpus/templates/design/app/components/design/EditPanel.tsx +68 -34
- package/corpus/templates/design/app/components/design/KeyboardShortcutsPanel.tsx +78 -4
- package/corpus/templates/design/app/components/design/MultiScreenCanvas.tsx +8 -0
- package/corpus/templates/design/app/components/design/QuestionFlow.tsx +5 -2
- package/corpus/templates/design/app/components/design/edit-panel/panel-primitives.tsx +10 -9
- package/corpus/templates/design/app/components/design/inspector/AutoLayoutMatrix.tsx +31 -69
- package/corpus/templates/design/app/components/design/inspector/design-icons.tsx +80 -106
- package/corpus/templates/design/app/components/design/multi-screen/types.ts +4 -0
- package/corpus/templates/design/app/hooks/use-editor-preferences.ts +75 -0
- package/corpus/templates/design/app/i18n-data.ts +8 -0
- package/corpus/templates/design/app/i18n-keyboard-shortcuts.ts +61 -0
- package/corpus/templates/design/app/pages/design-editor/editor-preferences.ts +98 -0
- package/corpus/templates/design/app/pages/design-editor/nudge-intent.ts +491 -0
- package/corpus/templates/design/app/pages/design-editor/paste-placement.ts +133 -0
- package/corpus/templates/design/app/pages/design-editor/png-export-render.ts +8 -0
- package/corpus/templates/design/app/pages/design-editor/selection-state.ts +5 -12
- package/corpus/templates/design/changelog/2026-08-03-arrow-keys-now-reorder-a-layer-inside-an-auto-layout-frame.md +6 -0
- package/corpus/templates/design/changelog/2026-08-03-auto-layout-flow-icons-show-the-direction-at-a-glance-instea.md +6 -0
- package/corpus/templates/design/changelog/2026-08-03-auto-layout-icons-share-one-outlined-square-style-so-flow-ga.md +6 -0
- package/corpus/templates/design/changelog/2026-08-03-export-has-a-named-preview-section-you-can-expand-replacing-.md +6 -0
- package/corpus/templates/design/changelog/2026-08-03-export-preview-shows-the-selected-element-instead-of-the-who.md +6 -0
- package/corpus/templates/design/changelog/2026-08-03-inspector-sections-show-an-expand-indicator-so-it-is-clear-w.md +6 -0
- package/corpus/templates/design/changelog/2026-08-03-paste-lands-inside-a-selected-frame-instead-of-beside-it.md +6 -0
- package/corpus/templates/design/changelog/2026-08-03-the-add-breakpoint-button-sits-outside-the-breakpoint-select.md +6 -0
- package/corpus/templates/design/changelog/2026-08-03-the-agent-s-follow-up-questions-keep-space-below-the-continu.md +6 -0
- package/corpus/templates/design/changelog/2026-08-03-the-agent-s-follow-up-questions-share-the-chat-panel-s-backg.md +6 -0
- package/corpus/templates/design/changelog/2026-08-03-the-export-panel-no-longer-stacks-a-duplicate-export-block-o.md +6 -0
- package/corpus/templates/design/changelog/2026-08-03-the-text-tool-uses-a-t-icon-matching-the-letter-it-inserts.md +6 -0
- package/corpus/templates/factory/.env.example +17 -0
- package/corpus/templates/factory/AGENTS.md +27 -17
- package/corpus/templates/factory/README.md +19 -9
- package/corpus/templates/factory/actions/get-slack-feedback-context.ts +90 -0
- package/corpus/templates/factory/actions/get-triage-config.ts +14 -3
- package/corpus/templates/factory/actions/govern-agent-native-pull-request.ts +386 -0
- package/corpus/templates/factory/actions/list-factory-automations.ts +53 -0
- package/corpus/templates/factory/actions/list-triage-items.ts +7 -2
- package/corpus/templates/factory/actions/poll-github-sources.ts +203 -0
- package/corpus/templates/factory/actions/poll-sentry-errors.ts +161 -0
- package/corpus/templates/factory/actions/poll-slack-channel.ts +4 -2
- package/corpus/templates/factory/actions/run-factory-automation.ts +42 -0
- package/corpus/templates/factory/actions/save-factory-automation.ts +69 -0
- package/corpus/templates/factory/actions/save-triage-config.ts +28 -2
- package/corpus/templates/factory/actions/start-builder-for-item.ts +411 -0
- package/corpus/templates/factory/app/components/factory/FactoryCanvas.tsx +14 -3
- package/corpus/templates/factory/app/components/ui/checkbox.tsx +1 -0
- package/corpus/templates/factory/app/hooks/use-navigation-state.ts +7 -0
- package/corpus/templates/factory/app/i18n/en-US.ts +35 -1
- package/corpus/templates/factory/app/routes/factory.tsx +462 -9
- package/corpus/templates/factory/changelog/2026-08-04-added-organization-owned-factory-automations-for-slack-bug-t.md +6 -0
- package/corpus/templates/factory/changelog/2026-08-04-automation-editor-controls-and-model-picker.md +6 -0
- package/corpus/templates/factory/netlify.toml +2 -2
- package/corpus/templates/factory/server/connectors/credentials.ts +6 -5
- package/corpus/templates/factory/server/connectors/slack.ts +133 -5
- package/corpus/templates/factory/server/db/schema.ts +6 -0
- package/corpus/templates/factory/server/lib/require-factory-automation.ts +65 -0
- package/corpus/templates/factory/server/plugins/agent-chat.ts +29 -11
- package/corpus/templates/factory/server/plugins/auth.ts +1 -0
- package/corpus/templates/factory/server/plugins/factory-migrations.ts +12 -0
- package/corpus/templates/factory/server/plugins/factory-scheduler-job.ts +218 -67
- package/corpus/templates/factory/server/triage/builder-executor.ts +4 -0
- package/corpus/templates/factory/server/triage/contracts.ts +14 -1
- package/corpus/templates/factory/server/triage/github-client.ts +404 -0
- package/corpus/templates/factory/server/triage/metadata.ts +44 -0
- package/corpus/templates/factory/server/triage/pr-babysit.ts +5 -5
- package/corpus/templates/factory/server/triage/pr-policy.ts +144 -0
- package/corpus/templates/factory/server/triage/sentry-client.ts +180 -0
- package/corpus/templates/factory/server/triage/slack-client.ts +43 -0
- package/corpus/templates/factory/server/triage/slack-poller.ts +9 -2
- package/corpus/templates/plan/.agents/skills/visual-plan/SKILL.md +27 -0
- package/corpus/templates/plan/.agents/skills/visual-plan/references/canvas.md +14 -4
- package/corpus/templates/plan/.agents/skills/visual-plan/references/wireframe.md +7 -0
- package/corpus/templates/plan/.agents/skills/visual-recap/references/wireframe.md +7 -0
- package/corpus/templates/plan/actions/create-plan-design.ts +8 -6
- package/corpus/templates/plan/actions/create-prototype-plan.ts +8 -6
- package/corpus/templates/plan/actions/create-ui-plan.ts +7 -7
- package/corpus/templates/plan/actions/get-plan-blocks.ts +7 -1
- package/corpus/templates/plan/actions/validate-plan-input.ts +39 -0
- package/corpus/templates/plan/app/components/plan/CanvasArea.tsx +167 -11
- package/corpus/templates/plan/app/i18n/en-US.ts +1 -0
- package/corpus/templates/plan/changelog/2026-08-04-canvas-zoom-controls-now-explain-the-command-ctrl-plus-scrol.md +6 -0
- package/corpus/templates/plan/changelog/2026-08-04-pinch-to-zoom-is-now-supported-on-touchscreens-in-visual-pla.md +6 -0
- package/corpus/templates/plan/shared/plan-content.ts +17 -2
- package/dist/cli/skills-content/canvas.d.ts +3 -3
- package/dist/cli/skills-content/canvas.js +16 -5
- package/dist/cli/skills-content/visual-plan-skill.d.ts +1 -1
- package/dist/cli/skills-content/visual-plan-skill.js +27 -0
- package/dist/cli/skills-content/wireframe.d.ts +2 -2
- package/dist/cli/skills-content/wireframe.js +7 -0
- package/dist/client/AgentPanel.js +23 -8
- package/dist/client/api-path.d.ts +6 -0
- package/dist/client/api-path.js +55 -0
- package/dist/client/onboarding/FirstRunOnboarding.d.ts +3 -0
- package/dist/client/onboarding/FirstRunOnboarding.js +93 -0
- package/dist/client/onboarding/first-run-enabled.d.ts +2 -0
- package/dist/client/onboarding/first-run-enabled.js +9 -0
- package/dist/client/onboarding/index.d.ts +2 -1
- package/dist/client/onboarding/index.js +1 -0
- package/dist/client/onboarding/use-onboarding.d.ts +6 -1
- package/dist/client/onboarding/use-onboarding.js +32 -1
- package/dist/client/route-state.js +10 -0
- package/dist/connections/catalog.d.ts +4 -4
- package/dist/connections/catalog.js +3 -3
- package/dist/db/index.d.ts +1 -1
- package/dist/db/index.js +1 -1
- package/dist/file-upload/actions/upload-image.d.ts +1 -1
- package/dist/notifications/routes.d.ts +5 -5
- package/dist/observability/routes.d.ts +3 -3
- package/dist/onboarding/app-profile.d.ts +4 -0
- package/dist/onboarding/app-profile.js +378 -0
- package/dist/onboarding/index.d.ts +2 -1
- package/dist/onboarding/index.js +1 -0
- package/dist/onboarding/plugin.d.ts +2 -0
- package/dist/onboarding/plugin.js +21 -1
- package/dist/onboarding/types.d.ts +19 -0
- package/dist/progress/routes.d.ts +1 -1
- package/dist/provider-api/actions/custom-provider-registration.d.ts +9 -9
- package/dist/provider-api/actions/provider-api.d.ts +12 -12
- package/dist/resources/handlers.d.ts +1 -1
- package/dist/server/auth.js +21 -1
- package/dist/server/better-auth-instance.d.ts +3 -2
- package/dist/server/better-auth-instance.js +9 -7
- package/dist/server/email-markdown.js +3 -8
- package/dist/server/transcribe-voice.d.ts +1 -1
- package/dist/shared/first-run-onboarding.d.ts +3 -0
- package/dist/shared/first-run-onboarding.js +3 -0
- package/dist/triggers/index.d.ts +3 -0
- package/dist/triggers/index.js +5 -0
- package/docs/content/cross-app-sso.mdx +26 -0
- package/package.json +1 -1
|
@@ -7,11 +7,13 @@
|
|
|
7
7
|
* POST /_agent-native/onboarding/dismiss — dismiss the banner
|
|
8
8
|
* GET /_agent-native/onboarding/dismissed — dismissed flag + allComplete
|
|
9
9
|
*/
|
|
10
|
-
import { defineEventHandler, getMethod, getQuery, setResponseStatus, } from "h3";
|
|
10
|
+
import { deleteCookie, defineEventHandler, getMethod, getQuery, setResponseStatus, } from "h3";
|
|
11
11
|
import { appStateGet, appStatePut } from "../application-state/store.js";
|
|
12
12
|
import { getSession } from "../server/auth.js";
|
|
13
13
|
import { awaitBootstrap, getH3App, markDefaultPluginProvided, } from "../server/framework-request-handler.js";
|
|
14
14
|
import { runWithRequestContext } from "../server/request-context.js";
|
|
15
|
+
import { FIRST_RUN_ONBOARDING_COOKIE } from "../shared/first-run-onboarding.js";
|
|
16
|
+
import { getOnboardingAppProfile } from "./app-profile.js";
|
|
15
17
|
import { registerDefaultOnboardingSteps } from "./default-steps.js";
|
|
16
18
|
import { listOnboardingSteps } from "./registry.js";
|
|
17
19
|
const ONBOARDING_PREFIX = "/_agent-native/onboarding";
|
|
@@ -89,6 +91,7 @@ export function createOnboardingPlugin(options = {}) {
|
|
|
89
91
|
return async (nitroApp) => {
|
|
90
92
|
markDefaultPluginProvided(nitroApp, "onboarding");
|
|
91
93
|
await awaitBootstrap(nitroApp);
|
|
94
|
+
const appProfile = getOnboardingAppProfile(options.appId);
|
|
92
95
|
if (!options.skipDefaultSteps) {
|
|
93
96
|
registerDefaultOnboardingSteps();
|
|
94
97
|
}
|
|
@@ -178,6 +181,23 @@ export function createOnboardingPlugin(options = {}) {
|
|
|
178
181
|
return { dismissed: false, allComplete: false };
|
|
179
182
|
}
|
|
180
183
|
}));
|
|
184
|
+
// GET /_agent-native/onboarding/profile
|
|
185
|
+
getH3App(nitroApp).use(`${ONBOARDING_PREFIX}/profile`, defineEventHandler(async (event) => {
|
|
186
|
+
if (getMethod(event) !== "GET") {
|
|
187
|
+
setResponseStatus(event, 405);
|
|
188
|
+
return { error: "Method not allowed" };
|
|
189
|
+
}
|
|
190
|
+
return appProfile;
|
|
191
|
+
}));
|
|
192
|
+
// POST /_agent-native/onboarding/first-run/complete
|
|
193
|
+
getH3App(nitroApp).use(`${ONBOARDING_PREFIX}/first-run/complete`, defineEventHandler(async (event) => {
|
|
194
|
+
if (getMethod(event) !== "POST") {
|
|
195
|
+
setResponseStatus(event, 405);
|
|
196
|
+
return { error: "Method not allowed" };
|
|
197
|
+
}
|
|
198
|
+
deleteCookie(event, FIRST_RUN_ONBOARDING_COOKIE, { path: "/" });
|
|
199
|
+
return { ok: true };
|
|
200
|
+
}));
|
|
181
201
|
};
|
|
182
202
|
}
|
|
183
203
|
/** Default plugin instance — mounted automatically when a template doesn't override. */
|
|
@@ -84,4 +84,23 @@ export interface OnboardingStepStatus {
|
|
|
84
84
|
complete: boolean;
|
|
85
85
|
methods: OnboardingMethod[];
|
|
86
86
|
}
|
|
87
|
+
export interface OnboardingCapability {
|
|
88
|
+
/** Stable capability id used by the profile and analytics. */
|
|
89
|
+
id: string;
|
|
90
|
+
/** Short label shown in the setup choice and BYOK list. */
|
|
91
|
+
label: string;
|
|
92
|
+
/** Whether this capability blocks the app's normal setup. */
|
|
93
|
+
required: boolean;
|
|
94
|
+
/** Whether Builder's managed connection covers this capability. */
|
|
95
|
+
builderIncluded: boolean;
|
|
96
|
+
/** Compact description of the key or connection the BYOK path needs. */
|
|
97
|
+
keySummary: string;
|
|
98
|
+
/** Hover/focus explanation for why the capability exists. */
|
|
99
|
+
why: string;
|
|
100
|
+
}
|
|
101
|
+
export interface OnboardingAppProfile {
|
|
102
|
+
appId: string;
|
|
103
|
+
appName: string;
|
|
104
|
+
capabilities: OnboardingCapability[];
|
|
105
|
+
}
|
|
87
106
|
//# sourceMappingURL=types.d.ts.map
|
|
@@ -75,6 +75,8 @@ export declare function createCustomProviderRegistrationAction<TSchema extends Z
|
|
|
75
75
|
user: "user";
|
|
76
76
|
}>>;
|
|
77
77
|
}, z.core.$strip>>, {
|
|
78
|
+
id?: undefined;
|
|
79
|
+
provider?: undefined;
|
|
78
80
|
deleted?: undefined;
|
|
79
81
|
found?: undefined;
|
|
80
82
|
providers: {
|
|
@@ -87,26 +89,24 @@ export declare function createCustomProviderRegistrationAction<TSchema extends Z
|
|
|
87
89
|
updatedAt: number;
|
|
88
90
|
}[];
|
|
89
91
|
count: number;
|
|
90
|
-
provider?: undefined;
|
|
91
92
|
registered?: undefined;
|
|
92
|
-
id?: undefined;
|
|
93
93
|
label?: undefined;
|
|
94
94
|
message?: undefined;
|
|
95
95
|
} | {
|
|
96
|
-
deleted?: undefined;
|
|
97
96
|
count?: undefined;
|
|
97
|
+
id?: undefined;
|
|
98
|
+
deleted?: undefined;
|
|
98
99
|
providers?: undefined;
|
|
99
100
|
found: boolean;
|
|
100
101
|
provider: import("../custom-registry.js").CustomProviderConfig;
|
|
101
102
|
registered?: undefined;
|
|
102
|
-
id?: undefined;
|
|
103
103
|
label?: undefined;
|
|
104
104
|
message?: undefined;
|
|
105
105
|
} | {
|
|
106
|
-
deleted?: undefined;
|
|
107
106
|
count?: undefined;
|
|
108
|
-
providers?: undefined;
|
|
109
107
|
provider?: undefined;
|
|
108
|
+
deleted?: undefined;
|
|
109
|
+
providers?: undefined;
|
|
110
110
|
found: boolean;
|
|
111
111
|
id: string;
|
|
112
112
|
registered?: undefined;
|
|
@@ -114,20 +114,20 @@ export declare function createCustomProviderRegistrationAction<TSchema extends Z
|
|
|
114
114
|
message?: undefined;
|
|
115
115
|
} | {
|
|
116
116
|
count?: undefined;
|
|
117
|
+
provider?: undefined;
|
|
117
118
|
found?: undefined;
|
|
118
119
|
providers?: undefined;
|
|
119
|
-
provider?: undefined;
|
|
120
120
|
deleted: boolean;
|
|
121
121
|
id: string;
|
|
122
122
|
registered?: undefined;
|
|
123
123
|
label?: undefined;
|
|
124
124
|
message?: undefined;
|
|
125
125
|
} | {
|
|
126
|
-
deleted?: undefined;
|
|
127
126
|
count?: undefined;
|
|
127
|
+
provider?: undefined;
|
|
128
|
+
deleted?: undefined;
|
|
128
129
|
found?: undefined;
|
|
129
130
|
providers?: undefined;
|
|
130
|
-
provider?: undefined;
|
|
131
131
|
registered: boolean;
|
|
132
132
|
id: string;
|
|
133
133
|
label: string;
|
|
@@ -311,9 +311,8 @@ export declare function createProviderApiActions(runtime: Pick<ProviderApiRuntim
|
|
|
311
311
|
notes?: string | undefined;
|
|
312
312
|
scope?: "org" | "user" | undefined;
|
|
313
313
|
}, {
|
|
314
|
+
message?: undefined;
|
|
314
315
|
id?: undefined;
|
|
315
|
-
provider?: undefined;
|
|
316
|
-
deleted?: undefined;
|
|
317
316
|
found?: undefined;
|
|
318
317
|
providers: {
|
|
319
318
|
id: string;
|
|
@@ -325,45 +324,46 @@ export declare function createProviderApiActions(runtime: Pick<ProviderApiRuntim
|
|
|
325
324
|
updatedAt: number;
|
|
326
325
|
}[];
|
|
327
326
|
count: number;
|
|
327
|
+
provider?: undefined;
|
|
328
|
+
deleted?: undefined;
|
|
328
329
|
registered?: undefined;
|
|
329
330
|
label?: undefined;
|
|
330
|
-
message?: undefined;
|
|
331
331
|
} | {
|
|
332
|
+
message?: undefined;
|
|
332
333
|
id?: undefined;
|
|
333
|
-
deleted?: undefined;
|
|
334
334
|
count?: undefined;
|
|
335
335
|
providers?: undefined;
|
|
336
336
|
found: boolean;
|
|
337
337
|
provider: import("../custom-registry.js").CustomProviderConfig;
|
|
338
|
+
deleted?: undefined;
|
|
338
339
|
registered?: undefined;
|
|
339
340
|
label?: undefined;
|
|
340
|
-
message?: undefined;
|
|
341
341
|
} | {
|
|
342
|
-
|
|
343
|
-
deleted?: undefined;
|
|
342
|
+
message?: undefined;
|
|
344
343
|
count?: undefined;
|
|
345
344
|
providers?: undefined;
|
|
345
|
+
provider?: undefined;
|
|
346
346
|
found: boolean;
|
|
347
347
|
id: string;
|
|
348
|
+
deleted?: undefined;
|
|
348
349
|
registered?: undefined;
|
|
349
350
|
label?: undefined;
|
|
350
|
-
message?: undefined;
|
|
351
351
|
} | {
|
|
352
|
-
|
|
352
|
+
message?: undefined;
|
|
353
353
|
found?: undefined;
|
|
354
354
|
count?: undefined;
|
|
355
355
|
providers?: undefined;
|
|
356
|
+
provider?: undefined;
|
|
356
357
|
deleted: boolean;
|
|
357
358
|
id: string;
|
|
358
359
|
registered?: undefined;
|
|
359
360
|
label?: undefined;
|
|
360
|
-
message?: undefined;
|
|
361
361
|
} | {
|
|
362
|
-
provider?: undefined;
|
|
363
|
-
deleted?: undefined;
|
|
364
362
|
found?: undefined;
|
|
365
363
|
count?: undefined;
|
|
366
364
|
providers?: undefined;
|
|
365
|
+
provider?: undefined;
|
|
366
|
+
deleted?: undefined;
|
|
367
367
|
registered: boolean;
|
|
368
368
|
id: string;
|
|
369
369
|
label: string;
|
|
@@ -48,8 +48,8 @@ export declare function handleUpdateResource(event: any): Promise<import("./stor
|
|
|
48
48
|
}>;
|
|
49
49
|
/** DELETE /_agent-native/resources/:id — delete a resource */
|
|
50
50
|
export declare function handleDeleteResource(event: any): Promise<{
|
|
51
|
-
error: string;
|
|
52
51
|
ok?: undefined;
|
|
52
|
+
error: string;
|
|
53
53
|
} | {
|
|
54
54
|
error?: undefined;
|
|
55
55
|
ok: boolean;
|
package/dist/server/auth.js
CHANGED
|
@@ -2,6 +2,7 @@ import crypto from "node:crypto";
|
|
|
2
2
|
import { defineEventHandler, getMethod, getQuery, getRequestIP, setResponseHeader, setResponseStatus, getCookie, setCookie, deleteCookie, getHeader, } from "h3";
|
|
3
3
|
import { EMBED_START_PATH } from "../shared/embed-auth.js";
|
|
4
4
|
import { EMBED_TARGET_HEADER } from "../shared/embed-auth.js";
|
|
5
|
+
import { FIRST_RUN_ONBOARDING_COOKIE, FIRST_RUN_ONBOARDING_MAX_AGE, } from "../shared/first-run-onboarding.js";
|
|
5
6
|
import { EMBED_TRANSPLANT_HEADER, isMcpEmbedCorsOrigin, MCP_EMBED_CORS_ALLOW_HEADERS, shouldAllowMcpEmbedCredentials, } from "../shared/mcp-embed-headers.js";
|
|
6
7
|
import { isEmbedCapabilityScope, requestHasEmbedAuthMarker, resolveEmbedSessionFromRequest, } from "./embed-session.js";
|
|
7
8
|
// In h3 v2, `event.req` IS the web Request — but in Nitro's dev server (srvx
|
|
@@ -1880,6 +1881,14 @@ function crossSiteCookieAttrs(event) {
|
|
|
1880
1881
|
? { sameSite: "none", secure: true, partitioned: true }
|
|
1881
1882
|
: { sameSite: "lax", secure: false };
|
|
1882
1883
|
}
|
|
1884
|
+
function setFirstRunOnboardingCookie(event) {
|
|
1885
|
+
setCookie(event, FIRST_RUN_ONBOARDING_COOKIE, "1", {
|
|
1886
|
+
...crossSiteCookieAttrs(event),
|
|
1887
|
+
httpOnly: false,
|
|
1888
|
+
path: "/",
|
|
1889
|
+
maxAge: FIRST_RUN_ONBOARDING_MAX_AGE,
|
|
1890
|
+
});
|
|
1891
|
+
}
|
|
1883
1892
|
export function setFrameworkSessionCookie(event, token) {
|
|
1884
1893
|
clearFrameworkSessionCookies(event);
|
|
1885
1894
|
setCookie(event, COOKIE_NAME, token, {
|
|
@@ -2293,11 +2302,14 @@ async function mountBetterAuthRoutes(app, options) {
|
|
|
2293
2302
|
if (!googleAccountId) {
|
|
2294
2303
|
throw new Error("Could not get Google account id");
|
|
2295
2304
|
}
|
|
2296
|
-
await ensureGoogleAuthIdentity({
|
|
2305
|
+
const isNewGoogleUser = await ensureGoogleAuthIdentity({
|
|
2297
2306
|
email,
|
|
2298
2307
|
accountId: googleAccountId,
|
|
2299
2308
|
name: typeof user.name === "string" ? user.name : undefined,
|
|
2300
2309
|
});
|
|
2310
|
+
if (isNewGoogleUser === true) {
|
|
2311
|
+
setFirstRunOnboardingCookie(event);
|
|
2312
|
+
}
|
|
2301
2313
|
if (typeof user.picture === "string" && user.picture.trim()) {
|
|
2302
2314
|
await putSetting(`avatar:${email}`, {
|
|
2303
2315
|
image: user.picture,
|
|
@@ -2633,6 +2645,12 @@ async function mountBetterAuthRoutes(app, options) {
|
|
|
2633
2645
|
// Best-effort — don't block the response
|
|
2634
2646
|
}
|
|
2635
2647
|
}
|
|
2648
|
+
if (reqPath.includes("/sign-up/email") &&
|
|
2649
|
+
isResponse &&
|
|
2650
|
+
response.status >= 200 &&
|
|
2651
|
+
response.status < 300) {
|
|
2652
|
+
setFirstRunOnboardingCookie(event);
|
|
2653
|
+
}
|
|
2636
2654
|
return response;
|
|
2637
2655
|
}));
|
|
2638
2656
|
// Backward-compat: POST /_agent-native/auth/login
|
|
@@ -2721,6 +2739,7 @@ async function mountBetterAuthRoutes(app, options) {
|
|
|
2721
2739
|
body: { email, password, name: email.split("@")[0], callbackURL },
|
|
2722
2740
|
headers: event.headers,
|
|
2723
2741
|
});
|
|
2742
|
+
setFirstRunOnboardingCookie(event);
|
|
2724
2743
|
return { ok: true };
|
|
2725
2744
|
}
|
|
2726
2745
|
catch (e) {
|
|
@@ -2939,6 +2958,7 @@ function mountAuthFallbackRoutes(app) {
|
|
|
2939
2958
|
body: { email, password, name: email.split("@")[0] },
|
|
2940
2959
|
headers: event.headers,
|
|
2941
2960
|
});
|
|
2961
|
+
setFirstRunOnboardingCookie(event);
|
|
2942
2962
|
return { ok: true };
|
|
2943
2963
|
}
|
|
2944
2964
|
catch (e) {
|
|
@@ -193,9 +193,10 @@ export interface GoogleAuthIdentity {
|
|
|
193
193
|
* Ensure a verified Google identity has a canonical Better Auth user/account
|
|
194
194
|
* before the legacy email-keyed session is issued. This prevents a later
|
|
195
195
|
* password signup from becoming the first canonical identity for that email.
|
|
196
|
+
* Returns whether this call created the canonical user.
|
|
196
197
|
*/
|
|
197
|
-
export declare function ensureGoogleAuthIdentity(identity: GoogleAuthIdentity): Promise<
|
|
198
|
-
export declare function ensureGoogleAuthIdentityWithAdapter(adapter: BetterAuthInternalAdapter, identity: GoogleAuthIdentity): Promise<
|
|
198
|
+
export declare function ensureGoogleAuthIdentity(identity: GoogleAuthIdentity): Promise<boolean>;
|
|
199
|
+
export declare function ensureGoogleAuthIdentityWithAdapter(adapter: BetterAuthInternalAdapter, identity: GoogleAuthIdentity): Promise<boolean>;
|
|
199
200
|
/** Reset for testing */
|
|
200
201
|
export declare function resetBetterAuth(): Promise<void>;
|
|
201
202
|
/**
|
|
@@ -709,13 +709,14 @@ export async function getBetterAuthInternalAdapter(config) {
|
|
|
709
709
|
* Ensure a verified Google identity has a canonical Better Auth user/account
|
|
710
710
|
* before the legacy email-keyed session is issued. This prevents a later
|
|
711
711
|
* password signup from becoming the first canonical identity for that email.
|
|
712
|
+
* Returns whether this call created the canonical user.
|
|
712
713
|
*/
|
|
713
714
|
export async function ensureGoogleAuthIdentity(identity) {
|
|
714
715
|
const adapter = await getBetterAuthInternalAdapter();
|
|
715
716
|
if (!adapter) {
|
|
716
717
|
throw new Error("Better Auth internal adapter is unavailable");
|
|
717
718
|
}
|
|
718
|
-
|
|
719
|
+
return ensureGoogleAuthIdentityWithAdapter(adapter, identity);
|
|
719
720
|
}
|
|
720
721
|
export async function ensureGoogleAuthIdentityWithAdapter(adapter, identity) {
|
|
721
722
|
const email = identity.email.trim().toLowerCase();
|
|
@@ -731,13 +732,13 @@ export async function ensureGoogleAuthIdentityWithAdapter(adapter, identity) {
|
|
|
731
732
|
if (!existing || linkedAccount.userId !== existing.user.id) {
|
|
732
733
|
throw new Error("Google account is already linked to another user");
|
|
733
734
|
}
|
|
734
|
-
return;
|
|
735
|
+
return false;
|
|
735
736
|
}
|
|
736
737
|
if (!existing) {
|
|
737
738
|
if (adapter.createOAuthUser) {
|
|
738
739
|
try {
|
|
739
740
|
await adapter.createOAuthUser({ email, name, emailVerified: true }, { providerId: "google", accountId });
|
|
740
|
-
return;
|
|
741
|
+
return true;
|
|
741
742
|
}
|
|
742
743
|
catch (error) {
|
|
743
744
|
// A concurrent first sign-in may have won the unique-email race. Only
|
|
@@ -754,7 +755,7 @@ export async function ensureGoogleAuthIdentityWithAdapter(adapter, identity) {
|
|
|
754
755
|
if (linkedAccount.userId !== existing.user.id) {
|
|
755
756
|
throw new Error("Google account is already linked to another user");
|
|
756
757
|
}
|
|
757
|
-
return;
|
|
758
|
+
return false;
|
|
758
759
|
}
|
|
759
760
|
}
|
|
760
761
|
}
|
|
@@ -769,7 +770,7 @@ export async function ensureGoogleAuthIdentityWithAdapter(adapter, identity) {
|
|
|
769
770
|
providerId: "google",
|
|
770
771
|
accountId,
|
|
771
772
|
});
|
|
772
|
-
return;
|
|
773
|
+
return true;
|
|
773
774
|
}
|
|
774
775
|
}
|
|
775
776
|
if (!existing) {
|
|
@@ -777,7 +778,7 @@ export async function ensureGoogleAuthIdentityWithAdapter(adapter, identity) {
|
|
|
777
778
|
}
|
|
778
779
|
const alreadyLinked = existing.accounts.some((account) => account.providerId === "google" && account.accountId === accountId);
|
|
779
780
|
if (alreadyLinked)
|
|
780
|
-
return;
|
|
781
|
+
return false;
|
|
781
782
|
// A password signup reserves the email before verification. If that row is
|
|
782
783
|
// credential-only, remove the unverified credential and promote the same
|
|
783
784
|
// canonical user to the verified Google identity. Any other linked account
|
|
@@ -793,13 +794,14 @@ export async function ensureGoogleAuthIdentityWithAdapter(adapter, identity) {
|
|
|
793
794
|
email,
|
|
794
795
|
accountId,
|
|
795
796
|
});
|
|
796
|
-
return;
|
|
797
|
+
return false;
|
|
797
798
|
}
|
|
798
799
|
await adapter.linkAccount({
|
|
799
800
|
userId: existing.user.id,
|
|
800
801
|
providerId: "google",
|
|
801
802
|
accountId,
|
|
802
803
|
});
|
|
804
|
+
return false;
|
|
803
805
|
}
|
|
804
806
|
/** Reset for testing */
|
|
805
807
|
export async function resetBetterAuth() {
|
|
@@ -25,14 +25,9 @@ function inlineMarkdown(value) {
|
|
|
25
25
|
trailing = url.slice(-1) + trailing;
|
|
26
26
|
url = url.slice(0, -1);
|
|
27
27
|
}
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
const host = new URL(normalizedUrl).hostname.replace(/^www\./, "");
|
|
32
|
-
if (host)
|
|
33
|
-
label = `Open ${host}`;
|
|
34
|
-
}
|
|
35
|
-
return `${prefix}<a href="${url}" style="color:${EMAIL_TEXT};text-decoration:underline;">${label}</a>${trailing}`;
|
|
28
|
+
// A bare URL stays its own link text: a recipient who cannot read the
|
|
29
|
+
// destination cannot tell a digest link from a phishing one.
|
|
30
|
+
return `${prefix}<a href="${url}" style="color:${EMAIL_TEXT};text-decoration:underline;">${url}</a>${trailing}`;
|
|
36
31
|
});
|
|
37
32
|
html = html
|
|
38
33
|
.replace(/`([^`]+)`/g, `<code style="background:${EMAIL_CODE};padding:2px 5px;border-radius:4px;font-size:0.92em;">$1</code>`)
|
package/dist/triggers/index.d.ts
CHANGED
|
@@ -2,4 +2,7 @@ export type { TriggerFrontmatter, TriggerDispatchContext } from "./types.js";
|
|
|
2
2
|
export { initTriggerDispatcher, refreshEventSubscriptions, parseTriggerFrontmatter, buildTriggerContent, type TriggerDispatcherDeps, } from "./dispatcher.js";
|
|
3
3
|
export { evaluateCondition, __clearConditionCache, } from "./condition-evaluator.js";
|
|
4
4
|
export { createAutomationToolEntries } from "./actions.js";
|
|
5
|
+
export { defineAutomation, listAutomationDefinitions, updateAutomation, type AutomationActor, type AutomationDefinition, } from "../automations/service.js";
|
|
6
|
+
export { queueAutomationRunNow } from "../jobs/run-now.js";
|
|
7
|
+
export { listAutomationRuns } from "../jobs/run-history.js";
|
|
5
8
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/triggers/index.js
CHANGED
|
@@ -1,4 +1,9 @@
|
|
|
1
1
|
export { initTriggerDispatcher, refreshEventSubscriptions, parseTriggerFrontmatter, buildTriggerContent, } from "./dispatcher.js";
|
|
2
2
|
export { evaluateCondition, __clearConditionCache, } from "./condition-evaluator.js";
|
|
3
3
|
export { createAutomationToolEntries } from "./actions.js";
|
|
4
|
+
// Template-native automation surfaces use the same organization-scoped
|
|
5
|
+
// service and run history as the framework Agent page.
|
|
6
|
+
export { defineAutomation, listAutomationDefinitions, updateAutomation, } from "../automations/service.js";
|
|
7
|
+
export { queueAutomationRunNow } from "../jobs/run-now.js";
|
|
8
|
+
export { listAutomationRuns } from "../jobs/run-history.js";
|
|
4
9
|
//# sourceMappingURL=index.js.map
|
|
@@ -15,6 +15,32 @@ This is the same trust primitive [A2A](/docs/a2a-protocol) and [External Agents]
|
|
|
15
15
|
|
|
16
16
|
</Callout>
|
|
17
17
|
|
|
18
|
+
## What the user sees {#user-flow}
|
|
19
|
+
|
|
20
|
+
Cross-App SSO should feel like moving between products in one workspace, not
|
|
21
|
+
creating a second account. For example:
|
|
22
|
+
|
|
23
|
+
1. Sign in to [Dispatch](https://dispatch.agent-native.com), or to any app
|
|
24
|
+
that already uses the workspace identity.
|
|
25
|
+
2. Open [Mail](https://mail.agent-native.com), [Calendar](https://calendar.agent-native.com),
|
|
26
|
+
or another enabled app in a new tab.
|
|
27
|
+
3. The app sends the browser to Dispatch only if it does not already have a
|
|
28
|
+
Dispatch session. If the session exists, the redirect is effectively
|
|
29
|
+
invisible.
|
|
30
|
+
4. Return to the app already signed in, with the same email, records, and org
|
|
31
|
+
context as before.
|
|
32
|
+
|
|
33
|
+
The important distinction is that this is **one sign-in, not one shared
|
|
34
|
+
cookie**. Each separately hosted app still creates and owns its own local
|
|
35
|
+
session. Dispatch proves the user's identity at the app's front door, and the
|
|
36
|
+
app then continues with its normal local auth and access checks.
|
|
37
|
+
|
|
38
|
+
For a product walkthrough, record this exact sequence: sign in once in
|
|
39
|
+
Dispatch, open two other hosted apps, show that neither asks for credentials,
|
|
40
|
+
then sign out of one app and show that the other app's session is independent.
|
|
41
|
+
That last step makes the security boundary visible: SSO removes repeated
|
|
42
|
+
logins without turning every app into one shared session store.
|
|
43
|
+
|
|
18
44
|
## What & why {#what-why}
|
|
19
45
|
|
|
20
46
|
Per-app user stores mean there is no single place a browser cookie could live that every app trusts. The federation model instead names one app — **Dispatch** — as the identity authority. Any other app can delegate "who is this person?" to Dispatch, get back a short-lived signed assertion of the user's verified email, and then **link that to its own local account by email**.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@agent-native/core",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.137.0",
|
|
4
4
|
"description": "Framework for agent-native application development — where AI agents and UI share SQL state, actions, and context",
|
|
5
5
|
"homepage": "https://github.com/BuilderIO/agent-native#readme",
|
|
6
6
|
"bugs": {
|