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,2483 @@
|
|
|
1
|
+
import * as plugins from './plugins.js';
|
|
2
|
+
import { EmbeddedControllerDatabase } from './classes.embeddeddb.js';
|
|
3
|
+
import { AuthError, } from './interfaces.auth.js';
|
|
4
|
+
import { ControllerAuditEventModel, ControllerAuthModel, ControllerProjectModel, ControllerResourceModel, ControllerSessionGroupsModel, ControllerSessionStateModel, ControllerSettingsModel, ControllerTempPasswordModel, isProjectRelativePathName, WebAuthnCeremonyModel, controllerSessionStateId, } from './classes.authmodels.js';
|
|
5
|
+
import { controllerProjectLimit, controllerResourceLimit, controllerResourcesPerProjectLimit, } from './interfaces.projects.js';
|
|
6
|
+
import { controllerRuntimeIdKey } from '../dist_ts_interfaces/index.js';
|
|
7
|
+
import { PostDatabaseDocumentMigrationRunner, } from '../dist_ts_migration/classes.documentmigrationrunner.js';
|
|
8
|
+
import { filesystemIdentitiesEqual } from './functions.canonicaldirectory.js';
|
|
9
|
+
// The audit log is write-only telemetry with no reader; retention keeps the
|
|
10
|
+
// embedded engine's working set bounded. This is load-bearing on smartdb:
|
|
11
|
+
// the engine resolves indexed lookups and unique checks by scanning, so
|
|
12
|
+
// per-operation cost grows linearly with collection size — a hard count cap
|
|
13
|
+
// keeps every scan trivially small. Deletes run in limit-bounded id batches
|
|
14
|
+
// because broad deleteMany filters can exceed smartdb's per-operation
|
|
15
|
+
// materialization capacity on large collections.
|
|
16
|
+
const auditRetentionMs = 7 * 24 * 60 * 60 * 1000;
|
|
17
|
+
const auditRetentionMaxEvents = 2_000;
|
|
18
|
+
const auditRetentionCountSlack = 500;
|
|
19
|
+
const auditPruneBatchSize = 1000;
|
|
20
|
+
const auditPruneMaxBatchesPerSweep = 50;
|
|
21
|
+
// The count cap must be able to clear a large pre-existing backlog in one
|
|
22
|
+
// sweep; each batch is a bounded id page, so this stays cheap per round trip.
|
|
23
|
+
const auditCountPruneMaxBatchesPerSweep = 250;
|
|
24
|
+
const auditPruneIntervalMs = 30 * 60 * 1000;
|
|
25
|
+
const setupLifetimeMs = 30 * 60 * 1000;
|
|
26
|
+
// CLI-minted temporary passwords: a debugging credential, deliberately capped.
|
|
27
|
+
const tempPasswordTtlMinMs = 60 * 1000;
|
|
28
|
+
const tempPasswordTtlMaxMs = 24 * 60 * 60 * 1000;
|
|
29
|
+
const maxActiveTempPasswords = 8;
|
|
30
|
+
const tempPasswordPattern = /^[A-Za-z0-9_-]{32}$/;
|
|
31
|
+
const sessionModelChoiceClearTransitionMaxAttempts = 16;
|
|
32
|
+
// Operator-provided codes are allowed, so the accepted shape is any printable
|
|
33
|
+
// non-whitespace ASCII within DoS-safe length bounds; only the hash is stored.
|
|
34
|
+
const setupCodePattern = /^[\x21-\x7e]{4,256}$/;
|
|
35
|
+
const ceremonyIdPattern = /^[A-Za-z0-9_-]{43}$/;
|
|
36
|
+
const randomAuthorityValue = () => plugins.crypto.randomBytes(32).toString('base64url');
|
|
37
|
+
const randomResourceId = () => plugins.crypto.randomBytes(16).toString('base64url');
|
|
38
|
+
const randomResourceOperationId = () => plugins.crypto.randomBytes(16).toString('base64url');
|
|
39
|
+
const cloneSessionId = (sessionIdArg) => (sessionIdArg === null ? null : { ...sessionIdArg });
|
|
40
|
+
const isSessionId = (valueArg) => valueArg.harnessId === 'opencode' || valueArg.harnessId === 'flex';
|
|
41
|
+
const cloneResourceDocument = (resourceArg) => ({
|
|
42
|
+
...resourceArg,
|
|
43
|
+
sessionId: cloneSessionId(resourceArg.sessionId),
|
|
44
|
+
...(resourceArg.pendingAttachment === undefined ? {} : {
|
|
45
|
+
pendingAttachment: {
|
|
46
|
+
...resourceArg.pendingAttachment,
|
|
47
|
+
sessionId: cloneSessionId(resourceArg.pendingAttachment.sessionId),
|
|
48
|
+
},
|
|
49
|
+
}),
|
|
50
|
+
...(resourceArg.terminal === undefined ? {} : { terminal: { ...resourceArg.terminal } }),
|
|
51
|
+
});
|
|
52
|
+
const cloneModelChoice = (modelArg) => (modelArg.harnessId === 'opencode'
|
|
53
|
+
? {
|
|
54
|
+
harnessId: 'opencode',
|
|
55
|
+
providerID: modelArg.providerID,
|
|
56
|
+
modelID: modelArg.modelID,
|
|
57
|
+
...(modelArg.variant === undefined ? {} : { variant: modelArg.variant }),
|
|
58
|
+
}
|
|
59
|
+
: {
|
|
60
|
+
harnessId: 'flex',
|
|
61
|
+
providerConnectionId: modelArg.providerConnectionId,
|
|
62
|
+
providerID: modelArg.providerID,
|
|
63
|
+
modelID: modelArg.modelID,
|
|
64
|
+
...(modelArg.variant === undefined ? {} : { variant: modelArg.variant }),
|
|
65
|
+
});
|
|
66
|
+
export const assertProvidedSetupCode = (setupCodeArg) => {
|
|
67
|
+
if (typeof setupCodeArg !== 'string' || !setupCodePattern.test(setupCodeArg)) {
|
|
68
|
+
throw new Error('A setup code must be 4-256 printable non-whitespace ASCII characters.');
|
|
69
|
+
}
|
|
70
|
+
return setupCodeArg;
|
|
71
|
+
};
|
|
72
|
+
const cloneRuntimeConfig = (runtimeConfigArg) => ({
|
|
73
|
+
controllerPort: runtimeConfigArg.controllerPort,
|
|
74
|
+
publicOrigin: runtimeConfigArg.publicOrigin,
|
|
75
|
+
rpId: runtimeConfigArg.rpId,
|
|
76
|
+
workspaceDirectory: runtimeConfigArg.workspaceDirectory,
|
|
77
|
+
// The key must be absent, not undefined-valued, for exact persistence.
|
|
78
|
+
...(runtimeConfigArg.projectsRoot !== undefined
|
|
79
|
+
? { projectsRoot: runtimeConfigArg.projectsRoot }
|
|
80
|
+
: {}),
|
|
81
|
+
opencodePort: runtimeConfigArg.opencodePort,
|
|
82
|
+
tlsMode: runtimeConfigArg.tlsMode,
|
|
83
|
+
});
|
|
84
|
+
const runtimeConfigsEqual = (leftArg, rightArg) => leftArg.controllerPort === rightArg.controllerPort
|
|
85
|
+
&& leftArg.publicOrigin === rightArg.publicOrigin
|
|
86
|
+
&& leftArg.rpId === rightArg.rpId
|
|
87
|
+
&& leftArg.workspaceDirectory === rightArg.workspaceDirectory
|
|
88
|
+
&& leftArg.projectsRoot === rightArg.projectsRoot
|
|
89
|
+
&& leftArg.opencodePort === rightArg.opencodePort
|
|
90
|
+
&& leftArg.tlsMode === rightArg.tlsMode;
|
|
91
|
+
const hashSetupCode = (setupCodeArg) => plugins.crypto.createHash('sha256').update(setupCodeArg, 'utf8').digest('base64url');
|
|
92
|
+
const hashesEqual = (leftArg, rightArg) => {
|
|
93
|
+
const left = Buffer.from(leftArg, 'base64url');
|
|
94
|
+
const right = Buffer.from(rightArg, 'base64url');
|
|
95
|
+
return left.byteLength === right.byteLength && plugins.crypto.timingSafeEqual(left, right);
|
|
96
|
+
};
|
|
97
|
+
const requireSafeCounter = (counterArg, labelArg) => {
|
|
98
|
+
if (!Number.isSafeInteger(counterArg) || counterArg < 0) {
|
|
99
|
+
throw new AuthError('counter_conflict', `${labelArg} must be a non-negative safe integer.`);
|
|
100
|
+
}
|
|
101
|
+
};
|
|
102
|
+
const requireCeremonyKind = (kindArg) => {
|
|
103
|
+
if (kindArg !== 'setup' && kindArg !== 'authentication') {
|
|
104
|
+
throw new AuthError('ceremony_invalid', 'The WebAuthn ceremony kind is invalid.');
|
|
105
|
+
}
|
|
106
|
+
return kindArg;
|
|
107
|
+
};
|
|
108
|
+
const requireCeremonyId = (ceremonyIdArg) => {
|
|
109
|
+
if (typeof ceremonyIdArg !== 'string' || !ceremonyIdPattern.test(ceremonyIdArg)) {
|
|
110
|
+
throw new AuthError('ceremony_invalid', 'The WebAuthn ceremony identifier is invalid.');
|
|
111
|
+
}
|
|
112
|
+
return ceremonyIdArg;
|
|
113
|
+
};
|
|
114
|
+
const requirePeerId = (peerIdArg) => {
|
|
115
|
+
if (typeof peerIdArg !== 'string'
|
|
116
|
+
|| peerIdArg.length === 0
|
|
117
|
+
|| peerIdArg.length > 512
|
|
118
|
+
|| peerIdArg.trim() !== peerIdArg) {
|
|
119
|
+
throw new AuthError('peer_mismatch', 'The connection identity is malformed.');
|
|
120
|
+
}
|
|
121
|
+
return peerIdArg;
|
|
122
|
+
};
|
|
123
|
+
const requireOrigin = (originArg) => {
|
|
124
|
+
if (typeof originArg !== 'string' || originArg.length === 0 || originArg.length > 2048) {
|
|
125
|
+
throw new AuthError('origin_mismatch', 'The ceremony origin is malformed.');
|
|
126
|
+
}
|
|
127
|
+
try {
|
|
128
|
+
const origin = new URL(originArg);
|
|
129
|
+
if (origin.origin !== originArg
|
|
130
|
+
|| (origin.protocol !== 'http:' && origin.protocol !== 'https:')
|
|
131
|
+
|| origin.username.length > 0
|
|
132
|
+
|| origin.password.length > 0
|
|
133
|
+
|| origin.pathname !== '/'
|
|
134
|
+
|| origin.search.length > 0
|
|
135
|
+
|| origin.hash.length > 0) {
|
|
136
|
+
throw new Error('not an origin');
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
catch {
|
|
140
|
+
throw new AuthError('origin_mismatch', 'The ceremony origin is malformed.');
|
|
141
|
+
}
|
|
142
|
+
return originArg;
|
|
143
|
+
};
|
|
144
|
+
const rpIdPattern = /^(?=.{1,253}$)[a-z0-9](?:[a-z0-9.-]*[a-z0-9])?$/;
|
|
145
|
+
const requireRpId = (rpIdArg) => {
|
|
146
|
+
if (typeof rpIdArg !== 'string' || !rpIdPattern.test(rpIdArg)) {
|
|
147
|
+
throw new AuthError('ceremony_invalid', 'The ceremony RP ID is malformed.');
|
|
148
|
+
}
|
|
149
|
+
return rpIdArg;
|
|
150
|
+
};
|
|
151
|
+
const requireUserId = (userIdArg) => {
|
|
152
|
+
if (typeof userIdArg !== 'string' || !ceremonyIdPattern.test(userIdArg)) {
|
|
153
|
+
throw new AuthError('ceremony_invalid', 'The ceremony user identifier is malformed.');
|
|
154
|
+
}
|
|
155
|
+
return userIdArg;
|
|
156
|
+
};
|
|
157
|
+
const requireValidDate = (dateArg, labelArg) => {
|
|
158
|
+
if (!(dateArg instanceof Date) || !Number.isFinite(dateArg.getTime())) {
|
|
159
|
+
throw new AuthError('ceremony_invalid', `${labelArg} must be a valid date.`);
|
|
160
|
+
}
|
|
161
|
+
return new Date(dateArg);
|
|
162
|
+
};
|
|
163
|
+
const isAmbiguousWrite = (errorArg) => errorArg instanceof plugins.smartdata.SmartdataExactPersistenceError
|
|
164
|
+
&& errorArg.code === 'ambiguous_write';
|
|
165
|
+
const sessionStateRecoveryLimit = 500;
|
|
166
|
+
const sessionStateRetirementPageLimit = 100;
|
|
167
|
+
const maxSessionStateRetirementPages = 100;
|
|
168
|
+
const maxSessionStateExchanges = 8;
|
|
169
|
+
const maxSessionStateExchangeBytes = 256 * 1024;
|
|
170
|
+
const toPublicIntelligenceExchange = (exchangeArg) => ({
|
|
171
|
+
id: exchangeArg.id,
|
|
172
|
+
question: exchangeArg.question,
|
|
173
|
+
status: exchangeArg.status,
|
|
174
|
+
...(exchangeArg.answer === undefined ? {} : { answer: exchangeArg.answer }),
|
|
175
|
+
...(exchangeArg.error === undefined ? {} : { error: exchangeArg.error }),
|
|
176
|
+
...(exchangeArg.model === undefined ? {} : { model: exchangeArg.model }),
|
|
177
|
+
...(exchangeArg.scratchpadConflict === undefined
|
|
178
|
+
? {}
|
|
179
|
+
: { scratchpadConflict: exchangeArg.scratchpadConflict }),
|
|
180
|
+
createdAt: exchangeArg.createdAt.getTime(),
|
|
181
|
+
...(exchangeArg.completedAt === undefined
|
|
182
|
+
? {}
|
|
183
|
+
: { completedAt: exchangeArg.completedAt.getTime() }),
|
|
184
|
+
});
|
|
185
|
+
const toPublicSessionState = (documentArg) => ({
|
|
186
|
+
scratchpad: {
|
|
187
|
+
id: documentArg.id,
|
|
188
|
+
text: documentArg.scratchpad.text,
|
|
189
|
+
revision: documentArg.scratchpad.revision,
|
|
190
|
+
...(documentArg.scratchpad.updatedAt === undefined
|
|
191
|
+
? {}
|
|
192
|
+
: { updatedAt: documentArg.scratchpad.updatedAt.getTime() }),
|
|
193
|
+
...(documentArg.scratchpad.updatedBy === undefined
|
|
194
|
+
? {}
|
|
195
|
+
: { updatedBy: documentArg.scratchpad.updatedBy }),
|
|
196
|
+
},
|
|
197
|
+
intelligenceExchanges: documentArg.intelligenceExchanges.map(toPublicIntelligenceExchange),
|
|
198
|
+
...(documentArg.modelChoice === undefined
|
|
199
|
+
? {}
|
|
200
|
+
: { modelChoice: cloneModelChoice(documentArg.modelChoice) }),
|
|
201
|
+
});
|
|
202
|
+
const trimSessionStateExchanges = (exchangesArg, protectedExchangeIdArg) => {
|
|
203
|
+
const exchanges = exchangesArg.slice(-maxSessionStateExchanges);
|
|
204
|
+
while (exchanges.length > 1
|
|
205
|
+
&& Buffer.byteLength(JSON.stringify(exchanges), 'utf8') > maxSessionStateExchangeBytes) {
|
|
206
|
+
const removableIndex = exchanges.findIndex((exchange) => exchange.id !== protectedExchangeIdArg && exchange.status !== 'running');
|
|
207
|
+
if (removableIndex < 0)
|
|
208
|
+
break;
|
|
209
|
+
exchanges.splice(removableIndex, 1);
|
|
210
|
+
}
|
|
211
|
+
return exchanges;
|
|
212
|
+
};
|
|
213
|
+
const projectManagementStoreKey = (projectIdArg, sessionIdArg) => JSON.stringify([projectIdArg, sessionIdArg]);
|
|
214
|
+
const cloneProjectManagementRecord = (recordArg) => structuredClone(recordArg);
|
|
215
|
+
const sameProjectManagementGeneration = (leftArg, rightArg) => leftArg.sessionGenerationId === rightArg.sessionGenerationId
|
|
216
|
+
&& leftArg.sessionGenerationSequence === rightArg.sessionGenerationSequence;
|
|
217
|
+
const canInitializeProjectManagementGeneration = (currentArg, nextArg, expectedRevisionArg) => Object.hasOwn(currentArg, 'deletedAt')
|
|
218
|
+
&& expectedRevisionArg === 0
|
|
219
|
+
&& nextArg.sessionGenerationId !== currentArg.sessionGenerationId
|
|
220
|
+
&& nextArg.sessionGenerationSequence > currentArg.sessionGenerationSequence;
|
|
221
|
+
const assertFlexSessionGeneration = (generationArg) => {
|
|
222
|
+
if (!generationArg
|
|
223
|
+
|| typeof generationArg.sessionGenerationId !== 'string'
|
|
224
|
+
|| generationArg.sessionGenerationId.trim().length === 0
|
|
225
|
+
|| Buffer.byteLength(generationArg.sessionGenerationId, 'utf8')
|
|
226
|
+
> plugins.flexharness.FLEX_SESSION_GENERATION_ID_MAX_BYTES
|
|
227
|
+
|| !Number.isSafeInteger(generationArg.sessionGenerationSequence)
|
|
228
|
+
|| generationArg.sessionGenerationSequence < 1) {
|
|
229
|
+
throw new plugins.flexharness.FlexHarnessStoreFormatError('The Flex project-management session generation is invalid.');
|
|
230
|
+
}
|
|
231
|
+
};
|
|
232
|
+
const assertProjectManagementWriteContext = (writeContextArg) => {
|
|
233
|
+
if (!writeContextArg
|
|
234
|
+
|| typeof writeContextArg !== 'object'
|
|
235
|
+
|| Array.isArray(writeContextArg)
|
|
236
|
+
|| ![Object.prototype, null].includes(Object.getPrototypeOf(writeContextArg))
|
|
237
|
+
|| Object.keys(writeContextArg).some((key) => !['actor', 'runId', 'agent', 'toolCallId'].includes(key))
|
|
238
|
+
|| (writeContextArg.actor !== 'agent' && writeContextArg.actor !== 'application')
|
|
239
|
+
|| ['runId', 'agent', 'toolCallId'].some((key) => {
|
|
240
|
+
const value = writeContextArg[key];
|
|
241
|
+
return value !== undefined && (typeof value !== 'string' || value.trim().length === 0);
|
|
242
|
+
})) {
|
|
243
|
+
throw new plugins.flexharness.FlexHarnessStoreFormatError('The Flex project-management write context is invalid.');
|
|
244
|
+
}
|
|
245
|
+
};
|
|
246
|
+
const assertProjectManagementNextRevision = (recordArg, expectedRevisionArg) => {
|
|
247
|
+
if (!Number.isSafeInteger(expectedRevisionArg) || expectedRevisionArg < 0) {
|
|
248
|
+
throw new plugins.flexharness.FlexHarnessStoreFormatError('The expected Flex project-management revision is invalid.');
|
|
249
|
+
}
|
|
250
|
+
if (recordArg.revision !== expectedRevisionArg + 1) {
|
|
251
|
+
throw new plugins.flexharness.FlexHarnessStoreFormatError('The Flex project-management revision must advance by exactly one.');
|
|
252
|
+
}
|
|
253
|
+
};
|
|
254
|
+
const projectManagementUpdater = (writeContextArg) => writeContextArg.actor;
|
|
255
|
+
export const assertControllerResourceCreationCapacity = (projectResourceCountArg, controllerResourceCountArg) => {
|
|
256
|
+
if (controllerResourceCountArg >= controllerResourceLimit) {
|
|
257
|
+
throw new AuthError('invalid_resource', `The controller supports at most ${controllerResourceLimit} resources.`);
|
|
258
|
+
}
|
|
259
|
+
if (projectResourceCountArg >= controllerResourcesPerProjectLimit) {
|
|
260
|
+
throw new AuthError('invalid_resource', `A project supports at most ${controllerResourcesPerProjectLimit} resources.`);
|
|
261
|
+
}
|
|
262
|
+
};
|
|
263
|
+
export class SmartDataAuthStore {
|
|
264
|
+
options;
|
|
265
|
+
database;
|
|
266
|
+
embeddedDatabase;
|
|
267
|
+
// smartdata resolves the manager's db lazily per operation, so the
|
|
268
|
+
// manager can be registered before init() constructs the database.
|
|
269
|
+
smartDataManager;
|
|
270
|
+
initialized = false;
|
|
271
|
+
initPromise;
|
|
272
|
+
controllerId;
|
|
273
|
+
resolvedMongoDbUrl;
|
|
274
|
+
closePromise;
|
|
275
|
+
closeStarted = false;
|
|
276
|
+
projectMutationAdmissionOpen = false;
|
|
277
|
+
projectMutationTail = Promise.resolve();
|
|
278
|
+
sessionStateMutationTail = Promise.resolve();
|
|
279
|
+
auditPruneTimer;
|
|
280
|
+
runSessionStateMutation(operationArg) {
|
|
281
|
+
if (this.closeStarted) {
|
|
282
|
+
return Promise.reject(new AuthError('not_initialized', 'The authentication store is shutting down.'));
|
|
283
|
+
}
|
|
284
|
+
const result = this.sessionStateMutationTail.then(operationArg);
|
|
285
|
+
this.sessionStateMutationTail = result.then(() => undefined, () => undefined);
|
|
286
|
+
return result;
|
|
287
|
+
}
|
|
288
|
+
constructor(options) {
|
|
289
|
+
this.options = options;
|
|
290
|
+
const hasExternalUrl = typeof options.mongoDbUrl === 'string'
|
|
291
|
+
&& options.mongoDbUrl.trim().length > 0;
|
|
292
|
+
const hasEmbeddedDirectory = typeof options.embeddedDataDirectory === 'string'
|
|
293
|
+
&& plugins.path.isAbsolute(options.embeddedDataDirectory);
|
|
294
|
+
if (!hasExternalUrl && !hasEmbeddedDirectory) {
|
|
295
|
+
throw new Error('Either mongoDbUrl or an absolute embeddedDataDirectory must be provided.');
|
|
296
|
+
}
|
|
297
|
+
if (!/^[A-Za-z0-9_-]{1,63}$/.test(options.mongoDbName)) {
|
|
298
|
+
throw new Error('mongoDbName must use 1-63 letters, digits, underscores, or dashes.');
|
|
299
|
+
}
|
|
300
|
+
const storeSelf = this;
|
|
301
|
+
this.smartDataManager = {
|
|
302
|
+
get db() {
|
|
303
|
+
return storeSelf.db;
|
|
304
|
+
},
|
|
305
|
+
};
|
|
306
|
+
plugins.smartdata.setDefaultManagerForDoc(this.smartDataManager, ControllerAuthModel);
|
|
307
|
+
plugins.smartdata.setDefaultManagerForDoc(this.smartDataManager, WebAuthnCeremonyModel);
|
|
308
|
+
plugins.smartdata.setDefaultManagerForDoc(this.smartDataManager, ControllerAuditEventModel);
|
|
309
|
+
plugins.smartdata.setDefaultManagerForDoc(this.smartDataManager, ControllerProjectModel);
|
|
310
|
+
plugins.smartdata.setDefaultManagerForDoc(this.smartDataManager, ControllerResourceModel);
|
|
311
|
+
plugins.smartdata.setDefaultManagerForDoc(this.smartDataManager, ControllerSettingsModel);
|
|
312
|
+
plugins.smartdata.setDefaultManagerForDoc(this.smartDataManager, ControllerTempPasswordModel);
|
|
313
|
+
plugins.smartdata.setDefaultManagerForDoc(this.smartDataManager, ControllerSessionGroupsModel);
|
|
314
|
+
plugins.smartdata.setDefaultManagerForDoc(this.smartDataManager, ControllerSessionStateModel);
|
|
315
|
+
}
|
|
316
|
+
get db() {
|
|
317
|
+
if (!this.database) {
|
|
318
|
+
throw new Error('The auth store database has not been initialized.');
|
|
319
|
+
}
|
|
320
|
+
return this.database;
|
|
321
|
+
}
|
|
322
|
+
async init() {
|
|
323
|
+
if (this.closeStarted) {
|
|
324
|
+
throw new Error('SmartDataAuthStore cannot initialize after shutdown has begun.');
|
|
325
|
+
}
|
|
326
|
+
if (this.initialized)
|
|
327
|
+
return;
|
|
328
|
+
if (this.initPromise)
|
|
329
|
+
return this.initPromise;
|
|
330
|
+
if (this.database || this.embeddedDatabase) {
|
|
331
|
+
throw new Error('SmartData cleanup must complete before initialization can be retried.');
|
|
332
|
+
}
|
|
333
|
+
const initPromise = this.initOnce();
|
|
334
|
+
this.initPromise = initPromise;
|
|
335
|
+
try {
|
|
336
|
+
await initPromise;
|
|
337
|
+
}
|
|
338
|
+
finally {
|
|
339
|
+
if (this.initPromise === initPromise)
|
|
340
|
+
this.initPromise = undefined;
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
async initOnce() {
|
|
344
|
+
try {
|
|
345
|
+
let mongoDbUrl = this.options.mongoDbUrl?.trim();
|
|
346
|
+
if (!mongoDbUrl) {
|
|
347
|
+
const embedded = new EmbeddedControllerDatabase({
|
|
348
|
+
dataDirectory: this.options.embeddedDataDirectory,
|
|
349
|
+
legacyDataDirectory: this.options.legacyEmbeddedDataDirectory,
|
|
350
|
+
});
|
|
351
|
+
this.embeddedDatabase = embedded;
|
|
352
|
+
mongoDbUrl = await embedded.start();
|
|
353
|
+
}
|
|
354
|
+
this.database = new plugins.smartdata.SmartdataDb({
|
|
355
|
+
mongoDbUrl,
|
|
356
|
+
mongoDbName: this.options.mongoDbName,
|
|
357
|
+
});
|
|
358
|
+
this.resolvedMongoDbUrl = mongoDbUrl;
|
|
359
|
+
await this.db.init();
|
|
360
|
+
await ControllerAuthModel.init();
|
|
361
|
+
await WebAuthnCeremonyModel.init();
|
|
362
|
+
await ControllerAuditEventModel.init();
|
|
363
|
+
await ControllerProjectModel.init();
|
|
364
|
+
await ControllerResourceModel.init();
|
|
365
|
+
await ControllerSettingsModel.init();
|
|
366
|
+
await ControllerTempPasswordModel.init();
|
|
367
|
+
await ControllerSessionGroupsModel.init();
|
|
368
|
+
await ControllerSessionStateModel.init();
|
|
369
|
+
await new PostDatabaseDocumentMigrationRunner(this.database).run();
|
|
370
|
+
this.initialized = true;
|
|
371
|
+
if (!this.closeStarted)
|
|
372
|
+
this.projectMutationAdmissionOpen = true;
|
|
373
|
+
}
|
|
374
|
+
catch (errorArg) {
|
|
375
|
+
const cleanupErrors = [];
|
|
376
|
+
if (this.database) {
|
|
377
|
+
try {
|
|
378
|
+
await this.database.close();
|
|
379
|
+
this.database = undefined;
|
|
380
|
+
this.resolvedMongoDbUrl = undefined;
|
|
381
|
+
}
|
|
382
|
+
catch (closeErrorArg) {
|
|
383
|
+
cleanupErrors.push(closeErrorArg);
|
|
384
|
+
}
|
|
385
|
+
}
|
|
386
|
+
try {
|
|
387
|
+
await this.stopEmbeddedDatabase();
|
|
388
|
+
}
|
|
389
|
+
catch (stopErrorArg) {
|
|
390
|
+
cleanupErrors.push(stopErrorArg);
|
|
391
|
+
}
|
|
392
|
+
if (cleanupErrors.length > 0) {
|
|
393
|
+
throw new AggregateError([errorArg, ...cleanupErrors], 'SmartData initialization failed and cleanup was incomplete.', { cause: errorArg });
|
|
394
|
+
}
|
|
395
|
+
throw errorArg;
|
|
396
|
+
}
|
|
397
|
+
// Retention is maintenance and must never gate readiness: clearing a
|
|
398
|
+
// large pre-existing backlog takes far longer than the controller's
|
|
399
|
+
// startup budget, so the first sweep runs detached like every later one.
|
|
400
|
+
void this.pruneAuditHistory();
|
|
401
|
+
this.auditPruneTimer = setInterval(() => {
|
|
402
|
+
void this.pruneAuditHistory();
|
|
403
|
+
}, auditPruneIntervalMs);
|
|
404
|
+
this.auditPruneTimer.unref?.();
|
|
405
|
+
}
|
|
406
|
+
async pruneAuditHistory() {
|
|
407
|
+
try {
|
|
408
|
+
const collection = ControllerAuditEventModel.collection.mongoDbCollection;
|
|
409
|
+
// Count cap first: it bounds the collection regardless of event rate,
|
|
410
|
+
// which the age rule alone cannot (heavy days produce tens of
|
|
411
|
+
// thousands of events).
|
|
412
|
+
const count = await collection.estimatedDocumentCount();
|
|
413
|
+
if (count > auditRetentionMaxEvents + auditRetentionCountSlack) {
|
|
414
|
+
// One bounded batch per round trip: a sorted find whose limit is the
|
|
415
|
+
// full excess exceeds the engine's per-operation materialization
|
|
416
|
+
// ceiling once the backlog is large (which is exactly when this
|
|
417
|
+
// runs). Re-reading the oldest page after each delete converges.
|
|
418
|
+
let remaining = count - auditRetentionMaxEvents;
|
|
419
|
+
for (let batch = 0; batch < auditCountPruneMaxBatchesPerSweep && remaining > 0; batch++) {
|
|
420
|
+
const pageSize = Math.min(auditPruneBatchSize, remaining);
|
|
421
|
+
const excess = await collection
|
|
422
|
+
.find({}, { projection: { _id: 1 } })
|
|
423
|
+
.sort({ timestamp: 1 })
|
|
424
|
+
.limit(pageSize)
|
|
425
|
+
.toArray();
|
|
426
|
+
if (excess.length === 0)
|
|
427
|
+
break;
|
|
428
|
+
await collection.deleteMany({ _id: { $in: excess.map((doc) => doc._id) } });
|
|
429
|
+
remaining -= excess.length;
|
|
430
|
+
}
|
|
431
|
+
}
|
|
432
|
+
const cutoffIso = new Date(Date.now() - auditRetentionMs).toISOString();
|
|
433
|
+
for (let batch = 0; batch < auditPruneMaxBatchesPerSweep; batch++) {
|
|
434
|
+
const expired = await collection
|
|
435
|
+
.find({ timestamp: { $lt: cutoffIso } }, { projection: { _id: 1 } })
|
|
436
|
+
.limit(auditPruneBatchSize)
|
|
437
|
+
.toArray();
|
|
438
|
+
if (expired.length === 0)
|
|
439
|
+
return;
|
|
440
|
+
await collection.deleteMany({ _id: { $in: expired.map((doc) => doc._id) } });
|
|
441
|
+
if (expired.length < auditPruneBatchSize)
|
|
442
|
+
return;
|
|
443
|
+
}
|
|
444
|
+
}
|
|
445
|
+
catch (errorArg) {
|
|
446
|
+
// Retention is maintenance; it must never take the controller down.
|
|
447
|
+
console.error('Audit history pruning failed.', errorArg);
|
|
448
|
+
}
|
|
449
|
+
}
|
|
450
|
+
async stopEmbeddedDatabase() {
|
|
451
|
+
const embedded = this.embeddedDatabase;
|
|
452
|
+
if (embedded) {
|
|
453
|
+
await embedded.stop();
|
|
454
|
+
if (this.embeddedDatabase === embedded)
|
|
455
|
+
this.embeddedDatabase = undefined;
|
|
456
|
+
}
|
|
457
|
+
}
|
|
458
|
+
async close() {
|
|
459
|
+
this.closeStarted = true;
|
|
460
|
+
this.projectMutationAdmissionOpen = false;
|
|
461
|
+
if (this.closePromise)
|
|
462
|
+
return this.closePromise;
|
|
463
|
+
const closePromise = (async () => {
|
|
464
|
+
if (this.initPromise)
|
|
465
|
+
await this.initPromise.catch(() => undefined);
|
|
466
|
+
await this.projectMutationTail;
|
|
467
|
+
await this.sessionStateMutationTail;
|
|
468
|
+
if (!this.database && !this.embeddedDatabase)
|
|
469
|
+
return;
|
|
470
|
+
if (this.auditPruneTimer) {
|
|
471
|
+
clearInterval(this.auditPruneTimer);
|
|
472
|
+
this.auditPruneTimer = undefined;
|
|
473
|
+
}
|
|
474
|
+
const cleanupErrors = [];
|
|
475
|
+
if (this.database) {
|
|
476
|
+
try {
|
|
477
|
+
await this.database.close();
|
|
478
|
+
this.database = undefined;
|
|
479
|
+
this.resolvedMongoDbUrl = undefined;
|
|
480
|
+
}
|
|
481
|
+
catch (errorArg) {
|
|
482
|
+
cleanupErrors.push(errorArg);
|
|
483
|
+
}
|
|
484
|
+
}
|
|
485
|
+
try {
|
|
486
|
+
await this.stopEmbeddedDatabase();
|
|
487
|
+
}
|
|
488
|
+
catch (errorArg) {
|
|
489
|
+
cleanupErrors.push(errorArg);
|
|
490
|
+
}
|
|
491
|
+
if (cleanupErrors.length === 1)
|
|
492
|
+
throw cleanupErrors[0];
|
|
493
|
+
if (cleanupErrors.length > 1) {
|
|
494
|
+
throw new AggregateError(cleanupErrors, 'SmartData shutdown was incomplete.');
|
|
495
|
+
}
|
|
496
|
+
})();
|
|
497
|
+
this.closePromise = closePromise;
|
|
498
|
+
try {
|
|
499
|
+
await closePromise;
|
|
500
|
+
this.initialized = false;
|
|
501
|
+
}
|
|
502
|
+
finally {
|
|
503
|
+
if (this.closePromise === closePromise)
|
|
504
|
+
this.closePromise = undefined;
|
|
505
|
+
}
|
|
506
|
+
}
|
|
507
|
+
async getRuntimeConfig(controllerPortArg) {
|
|
508
|
+
this.assertInitialized();
|
|
509
|
+
if (!Number.isSafeInteger(controllerPortArg)
|
|
510
|
+
|| controllerPortArg < 1
|
|
511
|
+
|| controllerPortArg > 65535) {
|
|
512
|
+
throw new Error('controllerPort must be an integer between 1 and 65535.');
|
|
513
|
+
}
|
|
514
|
+
this.controllerId = `controller:${controllerPortArg}`;
|
|
515
|
+
const stored = await ControllerAuthModel.exact.findStoredOne({ id: this.controllerId });
|
|
516
|
+
if (!stored)
|
|
517
|
+
return undefined;
|
|
518
|
+
return cloneRuntimeConfig(ControllerAuthModel.exact.toPersisted(stored).config);
|
|
519
|
+
}
|
|
520
|
+
/** Process-private connection data for the isolated Flex child and projection reader. */
|
|
521
|
+
getDatabaseDescriptor() {
|
|
522
|
+
this.assertInitialized();
|
|
523
|
+
if (!this.resolvedMongoDbUrl) {
|
|
524
|
+
throw new AuthError('not_initialized', 'The controller database connection is unavailable.');
|
|
525
|
+
}
|
|
526
|
+
return {
|
|
527
|
+
mongoDbUrl: this.resolvedMongoDbUrl,
|
|
528
|
+
mongoDbName: this.options.mongoDbName,
|
|
529
|
+
};
|
|
530
|
+
}
|
|
531
|
+
async resolveOrCreateRuntimeConfig(runtimeConfigArg) {
|
|
532
|
+
this.assertInitialized();
|
|
533
|
+
if (!Number.isSafeInteger(runtimeConfigArg.controllerPort)
|
|
534
|
+
|| runtimeConfigArg.controllerPort < 1
|
|
535
|
+
|| runtimeConfigArg.controllerPort > 65535) {
|
|
536
|
+
throw new Error('controllerPort must be an integer between 1 and 65535.');
|
|
537
|
+
}
|
|
538
|
+
const controllerId = `controller:${runtimeConfigArg.controllerPort}`;
|
|
539
|
+
this.controllerId = controllerId;
|
|
540
|
+
const existing = await ControllerAuthModel.exact.findStoredOne({ id: controllerId });
|
|
541
|
+
if (existing) {
|
|
542
|
+
const document = ControllerAuthModel.exact.toPersisted(existing);
|
|
543
|
+
if (document.config.projectsRoot === undefined
|
|
544
|
+
&& runtimeConfigArg.projectsRoot !== undefined) {
|
|
545
|
+
// One-time v2 upgrade: adopt the resolved projects root into the
|
|
546
|
+
// stored document; every other field must still match exactly.
|
|
547
|
+
this.assertRuntimeConfigMatches({ ...document.config, projectsRoot: runtimeConfigArg.projectsRoot }, runtimeConfigArg);
|
|
548
|
+
const upgraded = cloneRuntimeConfig(runtimeConfigArg);
|
|
549
|
+
const result = await ControllerAuthModel.exact.transition({
|
|
550
|
+
current: existing,
|
|
551
|
+
change: (model) => {
|
|
552
|
+
model.config = upgraded;
|
|
553
|
+
},
|
|
554
|
+
});
|
|
555
|
+
if (result.status === 'transitioned') {
|
|
556
|
+
return this.finalizeRuntimeConfigDocument(ControllerAuthModel.exact.toPersisted(result.document), runtimeConfigArg);
|
|
557
|
+
}
|
|
558
|
+
const reconciled = await ControllerAuthModel.exact.findStoredOne({ id: controllerId });
|
|
559
|
+
if (!reconciled) {
|
|
560
|
+
throw new AuthError('ambiguous_write', 'Controller runtime configuration upgrade has an ambiguous outcome.');
|
|
561
|
+
}
|
|
562
|
+
const reconciledDocument = ControllerAuthModel.exact.toPersisted(reconciled);
|
|
563
|
+
return this.finalizeRuntimeConfigDocument(reconciledDocument, runtimeConfigArg);
|
|
564
|
+
}
|
|
565
|
+
return this.finalizeRuntimeConfigDocument(document, runtimeConfigArg);
|
|
566
|
+
}
|
|
567
|
+
const candidate = {
|
|
568
|
+
id: controllerId,
|
|
569
|
+
config: cloneRuntimeConfig(runtimeConfigArg),
|
|
570
|
+
authState: 'setupRequired',
|
|
571
|
+
setup: null,
|
|
572
|
+
webauthnUserId: randomAuthorityValue(),
|
|
573
|
+
credentials: [],
|
|
574
|
+
};
|
|
575
|
+
try {
|
|
576
|
+
const insertResult = await ControllerAuthModel.exact.insert(candidate);
|
|
577
|
+
const document = ControllerAuthModel.exact.toPersisted(insertResult.document);
|
|
578
|
+
return this.finalizeRuntimeConfigDocument(document, runtimeConfigArg);
|
|
579
|
+
}
|
|
580
|
+
catch (errorArg) {
|
|
581
|
+
if (!isAmbiguousWrite(errorArg))
|
|
582
|
+
throw errorArg;
|
|
583
|
+
const reconciled = await ControllerAuthModel.exact.findStoredOne({ id: controllerId });
|
|
584
|
+
if (!reconciled) {
|
|
585
|
+
throw new AuthError('ambiguous_write', 'Controller authentication initialization has an ambiguous outcome.', { cause: errorArg });
|
|
586
|
+
}
|
|
587
|
+
const document = ControllerAuthModel.exact.toPersisted(reconciled);
|
|
588
|
+
return this.finalizeRuntimeConfigDocument(document, runtimeConfigArg);
|
|
589
|
+
}
|
|
590
|
+
}
|
|
591
|
+
async finalizeRuntimeConfigDocument(documentArg, runtimeConfigArg) {
|
|
592
|
+
this.assertRuntimeConfigMatches(documentArg.config, runtimeConfigArg);
|
|
593
|
+
await new PostDatabaseDocumentMigrationRunner(this.database)
|
|
594
|
+
.runProjectFilesystemIdentity(documentArg.id);
|
|
595
|
+
return documentArg;
|
|
596
|
+
}
|
|
597
|
+
async rotateSetupAuthority(providedCodeArg) {
|
|
598
|
+
const current = await this.findStoredState();
|
|
599
|
+
const currentBody = ControllerAuthModel.exact.toPersisted(current);
|
|
600
|
+
if (currentBody.credentials.length > 0)
|
|
601
|
+
return null;
|
|
602
|
+
const setupCode = providedCodeArg === undefined
|
|
603
|
+
? randomAuthorityValue()
|
|
604
|
+
: assertProvidedSetupCode(providedCodeArg);
|
|
605
|
+
const setupHash = hashSetupCode(setupCode);
|
|
606
|
+
const generation = randomAuthorityValue();
|
|
607
|
+
const expiresAt = new Date(Date.now() + setupLifetimeMs);
|
|
608
|
+
try {
|
|
609
|
+
const result = await ControllerAuthModel.exact.transition({
|
|
610
|
+
current,
|
|
611
|
+
change: (model) => {
|
|
612
|
+
model.authState = 'setupRequired';
|
|
613
|
+
model.setup = {
|
|
614
|
+
generation,
|
|
615
|
+
hash: setupHash,
|
|
616
|
+
expiresAt,
|
|
617
|
+
};
|
|
618
|
+
},
|
|
619
|
+
});
|
|
620
|
+
if (result.status !== 'transitioned') {
|
|
621
|
+
throw new AuthError('concurrent_change', 'Setup authority changed concurrently and was not rotated.');
|
|
622
|
+
}
|
|
623
|
+
return { setupCode, generation, expiresAt: new Date(expiresAt) };
|
|
624
|
+
}
|
|
625
|
+
catch (errorArg) {
|
|
626
|
+
if (!isAmbiguousWrite(errorArg))
|
|
627
|
+
throw errorArg;
|
|
628
|
+
const reconciled = await this.findStoredState();
|
|
629
|
+
const document = ControllerAuthModel.exact.toPersisted(reconciled);
|
|
630
|
+
if (document.setup?.generation === generation
|
|
631
|
+
&& document.setup.hash === setupHash
|
|
632
|
+
&& document.setup.expiresAt.getTime() === expiresAt.getTime()) {
|
|
633
|
+
return { setupCode, generation, expiresAt: new Date(expiresAt) };
|
|
634
|
+
}
|
|
635
|
+
throw new AuthError('ambiguous_write', 'Setup authority rotation has an ambiguous outcome.', { cause: errorArg });
|
|
636
|
+
}
|
|
637
|
+
}
|
|
638
|
+
async getState() {
|
|
639
|
+
const stored = await this.findStoredState();
|
|
640
|
+
return ControllerAuthModel.exact.toPersisted(stored);
|
|
641
|
+
}
|
|
642
|
+
async assertSetupAuthority(setupCodeArg, ceremonyArg, nowArg = new Date()) {
|
|
643
|
+
if (typeof setupCodeArg !== 'string'
|
|
644
|
+
|| setupCodeArg.length > 256
|
|
645
|
+
|| !setupCodePattern.test(setupCodeArg)) {
|
|
646
|
+
throw new AuthError('setup_invalid', 'The setup code is invalid or expired.');
|
|
647
|
+
}
|
|
648
|
+
if (!(nowArg instanceof Date) || !Number.isFinite(nowArg.getTime())) {
|
|
649
|
+
throw new AuthError('setup_invalid', 'The setup validation time is malformed.');
|
|
650
|
+
}
|
|
651
|
+
const state = await this.getState();
|
|
652
|
+
if (state.credentials.length > 0 || state.authState !== 'setupRequired' || !state.setup) {
|
|
653
|
+
throw new AuthError('setup_unavailable', 'Passkey setup is no longer available.');
|
|
654
|
+
}
|
|
655
|
+
if (state.setup.expiresAt.getTime() <= nowArg.getTime()) {
|
|
656
|
+
throw new AuthError('setup_expired', 'The setup code is invalid or expired.');
|
|
657
|
+
}
|
|
658
|
+
if (ceremonyArg
|
|
659
|
+
&& (ceremonyArg.setupGeneration !== state.setup.generation
|
|
660
|
+
|| ceremonyArg.setupHash !== state.setup.hash)) {
|
|
661
|
+
throw new AuthError('setup_invalid', 'The setup code is invalid or expired.');
|
|
662
|
+
}
|
|
663
|
+
const candidateHash = hashSetupCode(setupCodeArg);
|
|
664
|
+
if (!hashesEqual(candidateHash, state.setup.hash)) {
|
|
665
|
+
throw new AuthError('setup_invalid', 'The setup code is invalid or expired.');
|
|
666
|
+
}
|
|
667
|
+
return state;
|
|
668
|
+
}
|
|
669
|
+
async countActiveCeremonies(kindArg, nowArg) {
|
|
670
|
+
this.assertInitialized();
|
|
671
|
+
const kind = requireCeremonyKind(kindArg);
|
|
672
|
+
const now = requireValidDate(nowArg, 'Ceremony count time');
|
|
673
|
+
return WebAuthnCeremonyModel.exact.count({
|
|
674
|
+
kind,
|
|
675
|
+
state: 'pending',
|
|
676
|
+
expiresAt: { $gt: now },
|
|
677
|
+
});
|
|
678
|
+
}
|
|
679
|
+
async createCeremony(ceremonyArg) {
|
|
680
|
+
this.assertInitialized();
|
|
681
|
+
if (ceremonyArg.state !== 'pending') {
|
|
682
|
+
throw new AuthError('ceremony_invalid', 'A new WebAuthn ceremony must be pending.');
|
|
683
|
+
}
|
|
684
|
+
const result = await WebAuthnCeremonyModel.exact.insert(ceremonyArg);
|
|
685
|
+
if (result.status === 'conflict') {
|
|
686
|
+
throw new AuthError('ceremony_invalid', 'The WebAuthn ceremony identifier already exists.');
|
|
687
|
+
}
|
|
688
|
+
return WebAuthnCeremonyModel.exact.toPersisted(result.document);
|
|
689
|
+
}
|
|
690
|
+
async consumeCeremony(optionsArg) {
|
|
691
|
+
const { current, body, now } = await this.findPendingCeremony(optionsArg);
|
|
692
|
+
const consumedAt = now;
|
|
693
|
+
const consumedNonce = randomAuthorityValue();
|
|
694
|
+
try {
|
|
695
|
+
const result = await WebAuthnCeremonyModel.exact.transition({
|
|
696
|
+
current,
|
|
697
|
+
change: (model) => {
|
|
698
|
+
model.state = 'consumed';
|
|
699
|
+
model.consumedAt = consumedAt;
|
|
700
|
+
model.consumedNonce = consumedNonce;
|
|
701
|
+
},
|
|
702
|
+
});
|
|
703
|
+
if (result.status !== 'transitioned') {
|
|
704
|
+
throw new AuthError('ceremony_replayed', 'The WebAuthn ceremony was already consumed.');
|
|
705
|
+
}
|
|
706
|
+
return WebAuthnCeremonyModel.exact.toPersisted(result.document);
|
|
707
|
+
}
|
|
708
|
+
catch (errorArg) {
|
|
709
|
+
if (!isAmbiguousWrite(errorArg))
|
|
710
|
+
throw errorArg;
|
|
711
|
+
const reconciled = await WebAuthnCeremonyModel.exact.findStoredOne({
|
|
712
|
+
id: body.id,
|
|
713
|
+
});
|
|
714
|
+
if (reconciled) {
|
|
715
|
+
const document = WebAuthnCeremonyModel.exact.toPersisted(reconciled);
|
|
716
|
+
if (document.state === 'consumed' && document.consumedNonce === consumedNonce) {
|
|
717
|
+
return document;
|
|
718
|
+
}
|
|
719
|
+
}
|
|
720
|
+
throw new AuthError('ambiguous_write', 'WebAuthn ceremony consumption has an ambiguous outcome.', { cause: errorArg });
|
|
721
|
+
}
|
|
722
|
+
}
|
|
723
|
+
async assertPendingCeremony(optionsArg) {
|
|
724
|
+
const { body } = await this.findPendingCeremony(optionsArg);
|
|
725
|
+
return body;
|
|
726
|
+
}
|
|
727
|
+
async findPendingCeremony(optionsArg) {
|
|
728
|
+
this.assertInitialized();
|
|
729
|
+
const ceremonyId = requireCeremonyId(optionsArg.ceremonyId);
|
|
730
|
+
const kind = requireCeremonyKind(optionsArg.kind);
|
|
731
|
+
const peerId = requirePeerId(optionsArg.peerId);
|
|
732
|
+
const origin = requireOrigin(optionsArg.origin);
|
|
733
|
+
const rpId = requireRpId(optionsArg.rpId);
|
|
734
|
+
const userId = requireUserId(optionsArg.userId);
|
|
735
|
+
const now = requireValidDate(optionsArg.now, 'Ceremony validation time');
|
|
736
|
+
const current = await WebAuthnCeremonyModel.exact.findStoredOne({ id: ceremonyId });
|
|
737
|
+
if (optionsArg.ceremonyId !== ceremonyId
|
|
738
|
+
|| optionsArg.kind !== kind
|
|
739
|
+
|| optionsArg.peerId !== peerId
|
|
740
|
+
|| optionsArg.origin !== origin
|
|
741
|
+
|| optionsArg.rpId !== rpId
|
|
742
|
+
|| optionsArg.userId !== userId
|
|
743
|
+
|| !(optionsArg.now instanceof Date)
|
|
744
|
+
|| optionsArg.now.getTime() !== now.getTime()) {
|
|
745
|
+
throw new AuthError('ceremony_invalid', 'The WebAuthn ceremony validation authority changed during lookup.');
|
|
746
|
+
}
|
|
747
|
+
if (!current)
|
|
748
|
+
throw new AuthError('ceremony_invalid', 'The WebAuthn ceremony is invalid.');
|
|
749
|
+
const body = WebAuthnCeremonyModel.exact.toPersisted(current);
|
|
750
|
+
if (body.kind !== kind) {
|
|
751
|
+
throw new AuthError('ceremony_invalid', 'The WebAuthn ceremony has the wrong kind.');
|
|
752
|
+
}
|
|
753
|
+
if (body.peerId !== peerId) {
|
|
754
|
+
throw new AuthError('peer_mismatch', 'The WebAuthn ceremony belongs to another connection.');
|
|
755
|
+
}
|
|
756
|
+
if (body.origin !== origin) {
|
|
757
|
+
throw new AuthError('origin_mismatch', 'The WebAuthn ceremony origin changed.');
|
|
758
|
+
}
|
|
759
|
+
if (body.rpId !== rpId || body.userId !== userId) {
|
|
760
|
+
throw new AuthError('ceremony_invalid', 'The WebAuthn ceremony authority changed.');
|
|
761
|
+
}
|
|
762
|
+
if (body.expiresAt.getTime() <= now.getTime()) {
|
|
763
|
+
throw new AuthError('ceremony_expired', 'The WebAuthn ceremony expired.');
|
|
764
|
+
}
|
|
765
|
+
if (body.state !== 'pending') {
|
|
766
|
+
throw new AuthError('ceremony_replayed', 'The WebAuthn ceremony was already consumed.');
|
|
767
|
+
}
|
|
768
|
+
return { current, body, now };
|
|
769
|
+
}
|
|
770
|
+
async commitFirstCredential(ceremonyArg, credentialArg) {
|
|
771
|
+
if (ceremonyArg.state !== 'consumed') {
|
|
772
|
+
throw new AuthError('ceremony_invalid', 'The setup ceremony has not been consumed.');
|
|
773
|
+
}
|
|
774
|
+
const current = await this.findStoredState();
|
|
775
|
+
const body = ControllerAuthModel.exact.toPersisted(current);
|
|
776
|
+
if (body.credentials.length > 0 || body.authState !== 'setupRequired' || !body.setup) {
|
|
777
|
+
throw new AuthError('concurrent_change', 'Another passkey won first enrollment.');
|
|
778
|
+
}
|
|
779
|
+
if (body.webauthnUserId !== ceremonyArg.userId
|
|
780
|
+
|| body.config.publicOrigin !== ceremonyArg.origin
|
|
781
|
+
|| body.config.rpId !== ceremonyArg.rpId
|
|
782
|
+
|| body.setup.generation !== ceremonyArg.setupGeneration
|
|
783
|
+
|| body.setup.hash !== ceremonyArg.setupHash) {
|
|
784
|
+
throw new AuthError('concurrent_change', 'Setup authority changed before enrollment.');
|
|
785
|
+
}
|
|
786
|
+
try {
|
|
787
|
+
const result = await ControllerAuthModel.exact.transition({
|
|
788
|
+
current,
|
|
789
|
+
change: (model) => {
|
|
790
|
+
model.authState = 'ready';
|
|
791
|
+
model.setup = null;
|
|
792
|
+
model.credentials = [structuredClone(credentialArg)];
|
|
793
|
+
},
|
|
794
|
+
});
|
|
795
|
+
if (result.status !== 'transitioned') {
|
|
796
|
+
throw new AuthError('concurrent_change', 'Another passkey won first enrollment.');
|
|
797
|
+
}
|
|
798
|
+
return ControllerAuthModel.exact.toPersisted(result.document);
|
|
799
|
+
}
|
|
800
|
+
catch (errorArg) {
|
|
801
|
+
if (!isAmbiguousWrite(errorArg))
|
|
802
|
+
throw errorArg;
|
|
803
|
+
const reconciled = await this.findStoredState();
|
|
804
|
+
const document = ControllerAuthModel.exact.toPersisted(reconciled);
|
|
805
|
+
if (document.credentials.length === 1
|
|
806
|
+
&& document.credentials[0].id === credentialArg.id
|
|
807
|
+
&& document.credentials[0].counterUpdateId === credentialArg.counterUpdateId
|
|
808
|
+
&& document.authState === 'ready'
|
|
809
|
+
&& document.setup === null) {
|
|
810
|
+
return document;
|
|
811
|
+
}
|
|
812
|
+
throw new AuthError('ambiguous_write', 'First passkey enrollment has an ambiguous outcome.', { cause: errorArg });
|
|
813
|
+
}
|
|
814
|
+
}
|
|
815
|
+
async updateCounter(credentialIdArg, expectedCounterArg, newCounterArg) {
|
|
816
|
+
if (typeof credentialIdArg !== 'string' || credentialIdArg.length === 0) {
|
|
817
|
+
throw new AuthError('credential_not_found', 'The passkey credential is malformed.');
|
|
818
|
+
}
|
|
819
|
+
requireSafeCounter(expectedCounterArg, 'expectedCounter');
|
|
820
|
+
requireSafeCounter(newCounterArg, 'newCounter');
|
|
821
|
+
const current = await this.findStoredState();
|
|
822
|
+
const body = ControllerAuthModel.exact.toPersisted(current);
|
|
823
|
+
const credentialIndex = body.credentials.findIndex((credential) => credential.id === credentialIdArg);
|
|
824
|
+
if (credentialIndex < 0) {
|
|
825
|
+
throw new AuthError('credential_not_found', 'The passkey credential is unknown.');
|
|
826
|
+
}
|
|
827
|
+
const credential = body.credentials[credentialIndex];
|
|
828
|
+
if (credential.counter !== expectedCounterArg) {
|
|
829
|
+
throw new AuthError('counter_conflict', 'The passkey counter changed concurrently.');
|
|
830
|
+
}
|
|
831
|
+
if ((expectedCounterArg === 0 && newCounterArg !== 0 && newCounterArg <= expectedCounterArg)
|
|
832
|
+
|| (expectedCounterArg > 0 && newCounterArg <= expectedCounterArg)) {
|
|
833
|
+
throw new AuthError('counter_conflict', 'The passkey counter did not advance.');
|
|
834
|
+
}
|
|
835
|
+
const counterUpdateId = randomAuthorityValue();
|
|
836
|
+
try {
|
|
837
|
+
const result = await ControllerAuthModel.exact.transition({
|
|
838
|
+
current,
|
|
839
|
+
change: (model) => {
|
|
840
|
+
model.credentials = model.credentials.map((entry) => entry.id === credentialIdArg
|
|
841
|
+
? { ...entry, counter: newCounterArg, counterUpdateId }
|
|
842
|
+
: entry);
|
|
843
|
+
},
|
|
844
|
+
});
|
|
845
|
+
if (result.status !== 'transitioned') {
|
|
846
|
+
throw new AuthError('counter_conflict', 'The passkey counter changed concurrently.');
|
|
847
|
+
}
|
|
848
|
+
const document = ControllerAuthModel.exact.toPersisted(result.document);
|
|
849
|
+
return document.credentials.find((entry) => entry.id === credentialIdArg);
|
|
850
|
+
}
|
|
851
|
+
catch (errorArg) {
|
|
852
|
+
if (!isAmbiguousWrite(errorArg))
|
|
853
|
+
throw errorArg;
|
|
854
|
+
const reconciled = await this.findStoredState();
|
|
855
|
+
const document = ControllerAuthModel.exact.toPersisted(reconciled);
|
|
856
|
+
const credentialAfter = document.credentials.find((entry) => entry.id === credentialIdArg);
|
|
857
|
+
if (credentialAfter?.counter === newCounterArg
|
|
858
|
+
&& credentialAfter.counterUpdateId === counterUpdateId) {
|
|
859
|
+
return credentialAfter;
|
|
860
|
+
}
|
|
861
|
+
throw new AuthError('ambiguous_write', 'Passkey counter update has an ambiguous outcome.', { cause: errorArg });
|
|
862
|
+
}
|
|
863
|
+
}
|
|
864
|
+
async recordAuditEvent(eventArg) {
|
|
865
|
+
this.assertInitialized();
|
|
866
|
+
if (!this.controllerId) {
|
|
867
|
+
throw new AuthError('not_initialized', 'The controller runtime configuration is unresolved.');
|
|
868
|
+
}
|
|
869
|
+
const event = {
|
|
870
|
+
id: randomAuthorityValue(),
|
|
871
|
+
controllerId: this.controllerId,
|
|
872
|
+
timestamp: eventArg.timestamp === undefined
|
|
873
|
+
? new Date()
|
|
874
|
+
: new Date(eventArg.timestamp),
|
|
875
|
+
type: eventArg.type,
|
|
876
|
+
outcome: eventArg.outcome,
|
|
877
|
+
...(eventArg.operationId === undefined ? {} : { operationId: eventArg.operationId }),
|
|
878
|
+
...(eventArg.peerId === undefined ? {} : { peerId: eventArg.peerId }),
|
|
879
|
+
...(eventArg.credentialId === undefined ? {} : { credentialId: eventArg.credentialId }),
|
|
880
|
+
...(eventArg.sessionId === undefined ? {} : { sessionId: { ...eventArg.sessionId } }),
|
|
881
|
+
...(eventArg.requestId === undefined ? {} : { requestId: { ...eventArg.requestId } }),
|
|
882
|
+
};
|
|
883
|
+
try {
|
|
884
|
+
const result = await ControllerAuditEventModel.exact.insert(event);
|
|
885
|
+
if (result.status === 'conflict') {
|
|
886
|
+
throw new AuthError('concurrent_change', 'The audit event identifier conflicts.');
|
|
887
|
+
}
|
|
888
|
+
return ControllerAuditEventModel.exact.toPersisted(result.document);
|
|
889
|
+
}
|
|
890
|
+
catch (errorArg) {
|
|
891
|
+
if (!isAmbiguousWrite(errorArg))
|
|
892
|
+
throw errorArg;
|
|
893
|
+
const reconciled = await ControllerAuditEventModel.exact.findStoredOne({ id: event.id });
|
|
894
|
+
if (reconciled) {
|
|
895
|
+
const document = ControllerAuditEventModel.exact.toPersisted(reconciled);
|
|
896
|
+
if (this.auditEventsEqual(document, event))
|
|
897
|
+
return document;
|
|
898
|
+
}
|
|
899
|
+
throw new AuthError('ambiguous_write', 'Audit event persistence has an ambiguous outcome.', { cause: errorArg });
|
|
900
|
+
}
|
|
901
|
+
}
|
|
902
|
+
assertInitialized() {
|
|
903
|
+
if (!this.initialized) {
|
|
904
|
+
throw new AuthError('not_initialized', 'The authentication store is not initialized.');
|
|
905
|
+
}
|
|
906
|
+
}
|
|
907
|
+
async findStoredState() {
|
|
908
|
+
this.assertInitialized();
|
|
909
|
+
if (!this.controllerId) {
|
|
910
|
+
throw new AuthError('not_initialized', 'The controller runtime configuration is unresolved.');
|
|
911
|
+
}
|
|
912
|
+
const stored = await ControllerAuthModel.exact.findStoredOne({ id: this.controllerId });
|
|
913
|
+
if (!stored) {
|
|
914
|
+
throw new AuthError('not_initialized', 'The controller authentication document is missing.');
|
|
915
|
+
}
|
|
916
|
+
return stored;
|
|
917
|
+
}
|
|
918
|
+
requireControllerId() {
|
|
919
|
+
if (!this.controllerId) {
|
|
920
|
+
throw new AuthError('not_initialized', 'The controller identity has not been resolved yet.');
|
|
921
|
+
}
|
|
922
|
+
return this.controllerId;
|
|
923
|
+
}
|
|
924
|
+
async listProjects() {
|
|
925
|
+
this.assertInitialized();
|
|
926
|
+
const controllerId = this.requireControllerId();
|
|
927
|
+
const stored = await ControllerProjectModel.exact.findStored({
|
|
928
|
+
filter: {
|
|
929
|
+
controllerId,
|
|
930
|
+
removalStartedAt: { $exists: false },
|
|
931
|
+
removedAt: { $exists: false },
|
|
932
|
+
},
|
|
933
|
+
sort: { createdAt: 1 },
|
|
934
|
+
limit: controllerProjectLimit + 1,
|
|
935
|
+
});
|
|
936
|
+
if (stored.length > controllerProjectLimit) {
|
|
937
|
+
throw new AuthError('invalid_project', `The controller exceeds the ${controllerProjectLimit}-project limit.`);
|
|
938
|
+
}
|
|
939
|
+
return stored.map((entry) => ControllerProjectModel.exact.toPersisted(entry));
|
|
940
|
+
}
|
|
941
|
+
async createProject(nameArg, directoryArg, identityArg) {
|
|
942
|
+
this.assertInitialized();
|
|
943
|
+
const controllerId = this.requireControllerId();
|
|
944
|
+
if (!isProjectRelativePathName(nameArg)) {
|
|
945
|
+
throw new AuthError('invalid_project', 'Project names must be directory paths without dot navigation.');
|
|
946
|
+
}
|
|
947
|
+
if (typeof directoryArg !== 'string' || !plugins.path.isAbsolute(directoryArg)) {
|
|
948
|
+
throw new AuthError('invalid_project', 'The project directory must be an absolute path.');
|
|
949
|
+
}
|
|
950
|
+
return this.withProjectMutation(async () => {
|
|
951
|
+
const activeProjects = await this.listProjects();
|
|
952
|
+
const existing = activeProjects.find((entry) => entry.directory === directoryArg);
|
|
953
|
+
if (existing) {
|
|
954
|
+
if (existing.directoryIdentityState !== 'bound'
|
|
955
|
+
|| existing.directoryIdentity === undefined
|
|
956
|
+
|| !filesystemIdentitiesEqual(existing.directoryIdentity, identityArg)) {
|
|
957
|
+
throw new AuthError('concurrent_change', 'The registered project path has a different filesystem identity.');
|
|
958
|
+
}
|
|
959
|
+
return { project: existing, created: false };
|
|
960
|
+
}
|
|
961
|
+
const pendingRemovals = await this.listPendingProjectRemovals();
|
|
962
|
+
if (activeProjects.length + pendingRemovals.length >= controllerProjectLimit) {
|
|
963
|
+
throw new AuthError('invalid_project', `The controller supports at most ${controllerProjectLimit} active or pending-removal projects.`);
|
|
964
|
+
}
|
|
965
|
+
if (pendingRemovals.some((entry) => (entry.directory === directoryArg || entry.name === nameArg))) {
|
|
966
|
+
throw new AuthError('concurrent_change', 'The project path is still being removed and cannot be registered again.');
|
|
967
|
+
}
|
|
968
|
+
if (activeProjects.some((entry) => entry.name === nameArg)) {
|
|
969
|
+
throw new AuthError('invalid_project', 'A project with this name already exists.');
|
|
970
|
+
}
|
|
971
|
+
const candidate = {
|
|
972
|
+
id: plugins.crypto.randomBytes(16).toString('base64url'),
|
|
973
|
+
controllerId,
|
|
974
|
+
name: nameArg,
|
|
975
|
+
directory: directoryArg,
|
|
976
|
+
directoryIdentityState: 'bound',
|
|
977
|
+
directoryIdentity: structuredClone(identityArg),
|
|
978
|
+
createdAt: new Date(),
|
|
979
|
+
};
|
|
980
|
+
const result = await ControllerProjectModel.exact.insert(candidate);
|
|
981
|
+
if (result.status === 'conflict') {
|
|
982
|
+
throw new AuthError('concurrent_change', 'The project was created concurrently.');
|
|
983
|
+
}
|
|
984
|
+
return { project: ControllerProjectModel.exact.toPersisted(result.document), created: true };
|
|
985
|
+
});
|
|
986
|
+
}
|
|
987
|
+
async removeProject(projectIdArg) {
|
|
988
|
+
this.assertInitialized();
|
|
989
|
+
const controllerId = this.requireControllerId();
|
|
990
|
+
if (typeof projectIdArg !== 'string' || projectIdArg.length === 0 || projectIdArg.length > 64) {
|
|
991
|
+
throw new AuthError('invalid_project', 'The project identifier is malformed.');
|
|
992
|
+
}
|
|
993
|
+
return this.withProjectMutation(async () => {
|
|
994
|
+
const stored = await ControllerProjectModel.exact.findStoredOne({ id: projectIdArg });
|
|
995
|
+
if (!stored)
|
|
996
|
+
return false;
|
|
997
|
+
const document = ControllerProjectModel.exact.toPersisted(stored);
|
|
998
|
+
if (document.controllerId !== controllerId
|
|
999
|
+
|| document.removedAt !== undefined
|
|
1000
|
+
|| document.removalStartedAt === undefined) {
|
|
1001
|
+
return false;
|
|
1002
|
+
}
|
|
1003
|
+
const result = await ControllerProjectModel.exact.transition({
|
|
1004
|
+
current: stored,
|
|
1005
|
+
change: (model) => {
|
|
1006
|
+
delete model.removalStartedAt;
|
|
1007
|
+
model.removedAt = new Date();
|
|
1008
|
+
},
|
|
1009
|
+
});
|
|
1010
|
+
if (result.status !== 'transitioned') {
|
|
1011
|
+
throw new AuthError('concurrent_change', 'The project changed concurrently and was not removed.');
|
|
1012
|
+
}
|
|
1013
|
+
return true;
|
|
1014
|
+
});
|
|
1015
|
+
}
|
|
1016
|
+
async beginProjectRemoval(projectIdArg) {
|
|
1017
|
+
this.assertInitialized();
|
|
1018
|
+
const controllerId = this.requireControllerId();
|
|
1019
|
+
if (typeof projectIdArg !== 'string' || projectIdArg.length === 0 || projectIdArg.length > 64) {
|
|
1020
|
+
throw new AuthError('invalid_project', 'The project identifier is malformed.');
|
|
1021
|
+
}
|
|
1022
|
+
return this.withProjectMutation(async () => {
|
|
1023
|
+
const stored = await ControllerProjectModel.exact.findStoredOne({ id: projectIdArg });
|
|
1024
|
+
if (!stored)
|
|
1025
|
+
return undefined;
|
|
1026
|
+
const document = ControllerProjectModel.exact.toPersisted(stored);
|
|
1027
|
+
if (document.controllerId !== controllerId || document.removedAt !== undefined)
|
|
1028
|
+
return undefined;
|
|
1029
|
+
if (document.removalStartedAt !== undefined)
|
|
1030
|
+
return document;
|
|
1031
|
+
const result = await ControllerProjectModel.exact.transition({
|
|
1032
|
+
current: stored,
|
|
1033
|
+
change: (model) => {
|
|
1034
|
+
model.removalStartedAt = new Date();
|
|
1035
|
+
},
|
|
1036
|
+
});
|
|
1037
|
+
if (result.status !== 'transitioned') {
|
|
1038
|
+
throw new AuthError('concurrent_change', 'The project changed concurrently and was not retired.');
|
|
1039
|
+
}
|
|
1040
|
+
return ControllerProjectModel.exact.toPersisted(result.document);
|
|
1041
|
+
});
|
|
1042
|
+
}
|
|
1043
|
+
async listPendingProjectRemovals() {
|
|
1044
|
+
this.assertInitialized();
|
|
1045
|
+
const controllerId = this.requireControllerId();
|
|
1046
|
+
const stored = await ControllerProjectModel.exact.findStored({
|
|
1047
|
+
filter: {
|
|
1048
|
+
controllerId,
|
|
1049
|
+
removalStartedAt: { $exists: true },
|
|
1050
|
+
removedAt: { $exists: false },
|
|
1051
|
+
},
|
|
1052
|
+
sort: { removalStartedAt: 1 },
|
|
1053
|
+
limit: controllerProjectLimit + 1,
|
|
1054
|
+
});
|
|
1055
|
+
if (stored.length > controllerProjectLimit) {
|
|
1056
|
+
throw new AuthError('invalid_project', 'The pending project-removal limit was exceeded.');
|
|
1057
|
+
}
|
|
1058
|
+
return stored.map((entry) => ControllerProjectModel.exact.toPersisted(entry));
|
|
1059
|
+
}
|
|
1060
|
+
withProjectMutation(operationArg) {
|
|
1061
|
+
if (!this.projectMutationAdmissionOpen) {
|
|
1062
|
+
return Promise.reject(new AuthError('not_initialized', 'Project mutations are unavailable while the authentication store is closing.'));
|
|
1063
|
+
}
|
|
1064
|
+
const operation = this.projectMutationTail.then(async () => {
|
|
1065
|
+
if (!this.projectMutationAdmissionOpen) {
|
|
1066
|
+
throw new AuthError('not_initialized', 'Project mutations are unavailable while the authentication store is closing.');
|
|
1067
|
+
}
|
|
1068
|
+
return operationArg();
|
|
1069
|
+
});
|
|
1070
|
+
this.projectMutationTail = operation.then(() => undefined, () => undefined);
|
|
1071
|
+
return operation;
|
|
1072
|
+
}
|
|
1073
|
+
async insertResourceDocument(candidateArg) {
|
|
1074
|
+
try {
|
|
1075
|
+
const result = await ControllerResourceModel.exact.insert(candidateArg);
|
|
1076
|
+
if (result.status === 'conflict') {
|
|
1077
|
+
throw new AuthError('concurrent_change', 'The resource identifier conflicted.');
|
|
1078
|
+
}
|
|
1079
|
+
return cloneResourceDocument(ControllerResourceModel.exact.toPersisted(result.document));
|
|
1080
|
+
}
|
|
1081
|
+
catch (errorArg) {
|
|
1082
|
+
if (!isAmbiguousWrite(errorArg))
|
|
1083
|
+
throw errorArg;
|
|
1084
|
+
const reconciled = await ControllerResourceModel.exact.findStoredOne({ id: candidateArg.id });
|
|
1085
|
+
if (reconciled) {
|
|
1086
|
+
const document = ControllerResourceModel.exact.toPersisted(reconciled);
|
|
1087
|
+
if (document.updateId === candidateArg.updateId)
|
|
1088
|
+
return cloneResourceDocument(document);
|
|
1089
|
+
}
|
|
1090
|
+
throw new AuthError('ambiguous_write', 'The resource insertion has an ambiguous outcome.', { cause: errorArg });
|
|
1091
|
+
}
|
|
1092
|
+
}
|
|
1093
|
+
async transitionResourceDocument(currentArg, changeArg, concurrentMessageArg, ambiguousMessageArg) {
|
|
1094
|
+
const current = ControllerResourceModel.exact.toPersisted(currentArg);
|
|
1095
|
+
const updateId = randomAuthorityValue();
|
|
1096
|
+
try {
|
|
1097
|
+
const result = await ControllerResourceModel.exact.transition({
|
|
1098
|
+
current: currentArg,
|
|
1099
|
+
change: (model) => {
|
|
1100
|
+
changeArg(model);
|
|
1101
|
+
model.updateId = updateId;
|
|
1102
|
+
},
|
|
1103
|
+
});
|
|
1104
|
+
if (result.status !== 'transitioned') {
|
|
1105
|
+
throw new AuthError('concurrent_change', concurrentMessageArg);
|
|
1106
|
+
}
|
|
1107
|
+
return cloneResourceDocument(ControllerResourceModel.exact.toPersisted(result.document));
|
|
1108
|
+
}
|
|
1109
|
+
catch (errorArg) {
|
|
1110
|
+
if (!isAmbiguousWrite(errorArg))
|
|
1111
|
+
throw errorArg;
|
|
1112
|
+
const reconciled = await ControllerResourceModel.exact.findStoredOne({ id: current.id });
|
|
1113
|
+
if (reconciled) {
|
|
1114
|
+
const document = ControllerResourceModel.exact.toPersisted(reconciled);
|
|
1115
|
+
if (document.updateId === updateId)
|
|
1116
|
+
return cloneResourceDocument(document);
|
|
1117
|
+
}
|
|
1118
|
+
throw new AuthError('ambiguous_write', ambiguousMessageArg, { cause: errorArg });
|
|
1119
|
+
}
|
|
1120
|
+
}
|
|
1121
|
+
async getProject(projectIdArg) {
|
|
1122
|
+
this.assertInitialized();
|
|
1123
|
+
const controllerId = this.requireControllerId();
|
|
1124
|
+
if (typeof projectIdArg !== 'string' || projectIdArg.length === 0 || projectIdArg.length > 64) {
|
|
1125
|
+
return undefined;
|
|
1126
|
+
}
|
|
1127
|
+
const stored = await ControllerProjectModel.exact.findStoredOne({ id: projectIdArg });
|
|
1128
|
+
if (!stored)
|
|
1129
|
+
return undefined;
|
|
1130
|
+
const document = ControllerProjectModel.exact.toPersisted(stored);
|
|
1131
|
+
if (document.controllerId !== controllerId
|
|
1132
|
+
|| document.removalStartedAt !== undefined
|
|
1133
|
+
|| document.removedAt !== undefined) {
|
|
1134
|
+
return undefined;
|
|
1135
|
+
}
|
|
1136
|
+
return document;
|
|
1137
|
+
}
|
|
1138
|
+
async getPendingProjectRemoval(projectIdArg) {
|
|
1139
|
+
this.assertInitialized();
|
|
1140
|
+
const controllerId = this.requireControllerId();
|
|
1141
|
+
if (typeof projectIdArg !== 'string' || projectIdArg.length === 0 || projectIdArg.length > 64) {
|
|
1142
|
+
return undefined;
|
|
1143
|
+
}
|
|
1144
|
+
const stored = await ControllerProjectModel.exact.findStoredOne({ id: projectIdArg });
|
|
1145
|
+
if (!stored)
|
|
1146
|
+
return undefined;
|
|
1147
|
+
const document = ControllerProjectModel.exact.toPersisted(stored);
|
|
1148
|
+
if (document.controllerId !== controllerId
|
|
1149
|
+
|| document.removalStartedAt === undefined
|
|
1150
|
+
|| document.removedAt !== undefined)
|
|
1151
|
+
return undefined;
|
|
1152
|
+
return document;
|
|
1153
|
+
}
|
|
1154
|
+
async listResources(projectIdArg, optionsArg = {}) {
|
|
1155
|
+
this.assertInitialized();
|
|
1156
|
+
const controllerId = this.requireControllerId();
|
|
1157
|
+
const stored = await ControllerResourceModel.exact.findStored({
|
|
1158
|
+
filter: {
|
|
1159
|
+
controllerId,
|
|
1160
|
+
projectId: projectIdArg,
|
|
1161
|
+
...(optionsArg.includeRetired ? {} : { retiredAt: { $exists: false } }),
|
|
1162
|
+
},
|
|
1163
|
+
sort: { createdAt: 1 },
|
|
1164
|
+
limit: controllerResourcesPerProjectLimit + 1,
|
|
1165
|
+
});
|
|
1166
|
+
if (stored.length > controllerResourcesPerProjectLimit) {
|
|
1167
|
+
throw new AuthError('invalid_resource', `The project exceeds the ${controllerResourcesPerProjectLimit}-resource limit.`);
|
|
1168
|
+
}
|
|
1169
|
+
return stored.map((entry) => cloneResourceDocument(ControllerResourceModel.exact.toPersisted(entry)));
|
|
1170
|
+
}
|
|
1171
|
+
async listRecoverableResources() {
|
|
1172
|
+
this.assertInitialized();
|
|
1173
|
+
const stored = await ControllerResourceModel.exact.findStored({
|
|
1174
|
+
filter: {
|
|
1175
|
+
controllerId: this.requireControllerId(),
|
|
1176
|
+
retiredAt: { $exists: false },
|
|
1177
|
+
},
|
|
1178
|
+
sort: { createdAt: 1 },
|
|
1179
|
+
limit: controllerResourceLimit + 1,
|
|
1180
|
+
});
|
|
1181
|
+
if (stored.length > controllerResourceLimit) {
|
|
1182
|
+
throw new AuthError('invalid_resource', 'The controller resource limit was exceeded.');
|
|
1183
|
+
}
|
|
1184
|
+
return stored.map((entry) => cloneResourceDocument(ControllerResourceModel.exact.toPersisted(entry)));
|
|
1185
|
+
}
|
|
1186
|
+
async getResource(projectIdArg, resourceIdArg, optionsArg = {}) {
|
|
1187
|
+
this.assertInitialized();
|
|
1188
|
+
const stored = await ControllerResourceModel.exact.findStoredOne({ id: resourceIdArg });
|
|
1189
|
+
if (!stored)
|
|
1190
|
+
return undefined;
|
|
1191
|
+
const resource = ControllerResourceModel.exact.toPersisted(stored);
|
|
1192
|
+
if (resource.controllerId !== this.requireControllerId()
|
|
1193
|
+
|| resource.projectId !== projectIdArg
|
|
1194
|
+
|| (!optionsArg.includeRetired && resource.lifecycle === 'retired'))
|
|
1195
|
+
return undefined;
|
|
1196
|
+
return cloneResourceDocument(resource);
|
|
1197
|
+
}
|
|
1198
|
+
async createResource(inputArg) {
|
|
1199
|
+
this.assertInitialized();
|
|
1200
|
+
return this.withProjectMutation(async () => {
|
|
1201
|
+
const project = await this.getProject(inputArg.projectId);
|
|
1202
|
+
if (!project)
|
|
1203
|
+
throw new AuthError('invalid_project', 'The resource project is unavailable.');
|
|
1204
|
+
const [existing, recoverable] = await Promise.all([
|
|
1205
|
+
this.listResources(inputArg.projectId),
|
|
1206
|
+
this.listRecoverableResources(),
|
|
1207
|
+
]);
|
|
1208
|
+
assertControllerResourceCreationCapacity(existing.length, recoverable.length);
|
|
1209
|
+
const now = new Date();
|
|
1210
|
+
const candidate = {
|
|
1211
|
+
id: randomResourceId(),
|
|
1212
|
+
controllerId: this.requireControllerId(),
|
|
1213
|
+
projectId: inputArg.projectId,
|
|
1214
|
+
kind: inputArg.kind,
|
|
1215
|
+
title: inputArg.title,
|
|
1216
|
+
attachmentAuthorityId: randomAuthorityValue(),
|
|
1217
|
+
attachmentRevision: 0,
|
|
1218
|
+
sessionId: null,
|
|
1219
|
+
lifecycle: 'active',
|
|
1220
|
+
...(inputArg.terminal === undefined ? {} : { terminal: { ...inputArg.terminal } }),
|
|
1221
|
+
createdAt: now,
|
|
1222
|
+
updatedAt: now,
|
|
1223
|
+
updateId: randomAuthorityValue(),
|
|
1224
|
+
};
|
|
1225
|
+
return this.insertResourceDocument(candidate);
|
|
1226
|
+
});
|
|
1227
|
+
}
|
|
1228
|
+
async renameResource(projectIdArg, resourceIdArg, titleArg) {
|
|
1229
|
+
const current = await ControllerResourceModel.exact.findStoredOne({ id: resourceIdArg });
|
|
1230
|
+
if (!current)
|
|
1231
|
+
throw new AuthError('invalid_resource', 'The resource does not exist.');
|
|
1232
|
+
const before = ControllerResourceModel.exact.toPersisted(current);
|
|
1233
|
+
if (before.controllerId !== this.requireControllerId()
|
|
1234
|
+
|| before.projectId !== projectIdArg
|
|
1235
|
+
|| before.lifecycle !== 'active')
|
|
1236
|
+
throw new AuthError('invalid_resource', 'The resource is unavailable.');
|
|
1237
|
+
return this.transitionResourceDocument(current, (model) => {
|
|
1238
|
+
model.title = titleArg;
|
|
1239
|
+
model.updatedAt = new Date();
|
|
1240
|
+
}, 'The resource changed concurrently.', 'The resource rename has an ambiguous outcome.');
|
|
1241
|
+
}
|
|
1242
|
+
async beginResourceAttachmentTransition(projectIdArg, resourceIdArg, sessionIdArg, expectedAttachmentRevisionArg) {
|
|
1243
|
+
if (!Number.isSafeInteger(expectedAttachmentRevisionArg) || expectedAttachmentRevisionArg < 0) {
|
|
1244
|
+
throw new AuthError('invalid_resource', 'The expected attachment revision is malformed.');
|
|
1245
|
+
}
|
|
1246
|
+
const current = await ControllerResourceModel.exact.findStoredOne({ id: resourceIdArg });
|
|
1247
|
+
if (!current)
|
|
1248
|
+
throw new AuthError('invalid_resource', 'The resource does not exist.');
|
|
1249
|
+
const before = ControllerResourceModel.exact.toPersisted(current);
|
|
1250
|
+
if (before.controllerId !== this.requireControllerId()
|
|
1251
|
+
|| before.projectId !== projectIdArg
|
|
1252
|
+
|| before.lifecycle !== 'active')
|
|
1253
|
+
throw new AuthError('invalid_resource', 'The resource is unavailable.');
|
|
1254
|
+
if (before.pendingAttachment) {
|
|
1255
|
+
throw new AuthError('concurrent_change', 'The resource attachment is already changing.');
|
|
1256
|
+
}
|
|
1257
|
+
if (before.attachmentRevision !== expectedAttachmentRevisionArg) {
|
|
1258
|
+
throw new AuthError('concurrent_change', 'The resource attachment changed concurrently.');
|
|
1259
|
+
}
|
|
1260
|
+
const operationId = randomResourceOperationId();
|
|
1261
|
+
return this.transitionResourceDocument(current, (model) => {
|
|
1262
|
+
model.pendingAttachment = {
|
|
1263
|
+
operationId,
|
|
1264
|
+
attachmentRevision: before.attachmentRevision + 1,
|
|
1265
|
+
sessionId: cloneSessionId(sessionIdArg),
|
|
1266
|
+
requestedAt: new Date(),
|
|
1267
|
+
};
|
|
1268
|
+
model.updatedAt = new Date();
|
|
1269
|
+
}, 'The resource attachment changed concurrently.', 'Preparing the resource attachment has an ambiguous outcome.');
|
|
1270
|
+
}
|
|
1271
|
+
async commitResourceAttachmentTransition(projectIdArg, resourceIdArg, operationIdArg) {
|
|
1272
|
+
const current = await ControllerResourceModel.exact.findStoredOne({ id: resourceIdArg });
|
|
1273
|
+
if (!current)
|
|
1274
|
+
throw new AuthError('invalid_resource', 'The resource does not exist.');
|
|
1275
|
+
const before = ControllerResourceModel.exact.toPersisted(current);
|
|
1276
|
+
if (before.controllerId !== this.requireControllerId()
|
|
1277
|
+
|| before.projectId !== projectIdArg
|
|
1278
|
+
|| before.lifecycle !== 'active'
|
|
1279
|
+
|| before.pendingAttachment?.operationId !== operationIdArg)
|
|
1280
|
+
throw new AuthError('concurrent_change', 'The pending resource attachment no longer matches.');
|
|
1281
|
+
const pending = before.pendingAttachment;
|
|
1282
|
+
return this.transitionResourceDocument(current, (model) => {
|
|
1283
|
+
model.attachmentRevision = pending.attachmentRevision;
|
|
1284
|
+
model.sessionId = cloneSessionId(pending.sessionId);
|
|
1285
|
+
delete model.pendingAttachment;
|
|
1286
|
+
model.updatedAt = new Date();
|
|
1287
|
+
}, 'The resource attachment changed concurrently.', 'Committing the resource attachment has an ambiguous outcome.');
|
|
1288
|
+
}
|
|
1289
|
+
async beginResourceRetirement(projectIdArg, resourceIdArg) {
|
|
1290
|
+
const current = await ControllerResourceModel.exact.findStoredOne({ id: resourceIdArg });
|
|
1291
|
+
if (!current)
|
|
1292
|
+
throw new AuthError('invalid_resource', 'The resource does not exist.');
|
|
1293
|
+
const before = ControllerResourceModel.exact.toPersisted(current);
|
|
1294
|
+
if (before.controllerId !== this.requireControllerId() || before.projectId !== projectIdArg) {
|
|
1295
|
+
throw new AuthError('invalid_resource', 'The resource is unavailable.');
|
|
1296
|
+
}
|
|
1297
|
+
if (before.lifecycle !== 'active')
|
|
1298
|
+
return cloneResourceDocument(before);
|
|
1299
|
+
if (before.pendingAttachment) {
|
|
1300
|
+
throw new AuthError('concurrent_change', 'The resource attachment must settle before retirement.');
|
|
1301
|
+
}
|
|
1302
|
+
const now = new Date();
|
|
1303
|
+
return this.transitionResourceDocument(current, (model) => {
|
|
1304
|
+
model.lifecycle = 'retiring';
|
|
1305
|
+
model.retiringAt = now;
|
|
1306
|
+
model.updatedAt = now;
|
|
1307
|
+
}, 'The resource changed concurrently.', 'Preparing resource retirement has an ambiguous outcome.');
|
|
1308
|
+
}
|
|
1309
|
+
async completeResourceRetirement(projectIdArg, resourceIdArg) {
|
|
1310
|
+
const current = await ControllerResourceModel.exact.findStoredOne({ id: resourceIdArg });
|
|
1311
|
+
if (!current)
|
|
1312
|
+
throw new AuthError('invalid_resource', 'The resource does not exist.');
|
|
1313
|
+
const before = ControllerResourceModel.exact.toPersisted(current);
|
|
1314
|
+
if (before.controllerId !== this.requireControllerId() || before.projectId !== projectIdArg) {
|
|
1315
|
+
throw new AuthError('invalid_resource', 'The resource is unavailable.');
|
|
1316
|
+
}
|
|
1317
|
+
if (before.lifecycle === 'retired')
|
|
1318
|
+
return cloneResourceDocument(before);
|
|
1319
|
+
if (before.lifecycle !== 'retiring') {
|
|
1320
|
+
throw new AuthError('concurrent_change', 'The resource is not retiring.');
|
|
1321
|
+
}
|
|
1322
|
+
const now = new Date();
|
|
1323
|
+
return this.transitionResourceDocument(current, (model) => {
|
|
1324
|
+
model.lifecycle = 'retired';
|
|
1325
|
+
model.retiredAt = now;
|
|
1326
|
+
model.updatedAt = now;
|
|
1327
|
+
}, 'The resource changed concurrently.', 'Completing resource retirement has an ambiguous outcome.');
|
|
1328
|
+
}
|
|
1329
|
+
async markTerminalResourceStopped(projectIdArg, resourceIdArg, outcomeArg = {}) {
|
|
1330
|
+
const current = await ControllerResourceModel.exact.findStoredOne({ id: resourceIdArg });
|
|
1331
|
+
if (!current)
|
|
1332
|
+
throw new AuthError('invalid_resource', 'The terminal resource does not exist.');
|
|
1333
|
+
const before = ControllerResourceModel.exact.toPersisted(current);
|
|
1334
|
+
if (before.controllerId !== this.requireControllerId()
|
|
1335
|
+
|| before.projectId !== projectIdArg
|
|
1336
|
+
|| before.kind !== 'terminal'
|
|
1337
|
+
|| !before.terminal
|
|
1338
|
+
|| before.lifecycle === 'retired')
|
|
1339
|
+
throw new AuthError('invalid_resource', 'The terminal resource is unavailable.');
|
|
1340
|
+
const stoppedAt = outcomeArg.stoppedAt ?? new Date();
|
|
1341
|
+
return this.transitionResourceDocument(current, (model) => {
|
|
1342
|
+
model.terminal = {
|
|
1343
|
+
command: before.terminal.command,
|
|
1344
|
+
args: [...before.terminal.args],
|
|
1345
|
+
cwd: before.terminal.cwd,
|
|
1346
|
+
stoppedAt,
|
|
1347
|
+
...(outcomeArg.lastExitCode === undefined ? {} : { lastExitCode: outcomeArg.lastExitCode }),
|
|
1348
|
+
};
|
|
1349
|
+
model.updatedAt = stoppedAt;
|
|
1350
|
+
}, 'The terminal resource changed concurrently.', 'Persisting the stopped terminal resource has an ambiguous outcome.');
|
|
1351
|
+
}
|
|
1352
|
+
async markTerminalResourceRunning(projectIdArg, resourceIdArg) {
|
|
1353
|
+
const current = await ControllerResourceModel.exact.findStoredOne({ id: resourceIdArg });
|
|
1354
|
+
if (!current)
|
|
1355
|
+
throw new AuthError('invalid_resource', 'The terminal resource does not exist.');
|
|
1356
|
+
const before = ControllerResourceModel.exact.toPersisted(current);
|
|
1357
|
+
if (before.controllerId !== this.requireControllerId()
|
|
1358
|
+
|| before.projectId !== projectIdArg
|
|
1359
|
+
|| before.kind !== 'terminal'
|
|
1360
|
+
|| !before.terminal
|
|
1361
|
+
|| before.lifecycle !== 'active')
|
|
1362
|
+
throw new AuthError('invalid_resource', 'The terminal resource is unavailable.');
|
|
1363
|
+
const now = new Date();
|
|
1364
|
+
return this.transitionResourceDocument(current, (model) => {
|
|
1365
|
+
model.terminal = {
|
|
1366
|
+
command: before.terminal.command,
|
|
1367
|
+
args: [...before.terminal.args],
|
|
1368
|
+
cwd: before.terminal.cwd,
|
|
1369
|
+
};
|
|
1370
|
+
model.updatedAt = now;
|
|
1371
|
+
}, 'The terminal resource changed concurrently.', 'Persisting the running terminal resource has an ambiguous outcome.');
|
|
1372
|
+
}
|
|
1373
|
+
async getSettings() {
|
|
1374
|
+
this.assertInitialized();
|
|
1375
|
+
const controllerId = this.requireControllerId();
|
|
1376
|
+
const stored = await ControllerSettingsModel.exact.findStoredOne({
|
|
1377
|
+
id: `${controllerId}:settings`,
|
|
1378
|
+
});
|
|
1379
|
+
if (stored) {
|
|
1380
|
+
const persisted = ControllerSettingsModel.exact.toPersisted(stored);
|
|
1381
|
+
return { ...persisted, defaultModels: persisted.defaultModels.map(cloneModelChoice) };
|
|
1382
|
+
}
|
|
1383
|
+
return { id: `${controllerId}:settings`, controllerId, defaultModels: [] };
|
|
1384
|
+
}
|
|
1385
|
+
async updateSettings(patchArg) {
|
|
1386
|
+
this.assertInitialized();
|
|
1387
|
+
const controllerId = this.requireControllerId();
|
|
1388
|
+
const settingsId = `${controllerId}:settings`;
|
|
1389
|
+
const defaultModelsUpdate = patchArg.defaultModels === undefined
|
|
1390
|
+
? undefined
|
|
1391
|
+
: patchArg.defaultModels.map(cloneModelChoice);
|
|
1392
|
+
const applyPatch = (targetArg) => {
|
|
1393
|
+
if (defaultModelsUpdate !== undefined) {
|
|
1394
|
+
targetArg.defaultModels = defaultModelsUpdate;
|
|
1395
|
+
}
|
|
1396
|
+
if (patchArg.autoAcceptPermissions !== undefined) {
|
|
1397
|
+
if (patchArg.autoAcceptPermissions) {
|
|
1398
|
+
targetArg.autoAcceptPermissions = true;
|
|
1399
|
+
}
|
|
1400
|
+
else {
|
|
1401
|
+
// Disabled is an absent key; undefined values are dropped on write.
|
|
1402
|
+
delete targetArg.autoAcceptPermissions;
|
|
1403
|
+
}
|
|
1404
|
+
}
|
|
1405
|
+
if (patchArg.selectedOpenCodeProviderConnectionId !== undefined) {
|
|
1406
|
+
if (patchArg.selectedOpenCodeProviderConnectionId === null) {
|
|
1407
|
+
delete targetArg.selectedOpenCodeProviderConnectionId;
|
|
1408
|
+
}
|
|
1409
|
+
else {
|
|
1410
|
+
targetArg.selectedOpenCodeProviderConnectionId = patchArg.selectedOpenCodeProviderConnectionId;
|
|
1411
|
+
}
|
|
1412
|
+
}
|
|
1413
|
+
};
|
|
1414
|
+
const stored = await ControllerSettingsModel.exact.findStoredOne({ id: settingsId });
|
|
1415
|
+
if (!stored) {
|
|
1416
|
+
const candidate = {
|
|
1417
|
+
id: settingsId,
|
|
1418
|
+
controllerId,
|
|
1419
|
+
defaultModels: [],
|
|
1420
|
+
};
|
|
1421
|
+
applyPatch(candidate);
|
|
1422
|
+
const insertResult = await ControllerSettingsModel.exact.insert(candidate);
|
|
1423
|
+
if (insertResult.status !== 'conflict') {
|
|
1424
|
+
return ControllerSettingsModel.exact.toPersisted(insertResult.document);
|
|
1425
|
+
}
|
|
1426
|
+
// fall through to transition against the concurrently created document
|
|
1427
|
+
}
|
|
1428
|
+
const current = stored ?? await ControllerSettingsModel.exact.findStoredOne({ id: settingsId });
|
|
1429
|
+
if (!current) {
|
|
1430
|
+
throw new AuthError('ambiguous_write', 'The settings document has an ambiguous state.');
|
|
1431
|
+
}
|
|
1432
|
+
const result = await ControllerSettingsModel.exact.transition({
|
|
1433
|
+
current,
|
|
1434
|
+
change: (model) => {
|
|
1435
|
+
applyPatch(model);
|
|
1436
|
+
},
|
|
1437
|
+
});
|
|
1438
|
+
if (result.status !== 'transitioned') {
|
|
1439
|
+
throw new AuthError('concurrent_change', 'The settings changed concurrently and were not updated.');
|
|
1440
|
+
}
|
|
1441
|
+
const persisted = ControllerSettingsModel.exact.toPersisted(result.document);
|
|
1442
|
+
return { ...persisted, defaultModels: persisted.defaultModels.map(cloneModelChoice) };
|
|
1443
|
+
}
|
|
1444
|
+
async getSessionLayout(projectIdArg) {
|
|
1445
|
+
this.assertInitialized();
|
|
1446
|
+
const controllerId = this.requireControllerId();
|
|
1447
|
+
const stored = await ControllerSessionGroupsModel.exact.findStoredOne({
|
|
1448
|
+
id: `${controllerId}:groups:${projectIdArg}`,
|
|
1449
|
+
});
|
|
1450
|
+
if (!stored)
|
|
1451
|
+
return { groups: [], ungroupedSessionIds: [], revision: 0 };
|
|
1452
|
+
const persisted = ControllerSessionGroupsModel.exact.toPersisted(stored);
|
|
1453
|
+
return {
|
|
1454
|
+
groups: persisted.groups.map((group) => ({
|
|
1455
|
+
...group,
|
|
1456
|
+
sessionIds: group.sessionIds.filter(isSessionId).map((sessionId) => ({ ...sessionId })),
|
|
1457
|
+
})),
|
|
1458
|
+
ungroupedSessionIds: (persisted.ungroupedSessionIds ?? []).filter(isSessionId).map((sessionId) => ({ ...sessionId })),
|
|
1459
|
+
revision: persisted.revision ?? 0,
|
|
1460
|
+
};
|
|
1461
|
+
}
|
|
1462
|
+
async updateSessionLayout(projectIdArg, groupsArg, ungroupedSessionIdsArg, expectedRevisionArg) {
|
|
1463
|
+
this.assertInitialized();
|
|
1464
|
+
const controllerId = this.requireControllerId();
|
|
1465
|
+
const documentId = `${controllerId}:groups:${projectIdArg}`;
|
|
1466
|
+
const stored = await ControllerSessionGroupsModel.exact.findStoredOne({ id: documentId });
|
|
1467
|
+
const groups = groupsArg.map((group) => ({
|
|
1468
|
+
id: group.id,
|
|
1469
|
+
name: group.name,
|
|
1470
|
+
sessionIds: group.sessionIds.map((sessionId) => ({ ...sessionId })),
|
|
1471
|
+
}));
|
|
1472
|
+
const groupedSessionIds = new Set(groups.flatMap((group) => group.sessionIds.map(controllerRuntimeIdKey)));
|
|
1473
|
+
const storedPersisted = stored
|
|
1474
|
+
? ControllerSessionGroupsModel.exact.toPersisted(stored)
|
|
1475
|
+
: undefined;
|
|
1476
|
+
const storedRevision = storedPersisted?.revision ?? 0;
|
|
1477
|
+
if (expectedRevisionArg !== undefined && expectedRevisionArg !== storedRevision) {
|
|
1478
|
+
throw new AuthError('concurrent_change', 'The session layout changed in another client.');
|
|
1479
|
+
}
|
|
1480
|
+
const persistedUngroupedIds = storedPersisted?.ungroupedSessionIds ?? [];
|
|
1481
|
+
const ungroupedSessionIds = ungroupedSessionIdsArg === undefined
|
|
1482
|
+
? persistedUngroupedIds.filter((sessionId) => !groupedSessionIds.has(controllerRuntimeIdKey(sessionId)))
|
|
1483
|
+
: ungroupedSessionIdsArg.map((sessionId) => ({ ...sessionId }));
|
|
1484
|
+
const candidate = {
|
|
1485
|
+
id: documentId,
|
|
1486
|
+
controllerId,
|
|
1487
|
+
projectId: projectIdArg,
|
|
1488
|
+
groups,
|
|
1489
|
+
ungroupedSessionIds,
|
|
1490
|
+
revision: storedRevision + 1,
|
|
1491
|
+
};
|
|
1492
|
+
if (!stored) {
|
|
1493
|
+
const insertResult = await ControllerSessionGroupsModel.exact.insert(candidate);
|
|
1494
|
+
if (insertResult.status !== 'conflict') {
|
|
1495
|
+
return { groups, ungroupedSessionIds: ungroupedSessionIds.filter(isSessionId), revision: candidate.revision };
|
|
1496
|
+
}
|
|
1497
|
+
if (expectedRevisionArg !== undefined) {
|
|
1498
|
+
throw new AuthError('concurrent_change', 'The session layout changed in another client.');
|
|
1499
|
+
}
|
|
1500
|
+
// A legacy client did not supply a revision, so preserve its prior
|
|
1501
|
+
// last-write behavior against the concurrently created document.
|
|
1502
|
+
}
|
|
1503
|
+
const current = stored ?? await ControllerSessionGroupsModel.exact.findStoredOne({ id: documentId });
|
|
1504
|
+
if (!current) {
|
|
1505
|
+
throw new AuthError('ambiguous_write', 'The session groups document has an ambiguous state.');
|
|
1506
|
+
}
|
|
1507
|
+
const currentPersisted = ControllerSessionGroupsModel.exact.toPersisted(current);
|
|
1508
|
+
const currentRevision = currentPersisted.revision ?? 0;
|
|
1509
|
+
if (expectedRevisionArg !== undefined && expectedRevisionArg !== currentRevision) {
|
|
1510
|
+
throw new AuthError('concurrent_change', 'The session layout changed in another client.');
|
|
1511
|
+
}
|
|
1512
|
+
const transitionUngroupedSessionIds = ungroupedSessionIdsArg === undefined
|
|
1513
|
+
? (currentPersisted.ungroupedSessionIds ?? []).filter((sessionId) => !groupedSessionIds.has(controllerRuntimeIdKey(sessionId)))
|
|
1514
|
+
: candidate.ungroupedSessionIds;
|
|
1515
|
+
const result = await ControllerSessionGroupsModel.exact.transition({
|
|
1516
|
+
current,
|
|
1517
|
+
change: (model) => {
|
|
1518
|
+
model.groups = candidate.groups;
|
|
1519
|
+
model.ungroupedSessionIds = transitionUngroupedSessionIds;
|
|
1520
|
+
model.revision = currentRevision + 1;
|
|
1521
|
+
},
|
|
1522
|
+
});
|
|
1523
|
+
if (result.status !== 'transitioned') {
|
|
1524
|
+
throw new AuthError('concurrent_change', 'The session groups changed concurrently and were not updated.');
|
|
1525
|
+
}
|
|
1526
|
+
const persisted = ControllerSessionGroupsModel.exact.toPersisted(result.document);
|
|
1527
|
+
return {
|
|
1528
|
+
groups: persisted.groups.map((group) => ({
|
|
1529
|
+
...group,
|
|
1530
|
+
sessionIds: group.sessionIds.filter(isSessionId),
|
|
1531
|
+
})),
|
|
1532
|
+
ungroupedSessionIds: (persisted.ungroupedSessionIds ?? []).filter(isSessionId),
|
|
1533
|
+
revision: persisted.revision ?? 0,
|
|
1534
|
+
};
|
|
1535
|
+
}
|
|
1536
|
+
async removeSessionFromLayout(projectIdArg, sessionIdArg) {
|
|
1537
|
+
const sessionKey = controllerRuntimeIdKey(sessionIdArg);
|
|
1538
|
+
return this.filterSessionLayout(projectIdArg, (sessionId) => controllerRuntimeIdKey(sessionId) !== sessionKey);
|
|
1539
|
+
}
|
|
1540
|
+
async pruneTerminalLayoutEntries(projectIdArg, liveTerminalIdsArg) {
|
|
1541
|
+
const liveTerminalKeys = new Set(liveTerminalIdsArg.map(controllerRuntimeIdKey));
|
|
1542
|
+
return this.filterSessionLayout(projectIdArg, (layoutItemId) => (layoutItemId.harnessId !== 'controller'
|
|
1543
|
+
|| liveTerminalKeys.has(controllerRuntimeIdKey(layoutItemId))));
|
|
1544
|
+
}
|
|
1545
|
+
async pruneArchivedSessionLayoutEntries(projectIdArg, archivedSessionIdsArg) {
|
|
1546
|
+
const archivedSessionKeys = new Set(archivedSessionIdsArg.map(controllerRuntimeIdKey));
|
|
1547
|
+
return this.filterSessionLayout(projectIdArg, (sessionId) => !archivedSessionKeys.has(controllerRuntimeIdKey(sessionId)));
|
|
1548
|
+
}
|
|
1549
|
+
async filterSessionLayout(projectIdArg, keepSessionArg) {
|
|
1550
|
+
this.assertInitialized();
|
|
1551
|
+
const documentId = `${this.requireControllerId()}:groups:${projectIdArg}`;
|
|
1552
|
+
for (let attempt = 0; attempt < 3; attempt += 1) {
|
|
1553
|
+
const current = await ControllerSessionGroupsModel.exact.findStoredOne({ id: documentId });
|
|
1554
|
+
if (!current)
|
|
1555
|
+
return false;
|
|
1556
|
+
const persisted = ControllerSessionGroupsModel.exact.toPersisted(current);
|
|
1557
|
+
const groups = persisted.groups.map((group) => ({
|
|
1558
|
+
...group,
|
|
1559
|
+
sessionIds: group.sessionIds.filter(keepSessionArg),
|
|
1560
|
+
}));
|
|
1561
|
+
const ungroupedSessionIds = (persisted.ungroupedSessionIds ?? []).filter(keepSessionArg);
|
|
1562
|
+
const changed = groups.some((group, index) => (group.sessionIds.length !== persisted.groups[index].sessionIds.length)) || ungroupedSessionIds.length !== (persisted.ungroupedSessionIds ?? []).length;
|
|
1563
|
+
if (!changed)
|
|
1564
|
+
return false;
|
|
1565
|
+
const result = await ControllerSessionGroupsModel.exact.transition({
|
|
1566
|
+
current,
|
|
1567
|
+
change: (model) => {
|
|
1568
|
+
model.groups = groups;
|
|
1569
|
+
model.ungroupedSessionIds = ungroupedSessionIds;
|
|
1570
|
+
model.revision = (persisted.revision ?? 0) + 1;
|
|
1571
|
+
},
|
|
1572
|
+
});
|
|
1573
|
+
if (result.status === 'transitioned')
|
|
1574
|
+
return true;
|
|
1575
|
+
}
|
|
1576
|
+
throw new AuthError('concurrent_change', 'The session layout changed concurrently and was not pruned.');
|
|
1577
|
+
}
|
|
1578
|
+
sessionStateIdentity(projectIdArg, sessionIdArg) {
|
|
1579
|
+
const controllerId = this.requireControllerId();
|
|
1580
|
+
if (typeof projectIdArg !== 'string'
|
|
1581
|
+
|| projectIdArg.length === 0
|
|
1582
|
+
|| projectIdArg.length > 64
|
|
1583
|
+
|| typeof sessionIdArg?.nativeId !== 'string'
|
|
1584
|
+
|| sessionIdArg.nativeId.length === 0
|
|
1585
|
+
|| Buffer.byteLength(sessionIdArg.nativeId, 'utf8') > 512
|
|
1586
|
+
|| (sessionIdArg.harnessId !== 'opencode' && sessionIdArg.harnessId !== 'flex')) {
|
|
1587
|
+
throw new AuthError('invalid_project', 'The session-state scope is malformed.');
|
|
1588
|
+
}
|
|
1589
|
+
const sessionId = { ...sessionIdArg };
|
|
1590
|
+
return {
|
|
1591
|
+
controllerId,
|
|
1592
|
+
projectId: projectIdArg,
|
|
1593
|
+
sessionId,
|
|
1594
|
+
id: controllerSessionStateId(controllerId, projectIdArg, sessionId),
|
|
1595
|
+
};
|
|
1596
|
+
}
|
|
1597
|
+
createEmptySessionStateDocument(projectIdArg, sessionIdArg, updateIdArg) {
|
|
1598
|
+
const identity = this.sessionStateIdentity(projectIdArg, sessionIdArg);
|
|
1599
|
+
return {
|
|
1600
|
+
...identity,
|
|
1601
|
+
scratchpad: { text: '', revision: 0 },
|
|
1602
|
+
intelligenceExchanges: [],
|
|
1603
|
+
updateId: updateIdArg,
|
|
1604
|
+
};
|
|
1605
|
+
}
|
|
1606
|
+
async findStoredSessionState(projectIdArg, sessionIdArg) {
|
|
1607
|
+
this.assertInitialized();
|
|
1608
|
+
const { id } = this.sessionStateIdentity(projectIdArg, sessionIdArg);
|
|
1609
|
+
return (await ControllerSessionStateModel.exact.findStoredOne({ id })) ?? undefined;
|
|
1610
|
+
}
|
|
1611
|
+
async insertSessionState(candidateArg) {
|
|
1612
|
+
try {
|
|
1613
|
+
const result = await ControllerSessionStateModel.exact.insert(candidateArg);
|
|
1614
|
+
if (result.status === 'conflict') {
|
|
1615
|
+
throw new AuthError('concurrent_change', 'The session state was created concurrently.');
|
|
1616
|
+
}
|
|
1617
|
+
return ControllerSessionStateModel.exact.toPersisted(result.document);
|
|
1618
|
+
}
|
|
1619
|
+
catch (errorArg) {
|
|
1620
|
+
if (!isAmbiguousWrite(errorArg))
|
|
1621
|
+
throw errorArg;
|
|
1622
|
+
const reconciled = await ControllerSessionStateModel.exact.findStoredOne({ id: candidateArg.id });
|
|
1623
|
+
if (reconciled) {
|
|
1624
|
+
const document = ControllerSessionStateModel.exact.toPersisted(reconciled);
|
|
1625
|
+
if (document.updateId === candidateArg.updateId)
|
|
1626
|
+
return document;
|
|
1627
|
+
}
|
|
1628
|
+
throw new AuthError('ambiguous_write', 'The session-state insertion has an ambiguous outcome.', { cause: errorArg });
|
|
1629
|
+
}
|
|
1630
|
+
}
|
|
1631
|
+
async transitionSessionState(currentArg, changeArg) {
|
|
1632
|
+
const currentDocument = ControllerSessionStateModel.exact.toPersisted(currentArg);
|
|
1633
|
+
const updateId = randomAuthorityValue();
|
|
1634
|
+
try {
|
|
1635
|
+
const result = await ControllerSessionStateModel.exact.transition({
|
|
1636
|
+
current: currentArg,
|
|
1637
|
+
change: (model) => {
|
|
1638
|
+
changeArg(model);
|
|
1639
|
+
model.updateId = updateId;
|
|
1640
|
+
},
|
|
1641
|
+
});
|
|
1642
|
+
if (result.status !== 'transitioned') {
|
|
1643
|
+
throw new AuthError('concurrent_change', 'The session state changed concurrently.');
|
|
1644
|
+
}
|
|
1645
|
+
return ControllerSessionStateModel.exact.toPersisted(result.document);
|
|
1646
|
+
}
|
|
1647
|
+
catch (errorArg) {
|
|
1648
|
+
if (!isAmbiguousWrite(errorArg))
|
|
1649
|
+
throw errorArg;
|
|
1650
|
+
const reconciled = await ControllerSessionStateModel.exact.findStoredOne({
|
|
1651
|
+
id: currentDocument.id,
|
|
1652
|
+
});
|
|
1653
|
+
if (reconciled) {
|
|
1654
|
+
const document = ControllerSessionStateModel.exact.toPersisted(reconciled);
|
|
1655
|
+
if (document.updateId === updateId)
|
|
1656
|
+
return document;
|
|
1657
|
+
}
|
|
1658
|
+
throw new AuthError('ambiguous_write', 'The session-state transition has an ambiguous outcome.', { cause: errorArg });
|
|
1659
|
+
}
|
|
1660
|
+
}
|
|
1661
|
+
async getSessionState(projectIdArg, sessionIdArg) {
|
|
1662
|
+
const identity = this.sessionStateIdentity(projectIdArg, sessionIdArg);
|
|
1663
|
+
const stored = await this.findStoredSessionState(projectIdArg, sessionIdArg);
|
|
1664
|
+
if (!stored) {
|
|
1665
|
+
return {
|
|
1666
|
+
scratchpad: { id: identity.id, text: '', revision: 0 },
|
|
1667
|
+
intelligenceExchanges: [],
|
|
1668
|
+
};
|
|
1669
|
+
}
|
|
1670
|
+
return toPublicSessionState(ControllerSessionStateModel.exact.toPersisted(stored));
|
|
1671
|
+
}
|
|
1672
|
+
loadFlexProjectManagement(projectIdArg, sessionIdArg, sessionGenerationArg) {
|
|
1673
|
+
return this.runSessionStateMutation(async () => {
|
|
1674
|
+
assertFlexSessionGeneration(sessionGenerationArg);
|
|
1675
|
+
const runtimeId = { harnessId: 'flex', nativeId: sessionIdArg };
|
|
1676
|
+
for (let attempt = 0; attempt < 3; attempt += 1) {
|
|
1677
|
+
const stored = await this.findStoredSessionState(projectIdArg, runtimeId);
|
|
1678
|
+
if (!stored) {
|
|
1679
|
+
const candidate = this.createEmptySessionStateDocument(projectIdArg, runtimeId, randomAuthorityValue());
|
|
1680
|
+
const snapshot = {
|
|
1681
|
+
schemaVersion: 1,
|
|
1682
|
+
revision: 0,
|
|
1683
|
+
...sessionGenerationArg,
|
|
1684
|
+
scratchpad: '',
|
|
1685
|
+
tasks: [],
|
|
1686
|
+
};
|
|
1687
|
+
plugins.flexharness.assertFlexProjectManagementSnapshot(snapshot);
|
|
1688
|
+
candidate.flexProjectManagement = snapshot;
|
|
1689
|
+
try {
|
|
1690
|
+
const inserted = await this.insertSessionState(candidate);
|
|
1691
|
+
return cloneProjectManagementRecord(inserted.flexProjectManagement);
|
|
1692
|
+
}
|
|
1693
|
+
catch (errorArg) {
|
|
1694
|
+
if (!(errorArg instanceof AuthError) || errorArg.code !== 'concurrent_change') {
|
|
1695
|
+
throw errorArg;
|
|
1696
|
+
}
|
|
1697
|
+
continue;
|
|
1698
|
+
}
|
|
1699
|
+
}
|
|
1700
|
+
const current = ControllerSessionStateModel.exact.toPersisted(stored);
|
|
1701
|
+
if (current.flexProjectManagement) {
|
|
1702
|
+
return cloneProjectManagementRecord(current.flexProjectManagement);
|
|
1703
|
+
}
|
|
1704
|
+
if (current.deletedAt)
|
|
1705
|
+
return undefined;
|
|
1706
|
+
const snapshot = {
|
|
1707
|
+
schemaVersion: 1,
|
|
1708
|
+
revision: 0,
|
|
1709
|
+
...sessionGenerationArg,
|
|
1710
|
+
scratchpad: current.scratchpad.text,
|
|
1711
|
+
tasks: [],
|
|
1712
|
+
};
|
|
1713
|
+
plugins.flexharness.assertFlexProjectManagementSnapshot(snapshot);
|
|
1714
|
+
try {
|
|
1715
|
+
const transitioned = await this.transitionSessionState(stored, (document) => {
|
|
1716
|
+
document.flexProjectManagement = snapshot;
|
|
1717
|
+
});
|
|
1718
|
+
return cloneProjectManagementRecord(transitioned.flexProjectManagement);
|
|
1719
|
+
}
|
|
1720
|
+
catch (errorArg) {
|
|
1721
|
+
if (!(errorArg instanceof AuthError) || errorArg.code !== 'concurrent_change') {
|
|
1722
|
+
throw errorArg;
|
|
1723
|
+
}
|
|
1724
|
+
}
|
|
1725
|
+
}
|
|
1726
|
+
throw new AuthError('concurrent_change', 'The Flex project-management state remained busy during initialization.');
|
|
1727
|
+
});
|
|
1728
|
+
}
|
|
1729
|
+
saveFlexProjectManagement(projectIdArg, sessionIdArg, snapshotArg, expectedRevisionArg, writeContextArg) {
|
|
1730
|
+
return this.runSessionStateMutation(async () => {
|
|
1731
|
+
plugins.flexharness.assertFlexProjectManagementSnapshot(snapshotArg);
|
|
1732
|
+
assertProjectManagementNextRevision(snapshotArg, expectedRevisionArg);
|
|
1733
|
+
assertProjectManagementWriteContext(writeContextArg);
|
|
1734
|
+
const snapshot = cloneProjectManagementRecord(snapshotArg);
|
|
1735
|
+
const runtimeId = { harnessId: 'flex', nativeId: sessionIdArg };
|
|
1736
|
+
const stored = await this.findStoredSessionState(projectIdArg, runtimeId);
|
|
1737
|
+
if (!stored) {
|
|
1738
|
+
if (expectedRevisionArg !== 0) {
|
|
1739
|
+
throw new plugins.flexharness.FlexHarnessStoreConflictError(projectManagementStoreKey(projectIdArg, sessionIdArg), expectedRevisionArg, 0);
|
|
1740
|
+
}
|
|
1741
|
+
const candidate = this.createEmptySessionStateDocument(projectIdArg, runtimeId, randomAuthorityValue());
|
|
1742
|
+
candidate.flexProjectManagement = snapshot;
|
|
1743
|
+
if (snapshot.scratchpad !== '') {
|
|
1744
|
+
candidate.scratchpad = {
|
|
1745
|
+
text: snapshot.scratchpad,
|
|
1746
|
+
revision: 1,
|
|
1747
|
+
updatedAt: new Date(),
|
|
1748
|
+
updatedBy: projectManagementUpdater(writeContextArg),
|
|
1749
|
+
};
|
|
1750
|
+
}
|
|
1751
|
+
try {
|
|
1752
|
+
await this.insertSessionState(candidate);
|
|
1753
|
+
return;
|
|
1754
|
+
}
|
|
1755
|
+
catch (errorArg) {
|
|
1756
|
+
if (errorArg instanceof AuthError && errorArg.code === 'concurrent_change') {
|
|
1757
|
+
throw new plugins.flexharness.FlexHarnessStoreConflictError(projectManagementStoreKey(projectIdArg, sessionIdArg), expectedRevisionArg, 0);
|
|
1758
|
+
}
|
|
1759
|
+
throw errorArg;
|
|
1760
|
+
}
|
|
1761
|
+
}
|
|
1762
|
+
const current = ControllerSessionStateModel.exact.toPersisted(stored);
|
|
1763
|
+
const currentProjectManagement = current.flexProjectManagement;
|
|
1764
|
+
const actualRevision = currentProjectManagement?.revision ?? 0;
|
|
1765
|
+
const sameGeneration = currentProjectManagement
|
|
1766
|
+
? sameProjectManagementGeneration(currentProjectManagement, snapshot)
|
|
1767
|
+
: false;
|
|
1768
|
+
const canInitialize = currentProjectManagement
|
|
1769
|
+
? canInitializeProjectManagementGeneration(currentProjectManagement, snapshot, expectedRevisionArg)
|
|
1770
|
+
: expectedRevisionArg === 0;
|
|
1771
|
+
const conflicts = currentProjectManagement
|
|
1772
|
+
? sameGeneration
|
|
1773
|
+
? Object.hasOwn(currentProjectManagement, 'deletedAt')
|
|
1774
|
+
|| actualRevision !== expectedRevisionArg
|
|
1775
|
+
: !canInitialize
|
|
1776
|
+
: !canInitialize || (!current.deletedAt && current.scratchpad.text !== snapshot.scratchpad);
|
|
1777
|
+
if (conflicts) {
|
|
1778
|
+
throw new plugins.flexharness.FlexHarnessStoreConflictError(projectManagementStoreKey(projectIdArg, sessionIdArg), expectedRevisionArg, actualRevision);
|
|
1779
|
+
}
|
|
1780
|
+
const reviving = current.deletedAt !== undefined;
|
|
1781
|
+
await this.transitionSessionState(stored, (document) => {
|
|
1782
|
+
if (reviving) {
|
|
1783
|
+
delete document.deletedAt;
|
|
1784
|
+
document.intelligenceExchanges = [];
|
|
1785
|
+
delete document.modelChoice;
|
|
1786
|
+
}
|
|
1787
|
+
if (reviving || document.scratchpad.text !== snapshot.scratchpad) {
|
|
1788
|
+
document.scratchpad = {
|
|
1789
|
+
text: snapshot.scratchpad,
|
|
1790
|
+
revision: document.scratchpad.revision + 1,
|
|
1791
|
+
updatedAt: new Date(),
|
|
1792
|
+
updatedBy: projectManagementUpdater(writeContextArg),
|
|
1793
|
+
};
|
|
1794
|
+
}
|
|
1795
|
+
document.flexProjectManagement = snapshot;
|
|
1796
|
+
});
|
|
1797
|
+
});
|
|
1798
|
+
}
|
|
1799
|
+
tombstoneFlexProjectManagement(projectIdArg, sessionIdArg, tombstoneArg, expectedRevisionArg) {
|
|
1800
|
+
return this.runSessionStateMutation(async () => {
|
|
1801
|
+
plugins.flexharness.assertFlexProjectManagementTombstone(tombstoneArg);
|
|
1802
|
+
assertProjectManagementNextRevision(tombstoneArg, expectedRevisionArg);
|
|
1803
|
+
const tombstone = cloneProjectManagementRecord(tombstoneArg);
|
|
1804
|
+
const runtimeId = { harnessId: 'flex', nativeId: sessionIdArg };
|
|
1805
|
+
const stored = await this.findStoredSessionState(projectIdArg, runtimeId);
|
|
1806
|
+
const deletedAt = new Date(tombstone.deletedAt);
|
|
1807
|
+
if (!stored) {
|
|
1808
|
+
if (expectedRevisionArg !== 0) {
|
|
1809
|
+
throw new plugins.flexharness.FlexHarnessStoreConflictError(projectManagementStoreKey(projectIdArg, sessionIdArg), expectedRevisionArg, 0);
|
|
1810
|
+
}
|
|
1811
|
+
const candidate = this.createEmptySessionStateDocument(projectIdArg, runtimeId, randomAuthorityValue());
|
|
1812
|
+
candidate.flexProjectManagement = tombstone;
|
|
1813
|
+
this.applySessionStateTombstone(candidate, deletedAt);
|
|
1814
|
+
try {
|
|
1815
|
+
await this.insertSessionState(candidate);
|
|
1816
|
+
return;
|
|
1817
|
+
}
|
|
1818
|
+
catch (errorArg) {
|
|
1819
|
+
if (errorArg instanceof AuthError && errorArg.code === 'concurrent_change') {
|
|
1820
|
+
throw new plugins.flexharness.FlexHarnessStoreConflictError(projectManagementStoreKey(projectIdArg, sessionIdArg), expectedRevisionArg, 0);
|
|
1821
|
+
}
|
|
1822
|
+
throw errorArg;
|
|
1823
|
+
}
|
|
1824
|
+
}
|
|
1825
|
+
const current = ControllerSessionStateModel.exact.toPersisted(stored);
|
|
1826
|
+
const currentProjectManagement = current.flexProjectManagement;
|
|
1827
|
+
const actualRevision = currentProjectManagement?.revision ?? 0;
|
|
1828
|
+
if (currentProjectManagement && sameProjectManagementGeneration(currentProjectManagement, tombstone)) {
|
|
1829
|
+
if (Object.hasOwn(currentProjectManagement, 'deletedAt'))
|
|
1830
|
+
return;
|
|
1831
|
+
if (actualRevision !== expectedRevisionArg) {
|
|
1832
|
+
throw new plugins.flexharness.FlexHarnessStoreConflictError(projectManagementStoreKey(projectIdArg, sessionIdArg), expectedRevisionArg, actualRevision);
|
|
1833
|
+
}
|
|
1834
|
+
}
|
|
1835
|
+
else if (currentProjectManagement
|
|
1836
|
+
? !canInitializeProjectManagementGeneration(currentProjectManagement, tombstone, expectedRevisionArg)
|
|
1837
|
+
: expectedRevisionArg !== 0) {
|
|
1838
|
+
throw new plugins.flexharness.FlexHarnessStoreConflictError(projectManagementStoreKey(projectIdArg, sessionIdArg), expectedRevisionArg, actualRevision);
|
|
1839
|
+
}
|
|
1840
|
+
await this.transitionSessionState(stored, (document) => {
|
|
1841
|
+
document.flexProjectManagement = tombstone;
|
|
1842
|
+
this.applySessionStateTombstone(document, deletedAt);
|
|
1843
|
+
});
|
|
1844
|
+
});
|
|
1845
|
+
}
|
|
1846
|
+
purgeFlexProjectManagementNamespace(projectIdArg) {
|
|
1847
|
+
return this.runSessionStateMutation(async () => {
|
|
1848
|
+
this.assertInitialized();
|
|
1849
|
+
const controllerId = this.requireControllerId();
|
|
1850
|
+
this.sessionStateIdentity(projectIdArg, { harnessId: 'flex', nativeId: 'validation' });
|
|
1851
|
+
let lastStoredId;
|
|
1852
|
+
for (let pageIndex = 0; pageIndex < maxSessionStateRetirementPages; pageIndex += 1) {
|
|
1853
|
+
const storedEntries = await ControllerSessionStateModel.exact.findStored({
|
|
1854
|
+
filter: {
|
|
1855
|
+
controllerId,
|
|
1856
|
+
projectId: projectIdArg,
|
|
1857
|
+
flexProjectManagement: { $exists: true },
|
|
1858
|
+
...(lastStoredId === undefined ? {} : { _id: { $gt: lastStoredId } }),
|
|
1859
|
+
},
|
|
1860
|
+
sort: { _id: 1 },
|
|
1861
|
+
limit: sessionStateRetirementPageLimit,
|
|
1862
|
+
});
|
|
1863
|
+
for (const stored of storedEntries) {
|
|
1864
|
+
await this.transitionSessionState(stored, (document) => {
|
|
1865
|
+
delete document.flexProjectManagement;
|
|
1866
|
+
});
|
|
1867
|
+
}
|
|
1868
|
+
const lastStored = storedEntries.at(-1);
|
|
1869
|
+
if (!lastStored || storedEntries.length < sessionStateRetirementPageLimit)
|
|
1870
|
+
return;
|
|
1871
|
+
lastStoredId = lastStored._id;
|
|
1872
|
+
}
|
|
1873
|
+
throw new Error('Flex project-management namespace purge exceeded its bounded scan.');
|
|
1874
|
+
});
|
|
1875
|
+
}
|
|
1876
|
+
async setSessionModelChoice(projectIdArg, sessionIdArg, modelChoiceArg) {
|
|
1877
|
+
if (modelChoiceArg.harnessId !== sessionIdArg.harnessId) {
|
|
1878
|
+
throw new Error('The session model choice belongs to a different harness.');
|
|
1879
|
+
}
|
|
1880
|
+
const modelChoice = cloneModelChoice(modelChoiceArg);
|
|
1881
|
+
const stored = await this.findStoredSessionState(projectIdArg, sessionIdArg);
|
|
1882
|
+
if (!stored) {
|
|
1883
|
+
const candidate = this.createEmptySessionStateDocument(projectIdArg, sessionIdArg, randomAuthorityValue());
|
|
1884
|
+
candidate.modelChoice = modelChoice;
|
|
1885
|
+
return toPublicSessionState(await this.insertSessionState(candidate));
|
|
1886
|
+
}
|
|
1887
|
+
const current = ControllerSessionStateModel.exact.toPersisted(stored);
|
|
1888
|
+
if (current.deletedAt) {
|
|
1889
|
+
throw new AuthError('concurrent_change', 'The deleted session state cannot be recreated.');
|
|
1890
|
+
}
|
|
1891
|
+
return toPublicSessionState(await this.transitionSessionState(stored, (document) => {
|
|
1892
|
+
document.modelChoice = modelChoice;
|
|
1893
|
+
}));
|
|
1894
|
+
}
|
|
1895
|
+
async clearStoredSessionModelChoiceForProviderConnection(storedArg, providerConnectionIdArg, signalArg) {
|
|
1896
|
+
let stored = storedArg;
|
|
1897
|
+
for (let attempt = 0; attempt < sessionModelChoiceClearTransitionMaxAttempts; attempt++) {
|
|
1898
|
+
signalArg?.throwIfAborted();
|
|
1899
|
+
const current = ControllerSessionStateModel.exact.toPersisted(stored);
|
|
1900
|
+
if (current.deletedAt
|
|
1901
|
+
|| current.modelChoice?.harnessId !== 'flex'
|
|
1902
|
+
|| current.modelChoice.providerConnectionId !== providerConnectionIdArg)
|
|
1903
|
+
return false;
|
|
1904
|
+
try {
|
|
1905
|
+
await this.transitionSessionState(stored, (document) => {
|
|
1906
|
+
if (document.modelChoice?.harnessId === 'flex'
|
|
1907
|
+
&& document.modelChoice.providerConnectionId === providerConnectionIdArg)
|
|
1908
|
+
delete document.modelChoice;
|
|
1909
|
+
});
|
|
1910
|
+
return true;
|
|
1911
|
+
}
|
|
1912
|
+
catch (errorArg) {
|
|
1913
|
+
if (!(errorArg instanceof AuthError)
|
|
1914
|
+
|| (errorArg.code !== 'concurrent_change' && errorArg.code !== 'ambiguous_write'))
|
|
1915
|
+
throw errorArg;
|
|
1916
|
+
const latest = await this.findStoredSessionState(current.projectId, current.sessionId);
|
|
1917
|
+
if (!latest)
|
|
1918
|
+
return false;
|
|
1919
|
+
stored = latest;
|
|
1920
|
+
}
|
|
1921
|
+
}
|
|
1922
|
+
throw new AuthError('concurrent_change', 'The session model choice remained busy during provider cleanup.');
|
|
1923
|
+
}
|
|
1924
|
+
async clearSessionModelChoicesForProviderConnection(providerConnectionIdArg, signalArg) {
|
|
1925
|
+
this.assertInitialized();
|
|
1926
|
+
const controllerId = this.requireControllerId();
|
|
1927
|
+
if (typeof providerConnectionIdArg !== 'string'
|
|
1928
|
+
|| providerConnectionIdArg.length === 0
|
|
1929
|
+
|| Buffer.byteLength(providerConnectionIdArg, 'utf8') > 512) {
|
|
1930
|
+
throw new Error('The provider connection identifier is malformed.');
|
|
1931
|
+
}
|
|
1932
|
+
let clearedCount = 0;
|
|
1933
|
+
let lastStoredId;
|
|
1934
|
+
while (true) {
|
|
1935
|
+
signalArg?.throwIfAborted();
|
|
1936
|
+
const storedEntries = await ControllerSessionStateModel.exact.findStored({
|
|
1937
|
+
filter: {
|
|
1938
|
+
controllerId,
|
|
1939
|
+
deletedAt: { $exists: false },
|
|
1940
|
+
modelChoice: { $exists: true },
|
|
1941
|
+
...(lastStoredId === undefined ? {} : { _id: { $gt: lastStoredId } }),
|
|
1942
|
+
},
|
|
1943
|
+
sort: { _id: 1 },
|
|
1944
|
+
limit: sessionStateRetirementPageLimit,
|
|
1945
|
+
});
|
|
1946
|
+
for (let index = 0; index < storedEntries.length; index += 8) {
|
|
1947
|
+
signalArg?.throwIfAborted();
|
|
1948
|
+
const page = storedEntries.slice(index, index + 8);
|
|
1949
|
+
await Promise.all(page.map(async (storedEntry) => {
|
|
1950
|
+
if (await this.clearStoredSessionModelChoiceForProviderConnection(storedEntry, providerConnectionIdArg, signalArg))
|
|
1951
|
+
clearedCount += 1;
|
|
1952
|
+
}));
|
|
1953
|
+
}
|
|
1954
|
+
const lastStored = storedEntries.at(-1);
|
|
1955
|
+
if (!lastStored || storedEntries.length < sessionStateRetirementPageLimit)
|
|
1956
|
+
return clearedCount;
|
|
1957
|
+
lastStoredId = lastStored._id;
|
|
1958
|
+
}
|
|
1959
|
+
}
|
|
1960
|
+
saveSessionScratchpad(projectIdArg, sessionIdArg, textArg, expectedRevisionArg) {
|
|
1961
|
+
return this.runSessionStateMutation(() => this.saveSessionScratchpadUnqueued(projectIdArg, sessionIdArg, textArg, expectedRevisionArg));
|
|
1962
|
+
}
|
|
1963
|
+
async saveSessionScratchpadUnqueued(projectIdArg, sessionIdArg, textArg, expectedRevisionArg) {
|
|
1964
|
+
const stored = await this.findStoredSessionState(projectIdArg, sessionIdArg);
|
|
1965
|
+
const now = new Date();
|
|
1966
|
+
if (!stored) {
|
|
1967
|
+
if (expectedRevisionArg !== 0) {
|
|
1968
|
+
throw new AuthError('concurrent_change', 'The scratchpad revision is stale.');
|
|
1969
|
+
}
|
|
1970
|
+
const candidate = this.createEmptySessionStateDocument(projectIdArg, sessionIdArg, randomAuthorityValue());
|
|
1971
|
+
candidate.scratchpad = {
|
|
1972
|
+
text: textArg,
|
|
1973
|
+
revision: 1,
|
|
1974
|
+
updatedAt: now,
|
|
1975
|
+
updatedBy: 'user',
|
|
1976
|
+
};
|
|
1977
|
+
return toPublicSessionState(await this.insertSessionState(candidate));
|
|
1978
|
+
}
|
|
1979
|
+
const current = ControllerSessionStateModel.exact.toPersisted(stored);
|
|
1980
|
+
if (current.deletedAt) {
|
|
1981
|
+
throw new AuthError('concurrent_change', 'The deleted session state cannot be recreated.');
|
|
1982
|
+
}
|
|
1983
|
+
if (current.scratchpad.revision !== expectedRevisionArg) {
|
|
1984
|
+
throw new AuthError('concurrent_change', 'The scratchpad revision is stale.');
|
|
1985
|
+
}
|
|
1986
|
+
const next = await this.transitionSessionState(stored, (document) => {
|
|
1987
|
+
document.scratchpad = {
|
|
1988
|
+
text: textArg,
|
|
1989
|
+
revision: expectedRevisionArg + 1,
|
|
1990
|
+
updatedAt: now,
|
|
1991
|
+
updatedBy: 'user',
|
|
1992
|
+
};
|
|
1993
|
+
this.applyFlexProjectManagementScratchpad(document, textArg);
|
|
1994
|
+
});
|
|
1995
|
+
return toPublicSessionState(next);
|
|
1996
|
+
}
|
|
1997
|
+
admitSessionIntelligence(projectIdArg, sessionIdArg, questionArg) {
|
|
1998
|
+
return this.runSessionStateMutation(() => this.admitSessionIntelligenceUnqueued(projectIdArg, sessionIdArg, questionArg));
|
|
1999
|
+
}
|
|
2000
|
+
async admitSessionIntelligenceUnqueued(projectIdArg, sessionIdArg, questionArg) {
|
|
2001
|
+
const exchangeId = plugins.crypto.randomBytes(16).toString('base64url');
|
|
2002
|
+
const createdAt = new Date();
|
|
2003
|
+
let stored = await this.findStoredSessionState(projectIdArg, sessionIdArg);
|
|
2004
|
+
if (!stored) {
|
|
2005
|
+
const candidate = this.createEmptySessionStateDocument(projectIdArg, sessionIdArg, randomAuthorityValue());
|
|
2006
|
+
candidate.intelligenceExchanges = [{
|
|
2007
|
+
id: exchangeId,
|
|
2008
|
+
question: questionArg,
|
|
2009
|
+
status: 'running',
|
|
2010
|
+
scratchpadRevisionAtAdmission: 0,
|
|
2011
|
+
createdAt,
|
|
2012
|
+
}];
|
|
2013
|
+
const inserted = await this.insertSessionState(candidate);
|
|
2014
|
+
return {
|
|
2015
|
+
exchange: toPublicIntelligenceExchange(inserted.intelligenceExchanges[0]),
|
|
2016
|
+
scratchpadRevision: 0,
|
|
2017
|
+
scratchpadText: '',
|
|
2018
|
+
};
|
|
2019
|
+
}
|
|
2020
|
+
const current = ControllerSessionStateModel.exact.toPersisted(stored);
|
|
2021
|
+
if (current.deletedAt) {
|
|
2022
|
+
throw new AuthError('concurrent_change', 'The deleted session state cannot be recreated.');
|
|
2023
|
+
}
|
|
2024
|
+
if (current.intelligenceExchanges.some((exchange) => exchange.status === 'running' || exchange.temporarySessionId !== undefined)) {
|
|
2025
|
+
throw new AuthError('concurrent_change', 'Session Intelligence is already running or its cleanup is still pending.');
|
|
2026
|
+
}
|
|
2027
|
+
const scratchpadRevision = current.scratchpad.revision;
|
|
2028
|
+
const next = await this.transitionSessionState(stored, (document) => {
|
|
2029
|
+
document.intelligenceExchanges = trimSessionStateExchanges([
|
|
2030
|
+
...document.intelligenceExchanges,
|
|
2031
|
+
{
|
|
2032
|
+
id: exchangeId,
|
|
2033
|
+
question: questionArg,
|
|
2034
|
+
status: 'running',
|
|
2035
|
+
scratchpadRevisionAtAdmission: scratchpadRevision,
|
|
2036
|
+
createdAt,
|
|
2037
|
+
},
|
|
2038
|
+
], exchangeId);
|
|
2039
|
+
});
|
|
2040
|
+
const exchange = next.intelligenceExchanges.find((entry) => entry.id === exchangeId);
|
|
2041
|
+
return {
|
|
2042
|
+
exchange: toPublicIntelligenceExchange(exchange),
|
|
2043
|
+
scratchpadRevision,
|
|
2044
|
+
scratchpadText: current.scratchpad.text,
|
|
2045
|
+
};
|
|
2046
|
+
}
|
|
2047
|
+
attachSessionIntelligenceTemporarySession(projectIdArg, sessionIdArg, exchangeIdArg, temporarySessionIdArg) {
|
|
2048
|
+
return this.runSessionStateMutation(() => this.attachSessionIntelligenceTemporarySessionUnqueued(projectIdArg, sessionIdArg, exchangeIdArg, temporarySessionIdArg));
|
|
2049
|
+
}
|
|
2050
|
+
async attachSessionIntelligenceTemporarySessionUnqueued(projectIdArg, sessionIdArg, exchangeIdArg, temporarySessionIdArg) {
|
|
2051
|
+
const stored = await this.findStoredSessionState(projectIdArg, sessionIdArg);
|
|
2052
|
+
if (!stored)
|
|
2053
|
+
throw new AuthError('concurrent_change', 'The intelligence admission is missing.');
|
|
2054
|
+
const current = ControllerSessionStateModel.exact.toPersisted(stored);
|
|
2055
|
+
const exchange = current.intelligenceExchanges.find((entry) => entry.id === exchangeIdArg);
|
|
2056
|
+
if (current.deletedAt || exchange?.status !== 'running') {
|
|
2057
|
+
throw new AuthError('concurrent_change', 'The intelligence admission is no longer active.');
|
|
2058
|
+
}
|
|
2059
|
+
await this.transitionSessionState(stored, (document) => {
|
|
2060
|
+
const target = document.intelligenceExchanges.find((entry) => entry.id === exchangeIdArg);
|
|
2061
|
+
target.temporarySessionId = temporarySessionIdArg;
|
|
2062
|
+
});
|
|
2063
|
+
}
|
|
2064
|
+
completeSessionIntelligence(projectIdArg, sessionIdArg, exchangeIdArg, answerArg, scratchpadTextArg, modelArg) {
|
|
2065
|
+
return this.runSessionStateMutation(() => this.completeSessionIntelligenceUnqueued(projectIdArg, sessionIdArg, exchangeIdArg, answerArg, scratchpadTextArg, modelArg));
|
|
2066
|
+
}
|
|
2067
|
+
async completeSessionIntelligenceUnqueued(projectIdArg, sessionIdArg, exchangeIdArg, answerArg, scratchpadTextArg, modelArg) {
|
|
2068
|
+
const stored = await this.findStoredSessionState(projectIdArg, sessionIdArg);
|
|
2069
|
+
if (!stored)
|
|
2070
|
+
return undefined;
|
|
2071
|
+
const current = ControllerSessionStateModel.exact.toPersisted(stored);
|
|
2072
|
+
const exchange = current.intelligenceExchanges.find((entry) => entry.id === exchangeIdArg);
|
|
2073
|
+
if (current.deletedAt || exchange?.status !== 'running')
|
|
2074
|
+
return undefined;
|
|
2075
|
+
const scratchpadConflict = current.scratchpad.revision !== exchange.scratchpadRevisionAtAdmission;
|
|
2076
|
+
const completedAt = new Date();
|
|
2077
|
+
const next = await this.transitionSessionState(stored, (document) => {
|
|
2078
|
+
const target = document.intelligenceExchanges.find((entry) => entry.id === exchangeIdArg);
|
|
2079
|
+
document.intelligenceExchanges = trimSessionStateExchanges(document.intelligenceExchanges.map((entry) => entry.id === exchangeIdArg
|
|
2080
|
+
? {
|
|
2081
|
+
id: target.id,
|
|
2082
|
+
question: target.question,
|
|
2083
|
+
status: 'completed',
|
|
2084
|
+
answer: answerArg,
|
|
2085
|
+
model: modelArg,
|
|
2086
|
+
...(scratchpadConflict ? { scratchpadConflict: true } : {}),
|
|
2087
|
+
...(target.temporarySessionId === undefined
|
|
2088
|
+
? {}
|
|
2089
|
+
: { temporarySessionId: target.temporarySessionId }),
|
|
2090
|
+
createdAt: target.createdAt,
|
|
2091
|
+
completedAt,
|
|
2092
|
+
}
|
|
2093
|
+
: entry), exchangeIdArg);
|
|
2094
|
+
if (!scratchpadConflict && document.scratchpad.text !== scratchpadTextArg) {
|
|
2095
|
+
document.scratchpad = {
|
|
2096
|
+
text: scratchpadTextArg,
|
|
2097
|
+
revision: document.scratchpad.revision + 1,
|
|
2098
|
+
updatedAt: completedAt,
|
|
2099
|
+
updatedBy: 'intelligence',
|
|
2100
|
+
};
|
|
2101
|
+
this.applyFlexProjectManagementScratchpad(document, scratchpadTextArg);
|
|
2102
|
+
}
|
|
2103
|
+
});
|
|
2104
|
+
return toPublicSessionState(next);
|
|
2105
|
+
}
|
|
2106
|
+
failSessionIntelligence(projectIdArg, sessionIdArg, exchangeIdArg, errorArg, modelArg) {
|
|
2107
|
+
return this.runSessionStateMutation(() => this.failSessionIntelligenceUnqueued(projectIdArg, sessionIdArg, exchangeIdArg, errorArg, modelArg));
|
|
2108
|
+
}
|
|
2109
|
+
async failSessionIntelligenceUnqueued(projectIdArg, sessionIdArg, exchangeIdArg, errorArg, modelArg) {
|
|
2110
|
+
const stored = await this.findStoredSessionState(projectIdArg, sessionIdArg);
|
|
2111
|
+
if (!stored)
|
|
2112
|
+
return undefined;
|
|
2113
|
+
const current = ControllerSessionStateModel.exact.toPersisted(stored);
|
|
2114
|
+
const exchange = current.intelligenceExchanges.find((entry) => entry.id === exchangeIdArg);
|
|
2115
|
+
if (current.deletedAt || exchange?.status !== 'running')
|
|
2116
|
+
return undefined;
|
|
2117
|
+
const completedAt = new Date();
|
|
2118
|
+
const next = await this.transitionSessionState(stored, (document) => {
|
|
2119
|
+
const target = document.intelligenceExchanges.find((entry) => entry.id === exchangeIdArg);
|
|
2120
|
+
document.intelligenceExchanges = trimSessionStateExchanges(document.intelligenceExchanges.map((entry) => entry.id === exchangeIdArg
|
|
2121
|
+
? {
|
|
2122
|
+
id: target.id,
|
|
2123
|
+
question: target.question,
|
|
2124
|
+
status: 'error',
|
|
2125
|
+
error: errorArg,
|
|
2126
|
+
...(modelArg === undefined ? {} : { model: modelArg }),
|
|
2127
|
+
...(target.temporarySessionId === undefined
|
|
2128
|
+
? {}
|
|
2129
|
+
: { temporarySessionId: target.temporarySessionId }),
|
|
2130
|
+
createdAt: target.createdAt,
|
|
2131
|
+
completedAt,
|
|
2132
|
+
}
|
|
2133
|
+
: entry), exchangeIdArg);
|
|
2134
|
+
});
|
|
2135
|
+
return toPublicSessionState(next);
|
|
2136
|
+
}
|
|
2137
|
+
recoverInterruptedSessionIntelligence() {
|
|
2138
|
+
return this.runSessionStateMutation(() => this.recoverInterruptedSessionIntelligenceUnqueued());
|
|
2139
|
+
}
|
|
2140
|
+
async recoverInterruptedSessionIntelligenceUnqueued() {
|
|
2141
|
+
this.assertInitialized();
|
|
2142
|
+
const controllerId = this.requireControllerId();
|
|
2143
|
+
const storedEntries = await ControllerSessionStateModel.exact.findStored({
|
|
2144
|
+
filter: {
|
|
2145
|
+
controllerId,
|
|
2146
|
+
deletedAt: { $exists: false },
|
|
2147
|
+
intelligenceExchanges: { $elemMatch: { status: 'running' } },
|
|
2148
|
+
},
|
|
2149
|
+
limit: sessionStateRecoveryLimit,
|
|
2150
|
+
});
|
|
2151
|
+
const temporarySessionIds = [];
|
|
2152
|
+
let recoveredCount = 0;
|
|
2153
|
+
for (const stored of storedEntries) {
|
|
2154
|
+
const current = ControllerSessionStateModel.exact.toPersisted(stored);
|
|
2155
|
+
for (const exchange of current.intelligenceExchanges) {
|
|
2156
|
+
if (exchange.status === 'running' && exchange.temporarySessionId) {
|
|
2157
|
+
temporarySessionIds.push({
|
|
2158
|
+
projectId: current.projectId,
|
|
2159
|
+
sessionId: current.sessionId,
|
|
2160
|
+
exchangeId: exchange.id,
|
|
2161
|
+
nativeId: exchange.temporarySessionId,
|
|
2162
|
+
});
|
|
2163
|
+
}
|
|
2164
|
+
}
|
|
2165
|
+
const completedAt = new Date();
|
|
2166
|
+
await this.transitionSessionState(stored, (document) => {
|
|
2167
|
+
document.intelligenceExchanges = document.intelligenceExchanges.map((exchange) => exchange.status === 'running'
|
|
2168
|
+
? {
|
|
2169
|
+
id: exchange.id,
|
|
2170
|
+
question: exchange.question,
|
|
2171
|
+
status: 'error',
|
|
2172
|
+
error: 'Session Intelligence was interrupted by a controller restart.',
|
|
2173
|
+
...(exchange.temporarySessionId === undefined
|
|
2174
|
+
? {}
|
|
2175
|
+
: { temporarySessionId: exchange.temporarySessionId }),
|
|
2176
|
+
createdAt: exchange.createdAt,
|
|
2177
|
+
completedAt,
|
|
2178
|
+
}
|
|
2179
|
+
: exchange);
|
|
2180
|
+
});
|
|
2181
|
+
recoveredCount += 1;
|
|
2182
|
+
}
|
|
2183
|
+
return {
|
|
2184
|
+
recoveredCount,
|
|
2185
|
+
exhaustive: storedEntries.length < sessionStateRecoveryLimit,
|
|
2186
|
+
temporarySessionIds,
|
|
2187
|
+
};
|
|
2188
|
+
}
|
|
2189
|
+
async listProjectSessionIntelligenceCleanupObligations(projectIdArg) {
|
|
2190
|
+
this.assertInitialized();
|
|
2191
|
+
const controllerId = this.requireControllerId();
|
|
2192
|
+
if (typeof projectIdArg !== 'string'
|
|
2193
|
+
|| projectIdArg.length === 0
|
|
2194
|
+
|| projectIdArg.length > 64) {
|
|
2195
|
+
throw new AuthError('invalid_project', 'The project identifier is malformed.');
|
|
2196
|
+
}
|
|
2197
|
+
const storedEntries = await ControllerSessionStateModel.exact.findStored({
|
|
2198
|
+
filter: {
|
|
2199
|
+
controllerId,
|
|
2200
|
+
projectId: projectIdArg,
|
|
2201
|
+
deletedAt: { $exists: false },
|
|
2202
|
+
intelligenceExchanges: { $elemMatch: { temporarySessionId: { $exists: true } } },
|
|
2203
|
+
},
|
|
2204
|
+
limit: sessionStateRecoveryLimit,
|
|
2205
|
+
});
|
|
2206
|
+
return storedEntries.flatMap((stored) => {
|
|
2207
|
+
const current = ControllerSessionStateModel.exact.toPersisted(stored);
|
|
2208
|
+
return current.intelligenceExchanges.flatMap((exchange) => exchange.temporarySessionId
|
|
2209
|
+
? [{
|
|
2210
|
+
projectId: current.projectId,
|
|
2211
|
+
sessionId: current.sessionId,
|
|
2212
|
+
exchangeId: exchange.id,
|
|
2213
|
+
nativeId: exchange.temporarySessionId,
|
|
2214
|
+
}]
|
|
2215
|
+
: []);
|
|
2216
|
+
});
|
|
2217
|
+
}
|
|
2218
|
+
async getSessionIntelligenceCleanupObligations(projectIdArg, sessionIdArg) {
|
|
2219
|
+
const stored = await this.findStoredSessionState(projectIdArg, sessionIdArg);
|
|
2220
|
+
if (!stored)
|
|
2221
|
+
return [];
|
|
2222
|
+
const current = ControllerSessionStateModel.exact.toPersisted(stored);
|
|
2223
|
+
if (current.deletedAt)
|
|
2224
|
+
return [];
|
|
2225
|
+
return current.intelligenceExchanges.flatMap((exchange) => exchange.temporarySessionId
|
|
2226
|
+
? [{
|
|
2227
|
+
projectId: current.projectId,
|
|
2228
|
+
sessionId: current.sessionId,
|
|
2229
|
+
exchangeId: exchange.id,
|
|
2230
|
+
nativeId: exchange.temporarySessionId,
|
|
2231
|
+
}]
|
|
2232
|
+
: []);
|
|
2233
|
+
}
|
|
2234
|
+
async findProjectSessionIntelligenceTemporarySessionIds(projectIdArg, candidateIdsArg, signalArg) {
|
|
2235
|
+
this.assertInitialized();
|
|
2236
|
+
const controllerId = this.requireControllerId();
|
|
2237
|
+
if (typeof projectIdArg !== 'string'
|
|
2238
|
+
|| projectIdArg.length === 0
|
|
2239
|
+
|| projectIdArg.length > 64
|
|
2240
|
+
|| candidateIdsArg.length > 512
|
|
2241
|
+
|| candidateIdsArg.some((id) => (typeof id !== 'string'
|
|
2242
|
+
|| id.length === 0
|
|
2243
|
+
|| Buffer.byteLength(id, 'utf8') > 512))) {
|
|
2244
|
+
throw new AuthError('invalid_project', 'The temporary-session lookup is malformed.');
|
|
2245
|
+
}
|
|
2246
|
+
const candidateIds = [...new Set(candidateIdsArg)];
|
|
2247
|
+
if (candidateIds.length === 0)
|
|
2248
|
+
return new Set();
|
|
2249
|
+
const storedEntries = await ControllerSessionStateModel.exact.findStored({
|
|
2250
|
+
filter: {
|
|
2251
|
+
controllerId,
|
|
2252
|
+
projectId: projectIdArg,
|
|
2253
|
+
deletedAt: { $exists: false },
|
|
2254
|
+
intelligenceExchanges: {
|
|
2255
|
+
$elemMatch: { temporarySessionId: { $in: candidateIds } },
|
|
2256
|
+
},
|
|
2257
|
+
},
|
|
2258
|
+
limit: candidateIds.length,
|
|
2259
|
+
signal: signalArg,
|
|
2260
|
+
});
|
|
2261
|
+
const candidateSet = new Set(candidateIds);
|
|
2262
|
+
return new Set(storedEntries.flatMap((stored) => ControllerSessionStateModel.exact.toPersisted(stored).intelligenceExchanges.flatMap((exchange) => exchange.temporarySessionId
|
|
2263
|
+
&& candidateSet.has(exchange.temporarySessionId)
|
|
2264
|
+
? [exchange.temporarySessionId]
|
|
2265
|
+
: [])));
|
|
2266
|
+
}
|
|
2267
|
+
async isSessionStateTombstoned(projectIdArg, sessionIdArg) {
|
|
2268
|
+
const stored = await this.findStoredSessionState(projectIdArg, sessionIdArg);
|
|
2269
|
+
if (!stored)
|
|
2270
|
+
return false;
|
|
2271
|
+
return ControllerSessionStateModel.exact.toPersisted(stored).deletedAt !== undefined;
|
|
2272
|
+
}
|
|
2273
|
+
async retireProjectSessionStates(projectIdArg, cleanupTemporarySessionArg, signalArg) {
|
|
2274
|
+
this.assertInitialized();
|
|
2275
|
+
const controllerId = this.requireControllerId();
|
|
2276
|
+
if (typeof projectIdArg !== 'string'
|
|
2277
|
+
|| projectIdArg.length === 0
|
|
2278
|
+
|| projectIdArg.length > 64) {
|
|
2279
|
+
throw new AuthError('invalid_project', 'The project identifier is malformed.');
|
|
2280
|
+
}
|
|
2281
|
+
const temporarySessionIds = new Set();
|
|
2282
|
+
let retiredCount = 0;
|
|
2283
|
+
let lastStoredId;
|
|
2284
|
+
for (let pageIndex = 0; pageIndex < maxSessionStateRetirementPages; pageIndex += 1) {
|
|
2285
|
+
signalArg?.throwIfAborted();
|
|
2286
|
+
const storedEntries = await ControllerSessionStateModel.exact.findStored({
|
|
2287
|
+
filter: {
|
|
2288
|
+
controllerId,
|
|
2289
|
+
projectId: projectIdArg,
|
|
2290
|
+
deletedAt: { $exists: false },
|
|
2291
|
+
...(lastStoredId === undefined ? {} : { _id: { $gt: lastStoredId } }),
|
|
2292
|
+
},
|
|
2293
|
+
sort: { _id: 1 },
|
|
2294
|
+
limit: sessionStateRetirementPageLimit,
|
|
2295
|
+
});
|
|
2296
|
+
signalArg?.throwIfAborted();
|
|
2297
|
+
for (const stored of storedEntries) {
|
|
2298
|
+
const current = ControllerSessionStateModel.exact.toPersisted(stored);
|
|
2299
|
+
for (const exchange of current.intelligenceExchanges) {
|
|
2300
|
+
if (!exchange.temporarySessionId || temporarySessionIds.has(exchange.temporarySessionId)) {
|
|
2301
|
+
continue;
|
|
2302
|
+
}
|
|
2303
|
+
signalArg?.throwIfAborted();
|
|
2304
|
+
await cleanupTemporarySessionArg(exchange.temporarySessionId);
|
|
2305
|
+
temporarySessionIds.add(exchange.temporarySessionId);
|
|
2306
|
+
}
|
|
2307
|
+
signalArg?.throwIfAborted();
|
|
2308
|
+
const retired = await this.runSessionStateMutation(async () => {
|
|
2309
|
+
const latest = await this.findStoredSessionState(projectIdArg, current.sessionId);
|
|
2310
|
+
if (!latest || ControllerSessionStateModel.exact.toPersisted(latest).deletedAt)
|
|
2311
|
+
return false;
|
|
2312
|
+
await this.transitionSessionState(latest, (document) => {
|
|
2313
|
+
this.applySessionStateTombstone(document, new Date());
|
|
2314
|
+
});
|
|
2315
|
+
return true;
|
|
2316
|
+
});
|
|
2317
|
+
if (retired)
|
|
2318
|
+
retiredCount += 1;
|
|
2319
|
+
}
|
|
2320
|
+
const lastStored = storedEntries.at(-1);
|
|
2321
|
+
if (!lastStored || storedEntries.length < sessionStateRetirementPageLimit) {
|
|
2322
|
+
return { retiredCount, temporarySessionIds: [...temporarySessionIds] };
|
|
2323
|
+
}
|
|
2324
|
+
lastStoredId = lastStored._id;
|
|
2325
|
+
}
|
|
2326
|
+
throw new Error(`Project session-state retirement cleared ${retiredCount} state(s) before exceeding its bounded scan.`);
|
|
2327
|
+
}
|
|
2328
|
+
clearSessionIntelligenceTemporarySession(projectIdArg, sessionIdArg, exchangeIdArg, temporarySessionIdArg) {
|
|
2329
|
+
return this.runSessionStateMutation(() => this.clearSessionIntelligenceTemporarySessionUnqueued(projectIdArg, sessionIdArg, exchangeIdArg, temporarySessionIdArg));
|
|
2330
|
+
}
|
|
2331
|
+
async clearSessionIntelligenceTemporarySessionUnqueued(projectIdArg, sessionIdArg, exchangeIdArg, temporarySessionIdArg) {
|
|
2332
|
+
const stored = await this.findStoredSessionState(projectIdArg, sessionIdArg);
|
|
2333
|
+
if (!stored)
|
|
2334
|
+
return;
|
|
2335
|
+
const current = ControllerSessionStateModel.exact.toPersisted(stored);
|
|
2336
|
+
const exchange = current.intelligenceExchanges.find((entry) => entry.id === exchangeIdArg);
|
|
2337
|
+
if (current.deletedAt || exchange?.temporarySessionId !== temporarySessionIdArg)
|
|
2338
|
+
return;
|
|
2339
|
+
await this.transitionSessionState(stored, (document) => {
|
|
2340
|
+
const target = document.intelligenceExchanges.find((entry) => entry.id === exchangeIdArg);
|
|
2341
|
+
if (target?.temporarySessionId === temporarySessionIdArg) {
|
|
2342
|
+
delete target.temporarySessionId;
|
|
2343
|
+
}
|
|
2344
|
+
});
|
|
2345
|
+
}
|
|
2346
|
+
tombstoneSessionState(projectIdArg, sessionIdArg) {
|
|
2347
|
+
return this.runSessionStateMutation(() => this.tombstoneSessionStateUnqueued(projectIdArg, sessionIdArg));
|
|
2348
|
+
}
|
|
2349
|
+
async tombstoneSessionStateUnqueued(projectIdArg, sessionIdArg) {
|
|
2350
|
+
const stored = await this.findStoredSessionState(projectIdArg, sessionIdArg);
|
|
2351
|
+
const deletedAt = new Date();
|
|
2352
|
+
if (!stored) {
|
|
2353
|
+
const candidate = this.createEmptySessionStateDocument(projectIdArg, sessionIdArg, randomAuthorityValue());
|
|
2354
|
+
candidate.deletedAt = deletedAt;
|
|
2355
|
+
await this.insertSessionState(candidate);
|
|
2356
|
+
return;
|
|
2357
|
+
}
|
|
2358
|
+
const current = ControllerSessionStateModel.exact.toPersisted(stored);
|
|
2359
|
+
if (current.deletedAt)
|
|
2360
|
+
return;
|
|
2361
|
+
await this.transitionSessionState(stored, (document) => {
|
|
2362
|
+
this.applySessionStateTombstone(document, deletedAt);
|
|
2363
|
+
});
|
|
2364
|
+
}
|
|
2365
|
+
applyFlexProjectManagementScratchpad(documentArg, textArg) {
|
|
2366
|
+
const current = documentArg.flexProjectManagement;
|
|
2367
|
+
if (!current || 'deletedAt' in current || current.scratchpad === textArg)
|
|
2368
|
+
return;
|
|
2369
|
+
const snapshot = {
|
|
2370
|
+
...current,
|
|
2371
|
+
revision: current.revision + 1,
|
|
2372
|
+
scratchpad: textArg,
|
|
2373
|
+
};
|
|
2374
|
+
plugins.flexharness.assertFlexProjectManagementSnapshot(snapshot);
|
|
2375
|
+
documentArg.flexProjectManagement = snapshot;
|
|
2376
|
+
}
|
|
2377
|
+
applySessionStateTombstone(documentArg, deletedAtArg) {
|
|
2378
|
+
const projectManagement = documentArg.flexProjectManagement;
|
|
2379
|
+
if (projectManagement && !Object.hasOwn(projectManagement, 'deletedAt')) {
|
|
2380
|
+
const tombstone = {
|
|
2381
|
+
schemaVersion: 1,
|
|
2382
|
+
revision: projectManagement.revision + 1,
|
|
2383
|
+
sessionGenerationId: projectManagement.sessionGenerationId,
|
|
2384
|
+
sessionGenerationSequence: projectManagement.sessionGenerationSequence,
|
|
2385
|
+
deletedAt: deletedAtArg.toISOString(),
|
|
2386
|
+
};
|
|
2387
|
+
plugins.flexharness.assertFlexProjectManagementTombstone(tombstone);
|
|
2388
|
+
documentArg.flexProjectManagement = tombstone;
|
|
2389
|
+
}
|
|
2390
|
+
documentArg.scratchpad = {
|
|
2391
|
+
text: '',
|
|
2392
|
+
revision: documentArg.scratchpad.revision,
|
|
2393
|
+
...(documentArg.scratchpad.updatedAt === undefined
|
|
2394
|
+
? {}
|
|
2395
|
+
: { updatedAt: documentArg.scratchpad.updatedAt }),
|
|
2396
|
+
...(documentArg.scratchpad.updatedBy === undefined
|
|
2397
|
+
? {}
|
|
2398
|
+
: { updatedBy: documentArg.scratchpad.updatedBy }),
|
|
2399
|
+
};
|
|
2400
|
+
documentArg.intelligenceExchanges = [];
|
|
2401
|
+
delete documentArg.modelChoice;
|
|
2402
|
+
documentArg.deletedAt = deletedAtArg;
|
|
2403
|
+
}
|
|
2404
|
+
async createTempPassword(ttlMsArg) {
|
|
2405
|
+
this.assertInitialized();
|
|
2406
|
+
const controllerId = this.requireControllerId();
|
|
2407
|
+
if (!Number.isSafeInteger(ttlMsArg)
|
|
2408
|
+
|| ttlMsArg < tempPasswordTtlMinMs
|
|
2409
|
+
|| ttlMsArg > tempPasswordTtlMaxMs) {
|
|
2410
|
+
throw new AuthError('temp_password_invalid', 'A temporary password lifetime must be between one minute and 24 hours.');
|
|
2411
|
+
}
|
|
2412
|
+
const now = Date.now();
|
|
2413
|
+
const active = (await ControllerTempPasswordModel.exact.findStored({
|
|
2414
|
+
filter: { controllerId },
|
|
2415
|
+
limit: maxActiveTempPasswords * 4,
|
|
2416
|
+
}))
|
|
2417
|
+
.map((entry) => ControllerTempPasswordModel.exact.toPersisted(entry))
|
|
2418
|
+
.filter((entry) => entry.expiresAt.getTime() > now);
|
|
2419
|
+
if (active.length >= maxActiveTempPasswords) {
|
|
2420
|
+
throw new AuthError('temp_password_limit', `At most ${maxActiveTempPasswords} temporary passwords can be active; wait for one to expire.`);
|
|
2421
|
+
}
|
|
2422
|
+
const password = plugins.crypto.randomBytes(24).toString('base64url');
|
|
2423
|
+
const id = `${controllerId}:temppass:${randomAuthorityValue()}`;
|
|
2424
|
+
const insertResult = await ControllerTempPasswordModel.exact.insert({
|
|
2425
|
+
id,
|
|
2426
|
+
controllerId,
|
|
2427
|
+
secretHash: hashSetupCode(password),
|
|
2428
|
+
createdAt: new Date(now),
|
|
2429
|
+
expiresAt: new Date(now + ttlMsArg),
|
|
2430
|
+
});
|
|
2431
|
+
if (insertResult.status === 'conflict') {
|
|
2432
|
+
throw new AuthError('concurrent_change', 'The temporary password identifier conflicts.');
|
|
2433
|
+
}
|
|
2434
|
+
const persisted = ControllerTempPasswordModel.exact.toPersisted(insertResult.document);
|
|
2435
|
+
return { password, credentialId: `temp:${persisted.id}`, expiresAt: persisted.expiresAt };
|
|
2436
|
+
}
|
|
2437
|
+
async verifyTempPassword(passwordArg) {
|
|
2438
|
+
this.assertInitialized();
|
|
2439
|
+
const controllerId = this.requireControllerId();
|
|
2440
|
+
if (typeof passwordArg !== 'string' || !tempPasswordPattern.test(passwordArg)) {
|
|
2441
|
+
return undefined;
|
|
2442
|
+
}
|
|
2443
|
+
const candidateHash = hashSetupCode(passwordArg);
|
|
2444
|
+
const now = Date.now();
|
|
2445
|
+
const stored = await ControllerTempPasswordModel.exact.findStored({
|
|
2446
|
+
filter: { controllerId },
|
|
2447
|
+
limit: maxActiveTempPasswords * 4,
|
|
2448
|
+
});
|
|
2449
|
+
for (const entry of stored) {
|
|
2450
|
+
const persisted = ControllerTempPasswordModel.exact.toPersisted(entry);
|
|
2451
|
+
if (persisted.expiresAt.getTime() <= now)
|
|
2452
|
+
continue;
|
|
2453
|
+
if (hashesEqual(persisted.secretHash, candidateHash)) {
|
|
2454
|
+
return { credentialId: `temp:${persisted.id}`, expiresAt: persisted.expiresAt };
|
|
2455
|
+
}
|
|
2456
|
+
}
|
|
2457
|
+
return undefined;
|
|
2458
|
+
}
|
|
2459
|
+
assertRuntimeConfigMatches(storedArg, requestedArg) {
|
|
2460
|
+
if (!runtimeConfigsEqual(storedArg, requestedArg)) {
|
|
2461
|
+
throw new AuthError('config_mismatch', 'The stored controller runtime configuration is immutable and does not match.');
|
|
2462
|
+
}
|
|
2463
|
+
}
|
|
2464
|
+
auditEventsEqual(leftArg, rightArg) {
|
|
2465
|
+
return leftArg.id === rightArg.id
|
|
2466
|
+
&& leftArg.controllerId === rightArg.controllerId
|
|
2467
|
+
&& leftArg.timestamp.getTime() === rightArg.timestamp.getTime()
|
|
2468
|
+
&& leftArg.type === rightArg.type
|
|
2469
|
+
&& leftArg.outcome === rightArg.outcome
|
|
2470
|
+
&& leftArg.operationId === rightArg.operationId
|
|
2471
|
+
&& leftArg.peerId === rightArg.peerId
|
|
2472
|
+
&& leftArg.credentialId === rightArg.credentialId
|
|
2473
|
+
&& (leftArg.sessionId === undefined
|
|
2474
|
+
? rightArg.sessionId === undefined
|
|
2475
|
+
: rightArg.sessionId !== undefined
|
|
2476
|
+
&& controllerRuntimeIdKey(leftArg.sessionId) === controllerRuntimeIdKey(rightArg.sessionId))
|
|
2477
|
+
&& (leftArg.requestId === undefined
|
|
2478
|
+
? rightArg.requestId === undefined
|
|
2479
|
+
: rightArg.requestId !== undefined
|
|
2480
|
+
&& controllerRuntimeIdKey(leftArg.requestId) === controllerRuntimeIdKey(rightArg.requestId));
|
|
2481
|
+
}
|
|
2482
|
+
}
|
|
2483
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2xhc3Nlcy5hdXRoc3RvcmUuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi90cy9jbGFzc2VzLmF1dGhzdG9yZS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEtBQUssT0FBTyxNQUFNLGNBQWMsQ0FBQztBQUN4QyxPQUFPLEVBQUUsMEJBQTBCLEVBQUUsTUFBTSx5QkFBeUIsQ0FBQztBQUNyRSxPQUFPLEVBQ0wsU0FBUyxHQVlWLE1BQU0sc0JBQXNCLENBQUM7QUFFOUIsT0FBTyxFQUNMLHlCQUF5QixFQUN6QixtQkFBbUIsRUFDbkIsc0JBQXNCLEVBQ3RCLHVCQUF1QixFQUN2Qiw0QkFBNEIsRUFDNUIsMkJBQTJCLEVBQzNCLHVCQUF1QixFQUN2QiwyQkFBMkIsRUFDM0IseUJBQXlCLEVBQ3pCLHFCQUFxQixFQUNyQix3QkFBd0IsR0FDekIsTUFBTSx5QkFBeUIsQ0FBQztBQUNqQyxPQUFPLEVBQ0wsc0JBQXNCLEVBQ3RCLHVCQUF1QixFQUN2QixrQ0FBa0MsR0FVbkMsTUFBTSwwQkFBMEIsQ0FBQztBQVlsQyxPQUFPLEVBQUUsc0JBQXNCLEVBQUUsTUFBTSwyQkFBMkIsQ0FBQztBQUNuRSxPQUFPLEVBQ0wsbUNBQW1DLEdBQ3BDLE1BQU0sb0RBQW9ELENBQUM7QUFFNUQsT0FBTyxFQUFFLHlCQUF5QixFQUFFLE1BQU0sbUNBQW1DLENBQUM7QUFZOUUsNEVBQTRFO0FBQzVFLDBFQUEwRTtBQUMxRSx3RUFBd0U7QUFDeEUsNEVBQTRFO0FBQzVFLDRFQUE0RTtBQUM1RSxzRUFBc0U7QUFDdEUsaURBQWlEO0FBQ2pELE1BQU0sZ0JBQWdCLEdBQUcsQ0FBQyxHQUFHLEVBQUUsR0FBRyxFQUFFLEdBQUcsRUFBRSxHQUFHLElBQUksQ0FBQztBQUNqRCxNQUFNLHVCQUF1QixHQUFHLEtBQUssQ0FBQztBQUN0QyxNQUFNLHdCQUF3QixHQUFHLEdBQUcsQ0FBQztBQUNyQyxNQUFNLG1CQUFtQixHQUFHLElBQUksQ0FBQztBQUNq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
|