openlearn-next 0.7.5 → 0.7.7
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/README.md +66 -150
- package/dist/assets/{AcademicYearFilter-DUUGpDKt.js → AcademicYearFilter-Dm3no4Nb.js} +1 -1
- package/dist/assets/ActivityWorkspaceWidget-BLJAc5g8.js +1 -0
- package/dist/assets/{AdminDirectoryView-B6OAs5Rj.js → AdminDirectoryView-D6sMmobg.js} +1 -1
- package/dist/assets/{AssessmentCenter-B3f1DxSG.js → AssessmentCenter-3Cu5DE67.js} +1 -1
- package/dist/assets/{AssignmentFilePreview-DQbvbgnd.js → AssignmentFilePreview-DvBdEpB3.js} +2 -2
- package/dist/assets/{BatchPickerModal-CoOWloSS.js → BatchPickerModal-D1kEgc4L.js} +1 -1
- package/dist/assets/{ClassesView-Q56Kf4eL.js → ClassesView-DpC-D2y5.js} +10 -10
- package/dist/assets/{ClassroomCountdownWidget-C6luhy8P.js → ClassroomCountdownWidget-DFGC4XNs.js} +2 -2
- package/dist/assets/{CloudDriveModal-DLf4fbKR.js → CloudDriveModal-drWgNbEq.js} +1 -1
- package/dist/assets/ComputerLabView-BnfpX3XL.js +1 -0
- package/dist/assets/CourseManagement-DuVTm_hD.js +1 -0
- package/dist/assets/{CourseWizardModal-DAueHXcl.js → CourseWizardModal-BvQ4d1tN.js} +1 -1
- package/dist/assets/{CoursewareHubPanel-DLjH-UzF.js → CoursewareHubPanel-Ct9hTAOu.js} +1 -1
- package/dist/assets/{Dashboard-qMVadkd2.js → Dashboard-D3yj1oZj.js} +2 -2
- package/dist/assets/{ExportWeightModal-Dkh7OC8U.js → ExportWeightModal-CnbJuOav.js} +1 -1
- package/dist/assets/{HelpTour-BLuiS8rr.js → HelpTour-COz9zyR9.js} +1 -1
- package/dist/assets/{HelpView-CTF6B9ml.js → HelpView-PmIyAO8_.js} +2 -2
- package/dist/assets/{ImportLessonsModal-Ra-OF_Vo.js → ImportLessonsModal-CSlMGoet.js} +1 -1
- package/dist/assets/{ImportModal-H5s5MyZY.js → ImportModal-CCzFqKY0.js} +1 -1
- package/dist/assets/{InteractiveCoursewareViewer-BfHEDrCf.js → InteractiveCoursewareViewer-bgyDq7MF.js} +1 -1
- package/dist/assets/{InteractiveWhiteboard-KBzmiNBG.js → InteractiveWhiteboard-v8FqsMj3.js} +8 -8
- package/dist/assets/LazyCourseware-Bt31zjJT.js +2 -0
- package/dist/assets/LazyWhiteboard-Da0K2ZR1.js +2 -0
- package/dist/assets/LessonEditorView-DT3M9p_4.js +1 -0
- package/dist/assets/{LiveClassroomView-DezAlve2.js → LiveClassroomView-CrLRO8vI.js} +1 -1
- package/dist/assets/NotificationDetailModal-BgqbD3Gh.js +1 -0
- package/dist/assets/PluginView-CkICwR16.js +77 -0
- package/dist/assets/{ProcessLogsModal-_BwkmJVw.js → ProcessLogsModal-zO4lMuUa.js} +1 -1
- package/dist/assets/{QuizGeneratorModal-CTj2moWM.js → QuizGeneratorModal-D60-HJGk.js} +1 -1
- package/dist/assets/StudentAssignmentEvalPanel-C336iZSv.js +1 -0
- package/dist/assets/{StudentAssignmentView-D_EhblVQ.js → StudentAssignmentView--JlShlDQ.js} +1 -1
- package/dist/assets/{StudentLessonView-BHG50-4M.js → StudentLessonView-BgjjfEfD.js} +1 -1
- package/dist/assets/StudentView-Cjq1QOvV.js +2 -0
- package/dist/assets/{SystemResourceLibraryModal-C5y8H5Pf.js → SystemResourceLibraryModal-pPdl2NHf.js} +1 -1
- package/dist/assets/TeacherView-dLr1v6tY.js +2 -0
- package/dist/assets/{TimetableView-C8kdJlf7.js → TimetableView-CVAD4LYw.js} +1 -1
- package/dist/assets/{UTIF-4E-wdh3X.js → UTIF-p6fKAG_V.js} +1 -1
- package/dist/assets/index-BfKoCpo_.js +131 -0
- package/dist/assets/{index-DPky2leG.css → index-DIcDOunT.css} +1 -1
- package/dist/assets/{index.es-WXdI0L-F.js → index.es-B8wsP9dg.js} +1 -1
- package/dist/assets/{pluginParsers-DkiO-BBu.js → pluginParsers-D5PQwW_l.js} +1 -1
- package/dist/assets/{student-workspace-1yVTbWHC.js → student-workspace-C2tppsk6.js} +1 -1
- package/dist/assets/{vendor-charts-SrpBsvM3.js → vendor-charts-skggaP9D.js} +1 -1
- package/dist/assets/{vendor-icons-hc6MjYFv.js → vendor-icons-DGdjNlGa.js} +2 -2
- package/dist/assets/{vendor-konva-Dne0Z-WC.js → vendor-konva-BOuJWFuE.js} +1 -1
- package/dist/assets/{vendor-pdf-By0fofA0.js → vendor-pdf-DmaV9d9t.js} +3 -3
- package/dist/assets/{vendor-pptx-EjNUtdws.js → vendor-pptx-CpYklkz2.js} +4 -4
- package/dist/assets/{vendor-react-Kv_JATwr.js → vendor-react-DHoBZpn2.js} +2 -2
- package/dist/assets/{vendor-utils-aM7aYvPP.js → vendor-utils-BxOuk3id.js} +1 -1
- package/dist/env-validation.cjs +7 -1
- package/dist/index.html +5 -5
- package/dist/server.cjs +352 -51
- package/package.json +1 -1
- package/dist/assets/ActivityWorkspaceWidget-Dq4kjBS2.js +0 -1
- package/dist/assets/ComputerLabView-D9-Tk7yA.js +0 -1
- package/dist/assets/CourseManagement-DNSfyre-.js +0 -1
- package/dist/assets/LazyCourseware-BaZS8-i1.js +0 -2
- package/dist/assets/LazyWhiteboard-DGyln3JC.js +0 -2
- package/dist/assets/LessonEditorView-B5JXYyup.js +0 -1
- package/dist/assets/NotificationDetailModal-DbMMrIHQ.js +0 -1
- package/dist/assets/PluginView-CvIr-ANj.js +0 -77
- package/dist/assets/StudentAssignmentEvalPanel-DrfZT8Lr.js +0 -1
- package/dist/assets/StudentView-DKDhnJQx.js +0 -2
- package/dist/assets/TeacherView-CWDK3DOe.js +0 -2
- package/dist/assets/index-BBznBaN5.js +0 -131
package/dist/server.cjs
CHANGED
|
@@ -3578,6 +3578,19 @@ var init_errors2 = __esm({
|
|
|
3578
3578
|
function scopedId(scopeType, scopeId, key) {
|
|
3579
3579
|
return `${scopeType}\0${scopeId}\0${key}`;
|
|
3580
3580
|
}
|
|
3581
|
+
function getSharedState(db2, manifestId) {
|
|
3582
|
+
let byManifest = sharedStates.get(db2);
|
|
3583
|
+
if (!byManifest) {
|
|
3584
|
+
byManifest = /* @__PURE__ */ new Map();
|
|
3585
|
+
sharedStates.set(db2, byManifest);
|
|
3586
|
+
}
|
|
3587
|
+
let state = byManifest.get(manifestId);
|
|
3588
|
+
if (!state) {
|
|
3589
|
+
state = { values: /* @__PURE__ */ new Map(), instances: /* @__PURE__ */ new Set() };
|
|
3590
|
+
byManifest.set(manifestId, state);
|
|
3591
|
+
}
|
|
3592
|
+
return state;
|
|
3593
|
+
}
|
|
3581
3594
|
function normalizeWriteScope(scope) {
|
|
3582
3595
|
const scopeType = scope?.scopeType ?? "platform";
|
|
3583
3596
|
const scopeId = scope?.scopeId?.trim() ?? "";
|
|
@@ -3586,21 +3599,29 @@ function normalizeWriteScope(scope) {
|
|
|
3586
3599
|
}
|
|
3587
3600
|
return { scopeType, scopeId: scopeType === "platform" ? "" : scopeId };
|
|
3588
3601
|
}
|
|
3589
|
-
var CONFIG_SCOPE_TYPES, ConfigService;
|
|
3602
|
+
var CONFIG_SCOPE_TYPES, sharedStates, instanceCleanup, ConfigService;
|
|
3590
3603
|
var init_config_service = __esm({
|
|
3591
3604
|
"packages/core/plugin-host/config-service.ts"() {
|
|
3592
3605
|
"use strict";
|
|
3593
3606
|
CONFIG_SCOPE_TYPES = ["platform", "school", "class"];
|
|
3607
|
+
sharedStates = /* @__PURE__ */ new WeakMap();
|
|
3608
|
+
instanceCleanup = new FinalizationRegistry(
|
|
3609
|
+
({ state, ref }) => {
|
|
3610
|
+
state.instances.delete(ref);
|
|
3611
|
+
}
|
|
3612
|
+
);
|
|
3594
3613
|
ConfigService = class _ConfigService {
|
|
3595
3614
|
constructor(db2, manifest) {
|
|
3596
|
-
/**
|
|
3597
|
-
this.values = /* @__PURE__ */ new Map();
|
|
3598
|
-
/** Change listeners. */
|
|
3615
|
+
/** Change listeners(每个实例独立,广播时按实例分发)。 */
|
|
3599
3616
|
this.listeners = /* @__PURE__ */ new Set();
|
|
3600
3617
|
this.tableEnsured = false;
|
|
3601
3618
|
this.db = db2;
|
|
3602
3619
|
this.manifestId = manifest.id;
|
|
3603
3620
|
this.schema = manifest.configuration?.properties ?? {};
|
|
3621
|
+
this.state = getSharedState(db2, manifest.id);
|
|
3622
|
+
const ref = new WeakRef(this);
|
|
3623
|
+
this.state.instances.add(ref);
|
|
3624
|
+
instanceCleanup.register(this, { state: this.state, ref });
|
|
3604
3625
|
}
|
|
3605
3626
|
static {
|
|
3606
3627
|
this.KEY_PREFIX = "config:";
|
|
@@ -3663,21 +3684,21 @@ var init_config_service = __esm({
|
|
|
3663
3684
|
}
|
|
3664
3685
|
readScoped(key, scopeType, scopeId) {
|
|
3665
3686
|
const cacheKey2 = scopedId(scopeType, scopeId, key);
|
|
3666
|
-
if (this.values.has(cacheKey2)) {
|
|
3667
|
-
const cached3 = this.values.get(cacheKey2);
|
|
3687
|
+
if (this.state.values.has(cacheKey2)) {
|
|
3688
|
+
const cached3 = this.state.values.get(cacheKey2);
|
|
3668
3689
|
return cached3 === null ? { found: false } : { found: true, value: cached3 };
|
|
3669
3690
|
}
|
|
3670
3691
|
const row = this.queryScoped(key, scopeType, scopeId);
|
|
3671
3692
|
if (!row) {
|
|
3672
|
-
this.values.set(cacheKey2, null);
|
|
3693
|
+
this.state.values.set(cacheKey2, null);
|
|
3673
3694
|
return { found: false };
|
|
3674
3695
|
}
|
|
3675
3696
|
try {
|
|
3676
3697
|
const parsed = JSON.parse(row.value);
|
|
3677
|
-
this.values.set(cacheKey2, parsed);
|
|
3698
|
+
this.state.values.set(cacheKey2, parsed);
|
|
3678
3699
|
return { found: true, value: parsed };
|
|
3679
3700
|
} catch {
|
|
3680
|
-
this.values.set(cacheKey2, row.value);
|
|
3701
|
+
this.state.values.set(cacheKey2, row.value);
|
|
3681
3702
|
return { found: true, value: row.value };
|
|
3682
3703
|
}
|
|
3683
3704
|
}
|
|
@@ -3693,21 +3714,21 @@ var init_config_service = __esm({
|
|
|
3693
3714
|
}
|
|
3694
3715
|
readLegacyPlatformValue(key) {
|
|
3695
3716
|
const cacheKey2 = scopedId("platform", "", `legacy:${key}`);
|
|
3696
|
-
if (this.values.has(cacheKey2)) {
|
|
3697
|
-
const cached3 = this.values.get(cacheKey2);
|
|
3717
|
+
if (this.state.values.has(cacheKey2)) {
|
|
3718
|
+
const cached3 = this.state.values.get(cacheKey2);
|
|
3698
3719
|
return cached3 === null ? { found: false } : { found: true, value: cached3 };
|
|
3699
3720
|
}
|
|
3700
3721
|
try {
|
|
3701
3722
|
const row = this.db.prepare("SELECT value FROM plugin_storage WHERE plugin_id = ? AND key = ?").get(this.manifestId, _ConfigService.KEY_PREFIX + key);
|
|
3702
3723
|
if (!row) {
|
|
3703
|
-
this.values.set(cacheKey2, null);
|
|
3724
|
+
this.state.values.set(cacheKey2, null);
|
|
3704
3725
|
return { found: false };
|
|
3705
3726
|
}
|
|
3706
3727
|
const parsed = JSON.parse(row.value);
|
|
3707
|
-
this.values.set(cacheKey2, parsed);
|
|
3728
|
+
this.state.values.set(cacheKey2, parsed);
|
|
3708
3729
|
return { found: true, value: parsed };
|
|
3709
3730
|
} catch {
|
|
3710
|
-
this.values.set(cacheKey2, null);
|
|
3731
|
+
this.state.values.set(cacheKey2, null);
|
|
3711
3732
|
return { found: false };
|
|
3712
3733
|
}
|
|
3713
3734
|
}
|
|
@@ -3763,8 +3784,8 @@ var init_config_service = __esm({
|
|
|
3763
3784
|
const { scopeType, scopeId } = normalizeWriteScope(scope);
|
|
3764
3785
|
this.assertScopeAllowed(key, scopeType);
|
|
3765
3786
|
const cacheKey2 = scopedId(scopeType, scopeId, key);
|
|
3766
|
-
const previous = this.values.get(cacheKey2);
|
|
3767
|
-
this.values.set(cacheKey2, value);
|
|
3787
|
+
const previous = this.state.values.get(cacheKey2);
|
|
3788
|
+
this.state.values.set(cacheKey2, value);
|
|
3768
3789
|
try {
|
|
3769
3790
|
this.ensureTable();
|
|
3770
3791
|
this.db.prepare(
|
|
@@ -3775,16 +3796,32 @@ var init_config_service = __esm({
|
|
|
3775
3796
|
).run(this.manifestId, scopeType, scopeId, key, JSON.stringify(value), Date.now());
|
|
3776
3797
|
} catch (e) {
|
|
3777
3798
|
if (previous === void 0) {
|
|
3778
|
-
this.values.delete(cacheKey2);
|
|
3799
|
+
this.state.values.delete(cacheKey2);
|
|
3779
3800
|
} else {
|
|
3780
|
-
this.values.set(cacheKey2, previous);
|
|
3801
|
+
this.state.values.set(cacheKey2, previous);
|
|
3781
3802
|
}
|
|
3782
3803
|
throw e;
|
|
3783
3804
|
}
|
|
3784
|
-
|
|
3785
|
-
|
|
3786
|
-
|
|
3787
|
-
|
|
3805
|
+
this.broadcast(key, value, previous ?? void 0);
|
|
3806
|
+
}
|
|
3807
|
+
/**
|
|
3808
|
+
* 通知所有共享同一 db + manifest.id 的活跃实例(含自身)。
|
|
3809
|
+
*
|
|
3810
|
+
* 管理端通过临时实例写入时,运行中插件的 `onChange` 也因此能收到。
|
|
3811
|
+
* 已回收的实例在遍历时顺手清理。
|
|
3812
|
+
*/
|
|
3813
|
+
broadcast(key, newValue, oldValue) {
|
|
3814
|
+
for (const ref of this.state.instances) {
|
|
3815
|
+
const instance = ref.deref();
|
|
3816
|
+
if (!instance) {
|
|
3817
|
+
this.state.instances.delete(ref);
|
|
3818
|
+
continue;
|
|
3819
|
+
}
|
|
3820
|
+
for (const listener of instance.listeners) {
|
|
3821
|
+
try {
|
|
3822
|
+
listener(key, newValue, oldValue);
|
|
3823
|
+
} catch {
|
|
3824
|
+
}
|
|
3788
3825
|
}
|
|
3789
3826
|
}
|
|
3790
3827
|
}
|
|
@@ -3817,11 +3854,12 @@ var init_config_service = __esm({
|
|
|
3817
3854
|
* 插件在 `activate()` 里通常会马上读配置,提前填充避免每条配置一次查询。
|
|
3818
3855
|
*/
|
|
3819
3856
|
loadFromDB() {
|
|
3857
|
+
this.state.values.clear();
|
|
3820
3858
|
try {
|
|
3821
3859
|
const rows = this.db.prepare(`SELECT scope_type, scope_id, key, value FROM ${_ConfigService.TABLE} WHERE plugin_id = ?`).all(this.manifestId);
|
|
3822
3860
|
for (const row of rows) {
|
|
3823
3861
|
const scopeType = CONFIG_SCOPE_TYPES.includes(row.scope_type) ? row.scope_type : "platform";
|
|
3824
|
-
this.values.set(scopedId(scopeType, row.scope_id ?? "", row.key), this.parseStored(row.value));
|
|
3862
|
+
this.state.values.set(scopedId(scopeType, row.scope_id ?? "", row.key), this.parseStored(row.value));
|
|
3825
3863
|
}
|
|
3826
3864
|
} catch {
|
|
3827
3865
|
}
|
|
@@ -3830,7 +3868,7 @@ var init_config_service = __esm({
|
|
|
3830
3868
|
const rows = this.db.prepare(`SELECT key, value FROM plugin_storage WHERE plugin_id = ? AND key LIKE ?`).all(this.manifestId, prefix + "%");
|
|
3831
3869
|
for (const row of rows) {
|
|
3832
3870
|
const key = row.key.slice(prefix.length);
|
|
3833
|
-
this.values.set(scopedId("platform", "", `legacy:${key}`), this.parseStored(row.value));
|
|
3871
|
+
this.state.values.set(scopedId("platform", "", `legacy:${key}`), this.parseStored(row.value));
|
|
3834
3872
|
}
|
|
3835
3873
|
} catch {
|
|
3836
3874
|
}
|
|
@@ -3842,9 +3880,9 @@ var init_config_service = __esm({
|
|
|
3842
3880
|
return raw;
|
|
3843
3881
|
}
|
|
3844
3882
|
}
|
|
3845
|
-
/**
|
|
3883
|
+
/** 测试/诊断:当前共享缓存里的作用域条目数。 */
|
|
3846
3884
|
cachedEntryCount() {
|
|
3847
|
-
return this.values.size;
|
|
3885
|
+
return this.state.values.size;
|
|
3848
3886
|
}
|
|
3849
3887
|
};
|
|
3850
3888
|
}
|
|
@@ -4549,14 +4587,33 @@ function wrapProcessManager(processService, tracker, pluginId, processOwnerLooku
|
|
|
4549
4587
|
})
|
|
4550
4588
|
};
|
|
4551
4589
|
}
|
|
4552
|
-
function wrapActionRegistry(actionRegistry, tracker, pluginId) {
|
|
4590
|
+
function wrapActionRegistry(actionRegistry, tracker, pluginId, manifestId) {
|
|
4591
|
+
const prefix = manifestId || pluginId;
|
|
4592
|
+
const isKernel = prefix.startsWith("@openlearn/");
|
|
4553
4593
|
return {
|
|
4554
4594
|
register: createSafeFunction((descriptor) => {
|
|
4555
|
-
|
|
4595
|
+
const commandType = descriptor.commandType;
|
|
4596
|
+
const prefixed = isKernel || !commandType || commandType.startsWith(`${prefix}.`) ? commandType : `${prefix}.${commandType}`;
|
|
4597
|
+
const effectiveDescriptor = prefixed !== commandType ? { ...descriptor, commandType: prefixed } : descriptor;
|
|
4598
|
+
return Promise.resolve(actionRegistry.register(effectiveDescriptor)).then(() => {
|
|
4599
|
+
if (prefixed !== commandType) {
|
|
4600
|
+
Promise.resolve(
|
|
4601
|
+
actionRegistry.register({
|
|
4602
|
+
...descriptor,
|
|
4603
|
+
id: `${descriptor.id}__raw_alias`,
|
|
4604
|
+
exposeToAgent: false
|
|
4605
|
+
})
|
|
4606
|
+
).catch(() => {
|
|
4607
|
+
});
|
|
4608
|
+
}
|
|
4556
4609
|
tracker.track(pluginId, {
|
|
4557
4610
|
dispose: () => {
|
|
4558
|
-
Promise.resolve(actionRegistry.unregister(
|
|
4611
|
+
Promise.resolve(actionRegistry.unregister(effectiveDescriptor.id)).catch(() => {
|
|
4559
4612
|
});
|
|
4613
|
+
if (prefixed !== commandType) {
|
|
4614
|
+
Promise.resolve(actionRegistry.unregister(`${descriptor.id}__raw_alias`)).catch(() => {
|
|
4615
|
+
});
|
|
4616
|
+
}
|
|
4560
4617
|
}
|
|
4561
4618
|
});
|
|
4562
4619
|
});
|
|
@@ -4797,7 +4854,7 @@ async function buildContext(serviceRegistry, tracker, pluginId, manifest, db2, s
|
|
|
4797
4854
|
// 可选方法,mock 或旧部署可缺省 —— 缺省时 isOwnProcess 退化为「不拦截」,与旧行为一致。
|
|
4798
4855
|
typeof processService.getProcessOwner === "function" ? (processId) => processService.getProcessOwner(processId) : void 0
|
|
4799
4856
|
);
|
|
4800
|
-
const wrappedActionRegistry = wrapActionRegistry(actionRegistryService, tracker, pluginId);
|
|
4857
|
+
const wrappedActionRegistry = wrapActionRegistry(actionRegistryService, tracker, pluginId, manifest.id);
|
|
4801
4858
|
const wrappedCapability = wrapCapability(capabilityService);
|
|
4802
4859
|
const wrappedStorage = wrapStorage(storageService, db2, manifest.id);
|
|
4803
4860
|
const wrappedAI = wrapAI(aiService, pluginId, tracker);
|
|
@@ -8442,10 +8499,28 @@ var init_service_host = __esm({
|
|
|
8442
8499
|
const actionRegistry = service;
|
|
8443
8500
|
if (msg.method === "register") {
|
|
8444
8501
|
const [descriptor] = effectiveArgs;
|
|
8445
|
-
|
|
8446
|
-
|
|
8447
|
-
|
|
8448
|
-
|
|
8502
|
+
const pluginId = this.pluginId || this.pluginActorId.replace(/^plugin:/, "");
|
|
8503
|
+
const isKernel = pluginId.startsWith("@openlearn/");
|
|
8504
|
+
const rawCommandType = descriptor.commandType;
|
|
8505
|
+
const prefixed = isKernel || !rawCommandType || rawCommandType.startsWith(`${pluginId}.`) ? rawCommandType : resolvePluginCommandType(rawCommandType, pluginId);
|
|
8506
|
+
const effectiveDescriptor = prefixed !== rawCommandType ? { ...descriptor, commandType: prefixed } : descriptor;
|
|
8507
|
+
await actionRegistry.register(effectiveDescriptor);
|
|
8508
|
+
this.registeredActionIds.add(effectiveDescriptor.id);
|
|
8509
|
+
if (typeof effectiveDescriptor?.commandType === "string") {
|
|
8510
|
+
this.registeredActionCommandTypes.set(effectiveDescriptor.id, effectiveDescriptor.commandType);
|
|
8511
|
+
}
|
|
8512
|
+
if (prefixed !== rawCommandType) {
|
|
8513
|
+
try {
|
|
8514
|
+
const aliasId = `${descriptor.id}__raw_alias`;
|
|
8515
|
+
await actionRegistry.register({
|
|
8516
|
+
...descriptor,
|
|
8517
|
+
id: aliasId,
|
|
8518
|
+
exposeToAgent: false
|
|
8519
|
+
});
|
|
8520
|
+
this.registeredActionIds.add(aliasId);
|
|
8521
|
+
this.registeredActionCommandTypes.set(aliasId, rawCommandType);
|
|
8522
|
+
} catch {
|
|
8523
|
+
}
|
|
8449
8524
|
}
|
|
8450
8525
|
transport.postMessage({
|
|
8451
8526
|
type: "result",
|
|
@@ -8456,8 +8531,14 @@ var init_service_host = __esm({
|
|
|
8456
8531
|
} else if (msg.method === "unregister") {
|
|
8457
8532
|
const [actionId] = msg.args;
|
|
8458
8533
|
await actionRegistry.unregister(actionId);
|
|
8534
|
+
try {
|
|
8535
|
+
await actionRegistry.unregister(`${actionId}__raw_alias`);
|
|
8536
|
+
} catch {
|
|
8537
|
+
}
|
|
8459
8538
|
this.registeredActionIds.delete(actionId);
|
|
8539
|
+
this.registeredActionIds.delete(`${actionId}__raw_alias`);
|
|
8460
8540
|
this.registeredActionCommandTypes.delete(actionId);
|
|
8541
|
+
this.registeredActionCommandTypes.delete(`${actionId}__raw_alias`);
|
|
8461
8542
|
transport.postMessage({
|
|
8462
8543
|
type: "result",
|
|
8463
8544
|
invokeId: msg.invokeId,
|
|
@@ -15190,6 +15271,26 @@ var BuiltinPlugin = {
|
|
|
15190
15271
|
"page_meta"
|
|
15191
15272
|
// 分页与大纲元数据
|
|
15192
15273
|
];
|
|
15274
|
+
const isAllowedElementType = (type) => {
|
|
15275
|
+
if (!type || typeof type !== "string") return false;
|
|
15276
|
+
if (KNOWN_ELEMENT_TYPES2.includes(type)) return true;
|
|
15277
|
+
if (type.includes("/") || type.startsWith("plugin:") || type.startsWith("ext-") || type.startsWith("plugin-")) {
|
|
15278
|
+
return true;
|
|
15279
|
+
}
|
|
15280
|
+
try {
|
|
15281
|
+
const reg = pluginHost?.getContributionRegistry?.();
|
|
15282
|
+
if (reg) {
|
|
15283
|
+
const paletteItems = reg.getBySlot("editor.palette_item") || [];
|
|
15284
|
+
if (paletteItems.some((item) => item.type === type || item.id === type)) return true;
|
|
15285
|
+
const renderers = reg.getBySlot("whiteboard.renderer") || [];
|
|
15286
|
+
if (renderers.some((item) => item.targetType === type || item.id === type || item.elementType === type)) {
|
|
15287
|
+
return true;
|
|
15288
|
+
}
|
|
15289
|
+
}
|
|
15290
|
+
} catch {
|
|
15291
|
+
}
|
|
15292
|
+
return false;
|
|
15293
|
+
};
|
|
15193
15294
|
await actionRegistry.register({
|
|
15194
15295
|
id: "core-whiteboard-draw",
|
|
15195
15296
|
commandType: drawWhiteboardCmdType,
|
|
@@ -15213,8 +15314,8 @@ var BuiltinPlugin = {
|
|
|
15213
15314
|
await commandBus.registerHandler(drawWhiteboardCmdType, {
|
|
15214
15315
|
async execute(command) {
|
|
15215
15316
|
const payload = command.payload;
|
|
15216
|
-
if (!
|
|
15217
|
-
const hint = payload.type === "quiz" ? "" : payload.type && (payload.type.includes("quiz") || payload.type.includes("question")) ? ` \u63D0\u793A\uFF1A\u521B\u5EFA\u6D4B\u9A8C\u8BF7\u4F7F\u7528 quiz.create \u6216 quiz_pro.create \u5DE5\u5177\u3002` : ` \u5DF2\u77E5\u7C7B\u578B\uFF1A${KNOWN_ELEMENT_TYPES2.join(", ")}\u3002`;
|
|
15317
|
+
if (!isAllowedElementType(payload.type)) {
|
|
15318
|
+
const hint = payload.type === "quiz" ? "" : payload.type && (payload.type.includes("quiz") || payload.type.includes("question")) ? ` \u63D0\u793A\uFF1A\u521B\u5EFA\u6D4B\u9A8C\u8BF7\u4F7F\u7528 quiz.create \u6216 quiz_pro.create \u5DE5\u5177\u3002` : ` \u5DF2\u77E5\u7C7B\u578B\uFF1A${KNOWN_ELEMENT_TYPES2.join(", ")}\uFF0C\u6216\u63D2\u4EF6\u6269\u5C55\u56FE\u5143 (\u5982 ext-xxx/yyy)\u3002`;
|
|
15218
15319
|
throw new Error(`\u4E0D\u652F\u6301\u7684\u5143\u7D20\u7C7B\u578B "${payload.type}"\u3002${hint}`);
|
|
15219
15320
|
}
|
|
15220
15321
|
const elementId = (0, import_uuid7.v7)();
|
|
@@ -15456,7 +15557,7 @@ var BuiltinPlugin = {
|
|
|
15456
15557
|
);
|
|
15457
15558
|
const batchInsert = db2.transaction(() => {
|
|
15458
15559
|
for (const el of elements) {
|
|
15459
|
-
if (!
|
|
15560
|
+
if (!isAllowedElementType(el.type)) {
|
|
15460
15561
|
throw new Error(`\u4E0D\u652F\u6301\u7684\u5143\u7D20\u7C7B\u578B "${el.type}"\u3002\u5DF2\u77E5\u7C7B\u578B\uFF1A${KNOWN_ELEMENT_TYPES2.join(", ")}`);
|
|
15461
15562
|
}
|
|
15462
15563
|
const elementId = (0, import_uuid7.v7)();
|
|
@@ -18989,6 +19090,19 @@ function trustedInlineAllowlist(env = process.env) {
|
|
|
18989
19090
|
(env.OPENLEARN_TRUSTED_INLINE_PLUGINS ?? "").split(",").map((item) => item.trim()).filter((item) => item.length > 0)
|
|
18990
19091
|
);
|
|
18991
19092
|
}
|
|
19093
|
+
function matchesTrustedInlinePattern(pattern, manifestId) {
|
|
19094
|
+
if (!manifestId) return false;
|
|
19095
|
+
if (pattern === "*") return true;
|
|
19096
|
+
if (pattern.endsWith("*")) return manifestId.startsWith(pattern.slice(0, -1));
|
|
19097
|
+
return pattern === manifestId;
|
|
19098
|
+
}
|
|
19099
|
+
function isInTrustedInlineAllowlist(manifestId, env = process.env) {
|
|
19100
|
+
if (!manifestId) return false;
|
|
19101
|
+
for (const pattern of trustedInlineAllowlist(env)) {
|
|
19102
|
+
if (matchesTrustedInlinePattern(pattern, manifestId)) return true;
|
|
19103
|
+
}
|
|
19104
|
+
return false;
|
|
19105
|
+
}
|
|
18992
19106
|
function builtinPluginsDir() {
|
|
18993
19107
|
try {
|
|
18994
19108
|
const url = import_meta5.url;
|
|
@@ -19011,7 +19125,7 @@ function isInsideBuiltinPluginsDir(sourcePath, builtinDir = builtinPluginsDir())
|
|
|
19011
19125
|
}
|
|
19012
19126
|
function isTrustedInProcessPlugin(manifestId, env = process.env, sourcePath) {
|
|
19013
19127
|
if (isInsideBuiltinPluginsDir(sourcePath)) return true;
|
|
19014
|
-
if (manifestId
|
|
19128
|
+
if (isInTrustedInlineAllowlist(manifestId, env)) return true;
|
|
19015
19129
|
if (env.VITEST && env.OPENLEARN_ENFORCE_PLUGIN_ISOLATION !== "1") return true;
|
|
19016
19130
|
return false;
|
|
19017
19131
|
}
|
|
@@ -20999,7 +21113,7 @@ var import_node_fs11 = __toESM(require("node:fs"), 1);
|
|
|
20999
21113
|
var import_node_path13 = __toESM(require("node:path"), 1);
|
|
21000
21114
|
var import_node_url5 = require("node:url");
|
|
21001
21115
|
var import_meta7 = {};
|
|
21002
|
-
var FALLBACK_VERSION = "0.7.
|
|
21116
|
+
var FALLBACK_VERSION = "0.7.7";
|
|
21003
21117
|
function readPlatformVersion() {
|
|
21004
21118
|
const bases = [];
|
|
21005
21119
|
if (typeof __dirname !== "undefined") bases.push(__dirname);
|
|
@@ -32805,11 +32919,17 @@ function validateStartupEnv(env = process.env) {
|
|
|
32805
32919
|
severity: "warning",
|
|
32806
32920
|
message: "OPENLEARN_TRUSTED_INLINE_PLUGINS \u53EA\u542B\u7A7A\u767D/\u9017\u53F7\uFF0C\u7B49\u540C\u4E8E\u672A\u914D\u7F6E\u3002"
|
|
32807
32921
|
});
|
|
32922
|
+
} else if (ids.includes("*")) {
|
|
32923
|
+
warnings.push({
|
|
32924
|
+
key: "OPENLEARN_TRUSTED_INLINE_PLUGINS",
|
|
32925
|
+
severity: "warning",
|
|
32926
|
+
message: "OPENLEARN_TRUSTED_INLINE_PLUGINS \u542B\u901A\u914D\u7B26 `*`\uFF1A**\u6240\u6709**\u63D2\u4EF6\u90FD\u88AB\u89C6\u4E3A\u53D7\u4FE1\uFF0C\u53EF\u5728\u8FDB\u7A0B\u5185\u4EE5 inline/worker \u8FD0\u884C\uFF08\u542B\u65E5\u540E\u5B89\u88C5\u7684\u4EFB\u610F\u7B2C\u4E09\u65B9\u5305\uFF09\u3002\u5B83\u4EEC\u4E0E\u5BBF\u4E3B\u5171\u4EAB\u73AF\u5883\u53D8\u91CF\u4E0E\u7F51\u7EDC\u6808\uFF0C\u51FA\u7AD9\u7F51\u7EDC\u62E6\u622A\u5BF9\u5B83\u4EEC\u4E0D\u751F\u6548\uFF0C\u672A\u6355\u83B7\u5F02\u5E38\u53EF\u62D6\u57AE\u670D\u52A1\u3002\u4EC5\u9650\u672C\u5730\u5F00\u53D1\uFF1B\u751F\u4EA7\u73AF\u5883\u8BF7\u6539\u4E3A\u7CBE\u786E id \u6216\u524D\u7F00\u5F0F\uFF08\u5982 `@ext/*`\uFF09\u3002"
|
|
32927
|
+
});
|
|
32808
32928
|
} else if (isProduction) {
|
|
32809
32929
|
warnings.push({
|
|
32810
32930
|
key: "OPENLEARN_TRUSTED_INLINE_PLUGINS",
|
|
32811
32931
|
severity: "warning",
|
|
32812
|
-
message: `\u751F\u4EA7\u73AF\u5883\u4FE1\u4EFB\u4E86 ${ids.length} \u4E2A\
|
|
32932
|
+
message: `\u751F\u4EA7\u73AF\u5883\u4FE1\u4EFB\u4E86 ${ids.length} \u4E2A\u6761\u76EE\u5728**\u8FDB\u7A0B\u5185**\u8FD0\u884C\uFF1A${ids.join(", ")}\u3002 \u5B83\u4EEC\u4E0E\u5BBF\u4E3B\u5171\u4EAB\u73AF\u5883\u53D8\u91CF\u4E0E\u7F51\u7EDC\u6808\uFF0C\u51FA\u7AD9\u7F51\u7EDC\u62E6\u622A\u5BF9\u5B83\u4EEC\u4E0D\u751F\u6548\u3002 \u786E\u8BA4\u8FD9\u662F\u6709\u610F\u4E3A\u4E4B\uFF1B\u5426\u5219\u6E05\u7A7A\u8BE5\u53D8\u91CF\u8BA9\u5B83\u4EEC\u56DE\u5230 process \u5B50\u8FDB\u7A0B\u9694\u79BB\u3002`
|
|
32813
32933
|
});
|
|
32814
32934
|
}
|
|
32815
32935
|
}
|
|
@@ -33633,6 +33753,7 @@ var normalizeToolSchema = (schema) => {
|
|
|
33633
33753
|
};
|
|
33634
33754
|
var buildOpenAITools = (callerRole) => {
|
|
33635
33755
|
let actions = kernelContainer.actionRegistry.getAllActions();
|
|
33756
|
+
actions = actions.filter((action) => action.exposeToAgent !== false);
|
|
33636
33757
|
if (callerRole === "student") {
|
|
33637
33758
|
actions = actions.filter((action) => {
|
|
33638
33759
|
const cap = action.capabilityRequired || "";
|
|
@@ -36042,6 +36163,142 @@ post({ type: 'ready' });
|
|
|
36042
36163
|
</script>
|
|
36043
36164
|
</body></html>`;
|
|
36044
36165
|
|
|
36166
|
+
// server/utils/plugin-view-bridge.ts
|
|
36167
|
+
var PLUGIN_VIEW_CSP = "sandbox allow-scripts allow-forms allow-downloads; frame-ancestors 'self'; default-src 'self' 'unsafe-inline' data: blob: https:; script-src 'self' 'unsafe-inline' 'unsafe-eval' data: blob: https:; script-src-attr 'unsafe-inline'; style-src 'self' 'unsafe-inline' data: blob: https:; style-src-attr 'unsafe-inline'; connect-src 'self' blob: data: https:;";
|
|
36168
|
+
var PLUGIN_VIEW_BRIDGE_JS = `(function () {
|
|
36169
|
+
'use strict';
|
|
36170
|
+
const CHANNEL = 'ol-plugin-view';
|
|
36171
|
+
let targetOrigin = '*';
|
|
36172
|
+
const pending = new Map();
|
|
36173
|
+
const initCallbacks = [];
|
|
36174
|
+
const contextUpdateCallbacks = [];
|
|
36175
|
+
let currentContext = null;
|
|
36176
|
+
|
|
36177
|
+
function post(msg) {
|
|
36178
|
+
if (window.parent && window.parent !== window) {
|
|
36179
|
+
window.parent.postMessage(Object.assign({ channel: CHANNEL }, msg), targetOrigin);
|
|
36180
|
+
}
|
|
36181
|
+
}
|
|
36182
|
+
|
|
36183
|
+
function call(op, args) {
|
|
36184
|
+
const callId = Math.random().toString(16).slice(2) + Date.now().toString(16);
|
|
36185
|
+
return new Promise(function (resolve, reject) {
|
|
36186
|
+
pending.set(callId, { resolve: resolve, reject: reject });
|
|
36187
|
+
post({ type: 'call', callId: callId, op: op, args: args || [] });
|
|
36188
|
+
});
|
|
36189
|
+
}
|
|
36190
|
+
|
|
36191
|
+
window.addEventListener('message', function (event) {
|
|
36192
|
+
const data = event.data;
|
|
36193
|
+
if (!data || data.channel !== CHANNEL) return;
|
|
36194
|
+
if (event.source !== window.parent) return;
|
|
36195
|
+
|
|
36196
|
+
if (data.type === 'init') {
|
|
36197
|
+
currentContext = data.payload || {};
|
|
36198
|
+
targetOrigin = event.origin && event.origin !== 'null' ? event.origin : '*';
|
|
36199
|
+
for (let i = 0; i < initCallbacks.length; i++) {
|
|
36200
|
+
try {
|
|
36201
|
+
initCallbacks[i](currentContext);
|
|
36202
|
+
} catch (e) {
|
|
36203
|
+
console.error('[OpenLearnPluginBridge] init callback error:', e);
|
|
36204
|
+
}
|
|
36205
|
+
}
|
|
36206
|
+
return;
|
|
36207
|
+
}
|
|
36208
|
+
|
|
36209
|
+
if (data.type === 'context-update') {
|
|
36210
|
+
currentContext = Object.assign({}, currentContext, data.payload || {});
|
|
36211
|
+
for (let i = 0; i < contextUpdateCallbacks.length; i++) {
|
|
36212
|
+
try {
|
|
36213
|
+
contextUpdateCallbacks[i](currentContext);
|
|
36214
|
+
} catch (e) {
|
|
36215
|
+
console.error('[OpenLearnPluginBridge] contextUpdate callback error:', e);
|
|
36216
|
+
}
|
|
36217
|
+
}
|
|
36218
|
+
return;
|
|
36219
|
+
}
|
|
36220
|
+
|
|
36221
|
+
if (data.type === 'reply') {
|
|
36222
|
+
const waiter = pending.get(data.callId);
|
|
36223
|
+
if (!waiter) return;
|
|
36224
|
+
pending.delete(data.callId);
|
|
36225
|
+
if (data.ok) {
|
|
36226
|
+
waiter.resolve(data.value);
|
|
36227
|
+
} else {
|
|
36228
|
+
waiter.reject(new Error(data.error || 'bridge call failed'));
|
|
36229
|
+
}
|
|
36230
|
+
return;
|
|
36231
|
+
}
|
|
36232
|
+
});
|
|
36233
|
+
|
|
36234
|
+
const bridge = {
|
|
36235
|
+
CHANNEL: CHANNEL,
|
|
36236
|
+
onInit: function (callback) {
|
|
36237
|
+
if (typeof callback === 'function') {
|
|
36238
|
+
if (currentContext) {
|
|
36239
|
+
try {
|
|
36240
|
+
callback(currentContext);
|
|
36241
|
+
} catch (e) {
|
|
36242
|
+
console.error('[OpenLearnPluginBridge] onInit callback error:', e);
|
|
36243
|
+
}
|
|
36244
|
+
}
|
|
36245
|
+
initCallbacks.push(callback);
|
|
36246
|
+
}
|
|
36247
|
+
return bridge;
|
|
36248
|
+
},
|
|
36249
|
+
onContextUpdate: function (callback) {
|
|
36250
|
+
if (typeof callback === 'function') {
|
|
36251
|
+
contextUpdateCallbacks.push(callback);
|
|
36252
|
+
}
|
|
36253
|
+
return bridge;
|
|
36254
|
+
},
|
|
36255
|
+
getContext: function () {
|
|
36256
|
+
return currentContext;
|
|
36257
|
+
},
|
|
36258
|
+
ui: {
|
|
36259
|
+
toast: function (message, type) {
|
|
36260
|
+
return call('ui.toast', [message, type || 'info']);
|
|
36261
|
+
},
|
|
36262
|
+
showToast: function (message, type) {
|
|
36263
|
+
return call('ui.toast', [message, type || 'info']);
|
|
36264
|
+
},
|
|
36265
|
+
resize: function (height) {
|
|
36266
|
+
post({ type: 'resize', height: Number(height) || 0 });
|
|
36267
|
+
},
|
|
36268
|
+
},
|
|
36269
|
+
invokeCommand: function (type, payload) {
|
|
36270
|
+
return call('command.invoke', [type, payload]);
|
|
36271
|
+
},
|
|
36272
|
+
api: {
|
|
36273
|
+
get: function (path) {
|
|
36274
|
+
return call('api.get', [path]);
|
|
36275
|
+
},
|
|
36276
|
+
post: function (path, body) {
|
|
36277
|
+
return call('api.post', [path, body]);
|
|
36278
|
+
},
|
|
36279
|
+
del: function (path) {
|
|
36280
|
+
return call('api.del', [path]);
|
|
36281
|
+
},
|
|
36282
|
+
},
|
|
36283
|
+
storage: {
|
|
36284
|
+
get: function (key) {
|
|
36285
|
+
return call('storage.get', [key]);
|
|
36286
|
+
},
|
|
36287
|
+
set: function (key, value) {
|
|
36288
|
+
return call('storage.set', [key, value]);
|
|
36289
|
+
},
|
|
36290
|
+
delete: function (key) {
|
|
36291
|
+
return call('storage.delete', [key]);
|
|
36292
|
+
},
|
|
36293
|
+
},
|
|
36294
|
+
};
|
|
36295
|
+
|
|
36296
|
+
window.OpenLearnPluginBridge = bridge;
|
|
36297
|
+
// \u901A\u77E5\u5BBF\u4E3B\u89C6\u56FE\u6C99\u7BB1 iframe \u5DF2\u5C31\u7EEA
|
|
36298
|
+
post({ type: 'ready' });
|
|
36299
|
+
})();
|
|
36300
|
+
`;
|
|
36301
|
+
|
|
36045
36302
|
// packages/core/bootstrap/adapter/bootstrap-registration.ts
|
|
36046
36303
|
var BootstrapRegistration = class {
|
|
36047
36304
|
static registerConfiguration(builder, context) {
|
|
@@ -42477,7 +42734,8 @@ async function importCoursePackage(pkg, options) {
|
|
|
42477
42734
|
let elements = [];
|
|
42478
42735
|
try {
|
|
42479
42736
|
elements = pkg.elements.map((element) => {
|
|
42480
|
-
|
|
42737
|
+
const isAllowed = KNOWN_ELEMENT_TYPES.has(element.type) || typeof element.type === "string" && (element.type.includes("/") || element.type.startsWith("plugin:") || element.type.startsWith("ext-") || element.type.startsWith("plugin-"));
|
|
42738
|
+
if (!isAllowed) {
|
|
42481
42739
|
throw new Error(`\u8BFE\u7A0B\u5305\u5305\u542B\u4E0D\u652F\u6301\u7684\u767D\u677F\u5143\u7D20\u7C7B\u578B\uFF1A${element.type}`);
|
|
42482
42740
|
}
|
|
42483
42741
|
const data = resolveAssetPlaceholders(element.data, materialized);
|
|
@@ -49843,7 +50101,9 @@ async function assertCommunityZipAttestation(req, zipPath, targetPluginId) {
|
|
|
49843
50101
|
integrity: verifyRes.integrity
|
|
49844
50102
|
};
|
|
49845
50103
|
}
|
|
49846
|
-
|
|
50104
|
+
const allowUnsignedEnv = String(process.env.OPENLEARN_ALLOW_UNSIGNED ?? "").toLowerCase();
|
|
50105
|
+
const allowUnsignedEffective = allowUnsigned || !["0", "false"].includes(allowUnsignedEnv);
|
|
50106
|
+
if (!allowUnsignedEffective) {
|
|
49847
50107
|
return {
|
|
49848
50108
|
ok: false,
|
|
49849
50109
|
status: 400,
|
|
@@ -50085,6 +50345,25 @@ function registerPluginsRoutes(ctx) {
|
|
|
50085
50345
|
})
|
|
50086
50346
|
);
|
|
50087
50347
|
});
|
|
50348
|
+
app.get("/api/plugins/isolation-policy", requireAuth("administrator"), (req, res) => {
|
|
50349
|
+
const manifestId = String(req.query.manifestId || "").trim();
|
|
50350
|
+
if (!manifestId) {
|
|
50351
|
+
return res.status(400).json({ success: false, error: "manifestId is required" });
|
|
50352
|
+
}
|
|
50353
|
+
const requestedRaw = String(req.query.requestedMode || "").toLowerCase();
|
|
50354
|
+
const requested = isValidExecutionMode(requestedRaw) ? requestedRaw : void 0;
|
|
50355
|
+
const trusted = isTrustedInProcessPlugin(manifestId);
|
|
50356
|
+
const decision = resolvePluginExecutionMode(manifestId, requested);
|
|
50357
|
+
res.json({
|
|
50358
|
+
success: true,
|
|
50359
|
+
manifestId,
|
|
50360
|
+
trusted,
|
|
50361
|
+
requestedMode: requested ?? null,
|
|
50362
|
+
resolvedMode: decision.mode,
|
|
50363
|
+
coerced: decision.coerced,
|
|
50364
|
+
allowlistSize: trustedInlineAllowlist().size
|
|
50365
|
+
});
|
|
50366
|
+
});
|
|
50088
50367
|
app.get("/api/plugins/by-manifest/:manifestId(*)", requireScopedAuth("authenticated"), (req, res) => {
|
|
50089
50368
|
try {
|
|
50090
50369
|
const manifestId = decodeURIComponent(req.params.manifestId);
|
|
@@ -50101,7 +50380,12 @@ function registerPluginsRoutes(ctx) {
|
|
|
50101
50380
|
status: found.status,
|
|
50102
50381
|
state: found.state,
|
|
50103
50382
|
manifest: found.manifest,
|
|
50104
|
-
isSystem: kernelContainer.pluginHost.isOfficialPlugin(found.pluginId, manifestId)
|
|
50383
|
+
isSystem: kernelContainer.pluginHost.isOfficialPlugin(found.pluginId, manifestId),
|
|
50384
|
+
// 升级路径的回填:按库里存的请求值 + 当前信任策略算出**实际会用的**档位。
|
|
50385
|
+
isolationMode: resolvePluginExecutionMode(
|
|
50386
|
+
manifestId,
|
|
50387
|
+
kernelContainer.db.prepare("SELECT execution_mode FROM plugins WHERE id = ?").get(found.pluginId)?.execution_mode
|
|
50388
|
+
).mode
|
|
50105
50389
|
});
|
|
50106
50390
|
} catch (e) {
|
|
50107
50391
|
sendSafeError(res, e);
|
|
@@ -57704,18 +57988,35 @@ async function startServer() {
|
|
|
57704
57988
|
app.use(
|
|
57705
57989
|
"/plugins",
|
|
57706
57990
|
(req, res, next) => {
|
|
57707
|
-
const token = getCookieToken(req);
|
|
57708
|
-
if (
|
|
57709
|
-
|
|
57991
|
+
const token = getCookieToken(req) || (typeof req.query.token === "string" ? req.query.token : null) || (req.headers.authorization?.startsWith("Bearer ") ? req.headers.authorization.slice(7).trim() : null);
|
|
57992
|
+
if (token) {
|
|
57993
|
+
const session = getValidSession(token);
|
|
57994
|
+
if (session) {
|
|
57995
|
+
return next();
|
|
57996
|
+
}
|
|
57710
57997
|
}
|
|
57711
|
-
const
|
|
57712
|
-
|
|
57713
|
-
|
|
57998
|
+
const dest = req.headers["sec-fetch-dest"];
|
|
57999
|
+
const site = req.headers["sec-fetch-site"];
|
|
58000
|
+
if (site === "same-origin" || typeof dest === "string" && dest !== "" && dest !== "document") {
|
|
58001
|
+
return next();
|
|
57714
58002
|
}
|
|
57715
|
-
|
|
58003
|
+
return res.status(401).json({ error: "Authentication required" });
|
|
57716
58004
|
},
|
|
57717
|
-
import_express4.default.static(getPluginsDir(), {
|
|
58005
|
+
import_express4.default.static(getPluginsDir(), {
|
|
58006
|
+
index: false,
|
|
58007
|
+
dotfiles: "ignore",
|
|
58008
|
+
fallthrough: false,
|
|
58009
|
+
maxAge: 0,
|
|
58010
|
+
setHeaders: (res, filePath) => {
|
|
58011
|
+
if (filePath.endsWith(".html") || filePath.endsWith(".htm")) {
|
|
58012
|
+
res.setHeader("Content-Security-Policy", PLUGIN_VIEW_CSP);
|
|
58013
|
+
}
|
|
58014
|
+
}
|
|
58015
|
+
})
|
|
57718
58016
|
);
|
|
58017
|
+
app.get("/plugin-sandbox/view-bridge.js", (_req, res) => {
|
|
58018
|
+
res.status(200).setHeader("Content-Type", "application/javascript; charset=utf-8").setHeader("Cache-Control", "public, max-age=3600").send(PLUGIN_VIEW_BRIDGE_JS);
|
|
58019
|
+
});
|
|
57719
58020
|
app.get("/plugin-sandbox/frame", (req, res) => {
|
|
57720
58021
|
const token = getCookieToken(req);
|
|
57721
58022
|
const session = token ? getValidSession(token) : null;
|