@opengeni/api-router 0.30.3 → 2.2.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/api-websocket.d.ts +18 -0
- package/dist/app.js +1 -1
- package/dist/auth/managed-auth.d.ts +6 -0
- package/dist/{chunk-WCXHI3FF.js → chunk-3TP54PPX.js} +26692 -15389
- package/dist/chunk-3TP54PPX.js.map +1 -0
- package/dist/codemode.d.ts +8 -1
- package/dist/company-brain-okf.d.ts +24 -0
- package/dist/connected-machine-computer-access.d.ts +11 -0
- package/dist/connection-authority-owner.d.ts +59 -0
- package/dist/connection-ownership.d.ts +47 -0
- package/dist/controller-data-plane.d.ts +16 -0
- package/dist/editable-artifact-websocket.d.ts +5 -15
- package/dist/editable-artifact-workspace-files.d.ts +1 -1
- package/dist/http/api-error.d.ts +10 -0
- package/dist/http/cors.d.ts +5 -0
- package/dist/http/interaction-control-error.d.ts +13 -0
- package/dist/http/sse.d.ts +2 -3
- package/dist/index.d.ts +5 -2
- package/dist/index.js +326 -82
- package/dist/index.js.map +1 -1
- package/dist/integrations/atlassian.d.ts +17 -0
- package/dist/integrations/fiken.d.ts +7 -2
- package/dist/integrations/google-drive.d.ts +18 -0
- package/dist/integrations/oauth-client.d.ts +22 -3
- package/dist/integrations/oauth-profiles.d.ts +195 -0
- package/dist/integrations/personal-github-repositories.d.ts +45 -0
- package/dist/integrations/personal-github.d.ts +40 -0
- package/dist/integrations/pr-review-provider.d.ts +22 -0
- package/dist/integrations/provider-oauth.d.ts +8 -0
- package/dist/integrations/slack-app-home.d.ts +24 -0
- package/dist/integrations/slack-bot.d.ts +157 -9
- package/dist/integrations/slack-interactions.d.ts +39 -5
- package/dist/integrations/slack-routing.d.ts +120 -0
- package/dist/integrations/social-oauth.d.ts +5 -0
- package/dist/interaction-frame-proxy.d.ts +68 -0
- package/dist/mcp/company-brain-governed-writes.d.ts +26 -0
- package/dist/mcp/company-profile-agent-admin.d.ts +44 -0
- package/dist/mcp/documents.d.ts +1 -0
- package/dist/mcp/remember.d.ts +28 -0
- package/dist/mcp/request-abort.d.ts +19 -0
- package/dist/mcp/scheduled-task-view.d.ts +4 -4
- package/dist/mcp/server.d.ts +15 -2
- package/dist/mcp/session-view.d.ts +4 -0
- package/dist/mcp/session-wait.d.ts +137 -0
- package/dist/routes/automations.d.ts +4 -0
- package/dist/routes/billing.d.ts +5 -0
- package/dist/routes/browser-sessions.d.ts +4 -1
- package/dist/routes/company-brain.d.ts +3 -0
- package/dist/routes/company-profile.d.ts +2 -1
- package/dist/routes/connection-authorities.d.ts +3 -0
- package/dist/routes/personal-github-git-broker.d.ts +29 -0
- package/dist/routes/personal-github.d.ts +3 -0
- package/dist/routes/pr-review.d.ts +3 -0
- package/dist/routes/sessions.d.ts +1 -0
- package/dist/routes/user-resource-authorities.d.ts +3 -0
- package/dist/routes/workspace-capture.d.ts +10 -2
- package/dist/routes/workspace-learning.d.ts +3 -0
- package/dist/routes/workspaces.d.ts +19 -0
- package/dist/sandbox/channel-a.d.ts +11 -1
- package/dist/sandbox/connection-authority.d.ts +3 -0
- package/dist/sandbox/enrollment.d.ts +2 -0
- package/dist/sandbox/machines.d.ts +2 -2
- package/dist/sandbox/metrics-ingestion.d.ts +10 -20
- package/dist/sandbox/viewer.d.ts +24 -1
- package/dist/sandbox-file-artifacts.d.ts +11 -0
- package/dist/scheduled-task-deletion.d.ts +14 -0
- package/dist/slack-reaction-files.d.ts +1 -1
- package/dist/temporal-schedule-cleanup.d.ts +1 -0
- package/package.json +20 -18
- package/src/api-websocket.ts +23 -0
- package/src/app.ts +161 -23
- package/src/auth/managed-auth.ts +25 -3
- package/src/codemode.ts +53 -23
- package/src/codex-realtime.ts +8 -2
- package/src/company-brain-okf.ts +340 -0
- package/src/connected-machine-computer-access.ts +33 -0
- package/src/connection-authority-owner.ts +61 -0
- package/src/connection-ownership.ts +180 -0
- package/src/controller-data-plane.ts +47 -0
- package/src/editable-artifact-native-kernel.ts +26 -15
- package/src/editable-artifact-office-import.ts +28 -3
- package/src/editable-artifact-production.ts +13 -7
- package/src/editable-artifact-websocket.ts +11 -18
- package/src/editable-artifact-workspace-files.ts +31 -6
- package/src/http/api-error.ts +28 -0
- package/src/http/auth.ts +4 -0
- package/src/http/cors.ts +35 -0
- package/src/http/interaction-control-error.ts +164 -0
- package/src/http/sse.ts +112 -66
- package/src/index.ts +46 -6
- package/src/integrations/atlassian.ts +146 -35
- package/src/integrations/fiken.ts +102 -22
- package/src/integrations/google-drive.ts +301 -92
- package/src/integrations/oauth-client.ts +272 -143
- package/src/integrations/oauth-profiles.ts +477 -0
- package/src/integrations/personal-github-repositories.ts +445 -0
- package/src/integrations/personal-github.ts +705 -0
- package/src/integrations/pr-review-provider.ts +246 -0
- package/src/integrations/provider-oauth.ts +121 -5
- package/src/integrations/slack-app-home.ts +300 -0
- package/src/integrations/slack-bot.ts +342 -57
- package/src/integrations/slack-interactions.ts +1898 -259
- package/src/integrations/slack-routing.ts +337 -0
- package/src/integrations/social-oauth.ts +25 -0
- package/src/interaction-frame-proxy.ts +409 -0
- package/src/mcp/company-brain-governed-writes.ts +262 -0
- package/src/mcp/company-profile-agent-admin.ts +205 -0
- package/src/mcp/documents.ts +37 -6
- package/src/mcp/files.ts +16 -1
- package/src/mcp/remember.ts +181 -0
- package/src/mcp/request-abort.ts +44 -0
- package/src/mcp/scheduled-task-view.ts +1 -0
- package/src/mcp/server.ts +719 -369
- package/src/mcp/session-view.ts +54 -0
- package/src/mcp/session-wait.ts +554 -0
- package/src/model-catalog.ts +20 -12
- package/src/routes/api-integrations.ts +4 -0
- package/src/routes/api-keys.ts +1 -0
- package/src/routes/automations.ts +534 -0
- package/src/routes/billing.ts +57 -1
- package/src/routes/browser-sessions.ts +329 -79
- package/src/routes/channels.ts +17 -1
- package/src/routes/codex.ts +50 -0
- package/src/routes/company-brain.ts +367 -0
- package/src/routes/company-profile.ts +1 -1
- package/src/routes/computer-sessions.ts +320 -93
- package/src/routes/connection-authorities.ts +139 -0
- package/src/routes/connections.ts +144 -34
- package/src/routes/documents.ts +353 -4
- package/src/routes/editable-artifacts.ts +11 -3
- package/src/routes/enrollments.ts +116 -26
- package/src/routes/environments.ts +127 -55
- package/src/routes/files.ts +72 -11
- package/src/routes/install.ts +82 -28
- package/src/routes/integration-facets.ts +29 -0
- package/src/routes/interaction-resources.ts +20 -2
- package/src/routes/machines.ts +275 -13
- package/src/routes/organization-memberships.ts +717 -28
- package/src/routes/packs.ts +4 -3
- package/src/routes/personal-github-git-broker.ts +785 -0
- package/src/routes/personal-github.ts +319 -0
- package/src/routes/pr-review.ts +531 -0
- package/src/routes/rigs.ts +104 -39
- package/src/routes/scheduled-tasks.ts +19 -21
- package/src/routes/sessions.ts +775 -38
- package/src/routes/social.ts +14 -2
- package/src/routes/supergrok.ts +23 -4
- package/src/routes/transcription-recordings.ts +8 -2
- package/src/routes/user-resource-authorities.ts +138 -0
- package/src/routes/workspace-artifacts.ts +4 -1
- package/src/routes/workspace-capture.ts +21 -0
- package/src/routes/workspace-learning.ts +228 -0
- package/src/routes/workspaces.ts +59 -6
- package/src/sandbox/auth-callout.ts +38 -12
- package/src/sandbox/channel-a.ts +242 -19
- package/src/sandbox/connection-authority.ts +3 -0
- package/src/sandbox/enrollment.ts +15 -3
- package/src/sandbox/machines.ts +186 -64
- package/src/sandbox/metrics-ingestion.ts +220 -58
- package/src/sandbox/viewer.ts +243 -19
- package/src/sandbox-file-artifacts.ts +329 -0
- package/src/scheduled-task-deletion.ts +127 -0
- package/src/slack-reaction-files.ts +16 -5
- package/src/temporal-schedule-cleanup.ts +13 -0
- package/dist/chunk-WCXHI3FF.js.map +0 -1
package/src/routes/documents.ts
CHANGED
|
@@ -4,17 +4,31 @@ import {
|
|
|
4
4
|
CreateKnowledgeMemoryRequest,
|
|
5
5
|
CreateDocumentBaseRequest,
|
|
6
6
|
Document,
|
|
7
|
+
DocumentAuthorityReclassification,
|
|
7
8
|
DocumentBase,
|
|
9
|
+
DocumentDefaultCollectionBackfill,
|
|
10
|
+
DocumentDefaultCollectionBackfillAudit,
|
|
11
|
+
GetDocumentDefaultCollectionBackfillAuditQuery,
|
|
8
12
|
DocumentSearchRequest,
|
|
9
13
|
DocumentSearchResponse,
|
|
14
|
+
FileAsset,
|
|
15
|
+
FileDownloadUrlResponse,
|
|
10
16
|
KnowledgeMemory,
|
|
11
17
|
KnowledgeMemorySearchRequest,
|
|
18
|
+
ListDocumentAuthorityReclassificationsQuery,
|
|
19
|
+
ListDocumentAuthorityReclassificationsResponse,
|
|
20
|
+
ListDocumentDefaultCollectionBackfillRunsResponse,
|
|
21
|
+
ListDocumentMigrationAuditQuery,
|
|
22
|
+
ListOrganizationDocumentAuthorityReclassificationsResponse,
|
|
12
23
|
MoveDocumentRequest,
|
|
24
|
+
ReclassifyDocumentAuthorityRequest,
|
|
25
|
+
RunDocumentDefaultCollectionBackfillRequest,
|
|
13
26
|
UpdateKnowledgeMemoryRequest,
|
|
14
27
|
WorkspaceMemorySearchRequest,
|
|
15
28
|
WorkspaceMemorySearchResponse,
|
|
16
29
|
} from "@opengeni/contracts";
|
|
17
30
|
import {
|
|
31
|
+
recordAuditEvent,
|
|
18
32
|
completeFileUpload,
|
|
19
33
|
createFileUpload,
|
|
20
34
|
createKnowledgeMemory,
|
|
@@ -29,11 +43,19 @@ import {
|
|
|
29
43
|
deleteDocumentFromBase,
|
|
30
44
|
ensureDefaultBase,
|
|
31
45
|
getDocument,
|
|
46
|
+
getDocumentOriginalFile,
|
|
32
47
|
getDocumentBase,
|
|
48
|
+
getDocumentDefaultCollectionBackfillAudit,
|
|
49
|
+
listAccessibleDocuments,
|
|
50
|
+
listDocumentAuthorityReclassifications,
|
|
51
|
+
listDocumentDefaultCollectionBackfillRuns,
|
|
33
52
|
listDocumentBasesEnsuringDefault,
|
|
34
53
|
listDocuments,
|
|
54
|
+
listOrganizationDocumentAuthorityReclassifications,
|
|
35
55
|
moveDocumentToBase,
|
|
36
56
|
queueDocumentForReindex,
|
|
57
|
+
reclassifyDocumentAuthority,
|
|
58
|
+
runDocumentDefaultCollectionBackfill,
|
|
37
59
|
searchEffectiveDocuments,
|
|
38
60
|
} from "@opengeni/documents";
|
|
39
61
|
import { WebStandardStreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/webStandardStreamableHttp.js";
|
|
@@ -41,6 +63,7 @@ import type { Context, Hono } from "hono";
|
|
|
41
63
|
import { HTTPException } from "hono/http-exception";
|
|
42
64
|
import {
|
|
43
65
|
requireAccessGrant,
|
|
66
|
+
requireAccountAdminAuthorizationStamp,
|
|
44
67
|
requireAccessGrantAuthorization,
|
|
45
68
|
saveWorkspaceMemoryWithSlackPublication,
|
|
46
69
|
} from "@opengeni/core";
|
|
@@ -87,6 +110,136 @@ export function registerDocumentRoutes(app: Hono, deps: ApiRouteDeps): void {
|
|
|
87
110
|
return c.json(DocumentBase.parse(base));
|
|
88
111
|
});
|
|
89
112
|
|
|
113
|
+
app.post("/v1/workspaces/:workspaceId/document-default-collection-backfills", async (c) => {
|
|
114
|
+
const workspaceId = c.req.param("workspaceId");
|
|
115
|
+
const authorization = await requireAccessGrantAuthorization(
|
|
116
|
+
c,
|
|
117
|
+
deps,
|
|
118
|
+
workspaceId,
|
|
119
|
+
"documents:manage",
|
|
120
|
+
);
|
|
121
|
+
if (!hasAccountAdminAuthority(authorization)) {
|
|
122
|
+
throw new HTTPException(403, { message: "missing permission: account:admin" });
|
|
123
|
+
}
|
|
124
|
+
const accountAdminAuthorization = requireAccountAdminAuthorizationStamp(authorization);
|
|
125
|
+
const payload = RunDocumentDefaultCollectionBackfillRequest.parse(await c.req.json());
|
|
126
|
+
try {
|
|
127
|
+
return c.json(
|
|
128
|
+
DocumentDefaultCollectionBackfill.parse(
|
|
129
|
+
await runDocumentDefaultCollectionBackfill(db, {
|
|
130
|
+
...payload,
|
|
131
|
+
accountId: authorization.grant.accountId,
|
|
132
|
+
workspaceId,
|
|
133
|
+
actorSubjectId: authorization.grant.subjectId,
|
|
134
|
+
accountAdminAuthorization,
|
|
135
|
+
}),
|
|
136
|
+
),
|
|
137
|
+
);
|
|
138
|
+
} catch (error) {
|
|
139
|
+
throw documentHttpException(error);
|
|
140
|
+
}
|
|
141
|
+
});
|
|
142
|
+
|
|
143
|
+
app.get("/v1/workspaces/:workspaceId/document-default-collection-backfills", async (c) => {
|
|
144
|
+
const workspaceId = c.req.param("workspaceId");
|
|
145
|
+
const authorization = await requireAccessGrantAuthorization(
|
|
146
|
+
c,
|
|
147
|
+
deps,
|
|
148
|
+
workspaceId,
|
|
149
|
+
"documents:manage",
|
|
150
|
+
);
|
|
151
|
+
if (!hasAccountAdminAuthority(authorization)) {
|
|
152
|
+
throw new HTTPException(403, { message: "missing permission: account:admin" });
|
|
153
|
+
}
|
|
154
|
+
const query = ListDocumentMigrationAuditQuery.safeParse(c.req.query());
|
|
155
|
+
if (!query.success) {
|
|
156
|
+
throw new HTTPException(400, { message: "invalid document migration audit query" });
|
|
157
|
+
}
|
|
158
|
+
try {
|
|
159
|
+
return c.json(
|
|
160
|
+
ListDocumentDefaultCollectionBackfillRunsResponse.parse(
|
|
161
|
+
await listDocumentDefaultCollectionBackfillRuns(db, {
|
|
162
|
+
accountId: authorization.grant.accountId,
|
|
163
|
+
workspaceId,
|
|
164
|
+
actorSubjectId: authorization.grant.subjectId,
|
|
165
|
+
accountAdminAuthorization: requireAccountAdminAuthorizationStamp(authorization),
|
|
166
|
+
...query.data,
|
|
167
|
+
}),
|
|
168
|
+
),
|
|
169
|
+
);
|
|
170
|
+
} catch (error) {
|
|
171
|
+
throw documentHttpException(error);
|
|
172
|
+
}
|
|
173
|
+
});
|
|
174
|
+
|
|
175
|
+
app.get("/v1/workspaces/:workspaceId/document-default-collection-backfills/:runId", async (c) => {
|
|
176
|
+
const workspaceId = c.req.param("workspaceId");
|
|
177
|
+
const authorization = await requireAccessGrantAuthorization(
|
|
178
|
+
c,
|
|
179
|
+
deps,
|
|
180
|
+
workspaceId,
|
|
181
|
+
"documents:manage",
|
|
182
|
+
);
|
|
183
|
+
if (!hasAccountAdminAuthority(authorization)) {
|
|
184
|
+
throw new HTTPException(403, { message: "missing permission: account:admin" });
|
|
185
|
+
}
|
|
186
|
+
const runId = RunDocumentDefaultCollectionBackfillRequest.shape.runId.safeParse(
|
|
187
|
+
c.req.param("runId"),
|
|
188
|
+
);
|
|
189
|
+
const query = GetDocumentDefaultCollectionBackfillAuditQuery.safeParse(c.req.query());
|
|
190
|
+
if (!runId.success || !query.success) {
|
|
191
|
+
throw new HTTPException(400, { message: "invalid document migration audit query" });
|
|
192
|
+
}
|
|
193
|
+
try {
|
|
194
|
+
return c.json(
|
|
195
|
+
DocumentDefaultCollectionBackfillAudit.parse(
|
|
196
|
+
await getDocumentDefaultCollectionBackfillAudit(db, {
|
|
197
|
+
accountId: authorization.grant.accountId,
|
|
198
|
+
workspaceId,
|
|
199
|
+
actorSubjectId: authorization.grant.subjectId,
|
|
200
|
+
accountAdminAuthorization: requireAccountAdminAuthorizationStamp(authorization),
|
|
201
|
+
runId: runId.data,
|
|
202
|
+
...query.data,
|
|
203
|
+
}),
|
|
204
|
+
),
|
|
205
|
+
);
|
|
206
|
+
} catch (error) {
|
|
207
|
+
throw documentHttpException(error);
|
|
208
|
+
}
|
|
209
|
+
});
|
|
210
|
+
|
|
211
|
+
app.get("/v1/workspaces/:workspaceId/document-authority-reclassifications", async (c) => {
|
|
212
|
+
const workspaceId = c.req.param("workspaceId");
|
|
213
|
+
const authorization = await requireAccessGrantAuthorization(
|
|
214
|
+
c,
|
|
215
|
+
deps,
|
|
216
|
+
workspaceId,
|
|
217
|
+
"documents:manage",
|
|
218
|
+
);
|
|
219
|
+
if (!hasAccountAdminAuthority(authorization)) {
|
|
220
|
+
throw new HTTPException(403, { message: "missing permission: account:admin" });
|
|
221
|
+
}
|
|
222
|
+
const query = ListDocumentMigrationAuditQuery.safeParse(c.req.query());
|
|
223
|
+
if (!query.success) {
|
|
224
|
+
throw new HTTPException(400, { message: "invalid document migration audit query" });
|
|
225
|
+
}
|
|
226
|
+
try {
|
|
227
|
+
return c.json(
|
|
228
|
+
ListOrganizationDocumentAuthorityReclassificationsResponse.parse(
|
|
229
|
+
await listOrganizationDocumentAuthorityReclassifications(db, {
|
|
230
|
+
accountId: authorization.grant.accountId,
|
|
231
|
+
workspaceId,
|
|
232
|
+
actorSubjectId: authorization.grant.subjectId,
|
|
233
|
+
accountAdminAuthorization: requireAccountAdminAuthorizationStamp(authorization),
|
|
234
|
+
...query.data,
|
|
235
|
+
}),
|
|
236
|
+
),
|
|
237
|
+
);
|
|
238
|
+
} catch (error) {
|
|
239
|
+
throw documentHttpException(error);
|
|
240
|
+
}
|
|
241
|
+
});
|
|
242
|
+
|
|
90
243
|
app.post("/v1/workspaces/:workspaceId/document-bases/:baseId/documents", async (c) => {
|
|
91
244
|
const workspaceId = c.req.param("workspaceId");
|
|
92
245
|
const access = await requireAccessGrantAuthorization(c, deps, workspaceId, "documents:manage");
|
|
@@ -161,6 +314,148 @@ export function registerDocumentRoutes(app: Hono, deps: ApiRouteDeps): void {
|
|
|
161
314
|
);
|
|
162
315
|
});
|
|
163
316
|
|
|
317
|
+
app.get("/v1/workspaces/:workspaceId/documents", async (c) => {
|
|
318
|
+
const workspaceId = c.req.param("workspaceId");
|
|
319
|
+
const grant = await requireAccessGrant(c, deps, workspaceId, "documents:search");
|
|
320
|
+
return c.json(
|
|
321
|
+
(
|
|
322
|
+
await listAccessibleDocuments(db, workspaceId, {
|
|
323
|
+
viewerSubjectId: grant.subjectId,
|
|
324
|
+
})
|
|
325
|
+
).map((document) => Document.parse(document)),
|
|
326
|
+
);
|
|
327
|
+
});
|
|
328
|
+
|
|
329
|
+
app.post(
|
|
330
|
+
"/v1/workspaces/:workspaceId/documents/:documentId/authority-reclassifications",
|
|
331
|
+
async (c) => {
|
|
332
|
+
const workspaceId = c.req.param("workspaceId");
|
|
333
|
+
const authorization = await requireAccessGrantAuthorization(
|
|
334
|
+
c,
|
|
335
|
+
deps,
|
|
336
|
+
workspaceId,
|
|
337
|
+
"documents:manage",
|
|
338
|
+
);
|
|
339
|
+
const payload = ReclassifyDocumentAuthorityRequest.parse(await c.req.json());
|
|
340
|
+
const accountAdminAuthorized = hasAccountAdminAuthority(authorization);
|
|
341
|
+
const accountAdminAuthorization = accountAdminAuthorized
|
|
342
|
+
? requireAccountAdminAuthorizationStamp(authorization)
|
|
343
|
+
: null;
|
|
344
|
+
try {
|
|
345
|
+
const document = await getDocument(db, workspaceId, c.req.param("documentId"), {
|
|
346
|
+
viewerSubjectId: authorization.grant.subjectId,
|
|
347
|
+
});
|
|
348
|
+
if (!document) throw new HTTPException(404, { message: "document not found" });
|
|
349
|
+
if (
|
|
350
|
+
(document.authorityKind === "organization" ||
|
|
351
|
+
payload.targetAuthorityKind === "organization") &&
|
|
352
|
+
!accountAdminAuthorization
|
|
353
|
+
) {
|
|
354
|
+
throw new HTTPException(403, { message: "missing permission: account:admin" });
|
|
355
|
+
}
|
|
356
|
+
return c.json(
|
|
357
|
+
DocumentAuthorityReclassification.parse(
|
|
358
|
+
await reclassifyDocumentAuthority(db, {
|
|
359
|
+
...payload,
|
|
360
|
+
accountId: authorization.grant.accountId,
|
|
361
|
+
workspaceId,
|
|
362
|
+
documentId: document.id,
|
|
363
|
+
actorSubjectId: authorization.grant.subjectId,
|
|
364
|
+
accountAdminAuthorization,
|
|
365
|
+
}),
|
|
366
|
+
),
|
|
367
|
+
);
|
|
368
|
+
} catch (error) {
|
|
369
|
+
if (error instanceof HTTPException) throw error;
|
|
370
|
+
throw documentHttpException(error);
|
|
371
|
+
}
|
|
372
|
+
},
|
|
373
|
+
);
|
|
374
|
+
|
|
375
|
+
app.get(
|
|
376
|
+
"/v1/workspaces/:workspaceId/documents/:documentId/authority-reclassifications",
|
|
377
|
+
async (c) => {
|
|
378
|
+
const workspaceId = c.req.param("workspaceId");
|
|
379
|
+
const grant = await requireAccessGrant(c, deps, workspaceId, "documents:manage");
|
|
380
|
+
try {
|
|
381
|
+
const query = ListDocumentAuthorityReclassificationsQuery.parse(c.req.query());
|
|
382
|
+
return c.json(
|
|
383
|
+
ListDocumentAuthorityReclassificationsResponse.parse(
|
|
384
|
+
await listDocumentAuthorityReclassifications(db, {
|
|
385
|
+
accountId: grant.accountId,
|
|
386
|
+
workspaceId,
|
|
387
|
+
documentId: c.req.param("documentId"),
|
|
388
|
+
actorSubjectId: grant.subjectId,
|
|
389
|
+
...query,
|
|
390
|
+
}),
|
|
391
|
+
),
|
|
392
|
+
);
|
|
393
|
+
} catch (error) {
|
|
394
|
+
throw documentHttpException(error);
|
|
395
|
+
}
|
|
396
|
+
},
|
|
397
|
+
);
|
|
398
|
+
|
|
399
|
+
app.get("/v1/workspaces/:workspaceId/documents/:documentId/original-file", async (c) => {
|
|
400
|
+
const workspaceId = c.req.param("workspaceId");
|
|
401
|
+
const grant = await requireAccessGrant(c, deps, workspaceId, "documents:search");
|
|
402
|
+
await requireAccessGrant(c, deps, workspaceId, "files:read");
|
|
403
|
+
const file = await getDocumentOriginalFile(db, {
|
|
404
|
+
accountId: grant.accountId,
|
|
405
|
+
workspaceId,
|
|
406
|
+
documentId: c.req.param("documentId"),
|
|
407
|
+
access: { viewerSubjectId: grant.subjectId },
|
|
408
|
+
});
|
|
409
|
+
if (!file) {
|
|
410
|
+
throw new HTTPException(404, { message: "document file not found" });
|
|
411
|
+
}
|
|
412
|
+
return c.json(FileAsset.parse(file));
|
|
413
|
+
});
|
|
414
|
+
|
|
415
|
+
app.post(
|
|
416
|
+
"/v1/workspaces/:workspaceId/documents/:documentId/original-file/download-url",
|
|
417
|
+
async (c) => {
|
|
418
|
+
const workspaceId = c.req.param("workspaceId");
|
|
419
|
+
const grant = await requireAccessGrant(c, deps, workspaceId, "documents:search");
|
|
420
|
+
await requireAccessGrant(c, deps, workspaceId, "files:read");
|
|
421
|
+
if (!objectStorage) {
|
|
422
|
+
throw new HTTPException(503, { message: "object storage is not configured" });
|
|
423
|
+
}
|
|
424
|
+
const file = await getDocumentOriginalFile(db, {
|
|
425
|
+
accountId: grant.accountId,
|
|
426
|
+
workspaceId,
|
|
427
|
+
documentId: c.req.param("documentId"),
|
|
428
|
+
access: { viewerSubjectId: grant.subjectId },
|
|
429
|
+
});
|
|
430
|
+
if (!file) {
|
|
431
|
+
throw new HTTPException(404, { message: "document file not found" });
|
|
432
|
+
}
|
|
433
|
+
if (file.status !== "ready") {
|
|
434
|
+
throw new HTTPException(409, { message: `file is ${file.status}` });
|
|
435
|
+
}
|
|
436
|
+
const signed = await objectStorage.createGetUrl({ key: file.objectKey });
|
|
437
|
+
await recordAuditEvent(db, {
|
|
438
|
+
accountId: grant.accountId,
|
|
439
|
+
workspaceId,
|
|
440
|
+
subjectId: grant.subjectId,
|
|
441
|
+
action: "file.signed_url.issued",
|
|
442
|
+
targetType: "workspace_document",
|
|
443
|
+
targetId: c.req.param("documentId"),
|
|
444
|
+
metadata: {
|
|
445
|
+
fileId: file.id,
|
|
446
|
+
kind: "document_original",
|
|
447
|
+
expiresAt: signed.expiresAt.toISOString(),
|
|
448
|
+
},
|
|
449
|
+
});
|
|
450
|
+
return c.json(
|
|
451
|
+
FileDownloadUrlResponse.parse({
|
|
452
|
+
url: signed.url,
|
|
453
|
+
expiresAt: signed.expiresAt.toISOString(),
|
|
454
|
+
}),
|
|
455
|
+
);
|
|
456
|
+
},
|
|
457
|
+
);
|
|
458
|
+
|
|
164
459
|
app.delete(
|
|
165
460
|
"/v1/workspaces/:workspaceId/document-bases/:baseId/documents/:documentId",
|
|
166
461
|
async (c) => {
|
|
@@ -212,7 +507,9 @@ export function registerDocumentRoutes(app: Hono, deps: ApiRouteDeps): void {
|
|
|
212
507
|
const { grant } = authorization;
|
|
213
508
|
const organizationAuthorityGranted = hasAccountAdminAuthority(authorization);
|
|
214
509
|
if (!objectStorage) {
|
|
215
|
-
throw new HTTPException(503, {
|
|
510
|
+
throw new HTTPException(503, {
|
|
511
|
+
message: "object storage is not configured",
|
|
512
|
+
});
|
|
216
513
|
}
|
|
217
514
|
await requireLimit(deps, {
|
|
218
515
|
accountId: grant.accountId,
|
|
@@ -246,7 +543,9 @@ export function registerDocumentRoutes(app: Hono, deps: ApiRouteDeps): void {
|
|
|
246
543
|
const indexed =
|
|
247
544
|
(await documentIndexer.indexDocument({
|
|
248
545
|
accountId: grant.accountId,
|
|
249
|
-
|
|
546
|
+
// The requested workspace authorizes the human operation; the
|
|
547
|
+
// immutable ingestion workspace remains the indexing authority.
|
|
548
|
+
workspaceId: queued.workspaceId,
|
|
250
549
|
documentId: document.id,
|
|
251
550
|
authorityKind: document.authorityKind,
|
|
252
551
|
authorityWorkspaceId: document.authorityWorkspaceId,
|
|
@@ -651,13 +950,19 @@ export function registerDocumentRoutes(app: Hono, deps: ApiRouteDeps): void {
|
|
|
651
950
|
const grant = await requireAccessGrant(c, deps, workspaceId, "documents:search");
|
|
652
951
|
const sessionId =
|
|
653
952
|
typeof grant.metadata?.sessionId === "string" ? grant.metadata.sessionId : undefined;
|
|
953
|
+
const attemptId =
|
|
954
|
+
typeof grant.metadata?.attemptId === "string" ? grant.metadata.attemptId : undefined;
|
|
654
955
|
const transport = new WebStandardStreamableHTTPServerTransport({ enableJsonResponse: true });
|
|
655
956
|
const server = buildDocumentsMcpServer(
|
|
656
957
|
db,
|
|
657
958
|
grant.accountId,
|
|
658
959
|
workspaceId,
|
|
659
960
|
getDocumentServices(),
|
|
660
|
-
{
|
|
961
|
+
{
|
|
962
|
+
createdBySessionId: sessionId,
|
|
963
|
+
attemptId,
|
|
964
|
+
initiatingSubjectId: grant.subjectId,
|
|
965
|
+
},
|
|
661
966
|
);
|
|
662
967
|
await server.connect(transport);
|
|
663
968
|
return await transport.handleRequest(c.req.raw);
|
|
@@ -682,16 +987,47 @@ function dropFilename(preferred: string | undefined): string {
|
|
|
682
987
|
}
|
|
683
988
|
|
|
684
989
|
function documentHttpException(error: unknown): HTTPException {
|
|
685
|
-
const message =
|
|
990
|
+
const message = documentDomainErrorMessage(error);
|
|
686
991
|
if (message.includes("organization document") && message.includes("exact account authority")) {
|
|
687
992
|
return new HTTPException(403, { message: "missing permission: account:admin" });
|
|
688
993
|
}
|
|
689
994
|
if (message.includes("not found")) {
|
|
690
995
|
return new HTTPException(404, { message });
|
|
691
996
|
}
|
|
997
|
+
if (message.includes("document Default collection backfill audit run is unavailable")) {
|
|
998
|
+
return new HTTPException(404, { message });
|
|
999
|
+
}
|
|
692
1000
|
if (message.includes("already exists")) {
|
|
693
1001
|
return new HTTPException(409, { message });
|
|
694
1002
|
}
|
|
1003
|
+
if (
|
|
1004
|
+
message.includes("operation id was reused") ||
|
|
1005
|
+
message.includes("authority changed before reclassification") ||
|
|
1006
|
+
message.includes("run identity mismatch")
|
|
1007
|
+
) {
|
|
1008
|
+
return new HTTPException(409, { message });
|
|
1009
|
+
}
|
|
1010
|
+
if (
|
|
1011
|
+
message.includes("reclassification requires") ||
|
|
1012
|
+
message.includes("backfill requires organization administration") ||
|
|
1013
|
+
message.includes("document migration audit requires organization administration") ||
|
|
1014
|
+
message.includes("document migration audit scope is invalid")
|
|
1015
|
+
) {
|
|
1016
|
+
return new HTTPException(403, { message });
|
|
1017
|
+
}
|
|
1018
|
+
if (
|
|
1019
|
+
message.includes("reclassification input is invalid") ||
|
|
1020
|
+
message.includes("reclassification authority is invalid") ||
|
|
1021
|
+
message.includes("invalid document authority receipt cursor") ||
|
|
1022
|
+
message.includes("document authority receipt limit") ||
|
|
1023
|
+
message.includes("invalid document migration audit cursor") ||
|
|
1024
|
+
message.includes("document migration audit cursor is invalid") ||
|
|
1025
|
+
message.includes("document migration audit limit") ||
|
|
1026
|
+
message.includes("document migration audit authority is incomplete") ||
|
|
1027
|
+
message.includes("document Default collection backfill audit run id is required")
|
|
1028
|
+
) {
|
|
1029
|
+
return new HTTPException(400, { message });
|
|
1030
|
+
}
|
|
695
1031
|
if (message.includes("no suggested base")) {
|
|
696
1032
|
return new HTTPException(422, { message });
|
|
697
1033
|
}
|
|
@@ -711,6 +1047,19 @@ function documentHttpException(error: unknown): HTTPException {
|
|
|
711
1047
|
return new HTTPException(500, { message });
|
|
712
1048
|
}
|
|
713
1049
|
|
|
1050
|
+
function documentDomainErrorMessage(error: unknown): string {
|
|
1051
|
+
let current: unknown = error;
|
|
1052
|
+
let message = error instanceof Error ? error.message : String(error);
|
|
1053
|
+
const seen = new Set<unknown>();
|
|
1054
|
+
while (current && typeof current === "object" && !seen.has(current) && seen.size < 8) {
|
|
1055
|
+
seen.add(current);
|
|
1056
|
+
const record = current as { cause?: unknown; message?: unknown };
|
|
1057
|
+
if (typeof record.message === "string") message = record.message;
|
|
1058
|
+
current = record.cause;
|
|
1059
|
+
}
|
|
1060
|
+
return message;
|
|
1061
|
+
}
|
|
1062
|
+
|
|
714
1063
|
function hasAccountAdminAuthority(
|
|
715
1064
|
authorization: Awaited<ReturnType<typeof requireAccessGrantAuthorization>>,
|
|
716
1065
|
): boolean {
|
|
@@ -78,9 +78,13 @@ const ListEditableArtifactsQuery = z
|
|
|
78
78
|
const MintEditableArtifactLiveTicketRequest = z
|
|
79
79
|
.object({
|
|
80
80
|
replicaId: ReplicaId,
|
|
81
|
-
|
|
81
|
+
modality: z.enum(["document", "spreadsheet", "presentation"]),
|
|
82
|
+
liveProtocolVersion: PositiveProtocolVersion,
|
|
82
83
|
kernelVersion: VersionName,
|
|
83
84
|
modelSchemaVersion: PositiveModelSchemaVersion,
|
|
85
|
+
snapshotVersion: PositiveProtocolVersion,
|
|
86
|
+
commandProtocolVersion: PositiveProtocolVersion,
|
|
87
|
+
committedTransactionProtocolVersion: PositiveProtocolVersion,
|
|
84
88
|
})
|
|
85
89
|
.strict();
|
|
86
90
|
|
|
@@ -482,9 +486,13 @@ export function registerEditableArtifactRoutes(
|
|
|
482
486
|
scope,
|
|
483
487
|
actor,
|
|
484
488
|
artifactId,
|
|
485
|
-
|
|
489
|
+
modality: body.modality,
|
|
490
|
+
liveProtocolVersion: body.liveProtocolVersion,
|
|
486
491
|
kernelVersion: body.kernelVersion,
|
|
487
492
|
modelSchemaVersion: body.modelSchemaVersion,
|
|
493
|
+
snapshotVersion: body.snapshotVersion,
|
|
494
|
+
commandProtocolVersion: body.commandProtocolVersion,
|
|
495
|
+
committedTransactionProtocolVersion: body.committedTransactionProtocolVersion,
|
|
488
496
|
allowEdit: hasPermission(grant.permissions, "artifacts:publish"),
|
|
489
497
|
});
|
|
490
498
|
} catch (error) {
|
|
@@ -496,7 +504,7 @@ export function registerEditableArtifactRoutes(
|
|
|
496
504
|
!parsedTicket.success ||
|
|
497
505
|
parsedTicket.data.artifactId !== artifactId ||
|
|
498
506
|
parsedTicket.data.replicaId !== actor.replicaId ||
|
|
499
|
-
parsedTicket.data.protocolVersion !== body.
|
|
507
|
+
parsedTicket.data.protocolVersion !== body.liveProtocolVersion ||
|
|
500
508
|
Date.parse(parsedTicket.data.expiresAt) <= Date.now()
|
|
501
509
|
) {
|
|
502
510
|
throw new Error("Editable artifact application returned an invalid live ticket");
|