mnfst 0.5.22 → 0.5.23
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.
- package/dist/manifest.appwrite.auth.js +4 -1
- package/dist/manifest.code.js +17 -17
- package/dist/manifest.components.js +66 -39
- package/dist/manifest.data.js +38 -1
- package/dist/manifest.js +61 -9
- package/dist/manifest.localization.js +8 -4
- package/package.json +1 -1
|
@@ -8,11 +8,14 @@
|
|
|
8
8
|
|
|
9
9
|
/* Auth config */
|
|
10
10
|
|
|
11
|
-
// Load manifest if not already loaded
|
|
11
|
+
// Load manifest if not already loaded (loader may set __manifestLoaded / registry.manifest)
|
|
12
12
|
async function ensureManifest() {
|
|
13
13
|
if (window.ManifestComponentsRegistry?.manifest) {
|
|
14
14
|
return window.ManifestComponentsRegistry.manifest;
|
|
15
15
|
}
|
|
16
|
+
if (window.__manifestLoaded) {
|
|
17
|
+
return window.__manifestLoaded;
|
|
18
|
+
}
|
|
16
19
|
|
|
17
20
|
try {
|
|
18
21
|
const response = await fetch('/manifest.json');
|
package/dist/manifest.code.js
CHANGED
|
@@ -47,11 +47,6 @@ async function loadHighlightJS() {
|
|
|
47
47
|
return hljsPromise;
|
|
48
48
|
}
|
|
49
49
|
|
|
50
|
-
// Preload highlight.js as soon as script loads
|
|
51
|
-
loadHighlightJS().catch(() => {
|
|
52
|
-
// Silently ignore errors during preload
|
|
53
|
-
});
|
|
54
|
-
|
|
55
50
|
// Optional optimization: Configure utilities plugin if present
|
|
56
51
|
if (window.ManifestUtilities) {
|
|
57
52
|
// Tell utilities plugin to ignore code-related DOM changes and classes
|
|
@@ -798,19 +793,24 @@ function initializeCodePlugin() {
|
|
|
798
793
|
customElements.define('x-code-group', XCodeGroupElement);
|
|
799
794
|
}
|
|
800
795
|
|
|
801
|
-
//
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
});
|
|
808
|
-
|
|
809
|
-
// Also listen for the event on the document body for better coverage
|
|
810
|
-
document.body.addEventListener('manifest:code-blocks-converted', async () => {
|
|
811
|
-
await processExistingCodeBlocks();
|
|
812
|
-
});
|
|
796
|
+
// Listen for markdown plugin conversions (always process when new blocks appear)
|
|
797
|
+
const runProcess = () => processExistingCodeBlocks();
|
|
798
|
+
document.addEventListener('manifest:code-blocks-converted', runProcess);
|
|
799
|
+
if (document.body) {
|
|
800
|
+
document.body.addEventListener('manifest:code-blocks-converted', runProcess);
|
|
801
|
+
}
|
|
813
802
|
|
|
803
|
+
// Defer loading highlight.js until first code block is in view (or process immediately if none to observe)
|
|
804
|
+
const codeTargets = document.querySelectorAll('pre > code:not(.hljs):not([data-highlighted="yes"]), x-code:not([data-highlighted="yes"])');
|
|
805
|
+
if (codeTargets.length === 0) {
|
|
806
|
+
return;
|
|
807
|
+
}
|
|
808
|
+
const io = new IntersectionObserver((entries) => {
|
|
809
|
+
if (!entries.some(e => e.isIntersecting)) return;
|
|
810
|
+
io.disconnect();
|
|
811
|
+
runProcess();
|
|
812
|
+
}, { rootMargin: '100px', threshold: 0 });
|
|
813
|
+
codeTargets.forEach(el => io.observe(el));
|
|
814
814
|
} catch (error) {
|
|
815
815
|
console.error('[Manifest] Failed to initialize code plugin:', error);
|
|
816
816
|
}
|
|
@@ -6,40 +6,50 @@ window.ManifestComponentsRegistry = {
|
|
|
6
6
|
registered: new Set(),
|
|
7
7
|
preloaded: [],
|
|
8
8
|
initialize() {
|
|
9
|
-
//
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
});
|
|
28
|
-
this.preloaded = (this.manifest?.preloadedComponents || []).map(path => path.split('/').pop().replace('.html', ''));
|
|
29
|
-
} else {
|
|
30
|
-
console.warn('[Manifest] Failed to load manifest.json (HTTP', req.status + ')');
|
|
9
|
+
// Use loader-provided manifest if set; otherwise load synchronously (standalone)
|
|
10
|
+
let manifest = window.__manifestLoaded || this.manifest;
|
|
11
|
+
if (!manifest) {
|
|
12
|
+
try {
|
|
13
|
+
const manifestUrl = (document.querySelector('link[rel="manifest"]')?.getAttribute('href')) || '/manifest.json';
|
|
14
|
+
const req = new XMLHttpRequest();
|
|
15
|
+
req.open('GET', manifestUrl + (manifestUrl.includes('?') ? '&' : '?') + 't=' + Date.now(), false);
|
|
16
|
+
req.setRequestHeader('Cache-Control', 'no-cache, no-store, must-revalidate');
|
|
17
|
+
req.setRequestHeader('Pragma', 'no-cache');
|
|
18
|
+
req.setRequestHeader('Expires', '0');
|
|
19
|
+
req.send(null);
|
|
20
|
+
if (req.status === 200) {
|
|
21
|
+
manifest = JSON.parse(req.responseText);
|
|
22
|
+
} else {
|
|
23
|
+
console.warn('[Manifest] Failed to load manifest.json (HTTP', req.status + ')');
|
|
24
|
+
}
|
|
25
|
+
} catch (e) {
|
|
26
|
+
console.warn('[Manifest] Failed to load manifest.json:', e.message);
|
|
31
27
|
}
|
|
32
|
-
}
|
|
33
|
-
|
|
28
|
+
}
|
|
29
|
+
if (manifest) {
|
|
30
|
+
this.manifest = manifest;
|
|
31
|
+
const allComponents = [
|
|
32
|
+
...(this.manifest?.preloadedComponents || []),
|
|
33
|
+
...(this.manifest?.components || [])
|
|
34
|
+
];
|
|
35
|
+
allComponents.forEach(path => {
|
|
36
|
+
const name = path.split('/').pop().replace('.html', '');
|
|
37
|
+
this.registered.add(name);
|
|
38
|
+
});
|
|
39
|
+
this.preloaded = (this.manifest?.preloadedComponents || []).map(path => path.split('/').pop().replace('.html', ''));
|
|
34
40
|
}
|
|
35
41
|
}
|
|
36
42
|
};
|
|
37
43
|
|
|
38
44
|
// Components loader
|
|
45
|
+
// Uses cache for resolved content and _loading for in-flight promises so duplicate
|
|
46
|
+
// loadComponent(name) calls share one network request.
|
|
39
47
|
window.ManifestComponentsLoader = {
|
|
40
48
|
cache: {},
|
|
49
|
+
_loading: {},
|
|
41
50
|
initialize() {
|
|
42
51
|
this.cache = {};
|
|
52
|
+
this._loading = {};
|
|
43
53
|
// Preload components listed in registry.preloaded
|
|
44
54
|
const registry = window.ManifestComponentsRegistry;
|
|
45
55
|
if (registry && Array.isArray(registry.preloaded)) {
|
|
@@ -54,6 +64,9 @@ window.ManifestComponentsLoader = {
|
|
|
54
64
|
if (this.cache[name]) {
|
|
55
65
|
return this.cache[name];
|
|
56
66
|
}
|
|
67
|
+
if (this._loading[name]) {
|
|
68
|
+
return this._loading[name];
|
|
69
|
+
}
|
|
57
70
|
const registry = window.ManifestComponentsRegistry;
|
|
58
71
|
if (!registry || !registry.manifest) {
|
|
59
72
|
console.warn('[Manifest] Manifest not loaded, cannot load component:', name);
|
|
@@ -65,19 +78,25 @@ window.ManifestComponentsLoader = {
|
|
|
65
78
|
console.warn('[Manifest] Component', name, 'not found in manifest.');
|
|
66
79
|
return null;
|
|
67
80
|
}
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
81
|
+
const promise = (async () => {
|
|
82
|
+
try {
|
|
83
|
+
const response = await fetch('/' + path);
|
|
84
|
+
if (!response.ok) {
|
|
85
|
+
console.warn('[Manifest] HTML file not found for component', name, 'at path:', path, '(HTTP', response.status + ')');
|
|
86
|
+
return null;
|
|
87
|
+
}
|
|
88
|
+
const content = await response.text();
|
|
89
|
+
this.cache[name] = content;
|
|
90
|
+
return content;
|
|
91
|
+
} catch (error) {
|
|
92
|
+
console.warn('[Manifest] Failed to load component', name, 'from', path + ':', error.message);
|
|
72
93
|
return null;
|
|
94
|
+
} finally {
|
|
95
|
+
delete this._loading[name];
|
|
73
96
|
}
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
} catch (error) {
|
|
78
|
-
console.warn('[Manifest] Failed to load component', name, 'from', path + ':', error.message);
|
|
79
|
-
return null;
|
|
80
|
-
}
|
|
97
|
+
})();
|
|
98
|
+
this._loading[name] = promise;
|
|
99
|
+
return promise;
|
|
81
100
|
}
|
|
82
101
|
};
|
|
83
102
|
|
|
@@ -716,19 +735,27 @@ function initializeComponents() {
|
|
|
716
735
|
window.dispatchEvent(new CustomEvent('manifest:components-ready'));
|
|
717
736
|
}
|
|
718
737
|
|
|
719
|
-
//
|
|
720
|
-
//
|
|
738
|
+
// When data plugin is loaded: wait for manifest:data-ready so $x.content is ready before components render.
|
|
739
|
+
// When data plugin is absent: init immediately (no artificial delay).
|
|
721
740
|
function waitForDataThenInitialize() {
|
|
741
|
+
const hasDataPlugin = typeof window.ManifestDataConfig !== 'undefined';
|
|
742
|
+
|
|
743
|
+
if (!hasDataPlugin) {
|
|
744
|
+
initializeComponents();
|
|
745
|
+
return;
|
|
746
|
+
}
|
|
747
|
+
|
|
722
748
|
window.addEventListener('manifest:data-ready', () => {
|
|
723
749
|
initializeComponents();
|
|
724
750
|
}, { once: true });
|
|
725
751
|
|
|
726
|
-
// Fallback: if data plugin
|
|
752
|
+
// Fallback: if data plugin never fires (e.g. slow network, error), initialize anyway
|
|
753
|
+
const fallbackMs = 5000;
|
|
727
754
|
setTimeout(() => {
|
|
728
755
|
if (!window.__manifestComponentsInitialized) {
|
|
729
756
|
initializeComponents();
|
|
730
757
|
}
|
|
731
|
-
},
|
|
758
|
+
}, fallbackMs);
|
|
732
759
|
}
|
|
733
760
|
|
|
734
761
|
if (document.readyState === 'loading') {
|
package/dist/manifest.data.js
CHANGED
|
@@ -1,10 +1,13 @@
|
|
|
1
1
|
/* Manifest Data Sources - Configuration */
|
|
2
2
|
|
|
3
|
-
// Load manifest if not already loaded
|
|
3
|
+
// Load manifest if not already loaded (loader may set __manifestLoaded / registry.manifest)
|
|
4
4
|
async function ensureManifest() {
|
|
5
5
|
if (window.ManifestComponentsRegistry?.manifest) {
|
|
6
6
|
return window.ManifestComponentsRegistry.manifest;
|
|
7
7
|
}
|
|
8
|
+
if (window.__manifestLoaded) {
|
|
9
|
+
return window.__manifestLoaded;
|
|
10
|
+
}
|
|
8
11
|
|
|
9
12
|
try {
|
|
10
13
|
const response = await fetch('/manifest.json');
|
|
@@ -1148,10 +1151,38 @@ let yamlLoadingPromise = null;
|
|
|
1148
1151
|
let papaparse = null;
|
|
1149
1152
|
let csvLoadingPromise = null;
|
|
1150
1153
|
|
|
1154
|
+
// Collect all path-like strings from manifest.data (recursive; includes nested locale objects)
|
|
1155
|
+
function collectDataPaths(manifest) {
|
|
1156
|
+
const paths = [];
|
|
1157
|
+
if (!manifest?.data || typeof manifest.data !== 'object') return paths;
|
|
1158
|
+
function visit(val) {
|
|
1159
|
+
if (typeof val === 'string' && (val.startsWith('/') || /\.(yaml|yml|csv|json)$/i.test(val))) {
|
|
1160
|
+
paths.push(val);
|
|
1161
|
+
} else if (Array.isArray(val)) {
|
|
1162
|
+
val.forEach(visit);
|
|
1163
|
+
} else if (val && typeof val === 'object' && !Array.isArray(val)) {
|
|
1164
|
+
Object.values(val).forEach(visit);
|
|
1165
|
+
}
|
|
1166
|
+
}
|
|
1167
|
+
Object.values(manifest.data).forEach(visit);
|
|
1168
|
+
return paths;
|
|
1169
|
+
}
|
|
1170
|
+
|
|
1171
|
+
function manifestDataPathsInclude(manifest, extensions) {
|
|
1172
|
+
const paths = collectDataPaths(manifest);
|
|
1173
|
+
return paths.some(p => extensions.some(ext => p.toLowerCase().includes(ext)));
|
|
1174
|
+
}
|
|
1175
|
+
|
|
1151
1176
|
async function loadYamlLibrary() {
|
|
1152
1177
|
if (jsyaml) return jsyaml;
|
|
1153
1178
|
if (yamlLoadingPromise) return yamlLoadingPromise;
|
|
1154
1179
|
|
|
1180
|
+
const manifest = await window.ManifestDataConfig?.ensureManifest?.();
|
|
1181
|
+
if (manifest && !manifestDataPathsInclude(manifest, ['.yaml', '.yml'])) {
|
|
1182
|
+
yamlLoadingPromise = Promise.reject(new Error('[Manifest Data] No YAML paths in manifest - skipping loader'));
|
|
1183
|
+
return yamlLoadingPromise;
|
|
1184
|
+
}
|
|
1185
|
+
|
|
1155
1186
|
yamlLoadingPromise = new Promise((resolve, reject) => {
|
|
1156
1187
|
const script = document.createElement('script');
|
|
1157
1188
|
script.src = 'https://cdn.jsdelivr.net/npm/js-yaml/dist/js-yaml.min.js';
|
|
@@ -1181,6 +1212,12 @@ async function loadCSVParser() {
|
|
|
1181
1212
|
if (papaparse) return papaparse;
|
|
1182
1213
|
if (csvLoadingPromise) return csvLoadingPromise;
|
|
1183
1214
|
|
|
1215
|
+
const manifest = await window.ManifestDataConfig?.ensureManifest?.();
|
|
1216
|
+
if (manifest && !manifestDataPathsInclude(manifest, ['.csv'])) {
|
|
1217
|
+
csvLoadingPromise = Promise.reject(new Error('[Manifest Data] No CSV paths in manifest - skipping loader'));
|
|
1218
|
+
return csvLoadingPromise;
|
|
1219
|
+
}
|
|
1220
|
+
|
|
1184
1221
|
csvLoadingPromise = new Promise((resolve, reject) => {
|
|
1185
1222
|
const script = document.createElement('script');
|
|
1186
1223
|
script.src = 'https://cdn.jsdelivr.net/npm/papaparse@latest/papaparse.min.js';
|
package/dist/manifest.js
CHANGED
|
@@ -52,6 +52,33 @@
|
|
|
52
52
|
'appwrite-presence': ['data']
|
|
53
53
|
};
|
|
54
54
|
|
|
55
|
+
// Derive default plugin list from manifest (only load data/localization/components when manifest needs them)
|
|
56
|
+
function getDefaultPluginsFromManifest(manifest) {
|
|
57
|
+
if (!manifest || typeof manifest !== 'object') {
|
|
58
|
+
return AVAILABLE_PLUGINS.slice();
|
|
59
|
+
}
|
|
60
|
+
const hasData = manifest.data && typeof manifest.data === 'object' && Object.keys(manifest.data).length > 0;
|
|
61
|
+
const hasComponents = (manifest.components?.length > 0) || (manifest.preloadedComponents?.length > 0);
|
|
62
|
+
const hasLocalization = (() => {
|
|
63
|
+
if (!manifest.data || typeof manifest.data !== 'object') return false;
|
|
64
|
+
for (const collection of Object.values(manifest.data)) {
|
|
65
|
+
if (!collection || typeof collection !== 'object') continue;
|
|
66
|
+
if (typeof collection.locales === 'string') return true;
|
|
67
|
+
for (const key of Object.keys(collection)) {
|
|
68
|
+
if (['url', 'headers', 'params', 'transform', 'defaultValue', 'locales'].includes(key)) continue;
|
|
69
|
+
if (/^[a-zA-Z]{2}(-[a-zA-Z]{2})?$/.test(key)) return true;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
return false;
|
|
73
|
+
})();
|
|
74
|
+
return AVAILABLE_PLUGINS.filter(p => {
|
|
75
|
+
if (p === 'data') return hasData;
|
|
76
|
+
if (p === 'localization') return hasLocalization;
|
|
77
|
+
if (p === 'components') return hasComponents;
|
|
78
|
+
return true;
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
|
|
55
82
|
// Get plugin URL from CDN
|
|
56
83
|
function getPluginUrl(pluginName, version = DEFAULT_VERSION) {
|
|
57
84
|
const base = getBaseUrl(version);
|
|
@@ -193,12 +220,13 @@
|
|
|
193
220
|
const version = script.getAttribute('data-version') || DEFAULT_VERSION;
|
|
194
221
|
|
|
195
222
|
let pluginList = [];
|
|
223
|
+
const deriveFromManifest = !plugins;
|
|
196
224
|
|
|
197
225
|
if (plugins) {
|
|
198
226
|
// Explicit declaration - load only specified plugins (core + Appwrite)
|
|
199
227
|
pluginList = plugins.split(',').map(p => p.trim()).filter(p => p);
|
|
200
228
|
} else {
|
|
201
|
-
// Default:
|
|
229
|
+
// Default: start with all core plugins; loader will trim by manifest when manifest is available
|
|
202
230
|
pluginList = AVAILABLE_PLUGINS.slice();
|
|
203
231
|
}
|
|
204
232
|
|
|
@@ -213,6 +241,7 @@
|
|
|
213
241
|
|
|
214
242
|
return {
|
|
215
243
|
plugins: pluginList,
|
|
244
|
+
deriveFromManifest,
|
|
216
245
|
tailwind,
|
|
217
246
|
version
|
|
218
247
|
};
|
|
@@ -268,22 +297,45 @@
|
|
|
268
297
|
detectAppwriteFromManifest();
|
|
269
298
|
|
|
270
299
|
if (config && config.plugins.length > 0) {
|
|
271
|
-
|
|
300
|
+
const MANIFEST_DEPENDENT_PLUGINS = [
|
|
301
|
+
'data', 'localization', 'components',
|
|
302
|
+
'appwrite-auth', 'appwrite-data', 'appwrite-presence'
|
|
303
|
+
];
|
|
304
|
+
const manifestUrl = (document.querySelector('link[rel="manifest"]')?.getAttribute('href')) || '/manifest.json';
|
|
305
|
+
|
|
272
306
|
const loadPlugins = async () => {
|
|
273
|
-
|
|
307
|
+
let manifest = null;
|
|
308
|
+
let pluginsToLoad = config.plugins;
|
|
309
|
+
let manifestPromise = null;
|
|
310
|
+
|
|
311
|
+
if (config.deriveFromManifest) {
|
|
312
|
+
manifest = await fetch(manifestUrl).then(r => r.ok ? r.json() : null).catch(() => null);
|
|
313
|
+
pluginsToLoad = resolveDependencies(getDefaultPluginsFromManifest(manifest));
|
|
314
|
+
} else {
|
|
315
|
+
const needsManifest = config.plugins.some(p => MANIFEST_DEPENDENT_PLUGINS.includes(p));
|
|
316
|
+
if (needsManifest) {
|
|
317
|
+
manifestPromise = fetch(manifestUrl).then(r => r.ok ? r.json() : null).catch(() => null);
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
const pluginPromises = pluginsToLoad.map(pluginName => {
|
|
274
322
|
return addScript(pluginName, config.version).catch(error => {
|
|
275
323
|
console.warn(`[Manifest Loader] Failed to load plugin ${pluginName}:`, error);
|
|
276
324
|
});
|
|
277
325
|
});
|
|
278
|
-
|
|
279
|
-
// Load Tailwind in parallel if requested
|
|
280
326
|
if (config.tailwind) {
|
|
281
|
-
pluginPromises.push(loadTailwind(config.version).catch(
|
|
282
|
-
console.warn(`[Manifest Loader] Failed to load Tailwind:`, error);
|
|
283
|
-
}));
|
|
327
|
+
pluginPromises.push(loadTailwind(config.version).catch(() => {}));
|
|
284
328
|
}
|
|
285
|
-
|
|
286
329
|
await Promise.all(pluginPromises);
|
|
330
|
+
if (manifestPromise) {
|
|
331
|
+
manifest = await manifestPromise;
|
|
332
|
+
}
|
|
333
|
+
if (manifest && typeof window !== 'undefined') {
|
|
334
|
+
window.__manifestLoaded = manifest;
|
|
335
|
+
if (window.ManifestComponentsRegistry) {
|
|
336
|
+
window.ManifestComponentsRegistry.manifest = manifest;
|
|
337
|
+
}
|
|
338
|
+
}
|
|
287
339
|
loadAlpine();
|
|
288
340
|
};
|
|
289
341
|
|
|
@@ -137,11 +137,15 @@ function initializeLocalizationPlugin() {
|
|
|
137
137
|
}
|
|
138
138
|
|
|
139
139
|
try {
|
|
140
|
-
|
|
141
|
-
if (!
|
|
142
|
-
|
|
140
|
+
let manifest = window.__manifestLoaded || window.ManifestComponentsRegistry?.manifest;
|
|
141
|
+
if (!manifest) {
|
|
142
|
+
const manifestUrl = (document.querySelector('link[rel="manifest"]')?.getAttribute('href')) || '/manifest.json';
|
|
143
|
+
const response = await fetch(manifestUrl);
|
|
144
|
+
if (!response.ok) {
|
|
145
|
+
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
|
|
146
|
+
}
|
|
147
|
+
manifest = await response.json();
|
|
143
148
|
}
|
|
144
|
-
const manifest = await response.json();
|
|
145
149
|
|
|
146
150
|
// Validate manifest structure
|
|
147
151
|
if (!manifest || typeof manifest !== 'object') {
|