@moostjs/vite 0.6.29 → 0.6.30

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -389,11 +389,24 @@ function moostVite(options) {
389
389
  const prefixes = normalizePrefixes(options.prefix);
390
390
  let moostMiddleware = null;
391
391
  let localFetchTeardown = null;
392
+ /**
393
+ * Boot-identity stamps (dev-only "mongrel state" diagnostic — a stale pipeline
394
+ * presents as security middleware silently switched off). `bootGeneration` is
395
+ * bumped on every eject; `bootingGeneration` records which generation the
396
+ * in-flight/most recent boot belongs to (set by runReload). When listen()
397
+ * captures a middleware for a boot that is no longer current — e.g. a delayed
398
+ * listen() from a torn boot racing a newer eject — it logs loudly.
399
+ */ let bootGeneration = 0;
400
+ let bootingGeneration = 0;
401
+ /** Whether the HTTP listen() patch has ever captured a middleware (i.e. this is an HTTP app). */ let httpCaptured = false;
402
+ /** Module IDs awaiting DI cleanup — consumed in runReload; see ejectApp. */ let pendingCleanup = null;
392
403
  /** In middleware mode: maps req → next() for the onNoMatch callback */ const pendingNextMap = /* @__PURE__ */ new WeakMap();
393
404
  const adapters = isTest ? [] : [
394
405
  createAdapterDetector("http", (MoostHttp, moduleExports) => {
395
406
  MoostHttp.prototype.listen = function(...args) {
396
407
  logger.log(`🔌 Overtaking HTTP.listen`);
408
+ if (bootingGeneration !== bootGeneration) logger.error(`⚠️ A stale Moost boot captured the HTTP middleware (boot generation ${bootingGeneration}, latest ${bootGeneration}) — an HMR reload race; a follow-up reload will replace it.`);
409
+ httpCaptured = true;
397
410
  if (options.middleware) moostMiddleware = this.getServerCb((req) => {
398
411
  pendingNextMap.get(req)?.();
399
412
  });
@@ -433,15 +446,23 @@ function moostVite(options) {
433
446
  */ const getEntryModule = (moduleGraph) => moduleGraph.getModuleByUrl(options.entry);
434
447
  /**
435
448
  * Drops the captured Moost app so the next request triggers a full reload:
436
- * releases the middleware + local fetch and ejects DI instances affected by
437
- * the changed modules.
449
+ * releases the middleware + local fetch and queues the changed module IDs for
450
+ * DI cleanup. The cleanup itself (infact ejects, wooks reset) is deferred to
451
+ * runReload, under the reload lock: running it here, per hot-update wave,
452
+ * raced in-flight requests and mid-boot imports mutating the same global
453
+ * containers — ejected-but-still-referenced instances were lazily re-created
454
+ * into the OLD pipeline, producing a mongrel half-old/half-new app. Waves
455
+ * arriving before the lazy reload (editor bulk-save storms) coalesce into one
456
+ * pending set and one cleanup.
438
457
  */ const ejectApp = (cleanupInstances) => {
458
+ bootGeneration++;
439
459
  moostMiddleware = null;
440
460
  if (localFetchTeardown) {
441
461
  localFetchTeardown();
442
462
  localFetchTeardown = null;
443
463
  }
444
- moostRestartCleanup(adapters, options.onEject, cleanupInstances);
464
+ if (pendingCleanup) for (const id of cleanupInstances) pendingCleanup.add(id);
465
+ else pendingCleanup = cleanupInstances;
445
466
  reloadRequired = true;
446
467
  };
447
468
  patchMoostHandlerLogging();
@@ -595,6 +616,8 @@ function moostVite(options) {
595
616
  bootError = null;
596
617
  reloadRequired = false;
597
618
  reloadPromise = null;
619
+ pendingCleanup = null;
620
+ bootingGeneration = bootGeneration;
598
621
  const runReload = () => {
599
622
  reloadRequired = false;
600
623
  console.log();
@@ -602,11 +625,16 @@ function moostVite(options) {
602
625
  console.log();
603
626
  return (async () => {
604
627
  try {
628
+ bootingGeneration = bootGeneration;
629
+ const cleanupInstances = pendingCleanup ?? void 0;
630
+ pendingCleanup = null;
631
+ moostRestartCleanup(adapters, options.onEject, cleanupInstances);
605
632
  for (const adapter of adapters) if (adapter.detected) await adapter.init();
606
633
  const entryModule = await getEntryModule(server.environments.ssr.moduleGraph);
607
634
  if (entryModule?.transformResult) server.environments.ssr.moduleGraph.invalidateModule(entryModule);
608
635
  await ssrImport(options.entry);
609
636
  bootError = null;
637
+ if (httpCaptured && !moostMiddleware) logger.error(`⚠️ Moost app reloaded but no HTTP middleware was captured — the entry did not re-run listen().`);
610
638
  } catch (error) {
611
639
  bootError = error;
612
640
  logger.error(`✖️ Failed to reload Moost App: ${error.message}`);
package/dist/index.mjs CHANGED
@@ -358,11 +358,24 @@ function moostVite(options) {
358
358
  const prefixes = normalizePrefixes(options.prefix);
359
359
  let moostMiddleware = null;
360
360
  let localFetchTeardown = null;
361
+ /**
362
+ * Boot-identity stamps (dev-only "mongrel state" diagnostic — a stale pipeline
363
+ * presents as security middleware silently switched off). `bootGeneration` is
364
+ * bumped on every eject; `bootingGeneration` records which generation the
365
+ * in-flight/most recent boot belongs to (set by runReload). When listen()
366
+ * captures a middleware for a boot that is no longer current — e.g. a delayed
367
+ * listen() from a torn boot racing a newer eject — it logs loudly.
368
+ */ let bootGeneration = 0;
369
+ let bootingGeneration = 0;
370
+ /** Whether the HTTP listen() patch has ever captured a middleware (i.e. this is an HTTP app). */ let httpCaptured = false;
371
+ /** Module IDs awaiting DI cleanup — consumed in runReload; see ejectApp. */ let pendingCleanup = null;
361
372
  /** In middleware mode: maps req → next() for the onNoMatch callback */ const pendingNextMap = /* @__PURE__ */ new WeakMap();
362
373
  const adapters = [
363
374
  createAdapterDetector("http", (MoostHttp, moduleExports) => {
364
375
  MoostHttp.prototype.listen = function(...args) {
365
376
  logger.log(`🔌 Overtaking HTTP.listen`);
377
+ if (bootingGeneration !== bootGeneration) logger.error(`⚠️ A stale Moost boot captured the HTTP middleware (boot generation ${bootingGeneration}, latest ${bootGeneration}) — an HMR reload race; a follow-up reload will replace it.`);
378
+ httpCaptured = true;
366
379
  if (options.middleware) moostMiddleware = this.getServerCb((req) => {
367
380
  pendingNextMap.get(req)?.();
368
381
  });
@@ -402,15 +415,23 @@ function moostVite(options) {
402
415
  */ const getEntryModule = (moduleGraph) => moduleGraph.getModuleByUrl(options.entry);
403
416
  /**
404
417
  * Drops the captured Moost app so the next request triggers a full reload:
405
- * releases the middleware + local fetch and ejects DI instances affected by
406
- * the changed modules.
418
+ * releases the middleware + local fetch and queues the changed module IDs for
419
+ * DI cleanup. The cleanup itself (infact ejects, wooks reset) is deferred to
420
+ * runReload, under the reload lock: running it here, per hot-update wave,
421
+ * raced in-flight requests and mid-boot imports mutating the same global
422
+ * containers — ejected-but-still-referenced instances were lazily re-created
423
+ * into the OLD pipeline, producing a mongrel half-old/half-new app. Waves
424
+ * arriving before the lazy reload (editor bulk-save storms) coalesce into one
425
+ * pending set and one cleanup.
407
426
  */ const ejectApp = (cleanupInstances) => {
427
+ bootGeneration++;
408
428
  moostMiddleware = null;
409
429
  if (localFetchTeardown) {
410
430
  localFetchTeardown();
411
431
  localFetchTeardown = null;
412
432
  }
413
- moostRestartCleanup(adapters, options.onEject, cleanupInstances);
433
+ if (pendingCleanup) for (const id of cleanupInstances) pendingCleanup.add(id);
434
+ else pendingCleanup = cleanupInstances;
414
435
  reloadRequired = true;
415
436
  };
416
437
  patchMoostHandlerLogging();
@@ -564,6 +585,8 @@ function moostVite(options) {
564
585
  bootError = null;
565
586
  reloadRequired = false;
566
587
  reloadPromise = null;
588
+ pendingCleanup = null;
589
+ bootingGeneration = bootGeneration;
567
590
  const runReload = () => {
568
591
  reloadRequired = false;
569
592
  console.log();
@@ -571,11 +594,16 @@ function moostVite(options) {
571
594
  console.log();
572
595
  return (async () => {
573
596
  try {
597
+ bootingGeneration = bootGeneration;
598
+ const cleanupInstances = pendingCleanup ?? void 0;
599
+ pendingCleanup = null;
600
+ moostRestartCleanup(adapters, options.onEject, cleanupInstances);
574
601
  for (const adapter of adapters) if (adapter.detected) await adapter.init();
575
602
  const entryModule = await getEntryModule(server.environments.ssr.moduleGraph);
576
603
  if (entryModule?.transformResult) server.environments.ssr.moduleGraph.invalidateModule(entryModule);
577
604
  await ssrImport(options.entry);
578
605
  bootError = null;
606
+ if (httpCaptured && !moostMiddleware) logger.error(`⚠️ Moost app reloaded but no HTTP middleware was captured — the entry did not re-run listen().`);
579
607
  } catch (error) {
580
608
  bootError = error;
581
609
  logger.error(`✖️ Failed to reload Moost App: ${error.message}`);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@moostjs/vite",
3
- "version": "0.6.29",
3
+ "version": "0.6.30",
4
4
  "description": "Vite Dev plugin for moostjs",
5
5
  "keywords": [
6
6
  "composables",
@@ -58,8 +58,8 @@
58
58
  "peerDependencies": {
59
59
  "sirv": "^3.0.0",
60
60
  "vite": "^8.0.0",
61
- "@moostjs/event-http": "^0.6.29",
62
- "moost": "^0.6.29"
61
+ "@moostjs/event-http": "^0.6.30",
62
+ "moost": "^0.6.30"
63
63
  },
64
64
  "peerDependenciesMeta": {
65
65
  "sirv": {