@opengeni/documents 0.6.9-canary.0 → 0.7.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/index.d.ts +89 -0
- package/dist/index.js +200 -1
- package/dist/index.js.map +1 -1
- package/package.json +5 -5
- package/src/index.ts +266 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@opengeni/documents",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.7.0-canary.0",
|
|
4
4
|
"license": "Apache-2.0",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -40,10 +40,10 @@
|
|
|
40
40
|
},
|
|
41
41
|
"dependencies": {
|
|
42
42
|
"@llamaindex/liteparse": "^1.5.3",
|
|
43
|
-
"@opengeni/config": "^0.19.
|
|
44
|
-
"@opengeni/contracts": "^2.
|
|
45
|
-
"@opengeni/db": "^3.
|
|
46
|
-
"@opengeni/storage": "^0.2.
|
|
43
|
+
"@opengeni/config": "^0.19.1-canary.0",
|
|
44
|
+
"@opengeni/contracts": "^2.3.0-canary.0",
|
|
45
|
+
"@opengeni/db": "^3.2.0-canary.0",
|
|
46
|
+
"@opengeni/storage": "^0.2.106-canary.0",
|
|
47
47
|
"drizzle-orm": "^0.45.2",
|
|
48
48
|
"openai": "6.47.0"
|
|
49
49
|
}
|
package/src/index.ts
CHANGED
|
@@ -26,6 +26,13 @@ import {
|
|
|
26
26
|
type ReclassifyDocumentAuthorityRequest,
|
|
27
27
|
type RunDocumentDefaultCollectionBackfillRequest,
|
|
28
28
|
DocumentDefaultCollectionBackfill,
|
|
29
|
+
DocumentDefaultCollectionBackfillAudit,
|
|
30
|
+
DocumentDefaultCollectionBackfillOperationAudit,
|
|
31
|
+
DocumentDefaultCollectionBackfillReceiptAudit,
|
|
32
|
+
DocumentDefaultCollectionBackfillRunAudit,
|
|
33
|
+
ListDocumentDefaultCollectionBackfillRunsResponse,
|
|
34
|
+
ListOrganizationDocumentAuthorityReclassificationsResponse,
|
|
35
|
+
OrganizationDocumentAuthorityReclassification,
|
|
29
36
|
} from "@opengeni/contracts";
|
|
30
37
|
import {
|
|
31
38
|
createPersonalDocumentAuthority,
|
|
@@ -197,6 +204,15 @@ export type RunDocumentDefaultCollectionBackfillInput =
|
|
|
197
204
|
accountAdminAuthorization: DocumentAccountAdminAuthorization;
|
|
198
205
|
};
|
|
199
206
|
|
|
207
|
+
export type DocumentMigrationAuditInput = {
|
|
208
|
+
accountId: string;
|
|
209
|
+
workspaceId: string;
|
|
210
|
+
actorSubjectId: string;
|
|
211
|
+
accountAdminAuthorization: DocumentAccountAdminAuthorization;
|
|
212
|
+
limit?: number | undefined;
|
|
213
|
+
cursor?: string | undefined;
|
|
214
|
+
};
|
|
215
|
+
|
|
200
216
|
export type AgentDocumentAuthorityContext = {
|
|
201
217
|
sessionId: string;
|
|
202
218
|
attemptId: string;
|
|
@@ -1023,6 +1039,256 @@ export async function runDocumentDefaultCollectionBackfill(
|
|
|
1023
1039
|
);
|
|
1024
1040
|
}
|
|
1025
1041
|
|
|
1042
|
+
export async function listDocumentDefaultCollectionBackfillRuns(
|
|
1043
|
+
db: Database,
|
|
1044
|
+
input: DocumentMigrationAuditInput,
|
|
1045
|
+
) {
|
|
1046
|
+
const limit = validateDocumentMigrationAuditLimit(input.limit);
|
|
1047
|
+
const cursor = input.cursor
|
|
1048
|
+
? decodeDocumentMigrationAuditCursor(input.cursor, ["backfill-runs", input.accountId], true)
|
|
1049
|
+
: null;
|
|
1050
|
+
return await withDocumentAccountRls(
|
|
1051
|
+
db,
|
|
1052
|
+
input.accountId,
|
|
1053
|
+
input.workspaceId,
|
|
1054
|
+
{ viewerSubjectId: input.actorSubjectId },
|
|
1055
|
+
async (scopedDb) => {
|
|
1056
|
+
const command = {
|
|
1057
|
+
accountId: input.accountId,
|
|
1058
|
+
workspaceId: input.workspaceId,
|
|
1059
|
+
actorSubjectId: input.actorSubjectId,
|
|
1060
|
+
accountAdminAuthorization: input.accountAdminAuthorization,
|
|
1061
|
+
limit: limit + 1,
|
|
1062
|
+
beforeStartedAt: cursor?.timestamp ?? null,
|
|
1063
|
+
beforeRunId: cursor?.id ?? null,
|
|
1064
|
+
};
|
|
1065
|
+
const rows = (await scopedDb.execute(sql`
|
|
1066
|
+
SELECT list_document_default_collection_backfill_runs(
|
|
1067
|
+
${JSON.stringify(command)}::jsonb
|
|
1068
|
+
) AS result
|
|
1069
|
+
`)) as unknown as Array<{ result: unknown }>;
|
|
1070
|
+
const parsed = rows.map((row) => DocumentDefaultCollectionBackfillRunAudit.parse(row.result));
|
|
1071
|
+
const hasMore = parsed.length > limit;
|
|
1072
|
+
const runs = parsed.slice(0, limit);
|
|
1073
|
+
const tail = hasMore ? runs.at(-1) : null;
|
|
1074
|
+
return ListDocumentDefaultCollectionBackfillRunsResponse.parse({
|
|
1075
|
+
runs,
|
|
1076
|
+
hasMore,
|
|
1077
|
+
nextCursor: tail
|
|
1078
|
+
? encodeDocumentMigrationAuditCursor(["backfill-runs", input.accountId], {
|
|
1079
|
+
timestamp: tail.startedAt,
|
|
1080
|
+
id: tail.runId,
|
|
1081
|
+
})
|
|
1082
|
+
: null,
|
|
1083
|
+
});
|
|
1084
|
+
},
|
|
1085
|
+
);
|
|
1086
|
+
}
|
|
1087
|
+
|
|
1088
|
+
export async function getDocumentDefaultCollectionBackfillAudit(
|
|
1089
|
+
db: Database,
|
|
1090
|
+
input: DocumentMigrationAuditInput & {
|
|
1091
|
+
runId: string;
|
|
1092
|
+
operationCursor?: string | undefined;
|
|
1093
|
+
receiptCursor?: string | undefined;
|
|
1094
|
+
},
|
|
1095
|
+
) {
|
|
1096
|
+
const limit = validateDocumentMigrationAuditLimit(input.limit);
|
|
1097
|
+
const operationCursor = input.operationCursor
|
|
1098
|
+
? decodeDocumentMigrationAuditCursor(
|
|
1099
|
+
input.operationCursor,
|
|
1100
|
+
["backfill-operations", input.accountId, input.runId],
|
|
1101
|
+
true,
|
|
1102
|
+
)
|
|
1103
|
+
: null;
|
|
1104
|
+
const receiptCursor = input.receiptCursor
|
|
1105
|
+
? decodeDocumentMigrationAuditCursor(
|
|
1106
|
+
input.receiptCursor,
|
|
1107
|
+
["backfill-receipts", input.accountId, input.runId],
|
|
1108
|
+
false,
|
|
1109
|
+
)
|
|
1110
|
+
: null;
|
|
1111
|
+
return await withDocumentAccountRls(
|
|
1112
|
+
db,
|
|
1113
|
+
input.accountId,
|
|
1114
|
+
input.workspaceId,
|
|
1115
|
+
{ viewerSubjectId: input.actorSubjectId },
|
|
1116
|
+
async (scopedDb) => {
|
|
1117
|
+
const command = {
|
|
1118
|
+
accountId: input.accountId,
|
|
1119
|
+
workspaceId: input.workspaceId,
|
|
1120
|
+
actorSubjectId: input.actorSubjectId,
|
|
1121
|
+
accountAdminAuthorization: input.accountAdminAuthorization,
|
|
1122
|
+
runId: input.runId,
|
|
1123
|
+
limit,
|
|
1124
|
+
operationBeforeCreatedAt: operationCursor?.timestamp ?? null,
|
|
1125
|
+
operationBeforeId: operationCursor?.id ?? null,
|
|
1126
|
+
receiptAfterWorkspaceId: receiptCursor?.id ?? null,
|
|
1127
|
+
};
|
|
1128
|
+
const rows = (await scopedDb.execute(sql`
|
|
1129
|
+
SELECT get_document_default_collection_backfill_audit(
|
|
1130
|
+
${JSON.stringify(command)}::jsonb
|
|
1131
|
+
) AS result
|
|
1132
|
+
`)) as unknown as Array<{ result: unknown }>;
|
|
1133
|
+
const raw = rows[0]?.result;
|
|
1134
|
+
if (!raw || typeof raw !== "object" || Array.isArray(raw)) {
|
|
1135
|
+
throw new Error("document Default collection backfill audit returned no result");
|
|
1136
|
+
}
|
|
1137
|
+
const value = raw as Record<string, unknown>;
|
|
1138
|
+
const run = DocumentDefaultCollectionBackfillRunAudit.parse(value.run);
|
|
1139
|
+
const operations = Array.isArray(value.operations)
|
|
1140
|
+
? value.operations.map((operation) =>
|
|
1141
|
+
DocumentDefaultCollectionBackfillOperationAudit.parse(operation),
|
|
1142
|
+
)
|
|
1143
|
+
: [];
|
|
1144
|
+
const receipts = Array.isArray(value.receipts)
|
|
1145
|
+
? value.receipts.map((receipt) =>
|
|
1146
|
+
DocumentDefaultCollectionBackfillReceiptAudit.parse(receipt),
|
|
1147
|
+
)
|
|
1148
|
+
: [];
|
|
1149
|
+
const operationsHasMore = operations.length > limit;
|
|
1150
|
+
const receiptsHasMore = receipts.length > limit;
|
|
1151
|
+
const operationPage = operations.slice(0, limit);
|
|
1152
|
+
const receiptPage = receipts.slice(0, limit);
|
|
1153
|
+
const operationTail = operationsHasMore ? operationPage.at(-1) : null;
|
|
1154
|
+
const receiptTail = receiptsHasMore ? receiptPage.at(-1) : null;
|
|
1155
|
+
return DocumentDefaultCollectionBackfillAudit.parse({
|
|
1156
|
+
run,
|
|
1157
|
+
operations: operationPage,
|
|
1158
|
+
receipts: receiptPage,
|
|
1159
|
+
operationsHasMore,
|
|
1160
|
+
operationsNextCursor: operationTail
|
|
1161
|
+
? encodeDocumentMigrationAuditCursor(
|
|
1162
|
+
["backfill-operations", input.accountId, input.runId],
|
|
1163
|
+
{ timestamp: operationTail.createdAt, id: operationTail.operationId },
|
|
1164
|
+
)
|
|
1165
|
+
: null,
|
|
1166
|
+
receiptsHasMore,
|
|
1167
|
+
receiptsNextCursor: receiptTail
|
|
1168
|
+
? encodeDocumentMigrationAuditCursor(
|
|
1169
|
+
["backfill-receipts", input.accountId, input.runId],
|
|
1170
|
+
{ timestamp: null, id: receiptTail.workspaceId },
|
|
1171
|
+
)
|
|
1172
|
+
: null,
|
|
1173
|
+
});
|
|
1174
|
+
},
|
|
1175
|
+
);
|
|
1176
|
+
}
|
|
1177
|
+
|
|
1178
|
+
export async function listOrganizationDocumentAuthorityReclassifications(
|
|
1179
|
+
db: Database,
|
|
1180
|
+
input: DocumentMigrationAuditInput,
|
|
1181
|
+
) {
|
|
1182
|
+
const limit = validateDocumentMigrationAuditLimit(input.limit);
|
|
1183
|
+
const cursor = input.cursor
|
|
1184
|
+
? decodeDocumentMigrationAuditCursor(
|
|
1185
|
+
input.cursor,
|
|
1186
|
+
["organization-reclassifications", input.accountId],
|
|
1187
|
+
true,
|
|
1188
|
+
)
|
|
1189
|
+
: null;
|
|
1190
|
+
return await withDocumentAccountRls(
|
|
1191
|
+
db,
|
|
1192
|
+
input.accountId,
|
|
1193
|
+
input.workspaceId,
|
|
1194
|
+
{ viewerSubjectId: input.actorSubjectId },
|
|
1195
|
+
async (scopedDb) => {
|
|
1196
|
+
const command = {
|
|
1197
|
+
accountId: input.accountId,
|
|
1198
|
+
workspaceId: input.workspaceId,
|
|
1199
|
+
actorSubjectId: input.actorSubjectId,
|
|
1200
|
+
accountAdminAuthorization: input.accountAdminAuthorization,
|
|
1201
|
+
limit: limit + 1,
|
|
1202
|
+
beforeCreatedAt: cursor?.timestamp ?? null,
|
|
1203
|
+
beforeOperationId: cursor?.id ?? null,
|
|
1204
|
+
};
|
|
1205
|
+
const rows = (await scopedDb.execute(sql`
|
|
1206
|
+
SELECT list_organization_document_authority_reclassifications(
|
|
1207
|
+
${JSON.stringify(command)}::jsonb
|
|
1208
|
+
) AS result
|
|
1209
|
+
`)) as unknown as Array<{ result: unknown }>;
|
|
1210
|
+
const parsed = rows.map((row) =>
|
|
1211
|
+
OrganizationDocumentAuthorityReclassification.parse(row.result),
|
|
1212
|
+
);
|
|
1213
|
+
const hasMore = parsed.length > limit;
|
|
1214
|
+
const receipts = parsed.slice(0, limit);
|
|
1215
|
+
const tail = hasMore ? receipts.at(-1) : null;
|
|
1216
|
+
return ListOrganizationDocumentAuthorityReclassificationsResponse.parse({
|
|
1217
|
+
receipts,
|
|
1218
|
+
hasMore,
|
|
1219
|
+
nextCursor: tail
|
|
1220
|
+
? encodeDocumentMigrationAuditCursor(
|
|
1221
|
+
["organization-reclassifications", input.accountId],
|
|
1222
|
+
{ timestamp: tail.createdAt, id: tail.operationId },
|
|
1223
|
+
)
|
|
1224
|
+
: null,
|
|
1225
|
+
});
|
|
1226
|
+
},
|
|
1227
|
+
);
|
|
1228
|
+
}
|
|
1229
|
+
|
|
1230
|
+
function validateDocumentMigrationAuditLimit(value: number | undefined): number {
|
|
1231
|
+
const limit = value ?? 50;
|
|
1232
|
+
if (!Number.isInteger(limit) || limit < 1 || limit > 100) {
|
|
1233
|
+
throw new Error("document migration audit limit must be between 1 and 100");
|
|
1234
|
+
}
|
|
1235
|
+
return limit;
|
|
1236
|
+
}
|
|
1237
|
+
|
|
1238
|
+
type DocumentMigrationAuditCursor = { timestamp: string | null; id: string };
|
|
1239
|
+
|
|
1240
|
+
function documentMigrationAuditCursorScope(parts: string[]): string {
|
|
1241
|
+
return createHash("sha256")
|
|
1242
|
+
.update(JSON.stringify(["document-migration-audit", 1, ...parts]), "utf8")
|
|
1243
|
+
.digest("hex")
|
|
1244
|
+
.slice(0, 32);
|
|
1245
|
+
}
|
|
1246
|
+
|
|
1247
|
+
function encodeDocumentMigrationAuditCursor(
|
|
1248
|
+
parts: string[],
|
|
1249
|
+
cursor: DocumentMigrationAuditCursor,
|
|
1250
|
+
): string {
|
|
1251
|
+
return Buffer.from(
|
|
1252
|
+
JSON.stringify({
|
|
1253
|
+
v: 1,
|
|
1254
|
+
s: documentMigrationAuditCursorScope(parts),
|
|
1255
|
+
t: cursor.timestamp,
|
|
1256
|
+
i: cursor.id,
|
|
1257
|
+
}),
|
|
1258
|
+
"utf8",
|
|
1259
|
+
).toString("base64url");
|
|
1260
|
+
}
|
|
1261
|
+
|
|
1262
|
+
function decodeDocumentMigrationAuditCursor(
|
|
1263
|
+
value: string,
|
|
1264
|
+
parts: string[],
|
|
1265
|
+
requireTimestamp: boolean,
|
|
1266
|
+
): DocumentMigrationAuditCursor {
|
|
1267
|
+
try {
|
|
1268
|
+
if (!value || value.length > 1_024) throw new Error("cursor length");
|
|
1269
|
+
const bytes = Buffer.from(value, "base64url");
|
|
1270
|
+
if (bytes.toString("base64url") !== value) throw new Error("cursor encoding");
|
|
1271
|
+
const parsed = JSON.parse(bytes.toString("utf8")) as Record<string, unknown>;
|
|
1272
|
+
if (
|
|
1273
|
+
Object.keys(parsed).sort().join(",") !== "i,s,t,v" ||
|
|
1274
|
+
parsed.v !== 1 ||
|
|
1275
|
+
parsed.s !== documentMigrationAuditCursorScope(parts) ||
|
|
1276
|
+
typeof parsed.i !== "string" ||
|
|
1277
|
+
!/^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/iu.test(
|
|
1278
|
+
parsed.i,
|
|
1279
|
+
) ||
|
|
1280
|
+
(requireTimestamp
|
|
1281
|
+
? typeof parsed.t !== "string" || !Number.isFinite(new Date(parsed.t).getTime())
|
|
1282
|
+
: parsed.t !== null)
|
|
1283
|
+
) {
|
|
1284
|
+
throw new Error("cursor payload");
|
|
1285
|
+
}
|
|
1286
|
+
return { timestamp: typeof parsed.t === "string" ? parsed.t : null, id: parsed.i };
|
|
1287
|
+
} catch (error) {
|
|
1288
|
+
throw new Error("invalid document migration audit cursor", { cause: error });
|
|
1289
|
+
}
|
|
1290
|
+
}
|
|
1291
|
+
|
|
1026
1292
|
export async function reclassifyDocumentAuthority(
|
|
1027
1293
|
db: Database,
|
|
1028
1294
|
input: ReclassifyDocumentAuthorityInput,
|