@agent-native/core 0.209.1-nightly-20261015153252 → 0.209.1
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/index.d.ts +1 -1
- package/dist/a2a/index.js +1 -1
- package/dist/a2a/server.d.ts +10 -0
- package/dist/a2a/server.js +96 -0
- package/dist/agent/production-agent.d.ts +2 -0
- package/dist/agent/production-agent.js +43 -6
- package/dist/agent/submission-deadline.d.ts +1 -0
- package/dist/agent/submission-deadline.js +27 -0
- package/dist/agent/thread-data-builder.d.ts +2 -1
- package/dist/agent/thread-data-builder.js +37 -6
- package/dist/authorization/check-action.js +4 -3
- package/dist/chat-threads/store.d.ts +1 -0
- package/dist/chat-threads/store.js +34 -2
- package/dist/client/agent-chat.d.ts +3 -0
- package/dist/client/agent-chat.js +9 -0
- package/dist/client/chat/agentkit-agent-native.js +126 -3
- package/dist/client/error-format.d.ts +2 -0
- package/dist/client/error-format.js +10 -0
- package/dist/collab/routes.d.ts +1 -1
- package/dist/mcp/screen-memory-stdio.d.ts +7 -7
- package/dist/org/index.d.ts +1 -1
- package/dist/org/index.js +1 -1
- package/dist/org/workspace-app-access-outcome.d.ts +45 -0
- package/dist/org/workspace-app-access-outcome.js +80 -0
- package/dist/org/workspace-app-access-request.d.ts +2 -2
- package/dist/org/workspace-app-access-request.js +2 -2
- package/dist/org/workspace-app-access.d.ts +8 -3
- package/dist/org/workspace-app-access.js +122 -30
- package/dist/provider-api/actions/custom-provider-registration.d.ts +4 -4
- package/dist/provider-api/actions/provider-api.d.ts +6 -6
- package/dist/server/action-routes.js +10 -7
- package/dist/server/agent-chat-plugin.js +28 -2
- package/dist/server/agent-engine-ollama-models-route.d.ts +2 -2
- package/dist/server/auth.js +3 -3
- package/dist/server/realtime-token.d.ts +1 -1
- package/dist/triggers/actions/manage-automation.d.ts +3 -3
- package/package.json +4 -4
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import { AgentKitRunSlotBusyError } from "@agent-native/agentkit/client";
|
|
2
|
-
import { agentEventSequenceEnd, isAgentKitProtocolVersion, parseAgentQueuedMessage, parseAgentRunOptions, parseAgentThreadSnapshot, persistableFilePart, } from "@agent-native/agentkit/protocol";
|
|
2
|
+
import { AGENT_NATIVE_SUBMISSION_DEADLINES_CAPABILITY_ID, createCapabilityUnavailableError, createCapabilityUnsupportedError, agentEventSequenceEnd, isAgentKitProtocolVersion, negotiateAgentKitProtocolVersion, parseAgentQueuedMessage, parseAgentRunOptions, parseAgentThreadSnapshot, persistableFilePart, } from "@agent-native/agentkit/protocol";
|
|
3
3
|
import { failedRunIdsWithError, isRenderedRunNotStartedNotice, projectRootAssistantMessages, } from "../../agent/thread-message-projection.js";
|
|
4
4
|
import { RUN_NOT_STARTED_METADATA_KEY, retryContextFromRequest, } from "../../shared/agent-chat-run-not-started.js";
|
|
5
5
|
import { assertNoInlineImageBytes, stripInlineBytes, } from "../../shared/inline-bytes.js";
|
|
6
6
|
import { toolInputFingerprint } from "../../shared/tool-inputs.js";
|
|
7
7
|
import { agentEngineStatusUrlForChatApi, requireAgentEngineConfiguredForDispatch, } from "../agent-engine-readiness.js";
|
|
8
8
|
import { agentNativePath } from "../api-path.js";
|
|
9
|
-
import { CHAT_REQUEST_TOO_LARGE_MESSAGE } from "../error-format.js";
|
|
9
|
+
import { CHAT_CAPABILITY_UNAVAILABLE_MESSAGE, CHAT_CAPABILITY_UNSUPPORTED_MESSAGE, CHAT_REQUEST_TOO_LARGE_MESSAGE, } from "../error-format.js";
|
|
10
10
|
import { dispatchAgentChatRunning } from "../use-agent-chat-running-threads.js";
|
|
11
11
|
import { appendChatThreadScopeParams, } from "../use-chat-threads.js";
|
|
12
12
|
import { AGENT_NATIVE_PROTOCOL_METADATA_KEY, createAgentKitProtocolAdapter, } from "./agentkit-protocol.js";
|
|
@@ -2801,7 +2801,7 @@ export function createAgentNativeAgentKitTransport(options = {}) {
|
|
|
2801
2801
|
await waitForSnapshotRetry(attempt, signal);
|
|
2802
2802
|
};
|
|
2803
2803
|
throwIfRequestAborted(signal);
|
|
2804
|
-
let response;
|
|
2804
|
+
let response = undefined;
|
|
2805
2805
|
try {
|
|
2806
2806
|
response = await fetcher(threadUrl, {
|
|
2807
2807
|
method: "PUT",
|
|
@@ -2894,6 +2894,7 @@ export function createAgentNativeAgentKitTransport(options = {}) {
|
|
|
2894
2894
|
queuedMessages: storedQueue(value.queuedMessages, threadId, now()),
|
|
2895
2895
|
...(message ? { message } : {}),
|
|
2896
2896
|
...(claimedMessage ? { claimedMessage } : {}),
|
|
2897
|
+
...(value.submissionExpired === true ? { submissionExpired: true } : {}),
|
|
2897
2898
|
};
|
|
2898
2899
|
}
|
|
2899
2900
|
// A server that predates `active` meaning "in flight" reports a run inside
|
|
@@ -3040,6 +3041,9 @@ export function createAgentNativeAgentKitTransport(options = {}) {
|
|
|
3040
3041
|
type: "append",
|
|
3041
3042
|
message,
|
|
3042
3043
|
});
|
|
3044
|
+
if (result.submissionExpired) {
|
|
3045
|
+
throw Object.assign(new Error("The prompt expired before it could be queued."), { code: "submission_expired", retryable: false });
|
|
3046
|
+
}
|
|
3043
3047
|
if (!result.message) {
|
|
3044
3048
|
throw new TypeError("Agent chat queue mutation omitted its message.");
|
|
3045
3049
|
}
|
|
@@ -3093,6 +3097,10 @@ export function createAgentNativeAgentKitTransport(options = {}) {
|
|
|
3093
3097
|
throw error;
|
|
3094
3098
|
}
|
|
3095
3099
|
try {
|
|
3100
|
+
if (claim.submissionExpired) {
|
|
3101
|
+
clearPromotionClaimId(threadId, messageId);
|
|
3102
|
+
return { alreadyRemoved: true };
|
|
3103
|
+
}
|
|
3096
3104
|
if (!claim.claimedMessage) {
|
|
3097
3105
|
throw new TypeError("Agent chat queue claim response is invalid.");
|
|
3098
3106
|
}
|
|
@@ -3151,6 +3159,19 @@ export function createAgentNativeAgentKitTransport(options = {}) {
|
|
|
3151
3159
|
return run;
|
|
3152
3160
|
}
|
|
3153
3161
|
catch (error) {
|
|
3162
|
+
if (asRecord(error)?.code === "submission_expired") {
|
|
3163
|
+
try {
|
|
3164
|
+
await persistQueueMutation(threadId, {
|
|
3165
|
+
type: "remove",
|
|
3166
|
+
messageId,
|
|
3167
|
+
});
|
|
3168
|
+
}
|
|
3169
|
+
catch (removeError) {
|
|
3170
|
+
throw new AggregateError([error, removeError], "An expired queued prompt could not be removed.");
|
|
3171
|
+
}
|
|
3172
|
+
clearPromotionClaimId(threadId, messageId);
|
|
3173
|
+
return { alreadyRemoved: true };
|
|
3174
|
+
}
|
|
3154
3175
|
try {
|
|
3155
3176
|
await persistQueueMutation(threadId, {
|
|
3156
3177
|
type: "release",
|
|
@@ -3349,10 +3370,112 @@ export function createAgentNativeAgentKitTransport(options = {}) {
|
|
|
3349
3370
|
}
|
|
3350
3371
|
};
|
|
3351
3372
|
const subscribeToRun = protocolTransport.subscribeToRun.bind(protocolTransport);
|
|
3373
|
+
const discoverCapabilities = protocolTransport.discoverCapabilities?.bind(protocolTransport);
|
|
3374
|
+
const serverBackedCapabilities = isAgentNativeChatRuntime(runtime);
|
|
3375
|
+
const capabilitiesUrl = apiUrl.endsWith("/")
|
|
3376
|
+
? `${apiUrl}capabilities`
|
|
3377
|
+
: `${apiUrl}/capabilities`;
|
|
3352
3378
|
transport = {
|
|
3353
3379
|
...protocolTransport,
|
|
3354
3380
|
assertAiSetupReady,
|
|
3355
3381
|
startRun: (input, context) => startRunTrackingRunningState(input, context),
|
|
3382
|
+
async discoverCapabilities(input, context) {
|
|
3383
|
+
const capability = AGENT_NATIVE_SUBMISSION_DEADLINES_CAPABILITY_ID;
|
|
3384
|
+
const discovery = discoverCapabilities
|
|
3385
|
+
? await discoverCapabilities(input, context)
|
|
3386
|
+
: (() => {
|
|
3387
|
+
const legacy = protocolTransport.capabilities ?? {};
|
|
3388
|
+
return {
|
|
3389
|
+
protocol: negotiateAgentKitProtocolVersion(input.protocol, {
|
|
3390
|
+
correlationId: context?.correlationId,
|
|
3391
|
+
}),
|
|
3392
|
+
capabilities: Object.entries(legacy).reduce((descriptors, [id, state]) => {
|
|
3393
|
+
if (typeof state !== "boolean")
|
|
3394
|
+
return descriptors;
|
|
3395
|
+
const capabilityId = id;
|
|
3396
|
+
descriptors.push(state
|
|
3397
|
+
? { id: capabilityId, state: "available" }
|
|
3398
|
+
: {
|
|
3399
|
+
id: capabilityId,
|
|
3400
|
+
state: "unsupported",
|
|
3401
|
+
error: createCapabilityUnsupportedError(capabilityId),
|
|
3402
|
+
});
|
|
3403
|
+
return descriptors;
|
|
3404
|
+
}, []),
|
|
3405
|
+
discoveredAt: new Date().toISOString(),
|
|
3406
|
+
legacy,
|
|
3407
|
+
};
|
|
3408
|
+
})();
|
|
3409
|
+
let supported = false;
|
|
3410
|
+
let unavailableError;
|
|
3411
|
+
if (serverBackedCapabilities) {
|
|
3412
|
+
const createUnavailableError = () => createCapabilityUnavailableError(capability, {
|
|
3413
|
+
message: CHAT_CAPABILITY_UNAVAILABLE_MESSAGE,
|
|
3414
|
+
});
|
|
3415
|
+
let response = undefined;
|
|
3416
|
+
try {
|
|
3417
|
+
response = await fetcher(capabilitiesUrl, {
|
|
3418
|
+
method: "GET",
|
|
3419
|
+
headers: { Accept: "application/json" },
|
|
3420
|
+
credentials: "same-origin",
|
|
3421
|
+
cache: "no-store",
|
|
3422
|
+
...(context?.signal ? { signal: context.signal } : {}),
|
|
3423
|
+
});
|
|
3424
|
+
}
|
|
3425
|
+
catch (error) {
|
|
3426
|
+
if (context?.signal?.aborted)
|
|
3427
|
+
throw error;
|
|
3428
|
+
unavailableError = createUnavailableError();
|
|
3429
|
+
}
|
|
3430
|
+
if (!unavailableError &&
|
|
3431
|
+
response &&
|
|
3432
|
+
!response.ok &&
|
|
3433
|
+
response.status !== 404 &&
|
|
3434
|
+
response.status !== 405) {
|
|
3435
|
+
unavailableError = createUnavailableError();
|
|
3436
|
+
}
|
|
3437
|
+
if (!unavailableError && response?.ok) {
|
|
3438
|
+
try {
|
|
3439
|
+
const serverCapabilities = asRecord(await response.json());
|
|
3440
|
+
if (!serverCapabilities) {
|
|
3441
|
+
throw new TypeError("Capability response must be an object.");
|
|
3442
|
+
}
|
|
3443
|
+
supported = serverCapabilities?.[capability] === true;
|
|
3444
|
+
}
|
|
3445
|
+
catch (error) {
|
|
3446
|
+
if (context?.signal?.aborted)
|
|
3447
|
+
throw error;
|
|
3448
|
+
unavailableError = createUnavailableError();
|
|
3449
|
+
}
|
|
3450
|
+
}
|
|
3451
|
+
}
|
|
3452
|
+
const descriptor = supported
|
|
3453
|
+
? { id: capability, state: "available" }
|
|
3454
|
+
: unavailableError
|
|
3455
|
+
? { id: capability, state: "unavailable", error: unavailableError }
|
|
3456
|
+
: {
|
|
3457
|
+
id: capability,
|
|
3458
|
+
state: "unsupported",
|
|
3459
|
+
error: createCapabilityUnsupportedError(capability, {
|
|
3460
|
+
message: CHAT_CAPABILITY_UNSUPPORTED_MESSAGE,
|
|
3461
|
+
}),
|
|
3462
|
+
};
|
|
3463
|
+
const legacy = { ...discovery.legacy };
|
|
3464
|
+
if (unavailableError) {
|
|
3465
|
+
delete legacy[capability];
|
|
3466
|
+
}
|
|
3467
|
+
else {
|
|
3468
|
+
legacy[capability] = supported;
|
|
3469
|
+
}
|
|
3470
|
+
return {
|
|
3471
|
+
...discovery,
|
|
3472
|
+
capabilities: [
|
|
3473
|
+
...discovery.capabilities.filter((candidate) => candidate.id !== capability),
|
|
3474
|
+
descriptor,
|
|
3475
|
+
],
|
|
3476
|
+
legacy,
|
|
3477
|
+
};
|
|
3478
|
+
},
|
|
3356
3479
|
async *subscribeToRun(input) {
|
|
3357
3480
|
dispatchAgentChatRunning({
|
|
3358
3481
|
isRunning: true,
|
|
@@ -17,6 +17,8 @@ export declare const NEW_CHAT_ACTION_HREF = "agent-native:new-chat";
|
|
|
17
17
|
export declare const PROVIDER_CREDENTIAL_REJECTED_MESSAGE = "The provider rejected the credential used for this request; it is skipped on the next attempt. Retry, or update your provider key if it keeps failing.";
|
|
18
18
|
export declare const SERVER_AUTHORED_CREDENTIAL_CODES: ReadonlySet<string>;
|
|
19
19
|
export declare const CHAT_REQUEST_TOO_LARGE_MESSAGE = "This request exceeded the server's size limit (HTTP 413). Start a new chat or remove large attachments or references, then retry.";
|
|
20
|
+
export declare const CHAT_CAPABILITY_UNAVAILABLE_MESSAGE = "We couldn't send your message right now. Please try again shortly.";
|
|
21
|
+
export declare const CHAT_CAPABILITY_UNSUPPORTED_MESSAGE = "This app can't safely retry your saved prompt yet. Update the app, then try again.";
|
|
20
22
|
export declare function formatChatErrorText(errorMessage: string, upgradeUrl?: string, errorCode?: string): string;
|
|
21
23
|
export interface NormalizedChatError {
|
|
22
24
|
message: string;
|
|
@@ -54,6 +54,8 @@ const INVALID_ATTACHMENT_MESSAGE = "The model provider rejected this attachment'
|
|
|
54
54
|
const MALFORMED_REQUEST_ATTACHMENT_MESSAGE = "The model rejected an attached file, so this message was never sent. Remove the attachment and retry — a PDF, a plain-text file, or a JPEG, PNG, GIF, or WebP image is read directly; other formats have to be uploaded and linked instead.";
|
|
55
55
|
const MALFORMED_REQUEST_MESSAGE = "The model provider rejected this request as malformed, so it was not retried. Retry, or start a new chat if it keeps happening.";
|
|
56
56
|
export const CHAT_REQUEST_TOO_LARGE_MESSAGE = "This request exceeded the server's size limit (HTTP 413). Start a new chat or remove large attachments or references, then retry.";
|
|
57
|
+
export const CHAT_CAPABILITY_UNAVAILABLE_MESSAGE = "We couldn't send your message right now. Please try again shortly.";
|
|
58
|
+
export const CHAT_CAPABILITY_UNSUPPORTED_MESSAGE = "This app can't safely retry your saved prompt yet. Update the app, then try again.";
|
|
57
59
|
const MALFORMED_REQUEST_CODES = new Set([
|
|
58
60
|
"invalid_request",
|
|
59
61
|
"invalid_request_error",
|
|
@@ -108,6 +110,14 @@ const KNOWN_CHAT_ERROR_KEYS = new Map([
|
|
|
108
110
|
],
|
|
109
111
|
[INVALID_ATTACHMENT_MESSAGE, "agentChat.errorMessages.invalidAttachment"],
|
|
110
112
|
[CHAT_REQUEST_TOO_LARGE_MESSAGE, "agentChat.errorMessages.requestTooLarge"],
|
|
113
|
+
[
|
|
114
|
+
CHAT_CAPABILITY_UNAVAILABLE_MESSAGE,
|
|
115
|
+
"agentChat.errorMessages.capabilityUnavailable",
|
|
116
|
+
],
|
|
117
|
+
[
|
|
118
|
+
CHAT_CAPABILITY_UNSUPPORTED_MESSAGE,
|
|
119
|
+
"agentChat.errorMessages.capabilityUnsupported",
|
|
120
|
+
],
|
|
111
121
|
[
|
|
112
122
|
"No LLM provider is connected. Open this app's Manage agent > LLM, then use Builder.io or add a provider key.",
|
|
113
123
|
"agentChat.errorMessages.noProviderConnected",
|
package/dist/collab/routes.d.ts
CHANGED
|
@@ -13,8 +13,8 @@ export declare const getCollabState: import("h3").EventHandlerWithFetch<import("
|
|
|
13
13
|
};
|
|
14
14
|
}>>;
|
|
15
15
|
export declare const postCollabUpdate: import("h3").EventHandlerWithFetch<import("h3").EventHandlerRequest, Promise<{
|
|
16
|
-
ok?: undefined;
|
|
17
16
|
error: string;
|
|
17
|
+
ok?: undefined;
|
|
18
18
|
} | {
|
|
19
19
|
error?: undefined;
|
|
20
20
|
ok: boolean;
|
|
@@ -140,13 +140,13 @@ export declare function screenMemoryMcpToolDefinitions(): ({
|
|
|
140
140
|
clientHint?: undefined;
|
|
141
141
|
timestamp?: undefined;
|
|
142
142
|
chapterId?: undefined;
|
|
143
|
-
count?: undefined;
|
|
144
143
|
startAt?: undefined;
|
|
145
144
|
endAt?: undefined;
|
|
146
145
|
reason?: undefined;
|
|
147
146
|
includeMicrophone?: undefined;
|
|
148
147
|
includeSystemAudio?: undefined;
|
|
149
148
|
requestId?: undefined;
|
|
149
|
+
count?: undefined;
|
|
150
150
|
};
|
|
151
151
|
required?: undefined;
|
|
152
152
|
};
|
|
@@ -171,13 +171,13 @@ export declare function screenMemoryMcpToolDefinitions(): ({
|
|
|
171
171
|
clientHint?: undefined;
|
|
172
172
|
timestamp?: undefined;
|
|
173
173
|
chapterId?: undefined;
|
|
174
|
-
count?: undefined;
|
|
175
174
|
startAt?: undefined;
|
|
176
175
|
endAt?: undefined;
|
|
177
176
|
reason?: undefined;
|
|
178
177
|
includeMicrophone?: undefined;
|
|
179
178
|
includeSystemAudio?: undefined;
|
|
180
179
|
requestId?: undefined;
|
|
180
|
+
count?: undefined;
|
|
181
181
|
};
|
|
182
182
|
required?: undefined;
|
|
183
183
|
};
|
|
@@ -196,13 +196,13 @@ export declare function screenMemoryMcpToolDefinitions(): ({
|
|
|
196
196
|
clientHint?: undefined;
|
|
197
197
|
timestamp?: undefined;
|
|
198
198
|
chapterId?: undefined;
|
|
199
|
-
count?: undefined;
|
|
200
199
|
startAt?: undefined;
|
|
201
200
|
endAt?: undefined;
|
|
202
201
|
reason?: undefined;
|
|
203
202
|
includeMicrophone?: undefined;
|
|
204
203
|
includeSystemAudio?: undefined;
|
|
205
204
|
requestId?: undefined;
|
|
205
|
+
count?: undefined;
|
|
206
206
|
};
|
|
207
207
|
required?: undefined;
|
|
208
208
|
};
|
|
@@ -231,13 +231,13 @@ export declare function screenMemoryMcpToolDefinitions(): ({
|
|
|
231
231
|
};
|
|
232
232
|
timestamp?: undefined;
|
|
233
233
|
chapterId?: undefined;
|
|
234
|
-
count?: undefined;
|
|
235
234
|
startAt?: undefined;
|
|
236
235
|
endAt?: undefined;
|
|
237
236
|
reason?: undefined;
|
|
238
237
|
includeMicrophone?: undefined;
|
|
239
238
|
includeSystemAudio?: undefined;
|
|
240
239
|
requestId?: undefined;
|
|
240
|
+
count?: undefined;
|
|
241
241
|
};
|
|
242
242
|
};
|
|
243
243
|
} | {
|
|
@@ -260,12 +260,12 @@ export declare function screenMemoryMcpToolDefinitions(): ({
|
|
|
260
260
|
description: string;
|
|
261
261
|
};
|
|
262
262
|
chapterId?: undefined;
|
|
263
|
-
count?: undefined;
|
|
264
263
|
startAt?: undefined;
|
|
265
264
|
endAt?: undefined;
|
|
266
265
|
includeMicrophone?: undefined;
|
|
267
266
|
includeSystemAudio?: undefined;
|
|
268
267
|
requestId?: undefined;
|
|
268
|
+
count?: undefined;
|
|
269
269
|
};
|
|
270
270
|
};
|
|
271
271
|
} | {
|
|
@@ -317,7 +317,6 @@ export declare function screenMemoryMcpToolDefinitions(): ({
|
|
|
317
317
|
clientHint?: undefined;
|
|
318
318
|
timestamp?: undefined;
|
|
319
319
|
chapterId?: undefined;
|
|
320
|
-
count?: undefined;
|
|
321
320
|
startAt: {
|
|
322
321
|
type: string;
|
|
323
322
|
description: string;
|
|
@@ -337,6 +336,7 @@ export declare function screenMemoryMcpToolDefinitions(): ({
|
|
|
337
336
|
type: string;
|
|
338
337
|
};
|
|
339
338
|
requestId?: undefined;
|
|
339
|
+
count?: undefined;
|
|
340
340
|
};
|
|
341
341
|
};
|
|
342
342
|
} | {
|
|
@@ -352,7 +352,6 @@ export declare function screenMemoryMcpToolDefinitions(): ({
|
|
|
352
352
|
clientHint?: undefined;
|
|
353
353
|
timestamp?: undefined;
|
|
354
354
|
chapterId?: undefined;
|
|
355
|
-
count?: undefined;
|
|
356
355
|
startAt?: undefined;
|
|
357
356
|
endAt?: undefined;
|
|
358
357
|
reason?: undefined;
|
|
@@ -361,6 +360,7 @@ export declare function screenMemoryMcpToolDefinitions(): ({
|
|
|
361
360
|
requestId: {
|
|
362
361
|
type: string;
|
|
363
362
|
};
|
|
363
|
+
count?: undefined;
|
|
364
364
|
};
|
|
365
365
|
};
|
|
366
366
|
})[];
|
package/dist/org/index.d.ts
CHANGED
|
@@ -22,7 +22,7 @@ export { offboardMember } from "../identity/offboard.js";
|
|
|
22
22
|
export type { OffboardMemberOptions, OffboardMemberResult, } from "../identity/offboard.js";
|
|
23
23
|
export { registerIdentityColumns } from "../identity/rekey.js";
|
|
24
24
|
export type { AppIdentityColumn, IdentityEmailChange, IdentityOffboard, IdentityOrgScope, } from "../identity/rekey.js";
|
|
25
|
-
export { claimWorkspaceAppForOrganization, isStandaloneDispatchRuntime, isWorkspaceAppAccessAllowed, } from "./workspace-app-access.js";
|
|
25
|
+
export { checkWorkspaceAppAccess, claimWorkspaceAppForOrganization, isStandaloneDispatchRuntime, isWorkspaceAppAccessAllowed, isWorkspaceAppAccessUnavailable, type WorkspaceAppAccessCheck, type WorkspaceAppAccessOutcome, type WorkspaceAppAccessUnavailable, } from "./workspace-app-access.js";
|
|
26
26
|
export { defineAppRoles, getRegisteredAppRoles, listRegisteredAppRoles, listAppMemberRoles, resolveAppRole, setAppMemberRole, setAppMemberRoles, applyInvitationAppRoles, getAppPermissionOverrides, setAppPermissionRoles, resolveAppAuthorizationContext, } from "./app-roles.js";
|
|
27
27
|
export type { AppRoles, AppRolesDescriptor, AppRoleCaller, AppPermissionPolicy, AppRoleLookup, AppMemberRoleRow, AppAuthorizationContext, } from "./app-roles.js";
|
|
28
28
|
export { ORG_MIGRATIONS } from "./migrations.js";
|
package/dist/org/index.js
CHANGED
|
@@ -32,7 +32,7 @@ export { invalidateMemberOrgCaches } from "./request-org-cache.js";
|
|
|
32
32
|
export { isMissingOrganizationTableError } from "./membership.js";
|
|
33
33
|
export { offboardMember } from "../identity/offboard.js";
|
|
34
34
|
export { registerIdentityColumns } from "../identity/rekey.js";
|
|
35
|
-
export { claimWorkspaceAppForOrganization, isStandaloneDispatchRuntime, isWorkspaceAppAccessAllowed, } from "./workspace-app-access.js";
|
|
35
|
+
export { checkWorkspaceAppAccess, claimWorkspaceAppForOrganization, isStandaloneDispatchRuntime, isWorkspaceAppAccessAllowed, isWorkspaceAppAccessUnavailable, } from "./workspace-app-access.js";
|
|
36
36
|
export { defineAppRoles, getRegisteredAppRoles, listRegisteredAppRoles, listAppMemberRoles, resolveAppRole, setAppMemberRole, setAppMemberRoles, applyInvitationAppRoles, getAppPermissionOverrides, setAppPermissionRoles, resolveAppAuthorizationContext, } from "./app-roles.js";
|
|
37
37
|
export { ORG_MIGRATIONS } from "./migrations.js";
|
|
38
38
|
export { CROSS_APP_ORG_FEDERATION_FLAG, CROSS_APP_ORG_FEDERATION_SCOPE, } from "./feature-flags.js";
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
export declare const WORKSPACE_APP_ACCESS_UNAVAILABLE: "unavailable";
|
|
2
|
+
export declare const WORKSPACE_APP_ACCESS_UNAVAILABLE_MESSAGE = "Workspace app access is temporarily unavailable.";
|
|
3
|
+
export type WorkspaceAppAccessUnavailableReason = "directory-url-invalid" | "org-domain-lookup-failed" | "org-domain-missing" | "a2a-secret-missing" | "token-signing-failed" | "registry-timeout" | "registry-fetch-failed" | "registry-http-error" | "registry-malformed-response" | "claim-http-error" | "claim-malformed-response";
|
|
4
|
+
/**
|
|
5
|
+
* The access check could not reach a verdict. Distinct from `false`: the
|
|
6
|
+
* caller is not refused, the answer is unknown, and `reason` says which step
|
|
7
|
+
* failed so a 503 can be traced without server logs.
|
|
8
|
+
*/
|
|
9
|
+
export interface WorkspaceAppAccessUnavailable {
|
|
10
|
+
status: typeof WORKSPACE_APP_ACCESS_UNAVAILABLE;
|
|
11
|
+
reason: WorkspaceAppAccessUnavailableReason;
|
|
12
|
+
/** HTTP status of the Dispatch registry reply, when one arrived. */
|
|
13
|
+
upstreamStatus?: number;
|
|
14
|
+
/** Audience the caller signed for: origin and path only, never userinfo. */
|
|
15
|
+
audience?: string;
|
|
16
|
+
/** Short text from the upstream reply or error class. Untrusted. */
|
|
17
|
+
detail?: string;
|
|
18
|
+
}
|
|
19
|
+
/** What `isWorkspaceAppAccessAllowed` has always returned. */
|
|
20
|
+
export type WorkspaceAppAccessOutcome = boolean | typeof WORKSPACE_APP_ACCESS_UNAVAILABLE;
|
|
21
|
+
/** A verdict, or the cause when none could be reached. */
|
|
22
|
+
export type WorkspaceAppAccessCheck = boolean | WorkspaceAppAccessUnavailable;
|
|
23
|
+
export declare function isWorkspaceAppAccessUnavailable(outcome: unknown): outcome is WorkspaceAppAccessUnavailable;
|
|
24
|
+
export declare function workspaceAppAccessUnavailable(reason: WorkspaceAppAccessUnavailableReason, extra?: Pick<WorkspaceAppAccessUnavailable, "upstreamStatus" | "audience" | "detail">): WorkspaceAppAccessUnavailable;
|
|
25
|
+
export declare function workspaceAppAccessUnavailableBody(outcome: WorkspaceAppAccessUnavailable): {
|
|
26
|
+
error: string;
|
|
27
|
+
code: WorkspaceAppAccessUnavailableReason;
|
|
28
|
+
upstreamStatus?: number;
|
|
29
|
+
audience?: string;
|
|
30
|
+
detail?: string;
|
|
31
|
+
};
|
|
32
|
+
/**
|
|
33
|
+
* Names a thrown error without echoing its message: driver and upstream
|
|
34
|
+
* messages can carry hostnames or connection strings.
|
|
35
|
+
*/
|
|
36
|
+
export declare function describeFetchFailure(error: unknown): {
|
|
37
|
+
timedOut: boolean;
|
|
38
|
+
detail: string;
|
|
39
|
+
};
|
|
40
|
+
/**
|
|
41
|
+
* Reads the human-readable refusal out of a registry error reply, if it sent
|
|
42
|
+
* JSON. A non-JSON or unreadable body yields no detail; the HTTP status on the
|
|
43
|
+
* outcome already says the call failed.
|
|
44
|
+
*/
|
|
45
|
+
export declare function registryErrorDetail(body: unknown): string | undefined;
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
export const WORKSPACE_APP_ACCESS_UNAVAILABLE = "unavailable";
|
|
2
|
+
export const WORKSPACE_APP_ACCESS_UNAVAILABLE_MESSAGE = "Workspace app access is temporarily unavailable.";
|
|
3
|
+
const MAX_DETAIL_LENGTH = 160;
|
|
4
|
+
export function isWorkspaceAppAccessUnavailable(outcome) {
|
|
5
|
+
return (typeof outcome === "object" &&
|
|
6
|
+
outcome !== null &&
|
|
7
|
+
outcome.status ===
|
|
8
|
+
WORKSPACE_APP_ACCESS_UNAVAILABLE);
|
|
9
|
+
}
|
|
10
|
+
export function workspaceAppAccessUnavailable(reason, extra = {}) {
|
|
11
|
+
const detail = boundedDetail(extra.detail);
|
|
12
|
+
return {
|
|
13
|
+
status: WORKSPACE_APP_ACCESS_UNAVAILABLE,
|
|
14
|
+
reason,
|
|
15
|
+
...(extra.upstreamStatus === undefined
|
|
16
|
+
? {}
|
|
17
|
+
: { upstreamStatus: extra.upstreamStatus }),
|
|
18
|
+
...(extra.audience ? { audience: extra.audience } : {}),
|
|
19
|
+
...(detail ? { detail } : {}),
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
export function workspaceAppAccessUnavailableBody(outcome) {
|
|
23
|
+
return {
|
|
24
|
+
error: WORKSPACE_APP_ACCESS_UNAVAILABLE_MESSAGE,
|
|
25
|
+
code: outcome.reason,
|
|
26
|
+
...(outcome.upstreamStatus === undefined
|
|
27
|
+
? {}
|
|
28
|
+
: { upstreamStatus: outcome.upstreamStatus }),
|
|
29
|
+
...(outcome.audience ? { audience: outcome.audience } : {}),
|
|
30
|
+
...(outcome.detail ? { detail: outcome.detail } : {}),
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Names a thrown error without echoing its message: driver and upstream
|
|
35
|
+
* messages can carry hostnames or connection strings.
|
|
36
|
+
*/
|
|
37
|
+
export function describeFetchFailure(error) {
|
|
38
|
+
const name = error instanceof Error ? error.name : "UnknownError";
|
|
39
|
+
const cause = error instanceof Error ? error.cause : undefined;
|
|
40
|
+
const code = cause && typeof cause.code === "string"
|
|
41
|
+
? cause.code
|
|
42
|
+
: "";
|
|
43
|
+
return {
|
|
44
|
+
timedOut: name === "AbortError" || name === "TimeoutError",
|
|
45
|
+
detail: code ? `${name}:${code}` : name,
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Reads the human-readable refusal out of a registry error reply, if it sent
|
|
50
|
+
* JSON. A non-JSON or unreadable body yields no detail; the HTTP status on the
|
|
51
|
+
* outcome already says the call failed.
|
|
52
|
+
*/
|
|
53
|
+
export function registryErrorDetail(body) {
|
|
54
|
+
if (!body || typeof body !== "object")
|
|
55
|
+
return undefined;
|
|
56
|
+
const record = body;
|
|
57
|
+
for (const candidate of [
|
|
58
|
+
record.error,
|
|
59
|
+
record.statusMessage,
|
|
60
|
+
record.message,
|
|
61
|
+
]) {
|
|
62
|
+
if (typeof candidate === "string" && candidate.trim())
|
|
63
|
+
return candidate;
|
|
64
|
+
}
|
|
65
|
+
return undefined;
|
|
66
|
+
}
|
|
67
|
+
function boundedDetail(value) {
|
|
68
|
+
if (!value)
|
|
69
|
+
return undefined;
|
|
70
|
+
const collapsed = value
|
|
71
|
+
// eslint-disable-next-line no-control-regex
|
|
72
|
+
.replace(/[\u0000-\u001f\u007f]+/g, " ")
|
|
73
|
+
.replace(/\s+/g, " ")
|
|
74
|
+
.trim();
|
|
75
|
+
if (!collapsed)
|
|
76
|
+
return undefined;
|
|
77
|
+
return collapsed.length > MAX_DETAIL_LENGTH
|
|
78
|
+
? `${collapsed.slice(0, MAX_DETAIL_LENGTH)}…`
|
|
79
|
+
: collapsed;
|
|
80
|
+
}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { type
|
|
1
|
+
import { type WorkspaceAppAccessCheck } from "./workspace-app-access.js";
|
|
2
2
|
export type WorkspaceAppAccessRequest = {
|
|
3
3
|
path: string;
|
|
4
4
|
method: string;
|
|
5
5
|
email: string;
|
|
6
6
|
orgId?: string | null;
|
|
7
7
|
};
|
|
8
|
-
export declare function checkWorkspaceAppAccessForRequest(request: WorkspaceAppAccessRequest): Promise<
|
|
8
|
+
export declare function checkWorkspaceAppAccessForRequest(request: WorkspaceAppAccessRequest): Promise<WorkspaceAppAccessCheck | null>;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { checkWorkspaceAppAccess, } from "./workspace-app-access.js";
|
|
2
2
|
import { resolveWorkspaceAccessAppId } from "./workspace-app-identity.js";
|
|
3
3
|
function isWorkspaceAccessRecoveryPath(path, method) {
|
|
4
4
|
return (path === "/_agent-native/org/me" ||
|
|
@@ -13,7 +13,7 @@ export async function checkWorkspaceAppAccessForRequest(request) {
|
|
|
13
13
|
if (!appId || isWorkspaceAccessRecoveryPath(request.path, request.method)) {
|
|
14
14
|
return null;
|
|
15
15
|
}
|
|
16
|
-
return
|
|
16
|
+
return checkWorkspaceAppAccess(appId, {
|
|
17
17
|
email: request.email,
|
|
18
18
|
orgId: request.orgId,
|
|
19
19
|
});
|
|
@@ -1,10 +1,15 @@
|
|
|
1
|
-
|
|
2
|
-
export
|
|
3
|
-
export type WorkspaceAppAccessOutcome = boolean | typeof WORKSPACE_APP_ACCESS_UNAVAILABLE;
|
|
1
|
+
import { type WorkspaceAppAccessCheck, type WorkspaceAppAccessOutcome } from "./workspace-app-access-outcome.js";
|
|
2
|
+
export { WORKSPACE_APP_ACCESS_UNAVAILABLE, WORKSPACE_APP_ACCESS_UNAVAILABLE_MESSAGE, isWorkspaceAppAccessUnavailable, workspaceAppAccessUnavailableBody, type WorkspaceAppAccessCheck, type WorkspaceAppAccessOutcome, type WorkspaceAppAccessUnavailable, type WorkspaceAppAccessUnavailableReason, } from "./workspace-app-access-outcome.js";
|
|
4
3
|
export interface WorkspaceAppAccessContext {
|
|
5
4
|
email: string;
|
|
6
5
|
orgId?: string | null;
|
|
7
6
|
}
|
|
8
7
|
export declare function isStandaloneDispatchRuntime(): boolean;
|
|
9
8
|
export declare function claimWorkspaceAppForOrganization(appId: string, context: WorkspaceAppAccessContext): Promise<boolean>;
|
|
9
|
+
/**
|
|
10
|
+
* Keeps the contract this function has always had: `true`, `false`, or the
|
|
11
|
+
* `"unavailable"` sentinel. Use `checkWorkspaceAppAccess` to learn why a verdict
|
|
12
|
+
* could not be reached.
|
|
13
|
+
*/
|
|
10
14
|
export declare function isWorkspaceAppAccessAllowed(appId: string, context: WorkspaceAppAccessContext): Promise<WorkspaceAppAccessOutcome>;
|
|
15
|
+
export declare function checkWorkspaceAppAccess(appId: string, context: WorkspaceAppAccessContext): Promise<WorkspaceAppAccessCheck>;
|