@agent-native/core 0.227.0-nightly-20261110032437 → 0.227.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/dist/agent/default-agent-engine.d.ts +1 -0
- package/dist/agent/default-agent-engine.js +6 -3
- package/dist/agent/engine/builder-engine.js +10 -6
- package/dist/agent/engine/chat-model-availability.d.ts +9 -0
- package/dist/agent/engine/chat-model-availability.js +39 -0
- package/dist/agent/optional-placeholders.d.ts +1 -0
- package/dist/agent/optional-placeholders.js +3 -0
- package/dist/cli/create.js +0 -49
- package/dist/cli/index.js +1 -1
- package/dist/cli/react-router-command.js +13 -7
- package/dist/client/chat/agentkit-protocol.js +259 -200
- package/dist/client/chat/run-outcome.d.ts +48 -0
- package/dist/client/chat/run-outcome.js +50 -0
- package/dist/collab/routes.d.ts +1 -1
- package/dist/collab/struct-routes.d.ts +1 -1
- package/dist/deploy/build.d.ts +1 -0
- package/dist/deploy/build.js +30 -1
- package/dist/framework-package-versions.json +11 -11
- package/dist/jobs/run-now.js +9 -1
- package/dist/notifications/routes.d.ts +3 -3
- package/dist/org/index.d.ts +1 -1
- package/dist/org/migrations.d.ts +1 -1
- package/dist/provider-api/actions/provider-api.d.ts +1 -1
- package/dist/resources/handlers.d.ts +1 -1
- package/dist/scripts/agent-engines/list-agent-engines.js +9 -5
- package/dist/server/auth.d.ts +3 -1
- package/dist/server/auth.js +29 -9
- package/dist/server/builder-signup-experiment.d.ts +89 -42
- package/dist/server/builder-signup-experiment.js +36 -14
- package/dist/server/core-routes-plugin.js +5 -3
- package/dist/server/index.d.ts +2 -1
- package/dist/server/index.js +2 -1
- package/dist/server/onboarding-html.d.ts +2 -0
- package/dist/server/onboarding-html.js +9 -5
- package/dist/server/release-migrations.d.ts +3 -1
- package/dist/server/release-migrations.js +8 -6
- package/dist/shared/mcp-embed-headers.js +8 -2
- package/dist/templates/builder-code-starter/AGENTS.md.patch +1 -1
- package/dist/templates/builder-code-starter/server/plugins/auth.ts.patch +2 -1
- package/dist/templates/chat/AGENTS.md +1 -1
- package/dist/templates/chat/app/components/layout/Sidebar.tsx +1 -1
- package/dist/templates/chat/scripts/migrate-production.ts +1 -1
- package/dist/templates/chat/server/plugins/auth.ts +1 -0
- package/dist/templates/default/pnpm-workspace.yaml +0 -41
- package/dist/templates/default/scripts/migrate-production.ts +1 -1
- package/dist/templates/workspace-root/pnpm-workspace.yaml +0 -41
- package/dist/tracking/providers.js +20 -8
- package/dist/triggers/actions/list-automations.js +7 -1
- package/docs/content/agent-web-surfaces.mdx +54 -42
- package/docs/content/authentication.mdx +14 -0
- package/docs/content/client-agent-chat.mdx +2 -0
- package/docs/content/client-routing.mdx +2 -0
- package/docs/content/create-with-an-agent.mdx +1 -1
- package/docs/content/environment-variables.mdx +2 -0
- package/docs/content/extensions.mdx +8 -9
- package/docs/content/external-agents.mdx +8 -0
- package/docs/content/upgrading-core-ui.mdx +2 -0
- package/docs/content/vercel.mdx +2 -0
- package/package.json +4 -4
- package/src/templates/builder-code-starter/AGENTS.md.patch +1 -1
- package/src/templates/builder-code-starter/server/plugins/auth.ts.patch +2 -1
- package/src/templates/chat/AGENTS.md +1 -1
- package/src/templates/chat/app/components/layout/Sidebar.tsx +1 -1
- package/src/templates/chat/scripts/migrate-production.ts +1 -1
- package/src/templates/chat/server/plugins/auth.ts +1 -0
- package/src/templates/default/pnpm-workspace.yaml +0 -41
- package/src/templates/default/scripts/migrate-production.ts +1 -1
- package/src/templates/workspace-root/pnpm-workspace.yaml +0 -41
|
@@ -156,7 +156,8 @@ export async function bindBuilderSignupAttempt(event, attemptId, method, email)
|
|
|
156
156
|
const createdAtMs = createdAt ? new Date(createdAt).getTime() : Number.NaN;
|
|
157
157
|
if (!identity ||
|
|
158
158
|
!Number.isFinite(createdAtMs) ||
|
|
159
|
-
createdAtMs < assignment.issuedAt
|
|
159
|
+
createdAtMs < assignment.issuedAt ||
|
|
160
|
+
(assignment.acceptedAt !== undefined && createdAtMs < assignment.acceptedAt))
|
|
160
161
|
return false;
|
|
161
162
|
track("builder_signup_experiment_enrolled", { ...experimentProperties(assignment), method }, { authUserId: identity.user.id, userId: normalizedEmail });
|
|
162
163
|
if (assignment.variant === "control") {
|
|
@@ -186,8 +187,6 @@ export async function bindBuilderSignupAttempt(event, attemptId, method, email)
|
|
|
186
187
|
if (assignment.method !== method ||
|
|
187
188
|
(assignment.email && assignment.email !== normalizedEmail))
|
|
188
189
|
return false;
|
|
189
|
-
if (createdAtMs < assignment.acceptedAt)
|
|
190
|
-
return false;
|
|
191
190
|
const bound = z
|
|
192
191
|
.object({ id: z.string(), boundUserId: z.string() })
|
|
193
192
|
.parse(await mutateSetting(key, (current) => current ?? { id: assignment.id, boundUserId: identity.user.id }));
|
|
@@ -204,7 +203,7 @@ export async function bindBuilderSignupAttempt(event, attemptId, method, email)
|
|
|
204
203
|
maxAge: TTL,
|
|
205
204
|
secure: getHeader(event, "host")?.includes("localhost") !== true,
|
|
206
205
|
});
|
|
207
|
-
return
|
|
206
|
+
return { userId: identity.user.id };
|
|
208
207
|
}
|
|
209
208
|
export async function getBuilderSignupConnectError(userId) {
|
|
210
209
|
if (!userId || !isBuilderSignupExperimentEnabled())
|
|
@@ -257,7 +256,22 @@ async function finishSignupActivation(key, attempt, outcome) {
|
|
|
257
256
|
changed,
|
|
258
257
|
};
|
|
259
258
|
}
|
|
260
|
-
|
|
259
|
+
let verifiedSignupStarter;
|
|
260
|
+
export function setBuilderSignupVerifiedStarter(starter) {
|
|
261
|
+
verifiedSignupStarter = starter;
|
|
262
|
+
}
|
|
263
|
+
/** Called only after the auth provider issued this verified signup's session. */
|
|
264
|
+
export async function startBuilderSignupForVerifiedSession(event, session) {
|
|
265
|
+
if (!isBuilderSignupExperimentEnabled() ||
|
|
266
|
+
!session.userId ||
|
|
267
|
+
!session.token ||
|
|
268
|
+
session.emailVerified !== true)
|
|
269
|
+
return;
|
|
270
|
+
if (!verifiedSignupStarter)
|
|
271
|
+
throw new Error("Builder signup activation handler is unavailable");
|
|
272
|
+
await verifiedSignupStarter(event, session);
|
|
273
|
+
}
|
|
274
|
+
export function createBuilderSignupExperiment(dependencies) {
|
|
261
275
|
const reconcile = async (event, session, key, existing, assignment) => {
|
|
262
276
|
const { attempt, startedAt } = existing;
|
|
263
277
|
if (!session.userId ||
|
|
@@ -293,10 +307,11 @@ export function createBuilderSignupExperimentHandler(dependencies) {
|
|
|
293
307
|
...(result.code ? { code: result.code } : {}),
|
|
294
308
|
};
|
|
295
309
|
};
|
|
296
|
-
|
|
310
|
+
const handle = async (event, verifiedSignupSession) => {
|
|
297
311
|
setResponseHeader(event, "Cache-Control", "no-store");
|
|
298
312
|
const refuse = (status, code) => {
|
|
299
|
-
|
|
313
|
+
if (!verifiedSignupSession)
|
|
314
|
+
setResponseStatus(event, status);
|
|
300
315
|
return { status: "unavailable", code };
|
|
301
316
|
};
|
|
302
317
|
if (!isBuilderSignupExperimentEnabled()) {
|
|
@@ -304,12 +319,12 @@ export function createBuilderSignupExperimentHandler(dependencies) {
|
|
|
304
319
|
deleteCookie(event, "an_builder_signup_pending", { path: "/" });
|
|
305
320
|
return { status: "disabled" };
|
|
306
321
|
}
|
|
307
|
-
const method = getMethod(event);
|
|
322
|
+
const method = verifiedSignupSession ? "POST" : getMethod(event);
|
|
308
323
|
if (method !== "GET" && method !== "POST")
|
|
309
324
|
return refuse(405, "method_not_allowed");
|
|
310
|
-
if (!dependencies.sameOrigin(event))
|
|
325
|
+
if (!verifiedSignupSession && !dependencies.sameOrigin(event))
|
|
311
326
|
return refuse(403, "cross_origin");
|
|
312
|
-
const session = await dependencies.getSession(event);
|
|
327
|
+
const session = verifiedSignupSession ?? (await dependencies.getSession(event));
|
|
313
328
|
let assignment = decodeBuilderSignupAssignment(getCookie(event, builderSignupAssignmentCookieName()));
|
|
314
329
|
if (method === "GET") {
|
|
315
330
|
if (session)
|
|
@@ -329,7 +344,8 @@ export function createBuilderSignupExperimentHandler(dependencies) {
|
|
|
329
344
|
experimentId: experimentId(),
|
|
330
345
|
};
|
|
331
346
|
}
|
|
332
|
-
if (
|
|
347
|
+
if (!verifiedSignupSession &&
|
|
348
|
+
!/^application\/json\s*(;|$)/i.test(getHeader(event, "content-type") ?? ""))
|
|
333
349
|
return refuse(415, "json_required");
|
|
334
350
|
const body = z
|
|
335
351
|
.object({
|
|
@@ -339,7 +355,9 @@ export function createBuilderSignupExperimentHandler(dependencies) {
|
|
|
339
355
|
method: z.enum(["password", "magic-link", "google"]).optional(),
|
|
340
356
|
email: z.string().email().max(320).optional(),
|
|
341
357
|
})
|
|
342
|
-
.safeParse(
|
|
358
|
+
.safeParse(verifiedSignupSession
|
|
359
|
+
? { operation: "start" }
|
|
360
|
+
: await readBodyWithSizeLimit(event, 4096));
|
|
343
361
|
if (!body.success)
|
|
344
362
|
return refuse(400, "invalid_request");
|
|
345
363
|
const waitUntil = body.data.operation === "start"
|
|
@@ -385,7 +403,7 @@ export function createBuilderSignupExperimentHandler(dependencies) {
|
|
|
385
403
|
}
|
|
386
404
|
}
|
|
387
405
|
if (body.data.operation === "status" ||
|
|
388
|
-
(body.data.operation === "start" && !waitUntil)) {
|
|
406
|
+
(body.data.operation === "start" && !waitUntil && !verifiedSignupSession)) {
|
|
389
407
|
if (!session?.emailVerified || !session.userId)
|
|
390
408
|
return refuse(401, "verified_session_required");
|
|
391
409
|
if (!consent) {
|
|
@@ -586,5 +604,9 @@ export function createBuilderSignupExperimentHandler(dependencies) {
|
|
|
586
604
|
}
|
|
587
605
|
// Hosts without a durable background lifetime must await the write.
|
|
588
606
|
return completion;
|
|
589
|
-
}
|
|
607
|
+
};
|
|
608
|
+
return {
|
|
609
|
+
handler: defineEventHandler((event) => handle(event)),
|
|
610
|
+
startVerifiedSignup: (event, session) => handle(event, session),
|
|
611
|
+
};
|
|
590
612
|
}
|
|
@@ -10,7 +10,7 @@ import { registerBuiltinEngines } from "../agent/engine/builtin.js";
|
|
|
10
10
|
import { OPENAI_BASE_URL_ENV_VAR, PROVIDER_ENV_META, } from "../agent/engine/provider-env-vars.js";
|
|
11
11
|
import { detectEngineFromEnvForRequest, detectEngineFromUserSecrets, isStoredEngineUsableForRequest, } from "../agent/engine/registry.js";
|
|
12
12
|
import { canUpdateAgentLoopSettings, readAgentLoopSettings, resetAgentLoopSettings, validateMaxIterationsInput, writeAgentLoopSettings, } from "../agent/loop-settings.js";
|
|
13
|
-
import {
|
|
13
|
+
import { createBuilderSignupExperiment, setBuilderSignupVerifiedStarter, getBuilderSignupConnectError, getBuilderSignupTrackingIdentity, } from "./builder-signup-experiment.js";
|
|
14
14
|
export { normalizeAgentEngineStatusModel, resolveAgentEngineStatus, } from "../agent/engine-status.js";
|
|
15
15
|
import { getAppConfig } from "../app-config/index.js";
|
|
16
16
|
import { getState, putState, compareAndSetState, deleteState, listComposeDrafts, getComposeDraft, putComposeDraft, saveComposeDraft, deleteComposeDraft, deleteAllComposeDrafts, getStateMany, putStateMany, APP_STATE_ANONYMOUS_OWNER_CONTEXT_KEY, } from "../application-state/handlers.js";
|
|
@@ -3478,7 +3478,7 @@ export function createCoreRoutesPlugin(options = {}) {
|
|
|
3478
3478
|
setResponseHeader(event, "Location", authorizationUrl);
|
|
3479
3479
|
return "";
|
|
3480
3480
|
}));
|
|
3481
|
-
|
|
3481
|
+
const builderSignupExperiment = createBuilderSignupExperiment({
|
|
3482
3482
|
getSession,
|
|
3483
3483
|
sameOrigin: isSameOriginConnect,
|
|
3484
3484
|
activate: async (event, session, owner) => {
|
|
@@ -3498,7 +3498,9 @@ export function createCoreRoutesPlugin(options = {}) {
|
|
|
3498
3498
|
});
|
|
3499
3499
|
},
|
|
3500
3500
|
reconcile: reconcileBuilderSignupActivation,
|
|
3501
|
-
})
|
|
3501
|
+
});
|
|
3502
|
+
setBuilderSignupVerifiedStarter(builderSignupExperiment.startVerifiedSignup);
|
|
3503
|
+
getH3App(nitroApp).use(`${P}/auth/builder-signup-experiment`, builderSignupExperiment.handler);
|
|
3502
3504
|
getH3App(nitroApp).use(`${P}/builder/provision`, createBuilderProvisionHandler((event) => resolveBuilderOwnerContext(event)));
|
|
3503
3505
|
// Desktop Code Agents speak Anthropic Messages locally, but Builder
|
|
3504
3506
|
// Gateway credentials live on the server. This same-origin route keeps
|
package/dist/server/index.d.ts
CHANGED
|
@@ -16,7 +16,7 @@ export { createEmbedSessionTicket, consumeEmbedSessionTicket, normalizeEmbedTarg
|
|
|
16
16
|
export { createSSEHandler, type SSEHandlerOptions } from "./sse.js";
|
|
17
17
|
export { isCredentialMembershipUnavailable } from "./credential-membership-unavailable.js";
|
|
18
18
|
export { readOrgMemberRole } from "./personal-provider-key-policy.js";
|
|
19
|
-
export { mountAuthMiddleware, autoMountAuth, registerAuthPublicPaths, getSession, getBrowserCookieSession, isSessionResolutionUnavailable, getMcpOAuthBearerSession, logout, COOKIE_NAME, addSession, removeSession, getSessionEmail, getFrameworkSessionCookieValues, setFrameworkSessionCookie, setFirstRunOnboardingCookie, clearFrameworkSessionCookies, runAuthGuard, registerDesktopExchange, prepareDesktopOAuthBrowserBinding, matchesDesktopOAuthBrowserBinding, DESKTOP_OAUTH_BROWSER_BINDING_COOKIE, setDesktopExchange, setDesktopExchangeError, safeReturnPath, type DesktopExchangeErrorPayload, type AuthSession, type AuthOptions, } from "./auth.js";
|
|
19
|
+
export { mountAuthMiddleware, autoMountAuth, registerAuthPublicPaths, recordBuilderSignupBinding, getSession, getBrowserCookieSession, isSessionResolutionUnavailable, getMcpOAuthBearerSession, logout, COOKIE_NAME, addSession, removeSession, getSessionEmail, getFrameworkSessionCookieValues, setFrameworkSessionCookie, setFirstRunOnboardingCookie, clearFrameworkSessionCookies, runAuthGuard, registerDesktopExchange, prepareDesktopOAuthBrowserBinding, matchesDesktopOAuthBrowserBinding, DESKTOP_OAUTH_BROWSER_BINDING_COOKIE, setDesktopExchange, setDesktopExchangeError, safeReturnPath, type DesktopExchangeErrorPayload, type AuthSession, type AuthOptions, } from "./auth.js";
|
|
20
20
|
export { hasSameOriginBrowserEvidence } from "./request-origin.js";
|
|
21
21
|
export { getEmbedSessionOrigin } from "./embed-request-origin.js";
|
|
22
22
|
export { handleIdentitySso, ensureIdentityUser, getIdentityHubUrl, isIdentitySsoEnabled, isIdentitySsoBypassPath, identitySsoLoginButtonHtml, IDENTITY_SSO_BOOTSTRAP_ACTIVATE_PATH, IDENTITY_SSO_BOOTSTRAP_BINDING_COOKIE, clearIdentitySsoBootstrapBindingCookie, getIdentitySsoBootstrapBindingCookie, setIdentitySsoBootstrapBindingCookie, IDENTITY_SSO_PROVIDER_ID, IDENTITY_SSO_SCOPE, IDENTITY_SSO_DESKTOP_COMPLETE_PATH, } from "./identity-sso.js";
|
|
@@ -41,6 +41,7 @@ export { callerHasThreadAccess } from "../agent/run-ownership.js";
|
|
|
41
41
|
export { abortTurnByRefDurably, getActiveRunForThreadAsync, } from "../agent/run-manager.js";
|
|
42
42
|
export { mountRealtimeVoiceRoutes, realtimeVoiceSafetyIdentifier, REALTIME_VOICE_MAX_SDP_BYTES, REALTIME_VOICE_MAX_TOOL_BODY_BYTES, REALTIME_VOICE_MAX_TOOL_OUTPUT_CHARS, REALTIME_VOICE_SESSION_PATH, REALTIME_VOICE_TOOL_PATH, type MountRealtimeVoiceRoutesOptions, type RealtimeVoiceIntelligence, type RealtimeVoiceRequestContext, type RealtimeVoiceToolExecutionRequest, type RealtimeVoiceToolExecutionResult, } from "./realtime-voice.js";
|
|
43
43
|
export { getStoredModelForEngine, resolveEngine, } from "../agent/engine/index.js";
|
|
44
|
+
export { resolveChatModelAvailability, type ChatModelAvailability, } from "../agent/engine/chat-model-availability.js";
|
|
44
45
|
export { completeText, type CompleteTextMessage, type CompleteTextOptions, type CompleteTextResult, type CompleteTextUsage, } from "./complete-text.js";
|
|
45
46
|
export { createDevScriptRegistry } from "../scripts/dev/index.js";
|
|
46
47
|
export { createPollHandler, recordChange, prepareTransactionalChange, getVersion, getChangesSince, getCurrentPollBaseline, getPollEmitter, canSeeChangeForUser, POLL_CHANGE_EVENT, type TransactionalChange, } from "./poll.js";
|
package/dist/server/index.js
CHANGED
|
@@ -16,7 +16,7 @@ export { createEmbedSessionTicket, consumeEmbedSessionTicket, normalizeEmbedTarg
|
|
|
16
16
|
export { createSSEHandler } from "./sse.js";
|
|
17
17
|
export { isCredentialMembershipUnavailable } from "./credential-membership-unavailable.js";
|
|
18
18
|
export { readOrgMemberRole } from "./personal-provider-key-policy.js";
|
|
19
|
-
export { mountAuthMiddleware, autoMountAuth, registerAuthPublicPaths, getSession, getBrowserCookieSession, isSessionResolutionUnavailable, getMcpOAuthBearerSession, logout, COOKIE_NAME, addSession, removeSession, getSessionEmail, getFrameworkSessionCookieValues, setFrameworkSessionCookie, setFirstRunOnboardingCookie, clearFrameworkSessionCookies, runAuthGuard, registerDesktopExchange, prepareDesktopOAuthBrowserBinding, matchesDesktopOAuthBrowserBinding, DESKTOP_OAUTH_BROWSER_BINDING_COOKIE, setDesktopExchange, setDesktopExchangeError, safeReturnPath, } from "./auth.js";
|
|
19
|
+
export { mountAuthMiddleware, autoMountAuth, registerAuthPublicPaths, recordBuilderSignupBinding, getSession, getBrowserCookieSession, isSessionResolutionUnavailable, getMcpOAuthBearerSession, logout, COOKIE_NAME, addSession, removeSession, getSessionEmail, getFrameworkSessionCookieValues, setFrameworkSessionCookie, setFirstRunOnboardingCookie, clearFrameworkSessionCookies, runAuthGuard, registerDesktopExchange, prepareDesktopOAuthBrowserBinding, matchesDesktopOAuthBrowserBinding, DESKTOP_OAUTH_BROWSER_BINDING_COOKIE, setDesktopExchange, setDesktopExchangeError, safeReturnPath, } from "./auth.js";
|
|
20
20
|
export { hasSameOriginBrowserEvidence } from "./request-origin.js";
|
|
21
21
|
export { getEmbedSessionOrigin } from "./embed-request-origin.js";
|
|
22
22
|
export { handleIdentitySso, ensureIdentityUser, getIdentityHubUrl, isIdentitySsoEnabled, isIdentitySsoBypassPath, identitySsoLoginButtonHtml, IDENTITY_SSO_BOOTSTRAP_ACTIVATE_PATH, IDENTITY_SSO_BOOTSTRAP_BINDING_COOKIE, clearIdentitySsoBootstrapBindingCookie, getIdentitySsoBootstrapBindingCookie, setIdentitySsoBootstrapBindingCookie, IDENTITY_SSO_PROVIDER_ID, IDENTITY_SSO_SCOPE, IDENTITY_SSO_DESKTOP_COMPLETE_PATH, } from "./identity-sso.js";
|
|
@@ -39,6 +39,7 @@ export { callerHasThreadAccess } from "../agent/run-ownership.js";
|
|
|
39
39
|
export { abortTurnByRefDurably, getActiveRunForThreadAsync, } from "../agent/run-manager.js";
|
|
40
40
|
export { mountRealtimeVoiceRoutes, realtimeVoiceSafetyIdentifier, REALTIME_VOICE_MAX_SDP_BYTES, REALTIME_VOICE_MAX_TOOL_BODY_BYTES, REALTIME_VOICE_MAX_TOOL_OUTPUT_CHARS, REALTIME_VOICE_SESSION_PATH, REALTIME_VOICE_TOOL_PATH, } from "./realtime-voice.js";
|
|
41
41
|
export { getStoredModelForEngine, resolveEngine, } from "../agent/engine/index.js";
|
|
42
|
+
export { resolveChatModelAvailability, } from "../agent/engine/chat-model-availability.js";
|
|
42
43
|
export { completeText, } from "./complete-text.js";
|
|
43
44
|
export { createDevScriptRegistry } from "../scripts/dev/index.js";
|
|
44
45
|
export { createPollHandler, recordChange, prepareTransactionalChange, getVersion, getChangesSince, getCurrentPollBaseline, getPollEmitter, canSeeChangeForUser, POLL_CHANGE_EVENT, } from "./poll.js";
|
|
@@ -33,6 +33,8 @@ export interface OnboardingHtmlOptions {
|
|
|
33
33
|
signupLegalNotice?: SignupLegalNoticeOptions | false;
|
|
34
34
|
googleAuthMode?: GoogleAuthMode;
|
|
35
35
|
renderSignInPage?: (props: AuthPageProps) => string | undefined;
|
|
36
|
+
/** Trusted HTML appended to the sign-in document head. */
|
|
37
|
+
authHeadHtml?: string;
|
|
36
38
|
}
|
|
37
39
|
export declare function getOnboardingHtml(opts?: OnboardingHtmlOptions): string;
|
|
38
40
|
export declare function getResetPasswordHtml(requestPath?: string, renderResetPasswordPage?: (props: ResetPasswordPageProps) => string | undefined): string;
|
|
@@ -2129,6 +2129,10 @@ export function getOnboardingHtml(opts = {}) {
|
|
|
2129
2129
|
bottom: max(1.25rem, env(safe-area-inset-bottom));
|
|
2130
2130
|
inset-inline-end: max(1.25rem, env(safe-area-inset-right));
|
|
2131
2131
|
}
|
|
2132
|
+
body.has-marketing .locale-menu {
|
|
2133
|
+
top: auto;
|
|
2134
|
+
bottom: calc(100% + 0.375rem);
|
|
2135
|
+
}
|
|
2132
2136
|
@media (prefers-color-scheme: light) {
|
|
2133
2137
|
body.has-marketing {
|
|
2134
2138
|
--auth-marketing-border: color-mix(in srgb, var(--auth-marketing-foreground) 18%, transparent);
|
|
@@ -2185,7 +2189,7 @@ export function getOnboardingHtml(opts = {}) {
|
|
|
2185
2189
|
padding: max(1.5rem, env(safe-area-inset-top)) 1.25rem max(1.5rem, env(safe-area-inset-bottom));
|
|
2186
2190
|
border-inline-start: 0;
|
|
2187
2191
|
}
|
|
2188
|
-
.auth-marketing-home .marketing-panel {
|
|
2192
|
+
.auth-marketing-home .marketing-panel { order: 2; min-height: 0; }
|
|
2189
2193
|
.auth-marketing-home .card h1 {
|
|
2190
2194
|
font-size: clamp(1.625rem, 6vw, 2rem);
|
|
2191
2195
|
line-height: 1.15;
|
|
@@ -2211,9 +2215,9 @@ export function getOnboardingHtml(opts = {}) {
|
|
|
2211
2215
|
}
|
|
2212
2216
|
`;
|
|
2213
2217
|
const authClientScriptPath = authClientAssetPath(appBasePath);
|
|
2214
|
-
const title =
|
|
2215
|
-
? `${marketing.appName} — ${
|
|
2216
|
-
:
|
|
2218
|
+
const title = marketing && !simplifiedAuth
|
|
2219
|
+
? `${marketing.appName} — ${EN_AUTH_COPY.pageTitleSignIn}`
|
|
2220
|
+
: EN_AUTH_COPY.pageTitleWelcome;
|
|
2217
2221
|
const authPageMarkup = opts.renderSignInPage?.(authPageProps);
|
|
2218
2222
|
const fallbackTitle = googleOnly
|
|
2219
2223
|
? t("pageTitleSignIn")
|
|
@@ -2254,7 +2258,7 @@ export function getOnboardingHtml(opts = {}) {
|
|
|
2254
2258
|
: hasMarketing
|
|
2255
2259
|
? "has-marketing"
|
|
2256
2260
|
: "";
|
|
2257
|
-
return `<!DOCTYPE html><html lang="${DEFAULT_LOCALE}" dir="ltr"><head><meta charset="UTF-8"/><script data-agent-native-locale-init="">${localeInitScript}</script><script data-agent-native-embedded-init="">${embeddedAuthInitScript}</script><meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no"/>${fontLinks}<title>${escapeHtml(title)}</title><link rel="icon" type="image/svg+xml" href="${escapeHtml(withAppBasePath("/favicon.svg", appBasePath))}"/><link rel="apple-touch-icon" href="${escapeHtml(withAppBasePath("/icon-180.svg", appBasePath))}"/>${marketingMeta}<style>${authDocumentStyles + authPageLayoutStyles}</style
|
|
2261
|
+
return `<!DOCTYPE html><html lang="${DEFAULT_LOCALE}" dir="ltr"><head><meta charset="UTF-8"/><script data-agent-native-locale-init="">${localeInitScript}</script><script data-agent-native-embedded-init="">${embeddedAuthInitScript}</script><meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no"/>${fontLinks}<title>${escapeHtml(title)}</title><link rel="icon" type="image/svg+xml" href="${escapeHtml(withAppBasePath("/favicon.svg", appBasePath))}"/><link rel="apple-touch-icon" href="${escapeHtml(withAppBasePath("/icon-180.svg", appBasePath))}"/>${marketingMeta}<style>${authDocumentStyles + authPageLayoutStyles}</style>${opts.authHeadHtml ?? ""}<script type="module" src="${escapeHtml(authClientScriptPath)}"></script></head><body${bodyClass ? ` class="${bodyClass}"` : ""}><div id="agent-native-auth-root" class="auth-root"${authPageMarkup === undefined ? ' data-agent-native-auth-fallback="true"' : ""}>${pageMarkup}</div><script type="application/json" id="agent-native-auth-data">${authPageData}</script></body></html>`;
|
|
2258
2262
|
}
|
|
2259
2263
|
const RESET_PASSWORD_STYLES = `
|
|
2260
2264
|
/* guard:allow-raw-color - standalone reset page has no app theme token layer */
|
|
@@ -11,21 +11,23 @@ import { runFrameworkSchemaEnsures } from "./release-schema.js";
|
|
|
11
11
|
* still reports success — `Applied migration ...` lines, a zero exit, a
|
|
12
12
|
* published deploy — so this has to fail here or it fails silently forever.
|
|
13
13
|
*
|
|
14
|
-
*
|
|
14
|
+
* Explicit production commands always require a PostgreSQL target. Other callers
|
|
15
|
+
* are scoped to `CONTEXT=production`: the beta lane deliberately builds
|
|
15
16
|
* with `AGENT_NATIVE_RUN_RELEASE_MIGRATIONS=1` under a branch-deploy context
|
|
16
17
|
* against masked site secrets, and its database is migrated by the beta
|
|
17
18
|
* publish step — so keying off that flag would fail every beta deploy while
|
|
18
19
|
* never guarding the production one this exists for.
|
|
19
20
|
*/
|
|
20
|
-
function assertReleaseMigrationTargetsRemoteDatabase() {
|
|
21
|
-
if (
|
|
21
|
+
function assertReleaseMigrationTargetsRemoteDatabase(requirePostgres) {
|
|
22
|
+
if (!requirePostgres &&
|
|
23
|
+
getAppConfig().migration.deployContext !== "production")
|
|
22
24
|
return;
|
|
23
25
|
const url = getDatabaseUrl();
|
|
24
26
|
// `isLocalDatabase()` alone is not enough. Netlify hands the CLI a MASKED
|
|
25
27
|
// secret ("****************uire") outside its own build infra, and that is
|
|
26
28
|
// neither empty nor a local URL — so it reads as "not local" while being
|
|
27
29
|
// unconnectable. Require a real remote scheme too.
|
|
28
|
-
if (
|
|
30
|
+
if (/^postgres(?:ql)?:\/\//i.test(url))
|
|
29
31
|
return;
|
|
30
32
|
throw new Error(`Release migrations resolved to an unusable database (${describeReleaseMigrationUrl(url)}). ` +
|
|
31
33
|
"In a production deploy the schema must be applied to the same remote " +
|
|
@@ -50,7 +52,7 @@ function shouldLogReleaseTiming() {
|
|
|
50
52
|
process.env.VITEST !== "true" &&
|
|
51
53
|
process.env.VITEST !== "1");
|
|
52
54
|
}
|
|
53
|
-
export async function runFrameworkReleaseMigrations(_nitroApp) {
|
|
55
|
+
export async function runFrameworkReleaseMigrations(_nitroApp, options = {}) {
|
|
54
56
|
const logTiming = shouldLogReleaseTiming();
|
|
55
57
|
const startedAt = Date.now();
|
|
56
58
|
if (logTiming) {
|
|
@@ -58,7 +60,7 @@ export async function runFrameworkReleaseMigrations(_nitroApp) {
|
|
|
58
60
|
}
|
|
59
61
|
let lockWaitMs;
|
|
60
62
|
try {
|
|
61
|
-
assertReleaseMigrationTargetsRemoteDatabase();
|
|
63
|
+
assertReleaseMigrationTargetsRemoteDatabase(options.requirePostgres === true);
|
|
62
64
|
// One lease for the whole release, so two deploys against one database
|
|
63
65
|
// never interleave.
|
|
64
66
|
await withStoreMigrationLock(async () => {
|
|
@@ -164,8 +164,14 @@ const STATIC_ASSET_PATTERNS = [
|
|
|
164
164
|
"/favicon.ico",
|
|
165
165
|
"/favicon.svg",
|
|
166
166
|
"/manifest.json",
|
|
167
|
-
"/icon
|
|
168
|
-
"/
|
|
167
|
+
"/icon-180.svg",
|
|
168
|
+
"/icon-192.svg",
|
|
169
|
+
"/icon-512.svg",
|
|
170
|
+
"/agent-native-icon-dark.svg",
|
|
171
|
+
"/agent-native-icon-light.svg",
|
|
172
|
+
"/agent-native-icon-light-512.svg",
|
|
173
|
+
"/agent-native-logo-dark.svg",
|
|
174
|
+
"/agent-native-logo-light.svg",
|
|
169
175
|
"/library-presets/**",
|
|
170
176
|
];
|
|
171
177
|
function normalizeBasePath(basePath) {
|
|
@@ -41,7 +41,7 @@
|
|
|
41
41
|
-Choose the primary workflow and route before editing. Add a domain route under `app/routes/` and set `app.homePath` in `server/plugins/agent-native-email-branding.ts` with `defineAppConfig`. The default Get started page lives at `/home`, and Chat stays at `/chat`; edit `app/routes/home.tsx` when replacing that page with a domain-specific home. Add a static link in `app/components/layout/Sidebar.tsx` before `ChatThreadsSection`; `Header.tsx` uses `APP_TITLE` elsewhere. Shared sidebar and AgentInspector remain.
|
|
42
42
|
+Choose the primary workflow and route before editing. Build on the blank canvas in `app/routes/_index.tsx` or add domain routes under `app/routes/`. This starter has no Chat route, sidebar, header, or agent rail; add only the navigation the product needs. Set `app.homePath` in the existing `defineAppConfig` in `server/plugins/config.ts` as `DEVELOPING.md` describes.
|
|
43
43
|
|
|
44
|
-
-Use `adding-a-feature` for functional parity and `frontend-design` for a user-facing screen. Keep feature guidance here; do not rewrite `README.md` or `DESIGN.md`. After all edits, run one typecheck, one doctor check, and one browser smoke of the primary workflow
|
|
44
|
+
-Use `adding-a-feature` for functional parity and `frontend-design` for a user-facing screen. Keep feature guidance here; do not rewrite `README.md` or `DESIGN.md`. After all edits, run one typecheck, one doctor check, and one browser smoke of the primary workflow and its authenticated landing. Skip production build and extra test suites.
|
|
45
45
|
+Use `adding-a-feature` for functional parity and `frontend-design` for a user-facing screen. Keep feature guidance here and update `README.md` as `DEVELOPING.md` describes. After all edits, run one typecheck, one doctor check, and one browser smoke of the primary workflow and its authenticated landing. Skip production build and extra test suites.
|
|
46
46
|
|
|
47
47
|
Before building common workspace or agent UI, read `agent-native-toolkit`; for supported customization, read `customizing-agent-native`.
|
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
===================================================================
|
|
2
2
|
--- a/server/plugins/auth.ts
|
|
3
3
|
+++ b/server/plugins/auth.ts
|
|
4
|
-
@@ -1,
|
|
4
|
+
@@ -1,8 +1,8 @@
|
|
5
5
|
-import { createToolkitAuthPlugin } from "@agent-native/toolkit/app/auth/server";
|
|
6
6
|
+import { createAuthPlugin } from "@agent-native/core/server";
|
|
7
7
|
|
|
8
8
|
-export default createToolkitAuthPlugin({
|
|
9
9
|
- workspaceAppPublicPaths: ["/"],
|
|
10
10
|
- rootAuth: true,
|
|
11
|
+
- // Remove this option to use built-in marketing, or supply an object for custom copy.
|
|
11
12
|
- marketing: false,
|
|
12
13
|
+// Email/password auth with optional Google OAuth (enabled automatically when
|
|
13
14
|
+// GOOGLE_CLIENT_ID and GOOGLE_CLIENT_SECRET are set). No marketing copy — a
|
|
@@ -26,6 +26,6 @@ For custom branding, keep `server/plugins/agent-native-email-branding.ts` aligne
|
|
|
26
26
|
|
|
27
27
|
Choose the primary workflow and route before editing. Add a domain route under `app/routes/` and set `app.homePath` in `server/plugins/agent-native-email-branding.ts` with `defineAppConfig`. The default Get started page lives at `/home`, and Chat stays at `/chat`; edit `app/routes/home.tsx` when replacing that page with a domain-specific home. Add a static link in `app/components/layout/Sidebar.tsx` before `ChatThreadsSection`; `Header.tsx` uses `APP_TITLE` elsewhere. Shared sidebar and AgentInspector remain.
|
|
28
28
|
|
|
29
|
-
Use `adding-a-feature` for functional parity and `frontend-design` for a user-facing screen. Keep feature guidance here; do not rewrite `README.md` or `DESIGN.md`. After all edits, run one typecheck, one doctor check, and one browser smoke of the primary workflow
|
|
29
|
+
Use `adding-a-feature` for functional parity and `frontend-design` for a user-facing screen. Keep feature guidance here; do not rewrite `README.md` or `DESIGN.md`. After all edits, run one typecheck, one doctor check, and one browser smoke of the primary workflow and its authenticated landing. Skip production build and extra test suites.
|
|
30
30
|
|
|
31
31
|
Before building common workspace or agent UI, read `agent-native-toolkit`; for supported customization, read `customizing-agent-native`.
|
|
@@ -403,7 +403,7 @@ export function Sidebar({
|
|
|
403
403
|
<nav
|
|
404
404
|
aria-label={t("navigation.navigation")}
|
|
405
405
|
className={cn(
|
|
406
|
-
"flex min-h-0 flex-1 flex-col",
|
|
406
|
+
"flex min-h-0 flex-1 flex-col overflow-y-auto",
|
|
407
407
|
collapsed ? "items-center gap-1 px-1 py-2" : "pt-1",
|
|
408
408
|
)}
|
|
409
409
|
>
|
|
@@ -9,7 +9,7 @@ loadEnv();
|
|
|
9
9
|
|
|
10
10
|
async function main(): Promise<void> {
|
|
11
11
|
await withMigrationRuntime(async () => {
|
|
12
|
-
await runFrameworkReleaseMigrations(null);
|
|
12
|
+
await runFrameworkReleaseMigrations(null, { requirePostgres: true });
|
|
13
13
|
await runAppReleaseMigrations();
|
|
14
14
|
});
|
|
15
15
|
}
|
|
@@ -3,5 +3,6 @@ import { createToolkitAuthPlugin } from "@agent-native/toolkit/app/auth/server";
|
|
|
3
3
|
export default createToolkitAuthPlugin({
|
|
4
4
|
workspaceAppPublicPaths: ["/"],
|
|
5
5
|
rootAuth: true,
|
|
6
|
+
// Remove this option to use built-in marketing, or supply an object for custom copy.
|
|
6
7
|
marketing: false,
|
|
7
8
|
});
|
|
@@ -2,47 +2,6 @@ overrides:
|
|
|
2
2
|
"@assistant-ui/store": ">=0.2.9 <0.2.14"
|
|
3
3
|
"@assistant-ui/tap": "^0.5.14"
|
|
4
4
|
nf3: "0.3.17"
|
|
5
|
-
"@tiptap/core": "3.28.0"
|
|
6
|
-
"@tiptap/extension-blockquote": "3.28.0"
|
|
7
|
-
"@tiptap/extension-bold": "3.28.0"
|
|
8
|
-
"@tiptap/extension-bubble-menu": "3.28.0"
|
|
9
|
-
"@tiptap/extension-bullet-list": "3.28.0"
|
|
10
|
-
"@tiptap/extension-code": "3.28.0"
|
|
11
|
-
"@tiptap/extension-code-block": "3.28.0"
|
|
12
|
-
"@tiptap/extension-code-block-lowlight": "3.28.0"
|
|
13
|
-
"@tiptap/extension-collaboration": "3.28.0"
|
|
14
|
-
"@tiptap/extension-collaboration-caret": "3.28.0"
|
|
15
|
-
"@tiptap/extension-color": "3.28.0"
|
|
16
|
-
"@tiptap/extension-document": "3.28.0"
|
|
17
|
-
"@tiptap/extension-dropcursor": "3.28.0"
|
|
18
|
-
"@tiptap/extension-floating-menu": "3.28.0"
|
|
19
|
-
"@tiptap/extension-gapcursor": "3.28.0"
|
|
20
|
-
"@tiptap/extension-hard-break": "3.28.0"
|
|
21
|
-
"@tiptap/extension-heading": "3.28.0"
|
|
22
|
-
"@tiptap/extension-horizontal-rule": "3.28.0"
|
|
23
|
-
"@tiptap/extension-image": "3.28.0"
|
|
24
|
-
"@tiptap/extension-italic": "3.28.0"
|
|
25
|
-
"@tiptap/extension-link": "3.28.0"
|
|
26
|
-
"@tiptap/extension-list": "3.28.0"
|
|
27
|
-
"@tiptap/extension-list-item": "3.28.0"
|
|
28
|
-
"@tiptap/extension-list-keymap": "3.28.0"
|
|
29
|
-
"@tiptap/extension-ordered-list": "3.28.0"
|
|
30
|
-
"@tiptap/extension-paragraph": "3.28.0"
|
|
31
|
-
"@tiptap/extension-placeholder": "3.28.0"
|
|
32
|
-
"@tiptap/extension-strike": "3.28.0"
|
|
33
|
-
"@tiptap/extension-table": "3.28.0"
|
|
34
|
-
"@tiptap/extension-table-cell": "3.28.0"
|
|
35
|
-
"@tiptap/extension-table-header": "3.28.0"
|
|
36
|
-
"@tiptap/extension-table-row": "3.28.0"
|
|
37
|
-
"@tiptap/extension-task-item": "3.28.0"
|
|
38
|
-
"@tiptap/extension-task-list": "3.28.0"
|
|
39
|
-
"@tiptap/extension-text": "3.28.0"
|
|
40
|
-
"@tiptap/extension-text-style": "3.28.0"
|
|
41
|
-
"@tiptap/extension-underline": "3.28.0"
|
|
42
|
-
"@tiptap/extensions": "3.28.0"
|
|
43
|
-
"@tiptap/pm": "3.28.0"
|
|
44
|
-
"@tiptap/react": "3.28.0"
|
|
45
|
-
"@tiptap/starter-kit": "3.28.0"
|
|
46
5
|
|
|
47
6
|
allowBuilds:
|
|
48
7
|
esbuild: true
|
|
@@ -9,7 +9,7 @@ loadEnv();
|
|
|
9
9
|
|
|
10
10
|
async function main(): Promise<void> {
|
|
11
11
|
await withMigrationRuntime(async () => {
|
|
12
|
-
await runFrameworkReleaseMigrations(null);
|
|
12
|
+
await runFrameworkReleaseMigrations(null, { requirePostgres: true });
|
|
13
13
|
await runAppReleaseMigrations();
|
|
14
14
|
});
|
|
15
15
|
}
|
|
@@ -27,47 +27,6 @@ overrides:
|
|
|
27
27
|
esbuild: "^0.28.1"
|
|
28
28
|
srvx: "^0.12.4"
|
|
29
29
|
zod: "^4.4.3"
|
|
30
|
-
"@tiptap/core": "3.28.0"
|
|
31
|
-
"@tiptap/extension-blockquote": "3.28.0"
|
|
32
|
-
"@tiptap/extension-bold": "3.28.0"
|
|
33
|
-
"@tiptap/extension-bubble-menu": "3.28.0"
|
|
34
|
-
"@tiptap/extension-bullet-list": "3.28.0"
|
|
35
|
-
"@tiptap/extension-code": "3.28.0"
|
|
36
|
-
"@tiptap/extension-code-block": "3.28.0"
|
|
37
|
-
"@tiptap/extension-code-block-lowlight": "3.28.0"
|
|
38
|
-
"@tiptap/extension-collaboration": "3.28.0"
|
|
39
|
-
"@tiptap/extension-collaboration-caret": "3.28.0"
|
|
40
|
-
"@tiptap/extension-color": "3.28.0"
|
|
41
|
-
"@tiptap/extension-document": "3.28.0"
|
|
42
|
-
"@tiptap/extension-dropcursor": "3.28.0"
|
|
43
|
-
"@tiptap/extension-floating-menu": "3.28.0"
|
|
44
|
-
"@tiptap/extension-gapcursor": "3.28.0"
|
|
45
|
-
"@tiptap/extension-hard-break": "3.28.0"
|
|
46
|
-
"@tiptap/extension-heading": "3.28.0"
|
|
47
|
-
"@tiptap/extension-horizontal-rule": "3.28.0"
|
|
48
|
-
"@tiptap/extension-image": "3.28.0"
|
|
49
|
-
"@tiptap/extension-italic": "3.28.0"
|
|
50
|
-
"@tiptap/extension-link": "3.28.0"
|
|
51
|
-
"@tiptap/extension-list": "3.28.0"
|
|
52
|
-
"@tiptap/extension-list-item": "3.28.0"
|
|
53
|
-
"@tiptap/extension-list-keymap": "3.28.0"
|
|
54
|
-
"@tiptap/extension-ordered-list": "3.28.0"
|
|
55
|
-
"@tiptap/extension-paragraph": "3.28.0"
|
|
56
|
-
"@tiptap/extension-placeholder": "3.28.0"
|
|
57
|
-
"@tiptap/extension-strike": "3.28.0"
|
|
58
|
-
"@tiptap/extension-table": "3.28.0"
|
|
59
|
-
"@tiptap/extension-table-cell": "3.28.0"
|
|
60
|
-
"@tiptap/extension-table-header": "3.28.0"
|
|
61
|
-
"@tiptap/extension-table-row": "3.28.0"
|
|
62
|
-
"@tiptap/extension-task-item": "3.28.0"
|
|
63
|
-
"@tiptap/extension-task-list": "3.28.0"
|
|
64
|
-
"@tiptap/extension-text": "3.28.0"
|
|
65
|
-
"@tiptap/extension-text-style": "3.28.0"
|
|
66
|
-
"@tiptap/extension-underline": "3.28.0"
|
|
67
|
-
"@tiptap/extensions": "3.28.0"
|
|
68
|
-
"@tiptap/pm": "3.28.0"
|
|
69
|
-
"@tiptap/react": "3.28.0"
|
|
70
|
-
"@tiptap/starter-kit": "3.28.0"
|
|
71
30
|
|
|
72
31
|
packageExtensions:
|
|
73
32
|
"node-pty@*":
|
|
@@ -14,12 +14,17 @@ const MAX_BATCH_SIZE = 50;
|
|
|
14
14
|
const SEND_TIMEOUT_MS = 10_000;
|
|
15
15
|
const QUEUE_KEY = Symbol.for("@agent-native/core/tracking.queue");
|
|
16
16
|
const TIMER_KEY = Symbol.for("@agent-native/core/tracking.timer");
|
|
17
|
+
const IN_FLIGHT_KEY = Symbol.for("@agent-native/core/tracking.in-flight");
|
|
17
18
|
function getQueue() {
|
|
18
19
|
const g = globalThis;
|
|
19
20
|
if (!g[QUEUE_KEY])
|
|
20
21
|
g[QUEUE_KEY] = [];
|
|
21
22
|
return g[QUEUE_KEY];
|
|
22
23
|
}
|
|
24
|
+
function getInFlight() {
|
|
25
|
+
const global = globalThis;
|
|
26
|
+
return (global[IN_FLIGHT_KEY] ??= new Set());
|
|
27
|
+
}
|
|
23
28
|
function getTimer() {
|
|
24
29
|
const g = globalThis;
|
|
25
30
|
return g[TIMER_KEY] ?? null;
|
|
@@ -51,14 +56,21 @@ function drainQueue() {
|
|
|
51
56
|
}
|
|
52
57
|
const queue = getQueue();
|
|
53
58
|
const batch = queue.splice(0, queue.length);
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
59
|
+
const inFlight = getInFlight();
|
|
60
|
+
for (const item of batch) {
|
|
61
|
+
// Whichever call's frame drains the queue, the events are not its writes.
|
|
62
|
+
const send = withoutWriteObservation(() => fetch(item.url, {
|
|
63
|
+
method: "POST",
|
|
64
|
+
headers: { "Content-Type": "application/json", ...item.headers },
|
|
65
|
+
body: item.body,
|
|
66
|
+
signal: AbortSignal.timeout(SEND_TIMEOUT_MS),
|
|
67
|
+
})).then(() => undefined, () => undefined);
|
|
68
|
+
inFlight.add(send);
|
|
69
|
+
void send.finally(() => inFlight.delete(send));
|
|
70
|
+
}
|
|
71
|
+
// Serverless sends leave the queue immediately. A later flush must still
|
|
72
|
+
// hold the request's background lifetime until those sends settle.
|
|
73
|
+
return Promise.all([...inFlight]);
|
|
62
74
|
}
|
|
63
75
|
function isLocalhostUrl(value) {
|
|
64
76
|
if (!value || !value.trim())
|
|
@@ -3,6 +3,7 @@ import { defineAction } from "../../action.js";
|
|
|
3
3
|
import { listAccessibleAutomationDefinitions, } from "../../automations/service.js";
|
|
4
4
|
import { hasStalePause, isPausedByFramework, } from "../../jobs/automation-outcome.js";
|
|
5
5
|
import { describeCron, effectiveTimezone, isValidCron, nextOccurrence, } from "../../jobs/cron.js";
|
|
6
|
+
import { isRecoveredFactoryJob, jobBelongsToApp, } from "../../jobs/frontmatter.js";
|
|
6
7
|
import { listLatestAutomationRuns } from "../../jobs/run-history.js";
|
|
7
8
|
function nextRun(meta) {
|
|
8
9
|
if (!meta.enabled)
|
|
@@ -111,7 +112,12 @@ export default defineAction({
|
|
|
111
112
|
deliveryTenantId: meta.deliveryTenantId ?? null,
|
|
112
113
|
canUpdate,
|
|
113
114
|
effectiveRole,
|
|
114
|
-
capabilities
|
|
115
|
+
capabilities: {
|
|
116
|
+
...capabilities,
|
|
117
|
+
canOperate: capabilities.canOperate &&
|
|
118
|
+
(jobBelongsToApp(meta, ctx.appId) ||
|
|
119
|
+
isRecoveredFactoryJob(meta, resource.path, ctx.appId, resource.owner)),
|
|
120
|
+
},
|
|
115
121
|
sharing,
|
|
116
122
|
creator,
|
|
117
123
|
};
|