mnfst 0.5.176 → 0.5.178

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.
@@ -58,6 +58,18 @@
58
58
  return out;
59
59
  }
60
60
 
61
+ // ---- shared revision ----------------------------------------------------
62
+ // Bumped on every commit of every handle; list getters touch it so any
63
+ // effect that read chat state — even a stale/empty handle mid-transition —
64
+ // re-arms on the next commit anywhere. Guards against directive effects
65
+ // whose dependency edge to a specific handle's state is lost during a
66
+ // key-flip flush (x-for dying on first load while a sibling x-effect lives).
67
+ let _rev = null;
68
+ function rev() {
69
+ if (!_rev) _rev = window.Alpine.reactive({ n: 0 });
70
+ return _rev;
71
+ }
72
+
61
73
  // ---- handle -------------------------------------------------------------
62
74
  function createHandle(adapter, conversationId, opts) {
63
75
  opts = opts || {};
@@ -80,9 +92,9 @@
80
92
  function ordered() { return _msgs.slice().sort(byKey); }
81
93
  // Fresh per-message snapshots each commit so a keyed x-for re-renders
82
94
  // in-place mutations (streaming appends, status) that identity wouldn't trip.
83
- function commit() { state.messages = ordered().map(m => Object.assign({}, m, { body: Object.assign({}, m.body) })); }
84
- function commitParticipants() { state.participants = [..._participants.values()]; }
85
- function commitTyping() { state.typing = [..._typing.values()]; }
95
+ function commit() { state.messages = ordered().map(m => Object.assign({}, m, { body: Object.assign({}, m.body) })); rev().n++; }
96
+ function commitParticipants() { state.participants = [..._participants.values()]; rev().n++; }
97
+ function commitTyping() { state.typing = [..._typing.values()]; rev().n++; }
86
98
 
87
99
  function upsert(raw) {
88
100
  const incoming = normalize(raw, ++seq);
@@ -146,6 +158,10 @@
146
158
  ingestLoad(await adapter.load(conversationId, opts.around ? { around: opts.around } : undefined));
147
159
  if (adapter.subscribe) { unsub = adapter.subscribe(conversationId, handlers); state.live = true; }
148
160
  state.status = 'ready';
161
+ // Settled tick: the seed load resolves amid the consumer's own
162
+ // transition flush; one macrotask commit re-triggers any effect
163
+ // whose mid-transition run raced it.
164
+ setTimeout(() => commit(), 0);
149
165
  } catch (e) { state.status = 'error'; state.error = String(e && e.message || e); }
150
166
  }
151
167
 
@@ -179,10 +195,11 @@
179
195
  __v_skip: true, // keep Alpine from re-proxying the handle when stored in x-data
180
196
  id: 'h_' + Math.round(performance.now()) + '_' + (++seq),
181
197
  conversationId, isAggregate,
182
- get messages() { return state.messages; },
183
- get participants() { return state.participants; },
198
+ get messages() { void rev().n; return state.messages; },
199
+ get participants() { void rev().n; return state.participants; },
184
200
  get me() { return state.me; },
185
- get typing() { return state.typing; },
201
+ get typing() { void rev().n; return state.typing; },
202
+ get version() { return rev().n; }, // guaranteed-trackable scalar; bumps on every commit
186
203
  get status() { return state.status; },
187
204
  get live() { return state.live; },
188
205
  get atStart() { return state.atStart; },
@@ -198,8 +215,8 @@
198
215
  loadReplies: !!adapter.loadReplies, loadReactions: !!adapter.loadReactions
199
216
  };
200
217
  },
201
- tree(o) { void state.messages; return buildTree(state.messages, o); },
202
- flatTree(o) { void state.messages; return flattenTree(buildTree(state.messages, o)); },
218
+ tree(o) { void rev().n; void state.messages; return buildTree(state.messages, o); },
219
+ flatTree(o) { void rev().n; void state.messages; return flattenTree(buildTree(state.messages, o)); },
203
220
  send,
204
221
  edit: (id, body) => adapter.edit && adapter.edit(conversationId, id, body),
205
222
  retract: (id) => adapter.retract && adapter.retract(conversationId, id),
@@ -234,6 +251,7 @@
234
251
  return order === 'ts' ? all.sort(byKey) : all;
235
252
  },
236
253
  get participants() { const seen = new Map(); for (const h of handles) for (const p of h.participants) seen.set(p.id, p); return [...seen.values()]; },
254
+ get version() { return rev().n; },
237
255
  get status() { return handles.some(h => h.status === 'loading') ? 'loading' : (handles.every(h => h.status === 'ready') ? 'ready' : 'idle'); },
238
256
  get live() { return handles.some(h => h.live); },
239
257
  can: { send: handles.some(h => h.can.send) },
@@ -243,7 +261,15 @@
243
261
  };
244
262
  }
245
263
 
246
- window.ManifestChatStore = { createHandle, mergeHandles, buildTree, flattenTree };
264
+ window.ManifestChatStore = {
265
+ createHandle, mergeHandles, buildTree, flattenTree,
266
+ // Shared revision, readable with zero handles resolved. Pin it in a list
267
+ // expression (`void $chat.version`) when the handle is looked up through
268
+ // a key that may not exist yet — an Alpine scheduler bug (queueJob drops
269
+ // re-triggers of already-flushed jobs) otherwise strands the directive
270
+ // when a sibling effect creates the handle in the same flush.
271
+ get version() { return rev().n; }
272
+ };
247
273
  })();
248
274
 
249
275
 
@@ -743,6 +769,7 @@
743
769
  merge(handles, o) { return Store.mergeHandles(handles, o); },
744
770
  adapter(name, factory) { if (factory === undefined) return Adapters.resolve(name); Adapters.register(name, factory); },
745
771
  flatten(tree) { return Store.flattenTree(tree); },
772
+ get version() { return Store.version; }, // shared revision — trackable even before any handle resolves
746
773
  get sim() { return Adapters.sim; } // demo/sim hooks; harmless in prod (no callers)
747
774
  };
748
775
  }
@@ -3,7 +3,7 @@
3
3
  "manifest.appwrite.data.js": "sha384-KFKVo5TQESLJB7wgk+C8Zb/sAl43QAMdioWW3tQRWYq5umfdpGCZ5Hld9y9f6/Np",
4
4
  "manifest.appwrite.presences.js": "sha384-JyVDWFT69b7Svq8J8p9tNWe2v9PZNQBY5UyhtOl1vnuHFAX0CRQ3MA9SiKq5wzNh",
5
5
  "manifest.charts.js": "sha384-qQrjhWkIDi4oU5uQrpy8DdlMjY+gfiivBuX6mssNiFdkawgkVBvKneGgp+nd3PYJ",
6
- "manifest.chat.js": "sha384-3+eva9YYz5DrdS3DeRGw9oXH/CreuYX+ZHHtYP25vmnYDHiEpFf9nEGLvwSHBXjz",
6
+ "manifest.chat.js": "sha384-pnHY4dM4YL8aFH3zK3eAtn+edKjARVC113aI8dcJjIuuusjcqikVcoS4K3Slj33F",
7
7
  "manifest.code.js": "sha384-G3MNfvQRWWY+gm4SGGrSsgQbDeil9MP+ON2DTk6Rcq9Nsex8woHMDt5EJHrFH0Nj",
8
8
  "manifest.color.js": "sha384-6Rv3LxyTcZNjrhtayQfqRdCx0uSZ4BiEbgEI98I62eTvp8Aw7LBIoNJ0Je1oktwL",
9
9
  "manifest.colorpicker.js": "sha384-N5ezEwgKrDodV4YdURxhdyZKmg1n/QhqvmAC4SEG03mw1pEAZAA8Gphp+NLAOxts",
@@ -15,7 +15,7 @@
15
15
  "manifest.export.js": "sha384-NkqOydcrdQ6qFEcpBKc80JCbeSCuybASrTUGajuTMBrHMzt1OIe8b3ndNn9VfqSh",
16
16
  "manifest.icons.js": "sha384-kKOINpX70YzNO3FvkV6umrmO3f0KIu0DNbwB+ej55a7y/lhU7v/myQtXL0bwCTbt",
17
17
  "manifest.localization.js": "sha384-MUetuW8PllIM+9JDMw/tx+qGem8t+ZUN5WZpycsTDKtz+LaX4DJehsfh/YZt9J7L",
18
- "manifest.markdown.js": "sha384-qlhYOzX0nl8HzuaiMVTkIhsma9mv3PlEvHO2S0AzshgmIcdZFvth6/sbHPCe5Zwr",
18
+ "manifest.markdown.js": "sha384-zdN4TgS3A92DGxSCcnlwtoroiQeCzyH1RayLJN0pDlQ9R0trodWCXJda8+awFGlB",
19
19
  "manifest.native.js": "sha384-4WfuciRjqrfDLpHXp91AKQUTt8FDHaupSuVErRgdeaeoHf5d1CfHWqBd/aCOduDk",
20
20
  "manifest.payments.js": "sha384-vhG1ZL3wGzb0vt0ygJJQF3jVQumMuvc2smGjYezuyQ+auN+MN9HY2k5NW2bdClxl",
21
21
  "manifest.resize.js": "sha384-S3v4RAJoA77LUH6MddYG9bx//dZX//up7XWeH69Ql2ge3bVHgC6mR/CJBe6y4nQI",
@@ -27,7 +27,7 @@
27
27
  "manifest.tailwind.js": "sha384-r/Jvqb+Piz21jUts10BbVAJoKkShOdJRVFpywyi4HPIi/OfOJq5CtPyWAPbdkMgt",
28
28
  "manifest.toasts.js": "sha384-ytd5rDbax/Ou9z23uedFXPZbxDPsk2E/pxCTq4WLvfv+os1qTI6kELp0kPp07g24",
29
29
  "manifest.tooltips.js": "sha384-HeJ0BGK3ebut1t8lm+MGeUUxd1pOZDyX8e6HFLsa4kAiRL+LwGDr67ckkRqv7to1",
30
- "manifest.url.parameters.js": "sha384-FIufiClqDx1rJpU/QUc9z/D43qClQ6Qm8rBahipbJl9BDHUvhrOsUDegmTWW7Tuf",
30
+ "manifest.url.parameters.js": "sha384-+ZOsgPgbFmKOZsReC1EiH8PsZwvr2nC/duhzIzFf70xrbRrLsr926sLFW0M+BXtN",
31
31
  "manifest.utilities.js": "sha384-yLEqEbd1FncqswrtrcTO7KrIEK4iP0ZvqCi64XLI7D77/L0YiJbjLdLGGg6l7rgN",
32
32
  "manifest.virtual.js": "sha384-c194pXD0Ld48QJ+HPVNibvbn54/ETJRuYhUOWesEBjtOIQcQMIKo0DnCyQMvDlLg",
33
33
  "manifest.js": "sha384-FLz68HEE8hEVLlAsoAX2+5cWBrhS5+B24rdJy5obXtP5U5bJKCswjbIQL8MpDUFZ"
@@ -596,11 +596,29 @@ async function initializeMarkdownPlugin() {
596
596
  return;
597
597
  }
598
598
 
599
- // Quote bare string literals so Alpine doesn't treat them as expressions.
599
+ // Classify the source: real expressions evaluate; bare markdown/paths
600
+ // are quoted so Alpine doesn't choke on them.
601
+ const trimmed = expression.trim();
602
+ const isExplicitExpression = trimmed.includes('+') || trimmed.includes('`') || trimmed.includes('${') ||
603
+ trimmed.startsWith('$') || trimmed.startsWith("'") || trimmed.startsWith('"');
604
+ const looksLikePath = /\.(md|markdown)([?#]|$)/i.test(trimmed) || /^[\w./-]*\/[\w./-]*$/.test(trimmed);
605
+ const isMemberChain = !looksLikePath &&
606
+ /^[A-Za-z_$][\w$]*(\s*(\?\.|\.)\s*[A-Za-z_$][\w$]*|\s*\[[^\]]*\]|\s*\([^()]*\))+$/.test(trimmed);
607
+ const isBareIdentifier = !looksLikePath && /^[A-Za-z_$][\w$]*$/.test(trimmed);
608
+
600
609
  let processedExpression = expression;
601
- if (!expression.includes('+') && !expression.includes('`') && !expression.includes('${') &&
602
- !expression.startsWith('$') && !expression.startsWith("'") && !expression.startsWith('"')) {
603
- processedExpression = `'${expression.replace(/'/g, "\\'")}'`;
610
+ if (!isExplicitExpression) {
611
+ if (isMemberChain) {
612
+ // e.g. m.body.text — evaluate; undefined mid-chain (data still
613
+ // loading) resolves to undefined instead of throwing.
614
+ processedExpression = `(() => { try { return ${trimmed} } catch (_) { return undefined } })()`;
615
+ } else if (isBareIdentifier) {
616
+ // e.g. t — scope variable if defined, else literal one-word markdown
617
+ processedExpression = `(typeof ${trimmed} === 'undefined' ? '${trimmed}' : ${trimmed})`;
618
+ } else {
619
+ // inline markdown or file path — quote as literal
620
+ processedExpression = `'${expression.replace(/\\/g, '\\\\').replace(/'/g, "\\'").replace(/\n/g, '\\n')}'`;
621
+ }
604
622
  }
605
623
  const getMarkdownContent = evaluateLater(processedExpression);
606
624
 
@@ -620,12 +638,13 @@ async function initializeMarkdownPlugin() {
620
638
  pathOrContent = expression;
621
639
  }
622
640
 
623
- // Check if this looks like a file path (contains .md, .markdown, or starts with /)
641
+ // Path = single whitespace-free token: .md/.markdown file, or a
642
+ // slash path of plain word chars. Evaluated content (chat
643
+ // messages etc.) with slashes or extensions inside prose stays prose.
624
644
  const isFilePath = typeof pathOrContent === 'string' &&
625
- (pathOrContent.includes('.md') ||
626
- pathOrContent.includes('.markdown') ||
627
- pathOrContent.startsWith('/') ||
628
- pathOrContent.includes('/'));
645
+ !/\s/.test(pathOrContent) &&
646
+ (/\.(md|markdown)([?#]|$)/i.test(pathOrContent) ||
647
+ /^[\w./-]*\/[\w./-]*$/.test(pathOrContent));
629
648
 
630
649
  let markdownContent = pathOrContent;
631
650
 
@@ -1,199 +1,156 @@
1
1
  /* Manifest URL Parameters */
2
2
 
3
3
  function initializeUrlParametersPlugin() {
4
- // Initialize empty parameters store
5
- Alpine.store('urlParams', {
6
- current: {},
7
- _initialized: false
8
- });
9
-
10
- // Cache for debounced updates
11
- const updateTimeouts = new Map();
12
4
  const DEBOUNCE_DELAY = 300;
13
5
 
14
- // Helper to parse query string
6
+ // Parse query string; comma-separated values become arrays
15
7
  function parseQueryString(queryString) {
16
8
  const params = new URLSearchParams(queryString);
17
9
  const result = {};
18
-
19
10
  for (const [key, value] of params.entries()) {
20
- // Handle array values (comma-separated)
21
11
  if (value.includes(',')) {
22
12
  result[key] = value.split(',').filter(Boolean);
23
13
  } else {
24
14
  result[key] = value;
25
15
  }
26
16
  }
27
-
28
17
  return result;
29
18
  }
30
19
 
31
- // Helper to stringify query object
32
20
  function stringifyQueryObject(query) {
33
21
  const params = new URLSearchParams();
34
-
35
22
  for (const [key, value] of Object.entries(query)) {
36
23
  if (Array.isArray(value)) {
37
- params.set(key, value.filter(Boolean).join(','));
24
+ if (value.filter(Boolean).length) params.set(key, value.filter(Boolean).join(','));
38
25
  } else if (value != null && value !== '') {
39
26
  params.set(key, value);
40
27
  }
41
28
  }
42
-
43
29
  return params.toString();
44
30
  }
45
31
 
46
- // Helper to ensure value is in array format
47
32
  function ensureArray(value) {
48
33
  if (Array.isArray(value)) return value;
49
34
  if (value == null || value === '') return [];
35
+ if (typeof value === 'string' && value.includes(',')) return value.split(',').filter(Boolean);
50
36
  return [value];
51
37
  }
52
38
 
53
- // Update URL with new query parameters
54
- async function updateURL(updates, action = 'set') {
55
-
56
- const url = new URL(window.location.href);
57
- const currentParams = parseQueryString(url.search);
58
-
59
- // Apply updates based on action
60
- for (const [key, value] of Object.entries(updates)) {
61
- switch (action) {
62
- case 'add':
63
- const currentAdd = ensureArray(currentParams[key]);
64
- const newValues = ensureArray(value);
65
- currentParams[key] = [...new Set([...currentAdd, ...newValues])];
66
- break;
67
-
68
- case 'remove':
69
- const currentRemove = ensureArray(currentParams[key]);
70
- const removeValue = ensureArray(value)[0]; // Take first value to remove
71
- currentParams[key] = currentRemove.filter(v => v !== removeValue);
72
- if (currentParams[key].length === 0) {
73
- delete currentParams[key];
74
- }
75
- break;
76
-
77
- case 'set':
78
- default:
79
- if (value == null || value === '') {
80
- delete currentParams[key];
81
- } else {
82
- currentParams[key] = value;
83
- }
84
- break;
39
+ // Single reactive source of truth. Reads through $url register as Alpine
40
+ // dependencies; location is a debounced mirror of this state, not the store.
41
+ const params = Alpine.reactive({
42
+ current: parseQueryString(window.location.search),
43
+ _initialized: true
44
+ });
45
+ Alpine.store('urlParams', params);
46
+
47
+ // ---- location mirror (debounced, coalesces multi-key writes) ------------
48
+ let mirrorTimer = null;
49
+ function mirror() {
50
+ clearTimeout(mirrorTimer);
51
+ mirrorTimer = setTimeout(() => {
52
+ mirrorTimer = null;
53
+ const url = new URL(window.location.href);
54
+ const qs = stringifyQueryObject(params.current);
55
+ url.search = qs ? `?${qs}` : '';
56
+ if (url.toString() !== window.location.href) {
57
+ history.pushState({}, '', url.toString());
85
58
  }
86
- }
87
-
88
- // Update URL
89
- const newQueryString = stringifyQueryObject(currentParams);
90
- url.search = newQueryString ? `?${newQueryString}` : '';
91
-
92
- // Update URL using pushState to ensure changes are visible
93
- window.history.pushState({}, '', url.toString());
59
+ }, DEBOUNCE_DELAY);
60
+ }
94
61
 
95
- // Update store
96
- Alpine.store('urlParams', {
97
- current: currentParams,
98
- _initialized: true
99
- });
62
+ // ---- rehydrate from location (back/forward, router go/replace) ----------
63
+ function rehydrate() {
64
+ if (mirrorTimer) { clearTimeout(mirrorTimer); mirrorTimer = null; } // navigation wins over pending writes
65
+ const next = parseQueryString(window.location.search);
66
+ if (stringifyQueryObject(next) !== stringifyQueryObject(params.current)) {
67
+ params.current = next;
68
+ }
69
+ }
70
+ window.addEventListener('popstate', rehydrate);
71
+
72
+ // Router go()/replace() (and any third party) drive history directly with
73
+ // no popstate — wrap so $url reads stay fresh. Our own mirror round-trips
74
+ // through this harmlessly (equality check above makes it a no-op).
75
+ for (const method of ['pushState', 'replaceState']) {
76
+ const original = history[method].bind(history);
77
+ history[method] = function (...args) {
78
+ const result = original(...args);
79
+ rehydrate();
80
+ return result;
81
+ };
82
+ }
100
83
 
101
- // Dispatch event
84
+ // ---- mutations (synchronous into reactive state) ------------------------
85
+ function apply(prop, value, action) {
86
+ const next = Object.assign({}, params.current);
87
+ switch (action) {
88
+ case 'add': {
89
+ const merged = [...new Set([...ensureArray(next[prop]), ...ensureArray(value)])];
90
+ if (merged.length) next[prop] = merged; else delete next[prop];
91
+ break;
92
+ }
93
+ case 'remove': {
94
+ const remaining = ensureArray(next[prop]).filter(v => !ensureArray(value).includes(v));
95
+ if (remaining.length) next[prop] = remaining; else delete next[prop];
96
+ break;
97
+ }
98
+ case 'clear':
99
+ delete next[prop];
100
+ break;
101
+ case 'set':
102
+ default:
103
+ if (value == null || value === '' || (Array.isArray(value) && !value.length)) {
104
+ delete next[prop];
105
+ } else {
106
+ next[prop] = value;
107
+ }
108
+ break;
109
+ }
110
+ params.current = next;
111
+ mirror();
102
112
  document.dispatchEvent(new CustomEvent('url-updated', {
103
- detail: { updates, action }
113
+ detail: { updates: { [prop]: value }, action }
104
114
  }));
105
-
106
- return currentParams;
107
115
  }
108
116
 
109
- // Add $url magic method
117
+ // ---- $url magic ---------------------------------------------------------
110
118
  Alpine.magic('url', () => {
111
- const store = Alpine.store('urlParams');
112
-
113
119
  return new Proxy({}, {
114
120
  get(target, prop) {
115
- // Handle special keys
116
121
  if (prop === Symbol.iterator || prop === 'then' || prop === 'catch' || prop === 'finally') {
117
122
  return undefined;
118
123
  }
119
-
120
- // Get current value
121
- const value = store.current[prop];
122
-
123
- // Return a proxy for the value
124
124
  return new Proxy({}, {
125
- get(target, key) {
125
+ get(t, key) {
126
+ // reads happen at access time so effects track them
126
127
  if (key === 'value') {
127
- // Ensure arrays are returned as arrays, not strings
128
+ const value = params.current[prop];
128
129
  if (Array.isArray(value)) return value;
129
- if (typeof value === 'string' && value.includes(',')) {
130
- return value.split(',').filter(Boolean);
131
- }
132
- // Return undefined/null values as they are (for proper falsy checks)
130
+ if (typeof value === 'string' && value.includes(',')) return value.split(',').filter(Boolean);
133
131
  return value;
134
132
  }
135
- if (key === 'set') return (newValue) => {
136
- clearTimeout(updateTimeouts.get(prop));
137
- const timeout = setTimeout(() => {
138
- updateURL({ [prop]: newValue }, 'set');
139
- }, DEBOUNCE_DELAY);
140
- updateTimeouts.set(prop, timeout);
141
- };
142
- if (key === 'add') return (newValue) => {
143
- clearTimeout(updateTimeouts.get(prop));
144
- const timeout = setTimeout(() => {
145
- updateURL({ [prop]: newValue }, 'add');
146
- }, DEBOUNCE_DELAY);
147
- updateTimeouts.set(prop, timeout);
148
- };
149
- if (key === 'remove') return (value) => {
150
- clearTimeout(updateTimeouts.get(prop));
151
- const timeout = setTimeout(() => {
152
- updateURL({ [prop]: value }, 'remove');
153
- }, DEBOUNCE_DELAY);
154
- updateTimeouts.set(prop, timeout);
155
- };
156
- if (key === 'clear') return () => {
157
- clearTimeout(updateTimeouts.get(prop));
158
- const timeout = setTimeout(() => {
159
- updateURL({ [prop]: null }, 'set');
160
- }, DEBOUNCE_DELAY);
161
- updateTimeouts.set(prop, timeout);
162
- };
133
+ if (key === 'first') {
134
+ const all = ensureArray(params.current[prop]);
135
+ return all.length ? all[0] : null;
136
+ }
137
+ if (key === 'all') return ensureArray(params.current[prop]);
138
+ if (key === 'set') return (v) => apply(prop, v, 'set');
139
+ if (key === 'add') return (v) => apply(prop, v, 'add');
140
+ // no-arg remove clears the whole param
141
+ if (key === 'remove') return (v) => apply(prop, v, v === undefined ? 'clear' : 'remove');
142
+ if (key === 'clear') return () => apply(prop, null, 'clear');
163
143
  return undefined;
164
144
  },
165
- set(target, key, newValue) {
166
- if (key === 'value') {
167
- // Make value settable for x-model compatibility
168
- clearTimeout(updateTimeouts.get(prop));
169
- const timeout = setTimeout(() => {
170
- updateURL({ [prop]: newValue }, 'set');
171
- }, DEBOUNCE_DELAY);
172
- updateTimeouts.set(prop, timeout);
173
- return true;
174
- }
145
+ set(t, key, v) {
146
+ // settable value for x-model compatibility
147
+ if (key === 'value') { apply(prop, v, 'set'); return true; }
175
148
  return false;
176
149
  }
177
150
  });
178
151
  }
179
152
  });
180
153
  });
181
-
182
- // Initialize with current URL parameters
183
- const initialParams = parseQueryString(window.location.search);
184
- Alpine.store('urlParams', {
185
- current: initialParams,
186
- _initialized: true
187
- });
188
-
189
- // Listen for popstate events
190
- window.addEventListener('popstate', () => {
191
- const params = parseQueryString(window.location.search);
192
- Alpine.store('urlParams', {
193
- current: params,
194
- _initialized: true
195
- });
196
- });
197
154
  }
198
155
 
199
156
  // Track initialization to prevent duplicates
@@ -233,4 +190,4 @@ if (window.Alpine && typeof window.Alpine.directive === 'function') {
233
190
  }
234
191
  }, 10);
235
192
  setTimeout(() => clearInterval(checkAlpine), 5000);
236
- }
193
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mnfst",
3
- "version": "0.5.176",
3
+ "version": "0.5.178",
4
4
  "private": false,
5
5
  "workspaces": [
6
6
  "templates/starter",