mnfst 0.5.45 → 0.5.46

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.
@@ -207,6 +207,10 @@ const rawDataStore = new Map();
207
207
  let isInitializing = false;
208
208
  let initializationComplete = false;
209
209
 
210
+ // Render-ready: debounced timer used by checkAndDispatchRenderReady
211
+ let _renderReadyTimer = null;
212
+ const RENDER_READY_QUIET_MS = 150; // ms of quiet (no loading) before firing
213
+
210
214
  // Deep seal an object to prevent Alpine from making it reactive
211
215
  // This prevents double-proxying which causes recursion errors
212
216
  function deepSeal(obj) {
@@ -301,6 +305,12 @@ function updateStore(dataSourceName, data, options = {}) {
301
305
 
302
306
  Alpine.store('data', updatedStore);
303
307
 
308
+ // When a source finishes loading (success or error), check if everything is settled.
309
+ // This is the primary trigger for manifest:render-ready.
310
+ if (!newState.loading) {
311
+ checkAndDispatchRenderReady();
312
+ }
313
+
304
314
  // Attach methods to array if it's an array (for new architecture)
305
315
  // This ensures methods are available on the new array reference
306
316
  if (Array.isArray(reactiveData) && window.ManifestDataProxies?.attachArrayMethods) {
@@ -766,6 +776,49 @@ function setupTeamChangeListener() {
766
776
  }
767
777
  }
768
778
 
779
+ // Dispatch manifest:render-ready when all tracked data sources have settled.
780
+ // Uses a debounce so rapid sequential source completions coalesce into one event.
781
+ // The render script listens for this event instead of polling internal store state.
782
+ function checkAndDispatchRenderReady() {
783
+ if (_renderReadyTimer) {
784
+ clearTimeout(_renderReadyTimer);
785
+ }
786
+ _renderReadyTimer = setTimeout(() => {
787
+ _renderReadyTimer = null;
788
+ try {
789
+ if (typeof window === 'undefined' || typeof Alpine === 'undefined') return;
790
+ const store = Alpine.store('data');
791
+ if (!store) return;
792
+
793
+ // Don't fire while a locale change is still in progress
794
+ if (store._localeChanging) return;
795
+
796
+ // Don't fire if any source state still shows loading
797
+ for (const key of Object.keys(store)) {
798
+ if (key.startsWith('_') && key.endsWith('_state')) {
799
+ if (store[key]?.loading) return;
800
+ }
801
+ }
802
+
803
+ // Don't fire if any fetch promises are still in flight
804
+ if (loadingPromises.size > 0) return;
805
+
806
+ // All settled — dispatch the authoritative prerender signal
807
+ const locale =
808
+ (typeof document !== 'undefined' && document.documentElement.lang) ||
809
+ Alpine.store('locale')?.current ||
810
+ 'en';
811
+ const sources = Object.keys(store).filter(k => !k.startsWith('_') && k !== 'all');
812
+
813
+ window.dispatchEvent(new CustomEvent('manifest:render-ready', {
814
+ detail: { locale, sources }
815
+ }));
816
+ } catch {
817
+ // Silently fail — the render script has its own timeout fallback
818
+ }
819
+ }, RENDER_READY_QUIET_MS);
820
+ }
821
+
769
822
  // Listen for locale changes to reload data
770
823
  function setupLocaleChangeListener() {
771
824
  window.addEventListener('localechange', async (event) => {
@@ -900,6 +953,10 @@ function setupLocaleChangeListener() {
900
953
  );
901
954
  }
902
955
 
956
+ // All localized sources have reloaded — check if everything is settled.
957
+ // This fires manifest:render-ready after a locale change completes end-to-end.
958
+ checkAndDispatchRenderReady();
959
+
903
960
  } catch (error) {
904
961
  console.error('[Manifest Data] Error handling locale change:', error);
905
962
  // Fallback to full reload if something goes wrong
@@ -1125,6 +1182,7 @@ window.ManifestDataStore = {
1125
1182
  initializeStore,
1126
1183
  setupLocaleChangeListener,
1127
1184
  setupTeamChangeListener,
1185
+ checkAndDispatchRenderReady,
1128
1186
  // Operation-specific loading state helpers
1129
1187
  setCreatingEntry,
1130
1188
  clearCreatingEntry,
@@ -11732,6 +11790,9 @@ async function initializeDataSourcesPlugin() {
11732
11790
  if (typeof window !== 'undefined') {
11733
11791
  window.dispatchEvent(new CustomEvent('manifest:data-ready'));
11734
11792
  }
11793
+ // Check if all sources are settled and dispatch manifest:render-ready if so.
11794
+ // Covers the initial-load path (no data sources, or only content pre-loaded).
11795
+ window.ManifestDataStore?.checkAndDispatchRenderReady?.();
11735
11796
  };
11736
11797
  if (typeof Alpine !== 'undefined' && Alpine.nextTick) {
11737
11798
  Alpine.nextTick(flushThenDispatch);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mnfst",
3
- "version": "0.5.45",
3
+ "version": "0.5.46",
4
4
  "private": false,
5
5
  "workspaces": [
6
6
  "templates/starter",