@objectstack/core 4.0.3 → 4.0.5

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 (75) hide show
  1. package/README.md +95 -10
  2. package/dist/index.cjs +169 -507
  3. package/dist/index.cjs.map +1 -1
  4. package/dist/index.d.cts +24 -223
  5. package/dist/index.d.ts +24 -223
  6. package/dist/index.js +175 -505
  7. package/dist/index.js.map +1 -1
  8. package/dist/logger.cjs +177 -0
  9. package/dist/logger.cjs.map +1 -0
  10. package/dist/logger.d.cts +26 -0
  11. package/dist/logger.d.ts +26 -0
  12. package/dist/logger.js +158 -0
  13. package/dist/logger.js.map +1 -0
  14. package/package.json +36 -15
  15. package/.turbo/turbo-build.log +0 -22
  16. package/ADVANCED_FEATURES.md +0 -380
  17. package/API_REGISTRY.md +0 -392
  18. package/CHANGELOG.md +0 -465
  19. package/PHASE2_IMPLEMENTATION.md +0 -388
  20. package/REFACTORING_SUMMARY.md +0 -40
  21. package/examples/api-registry-example.ts +0 -559
  22. package/examples/kernel-features-example.ts +0 -311
  23. package/examples/phase2-integration.ts +0 -357
  24. package/src/api-registry-plugin.test.ts +0 -393
  25. package/src/api-registry-plugin.ts +0 -89
  26. package/src/api-registry.test.ts +0 -1089
  27. package/src/api-registry.ts +0 -739
  28. package/src/contracts/data-engine.ts +0 -57
  29. package/src/contracts/http-server.ts +0 -151
  30. package/src/contracts/logger.ts +0 -72
  31. package/src/dependency-resolver.test.ts +0 -287
  32. package/src/dependency-resolver.ts +0 -390
  33. package/src/fallbacks/fallbacks.test.ts +0 -281
  34. package/src/fallbacks/index.ts +0 -26
  35. package/src/fallbacks/memory-cache.ts +0 -34
  36. package/src/fallbacks/memory-i18n.ts +0 -112
  37. package/src/fallbacks/memory-job.ts +0 -23
  38. package/src/fallbacks/memory-metadata.ts +0 -50
  39. package/src/fallbacks/memory-queue.ts +0 -28
  40. package/src/health-monitor.test.ts +0 -81
  41. package/src/health-monitor.ts +0 -318
  42. package/src/hot-reload.ts +0 -382
  43. package/src/index.ts +0 -50
  44. package/src/kernel-base.ts +0 -273
  45. package/src/kernel.test.ts +0 -624
  46. package/src/kernel.ts +0 -631
  47. package/src/lite-kernel.test.ts +0 -248
  48. package/src/lite-kernel.ts +0 -137
  49. package/src/logger.test.ts +0 -116
  50. package/src/logger.ts +0 -355
  51. package/src/namespace-resolver.test.ts +0 -130
  52. package/src/namespace-resolver.ts +0 -188
  53. package/src/package-manager.test.ts +0 -225
  54. package/src/package-manager.ts +0 -428
  55. package/src/plugin-loader.test.ts +0 -421
  56. package/src/plugin-loader.ts +0 -484
  57. package/src/qa/adapter.ts +0 -16
  58. package/src/qa/http-adapter.ts +0 -116
  59. package/src/qa/index.ts +0 -5
  60. package/src/qa/runner.ts +0 -189
  61. package/src/security/index.ts +0 -50
  62. package/src/security/permission-manager.test.ts +0 -256
  63. package/src/security/permission-manager.ts +0 -338
  64. package/src/security/plugin-config-validator.test.ts +0 -276
  65. package/src/security/plugin-config-validator.ts +0 -193
  66. package/src/security/plugin-permission-enforcer.test.ts +0 -251
  67. package/src/security/plugin-permission-enforcer.ts +0 -436
  68. package/src/security/plugin-signature-verifier.ts +0 -403
  69. package/src/security/sandbox-runtime.ts +0 -462
  70. package/src/security/security-scanner.ts +0 -367
  71. package/src/types.ts +0 -120
  72. package/src/utils/env.test.ts +0 -62
  73. package/src/utils/env.ts +0 -53
  74. package/tsconfig.json +0 -10
  75. package/vitest.config.ts +0 -10
package/dist/index.cjs CHANGED
@@ -39,7 +39,6 @@ __export(index_exports, {
39
39
  ObjectKernel: () => ObjectKernel,
40
40
  ObjectKernelBase: () => ObjectKernelBase,
41
41
  ObjectLogger: () => ObjectLogger,
42
- PackageManager: () => PackageManager,
43
42
  PluginConfigValidator: () => PluginConfigValidator,
44
43
  PluginHealthMonitor: () => PluginHealthMonitor,
45
44
  PluginLoader: () => PluginLoader,
@@ -160,7 +159,13 @@ var ObjectKernelBase = class {
160
159
  }
161
160
  },
162
161
  logger: this.logger,
163
- getKernel: () => this
162
+ getKernel: () => this,
163
+ registerServiceFactory: (_name, _factory, _lifecycle, _dependencies) => {
164
+ throw new Error("[KernelBase] registerServiceFactory not supported \u2014 use ObjectKernel");
165
+ },
166
+ getServiceScoped: async (_name, _scopeId) => {
167
+ throw new Error("[KernelBase] getServiceScoped not supported \u2014 use ObjectKernel");
168
+ }
164
169
  };
165
170
  }
166
171
  /**
@@ -279,145 +284,58 @@ var ObjectKernelBase = class {
279
284
  }
280
285
  };
281
286
 
282
- // src/utils/env.ts
283
- var isNode = typeof process !== "undefined" && process.versions != null && process.versions.node != null;
284
- function getEnv(key, defaultValue) {
285
- if (typeof process !== "undefined" && process.env) {
286
- return process.env[key] || defaultValue;
287
- }
288
- try {
289
- if (typeof globalThis !== "undefined" && globalThis.process?.env) {
290
- return globalThis.process.env[key] || defaultValue;
291
- }
292
- } catch (e) {
293
- }
294
- return defaultValue;
295
- }
296
- function safeExit(code = 0) {
297
- if (isNode) {
298
- process.exit(code);
299
- }
300
- }
301
- function getMemoryUsage() {
302
- if (isNode) {
303
- return process.memoryUsage();
304
- }
305
- return { heapUsed: 0, heapTotal: 0 };
306
- }
307
-
308
287
  // src/logger.ts
309
- var import_meta = {};
288
+ var LEVEL_ORDER = {
289
+ debug: 0,
290
+ info: 1,
291
+ warn: 2,
292
+ error: 3,
293
+ fatal: 4,
294
+ silent: 5
295
+ };
296
+ var LEVEL_COLORS = {
297
+ debug: "\x1B[36m",
298
+ info: "\x1B[32m",
299
+ warn: "\x1B[33m",
300
+ error: "\x1B[31m",
301
+ fatal: "\x1B[35m",
302
+ silent: ""
303
+ };
304
+ var RESET = "\x1B[0m";
310
305
  var ObjectLogger = class _ObjectLogger {
311
- // CommonJS require function for Node.js
312
- constructor(config = {}) {
313
- this.isNode = isNode;
306
+ constructor(config = {}, bindings = {}) {
314
307
  this.config = {
315
308
  name: config.name,
316
309
  level: config.level ?? "info",
317
- format: config.format ?? (this.isNode ? "json" : "pretty"),
310
+ format: config.format ?? "pretty",
318
311
  redact: config.redact ?? ["password", "token", "secret", "key"],
319
312
  sourceLocation: config.sourceLocation ?? false,
320
313
  file: config.file,
321
- rotation: config.rotation ?? {
322
- maxSize: "10m",
323
- maxFiles: 5
324
- }
314
+ rotation: config.rotation ?? { maxSize: "10m", maxFiles: 5 }
325
315
  };
326
- if (this.isNode) {
327
- this.initPinoLogger();
316
+ this.bindings = bindings;
317
+ if (this.config.file && typeof process !== "undefined") {
318
+ this.openFileStream(this.config.file);
328
319
  }
329
320
  }
330
- /**
331
- * Initialize Pino logger for Node.js
332
- */
333
- async initPinoLogger() {
334
- if (!this.isNode) return;
321
+ openFileStream(path) {
335
322
  try {
336
- const { createRequire } = await import("module");
337
- this.require = createRequire(import_meta.url);
338
- const pino = this.require("pino");
339
- const pinoOptions = {
340
- level: this.config.level,
341
- redact: {
342
- paths: this.config.redact,
343
- censor: "***REDACTED***"
344
- }
345
- };
346
- if (this.config.name) {
347
- pinoOptions.name = this.config.name;
348
- }
349
- const targets = [];
350
- if (this.config.format === "pretty") {
351
- let hasPretty = false;
352
- try {
353
- this.require.resolve("pino-pretty");
354
- hasPretty = true;
355
- } catch (e) {
356
- }
357
- if (hasPretty) {
358
- targets.push({
359
- target: "pino-pretty",
360
- options: {
361
- colorize: true,
362
- translateTime: "SYS:standard",
363
- ignore: "pid,hostname"
364
- },
365
- level: this.config.level
366
- });
367
- } else {
368
- console.warn("[Logger] pino-pretty not found. Install it for pretty logging: pnpm add -D pino-pretty");
369
- targets.push({
370
- target: "pino/file",
371
- options: { destination: 1 },
372
- level: this.config.level
373
- });
374
- }
375
- } else if (this.config.format === "json") {
376
- targets.push({
377
- target: "pino/file",
378
- options: { destination: 1 },
379
- // stdout
380
- level: this.config.level
381
- });
382
- } else {
383
- targets.push({
384
- target: "pino/file",
385
- options: { destination: 1 },
386
- level: this.config.level
387
- });
388
- }
389
- if (this.config.file) {
390
- targets.push({
391
- target: "pino/file",
392
- options: {
393
- destination: this.config.file,
394
- mkdir: true
395
- },
396
- level: this.config.level
397
- });
398
- }
399
- if (targets.length > 0) {
400
- pinoOptions.transport = targets.length === 1 ? targets[0] : { targets };
401
- }
402
- this.pinoInstance = pino(pinoOptions);
403
- this.pinoLogger = this.pinoInstance;
404
- } catch (error) {
405
- console.warn("[Logger] Pino not available, falling back to console:", error);
406
- this.pinoLogger = null;
323
+ const fs = require("fs");
324
+ const dir = require("path").dirname(path);
325
+ fs.mkdirSync(dir, { recursive: true });
326
+ this.fileStream = fs.createWriteStream(path, { flags: "a" });
327
+ } catch {
407
328
  }
408
329
  }
409
- /**
410
- * Redact sensitive keys from context object (for browser)
411
- */
330
+ isEnabled(level) {
331
+ return LEVEL_ORDER[level] >= LEVEL_ORDER[this.config.level];
332
+ }
412
333
  redactSensitive(obj) {
413
334
  if (!obj || typeof obj !== "object") return obj;
414
335
  const redacted = Array.isArray(obj) ? [...obj] : { ...obj };
415
336
  for (const key in redacted) {
416
- const lowerKey = key.toLowerCase();
417
- const shouldRedact = this.config.redact.some(
418
- (pattern) => lowerKey.includes(pattern.toLowerCase())
419
- );
420
- if (shouldRedact) {
337
+ const lower = key.toLowerCase();
338
+ if (this.config.redact.some((p) => lower.includes(p.toLowerCase()))) {
421
339
  redacted[key] = "***REDACTED***";
422
340
  } else if (typeof redacted[key] === "object" && redacted[key] !== null) {
423
341
  redacted[key] = this.redactSensitive(redacted[key]);
@@ -425,146 +343,89 @@ var ObjectLogger = class _ObjectLogger {
425
343
  }
426
344
  return redacted;
427
345
  }
428
- /**
429
- * Format log entry for browser
430
- */
431
- formatBrowserLog(level, message, context) {
346
+ write(level, message, meta, error) {
347
+ if (!this.isEnabled(level)) return;
348
+ const context = this.redactSensitive({
349
+ ...this.bindings,
350
+ ...meta,
351
+ ...error ? { error: { message: error.message, stack: error.stack } } : {}
352
+ });
353
+ const hasContext = Object.keys(context).length > 0;
354
+ const ts = (/* @__PURE__ */ new Date()).toISOString();
355
+ let line;
432
356
  if (this.config.format === "json") {
433
- return JSON.stringify({
434
- timestamp: (/* @__PURE__ */ new Date()).toISOString(),
357
+ line = JSON.stringify({
358
+ time: ts,
435
359
  level,
436
- message,
360
+ ...this.config.name ? { name: this.config.name } : {},
361
+ msg: message,
437
362
  ...context
438
363
  });
439
- }
440
- if (this.config.format === "text") {
441
- const parts = [(/* @__PURE__ */ new Date()).toISOString(), level.toUpperCase(), message];
442
- if (context && Object.keys(context).length > 0) {
443
- parts.push(JSON.stringify(context));
364
+ } else if (this.config.format === "text") {
365
+ const parts = [ts, level.toUpperCase(), message];
366
+ if (hasContext) parts.push(JSON.stringify(context));
367
+ line = parts.join(" | ");
368
+ } else {
369
+ const color = LEVEL_COLORS[level] || "";
370
+ const label = this.config.name ? `[${this.config.name}] ` : "";
371
+ line = `${color}${ts} ${level.toUpperCase()}${RESET} ${label}${message}`;
372
+ if (hasContext) line += ` ${JSON.stringify(context)}`;
373
+ }
374
+ const out = line + "\n";
375
+ if (typeof process !== "undefined" && process.stderr) {
376
+ if (level === "error" || level === "fatal") {
377
+ process.stderr.write(out);
378
+ } else {
379
+ process.stdout?.write(out);
444
380
  }
445
- return parts.join(" | ");
446
- }
447
- const levelColors = {
448
- debug: "\x1B[36m",
449
- // Cyan
450
- info: "\x1B[32m",
451
- // Green
452
- warn: "\x1B[33m",
453
- // Yellow
454
- error: "\x1B[31m",
455
- // Red
456
- fatal: "\x1B[35m",
457
- // Magenta
458
- silent: ""
459
- };
460
- const reset = "\x1B[0m";
461
- const color = levelColors[level] || "";
462
- let output = `${color}[${level.toUpperCase()}]${reset} ${message}`;
463
- if (context && Object.keys(context).length > 0) {
464
- output += ` ${JSON.stringify(context, null, 2)}`;
381
+ } else if (typeof console !== "undefined") {
382
+ const fn = level === "error" || level === "fatal" ? console.error : level === "warn" ? console.warn : level === "debug" ? console.debug : console.log;
383
+ fn(line);
384
+ }
385
+ if (this.fileStream) {
386
+ this.fileStream.write(out);
465
387
  }
466
- return output;
467
- }
468
- /**
469
- * Log using browser console
470
- */
471
- logBrowser(level, message, context, error) {
472
- const redactedContext = context ? this.redactSensitive(context) : void 0;
473
- const mergedContext = error ? { ...redactedContext, error: { message: error.message, stack: error.stack } } : redactedContext;
474
- const formatted = this.formatBrowserLog(level, message, mergedContext);
475
- const consoleMethod = level === "debug" ? "debug" : level === "info" ? "log" : level === "warn" ? "warn" : level === "error" || level === "fatal" ? "error" : "log";
476
- console[consoleMethod](formatted);
477
388
  }
478
- /**
479
- * Public logging methods
480
- */
481
389
  debug(message, meta) {
482
- if (this.isNode && this.pinoLogger) {
483
- this.pinoLogger.debug(meta || {}, message);
484
- } else {
485
- this.logBrowser("debug", message, meta);
486
- }
390
+ this.write("debug", message, meta);
487
391
  }
488
392
  info(message, meta) {
489
- if (this.isNode && this.pinoLogger) {
490
- this.pinoLogger.info(meta || {}, message);
491
- } else {
492
- this.logBrowser("info", message, meta);
493
- }
393
+ this.write("info", message, meta);
494
394
  }
495
395
  warn(message, meta) {
496
- if (this.isNode && this.pinoLogger) {
497
- this.pinoLogger.warn(meta || {}, message);
498
- } else {
499
- this.logBrowser("warn", message, meta);
500
- }
396
+ this.write("warn", message, meta);
501
397
  }
502
398
  error(message, errorOrMeta, meta) {
503
- let error;
504
- let context = {};
505
399
  if (errorOrMeta instanceof Error) {
506
- error = errorOrMeta;
507
- context = meta || {};
508
- } else {
509
- context = errorOrMeta || {};
510
- }
511
- if (this.isNode && this.pinoLogger) {
512
- const errorContext = error ? { err: error, ...context } : context;
513
- this.pinoLogger.error(errorContext, message);
400
+ this.write("error", message, meta, errorOrMeta);
514
401
  } else {
515
- this.logBrowser("error", message, context, error);
402
+ this.write("error", message, errorOrMeta);
516
403
  }
517
404
  }
518
405
  fatal(message, errorOrMeta, meta) {
519
- let error;
520
- let context = {};
521
406
  if (errorOrMeta instanceof Error) {
522
- error = errorOrMeta;
523
- context = meta || {};
524
- } else {
525
- context = errorOrMeta || {};
526
- }
527
- if (this.isNode && this.pinoLogger) {
528
- const errorContext = error ? { err: error, ...context } : context;
529
- this.pinoLogger.fatal(errorContext, message);
407
+ this.write("fatal", message, meta, errorOrMeta);
530
408
  } else {
531
- this.logBrowser("fatal", message, context, error);
409
+ this.write("fatal", message, errorOrMeta);
532
410
  }
533
411
  }
534
- /**
535
- * Create a child logger with additional context
536
- * Note: Child loggers share the parent's Pino instance
537
- */
412
+ log(message, ...args) {
413
+ this.info(message, args.length > 0 ? { args } : void 0);
414
+ }
538
415
  child(context) {
539
- const childLogger = new _ObjectLogger(this.config);
540
- if (this.isNode && this.pinoInstance) {
541
- childLogger.pinoLogger = this.pinoInstance.child(context);
542
- childLogger.pinoInstance = this.pinoInstance;
543
- }
544
- return childLogger;
416
+ const child = new _ObjectLogger(this.config, { ...this.bindings, ...context });
417
+ child.fileStream = this.fileStream;
418
+ return child;
545
419
  }
546
- /**
547
- * Set trace context for distributed tracing
548
- */
549
420
  withTrace(traceId, spanId) {
550
421
  return this.child({ traceId, spanId });
551
422
  }
552
- /**
553
- * Cleanup resources
554
- */
555
423
  async destroy() {
556
- if (this.pinoLogger && this.pinoLogger.flush) {
557
- await new Promise((resolve) => {
558
- this.pinoLogger.flush(() => resolve());
559
- });
424
+ if (this.fileStream) {
425
+ await new Promise((resolve) => this.fileStream.end(resolve));
426
+ this.fileStream = void 0;
560
427
  }
561
428
  }
562
- /**
563
- * Compatibility method for console.log usage
564
- */
565
- log(message, ...args) {
566
- this.info(message, args.length > 0 ? { args } : void 0);
567
- }
568
429
  };
569
430
  function createLogger(config) {
570
431
  return new ObjectLogger(config);
@@ -985,13 +846,13 @@ var PluginLoader = class {
985
846
  const scope = this.scopedServices.get(scopeId);
986
847
  let instance = scope.get(registration.name);
987
848
  if (!instance) {
988
- instance = await this.createServiceInstance(registration);
849
+ instance = await this.createServiceInstance(registration, scopeId);
989
850
  scope.set(registration.name, instance);
990
851
  this.logger.debug(`Scoped service created: ${registration.name} (scope: ${scopeId})`);
991
852
  }
992
853
  return instance;
993
854
  }
994
- async createServiceInstance(registration) {
855
+ async createServiceInstance(registration, scopeId) {
995
856
  if (!this.context) {
996
857
  throw new Error(`[PluginLoader] Context not set - cannot create service '${registration.name}'`);
997
858
  }
@@ -1000,13 +861,39 @@ var PluginLoader = class {
1000
861
  }
1001
862
  this.creating.add(registration.name);
1002
863
  try {
1003
- return await registration.factory(this.context);
864
+ return await registration.factory(this.context, scopeId);
1004
865
  } finally {
1005
866
  this.creating.delete(registration.name);
1006
867
  }
1007
868
  }
1008
869
  };
1009
870
 
871
+ // src/utils/env.ts
872
+ var isNode = typeof process !== "undefined" && process.versions != null && process.versions.node != null;
873
+ function getEnv(key, defaultValue) {
874
+ if (typeof process !== "undefined" && process.env) {
875
+ return process.env[key] || defaultValue;
876
+ }
877
+ try {
878
+ if (typeof globalThis !== "undefined" && globalThis.process?.env) {
879
+ return globalThis.process.env[key] || defaultValue;
880
+ }
881
+ } catch (e) {
882
+ }
883
+ return defaultValue;
884
+ }
885
+ function safeExit(code = 0) {
886
+ if (isNode) {
887
+ process.exit(code);
888
+ }
889
+ }
890
+ function getMemoryUsage() {
891
+ if (isNode) {
892
+ return process.memoryUsage();
893
+ }
894
+ return { heapUsed: 0, heapTotal: 0 };
895
+ }
896
+
1010
897
  // src/fallbacks/memory-cache.ts
1011
898
  function createMemoryCache() {
1012
899
  const store = /* @__PURE__ */ new Map();
@@ -1097,6 +984,22 @@ function createMemoryJob() {
1097
984
  }
1098
985
 
1099
986
  // src/fallbacks/memory-i18n.ts
987
+ function deepMerge(target, source) {
988
+ const result = { ...target };
989
+ for (const key of Object.keys(source)) {
990
+ const tVal = target[key];
991
+ const sVal = source[key];
992
+ if (tVal && sVal && typeof tVal === "object" && !Array.isArray(tVal) && typeof sVal === "object" && !Array.isArray(sVal)) {
993
+ result[key] = deepMerge(
994
+ tVal,
995
+ sVal
996
+ );
997
+ } else {
998
+ result[key] = sVal;
999
+ }
1000
+ }
1001
+ return result;
1002
+ }
1100
1003
  function resolveLocale(requestedLocale, availableLocales) {
1101
1004
  if (availableLocales.length === 0) return void 0;
1102
1005
  if (availableLocales.includes(requestedLocale)) return requestedLocale;
@@ -1142,8 +1045,12 @@ function createMemoryI18n() {
1142
1045
  return resolveTranslations(locale) ?? {};
1143
1046
  },
1144
1047
  loadTranslations(locale, data) {
1145
- const existing = translations.get(locale) ?? {};
1146
- translations.set(locale, { ...existing, ...data });
1048
+ const existing = translations.get(locale);
1049
+ if (existing) {
1050
+ translations.set(locale, deepMerge(existing, data));
1051
+ } else {
1052
+ translations.set(locale, { ...data });
1053
+ }
1147
1054
  },
1148
1055
  getLocales() {
1149
1056
  return [...translations.keys()];
@@ -1232,6 +1139,9 @@ var ObjectKernel = class {
1232
1139
  registerService: (name, service) => {
1233
1140
  this.registerService(name, service);
1234
1141
  },
1142
+ registerServiceFactory: (name, factory, lifecycle, dependencies) => {
1143
+ this.registerServiceFactory(name, factory, lifecycle, dependencies);
1144
+ },
1235
1145
  getService: (name) => {
1236
1146
  const service = this.services.get(name);
1237
1147
  if (service) {
@@ -1285,6 +1195,9 @@ var ObjectKernel = class {
1285
1195
  getServices: () => {
1286
1196
  return new Map(this.services);
1287
1197
  },
1198
+ getServiceScoped: (name, scopeId) => {
1199
+ return this.pluginLoader.getService(name, scopeId);
1200
+ },
1288
1201
  logger: this.logger,
1289
1202
  getKernel: () => this
1290
1203
  // Type compatibility
@@ -1426,6 +1339,7 @@ var ObjectKernel = class {
1426
1339
  const result = await this.startPluginWithTimeout(plugin);
1427
1340
  if (!result.success) {
1428
1341
  this.logger.error(`Plugin startup failed: ${plugin.name}`, result.error);
1342
+ console.error(`[Kernel] Plugin startup failed: ${plugin.name}`, result.error instanceof Error ? result.error.message : result.error, result.error instanceof Error ? result.error.stack : "");
1429
1343
  if (this.config.rollbackOnFailure) {
1430
1344
  this.logger.warn("Rolling back started plugins...");
1431
1345
  await this.rollbackStartedPlugins();
@@ -1458,17 +1372,19 @@ var ObjectKernel = class {
1458
1372
  try {
1459
1373
  const shutdownPromise = this.performShutdown();
1460
1374
  const timeoutPromise = new Promise((_, reject) => {
1461
- setTimeout(() => {
1375
+ const t = setTimeout(() => {
1462
1376
  reject(new Error("Shutdown timeout exceeded"));
1463
1377
  }, this.config.shutdownTimeout);
1378
+ if (t.unref) t.unref();
1464
1379
  });
1465
1380
  await Promise.race([shutdownPromise, timeoutPromise]);
1466
1381
  this.state = "stopped";
1467
1382
  this.logger.info("\u2705 Graceful shutdown complete");
1468
1383
  } catch (error) {
1469
- this.logger.error("Shutdown error - forcing stop", error);
1384
+ this.logger.error("Shutdown timed out \u2014 forcing exit", error);
1470
1385
  this.state = "stopped";
1471
- throw error;
1386
+ await this.logger.destroy();
1387
+ process.exit(1);
1472
1388
  } finally {
1473
1389
  await this.logger.destroy();
1474
1390
  }
@@ -1508,6 +1424,13 @@ var ObjectKernel = class {
1508
1424
  async getServiceAsync(name, scopeId) {
1509
1425
  return await this.pluginLoader.getService(name, scopeId);
1510
1426
  }
1427
+ /**
1428
+ * Clear all scoped service instances for a given scope (e.g., projectId).
1429
+ * Releases driver connections and metadata caches for idle projects.
1430
+ */
1431
+ clearScope(scopeId) {
1432
+ this.pluginLoader.clearScope(scopeId);
1433
+ }
1511
1434
  /**
1512
1435
  * Check if kernel is running
1513
1436
  */
@@ -3087,6 +3010,12 @@ var SecurePluginContext = class {
3087
3010
  getKernel() {
3088
3011
  return this.baseContext.getKernel();
3089
3012
  }
3013
+ registerServiceFactory(name, factory, lifecycle, dependencies) {
3014
+ this.baseContext.registerServiceFactory(name, factory, lifecycle, dependencies);
3015
+ }
3016
+ getServiceScoped(name, scopeId) {
3017
+ return this.baseContext.getServiceScoped(name, scopeId);
3018
+ }
3090
3019
  };
3091
3020
  function createPluginPermissionEnforcer(logger) {
3092
3021
  return new PluginPermissionEnforcer(logger);
@@ -4756,272 +4685,6 @@ var NamespaceResolver = class {
4756
4685
  return `${shortName}_${ns}`;
4757
4686
  }
4758
4687
  };
4759
-
4760
- // src/package-manager.ts
4761
- var PackageManager = class {
4762
- constructor(logger, options = {}) {
4763
- this.packages = /* @__PURE__ */ new Map();
4764
- this.snapshots = /* @__PURE__ */ new Map();
4765
- this.logger = logger.child({ component: "PackageManager" });
4766
- this.dependencyResolver = new DependencyResolver(logger);
4767
- this.namespaceResolver = new NamespaceResolver(logger);
4768
- this.platformVersion = options.platformVersion || "3.0.0";
4769
- }
4770
- /**
4771
- * Install a package with full dependency resolution and namespace checking.
4772
- */
4773
- async install(packageId, version, manifest) {
4774
- this.logger.info("Installing package", { packageId, version });
4775
- if (this.packages.has(packageId)) {
4776
- const existing = this.packages.get(packageId);
4777
- if (existing.status === "installed") {
4778
- return {
4779
- success: false,
4780
- packageId,
4781
- version,
4782
- installedDependencies: [],
4783
- namespaceConflicts: [],
4784
- errorMessage: `Package ${packageId}@${existing.version} is already installed. Use upgrade instead.`
4785
- };
4786
- }
4787
- }
4788
- const engine = manifest.engine?.objectstack;
4789
- if (engine) {
4790
- const platformSemver = SemanticVersionManager.parse(this.platformVersion);
4791
- if (!SemanticVersionManager.satisfies(platformSemver, engine)) {
4792
- return {
4793
- success: false,
4794
- packageId,
4795
- version,
4796
- installedDependencies: [],
4797
- namespaceConflicts: [],
4798
- errorMessage: `Package requires platform ${engine}, but current platform is v${this.platformVersion}`
4799
- };
4800
- }
4801
- }
4802
- const namespaces = this.namespaceResolver.extractNamespaces(manifest);
4803
- const nsCheck = this.namespaceResolver.checkAvailability(packageId, namespaces);
4804
- if (!nsCheck.available) {
4805
- return {
4806
- success: false,
4807
- packageId,
4808
- version,
4809
- installedDependencies: [],
4810
- namespaceConflicts: nsCheck.conflicts.map((c) => ({
4811
- namespace: c.namespace,
4812
- existingPackageId: c.existingPackageId
4813
- })),
4814
- errorMessage: `Namespace conflicts detected: ${nsCheck.conflicts.map((c) => c.namespace).join(", ")}`
4815
- };
4816
- }
4817
- const deps = manifest.dependencies;
4818
- const depNames = deps ? Object.keys(deps) : [];
4819
- const missingDeps = depNames.filter((d) => !this.packages.has(d));
4820
- if (missingDeps.length > 0) {
4821
- return {
4822
- success: false,
4823
- packageId,
4824
- version,
4825
- installedDependencies: [],
4826
- namespaceConflicts: [],
4827
- errorMessage: `Missing dependencies: ${missingDeps.join(", ")}`
4828
- };
4829
- }
4830
- this.packages.set(packageId, {
4831
- packageId,
4832
- version,
4833
- manifest,
4834
- installedAt: (/* @__PURE__ */ new Date()).toISOString(),
4835
- status: "installed",
4836
- namespaces,
4837
- dependencies: depNames
4838
- });
4839
- this.namespaceResolver.register(packageId, namespaces);
4840
- this.logger.info("Package installed", { packageId, version, namespaces: namespaces.length });
4841
- return {
4842
- success: true,
4843
- packageId,
4844
- version,
4845
- installedDependencies: depNames,
4846
- namespaceConflicts: []
4847
- };
4848
- }
4849
- /**
4850
- * Uninstall a package, checking for dependents first.
4851
- */
4852
- async uninstall(packageId) {
4853
- const pkg = this.packages.get(packageId);
4854
- if (!pkg) {
4855
- return { success: false, errorMessage: `Package ${packageId} is not installed` };
4856
- }
4857
- const dependents = [];
4858
- for (const [id, record] of this.packages) {
4859
- if (id !== packageId && record.dependencies.includes(packageId)) {
4860
- dependents.push(id);
4861
- }
4862
- }
4863
- if (dependents.length > 0) {
4864
- return {
4865
- success: false,
4866
- errorMessage: `Cannot uninstall ${packageId}: depended upon by ${dependents.join(", ")}`
4867
- };
4868
- }
4869
- this.namespaceResolver.unregister(packageId);
4870
- this.packages.delete(packageId);
4871
- this.snapshots.delete(packageId);
4872
- this.logger.info("Package uninstalled", { packageId });
4873
- return { success: true };
4874
- }
4875
- /**
4876
- * Upgrade a package: snapshot → update → register.
4877
- */
4878
- async upgrade(packageId, newVersion, newManifest) {
4879
- const existing = this.packages.get(packageId);
4880
- if (!existing) {
4881
- return {
4882
- success: false,
4883
- packageId,
4884
- fromVersion: "",
4885
- toVersion: newVersion,
4886
- snapshot: { packageId, previousVersion: "", previousManifest: {}, previousNamespaces: [], installedAt: "", createdAt: (/* @__PURE__ */ new Date()).toISOString() },
4887
- errorMessage: `Package ${packageId} is not installed`
4888
- };
4889
- }
4890
- const snapshot = {
4891
- packageId,
4892
- previousVersion: existing.version,
4893
- previousManifest: existing.manifest,
4894
- previousNamespaces: [...existing.namespaces],
4895
- installedAt: existing.installedAt,
4896
- createdAt: (/* @__PURE__ */ new Date()).toISOString()
4897
- };
4898
- this.snapshots.set(packageId, snapshot);
4899
- const engine = newManifest.engine?.objectstack;
4900
- if (engine) {
4901
- const platformSemver = SemanticVersionManager.parse(this.platformVersion);
4902
- if (!SemanticVersionManager.satisfies(platformSemver, engine)) {
4903
- return {
4904
- success: false,
4905
- packageId,
4906
- fromVersion: existing.version,
4907
- toVersion: newVersion,
4908
- snapshot,
4909
- errorMessage: `New version requires platform ${engine}, current is v${this.platformVersion}`
4910
- };
4911
- }
4912
- }
4913
- const newNamespaces = this.namespaceResolver.extractNamespaces(newManifest);
4914
- this.namespaceResolver.unregister(packageId);
4915
- const nsCheck = this.namespaceResolver.checkAvailability(packageId, newNamespaces);
4916
- if (!nsCheck.available) {
4917
- this.namespaceResolver.register(packageId, existing.namespaces);
4918
- return {
4919
- success: false,
4920
- packageId,
4921
- fromVersion: existing.version,
4922
- toVersion: newVersion,
4923
- snapshot,
4924
- errorMessage: `Namespace conflicts in new version: ${nsCheck.conflicts.map((c) => c.namespace).join(", ")}`
4925
- };
4926
- }
4927
- this.namespaceResolver.register(packageId, newNamespaces);
4928
- const deps = newManifest.dependencies;
4929
- this.packages.set(packageId, {
4930
- packageId,
4931
- version: newVersion,
4932
- manifest: newManifest,
4933
- installedAt: existing.installedAt,
4934
- status: "installed",
4935
- namespaces: newNamespaces,
4936
- dependencies: deps ? Object.keys(deps) : []
4937
- });
4938
- this.logger.info("Package upgraded", { packageId, from: existing.version, to: newVersion });
4939
- return {
4940
- success: true,
4941
- packageId,
4942
- fromVersion: existing.version,
4943
- toVersion: newVersion,
4944
- snapshot
4945
- };
4946
- }
4947
- /**
4948
- * Rollback a package to its pre-upgrade snapshot.
4949
- */
4950
- async rollback(packageId) {
4951
- const snapshot = this.snapshots.get(packageId);
4952
- if (!snapshot) {
4953
- return {
4954
- success: false,
4955
- packageId,
4956
- restoredVersion: "",
4957
- errorMessage: `No upgrade snapshot found for ${packageId}`
4958
- };
4959
- }
4960
- this.namespaceResolver.unregister(packageId);
4961
- this.namespaceResolver.register(packageId, snapshot.previousNamespaces);
4962
- const deps = snapshot.previousManifest.dependencies;
4963
- this.packages.set(packageId, {
4964
- packageId,
4965
- version: snapshot.previousVersion,
4966
- manifest: snapshot.previousManifest,
4967
- installedAt: snapshot.installedAt,
4968
- status: "installed",
4969
- namespaces: snapshot.previousNamespaces,
4970
- dependencies: deps ? Object.keys(deps) : []
4971
- });
4972
- this.snapshots.delete(packageId);
4973
- this.logger.info("Package rolled back", { packageId, to: snapshot.previousVersion });
4974
- return {
4975
- success: true,
4976
- packageId,
4977
- restoredVersion: snapshot.previousVersion
4978
- };
4979
- }
4980
- /**
4981
- * Get an installed package record.
4982
- */
4983
- getPackage(packageId) {
4984
- return this.packages.get(packageId);
4985
- }
4986
- /**
4987
- * List all installed packages.
4988
- */
4989
- listPackages() {
4990
- return Array.from(this.packages.values());
4991
- }
4992
- /**
4993
- * Resolve dependencies for a set of packages.
4994
- */
4995
- resolveDependencies(packages) {
4996
- return this.dependencyResolver.resolve(packages);
4997
- }
4998
- /**
4999
- * Check namespace availability for a package's metadata.
5000
- */
5001
- checkNamespaces(packageId, config) {
5002
- const namespaces = this.namespaceResolver.extractNamespaces(config);
5003
- const result = this.namespaceResolver.checkAvailability(packageId, namespaces);
5004
- return {
5005
- available: result.available,
5006
- conflicts: result.conflicts.map((c) => ({
5007
- namespace: c.namespace,
5008
- existingPackageId: c.existingPackageId
5009
- }))
5010
- };
5011
- }
5012
- /**
5013
- * Get the namespace resolver instance.
5014
- */
5015
- getNamespaceResolver() {
5016
- return this.namespaceResolver;
5017
- }
5018
- /**
5019
- * Get a snapshot for a given package (if available).
5020
- */
5021
- getSnapshot(packageId) {
5022
- return this.snapshots.get(packageId);
5023
- }
5024
- };
5025
4688
  // Annotate the CommonJS export names for ESM import in node:
5026
4689
  0 && (module.exports = {
5027
4690
  ApiRegistry,
@@ -5033,7 +4696,6 @@ var PackageManager = class {
5033
4696
  ObjectKernel,
5034
4697
  ObjectKernelBase,
5035
4698
  ObjectLogger,
5036
- PackageManager,
5037
4699
  PluginConfigValidator,
5038
4700
  PluginHealthMonitor,
5039
4701
  PluginLoader,