mnfst 0.5.80 → 0.5.82

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 (42) hide show
  1. package/LICENSE +1 -1
  2. package/lib/manifest.accordion.css +4 -4
  3. package/lib/manifest.appwrite.auth.js +66 -33
  4. package/lib/manifest.avatar.css +8 -8
  5. package/lib/manifest.button.css +7 -7
  6. package/lib/manifest.checkbox.css +5 -5
  7. package/lib/manifest.code.css +152 -193
  8. package/lib/manifest.code.js +841 -881
  9. package/lib/manifest.code.min.css +1 -1
  10. package/lib/manifest.colorpicker.css +11 -11
  11. package/lib/manifest.components.js +25 -155
  12. package/lib/manifest.css +278 -230
  13. package/lib/manifest.data.js +46 -2
  14. package/lib/manifest.dialog.css +2 -2
  15. package/lib/manifest.divider.css +2 -2
  16. package/lib/manifest.dropdown.css +9 -9
  17. package/lib/manifest.form.css +10 -10
  18. package/lib/manifest.input.css +9 -9
  19. package/lib/manifest.integrity.json +26 -0
  20. package/lib/manifest.js +60 -5
  21. package/lib/manifest.markdown.js +192 -79
  22. package/lib/manifest.min.css +1 -1
  23. package/lib/manifest.radio.css +1 -1
  24. package/lib/manifest.range.css +7 -7
  25. package/lib/manifest.resize.css +1 -1
  26. package/lib/manifest.router.js +49 -76
  27. package/lib/manifest.schema.json +1 -1
  28. package/lib/manifest.sidebar.css +5 -6
  29. package/lib/manifest.slides.css +5 -5
  30. package/lib/manifest.svg.js +75 -5
  31. package/lib/manifest.switch.css +4 -4
  32. package/lib/manifest.table.css +4 -4
  33. package/lib/manifest.theme.css +46 -41
  34. package/lib/manifest.toast.css +7 -7
  35. package/lib/manifest.tooltip.css +3 -3
  36. package/lib/manifest.tooltips.js +41 -0
  37. package/lib/manifest.typography.css +124 -69
  38. package/lib/manifest.utilities.css +48 -54
  39. package/lib/manifest.utilities.js +9 -29
  40. package/package.json +4 -7
  41. package/lib/manifest.export.js +0 -535
  42. package/lib/manifest.virtual.js +0 -319
@@ -12,7 +12,9 @@ async function ensureManifest() {
12
12
  try {
13
13
  const manifestUrl = (document.querySelector('link[rel="manifest"]')?.getAttribute('href')) || '/manifest.json';
14
14
  const response = await fetch(manifestUrl);
15
- return await response.json();
15
+ const manifest = await response.json();
16
+ interpolateManifest(manifest);
17
+ return manifest;
16
18
  } catch (error) {
17
19
  console.error('[Manifest Data] Failed to load manifest:', error);
18
20
  return null;
@@ -36,6 +38,33 @@ function interpolateEnvVars(str) {
36
38
  });
37
39
  }
38
40
 
41
+ // Recursively walk a manifest object and interpolate every string value in
42
+ // place. Object keys are left untouched. Called once at manifest-load time so
43
+ // downstream consumers (auth, data, appwrite) read already-resolved values.
44
+ function interpolateManifest(obj) {
45
+ if (obj === null || typeof obj !== 'object') return obj;
46
+ if (Array.isArray(obj)) {
47
+ for (let i = 0; i < obj.length; i++) {
48
+ const v = obj[i];
49
+ if (typeof v === 'string') {
50
+ obj[i] = interpolateEnvVars(v);
51
+ } else if (v !== null && typeof v === 'object') {
52
+ interpolateManifest(v);
53
+ }
54
+ }
55
+ return obj;
56
+ }
57
+ for (const key of Object.keys(obj)) {
58
+ const v = obj[key];
59
+ if (typeof v === 'string') {
60
+ obj[key] = interpolateEnvVars(v);
61
+ } else if (v !== null && typeof v === 'object') {
62
+ interpolateManifest(v);
63
+ }
64
+ }
65
+ return obj;
66
+ }
67
+
39
68
  // Helper to get nested value from object
40
69
  function getNestedValue(obj, path) {
41
70
  return path.split('.').reduce((current, key) => {
@@ -179,6 +208,7 @@ function getQueries(dataSource) {
179
208
  window.ManifestDataConfig = {
180
209
  ensureManifest,
181
210
  interpolateEnvVars,
211
+ interpolateManifest,
182
212
  getNestedValue,
183
213
  getDefaultLocale,
184
214
  parseContentPath,
@@ -1202,6 +1232,13 @@ window.ManifestDataStore = {
1202
1232
 
1203
1233
  /* Manifest Data Sources - File Loaders */
1204
1234
 
1235
+ // Key names that would walk into Object's prototype chain if used as nested-
1236
+ // path segments. Rejecting them in setNestedValue and deepMergeWithFallback
1237
+ // prevents a CSV row like `__proto__.polluted, true` (or a malicious JSON
1238
+ // locale file containing `{"__proto__": {...}}`) from polluting
1239
+ // Object.prototype and silently affecting every plain object on the page.
1240
+ const POLLUTING_KEYS = new Set(['__proto__', 'constructor', 'prototype']);
1241
+
1205
1242
  // Dynamic js-yaml loader
1206
1243
  let jsyaml = null;
1207
1244
  let yamlLoadingPromise = null;
@@ -1336,6 +1373,7 @@ function deepMergeWithFallback(currentData, fallbackData) {
1336
1373
  !Array.isArray(currentData) && !Array.isArray(fallbackData)) {
1337
1374
  const merged = { ...fallbackData };
1338
1375
  for (const key in currentData) {
1376
+ if (POLLUTING_KEYS.has(key)) continue;
1339
1377
  if (key.startsWith('_')) {
1340
1378
  // Preserve metadata from current locale
1341
1379
  merged[key] = currentData[key];
@@ -1363,6 +1401,9 @@ function deepMergeWithFallback(currentData, fallbackData) {
1363
1401
  // Numeric path segments (e.g. cards.0.title) create real arrays so x-for="card in $x....cards" works.
1364
1402
  function setNestedValue(obj, path, value) {
1365
1403
  const keys = path.split('.');
1404
+ // Drop the whole row if any segment would walk into the prototype chain.
1405
+ // `foo.constructor.prototype.polluted` is just as dangerous as `__proto__.polluted`.
1406
+ if (keys.some(k => POLLUTING_KEYS.has(k))) return;
1366
1407
  let current = obj;
1367
1408
 
1368
1409
  for (let i = 0; i < keys.length - 1; i++) {
@@ -11813,7 +11854,10 @@ async function initializeDataSourcesPlugin() {
11813
11854
  const manifestData = manifest;
11814
11855
  // Remove internal properties that shouldn't be exposed
11815
11856
  const { data, appwrite, components, preloadedComponents, ...publicManifest } = manifestData;
11816
- updateStore('manifest', publicManifest);
11857
+ // allowDuringInit: setIsInitializing(true) is active, so without this
11858
+ // flag updateStore short-circuits and $x.manifest stays unpopulated.
11859
+ window.ManifestDataStore.dataSourceCache.set(`manifest:${locale}`, publicManifest);
11860
+ updateStore('manifest', publicManifest, { loading: false, error: null, ready: true, allowDuringInit: true });
11817
11861
 
11818
11862
  const store = Alpine.store('data');
11819
11863
  Alpine.store('data', {
@@ -41,8 +41,8 @@
41
41
  min-height: 200px;
42
42
  max-height: 90vh;
43
43
  margin: auto;
44
- color: var(--color-content-stark, oklch(16.6% 0.026 267));
45
- background-color: var(--color-popover-surface, oklch(100% 0 0));
44
+ color: var(--color-content-stark, darkslategray);
45
+ background-color: var(--color-popover-surface, white);
46
46
  border: 0 none;
47
47
  border-radius: calc(var(--radius, 0.5rem) * 2);
48
48
  box-shadow: 0 20px 25px -5px rgb(0 0 0 / 0.1), 0 8px 10px -6px rgb(0 0 0 / 0.1);
@@ -12,7 +12,7 @@
12
12
  margin: var(--spacing-field-padding, 0.625rem) 0;
13
13
  white-space: nowrap;
14
14
  font-size: 0.875rem;
15
- color: var(--color-content-neutral, oklch(48.26% 0.0365 255.09));
15
+ color: var(--color-content-neutral, gray);
16
16
 
17
17
  /* Lines before and after content */
18
18
  &:before,
@@ -22,7 +22,7 @@
22
22
  flex: 1;
23
23
  width: auto;
24
24
  height: 1px;
25
- background-color: var(--color-line, oklch(48.3% 0.006422 17.4 / 0.15))
25
+ background-color: var(--color-line, color-mix(darkslategray 10%, transparent))
26
26
  }
27
27
 
28
28
  /* Space between lines and content */
@@ -45,7 +45,7 @@
45
45
  padding: 0.25rem;
46
46
  z-index: 50;
47
47
  list-style: none;
48
- background: var(--color-popover-surface, oklch(100% 0 0));
48
+ background: var(--color-popover-surface, white);
49
49
  border: 0 none;
50
50
  border-radius: var(--radius, 0.5rem);
51
51
  box-shadow: rgba(15, 15, 15, 0.05) 0px 0px 0px 1px, rgba(15, 15, 15, 0.1) 0px 3px 6px, rgba(15, 15, 15, 0.2) 0px 9px 24px;
@@ -63,7 +63,7 @@
63
63
  padding-inline-start: 0.5rem;
64
64
  padding-inline-end: 0.5rem;
65
65
  font-weight: normal;
66
- color: var(--color-content-stark, oklch(16.6% 0.026 267));
66
+ color: var(--color-content-stark, darkslategray);
67
67
  text-align: start;
68
68
  text-decoration: none;
69
69
  text-overflow: ellipsis;
@@ -75,14 +75,14 @@
75
75
  user-select: none;
76
76
 
77
77
  &:hover {
78
- color: var(--color-field-inverse, oklch(16.6% 0.026 267));
78
+ color: var(--color-field-inverse, darkslategray);
79
79
  text-decoration: inherit;
80
- background-color: var(--color-field-surface, oklch(91.79% 0.0029 264.26));
80
+ background-color: var(--color-field-surface, color-mix(darkslategray 10%, transparent));
81
81
  }
82
82
 
83
83
  &:active {
84
- color: var(--color-field-inverse, oklch(16.6% 0.026 267));
85
- background-color: var(--color-field-surface, oklch(91.79% 0.0029 264.26));
84
+ color: var(--color-field-inverse, darkslategray);
85
+ background-color: var(--color-field-surface, color-mix(darkslategray 10%, transparent));
86
86
  }
87
87
 
88
88
  & span,
@@ -99,7 +99,7 @@
99
99
  /* Titles */
100
100
  & small {
101
101
  padding: 0.25rem 0.5rem;
102
- color: var(--color-content-neutral, oklch(48.26% 0.0365 255.09));
102
+ color: var(--color-content-neutral, gray);
103
103
  }
104
104
 
105
105
  /* Horizontal rules (offset to ignore menu padding) */
@@ -109,7 +109,7 @@
109
109
  margin-inline-start: calc(0.25rem * -1);
110
110
  margin-top: 0.25rem;
111
111
  margin-bottom: 0.25rem;
112
- background-color: var(--color-line, oklch(48.3% 0.006422 17.4 / 0.15));
112
+ background-color: var(--color-line, color-mix(darkslategray 10%, transparent));
113
113
  }
114
114
 
115
115
  /* Labels */
@@ -146,7 +146,7 @@
146
146
 
147
147
  /* Dark theme */
148
148
  :where(.dark menu[popover]) :where(li, a, button, label):hover {
149
- background-color: var(--color-field-surface-hover, oklch(89.24% 0.0024 12.48));
149
+ background-color: var(--color-field-surface-hover, color-mix(darkslategray 15%, transparent));
150
150
  }
151
151
 
152
152
  /* Nested menu alignment */
@@ -47,7 +47,7 @@
47
47
  :where(form):not(.unstyle) {
48
48
  display: flex;
49
49
  flex-direction: column;
50
- gap: calc(var(--spacing) * 4);
50
+ gap: calc(var(--spacing, 0.25rem) * 4);
51
51
  width: 100%
52
52
  }
53
53
 
@@ -55,25 +55,25 @@
55
55
  :where(fieldset):not(.unstyle) {
56
56
  display: flex;
57
57
  flex-direction: column;
58
- gap: 0.375ch calc(var(--spacing) * 2);
58
+ gap: 0.375ch calc(var(--spacing, 0.25rem) * 2);
59
59
  width: 100%;
60
60
 
61
61
  &:has([type=radio], [type=checkbox]) {
62
- gap: calc(var(--spacing) * 2);
62
+ gap: calc(var(--spacing, 0.25rem) * 2);
63
63
  }
64
64
  }
65
65
 
66
66
  :where(fieldset:has(legend)):not(.unstyle) {
67
67
  padding: 1ch 1.5ch 1.5ch 1.5ch;
68
68
  border-radius: var(--radius, 0.5rem);
69
- border-color: var(--color-line, oklch(48.3% 0.006422 17.4 / 0.15));
69
+ border-color: var(--color-line, color-mix(darkslategray 10%, transparent));
70
70
  border-style: solid;
71
71
  border-width: 1px;
72
72
 
73
73
  & :where(legend) {
74
74
  padding: 0 1.5ch;
75
75
  font-size: 0.875rem;
76
- color: var(--color-content-subtle, oklch(67.4% 0.0318 251.27));
76
+ color: var(--color-content-subtle, darkgray);
77
77
  }
78
78
  }
79
79
 
@@ -97,7 +97,7 @@
97
97
  flex-direction: column;
98
98
  gap: 0.2ch;
99
99
  width: 100%;
100
- text-indent: calc(var(--radius) / 2);
100
+ text-indent: calc(var(--radius, 0.5rem) / 2);
101
101
  cursor: pointer;
102
102
 
103
103
  /* Prevent text indentation of bare label text nodes from being inherited */
@@ -107,7 +107,7 @@
107
107
 
108
108
  /* Indent label text in spans */
109
109
  :where(span:first-of-type) {
110
- padding-inline-start: calc(var(--radius) / 2)
110
+ padding-inline-start: calc(var(--radius, 0.5rem) / 2)
111
111
  }
112
112
 
113
113
  :where(button, [role=button], [type=button], [type=submit], select, input:not([role=button], [type=checkbox], [type=radio], [type=file], [type=search]), textarea) {
@@ -136,13 +136,13 @@
136
136
 
137
137
  /* Size buttons and inputs */
138
138
  & :where(.label, button, input:not([type=checkbox], [type=radio]), select, textarea) {
139
- width: calc(var(--spacing-field-height) * 8);
139
+ width: calc(var(--spacing-field-height, 2.25rem) * 8);
140
140
  max-width: 50%;
141
141
  }
142
142
 
143
143
  /* Focus state for .label wrapper for search and file inputs */
144
144
  & .label:focus-within {
145
- box-shadow: 0 0 0 2px color-mix(in oklch, var(--color-content-stark) 35%, transparent)
145
+ box-shadow: 0 0 0 2px color-mix(in oklch, var(--color-content-stark, darkslategray) 35%, transparent)
146
146
  }
147
147
 
148
148
  /* Align textarea label to top */
@@ -150,7 +150,7 @@
150
150
  align-items: start;
151
151
 
152
152
  :where(data) {
153
- padding-top: calc(var(--spacing))
153
+ padding-top: calc(var(--spacing, 0.25rem))
154
154
  }
155
155
  }
156
156
  }
@@ -5,8 +5,8 @@
5
5
  :where(input:not([type=range], [type=color]), textarea, label:has([type=search], [type=file]), .label:has([type=search], [type=file])):not(.unstyle) {
6
6
  width: 100%;
7
7
  max-width: 100%;
8
- color: var(--color-field-inverse, oklch(16.6% 0.026 267));
9
- background-color: var(--color-field-surface, oklch(91.79% 0.0029 264.26));
8
+ color: var(--color-field-inverse, darkslategray);
9
+ background-color: var(--color-field-surface, color-mix(darkslategray 10%, transparent));
10
10
  border-width: 0;
11
11
  border-style: solid;
12
12
  border-color: transparent;
@@ -16,23 +16,23 @@
16
16
  appearance: none;
17
17
 
18
18
  &:hover {
19
- background-color: var(--color-field-surface-hover, oklch(89.24% 0.0024 12.48))
19
+ background-color: var(--color-field-surface-hover, color-mix(darkslategray 15%, transparent))
20
20
  }
21
21
 
22
22
  &:active {
23
- background-color: var(--color-field-surface-hover, oklch(89.24% 0.0024 12.48))
23
+ background-color: var(--color-field-surface-hover, color-mix(darkslategray 15%, transparent))
24
24
  }
25
25
 
26
26
  &:focus-visible {
27
- background-color: var(--color-field-surface, oklch(91.79% 0.0029 264.26))
27
+ background-color: var(--color-field-surface, color-mix(darkslategray 10%, transparent))
28
28
  }
29
29
 
30
30
  &::placeholder {
31
- color: color-mix(in oklch, var(--color-field-inverse, oklch(16.6% 0.026 267)) 65%, transparent)
31
+ color: color-mix(in oklch, var(--color-field-inverse, darkslategray) 65%, transparent)
32
32
  }
33
33
 
34
34
  &::selection {
35
- background-color: color-mix(in oklch, var(--color-field-surface, oklch(91.79% 0.0029 264.26)) 80%, var(--color-field-inverse, oklch(16.6% 0.026 267)))
35
+ background-color: color-mix(in oklch, var(--color-field-surface, color-mix(darkslategray 10%, transparent)) 80%, var(--color-field-inverse, darkslategray))
36
36
  }
37
37
 
38
38
  &[type=file] {
@@ -91,7 +91,7 @@
91
91
  /* Additional styles for label with file input */
92
92
  :where(label, .label):has([type=file]):not(.unstyle) {
93
93
  justify-content: center;
94
- gap: var(--spacing, 0.5rem);
94
+ gap: var(--spacing, 0.25rem);
95
95
  height: var(--spacing-field-height, 2.25rem);
96
96
  cursor: pointer
97
97
  }
@@ -108,7 +108,7 @@
108
108
  width: var(--spacing-field-height, 2.25rem);
109
109
  height: 100%;
110
110
  margin-inline-end: 0;
111
- color: var(--color-content-subtle, oklch(67.4% 0.0318 251.27))
111
+ color: var(--color-content-subtle, darkgray)
112
112
  }
113
113
  }
114
114
 
@@ -0,0 +1,26 @@
1
+ {
2
+ "manifest.appwrite.auth.js": "sha384-to37ssZJXGeOS6+rf2VI47ox2mEqgsi5oQ1E5vv8XU/lDspbDFE1KHEMm8TxBhxW",
3
+ "manifest.appwrite.data.js": "sha384-00ulLT+GAIuPHA/rRT9p98vYlsyDzkyKXtg86BDQ6FGQa5vVVN+W6kuforniBAsz",
4
+ "manifest.appwrite.presence.js": "sha384-uxRpx9/Jj0kGtklH5QmUlAzD3zdSvFRfK6bcJQqxl+Bsf5tOo4zgwqJTQgtZoHQP",
5
+ "manifest.code.js": "sha384-7u03iKpTAimcMkf82glkELWzwDWRmlB9iYOC9tJ40gPH1QwyzdtFWA3OaSScJsFM",
6
+ "manifest.color.js": "sha384-Z9G/lzt0vVMxjz4wkPuGG1X9mmQAJR15aOoGX3ephf7r2wnlUWet5GLgkUMtT4vt",
7
+ "manifest.colorpicker.js": "sha384-0EVn+Ha06h7FIvOxc6WjZYnKYXzi+zba08yKvczSEGTRkWRxyKN2TFrZHI1SDCXu",
8
+ "manifest.colors.js": "sha384-u8iD6kapVj4OjeCILxBkYQKgXtDQ7LdEodILkQuknzPMwzSMBmDHN25UuzxepHby",
9
+ "manifest.components.js": "sha384-3dCTD5EwCZTiX+1obYtDNM3WWwPh2JDQUQQsdRUUK3gs6FXjse1ShkKaT/2jsNaI",
10
+ "manifest.data.js": "sha384-+wfMPBlMsmLJ7EJWGJMTKGAhLaLCyOVX+Nq+ps3Lly58QC9Dp3XRHK5yangII0yq",
11
+ "manifest.dropdowns.js": "sha384-WMrFoSpKfJuo81dyrwhVrDO8rq+rDwh2x8x4nH01BY5ZHkvjE+/SaT2gWCI0zOn+",
12
+ "manifest.icons.js": "sha384-uOkboYrovjCpl22eey3Jaxpey+pOnot5NDnRRumcRxiR7IOVaRh1i20gYnWXR5dW",
13
+ "manifest.localization.js": "sha384-eKdBIMEAwsugPP2p2fuPzQUkU44f1+Y0JgukMJ1KXLQY1/AYvpcGsEiritVDElsN",
14
+ "manifest.markdown.js": "sha384-5dpYLup1j/JLmoVvE1Qn47rwYwtU6kH2PvuiNzU1nqa0LMRWZhdnKhKO7I3I0cyI",
15
+ "manifest.resize.js": "sha384-Ak5gf44ERfh9pOSAD1qZzJSysslpwBCkevIlz7R3dszTUyzUKGKGF4pn5arOtgG0",
16
+ "manifest.router.js": "sha384-n6xmIfWnYzd/0kkVTFuHhFzHuxiDgZ1Lg1W0yB6/w3Myw5pQ6PgE6SJBHfVsO7/D",
17
+ "manifest.slides.js": "sha384-3uRTkyK9XPLmnxI2+igZlpi4EyPlU/7IHj5j3BZJJ2KN455vXyk99fiXV3feO/XY",
18
+ "manifest.svg.js": "sha384-nc+3spSGNS2l+82maL/OFz2iOGUhLZ0kqeooj28CEcdElM4OZa34e0tbnokZHVI6",
19
+ "manifest.tabs.js": "sha384-v6Ti0zHfdLhkFHbTMg0FH6uMrThuBvZrL2PQgVBeeXhDjuN7x4MtoNWogPbAQTaD",
20
+ "manifest.tailwind.js": "sha384-aHLvl2oSuUgy06VaBqhhByn5wWxqvnqxw6KCwehakKUS00F/s/Nb62umeASS6Y4P",
21
+ "manifest.toasts.js": "sha384-ytd5rDbax/Ou9z23uedFXPZbxDPsk2E/pxCTq4WLvfv+os1qTI6kELp0kPp07g24",
22
+ "manifest.tooltips.js": "sha384-Hhip5ZN66xhDw3m0XBrKLKLpcVRz3Z9RszPKqo6xvFF0mrUgQBVZ+mZjZsXgOOjS",
23
+ "manifest.url.parameters.js": "sha384-FIufiClqDx1rJpU/QUc9z/D43qClQ6Qm8rBahipbJl9BDHUvhrOsUDegmTWW7Tuf",
24
+ "manifest.utilities.js": "sha384-Q98oZClq/iRKFmuwHolisLgEitsTZiEPHxUW29liKlnL1Gx+YGq8MMivYbDlGDD6",
25
+ "manifest.js": "sha384-M0y6toAEVWcozOx0D6eVdOiYOgF4f3nJyNmvfvh+/sr8gcMiugytOIC9FZ22NC8H"
26
+ }
package/lib/manifest.js CHANGED
@@ -175,6 +175,41 @@
175
175
  const DEFAULT_VERSION = 'latest';
176
176
  const ALPINE_CDN_URL = 'https://cdn.jsdelivr.net/npm/alpinejs@3/dist/cdn.min.js';
177
177
 
178
+ // SRI integrity map: { 'manifest.foo.min.js': 'sha384-...', ... }
179
+ // Inlined by build.mjs's emitIntegrityMap() step. Empty in source so the
180
+ // unbuilt loader works in dev (where files are served from the local
181
+ // project, same-origin, no SRI needed). Built artifact in lib/ carries
182
+ // the populated map. Looked up by the filename suffix of every script URL
183
+ // addScript() injects — when the file is in the map, the matching
184
+ // integrity + crossorigin attributes are set, and the browser refuses to
185
+ // execute the script if the bytes don't match (defends against CDN
186
+ // poisoning / npm hijack).
187
+ const INTEGRITY = {
188
+ "manifest.appwrite.auth.js": "sha384-to37ssZJXGeOS6+rf2VI47ox2mEqgsi5oQ1E5vv8XU/lDspbDFE1KHEMm8TxBhxW",
189
+ "manifest.appwrite.data.js": "sha384-00ulLT+GAIuPHA/rRT9p98vYlsyDzkyKXtg86BDQ6FGQa5vVVN+W6kuforniBAsz",
190
+ "manifest.appwrite.presence.js": "sha384-uxRpx9/Jj0kGtklH5QmUlAzD3zdSvFRfK6bcJQqxl+Bsf5tOo4zgwqJTQgtZoHQP",
191
+ "manifest.code.js": "sha384-7u03iKpTAimcMkf82glkELWzwDWRmlB9iYOC9tJ40gPH1QwyzdtFWA3OaSScJsFM",
192
+ "manifest.color.js": "sha384-Z9G/lzt0vVMxjz4wkPuGG1X9mmQAJR15aOoGX3ephf7r2wnlUWet5GLgkUMtT4vt",
193
+ "manifest.colorpicker.js": "sha384-0EVn+Ha06h7FIvOxc6WjZYnKYXzi+zba08yKvczSEGTRkWRxyKN2TFrZHI1SDCXu",
194
+ "manifest.colors.js": "sha384-u8iD6kapVj4OjeCILxBkYQKgXtDQ7LdEodILkQuknzPMwzSMBmDHN25UuzxepHby",
195
+ "manifest.components.js": "sha384-3dCTD5EwCZTiX+1obYtDNM3WWwPh2JDQUQQsdRUUK3gs6FXjse1ShkKaT/2jsNaI",
196
+ "manifest.data.js": "sha384-+wfMPBlMsmLJ7EJWGJMTKGAhLaLCyOVX+Nq+ps3Lly58QC9Dp3XRHK5yangII0yq",
197
+ "manifest.dropdowns.js": "sha384-WMrFoSpKfJuo81dyrwhVrDO8rq+rDwh2x8x4nH01BY5ZHkvjE+/SaT2gWCI0zOn+",
198
+ "manifest.icons.js": "sha384-uOkboYrovjCpl22eey3Jaxpey+pOnot5NDnRRumcRxiR7IOVaRh1i20gYnWXR5dW",
199
+ "manifest.localization.js": "sha384-eKdBIMEAwsugPP2p2fuPzQUkU44f1+Y0JgukMJ1KXLQY1/AYvpcGsEiritVDElsN",
200
+ "manifest.markdown.js": "sha384-5dpYLup1j/JLmoVvE1Qn47rwYwtU6kH2PvuiNzU1nqa0LMRWZhdnKhKO7I3I0cyI",
201
+ "manifest.resize.js": "sha384-Ak5gf44ERfh9pOSAD1qZzJSysslpwBCkevIlz7R3dszTUyzUKGKGF4pn5arOtgG0",
202
+ "manifest.router.js": "sha384-n6xmIfWnYzd/0kkVTFuHhFzHuxiDgZ1Lg1W0yB6/w3Myw5pQ6PgE6SJBHfVsO7/D",
203
+ "manifest.slides.js": "sha384-3uRTkyK9XPLmnxI2+igZlpi4EyPlU/7IHj5j3BZJJ2KN455vXyk99fiXV3feO/XY",
204
+ "manifest.svg.js": "sha384-nc+3spSGNS2l+82maL/OFz2iOGUhLZ0kqeooj28CEcdElM4OZa34e0tbnokZHVI6",
205
+ "manifest.tabs.js": "sha384-v6Ti0zHfdLhkFHbTMg0FH6uMrThuBvZrL2PQgVBeeXhDjuN7x4MtoNWogPbAQTaD",
206
+ "manifest.tailwind.js": "sha384-aHLvl2oSuUgy06VaBqhhByn5wWxqvnqxw6KCwehakKUS00F/s/Nb62umeASS6Y4P",
207
+ "manifest.toasts.js": "sha384-ytd5rDbax/Ou9z23uedFXPZbxDPsk2E/pxCTq4WLvfv+os1qTI6kELp0kPp07g24",
208
+ "manifest.tooltips.js": "sha384-Hhip5ZN66xhDw3m0XBrKLKLpcVRz3Z9RszPKqo6xvFF0mrUgQBVZ+mZjZsXgOOjS",
209
+ "manifest.url.parameters.js": "sha384-FIufiClqDx1rJpU/QUc9z/D43qClQ6Qm8rBahipbJl9BDHUvhrOsUDegmTWW7Tuf",
210
+ "manifest.utilities.js": "sha384-Q98oZClq/iRKFmuwHolisLgEitsTZiEPHxUW29liKlnL1Gx+YGq8MMivYbDlGDD6"
211
+ };
212
+
178
213
  // Get base URL for a given version
179
214
  function getBaseUrl(version = DEFAULT_VERSION) {
180
215
  return `https://cdn.jsdelivr.net/npm/mnfst@${version}/lib`;
@@ -199,9 +234,7 @@
199
234
  'slides',
200
235
  'resize',
201
236
  'colorpicker',
202
- 'url-parameters',
203
- 'virtual',
204
- 'export'
237
+ 'url-parameters'
205
238
  ];
206
239
 
207
240
  // Appwrite integration plugins (opt-in only, never auto-loaded)
@@ -211,10 +244,16 @@
211
244
  'appwrite-presence'
212
245
  ];
213
246
 
214
- // Plugin dependencies: plugins that require other plugins to be loaded first
247
+ // Plugin dependencies: plugins that require other plugins to be loaded first.
248
+ // All Appwrite plugins depend on `data` for env-var interpolation at
249
+ // manifest-load time (window.ManifestDataConfig.interpolateManifest); auth
250
+ // and presence also share the data plugin's manifest-fetch plumbing.
251
+ // Localization reads data-source URLs that may carry ${VAR} references.
215
252
  const PLUGIN_DEPENDENCIES = {
253
+ 'appwrite-auth': ['data'],
216
254
  'appwrite-data': ['data'],
217
- 'appwrite-presence': ['data']
255
+ 'appwrite-presence': ['data'],
256
+ 'localization': ['data']
218
257
  };
219
258
 
220
259
  // Derive default plugin list from manifest (only load data/localization/components when manifest needs them)
@@ -315,6 +354,15 @@
315
354
  const script = document.createElement('script');
316
355
  script.src = url;
317
356
  script.async = false; // Ensure scripts execute in order
357
+ // Apply SRI when the file is in the inlined integrity map. The map
358
+ // keys files by basename, so it works whether the URL points at
359
+ // jsDelivr or a user-configured pluginBase mirror — as long as the
360
+ // served bytes match what this loader version was built against.
361
+ const fileName = url.split('/').pop().split('?')[0];
362
+ if (INTEGRITY[fileName]) {
363
+ script.integrity = INTEGRITY[fileName];
364
+ script.crossOrigin = 'anonymous';
365
+ }
318
366
  script.onload = () => resolve();
319
367
  script.onerror = () => reject(new Error(`Failed to load ${pluginName} from ${url}`));
320
368
  document.head.appendChild(script);
@@ -522,6 +570,13 @@
522
570
  manifest = await manifestPromise;
523
571
  }
524
572
  if (manifest && typeof window !== 'undefined') {
573
+ // Resolve ${VAR} env-var references once, at the canonical load
574
+ // point, so downstream plugins (auth, data, appwrite) read
575
+ // already-interpolated values instead of each handling env-var
576
+ // substitution themselves.
577
+ if (window.ManifestDataConfig?.interpolateManifest) {
578
+ window.ManifestDataConfig.interpolateManifest(manifest);
579
+ }
525
580
  window.__manifestLoaded = manifest;
526
581
  if (window.ManifestComponentsRegistry) {
527
582
  window.ManifestComponentsRegistry.manifest = manifest;