kitchen-simulator 5.10.9-react.18 → 5.10.10-react.18

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 (2) hide show
  1. package/es/index.js +268 -293
  2. package/package.json +1 -1
package/es/index.js CHANGED
@@ -21,13 +21,6 @@ import LiteRenderer from "./LiteRenderer";
21
21
  import { createRoot } from 'react-dom/client';
22
22
  var ROOT_KEY = '__kitchenSimulatorRoot__';
23
23
  var API_KEY = '__kitchenSimulatorApi__';
24
-
25
- /**
26
- * Debug logging
27
- * - Enable via:
28
- * - window.__kitchenSimulatorDebug__ = true
29
- * - or pass props.debug = true to renderKitchenSimulator(container, { debug: true })
30
- */
31
24
  function makeLogger(getEnabled) {
32
25
  var prefix = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : '[kitchen-simulator]';
33
26
  var now = function now() {
@@ -38,7 +31,6 @@ function makeLogger(getEnabled) {
38
31
  if (v == null) return v;
39
32
  if (typeof v === 'string') return v;
40
33
  if (typeof v === 'number' || typeof v === 'boolean') return v;
41
- // avoid huge logs
42
34
  return JSON.stringify(v, function (k, val) {
43
35
  if (k === 'children' || k === 'parent') return '[omitted]';
44
36
  if (typeof val === 'function') return '[fn]';
@@ -51,7 +43,6 @@ function makeLogger(getEnabled) {
51
43
  var log = function log() {
52
44
  var _console;
53
45
  if (!getEnabled()) return;
54
- // eslint-disable-next-line no-console
55
46
  for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
56
47
  args[_key] = arguments[_key];
57
48
  }
@@ -60,7 +51,6 @@ function makeLogger(getEnabled) {
60
51
  var warn = function warn() {
61
52
  var _console2;
62
53
  if (!getEnabled()) return;
63
- // eslint-disable-next-line no-console
64
54
  for (var _len2 = arguments.length, args = new Array(_len2), _key2 = 0; _key2 < _len2; _key2++) {
65
55
  args[_key2] = arguments[_key2];
66
56
  }
@@ -69,7 +59,6 @@ function makeLogger(getEnabled) {
69
59
  var error = function error() {
70
60
  var _console3;
71
61
  if (!getEnabled()) return;
72
- // eslint-disable-next-line no-console
73
62
  for (var _len3 = arguments.length, args = new Array(_len3), _key3 = 0; _key3 < _len3; _key3++) {
74
63
  args[_key3] = arguments[_key3];
75
64
  }
@@ -81,11 +70,6 @@ function makeLogger(getEnabled) {
81
70
  error: error
82
71
  };
83
72
  }
84
- function nextFrame() {
85
- return new Promise(function (resolve) {
86
- return requestAnimationFrame(resolve);
87
- });
88
- }
89
73
 
90
74
  // DIY-714 [Temp Fix] Rewrite API URLs
91
75
  var API_HOST_REGEX = /(https?:\/\/)?(api\.diydesignspace\.com|api\.addovisuals\.com|127\.0\.0\.1:4002)/;
@@ -159,7 +143,7 @@ function installGltfTracker() {
159
143
  try {
160
144
  var _url$toString, _url$toString2;
161
145
  var s = typeof url === 'string' ? url : (_url$toString = url === null || url === void 0 || (_url$toString2 = url.toString) === null || _url$toString2 === void 0 ? void 0 : _url$toString2.call(url)) !== null && _url$toString !== void 0 ? _url$toString : '';
162
- var u = s.toLowerCase().split('?')[0]; // ignore cache params
146
+ var u = s.toLowerCase().split('?')[0];
163
147
  return u.endsWith('.gltf') || u.endsWith('.glb') || u.endsWith('.bin') || u.endsWith('.ktx2') || u.endsWith('.hdr') || u.endsWith('.exr') || u.endsWith('.png') || u.endsWith('.jpg') || u.endsWith('.jpeg') || u.endsWith('.webp');
164
148
  } catch (_unused2) {
165
149
  return false;
@@ -181,7 +165,7 @@ function installGltfTracker() {
181
165
  };
182
166
  var subscribe = function subscribe(fn) {
183
167
  g.listeners.add(fn);
184
- fn(g.inFlight); // sync emit on subscribe
168
+ fn(g.inFlight);
185
169
  return function () {
186
170
  return g.listeners["delete"](fn);
187
171
  };
@@ -191,7 +175,7 @@ function installGltfTracker() {
191
175
  if (g.installed) return;
192
176
  log('Installing GLTF tracker hooks');
193
177
 
194
- // ---- XHR hook ----
178
+ // XHR hook
195
179
  var XHR = window.XMLHttpRequest;
196
180
  if (XHR !== null && XHR !== void 0 && (_XHR$prototype = XHR.prototype) !== null && _XHR$prototype !== void 0 && _XHR$prototype.open && XHR !== null && XHR !== void 0 && (_XHR$prototype2 = XHR.prototype) !== null && _XHR$prototype2 !== void 0 && _XHR$prototype2.send) {
197
181
  g.originalOpen = XHR.prototype.open;
@@ -199,12 +183,10 @@ function installGltfTracker() {
199
183
  XHR.prototype.open = function (method, url) {
200
184
  var _g$originalOpen;
201
185
  this.__is3dAssetRequest = is3dAssetUrl(url);
202
- if (this.__is3dAssetRequest) {
203
- log('XHR open (3D asset)', {
204
- method: method,
205
- url: url
206
- });
207
- }
186
+ if (this.__is3dAssetRequest) log('XHR open (3D asset)', {
187
+ method: method,
188
+ url: url
189
+ });
208
190
  for (var _len4 = arguments.length, rest = new Array(_len4 > 2 ? _len4 - 2 : 0), _key4 = 2; _key4 < _len4; _key4++) {
209
191
  rest[_key4 - 2] = arguments[_key4];
210
192
  }
@@ -240,7 +222,7 @@ function installGltfTracker() {
240
222
  warn('XHR hooks not installed (missing open/send)');
241
223
  }
242
224
 
243
- // ---- fetch hook ----
225
+ // fetch hook
244
226
  g.originalFetch = window.fetch;
245
227
  if (typeof g.originalFetch === 'function') {
246
228
  window.fetch = /*#__PURE__*/_asyncToGenerator(/*#__PURE__*/_regeneratorRuntime.mark(function _callee2() {
@@ -264,7 +246,7 @@ function installGltfTracker() {
264
246
  for (_len6 = _args2.length, args = new Array(_len6), _key6 = 0; _key6 < _len6; _key6++) {
265
247
  args[_key6] = _args2[_key6];
266
248
  }
267
- input = args[0], init = args[1]; // DIY-714 [Temp Fix] Rewrite API URLs
249
+ input = args[0], init = args[1];
268
250
  if (typeof input === 'string') {
269
251
  input = rewriteApiUrl(input);
270
252
  } else if (input instanceof Request) {
@@ -320,34 +302,51 @@ function installGltfTracker() {
320
302
  }
321
303
  g.installed = true;
322
304
  };
323
-
324
- // “No grace” but stable: idle must remain idle for 2 RAF frames
305
+ function nextFrame() {
306
+ return _nextFrame.apply(this, arguments);
307
+ }
308
+ function _nextFrame() {
309
+ _nextFrame = _asyncToGenerator(/*#__PURE__*/_regeneratorRuntime.mark(function _callee5() {
310
+ return _regeneratorRuntime.wrap(function (_context5) {
311
+ while (1) switch (_context5.prev = _context5.next) {
312
+ case 0:
313
+ return _context5.abrupt("return", new Promise(function (resolve) {
314
+ return requestAnimationFrame(resolve);
315
+ }));
316
+ case 1:
317
+ case "end":
318
+ return _context5.stop();
319
+ }
320
+ }, _callee5);
321
+ }));
322
+ return _nextFrame.apply(this, arguments);
323
+ }
325
324
  function waitStableIdle2Frames() {
326
325
  return _waitStableIdle2Frames.apply(this, arguments);
327
326
  }
328
327
  function _waitStableIdle2Frames() {
329
- _waitStableIdle2Frames = _asyncToGenerator(/*#__PURE__*/_regeneratorRuntime.mark(function _callee5() {
330
- return _regeneratorRuntime.wrap(function (_context5) {
331
- while (1) switch (_context5.prev = _context5.next) {
328
+ _waitStableIdle2Frames = _asyncToGenerator(/*#__PURE__*/_regeneratorRuntime.mark(function _callee6() {
329
+ return _regeneratorRuntime.wrap(function (_context6) {
330
+ while (1) switch (_context6.prev = _context6.next) {
332
331
  case 0:
333
- _context5.next = 1;
332
+ _context6.next = 1;
334
333
  return nextFrame();
335
334
  case 1:
336
335
  if (!(g.inFlight !== 0)) {
337
- _context5.next = 2;
336
+ _context6.next = 2;
338
337
  break;
339
338
  }
340
- return _context5.abrupt("return", false);
339
+ return _context6.abrupt("return", false);
341
340
  case 2:
342
- _context5.next = 3;
341
+ _context6.next = 3;
343
342
  return nextFrame();
344
343
  case 3:
345
- return _context5.abrupt("return", g.inFlight === 0);
344
+ return _context6.abrupt("return", g.inFlight === 0);
346
345
  case 4:
347
346
  case "end":
348
- return _context5.stop();
347
+ return _context6.stop();
349
348
  }
350
- }, _callee5);
349
+ }, _callee6);
351
350
  }));
352
351
  return _waitStableIdle2Frames.apply(this, arguments);
353
352
  }
@@ -365,8 +364,6 @@ function installGltfTracker() {
365
364
  timeoutMs: timeoutMs,
366
365
  inFlight: g.inFlight
367
366
  });
368
-
369
- // Fast path
370
367
  _context4.next = 1;
371
368
  return waitStableIdle2Frames();
372
369
  case 1:
@@ -397,8 +394,6 @@ function installGltfTracker() {
397
394
  error('waitForIdle timeout/reject', (_err$message = err === null || err === void 0 ? void 0 : err.message) !== null && _err$message !== void 0 ? _err$message : err);
398
395
  reject(err);
399
396
  };
400
-
401
- // ✅ Real timeout no matter what happens with inFlight changes
402
397
  var timer = setTimeout(function () {
403
398
  finishErr(new Error('3D assets did not become idle within timeout'));
404
399
  }, timeoutMs);
@@ -415,8 +410,6 @@ function installGltfTracker() {
415
410
  return _context3.abrupt("return");
416
411
  case 1:
417
412
  log('waitForIdle inFlight change', count);
418
-
419
- // Only care when it hits zero; otherwise we just wait
420
413
  if (!(count !== 0)) {
421
414
  _context3.next = 2;
422
415
  break;
@@ -429,7 +422,6 @@ function installGltfTracker() {
429
422
  stable = _context3.sent;
430
423
  log('waitForIdle stable check', stable);
431
424
  if (stable) finishOk();
432
- // else keep waiting
433
425
  case 4:
434
426
  case "end":
435
427
  return _context3.stop();
@@ -494,6 +486,39 @@ export function renderKitchenSimulator(container) {
494
486
  warn = _makeLogger2.warn,
495
487
  error = _makeLogger2.error;
496
488
 
489
+ // ---- Long-task observer (find main-thread blocks) ----
490
+ var longTaskObserver = null;
491
+ if (typeof window !== 'undefined' && 'PerformanceObserver' in window) {
492
+ try {
493
+ longTaskObserver = new PerformanceObserver(function (list) {
494
+ var _iterator2 = _createForOfIteratorHelper(list.getEntries()),
495
+ _step2;
496
+ try {
497
+ for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {
498
+ var entry = _step2.value;
499
+ // entry.duration is the smoking gun when UI freezes
500
+ warn('Long task detected', {
501
+ name: entry.name,
502
+ duration: entry.duration,
503
+ startTime: entry.startTime
504
+ });
505
+ }
506
+ } catch (err) {
507
+ _iterator2.e(err);
508
+ } finally {
509
+ _iterator2.f();
510
+ }
511
+ });
512
+ // may throw in some browsers
513
+ longTaskObserver.observe({
514
+ entryTypes: ['longtask']
515
+ });
516
+ log('Long-task observer installed');
517
+ } catch (_unused3) {
518
+ // ignore
519
+ }
520
+ }
521
+
497
522
  // ✅ Reuse existing API
498
523
  if (container[API_KEY]) {
499
524
  var _container$API_KEY$__, _container$API_KEY;
@@ -502,14 +527,12 @@ export function renderKitchenSimulator(container) {
502
527
  return container[API_KEY];
503
528
  }
504
529
 
505
- // ✅ Reuse root
530
+ // ✅ Root
506
531
  var root = container[ROOT_KEY];
507
532
  if (!root) {
508
533
  root = createRoot(container);
509
534
  container[ROOT_KEY] = root;
510
535
  log('Created new React root');
511
- } else {
512
- log('Reusing existing React root');
513
536
  }
514
537
  var setExternalEventFn = null;
515
538
  var destroyed = false;
@@ -517,61 +540,70 @@ export function renderKitchenSimulator(container) {
517
540
  var pendingMarkers = new Set();
518
541
  var MARKER = Symbol('marker');
519
542
  var gltfTracker = installGltfTracker(debugEnabled);
520
-
521
- // FAST defaults (safe)
522
543
  var defaultFramesPerEvent = (_props$framesPerEvent = props.framesPerEvent) !== null && _props$framesPerEvent !== void 0 ? _props$framesPerEvent : 1;
523
544
  var waitForAssets = (_props$waitForGltfIdl = props.waitForGltfIdleAfterEachEvent) !== null && _props$waitForGltfIdl !== void 0 ? _props$waitForGltfIdl : true;
524
545
  var defaultTimeout = (_props$gltfTimeoutMs = props.gltfTimeoutMs) !== null && _props$gltfTimeoutMs !== void 0 ? _props$gltfTimeoutMs : 30000;
525
546
  var draining = false;
526
547
 
527
- // ---- Loop detection / profiling helpers ----
528
- var drainRunId = 0;
529
- var eventSeq = 0;
530
- var lastEvents = [];
531
- var LAST_N = 40;
532
- function summarizeEvent(ev) {
533
- var _ref5, _ref6, _ev$type, _ev$payload, _ref7, _ev$id, _ev$payload2;
534
- if (!ev) return ev;
535
- var t = (_ref5 = (_ref6 = (_ev$type = ev === null || ev === void 0 ? void 0 : ev.type) !== null && _ev$type !== void 0 ? _ev$type : ev === null || ev === void 0 || (_ev$payload = ev.payload) === null || _ev$payload === void 0 ? void 0 : _ev$payload.mode) !== null && _ref6 !== void 0 ? _ref6 : ev === null || ev === void 0 ? void 0 : ev.name) !== null && _ref5 !== void 0 ? _ref5 : 'unknown';
536
- var id = (_ref7 = (_ev$id = ev === null || ev === void 0 ? void 0 : ev.id) !== null && _ev$id !== void 0 ? _ev$id : ev === null || ev === void 0 || (_ev$payload2 = ev.payload) === null || _ev$payload2 === void 0 ? void 0 : _ev$payload2.id) !== null && _ref7 !== void 0 ? _ref7 : null;
537
- return {
538
- type: t,
539
- id: id,
540
- framesPerEvent: ev === null || ev === void 0 ? void 0 : ev.framesPerEvent,
541
- waitForGltfIdleAfterEachEvent: ev === null || ev === void 0 ? void 0 : ev.waitForGltfIdleAfterEachEvent,
542
- gltfTimeoutMs: ev === null || ev === void 0 ? void 0 : ev.gltfTimeoutMs
543
- };
544
- }
545
- function recordEvent(ev) {
546
- var s = summarizeEvent(ev);
547
- lastEvents.push(s);
548
- if (lastEvents.length > LAST_N) lastEvents.shift();
549
- }
550
- function dumpLoopHint() {
551
- var context = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : '';
552
- warn('Possible infinite loop / stall detected', {
553
- context: context,
554
- destroyed: destroyed,
555
- draining: draining,
556
- queueLength: queue.length,
557
- pendingMarkers: pendingMarkers.size,
558
- gltfInFlight: gltfTracker.getInFlight(),
559
- lastEvents: lastEvents
548
+ // ---- Ready gate (super important for first event) ----
549
+ var readyResolve = null;
550
+ var readyReject = null;
551
+ var readyPromise = new Promise(function (res, rej) {
552
+ readyResolve = res;
553
+ readyReject = rej;
554
+ });
555
+
556
+ // ---- RAF diagnostic wrapper ----
557
+ function nextFrameDiag() {
558
+ var label = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 'raf';
559
+ var warnAfterMs = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 250;
560
+ if (typeof window === 'undefined') return Promise.resolve();
561
+ return new Promise(function (resolve) {
562
+ var done = false;
563
+ var start = performance.now();
564
+ var t = setTimeout(function () {
565
+ var _document, _document2;
566
+ if (done) return;
567
+
568
+ // If this fires, RAF is not arriving (hidden tab / throttling) or main thread blocked
569
+ warn('RAF not fired within threshold', {
570
+ label: label,
571
+ warnAfterMs: warnAfterMs,
572
+ elapsedMs: performance.now() - start,
573
+ visibilityState: (_document = document) === null || _document === void 0 ? void 0 : _document.visibilityState,
574
+ hidden: (_document2 = document) === null || _document2 === void 0 ? void 0 : _document2.hidden,
575
+ gltfInFlight: gltfTracker.getInFlight(),
576
+ queueLength: queue.length,
577
+ draining: draining,
578
+ destroyed: destroyed
579
+ });
580
+
581
+ // Optional fail-open so you don't hang forever:
582
+ // If you want STRICT behavior, comment the next 2 lines and only keep logging.
583
+ done = true;
584
+ resolve();
585
+ }, warnAfterMs);
586
+ requestAnimationFrame(function () {
587
+ if (done) return;
588
+ done = true;
589
+ clearTimeout(t);
590
+ resolve();
591
+ });
560
592
  });
561
593
  }
562
594
  function isSyncScene(ev) {
563
- var _ev$payload3;
564
- return (ev === null || ev === void 0 ? void 0 : ev.type) === 'EXTERNAL_EVENT_SYNC_SCENE' || (ev === null || ev === void 0 || (_ev$payload3 = ev.payload) === null || _ev$payload3 === void 0 ? void 0 : _ev$payload3.mode) === 'sync-scene' || (ev === null || ev === void 0 ? void 0 : ev.__sync) === true;
595
+ var _ev$payload;
596
+ return (ev === null || ev === void 0 ? void 0 : ev.type) === 'EXTERNAL_EVENT_SYNC_SCENE' || (ev === null || ev === void 0 || (_ev$payload = ev.payload) === null || _ev$payload === void 0 ? void 0 : _ev$payload.mode) === 'sync-scene' || (ev === null || ev === void 0 ? void 0 : ev.__sync) === true;
565
597
  }
566
598
  function settle(_x2, _x3) {
567
599
  return _settle.apply(this, arguments);
568
600
  }
569
601
  function _settle() {
570
- _settle = _asyncToGenerator(/*#__PURE__*/_regeneratorRuntime.mark(function _callee7(ev, meta) {
571
- var _ev$framesPerEvent, _ev$waitForGltfIdleAf, _ev$gltfTimeoutMs;
572
- var frames, shouldWait, timeoutMs, i, start, _e$message2, _t2;
573
- return _regeneratorRuntime.wrap(function (_context7) {
574
- while (1) switch (_context7.prev = _context7.next) {
602
+ _settle = _asyncToGenerator(/*#__PURE__*/_regeneratorRuntime.mark(function _callee8(ev, meta) {
603
+ var _ev$framesPerEvent, _ev$waitForGltfIdleAf, _ev$gltfTimeoutMs, _document7, _document8;
604
+ var frames, shouldWait, timeoutMs, i, start;
605
+ return _regeneratorRuntime.wrap(function (_context8) {
606
+ while (1) switch (_context8.prev = _context8.next) {
575
607
  case 0:
576
608
  frames = (_ev$framesPerEvent = ev === null || ev === void 0 ? void 0 : ev.framesPerEvent) !== null && _ev$framesPerEvent !== void 0 ? _ev$framesPerEvent : defaultFramesPerEvent;
577
609
  shouldWait = (_ev$waitForGltfIdleAf = ev === null || ev === void 0 ? void 0 : ev.waitForGltfIdleAfterEachEvent) !== null && _ev$waitForGltfIdleAf !== void 0 ? _ev$waitForGltfIdleAf : waitForAssets;
@@ -580,69 +612,63 @@ export function renderKitchenSimulator(container) {
580
612
  frames: frames,
581
613
  shouldWait: shouldWait,
582
614
  timeoutMs: timeoutMs,
583
- gltfInFlight: gltfTracker.getInFlight()
615
+ visibilityState: (_document7 = document) === null || _document7 === void 0 ? void 0 : _document7.visibilityState,
616
+ hidden: (_document8 = document) === null || _document8 === void 0 ? void 0 : _document8.hidden
584
617
  }));
585
618
 
586
- // (1) allow react/reducers to run (fixes “must zoom to see updates”)
619
+ // (1) RAF frames (diagnostic)
587
620
  i = 0;
588
621
  case 1:
589
622
  if (!(i < frames)) {
590
- _context7.next = 3;
623
+ _context8.next = 4;
591
624
  break;
592
625
  }
593
- _context7.next = 2;
594
- return nextFrame();
626
+ _context8.next = 2;
627
+ return nextFrameDiag("settle:frame ".concat(i + 1, "/").concat(frames), 500);
595
628
  case 2:
629
+ if (debugEnabled) log('settle:after frame', _objectSpread(_objectSpread({}, meta), {}, {
630
+ i: i + 1
631
+ }));
632
+ case 3:
596
633
  i += 1;
597
- _context7.next = 1;
634
+ _context8.next = 1;
598
635
  break;
599
- case 3:
636
+ case 4:
600
637
  if (!shouldWait) {
601
- _context7.next = 8;
638
+ _context8.next = 6;
602
639
  break;
603
640
  }
604
641
  start = Date.now();
605
- _context7.prev = 4;
606
- _context7.next = 5;
642
+ log('settle:waitForIdle start', _objectSpread(_objectSpread({}, meta), {}, {
643
+ timeoutMs: timeoutMs,
644
+ gltfInFlight: gltfTracker.getInFlight()
645
+ }));
646
+ _context8.next = 5;
607
647
  return gltfTracker.waitForIdle({
608
648
  timeoutMs: timeoutMs
609
649
  });
610
650
  case 5:
611
- _context7.next = 7;
612
- break;
613
- case 6:
614
- _context7.prev = 6;
615
- _t2 = _context7["catch"](4);
616
- error('settle:waitForIdle failed', _objectSpread(_objectSpread({}, meta), {}, {
617
- err: (_e$message2 = _t2 === null || _t2 === void 0 ? void 0 : _t2.message) !== null && _e$message2 !== void 0 ? _e$message2 : _t2,
618
- waitedMs: Date.now() - start,
619
- gltfInFlight: gltfTracker.getInFlight()
620
- }));
621
- // Don’t throw unless you want the whole queue to stop.
622
- // Keeping behavior: let it bubble so caller catches and continues.
623
- throw _t2;
624
- case 7:
625
651
  log('settle:waitForIdle done', _objectSpread(_objectSpread({}, meta), {}, {
626
652
  waitedMs: Date.now() - start,
627
653
  gltfInFlight: gltfTracker.getInFlight()
628
654
  }));
629
- case 8:
630
- _context7.next = 9;
631
- return nextFrame();
632
- case 9:
655
+ case 6:
656
+ _context8.next = 7;
657
+ return nextFrameDiag('settle:final commit frame', 500);
658
+ case 7:
633
659
  if (!isSyncScene(ev)) {
634
- _context7.next = 10;
660
+ _context8.next = 8;
635
661
  break;
636
662
  }
637
- _context7.next = 10;
638
- return nextFrame();
639
- case 10:
640
- log('settle:done', _objectSpread({}, meta));
641
- case 11:
663
+ _context8.next = 8;
664
+ return nextFrameDiag('settle:sync-scene extra frame', 500);
665
+ case 8:
666
+ log('settle:done', meta);
667
+ case 9:
642
668
  case "end":
643
- return _context7.stop();
669
+ return _context8.stop();
644
670
  }
645
- }, _callee7, null, [[4, 6]]);
671
+ }, _callee8);
646
672
  }));
647
673
  return _settle.apply(this, arguments);
648
674
  }
@@ -650,140 +676,108 @@ export function renderKitchenSimulator(container) {
650
676
  return _drain.apply(this, arguments);
651
677
  }
652
678
  function _drain() {
653
- _drain = _asyncToGenerator(/*#__PURE__*/_regeneratorRuntime.mark(function _callee8() {
654
- var myRunId, start, watchdogEveryMs, watchdog, MAX_ITERATIONS, iterations, item, seq, meta, _err$message2, _t3;
655
- return _regeneratorRuntime.wrap(function (_context8) {
656
- while (1) switch (_context8.prev = _context8.next) {
679
+ _drain = _asyncToGenerator(/*#__PURE__*/_regeneratorRuntime.mark(function _callee9() {
680
+ var watchdog, item, meta, _err$message2, _t2;
681
+ return _regeneratorRuntime.wrap(function (_context9) {
682
+ while (1) switch (_context9.prev = _context9.next) {
657
683
  case 0:
658
684
  if (!(draining || destroyed)) {
659
- _context8.next = 1;
685
+ _context9.next = 1;
660
686
  break;
661
687
  }
662
- log('drain:skip', {
688
+ if (debugEnabled) log('drain:skip', {
663
689
  draining: draining,
664
690
  destroyed: destroyed,
665
691
  queueLength: queue.length
666
692
  });
667
- return _context8.abrupt("return");
693
+ return _context9.abrupt("return");
668
694
  case 1:
669
695
  draining = true;
670
- myRunId = drainRunId += 1;
671
- start = Date.now();
672
- log('drain:start', {
673
- runId: myRunId,
674
- queueLength: queue.length,
675
- pendingMarkers: pendingMarkers.size,
676
- gltfInFlight: gltfTracker.getInFlight()
677
- });
678
696
 
679
- // Watchdog: if drain runs too long, dump state (helps spot infinite loops)
680
- watchdogEveryMs = 4000;
697
+ // Watchdog: if we’re “stuck” in draining, dump state periodically
681
698
  watchdog = setInterval(function () {
682
- dumpLoopHint("drain watchdog runId=".concat(myRunId));
683
- }, watchdogEveryMs); // Hard cap of iterations in one drain call (fail-open) to prevent true infinite loops
684
- MAX_ITERATIONS = 5000;
685
- iterations = 0;
686
- _context8.prev = 2;
699
+ var _document9, _document0;
700
+ warn('drain watchdog', {
701
+ destroyed: destroyed,
702
+ draining: draining,
703
+ queueLength: queue.length,
704
+ pendingMarkers: pendingMarkers.size,
705
+ gltfInFlight: gltfTracker.getInFlight(),
706
+ visibilityState: (_document9 = document) === null || _document9 === void 0 ? void 0 : _document9.visibilityState,
707
+ hidden: (_document0 = document) === null || _document0 === void 0 ? void 0 : _document0.hidden
708
+ });
709
+ }, 4000);
710
+ _context9.prev = 2;
711
+ _context9.next = 3;
712
+ return readyPromise;
687
713
  case 3:
688
714
  if (!(!destroyed && queue.length)) {
689
- _context8.next = 12;
715
+ _context9.next = 11;
690
716
  break;
691
717
  }
692
- iterations += 1;
693
- if (!(iterations >= MAX_ITERATIONS)) {
694
- _context8.next = 4;
695
- break;
696
- }
697
- dumpLoopHint("MAX_ITERATIONS reached runId=".concat(myRunId));
698
- // fail-open: stop draining; future drain() calls can continue
699
- return _context8.abrupt("continue", 12);
700
- case 4:
701
718
  if (setExternalEventFn) {
702
- _context8.next = 6;
719
+ _context9.next = 5;
703
720
  break;
704
721
  }
705
- log('drain:waiting for setExternalEventFn');
706
- _context8.next = 5;
707
- return nextFrame();
722
+ warn('drain: no setExternalEventFn even after ready (unexpected)');
723
+ _context9.next = 4;
724
+ return nextFrameDiag('drain:waiting for setExternalEventFn', 500);
725
+ case 4:
726
+ return _context9.abrupt("continue", 3);
708
727
  case 5:
709
- return _context8.abrupt("continue", 3);
710
- case 6:
711
728
  item = queue.shift();
712
729
  if (!(item && item.__marker === MARKER)) {
713
- _context8.next = 7;
730
+ _context9.next = 6;
714
731
  break;
715
732
  }
716
733
  pendingMarkers["delete"](item.token);
717
734
  log('drain:marker consumed', {
718
- runId: myRunId,
719
735
  pendingMarkers: pendingMarkers.size,
720
736
  queueLength: queue.length
721
737
  });
722
- return _context8.abrupt("continue", 3);
723
- case 7:
724
- seq = eventSeq += 1;
725
- recordEvent(item);
738
+ return _context9.abrupt("continue", 3);
739
+ case 6:
726
740
  meta = {
727
- runId: myRunId,
728
- seq: seq,
741
+ eventType: item === null || item === void 0 ? void 0 : item.type,
729
742
  queueLengthAfterShift: queue.length,
730
743
  pendingMarkers: pendingMarkers.size,
731
- gltfInFlightBefore: gltfTracker.getInFlight(),
732
- event: summarizeEvent(item)
744
+ gltfInFlight: gltfTracker.getInFlight()
733
745
  };
734
746
  log('drain:event begin', meta);
735
- _context8.prev = 8;
747
+ _context9.prev = 7;
736
748
  setExternalEventFn(item);
737
749
  log('drain:setExternalEventFn called', meta);
738
- _context8.next = 9;
750
+ _context9.next = 8;
739
751
  return settle(item, meta);
740
- case 9:
741
- log('drain:event done', _objectSpread(_objectSpread({}, meta), {}, {
742
- gltfInFlightAfter: gltfTracker.getInFlight()
743
- }));
744
- _context8.next = 11;
752
+ case 8:
753
+ log('drain:event done', meta);
754
+ _context9.next = 10;
745
755
  break;
746
- case 10:
747
- _context8.prev = 10;
748
- _t3 = _context8["catch"](8);
756
+ case 9:
757
+ _context9.prev = 9;
758
+ _t2 = _context9["catch"](7);
749
759
  error('drain:event failed', _objectSpread(_objectSpread({}, meta), {}, {
750
- err: (_err$message2 = _t3 === null || _t3 === void 0 ? void 0 : _t3.message) !== null && _err$message2 !== void 0 ? _err$message2 : _t3,
751
- gltfInFlight: gltfTracker.getInFlight()
760
+ err: (_err$message2 = _t2 === null || _t2 === void 0 ? void 0 : _t2.message) !== null && _err$message2 !== void 0 ? _err$message2 : _t2
752
761
  }));
753
- // IMPORTANT: continue so we can eventually consume the marker
754
- case 11:
755
- // If queue never drains (e.g. events enqueue more events endlessly),
756
- // these logs help identify repeating patterns:
757
- if (debugEnabled && seq % 50 === 0) {
758
- warn('drain:progress snapshot', {
759
- runId: myRunId,
760
- processedEvents: seq,
761
- queueLength: queue.length,
762
- pendingMarkers: pendingMarkers.size,
763
- gltfInFlight: gltfTracker.getInFlight(),
764
- lastEvents: lastEvents
765
- });
766
- }
767
- _context8.next = 3;
762
+ case 10:
763
+ _context9.next = 3;
768
764
  break;
769
- case 12:
770
- _context8.prev = 12;
765
+ case 11:
766
+ _context9.prev = 11;
771
767
  clearInterval(watchdog);
772
768
  draining = false;
773
769
  log('drain:done', {
774
- runId: myRunId,
775
- ms: Date.now() - start,
776
770
  destroyed: destroyed,
777
771
  queueLength: queue.length,
778
772
  pendingMarkers: pendingMarkers.size,
779
773
  gltfInFlight: gltfTracker.getInFlight()
780
774
  });
781
- return _context8.finish(12);
782
- case 13:
775
+ return _context9.finish(11);
776
+ case 12:
783
777
  case "end":
784
- return _context8.stop();
778
+ return _context9.stop();
785
779
  }
786
- }, _callee8, null, [[2,, 12, 13], [8, 10]]);
780
+ }, _callee9, null, [[2,, 11, 12], [7, 9]]);
787
781
  }));
788
782
  return _drain.apply(this, arguments);
789
783
  }
@@ -804,18 +798,22 @@ export function renderKitchenSimulator(container) {
804
798
  value: function componentDidMount() {
805
799
  var _this3 = this;
806
800
  this._mounted = true;
807
- log('Wrapper mounted');
801
+ log('Wrapper mounted -> ready');
808
802
  setExternalEventFn = function setExternalEventFn(newEvent) {
809
- if (!_this3._mounted) {
810
- warn('setExternalEventFn called while unmounted (ignored)');
811
- return;
812
- }
813
- // This is the most important log to see if you’re triggering re-renders endlessly:
814
- log('Wrapper setState(externalEvent)', summarizeEvent(newEvent));
803
+ if (!_this3._mounted) return;
804
+ log('Wrapper setState(externalEvent)', {
805
+ type: newEvent === null || newEvent === void 0 ? void 0 : newEvent.type
806
+ });
815
807
  _this3.setState({
816
808
  externalEvent: newEvent
817
809
  });
818
810
  };
811
+
812
+ // ✅ resolve readiness here (first time)
813
+ if (readyResolve) {
814
+ readyResolve(true);
815
+ readyResolve = null;
816
+ }
819
817
  }
820
818
  }, {
821
819
  key: "componentWillUnmount",
@@ -823,14 +821,18 @@ export function renderKitchenSimulator(container) {
823
821
  log('Wrapper will unmount');
824
822
  this._mounted = false;
825
823
  setExternalEventFn = null;
824
+
825
+ // If unmount happens before ready, reject so drain can stop cleanly
826
+ if (readyReject) {
827
+ readyReject(new Error('Wrapper unmounted before ready'));
828
+ readyReject = null;
829
+ }
826
830
  }
827
831
  }, {
828
832
  key: "render",
829
833
  value: function render() {
830
- // Render spam can indicate infinite render loop; keep it lightweight
831
834
  if (debugEnabled) log('Wrapper render', {
832
- hasExternalEvent: !!this.state.externalEvent,
833
- externalEvent: summarizeEvent(this.state.externalEvent)
835
+ hasExternalEvent: !!this.state.externalEvent
834
836
  });
835
837
  return /*#__PURE__*/React.createElement(LiteRenderer, _extends({}, this.props, {
836
838
  externalEvent: this.state.externalEvent
@@ -841,50 +843,45 @@ export function renderKitchenSimulator(container) {
841
843
  var api = {
842
844
  __render: function __render(nextProps) {
843
845
  log('__render called', {
844
- debug: !!(nextProps !== null && nextProps !== void 0 && nextProps.debug),
845
- framesPerEvent: nextProps === null || nextProps === void 0 ? void 0 : nextProps.framesPerEvent,
846
- waitForGltfIdleAfterEachEvent: nextProps === null || nextProps === void 0 ? void 0 : nextProps.waitForGltfIdleAfterEachEvent,
847
- gltfTimeoutMs: nextProps === null || nextProps === void 0 ? void 0 : nextProps.gltfTimeoutMs
846
+ debug: !!(nextProps !== null && nextProps !== void 0 && nextProps.debug)
848
847
  });
849
848
  root.render(/*#__PURE__*/React.createElement(Wrapper, nextProps));
850
849
  },
851
- // host can query current inFlight
850
+ whenReady: function whenReady() {
851
+ return readyPromise;
852
+ },
852
853
  getGltfInFlight: function getGltfInFlight() {
853
- var v = gltfTracker.getInFlight();
854
- log('getGltfInFlight', v);
855
- return v;
854
+ return gltfTracker.getInFlight();
856
855
  },
857
- // ✅ host can subscribe to inFlight changes (loader)
858
856
  subscribeGltfInFlight: function subscribeGltfInFlight(cb) {
859
- log('subscribeGltfInFlight');
860
- return gltfTracker.subscribe(function (count) {
861
- if (debugEnabled) log('gltf inFlight changed', count);
862
- cb(count);
863
- });
857
+ return gltfTracker.subscribe(cb);
864
858
  },
865
859
  sendExternalEvents: function sendExternalEvents(eventOrEvents) {
866
- var _ref8 = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {},
867
- _ref8$timeoutMs = _ref8.timeoutMs,
868
- timeoutMs = _ref8$timeoutMs === void 0 ? 60000 : _ref8$timeoutMs;
860
+ var _document3, _document4;
861
+ var _ref5 = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {},
862
+ _ref5$timeoutMs = _ref5.timeoutMs,
863
+ timeoutMs = _ref5$timeoutMs === void 0 ? 60000 : _ref5$timeoutMs;
869
864
  var events = Array.isArray(eventOrEvents) ? eventOrEvents : [eventOrEvents];
870
865
  var batchId = Math.random().toString(16).slice(2);
871
866
  log('sendExternalEvents:enqueue', {
872
867
  batchId: batchId,
873
868
  count: events.length,
874
869
  timeoutMs: timeoutMs,
875
- events: events.map(summarizeEvent)
870
+ visibilityState: (_document3 = document) === null || _document3 === void 0 ? void 0 : _document3.visibilityState,
871
+ hidden: (_document4 = document) === null || _document4 === void 0 ? void 0 : _document4.hidden,
872
+ gltfInFlight: gltfTracker.getInFlight()
876
873
  });
877
- var _iterator2 = _createForOfIteratorHelper(events),
878
- _step2;
874
+ var _iterator3 = _createForOfIteratorHelper(events),
875
+ _step3;
879
876
  try {
880
- for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {
881
- var e = _step2.value;
877
+ for (_iterator3.s(); !(_step3 = _iterator3.n()).done;) {
878
+ var e = _step3.value;
882
879
  queue.push(e);
883
880
  }
884
881
  } catch (err) {
885
- _iterator2.e(err);
882
+ _iterator3.e(err);
886
883
  } finally {
887
- _iterator2.f();
884
+ _iterator3.f();
888
885
  }
889
886
  var token = Symbol('batch');
890
887
  pendingMarkers.add(token);
@@ -898,106 +895,89 @@ export function renderKitchenSimulator(container) {
898
895
  pendingMarkers: pendingMarkers.size
899
896
  });
900
897
  drain();
901
-
902
- // resolve when marker cleared
903
898
  return new Promise(function (resolve) {
904
899
  var start = Date.now();
905
900
  var check = /*#__PURE__*/function () {
906
- var _ref9 = _asyncToGenerator(/*#__PURE__*/_regeneratorRuntime.mark(function _callee6() {
907
- var spins;
908
- return _regeneratorRuntime.wrap(function (_context6) {
909
- while (1) switch (_context6.prev = _context6.next) {
901
+ var _ref6 = _asyncToGenerator(/*#__PURE__*/_regeneratorRuntime.mark(function _callee7() {
902
+ var _document5, _document6;
903
+ return _regeneratorRuntime.wrap(function (_context7) {
904
+ while (1) switch (_context7.prev = _context7.next) {
910
905
  case 0:
911
- spins = 0;
912
- case 1:
913
906
  if (destroyed) {
914
- _context6.next = 5;
907
+ _context7.next = 4;
915
908
  break;
916
909
  }
917
- spins += 1;
918
910
  if (pendingMarkers.has(token)) {
919
- _context6.next = 2;
911
+ _context7.next = 1;
920
912
  break;
921
913
  }
922
914
  log('sendExternalEvents:resolved', {
923
915
  batchId: batchId,
924
- ms: Date.now() - start,
925
- spins: spins,
926
- queueLength: queue.length
916
+ ms: Date.now() - start
927
917
  });
928
918
  resolve(true);
929
- return _context6.abrupt("return");
930
- case 2:
919
+ return _context7.abrupt("return");
920
+ case 1:
931
921
  if (!(Date.now() - start > timeoutMs)) {
932
- _context6.next = 3;
922
+ _context7.next = 2;
933
923
  break;
934
924
  }
935
925
  error('sendExternalEvents timed out', {
936
926
  batchId: batchId,
937
927
  timeoutMs: timeoutMs,
938
928
  ms: Date.now() - start,
939
- spins: spins,
940
929
  queueLength: queue.length,
941
930
  pendingMarkers: pendingMarkers.size,
942
931
  gltfInFlight: gltfTracker.getInFlight(),
943
- lastEvents: lastEvents
932
+ visibilityState: (_document5 = document) === null || _document5 === void 0 ? void 0 : _document5.visibilityState,
933
+ hidden: (_document6 = document) === null || _document6 === void 0 ? void 0 : _document6.hidden
944
934
  });
945
935
  pendingMarkers["delete"](token); // fail-open
946
936
  resolve(false);
947
- return _context6.abrupt("return");
937
+ return _context7.abrupt("return");
938
+ case 2:
939
+ _context7.next = 3;
940
+ return nextFrameDiag("sendExternalEvents:waiting batch=".concat(batchId), 1000);
948
941
  case 3:
949
- // Periodic “I might be stuck” hint
950
- if (debugEnabled && spins % 240 === 0) {
951
- dumpLoopHint("sendExternalEvents waiting batchId=".concat(batchId));
952
- }
953
- _context6.next = 4;
954
- return nextFrame();
955
- case 4:
956
- _context6.next = 1;
942
+ _context7.next = 0;
957
943
  break;
958
- case 5:
959
- warn('sendExternalEvents:destroyed while waiting', {
960
- batchId: batchId
961
- });
944
+ case 4:
962
945
  resolve(false);
963
- case 6:
946
+ case 5:
964
947
  case "end":
965
- return _context6.stop();
948
+ return _context7.stop();
966
949
  }
967
- }, _callee6);
950
+ }, _callee7);
968
951
  }));
969
952
  return function check() {
970
- return _ref9.apply(this, arguments);
953
+ return _ref6.apply(this, arguments);
971
954
  };
972
955
  }();
973
956
  check();
974
957
  });
975
958
  },
976
959
  updateExternalEvent: function updateExternalEvent(e) {
977
- log('updateExternalEvent', summarizeEvent(e));
978
960
  return api.sendExternalEvents(e);
979
961
  },
980
962
  clearQueue: function clearQueue() {
981
- log('clearQueue', {
982
- queueLength: queue.length,
983
- pendingMarkers: pendingMarkers.size
984
- });
985
963
  queue.length = 0;
986
964
  pendingMarkers.clear();
987
965
  },
988
966
  unmount: function unmount() {
989
- log('unmount called');
990
967
  destroyed = true;
991
968
  api.clearQueue();
992
969
  gltfTracker.uninstall();
970
+ try {
971
+ if (longTaskObserver) longTaskObserver.disconnect();
972
+ } catch (_unused4) {
973
+ // ignore
974
+ }
993
975
  var doUnmount = function doUnmount() {
994
976
  try {
995
- log('root.unmount()');
996
977
  root.unmount();
997
978
  } finally {
998
979
  container[ROOT_KEY] = null;
999
980
  container[API_KEY] = null;
1000
- log('unmounted + cleared container keys');
1001
981
  }
1002
982
  };
1003
983
  if (typeof queueMicrotask === 'function') queueMicrotask(doUnmount);else setTimeout(doUnmount, 0);
@@ -1005,11 +985,6 @@ export function renderKitchenSimulator(container) {
1005
985
  };
1006
986
  api.__render(props);
1007
987
  container[API_KEY] = api;
1008
-
1009
- // Helpful: show how to enable debug quickly at runtime
1010
- if (debugEnabled) {
1011
- log('Debug enabled. Tip: window.__kitchenSimulatorDebug__ = true (global)');
1012
- }
1013
988
  return api;
1014
989
  }
1015
990
  export default renderKitchenSimulator;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "kitchen-simulator",
3
- "version": "5.10.9-react.18",
3
+ "version": "5.10.10-react.18",
4
4
  "description": "It is a kitchen simulator (self-contained micro-frontend).",
5
5
  "license": "MIT",
6
6
  "module": "es/index.js",