mnfst 0.5.226 → 0.5.228

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.
@@ -303,14 +303,13 @@ function initializeAuthStore() {
303
303
  // Identity ended or changed in another tab: scoped data must drop this tab's rows
304
304
  const nextId = state.isAuthenticated ? (state.user?.$id || null) : null;
305
305
  if (prevId && nextId !== prevId) {
306
- if (!nextId) {
307
- store.teams = [];
308
- store.currentTeam = null;
309
- }
306
+ store._resetTeamsState();
310
307
  window.dispatchEvent(new CustomEvent('manifest:auth:session-cleared'));
308
+ if (nextId) store._adoptCrossTabTeams(nextId);
311
309
  } else if (nextId && !wasAuthenticated) {
312
310
  // Signed in from another tab: this tab's identity-bound data reloads
313
311
  window.dispatchEvent(new CustomEvent(state.isAnonymous ? 'manifest:auth:anonymous' : 'manifest:auth:login', { detail: { user: state.user, crossTab: true } }));
312
+ store._adoptCrossTabTeams(nextId);
314
313
  }
315
314
  }
316
315
  } catch (error) {
@@ -405,6 +404,8 @@ function initializeAuthStore() {
405
404
  _guestManual: false,
406
405
  _signInPendingUntil: 0, // signed-out init with guest-auto or an auth callback still to sign in
407
406
  _sessionUnverified: false, // init could not reach Appwrite: signed out locally, never broadcast
407
+ _crossTabTeams: null, // latest cross-tab team load; older ones skip their writes
408
+ _teamsEpoch: 0, // bumped by every team reset; an in-flight listTeams from an older one is discarded
408
409
  _authEpoch: 0, // bumped by every identity change; an in-flight recheck from an older epoch is dropped
409
410
  _recheckTimer: null,
410
411
  _recheckAttempt: 0,
@@ -640,8 +641,9 @@ function initializeAuthStore() {
640
641
  this._initialized = true;
641
642
  this._initializing = false;
642
643
 
643
- // Guest-auto / callback sign-in follows: scoped data holds instead of flashing signed-out
644
- if (!this.isAuthenticated) {
644
+ // Guest-auto / callback sign-in follows: scoped data holds instead of flashing signed-out.
645
+ // Not while unverified: nothing signs in until Appwrite is reachable (the recheck handles it)
646
+ if (!this.isAuthenticated && !this._sessionUnverified) {
645
647
  let callback = false;
646
648
  try {
647
649
  // Team invites need an existing session (acceptInvite refuses signed-out), so they don't sign in
@@ -665,10 +667,14 @@ function initializeAuthStore() {
665
667
  // manifest:auth:teams-loaded for anything needing the full set.
666
668
  if (appwriteConfig && this.isAuthenticated && appwriteConfig.teams
667
669
  && (!this.isAnonymous || appwriteConfig.guestTeams)) {
670
+ const owner = this.user?.$id;
668
671
  this._loadTeamsAndSeed(appwriteConfig)
669
- .then(() => window.dispatchEvent(new CustomEvent('manifest:auth:teams-loaded', {
670
- detail: { teams: this.teams, currentTeam: this.currentTeam }
671
- })))
672
+ .then(() => {
673
+ if (!this.isAuthenticated || this.user?.$id !== owner) return;
674
+ window.dispatchEvent(new CustomEvent('manifest:auth:teams-loaded', {
675
+ detail: { teams: this.teams, currentTeam: this.currentTeam }
676
+ }));
677
+ })
672
678
  .catch(e => console.warn('[Manifest Appwrite Auth] Background team load failed:', e?.message || e));
673
679
  }
674
680
  },
@@ -774,9 +780,34 @@ function initializeAuthStore() {
774
780
  this.deletedTemplateTeams = [];
775
781
  this.deletedTemplateRoles = [];
776
782
  this._teamImmutableCache = {};
783
+ this._teamsEpoch++;
777
784
  if (this.stopTeamsRealtime) {
778
785
  try { this.stopTeamsRealtime(); } catch (e) { /* ignore */ }
779
786
  }
787
+ if (this.stopTeamsPolling) {
788
+ try { this.stopTeamsPolling(); } catch (e) { /* ignore */ }
789
+ }
790
+ },
791
+
792
+ // Teams for an identity adopted from another tab. That tab seeds; this one
793
+ // only lists. A newer adoption or identity change supersedes this load.
794
+ _adoptCrossTabTeams(userId) {
795
+ const token = {};
796
+ this._crossTabTeams = token;
797
+ const current = () => this._crossTabTeams === token && this.isAuthenticated === true && this.user?.$id === userId;
798
+ (async () => {
799
+ try {
800
+ const cfg = await config.getAppwriteConfig();
801
+ if (!cfg?.teams || (this.isAnonymous && !cfg.guestTeams) || !current()) return;
802
+ await this._loadTeamsAndSeed(cfg, { seed: false });
803
+ } catch (e) {
804
+ console.warn('[Manifest Appwrite Auth] Cross-tab team load failed:', e?.message || e);
805
+ }
806
+ if (!current()) return;
807
+ window.dispatchEvent(new CustomEvent('manifest:auth:teams-loaded', {
808
+ detail: { teams: this.teams, currentTeam: this.currentTeam }
809
+ }));
810
+ })();
780
811
  },
781
812
 
782
813
  // Call the deployed guest-migration function; the current session authenticates it.
@@ -801,14 +832,14 @@ function initializeAuthStore() {
801
832
 
802
833
  // Load the user's teams and seed configured defaults. Shared by the guest,
803
834
  // magic-link, OAuth, and init/restore paths.
804
- async _loadTeamsAndSeed(appwriteConfig) {
835
+ async _loadTeamsAndSeed(appwriteConfig, { seed = true } = {}) {
805
836
  const cfg = appwriteConfig || await config.getAppwriteConfig();
806
837
  if (!cfg?.teams) {
807
838
  return;
808
839
  }
809
840
  // Startup race: we can arrive before teams.core/defaults wire listTeams +
810
841
  // ensureDefaultTeams onto the store. Wait briefly rather than skip.
811
- const needsSeed = !!(cfg.permanentTeams || cfg.templateTeams);
842
+ const needsSeed = seed && !!(cfg.permanentTeams || cfg.templateTeams);
812
843
  const ready = () => typeof this.listTeams === 'function'
813
844
  && (!needsSeed || typeof window.ManifestAppwriteAuthTeamsDefaults?.ensureDefaultTeams === 'function');
814
845
  for (let i = 0; i < 40 && !ready(); i++) {
@@ -968,19 +999,8 @@ function initializeAuthStore() {
968
999
  this.otpPhrase = null;
969
1000
  this._otpUserId = null;
970
1001
 
971
- // Stop teams realtime subscription if active
972
- if (this.stopTeamsRealtime) {
973
- this.stopTeamsRealtime();
974
- }
975
-
976
- // Stop teams polling if active (fallback)
977
- if (this.stopTeamsPolling) {
978
- this.stopTeamsPolling();
979
- }
980
-
981
- // Clear teams on logout
982
- this.teams = [];
983
- this.currentTeam = null;
1002
+ // Clear teams (stops realtime/polling, discards in-flight lists)
1003
+ this._resetTeamsState();
984
1004
 
985
1005
  // Restore to guest state after logout (guest-auto only, and not when
986
1006
  // already a guest — don't mint a new guest on top).
@@ -1014,19 +1034,8 @@ function initializeAuthStore() {
1014
1034
  this.user = null;
1015
1035
  this.session = null;
1016
1036
  }
1017
- // Stop teams realtime subscription if active
1018
- if (this.stopTeamsRealtime) {
1019
- this.stopTeamsRealtime();
1020
- }
1021
-
1022
- // Stop teams polling if active (fallback)
1023
- if (this.stopTeamsPolling) {
1024
- this.stopTeamsPolling();
1025
- }
1026
-
1027
1037
  // Clear teams on logout error too
1028
- this.teams = [];
1029
- this.currentTeam = null;
1038
+ this._resetTeamsState();
1030
1039
  if (!this.isAuthenticated) this._clearIdentity();
1031
1040
  // Expired session (401) is still a logout: scoped data must drop the old rows
1032
1041
  syncStateToStorage(this);
@@ -1062,8 +1071,7 @@ function initializeAuthStore() {
1062
1071
  this._oauthProvider = null;
1063
1072
 
1064
1073
  // Clear teams
1065
- this.teams = [];
1066
- this.currentTeam = null;
1074
+ this._resetTeamsState();
1067
1075
 
1068
1076
  // Clear OAuth provider from storage
1069
1077
  try {
@@ -1084,8 +1092,7 @@ function initializeAuthStore() {
1084
1092
  this.session = null;
1085
1093
  this.magicLinkSent = false;
1086
1094
  this.magicLinkExpired = false;
1087
- this.teams = [];
1088
- this.currentTeam = null;
1095
+ this._resetTeamsState();
1089
1096
  syncStateToStorage(this);
1090
1097
  window.dispatchEvent(new CustomEvent('manifest:auth:session-cleared'));
1091
1098
  return { success: false, error: error.message };
@@ -1520,6 +1527,12 @@ function initializeTeamsCore() {
1520
1527
  return { success: false, error: 'You must be signed in to list teams' };
1521
1528
  }
1522
1529
 
1530
+ // Answer for this identity only: a reset or identity change discards it
1531
+ const owner = this.user?.$id || null;
1532
+ const generation = this._teamsEpoch;
1533
+ const stale = () => !this.isAuthenticated || (this.user?.$id || null) !== owner || this._teamsEpoch !== generation;
1534
+ const discarded = { success: false, error: 'Identity changed during team load', stale: true };
1535
+
1523
1536
  try {
1524
1537
  const params = {
1525
1538
  queries: queries
@@ -1528,6 +1541,7 @@ function initializeTeamsCore() {
1528
1541
  params.search = search;
1529
1542
  }
1530
1543
  const result = await this._appwrite.teams.list(params);
1544
+ if (stale()) return discarded;
1531
1545
 
1532
1546
  // Update store with teams
1533
1547
  this.teams = result.teams || [];
@@ -1547,19 +1561,24 @@ function initializeTeamsCore() {
1547
1561
  if (window.ManifestAppwriteAuthTeamsDefaults && this.isTeamImmutable) {
1548
1562
  for (const team of this.teams) {
1549
1563
  if (!this._teamImmutableCache[team.$id]) {
1550
- this._teamImmutableCache[team.$id] = await this.isTeamImmutable(team.$id);
1564
+ const immutable = await this.isTeamImmutable(team.$id);
1565
+ if (stale()) return discarded;
1566
+ this._teamImmutableCache[team.$id] = immutable;
1551
1567
  }
1552
1568
  }
1553
1569
  }
1554
1570
 
1555
1571
  // Load deleted template teams (if defaults module is loaded)
1556
1572
  if (window.ManifestAppwriteAuthTeamsDefaults && this.getDeletedTemplateTeams) {
1557
- this.deletedTemplateTeams = await this.getDeletedTemplateTeams();
1573
+ const deletedTemplateTeams = await this.getDeletedTemplateTeams();
1574
+ if (stale()) return discarded;
1575
+ this.deletedTemplateTeams = deletedTemplateTeams;
1558
1576
  }
1559
1577
 
1560
1578
  // Clean up duplicate default teams (permanent/template) if any exist
1561
1579
  if (window.ManifestAppwriteAuthTeamsDefaults && this.cleanupDuplicateDefaultTeams) {
1562
1580
  const cleanupResult = await this.cleanupDuplicateDefaultTeams();
1581
+ if (stale()) return discarded;
1563
1582
  if (cleanupResult.cleaned > 0) {
1564
1583
  if (cleanupResult.errors && cleanupResult.errors.length > 0) {
1565
1584
  console.warn('[Manifest Appwrite Auth] Some duplicate teams could not be deleted:', cleanupResult.errors);
@@ -1568,12 +1587,15 @@ function initializeTeamsCore() {
1568
1587
  if (this.listTeams) {
1569
1588
  await this.listTeams();
1570
1589
  }
1590
+ if (stale()) return discarded;
1571
1591
  }
1572
1592
  }
1573
1593
 
1574
1594
  // Load deleted template roles for current team (if roles defaults module is loaded)
1575
1595
  if (this.currentTeam && this.currentTeam.$id && window.ManifestAppwriteAuthTeamsRolesDefaults && this.getDeletedTemplateRoles) {
1576
- this.deletedTemplateRoles = await this.getDeletedTemplateRoles(this.currentTeam.$id);
1596
+ const deletedTemplateRoles = await this.getDeletedTemplateRoles(this.currentTeam.$id);
1597
+ if (stale()) return discarded;
1598
+ this.deletedTemplateRoles = deletedTemplateRoles;
1577
1599
  }
1578
1600
 
1579
1601
  // Set currentTeam to first default team if available and not already set
@@ -1582,8 +1604,10 @@ function initializeTeamsCore() {
1582
1604
  const hasDefaultTeams = (appwriteConfig?.permanentTeams && Array.isArray(appwriteConfig.permanentTeams) && appwriteConfig.permanentTeams.length > 0) ||
1583
1605
  (appwriteConfig?.templateTeams && Array.isArray(appwriteConfig.templateTeams) && appwriteConfig.templateTeams.length > 0);
1584
1606
 
1607
+ if (stale()) return discarded;
1585
1608
  if (hasDefaultTeams && window.ManifestAppwriteAuthTeamsDefaults && this.getDefaultTeams) {
1586
1609
  const defaultTeams = await this.getDefaultTeams();
1610
+ if (stale()) return discarded;
1587
1611
  if (defaultTeams.length > 0) {
1588
1612
  this.currentTeam = defaultTeams[0];
1589
1613
  } else {
@@ -1598,12 +1622,14 @@ function initializeTeamsCore() {
1598
1622
  if (this.currentTeam && this.currentTeam.$id && window.ManifestAppwriteAuthTeamsMembers && this.listMemberships) {
1599
1623
  try {
1600
1624
  const membershipsResult = await this.listMemberships(this.currentTeam.$id);
1625
+ if (stale()) return discarded;
1601
1626
  if (membershipsResult.success) {
1602
1627
  this.currentTeamMemberships = membershipsResult.memberships || [];
1603
1628
  }
1604
1629
  } catch (error) {
1605
1630
  // Silently handle errors (e.g., team was deleted)
1606
1631
  // listMemberships already handles "team not found" gracefully
1632
+ if (stale()) return discarded;
1607
1633
  this.currentTeamMemberships = [];
1608
1634
  }
1609
1635
  }
@@ -1613,6 +1639,7 @@ function initializeTeamsCore() {
1613
1639
  // Check for any truthy value (function, object, or true flag)
1614
1640
  if (!this._teamsRealtimeUnsubscribe && !this._teamsRealtimeSubscribing) {
1615
1641
  const appwriteConfig = await config.getAppwriteConfig();
1642
+ if (stale()) return discarded;
1616
1643
  if (this._appwrite?.realtime && this.startTeamsRealtime) {
1617
1644
  this.startTeamsRealtime();
1618
1645
  } else if (appwriteConfig?.teamsPollInterval && typeof appwriteConfig.teamsPollInterval === 'number' && appwriteConfig.teamsPollInterval > 0) {
@@ -1626,6 +1653,7 @@ function initializeTeamsCore() {
1626
1653
 
1627
1654
  return { success: true, teams: result.teams || [], total: result.total || 0 };
1628
1655
  } catch (error) {
1656
+ if (stale()) return discarded;
1629
1657
  this.error = error.message;
1630
1658
  return { success: false, error: error.message };
1631
1659
  }
@@ -2,7 +2,7 @@
2
2
 
3
3
  (function () {
4
4
 
5
- const MANIFEST_BUILD_VERSION = '0.5.226';
5
+ const MANIFEST_BUILD_VERSION = '0.5.228';
6
6
 
7
7
  /* Manifest Data Sources - Appwrite Integration */
8
8
 
@@ -2,7 +2,7 @@
2
2
 
3
3
  (function () {
4
4
 
5
- const MANIFEST_BUILD_VERSION = '0.5.226';
5
+ const MANIFEST_BUILD_VERSION = '0.5.228';
6
6
 
7
7
  /* Manifest Data Sources - Configuration */
8
8
 
@@ -11459,13 +11459,14 @@ function scheduleAuthRetry(dataSourceName, locale) {
11459
11459
  AUTH_RETRY_EVENTS.forEach(type => window.addEventListener(type, retry));
11460
11460
  }
11461
11461
 
11462
- // Teams known for this identity: login/anonymous dispatch after teams load, teams-loaded after the background load
11462
+ // Teams known for this identity: login/anonymous dispatch after teams load, teams-loaded after the background load.
11463
+ // A cross-tab login arrives before this tab's team load; its teams-loaded follows.
11463
11464
  let teamsSettledFor = null;
11464
11465
  // A sign-in deadline already answered by an auth event no longer holds sources
11465
11466
  let answeredDeadline = 0;
11466
11467
  if (typeof window !== 'undefined') {
11467
11468
  ['manifest:auth:teams-loaded', 'manifest:auth:login', 'manifest:auth:anonymous'].forEach(type =>
11468
- window.addEventListener(type, () => { teamsSettledFor = authUserId(currentAuth()); }));
11469
+ window.addEventListener(type, e => { if (!e?.detail?.crossTab) teamsSettledFor = authUserId(currentAuth()); }));
11469
11470
  // Kept only when logout restored the same (guest) identity whose teams already loaded
11470
11471
  ['manifest:auth:logout', 'manifest:auth:session-cleared', 'manifest:auth:initialized'].forEach(type =>
11471
11472
  window.addEventListener(type, () => { if (type === 'manifest:auth:initialized' || teamsSettledFor !== authUserId(currentAuth())) teamsSettledFor = null; }));
@@ -11481,10 +11482,11 @@ function authUserId(auth) {
11481
11482
  return auth?.user?.$id || auth?.user?.id || null;
11482
11483
  }
11483
11484
 
11484
- // Guest-auto or an auth callback is signing in after a signed-out init (bounded by the auth store)
11485
+ // Guest-auto or an auth callback is signing in after a signed-out init (bounded by the auth store).
11486
+ // Not while the session is unverified (no sign-in follows until Appwrite is reachable).
11485
11487
  // Prerender never waits on (or bakes) a guest's rows
11486
11488
  function signInWaitMs(auth) {
11487
- if (!auth || auth.isAuthenticated === true || window.__manifestRender) return 0;
11489
+ if (!auth || auth.isAuthenticated === true || auth._sessionUnverified === true || window.__manifestRender) return 0;
11488
11490
  const until = auth._signInPendingUntil || 0;
11489
11491
  if (until === answeredDeadline) return 0;
11490
11492
  return Math.max(0, until - Date.now());
@@ -11551,6 +11553,8 @@ function confirmedIdentity() {
11551
11553
  // A previous user's rows drop at once; rows read signed out stay live until the reload lands.
11552
11554
  function setupAuthResetListener() {
11553
11555
  let bound = (currentAuth() ? confirmedIdentity() : null) ?? lastKnownIdentity();
11556
+ // Reads under an unverified session failed or came from the snapshot: confirming the same identity still reloads
11557
+ let unverified = currentAuth()?._sessionUnverified === true;
11554
11558
  const reset = async (clear) => {
11555
11559
  const manifest = await window.ManifestDataConfig?.ensureManifest?.();
11556
11560
  const ds = window.ManifestDataStore;
@@ -11571,12 +11575,17 @@ function setupAuthResetListener() {
11571
11575
  const onAuth = (type) => {
11572
11576
  const ended = type === 'manifest:auth:logout' || type === 'manifest:auth:session-cleared';
11573
11577
  const next = confirmedIdentity() ?? (ended ? '' : null);
11574
- if (next === null) return;
11578
+ if (next === null) { if (currentAuth()?._sessionUnverified === true) unverified = true; return; }
11575
11579
  const prev = bound;
11576
11580
  bound = next;
11577
- if (prev === next) return;
11578
- // Unknown before: rows so far were read under this same session (a sign-out still drops them)
11579
- if (prev === null && !ended) return;
11581
+ const recovered = unverified;
11582
+ unverified = false;
11583
+ // Same identity, or unknown before (rows so far were read under this same session; a sign-out still drops them):
11584
+ // no reset, but an unverified boot's reads are redone with the rows kept live
11585
+ if (prev === next || (prev === null && !ended)) {
11586
+ if (recovered) reset(false);
11587
+ return;
11588
+ }
11580
11589
  reset(prev !== '');
11581
11590
  };
11582
11591
  ['manifest:auth:logout', 'manifest:auth:session-cleared', 'manifest:auth:login', 'manifest:auth:anonymous', 'manifest:auth:initialized']
@@ -1,6 +1,6 @@
1
1
  {
2
- "manifest.appwrite.auth.js": "sha384-Ek2fHprBtcIFHAkOHtELD40gjfME3lWdmIQGB7h8+gcm7hn5QJzt9DRpo9huz4BE",
3
- "manifest.appwrite.data.js": "sha384-bwfWutqQz9CnVgvXIKCR9VZrRQ3ytswJ6zvKOevhLobHOaryZazSAr4tFRurawiZ",
2
+ "manifest.appwrite.auth.js": "sha384-dsIWnH0qCAGSzAXMGrd8fvOrVl4tOIE6j5tC35JPTrQXZ56qLD36ARyvhR7vi3Id",
3
+ "manifest.appwrite.data.js": "sha384-KZ8iQZ7C8DRx64IK49o+sqXFxHhIK7GKm8cRj4gvEy1MYmVWpnCmznPCWztFI5g3",
4
4
  "manifest.appwrite.presences.js": "sha384-JyVDWFT69b7Svq8J8p9tNWe2v9PZNQBY5UyhtOl1vnuHFAX0CRQ3MA9SiKq5wzNh",
5
5
  "manifest.bindings.js": "sha384-lPtMf8Ykaic9gNVZKq8Scia1881ZeMAyxer3WCIkUNwwrgzGBWto1OXADUwjvORF",
6
6
  "manifest.charts.js": "sha384-gEAv/98+29RbhvNkiNWTNyBPbLTFr2Ld15wLu29FLCL57j1cwGChRrL9Pfk7dBtT",
@@ -11,7 +11,7 @@
11
11
  "manifest.combobox.js": "sha384-MILTkrgsTzsYUjGo4ZuADqV85Xs4GmfB4xexfe9vbJMIoQTZ42W4zs+DTaVSPEsx",
12
12
  "manifest.components.js": "sha384-4bc3HgPvF9DHMiOG08w+nWXI7Hho01RuAPAUL9xyLxOiS2igeZpulCVcvr5aT9v6",
13
13
  "manifest.computed.js": "sha384-GYML/e81gQfN+iDbqhPUgny8bINCyL+SrbTofoGk4hlCnLLjv51mCv42JMqq+ku5",
14
- "manifest.data.js": "sha384-Dtpxer0CayxZCsGD8zCe8lW4MwsnaWA7Yxu1cWBxPQI1PJHh6qCwEJejHYt2go3F",
14
+ "manifest.data.js": "sha384-kaByNpTzaPcQiJeIDl7CTnXale/otGrq4BG9dfv+Fhw+s95z4A7YhgvtAZmMKLIa",
15
15
  "manifest.datepicker.js": "sha384-XnbeURni2X91ozVzatQcSjYYIS4MoW12dBRJnYAGBr0nCQ624heH5s+xtQSpLZX6",
16
16
  "manifest.defer.js": "sha384-WcCf8YQ1bKIXCLSZ24a0bJwepbYntYc8TzQM50hklo5VMIH8AtzDnwl6WU4prRv1",
17
17
  "manifest.device.js": "sha384-g+txmrEszYtuOvRelTp/c1wSNR2AtllVI9rx5NPPD7DzhVUnMNughonZykv2xlBW",
@@ -20,14 +20,14 @@
20
20
  "manifest.export.js": "sha384-Rx6XvqBZc4apzP/FwcDr6yIln4/zNa08Q4ZqBZcEqUz1aNZQfl4h0+Ae7mqCQyuG",
21
21
  "manifest.icons.js": "sha384-kKOINpX70YzNO3FvkV6umrmO3f0KIu0DNbwB+ej55a7y/lhU7v/myQtXL0bwCTbt",
22
22
  "manifest.localization.js": "sha384-EImsIw8Z3l13V5eH9ZJF/yfsOfIvR1oPRNSArANkPji7V8O3IRf6zMwsNiAGj3Hk",
23
- "manifest.markdown.js": "sha384-JWUxlUZADxk1hZY7NpDX051UhtXt/ofpfsCDBRcweU6JhLbN8B832yPLgCatxFdl",
23
+ "manifest.markdown.js": "sha384-heyDR40LXHaAmAuA+fa381uFwShk1oAqpFFY6E2Qq4T3VN0TQfRqyc++MF40K5Hj",
24
24
  "manifest.native.js": "sha384-g+txmrEszYtuOvRelTp/c1wSNR2AtllVI9rx5NPPD7DzhVUnMNughonZykv2xlBW",
25
25
  "manifest.payments.js": "sha384-8pofk2zhxtapPMpwnFyTelPMrYhShNhDCE722uQh/EYFvZFuPLmSdgunqsarVQjv",
26
26
  "manifest.router.js": "sha384-xkQaHO60lMQwtnqGPxPJJ646eyqBjINs4AFesrQbe2dWqPIoIcJ9RD5wsjqjak7w",
27
27
  "manifest.slides.js": "sha384-3uRTkyK9XPLmnxI2+igZlpi4EyPlU/7IHj5j3BZJJ2KN455vXyk99fiXV3feO/XY",
28
28
  "manifest.status.js": "sha384-MBO345ab7H6Uq1X2dZLt4Ge1Gcra+Z2qYApvlAeIV8CJhDDJrz2FPXpp+Kcp8zcM",
29
29
  "manifest.svg.js": "sha384-qr/8H9+2cIhSXNbRWRtIdrDlTOxKlNJqwEefHvCYoiBNW/kKhPTFa109Orv/EBnb",
30
- "manifest.sw.js": "sha384-e59BjfTqiJXTPdMgK3bkvYA2mzha1WEQeLgPABSDg35IPb+5Zd0BMUvND2kxrxoc",
30
+ "manifest.sw.js": "sha384-r3vBPbaW3PRru8sBETOY01m0hg7bV5IgEptsEmnZReTHSIfKWoFgrV6GivNkphuK",
31
31
  "manifest.tabs.js": "sha384-OIIcyaQnGS0eNYk4zgAFEDboNYect7THvUd9D0V6nqCeDOxQcoiqLrBEmmWVTTet",
32
32
  "manifest.tailwind.js": "sha384-r/Jvqb+Piz21jUts10BbVAJoKkShOdJRVFpywyi4HPIi/OfOJq5CtPyWAPbdkMgt",
33
33
  "manifest.text.edit.js": "sha384-RzOvLQE8GbmI6gntAwiotDewYT/08OHcd7sJ5hLon8e8u1Xbq1D7VfEGuaRVd2CE",
@@ -769,9 +769,17 @@ async function initializeMarkdownPlugin() {
769
769
  }, 0);
770
770
  }
771
771
  }
772
- }
773
772
 
774
- // Code highlighting is handled by manifest.code.js plugin
773
+ // Notify the code plugin to scan the new subtree — copy-only
774
+ // inline codespans have no directive, so initTree misses them.
775
+ if (window.ManifestCode?.observeAll) {
776
+ window.ManifestCode.observeAll(el);
777
+ }
778
+ document.dispatchEvent(new CustomEvent('manifest:code-blocks-converted', {
779
+ bubbles: true,
780
+ detail: { root: el }
781
+ }));
782
+ }
775
783
 
776
784
  // Show content with fade-in
777
785
  hasContent = true;
@@ -835,6 +843,9 @@ async function initializeMarkdownPlugin() {
835
843
  // Post-process HTML to enable checkboxes (remove disabled attribute)
836
844
  html = html.replace(/<input type="checkbox"([^>]*?)disabled([^>]*?)>/g, '<input type="checkbox"$1$2>');
837
845
 
846
+ // Promote inline `foo`{copy} blocks to real attributes.
847
+ html = applyInlineCodeAttributes(html);
848
+
838
849
  // Apply opt-in DOMPurify sanitization for x-markdown.safe
839
850
  html = await maybeSanitizeMarkdownHtml(html, safe);
840
851
 
@@ -888,8 +899,15 @@ async function initializeMarkdownPlugin() {
888
899
  // Start initialization
889
900
  initAlpine();
890
901
 
891
- // Re-highlight code blocks after content update
892
- // Code highlighting is handled by manifest.code.js plugin
902
+ // Notify the code plugin to scan the new subtree — copy-only
903
+ // inline codespans have no directive, so initTree misses them.
904
+ if (window.ManifestCode?.observeAll) {
905
+ window.ManifestCode.observeAll(element);
906
+ }
907
+ document.dispatchEvent(new CustomEvent('manifest:code-blocks-converted', {
908
+ bubbles: true,
909
+ detail: { root: element }
910
+ }));
893
911
  } catch (error) {
894
912
  console.error('[Manifest Markdown] Failed to process element:', error);
895
913
  }
@@ -16,7 +16,7 @@
16
16
 
17
17
  // Build stamps the published version here; unstamped (dev) falls back to the
18
18
  // registration URL's `v`, then 'dev'.
19
- const BUILD_VERSION = '0.5.226';
19
+ const BUILD_VERSION = '0.5.228';
20
20
  const CACHE_PREFIX = 'mnfst-sw:';
21
21
  const META_CACHE = CACHE_PREFIX + 'meta';
22
22
  // Sized to hold a full precache.json warm-up (PRECACHE_MAX_ENTRIES server-side)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mnfst",
3
- "version": "0.5.226",
3
+ "version": "0.5.228",
4
4
  "private": false,
5
5
  "workspaces": [
6
6
  "templates/starter",