@agent-native/core 0.209.2 → 0.209.3-nightly-20261016212700
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/a2a-claims.js +5 -5
- package/dist/agent/context-xray/plugin.js +2 -6
- package/dist/agent/context-xray/schema-store.d.ts +1 -0
- package/dist/agent/context-xray/schema-store.js +7 -0
- package/dist/agent/harness/store.js +3 -0
- package/dist/agent/observational-memory/plugin.js +2 -6
- package/dist/agent/observational-memory/store.js +3 -0
- package/dist/agent/run-store.js +3 -0
- package/dist/agent/tool-approval-store.js +4 -0
- package/dist/automation/index.d.ts +1 -1
- package/dist/chat-threads/store.js +3 -0
- package/dist/client/action-query-cache-context.d.ts +1 -0
- package/dist/client/action-query-cache-context.js +2 -0
- package/dist/client/action-query-cache.d.ts +1 -1
- package/dist/client/action-query-cache.js +34 -15
- package/dist/client/motion-text.css +8 -0
- package/dist/client/motion-text.d.ts +6 -0
- package/dist/client/motion-text.js +154 -29
- package/dist/client/use-action.js +18 -1
- package/dist/collab/routes.d.ts +1 -1
- package/dist/db/migrations.d.ts +1 -0
- package/dist/db/migrations.js +1 -1
- package/dist/db/runtime-facts.d.ts +7 -0
- package/dist/db/runtime-facts.js +18 -0
- package/dist/db/schema-catalog.js +4 -1
- package/dist/db/store-ledger.test-helpers.d.ts +5 -0
- package/dist/db/store-ledger.test-helpers.js +19 -0
- package/dist/db/store-registry.d.ts +34 -0
- package/dist/db/store-registry.generated.js +13 -0
- package/dist/db/store-registry.js +288 -46
- package/dist/db/versioned-store-migrations.d.ts +14 -0
- package/dist/db/versioned-store-migrations.js +37 -0
- package/dist/db/widen-columns.js +5 -2
- package/dist/extensions/html-shell.js +67 -0
- package/dist/integrations/remote-devices-store.js +3 -0
- package/dist/jobs/run-history.d.ts +3 -2
- package/dist/jobs/run-history.js +5 -5
- package/dist/jobs/scheduler-health.d.ts +3 -2
- package/dist/jobs/scheduler-health.js +5 -5
- package/dist/mcp/build-server.d.ts +3 -0
- package/dist/mcp/build-server.js +24 -7
- package/dist/mcp/server.js +40 -9
- package/dist/notifications/routes.d.ts +1 -1
- package/dist/oauth-tokens/store.js +3 -0
- package/dist/observability/routes.d.ts +4 -4
- package/dist/observability/store.js +4 -0
- package/dist/org/auto-join-domain.js +23 -15
- package/dist/org/context.d.ts +12 -0
- package/dist/org/context.js +27 -19
- package/dist/org/handlers.js +31 -13
- package/dist/org/index.d.ts +2 -1
- package/dist/org/index.js +1 -0
- package/dist/org/plugin.js +2 -4
- package/dist/org/schema-store.d.ts +1 -0
- package/dist/org/schema-store.js +13 -0
- package/dist/provider-api/actions/custom-provider-registration.d.ts +8 -8
- package/dist/provider-api/actions/provider-api.d.ts +9 -9
- package/dist/resources/store.js +5 -2
- package/dist/server/agent-access.js +2 -6
- package/dist/server/agent-engine-api-key-route.d.ts +1 -1
- package/dist/server/agent-engine-default-model-route.d.ts +1 -1
- package/dist/server/auth-plugin.js +2 -6
- package/dist/server/auth.js +22 -2
- package/dist/server/better-auth-migrations.d.ts +4 -2
- package/dist/server/better-auth-migrations.js +18 -6
- package/dist/server/identity-sso-store.js +3 -0
- package/dist/server/realtime-token.d.ts +1 -1
- package/dist/server/release-migrations.d.ts +1 -1
- package/dist/server/release-migrations.js +3 -65
- package/dist/server/release-schema.js +10 -2
- package/dist/server/short-lived-token.d.ts +3 -2
- package/dist/server/short-lived-token.js +3 -2
- package/dist/triggers/actions/manage-automation.d.ts +3 -3
- package/dist/triggers/event-queue.d.ts +4 -2
- package/dist/triggers/event-queue.js +38 -38
- package/dist/usage/alerts-store.js +3 -0
- package/dist/workspace-connections/groups.js +4 -0
- package/dist/workspace-connections/store.js +3 -0
- package/package.json +3 -3
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import type { MigrationEntry } from "../db/migrations.js";
|
|
2
2
|
export declare const AUTOMATION_SCHEDULER_LEASE_MS: number;
|
|
3
3
|
export declare const AUTOMATION_SCHEDULER_LEASE_RENEWAL_MS = 60000;
|
|
4
4
|
export declare class AutomationSchedulerLeaseLostError extends Error {
|
|
@@ -6,7 +6,8 @@ export declare class AutomationSchedulerLeaseLostError extends Error {
|
|
|
6
6
|
constructor(cause?: unknown);
|
|
7
7
|
}
|
|
8
8
|
export declare const AUTOMATION_SCHEDULER_HEALTH_MIGRATIONS: MigrationEntry[];
|
|
9
|
-
export
|
|
9
|
+
/** Kept for callers of the public export; the store owns these migrations. */
|
|
10
|
+
export declare function runAutomationSchedulerHealthMigrations(_nitroApp?: unknown): Promise<void>;
|
|
10
11
|
export interface AutomationSchedulerHealth {
|
|
11
12
|
appId: string;
|
|
12
13
|
orgId: string | null;
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { randomUUID } from "node:crypto";
|
|
2
2
|
import { getDbExec } from "../db/client.js";
|
|
3
3
|
import { ensureColumnExists, ensureIndexExists, ensureTableExists, } from "../db/ddl-guard.js";
|
|
4
|
-
import { runMigrations } from "../db/migrations.js";
|
|
5
4
|
import { defineStore } from "../db/store-registry.js";
|
|
5
|
+
import { fromMigrationEntries } from "../db/versioned-store-migrations.js";
|
|
6
6
|
import { automationRecoveryMessagesForLocale } from "../localization/automation-recovery-messages.js";
|
|
7
7
|
const TABLE = "automation_scheduler_health";
|
|
8
8
|
const DEFAULT_APP_ID = "default";
|
|
@@ -50,10 +50,9 @@ export const AUTOMATION_SCHEDULER_HEALTH_MIGRATIONS = [
|
|
|
50
50
|
`,
|
|
51
51
|
},
|
|
52
52
|
];
|
|
53
|
-
export
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
})(nitroApp);
|
|
53
|
+
/** Kept for callers of the public export; the store owns these migrations. */
|
|
54
|
+
export async function runAutomationSchedulerHealthMigrations(_nitroApp) {
|
|
55
|
+
await schedulerHealthStore.ready();
|
|
57
56
|
}
|
|
58
57
|
function normalizeAppId(appId) {
|
|
59
58
|
const normalized = appId?.trim();
|
|
@@ -96,6 +95,7 @@ export const schedulerHealthStore = defineStore({
|
|
|
96
95
|
await ensureIndexExists(`idx_${TABLE}_updated`, indexSql);
|
|
97
96
|
},
|
|
98
97
|
},
|
|
98
|
+
...fromMigrationEntries("_automation_scheduler_health_migrations", AUTOMATION_SCHEDULER_HEALTH_MIGRATIONS),
|
|
99
99
|
],
|
|
100
100
|
});
|
|
101
101
|
export function ensureHealthTable() {
|
|
@@ -156,6 +156,9 @@ export declare class McpIdentityVerificationUnavailableError extends Error {
|
|
|
156
156
|
readonly cause: unknown;
|
|
157
157
|
constructor(cause: unknown);
|
|
158
158
|
}
|
|
159
|
+
export declare class McpIdentityVerificationRefusedError extends Error {
|
|
160
|
+
constructor();
|
|
161
|
+
}
|
|
159
162
|
export type VerifyAuthResult = {
|
|
160
163
|
authed: boolean;
|
|
161
164
|
identity?: MCPCallerIdentity;
|
package/dist/mcp/build-server.js
CHANGED
|
@@ -2843,6 +2843,12 @@ export class McpIdentityVerificationUnavailableError extends Error {
|
|
|
2843
2843
|
this.cause = cause;
|
|
2844
2844
|
}
|
|
2845
2845
|
}
|
|
2846
|
+
export class McpIdentityVerificationRefusedError extends Error {
|
|
2847
|
+
constructor() {
|
|
2848
|
+
super("MCP identity verification was refused");
|
|
2849
|
+
this.name = "McpIdentityVerificationRefusedError";
|
|
2850
|
+
}
|
|
2851
|
+
}
|
|
2846
2852
|
async function verifyA2AJwtForMcp(token, resourceUrl) {
|
|
2847
2853
|
const jose = await import("jose");
|
|
2848
2854
|
let unverifiedPayload = null;
|
|
@@ -3245,6 +3251,9 @@ export async function verifyAuth(authHeader, ownerEmailHeader, options = {}) {
|
|
|
3245
3251
|
if (error instanceof McpIdentityVerificationUnavailableError) {
|
|
3246
3252
|
return { authed: false, unavailable: true };
|
|
3247
3253
|
}
|
|
3254
|
+
if (error instanceof McpIdentityVerificationRefusedError) {
|
|
3255
|
+
return { authed: false, refusal: "invalid" };
|
|
3256
|
+
}
|
|
3248
3257
|
throw error;
|
|
3249
3258
|
}
|
|
3250
3259
|
if (payload) {
|
|
@@ -3321,21 +3330,29 @@ async function matchStaticAccessToken(token, accessTokens, ownerEmailHeader) {
|
|
|
3321
3330
|
export async function resolveOrgIdFromDomain(orgDomain) {
|
|
3322
3331
|
if (!orgDomain)
|
|
3323
3332
|
return undefined;
|
|
3333
|
+
const { lookupOrgByDomain } = await import("../org/context.js");
|
|
3334
|
+
let result;
|
|
3324
3335
|
try {
|
|
3325
|
-
|
|
3326
|
-
const org = await resolveOrgByDomain(orgDomain);
|
|
3327
|
-
return org?.orgId ?? undefined;
|
|
3336
|
+
result = await lookupOrgByDomain(orgDomain);
|
|
3328
3337
|
}
|
|
3329
|
-
catch {
|
|
3330
|
-
|
|
3338
|
+
catch (cause) {
|
|
3339
|
+
throw new McpIdentityVerificationUnavailableError(cause);
|
|
3340
|
+
}
|
|
3341
|
+
if (result.status === "ambiguous") {
|
|
3342
|
+
throw new McpIdentityVerificationRefusedError();
|
|
3331
3343
|
}
|
|
3344
|
+
return result.status === "found" ? result.org.orgId : undefined;
|
|
3332
3345
|
}
|
|
3333
3346
|
export async function resolveMcpIdentityOrgId(identity) {
|
|
3334
3347
|
if (identity?.orgId !== undefined)
|
|
3335
3348
|
return identity.orgId ?? undefined;
|
|
3336
|
-
|
|
3337
|
-
|
|
3349
|
+
if (identity?.orgDomain !== undefined) {
|
|
3350
|
+
const orgIdFromDomain = await resolveOrgIdFromDomain(identity.orgDomain);
|
|
3351
|
+
if (!orgIdFromDomain) {
|
|
3352
|
+
throw new McpIdentityVerificationRefusedError();
|
|
3353
|
+
}
|
|
3338
3354
|
return orgIdFromDomain;
|
|
3355
|
+
}
|
|
3339
3356
|
const userEmail = identity?.userEmail?.trim();
|
|
3340
3357
|
if (!userEmail)
|
|
3341
3358
|
return undefined;
|
package/dist/mcp/server.js
CHANGED
|
@@ -8,7 +8,7 @@ import { getH3App } from "../server/framework-request-handler.js";
|
|
|
8
8
|
import { getOrigin } from "../server/google-oauth.js";
|
|
9
9
|
import { readBody } from "../server/h3-helpers.js";
|
|
10
10
|
import { trackMcpInitialize } from "./analytics.js";
|
|
11
|
-
import { createMCPServerForRequest, verifyAuth, McpIdentityVerificationUnavailableError, getAccessTokens, resolveOrgIdFromDomain, buildLinkArtifacts, McpDirectoryProfileValidationError, validateMcpDirectoryProfile, validateMcpDirectoryWidgetDomain, selectMcpActionSurface, selectMcpDirectoryWidgetReadActions, selectMcpDirectoryWidgetWriteActions, } from "./build-server.js";
|
|
11
|
+
import { createMCPServerForRequest, verifyAuth, McpIdentityVerificationUnavailableError, McpIdentityVerificationRefusedError, getAccessTokens, resolveOrgIdFromDomain, resolveMcpIdentityOrgId, buildLinkArtifacts, McpDirectoryProfileValidationError, validateMcpDirectoryProfile, validateMcpDirectoryWidgetDomain, selectMcpActionSurface, selectMcpDirectoryWidgetReadActions, selectMcpDirectoryWidgetWriteActions, } from "./build-server.js";
|
|
12
12
|
import { buildMcpOAuthChallenge, getMcpOAuthAudiences, getMcpOAuthIssuer, getMcpOAuthProtectedResourceMetadataUrl, getMcpOAuthResource, } from "./oauth-route.js";
|
|
13
13
|
import { MCP_DIRECTORY_ROUTE_PREFIX, MCP_PUBLIC_ROUTE_PREFIX, MCP_ROUTE_PREFIXES, joinMcpRoute, } from "./route-paths.js";
|
|
14
14
|
export { createMCPServerForRequest, verifyAuth, getAccessTokens, resolveOrgIdFromDomain, buildLinkArtifacts, selectMcpDirectoryWidgetReadActions, selectMcpDirectoryWidgetWriteActions, };
|
|
@@ -183,6 +183,19 @@ function directoryProfileUnavailable(event, validationError) {
|
|
|
183
183
|
message: "The MCP directory is unavailable because its profile or widget origin is invalid.",
|
|
184
184
|
};
|
|
185
185
|
}
|
|
186
|
+
function identityVerificationUnavailable(event) {
|
|
187
|
+
setResponseStatus(event, 503);
|
|
188
|
+
setResponseHeader(event, "Retry-After", "5");
|
|
189
|
+
return {
|
|
190
|
+
error: "Service Unavailable",
|
|
191
|
+
message: CREDENTIAL_MEMBERSHIP_UNAVAILABLE_MESSAGE,
|
|
192
|
+
};
|
|
193
|
+
}
|
|
194
|
+
function identityVerificationRefused(event, routePath) {
|
|
195
|
+
setResponseStatus(event, 401);
|
|
196
|
+
setResponseHeader(event, "WWW-Authenticate", buildMcpOAuthChallenge(event, routePath, "invalid"));
|
|
197
|
+
return buildUnauthorizedBody(event, routePath, "invalid");
|
|
198
|
+
}
|
|
186
199
|
// ---------------------------------------------------------------------------
|
|
187
200
|
// handleMcpRequest — runtime-agnostic MCP request handler
|
|
188
201
|
// ---------------------------------------------------------------------------
|
|
@@ -245,14 +258,13 @@ async function handleMcpRequestInternal(event, config, routePath = MCP_PUBLIC_RO
|
|
|
245
258
|
});
|
|
246
259
|
}
|
|
247
260
|
catch (error) {
|
|
248
|
-
if (
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
};
|
|
261
|
+
if (error instanceof McpIdentityVerificationUnavailableError) {
|
|
262
|
+
return identityVerificationUnavailable(event);
|
|
263
|
+
}
|
|
264
|
+
if (error instanceof McpIdentityVerificationRefusedError) {
|
|
265
|
+
return identityVerificationRefused(event, routePath);
|
|
266
|
+
}
|
|
267
|
+
throw error;
|
|
256
268
|
}
|
|
257
269
|
if (!authResult.authed && authResult.unavailable) {
|
|
258
270
|
// The token is valid but its org membership could not be checked. No auth
|
|
@@ -270,6 +282,25 @@ async function handleMcpRequestInternal(event, config, routePath = MCP_PUBLIC_RO
|
|
|
270
282
|
setResponseHeader(event, "WWW-Authenticate", buildMcpOAuthChallenge(event, routePath, authResult.refusal));
|
|
271
283
|
return buildUnauthorizedBody(event, routePath, authResult.refusal);
|
|
272
284
|
}
|
|
285
|
+
if (authResult.identity?.orgId === undefined &&
|
|
286
|
+
authResult.identity?.orgDomain !== undefined) {
|
|
287
|
+
try {
|
|
288
|
+
const orgId = await resolveMcpIdentityOrgId(authResult.identity);
|
|
289
|
+
authResult = {
|
|
290
|
+
...authResult,
|
|
291
|
+
identity: { ...authResult.identity, orgId },
|
|
292
|
+
};
|
|
293
|
+
}
|
|
294
|
+
catch (error) {
|
|
295
|
+
if (error instanceof McpIdentityVerificationUnavailableError) {
|
|
296
|
+
return identityVerificationUnavailable(event);
|
|
297
|
+
}
|
|
298
|
+
if (error instanceof McpIdentityVerificationRefusedError) {
|
|
299
|
+
return identityVerificationRefused(event, routePath);
|
|
300
|
+
}
|
|
301
|
+
throw error;
|
|
302
|
+
}
|
|
303
|
+
}
|
|
273
304
|
const body = method === "POST" ? await readBody(event) : undefined;
|
|
274
305
|
onMcpMethod?.(directoryLogMethod(body) ?? method);
|
|
275
306
|
const initializeRequest = body
|
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
import { getDbExec } from "../db/client.js";
|
|
2
2
|
import { ensureColumnExists, ensureTableExists } from "../db/ddl-guard.js";
|
|
3
3
|
import { defineStore } from "../db/store-registry.js";
|
|
4
|
+
import { fromMigrationEntries } from "../db/versioned-store-migrations.js";
|
|
4
5
|
import { widenIntColumnsToBigInt } from "../db/widen-columns.js";
|
|
5
6
|
import { encryptSecretValue, decryptSecretValue, isEncryptedSecretValue, } from "../secrets/crypto.js";
|
|
7
|
+
import { OAUTH_TOKEN_MIGRATIONS, OAUTH_TOKEN_MIGRATIONS_TABLE, } from "./migrations.js";
|
|
6
8
|
function serializeTokens(tokens) {
|
|
7
9
|
return encryptSecretValue(JSON.stringify(tokens));
|
|
8
10
|
}
|
|
@@ -79,6 +81,7 @@ export const oauthTokensStore = defineStore({
|
|
|
79
81
|
await widenIntColumnsToBigInt("oauth_tokens", ["updated_at"], exec);
|
|
80
82
|
},
|
|
81
83
|
},
|
|
84
|
+
...fromMigrationEntries(OAUTH_TOKEN_MIGRATIONS_TABLE, OAUTH_TOKEN_MIGRATIONS, { data: [4, 6] }),
|
|
82
85
|
],
|
|
83
86
|
});
|
|
84
87
|
export function ensureTable() {
|
|
@@ -33,26 +33,26 @@ export declare function createObservabilityHandler(): import("h3").EventHandlerW
|
|
|
33
33
|
spans?: undefined;
|
|
34
34
|
ok?: undefined;
|
|
35
35
|
} | {
|
|
36
|
+
error?: undefined;
|
|
36
37
|
message?: undefined;
|
|
37
38
|
summary: import("./types.js").TraceSummary;
|
|
38
39
|
spans: import("./types.js").TraceSpan[];
|
|
39
|
-
error?: undefined;
|
|
40
40
|
ok?: undefined;
|
|
41
41
|
} | {
|
|
42
|
+
error?: undefined;
|
|
42
43
|
message?: undefined;
|
|
43
44
|
summary?: undefined;
|
|
44
45
|
spans?: undefined;
|
|
45
46
|
traceMissing: true;
|
|
46
47
|
id: string;
|
|
47
|
-
error?: undefined;
|
|
48
48
|
ok?: undefined;
|
|
49
49
|
} | {
|
|
50
|
+
error?: undefined;
|
|
50
51
|
message?: undefined;
|
|
51
52
|
summary?: undefined;
|
|
52
53
|
spans?: undefined;
|
|
53
54
|
traceMissing?: undefined;
|
|
54
55
|
id: string;
|
|
55
|
-
error?: undefined;
|
|
56
56
|
ok?: undefined;
|
|
57
57
|
} | {
|
|
58
58
|
message?: undefined;
|
|
@@ -61,9 +61,9 @@ export declare function createObservabilityHandler(): import("h3").EventHandlerW
|
|
|
61
61
|
error: any;
|
|
62
62
|
ok?: undefined;
|
|
63
63
|
} | {
|
|
64
|
+
error?: undefined;
|
|
64
65
|
message?: undefined;
|
|
65
66
|
summary?: undefined;
|
|
66
67
|
spans?: undefined;
|
|
67
|
-
error?: undefined;
|
|
68
68
|
ok: boolean;
|
|
69
69
|
}>>;
|
|
@@ -2,6 +2,8 @@ import { z } from "zod";
|
|
|
2
2
|
import { getDbExec } from "../db/client.js";
|
|
3
3
|
import { ensureTableExists, ensureColumnExists, ensureIndexExists, } from "../db/ddl-guard.js";
|
|
4
4
|
import { defineStore } from "../db/store-registry.js";
|
|
5
|
+
import { fromMigrationEntries } from "../db/versioned-store-migrations.js";
|
|
6
|
+
import { OBSERVABILITY_MIGRATIONS, OBSERVABILITY_MIGRATIONS_TABLE, } from "./migrations.js";
|
|
5
7
|
import { sanitizeToolErrorMessage, TOOL_ERROR_CAPTURE_METADATA_KEY, TOOL_ERROR_DETAIL_METADATA_KEY, } from "./trace-error.js";
|
|
6
8
|
import { redactSensitiveFields } from "./trace-redaction.js";
|
|
7
9
|
import { observabilityReviewThreadKey } from "./types.js";
|
|
@@ -118,6 +120,7 @@ function withUserFilter(baseWhere, baseArgs, userId, orgId) {
|
|
|
118
120
|
}
|
|
119
121
|
export const observabilityStore = defineStore({
|
|
120
122
|
id: "observability",
|
|
123
|
+
after: ["chat_threads"],
|
|
121
124
|
migrations: [
|
|
122
125
|
{
|
|
123
126
|
name: "baseline",
|
|
@@ -334,6 +337,7 @@ export const observabilityStore = defineStore({
|
|
|
334
337
|
await ensureIndexExists("idx_experiment_results_exp", `CREATE INDEX IF NOT EXISTS idx_experiment_results_exp ON agent_experiment_results (experiment_id)`);
|
|
335
338
|
},
|
|
336
339
|
},
|
|
340
|
+
...fromMigrationEntries(OBSERVABILITY_MIGRATIONS_TABLE, OBSERVABILITY_MIGRATIONS, { data: [1, 2, 3] }),
|
|
337
341
|
],
|
|
338
342
|
});
|
|
339
343
|
export function ensureObservabilityTables() {
|
|
@@ -59,24 +59,32 @@ export async function autoJoinDomainMatchingOrgs(rawEmail, options = {}) {
|
|
|
59
59
|
try {
|
|
60
60
|
const res = await db.execute({
|
|
61
61
|
sql: `SELECT o.id AS "orgId", o.identity_authority AS "identityAuthority",
|
|
62
|
-
o.identity_id AS "identityId"
|
|
62
|
+
o.identity_id AS "identityId",
|
|
63
|
+
EXISTS (
|
|
64
|
+
SELECT 1 FROM org_members m
|
|
65
|
+
WHERE m.org_id = o.id
|
|
66
|
+
AND LOWER(m.email) = ?
|
|
67
|
+
AND m.federation_removal_pending_at IS NULL
|
|
68
|
+
) AS "isMember"
|
|
63
69
|
FROM organizations o
|
|
64
70
|
WHERE LOWER(o.allowed_domain) = ?
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
FROM org_members m
|
|
68
|
-
WHERE m.org_id = o.id
|
|
69
|
-
AND LOWER(m.email) = ?
|
|
70
|
-
AND m.federation_removal_pending_at IS NULL
|
|
71
|
-
)
|
|
72
|
-
ORDER BY o.created_at ASC`,
|
|
73
|
-
args: [domain, email],
|
|
71
|
+
LIMIT 2`,
|
|
72
|
+
args: [email, domain],
|
|
74
73
|
});
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
74
|
+
if (res.rows.length > 1)
|
|
75
|
+
return { joined: [], activeOrgId: null };
|
|
76
|
+
if (res.rows.length === 1) {
|
|
77
|
+
const row = res.rows[0];
|
|
78
|
+
if (Boolean(row.isMember ?? row.is_member)) {
|
|
79
|
+
return { joined: [], activeOrgId: null };
|
|
80
|
+
}
|
|
81
|
+
matches = [
|
|
82
|
+
{
|
|
83
|
+
orgId: String(row.orgId ?? row.org_id),
|
|
84
|
+
federated: Boolean(String(row.identityAuthority ?? row.identity_authority ?? "").trim() && String(row.identityId ?? row.identity_id ?? "").trim()),
|
|
85
|
+
},
|
|
86
|
+
];
|
|
87
|
+
}
|
|
80
88
|
}
|
|
81
89
|
catch {
|
|
82
90
|
return { joined: [], activeOrgId: null };
|
package/dist/org/context.d.ts
CHANGED
|
@@ -56,6 +56,18 @@ export declare function bootstrapAdminOrganization(rawEmail: string, event?: H3E
|
|
|
56
56
|
export declare function getOrgDomain(orgId: string): Promise<string | null>;
|
|
57
57
|
export declare function getOrgA2ASecret(orgId: string): Promise<string | null>;
|
|
58
58
|
export declare function getA2ASecretByDomain(domain: string): Promise<string | null>;
|
|
59
|
+
export type OrgDomainLookup = {
|
|
60
|
+
status: "found";
|
|
61
|
+
org: {
|
|
62
|
+
orgId: string;
|
|
63
|
+
orgName: string;
|
|
64
|
+
};
|
|
65
|
+
} | {
|
|
66
|
+
status: "not-found";
|
|
67
|
+
} | {
|
|
68
|
+
status: "ambiguous";
|
|
69
|
+
};
|
|
70
|
+
export declare function lookupOrgByDomain(domain: string): Promise<OrgDomainLookup>;
|
|
59
71
|
export declare function resolveOrgByDomain(domain: string): Promise<{
|
|
60
72
|
orgId: string;
|
|
61
73
|
orgName: string;
|
package/dist/org/context.js
CHANGED
|
@@ -755,31 +755,35 @@ export async function getOrgA2ASecret(orgId) {
|
|
|
755
755
|
export async function getA2ASecretByDomain(domain) {
|
|
756
756
|
const exec = getDbExec();
|
|
757
757
|
const { rows } = await exec.execute({
|
|
758
|
-
sql: `SELECT a2a_secret FROM organizations WHERE LOWER(allowed_domain) = ? LIMIT
|
|
758
|
+
sql: `SELECT a2a_secret FROM organizations WHERE LOWER(allowed_domain) = ? LIMIT 2`,
|
|
759
759
|
args: [domain.toLowerCase()],
|
|
760
760
|
});
|
|
761
|
-
if (
|
|
761
|
+
if (rows.length !== 1)
|
|
762
762
|
return null;
|
|
763
763
|
const secret = String(rows[0].a2a_secret || "");
|
|
764
764
|
return secret || null;
|
|
765
765
|
}
|
|
766
|
-
export async function
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
return {
|
|
766
|
+
export async function lookupOrgByDomain(domain) {
|
|
767
|
+
const exec = getDbExec();
|
|
768
|
+
const { rows } = await exec.execute({
|
|
769
|
+
sql: `SELECT id, name FROM organizations WHERE LOWER(allowed_domain) = ? LIMIT 2`,
|
|
770
|
+
args: [domain.toLowerCase()],
|
|
771
|
+
});
|
|
772
|
+
if (rows.length === 0)
|
|
773
|
+
return { status: "not-found" };
|
|
774
|
+
if (rows.length > 1)
|
|
775
|
+
return { status: "ambiguous" };
|
|
776
|
+
return {
|
|
777
|
+
status: "found",
|
|
778
|
+
org: {
|
|
776
779
|
orgId: String(rows[0].id),
|
|
777
780
|
orgName: String(rows[0].name),
|
|
778
|
-
}
|
|
779
|
-
}
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
781
|
+
},
|
|
782
|
+
};
|
|
783
|
+
}
|
|
784
|
+
export async function resolveOrgByDomain(domain) {
|
|
785
|
+
const result = await lookupOrgByDomain(domain);
|
|
786
|
+
return result.status === "found" ? result.org : null;
|
|
783
787
|
}
|
|
784
788
|
export async function resolveA2AOrganizationMetadataByDomain(domain) {
|
|
785
789
|
const normalizedDomain = domain.trim().toLowerCase();
|
|
@@ -787,9 +791,11 @@ export async function resolveA2AOrganizationMetadataByDomain(domain) {
|
|
|
787
791
|
return null;
|
|
788
792
|
const { rows } = await getDbExec().execute({
|
|
789
793
|
sql: `SELECT id, allowed_domain
|
|
790
|
-
FROM organizations WHERE LOWER(allowed_domain) = ? LIMIT
|
|
794
|
+
FROM organizations WHERE LOWER(allowed_domain) = ? LIMIT 2`,
|
|
791
795
|
args: [normalizedDomain],
|
|
792
796
|
});
|
|
797
|
+
if (rows.length !== 1)
|
|
798
|
+
return null;
|
|
793
799
|
const row = rows[0];
|
|
794
800
|
if (!row)
|
|
795
801
|
return null;
|
|
@@ -826,9 +832,11 @@ export async function resolveA2AOrganizationCredentialsByDomain(domain) {
|
|
|
826
832
|
return null;
|
|
827
833
|
const { rows } = await getDbExec().execute({
|
|
828
834
|
sql: `SELECT id, allowed_domain, a2a_secret
|
|
829
|
-
FROM organizations WHERE LOWER(allowed_domain) = ? LIMIT
|
|
835
|
+
FROM organizations WHERE LOWER(allowed_domain) = ? LIMIT 2`,
|
|
830
836
|
args: [normalizedDomain],
|
|
831
837
|
});
|
|
838
|
+
if (rows.length !== 1)
|
|
839
|
+
return null;
|
|
832
840
|
const row = rows[0];
|
|
833
841
|
if (!row)
|
|
834
842
|
return null;
|
package/dist/org/handlers.js
CHANGED
|
@@ -1439,21 +1439,33 @@ export const setDomainHandler = defineEventHandler(async (event) => {
|
|
|
1439
1439
|
}
|
|
1440
1440
|
}
|
|
1441
1441
|
const e = await exec();
|
|
1442
|
-
if (
|
|
1443
|
-
|
|
1444
|
-
|
|
1445
|
-
|
|
1442
|
+
if (!e.transaction) {
|
|
1443
|
+
throw createError({
|
|
1444
|
+
statusCode: 503,
|
|
1445
|
+
message: "Organization domain updates require transaction support",
|
|
1446
1446
|
});
|
|
1447
|
-
|
|
1448
|
-
|
|
1449
|
-
|
|
1450
|
-
|
|
1447
|
+
}
|
|
1448
|
+
await e.transaction(async (tx) => {
|
|
1449
|
+
if (raw) {
|
|
1450
|
+
await tx.execute({
|
|
1451
|
+
sql: `SELECT pg_advisory_xact_lock(hashtextextended(?, 0::bigint))`,
|
|
1452
|
+
args: [`agent-native:org-domain:${raw}`],
|
|
1453
|
+
});
|
|
1454
|
+
const existing = await tx.execute({
|
|
1455
|
+
sql: `SELECT id FROM organizations WHERE LOWER(allowed_domain) = ? AND id != ? LIMIT 1`,
|
|
1456
|
+
args: [raw, ctx.orgId],
|
|
1451
1457
|
});
|
|
1458
|
+
if (existing.rows.length > 0) {
|
|
1459
|
+
throw createError({
|
|
1460
|
+
statusCode: 409,
|
|
1461
|
+
message: "Another organization already uses this domain",
|
|
1462
|
+
});
|
|
1463
|
+
}
|
|
1452
1464
|
}
|
|
1453
|
-
|
|
1454
|
-
|
|
1455
|
-
|
|
1456
|
-
|
|
1465
|
+
await tx.execute({
|
|
1466
|
+
sql: `UPDATE organizations SET allowed_domain = ? WHERE id = ?`,
|
|
1467
|
+
args: [raw, ctx.orgId],
|
|
1468
|
+
});
|
|
1457
1469
|
});
|
|
1458
1470
|
invalidateDomainMatchCache();
|
|
1459
1471
|
invalidateMemberOrgCaches();
|
|
@@ -1758,7 +1770,7 @@ export const receiveA2ASecretHandler = defineEventHandler(async (event) => {
|
|
|
1758
1770
|
}
|
|
1759
1771
|
const e = await exec();
|
|
1760
1772
|
const orgRes = await e.execute({
|
|
1761
|
-
sql: `SELECT id, a2a_secret FROM organizations WHERE LOWER(allowed_domain) = ? LIMIT
|
|
1773
|
+
sql: `SELECT id, a2a_secret FROM organizations WHERE LOWER(allowed_domain) = ? LIMIT 2`,
|
|
1762
1774
|
args: [orgDomain],
|
|
1763
1775
|
});
|
|
1764
1776
|
if (orgRes.rows.length === 0) {
|
|
@@ -1767,6 +1779,12 @@ export const receiveA2ASecretHandler = defineEventHandler(async (event) => {
|
|
|
1767
1779
|
message: "No local org matches that domain",
|
|
1768
1780
|
});
|
|
1769
1781
|
}
|
|
1782
|
+
if (orgRes.rows.length > 1) {
|
|
1783
|
+
throw createError({
|
|
1784
|
+
statusCode: 409,
|
|
1785
|
+
message: "Multiple local organizations match that domain",
|
|
1786
|
+
});
|
|
1787
|
+
}
|
|
1770
1788
|
const row = orgRes.rows[0];
|
|
1771
1789
|
const localOrgId = String(row.id);
|
|
1772
1790
|
const existingSecret = String(row.a2a_secret ?? "") || null;
|
package/dist/org/index.d.ts
CHANGED
|
@@ -7,6 +7,7 @@ export declare const getOrgA2ASecret: typeof import("./context.js").getOrgA2ASec
|
|
|
7
7
|
export declare const getA2ASecretByDomain: typeof import("./context.js").getA2ASecretByDomain;
|
|
8
8
|
export declare const isSoleOrgDomain: typeof import("./context.js").isSoleOrgDomain;
|
|
9
9
|
export declare const resolveOrgByDomain: typeof import("./context.js").resolveOrgByDomain;
|
|
10
|
+
export declare const lookupOrgByDomain: typeof import("./context.js").lookupOrgByDomain;
|
|
10
11
|
export declare const resolveOrgIdForEmail: typeof import("./context.js").resolveOrgIdForEmail;
|
|
11
12
|
export declare const resolveActiveOrgIdForStorageCredential: typeof import("./context.js").resolveActiveOrgIdForStorageCredential;
|
|
12
13
|
export declare const createOrganization: typeof import("./context.js").createOrganization;
|
|
@@ -161,9 +162,9 @@ export declare const getMyOrgHandler: import("h3").EventHandlerWithFetch<import(
|
|
|
161
162
|
soloDeploymentAdmin: boolean;
|
|
162
163
|
}>>;
|
|
163
164
|
export declare const createOrgHandler: import("h3").EventHandlerWithFetch<import("h3").EventHandlerRequest, Promise<{
|
|
165
|
+
name?: undefined;
|
|
164
166
|
success: boolean;
|
|
165
167
|
id?: undefined;
|
|
166
|
-
name?: undefined;
|
|
167
168
|
role?: undefined;
|
|
168
169
|
} | {
|
|
169
170
|
success?: undefined;
|
package/dist/org/index.js
CHANGED
|
@@ -21,6 +21,7 @@ export const getOrgA2ASecret = lazyFunction(loadOrgContext, "getOrgA2ASecret");
|
|
|
21
21
|
export const getA2ASecretByDomain = lazyFunction(loadOrgContext, "getA2ASecretByDomain");
|
|
22
22
|
export const isSoleOrgDomain = lazyFunction(loadOrgContext, "isSoleOrgDomain");
|
|
23
23
|
export const resolveOrgByDomain = lazyFunction(loadOrgContext, "resolveOrgByDomain");
|
|
24
|
+
export const lookupOrgByDomain = lazyFunction(loadOrgContext, "lookupOrgByDomain");
|
|
24
25
|
export const resolveOrgIdForEmail = lazyFunction(loadOrgContext, "resolveOrgIdForEmail");
|
|
25
26
|
export const resolveActiveOrgIdForStorageCredential = lazyFunction(loadOrgContext, "resolveActiveOrgIdForStorageCredential");
|
|
26
27
|
export const createOrganization = lazyFunction(loadOrgContext, "createOrganization");
|
package/dist/org/plugin.js
CHANGED
|
@@ -1,13 +1,12 @@
|
|
|
1
1
|
import { defineEventHandler, setResponseStatus, getMethod, getRequestURL, } from "h3";
|
|
2
|
-
import { runMigrations } from "../db/migrations.js";
|
|
3
2
|
import { registerFeatureFlags } from "../feature-flags/registry.js";
|
|
4
3
|
import { awaitBootstrap, getH3App, FRAMEWORK_PREFIX, markDefaultPluginProvided, } from "../server/framework-request-handler.js";
|
|
5
4
|
import { listAppRolesHandler, setAppRoleHandler, getAppPermissionsHandler, setAppPermissionsHandler, resetAppPermissionHandler, } from "./app-roles-handlers.js";
|
|
6
5
|
import { listSSOProvidersHandler, createSSOProviderHandler, verifySSOProviderHandler, deleteSSOProviderHandler, getSCIMHandler, createSCIMHandler, deleteSCIMHandler, } from "./enterprise-auth-handlers.js";
|
|
7
6
|
import { CROSS_APP_ORG_FEDERATION_FLAG } from "./feature-flags.js";
|
|
8
7
|
import { getMyOrgHandler, createOrgHandler, updateOrgHandler, deleteOrgHandler, switchOrgHandler, listMembersHandler, removeMemberHandler, retryPendingFederatedRemovalHandler, changeMemberRoleHandler, listInvitationsHandler, createInvitationHandler, acceptInvitationHandler, joinByDomainHandler, setDomainHandler, setWorkspaceUrlHandler, setRequiredAuthProviderHandler, revealA2ASecretHandler, setA2ASecretHandler, syncA2ASecretHandler, receiveA2ASecretHandler, setWorkspaceAppDefaultVisibilityHandler, setOrgVisualIdentityHandler, } from "./handlers.js";
|
|
9
|
-
import { ORG_MIGRATIONS } from "./migrations.js";
|
|
10
8
|
import { readWorkspacePrivateIconHandler, uploadWorkspacePrivateIconHandler, } from "./private-icon-handlers.js";
|
|
9
|
+
import { orgStore } from "./schema-store.js";
|
|
11
10
|
const ORG_PREFIX = `${FRAMEWORK_PREFIX}/org`;
|
|
12
11
|
async function workspaceIconUploadResponse(event) {
|
|
13
12
|
try {
|
|
@@ -64,12 +63,11 @@ async function workspaceIconUploadResponse(event) {
|
|
|
64
63
|
* POST /_agent-native/org/a2a-secret/receive — accept a peer's secret push (JWT-auth, no session)
|
|
65
64
|
*/
|
|
66
65
|
export function createOrgPlugin() {
|
|
67
|
-
const migrate = runMigrations(ORG_MIGRATIONS, { table: "_org_migrations" });
|
|
68
66
|
return async (nitroApp) => {
|
|
69
67
|
registerFeatureFlags([CROSS_APP_ORG_FEDERATION_FLAG]);
|
|
70
68
|
markDefaultPluginProvided(nitroApp, "org");
|
|
71
69
|
await awaitBootstrap(nitroApp);
|
|
72
|
-
await
|
|
70
|
+
await orgStore.ready();
|
|
73
71
|
const app = getH3App(nitroApp);
|
|
74
72
|
app.use(`${ORG_PREFIX}/private-icons`, defineEventHandler(async (event) => {
|
|
75
73
|
const tail = getRequestURL(event).pathname || "/";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const orgStore: import("../db/store-registry.js").Store;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { defineStore } from "../db/store-registry.js";
|
|
2
|
+
import { fromMigrationEntries } from "../db/versioned-store-migrations.js";
|
|
3
|
+
import { ORG_MIGRATIONS } from "./migrations.js";
|
|
4
|
+
export const orgStore = defineStore({
|
|
5
|
+
id: "org",
|
|
6
|
+
// Entries 1024 and 1032 touch the review-suggestion and audit tables; on main
|
|
7
|
+
// every store ran before this list, so keep that order at release.
|
|
8
|
+
after: ["audit", "review_suggestions"],
|
|
9
|
+
migrations: fromMigrationEntries("_org_migrations", ORG_MIGRATIONS, {
|
|
10
|
+
ranAtBoot: true,
|
|
11
|
+
data: [1009, 1018],
|
|
12
|
+
}),
|
|
13
|
+
});
|
|
@@ -75,9 +75,8 @@ export declare function createCustomProviderRegistrationAction<TSchema extends Z
|
|
|
75
75
|
user: "user";
|
|
76
76
|
}>>;
|
|
77
77
|
}, z.core.$strip>>, {
|
|
78
|
-
id?: undefined;
|
|
79
|
-
deleted?: undefined;
|
|
80
78
|
message?: undefined;
|
|
79
|
+
id?: undefined;
|
|
81
80
|
providers: {
|
|
82
81
|
id: string;
|
|
83
82
|
label: string;
|
|
@@ -90,31 +89,32 @@ export declare function createCustomProviderRegistrationAction<TSchema extends Z
|
|
|
90
89
|
count: number;
|
|
91
90
|
provider?: undefined;
|
|
92
91
|
found?: undefined;
|
|
92
|
+
deleted?: undefined;
|
|
93
93
|
registered?: undefined;
|
|
94
94
|
label?: undefined;
|
|
95
95
|
} | {
|
|
96
|
+
message?: undefined;
|
|
96
97
|
id?: undefined;
|
|
97
|
-
deleted?: undefined;
|
|
98
98
|
count?: undefined;
|
|
99
|
-
message?: undefined;
|
|
100
99
|
providers?: undefined;
|
|
101
100
|
found: boolean;
|
|
102
101
|
provider: import("../custom-registry.js").CustomProviderConfig;
|
|
102
|
+
deleted?: undefined;
|
|
103
103
|
registered?: undefined;
|
|
104
104
|
label?: undefined;
|
|
105
105
|
} | {
|
|
106
|
-
deleted?: undefined;
|
|
107
|
-
count?: undefined;
|
|
108
106
|
message?: undefined;
|
|
107
|
+
count?: undefined;
|
|
109
108
|
providers?: undefined;
|
|
110
109
|
provider?: undefined;
|
|
111
110
|
found: boolean;
|
|
112
111
|
id: string;
|
|
112
|
+
deleted?: undefined;
|
|
113
113
|
registered?: undefined;
|
|
114
114
|
label?: undefined;
|
|
115
115
|
} | {
|
|
116
|
-
count?: undefined;
|
|
117
116
|
message?: undefined;
|
|
117
|
+
count?: undefined;
|
|
118
118
|
providers?: undefined;
|
|
119
119
|
provider?: undefined;
|
|
120
120
|
found?: undefined;
|
|
@@ -123,11 +123,11 @@ export declare function createCustomProviderRegistrationAction<TSchema extends Z
|
|
|
123
123
|
registered?: undefined;
|
|
124
124
|
label?: undefined;
|
|
125
125
|
} | {
|
|
126
|
-
deleted?: undefined;
|
|
127
126
|
count?: undefined;
|
|
128
127
|
providers?: undefined;
|
|
129
128
|
provider?: undefined;
|
|
130
129
|
found?: undefined;
|
|
130
|
+
deleted?: undefined;
|
|
131
131
|
registered: boolean;
|
|
132
132
|
id: string;
|
|
133
133
|
label: string;
|