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,144 @@
|
|
|
1
|
+
import * as plugins from '../ts/plugins.js';
|
|
2
|
+
import {
|
|
3
|
+
assertControllerSessionGroupsDocument,
|
|
4
|
+
assertControllerSettingsDocument,
|
|
5
|
+
ControllerSessionGroupsModel,
|
|
6
|
+
ControllerSettingsModel,
|
|
7
|
+
} from '../ts/classes.authmodels.js';
|
|
8
|
+
import { AuthError } from '../ts/interfaces.auth.js';
|
|
9
|
+
import type {
|
|
10
|
+
IControllerSessionGroupsDocument,
|
|
11
|
+
IControllerSettingsDocument,
|
|
12
|
+
} from '../ts/interfaces.projects.js';
|
|
13
|
+
import {
|
|
14
|
+
migrateProtocolV6SessionGroupsDocument,
|
|
15
|
+
migrateProtocolV6SettingsDocument,
|
|
16
|
+
} from './v6_protocoldocuments.js';
|
|
17
|
+
|
|
18
|
+
const migrationPageLimit = 128;
|
|
19
|
+
|
|
20
|
+
const persistedBodyFromRawDocument = (
|
|
21
|
+
valueArg: Record<string, unknown>,
|
|
22
|
+
): Record<string, unknown> => {
|
|
23
|
+
const body = { ...valueArg };
|
|
24
|
+
delete body._id;
|
|
25
|
+
delete body._smartdataRevision;
|
|
26
|
+
return body;
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
export class ProtocolV6DocumentMigration {
|
|
30
|
+
constructor(private readonly database: plugins.smartdata.SmartdataDb | undefined) {}
|
|
31
|
+
|
|
32
|
+
/** Runs before store readiness and is safe to repeat after partial or concurrent completion. */
|
|
33
|
+
public async run(): Promise<void> {
|
|
34
|
+
if (!this.database) {
|
|
35
|
+
throw new AuthError('not_initialized', 'The authentication store database is unavailable.');
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
const settingsCollection = ControllerSettingsModel.collection.mongoDbCollection;
|
|
39
|
+
let lastSettingsId: plugins.smartdata.TStoredDocument<IControllerSettingsDocument>['_id']
|
|
40
|
+
| undefined;
|
|
41
|
+
while (true) {
|
|
42
|
+
const cursor = settingsCollection.find(
|
|
43
|
+
lastSettingsId ? { _id: { $gt: lastSettingsId } } : {},
|
|
44
|
+
).sort({ _id: 1 }).limit(migrationPageLimit);
|
|
45
|
+
let settingsDocuments: Awaited<ReturnType<typeof cursor.toArray>>;
|
|
46
|
+
try {
|
|
47
|
+
settingsDocuments = await cursor.toArray();
|
|
48
|
+
} finally {
|
|
49
|
+
await cursor.close();
|
|
50
|
+
}
|
|
51
|
+
for (const rawDocument of settingsDocuments) {
|
|
52
|
+
const migration = migrateProtocolV6SettingsDocument(
|
|
53
|
+
persistedBodyFromRawDocument(rawDocument),
|
|
54
|
+
);
|
|
55
|
+
assertControllerSettingsDocument(migration.document);
|
|
56
|
+
if (!migration.migrated) continue;
|
|
57
|
+
const revision = plugins.crypto.randomUUID();
|
|
58
|
+
const selector = rawDocument._smartdataRevision === undefined
|
|
59
|
+
? { _id: rawDocument._id, _smartdataRevision: { $exists: false } }
|
|
60
|
+
: { _id: rawDocument._id, _smartdataRevision: rawDocument._smartdataRevision };
|
|
61
|
+
const replaced = await settingsCollection.findOneAndReplace(
|
|
62
|
+
selector,
|
|
63
|
+
{ _id: rawDocument._id, ...migration.document, _smartdataRevision: revision },
|
|
64
|
+
{ returnDocument: 'after', includeResultMetadata: false, upsert: false },
|
|
65
|
+
);
|
|
66
|
+
if (!replaced) {
|
|
67
|
+
const concurrent = await settingsCollection.findOne({ _id: rawDocument._id });
|
|
68
|
+
if (!concurrent) {
|
|
69
|
+
throw new AuthError(
|
|
70
|
+
'concurrent_change',
|
|
71
|
+
'The settings protocol migration changed concurrently.',
|
|
72
|
+
);
|
|
73
|
+
}
|
|
74
|
+
const concurrentMigration = migrateProtocolV6SettingsDocument(
|
|
75
|
+
persistedBodyFromRawDocument(concurrent),
|
|
76
|
+
);
|
|
77
|
+
assertControllerSettingsDocument(concurrentMigration.document);
|
|
78
|
+
if (concurrentMigration.migrated) {
|
|
79
|
+
throw new AuthError(
|
|
80
|
+
'concurrent_change',
|
|
81
|
+
'The settings protocol migration changed concurrently.',
|
|
82
|
+
);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
const lastDocument = settingsDocuments.at(-1);
|
|
87
|
+
if (!lastDocument || settingsDocuments.length < migrationPageLimit) break;
|
|
88
|
+
lastSettingsId = lastDocument._id;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
const layoutsCollection = ControllerSessionGroupsModel.collection.mongoDbCollection;
|
|
92
|
+
let lastLayoutId: plugins.smartdata.TStoredDocument<IControllerSessionGroupsDocument>['_id']
|
|
93
|
+
| undefined;
|
|
94
|
+
while (true) {
|
|
95
|
+
const cursor = layoutsCollection.find(
|
|
96
|
+
lastLayoutId ? { _id: { $gt: lastLayoutId } } : {},
|
|
97
|
+
).sort({ _id: 1 }).limit(migrationPageLimit);
|
|
98
|
+
let layoutDocuments: Awaited<ReturnType<typeof cursor.toArray>>;
|
|
99
|
+
try {
|
|
100
|
+
layoutDocuments = await cursor.toArray();
|
|
101
|
+
} finally {
|
|
102
|
+
await cursor.close();
|
|
103
|
+
}
|
|
104
|
+
for (const rawDocument of layoutDocuments) {
|
|
105
|
+
const migration = migrateProtocolV6SessionGroupsDocument(
|
|
106
|
+
persistedBodyFromRawDocument(rawDocument),
|
|
107
|
+
);
|
|
108
|
+
assertControllerSessionGroupsDocument(migration.document);
|
|
109
|
+
if (!migration.migrated) continue;
|
|
110
|
+
const revision = plugins.crypto.randomUUID();
|
|
111
|
+
const selector = rawDocument._smartdataRevision === undefined
|
|
112
|
+
? { _id: rawDocument._id, _smartdataRevision: { $exists: false } }
|
|
113
|
+
: { _id: rawDocument._id, _smartdataRevision: rawDocument._smartdataRevision };
|
|
114
|
+
const replaced = await layoutsCollection.findOneAndReplace(
|
|
115
|
+
selector,
|
|
116
|
+
{ _id: rawDocument._id, ...migration.document, _smartdataRevision: revision },
|
|
117
|
+
{ returnDocument: 'after', includeResultMetadata: false, upsert: false },
|
|
118
|
+
);
|
|
119
|
+
if (!replaced) {
|
|
120
|
+
const concurrent = await layoutsCollection.findOne({ _id: rawDocument._id });
|
|
121
|
+
if (!concurrent) {
|
|
122
|
+
throw new AuthError(
|
|
123
|
+
'concurrent_change',
|
|
124
|
+
'The session layout protocol migration changed concurrently.',
|
|
125
|
+
);
|
|
126
|
+
}
|
|
127
|
+
const concurrentMigration = migrateProtocolV6SessionGroupsDocument(
|
|
128
|
+
persistedBodyFromRawDocument(concurrent),
|
|
129
|
+
);
|
|
130
|
+
assertControllerSessionGroupsDocument(concurrentMigration.document);
|
|
131
|
+
if (concurrentMigration.migrated) {
|
|
132
|
+
throw new AuthError(
|
|
133
|
+
'concurrent_change',
|
|
134
|
+
'The session layout protocol migration changed concurrently.',
|
|
135
|
+
);
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
const lastDocument = layoutDocuments.at(-1);
|
|
140
|
+
if (!lastDocument || layoutDocuments.length < migrationPageLimit) break;
|
|
141
|
+
lastLayoutId = lastDocument._id;
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
}
|
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
TControllerModelChoice,
|
|
3
|
+
IControllerRuntimeId,
|
|
4
|
+
IControllerSessionGroup,
|
|
5
|
+
TControllerSessionId,
|
|
6
|
+
} from '../ts_interfaces/index.js';
|
|
7
|
+
import type {
|
|
8
|
+
IControllerSessionGroupsDocument,
|
|
9
|
+
IControllerSettingsDocument,
|
|
10
|
+
} from '../ts/interfaces.projects.js';
|
|
11
|
+
|
|
12
|
+
type TObject = Record<string, unknown>;
|
|
13
|
+
|
|
14
|
+
export interface IProtocolV6DocumentMigrationResult<T> {
|
|
15
|
+
document: T;
|
|
16
|
+
migrated: boolean;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
const isPlainObject = (valueArg: unknown): valueArg is TObject => {
|
|
20
|
+
if (typeof valueArg !== 'object' || valueArg === null || Array.isArray(valueArg)) return false;
|
|
21
|
+
const prototype = Object.getPrototypeOf(valueArg);
|
|
22
|
+
return prototype === Object.prototype || prototype === null;
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
const hasExactKeys = (
|
|
26
|
+
valueArg: TObject,
|
|
27
|
+
requiredArg: readonly string[],
|
|
28
|
+
optionalArg: readonly string[] = [],
|
|
29
|
+
): boolean => {
|
|
30
|
+
const allowed = new Set([...requiredArg, ...optionalArg]);
|
|
31
|
+
return requiredArg.every((key) => Object.hasOwn(valueArg, key))
|
|
32
|
+
&& Object.keys(valueArg).every((key) => allowed.has(key));
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
const isBoundedString = (valueArg: unknown, maximumBytesArg: number): valueArg is string =>
|
|
36
|
+
typeof valueArg === 'string'
|
|
37
|
+
&& valueArg.length > 0
|
|
38
|
+
&& Buffer.byteLength(valueArg, 'utf8') <= maximumBytesArg;
|
|
39
|
+
|
|
40
|
+
const isRuntimeId = (valueArg: unknown): valueArg is IControllerRuntimeId =>
|
|
41
|
+
isPlainObject(valueArg)
|
|
42
|
+
&& hasExactKeys(valueArg, ['harnessId', 'nativeId'])
|
|
43
|
+
&& (
|
|
44
|
+
valueArg.harnessId === 'opencode'
|
|
45
|
+
|| valueArg.harnessId === 'flex'
|
|
46
|
+
|| valueArg.harnessId === 'controller'
|
|
47
|
+
)
|
|
48
|
+
&& isBoundedString(valueArg.nativeId, 512);
|
|
49
|
+
|
|
50
|
+
const qualifyLegacySessionId = (nativeIdArg: string): TControllerSessionId => ({
|
|
51
|
+
harnessId: 'opencode',
|
|
52
|
+
nativeId: nativeIdArg,
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
const toSessionRuntimeId = (valueArg: IControllerRuntimeId): TControllerSessionId | undefined => (
|
|
56
|
+
valueArg.harnessId === 'opencode' || valueArg.harnessId === 'flex'
|
|
57
|
+
? valueArg as TControllerSessionId
|
|
58
|
+
: undefined
|
|
59
|
+
);
|
|
60
|
+
|
|
61
|
+
const isLegacySessionId = (valueArg: unknown): valueArg is string =>
|
|
62
|
+
isBoundedString(valueArg, 512) && /^[A-Za-z0-9_-]+$/.test(valueArg);
|
|
63
|
+
|
|
64
|
+
const isLegacyModelChoice = (valueArg: unknown): valueArg is {
|
|
65
|
+
providerID: string;
|
|
66
|
+
modelID: string;
|
|
67
|
+
variant?: string;
|
|
68
|
+
} => {
|
|
69
|
+
if (!isPlainObject(valueArg)) return false;
|
|
70
|
+
if (!hasExactKeys(valueArg, ['providerID', 'modelID'], ['variant'])) return false;
|
|
71
|
+
return isBoundedString(valueArg.providerID, 256)
|
|
72
|
+
&& isBoundedString(valueArg.modelID, 256)
|
|
73
|
+
&& (
|
|
74
|
+
!Object.hasOwn(valueArg, 'variant')
|
|
75
|
+
|| (
|
|
76
|
+
typeof valueArg.variant === 'string'
|
|
77
|
+
&& /^[A-Za-z0-9][A-Za-z0-9._-]{0,63}$/.test(valueArg.variant)
|
|
78
|
+
)
|
|
79
|
+
);
|
|
80
|
+
};
|
|
81
|
+
|
|
82
|
+
const qualifyLegacyModel = (
|
|
83
|
+
modelArg: { providerID: string; modelID: string; variant?: string },
|
|
84
|
+
): TControllerModelChoice => ({
|
|
85
|
+
harnessId: 'opencode',
|
|
86
|
+
providerID: modelArg.providerID,
|
|
87
|
+
modelID: modelArg.modelID,
|
|
88
|
+
...(modelArg.variant === undefined ? {} : { variant: modelArg.variant }),
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
export const migrateProtocolV6SettingsDocument = (
|
|
92
|
+
valueArg: unknown,
|
|
93
|
+
): IProtocolV6DocumentMigrationResult<IControllerSettingsDocument> => {
|
|
94
|
+
if (!isPlainObject(valueArg)) throw new Error('Invalid controller settings migration document.');
|
|
95
|
+
if (hasExactKeys(valueArg, ['id', 'controllerId', 'defaultModels'], ['autoAcceptPermissions'])) {
|
|
96
|
+
return {
|
|
97
|
+
document: valueArg as unknown as IControllerSettingsDocument,
|
|
98
|
+
migrated: false,
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
if (
|
|
102
|
+
!hasExactKeys(valueArg, ['id', 'controllerId', 'defaultModel'], ['autoAcceptPermissions'])
|
|
103
|
+
|| (valueArg.defaultModel !== null && !isLegacyModelChoice(valueArg.defaultModel))
|
|
104
|
+
) {
|
|
105
|
+
throw new Error('Invalid legacy controller settings migration document.');
|
|
106
|
+
}
|
|
107
|
+
return {
|
|
108
|
+
document: {
|
|
109
|
+
id: valueArg.id as string,
|
|
110
|
+
controllerId: valueArg.controllerId as string,
|
|
111
|
+
defaultModels: valueArg.defaultModel === null
|
|
112
|
+
? []
|
|
113
|
+
: [qualifyLegacyModel(valueArg.defaultModel)],
|
|
114
|
+
...(valueArg.autoAcceptPermissions === undefined
|
|
115
|
+
? {}
|
|
116
|
+
: { autoAcceptPermissions: valueArg.autoAcceptPermissions as true }),
|
|
117
|
+
},
|
|
118
|
+
migrated: true,
|
|
119
|
+
};
|
|
120
|
+
};
|
|
121
|
+
|
|
122
|
+
export const migrateProtocolV6SessionGroupsDocument = (
|
|
123
|
+
valueArg: unknown,
|
|
124
|
+
): IProtocolV6DocumentMigrationResult<IControllerSessionGroupsDocument> => {
|
|
125
|
+
if (!isPlainObject(valueArg)) throw new Error('Invalid controller layout migration document.');
|
|
126
|
+
if (
|
|
127
|
+
!hasExactKeys(
|
|
128
|
+
valueArg,
|
|
129
|
+
['id', 'controllerId', 'projectId', 'groups'],
|
|
130
|
+
['ungroupedSessionIds', 'revision'],
|
|
131
|
+
)
|
|
132
|
+
|| !Array.isArray(valueArg.groups)
|
|
133
|
+
) {
|
|
134
|
+
throw new Error('Invalid controller layout migration document.');
|
|
135
|
+
}
|
|
136
|
+
const hasLegacyShape = valueArg.ungroupedSessionIds === undefined
|
|
137
|
+
|| valueArg.revision === undefined
|
|
138
|
+
|| valueArg.groups.some((groupArg) => (
|
|
139
|
+
isPlainObject(groupArg)
|
|
140
|
+
&& Array.isArray(groupArg.sessionIds)
|
|
141
|
+
&& groupArg.sessionIds.some(isLegacySessionId)
|
|
142
|
+
))
|
|
143
|
+
|| (
|
|
144
|
+
Array.isArray(valueArg.ungroupedSessionIds)
|
|
145
|
+
&& valueArg.ungroupedSessionIds.some(isLegacySessionId)
|
|
146
|
+
);
|
|
147
|
+
if (!hasLegacyShape) {
|
|
148
|
+
return {
|
|
149
|
+
document: valueArg as unknown as IControllerSessionGroupsDocument,
|
|
150
|
+
migrated: false,
|
|
151
|
+
};
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
const groups: IControllerSessionGroup[] = valueArg.groups.map((groupArg) => {
|
|
155
|
+
if (
|
|
156
|
+
!isPlainObject(groupArg)
|
|
157
|
+
|| !hasExactKeys(groupArg, ['id', 'name', 'sessionIds'])
|
|
158
|
+
|| !Array.isArray(groupArg.sessionIds)
|
|
159
|
+
) {
|
|
160
|
+
throw new Error('Invalid legacy controller layout group.');
|
|
161
|
+
}
|
|
162
|
+
return {
|
|
163
|
+
id: groupArg.id as string,
|
|
164
|
+
name: groupArg.name as string,
|
|
165
|
+
sessionIds: groupArg.sessionIds.flatMap((sessionIdArg): TControllerSessionId[] => {
|
|
166
|
+
if (isLegacySessionId(sessionIdArg)) return [qualifyLegacySessionId(sessionIdArg)];
|
|
167
|
+
if (isRuntimeId(sessionIdArg)) {
|
|
168
|
+
const sessionId = toSessionRuntimeId(sessionIdArg);
|
|
169
|
+
return sessionId ? [sessionId] : [];
|
|
170
|
+
}
|
|
171
|
+
throw new Error('Invalid legacy controller layout session ID.');
|
|
172
|
+
}),
|
|
173
|
+
};
|
|
174
|
+
});
|
|
175
|
+
const legacyUngrouped = valueArg.ungroupedSessionIds ?? [];
|
|
176
|
+
if (!Array.isArray(legacyUngrouped)) {
|
|
177
|
+
throw new Error('Invalid legacy controller ungrouped session list.');
|
|
178
|
+
}
|
|
179
|
+
const ungroupedSessionIds = legacyUngrouped.flatMap((sessionIdArg): TControllerSessionId[] => {
|
|
180
|
+
if (isLegacySessionId(sessionIdArg)) return [qualifyLegacySessionId(sessionIdArg)];
|
|
181
|
+
if (isRuntimeId(sessionIdArg)) {
|
|
182
|
+
const sessionId = toSessionRuntimeId(sessionIdArg);
|
|
183
|
+
return sessionId ? [sessionId] : [];
|
|
184
|
+
}
|
|
185
|
+
throw new Error('Invalid legacy controller ungrouped session ID.');
|
|
186
|
+
});
|
|
187
|
+
return {
|
|
188
|
+
document: {
|
|
189
|
+
id: valueArg.id as string,
|
|
190
|
+
controllerId: valueArg.controllerId as string,
|
|
191
|
+
projectId: valueArg.projectId as string,
|
|
192
|
+
groups,
|
|
193
|
+
ungroupedSessionIds,
|
|
194
|
+
revision: valueArg.revision === undefined ? 0 : valueArg.revision as number,
|
|
195
|
+
},
|
|
196
|
+
migrated: true,
|
|
197
|
+
};
|
|
198
|
+
};
|