@opengeni/api-router 1.2.1-canary.37222965366001 → 1.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/app.js +1 -1
- package/dist/{chunk-Q77DZ2M4.js → chunk-IZEGLLKZ.js} +1236 -468
- package/dist/{chunk-Q77DZ2M4.js.map → chunk-IZEGLLKZ.js.map} +1 -1
- package/dist/codemode.d.ts +3 -1
- package/dist/fatal-process-boundary.d.ts +9 -1
- package/dist/http/api-error.d.ts +11 -0
- package/dist/index.js +40 -1
- package/dist/index.js.map +1 -1
- package/dist/integrations/slack-bot.d.ts +72 -1
- package/dist/integrations/slack-tool-review.d.ts +5 -0
- package/dist/mcp/action-catalog-types.d.ts +5 -0
- package/dist/mcp/scheduled-task-view.d.ts +191 -0
- package/dist/mcp/server.d.ts +1 -1
- package/dist/organization-mcp.d.ts +8 -0
- package/dist/routes/client-errors.d.ts +1 -0
- package/dist/routes/organization-integration-policy.d.ts +6 -1
- package/dist/routes/slack-bot-access.d.ts +3 -0
- package/package.json +20 -20
- package/src/app.ts +38 -1
- package/src/auth/managed-auth-session-adapter.ts +8 -2
- package/src/auth/managed-auth.ts +19 -0
- package/src/codemode.ts +14 -7
- package/src/fatal-process-boundary.ts +50 -1
- package/src/http/api-error.ts +26 -1
- package/src/integrations/slack-bot.ts +276 -23
- package/src/integrations/slack-interactions.ts +177 -11
- package/src/integrations/slack-tool-review.ts +65 -0
- package/src/mcp/action-catalog-types.ts +5 -0
- package/src/mcp/action-catalog.gen.ts +85 -19
- package/src/mcp/scheduled-task-view.ts +10 -0
- package/src/mcp/server.ts +38 -16
- package/src/organization-mcp.ts +63 -3
- package/src/routes/api-integrations.ts +0 -17
- package/src/routes/capabilities.ts +2 -0
- package/src/routes/codex.ts +25 -12
- package/src/routes/managed-auth-session-sets.ts +11 -5
- package/src/routes/organization-integration-policy.ts +4 -4
- package/src/routes/sessions.ts +44 -0
- package/src/routes/slack-bot-access.ts +108 -0
- package/src/workspace-tool-gateway.ts +90 -4
|
@@ -511,13 +511,19 @@ async function requireRedemptionHuman(c, deps, workspaceId) {
|
|
|
511
511
|
message: "reset redemption requires managed product mode"
|
|
512
512
|
});
|
|
513
513
|
}
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
514
|
+
const agent = isAgentActingAsPerson(c) ? agentActingAsPersonBeforeGrantCheck(c) : null;
|
|
515
|
+
if (!agent) {
|
|
516
|
+
if (c.req.header("authorization")) {
|
|
517
|
+
throw new HTTPException4(403, {
|
|
518
|
+
message: "authorization bearer is not allowed for redemption"
|
|
519
|
+
});
|
|
520
|
+
}
|
|
521
|
+
requireSameOriginBrowserMutation(c, deps);
|
|
518
522
|
}
|
|
519
|
-
|
|
520
|
-
|
|
523
|
+
const human = agent ? {
|
|
524
|
+
subjectId: agent.subjectId,
|
|
525
|
+
browserSessionHash: await hashCodexBrowserSession(`agent:${agent.subjectId}`)
|
|
526
|
+
} : await managedCookieHuman(c, deps);
|
|
521
527
|
if (!human) {
|
|
522
528
|
throw new HTTPException4(401, {
|
|
523
529
|
message: "managed browser session required"
|
|
@@ -5239,9 +5245,11 @@ import {
|
|
|
5239
5245
|
} from "@opengeni/contracts";
|
|
5240
5246
|
import { hasPermission as hasPermission3, isDeveloperSetupGrant, requireSessionAuthorization as requireSessionAuthorization2 } from "@opengeni/core";
|
|
5241
5247
|
import {
|
|
5248
|
+
CodemodeToolApprovalRequiredError,
|
|
5242
5249
|
getActiveSessionTurnForExecution,
|
|
5243
5250
|
getAttemptToolCatalog,
|
|
5244
5251
|
getCodemodeOperation,
|
|
5252
|
+
readTurnCodemodeOperation,
|
|
5245
5253
|
submitCodemodeOperation
|
|
5246
5254
|
} from "@opengeni/db";
|
|
5247
5255
|
import { getSession } from "@opengeni/db";
|
|
@@ -5672,11 +5680,12 @@ async function requireActiveCodemodeCatalog(deps, grant) {
|
|
|
5672
5680
|
return { authority, catalog, turn: active };
|
|
5673
5681
|
}
|
|
5674
5682
|
async function submitAndDispatchCodemodeCall(deps, grant, rawRequest) {
|
|
5675
|
-
const request = CodemodeCallRequest.parse(rawRequest);
|
|
5683
|
+
const { durableApproval, ...request } = CodemodeCallRequest.parse(rawRequest);
|
|
5676
5684
|
const { authority, catalog } = await requireActiveCodemodeCatalog(deps, grant);
|
|
5677
5685
|
if (request.catalogDigest !== catalog.digest) throw new CodemodeCatalogStaleError();
|
|
5678
5686
|
const submitted = await submitCodemodeOperation(deps.db, {
|
|
5679
5687
|
...authority,
|
|
5688
|
+
...durableApproval ? { durableApproval: true } : {},
|
|
5680
5689
|
call: {
|
|
5681
5690
|
...request,
|
|
5682
5691
|
caller: { kind: "codemode", subjectId: authority.subjectId }
|
|
@@ -5718,15 +5727,18 @@ async function submitAndDispatchCodemodeCall(deps, grant, rawRequest) {
|
|
|
5718
5727
|
function codemodeOperationNeedsDispatch(operation) {
|
|
5719
5728
|
return operation.state === "queued" || operation.state === "running";
|
|
5720
5729
|
}
|
|
5721
|
-
async function readCodemodeOperation(deps, grant, operationId) {
|
|
5722
|
-
|
|
5723
|
-
const
|
|
5724
|
-
|
|
5725
|
-
|
|
5726
|
-
workspaceId: authority.workspaceId,
|
|
5727
|
-
attemptId: authority.attemptId,
|
|
5730
|
+
async function readCodemodeOperation(deps, grant, operationId, options = {}) {
|
|
5731
|
+
const { authority } = await requireActiveCodemodeCatalog(deps, grant);
|
|
5732
|
+
const operation = await readTurnCodemodeOperation(deps.db, {
|
|
5733
|
+
...authority,
|
|
5734
|
+
callerSubjectId: authority.subjectId,
|
|
5728
5735
|
operationId
|
|
5729
5736
|
});
|
|
5737
|
+
if (operation?.state === "waiting_for_approval" && !options.durableApproval)
|
|
5738
|
+
throw new CodemodeToolApprovalRequiredError();
|
|
5739
|
+
if (!operation || options.durableApproval) return operation;
|
|
5740
|
+
const { durableApproval: _capability, approvalRequestId: _requestId, ...legacy } = operation;
|
|
5741
|
+
return legacy;
|
|
5730
5742
|
}
|
|
5731
5743
|
function terminal(operation) {
|
|
5732
5744
|
return ["completed", "failed", "outcome_unknown", "cancelled"].includes(operation.state);
|
|
@@ -6502,6 +6514,7 @@ function registerModelConnectionAccessRoutes(app, deps) {
|
|
|
6502
6514
|
import {
|
|
6503
6515
|
codeSearchDeploymentPolicy,
|
|
6504
6516
|
agentConfigDeploymentPolicy,
|
|
6517
|
+
canonicalPublicOrigin as canonicalPublicOrigin3,
|
|
6505
6518
|
configuredAllowedReasoningEfforts,
|
|
6506
6519
|
resolveFirstPartyMcpToolPolicy as resolveFirstPartyMcpToolPolicy2,
|
|
6507
6520
|
resolveVoiceInputProviderRegistry as resolveVoiceInputProviderRegistry2,
|
|
@@ -6532,7 +6545,8 @@ import {
|
|
|
6532
6545
|
CodemodeOperationConflictError,
|
|
6533
6546
|
CodemodeOperationNotExecutableError,
|
|
6534
6547
|
CodemodePayloadTooLargeError,
|
|
6535
|
-
|
|
6548
|
+
CodemodeOperationLimitError,
|
|
6549
|
+
CodemodeToolApprovalRequiredError as CodemodeToolApprovalRequiredError2,
|
|
6536
6550
|
CodemodeToolNotInCatalogError,
|
|
6537
6551
|
ConnectAttemptConflictError,
|
|
6538
6552
|
ConnectAttemptNotFoundError,
|
|
@@ -6588,7 +6602,7 @@ import { bodyLimit as bodyLimit3 } from "hono/body-limit";
|
|
|
6588
6602
|
import { compress } from "hono/compress";
|
|
6589
6603
|
import { cors } from "hono/cors";
|
|
6590
6604
|
import { getCookie as getCookie3 } from "hono/cookie";
|
|
6591
|
-
import { HTTPException as
|
|
6605
|
+
import { HTTPException as HTTPException118 } from "hono/http-exception";
|
|
6592
6606
|
|
|
6593
6607
|
// src/http/api-error.ts
|
|
6594
6608
|
import {
|
|
@@ -6597,7 +6611,7 @@ import {
|
|
|
6597
6611
|
ModelUnavailableError,
|
|
6598
6612
|
ScheduledTaskTargetAccessChange
|
|
6599
6613
|
} from "@opengeni/contracts";
|
|
6600
|
-
import { WorkspaceControlBusyError } from "@opengeni/db";
|
|
6614
|
+
import { isDatabaseConnectionLoss, WorkspaceControlBusyError } from "@opengeni/db";
|
|
6601
6615
|
import { HTTPException as HTTPException20 } from "hono/http-exception";
|
|
6602
6616
|
var ApiHttpError = class extends HTTPException20 {
|
|
6603
6617
|
code;
|
|
@@ -6650,6 +6664,20 @@ function workspaceControlBusyHttpError(error) {
|
|
|
6650
6664
|
details: { code: busy.code, lockTimeoutMs: busy.lockTimeoutMs }
|
|
6651
6665
|
});
|
|
6652
6666
|
}
|
|
6667
|
+
var DATABASE_UNAVAILABLE_ERROR_DETAIL_CODE = "DATABASE_UNAVAILABLE";
|
|
6668
|
+
function databaseUnavailableHttpError(error, method) {
|
|
6669
|
+
if (error instanceof ApiHttpError) return null;
|
|
6670
|
+
if (error instanceof HTTPException20 && error.status < 500) return null;
|
|
6671
|
+
if (!isDatabaseConnectionLoss(error)) return null;
|
|
6672
|
+
const safeMethod = method === "GET" || method === "HEAD" || method === "OPTIONS";
|
|
6673
|
+
return new ApiHttpError(503, {
|
|
6674
|
+
code: "upstream_unavailable",
|
|
6675
|
+
message: "Opengeni is temporarily unavailable. Retry shortly.",
|
|
6676
|
+
retryable: true,
|
|
6677
|
+
outcomeUnknown: !safeMethod,
|
|
6678
|
+
details: { code: DATABASE_UNAVAILABLE_ERROR_DETAIL_CODE }
|
|
6679
|
+
});
|
|
6680
|
+
}
|
|
6653
6681
|
function agentConfigHttpError(error) {
|
|
6654
6682
|
const cause = error instanceof AgentConfigError ? error : error instanceof HTTPException20 && error.cause instanceof AgentConfigError ? error.cause : null;
|
|
6655
6683
|
if (!cause) return null;
|
|
@@ -7037,7 +7065,7 @@ import {
|
|
|
7037
7065
|
CodexCompactionV2ProviderLockedError,
|
|
7038
7066
|
ManagedAuthActorLeaseOutcomeUnknownError,
|
|
7039
7067
|
hasPermission as hasPermission34,
|
|
7040
|
-
requireAccessGrant as
|
|
7068
|
+
requireAccessGrant as requireAccessGrant54,
|
|
7041
7069
|
requireAccessGrantAuthorization as requireAccessGrantAuthorization40,
|
|
7042
7070
|
accountScopedApiKeyWorkspaceAuthority as accountScopedApiKeyWorkspaceAuthority10,
|
|
7043
7071
|
requireAccessContext as requireAccessContext15,
|
|
@@ -7090,7 +7118,8 @@ function createManagedAuthNewSignupsGate(input) {
|
|
|
7090
7118
|
import { canonicalPublicOrigin, managedUserEmailAllowed } from "@opengeni/config";
|
|
7091
7119
|
import { MANAGED_AUTH_NEW_SIGNUPS_PAUSED_CODE } from "@opengeni/contracts";
|
|
7092
7120
|
import {
|
|
7093
|
-
configureManagedUserAdmission
|
|
7121
|
+
configureManagedUserAdmission,
|
|
7122
|
+
recordManagedAuthLoggedFailure
|
|
7094
7123
|
} from "@opengeni/core";
|
|
7095
7124
|
import { ensureManagedAccessForUser } from "@opengeni/db";
|
|
7096
7125
|
import {
|
|
@@ -8676,6 +8705,13 @@ async function hashManagedAuthPassword(password) {
|
|
|
8676
8705
|
async function verifyManagedAuthPassword(password, hash) {
|
|
8677
8706
|
return await verifyPassword({ password, hash });
|
|
8678
8707
|
}
|
|
8708
|
+
function logBetterAuthMessage(level, message, ...args) {
|
|
8709
|
+
if (level === "error") recordManagedAuthLoggedFailure(args);
|
|
8710
|
+
const line = `${(/* @__PURE__ */ new Date()).toISOString()} ${level.toUpperCase()} [Better Auth]: ${message}`;
|
|
8711
|
+
if (level === "error") console.error(line, ...args);
|
|
8712
|
+
else if (level === "warn") console.warn(line, ...args);
|
|
8713
|
+
else console.log(line, ...args);
|
|
8714
|
+
}
|
|
8679
8715
|
var MANAGED_AUTH_DATABASE_POOL_OPTIONS = {
|
|
8680
8716
|
max: 10,
|
|
8681
8717
|
connectionTimeoutMillis: 1e4,
|
|
@@ -8731,6 +8767,7 @@ function createManagedAuth(settings, db, managedEmailTransport, options = {}) {
|
|
|
8731
8767
|
secret: settings.betterAuthSecret,
|
|
8732
8768
|
database: pool,
|
|
8733
8769
|
trustedOrigins: betterAuthTrustedOrigins(settings),
|
|
8770
|
+
logger: { log: logBetterAuthMessage },
|
|
8734
8771
|
hooks: {
|
|
8735
8772
|
before: createManagedAuthEmailThrottleHook(
|
|
8736
8773
|
db,
|
|
@@ -9216,7 +9253,10 @@ import {
|
|
|
9216
9253
|
} from "@opengeni/core/managed-auth-session-sets";
|
|
9217
9254
|
|
|
9218
9255
|
// src/auth/managed-auth-session-adapter.ts
|
|
9219
|
-
import {
|
|
9256
|
+
import {
|
|
9257
|
+
assertManagedUserAdmission,
|
|
9258
|
+
withManagedAuthSessionLookup
|
|
9259
|
+
} from "@opengeni/core";
|
|
9220
9260
|
import { createHmac as createHmac5, timingSafeEqual as timingSafeEqual2 } from "crypto";
|
|
9221
9261
|
async function managedAuthSelectedProofHeaders(auth, token) {
|
|
9222
9262
|
const context = await auth.$context;
|
|
@@ -9275,7 +9315,9 @@ function createBetterAuthSessionAdapter(auth, db) {
|
|
|
9275
9315
|
const headers = new Headers({
|
|
9276
9316
|
cookie: `${cookie.name}=${signedCookieValue(input.token, context.secret)}`
|
|
9277
9317
|
});
|
|
9278
|
-
const resolved = await
|
|
9318
|
+
const resolved = await withManagedAuthSessionLookup(
|
|
9319
|
+
() => auth.api.getSession({ headers, returnHeaders: true })
|
|
9320
|
+
);
|
|
9279
9321
|
if (!resolved.response) return null;
|
|
9280
9322
|
assertManagedUserAdmission(auth, resolved.response.user);
|
|
9281
9323
|
return resolved.response;
|
|
@@ -13959,6 +14001,7 @@ async function withOptionalSiteCommandOrigin(db, workspaceId, siteId, versionId,
|
|
|
13959
14001
|
|
|
13960
14002
|
// src/workspace-tool-gateway.ts
|
|
13961
14003
|
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
|
|
14004
|
+
import { recordToolApproval } from "@opengeni/observability";
|
|
13962
14005
|
import {
|
|
13963
14006
|
CallToolRequestSchema,
|
|
13964
14007
|
ListToolsRequestSchema
|
|
@@ -13971,7 +14014,8 @@ import {
|
|
|
13971
14014
|
ToolGatewayCallResponse,
|
|
13972
14015
|
ToolGatewayApprovalRequest,
|
|
13973
14016
|
ToolGatewayApprovalResponse,
|
|
13974
|
-
ToolGatewayDeclarationsResponse
|
|
14017
|
+
ToolGatewayDeclarationsResponse,
|
|
14018
|
+
toolPolicyActionName
|
|
13975
14019
|
} from "@opengeni/contracts";
|
|
13976
14020
|
import {
|
|
13977
14021
|
availableMcpAccountBindings,
|
|
@@ -14000,13 +14044,18 @@ import {
|
|
|
14000
14044
|
issueToolGatewayApproval,
|
|
14001
14045
|
ToolGatewayApprovalOperationStartedError,
|
|
14002
14046
|
ToolGatewayApprovalRateLimitError,
|
|
14003
|
-
WorkspaceArtifactNotFoundError as WorkspaceArtifactNotFoundError2
|
|
14047
|
+
WorkspaceArtifactNotFoundError as WorkspaceArtifactNotFoundError2,
|
|
14048
|
+
listConnectorToolPermissionPolicies,
|
|
14049
|
+
projectConnectorToolPermission,
|
|
14050
|
+
resolveConnectorActionPolicy,
|
|
14051
|
+
connectorActionPolicyDecision
|
|
14004
14052
|
} from "@opengeni/db";
|
|
14005
14053
|
import {
|
|
14006
14054
|
prepareWorkspaceToolGatewayTools
|
|
14007
14055
|
} from "@opengeni/runtime/workspace-tool-gateway";
|
|
14008
14056
|
import {
|
|
14009
14057
|
ToolGatewayApprovalRequiredError,
|
|
14058
|
+
ToolGatewayBlockedError,
|
|
14010
14059
|
ToolGatewayCatalogStaleError,
|
|
14011
14060
|
ToolGatewayInputValidationError,
|
|
14012
14061
|
ToolGatewayToolNotFoundError,
|
|
@@ -14403,6 +14452,32 @@ async function prepareWorkspaceToolGatewayForGrantInternal(routeDeps, grant, all
|
|
|
14403
14452
|
};
|
|
14404
14453
|
})() : void 0;
|
|
14405
14454
|
const localMcpServers = [...firstPartyServers, ...apiIntegrationServers];
|
|
14455
|
+
const policyTargets = new Map(
|
|
14456
|
+
gatewaySettings.mcpServers.map((config) => {
|
|
14457
|
+
const binding = accountBindings.find((candidate) => candidate.serverId === config.id);
|
|
14458
|
+
return [
|
|
14459
|
+
config.id,
|
|
14460
|
+
{
|
|
14461
|
+
connectionId: binding?.connectionId ?? config.connectionRef?.connectionId ?? `session-mcp:${config.id}:${createHash3("sha256").update(config.url, "utf8").digest("hex")}`,
|
|
14462
|
+
serverId: binding?.canonicalServerId ?? config.id
|
|
14463
|
+
}
|
|
14464
|
+
];
|
|
14465
|
+
})
|
|
14466
|
+
);
|
|
14467
|
+
const policiesByServer = new Map(
|
|
14468
|
+
await Promise.all(
|
|
14469
|
+
[...policyTargets].map(
|
|
14470
|
+
async ([id, target2]) => [
|
|
14471
|
+
id,
|
|
14472
|
+
await listConnectorToolPermissionPolicies(routeDeps.db, {
|
|
14473
|
+
...grant,
|
|
14474
|
+
connectionId: target2.connectionId
|
|
14475
|
+
})
|
|
14476
|
+
]
|
|
14477
|
+
)
|
|
14478
|
+
)
|
|
14479
|
+
);
|
|
14480
|
+
const recommendations = /* @__PURE__ */ new Map();
|
|
14406
14481
|
const prepared = await prepareWorkspaceToolGatewayTools(
|
|
14407
14482
|
gatewaySettings,
|
|
14408
14483
|
allGatewayToolRefs(gatewaySettings),
|
|
@@ -14417,7 +14492,43 @@ async function prepareWorkspaceToolGatewayForGrantInternal(routeDeps, grant, all
|
|
|
14417
14492
|
localMcpServers,
|
|
14418
14493
|
...codexAppsAuth ? { codexAppsAuth } : {},
|
|
14419
14494
|
workspaceToolGateway: {
|
|
14420
|
-
|
|
14495
|
+
mapDefinition: (definition) => {
|
|
14496
|
+
const recommendation = definition.approval === "human" ? "ask" : "allow";
|
|
14497
|
+
recommendations.set(workspaceToolGatewayIdentityKey(definition.identity), recommendation);
|
|
14498
|
+
const target2 = policyTargets.get(definition.identity.serverId);
|
|
14499
|
+
if (!target2) return definition;
|
|
14500
|
+
const permission = projectConnectorToolPermission(
|
|
14501
|
+
policiesByServer.get(definition.identity.serverId) ?? [],
|
|
14502
|
+
{
|
|
14503
|
+
...target2,
|
|
14504
|
+
toolName: definition.identity.toolName,
|
|
14505
|
+
defaultDecision: recommendation
|
|
14506
|
+
}
|
|
14507
|
+
);
|
|
14508
|
+
return { ...definition, approval: permission.approvalRequired ? "human" : "policy" };
|
|
14509
|
+
},
|
|
14510
|
+
resolveApproval: async ({ call, entry: entry2 }) => {
|
|
14511
|
+
const defaultDecision = recommendations.get(workspaceToolGatewayIdentityKey(entry2.identity)) ?? (entry2.approval === "human" ? "ask" : "allow");
|
|
14512
|
+
const target2 = policyTargets.get(entry2.identity.serverId);
|
|
14513
|
+
if (!target2) return defaultDecision;
|
|
14514
|
+
const policies = await listConnectorToolPermissionPolicies(routeDeps.db, {
|
|
14515
|
+
...grant,
|
|
14516
|
+
connectionId: target2.connectionId
|
|
14517
|
+
});
|
|
14518
|
+
const resolved = resolveConnectorActionPolicy(policies, {
|
|
14519
|
+
...target2,
|
|
14520
|
+
toolName: entry2.identity.toolName,
|
|
14521
|
+
defaultDecision,
|
|
14522
|
+
actionName: toolPolicyActionName(
|
|
14523
|
+
entry2.identity.toolName,
|
|
14524
|
+
entry2.inputSchema,
|
|
14525
|
+
call.arguments
|
|
14526
|
+
)
|
|
14527
|
+
});
|
|
14528
|
+
const decision = !resolved.managed ? defaultDecision : connectorActionPolicyDecision(resolved);
|
|
14529
|
+
recordToolApproval(decision, resolved.managed ? resolved.source : "default");
|
|
14530
|
+
return decision;
|
|
14531
|
+
},
|
|
14421
14532
|
filterDefinition: workspaceToolGatewayDefinitionFilter(gatewaySettings, allowedIdentities)
|
|
14422
14533
|
}
|
|
14423
14534
|
}
|
|
@@ -14559,7 +14670,7 @@ async function callWorkspaceToolGateway(prepared, grant, input, db, consumeAppro
|
|
|
14559
14670
|
);
|
|
14560
14671
|
await prepared.reauthorize?.();
|
|
14561
14672
|
let approvalConfirmed = false;
|
|
14562
|
-
const approvalRequired = preparedCall.entry.approval === "human";
|
|
14673
|
+
const approvalRequired = preparedCall.approvalDecision === "ask" || preparedCall.approvalDecision === void 0 && preparedCall.entry.approval === "human";
|
|
14563
14674
|
if (approvalRequired && request.approvalToken && db) {
|
|
14564
14675
|
approvalConfirmed = await consumeApproval(db, {
|
|
14565
14676
|
tokenHash: hashOpaqueValue(request.approvalToken),
|
|
@@ -14614,7 +14725,7 @@ async function approveWorkspaceToolGatewayCall(prepared, grant, db, input, issue
|
|
|
14614
14725
|
} catch (error) {
|
|
14615
14726
|
throwWorkspaceToolGatewayHttpError(error);
|
|
14616
14727
|
}
|
|
14617
|
-
if (preparedCall.entry.approval
|
|
14728
|
+
if (preparedCall.approvalDecision !== "ask" && !(preparedCall.approvalDecision === void 0 && preparedCall.entry.approval === "human")) {
|
|
14618
14729
|
throw new HTTPException24(422, { message: "tool_does_not_require_human_approval" });
|
|
14619
14730
|
}
|
|
14620
14731
|
const observation = startWorkspaceToolGatewayObservation(observability, {
|
|
@@ -14698,6 +14809,9 @@ function throwWorkspaceToolGatewayHttpError(error) {
|
|
|
14698
14809
|
if (error instanceof ToolGatewayApprovalRequiredError) {
|
|
14699
14810
|
throw new HTTPException24(409, { message: error.code, cause: error });
|
|
14700
14811
|
}
|
|
14812
|
+
if (error instanceof ToolGatewayBlockedError) {
|
|
14813
|
+
throw new HTTPException24(403, { message: error.code, cause: error });
|
|
14814
|
+
}
|
|
14701
14815
|
if (error instanceof IntegrationInvocationError && error.outcome === "unknown") {
|
|
14702
14816
|
throw new ApiHttpError(502, {
|
|
14703
14817
|
code: "upstream_unavailable",
|
|
@@ -21883,7 +21997,16 @@ function buildScheduledTaskDetailMcp(task, budget, reducedForBytes) {
|
|
|
21883
21997
|
maxAutoContinuations: task.agentConfig.goal?.maxAutoContinuations ?? null
|
|
21884
21998
|
} : null
|
|
21885
21999
|
},
|
|
21886
|
-
taskMetadataKeys
|
|
22000
|
+
taskMetadataKeys,
|
|
22001
|
+
slackPosting: {
|
|
22002
|
+
identity: task.agentConfig.slackBotConnectionId ? "opengeni_bot" : null,
|
|
22003
|
+
connectionId: task.agentConfig.slackBotConnectionId ?? null,
|
|
22004
|
+
channelId: task.agentConfig.slackBotChannelId ?? null,
|
|
22005
|
+
configured: Boolean(
|
|
22006
|
+
task.agentConfig.slackBotConnectionId && task.agentConfig.slackBotChannelId
|
|
22007
|
+
),
|
|
22008
|
+
setup: "A person can choose Post to Slack in the schedule editor. Personal Slack tools send as their connected account; they do not select the Opengeni bot."
|
|
22009
|
+
}
|
|
21887
22010
|
},
|
|
21888
22011
|
detailProjection: {
|
|
21889
22012
|
bounded: true,
|
|
@@ -22906,6 +23029,7 @@ import {
|
|
|
22906
23029
|
hasOpenGeniSlackReactionScope
|
|
22907
23030
|
} from "@opengeni/contracts";
|
|
22908
23031
|
import {
|
|
23032
|
+
grantHasAgentAttemptAuthority as grantHasAgentAttemptAuthority2,
|
|
22909
23033
|
isOpenGeniSlackBotConnection,
|
|
22910
23034
|
isTrustedScheduledSlackBotSession,
|
|
22911
23035
|
openGeniSlackBotMetadata,
|
|
@@ -22924,10 +23048,11 @@ import {
|
|
|
22924
23048
|
getScheduledTask,
|
|
22925
23049
|
getSession as getSession2,
|
|
22926
23050
|
getSlackBotPostOperation,
|
|
22927
|
-
|
|
22928
|
-
|
|
22929
|
-
|
|
22930
|
-
|
|
23051
|
+
availableSlackBotConnectionMetadata,
|
|
23052
|
+
sharedOrganizationSlackBots,
|
|
23053
|
+
prepareBotMessage,
|
|
23054
|
+
readPreparedBotMessage,
|
|
23055
|
+
freezeAgentLearningPolicy as freezeAgentLearningPolicy2,
|
|
22931
23056
|
markSlackBotDeleteOperationProviderStarted,
|
|
22932
23057
|
markSlackBotPostOperationProviderStarted,
|
|
22933
23058
|
recordAuditEvent as recordAuditEvent3,
|
|
@@ -23154,11 +23279,13 @@ async function resolveSlackBotConnectionForTool(input) {
|
|
|
23154
23279
|
}
|
|
23155
23280
|
let connectionId = boundConnectionId ?? input.requestedConnectionId;
|
|
23156
23281
|
if (!connectionId) {
|
|
23157
|
-
const activeConnections = (await
|
|
23282
|
+
const activeConnections = (await availableSlackBotConnectionMetadata(input.db, input.grant)).filter(
|
|
23158
23283
|
(connection2) => connection2.status === "active" && isOpenGeniSlackBotConnection(connection2)
|
|
23159
23284
|
);
|
|
23160
23285
|
if (activeConnections.length === 0) {
|
|
23161
|
-
throw new Error(
|
|
23286
|
+
throw new Error(
|
|
23287
|
+
"No active Opengeni bot is available. Connect it in Capabilities or ask an organization administrator to share the installed bot."
|
|
23288
|
+
);
|
|
23162
23289
|
}
|
|
23163
23290
|
if (activeConnections.length > 1) {
|
|
23164
23291
|
const principals = new Set(
|
|
@@ -23169,7 +23296,7 @@ async function resolveSlackBotConnectionForTool(input) {
|
|
|
23169
23296
|
);
|
|
23170
23297
|
if (principals.size > 1) {
|
|
23171
23298
|
throw new Error(
|
|
23172
|
-
|
|
23299
|
+
`Choose connectionId because multiple Opengeni bots are available: ${activeConnections.slice(0, 20).map((bot) => `${openGeniSlackBotMetadataLabel(bot)} (${bot.id})`).join(", ")}`
|
|
23173
23300
|
);
|
|
23174
23301
|
}
|
|
23175
23302
|
}
|
|
@@ -23184,18 +23311,29 @@ async function resolveSlackBotConnectionForTool(input) {
|
|
|
23184
23311
|
if (!metadata) {
|
|
23185
23312
|
throw new Error("Opengeni Slack bot connection metadata is invalid");
|
|
23186
23313
|
}
|
|
23314
|
+
const sharingGeneration = connection.workspaceId === input.grant.workspaceId ? 0 : Number(connection.metadata.organizationSharingGeneration);
|
|
23187
23315
|
return {
|
|
23188
23316
|
connection,
|
|
23189
23317
|
metadata,
|
|
23318
|
+
sharingGeneration,
|
|
23319
|
+
...connection.workspaceId !== input.grant.workspaceId ? {
|
|
23320
|
+
authorizeOrganizationAccess: async () => (await sharedOrganizationSlackBots(input.db, input.grant)).some(
|
|
23321
|
+
(share) => share.connectionId === connection.id && share.homeWorkspaceId === connection.workspaceId && share.generation === sharingGeneration && share.connectionVersion === connection.version
|
|
23322
|
+
)
|
|
23323
|
+
} : {},
|
|
23190
23324
|
context: {
|
|
23191
23325
|
accountId: input.grant.accountId,
|
|
23192
|
-
workspaceId:
|
|
23326
|
+
workspaceId: connection.workspaceId,
|
|
23193
23327
|
subjectId: input.grant.subjectId,
|
|
23194
23328
|
sessionId: input.sessionId,
|
|
23195
23329
|
scheduledTaskId: typeof session?.metadata.scheduledTaskId === "string" ? session.metadata.scheduledTaskId : null
|
|
23196
23330
|
}
|
|
23197
23331
|
};
|
|
23198
23332
|
}
|
|
23333
|
+
function openGeniSlackBotMetadataLabel(connection) {
|
|
23334
|
+
const metadata = openGeniSlackBotMetadata(connection.metadata);
|
|
23335
|
+
return metadata?.slackTeamName ?? "Slack workspace";
|
|
23336
|
+
}
|
|
23199
23337
|
async function resolveScheduledSlackBotPostTarget(input) {
|
|
23200
23338
|
const refuse = (reason) => {
|
|
23201
23339
|
throw new Error(`Posting to the task's Slack channel is unavailable: ${reason}`);
|
|
@@ -23225,21 +23363,18 @@ async function resolveScheduledSlackBotPostTarget(input) {
|
|
|
23225
23363
|
}
|
|
23226
23364
|
async function prepareScheduledSlackBotPost(input) {
|
|
23227
23365
|
const target2 = await resolveScheduledSlackBotPostTarget(input);
|
|
23228
|
-
const message = await
|
|
23366
|
+
const message = await prepareBotMessage(input.db, {
|
|
23229
23367
|
accountId: input.grant.accountId,
|
|
23230
23368
|
workspaceId: input.grant.workspaceId,
|
|
23231
23369
|
sessionId: input.sessionId,
|
|
23232
23370
|
scheduledTaskId: target2.scheduledTaskId,
|
|
23233
23371
|
connectionId: target2.connection.id,
|
|
23234
23372
|
connectionVersion: target2.connection.version,
|
|
23373
|
+
homeWorkspaceId: target2.connection.workspaceId,
|
|
23374
|
+
sharingGeneration: target2.sharingGeneration ?? 0,
|
|
23235
23375
|
channelId: target2.channelId,
|
|
23236
23376
|
threadTimestamp: input.threadTimestamp ?? null,
|
|
23237
23377
|
text: input.text
|
|
23238
|
-
}).catch((error) => {
|
|
23239
|
-
if (error instanceof ScheduledSlackBotMessageRefusedError) {
|
|
23240
|
-
throw new Error(`Posting to the task's Slack channel is unavailable: ${error.message}`);
|
|
23241
|
-
}
|
|
23242
|
-
throw error;
|
|
23243
23378
|
});
|
|
23244
23379
|
return {
|
|
23245
23380
|
messageId: message.id,
|
|
@@ -23250,9 +23385,143 @@ async function prepareScheduledSlackBotPost(input) {
|
|
|
23250
23385
|
sent: false
|
|
23251
23386
|
};
|
|
23252
23387
|
}
|
|
23388
|
+
async function prepareSlackBotPost(input) {
|
|
23389
|
+
if (!input.sessionId) throw new Error("Bot posting requires a chat");
|
|
23390
|
+
const session = await getSession2(input.db, input.grant.workspaceId, input.sessionId);
|
|
23391
|
+
if (!session) throw new Error("Bot posting chat is unavailable");
|
|
23392
|
+
if (isTrustedScheduledSlackBotSession(session)) {
|
|
23393
|
+
if (input.channelId || input.connectionId)
|
|
23394
|
+
throw new Error(
|
|
23395
|
+
"A scheduled task uses only the bot and channel chosen by a person on the task"
|
|
23396
|
+
);
|
|
23397
|
+
return prepareScheduledSlackBotPost(input);
|
|
23398
|
+
}
|
|
23399
|
+
await authorizeOrdinaryBotPosting(input);
|
|
23400
|
+
if (!input.grant.permissions.includes("connections:read"))
|
|
23401
|
+
throw new Error("connections:read is required to post as the bot");
|
|
23402
|
+
if (!input.channelId)
|
|
23403
|
+
throw new Error(
|
|
23404
|
+
"Choose the Slack channel for this bot message. For a schedule, choose Post to Slack in the schedule editor."
|
|
23405
|
+
);
|
|
23406
|
+
const target2 = await resolveSlackBotConnectionForTool({
|
|
23407
|
+
db: input.db,
|
|
23408
|
+
grant: input.grant,
|
|
23409
|
+
sessionId: input.sessionId,
|
|
23410
|
+
...input.connectionId ? { requestedConnectionId: input.connectionId } : {}
|
|
23411
|
+
});
|
|
23412
|
+
const message = await prepareBotMessage(input.db, {
|
|
23413
|
+
accountId: input.grant.accountId,
|
|
23414
|
+
workspaceId: input.grant.workspaceId,
|
|
23415
|
+
sessionId: input.sessionId,
|
|
23416
|
+
scheduledTaskId: null,
|
|
23417
|
+
connectionId: target2.connection.id,
|
|
23418
|
+
connectionVersion: target2.connection.version,
|
|
23419
|
+
homeWorkspaceId: target2.connection.workspaceId,
|
|
23420
|
+
sharingGeneration: target2.sharingGeneration ?? 0,
|
|
23421
|
+
channelId: input.channelId,
|
|
23422
|
+
threadTimestamp: input.threadTimestamp ?? null,
|
|
23423
|
+
text: input.text
|
|
23424
|
+
});
|
|
23425
|
+
return {
|
|
23426
|
+
messageId: message.id,
|
|
23427
|
+
identity: "organization_bot",
|
|
23428
|
+
channelId: message.channelId,
|
|
23429
|
+
threadTimestamp: message.threadTimestamp,
|
|
23430
|
+
text: message.text,
|
|
23431
|
+
sent: false
|
|
23432
|
+
};
|
|
23433
|
+
}
|
|
23434
|
+
async function sendSlackBotPost(input) {
|
|
23435
|
+
if (!input.sessionId) throw new Error("Bot posting requires a chat");
|
|
23436
|
+
const message = await readPreparedBotMessage(input.db, {
|
|
23437
|
+
accountId: input.grant.accountId,
|
|
23438
|
+
workspaceId: input.grant.workspaceId,
|
|
23439
|
+
sessionId: input.sessionId,
|
|
23440
|
+
id: input.messageId
|
|
23441
|
+
});
|
|
23442
|
+
if (!message) throw new Error("This prepared bot message does not exist in this chat");
|
|
23443
|
+
if (message.scheduledTaskId) return sendScheduledSlackBotPost(input);
|
|
23444
|
+
await authorizeOrdinaryBotPosting(input);
|
|
23445
|
+
const earlier = await getSlackBotPostOperation(
|
|
23446
|
+
input.db,
|
|
23447
|
+
message.homeWorkspaceId,
|
|
23448
|
+
message.connectionId,
|
|
23449
|
+
message.id
|
|
23450
|
+
);
|
|
23451
|
+
if (earlier?.status === "completed") return completedPreparedBotPost(message, earlier);
|
|
23452
|
+
if (!input.grant.permissions.includes("connections:read"))
|
|
23453
|
+
throw new Error("connections:read is required to post as the bot");
|
|
23454
|
+
const target2 = await resolveSlackBotConnectionForTool({
|
|
23455
|
+
db: input.db,
|
|
23456
|
+
grant: input.grant,
|
|
23457
|
+
sessionId: input.sessionId,
|
|
23458
|
+
requestedConnectionId: message.connectionId
|
|
23459
|
+
});
|
|
23460
|
+
if (message.connectionVersion !== target2.connection.version || message.homeWorkspaceId !== target2.connection.workspaceId || message.sharingGeneration !== (target2.sharingGeneration ?? 0)) {
|
|
23461
|
+
throw new Error(
|
|
23462
|
+
"Bot access changed after this message was prepared. It was not sent again; an earlier interrupted send may already have posted it."
|
|
23463
|
+
);
|
|
23464
|
+
}
|
|
23465
|
+
const client = createOpenGeniSlackBotClient(input, target2);
|
|
23466
|
+
return client.postMessage({
|
|
23467
|
+
operationId: message.id,
|
|
23468
|
+
channelId: message.channelId,
|
|
23469
|
+
...message.threadTimestamp ? { threadTimestamp: message.threadTimestamp } : {},
|
|
23470
|
+
text: message.text,
|
|
23471
|
+
requireActiveNonSharedChannel: true
|
|
23472
|
+
});
|
|
23473
|
+
}
|
|
23474
|
+
async function authorizeOrdinaryBotPosting(input) {
|
|
23475
|
+
if (!grantHasAgentAttemptAuthority2(input.grant)) return;
|
|
23476
|
+
const { sessionId, turnId, attemptId, executionGeneration } = input.grant.metadata ?? {};
|
|
23477
|
+
if (typeof sessionId !== "string" || sessionId !== input.sessionId || typeof turnId !== "string" || typeof attemptId !== "string" || typeof executionGeneration !== "number" || !Number.isSafeInteger(executionGeneration) || executionGeneration < 1)
|
|
23478
|
+
throw new Error("Exact live agent attempt required for bot posting");
|
|
23479
|
+
const policy = await freezeAgentLearningPolicy2(input.db, {
|
|
23480
|
+
accountId: input.grant.accountId,
|
|
23481
|
+
workspaceId: input.grant.workspaceId,
|
|
23482
|
+
actor: { kind: "agent", sessionId, turnId, attemptId, executionGeneration }
|
|
23483
|
+
});
|
|
23484
|
+
if (typeof policy.scheduledTaskRunId === "string") {
|
|
23485
|
+
throw new Error(
|
|
23486
|
+
"A scheduled occurrence can post as the bot only to its person-chosen Post to Slack destination. Tasks that continue an existing chat cannot post as the bot."
|
|
23487
|
+
);
|
|
23488
|
+
}
|
|
23489
|
+
}
|
|
23490
|
+
function completedPreparedBotPost(message, operation) {
|
|
23491
|
+
return {
|
|
23492
|
+
channelId: operation.slackChannelId,
|
|
23493
|
+
timestamp: operation.slackMessageTimestamp,
|
|
23494
|
+
threadTimestamp: message.threadTimestamp,
|
|
23495
|
+
alreadySent: true,
|
|
23496
|
+
receipt: {
|
|
23497
|
+
credentialRole: OPENGENI_SLACK_BOT_CREDENTIAL_ROLE,
|
|
23498
|
+
credentialLabel: OPENGENI_SLACK_BOT_CREDENTIAL_LABEL,
|
|
23499
|
+
connectionId: message.connectionId,
|
|
23500
|
+
operation: "message.post",
|
|
23501
|
+
operationId: message.id,
|
|
23502
|
+
clientMessageId: message.id
|
|
23503
|
+
}
|
|
23504
|
+
};
|
|
23505
|
+
}
|
|
23253
23506
|
async function sendScheduledSlackBotPost(input) {
|
|
23507
|
+
if (!input.sessionId) throw new Error("Bot posting requires a chat");
|
|
23508
|
+
const saved = await readPreparedBotMessage(input.db, {
|
|
23509
|
+
accountId: input.grant.accountId,
|
|
23510
|
+
workspaceId: input.grant.workspaceId,
|
|
23511
|
+
sessionId: input.sessionId,
|
|
23512
|
+
id: input.messageId
|
|
23513
|
+
});
|
|
23514
|
+
if (saved) {
|
|
23515
|
+
const earlier2 = await getSlackBotPostOperation(
|
|
23516
|
+
input.db,
|
|
23517
|
+
saved.homeWorkspaceId,
|
|
23518
|
+
saved.connectionId,
|
|
23519
|
+
saved.id
|
|
23520
|
+
);
|
|
23521
|
+
if (earlier2?.status === "completed") return completedPreparedBotPost(saved, earlier2);
|
|
23522
|
+
}
|
|
23254
23523
|
const target2 = await resolveScheduledSlackBotPostTarget(input);
|
|
23255
|
-
const message = await
|
|
23524
|
+
const message = await readPreparedBotMessage(input.db, {
|
|
23256
23525
|
accountId: input.grant.accountId,
|
|
23257
23526
|
workspaceId: input.grant.workspaceId,
|
|
23258
23527
|
sessionId: input.sessionId,
|
|
@@ -23262,13 +23531,20 @@ async function sendScheduledSlackBotPost(input) {
|
|
|
23262
23531
|
throw new Error("This prepared Slack message does not exist in this chat");
|
|
23263
23532
|
}
|
|
23264
23533
|
const channelChanged = message.channelId !== target2.channelId || message.scheduledTaskId !== target2.scheduledTaskId;
|
|
23265
|
-
const botChanged = message.connectionId !== target2.connection.id || message.connectionVersion !== target2.connection.version;
|
|
23534
|
+
const botChanged = message.connectionId !== target2.connection.id || message.connectionVersion !== target2.connection.version || message.homeWorkspaceId !== target2.connection.workspaceId || message.sharingGeneration !== (target2.sharingGeneration ?? 0);
|
|
23266
23535
|
const client = createOpenGeniSlackBotClient(
|
|
23267
23536
|
{
|
|
23268
23537
|
db: input.db,
|
|
23269
23538
|
settings: input.settings,
|
|
23270
23539
|
...input.slackFetch ? { slackFetch: input.slackFetch } : {},
|
|
23271
|
-
...input.authorizeProviderRequest ? { authorizeProviderRequest: input.authorizeProviderRequest } : {}
|
|
23540
|
+
...input.authorizeProviderRequest ? { authorizeProviderRequest: input.authorizeProviderRequest } : {},
|
|
23541
|
+
authorizeBotMutation: async () => {
|
|
23542
|
+
const current = await resolveScheduledSlackBotPostTarget(input);
|
|
23543
|
+
if (current.channelId !== message.channelId || current.connection.id !== message.connectionId || current.connection.version !== message.connectionVersion || (current.sharingGeneration ?? 0) !== message.sharingGeneration)
|
|
23544
|
+
throw new Error(
|
|
23545
|
+
"The task's bot destination changed before sending; the message was not sent again"
|
|
23546
|
+
);
|
|
23547
|
+
}
|
|
23272
23548
|
},
|
|
23273
23549
|
target2
|
|
23274
23550
|
);
|
|
@@ -23282,7 +23558,7 @@ async function sendScheduledSlackBotPost(input) {
|
|
|
23282
23558
|
if (!channelChanged && !botChanged) return await post();
|
|
23283
23559
|
const earlier = await getSlackBotPostOperation(
|
|
23284
23560
|
input.db,
|
|
23285
|
-
|
|
23561
|
+
message.homeWorkspaceId,
|
|
23286
23562
|
message.connectionId,
|
|
23287
23563
|
message.id
|
|
23288
23564
|
);
|
|
@@ -23322,7 +23598,7 @@ async function verifyScheduledTaskSlackChannel(deps, input) {
|
|
|
23322
23598
|
}
|
|
23323
23599
|
}
|
|
23324
23600
|
var OpenGeniSlackBotClient = class {
|
|
23325
|
-
constructor(db, settings, connection, metadata, context, fetchImpl = fetch, authorizeProviderRequest) {
|
|
23601
|
+
constructor(db, settings, connection, metadata, context, fetchImpl = fetch, authorizeProviderRequest, authorizeBotAccess) {
|
|
23326
23602
|
this.db = db;
|
|
23327
23603
|
this.settings = settings;
|
|
23328
23604
|
this.connection = connection;
|
|
@@ -23330,6 +23606,7 @@ var OpenGeniSlackBotClient = class {
|
|
|
23330
23606
|
this.context = context;
|
|
23331
23607
|
this.fetchImpl = fetchImpl;
|
|
23332
23608
|
this.authorizeProviderRequest = authorizeProviderRequest;
|
|
23609
|
+
this.authorizeBotAccess = authorizeBotAccess;
|
|
23333
23610
|
this.resolveCredential = buildConnectionTokenResolver2(db, settings);
|
|
23334
23611
|
this.rateLimit = buildSlackApiRateLimiter2(db, settings);
|
|
23335
23612
|
}
|
|
@@ -24442,6 +24719,9 @@ var OpenGeniSlackBotClient = class {
|
|
|
24442
24719
|
if (result.status !== "ok" || result.connectionId !== this.connection.id) {
|
|
24443
24720
|
throw new Error("Opengeni Slack bot connection needs to be reinstalled");
|
|
24444
24721
|
}
|
|
24722
|
+
if (this.authorizeProviderRequest && await this.authorizeProviderRequest() === false) {
|
|
24723
|
+
throw new Error("Opengeni Slack bot provider request is no longer authorized");
|
|
24724
|
+
}
|
|
24445
24725
|
const current = await requireOpenGeniSlackBotConnection(
|
|
24446
24726
|
this.db,
|
|
24447
24727
|
this.context.workspaceId,
|
|
@@ -24454,12 +24734,12 @@ var OpenGeniSlackBotClient = class {
|
|
|
24454
24734
|
if (current.accountId !== this.context.accountId || current.version !== this.connection.version || result.connectionVersion !== this.connection.version || !currentMetadata || currentMetadata.slackTeamId !== this.metadata.slackTeamId || currentMetadata.botId !== this.metadata.botId || currentMetadata.botUserId !== this.metadata.botUserId) {
|
|
24455
24735
|
throw new Error("Opengeni Slack bot connection authority changed");
|
|
24456
24736
|
}
|
|
24457
|
-
if (this.authorizeProviderRequest && await this.authorizeProviderRequest() === false) {
|
|
24458
|
-
throw new Error("Opengeni Slack bot provider request is no longer authorized");
|
|
24459
|
-
}
|
|
24460
24737
|
if (credentialResolutionMode === "execution" && result.authorizeProviderRequest && !await result.authorizeProviderRequest()) {
|
|
24461
24738
|
throw new Error("Opengeni Slack bot provider request is no longer authorized");
|
|
24462
24739
|
}
|
|
24740
|
+
if (this.authorizeBotAccess && await this.authorizeBotAccess(new URL(destinationUrl).pathname.split("/").at(-1) ?? "") === false) {
|
|
24741
|
+
throw new Error("Opengeni Slack bot organization access is no longer authorized");
|
|
24742
|
+
}
|
|
24463
24743
|
return result.headers;
|
|
24464
24744
|
}
|
|
24465
24745
|
async fetchPrivateFile(url, operation, authorizeBeforeFetch) {
|
|
@@ -24656,7 +24936,13 @@ function createOpenGeniSlackBotClient(deps, resolved) {
|
|
|
24656
24936
|
resolved.metadata,
|
|
24657
24937
|
resolved.context,
|
|
24658
24938
|
deps.slackFetch,
|
|
24659
|
-
deps.authorizeProviderRequest
|
|
24939
|
+
deps.authorizeProviderRequest,
|
|
24940
|
+
async (method) => {
|
|
24941
|
+
if (method === "chat.postMessage") await deps.authorizeBotMutation?.();
|
|
24942
|
+
if (resolved.authorizeOrganizationAccess && await resolved.authorizeOrganizationAccess() === false)
|
|
24943
|
+
return false;
|
|
24944
|
+
return true;
|
|
24945
|
+
}
|
|
24660
24946
|
);
|
|
24661
24947
|
}
|
|
24662
24948
|
async function createOpenGeniSlackBotInteractionClient(deps, input) {
|
|
@@ -24677,13 +24963,20 @@ async function createOpenGeniSlackBotInteractionClient(deps, input) {
|
|
|
24677
24963
|
metadata,
|
|
24678
24964
|
{
|
|
24679
24965
|
accountId: input.accountId,
|
|
24680
|
-
workspaceId:
|
|
24966
|
+
workspaceId: connection.workspaceId,
|
|
24681
24967
|
subjectId: input.subjectId,
|
|
24682
24968
|
sessionId: input.sessionId ?? null,
|
|
24683
24969
|
scheduledTaskId: null
|
|
24684
24970
|
},
|
|
24685
24971
|
deps.slackFetch,
|
|
24686
|
-
deps.authorizeProviderRequest
|
|
24972
|
+
deps.authorizeProviderRequest,
|
|
24973
|
+
async () => {
|
|
24974
|
+
if (connection.workspaceId !== input.workspaceId && !(await sharedOrganizationSlackBots(deps.db, input)).some(
|
|
24975
|
+
(share) => share.connectionId === connection.id && share.homeWorkspaceId === connection.workspaceId && share.generation === Number(connection.metadata.organizationSharingGeneration) && share.connectionVersion === connection.version
|
|
24976
|
+
))
|
|
24977
|
+
return false;
|
|
24978
|
+
return true;
|
|
24979
|
+
}
|
|
24687
24980
|
);
|
|
24688
24981
|
}
|
|
24689
24982
|
async function slackApiFetch(fetchImpl, method, token, params) {
|
|
@@ -25774,7 +26067,7 @@ import {
|
|
|
25774
26067
|
getConnectAttempt as getConnectAttempt4,
|
|
25775
26068
|
finishConnectOperation as finishConnectOperation3,
|
|
25776
26069
|
getConnectionMetadata as getConnectionMetadata2,
|
|
25777
|
-
listConnectionsMetadata as
|
|
26070
|
+
listConnectionsMetadata as listConnectionsMetadata2,
|
|
25778
26071
|
loadConnectionCredentialForBroker,
|
|
25779
26072
|
recordAuditEvent as recordAuditEvent5,
|
|
25780
26073
|
setConnectionStatus as setConnectionStatus2,
|
|
@@ -25972,7 +26265,7 @@ async function resolveFikenConnectionForTool(input) {
|
|
|
25972
26265
|
input.requestedConnectionId,
|
|
25973
26266
|
null
|
|
25974
26267
|
) : preferredFikenConnection(
|
|
25975
|
-
(await
|
|
26268
|
+
(await listConnectionsMetadata2(input.db, input.grant.workspaceId, null)).filter(
|
|
25976
26269
|
isFikenConnection
|
|
25977
26270
|
)
|
|
25978
26271
|
);
|
|
@@ -32605,7 +32898,22 @@ function registerSlackBotTools(server, deps, grant, sessionId, json2) {
|
|
|
32605
32898
|
sessionId,
|
|
32606
32899
|
...connectionId ? { requestedConnectionId: connectionId } : {}
|
|
32607
32900
|
});
|
|
32608
|
-
return createOpenGeniSlackBotClient(
|
|
32901
|
+
return createOpenGeniSlackBotClient(
|
|
32902
|
+
{
|
|
32903
|
+
...deps,
|
|
32904
|
+
authorizeProviderRequest: async () => {
|
|
32905
|
+
if (sessionId !== null)
|
|
32906
|
+
await authorizeFirstPartySession(
|
|
32907
|
+
deps,
|
|
32908
|
+
grant,
|
|
32909
|
+
sessionId,
|
|
32910
|
+
"session.first_party_mcp.call"
|
|
32911
|
+
);
|
|
32912
|
+
return true;
|
|
32913
|
+
}
|
|
32914
|
+
},
|
|
32915
|
+
resolved
|
|
32916
|
+
);
|
|
32609
32917
|
};
|
|
32610
32918
|
server.registerTool(
|
|
32611
32919
|
"slack_bot_list_channels",
|
|
@@ -32775,29 +33083,33 @@ function registerSlackBotTools(server, deps, grant, sessionId, json2) {
|
|
|
32775
33083
|
);
|
|
32776
33084
|
}
|
|
32777
33085
|
);
|
|
32778
|
-
const
|
|
33086
|
+
const authorizeBotPost = async () => {
|
|
32779
33087
|
if (sessionId === null) {
|
|
32780
|
-
throw new Error("
|
|
33088
|
+
throw new Error("Bot posting requires a chat");
|
|
32781
33089
|
}
|
|
32782
33090
|
await authorizeFirstPartySession(deps, grant, sessionId, "session.first_party_mcp.call");
|
|
32783
33091
|
};
|
|
32784
33092
|
server.registerTool(
|
|
32785
33093
|
"slack_bot_prepare_message",
|
|
32786
33094
|
{
|
|
32787
|
-
description: "Prepare a message
|
|
33095
|
+
description: "Prepare a message as the Opengeni bot, never as a personal Slack account. In an ordinary chat supply channelId and, if multiple bots are available, connectionId. Scheduled runs omit both and use only the channel chosen by a person in Post to Slack. Nothing is sent until slack_bot_send_prepared_message is called with the returned messageId. Reuse that messageId for retries. Bot membership and organization sharing are checked when sending.",
|
|
32788
33096
|
inputSchema: {
|
|
33097
|
+
connectionId: z43.string().uuid().optional(),
|
|
33098
|
+
channelId: z43.string().regex(/^[CG][A-Z0-9]{2,63}$/).optional(),
|
|
32789
33099
|
text: z43.string().min(1).max(4e4),
|
|
32790
33100
|
threadTimestamp: z43.string().regex(/^\d{1,20}\.\d{1,12}$/).optional()
|
|
32791
33101
|
}
|
|
32792
33102
|
},
|
|
32793
|
-
async ({ text, threadTimestamp }) => {
|
|
32794
|
-
await
|
|
33103
|
+
async ({ text, threadTimestamp, channelId, connectionId }) => {
|
|
33104
|
+
await authorizeBotPost();
|
|
32795
33105
|
return json2(
|
|
32796
|
-
await
|
|
33106
|
+
await prepareSlackBotPost({
|
|
32797
33107
|
db: deps.db,
|
|
32798
33108
|
grant,
|
|
32799
33109
|
sessionId,
|
|
32800
33110
|
text,
|
|
33111
|
+
...channelId ? { channelId } : {},
|
|
33112
|
+
...connectionId ? { connectionId } : {},
|
|
32801
33113
|
...threadTimestamp ? { threadTimestamp } : {}
|
|
32802
33114
|
})
|
|
32803
33115
|
);
|
|
@@ -32806,20 +33118,20 @@ function registerSlackBotTools(server, deps, grant, sessionId, json2) {
|
|
|
32806
33118
|
server.registerTool(
|
|
32807
33119
|
"slack_bot_send_prepared_message",
|
|
32808
33120
|
{
|
|
32809
|
-
description: "Send a message prepared by slack_bot_prepare_message in this chat, exactly as saved,
|
|
33121
|
+
description: "Send a message prepared by slack_bot_prepare_message in this chat, exactly as saved, as the Opengeni bot. If a send is interrupted or its outcome is unclear, retry with the same messageId: Opengeni checks Slack and never posts the same message twice. Do not prepare a new message just to retry.",
|
|
32810
33122
|
inputSchema: { messageId: z43.string().uuid() }
|
|
32811
33123
|
},
|
|
32812
33124
|
async ({ messageId }) => {
|
|
32813
|
-
await
|
|
33125
|
+
await authorizeBotPost();
|
|
32814
33126
|
return json2(
|
|
32815
|
-
await
|
|
33127
|
+
await sendSlackBotPost({
|
|
32816
33128
|
db: deps.db,
|
|
32817
33129
|
settings: deps.settings,
|
|
32818
33130
|
grant,
|
|
32819
33131
|
sessionId,
|
|
32820
33132
|
messageId,
|
|
32821
33133
|
...deps.slackFetch ? { slackFetch: deps.slackFetch } : {},
|
|
32822
|
-
authorizeProviderRequest:
|
|
33134
|
+
authorizeProviderRequest: authorizeBotPost
|
|
32823
33135
|
})
|
|
32824
33136
|
);
|
|
32825
33137
|
}
|
|
@@ -36817,7 +37129,8 @@ var ACTION_CATALOG = [
|
|
|
36817
37129
|
],
|
|
36818
37130
|
"response": [
|
|
36819
37131
|
"AcceptOrganizationInvitationResponse"
|
|
36820
|
-
]
|
|
37132
|
+
],
|
|
37133
|
+
"browserOnly": "it acts on the person's own account across organizations (creating an organization, listing their memberships or invitations, accepting an invitation), and a connection is limited to one organization"
|
|
36821
37134
|
},
|
|
36822
37135
|
{
|
|
36823
37136
|
"id": "acceptOrganizationRecoveryCustody",
|
|
@@ -36828,7 +37141,8 @@ var ACTION_CATALOG = [
|
|
|
36828
37141
|
],
|
|
36829
37142
|
"response": [
|
|
36830
37143
|
"OrganizationRecoveryMutationResponse"
|
|
36831
|
-
]
|
|
37144
|
+
],
|
|
37145
|
+
"browserOnly": "organization recovery is a ceremony in the person's own browser session"
|
|
36832
37146
|
},
|
|
36833
37147
|
{
|
|
36834
37148
|
"id": "acknowledgeStream",
|
|
@@ -37070,7 +37384,8 @@ var ACTION_CATALOG = [
|
|
|
37070
37384
|
],
|
|
37071
37385
|
"response": [
|
|
37072
37386
|
"OrganizationRecoveryMutationResponse"
|
|
37073
|
-
]
|
|
37387
|
+
],
|
|
37388
|
+
"browserOnly": "organization recovery is a ceremony in the person's own browser session"
|
|
37074
37389
|
},
|
|
37075
37390
|
{
|
|
37076
37391
|
"id": "approveSlackUserLinkAccessRequest",
|
|
@@ -37165,7 +37480,8 @@ var ACTION_CATALOG = [
|
|
|
37165
37480
|
],
|
|
37166
37481
|
"response": [
|
|
37167
37482
|
"BeginExternalIdentityLinkResponse"
|
|
37168
|
-
]
|
|
37483
|
+
],
|
|
37484
|
+
"browserOnly": "linking a product user to an Opengeni account is confirmed by that person signed in to Opengeni, or started by the embedding product as its user"
|
|
37169
37485
|
},
|
|
37170
37486
|
{
|
|
37171
37487
|
"id": "beginSessionRealtime",
|
|
@@ -37226,7 +37542,8 @@ var ACTION_CATALOG = [
|
|
|
37226
37542
|
],
|
|
37227
37543
|
"response": [
|
|
37228
37544
|
"OrganizationRecoveryMutationResponse"
|
|
37229
|
-
]
|
|
37545
|
+
],
|
|
37546
|
+
"browserOnly": "organization recovery is a ceremony in the person's own browser session"
|
|
37230
37547
|
},
|
|
37231
37548
|
{
|
|
37232
37549
|
"id": "cancelSessionBackgroundCommand",
|
|
@@ -37417,7 +37734,8 @@ var ACTION_CATALOG = [
|
|
|
37417
37734
|
],
|
|
37418
37735
|
"response": [
|
|
37419
37736
|
"OrganizationRecoveryMutationResponse"
|
|
37420
|
-
]
|
|
37737
|
+
],
|
|
37738
|
+
"browserOnly": "organization recovery is a ceremony in the person's own browser session"
|
|
37421
37739
|
},
|
|
37422
37740
|
{
|
|
37423
37741
|
"id": "confirmIdentityLink",
|
|
@@ -37429,7 +37747,8 @@ var ACTION_CATALOG = [
|
|
|
37429
37747
|
"response": [
|
|
37430
37748
|
"ExternalIdentityLink",
|
|
37431
37749
|
"ExternalIdentityLinkPreview"
|
|
37432
|
-
]
|
|
37750
|
+
],
|
|
37751
|
+
"browserOnly": "linking a product user to an Opengeni account is confirmed by that person signed in to Opengeni, or started by the embedding product as its user"
|
|
37433
37752
|
},
|
|
37434
37753
|
{
|
|
37435
37754
|
"id": "connectClaudeSubscriptionSetupToken",
|
|
@@ -37482,7 +37801,8 @@ var ACTION_CATALOG = [
|
|
|
37482
37801
|
],
|
|
37483
37802
|
"response": [
|
|
37484
37803
|
"CreateAdditionalOrganizationResponse"
|
|
37485
|
-
]
|
|
37804
|
+
],
|
|
37805
|
+
"browserOnly": "it acts on the person's own account across organizations (creating an organization, listing their memberships or invitations, accepting an invitation), and a connection is limited to one organization"
|
|
37486
37806
|
},
|
|
37487
37807
|
{
|
|
37488
37808
|
"id": "createApiKey",
|
|
@@ -37707,7 +38027,8 @@ var ACTION_CATALOG = [
|
|
|
37707
38027
|
],
|
|
37708
38028
|
"response": [
|
|
37709
38029
|
"CreateOrganizationResponse"
|
|
37710
|
-
]
|
|
38030
|
+
],
|
|
38031
|
+
"browserOnly": "it acts on the person's own account across organizations (creating an organization, listing their memberships or invitations, accepting an invitation), and a connection is limited to one organization"
|
|
37711
38032
|
},
|
|
37712
38033
|
{
|
|
37713
38034
|
"id": "createOrganizationApiKey",
|
|
@@ -38290,7 +38611,8 @@ var ACTION_CATALOG = [
|
|
|
38290
38611
|
],
|
|
38291
38612
|
"response": [
|
|
38292
38613
|
"OrganizationRecoveryMutationResponse"
|
|
38293
|
-
]
|
|
38614
|
+
],
|
|
38615
|
+
"browserOnly": "organization recovery is a ceremony in the person's own browser session"
|
|
38294
38616
|
},
|
|
38295
38617
|
{
|
|
38296
38618
|
"id": "disableSource",
|
|
@@ -38457,7 +38779,8 @@ var ACTION_CATALOG = [
|
|
|
38457
38779
|
],
|
|
38458
38780
|
"response": [
|
|
38459
38781
|
"OrganizationRecoveryMutationResponse"
|
|
38460
|
-
]
|
|
38782
|
+
],
|
|
38783
|
+
"browserOnly": "organization recovery is a ceremony in the person's own browser session"
|
|
38461
38784
|
},
|
|
38462
38785
|
{
|
|
38463
38786
|
"id": "exportCompanyBrainOkf",
|
|
@@ -38717,7 +39040,8 @@ var ACTION_CATALOG = [
|
|
|
38717
39040
|
"method": "GET",
|
|
38718
39041
|
"path": "/v1/workspaces/:workspaceId/identity-links/:linkId/:operation",
|
|
38719
39042
|
"request": [],
|
|
38720
|
-
"response": []
|
|
39043
|
+
"response": [],
|
|
39044
|
+
"browserOnly": "linking a product user to an Opengeni account is confirmed by that person signed in to Opengeni, or started by the embedding product as its user"
|
|
38721
39045
|
},
|
|
38722
39046
|
{
|
|
38723
39047
|
"id": "GET /v1/workspaces/:workspaceId/insights/calls",
|
|
@@ -39168,7 +39492,8 @@ var ACTION_CATALOG = [
|
|
|
39168
39492
|
"request": [],
|
|
39169
39493
|
"response": [
|
|
39170
39494
|
"ExternalIdentityLink"
|
|
39171
|
-
]
|
|
39495
|
+
],
|
|
39496
|
+
"browserOnly": "linking a product user to an Opengeni account is confirmed by that person signed in to Opengeni, or started by the embedding product as its user"
|
|
39172
39497
|
},
|
|
39173
39498
|
{
|
|
39174
39499
|
"id": "getInstalledPluginDetails",
|
|
@@ -39242,6 +39567,15 @@ var ACTION_CATALOG = [
|
|
|
39242
39567
|
"NewSessionDraft"
|
|
39243
39568
|
]
|
|
39244
39569
|
},
|
|
39570
|
+
{
|
|
39571
|
+
"id": "getOpenGeniSlackBotOrganizationAccess",
|
|
39572
|
+
"method": "GET",
|
|
39573
|
+
"path": "/v1/workspaces/:workspaceId/connections/:connectionId/slack-bot/organization-access",
|
|
39574
|
+
"request": [],
|
|
39575
|
+
"response": [
|
|
39576
|
+
"OpenGeniSlackBotOrganizationAccess"
|
|
39577
|
+
]
|
|
39578
|
+
},
|
|
39245
39579
|
{
|
|
39246
39580
|
"id": "getOrganizationAdministrationOverview",
|
|
39247
39581
|
"method": "GET",
|
|
@@ -39348,7 +39682,8 @@ var ACTION_CATALOG = [
|
|
|
39348
39682
|
"request": [],
|
|
39349
39683
|
"response": [
|
|
39350
39684
|
"OrganizationRecoveryOverview"
|
|
39351
|
-
]
|
|
39685
|
+
],
|
|
39686
|
+
"browserOnly": "organization recovery is a ceremony in the person's own browser session"
|
|
39352
39687
|
},
|
|
39353
39688
|
{
|
|
39354
39689
|
"id": "getOrganizationRetentionPolicy",
|
|
@@ -39587,6 +39922,24 @@ var ACTION_CATALOG = [
|
|
|
39587
39922
|
"SessionCapabilities"
|
|
39588
39923
|
]
|
|
39589
39924
|
},
|
|
39925
|
+
{
|
|
39926
|
+
"id": "getToolActionReview",
|
|
39927
|
+
"method": "GET",
|
|
39928
|
+
"path": "/v1/workspaces/:workspaceId/sessions/:sessionId/tool-reviews/:approvalId",
|
|
39929
|
+
"request": [],
|
|
39930
|
+
"response": [
|
|
39931
|
+
"ToolActionReview"
|
|
39932
|
+
]
|
|
39933
|
+
},
|
|
39934
|
+
{
|
|
39935
|
+
"id": "getToolReviewDetails",
|
|
39936
|
+
"method": "GET",
|
|
39937
|
+
"path": "/v1/workspaces/:workspaceId/sessions/:sessionId/tool-reviews/:approvalId/details",
|
|
39938
|
+
"request": [],
|
|
39939
|
+
"response": [
|
|
39940
|
+
"ToolReviewDetailsPage"
|
|
39941
|
+
]
|
|
39942
|
+
},
|
|
39590
39943
|
{
|
|
39591
39944
|
"id": "getTranscriptionRecording",
|
|
39592
39945
|
"method": "GET",
|
|
@@ -40123,6 +40476,15 @@ var ACTION_CATALOG = [
|
|
|
40123
40476
|
"AuthRunListResponse"
|
|
40124
40477
|
]
|
|
40125
40478
|
},
|
|
40479
|
+
{
|
|
40480
|
+
"id": "listAvailableOpenGeniSlackBots",
|
|
40481
|
+
"method": "GET",
|
|
40482
|
+
"path": "/v1/workspaces/:workspaceId/connections/slack-bot/available",
|
|
40483
|
+
"request": [],
|
|
40484
|
+
"response": [
|
|
40485
|
+
"AvailableOpenGeniSlackBots"
|
|
40486
|
+
]
|
|
40487
|
+
},
|
|
40126
40488
|
{
|
|
40127
40489
|
"id": "listBrowserDiagnostics",
|
|
40128
40490
|
"method": "GET",
|
|
@@ -40381,7 +40743,8 @@ var ACTION_CATALOG = [
|
|
|
40381
40743
|
"request": [],
|
|
40382
40744
|
"response": [
|
|
40383
40745
|
"ExternalIdentityLinkPage"
|
|
40384
|
-
]
|
|
40746
|
+
],
|
|
40747
|
+
"browserOnly": "linking a product user to an Opengeni account is confirmed by that person signed in to Opengeni, or started by the embedding product as its user"
|
|
40385
40748
|
},
|
|
40386
40749
|
{
|
|
40387
40750
|
"id": "listInstalledPlugins",
|
|
@@ -40556,7 +40919,8 @@ var ACTION_CATALOG = [
|
|
|
40556
40919
|
"request": [],
|
|
40557
40920
|
"response": [
|
|
40558
40921
|
"ListOrganizationInvitationsPageResponse"
|
|
40559
|
-
]
|
|
40922
|
+
],
|
|
40923
|
+
"browserOnly": "it acts on the person's own account across organizations (creating an organization, listing their memberships or invitations, accepting an invitation), and a connection is limited to one organization"
|
|
40560
40924
|
},
|
|
40561
40925
|
{
|
|
40562
40926
|
"id": "listOrganizationInvitationsForOrganization",
|
|
@@ -40574,7 +40938,8 @@ var ACTION_CATALOG = [
|
|
|
40574
40938
|
"request": [],
|
|
40575
40939
|
"response": [
|
|
40576
40940
|
"ListManagedOrganizationMembershipsResponse"
|
|
40577
|
-
]
|
|
40941
|
+
],
|
|
40942
|
+
"browserOnly": "it acts on the person's own account across organizations (creating an organization, listing their memberships or invitations, accepting an invitation), and a connection is limited to one organization"
|
|
40578
40943
|
},
|
|
40579
40944
|
{
|
|
40580
40945
|
"id": "listOrganizationProviderCustomModels",
|
|
@@ -41327,7 +41692,8 @@ var ACTION_CATALOG = [
|
|
|
41327
41692
|
"method": "POST",
|
|
41328
41693
|
"path": "/v1/workspaces/:workspaceId/identity-links/:linkId",
|
|
41329
41694
|
"request": [],
|
|
41330
|
-
"response": []
|
|
41695
|
+
"response": [],
|
|
41696
|
+
"browserOnly": "linking a product user to an Opengeni account is confirmed by that person signed in to Opengeni, or started by the embedding product as its user"
|
|
41331
41697
|
},
|
|
41332
41698
|
{
|
|
41333
41699
|
"id": "POST /v1/workspaces/:workspaceId/integrations/:capabilityId/instances/:instanceKey/facets/:facetKey/pause",
|
|
@@ -42435,6 +42801,17 @@ var ACTION_CATALOG = [
|
|
|
42435
42801
|
"MemberAllowance"
|
|
42436
42802
|
]
|
|
42437
42803
|
},
|
|
42804
|
+
{
|
|
42805
|
+
"id": "setOpenGeniSlackBotOrganizationAccess",
|
|
42806
|
+
"method": "PUT",
|
|
42807
|
+
"path": "/v1/workspaces/:workspaceId/connections/:connectionId/slack-bot/organization-access",
|
|
42808
|
+
"request": [
|
|
42809
|
+
"UpdateOpenGeniSlackBotOrganizationAccess"
|
|
42810
|
+
],
|
|
42811
|
+
"response": [
|
|
42812
|
+
"OpenGeniSlackBotOrganizationAccess"
|
|
42813
|
+
]
|
|
42814
|
+
},
|
|
42438
42815
|
{
|
|
42439
42816
|
"id": "setOrganizationClaudeSubscriptionAccountAllocator",
|
|
42440
42817
|
"method": "PATCH",
|
|
@@ -42614,7 +42991,8 @@ var ACTION_CATALOG = [
|
|
|
42614
42991
|
],
|
|
42615
42992
|
"response": [
|
|
42616
42993
|
"OrganizationRecoveryMutationResponse"
|
|
42617
|
-
]
|
|
42994
|
+
],
|
|
42995
|
+
"browserOnly": "organization recovery is a ceremony in the person's own browser session"
|
|
42618
42996
|
},
|
|
42619
42997
|
{
|
|
42620
42998
|
"id": "startPersonalGitHubOAuth",
|
|
@@ -43572,9 +43950,45 @@ var TOOLS = [
|
|
|
43572
43950
|
annotations: { readOnlyHint: false, openWorldHint: false }
|
|
43573
43951
|
}
|
|
43574
43952
|
];
|
|
43953
|
+
var BRAND_MARK_PATH = "M251 83.5966L207 109L163 83.5966L119 109L75 83.5966L141 45.4915A44 44 0 0 1 185 45.4915ZM185.25 172.3642A44.5 44.5 0 0 1 140.75 172.3642L75 134.4034L119 109L163 134.4034L207 109L251 134.4034Z";
|
|
43954
|
+
function brandMarkSvgDataUri(fill) {
|
|
43955
|
+
const svg = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="71 17 184 184" width="184" height="184"><path fill="${fill}" d="${BRAND_MARK_PATH}"/></svg>`;
|
|
43956
|
+
return `data:image/svg+xml;base64,${Buffer.from(svg).toString("base64")}`;
|
|
43957
|
+
}
|
|
43958
|
+
function organizationMcpIcons(publicOrigin) {
|
|
43959
|
+
const icons = [
|
|
43960
|
+
{
|
|
43961
|
+
src: brandMarkSvgDataUri("#111111"),
|
|
43962
|
+
mimeType: "image/svg+xml",
|
|
43963
|
+
sizes: ["any"],
|
|
43964
|
+
theme: "light"
|
|
43965
|
+
},
|
|
43966
|
+
{
|
|
43967
|
+
src: brandMarkSvgDataUri("#FFFFFF"),
|
|
43968
|
+
mimeType: "image/svg+xml",
|
|
43969
|
+
sizes: ["any"],
|
|
43970
|
+
theme: "dark"
|
|
43971
|
+
}
|
|
43972
|
+
];
|
|
43973
|
+
if (publicOrigin) {
|
|
43974
|
+
icons.push({
|
|
43975
|
+
src: new URL("/icon-512.png", publicOrigin).href,
|
|
43976
|
+
mimeType: "image/png",
|
|
43977
|
+
sizes: ["512x512"],
|
|
43978
|
+
theme: "light"
|
|
43979
|
+
});
|
|
43980
|
+
}
|
|
43981
|
+
return icons;
|
|
43982
|
+
}
|
|
43575
43983
|
function buildOrganizationMcpServer(input) {
|
|
43576
43984
|
const server = new Server2(
|
|
43577
|
-
{
|
|
43985
|
+
{
|
|
43986
|
+
name: "opengeni",
|
|
43987
|
+
title: "Opengeni",
|
|
43988
|
+
version: "1.0.0",
|
|
43989
|
+
websiteUrl: "https://opengeni.ai",
|
|
43990
|
+
icons: organizationMcpIcons(input.publicOrigin ?? null)
|
|
43991
|
+
},
|
|
43578
43992
|
{
|
|
43579
43993
|
capabilities: { tools: {} },
|
|
43580
43994
|
instructions: "Opengeni actions: use opengeni_actions_search to find what you need, opengeni_action_describe for its inputs, then opengeni_action_call. Most actions take a workspaceId path parameter; list workspaces first (search 'workspaces')."
|
|
@@ -43596,6 +44010,7 @@ function buildOrganizationMcpServer(input) {
|
|
|
43596
44010
|
if (!parsed.success) return invalid(parsed.error);
|
|
43597
44011
|
const entry2 = findAction(parsed.data.id);
|
|
43598
44012
|
if (!entry2) return failure(`No action "${parsed.data.id}". Search for it first.`);
|
|
44013
|
+
if (entry2.browserOnly) return browserOnly(entry2);
|
|
43599
44014
|
return json(describeAction(entry2));
|
|
43600
44015
|
}
|
|
43601
44016
|
case "opengeni_action_call": {
|
|
@@ -43618,11 +44033,12 @@ function findAction(id) {
|
|
|
43618
44033
|
function words(value) {
|
|
43619
44034
|
return value.replace(/([a-z0-9])([A-Z])/g, "$1 $2").toLowerCase().split(/[^a-z0-9]+/u).filter(Boolean);
|
|
43620
44035
|
}
|
|
44036
|
+
var CALLABLE_ACTIONS = ACTION_CATALOG.filter((entry2) => !entry2.browserOnly);
|
|
43621
44037
|
function searchActions(input) {
|
|
43622
44038
|
const stem = (word) => word.endsWith("ies") ? `${word.slice(0, -3)}y` : word.replace(/(?<!s)s$/u, "");
|
|
43623
44039
|
const wanted = words(input.query).map(stem);
|
|
43624
44040
|
const plural = words(input.query).some((word) => /[^s]s$/u.test(word));
|
|
43625
|
-
const scored =
|
|
44041
|
+
const scored = CALLABLE_ACTIONS.map((entry2) => {
|
|
43626
44042
|
const name = words(entry2.id).map(stem);
|
|
43627
44043
|
const path = [...words(entry2.path.replace(/:\w+/g, "")), entry2.method.toLowerCase()].map(stem);
|
|
43628
44044
|
const score = wanted.reduce(
|
|
@@ -43679,6 +44095,7 @@ function describeAction(entry2) {
|
|
|
43679
44095
|
async function callAction(context, input) {
|
|
43680
44096
|
const entry2 = findAction(input.id);
|
|
43681
44097
|
if (!entry2) return failure(`No action "${input.id}". Search for it first.`);
|
|
44098
|
+
if (entry2.browserOnly) return browserOnly(entry2);
|
|
43682
44099
|
const reads = entry2.method === "GET" || entry2.method === "HEAD";
|
|
43683
44100
|
if (context.caller.kind === "person" && !reads && !READ_ONLY_POST_ACTIONS.has(entry2.path) && isReadOnlyPermissionSet(context.caller.access.permissions)) {
|
|
43684
44101
|
return failure("This connection is read only, so it can't change anything.");
|
|
@@ -43757,7 +44174,7 @@ async function toolResult(response) {
|
|
|
43757
44174
|
if (truncated)
|
|
43758
44175
|
result.truncated = { returnedBytes: MAX_RESPONSE_BYTES, totalBytes: bytes.byteLength };
|
|
43759
44176
|
}
|
|
43760
|
-
if (status === 403 && /human|browser|cookie|same-origin/i.test(JSON.stringify(result.body ?? ""))) {
|
|
44177
|
+
if ((status === 401 || status === 403) && /human|browser|cookie|same-origin/i.test(JSON.stringify(result.body ?? ""))) {
|
|
43761
44178
|
result.hint = "This action has to be done by the person in the Opengeni app in a browser.";
|
|
43762
44179
|
}
|
|
43763
44180
|
return {
|
|
@@ -43793,6 +44210,11 @@ async function readStream(response) {
|
|
|
43793
44210
|
function json(value) {
|
|
43794
44211
|
return { content: [{ type: "text", text: JSON.stringify(value) }] };
|
|
43795
44212
|
}
|
|
44213
|
+
function browserOnly(entry2) {
|
|
44214
|
+
return failure(
|
|
44215
|
+
`${entry2.id} isn't available to connected agents or API keys: ${entry2.browserOnly}. The person has to do it in the Opengeni app in a browser.`
|
|
44216
|
+
);
|
|
44217
|
+
}
|
|
43796
44218
|
function failure(message) {
|
|
43797
44219
|
return { content: [{ type: "text", text: message }], isError: true };
|
|
43798
44220
|
}
|
|
@@ -73401,7 +73823,9 @@ function registerCapabilityRoutes(app, deps) {
|
|
|
73401
73823
|
workspaceId,
|
|
73402
73824
|
grant: access.grant,
|
|
73403
73825
|
capabilityId: decodeURIComponent(c.req.param("capabilityId")),
|
|
73404
|
-
personalOwnerVerified: isPersonalConnectionOwnerPrincipal(access)
|
|
73826
|
+
personalOwnerVerified: isPersonalConnectionOwnerPrincipal(access),
|
|
73827
|
+
...c.req.query("connectionId") ? { connectionId: c.req.query("connectionId") } : {},
|
|
73828
|
+
...c.req.query("instanceKey") ? { instanceKey: c.req.query("instanceKey") } : {}
|
|
73405
73829
|
})
|
|
73406
73830
|
)
|
|
73407
73831
|
);
|
|
@@ -73814,7 +74238,7 @@ import {
|
|
|
73814
74238
|
import { nestedPostgresSqlState as nestedPostgresSqlState6 } from "@opengeni/db";
|
|
73815
74239
|
import { HTTPException as HTTPException46 } from "hono/http-exception";
|
|
73816
74240
|
import { z as z32 } from "zod";
|
|
73817
|
-
async function
|
|
74241
|
+
async function authorizeOrganizationIntegrationAdministration(context, deps, accountId, mutation) {
|
|
73818
74242
|
const access = await requireAccessContext4(context, deps);
|
|
73819
74243
|
const service = accountScopedApiKeyWorkspaceAuthority3(access);
|
|
73820
74244
|
if (service) {
|
|
@@ -73868,7 +74292,7 @@ function registerOrganizationIntegrationPolicyRoutes(app, deps) {
|
|
|
73868
74292
|
() => getOrganizationIntegrationPolicy(
|
|
73869
74293
|
deps.db,
|
|
73870
74294
|
{ accountId },
|
|
73871
|
-
() =>
|
|
74295
|
+
() => authorizeOrganizationIntegrationAdministration(context, deps, accountId, false)
|
|
73872
74296
|
)
|
|
73873
74297
|
);
|
|
73874
74298
|
context.header("cache-control", "private, no-store");
|
|
@@ -73882,7 +74306,7 @@ function registerOrganizationIntegrationPolicyRoutes(app, deps) {
|
|
|
73882
74306
|
() => getOrganizationIntegrationPolicy(
|
|
73883
74307
|
deps.db,
|
|
73884
74308
|
{ accountId },
|
|
73885
|
-
() =>
|
|
74309
|
+
() => authorizeOrganizationIntegrationAdministration(context, deps, accountId, false)
|
|
73886
74310
|
)
|
|
73887
74311
|
)
|
|
73888
74312
|
);
|
|
@@ -73900,7 +74324,7 @@ function registerOrganizationIntegrationPolicyRoutes(app, deps) {
|
|
|
73900
74324
|
deps.db,
|
|
73901
74325
|
{ accountId },
|
|
73902
74326
|
parsed.data,
|
|
73903
|
-
() =>
|
|
74327
|
+
() => authorizeOrganizationIntegrationAdministration(context, deps, accountId, true)
|
|
73904
74328
|
)
|
|
73905
74329
|
)
|
|
73906
74330
|
);
|
|
@@ -74062,7 +74486,7 @@ import {
|
|
|
74062
74486
|
encryptEnvironmentValue as encryptEnvironmentValue15,
|
|
74063
74487
|
brokeredCredentialBundleProblem,
|
|
74064
74488
|
getConnectionMetadata as getConnectionMetadata8,
|
|
74065
|
-
listConnectionsMetadata as
|
|
74489
|
+
listConnectionsMetadata as listConnectionsMetadata4,
|
|
74066
74490
|
listSlackInstallationBindings,
|
|
74067
74491
|
persistSlackBotInstallationWithSuccessAudit,
|
|
74068
74492
|
recordSlackBotInstallCallbackFailure,
|
|
@@ -74813,7 +75237,7 @@ import {
|
|
|
74813
75237
|
disconnectConnectionIdempotently as disconnectConnectionIdempotently3,
|
|
74814
75238
|
encryptEnvironmentValue as encryptEnvironmentValue14,
|
|
74815
75239
|
getConnectionMetadata as getConnectionMetadata7,
|
|
74816
|
-
listConnectionsMetadata as
|
|
75240
|
+
listConnectionsMetadata as listConnectionsMetadata3,
|
|
74817
75241
|
persistProviderOAuthConnection as persistProviderOAuthConnection2
|
|
74818
75242
|
} from "@opengeni/db";
|
|
74819
75243
|
import { createSignedState as createSignedState11, readSignedState as readSignedState10 } from "@opengeni/github";
|
|
@@ -74854,7 +75278,7 @@ function requirePersonalGitHubOAuthSettings(settings) {
|
|
|
74854
75278
|
};
|
|
74855
75279
|
}
|
|
74856
75280
|
async function listPersonalGitHubConnections(deps, input) {
|
|
74857
|
-
const visible = await
|
|
75281
|
+
const visible = await listConnectionsMetadata3(deps.db, input.workspaceId, input.subjectId);
|
|
74858
75282
|
return visible.filter(
|
|
74859
75283
|
(connection) => connection.subjectId === input.subjectId && isPersonalGitHubConnection(connection)
|
|
74860
75284
|
);
|
|
@@ -75418,7 +75842,7 @@ function registerConnectionRoutes(app, deps) {
|
|
|
75418
75842
|
const grant = await requireAccessGrant14(c, deps, workspaceId, "connections:read");
|
|
75419
75843
|
return c.json(
|
|
75420
75844
|
ListConnectionsResponse.parse({
|
|
75421
|
-
connections: await
|
|
75845
|
+
connections: await listConnectionsMetadata4(db, workspaceId, grant.subjectId)
|
|
75422
75846
|
})
|
|
75423
75847
|
);
|
|
75424
75848
|
});
|
|
@@ -76904,7 +77328,7 @@ import {
|
|
|
76904
77328
|
listPendingConnectAttempts,
|
|
76905
77329
|
withWorkspaceSubjectRls as withWorkspaceSubjectRls4,
|
|
76906
77330
|
installApiIntegration as installApiIntegration2,
|
|
76907
|
-
listConnectionsMetadata as
|
|
77331
|
+
listConnectionsMetadata as listConnectionsMetadata5,
|
|
76908
77332
|
getConnectionMetadata as getConnectionMetadata10,
|
|
76909
77333
|
createConnection as createConnection5,
|
|
76910
77334
|
updateConnection as updateConnection6,
|
|
@@ -77481,9 +77905,7 @@ import { ATLASSIAN_NATIVE_RETIRED_MESSAGE as ATLASSIAN_NATIVE_RETIRED_MESSAGE2 }
|
|
|
77481
77905
|
import {
|
|
77482
77906
|
CORE_INTEGRATION_DEFINITIONS as CORE_INTEGRATION_DEFINITIONS2,
|
|
77483
77907
|
INTEGRATION_DEFINITION_PRESENTATIONS,
|
|
77484
|
-
autoApprovalForbidden,
|
|
77485
77908
|
createPinnedIntegrationTransport,
|
|
77486
|
-
integrationDefinitionById as integrationDefinitionById3,
|
|
77487
77909
|
integrationFacetDefinitions
|
|
77488
77910
|
} from "@opengeni/capabilities";
|
|
77489
77911
|
import {
|
|
@@ -77884,16 +78306,6 @@ function validatedIntegrationInstallInput(grant, workspaceId, payload, resolved)
|
|
|
77884
78306
|
throw new HTTPException53(422, {
|
|
77885
78307
|
message: `autoApprovedTools must name selected Integration tools: ${outside.slice(0, 200)}`
|
|
77886
78308
|
});
|
|
77887
|
-
if (resolved.preview.definitionProvenance === "curated") {
|
|
77888
|
-
const definition = integrationDefinitionById3(resolved.preview.definitionId);
|
|
77889
|
-
const forbidden = resolved.preview.tools.find(
|
|
77890
|
-
(tool) => payload.autoApprovedTools.includes(tool.id) && autoApprovalForbidden(definition, tool.operationKey)
|
|
77891
|
-
);
|
|
77892
|
-
if (forbidden)
|
|
77893
|
-
throw new HTTPException53(422, {
|
|
77894
|
-
message: `This Integration requires human approval for ${forbidden.id.slice(0, 200)}; it cannot be auto-approved.`
|
|
77895
|
-
});
|
|
77896
|
-
}
|
|
77897
78309
|
}
|
|
77898
78310
|
return {
|
|
77899
78311
|
accountId: grant.accountId,
|
|
@@ -78543,7 +78955,7 @@ function registerConnectRoutes(app, deps) {
|
|
|
78543
78955
|
app.get("/v1/workspaces/:workspaceId/connect/accounts", async (c) => {
|
|
78544
78956
|
const workspaceId = c.req.param("workspaceId");
|
|
78545
78957
|
const { grant } = await requireAccessGrantAuthorization9(c, deps, workspaceId, "workspace:read");
|
|
78546
|
-
const connections = hasPermission13(grant.permissions, "connections:read") ? await
|
|
78958
|
+
const connections = hasPermission13(grant.permissions, "connections:read") ? await listConnectionsMetadata5(deps.db, workspaceId, grant.subjectId) : [];
|
|
78547
78959
|
const githubInstallations = hasPermission13(grant.permissions, "github:use") || hasPermission13(grant.permissions, "github:manage") ? await listGitHubInstallationAccessForWorkspace2(deps.db, workspaceId) : [];
|
|
78548
78960
|
const lensRegistrations = await listPrReviewAppRegistrations(
|
|
78549
78961
|
deps.db,
|
|
@@ -79440,7 +79852,7 @@ function registerConnectRoutes(app, deps) {
|
|
|
79440
79852
|
throw new HTTPException54(422, { message: "Select the service connection during setup" });
|
|
79441
79853
|
if (input.ownership === "personal" && !isPersonalConnectionOwnerPrincipal(authorization))
|
|
79442
79854
|
throw new HTTPException54(403, { message: "personal ownership unavailable" });
|
|
79443
|
-
const choices = hasPermission13(authorization.grant.permissions, "connections:read") ? (await
|
|
79855
|
+
const choices = hasPermission13(authorization.grant.permissions, "connections:read") ? (await listConnectionsMetadata5(tx, workspaceId, scope.subjectId)).filter(
|
|
79444
79856
|
(connection) => connection.status === "active" && (input.ownership === "workspace" ? connection.subjectId === null : connection.subjectId === scope.subjectId)
|
|
79445
79857
|
).map((connection) => ({
|
|
79446
79858
|
value: connection.id,
|
|
@@ -81621,7 +82033,7 @@ import {
|
|
|
81621
82033
|
} from "@opengeni/db";
|
|
81622
82034
|
import { HTTPException as HTTPException59 } from "hono/http-exception";
|
|
81623
82035
|
import {
|
|
81624
|
-
grantHasAgentAttemptAuthority as
|
|
82036
|
+
grantHasAgentAttemptAuthority as grantHasAgentAttemptAuthority3,
|
|
81625
82037
|
requireAccessGrant as requireAccessGrant18,
|
|
81626
82038
|
requireAccessGrantAuthorization as requireAccessGrantAuthorization14,
|
|
81627
82039
|
requireSessionAuthorization as requireSessionAuthorization7,
|
|
@@ -82165,7 +82577,7 @@ function registerMachineRoutes(app, deps) {
|
|
|
82165
82577
|
const grant = await requireAccessGrant18(c, deps, workspaceId, "sessions:control");
|
|
82166
82578
|
assertSelfhostedEnabled();
|
|
82167
82579
|
const sessionId = c.req.param("sessionId");
|
|
82168
|
-
if (
|
|
82580
|
+
if (grantHasAgentAttemptAuthority3(grant)) {
|
|
82169
82581
|
try {
|
|
82170
82582
|
await requireSessionAuthorization7(deps, grant, {
|
|
82171
82583
|
sessionId,
|
|
@@ -99785,6 +100197,7 @@ import { SandboxRecoveryRequest } from "@opengeni/contracts";
|
|
|
99785
100197
|
import { getManagedHumanSandboxRecovery, consentManagedHumanSandboxRecovery } from "@opengeni/core";
|
|
99786
100198
|
import { SandboxRecoveryConflictError } from "@opengeni/db";
|
|
99787
100199
|
import { getSessionCodexAccounts } from "@opengeni/db";
|
|
100200
|
+
import { getToolActionReview, getToolReviewDetailsPage } from "@opengeni/db";
|
|
99788
100201
|
import {
|
|
99789
100202
|
AcknowledgeStreamRequest,
|
|
99790
100203
|
ApplySessionGoalRevisionRequest,
|
|
@@ -101675,6 +102088,44 @@ function registerSessionRoutes(app, deps) {
|
|
|
101675
102088
|
throw error;
|
|
101676
102089
|
}
|
|
101677
102090
|
});
|
|
102091
|
+
app.get("/v1/workspaces/:workspaceId/sessions/:sessionId/tool-reviews/:approvalId", async (c) => {
|
|
102092
|
+
const workspaceId = c.req.param("workspaceId");
|
|
102093
|
+
const grant = await requireAccessGrant37(c, deps, workspaceId, "sessions:read");
|
|
102094
|
+
const input = {
|
|
102095
|
+
accountId: grant.accountId,
|
|
102096
|
+
workspaceId,
|
|
102097
|
+
sessionId: c.req.param("sessionId"),
|
|
102098
|
+
approvalId: c.req.param("approvalId")
|
|
102099
|
+
};
|
|
102100
|
+
const review = await getToolActionReview(db, input);
|
|
102101
|
+
if (!review) throw new HTTPException88(404, { message: "Review not found" });
|
|
102102
|
+
c.header("Cache-Control", "private, no-store");
|
|
102103
|
+
return c.json(review);
|
|
102104
|
+
});
|
|
102105
|
+
app.get(
|
|
102106
|
+
"/v1/workspaces/:workspaceId/sessions/:sessionId/tool-reviews/:approvalId/details",
|
|
102107
|
+
async (c) => {
|
|
102108
|
+
const workspaceId = c.req.param("workspaceId");
|
|
102109
|
+
const grant = await requireAccessGrant37(c, deps, workspaceId, "sessions:read");
|
|
102110
|
+
const query = z45.object({
|
|
102111
|
+
actionDigest: z45.string().regex(/^[0-9a-f]{64}$/),
|
|
102112
|
+
path: z45.string().max(2048).default(""),
|
|
102113
|
+
offset: z45.coerce.number().int().min(0).max(4194304).default(0)
|
|
102114
|
+
}).safeParse(c.req.query());
|
|
102115
|
+
if (!query.success) throw new HTTPException88(400, { message: "Invalid review page" });
|
|
102116
|
+
const input = {
|
|
102117
|
+
accountId: grant.accountId,
|
|
102118
|
+
workspaceId,
|
|
102119
|
+
sessionId: c.req.param("sessionId"),
|
|
102120
|
+
approvalId: c.req.param("approvalId"),
|
|
102121
|
+
...query.data
|
|
102122
|
+
};
|
|
102123
|
+
const page2 = await getToolReviewDetailsPage(db, input);
|
|
102124
|
+
if (!page2) throw new HTTPException88(404, { message: "Review details unavailable" });
|
|
102125
|
+
c.header("Cache-Control", "private, no-store");
|
|
102126
|
+
return c.json(page2);
|
|
102127
|
+
}
|
|
102128
|
+
);
|
|
101678
102129
|
app.get("/v1/workspaces/:workspaceId/sessions/:sessionId", async (c) => {
|
|
101679
102130
|
const workspaceId = c.req.param("workspaceId");
|
|
101680
102131
|
const grant = await requireAccessGrant37(c, deps, workspaceId, "sessions:read");
|
|
@@ -105131,6 +105582,7 @@ function sessionAuthorizationOperationForHttp(method, pathname, sessionId) {
|
|
|
105131
105582
|
if (suffix === "/lineage" && verb === "GET") return "session.lineage.read";
|
|
105132
105583
|
if (suffix === "/background-commands" && verb === "GET") return "session.read";
|
|
105133
105584
|
if (suffix === "/model-context" && verb === "GET") return "session.read";
|
|
105585
|
+
if (/^\/tool-reviews\/[^/]+(?:\/details)?$/.test(suffix) && verb === "GET") return "session.read";
|
|
105134
105586
|
if (suffix === "/codex-accounts" && verb === "GET") return "session.read";
|
|
105135
105587
|
if (/^\/background-commands\/[^/]+$/.test(suffix) && verb === "DELETE") {
|
|
105136
105588
|
return "session.control";
|
|
@@ -106347,7 +106799,7 @@ function socialHttpException(error) {
|
|
|
106347
106799
|
|
|
106348
106800
|
// src/routes/workspaces.ts
|
|
106349
106801
|
import { withDirectModelProviders } from "@opengeni/config";
|
|
106350
|
-
import { listConnectionsMetadata as
|
|
106802
|
+
import { listConnectionsMetadata as listConnectionsMetadata6 } from "@opengeni/db";
|
|
106351
106803
|
import {
|
|
106352
106804
|
workspaceProviderApiKeyConnectionMetadataFromConnections,
|
|
106353
106805
|
listWorkspaceProviderCustomModelsByKind,
|
|
@@ -106936,7 +107388,7 @@ function registerWorkspaceRoutes(app, deps) {
|
|
|
106936
107388
|
workspaceId,
|
|
106937
107389
|
subjectId: grant.subjectId
|
|
106938
107390
|
}),
|
|
106939
|
-
|
|
107391
|
+
listConnectionsMetadata6(deps.db, workspaceId, null),
|
|
106940
107392
|
listWorkspaceProviderCustomModelsByKind(deps.db, {
|
|
106941
107393
|
accountId: grant.accountId,
|
|
106942
107394
|
workspaceId,
|
|
@@ -109577,6 +110029,111 @@ function registerSlackTaskPolicyRoutes(app, deps) {
|
|
|
109577
110029
|
});
|
|
109578
110030
|
}
|
|
109579
110031
|
|
|
110032
|
+
// src/routes/slack-bot-access.ts
|
|
110033
|
+
import {
|
|
110034
|
+
AvailableOpenGeniSlackBots,
|
|
110035
|
+
OpenGeniSlackBotOrganizationAccess,
|
|
110036
|
+
UpdateOpenGeniSlackBotOrganizationAccess
|
|
110037
|
+
} from "@opengeni/contracts";
|
|
110038
|
+
import {
|
|
110039
|
+
isOpenGeniSlackBotConnection as isOpenGeniSlackBotConnection5,
|
|
110040
|
+
requireAccessGrant as requireAccessGrant45
|
|
110041
|
+
} from "@opengeni/core";
|
|
110042
|
+
import {
|
|
110043
|
+
availableSlackBotConnectionMetadata as availableSlackBotConnectionMetadata2,
|
|
110044
|
+
nestedPostgresSqlState as nestedPostgresSqlState13,
|
|
110045
|
+
readOrganizationSlackBotAccess,
|
|
110046
|
+
setOrganizationSlackBotAccess,
|
|
110047
|
+
sharedOrganizationSlackBots as sharedOrganizationSlackBots2
|
|
110048
|
+
} from "@opengeni/db";
|
|
110049
|
+
import { HTTPException as HTTPException99 } from "hono/http-exception";
|
|
110050
|
+
import { z as z51 } from "zod";
|
|
110051
|
+
function registerSlackBotAccessRoutes(app, deps) {
|
|
110052
|
+
const base = "/v1/workspaces/:workspaceId/connections";
|
|
110053
|
+
app.get(`${base}/:connectionId/slack-bot/organization-access`, async (context) => {
|
|
110054
|
+
const grant = await requireAccessGrant45(
|
|
110055
|
+
context,
|
|
110056
|
+
deps,
|
|
110057
|
+
context.req.param("workspaceId"),
|
|
110058
|
+
"connections:read"
|
|
110059
|
+
);
|
|
110060
|
+
const connectionId = z51.string().uuid().safeParse(context.req.param("connectionId"));
|
|
110061
|
+
if (!connectionId.success) throw new HTTPException99(422, { message: "Invalid bot connection" });
|
|
110062
|
+
context.header("cache-control", "private, no-store");
|
|
110063
|
+
try {
|
|
110064
|
+
return context.json(
|
|
110065
|
+
OpenGeniSlackBotOrganizationAccess.parse(
|
|
110066
|
+
await readOrganizationSlackBotAccess(deps.db, {
|
|
110067
|
+
accountId: grant.accountId,
|
|
110068
|
+
workspaceId: grant.workspaceId,
|
|
110069
|
+
connectionId: connectionId.data
|
|
110070
|
+
})
|
|
110071
|
+
)
|
|
110072
|
+
);
|
|
110073
|
+
} catch (error) {
|
|
110074
|
+
if (nestedPostgresSqlState13(error) === "42501")
|
|
110075
|
+
throw new HTTPException99(404, { message: "Local bot installation unavailable" });
|
|
110076
|
+
throw error;
|
|
110077
|
+
}
|
|
110078
|
+
});
|
|
110079
|
+
app.get(`${base}/slack-bot/available`, async (context) => {
|
|
110080
|
+
const grant = await requireAccessGrant45(
|
|
110081
|
+
context,
|
|
110082
|
+
deps,
|
|
110083
|
+
context.req.param("workspaceId"),
|
|
110084
|
+
"connections:read"
|
|
110085
|
+
);
|
|
110086
|
+
context.header("cache-control", "private, no-store");
|
|
110087
|
+
const [connections, shares] = await Promise.all([
|
|
110088
|
+
availableSlackBotConnectionMetadata2(deps.db, grant),
|
|
110089
|
+
sharedOrganizationSlackBots2(deps.db, grant)
|
|
110090
|
+
]);
|
|
110091
|
+
return context.json(
|
|
110092
|
+
AvailableOpenGeniSlackBots.parse({
|
|
110093
|
+
connections: connections.filter(
|
|
110094
|
+
(connection) => connection.status === "active" && isOpenGeniSlackBotConnection5(connection)
|
|
110095
|
+
),
|
|
110096
|
+
organizationSharedConnectionIds: shares.map((share) => share.connectionId)
|
|
110097
|
+
})
|
|
110098
|
+
);
|
|
110099
|
+
});
|
|
110100
|
+
app.put(`${base}/:connectionId/slack-bot/organization-access`, async (context) => {
|
|
110101
|
+
const grant = await requireAccessGrant45(
|
|
110102
|
+
context,
|
|
110103
|
+
deps,
|
|
110104
|
+
context.req.param("workspaceId"),
|
|
110105
|
+
"connections:write"
|
|
110106
|
+
);
|
|
110107
|
+
const connectionId = z51.string().uuid().safeParse(context.req.param("connectionId"));
|
|
110108
|
+
const request = UpdateOpenGeniSlackBotOrganizationAccess.safeParse(
|
|
110109
|
+
await context.req.json().catch(() => null)
|
|
110110
|
+
);
|
|
110111
|
+
if (!connectionId.success || !request.success)
|
|
110112
|
+
throw new HTTPException99(422, { message: "Invalid bot access setting" });
|
|
110113
|
+
context.header("cache-control", "private, no-store");
|
|
110114
|
+
try {
|
|
110115
|
+
const result = await setOrganizationSlackBotAccess(
|
|
110116
|
+
deps.db,
|
|
110117
|
+
{
|
|
110118
|
+
accountId: grant.accountId,
|
|
110119
|
+
workspaceId: grant.workspaceId,
|
|
110120
|
+
connectionId: connectionId.data,
|
|
110121
|
+
enabled: request.data.enabled
|
|
110122
|
+
},
|
|
110123
|
+
() => authorizeOrganizationIntegrationAdministration(context, deps, grant.accountId, true)
|
|
110124
|
+
);
|
|
110125
|
+
return context.json(OpenGeniSlackBotOrganizationAccess.parse(result));
|
|
110126
|
+
} catch (error) {
|
|
110127
|
+
if (error instanceof HTTPException99) throw error;
|
|
110128
|
+
if (nestedPostgresSqlState13(error) === "42501")
|
|
110129
|
+
throw new HTTPException99(403, {
|
|
110130
|
+
message: "Organization administrator and a verified local bot installation required"
|
|
110131
|
+
});
|
|
110132
|
+
throw error;
|
|
110133
|
+
}
|
|
110134
|
+
});
|
|
110135
|
+
}
|
|
110136
|
+
|
|
109580
110137
|
// src/routes/workspace-state.ts
|
|
109581
110138
|
import {
|
|
109582
110139
|
WORKSPACE_STATE_KNOWLEDGE_SAMPLE_LIMIT as WORKSPACE_STATE_KNOWLEDGE_SAMPLE_LIMIT3,
|
|
@@ -109595,7 +110152,7 @@ import {
|
|
|
109595
110152
|
listKnowledgeEntries as listKnowledgeEntries4,
|
|
109596
110153
|
listWorkspaceInstructionPolicyRevisions as listWorkspaceInstructionPolicyRevisions3
|
|
109597
110154
|
} from "@opengeni/db";
|
|
109598
|
-
import { HTTPException as
|
|
110155
|
+
import { HTTPException as HTTPException100 } from "hono/http-exception";
|
|
109599
110156
|
|
|
109600
110157
|
// src/workspace-state-export.ts
|
|
109601
110158
|
import { createHash as createHash27 } from "crypto";
|
|
@@ -109667,7 +110224,7 @@ async function readWorkspaceState(deps, input) {
|
|
|
109667
110224
|
attemptId: query.attemptId
|
|
109668
110225
|
}) : Promise.resolve(null)
|
|
109669
110226
|
]);
|
|
109670
|
-
if (!workspace) throw new
|
|
110227
|
+
if (!workspace) throw new HTTPException100(404, { message: "workspace not found" });
|
|
109671
110228
|
const attemptGovernance = query.attemptId ? acceptedAttempt ? {
|
|
109672
110229
|
status: "available",
|
|
109673
110230
|
attemptId: acceptedAttempt.attemptId,
|
|
@@ -109754,7 +110311,7 @@ import {
|
|
|
109754
110311
|
normalizeWorkspaceArtifactSlug as normalizeWorkspaceArtifactSlug2
|
|
109755
110312
|
} from "@opengeni/contracts";
|
|
109756
110313
|
import {
|
|
109757
|
-
requireAccessGrant as
|
|
110314
|
+
requireAccessGrant as requireAccessGrant46,
|
|
109758
110315
|
requireAccessGrantAuthorization as requireAccessGrantAuthorization35,
|
|
109759
110316
|
requireSessionAuthorization as requireSessionAuthorization13,
|
|
109760
110317
|
SessionAuthorizationDeniedError as SessionAuthorizationDeniedError13,
|
|
@@ -109765,7 +110322,7 @@ import {
|
|
|
109765
110322
|
getWorkspaceArtifact as getWorkspaceArtifact3,
|
|
109766
110323
|
getWorkspaceArtifactContentRef as getWorkspaceArtifactContentRef3,
|
|
109767
110324
|
listWorkspaceArtifacts as listWorkspaceArtifacts2,
|
|
109768
|
-
nestedPostgresSqlState as
|
|
110325
|
+
nestedPostgresSqlState as nestedPostgresSqlState14,
|
|
109769
110326
|
publishWorkspaceArtifactVersion as publishWorkspaceArtifactVersion2,
|
|
109770
110327
|
rollbackWorkspaceArtifact as rollbackWorkspaceArtifact2,
|
|
109771
110328
|
setWorkspaceArtifactStatus as setWorkspaceArtifactStatus2,
|
|
@@ -109773,23 +110330,23 @@ import {
|
|
|
109773
110330
|
WorkspaceArtifactNotFoundError as WorkspaceArtifactNotFoundError3,
|
|
109774
110331
|
WorkspaceArtifactOperationError as WorkspaceArtifactOperationError2
|
|
109775
110332
|
} from "@opengeni/db";
|
|
109776
|
-
import { HTTPException as
|
|
109777
|
-
import { z as
|
|
109778
|
-
var ArtifactId3 =
|
|
110333
|
+
import { HTTPException as HTTPException101 } from "hono/http-exception";
|
|
110334
|
+
import { z as z52 } from "zod";
|
|
110335
|
+
var ArtifactId3 = z52.string().uuid();
|
|
109779
110336
|
async function body(context, schema) {
|
|
109780
110337
|
const parsed = schema.safeParse(await context.req.json().catch(() => null));
|
|
109781
|
-
if (!parsed.success) throw new
|
|
110338
|
+
if (!parsed.success) throw new HTTPException101(422, { message: "Invalid artifact request" });
|
|
109782
110339
|
return parsed.data;
|
|
109783
110340
|
}
|
|
109784
110341
|
function parseVersionId(value) {
|
|
109785
110342
|
if (value !== void 0 && !ArtifactId3.safeParse(value).success) {
|
|
109786
|
-
throw new
|
|
110343
|
+
throw new HTTPException101(422, { message: "Invalid artifact version id" });
|
|
109787
110344
|
}
|
|
109788
110345
|
return value;
|
|
109789
110346
|
}
|
|
109790
110347
|
function artifactId(context) {
|
|
109791
110348
|
const parsed = ArtifactId3.safeParse(context.req.param("artifactId"));
|
|
109792
|
-
if (!parsed.success) throw new
|
|
110349
|
+
if (!parsed.success) throw new HTTPException101(422, { message: "Invalid artifact id" });
|
|
109793
110350
|
return parsed.data;
|
|
109794
110351
|
}
|
|
109795
110352
|
function workspaceArtifactErrorResponse(context, error) {
|
|
@@ -109812,7 +110369,7 @@ function workspaceArtifactErrorResponse(context, error) {
|
|
|
109812
110369
|
422
|
|
109813
110370
|
);
|
|
109814
110371
|
}
|
|
109815
|
-
if (
|
|
110372
|
+
if (nestedPostgresSqlState14(error) === "23505") {
|
|
109816
110373
|
return context.json(
|
|
109817
110374
|
{
|
|
109818
110375
|
code: "WORKSPACE_ARTIFACT_CONFLICT",
|
|
@@ -109825,7 +110382,7 @@ function workspaceArtifactErrorResponse(context, error) {
|
|
|
109825
110382
|
}
|
|
109826
110383
|
function prepareContent(deps, grant, input) {
|
|
109827
110384
|
if (!deps.objectStorage)
|
|
109828
|
-
throw new
|
|
110385
|
+
throw new HTTPException101(503, {
|
|
109829
110386
|
message: "Object storage is not configured"
|
|
109830
110387
|
});
|
|
109831
110388
|
return prepareWorkspaceArtifactPublication(deps, grant, input);
|
|
@@ -109852,7 +110409,7 @@ async function canReadProvenanceSession(deps, grant, sessionId) {
|
|
|
109852
110409
|
} catch (error) {
|
|
109853
110410
|
if (error instanceof SessionAuthorizationDeniedError13) return false;
|
|
109854
110411
|
if (error instanceof SessionAuthorizationUnavailableError11) {
|
|
109855
|
-
throw new
|
|
110412
|
+
throw new HTTPException101(503, {
|
|
109856
110413
|
message: "Session authorization is unavailable"
|
|
109857
110414
|
});
|
|
109858
110415
|
}
|
|
@@ -109870,7 +110427,7 @@ async function mutationResponse(deps, grant, response) {
|
|
|
109870
110427
|
function registerWorkspaceArtifactRoutes(app, deps) {
|
|
109871
110428
|
const base = "/v1/workspaces/:workspaceId/published-artifacts";
|
|
109872
110429
|
app.post(`${base}/uploads`, async (context) => {
|
|
109873
|
-
const grant = await
|
|
110430
|
+
const grant = await requireAccessGrant46(
|
|
109874
110431
|
context,
|
|
109875
110432
|
deps,
|
|
109876
110433
|
context.req.param("workspaceId"),
|
|
@@ -109880,9 +110437,9 @@ function registerWorkspaceArtifactRoutes(app, deps) {
|
|
|
109880
110437
|
});
|
|
109881
110438
|
app.get(`${base}/:artifactId/downloads`, async (context) => {
|
|
109882
110439
|
const workspaceId = context.req.param("workspaceId");
|
|
109883
|
-
await
|
|
110440
|
+
await requireAccessGrant46(context, deps, workspaceId, "artifacts:read");
|
|
109884
110441
|
if (!deps.objectStorage)
|
|
109885
|
-
throw new
|
|
110442
|
+
throw new HTTPException101(503, {
|
|
109886
110443
|
message: "Object storage is not configured"
|
|
109887
110444
|
});
|
|
109888
110445
|
const ref = await getWorkspaceArtifactContentRef3(
|
|
@@ -109895,16 +110452,16 @@ function registerWorkspaceArtifactRoutes(app, deps) {
|
|
|
109895
110452
|
});
|
|
109896
110453
|
app.get(base, async (context) => {
|
|
109897
110454
|
const workspaceId = context.req.param("workspaceId");
|
|
109898
|
-
const grant = await
|
|
110455
|
+
const grant = await requireAccessGrant46(context, deps, workspaceId, "artifacts:read");
|
|
109899
110456
|
const query = WorkspaceArtifactListQuery.safeParse({
|
|
109900
110457
|
limit: context.req.query("limit"),
|
|
109901
110458
|
cursor: context.req.query("cursor"),
|
|
109902
110459
|
status: context.req.query("status"),
|
|
109903
110460
|
sourceSessionId: context.req.query("sourceSessionId")
|
|
109904
110461
|
});
|
|
109905
|
-
if (!query.success) throw new
|
|
110462
|
+
if (!query.success) throw new HTTPException101(422, { message: "Invalid artifact list query" });
|
|
109906
110463
|
if (query.data.sourceSessionId && !await canReadProvenanceSession(deps, grant, query.data.sourceSessionId)) {
|
|
109907
|
-
throw new
|
|
110464
|
+
throw new HTTPException101(404, { message: "Session not found" });
|
|
109908
110465
|
}
|
|
109909
110466
|
try {
|
|
109910
110467
|
return context.json(
|
|
@@ -109967,7 +110524,7 @@ function registerWorkspaceArtifactRoutes(app, deps) {
|
|
|
109967
110524
|
});
|
|
109968
110525
|
app.get(`${base}/:artifactId`, async (context) => {
|
|
109969
110526
|
const workspaceId = context.req.param("workspaceId");
|
|
109970
|
-
const grant = await
|
|
110527
|
+
const grant = await requireAccessGrant46(context, deps, workspaceId, "artifacts:read");
|
|
109971
110528
|
try {
|
|
109972
110529
|
const detail = await getWorkspaceArtifact3(deps.db, workspaceId, artifactId(context));
|
|
109973
110530
|
return context.json(
|
|
@@ -109984,9 +110541,9 @@ function registerWorkspaceArtifactRoutes(app, deps) {
|
|
|
109984
110541
|
});
|
|
109985
110542
|
app.get(`${base}/:artifactId/html`, async (context) => {
|
|
109986
110543
|
const workspaceId = context.req.param("workspaceId");
|
|
109987
|
-
await
|
|
110544
|
+
await requireAccessGrant46(context, deps, workspaceId, "artifacts:read");
|
|
109988
110545
|
if (!deps.objectStorage)
|
|
109989
|
-
throw new
|
|
110546
|
+
throw new HTTPException101(503, {
|
|
109990
110547
|
message: "Object storage is not configured"
|
|
109991
110548
|
});
|
|
109992
110549
|
const ref = await getWorkspaceArtifactContentRef3(
|
|
@@ -110030,9 +110587,9 @@ function registerWorkspaceArtifactRoutes(app, deps) {
|
|
|
110030
110587
|
});
|
|
110031
110588
|
app.get(`${base}/:artifactId/content`, async (context) => {
|
|
110032
110589
|
const workspaceId = context.req.param("workspaceId");
|
|
110033
|
-
await
|
|
110590
|
+
await requireAccessGrant46(context, deps, workspaceId, "artifacts:read");
|
|
110034
110591
|
if (!deps.objectStorage)
|
|
110035
|
-
throw new
|
|
110592
|
+
throw new HTTPException101(503, {
|
|
110036
110593
|
message: "Object storage is not configured"
|
|
110037
110594
|
});
|
|
110038
110595
|
const parsedVersion = parseVersionId(context.req.query("versionId"));
|
|
@@ -110047,7 +110604,7 @@ function registerWorkspaceArtifactRoutes(app, deps) {
|
|
|
110047
110604
|
try {
|
|
110048
110605
|
content = await readWorkspaceArtifactContent(deps.objectStorage, ref);
|
|
110049
110606
|
} catch (error) {
|
|
110050
|
-
throw new
|
|
110607
|
+
throw new HTTPException101(503, {
|
|
110051
110608
|
message: error instanceof Error ? error.message : "Artifact content is unavailable",
|
|
110052
110609
|
cause: error
|
|
110053
110610
|
});
|
|
@@ -110183,7 +110740,7 @@ import {
|
|
|
110183
110740
|
editableArtifactId as editableArtifactId3,
|
|
110184
110741
|
editableArtifactScope as editableArtifactScope2,
|
|
110185
110742
|
fileOwnerContextForAccess as fileOwnerContextForAccess5,
|
|
110186
|
-
grantHasAgentAttemptAuthority as
|
|
110743
|
+
grantHasAgentAttemptAuthority as grantHasAgentAttemptAuthority4,
|
|
110187
110744
|
hasPermission as hasPermission27,
|
|
110188
110745
|
requireAccessGrantAuthorization as requireAccessGrantAuthorization36,
|
|
110189
110746
|
requireLiveAgentAttemptAuthorization as requireLiveAgentAttemptAuthorization5,
|
|
@@ -110196,27 +110753,27 @@ import {
|
|
|
110196
110753
|
getGeneratedImageArtifact as getGeneratedImageArtifact2,
|
|
110197
110754
|
getSessionAuthorityProjection as getSessionAuthorityProjection3,
|
|
110198
110755
|
listArtifactCatalogCandidates,
|
|
110199
|
-
nestedPostgresSqlState as
|
|
110756
|
+
nestedPostgresSqlState as nestedPostgresSqlState15,
|
|
110200
110757
|
updateArtifactPin,
|
|
110201
110758
|
withSessionRlsActorContext as withSessionRlsActorContext9
|
|
110202
110759
|
} from "@opengeni/db";
|
|
110203
|
-
import { HTTPException as
|
|
110204
|
-
import { z as
|
|
110760
|
+
import { HTTPException as HTTPException103 } from "hono/http-exception";
|
|
110761
|
+
import { z as z54 } from "zod";
|
|
110205
110762
|
|
|
110206
110763
|
// src/artifact-catalog-cursor.ts
|
|
110207
110764
|
import { createCipheriv as createCipheriv2, createDecipheriv as createDecipheriv2, createHash as createHash29, randomBytes as randomBytes12 } from "crypto";
|
|
110208
110765
|
import { ArtifactCatalogKind } from "@opengeni/contracts";
|
|
110209
|
-
import { HTTPException as
|
|
110210
|
-
import { z as
|
|
110211
|
-
var Cursor =
|
|
110212
|
-
version:
|
|
110213
|
-
snapshotAt:
|
|
110214
|
-
expiresAt:
|
|
110215
|
-
after:
|
|
110216
|
-
key:
|
|
110766
|
+
import { HTTPException as HTTPException102 } from "hono/http-exception";
|
|
110767
|
+
import { z as z53 } from "zod";
|
|
110768
|
+
var Cursor = z53.object({
|
|
110769
|
+
version: z53.literal(1),
|
|
110770
|
+
snapshotAt: z53.string().datetime(),
|
|
110771
|
+
expiresAt: z53.number().int().positive(),
|
|
110772
|
+
after: z53.object({
|
|
110773
|
+
key: z53.string().max(4096),
|
|
110217
110774
|
kind: ArtifactCatalogKind,
|
|
110218
|
-
id:
|
|
110219
|
-
pinned:
|
|
110775
|
+
id: z53.string().min(1).max(128),
|
|
110776
|
+
pinned: z53.boolean().optional()
|
|
110220
110777
|
}).strict()
|
|
110221
110778
|
}).strict();
|
|
110222
110779
|
function artifactCatalogCursorCodec(secret, binding) {
|
|
@@ -110250,7 +110807,7 @@ function artifactCatalogCursorCodec(secret, binding) {
|
|
|
110250
110807
|
throw new Error();
|
|
110251
110808
|
return parsed;
|
|
110252
110809
|
} catch {
|
|
110253
|
-
throw new
|
|
110810
|
+
throw new HTTPException102(422, { message: "Invalid or expired artifact catalog cursor" });
|
|
110254
110811
|
}
|
|
110255
110812
|
}
|
|
110256
110813
|
};
|
|
@@ -110278,22 +110835,22 @@ function registerArtifactCatalogRoutes(app, deps) {
|
|
|
110278
110835
|
);
|
|
110279
110836
|
const grant = authorization.grant;
|
|
110280
110837
|
if (!hasPermission27(grant.permissions, "artifacts:publish"))
|
|
110281
|
-
throw new
|
|
110838
|
+
throw new HTTPException103(403, { message: "Artifact publish access required" });
|
|
110282
110839
|
const kind = ArtifactCatalogKind2.safeParse(context.req.param("kind"));
|
|
110283
110840
|
const body3 = UpdateArtifactPinRequest.safeParse(await context.req.json().catch(() => null));
|
|
110284
110841
|
const requestedId = context.req.param("artifactId");
|
|
110285
|
-
if (!kind.success || !body3.success || !(editableKinds.has(kind.data) ? /^[0-9a-f]{32}$/.test(requestedId) :
|
|
110286
|
-
throw new
|
|
110842
|
+
if (!kind.success || !body3.success || !(editableKinds.has(kind.data) ? /^[0-9a-f]{32}$/.test(requestedId) : z54.string().uuid().safeParse(requestedId).success))
|
|
110843
|
+
throw new HTTPException103(422, { message: "Invalid artifact pin request" });
|
|
110287
110844
|
const artifactId2 = editableKinds.has(kind.data) ? requestedId : requestedId.toLowerCase();
|
|
110288
110845
|
const fileKind = kind.data === "file" || kind.data === "image";
|
|
110289
110846
|
if (!hasPermission27(grant.permissions, fileKind ? "files:read" : "artifacts:read"))
|
|
110290
|
-
throw new
|
|
110847
|
+
throw new HTTPException103(403, { message: "Artifact read access required" });
|
|
110291
110848
|
const actor = fileKind ? await fileOwnerContextForAccess5(deps, authorization, "files:read") : { subjectId: grant.subjectId, privateFileOwnerSubjectId: null };
|
|
110292
110849
|
context.header("cache-control", "private, no-store");
|
|
110293
110850
|
return withSessionRlsActorContext9(actor, async () => {
|
|
110294
110851
|
if (editableKinds.has(kind.data)) {
|
|
110295
110852
|
if (!deps.editableArtifacts)
|
|
110296
|
-
throw new
|
|
110853
|
+
throw new HTTPException103(503, { message: "Editable artifacts are unavailable" });
|
|
110297
110854
|
try {
|
|
110298
110855
|
const scope = editableArtifactScope2({ accountId: grant.accountId, workspaceId });
|
|
110299
110856
|
const artifact = await deps.editableArtifacts.readArtifact({
|
|
@@ -110302,10 +110859,10 @@ function registerArtifactCatalogRoutes(app, deps) {
|
|
|
110302
110859
|
artifactId: editableArtifactId3(artifactId2)
|
|
110303
110860
|
});
|
|
110304
110861
|
if (artifact.scope.accountId !== scope.accountId || artifact.scope.workspaceId !== scope.workspaceId || artifact.id !== artifactId2 || artifact.modality !== kind.data)
|
|
110305
|
-
throw new
|
|
110862
|
+
throw new HTTPException103(404, { message: "Artifact not found" });
|
|
110306
110863
|
} catch (error) {
|
|
110307
110864
|
if (isInvisibleListCandidate(error))
|
|
110308
|
-
throw new
|
|
110865
|
+
throw new HTTPException103(404, { message: "Artifact not found" });
|
|
110309
110866
|
throw editableArtifactHttpError(error);
|
|
110310
110867
|
}
|
|
110311
110868
|
}
|
|
@@ -110318,7 +110875,7 @@ function registerArtifactCatalogRoutes(app, deps) {
|
|
|
110318
110875
|
fileIds: [artifactId2]
|
|
110319
110876
|
});
|
|
110320
110877
|
if (!file || file.status !== "ready")
|
|
110321
|
-
throw new
|
|
110878
|
+
throw new HTTPException103(404, { message: "Artifact not found" });
|
|
110322
110879
|
}
|
|
110323
110880
|
try {
|
|
110324
110881
|
await updateArtifactPin(
|
|
@@ -110331,8 +110888,8 @@ function registerArtifactCatalogRoutes(app, deps) {
|
|
|
110331
110888
|
}
|
|
110332
110889
|
);
|
|
110333
110890
|
} catch (error) {
|
|
110334
|
-
if (
|
|
110335
|
-
throw new
|
|
110891
|
+
if (nestedPostgresSqlState15(error) === "42501")
|
|
110892
|
+
throw new HTTPException103(404, { message: "Artifact not found" });
|
|
110336
110893
|
throw error;
|
|
110337
110894
|
}
|
|
110338
110895
|
return context.json(
|
|
@@ -110346,23 +110903,23 @@ function registerArtifactCatalogRoutes(app, deps) {
|
|
|
110346
110903
|
const grant = authorization.grant;
|
|
110347
110904
|
const parsed = ArtifactCatalogListQuery.safeParse(context.req.query());
|
|
110348
110905
|
if (!parsed.success)
|
|
110349
|
-
throw new
|
|
110906
|
+
throw new HTTPException103(422, { message: "Invalid artifact catalog query" });
|
|
110350
110907
|
const query = parsed.data;
|
|
110351
110908
|
const artifactsAllowed = hasPermission27(grant.permissions, "artifacts:read");
|
|
110352
110909
|
const filesAllowed = hasPermission27(grant.permissions, "files:read");
|
|
110353
110910
|
if (!artifactsAllowed && !filesAllowed)
|
|
110354
|
-
throw new
|
|
110911
|
+
throw new HTTPException103(403, { message: "Artifact catalog read access required" });
|
|
110355
110912
|
let kinds = ArtifactCatalogKind2.options.filter(
|
|
110356
110913
|
(kind) => (kind === "image" || kind === "file" ? filesAllowed : artifactsAllowed) && (!query.kind || kind === query.kind)
|
|
110357
110914
|
);
|
|
110358
110915
|
if (!deps.editableArtifacts) {
|
|
110359
110916
|
if (query.kind && editableKinds.has(query.kind) && artifactsAllowed)
|
|
110360
|
-
throw new
|
|
110917
|
+
throw new HTTPException103(503, { message: "Editable artifacts are unavailable" });
|
|
110361
110918
|
kinds = kinds.filter((kind) => !editableKinds.has(kind));
|
|
110362
110919
|
}
|
|
110363
110920
|
const includesFiles = kinds.includes("file") || kinds.includes("image");
|
|
110364
110921
|
const actor = includesFiles ? await fileOwnerContextForAccess5(deps, authorization, "files:read") : { subjectId: grant.subjectId, privateFileOwnerSubjectId: null };
|
|
110365
|
-
if (
|
|
110922
|
+
if (grantHasAgentAttemptAuthority4(grant) && actor.initiatingHumanSubjectId === void 0) {
|
|
110366
110923
|
const callerSessionId = grant.metadata?.["sessionId"];
|
|
110367
110924
|
try {
|
|
110368
110925
|
if (typeof callerSessionId !== "string")
|
|
@@ -110371,7 +110928,7 @@ function registerArtifactCatalogRoutes(app, deps) {
|
|
|
110371
110928
|
actor.initiatingHumanSubjectId = attempt.initiatingHumanSubjectId;
|
|
110372
110929
|
} catch (error) {
|
|
110373
110930
|
if (error instanceof SessionAuthorizationDeniedError14)
|
|
110374
|
-
throw new
|
|
110931
|
+
throw new HTTPException103(404, { message: "Session not found", cause: error });
|
|
110375
110932
|
throw error;
|
|
110376
110933
|
}
|
|
110377
110934
|
}
|
|
@@ -110397,17 +110954,17 @@ function registerArtifactCatalogRoutes(app, deps) {
|
|
|
110397
110954
|
return false;
|
|
110398
110955
|
}
|
|
110399
110956
|
if (error instanceof SessionAuthorizationUnavailableError12)
|
|
110400
|
-
throw new
|
|
110957
|
+
throw new HTTPException103(503, { message: "Session authorization is unavailable" });
|
|
110401
110958
|
throw error;
|
|
110402
110959
|
}
|
|
110403
110960
|
};
|
|
110404
110961
|
context.header("cache-control", "private, no-store");
|
|
110405
110962
|
return withSessionRlsActorContext9(actor, async () => {
|
|
110406
110963
|
if (query.sourceSessionId && !await canReadSession(query.sourceSessionId))
|
|
110407
|
-
throw new
|
|
110964
|
+
throw new HTTPException103(404, { message: "Session not found" });
|
|
110408
110965
|
const secret = resolveFirstPartyDelegationSecret6(deps.settings);
|
|
110409
110966
|
if (!secret)
|
|
110410
|
-
throw new
|
|
110967
|
+
throw new HTTPException103(503, { message: "Artifact catalog cursor signing is unavailable" });
|
|
110411
110968
|
const filters = { ...query, cursor: void 0 };
|
|
110412
110969
|
const codec = artifactCatalogCursorCodec(
|
|
110413
110970
|
secret,
|
|
@@ -110536,18 +111093,18 @@ import {
|
|
|
110536
111093
|
workspaceInsightsPhaseMetricObserver,
|
|
110537
111094
|
normalizeWorkspaceInsightsFilter,
|
|
110538
111095
|
normalizeWorkspaceInsightsSessionScope,
|
|
110539
|
-
requireAccessGrant as
|
|
111096
|
+
requireAccessGrant as requireAccessGrant47,
|
|
110540
111097
|
WorkspaceInsightsFilterValidationError
|
|
110541
111098
|
} from "@opengeni/core";
|
|
110542
111099
|
import { currentSessionRlsActorIdentityKey } from "@opengeni/db";
|
|
110543
111100
|
import { workspaceInsightsMetricObserver } from "@opengeni/observability";
|
|
110544
|
-
import { HTTPException as
|
|
111101
|
+
import { HTTPException as HTTPException104 } from "hono/http-exception";
|
|
110545
111102
|
function normalizeWorkspaceInsightsQueryFilter(value, field) {
|
|
110546
111103
|
try {
|
|
110547
111104
|
return field === "rootSessionId" || field === "sessionId" ? normalizeWorkspaceInsightsSessionScope(value, field) : normalizeWorkspaceInsightsFilter(value, field);
|
|
110548
111105
|
} catch (error) {
|
|
110549
111106
|
if (error instanceof WorkspaceInsightsFilterValidationError) {
|
|
110550
|
-
throw new
|
|
111107
|
+
throw new HTTPException104(400, { message: error.message });
|
|
110551
111108
|
}
|
|
110552
111109
|
throw error;
|
|
110553
111110
|
}
|
|
@@ -110599,11 +111156,11 @@ function registerInsightsRoutes(app, deps) {
|
|
|
110599
111156
|
await measureInsightsPhase(
|
|
110600
111157
|
observePhase,
|
|
110601
111158
|
"auth",
|
|
110602
|
-
() =>
|
|
111159
|
+
() => requireAccessGrant47(c, deps, workspaceId, "workspace:admin")
|
|
110603
111160
|
);
|
|
110604
111161
|
const rangeParsed = InsightsRange.safeParse(rangeRaw);
|
|
110605
111162
|
if (!rangeParsed.success) {
|
|
110606
|
-
throw new
|
|
111163
|
+
throw new HTTPException104(400, {
|
|
110607
111164
|
message: "range must be one of today|week|month|ytd"
|
|
110608
111165
|
});
|
|
110609
111166
|
}
|
|
@@ -110669,7 +111226,7 @@ import {
|
|
|
110669
111226
|
hasPermission as hasPermission28,
|
|
110670
111227
|
listInsightsCalls,
|
|
110671
111228
|
requireAccessContext as requireAccessContext11,
|
|
110672
|
-
requireAccessGrant as
|
|
111229
|
+
requireAccessGrant as requireAccessGrant48
|
|
110673
111230
|
} from "@opengeni/core";
|
|
110674
111231
|
import {
|
|
110675
111232
|
currentSessionRlsActorIdentityKey as currentSessionRlsActorIdentityKey2,
|
|
@@ -110677,11 +111234,11 @@ import {
|
|
|
110677
111234
|
readInsightsResponseCacheFence
|
|
110678
111235
|
} from "@opengeni/db";
|
|
110679
111236
|
import { createHash as createHash30 } from "crypto";
|
|
110680
|
-
import { HTTPException as
|
|
111237
|
+
import { HTTPException as HTTPException106 } from "hono/http-exception";
|
|
110681
111238
|
|
|
110682
111239
|
// src/routes/insights-response-cache.ts
|
|
110683
111240
|
import { createHmac as createHmac13, randomBytes as randomBytes13 } from "crypto";
|
|
110684
|
-
import { HTTPException as
|
|
111241
|
+
import { HTTPException as HTTPException105 } from "hono/http-exception";
|
|
110685
111242
|
var INSIGHTS_RESPONSE_TTL_MS = 6e4;
|
|
110686
111243
|
var MAX_ENTRIES = 128;
|
|
110687
111244
|
var MAX_BYTES = 8 * 1024 * 1024;
|
|
@@ -110736,7 +111293,7 @@ async function insightsWithFriendlyTimeout(read) {
|
|
|
110736
111293
|
for (let depth = 0; depth < 4 && current && typeof current === "object"; depth++) {
|
|
110737
111294
|
const candidate = current;
|
|
110738
111295
|
if (candidate.code === "57014" || typeof candidate.message === "string" && candidate.message.toLowerCase().includes("statement timeout")) {
|
|
110739
|
-
throw new
|
|
111296
|
+
throw new HTTPException105(408, {
|
|
110740
111297
|
message: "This range has too much data right now. Try a shorter range."
|
|
110741
111298
|
});
|
|
110742
111299
|
}
|
|
@@ -110837,7 +111394,7 @@ async function callsWithValidation(read) {
|
|
|
110837
111394
|
return await read();
|
|
110838
111395
|
} catch (error) {
|
|
110839
111396
|
if (error instanceof InvalidInsightsCallsCursorError)
|
|
110840
|
-
throw new
|
|
111397
|
+
throw new HTTPException106(400, { message: "invalid Insights calls cursor" });
|
|
110841
111398
|
throw error;
|
|
110842
111399
|
}
|
|
110843
111400
|
}
|
|
@@ -110873,12 +111430,12 @@ function registerInsightsUsageRoutes(app, deps) {
|
|
|
110873
111430
|
}
|
|
110874
111431
|
app.get("/v1/workspaces/:workspaceId/insights/usage", async (c) => {
|
|
110875
111432
|
const workspaceId = c.req.param("workspaceId");
|
|
110876
|
-
const grant = await
|
|
111433
|
+
const grant = await requireAccessGrant48(c, deps, workspaceId, "workspace:admin");
|
|
110877
111434
|
const query = insightsQueryParameters(c.req.queries());
|
|
110878
111435
|
if (!insightsRawQuerySupported(query, false, false))
|
|
110879
|
-
throw new
|
|
111436
|
+
throw new HTTPException106(400, { message: "unsupported interim Insights query" });
|
|
110880
111437
|
const parsed = WorkspaceInsightsUsageQuery.safeParse(query);
|
|
110881
|
-
if (!parsed.success) throw new
|
|
111438
|
+
if (!parsed.success) throw new HTTPException106(400, { message: "invalid Insights usage query" });
|
|
110882
111439
|
const scope = {
|
|
110883
111440
|
accountId: grant.accountId,
|
|
110884
111441
|
workspaceId,
|
|
@@ -110899,12 +111456,12 @@ function registerInsightsUsageRoutes(app, deps) {
|
|
|
110899
111456
|
});
|
|
110900
111457
|
app.get("/v1/workspaces/:workspaceId/insights/calls", async (c) => {
|
|
110901
111458
|
const workspaceId = c.req.param("workspaceId");
|
|
110902
|
-
const grant = await
|
|
111459
|
+
const grant = await requireAccessGrant48(c, deps, workspaceId, "workspace:admin");
|
|
110903
111460
|
const query = insightsQueryParameters(c.req.queries());
|
|
110904
111461
|
if (!insightsRawQuerySupported(query, false, true))
|
|
110905
|
-
throw new
|
|
111462
|
+
throw new HTTPException106(400, { message: "unsupported interim Insights query" });
|
|
110906
111463
|
const parsed = WorkspaceInsightsCallsQuery.safeParse(query);
|
|
110907
|
-
if (!parsed.success) throw new
|
|
111464
|
+
if (!parsed.success) throw new HTTPException106(400, { message: "invalid Insights calls query" });
|
|
110908
111465
|
const scope = {
|
|
110909
111466
|
accountId: grant.accountId,
|
|
110910
111467
|
workspaceId,
|
|
@@ -110932,9 +111489,9 @@ function registerInsightsUsageRoutes(app, deps) {
|
|
|
110932
111489
|
const accountId = requireSelectedAccount(context, c.req.param("accountId"), "billing:read");
|
|
110933
111490
|
const query = insightsQueryParameters(c.req.queries());
|
|
110934
111491
|
if (!insightsRawQuerySupported(query, true, false))
|
|
110935
|
-
throw new
|
|
111492
|
+
throw new HTTPException106(400, { message: "unsupported interim Insights query" });
|
|
110936
111493
|
const parsed = OrganizationInsightsUsageQuery.safeParse(query);
|
|
110937
|
-
if (!parsed.success) throw new
|
|
111494
|
+
if (!parsed.success) throw new HTTPException106(400, { message: "invalid Insights usage query" });
|
|
110938
111495
|
const scope = organizationInsightsScope(context, accountId);
|
|
110939
111496
|
const response = await withBillingUsageActor(
|
|
110940
111497
|
deps,
|
|
@@ -110959,9 +111516,9 @@ function registerInsightsUsageRoutes(app, deps) {
|
|
|
110959
111516
|
const accountId = requireSelectedAccount(context, c.req.param("accountId"), "billing:read");
|
|
110960
111517
|
const query = insightsQueryParameters(c.req.queries());
|
|
110961
111518
|
if (!insightsRawQuerySupported(query, true, true))
|
|
110962
|
-
throw new
|
|
111519
|
+
throw new HTTPException106(400, { message: "unsupported interim Insights query" });
|
|
110963
111520
|
const parsed = OrganizationInsightsCallsQuery.safeParse(query);
|
|
110964
|
-
if (!parsed.success) throw new
|
|
111521
|
+
if (!parsed.success) throw new HTTPException106(400, { message: "invalid Insights calls query" });
|
|
110965
111522
|
const scope = organizationInsightsScope(context, accountId);
|
|
110966
111523
|
const response = await withBillingUsageActor(
|
|
110967
111524
|
deps,
|
|
@@ -110992,7 +111549,7 @@ import {
|
|
|
110992
111549
|
resolveWorkspaceVoiceInputEnabled as resolveWorkspaceVoiceInputEnabled2,
|
|
110993
111550
|
WorkspaceVoiceInputSettings as WorkspaceVoiceInputSettings2
|
|
110994
111551
|
} from "@opengeni/contracts";
|
|
110995
|
-
import { requireAccessGrant as
|
|
111552
|
+
import { requireAccessGrant as requireAccessGrant50, TranscriptionServiceError as TranscriptionServiceError2 } from "@opengeni/core";
|
|
110996
111553
|
import { getWorkspace as getWorkspace10 } from "@opengeni/db";
|
|
110997
111554
|
|
|
110998
111555
|
// src/routes/transcription-recordings.ts
|
|
@@ -111008,7 +111565,7 @@ import {
|
|
|
111008
111565
|
import {
|
|
111009
111566
|
isAcceptedMimeType,
|
|
111010
111567
|
normalizeMimeType,
|
|
111011
|
-
requireAccessGrant as
|
|
111568
|
+
requireAccessGrant as requireAccessGrant49,
|
|
111012
111569
|
TRANSCRIPTION_PROVIDER_REQUEST_TIMEOUT_MILLISECONDS,
|
|
111013
111570
|
TranscriptionServiceError
|
|
111014
111571
|
} from "@opengeni/core";
|
|
@@ -111700,7 +112257,7 @@ async function requireRecordingAuthority(c, deps, requirePolicy) {
|
|
|
111700
112257
|
if (!workspaceId) {
|
|
111701
112258
|
throw new TranscriptionRecordingNotFoundError("Workspace not found");
|
|
111702
112259
|
}
|
|
111703
|
-
const grant = await
|
|
112260
|
+
const grant = await requireAccessGrant49(c, deps, workspaceId, "sessions:create");
|
|
111704
112261
|
const workspace = await getWorkspace9(deps.db, workspaceId);
|
|
111705
112262
|
if (requirePolicy) {
|
|
111706
112263
|
if (!workspace) throw new TranscriptionRecordingNotFoundError("Workspace not found");
|
|
@@ -111913,7 +112470,7 @@ function registerTranscriptionRoutes(app, deps) {
|
|
|
111913
112470
|
registerResumableTranscriptionRoutes(app, deps);
|
|
111914
112471
|
app.post("/v1/workspaces/:workspaceId/transcriptions", async (c) => {
|
|
111915
112472
|
const workspaceId = c.req.param("workspaceId");
|
|
111916
|
-
const grant = await
|
|
112473
|
+
const grant = await requireAccessGrant50(c, deps, workspaceId, "sessions:create");
|
|
111917
112474
|
const workspace = await getWorkspace10(deps.db, workspaceId);
|
|
111918
112475
|
if (!workspace) return c.json({ code: "not_found" }, 404);
|
|
111919
112476
|
if (resolveWorkspaceVoiceInputEnabled2(workspace.settings) === false) {
|
|
@@ -112052,7 +112609,7 @@ function isAbort3(error) {
|
|
|
112052
112609
|
|
|
112053
112610
|
// src/routes/session-artifact-associations.ts
|
|
112054
112611
|
import {
|
|
112055
|
-
requireAccessGrant as
|
|
112612
|
+
requireAccessGrant as requireAccessGrant51,
|
|
112056
112613
|
requirePermission as requirePermission12,
|
|
112057
112614
|
requireSessionAuthorization as requireSessionAuthorization15,
|
|
112058
112615
|
SessionAuthorizationDeniedError as SessionAuthorizationDeniedError15,
|
|
@@ -112064,23 +112621,23 @@ import {
|
|
|
112064
112621
|
transactionallyAuthorizeEditableArtifactActor,
|
|
112065
112622
|
withRlsContext as withRlsContext3
|
|
112066
112623
|
} from "@opengeni/db";
|
|
112067
|
-
import { HTTPException as
|
|
112068
|
-
import { z as
|
|
112069
|
-
var SessionId2 =
|
|
112070
|
-
var EditableArtifactId =
|
|
112624
|
+
import { HTTPException as HTTPException107 } from "hono/http-exception";
|
|
112625
|
+
import { z as z55 } from "zod";
|
|
112626
|
+
var SessionId2 = z55.string().uuid();
|
|
112627
|
+
var EditableArtifactId = z55.string().regex(/^(?!0{32}$)[0-9a-f]{32}$/u);
|
|
112071
112628
|
function registerSessionArtifactAssociationRoutes(app, deps) {
|
|
112072
112629
|
app.get(
|
|
112073
112630
|
"/v1/workspaces/:workspaceId/sessions/:sessionId/artifact-associations/:artifactId",
|
|
112074
112631
|
async (context) => {
|
|
112075
112632
|
const workspaceId = context.req.param("workspaceId");
|
|
112076
|
-
const grant = await
|
|
112633
|
+
const grant = await requireAccessGrant51(context, deps, workspaceId, "artifacts:read");
|
|
112077
112634
|
requirePermission12(grant, "sessions:read");
|
|
112078
112635
|
const sessionId = context.req.param("sessionId");
|
|
112079
112636
|
const artifactId2 = context.req.param("artifactId");
|
|
112080
112637
|
const kind = EditableArtifactId.safeParse(artifactId2).success ? "editable" : SessionId2.safeParse(artifactId2).success ? "site" : null;
|
|
112081
112638
|
const requestedKind = context.req.query("kind");
|
|
112082
112639
|
if (!SessionId2.safeParse(sessionId).success || !kind || requestedKind !== void 0 && requestedKind !== kind) {
|
|
112083
|
-
throw new
|
|
112640
|
+
throw new HTTPException107(404, { message: "Artifact association not found" });
|
|
112084
112641
|
}
|
|
112085
112642
|
try {
|
|
112086
112643
|
return await withAccessGrantSessionRlsContext(deps, grant, async () => {
|
|
@@ -112091,7 +112648,7 @@ function registerSessionArtifactAssociationRoutes(app, deps) {
|
|
|
112091
112648
|
});
|
|
112092
112649
|
const scope = { accountId: grant.accountId, workspaceId };
|
|
112093
112650
|
const linked = kind === "editable" ? await hasEditableArtifactSessionLink2(deps.db, scope, sessionId, artifactId2) : await hasWorkspaceArtifactSessionLink(deps.db, workspaceId, sessionId, artifactId2);
|
|
112094
|
-
if (!linked) throw new
|
|
112651
|
+
if (!linked) throw new HTTPException107(404, { message: "Artifact association not found" });
|
|
112095
112652
|
if (kind === "editable") {
|
|
112096
112653
|
const decision = await withRlsContext3(
|
|
112097
112654
|
deps.db,
|
|
@@ -112104,7 +112661,7 @@ function registerSessionArtifactAssociationRoutes(app, deps) {
|
|
|
112104
112661
|
})
|
|
112105
112662
|
);
|
|
112106
112663
|
if (!decision.allowed) {
|
|
112107
|
-
throw new
|
|
112664
|
+
throw new HTTPException107(404, { message: "Artifact association not found" });
|
|
112108
112665
|
}
|
|
112109
112666
|
}
|
|
112110
112667
|
context.header("cache-control", "private, no-store");
|
|
@@ -112112,10 +112669,10 @@ function registerSessionArtifactAssociationRoutes(app, deps) {
|
|
|
112112
112669
|
});
|
|
112113
112670
|
} catch (error) {
|
|
112114
112671
|
if (error instanceof SessionAuthorizationDeniedError15) {
|
|
112115
|
-
throw new
|
|
112672
|
+
throw new HTTPException107(404, { message: "Artifact association not found" });
|
|
112116
112673
|
}
|
|
112117
112674
|
if (error instanceof SessionAuthorizationUnavailableError13) {
|
|
112118
|
-
throw new
|
|
112675
|
+
throw new HTTPException107(503, { message: "Session authorization is unavailable" });
|
|
112119
112676
|
}
|
|
112120
112677
|
throw error;
|
|
112121
112678
|
}
|
|
@@ -112140,7 +112697,7 @@ import {
|
|
|
112140
112697
|
workspaceXaiSubscriptionActive as workspaceXaiSubscriptionActive2
|
|
112141
112698
|
} from "@opengeni/db";
|
|
112142
112699
|
import {
|
|
112143
|
-
requireAccessGrant as
|
|
112700
|
+
requireAccessGrant as requireAccessGrant52,
|
|
112144
112701
|
requireAccessGrantAuthorization as requireAccessGrantAuthorization37,
|
|
112145
112702
|
fileOwnerContextForAccess as fileOwnerContextForAccess6,
|
|
112146
112703
|
requireWorkspaceSettingsGrant as requireWorkspaceSettingsGrant6,
|
|
@@ -112148,11 +112705,11 @@ import {
|
|
|
112148
112705
|
videoGenerationModelSupportsFundingSource,
|
|
112149
112706
|
videoGenerationCapabilitiesForPolicy
|
|
112150
112707
|
} from "@opengeni/core";
|
|
112151
|
-
import { HTTPException as
|
|
112708
|
+
import { HTTPException as HTTPException108 } from "hono/http-exception";
|
|
112152
112709
|
function registerVideoGenerationRoutes(app, deps) {
|
|
112153
112710
|
app.get("/v1/workspaces/:workspaceId/video-generation", async (c) => {
|
|
112154
112711
|
const workspaceId = c.req.param("workspaceId");
|
|
112155
|
-
const grant = await
|
|
112712
|
+
const grant = await requireAccessGrant52(c, deps, workspaceId, "workspace:read");
|
|
112156
112713
|
const [policy, connection, supergrokConfigured] = await Promise.all([
|
|
112157
112714
|
getWorkspaceVideoGenerationPolicy(deps.db, workspaceId),
|
|
112158
112715
|
getWorkspaceVercelAiGatewayConnectionMetadata(deps.db, workspaceId),
|
|
@@ -112195,14 +112752,14 @@ function registerVideoGenerationRoutes(app, deps) {
|
|
|
112195
112752
|
(option) => option.source === payload.fundingSource
|
|
112196
112753
|
);
|
|
112197
112754
|
if (payload.enabledModelIds.length > 0 && !selectedFunding?.available) {
|
|
112198
|
-
throw new
|
|
112755
|
+
throw new HTTPException108(422, {
|
|
112199
112756
|
message: selectedFunding?.unavailableReason ?? "Video generation funding is unavailable"
|
|
112200
112757
|
});
|
|
112201
112758
|
}
|
|
112202
112759
|
if (payload.enabledModelIds.some(
|
|
112203
112760
|
(modelId) => !videoGenerationModelSupportsFundingSource(modelId, payload.fundingSource)
|
|
112204
112761
|
)) {
|
|
112205
|
-
throw new
|
|
112762
|
+
throw new HTTPException108(422, {
|
|
112206
112763
|
message: "The selected video model is unavailable for this funding source"
|
|
112207
112764
|
});
|
|
112208
112765
|
}
|
|
@@ -112216,10 +112773,10 @@ function registerVideoGenerationRoutes(app, deps) {
|
|
|
112216
112773
|
return c.json(VideoGenerationPolicy.parse(policy));
|
|
112217
112774
|
} catch (error) {
|
|
112218
112775
|
if (error instanceof VideoGenerationConflictError) {
|
|
112219
|
-
throw new
|
|
112776
|
+
throw new HTTPException108(409, { message: error.message });
|
|
112220
112777
|
}
|
|
112221
112778
|
if (error instanceof Error && error.message.startsWith("Unknown video generation model:")) {
|
|
112222
|
-
throw new
|
|
112779
|
+
throw new HTTPException108(422, { message: error.message });
|
|
112223
112780
|
}
|
|
112224
112781
|
throw error;
|
|
112225
112782
|
}
|
|
@@ -112233,7 +112790,7 @@ function registerVideoGenerationRoutes(app, deps) {
|
|
|
112233
112790
|
() => getVideoGenerationOperationSummary(deps.db, workspaceId, c.req.param("operationId"))
|
|
112234
112791
|
);
|
|
112235
112792
|
if (!summary)
|
|
112236
|
-
throw new
|
|
112793
|
+
throw new HTTPException108(404, {
|
|
112237
112794
|
message: "video generation operation not found"
|
|
112238
112795
|
});
|
|
112239
112796
|
return c.json(VideoGenerationOperationSummary.parse(summary));
|
|
@@ -112290,8 +112847,8 @@ import {
|
|
|
112290
112847
|
CanonicalHumanIdentityMutationInFlightError,
|
|
112291
112848
|
getCanonicalHumanIdentityProjection as getCanonicalHumanIdentityProjection3
|
|
112292
112849
|
} from "@opengeni/db/canonical-human-identities";
|
|
112293
|
-
import { HTTPException as
|
|
112294
|
-
import { z as
|
|
112850
|
+
import { HTTPException as HTTPException111 } from "hono/http-exception";
|
|
112851
|
+
import { z as z58 } from "zod";
|
|
112295
112852
|
|
|
112296
112853
|
// src/routes/managed-sign-in-methods.ts
|
|
112297
112854
|
import {
|
|
@@ -112314,11 +112871,15 @@ import {
|
|
|
112314
112871
|
import { getManagedAuthSessionSetSnapshot as getManagedAuthSessionSetSnapshot2 } from "@opengeni/db/managed-auth-session-sets";
|
|
112315
112872
|
import { getCanonicalHumanIdentityProjection as getCanonicalHumanIdentityProjection2 } from "@opengeni/db/canonical-human-identities";
|
|
112316
112873
|
import { getCookie as getCookie2 } from "hono/cookie";
|
|
112317
|
-
import { HTTPException as
|
|
112318
|
-
import { z as
|
|
112874
|
+
import { HTTPException as HTTPException110 } from "hono/http-exception";
|
|
112875
|
+
import { z as z57 } from "zod";
|
|
112319
112876
|
|
|
112320
112877
|
// src/routes/managed-auth-session-sets.ts
|
|
112321
|
-
import {
|
|
112878
|
+
import {
|
|
112879
|
+
assertManagedUserAdmission as assertManagedUserAdmission2,
|
|
112880
|
+
getManagedSession as getManagedSession3,
|
|
112881
|
+
withManagedAuthSessionLookup as withManagedAuthSessionLookup2
|
|
112882
|
+
} from "@opengeni/core";
|
|
112322
112883
|
import { randomUUID as randomUUID16 } from "crypto";
|
|
112323
112884
|
import {
|
|
112324
112885
|
BeginManagedAuthLoginTransactionRequest,
|
|
@@ -112380,13 +112941,13 @@ import {
|
|
|
112380
112941
|
} from "@opengeni/db/managed-auth-session-sets";
|
|
112381
112942
|
import { ensureManagedAccessForUser as ensureManagedAccessForUser2, getSession as getSession10 } from "@opengeni/db";
|
|
112382
112943
|
import { deleteCookie as deleteCookie3, getCookie, setCookie as setCookie3 } from "hono/cookie";
|
|
112383
|
-
import { HTTPException as
|
|
112384
|
-
import { z as
|
|
112385
|
-
var ManagedAuthSocialStartReceipt =
|
|
112386
|
-
version:
|
|
112387
|
-
requestDigest:
|
|
112388
|
-
url:
|
|
112389
|
-
stateCookie:
|
|
112944
|
+
import { HTTPException as HTTPException109 } from "hono/http-exception";
|
|
112945
|
+
import { z as z56 } from "zod";
|
|
112946
|
+
var ManagedAuthSocialStartReceipt = z56.object({
|
|
112947
|
+
version: z56.literal(1),
|
|
112948
|
+
requestDigest: z56.string().regex(/^[0-9a-f]{64}$/u),
|
|
112949
|
+
url: z56.string().url().max(4096),
|
|
112950
|
+
stateCookie: z56.string().min(1).max(4096)
|
|
112390
112951
|
}).strict();
|
|
112391
112952
|
function registerManagedAuthSessionSetRoutes(app, deps) {
|
|
112392
112953
|
const noStore = async (context, next) => {
|
|
@@ -112407,7 +112968,7 @@ function registerManagedAuthSessionSetRoutes(app, deps) {
|
|
|
112407
112968
|
app.use("/v1/auth/session-set/*", noStore);
|
|
112408
112969
|
app.get("/v1/auth/get-session", async (context) => {
|
|
112409
112970
|
if (deps.settings.managedAuthSessionSetMode === "legacy") {
|
|
112410
|
-
if (!deps.managedAuth) throw new
|
|
112971
|
+
if (!deps.managedAuth) throw new HTTPException109(404);
|
|
112411
112972
|
if (deps.settings.allowedUserEmails !== void 0) {
|
|
112412
112973
|
const session = await getManagedSession3(context, deps.managedAuth, { db: deps.db });
|
|
112413
112974
|
context.header("cache-control", "no-store");
|
|
@@ -112491,10 +113052,12 @@ function registerManagedAuthSessionSetRoutes(app, deps) {
|
|
|
112491
113052
|
app.post("/v1/auth/session-set/bootstrap", async (context) => {
|
|
112492
113053
|
const body3 = await bodyAs(context, BootstrapManagedAuthSessionSetRequest);
|
|
112493
113054
|
const { authority, actorEpoch } = await requireMutation(context, deps, body3.expectedGeneration);
|
|
112494
|
-
const ambient = await
|
|
112495
|
-
|
|
112496
|
-
|
|
112497
|
-
|
|
113055
|
+
const ambient = await withManagedAuthSessionLookup2(
|
|
113056
|
+
() => requireAvailable(deps).managedAuth.api.getSession({
|
|
113057
|
+
headers: context.req.raw.headers,
|
|
113058
|
+
returnHeaders: true
|
|
113059
|
+
})
|
|
113060
|
+
);
|
|
112498
113061
|
assertManagedUserAdmission2(deps.managedAuth, ambient.response?.user);
|
|
112499
113062
|
const authSessionId = ambient.response?.session?.id;
|
|
112500
113063
|
if (typeof authSessionId !== "string") {
|
|
@@ -113253,7 +113816,7 @@ function appendCookies(context, cookies) {
|
|
|
113253
113816
|
for (const cookie of cookies) context.header("set-cookie", cookie, { append: true });
|
|
113254
113817
|
}
|
|
113255
113818
|
function throwHttp(error, context) {
|
|
113256
|
-
if (error instanceof
|
|
113819
|
+
if (error instanceof HTTPException109) throw error;
|
|
113257
113820
|
if (error instanceof ManagedAuthSessionSetGenerationConflictError) {
|
|
113258
113821
|
throw managedAuthApiError(409, "generation_conflict", { cause: error, retryable: true });
|
|
113259
113822
|
}
|
|
@@ -113322,23 +113885,23 @@ function setCookieHeaders(headers) {
|
|
|
113322
113885
|
}
|
|
113323
113886
|
|
|
113324
113887
|
// src/routes/managed-sign-in-methods.ts
|
|
113325
|
-
var ConnectState =
|
|
113326
|
-
opengeniSignInMethod:
|
|
113327
|
-
intentId:
|
|
113328
|
-
provider:
|
|
113888
|
+
var ConnectState = z57.object({
|
|
113889
|
+
opengeniSignInMethod: z57.object({
|
|
113890
|
+
intentId: z57.string().uuid(),
|
|
113891
|
+
provider: z57.enum(["google", "github"])
|
|
113329
113892
|
}),
|
|
113330
|
-
link:
|
|
113331
|
-
callbackURL:
|
|
113332
|
-
errorURL:
|
|
113893
|
+
link: z57.object({ userId: z57.string().min(1), email: z57.string().email() }),
|
|
113894
|
+
callbackURL: z57.string().url(),
|
|
113895
|
+
errorURL: z57.string().url()
|
|
113333
113896
|
});
|
|
113334
|
-
var ConnectIntent =
|
|
113335
|
-
authUserId:
|
|
113336
|
-
authSessionId:
|
|
113337
|
-
expectedIdentityId:
|
|
113338
|
-
actorFence:
|
|
113339
|
-
authorityHash:
|
|
113340
|
-
actorEpoch:
|
|
113341
|
-
requestId:
|
|
113897
|
+
var ConnectIntent = z57.object({
|
|
113898
|
+
authUserId: z57.string().min(1),
|
|
113899
|
+
authSessionId: z57.string().min(1),
|
|
113900
|
+
expectedIdentityId: z57.string().uuid(),
|
|
113901
|
+
actorFence: z57.object({
|
|
113902
|
+
authorityHash: z57.string().regex(/^[0-9a-f]{64}$/),
|
|
113903
|
+
actorEpoch: z57.string().regex(/^[1-9][0-9]*$/),
|
|
113904
|
+
requestId: z57.string().uuid()
|
|
113342
113905
|
}).optional()
|
|
113343
113906
|
});
|
|
113344
113907
|
async function rows(deps, query) {
|
|
@@ -113356,7 +113919,7 @@ async function identity(context, deps) {
|
|
|
113356
113919
|
async function admitManagedSignInMutation(context, deps) {
|
|
113357
113920
|
const origin = deps.settings.publicBaseUrl ? new URL(deps.settings.publicBaseUrl).origin : null;
|
|
113358
113921
|
if (!origin || context.req.header("origin") !== origin || context.req.header("sec-fetch-site") !== "same-origin" || context.req.header("content-type")?.split(";", 1)[0] !== "application/json") {
|
|
113359
|
-
throw new
|
|
113922
|
+
throw new HTTPException110(403, { message: "Same-origin browser mutation required" });
|
|
113360
113923
|
}
|
|
113361
113924
|
const authority = getCookie2(context, MANAGED_AUTH_SESSION_SET_COOKIE2);
|
|
113362
113925
|
if (deps.settings.managedAuthSessionSetMode !== "legacy" && authority) {
|
|
@@ -113365,7 +113928,7 @@ async function admitManagedSignInMutation(context, deps) {
|
|
|
113365
113928
|
mode: deps.settings.managedAuthSessionSetMode,
|
|
113366
113929
|
readOnly: true
|
|
113367
113930
|
});
|
|
113368
|
-
if (!snapshot) throw new
|
|
113931
|
+
if (!snapshot) throw new HTTPException110(401);
|
|
113369
113932
|
try {
|
|
113370
113933
|
requireManagedAuthMutationAdmission2({
|
|
113371
113934
|
request: context.req.raw,
|
|
@@ -113375,7 +113938,7 @@ async function admitManagedSignInMutation(context, deps) {
|
|
|
113375
113938
|
expectedGeneration: snapshot.projection.generation
|
|
113376
113939
|
});
|
|
113377
113940
|
} catch {
|
|
113378
|
-
throw new
|
|
113941
|
+
throw new HTTPException110(403, { message: "Browser session-set CSRF validation failed" });
|
|
113379
113942
|
}
|
|
113380
113943
|
}
|
|
113381
113944
|
}
|
|
@@ -113413,7 +113976,7 @@ function registerManagedSignInMethodRoutes(app, deps) {
|
|
|
113413
113976
|
select u.email, u.email_verified as "emailVerified", s.created_at > clock_timestamp()-interval '5 minutes' as fresh
|
|
113414
113977
|
from auth_users u join auth_sessions s on s.user_id=u.id where u.id=${actor.authUserId} and s.id=${actor.authSessionId}`
|
|
113415
113978
|
);
|
|
113416
|
-
if (!user) throw new
|
|
113979
|
+
if (!user) throw new HTTPException110(401);
|
|
113417
113980
|
const accounts = await rows(
|
|
113418
113981
|
deps,
|
|
113419
113982
|
sql`
|
|
@@ -113447,11 +114010,11 @@ function registerManagedSignInMethodRoutes(app, deps) {
|
|
|
113447
114010
|
const actor = await identity(context, deps);
|
|
113448
114011
|
const actorFence = getManagedAuthRequestActorLeaseStamp(context.req.raw);
|
|
113449
114012
|
if (deps.settings.managedAuthSessionSetMode !== "legacy" && !actorFence)
|
|
113450
|
-
throw new
|
|
114013
|
+
throw new HTTPException110(409, { message: "Managed actor fence required" });
|
|
113451
114014
|
const schema = kind === "password" ? ManagedSignInPasswordMutation : ManagedSignInProviderMutation;
|
|
113452
114015
|
const parsed = schema.safeParse(await context.req.json().catch(() => null));
|
|
113453
114016
|
if (!parsed.success)
|
|
113454
|
-
throw new
|
|
114017
|
+
throw new HTTPException110(422, { message: "Invalid sign-in method request" });
|
|
113455
114018
|
const body3 = parsed.data;
|
|
113456
114019
|
const currentIdentity = await getCanonicalHumanIdentityProjection2(deps.db, actor.authUserId);
|
|
113457
114020
|
if (currentIdentity.activeIdentity.id !== body3.expectedIdentityId)
|
|
@@ -113466,7 +114029,7 @@ function registerManagedSignInMethodRoutes(app, deps) {
|
|
|
113466
114029
|
deps,
|
|
113467
114030
|
sql`select u.email,s.token from auth_users u join auth_sessions s on s.user_id=u.id where u.id=${actor.authUserId} and s.id=${actor.authSessionId}`
|
|
113468
114031
|
);
|
|
113469
|
-
if (!user) throw new
|
|
114032
|
+
if (!user) throw new HTTPException110(401);
|
|
113470
114033
|
const request = {
|
|
113471
114034
|
kind,
|
|
113472
114035
|
operationId: body3.operationId,
|
|
@@ -113519,7 +114082,7 @@ function registerManagedSignInMethodRoutes(app, deps) {
|
|
|
113519
114082
|
if ("provider" in body3) {
|
|
113520
114083
|
request.provider = body3.provider;
|
|
113521
114084
|
if (kind === "connect" && !configured(deps, body3.provider))
|
|
113522
|
-
throw new
|
|
114085
|
+
throw new HTTPException110(409, { message: "Sign-in provider is not configured" });
|
|
113523
114086
|
} else {
|
|
113524
114087
|
const [credential] = await rows(
|
|
113525
114088
|
deps,
|
|
@@ -113600,18 +114163,18 @@ async function handleManagedSignInConnectCallback(context, deps, provider) {
|
|
|
113600
114163
|
return null;
|
|
113601
114164
|
const parsed = ConnectState.safeParse(rawState);
|
|
113602
114165
|
if (!parsed.success)
|
|
113603
|
-
throw new
|
|
114166
|
+
throw new HTTPException110(403, { message: "Invalid sign-in method OAuth proof" });
|
|
113604
114167
|
const value = parsed.data, proof = value.opengeniSignInMethod;
|
|
113605
114168
|
if (proof.provider !== provider || value.callbackURL !== new URL(
|
|
113606
114169
|
"/settings/security?signInMethod=connected",
|
|
113607
114170
|
deps.settings.publicBaseUrl
|
|
113608
114171
|
).toString() || value.errorURL !== new URL("/settings/security?signInMethod=error", deps.settings.publicBaseUrl).toString())
|
|
113609
|
-
throw new
|
|
114172
|
+
throw new HTTPException110(403);
|
|
113610
114173
|
const [intent] = await rows(
|
|
113611
114174
|
deps,
|
|
113612
114175
|
sql`select value from auth_verifications where identifier=${`managed-sign-in:${proof.intentId}`} and expires_at>clock_timestamp()`
|
|
113613
114176
|
);
|
|
113614
|
-
if (!intent) throw new
|
|
114177
|
+
if (!intent) throw new HTTPException110(403, { message: "Sign-in method connection expired" });
|
|
113615
114178
|
const request = ConnectIntent.parse(JSON.parse(intent.value));
|
|
113616
114179
|
const authority = getCookie2(context, MANAGED_AUTH_SESSION_SET_COOKIE2);
|
|
113617
114180
|
if (!request.actorFence) {
|
|
@@ -113628,9 +114191,9 @@ async function handleManagedSignInConnectCallback(context, deps, provider) {
|
|
|
113628
114191
|
}
|
|
113629
114192
|
}
|
|
113630
114193
|
if (request.actorFence && (!authority || managedAuthSha2562(authority) !== request.actorFence.authorityHash))
|
|
113631
|
-
throw new
|
|
114194
|
+
throw new HTTPException110(403);
|
|
113632
114195
|
if (value.link?.userId !== request.authUserId || value.link?.email === void 0)
|
|
113633
|
-
throw new
|
|
114196
|
+
throw new HTTPException110(403);
|
|
113634
114197
|
const isolated = await isolatedManagedAuthOAuthCallbackRequest(deps.managedAuth, context.req.raw);
|
|
113635
114198
|
const response = await runManagedSignInConnect(
|
|
113636
114199
|
proof.intentId,
|
|
@@ -113658,7 +114221,7 @@ async function handleManagedSignInConnectCallback(context, deps, provider) {
|
|
|
113658
114221
|
|
|
113659
114222
|
// src/routes/canonical-human-identities.ts
|
|
113660
114223
|
import { managedAuthSecretRequestDigest as managedAuthSecretRequestDigest3 } from "@opengeni/core/managed-auth-session-sets";
|
|
113661
|
-
var BindingId =
|
|
114224
|
+
var BindingId = z58.string().uuid();
|
|
113662
114225
|
async function requestIdentity(context, deps) {
|
|
113663
114226
|
return await requireCanonicalHumanRequestIdentity2(context, {
|
|
113664
114227
|
db: deps.db,
|
|
@@ -113671,13 +114234,13 @@ async function requestIdentity(context, deps) {
|
|
|
113671
114234
|
async function parseBody5(context, schema) {
|
|
113672
114235
|
const parsed = schema.safeParse(await context.req.json().catch(() => null));
|
|
113673
114236
|
if (!parsed.success) {
|
|
113674
|
-
throw new
|
|
114237
|
+
throw new HTTPException111(422, { message: "Invalid canonical human identity request" });
|
|
113675
114238
|
}
|
|
113676
114239
|
return parsed.data;
|
|
113677
114240
|
}
|
|
113678
114241
|
function bindingId(context) {
|
|
113679
114242
|
const parsed = BindingId.safeParse(context.req.param("bindingId"));
|
|
113680
|
-
if (!parsed.success) throw new
|
|
114243
|
+
if (!parsed.success) throw new HTTPException111(422, { message: "Invalid login binding id" });
|
|
113681
114244
|
return parsed.data;
|
|
113682
114245
|
}
|
|
113683
114246
|
function identityError(context, error) {
|
|
@@ -113708,7 +114271,7 @@ async function mutate(context, deps, input) {
|
|
|
113708
114271
|
const identity2 = await requestIdentity(context, deps);
|
|
113709
114272
|
const actorFence = getManagedAuthRequestActorLeaseStamp2(context.req.raw);
|
|
113710
114273
|
if (deps.settings.managedAuthSessionSetMode !== "legacy" && !actorFence) {
|
|
113711
|
-
throw new
|
|
114274
|
+
throw new HTTPException111(409, { message: "Managed actor mutation fence is unavailable" });
|
|
113712
114275
|
}
|
|
113713
114276
|
try {
|
|
113714
114277
|
const response = CanonicalHumanIdentityMutationResponse.parse(
|
|
@@ -113762,7 +114325,7 @@ function registerCanonicalHumanIdentityRoutes(app, deps) {
|
|
|
113762
114325
|
app.post(`${base}/login-bindings`, async (context) => {
|
|
113763
114326
|
const request = await parseBody5(context, LinkCanonicalHumanLoginBindingRequest);
|
|
113764
114327
|
if (["google", "github", "credential"].includes(request.providerId.trim().toLowerCase())) {
|
|
113765
|
-
throw new
|
|
114328
|
+
throw new HTTPException111(403, {
|
|
113766
114329
|
message: "Use personal sign-in method settings with fresh provider proof"
|
|
113767
114330
|
});
|
|
113768
114331
|
}
|
|
@@ -113779,7 +114342,7 @@ function registerCanonicalHumanIdentityRoutes(app, deps) {
|
|
|
113779
114342
|
if (projection.loginBindings.some(
|
|
113780
114343
|
(binding) => binding.id === bindingId(context) && ["google", "github", "credential"].includes(binding.providerId)
|
|
113781
114344
|
)) {
|
|
113782
|
-
throw new
|
|
114345
|
+
throw new HTTPException111(403, {
|
|
113783
114346
|
message: "Use personal sign-in method settings with last-method protection"
|
|
113784
114347
|
});
|
|
113785
114348
|
}
|
|
@@ -113797,7 +114360,7 @@ function registerCanonicalHumanIdentityRoutes(app, deps) {
|
|
|
113797
114360
|
if (projection.loginBindings.some(
|
|
113798
114361
|
(binding) => binding.id === bindingId(context) && ["google", "github", "credential"].includes(binding.providerId)
|
|
113799
114362
|
)) {
|
|
113800
|
-
throw new
|
|
114363
|
+
throw new HTTPException111(403, {
|
|
113801
114364
|
message: "Managed-provider recovery cannot be initiated through raw binding management"
|
|
113802
114365
|
});
|
|
113803
114366
|
}
|
|
@@ -113895,7 +114458,7 @@ import {
|
|
|
113895
114458
|
listOrganizationAdministrationMembers,
|
|
113896
114459
|
listOrganizationInvitations,
|
|
113897
114460
|
listSelfOrganizationInvitations,
|
|
113898
|
-
nestedPostgresSqlState as
|
|
114461
|
+
nestedPostgresSqlState as nestedPostgresSqlState16,
|
|
113899
114462
|
prepareOrganizationUserSetupDelivery,
|
|
113900
114463
|
revokeOrganizationInvitation,
|
|
113901
114464
|
settleOrganizationUserSetupDelivery,
|
|
@@ -113908,12 +114471,12 @@ import {
|
|
|
113908
114471
|
updateOrganizationPrivateSessionSettings,
|
|
113909
114472
|
updateOrganizationRetentionPolicy
|
|
113910
114473
|
} from "@opengeni/db";
|
|
113911
|
-
import { HTTPException as
|
|
113912
|
-
import { z as
|
|
113913
|
-
var OrganizationId2 =
|
|
113914
|
-
var WorkspaceId =
|
|
113915
|
-
var MembershipId =
|
|
113916
|
-
var InvitationId =
|
|
114474
|
+
import { HTTPException as HTTPException112 } from "hono/http-exception";
|
|
114475
|
+
import { z as z59 } from "zod";
|
|
114476
|
+
var OrganizationId2 = z59.string().uuid();
|
|
114477
|
+
var WorkspaceId = z59.string().uuid();
|
|
114478
|
+
var MembershipId = z59.string().uuid();
|
|
114479
|
+
var InvitationId = z59.string().uuid();
|
|
113917
114480
|
async function requirePrivateSessionAdministrator(context, deps, organizationId2) {
|
|
113918
114481
|
const agent = agentActingAsPerson(
|
|
113919
114482
|
context,
|
|
@@ -113925,14 +114488,14 @@ async function requirePrivateSessionAdministrator(context, deps, organizationId2
|
|
|
113925
114488
|
const access = await requireAccessContext12(context, deps);
|
|
113926
114489
|
const key = accountScopedApiKeyWorkspaceAuthority8(access);
|
|
113927
114490
|
if (!key || key.accountId !== organizationId2 || !key.permissions.includes("workspace:admin")) {
|
|
113928
|
-
throw new
|
|
114491
|
+
throw new HTTPException112(403, {
|
|
113929
114492
|
message: "organization administration required"
|
|
113930
114493
|
});
|
|
113931
114494
|
}
|
|
113932
114495
|
if (key.permissionMode === "explicit" && !access.accountGrants.some(
|
|
113933
114496
|
(grant) => grant.accountId === organizationId2 && grant.permissions.includes("account:admin")
|
|
113934
114497
|
)) {
|
|
113935
|
-
throw new
|
|
114498
|
+
throw new HTTPException112(403, { message: "organization administration requires account:admin" });
|
|
113936
114499
|
}
|
|
113937
114500
|
return { subjectId: access.subjectId };
|
|
113938
114501
|
}
|
|
@@ -113940,25 +114503,25 @@ async function requireOrganizationKeyWorkspaceDeletion(context, deps, organizati
|
|
|
113940
114503
|
const access = await requireAccessContext12(context, deps);
|
|
113941
114504
|
const key = accountScopedApiKeyWorkspaceAuthority8(access);
|
|
113942
114505
|
if (!key || key.accountId !== organizationId2 || !hasPermission30(key.permissions, "workspace:admin")) {
|
|
113943
|
-
throw new
|
|
114506
|
+
throw new HTTPException112(403, {
|
|
113944
114507
|
message: "deleting an organization workspace requires an organization owner session or an organization API key with workspace:admin"
|
|
113945
114508
|
});
|
|
113946
114509
|
}
|
|
113947
114510
|
const workspace = await requireWorkspace4(deps.db, workspaceId).catch(() => null);
|
|
113948
114511
|
if (!workspace || workspace.accountId !== organizationId2) {
|
|
113949
|
-
throw new
|
|
114512
|
+
throw new HTTPException112(404, { message: "workspace not found" });
|
|
113950
114513
|
}
|
|
113951
114514
|
if (workspace.kind !== "shared") {
|
|
113952
|
-
throw new
|
|
114515
|
+
throw new HTTPException112(403, {
|
|
113953
114516
|
message: "organization API keys cannot delete a Personal workspace"
|
|
113954
114517
|
});
|
|
113955
114518
|
}
|
|
113956
114519
|
if (!organizationWorkspaceInScope3(key.workspaceScope, workspaceId))
|
|
113957
|
-
throw new
|
|
114520
|
+
throw new HTTPException112(403, { message: "workspace is outside organization key scope" });
|
|
113958
114521
|
}
|
|
113959
114522
|
async function requireManagedHuman(context, deps) {
|
|
113960
114523
|
if (deps.settings.productAccessMode !== "managed" || !deps.managedAuth || !context.req.header("cookie") || context.req.header("authorization")) {
|
|
113961
|
-
throw new
|
|
114524
|
+
throw new HTTPException112(401, { message: "managed human session required" });
|
|
113962
114525
|
}
|
|
113963
114526
|
const session = await getManagedSession4(context, deps.managedAuth, {
|
|
113964
114527
|
db: deps.db,
|
|
@@ -113966,7 +114529,7 @@ async function requireManagedHuman(context, deps) {
|
|
|
113966
114529
|
sessionSetMode: deps.settings.managedAuthSessionSetMode
|
|
113967
114530
|
});
|
|
113968
114531
|
if (!session?.user) {
|
|
113969
|
-
throw new
|
|
114532
|
+
throw new HTTPException112(401, { message: "managed human session required" });
|
|
113970
114533
|
}
|
|
113971
114534
|
return { session, subjectId: `user:${session.user.id}` };
|
|
113972
114535
|
}
|
|
@@ -113993,14 +114556,14 @@ async function requireOrganizationAdministrator(context, deps, organizationId2)
|
|
|
113993
114556
|
);
|
|
113994
114557
|
return { subjectId };
|
|
113995
114558
|
}
|
|
113996
|
-
throw new
|
|
114559
|
+
throw new HTTPException112(401, {
|
|
113997
114560
|
message: "organization administrator session required"
|
|
113998
114561
|
});
|
|
113999
114562
|
}
|
|
114000
114563
|
async function parseBody6(context, schema) {
|
|
114001
114564
|
const parsed = schema.safeParse(await context.req.json().catch(() => null));
|
|
114002
114565
|
if (!parsed.success) {
|
|
114003
|
-
throw new
|
|
114566
|
+
throw new HTTPException112(422, {
|
|
114004
114567
|
message: "invalid organization membership request"
|
|
114005
114568
|
});
|
|
114006
114569
|
}
|
|
@@ -114008,19 +114571,19 @@ async function parseBody6(context, schema) {
|
|
|
114008
114571
|
}
|
|
114009
114572
|
function parseId(schema, value, label) {
|
|
114010
114573
|
const parsed = schema.safeParse(value);
|
|
114011
|
-
if (!parsed.success) throw new
|
|
114574
|
+
if (!parsed.success) throw new HTTPException112(422, { message: `invalid ${label}` });
|
|
114012
114575
|
return parsed.data;
|
|
114013
114576
|
}
|
|
114014
114577
|
function rethrowMembershipError(error, resourceLimitMessage) {
|
|
114015
|
-
const sqlState =
|
|
114578
|
+
const sqlState = nestedPostgresSqlState16(error);
|
|
114016
114579
|
if (sqlState === "54000" && resourceLimitMessage) {
|
|
114017
|
-
throw new
|
|
114580
|
+
throw new HTTPException112(409, {
|
|
114018
114581
|
message: resourceLimitMessage
|
|
114019
114582
|
});
|
|
114020
114583
|
}
|
|
114021
114584
|
const status = organizationMembershipHttpStatus(sqlState);
|
|
114022
114585
|
if (status !== null) {
|
|
114023
|
-
throw new
|
|
114586
|
+
throw new HTTPException112(status, {
|
|
114024
114587
|
message: status === 403 ? "organization administration is not authorized" : status === 404 ? "organization resource not found" : status === 409 ? "organization membership state changed; refresh and retry" : "invalid organization membership operation"
|
|
114025
114588
|
});
|
|
114026
114589
|
}
|
|
@@ -114060,7 +114623,7 @@ function registerOrganizationMembershipRoutes(app, deps) {
|
|
|
114060
114623
|
)
|
|
114061
114624
|
);
|
|
114062
114625
|
} catch (error) {
|
|
114063
|
-
if (error instanceof
|
|
114626
|
+
if (error instanceof HTTPException112) throw error;
|
|
114064
114627
|
rethrowMembershipError(error);
|
|
114065
114628
|
}
|
|
114066
114629
|
});
|
|
@@ -114118,8 +114681,8 @@ function registerOrganizationMembershipRoutes(app, deps) {
|
|
|
114118
114681
|
})
|
|
114119
114682
|
);
|
|
114120
114683
|
} catch (error) {
|
|
114121
|
-
if (
|
|
114122
|
-
throw new
|
|
114684
|
+
if (nestedPostgresSqlState16(error) === "42501") {
|
|
114685
|
+
throw new HTTPException112(403, {
|
|
114123
114686
|
message: "organization membership is not active"
|
|
114124
114687
|
});
|
|
114125
114688
|
}
|
|
@@ -114130,7 +114693,7 @@ function registerOrganizationMembershipRoutes(app, deps) {
|
|
|
114130
114693
|
const { session, subjectId } = await requireManagedHuman(context, deps);
|
|
114131
114694
|
const query = ListOrganizationInvitationsPageQuery.safeParse(context.req.query());
|
|
114132
114695
|
if (!query.success) {
|
|
114133
|
-
throw new
|
|
114696
|
+
throw new HTTPException112(422, {
|
|
114134
114697
|
message: "invalid organization invitation page"
|
|
114135
114698
|
});
|
|
114136
114699
|
}
|
|
@@ -114440,7 +115003,7 @@ function registerOrganizationMembershipRoutes(app, deps) {
|
|
|
114440
115003
|
try {
|
|
114441
115004
|
assertOrganizationUserSetupDeliveryConfigured(deps.settings, deps.managedEmailTransport);
|
|
114442
115005
|
} catch {
|
|
114443
|
-
throw new
|
|
115006
|
+
throw new HTTPException112(503, {
|
|
114444
115007
|
message: "invited-user account setup delivery is not configured on this deployment"
|
|
114445
115008
|
});
|
|
114446
115009
|
}
|
|
@@ -114476,7 +115039,7 @@ function registerOrganizationMembershipRoutes(app, deps) {
|
|
|
114476
115039
|
201
|
|
114477
115040
|
);
|
|
114478
115041
|
} catch (error) {
|
|
114479
|
-
if (error instanceof
|
|
115042
|
+
if (error instanceof HTTPException112) throw error;
|
|
114480
115043
|
rethrowMembershipError(error);
|
|
114481
115044
|
}
|
|
114482
115045
|
});
|
|
@@ -114489,7 +115052,7 @@ function registerOrganizationMembershipRoutes(app, deps) {
|
|
|
114489
115052
|
);
|
|
114490
115053
|
const query = ListOrganizationInvitationsPageQuery.safeParse(context.req.query());
|
|
114491
115054
|
if (!query.success) {
|
|
114492
|
-
throw new
|
|
115055
|
+
throw new HTTPException112(422, {
|
|
114493
115056
|
message: "invalid organization invitation page"
|
|
114494
115057
|
});
|
|
114495
115058
|
}
|
|
@@ -114526,7 +115089,7 @@ function registerOrganizationMembershipRoutes(app, deps) {
|
|
|
114526
115089
|
try {
|
|
114527
115090
|
assertOrganizationUserSetupDeliveryConfigured(deps.settings, deps.managedEmailTransport);
|
|
114528
115091
|
} catch {
|
|
114529
|
-
throw new
|
|
115092
|
+
throw new HTTPException112(503, {
|
|
114530
115093
|
message: "invited-user account setup delivery is not configured on this deployment"
|
|
114531
115094
|
});
|
|
114532
115095
|
}
|
|
@@ -114573,7 +115136,7 @@ function registerOrganizationMembershipRoutes(app, deps) {
|
|
|
114573
115136
|
membership: OrganizationMember.parse(result.membership)
|
|
114574
115137
|
});
|
|
114575
115138
|
} catch (error) {
|
|
114576
|
-
if (error instanceof
|
|
115139
|
+
if (error instanceof HTTPException112) throw error;
|
|
114577
115140
|
rethrowMembershipError(error);
|
|
114578
115141
|
}
|
|
114579
115142
|
});
|
|
@@ -114772,14 +115335,14 @@ import {
|
|
|
114772
115335
|
SessionListCursorError as SessionListCursorError2,
|
|
114773
115336
|
SessionListCursorExpiredError as SessionListCursorExpiredError2
|
|
114774
115337
|
} from "@opengeni/db";
|
|
114775
|
-
import { HTTPException as
|
|
114776
|
-
import { z as
|
|
115338
|
+
import { HTTPException as HTTPException113 } from "hono/http-exception";
|
|
115339
|
+
import { z as z60 } from "zod";
|
|
114777
115340
|
var ORGANIZATION_SESSION_LIST_MAX_WORKSPACE_READS = 25;
|
|
114778
|
-
var OrganizationId3 =
|
|
114779
|
-
var OrganizationSessionListCursorEnvelope =
|
|
114780
|
-
workspaceId:
|
|
114781
|
-
cursor:
|
|
114782
|
-
pinnedOffset:
|
|
115341
|
+
var OrganizationId3 = z60.string().uuid();
|
|
115342
|
+
var OrganizationSessionListCursorEnvelope = z60.object({
|
|
115343
|
+
workspaceId: z60.string().uuid(),
|
|
115344
|
+
cursor: z60.string().min(1).nullable(),
|
|
115345
|
+
pinnedOffset: z60.number().int().nonnegative().max(1e4).optional()
|
|
114783
115346
|
}).strict();
|
|
114784
115347
|
function encodeOrganizationSessionListCursor(cursor) {
|
|
114785
115348
|
return Buffer.from(JSON.stringify(cursor)).toString("base64url");
|
|
@@ -114804,7 +115367,7 @@ function requireOrganizationSessionReadAuthority(context, organizationId2) {
|
|
|
114804
115367
|
if (authority.accountId === organizationId2 && hasPermission31(authority.permissions, "sessions:read")) {
|
|
114805
115368
|
return "organization_api_key";
|
|
114806
115369
|
}
|
|
114807
|
-
throw new
|
|
115370
|
+
throw new HTTPException113(403, { message: "organization session read authority required" });
|
|
114808
115371
|
}
|
|
114809
115372
|
const accountGrant = context.accountGrants.find(
|
|
114810
115373
|
(candidate) => candidate.accountId === organizationId2
|
|
@@ -114812,16 +115375,16 @@ function requireOrganizationSessionReadAuthority(context, organizationId2) {
|
|
|
114812
115375
|
if (accountGrant?.permissions.includes("account:admin")) {
|
|
114813
115376
|
return "account_admin";
|
|
114814
115377
|
}
|
|
114815
|
-
throw new
|
|
115378
|
+
throw new HTTPException113(403, { message: "organization session read authority required" });
|
|
114816
115379
|
}
|
|
114817
115380
|
function sessionAuthorizationHttpError2(error) {
|
|
114818
115381
|
if (error instanceof SessionAuthorizationDeniedError16) {
|
|
114819
|
-
return new
|
|
115382
|
+
return new HTTPException113(404, { message: "session not found" });
|
|
114820
115383
|
}
|
|
114821
115384
|
if (error instanceof SessionAuthorizationUnavailableError14) {
|
|
114822
|
-
return new
|
|
115385
|
+
return new HTTPException113(503, { message: "session authorization is unavailable" });
|
|
114823
115386
|
}
|
|
114824
|
-
if (error instanceof
|
|
115387
|
+
if (error instanceof HTTPException113) return error;
|
|
114825
115388
|
throw error;
|
|
114826
115389
|
}
|
|
114827
115390
|
function compareWorkspaceIds(left, right) {
|
|
@@ -114831,7 +115394,7 @@ function registerOrganizationSessionRoutes(app, deps) {
|
|
|
114831
115394
|
app.get("/v1/organizations/:organizationId/sessions", async (c) => {
|
|
114832
115395
|
const organizationIdResult = OrganizationId3.safeParse(c.req.param("organizationId"));
|
|
114833
115396
|
if (!organizationIdResult.success) {
|
|
114834
|
-
throw new
|
|
115397
|
+
throw new HTTPException113(422, { message: "invalid organization id" });
|
|
114835
115398
|
}
|
|
114836
115399
|
const organizationId2 = organizationIdResult.data;
|
|
114837
115400
|
const context = await requireAccessContext13(c, deps);
|
|
@@ -114839,14 +115402,14 @@ function registerOrganizationSessionRoutes(app, deps) {
|
|
|
114839
115402
|
const queryResult = ListOrganizationSessionsQuery.safeParse(c.req.query());
|
|
114840
115403
|
if (!queryResult.success) {
|
|
114841
115404
|
const issue = queryResult.error.issues[0];
|
|
114842
|
-
throw new
|
|
115405
|
+
throw new HTTPException113(400, {
|
|
114843
115406
|
message: issue ? `${issue.path.length > 0 ? `${issue.path.join(".")}: ` : ""}${issue.message}` : "invalid organization session list query"
|
|
114844
115407
|
});
|
|
114845
115408
|
}
|
|
114846
115409
|
const query = queryResult.data;
|
|
114847
115410
|
const cursor = query.cursor ? decodeOrganizationSessionListCursor(query.cursor) : null;
|
|
114848
115411
|
if (query.cursor && !cursor) {
|
|
114849
|
-
throw new
|
|
115412
|
+
throw new HTTPException113(400, { message: "cursor is invalid" });
|
|
114850
115413
|
}
|
|
114851
115414
|
const authority = accountScopedApiKeyWorkspaceAuthority9(context);
|
|
114852
115415
|
const workspaces = (await listSharedWorkspacesForAccount3(deps.db, organizationId2)).filter(
|
|
@@ -114918,7 +115481,7 @@ async function listWorkspaceSessionPage(c, deps, input) {
|
|
|
114918
115481
|
"sessions:read"
|
|
114919
115482
|
);
|
|
114920
115483
|
} catch (error) {
|
|
114921
|
-
if (input.readAuthority === "account_admin" && error instanceof
|
|
115484
|
+
if (input.readAuthority === "account_admin" && error instanceof HTTPException113 && error.status === 403) {
|
|
114922
115485
|
return null;
|
|
114923
115486
|
}
|
|
114924
115487
|
throw error;
|
|
@@ -114932,7 +115495,7 @@ async function listWorkspaceSessionPage(c, deps, input) {
|
|
|
114932
115495
|
}
|
|
114933
115496
|
const cursor = input.innerCursor ? decodeSessionListCursor2(input.innerCursor) : null;
|
|
114934
115497
|
if (input.innerCursor && !cursor) {
|
|
114935
|
-
throw new
|
|
115498
|
+
throw new HTTPException113(400, { message: "cursor is invalid" });
|
|
114936
115499
|
}
|
|
114937
115500
|
try {
|
|
114938
115501
|
const list = async (limit) => await listSessionsForSubject2(deps.db, input.workspace.id, {
|
|
@@ -114965,13 +115528,13 @@ async function listWorkspaceSessionPage(c, deps, input) {
|
|
|
114965
115528
|
return { sessions: withStatus(rows2), nextCursor: page2.nextCursor, nextPinnedOffset };
|
|
114966
115529
|
} catch (error) {
|
|
114967
115530
|
if (error instanceof SessionListAccessError2) {
|
|
114968
|
-
throw new
|
|
115531
|
+
throw new HTTPException113(403, { message: error.message });
|
|
114969
115532
|
}
|
|
114970
115533
|
if (error instanceof SessionListCursorExpiredError2) {
|
|
114971
|
-
throw new
|
|
115534
|
+
throw new HTTPException113(410, { message: error.message });
|
|
114972
115535
|
}
|
|
114973
115536
|
if (error instanceof SessionListCursorError2) {
|
|
114974
|
-
throw new
|
|
115537
|
+
throw new HTTPException113(400, { message: error.message });
|
|
114975
115538
|
}
|
|
114976
115539
|
throw error;
|
|
114977
115540
|
}
|
|
@@ -115006,10 +115569,10 @@ import {
|
|
|
115006
115569
|
OrganizationRecoveryUnavailableError,
|
|
115007
115570
|
startOrganizationRecoveryOperation
|
|
115008
115571
|
} from "@opengeni/db";
|
|
115009
|
-
import { HTTPException as
|
|
115010
|
-
import { z as
|
|
115011
|
-
var OrganizationId4 =
|
|
115012
|
-
var RecoveryOperationId =
|
|
115572
|
+
import { HTTPException as HTTPException114 } from "hono/http-exception";
|
|
115573
|
+
import { z as z61 } from "zod";
|
|
115574
|
+
var OrganizationId4 = z61.string().uuid();
|
|
115575
|
+
var RecoveryOperationId = z61.string().uuid();
|
|
115013
115576
|
var productionServices = {
|
|
115014
115577
|
requireCanonicalHumanRequestIdentity: requireCanonicalHumanRequestIdentity3,
|
|
115015
115578
|
getManagedAuthRequestActorAdmissionStamp,
|
|
@@ -115025,7 +115588,7 @@ var productionServices = {
|
|
|
115025
115588
|
};
|
|
115026
115589
|
async function requireRecoveryIdentity(context, deps, services) {
|
|
115027
115590
|
if (deps.settings.productAccessMode !== "managed" || !deps.managedAuth || !context.req.header("cookie") || context.req.header("authorization")) {
|
|
115028
|
-
throw new
|
|
115591
|
+
throw new HTTPException114(401, {
|
|
115029
115592
|
message: "Managed human authentication required"
|
|
115030
115593
|
});
|
|
115031
115594
|
}
|
|
@@ -115041,7 +115604,7 @@ async function requireRecoveryIdentity(context, deps, services) {
|
|
|
115041
115604
|
async function parseBody7(context, schema) {
|
|
115042
115605
|
const parsed = schema.safeParse(await context.req.json().catch(() => null));
|
|
115043
115606
|
if (!parsed.success) {
|
|
115044
|
-
throw new
|
|
115607
|
+
throw new HTTPException114(422, {
|
|
115045
115608
|
message: "Invalid organization recovery request"
|
|
115046
115609
|
});
|
|
115047
115610
|
}
|
|
@@ -115049,7 +115612,7 @@ async function parseBody7(context, schema) {
|
|
|
115049
115612
|
}
|
|
115050
115613
|
function parseId2(schema, value, label) {
|
|
115051
115614
|
const parsed = schema.safeParse(value);
|
|
115052
|
-
if (!parsed.success) throw new
|
|
115615
|
+
if (!parsed.success) throw new HTTPException114(422, { message: `Invalid ${label}` });
|
|
115053
115616
|
return parsed.data;
|
|
115054
115617
|
}
|
|
115055
115618
|
function organizationId(context) {
|
|
@@ -115104,12 +115667,12 @@ function organizationRecoveryHttpError(error) {
|
|
|
115104
115667
|
function requireActorFence(context, deps, services) {
|
|
115105
115668
|
const actorFence = services.getManagedAuthRequestActorLeaseStamp(context.req.raw);
|
|
115106
115669
|
if (deps.settings.managedAuthSessionSetMode !== "legacy" && !actorFence) {
|
|
115107
|
-
throw new
|
|
115670
|
+
throw new HTTPException114(409, {
|
|
115108
115671
|
message: "Managed actor mutation fence is unavailable"
|
|
115109
115672
|
});
|
|
115110
115673
|
}
|
|
115111
115674
|
if (!actorFence) {
|
|
115112
|
-
throw new
|
|
115675
|
+
throw new HTTPException114(409, {
|
|
115113
115676
|
message: "Organization recovery requires provider-neutral browser login slots"
|
|
115114
115677
|
});
|
|
115115
115678
|
}
|
|
@@ -115261,12 +115824,12 @@ import {
|
|
|
115261
115824
|
completeSelfServiceOrganizationSetup,
|
|
115262
115825
|
completeOrganizationUserSetup,
|
|
115263
115826
|
getSelfServiceOrganizationOnboardingState,
|
|
115264
|
-
nestedPostgresSqlState as
|
|
115827
|
+
nestedPostgresSqlState as nestedPostgresSqlState17,
|
|
115265
115828
|
preflightOrganizationUserSetup,
|
|
115266
115829
|
previewOrganizationUserSetup,
|
|
115267
115830
|
recordOrganizationSignupUseCase
|
|
115268
115831
|
} from "@opengeni/db";
|
|
115269
|
-
import { HTTPException as
|
|
115832
|
+
import { HTTPException as HTTPException115 } from "hono/http-exception";
|
|
115270
115833
|
var completedSetupReplayPasswordHash = `completed-replay:${"0".repeat(64)}`;
|
|
115271
115834
|
function registerManagedOnboardingRoutes(app, deps, options = {}) {
|
|
115272
115835
|
const accountSetupLimiter = options.accountSetupLimiter ?? new PublicSetupRateLimiter();
|
|
@@ -115290,7 +115853,7 @@ function registerManagedOnboardingRoutes(app, deps, options = {}) {
|
|
|
115290
115853
|
);
|
|
115291
115854
|
if (!parsed.success) {
|
|
115292
115855
|
recordOrganizationSetupOutcome(deps.observability, "failed");
|
|
115293
|
-
throw new
|
|
115856
|
+
throw new HTTPException115(422, {
|
|
115294
115857
|
message: "invalid organization setup request"
|
|
115295
115858
|
});
|
|
115296
115859
|
}
|
|
@@ -115319,26 +115882,26 @@ function registerManagedOnboardingRoutes(app, deps, options = {}) {
|
|
|
115319
115882
|
useCase: parsed.data.useCase
|
|
115320
115883
|
}).catch((error) => {
|
|
115321
115884
|
console.warn("[api] could not record the signup use case", {
|
|
115322
|
-
sqlState:
|
|
115885
|
+
sqlState: nestedPostgresSqlState17(error) ?? null
|
|
115323
115886
|
});
|
|
115324
115887
|
});
|
|
115325
115888
|
}
|
|
115326
115889
|
return context.json(completed);
|
|
115327
115890
|
} catch (error) {
|
|
115328
115891
|
recordOrganizationSetupOutcome(deps.observability, "failed");
|
|
115329
|
-
const sqlState =
|
|
115892
|
+
const sqlState = nestedPostgresSqlState17(error);
|
|
115330
115893
|
if (sqlState === "22023") {
|
|
115331
|
-
throw new
|
|
115894
|
+
throw new HTTPException115(422, {
|
|
115332
115895
|
message: "invalid organization setup request"
|
|
115333
115896
|
});
|
|
115334
115897
|
}
|
|
115335
115898
|
if (sqlState === "42501") {
|
|
115336
|
-
throw new
|
|
115899
|
+
throw new HTTPException115(403, {
|
|
115337
115900
|
message: "verified managed user required"
|
|
115338
115901
|
});
|
|
115339
115902
|
}
|
|
115340
115903
|
if (sqlState === "23505" || sqlState === "55000") {
|
|
115341
|
-
throw new
|
|
115904
|
+
throw new HTTPException115(409, {
|
|
115342
115905
|
message: "organization setup is no longer available; refresh to continue"
|
|
115343
115906
|
});
|
|
115344
115907
|
}
|
|
@@ -115347,14 +115910,14 @@ function registerManagedOnboardingRoutes(app, deps, options = {}) {
|
|
|
115347
115910
|
});
|
|
115348
115911
|
app.post("/v1/auth/organization-setup/preview", async (context) => {
|
|
115349
115912
|
if (deps.settings.productAccessMode !== "managed" || !deps.managedAuth) {
|
|
115350
|
-
throw new
|
|
115913
|
+
throw new HTTPException115(404, { message: "account setup is unavailable" });
|
|
115351
115914
|
}
|
|
115352
115915
|
enforceAccountSetupRateLimit(context, deps, accountSetupLimiter);
|
|
115353
115916
|
const parsed = PreviewOrganizationUserSetupRequest.safeParse(
|
|
115354
115917
|
await context.req.json().catch(() => null)
|
|
115355
115918
|
);
|
|
115356
115919
|
if (!parsed.success) {
|
|
115357
|
-
throw new
|
|
115920
|
+
throw new HTTPException115(422, { message: "invalid account setup preview request" });
|
|
115358
115921
|
}
|
|
115359
115922
|
return context.json(
|
|
115360
115923
|
OrganizationUserSetupPreview.parse(
|
|
@@ -115367,14 +115930,14 @@ function registerManagedOnboardingRoutes(app, deps, options = {}) {
|
|
|
115367
115930
|
});
|
|
115368
115931
|
app.post("/v1/auth/organization-setup", async (context) => {
|
|
115369
115932
|
if (deps.settings.productAccessMode !== "managed" || !deps.managedAuth) {
|
|
115370
|
-
throw new
|
|
115933
|
+
throw new HTTPException115(404, { message: "account setup is unavailable" });
|
|
115371
115934
|
}
|
|
115372
115935
|
enforceAccountSetupRateLimit(context, deps, accountSetupLimiter);
|
|
115373
115936
|
const parsed = CompleteOrganizationUserSetupRequest.safeParse(
|
|
115374
115937
|
await context.req.json().catch(() => null)
|
|
115375
115938
|
);
|
|
115376
115939
|
if (!parsed.success) {
|
|
115377
|
-
throw new
|
|
115940
|
+
throw new HTTPException115(422, {
|
|
115378
115941
|
message: "invalid account setup request"
|
|
115379
115942
|
});
|
|
115380
115943
|
}
|
|
@@ -115382,7 +115945,7 @@ function registerManagedOnboardingRoutes(app, deps, options = {}) {
|
|
|
115382
115945
|
const tokenDigest = await organizationUserSetupTokenDigest(parsed.data.token);
|
|
115383
115946
|
const preflight = await preflightOrganizationUserSetup(deps.db, tokenDigest);
|
|
115384
115947
|
if (preflight === "unavailable") {
|
|
115385
|
-
throw new
|
|
115948
|
+
throw new HTTPException115(404, {
|
|
115386
115949
|
message: "account setup link is invalid, expired, or already belongs to an account"
|
|
115387
115950
|
});
|
|
115388
115951
|
}
|
|
@@ -115406,19 +115969,19 @@ function registerManagedOnboardingRoutes(app, deps, options = {}) {
|
|
|
115406
115969
|
)
|
|
115407
115970
|
);
|
|
115408
115971
|
} catch (error) {
|
|
115409
|
-
const sqlState =
|
|
115972
|
+
const sqlState = nestedPostgresSqlState17(error);
|
|
115410
115973
|
if (sqlState === "22023") {
|
|
115411
|
-
throw new
|
|
115974
|
+
throw new HTTPException115(422, {
|
|
115412
115975
|
message: "invalid account setup request"
|
|
115413
115976
|
});
|
|
115414
115977
|
}
|
|
115415
115978
|
if (sqlState === "23505") {
|
|
115416
|
-
throw new
|
|
115979
|
+
throw new HTTPException115(409, {
|
|
115417
115980
|
message: "account setup request changed; reopen the original link and try again"
|
|
115418
115981
|
});
|
|
115419
115982
|
}
|
|
115420
115983
|
if (sqlState === "P0002" || sqlState === "42501" || sqlState === "55000") {
|
|
115421
|
-
throw new
|
|
115984
|
+
throw new HTTPException115(404, {
|
|
115422
115985
|
message: "account setup link is invalid, expired, or already belongs to an account"
|
|
115423
115986
|
});
|
|
115424
115987
|
}
|
|
@@ -115433,7 +115996,7 @@ function enforceAccountSetupRateLimit(context, deps, limiter) {
|
|
|
115433
115996
|
} catch {
|
|
115434
115997
|
}
|
|
115435
115998
|
if (!allowed2) {
|
|
115436
|
-
throw new
|
|
115999
|
+
throw new HTTPException115(429, { message: "too many account setup requests; slow down" });
|
|
115437
116000
|
}
|
|
115438
116001
|
}
|
|
115439
116002
|
var PublicSetupRateLimiter = class {
|
|
@@ -115496,7 +116059,7 @@ function refillSetupRateLimitBucket(bucket, capacity, refillPerSecond, now) {
|
|
|
115496
116059
|
}
|
|
115497
116060
|
async function requireManagedHuman2(context, deps) {
|
|
115498
116061
|
if (deps.settings.productAccessMode !== "managed" || !deps.managedAuth || !context.req.header("cookie") || context.req.header("authorization")) {
|
|
115499
|
-
throw new
|
|
116062
|
+
throw new HTTPException115(401, { message: "managed human session required" });
|
|
115500
116063
|
}
|
|
115501
116064
|
const session = await getManagedSession5(context, deps.managedAuth, {
|
|
115502
116065
|
db: deps.db,
|
|
@@ -115504,7 +116067,7 @@ async function requireManagedHuman2(context, deps) {
|
|
|
115504
116067
|
sessionSetMode: deps.settings.managedAuthSessionSetMode
|
|
115505
116068
|
});
|
|
115506
116069
|
if (!session?.user) {
|
|
115507
|
-
throw new
|
|
116070
|
+
throw new HTTPException115(401, { message: "managed human session required" });
|
|
115508
116071
|
}
|
|
115509
116072
|
return session;
|
|
115510
116073
|
}
|
|
@@ -115527,26 +116090,26 @@ import {
|
|
|
115527
116090
|
SessionAuthorizationUnavailableError as SessionAuthorizationUnavailableError15,
|
|
115528
116091
|
SessionTenancyManagedHumanRequiredError as SessionTenancyManagedHumanRequiredError3
|
|
115529
116092
|
} from "@opengeni/core";
|
|
115530
|
-
import { nestedPostgresSqlState as
|
|
115531
|
-
import { HTTPException as
|
|
115532
|
-
import { z as
|
|
116093
|
+
import { nestedPostgresSqlState as nestedPostgresSqlState18, SessionTenancyNotActivatedError as SessionTenancyNotActivatedError3 } from "@opengeni/db";
|
|
116094
|
+
import { HTTPException as HTTPException116 } from "hono/http-exception";
|
|
116095
|
+
import { z as z62 } from "zod";
|
|
115533
116096
|
async function body2(context, schema) {
|
|
115534
116097
|
const parsed = schema.safeParse(await context.req.json().catch(() => null));
|
|
115535
|
-
if (!parsed.success) throw new
|
|
116098
|
+
if (!parsed.success) throw new HTTPException116(422, { message: "invalid user-resource request" });
|
|
115536
116099
|
return parsed.data;
|
|
115537
116100
|
}
|
|
115538
116101
|
function lifecycleError(error) {
|
|
115539
116102
|
if (error instanceof SessionAuthorizationDeniedError17 || error instanceof SessionTenancyManagedHumanRequiredError3 || error instanceof SessionTenancyNotActivatedError3) {
|
|
115540
|
-
throw new
|
|
116103
|
+
throw new HTTPException116(403, { message: "user-resource authority denied" });
|
|
115541
116104
|
}
|
|
115542
116105
|
if (error instanceof SessionAuthorizationUnavailableError15) {
|
|
115543
|
-
throw new
|
|
116106
|
+
throw new HTTPException116(503, { message: "session authorization unavailable" });
|
|
115544
116107
|
}
|
|
115545
|
-
if (
|
|
115546
|
-
throw new
|
|
116108
|
+
if (nestedPostgresSqlState18(error) === "42501") {
|
|
116109
|
+
throw new HTTPException116(403, { message: "user-resource authority denied" });
|
|
115547
116110
|
}
|
|
115548
|
-
if (
|
|
115549
|
-
throw new
|
|
116111
|
+
if (nestedPostgresSqlState18(error) === "22023") {
|
|
116112
|
+
throw new HTTPException116(422, { message: "invalid user-resource request" });
|
|
115550
116113
|
}
|
|
115551
116114
|
throw error;
|
|
115552
116115
|
}
|
|
@@ -115559,7 +116122,7 @@ function registerUserResourceAuthorityRoutes(app, deps) {
|
|
|
115559
116122
|
cursor: context.req.query("cursor"),
|
|
115560
116123
|
limit: context.req.query("limit")
|
|
115561
116124
|
});
|
|
115562
|
-
if (!query.success) throw new
|
|
116125
|
+
if (!query.success) throw new HTTPException116(422, { message: "explicit scope=user required" });
|
|
115563
116126
|
const workspaceId = context.req.param("workspaceId");
|
|
115564
116127
|
const access = await requireAccessGrantAuthorization39(
|
|
115565
116128
|
context,
|
|
@@ -115586,8 +116149,8 @@ function registerUserResourceAuthorityRoutes(app, deps) {
|
|
|
115586
116149
|
});
|
|
115587
116150
|
app.post(`${base}/:authorityId/grants`, async (context) => {
|
|
115588
116151
|
const workspaceId = context.req.param("workspaceId");
|
|
115589
|
-
const authorityId =
|
|
115590
|
-
if (!authorityId.success) throw new
|
|
116152
|
+
const authorityId = z62.string().uuid().safeParse(context.req.param("authorityId"));
|
|
116153
|
+
if (!authorityId.success) throw new HTTPException116(422, { message: "invalid authority id" });
|
|
115591
116154
|
const request = await body2(context, IssueUserResourceGrantRequest);
|
|
115592
116155
|
const access = await requireAccessGrantAuthorization39(
|
|
115593
116156
|
context,
|
|
@@ -115615,9 +116178,9 @@ function registerUserResourceAuthorityRoutes(app, deps) {
|
|
|
115615
116178
|
});
|
|
115616
116179
|
app.delete(`${base}/grants/:grantId`, async (context) => {
|
|
115617
116180
|
const query = RevokeUserResourceGrantQuery.safeParse({ scope: context.req.query("scope") });
|
|
115618
|
-
if (!query.success) throw new
|
|
115619
|
-
const grantId =
|
|
115620
|
-
if (!grantId.success) throw new
|
|
116181
|
+
if (!query.success) throw new HTTPException116(422, { message: "explicit scope=user required" });
|
|
116182
|
+
const grantId = z62.string().uuid().safeParse(context.req.param("grantId"));
|
|
116183
|
+
if (!grantId.success) throw new HTTPException116(422, { message: "invalid grant id" });
|
|
115621
116184
|
const workspaceId = context.req.param("workspaceId");
|
|
115622
116185
|
const access = await requireAccessGrantAuthorization39(
|
|
115623
116186
|
context,
|
|
@@ -116205,6 +116768,58 @@ async function exactAvailable(providers, providerId, context) {
|
|
|
116205
116768
|
return provider && await provider.available(context) ? provider : null;
|
|
116206
116769
|
}
|
|
116207
116770
|
|
|
116771
|
+
// src/integrations/slack-tool-review.ts
|
|
116772
|
+
function slackToolReviewCanDecide(review) {
|
|
116773
|
+
return review.detailsAvailable && reviewLines(review).every((line) => line.length <= 2800) && JSON.stringify({
|
|
116774
|
+
title: review.title,
|
|
116775
|
+
account: review.accountLabel,
|
|
116776
|
+
consequence: review.consequence,
|
|
116777
|
+
effects: review.effects,
|
|
116778
|
+
samples: review.samples,
|
|
116779
|
+
fields: review.fields,
|
|
116780
|
+
moreFields: review.moreFields,
|
|
116781
|
+
reason: review.reason
|
|
116782
|
+
}).length <= 6e3;
|
|
116783
|
+
}
|
|
116784
|
+
function slackToolReviewBlocks(review, privateAudience) {
|
|
116785
|
+
if (!privateAudience || !slackToolReviewCanDecide(review))
|
|
116786
|
+
return [
|
|
116787
|
+
{
|
|
116788
|
+
type: "section",
|
|
116789
|
+
text: {
|
|
116790
|
+
type: "plain_text",
|
|
116791
|
+
text: "An action needs review. Open the task to review its private details."
|
|
116792
|
+
}
|
|
116793
|
+
}
|
|
116794
|
+
];
|
|
116795
|
+
const lines = reviewLines(review);
|
|
116796
|
+
const blocks = [];
|
|
116797
|
+
let text = "";
|
|
116798
|
+
for (const line of lines) {
|
|
116799
|
+
if (text && text.length + line.length + 1 > 2800) {
|
|
116800
|
+
blocks.push({ type: "section", text: { type: "plain_text", text } });
|
|
116801
|
+
text = "";
|
|
116802
|
+
}
|
|
116803
|
+
text += `${text ? "\n" : ""}${line}`;
|
|
116804
|
+
}
|
|
116805
|
+
if (text) blocks.push({ type: "section", text: { type: "plain_text", text } });
|
|
116806
|
+
return blocks;
|
|
116807
|
+
}
|
|
116808
|
+
function reviewLines(review) {
|
|
116809
|
+
return [
|
|
116810
|
+
review.title,
|
|
116811
|
+
review.accountLabel,
|
|
116812
|
+
review.consequence,
|
|
116813
|
+
...review.effects,
|
|
116814
|
+
...(review.samples ?? []).map(
|
|
116815
|
+
(sample) => [sample.title, sample.subtitle].filter(Boolean).join(" \u2014 ")
|
|
116816
|
+
),
|
|
116817
|
+
...review.fields.map((field) => `${field.label}: ${field.preview}`),
|
|
116818
|
+
review.moreFields ? `${review.moreFields} more fields in full details.` : null,
|
|
116819
|
+
review.reason
|
|
116820
|
+
].filter((line) => Boolean(line));
|
|
116821
|
+
}
|
|
116822
|
+
|
|
116208
116823
|
// src/integrations/slack-interactions.ts
|
|
116209
116824
|
import { createHash as createHash33, createHmac as createHmac14, timingSafeEqual as timingSafeEqual4 } from "crypto";
|
|
116210
116825
|
import {
|
|
@@ -116254,6 +116869,7 @@ import {
|
|
|
116254
116869
|
enqueueSlackAppHomeRefresh,
|
|
116255
116870
|
enqueueSlackInteractionInbox,
|
|
116256
116871
|
getConnectionMetadata as getConnectionMetadata14,
|
|
116872
|
+
getToolActionReview as getToolActionReview2,
|
|
116257
116873
|
getOrCreateSlackInteraction,
|
|
116258
116874
|
getLatestSessionModelForSubject,
|
|
116259
116875
|
getSession as getSession11,
|
|
@@ -116320,7 +116936,7 @@ import {
|
|
|
116320
116936
|
getActorNewSessionModelChoice,
|
|
116321
116937
|
hasPermission as hasPermission33,
|
|
116322
116938
|
requireAccessContext as requireAccessContext14,
|
|
116323
|
-
requireAccessGrant as
|
|
116939
|
+
requireAccessGrant as requireAccessGrant53,
|
|
116324
116940
|
requireSessionAuthorizationListScope as requireSessionAuthorizationListScope4,
|
|
116325
116941
|
resolveWorkspaceCatalogSettings as resolveWorkspaceCatalogSettings9
|
|
116326
116942
|
} from "@opengeni/core";
|
|
@@ -116462,7 +117078,7 @@ function otherDeploymentLinkContext(text, webBaseUrl) {
|
|
|
116462
117078
|
}
|
|
116463
117079
|
|
|
116464
117080
|
// src/integrations/slack-interactions.ts
|
|
116465
|
-
import { HTTPException as
|
|
117081
|
+
import { HTTPException as HTTPException117 } from "hono/http-exception";
|
|
116466
117082
|
|
|
116467
117083
|
// src/integrations/slack-mrkdwn.ts
|
|
116468
117084
|
var PROVIDER_CITATION_TOKEN = /[ \t]*\u{E200}(?:cite|filecite)(?:\u{E202}[^\u{E200}-\u{E202}]*)*\u{E201}/gu;
|
|
@@ -117230,14 +117846,14 @@ function registerSlackInteractionRoutes(app, deps) {
|
|
|
117230
117846
|
const payload = parseJsonObject(signed.rawBody);
|
|
117231
117847
|
if (payload.type === "url_verification") {
|
|
117232
117848
|
const challenge = boundedString(payload.challenge, 512);
|
|
117233
|
-
if (!challenge) throw new
|
|
117849
|
+
if (!challenge) throw new HTTPException117(400, { message: "invalid Slack challenge" });
|
|
117234
117850
|
return c.json({ challenge });
|
|
117235
117851
|
}
|
|
117236
117852
|
const teamId = boundedString(payload.team_id, 64);
|
|
117237
|
-
if (!teamId) throw new
|
|
117853
|
+
if (!teamId) throw new HTTPException117(400, { message: "invalid Slack event" });
|
|
117238
117854
|
const installation = await resolveSlackInstallationRoute2(deps.db, teamId);
|
|
117239
117855
|
if (!installation)
|
|
117240
|
-
throw new
|
|
117856
|
+
throw new HTTPException117(403, {
|
|
117241
117857
|
message: "Slack installation unavailable"
|
|
117242
117858
|
});
|
|
117243
117859
|
const event = record5(payload.event);
|
|
@@ -117280,12 +117896,12 @@ function registerSlackInteractionRoutes(app, deps) {
|
|
|
117280
117896
|
const signed = await readSignedSlackRequest(c, deps);
|
|
117281
117897
|
const form = new URLSearchParams(signed.rawBody);
|
|
117282
117898
|
if (form.get("command") !== deps.settings.slackCommand) {
|
|
117283
|
-
throw new
|
|
117899
|
+
throw new HTTPException117(400, { message: "invalid Slack command" });
|
|
117284
117900
|
}
|
|
117285
117901
|
const entry2 = normalizedFormInteraction(form, "slash_command");
|
|
117286
117902
|
const installation = await resolveSlackInstallationRoute2(deps.db, entry2.slackTeamId);
|
|
117287
117903
|
if (!installation)
|
|
117288
|
-
throw new
|
|
117904
|
+
throw new HTTPException117(403, {
|
|
117289
117905
|
message: "Slack installation unavailable"
|
|
117290
117906
|
});
|
|
117291
117907
|
if (isSlackInfoCommand(entry2.text)) {
|
|
@@ -117322,13 +117938,13 @@ function registerSlackInteractionRoutes(app, deps) {
|
|
|
117322
117938
|
const entry2 = normalizedBlockActionInteraction(payload);
|
|
117323
117939
|
const installation2 = await resolveSlackInstallationRoute2(deps.db, entry2.slackTeamId);
|
|
117324
117940
|
if (!installation2) {
|
|
117325
|
-
throw new
|
|
117941
|
+
throw new HTTPException117(403, { message: "Slack installation unavailable" });
|
|
117326
117942
|
}
|
|
117327
117943
|
await enqueueNormalizedSlackInteraction(deps, installation2, entry2);
|
|
117328
117944
|
return c.json({ ok: true });
|
|
117329
117945
|
}
|
|
117330
117946
|
if (payload.type !== "message_action") {
|
|
117331
|
-
throw new
|
|
117947
|
+
throw new HTTPException117(400, {
|
|
117332
117948
|
message: "unsupported Slack interaction"
|
|
117333
117949
|
});
|
|
117334
117950
|
}
|
|
@@ -117344,13 +117960,13 @@ function registerSlackInteractionRoutes(app, deps) {
|
|
|
117344
117960
|
const threadTs = boundedString(message?.thread_ts, 64);
|
|
117345
117961
|
const text = boundedText(message?.text);
|
|
117346
117962
|
if (!triggerId || !teamId || !userId || !channelId || !messageTs || !text) {
|
|
117347
|
-
throw new
|
|
117963
|
+
throw new HTTPException117(400, {
|
|
117348
117964
|
message: "invalid Slack message shortcut"
|
|
117349
117965
|
});
|
|
117350
117966
|
}
|
|
117351
117967
|
const installation = await resolveSlackInstallationRoute2(deps.db, teamId);
|
|
117352
117968
|
if (!installation)
|
|
117353
|
-
throw new
|
|
117969
|
+
throw new HTTPException117(403, {
|
|
117354
117970
|
message: "Slack installation unavailable"
|
|
117355
117971
|
});
|
|
117356
117972
|
await enqueueNormalizedSlackInteraction(deps, installation, {
|
|
@@ -117487,7 +118103,7 @@ function registerSlackInteractionRoutes(app, deps) {
|
|
|
117487
118103
|
);
|
|
117488
118104
|
app.get("/v1/workspaces/:workspaceId/members/access-requests/slack", async (c) => {
|
|
117489
118105
|
const workspaceId = c.req.param("workspaceId");
|
|
117490
|
-
await
|
|
118106
|
+
await requireAccessGrant53(c, deps, workspaceId, "members:manage");
|
|
117491
118107
|
const workspace = await getWorkspace11(deps.db, workspaceId);
|
|
117492
118108
|
const requests = await listPendingSlackUserLinkAccessRequests(deps.db, workspaceId);
|
|
117493
118109
|
return c.json(
|
|
@@ -117503,7 +118119,7 @@ function registerSlackInteractionRoutes(app, deps) {
|
|
|
117503
118119
|
"/v1/workspaces/:workspaceId/members/access-requests/slack/:requestId/approve",
|
|
117504
118120
|
async (c) => {
|
|
117505
118121
|
const workspaceId = c.req.param("workspaceId");
|
|
117506
|
-
const grant = await
|
|
118122
|
+
const grant = await requireAccessGrant53(c, deps, workspaceId, "members:manage");
|
|
117507
118123
|
const payload = await parseRequestJson(c, ApproveSlackUserLinkAccessRequest);
|
|
117508
118124
|
const requestId = c.req.param("requestId");
|
|
117509
118125
|
const requestTeam = await slackUserLinkAccessRequestTeam(deps.db, {
|
|
@@ -117543,7 +118159,7 @@ function registerSlackInteractionRoutes(app, deps) {
|
|
|
117543
118159
|
"/v1/workspaces/:workspaceId/members/access-requests/slack/:requestId/deny",
|
|
117544
118160
|
async (c) => {
|
|
117545
118161
|
const workspaceId = c.req.param("workspaceId");
|
|
117546
|
-
const grant = await
|
|
118162
|
+
const grant = await requireAccessGrant53(c, deps, workspaceId, "members:manage");
|
|
117547
118163
|
const payload = await parseRequestJson(c, SlackUserLinkAccessMutationRequest);
|
|
117548
118164
|
try {
|
|
117549
118165
|
const request = await denySlackUserLinkAccessRequest(deps.db, {
|
|
@@ -117566,24 +118182,24 @@ function registerSlackInteractionRoutes(app, deps) {
|
|
|
117566
118182
|
);
|
|
117567
118183
|
app.post("/v1/workspaces/:workspaceId/integrations/slack/user-links", async (c) => {
|
|
117568
118184
|
const workspaceId = c.req.param("workspaceId");
|
|
117569
|
-
const grant = await
|
|
118185
|
+
const grant = await requireAccessGrant53(c, deps, workspaceId, "sessions:create");
|
|
117570
118186
|
const body3 = record5(await c.req.json().catch(() => null));
|
|
117571
118187
|
const linkToken = boundedString(body3?.linkToken, 2048);
|
|
117572
118188
|
const signingSecret = deps.settings.slackSigningSecret;
|
|
117573
118189
|
if (!linkToken || !signingSecret) {
|
|
117574
|
-
throw new
|
|
118190
|
+
throw new HTTPException117(400, {
|
|
117575
118191
|
message: "invalid or expired Slack identity link"
|
|
117576
118192
|
});
|
|
117577
118193
|
}
|
|
117578
118194
|
const link = verifySlackUserLinkToken(signingSecret, linkToken);
|
|
117579
118195
|
if (!link || link.workspaceId !== workspaceId) {
|
|
117580
|
-
throw new
|
|
118196
|
+
throw new HTTPException117(400, {
|
|
117581
118197
|
message: "invalid or expired Slack identity link"
|
|
117582
118198
|
});
|
|
117583
118199
|
}
|
|
117584
118200
|
const installation = await resolveSlackLinkTargetInstallation(deps, link, workspaceId);
|
|
117585
118201
|
if (!installation) {
|
|
117586
|
-
throw new
|
|
118202
|
+
throw new HTTPException117(404, {
|
|
117587
118203
|
message: "Slack installation not found"
|
|
117588
118204
|
});
|
|
117589
118205
|
}
|
|
@@ -117622,9 +118238,9 @@ function registerSlackInteractionRoutes(app, deps) {
|
|
|
117622
118238
|
"/v1/workspaces/:workspaceId/integrations/slack/user-links/:slackUserId",
|
|
117623
118239
|
async (c) => {
|
|
117624
118240
|
const workspaceId = c.req.param("workspaceId");
|
|
117625
|
-
await
|
|
118241
|
+
await requireAccessGrant53(c, deps, workspaceId, "connections:write");
|
|
117626
118242
|
const connectionId = boundedString(c.req.query("connectionId"), 64);
|
|
117627
|
-
if (!connectionId) throw new
|
|
118243
|
+
if (!connectionId) throw new HTTPException117(400, { message: "connectionId is required" });
|
|
117628
118244
|
return c.json({
|
|
117629
118245
|
deleted: await deleteSlackBotUserLink(
|
|
117630
118246
|
deps.db,
|
|
@@ -117637,9 +118253,9 @@ function registerSlackInteractionRoutes(app, deps) {
|
|
|
117637
118253
|
);
|
|
117638
118254
|
app.get("/v1/workspaces/:workspaceId/integrations/slack/channel-routes", async (c) => {
|
|
117639
118255
|
const workspaceId = c.req.param("workspaceId");
|
|
117640
|
-
const grant = await
|
|
118256
|
+
const grant = await requireAccessGrant53(c, deps, workspaceId, "workspace:admin");
|
|
117641
118257
|
const connectionId = boundedString(c.req.query("connectionId"), 64);
|
|
117642
|
-
if (!connectionId) throw new
|
|
118258
|
+
if (!connectionId) throw new HTTPException117(400, { message: "connectionId is required" });
|
|
117643
118259
|
const routes = await listSlackChannelRoutes(
|
|
117644
118260
|
deps.db,
|
|
117645
118261
|
{ accountId: grant.accountId, workspaceId },
|
|
@@ -117668,7 +118284,7 @@ function registerSlackInteractionRoutes(app, deps) {
|
|
|
117668
118284
|
});
|
|
117669
118285
|
app.put("/v1/workspaces/:workspaceId/integrations/slack/channel-routes", async (c) => {
|
|
117670
118286
|
const workspaceId = c.req.param("workspaceId");
|
|
117671
|
-
const grant = await
|
|
118287
|
+
const grant = await requireAccessGrant53(c, deps, workspaceId, "workspace:admin");
|
|
117672
118288
|
const payload = await parseRequestJson(c, UpdateSlackChannelRoutesRequest);
|
|
117673
118289
|
const home = { accountId: grant.accountId, workspaceId };
|
|
117674
118290
|
const installation = await listSlackInstallationBindings2(deps.db, home);
|
|
@@ -117676,7 +118292,7 @@ function registerSlackInteractionRoutes(app, deps) {
|
|
|
117676
118292
|
(candidate) => candidate.connectionId === payload.connectionId
|
|
117677
118293
|
);
|
|
117678
118294
|
if (!binding) {
|
|
117679
|
-
throw new
|
|
118295
|
+
throw new HTTPException117(404, { message: "Slack installation not found" });
|
|
117680
118296
|
}
|
|
117681
118297
|
const callerPersonalWorkspaceId = await namedSubjectPersonalWorkspaceId2(deps.db, {
|
|
117682
118298
|
accountId: grant.accountId,
|
|
@@ -117690,12 +118306,12 @@ function registerSlackInteractionRoutes(app, deps) {
|
|
|
117690
118306
|
targetWorkspaceId: route2.targetWorkspaceId
|
|
117691
118307
|
});
|
|
117692
118308
|
if (!authorized || !hasPermission33(authorized.permissions, "sessions:create")) {
|
|
117693
|
-
throw new
|
|
118309
|
+
throw new HTTPException117(403, {
|
|
117694
118310
|
message: `you cannot start work in the workspace chosen for ${route2.slackChannelId}`
|
|
117695
118311
|
});
|
|
117696
118312
|
}
|
|
117697
118313
|
if (callerPersonalWorkspaceId !== null && route2.targetWorkspaceId === callerPersonalWorkspaceId) {
|
|
117698
|
-
throw new
|
|
118314
|
+
throw new HTTPException117(422, {
|
|
117699
118315
|
message: `a channel cannot be routed to a personal workspace: work started in ${route2.slackChannelId} would be invisible to everyone else in it`
|
|
117700
118316
|
});
|
|
117701
118317
|
}
|
|
@@ -117723,9 +118339,9 @@ function registerSlackInteractionRoutes(app, deps) {
|
|
|
117723
118339
|
});
|
|
117724
118340
|
app.get("/v1/workspaces/:workspaceId/integrations/slack/reaction-channels", async (c) => {
|
|
117725
118341
|
const workspaceId = c.req.param("workspaceId");
|
|
117726
|
-
const grant = await
|
|
118342
|
+
const grant = await requireAccessGrant53(c, deps, workspaceId, "workspace:admin");
|
|
117727
118343
|
const connectionId = boundedString(c.req.query("connectionId"), 64);
|
|
117728
|
-
if (!connectionId) throw new
|
|
118344
|
+
if (!connectionId) throw new HTTPException117(400, { message: "connectionId is required" });
|
|
117729
118345
|
const cursor = boundedString(c.req.query("cursor"), 1024);
|
|
117730
118346
|
const client = await createOpenGeniSlackBotInteractionClient(deps, {
|
|
117731
118347
|
accountId: grant.accountId,
|
|
@@ -118070,6 +118686,15 @@ function startSlackInteractionPump(deps, options = {}) {
|
|
|
118070
118686
|
for (let index = 0; index < maxPerTick; index += 1) {
|
|
118071
118687
|
if (!await drainSlackInteractionsOnce(deps)) break;
|
|
118072
118688
|
}
|
|
118689
|
+
} catch (error) {
|
|
118690
|
+
try {
|
|
118691
|
+
deps.observability?.error("Slack interaction delivery claim failed", {
|
|
118692
|
+
errorClass: error instanceof Error ? error.name : "SlackInteractionPumpError",
|
|
118693
|
+
errorCode: safeErrorCode(error),
|
|
118694
|
+
origin: "api"
|
|
118695
|
+
});
|
|
118696
|
+
} catch {
|
|
118697
|
+
}
|
|
118073
118698
|
} finally {
|
|
118074
118699
|
running = false;
|
|
118075
118700
|
}
|
|
@@ -118684,7 +119309,7 @@ async function processSlackInboxEntry(deps, entry2) {
|
|
|
118684
119309
|
{ surface: "slack" }
|
|
118685
119310
|
);
|
|
118686
119311
|
} catch (error) {
|
|
118687
|
-
if (error instanceof
|
|
119312
|
+
if (error instanceof HTTPException117) {
|
|
118688
119313
|
await client.postMessage({
|
|
118689
119314
|
operationId: deterministicUuid2(`slack-admission-failed:${interaction.id}`),
|
|
118690
119315
|
...routePolicy.directMessageShortcut ? { userId: entry2.slackUserId } : {
|
|
@@ -119220,7 +119845,7 @@ async function processSlackReactionInboxEntry(deps, entry2) {
|
|
|
119220
119845
|
);
|
|
119221
119846
|
await acceptSlackReactionTask(deps, grant, session.id, preparedEntry, preparedTask.resources);
|
|
119222
119847
|
} catch (error) {
|
|
119223
|
-
if (error instanceof
|
|
119848
|
+
if (error instanceof HTTPException117) {
|
|
119224
119849
|
await client.postMessage({
|
|
119225
119850
|
operationId: deterministicUuid2(`slack-reaction-admission-failed:${interaction.id}`),
|
|
119226
119851
|
channelId: entry2.slackChannelId,
|
|
@@ -119671,7 +120296,7 @@ async function withSlackAllowanceAdmissionNotice(deps, entry2, destination, admi
|
|
|
119671
120296
|
try {
|
|
119672
120297
|
await admit();
|
|
119673
120298
|
} catch (error) {
|
|
119674
|
-
if (error instanceof
|
|
120299
|
+
if (error instanceof HTTPException117 && (parseAllowanceExhaustedRefusal2(error.cause) ?? parseAllowanceExhaustedRefusal2(error))) {
|
|
119675
120300
|
const client = await createOpenGeniSlackBotInteractionClient(deps, {
|
|
119676
120301
|
accountId: entry2.accountId,
|
|
119677
120302
|
workspaceId: entry2.workspaceId,
|
|
@@ -120010,7 +120635,7 @@ async function executeSlackAction(deps, grant, interaction, handle) {
|
|
|
120010
120635
|
});
|
|
120011
120636
|
return {
|
|
120012
120637
|
result: decision === "approve" ? "approved" : "rejected",
|
|
120013
|
-
text: `${mention}${decision === "approve" ? "Approved
|
|
120638
|
+
text: `${mention}${decision === "approve" ? "Approved. Waiting to run." : "Declined. This action will not run."} ${openSessionText(deps, interaction.workspaceId, handle.sessionId)}`
|
|
120014
120639
|
};
|
|
120015
120640
|
}
|
|
120016
120641
|
if (handle.actionKind === "human_input_select" || handle.actionKind === "human_input_skip") {
|
|
@@ -120307,7 +120932,7 @@ function slackApprovalSummaries(payload) {
|
|
|
120307
120932
|
return id ? { id, name: name ?? "OpenGeni action" } : null;
|
|
120308
120933
|
}).filter((approval) => approval !== null).slice(0, MAX_SLACK_APPROVALS_PER_CARD);
|
|
120309
120934
|
}
|
|
120310
|
-
async function
|
|
120935
|
+
async function legacySlackApprovalCard(deps, interaction, event, mention, requesterAuthorized) {
|
|
120311
120936
|
const operationId = deterministicUuid2(
|
|
120312
120937
|
slackPostSeed(interaction, `slack-delivery:${interaction.id}:${event.sequence}:approval`)
|
|
120313
120938
|
);
|
|
@@ -120380,6 +121005,94 @@ ${approval.name}` }
|
|
|
120380
121005
|
operationId
|
|
120381
121006
|
};
|
|
120382
121007
|
}
|
|
121008
|
+
async function slackApprovalCard(deps, interaction, event, mention, requesterAuthorized) {
|
|
121009
|
+
const operationId = deterministicUuid2(
|
|
121010
|
+
slackPostSeed(interaction, `slack-delivery:${interaction.id}:${event.sequence}:approval`)
|
|
121011
|
+
);
|
|
121012
|
+
const approvals = slackApprovalSummaries(event.payload);
|
|
121013
|
+
const link = interaction.sessionId ? slackSessionUrl(deps, interaction.workspaceId, interaction.sessionId) : null;
|
|
121014
|
+
const fallback = `${mention}An action needs review.${link ? ` <${link}|Open the task to review>` : " Open the task to review it."}`;
|
|
121015
|
+
const privateAudience = requesterAuthorized && interaction.visibility === "private" && interaction.slackChannelId.startsWith("D");
|
|
121016
|
+
if (!privateAudience || !interaction.sessionId || !interaction.initiatingSlackUserId || approvals.length === 0)
|
|
121017
|
+
return { text: fallback, operationId };
|
|
121018
|
+
const reviews = await Promise.all(
|
|
121019
|
+
approvals.map(
|
|
121020
|
+
(approval) => getToolActionReview2(deps.db, {
|
|
121021
|
+
accountId: interaction.accountId,
|
|
121022
|
+
workspaceId: interaction.workspaceId,
|
|
121023
|
+
sessionId: interaction.sessionId,
|
|
121024
|
+
approvalId: approval.id
|
|
121025
|
+
})
|
|
121026
|
+
)
|
|
121027
|
+
);
|
|
121028
|
+
const reviewById = new Map(
|
|
121029
|
+
reviews.flatMap((review) => review ? [[review.id, review]] : [])
|
|
121030
|
+
);
|
|
121031
|
+
const actionable = approvals.filter((approval) => {
|
|
121032
|
+
const review = reviewById.get(approval.id);
|
|
121033
|
+
return review && slackToolReviewCanDecide(review);
|
|
121034
|
+
});
|
|
121035
|
+
const specs = actionable.flatMap((approval) => [
|
|
121036
|
+
{
|
|
121037
|
+
actionKind: "approval_approve",
|
|
121038
|
+
actionKey: `approval:${approval.id}:approve`,
|
|
121039
|
+
targetId: approval.id
|
|
121040
|
+
},
|
|
121041
|
+
{
|
|
121042
|
+
actionKind: "approval_reject",
|
|
121043
|
+
actionKey: `approval:${approval.id}:reject`,
|
|
121044
|
+
targetId: approval.id
|
|
121045
|
+
}
|
|
121046
|
+
]).slice(0, MAX_SLACK_ACTIONS_PER_CARD);
|
|
121047
|
+
const handles = specs.length ? await reserveSlackInteractionActionHandles(deps.db, {
|
|
121048
|
+
interaction,
|
|
121049
|
+
sessionEventSequence: event.sequence,
|
|
121050
|
+
messageOperationId: operationId,
|
|
121051
|
+
expiresAt: new Date(Date.now() + SLACK_ACTION_TTL_MS),
|
|
121052
|
+
actions: specs
|
|
121053
|
+
}) : [];
|
|
121054
|
+
const byKey = new Map(handles.map((handle) => [handle.actionKey, handle]));
|
|
121055
|
+
const blocks = [];
|
|
121056
|
+
for (const approval of approvals) {
|
|
121057
|
+
const approve = byKey.get(`approval:${approval.id}:approve`);
|
|
121058
|
+
const reject = byKey.get(`approval:${approval.id}:reject`);
|
|
121059
|
+
const review = reviewById.get(approval.id);
|
|
121060
|
+
if (!review) continue;
|
|
121061
|
+
blocks.push(...slackToolReviewBlocks(review, privateAudience));
|
|
121062
|
+
if (approve && reject) {
|
|
121063
|
+
blocks.push({
|
|
121064
|
+
type: "actions",
|
|
121065
|
+
block_id: `opengeni_approval_${event.sequence}_${blocks.length}`,
|
|
121066
|
+
elements: [
|
|
121067
|
+
{
|
|
121068
|
+
type: "button",
|
|
121069
|
+
action_id: SLACK_ACTION_ID_BY_KIND.approval_approve,
|
|
121070
|
+
value: approve.id,
|
|
121071
|
+
text: { type: "plain_text", text: review.approveLabel.slice(0, 75), emoji: true },
|
|
121072
|
+
style: "primary"
|
|
121073
|
+
},
|
|
121074
|
+
{
|
|
121075
|
+
type: "button",
|
|
121076
|
+
action_id: SLACK_ACTION_ID_BY_KIND.approval_reject,
|
|
121077
|
+
value: reject.id,
|
|
121078
|
+
text: { type: "plain_text", text: "Decline", emoji: true }
|
|
121079
|
+
}
|
|
121080
|
+
]
|
|
121081
|
+
});
|
|
121082
|
+
}
|
|
121083
|
+
}
|
|
121084
|
+
return {
|
|
121085
|
+
text: fallback,
|
|
121086
|
+
blocks: [
|
|
121087
|
+
{
|
|
121088
|
+
type: "section",
|
|
121089
|
+
text: { type: "mrkdwn", text: fallback }
|
|
121090
|
+
},
|
|
121091
|
+
...blocks
|
|
121092
|
+
],
|
|
121093
|
+
operationId
|
|
121094
|
+
};
|
|
121095
|
+
}
|
|
120383
121096
|
async function slackSharedResultPublicationBlocks(deps, interaction, event, requesterAuthorized, messageOperationId) {
|
|
120384
121097
|
if (!safePayloadText(event.payload, "output").trim()) return [];
|
|
120385
121098
|
if (!requesterAuthorized || !interaction.sessionId || !interaction.initiatingSlackUserId) {
|
|
@@ -120677,15 +121390,42 @@ async function deliverSlackSessionEvents(deps, interaction, claimHolderId) {
|
|
|
120677
121390
|
requester.mention,
|
|
120678
121391
|
requester.authorized
|
|
120679
121392
|
);
|
|
120680
|
-
|
|
120681
|
-
|
|
120682
|
-
|
|
120683
|
-
|
|
120684
|
-
|
|
120685
|
-
|
|
120686
|
-
|
|
120687
|
-
|
|
120688
|
-
|
|
121393
|
+
try {
|
|
121394
|
+
await postDelivery(
|
|
121395
|
+
client,
|
|
121396
|
+
interaction,
|
|
121397
|
+
event,
|
|
121398
|
+
card.text,
|
|
121399
|
+
"approval",
|
|
121400
|
+
card.operationId,
|
|
121401
|
+
card.blocks
|
|
121402
|
+
);
|
|
121403
|
+
} catch (error) {
|
|
121404
|
+
if (!(error instanceof SlackBotOperationConflictError)) throw error;
|
|
121405
|
+
const prior = await getSlackBotPostOperation2(
|
|
121406
|
+
deps.db,
|
|
121407
|
+
interaction.workspaceId,
|
|
121408
|
+
interaction.connectionId,
|
|
121409
|
+
card.operationId
|
|
121410
|
+
);
|
|
121411
|
+
if (prior?.status === "completed") continue;
|
|
121412
|
+
const legacy = await legacySlackApprovalCard(
|
|
121413
|
+
deps,
|
|
121414
|
+
interaction,
|
|
121415
|
+
event,
|
|
121416
|
+
requester.mention,
|
|
121417
|
+
requester.authorized
|
|
121418
|
+
);
|
|
121419
|
+
await postDelivery(
|
|
121420
|
+
client,
|
|
121421
|
+
interaction,
|
|
121422
|
+
event,
|
|
121423
|
+
legacy.text,
|
|
121424
|
+
"approval",
|
|
121425
|
+
legacy.operationId,
|
|
121426
|
+
legacy.blocks
|
|
121427
|
+
);
|
|
121428
|
+
}
|
|
120689
121429
|
} else if (event.type === "session.humanInput.requested") {
|
|
120690
121430
|
const card = await slackHumanInputCard(
|
|
120691
121431
|
deps,
|
|
@@ -120926,12 +121666,12 @@ async function enqueueNormalizedSlackInteraction(deps, route2, entry2) {
|
|
|
120926
121666
|
async function readSignedSlackRequest(c, deps) {
|
|
120927
121667
|
const signingSecret = deps.settings.slackSigningSecret;
|
|
120928
121668
|
if (!signingSecret)
|
|
120929
|
-
throw new
|
|
121669
|
+
throw new HTTPException117(503, {
|
|
120930
121670
|
message: "Slack interactions are disabled"
|
|
120931
121671
|
});
|
|
120932
121672
|
const rawBytes = new Uint8Array(await c.req.raw.arrayBuffer());
|
|
120933
121673
|
if (rawBytes.byteLength === 0 || rawBytes.byteLength > SLACK_INTERACTION_MAX_BODY_BYTES) {
|
|
120934
|
-
throw new
|
|
121674
|
+
throw new HTTPException117(rawBytes.byteLength > SLACK_INTERACTION_MAX_BODY_BYTES ? 413 : 400, {
|
|
120935
121675
|
message: "invalid Slack request body"
|
|
120936
121676
|
});
|
|
120937
121677
|
}
|
|
@@ -120944,7 +121684,7 @@ async function readSignedSlackRequest(c, deps) {
|
|
|
120944
121684
|
},
|
|
120945
121685
|
signingSecret
|
|
120946
121686
|
)) {
|
|
120947
|
-
throw new
|
|
121687
|
+
throw new HTTPException117(401, { message: "invalid Slack signature" });
|
|
120948
121688
|
}
|
|
120949
121689
|
return { rawBody };
|
|
120950
121690
|
}
|
|
@@ -120955,7 +121695,7 @@ function normalizedFormInteraction(form, triggerKind) {
|
|
|
120955
121695
|
const triggerId = boundedString(form.get("trigger_id"), 256);
|
|
120956
121696
|
const text = boundedText(form.get("text"));
|
|
120957
121697
|
if (!teamId || !userId || !channelId || !triggerId || !text) {
|
|
120958
|
-
throw new
|
|
121698
|
+
throw new HTTPException117(400, { message: "invalid Slack command payload" });
|
|
120959
121699
|
}
|
|
120960
121700
|
return {
|
|
120961
121701
|
providerEventId: `command:${triggerId}`,
|
|
@@ -120998,7 +121738,7 @@ function normalizedBlockActionInteraction(payload) {
|
|
|
120998
121738
|
const actionId = boundedString(action?.action_id, 128);
|
|
120999
121739
|
const handleId = boundedString(action?.value, 64);
|
|
121000
121740
|
if (!teamId || !userId || !channelId || !messageTs || !actionTs || !actionId || !SLACK_BLOCK_ACTION_IDS.has(actionId) || !handleId || !/^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i.test(handleId) || !Array.isArray(payload.actions) || payload.actions.length !== 1) {
|
|
121001
|
-
throw new
|
|
121741
|
+
throw new HTTPException117(400, { message: "invalid Slack block action" });
|
|
121002
121742
|
}
|
|
121003
121743
|
const identity2 = createHash33("sha256").update([teamId, userId, channelId, messageTs, actionTs, actionId, handleId].join("\n")).digest("hex");
|
|
121004
121744
|
return {
|
|
@@ -121199,29 +121939,29 @@ function linkUrl(deps, entry2, mintedAtMs) {
|
|
|
121199
121939
|
}
|
|
121200
121940
|
async function requireManagedSlackLinkHuman(c, deps) {
|
|
121201
121941
|
if (c.req.header("authorization")) {
|
|
121202
|
-
throw new
|
|
121942
|
+
throw new HTTPException117(401, { message: "managed browser sign-in required" });
|
|
121203
121943
|
}
|
|
121204
121944
|
const context = await requireAccessContext14(c, deps);
|
|
121205
121945
|
if (context.mode !== "managed" || !context.subjectId.startsWith("user:")) {
|
|
121206
|
-
throw new
|
|
121946
|
+
throw new HTTPException117(403, { message: "managed browser sign-in required" });
|
|
121207
121947
|
}
|
|
121208
121948
|
return context;
|
|
121209
121949
|
}
|
|
121210
121950
|
function freshSlackLinkRequired() {
|
|
121211
|
-
return new
|
|
121951
|
+
return new HTTPException117(400, {
|
|
121212
121952
|
message: "This Slack link is invalid or expired. Request a fresh link from Slack."
|
|
121213
121953
|
});
|
|
121214
121954
|
}
|
|
121215
121955
|
function slackLinkAccessHttpError(error) {
|
|
121216
|
-
if (error instanceof
|
|
121956
|
+
if (error instanceof HTTPException117) return error;
|
|
121217
121957
|
if (!(error instanceof SlackUserLinkAccessPersistenceError)) throw error;
|
|
121218
121958
|
if (error.code === "version_conflict" || error.code === "idempotency_conflict") {
|
|
121219
|
-
return new
|
|
121959
|
+
return new HTTPException117(409, {
|
|
121220
121960
|
message: "The Slack access request changed. Refresh and try again."
|
|
121221
121961
|
});
|
|
121222
121962
|
}
|
|
121223
121963
|
if (error.code === "state_conflict") {
|
|
121224
|
-
return new
|
|
121964
|
+
return new HTTPException117(409, {
|
|
121225
121965
|
message: "This Slack link is no longer pending. Request a fresh link from Slack."
|
|
121226
121966
|
});
|
|
121227
121967
|
}
|
|
@@ -121289,7 +122029,7 @@ function parseJsonObject(value) {
|
|
|
121289
122029
|
if (result) return result;
|
|
121290
122030
|
} catch {
|
|
121291
122031
|
}
|
|
121292
|
-
throw new
|
|
122032
|
+
throw new HTTPException117(400, { message: "invalid Slack JSON payload" });
|
|
121293
122033
|
}
|
|
121294
122034
|
function record5(value) {
|
|
121295
122035
|
return value && typeof value === "object" && !Array.isArray(value) ? value : null;
|
|
@@ -121319,7 +122059,7 @@ function safeErrorCode(error) {
|
|
|
121319
122059
|
if (error instanceof SlackBotProviderError) return error.code.slice(0, 128);
|
|
121320
122060
|
if (error instanceof SlackInteractionPermanentError) return error.code.slice(0, 128);
|
|
121321
122061
|
if (error instanceof SlackInteractionRetryableError) return error.code.slice(0, 128);
|
|
121322
|
-
if (error instanceof
|
|
122062
|
+
if (error instanceof HTTPException117) return `http_${error.status}`;
|
|
121323
122063
|
const raw = error instanceof Error ? error.name : "slack_interaction_error";
|
|
121324
122064
|
return raw.toLowerCase().replace(/[^a-z0-9_-]/g, "_").slice(0, 128) || "error";
|
|
121325
122065
|
}
|
|
@@ -121351,7 +122091,7 @@ var SlackInteractionRetryableError = class extends Error {
|
|
|
121351
122091
|
}
|
|
121352
122092
|
};
|
|
121353
122093
|
function permanentSlackInteractionError(error) {
|
|
121354
|
-
return error instanceof SlackInteractionPermanentError || error instanceof
|
|
122094
|
+
return error instanceof SlackInteractionPermanentError || error instanceof HTTPException117;
|
|
121355
122095
|
}
|
|
121356
122096
|
var PERMANENT_SLACK_DELIVERY_CODES = /* @__PURE__ */ new Set([
|
|
121357
122097
|
"account_inactive",
|
|
@@ -121462,7 +122202,7 @@ function createAppComposition(deps) {
|
|
|
121462
122202
|
authoritySubjectId
|
|
121463
122203
|
}) => {
|
|
121464
122204
|
if (!objectStorage) {
|
|
121465
|
-
throw new
|
|
122205
|
+
throw new HTTPException118(503, {
|
|
121466
122206
|
message: "object storage is not configured"
|
|
121467
122207
|
});
|
|
121468
122208
|
}
|
|
@@ -121828,7 +122568,7 @@ function createAppComposition(deps) {
|
|
|
121828
122568
|
} catch (error) {
|
|
121829
122569
|
if (error instanceof ManagedAuthActorChangeError2) {
|
|
121830
122570
|
c.header("x-opengeni-actor-state", "changed");
|
|
121831
|
-
throw new
|
|
122571
|
+
throw new HTTPException118(409, { message: error.code, cause: error });
|
|
121832
122572
|
}
|
|
121833
122573
|
if (error instanceof ManagedAuthActorLeaseOutcomeUnknownError) {
|
|
121834
122574
|
throw new ApiHttpError(503, {
|
|
@@ -121918,7 +122658,7 @@ function createAppComposition(deps) {
|
|
|
121918
122658
|
deps.settings.publicBaseUrl
|
|
121919
122659
|
);
|
|
121920
122660
|
if (!attempt || !authority || attempt.authorityHash !== managedAuthSha2563(authority)) {
|
|
121921
|
-
throw new
|
|
122661
|
+
throw new HTTPException118(409, { message: "provider_route_blocked" });
|
|
121922
122662
|
}
|
|
121923
122663
|
const isolated = await isolatedManagedAuthOAuthCallbackRequest(managedAuth, c.req.raw);
|
|
121924
122664
|
preserveCookieNames = [isolated.stateCookieName];
|
|
@@ -122065,7 +122805,7 @@ function createAppComposition(deps) {
|
|
|
122065
122805
|
let modelSelectionForbidden = false;
|
|
122066
122806
|
const requestedWorkspaceId = c.req.query("workspaceId");
|
|
122067
122807
|
if (requestedWorkspaceId !== void 0 && requestedWorkspaceId.trim() === "") {
|
|
122068
|
-
throw new
|
|
122808
|
+
throw new HTTPException118(422, { message: "workspaceId must not be empty" });
|
|
122069
122809
|
}
|
|
122070
122810
|
const callerScoped = requestedWorkspaceId !== void 0 || deps.settings.productAccessMode !== "managed" || c.req.header("authorization") !== void 0 || // Browser bootstrap precedes session-set reconciliation. A cookie alone
|
|
122071
122811
|
// cannot scope this public read (broker/changed actors need an epoch).
|
|
@@ -122075,13 +122815,13 @@ function createAppComposition(deps) {
|
|
|
122075
122815
|
try {
|
|
122076
122816
|
context = await requireAccessContext15(c, routeDeps);
|
|
122077
122817
|
} catch (error) {
|
|
122078
|
-
if (!(error instanceof
|
|
122818
|
+
if (!(error instanceof HTTPException118 && error.status === 401) || requestedWorkspaceId !== void 0 || c.req.header("authorization") !== void 0 || c.req.header("x-opengeni-actor-epoch") !== void 0 || c.req.header("x-opengeni-external-actor") !== void 0) {
|
|
122079
122819
|
throw error;
|
|
122080
122820
|
}
|
|
122081
122821
|
}
|
|
122082
122822
|
const workspaceId = requestedWorkspaceId ?? context?.defaultWorkspaceId;
|
|
122083
122823
|
if (context && workspaceId) {
|
|
122084
|
-
const grant = await
|
|
122824
|
+
const grant = await requireAccessGrant54(c, routeDeps, workspaceId);
|
|
122085
122825
|
await withAccessGrantSessionRlsContext(routeDeps, grant, async () => {
|
|
122086
122826
|
catalogSettings = (await resolveWorkspaceCatalogSettings10(deps.db, deps.settings, {
|
|
122087
122827
|
accountId: grant.accountId,
|
|
@@ -122196,7 +122936,7 @@ function createAppComposition(deps) {
|
|
|
122196
122936
|
boundedRequest = await boundedMcpRequest(c.req.raw);
|
|
122197
122937
|
} catch (error) {
|
|
122198
122938
|
if (error instanceof McpPayloadTooLargeError) {
|
|
122199
|
-
throw new
|
|
122939
|
+
throw new HTTPException118(413, { message: "MCP request body exceeds the safety limit" });
|
|
122200
122940
|
}
|
|
122201
122941
|
throw error;
|
|
122202
122942
|
}
|
|
@@ -122219,7 +122959,7 @@ function createAppComposition(deps) {
|
|
|
122219
122959
|
const context = await requireAccessContext15(c, routeDeps);
|
|
122220
122960
|
const authorization = c.req.header("authorization");
|
|
122221
122961
|
if (!accountScopedApiKeyWorkspaceAuthority10(context) || !authorization) {
|
|
122222
|
-
throw new
|
|
122962
|
+
throw new HTTPException118(403, {
|
|
122223
122963
|
message: "Connect with Opengeni sign-in or an organization API key."
|
|
122224
122964
|
});
|
|
122225
122965
|
}
|
|
@@ -122230,13 +122970,32 @@ function createAppComposition(deps) {
|
|
|
122230
122970
|
};
|
|
122231
122971
|
}
|
|
122232
122972
|
} catch (error) {
|
|
122233
|
-
if (error instanceof
|
|
122973
|
+
if (error instanceof HTTPException118 && error.status === 401) challenge();
|
|
122234
122974
|
throw error;
|
|
122235
122975
|
}
|
|
122976
|
+
if (c.req.method === "GET") {
|
|
122977
|
+
const version2 = c.req.header("mcp-protocol-version");
|
|
122978
|
+
if (version2 && !SUPPORTED_PROTOCOL_VERSIONS.includes(version2)) {
|
|
122979
|
+
return c.json(
|
|
122980
|
+
{
|
|
122981
|
+
jsonrpc: "2.0",
|
|
122982
|
+
id: null,
|
|
122983
|
+
error: { code: -32e3, message: "Unsupported protocol version." }
|
|
122984
|
+
},
|
|
122985
|
+
400
|
|
122986
|
+
);
|
|
122987
|
+
}
|
|
122988
|
+
return c.json(
|
|
122989
|
+
{ jsonrpc: "2.0", id: null, error: { code: -32e3, message: "Method not allowed." } },
|
|
122990
|
+
405,
|
|
122991
|
+
{ allow: "POST" }
|
|
122992
|
+
);
|
|
122993
|
+
}
|
|
122236
122994
|
const transport = new WebStandardStreamableHTTPServerTransport3({ enableJsonResponse: true });
|
|
122237
122995
|
const mcp = buildOrganizationMcpServer({
|
|
122238
122996
|
caller,
|
|
122239
122997
|
origin: new URL(c.req.url).origin,
|
|
122998
|
+
publicOrigin: canonicalPublicOrigin3(deps.settings.publicBaseUrl),
|
|
122240
122999
|
dispatch: async (request) => await app.fetch(request, c.env),
|
|
122241
123000
|
signal: c.req.raw.signal
|
|
122242
123001
|
});
|
|
@@ -122250,7 +123009,7 @@ function createAppComposition(deps) {
|
|
|
122250
123009
|
app.use("/v1/workspaces/:workspaceId/*", async (c, next) => {
|
|
122251
123010
|
const workspaceId = c.req.param("workspaceId");
|
|
122252
123011
|
if (workspaceRequestRequiresCodexAccountPrevalidation(c.req.raw)) {
|
|
122253
|
-
const grant2 = await
|
|
123012
|
+
const grant2 = await requireAccessGrant54(c, routeDeps, workspaceId);
|
|
122254
123013
|
await validateCodexAccountTarget(c.req.raw);
|
|
122255
123014
|
await withAccessGrantSessionRlsContext(routeDeps, grant2, next);
|
|
122256
123015
|
return;
|
|
@@ -122260,7 +123019,7 @@ function createAppComposition(deps) {
|
|
|
122260
123019
|
return;
|
|
122261
123020
|
}
|
|
122262
123021
|
const permission = c.req.method === "PUT" && /^\/v1\/workspaces\/[^/]+\/artifact-catalog\/[^/]+\/[^/]+\/pin$/.test(c.req.path) ? "artifacts:publish" : void 0;
|
|
122263
|
-
const grant = await
|
|
123022
|
+
const grant = await requireAccessGrant54(c, routeDeps, workspaceId, permission);
|
|
122264
123023
|
await withAccessGrantSessionRlsContext(routeDeps, grant, next);
|
|
122265
123024
|
});
|
|
122266
123025
|
app.all("/v1/workspaces/:workspaceId/mcp", async (c) => {
|
|
@@ -122288,7 +123047,7 @@ function createAppComposition(deps) {
|
|
|
122288
123047
|
boundedRequest = await boundedMcpRequest(c.req.raw);
|
|
122289
123048
|
} catch (error) {
|
|
122290
123049
|
if (error instanceof McpPayloadTooLargeError) {
|
|
122291
|
-
throw new
|
|
123050
|
+
throw new HTTPException118(413, {
|
|
122292
123051
|
message: "MCP request body exceeds the safety limit"
|
|
122293
123052
|
});
|
|
122294
123053
|
}
|
|
@@ -122298,7 +123057,7 @@ function createAppComposition(deps) {
|
|
|
122298
123057
|
try {
|
|
122299
123058
|
oauthAccess = await resolveMcpOAuthRouteAccess(routeDeps, c.req.raw, workspaceId);
|
|
122300
123059
|
} catch (error) {
|
|
122301
|
-
if (error instanceof
|
|
123060
|
+
if (error instanceof HTTPException118 && error.status === 401) {
|
|
122302
123061
|
c.header(
|
|
122303
123062
|
"www-authenticate",
|
|
122304
123063
|
mcpOAuthAuthenticateHeader(routeDeps, new URL(c.req.url).pathname)
|
|
@@ -122334,7 +123093,7 @@ function createAppComposition(deps) {
|
|
|
122334
123093
|
try {
|
|
122335
123094
|
authorization = await requireMcpAccessGrantAuthorization(c, routeDeps, workspaceId);
|
|
122336
123095
|
} catch (error) {
|
|
122337
|
-
if (deps.settings.mcpOauthEnabled && error instanceof
|
|
123096
|
+
if (deps.settings.mcpOauthEnabled && error instanceof HTTPException118 && error.status === 401) {
|
|
122338
123097
|
c.header(
|
|
122339
123098
|
"www-authenticate",
|
|
122340
123099
|
mcpOAuthAuthenticateHeader(routeDeps, new URL(c.req.url).pathname)
|
|
@@ -122355,10 +123114,10 @@ function createAppComposition(deps) {
|
|
|
122355
123114
|
});
|
|
122356
123115
|
} catch (error) {
|
|
122357
123116
|
if (error instanceof SessionAuthorizationDeniedError18) {
|
|
122358
|
-
throw new
|
|
123117
|
+
throw new HTTPException118(404, { message: "session not found" });
|
|
122359
123118
|
}
|
|
122360
123119
|
if (error instanceof SessionAuthorizationUnavailableError16) {
|
|
122361
|
-
throw new
|
|
123120
|
+
throw new HTTPException118(503, {
|
|
122362
123121
|
message: "session authorization is unavailable"
|
|
122363
123122
|
});
|
|
122364
123123
|
}
|
|
@@ -122440,7 +123199,7 @@ function createAppComposition(deps) {
|
|
|
122440
123199
|
const grant = authorization.grant;
|
|
122441
123200
|
const parsed = ToolGatewayCallRequest2.safeParse(await c.req.json().catch(() => null));
|
|
122442
123201
|
if (!parsed.success) {
|
|
122443
|
-
throw new
|
|
123202
|
+
throw new HTTPException118(400, { message: "Invalid tool gateway call" });
|
|
122444
123203
|
}
|
|
122445
123204
|
const prepared = await prepareWorkspaceToolGateway(routeDeps, authorization);
|
|
122446
123205
|
try {
|
|
@@ -122468,7 +123227,7 @@ function createAppComposition(deps) {
|
|
|
122468
123227
|
);
|
|
122469
123228
|
const parsed = ToolGatewayApprovalRequest2.safeParse(await c.req.json().catch(() => null));
|
|
122470
123229
|
if (!parsed.success) {
|
|
122471
|
-
throw new
|
|
123230
|
+
throw new HTTPException118(400, { message: "Invalid tool gateway approval" });
|
|
122472
123231
|
}
|
|
122473
123232
|
const prepared = await prepareWorkspaceToolGateway(routeDeps, authorization);
|
|
122474
123233
|
try {
|
|
@@ -122505,7 +123264,7 @@ function createAppComposition(deps) {
|
|
|
122505
123264
|
});
|
|
122506
123265
|
app.all("/v1/workspaces/:workspaceId/codemode/sdk/*", async (c) => {
|
|
122507
123266
|
const workspaceId = c.req.param("workspaceId");
|
|
122508
|
-
const grant = await
|
|
123267
|
+
const grant = await requireAccessGrant54(c, routeDeps, workspaceId);
|
|
122509
123268
|
const url = new URL(c.req.url);
|
|
122510
123269
|
const prefix2 = `/v1/workspaces/${workspaceId}/codemode/sdk`;
|
|
122511
123270
|
let forwarded;
|
|
@@ -122523,9 +123282,9 @@ function createAppComposition(deps) {
|
|
|
122523
123282
|
});
|
|
122524
123283
|
app.get("/v1/workspaces/:workspaceId/codemode/catalog", async (c) => {
|
|
122525
123284
|
const workspaceId = c.req.param("workspaceId");
|
|
122526
|
-
const grant = await
|
|
123285
|
+
const grant = await requireAccessGrant54(c, routeDeps, workspaceId);
|
|
122527
123286
|
if (!isCodemodeGrant(grant)) {
|
|
122528
|
-
throw new
|
|
123287
|
+
throw new HTTPException118(403, { message: "Codemode access denied" });
|
|
122529
123288
|
}
|
|
122530
123289
|
try {
|
|
122531
123290
|
return c.json((await requireActiveCodemodeCatalog(routeDeps, grant)).catalog);
|
|
@@ -122535,13 +123294,13 @@ function createAppComposition(deps) {
|
|
|
122535
123294
|
});
|
|
122536
123295
|
app.post("/v1/workspaces/:workspaceId/codemode/calls", async (c) => {
|
|
122537
123296
|
const workspaceId = c.req.param("workspaceId");
|
|
122538
|
-
const grant = await
|
|
123297
|
+
const grant = await requireAccessGrant54(c, routeDeps, workspaceId);
|
|
122539
123298
|
if (!isCodemodeGrant(grant)) {
|
|
122540
|
-
throw new
|
|
123299
|
+
throw new HTTPException118(403, { message: "Codemode access denied" });
|
|
122541
123300
|
}
|
|
122542
123301
|
const parsed = CodemodeCallRequest2.safeParse(await c.req.json().catch(() => null));
|
|
122543
123302
|
if (!parsed.success) {
|
|
122544
|
-
throw new
|
|
123303
|
+
throw new HTTPException118(400, { message: "Invalid Codemode call" });
|
|
122545
123304
|
}
|
|
122546
123305
|
try {
|
|
122547
123306
|
const submission = await submitAndDispatchCodemodeCall(routeDeps, grant, parsed.data);
|
|
@@ -122555,19 +123314,21 @@ function createAppComposition(deps) {
|
|
|
122555
123314
|
});
|
|
122556
123315
|
app.get("/v1/workspaces/:workspaceId/codemode/calls/:operationId", async (c) => {
|
|
122557
123316
|
const workspaceId = c.req.param("workspaceId");
|
|
122558
|
-
const grant = await
|
|
123317
|
+
const grant = await requireAccessGrant54(c, routeDeps, workspaceId);
|
|
122559
123318
|
if (!isCodemodeGrant(grant)) {
|
|
122560
|
-
throw new
|
|
123319
|
+
throw new HTTPException118(403, { message: "Codemode access denied" });
|
|
122561
123320
|
}
|
|
122562
123321
|
try {
|
|
122563
|
-
const operation = await readCodemodeOperation(routeDeps, grant, c.req.param("operationId")
|
|
123322
|
+
const operation = await readCodemodeOperation(routeDeps, grant, c.req.param("operationId"), {
|
|
123323
|
+
durableApproval: c.req.header("x-opengeni-codemode-capabilities") === "durable-approval-v1"
|
|
123324
|
+
});
|
|
122564
123325
|
if (!operation)
|
|
122565
|
-
throw new
|
|
123326
|
+
throw new HTTPException118(404, {
|
|
122566
123327
|
message: "Codemode operation not found"
|
|
122567
123328
|
});
|
|
122568
123329
|
return c.json(operation);
|
|
122569
123330
|
} catch (error) {
|
|
122570
|
-
if (error instanceof
|
|
123331
|
+
if (error instanceof HTTPException118) throw error;
|
|
122571
123332
|
throw codemodeHttpError(error);
|
|
122572
123333
|
}
|
|
122573
123334
|
});
|
|
@@ -122595,6 +123356,7 @@ function createAppComposition(deps) {
|
|
|
122595
123356
|
registerCompanyProfileRoutes(app, routeDeps);
|
|
122596
123357
|
registerCompanyBrainRoutes(app, routeDeps);
|
|
122597
123358
|
registerSlackTaskPolicyRoutes(app, routeDeps);
|
|
123359
|
+
registerSlackBotAccessRoutes(app, routeDeps);
|
|
122598
123360
|
registerWorkspaceStateRoutes(app, routeDeps);
|
|
122599
123361
|
registerMemorySlackPublicationRoutes(app, routeDeps);
|
|
122600
123362
|
registerWorkspaceArtifactRoutes(app, routeDeps);
|
|
@@ -122666,7 +123428,7 @@ function createAppComposition(deps) {
|
|
|
122666
123428
|
}
|
|
122667
123429
|
const importErrorResponse = archivedSessionImportErrorResponse(c, rawError);
|
|
122668
123430
|
if (importErrorResponse) return importErrorResponse;
|
|
122669
|
-
const error = rawError instanceof OrganizationIntegrationDeniedError4 ? new
|
|
123431
|
+
const error = rawError instanceof OrganizationIntegrationDeniedError4 ? new HTTPException118(403, { message: rawError.message }) : allowanceExhaustedHttpError(rawError) ?? workspaceControlBusyHttpError(rawError) ?? scheduledTaskTargetAccessHttpError(rawError) ?? agentConfigHttpError(rawError) ?? modelUnavailableHttpError(rawError) ?? (rawError instanceof UnsupportedLatencyModeError2 ? new ApiHttpError(422, {
|
|
122670
123432
|
code: "validation_failed",
|
|
122671
123433
|
message: rawError.message,
|
|
122672
123434
|
retryable: false,
|
|
@@ -122677,12 +123439,15 @@ function createAppComposition(deps) {
|
|
|
122677
123439
|
latencyMode: rawError.latencyMode,
|
|
122678
123440
|
allowedLatencyModes: [...rawError.allowedLatencyModes]
|
|
122679
123441
|
}
|
|
122680
|
-
}) : null) ?? requestBodyValidationHttpError(rawError) ?? invalidPathIdentifierHttpError(rawError, new URL(c.req.url).pathname) ?? rawError;
|
|
123442
|
+
}) : null) ?? requestBodyValidationHttpError(rawError) ?? invalidPathIdentifierHttpError(rawError, new URL(c.req.url).pathname) ?? databaseUnavailableHttpError(rawError, c.req.method) ?? rawError;
|
|
122681
123443
|
const compactionLock = codexCompactionV2ProviderLockedError(error);
|
|
122682
123444
|
const apiError = error instanceof ApiHttpError ? error : null;
|
|
122683
123445
|
const status = compactionLock ? 422 : httpStatusForError(error);
|
|
122684
123446
|
const code = compactionLock ? compactionLock.code : apiError?.code ?? errorCodeForStatus(status);
|
|
122685
123447
|
if (status >= 500) logHttpFailure(c, status, code, rawError);
|
|
123448
|
+
if (apiError?.details?.code === DATABASE_UNAVAILABLE_ERROR_DETAIL_CODE) {
|
|
123449
|
+
c.header("retry-after", "1");
|
|
123450
|
+
}
|
|
122686
123451
|
const envelope = ErrorEnvelope.parse({
|
|
122687
123452
|
error: {
|
|
122688
123453
|
status,
|
|
@@ -122704,7 +123469,7 @@ function managedAuthOAuthCallbackProvider(pathname) {
|
|
|
122704
123469
|
}
|
|
122705
123470
|
function mutationOutcomeUnknown(error, method) {
|
|
122706
123471
|
if (method === "GET" || method === "HEAD" || method === "OPTIONS") return false;
|
|
122707
|
-
const cause = error instanceof
|
|
123472
|
+
const cause = error instanceof HTTPException118 ? error.cause : error;
|
|
122708
123473
|
return cause instanceof BrowserControlTransportError5 || cause instanceof BrowserControlProtocolError3;
|
|
122709
123474
|
}
|
|
122710
123475
|
function appendVary(current, value) {
|
|
@@ -122740,7 +123505,7 @@ function workspaceRequestRequiresCodexAccountPrevalidation(request) {
|
|
|
122740
123505
|
async function validateCodexAccountTarget(request) {
|
|
122741
123506
|
const body3 = await request.clone().json().catch(() => null);
|
|
122742
123507
|
if (typeof body3?.target !== "string" || body3.target.length === 0) {
|
|
122743
|
-
throw new
|
|
123508
|
+
throw new HTTPException118(400, {
|
|
122744
123509
|
message: 'target is required ("auto" or an account id)'
|
|
122745
123510
|
});
|
|
122746
123511
|
}
|
|
@@ -122895,23 +123660,23 @@ function assertConfiguredCodemodeSessionProxyPath(session, path, method) {
|
|
|
122895
123660
|
}
|
|
122896
123661
|
}
|
|
122897
123662
|
if (!allowed2) {
|
|
122898
|
-
throw new
|
|
123663
|
+
throw new HTTPException118(403, {
|
|
122899
123664
|
message: "Agent configuration does not allow this Codemode SDK operation"
|
|
122900
123665
|
});
|
|
122901
123666
|
}
|
|
122902
123667
|
}
|
|
122903
123668
|
function codemodeHttpError(error) {
|
|
122904
123669
|
if (error instanceof SiteSessionPathError) {
|
|
122905
|
-
return new
|
|
123670
|
+
return new HTTPException118(404, { message: error.message, cause: error });
|
|
122906
123671
|
}
|
|
122907
123672
|
if (error instanceof SessionAuthorizationDeniedError18) {
|
|
122908
|
-
return new
|
|
123673
|
+
return new HTTPException118(404, {
|
|
122909
123674
|
message: "session not found",
|
|
122910
123675
|
cause: error
|
|
122911
123676
|
});
|
|
122912
123677
|
}
|
|
122913
123678
|
if (error instanceof SessionAuthorizationUnavailableError16) {
|
|
122914
|
-
return new
|
|
123679
|
+
return new HTTPException118(503, {
|
|
122915
123680
|
message: "session authorization is unavailable",
|
|
122916
123681
|
cause: error
|
|
122917
123682
|
});
|
|
@@ -122944,21 +123709,24 @@ function codemodeHttpError(error) {
|
|
|
122944
123709
|
});
|
|
122945
123710
|
}
|
|
122946
123711
|
if (error instanceof CodemodeOperationNotExecutableError) {
|
|
122947
|
-
return new
|
|
123712
|
+
return new HTTPException118(409, { message: error.message, cause: error });
|
|
122948
123713
|
}
|
|
122949
123714
|
if (error instanceof CodemodeOperationConflictError) {
|
|
122950
|
-
return new
|
|
123715
|
+
return new HTTPException118(409, { message: error.message, cause: error });
|
|
122951
123716
|
}
|
|
122952
123717
|
if (error instanceof CodemodeToolNotInCatalogError) {
|
|
122953
|
-
return new
|
|
123718
|
+
return new HTTPException118(404, { message: error.message, cause: error });
|
|
122954
123719
|
}
|
|
122955
|
-
if (error instanceof
|
|
122956
|
-
return new
|
|
123720
|
+
if (error instanceof CodemodeToolApprovalRequiredError2) {
|
|
123721
|
+
return new HTTPException118(409, { message: error.message, cause: error });
|
|
122957
123722
|
}
|
|
122958
123723
|
if (error instanceof CodemodePayloadTooLargeError) {
|
|
122959
|
-
return new
|
|
123724
|
+
return new HTTPException118(413, { message: error.message, cause: error });
|
|
123725
|
+
}
|
|
123726
|
+
if (error instanceof CodemodeOperationLimitError) {
|
|
123727
|
+
return new HTTPException118(429, { message: error.message, cause: error });
|
|
122960
123728
|
}
|
|
122961
|
-
return error instanceof
|
|
123729
|
+
return error instanceof HTTPException118 ? error : new HTTPException118(500, {
|
|
122962
123730
|
message: "Codemode request failed",
|
|
122963
123731
|
cause: error
|
|
122964
123732
|
});
|
|
@@ -122993,7 +123761,7 @@ function structuredServicesHint(backend) {
|
|
|
122993
123761
|
}
|
|
122994
123762
|
function codexCompactionV2ProviderLockedError(error) {
|
|
122995
123763
|
if (error instanceof CodexCompactionV2ProviderLockedError) return error;
|
|
122996
|
-
if (error instanceof
|
|
123764
|
+
if (error instanceof HTTPException118 && error.cause instanceof CodexCompactionV2ProviderLockedError) {
|
|
122997
123765
|
return error.cause;
|
|
122998
123766
|
}
|
|
122999
123767
|
return null;
|
|
@@ -123010,7 +123778,7 @@ function httpStatusForError(error) {
|
|
|
123010
123778
|
if (isRequestBodyValidationError(error)) {
|
|
123011
123779
|
return 400;
|
|
123012
123780
|
}
|
|
123013
|
-
if (error instanceof
|
|
123781
|
+
if (error instanceof HTTPException118) {
|
|
123014
123782
|
return error.status;
|
|
123015
123783
|
}
|
|
123016
123784
|
if (error instanceof McpPayloadTooLargeError) {
|
|
@@ -123042,7 +123810,7 @@ function publicErrorMessage(error, status) {
|
|
|
123042
123810
|
if (status >= 500) {
|
|
123043
123811
|
return "Opengeni could not complete the request.";
|
|
123044
123812
|
}
|
|
123045
|
-
if (error instanceof
|
|
123813
|
+
if (error instanceof HTTPException118) {
|
|
123046
123814
|
return boundedPublicMessage(error.message) ?? "Request failed.";
|
|
123047
123815
|
}
|
|
123048
123816
|
if (error instanceof McpPayloadTooLargeError) {
|
|
@@ -124137,4 +124905,4 @@ export {
|
|
|
124137
124905
|
withDefaultEnabledCapabilityMcpTools,
|
|
124138
124906
|
workflowIdForSession4 as workflowIdForSession
|
|
124139
124907
|
};
|
|
124140
|
-
//# sourceMappingURL=chunk-
|
|
124908
|
+
//# sourceMappingURL=chunk-IZEGLLKZ.js.map
|