@opengeni/api-router 0.17.0 → 0.20.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/app.js +1 -1
- package/dist/{chunk-MWBF2GXL.js → chunk-AEVD7E2F.js} +757 -110
- package/dist/chunk-AEVD7E2F.js.map +1 -0
- package/dist/codex-realtime.d.ts +1 -1
- package/dist/index.js +4 -3
- package/dist/index.js.map +1 -1
- package/dist/integrations/google-drive.d.ts +16 -1
- package/dist/mcp/documents.d.ts +3 -3
- package/dist/workspace-state-projection.d.ts +29 -1
- package/package.json +11 -11
- package/src/app.ts +33 -2
- package/src/codex-realtime.ts +4 -0
- package/src/index.ts +3 -2
- package/src/integrations/google-drive.ts +385 -20
- package/src/mcp/documents.ts +49 -27
- package/src/routes/connections.ts +61 -9
- package/src/routes/documents.ts +134 -43
- package/src/routes/workspace-instruction-policies.ts +22 -0
- package/src/routes/workspace-state.ts +46 -1
- package/src/workspace-state-projection.ts +203 -4
- package/dist/chunk-MWBF2GXL.js.map +0 -1
|
@@ -17,9 +17,10 @@ import {
|
|
|
17
17
|
} from "@opengeni/contracts";
|
|
18
18
|
import {
|
|
19
19
|
createDocumentServices,
|
|
20
|
+
getDocument as getDocument2,
|
|
20
21
|
indexDocumentNow
|
|
21
22
|
} from "@opengeni/documents";
|
|
22
|
-
import { dbSql, getWorkspace as getWorkspace5 } from "@opengeni/db";
|
|
23
|
+
import { dbSql, getWorkspace as getWorkspace5, rlsContextForWorkspace } from "@opengeni/db";
|
|
23
24
|
import { createObservability } from "@opengeni/observability";
|
|
24
25
|
import { createObjectStorage } from "@opengeni/storage";
|
|
25
26
|
import { WebStandardStreamableHTTPServerTransport as WebStandardStreamableHTTPServerTransport3 } from "@modelcontextprotocol/sdk/server/webStandardStreamableHttp.js";
|
|
@@ -10948,6 +10949,8 @@ import {
|
|
|
10948
10949
|
import {
|
|
10949
10950
|
GOOGLE_DRIVE_PROVIDER_DOMAIN as GOOGLE_DRIVE_PROVIDER_DOMAIN2,
|
|
10950
10951
|
GoogleDriveConnectionMetadata as GoogleDriveConnectionMetadata2,
|
|
10952
|
+
GoogleDriveDisconnectRequest,
|
|
10953
|
+
GoogleDriveLifecycleActionRequest,
|
|
10951
10954
|
GoogleDriveOAuthStartRequest,
|
|
10952
10955
|
GoogleDriveOAuthStartResponse as GoogleDriveOAuthStartResponse2
|
|
10953
10956
|
} from "@opengeni/contracts/google-drive";
|
|
@@ -10985,6 +10988,7 @@ import {
|
|
|
10985
10988
|
GOOGLE_DRIVE_READONLY_SCOPE,
|
|
10986
10989
|
GoogleDriveBrowseItem,
|
|
10987
10990
|
GoogleDriveBrowseResponse,
|
|
10991
|
+
GoogleDriveConnectionLifecycle,
|
|
10988
10992
|
GoogleDriveConnectionMetadata,
|
|
10989
10993
|
GoogleDriveOAuthStartResponse,
|
|
10990
10994
|
SaveGoogleDriveSourceRequest,
|
|
@@ -10994,13 +10998,17 @@ import {
|
|
|
10994
10998
|
import { hasPermission as hasPermission7, requireEnvironmentEncryption as requireEnvironmentEncryption3 } from "@opengeni/core";
|
|
10995
10999
|
import {
|
|
10996
11000
|
buildConnectionTokenResolver as buildConnectionTokenResolver3,
|
|
11001
|
+
ConnectionDisconnectGenerationError,
|
|
11002
|
+
ConnectionDisconnectIdempotencyError,
|
|
10997
11003
|
consumeIntegrationOAuthStateNonce as consumeIntegrationOAuthStateNonce3,
|
|
10998
11004
|
createConnection as createConnection2,
|
|
10999
11005
|
decryptEnvironmentValue as decryptEnvironmentValue3,
|
|
11006
|
+
disconnectConnectionIdempotently,
|
|
11000
11007
|
encryptEnvironmentValue as encryptEnvironmentValue4,
|
|
11001
11008
|
getConnectionMetadata as getConnectionMetadata2,
|
|
11002
11009
|
getWorkspaceGrant as getWorkspaceGrant4,
|
|
11003
11010
|
loadConnectionCredentialForBroker,
|
|
11011
|
+
transitionConnectionState,
|
|
11004
11012
|
updateConnection as updateConnection2
|
|
11005
11013
|
} from "@opengeni/db";
|
|
11006
11014
|
import { createSignedState as createSignedState5, readSignedState as readSignedState4 } from "@opengeni/github";
|
|
@@ -11014,6 +11022,12 @@ var GOOGLE_RESPONSE_MAX_BYTES = 2 * 1024 * 1024;
|
|
|
11014
11022
|
var GOOGLE_REQUEST_TIMEOUT_MS = 1e4;
|
|
11015
11023
|
var GOOGLE_DRIVE_PAGE_SIZE = 100;
|
|
11016
11024
|
var GOOGLE_DRIVE_RETURN_PATH = (workspaceId) => `/workspaces/${workspaceId}/capabilities`;
|
|
11025
|
+
var GOOGLE_DRIVE_RECONSENT_ERROR_CODES = /* @__PURE__ */ new Set([
|
|
11026
|
+
"appNotAuthorizedToFile",
|
|
11027
|
+
"authError",
|
|
11028
|
+
"insufficientFilePermissions",
|
|
11029
|
+
"insufficientPermissions"
|
|
11030
|
+
]);
|
|
11017
11031
|
async function startGoogleDriveOAuth(deps, input) {
|
|
11018
11032
|
const google = requireGoogleDriveSettings(deps.settings);
|
|
11019
11033
|
const existing = input.payload.connectionId ? await getConnectionMetadata2(
|
|
@@ -11156,6 +11170,7 @@ async function completeGoogleDriveOAuthCallback(deps, input) {
|
|
|
11156
11170
|
googleDisplayName: identity.displayName,
|
|
11157
11171
|
verifiedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
11158
11172
|
accessMode: scopeDecision.accessMode,
|
|
11173
|
+
lifecycle: googleDriveLifecycle("active"),
|
|
11159
11174
|
...previousMetadata?.selectedSources ? { selectedSources: previousMetadata.selectedSources } : previousMetadata?.selectedSource ? { selectedSources: [previousMetadata.selectedSource] } : {}
|
|
11160
11175
|
});
|
|
11161
11176
|
const connection = existing ? await updateConnection2(deps.db, {
|
|
@@ -11201,6 +11216,101 @@ async function completeGoogleDriveOAuthCallback(deps, input) {
|
|
|
11201
11216
|
};
|
|
11202
11217
|
}
|
|
11203
11218
|
}
|
|
11219
|
+
async function transitionGoogleDriveLifecycle(deps, input) {
|
|
11220
|
+
const existing = await getConnectionMetadata2(
|
|
11221
|
+
deps.db,
|
|
11222
|
+
input.workspaceId,
|
|
11223
|
+
input.connectionId,
|
|
11224
|
+
input.subjectId
|
|
11225
|
+
);
|
|
11226
|
+
if (!existing) {
|
|
11227
|
+
throw new HTTPException10(404, { message: "Google Drive connection not found" });
|
|
11228
|
+
}
|
|
11229
|
+
const metadata = requireGoogleDriveConnection(existing, input.subjectId);
|
|
11230
|
+
const lifecycle = effectiveGoogleDriveLifecycle(existing, metadata);
|
|
11231
|
+
const targetState = input.payload.action === "pause" ? "paused" : "active";
|
|
11232
|
+
if (existing.status === "active" && lifecycle.state === targetState) {
|
|
11233
|
+
return existing;
|
|
11234
|
+
}
|
|
11235
|
+
if (existing.status === "revoked") {
|
|
11236
|
+
throw new HTTPException10(409, {
|
|
11237
|
+
message: "Google Drive is disconnected; connect it again instead"
|
|
11238
|
+
});
|
|
11239
|
+
}
|
|
11240
|
+
if (input.payload.action === "pause" && lifecycle.state !== "active") {
|
|
11241
|
+
throw new HTTPException10(409, {
|
|
11242
|
+
message: "Google Drive must be reconnected before it can be paused"
|
|
11243
|
+
});
|
|
11244
|
+
}
|
|
11245
|
+
if (input.payload.action === "resume" && lifecycle.state !== "paused") {
|
|
11246
|
+
throw new HTTPException10(409, {
|
|
11247
|
+
message: "Google Drive must be reconnected or re-consented before it can resume"
|
|
11248
|
+
});
|
|
11249
|
+
}
|
|
11250
|
+
if (existing.status !== "active" || existing.version !== input.payload.expectedVersion) {
|
|
11251
|
+
throw new HTTPException10(409, { message: "Google Drive connection changed; try again" });
|
|
11252
|
+
}
|
|
11253
|
+
const updated = await transitionConnectionState(deps.db, {
|
|
11254
|
+
workspaceId: input.workspaceId,
|
|
11255
|
+
connectionId: existing.id,
|
|
11256
|
+
visibleToSubjectId: input.subjectId,
|
|
11257
|
+
expectedVersion: existing.version,
|
|
11258
|
+
status: "active",
|
|
11259
|
+
metadata: GoogleDriveConnectionMetadata.parse({
|
|
11260
|
+
...metadata,
|
|
11261
|
+
lifecycle: googleDriveLifecycle(targetState)
|
|
11262
|
+
}),
|
|
11263
|
+
lastError: null,
|
|
11264
|
+
updatedBySubjectId: input.subjectId
|
|
11265
|
+
});
|
|
11266
|
+
if (!updated) {
|
|
11267
|
+
const converged = await getConnectionMetadata2(
|
|
11268
|
+
deps.db,
|
|
11269
|
+
input.workspaceId,
|
|
11270
|
+
input.connectionId,
|
|
11271
|
+
input.subjectId
|
|
11272
|
+
);
|
|
11273
|
+
if (converged?.status === "active") {
|
|
11274
|
+
const convergedMetadata = requireGoogleDriveConnection(converged, input.subjectId);
|
|
11275
|
+
if (effectiveGoogleDriveLifecycle(converged, convergedMetadata).state === targetState) {
|
|
11276
|
+
return converged;
|
|
11277
|
+
}
|
|
11278
|
+
}
|
|
11279
|
+
throw new HTTPException10(409, { message: "Google Drive connection changed; try again" });
|
|
11280
|
+
}
|
|
11281
|
+
return updated;
|
|
11282
|
+
}
|
|
11283
|
+
async function disconnectGoogleDrive(deps, input) {
|
|
11284
|
+
const metadata = requireGoogleDriveConnection(input.connection, input.subjectId);
|
|
11285
|
+
try {
|
|
11286
|
+
return await disconnectConnectionIdempotently(deps.db, {
|
|
11287
|
+
accountId: input.connection.accountId,
|
|
11288
|
+
workspaceId: input.workspaceId,
|
|
11289
|
+
subjectId: input.subjectId,
|
|
11290
|
+
connectionId: input.connection.id,
|
|
11291
|
+
expectedVersion: input.payload.expectedVersion,
|
|
11292
|
+
idempotencyKey: input.payload.idempotencyKey,
|
|
11293
|
+
metadata: GoogleDriveConnectionMetadata.parse({
|
|
11294
|
+
...metadata,
|
|
11295
|
+
lifecycle: googleDriveLifecycle("disconnected")
|
|
11296
|
+
}),
|
|
11297
|
+
lastError: null,
|
|
11298
|
+
updatedBySubjectId: input.subjectId
|
|
11299
|
+
});
|
|
11300
|
+
} catch (error) {
|
|
11301
|
+
if (error instanceof ConnectionDisconnectIdempotencyError) {
|
|
11302
|
+
throw new HTTPException10(409, {
|
|
11303
|
+
message: "Google Drive disconnect key was already used for another operation"
|
|
11304
|
+
});
|
|
11305
|
+
}
|
|
11306
|
+
if (error instanceof ConnectionDisconnectGenerationError) {
|
|
11307
|
+
throw new HTTPException10(409, {
|
|
11308
|
+
message: "Google Drive connection changed; refresh before disconnecting"
|
|
11309
|
+
});
|
|
11310
|
+
}
|
|
11311
|
+
throw error;
|
|
11312
|
+
}
|
|
11313
|
+
}
|
|
11204
11314
|
async function browseGoogleDrive(deps, input) {
|
|
11205
11315
|
const connection = await getConnectionMetadata2(
|
|
11206
11316
|
deps.db,
|
|
@@ -11211,7 +11321,7 @@ async function browseGoogleDrive(deps, input) {
|
|
|
11211
11321
|
if (!connection) {
|
|
11212
11322
|
throw new HTTPException10(404, { message: "Google Drive connection not found" });
|
|
11213
11323
|
}
|
|
11214
|
-
requireGoogleDriveSourceConnection(connection, input.subjectId);
|
|
11324
|
+
await requireGoogleDriveSourceConnection(deps, connection, input.subjectId);
|
|
11215
11325
|
const parentId = validDriveId(input.parentId, "parentId");
|
|
11216
11326
|
const currentItem = await resolveGoogleDriveBoundaryItem(deps, {
|
|
11217
11327
|
workspaceId: input.workspaceId,
|
|
@@ -11272,7 +11382,7 @@ async function saveGoogleDriveSource(deps, input) {
|
|
|
11272
11382
|
if (!existing) {
|
|
11273
11383
|
throw new HTTPException10(404, { message: "Google Drive connection not found" });
|
|
11274
11384
|
}
|
|
11275
|
-
requireGoogleDriveSourceConnection(existing, input.subjectId);
|
|
11385
|
+
await requireGoogleDriveSourceConnection(deps, existing, input.subjectId);
|
|
11276
11386
|
const verifiedSources = [];
|
|
11277
11387
|
for (const source of payload.sources) {
|
|
11278
11388
|
const sourceId = validDriveId(source.id, "source.id");
|
|
@@ -11295,8 +11405,8 @@ async function saveGoogleDriveSource(deps, input) {
|
|
|
11295
11405
|
input.connectionId,
|
|
11296
11406
|
input.subjectId
|
|
11297
11407
|
) ?? existing;
|
|
11298
|
-
const latestMetadata = requireGoogleDriveSourceConnection(latest, input.subjectId);
|
|
11299
|
-
const updated = await
|
|
11408
|
+
const latestMetadata = await requireGoogleDriveSourceConnection(deps, latest, input.subjectId);
|
|
11409
|
+
const updated = await transitionConnectionState(deps.db, {
|
|
11300
11410
|
workspaceId: input.workspaceId,
|
|
11301
11411
|
connectionId: latest.id,
|
|
11302
11412
|
visibleToSubjectId: input.subjectId,
|
|
@@ -11407,11 +11517,60 @@ function requireGoogleDriveConnection(connection, subjectId) {
|
|
|
11407
11517
|
}
|
|
11408
11518
|
return parsed.data;
|
|
11409
11519
|
}
|
|
11410
|
-
function
|
|
11520
|
+
function googleDriveLifecycle(state) {
|
|
11521
|
+
return GoogleDriveConnectionLifecycle.parse({
|
|
11522
|
+
state,
|
|
11523
|
+
recoverable: state !== "app_removed",
|
|
11524
|
+
observedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
11525
|
+
});
|
|
11526
|
+
}
|
|
11527
|
+
function effectiveGoogleDriveLifecycle(connection, metadata) {
|
|
11528
|
+
if (metadata.lifecycle) return metadata.lifecycle;
|
|
11529
|
+
if (connection.status === "revoked") return googleDriveLifecycle("disconnected");
|
|
11530
|
+
if (connection.status === "active") return googleDriveLifecycle("active");
|
|
11531
|
+
return googleDriveLifecycle("reconnect_required");
|
|
11532
|
+
}
|
|
11533
|
+
async function transitionGoogleDriveConnectionLifecycle(deps, connection, subjectId, lifecycle, status, lastError) {
|
|
11534
|
+
const metadata = requireGoogleDriveConnection(connection, subjectId);
|
|
11535
|
+
if (connection.status === status && metadata.lifecycle?.state === lifecycle.state && metadata.lifecycle.recoverable === lifecycle.recoverable) {
|
|
11536
|
+
return connection;
|
|
11537
|
+
}
|
|
11538
|
+
return await transitionConnectionState(deps.db, {
|
|
11539
|
+
workspaceId: connection.workspaceId,
|
|
11540
|
+
connectionId: connection.id,
|
|
11541
|
+
visibleToSubjectId: subjectId,
|
|
11542
|
+
expectedVersion: connection.version,
|
|
11543
|
+
status,
|
|
11544
|
+
metadata: GoogleDriveConnectionMetadata.parse({ ...metadata, lifecycle }),
|
|
11545
|
+
lastError,
|
|
11546
|
+
updatedBySubjectId: subjectId
|
|
11547
|
+
});
|
|
11548
|
+
}
|
|
11549
|
+
async function requireGoogleDriveSourceConnection(deps, connection, subjectId) {
|
|
11411
11550
|
const metadata = requireGoogleDriveConnection(connection, subjectId);
|
|
11551
|
+
const lifecycle = effectiveGoogleDriveLifecycle(connection, metadata);
|
|
11552
|
+
if (connection.status === "revoked") {
|
|
11553
|
+
throw new HTTPException10(409, { message: "Google Drive is disconnected" });
|
|
11554
|
+
}
|
|
11555
|
+
if (lifecycle.state === "paused") {
|
|
11556
|
+
throw new HTTPException10(409, { message: "Google Drive is paused" });
|
|
11557
|
+
}
|
|
11558
|
+
if (connection.status !== "active" || lifecycle.state !== "active") {
|
|
11559
|
+
throw new HTTPException10(401, {
|
|
11560
|
+
message: lifecycle.state === "reconsent_required" ? "Google Drive needs permission re-consent" : lifecycle.state === "app_removed" ? "Google Drive app access is unavailable" : "Google Drive needs to be reconnected"
|
|
11561
|
+
});
|
|
11562
|
+
}
|
|
11412
11563
|
if (!googleDriveScopesAllowCapability(connection.grantedScopes, "recursive_source_sync")) {
|
|
11564
|
+
await transitionGoogleDriveConnectionLifecycle(
|
|
11565
|
+
deps,
|
|
11566
|
+
connection,
|
|
11567
|
+
subjectId,
|
|
11568
|
+
googleDriveLifecycle("reconsent_required"),
|
|
11569
|
+
"needs_reauth",
|
|
11570
|
+
"google_drive_reconsent_required"
|
|
11571
|
+
);
|
|
11413
11572
|
throw new HTTPException10(401, {
|
|
11414
|
-
message: "Google Drive needs
|
|
11573
|
+
message: "Google Drive needs permission re-consent for selected-source read access"
|
|
11415
11574
|
});
|
|
11416
11575
|
}
|
|
11417
11576
|
return metadata;
|
|
@@ -11522,8 +11681,93 @@ async function verifyGoogleDriveIdentity(accessToken, fetchImpl) {
|
|
|
11522
11681
|
displayName: optionalString(user.displayName)
|
|
11523
11682
|
};
|
|
11524
11683
|
}
|
|
11684
|
+
function googleDriveRefreshFailureLifecycle(failure) {
|
|
11685
|
+
const code = failure.oauthErrorCode?.toLowerCase() ?? null;
|
|
11686
|
+
if (code === "invalid_client" || code === "unauthorized_client") {
|
|
11687
|
+
return {
|
|
11688
|
+
lifecycle: googleDriveLifecycle("app_removed"),
|
|
11689
|
+
status: "error",
|
|
11690
|
+
lastError: "google_drive_app_removed"
|
|
11691
|
+
};
|
|
11692
|
+
}
|
|
11693
|
+
if (code === "invalid_scope" || code === "insufficient_scope") {
|
|
11694
|
+
return {
|
|
11695
|
+
lifecycle: googleDriveLifecycle("reconsent_required"),
|
|
11696
|
+
status: "needs_reauth",
|
|
11697
|
+
lastError: "google_drive_reconsent_required"
|
|
11698
|
+
};
|
|
11699
|
+
}
|
|
11700
|
+
if (code === "invalid_grant") {
|
|
11701
|
+
return {
|
|
11702
|
+
lifecycle: googleDriveLifecycle("token_revoked"),
|
|
11703
|
+
status: "needs_reauth",
|
|
11704
|
+
lastError: "google_drive_token_revoked"
|
|
11705
|
+
};
|
|
11706
|
+
}
|
|
11707
|
+
return {
|
|
11708
|
+
lifecycle: googleDriveLifecycle("reconnect_required"),
|
|
11709
|
+
status: "needs_reauth",
|
|
11710
|
+
lastError: "google_drive_reconnect_required"
|
|
11711
|
+
};
|
|
11712
|
+
}
|
|
11713
|
+
async function transitionGoogleDrivePermanentRefreshFailure(deps, failure) {
|
|
11714
|
+
if (failure.providerDomain !== GOOGLE_DRIVE_PROVIDER_DOMAIN || !failure.subjectId) {
|
|
11715
|
+
return false;
|
|
11716
|
+
}
|
|
11717
|
+
const connection = await getConnectionMetadata2(
|
|
11718
|
+
deps.db,
|
|
11719
|
+
failure.workspaceId,
|
|
11720
|
+
failure.connectionId,
|
|
11721
|
+
failure.subjectId
|
|
11722
|
+
);
|
|
11723
|
+
if (!connection || connection.version !== failure.connectionVersion) {
|
|
11724
|
+
return true;
|
|
11725
|
+
}
|
|
11726
|
+
const transition = googleDriveRefreshFailureLifecycle(failure);
|
|
11727
|
+
await transitionGoogleDriveConnectionLifecycle(
|
|
11728
|
+
deps,
|
|
11729
|
+
connection,
|
|
11730
|
+
failure.subjectId,
|
|
11731
|
+
transition.lifecycle,
|
|
11732
|
+
transition.status,
|
|
11733
|
+
transition.lastError
|
|
11734
|
+
);
|
|
11735
|
+
return true;
|
|
11736
|
+
}
|
|
11737
|
+
async function transitionGoogleDriveProviderResponseFailure(deps, input) {
|
|
11738
|
+
const latest = await getConnectionMetadata2(
|
|
11739
|
+
deps.db,
|
|
11740
|
+
input.workspaceId,
|
|
11741
|
+
input.connectionId,
|
|
11742
|
+
input.subjectId
|
|
11743
|
+
);
|
|
11744
|
+
if (!latest || latest.version !== input.connectionVersion || latest.status !== "active") {
|
|
11745
|
+
return;
|
|
11746
|
+
}
|
|
11747
|
+
await transitionGoogleDriveConnectionLifecycle(
|
|
11748
|
+
deps,
|
|
11749
|
+
latest,
|
|
11750
|
+
input.subjectId,
|
|
11751
|
+
input.lifecycle,
|
|
11752
|
+
input.status,
|
|
11753
|
+
input.lastError
|
|
11754
|
+
);
|
|
11755
|
+
}
|
|
11525
11756
|
async function googleDriveApiRequest(deps, input) {
|
|
11526
|
-
const
|
|
11757
|
+
const current = await getConnectionMetadata2(
|
|
11758
|
+
deps.db,
|
|
11759
|
+
input.workspaceId,
|
|
11760
|
+
input.connectionId,
|
|
11761
|
+
input.subjectId
|
|
11762
|
+
);
|
|
11763
|
+
if (!current) {
|
|
11764
|
+
throw new HTTPException10(404, { message: "Google Drive connection not found" });
|
|
11765
|
+
}
|
|
11766
|
+
await requireGoogleDriveSourceConnection(deps, current, input.subjectId);
|
|
11767
|
+
const resolver = buildConnectionTokenResolver3(deps.db, deps.settings, void 0, {
|
|
11768
|
+
...deps.googleDriveFetch ? { refreshTransport: { fetchImpl: deps.googleDriveFetch } } : {},
|
|
11769
|
+
transitionPermanentRefreshFailure: async (failure) => await transitionGoogleDrivePermanentRefreshFailure(deps, failure)
|
|
11770
|
+
});
|
|
11527
11771
|
const resolve = async (forceRefresh) => await resolver({
|
|
11528
11772
|
workspaceId: input.workspaceId,
|
|
11529
11773
|
subjectId: input.subjectId,
|
|
@@ -11542,6 +11786,10 @@ async function googleDriveApiRequest(deps, input) {
|
|
|
11542
11786
|
if (credential.status !== "ok") {
|
|
11543
11787
|
throw new HTTPException10(401, { message: "Google Drive needs to be reconnected" });
|
|
11544
11788
|
}
|
|
11789
|
+
let providerConnectionVersion = credential.connectionVersion;
|
|
11790
|
+
if (providerConnectionVersion === void 0) {
|
|
11791
|
+
throw new Error("Google Drive credential resolver omitted the connection version");
|
|
11792
|
+
}
|
|
11545
11793
|
const fetchImpl = deps.googleDriveFetch ?? fetch;
|
|
11546
11794
|
let response = await providerFetch(fetchImpl, input.url, {
|
|
11547
11795
|
headers: { ...credential.headers, accept: "application/json" }
|
|
@@ -11552,14 +11800,45 @@ async function googleDriveApiRequest(deps, input) {
|
|
|
11552
11800
|
if (credential.status !== "ok") {
|
|
11553
11801
|
throw new HTTPException10(401, { message: "Google Drive needs to be reconnected" });
|
|
11554
11802
|
}
|
|
11803
|
+
providerConnectionVersion = credential.connectionVersion;
|
|
11804
|
+
if (providerConnectionVersion === void 0) {
|
|
11805
|
+
throw new Error("Google Drive credential resolver omitted the connection version");
|
|
11806
|
+
}
|
|
11555
11807
|
response = await providerFetch(fetchImpl, input.url, {
|
|
11556
11808
|
headers: { ...credential.headers, accept: "application/json" }
|
|
11557
11809
|
});
|
|
11558
11810
|
}
|
|
11559
11811
|
if (!response.ok) {
|
|
11560
|
-
|
|
11812
|
+
if (response.status === 401) {
|
|
11813
|
+
await response.body?.cancel().catch(() => void 0);
|
|
11814
|
+
await transitionGoogleDriveProviderResponseFailure(deps, {
|
|
11815
|
+
workspaceId: input.workspaceId,
|
|
11816
|
+
subjectId: input.subjectId,
|
|
11817
|
+
connectionId: input.connectionId,
|
|
11818
|
+
connectionVersion: providerConnectionVersion,
|
|
11819
|
+
lifecycle: googleDriveLifecycle("reconnect_required"),
|
|
11820
|
+
status: "needs_reauth",
|
|
11821
|
+
lastError: "google_drive_reconnect_required"
|
|
11822
|
+
});
|
|
11823
|
+
throw new HTTPException10(401, { message: "Google Drive needs to be reconnected" });
|
|
11824
|
+
}
|
|
11825
|
+
const providerErrorCode = response.status === 403 ? await readGoogleDriveProviderErrorCode(response) : null;
|
|
11826
|
+
if (response.status !== 403) {
|
|
11827
|
+
await response.body?.cancel().catch(() => void 0);
|
|
11828
|
+
}
|
|
11829
|
+
if (response.status === 403 && providerErrorCode && GOOGLE_DRIVE_RECONSENT_ERROR_CODES.has(providerErrorCode)) {
|
|
11830
|
+
await transitionGoogleDriveProviderResponseFailure(deps, {
|
|
11831
|
+
workspaceId: input.workspaceId,
|
|
11832
|
+
subjectId: input.subjectId,
|
|
11833
|
+
connectionId: input.connectionId,
|
|
11834
|
+
connectionVersion: providerConnectionVersion,
|
|
11835
|
+
lifecycle: googleDriveLifecycle("reconsent_required"),
|
|
11836
|
+
status: "needs_reauth",
|
|
11837
|
+
lastError: "google_drive_reconsent_required"
|
|
11838
|
+
});
|
|
11839
|
+
}
|
|
11561
11840
|
throw new HTTPException10(response.status === 403 ? 403 : 502, {
|
|
11562
|
-
message: response.status === 403 ? "Google Drive denied metadata access;
|
|
11841
|
+
message: response.status === 403 ? "Google Drive denied metadata access; re-consent may be required" : "Google Drive metadata request failed"
|
|
11563
11842
|
});
|
|
11564
11843
|
}
|
|
11565
11844
|
return await readResponseJsonBounded5(response, GOOGLE_RESPONSE_MAX_BYTES, input.label);
|
|
@@ -11575,6 +11854,24 @@ async function providerFetch(fetchImpl, url, init) {
|
|
|
11575
11854
|
throw new HTTPException10(502, { message: "Google Drive is temporarily unavailable" });
|
|
11576
11855
|
}
|
|
11577
11856
|
}
|
|
11857
|
+
async function readGoogleDriveProviderErrorCode(response) {
|
|
11858
|
+
try {
|
|
11859
|
+
const payload = objectRecord(
|
|
11860
|
+
await readResponseJsonBounded5(
|
|
11861
|
+
response,
|
|
11862
|
+
GOOGLE_RESPONSE_MAX_BYTES,
|
|
11863
|
+
"Google Drive error response"
|
|
11864
|
+
)
|
|
11865
|
+
);
|
|
11866
|
+
const error = objectRecord(payload.error);
|
|
11867
|
+
const first = Array.isArray(error.errors) ? objectRecord(error.errors[0]) : {};
|
|
11868
|
+
const code = optionalString(first.reason) ?? optionalString(error.status);
|
|
11869
|
+
return code && /^[A-Za-z0-9_.-]{1,64}$/.test(code) ? code : null;
|
|
11870
|
+
} catch {
|
|
11871
|
+
await response.body?.cancel().catch(() => void 0);
|
|
11872
|
+
return null;
|
|
11873
|
+
}
|
|
11874
|
+
}
|
|
11578
11875
|
function parseDriveItem(value) {
|
|
11579
11876
|
const item = objectRecord(value);
|
|
11580
11877
|
const id = optionalString(item.id);
|
|
@@ -11864,6 +12161,28 @@ function registerConnectionRoutes(app, deps) {
|
|
|
11864
12161
|
});
|
|
11865
12162
|
return c.redirect(result.redirectTo, 302);
|
|
11866
12163
|
});
|
|
12164
|
+
app.patch(
|
|
12165
|
+
"/v1/workspaces/:workspaceId/connections/google-drive/:connectionId/lifecycle",
|
|
12166
|
+
async (c) => {
|
|
12167
|
+
assertIntegrationsEnabled();
|
|
12168
|
+
const workspaceId = c.req.param("workspaceId");
|
|
12169
|
+
const grant = await requireAccessGrant3(c, deps, workspaceId, "connections:write");
|
|
12170
|
+
const parsed = GoogleDriveLifecycleActionRequest.safeParse(await c.req.json());
|
|
12171
|
+
if (!parsed.success) {
|
|
12172
|
+
throw new HTTPException11(400, { message: "invalid Google Drive lifecycle request" });
|
|
12173
|
+
}
|
|
12174
|
+
return c.json(
|
|
12175
|
+
ConnectionResponse.parse({
|
|
12176
|
+
connection: await transitionGoogleDriveLifecycle(deps, {
|
|
12177
|
+
workspaceId,
|
|
12178
|
+
subjectId: grant.subjectId,
|
|
12179
|
+
connectionId: c.req.param("connectionId"),
|
|
12180
|
+
payload: parsed.data
|
|
12181
|
+
})
|
|
12182
|
+
})
|
|
12183
|
+
);
|
|
12184
|
+
}
|
|
12185
|
+
);
|
|
11867
12186
|
app.get(
|
|
11868
12187
|
"/v1/workspaces/:workspaceId/connections/google-drive/:connectionId/browse",
|
|
11869
12188
|
async (c) => {
|
|
@@ -11980,7 +12299,22 @@ function registerConnectionRoutes(app, deps) {
|
|
|
11980
12299
|
if (!existing) {
|
|
11981
12300
|
throw new HTTPException11(404, { message: "connection not found" });
|
|
11982
12301
|
}
|
|
11983
|
-
const
|
|
12302
|
+
const isGoogleDrive = existing.subjectId === grant.subjectId && existing.providerDomain === GOOGLE_DRIVE_PROVIDER_DOMAIN2 && existing.kind === "oauth2" && GoogleDriveConnectionMetadata2.safeParse(existing.metadata).success;
|
|
12303
|
+
const googleDriveDisconnect = isGoogleDrive ? GoogleDriveDisconnectRequest.safeParse(await c.req.json().catch(() => null)) : null;
|
|
12304
|
+
if (googleDriveDisconnect && !googleDriveDisconnect.success) {
|
|
12305
|
+
throw new HTTPException11(400, {
|
|
12306
|
+
message: googleDriveDisconnect.error.issues[0]?.message ?? "invalid Google Drive disconnect request"
|
|
12307
|
+
});
|
|
12308
|
+
}
|
|
12309
|
+
if (existing.status === "revoked" && !isGoogleDrive) {
|
|
12310
|
+
return c.json(ConnectionResponse.parse({ connection: existing }));
|
|
12311
|
+
}
|
|
12312
|
+
const connection = isGoogleDrive ? await disconnectGoogleDrive(deps, {
|
|
12313
|
+
workspaceId,
|
|
12314
|
+
subjectId: grant.subjectId,
|
|
12315
|
+
connection: existing,
|
|
12316
|
+
payload: googleDriveDisconnect.data
|
|
12317
|
+
}) : isOpenGeniSlackBotConnection2(existing) ? await revokeConnectionWithSlackBotSuccessAudit(db, {
|
|
11984
12318
|
accountId: grant.accountId,
|
|
11985
12319
|
workspaceId,
|
|
11986
12320
|
subjectId: grant.subjectId,
|
|
@@ -11989,7 +12323,7 @@ function registerConnectionRoutes(app, deps) {
|
|
|
11989
12323
|
credentialRole: OPENGENI_SLACK_BOT_CREDENTIAL_ROLE2,
|
|
11990
12324
|
credentialLabel: OPENGENI_SLACK_BOT_CREDENTIAL_LABEL2,
|
|
11991
12325
|
slackTeamId: openGeniSlackBotMetadata2(existing.metadata).slackTeamId
|
|
11992
|
-
}) : await revokeConnection(db, workspaceId, connectionId, grant.subjectId);
|
|
12326
|
+
}) : await revokeConnection(db, workspaceId, connectionId, grant.subjectId, existing.version);
|
|
11993
12327
|
if (!connection) {
|
|
11994
12328
|
throw new HTTPException11(409, { message: "connection changed during disconnect; try again" });
|
|
11995
12329
|
}
|
|
@@ -12326,6 +12660,7 @@ import {
|
|
|
12326
12660
|
Document,
|
|
12327
12661
|
DocumentBase,
|
|
12328
12662
|
DocumentSearchRequest,
|
|
12663
|
+
DocumentSearchResponse as DocumentSearchResponse2,
|
|
12329
12664
|
KnowledgeMemory,
|
|
12330
12665
|
KnowledgeMemorySearchRequest,
|
|
12331
12666
|
MoveDocumentRequest,
|
|
@@ -12354,18 +12689,19 @@ import {
|
|
|
12354
12689
|
listDocuments,
|
|
12355
12690
|
moveDocumentToBase,
|
|
12356
12691
|
queueDocumentForReindex,
|
|
12357
|
-
|
|
12692
|
+
searchEffectiveDocuments as searchEffectiveDocuments2
|
|
12358
12693
|
} from "@opengeni/documents";
|
|
12359
12694
|
import { WebStandardStreamableHTTPServerTransport as WebStandardStreamableHTTPServerTransport2 } from "@modelcontextprotocol/sdk/server/webStandardStreamableHttp.js";
|
|
12360
12695
|
import { HTTPException as HTTPException13 } from "hono/http-exception";
|
|
12361
|
-
import { requireAccessGrant as requireAccessGrant5 } from "@opengeni/core";
|
|
12696
|
+
import { requireAccessGrant as requireAccessGrant5, requireAccessGrantAuthorization } from "@opengeni/core";
|
|
12362
12697
|
import { recordWorkspaceUsage as recordWorkspaceUsage3, requireLimit as requireLimit3 } from "@opengeni/core";
|
|
12363
12698
|
|
|
12364
12699
|
// src/mcp/documents.ts
|
|
12700
|
+
import { DocumentSearchResponse } from "@opengeni/contracts";
|
|
12365
12701
|
import {
|
|
12366
12702
|
getDocumentChunk,
|
|
12367
12703
|
listDocumentBases,
|
|
12368
|
-
|
|
12704
|
+
searchEffectiveDocuments
|
|
12369
12705
|
} from "@opengeni/documents";
|
|
12370
12706
|
import { createKnowledgeMemory, listKnowledgeMemories } from "@opengeni/db";
|
|
12371
12707
|
import { McpServer as McpServer2 } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
@@ -12397,14 +12733,14 @@ var SourceRefSchema = z2.object({
|
|
|
12397
12733
|
title: z2.string().min(1).optional(),
|
|
12398
12734
|
metadata: z2.record(z2.string(), z2.unknown()).optional()
|
|
12399
12735
|
});
|
|
12400
|
-
function buildDocumentsMcpServer(db, accountId, workspaceId, documentServices, options
|
|
12736
|
+
function buildDocumentsMcpServer(db, accountId, workspaceId, documentServices, options) {
|
|
12401
12737
|
const server = new McpServer2({
|
|
12402
12738
|
name: "opengeni-documents",
|
|
12403
12739
|
version: "1.0.0"
|
|
12404
12740
|
});
|
|
12405
12741
|
const agentAccess = {
|
|
12406
12742
|
agentOnly: true,
|
|
12407
|
-
|
|
12743
|
+
viewerSubjectId: options.initiatingSubjectId
|
|
12408
12744
|
};
|
|
12409
12745
|
server.registerTool(
|
|
12410
12746
|
"list_document_bases",
|
|
@@ -12422,15 +12758,31 @@ function buildDocumentsMcpServer(db, accountId, workspaceId, documentServices, o
|
|
|
12422
12758
|
description: "Search indexed documents with hybrid, vector, or keyword retrieval.",
|
|
12423
12759
|
inputSchema: SearchInputSchema
|
|
12424
12760
|
},
|
|
12425
|
-
async (input) => searchContent(
|
|
12761
|
+
async (input) => searchContent(
|
|
12762
|
+
db,
|
|
12763
|
+
accountId,
|
|
12764
|
+
workspaceId,
|
|
12765
|
+
documentServices,
|
|
12766
|
+
input,
|
|
12767
|
+
options.initiatingSubjectId,
|
|
12768
|
+
false
|
|
12769
|
+
)
|
|
12426
12770
|
);
|
|
12427
12771
|
server.registerTool(
|
|
12428
12772
|
"knowledge_search",
|
|
12429
12773
|
{
|
|
12430
|
-
description: "Search
|
|
12774
|
+
description: "Search the effective authorized organization, current-workspace, and immutable initiating-user personal document scope. Authorization is applied before ranking and every result retains source and authority provenance.",
|
|
12431
12775
|
inputSchema: SearchInputSchema
|
|
12432
12776
|
},
|
|
12433
|
-
async (input) => searchContent(
|
|
12777
|
+
async (input) => searchContent(
|
|
12778
|
+
db,
|
|
12779
|
+
accountId,
|
|
12780
|
+
workspaceId,
|
|
12781
|
+
documentServices,
|
|
12782
|
+
input,
|
|
12783
|
+
options.initiatingSubjectId,
|
|
12784
|
+
true
|
|
12785
|
+
)
|
|
12434
12786
|
);
|
|
12435
12787
|
server.registerTool(
|
|
12436
12788
|
"fetch_document_chunk",
|
|
@@ -12441,7 +12793,7 @@ function buildDocumentsMcpServer(db, accountId, workspaceId, documentServices, o
|
|
|
12441
12793
|
}
|
|
12442
12794
|
},
|
|
12443
12795
|
async ({ chunkId }) => {
|
|
12444
|
-
const found = await getDocumentChunk(db, workspaceId, chunkId, agentAccess);
|
|
12796
|
+
const found = await getDocumentChunk(db, accountId, workspaceId, chunkId, agentAccess);
|
|
12445
12797
|
return {
|
|
12446
12798
|
content: [
|
|
12447
12799
|
{ type: "text", text: found ? JSON.stringify(found) : `chunk not found: ${chunkId}` }
|
|
@@ -12459,7 +12811,7 @@ function buildDocumentsMcpServer(db, accountId, workspaceId, documentServices, o
|
|
|
12459
12811
|
}
|
|
12460
12812
|
},
|
|
12461
12813
|
async ({ chunkId }) => {
|
|
12462
|
-
const found = await getDocumentChunk(db, workspaceId, chunkId, agentAccess);
|
|
12814
|
+
const found = await getDocumentChunk(db, accountId, workspaceId, chunkId, agentAccess);
|
|
12463
12815
|
return {
|
|
12464
12816
|
content: [
|
|
12465
12817
|
{ type: "text", text: found ? JSON.stringify(found) : `chunk not found: ${chunkId}` }
|
|
@@ -12536,27 +12888,28 @@ function buildDocumentsMcpServer(db, accountId, workspaceId, documentServices, o
|
|
|
12536
12888
|
);
|
|
12537
12889
|
return server;
|
|
12538
12890
|
}
|
|
12539
|
-
async function searchContent(db, workspaceId, documentServices, input,
|
|
12891
|
+
async function searchContent(db, accountId, workspaceId, documentServices, input, initiatingSubjectId, wrapResponse) {
|
|
12892
|
+
const results = await searchEffectiveDocuments(
|
|
12893
|
+
db,
|
|
12894
|
+
{
|
|
12895
|
+
accountId,
|
|
12896
|
+
workspaceId,
|
|
12897
|
+
query: input.query,
|
|
12898
|
+
...input.baseIds ? { baseIds: input.baseIds } : {},
|
|
12899
|
+
...input.limit ? { limit: input.limit } : {},
|
|
12900
|
+
...input.mode ? { mode: input.mode } : {},
|
|
12901
|
+
...input.sourceKinds ? { sourceKinds: input.sourceKinds } : {},
|
|
12902
|
+
...input.aclTags ? { aclTags: input.aclTags } : {},
|
|
12903
|
+
initiatingSubjectId,
|
|
12904
|
+
surface: "agent"
|
|
12905
|
+
},
|
|
12906
|
+
documentServices
|
|
12907
|
+
);
|
|
12540
12908
|
return {
|
|
12541
12909
|
content: [
|
|
12542
12910
|
{
|
|
12543
12911
|
type: "text",
|
|
12544
|
-
text: JSON.stringify(
|
|
12545
|
-
await searchDocuments(
|
|
12546
|
-
db,
|
|
12547
|
-
{
|
|
12548
|
-
workspaceId,
|
|
12549
|
-
query: input.query,
|
|
12550
|
-
...input.baseIds ? { baseIds: input.baseIds } : {},
|
|
12551
|
-
...input.limit ? { limit: input.limit } : {},
|
|
12552
|
-
...input.mode ? { mode: input.mode } : {},
|
|
12553
|
-
...input.sourceKinds ? { sourceKinds: input.sourceKinds } : {},
|
|
12554
|
-
...input.aclTags ? { aclTags: input.aclTags } : {},
|
|
12555
|
-
access
|
|
12556
|
-
},
|
|
12557
|
-
documentServices
|
|
12558
|
-
)
|
|
12559
|
-
)
|
|
12912
|
+
text: JSON.stringify(wrapResponse ? DocumentSearchResponse.parse({ results }) : results)
|
|
12560
12913
|
}
|
|
12561
12914
|
]
|
|
12562
12915
|
};
|
|
@@ -13047,7 +13400,8 @@ function registerDocumentRoutes(app, deps) {
|
|
|
13047
13400
|
});
|
|
13048
13401
|
app.post("/v1/workspaces/:workspaceId/document-bases/:baseId/documents", async (c) => {
|
|
13049
13402
|
const workspaceId = c.req.param("workspaceId");
|
|
13050
|
-
const
|
|
13403
|
+
const access = await requireAccessGrantAuthorization(c, deps, workspaceId, "documents:manage");
|
|
13404
|
+
const { grant } = access;
|
|
13051
13405
|
if (!objectStorage) {
|
|
13052
13406
|
throw new HTTPException13(503, { message: "object storage is not configured" });
|
|
13053
13407
|
}
|
|
@@ -13058,6 +13412,10 @@ function registerDocumentRoutes(app, deps) {
|
|
|
13058
13412
|
quantity: 0
|
|
13059
13413
|
});
|
|
13060
13414
|
const payload = AddDocumentRequest.parse(await c.req.json());
|
|
13415
|
+
const organizationAuthorityGranted = access.accountGrant?.permissions.includes("account:admin") === true;
|
|
13416
|
+
if (payload.authorityKind === "organization" && !organizationAuthorityGranted) {
|
|
13417
|
+
throw new HTTPException13(403, { message: "missing permission: account:admin" });
|
|
13418
|
+
}
|
|
13061
13419
|
try {
|
|
13062
13420
|
const document = await addDocumentToBase(db, {
|
|
13063
13421
|
...payload,
|
|
@@ -13065,13 +13423,18 @@ function registerDocumentRoutes(app, deps) {
|
|
|
13065
13423
|
workspaceId,
|
|
13066
13424
|
baseId: c.req.param("baseId"),
|
|
13067
13425
|
createdBy: grant.subjectId,
|
|
13426
|
+
initiatingSubjectId: grant.subjectId,
|
|
13427
|
+
organizationAuthorityGranted,
|
|
13068
13428
|
access: { viewerSubjectId: grant.subjectId }
|
|
13069
13429
|
});
|
|
13070
13430
|
const wasCreated = document.status === "queued" && document.chunkCount === 0 && document.error === null;
|
|
13071
13431
|
const indexed = document.status === "ready" ? document : await documentIndexer.indexDocument({
|
|
13072
13432
|
accountId: grant.accountId,
|
|
13073
13433
|
workspaceId,
|
|
13074
|
-
documentId: document.id
|
|
13434
|
+
documentId: document.id,
|
|
13435
|
+
authorityKind: document.authorityKind,
|
|
13436
|
+
authorityWorkspaceId: document.authorityWorkspaceId,
|
|
13437
|
+
authoritySubjectId: document.authoritySubjectId
|
|
13075
13438
|
}) ?? document;
|
|
13076
13439
|
if (indexed.status === "ready") {
|
|
13077
13440
|
await recordWorkspaceUsage3(deps, {
|
|
@@ -13104,13 +13467,28 @@ function registerDocumentRoutes(app, deps) {
|
|
|
13104
13467
|
"/v1/workspaces/:workspaceId/document-bases/:baseId/documents/:documentId",
|
|
13105
13468
|
async (c) => {
|
|
13106
13469
|
const workspaceId = c.req.param("workspaceId");
|
|
13107
|
-
const
|
|
13470
|
+
const authorization = await requireAccessGrantAuthorization(
|
|
13471
|
+
c,
|
|
13472
|
+
deps,
|
|
13473
|
+
workspaceId,
|
|
13474
|
+
"documents:manage"
|
|
13475
|
+
);
|
|
13476
|
+
const { grant } = authorization;
|
|
13477
|
+
const organizationAuthorityGranted = hasAccountAdminAuthority(authorization);
|
|
13108
13478
|
try {
|
|
13479
|
+
const document = await getDocument(db, workspaceId, c.req.param("documentId"), {
|
|
13480
|
+
viewerSubjectId: grant.subjectId
|
|
13481
|
+
});
|
|
13482
|
+
if (!document || document.baseId !== c.req.param("baseId")) {
|
|
13483
|
+
throw new HTTPException13(404, { message: "document not found" });
|
|
13484
|
+
}
|
|
13485
|
+
requireOrganizationDocumentAuthority(document.authorityKind, organizationAuthorityGranted);
|
|
13109
13486
|
await deleteDocumentFromBase(db, {
|
|
13110
13487
|
accountId: grant.accountId,
|
|
13111
13488
|
workspaceId,
|
|
13112
13489
|
baseId: c.req.param("baseId"),
|
|
13113
13490
|
documentId: c.req.param("documentId"),
|
|
13491
|
+
organizationAuthorityGranted,
|
|
13114
13492
|
access: { viewerSubjectId: grant.subjectId }
|
|
13115
13493
|
});
|
|
13116
13494
|
return c.body(null, 204);
|
|
@@ -13126,7 +13504,14 @@ function registerDocumentRoutes(app, deps) {
|
|
|
13126
13504
|
"/v1/workspaces/:workspaceId/document-bases/:baseId/documents/:documentId/reindex",
|
|
13127
13505
|
async (c) => {
|
|
13128
13506
|
const workspaceId = c.req.param("workspaceId");
|
|
13129
|
-
const
|
|
13507
|
+
const authorization = await requireAccessGrantAuthorization(
|
|
13508
|
+
c,
|
|
13509
|
+
deps,
|
|
13510
|
+
workspaceId,
|
|
13511
|
+
"documents:manage"
|
|
13512
|
+
);
|
|
13513
|
+
const { grant } = authorization;
|
|
13514
|
+
const organizationAuthorityGranted = hasAccountAdminAuthority(authorization);
|
|
13130
13515
|
if (!objectStorage) {
|
|
13131
13516
|
throw new HTTPException13(503, { message: "object storage is not configured" });
|
|
13132
13517
|
}
|
|
@@ -13143,19 +13528,29 @@ function registerDocumentRoutes(app, deps) {
|
|
|
13143
13528
|
if (!document) {
|
|
13144
13529
|
throw new HTTPException13(404, { message: "document not found" });
|
|
13145
13530
|
}
|
|
13531
|
+
requireOrganizationDocumentAuthority(document.authorityKind, organizationAuthorityGranted);
|
|
13146
13532
|
if (document.status !== "failed") {
|
|
13147
13533
|
throw new HTTPException13(422, { message: "only failed documents can be retried" });
|
|
13148
13534
|
}
|
|
13149
13535
|
if (document.baseId !== c.req.param("baseId")) {
|
|
13150
13536
|
throw new HTTPException13(404, { message: "document not found" });
|
|
13151
13537
|
}
|
|
13152
|
-
const queued = await queueDocumentForReindex(
|
|
13153
|
-
|
|
13154
|
-
|
|
13538
|
+
const queued = await queueDocumentForReindex(
|
|
13539
|
+
db,
|
|
13540
|
+
workspaceId,
|
|
13541
|
+
document.id,
|
|
13542
|
+
{
|
|
13543
|
+
viewerSubjectId: grant.subjectId
|
|
13544
|
+
},
|
|
13545
|
+
organizationAuthorityGranted
|
|
13546
|
+
);
|
|
13155
13547
|
const indexed = await documentIndexer.indexDocument({
|
|
13156
13548
|
accountId: grant.accountId,
|
|
13157
13549
|
workspaceId,
|
|
13158
|
-
documentId: document.id
|
|
13550
|
+
documentId: document.id,
|
|
13551
|
+
authorityKind: document.authorityKind,
|
|
13552
|
+
authorityWorkspaceId: document.authorityWorkspaceId,
|
|
13553
|
+
authoritySubjectId: document.authoritySubjectId
|
|
13159
13554
|
}) ?? queued;
|
|
13160
13555
|
if (indexed.status === "ready") {
|
|
13161
13556
|
await recordWorkspaceUsage3(deps, {
|
|
@@ -13187,47 +13582,56 @@ function registerDocumentRoutes(app, deps) {
|
|
|
13187
13582
|
if (!base) {
|
|
13188
13583
|
throw new HTTPException13(404, { message: "document base not found" });
|
|
13189
13584
|
}
|
|
13190
|
-
return c.json(
|
|
13191
|
-
|
|
13192
|
-
|
|
13193
|
-
|
|
13194
|
-
|
|
13195
|
-
|
|
13196
|
-
|
|
13197
|
-
|
|
13198
|
-
|
|
13199
|
-
|
|
13200
|
-
|
|
13201
|
-
|
|
13202
|
-
|
|
13203
|
-
|
|
13204
|
-
|
|
13205
|
-
|
|
13585
|
+
return c.json(
|
|
13586
|
+
DocumentSearchResponse2.parse({
|
|
13587
|
+
results: await searchEffectiveDocuments2(
|
|
13588
|
+
db,
|
|
13589
|
+
{
|
|
13590
|
+
accountId: grant.accountId,
|
|
13591
|
+
workspaceId,
|
|
13592
|
+
baseIds: [base.id],
|
|
13593
|
+
query: payload.query,
|
|
13594
|
+
limit: payload.limit,
|
|
13595
|
+
mode: payload.mode,
|
|
13596
|
+
sourceKinds: payload.sourceKinds,
|
|
13597
|
+
aclTags: payload.aclTags,
|
|
13598
|
+
initiatingSubjectId: grant.subjectId,
|
|
13599
|
+
surface: "human"
|
|
13600
|
+
},
|
|
13601
|
+
getDocumentServices()
|
|
13602
|
+
)
|
|
13603
|
+
})
|
|
13604
|
+
);
|
|
13206
13605
|
});
|
|
13207
13606
|
app.post("/v1/workspaces/:workspaceId/knowledge/search", async (c) => {
|
|
13208
13607
|
const workspaceId = c.req.param("workspaceId");
|
|
13209
13608
|
const grant = await requireAccessGrant5(c, deps, workspaceId, "documents:search");
|
|
13210
13609
|
const payload = await parseDocumentSearchRequest(c, "invalid knowledge search request");
|
|
13211
|
-
return c.json(
|
|
13212
|
-
|
|
13213
|
-
|
|
13214
|
-
|
|
13215
|
-
|
|
13216
|
-
|
|
13217
|
-
|
|
13218
|
-
|
|
13219
|
-
|
|
13220
|
-
|
|
13221
|
-
|
|
13222
|
-
|
|
13223
|
-
|
|
13224
|
-
|
|
13225
|
-
|
|
13226
|
-
|
|
13610
|
+
return c.json(
|
|
13611
|
+
DocumentSearchResponse2.parse({
|
|
13612
|
+
results: await searchEffectiveDocuments2(
|
|
13613
|
+
db,
|
|
13614
|
+
{
|
|
13615
|
+
accountId: grant.accountId,
|
|
13616
|
+
workspaceId,
|
|
13617
|
+
query: payload.query,
|
|
13618
|
+
baseIds: payload.baseIds,
|
|
13619
|
+
limit: payload.limit,
|
|
13620
|
+
mode: payload.mode,
|
|
13621
|
+
sourceKinds: payload.sourceKinds,
|
|
13622
|
+
aclTags: payload.aclTags,
|
|
13623
|
+
initiatingSubjectId: grant.subjectId,
|
|
13624
|
+
surface: "human"
|
|
13625
|
+
},
|
|
13626
|
+
getDocumentServices()
|
|
13627
|
+
)
|
|
13628
|
+
})
|
|
13629
|
+
);
|
|
13227
13630
|
});
|
|
13228
13631
|
app.post("/v1/workspaces/:workspaceId/knowledge/drops", async (c) => {
|
|
13229
13632
|
const workspaceId = c.req.param("workspaceId");
|
|
13230
|
-
const
|
|
13633
|
+
const access = await requireAccessGrantAuthorization(c, deps, workspaceId, "documents:manage");
|
|
13634
|
+
const { grant } = access;
|
|
13231
13635
|
if (!objectStorage) {
|
|
13232
13636
|
throw new HTTPException13(503, { message: "object storage is not configured" });
|
|
13233
13637
|
}
|
|
@@ -13238,6 +13642,10 @@ function registerDocumentRoutes(app, deps) {
|
|
|
13238
13642
|
quantity: 0
|
|
13239
13643
|
});
|
|
13240
13644
|
const payload = CreateKnowledgeDropRequest.parse(await c.req.json());
|
|
13645
|
+
const organizationAuthorityGranted = access.accountGrant?.permissions.includes("account:admin") === true;
|
|
13646
|
+
if (payload.authorityKind === "organization" && !organizationAuthorityGranted) {
|
|
13647
|
+
throw new HTTPException13(403, { message: "missing permission: account:admin" });
|
|
13648
|
+
}
|
|
13241
13649
|
try {
|
|
13242
13650
|
let fileId;
|
|
13243
13651
|
if (payload.text !== void 0) {
|
|
@@ -13298,12 +13706,15 @@ function registerDocumentRoutes(app, deps) {
|
|
|
13298
13706
|
const document = await addDocumentToBase(db, {
|
|
13299
13707
|
fileId,
|
|
13300
13708
|
...payload.title ? { title: payload.title } : {},
|
|
13709
|
+
...payload.authorityKind ? { authorityKind: payload.authorityKind } : {},
|
|
13301
13710
|
...payload.visibility ? { visibility: payload.visibility } : {},
|
|
13302
13711
|
...payload.agentAccess !== void 0 ? { agentAccess: payload.agentAccess } : {},
|
|
13303
13712
|
accountId: grant.accountId,
|
|
13304
13713
|
workspaceId,
|
|
13305
13714
|
baseId: defaultBase.id,
|
|
13306
13715
|
createdBy: grant.subjectId,
|
|
13716
|
+
initiatingSubjectId: grant.subjectId,
|
|
13717
|
+
organizationAuthorityGranted,
|
|
13307
13718
|
curationStatus: "pending",
|
|
13308
13719
|
access: { viewerSubjectId: grant.subjectId }
|
|
13309
13720
|
});
|
|
@@ -13311,7 +13722,10 @@ function registerDocumentRoutes(app, deps) {
|
|
|
13311
13722
|
const indexed = document.status === "ready" ? document : await documentIndexer.indexDocument({
|
|
13312
13723
|
accountId: grant.accountId,
|
|
13313
13724
|
workspaceId,
|
|
13314
|
-
documentId: document.id
|
|
13725
|
+
documentId: document.id,
|
|
13726
|
+
authorityKind: document.authorityKind,
|
|
13727
|
+
authorityWorkspaceId: document.authorityWorkspaceId,
|
|
13728
|
+
authoritySubjectId: document.authoritySubjectId
|
|
13315
13729
|
}) ?? document;
|
|
13316
13730
|
if (indexed.status === "ready") {
|
|
13317
13731
|
await recordWorkspaceUsage3(deps, {
|
|
@@ -13336,7 +13750,14 @@ function registerDocumentRoutes(app, deps) {
|
|
|
13336
13750
|
});
|
|
13337
13751
|
app.post("/v1/workspaces/:workspaceId/documents/:documentId/move", async (c) => {
|
|
13338
13752
|
const workspaceId = c.req.param("workspaceId");
|
|
13339
|
-
const
|
|
13753
|
+
const authorization = await requireAccessGrantAuthorization(
|
|
13754
|
+
c,
|
|
13755
|
+
deps,
|
|
13756
|
+
workspaceId,
|
|
13757
|
+
"documents:manage"
|
|
13758
|
+
);
|
|
13759
|
+
const { grant } = authorization;
|
|
13760
|
+
const organizationAuthorityGranted = hasAccountAdminAuthority(authorization);
|
|
13340
13761
|
const payload = MoveDocumentRequest.parse(await c.req.json().catch(() => ({})));
|
|
13341
13762
|
try {
|
|
13342
13763
|
const document = await getDocument(db, workspaceId, c.req.param("documentId"), {
|
|
@@ -13345,6 +13766,7 @@ function registerDocumentRoutes(app, deps) {
|
|
|
13345
13766
|
if (!document) {
|
|
13346
13767
|
throw new HTTPException13(404, { message: "document not found" });
|
|
13347
13768
|
}
|
|
13769
|
+
requireOrganizationDocumentAuthority(document.authorityKind, organizationAuthorityGranted);
|
|
13348
13770
|
return c.json(
|
|
13349
13771
|
Document.parse(
|
|
13350
13772
|
await moveDocumentToBase(db, {
|
|
@@ -13352,6 +13774,7 @@ function registerDocumentRoutes(app, deps) {
|
|
|
13352
13774
|
workspaceId,
|
|
13353
13775
|
documentId: document.id,
|
|
13354
13776
|
targetBaseId: payload.targetBaseId ?? null,
|
|
13777
|
+
organizationAuthorityGranted,
|
|
13355
13778
|
access: { viewerSubjectId: grant.subjectId }
|
|
13356
13779
|
})
|
|
13357
13780
|
)
|
|
@@ -13488,7 +13911,7 @@ function registerDocumentRoutes(app, deps) {
|
|
|
13488
13911
|
grant.accountId,
|
|
13489
13912
|
workspaceId,
|
|
13490
13913
|
getDocumentServices(),
|
|
13491
|
-
{ createdBySessionId: sessionId,
|
|
13914
|
+
{ createdBySessionId: sessionId, initiatingSubjectId: grant.subjectId }
|
|
13492
13915
|
);
|
|
13493
13916
|
await server.connect(transport);
|
|
13494
13917
|
return await transport.handleRequest(c.req.raw);
|
|
@@ -13507,6 +13930,9 @@ function dropFilename(preferred) {
|
|
|
13507
13930
|
}
|
|
13508
13931
|
function documentHttpException(error) {
|
|
13509
13932
|
const message = error instanceof Error ? error.message : String(error);
|
|
13933
|
+
if (message.includes("organization document") && message.includes("exact account authority")) {
|
|
13934
|
+
return new HTTPException13(403, { message: "missing permission: account:admin" });
|
|
13935
|
+
}
|
|
13510
13936
|
if (message.includes("not found")) {
|
|
13511
13937
|
return new HTTPException13(404, { message });
|
|
13512
13938
|
}
|
|
@@ -13524,6 +13950,14 @@ function documentHttpException(error) {
|
|
|
13524
13950
|
}
|
|
13525
13951
|
return new HTTPException13(500, { message });
|
|
13526
13952
|
}
|
|
13953
|
+
function hasAccountAdminAuthority(authorization) {
|
|
13954
|
+
return authorization.accountGrant?.permissions.includes("account:admin") === true;
|
|
13955
|
+
}
|
|
13956
|
+
function requireOrganizationDocumentAuthority(authorityKind, organizationAuthorityGranted) {
|
|
13957
|
+
if (authorityKind === "organization" && !organizationAuthorityGranted) {
|
|
13958
|
+
throw new HTTPException13(403, { message: "missing permission: account:admin" });
|
|
13959
|
+
}
|
|
13960
|
+
}
|
|
13527
13961
|
|
|
13528
13962
|
// src/routes/enrollments.ts
|
|
13529
13963
|
import {
|
|
@@ -16679,6 +17113,10 @@ The initial conversation items are authoritative context from the current sessio
|
|
|
16679
17113
|
|
|
16680
17114
|
Live context wrapped in <session_user_message> is an authoritative user message already routed to the current session. A status of queued_for_execution means it is waiting behind existing work; accepted_for_execution means it is next with no existing work ahead; accepted_for_steering means it was given priority as a change of direction, while any prior work may still be yielding. Incorporate it immediately as conversation context, but never delegate it again or treat the wrapper metadata as user-authored text.
|
|
16681
17115
|
|
|
17116
|
+
Live context wrapped in <session_human_input_request> means current work is paused for the user's answer. Preserve the exact question meaning and options. Ask one question at a time when useful. The user may answer in the visible form or answer conversationally. If the user answers conversationally, create exactly one delegation containing the relevant question and the user's answer so the session agent can continue with complete context. If the user changes direction instead, delegate the new direction normally. Do not claim work resumed until session context confirms it.
|
|
17117
|
+
|
|
17118
|
+
Live context wrapped in <session_human_input_response> is the authoritative outcome of that pending question. An answered or skipped response came through the structured session UI and is already routed; incorporate it, never delegate it again, and acknowledge briefly only if useful. An expired or cancelled response means the question is no longer active.
|
|
17119
|
+
|
|
16682
17120
|
Live session updates may describe work that started before this realtime conversation, work sent directly by the user, or work delegated during an earlier realtime connection. Treat those updates as part of this same session even when they have no current delegation identity.
|
|
16683
17121
|
|
|
16684
17122
|
## Backend use
|
|
@@ -21426,6 +21864,7 @@ function requireAccountPermission(context, accountId, permission) {
|
|
|
21426
21864
|
}
|
|
21427
21865
|
|
|
21428
21866
|
// src/routes/workspace-instruction-policies.ts
|
|
21867
|
+
import { randomUUID } from "crypto";
|
|
21429
21868
|
import {
|
|
21430
21869
|
ActivateWorkspaceInstructionPolicyRequest,
|
|
21431
21870
|
CreateWorkspaceInstructionPolicyDraftRequest,
|
|
@@ -21437,6 +21876,7 @@ import {
|
|
|
21437
21876
|
WorkspaceInstructionPolicyDiffResponse,
|
|
21438
21877
|
WorkspaceInstructionPolicyListQuery,
|
|
21439
21878
|
WorkspaceInstructionPolicyListResponse,
|
|
21879
|
+
WorkspaceInstructionPolicyOperationReuseResponse,
|
|
21440
21880
|
WorkspaceInstructionPolicyRevision
|
|
21441
21881
|
} from "@opengeni/contracts";
|
|
21442
21882
|
import { requireAccessGrant as requireAccessGrant17 } from "@opengeni/core";
|
|
@@ -21451,7 +21891,8 @@ import {
|
|
|
21451
21891
|
WorkspaceInstructionPolicyConflictError,
|
|
21452
21892
|
WorkspaceInstructionPolicyInvalidOperationError,
|
|
21453
21893
|
WorkspaceInstructionPolicyLegacyUnavailableError,
|
|
21454
|
-
WorkspaceInstructionPolicyNotFoundError
|
|
21894
|
+
WorkspaceInstructionPolicyNotFoundError,
|
|
21895
|
+
WorkspaceInstructionPolicyOperationReuseError
|
|
21455
21896
|
} from "@opengeni/db";
|
|
21456
21897
|
import { HTTPException as HTTPException27 } from "hono/http-exception";
|
|
21457
21898
|
import { z as z7 } from "zod";
|
|
@@ -21474,6 +21915,15 @@ function policyErrorResponse(context, error) {
|
|
|
21474
21915
|
409
|
|
21475
21916
|
);
|
|
21476
21917
|
}
|
|
21918
|
+
if (error instanceof WorkspaceInstructionPolicyOperationReuseError) {
|
|
21919
|
+
return context.json(
|
|
21920
|
+
WorkspaceInstructionPolicyOperationReuseResponse.parse({
|
|
21921
|
+
code: error.code,
|
|
21922
|
+
message: error.message
|
|
21923
|
+
}),
|
|
21924
|
+
409
|
|
21925
|
+
);
|
|
21926
|
+
}
|
|
21477
21927
|
if (error instanceof WorkspaceInstructionPolicyNotFoundError) {
|
|
21478
21928
|
return context.json(
|
|
21479
21929
|
{ code: "WORKSPACE_INSTRUCTION_POLICY_NOT_FOUND", message: error.message },
|
|
@@ -21536,6 +21986,7 @@ function registerWorkspaceInstructionPolicyRoutes(app, deps) {
|
|
|
21536
21986
|
return context.json(
|
|
21537
21987
|
WorkspaceInstructionPolicyRevision.parse(
|
|
21538
21988
|
await createWorkspaceInstructionPolicyDraft(deps.db, {
|
|
21989
|
+
operationId: request.operationId ?? randomUUID(),
|
|
21539
21990
|
accountId: grant.accountId,
|
|
21540
21991
|
workspaceId,
|
|
21541
21992
|
createdBySubjectId: grant.subjectId,
|
|
@@ -21563,6 +22014,7 @@ function registerWorkspaceInstructionPolicyRoutes(app, deps) {
|
|
|
21563
22014
|
return context.json(
|
|
21564
22015
|
WorkspaceInstructionPolicyRevision.parse(
|
|
21565
22016
|
await importLegacyWorkspaceInstructionPolicyDraft(deps.db, {
|
|
22017
|
+
operationId: request.operationId ?? randomUUID(),
|
|
21566
22018
|
accountId: grant.accountId,
|
|
21567
22019
|
workspaceId,
|
|
21568
22020
|
createdBySubjectId: grant.subjectId,
|
|
@@ -21604,10 +22056,12 @@ function registerWorkspaceInstructionPolicyRoutes(app, deps) {
|
|
|
21604
22056
|
return context.json(
|
|
21605
22057
|
WorkspaceInstructionPolicyActivationResponse.parse(
|
|
21606
22058
|
await rollbackWorkspaceInstructionPolicyRevision(deps.db, {
|
|
22059
|
+
operationId: request.operationId ?? randomUUID(),
|
|
21607
22060
|
accountId: grant.accountId,
|
|
21608
22061
|
workspaceId,
|
|
21609
22062
|
targetRevisionId: request.targetRevisionId,
|
|
21610
22063
|
expectedCurrentRevisionId: request.expectedCurrentRevisionId,
|
|
22064
|
+
...request.expectedActivationVersion === void 0 ? {} : { expectedActivationVersion: request.expectedActivationVersion },
|
|
21611
22065
|
actorSubjectId: grant.subjectId,
|
|
21612
22066
|
reason: request.reason
|
|
21613
22067
|
})
|
|
@@ -21641,10 +22095,12 @@ function registerWorkspaceInstructionPolicyRoutes(app, deps) {
|
|
|
21641
22095
|
return context.json(
|
|
21642
22096
|
WorkspaceInstructionPolicyActivationResponse.parse(
|
|
21643
22097
|
await activateWorkspaceInstructionPolicyRevision(deps.db, {
|
|
22098
|
+
operationId: request.operationId ?? randomUUID(),
|
|
21644
22099
|
accountId: grant.accountId,
|
|
21645
22100
|
workspaceId,
|
|
21646
22101
|
revisionId,
|
|
21647
22102
|
expectedCurrentRevisionId: request.expectedCurrentRevisionId,
|
|
22103
|
+
...request.expectedActivationVersion === void 0 ? {} : { expectedActivationVersion: request.expectedActivationVersion },
|
|
21648
22104
|
actorSubjectId: grant.subjectId,
|
|
21649
22105
|
reason: request.reason
|
|
21650
22106
|
})
|
|
@@ -21661,11 +22117,14 @@ import {
|
|
|
21661
22117
|
WORKSPACE_STATE_MAX_BASES as WORKSPACE_STATE_MAX_BASES2,
|
|
21662
22118
|
WORKSPACE_STATE_MAX_TOPICS as WORKSPACE_STATE_MAX_TOPICS2,
|
|
21663
22119
|
WORKSPACE_STATE_TOPIC_MAX_CHARS as WORKSPACE_STATE_TOPIC_MAX_CHARS2,
|
|
22120
|
+
WorkspaceStateQuery,
|
|
21664
22121
|
WorkspaceStateResponse as WorkspaceStateResponse2
|
|
21665
22122
|
} from "@opengeni/contracts";
|
|
21666
22123
|
import { hasPermission as hasPermission12, requireAccessGrant as requireAccessGrant18 } from "@opengeni/core";
|
|
21667
22124
|
import {
|
|
21668
22125
|
getWorkspace as getWorkspace2,
|
|
22126
|
+
getCurrentPreferenceRegistryGovernanceMetadata,
|
|
22127
|
+
getWorkspaceStateAcceptedAttemptGovernance,
|
|
21669
22128
|
listWorkspaceStateMemoryRecords,
|
|
21670
22129
|
listWorkspaceInstructionPolicyRevisions as listWorkspaceInstructionPolicyRevisions2
|
|
21671
22130
|
} from "@opengeni/db";
|
|
@@ -21673,6 +22132,7 @@ import { getDocumentInventory } from "@opengeni/documents";
|
|
|
21673
22132
|
import { HTTPException as HTTPException28 } from "hono/http-exception";
|
|
21674
22133
|
|
|
21675
22134
|
// src/workspace-state-projection.ts
|
|
22135
|
+
import { createHash as createHash8 } from "crypto";
|
|
21676
22136
|
import {
|
|
21677
22137
|
KnowledgeMemoryKind,
|
|
21678
22138
|
KnowledgeMemoryStatus,
|
|
@@ -21685,6 +22145,140 @@ import {
|
|
|
21685
22145
|
WORKSPACE_STATE_TOPIC_MAX_CHARS,
|
|
21686
22146
|
WorkspaceStateResponse
|
|
21687
22147
|
} from "@opengeni/contracts";
|
|
22148
|
+
function hashIdentities(values) {
|
|
22149
|
+
return createHash8("sha256").update(values.join("\n"), "utf8").digest("hex");
|
|
22150
|
+
}
|
|
22151
|
+
function policyTargetKey(value) {
|
|
22152
|
+
return `${value.kind}:${value.scope}:${value.roleKey ?? ""}`;
|
|
22153
|
+
}
|
|
22154
|
+
function policyTargetKeysForRole(policyRole) {
|
|
22155
|
+
const keys = /* @__PURE__ */ new Set(["charter:global:", "policy:global:"]);
|
|
22156
|
+
if (policyRole !== null) keys.add(`policy:role:${policyRole}`);
|
|
22157
|
+
return keys;
|
|
22158
|
+
}
|
|
22159
|
+
function policyIdentity(value) {
|
|
22160
|
+
return `${policyTargetKey(value)}:${value.revisionId}:${value.contentHash}:${value.activationVersion}`;
|
|
22161
|
+
}
|
|
22162
|
+
function preferenceIdentity(value) {
|
|
22163
|
+
return `${value.scope}:${value.id}:${value.revisionId}:${value.contentHash}:${value.activeVersion}`;
|
|
22164
|
+
}
|
|
22165
|
+
function classifyIdentityDrift(snapshotIdentities, currentIdentities, snapshotKeys, currentKeys) {
|
|
22166
|
+
if (snapshotIdentities.join("\n") === currentIdentities.join("\n")) return "identical";
|
|
22167
|
+
return snapshotKeys.join("\n") === currentKeys.join("\n") ? "superseded" : "changed";
|
|
22168
|
+
}
|
|
22169
|
+
function overallDriftStatus(policy, preferences) {
|
|
22170
|
+
for (const status of ["unavailable", "truncated", "missing", "changed", "superseded"]) {
|
|
22171
|
+
if (policy === status || preferences === status) return status;
|
|
22172
|
+
}
|
|
22173
|
+
return "identical";
|
|
22174
|
+
}
|
|
22175
|
+
function attemptGovernanceProjection(input) {
|
|
22176
|
+
const governance = input.attemptGovernance ?? null;
|
|
22177
|
+
if (governance === null) return { status: "not_requested" };
|
|
22178
|
+
if (governance.status === "unavailable") {
|
|
22179
|
+
return {
|
|
22180
|
+
status: "unavailable",
|
|
22181
|
+
reason: "attempt_not_found_or_not_authorized",
|
|
22182
|
+
driftStatus: "unavailable"
|
|
22183
|
+
};
|
|
22184
|
+
}
|
|
22185
|
+
const policySnapshot = governance.policySnapshot;
|
|
22186
|
+
let policyStatus = "missing";
|
|
22187
|
+
let policySnapshotHash = null;
|
|
22188
|
+
let policyCurrentHash = null;
|
|
22189
|
+
let policySnapshotTargetCount = 0;
|
|
22190
|
+
let policyCurrentTargetCount = 0;
|
|
22191
|
+
if (policySnapshot) {
|
|
22192
|
+
const snapshotEntries = [...policySnapshot.entries].sort(
|
|
22193
|
+
(left, right) => policyTargetKey(left).localeCompare(policyTargetKey(right))
|
|
22194
|
+
);
|
|
22195
|
+
const snapshotKeys = snapshotEntries.map(policyTargetKey);
|
|
22196
|
+
const relevantTargetKeys = policyTargetKeysForRole(policySnapshot.policyRole);
|
|
22197
|
+
const currentEntries = input.policies.activeHeads.filter((head) => relevantTargetKeys.has(policyTargetKey(head))).sort((left, right) => policyTargetKey(left).localeCompare(policyTargetKey(right)));
|
|
22198
|
+
const snapshotIdentities = snapshotEntries.map(policyIdentity);
|
|
22199
|
+
const currentIdentities = currentEntries.map(policyIdentity);
|
|
22200
|
+
const currentKeys = currentEntries.map(policyTargetKey);
|
|
22201
|
+
policyStatus = classifyIdentityDrift(
|
|
22202
|
+
snapshotIdentities,
|
|
22203
|
+
currentIdentities,
|
|
22204
|
+
snapshotKeys,
|
|
22205
|
+
currentKeys
|
|
22206
|
+
);
|
|
22207
|
+
policySnapshotHash = hashIdentities(snapshotIdentities);
|
|
22208
|
+
policyCurrentHash = hashIdentities(currentIdentities);
|
|
22209
|
+
policySnapshotTargetCount = snapshotEntries.length;
|
|
22210
|
+
policyCurrentTargetCount = currentEntries.length;
|
|
22211
|
+
}
|
|
22212
|
+
const preferenceSnapshot = governance.preferenceSnapshot;
|
|
22213
|
+
const currentPreferences = [...governance.currentPreferences.descriptors].sort(
|
|
22214
|
+
(left, right) => preferenceIdentity(left).localeCompare(preferenceIdentity(right))
|
|
22215
|
+
);
|
|
22216
|
+
let preferenceStatus = "missing";
|
|
22217
|
+
let preferenceSnapshotHash = null;
|
|
22218
|
+
const currentPreferenceIdentities = currentPreferences.map(preferenceIdentity);
|
|
22219
|
+
const currentPreferenceHash = hashIdentities(currentPreferenceIdentities);
|
|
22220
|
+
let snapshotPreferenceCount = 0;
|
|
22221
|
+
let snapshotPreferenceTruncated = false;
|
|
22222
|
+
if (preferenceSnapshot) {
|
|
22223
|
+
const snapshotPreferences = [...preferenceSnapshot.descriptors].sort(
|
|
22224
|
+
(left, right) => preferenceIdentity(left).localeCompare(preferenceIdentity(right))
|
|
22225
|
+
);
|
|
22226
|
+
const snapshotPreferenceIdentities = snapshotPreferences.map(preferenceIdentity);
|
|
22227
|
+
const snapshotPreferenceKeys = snapshotPreferences.map((descriptor) => descriptor.id).sort();
|
|
22228
|
+
const currentPreferenceKeys = currentPreferences.map((descriptor) => descriptor.id).sort();
|
|
22229
|
+
preferenceSnapshotHash = hashIdentities(snapshotPreferenceIdentities);
|
|
22230
|
+
snapshotPreferenceCount = snapshotPreferences.length;
|
|
22231
|
+
snapshotPreferenceTruncated = preferenceSnapshot.truncated;
|
|
22232
|
+
preferenceStatus = preferenceSnapshot.truncated || governance.currentPreferences.truncated ? "truncated" : classifyIdentityDrift(
|
|
22233
|
+
snapshotPreferenceIdentities,
|
|
22234
|
+
currentPreferenceIdentities,
|
|
22235
|
+
snapshotPreferenceKeys,
|
|
22236
|
+
currentPreferenceKeys
|
|
22237
|
+
);
|
|
22238
|
+
}
|
|
22239
|
+
return {
|
|
22240
|
+
status: "available",
|
|
22241
|
+
attemptId: governance.attemptId,
|
|
22242
|
+
executionGeneration: governance.executionGeneration,
|
|
22243
|
+
acceptedAt: governance.acceptedAt,
|
|
22244
|
+
policySnapshot: policySnapshot ? {
|
|
22245
|
+
status: "available",
|
|
22246
|
+
id: policySnapshot.id,
|
|
22247
|
+
createdAt: policySnapshot.createdAt,
|
|
22248
|
+
entryHash: policySnapshot.entryHash,
|
|
22249
|
+
policyRole: policySnapshot.policyRole,
|
|
22250
|
+
roleSource: policySnapshot.roleSource,
|
|
22251
|
+
entries: policySnapshot.entries
|
|
22252
|
+
} : { status: "missing" },
|
|
22253
|
+
preferenceSnapshot: preferenceSnapshot ? {
|
|
22254
|
+
status: "available",
|
|
22255
|
+
id: preferenceSnapshot.id,
|
|
22256
|
+
createdAt: preferenceSnapshot.createdAt,
|
|
22257
|
+
descriptorHash: preferenceSnapshot.descriptorHash,
|
|
22258
|
+
descriptorCount: preferenceSnapshot.descriptors.length,
|
|
22259
|
+
truncated: preferenceSnapshot.truncated
|
|
22260
|
+
} : { status: "missing" },
|
|
22261
|
+
drift: {
|
|
22262
|
+
overall: overallDriftStatus(policyStatus, preferenceStatus),
|
|
22263
|
+
policy: {
|
|
22264
|
+
status: policyStatus,
|
|
22265
|
+
snapshotHash: policySnapshotHash,
|
|
22266
|
+
currentHash: policyCurrentHash,
|
|
22267
|
+
snapshotTargetCount: policySnapshotTargetCount,
|
|
22268
|
+
currentTargetCount: policyCurrentTargetCount
|
|
22269
|
+
},
|
|
22270
|
+
preferences: {
|
|
22271
|
+
status: preferenceStatus,
|
|
22272
|
+
snapshotHash: preferenceSnapshotHash,
|
|
22273
|
+
currentHash: currentPreferenceHash,
|
|
22274
|
+
snapshotDescriptorCount: snapshotPreferenceCount,
|
|
22275
|
+
currentDescriptorCount: currentPreferences.length,
|
|
22276
|
+
snapshotTruncated: snapshotPreferenceTruncated,
|
|
22277
|
+
currentTruncated: governance.currentPreferences.truncated
|
|
22278
|
+
}
|
|
22279
|
+
}
|
|
22280
|
+
};
|
|
22281
|
+
}
|
|
21688
22282
|
function emptyMemoryStatusCounts() {
|
|
21689
22283
|
return Object.fromEntries(
|
|
21690
22284
|
KnowledgeMemoryStatus.options.map((status) => [status, 0])
|
|
@@ -21856,10 +22450,7 @@ function projectWorkspaceState(input) {
|
|
|
21856
22450
|
generatedAt: input.generatedAt,
|
|
21857
22451
|
truth: {
|
|
21858
22452
|
current: { source: "read_time_projection", capturedAt: input.generatedAt },
|
|
21859
|
-
|
|
21860
|
-
status: "not_captured",
|
|
21861
|
-
reason: "workspace_instruction_policy_snapshot_not_implemented"
|
|
21862
|
-
}
|
|
22453
|
+
attemptGovernance: attemptGovernanceProjection(input)
|
|
21863
22454
|
},
|
|
21864
22455
|
policy: policyProjection(input),
|
|
21865
22456
|
knowledge: input.knowledge ? availableKnowledgeProjection(input.knowledge) : {
|
|
@@ -21874,10 +22465,11 @@ function projectWorkspaceState(input) {
|
|
|
21874
22465
|
function registerWorkspaceStateRoutes(app, deps) {
|
|
21875
22466
|
app.get("/v1/workspaces/:workspaceId/workspace-state", async (context) => {
|
|
21876
22467
|
const workspaceId = context.req.param("workspaceId");
|
|
22468
|
+
const query = WorkspaceStateQuery.parse(context.req.query());
|
|
21877
22469
|
const grant = await requireAccessGrant18(context, deps, workspaceId, "workspace:read");
|
|
21878
22470
|
const generatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
21879
22471
|
const canInspectKnowledge = hasPermission12(grant.permissions, "documents:search");
|
|
21880
|
-
const [workspace, policies, knowledge] = await Promise.all([
|
|
22472
|
+
const [workspace, policies, knowledge, attemptGovernance] = await Promise.all([
|
|
21881
22473
|
getWorkspace2(deps.db, workspaceId),
|
|
21882
22474
|
listWorkspaceInstructionPolicyRevisions2(deps.db, workspaceId, { limit: 1 }),
|
|
21883
22475
|
canInspectKnowledge ? (async () => {
|
|
@@ -21891,7 +22483,43 @@ function registerWorkspaceStateRoutes(app, deps) {
|
|
|
21891
22483
|
listWorkspaceStateMemoryRecords(deps.db, workspaceId)
|
|
21892
22484
|
]);
|
|
21893
22485
|
return { documents, memories };
|
|
21894
|
-
})() : Promise.resolve(null)
|
|
22486
|
+
})() : Promise.resolve(null),
|
|
22487
|
+
query.attemptId ? getWorkspaceStateAcceptedAttemptGovernance(deps.db, {
|
|
22488
|
+
accountId: grant.accountId,
|
|
22489
|
+
workspaceId,
|
|
22490
|
+
subjectId: grant.subjectId,
|
|
22491
|
+
attemptId: query.attemptId
|
|
22492
|
+
}).then(async (snapshot) => {
|
|
22493
|
+
if (!snapshot) return { status: "unavailable" };
|
|
22494
|
+
const currentPreferences = await getCurrentPreferenceRegistryGovernanceMetadata(
|
|
22495
|
+
deps.db,
|
|
22496
|
+
{
|
|
22497
|
+
workspaceId,
|
|
22498
|
+
subjectId: grant.subjectId
|
|
22499
|
+
}
|
|
22500
|
+
);
|
|
22501
|
+
return {
|
|
22502
|
+
status: "available",
|
|
22503
|
+
attemptId: snapshot.attemptId,
|
|
22504
|
+
executionGeneration: snapshot.executionGeneration,
|
|
22505
|
+
acceptedAt: snapshot.acceptedAt,
|
|
22506
|
+
policySnapshot: snapshot.policySnapshot,
|
|
22507
|
+
preferenceSnapshot: snapshot.preferenceSnapshot ? {
|
|
22508
|
+
id: snapshot.preferenceSnapshot.id,
|
|
22509
|
+
descriptorHash: snapshot.preferenceSnapshot.descriptorHash,
|
|
22510
|
+
descriptors: snapshot.preferenceSnapshot.descriptors.map((descriptor) => ({
|
|
22511
|
+
id: descriptor.id,
|
|
22512
|
+
revisionId: descriptor.revisionId,
|
|
22513
|
+
contentHash: descriptor.contentHash,
|
|
22514
|
+
activeVersion: descriptor.activeVersion,
|
|
22515
|
+
scope: descriptor.scope
|
|
22516
|
+
})),
|
|
22517
|
+
truncated: snapshot.preferenceSnapshot.truncated,
|
|
22518
|
+
createdAt: snapshot.preferenceSnapshot.createdAt
|
|
22519
|
+
} : null,
|
|
22520
|
+
currentPreferences
|
|
22521
|
+
};
|
|
22522
|
+
}) : Promise.resolve(null)
|
|
21895
22523
|
]);
|
|
21896
22524
|
if (!workspace) {
|
|
21897
22525
|
throw new HTTPException28(404, { message: "workspace not found" });
|
|
@@ -21904,7 +22532,8 @@ function registerWorkspaceStateRoutes(app, deps) {
|
|
|
21904
22532
|
generatedAt,
|
|
21905
22533
|
workspaceAgentInstructions: workspace.agentInstructions,
|
|
21906
22534
|
policies,
|
|
21907
|
-
knowledge
|
|
22535
|
+
knowledge,
|
|
22536
|
+
attemptGovernance
|
|
21908
22537
|
})
|
|
21909
22538
|
)
|
|
21910
22539
|
);
|
|
@@ -21912,7 +22541,7 @@ function registerWorkspaceStateRoutes(app, deps) {
|
|
|
21912
22541
|
}
|
|
21913
22542
|
|
|
21914
22543
|
// src/routes/workspace-artifacts.ts
|
|
21915
|
-
import { createHash as
|
|
22544
|
+
import { createHash as createHash9 } from "crypto";
|
|
21916
22545
|
import {
|
|
21917
22546
|
CreateWorkspaceArtifactRequest,
|
|
21918
22547
|
PublishWorkspaceArtifactVersionRequest,
|
|
@@ -21981,7 +22610,7 @@ function errorResponse(context, error) {
|
|
|
21981
22610
|
}
|
|
21982
22611
|
function contentMetadata(workspaceId, html) {
|
|
21983
22612
|
const bytes = encoder2.encode(html);
|
|
21984
|
-
const sha256 =
|
|
22613
|
+
const sha256 = createHash9("sha256").update(bytes).digest("hex");
|
|
21985
22614
|
return {
|
|
21986
22615
|
bytes,
|
|
21987
22616
|
contentSha256: sha256,
|
|
@@ -22007,7 +22636,7 @@ function prepareHtml(deps, workspaceId, html) {
|
|
|
22007
22636
|
}
|
|
22008
22637
|
function provenance(subjectId, idempotencyKey) {
|
|
22009
22638
|
return {
|
|
22010
|
-
operationKey: `subject:${
|
|
22639
|
+
operationKey: `subject:${createHash9("sha256").update(`${subjectId}:${idempotencyKey}`).digest("hex")}`,
|
|
22011
22640
|
actorSubjectId: subjectId,
|
|
22012
22641
|
sourceSessionId: null,
|
|
22013
22642
|
sourceTurnId: null,
|
|
@@ -22098,7 +22727,7 @@ function registerWorkspaceArtifactRoutes(app, deps) {
|
|
|
22098
22727
|
);
|
|
22099
22728
|
const object5 = await deps.objectStorage.getObjectBytes(ref.contentKey);
|
|
22100
22729
|
if (!object5) throw new HTTPException29(503, { message: "Artifact content is unavailable" });
|
|
22101
|
-
const actualHash =
|
|
22730
|
+
const actualHash = createHash9("sha256").update(object5.bytes).digest("hex");
|
|
22102
22731
|
if (actualHash !== ref.version.contentSha256) {
|
|
22103
22732
|
throw new HTTPException29(503, { message: "Artifact content failed integrity verification" });
|
|
22104
22733
|
}
|
|
@@ -22192,7 +22821,7 @@ import {
|
|
|
22192
22821
|
import {
|
|
22193
22822
|
hasPermission as hasPermission13,
|
|
22194
22823
|
requireAccessGrant as requireAccessGrant20,
|
|
22195
|
-
requireAccessGrantAuthorization
|
|
22824
|
+
requireAccessGrantAuthorization as requireAccessGrantAuthorization2
|
|
22196
22825
|
} from "@opengeni/core";
|
|
22197
22826
|
import {
|
|
22198
22827
|
activatePreferenceRegistryRevision,
|
|
@@ -22340,7 +22969,7 @@ function registerPreferenceRegistryRoutes(app, deps) {
|
|
|
22340
22969
|
});
|
|
22341
22970
|
app.post(`${base}/proposals`, async (context) => {
|
|
22342
22971
|
const workspaceId = context.req.param("workspaceId");
|
|
22343
|
-
const access = await
|
|
22972
|
+
const access = await requireAccessGrantAuthorization2(
|
|
22344
22973
|
context,
|
|
22345
22974
|
deps,
|
|
22346
22975
|
workspaceId,
|
|
@@ -22420,7 +23049,7 @@ function registerPreferenceRegistryRoutes(app, deps) {
|
|
|
22420
23049
|
});
|
|
22421
23050
|
app.post(`${base}/:preferenceId/activate`, async (context) => {
|
|
22422
23051
|
const workspaceId = context.req.param("workspaceId");
|
|
22423
|
-
const access = await
|
|
23052
|
+
const access = await requireAccessGrantAuthorization2(
|
|
22424
23053
|
context,
|
|
22425
23054
|
deps,
|
|
22426
23055
|
workspaceId,
|
|
@@ -22449,7 +23078,7 @@ function registerPreferenceRegistryRoutes(app, deps) {
|
|
|
22449
23078
|
});
|
|
22450
23079
|
app.post(`${base}/:preferenceId/correct`, async (context) => {
|
|
22451
23080
|
const workspaceId = context.req.param("workspaceId");
|
|
22452
|
-
const access = await
|
|
23081
|
+
const access = await requireAccessGrantAuthorization2(
|
|
22453
23082
|
context,
|
|
22454
23083
|
deps,
|
|
22455
23084
|
workspaceId,
|
|
@@ -22478,7 +23107,7 @@ function registerPreferenceRegistryRoutes(app, deps) {
|
|
|
22478
23107
|
});
|
|
22479
23108
|
app.post(`${base}/:preferenceId/scope`, async (context) => {
|
|
22480
23109
|
const workspaceId = context.req.param("workspaceId");
|
|
22481
|
-
const access = await
|
|
23110
|
+
const access = await requireAccessGrantAuthorization2(
|
|
22482
23111
|
context,
|
|
22483
23112
|
deps,
|
|
22484
23113
|
workspaceId,
|
|
@@ -22507,7 +23136,7 @@ function registerPreferenceRegistryRoutes(app, deps) {
|
|
|
22507
23136
|
});
|
|
22508
23137
|
app.post(`${base}/:preferenceId/deactivate`, async (context) => {
|
|
22509
23138
|
const workspaceId = context.req.param("workspaceId");
|
|
22510
|
-
const access = await
|
|
23139
|
+
const access = await requireAccessGrantAuthorization2(
|
|
22511
23140
|
context,
|
|
22512
23141
|
deps,
|
|
22513
23142
|
workspaceId,
|
|
@@ -22536,7 +23165,7 @@ function registerPreferenceRegistryRoutes(app, deps) {
|
|
|
22536
23165
|
});
|
|
22537
23166
|
app.post(`${base}/:preferenceId/supersede`, async (context) => {
|
|
22538
23167
|
const workspaceId = context.req.param("workspaceId");
|
|
22539
|
-
const access = await
|
|
23168
|
+
const access = await requireAccessGrantAuthorization2(
|
|
22540
23169
|
context,
|
|
22541
23170
|
deps,
|
|
22542
23171
|
workspaceId,
|
|
@@ -22565,7 +23194,7 @@ function registerPreferenceRegistryRoutes(app, deps) {
|
|
|
22565
23194
|
});
|
|
22566
23195
|
app.post(`${base}/:preferenceId/reject`, async (context) => {
|
|
22567
23196
|
const workspaceId = context.req.param("workspaceId");
|
|
22568
|
-
const access = await
|
|
23197
|
+
const access = await requireAccessGrantAuthorization2(
|
|
22569
23198
|
context,
|
|
22570
23199
|
deps,
|
|
22571
23200
|
workspaceId,
|
|
@@ -23072,7 +23701,7 @@ async function firstAvailable(providers, context) {
|
|
|
23072
23701
|
}
|
|
23073
23702
|
|
|
23074
23703
|
// src/integrations/slack-interactions.ts
|
|
23075
|
-
import { createHash as
|
|
23704
|
+
import { createHash as createHash10, createHmac as createHmac2, timingSafeEqual as timingSafeEqual2 } from "crypto";
|
|
23076
23705
|
import {
|
|
23077
23706
|
DEFAULT_FIRST_PARTY_MCP_TOOLS as DEFAULT_FIRST_PARTY_MCP_TOOLS2,
|
|
23078
23707
|
hasOpenGeniSlackReactionScope,
|
|
@@ -23220,7 +23849,7 @@ function slackReactionInboxEntry(payload, bot, settings) {
|
|
|
23220
23849
|
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) {
|
|
23221
23850
|
return null;
|
|
23222
23851
|
}
|
|
23223
|
-
const stableReactionIdentity =
|
|
23852
|
+
const stableReactionIdentity = createHash10("sha256").update([teamId, userId, channelId, timestamp, reaction].join("\n")).digest("hex");
|
|
23224
23853
|
return {
|
|
23225
23854
|
providerEventId: eventId,
|
|
23226
23855
|
providerMessageId: `reaction:${stableReactionIdentity}`,
|
|
@@ -24221,7 +24850,7 @@ function slackRouteKey(channelId, threadTs) {
|
|
|
24221
24850
|
return `${channelId}:${threadTs}`;
|
|
24222
24851
|
}
|
|
24223
24852
|
function deterministicUuid(value) {
|
|
24224
|
-
const bytes =
|
|
24853
|
+
const bytes = createHash10("sha256").update(value).digest().subarray(0, 16);
|
|
24225
24854
|
bytes[6] = bytes[6] & 15 | 80;
|
|
24226
24855
|
bytes[8] = bytes[8] & 63 | 128;
|
|
24227
24856
|
const hex = bytes.toString("hex");
|
|
@@ -24358,14 +24987,27 @@ function createAppComposition(deps) {
|
|
|
24358
24987
|
indexDocument: async ({
|
|
24359
24988
|
accountId,
|
|
24360
24989
|
workspaceId,
|
|
24361
|
-
documentId
|
|
24990
|
+
documentId,
|
|
24991
|
+
authorityKind,
|
|
24992
|
+
authorityWorkspaceId,
|
|
24993
|
+
authoritySubjectId
|
|
24362
24994
|
}) => {
|
|
24363
24995
|
if (!objectStorage) {
|
|
24364
24996
|
throw new HTTPException33(503, {
|
|
24365
24997
|
message: "object storage is not configured"
|
|
24366
24998
|
});
|
|
24367
24999
|
}
|
|
24368
|
-
|
|
25000
|
+
const context = await rlsContextForWorkspace(deps.db, workspaceId);
|
|
25001
|
+
if (context.accountId !== accountId) {
|
|
25002
|
+
throw new Error("document account/workspace authority mismatch");
|
|
25003
|
+
}
|
|
25004
|
+
const claimedDocument = await getDocument2(deps.db, workspaceId, documentId, {
|
|
25005
|
+
viewerSubjectId: authoritySubjectId
|
|
25006
|
+
});
|
|
25007
|
+
if (!claimedDocument || claimedDocument.authorityKind !== authorityKind || claimedDocument.authorityWorkspaceId !== authorityWorkspaceId || claimedDocument.authoritySubjectId !== authoritySubjectId) {
|
|
25008
|
+
throw new Error("document authority changed before indexing");
|
|
25009
|
+
}
|
|
25010
|
+
const document = await indexDocumentNow(
|
|
24369
25011
|
deps.db,
|
|
24370
25012
|
objectStorage,
|
|
24371
25013
|
workspaceId,
|
|
@@ -24380,8 +25022,13 @@ function createAppComposition(deps) {
|
|
|
24380
25022
|
quantity: chunkCount
|
|
24381
25023
|
});
|
|
24382
25024
|
}
|
|
24383
|
-
}
|
|
25025
|
+
},
|
|
25026
|
+
{ viewerSubjectId: authoritySubjectId }
|
|
24384
25027
|
);
|
|
25028
|
+
if (document.authorityKind !== authorityKind || document.authorityWorkspaceId !== authorityWorkspaceId || document.authoritySubjectId !== authoritySubjectId) {
|
|
25029
|
+
throw new Error("document authority changed before indexing");
|
|
25030
|
+
}
|
|
25031
|
+
return document;
|
|
24385
25032
|
}
|
|
24386
25033
|
};
|
|
24387
25034
|
const sandboxClient = deps.sandboxClient ?? createApiSandboxClient(deps.settings);
|
|
@@ -25349,4 +25996,4 @@ export {
|
|
|
25349
25996
|
withDefaultEnabledCapabilityMcpTools,
|
|
25350
25997
|
workflowIdForSession2 as workflowIdForSession
|
|
25351
25998
|
};
|
|
25352
|
-
//# sourceMappingURL=chunk-
|
|
25999
|
+
//# sourceMappingURL=chunk-AEVD7E2F.js.map
|