openlearn-next 0.7.12 → 0.7.13

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.
Files changed (54) hide show
  1. package/dist/assets/{ActivityWorkspaceWidget-TtBuNORs.js → ActivityWorkspaceWidget-9DeXkxGk.js} +1 -1
  2. package/dist/assets/{AdminDirectoryView-D03WOMc-.js → AdminDirectoryView-5gupeGAR.js} +1 -1
  3. package/dist/assets/{AssessmentCenter-MUvoJySb.js → AssessmentCenter-CPaqy0Xa.js} +1 -1
  4. package/dist/assets/{AssignmentFilePreview-dVhnTYmq.js → AssignmentFilePreview-7fHtUuUL.js} +2 -2
  5. package/dist/assets/{BatchPickerModal-QALdhrX6.js → BatchPickerModal-0yIe1DXi.js} +1 -1
  6. package/dist/assets/{ClassesView-CKwlRz-A.js → ClassesView-CGpoW0IC.js} +1 -1
  7. package/dist/assets/{ClassroomCountdownWidget-DyWyForY.js → ClassroomCountdownWidget-B_5--dn_.js} +1 -1
  8. package/dist/assets/{CloudDriveModal-C8UAn3MO.js → CloudDriveModal-4Ts5Duh5.js} +1 -1
  9. package/dist/assets/{ComputerLabView-E5b3XTkk.js → ComputerLabView-DAEaKTBj.js} +1 -1
  10. package/dist/assets/{CourseManagement-3jSlq7lV.js → CourseManagement-CxIBH7lA.js} +1 -1
  11. package/dist/assets/{CourseWizardModal-BAkW5VJX.js → CourseWizardModal-R0xpa_Aw.js} +1 -1
  12. package/dist/assets/{CoursewareHubPanel-BkjcusjZ.js → CoursewareHubPanel-CpHptmSa.js} +1 -1
  13. package/dist/assets/{Dashboard-Ha2fZAqD.js → Dashboard-DeBfP_Nc.js} +1 -1
  14. package/dist/assets/{ExportWeightModal-D2Y13384.js → ExportWeightModal-DlnCOBlL.js} +1 -1
  15. package/dist/assets/{HelpTour-DBq2otcV.js → HelpTour-Cztpqw_J.js} +1 -1
  16. package/dist/assets/{HelpView-BVLRnMxl.js → HelpView-LPLAY9bq.js} +3 -3
  17. package/dist/assets/{ImportLessonsModal-CQlq4b81.js → ImportLessonsModal-BopEHmU_.js} +1 -1
  18. package/dist/assets/{ImportModal-Ct0I5cAL.js → ImportModal-CYU3aMYY.js} +1 -1
  19. package/dist/assets/{InteractiveCoursewareViewer-DGKh1gO8.js → InteractiveCoursewareViewer-CGc3P4HF.js} +1 -1
  20. package/dist/assets/InteractiveWhiteboard-DiyHrIGn.js +19 -0
  21. package/dist/assets/{LazyCourseware-zONqinCM.js → LazyCourseware-Bj1jm0nC.js} +2 -2
  22. package/dist/assets/LazyWhiteboard-NPD1EoyO.js +2 -0
  23. package/dist/assets/LessonEditorView-DqreBtFx.js +1 -0
  24. package/dist/assets/{LiveClassroomView-TaHtHWkY.js → LiveClassroomView-eTc6Fb9g.js} +11 -10
  25. package/dist/assets/{NotificationDetailModal-BF_-pn0c.js → NotificationDetailModal-B7G7ra9a.js} +1 -1
  26. package/dist/assets/{PluginView-sVMPXae9.js → PluginView-DP6s-L70.js} +1 -1
  27. package/dist/assets/{ProcessLogsModal-D97xLgnL.js → ProcessLogsModal-Dq5C4s7j.js} +1 -1
  28. package/dist/assets/{QuizGeneratorModal-CNY8ISjR.js → QuizGeneratorModal-CoX9f8Wp.js} +1 -1
  29. package/dist/assets/RevealPresentationWrapper-wwlcfNWB.js +48 -0
  30. package/dist/assets/{StudentAssignmentEvalPanel-CUmM5DbT.js → StudentAssignmentEvalPanel-DHb-asHQ.js} +1 -1
  31. package/dist/assets/{StudentAssignmentView-B-1MtwKj.js → StudentAssignmentView-AJpjQK3f.js} +1 -1
  32. package/dist/assets/{StudentLessonView-CqrcvVND.js → StudentLessonView-Djd1T1QF.js} +1 -1
  33. package/dist/assets/{StudentView-Bi9kgSrN.js → StudentView-D41z7GY5.js} +2 -2
  34. package/dist/assets/{SystemResourceLibraryModal-DDALKrJC.js → SystemResourceLibraryModal-CxmQh1HA.js} +1 -1
  35. package/dist/assets/TeacherView-DqSWaNuI.js +2 -0
  36. package/dist/assets/{TimetableView-BOLB-kZC.js → TimetableView-DrFs_xgc.js} +1 -1
  37. package/dist/assets/{UTIF-BtQhea94.js → UTIF-u3Ct70K4.js} +1 -1
  38. package/dist/assets/{index-Bc9003lB.js → index-7CK1B0tE.js} +28 -28
  39. package/dist/assets/index-BaGZmpr6.css +1 -0
  40. package/dist/assets/{index.es-CijVATXs.js → index.es-CcQ2kcDj.js} +1 -1
  41. package/dist/assets/{pluginParsers-DD3QL1Xl.js → pluginParsers-BN3lQ7PJ.js} +1 -1
  42. package/dist/assets/{student-workspace-C4UgD58C.js → student-workspace-DkTkcAGK.js} +1 -1
  43. package/dist/assets/{vendor-icons-CaXLq01o.js → vendor-icons-CqLdl4B_.js} +1 -1
  44. package/dist/assets/{vendor-pdf-DVWGghIL.js → vendor-pdf-BMEc_Clb.js} +3 -3
  45. package/dist/assets/{vendor-pptx-BqU7v5zS.js → vendor-pptx-C0qaOH5T.js} +178 -178
  46. package/dist/index.html +3 -3
  47. package/dist/server.cjs +732 -1109
  48. package/package.json +2 -1
  49. package/dist/assets/InteractiveWhiteboard-BbZlYpRu.js +0 -65
  50. package/dist/assets/LazyWhiteboard-BV98LEZ8.js +0 -2
  51. package/dist/assets/LessonEditorView-LXRkKxdY.js +0 -1
  52. package/dist/assets/TeacherView-C5JmoKHk.js +0 -2
  53. package/dist/assets/index-D4aq9poS.css +0 -1
  54. package/dist/assets/vendor-reveal-DcQQzuI9.css +0 -1
package/dist/server.cjs CHANGED
@@ -21290,7 +21290,7 @@ var import_node_fs11 = __toESM(require("node:fs"), 1);
21290
21290
  var import_node_path13 = __toESM(require("node:path"), 1);
21291
21291
  var import_node_url5 = require("node:url");
21292
21292
  var import_meta7 = {};
21293
- var FALLBACK_VERSION = "0.7.12";
21293
+ var FALLBACK_VERSION = "0.7.13";
21294
21294
  function readPlatformVersion() {
21295
21295
  const bases = [];
21296
21296
  if (typeof __dirname !== "undefined") bases.push(__dirname);
@@ -29983,924 +29983,6 @@ var ServiceRegistryKernel = class {
29983
29983
  }
29984
29984
  };
29985
29985
 
29986
- // packages/core/bootstrap/composition/composition-validator.ts
29987
- var CompositionValidator = class {
29988
- static validate(options, pipeline, modules) {
29989
- const errors = [];
29990
- const warnings = [];
29991
- if (options.config && options.config.port !== void 0) {
29992
- if (options.config.port <= 0 || options.config.port > 65535) {
29993
- errors.push({
29994
- code: "INVALID_PORT",
29995
- message: `Port must be a valid number between 1 and 65535. Received: ${options.config.port}`,
29996
- target: "config.port"
29997
- });
29998
- }
29999
- }
30000
- if (!pipeline || pipeline.stages.length === 0) {
30001
- errors.push({
30002
- code: "EMPTY_PIPELINE",
30003
- message: "Bootstrap pipeline is missing or contains zero stages.",
30004
- target: "pipeline"
30005
- });
30006
- }
30007
- const moduleIds = /* @__PURE__ */ new Set();
30008
- for (const mod of modules) {
30009
- if (!mod.id) {
30010
- errors.push({
30011
- code: "INVALID_MODULE",
30012
- message: `Module '${mod.name}' has no unique ID.`,
30013
- target: "module.id"
30014
- });
30015
- } else if (moduleIds.has(mod.id)) {
30016
- errors.push({
30017
- code: "DUPLICATE_MODULE",
30018
- message: `Duplicate composition module detected: '${mod.id}'.`,
30019
- target: "module.id"
30020
- });
30021
- } else {
30022
- moduleIds.add(mod.id);
30023
- }
30024
- }
30025
- return {
30026
- isValid: errors.length === 0,
30027
- errors: Object.freeze(errors),
30028
- warnings: Object.freeze(warnings)
30029
- };
30030
- }
30031
- };
30032
-
30033
- // packages/core/bootstrap/builder/builder-validation-engine.ts
30034
- var BuilderValidationEngine = class {
30035
- static validate(config, environment, stages) {
30036
- const errors = [];
30037
- const warnings = [];
30038
- if (!["development", "production", "test"].includes(environment)) {
30039
- errors.push({
30040
- code: "INVALID_ENVIRONMENT",
30041
- message: `Environment must be one of 'development', 'production', 'test'. Received: '${environment}'`,
30042
- field: "environment"
30043
- });
30044
- }
30045
- if (!config.port || config.port <= 0 || config.port > 65535) {
30046
- errors.push({
30047
- code: "INVALID_PORT",
30048
- message: `Port must be a valid number between 1 and 65535. Received: ${config.port}`,
30049
- field: "port"
30050
- });
30051
- }
30052
- if (!stages || stages.length === 0) {
30053
- errors.push({
30054
- code: "MISSING_STAGES",
30055
- message: "Bootstrap pipeline contains no registered stages.",
30056
- field: "stages"
30057
- });
30058
- } else {
30059
- const stageIds = /* @__PURE__ */ new Set();
30060
- for (const stage of stages) {
30061
- if (!stage.id) {
30062
- errors.push({
30063
- code: "INVALID_STAGE",
30064
- message: `Stage '${stage.name}' has no unique ID.`
30065
- });
30066
- } else if (stageIds.has(stage.id)) {
30067
- errors.push({
30068
- code: "DUPLICATE_STAGE",
30069
- message: `Duplicate stage registration detected for stage ID '${stage.id}'.`,
30070
- field: "stage.id"
30071
- });
30072
- } else {
30073
- stageIds.add(stage.id);
30074
- }
30075
- }
30076
- }
30077
- return {
30078
- isValid: errors.length === 0,
30079
- errors: Object.freeze(errors),
30080
- warnings: Object.freeze(warnings)
30081
- };
30082
- }
30083
- };
30084
-
30085
- // packages/core/bootstrap/types/index.ts
30086
- var PlatformBootstrapError = class extends Error {
30087
- constructor(message, stage, cause) {
30088
- super(`[PlatformBootstrapError${stage ? `:${stage}` : ""}] ${message}`);
30089
- this.stage = stage;
30090
- this.cause = cause;
30091
- this.name = "PlatformBootstrapError";
30092
- }
30093
- };
30094
- var ConfigurationError = class extends PlatformBootstrapError {
30095
- constructor(message, cause) {
30096
- super(message, "Configuring" /* Configuring */, cause);
30097
- this.name = "ConfigurationError";
30098
- }
30099
- };
30100
- var StartupTimeoutError = class extends PlatformBootstrapError {
30101
- constructor(message, stage, cause) {
30102
- super(message, stage, cause);
30103
- this.name = "StartupTimeoutError";
30104
- }
30105
- };
30106
- var PLATFORM_VERSION2 = PLATFORM_VERSION;
30107
- var BOOTSTRAP_STAGE_NAMES = Object.freeze([
30108
- "Created" /* Created */,
30109
- "Configuring" /* Configuring */,
30110
- "Registering" /* Registering */,
30111
- "Initializing" /* Initializing */,
30112
- "Activating" /* Activating */,
30113
- "Ready" /* Ready */,
30114
- "ShuttingDown" /* ShuttingDown */,
30115
- "Disposed" /* Disposed */
30116
- ]);
30117
- var DEFAULT_BOOTSTRAP_CONFIG = Object.freeze({
30118
- environment: "development",
30119
- mode: "standalone",
30120
- port: 9e3,
30121
- debug: false,
30122
- pluginsDir: "./plugins",
30123
- dbPath: "./packages/core/db/educational_os.db"
30124
- });
30125
-
30126
- // packages/core/bootstrap/pipeline/pipeline-executor.ts
30127
- var PipelineExecutor = class {
30128
- constructor() {
30129
- this.listeners = /* @__PURE__ */ new Set();
30130
- }
30131
- addListener(listener) {
30132
- this.listeners.add(listener);
30133
- return () => {
30134
- this.listeners.delete(listener);
30135
- };
30136
- }
30137
- emit(event) {
30138
- for (const listener of Array.from(this.listeners)) {
30139
- try {
30140
- listener(event);
30141
- } catch (err) {
30142
- console.error("[PipelineExecutor] Listener error:", err);
30143
- }
30144
- }
30145
- }
30146
- async execute(stages, context) {
30147
- const startTime = Date.now();
30148
- const results = [];
30149
- const executedStages = [];
30150
- this.emit({ type: "PipelineStarted", timestamp: startTime });
30151
- console.log("[Platform] Starting Bootstrap Pipeline execution...");
30152
- for (const stage of stages) {
30153
- if (context.isCancelled) {
30154
- console.warn(`[Platform] Pipeline cancelled before stage ${stage.name}`);
30155
- const totalDurationMs2 = Date.now() - startTime;
30156
- return {
30157
- totalDurationMs: totalDurationMs2,
30158
- status: "Aborted",
30159
- stageResults: Object.freeze(results)
30160
- };
30161
- }
30162
- console.log(`[Platform] Entering ${stage.name}`);
30163
- this.emit({
30164
- type: "StageStarted",
30165
- timestamp: Date.now(),
30166
- stageId: stage.id,
30167
- stageName: String(stage.name)
30168
- });
30169
- const stageStart = Date.now();
30170
- try {
30171
- if (stage.timeoutMs && stage.timeoutMs > 0) {
30172
- await this.executeWithTimeout(stage, context, stage.timeoutMs);
30173
- } else {
30174
- await stage.execute(context);
30175
- }
30176
- const durationMs = Date.now() - stageStart;
30177
- console.log(`[Platform] Completed ${stage.name} (${durationMs} ms)`);
30178
- results.push({
30179
- stageId: stage.id,
30180
- stageName: String(stage.name),
30181
- durationMs,
30182
- status: "Success"
30183
- });
30184
- executedStages.push(stage);
30185
- this.emit({
30186
- type: "StageCompleted",
30187
- timestamp: Date.now(),
30188
- stageId: stage.id,
30189
- stageName: String(stage.name),
30190
- durationMs
30191
- });
30192
- } catch (err) {
30193
- const error = err instanceof Error ? err : new Error(String(err));
30194
- const durationMs = Date.now() - stageStart;
30195
- console.error(`[Platform] Failed ${stage.name} (${durationMs} ms): ${error.message}`);
30196
- results.push({
30197
- stageId: stage.id,
30198
- stageName: String(stage.name),
30199
- durationMs,
30200
- status: "Failed",
30201
- error
30202
- });
30203
- this.emit({
30204
- type: "StageFailed",
30205
- timestamp: Date.now(),
30206
- stageId: stage.id,
30207
- stageName: String(stage.name),
30208
- durationMs,
30209
- error
30210
- });
30211
- await this.rollbackExecutedStages(executedStages, context);
30212
- const totalDurationMs2 = Date.now() - startTime;
30213
- const pipelineResult = {
30214
- totalDurationMs: totalDurationMs2,
30215
- status: "Failed",
30216
- stageResults: Object.freeze(results),
30217
- failedStage: stage.id,
30218
- error
30219
- };
30220
- this.emit({
30221
- type: "PipelineCompleted",
30222
- timestamp: Date.now(),
30223
- durationMs: totalDurationMs2,
30224
- error
30225
- });
30226
- return pipelineResult;
30227
- }
30228
- }
30229
- const totalDurationMs = Date.now() - startTime;
30230
- console.log(`[Platform] Ready. Total startup duration: ${totalDurationMs} ms.`);
30231
- const finalResult = {
30232
- totalDurationMs,
30233
- status: "Success",
30234
- stageResults: Object.freeze(results)
30235
- };
30236
- this.emit({
30237
- type: "PipelineCompleted",
30238
- timestamp: Date.now(),
30239
- durationMs: totalDurationMs
30240
- });
30241
- return finalResult;
30242
- }
30243
- async executeWithTimeout(stage, context, timeoutMs) {
30244
- let timer;
30245
- const timeoutPromise = new Promise((_, reject) => {
30246
- timer = setTimeout(() => {
30247
- reject(new StartupTimeoutError(`Stage execution timed out after ${timeoutMs} ms`));
30248
- }, timeoutMs);
30249
- });
30250
- try {
30251
- await Promise.race([stage.execute(context), timeoutPromise]);
30252
- } finally {
30253
- if (timer) {
30254
- clearTimeout(timer);
30255
- }
30256
- }
30257
- }
30258
- async rollbackExecutedStages(executedStages, context) {
30259
- console.log("[Platform] Triggering stage rollbacks...");
30260
- for (let i = executedStages.length - 1; i >= 0; i--) {
30261
- const stage = executedStages[i];
30262
- if (stage.rollback) {
30263
- try {
30264
- console.log(`[Platform] Rolling back ${stage.name}`);
30265
- await stage.rollback(context);
30266
- } catch (rbErr) {
30267
- console.error(`[Platform] Error during rollback of ${stage.name}:`, rbErr);
30268
- }
30269
- }
30270
- }
30271
- }
30272
- };
30273
-
30274
- // packages/core/bootstrap/pipeline/stages/standard-stages.ts
30275
- var StartupStageImpl = class {
30276
- constructor() {
30277
- this.id = "stage_startup";
30278
- this.name = "Created" /* Created */;
30279
- this.description = "Environment & configuration validation";
30280
- }
30281
- async execute(context) {
30282
- context.setStage("Configuring" /* Configuring */);
30283
- }
30284
- };
30285
- var RegistrationStageImpl = class {
30286
- constructor() {
30287
- this.id = "stage_registration";
30288
- this.name = "Registering" /* Registering */;
30289
- this.description = "Core Service Contracts & DI Tokens registration";
30290
- }
30291
- async execute(context) {
30292
- context.setStage("Registering" /* Registering */);
30293
- }
30294
- };
30295
- var InitializationStageImpl = class {
30296
- constructor() {
30297
- this.id = "stage_initialization";
30298
- this.name = "Initializing" /* Initializing */;
30299
- this.description = "Subsystem Kernels initialization";
30300
- }
30301
- async execute(context) {
30302
- context.setStage("Initializing" /* Initializing */);
30303
- }
30304
- };
30305
- var ActivationStageImpl = class {
30306
- constructor() {
30307
- this.id = "stage_activation";
30308
- this.name = "Activating" /* Activating */;
30309
- this.description = "Plugin Host discovery & ESM plugins activation";
30310
- }
30311
- async execute(context) {
30312
- context.setStage("Activating" /* Activating */);
30313
- }
30314
- };
30315
- var ReadyStageImpl = class {
30316
- constructor() {
30317
- this.id = "stage_ready";
30318
- this.name = "Ready" /* Ready */;
30319
- this.description = "HTTP & Socket.IO server readiness";
30320
- }
30321
- async execute(context) {
30322
- context.setStage("Ready" /* Ready */);
30323
- }
30324
- };
30325
-
30326
- // packages/core/bootstrap/pipeline/bootstrap-pipeline.ts
30327
- var BootstrapPipeline = class {
30328
- constructor(stages) {
30329
- this._stages = [];
30330
- this.executor = new PipelineExecutor();
30331
- if (stages && stages.length > 0) {
30332
- this._stages = [...stages];
30333
- } else {
30334
- this._stages = [
30335
- new StartupStageImpl(),
30336
- new RegistrationStageImpl(),
30337
- new InitializationStageImpl(),
30338
- new ActivationStageImpl(),
30339
- new ReadyStageImpl()
30340
- ];
30341
- }
30342
- }
30343
- get stages() {
30344
- return Object.freeze(this._stages);
30345
- }
30346
- addStage(stage) {
30347
- this._stages.push(stage);
30348
- return this;
30349
- }
30350
- addListener(listener) {
30351
- return this.executor.addListener(listener);
30352
- }
30353
- async run(context) {
30354
- const result = await this.execute(context);
30355
- if (result.status === "Failed") {
30356
- throw result.error || new Error(`Bootstrap Pipeline failed at stage: ${result.failedStage}`);
30357
- }
30358
- }
30359
- async execute(context) {
30360
- return this.executor.execute(this._stages, context);
30361
- }
30362
- };
30363
-
30364
- // packages/core/bootstrap/builder/platform-builder.ts
30365
- var DefaultPlatformLogger = class {
30366
- info(message, ...args) {
30367
- console.log(`[PlatformBuilder:INFO] ${message}`, ...args);
30368
- }
30369
- warn(message, ...args) {
30370
- console.warn(`[PlatformBuilder:WARN] ${message}`, ...args);
30371
- }
30372
- error(message, ...args) {
30373
- console.error(`[PlatformBuilder:ERROR] ${message}`, ...args);
30374
- }
30375
- debug(message, ...args) {
30376
- console.debug(`[PlatformBuilder:DEBUG] ${message}`, ...args);
30377
- }
30378
- };
30379
- var PlatformBuilder = class _PlatformBuilder {
30380
- constructor(options) {
30381
- this._state = "Created";
30382
- this._config = { ...DEFAULT_BOOTSTRAP_CONFIG };
30383
- this._logger = new DefaultPlatformLogger();
30384
- this._environment = "development";
30385
- this._metadata = /* @__PURE__ */ new Map();
30386
- this._services = /* @__PURE__ */ new Map();
30387
- this._capabilities = /* @__PURE__ */ new Map();
30388
- this._extensions = /* @__PURE__ */ new Map();
30389
- this._pipeline = new BootstrapPipeline();
30390
- this._state = "Created";
30391
- this._logger.info("Builder Started");
30392
- if (options) {
30393
- if (options.config) this.withConfiguration(options.config);
30394
- if (options.logger) this.withLogger(options.logger);
30395
- if (options.environment) this.withEnvironment(options.environment);
30396
- if (options.metadata) {
30397
- for (const [k, v] of Object.entries(options.metadata)) {
30398
- this.withMetadata(k, v);
30399
- }
30400
- }
30401
- }
30402
- }
30403
- static create(options) {
30404
- return new _PlatformBuilder(options);
30405
- }
30406
- get state() {
30407
- return this._state;
30408
- }
30409
- transitionTo(newState) {
30410
- if (this._state === "Disposed") {
30411
- throw new Error("PlatformBuilder has been disposed and cannot accept further transitions.");
30412
- }
30413
- if (this._state === "Built" && newState !== "Disposed") {
30414
- throw new Error(`Invalid state transition from Built to ${newState}. Builder is already built.`);
30415
- }
30416
- this._state = newState;
30417
- }
30418
- withConfiguration(config) {
30419
- this.transitionTo("Configuring");
30420
- this._config = { ...this._config, ...config };
30421
- if (config.environment) {
30422
- this._environment = config.environment;
30423
- }
30424
- this._logger.info("Configuration Loaded");
30425
- return this;
30426
- }
30427
- withLogger(logger2) {
30428
- this.transitionTo("Configuring");
30429
- this._logger = logger2;
30430
- return this;
30431
- }
30432
- withEnvironment(env) {
30433
- this.transitionTo("Configuring");
30434
- this._environment = env;
30435
- this._config = { ...this._config, environment: env };
30436
- return this;
30437
- }
30438
- withMetadata(key, value) {
30439
- this.transitionTo("Configuring");
30440
- this._metadata.set(key, value);
30441
- return this;
30442
- }
30443
- addBootstrapStage(stage) {
30444
- this.transitionTo("Configuring");
30445
- this._pipeline.addStage(stage);
30446
- return this;
30447
- }
30448
- addService(serviceId, instance) {
30449
- this.transitionTo("Configuring");
30450
- this._services.set(serviceId, instance);
30451
- return this;
30452
- }
30453
- addCapability(capabilityId, descriptor) {
30454
- this.transitionTo("Configuring");
30455
- this._capabilities.set(capabilityId, descriptor);
30456
- return this;
30457
- }
30458
- addExtension(extensionId, extensionSpec) {
30459
- this.transitionTo("Configuring");
30460
- this._extensions.set(extensionId, extensionSpec);
30461
- return this;
30462
- }
30463
- buildResult() {
30464
- const buildStart = Date.now();
30465
- this.transitionTo("Validating");
30466
- this._logger.info("Validation Started");
30467
- const validation = BuilderValidationEngine.validate(this._config, this._environment, this._pipeline.stages);
30468
- this._logger.info("Validation Completed");
30469
- if (!validation.isValid) {
30470
- this._logger.error(`Validation Failed with ${validation.errors.length} errors.`);
30471
- throw new ConfigurationError(
30472
- `PlatformBuilder validation failed: ${validation.errors.map((e) => e.message).join("; ")}`
30473
- );
30474
- }
30475
- this.transitionTo("Building");
30476
- this._logger.info("Build Started");
30477
- const platformContext = {
30478
- platformId: `plt_${globalThis.crypto.randomUUID()}`,
30479
- version: PLATFORM_VERSION2,
30480
- namespace: "openlearn.core",
30481
- mode: this._config.mode,
30482
- environment: {
30483
- type: this._environment,
30484
- isDevelopment: this._environment === "development",
30485
- isProduction: this._environment === "production",
30486
- isTest: this._environment === "test",
30487
- isPluginSandbox: false
30488
- },
30489
- config: this._config,
30490
- featureFlags: {
30491
- isEnabled: () => true,
30492
- getFlag: (_, def) => def,
30493
- getAllFlags: () => ({})
30494
- },
30495
- runtimeMetadata: {
30496
- os: process.platform,
30497
- nodeVersion: process.version,
30498
- arch: process.arch,
30499
- processId: process.pid,
30500
- memoryUsage: process.memoryUsage(),
30501
- buildVersion: PLATFORM_VERSION2
30502
- },
30503
- bootstrapState: "Bootstrapping",
30504
- logger: this._logger,
30505
- diagnostics: {
30506
- getMetrics: () => ({ uptime: 0 }),
30507
- getSystemStatus: () => ({ isHealthy: true, activeServicesCount: this._services.size, uptimeSeconds: 0 })
30508
- },
30509
- serviceLocator: {
30510
- hasService: (id) => this._services.has(id),
30511
- getService: (id) => this._services.get(id)
30512
- },
30513
- capabilityCatalog: {
30514
- hasCapability: (id) => this._capabilities.has(id),
30515
- getCapability: (id) => this._capabilities.get(id)
30516
- },
30517
- extensionCatalog: {
30518
- hasExtension: (id) => this._extensions.has(id),
30519
- getExtension: (id) => this._extensions.get(id)
30520
- },
30521
- eventDispatcher: {
30522
- dispatch: async () => {
30523
- }
30524
- },
30525
- shutdownToken: {
30526
- isRequested: false,
30527
- onShutdown: () => {
30528
- }
30529
- }
30530
- };
30531
- const buildDurationMs = Date.now() - buildStart;
30532
- this.transitionTo("Built");
30533
- this._logger.info(`Build Completed in ${buildDurationMs} ms`);
30534
- const result = {
30535
- platformContext,
30536
- pipeline: this._pipeline,
30537
- buildDurationMs,
30538
- validation,
30539
- metadata: Object.fromEntries(this._metadata.entries()),
30540
- builderVersion: PLATFORM_VERSION2
30541
- };
30542
- return result;
30543
- }
30544
- async build() {
30545
- const res = this.buildResult();
30546
- return {
30547
- currentStage: "Created" /* Created */,
30548
- context: res.platformContext,
30549
- pipeline: res.pipeline,
30550
- start: async () => {
30551
- },
30552
- shutdown: async () => {
30553
- },
30554
- dispose: async () => {
30555
- }
30556
- };
30557
- }
30558
- async start() {
30559
- const kernel = await this.build();
30560
- await kernel.start();
30561
- return kernel;
30562
- }
30563
- async shutdown() {
30564
- this.transitionTo("Disposed");
30565
- }
30566
- dispose() {
30567
- this._state = "Disposed";
30568
- this._services.clear();
30569
- this._capabilities.clear();
30570
- this._extensions.clear();
30571
- this._metadata.clear();
30572
- }
30573
- };
30574
-
30575
- // packages/core/bootstrap/composition/platform-composition-root.ts
30576
- var PlatformCompositionRoot = class _PlatformCompositionRoot {
30577
- constructor() {
30578
- this._state = "Created";
30579
- this._modules = [];
30580
- this._state = "Created";
30581
- }
30582
- static create() {
30583
- return new _PlatformCompositionRoot();
30584
- }
30585
- get state() {
30586
- return this._state;
30587
- }
30588
- registerModule(module2) {
30589
- if (this._state === "Disposed" || this._state === "Composed") {
30590
- throw new Error(`Cannot register composition module in state: ${this._state}`);
30591
- }
30592
- this._modules.push(module2);
30593
- return this;
30594
- }
30595
- compose(options) {
30596
- const startTime = Date.now();
30597
- this._state = "Validating";
30598
- const opts = options || {};
30599
- const builder = PlatformBuilder.create();
30600
- if (opts.config) builder.withConfiguration(opts.config);
30601
- if (opts.logger) builder.withLogger(opts.logger);
30602
- if (opts.environment) builder.withEnvironment(opts.environment);
30603
- const builderResult = builder.buildResult();
30604
- const validation = CompositionValidator.validate(opts, builderResult.pipeline, this._modules);
30605
- if (!validation.isValid) {
30606
- throw new ConfigurationError(
30607
- `CompositionRoot validation failed: ${validation.errors.map((e) => e.message).join("; ")}`
30608
- );
30609
- }
30610
- this._state = "Composing";
30611
- for (const mod of this._modules) {
30612
- mod.compose(opts);
30613
- }
30614
- const durationMs = Date.now() - startTime;
30615
- this._state = "Composed";
30616
- return {
30617
- context: builderResult.platformContext,
30618
- pipeline: builderResult.pipeline,
30619
- durationMs,
30620
- validation
30621
- };
30622
- }
30623
- dispose() {
30624
- this._state = "Disposed";
30625
- this._modules = [];
30626
- }
30627
- };
30628
-
30629
- // packages/core/bootstrap/permission/permission-registry.ts
30630
- var PermissionRegistry = class {
30631
- constructor() {
30632
- this.descriptors = /* @__PURE__ */ new Map();
30633
- }
30634
- register(descriptor) {
30635
- if (!descriptor || !descriptor.id) {
30636
- throw new Error("PermissionRegistry Error: PermissionDescriptor must have a valid ID.");
30637
- }
30638
- if (this.descriptors.has(descriptor.id)) {
30639
- throw new Error(`PermissionRegistry Collision: Permission '${descriptor.id}' is already registered.`);
30640
- }
30641
- this.descriptors.set(descriptor.id, Object.freeze({ ...descriptor }));
30642
- }
30643
- unregister(permissionId) {
30644
- return this.descriptors.delete(permissionId);
30645
- }
30646
- get(permissionId) {
30647
- return this.descriptors.get(permissionId);
30648
- }
30649
- exists(permissionId) {
30650
- return this.descriptors.has(permissionId);
30651
- }
30652
- list() {
30653
- return Object.freeze(Array.from(this.descriptors.values()));
30654
- }
30655
- clear() {
30656
- this.descriptors.clear();
30657
- }
30658
- };
30659
-
30660
- // packages/core/bootstrap/permission/permission-evaluator.ts
30661
- var PermissionEvaluator = class {
30662
- static async evaluate(subject, permission, explicitGrants, descriptor, providers) {
30663
- const evaluatedAt = Date.now();
30664
- const grantKey = `${subject}::${permission}`;
30665
- if (explicitGrants.has(grantKey)) {
30666
- const policy = explicitGrants.get(grantKey);
30667
- if (policy === "Allow") {
30668
- return { allowed: true, policy: "Allow", reason: "Explicitly granted to subject", evaluatedAt };
30669
- }
30670
- if (policy === "Deny") {
30671
- return { allowed: false, policy: "Deny", reason: "Explicitly denied to subject", evaluatedAt };
30672
- }
30673
- }
30674
- if (providers && providers.length > 0) {
30675
- for (const provider of providers) {
30676
- const policy = await provider.getPolicy(subject, permission);
30677
- if (policy === "Allow") {
30678
- return { allowed: true, policy: "Allow", reason: `Granted by provider '${provider.id}'`, evaluatedAt };
30679
- }
30680
- if (policy === "Deny") {
30681
- return { allowed: false, policy: "Deny", reason: `Denied by provider '${provider.id}'`, evaluatedAt };
30682
- }
30683
- }
30684
- }
30685
- if (descriptor && descriptor.defaultPolicy) {
30686
- const defaultPol = descriptor.defaultPolicy;
30687
- if (defaultPol === "Allow") {
30688
- return { allowed: true, policy: "Allow", reason: "Allowed by descriptor default policy", evaluatedAt };
30689
- }
30690
- if (defaultPol === "Deny") {
30691
- return { allowed: false, policy: "Deny", reason: "Denied by descriptor default policy", evaluatedAt };
30692
- }
30693
- }
30694
- return {
30695
- allowed: false,
30696
- policy: "Default",
30697
- reason: "No explicit allow policy resolved; default deny",
30698
- evaluatedAt
30699
- };
30700
- }
30701
- };
30702
-
30703
- // packages/core/bootstrap/permission/permission-manager.ts
30704
- var PermissionManager = class {
30705
- constructor() {
30706
- this.registry = new PermissionRegistry();
30707
- this.grants = /* @__PURE__ */ new Map();
30708
- this.providers = [];
30709
- }
30710
- register(descriptor) {
30711
- this.registry.register(descriptor);
30712
- }
30713
- unregister(permissionId) {
30714
- return this.registry.unregister(permissionId);
30715
- }
30716
- grant(subject, permissionId, policy = "Allow") {
30717
- const key = `${subject}::${permissionId}`;
30718
- this.grants.set(key, policy);
30719
- }
30720
- revoke(subject, permissionId) {
30721
- const key = `${subject}::${permissionId}`;
30722
- this.grants.delete(key);
30723
- }
30724
- addProvider(provider) {
30725
- if (!this.providers.some((p) => p.id === provider.id)) {
30726
- this.providers.push(provider);
30727
- }
30728
- }
30729
- removeProvider(providerId) {
30730
- this.providers = this.providers.filter((p) => p.id !== providerId);
30731
- }
30732
- exists(permissionId) {
30733
- return this.registry.exists(permissionId);
30734
- }
30735
- list() {
30736
- return this.registry.list();
30737
- }
30738
- async check(subject, target, permissionId, metadata) {
30739
- const timestamp = Date.now();
30740
- const descriptor = this.registry.get(permissionId);
30741
- const result = await PermissionEvaluator.evaluate(subject, permissionId, this.grants, descriptor, this.providers);
30742
- const context = {
30743
- subject,
30744
- target,
30745
- permission: permissionId,
30746
- metadata,
30747
- timestamp,
30748
- result
30749
- };
30750
- return context;
30751
- }
30752
- async require(subject, target, permissionId, metadata) {
30753
- const context = await this.check(subject, target, permissionId, metadata);
30754
- if (!context.result || !context.result.allowed) {
30755
- const reason = context.result?.reason || "Permission Denied";
30756
- throw new Error(
30757
- `Infrastructure Permission Exception: Subject '${subject}' is denied '${permissionId}' on target '${target}'. Reason: ${reason}`
30758
- );
30759
- }
30760
- return context;
30761
- }
30762
- clear() {
30763
- this.registry.clear();
30764
- this.grants.clear();
30765
- this.providers = [];
30766
- }
30767
- };
30768
-
30769
- // packages/core/bootstrap/composition/plugin-composition-module.ts
30770
- var _sharedPlatformRegistry;
30771
- function getPlatformServiceRegistry() {
30772
- if (!_sharedPlatformRegistry) {
30773
- _sharedPlatformRegistry = new PlatformServiceRegistry();
30774
- }
30775
- return _sharedPlatformRegistry;
30776
- }
30777
- var PluginCompositionModule = class {
30778
- constructor() {
30779
- this.id = "mod_plugin_composition";
30780
- this.name = "PluginCompositionModule";
30781
- }
30782
- compose(options) {
30783
- const serviceRegistry = getPlatformServiceRegistry();
30784
- const registerOrReplace = (config) => {
30785
- const { id, instance } = config;
30786
- if (serviceRegistry.has(id)) {
30787
- serviceRegistry.replace(id, instance);
30788
- } else {
30789
- serviceRegistry.register({ id }, instance);
30790
- }
30791
- };
30792
- const capabilityRegistry = new CapabilityRegistry();
30793
- const permissionManager = new PermissionManager();
30794
- const eventBus = new EventBus();
30795
- const realPluginHost = options?.infrastructureRefs?.get("pluginHost") ?? {
30796
- name: "PluginHostService",
30797
- isReady: true,
30798
- pluginsCount: 0
30799
- };
30800
- const realContributionRegistry = options?.infrastructureRefs?.get("contributionRegistry") ?? {
30801
- name: "ContributionRegistry",
30802
- slotsCount: 0
30803
- };
30804
- const realRuntimeComposition = options?.infrastructureRefs?.get("runtimeComposition") ?? {
30805
- name: "PluginRuntimeComposition",
30806
- isStarted: true
30807
- };
30808
- const realLifecycleManager = options?.infrastructureRefs?.get("lifecycleManager") ?? {
30809
- name: "PluginLifecycleManager",
30810
- version: PLATFORM_VERSION
30811
- };
30812
- const realCapabilityGateway = options?.infrastructureRefs?.get("capabilityGateway") ?? {
30813
- name: "PluginCapabilityGateway",
30814
- version: PLATFORM_VERSION
30815
- };
30816
- const realExtensionRegistry = options?.infrastructureRefs?.get("extensionRegistry") ?? {
30817
- name: "UnifiedExtensionRegistry",
30818
- version: PLATFORM_VERSION
30819
- };
30820
- const realDistributionManager = options?.infrastructureRefs?.get("distributionManager") ?? {
30821
- name: "PluginDistributionManager",
30822
- version: PLATFORM_VERSION
30823
- };
30824
- registerOrReplace({
30825
- id: "srv_plugin_host",
30826
- lifetime: "Singleton",
30827
- description: "OpenLearn Plugin Host Service Engine",
30828
- instance: realPluginHost
30829
- });
30830
- registerOrReplace({
30831
- id: "srv_plugin_contribution_registry",
30832
- lifetime: "Singleton",
30833
- description: "Plugin UI & Slot Contribution Registry",
30834
- instance: realContributionRegistry
30835
- });
30836
- registerOrReplace({
30837
- id: "srv_plugin_runtime_composition",
30838
- lifetime: "Singleton",
30839
- description: "OpenLearn Plugin Runtime Composition Facade",
30840
- instance: realRuntimeComposition
30841
- });
30842
- registerOrReplace({
30843
- id: "srv_plugin_lifecycle_manager",
30844
- lifetime: "Singleton",
30845
- description: "OpenLearn Unified Plugin Lifecycle Manager",
30846
- instance: realLifecycleManager
30847
- });
30848
- registerOrReplace({
30849
- id: "srv_plugin_capability_gateway",
30850
- lifetime: "Singleton",
30851
- description: "OpenLearn Unified Plugin Capability Gateway",
30852
- instance: realCapabilityGateway
30853
- });
30854
- registerOrReplace({
30855
- id: "srv_unified_extension_registry",
30856
- lifetime: "Singleton",
30857
- description: "OpenLearn Unified Extension Registry Foundation",
30858
- instance: realExtensionRegistry
30859
- });
30860
- registerOrReplace({
30861
- id: "srv_plugin_distribution_manager",
30862
- lifetime: "Singleton",
30863
- description: "OpenLearn Plugin Distribution Manager Foundation",
30864
- instance: realDistributionManager
30865
- });
30866
- permissionManager.register({
30867
- id: "perm_plugin_execute",
30868
- name: "Plugin Execution Permission",
30869
- category: "Infrastructure",
30870
- description: "Allows plugin sandbox execution within Platform",
30871
- defaultPolicy: "Allow"
30872
- });
30873
- permissionManager.register({
30874
- id: "perm_plugin_install",
30875
- name: "Plugin Installation Permission",
30876
- category: "Infrastructure",
30877
- description: "Allows installing new plugin packages into storage",
30878
- defaultPolicy: "Allow"
30879
- });
30880
- eventBus.publish({
30881
- id: `evt_${globalThis.crypto.randomUUID()}`,
30882
- type: "PluginHostInitialized",
30883
- source: "PluginCompositionModule",
30884
- payload: { timestamp: Date.now(), status: "Ready" },
30885
- timestamp: Date.now()
30886
- });
30887
- eventBus.publish({
30888
- id: `evt_${globalThis.crypto.randomUUID()}`,
30889
- type: "PluginLoaded",
30890
- source: "PluginCompositionModule",
30891
- payload: { timestamp: Date.now(), pluginsLoaded: 0 },
30892
- timestamp: Date.now()
30893
- });
30894
- eventBus.publish({
30895
- id: `evt_${globalThis.crypto.randomUUID()}`,
30896
- type: "PluginActivated",
30897
- source: "PluginCompositionModule",
30898
- payload: { timestamp: Date.now(), activePlugins: [] },
30899
- timestamp: Date.now()
30900
- });
30901
- }
30902
- };
30903
-
30904
29986
  // packages/core/kernel/index.ts
30905
29987
  var import_path12 = __toESM(require("path"), 1);
30906
29988
  var Kernel = class {
@@ -30967,20 +30049,6 @@ var Kernel = class {
30967
30049
  this.unifiedExtensionRegistry = new UnifiedExtensionRegistry();
30968
30050
  this.capabilityRegistry = capabilityRegistry;
30969
30051
  this.pluginCapabilityGateway = new PluginCapabilityGateway(capabilityRegistry);
30970
- const infrastructureRefs = /* @__PURE__ */ new Map([
30971
- ["pluginHost", this.pluginHost],
30972
- ["contributionRegistry", this.pluginHost.getContributionRegistry()],
30973
- ["runtimeComposition", this.pluginRuntimeComposition],
30974
- ["lifecycleManager", this.pluginLifecycleManager],
30975
- ["capabilityGateway", this.pluginCapabilityGateway],
30976
- ["extensionRegistry", this.unifiedExtensionRegistry],
30977
- ["distributionManager", this.pluginDistributionManager]
30978
- ]);
30979
- try {
30980
- PlatformCompositionRoot.create().registerModule(new PluginCompositionModule()).compose({ infrastructureRefs });
30981
- } catch (e) {
30982
- console.warn("[P7-A2] Plugin composition failed (non-fatal):", e.message);
30983
- }
30984
30052
  this.serviceRegistry.register(IEventBusServiceToken3, this.eventBus);
30985
30053
  this.serviceRegistry.register(ICapabilityServiceToken, this.capabilityGuard);
30986
30054
  this.serviceRegistry.register(IStorageServiceToken, this.storageService);
@@ -34823,7 +33891,7 @@ function sendSafeError(res, err, status = 500, fallbackMessage = "Internal serve
34823
33891
  }
34824
33892
  const isProd = process.env.NODE_ENV === "production";
34825
33893
  const exposedMessage = isProd && effectiveStatus >= 500 ? fallbackMessage : message;
34826
- const rawCode = err && typeof err === "object" && typeof err.code === "string" ? err.code : void 0;
33894
+ const rawCode = err && typeof err === "object" && typeof err.code === "string" ? err.code : err && typeof err === "object" && err.type === "entity.too.large" ? "PAYLOAD_TOO_LARGE" : void 0;
34827
33895
  const errorCode = effectiveStatus >= 400 && effectiveStatus < 500 && rawCode ? rawCode : void 0;
34828
33896
  return res.status(effectiveStatus).json({ success: false, ...errorCode ? { code: errorCode } : {}, error: exposedMessage });
34829
33897
  }
@@ -36281,15 +35349,28 @@ var LARGE_UPLOAD_ENDPOINTS = [
36281
35349
  "/api/upload",
36282
35350
  "/api/courseware/upload",
36283
35351
  "/api/courseware/inline",
36284
- "/api/plugins/upload-zip"
35352
+ "/api/plugins/upload-zip",
35353
+ "/api/resources"
36285
35354
  ];
36286
35355
  var LARGE_UPLOAD_LIMIT = "110mb";
35356
+ var MEDIUM_UPLOAD_ENDPOINTS = [
35357
+ "/api/auth/avatar",
35358
+ "/api/timetable/ocr",
35359
+ "/api/site-settings",
35360
+ "/api/agent/chat"
35361
+ ];
35362
+ var MEDIUM_UPLOAD_LIMIT = "30mb";
36287
35363
  function mountLargeBodyParsers(app) {
36288
35364
  app.use(
36289
35365
  LARGE_UPLOAD_ENDPOINTS,
36290
35366
  import_express2.default.json({ limit: LARGE_UPLOAD_LIMIT }),
36291
35367
  import_express2.default.urlencoded({ limit: LARGE_UPLOAD_LIMIT, extended: true })
36292
35368
  );
35369
+ app.use(
35370
+ MEDIUM_UPLOAD_ENDPOINTS,
35371
+ import_express2.default.json({ limit: MEDIUM_UPLOAD_LIMIT }),
35372
+ import_express2.default.urlencoded({ limit: MEDIUM_UPLOAD_LIMIT, extended: true })
35373
+ );
36293
35374
  app.use(
36294
35375
  COURSE_PACKAGE_IMPORT_PATH,
36295
35376
  import_express2.default.json({ limit: COURSE_PACKAGE_IMPORT_BODY_LIMIT_BYTES }),
@@ -36326,211 +35407,753 @@ function call(op, args) {
36326
35407
  pending.set(callId, { resolve: resolve, reject: reject });
36327
35408
  post({ type: 'call', callId: callId, op: op, args: args });
36328
35409
  });
36329
- }
36330
- function makeCtx(pluginId, manifest) {
36331
- return {
36332
- pluginId: pluginId,
36333
- manifest: manifest,
36334
- services: {
36335
- frontendApi: {
36336
- get: function (path) { return call('api.get', [path]); },
36337
- post: function (path, body) { return call('api.post', [path, body]); },
36338
- del: function (path) { return call('api.del', [path]); }
36339
- },
36340
- storageService: {
36341
- get: function (key) { return call('storage.get', [key]); },
36342
- set: function (key, value) { return call('storage.set', [key, value]); },
36343
- delete: function (key) { return call('storage.delete', [key]); }
35410
+ }
35411
+ function makeCtx(pluginId, manifest) {
35412
+ return {
35413
+ pluginId: pluginId,
35414
+ manifest: manifest,
35415
+ services: {
35416
+ frontendApi: {
35417
+ get: function (path) { return call('api.get', [path]); },
35418
+ post: function (path, body) { return call('api.post', [path, body]); },
35419
+ del: function (path) { return call('api.del', [path]); }
35420
+ },
35421
+ storageService: {
35422
+ get: function (key) { return call('storage.get', [key]); },
35423
+ set: function (key, value) { return call('storage.set', [key, value]); },
35424
+ delete: function (key) { return call('storage.delete', [key]); }
35425
+ }
35426
+ },
35427
+ ui: {
35428
+ registerExtensionPoint: function (slot, config) { return call('ui.register', [slot, config]); },
35429
+ showToast: function (message) { return call('ui.toast', [message]); }
35430
+ },
35431
+ invokeCommand: function (type, payload) { return call('command.invoke', [type, payload]); },
35432
+ context: { get: function () { return call('context.get', []); } }
35433
+ };
35434
+ }
35435
+ window.addEventListener('message', async function (event) {
35436
+ const data = event.data;
35437
+ if (!data || data.channel !== CHANNEL || event.source !== parent) return;
35438
+ if (data.type === 'reply') {
35439
+ const waiter = pending.get(data.callId);
35440
+ if (!waiter) return;
35441
+ pending.delete(data.callId);
35442
+ if (data.ok) waiter.resolve(data.value);
35443
+ else waiter.reject(new Error(data.error || 'bridge call failed'));
35444
+ return;
35445
+ }
35446
+ if (data.type === 'deactivate') {
35447
+ try {
35448
+ if (activePlugin && typeof activePlugin.deactivate === 'function') {
35449
+ await activePlugin.deactivate();
35450
+ }
35451
+ } catch (_) {}
35452
+ activePlugin = null;
35453
+ pending.clear();
35454
+ post({ type: 'deactivated', id: data.id });
35455
+ return;
35456
+ }
35457
+ if (data.type !== 'load') return;
35458
+ targetOrigin = event.origin && event.origin !== 'null' ? event.origin : '*';
35459
+ try {
35460
+ const blob = new Blob([data.source], { type: 'text/javascript' });
35461
+ const url = URL.createObjectURL(blob);
35462
+ let mod;
35463
+ try { mod = await import(url); } finally { URL.revokeObjectURL(url); }
35464
+ const plugin = mod.default || mod;
35465
+ if (typeof plugin.activate !== 'function') throw new Error('missing activate function');
35466
+ activePlugin = plugin;
35467
+ await Promise.race([
35468
+ plugin.activate(makeCtx(data.pluginId, data.manifest)),
35469
+ new Promise(function (_, reject) { setTimeout(function () { reject(new Error('Activation timeout (5000ms)')); }, 5000); })
35470
+ ]);
35471
+ post({ type: 'activated', id: data.id });
35472
+ } catch (error) {
35473
+ post({ type: 'activate-error', id: data.id, error: error && error.message ? error.message : String(error) });
35474
+ }
35475
+ });
35476
+ post({ type: 'ready' });
35477
+ </script>
35478
+ </body></html>`;
35479
+
35480
+ // server/utils/plugin-view-bridge.ts
35481
+ 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:;";
35482
+ var PLUGIN_VIEW_BRIDGE_JS = `(function () {
35483
+ 'use strict';
35484
+ const CHANNEL = 'ol-plugin-view';
35485
+ let targetOrigin = '*';
35486
+ const pending = new Map();
35487
+ const initCallbacks = [];
35488
+ const contextUpdateCallbacks = [];
35489
+ let currentContext = null;
35490
+
35491
+ function post(msg) {
35492
+ if (window.parent && window.parent !== window) {
35493
+ window.parent.postMessage(Object.assign({ channel: CHANNEL }, msg), targetOrigin);
35494
+ }
35495
+ }
35496
+
35497
+ function call(op, args) {
35498
+ const callId = Math.random().toString(16).slice(2) + Date.now().toString(16);
35499
+ return new Promise(function (resolve, reject) {
35500
+ pending.set(callId, { resolve: resolve, reject: reject });
35501
+ post({ type: 'call', callId: callId, op: op, args: args || [] });
35502
+ });
35503
+ }
35504
+
35505
+ window.addEventListener('message', function (event) {
35506
+ const data = event.data;
35507
+ if (!data || data.channel !== CHANNEL) return;
35508
+ if (event.source !== window.parent) return;
35509
+
35510
+ if (data.type === 'init') {
35511
+ currentContext = data.payload || {};
35512
+ targetOrigin = event.origin && event.origin !== 'null' ? event.origin : '*';
35513
+ for (let i = 0; i < initCallbacks.length; i++) {
35514
+ try {
35515
+ initCallbacks[i](currentContext);
35516
+ } catch (e) {
35517
+ console.error('[OpenLearnPluginBridge] init callback error:', e);
35518
+ }
35519
+ }
35520
+ return;
35521
+ }
35522
+
35523
+ if (data.type === 'context-update') {
35524
+ currentContext = Object.assign({}, currentContext, data.payload || {});
35525
+ for (let i = 0; i < contextUpdateCallbacks.length; i++) {
35526
+ try {
35527
+ contextUpdateCallbacks[i](currentContext);
35528
+ } catch (e) {
35529
+ console.error('[OpenLearnPluginBridge] contextUpdate callback error:', e);
35530
+ }
35531
+ }
35532
+ return;
35533
+ }
35534
+
35535
+ if (data.type === 'reply') {
35536
+ const waiter = pending.get(data.callId);
35537
+ if (!waiter) return;
35538
+ pending.delete(data.callId);
35539
+ if (data.ok) {
35540
+ waiter.resolve(data.value);
35541
+ } else {
35542
+ waiter.reject(new Error(data.error || 'bridge call failed'));
35543
+ }
35544
+ return;
35545
+ }
35546
+ });
35547
+
35548
+ const bridge = {
35549
+ CHANNEL: CHANNEL,
35550
+ onInit: function (callback) {
35551
+ if (typeof callback === 'function') {
35552
+ if (currentContext) {
35553
+ try {
35554
+ callback(currentContext);
35555
+ } catch (e) {
35556
+ console.error('[OpenLearnPluginBridge] onInit callback error:', e);
35557
+ }
35558
+ }
35559
+ initCallbacks.push(callback);
35560
+ }
35561
+ return bridge;
35562
+ },
35563
+ onContextUpdate: function (callback) {
35564
+ if (typeof callback === 'function') {
35565
+ contextUpdateCallbacks.push(callback);
36344
35566
  }
35567
+ return bridge;
35568
+ },
35569
+ getContext: function () {
35570
+ return currentContext;
36345
35571
  },
36346
35572
  ui: {
36347
- registerExtensionPoint: function (slot, config) { return call('ui.register', [slot, config]); },
36348
- showToast: function (message) { return call('ui.toast', [message]); }
35573
+ toast: function (message, type) {
35574
+ return call('ui.toast', [message, type || 'info']);
35575
+ },
35576
+ showToast: function (message, type) {
35577
+ return call('ui.toast', [message, type || 'info']);
35578
+ },
35579
+ resize: function (height) {
35580
+ post({ type: 'resize', height: Number(height) || 0 });
35581
+ },
35582
+ },
35583
+ invokeCommand: function (type, payload) {
35584
+ return call('command.invoke', [type, payload]);
35585
+ },
35586
+ api: {
35587
+ get: function (path) {
35588
+ return call('api.get', [path]);
35589
+ },
35590
+ post: function (path, body) {
35591
+ return call('api.post', [path, body]);
35592
+ },
35593
+ del: function (path) {
35594
+ return call('api.del', [path]);
35595
+ },
35596
+ },
35597
+ storage: {
35598
+ get: function (key) {
35599
+ return call('storage.get', [key]);
35600
+ },
35601
+ set: function (key, value) {
35602
+ return call('storage.set', [key, value]);
35603
+ },
35604
+ delete: function (key) {
35605
+ return call('storage.delete', [key]);
35606
+ },
36349
35607
  },
36350
- invokeCommand: function (type, payload) { return call('command.invoke', [type, payload]); },
36351
- context: { get: function () { return call('context.get', []); } }
36352
35608
  };
36353
- }
36354
- window.addEventListener('message', async function (event) {
36355
- const data = event.data;
36356
- if (!data || data.channel !== CHANNEL || event.source !== parent) return;
36357
- if (data.type === 'reply') {
36358
- const waiter = pending.get(data.callId);
36359
- if (!waiter) return;
36360
- pending.delete(data.callId);
36361
- if (data.ok) waiter.resolve(data.value);
36362
- else waiter.reject(new Error(data.error || 'bridge call failed'));
36363
- return;
35609
+
35610
+ window.OpenLearnPluginBridge = bridge;
35611
+ // \u901A\u77E5\u5BBF\u4E3B\u89C6\u56FE\u6C99\u7BB1 iframe \u5DF2\u5C31\u7EEA
35612
+ post({ type: 'ready' });
35613
+ })();
35614
+ `;
35615
+
35616
+ // packages/core/bootstrap/types/index.ts
35617
+ var PlatformBootstrapError = class extends Error {
35618
+ constructor(message, stage, cause) {
35619
+ super(`[PlatformBootstrapError${stage ? `:${stage}` : ""}] ${message}`);
35620
+ this.stage = stage;
35621
+ this.cause = cause;
35622
+ this.name = "PlatformBootstrapError";
35623
+ }
35624
+ };
35625
+ var ConfigurationError = class extends PlatformBootstrapError {
35626
+ constructor(message, cause) {
35627
+ super(message, "Configuring" /* Configuring */, cause);
35628
+ this.name = "ConfigurationError";
35629
+ }
35630
+ };
35631
+ var StartupTimeoutError = class extends PlatformBootstrapError {
35632
+ constructor(message, stage, cause) {
35633
+ super(message, stage, cause);
35634
+ this.name = "StartupTimeoutError";
35635
+ }
35636
+ };
35637
+ var PLATFORM_VERSION2 = PLATFORM_VERSION;
35638
+ var BOOTSTRAP_STAGE_NAMES = Object.freeze([
35639
+ "Created" /* Created */,
35640
+ "Configuring" /* Configuring */,
35641
+ "Registering" /* Registering */,
35642
+ "Initializing" /* Initializing */,
35643
+ "Activating" /* Activating */,
35644
+ "Ready" /* Ready */,
35645
+ "ShuttingDown" /* ShuttingDown */,
35646
+ "Disposed" /* Disposed */
35647
+ ]);
35648
+ var DEFAULT_BOOTSTRAP_CONFIG = Object.freeze({
35649
+ environment: "development",
35650
+ mode: "standalone",
35651
+ port: 9e3,
35652
+ debug: false,
35653
+ pluginsDir: "./plugins",
35654
+ dbPath: "./packages/core/db/educational_os.db"
35655
+ });
35656
+
35657
+ // packages/core/bootstrap/pipeline/pipeline-executor.ts
35658
+ var PipelineExecutor = class {
35659
+ constructor() {
35660
+ this.listeners = /* @__PURE__ */ new Set();
35661
+ }
35662
+ addListener(listener) {
35663
+ this.listeners.add(listener);
35664
+ return () => {
35665
+ this.listeners.delete(listener);
35666
+ };
35667
+ }
35668
+ emit(event) {
35669
+ for (const listener of Array.from(this.listeners)) {
35670
+ try {
35671
+ listener(event);
35672
+ } catch (err) {
35673
+ console.error("[PipelineExecutor] Listener error:", err);
35674
+ }
35675
+ }
35676
+ }
35677
+ async execute(stages, context) {
35678
+ const startTime = Date.now();
35679
+ const results = [];
35680
+ const executedStages = [];
35681
+ this.emit({ type: "PipelineStarted", timestamp: startTime });
35682
+ console.log("[Platform] Starting Bootstrap Pipeline execution...");
35683
+ for (const stage of stages) {
35684
+ if (context.isCancelled) {
35685
+ console.warn(`[Platform] Pipeline cancelled before stage ${stage.name}`);
35686
+ const totalDurationMs2 = Date.now() - startTime;
35687
+ return {
35688
+ totalDurationMs: totalDurationMs2,
35689
+ status: "Aborted",
35690
+ stageResults: Object.freeze(results)
35691
+ };
35692
+ }
35693
+ console.log(`[Platform] Entering ${stage.name}`);
35694
+ this.emit({
35695
+ type: "StageStarted",
35696
+ timestamp: Date.now(),
35697
+ stageId: stage.id,
35698
+ stageName: String(stage.name)
35699
+ });
35700
+ const stageStart = Date.now();
35701
+ try {
35702
+ if (stage.timeoutMs && stage.timeoutMs > 0) {
35703
+ await this.executeWithTimeout(stage, context, stage.timeoutMs);
35704
+ } else {
35705
+ await stage.execute(context);
35706
+ }
35707
+ const durationMs = Date.now() - stageStart;
35708
+ console.log(`[Platform] Completed ${stage.name} (${durationMs} ms)`);
35709
+ results.push({
35710
+ stageId: stage.id,
35711
+ stageName: String(stage.name),
35712
+ durationMs,
35713
+ status: "Success"
35714
+ });
35715
+ executedStages.push(stage);
35716
+ this.emit({
35717
+ type: "StageCompleted",
35718
+ timestamp: Date.now(),
35719
+ stageId: stage.id,
35720
+ stageName: String(stage.name),
35721
+ durationMs
35722
+ });
35723
+ } catch (err) {
35724
+ const error = err instanceof Error ? err : new Error(String(err));
35725
+ const durationMs = Date.now() - stageStart;
35726
+ console.error(`[Platform] Failed ${stage.name} (${durationMs} ms): ${error.message}`);
35727
+ results.push({
35728
+ stageId: stage.id,
35729
+ stageName: String(stage.name),
35730
+ durationMs,
35731
+ status: "Failed",
35732
+ error
35733
+ });
35734
+ this.emit({
35735
+ type: "StageFailed",
35736
+ timestamp: Date.now(),
35737
+ stageId: stage.id,
35738
+ stageName: String(stage.name),
35739
+ durationMs,
35740
+ error
35741
+ });
35742
+ await this.rollbackExecutedStages(executedStages, context);
35743
+ const totalDurationMs2 = Date.now() - startTime;
35744
+ const pipelineResult = {
35745
+ totalDurationMs: totalDurationMs2,
35746
+ status: "Failed",
35747
+ stageResults: Object.freeze(results),
35748
+ failedStage: stage.id,
35749
+ error
35750
+ };
35751
+ this.emit({
35752
+ type: "PipelineCompleted",
35753
+ timestamp: Date.now(),
35754
+ durationMs: totalDurationMs2,
35755
+ error
35756
+ });
35757
+ return pipelineResult;
35758
+ }
35759
+ }
35760
+ const totalDurationMs = Date.now() - startTime;
35761
+ console.log(`[Platform] Ready. Total startup duration: ${totalDurationMs} ms.`);
35762
+ const finalResult = {
35763
+ totalDurationMs,
35764
+ status: "Success",
35765
+ stageResults: Object.freeze(results)
35766
+ };
35767
+ this.emit({
35768
+ type: "PipelineCompleted",
35769
+ timestamp: Date.now(),
35770
+ durationMs: totalDurationMs
35771
+ });
35772
+ return finalResult;
36364
35773
  }
36365
- if (data.type === 'deactivate') {
35774
+ async executeWithTimeout(stage, context, timeoutMs) {
35775
+ let timer;
35776
+ const timeoutPromise = new Promise((_, reject) => {
35777
+ timer = setTimeout(() => {
35778
+ reject(new StartupTimeoutError(`Stage execution timed out after ${timeoutMs} ms`));
35779
+ }, timeoutMs);
35780
+ });
36366
35781
  try {
36367
- if (activePlugin && typeof activePlugin.deactivate === 'function') {
36368
- await activePlugin.deactivate();
35782
+ await Promise.race([stage.execute(context), timeoutPromise]);
35783
+ } finally {
35784
+ if (timer) {
35785
+ clearTimeout(timer);
36369
35786
  }
36370
- } catch (_) {}
36371
- activePlugin = null;
36372
- pending.clear();
36373
- post({ type: 'deactivated', id: data.id });
36374
- return;
35787
+ }
36375
35788
  }
36376
- if (data.type !== 'load') return;
36377
- targetOrigin = event.origin && event.origin !== 'null' ? event.origin : '*';
36378
- try {
36379
- const blob = new Blob([data.source], { type: 'text/javascript' });
36380
- const url = URL.createObjectURL(blob);
36381
- let mod;
36382
- try { mod = await import(url); } finally { URL.revokeObjectURL(url); }
36383
- const plugin = mod.default || mod;
36384
- if (typeof plugin.activate !== 'function') throw new Error('missing activate function');
36385
- activePlugin = plugin;
36386
- await Promise.race([
36387
- plugin.activate(makeCtx(data.pluginId, data.manifest)),
36388
- new Promise(function (_, reject) { setTimeout(function () { reject(new Error('Activation timeout (5000ms)')); }, 5000); })
36389
- ]);
36390
- post({ type: 'activated', id: data.id });
36391
- } catch (error) {
36392
- post({ type: 'activate-error', id: data.id, error: error && error.message ? error.message : String(error) });
35789
+ async rollbackExecutedStages(executedStages, context) {
35790
+ console.log("[Platform] Triggering stage rollbacks...");
35791
+ for (let i = executedStages.length - 1; i >= 0; i--) {
35792
+ const stage = executedStages[i];
35793
+ if (stage.rollback) {
35794
+ try {
35795
+ console.log(`[Platform] Rolling back ${stage.name}`);
35796
+ await stage.rollback(context);
35797
+ } catch (rbErr) {
35798
+ console.error(`[Platform] Error during rollback of ${stage.name}:`, rbErr);
35799
+ }
35800
+ }
35801
+ }
36393
35802
  }
36394
- });
36395
- post({ type: 'ready' });
36396
- </script>
36397
- </body></html>`;
35803
+ };
36398
35804
 
36399
- // server/utils/plugin-view-bridge.ts
36400
- 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:;";
36401
- var PLUGIN_VIEW_BRIDGE_JS = `(function () {
36402
- 'use strict';
36403
- const CHANNEL = 'ol-plugin-view';
36404
- let targetOrigin = '*';
36405
- const pending = new Map();
36406
- const initCallbacks = [];
36407
- const contextUpdateCallbacks = [];
36408
- let currentContext = null;
35805
+ // packages/core/bootstrap/pipeline/stages/standard-stages.ts
35806
+ var StartupStageImpl = class {
35807
+ constructor() {
35808
+ this.id = "stage_startup";
35809
+ this.name = "Created" /* Created */;
35810
+ this.description = "Environment & configuration validation";
35811
+ }
35812
+ async execute(context) {
35813
+ context.setStage("Configuring" /* Configuring */);
35814
+ }
35815
+ };
35816
+ var RegistrationStageImpl = class {
35817
+ constructor() {
35818
+ this.id = "stage_registration";
35819
+ this.name = "Registering" /* Registering */;
35820
+ this.description = "Core Service Contracts & DI Tokens registration";
35821
+ }
35822
+ async execute(context) {
35823
+ context.setStage("Registering" /* Registering */);
35824
+ }
35825
+ };
35826
+ var InitializationStageImpl = class {
35827
+ constructor() {
35828
+ this.id = "stage_initialization";
35829
+ this.name = "Initializing" /* Initializing */;
35830
+ this.description = "Subsystem Kernels initialization";
35831
+ }
35832
+ async execute(context) {
35833
+ context.setStage("Initializing" /* Initializing */);
35834
+ }
35835
+ };
35836
+ var ActivationStageImpl = class {
35837
+ constructor() {
35838
+ this.id = "stage_activation";
35839
+ this.name = "Activating" /* Activating */;
35840
+ this.description = "Plugin Host discovery & ESM plugins activation";
35841
+ }
35842
+ async execute(context) {
35843
+ context.setStage("Activating" /* Activating */);
35844
+ }
35845
+ };
35846
+ var ReadyStageImpl = class {
35847
+ constructor() {
35848
+ this.id = "stage_ready";
35849
+ this.name = "Ready" /* Ready */;
35850
+ this.description = "HTTP & Socket.IO server readiness";
35851
+ }
35852
+ async execute(context) {
35853
+ context.setStage("Ready" /* Ready */);
35854
+ }
35855
+ };
36409
35856
 
36410
- function post(msg) {
36411
- if (window.parent && window.parent !== window) {
36412
- window.parent.postMessage(Object.assign({ channel: CHANNEL }, msg), targetOrigin);
35857
+ // packages/core/bootstrap/pipeline/bootstrap-pipeline.ts
35858
+ var BootstrapPipeline = class {
35859
+ constructor(stages) {
35860
+ this._stages = [];
35861
+ this.executor = new PipelineExecutor();
35862
+ if (stages && stages.length > 0) {
35863
+ this._stages = [...stages];
35864
+ } else {
35865
+ this._stages = [
35866
+ new StartupStageImpl(),
35867
+ new RegistrationStageImpl(),
35868
+ new InitializationStageImpl(),
35869
+ new ActivationStageImpl(),
35870
+ new ReadyStageImpl()
35871
+ ];
36413
35872
  }
36414
35873
  }
36415
-
36416
- function call(op, args) {
36417
- const callId = Math.random().toString(16).slice(2) + Date.now().toString(16);
36418
- return new Promise(function (resolve, reject) {
36419
- pending.set(callId, { resolve: resolve, reject: reject });
36420
- post({ type: 'call', callId: callId, op: op, args: args || [] });
36421
- });
35874
+ get stages() {
35875
+ return Object.freeze(this._stages);
35876
+ }
35877
+ addStage(stage) {
35878
+ this._stages.push(stage);
35879
+ return this;
35880
+ }
35881
+ addListener(listener) {
35882
+ return this.executor.addListener(listener);
36422
35883
  }
35884
+ async run(context) {
35885
+ const result = await this.execute(context);
35886
+ if (result.status === "Failed") {
35887
+ throw result.error || new Error(`Bootstrap Pipeline failed at stage: ${result.failedStage}`);
35888
+ }
35889
+ }
35890
+ async execute(context) {
35891
+ return this.executor.execute(this._stages, context);
35892
+ }
35893
+ };
36423
35894
 
36424
- window.addEventListener('message', function (event) {
36425
- const data = event.data;
36426
- if (!data || data.channel !== CHANNEL) return;
36427
- if (event.source !== window.parent) return;
35895
+ // packages/core/bootstrap/builder/builder-validation-engine.ts
35896
+ var BuilderValidationEngine = class {
35897
+ static validate(config, environment, stages) {
35898
+ const errors = [];
35899
+ const warnings = [];
35900
+ if (!["development", "production", "test"].includes(environment)) {
35901
+ errors.push({
35902
+ code: "INVALID_ENVIRONMENT",
35903
+ message: `Environment must be one of 'development', 'production', 'test'. Received: '${environment}'`,
35904
+ field: "environment"
35905
+ });
35906
+ }
35907
+ if (!config.port || config.port <= 0 || config.port > 65535) {
35908
+ errors.push({
35909
+ code: "INVALID_PORT",
35910
+ message: `Port must be a valid number between 1 and 65535. Received: ${config.port}`,
35911
+ field: "port"
35912
+ });
35913
+ }
35914
+ if (!stages || stages.length === 0) {
35915
+ errors.push({
35916
+ code: "MISSING_STAGES",
35917
+ message: "Bootstrap pipeline contains no registered stages.",
35918
+ field: "stages"
35919
+ });
35920
+ } else {
35921
+ const stageIds = /* @__PURE__ */ new Set();
35922
+ for (const stage of stages) {
35923
+ if (!stage.id) {
35924
+ errors.push({
35925
+ code: "INVALID_STAGE",
35926
+ message: `Stage '${stage.name}' has no unique ID.`
35927
+ });
35928
+ } else if (stageIds.has(stage.id)) {
35929
+ errors.push({
35930
+ code: "DUPLICATE_STAGE",
35931
+ message: `Duplicate stage registration detected for stage ID '${stage.id}'.`,
35932
+ field: "stage.id"
35933
+ });
35934
+ } else {
35935
+ stageIds.add(stage.id);
35936
+ }
35937
+ }
35938
+ }
35939
+ return {
35940
+ isValid: errors.length === 0,
35941
+ errors: Object.freeze(errors),
35942
+ warnings: Object.freeze(warnings)
35943
+ };
35944
+ }
35945
+ };
36428
35946
 
36429
- if (data.type === 'init') {
36430
- currentContext = data.payload || {};
36431
- targetOrigin = event.origin && event.origin !== 'null' ? event.origin : '*';
36432
- for (let i = 0; i < initCallbacks.length; i++) {
36433
- try {
36434
- initCallbacks[i](currentContext);
36435
- } catch (e) {
36436
- console.error('[OpenLearnPluginBridge] init callback error:', e);
35947
+ // packages/core/bootstrap/builder/platform-builder.ts
35948
+ var DefaultPlatformLogger = class {
35949
+ info(message, ...args) {
35950
+ console.log(`[PlatformBuilder:INFO] ${message}`, ...args);
35951
+ }
35952
+ warn(message, ...args) {
35953
+ console.warn(`[PlatformBuilder:WARN] ${message}`, ...args);
35954
+ }
35955
+ error(message, ...args) {
35956
+ console.error(`[PlatformBuilder:ERROR] ${message}`, ...args);
35957
+ }
35958
+ debug(message, ...args) {
35959
+ console.debug(`[PlatformBuilder:DEBUG] ${message}`, ...args);
35960
+ }
35961
+ };
35962
+ var PlatformBuilder = class _PlatformBuilder {
35963
+ constructor(options) {
35964
+ this._state = "Created";
35965
+ this._config = { ...DEFAULT_BOOTSTRAP_CONFIG };
35966
+ this._logger = new DefaultPlatformLogger();
35967
+ this._environment = "development";
35968
+ this._metadata = /* @__PURE__ */ new Map();
35969
+ this._services = /* @__PURE__ */ new Map();
35970
+ this._capabilities = /* @__PURE__ */ new Map();
35971
+ this._extensions = /* @__PURE__ */ new Map();
35972
+ this._pipeline = new BootstrapPipeline();
35973
+ this._state = "Created";
35974
+ this._logger.info("Builder Started");
35975
+ if (options) {
35976
+ if (options.config) this.withConfiguration(options.config);
35977
+ if (options.logger) this.withLogger(options.logger);
35978
+ if (options.environment) this.withEnvironment(options.environment);
35979
+ if (options.metadata) {
35980
+ for (const [k, v] of Object.entries(options.metadata)) {
35981
+ this.withMetadata(k, v);
36437
35982
  }
36438
35983
  }
36439
- return;
36440
35984
  }
36441
-
36442
- if (data.type === 'context-update') {
36443
- currentContext = Object.assign({}, currentContext, data.payload || {});
36444
- for (let i = 0; i < contextUpdateCallbacks.length; i++) {
36445
- try {
36446
- contextUpdateCallbacks[i](currentContext);
36447
- } catch (e) {
36448
- console.error('[OpenLearnPluginBridge] contextUpdate callback error:', e);
36449
- }
36450
- }
36451
- return;
35985
+ }
35986
+ static create(options) {
35987
+ return new _PlatformBuilder(options);
35988
+ }
35989
+ get state() {
35990
+ return this._state;
35991
+ }
35992
+ transitionTo(newState) {
35993
+ if (this._state === "Disposed") {
35994
+ throw new Error("PlatformBuilder has been disposed and cannot accept further transitions.");
36452
35995
  }
36453
-
36454
- if (data.type === 'reply') {
36455
- const waiter = pending.get(data.callId);
36456
- if (!waiter) return;
36457
- pending.delete(data.callId);
36458
- if (data.ok) {
36459
- waiter.resolve(data.value);
36460
- } else {
36461
- waiter.reject(new Error(data.error || 'bridge call failed'));
36462
- }
36463
- return;
35996
+ if (this._state === "Built" && newState !== "Disposed") {
35997
+ throw new Error(`Invalid state transition from Built to ${newState}. Builder is already built.`);
36464
35998
  }
36465
- });
36466
-
36467
- const bridge = {
36468
- CHANNEL: CHANNEL,
36469
- onInit: function (callback) {
36470
- if (typeof callback === 'function') {
36471
- if (currentContext) {
36472
- try {
36473
- callback(currentContext);
36474
- } catch (e) {
36475
- console.error('[OpenLearnPluginBridge] onInit callback error:', e);
36476
- }
36477
- }
36478
- initCallbacks.push(callback);
36479
- }
36480
- return bridge;
36481
- },
36482
- onContextUpdate: function (callback) {
36483
- if (typeof callback === 'function') {
36484
- contextUpdateCallbacks.push(callback);
36485
- }
36486
- return bridge;
36487
- },
36488
- getContext: function () {
36489
- return currentContext;
36490
- },
36491
- ui: {
36492
- toast: function (message, type) {
36493
- return call('ui.toast', [message, type || 'info']);
35999
+ this._state = newState;
36000
+ }
36001
+ withConfiguration(config) {
36002
+ this.transitionTo("Configuring");
36003
+ this._config = { ...this._config, ...config };
36004
+ if (config.environment) {
36005
+ this._environment = config.environment;
36006
+ }
36007
+ this._logger.info("Configuration Loaded");
36008
+ return this;
36009
+ }
36010
+ withLogger(logger2) {
36011
+ this.transitionTo("Configuring");
36012
+ this._logger = logger2;
36013
+ return this;
36014
+ }
36015
+ withEnvironment(env) {
36016
+ this.transitionTo("Configuring");
36017
+ this._environment = env;
36018
+ this._config = { ...this._config, environment: env };
36019
+ return this;
36020
+ }
36021
+ withMetadata(key, value) {
36022
+ this.transitionTo("Configuring");
36023
+ this._metadata.set(key, value);
36024
+ return this;
36025
+ }
36026
+ addBootstrapStage(stage) {
36027
+ this.transitionTo("Configuring");
36028
+ this._pipeline.addStage(stage);
36029
+ return this;
36030
+ }
36031
+ addService(serviceId, instance) {
36032
+ this.transitionTo("Configuring");
36033
+ this._services.set(serviceId, instance);
36034
+ return this;
36035
+ }
36036
+ addCapability(capabilityId, descriptor) {
36037
+ this.transitionTo("Configuring");
36038
+ this._capabilities.set(capabilityId, descriptor);
36039
+ return this;
36040
+ }
36041
+ addExtension(extensionId, extensionSpec) {
36042
+ this.transitionTo("Configuring");
36043
+ this._extensions.set(extensionId, extensionSpec);
36044
+ return this;
36045
+ }
36046
+ buildResult() {
36047
+ const buildStart = Date.now();
36048
+ this.transitionTo("Validating");
36049
+ this._logger.info("Validation Started");
36050
+ const validation = BuilderValidationEngine.validate(this._config, this._environment, this._pipeline.stages);
36051
+ this._logger.info("Validation Completed");
36052
+ if (!validation.isValid) {
36053
+ this._logger.error(`Validation Failed with ${validation.errors.length} errors.`);
36054
+ throw new ConfigurationError(
36055
+ `PlatformBuilder validation failed: ${validation.errors.map((e) => e.message).join("; ")}`
36056
+ );
36057
+ }
36058
+ this.transitionTo("Building");
36059
+ this._logger.info("Build Started");
36060
+ const platformContext = {
36061
+ platformId: `plt_${globalThis.crypto.randomUUID()}`,
36062
+ version: PLATFORM_VERSION2,
36063
+ namespace: "openlearn.core",
36064
+ mode: this._config.mode,
36065
+ environment: {
36066
+ type: this._environment,
36067
+ isDevelopment: this._environment === "development",
36068
+ isProduction: this._environment === "production",
36069
+ isTest: this._environment === "test",
36070
+ isPluginSandbox: false
36494
36071
  },
36495
- showToast: function (message, type) {
36496
- return call('ui.toast', [message, type || 'info']);
36072
+ config: this._config,
36073
+ featureFlags: {
36074
+ isEnabled: () => true,
36075
+ getFlag: (_, def) => def,
36076
+ getAllFlags: () => ({})
36497
36077
  },
36498
- resize: function (height) {
36499
- post({ type: 'resize', height: Number(height) || 0 });
36078
+ runtimeMetadata: {
36079
+ os: process.platform,
36080
+ nodeVersion: process.version,
36081
+ arch: process.arch,
36082
+ processId: process.pid,
36083
+ memoryUsage: process.memoryUsage(),
36084
+ buildVersion: PLATFORM_VERSION2
36500
36085
  },
36501
- },
36502
- invokeCommand: function (type, payload) {
36503
- return call('command.invoke', [type, payload]);
36504
- },
36505
- api: {
36506
- get: function (path) {
36507
- return call('api.get', [path]);
36086
+ bootstrapState: "Bootstrapping",
36087
+ logger: this._logger,
36088
+ diagnostics: {
36089
+ getMetrics: () => ({ uptime: 0 }),
36090
+ getSystemStatus: () => ({ isHealthy: true, activeServicesCount: this._services.size, uptimeSeconds: 0 })
36508
36091
  },
36509
- post: function (path, body) {
36510
- return call('api.post', [path, body]);
36092
+ serviceLocator: {
36093
+ hasService: (id) => this._services.has(id),
36094
+ getService: (id) => this._services.get(id)
36511
36095
  },
36512
- del: function (path) {
36513
- return call('api.del', [path]);
36096
+ capabilityCatalog: {
36097
+ hasCapability: (id) => this._capabilities.has(id),
36098
+ getCapability: (id) => this._capabilities.get(id)
36514
36099
  },
36515
- },
36516
- storage: {
36517
- get: function (key) {
36518
- return call('storage.get', [key]);
36100
+ extensionCatalog: {
36101
+ hasExtension: (id) => this._extensions.has(id),
36102
+ getExtension: (id) => this._extensions.get(id)
36519
36103
  },
36520
- set: function (key, value) {
36521
- return call('storage.set', [key, value]);
36104
+ eventDispatcher: {
36105
+ dispatch: async () => {
36106
+ }
36522
36107
  },
36523
- delete: function (key) {
36524
- return call('storage.delete', [key]);
36108
+ shutdownToken: {
36109
+ isRequested: false,
36110
+ onShutdown: () => {
36111
+ }
36112
+ }
36113
+ };
36114
+ const buildDurationMs = Date.now() - buildStart;
36115
+ this.transitionTo("Built");
36116
+ this._logger.info(`Build Completed in ${buildDurationMs} ms`);
36117
+ const result = {
36118
+ platformContext,
36119
+ pipeline: this._pipeline,
36120
+ buildDurationMs,
36121
+ validation,
36122
+ metadata: Object.fromEntries(this._metadata.entries()),
36123
+ builderVersion: PLATFORM_VERSION2
36124
+ };
36125
+ return result;
36126
+ }
36127
+ async build() {
36128
+ const res = this.buildResult();
36129
+ return {
36130
+ currentStage: "Created" /* Created */,
36131
+ context: res.platformContext,
36132
+ pipeline: res.pipeline,
36133
+ start: async () => {
36525
36134
  },
36526
- },
36527
- };
36528
-
36529
- window.OpenLearnPluginBridge = bridge;
36530
- // \u901A\u77E5\u5BBF\u4E3B\u89C6\u56FE\u6C99\u7BB1 iframe \u5DF2\u5C31\u7EEA
36531
- post({ type: 'ready' });
36532
- })();
36533
- `;
36135
+ shutdown: async () => {
36136
+ },
36137
+ dispose: async () => {
36138
+ }
36139
+ };
36140
+ }
36141
+ async start() {
36142
+ const kernel = await this.build();
36143
+ await kernel.start();
36144
+ return kernel;
36145
+ }
36146
+ async shutdown() {
36147
+ this.transitionTo("Disposed");
36148
+ }
36149
+ dispose() {
36150
+ this._state = "Disposed";
36151
+ this._services.clear();
36152
+ this._capabilities.clear();
36153
+ this._extensions.clear();
36154
+ this._metadata.clear();
36155
+ }
36156
+ };
36534
36157
 
36535
36158
  // packages/core/bootstrap/adapter/bootstrap-registration.ts
36536
36159
  var BootstrapRegistration = class {