@opengeni/api-router 2.13.0-canary.2 → 3.0.0-canary.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/artifact-catalog-cursor.d.ts +27 -0
- package/dist/{chunk-K2NU4KRK.js → chunk-7IAWEYBH.js} +567 -269
- package/dist/{chunk-K2NU4KRK.js.map → chunk-7IAWEYBH.js.map} +1 -1
- package/dist/index.js +1 -1
- package/dist/routes/artifact-catalog.d.ts +6 -0
- package/dist/routes/editable-artifacts.d.ts +2 -0
- package/dist/sandbox-file-artifacts.d.ts +19 -0
- package/package.json +19 -19
- package/src/app.ts +2 -0
- package/src/artifact-catalog-cursor.ts +60 -0
- package/src/integrations/api-integrations.ts +17 -4
- package/src/mcp/knowledge-entries.ts +2 -2
- package/src/routes/artifact-catalog.ts +279 -0
- package/src/routes/editable-artifacts.ts +2 -2
- package/src/sandbox-file-artifacts.ts +9 -2
|
@@ -3557,7 +3557,7 @@ import { bodyLimit } from "hono/body-limit";
|
|
|
3557
3557
|
import { compress } from "hono/compress";
|
|
3558
3558
|
import { cors } from "hono/cors";
|
|
3559
3559
|
import { getCookie as getCookie2 } from "hono/cookie";
|
|
3560
|
-
import { HTTPException as
|
|
3560
|
+
import { HTTPException as HTTPException97 } from "hono/http-exception";
|
|
3561
3561
|
|
|
3562
3562
|
// src/http/api-error.ts
|
|
3563
3563
|
import { WorkspaceControlBusyError } from "@opengeni/db";
|
|
@@ -3592,17 +3592,17 @@ function workspaceControlBusyHttpError(error) {
|
|
|
3592
3592
|
import {
|
|
3593
3593
|
CodexCompactionV2ProviderLockedError,
|
|
3594
3594
|
ManagedAuthActorLeaseOutcomeUnknownError,
|
|
3595
|
-
hasPermission as
|
|
3595
|
+
hasPermission as hasPermission25,
|
|
3596
3596
|
requireAccessGrant as requireAccessGrant47,
|
|
3597
|
-
requireAccessGrantAuthorization as
|
|
3597
|
+
requireAccessGrantAuthorization as requireAccessGrantAuthorization37,
|
|
3598
3598
|
requirePermission as requirePermission9,
|
|
3599
3599
|
releaseManagedAuthRequestActorLease,
|
|
3600
3600
|
resolveCatalogSettings,
|
|
3601
3601
|
resolveWorkspaceCatalogSettings as resolveWorkspaceCatalogSettings10,
|
|
3602
3602
|
validateManagedAuthRequestActorLease,
|
|
3603
|
-
requireSessionAuthorization as
|
|
3604
|
-
SessionAuthorizationDeniedError as
|
|
3605
|
-
SessionAuthorizationUnavailableError as
|
|
3603
|
+
requireSessionAuthorization as requireSessionAuthorization16,
|
|
3604
|
+
SessionAuthorizationDeniedError as SessionAuthorizationDeniedError17,
|
|
3605
|
+
SessionAuthorizationUnavailableError as SessionAuthorizationUnavailableError15
|
|
3606
3606
|
} from "@opengeni/core";
|
|
3607
3607
|
|
|
3608
3608
|
// src/auth/managed-auth.ts
|
|
@@ -6221,7 +6221,7 @@ function registerKnowledgeEntryTools(server, deps, grant, sessionId) {
|
|
|
6221
6221
|
return { content: [{ type: "text", text: JSON.stringify(result) }] };
|
|
6222
6222
|
} catch (error) {
|
|
6223
6223
|
const state = nestedPostgresSqlState2(error);
|
|
6224
|
-
const message = surface === "instruction" ? state === "40001" ? "This instruction changed. Read its current content and baseline, then retry the same intended edit against that exact state." : state === "23505" ? "This instruction operation ID was already used with different input. Reuse it only for an exact retry." : state === "42501" ? "The instruction change is unavailable in this task's scope or Agent learning policy. Off disables authoring, not the task. Do not ask for approval to continue." : state === "22023" || state === "23514" ? "Invalid instruction change. Read the current instruction, use append for a new rule, edit with one exact oldText match to update or remove text
|
|
6224
|
+
const message = surface === "instruction" ? state === "40001" ? "This instruction changed. Read its current content and baseline, then retry the same intended edit against that exact state." : state === "23505" ? "This instruction operation ID was already used with different input. Reuse it only for an exact retry." : state === "42501" ? "The instruction change is unavailable in this task's scope or Agent learning policy. Off disables authoring, not the task. Do not ask for approval to continue." : state === "22023" || state === "23514" ? "Invalid instruction change. Read the current instruction, use append for a new rule, or edit with one localized exact oldText match to update or remove text. Agents cannot replace the complete instruction. The resulting instruction must stay within 600 characters." : "Workspace instructions are temporarily unavailable. Retry the same operation ID only if the prior change may have succeeded." : state === "40001" ? "This entry changed. Read its current revision and retry your correction with the current version." : state === "23505" ? "This operation ID was already used with different input. Reuse it only for an exact retry." : state === "42501" ? "The entry, reference, or write is unavailable in this task's scope and Agent learning policy. Off disables saving, not your task. Do not ask for an approval to continue." : state === "22023" || state === "23514" ? "Invalid Knowledge entry or relationship. Check the referenced IDs and revision before retrying." : "Knowledge is temporarily unavailable. Your task can continue; retry the same operation ID if saving may have succeeded.";
|
|
6225
6225
|
return {
|
|
6226
6226
|
isError: true,
|
|
6227
6227
|
content: [
|
|
@@ -6380,7 +6380,7 @@ function registerKnowledgeEntryTools(server, deps, grant, sessionId) {
|
|
|
6380
6380
|
server.registerTool(
|
|
6381
6381
|
"instruction_policy_save",
|
|
6382
6382
|
{
|
|
6383
|
-
description: "Change a concise standing workspace instruction through this task's Agent learning policy. Read the current policy first and submit its exact baseline. Use editMode=append by default for a new rule; it preserves the current content and adds one blank-line separator. Use edit with oldText that occurs exactly once and newText to update or remove
|
|
6383
|
+
description: "Change a concise standing workspace instruction through this task's Agent learning policy. Read the current policy first and submit its exact baseline. Use editMode=append by default for a new rule; it preserves the current content and adds one blank-line separator. Use edit with a localized oldText that occurs exactly once and newText to update or remove only that passage. Agents cannot replace the complete instruction; direct the user to the manual workspace-instruction editor for a whole-policy rewrite. Each supplied text and the resulting instruction are limited to 600 characters. Facts and incidents belong in knowledge_save and reusable procedures in skill_save. Review first saves an inactive revision and returns pending; continue the task without an approval question.",
|
|
6384
6384
|
inputSchema: AgentInstructionSaveRequest.shape
|
|
6385
6385
|
},
|
|
6386
6386
|
(input) => run((context) => saveAgentInstruction(deps.db, context, input), "instruction")
|
|
@@ -6664,6 +6664,7 @@ import {
|
|
|
6664
6664
|
prepareGeneratedWorkspaceFile,
|
|
6665
6665
|
getSessionAuthorityProjection,
|
|
6666
6666
|
requireWorkspace as requireWorkspace2,
|
|
6667
|
+
recordSandboxFilePublication,
|
|
6667
6668
|
withSessionRlsActorContext as withSessionRlsActorContext5
|
|
6668
6669
|
} from "@opengeni/db";
|
|
6669
6670
|
import { retryWhileMissing as retryWhileMissing3 } from "@opengeni/storage";
|
|
@@ -10343,6 +10344,12 @@ async function publishSandboxFileArtifactInScope(deps, input) {
|
|
|
10343
10344
|
if (!artifact) {
|
|
10344
10345
|
throw new HTTPException12(502, { message: "published sandbox artifact is not ready" });
|
|
10345
10346
|
}
|
|
10347
|
+
await recordSandboxFilePublication(deps.db, {
|
|
10348
|
+
accountId: input.grant.accountId,
|
|
10349
|
+
workspaceId: input.grant.workspaceId,
|
|
10350
|
+
fileId: file.id,
|
|
10351
|
+
sourceSessionId: input.session.id
|
|
10352
|
+
});
|
|
10346
10353
|
return SandboxFileArtifactReceipt.parse({
|
|
10347
10354
|
type: "sandbox_file",
|
|
10348
10355
|
sandboxPath: `/workspace/${path}`,
|
|
@@ -17864,7 +17871,7 @@ function parseSlackReactionContextCheckpoint(value, expectedBinding, key, nowMs
|
|
|
17864
17871
|
(message) => seenMessageTimestamps.indexOf(message.timestamp)
|
|
17865
17872
|
);
|
|
17866
17873
|
if (seenMessageTimestamps.length > 0 && messages.length === 0 || messages.length > 0 && threadTimestamp === null || messages.length > 0 && messages[0].timestamp !== seenMessageTimestamps[0] || seenTimestampIndexes.some(
|
|
17867
|
-
(index,
|
|
17874
|
+
(index, position2) => index < 0 || position2 > 0 && index <= seenTimestampIndexes[position2 - 1]
|
|
17868
17875
|
)) {
|
|
17869
17876
|
throw new SlackBotProviderError("reaction_checkpoint_invalid");
|
|
17870
17877
|
}
|
|
@@ -62833,12 +62840,12 @@ import {
|
|
|
62833
62840
|
filterOpenApiDocumentForDefinition,
|
|
62834
62841
|
googleDiscoveryToOpenApi,
|
|
62835
62842
|
integrationDefinitionById as integrationDefinitionById2,
|
|
62836
|
-
parseOpenApiDocument
|
|
62843
|
+
parseOpenApiDocument,
|
|
62844
|
+
MAX_CURATED_INTEGRATION_SPEC_BYTES
|
|
62837
62845
|
} from "@opengeni/capabilities";
|
|
62838
62846
|
import {
|
|
62839
62847
|
ApiIntegrationPreview
|
|
62840
62848
|
} from "@opengeni/contracts";
|
|
62841
|
-
var MAX_CURATED_DEFINITION_SOURCE_BYTES = 64 * 1024 * 1024;
|
|
62842
62849
|
async function resolveApiIntegrationPreview(input) {
|
|
62843
62850
|
if (input.source.kind === "definition") {
|
|
62844
62851
|
return await resolveDefinition(input);
|
|
@@ -62876,20 +62883,26 @@ async function resolveDefinition(input) {
|
|
|
62876
62883
|
const bytes = await fetchIntegrationSourceDocument(
|
|
62877
62884
|
input.transport,
|
|
62878
62885
|
definition.source.url,
|
|
62879
|
-
|
|
62886
|
+
MAX_CURATED_INTEGRATION_SPEC_BYTES
|
|
62880
62887
|
);
|
|
62881
62888
|
let document;
|
|
62882
62889
|
if (definition.source.kind === "google_discovery") {
|
|
62883
62890
|
document = googleDiscoveryToOpenApi(JSON.parse(new TextDecoder().decode(bytes)));
|
|
62884
62891
|
} else {
|
|
62885
|
-
document = filterOpenApiDocumentForDefinition(
|
|
62892
|
+
document = filterOpenApiDocumentForDefinition(
|
|
62893
|
+
parseOpenApiDocument(bytes, {
|
|
62894
|
+
maxBytes: MAX_CURATED_INTEGRATION_SPEC_BYTES
|
|
62895
|
+
}),
|
|
62896
|
+
definition
|
|
62897
|
+
);
|
|
62886
62898
|
}
|
|
62887
62899
|
const identity = integrationInstallationIdentity("openapi", definition.id, definition.source.url);
|
|
62888
62900
|
const revision = compileOpenApiRevision(document, {
|
|
62889
62901
|
definitionId: definition.id,
|
|
62890
62902
|
sourceUrl: definition.source.url,
|
|
62891
62903
|
baseUrl: definition.baseUrl,
|
|
62892
|
-
provider: definition.provider.id
|
|
62904
|
+
provider: definition.provider.id,
|
|
62905
|
+
...definition.source.kind === "openapi" && definition.source.schemaMode ? { schemaMode: definition.source.schemaMode } : {}
|
|
62893
62906
|
});
|
|
62894
62907
|
const baseUrl = firstOpenApiServerUrl(revision);
|
|
62895
62908
|
const providerDomain = definition.provider.domain;
|
|
@@ -62990,6 +63003,9 @@ async function resolveGraphql(input, endpoint, name) {
|
|
|
62990
63003
|
});
|
|
62991
63004
|
}
|
|
62992
63005
|
function resolvedPreview(input) {
|
|
63006
|
+
if (Buffer.byteLength(JSON.stringify(input.revision, null, 2), "utf8") > 4 * 1024 * 1024) {
|
|
63007
|
+
throw new Error("Compiled integration exceeds the supported 4 MiB storage limit");
|
|
63008
|
+
}
|
|
62993
63009
|
const deprecated = input.revision.tools.filter((tool) => tool.deprecated).length;
|
|
62994
63010
|
const warnings = [
|
|
62995
63011
|
...deprecated > 0 ? [`${deprecated} deprecated operation${deprecated === 1 ? "" : "s"} will not be enabled.`] : [],
|
|
@@ -93981,6 +93997,287 @@ function registerWorkspaceArtifactRoutes(app, deps) {
|
|
|
93981
93997
|
});
|
|
93982
93998
|
}
|
|
93983
93999
|
|
|
94000
|
+
// src/routes/artifact-catalog.ts
|
|
94001
|
+
import { resolveFirstPartyDelegationSecret as resolveFirstPartyDelegationSecret5 } from "@opengeni/config";
|
|
94002
|
+
import {
|
|
94003
|
+
ArtifactCatalogItem,
|
|
94004
|
+
ArtifactCatalogKind as ArtifactCatalogKind2,
|
|
94005
|
+
ArtifactCatalogListQuery,
|
|
94006
|
+
ArtifactCatalogListResponse,
|
|
94007
|
+
retainedArtifactReferenceFromFile as retainedArtifactReferenceFromFile3,
|
|
94008
|
+
retainedGeneratedImageReferenceFromFile as retainedGeneratedImageReferenceFromFile2
|
|
94009
|
+
} from "@opengeni/contracts";
|
|
94010
|
+
import {
|
|
94011
|
+
editableArtifactId as editableArtifactId3,
|
|
94012
|
+
editableArtifactScope as editableArtifactScope2,
|
|
94013
|
+
fileOwnerContextForAccess as fileOwnerContextForAccess5,
|
|
94014
|
+
grantHasAgentAttemptAuthority as grantHasAgentAttemptAuthority4,
|
|
94015
|
+
hasPermission as hasPermission21,
|
|
94016
|
+
requireAccessGrantAuthorization as requireAccessGrantAuthorization32,
|
|
94017
|
+
requireLiveAgentAttemptAuthorization as requireLiveAgentAttemptAuthorization5,
|
|
94018
|
+
requireSessionAuthorization as requireSessionAuthorization14,
|
|
94019
|
+
SessionAuthorizationDeniedError as SessionAuthorizationDeniedError13,
|
|
94020
|
+
SessionAuthorizationUnavailableError as SessionAuthorizationUnavailableError11
|
|
94021
|
+
} from "@opengeni/core";
|
|
94022
|
+
import {
|
|
94023
|
+
getFilesForSubject as getFilesForSubject3,
|
|
94024
|
+
getGeneratedImageArtifact as getGeneratedImageArtifact2,
|
|
94025
|
+
getSessionAuthorityProjection as getSessionAuthorityProjection3,
|
|
94026
|
+
listArtifactCatalogCandidates,
|
|
94027
|
+
withSessionRlsActorContext as withSessionRlsActorContext7
|
|
94028
|
+
} from "@opengeni/db";
|
|
94029
|
+
import { HTTPException as HTTPException84 } from "hono/http-exception";
|
|
94030
|
+
|
|
94031
|
+
// src/artifact-catalog-cursor.ts
|
|
94032
|
+
import { createCipheriv as createCipheriv3, createDecipheriv as createDecipheriv3, createHash as createHash27, randomBytes as randomBytes11 } from "crypto";
|
|
94033
|
+
import { ArtifactCatalogKind } from "@opengeni/contracts";
|
|
94034
|
+
import { HTTPException as HTTPException83 } from "hono/http-exception";
|
|
94035
|
+
import { z as z33 } from "zod";
|
|
94036
|
+
var Cursor = z33.object({
|
|
94037
|
+
version: z33.literal(1),
|
|
94038
|
+
snapshotAt: z33.string().datetime(),
|
|
94039
|
+
expiresAt: z33.number().int().positive(),
|
|
94040
|
+
after: z33.object({
|
|
94041
|
+
key: z33.string().max(4096),
|
|
94042
|
+
kind: ArtifactCatalogKind,
|
|
94043
|
+
id: z33.string().min(1).max(128)
|
|
94044
|
+
}).strict()
|
|
94045
|
+
}).strict();
|
|
94046
|
+
function artifactCatalogCursorCodec(secret, binding) {
|
|
94047
|
+
const key = createHash27("sha256").update("opengeni:artifact-catalog:v1\0").update(secret).digest();
|
|
94048
|
+
const aad = createHash27("sha256").update(binding).digest();
|
|
94049
|
+
return {
|
|
94050
|
+
encode(value) {
|
|
94051
|
+
const iv = randomBytes11(12);
|
|
94052
|
+
const cipher = createCipheriv3("aes-256-gcm", key, iv);
|
|
94053
|
+
cipher.setAAD(aad);
|
|
94054
|
+
const bytes = Buffer.concat([
|
|
94055
|
+
cipher.update(JSON.stringify(Cursor.parse(value)), "utf8"),
|
|
94056
|
+
cipher.final()
|
|
94057
|
+
]);
|
|
94058
|
+
return Buffer.concat([iv, cipher.getAuthTag(), bytes]).toString("base64url");
|
|
94059
|
+
},
|
|
94060
|
+
decode(value) {
|
|
94061
|
+
try {
|
|
94062
|
+
if (value.length > 8192 || !/^[A-Za-z0-9_-]+$/.test(value)) throw new Error();
|
|
94063
|
+
const bytes = Buffer.from(value, "base64url");
|
|
94064
|
+
if (bytes.length < 29 || bytes.toString("base64url") !== value) throw new Error();
|
|
94065
|
+
const decipher = createDecipheriv3("aes-256-gcm", key, bytes.subarray(0, 12));
|
|
94066
|
+
decipher.setAAD(aad);
|
|
94067
|
+
decipher.setAuthTag(bytes.subarray(12, 28));
|
|
94068
|
+
const parsed = Cursor.parse(
|
|
94069
|
+
JSON.parse(
|
|
94070
|
+
Buffer.concat([decipher.update(bytes.subarray(28)), decipher.final()]).toString("utf8")
|
|
94071
|
+
)
|
|
94072
|
+
);
|
|
94073
|
+
if (parsed.expiresAt <= Date.now() || Date.parse(parsed.snapshotAt) > Date.now() + 6e4)
|
|
94074
|
+
throw new Error();
|
|
94075
|
+
return parsed;
|
|
94076
|
+
} catch {
|
|
94077
|
+
throw new HTTPException83(422, { message: "Invalid or expired artifact catalog cursor" });
|
|
94078
|
+
}
|
|
94079
|
+
}
|
|
94080
|
+
};
|
|
94081
|
+
}
|
|
94082
|
+
|
|
94083
|
+
// src/routes/artifact-catalog.ts
|
|
94084
|
+
var editableKinds = /* @__PURE__ */ new Set(["document", "spreadsheet", "presentation"]);
|
|
94085
|
+
var CANDIDATE_BATCH = 200;
|
|
94086
|
+
var MAX_BATCHES = 10;
|
|
94087
|
+
var iso = (value) => new Date(value).toISOString();
|
|
94088
|
+
var position = (row) => ({
|
|
94089
|
+
key: row.sort_key,
|
|
94090
|
+
kind: row.kind,
|
|
94091
|
+
id: row.id
|
|
94092
|
+
});
|
|
94093
|
+
function registerArtifactCatalogRoutes(app, deps) {
|
|
94094
|
+
app.get("/v1/workspaces/:workspaceId/artifact-catalog", async (context) => {
|
|
94095
|
+
const workspaceId = context.req.param("workspaceId");
|
|
94096
|
+
const authorization = await requireAccessGrantAuthorization32(context, deps, workspaceId);
|
|
94097
|
+
const grant = authorization.grant;
|
|
94098
|
+
const parsed = ArtifactCatalogListQuery.safeParse(context.req.query());
|
|
94099
|
+
if (!parsed.success)
|
|
94100
|
+
throw new HTTPException84(422, { message: "Invalid artifact catalog query" });
|
|
94101
|
+
const query = parsed.data;
|
|
94102
|
+
const artifactsAllowed = hasPermission21(grant.permissions, "artifacts:read");
|
|
94103
|
+
const filesAllowed = hasPermission21(grant.permissions, "files:read");
|
|
94104
|
+
if (!artifactsAllowed && !filesAllowed)
|
|
94105
|
+
throw new HTTPException84(403, { message: "Artifact catalog read access required" });
|
|
94106
|
+
let kinds = ArtifactCatalogKind2.options.filter(
|
|
94107
|
+
(kind) => (kind === "image" || kind === "file" ? filesAllowed : artifactsAllowed) && (!query.kind || kind === query.kind)
|
|
94108
|
+
);
|
|
94109
|
+
if (!deps.editableArtifacts) {
|
|
94110
|
+
if (query.kind && editableKinds.has(query.kind) && artifactsAllowed)
|
|
94111
|
+
throw new HTTPException84(503, { message: "Editable artifacts are unavailable" });
|
|
94112
|
+
kinds = kinds.filter((kind) => !editableKinds.has(kind));
|
|
94113
|
+
}
|
|
94114
|
+
const includesFiles = kinds.includes("file") || kinds.includes("image");
|
|
94115
|
+
const actor = includesFiles ? await fileOwnerContextForAccess5(deps, authorization, "files:read") : { subjectId: grant.subjectId, privateFileOwnerSubjectId: null };
|
|
94116
|
+
if (grantHasAgentAttemptAuthority4(grant) && actor.initiatingHumanSubjectId === void 0) {
|
|
94117
|
+
const callerSessionId = grant.metadata?.["sessionId"];
|
|
94118
|
+
try {
|
|
94119
|
+
if (typeof callerSessionId !== "string")
|
|
94120
|
+
throw new SessionAuthorizationDeniedError13("caller_stale");
|
|
94121
|
+
const attempt = await requireLiveAgentAttemptAuthorization5(deps.db, grant, callerSessionId);
|
|
94122
|
+
actor.initiatingHumanSubjectId = attempt.initiatingHumanSubjectId;
|
|
94123
|
+
} catch (error) {
|
|
94124
|
+
if (error instanceof SessionAuthorizationDeniedError13)
|
|
94125
|
+
throw new HTTPException84(404, { message: "Session not found", cause: error });
|
|
94126
|
+
throw error;
|
|
94127
|
+
}
|
|
94128
|
+
}
|
|
94129
|
+
const sourceDecisions = /* @__PURE__ */ new Map();
|
|
94130
|
+
const canReadSession = async (sessionId) => {
|
|
94131
|
+
if (!hasPermission21(grant.permissions, "sessions:read")) return false;
|
|
94132
|
+
if (sourceDecisions.has(sessionId)) return sourceDecisions.get(sessionId);
|
|
94133
|
+
try {
|
|
94134
|
+
await requireSessionAuthorization14(deps, grant, {
|
|
94135
|
+
sessionId,
|
|
94136
|
+
operation: "session.read",
|
|
94137
|
+
surface: "http"
|
|
94138
|
+
});
|
|
94139
|
+
if (!await getSessionAuthorityProjection3(deps.db, workspaceId, sessionId)) {
|
|
94140
|
+
sourceDecisions.set(sessionId, false);
|
|
94141
|
+
return false;
|
|
94142
|
+
}
|
|
94143
|
+
sourceDecisions.set(sessionId, true);
|
|
94144
|
+
return true;
|
|
94145
|
+
} catch (error) {
|
|
94146
|
+
if (error instanceof SessionAuthorizationDeniedError13) {
|
|
94147
|
+
sourceDecisions.set(sessionId, false);
|
|
94148
|
+
return false;
|
|
94149
|
+
}
|
|
94150
|
+
if (error instanceof SessionAuthorizationUnavailableError11)
|
|
94151
|
+
throw new HTTPException84(503, { message: "Session authorization is unavailable" });
|
|
94152
|
+
throw error;
|
|
94153
|
+
}
|
|
94154
|
+
};
|
|
94155
|
+
context.header("cache-control", "private, no-store");
|
|
94156
|
+
return withSessionRlsActorContext7(actor, async () => {
|
|
94157
|
+
if (query.sourceSessionId && !await canReadSession(query.sourceSessionId))
|
|
94158
|
+
throw new HTTPException84(404, { message: "Session not found" });
|
|
94159
|
+
const secret = resolveFirstPartyDelegationSecret5(deps.settings);
|
|
94160
|
+
if (!secret)
|
|
94161
|
+
throw new HTTPException84(503, { message: "Artifact catalog cursor signing is unavailable" });
|
|
94162
|
+
const filters = { ...query, cursor: void 0 };
|
|
94163
|
+
const codec = artifactCatalogCursorCodec(
|
|
94164
|
+
secret,
|
|
94165
|
+
JSON.stringify({
|
|
94166
|
+
accountId: grant.accountId,
|
|
94167
|
+
workspaceId,
|
|
94168
|
+
subjectId: grant.subjectId,
|
|
94169
|
+
principalKind: grant.principalKind,
|
|
94170
|
+
metadata: grant.metadata,
|
|
94171
|
+
permissions: [...grant.permissions].sort(),
|
|
94172
|
+
initiatingHumanSubjectId: actor.initiatingHumanSubjectId ?? null,
|
|
94173
|
+
owner: actor.privateFileOwnerSubjectId ?? null,
|
|
94174
|
+
kinds,
|
|
94175
|
+
filters
|
|
94176
|
+
})
|
|
94177
|
+
);
|
|
94178
|
+
const prior = query.cursor ? codec.decode(query.cursor) : void 0;
|
|
94179
|
+
const snapshotAt = prior?.snapshotAt ?? (/* @__PURE__ */ new Date()).toISOString();
|
|
94180
|
+
const expiresAt = prior?.expiresAt ?? Date.now() + 60 * 6e4;
|
|
94181
|
+
let after = prior?.after;
|
|
94182
|
+
const items = [];
|
|
94183
|
+
let lastReturned;
|
|
94184
|
+
let nextCursor = null;
|
|
94185
|
+
const fileSubject = includesFiles ? await fileAuthoritySubjectIdForGrant(deps, grant) : null;
|
|
94186
|
+
for (let batch = 0; batch < MAX_BATCHES; batch++) {
|
|
94187
|
+
const candidates = await listArtifactCatalogCandidates(
|
|
94188
|
+
deps.db,
|
|
94189
|
+
{ accountId: grant.accountId, workspaceId },
|
|
94190
|
+
{
|
|
94191
|
+
query,
|
|
94192
|
+
kinds,
|
|
94193
|
+
snapshotAt,
|
|
94194
|
+
...after ? { after } : {},
|
|
94195
|
+
limit: CANDIDATE_BATCH
|
|
94196
|
+
}
|
|
94197
|
+
);
|
|
94198
|
+
for (const candidate of candidates) {
|
|
94199
|
+
after = position(candidate);
|
|
94200
|
+
const item = await projectCandidate(deps, grant, candidate, fileSubject);
|
|
94201
|
+
if (!item || item.status !== query.status || query.q && !item.title.toLowerCase().includes(query.q.toLowerCase()))
|
|
94202
|
+
continue;
|
|
94203
|
+
if (items.length === query.limit) {
|
|
94204
|
+
nextCursor = codec.encode({ version: 1, snapshotAt, expiresAt, after: lastReturned });
|
|
94205
|
+
return context.json(ArtifactCatalogListResponse.parse({ items, nextCursor }));
|
|
94206
|
+
}
|
|
94207
|
+
if (candidate.source_session_id && await canReadSession(candidate.source_session_id))
|
|
94208
|
+
item.sourceSessionId = candidate.source_session_id;
|
|
94209
|
+
items.push(ArtifactCatalogItem.parse(item));
|
|
94210
|
+
lastReturned = after;
|
|
94211
|
+
}
|
|
94212
|
+
if (candidates.length < CANDIDATE_BATCH) break;
|
|
94213
|
+
if (batch === MAX_BATCHES - 1 && after)
|
|
94214
|
+
nextCursor = codec.encode({ version: 1, snapshotAt, expiresAt, after });
|
|
94215
|
+
}
|
|
94216
|
+
return context.json(ArtifactCatalogListResponse.parse({ items, nextCursor }));
|
|
94217
|
+
});
|
|
94218
|
+
});
|
|
94219
|
+
}
|
|
94220
|
+
async function projectCandidate(deps, grant, row, fileSubject) {
|
|
94221
|
+
const item = {
|
|
94222
|
+
id: row.id,
|
|
94223
|
+
kind: row.kind,
|
|
94224
|
+
title: row.title,
|
|
94225
|
+
status: row.status,
|
|
94226
|
+
createdAt: iso(row.created_at),
|
|
94227
|
+
updatedAt: iso(row.updated_at)
|
|
94228
|
+
};
|
|
94229
|
+
if (row.version_id) item.versionId = row.version_id;
|
|
94230
|
+
if (editableKinds.has(row.kind)) {
|
|
94231
|
+
const scope = editableArtifactScope2({
|
|
94232
|
+
accountId: grant.accountId,
|
|
94233
|
+
workspaceId: grant.workspaceId
|
|
94234
|
+
});
|
|
94235
|
+
try {
|
|
94236
|
+
const artifact = await deps.editableArtifacts.readArtifact({
|
|
94237
|
+
scope,
|
|
94238
|
+
actor: editableArtifactActorForGrant(grant, "0000000000000001"),
|
|
94239
|
+
artifactId: editableArtifactId3(row.id)
|
|
94240
|
+
});
|
|
94241
|
+
if (artifact.scope.accountId !== scope.accountId || artifact.scope.workspaceId !== scope.workspaceId || artifact.id !== row.id || artifact.modality !== row.kind)
|
|
94242
|
+
throw new Error("Artifact application returned mismatched catalog metadata");
|
|
94243
|
+
return {
|
|
94244
|
+
...item,
|
|
94245
|
+
title: artifact.title,
|
|
94246
|
+
status: artifact.lifecycle,
|
|
94247
|
+
createdAt: artifact.createdAt,
|
|
94248
|
+
updatedAt: artifact.updatedAt
|
|
94249
|
+
};
|
|
94250
|
+
} catch (error) {
|
|
94251
|
+
if (isInvisibleListCandidate(error)) return null;
|
|
94252
|
+
throw editableArtifactHttpError(error);
|
|
94253
|
+
}
|
|
94254
|
+
}
|
|
94255
|
+
if (row.kind === "file" || row.kind === "image") {
|
|
94256
|
+
const [file] = await getFilesForSubject3(deps.db, {
|
|
94257
|
+
accountId: grant.accountId,
|
|
94258
|
+
workspaceId: grant.workspaceId,
|
|
94259
|
+
subjectId: fileSubject,
|
|
94260
|
+
fileIds: [row.id]
|
|
94261
|
+
});
|
|
94262
|
+
if (!file || file.status !== "ready") return null;
|
|
94263
|
+
const generated = row.origin === "generated_image" ? await getGeneratedImageArtifact2(deps.db, grant.workspaceId, row.id) : null;
|
|
94264
|
+
const reference = row.origin === "generated_image" ? generated?.status === "ready" ? retainedGeneratedImageReferenceFromFile2({
|
|
94265
|
+
...file,
|
|
94266
|
+
width: generated.width,
|
|
94267
|
+
height: generated.height
|
|
94268
|
+
}) : null : retainedArtifactReferenceFromFile3(file, "file");
|
|
94269
|
+
if (!reference) return null;
|
|
94270
|
+
return {
|
|
94271
|
+
...item,
|
|
94272
|
+
file: reference,
|
|
94273
|
+
filename: file.filename,
|
|
94274
|
+
contentType: reference.contentType,
|
|
94275
|
+
sizeBytes: file.sizeBytes
|
|
94276
|
+
};
|
|
94277
|
+
}
|
|
94278
|
+
return item;
|
|
94279
|
+
}
|
|
94280
|
+
|
|
93984
94281
|
// src/routes/insights.ts
|
|
93985
94282
|
import { InsightsRange, WorkspaceInsightsResponse } from "@opengeni/contracts";
|
|
93986
94283
|
import {
|
|
@@ -93990,13 +94287,13 @@ import {
|
|
|
93990
94287
|
WorkspaceInsightsFilterValidationError
|
|
93991
94288
|
} from "@opengeni/core";
|
|
93992
94289
|
import { workspaceInsightsMetricObserver } from "@opengeni/observability";
|
|
93993
|
-
import { HTTPException as
|
|
94290
|
+
import { HTTPException as HTTPException85 } from "hono/http-exception";
|
|
93994
94291
|
function normalizeWorkspaceInsightsQueryFilter(value, field) {
|
|
93995
94292
|
try {
|
|
93996
94293
|
return normalizeWorkspaceInsightsFilter(value, field);
|
|
93997
94294
|
} catch (error) {
|
|
93998
94295
|
if (error instanceof WorkspaceInsightsFilterValidationError) {
|
|
93999
|
-
throw new
|
|
94296
|
+
throw new HTTPException85(400, { message: error.message });
|
|
94000
94297
|
}
|
|
94001
94298
|
throw error;
|
|
94002
94299
|
}
|
|
@@ -94016,7 +94313,7 @@ function registerInsightsRoutes(app, deps) {
|
|
|
94016
94313
|
await requireAccessGrant42(c, deps, workspaceId, "workspace:admin");
|
|
94017
94314
|
const rangeParsed = InsightsRange.safeParse(rangeRaw);
|
|
94018
94315
|
if (!rangeParsed.success) {
|
|
94019
|
-
throw new
|
|
94316
|
+
throw new HTTPException85(400, {
|
|
94020
94317
|
message: "range must be one of today|week|month|ytd"
|
|
94021
94318
|
});
|
|
94022
94319
|
}
|
|
@@ -94053,7 +94350,7 @@ import { requireAccessGrant as requireAccessGrant44, TranscriptionServiceError a
|
|
|
94053
94350
|
import { getWorkspace as getWorkspace5 } from "@opengeni/db";
|
|
94054
94351
|
|
|
94055
94352
|
// src/routes/transcription-recordings.ts
|
|
94056
|
-
import { createHash as
|
|
94353
|
+
import { createHash as createHash28 } from "crypto";
|
|
94057
94354
|
import {
|
|
94058
94355
|
CreateTranscriptionRecordingRequest,
|
|
94059
94356
|
FinalizeTranscriptionRecordingRequest,
|
|
@@ -94898,7 +95195,7 @@ function valueAsUuid(value) {
|
|
|
94898
95195
|
if (/^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i.test(value)) {
|
|
94899
95196
|
return value;
|
|
94900
95197
|
}
|
|
94901
|
-
const hex2 =
|
|
95198
|
+
const hex2 = createHash28("sha256").update(value).digest("hex").slice(0, 32);
|
|
94902
95199
|
return `${hex2.slice(0, 8)}-${hex2.slice(8, 12)}-4${hex2.slice(13, 16)}-a${hex2.slice(17, 20)}-${hex2.slice(20, 32)}`;
|
|
94903
95200
|
}
|
|
94904
95201
|
function nonnegativeInteger(value) {
|
|
@@ -94962,7 +95259,7 @@ async function readBoundedBody(request, maxBytes) {
|
|
|
94962
95259
|
return body4;
|
|
94963
95260
|
}
|
|
94964
95261
|
function sha256Hex3(bytes) {
|
|
94965
|
-
return
|
|
95262
|
+
return createHash28("sha256").update(bytes).digest("hex");
|
|
94966
95263
|
}
|
|
94967
95264
|
|
|
94968
95265
|
// src/routes/transcriptions.ts
|
|
@@ -95116,7 +95413,7 @@ import {
|
|
|
95116
95413
|
} from "@opengeni/contracts";
|
|
95117
95414
|
import {
|
|
95118
95415
|
getVideoGenerationOperationSummary,
|
|
95119
|
-
withSessionRlsActorContext as
|
|
95416
|
+
withSessionRlsActorContext as withSessionRlsActorContext8,
|
|
95120
95417
|
getWorkspaceVercelAiGatewayConnectionMetadata as getWorkspaceVercelAiGatewayConnectionMetadata2,
|
|
95121
95418
|
getWorkspaceVideoGenerationPolicy,
|
|
95122
95419
|
updateWorkspaceVideoGenerationPolicy,
|
|
@@ -95125,14 +95422,14 @@ import {
|
|
|
95125
95422
|
} from "@opengeni/db";
|
|
95126
95423
|
import {
|
|
95127
95424
|
requireAccessGrant as requireAccessGrant45,
|
|
95128
|
-
requireAccessGrantAuthorization as
|
|
95129
|
-
fileOwnerContextForAccess as
|
|
95425
|
+
requireAccessGrantAuthorization as requireAccessGrantAuthorization33,
|
|
95426
|
+
fileOwnerContextForAccess as fileOwnerContextForAccess6,
|
|
95130
95427
|
requireWorkspaceSettingsGrant as requireWorkspaceSettingsGrant4,
|
|
95131
95428
|
VIDEO_GENERATION_MODEL_CATALOG,
|
|
95132
95429
|
videoGenerationModelSupportsFundingSource,
|
|
95133
95430
|
videoGenerationCapabilitiesForPolicy
|
|
95134
95431
|
} from "@opengeni/core";
|
|
95135
|
-
import { HTTPException as
|
|
95432
|
+
import { HTTPException as HTTPException86 } from "hono/http-exception";
|
|
95136
95433
|
function registerVideoGenerationRoutes(app, deps) {
|
|
95137
95434
|
app.get("/v1/workspaces/:workspaceId/video-generation", async (c) => {
|
|
95138
95435
|
const workspaceId = c.req.param("workspaceId");
|
|
@@ -95179,14 +95476,14 @@ function registerVideoGenerationRoutes(app, deps) {
|
|
|
95179
95476
|
(option) => option.source === payload.fundingSource
|
|
95180
95477
|
);
|
|
95181
95478
|
if (payload.enabledModelIds.length > 0 && !selectedFunding?.available) {
|
|
95182
|
-
throw new
|
|
95479
|
+
throw new HTTPException86(422, {
|
|
95183
95480
|
message: selectedFunding?.unavailableReason ?? "Video generation funding is unavailable"
|
|
95184
95481
|
});
|
|
95185
95482
|
}
|
|
95186
95483
|
if (payload.enabledModelIds.some(
|
|
95187
95484
|
(modelId) => !videoGenerationModelSupportsFundingSource(modelId, payload.fundingSource)
|
|
95188
95485
|
)) {
|
|
95189
|
-
throw new
|
|
95486
|
+
throw new HTTPException86(422, {
|
|
95190
95487
|
message: "The selected video model is unavailable for this funding source"
|
|
95191
95488
|
});
|
|
95192
95489
|
}
|
|
@@ -95200,24 +95497,24 @@ function registerVideoGenerationRoutes(app, deps) {
|
|
|
95200
95497
|
return c.json(VideoGenerationPolicy.parse(policy));
|
|
95201
95498
|
} catch (error) {
|
|
95202
95499
|
if (error instanceof VideoGenerationConflictError) {
|
|
95203
|
-
throw new
|
|
95500
|
+
throw new HTTPException86(409, { message: error.message });
|
|
95204
95501
|
}
|
|
95205
95502
|
if (error instanceof Error && error.message.startsWith("Unknown video generation model:")) {
|
|
95206
|
-
throw new
|
|
95503
|
+
throw new HTTPException86(422, { message: error.message });
|
|
95207
95504
|
}
|
|
95208
95505
|
throw error;
|
|
95209
95506
|
}
|
|
95210
95507
|
});
|
|
95211
95508
|
app.get("/v1/workspaces/:workspaceId/video-generation/operations/:operationId", async (c) => {
|
|
95212
95509
|
const workspaceId = c.req.param("workspaceId");
|
|
95213
|
-
const access = await
|
|
95214
|
-
const actor = await
|
|
95215
|
-
const summary = await
|
|
95510
|
+
const access = await requireAccessGrantAuthorization33(c, deps, workspaceId, "workspace:read");
|
|
95511
|
+
const actor = await fileOwnerContextForAccess6(deps, access, "workspace:read");
|
|
95512
|
+
const summary = await withSessionRlsActorContext8(
|
|
95216
95513
|
actor,
|
|
95217
95514
|
() => getVideoGenerationOperationSummary(deps.db, workspaceId, c.req.param("operationId"))
|
|
95218
95515
|
);
|
|
95219
95516
|
if (!summary)
|
|
95220
|
-
throw new
|
|
95517
|
+
throw new HTTPException86(404, {
|
|
95221
95518
|
message: "video generation operation not found"
|
|
95222
95519
|
});
|
|
95223
95520
|
return c.json(VideoGenerationOperationSummary.parse(summary));
|
|
@@ -95274,9 +95571,9 @@ import {
|
|
|
95274
95571
|
CanonicalHumanIdentityMutationInFlightError,
|
|
95275
95572
|
getCanonicalHumanIdentityProjection as getCanonicalHumanIdentityProjection2
|
|
95276
95573
|
} from "@opengeni/db/canonical-human-identities";
|
|
95277
|
-
import { HTTPException as
|
|
95278
|
-
import { z as
|
|
95279
|
-
var BindingId =
|
|
95574
|
+
import { HTTPException as HTTPException87 } from "hono/http-exception";
|
|
95575
|
+
import { z as z34 } from "zod";
|
|
95576
|
+
var BindingId = z34.string().uuid();
|
|
95280
95577
|
async function requestIdentity(context, deps) {
|
|
95281
95578
|
return await requireCanonicalHumanRequestIdentity(context, {
|
|
95282
95579
|
db: deps.db,
|
|
@@ -95289,13 +95586,13 @@ async function requestIdentity(context, deps) {
|
|
|
95289
95586
|
async function parseBody5(context, schema) {
|
|
95290
95587
|
const parsed = schema.safeParse(await context.req.json().catch(() => null));
|
|
95291
95588
|
if (!parsed.success) {
|
|
95292
|
-
throw new
|
|
95589
|
+
throw new HTTPException87(422, { message: "Invalid canonical human identity request" });
|
|
95293
95590
|
}
|
|
95294
95591
|
return parsed.data;
|
|
95295
95592
|
}
|
|
95296
95593
|
function bindingId(context) {
|
|
95297
95594
|
const parsed = BindingId.safeParse(context.req.param("bindingId"));
|
|
95298
|
-
if (!parsed.success) throw new
|
|
95595
|
+
if (!parsed.success) throw new HTTPException87(422, { message: "Invalid login binding id" });
|
|
95299
95596
|
return parsed.data;
|
|
95300
95597
|
}
|
|
95301
95598
|
function identityError(context, error) {
|
|
@@ -95326,7 +95623,7 @@ async function mutate(context, deps, input) {
|
|
|
95326
95623
|
const identity = await requestIdentity(context, deps);
|
|
95327
95624
|
const actorFence = getManagedAuthRequestActorLeaseStamp(context.req.raw);
|
|
95328
95625
|
if (deps.settings.managedAuthSessionSetMode !== "legacy" && !actorFence) {
|
|
95329
|
-
throw new
|
|
95626
|
+
throw new HTTPException87(409, { message: "Managed actor mutation fence is unavailable" });
|
|
95330
95627
|
}
|
|
95331
95628
|
try {
|
|
95332
95629
|
const response = CanonicalHumanIdentityMutationResponse.parse(
|
|
@@ -95474,15 +95771,15 @@ import {
|
|
|
95474
95771
|
updateOrganizationPrivateSessionSettings,
|
|
95475
95772
|
updateOrganizationRetentionPolicy
|
|
95476
95773
|
} from "@opengeni/db";
|
|
95477
|
-
import { HTTPException as
|
|
95478
|
-
import { z as
|
|
95479
|
-
var OrganizationId2 =
|
|
95480
|
-
var WorkspaceId =
|
|
95481
|
-
var MembershipId =
|
|
95482
|
-
var InvitationId =
|
|
95774
|
+
import { HTTPException as HTTPException88 } from "hono/http-exception";
|
|
95775
|
+
import { z as z35 } from "zod";
|
|
95776
|
+
var OrganizationId2 = z35.string().uuid();
|
|
95777
|
+
var WorkspaceId = z35.string().uuid();
|
|
95778
|
+
var MembershipId = z35.string().uuid();
|
|
95779
|
+
var InvitationId = z35.string().uuid();
|
|
95483
95780
|
async function requireManagedHuman(context, deps) {
|
|
95484
95781
|
if (deps.settings.productAccessMode !== "managed" || !deps.managedAuth || !context.req.header("cookie") || context.req.header("authorization")) {
|
|
95485
|
-
throw new
|
|
95782
|
+
throw new HTTPException88(401, { message: "managed human session required" });
|
|
95486
95783
|
}
|
|
95487
95784
|
const session = await getManagedSession3(context, deps.managedAuth, {
|
|
95488
95785
|
db: deps.db,
|
|
@@ -95490,7 +95787,7 @@ async function requireManagedHuman(context, deps) {
|
|
|
95490
95787
|
sessionSetMode: deps.settings.managedAuthSessionSetMode
|
|
95491
95788
|
});
|
|
95492
95789
|
if (!session?.user) {
|
|
95493
|
-
throw new
|
|
95790
|
+
throw new HTTPException88(401, { message: "managed human session required" });
|
|
95494
95791
|
}
|
|
95495
95792
|
return { session, subjectId: `user:${session.user.id}` };
|
|
95496
95793
|
}
|
|
@@ -95506,14 +95803,14 @@ async function requireOrganizationAdministrator(context, deps, organizationId2)
|
|
|
95506
95803
|
);
|
|
95507
95804
|
return { subjectId };
|
|
95508
95805
|
}
|
|
95509
|
-
throw new
|
|
95806
|
+
throw new HTTPException88(401, {
|
|
95510
95807
|
message: "organization administrator session required"
|
|
95511
95808
|
});
|
|
95512
95809
|
}
|
|
95513
95810
|
async function parseBody6(context, schema) {
|
|
95514
95811
|
const parsed = schema.safeParse(await context.req.json().catch(() => null));
|
|
95515
95812
|
if (!parsed.success) {
|
|
95516
|
-
throw new
|
|
95813
|
+
throw new HTTPException88(422, {
|
|
95517
95814
|
message: "invalid organization membership request"
|
|
95518
95815
|
});
|
|
95519
95816
|
}
|
|
@@ -95521,19 +95818,19 @@ async function parseBody6(context, schema) {
|
|
|
95521
95818
|
}
|
|
95522
95819
|
function parseId(schema, value, label) {
|
|
95523
95820
|
const parsed = schema.safeParse(value);
|
|
95524
|
-
if (!parsed.success) throw new
|
|
95821
|
+
if (!parsed.success) throw new HTTPException88(422, { message: `invalid ${label}` });
|
|
95525
95822
|
return parsed.data;
|
|
95526
95823
|
}
|
|
95527
95824
|
function rethrowMembershipError(error, resourceLimitMessage) {
|
|
95528
95825
|
const sqlState = nestedPostgresSqlState9(error);
|
|
95529
95826
|
if (sqlState === "54000" && resourceLimitMessage) {
|
|
95530
|
-
throw new
|
|
95827
|
+
throw new HTTPException88(409, {
|
|
95531
95828
|
message: resourceLimitMessage
|
|
95532
95829
|
});
|
|
95533
95830
|
}
|
|
95534
95831
|
const status = organizationMembershipHttpStatus(sqlState);
|
|
95535
95832
|
if (status !== null) {
|
|
95536
|
-
throw new
|
|
95833
|
+
throw new HTTPException88(status, {
|
|
95537
95834
|
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"
|
|
95538
95835
|
});
|
|
95539
95836
|
}
|
|
@@ -95573,7 +95870,7 @@ function registerOrganizationMembershipRoutes(app, deps) {
|
|
|
95573
95870
|
)
|
|
95574
95871
|
);
|
|
95575
95872
|
} catch (error) {
|
|
95576
|
-
if (error instanceof
|
|
95873
|
+
if (error instanceof HTTPException88) throw error;
|
|
95577
95874
|
rethrowMembershipError(error);
|
|
95578
95875
|
}
|
|
95579
95876
|
});
|
|
@@ -95630,7 +95927,7 @@ function registerOrganizationMembershipRoutes(app, deps) {
|
|
|
95630
95927
|
);
|
|
95631
95928
|
} catch (error) {
|
|
95632
95929
|
if (nestedPostgresSqlState9(error) === "42501") {
|
|
95633
|
-
throw new
|
|
95930
|
+
throw new HTTPException88(403, {
|
|
95634
95931
|
message: "organization membership is not active"
|
|
95635
95932
|
});
|
|
95636
95933
|
}
|
|
@@ -95641,7 +95938,7 @@ function registerOrganizationMembershipRoutes(app, deps) {
|
|
|
95641
95938
|
const { session, subjectId } = await requireManagedHuman(context, deps);
|
|
95642
95939
|
const query = ListOrganizationInvitationsPageQuery.safeParse(context.req.query());
|
|
95643
95940
|
if (!query.success) {
|
|
95644
|
-
throw new
|
|
95941
|
+
throw new HTTPException88(422, {
|
|
95645
95942
|
message: "invalid organization invitation page"
|
|
95646
95943
|
});
|
|
95647
95944
|
}
|
|
@@ -95919,7 +96216,7 @@ function registerOrganizationMembershipRoutes(app, deps) {
|
|
|
95919
96216
|
);
|
|
95920
96217
|
} catch (error) {
|
|
95921
96218
|
if (nestedPostgresSqlState9(error) === "55000") {
|
|
95922
|
-
throw new
|
|
96219
|
+
throw new HTTPException88(409, {
|
|
95923
96220
|
message: "private-session readiness is not activated for this organization"
|
|
95924
96221
|
});
|
|
95925
96222
|
}
|
|
@@ -95937,7 +96234,7 @@ function registerOrganizationMembershipRoutes(app, deps) {
|
|
|
95937
96234
|
try {
|
|
95938
96235
|
assertOrganizationUserSetupDeliveryConfigured(deps.settings, deps.managedEmailTransport);
|
|
95939
96236
|
} catch {
|
|
95940
|
-
throw new
|
|
96237
|
+
throw new HTTPException88(503, {
|
|
95941
96238
|
message: "invited-user account setup delivery is not configured on this deployment"
|
|
95942
96239
|
});
|
|
95943
96240
|
}
|
|
@@ -95973,7 +96270,7 @@ function registerOrganizationMembershipRoutes(app, deps) {
|
|
|
95973
96270
|
201
|
|
95974
96271
|
);
|
|
95975
96272
|
} catch (error) {
|
|
95976
|
-
if (error instanceof
|
|
96273
|
+
if (error instanceof HTTPException88) throw error;
|
|
95977
96274
|
rethrowMembershipError(error);
|
|
95978
96275
|
}
|
|
95979
96276
|
});
|
|
@@ -95986,7 +96283,7 @@ function registerOrganizationMembershipRoutes(app, deps) {
|
|
|
95986
96283
|
);
|
|
95987
96284
|
const query = ListOrganizationInvitationsPageQuery.safeParse(context.req.query());
|
|
95988
96285
|
if (!query.success) {
|
|
95989
|
-
throw new
|
|
96286
|
+
throw new HTTPException88(422, {
|
|
95990
96287
|
message: "invalid organization invitation page"
|
|
95991
96288
|
});
|
|
95992
96289
|
}
|
|
@@ -96023,7 +96320,7 @@ function registerOrganizationMembershipRoutes(app, deps) {
|
|
|
96023
96320
|
try {
|
|
96024
96321
|
assertOrganizationUserSetupDeliveryConfigured(deps.settings, deps.managedEmailTransport);
|
|
96025
96322
|
} catch {
|
|
96026
|
-
throw new
|
|
96323
|
+
throw new HTTPException88(503, {
|
|
96027
96324
|
message: "invited-user account setup delivery is not configured on this deployment"
|
|
96028
96325
|
});
|
|
96029
96326
|
}
|
|
@@ -96070,7 +96367,7 @@ function registerOrganizationMembershipRoutes(app, deps) {
|
|
|
96070
96367
|
membership: OrganizationMember.parse(result.membership)
|
|
96071
96368
|
});
|
|
96072
96369
|
} catch (error) {
|
|
96073
|
-
if (error instanceof
|
|
96370
|
+
if (error instanceof HTTPException88) throw error;
|
|
96074
96371
|
rethrowMembershipError(error);
|
|
96075
96372
|
}
|
|
96076
96373
|
});
|
|
@@ -96252,12 +96549,12 @@ import {
|
|
|
96252
96549
|
} from "@opengeni/contracts";
|
|
96253
96550
|
import {
|
|
96254
96551
|
accountScopedApiKeyWorkspaceAuthority as accountScopedApiKeyWorkspaceAuthority3,
|
|
96255
|
-
hasPermission as
|
|
96552
|
+
hasPermission as hasPermission22,
|
|
96256
96553
|
requireAccessContext as requireAccessContext4,
|
|
96257
|
-
requireAccessGrantAuthorization as
|
|
96554
|
+
requireAccessGrantAuthorization as requireAccessGrantAuthorization34,
|
|
96258
96555
|
requireSessionAuthorizationListScope as requireSessionAuthorizationListScope3,
|
|
96259
|
-
SessionAuthorizationDeniedError as
|
|
96260
|
-
SessionAuthorizationUnavailableError as
|
|
96556
|
+
SessionAuthorizationDeniedError as SessionAuthorizationDeniedError14,
|
|
96557
|
+
SessionAuthorizationUnavailableError as SessionAuthorizationUnavailableError12
|
|
96261
96558
|
} from "@opengeni/core";
|
|
96262
96559
|
import {
|
|
96263
96560
|
decodeSessionListCursor as decodeSessionListCursor2,
|
|
@@ -96267,14 +96564,14 @@ import {
|
|
|
96267
96564
|
SessionListCursorError as SessionListCursorError2,
|
|
96268
96565
|
SessionListCursorExpiredError as SessionListCursorExpiredError2
|
|
96269
96566
|
} from "@opengeni/db";
|
|
96270
|
-
import { HTTPException as
|
|
96271
|
-
import { z as
|
|
96567
|
+
import { HTTPException as HTTPException89 } from "hono/http-exception";
|
|
96568
|
+
import { z as z36 } from "zod";
|
|
96272
96569
|
var ORGANIZATION_SESSION_LIST_MAX_WORKSPACE_READS = 25;
|
|
96273
|
-
var OrganizationId3 =
|
|
96274
|
-
var OrganizationSessionListCursorEnvelope =
|
|
96275
|
-
workspaceId:
|
|
96276
|
-
cursor:
|
|
96277
|
-
pinnedOffset:
|
|
96570
|
+
var OrganizationId3 = z36.string().uuid();
|
|
96571
|
+
var OrganizationSessionListCursorEnvelope = z36.object({
|
|
96572
|
+
workspaceId: z36.string().uuid(),
|
|
96573
|
+
cursor: z36.string().min(1).nullable(),
|
|
96574
|
+
pinnedOffset: z36.number().int().nonnegative().max(1e4).optional()
|
|
96278
96575
|
}).strict();
|
|
96279
96576
|
function encodeOrganizationSessionListCursor(cursor) {
|
|
96280
96577
|
return Buffer.from(JSON.stringify(cursor)).toString("base64url");
|
|
@@ -96296,10 +96593,10 @@ function decodeOrganizationSessionListCursor(value) {
|
|
|
96296
96593
|
function requireOrganizationSessionReadAuthority(context, organizationId2) {
|
|
96297
96594
|
const authority = accountScopedApiKeyWorkspaceAuthority3(context);
|
|
96298
96595
|
if (authority) {
|
|
96299
|
-
if (authority.accountId === organizationId2 &&
|
|
96596
|
+
if (authority.accountId === organizationId2 && hasPermission22(authority.permissions, "sessions:read")) {
|
|
96300
96597
|
return "organization_api_key";
|
|
96301
96598
|
}
|
|
96302
|
-
throw new
|
|
96599
|
+
throw new HTTPException89(403, { message: "organization session read authority required" });
|
|
96303
96600
|
}
|
|
96304
96601
|
const accountGrant = context.accountGrants.find(
|
|
96305
96602
|
(candidate) => candidate.accountId === organizationId2
|
|
@@ -96307,16 +96604,16 @@ function requireOrganizationSessionReadAuthority(context, organizationId2) {
|
|
|
96307
96604
|
if (accountGrant?.permissions.includes("account:admin")) {
|
|
96308
96605
|
return "account_admin";
|
|
96309
96606
|
}
|
|
96310
|
-
throw new
|
|
96607
|
+
throw new HTTPException89(403, { message: "organization session read authority required" });
|
|
96311
96608
|
}
|
|
96312
96609
|
function sessionAuthorizationHttpError2(error) {
|
|
96313
|
-
if (error instanceof
|
|
96314
|
-
return new
|
|
96610
|
+
if (error instanceof SessionAuthorizationDeniedError14) {
|
|
96611
|
+
return new HTTPException89(404, { message: "session not found" });
|
|
96315
96612
|
}
|
|
96316
|
-
if (error instanceof
|
|
96317
|
-
return new
|
|
96613
|
+
if (error instanceof SessionAuthorizationUnavailableError12) {
|
|
96614
|
+
return new HTTPException89(503, { message: "session authorization is unavailable" });
|
|
96318
96615
|
}
|
|
96319
|
-
if (error instanceof
|
|
96616
|
+
if (error instanceof HTTPException89) return error;
|
|
96320
96617
|
throw error;
|
|
96321
96618
|
}
|
|
96322
96619
|
function compareWorkspaceIds(left, right) {
|
|
@@ -96326,7 +96623,7 @@ function registerOrganizationSessionRoutes(app, deps) {
|
|
|
96326
96623
|
app.get("/v1/organizations/:organizationId/sessions", async (c) => {
|
|
96327
96624
|
const organizationIdResult = OrganizationId3.safeParse(c.req.param("organizationId"));
|
|
96328
96625
|
if (!organizationIdResult.success) {
|
|
96329
|
-
throw new
|
|
96626
|
+
throw new HTTPException89(422, { message: "invalid organization id" });
|
|
96330
96627
|
}
|
|
96331
96628
|
const organizationId2 = organizationIdResult.data;
|
|
96332
96629
|
const context = await requireAccessContext4(c, deps);
|
|
@@ -96334,14 +96631,14 @@ function registerOrganizationSessionRoutes(app, deps) {
|
|
|
96334
96631
|
const queryResult = ListOrganizationSessionsQuery.safeParse(c.req.query());
|
|
96335
96632
|
if (!queryResult.success) {
|
|
96336
96633
|
const issue = queryResult.error.issues[0];
|
|
96337
|
-
throw new
|
|
96634
|
+
throw new HTTPException89(400, {
|
|
96338
96635
|
message: issue ? `${issue.path.length > 0 ? `${issue.path.join(".")}: ` : ""}${issue.message}` : "invalid organization session list query"
|
|
96339
96636
|
});
|
|
96340
96637
|
}
|
|
96341
96638
|
const query = queryResult.data;
|
|
96342
96639
|
const cursor = query.cursor ? decodeOrganizationSessionListCursor(query.cursor) : null;
|
|
96343
96640
|
if (query.cursor && !cursor) {
|
|
96344
|
-
throw new
|
|
96641
|
+
throw new HTTPException89(400, { message: "cursor is invalid" });
|
|
96345
96642
|
}
|
|
96346
96643
|
const workspaces = (await listSharedWorkspacesForAccount2(deps.db, organizationId2)).sort(
|
|
96347
96644
|
compareWorkspaceIds
|
|
@@ -96405,14 +96702,14 @@ function registerOrganizationSessionRoutes(app, deps) {
|
|
|
96405
96702
|
async function listWorkspaceSessionPage(c, deps, input) {
|
|
96406
96703
|
let authorization;
|
|
96407
96704
|
try {
|
|
96408
|
-
authorization = await
|
|
96705
|
+
authorization = await requireAccessGrantAuthorization34(
|
|
96409
96706
|
c,
|
|
96410
96707
|
deps,
|
|
96411
96708
|
input.workspace.id,
|
|
96412
96709
|
"sessions:read"
|
|
96413
96710
|
);
|
|
96414
96711
|
} catch (error) {
|
|
96415
|
-
if (input.readAuthority === "account_admin" && error instanceof
|
|
96712
|
+
if (input.readAuthority === "account_admin" && error instanceof HTTPException89 && error.status === 403) {
|
|
96416
96713
|
return null;
|
|
96417
96714
|
}
|
|
96418
96715
|
throw error;
|
|
@@ -96426,7 +96723,7 @@ async function listWorkspaceSessionPage(c, deps, input) {
|
|
|
96426
96723
|
}
|
|
96427
96724
|
const cursor = input.innerCursor ? decodeSessionListCursor2(input.innerCursor) : null;
|
|
96428
96725
|
if (input.innerCursor && !cursor) {
|
|
96429
|
-
throw new
|
|
96726
|
+
throw new HTTPException89(400, { message: "cursor is invalid" });
|
|
96430
96727
|
}
|
|
96431
96728
|
try {
|
|
96432
96729
|
const list = async (limit) => await listSessionsForSubject2(deps.db, input.workspace.id, {
|
|
@@ -96459,13 +96756,13 @@ async function listWorkspaceSessionPage(c, deps, input) {
|
|
|
96459
96756
|
return { sessions: withStatus(rows), nextCursor: page.nextCursor, nextPinnedOffset };
|
|
96460
96757
|
} catch (error) {
|
|
96461
96758
|
if (error instanceof SessionListAccessError2) {
|
|
96462
|
-
throw new
|
|
96759
|
+
throw new HTTPException89(403, { message: error.message });
|
|
96463
96760
|
}
|
|
96464
96761
|
if (error instanceof SessionListCursorExpiredError2) {
|
|
96465
|
-
throw new
|
|
96762
|
+
throw new HTTPException89(410, { message: error.message });
|
|
96466
96763
|
}
|
|
96467
96764
|
if (error instanceof SessionListCursorError2) {
|
|
96468
|
-
throw new
|
|
96765
|
+
throw new HTTPException89(400, { message: error.message });
|
|
96469
96766
|
}
|
|
96470
96767
|
throw error;
|
|
96471
96768
|
}
|
|
@@ -96500,10 +96797,10 @@ import {
|
|
|
96500
96797
|
OrganizationRecoveryUnavailableError,
|
|
96501
96798
|
startOrganizationRecoveryOperation
|
|
96502
96799
|
} from "@opengeni/db";
|
|
96503
|
-
import { HTTPException as
|
|
96504
|
-
import { z as
|
|
96505
|
-
var OrganizationId4 =
|
|
96506
|
-
var RecoveryOperationId =
|
|
96800
|
+
import { HTTPException as HTTPException90 } from "hono/http-exception";
|
|
96801
|
+
import { z as z37 } from "zod";
|
|
96802
|
+
var OrganizationId4 = z37.string().uuid();
|
|
96803
|
+
var RecoveryOperationId = z37.string().uuid();
|
|
96507
96804
|
var productionServices = {
|
|
96508
96805
|
requireCanonicalHumanRequestIdentity: requireCanonicalHumanRequestIdentity2,
|
|
96509
96806
|
getManagedAuthRequestActorAdmissionStamp,
|
|
@@ -96519,7 +96816,7 @@ var productionServices = {
|
|
|
96519
96816
|
};
|
|
96520
96817
|
async function requireRecoveryIdentity(context, deps, services) {
|
|
96521
96818
|
if (deps.settings.productAccessMode !== "managed" || !deps.managedAuth || !context.req.header("cookie") || context.req.header("authorization")) {
|
|
96522
|
-
throw new
|
|
96819
|
+
throw new HTTPException90(401, {
|
|
96523
96820
|
message: "Managed human authentication required"
|
|
96524
96821
|
});
|
|
96525
96822
|
}
|
|
@@ -96535,7 +96832,7 @@ async function requireRecoveryIdentity(context, deps, services) {
|
|
|
96535
96832
|
async function parseBody7(context, schema) {
|
|
96536
96833
|
const parsed = schema.safeParse(await context.req.json().catch(() => null));
|
|
96537
96834
|
if (!parsed.success) {
|
|
96538
|
-
throw new
|
|
96835
|
+
throw new HTTPException90(422, {
|
|
96539
96836
|
message: "Invalid organization recovery request"
|
|
96540
96837
|
});
|
|
96541
96838
|
}
|
|
@@ -96543,7 +96840,7 @@ async function parseBody7(context, schema) {
|
|
|
96543
96840
|
}
|
|
96544
96841
|
function parseId2(schema, value, label) {
|
|
96545
96842
|
const parsed = schema.safeParse(value);
|
|
96546
|
-
if (!parsed.success) throw new
|
|
96843
|
+
if (!parsed.success) throw new HTTPException90(422, { message: `Invalid ${label}` });
|
|
96547
96844
|
return parsed.data;
|
|
96548
96845
|
}
|
|
96549
96846
|
function organizationId(context) {
|
|
@@ -96598,12 +96895,12 @@ function organizationRecoveryHttpError(error) {
|
|
|
96598
96895
|
function requireActorFence(context, deps, services) {
|
|
96599
96896
|
const actorFence = services.getManagedAuthRequestActorLeaseStamp(context.req.raw);
|
|
96600
96897
|
if (deps.settings.managedAuthSessionSetMode !== "legacy" && !actorFence) {
|
|
96601
|
-
throw new
|
|
96898
|
+
throw new HTTPException90(409, {
|
|
96602
96899
|
message: "Managed actor mutation fence is unavailable"
|
|
96603
96900
|
});
|
|
96604
96901
|
}
|
|
96605
96902
|
if (!actorFence) {
|
|
96606
|
-
throw new
|
|
96903
|
+
throw new HTTPException90(409, {
|
|
96607
96904
|
message: "Organization recovery requires provider-neutral browser login slots"
|
|
96608
96905
|
});
|
|
96609
96906
|
}
|
|
@@ -96758,7 +97055,7 @@ import {
|
|
|
96758
97055
|
preflightOrganizationUserSetup,
|
|
96759
97056
|
previewOrganizationUserSetup
|
|
96760
97057
|
} from "@opengeni/db";
|
|
96761
|
-
import { HTTPException as
|
|
97058
|
+
import { HTTPException as HTTPException91 } from "hono/http-exception";
|
|
96762
97059
|
var completedSetupReplayPasswordHash = `completed-replay:${"0".repeat(64)}`;
|
|
96763
97060
|
function registerManagedOnboardingRoutes(app, deps, options = {}) {
|
|
96764
97061
|
const accountSetupLimiter = options.accountSetupLimiter ?? new PublicSetupRateLimiter();
|
|
@@ -96781,7 +97078,7 @@ function registerManagedOnboardingRoutes(app, deps, options = {}) {
|
|
|
96781
97078
|
await context.req.json().catch(() => null)
|
|
96782
97079
|
);
|
|
96783
97080
|
if (!parsed.success) {
|
|
96784
|
-
throw new
|
|
97081
|
+
throw new HTTPException91(422, {
|
|
96785
97082
|
message: "invalid organization setup request"
|
|
96786
97083
|
});
|
|
96787
97084
|
}
|
|
@@ -96805,17 +97102,17 @@ function registerManagedOnboardingRoutes(app, deps, options = {}) {
|
|
|
96805
97102
|
} catch (error) {
|
|
96806
97103
|
const sqlState = nestedPostgresSqlState10(error);
|
|
96807
97104
|
if (sqlState === "22023") {
|
|
96808
|
-
throw new
|
|
97105
|
+
throw new HTTPException91(422, {
|
|
96809
97106
|
message: "invalid organization setup request"
|
|
96810
97107
|
});
|
|
96811
97108
|
}
|
|
96812
97109
|
if (sqlState === "42501") {
|
|
96813
|
-
throw new
|
|
97110
|
+
throw new HTTPException91(403, {
|
|
96814
97111
|
message: "verified managed user required"
|
|
96815
97112
|
});
|
|
96816
97113
|
}
|
|
96817
97114
|
if (sqlState === "23505" || sqlState === "55000") {
|
|
96818
|
-
throw new
|
|
97115
|
+
throw new HTTPException91(409, {
|
|
96819
97116
|
message: "organization setup is no longer available; refresh to continue"
|
|
96820
97117
|
});
|
|
96821
97118
|
}
|
|
@@ -96824,14 +97121,14 @@ function registerManagedOnboardingRoutes(app, deps, options = {}) {
|
|
|
96824
97121
|
});
|
|
96825
97122
|
app.post("/v1/auth/organization-setup/preview", async (context) => {
|
|
96826
97123
|
if (deps.settings.productAccessMode !== "managed" || !deps.managedAuth) {
|
|
96827
|
-
throw new
|
|
97124
|
+
throw new HTTPException91(404, { message: "account setup is unavailable" });
|
|
96828
97125
|
}
|
|
96829
97126
|
enforceAccountSetupRateLimit(context, accountSetupLimiter);
|
|
96830
97127
|
const parsed = PreviewOrganizationUserSetupRequest.safeParse(
|
|
96831
97128
|
await context.req.json().catch(() => null)
|
|
96832
97129
|
);
|
|
96833
97130
|
if (!parsed.success) {
|
|
96834
|
-
throw new
|
|
97131
|
+
throw new HTTPException91(422, { message: "invalid account setup preview request" });
|
|
96835
97132
|
}
|
|
96836
97133
|
return context.json(
|
|
96837
97134
|
OrganizationUserSetupPreview.parse(
|
|
@@ -96844,14 +97141,14 @@ function registerManagedOnboardingRoutes(app, deps, options = {}) {
|
|
|
96844
97141
|
});
|
|
96845
97142
|
app.post("/v1/auth/organization-setup", async (context) => {
|
|
96846
97143
|
if (deps.settings.productAccessMode !== "managed" || !deps.managedAuth) {
|
|
96847
|
-
throw new
|
|
97144
|
+
throw new HTTPException91(404, { message: "account setup is unavailable" });
|
|
96848
97145
|
}
|
|
96849
97146
|
enforceAccountSetupRateLimit(context, accountSetupLimiter);
|
|
96850
97147
|
const parsed = CompleteOrganizationUserSetupRequest.safeParse(
|
|
96851
97148
|
await context.req.json().catch(() => null)
|
|
96852
97149
|
);
|
|
96853
97150
|
if (!parsed.success) {
|
|
96854
|
-
throw new
|
|
97151
|
+
throw new HTTPException91(422, {
|
|
96855
97152
|
message: "invalid account setup request"
|
|
96856
97153
|
});
|
|
96857
97154
|
}
|
|
@@ -96859,7 +97156,7 @@ function registerManagedOnboardingRoutes(app, deps, options = {}) {
|
|
|
96859
97156
|
const tokenDigest = await organizationUserSetupTokenDigest(parsed.data.token);
|
|
96860
97157
|
const preflight = await preflightOrganizationUserSetup(deps.db, tokenDigest);
|
|
96861
97158
|
if (preflight === "unavailable") {
|
|
96862
|
-
throw new
|
|
97159
|
+
throw new HTTPException91(404, {
|
|
96863
97160
|
message: "account setup link is invalid, expired, or already belongs to an account"
|
|
96864
97161
|
});
|
|
96865
97162
|
}
|
|
@@ -96885,17 +97182,17 @@ function registerManagedOnboardingRoutes(app, deps, options = {}) {
|
|
|
96885
97182
|
} catch (error) {
|
|
96886
97183
|
const sqlState = nestedPostgresSqlState10(error);
|
|
96887
97184
|
if (sqlState === "22023") {
|
|
96888
|
-
throw new
|
|
97185
|
+
throw new HTTPException91(422, {
|
|
96889
97186
|
message: "invalid account setup request"
|
|
96890
97187
|
});
|
|
96891
97188
|
}
|
|
96892
97189
|
if (sqlState === "23505") {
|
|
96893
|
-
throw new
|
|
97190
|
+
throw new HTTPException91(409, {
|
|
96894
97191
|
message: "account setup request changed; reopen the original link and try again"
|
|
96895
97192
|
});
|
|
96896
97193
|
}
|
|
96897
97194
|
if (sqlState === "P0002" || sqlState === "42501" || sqlState === "55000") {
|
|
96898
|
-
throw new
|
|
97195
|
+
throw new HTTPException91(404, {
|
|
96899
97196
|
message: "account setup link is invalid, expired, or already belongs to an account"
|
|
96900
97197
|
});
|
|
96901
97198
|
}
|
|
@@ -96910,7 +97207,7 @@ function enforceAccountSetupRateLimit(context, limiter) {
|
|
|
96910
97207
|
} catch {
|
|
96911
97208
|
}
|
|
96912
97209
|
if (!allowed2) {
|
|
96913
|
-
throw new
|
|
97210
|
+
throw new HTTPException91(429, { message: "too many account setup requests; slow down" });
|
|
96914
97211
|
}
|
|
96915
97212
|
}
|
|
96916
97213
|
function accountSetupClientKey(context) {
|
|
@@ -96978,7 +97275,7 @@ function refillSetupRateLimitBucket(bucket, capacity, refillPerSecond, now) {
|
|
|
96978
97275
|
}
|
|
96979
97276
|
async function requireManagedHuman2(context, deps) {
|
|
96980
97277
|
if (deps.settings.productAccessMode !== "managed" || !deps.managedAuth || !context.req.header("cookie") || context.req.header("authorization")) {
|
|
96981
|
-
throw new
|
|
97278
|
+
throw new HTTPException91(401, { message: "managed human session required" });
|
|
96982
97279
|
}
|
|
96983
97280
|
const session = await getManagedSession4(context, deps.managedAuth, {
|
|
96984
97281
|
db: deps.db,
|
|
@@ -96986,7 +97283,7 @@ async function requireManagedHuman2(context, deps) {
|
|
|
96986
97283
|
sessionSetMode: deps.settings.managedAuthSessionSetMode
|
|
96987
97284
|
});
|
|
96988
97285
|
if (!session?.user) {
|
|
96989
|
-
throw new
|
|
97286
|
+
throw new HTTPException91(401, { message: "managed human session required" });
|
|
96990
97287
|
}
|
|
96991
97288
|
return session;
|
|
96992
97289
|
}
|
|
@@ -97013,7 +97310,7 @@ import {
|
|
|
97013
97310
|
StartManagedAuthSocialTransactionRequest,
|
|
97014
97311
|
StartManagedAuthSocialTransactionResponse
|
|
97015
97312
|
} from "@opengeni/contracts/managed-auth-session-sets";
|
|
97016
|
-
import { hasPermission as
|
|
97313
|
+
import { hasPermission as hasPermission23, requireSessionAuthorization as requireSessionAuthorization15 } from "@opengeni/core";
|
|
97017
97314
|
import {
|
|
97018
97315
|
authenticateAndAdoptManagedAuthSession,
|
|
97019
97316
|
isolatedManagedAuthHeaders,
|
|
@@ -97053,13 +97350,13 @@ import {
|
|
|
97053
97350
|
} from "@opengeni/db/managed-auth-session-sets";
|
|
97054
97351
|
import { ensureManagedAccessForUser as ensureManagedAccessForUser2, getSession as getSession10 } from "@opengeni/db";
|
|
97055
97352
|
import { deleteCookie as deleteCookie3, getCookie, setCookie as setCookie3 } from "hono/cookie";
|
|
97056
|
-
import { HTTPException as
|
|
97057
|
-
import { z as
|
|
97058
|
-
var ManagedAuthSocialStartReceipt =
|
|
97059
|
-
version:
|
|
97060
|
-
requestDigest:
|
|
97061
|
-
url:
|
|
97062
|
-
stateCookie:
|
|
97353
|
+
import { HTTPException as HTTPException92 } from "hono/http-exception";
|
|
97354
|
+
import { z as z38 } from "zod";
|
|
97355
|
+
var ManagedAuthSocialStartReceipt = z38.object({
|
|
97356
|
+
version: z38.literal(1),
|
|
97357
|
+
requestDigest: z38.string().regex(/^[0-9a-f]{64}$/u),
|
|
97358
|
+
url: z38.string().url().max(4096),
|
|
97359
|
+
stateCookie: z38.string().min(1).max(4096)
|
|
97063
97360
|
}).strict();
|
|
97064
97361
|
function registerManagedAuthSessionSetRoutes(app, deps) {
|
|
97065
97362
|
const noStore = async (context, next) => {
|
|
@@ -97080,7 +97377,7 @@ function registerManagedAuthSessionSetRoutes(app, deps) {
|
|
|
97080
97377
|
app.use("/v1/auth/session-set/*", noStore);
|
|
97081
97378
|
app.get("/v1/auth/get-session", async (context) => {
|
|
97082
97379
|
if (deps.settings.managedAuthSessionSetMode === "legacy") {
|
|
97083
|
-
if (!deps.managedAuth) throw new
|
|
97380
|
+
if (!deps.managedAuth) throw new HTTPException92(404);
|
|
97084
97381
|
return await deps.managedAuth.handler(context.req.raw);
|
|
97085
97382
|
}
|
|
97086
97383
|
context.header("cache-control", "no-store");
|
|
@@ -97685,14 +97982,14 @@ async function resolveCanonicalDeepLink(deps, authority, path, expectedActorEpoc
|
|
|
97685
97982
|
const grants = target.workspaceId ? access.workspaceGrants.filter((grant) => grant.workspaceId === target.workspaceId) : access.workspaceGrants;
|
|
97686
97983
|
let authorized = false;
|
|
97687
97984
|
for (const grant of grants) {
|
|
97688
|
-
if (!
|
|
97985
|
+
if (!hasPermission23(grant.permissions, target.sessionId ? "sessions:read" : target.permission)) {
|
|
97689
97986
|
continue;
|
|
97690
97987
|
}
|
|
97691
97988
|
if (target.sessionId) {
|
|
97692
97989
|
const session = await getSession10(deps.db, grant.workspaceId, target.sessionId);
|
|
97693
97990
|
if (!session) continue;
|
|
97694
97991
|
try {
|
|
97695
|
-
await
|
|
97992
|
+
await requireSessionAuthorization15(deps, grant, {
|
|
97696
97993
|
sessionId: target.sessionId,
|
|
97697
97994
|
operation: "session.read",
|
|
97698
97995
|
surface: "http"
|
|
@@ -97919,7 +98216,7 @@ function appendCookies(context, cookies) {
|
|
|
97919
98216
|
for (const cookie of cookies) context.header("set-cookie", cookie, { append: true });
|
|
97920
98217
|
}
|
|
97921
98218
|
function throwHttp(error) {
|
|
97922
|
-
if (error instanceof
|
|
98219
|
+
if (error instanceof HTTPException92) throw error;
|
|
97923
98220
|
if (error instanceof ManagedAuthSessionSetGenerationConflictError) {
|
|
97924
98221
|
throw managedAuthApiError(409, "generation_conflict", { cause: error, retryable: true });
|
|
97925
98222
|
}
|
|
@@ -97988,32 +98285,32 @@ import {
|
|
|
97988
98285
|
import {
|
|
97989
98286
|
issueManagedHumanUserResourceGrant,
|
|
97990
98287
|
listManagedHumanUserResourceAuthorities,
|
|
97991
|
-
requireAccessGrantAuthorization as
|
|
98288
|
+
requireAccessGrantAuthorization as requireAccessGrantAuthorization35,
|
|
97992
98289
|
revokeManagedHumanUserResourceGrant,
|
|
97993
|
-
SessionAuthorizationDeniedError as
|
|
97994
|
-
SessionAuthorizationUnavailableError as
|
|
98290
|
+
SessionAuthorizationDeniedError as SessionAuthorizationDeniedError15,
|
|
98291
|
+
SessionAuthorizationUnavailableError as SessionAuthorizationUnavailableError13,
|
|
97995
98292
|
SessionTenancyManagedHumanRequiredError as SessionTenancyManagedHumanRequiredError2
|
|
97996
98293
|
} from "@opengeni/core";
|
|
97997
98294
|
import { nestedPostgresSqlState as nestedPostgresSqlState11, SessionTenancyNotActivatedError as SessionTenancyNotActivatedError2 } from "@opengeni/db";
|
|
97998
|
-
import { HTTPException as
|
|
97999
|
-
import { z as
|
|
98295
|
+
import { HTTPException as HTTPException93 } from "hono/http-exception";
|
|
98296
|
+
import { z as z39 } from "zod";
|
|
98000
98297
|
async function body2(context, schema) {
|
|
98001
98298
|
const parsed = schema.safeParse(await context.req.json().catch(() => null));
|
|
98002
|
-
if (!parsed.success) throw new
|
|
98299
|
+
if (!parsed.success) throw new HTTPException93(422, { message: "invalid user-resource request" });
|
|
98003
98300
|
return parsed.data;
|
|
98004
98301
|
}
|
|
98005
98302
|
function lifecycleError(error) {
|
|
98006
|
-
if (error instanceof
|
|
98007
|
-
throw new
|
|
98303
|
+
if (error instanceof SessionAuthorizationDeniedError15 || error instanceof SessionTenancyManagedHumanRequiredError2 || error instanceof SessionTenancyNotActivatedError2) {
|
|
98304
|
+
throw new HTTPException93(403, { message: "user-resource authority denied" });
|
|
98008
98305
|
}
|
|
98009
|
-
if (error instanceof
|
|
98010
|
-
throw new
|
|
98306
|
+
if (error instanceof SessionAuthorizationUnavailableError13) {
|
|
98307
|
+
throw new HTTPException93(503, { message: "session authorization unavailable" });
|
|
98011
98308
|
}
|
|
98012
98309
|
if (nestedPostgresSqlState11(error) === "42501") {
|
|
98013
|
-
throw new
|
|
98310
|
+
throw new HTTPException93(403, { message: "user-resource authority denied" });
|
|
98014
98311
|
}
|
|
98015
98312
|
if (nestedPostgresSqlState11(error) === "22023") {
|
|
98016
|
-
throw new
|
|
98313
|
+
throw new HTTPException93(422, { message: "invalid user-resource request" });
|
|
98017
98314
|
}
|
|
98018
98315
|
throw error;
|
|
98019
98316
|
}
|
|
@@ -98026,9 +98323,9 @@ function registerUserResourceAuthorityRoutes(app, deps) {
|
|
|
98026
98323
|
cursor: context.req.query("cursor"),
|
|
98027
98324
|
limit: context.req.query("limit")
|
|
98028
98325
|
});
|
|
98029
|
-
if (!query.success) throw new
|
|
98326
|
+
if (!query.success) throw new HTTPException93(422, { message: "explicit scope=user required" });
|
|
98030
98327
|
const workspaceId = context.req.param("workspaceId");
|
|
98031
|
-
const access = await
|
|
98328
|
+
const access = await requireAccessGrantAuthorization35(
|
|
98032
98329
|
context,
|
|
98033
98330
|
deps,
|
|
98034
98331
|
workspaceId,
|
|
@@ -98053,10 +98350,10 @@ function registerUserResourceAuthorityRoutes(app, deps) {
|
|
|
98053
98350
|
});
|
|
98054
98351
|
app.post(`${base}/:authorityId/grants`, async (context) => {
|
|
98055
98352
|
const workspaceId = context.req.param("workspaceId");
|
|
98056
|
-
const authorityId =
|
|
98057
|
-
if (!authorityId.success) throw new
|
|
98353
|
+
const authorityId = z39.string().uuid().safeParse(context.req.param("authorityId"));
|
|
98354
|
+
if (!authorityId.success) throw new HTTPException93(422, { message: "invalid authority id" });
|
|
98058
98355
|
const request = await body2(context, IssueUserResourceGrantRequest);
|
|
98059
|
-
const access = await
|
|
98356
|
+
const access = await requireAccessGrantAuthorization35(
|
|
98060
98357
|
context,
|
|
98061
98358
|
deps,
|
|
98062
98359
|
workspaceId,
|
|
@@ -98082,11 +98379,11 @@ function registerUserResourceAuthorityRoutes(app, deps) {
|
|
|
98082
98379
|
});
|
|
98083
98380
|
app.delete(`${base}/grants/:grantId`, async (context) => {
|
|
98084
98381
|
const query = RevokeUserResourceGrantQuery.safeParse({ scope: context.req.query("scope") });
|
|
98085
|
-
if (!query.success) throw new
|
|
98086
|
-
const grantId =
|
|
98087
|
-
if (!grantId.success) throw new
|
|
98382
|
+
if (!query.success) throw new HTTPException93(422, { message: "explicit scope=user required" });
|
|
98383
|
+
const grantId = z39.string().uuid().safeParse(context.req.param("grantId"));
|
|
98384
|
+
if (!grantId.success) throw new HTTPException93(422, { message: "invalid grant id" });
|
|
98088
98385
|
const workspaceId = context.req.param("workspaceId");
|
|
98089
|
-
const access = await
|
|
98386
|
+
const access = await requireAccessGrantAuthorization35(
|
|
98090
98387
|
context,
|
|
98091
98388
|
deps,
|
|
98092
98389
|
workspaceId,
|
|
@@ -98116,22 +98413,22 @@ import {
|
|
|
98116
98413
|
import {
|
|
98117
98414
|
issueManagedHumanUserResourceGrant as issueManagedHumanUserResourceGrant2,
|
|
98118
98415
|
listManagedHumanUserResourceAuthorities as listManagedHumanUserResourceAuthorities2,
|
|
98119
|
-
requireAccessGrantAuthorization as
|
|
98416
|
+
requireAccessGrantAuthorization as requireAccessGrantAuthorization36,
|
|
98120
98417
|
revokeManagedHumanUserResourceGrant as revokeManagedHumanUserResourceGrant2,
|
|
98121
|
-
SessionAuthorizationDeniedError as
|
|
98122
|
-
SessionAuthorizationUnavailableError as
|
|
98418
|
+
SessionAuthorizationDeniedError as SessionAuthorizationDeniedError16,
|
|
98419
|
+
SessionAuthorizationUnavailableError as SessionAuthorizationUnavailableError14,
|
|
98123
98420
|
SessionTenancyManagedHumanRequiredError as SessionTenancyManagedHumanRequiredError3
|
|
98124
98421
|
} from "@opengeni/core";
|
|
98125
98422
|
import { nestedPostgresSqlState as nestedPostgresSqlState12, SessionTenancyNotActivatedError as SessionTenancyNotActivatedError3 } from "@opengeni/db";
|
|
98126
|
-
import { HTTPException as
|
|
98127
|
-
import { z as
|
|
98423
|
+
import { HTTPException as HTTPException95 } from "hono/http-exception";
|
|
98424
|
+
import { z as z40 } from "zod";
|
|
98128
98425
|
|
|
98129
98426
|
// src/connection-authority-owner.ts
|
|
98130
98427
|
import {
|
|
98131
98428
|
IssueConnectionUseGrantRequest,
|
|
98132
98429
|
ListConnectionAuthoritiesResponse
|
|
98133
98430
|
} from "@opengeni/contracts/connection-authority";
|
|
98134
|
-
import { HTTPException as
|
|
98431
|
+
import { HTTPException as HTTPException94 } from "hono/http-exception";
|
|
98135
98432
|
function projectSelfConnectionAuthorities(page) {
|
|
98136
98433
|
return ListConnectionAuthoritiesResponse.parse({
|
|
98137
98434
|
scope: "user",
|
|
@@ -98154,21 +98451,21 @@ function connectionUseGrantLifecycleInput(input) {
|
|
|
98154
98451
|
// src/routes/connection-authorities.ts
|
|
98155
98452
|
async function body3(context, schema) {
|
|
98156
98453
|
const parsed = schema.safeParse(await context.req.json().catch(() => null));
|
|
98157
|
-
if (!parsed.success) throw new
|
|
98454
|
+
if (!parsed.success) throw new HTTPException95(422, { message: "invalid connection authority" });
|
|
98158
98455
|
return parsed.data;
|
|
98159
98456
|
}
|
|
98160
98457
|
function lifecycleError2(error) {
|
|
98161
|
-
if (error instanceof
|
|
98162
|
-
throw new
|
|
98458
|
+
if (error instanceof SessionAuthorizationDeniedError16 || error instanceof SessionTenancyManagedHumanRequiredError3 || error instanceof SessionTenancyNotActivatedError3) {
|
|
98459
|
+
throw new HTTPException95(403, { message: "connection authority denied" });
|
|
98163
98460
|
}
|
|
98164
|
-
if (error instanceof
|
|
98165
|
-
throw new
|
|
98461
|
+
if (error instanceof SessionAuthorizationUnavailableError14) {
|
|
98462
|
+
throw new HTTPException95(503, { message: "session authorization unavailable" });
|
|
98166
98463
|
}
|
|
98167
98464
|
if (nestedPostgresSqlState12(error) === "42501") {
|
|
98168
|
-
throw new
|
|
98465
|
+
throw new HTTPException95(403, { message: "connection authority denied" });
|
|
98169
98466
|
}
|
|
98170
98467
|
if (nestedPostgresSqlState12(error) === "22023") {
|
|
98171
|
-
throw new
|
|
98468
|
+
throw new HTTPException95(422, { message: "invalid connection authority" });
|
|
98172
98469
|
}
|
|
98173
98470
|
throw error;
|
|
98174
98471
|
}
|
|
@@ -98180,9 +98477,9 @@ function registerConnectionAuthorityRoutes(app, deps) {
|
|
|
98180
98477
|
cursor: context.req.query("cursor"),
|
|
98181
98478
|
limit: context.req.query("limit")
|
|
98182
98479
|
});
|
|
98183
|
-
if (!query.success) throw new
|
|
98480
|
+
if (!query.success) throw new HTTPException95(422, { message: "explicit scope=user required" });
|
|
98184
98481
|
const workspaceId = context.req.param("workspaceId");
|
|
98185
|
-
const access = await
|
|
98482
|
+
const access = await requireAccessGrantAuthorization36(
|
|
98186
98483
|
context,
|
|
98187
98484
|
deps,
|
|
98188
98485
|
workspaceId,
|
|
@@ -98204,10 +98501,10 @@ function registerConnectionAuthorityRoutes(app, deps) {
|
|
|
98204
98501
|
});
|
|
98205
98502
|
app.post(`${base}/:authorityId/grants`, async (context) => {
|
|
98206
98503
|
const workspaceId = context.req.param("workspaceId");
|
|
98207
|
-
const authorityId =
|
|
98208
|
-
if (!authorityId.success) throw new
|
|
98504
|
+
const authorityId = z40.string().uuid().safeParse(context.req.param("authorityId"));
|
|
98505
|
+
if (!authorityId.success) throw new HTTPException95(422, { message: "invalid authority id" });
|
|
98209
98506
|
const request = await body3(context, IssueConnectionUseGrantRequest2);
|
|
98210
|
-
const access = await
|
|
98507
|
+
const access = await requireAccessGrantAuthorization36(
|
|
98211
98508
|
context,
|
|
98212
98509
|
deps,
|
|
98213
98510
|
workspaceId,
|
|
@@ -98234,11 +98531,11 @@ function registerConnectionAuthorityRoutes(app, deps) {
|
|
|
98234
98531
|
});
|
|
98235
98532
|
app.delete(`${base}/grants/:grantId`, async (context) => {
|
|
98236
98533
|
const query = RevokeConnectionUseGrantQuery.safeParse({ scope: context.req.query("scope") });
|
|
98237
|
-
if (!query.success) throw new
|
|
98238
|
-
const grantId =
|
|
98239
|
-
if (!grantId.success) throw new
|
|
98534
|
+
if (!query.success) throw new HTTPException95(422, { message: "explicit scope=user required" });
|
|
98535
|
+
const grantId = z40.string().uuid().safeParse(context.req.param("grantId"));
|
|
98536
|
+
if (!grantId.success) throw new HTTPException95(422, { message: "invalid grant id" });
|
|
98240
98537
|
const workspaceId = context.req.param("workspaceId");
|
|
98241
|
-
const access = await
|
|
98538
|
+
const access = await requireAccessGrantAuthorization36(
|
|
98242
98539
|
context,
|
|
98243
98540
|
deps,
|
|
98244
98541
|
workspaceId,
|
|
@@ -98825,7 +99122,7 @@ async function exactAvailable(providers, providerId, context) {
|
|
|
98825
99122
|
}
|
|
98826
99123
|
|
|
98827
99124
|
// src/integrations/slack-interactions.ts
|
|
98828
|
-
import { createHash as
|
|
99125
|
+
import { createHash as createHash30, createHmac as createHmac10, timingSafeEqual as timingSafeEqual3 } from "crypto";
|
|
98829
99126
|
import {
|
|
98830
99127
|
approvalIdentifier,
|
|
98831
99128
|
ApproveSlackUserLinkAccessRequest,
|
|
@@ -98928,14 +99225,14 @@ import {
|
|
|
98928
99225
|
acceptSessionUserMessage as acceptSessionUserMessage2,
|
|
98929
99226
|
controlHumanSessionWorkstream as controlHumanSessionWorkstream2,
|
|
98930
99227
|
createSessionForRequest as createSessionForRequest2,
|
|
98931
|
-
hasPermission as
|
|
99228
|
+
hasPermission as hasPermission24,
|
|
98932
99229
|
requireAccessContext as requireAccessContext5,
|
|
98933
99230
|
requireAccessGrant as requireAccessGrant46,
|
|
98934
99231
|
requireSessionAuthorizationListScope as requireSessionAuthorizationListScope4,
|
|
98935
99232
|
resolveWorkspaceCatalogSettings as resolveWorkspaceCatalogSettings9
|
|
98936
99233
|
} from "@opengeni/core";
|
|
98937
99234
|
import { publishDurableSessionEvents as publishDurableSessionEvents4 } from "@opengeni/events";
|
|
98938
|
-
import { HTTPException as
|
|
99235
|
+
import { HTTPException as HTTPException96 } from "hono/http-exception";
|
|
98939
99236
|
|
|
98940
99237
|
// src/integrations/slack-routing.ts
|
|
98941
99238
|
function isSlackDirectMessageConversation(entry2) {
|
|
@@ -99303,7 +99600,7 @@ function record4(value) {
|
|
|
99303
99600
|
}
|
|
99304
99601
|
|
|
99305
99602
|
// src/slack-reaction-files.ts
|
|
99306
|
-
import { createHash as
|
|
99603
|
+
import { createHash as createHash29 } from "crypto";
|
|
99307
99604
|
import { completeFileUpload as completeFileUpload5, prepareGeneratedWorkspaceFile as prepareGeneratedWorkspaceFile2 } from "@opengeni/db";
|
|
99308
99605
|
import { retryWhileMissing as retryWhileMissing7 } from "@opengeni/storage";
|
|
99309
99606
|
var IMPORT_IDENTITY_VERSION = "slack-reaction-image-v1";
|
|
@@ -99320,7 +99617,7 @@ async function importSlackReactionImage(dependencies, source, image, ordinal) {
|
|
|
99320
99617
|
if (image.bytes.byteLength < 1 || image.bytes.byteLength > 4 * 1024 * 1024) {
|
|
99321
99618
|
throw new Error("Slack reaction image size is invalid");
|
|
99322
99619
|
}
|
|
99323
|
-
const sha2564 =
|
|
99620
|
+
const sha2564 = createHash29("sha256").update(image.bytes).digest("hex");
|
|
99324
99621
|
const identity = slackReactionImageIdentity(source, image.fileId);
|
|
99325
99622
|
const fileId = deterministicUuid(`${identity}:file`);
|
|
99326
99623
|
const uploadId = deterministicUuid(`${identity}:upload`);
|
|
@@ -99414,7 +99711,7 @@ function assertStoredSlackImage(head, image, sha2564) {
|
|
|
99414
99711
|
}
|
|
99415
99712
|
}
|
|
99416
99713
|
function deterministicUuid(seed) {
|
|
99417
|
-
const bytes =
|
|
99714
|
+
const bytes = createHash29("sha256").update(seed, "utf8").digest().subarray(0, 16);
|
|
99418
99715
|
bytes[6] = (bytes[6] ?? 0) & 15 | 80;
|
|
99419
99716
|
bytes[8] = (bytes[8] ?? 0) & 63 | 128;
|
|
99420
99717
|
const hex2 = bytes.toString("hex");
|
|
@@ -99573,7 +99870,7 @@ function slackReactionInboxEntry(payload, bot, settings) {
|
|
|
99573
99870
|
if (!settings.enabled || !event || event.type !== "reaction_added" || item?.type !== "message" || !teamId || !eventId || !userId || userId === bot.botUserId || !reaction || reaction !== settings.emoji || !channelId || !workspaceSlackReactionChannelAllowed(settings, channelId) || !timestamp) {
|
|
99574
99871
|
return null;
|
|
99575
99872
|
}
|
|
99576
|
-
const stableReactionIdentity =
|
|
99873
|
+
const stableReactionIdentity = createHash30("sha256").update([teamId, userId, channelId, timestamp, reaction].join("\n")).digest("hex");
|
|
99577
99874
|
return {
|
|
99578
99875
|
providerEventId: eventId,
|
|
99579
99876
|
providerMessageId: `reaction:${stableReactionIdentity}`,
|
|
@@ -99609,14 +99906,14 @@ function registerSlackInteractionRoutes(app, deps) {
|
|
|
99609
99906
|
const payload = parseJsonObject(signed.rawBody);
|
|
99610
99907
|
if (payload.type === "url_verification") {
|
|
99611
99908
|
const challenge = boundedString(payload.challenge, 512);
|
|
99612
|
-
if (!challenge) throw new
|
|
99909
|
+
if (!challenge) throw new HTTPException96(400, { message: "invalid Slack challenge" });
|
|
99613
99910
|
return c.json({ challenge });
|
|
99614
99911
|
}
|
|
99615
99912
|
const teamId = boundedString(payload.team_id, 64);
|
|
99616
|
-
if (!teamId) throw new
|
|
99913
|
+
if (!teamId) throw new HTTPException96(400, { message: "invalid Slack event" });
|
|
99617
99914
|
const installation = await resolveSlackInstallationRoute(deps.db, teamId);
|
|
99618
99915
|
if (!installation)
|
|
99619
|
-
throw new
|
|
99916
|
+
throw new HTTPException96(403, {
|
|
99620
99917
|
message: "Slack installation unavailable"
|
|
99621
99918
|
});
|
|
99622
99919
|
const event = record5(payload.event);
|
|
@@ -99659,12 +99956,12 @@ function registerSlackInteractionRoutes(app, deps) {
|
|
|
99659
99956
|
const signed = await readSignedSlackRequest(c, deps);
|
|
99660
99957
|
const form = new URLSearchParams(signed.rawBody);
|
|
99661
99958
|
if (form.get("command") !== deps.settings.slackCommand) {
|
|
99662
|
-
throw new
|
|
99959
|
+
throw new HTTPException96(400, { message: "invalid Slack command" });
|
|
99663
99960
|
}
|
|
99664
99961
|
const entry2 = normalizedFormInteraction(form, "slash_command");
|
|
99665
99962
|
const installation = await resolveSlackInstallationRoute(deps.db, entry2.slackTeamId);
|
|
99666
99963
|
if (!installation)
|
|
99667
|
-
throw new
|
|
99964
|
+
throw new HTTPException96(403, {
|
|
99668
99965
|
message: "Slack installation unavailable"
|
|
99669
99966
|
});
|
|
99670
99967
|
if (isSlackInfoCommand(entry2.text)) {
|
|
@@ -99701,13 +99998,13 @@ function registerSlackInteractionRoutes(app, deps) {
|
|
|
99701
99998
|
const entry2 = normalizedBlockActionInteraction(payload);
|
|
99702
99999
|
const installation2 = await resolveSlackInstallationRoute(deps.db, entry2.slackTeamId);
|
|
99703
100000
|
if (!installation2) {
|
|
99704
|
-
throw new
|
|
100001
|
+
throw new HTTPException96(403, { message: "Slack installation unavailable" });
|
|
99705
100002
|
}
|
|
99706
100003
|
await enqueueNormalizedSlackInteraction(deps, installation2, entry2);
|
|
99707
100004
|
return c.json({ ok: true });
|
|
99708
100005
|
}
|
|
99709
100006
|
if (payload.type !== "message_action") {
|
|
99710
|
-
throw new
|
|
100007
|
+
throw new HTTPException96(400, {
|
|
99711
100008
|
message: "unsupported Slack interaction"
|
|
99712
100009
|
});
|
|
99713
100010
|
}
|
|
@@ -99723,13 +100020,13 @@ function registerSlackInteractionRoutes(app, deps) {
|
|
|
99723
100020
|
const threadTs = boundedString(message?.thread_ts, 64);
|
|
99724
100021
|
const text = boundedText(message?.text);
|
|
99725
100022
|
if (!triggerId || !teamId || !userId || !channelId || !messageTs || !text) {
|
|
99726
|
-
throw new
|
|
100023
|
+
throw new HTTPException96(400, {
|
|
99727
100024
|
message: "invalid Slack message shortcut"
|
|
99728
100025
|
});
|
|
99729
100026
|
}
|
|
99730
100027
|
const installation = await resolveSlackInstallationRoute(deps.db, teamId);
|
|
99731
100028
|
if (!installation)
|
|
99732
|
-
throw new
|
|
100029
|
+
throw new HTTPException96(403, {
|
|
99733
100030
|
message: "Slack installation unavailable"
|
|
99734
100031
|
});
|
|
99735
100032
|
await enqueueNormalizedSlackInteraction(deps, installation, {
|
|
@@ -99763,7 +100060,7 @@ function registerSlackInteractionRoutes(app, deps) {
|
|
|
99763
100060
|
const prepared = await prepareSlackUserLinkAccessRequest(deps.db, {
|
|
99764
100061
|
accountId: installation.accountId,
|
|
99765
100062
|
workspaceId,
|
|
99766
|
-
tokenDigest:
|
|
100063
|
+
tokenDigest: createHash30("sha256").update(payload.linkToken).digest("hex"),
|
|
99767
100064
|
connectionId: link.connectionId,
|
|
99768
100065
|
slackTeamId: link.slackTeamId,
|
|
99769
100066
|
slackUserId: link.slackUserId,
|
|
@@ -99950,19 +100247,19 @@ function registerSlackInteractionRoutes(app, deps) {
|
|
|
99950
100247
|
const linkToken = boundedString(body4?.linkToken, 2048);
|
|
99951
100248
|
const signingSecret = deps.settings.slackSigningSecret;
|
|
99952
100249
|
if (!linkToken || !signingSecret) {
|
|
99953
|
-
throw new
|
|
100250
|
+
throw new HTTPException96(400, {
|
|
99954
100251
|
message: "invalid or expired Slack identity link"
|
|
99955
100252
|
});
|
|
99956
100253
|
}
|
|
99957
100254
|
const link = verifySlackUserLinkToken(signingSecret, linkToken);
|
|
99958
100255
|
if (!link || link.workspaceId !== workspaceId) {
|
|
99959
|
-
throw new
|
|
100256
|
+
throw new HTTPException96(400, {
|
|
99960
100257
|
message: "invalid or expired Slack identity link"
|
|
99961
100258
|
});
|
|
99962
100259
|
}
|
|
99963
100260
|
const installation = await resolveSlackLinkTargetInstallation(deps, link, workspaceId);
|
|
99964
100261
|
if (!installation) {
|
|
99965
|
-
throw new
|
|
100262
|
+
throw new HTTPException96(404, {
|
|
99966
100263
|
message: "Slack installation not found"
|
|
99967
100264
|
});
|
|
99968
100265
|
}
|
|
@@ -99970,7 +100267,7 @@ function registerSlackInteractionRoutes(app, deps) {
|
|
|
99970
100267
|
const prepared = await prepareSlackUserLinkAccessRequest(deps.db, {
|
|
99971
100268
|
accountId: grant.accountId,
|
|
99972
100269
|
workspaceId,
|
|
99973
|
-
tokenDigest:
|
|
100270
|
+
tokenDigest: createHash30("sha256").update(linkToken).digest("hex"),
|
|
99974
100271
|
connectionId: link.connectionId,
|
|
99975
100272
|
slackTeamId: link.slackTeamId,
|
|
99976
100273
|
slackUserId: link.slackUserId,
|
|
@@ -100003,7 +100300,7 @@ function registerSlackInteractionRoutes(app, deps) {
|
|
|
100003
100300
|
const workspaceId = c.req.param("workspaceId");
|
|
100004
100301
|
await requireAccessGrant46(c, deps, workspaceId, "connections:write");
|
|
100005
100302
|
const connectionId = boundedString(c.req.query("connectionId"), 64);
|
|
100006
|
-
if (!connectionId) throw new
|
|
100303
|
+
if (!connectionId) throw new HTTPException96(400, { message: "connectionId is required" });
|
|
100007
100304
|
return c.json({
|
|
100008
100305
|
deleted: await deleteSlackBotUserLink(
|
|
100009
100306
|
deps.db,
|
|
@@ -100018,7 +100315,7 @@ function registerSlackInteractionRoutes(app, deps) {
|
|
|
100018
100315
|
const workspaceId = c.req.param("workspaceId");
|
|
100019
100316
|
const grant = await requireAccessGrant46(c, deps, workspaceId, "workspace:admin");
|
|
100020
100317
|
const connectionId = boundedString(c.req.query("connectionId"), 64);
|
|
100021
|
-
if (!connectionId) throw new
|
|
100318
|
+
if (!connectionId) throw new HTTPException96(400, { message: "connectionId is required" });
|
|
100022
100319
|
const routes = await listSlackChannelRoutes(
|
|
100023
100320
|
deps.db,
|
|
100024
100321
|
{ accountId: grant.accountId, workspaceId },
|
|
@@ -100055,7 +100352,7 @@ function registerSlackInteractionRoutes(app, deps) {
|
|
|
100055
100352
|
(candidate) => candidate.connectionId === payload.connectionId
|
|
100056
100353
|
);
|
|
100057
100354
|
if (!binding) {
|
|
100058
|
-
throw new
|
|
100355
|
+
throw new HTTPException96(404, { message: "Slack installation not found" });
|
|
100059
100356
|
}
|
|
100060
100357
|
const callerPersonalWorkspaceId = await namedSubjectPersonalWorkspaceId2(deps.db, {
|
|
100061
100358
|
accountId: grant.accountId,
|
|
@@ -100068,13 +100365,13 @@ function registerSlackInteractionRoutes(app, deps) {
|
|
|
100068
100365
|
targetAccountId: grant.accountId,
|
|
100069
100366
|
targetWorkspaceId: route.targetWorkspaceId
|
|
100070
100367
|
});
|
|
100071
|
-
if (!authorized || !
|
|
100072
|
-
throw new
|
|
100368
|
+
if (!authorized || !hasPermission24(authorized.permissions, "sessions:create")) {
|
|
100369
|
+
throw new HTTPException96(403, {
|
|
100073
100370
|
message: `you cannot start work in the workspace chosen for ${route.slackChannelId}`
|
|
100074
100371
|
});
|
|
100075
100372
|
}
|
|
100076
100373
|
if (callerPersonalWorkspaceId !== null && route.targetWorkspaceId === callerPersonalWorkspaceId) {
|
|
100077
|
-
throw new
|
|
100374
|
+
throw new HTTPException96(422, {
|
|
100078
100375
|
message: `a channel cannot be routed to a personal workspace: work started in ${route.slackChannelId} would be invisible to everyone else in it`
|
|
100079
100376
|
});
|
|
100080
100377
|
}
|
|
@@ -100104,7 +100401,7 @@ function registerSlackInteractionRoutes(app, deps) {
|
|
|
100104
100401
|
const workspaceId = c.req.param("workspaceId");
|
|
100105
100402
|
const grant = await requireAccessGrant46(c, deps, workspaceId, "workspace:admin");
|
|
100106
100403
|
const connectionId = boundedString(c.req.query("connectionId"), 64);
|
|
100107
|
-
if (!connectionId) throw new
|
|
100404
|
+
if (!connectionId) throw new HTTPException96(400, { message: "connectionId is required" });
|
|
100108
100405
|
const cursor = boundedString(c.req.query("cursor"), 1024);
|
|
100109
100406
|
const client = await createOpenGeniSlackBotInteractionClient(deps, {
|
|
100110
100407
|
accountId: grant.accountId,
|
|
@@ -100151,7 +100448,7 @@ async function publishSlackAppHome(deps, installation, refresh, renewLease) {
|
|
|
100151
100448
|
const grant = link ? await getWorkspaceGrant4(deps.db, link.subjectId, installation.workspaceId, {
|
|
100152
100449
|
principalKind: "human_session"
|
|
100153
100450
|
}) : null;
|
|
100154
|
-
if (!grant || grant.accountId !== installation.accountId || !
|
|
100451
|
+
if (!grant || grant.accountId !== installation.accountId || !hasPermission24(grant.permissions, "sessions:read")) {
|
|
100155
100452
|
const client2 = await createOpenGeniSlackBotInteractionClient(deps, {
|
|
100156
100453
|
accountId: installation.accountId,
|
|
100157
100454
|
workspaceId: installation.workspaceId,
|
|
@@ -100229,7 +100526,7 @@ async function publishSlackAppHome(deps, installation, refresh, renewLease) {
|
|
|
100229
100526
|
const currentGrant = currentLink ? await getWorkspaceGrant4(deps.db, currentLink.subjectId, installation.workspaceId, {
|
|
100230
100527
|
principalKind: "human_session"
|
|
100231
100528
|
}) : null;
|
|
100232
|
-
if (!currentLink || currentLink.subjectId !== grant.subjectId || !currentGrant || currentGrant.accountId !== installation.accountId || !
|
|
100529
|
+
if (!currentLink || currentLink.subjectId !== grant.subjectId || !currentGrant || currentGrant.accountId !== installation.accountId || !hasPermission24(currentGrant.permissions, "sessions:read")) {
|
|
100233
100530
|
await publishSlackAppHomeAccessView(
|
|
100234
100531
|
client,
|
|
100235
100532
|
refresh,
|
|
@@ -100694,7 +100991,7 @@ async function handleSlackRouteChoice(deps, home, entry2, actionId, optionId) {
|
|
|
100694
100991
|
targetAccountId: chosen.candidateAccountId,
|
|
100695
100992
|
targetWorkspaceId: chosen.candidateWorkspaceId
|
|
100696
100993
|
}) : null;
|
|
100697
|
-
if (!grant || !
|
|
100994
|
+
if (!grant || !hasPermission24(grant.permissions, "sessions:create")) {
|
|
100698
100995
|
await client.postMessage({
|
|
100699
100996
|
operationId: deterministicUuid2(`slack-route-denied:${prompt.id}:${chosen.id}`),
|
|
100700
100997
|
userId: entry2.slackUserId,
|
|
@@ -100892,7 +101189,7 @@ async function processSlackInboxEntry(deps, entry2) {
|
|
|
100892
101189
|
});
|
|
100893
101190
|
return;
|
|
100894
101191
|
}
|
|
100895
|
-
if (!
|
|
101192
|
+
if (!hasPermission24(grant.permissions, "sessions:create")) {
|
|
100896
101193
|
throw new SlackInteractionPermanentError("sessions_create_denied");
|
|
100897
101194
|
}
|
|
100898
101195
|
const { interaction } = await getOrCreateSlackInteraction(deps.db, {
|
|
@@ -100955,7 +101252,7 @@ async function processSlackInboxEntry(deps, entry2) {
|
|
|
100955
101252
|
}
|
|
100956
101253
|
);
|
|
100957
101254
|
} catch (error) {
|
|
100958
|
-
if (error instanceof
|
|
101255
|
+
if (error instanceof HTTPException96) {
|
|
100959
101256
|
await client.postMessage({
|
|
100960
101257
|
operationId: deterministicUuid2(`slack-admission-failed:${interaction.id}`),
|
|
100961
101258
|
...routePolicy.directMessageShortcut ? { userId: entry2.slackUserId } : {
|
|
@@ -101222,7 +101519,7 @@ async function processSlackReactionInboxEntry(deps, entry2) {
|
|
|
101222
101519
|
if (!resolved) {
|
|
101223
101520
|
throw new SlackInteractionPermanentError("identity_access_revoked");
|
|
101224
101521
|
}
|
|
101225
|
-
if (!
|
|
101522
|
+
if (!hasPermission24(resolved.permissions, "sessions:create") || !hasPermission24(resolved.permissions, "sessions:control")) {
|
|
101226
101523
|
throw new SlackInteractionPermanentError("reaction_session_permissions_denied");
|
|
101227
101524
|
}
|
|
101228
101525
|
return resolved;
|
|
@@ -101392,7 +101689,7 @@ async function processSlackReactionInboxEntry(deps, entry2) {
|
|
|
101392
101689
|
);
|
|
101393
101690
|
await acceptSlackReactionTask(deps, grant, session.id, preparedEntry, preparedTask.resources);
|
|
101394
101691
|
} catch (error) {
|
|
101395
|
-
if (error instanceof
|
|
101692
|
+
if (error instanceof HTTPException96) {
|
|
101396
101693
|
await client.postMessage({
|
|
101397
101694
|
operationId: deterministicUuid2(`slack-reaction-admission-failed:${interaction.id}`),
|
|
101398
101695
|
channelId: entry2.slackChannelId,
|
|
@@ -101692,7 +101989,7 @@ async function continueSlackSession(deps, grant, interaction, entry2, resources
|
|
|
101692
101989
|
}
|
|
101693
101990
|
await reopenSlackInteractionDelivery(deps.db, interaction);
|
|
101694
101991
|
if (entry2.text.trim().toLowerCase() === "stop") {
|
|
101695
|
-
if (!
|
|
101992
|
+
if (!hasPermission24(grant.permissions, "sessions:control")) {
|
|
101696
101993
|
throw new SlackInteractionPermanentError("sessions_control_denied");
|
|
101697
101994
|
}
|
|
101698
101995
|
await controlHumanSessionWorkstream2(
|
|
@@ -101753,7 +102050,7 @@ async function continueSlackSession(deps, grant, interaction, entry2, resources
|
|
|
101753
102050
|
}
|
|
101754
102051
|
}
|
|
101755
102052
|
}
|
|
101756
|
-
if (!
|
|
102053
|
+
if (!hasPermission24(grant.permissions, "sessions:control")) {
|
|
101757
102054
|
throw new SlackInteractionPermanentError("sessions_control_denied");
|
|
101758
102055
|
}
|
|
101759
102056
|
await acceptSessionUserMessage2(
|
|
@@ -101841,7 +102138,7 @@ async function processSlackBlockAction(deps, entry2) {
|
|
|
101841
102138
|
targetAccountId: target.accountId,
|
|
101842
102139
|
targetWorkspaceId: target.workspaceId
|
|
101843
102140
|
});
|
|
101844
|
-
if (!grant || !
|
|
102141
|
+
if (!grant || !hasPermission24(grant.permissions, "sessions:control")) {
|
|
101845
102142
|
throw new SlackInteractionPermanentError("sessions_control_denied");
|
|
101846
102143
|
}
|
|
101847
102144
|
const client = await createOpenGeniSlackBotInteractionClient(deps, {
|
|
@@ -102032,7 +102329,7 @@ async function executeSlackAction(deps, grant, interaction, handle) {
|
|
|
102032
102329
|
}
|
|
102033
102330
|
const session = await getSession11(deps.db, grant.workspaceId, handle.sessionId);
|
|
102034
102331
|
if (!session) throw new SlackInteractionPermanentError("slack_action_session_missing");
|
|
102035
|
-
const recurring =
|
|
102332
|
+
const recurring = hasPermission24(grant.permissions, "sessions:read") && hasPermission24(grant.permissions, "scheduled_tasks:manage") ? makeRecurringText(deps, grant.workspaceId, handle.sessionId) : null;
|
|
102036
102333
|
return {
|
|
102037
102334
|
result: "status",
|
|
102038
102335
|
text: `${mention}OpenGeni task status: *${session.status.replaceAll("_", " ")}*.${recurring ? `
|
|
@@ -102789,12 +103086,12 @@ async function enqueueNormalizedSlackInteraction(deps, route, entry2) {
|
|
|
102789
103086
|
async function readSignedSlackRequest(c, deps) {
|
|
102790
103087
|
const signingSecret = deps.settings.slackSigningSecret;
|
|
102791
103088
|
if (!signingSecret)
|
|
102792
|
-
throw new
|
|
103089
|
+
throw new HTTPException96(503, {
|
|
102793
103090
|
message: "Slack interactions are disabled"
|
|
102794
103091
|
});
|
|
102795
103092
|
const rawBytes = new Uint8Array(await c.req.raw.arrayBuffer());
|
|
102796
103093
|
if (rawBytes.byteLength === 0 || rawBytes.byteLength > SLACK_INTERACTION_MAX_BODY_BYTES) {
|
|
102797
|
-
throw new
|
|
103094
|
+
throw new HTTPException96(rawBytes.byteLength > SLACK_INTERACTION_MAX_BODY_BYTES ? 413 : 400, {
|
|
102798
103095
|
message: "invalid Slack request body"
|
|
102799
103096
|
});
|
|
102800
103097
|
}
|
|
@@ -102807,7 +103104,7 @@ async function readSignedSlackRequest(c, deps) {
|
|
|
102807
103104
|
},
|
|
102808
103105
|
signingSecret
|
|
102809
103106
|
)) {
|
|
102810
|
-
throw new
|
|
103107
|
+
throw new HTTPException96(401, { message: "invalid Slack signature" });
|
|
102811
103108
|
}
|
|
102812
103109
|
return { rawBody };
|
|
102813
103110
|
}
|
|
@@ -102818,7 +103115,7 @@ function normalizedFormInteraction(form, triggerKind) {
|
|
|
102818
103115
|
const triggerId = boundedString(form.get("trigger_id"), 256);
|
|
102819
103116
|
const text = boundedText(form.get("text"));
|
|
102820
103117
|
if (!teamId || !userId || !channelId || !triggerId || !text) {
|
|
102821
|
-
throw new
|
|
103118
|
+
throw new HTTPException96(400, { message: "invalid Slack command payload" });
|
|
102822
103119
|
}
|
|
102823
103120
|
return {
|
|
102824
103121
|
providerEventId: `command:${triggerId}`,
|
|
@@ -102861,9 +103158,9 @@ function normalizedBlockActionInteraction(payload) {
|
|
|
102861
103158
|
const actionId = boundedString(action?.action_id, 128);
|
|
102862
103159
|
const handleId = boundedString(action?.value, 64);
|
|
102863
103160
|
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) {
|
|
102864
|
-
throw new
|
|
103161
|
+
throw new HTTPException96(400, { message: "invalid Slack block action" });
|
|
102865
103162
|
}
|
|
102866
|
-
const identity =
|
|
103163
|
+
const identity = createHash30("sha256").update([teamId, userId, channelId, messageTs, actionTs, actionId, handleId].join("\n")).digest("hex");
|
|
102867
103164
|
return {
|
|
102868
103165
|
providerEventId: `block:${identity}`,
|
|
102869
103166
|
providerMessageId: `block:${identity}`,
|
|
@@ -102928,7 +103225,7 @@ async function slackInfoCommandResponse(deps, installation, entry2) {
|
|
|
102928
103225
|
const grant = link ? await getWorkspaceGrant4(deps.db, link.subjectId, installation.workspaceId, {
|
|
102929
103226
|
principalKind: "human_session"
|
|
102930
103227
|
}) : null;
|
|
102931
|
-
if (!grant || grant.accountId !== installation.accountId || !
|
|
103228
|
+
if (!grant || grant.accountId !== installation.accountId || !hasPermission24(grant.permissions, "sessions:read")) {
|
|
102932
103229
|
return ephemeralSlackResponse(
|
|
102933
103230
|
link ? `Your Slack identity is linked, but it does not currently have access to this OpenGeni workspace. Request access: ${linkUrl(deps, identity)}. No session was created.` : `Link your Slack identity to OpenGeni before starting work: ${linkUrl(deps, identity)}. No session was created.`
|
|
102934
103231
|
);
|
|
@@ -102936,9 +103233,9 @@ async function slackInfoCommandResponse(deps, installation, entry2) {
|
|
|
102936
103233
|
const workspace = await getWorkspace6(deps.db, installation.workspaceId);
|
|
102937
103234
|
const command = deps.settings.slackCommand;
|
|
102938
103235
|
const botMention = slackBotMention(installation.botUserId);
|
|
102939
|
-
const canControl =
|
|
102940
|
-
const canCreate =
|
|
102941
|
-
const schedules =
|
|
103236
|
+
const canControl = hasPermission24(grant.permissions, "sessions:control");
|
|
103237
|
+
const canCreate = hasPermission24(grant.permissions, "sessions:create");
|
|
103238
|
+
const schedules = hasPermission24(grant.permissions, "scheduled_tasks:manage") ? slackSchedulesUrl(deps, installation.workspaceId) : null;
|
|
102942
103239
|
const workspaceUrl = slackWorkspaceUrl(deps, installation.workspaceId);
|
|
102943
103240
|
const workspaceName = (workspace?.name ?? "").trim().slice(0, 120);
|
|
102944
103241
|
const destination = workspaceName ? `the *${escapeSlackMrkdwn(workspaceName)}* workspace` : "your OpenGeni workspace";
|
|
@@ -103051,29 +103348,29 @@ function linkUrl(deps, entry2, mintedAtMs) {
|
|
|
103051
103348
|
}
|
|
103052
103349
|
async function requireManagedSlackLinkHuman(c, deps) {
|
|
103053
103350
|
if (c.req.header("authorization")) {
|
|
103054
|
-
throw new
|
|
103351
|
+
throw new HTTPException96(401, { message: "managed browser sign-in required" });
|
|
103055
103352
|
}
|
|
103056
103353
|
const context = await requireAccessContext5(c, deps);
|
|
103057
103354
|
if (context.mode !== "managed" || !context.subjectId.startsWith("user:")) {
|
|
103058
|
-
throw new
|
|
103355
|
+
throw new HTTPException96(403, { message: "managed browser sign-in required" });
|
|
103059
103356
|
}
|
|
103060
103357
|
return context;
|
|
103061
103358
|
}
|
|
103062
103359
|
function freshSlackLinkRequired() {
|
|
103063
|
-
return new
|
|
103360
|
+
return new HTTPException96(400, {
|
|
103064
103361
|
message: "This Slack link is invalid or expired. Request a fresh link from Slack."
|
|
103065
103362
|
});
|
|
103066
103363
|
}
|
|
103067
103364
|
function slackLinkAccessHttpError(error) {
|
|
103068
|
-
if (error instanceof
|
|
103365
|
+
if (error instanceof HTTPException96) return error;
|
|
103069
103366
|
if (!(error instanceof SlackUserLinkAccessPersistenceError)) throw error;
|
|
103070
103367
|
if (error.code === "version_conflict" || error.code === "idempotency_conflict") {
|
|
103071
|
-
return new
|
|
103368
|
+
return new HTTPException96(409, {
|
|
103072
103369
|
message: "The Slack access request changed. Refresh and try again."
|
|
103073
103370
|
});
|
|
103074
103371
|
}
|
|
103075
103372
|
if (error.code === "state_conflict") {
|
|
103076
|
-
return new
|
|
103373
|
+
return new HTTPException96(409, {
|
|
103077
103374
|
message: "This Slack link is no longer pending. Request a fresh link from Slack."
|
|
103078
103375
|
});
|
|
103079
103376
|
}
|
|
@@ -103128,7 +103425,7 @@ function usesPrivateBotDm(interaction, entry2) {
|
|
|
103128
103425
|
return isDirectMessageShortcut(entry2) || interaction.visibility === "private" && entry2.triggerKind !== "dm";
|
|
103129
103426
|
}
|
|
103130
103427
|
function deterministicUuid2(value) {
|
|
103131
|
-
const bytes =
|
|
103428
|
+
const bytes = createHash30("sha256").update(value).digest().subarray(0, 16);
|
|
103132
103429
|
bytes[6] = bytes[6] & 15 | 80;
|
|
103133
103430
|
bytes[8] = bytes[8] & 63 | 128;
|
|
103134
103431
|
const hex2 = bytes.toString("hex");
|
|
@@ -103141,7 +103438,7 @@ function parseJsonObject(value) {
|
|
|
103141
103438
|
if (result) return result;
|
|
103142
103439
|
} catch {
|
|
103143
103440
|
}
|
|
103144
|
-
throw new
|
|
103441
|
+
throw new HTTPException96(400, { message: "invalid Slack JSON payload" });
|
|
103145
103442
|
}
|
|
103146
103443
|
function record5(value) {
|
|
103147
103444
|
return value && typeof value === "object" && !Array.isArray(value) ? value : null;
|
|
@@ -103171,7 +103468,7 @@ function safeErrorCode(error) {
|
|
|
103171
103468
|
if (error instanceof SlackBotProviderError) return error.code.slice(0, 128);
|
|
103172
103469
|
if (error instanceof SlackInteractionPermanentError) return error.code.slice(0, 128);
|
|
103173
103470
|
if (error instanceof SlackInteractionRetryableError) return error.code.slice(0, 128);
|
|
103174
|
-
if (error instanceof
|
|
103471
|
+
if (error instanceof HTTPException96) return `http_${error.status}`;
|
|
103175
103472
|
const raw = error instanceof Error ? error.name : "slack_interaction_error";
|
|
103176
103473
|
return raw.toLowerCase().replace(/[^a-z0-9_-]/g, "_").slice(0, 128) || "error";
|
|
103177
103474
|
}
|
|
@@ -103199,7 +103496,7 @@ var SlackInteractionRetryableError = class extends Error {
|
|
|
103199
103496
|
}
|
|
103200
103497
|
};
|
|
103201
103498
|
function permanentSlackInteractionError(error) {
|
|
103202
|
-
return error instanceof SlackInteractionPermanentError || error instanceof
|
|
103499
|
+
return error instanceof SlackInteractionPermanentError || error instanceof HTTPException96;
|
|
103203
103500
|
}
|
|
103204
103501
|
var PERMANENT_SLACK_DELIVERY_CODES = /* @__PURE__ */ new Set([
|
|
103205
103502
|
"account_inactive",
|
|
@@ -103299,7 +103596,7 @@ function createAppComposition(deps) {
|
|
|
103299
103596
|
authoritySubjectId
|
|
103300
103597
|
}) => {
|
|
103301
103598
|
if (!objectStorage) {
|
|
103302
|
-
throw new
|
|
103599
|
+
throw new HTTPException97(503, {
|
|
103303
103600
|
message: "object storage is not configured"
|
|
103304
103601
|
});
|
|
103305
103602
|
}
|
|
@@ -103557,7 +103854,7 @@ function createAppComposition(deps) {
|
|
|
103557
103854
|
} catch (error) {
|
|
103558
103855
|
if (error instanceof ManagedAuthActorChangeError2) {
|
|
103559
103856
|
c.header("x-opengeni-actor-state", "changed");
|
|
103560
|
-
throw new
|
|
103857
|
+
throw new HTTPException97(409, { message: error.code, cause: error });
|
|
103561
103858
|
}
|
|
103562
103859
|
if (error instanceof ManagedAuthActorLeaseOutcomeUnknownError) {
|
|
103563
103860
|
throw new ApiHttpError(503, {
|
|
@@ -103602,7 +103899,7 @@ function createAppComposition(deps) {
|
|
|
103602
103899
|
deps.settings.publicBaseUrl
|
|
103603
103900
|
);
|
|
103604
103901
|
if (!attempt || !authority || attempt.authorityHash !== managedAuthSha2562(authority)) {
|
|
103605
|
-
throw new
|
|
103902
|
+
throw new HTTPException97(409, { message: "provider_route_blocked" });
|
|
103606
103903
|
}
|
|
103607
103904
|
const isolated = await isolatedManagedAuthOAuthCallbackRequest(managedAuth, c.req.raw);
|
|
103608
103905
|
preserveCookieNames = [isolated.stateCookieName];
|
|
@@ -103816,7 +104113,7 @@ function createAppComposition(deps) {
|
|
|
103816
104113
|
boundedRequest = await boundedMcpRequest(c.req.raw);
|
|
103817
104114
|
} catch (error) {
|
|
103818
104115
|
if (error instanceof McpPayloadTooLargeError) {
|
|
103819
|
-
throw new
|
|
104116
|
+
throw new HTTPException97(413, {
|
|
103820
104117
|
message: "MCP request body exceeds the safety limit"
|
|
103821
104118
|
});
|
|
103822
104119
|
}
|
|
@@ -103826,7 +104123,7 @@ function createAppComposition(deps) {
|
|
|
103826
104123
|
try {
|
|
103827
104124
|
oauthAccess = await resolveMcpOAuthRouteAccess(routeDeps, c.req.raw, workspaceId);
|
|
103828
104125
|
} catch (error) {
|
|
103829
|
-
if (error instanceof
|
|
104126
|
+
if (error instanceof HTTPException97 && error.status === 401) {
|
|
103830
104127
|
c.header(
|
|
103831
104128
|
"www-authenticate",
|
|
103832
104129
|
mcpOAuthAuthenticateHeader(routeDeps, new URL(c.req.url).pathname)
|
|
@@ -103861,7 +104158,7 @@ function createAppComposition(deps) {
|
|
|
103861
104158
|
try {
|
|
103862
104159
|
authorization = await requireMcpAccessGrantAuthorization(c, routeDeps, workspaceId);
|
|
103863
104160
|
} catch (error) {
|
|
103864
|
-
if (deps.settings.mcpOauthEnabled && error instanceof
|
|
104161
|
+
if (deps.settings.mcpOauthEnabled && error instanceof HTTPException97 && error.status === 401) {
|
|
103865
104162
|
c.header(
|
|
103866
104163
|
"www-authenticate",
|
|
103867
104164
|
mcpOAuthAuthenticateHeader(routeDeps, new URL(c.req.url).pathname)
|
|
@@ -103874,17 +104171,17 @@ function createAppComposition(deps) {
|
|
|
103874
104171
|
const boundSessionId = grant.metadata?.sessionId;
|
|
103875
104172
|
if (typeof boundSessionId === "string") {
|
|
103876
104173
|
try {
|
|
103877
|
-
await
|
|
104174
|
+
await requireSessionAuthorization16(routeDeps, grant, {
|
|
103878
104175
|
sessionId: boundSessionId,
|
|
103879
104176
|
operation: "session.first_party_mcp.call",
|
|
103880
104177
|
surface: "first_party_mcp"
|
|
103881
104178
|
});
|
|
103882
104179
|
} catch (error) {
|
|
103883
|
-
if (error instanceof
|
|
103884
|
-
throw new
|
|
104180
|
+
if (error instanceof SessionAuthorizationDeniedError17) {
|
|
104181
|
+
throw new HTTPException97(404, { message: "session not found" });
|
|
103885
104182
|
}
|
|
103886
|
-
if (error instanceof
|
|
103887
|
-
throw new
|
|
104183
|
+
if (error instanceof SessionAuthorizationUnavailableError15) {
|
|
104184
|
+
throw new HTTPException97(503, {
|
|
103888
104185
|
message: "session authorization is unavailable"
|
|
103889
104186
|
});
|
|
103890
104187
|
}
|
|
@@ -103930,7 +104227,7 @@ function createAppComposition(deps) {
|
|
|
103930
104227
|
});
|
|
103931
104228
|
app.get("/v1/workspaces/:workspaceId/tools/catalog", async (c) => {
|
|
103932
104229
|
const workspaceId = c.req.param("workspaceId");
|
|
103933
|
-
const authorization = await
|
|
104230
|
+
const authorization = await requireAccessGrantAuthorization37(
|
|
103934
104231
|
c,
|
|
103935
104232
|
routeDeps,
|
|
103936
104233
|
workspaceId,
|
|
@@ -103946,7 +104243,7 @@ function createAppComposition(deps) {
|
|
|
103946
104243
|
});
|
|
103947
104244
|
app.post("/v1/workspaces/:workspaceId/tools/calls", async (c) => {
|
|
103948
104245
|
const workspaceId = c.req.param("workspaceId");
|
|
103949
|
-
const authorization = await
|
|
104246
|
+
const authorization = await requireAccessGrantAuthorization37(
|
|
103950
104247
|
c,
|
|
103951
104248
|
routeDeps,
|
|
103952
104249
|
workspaceId,
|
|
@@ -103955,7 +104252,7 @@ function createAppComposition(deps) {
|
|
|
103955
104252
|
const grant = authorization.grant;
|
|
103956
104253
|
const parsed = ToolGatewayCallRequest2.safeParse(await c.req.json().catch(() => null));
|
|
103957
104254
|
if (!parsed.success) {
|
|
103958
|
-
throw new
|
|
104255
|
+
throw new HTTPException97(400, { message: "Invalid tool gateway call" });
|
|
103959
104256
|
}
|
|
103960
104257
|
const prepared = await prepareWorkspaceToolGateway(routeDeps, authorization);
|
|
103961
104258
|
try {
|
|
@@ -103975,7 +104272,7 @@ function createAppComposition(deps) {
|
|
|
103975
104272
|
});
|
|
103976
104273
|
app.post("/v1/workspaces/:workspaceId/tools/approvals", async (c) => {
|
|
103977
104274
|
const workspaceId = c.req.param("workspaceId");
|
|
103978
|
-
const authorization = await
|
|
104275
|
+
const authorization = await requireAccessGrantAuthorization37(
|
|
103979
104276
|
c,
|
|
103980
104277
|
routeDeps,
|
|
103981
104278
|
workspaceId,
|
|
@@ -103983,7 +104280,7 @@ function createAppComposition(deps) {
|
|
|
103983
104280
|
);
|
|
103984
104281
|
const parsed = ToolGatewayApprovalRequest2.safeParse(await c.req.json().catch(() => null));
|
|
103985
104282
|
if (!parsed.success) {
|
|
103986
|
-
throw new
|
|
104283
|
+
throw new HTTPException97(400, { message: "Invalid tool gateway approval" });
|
|
103987
104284
|
}
|
|
103988
104285
|
const prepared = await prepareWorkspaceToolGateway(routeDeps, authorization);
|
|
103989
104286
|
try {
|
|
@@ -104004,7 +104301,7 @@ function createAppComposition(deps) {
|
|
|
104004
104301
|
});
|
|
104005
104302
|
app.get("/v1/workspaces/:workspaceId/tools/declarations", async (c) => {
|
|
104006
104303
|
const workspaceId = c.req.param("workspaceId");
|
|
104007
|
-
const authorization = await
|
|
104304
|
+
const authorization = await requireAccessGrantAuthorization37(
|
|
104008
104305
|
c,
|
|
104009
104306
|
routeDeps,
|
|
104010
104307
|
workspaceId,
|
|
@@ -104040,7 +104337,7 @@ function createAppComposition(deps) {
|
|
|
104040
104337
|
const workspaceId = c.req.param("workspaceId");
|
|
104041
104338
|
const grant = await requireAccessGrant47(c, routeDeps, workspaceId);
|
|
104042
104339
|
if (!isCodemodeGrant(grant)) {
|
|
104043
|
-
throw new
|
|
104340
|
+
throw new HTTPException97(403, { message: "Codemode access denied" });
|
|
104044
104341
|
}
|
|
104045
104342
|
try {
|
|
104046
104343
|
return c.json((await requireActiveCodemodeCatalog(routeDeps, grant)).catalog);
|
|
@@ -104052,11 +104349,11 @@ function createAppComposition(deps) {
|
|
|
104052
104349
|
const workspaceId = c.req.param("workspaceId");
|
|
104053
104350
|
const grant = await requireAccessGrant47(c, routeDeps, workspaceId);
|
|
104054
104351
|
if (!isCodemodeGrant(grant)) {
|
|
104055
|
-
throw new
|
|
104352
|
+
throw new HTTPException97(403, { message: "Codemode access denied" });
|
|
104056
104353
|
}
|
|
104057
104354
|
const parsed = CodemodeCallRequest2.safeParse(await c.req.json().catch(() => null));
|
|
104058
104355
|
if (!parsed.success) {
|
|
104059
|
-
throw new
|
|
104356
|
+
throw new HTTPException97(400, { message: "Invalid Codemode call" });
|
|
104060
104357
|
}
|
|
104061
104358
|
try {
|
|
104062
104359
|
const submission = await submitAndDispatchCodemodeCall(routeDeps, grant, parsed.data);
|
|
@@ -104072,17 +104369,17 @@ function createAppComposition(deps) {
|
|
|
104072
104369
|
const workspaceId = c.req.param("workspaceId");
|
|
104073
104370
|
const grant = await requireAccessGrant47(c, routeDeps, workspaceId);
|
|
104074
104371
|
if (!isCodemodeGrant(grant)) {
|
|
104075
|
-
throw new
|
|
104372
|
+
throw new HTTPException97(403, { message: "Codemode access denied" });
|
|
104076
104373
|
}
|
|
104077
104374
|
try {
|
|
104078
104375
|
const operation = await readCodemodeOperation(routeDeps, grant, c.req.param("operationId"));
|
|
104079
104376
|
if (!operation)
|
|
104080
|
-
throw new
|
|
104377
|
+
throw new HTTPException97(404, {
|
|
104081
104378
|
message: "Codemode operation not found"
|
|
104082
104379
|
});
|
|
104083
104380
|
return c.json(operation);
|
|
104084
104381
|
} catch (error) {
|
|
104085
|
-
if (error instanceof
|
|
104382
|
+
if (error instanceof HTTPException97) throw error;
|
|
104086
104383
|
throw codemodeHttpError(error);
|
|
104087
104384
|
}
|
|
104088
104385
|
});
|
|
@@ -104108,6 +104405,7 @@ function createAppComposition(deps) {
|
|
|
104108
104405
|
registerWorkspaceStateRoutes(app, routeDeps);
|
|
104109
104406
|
registerMemorySlackPublicationRoutes(app, routeDeps);
|
|
104110
104407
|
registerWorkspaceArtifactRoutes(app, routeDeps);
|
|
104408
|
+
registerArtifactCatalogRoutes(app, routeDeps);
|
|
104111
104409
|
registerPreferenceRegistryRoutes(app, routeDeps);
|
|
104112
104410
|
registerSocialRoutes(app, routeDeps);
|
|
104113
104411
|
registerPersonalGitHubRoutes(app, routeDeps);
|
|
@@ -104196,7 +104494,7 @@ function managedAuthOAuthCallbackProvider(pathname) {
|
|
|
104196
104494
|
}
|
|
104197
104495
|
function mutationOutcomeUnknown(error, method) {
|
|
104198
104496
|
if (method === "GET" || method === "HEAD" || method === "OPTIONS") return false;
|
|
104199
|
-
const cause = error instanceof
|
|
104497
|
+
const cause = error instanceof HTTPException97 ? error.cause : error;
|
|
104200
104498
|
return cause instanceof BrowserControlTransportError5 || cause instanceof BrowserControlProtocolError3;
|
|
104201
104499
|
}
|
|
104202
104500
|
function appendVary(current, value) {
|
|
@@ -104225,15 +104523,15 @@ function workspaceRequestRequiresCodexAccountPrevalidation(request) {
|
|
|
104225
104523
|
async function validateCodexAccountTarget(request) {
|
|
104226
104524
|
const body4 = await request.clone().json().catch(() => null);
|
|
104227
104525
|
if (typeof body4?.target !== "string" || body4.target.length === 0) {
|
|
104228
|
-
throw new
|
|
104526
|
+
throw new HTTPException97(400, {
|
|
104229
104527
|
message: 'target is required ("auto" or an account id)'
|
|
104230
104528
|
});
|
|
104231
104529
|
}
|
|
104232
104530
|
}
|
|
104233
104531
|
async function requireMcpAccessGrantAuthorization(c, deps, workspaceId) {
|
|
104234
|
-
const authorization = await
|
|
104532
|
+
const authorization = await requireAccessGrantAuthorization37(c, deps, workspaceId);
|
|
104235
104533
|
const grant = authorization.grant;
|
|
104236
|
-
if (
|
|
104534
|
+
if (hasPermission25(grant.permissions, "workspace:read")) {
|
|
104237
104535
|
return authorization;
|
|
104238
104536
|
}
|
|
104239
104537
|
if (isCodemodeGrant(grant)) {
|
|
@@ -104274,16 +104572,16 @@ function clientAuthConfig(settings) {
|
|
|
104274
104572
|
}
|
|
104275
104573
|
function codemodeHttpError(error) {
|
|
104276
104574
|
if (error instanceof SiteSessionPathError) {
|
|
104277
|
-
return new
|
|
104575
|
+
return new HTTPException97(404, { message: error.message, cause: error });
|
|
104278
104576
|
}
|
|
104279
|
-
if (error instanceof
|
|
104280
|
-
return new
|
|
104577
|
+
if (error instanceof SessionAuthorizationDeniedError17) {
|
|
104578
|
+
return new HTTPException97(404, {
|
|
104281
104579
|
message: "session not found",
|
|
104282
104580
|
cause: error
|
|
104283
104581
|
});
|
|
104284
104582
|
}
|
|
104285
|
-
if (error instanceof
|
|
104286
|
-
return new
|
|
104583
|
+
if (error instanceof SessionAuthorizationUnavailableError15) {
|
|
104584
|
+
return new HTTPException97(503, {
|
|
104287
104585
|
message: "session authorization is unavailable",
|
|
104288
104586
|
cause: error
|
|
104289
104587
|
});
|
|
@@ -104316,21 +104614,21 @@ function codemodeHttpError(error) {
|
|
|
104316
104614
|
});
|
|
104317
104615
|
}
|
|
104318
104616
|
if (error instanceof CodemodeOperationNotExecutableError) {
|
|
104319
|
-
return new
|
|
104617
|
+
return new HTTPException97(409, { message: error.message, cause: error });
|
|
104320
104618
|
}
|
|
104321
104619
|
if (error instanceof CodemodeOperationConflictError) {
|
|
104322
|
-
return new
|
|
104620
|
+
return new HTTPException97(409, { message: error.message, cause: error });
|
|
104323
104621
|
}
|
|
104324
104622
|
if (error instanceof CodemodeToolNotInCatalogError) {
|
|
104325
|
-
return new
|
|
104623
|
+
return new HTTPException97(404, { message: error.message, cause: error });
|
|
104326
104624
|
}
|
|
104327
104625
|
if (error instanceof CodemodeToolApprovalRequiredError) {
|
|
104328
|
-
return new
|
|
104626
|
+
return new HTTPException97(409, { message: error.message, cause: error });
|
|
104329
104627
|
}
|
|
104330
104628
|
if (error instanceof CodemodePayloadTooLargeError) {
|
|
104331
|
-
return new
|
|
104629
|
+
return new HTTPException97(413, { message: error.message, cause: error });
|
|
104332
104630
|
}
|
|
104333
|
-
return error instanceof
|
|
104631
|
+
return error instanceof HTTPException97 ? error : new HTTPException97(500, {
|
|
104334
104632
|
message: "Codemode request failed",
|
|
104335
104633
|
cause: error
|
|
104336
104634
|
});
|
|
@@ -104359,7 +104657,7 @@ function structuredServicesHint(backend) {
|
|
|
104359
104657
|
}
|
|
104360
104658
|
function codexCompactionV2ProviderLockedError(error) {
|
|
104361
104659
|
if (error instanceof CodexCompactionV2ProviderLockedError) return error;
|
|
104362
|
-
if (error instanceof
|
|
104660
|
+
if (error instanceof HTTPException97 && error.cause instanceof CodexCompactionV2ProviderLockedError) {
|
|
104363
104661
|
return error.cause;
|
|
104364
104662
|
}
|
|
104365
104663
|
return null;
|
|
@@ -104373,7 +104671,7 @@ function httpStatusForError(error) {
|
|
|
104373
104671
|
if (workspaceControlBusyHttpError(error)) {
|
|
104374
104672
|
return 503;
|
|
104375
104673
|
}
|
|
104376
|
-
if (error instanceof
|
|
104674
|
+
if (error instanceof HTTPException97) {
|
|
104377
104675
|
return error.status;
|
|
104378
104676
|
}
|
|
104379
104677
|
if (error instanceof McpPayloadTooLargeError) {
|
|
@@ -104405,7 +104703,7 @@ function publicErrorMessage(error, status) {
|
|
|
104405
104703
|
if (status >= 500) {
|
|
104406
104704
|
return "OpenGeni could not complete the request.";
|
|
104407
104705
|
}
|
|
104408
|
-
if (error instanceof
|
|
104706
|
+
if (error instanceof HTTPException97) {
|
|
104409
104707
|
return boundedPublicMessage(error.message) ?? "Request failed.";
|
|
104410
104708
|
}
|
|
104411
104709
|
if (error instanceof McpPayloadTooLargeError) {
|
|
@@ -105379,4 +105677,4 @@ export {
|
|
|
105379
105677
|
withDefaultEnabledCapabilityMcpTools,
|
|
105380
105678
|
workflowIdForSession4 as workflowIdForSession
|
|
105381
105679
|
};
|
|
105382
|
-
//# sourceMappingURL=chunk-
|
|
105680
|
+
//# sourceMappingURL=chunk-7IAWEYBH.js.map
|