forked from Ikalus1988/MisakaNet
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathcore.js
More file actions
76 lines (69 loc) · 2.38 KB
/
Copy pathcore.js
File metadata and controls
76 lines (69 loc) · 2.38 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
/**
* MisakaNet Frontend Core — 类型安全 + 错误边界 + XSS 净化
* 提供 ESM / CommonJS / 浏览器全局变量三种加载方式
*/
/**
* @typedef {Object} Lesson
* @property {string} id
* @property {string} domain
* @property {string} title
* @property {string} [summary]
* @property {string[]} [tags]
* @property {string} [url]
*/
/**
* 安全异步加载并校验 Lessons 数据
* @param {string} url
* @param {Function} [errorUI]
* @returns {Promise<Array>}
*/
export async function safeFetchLessons(url, errorUI) {
try {
const response = await fetch(url);
if (!response.ok) throw new Error('HTTP ' + response.status);
const data = await response.json();
if (!Array.isArray(data)) throw new TypeError('lessons.json root must be an Array');
return data.filter(function(l) {
return l && typeof l.title === 'string' && typeof l.domain === 'string';
});
} catch (err) {
console.error('MisakaNet Frontend Shield: Lessons load blocked \u2014', err.message);
if (typeof errorUI === 'function') errorUI(err.message);
return [];
}
}
/**
* 构建降级 UI HTML
* @param {string} message
* @returns {string}
*/
export function buildErrorHTML(message) {
var safeMsg = encodeURIComponent(String(message));
return '<div style="border:1px solid #ff4d4f;padding:12px;margin:8px;background:rgba(255,77,79,0.08);border-radius:8px;">' +
'<div style="color:#ff4d4f;font-weight:600;font-size:13px;">\u26a0\ufe0f Frontend Shield: Data Parse Blocked</div>' +
'<div style="color:#8b949e;font-size:11px;margin-top:4px;">The intelligence feed contains anomalies or failed to load.</div>' +
'<code style="color:#ff4d4f;font-size:10px;">' + safeMsg + '</code></div>';
}
/**
* 验证 Lesson 对象
* @param {*} obj
* @returns {boolean}
*/
export function isValidLesson(obj) {
return obj && typeof obj.title === 'string' && typeof obj.domain === 'string';
}
// ── 浏览器全局挂载 & CommonJS 兼容 ──
(function() {
'use strict';
// Expose globally (browser: window, Node: globalThis)
var root = typeof window !== 'undefined' ? window : globalThis;
root.MisakaCore = {
safeFetchLessons,
buildErrorHTML,
isValidLesson
};
// CommonJS export (for vitest with node environment)
if (typeof module !== 'undefined' && module.exports) {
module.exports = { safeFetchLessons, buildErrorHTML, isValidLesson };
}
})();