@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.
- package/corpus/templates/analytics/server/lib/first-party-analytics-purge.ts +64 -76
- package/corpus/templates/slides/actions/export-pptx.ts +7 -2
- package/dist/db/runtime-diagnostics.js +12 -0
- package/dist/deploy/workspace-deploy.js +21 -0
- package/dist/file-upload/actions/upload-image.d.ts +1 -1
- package/dist/integrations/plugin.js +9 -6
- package/dist/integrations/remote-device-migrations.d.ts +9 -0
- package/dist/integrations/remote-device-migrations.js +59 -0
- package/dist/observability/routes.d.ts +6 -6
- package/dist/progress/routes.d.ts +1 -1
- package/dist/resources/handlers.d.ts +1 -1
- package/dist/secrets/routes.d.ts +3 -3
- package/dist/server/action-routes.js +8 -1
- package/dist/server/agent-engine-api-key-route.d.ts +1 -1
- package/dist/server/auth.d.ts +9 -0
- package/dist/server/auth.js +26 -2
- package/dist/server/index.d.ts +1 -1
- package/dist/server/index.js +1 -1
- package/dist/server/realtime-token.d.ts +1 -1
- package/dist/server/release-migrations.js +4 -0
- package/package.json +1 -1
|
@@ -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:
|
|
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
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
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
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
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
|
}>>;
|
|
@@ -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/secrets/routes.d.ts
CHANGED
|
@@ -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 {};
|
package/dist/server/auth.d.ts
CHANGED
|
@@ -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;
|
package/dist/server/auth.js
CHANGED
|
@@ -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 =
|
|
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);
|
package/dist/server/index.d.ts
CHANGED
|
@@ -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";
|
package/dist/server/index.js
CHANGED
|
@@ -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.
|
|
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": {
|