@agent-native/core 0.157.11 → 0.157.13

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.
@@ -1,7 +1,4 @@
1
1
  import { getDbExec } from "@agent-native/core/db";
2
- import { and, eq, gte, isNull, ne, or } from "drizzle-orm";
3
-
4
- import { getDb, schema } from "../db/index.js";
5
2
 
6
3
  export interface FirstPartyAnalyticsPurgeScope {
7
4
  userEmail: string;
@@ -19,34 +16,6 @@ export interface FirstPartyAnalyticsPurgeWindow {
19
16
  startEventDate: string;
20
17
  }
21
18
 
22
- function scopePredicate(
23
- table: {
24
- orgId: any;
25
- ownerEmail: any;
26
- },
27
- scope: FirstPartyAnalyticsPurgeScope,
28
- includeLegacyOwnerRows: boolean,
29
- ) {
30
- if (!includeLegacyOwnerRows) return eq(table.orgId, scope.orgId);
31
- return or(
32
- eq(table.orgId, scope.orgId),
33
- and(isNull(table.orgId), eq(table.ownerEmail, scope.userEmail)),
34
- );
35
- }
36
-
37
- function windowPredicate(
38
- table: {
39
- eventDate: any;
40
- receivedAt?: any;
41
- },
42
- predicate: any,
43
- window: FirstPartyAnalyticsPurgeWindow,
44
- ) {
45
- return table.receivedAt
46
- ? and(predicate, gte(table.receivedAt, window.startReceivedAt))
47
- : and(predicate, gte(table.eventDate, window.startEventDate));
48
- }
49
-
50
19
  type CountTable =
51
20
  | "analytics_events"
52
21
  | "analytics_event_daily_rollups"
@@ -54,6 +23,40 @@ type CountTable =
54
23
 
55
24
  type CountTimeColumn = "received_at" | "event_date";
56
25
 
26
+ const PURGE_BATCH_SIZE = 10_000;
27
+ const PURGE_BATCH_TIMEOUT_MS = 60_000;
28
+ const PURGE_COUNT_TIMEOUT_MS = 60_000;
29
+
30
+ function purgeWhereSql(
31
+ table: CountTable,
32
+ scope: FirstPartyAnalyticsPurgeScope,
33
+ includeLegacyOwnerRows: boolean,
34
+ window: FirstPartyAnalyticsPurgeWindow,
35
+ ): { sql: string; args: unknown[]; timeColumn: CountTimeColumn } {
36
+ const scopeSql = includeLegacyOwnerRows
37
+ ? "(org_id = ? OR (org_id IS NULL AND owner_email = ?))"
38
+ : "org_id = ?";
39
+ const args: unknown[] = includeLegacyOwnerRows
40
+ ? [scope.orgId, scope.userEmail]
41
+ : [scope.orgId];
42
+ const timeColumn =
43
+ table === "analytics_events" ? "received_at" : "event_date";
44
+ args.push(
45
+ timeColumn === "received_at"
46
+ ? window.startReceivedAt
47
+ : window.startEventDate,
48
+ );
49
+ const eventFilter =
50
+ table === "analytics_events"
51
+ ? " AND event_name IS DISTINCT FROM 'http.response'"
52
+ : "";
53
+ return {
54
+ sql: `${scopeSql}${eventFilter} AND ${timeColumn} >= ?`,
55
+ args,
56
+ timeColumn,
57
+ };
58
+ }
59
+
57
60
  async function countScopedRows(
58
61
  table: CountTable,
59
62
  timeColumn: CountTimeColumn,
@@ -84,7 +87,7 @@ async function countScopedRows(
84
87
  ${eventFilter}
85
88
  AND ${timeColumn} >= ?`,
86
89
  args,
87
- timeoutMs: 5_000,
90
+ timeoutMs: PURGE_COUNT_TIMEOUT_MS,
88
91
  maxAttempts: 1,
89
92
  });
90
93
  const rawCount = (rows[0] as { row_count?: unknown } | undefined)?.row_count;
@@ -136,49 +139,34 @@ export async function purgeFirstPartyAnalyticsPostgresRows(
136
139
  includeLegacyOwnerRows,
137
140
  window,
138
141
  );
139
- await (getDb() as any).transaction(async (tx: any) => {
140
- await tx
141
- .delete(schema.analyticsEvents)
142
- .where(
143
- and(
144
- windowPredicate(
145
- schema.analyticsEvents,
146
- scopePredicate(
147
- schema.analyticsEvents,
148
- scope,
149
- includeLegacyOwnerRows,
150
- ),
151
- window,
152
- ),
153
- ne(schema.analyticsEvents.eventName, "http.response"),
154
- ),
155
- );
156
- await tx
157
- .delete(schema.analyticsEventDailyRollups)
158
- .where(
159
- windowPredicate(
160
- schema.analyticsEventDailyRollups,
161
- scopePredicate(
162
- schema.analyticsEventDailyRollups,
163
- scope,
164
- includeLegacyOwnerRows,
165
- ),
166
- window,
167
- ),
168
- );
169
- await tx
170
- .delete(schema.analyticsUserDays)
171
- .where(
172
- windowPredicate(
173
- schema.analyticsUserDays,
174
- scopePredicate(
175
- schema.analyticsUserDays,
176
- scope,
177
- includeLegacyOwnerRows,
178
- ),
179
- window,
180
- ),
181
- );
182
- });
142
+
143
+ for (const table of [
144
+ "analytics_events",
145
+ "analytics_event_daily_rollups",
146
+ "analytics_user_days",
147
+ ] as const) {
148
+ const {
149
+ sql: whereSql,
150
+ args,
151
+ timeColumn,
152
+ } = purgeWhereSql(table, scope, includeLegacyOwnerRows, window);
153
+ while (true) {
154
+ const result = await getDbExec().execute({
155
+ sql: `WITH candidates AS (
156
+ SELECT id
157
+ FROM ${table}
158
+ WHERE ${whereSql}
159
+ ORDER BY ${timeColumn}, id
160
+ LIMIT ?
161
+ )
162
+ DELETE FROM ${table}
163
+ WHERE id IN (SELECT id FROM candidates)`,
164
+ args: [...args, PURGE_BATCH_SIZE],
165
+ timeoutMs: PURGE_BATCH_TIMEOUT_MS,
166
+ maxAttempts: 1,
167
+ });
168
+ if (Number(result.rowsAffected ?? 0) < PURGE_BATCH_SIZE) break;
169
+ }
170
+ }
183
171
  return counts;
184
172
  }
@@ -1051,7 +1051,7 @@ function importedLineStroke(
1051
1051
  innerHtml: string,
1052
1052
  dims: SlideDims,
1053
1053
  ):
1054
- | Pick<
1054
+ | (Pick<
1055
1055
  ShapeElement,
1056
1056
  | "shapeType"
1057
1057
  | "lineColor"
@@ -1060,7 +1060,8 @@ function importedLineStroke(
1060
1060
  | "lineDashType"
1061
1061
  | "lineHeadType"
1062
1062
  | "lineTailType"
1063
- >
1063
+ > &
1064
+ Partial<Pick<ShapeElement, "w" | "h">>)
1064
1065
  | undefined {
1065
1066
  for (const [property, axis] of Object.entries(SINGLE_EDGE_BORDER_AXES)) {
1066
1067
  const border = parseCssBorder(getStyle(style, property));
@@ -1068,6 +1069,10 @@ function importedLineStroke(
1068
1069
  const color = colorToHex(border.color);
1069
1070
  return {
1070
1071
  shapeType: "line",
1072
+ // A single-edge border is a line in the element's local coordinate
1073
+ // system. Keep its perpendicular dimension collapsed after the box
1074
+ // geometry has been parsed, or a thin rule becomes a diagonal line.
1075
+ ...(axis === "x" ? { h: 0 } : { w: 0 }),
1071
1076
  lineColor: color.hex,
1072
1077
  lineTransparency: color.transparency,
1073
1078
  // The same 0.5pt floor the outline paths use, for the same reason:
@@ -54,6 +54,18 @@ export const DEFAULT_REQUIRED_SCHEMA = [
54
54
  table: "application_state",
55
55
  columns: ["session_id", "key", "value", "updated_at"],
56
56
  },
57
+ {
58
+ table: "integration_remote_devices",
59
+ columns: [
60
+ "id",
61
+ "owner_email",
62
+ "label",
63
+ "device_token_hash",
64
+ "status",
65
+ "created_at",
66
+ "updated_at",
67
+ ],
68
+ },
57
69
  ];
58
70
  function envValue(key) {
59
71
  const value = process.env[key]?.trim();
@@ -52,6 +52,18 @@ const WORKSPACE_APPS_ENV_KEY = "AGENT_NATIVE_WORKSPACE_APPS_JSON";
52
52
  const WORKSPACE_APPS_MANIFEST_DIR = ".agent-native";
53
53
  const WORKSPACE_APPS_MANIFEST_FILE = "workspace-apps.json";
54
54
  const VERCEL_OUTPUT_DIR = ".vercel/output";
55
+ const WORKSPACE_DIRECTORY_ENV_SNIPPET = `
56
+ const directoryOrigin =
57
+ processRef.env.AGENT_NATIVE_ORG_DIRECTORY_URL ||
58
+ processRef.env.WORKSPACE_GATEWAY_URL ||
59
+ processRef.env.APP_URL ||
60
+ processRef.env.URL ||
61
+ processRef.env.DEPLOY_URL ||
62
+ processRef.env.BETTER_AUTH_URL;
63
+ if (directoryOrigin) {
64
+ processRef.env.AGENT_NATIVE_ORG_DIRECTORY_URL = directoryOrigin;
65
+ }
66
+ `;
55
67
  export async function runWorkspaceDeploy(opts = {}) {
56
68
  const workspaceRoot = opts.workspaceRoot ?? findWorkspaceRoot(process.cwd()) ?? process.cwd();
57
69
  const appsDir = path.join(workspaceRoot, "apps");
@@ -149,6 +161,11 @@ function buildOneApp(workspaceRoot, app, preset, execFile, workspaceApps) {
149
161
  VITE_AGENT_NATIVE_WORKSPACE_APP_PUBLIC_PATHS: JSON.stringify(workspaceAppRouteAccess.publicPaths),
150
162
  VITE_AGENT_NATIVE_WORKSPACE_APP_PROTECTED_PATHS: JSON.stringify(workspaceAppRouteAccess.protectedPaths),
151
163
  VITE_AGENT_NATIVE_WORKSPACE_APPS_JSON: JSON.stringify(workspaceApps),
164
+ ...(workspaceGatewayUrl
165
+ ? {
166
+ AGENT_NATIVE_ORG_DIRECTORY_URL: process.env.AGENT_NATIVE_ORG_DIRECTORY_URL || workspaceGatewayUrl,
167
+ }
168
+ : {}),
152
169
  ...(workspaceGatewayUrl
153
170
  ? {
154
171
  WORKSPACE_GATEWAY_URL: process.env.WORKSPACE_GATEWAY_URL || workspaceGatewayUrl,
@@ -670,6 +687,7 @@ function processorPathFromBody(body) {
670
687
  function setBasePathEnv() {
671
688
  const processRef = globalThis.process ??= { env: {} };
672
689
  processRef.env ??= {};
690
+ ${WORKSPACE_DIRECTORY_ENV_SNIPPET}
673
691
  Object.assign(processRef.env, {
674
692
  AGENT_NATIVE_WORKSPACE: "1",
675
693
  AGENT_NATIVE_WORKSPACE_APP_ID: ${JSON.stringify(app)},
@@ -755,6 +773,7 @@ globalThis.${INTEGRATION_RECOVERY_RUNTIME_MARKER} = true;
755
773
  function setBasePathEnv() {
756
774
  const processRef = globalThis.process ??= { env: {} };
757
775
  processRef.env ??= {};
776
+ ${WORKSPACE_DIRECTORY_ENV_SNIPPET}
758
777
  Object.assign(processRef.env, {
759
778
  AGENT_NATIVE_WORKSPACE: "1",
760
779
  AGENT_NATIVE_WORKSPACE_APP_ID: ${JSON.stringify(app)},
@@ -855,6 +874,7 @@ function normalizeBasePathArgs(args) {
855
874
  function setBasePathEnv() {
856
875
  const processRef = globalThis.process ??= { env: {} };
857
876
  processRef.env ??= {};
877
+ ${WORKSPACE_DIRECTORY_ENV_SNIPPET}
858
878
  Object.assign(processRef.env, {
859
879
  AGENT_NATIVE_WORKSPACE: "1",
860
880
  AGENT_NATIVE_WORKSPACE_APP_ID: ${JSON.stringify(app)},
@@ -914,6 +934,7 @@ function patchVercelFunctionEntry(functionDir, app, workspaceApps) {
914
934
  function setBasePathEnv() {
915
935
  const processRef = globalThis.process ??= { env: {} };
916
936
  processRef.env ??= {};
937
+ ${WORKSPACE_DIRECTORY_ENV_SNIPPET}
917
938
  Object.assign(processRef.env, {
918
939
  AGENT_NATIVE_WORKSPACE: "1",
919
940
  AGENT_NATIVE_WORKSPACE_APP_ID: ${JSON.stringify(app)},
@@ -17,11 +17,11 @@ declare const _default: import("../../action.js").ActionDefinition<{
17
17
  id?: undefined;
18
18
  provider?: undefined;
19
19
  } | {
20
- error?: undefined;
21
20
  configured?: undefined;
22
21
  connectPath?: undefined;
23
22
  url: string;
24
23
  id: string;
25
24
  provider: string;
25
+ error?: undefined;
26
26
  }>;
27
27
  export default _default;
@@ -708,12 +708,15 @@ export function createIntegrationsPlugin(options) {
708
708
  // sees the request. Keep the device secret in a dedicated TLS-only
709
709
  // header as a transport fallback; the value is still hashed and looked
710
710
  // up by authenticateRemoteDeviceToken, never persisted raw.
711
- const token = extractBearerToken(getRequestHeader(event, "authorization")) ??
712
- (getRequestHeader(event, "x-agent-native-device-token")?.trim() ||
713
- null);
714
- const device = await authenticateRemoteDeviceToken(token);
715
- if (device)
716
- return device;
711
+ const candidates = [
712
+ getRequestHeader(event, "x-agent-native-device-token")?.trim() || null,
713
+ extractBearerToken(getRequestHeader(event, "authorization")),
714
+ ].filter((token, index, all) => Boolean(token) && all.indexOf(token) === index);
715
+ for (const token of candidates) {
716
+ const device = await authenticateRemoteDeviceToken(token);
717
+ if (device)
718
+ return device;
719
+ }
717
720
  setResponseStatus(event, 401);
718
721
  return null;
719
722
  }
@@ -0,0 +1,9 @@
1
+ import type { MigrationEntry } from "../db/migrations.js";
2
+ /**
3
+ * Remote-device state is read on request paths, so its table must exist before
4
+ * production serverless functions serve requests. The store keeps its local
5
+ * development convergence path for older databases; release migrations own
6
+ * production schema.
7
+ */
8
+ export declare const REMOTE_DEVICE_MIGRATIONS: MigrationEntry[];
9
+ export declare const REMOTE_DEVICE_MIGRATIONS_TABLE = "_remote_device_migrations";
@@ -0,0 +1,59 @@
1
+ /**
2
+ * Remote-device state is read on request paths, so its table must exist before
3
+ * production serverless functions serve requests. The store keeps its local
4
+ * development convergence path for older databases; release migrations own
5
+ * production schema.
6
+ */
7
+ export const REMOTE_DEVICE_MIGRATIONS = [
8
+ {
9
+ version: 1,
10
+ name: "remote-device-table-and-indexes",
11
+ sql: {
12
+ postgres: `
13
+ CREATE TABLE IF NOT EXISTS integration_remote_devices (
14
+ id TEXT PRIMARY KEY,
15
+ owner_email TEXT NOT NULL,
16
+ org_id TEXT,
17
+ label TEXT NOT NULL,
18
+ platform TEXT,
19
+ app_version TEXT,
20
+ host_name TEXT,
21
+ metadata_json TEXT,
22
+ device_token_hash TEXT NOT NULL,
23
+ last_seen_at BIGINT,
24
+ status TEXT NOT NULL,
25
+ revoked_at BIGINT,
26
+ created_at BIGINT NOT NULL,
27
+ updated_at BIGINT NOT NULL
28
+ );
29
+ CREATE UNIQUE INDEX IF NOT EXISTS idx_remote_devices_token_hash
30
+ ON integration_remote_devices (device_token_hash);
31
+ CREATE INDEX IF NOT EXISTS idx_remote_devices_owner
32
+ ON integration_remote_devices (owner_email, org_id);
33
+ `,
34
+ sqlite: `
35
+ CREATE TABLE IF NOT EXISTS integration_remote_devices (
36
+ id TEXT PRIMARY KEY,
37
+ owner_email TEXT NOT NULL,
38
+ org_id TEXT,
39
+ label TEXT NOT NULL,
40
+ platform TEXT,
41
+ app_version TEXT,
42
+ host_name TEXT,
43
+ metadata_json TEXT,
44
+ device_token_hash TEXT NOT NULL,
45
+ last_seen_at INTEGER,
46
+ status TEXT NOT NULL,
47
+ revoked_at INTEGER,
48
+ created_at INTEGER NOT NULL,
49
+ updated_at INTEGER NOT NULL
50
+ );
51
+ CREATE UNIQUE INDEX IF NOT EXISTS idx_remote_devices_token_hash
52
+ ON integration_remote_devices (device_token_hash);
53
+ CREATE INDEX IF NOT EXISTS idx_remote_devices_owner
54
+ ON integration_remote_devices (owner_email, org_id);
55
+ `,
56
+ },
57
+ },
58
+ ];
59
+ export const REMOTE_DEVICE_MIGRATIONS_TABLE = "_remote_device_migrations";
@@ -41,27 +41,27 @@ export declare function createObservabilityHandler(): import("h3").EventHandlerW
41
41
  thumbsUpRate: number;
42
42
  avgEvalScore: number;
43
43
  } | {
44
+ ok?: undefined;
45
+ error?: undefined;
44
46
  summary: import("./types.js").TraceSummary;
45
47
  spans: import("./types.js").TraceSpan[];
46
48
  id?: undefined;
47
- error?: undefined;
48
- ok?: undefined;
49
49
  } | {
50
+ ok?: undefined;
51
+ error?: undefined;
50
52
  summary?: undefined;
51
53
  spans?: undefined;
52
54
  id: string;
53
- error?: undefined;
54
- ok?: undefined;
55
55
  } | {
56
+ ok?: undefined;
56
57
  summary?: undefined;
57
58
  spans?: undefined;
58
59
  id?: undefined;
59
60
  error: any;
60
- ok?: undefined;
61
61
  } | {
62
+ error?: undefined;
62
63
  summary?: undefined;
63
64
  spans?: undefined;
64
65
  id?: undefined;
65
- error?: undefined;
66
66
  ok: boolean;
67
67
  }>>;
@@ -15,6 +15,6 @@ export declare function createProgressHandler(): import("h3").EventHandlerWithFe
15
15
  error: string;
16
16
  ok?: undefined;
17
17
  } | {
18
- ok: boolean;
19
18
  error?: undefined;
19
+ ok: boolean;
20
20
  }>>;
@@ -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;
@@ -34,16 +34,16 @@ export declare function createListSecretsHandler(): import("h3").EventHandlerWit
34
34
  /** POST /_agent-native/secrets/:key — write a secret. */
35
35
  export declare function createWriteSecretHandler(): import("h3").EventHandlerWithFetch<import("h3").EventHandlerRequest, Promise<{
36
36
  error: string;
37
- status?: undefined;
38
37
  ok?: undefined;
38
+ status?: undefined;
39
39
  } | {
40
40
  ok: boolean;
41
41
  status: string;
42
42
  error?: undefined;
43
43
  } | {
44
+ ok?: undefined;
44
45
  error: string;
45
46
  removed?: undefined;
46
- ok?: undefined;
47
47
  } | {
48
48
  ok: boolean;
49
49
  removed: boolean;
@@ -54,9 +54,9 @@ export declare function createWriteSecretHandler(): import("h3").EventHandlerWit
54
54
  * or the current stored value without changing anything.
55
55
  */
56
56
  export declare function createTestSecretHandler(): import("h3").EventHandlerWithFetch<import("h3").EventHandlerRequest, Promise<{
57
+ ok?: undefined;
57
58
  error: string;
58
59
  note?: undefined;
59
- ok?: undefined;
60
60
  } | {
61
61
  ok: boolean;
62
62
  note?: undefined;
@@ -33,7 +33,7 @@ function currentBuildId() {
33
33
  * Actions are exposed as POST by default. Use `http: { method: "GET" }` in
34
34
  * defineAction to expose as GET. Use `http: false` to mark as agent-only.
35
35
  */
36
- import { isLoopbackRequest } from "./auth.js";
36
+ import { isLoopbackRequest, registerAuthPublicPaths } from "./auth.js";
37
37
  import { getH3App } from "./framework-request-handler.js";
38
38
  import { runWithRequestContext } from "./request-context.js";
39
39
  const ROUTE_PREFIX = "/_agent-native/actions";
@@ -245,6 +245,13 @@ export function mountActionRoutes(nitroApp, actions, options) {
245
245
  const method = entry.http?.method ?? "POST";
246
246
  const path = entry.http?.path ?? name;
247
247
  const routePath = `${ROUTE_PREFIX}/${path}`;
248
+ // These two actions authenticate with a scoped A2A bearer rather than a
249
+ // browser session. Let that verifier see the request before the cookie
250
+ // auth guard rejects it; the action route still fails closed on invalid
251
+ // or missing credentials.
252
+ if (name === "list-feature-flags" || name === "set-feature-flag") {
253
+ registerAuthPublicPaths([routePath]);
254
+ }
248
255
  getH3App(nitroApp).use(routePath, defineEventHandler(async (event) => {
249
256
  const reqMethod = getMethod(event);
250
257
  const effectiveMethod = reqMethod === "HEAD" && method === "GET" ? "GET" : reqMethod;
@@ -27,10 +27,10 @@ export declare function resolveAgentEngineApiKeyWriteTarget(event: H3Event, scop
27
27
  export declare function createAgentEngineApiKeyHandler(): import("h3").EventHandlerWithFetch<import("h3").EventHandlerRequest, Promise<{
28
28
  error: any;
29
29
  } | {
30
+ error?: undefined;
30
31
  ok: boolean;
31
32
  key: string;
32
33
  baseUrlKey?: string;
33
34
  scope: AgentEngineApiKeyScope;
34
- error?: undefined;
35
35
  }>>;
36
36
  export {};
@@ -221,6 +221,15 @@ export declare function removeSession(token: string): Promise<void>;
221
221
  * TTL and the only-cache-successes rule.
222
222
  */
223
223
  export declare function getSessionEmail(token: string): Promise<string | null>;
224
+ /**
225
+ * Allow framework routes with their own non-cookie authentication to reach
226
+ * the handler. The handler remains responsible for verifying the credential.
227
+ *
228
+ * This is registered separately from template auth options because framework
229
+ * routes can be mounted after the auth plugin and must also work in custom
230
+ * workspace deployments that do not own a template auth file.
231
+ */
232
+ export declare function registerAuthPublicPaths(paths: readonly string[]): void;
224
233
  export interface DesktopExchangeErrorPayload {
225
234
  message: string;
226
235
  code?: string;
@@ -960,7 +960,31 @@ export async function getSessionEmail(token) {
960
960
  // ---------------------------------------------------------------------------
961
961
  let customGetSession = null;
962
962
  let _authGuardConfig = null;
963
+ const _registeredAuthPublicPaths = new Set();
963
964
  const _genericGoogleOAuthRoutesEnabled = new WeakMap();
965
+ /**
966
+ * Allow framework routes with their own non-cookie authentication to reach
967
+ * the handler. The handler remains responsible for verifying the credential.
968
+ *
969
+ * This is registered separately from template auth options because framework
970
+ * routes can be mounted after the auth plugin and must also work in custom
971
+ * workspace deployments that do not own a template auth file.
972
+ */
973
+ export function registerAuthPublicPaths(paths) {
974
+ for (const path of paths) {
975
+ const normalized = typeof path === "string" ? path.trim() : "";
976
+ if (!normalized.startsWith("/"))
977
+ continue;
978
+ _registeredAuthPublicPaths.add(normalized);
979
+ if (_authGuardConfig &&
980
+ !_authGuardConfig.publicPaths.includes(normalized)) {
981
+ _authGuardConfig.publicPaths.push(normalized);
982
+ }
983
+ }
984
+ }
985
+ function resolveAuthPublicPaths(paths) {
986
+ return [...new Set([...(paths ?? []), ..._registeredAuthPublicPaths])];
987
+ }
964
988
  function getRequestHost(event) {
965
989
  return (getHeader(event, "x-forwarded-host") ??
966
990
  getHeader(event, "host") ??
@@ -2578,7 +2602,7 @@ function getCustomAuthRequiredHtml() {
2578
2602
  // mountBetterAuthRoutes — Better Auth powered auth with backward-compat routes
2579
2603
  // ---------------------------------------------------------------------------
2580
2604
  async function mountBetterAuthRoutes(app, options) {
2581
- const publicPaths = [...(options.publicPaths ?? [])];
2605
+ const publicPaths = resolveAuthPublicPaths(options.publicPaths);
2582
2606
  const workspaceAppAudience = resolveWorkspaceAppAudience(options);
2583
2607
  const workspaceAppRouteAccess = resolveWorkspaceAppRouteAccess(options);
2584
2608
  // The A2A agent card is part of an open protocol — other agents must be
@@ -3811,7 +3835,7 @@ export async function autoMountAuth(app, options = {}) {
3811
3835
  // Reset globals
3812
3836
  customGetSession = null;
3813
3837
  sessionMaxAge = options.maxAge ?? DEFAULT_MAX_AGE;
3814
- const publicPaths = options.publicPaths ?? [];
3838
+ const publicPaths = resolveAuthPublicPaths(options.publicPaths);
3815
3839
  const workspaceAppAudience = resolveWorkspaceAppAudience(options);
3816
3840
  const workspaceAppRouteAccess = resolveWorkspaceAppRouteAccess(options);
3817
3841
  mountAuthCorsMiddleware(app);
@@ -7,7 +7,7 @@ export { createOpenRouteHandler, type OpenRouteOptions } from "./open-route.js";
7
7
  export { createEmbedStartRouteHandler, buildEmbedStartPath, type EmbedStartRouteOptions, } from "./embed-route.js";
8
8
  export { createEmbedSessionTicket, consumeEmbedSessionTicket, normalizeEmbedTargetPath, requestHasEmbedAuthMarker, resolveEmbedSessionFromRequest, setEmbedSessionCookie, signEmbedSessionToken, verifyEmbedSessionToken, type ConsumedEmbedSessionTicket, type ConsumeEmbedSessionTicketOptions, type EmbedSessionTicket, type EmbedSessionTicketInput, type EmbedSessionTokenClaims, type ResolvedEmbedSession, type VerifyEmbedSessionTokenResult, } from "./embed-session.js";
9
9
  export { createSSEHandler, type SSEHandlerOptions } from "./sse.js";
10
- export { mountAuthMiddleware, autoMountAuth, getSession, COOKIE_NAME, addSession, removeSession, getSessionEmail, getFrameworkSessionCookieValues, setFrameworkSessionCookie, clearFrameworkSessionCookies, runAuthGuard, setDesktopExchange, setDesktopExchangeError, safeReturnPath, type DesktopExchangeErrorPayload, type AuthSession, type AuthOptions, } from "./auth.js";
10
+ export { mountAuthMiddleware, autoMountAuth, registerAuthPublicPaths, getSession, COOKIE_NAME, addSession, removeSession, getSessionEmail, getFrameworkSessionCookieValues, setFrameworkSessionCookie, clearFrameworkSessionCookies, runAuthGuard, setDesktopExchange, setDesktopExchangeError, safeReturnPath, type DesktopExchangeErrorPayload, type AuthSession, type AuthOptions, } from "./auth.js";
11
11
  export { handleIdentitySso, getIdentityHubUrl, isIdentitySsoEnabled, isIdentitySsoBypassPath, identitySsoLoginButtonHtml, IDENTITY_SSO_PROVIDER_ID, IDENTITY_SSO_SCOPE, IDENTITY_SSO_DESKTOP_COMPLETE_PATH, } from "./identity-sso.js";
12
12
  export { requireEnvKey, type MissingKeyResponse } from "./missing-key.js";
13
13
  export { assertCurrentRequestUserIsOrgAdmin, currentRequestUserIsOrgAdmin, } from "./org-admin.js";
@@ -7,7 +7,7 @@ export { createOpenRouteHandler } from "./open-route.js";
7
7
  export { createEmbedStartRouteHandler, buildEmbedStartPath, } from "./embed-route.js";
8
8
  export { createEmbedSessionTicket, consumeEmbedSessionTicket, normalizeEmbedTargetPath, requestHasEmbedAuthMarker, resolveEmbedSessionFromRequest, setEmbedSessionCookie, signEmbedSessionToken, verifyEmbedSessionToken, } from "./embed-session.js";
9
9
  export { createSSEHandler } from "./sse.js";
10
- export { mountAuthMiddleware, autoMountAuth, getSession, COOKIE_NAME, addSession, removeSession, getSessionEmail, getFrameworkSessionCookieValues, setFrameworkSessionCookie, clearFrameworkSessionCookies, runAuthGuard, setDesktopExchange, setDesktopExchangeError, safeReturnPath, } from "./auth.js";
10
+ export { mountAuthMiddleware, autoMountAuth, registerAuthPublicPaths, getSession, COOKIE_NAME, addSession, removeSession, getSessionEmail, getFrameworkSessionCookieValues, setFrameworkSessionCookie, clearFrameworkSessionCookies, runAuthGuard, setDesktopExchange, setDesktopExchangeError, safeReturnPath, } from "./auth.js";
11
11
  export { handleIdentitySso, getIdentityHubUrl, isIdentitySsoEnabled, isIdentitySsoBypassPath, identitySsoLoginButtonHtml, IDENTITY_SSO_PROVIDER_ID, IDENTITY_SSO_SCOPE, IDENTITY_SSO_DESKTOP_COMPLETE_PATH, } from "./identity-sso.js";
12
12
  export { requireEnvKey } from "./missing-key.js";
13
13
  export { assertCurrentRequestUserIsOrgAdmin, currentRequestUserIsOrgAdmin, } from "./org-admin.js";
@@ -26,8 +26,8 @@ export declare function createRealtimeTokenHandler(): import("h3").EventHandlerW
26
26
  expiresAt?: undefined;
27
27
  ttlSeconds?: undefined;
28
28
  } | {
29
+ error?: undefined;
29
30
  token: string;
30
31
  expiresAt: string;
31
32
  ttlSeconds: number;
32
- error?: undefined;
33
33
  }>>;
@@ -5,6 +5,7 @@ import { AGENT_RUN_MIGRATIONS, AGENT_RUN_MIGRATIONS_TABLE, } from "../agent/run-
5
5
  import { AGENT_TOOL_APPROVAL_MIGRATIONS, AGENT_TOOL_APPROVAL_MIGRATIONS_TABLE, } from "../agent/tool-approval-migrations.js";
6
6
  import { CHAT_THREAD_SCHEMA_MIGRATIONS, CHAT_THREAD_SCHEMA_MIGRATIONS_TABLE, } from "../chat-threads/schema-migrations.js";
7
7
  import { runMigrations } from "../db/migrations.js";
8
+ import { REMOTE_DEVICE_MIGRATIONS, REMOTE_DEVICE_MIGRATIONS_TABLE, } from "../integrations/remote-device-migrations.js";
8
9
  import { runAutomationRunMigrations } from "../jobs/run-history.js";
9
10
  import { runAutomationSchedulerHealthMigrations } from "../jobs/scheduler-health.js";
10
11
  import { OAUTH_TOKEN_MIGRATIONS, OAUTH_TOKEN_MIGRATIONS_TABLE, } from "../oauth-tokens/migrations.js";
@@ -40,6 +41,9 @@ export async function runFrameworkReleaseMigrations(nitroApp) {
40
41
  table: USAGE_ALERT_MIGRATIONS_TABLE,
41
42
  })(nitroApp);
42
43
  await runMigrations(ORG_MIGRATIONS, { table: "_org_migrations" })(nitroApp);
44
+ await runMigrations(REMOTE_DEVICE_MIGRATIONS, {
45
+ table: REMOTE_DEVICE_MIGRATIONS_TABLE,
46
+ })(nitroApp);
43
47
  await runMigrations(IDENTITY_SSO_MIGRATIONS, {
44
48
  table: "_identity_sso_migrations",
45
49
  })(nitroApp);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agent-native/core",
3
- "version": "0.157.11",
3
+ "version": "0.157.13",
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": {