mnfst 0.5.246 → 0.5.248

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.
@@ -2,7 +2,7 @@
2
2
 
3
3
  (function () {
4
4
 
5
- const MANIFEST_BUILD_VERSION = '0.5.246';
5
+ const MANIFEST_BUILD_VERSION = '0.5.248';
6
6
 
7
7
  /* Manifest Data Sources - Configuration */
8
8
 
@@ -574,7 +574,8 @@ function writeSource(dataSourceName, data, options = {}) {
574
574
  error: options.error !== undefined ? options.error : currentState.error,
575
575
  ready: options.ready !== undefined ? options.ready : (data !== null && data !== undefined),
576
576
  errorTime: options.error !== undefined && options.error !== null ? Date.now() : (currentState.errorTime || null),
577
- stale: fresh ? false : currentState.stale !== false
577
+ stale: fresh ? false : currentState.stale !== false,
578
+ realtimeOverflow: currentState.realtimeOverflow || 0 // set via setSourceState (realtime caps)
578
579
  };
579
580
  store[`_${dataSourceName}_state`] = newState;
580
581
  if (fresh) markFresh(dataSourceName);
@@ -4923,8 +4924,8 @@ function createArrayProxyWithRoute(arrayTarget, dataSourceName = null, reloadDat
4923
4924
  return undefined;
4924
4925
  }
4925
4926
 
4926
- // Handle state properties ($loading, $error, $ready, $stale, $fresh)
4927
- if (key === '$stale' || key === '$fresh') {
4927
+ // Handle state properties ($loading, $error, $ready, $stale, $fresh, $realtimeOverflow)
4928
+ if (key === '$stale' || key === '$fresh' || key === '$realtimeOverflow') {
4928
4929
  return window.ManifestDataProxiesMagic?.getStateProperty?.(key, dataSourceName);
4929
4930
  }
4930
4931
  if (key === '$loading' || key === '$error' || key === '$ready') {
@@ -8816,7 +8817,7 @@ window.ManifestDataProxiesAppwrite.createAppwriteMethodsHandler = createAppwrite
8816
8817
 
8817
8818
 
8818
8819
  /* Manifest Data Sources - Magic Method State Properties */
8819
- // $loading, $error, $ready, $stale, $fresh state properties
8820
+ // $loading, $error, $ready, $stale, $fresh, $realtimeOverflow state properties
8820
8821
  //
8821
8822
  // $stale: true until the first network-fresh landing of this page-load is
8822
8823
  // applied (rows from a fetch, `$query`, or the memory cache of a fetch made
@@ -8824,12 +8825,15 @@ window.ManifestDataProxiesAppwrite.createAppwriteMethodsHandler = createAppwrite
8824
8825
  // reports through $loading. Single-reveal UIs gate on `!$stale`.
8825
8826
  // $fresh: promise resolving at that same first fresh landing; never rejects
8826
8827
  // (a failed reload keeps old rows and sets $error). Per page-load.
8828
+ // $realtimeOverflow: realtime events not applied since the last load (bounded
8829
+ // growth caps); reset to 0 on each load.
8827
8830
 
8828
- const STATE_PROPS = ['$loading', '$error', '$ready', '$stale', '$fresh'];
8831
+ const STATE_PROPS = ['$loading', '$error', '$ready', '$stale', '$fresh', '$realtimeOverflow'];
8829
8832
 
8830
8833
  function defaultStateValue(prop) {
8831
8834
  if (prop === '$error') return null;
8832
8835
  if (prop === '$stale') return true;
8836
+ if (prop === '$realtimeOverflow') return 0;
8833
8837
  return false;
8834
8838
  }
8835
8839
 
@@ -8858,6 +8862,8 @@ function getStateProperty(prop, dataSourceName) {
8858
8862
  return state.ready || false;
8859
8863
  } else if (prop === '$stale') {
8860
8864
  return state.stale !== false;
8865
+ } else if (prop === '$realtimeOverflow') {
8866
+ return state.realtimeOverflow || 0;
8861
8867
  }
8862
8868
 
8863
8869
  return undefined;
@@ -11502,6 +11508,11 @@ function dropSubscription(dataSourceName, unsubscribe) {
11502
11508
  if (subs?.get?.(dataSourceName) === unsubscribe) subs.delete(dataSourceName);
11503
11509
  }
11504
11510
 
11511
+ // Init couldn't reach Appwrite: signed out locally until the recheck confirms or clears the session
11512
+ function sessionUnverified(auth) {
11513
+ return auth?._sessionUnverified === true && auth.isAuthenticated !== true;
11514
+ }
11515
+
11505
11516
  // Auth settled with no identity (or no auth plugin): a scoped read can't resolve until sign-in
11506
11517
  function authSettledSignedOut() {
11507
11518
  const auth = currentAuth();
@@ -11700,10 +11711,10 @@ async function filterFilesByScope(files, scope) {
11700
11711
  }
11701
11712
 
11702
11713
  // Handle real-time storage events
11703
- async function handleStorageRealtimeEvent(dataSourceName, bucketId, scope, eventType, payload, generation) {
11714
+ async function handleStorageRealtimeEvent(dataSourceName, bucketId, scope, eventType, payload, generation, queriesConfig) {
11704
11715
 
11705
- // Deduplicate events
11706
- const eventKey = getEventKey(eventType, payload);
11716
+ // Deduplicate events (per source: shared-channel peers each process once)
11717
+ const eventKey = `${dataSourceName}|${getEventKey(eventType, payload)}`;
11707
11718
  if (isEventProcessed(eventKey)) {
11708
11719
  return;
11709
11720
  }
@@ -11726,8 +11737,12 @@ async function handleStorageRealtimeEvent(dataSourceName, bucketId, scope, event
11726
11737
  const file = payload?.$id ? payload : (payload?.file || payload);
11727
11738
  if (file && file.$id) {
11728
11739
  const fileMatchesScope = await checkFileMatchesScope(file, scope);
11729
- if (fileMatchesScope) {
11730
- landRows(dataSourceName, [file], { mode: 'append', generation });
11740
+ if (fileMatchesScope && eventMatchesQueries(file, queriesConfig)) {
11741
+ if (currentFiles.find(f => f && f.$id === file.$id)) {
11742
+ landRows(dataSourceName, [file], { mode: 'append', generation });
11743
+ } else {
11744
+ realtimeAppend(dataSourceName, file, currentFiles, generation);
11745
+ }
11731
11746
 
11732
11747
  // Emit custom event for new file creation so UI can refresh project files
11733
11748
  window.dispatchEvent(new CustomEvent('manifest:file-created', {
@@ -11741,10 +11756,14 @@ async function handleStorageRealtimeEvent(dataSourceName, bucketId, scope, event
11741
11756
  const file = payload?.$id ? payload : (payload?.file || payload);
11742
11757
  if (file && file.$id) {
11743
11758
  const fileMatchesScope = await checkFileMatchesScope(file, scope);
11744
- if (fileMatchesScope) {
11745
- landRows(dataSourceName, [file], { mode: 'append', generation });
11759
+ if (fileMatchesScope && eventMatchesQueries(file, queriesConfig)) {
11760
+ if (currentFiles.find(f => f && f.$id === file.$id)) {
11761
+ landRows(dataSourceName, [file], { mode: 'append', generation });
11762
+ } else {
11763
+ realtimeAppend(dataSourceName, file, currentFiles, generation);
11764
+ }
11746
11765
  } else {
11747
- // File no longer matches scope, remove it
11766
+ // File no longer matches scope/queries, remove it
11748
11767
  landRemove(dataSourceName, [file.$id], { generation });
11749
11768
  }
11750
11769
  }
@@ -11752,11 +11771,14 @@ async function handleStorageRealtimeEvent(dataSourceName, bucketId, scope, event
11752
11771
  const fileId = payload?.$id || payload?.file?.$id || payload?.fileId || payload;
11753
11772
  if (fileId) {
11754
11773
  landRemove(dataSourceName, [fileId.$id || fileId], { generation });
11774
+ forgetRealtimeRow(dataSourceName, fileId.$id || fileId);
11755
11775
  }
11756
11776
  }
11757
11777
  }
11758
11778
 
11759
- // Realtime event dedup: key by type+id+sequence(+timestamp)
11779
+ // Realtime event dedup: key by source+type+id+sequence(+timestamp).
11780
+ // Keyed PER SOURCE: on the shared realtime client two sources sharing a channel
11781
+ // each process an event once; the dedupe only absorbs replays within a source.
11760
11782
  const processedEvents = new Map(); // Map<eventKey, timestamp>
11761
11783
  const EVENT_DEDUP_WINDOW = 2000; // ms
11762
11784
 
@@ -11801,11 +11823,92 @@ function markEventProcessed(eventKey) {
11801
11823
  }
11802
11824
  }
11803
11825
 
11826
+ // Bounded realtime growth: per-source caps + overflow counter, reset each load
11827
+ const realtimeMeta = new Map(); // Map<name, { mode, maxRows, appended: [], pending: 0 }>
11828
+
11829
+ function configureRealtimeMeta(dataSourceName, config, initialCount, limitQuery) {
11830
+ const cfg = (config && typeof config === 'object') ? config : {};
11831
+ const mode = cfg.mode === 'window' ? 'window' : 'append';
11832
+ const fallback = Math.max(500, 2 * initialCount);
11833
+ let maxRows;
11834
+ if (typeof cfg.maxRows === 'number' && cfg.maxRows >= 0) {
11835
+ maxRows = cfg.maxRows; // explicit 0 = unbounded (legacy opt-in, append only)
11836
+ if (maxRows === 0 && mode === 'window') {
11837
+ console.warn(`[Manifest Data] realtime maxRows 0 contradicts window mode for "${dataSourceName}"; using the default cap`);
11838
+ maxRows = fallback;
11839
+ }
11840
+ } else if (mode === 'window') {
11841
+ // Window = the limit query, else the initial count; a computed 0 is no window, so default
11842
+ const windowSize = (typeof limitQuery === 'number' && limitQuery > 0) ? limitQuery : initialCount;
11843
+ maxRows = windowSize > 0 ? windowSize : fallback;
11844
+ } else {
11845
+ maxRows = fallback;
11846
+ }
11847
+ realtimeMeta.set(dataSourceName, { mode, maxRows, appended: [], pending: 0 });
11848
+ window.ManifestDataStore.setSourceState(dataSourceName, { realtimeOverflow: 0 });
11849
+ }
11850
+
11851
+ // Events not applied since the last load — $x.<source>.$realtimeOverflow
11852
+ function bumpRealtimeOverflow(dataSourceName) {
11853
+ const state = Alpine.store('data')?.[`_${dataSourceName}_state`];
11854
+ window.ManifestDataStore.setSourceState(dataSourceName, { realtimeOverflow: (state?.realtimeOverflow || 0) + 1 });
11855
+ }
11856
+
11857
+ // Append under the cap. 'window' evicts the oldest realtime-appended row first
11858
+ // (never an initially-loaded row); otherwise the event counts in $realtimeOverflow.
11859
+ function realtimeAppend(dataSourceName, row, currentRows, generation) {
11860
+ const { landRows, landRemove } = window.ManifestDataStore;
11861
+ const meta = realtimeMeta.get(dataSourceName);
11862
+ if (!meta || meta.maxRows === 0) {
11863
+ if (meta) meta.appended.push(row.$id);
11864
+ landRows(dataSourceName, [row], { mode: 'append', generation });
11865
+ return;
11866
+ }
11867
+ const len = currentRows.length + meta.pending;
11868
+ if (len >= meta.maxRows) {
11869
+ if (meta.mode !== 'window') {
11870
+ bumpRealtimeOverflow(dataSourceName);
11871
+ return;
11872
+ }
11873
+ let evicted = null;
11874
+ for (let i = 0; i < meta.appended.length; i++) {
11875
+ // Oldest appended row still landed; pending (unflushed) ids stay tracked
11876
+ if (currentRows.some(r => r && r.$id === meta.appended[i])) {
11877
+ evicted = meta.appended.splice(i, 1)[0];
11878
+ break;
11879
+ }
11880
+ }
11881
+ if (evicted === null) {
11882
+ bumpRealtimeOverflow(dataSourceName);
11883
+ return;
11884
+ }
11885
+ landRemove(dataSourceName, [evicted], { generation });
11886
+ }
11887
+ meta.pending++;
11888
+ meta.appended.push(row.$id);
11889
+ landRows(dataSourceName, [row], { mode: 'append', generation })
11890
+ .then(() => { meta.pending = Math.max(0, meta.pending - 1); });
11891
+ }
11892
+
11893
+ function forgetRealtimeRow(dataSourceName, id) {
11894
+ const meta = realtimeMeta.get(dataSourceName);
11895
+ if (!meta) return;
11896
+ const i = meta.appended.indexOf(id);
11897
+ if (i !== -1) meta.appended.splice(i, 1);
11898
+ }
11899
+
11900
+ // Query-aware event filter: the source's own queries, evaluated client-side
11901
+ // (unevaluable → match; see rowMatchesQueries)
11902
+ function eventMatchesQueries(row, queriesConfig) {
11903
+ const matcher = window.ManifestDataQueries?.rowMatchesQueries;
11904
+ return matcher ? matcher(row, queriesConfig) : true;
11905
+ }
11906
+
11804
11907
  // Handle real-time events for database tables
11805
- async function handleTableRealtimeEvent(dataSourceName, databaseId, tableId, scope, scopeColumns, eventType, payload, generation) {
11908
+ async function handleTableRealtimeEvent(dataSourceName, databaseId, tableId, scope, scopeColumns, eventType, payload, generation, queriesConfig) {
11806
11909
 
11807
- // Deduplicate events
11808
- const eventKey = getEventKey(eventType, payload);
11910
+ // Deduplicate events (per source: shared-channel peers each process once)
11911
+ const eventKey = `${dataSourceName}|${getEventKey(eventType, payload)}`;
11809
11912
  if (isEventProcessed(eventKey)) {
11810
11913
  return;
11811
11914
  }
@@ -11829,9 +11932,15 @@ async function handleTableRealtimeEvent(dataSourceName, databaseId, tableId, sco
11829
11932
  if (eventType === 'create') {
11830
11933
  const row = payload?.$id ? payload : (payload?.row || payload);
11831
11934
  if (row && row.$id) {
11935
+ // Scope AND queries must match before the row lands
11832
11936
  const rowMatchesScope = await checkRowMatchesScope(row, scope, scopeColumns);
11833
- if (rowMatchesScope) {
11834
- landRows(dataSourceName, [row], { mode: 'append', generation });
11937
+ if (rowMatchesScope && eventMatchesQueries(row, queriesConfig)) {
11938
+ if (currentRows.find(r => r.$id === row.$id)) {
11939
+ // Echo of a row already held (optimistic create): merge, never counts as growth
11940
+ landRows(dataSourceName, [row], { mode: 'append', generation });
11941
+ } else {
11942
+ realtimeAppend(dataSourceName, row, currentRows, generation);
11943
+ }
11835
11944
  }
11836
11945
  } else {
11837
11946
  console.warn('[Manifest Data] Invalid row payload in create event:', payload);
@@ -11841,14 +11950,17 @@ async function handleTableRealtimeEvent(dataSourceName, databaseId, tableId, sco
11841
11950
  if (row && row.$id) {
11842
11951
  const existingRow = currentRows.find(r => r.$id === row.$id);
11843
11952
  const rowMatchesScope = await checkRowMatchesScope(row, scope, scopeColumns);
11844
- if (!rowMatchesScope) {
11845
- // Row no longer matches scope, remove it
11846
- if (existingRow) landRemove(dataSourceName, [row.$id], { generation });
11953
+ if (!rowMatchesScope || !eventMatchesQueries(row, queriesConfig)) {
11954
+ // Row stopped matching scope or queries, remove it
11955
+ if (existingRow) {
11956
+ landRemove(dataSourceName, [row.$id], { generation });
11957
+ forgetRealtimeRow(dataSourceName, row.$id);
11958
+ }
11847
11959
  return;
11848
11960
  }
11849
11961
  if (!existingRow) {
11850
- // Row not in list, but matches scope now - add it
11851
- landRows(dataSourceName, [row], { mode: 'append', generation });
11962
+ // Row not in list, but matches now - add it (capped like a create)
11963
+ realtimeAppend(dataSourceName, row, currentRows, generation);
11852
11964
  return;
11853
11965
  }
11854
11966
 
@@ -11922,6 +12034,7 @@ async function handleTableRealtimeEvent(dataSourceName, databaseId, tableId, sco
11922
12034
  const rowId = payload?.$id || payload?.row?.$id || payload?.rowId || payload;
11923
12035
  if (rowId) {
11924
12036
  landRemove(dataSourceName, [rowId.$id || rowId], { generation });
12037
+ forgetRealtimeRow(dataSourceName, rowId.$id || rowId);
11925
12038
  }
11926
12039
  }
11927
12040
 
@@ -12117,6 +12230,11 @@ async function loadDataSource(dataSourceName, locale = 'en', options = {}) {
12117
12230
  return false;
12118
12231
  }
12119
12232
  if (!authSettledUnresolvable(manifest)) return false;
12233
+ // Offline/unverified: restored rows of the last-known identity stay (logout and identity changes still reset)
12234
+ if (sessionUnverified(currentAuth()) && hasLiveRows(dataSourceName)) {
12235
+ setSourceState(dataSourceName, { loading: false, error: null, ready: true });
12236
+ return true;
12237
+ }
12120
12238
  updateStore(dataSourceName, [], { loading: false, error: null, ready: true });
12121
12239
  return true;
12122
12240
  };
@@ -12216,15 +12334,19 @@ async function loadDataSource(dataSourceName, locale = 'en', options = {}) {
12216
12334
  );
12217
12335
  if (superseded()) { landed = true; return null; }
12218
12336
 
12219
- // Subscribe to real-time updates for this table (events from a superseded identity drop)
12220
- if (window.ManifestDataRealtime && window.ManifestDataRealtime.subscribeToTable) {
12337
+ // Subscribe to real-time updates for this table (events from a
12338
+ // superseded identity drop); realtime: false opts the source out
12339
+ if (dataSource.realtime !== false && window.ManifestDataRealtime && window.ManifestDataRealtime.subscribeToTable) {
12340
+ const rtQueries = Array.isArray(queriesConfig?.default || queriesConfig) ? (queriesConfig.default || queriesConfig) : [];
12341
+ const limitQ = rtQueries.find(q => Array.isArray(q) && q[0] === 'limit');
12342
+ configureRealtimeMeta(dataSourceName, dataSource.realtime, Array.isArray(data) ? data.length : 0, limitQ ? limitQ[1] : null);
12221
12343
  const unsubscribe = await window.ManifestDataRealtime.subscribeToTable(
12222
12344
  dataSourceName,
12223
12345
  appwriteConfig.databaseId,
12224
12346
  tableId,
12225
12347
  scope,
12226
12348
  async (eventType, payload) => {
12227
- await handleTableRealtimeEvent(dataSourceName, appwriteConfig.databaseId, tableId, scope, scopeColumns, eventType, payload, generation);
12349
+ await handleTableRealtimeEvent(dataSourceName, appwriteConfig.databaseId, tableId, scope, scopeColumns, eventType, payload, generation, rtQueries);
12228
12350
  },
12229
12351
  () => !superseded()
12230
12352
  );
@@ -12265,15 +12387,19 @@ async function loadDataSource(dataSourceName, locale = 'en', options = {}) {
12265
12387
 
12266
12388
  if (superseded()) { landed = true; return null; }
12267
12389
 
12268
- // Subscribe to real-time updates for this bucket (events from a superseded identity drop)
12269
- if (window.ManifestDataRealtime && window.ManifestDataRealtime.subscribeToStorageBucket) {
12390
+ // Subscribe to real-time updates for this bucket (events from a
12391
+ // superseded identity drop); realtime: false opts the source out
12392
+ if (dataSource.realtime !== false && window.ManifestDataRealtime && window.ManifestDataRealtime.subscribeToStorageBucket) {
12393
+ const rtQueries = Array.isArray(queriesConfig?.default || queriesConfig) ? (queriesConfig.default || queriesConfig) : [];
12394
+ const limitQ = rtQueries.find(q => Array.isArray(q) && q[0] === 'limit');
12395
+ configureRealtimeMeta(dataSourceName, dataSource.realtime, Array.isArray(data) ? data.length : 0, limitQ ? limitQ[1] : null);
12270
12396
  const unsubscribe = await window.ManifestDataRealtime.subscribeToStorageBucket(
12271
12397
  dataSourceName,
12272
12398
  bucketId,
12273
12399
  scope,
12274
12400
  async (eventType, payload) => {
12275
12401
  if (superseded()) return;
12276
- await handleStorageRealtimeEvent(dataSourceName, bucketId, scope, eventType, payload, generation);
12402
+ await handleStorageRealtimeEvent(dataSourceName, bucketId, scope, eventType, payload, generation, rtQueries);
12277
12403
  },
12278
12404
  () => !superseded()
12279
12405
  );
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "manifest.appwrite.auth.js": "sha384-dsIWnH0qCAGSzAXMGrd8fvOrVl4tOIE6j5tC35JPTrQXZ56qLD36ARyvhR7vi3Id",
3
- "manifest.appwrite.data.js": "sha384-jeOzobMZv42WhbZ48jzse5PHLexYXx7VhHR59IyT5E7e+On+O5zLHBje0D0mMRS3",
3
+ "manifest.appwrite.data.js": "sha384-cmzVdqqqKGSMnroBhHczc9m7W72E9O/fV2KEHRDgHkTiLTbZjJj2bAoaVbXtn3A8",
4
4
  "manifest.appwrite.presences.js": "sha384-JyVDWFT69b7Svq8J8p9tNWe2v9PZNQBY5UyhtOl1vnuHFAX0CRQ3MA9SiKq5wzNh",
5
5
  "manifest.bindings.js": "sha384-lPtMf8Ykaic9gNVZKq8Scia1881ZeMAyxer3WCIkUNwwrgzGBWto1OXADUwjvORF",
6
6
  "manifest.charts.js": "sha384-G+huD7UvjF9zDovdVVlh4I5X1Mq4oNnJfoFg4NnGdP3R/4Skq9hy5cGuHNYLxDYm",
@@ -11,7 +11,7 @@
11
11
  "manifest.combobox.js": "sha384-MILTkrgsTzsYUjGo4ZuADqV85Xs4GmfB4xexfe9vbJMIoQTZ42W4zs+DTaVSPEsx",
12
12
  "manifest.components.js": "sha384-BUFA8h+G5Plr82sV7bKzO42pPoiRZwRQcKj1lt2ROFiKjjlkayU/vmkAFqEsdBA+",
13
13
  "manifest.computed.js": "sha384-GYML/e81gQfN+iDbqhPUgny8bINCyL+SrbTofoGk4hlCnLLjv51mCv42JMqq+ku5",
14
- "manifest.data.js": "sha384-j9OVEFvsLbMITqA9Fu8f3KcvcGjNO2HE5FgW1tjxMwwUikRoubaEj8XhFH01aR4s",
14
+ "manifest.data.js": "sha384-+1UOcfFJFXzjpwvvFiLB08B0++DrRbt/CssP8XuAmO+BdqqFfXafC1KmYLlzUEDC",
15
15
  "manifest.datepicker.js": "sha384-2XwFFnS4Bg5FDvG/v8x6KUvrjcBQEOYyTxynX2K/D/Qb3PI6+Y04lEwCnVDJLzwL",
16
16
  "manifest.defer.js": "sha384-pMRGqQKiEoJhpUcD40QeM4jEHau7sz9Xn/YCpiUamT1T4xJBZDSiYX+xnVrSWoq+",
17
17
  "manifest.device.js": "sha384-g+txmrEszYtuOvRelTp/c1wSNR2AtllVI9rx5NPPD7DzhVUnMNughonZykv2xlBW",
@@ -28,7 +28,7 @@
28
28
  "manifest.slides.js": "sha384-3uRTkyK9XPLmnxI2+igZlpi4EyPlU/7IHj5j3BZJJ2KN455vXyk99fiXV3feO/XY",
29
29
  "manifest.status.js": "sha384-MBO345ab7H6Uq1X2dZLt4Ge1Gcra+Z2qYApvlAeIV8CJhDDJrz2FPXpp+Kcp8zcM",
30
30
  "manifest.svg.js": "sha384-qr/8H9+2cIhSXNbRWRtIdrDlTOxKlNJqwEefHvCYoiBNW/kKhPTFa109Orv/EBnb",
31
- "manifest.sw.js": "sha384-4xhlg8+MN2W32Yh+pz7Ns5wYZ6qo6Tq6yWCneEFpiUepjwpMOA4AOI5yTsxQqQ7X",
31
+ "manifest.sw.js": "sha384-sTcnAL2w7bznwSS8c7uFDuPd/ImDTZlO1FBddiOuR0iDaiPo0TGPGeYk0ZeWUbQ5",
32
32
  "manifest.tabs.js": "sha384-OIIcyaQnGS0eNYk4zgAFEDboNYect7THvUd9D0V6nqCeDOxQcoiqLrBEmmWVTTet",
33
33
  "manifest.tailwind.js": "sha384-r/Jvqb+Piz21jUts10BbVAJoKkShOdJRVFpywyi4HPIi/OfOJq5CtPyWAPbdkMgt",
34
34
  "manifest.toasts.js": "sha384-3zkWxzw693pxg3QDFsoYCA3CqYaLKmBaMArULXODD66Utolpewl0OAeTB92aWUVv",
@@ -36,5 +36,5 @@
36
36
  "manifest.url.parameters.js": "sha384-J2aSVBOPsoqsbafHndrWLHEDpKb4AKJAoQnVmKA4gZh5P/8HHjFWHO/lkusmG84l",
37
37
  "manifest.utilities.js": "sha384-L5uXMLFBIF6LUM1haRjd4eGjHSWuqsCYSpPZRPYosNfJsMC5U5TnmjBxIhrZRe2d",
38
38
  "manifest.virtual.js": "sha384-ZDNoF9QVhVcVpkjIK6NH15S6I5c6OBshiJpXSOYjNsIB+298I0a7g3aFO+jyq4Vb",
39
- "manifest.js": "sha384-AvD8QPahsOp5hmdBGJtfu2jp/dYrxLgapvAzx0oc2POlfb/Gj1tvFBHG+ct76p3d"
39
+ "manifest.js": "sha384-lLuq+77pwlGNK01XTOSimDh8boFBUmKQA8rR53QudXl/Igiv8MU4w+wRCSHdc/mg"
40
40
  }
package/lib/manifest.js CHANGED
@@ -456,9 +456,9 @@
456
456
  return getPluginUrlCandidates(pluginName, version)[0];
457
457
  }
458
458
 
459
- // Alpine URL candidates from a data-alpine value (version tag or full URL)
459
+ // Alpine URL candidates from a data-alpine value (version tag, full URL, or same-origin path)
460
460
  function alpineUrlCandidates(dataAlpine) {
461
- if (dataAlpine && dataAlpine.startsWith('http')) return [dataAlpine];
461
+ if (dataAlpine && (dataAlpine.startsWith('http') || dataAlpine.startsWith('/'))) return [dataAlpine];
462
462
  const v = dataAlpine || '3';
463
463
  return CDN_HOSTS.map(h => `${h}/alpinejs@${v}/dist/cdn.min.js`);
464
464
  }