agl 1.0.17 → 21.0.2
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/.smartconfig.json +55 -0
- package/changelog.md +1026 -0
- package/cli.js +14 -0
- package/dist_serve/bundle.js +44778 -0
- package/dist_serve/index.html +13 -0
- package/dist_ts/00_commitinfo_data.d.ts +8 -0
- package/dist_ts/00_commitinfo_data.js +9 -0
- package/dist_ts/classes.authmodels.d.ts +126 -0
- package/dist_ts/classes.authmodels.js +1422 -0
- package/dist_ts/classes.authstore.d.ts +160 -0
- package/dist_ts/classes.authstore.js +2483 -0
- package/dist_ts/classes.browserresourcehost.d.ts +85 -0
- package/dist_ts/classes.browserresourcehost.js +912 -0
- package/dist_ts/classes.cli.d.ts +21 -0
- package/dist_ts/classes.cli.js +1082 -0
- package/dist_ts/classes.config.d.ts +23 -0
- package/dist_ts/classes.config.js +267 -0
- package/dist_ts/classes.controller.d.ts +523 -0
- package/dist_ts/classes.controller.js +10611 -0
- package/dist_ts/classes.controllermanagement.d.ts +32 -0
- package/dist_ts/classes.controllermanagement.js +222 -0
- package/dist_ts/classes.draftmanager.d.ts +30 -0
- package/dist_ts/classes.draftmanager.js +179 -0
- package/dist_ts/classes.embeddeddb.d.ts +30 -0
- package/dist_ts/classes.embeddeddb.js +159 -0
- package/dist_ts/classes.flexframedtransport.d.ts +56 -0
- package/dist_ts/classes.flexframedtransport.js +275 -0
- package/dist_ts/classes.flexmodels.private.d.ts +231 -0
- package/dist_ts/classes.flexmodels.private.js +985 -0
- package/dist_ts/classes.flexmodels.public.d.ts +207 -0
- package/dist_ts/classes.flexmodels.public.js +885 -0
- package/dist_ts/classes.flexprojectionreader.d.ts +89 -0
- package/dist_ts/classes.flexprojectionreader.js +580 -0
- package/dist_ts/classes.flexservice.d.ts +196 -0
- package/dist_ts/classes.flexservice.js +3704 -0
- package/dist_ts/classes.flexstore.d.ts +174 -0
- package/dist_ts/classes.flexstore.js +3400 -0
- package/dist_ts/classes.flexsupervisor.d.ts +105 -0
- package/dist_ts/classes.flexsupervisor.js +1191 -0
- package/dist_ts/classes.gitreversion.d.ts +431 -0
- package/dist_ts/classes.gitreversion.js +10592 -0
- package/dist_ts/classes.harnessoperationmanager.d.ts +113 -0
- package/dist_ts/classes.harnessoperationmanager.js +602 -0
- package/dist_ts/classes.opencodeclient.d.ts +146 -0
- package/dist_ts/classes.opencodeclient.js +3003 -0
- package/dist_ts/classes.opencodesupervisor.d.ts +60 -0
- package/dist_ts/classes.opencodesupervisor.js +1003 -0
- package/dist_ts/classes.passkeymanager.d.ts +34 -0
- package/dist_ts/classes.passkeymanager.js +456 -0
- package/dist_ts/classes.processinspection.d.ts +50 -0
- package/dist_ts/classes.processinspection.js +484 -0
- package/dist_ts/classes.resourcecoordinator.d.ts +64 -0
- package/dist_ts/classes.resourcecoordinator.js +294 -0
- package/dist_ts/classes.sessionintelligencereader.d.ts +13 -0
- package/dist_ts/classes.sessionintelligencereader.js +40 -0
- package/dist_ts/classes.systemmetricssampler.d.ts +53 -0
- package/dist_ts/classes.systemmetricssampler.js +168 -0
- package/dist_ts/classes.terminalmanager.d.ts +95 -0
- package/dist_ts/classes.terminalmanager.js +981 -0
- package/dist_ts/classes.terminalresourcehost.d.ts +20 -0
- package/dist_ts/classes.terminalresourcehost.js +84 -0
- package/dist_ts/classes.upgradecoordinator.d.ts +244 -0
- package/dist_ts/classes.upgradecoordinator.js +2155 -0
- package/dist_ts/classes.upgradetransaction.d.ts +92 -0
- package/dist_ts/classes.upgradetransaction.js +2125 -0
- package/dist_ts/classes.uploadmanager.d.ts +24 -0
- package/dist_ts/classes.uploadmanager.js +210 -0
- package/dist_ts/classes.validation.d.ts +91 -0
- package/dist_ts/classes.validation.js +1087 -0
- package/dist_ts/flexharness.child.d.ts +1 -0
- package/dist_ts/flexharness.child.js +28 -0
- package/dist_ts/functions.canonicaldirectory.d.ts +21 -0
- package/dist_ts/functions.canonicaldirectory.js +144 -0
- package/dist_ts/functions.controllerdataroot.d.ts +15 -0
- package/dist_ts/functions.controllerdataroot.js +76 -0
- package/dist_ts/functions.embeddeddb.d.ts +2 -0
- package/dist_ts/functions.embeddeddb.js +21 -0
- package/dist_ts/functions.flexcredentialstore.d.ts +16 -0
- package/dist_ts/functions.flexcredentialstore.js +93 -0
- package/dist_ts/functions.opencodeauth.d.ts +3 -0
- package/dist_ts/functions.opencodeauth.js +31 -0
- package/dist_ts/functions.runtimeenvironment.d.ts +2 -0
- package/dist_ts/functions.runtimeenvironment.js +79 -0
- package/dist_ts/functions.upgradefollower.d.ts +3 -0
- package/dist_ts/functions.upgradefollower.js +95 -0
- package/dist_ts/index.d.ts +24 -0
- package/dist_ts/index.js +25 -0
- package/dist_ts/interfaces.auth.d.ts +181 -0
- package/dist_ts/interfaces.auth.js +82 -0
- package/dist_ts/interfaces.config.d.ts +34 -0
- package/dist_ts/interfaces.config.js +2 -0
- package/dist_ts/interfaces.flexipc.d.ts +939 -0
- package/dist_ts/interfaces.flexipc.js +1492 -0
- package/dist_ts/interfaces.gitreversion.d.ts +246 -0
- package/dist_ts/interfaces.gitreversion.js +2 -0
- package/dist_ts/interfaces.lifecycle.d.ts +37 -0
- package/dist_ts/interfaces.lifecycle.js +2 -0
- package/dist_ts/interfaces.opencode.d.ts +101 -0
- package/dist_ts/interfaces.opencode.js +3 -0
- package/dist_ts/interfaces.projects.d.ts +156 -0
- package/dist_ts/interfaces.projects.js +5 -0
- package/dist_ts/plugins.d.ts +36 -0
- package/dist_ts/plugins.js +40 -0
- package/dist_ts_interfaces/index.d.ts +2 -0
- package/dist_ts_interfaces/index.js +3 -0
- package/dist_ts_interfaces/interfaces.d.ts +747 -0
- package/dist_ts_interfaces/interfaces.js +47 -0
- package/dist_ts_interfaces/plugins.d.ts +4 -0
- package/dist_ts_interfaces/plugins.js +3 -0
- package/dist_ts_interfaces/requests.d.ts +806 -0
- package/dist_ts_interfaces/requests.js +2 -0
- package/dist_ts_migration/classes.documentmigrationrunner.d.ts +8 -0
- package/dist_ts_migration/classes.documentmigrationrunner.js +24 -0
- package/dist_ts_migration/classes.flexmigrationrunner.d.ts +11 -0
- package/dist_ts_migration/classes.flexmigrationrunner.js +25 -0
- package/dist_ts_migration/classes.flexpostharnessmigrationrunner.d.ts +10 -0
- package/dist_ts_migration/classes.flexpostharnessmigrationrunner.js +15 -0
- package/dist_ts_migration/classes.migrationrunner.d.ts +8 -0
- package/dist_ts_migration/classes.migrationrunner.js +34 -0
- package/dist_ts_migration/index.d.ts +12 -0
- package/dist_ts_migration/index.js +13 -0
- package/dist_ts_migration/v10_flexharnessv3migration.d.ts +11 -0
- package/dist_ts_migration/v10_flexharnessv3migration.js +23 -0
- package/dist_ts_migration/v13_flexprojectionorder.d.ts +11 -0
- package/dist_ts_migration/v13_flexprojectionorder.js +23 -0
- package/dist_ts_migration/v16_flexprovidercredentials.d.ts +22 -0
- package/dist_ts_migration/v16_flexprovidercredentials.js +149 -0
- package/dist_ts_migration/v18_resourcelayout.d.ts +22 -0
- package/dist_ts_migration/v18_resourcelayout.js +23 -0
- package/dist_ts_migration/v18_resourcelayoutmigration.d.ts +6 -0
- package/dist_ts_migration/v18_resourcelayoutmigration.js +61 -0
- package/dist_ts_migration/v19_flexprojectmanagement.d.ts +11 -0
- package/dist_ts_migration/v19_flexprojectmanagement.js +21 -0
- package/dist_ts_migration/v1_embeddeddatabaselocation.d.ts +28 -0
- package/dist_ts_migration/v1_embeddeddatabaselocation.js +415 -0
- package/dist_ts_migration/v22_projectfilesystemidentitymigration.d.ts +7 -0
- package/dist_ts_migration/v22_projectfilesystemidentitymigration.js +105 -0
- package/dist_ts_migration/v2_controllerdataroot.d.ts +130 -0
- package/dist_ts_migration/v2_controllerdataroot.js +1887 -0
- package/dist_ts_migration/v6_protocoldocumentmigration.d.ts +7 -0
- package/dist_ts_migration/v6_protocoldocumentmigration.js +100 -0
- package/dist_ts_migration/v6_protocoldocuments.d.ts +7 -0
- package/dist_ts_migration/v6_protocoldocuments.js +138 -0
- package/html/index.html +13 -0
- package/{LICENSE → license.md} +2 -2
- package/package.json +86 -48
- package/readme.md +480 -0
- package/readme.plan.md +188 -0
- package/ts/00_commitinfo_data.ts +8 -0
- package/ts/classes.authmodels.ts +1245 -0
- package/ts/classes.authstore.ts +3274 -0
- package/ts/classes.browserresourcehost.ts +1205 -0
- package/ts/classes.cli.ts +1254 -0
- package/ts/classes.config.ts +351 -0
- package/ts/classes.controller.ts +14426 -0
- package/ts/classes.controllermanagement.ts +330 -0
- package/ts/classes.draftmanager.ts +232 -0
- package/ts/classes.embeddeddb.ts +166 -0
- package/ts/classes.flexframedtransport.ts +283 -0
- package/ts/classes.flexmodels.private.ts +823 -0
- package/ts/classes.flexmodels.public.ts +732 -0
- package/ts/classes.flexprojectionreader.ts +816 -0
- package/ts/classes.flexservice.ts +4302 -0
- package/ts/classes.flexstore.ts +4565 -0
- package/ts/classes.flexsupervisor.ts +1453 -0
- package/ts/classes.gitreversion.ts +13353 -0
- package/ts/classes.harnessoperationmanager.ts +870 -0
- package/ts/classes.opencodeclient.ts +4110 -0
- package/ts/classes.opencodesupervisor.ts +1280 -0
- package/ts/classes.passkeymanager.ts +570 -0
- package/ts/classes.processinspection.ts +623 -0
- package/ts/classes.resourcecoordinator.ts +436 -0
- package/ts/classes.sessionintelligencereader.ts +52 -0
- package/ts/classes.systemmetricssampler.ts +215 -0
- package/ts/classes.terminalmanager.ts +1207 -0
- package/ts/classes.terminalresourcehost.ts +122 -0
- package/ts/classes.upgradecoordinator.ts +2675 -0
- package/ts/classes.upgradetransaction.ts +2900 -0
- package/ts/classes.uploadmanager.ts +240 -0
- package/ts/classes.validation.ts +1409 -0
- package/ts/flexharness.child.ts +35 -0
- package/ts/functions.canonicaldirectory.ts +213 -0
- package/ts/functions.controllerdataroot.ts +107 -0
- package/ts/functions.embeddeddb.ts +22 -0
- package/ts/functions.flexcredentialstore.ts +128 -0
- package/ts/functions.opencodeauth.ts +34 -0
- package/ts/functions.runtimeenvironment.ts +90 -0
- package/ts/functions.upgradefollower.ts +115 -0
- package/ts/index.ts +36 -6
- package/ts/interfaces.auth.ts +316 -0
- package/ts/interfaces.config.ts +37 -0
- package/ts/interfaces.flexipc.ts +2586 -0
- package/ts/interfaces.gitreversion.ts +336 -0
- package/ts/interfaces.lifecycle.ts +46 -0
- package/ts/interfaces.opencode.ts +153 -0
- package/ts/interfaces.projects.ts +182 -0
- package/ts/plugins.ts +64 -0
- package/ts_interfaces/index.ts +2 -0
- package/ts_interfaces/interfaces.ts +827 -0
- package/ts_interfaces/plugins.ts +15 -0
- package/ts_interfaces/requests.ts +1186 -0
- package/ts_migration/classes.documentmigrationrunner.ts +32 -0
- package/ts_migration/classes.flexmigrationrunner.ts +33 -0
- package/ts_migration/classes.flexpostharnessmigrationrunner.ts +22 -0
- package/ts_migration/classes.migrationrunner.ts +40 -0
- package/ts_migration/index.ts +12 -0
- package/ts_migration/v10_flexharnessv3migration.ts +35 -0
- package/ts_migration/v13_flexprojectionorder.ts +33 -0
- package/ts_migration/v16_flexprovidercredentials.ts +196 -0
- package/ts_migration/v18_resourcelayout.ts +55 -0
- package/ts_migration/v18_resourcelayoutmigration.ts +68 -0
- package/ts_migration/v19_flexprojectmanagement.ts +28 -0
- package/ts_migration/v1_embeddeddatabaselocation.ts +560 -0
- package/ts_migration/v22_projectfilesystemidentitymigration.ts +121 -0
- package/ts_migration/v2_controllerdataroot.ts +2349 -0
- package/ts_migration/v6_protocoldocumentmigration.ts +144 -0
- package/ts_migration/v6_protocoldocuments.ts +198 -0
- package/ts_web/00_commitinfo_data.ts +8 -0
- package/ts_web/classes.controllersocketclient.ts +517 -0
- package/ts_web/classes.sessiondraftsync.ts +390 -0
- package/ts_web/elements.harnesscontrollerapp.ts +11494 -0
- package/ts_web/index.ts +2 -0
- package/ts_web/plugins.ts +31 -0
- package/.gitlab-ci.yml +0 -71
- package/.npmignore +0 -5
- package/README.md +0 -40
- package/dist/cli.js +0 -2
- package/dist/index.d.ts +0 -0
- package/dist/index.js +0 -9
- package/dist/mod_bundle/index.d.ts +0 -1
- package/dist/mod_bundle/index.js +0 -18
- package/dist/mod_bundle/mod.plugins.d.ts +0 -4
- package/dist/mod_bundle/mod.plugins.js +0 -11
- package/dist/mod_install/index.d.ts +0 -4
- package/dist/mod_install/index.js +0 -21
- package/dist/mod_install/mod.plugins.d.ts +0 -1
- package/dist/mod_install/mod.plugins.js +0 -7
- package/dist/mod_standard/index.d.ts +0 -4
- package/dist/mod_standard/index.js +0 -21
- package/dist/mod_standard/mod.browser.d.ts +0 -6
- package/dist/mod_standard/mod.browser.js +0 -14
- package/dist/mod_standard/mod.clean.d.ts +0 -4
- package/dist/mod_standard/mod.clean.js +0 -12
- package/dist/mod_standard/mod.compile.d.ts +0 -4
- package/dist/mod_standard/mod.compile.js +0 -21
- package/dist/mod_standard/mod.plugins.d.ts +0 -8
- package/dist/mod_standard/mod.plugins.js +0 -19
- package/dist/mod_standard/mod.test.d.ts +0 -4
- package/dist/mod_standard/mod.test.js +0 -12
- package/dist/plr.cli.d.ts +0 -3
- package/dist/plr.cli.js +0 -57
- package/dist/plr.config.d.ts +0 -11
- package/dist/plr.config.js +0 -26
- package/dist/plr.mods.d.ts +0 -17
- package/dist/plr.mods.js +0 -17
- package/dist/plr.paths.d.ts +0 -19
- package/dist/plr.paths.js +0 -26
- package/dist/plr.plugins.d.ts +0 -8
- package/dist/plr.plugins.js +0 -16
- package/npmextra.json +0 -10
- package/ts/mod_bundle/index.ts +0 -20
- package/ts/mod_bundle/mod.plugins.ts +0 -9
- package/ts/mod_install/index.ts +0 -20
- package/ts/mod_install/mod.plugins.ts +0 -1
- package/ts/mod_standard/index.ts +0 -23
- package/ts/mod_standard/mod.browser.ts +0 -17
- package/ts/mod_standard/mod.clean.ts +0 -13
- package/ts/mod_standard/mod.compile.ts +0 -23
- package/ts/mod_standard/mod.plugins.ts +0 -17
- package/ts/mod_standard/mod.test.ts +0 -13
- package/ts/plr.cli.ts +0 -60
- package/ts/plr.config.ts +0 -36
- package/ts/plr.mods.ts +0 -25
- package/ts/plr.paths.ts +0 -29
- package/ts/plr.plugins.ts +0 -17
- package/tslint.json +0 -3
- package/yarn.lock +0 -3464
|
@@ -0,0 +1,3400 @@
|
|
|
1
|
+
import * as plugins from './plugins.js';
|
|
2
|
+
import { FlexDomainHeadModel, FlexHeadModel, FlexMigrationModel, FlexPrivateCandidateModel, FlexPrivateChunkModel, FlexWriterLeaseModel, assertFlexDomainHeadDocument, assertFlexHeadDocument, assertFlexMigrationDocument, assertFlexPrivateCandidateDocument, assertFlexPrivateChunkDocument, assertFlexWriterLeaseDocument, flexDomainHeadId, flexMigrationId, flexPrivateChunkBytes, flexWriterLeaseId, initFlexPrivateModels, registerFlexPrivateModels, } from './classes.flexmodels.private.js';
|
|
3
|
+
import { FlexPublicCandidateModel, FlexPublicHeadModel, FlexPublicMessageRecordModel, FlexPublicSessionRecordModel, FlexProjectionMessageRecordModel, FlexProjectionSourceModel, assertFlexPublicCandidateDocument, assertFlexPublicHeadDocument, assertFlexPublicMessageRecordDocument, assertFlexPublicSessionRecordDocument, assertFlexProjectionMessageRecordDocument, assertFlexProjectionSourceDocument, flexHeadId, flexPublicHeadId, flexPublicMessageBytesLimit, flexPublicMessageLimit, flexPublicSessionLimit, flexPublicSingleMessageBytesLimit, initFlexPublicModels, registerFlexPublicModels, } from './classes.flexmodels.public.js';
|
|
4
|
+
export const flexOrphanGraceMs = 60 * 60 * 1000;
|
|
5
|
+
const flexMaintenancePageLimit = 128;
|
|
6
|
+
const flexOrphanMaintenanceIntervalMs = 15 * 60 * 1000;
|
|
7
|
+
const flexLeaseDurationMs = 30_000;
|
|
8
|
+
const flexLeaseHeartbeatMs = 10_000;
|
|
9
|
+
const flexLeaseHeartbeatOperationTimeoutMs = 5_000;
|
|
10
|
+
const flexLeaseTransitionTimeoutMs = 20_000;
|
|
11
|
+
const flexMaintenanceOperationTimeoutMs = 10_000;
|
|
12
|
+
const sha256 = (valueArg) => plugins.crypto.createHash('sha256').update(valueArg).digest('hex');
|
|
13
|
+
const serializedBytes = (valueArg) => Buffer.from(JSON.stringify(valueArg), 'utf8');
|
|
14
|
+
const canonicalJson = (valueArg) => JSON.stringify(valueArg, (_key, value) => {
|
|
15
|
+
if (!value || typeof value !== 'object' || Array.isArray(value))
|
|
16
|
+
return value;
|
|
17
|
+
return Object.fromEntries(Object.keys(value).sort().map((key) => [key, value[key]]));
|
|
18
|
+
});
|
|
19
|
+
const randomCandidateId = () => plugins.crypto.randomBytes(16).toString('base64url');
|
|
20
|
+
const randomOwnerToken = () => plugins.crypto.randomBytes(32).toString('base64url');
|
|
21
|
+
const privateCandidateDocumentId = (candidateIdArg) => `flex-private-candidate:${candidateIdArg}`;
|
|
22
|
+
const privateChunkDocumentId = (candidateIdArg, indexArg) => `flex-private-chunk:${candidateIdArg}:${indexArg}`;
|
|
23
|
+
const publicCandidateDocumentId = (candidateIdArg) => `flex-public-candidate:${candidateIdArg}`;
|
|
24
|
+
const publicSessionDocumentId = (candidateIdArg, sessionIdArg) => `flex-public-session:${candidateIdArg}:${sha256(sessionIdArg).slice(0, 32)}`;
|
|
25
|
+
const publicMessageDocumentId = (candidateIdArg, sessionIdArg, messageIdArg) => `flex-public-message:${candidateIdArg}:${sha256(`${sessionIdArg}\0${messageIdArg}`).slice(0, 32)}`;
|
|
26
|
+
const projectionSourceDocumentId = (candidateIdArg) => `flex-projection-source:${candidateIdArg}`;
|
|
27
|
+
const projectionMessageDocumentId = (candidateIdArg, indexArg) => `flex-projection-message:${candidateIdArg}:${String(indexArg).padStart(16, '0')}`;
|
|
28
|
+
const providerKey = (storageKeyArg, sessionIdArg) => JSON.stringify([storageKeyArg, sessionIdArg]);
|
|
29
|
+
const compareNewestSession = (leftArg, rightArg) => rightArg.updatedAt.localeCompare(leftArg.updatedAt)
|
|
30
|
+
|| rightArg.createdAt.localeCompare(leftArg.createdAt)
|
|
31
|
+
|| leftArg.sessionId.localeCompare(rightArg.sessionId);
|
|
32
|
+
const compareNewestOrderedMessage = (leftArg, rightArg) => {
|
|
33
|
+
if (leftArg.message.sessionId === rightArg.message.sessionId) {
|
|
34
|
+
return rightArg.messageIndex - leftArg.messageIndex;
|
|
35
|
+
}
|
|
36
|
+
return rightArg.message.createdAt.localeCompare(leftArg.message.createdAt)
|
|
37
|
+
|| leftArg.message.sessionId.localeCompare(rightArg.message.sessionId)
|
|
38
|
+
|| leftArg.message.messageId.localeCompare(rightArg.message.messageId)
|
|
39
|
+
|| rightArg.messageIndex - leftArg.messageIndex;
|
|
40
|
+
};
|
|
41
|
+
const compareNewestProjectionDescriptor = (leftArg, rightArg) => leftArg.sessionId === rightArg.sessionId
|
|
42
|
+
? (rightArg.messageIndex ?? rightArg.index) - (leftArg.messageIndex ?? leftArg.index)
|
|
43
|
+
: rightArg.messageCreatedAt.localeCompare(leftArg.messageCreatedAt)
|
|
44
|
+
|| leftArg.sessionId.localeCompare(rightArg.sessionId)
|
|
45
|
+
|| leftArg.messageId.localeCompare(rightArg.messageId)
|
|
46
|
+
|| (rightArg.messageIndex ?? rightArg.index) - (leftArg.messageIndex ?? leftArg.index);
|
|
47
|
+
const retainNewest = (valuesArg, limitArg, compareArg) => {
|
|
48
|
+
const retained = [];
|
|
49
|
+
for (const value of valuesArg) {
|
|
50
|
+
let low = 0;
|
|
51
|
+
let high = retained.length;
|
|
52
|
+
while (low < high) {
|
|
53
|
+
const middle = (low + high) >>> 1;
|
|
54
|
+
if (compareArg(value, retained[middle]) < 0)
|
|
55
|
+
high = middle;
|
|
56
|
+
else
|
|
57
|
+
low = middle + 1;
|
|
58
|
+
}
|
|
59
|
+
if (low >= limitArg)
|
|
60
|
+
continue;
|
|
61
|
+
retained.splice(low, 0, value);
|
|
62
|
+
if (retained.length > limitArg)
|
|
63
|
+
retained.pop();
|
|
64
|
+
}
|
|
65
|
+
return retained;
|
|
66
|
+
};
|
|
67
|
+
const retainPublicSessions = (sessionsArg) => {
|
|
68
|
+
const roots = retainNewest(sessionsArg.filter((session) => session.parentSessionId === undefined), flexPublicSessionLimit, compareNewestSession);
|
|
69
|
+
const children = retainNewest(sessionsArg.filter((session) => session.parentSessionId !== undefined), flexPublicSessionLimit - roots.length, compareNewestSession);
|
|
70
|
+
return [...roots, ...children].sort(compareNewestSession);
|
|
71
|
+
};
|
|
72
|
+
const flexTaskPlaceholderBytesLimit = 384 * 1024;
|
|
73
|
+
const taskOutputOmittedNotice = '[Task output omitted because its public projection exceeded 480 KiB.]';
|
|
74
|
+
const placeholderMessage = (messageArg) => {
|
|
75
|
+
const linkedTaskParts = messageArg.parts.flatMap((part) => (part.type === 'tool' && part.childSessionId !== undefined
|
|
76
|
+
? [{
|
|
77
|
+
partId: part.partId,
|
|
78
|
+
type: 'tool',
|
|
79
|
+
toolCallId: part.toolCallId,
|
|
80
|
+
toolName: part.toolName,
|
|
81
|
+
status: part.status,
|
|
82
|
+
input: {},
|
|
83
|
+
output: taskOutputOmittedNotice,
|
|
84
|
+
childSessionId: part.childSessionId,
|
|
85
|
+
...(part.model === undefined ? {} : { model: part.model }),
|
|
86
|
+
}]
|
|
87
|
+
: []));
|
|
88
|
+
if (linkedTaskParts.length === 0) {
|
|
89
|
+
return {
|
|
90
|
+
...messageArg,
|
|
91
|
+
parts: [{
|
|
92
|
+
partId: messageArg.parts[0]?.partId ?? messageArg.messageId,
|
|
93
|
+
type: 'text',
|
|
94
|
+
text: '[Message content omitted because its public projection exceeded 480 KiB.]',
|
|
95
|
+
}],
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
const retainedTaskParts = [];
|
|
99
|
+
for (const part of linkedTaskParts) {
|
|
100
|
+
const candidate = { ...messageArg, parts: [...retainedTaskParts, part] };
|
|
101
|
+
if (serializedBytes(candidate).byteLength > flexTaskPlaceholderBytesLimit)
|
|
102
|
+
break;
|
|
103
|
+
retainedTaskParts.push(part);
|
|
104
|
+
}
|
|
105
|
+
if (retainedTaskParts.length < linkedTaskParts.length) {
|
|
106
|
+
retainedTaskParts.at(-1).output = `${taskOutputOmittedNotice} ${linkedTaskParts.length - retainedTaskParts.length} additional task link(s) omitted.`;
|
|
107
|
+
}
|
|
108
|
+
return { ...messageArg, parts: retainedTaskParts };
|
|
109
|
+
};
|
|
110
|
+
const recordManifest = (documentArg) => {
|
|
111
|
+
const bytes = serializedBytes(documentArg);
|
|
112
|
+
return { id: documentArg.id, sha256: sha256(bytes), bytes: bytes.byteLength };
|
|
113
|
+
};
|
|
114
|
+
const publicCandidateManifestBytes = (manifestArg) => serializedBytes(manifestArg);
|
|
115
|
+
const projectionSourceManifestBytes = (manifestArg) => Buffer.from(canonicalJson(manifestArg), 'utf8');
|
|
116
|
+
const projectionMessagePayload = (messageArg, previousArg) => ({
|
|
117
|
+
message: messageArg,
|
|
118
|
+
...(previousArg === undefined ? {} : { previous: previousArg }),
|
|
119
|
+
});
|
|
120
|
+
const projectionMessagePayloadBytes = (messageArg, previousArg) => Buffer.from(canonicalJson(projectionMessagePayload(messageArg, previousArg)), 'utf8');
|
|
121
|
+
const projectionMessageBodyBytes = (messageArg) => Buffer.byteLength(canonicalJson(messageArg), 'utf8');
|
|
122
|
+
const cloneJson = (valueArg, pathArg = '$') => {
|
|
123
|
+
const seen = new WeakSet();
|
|
124
|
+
const visit = (value, path) => {
|
|
125
|
+
if (value === null || typeof value === 'string' || typeof value === 'boolean')
|
|
126
|
+
return value;
|
|
127
|
+
if (typeof value === 'number') {
|
|
128
|
+
if (!Number.isFinite(value)) {
|
|
129
|
+
throw new plugins.flexharness.FlexHarnessStoreFormatError(`${path} contains a non-finite number.`);
|
|
130
|
+
}
|
|
131
|
+
return value;
|
|
132
|
+
}
|
|
133
|
+
if (typeof value === 'undefined')
|
|
134
|
+
return undefined;
|
|
135
|
+
if (typeof value !== 'object') {
|
|
136
|
+
throw new plugins.flexharness.FlexHarnessStoreFormatError(`${path} contains ${typeof value}, which is not JSON-safe.`);
|
|
137
|
+
}
|
|
138
|
+
if (seen.has(value)) {
|
|
139
|
+
throw new plugins.flexharness.FlexHarnessStoreFormatError(`${path} contains a cycle.`);
|
|
140
|
+
}
|
|
141
|
+
const prototype = Object.getPrototypeOf(value);
|
|
142
|
+
if (!Array.isArray(value) && prototype !== Object.prototype && prototype !== null) {
|
|
143
|
+
throw new plugins.flexharness.FlexHarnessStoreFormatError(`${path} is not a plain object.`);
|
|
144
|
+
}
|
|
145
|
+
if (Object.getOwnPropertySymbols(value).length > 0) {
|
|
146
|
+
throw new plugins.flexharness.FlexHarnessStoreFormatError(`${path} contains a symbol-keyed property.`);
|
|
147
|
+
}
|
|
148
|
+
seen.add(value);
|
|
149
|
+
if (Array.isArray(value)) {
|
|
150
|
+
const result = value.map((entry, index) => {
|
|
151
|
+
if (!(index in value) || entry === undefined) {
|
|
152
|
+
throw new plugins.flexharness.FlexHarnessStoreFormatError(`${path}[${index}] is not JSON-safe.`);
|
|
153
|
+
}
|
|
154
|
+
return visit(entry, `${path}[${index}]`);
|
|
155
|
+
});
|
|
156
|
+
seen.delete(value);
|
|
157
|
+
return result;
|
|
158
|
+
}
|
|
159
|
+
const result = {};
|
|
160
|
+
for (const key of Object.getOwnPropertyNames(value)) {
|
|
161
|
+
const descriptor = Object.getOwnPropertyDescriptor(value, key);
|
|
162
|
+
if (!descriptor.enumerable || !('value' in descriptor)) {
|
|
163
|
+
throw new plugins.flexharness.FlexHarnessStoreFormatError(`${path}.${key} is not a plain JSON property.`);
|
|
164
|
+
}
|
|
165
|
+
const entry = visit(descriptor.value, `${path}.${key}`);
|
|
166
|
+
if (entry !== undefined)
|
|
167
|
+
result[key] = entry;
|
|
168
|
+
}
|
|
169
|
+
seen.delete(value);
|
|
170
|
+
return result;
|
|
171
|
+
};
|
|
172
|
+
return visit(valueArg, pathArg);
|
|
173
|
+
};
|
|
174
|
+
const assertIdentifier = (valueArg, nameArg) => {
|
|
175
|
+
if (typeof valueArg !== 'string'
|
|
176
|
+
|| valueArg.trim().length === 0
|
|
177
|
+
|| Buffer.byteLength(valueArg, 'utf8') > 512) {
|
|
178
|
+
throw new plugins.flexharness.FlexHarnessStoreFormatError(`${nameArg} must be a non-empty string of at most 512 bytes.`);
|
|
179
|
+
}
|
|
180
|
+
};
|
|
181
|
+
const assertExpectedNextRevision = (snapshotRevisionArg, expectedRevisionArg) => {
|
|
182
|
+
if (!Number.isSafeInteger(expectedRevisionArg) || expectedRevisionArg < 0) {
|
|
183
|
+
throw new plugins.flexharness.FlexHarnessStoreFormatError('expectedRevision must be a non-negative integer.');
|
|
184
|
+
}
|
|
185
|
+
if (snapshotRevisionArg !== expectedRevisionArg + 1) {
|
|
186
|
+
throw new plugins.flexharness.FlexHarnessStoreFormatError(`Snapshot revision ${snapshotRevisionArg} must equal expected revision ${expectedRevisionArg} plus one.`);
|
|
187
|
+
}
|
|
188
|
+
};
|
|
189
|
+
const smartRevisionSelector = (valueArg) => valueArg._smartdataRevision === undefined ? { $exists: false } : valueArg._smartdataRevision;
|
|
190
|
+
const privateChunkManifestsEqual = (leftArg, rightArg) => leftArg.length === rightArg.length && leftArg.every((left, index) => {
|
|
191
|
+
const right = rightArg[index];
|
|
192
|
+
return right !== undefined
|
|
193
|
+
&& left.id === right.id
|
|
194
|
+
&& left.index === right.index
|
|
195
|
+
&& left.sha256 === right.sha256
|
|
196
|
+
&& left.bytes === right.bytes;
|
|
197
|
+
});
|
|
198
|
+
const publicManifestsEqual = (leftArg, rightArg) => canonicalJson(leftArg) === canonicalJson(rightArg);
|
|
199
|
+
const domainHeadBody = (valueArg) => ({
|
|
200
|
+
id: valueArg.id,
|
|
201
|
+
controllerId: valueArg.controllerId,
|
|
202
|
+
storageKey: valueArg.storageKey,
|
|
203
|
+
domain: valueArg.domain,
|
|
204
|
+
incarnationId: valueArg.incarnationId,
|
|
205
|
+
revision: valueArg.revision,
|
|
206
|
+
currentPrivateCandidateId: valueArg.currentPrivateCandidateId,
|
|
207
|
+
privateCandidate: valueArg.privateCandidate,
|
|
208
|
+
...(valueArg.projectionSource !== undefined
|
|
209
|
+
? { projectionSource: valueArg.projectionSource }
|
|
210
|
+
: {}),
|
|
211
|
+
...(valueArg.sessionId !== undefined ? { sessionId: valueArg.sessionId } : {}),
|
|
212
|
+
...(valueArg.archiveId !== undefined ? { archiveId: valueArg.archiveId } : {}),
|
|
213
|
+
});
|
|
214
|
+
const publicHeadBody = (valueArg) => ({
|
|
215
|
+
id: valueArg.id,
|
|
216
|
+
controllerId: valueArg.controllerId,
|
|
217
|
+
storageKey: valueArg.storageKey,
|
|
218
|
+
revision: valueArg.revision,
|
|
219
|
+
currentPublicCandidateId: valueArg.currentPublicCandidateId,
|
|
220
|
+
publicCandidates: valueArg.publicCandidates,
|
|
221
|
+
});
|
|
222
|
+
const leaseBody = (valueArg) => ({
|
|
223
|
+
id: valueArg.id,
|
|
224
|
+
controllerId: valueArg.controllerId,
|
|
225
|
+
storageKey: valueArg.storageKey,
|
|
226
|
+
ownerToken: valueArg.ownerToken,
|
|
227
|
+
epoch: valueArg.epoch,
|
|
228
|
+
state: valueArg.state,
|
|
229
|
+
expiresAt: valueArg.expiresAt,
|
|
230
|
+
updatedAt: valueArg.updatedAt,
|
|
231
|
+
});
|
|
232
|
+
const leaseTransitionImage = (valueArg) => ({
|
|
233
|
+
_id: valueArg._id,
|
|
234
|
+
...leaseBody(valueArg),
|
|
235
|
+
...(valueArg._smartdataRevision !== undefined
|
|
236
|
+
? { _smartdataRevision: valueArg._smartdataRevision }
|
|
237
|
+
: {}),
|
|
238
|
+
});
|
|
239
|
+
const leaseTransitionImagesEqual = (leftArg, rightArg) => String(leftArg._id) === String(rightArg._id)
|
|
240
|
+
&& canonicalJson(leaseBody(leftArg)) === canonicalJson(leaseBody(rightArg))
|
|
241
|
+
&& leftArg._smartdataRevision === rightArg._smartdataRevision;
|
|
242
|
+
const migrationBody = (valueArg) => ({
|
|
243
|
+
id: valueArg.id,
|
|
244
|
+
controllerId: valueArg.controllerId,
|
|
245
|
+
storageKey: valueArg.storageKey,
|
|
246
|
+
migration: valueArg.migration,
|
|
247
|
+
legacyRevision: valueArg.legacyRevision,
|
|
248
|
+
legacyCandidateId: valueArg.legacyCandidateId,
|
|
249
|
+
completedAt: valueArg.completedAt,
|
|
250
|
+
});
|
|
251
|
+
const projectPrivateChunk = (modelArg) => ({
|
|
252
|
+
id: modelArg.id,
|
|
253
|
+
controllerId: modelArg.controllerId,
|
|
254
|
+
scopeId: modelArg.scopeId,
|
|
255
|
+
candidateId: modelArg.candidateId,
|
|
256
|
+
revision: modelArg.revision,
|
|
257
|
+
index: modelArg.index,
|
|
258
|
+
sha256: modelArg.sha256,
|
|
259
|
+
bytes: modelArg.bytes,
|
|
260
|
+
data: modelArg.data,
|
|
261
|
+
createdAt: modelArg.createdAt,
|
|
262
|
+
...(modelArg.domain !== undefined ? { domain: modelArg.domain } : {}),
|
|
263
|
+
...(modelArg.incarnationId !== undefined ? { incarnationId: modelArg.incarnationId } : {}),
|
|
264
|
+
...(modelArg.sessionId !== undefined ? { sessionId: modelArg.sessionId } : {}),
|
|
265
|
+
...(modelArg.archiveId !== undefined ? { archiveId: modelArg.archiveId } : {}),
|
|
266
|
+
});
|
|
267
|
+
const projectPrivateCandidate = (modelArg) => ({
|
|
268
|
+
id: modelArg.id,
|
|
269
|
+
controllerId: modelArg.controllerId,
|
|
270
|
+
scopeId: modelArg.scopeId,
|
|
271
|
+
candidateId: modelArg.candidateId,
|
|
272
|
+
revision: modelArg.revision,
|
|
273
|
+
sha256: modelArg.sha256,
|
|
274
|
+
bytes: modelArg.bytes,
|
|
275
|
+
chunks: modelArg.chunks,
|
|
276
|
+
createdAt: modelArg.createdAt,
|
|
277
|
+
...(modelArg.domain !== undefined ? { domain: modelArg.domain } : {}),
|
|
278
|
+
...(modelArg.incarnationId !== undefined ? { incarnationId: modelArg.incarnationId } : {}),
|
|
279
|
+
...(modelArg.sessionId !== undefined ? { sessionId: modelArg.sessionId } : {}),
|
|
280
|
+
...(modelArg.archiveId !== undefined ? { archiveId: modelArg.archiveId } : {}),
|
|
281
|
+
});
|
|
282
|
+
const projectPublicCandidate = (modelArg) => ({
|
|
283
|
+
id: modelArg.id,
|
|
284
|
+
controllerId: modelArg.controllerId,
|
|
285
|
+
scopeId: modelArg.scopeId,
|
|
286
|
+
candidateId: modelArg.candidateId,
|
|
287
|
+
revision: modelArg.revision,
|
|
288
|
+
sha256: modelArg.sha256,
|
|
289
|
+
bytes: modelArg.bytes,
|
|
290
|
+
sessionRecords: modelArg.sessionRecords,
|
|
291
|
+
messageRecords: modelArg.messageRecords,
|
|
292
|
+
sessionsTruncated: modelArg.sessionsTruncated,
|
|
293
|
+
messagesTruncated: modelArg.messagesTruncated,
|
|
294
|
+
messageBytesTruncated: modelArg.messageBytesTruncated,
|
|
295
|
+
visibleDigest: modelArg.visibleDigest,
|
|
296
|
+
scopeSource: modelArg.scopeSource,
|
|
297
|
+
projectionSources: modelArg.projectionSources,
|
|
298
|
+
createdAt: modelArg.createdAt,
|
|
299
|
+
});
|
|
300
|
+
const projectPublicSession = (modelArg) => ({
|
|
301
|
+
id: modelArg.id,
|
|
302
|
+
controllerId: modelArg.controllerId,
|
|
303
|
+
scopeId: modelArg.scopeId,
|
|
304
|
+
candidateId: modelArg.candidateId,
|
|
305
|
+
revision: modelArg.revision,
|
|
306
|
+
session: modelArg.session,
|
|
307
|
+
createdAt: modelArg.createdAt,
|
|
308
|
+
});
|
|
309
|
+
const projectPublicMessage = (modelArg) => ({
|
|
310
|
+
id: modelArg.id,
|
|
311
|
+
controllerId: modelArg.controllerId,
|
|
312
|
+
scopeId: modelArg.scopeId,
|
|
313
|
+
candidateId: modelArg.candidateId,
|
|
314
|
+
revision: modelArg.revision,
|
|
315
|
+
messageIndex: modelArg.messageIndex,
|
|
316
|
+
message: modelArg.message,
|
|
317
|
+
createdAt: modelArg.createdAt,
|
|
318
|
+
});
|
|
319
|
+
const projectProjectionSource = (modelArg) => ({
|
|
320
|
+
id: modelArg.id,
|
|
321
|
+
controllerId: modelArg.controllerId,
|
|
322
|
+
scopeId: modelArg.scopeId,
|
|
323
|
+
sessionId: modelArg.sessionId,
|
|
324
|
+
candidateId: modelArg.candidateId,
|
|
325
|
+
incarnationId: modelArg.incarnationId,
|
|
326
|
+
revision: modelArg.revision,
|
|
327
|
+
...(modelArg.orderVersion === undefined ? {} : { orderVersion: modelArg.orderVersion }),
|
|
328
|
+
sha256: modelArg.sha256,
|
|
329
|
+
bytes: modelArg.bytes,
|
|
330
|
+
messageCount: modelArg.messageCount,
|
|
331
|
+
messagesTruncated: modelArg.messagesTruncated,
|
|
332
|
+
visibleDigest: modelArg.visibleDigest,
|
|
333
|
+
...(modelArg.latestMessage === undefined ? {} : { latestMessage: modelArg.latestMessage }),
|
|
334
|
+
createdAt: modelArg.createdAt,
|
|
335
|
+
});
|
|
336
|
+
const projectProjectionMessage = (modelArg) => ({
|
|
337
|
+
id: modelArg.id,
|
|
338
|
+
controllerId: modelArg.controllerId,
|
|
339
|
+
scopeId: modelArg.scopeId,
|
|
340
|
+
candidateId: modelArg.candidateId,
|
|
341
|
+
sessionId: modelArg.sessionId,
|
|
342
|
+
incarnationId: modelArg.incarnationId,
|
|
343
|
+
revision: modelArg.revision,
|
|
344
|
+
index: modelArg.index,
|
|
345
|
+
...(modelArg.messageIndex === undefined ? {} : { messageIndex: modelArg.messageIndex }),
|
|
346
|
+
sha256: modelArg.sha256,
|
|
347
|
+
bytes: modelArg.bytes,
|
|
348
|
+
messageCreatedAt: modelArg.messageCreatedAt,
|
|
349
|
+
messageId: modelArg.messageId,
|
|
350
|
+
message: modelArg.message,
|
|
351
|
+
...(modelArg.previous === undefined ? {} : { previous: modelArg.previous }),
|
|
352
|
+
createdAt: modelArg.createdAt,
|
|
353
|
+
});
|
|
354
|
+
const insertOrdinary = async (modelConstructorArg, documentArg) => {
|
|
355
|
+
const model = Object.assign(new modelConstructorArg(), documentArg);
|
|
356
|
+
await modelConstructorArg.insert(model);
|
|
357
|
+
};
|
|
358
|
+
const inBatches = async (valuesArg, operationArg) => {
|
|
359
|
+
for (let index = 0; index < valuesArg.length; index += 32) {
|
|
360
|
+
await Promise.all(valuesArg.slice(index, index + 32).map(operationArg));
|
|
361
|
+
}
|
|
362
|
+
};
|
|
363
|
+
const createPrivateProjection = (controllerIdArg, storageKeyArg, candidateIdArg, revisionArg, snapshotArg, createdAtArg, sourceArg) => {
|
|
364
|
+
const complete = serializedBytes(snapshotArg);
|
|
365
|
+
const chunks = [];
|
|
366
|
+
for (let offset = 0, index = 0; offset < complete.byteLength || index === 0; index++) {
|
|
367
|
+
const chunk = complete.subarray(offset, Math.min(offset + flexPrivateChunkBytes, complete.byteLength));
|
|
368
|
+
const id = privateChunkDocumentId(candidateIdArg, index);
|
|
369
|
+
chunks.push({
|
|
370
|
+
id,
|
|
371
|
+
controllerId: controllerIdArg,
|
|
372
|
+
scopeId: storageKeyArg,
|
|
373
|
+
candidateId: candidateIdArg,
|
|
374
|
+
revision: revisionArg,
|
|
375
|
+
index,
|
|
376
|
+
sha256: sha256(chunk),
|
|
377
|
+
bytes: chunk.byteLength,
|
|
378
|
+
data: chunk.toString('base64'),
|
|
379
|
+
createdAt: createdAtArg,
|
|
380
|
+
...(sourceArg ? {
|
|
381
|
+
domain: sourceArg.identity.domain,
|
|
382
|
+
incarnationId: sourceArg.incarnationId,
|
|
383
|
+
...(sourceArg.identity.sessionId !== undefined
|
|
384
|
+
? { sessionId: sourceArg.identity.sessionId }
|
|
385
|
+
: {}),
|
|
386
|
+
...(sourceArg.identity.archiveId !== undefined
|
|
387
|
+
? { archiveId: sourceArg.identity.archiveId }
|
|
388
|
+
: {}),
|
|
389
|
+
} : {}),
|
|
390
|
+
});
|
|
391
|
+
offset += chunk.byteLength;
|
|
392
|
+
if (complete.byteLength === 0)
|
|
393
|
+
break;
|
|
394
|
+
}
|
|
395
|
+
const candidate = {
|
|
396
|
+
id: privateCandidateDocumentId(candidateIdArg),
|
|
397
|
+
controllerId: controllerIdArg,
|
|
398
|
+
scopeId: storageKeyArg,
|
|
399
|
+
candidateId: candidateIdArg,
|
|
400
|
+
revision: revisionArg,
|
|
401
|
+
sha256: sha256(complete),
|
|
402
|
+
bytes: complete.byteLength,
|
|
403
|
+
chunks: chunks.map(({ id, index, sha256: digest, bytes }) => ({
|
|
404
|
+
id, index, sha256: digest, bytes,
|
|
405
|
+
})),
|
|
406
|
+
createdAt: createdAtArg,
|
|
407
|
+
...(sourceArg ? {
|
|
408
|
+
domain: sourceArg.identity.domain,
|
|
409
|
+
incarnationId: sourceArg.incarnationId,
|
|
410
|
+
...(sourceArg.identity.sessionId !== undefined
|
|
411
|
+
? { sessionId: sourceArg.identity.sessionId }
|
|
412
|
+
: {}),
|
|
413
|
+
...(sourceArg.identity.archiveId !== undefined
|
|
414
|
+
? { archiveId: sourceArg.identity.archiveId }
|
|
415
|
+
: {}),
|
|
416
|
+
} : {}),
|
|
417
|
+
};
|
|
418
|
+
assertFlexPrivateCandidateDocument(candidate);
|
|
419
|
+
for (const chunk of chunks)
|
|
420
|
+
assertFlexPrivateChunkDocument(chunk);
|
|
421
|
+
return { candidate, chunks };
|
|
422
|
+
};
|
|
423
|
+
export const createProjectionSource = (controllerIdArg, storageKeyArg, sessionIdArg, snapshotArg, preparationArg, limitsArg = {
|
|
424
|
+
messageLimit: flexPublicMessageLimit,
|
|
425
|
+
messageBytesLimit: flexPublicMessageBytesLimit,
|
|
426
|
+
singleMessageBytesLimit: flexPublicSingleMessageBytesLimit,
|
|
427
|
+
}) => {
|
|
428
|
+
const retainedMessages = snapshotArg.messages.slice(-limitsArg.messageLimit);
|
|
429
|
+
const buildChain = (orderedMessagesArg, normalizeOversizedArg, messageIndexOffsetArg) => {
|
|
430
|
+
const messages = [];
|
|
431
|
+
let previous;
|
|
432
|
+
let replaced = false;
|
|
433
|
+
for (const [index, sourceMessage] of orderedMessagesArg.entries()) {
|
|
434
|
+
let message = sourceMessage;
|
|
435
|
+
let payload = projectionMessagePayloadBytes(message, previous);
|
|
436
|
+
if (payload.byteLength > limitsArg.singleMessageBytesLimit) {
|
|
437
|
+
if (!normalizeOversizedArg) {
|
|
438
|
+
throw new Error('Flex projection source normalization invariant failed.');
|
|
439
|
+
}
|
|
440
|
+
const placeholder = placeholderMessage(sourceMessage);
|
|
441
|
+
const placeholderPayload = projectionMessagePayloadBytes(placeholder, previous);
|
|
442
|
+
if (projectionMessageBodyBytes(placeholder) >= projectionMessageBodyBytes(sourceMessage)
|
|
443
|
+
|| placeholderPayload.byteLength > limitsArg.singleMessageBytesLimit) {
|
|
444
|
+
throw new plugins.flexharness.FlexHarnessStoreFormatError('Flex projection source message metadata exceeds its projection limit.');
|
|
445
|
+
}
|
|
446
|
+
message = placeholder;
|
|
447
|
+
payload = placeholderPayload;
|
|
448
|
+
replaced = true;
|
|
449
|
+
}
|
|
450
|
+
const descriptor = {
|
|
451
|
+
id: projectionMessageDocumentId(preparationArg.candidateId, index),
|
|
452
|
+
index,
|
|
453
|
+
messageIndex: messageIndexOffsetArg + index,
|
|
454
|
+
sha256: sha256(payload),
|
|
455
|
+
bytes: payload.byteLength,
|
|
456
|
+
messageCreatedAt: message.createdAt,
|
|
457
|
+
sessionId: sessionIdArg,
|
|
458
|
+
messageId: message.messageId,
|
|
459
|
+
};
|
|
460
|
+
const record = {
|
|
461
|
+
...descriptor,
|
|
462
|
+
controllerId: controllerIdArg,
|
|
463
|
+
scopeId: storageKeyArg,
|
|
464
|
+
candidateId: preparationArg.candidateId,
|
|
465
|
+
incarnationId: preparationArg.incarnationId,
|
|
466
|
+
revision: preparationArg.revision,
|
|
467
|
+
message,
|
|
468
|
+
...(previous === undefined ? {} : { previous }),
|
|
469
|
+
createdAt: preparationArg.createdAt,
|
|
470
|
+
};
|
|
471
|
+
assertFlexProjectionMessageRecordDocument(record);
|
|
472
|
+
messages.push(record);
|
|
473
|
+
previous = descriptor;
|
|
474
|
+
}
|
|
475
|
+
return { messages, replaced };
|
|
476
|
+
};
|
|
477
|
+
const normalized = buildChain(retainedMessages, true, snapshotArg.messages.length - retainedMessages.length);
|
|
478
|
+
const selectedNewest = [];
|
|
479
|
+
let selectedMessageBytes = 0;
|
|
480
|
+
for (let index = normalized.messages.length - 1; index >= 0; index--) {
|
|
481
|
+
const message = normalized.messages[index].message;
|
|
482
|
+
const bodyBytes = projectionMessageBodyBytes(message);
|
|
483
|
+
if (selectedMessageBytes + bodyBytes > limitsArg.messageBytesLimit)
|
|
484
|
+
break;
|
|
485
|
+
selectedMessageBytes += bodyBytes;
|
|
486
|
+
selectedNewest.push(message);
|
|
487
|
+
}
|
|
488
|
+
const finalChain = buildChain(selectedNewest.reverse(), false, snapshotArg.messages.length - selectedNewest.length);
|
|
489
|
+
const messages = finalChain.messages;
|
|
490
|
+
const previous = messages.at(-1);
|
|
491
|
+
const latestMessage = previous
|
|
492
|
+
? {
|
|
493
|
+
id: previous.id,
|
|
494
|
+
index: previous.index,
|
|
495
|
+
messageIndex: previous.messageIndex,
|
|
496
|
+
sha256: previous.sha256,
|
|
497
|
+
bytes: previous.bytes,
|
|
498
|
+
messageCreatedAt: previous.messageCreatedAt,
|
|
499
|
+
sessionId: previous.sessionId,
|
|
500
|
+
messageId: previous.messageId,
|
|
501
|
+
}
|
|
502
|
+
: undefined;
|
|
503
|
+
const messagesTruncated = retainedMessages.length < snapshotArg.messages.length
|
|
504
|
+
|| messages.length < retainedMessages.length
|
|
505
|
+
|| normalized.replaced;
|
|
506
|
+
const visibleHash = plugins.crypto.createHash('sha256');
|
|
507
|
+
visibleHash.update('order:1', 'utf8');
|
|
508
|
+
visibleHash.update(messagesTruncated ? '1' : '0', 'utf8');
|
|
509
|
+
for (const message of messages) {
|
|
510
|
+
visibleHash.update('\0', 'utf8');
|
|
511
|
+
visibleHash.update(String(message.messageIndex), 'utf8');
|
|
512
|
+
visibleHash.update('\0', 'utf8');
|
|
513
|
+
visibleHash.update(sha256(Buffer.from(canonicalJson(message.message), 'utf8')), 'utf8');
|
|
514
|
+
}
|
|
515
|
+
const unhashedManifest = {
|
|
516
|
+
candidateId: preparationArg.candidateId,
|
|
517
|
+
orderVersion: 1,
|
|
518
|
+
messageCount: messages.length,
|
|
519
|
+
messagesTruncated,
|
|
520
|
+
visibleDigest: visibleHash.digest('hex'),
|
|
521
|
+
...(latestMessage === undefined ? {} : { latestMessage }),
|
|
522
|
+
};
|
|
523
|
+
const manifestBytes = projectionSourceManifestBytes(unhashedManifest);
|
|
524
|
+
const manifest = {
|
|
525
|
+
...unhashedManifest,
|
|
526
|
+
sha256: sha256(manifestBytes),
|
|
527
|
+
bytes: manifestBytes.byteLength,
|
|
528
|
+
};
|
|
529
|
+
const source = {
|
|
530
|
+
id: projectionSourceDocumentId(preparationArg.candidateId),
|
|
531
|
+
controllerId: controllerIdArg,
|
|
532
|
+
scopeId: storageKeyArg,
|
|
533
|
+
sessionId: sessionIdArg,
|
|
534
|
+
incarnationId: preparationArg.incarnationId,
|
|
535
|
+
revision: preparationArg.revision,
|
|
536
|
+
...manifest,
|
|
537
|
+
createdAt: preparationArg.createdAt,
|
|
538
|
+
};
|
|
539
|
+
assertFlexProjectionSourceDocument(source);
|
|
540
|
+
return { manifest, source, messages };
|
|
541
|
+
};
|
|
542
|
+
export const createFlexPublicProjection = (controllerIdArg, storageKeyArg, candidateIdArg, publicationRevisionArg, scopeSourceArg, projectionSourcesArg, createdAtArg = new Date().toISOString()) => {
|
|
543
|
+
const retainedSessions = retainPublicSessions(scopeSourceArg.snapshot.sessions);
|
|
544
|
+
const retainedSessionIds = new Set(retainedSessions.map((session) => session.sessionId));
|
|
545
|
+
const projectionBySession = new Map(projectionSourcesArg.map((source) => [
|
|
546
|
+
source.head.sessionId,
|
|
547
|
+
source,
|
|
548
|
+
]));
|
|
549
|
+
const sessions = retainedSessions.map((session) => ({
|
|
550
|
+
id: publicSessionDocumentId(candidateIdArg, session.sessionId),
|
|
551
|
+
controllerId: controllerIdArg,
|
|
552
|
+
scopeId: storageKeyArg,
|
|
553
|
+
candidateId: candidateIdArg,
|
|
554
|
+
revision: publicationRevisionArg,
|
|
555
|
+
session: cloneJson(session),
|
|
556
|
+
createdAt: createdAtArg,
|
|
557
|
+
}));
|
|
558
|
+
const scopeSessionIds = new Set(scopeSourceArg.snapshot.sessions.map((session) => session.sessionId));
|
|
559
|
+
const originalMessageCount = projectionSourcesArg.reduce((total, source) => (source.head.sessionId && scopeSessionIds.has(source.head.sessionId)
|
|
560
|
+
? total + source.snapshot.messages.length
|
|
561
|
+
: total), 0);
|
|
562
|
+
const sourceEntries = projectionSourcesArg.flatMap((source) => {
|
|
563
|
+
if (!source.head.sessionId || !retainedSessionIds.has(source.head.sessionId))
|
|
564
|
+
return [];
|
|
565
|
+
const sourceTail = source.snapshot.messages.slice(-flexPublicMessageLimit);
|
|
566
|
+
return sourceTail.length === 0 ? [] : [{
|
|
567
|
+
messages: sourceTail,
|
|
568
|
+
sourceIndex: sourceTail.length - 1,
|
|
569
|
+
messageIndex: source.snapshot.messages.length - 1,
|
|
570
|
+
}];
|
|
571
|
+
});
|
|
572
|
+
const allMessages = [];
|
|
573
|
+
while (sourceEntries.length > 0 && allMessages.length < flexPublicMessageLimit) {
|
|
574
|
+
let newestIndex = 0;
|
|
575
|
+
for (let index = 1; index < sourceEntries.length; index++) {
|
|
576
|
+
const candidate = sourceEntries[index];
|
|
577
|
+
const newest = sourceEntries[newestIndex];
|
|
578
|
+
if (compareNewestOrderedMessage({ messageIndex: candidate.messageIndex, message: candidate.messages[candidate.sourceIndex] }, { messageIndex: newest.messageIndex, message: newest.messages[newest.sourceIndex] }) < 0)
|
|
579
|
+
newestIndex = index;
|
|
580
|
+
}
|
|
581
|
+
const newest = sourceEntries[newestIndex];
|
|
582
|
+
allMessages.push({
|
|
583
|
+
messageIndex: newest.messageIndex,
|
|
584
|
+
message: newest.messages[newest.sourceIndex],
|
|
585
|
+
});
|
|
586
|
+
newest.sourceIndex -= 1;
|
|
587
|
+
newest.messageIndex -= 1;
|
|
588
|
+
if (newest.sourceIndex < 0)
|
|
589
|
+
sourceEntries.splice(newestIndex, 1);
|
|
590
|
+
}
|
|
591
|
+
const messages = [];
|
|
592
|
+
let messageBytes = 0;
|
|
593
|
+
let messageBytesTruncated = false;
|
|
594
|
+
let oversizedMessagesReplaced = false;
|
|
595
|
+
for (const sourceEntry of allMessages) {
|
|
596
|
+
if (messages.length >= flexPublicMessageLimit)
|
|
597
|
+
break;
|
|
598
|
+
const createRecord = (messageArg) => ({
|
|
599
|
+
id: publicMessageDocumentId(candidateIdArg, messageArg.sessionId, messageArg.messageId),
|
|
600
|
+
controllerId: controllerIdArg,
|
|
601
|
+
scopeId: storageKeyArg,
|
|
602
|
+
candidateId: candidateIdArg,
|
|
603
|
+
revision: publicationRevisionArg,
|
|
604
|
+
messageIndex: sourceEntry.messageIndex,
|
|
605
|
+
message: cloneJson(messageArg),
|
|
606
|
+
createdAt: createdAtArg,
|
|
607
|
+
});
|
|
608
|
+
let record = createRecord(sourceEntry.message);
|
|
609
|
+
let recordBytes = serializedBytes(record).byteLength;
|
|
610
|
+
if (recordBytes > flexPublicSingleMessageBytesLimit) {
|
|
611
|
+
record = createRecord(placeholderMessage(sourceEntry.message));
|
|
612
|
+
recordBytes = serializedBytes(record).byteLength;
|
|
613
|
+
oversizedMessagesReplaced = true;
|
|
614
|
+
if (recordBytes > flexPublicSingleMessageBytesLimit) {
|
|
615
|
+
throw new plugins.flexharness.FlexHarnessStoreFormatError('Flex public message metadata exceeds its projection limit.');
|
|
616
|
+
}
|
|
617
|
+
}
|
|
618
|
+
if (messageBytes + recordBytes > flexPublicMessageBytesLimit) {
|
|
619
|
+
messageBytesTruncated = true;
|
|
620
|
+
break;
|
|
621
|
+
}
|
|
622
|
+
messageBytes += recordBytes;
|
|
623
|
+
messages.push(record);
|
|
624
|
+
}
|
|
625
|
+
const sessionsTruncated = retainedSessions.length < scopeSourceArg.snapshot.sessions.length;
|
|
626
|
+
const messagesTruncated = sessionsTruncated
|
|
627
|
+
|| messages.length < originalMessageCount
|
|
628
|
+
|| oversizedMessagesReplaced;
|
|
629
|
+
const sessionRecords = sessions.map(recordManifest);
|
|
630
|
+
if (new Set(messages.map((record) => (`${record.message.sessionId}\0${record.messageIndex}`))).size !== messages.length) {
|
|
631
|
+
throw new plugins.flexharness.FlexHarnessStoreFormatError('Flex public projection contains duplicate message indexes.');
|
|
632
|
+
}
|
|
633
|
+
const messageRecords = messages.map(recordManifest);
|
|
634
|
+
const visibleDigest = sha256(serializedBytes({
|
|
635
|
+
sessions: sessions.map((record) => record.session),
|
|
636
|
+
messages: messages.map((record) => ({
|
|
637
|
+
messageIndex: record.messageIndex,
|
|
638
|
+
message: record.message,
|
|
639
|
+
})),
|
|
640
|
+
sessionsTruncated,
|
|
641
|
+
messagesTruncated,
|
|
642
|
+
messageBytesTruncated,
|
|
643
|
+
}));
|
|
644
|
+
const projectionSources = retainedSessions.flatMap((session) => {
|
|
645
|
+
const source = projectionBySession.get(session.sessionId);
|
|
646
|
+
return source ? [{
|
|
647
|
+
sessionId: session.sessionId,
|
|
648
|
+
incarnationId: source.head.incarnationId,
|
|
649
|
+
revision: source.head.revision,
|
|
650
|
+
}] : [];
|
|
651
|
+
});
|
|
652
|
+
const unhashedManifest = {
|
|
653
|
+
candidateId: candidateIdArg,
|
|
654
|
+
revision: publicationRevisionArg,
|
|
655
|
+
sessionRecords,
|
|
656
|
+
messageRecords,
|
|
657
|
+
sessionsTruncated,
|
|
658
|
+
messagesTruncated,
|
|
659
|
+
messageBytesTruncated,
|
|
660
|
+
visibleDigest,
|
|
661
|
+
scopeSource: {
|
|
662
|
+
incarnationId: scopeSourceArg.head.incarnationId,
|
|
663
|
+
revision: scopeSourceArg.head.revision,
|
|
664
|
+
},
|
|
665
|
+
projectionSources,
|
|
666
|
+
};
|
|
667
|
+
const candidateBytes = publicCandidateManifestBytes(unhashedManifest);
|
|
668
|
+
const candidate = {
|
|
669
|
+
id: publicCandidateDocumentId(candidateIdArg),
|
|
670
|
+
controllerId: controllerIdArg,
|
|
671
|
+
scopeId: storageKeyArg,
|
|
672
|
+
...unhashedManifest,
|
|
673
|
+
sha256: sha256(candidateBytes),
|
|
674
|
+
bytes: candidateBytes.byteLength,
|
|
675
|
+
createdAt: createdAtArg,
|
|
676
|
+
};
|
|
677
|
+
assertFlexPublicCandidateDocument(candidate);
|
|
678
|
+
for (const session of sessions)
|
|
679
|
+
assertFlexPublicSessionRecordDocument(session);
|
|
680
|
+
for (const message of messages)
|
|
681
|
+
assertFlexPublicMessageRecordDocument(message);
|
|
682
|
+
return { candidate, sessions, messages };
|
|
683
|
+
};
|
|
684
|
+
class FlexLeaseLostError extends Error {
|
|
685
|
+
constructor(storageKeyArg) {
|
|
686
|
+
super(`Flex writer lease for storage key "${storageKeyArg}" is not owned or has expired.`);
|
|
687
|
+
this.name = 'FlexLeaseLostError';
|
|
688
|
+
}
|
|
689
|
+
}
|
|
690
|
+
class FlexHeadCasError extends Error {
|
|
691
|
+
actualRevision;
|
|
692
|
+
constructor(actualRevision) {
|
|
693
|
+
super('Flex head compare-and-swap did not match.');
|
|
694
|
+
this.actualRevision = actualRevision;
|
|
695
|
+
this.name = 'FlexHeadCasError';
|
|
696
|
+
}
|
|
697
|
+
}
|
|
698
|
+
const waitForFlexStoreDeadline = async (promiseArg, timeoutMsArg, messageArg) => new Promise((resolve, reject) => {
|
|
699
|
+
const timer = setTimeout(() => reject(new Error(messageArg)), timeoutMsArg);
|
|
700
|
+
timer.unref?.();
|
|
701
|
+
void promiseArg.then(resolve, reject).finally(() => clearTimeout(timer));
|
|
702
|
+
});
|
|
703
|
+
const waitForFlexStoreRetry = async (timeoutMsArg, abortSignalArg) => new Promise((resolve, reject) => {
|
|
704
|
+
const timer = setTimeout(finish, timeoutMsArg);
|
|
705
|
+
timer.unref?.();
|
|
706
|
+
const abort = () => finish(abortSignalArg.reason, true);
|
|
707
|
+
function finish(errorArg, rejectedArg = false) {
|
|
708
|
+
clearTimeout(timer);
|
|
709
|
+
abortSignalArg?.removeEventListener('abort', abort);
|
|
710
|
+
if (rejectedArg)
|
|
711
|
+
reject(errorArg);
|
|
712
|
+
else
|
|
713
|
+
resolve();
|
|
714
|
+
}
|
|
715
|
+
if (abortSignalArg?.aborted)
|
|
716
|
+
abort();
|
|
717
|
+
else
|
|
718
|
+
abortSignalArg?.addEventListener('abort', abort, { once: true });
|
|
719
|
+
});
|
|
720
|
+
export class FlexStore {
|
|
721
|
+
scopes;
|
|
722
|
+
projections;
|
|
723
|
+
permissions;
|
|
724
|
+
projectManagement;
|
|
725
|
+
agentEvents;
|
|
726
|
+
jobs;
|
|
727
|
+
database;
|
|
728
|
+
controllerId;
|
|
729
|
+
onFatalError;
|
|
730
|
+
manager;
|
|
731
|
+
initialized = false;
|
|
732
|
+
initPromise;
|
|
733
|
+
closed = false;
|
|
734
|
+
closeComplete = false;
|
|
735
|
+
closePromise;
|
|
736
|
+
closeDrainTimeoutMs = flexMaintenanceOperationTimeoutMs;
|
|
737
|
+
maintenanceOpen = true;
|
|
738
|
+
maintenanceAbortController = new AbortController();
|
|
739
|
+
orphanMaintenanceTask;
|
|
740
|
+
orphanMaintenanceTimer;
|
|
741
|
+
heartbeatsOpen = true;
|
|
742
|
+
leaseHeartbeatTimer;
|
|
743
|
+
leaseTransitionTimeoutMs = flexLeaseTransitionTimeoutMs;
|
|
744
|
+
fatalError;
|
|
745
|
+
leaseTransitionAbortControllers = new Set();
|
|
746
|
+
heldLeases = new Map();
|
|
747
|
+
storageQueues = new Map();
|
|
748
|
+
activeCandidateIds = new Set();
|
|
749
|
+
agentEventStores = new Map();
|
|
750
|
+
jobStores = new Map();
|
|
751
|
+
constructor(optionsArg) {
|
|
752
|
+
assertIdentifier(optionsArg.controllerId, 'controllerId');
|
|
753
|
+
if (!optionsArg.projectManagementHost
|
|
754
|
+
|| typeof optionsArg.projectManagementHost.load !== 'function'
|
|
755
|
+
|| typeof optionsArg.projectManagementHost.save !== 'function'
|
|
756
|
+
|| typeof optionsArg.projectManagementHost.tombstoneSession !== 'function'
|
|
757
|
+
|| typeof optionsArg.projectManagementHost.purgeNamespace !== 'function')
|
|
758
|
+
throw new Error('FlexStore requires a durable project-management host.');
|
|
759
|
+
this.database = optionsArg.database;
|
|
760
|
+
this.controllerId = optionsArg.controllerId;
|
|
761
|
+
this.onFatalError = optionsArg.onFatalError;
|
|
762
|
+
this.manager = { db: this.database };
|
|
763
|
+
registerFlexPrivateModels(this.manager);
|
|
764
|
+
registerFlexPublicModels(this.manager);
|
|
765
|
+
this.scopes = {
|
|
766
|
+
load: (storageKey) => this.loadScope(storageKey),
|
|
767
|
+
save: (storageKey, snapshot, expectedRevision) => this.saveScope(storageKey, snapshot, expectedRevision),
|
|
768
|
+
};
|
|
769
|
+
this.projections = {
|
|
770
|
+
load: (storageKey, sessionId) => this.loadProjection(storageKey, sessionId),
|
|
771
|
+
save: (storageKey, sessionId, snapshot, expectedRevision) => this.saveProjection(storageKey, sessionId, snapshot, expectedRevision),
|
|
772
|
+
deleteSession: (storageKey, sessionId) => this.deleteProjection(storageKey, sessionId),
|
|
773
|
+
};
|
|
774
|
+
this.permissions = {
|
|
775
|
+
load: (storageKey, sessionId) => this.loadPermission(storageKey, sessionId),
|
|
776
|
+
save: (storageKey, sessionId, snapshot, expectedRevision) => this.savePermission(storageKey, sessionId, snapshot, expectedRevision),
|
|
777
|
+
deleteSession: (storageKey, sessionId) => this.deletePermission(storageKey, sessionId),
|
|
778
|
+
};
|
|
779
|
+
this.projectManagement = {
|
|
780
|
+
load: (storageKey, sessionId, sessionGeneration) => {
|
|
781
|
+
if (!sessionGeneration
|
|
782
|
+
|| typeof sessionGeneration.sessionGenerationId !== 'string'
|
|
783
|
+
|| sessionGeneration.sessionGenerationId.trim().length === 0
|
|
784
|
+
|| Buffer.byteLength(sessionGeneration.sessionGenerationId, 'utf8')
|
|
785
|
+
> plugins.flexharness.FLEX_SESSION_GENERATION_ID_MAX_BYTES
|
|
786
|
+
|| !Number.isSafeInteger(sessionGeneration.sessionGenerationSequence)
|
|
787
|
+
|| sessionGeneration.sessionGenerationSequence < 1) {
|
|
788
|
+
throw new plugins.flexharness.FlexHarnessStoreFormatError('Flex project-management load requires an authoritative session generation.');
|
|
789
|
+
}
|
|
790
|
+
return optionsArg.projectManagementHost.load(storageKey, sessionId, sessionGeneration);
|
|
791
|
+
},
|
|
792
|
+
save: (storageKey, sessionId, snapshot, expectedRevision, writeContext) => optionsArg.projectManagementHost.save(storageKey, sessionId, snapshot, expectedRevision, writeContext),
|
|
793
|
+
tombstoneSession: (storageKey, sessionId, tombstone, expectedRevision) => optionsArg.projectManagementHost.tombstoneSession(storageKey, sessionId, tombstone, expectedRevision),
|
|
794
|
+
purgeNamespace: (storageKey) => optionsArg.projectManagementHost.purgeNamespace(storageKey),
|
|
795
|
+
};
|
|
796
|
+
this.agentEvents = {
|
|
797
|
+
getStore: (storageKey, sessionId) => this.getAgentEventStore(storageKey, sessionId),
|
|
798
|
+
releaseSession: (storageKey, sessionId) => {
|
|
799
|
+
this.agentEventStores.delete(providerKey(storageKey, sessionId));
|
|
800
|
+
},
|
|
801
|
+
deleteSession: (storageKey, sessionId) => this.deleteAgentEventSession(storageKey, sessionId),
|
|
802
|
+
};
|
|
803
|
+
this.jobs = {
|
|
804
|
+
getStore: (storageKey, sessionId) => this.getJobStore(storageKey, sessionId),
|
|
805
|
+
releaseSession: (storageKey, sessionId) => {
|
|
806
|
+
this.jobStores.delete(providerKey(storageKey, sessionId));
|
|
807
|
+
},
|
|
808
|
+
deleteSession: (storageKey, sessionId) => this.deleteJobSession(storageKey, sessionId),
|
|
809
|
+
};
|
|
810
|
+
}
|
|
811
|
+
async init() {
|
|
812
|
+
this.throwIfFatal();
|
|
813
|
+
if (this.closed)
|
|
814
|
+
throw new Error('The Flex store is closed.');
|
|
815
|
+
if (this.initialized)
|
|
816
|
+
return;
|
|
817
|
+
if (this.initPromise)
|
|
818
|
+
return this.initPromise;
|
|
819
|
+
const initPromise = (async () => {
|
|
820
|
+
await initFlexPrivateModels();
|
|
821
|
+
await initFlexPublicModels();
|
|
822
|
+
this.initialized = true;
|
|
823
|
+
this.queueOrphanMaintenance();
|
|
824
|
+
})();
|
|
825
|
+
this.initPromise = initPromise;
|
|
826
|
+
try {
|
|
827
|
+
await initPromise;
|
|
828
|
+
}
|
|
829
|
+
finally {
|
|
830
|
+
if (this.initPromise === initPromise)
|
|
831
|
+
this.initPromise = undefined;
|
|
832
|
+
}
|
|
833
|
+
}
|
|
834
|
+
getLegacyMigrationStores() {
|
|
835
|
+
return {
|
|
836
|
+
scopes: {
|
|
837
|
+
...this.scopes,
|
|
838
|
+
save: (storageKey, snapshot, expectedRevision) => this.saveScope(storageKey, snapshot, expectedRevision, false),
|
|
839
|
+
},
|
|
840
|
+
projections: {
|
|
841
|
+
...this.projections,
|
|
842
|
+
save: (storageKey, sessionId, snapshot, expectedRevision) => this.saveProjection(storageKey, sessionId, snapshot, expectedRevision, false),
|
|
843
|
+
},
|
|
844
|
+
permissions: this.permissions,
|
|
845
|
+
projectManagement: this.projectManagement,
|
|
846
|
+
agentEvents: this.agentEvents,
|
|
847
|
+
jobs: this.jobs,
|
|
848
|
+
};
|
|
849
|
+
}
|
|
850
|
+
async loadLegacy(storageKeyArg) {
|
|
851
|
+
return this.runStorage(storageKeyArg, async () => {
|
|
852
|
+
const head = await this.readLegacyHead(storageKeyArg);
|
|
853
|
+
if (!head)
|
|
854
|
+
return undefined;
|
|
855
|
+
const manifest = head.privateCandidates.find((candidate) => candidate.candidateId === head.currentPrivateCandidateId);
|
|
856
|
+
if (!manifest || manifest.revision !== head.revision) {
|
|
857
|
+
throw new plugins.flexharness.FlexHarnessStoreFormatError('Flex legacy private head manifest is invalid.');
|
|
858
|
+
}
|
|
859
|
+
return this.loadPrivateCandidate(storageKeyArg, manifest, async (value) => value);
|
|
860
|
+
});
|
|
861
|
+
}
|
|
862
|
+
async hasCompletedLegacyMigration(storageKeyArg) {
|
|
863
|
+
return this.runStorage(storageKeyArg, async () => {
|
|
864
|
+
const marker = await this.readMigration(storageKeyArg);
|
|
865
|
+
if (!marker)
|
|
866
|
+
return false;
|
|
867
|
+
const legacyHead = await this.readLegacyHead(storageKeyArg);
|
|
868
|
+
if (!legacyHead
|
|
869
|
+
|| marker.legacyRevision !== legacyHead.revision
|
|
870
|
+
|| marker.legacyCandidateId !== legacyHead.currentPrivateCandidateId) {
|
|
871
|
+
throw new plugins.flexharness.FlexHarnessStoreFormatError('Completed Flex migration does not match its retained legacy source.');
|
|
872
|
+
}
|
|
873
|
+
return true;
|
|
874
|
+
});
|
|
875
|
+
}
|
|
876
|
+
async completeLegacyMigration(storageKeyArg) {
|
|
877
|
+
await this.runStorage(storageKeyArg, async (lease) => {
|
|
878
|
+
const legacyHead = await this.readLegacyHead(storageKeyArg);
|
|
879
|
+
if (!legacyHead) {
|
|
880
|
+
throw new plugins.flexharness.FlexHarnessStoreFormatError('Cannot complete Flex migration without its retained legacy source.');
|
|
881
|
+
}
|
|
882
|
+
const current = await this.readMigration(storageKeyArg);
|
|
883
|
+
if (current) {
|
|
884
|
+
if (current.legacyRevision !== legacyHead.revision
|
|
885
|
+
|| current.legacyCandidateId !== legacyHead.currentPrivateCandidateId) {
|
|
886
|
+
throw new plugins.flexharness.FlexHarnessStoreFormatError('Completed Flex migration does not match its retained legacy source.');
|
|
887
|
+
}
|
|
888
|
+
return;
|
|
889
|
+
}
|
|
890
|
+
const next = {
|
|
891
|
+
id: flexMigrationId(this.controllerId, storageKeyArg),
|
|
892
|
+
controllerId: this.controllerId,
|
|
893
|
+
storageKey: storageKeyArg,
|
|
894
|
+
migration: 'flexharness-v3',
|
|
895
|
+
legacyRevision: legacyHead.revision,
|
|
896
|
+
legacyCandidateId: legacyHead.currentPrivateCandidateId,
|
|
897
|
+
completedAt: new Date().toISOString(),
|
|
898
|
+
};
|
|
899
|
+
assertFlexMigrationDocument(next);
|
|
900
|
+
await this.commitHeadMutation({
|
|
901
|
+
lease,
|
|
902
|
+
collection: FlexMigrationModel.collection.mongoDbCollection,
|
|
903
|
+
current: null,
|
|
904
|
+
next,
|
|
905
|
+
selector: { id: next.id },
|
|
906
|
+
readCurrent: (options) => this.readMigration(storageKeyArg, options),
|
|
907
|
+
project: migrationBody,
|
|
908
|
+
targetName: `migration:${next.id}`,
|
|
909
|
+
});
|
|
910
|
+
});
|
|
911
|
+
}
|
|
912
|
+
async ensurePublicProjection(storageKeyArg) {
|
|
913
|
+
await this.runStorage(storageKeyArg, async (lease) => this.publishPublicProjection(storageKeyArg, lease));
|
|
914
|
+
}
|
|
915
|
+
async listProjectionOrderMigrationPage(storageKeyArg, cursorArg) {
|
|
916
|
+
return this.runStorage(storageKeyArg, async () => {
|
|
917
|
+
const heads = await this.readDomainHeadPage({
|
|
918
|
+
controllerId: this.controllerId,
|
|
919
|
+
storageKey: storageKeyArg,
|
|
920
|
+
domain: 'projection',
|
|
921
|
+
}, cursorArg);
|
|
922
|
+
const sessionIds = [];
|
|
923
|
+
for (const head of heads) {
|
|
924
|
+
if (!head.sessionId) {
|
|
925
|
+
throw new plugins.flexharness.FlexHarnessStoreFormatError('Flex projection head is missing its session identity.');
|
|
926
|
+
}
|
|
927
|
+
this.assertDomainHeadIdentity(head, {
|
|
928
|
+
storageKey: storageKeyArg,
|
|
929
|
+
domain: 'projection',
|
|
930
|
+
sessionId: head.sessionId,
|
|
931
|
+
});
|
|
932
|
+
if (head.projectionSource?.orderVersion !== 1)
|
|
933
|
+
sessionIds.push(head.sessionId);
|
|
934
|
+
}
|
|
935
|
+
const last = heads.at(-1);
|
|
936
|
+
return {
|
|
937
|
+
sessionIds,
|
|
938
|
+
...(last && heads.length === flexMaintenancePageLimit ? { nextCursor: last._id } : {}),
|
|
939
|
+
};
|
|
940
|
+
});
|
|
941
|
+
}
|
|
942
|
+
async rewriteProjectionSourceOrder(storageKeyArg, sessionIdArg) {
|
|
943
|
+
return this.runStorage(storageKeyArg, async (lease) => {
|
|
944
|
+
const identity = {
|
|
945
|
+
storageKey: storageKeyArg,
|
|
946
|
+
domain: 'projection',
|
|
947
|
+
sessionId: sessionIdArg,
|
|
948
|
+
};
|
|
949
|
+
const current = await this.readDomainHead(identity);
|
|
950
|
+
if (!current || current.projectionSource?.orderVersion === 1)
|
|
951
|
+
return false;
|
|
952
|
+
const snapshot = await this.loadPrivateCandidate(storageKeyArg, current.privateCandidate, (value) => this.validateProjectionSnapshot(value, sessionIdArg), undefined, { identity, incarnationId: current.incarnationId });
|
|
953
|
+
const candidateId = randomCandidateId();
|
|
954
|
+
const build = createProjectionSource(this.controllerId, storageKeyArg, sessionIdArg, snapshot, {
|
|
955
|
+
candidateId,
|
|
956
|
+
incarnationId: current.incarnationId,
|
|
957
|
+
revision: current.revision,
|
|
958
|
+
createdAt: new Date().toISOString(),
|
|
959
|
+
});
|
|
960
|
+
const next = {
|
|
961
|
+
...domainHeadBody(current),
|
|
962
|
+
projectionSource: build.manifest,
|
|
963
|
+
};
|
|
964
|
+
assertFlexDomainHeadDocument(next);
|
|
965
|
+
this.activeCandidateIds.add(candidateId);
|
|
966
|
+
let committed = false;
|
|
967
|
+
try {
|
|
968
|
+
await this.writeAndVerifyProjectionSource(build);
|
|
969
|
+
await this.commitDomainHead(lease, current, next, identity);
|
|
970
|
+
committed = true;
|
|
971
|
+
if (current.projectionSource) {
|
|
972
|
+
await this.cleanupProjectionSourceByCandidate(current.projectionSource.candidateId).catch(() => undefined);
|
|
973
|
+
}
|
|
974
|
+
}
|
|
975
|
+
finally {
|
|
976
|
+
this.activeCandidateIds.delete(candidateId);
|
|
977
|
+
if (!committed)
|
|
978
|
+
this.queueOrphanMaintenance();
|
|
979
|
+
}
|
|
980
|
+
return true;
|
|
981
|
+
});
|
|
982
|
+
}
|
|
983
|
+
async purgeScope(storageKeyArg) {
|
|
984
|
+
await this.runStorage(storageKeyArg, async (lease) => {
|
|
985
|
+
this.evictProviderScope(storageKeyArg);
|
|
986
|
+
let lastDomainHeadId;
|
|
987
|
+
while (true) {
|
|
988
|
+
const domainHeads = await this.readDomainHeadPage({
|
|
989
|
+
controllerId: this.controllerId,
|
|
990
|
+
storageKey: storageKeyArg,
|
|
991
|
+
}, lastDomainHeadId);
|
|
992
|
+
for (const head of domainHeads) {
|
|
993
|
+
const identity = {
|
|
994
|
+
storageKey: storageKeyArg,
|
|
995
|
+
domain: head.domain,
|
|
996
|
+
...(head.sessionId !== undefined ? { sessionId: head.sessionId } : {}),
|
|
997
|
+
...(head.archiveId !== undefined ? { archiveId: head.archiveId } : {}),
|
|
998
|
+
};
|
|
999
|
+
this.assertDomainHeadIdentity(head, identity);
|
|
1000
|
+
await this.deleteDomainHead(lease, head, identity);
|
|
1001
|
+
}
|
|
1002
|
+
const last = domainHeads.at(-1);
|
|
1003
|
+
if (!last || domainHeads.length < flexMaintenancePageLimit)
|
|
1004
|
+
break;
|
|
1005
|
+
lastDomainHeadId = last._id;
|
|
1006
|
+
}
|
|
1007
|
+
const publicHead = await this.readPublicHead(storageKeyArg);
|
|
1008
|
+
if (publicHead)
|
|
1009
|
+
await this.deletePublicHead(lease, publicHead, storageKeyArg);
|
|
1010
|
+
const migration = await this.readMigration(storageKeyArg);
|
|
1011
|
+
if (migration) {
|
|
1012
|
+
await this.commitHeadMutation({
|
|
1013
|
+
lease,
|
|
1014
|
+
collection: FlexMigrationModel.collection.mongoDbCollection,
|
|
1015
|
+
current: migration,
|
|
1016
|
+
next: null,
|
|
1017
|
+
selector: {
|
|
1018
|
+
_id: migration._id,
|
|
1019
|
+
id: migration.id,
|
|
1020
|
+
controllerId: this.controllerId,
|
|
1021
|
+
storageKey: storageKeyArg,
|
|
1022
|
+
_smartdataRevision: smartRevisionSelector(migration),
|
|
1023
|
+
},
|
|
1024
|
+
readCurrent: (options) => this.readMigration(storageKeyArg, options),
|
|
1025
|
+
project: migrationBody,
|
|
1026
|
+
targetName: `migration:${migration.id}`,
|
|
1027
|
+
});
|
|
1028
|
+
}
|
|
1029
|
+
const legacyRaw = await FlexHeadModel.collection.mongoDbCollection.findOne({
|
|
1030
|
+
id: flexHeadId(this.controllerId, storageKeyArg),
|
|
1031
|
+
controllerId: this.controllerId,
|
|
1032
|
+
storageKey: storageKeyArg,
|
|
1033
|
+
});
|
|
1034
|
+
if (legacyRaw) {
|
|
1035
|
+
await this.commitHeadMutation({
|
|
1036
|
+
lease,
|
|
1037
|
+
collection: FlexHeadModel.collection.mongoDbCollection,
|
|
1038
|
+
current: legacyRaw,
|
|
1039
|
+
next: null,
|
|
1040
|
+
selector: {
|
|
1041
|
+
_id: legacyRaw._id,
|
|
1042
|
+
id: flexHeadId(this.controllerId, storageKeyArg),
|
|
1043
|
+
controllerId: this.controllerId,
|
|
1044
|
+
storageKey: storageKeyArg,
|
|
1045
|
+
_smartdataRevision: smartRevisionSelector(legacyRaw),
|
|
1046
|
+
},
|
|
1047
|
+
readCurrent: async (options) => await FlexHeadModel.collection.mongoDbCollection.findOne({
|
|
1048
|
+
id: flexHeadId(this.controllerId, storageKeyArg),
|
|
1049
|
+
}, options),
|
|
1050
|
+
project: (value) => value,
|
|
1051
|
+
targetName: `legacy:${storageKeyArg}`,
|
|
1052
|
+
});
|
|
1053
|
+
}
|
|
1054
|
+
await this.deleteScopeRecords(lease, storageKeyArg);
|
|
1055
|
+
const remaining = await Promise.all([
|
|
1056
|
+
FlexDomainHeadModel.exact.count({ controllerId: this.controllerId, storageKey: storageKeyArg }),
|
|
1057
|
+
FlexPublicHeadModel.exact.count({ controllerId: this.controllerId, storageKey: storageKeyArg }),
|
|
1058
|
+
FlexMigrationModel.exact.count({ controllerId: this.controllerId, storageKey: storageKeyArg }),
|
|
1059
|
+
FlexHeadModel.collection.mongoDbCollection.countDocuments({
|
|
1060
|
+
controllerId: this.controllerId,
|
|
1061
|
+
storageKey: storageKeyArg,
|
|
1062
|
+
}),
|
|
1063
|
+
]);
|
|
1064
|
+
if (remaining.some((count) => count !== 0)) {
|
|
1065
|
+
throw new plugins.smartdata.SmartdataExactPersistenceError('ambiguous_write', 'Flex scope purge could not confirm all head deletions.');
|
|
1066
|
+
}
|
|
1067
|
+
await this.releaseHeldLease(lease);
|
|
1068
|
+
});
|
|
1069
|
+
}
|
|
1070
|
+
async reconcileOrphans(nowArg = Date.now(), abortSignalArg) {
|
|
1071
|
+
await this.init();
|
|
1072
|
+
abortSignalArg?.throwIfAborted();
|
|
1073
|
+
const cutoff = new Date(nowArg - flexOrphanGraceMs).toISOString();
|
|
1074
|
+
await this.reconcileCandidateOrphans('private', cutoff, abortSignalArg);
|
|
1075
|
+
await this.reconcileCandidateOrphans('public', cutoff, abortSignalArg);
|
|
1076
|
+
await this.reconcileCandidateOrphans('projectionSource', cutoff, abortSignalArg);
|
|
1077
|
+
}
|
|
1078
|
+
async close() {
|
|
1079
|
+
if (this.closeComplete)
|
|
1080
|
+
return;
|
|
1081
|
+
if (this.closePromise)
|
|
1082
|
+
return this.closePromise;
|
|
1083
|
+
const closePromise = (async () => {
|
|
1084
|
+
const errors = [];
|
|
1085
|
+
this.closed = true;
|
|
1086
|
+
for (const controller of this.leaseTransitionAbortControllers) {
|
|
1087
|
+
controller.abort(new Error('The Flex store is closing.'));
|
|
1088
|
+
}
|
|
1089
|
+
this.maintenanceOpen = false;
|
|
1090
|
+
this.maintenanceAbortController.abort(new Error('The Flex store is closing.'));
|
|
1091
|
+
if (this.orphanMaintenanceTimer) {
|
|
1092
|
+
clearTimeout(this.orphanMaintenanceTimer);
|
|
1093
|
+
this.orphanMaintenanceTimer = undefined;
|
|
1094
|
+
}
|
|
1095
|
+
if (this.orphanMaintenanceTask) {
|
|
1096
|
+
try {
|
|
1097
|
+
await waitForFlexStoreDeadline(this.orphanMaintenanceTask, this.closeDrainTimeoutMs, 'Flex orphan maintenance did not stop before the close deadline.');
|
|
1098
|
+
}
|
|
1099
|
+
catch (errorArg) {
|
|
1100
|
+
errors.push(errorArg);
|
|
1101
|
+
}
|
|
1102
|
+
}
|
|
1103
|
+
try {
|
|
1104
|
+
await waitForFlexStoreDeadline(Promise.allSettled([...this.storageQueues.values()]), this.closeDrainTimeoutMs, 'Flex storage operations did not drain before the close deadline.');
|
|
1105
|
+
}
|
|
1106
|
+
catch (errorArg) {
|
|
1107
|
+
errors.push(errorArg);
|
|
1108
|
+
for (const controller of this.leaseTransitionAbortControllers) {
|
|
1109
|
+
controller.abort(errorArg);
|
|
1110
|
+
}
|
|
1111
|
+
}
|
|
1112
|
+
this.heartbeatsOpen = false;
|
|
1113
|
+
if (this.leaseHeartbeatTimer) {
|
|
1114
|
+
clearInterval(this.leaseHeartbeatTimer);
|
|
1115
|
+
this.leaseHeartbeatTimer = undefined;
|
|
1116
|
+
}
|
|
1117
|
+
this.agentEventStores.clear();
|
|
1118
|
+
this.jobStores.clear();
|
|
1119
|
+
const releaseResults = await Promise.allSettled([...this.heldLeases.values()].map((lease) => this.releaseHeldLease(lease, this.closeDrainTimeoutMs)));
|
|
1120
|
+
errors.push(...releaseResults
|
|
1121
|
+
.filter((result) => result.status === 'rejected')
|
|
1122
|
+
.map((result) => result.reason));
|
|
1123
|
+
if (errors.length > 0)
|
|
1124
|
+
throw new AggregateError(errors, 'Flex store close failed.');
|
|
1125
|
+
this.closeComplete = true;
|
|
1126
|
+
})();
|
|
1127
|
+
this.closePromise = closePromise;
|
|
1128
|
+
try {
|
|
1129
|
+
await closePromise;
|
|
1130
|
+
}
|
|
1131
|
+
finally {
|
|
1132
|
+
if (!this.closeComplete && this.closePromise === closePromise)
|
|
1133
|
+
this.closePromise = undefined;
|
|
1134
|
+
}
|
|
1135
|
+
}
|
|
1136
|
+
async loadScope(storageKeyArg) {
|
|
1137
|
+
return this.runStorage(storageKeyArg, async () => (await this.loadDomainDirect({ storageKey: storageKeyArg, domain: 'scope' }, (value) => this.validateScopeSnapshot(value)))?.snapshot);
|
|
1138
|
+
}
|
|
1139
|
+
async saveScope(storageKeyArg, snapshotArg, expectedRevisionArg, publishPublicProjectionArg = true) {
|
|
1140
|
+
assertExpectedNextRevision(snapshotArg.revision, expectedRevisionArg);
|
|
1141
|
+
const snapshot = await this.validateScopeSnapshot(snapshotArg);
|
|
1142
|
+
await this.runStorage(storageKeyArg, async (lease) => {
|
|
1143
|
+
await this.saveDomain(lease, { storageKey: storageKeyArg, domain: 'scope' }, snapshot, expectedRevisionArg, (actual) => new plugins.flexharness.FlexHarnessStoreConflictError(storageKeyArg, expectedRevisionArg, actual));
|
|
1144
|
+
if (!publishPublicProjectionArg)
|
|
1145
|
+
return;
|
|
1146
|
+
try {
|
|
1147
|
+
await this.publishPublicProjection(storageKeyArg, lease);
|
|
1148
|
+
}
|
|
1149
|
+
catch (errorArg) {
|
|
1150
|
+
throw new plugins.flexharness.FlexHarnessStoreCommitUncertainError(flexPublicHeadId(this.controllerId, storageKeyArg), 'write', { cause: errorArg });
|
|
1151
|
+
}
|
|
1152
|
+
});
|
|
1153
|
+
}
|
|
1154
|
+
async loadProjection(storageKeyArg, sessionIdArg) {
|
|
1155
|
+
assertIdentifier(sessionIdArg, 'sessionId');
|
|
1156
|
+
return this.runStorage(storageKeyArg, async () => (await this.loadDomainDirect({ storageKey: storageKeyArg, domain: 'projection', sessionId: sessionIdArg }, (value) => this.validateProjectionSnapshot(value, sessionIdArg)))?.snapshot);
|
|
1157
|
+
}
|
|
1158
|
+
async saveProjection(storageKeyArg, sessionIdArg, snapshotArg, expectedRevisionArg, publishPublicProjectionArg = true) {
|
|
1159
|
+
assertIdentifier(sessionIdArg, 'sessionId');
|
|
1160
|
+
assertExpectedNextRevision(snapshotArg.revision, expectedRevisionArg);
|
|
1161
|
+
const snapshot = await this.validateProjectionSnapshot(snapshotArg, sessionIdArg);
|
|
1162
|
+
await this.runStorage(storageKeyArg, async (lease) => {
|
|
1163
|
+
let visibleSourceChanged = true;
|
|
1164
|
+
await this.saveDomain(lease, { storageKey: storageKeyArg, domain: 'projection', sessionId: sessionIdArg }, snapshot, expectedRevisionArg, (actual) => new plugins.flexharness.FlexHarnessStoreConflictError(providerKey(storageKeyArg, sessionIdArg), expectedRevisionArg, actual), undefined, undefined, async (preparation, current) => {
|
|
1165
|
+
const source = createProjectionSource(this.controllerId, storageKeyArg, sessionIdArg, snapshot, preparation);
|
|
1166
|
+
if (current?.projectionSource?.orderVersion === 1
|
|
1167
|
+
&& current.projectionSource.visibleDigest === source.manifest.visibleDigest) {
|
|
1168
|
+
await this.loadProjectionSource(current);
|
|
1169
|
+
visibleSourceChanged = false;
|
|
1170
|
+
return current.projectionSource;
|
|
1171
|
+
}
|
|
1172
|
+
await this.writeAndVerifyProjectionSource(source);
|
|
1173
|
+
return source.manifest;
|
|
1174
|
+
});
|
|
1175
|
+
if (!visibleSourceChanged || !publishPublicProjectionArg)
|
|
1176
|
+
return;
|
|
1177
|
+
try {
|
|
1178
|
+
await this.publishPublicProjection(storageKeyArg, lease);
|
|
1179
|
+
}
|
|
1180
|
+
catch (errorArg) {
|
|
1181
|
+
throw new plugins.flexharness.FlexHarnessStoreCommitUncertainError(flexPublicHeadId(this.controllerId, storageKeyArg), 'write', { cause: errorArg });
|
|
1182
|
+
}
|
|
1183
|
+
});
|
|
1184
|
+
}
|
|
1185
|
+
async deleteProjection(storageKeyArg, sessionIdArg) {
|
|
1186
|
+
assertIdentifier(sessionIdArg, 'sessionId');
|
|
1187
|
+
await this.runStorage(storageKeyArg, async (lease) => {
|
|
1188
|
+
const identity = {
|
|
1189
|
+
storageKey: storageKeyArg,
|
|
1190
|
+
domain: 'projection',
|
|
1191
|
+
sessionId: sessionIdArg,
|
|
1192
|
+
};
|
|
1193
|
+
const head = await this.readDomainHead(identity);
|
|
1194
|
+
if (head)
|
|
1195
|
+
await this.deleteDomainHead(lease, head, identity);
|
|
1196
|
+
try {
|
|
1197
|
+
await this.publishPublicProjection(storageKeyArg, lease);
|
|
1198
|
+
}
|
|
1199
|
+
catch (errorArg) {
|
|
1200
|
+
throw new plugins.flexharness.FlexHarnessStoreCommitUncertainError(flexPublicHeadId(this.controllerId, storageKeyArg), 'write', { cause: errorArg });
|
|
1201
|
+
}
|
|
1202
|
+
});
|
|
1203
|
+
}
|
|
1204
|
+
async loadPermission(storageKeyArg, sessionIdArg) {
|
|
1205
|
+
assertIdentifier(sessionIdArg, 'sessionId');
|
|
1206
|
+
return this.runStorage(storageKeyArg, async () => (await this.loadDomainDirect({ storageKey: storageKeyArg, domain: 'permission', sessionId: sessionIdArg }, (value) => this.validatePermissionSnapshot(value)))?.snapshot);
|
|
1207
|
+
}
|
|
1208
|
+
async savePermission(storageKeyArg, sessionIdArg, snapshotArg, expectedRevisionArg) {
|
|
1209
|
+
assertIdentifier(sessionIdArg, 'sessionId');
|
|
1210
|
+
assertExpectedNextRevision(snapshotArg.revision, expectedRevisionArg);
|
|
1211
|
+
const snapshot = await this.validatePermissionSnapshot(snapshotArg);
|
|
1212
|
+
await this.runStorage(storageKeyArg, async (lease) => {
|
|
1213
|
+
await this.saveDomain(lease, { storageKey: storageKeyArg, domain: 'permission', sessionId: sessionIdArg }, snapshot, expectedRevisionArg, (actual) => new plugins.flexharness.FlexHarnessStoreConflictError(providerKey(storageKeyArg, sessionIdArg), expectedRevisionArg, actual));
|
|
1214
|
+
});
|
|
1215
|
+
}
|
|
1216
|
+
async deletePermission(storageKeyArg, sessionIdArg) {
|
|
1217
|
+
assertIdentifier(sessionIdArg, 'sessionId');
|
|
1218
|
+
await this.runStorage(storageKeyArg, async (lease) => {
|
|
1219
|
+
const identity = {
|
|
1220
|
+
storageKey: storageKeyArg,
|
|
1221
|
+
domain: 'permission',
|
|
1222
|
+
sessionId: sessionIdArg,
|
|
1223
|
+
};
|
|
1224
|
+
const head = await this.readDomainHead(identity);
|
|
1225
|
+
if (head)
|
|
1226
|
+
await this.deleteDomainHead(lease, head, identity);
|
|
1227
|
+
});
|
|
1228
|
+
}
|
|
1229
|
+
async getAgentEventStore(storageKeyArg, sessionIdArg) {
|
|
1230
|
+
assertIdentifier(sessionIdArg, 'sessionId');
|
|
1231
|
+
return this.runStorage(storageKeyArg, async () => {
|
|
1232
|
+
const key = providerKey(storageKeyArg, sessionIdArg);
|
|
1233
|
+
const existing = this.agentEventStores.get(key);
|
|
1234
|
+
if (existing)
|
|
1235
|
+
return existing;
|
|
1236
|
+
const wrapper = {
|
|
1237
|
+
eventSchemaVersion: 2,
|
|
1238
|
+
load: (sessionId) => this.loadAgentEventSnapshot(storageKeyArg, sessionIdArg, sessionId),
|
|
1239
|
+
save: (sessionId, events, expectedRevision) => this.saveAgentEventSnapshot(storageKeyArg, sessionIdArg, sessionId, events, expectedRevision),
|
|
1240
|
+
archive: (archive) => this.saveAgentEventArchive(storageKeyArg, sessionIdArg, archive),
|
|
1241
|
+
loadArchive: (sessionId, archiveId) => this.loadAgentEventArchive(storageKeyArg, sessionIdArg, sessionId, archiveId),
|
|
1242
|
+
};
|
|
1243
|
+
this.agentEventStores.set(key, wrapper);
|
|
1244
|
+
return wrapper;
|
|
1245
|
+
});
|
|
1246
|
+
}
|
|
1247
|
+
assertBoundSession(boundSessionIdArg, requestedSessionIdArg) {
|
|
1248
|
+
if (boundSessionIdArg !== requestedSessionIdArg) {
|
|
1249
|
+
throw new plugins.flexharness.FlexHarnessStoreFormatError(`Store is bound to session "${boundSessionIdArg}", not "${requestedSessionIdArg}".`);
|
|
1250
|
+
}
|
|
1251
|
+
}
|
|
1252
|
+
async loadAgentEventSnapshot(storageKeyArg, boundSessionIdArg, sessionIdArg) {
|
|
1253
|
+
this.assertBoundSession(boundSessionIdArg, sessionIdArg);
|
|
1254
|
+
return this.runStorage(storageKeyArg, async () => (await this.loadDomainDirect({ storageKey: storageKeyArg, domain: 'agentEvents', sessionId: sessionIdArg }, (value) => this.validateAgentEventSnapshot(value, sessionIdArg)))?.snapshot);
|
|
1255
|
+
}
|
|
1256
|
+
async saveAgentEventSnapshot(storageKeyArg, boundSessionIdArg, sessionIdArg, eventsArg, expectedRevisionArg) {
|
|
1257
|
+
this.assertBoundSession(boundSessionIdArg, sessionIdArg);
|
|
1258
|
+
assertExpectedNextRevision(expectedRevisionArg + 1, expectedRevisionArg);
|
|
1259
|
+
const snapshot = this.validateAgentEventSnapshot({
|
|
1260
|
+
schemaVersion: 2,
|
|
1261
|
+
sessionId: sessionIdArg,
|
|
1262
|
+
revision: expectedRevisionArg + 1,
|
|
1263
|
+
updatedAt: eventsArg.reduce((latest, event) => Math.max(latest, event.timestamp), 0),
|
|
1264
|
+
events: cloneJson([...eventsArg], '$events'),
|
|
1265
|
+
}, sessionIdArg);
|
|
1266
|
+
await this.runStorage(storageKeyArg, async (lease) => {
|
|
1267
|
+
await this.saveDomain(lease, { storageKey: storageKeyArg, domain: 'agentEvents', sessionId: sessionIdArg }, snapshot, expectedRevisionArg, (actual) => new plugins.smartagent.AgentEventStoreConflictError(sessionIdArg, expectedRevisionArg, actual));
|
|
1268
|
+
});
|
|
1269
|
+
return snapshot.revision;
|
|
1270
|
+
}
|
|
1271
|
+
async saveAgentEventArchive(storageKeyArg, boundSessionIdArg, archiveArg) {
|
|
1272
|
+
this.assertBoundSession(boundSessionIdArg, archiveArg.sessionId);
|
|
1273
|
+
assertIdentifier(archiveArg.archiveId, 'archiveId');
|
|
1274
|
+
const archive = this.validateAgentEventArchive(cloneJson(archiveArg, '$archive'), boundSessionIdArg, archiveArg.archiveId);
|
|
1275
|
+
await this.runStorage(storageKeyArg, async (lease) => {
|
|
1276
|
+
const identity = {
|
|
1277
|
+
storageKey: storageKeyArg,
|
|
1278
|
+
domain: 'agentArchive',
|
|
1279
|
+
sessionId: boundSessionIdArg,
|
|
1280
|
+
archiveId: archive.archiveId,
|
|
1281
|
+
};
|
|
1282
|
+
const current = await this.loadDomainDirect(identity, (value) => this.validateAgentEventArchive(value, boundSessionIdArg, archive.archiveId));
|
|
1283
|
+
if (current) {
|
|
1284
|
+
if (canonicalJson(current.snapshot) !== canonicalJson(archive)) {
|
|
1285
|
+
throw new Error(`Archive "${archive.archiveId}" already exists with different content.`);
|
|
1286
|
+
}
|
|
1287
|
+
return;
|
|
1288
|
+
}
|
|
1289
|
+
try {
|
|
1290
|
+
await this.saveDomain(lease, identity, archive, 0, () => new Error(`Archive "${archive.archiveId}" already exists.`), 1);
|
|
1291
|
+
}
|
|
1292
|
+
catch (errorArg) {
|
|
1293
|
+
const reconciled = await this.loadDomainDirect(identity, (value) => this.validateAgentEventArchive(value, boundSessionIdArg, archive.archiveId));
|
|
1294
|
+
if (reconciled && canonicalJson(reconciled.snapshot) === canonicalJson(archive))
|
|
1295
|
+
return;
|
|
1296
|
+
throw errorArg;
|
|
1297
|
+
}
|
|
1298
|
+
});
|
|
1299
|
+
}
|
|
1300
|
+
async loadAgentEventArchive(storageKeyArg, boundSessionIdArg, sessionIdArg, archiveIdArg) {
|
|
1301
|
+
this.assertBoundSession(boundSessionIdArg, sessionIdArg);
|
|
1302
|
+
assertIdentifier(archiveIdArg, 'archiveId');
|
|
1303
|
+
return this.runStorage(storageKeyArg, async () => (await this.loadDomainDirect({
|
|
1304
|
+
storageKey: storageKeyArg,
|
|
1305
|
+
domain: 'agentArchive',
|
|
1306
|
+
sessionId: sessionIdArg,
|
|
1307
|
+
archiveId: archiveIdArg,
|
|
1308
|
+
}, (value) => this.validateAgentEventArchive(value, sessionIdArg, archiveIdArg)))?.snapshot);
|
|
1309
|
+
}
|
|
1310
|
+
async deleteAgentEventSession(storageKeyArg, sessionIdArg) {
|
|
1311
|
+
assertIdentifier(sessionIdArg, 'sessionId');
|
|
1312
|
+
await this.runStorage(storageKeyArg, async (lease) => {
|
|
1313
|
+
let lastId;
|
|
1314
|
+
while (true) {
|
|
1315
|
+
const heads = await this.readDomainHeadPage({
|
|
1316
|
+
controllerId: this.controllerId,
|
|
1317
|
+
storageKey: storageKeyArg,
|
|
1318
|
+
sessionId: sessionIdArg,
|
|
1319
|
+
domain: { $in: ['agentEvents', 'agentArchive'] },
|
|
1320
|
+
}, lastId);
|
|
1321
|
+
for (const head of heads) {
|
|
1322
|
+
const identity = {
|
|
1323
|
+
storageKey: storageKeyArg,
|
|
1324
|
+
domain: head.domain,
|
|
1325
|
+
sessionId: sessionIdArg,
|
|
1326
|
+
...(head.archiveId !== undefined ? { archiveId: head.archiveId } : {}),
|
|
1327
|
+
};
|
|
1328
|
+
this.assertDomainHeadIdentity(head, identity);
|
|
1329
|
+
await this.deleteDomainHead(lease, head, identity);
|
|
1330
|
+
}
|
|
1331
|
+
const last = heads.at(-1);
|
|
1332
|
+
if (!last || heads.length < flexMaintenancePageLimit)
|
|
1333
|
+
break;
|
|
1334
|
+
lastId = last._id;
|
|
1335
|
+
}
|
|
1336
|
+
this.agentEventStores.delete(providerKey(storageKeyArg, sessionIdArg));
|
|
1337
|
+
});
|
|
1338
|
+
}
|
|
1339
|
+
async getJobStore(storageKeyArg, sessionIdArg) {
|
|
1340
|
+
assertIdentifier(sessionIdArg, 'sessionId');
|
|
1341
|
+
return this.runStorage(storageKeyArg, async () => {
|
|
1342
|
+
const key = providerKey(storageKeyArg, sessionIdArg);
|
|
1343
|
+
const existing = this.jobStores.get(key);
|
|
1344
|
+
if (existing)
|
|
1345
|
+
return existing;
|
|
1346
|
+
const wrapper = {
|
|
1347
|
+
load: (abortSignal) => this.loadJobSnapshot(storageKeyArg, sessionIdArg, abortSignal),
|
|
1348
|
+
save: (jobs, expectedRevision, abortSignal) => this.saveJobSnapshot(storageKeyArg, sessionIdArg, jobs, expectedRevision, abortSignal),
|
|
1349
|
+
};
|
|
1350
|
+
this.jobStores.set(key, wrapper);
|
|
1351
|
+
return wrapper;
|
|
1352
|
+
});
|
|
1353
|
+
}
|
|
1354
|
+
async loadJobSnapshot(storageKeyArg, sessionIdArg, abortSignalArg) {
|
|
1355
|
+
abortSignalArg?.throwIfAborted();
|
|
1356
|
+
const result = await this.runStorage(storageKeyArg, async () => {
|
|
1357
|
+
abortSignalArg?.throwIfAborted();
|
|
1358
|
+
const loaded = await this.loadDomainDirect({ storageKey: storageKeyArg, domain: 'jobs', sessionId: sessionIdArg }, (value) => this.validateToolJobSnapshot(value), abortSignalArg);
|
|
1359
|
+
abortSignalArg?.throwIfAborted();
|
|
1360
|
+
return loaded?.snapshot;
|
|
1361
|
+
});
|
|
1362
|
+
abortSignalArg?.throwIfAborted();
|
|
1363
|
+
return result;
|
|
1364
|
+
}
|
|
1365
|
+
async saveJobSnapshot(storageKeyArg, sessionIdArg, jobsArg, expectedRevisionArg, abortSignalArg) {
|
|
1366
|
+
abortSignalArg?.throwIfAborted();
|
|
1367
|
+
assertExpectedNextRevision(expectedRevisionArg + 1, expectedRevisionArg);
|
|
1368
|
+
const snapshot = this.validateToolJobSnapshot({
|
|
1369
|
+
schemaVersion: 1,
|
|
1370
|
+
revision: expectedRevisionArg + 1,
|
|
1371
|
+
updatedAt: Date.now(),
|
|
1372
|
+
jobs: cloneJson([...jobsArg], '$jobs'),
|
|
1373
|
+
});
|
|
1374
|
+
await this.runStorage(storageKeyArg, async (lease) => {
|
|
1375
|
+
abortSignalArg?.throwIfAborted();
|
|
1376
|
+
await this.saveDomain(lease, { storageKey: storageKeyArg, domain: 'jobs', sessionId: sessionIdArg }, snapshot, expectedRevisionArg, (actual) => new plugins.smartagentTools.ToolJobStoreConflictError(expectedRevisionArg, actual), snapshot.revision, abortSignalArg);
|
|
1377
|
+
});
|
|
1378
|
+
return snapshot.revision;
|
|
1379
|
+
}
|
|
1380
|
+
async deleteJobSession(storageKeyArg, sessionIdArg) {
|
|
1381
|
+
assertIdentifier(sessionIdArg, 'sessionId');
|
|
1382
|
+
await this.runStorage(storageKeyArg, async (lease) => {
|
|
1383
|
+
const identity = {
|
|
1384
|
+
storageKey: storageKeyArg,
|
|
1385
|
+
domain: 'jobs',
|
|
1386
|
+
sessionId: sessionIdArg,
|
|
1387
|
+
};
|
|
1388
|
+
const head = await this.readDomainHead(identity);
|
|
1389
|
+
if (head)
|
|
1390
|
+
await this.deleteDomainHead(lease, head, identity);
|
|
1391
|
+
this.jobStores.delete(providerKey(storageKeyArg, sessionIdArg));
|
|
1392
|
+
});
|
|
1393
|
+
}
|
|
1394
|
+
async validateScopeSnapshot(valueArg) {
|
|
1395
|
+
const value = valueArg;
|
|
1396
|
+
if (!Number.isSafeInteger(value?.revision) || value.revision < 0) {
|
|
1397
|
+
throw new plugins.flexharness.FlexHarnessStoreFormatError('Invalid scope snapshot revision.');
|
|
1398
|
+
}
|
|
1399
|
+
const stores = new plugins.flexharness.InMemoryFlexHarnessStores();
|
|
1400
|
+
await stores.scopes.save('__validation__', { ...value, revision: 1 }, 0);
|
|
1401
|
+
return cloneJson(value);
|
|
1402
|
+
}
|
|
1403
|
+
async validateProjectionSnapshot(valueArg, sessionIdArg) {
|
|
1404
|
+
const value = valueArg;
|
|
1405
|
+
if (!Number.isSafeInteger(value?.revision) || value.revision < 0) {
|
|
1406
|
+
throw new plugins.flexharness.FlexHarnessStoreFormatError('Invalid projection snapshot revision.');
|
|
1407
|
+
}
|
|
1408
|
+
const stores = new plugins.flexharness.InMemoryFlexHarnessStores();
|
|
1409
|
+
await stores.projections.save('__validation__', sessionIdArg, { ...value, revision: 1 }, 0);
|
|
1410
|
+
return cloneJson(value);
|
|
1411
|
+
}
|
|
1412
|
+
async validatePermissionSnapshot(valueArg) {
|
|
1413
|
+
const value = valueArg;
|
|
1414
|
+
if (!Number.isSafeInteger(value?.revision) || value.revision < 0) {
|
|
1415
|
+
throw new plugins.flexharness.FlexHarnessStoreFormatError('Invalid permission snapshot revision.');
|
|
1416
|
+
}
|
|
1417
|
+
const stores = new plugins.flexharness.InMemoryFlexHarnessStores();
|
|
1418
|
+
await stores.permissions.save('__validation__', '__validation__', { ...value, revision: 1 }, 0);
|
|
1419
|
+
return cloneJson(value);
|
|
1420
|
+
}
|
|
1421
|
+
validateAgentEventSnapshot(valueArg, sessionIdArg) {
|
|
1422
|
+
try {
|
|
1423
|
+
return cloneJson(plugins.smartagent.validateAgentEventSnapshotV2(valueArg, sessionIdArg));
|
|
1424
|
+
}
|
|
1425
|
+
catch (errorArg) {
|
|
1426
|
+
if (errorArg instanceof plugins.flexharness.FlexHarnessStoreFormatError)
|
|
1427
|
+
throw errorArg;
|
|
1428
|
+
throw new plugins.flexharness.FlexHarnessStoreFormatError('Invalid schema-2 Agent event snapshot.', { cause: errorArg });
|
|
1429
|
+
}
|
|
1430
|
+
}
|
|
1431
|
+
validateAgentEventArchive(valueArg, sessionIdArg, archiveIdArg) {
|
|
1432
|
+
try {
|
|
1433
|
+
return cloneJson(plugins.smartagent.validateAgentEventArchiveV2(valueArg, sessionIdArg, archiveIdArg));
|
|
1434
|
+
}
|
|
1435
|
+
catch (errorArg) {
|
|
1436
|
+
if (errorArg instanceof plugins.flexharness.FlexHarnessStoreFormatError)
|
|
1437
|
+
throw errorArg;
|
|
1438
|
+
throw new plugins.flexharness.FlexHarnessStoreFormatError('Invalid schema-2 Agent event archive.', { cause: errorArg });
|
|
1439
|
+
}
|
|
1440
|
+
}
|
|
1441
|
+
validateToolJobSnapshot(valueArg) {
|
|
1442
|
+
const value = cloneJson(valueArg);
|
|
1443
|
+
if (!value
|
|
1444
|
+
|| value.schemaVersion !== 1
|
|
1445
|
+
|| !Number.isSafeInteger(value.revision)
|
|
1446
|
+
|| (value.revision ?? -1) < 1
|
|
1447
|
+
|| !Number.isSafeInteger(value.updatedAt)
|
|
1448
|
+
|| (value.updatedAt ?? -1) < 0
|
|
1449
|
+
|| !Array.isArray(value.jobs)
|
|
1450
|
+
|| Object.keys(value).some((key) => !['schemaVersion', 'revision', 'updatedAt', 'jobs'].includes(key))) {
|
|
1451
|
+
throw new plugins.flexharness.FlexHarnessStoreFormatError('Invalid tool job snapshot.');
|
|
1452
|
+
}
|
|
1453
|
+
const executionIds = new Set();
|
|
1454
|
+
for (const job of value.jobs) {
|
|
1455
|
+
if (!job
|
|
1456
|
+
|| typeof job !== 'object'
|
|
1457
|
+
|| Array.isArray(job)
|
|
1458
|
+
|| typeof job.executionId !== 'string'
|
|
1459
|
+
|| job.executionId.length === 0
|
|
1460
|
+
|| executionIds.has(job.executionId)
|
|
1461
|
+
|| typeof job.type !== 'string'
|
|
1462
|
+
|| job.type.length === 0
|
|
1463
|
+
|| !['running', 'finished', 'failed', 'aborted'].includes(job.state)
|
|
1464
|
+
|| Object.keys(job).some((key) => ![
|
|
1465
|
+
'executionId', 'type', 'state', 'request', 'exitCode', 'stdout', 'stderr', 'signal',
|
|
1466
|
+
'startedAt', 'updatedAt', 'finishedAt',
|
|
1467
|
+
].includes(key))) {
|
|
1468
|
+
throw new plugins.flexharness.FlexHarnessStoreFormatError('Invalid tool job state.');
|
|
1469
|
+
}
|
|
1470
|
+
executionIds.add(job.executionId);
|
|
1471
|
+
if ((job.exitCode !== undefined && job.exitCode !== null && !Number.isSafeInteger(job.exitCode))
|
|
1472
|
+
|| (job.stdout !== undefined && typeof job.stdout !== 'string')
|
|
1473
|
+
|| (job.stderr !== undefined && typeof job.stderr !== 'string')
|
|
1474
|
+
|| (job.signal !== undefined && typeof job.signal !== 'string')
|
|
1475
|
+
|| [job.startedAt, job.updatedAt, job.finishedAt].some((time) => (time !== undefined && (!Number.isSafeInteger(time) || time < 0)))) {
|
|
1476
|
+
throw new plugins.flexharness.FlexHarnessStoreFormatError('Invalid tool job state values.');
|
|
1477
|
+
}
|
|
1478
|
+
if (job.request !== undefined) {
|
|
1479
|
+
const request = job.request;
|
|
1480
|
+
if (!request
|
|
1481
|
+
|| typeof request !== 'object'
|
|
1482
|
+
|| Array.isArray(request)
|
|
1483
|
+
|| typeof request.type !== 'string'
|
|
1484
|
+
|| request.type.length === 0
|
|
1485
|
+
|| Object.keys(request).some((key) => ![
|
|
1486
|
+
'type', 'command', 'cwd', 'timeoutMs', 'metadata',
|
|
1487
|
+
].includes(key))
|
|
1488
|
+
|| (request.cwd !== undefined && typeof request.cwd !== 'string')
|
|
1489
|
+
|| (request.timeoutMs !== undefined && (!Number.isSafeInteger(request.timeoutMs) || request.timeoutMs < 0))) {
|
|
1490
|
+
throw new plugins.flexharness.FlexHarnessStoreFormatError('Invalid tool job request.');
|
|
1491
|
+
}
|
|
1492
|
+
if (request.command !== undefined && (!request.command
|
|
1493
|
+
|| typeof request.command !== 'object'
|
|
1494
|
+
|| Array.isArray(request.command)
|
|
1495
|
+
|| typeof request.command.executable !== 'string'
|
|
1496
|
+
|| request.command.executable.length === 0
|
|
1497
|
+
|| !Array.isArray(request.command.args)
|
|
1498
|
+
|| !request.command.args.every((argument) => typeof argument === 'string')
|
|
1499
|
+
|| Object.keys(request.command).some((key) => !['executable', 'args'].includes(key)))) {
|
|
1500
|
+
throw new plugins.flexharness.FlexHarnessStoreFormatError('Invalid tool job command.');
|
|
1501
|
+
}
|
|
1502
|
+
if (request.metadata !== undefined && (!request.metadata
|
|
1503
|
+
|| typeof request.metadata !== 'object'
|
|
1504
|
+
|| Array.isArray(request.metadata))) {
|
|
1505
|
+
throw new plugins.flexharness.FlexHarnessStoreFormatError('Invalid tool job metadata.');
|
|
1506
|
+
}
|
|
1507
|
+
}
|
|
1508
|
+
}
|
|
1509
|
+
return value;
|
|
1510
|
+
}
|
|
1511
|
+
async saveDomain(leaseArg, identityArg, snapshotArg, expectedRevisionArg, conflictArg, revisionArg = snapshotArg.revision, abortSignalArg, prepareCandidateArg) {
|
|
1512
|
+
if (!Number.isSafeInteger(revisionArg) || Number(revisionArg) < 1) {
|
|
1513
|
+
throw new plugins.flexharness.FlexHarnessStoreFormatError('Invalid domain revision.');
|
|
1514
|
+
}
|
|
1515
|
+
const revision = Number(revisionArg);
|
|
1516
|
+
const current = await this.readDomainHead(identityArg);
|
|
1517
|
+
const actualRevision = current?.revision ?? 0;
|
|
1518
|
+
if (actualRevision !== expectedRevisionArg)
|
|
1519
|
+
throw conflictArg(actualRevision);
|
|
1520
|
+
abortSignalArg?.throwIfAborted();
|
|
1521
|
+
const candidateId = randomCandidateId();
|
|
1522
|
+
const createdAt = new Date().toISOString();
|
|
1523
|
+
const incarnationId = current?.incarnationId ?? randomCandidateId();
|
|
1524
|
+
const projection = createPrivateProjection(this.controllerId, identityArg.storageKey, candidateId, revision, snapshotArg, createdAt, { identity: identityArg, incarnationId });
|
|
1525
|
+
const manifest = {
|
|
1526
|
+
candidateId,
|
|
1527
|
+
revision,
|
|
1528
|
+
sha256: projection.candidate.sha256,
|
|
1529
|
+
bytes: projection.candidate.bytes,
|
|
1530
|
+
chunks: projection.candidate.chunks,
|
|
1531
|
+
};
|
|
1532
|
+
this.activeCandidateIds.add(candidateId);
|
|
1533
|
+
let committed = false;
|
|
1534
|
+
try {
|
|
1535
|
+
await this.writeAndVerifyPrivate(projection.candidate, projection.chunks, abortSignalArg);
|
|
1536
|
+
abortSignalArg?.throwIfAborted();
|
|
1537
|
+
const projectionSource = await prepareCandidateArg?.({
|
|
1538
|
+
candidateId,
|
|
1539
|
+
incarnationId,
|
|
1540
|
+
revision,
|
|
1541
|
+
createdAt,
|
|
1542
|
+
}, current);
|
|
1543
|
+
abortSignalArg?.throwIfAborted();
|
|
1544
|
+
const next = {
|
|
1545
|
+
id: flexDomainHeadId(this.controllerId, identityArg.storageKey, identityArg.domain, identityArg.sessionId, identityArg.archiveId),
|
|
1546
|
+
controllerId: this.controllerId,
|
|
1547
|
+
storageKey: identityArg.storageKey,
|
|
1548
|
+
domain: identityArg.domain,
|
|
1549
|
+
incarnationId,
|
|
1550
|
+
revision,
|
|
1551
|
+
currentPrivateCandidateId: candidateId,
|
|
1552
|
+
privateCandidate: manifest,
|
|
1553
|
+
...(projectionSource === undefined ? {} : { projectionSource }),
|
|
1554
|
+
...(identityArg.sessionId !== undefined ? { sessionId: identityArg.sessionId } : {}),
|
|
1555
|
+
...(identityArg.archiveId !== undefined ? { archiveId: identityArg.archiveId } : {}),
|
|
1556
|
+
};
|
|
1557
|
+
assertFlexDomainHeadDocument(next);
|
|
1558
|
+
this.assertDomainHeadIdentity(next, identityArg);
|
|
1559
|
+
try {
|
|
1560
|
+
await this.commitDomainHead(leaseArg, current, next, identityArg);
|
|
1561
|
+
}
|
|
1562
|
+
catch (errorArg) {
|
|
1563
|
+
if (errorArg instanceof FlexHeadCasError)
|
|
1564
|
+
throw conflictArg(errorArg.actualRevision);
|
|
1565
|
+
throw errorArg;
|
|
1566
|
+
}
|
|
1567
|
+
committed = true;
|
|
1568
|
+
if (current) {
|
|
1569
|
+
await this.cleanupPrivateByCandidate(current.privateCandidate).catch(() => undefined);
|
|
1570
|
+
if (current.domain === 'projection'
|
|
1571
|
+
&& current.projectionSource?.candidateId !== projectionSource?.candidateId) {
|
|
1572
|
+
await this.cleanupProjectionSourceByCandidate(current.projectionSource.candidateId).catch(() => undefined);
|
|
1573
|
+
}
|
|
1574
|
+
}
|
|
1575
|
+
return await this.readDomainHead(identityArg) ?? (() => {
|
|
1576
|
+
throw new plugins.smartdata.SmartdataExactPersistenceError('ambiguous_write', 'Committed Flex domain head is missing on readback.');
|
|
1577
|
+
})();
|
|
1578
|
+
}
|
|
1579
|
+
finally {
|
|
1580
|
+
if (!committed)
|
|
1581
|
+
this.queueOrphanMaintenance();
|
|
1582
|
+
this.activeCandidateIds.delete(candidateId);
|
|
1583
|
+
}
|
|
1584
|
+
}
|
|
1585
|
+
async loadDomainDirect(identityArg, validateArg, abortSignalArg) {
|
|
1586
|
+
abortSignalArg?.throwIfAborted();
|
|
1587
|
+
const head = await this.readDomainHead(identityArg);
|
|
1588
|
+
if (!head)
|
|
1589
|
+
return undefined;
|
|
1590
|
+
const snapshot = await this.loadPrivateCandidate(identityArg.storageKey, head.privateCandidate, validateArg, abortSignalArg, { identity: identityArg, incarnationId: head.incarnationId });
|
|
1591
|
+
abortSignalArg?.throwIfAborted();
|
|
1592
|
+
const snapshotRevision = snapshot.revision;
|
|
1593
|
+
if (identityArg.domain !== 'agentArchive'
|
|
1594
|
+
&& snapshotRevision !== head.revision) {
|
|
1595
|
+
throw new plugins.flexharness.FlexHarnessStoreFormatError('Flex domain snapshot revision does not match its head.');
|
|
1596
|
+
}
|
|
1597
|
+
return { head, snapshot };
|
|
1598
|
+
}
|
|
1599
|
+
async readLegacyHead(storageKeyArg, optionsArg) {
|
|
1600
|
+
const expectedId = flexHeadId(this.controllerId, storageKeyArg);
|
|
1601
|
+
const raw = await FlexHeadModel.collection.mongoDbCollection.findOne({ id: expectedId }, optionsArg);
|
|
1602
|
+
const head = raw;
|
|
1603
|
+
if (!head)
|
|
1604
|
+
return null;
|
|
1605
|
+
const body = {
|
|
1606
|
+
id: head.id,
|
|
1607
|
+
controllerId: head.controllerId,
|
|
1608
|
+
storageKey: head.storageKey,
|
|
1609
|
+
revision: head.revision,
|
|
1610
|
+
currentPrivateCandidateId: head.currentPrivateCandidateId,
|
|
1611
|
+
currentPublicCandidateId: head.currentPublicCandidateId,
|
|
1612
|
+
privateCandidates: head.privateCandidates,
|
|
1613
|
+
publicCandidates: head.publicCandidates,
|
|
1614
|
+
};
|
|
1615
|
+
try {
|
|
1616
|
+
assertFlexHeadDocument(body);
|
|
1617
|
+
}
|
|
1618
|
+
catch (errorArg) {
|
|
1619
|
+
throw new plugins.flexharness.FlexHarnessStoreFormatError('Flex legacy head is invalid.', { cause: errorArg });
|
|
1620
|
+
}
|
|
1621
|
+
if (body.id !== expectedId
|
|
1622
|
+
|| body.controllerId !== this.controllerId
|
|
1623
|
+
|| body.storageKey !== storageKeyArg) {
|
|
1624
|
+
throw new plugins.flexharness.FlexHarnessStoreFormatError('Flex legacy head identity mismatch.');
|
|
1625
|
+
}
|
|
1626
|
+
return head;
|
|
1627
|
+
}
|
|
1628
|
+
async readMigration(storageKeyArg, optionsArg) {
|
|
1629
|
+
const expectedId = flexMigrationId(this.controllerId, storageKeyArg);
|
|
1630
|
+
const marker = await FlexMigrationModel.collection.mongoDbCollection.findOne({ id: expectedId }, optionsArg);
|
|
1631
|
+
if (!marker)
|
|
1632
|
+
return null;
|
|
1633
|
+
const body = migrationBody(marker);
|
|
1634
|
+
try {
|
|
1635
|
+
assertFlexMigrationDocument(body);
|
|
1636
|
+
}
|
|
1637
|
+
catch (errorArg) {
|
|
1638
|
+
throw new plugins.flexharness.FlexHarnessStoreFormatError('Flex migration marker is invalid.', { cause: errorArg });
|
|
1639
|
+
}
|
|
1640
|
+
if (body.id !== expectedId
|
|
1641
|
+
|| body.controllerId !== this.controllerId
|
|
1642
|
+
|| body.storageKey !== storageKeyArg) {
|
|
1643
|
+
throw new plugins.flexharness.FlexHarnessStoreFormatError('Flex migration marker identity mismatch.');
|
|
1644
|
+
}
|
|
1645
|
+
return marker;
|
|
1646
|
+
}
|
|
1647
|
+
async readDomainHead(identityArg, optionsArg) {
|
|
1648
|
+
const id = flexDomainHeadId(this.controllerId, identityArg.storageKey, identityArg.domain, identityArg.sessionId, identityArg.archiveId);
|
|
1649
|
+
const head = await FlexDomainHeadModel.collection.mongoDbCollection.findOne({ id }, optionsArg);
|
|
1650
|
+
if (head)
|
|
1651
|
+
this.assertDomainHeadIdentity(head, identityArg);
|
|
1652
|
+
return head;
|
|
1653
|
+
}
|
|
1654
|
+
async readDomainHeadPage(filterArg, lastIdArg) {
|
|
1655
|
+
const cursor = FlexDomainHeadModel.collection.mongoDbCollection.find({
|
|
1656
|
+
...filterArg,
|
|
1657
|
+
...(lastIdArg ? { _id: { $gt: lastIdArg } } : {}),
|
|
1658
|
+
}).sort({ _id: 1 }).limit(flexMaintenancePageLimit);
|
|
1659
|
+
try {
|
|
1660
|
+
return await cursor.toArray();
|
|
1661
|
+
}
|
|
1662
|
+
finally {
|
|
1663
|
+
await cursor.close();
|
|
1664
|
+
}
|
|
1665
|
+
}
|
|
1666
|
+
assertDomainHeadIdentity(headArg, identityArg) {
|
|
1667
|
+
const body = domainHeadBody(headArg);
|
|
1668
|
+
assertFlexDomainHeadDocument(body);
|
|
1669
|
+
if (body.id !== flexDomainHeadId(this.controllerId, identityArg.storageKey, identityArg.domain, identityArg.sessionId, identityArg.archiveId)
|
|
1670
|
+
|| body.controllerId !== this.controllerId
|
|
1671
|
+
|| body.storageKey !== identityArg.storageKey
|
|
1672
|
+
|| body.domain !== identityArg.domain
|
|
1673
|
+
|| body.sessionId !== identityArg.sessionId
|
|
1674
|
+
|| body.archiveId !== identityArg.archiveId) {
|
|
1675
|
+
throw new plugins.flexharness.FlexHarnessStoreFormatError('Flex domain head identity mismatch.');
|
|
1676
|
+
}
|
|
1677
|
+
}
|
|
1678
|
+
async commitDomainHead(leaseArg, currentArg, nextArg, identityArg) {
|
|
1679
|
+
await this.commitHeadMutation({
|
|
1680
|
+
lease: leaseArg,
|
|
1681
|
+
collection: FlexDomainHeadModel.collection.mongoDbCollection,
|
|
1682
|
+
current: currentArg,
|
|
1683
|
+
next: nextArg,
|
|
1684
|
+
selector: currentArg ? {
|
|
1685
|
+
_id: currentArg._id,
|
|
1686
|
+
id: currentArg.id,
|
|
1687
|
+
controllerId: this.controllerId,
|
|
1688
|
+
storageKey: identityArg.storageKey,
|
|
1689
|
+
domain: identityArg.domain,
|
|
1690
|
+
revision: currentArg.revision,
|
|
1691
|
+
_smartdataRevision: smartRevisionSelector(currentArg),
|
|
1692
|
+
} : { id: nextArg.id },
|
|
1693
|
+
readCurrent: (options) => this.readDomainHead(identityArg, options),
|
|
1694
|
+
project: domainHeadBody,
|
|
1695
|
+
targetName: `domain:${nextArg.id}`,
|
|
1696
|
+
});
|
|
1697
|
+
}
|
|
1698
|
+
async deleteDomainHead(leaseArg, headArg, identityArg) {
|
|
1699
|
+
await this.commitHeadMutation({
|
|
1700
|
+
lease: leaseArg,
|
|
1701
|
+
collection: FlexDomainHeadModel.collection.mongoDbCollection,
|
|
1702
|
+
current: headArg,
|
|
1703
|
+
next: null,
|
|
1704
|
+
selector: {
|
|
1705
|
+
_id: headArg._id,
|
|
1706
|
+
id: headArg.id,
|
|
1707
|
+
controllerId: this.controllerId,
|
|
1708
|
+
storageKey: identityArg.storageKey,
|
|
1709
|
+
domain: identityArg.domain,
|
|
1710
|
+
revision: headArg.revision,
|
|
1711
|
+
_smartdataRevision: smartRevisionSelector(headArg),
|
|
1712
|
+
},
|
|
1713
|
+
readCurrent: (options) => this.readDomainHead(identityArg, options),
|
|
1714
|
+
project: domainHeadBody,
|
|
1715
|
+
targetName: `domain:${headArg.id}`,
|
|
1716
|
+
});
|
|
1717
|
+
await this.cleanupPrivateByCandidate(headArg.privateCandidate).catch(() => undefined);
|
|
1718
|
+
if (headArg.domain === 'projection') {
|
|
1719
|
+
await this.cleanupProjectionSourceByCandidate(headArg.projectionSource.candidateId).catch(() => undefined);
|
|
1720
|
+
}
|
|
1721
|
+
}
|
|
1722
|
+
async loadPrivateCandidate(storageKeyArg, manifestArg, validateArg, abortSignalArg, sourceArg) {
|
|
1723
|
+
abortSignalArg?.throwIfAborted();
|
|
1724
|
+
const candidateModel = await FlexPrivateCandidateModel.getInstance({
|
|
1725
|
+
id: privateCandidateDocumentId(manifestArg.candidateId),
|
|
1726
|
+
controllerId: this.controllerId,
|
|
1727
|
+
scopeId: storageKeyArg,
|
|
1728
|
+
candidateId: manifestArg.candidateId,
|
|
1729
|
+
});
|
|
1730
|
+
if (!candidateModel) {
|
|
1731
|
+
throw new plugins.flexharness.FlexHarnessStoreFormatError('Flex private candidate is missing.');
|
|
1732
|
+
}
|
|
1733
|
+
const candidate = projectPrivateCandidate(candidateModel);
|
|
1734
|
+
assertFlexPrivateCandidateDocument(candidate);
|
|
1735
|
+
if (candidate.id !== privateCandidateDocumentId(manifestArg.candidateId)
|
|
1736
|
+
|| candidate.controllerId !== this.controllerId
|
|
1737
|
+
|| candidate.scopeId !== storageKeyArg
|
|
1738
|
+
|| candidate.candidateId !== manifestArg.candidateId
|
|
1739
|
+
|| !privateChunkManifestsEqual(candidate.chunks, manifestArg.chunks)
|
|
1740
|
+
|| candidate.sha256 !== manifestArg.sha256
|
|
1741
|
+
|| candidate.bytes !== manifestArg.bytes
|
|
1742
|
+
|| candidate.revision !== manifestArg.revision
|
|
1743
|
+
|| (sourceArg && (candidate.domain !== sourceArg.identity.domain
|
|
1744
|
+
|| candidate.incarnationId !== sourceArg.incarnationId
|
|
1745
|
+
|| candidate.sessionId !== sourceArg.identity.sessionId
|
|
1746
|
+
|| candidate.archiveId !== sourceArg.identity.archiveId))) {
|
|
1747
|
+
throw new plugins.flexharness.FlexHarnessStoreFormatError('Flex private candidate mismatch.');
|
|
1748
|
+
}
|
|
1749
|
+
const chunkModels = await FlexPrivateChunkModel.getInstances({
|
|
1750
|
+
controllerId: this.controllerId,
|
|
1751
|
+
scopeId: storageKeyArg,
|
|
1752
|
+
candidateId: manifestArg.candidateId,
|
|
1753
|
+
});
|
|
1754
|
+
if (chunkModels.length !== manifestArg.chunks.length) {
|
|
1755
|
+
throw new plugins.flexharness.FlexHarnessStoreFormatError('Flex private candidate has an unexpected chunk set.');
|
|
1756
|
+
}
|
|
1757
|
+
const chunksById = new Map(chunkModels.map((model) => [model.id, model]));
|
|
1758
|
+
const chunks = [];
|
|
1759
|
+
for (const chunkManifest of manifestArg.chunks) {
|
|
1760
|
+
abortSignalArg?.throwIfAborted();
|
|
1761
|
+
const model = chunksById.get(chunkManifest.id);
|
|
1762
|
+
if (!model) {
|
|
1763
|
+
throw new plugins.flexharness.FlexHarnessStoreFormatError('Flex private chunk is missing.');
|
|
1764
|
+
}
|
|
1765
|
+
const document = projectPrivateChunk(model);
|
|
1766
|
+
assertFlexPrivateChunkDocument(document);
|
|
1767
|
+
const bytes = Buffer.from(document.data, 'base64');
|
|
1768
|
+
if (document.id !== privateChunkDocumentId(manifestArg.candidateId, chunkManifest.index)
|
|
1769
|
+
|| bytes.toString('base64') !== document.data
|
|
1770
|
+
|| document.controllerId !== this.controllerId
|
|
1771
|
+
|| document.scopeId !== storageKeyArg
|
|
1772
|
+
|| document.candidateId !== manifestArg.candidateId
|
|
1773
|
+
|| document.revision !== manifestArg.revision
|
|
1774
|
+
|| document.createdAt !== candidate.createdAt
|
|
1775
|
+
|| (sourceArg && (document.domain !== sourceArg.identity.domain
|
|
1776
|
+
|| document.incarnationId !== sourceArg.incarnationId
|
|
1777
|
+
|| document.sessionId !== sourceArg.identity.sessionId
|
|
1778
|
+
|| document.archiveId !== sourceArg.identity.archiveId))
|
|
1779
|
+
|| document.index !== chunkManifest.index
|
|
1780
|
+
|| document.sha256 !== chunkManifest.sha256
|
|
1781
|
+
|| document.bytes !== chunkManifest.bytes
|
|
1782
|
+
|| bytes.byteLength !== chunkManifest.bytes
|
|
1783
|
+
|| sha256(bytes) !== chunkManifest.sha256) {
|
|
1784
|
+
bytes.fill(0);
|
|
1785
|
+
throw new plugins.flexharness.FlexHarnessStoreFormatError('Flex private chunk mismatch.');
|
|
1786
|
+
}
|
|
1787
|
+
chunks.push(bytes);
|
|
1788
|
+
}
|
|
1789
|
+
const complete = Buffer.concat(chunks, manifestArg.bytes);
|
|
1790
|
+
for (const chunk of chunks)
|
|
1791
|
+
chunk.fill(0);
|
|
1792
|
+
try {
|
|
1793
|
+
if (complete.byteLength !== manifestArg.bytes || sha256(complete) !== manifestArg.sha256) {
|
|
1794
|
+
throw new plugins.flexharness.FlexHarnessStoreFormatError('Flex private snapshot hash mismatch.');
|
|
1795
|
+
}
|
|
1796
|
+
let parsed;
|
|
1797
|
+
try {
|
|
1798
|
+
parsed = JSON.parse(complete.toString('utf8'));
|
|
1799
|
+
}
|
|
1800
|
+
catch (errorArg) {
|
|
1801
|
+
throw new plugins.flexharness.FlexHarnessStoreFormatError('Flex private snapshot is not JSON.', { cause: errorArg });
|
|
1802
|
+
}
|
|
1803
|
+
abortSignalArg?.throwIfAborted();
|
|
1804
|
+
try {
|
|
1805
|
+
return await validateArg(parsed);
|
|
1806
|
+
}
|
|
1807
|
+
catch (errorArg) {
|
|
1808
|
+
if (errorArg instanceof plugins.flexharness.FlexHarnessStoreFormatError)
|
|
1809
|
+
throw errorArg;
|
|
1810
|
+
throw new plugins.flexharness.FlexHarnessStoreFormatError('Flex private snapshot has an invalid schema.', { cause: errorArg });
|
|
1811
|
+
}
|
|
1812
|
+
}
|
|
1813
|
+
finally {
|
|
1814
|
+
complete.fill(0);
|
|
1815
|
+
}
|
|
1816
|
+
}
|
|
1817
|
+
async writeAndVerifyPrivate(candidateArg, chunksArg, abortSignalArg) {
|
|
1818
|
+
await insertOrdinary(FlexPrivateCandidateModel, candidateArg);
|
|
1819
|
+
abortSignalArg?.throwIfAborted();
|
|
1820
|
+
await inBatches(chunksArg, async (chunk) => {
|
|
1821
|
+
abortSignalArg?.throwIfAborted();
|
|
1822
|
+
await insertOrdinary(FlexPrivateChunkModel, chunk);
|
|
1823
|
+
abortSignalArg?.throwIfAborted();
|
|
1824
|
+
});
|
|
1825
|
+
abortSignalArg?.throwIfAborted();
|
|
1826
|
+
const storedCandidate = await FlexPrivateCandidateModel.getInstance({ id: candidateArg.id });
|
|
1827
|
+
if (!storedCandidate)
|
|
1828
|
+
throw new Error('Flex private candidate verification failed.');
|
|
1829
|
+
const projectedCandidate = projectPrivateCandidate(storedCandidate);
|
|
1830
|
+
assertFlexPrivateCandidateDocument(projectedCandidate);
|
|
1831
|
+
if (canonicalJson(projectedCandidate) !== canonicalJson(candidateArg)) {
|
|
1832
|
+
throw new Error('Flex private candidate verification failed.');
|
|
1833
|
+
}
|
|
1834
|
+
const storedChunks = await FlexPrivateChunkModel.getInstances({
|
|
1835
|
+
controllerId: candidateArg.controllerId,
|
|
1836
|
+
scopeId: candidateArg.scopeId,
|
|
1837
|
+
candidateId: candidateArg.candidateId,
|
|
1838
|
+
});
|
|
1839
|
+
if (storedChunks.length !== chunksArg.length) {
|
|
1840
|
+
throw new Error('Flex private chunk verification failed.');
|
|
1841
|
+
}
|
|
1842
|
+
const expectedById = new Map(chunksArg.map((chunk) => [chunk.id, chunk]));
|
|
1843
|
+
for (const stored of storedChunks) {
|
|
1844
|
+
abortSignalArg?.throwIfAborted();
|
|
1845
|
+
const projected = projectPrivateChunk(stored);
|
|
1846
|
+
assertFlexPrivateChunkDocument(projected);
|
|
1847
|
+
const expected = expectedById.get(projected.id);
|
|
1848
|
+
if (!expected || canonicalJson(projected) !== canonicalJson(expected)) {
|
|
1849
|
+
throw new Error('Flex private chunk verification failed.');
|
|
1850
|
+
}
|
|
1851
|
+
}
|
|
1852
|
+
}
|
|
1853
|
+
async writeAndVerifyProjectionSource(buildArg) {
|
|
1854
|
+
await insertOrdinary(FlexProjectionSourceModel, buildArg.source);
|
|
1855
|
+
await inBatches(buildArg.messages, (message) => insertOrdinary(FlexProjectionMessageRecordModel, message));
|
|
1856
|
+
const storedSource = await FlexProjectionSourceModel.getInstance({ id: buildArg.source.id });
|
|
1857
|
+
if (!storedSource)
|
|
1858
|
+
throw new Error('Flex projection source verification failed.');
|
|
1859
|
+
const source = projectProjectionSource(storedSource);
|
|
1860
|
+
assertFlexProjectionSourceDocument(source);
|
|
1861
|
+
if (canonicalJson(source) !== canonicalJson(buildArg.source)) {
|
|
1862
|
+
throw new Error('Flex projection source verification failed.');
|
|
1863
|
+
}
|
|
1864
|
+
await inBatches(buildArg.messages, async (expected) => {
|
|
1865
|
+
const stored = await FlexProjectionMessageRecordModel.getInstance({ id: expected.id });
|
|
1866
|
+
if (!stored)
|
|
1867
|
+
throw new Error('Flex projection message verification failed.');
|
|
1868
|
+
const message = projectProjectionMessage(stored);
|
|
1869
|
+
assertFlexProjectionMessageRecordDocument(message);
|
|
1870
|
+
if (canonicalJson(message) !== canonicalJson(expected)) {
|
|
1871
|
+
throw new Error('Flex projection message verification failed.');
|
|
1872
|
+
}
|
|
1873
|
+
});
|
|
1874
|
+
}
|
|
1875
|
+
async loadProjectionSource(headArg) {
|
|
1876
|
+
if (headArg.domain !== 'projection' || !headArg.sessionId || !headArg.projectionSource) {
|
|
1877
|
+
throw new plugins.flexharness.FlexHarnessStoreFormatError('Flex projection head does not contain a projection source.');
|
|
1878
|
+
}
|
|
1879
|
+
const model = await FlexProjectionSourceModel.getInstance({
|
|
1880
|
+
id: projectionSourceDocumentId(headArg.projectionSource.candidateId),
|
|
1881
|
+
});
|
|
1882
|
+
if (!model) {
|
|
1883
|
+
throw new plugins.flexharness.FlexHarnessStoreFormatError('Flex projection source is missing.');
|
|
1884
|
+
}
|
|
1885
|
+
const source = projectProjectionSource(model);
|
|
1886
|
+
assertFlexProjectionSourceDocument(source);
|
|
1887
|
+
const unhashedManifest = {
|
|
1888
|
+
candidateId: source.candidateId,
|
|
1889
|
+
...(source.orderVersion === undefined ? {} : { orderVersion: source.orderVersion }),
|
|
1890
|
+
messageCount: source.messageCount,
|
|
1891
|
+
messagesTruncated: source.messagesTruncated,
|
|
1892
|
+
visibleDigest: source.visibleDigest,
|
|
1893
|
+
...(source.latestMessage === undefined ? {} : { latestMessage: source.latestMessage }),
|
|
1894
|
+
};
|
|
1895
|
+
const bytes = projectionSourceManifestBytes(unhashedManifest);
|
|
1896
|
+
const manifest = {
|
|
1897
|
+
...unhashedManifest,
|
|
1898
|
+
sha256: sha256(bytes),
|
|
1899
|
+
bytes: bytes.byteLength,
|
|
1900
|
+
};
|
|
1901
|
+
if (source.id !== projectionSourceDocumentId(headArg.projectionSource.candidateId)
|
|
1902
|
+
|| source.controllerId !== this.controllerId
|
|
1903
|
+
|| source.scopeId !== headArg.storageKey
|
|
1904
|
+
|| source.sessionId !== headArg.sessionId
|
|
1905
|
+
|| source.candidateId !== headArg.projectionSource.candidateId
|
|
1906
|
+
|| source.incarnationId !== headArg.incarnationId
|
|
1907
|
+
|| source.revision > headArg.revision
|
|
1908
|
+
|| canonicalJson(manifest) !== canonicalJson(headArg.projectionSource)) {
|
|
1909
|
+
throw new plugins.flexharness.FlexHarnessStoreFormatError('Flex projection source does not match its domain head.');
|
|
1910
|
+
}
|
|
1911
|
+
return source;
|
|
1912
|
+
}
|
|
1913
|
+
async loadProjectionMessageRecord(sourceArg, descriptorArg) {
|
|
1914
|
+
const model = await FlexProjectionMessageRecordModel.getInstance({ id: descriptorArg.id });
|
|
1915
|
+
if (!model) {
|
|
1916
|
+
throw new plugins.flexharness.FlexHarnessStoreFormatError('Flex projection message record is missing.');
|
|
1917
|
+
}
|
|
1918
|
+
const record = projectProjectionMessage(model);
|
|
1919
|
+
assertFlexProjectionMessageRecordDocument(record);
|
|
1920
|
+
const descriptor = {
|
|
1921
|
+
id: record.id,
|
|
1922
|
+
index: record.index,
|
|
1923
|
+
...(record.messageIndex === undefined ? {} : { messageIndex: record.messageIndex }),
|
|
1924
|
+
sha256: record.sha256,
|
|
1925
|
+
bytes: record.bytes,
|
|
1926
|
+
messageCreatedAt: record.messageCreatedAt,
|
|
1927
|
+
sessionId: record.sessionId,
|
|
1928
|
+
messageId: record.messageId,
|
|
1929
|
+
};
|
|
1930
|
+
const payload = projectionMessagePayloadBytes(record.message, record.previous);
|
|
1931
|
+
if (record.id !== projectionMessageDocumentId(sourceArg.candidateId, record.index)
|
|
1932
|
+
|| record.controllerId !== this.controllerId
|
|
1933
|
+
|| record.scopeId !== sourceArg.scopeId
|
|
1934
|
+
|| record.candidateId !== sourceArg.candidateId
|
|
1935
|
+
|| record.sessionId !== sourceArg.sessionId
|
|
1936
|
+
|| record.incarnationId !== sourceArg.incarnationId
|
|
1937
|
+
|| record.revision !== sourceArg.revision
|
|
1938
|
+
|| canonicalJson(descriptor) !== canonicalJson(descriptorArg)
|
|
1939
|
+
|| payload.byteLength !== record.bytes
|
|
1940
|
+
|| sha256(payload) !== record.sha256
|
|
1941
|
+
|| (record.index === 0
|
|
1942
|
+
? record.previous !== undefined
|
|
1943
|
+
: !record.previous
|
|
1944
|
+
|| record.previous.index !== record.index - 1
|
|
1945
|
+
|| record.previous.id !== projectionMessageDocumentId(sourceArg.candidateId, record.index - 1))) {
|
|
1946
|
+
throw new plugins.flexharness.FlexHarnessStoreFormatError('Flex projection message chain is invalid.');
|
|
1947
|
+
}
|
|
1948
|
+
return record;
|
|
1949
|
+
}
|
|
1950
|
+
async buildPublicProjectionFromSources(storageKeyArg, candidateIdArg, publicationRevisionArg, scopeArg, sourcesArg, createdAtArg = new Date().toISOString()) {
|
|
1951
|
+
const retainedSessions = retainPublicSessions(scopeArg.snapshot.sessions);
|
|
1952
|
+
const retainedSessionIds = new Set(retainedSessions.map((session) => session.sessionId));
|
|
1953
|
+
const sessions = retainedSessions.map((session) => ({
|
|
1954
|
+
id: publicSessionDocumentId(candidateIdArg, session.sessionId),
|
|
1955
|
+
controllerId: this.controllerId,
|
|
1956
|
+
scopeId: storageKeyArg,
|
|
1957
|
+
candidateId: candidateIdArg,
|
|
1958
|
+
revision: publicationRevisionArg,
|
|
1959
|
+
session: cloneJson(session),
|
|
1960
|
+
createdAt: createdAtArg,
|
|
1961
|
+
}));
|
|
1962
|
+
const sourceBySession = new Map(sourcesArg.map((source) => [source.sessionId, source]));
|
|
1963
|
+
if (sourceBySession.size !== sourcesArg.length) {
|
|
1964
|
+
throw new plugins.flexharness.FlexHarnessStoreFormatError('Flex projection source set contains duplicate sessions.');
|
|
1965
|
+
}
|
|
1966
|
+
const sources = retainedSessions.flatMap((session) => {
|
|
1967
|
+
const source = sourceBySession.get(session.sessionId);
|
|
1968
|
+
return source && retainedSessionIds.has(source.sessionId) ? [source] : [];
|
|
1969
|
+
});
|
|
1970
|
+
const entries = sources.flatMap((source) => source.latestMessage
|
|
1971
|
+
? [{ source, descriptor: source.latestMessage }]
|
|
1972
|
+
: []);
|
|
1973
|
+
const messages = [];
|
|
1974
|
+
let messageBytes = 0;
|
|
1975
|
+
let messageBytesTruncated = false;
|
|
1976
|
+
let oversizedMessagesReplaced = false;
|
|
1977
|
+
while (entries.length > 0 && messages.length < flexPublicMessageLimit) {
|
|
1978
|
+
let newestIndex = 0;
|
|
1979
|
+
for (let index = 1; index < entries.length; index++) {
|
|
1980
|
+
if (compareNewestProjectionDescriptor(entries[index].descriptor, entries[newestIndex].descriptor) < 0)
|
|
1981
|
+
newestIndex = index;
|
|
1982
|
+
}
|
|
1983
|
+
const entry = entries[newestIndex];
|
|
1984
|
+
const sourceRecord = await this.loadProjectionMessageRecord(entry.source, entry.descriptor);
|
|
1985
|
+
if (sourceRecord.messageIndex === undefined) {
|
|
1986
|
+
throw new plugins.flexharness.FlexHarnessStoreFormatError('Flex projection source message order is unavailable.');
|
|
1987
|
+
}
|
|
1988
|
+
const messageIndex = sourceRecord.messageIndex;
|
|
1989
|
+
const createRecord = (messageArg) => ({
|
|
1990
|
+
id: publicMessageDocumentId(candidateIdArg, messageArg.sessionId, messageArg.messageId),
|
|
1991
|
+
controllerId: this.controllerId,
|
|
1992
|
+
scopeId: storageKeyArg,
|
|
1993
|
+
candidateId: candidateIdArg,
|
|
1994
|
+
revision: publicationRevisionArg,
|
|
1995
|
+
messageIndex,
|
|
1996
|
+
message: cloneJson(messageArg),
|
|
1997
|
+
createdAt: createdAtArg,
|
|
1998
|
+
});
|
|
1999
|
+
let publicRecord = createRecord(sourceRecord.message);
|
|
2000
|
+
let publicRecordBytes = serializedBytes(publicRecord).byteLength;
|
|
2001
|
+
if (publicRecordBytes > flexPublicSingleMessageBytesLimit) {
|
|
2002
|
+
publicRecord = createRecord(placeholderMessage(sourceRecord.message));
|
|
2003
|
+
publicRecordBytes = serializedBytes(publicRecord).byteLength;
|
|
2004
|
+
oversizedMessagesReplaced = true;
|
|
2005
|
+
if (publicRecordBytes > flexPublicSingleMessageBytesLimit) {
|
|
2006
|
+
throw new plugins.flexharness.FlexHarnessStoreFormatError('Flex public message metadata exceeds its projection limit.');
|
|
2007
|
+
}
|
|
2008
|
+
}
|
|
2009
|
+
if (messageBytes + publicRecordBytes > flexPublicMessageBytesLimit) {
|
|
2010
|
+
messageBytesTruncated = true;
|
|
2011
|
+
break;
|
|
2012
|
+
}
|
|
2013
|
+
messageBytes += publicRecordBytes;
|
|
2014
|
+
messages.push(publicRecord);
|
|
2015
|
+
if (sourceRecord.previous) {
|
|
2016
|
+
entries[newestIndex] = { source: entry.source, descriptor: sourceRecord.previous };
|
|
2017
|
+
}
|
|
2018
|
+
else {
|
|
2019
|
+
entries.splice(newestIndex, 1);
|
|
2020
|
+
}
|
|
2021
|
+
}
|
|
2022
|
+
const sessionsTruncated = retainedSessions.length < scopeArg.snapshot.sessions.length;
|
|
2023
|
+
let availableMessageCount = 0;
|
|
2024
|
+
for (const source of sources) {
|
|
2025
|
+
availableMessageCount = Math.min(flexPublicMessageLimit + 1, availableMessageCount + source.messageCount);
|
|
2026
|
+
}
|
|
2027
|
+
const messagesTruncated = sessionsTruncated
|
|
2028
|
+
|| sources.some((source) => source.messagesTruncated)
|
|
2029
|
+
|| messages.length < availableMessageCount
|
|
2030
|
+
|| oversizedMessagesReplaced;
|
|
2031
|
+
const sessionRecords = sessions.map(recordManifest);
|
|
2032
|
+
if (new Set(messages.map((record) => (`${record.message.sessionId}\0${record.messageIndex}`))).size !== messages.length) {
|
|
2033
|
+
throw new plugins.flexharness.FlexHarnessStoreFormatError('Flex public projection contains duplicate message indexes.');
|
|
2034
|
+
}
|
|
2035
|
+
const messageRecords = messages.map(recordManifest);
|
|
2036
|
+
const visibleDigest = sha256(serializedBytes({
|
|
2037
|
+
sessions: sessions.map((record) => record.session),
|
|
2038
|
+
messages: messages.map((record) => ({
|
|
2039
|
+
messageIndex: record.messageIndex,
|
|
2040
|
+
message: record.message,
|
|
2041
|
+
})),
|
|
2042
|
+
sessionsTruncated,
|
|
2043
|
+
messagesTruncated,
|
|
2044
|
+
messageBytesTruncated,
|
|
2045
|
+
}));
|
|
2046
|
+
const projectionSources = sources.map((source) => ({
|
|
2047
|
+
sessionId: source.sessionId,
|
|
2048
|
+
incarnationId: source.incarnationId,
|
|
2049
|
+
revision: source.revision,
|
|
2050
|
+
}));
|
|
2051
|
+
const unhashedManifest = {
|
|
2052
|
+
candidateId: candidateIdArg,
|
|
2053
|
+
revision: publicationRevisionArg,
|
|
2054
|
+
sessionRecords,
|
|
2055
|
+
messageRecords,
|
|
2056
|
+
sessionsTruncated,
|
|
2057
|
+
messagesTruncated,
|
|
2058
|
+
messageBytesTruncated,
|
|
2059
|
+
visibleDigest,
|
|
2060
|
+
scopeSource: {
|
|
2061
|
+
incarnationId: scopeArg.head.incarnationId,
|
|
2062
|
+
revision: scopeArg.head.revision,
|
|
2063
|
+
},
|
|
2064
|
+
projectionSources,
|
|
2065
|
+
};
|
|
2066
|
+
const candidateBytes = publicCandidateManifestBytes(unhashedManifest);
|
|
2067
|
+
const candidate = {
|
|
2068
|
+
id: publicCandidateDocumentId(candidateIdArg),
|
|
2069
|
+
controllerId: this.controllerId,
|
|
2070
|
+
scopeId: storageKeyArg,
|
|
2071
|
+
...unhashedManifest,
|
|
2072
|
+
sha256: sha256(candidateBytes),
|
|
2073
|
+
bytes: candidateBytes.byteLength,
|
|
2074
|
+
createdAt: createdAtArg,
|
|
2075
|
+
};
|
|
2076
|
+
assertFlexPublicCandidateDocument(candidate);
|
|
2077
|
+
for (const session of sessions)
|
|
2078
|
+
assertFlexPublicSessionRecordDocument(session);
|
|
2079
|
+
for (const message of messages)
|
|
2080
|
+
assertFlexPublicMessageRecordDocument(message);
|
|
2081
|
+
return { candidate, sessions, messages };
|
|
2082
|
+
}
|
|
2083
|
+
async publishPublicProjection(storageKeyArg, leaseArg) {
|
|
2084
|
+
const scope = await this.loadDomainDirect({ storageKey: storageKeyArg, domain: 'scope' }, (value) => this.validateScopeSnapshot(value));
|
|
2085
|
+
if (!scope)
|
|
2086
|
+
return;
|
|
2087
|
+
const retainedSessionIds = retainNewest(scope.snapshot.sessions, flexPublicSessionLimit, compareNewestSession)
|
|
2088
|
+
.map((session) => session.sessionId);
|
|
2089
|
+
const projectionHeads = [];
|
|
2090
|
+
if (retainedSessionIds.length > 0) {
|
|
2091
|
+
const cursor = FlexDomainHeadModel.collection.mongoDbCollection.find({
|
|
2092
|
+
controllerId: this.controllerId,
|
|
2093
|
+
storageKey: storageKeyArg,
|
|
2094
|
+
domain: 'projection',
|
|
2095
|
+
sessionId: { $in: retainedSessionIds },
|
|
2096
|
+
}).limit(retainedSessionIds.length + 1);
|
|
2097
|
+
try {
|
|
2098
|
+
projectionHeads.push(...await cursor.toArray());
|
|
2099
|
+
}
|
|
2100
|
+
finally {
|
|
2101
|
+
await cursor.close();
|
|
2102
|
+
}
|
|
2103
|
+
if (projectionHeads.length > retainedSessionIds.length) {
|
|
2104
|
+
throw new plugins.flexharness.FlexHarnessStoreFormatError('Flex projection head set exceeds the retained session set.');
|
|
2105
|
+
}
|
|
2106
|
+
}
|
|
2107
|
+
const sources = [];
|
|
2108
|
+
for (let index = 0; index < projectionHeads.length; index += 32) {
|
|
2109
|
+
const batch = projectionHeads.slice(index, index + 32);
|
|
2110
|
+
sources.push(...await Promise.all(batch.map(async (head) => {
|
|
2111
|
+
if (!head.sessionId) {
|
|
2112
|
+
throw new plugins.flexharness.FlexHarnessStoreFormatError('Flex projection head is missing its session identity.');
|
|
2113
|
+
}
|
|
2114
|
+
const identity = {
|
|
2115
|
+
storageKey: storageKeyArg,
|
|
2116
|
+
domain: 'projection',
|
|
2117
|
+
sessionId: head.sessionId,
|
|
2118
|
+
};
|
|
2119
|
+
this.assertDomainHeadIdentity(head, identity);
|
|
2120
|
+
const source = await this.loadProjectionSource(head);
|
|
2121
|
+
if (source.orderVersion !== 1) {
|
|
2122
|
+
throw new plugins.flexharness.FlexHarnessStoreFormatError('Flex projection source ordering migration is required before publication.');
|
|
2123
|
+
}
|
|
2124
|
+
return source;
|
|
2125
|
+
})));
|
|
2126
|
+
}
|
|
2127
|
+
const currentHead = await this.readPublicHead(storageKeyArg);
|
|
2128
|
+
const publicationRevision = (currentHead?.revision ?? 0) + 1;
|
|
2129
|
+
const candidateId = randomCandidateId();
|
|
2130
|
+
const build = await this.buildPublicProjectionFromSources(storageKeyArg, candidateId, publicationRevision, scope, sources);
|
|
2131
|
+
const currentManifest = currentHead?.publicCandidates[0];
|
|
2132
|
+
if (currentManifest?.visibleDigest === build.candidate.visibleDigest
|
|
2133
|
+
&& await this.verifyPublicCandidate(storageKeyArg, currentManifest).catch(() => false))
|
|
2134
|
+
return;
|
|
2135
|
+
const manifest = {
|
|
2136
|
+
candidateId: build.candidate.candidateId,
|
|
2137
|
+
revision: build.candidate.revision,
|
|
2138
|
+
sha256: build.candidate.sha256,
|
|
2139
|
+
bytes: build.candidate.bytes,
|
|
2140
|
+
sessionRecords: build.candidate.sessionRecords,
|
|
2141
|
+
messageRecords: build.candidate.messageRecords,
|
|
2142
|
+
sessionsTruncated: build.candidate.sessionsTruncated,
|
|
2143
|
+
messagesTruncated: build.candidate.messagesTruncated,
|
|
2144
|
+
messageBytesTruncated: build.candidate.messageBytesTruncated,
|
|
2145
|
+
visibleDigest: build.candidate.visibleDigest,
|
|
2146
|
+
scopeSource: build.candidate.scopeSource,
|
|
2147
|
+
projectionSources: build.candidate.projectionSources,
|
|
2148
|
+
};
|
|
2149
|
+
const nextHead = {
|
|
2150
|
+
id: flexPublicHeadId(this.controllerId, storageKeyArg),
|
|
2151
|
+
controllerId: this.controllerId,
|
|
2152
|
+
storageKey: storageKeyArg,
|
|
2153
|
+
revision: publicationRevision,
|
|
2154
|
+
currentPublicCandidateId: candidateId,
|
|
2155
|
+
publicCandidates: [
|
|
2156
|
+
manifest,
|
|
2157
|
+
...(currentHead?.publicCandidates ?? []).slice(0, 3),
|
|
2158
|
+
],
|
|
2159
|
+
};
|
|
2160
|
+
assertFlexPublicHeadDocument(nextHead);
|
|
2161
|
+
this.activeCandidateIds.add(candidateId);
|
|
2162
|
+
let committed = false;
|
|
2163
|
+
try {
|
|
2164
|
+
await this.writeAndVerifyPublic(build);
|
|
2165
|
+
await this.commitPublicHead(leaseArg, currentHead, nextHead, storageKeyArg);
|
|
2166
|
+
committed = true;
|
|
2167
|
+
if (currentHead) {
|
|
2168
|
+
const retained = new Set(nextHead.publicCandidates.map((entry) => entry.candidateId));
|
|
2169
|
+
for (const evicted of currentHead.publicCandidates) {
|
|
2170
|
+
if (!retained.has(evicted.candidateId)) {
|
|
2171
|
+
await this.cleanupPublicByCandidate(evicted, storageKeyArg).catch(() => undefined);
|
|
2172
|
+
}
|
|
2173
|
+
}
|
|
2174
|
+
}
|
|
2175
|
+
}
|
|
2176
|
+
finally {
|
|
2177
|
+
this.activeCandidateIds.delete(candidateId);
|
|
2178
|
+
if (!committed)
|
|
2179
|
+
this.queueOrphanMaintenance();
|
|
2180
|
+
}
|
|
2181
|
+
}
|
|
2182
|
+
async readPublicHead(storageKeyArg, optionsArg) {
|
|
2183
|
+
const id = flexPublicHeadId(this.controllerId, storageKeyArg);
|
|
2184
|
+
const rawHead = await this.database.mongoDb.collection('flex_public_heads').findOne({ id }, optionsArg);
|
|
2185
|
+
const head = rawHead;
|
|
2186
|
+
if (head) {
|
|
2187
|
+
const body = publicHeadBody(head);
|
|
2188
|
+
assertFlexPublicHeadDocument(body);
|
|
2189
|
+
if (body.id !== id
|
|
2190
|
+
|| body.controllerId !== this.controllerId
|
|
2191
|
+
|| body.storageKey !== storageKeyArg) {
|
|
2192
|
+
throw new plugins.flexharness.FlexHarnessStoreFormatError('Flex public head identity mismatch.');
|
|
2193
|
+
}
|
|
2194
|
+
}
|
|
2195
|
+
return head;
|
|
2196
|
+
}
|
|
2197
|
+
async commitPublicHead(leaseArg, currentArg, nextArg, storageKeyArg) {
|
|
2198
|
+
await this.commitHeadMutation({
|
|
2199
|
+
lease: leaseArg,
|
|
2200
|
+
collection: this.database.mongoDb.collection('flex_public_heads'),
|
|
2201
|
+
current: currentArg,
|
|
2202
|
+
next: nextArg,
|
|
2203
|
+
selector: currentArg ? {
|
|
2204
|
+
_id: currentArg._id,
|
|
2205
|
+
id: currentArg.id,
|
|
2206
|
+
controllerId: this.controllerId,
|
|
2207
|
+
storageKey: storageKeyArg,
|
|
2208
|
+
revision: currentArg.revision,
|
|
2209
|
+
_smartdataRevision: smartRevisionSelector(currentArg),
|
|
2210
|
+
} : { id: nextArg.id },
|
|
2211
|
+
readCurrent: (options) => this.readPublicHead(storageKeyArg, options),
|
|
2212
|
+
project: publicHeadBody,
|
|
2213
|
+
targetName: `public:${nextArg.id}`,
|
|
2214
|
+
});
|
|
2215
|
+
}
|
|
2216
|
+
async deletePublicHead(leaseArg, headArg, storageKeyArg) {
|
|
2217
|
+
await this.commitHeadMutation({
|
|
2218
|
+
lease: leaseArg,
|
|
2219
|
+
collection: this.database.mongoDb.collection('flex_public_heads'),
|
|
2220
|
+
current: headArg,
|
|
2221
|
+
next: null,
|
|
2222
|
+
selector: {
|
|
2223
|
+
_id: headArg._id,
|
|
2224
|
+
id: headArg.id,
|
|
2225
|
+
controllerId: this.controllerId,
|
|
2226
|
+
storageKey: storageKeyArg,
|
|
2227
|
+
revision: headArg.revision,
|
|
2228
|
+
_smartdataRevision: smartRevisionSelector(headArg),
|
|
2229
|
+
},
|
|
2230
|
+
readCurrent: (options) => this.readPublicHead(storageKeyArg, options),
|
|
2231
|
+
project: publicHeadBody,
|
|
2232
|
+
targetName: `public:${headArg.id}`,
|
|
2233
|
+
});
|
|
2234
|
+
}
|
|
2235
|
+
async writeAndVerifyPublic(buildArg) {
|
|
2236
|
+
await insertOrdinary(FlexPublicCandidateModel, buildArg.candidate);
|
|
2237
|
+
await inBatches(buildArg.sessions, (session) => insertOrdinary(FlexPublicSessionRecordModel, session));
|
|
2238
|
+
await inBatches(buildArg.messages, (message) => insertOrdinary(FlexPublicMessageRecordModel, message));
|
|
2239
|
+
const manifest = {
|
|
2240
|
+
candidateId: buildArg.candidate.candidateId,
|
|
2241
|
+
revision: buildArg.candidate.revision,
|
|
2242
|
+
sha256: buildArg.candidate.sha256,
|
|
2243
|
+
bytes: buildArg.candidate.bytes,
|
|
2244
|
+
sessionRecords: buildArg.candidate.sessionRecords,
|
|
2245
|
+
messageRecords: buildArg.candidate.messageRecords,
|
|
2246
|
+
sessionsTruncated: buildArg.candidate.sessionsTruncated,
|
|
2247
|
+
messagesTruncated: buildArg.candidate.messagesTruncated,
|
|
2248
|
+
messageBytesTruncated: buildArg.candidate.messageBytesTruncated,
|
|
2249
|
+
visibleDigest: buildArg.candidate.visibleDigest,
|
|
2250
|
+
scopeSource: buildArg.candidate.scopeSource,
|
|
2251
|
+
projectionSources: buildArg.candidate.projectionSources,
|
|
2252
|
+
};
|
|
2253
|
+
if (!await this.verifyPublicCandidate(buildArg.candidate.scopeId, manifest)) {
|
|
2254
|
+
throw new Error('Flex public candidate verification failed.');
|
|
2255
|
+
}
|
|
2256
|
+
}
|
|
2257
|
+
async verifyPublicCandidate(storageKeyArg, manifestArg) {
|
|
2258
|
+
const model = await FlexPublicCandidateModel.getInstance({
|
|
2259
|
+
id: publicCandidateDocumentId(manifestArg.candidateId),
|
|
2260
|
+
controllerId: this.controllerId,
|
|
2261
|
+
scopeId: storageKeyArg,
|
|
2262
|
+
candidateId: manifestArg.candidateId,
|
|
2263
|
+
});
|
|
2264
|
+
if (!model)
|
|
2265
|
+
return false;
|
|
2266
|
+
const candidate = projectPublicCandidate(model);
|
|
2267
|
+
assertFlexPublicCandidateDocument(candidate);
|
|
2268
|
+
const projectedManifest = {
|
|
2269
|
+
candidateId: candidate.candidateId,
|
|
2270
|
+
revision: candidate.revision,
|
|
2271
|
+
sha256: candidate.sha256,
|
|
2272
|
+
bytes: candidate.bytes,
|
|
2273
|
+
sessionRecords: candidate.sessionRecords,
|
|
2274
|
+
messageRecords: candidate.messageRecords,
|
|
2275
|
+
sessionsTruncated: candidate.sessionsTruncated,
|
|
2276
|
+
messagesTruncated: candidate.messagesTruncated,
|
|
2277
|
+
messageBytesTruncated: candidate.messageBytesTruncated,
|
|
2278
|
+
visibleDigest: candidate.visibleDigest,
|
|
2279
|
+
scopeSource: candidate.scopeSource,
|
|
2280
|
+
projectionSources: candidate.projectionSources,
|
|
2281
|
+
};
|
|
2282
|
+
const unhashed = {
|
|
2283
|
+
candidateId: candidate.candidateId,
|
|
2284
|
+
revision: candidate.revision,
|
|
2285
|
+
sessionRecords: candidate.sessionRecords,
|
|
2286
|
+
messageRecords: candidate.messageRecords,
|
|
2287
|
+
sessionsTruncated: candidate.sessionsTruncated,
|
|
2288
|
+
messagesTruncated: candidate.messagesTruncated,
|
|
2289
|
+
messageBytesTruncated: candidate.messageBytesTruncated,
|
|
2290
|
+
visibleDigest: candidate.visibleDigest,
|
|
2291
|
+
scopeSource: candidate.scopeSource,
|
|
2292
|
+
projectionSources: candidate.projectionSources,
|
|
2293
|
+
};
|
|
2294
|
+
const bytes = publicCandidateManifestBytes(unhashed);
|
|
2295
|
+
if (candidate.id !== publicCandidateDocumentId(manifestArg.candidateId)
|
|
2296
|
+
|| candidate.controllerId !== this.controllerId
|
|
2297
|
+
|| candidate.scopeId !== storageKeyArg
|
|
2298
|
+
|| !publicManifestsEqual(projectedManifest, manifestArg)
|
|
2299
|
+
|| candidate.bytes !== bytes.byteLength
|
|
2300
|
+
|| candidate.sha256 !== sha256(bytes))
|
|
2301
|
+
return false;
|
|
2302
|
+
const [sessionModels, messageModels] = await Promise.all([
|
|
2303
|
+
FlexPublicSessionRecordModel.getInstances({
|
|
2304
|
+
controllerId: this.controllerId,
|
|
2305
|
+
scopeId: storageKeyArg,
|
|
2306
|
+
candidateId: manifestArg.candidateId,
|
|
2307
|
+
}),
|
|
2308
|
+
FlexPublicMessageRecordModel.getInstances({
|
|
2309
|
+
controllerId: this.controllerId,
|
|
2310
|
+
scopeId: storageKeyArg,
|
|
2311
|
+
candidateId: manifestArg.candidateId,
|
|
2312
|
+
}),
|
|
2313
|
+
]);
|
|
2314
|
+
if (sessionModels.length !== manifestArg.sessionRecords.length
|
|
2315
|
+
|| messageModels.length !== manifestArg.messageRecords.length)
|
|
2316
|
+
return false;
|
|
2317
|
+
const manifests = new Map([
|
|
2318
|
+
...manifestArg.sessionRecords,
|
|
2319
|
+
...manifestArg.messageRecords,
|
|
2320
|
+
].map((manifest) => [manifest.id, manifest]));
|
|
2321
|
+
for (const sessionModel of sessionModels) {
|
|
2322
|
+
const document = projectPublicSession(sessionModel);
|
|
2323
|
+
assertFlexPublicSessionRecordDocument(document);
|
|
2324
|
+
if (document.controllerId !== this.controllerId
|
|
2325
|
+
|| document.scopeId !== storageKeyArg
|
|
2326
|
+
|| document.candidateId !== manifestArg.candidateId
|
|
2327
|
+
|| document.revision !== manifestArg.revision
|
|
2328
|
+
|| canonicalJson(recordManifest(document)) !== canonicalJson(manifests.get(document.id)))
|
|
2329
|
+
return false;
|
|
2330
|
+
}
|
|
2331
|
+
for (const messageModel of messageModels) {
|
|
2332
|
+
const document = projectPublicMessage(messageModel);
|
|
2333
|
+
assertFlexPublicMessageRecordDocument(document);
|
|
2334
|
+
if (document.controllerId !== this.controllerId
|
|
2335
|
+
|| document.scopeId !== storageKeyArg
|
|
2336
|
+
|| document.candidateId !== manifestArg.candidateId
|
|
2337
|
+
|| document.revision !== manifestArg.revision
|
|
2338
|
+
|| canonicalJson(recordManifest(document)) !== canonicalJson(manifests.get(document.id)))
|
|
2339
|
+
return false;
|
|
2340
|
+
}
|
|
2341
|
+
return true;
|
|
2342
|
+
}
|
|
2343
|
+
async commitHeadMutation(optionsArg) {
|
|
2344
|
+
return this.runLeaseTransition(optionsArg.lease, (abortSignal, timeoutMs) => this.commitHeadMutationWithLease(optionsArg, abortSignal, timeoutMs));
|
|
2345
|
+
}
|
|
2346
|
+
async commitHeadMutationWithLease(optionsArg, abortSignalArg, timeoutMsArg) {
|
|
2347
|
+
const deadline = Date.now() + timeoutMsArg;
|
|
2348
|
+
const session = this.database.startSession();
|
|
2349
|
+
let callbackError;
|
|
2350
|
+
try {
|
|
2351
|
+
await session.withTransaction(async () => {
|
|
2352
|
+
abortSignalArg.throwIfAborted();
|
|
2353
|
+
const now = Date.now();
|
|
2354
|
+
const leasePostimage = await FlexWriterLeaseModel.collection.mongoDbCollection.findOneAndUpdate({
|
|
2355
|
+
id: flexWriterLeaseId(this.controllerId, optionsArg.lease.storageKey),
|
|
2356
|
+
controllerId: this.controllerId,
|
|
2357
|
+
storageKey: optionsArg.lease.storageKey,
|
|
2358
|
+
ownerToken: optionsArg.lease.ownerToken,
|
|
2359
|
+
epoch: optionsArg.lease.epoch,
|
|
2360
|
+
state: 'active',
|
|
2361
|
+
expiresAt: { $gt: now },
|
|
2362
|
+
}, {
|
|
2363
|
+
$set: {
|
|
2364
|
+
expiresAt: now + flexLeaseDurationMs,
|
|
2365
|
+
updatedAt: new Date(now).toISOString(),
|
|
2366
|
+
_smartdataRevision: plugins.crypto.randomUUID(),
|
|
2367
|
+
},
|
|
2368
|
+
}, {
|
|
2369
|
+
session,
|
|
2370
|
+
returnDocument: 'after',
|
|
2371
|
+
includeResultMetadata: false,
|
|
2372
|
+
});
|
|
2373
|
+
abortSignalArg.throwIfAborted();
|
|
2374
|
+
if (!leasePostimage)
|
|
2375
|
+
throw new FlexLeaseLostError(optionsArg.lease.storageKey);
|
|
2376
|
+
if (!optionsArg.current && optionsArg.next) {
|
|
2377
|
+
try {
|
|
2378
|
+
await optionsArg.collection.insertOne({
|
|
2379
|
+
...optionsArg.next,
|
|
2380
|
+
_smartdataRevision: plugins.crypto.randomUUID(),
|
|
2381
|
+
}, { session });
|
|
2382
|
+
abortSignalArg.throwIfAborted();
|
|
2383
|
+
}
|
|
2384
|
+
catch (errorArg) {
|
|
2385
|
+
callbackError = errorArg;
|
|
2386
|
+
throw errorArg;
|
|
2387
|
+
}
|
|
2388
|
+
return;
|
|
2389
|
+
}
|
|
2390
|
+
if (optionsArg.current && optionsArg.next) {
|
|
2391
|
+
const postimage = await optionsArg.collection.findOneAndReplace(optionsArg.selector, { ...optionsArg.next, _smartdataRevision: plugins.crypto.randomUUID() }, {
|
|
2392
|
+
session,
|
|
2393
|
+
upsert: false,
|
|
2394
|
+
returnDocument: 'after',
|
|
2395
|
+
includeResultMetadata: false,
|
|
2396
|
+
});
|
|
2397
|
+
abortSignalArg.throwIfAborted();
|
|
2398
|
+
if (!postimage) {
|
|
2399
|
+
throw new FlexHeadCasError(optionsArg.current.revision ?? 0);
|
|
2400
|
+
}
|
|
2401
|
+
return;
|
|
2402
|
+
}
|
|
2403
|
+
if (optionsArg.current && !optionsArg.next) {
|
|
2404
|
+
const deletion = await optionsArg.collection.deleteOne(optionsArg.selector, {
|
|
2405
|
+
session,
|
|
2406
|
+
});
|
|
2407
|
+
abortSignalArg.throwIfAborted();
|
|
2408
|
+
if (deletion.deletedCount !== 1) {
|
|
2409
|
+
throw new FlexHeadCasError(optionsArg.current.revision ?? 0);
|
|
2410
|
+
}
|
|
2411
|
+
}
|
|
2412
|
+
}, {
|
|
2413
|
+
timeoutMS: Math.max(1, deadline - Date.now()),
|
|
2414
|
+
maxCommitTimeMS: Math.max(1, deadline - Date.now()),
|
|
2415
|
+
});
|
|
2416
|
+
this.throwIfFatal();
|
|
2417
|
+
await this.verifyHeldLease(optionsArg.lease, false, abortSignalArg, false, Math.max(1, deadline - Date.now()));
|
|
2418
|
+
return;
|
|
2419
|
+
}
|
|
2420
|
+
catch (errorArg) {
|
|
2421
|
+
this.throwIfFatal();
|
|
2422
|
+
const operationError = callbackError ?? errorArg;
|
|
2423
|
+
const reconciliationOptions = {
|
|
2424
|
+
signal: abortSignalArg,
|
|
2425
|
+
timeoutMS: Math.max(1, deadline - Date.now()),
|
|
2426
|
+
};
|
|
2427
|
+
let leaseCurrent;
|
|
2428
|
+
let targetCurrent;
|
|
2429
|
+
try {
|
|
2430
|
+
[leaseCurrent, targetCurrent] = await Promise.all([
|
|
2431
|
+
FlexWriterLeaseModel.collection.mongoDbCollection.findOne({
|
|
2432
|
+
id: flexWriterLeaseId(this.controllerId, optionsArg.lease.storageKey),
|
|
2433
|
+
}, reconciliationOptions),
|
|
2434
|
+
optionsArg.readCurrent(reconciliationOptions),
|
|
2435
|
+
]);
|
|
2436
|
+
}
|
|
2437
|
+
catch (readbackError) {
|
|
2438
|
+
throw new plugins.smartdata.SmartdataExactPersistenceError('ambiguous_write', `Flex ${optionsArg.targetName} mutation failed and readback was unavailable.`, { cause: new AggregateError([operationError, readbackError]) });
|
|
2439
|
+
}
|
|
2440
|
+
const uncertainTransition = optionsArg.lease.uncertainTransition;
|
|
2441
|
+
if (leaseCurrent
|
|
2442
|
+
&& uncertainTransition
|
|
2443
|
+
&& leaseTransitionImagesEqual(leaseCurrent, uncertainTransition.postimage)) {
|
|
2444
|
+
optionsArg.lease.ownerToken = leaseCurrent.ownerToken;
|
|
2445
|
+
optionsArg.lease.epoch = leaseCurrent.epoch;
|
|
2446
|
+
optionsArg.lease.expiresAt = leaseCurrent.expiresAt;
|
|
2447
|
+
optionsArg.lease.uncertainTransition = undefined;
|
|
2448
|
+
}
|
|
2449
|
+
const sameLease = !!leaseCurrent
|
|
2450
|
+
&& leaseCurrent.controllerId === this.controllerId
|
|
2451
|
+
&& leaseCurrent.storageKey === optionsArg.lease.storageKey
|
|
2452
|
+
&& leaseCurrent.ownerToken === optionsArg.lease.ownerToken
|
|
2453
|
+
&& leaseCurrent.epoch === optionsArg.lease.epoch
|
|
2454
|
+
&& leaseCurrent.state === 'active'
|
|
2455
|
+
&& leaseCurrent.expiresAt > Date.now();
|
|
2456
|
+
const requestedCommitted = optionsArg.next
|
|
2457
|
+
? !!targetCurrent
|
|
2458
|
+
&& canonicalJson(optionsArg.project(targetCurrent))
|
|
2459
|
+
=== canonicalJson(optionsArg.project(optionsArg.next))
|
|
2460
|
+
: targetCurrent === null;
|
|
2461
|
+
if (sameLease && requestedCommitted) {
|
|
2462
|
+
optionsArg.lease.expiresAt = leaseCurrent.expiresAt;
|
|
2463
|
+
return;
|
|
2464
|
+
}
|
|
2465
|
+
if (!sameLease) {
|
|
2466
|
+
if (uncertainTransition
|
|
2467
|
+
&& leaseCurrent
|
|
2468
|
+
&& leaseTransitionImagesEqual(leaseCurrent, uncertainTransition.preimage))
|
|
2469
|
+
throw operationError;
|
|
2470
|
+
throw this.markLeaseLost(optionsArg.lease);
|
|
2471
|
+
}
|
|
2472
|
+
if (errorArg instanceof FlexHeadCasError) {
|
|
2473
|
+
throw new FlexHeadCasError(targetCurrent?.revision ?? 0);
|
|
2474
|
+
}
|
|
2475
|
+
if (targetCurrent && optionsArg.current) {
|
|
2476
|
+
const stillCurrent = canonicalJson(optionsArg.project(targetCurrent))
|
|
2477
|
+
=== canonicalJson(optionsArg.project(optionsArg.current));
|
|
2478
|
+
if (stillCurrent)
|
|
2479
|
+
throw operationError;
|
|
2480
|
+
}
|
|
2481
|
+
if (!targetCurrent && !optionsArg.current)
|
|
2482
|
+
throw operationError;
|
|
2483
|
+
throw new FlexHeadCasError(targetCurrent?.revision ?? 0);
|
|
2484
|
+
}
|
|
2485
|
+
finally {
|
|
2486
|
+
await session.endSession();
|
|
2487
|
+
}
|
|
2488
|
+
}
|
|
2489
|
+
async deleteScopeRecords(leaseArg, storageKeyArg) {
|
|
2490
|
+
const collections = [
|
|
2491
|
+
FlexPrivateChunkModel.collection.mongoDbCollection,
|
|
2492
|
+
FlexPrivateCandidateModel.collection.mongoDbCollection,
|
|
2493
|
+
FlexPublicSessionRecordModel.collection.mongoDbCollection,
|
|
2494
|
+
FlexPublicMessageRecordModel.collection.mongoDbCollection,
|
|
2495
|
+
FlexPublicCandidateModel.collection.mongoDbCollection,
|
|
2496
|
+
FlexProjectionMessageRecordModel.collection.mongoDbCollection,
|
|
2497
|
+
FlexProjectionSourceModel.collection.mongoDbCollection,
|
|
2498
|
+
];
|
|
2499
|
+
for (const collection of collections) {
|
|
2500
|
+
let lastId;
|
|
2501
|
+
while (true) {
|
|
2502
|
+
const cursor = collection.find({
|
|
2503
|
+
controllerId: this.controllerId,
|
|
2504
|
+
scopeId: storageKeyArg,
|
|
2505
|
+
...(lastId ? { _id: { $gt: lastId } } : {}),
|
|
2506
|
+
}, { projection: { _id: 1 } }).sort({ _id: 1 }).limit(flexMaintenancePageLimit);
|
|
2507
|
+
let documents;
|
|
2508
|
+
try {
|
|
2509
|
+
documents = await cursor.toArray();
|
|
2510
|
+
}
|
|
2511
|
+
finally {
|
|
2512
|
+
await cursor.close();
|
|
2513
|
+
}
|
|
2514
|
+
if (documents.length === 0)
|
|
2515
|
+
break;
|
|
2516
|
+
const documentIds = documents.map((document) => document._id);
|
|
2517
|
+
await this.deleteScopeRecordBatch(leaseArg, storageKeyArg, collection, documentIds);
|
|
2518
|
+
const last = documents.at(-1);
|
|
2519
|
+
if (!last || documents.length < flexMaintenancePageLimit)
|
|
2520
|
+
break;
|
|
2521
|
+
lastId = last._id;
|
|
2522
|
+
}
|
|
2523
|
+
}
|
|
2524
|
+
}
|
|
2525
|
+
async deleteScopeRecordBatch(leaseArg, storageKeyArg, collectionArg, documentIdsArg) {
|
|
2526
|
+
return this.runLeaseTransition(leaseArg, (abortSignal, timeoutMs) => this.deleteScopeRecordBatchWithLease(leaseArg, storageKeyArg, collectionArg, documentIdsArg, abortSignal, timeoutMs));
|
|
2527
|
+
}
|
|
2528
|
+
async deleteScopeRecordBatchWithLease(leaseArg, storageKeyArg, collectionArg, documentIdsArg, abortSignalArg, timeoutMsArg) {
|
|
2529
|
+
const deadline = Date.now() + timeoutMsArg;
|
|
2530
|
+
const session = this.database.startSession();
|
|
2531
|
+
try {
|
|
2532
|
+
await session.withTransaction(async () => {
|
|
2533
|
+
abortSignalArg.throwIfAborted();
|
|
2534
|
+
const now = Date.now();
|
|
2535
|
+
const leasePostimage = await FlexWriterLeaseModel.collection.mongoDbCollection.findOneAndUpdate({
|
|
2536
|
+
id: flexWriterLeaseId(this.controllerId, storageKeyArg),
|
|
2537
|
+
controllerId: this.controllerId,
|
|
2538
|
+
storageKey: storageKeyArg,
|
|
2539
|
+
ownerToken: leaseArg.ownerToken,
|
|
2540
|
+
epoch: leaseArg.epoch,
|
|
2541
|
+
state: 'active',
|
|
2542
|
+
expiresAt: { $gt: now },
|
|
2543
|
+
}, {
|
|
2544
|
+
$set: {
|
|
2545
|
+
expiresAt: now + flexLeaseDurationMs,
|
|
2546
|
+
updatedAt: new Date(now).toISOString(),
|
|
2547
|
+
_smartdataRevision: plugins.crypto.randomUUID(),
|
|
2548
|
+
},
|
|
2549
|
+
}, {
|
|
2550
|
+
session,
|
|
2551
|
+
returnDocument: 'after',
|
|
2552
|
+
includeResultMetadata: false,
|
|
2553
|
+
});
|
|
2554
|
+
abortSignalArg.throwIfAborted();
|
|
2555
|
+
if (!leasePostimage)
|
|
2556
|
+
throw new FlexLeaseLostError(storageKeyArg);
|
|
2557
|
+
await collectionArg.deleteMany({
|
|
2558
|
+
controllerId: this.controllerId,
|
|
2559
|
+
scopeId: storageKeyArg,
|
|
2560
|
+
_id: { $in: documentIdsArg },
|
|
2561
|
+
}, { session });
|
|
2562
|
+
abortSignalArg.throwIfAborted();
|
|
2563
|
+
}, {
|
|
2564
|
+
timeoutMS: Math.max(1, deadline - Date.now()),
|
|
2565
|
+
maxCommitTimeMS: Math.max(1, deadline - Date.now()),
|
|
2566
|
+
});
|
|
2567
|
+
this.throwIfFatal();
|
|
2568
|
+
await this.verifyHeldLease(leaseArg, false, abortSignalArg, false, Math.max(1, deadline - Date.now()));
|
|
2569
|
+
}
|
|
2570
|
+
catch (errorArg) {
|
|
2571
|
+
this.throwIfFatal();
|
|
2572
|
+
const [currentLease, remaining] = await Promise.all([
|
|
2573
|
+
FlexWriterLeaseModel.collection.mongoDbCollection.findOne({
|
|
2574
|
+
id: flexWriterLeaseId(this.controllerId, storageKeyArg),
|
|
2575
|
+
}, {
|
|
2576
|
+
signal: abortSignalArg,
|
|
2577
|
+
timeoutMS: Math.max(1, deadline - Date.now()),
|
|
2578
|
+
}),
|
|
2579
|
+
collectionArg.countDocuments({ _id: { $in: documentIdsArg } }, {
|
|
2580
|
+
signal: abortSignalArg,
|
|
2581
|
+
timeoutMS: Math.max(1, deadline - Date.now()),
|
|
2582
|
+
}),
|
|
2583
|
+
]);
|
|
2584
|
+
const uncertainTransition = leaseArg.uncertainTransition;
|
|
2585
|
+
if (currentLease
|
|
2586
|
+
&& uncertainTransition
|
|
2587
|
+
&& leaseTransitionImagesEqual(currentLease, uncertainTransition.postimage)) {
|
|
2588
|
+
leaseArg.ownerToken = currentLease.ownerToken;
|
|
2589
|
+
leaseArg.epoch = currentLease.epoch;
|
|
2590
|
+
leaseArg.expiresAt = currentLease.expiresAt;
|
|
2591
|
+
leaseArg.uncertainTransition = undefined;
|
|
2592
|
+
}
|
|
2593
|
+
const sameLease = !!currentLease
|
|
2594
|
+
&& currentLease.controllerId === this.controllerId
|
|
2595
|
+
&& currentLease.storageKey === storageKeyArg
|
|
2596
|
+
&& currentLease.ownerToken === leaseArg.ownerToken
|
|
2597
|
+
&& currentLease.epoch === leaseArg.epoch
|
|
2598
|
+
&& currentLease.state === 'active'
|
|
2599
|
+
&& currentLease.expiresAt > Date.now();
|
|
2600
|
+
if (sameLease && remaining === 0) {
|
|
2601
|
+
leaseArg.expiresAt = currentLease.expiresAt;
|
|
2602
|
+
return;
|
|
2603
|
+
}
|
|
2604
|
+
if (!sameLease) {
|
|
2605
|
+
if (uncertainTransition
|
|
2606
|
+
&& currentLease
|
|
2607
|
+
&& leaseTransitionImagesEqual(currentLease, uncertainTransition.preimage))
|
|
2608
|
+
throw errorArg;
|
|
2609
|
+
throw this.markLeaseLost(leaseArg);
|
|
2610
|
+
}
|
|
2611
|
+
throw errorArg;
|
|
2612
|
+
}
|
|
2613
|
+
finally {
|
|
2614
|
+
await session.endSession();
|
|
2615
|
+
}
|
|
2616
|
+
}
|
|
2617
|
+
async runStorage(storageKeyArg, operationArg) {
|
|
2618
|
+
assertIdentifier(storageKeyArg, 'storageKey');
|
|
2619
|
+
this.throwIfFatal();
|
|
2620
|
+
await this.init();
|
|
2621
|
+
if (this.closed)
|
|
2622
|
+
throw new Error('The Flex store is closed.');
|
|
2623
|
+
const prior = this.storageQueues.get(storageKeyArg) ?? Promise.resolve();
|
|
2624
|
+
const operation = prior.catch(() => undefined).then(async () => {
|
|
2625
|
+
this.throwIfFatal();
|
|
2626
|
+
if (this.closed)
|
|
2627
|
+
throw new Error('The Flex store is closed.');
|
|
2628
|
+
const lease = await this.ensureLease(storageKeyArg);
|
|
2629
|
+
if (this.closed) {
|
|
2630
|
+
await this.releaseHeldLease(lease, this.closeDrainTimeoutMs);
|
|
2631
|
+
throw new Error('The Flex store is closed.');
|
|
2632
|
+
}
|
|
2633
|
+
return operationArg(lease);
|
|
2634
|
+
});
|
|
2635
|
+
const settled = operation.then(() => undefined, () => undefined);
|
|
2636
|
+
this.storageQueues.set(storageKeyArg, settled);
|
|
2637
|
+
void settled.then(() => {
|
|
2638
|
+
if (this.storageQueues.get(storageKeyArg) === settled) {
|
|
2639
|
+
this.storageQueues.delete(storageKeyArg);
|
|
2640
|
+
}
|
|
2641
|
+
});
|
|
2642
|
+
return operation;
|
|
2643
|
+
}
|
|
2644
|
+
async ensureLease(storageKeyArg) {
|
|
2645
|
+
this.throwIfFatal();
|
|
2646
|
+
if (this.closed)
|
|
2647
|
+
throw new Error('The Flex store is closed.');
|
|
2648
|
+
const held = this.heldLeases.get(storageKeyArg);
|
|
2649
|
+
if (held) {
|
|
2650
|
+
if (held.lost || held.releasing)
|
|
2651
|
+
throw new FlexLeaseLostError(storageKeyArg);
|
|
2652
|
+
await this.runLeaseTransition(held, (abortSignal, timeoutMs) => this.verifyHeldLease(held, true, abortSignal, false, timeoutMs));
|
|
2653
|
+
return held;
|
|
2654
|
+
}
|
|
2655
|
+
const id = flexWriterLeaseId(this.controllerId, storageKeyArg);
|
|
2656
|
+
const ownerToken = randomOwnerToken();
|
|
2657
|
+
while (true) {
|
|
2658
|
+
if (this.closed)
|
|
2659
|
+
throw new Error('The Flex store is closed.');
|
|
2660
|
+
const now = Date.now();
|
|
2661
|
+
const current = await FlexWriterLeaseModel.exact.findStoredOne({ id });
|
|
2662
|
+
if (!current) {
|
|
2663
|
+
const document = {
|
|
2664
|
+
id,
|
|
2665
|
+
controllerId: this.controllerId,
|
|
2666
|
+
storageKey: storageKeyArg,
|
|
2667
|
+
ownerToken,
|
|
2668
|
+
epoch: 1,
|
|
2669
|
+
state: 'active',
|
|
2670
|
+
expiresAt: now + flexLeaseDurationMs,
|
|
2671
|
+
updatedAt: new Date(now).toISOString(),
|
|
2672
|
+
};
|
|
2673
|
+
assertFlexWriterLeaseDocument(document);
|
|
2674
|
+
const insertion = await FlexWriterLeaseModel.exact.insert(document);
|
|
2675
|
+
if (insertion.status === 'conflict')
|
|
2676
|
+
continue;
|
|
2677
|
+
const lease = {
|
|
2678
|
+
storageKey: storageKeyArg,
|
|
2679
|
+
ownerToken,
|
|
2680
|
+
epoch: 1,
|
|
2681
|
+
expiresAt: document.expiresAt,
|
|
2682
|
+
lost: false,
|
|
2683
|
+
releasing: false,
|
|
2684
|
+
};
|
|
2685
|
+
this.heldLeases.set(storageKeyArg, lease);
|
|
2686
|
+
if (this.closed) {
|
|
2687
|
+
await this.releaseHeldLease(lease, this.closeDrainTimeoutMs);
|
|
2688
|
+
throw new Error('The Flex store is closed.');
|
|
2689
|
+
}
|
|
2690
|
+
this.startLeaseHeartbeat();
|
|
2691
|
+
return lease;
|
|
2692
|
+
}
|
|
2693
|
+
const body = leaseBody(current);
|
|
2694
|
+
assertFlexWriterLeaseDocument(body);
|
|
2695
|
+
if (body.id !== id
|
|
2696
|
+
|| body.controllerId !== this.controllerId
|
|
2697
|
+
|| body.storageKey !== storageKeyArg) {
|
|
2698
|
+
throw new plugins.flexharness.FlexHarnessStoreFormatError('Flex writer lease identity mismatch.');
|
|
2699
|
+
}
|
|
2700
|
+
if (body.state === 'active' && body.expiresAt > now) {
|
|
2701
|
+
throw new Error(`Storage key "${storageKeyArg}" has an active foreign Flex writer lease.`);
|
|
2702
|
+
}
|
|
2703
|
+
const transition = await FlexWriterLeaseModel.exact.transition({
|
|
2704
|
+
current,
|
|
2705
|
+
change: (model) => {
|
|
2706
|
+
model.ownerToken = ownerToken;
|
|
2707
|
+
model.epoch = current.epoch + 1;
|
|
2708
|
+
model.state = 'active';
|
|
2709
|
+
model.expiresAt = now + flexLeaseDurationMs;
|
|
2710
|
+
model.updatedAt = new Date(now).toISOString();
|
|
2711
|
+
},
|
|
2712
|
+
});
|
|
2713
|
+
if (transition.status === 'concurrent_change')
|
|
2714
|
+
continue;
|
|
2715
|
+
const lease = {
|
|
2716
|
+
storageKey: storageKeyArg,
|
|
2717
|
+
ownerToken,
|
|
2718
|
+
epoch: current.epoch + 1,
|
|
2719
|
+
expiresAt: now + flexLeaseDurationMs,
|
|
2720
|
+
lost: false,
|
|
2721
|
+
releasing: false,
|
|
2722
|
+
};
|
|
2723
|
+
this.heldLeases.set(storageKeyArg, lease);
|
|
2724
|
+
if (this.closed) {
|
|
2725
|
+
await this.releaseHeldLease(lease, this.closeDrainTimeoutMs);
|
|
2726
|
+
throw new Error('The Flex store is closed.');
|
|
2727
|
+
}
|
|
2728
|
+
this.startLeaseHeartbeat();
|
|
2729
|
+
return lease;
|
|
2730
|
+
}
|
|
2731
|
+
}
|
|
2732
|
+
async verifyHeldLease(leaseArg, renewIfNeededArg, abortSignalArg, forceRenewalArg = false, timeoutMsArg = flexMaintenanceOperationTimeoutMs) {
|
|
2733
|
+
if (leaseArg.lost)
|
|
2734
|
+
throw new FlexLeaseLostError(leaseArg.storageKey);
|
|
2735
|
+
this.throwIfFatal();
|
|
2736
|
+
const id = flexWriterLeaseId(this.controllerId, leaseArg.storageKey);
|
|
2737
|
+
const collection = FlexWriterLeaseModel.collection.mongoDbCollection;
|
|
2738
|
+
const deadline = Date.now() + timeoutMsArg;
|
|
2739
|
+
const operationOptions = () => ({
|
|
2740
|
+
timeoutMS: Math.max(1, deadline - Date.now()),
|
|
2741
|
+
...(abortSignalArg ? { signal: abortSignalArg } : {}),
|
|
2742
|
+
});
|
|
2743
|
+
while (true) {
|
|
2744
|
+
abortSignalArg?.throwIfAborted();
|
|
2745
|
+
this.throwIfFatal();
|
|
2746
|
+
if (Date.now() >= deadline) {
|
|
2747
|
+
throw new plugins.smartdata.SmartdataExactPersistenceError('ambiguous_write', `Flex writer lease transition for "${leaseArg.storageKey}" exceeded its deadline.`);
|
|
2748
|
+
}
|
|
2749
|
+
const uncertain = leaseArg.uncertainTransition;
|
|
2750
|
+
if (uncertain) {
|
|
2751
|
+
let current;
|
|
2752
|
+
try {
|
|
2753
|
+
current = await collection.findOne({ id }, operationOptions());
|
|
2754
|
+
}
|
|
2755
|
+
catch (readbackError) {
|
|
2756
|
+
if (uncertain.postimage.expiresAt <= Date.now()) {
|
|
2757
|
+
throw this.markLeaseLost(leaseArg);
|
|
2758
|
+
}
|
|
2759
|
+
throw new plugins.smartdata.SmartdataExactPersistenceError('ambiguous_write', `Flex writer lease transition for "${leaseArg.storageKey}" remains uncertain.`, { cause: readbackError });
|
|
2760
|
+
}
|
|
2761
|
+
this.throwIfFatal();
|
|
2762
|
+
if (uncertain.postimage.expiresAt <= Date.now()) {
|
|
2763
|
+
throw this.markLeaseLost(leaseArg);
|
|
2764
|
+
}
|
|
2765
|
+
if (current && leaseTransitionImagesEqual(current, uncertain.postimage)) {
|
|
2766
|
+
leaseArg.ownerToken = current.ownerToken;
|
|
2767
|
+
leaseArg.epoch = current.epoch;
|
|
2768
|
+
leaseArg.expiresAt = current.expiresAt;
|
|
2769
|
+
leaseArg.uncertainTransition = undefined;
|
|
2770
|
+
continue;
|
|
2771
|
+
}
|
|
2772
|
+
if (!current || !leaseTransitionImagesEqual(current, uncertain.preimage)) {
|
|
2773
|
+
throw this.markLeaseLost(leaseArg);
|
|
2774
|
+
}
|
|
2775
|
+
let transition;
|
|
2776
|
+
try {
|
|
2777
|
+
transition = await collection.findOneAndReplace({
|
|
2778
|
+
_id: uncertain.preimage._id,
|
|
2779
|
+
...leaseBody(uncertain.preimage),
|
|
2780
|
+
_smartdataRevision: smartRevisionSelector(uncertain.preimage),
|
|
2781
|
+
}, {
|
|
2782
|
+
...leaseBody(uncertain.postimage),
|
|
2783
|
+
_smartdataRevision: uncertain.postimage._smartdataRevision,
|
|
2784
|
+
}, {
|
|
2785
|
+
returnDocument: 'after',
|
|
2786
|
+
includeResultMetadata: false,
|
|
2787
|
+
...operationOptions(),
|
|
2788
|
+
});
|
|
2789
|
+
}
|
|
2790
|
+
catch {
|
|
2791
|
+
await waitForFlexStoreRetry(10, abortSignalArg);
|
|
2792
|
+
continue;
|
|
2793
|
+
}
|
|
2794
|
+
this.throwIfFatal();
|
|
2795
|
+
if (transition && leaseTransitionImagesEqual(transition, uncertain.postimage)) {
|
|
2796
|
+
leaseArg.ownerToken = transition.ownerToken;
|
|
2797
|
+
leaseArg.epoch = transition.epoch;
|
|
2798
|
+
leaseArg.expiresAt = transition.expiresAt;
|
|
2799
|
+
leaseArg.uncertainTransition = undefined;
|
|
2800
|
+
continue;
|
|
2801
|
+
}
|
|
2802
|
+
if (transition && !leaseTransitionImagesEqual(transition, uncertain.preimage)) {
|
|
2803
|
+
throw this.markLeaseLost(leaseArg);
|
|
2804
|
+
}
|
|
2805
|
+
await waitForFlexStoreRetry(10, abortSignalArg);
|
|
2806
|
+
continue;
|
|
2807
|
+
}
|
|
2808
|
+
let current;
|
|
2809
|
+
try {
|
|
2810
|
+
current = await collection.findOne({ id }, operationOptions());
|
|
2811
|
+
}
|
|
2812
|
+
catch (readError) {
|
|
2813
|
+
if (leaseArg.expiresAt <= Date.now())
|
|
2814
|
+
throw this.markLeaseLost(leaseArg);
|
|
2815
|
+
throw readError;
|
|
2816
|
+
}
|
|
2817
|
+
this.throwIfFatal();
|
|
2818
|
+
if (!current
|
|
2819
|
+
|| current.controllerId !== this.controllerId
|
|
2820
|
+
|| current.storageKey !== leaseArg.storageKey
|
|
2821
|
+
|| current.ownerToken !== leaseArg.ownerToken
|
|
2822
|
+
|| current.epoch !== leaseArg.epoch
|
|
2823
|
+
|| current.state !== 'active') {
|
|
2824
|
+
throw this.markLeaseLost(leaseArg);
|
|
2825
|
+
}
|
|
2826
|
+
leaseArg.expiresAt = current.expiresAt;
|
|
2827
|
+
const now = Date.now();
|
|
2828
|
+
const expired = current.expiresAt <= now;
|
|
2829
|
+
if (!expired
|
|
2830
|
+
&& (!renewIfNeededArg
|
|
2831
|
+
|| (!forceRenewalArg && current.expiresAt - now > flexLeaseHeartbeatMs)))
|
|
2832
|
+
return;
|
|
2833
|
+
const previousOwnerToken = leaseArg.ownerToken;
|
|
2834
|
+
const previousEpoch = leaseArg.epoch;
|
|
2835
|
+
const nextOwnerToken = expired ? randomOwnerToken() : previousOwnerToken;
|
|
2836
|
+
const nextEpoch = expired ? previousEpoch + 1 : previousEpoch;
|
|
2837
|
+
const nextRevision = plugins.crypto.randomUUID();
|
|
2838
|
+
const next = {
|
|
2839
|
+
...leaseBody(current),
|
|
2840
|
+
ownerToken: nextOwnerToken,
|
|
2841
|
+
epoch: nextEpoch,
|
|
2842
|
+
expiresAt: now + flexLeaseDurationMs,
|
|
2843
|
+
updatedAt: new Date(now).toISOString(),
|
|
2844
|
+
};
|
|
2845
|
+
assertFlexWriterLeaseDocument(next);
|
|
2846
|
+
const uncertainTransition = {
|
|
2847
|
+
preimage: leaseTransitionImage(current),
|
|
2848
|
+
postimage: leaseTransitionImage({
|
|
2849
|
+
_id: current._id,
|
|
2850
|
+
...next,
|
|
2851
|
+
_smartdataRevision: nextRevision,
|
|
2852
|
+
}),
|
|
2853
|
+
};
|
|
2854
|
+
leaseArg.uncertainTransition = uncertainTransition;
|
|
2855
|
+
let transition;
|
|
2856
|
+
try {
|
|
2857
|
+
transition = await collection.findOneAndReplace({
|
|
2858
|
+
_id: uncertainTransition.preimage._id,
|
|
2859
|
+
...leaseBody(uncertainTransition.preimage),
|
|
2860
|
+
_smartdataRevision: smartRevisionSelector(uncertainTransition.preimage),
|
|
2861
|
+
}, {
|
|
2862
|
+
...leaseBody(uncertainTransition.postimage),
|
|
2863
|
+
_smartdataRevision: uncertainTransition.postimage._smartdataRevision,
|
|
2864
|
+
}, {
|
|
2865
|
+
returnDocument: 'after',
|
|
2866
|
+
includeResultMetadata: false,
|
|
2867
|
+
...operationOptions(),
|
|
2868
|
+
});
|
|
2869
|
+
}
|
|
2870
|
+
catch {
|
|
2871
|
+
continue;
|
|
2872
|
+
}
|
|
2873
|
+
this.throwIfFatal();
|
|
2874
|
+
if (transition && leaseTransitionImagesEqual(transition, uncertainTransition.postimage)) {
|
|
2875
|
+
leaseArg.ownerToken = nextOwnerToken;
|
|
2876
|
+
leaseArg.epoch = nextEpoch;
|
|
2877
|
+
leaseArg.expiresAt = transition.expiresAt;
|
|
2878
|
+
leaseArg.uncertainTransition = undefined;
|
|
2879
|
+
if (transition.expiresAt > Date.now())
|
|
2880
|
+
return;
|
|
2881
|
+
await waitForFlexStoreRetry(10, abortSignalArg);
|
|
2882
|
+
continue;
|
|
2883
|
+
}
|
|
2884
|
+
if (transition && !leaseTransitionImagesEqual(transition, uncertainTransition.preimage)) {
|
|
2885
|
+
throw this.markLeaseLost(leaseArg);
|
|
2886
|
+
}
|
|
2887
|
+
await waitForFlexStoreRetry(10, abortSignalArg);
|
|
2888
|
+
}
|
|
2889
|
+
}
|
|
2890
|
+
async runLeaseTransition(leaseArg, operationArg) {
|
|
2891
|
+
this.throwIfFatal();
|
|
2892
|
+
const deadline = Date.now() + this.leaseTransitionTimeoutMs;
|
|
2893
|
+
const abortController = new AbortController();
|
|
2894
|
+
this.leaseTransitionAbortControllers.add(abortController);
|
|
2895
|
+
const prior = leaseArg.transitionTask ?? Promise.resolve();
|
|
2896
|
+
const operation = prior.catch(() => undefined).then(async () => {
|
|
2897
|
+
this.throwIfFatal();
|
|
2898
|
+
if (leaseArg.lost)
|
|
2899
|
+
throw new FlexLeaseLostError(leaseArg.storageKey);
|
|
2900
|
+
abortController.signal.throwIfAborted();
|
|
2901
|
+
if (leaseArg.uncertainTransition) {
|
|
2902
|
+
await this.verifyHeldLease(leaseArg, false, abortController.signal, false, Math.max(1, deadline - Date.now()));
|
|
2903
|
+
}
|
|
2904
|
+
abortController.signal.throwIfAborted();
|
|
2905
|
+
return operationArg(abortController.signal, Math.max(1, deadline - Date.now()));
|
|
2906
|
+
});
|
|
2907
|
+
let operationSettled = false;
|
|
2908
|
+
const settled = operation.then(() => { operationSettled = true; }, () => { operationSettled = true; });
|
|
2909
|
+
leaseArg.transitionTask = settled;
|
|
2910
|
+
void settled.then(() => {
|
|
2911
|
+
this.leaseTransitionAbortControllers.delete(abortController);
|
|
2912
|
+
if (leaseArg.transitionTask === settled)
|
|
2913
|
+
leaseArg.transitionTask = undefined;
|
|
2914
|
+
});
|
|
2915
|
+
try {
|
|
2916
|
+
await waitForFlexStoreDeadline(prior, Math.max(1, deadline - Date.now()), `Flex writer lease transition queue for "${leaseArg.storageKey}" stalled.`);
|
|
2917
|
+
}
|
|
2918
|
+
catch (errorArg) {
|
|
2919
|
+
abortController.abort(errorArg);
|
|
2920
|
+
throw this.failStore(errorArg, leaseArg);
|
|
2921
|
+
}
|
|
2922
|
+
try {
|
|
2923
|
+
return await waitForFlexStoreDeadline(operation, Math.max(1, deadline - Date.now()), `Flex writer lease transition for "${leaseArg.storageKey}" stalled.`);
|
|
2924
|
+
}
|
|
2925
|
+
catch (errorArg) {
|
|
2926
|
+
if (!operationSettled) {
|
|
2927
|
+
abortController.abort(errorArg);
|
|
2928
|
+
throw this.failStore(errorArg, leaseArg);
|
|
2929
|
+
}
|
|
2930
|
+
throw errorArg;
|
|
2931
|
+
}
|
|
2932
|
+
}
|
|
2933
|
+
throwIfFatal() {
|
|
2934
|
+
if (this.fatalError)
|
|
2935
|
+
throw this.fatalError;
|
|
2936
|
+
}
|
|
2937
|
+
markLeaseLost(leaseArg) {
|
|
2938
|
+
return this.failStore(new FlexLeaseLostError(leaseArg.storageKey), leaseArg);
|
|
2939
|
+
}
|
|
2940
|
+
failStore(errorArg, leaseArg) {
|
|
2941
|
+
const error = errorArg instanceof Error ? errorArg : new Error(String(errorArg));
|
|
2942
|
+
if (leaseArg)
|
|
2943
|
+
leaseArg.lost = true;
|
|
2944
|
+
if (this.fatalError)
|
|
2945
|
+
return this.fatalError;
|
|
2946
|
+
this.fatalError = error;
|
|
2947
|
+
this.heartbeatsOpen = false;
|
|
2948
|
+
this.maintenanceOpen = false;
|
|
2949
|
+
this.maintenanceAbortController.abort(error);
|
|
2950
|
+
if (this.orphanMaintenanceTimer) {
|
|
2951
|
+
clearTimeout(this.orphanMaintenanceTimer);
|
|
2952
|
+
this.orphanMaintenanceTimer = undefined;
|
|
2953
|
+
}
|
|
2954
|
+
if (this.leaseHeartbeatTimer) {
|
|
2955
|
+
clearInterval(this.leaseHeartbeatTimer);
|
|
2956
|
+
this.leaseHeartbeatTimer = undefined;
|
|
2957
|
+
}
|
|
2958
|
+
for (const controller of this.leaseTransitionAbortControllers)
|
|
2959
|
+
controller.abort(error);
|
|
2960
|
+
for (const lease of this.heldLeases.values()) {
|
|
2961
|
+
lease.lost = true;
|
|
2962
|
+
lease.heartbeatAbortController?.abort(error);
|
|
2963
|
+
}
|
|
2964
|
+
try {
|
|
2965
|
+
this.onFatalError?.(error);
|
|
2966
|
+
}
|
|
2967
|
+
catch {
|
|
2968
|
+
// Store fencing is independent from health-listener behavior.
|
|
2969
|
+
}
|
|
2970
|
+
return error;
|
|
2971
|
+
}
|
|
2972
|
+
startLeaseHeartbeat() {
|
|
2973
|
+
if (this.leaseHeartbeatTimer || !this.heartbeatsOpen)
|
|
2974
|
+
return;
|
|
2975
|
+
this.leaseHeartbeatTimer = setInterval(() => this.heartbeatHeldLeases(), flexLeaseHeartbeatMs);
|
|
2976
|
+
this.leaseHeartbeatTimer.unref?.();
|
|
2977
|
+
}
|
|
2978
|
+
heartbeatHeldLeases() {
|
|
2979
|
+
for (const lease of this.heldLeases.values()) {
|
|
2980
|
+
if (lease.lost || lease.releasing || lease.heartbeatTask)
|
|
2981
|
+
continue;
|
|
2982
|
+
const abortController = new AbortController();
|
|
2983
|
+
const task = this.runLeaseTransition(lease, (transitionSignal, timeoutMs) => (this.verifyHeldLease(lease, true, AbortSignal.any([abortController.signal, transitionSignal]), true, Math.min(timeoutMs, flexLeaseHeartbeatOperationTimeoutMs)))).catch((errorArg) => {
|
|
2984
|
+
if (errorArg instanceof FlexLeaseLostError) {
|
|
2985
|
+
if (!lease.releasing)
|
|
2986
|
+
lease.lost = true;
|
|
2987
|
+
return;
|
|
2988
|
+
}
|
|
2989
|
+
if (!lease.releasing && this.heartbeatsOpen && !abortController.signal.aborted) {
|
|
2990
|
+
console.error(`Flex writer lease heartbeat for "${lease.storageKey}" failed; retrying on the next interval.`, errorArg);
|
|
2991
|
+
}
|
|
2992
|
+
}).finally(() => {
|
|
2993
|
+
if (lease.heartbeatTask === task)
|
|
2994
|
+
lease.heartbeatTask = undefined;
|
|
2995
|
+
if (lease.heartbeatAbortController === abortController) {
|
|
2996
|
+
lease.heartbeatAbortController = undefined;
|
|
2997
|
+
}
|
|
2998
|
+
});
|
|
2999
|
+
lease.heartbeatAbortController = abortController;
|
|
3000
|
+
lease.heartbeatTask = task;
|
|
3001
|
+
}
|
|
3002
|
+
}
|
|
3003
|
+
async releaseHeldLease(leaseArg, timeoutMsArg = flexMaintenanceOperationTimeoutMs) {
|
|
3004
|
+
const deadline = Date.now() + timeoutMsArg;
|
|
3005
|
+
leaseArg.releasing = true;
|
|
3006
|
+
try {
|
|
3007
|
+
const heartbeatTask = leaseArg.heartbeatTask;
|
|
3008
|
+
const heartbeatAbortController = leaseArg.heartbeatAbortController;
|
|
3009
|
+
heartbeatAbortController?.abort(new Error('The Flex writer lease is being released.'));
|
|
3010
|
+
if (heartbeatTask) {
|
|
3011
|
+
await waitForFlexStoreDeadline(heartbeatTask, Math.max(1, deadline - Date.now()), `Flex writer lease heartbeat for "${leaseArg.storageKey}" did not stop before the release deadline.`);
|
|
3012
|
+
if (leaseArg.heartbeatTask === heartbeatTask)
|
|
3013
|
+
leaseArg.heartbeatTask = undefined;
|
|
3014
|
+
if (leaseArg.heartbeatAbortController === heartbeatAbortController) {
|
|
3015
|
+
leaseArg.heartbeatAbortController = undefined;
|
|
3016
|
+
}
|
|
3017
|
+
}
|
|
3018
|
+
const transitionTask = leaseArg.transitionTask;
|
|
3019
|
+
if (transitionTask) {
|
|
3020
|
+
try {
|
|
3021
|
+
await waitForFlexStoreDeadline(transitionTask, Math.max(1, deadline - Date.now()), `Flex writer lease transition for "${leaseArg.storageKey}" did not stop before the release deadline.`);
|
|
3022
|
+
}
|
|
3023
|
+
catch {
|
|
3024
|
+
leaseArg.lost = true;
|
|
3025
|
+
}
|
|
3026
|
+
}
|
|
3027
|
+
if (leaseArg.lost || this.fatalError) {
|
|
3028
|
+
this.forgetHeldLease(leaseArg);
|
|
3029
|
+
if (this.closed)
|
|
3030
|
+
this.leaseTransitionAbortControllers.clear();
|
|
3031
|
+
return;
|
|
3032
|
+
}
|
|
3033
|
+
const remainingMs = deadline - Date.now();
|
|
3034
|
+
if (remainingMs <= 0) {
|
|
3035
|
+
throw new plugins.smartdata.SmartdataExactPersistenceError('ambiguous_write', `Flex writer lease release for "${leaseArg.storageKey}" exceeded its deadline.`);
|
|
3036
|
+
}
|
|
3037
|
+
await this.releaseLease(leaseArg, remainingMs);
|
|
3038
|
+
this.forgetHeldLease(leaseArg);
|
|
3039
|
+
}
|
|
3040
|
+
catch (errorArg) {
|
|
3041
|
+
leaseArg.releasing = false;
|
|
3042
|
+
if (!this.heldLeases.has(leaseArg.storageKey)) {
|
|
3043
|
+
this.heldLeases.set(leaseArg.storageKey, leaseArg);
|
|
3044
|
+
}
|
|
3045
|
+
throw errorArg;
|
|
3046
|
+
}
|
|
3047
|
+
}
|
|
3048
|
+
forgetHeldLease(leaseArg) {
|
|
3049
|
+
if (this.heldLeases.get(leaseArg.storageKey) === leaseArg) {
|
|
3050
|
+
this.heldLeases.delete(leaseArg.storageKey);
|
|
3051
|
+
}
|
|
3052
|
+
if (this.heldLeases.size === 0 && this.leaseHeartbeatTimer) {
|
|
3053
|
+
clearInterval(this.leaseHeartbeatTimer);
|
|
3054
|
+
this.leaseHeartbeatTimer = undefined;
|
|
3055
|
+
}
|
|
3056
|
+
}
|
|
3057
|
+
async releaseLease(leaseArg, timeoutMsArg = flexMaintenanceOperationTimeoutMs) {
|
|
3058
|
+
const id = flexWriterLeaseId(this.controllerId, leaseArg.storageKey);
|
|
3059
|
+
const collection = FlexWriterLeaseModel.collection.mongoDbCollection;
|
|
3060
|
+
const deadline = Date.now() + timeoutMsArg;
|
|
3061
|
+
while (Date.now() < deadline) {
|
|
3062
|
+
const remainingMs = Math.max(1, deadline - Date.now());
|
|
3063
|
+
const current = await collection.findOne({ id }, { timeoutMS: remainingMs });
|
|
3064
|
+
if (!current
|
|
3065
|
+
|| current.ownerToken !== leaseArg.ownerToken
|
|
3066
|
+
|| current.epoch !== leaseArg.epoch
|
|
3067
|
+
|| current.state === 'released')
|
|
3068
|
+
return;
|
|
3069
|
+
const now = Date.now();
|
|
3070
|
+
const next = {
|
|
3071
|
+
...leaseBody(current),
|
|
3072
|
+
state: 'released',
|
|
3073
|
+
expiresAt: now,
|
|
3074
|
+
updatedAt: new Date(now).toISOString(),
|
|
3075
|
+
};
|
|
3076
|
+
assertFlexWriterLeaseDocument(next);
|
|
3077
|
+
const transition = await collection.findOneAndReplace({
|
|
3078
|
+
_id: current._id,
|
|
3079
|
+
id,
|
|
3080
|
+
ownerToken: leaseArg.ownerToken,
|
|
3081
|
+
epoch: leaseArg.epoch,
|
|
3082
|
+
state: current.state,
|
|
3083
|
+
_smartdataRevision: smartRevisionSelector(current),
|
|
3084
|
+
}, {
|
|
3085
|
+
...next,
|
|
3086
|
+
_smartdataRevision: plugins.crypto.randomUUID(),
|
|
3087
|
+
}, {
|
|
3088
|
+
returnDocument: 'after',
|
|
3089
|
+
includeResultMetadata: false,
|
|
3090
|
+
timeoutMS: Math.max(1, deadline - Date.now()),
|
|
3091
|
+
});
|
|
3092
|
+
if (transition)
|
|
3093
|
+
return;
|
|
3094
|
+
}
|
|
3095
|
+
throw new plugins.smartdata.SmartdataExactPersistenceError('ambiguous_write', `Flex writer lease release for "${leaseArg.storageKey}" exceeded its deadline.`);
|
|
3096
|
+
}
|
|
3097
|
+
async cleanupPrivateByCandidate(manifestArg, timeoutMsArg) {
|
|
3098
|
+
const options = timeoutMsArg === undefined ? {} : { timeoutMS: timeoutMsArg };
|
|
3099
|
+
await FlexPrivateChunkModel.collection.mongoDbCollection.deleteMany({
|
|
3100
|
+
controllerId: this.controllerId,
|
|
3101
|
+
candidateId: manifestArg.candidateId,
|
|
3102
|
+
}, options);
|
|
3103
|
+
await FlexPrivateCandidateModel.collection.mongoDbCollection.deleteMany({
|
|
3104
|
+
controllerId: this.controllerId,
|
|
3105
|
+
candidateId: manifestArg.candidateId,
|
|
3106
|
+
}, options);
|
|
3107
|
+
}
|
|
3108
|
+
async cleanupProjectionSourceByCandidate(candidateIdArg, timeoutMsArg) {
|
|
3109
|
+
const filter = { controllerId: this.controllerId, candidateId: candidateIdArg };
|
|
3110
|
+
const options = timeoutMsArg === undefined ? {} : { timeoutMS: timeoutMsArg };
|
|
3111
|
+
await FlexProjectionMessageRecordModel.collection.mongoDbCollection.deleteMany(filter, options);
|
|
3112
|
+
await FlexProjectionSourceModel.collection.mongoDbCollection.deleteMany(filter, options);
|
|
3113
|
+
}
|
|
3114
|
+
async cleanupPublicByCandidate(manifestArg, storageKeyArg, timeoutMsArg) {
|
|
3115
|
+
await Promise.all([
|
|
3116
|
+
FlexPublicSessionRecordModel.collection.mongoDbCollection.deleteMany({
|
|
3117
|
+
controllerId: this.controllerId,
|
|
3118
|
+
scopeId: storageKeyArg,
|
|
3119
|
+
candidateId: manifestArg.candidateId,
|
|
3120
|
+
}, timeoutMsArg === undefined ? {} : { timeoutMS: timeoutMsArg }),
|
|
3121
|
+
FlexPublicMessageRecordModel.collection.mongoDbCollection.deleteMany({
|
|
3122
|
+
controllerId: this.controllerId,
|
|
3123
|
+
scopeId: storageKeyArg,
|
|
3124
|
+
candidateId: manifestArg.candidateId,
|
|
3125
|
+
}, timeoutMsArg === undefined ? {} : { timeoutMS: timeoutMsArg }),
|
|
3126
|
+
]);
|
|
3127
|
+
await FlexPublicCandidateModel.collection.mongoDbCollection.deleteMany({
|
|
3128
|
+
controllerId: this.controllerId,
|
|
3129
|
+
scopeId: storageKeyArg,
|
|
3130
|
+
candidateId: manifestArg.candidateId,
|
|
3131
|
+
}, timeoutMsArg === undefined ? {} : { timeoutMS: timeoutMsArg });
|
|
3132
|
+
}
|
|
3133
|
+
async ensureMaintenanceLease(storageKeyArg, abortSignalArg) {
|
|
3134
|
+
abortSignalArg.throwIfAborted();
|
|
3135
|
+
const id = flexWriterLeaseId(this.controllerId, storageKeyArg);
|
|
3136
|
+
const collection = FlexWriterLeaseModel.collection.mongoDbCollection;
|
|
3137
|
+
const readLease = async (withAbortSignalArg = true) => {
|
|
3138
|
+
const raw = await collection.findOne({ id }, {
|
|
3139
|
+
...(withAbortSignalArg ? { signal: abortSignalArg } : {}),
|
|
3140
|
+
timeoutMS: flexMaintenanceOperationTimeoutMs,
|
|
3141
|
+
});
|
|
3142
|
+
if (!raw)
|
|
3143
|
+
return null;
|
|
3144
|
+
const body = leaseBody(raw);
|
|
3145
|
+
assertFlexWriterLeaseDocument(body);
|
|
3146
|
+
if (body.id !== id
|
|
3147
|
+
|| body.controllerId !== this.controllerId
|
|
3148
|
+
|| body.storageKey !== storageKeyArg) {
|
|
3149
|
+
throw new plugins.flexharness.FlexHarnessStoreFormatError('Flex writer lease identity mismatch.');
|
|
3150
|
+
}
|
|
3151
|
+
return raw;
|
|
3152
|
+
};
|
|
3153
|
+
const held = this.heldLeases.get(storageKeyArg);
|
|
3154
|
+
if (held) {
|
|
3155
|
+
if (held.lost || held.releasing)
|
|
3156
|
+
return undefined;
|
|
3157
|
+
try {
|
|
3158
|
+
await this.runLeaseTransition(held, (transitionSignal, timeoutMs) => this.verifyHeldLease(held, false, AbortSignal.any([abortSignalArg, transitionSignal]), false, Math.min(timeoutMs, flexMaintenanceOperationTimeoutMs)));
|
|
3159
|
+
}
|
|
3160
|
+
catch (errorArg) {
|
|
3161
|
+
if (abortSignalArg.aborted)
|
|
3162
|
+
throw abortSignalArg.reason;
|
|
3163
|
+
return undefined;
|
|
3164
|
+
}
|
|
3165
|
+
return { lease: held, acquired: false };
|
|
3166
|
+
}
|
|
3167
|
+
const ownerToken = randomOwnerToken();
|
|
3168
|
+
const now = Date.now();
|
|
3169
|
+
let current = await readLease();
|
|
3170
|
+
if (!current) {
|
|
3171
|
+
const document = {
|
|
3172
|
+
id,
|
|
3173
|
+
controllerId: this.controllerId,
|
|
3174
|
+
storageKey: storageKeyArg,
|
|
3175
|
+
ownerToken,
|
|
3176
|
+
epoch: 1,
|
|
3177
|
+
state: 'active',
|
|
3178
|
+
expiresAt: now + flexLeaseDurationMs,
|
|
3179
|
+
updatedAt: new Date(now).toISOString(),
|
|
3180
|
+
};
|
|
3181
|
+
assertFlexWriterLeaseDocument(document);
|
|
3182
|
+
try {
|
|
3183
|
+
await collection.insertOne({
|
|
3184
|
+
...document,
|
|
3185
|
+
_smartdataRevision: plugins.crypto.randomUUID(),
|
|
3186
|
+
}, { timeoutMS: flexMaintenanceOperationTimeoutMs });
|
|
3187
|
+
current = await readLease(false);
|
|
3188
|
+
}
|
|
3189
|
+
catch (errorArg) {
|
|
3190
|
+
current = await readLease(false);
|
|
3191
|
+
if (!current)
|
|
3192
|
+
throw errorArg;
|
|
3193
|
+
}
|
|
3194
|
+
if (!current
|
|
3195
|
+
|| current.ownerToken !== ownerToken
|
|
3196
|
+
|| current.epoch !== 1
|
|
3197
|
+
|| current.state !== 'active')
|
|
3198
|
+
return undefined;
|
|
3199
|
+
}
|
|
3200
|
+
else {
|
|
3201
|
+
if (current.state === 'active' && current.expiresAt > now)
|
|
3202
|
+
return undefined;
|
|
3203
|
+
const next = {
|
|
3204
|
+
...leaseBody(current),
|
|
3205
|
+
ownerToken,
|
|
3206
|
+
epoch: current.epoch + 1,
|
|
3207
|
+
state: 'active',
|
|
3208
|
+
expiresAt: now + flexLeaseDurationMs,
|
|
3209
|
+
updatedAt: new Date(now).toISOString(),
|
|
3210
|
+
};
|
|
3211
|
+
assertFlexWriterLeaseDocument(next);
|
|
3212
|
+
const postimage = await collection.findOneAndReplace({
|
|
3213
|
+
_id: current._id,
|
|
3214
|
+
id,
|
|
3215
|
+
ownerToken: current.ownerToken,
|
|
3216
|
+
epoch: current.epoch,
|
|
3217
|
+
state: current.state,
|
|
3218
|
+
_smartdataRevision: smartRevisionSelector(current),
|
|
3219
|
+
}, {
|
|
3220
|
+
...next,
|
|
3221
|
+
_smartdataRevision: plugins.crypto.randomUUID(),
|
|
3222
|
+
}, {
|
|
3223
|
+
returnDocument: 'after',
|
|
3224
|
+
includeResultMetadata: false,
|
|
3225
|
+
timeoutMS: flexMaintenanceOperationTimeoutMs,
|
|
3226
|
+
});
|
|
3227
|
+
if (!postimage)
|
|
3228
|
+
return undefined;
|
|
3229
|
+
current = postimage;
|
|
3230
|
+
}
|
|
3231
|
+
const lease = {
|
|
3232
|
+
storageKey: storageKeyArg,
|
|
3233
|
+
ownerToken,
|
|
3234
|
+
epoch: current.epoch,
|
|
3235
|
+
expiresAt: current.expiresAt,
|
|
3236
|
+
lost: false,
|
|
3237
|
+
releasing: false,
|
|
3238
|
+
};
|
|
3239
|
+
this.heldLeases.set(storageKeyArg, lease);
|
|
3240
|
+
this.startLeaseHeartbeat();
|
|
3241
|
+
return { lease, acquired: true };
|
|
3242
|
+
}
|
|
3243
|
+
async runIdleMaintenanceStorage(storageKeyArg, abortSignalArg, operationArg) {
|
|
3244
|
+
abortSignalArg.throwIfAborted();
|
|
3245
|
+
if (this.storageQueues.has(storageKeyArg))
|
|
3246
|
+
return false;
|
|
3247
|
+
const operation = (async () => {
|
|
3248
|
+
const leaseResult = await this.ensureMaintenanceLease(storageKeyArg, abortSignalArg);
|
|
3249
|
+
if (!leaseResult)
|
|
3250
|
+
return false;
|
|
3251
|
+
try {
|
|
3252
|
+
abortSignalArg.throwIfAborted();
|
|
3253
|
+
await operationArg();
|
|
3254
|
+
return true;
|
|
3255
|
+
}
|
|
3256
|
+
finally {
|
|
3257
|
+
if (leaseResult.acquired) {
|
|
3258
|
+
await this.releaseHeldLease(leaseResult.lease, flexMaintenanceOperationTimeoutMs);
|
|
3259
|
+
}
|
|
3260
|
+
}
|
|
3261
|
+
})();
|
|
3262
|
+
const settled = operation.then(() => undefined, () => undefined);
|
|
3263
|
+
this.storageQueues.set(storageKeyArg, settled);
|
|
3264
|
+
void settled.then(() => {
|
|
3265
|
+
if (this.storageQueues.get(storageKeyArg) === settled) {
|
|
3266
|
+
this.storageQueues.delete(storageKeyArg);
|
|
3267
|
+
}
|
|
3268
|
+
});
|
|
3269
|
+
return operation;
|
|
3270
|
+
}
|
|
3271
|
+
async reconcileCandidateOrphans(kindArg, cutoffArg, abortSignalArg) {
|
|
3272
|
+
const model = kindArg === 'private'
|
|
3273
|
+
? FlexPrivateCandidateModel
|
|
3274
|
+
: kindArg === 'public'
|
|
3275
|
+
? FlexPublicCandidateModel
|
|
3276
|
+
: FlexProjectionSourceModel;
|
|
3277
|
+
let lastPosition;
|
|
3278
|
+
while (true) {
|
|
3279
|
+
abortSignalArg?.throwIfAborted();
|
|
3280
|
+
const cursor = model.collection.mongoDbCollection.find({
|
|
3281
|
+
controllerId: this.controllerId,
|
|
3282
|
+
...(lastPosition ? {
|
|
3283
|
+
$or: [{
|
|
3284
|
+
createdAt: { $gt: lastPosition.createdAt, $lte: cutoffArg },
|
|
3285
|
+
}, {
|
|
3286
|
+
createdAt: lastPosition.createdAt,
|
|
3287
|
+
_id: { $gt: lastPosition.id },
|
|
3288
|
+
}],
|
|
3289
|
+
} : { createdAt: { $lte: cutoffArg } }),
|
|
3290
|
+
}, abortSignalArg ? { signal: abortSignalArg } : {})
|
|
3291
|
+
.sort({ createdAt: 1, _id: 1 })
|
|
3292
|
+
.limit(flexMaintenancePageLimit);
|
|
3293
|
+
let documents;
|
|
3294
|
+
try {
|
|
3295
|
+
documents = await cursor.toArray();
|
|
3296
|
+
}
|
|
3297
|
+
finally {
|
|
3298
|
+
await cursor.close();
|
|
3299
|
+
}
|
|
3300
|
+
for (const document of documents) {
|
|
3301
|
+
abortSignalArg?.throwIfAborted();
|
|
3302
|
+
if (this.activeCandidateIds.has(document.candidateId))
|
|
3303
|
+
continue;
|
|
3304
|
+
try {
|
|
3305
|
+
await this.runIdleMaintenanceStorage(document.scopeId, abortSignalArg ?? this.maintenanceAbortController.signal, async () => {
|
|
3306
|
+
if (await this.hasCandidateHeadReference(kindArg, document.candidateId, abortSignalArg))
|
|
3307
|
+
return;
|
|
3308
|
+
abortSignalArg?.throwIfAborted();
|
|
3309
|
+
if (kindArg === 'private') {
|
|
3310
|
+
await this.cleanupPrivateByCandidate({ candidateId: document.candidateId }, flexMaintenanceOperationTimeoutMs);
|
|
3311
|
+
}
|
|
3312
|
+
else if (kindArg === 'public') {
|
|
3313
|
+
await this.cleanupPublicByCandidate(document, document.scopeId, flexMaintenanceOperationTimeoutMs);
|
|
3314
|
+
}
|
|
3315
|
+
else {
|
|
3316
|
+
await this.cleanupProjectionSourceByCandidate(document.candidateId, flexMaintenanceOperationTimeoutMs);
|
|
3317
|
+
}
|
|
3318
|
+
});
|
|
3319
|
+
}
|
|
3320
|
+
catch (errorArg) {
|
|
3321
|
+
if (abortSignalArg?.aborted)
|
|
3322
|
+
throw abortSignalArg.reason;
|
|
3323
|
+
}
|
|
3324
|
+
}
|
|
3325
|
+
const last = documents.at(-1);
|
|
3326
|
+
if (!last || documents.length < flexMaintenancePageLimit)
|
|
3327
|
+
break;
|
|
3328
|
+
lastPosition = { createdAt: last.createdAt, id: last._id };
|
|
3329
|
+
}
|
|
3330
|
+
}
|
|
3331
|
+
async hasCandidateHeadReference(kindArg, candidateIdArg, abortSignalArg) {
|
|
3332
|
+
if (kindArg === 'private') {
|
|
3333
|
+
const [legacy, domain] = await Promise.all([
|
|
3334
|
+
FlexHeadModel.collection.mongoDbCollection.findOne({
|
|
3335
|
+
controllerId: this.controllerId,
|
|
3336
|
+
currentPrivateCandidateId: candidateIdArg,
|
|
3337
|
+
}, { projection: { _id: 1 }, ...(abortSignalArg ? { signal: abortSignalArg } : {}) }),
|
|
3338
|
+
FlexDomainHeadModel.collection.mongoDbCollection.findOne({
|
|
3339
|
+
controllerId: this.controllerId,
|
|
3340
|
+
currentPrivateCandidateId: candidateIdArg,
|
|
3341
|
+
}, { projection: { _id: 1 }, ...(abortSignalArg ? { signal: abortSignalArg } : {}) }),
|
|
3342
|
+
]);
|
|
3343
|
+
return !!legacy || !!domain;
|
|
3344
|
+
}
|
|
3345
|
+
if (kindArg === 'projectionSource') {
|
|
3346
|
+
return !!await FlexDomainHeadModel.collection.mongoDbCollection.findOne({
|
|
3347
|
+
controllerId: this.controllerId,
|
|
3348
|
+
domain: 'projection',
|
|
3349
|
+
'projectionSource.candidateId': candidateIdArg,
|
|
3350
|
+
}, { projection: { _id: 1 }, ...(abortSignalArg ? { signal: abortSignalArg } : {}) });
|
|
3351
|
+
}
|
|
3352
|
+
const [legacy, current] = await Promise.all([
|
|
3353
|
+
FlexHeadModel.collection.mongoDbCollection.findOne({
|
|
3354
|
+
controllerId: this.controllerId,
|
|
3355
|
+
'publicCandidates.candidateId': candidateIdArg,
|
|
3356
|
+
}, { projection: { _id: 1 }, ...(abortSignalArg ? { signal: abortSignalArg } : {}) }),
|
|
3357
|
+
FlexPublicHeadModel.collection.mongoDbCollection.findOne({
|
|
3358
|
+
controllerId: this.controllerId,
|
|
3359
|
+
'publicCandidates.candidateId': candidateIdArg,
|
|
3360
|
+
}, { projection: { _id: 1 }, ...(abortSignalArg ? { signal: abortSignalArg } : {}) }),
|
|
3361
|
+
]);
|
|
3362
|
+
return !!legacy || !!current;
|
|
3363
|
+
}
|
|
3364
|
+
evictProviderScope(storageKeyArg) {
|
|
3365
|
+
for (const key of this.agentEventStores.keys()) {
|
|
3366
|
+
if (JSON.parse(key)[0] === storageKeyArg)
|
|
3367
|
+
this.agentEventStores.delete(key);
|
|
3368
|
+
}
|
|
3369
|
+
for (const key of this.jobStores.keys()) {
|
|
3370
|
+
if (JSON.parse(key)[0] === storageKeyArg)
|
|
3371
|
+
this.jobStores.delete(key);
|
|
3372
|
+
}
|
|
3373
|
+
}
|
|
3374
|
+
queueOrphanMaintenance() {
|
|
3375
|
+
if (!this.maintenanceOpen)
|
|
3376
|
+
return;
|
|
3377
|
+
if (this.orphanMaintenanceTask)
|
|
3378
|
+
return;
|
|
3379
|
+
const task = Promise.resolve().then(async () => {
|
|
3380
|
+
await this.reconcileOrphans(Date.now(), this.maintenanceAbortController.signal).catch(() => undefined);
|
|
3381
|
+
}).finally(() => {
|
|
3382
|
+
if (this.orphanMaintenanceTask === task)
|
|
3383
|
+
this.orphanMaintenanceTask = undefined;
|
|
3384
|
+
this.scheduleOrphanMaintenance();
|
|
3385
|
+
});
|
|
3386
|
+
this.orphanMaintenanceTask = task;
|
|
3387
|
+
}
|
|
3388
|
+
scheduleOrphanMaintenance() {
|
|
3389
|
+
if (!this.maintenanceOpen || this.orphanMaintenanceTimer)
|
|
3390
|
+
return;
|
|
3391
|
+
this.orphanMaintenanceTimer = setTimeout(() => {
|
|
3392
|
+
this.orphanMaintenanceTimer = undefined;
|
|
3393
|
+
if (!this.maintenanceOpen)
|
|
3394
|
+
return;
|
|
3395
|
+
this.queueOrphanMaintenance();
|
|
3396
|
+
}, flexOrphanMaintenanceIntervalMs);
|
|
3397
|
+
this.orphanMaintenanceTimer.unref?.();
|
|
3398
|
+
}
|
|
3399
|
+
}
|
|
3400
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2xhc3Nlcy5mbGV4c3RvcmUuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi90cy9jbGFzc2VzLmZsZXhzdG9yZS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEtBQUssT0FBTyxNQUFNLGNBQWMsQ0FBQztBQUN4QyxPQUFPLEVBQ0wsbUJBQW1CLEVBQ25CLGFBQWEsRUFDYixrQkFBa0IsRUFDbEIseUJBQXlCLEVBQ3pCLHFCQUFxQixFQUNyQixvQkFBb0IsRUFTcEIsNEJBQTRCLEVBQzVCLHNCQUFzQixFQUN0QiwyQkFBMkIsRUFDM0Isa0NBQWtDLEVBQ2xDLDhCQUE4QixFQUM5Qiw2QkFBNkIsRUFDN0IsZ0JBQWdCLEVBQ2hCLGVBQWUsRUFDZixxQkFBcUIsRUFDckIsaUJBQWlCLEVBQ2pCLHFCQUFxQixFQUNyQix5QkFBeUIsR0FDMUIsTUFBTSxpQ0FBaUMsQ0FBQztBQUN6QyxPQUFPLEVBQ0wsd0JBQXdCLEVBQ3hCLG1CQUFtQixFQUNuQiw0QkFBNEIsRUFDNUIsNEJBQTRCLEVBQzVCLGdDQUFnQyxFQUNoQyx5QkFBeUIsRUFZekIsaUNBQWlDLEVBQ2pDLDRCQUE0QixFQUM1QixxQ0FBcUMsRUFDckMscUNBQXFDLEVBQ3JDLHlDQUF5QyxFQUN6QyxrQ0FBa0MsRUFDbEMsVUFBVSxFQUNWLGdCQUFnQixFQUNoQiwyQkFBMkIsRUFDM0Isc0JBQXNCLEVBQ3RCLHNCQUFzQixFQUN0QixpQ0FBaUMsRUFDakMsb0JBQW9CLEVBQ3BCLHdCQUF3QixHQUN6QixNQUFNLGdDQUFnQyxDQUFDO0FBOEp4QyxNQUFNLENBQUMsTUFBTSxpQkFBaUIsR0FBRyxFQUFFLEdBQUcsRUFBRSxHQUFHLElBQUksQ0FBQztBQUNoRCxNQUFNLHdCQUF3QixHQUFHLEdBQUcsQ0FBQztBQUNyQyxNQUFNLCtCQUErQixHQUFHLEVBQUUsR0FBRyxFQUFFLEdBQUcsSUFBSSxDQUFDO0FBQ3ZELE1BQU0sbUJBQW1CLEdBQUcsTUFBTSxDQUFDO0FBQ25D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
|