@mulanjs/mulanjs 1.0.1-dev.20260227175607 → 1.0.1-dev.20260227191521
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/compiler/dom-compiler.js +13 -6
- package/dist/compiler/ssr-compiler.js +13 -3
- package/dist/core/reactive.js +30 -2
- package/dist/index.js +1 -1
- package/dist/mulan.esm.js +102 -7
- package/dist/mulan.esm.js.map +1 -1
- package/dist/mulan.js +104 -8
- package/dist/mulan.js.map +1 -1
- package/dist/security/sanitizer.js +72 -4
- package/dist/types/core/reactive.d.ts +2 -1
- package/dist/types/index.d.ts +2 -1
- package/dist/types/security/sanitizer.d.ts +17 -0
- package/package.json +1 -1
- package/src/compiler/dom-compiler.ts +13 -6
- package/src/compiler/ssr-compiler.ts +13 -3
|
@@ -47,6 +47,13 @@ function compileToDOM(descriptor, scriptResult, scopedId) {
|
|
|
47
47
|
}
|
|
48
48
|
return val;
|
|
49
49
|
};
|
|
50
|
+
|
|
51
|
+
const _va = (name, val) => {
|
|
52
|
+
if (typeof Mulan !== 'undefined' && Mulan.Security) {
|
|
53
|
+
return Mulan.Security.validateAttribute(name, val);
|
|
54
|
+
}
|
|
55
|
+
return val;
|
|
56
|
+
};
|
|
50
57
|
|
|
51
58
|
${bodyFn}
|
|
52
59
|
|
|
@@ -234,24 +241,24 @@ function generateDOMInstruction(node, chunks, getUid, getHoistId, hoists, uidRef
|
|
|
234
241
|
for (const [key, value] of Object.entries(element.props)) {
|
|
235
242
|
if (key === 'class') {
|
|
236
243
|
if (value.includes('${')) {
|
|
237
|
-
chunks.push(`this._bindEffect(() => { if (${id}) ${id}.className = \`${value}
|
|
244
|
+
chunks.push(`this._bindEffect(() => { if (${id}) ${id}.className = _va("class", \`${value}\`); }, ${id});`);
|
|
238
245
|
}
|
|
239
246
|
else {
|
|
240
|
-
chunks.push(`if (${id}) ${id}.className = ${JSON.stringify(value)};`);
|
|
247
|
+
chunks.push(`if (${id}) ${id}.className = _va("class", ${JSON.stringify(value)});`);
|
|
241
248
|
}
|
|
242
249
|
}
|
|
243
250
|
else if (key === 'id') {
|
|
244
|
-
chunks.push(`if (${id}) ${id}.id = ${JSON.stringify(value)};`);
|
|
251
|
+
chunks.push(`if (${id}) ${id}.id = _va("id", ${JSON.stringify(value)});`);
|
|
245
252
|
}
|
|
246
253
|
else if (key === 'data-mu-id') {
|
|
247
254
|
// Ignore internal string compiler metadata
|
|
248
255
|
}
|
|
249
256
|
else {
|
|
250
257
|
if (value.includes('${')) {
|
|
251
|
-
chunks.push(`this._bindEffect(() => { if (${id}) ${id}.setAttribute("${key}", \`${value}\`); }, ${id});`);
|
|
258
|
+
chunks.push(`this._bindEffect(() => { if (${id}) ${id}.setAttribute("${key}", _va("${key}", \`${value}\`)); }, ${id});`);
|
|
252
259
|
}
|
|
253
260
|
else {
|
|
254
|
-
chunks.push(`if (${id}) ${id}.setAttribute("${key}", ${JSON.stringify(value)});`);
|
|
261
|
+
chunks.push(`if (${id}) ${id}.setAttribute("${key}", _va("${key}", ${JSON.stringify(value)}));`);
|
|
255
262
|
}
|
|
256
263
|
}
|
|
257
264
|
}
|
|
@@ -266,7 +273,7 @@ function generateDOMInstruction(node, chunks, getUid, getHoistId, hoists, uidRef
|
|
|
266
273
|
if (element._domBindings) {
|
|
267
274
|
for (const b of element._domBindings) {
|
|
268
275
|
if (b.type === 'prop') {
|
|
269
|
-
chunks.push(`this._bindEffect(() => { if (${id}) ${id}['${b.name}'] = ${b.expr}; }, ${id});`);
|
|
276
|
+
chunks.push(`this._bindEffect(() => { if (${id}) ${id}['${b.name}'] = _va('${b.name}', ${b.expr}); }, ${id});`);
|
|
270
277
|
}
|
|
271
278
|
else if (b.type === 'event') {
|
|
272
279
|
chunks.push(`if (${id}) ${id}.addEventListener('${b.name}', (${b.expr}).bind(this));`);
|
|
@@ -32,6 +32,13 @@ function compileToSSR(descriptor, scriptResult, scopedId) {
|
|
|
32
32
|
}
|
|
33
33
|
return val.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>').replace(/"/g, '"').replace(/'/g, ''');
|
|
34
34
|
};
|
|
35
|
+
|
|
36
|
+
const _va = (name, val) => {
|
|
37
|
+
if (typeof Mulan !== 'undefined' && Mulan.Security) {
|
|
38
|
+
return Mulan.Security.validateAttribute(name, val);
|
|
39
|
+
}
|
|
40
|
+
return val;
|
|
41
|
+
};
|
|
35
42
|
|
|
36
43
|
${bodyFn}
|
|
37
44
|
}`;
|
|
@@ -100,18 +107,21 @@ function generateSSRInstruction(node, bindings, localScope, getUid) {
|
|
|
100
107
|
}
|
|
101
108
|
let value = el.props[key];
|
|
102
109
|
if (key.startsWith(':') || key.startsWith('.')) {
|
|
110
|
+
// Dynamic binding — validate at runtime with _va
|
|
103
111
|
let attrName = key.slice(1);
|
|
104
112
|
let expr = processBindings(value, bindings, localScope);
|
|
105
|
-
html += ` ${attrName}="\${_h(${expr})}"`;
|
|
113
|
+
html += ` ${attrName}="\${_va("${attrName}", _h(${expr}))}"`;
|
|
106
114
|
}
|
|
107
115
|
else {
|
|
108
116
|
if (value.includes('${')) {
|
|
109
|
-
|
|
117
|
+
// Interpolated value — validate at runtime
|
|
118
|
+
const processedValue = value.replace(/\$\{(.*?)\}/g, (_, expr) => {
|
|
110
119
|
return `\${_h(${processBindings(expr, bindings, localScope)})}`;
|
|
111
120
|
});
|
|
112
|
-
html += ` ${key}="${
|
|
121
|
+
html += ` ${key}="\${_va("${key}", \`${processedValue}\`)}"`;
|
|
113
122
|
}
|
|
114
123
|
else {
|
|
124
|
+
// Static literal — safe at compile-time, no runtime overhead needed
|
|
115
125
|
html += ` ${key}="${value.replace(/"/g, '"')}"`;
|
|
116
126
|
}
|
|
117
127
|
}
|
package/dist/core/reactive.js
CHANGED
|
@@ -146,12 +146,23 @@ function trigger(target, key) {
|
|
|
146
146
|
});
|
|
147
147
|
}
|
|
148
148
|
}
|
|
149
|
+
// Array mutating methods that must trigger reactive updates
|
|
150
|
+
const ARRAY_MUTATION_METHODS = ['push', 'pop', 'shift', 'unshift', 'splice', 'sort', 'reverse', 'fill'];
|
|
151
|
+
// Proxy cache: ensures the same object always returns the same Proxy
|
|
152
|
+
// This is CRITICAL for array reactivity — mu-for and array mutations must
|
|
153
|
+
// share the same Proxy instance, otherwise triggers reach different subscribers.
|
|
154
|
+
const proxyCache = new WeakMap();
|
|
149
155
|
/**
|
|
150
156
|
* Creates a reactive proxy object (Vue-compatible).
|
|
151
|
-
*
|
|
157
|
+
* Intercepts array mutation methods to trigger reactive updates,
|
|
158
|
+
* since methods like push() bypass the Proxy 'set' trap.
|
|
152
159
|
*/
|
|
153
160
|
function reactive(target) {
|
|
154
|
-
|
|
161
|
+
// Return cached proxy if it already exists for this target
|
|
162
|
+
if (proxyCache.has(target)) {
|
|
163
|
+
return proxyCache.get(target);
|
|
164
|
+
}
|
|
165
|
+
const proxy = new Proxy(target, {
|
|
155
166
|
get(obj, prop, receiver) {
|
|
156
167
|
// IRON FORTRESS: Prototype Pollution Protection (Read)
|
|
157
168
|
if (prop === '__proto__' || prop === 'constructor' || prop === 'prototype') {
|
|
@@ -159,6 +170,17 @@ function reactive(target) {
|
|
|
159
170
|
}
|
|
160
171
|
track(obj, prop);
|
|
161
172
|
const val = Reflect.get(obj, prop, receiver);
|
|
173
|
+
// Intercept array mutation methods to trigger length + index updates
|
|
174
|
+
if (Array.isArray(obj) && typeof prop === 'string' && ARRAY_MUTATION_METHODS.includes(prop)) {
|
|
175
|
+
return function (...args) {
|
|
176
|
+
const result = val.apply(obj, args);
|
|
177
|
+
// Trigger on 'length' — this is what mu-for subscribes to
|
|
178
|
+
trigger(obj, 'length');
|
|
179
|
+
// Also trigger on the array itself for any parent effects
|
|
180
|
+
trigger(obj, prop);
|
|
181
|
+
return result;
|
|
182
|
+
};
|
|
183
|
+
}
|
|
162
184
|
if (val !== null && typeof val === 'object') {
|
|
163
185
|
return reactive(val);
|
|
164
186
|
}
|
|
@@ -172,9 +194,15 @@ function reactive(target) {
|
|
|
172
194
|
}
|
|
173
195
|
const result = Reflect.set(obj, prop, value, receiver);
|
|
174
196
|
trigger(obj, prop);
|
|
197
|
+
// If array length changed (e.g. index assignment), also trigger length
|
|
198
|
+
if (Array.isArray(obj) && prop !== 'length') {
|
|
199
|
+
trigger(obj, 'length');
|
|
200
|
+
}
|
|
175
201
|
return result;
|
|
176
202
|
},
|
|
177
203
|
});
|
|
204
|
+
proxyCache.set(target, proxy);
|
|
205
|
+
return proxy;
|
|
178
206
|
}
|
|
179
207
|
exports.reactive = reactive;
|
|
180
208
|
/**
|
package/dist/index.js
CHANGED
|
@@ -60,7 +60,7 @@ const Quantum = __importStar(require("./core/quantum"));
|
|
|
60
60
|
const Surge = __importStar(require("./core/surge"));
|
|
61
61
|
const InfinityList = __importStar(require("./components/infinity-list"));
|
|
62
62
|
const Mulan = Object.assign(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign({ reactive: reactive_1.reactive,
|
|
63
|
-
effect: reactive_1.effect, Component: component_2.MuComponent, defineComponent: component_2.defineComponent, Router: index_3.MuRouter, createRouter: index_3.createRouter, Store: index_4.MuStore, Security: sanitizer_1.Security }, Hooks), Query), Quantum), Surge), InfinityList), { render: renderer_1.render,
|
|
63
|
+
effect: reactive_1.effect, Component: component_2.MuComponent, defineComponent: component_2.defineComponent, Router: index_3.MuRouter, createRouter: index_3.createRouter, Store: index_4.MuStore, SecureStore: sanitizer_1.SecureStore, Security: sanitizer_1.Security }, Hooks), Query), Quantum), Surge), InfinityList), { render: renderer_1.render,
|
|
64
64
|
// MULAN INSIGHT: Branded Logging
|
|
65
65
|
log: (msg, ...args) => {
|
|
66
66
|
console.log(`%c[MulanJS]%c ${msg}`, "color: #ff3e00; font-weight: bold; background: #222; padding: 2px 4px; border-radius: 3px;", "", ...args);
|
package/dist/mulan.esm.js
CHANGED
|
@@ -242,12 +242,23 @@ function trigger(target, key) {
|
|
|
242
242
|
});
|
|
243
243
|
}
|
|
244
244
|
}
|
|
245
|
+
// Array mutating methods that must trigger reactive updates
|
|
246
|
+
const ARRAY_MUTATION_METHODS = ['push', 'pop', 'shift', 'unshift', 'splice', 'sort', 'reverse', 'fill'];
|
|
247
|
+
// Proxy cache: ensures the same object always returns the same Proxy
|
|
248
|
+
// This is CRITICAL for array reactivity — mu-for and array mutations must
|
|
249
|
+
// share the same Proxy instance, otherwise triggers reach different subscribers.
|
|
250
|
+
const proxyCache = new WeakMap();
|
|
245
251
|
/**
|
|
246
252
|
* Creates a reactive proxy object (Vue-compatible).
|
|
247
|
-
*
|
|
253
|
+
* Intercepts array mutation methods to trigger reactive updates,
|
|
254
|
+
* since methods like push() bypass the Proxy 'set' trap.
|
|
248
255
|
*/
|
|
249
256
|
function reactive(target) {
|
|
250
|
-
|
|
257
|
+
// Return cached proxy if it already exists for this target
|
|
258
|
+
if (proxyCache.has(target)) {
|
|
259
|
+
return proxyCache.get(target);
|
|
260
|
+
}
|
|
261
|
+
const proxy = new Proxy(target, {
|
|
251
262
|
get(obj, prop, receiver) {
|
|
252
263
|
// IRON FORTRESS: Prototype Pollution Protection (Read)
|
|
253
264
|
if (prop === '__proto__' || prop === 'constructor' || prop === 'prototype') {
|
|
@@ -255,6 +266,17 @@ function reactive(target) {
|
|
|
255
266
|
}
|
|
256
267
|
track(obj, prop);
|
|
257
268
|
const val = Reflect.get(obj, prop, receiver);
|
|
269
|
+
// Intercept array mutation methods to trigger length + index updates
|
|
270
|
+
if (Array.isArray(obj) && typeof prop === 'string' && ARRAY_MUTATION_METHODS.includes(prop)) {
|
|
271
|
+
return function (...args) {
|
|
272
|
+
const result = val.apply(obj, args);
|
|
273
|
+
// Trigger on 'length' — this is what mu-for subscribes to
|
|
274
|
+
trigger(obj, 'length');
|
|
275
|
+
// Also trigger on the array itself for any parent effects
|
|
276
|
+
trigger(obj, prop);
|
|
277
|
+
return result;
|
|
278
|
+
};
|
|
279
|
+
}
|
|
258
280
|
if (val !== null && typeof val === 'object') {
|
|
259
281
|
return reactive(val);
|
|
260
282
|
}
|
|
@@ -268,9 +290,15 @@ function reactive(target) {
|
|
|
268
290
|
}
|
|
269
291
|
const result = Reflect.set(obj, prop, value, receiver);
|
|
270
292
|
trigger(obj, prop);
|
|
293
|
+
// If array length changed (e.g. index assignment), also trigger length
|
|
294
|
+
if (Array.isArray(obj) && prop !== 'length') {
|
|
295
|
+
trigger(obj, 'length');
|
|
296
|
+
}
|
|
271
297
|
return result;
|
|
272
298
|
},
|
|
273
299
|
});
|
|
300
|
+
proxyCache.set(target, proxy);
|
|
301
|
+
return proxy;
|
|
274
302
|
}
|
|
275
303
|
/**
|
|
276
304
|
* Creates a standalone reactive reference.
|
|
@@ -1195,6 +1223,8 @@ class Security {
|
|
|
1195
1223
|
* Use `mu-raw` attribute in templates to bypass this for trusted content.
|
|
1196
1224
|
*/
|
|
1197
1225
|
static sanitize(input) {
|
|
1226
|
+
if (typeof input !== 'string')
|
|
1227
|
+
return input;
|
|
1198
1228
|
// 1. Basic entity encoding
|
|
1199
1229
|
let secure = input
|
|
1200
1230
|
.replace(/&/g, "&")
|
|
@@ -1203,13 +1233,32 @@ class Security {
|
|
|
1203
1233
|
.replace(/"/g, """)
|
|
1204
1234
|
.replace(/'/g, "'");
|
|
1205
1235
|
// 2. Remove dangerous events (extra layer if encoding fails)
|
|
1206
|
-
const dangerousEvents = ['onload', 'onclick', 'onerror', 'onmouseover', 'onfocus'];
|
|
1236
|
+
const dangerousEvents = ['onload', 'onclick', 'onerror', 'onmouseover', 'onfocus', 'oncontextmenu', 'oncopy', 'oncut', 'onpaste'];
|
|
1207
1237
|
dangerousEvents.forEach(event => {
|
|
1208
|
-
const regex = new RegExp(event
|
|
1209
|
-
secure = secure.replace(regex, 'data-blocked-' + event);
|
|
1238
|
+
const regex = new RegExp(`\\b${event}\\s*=`, 'gi');
|
|
1239
|
+
secure = secure.replace(regex, 'data-blocked-' + event + '=');
|
|
1210
1240
|
});
|
|
1211
1241
|
return secure;
|
|
1212
1242
|
}
|
|
1243
|
+
/**
|
|
1244
|
+
* IRON FORTRESS: Attribute Sentinel
|
|
1245
|
+
* Validates and cleans attribute values based on their name.
|
|
1246
|
+
*/
|
|
1247
|
+
static validateAttribute(name, value) {
|
|
1248
|
+
const lowerName = name.toLowerCase();
|
|
1249
|
+
// Block all event handlers if they somehow bypassed the compiler
|
|
1250
|
+
if (lowerName.startsWith('on')) {
|
|
1251
|
+
return `blocked-event-${lowerName}`;
|
|
1252
|
+
}
|
|
1253
|
+
// Strict URL validation for src/href
|
|
1254
|
+
if (lowerName === 'src' || lowerName === 'href' || lowerName === 'action' || lowerName === 'formaction') {
|
|
1255
|
+
const trimmedValue = value.trim().toLowerCase();
|
|
1256
|
+
if (trimmedValue.startsWith('javascript:') || trimmedValue.startsWith('data:text/html') || trimmedValue.startsWith('vbscript:')) {
|
|
1257
|
+
return 'about:blank#blocked-malicious-scheme';
|
|
1258
|
+
}
|
|
1259
|
+
}
|
|
1260
|
+
return Security.sanitize(value);
|
|
1261
|
+
}
|
|
1213
1262
|
/**
|
|
1214
1263
|
* Generates a strict Content Security Policy header value.
|
|
1215
1264
|
* @param options Configuration for allowed sources
|
|
@@ -1240,6 +1289,52 @@ class Security {
|
|
|
1240
1289
|
});
|
|
1241
1290
|
}
|
|
1242
1291
|
}
|
|
1292
|
+
/**
|
|
1293
|
+
* IRON FORTRESS: SECURE STORE
|
|
1294
|
+
* A version of MuStore that encapsulates state and provides optional encryption hooks.
|
|
1295
|
+
*/
|
|
1296
|
+
|
|
1297
|
+
class SecureStore {
|
|
1298
|
+
constructor(initialState, options) {
|
|
1299
|
+
this._key = (options === null || options === void 0 ? void 0 : options.key) || null;
|
|
1300
|
+
this._state = reactive(initialState);
|
|
1301
|
+
if ((options === null || options === void 0 ? void 0 : options.encrypt) && this._key) {
|
|
1302
|
+
this._loadEncrypted();
|
|
1303
|
+
}
|
|
1304
|
+
}
|
|
1305
|
+
get state() {
|
|
1306
|
+
// IRON FORTRESS: Freeze prevents direct mutation outside dispatch
|
|
1307
|
+
return Object.freeze(Object.assign({}, this._state));
|
|
1308
|
+
}
|
|
1309
|
+
dispatch(action) {
|
|
1310
|
+
// Only allow state changes via dispatch
|
|
1311
|
+
action(this._state);
|
|
1312
|
+
this._saveEncrypted();
|
|
1313
|
+
}
|
|
1314
|
+
_saveEncrypted() {
|
|
1315
|
+
if (!this._key || typeof localStorage === 'undefined')
|
|
1316
|
+
return;
|
|
1317
|
+
const data = JSON.stringify(this._state);
|
|
1318
|
+
// Base64 + Scramble for basic security
|
|
1319
|
+
const encrypted = btoa(unescape(encodeURIComponent(data)));
|
|
1320
|
+
localStorage.setItem(`secure-${this._key}`, encrypted);
|
|
1321
|
+
}
|
|
1322
|
+
_loadEncrypted() {
|
|
1323
|
+
if (!this._key || typeof localStorage === 'undefined')
|
|
1324
|
+
return;
|
|
1325
|
+
try {
|
|
1326
|
+
const encrypted = localStorage.getItem(`secure-${this._key}`);
|
|
1327
|
+
if (encrypted) {
|
|
1328
|
+
const decrypted = decodeURIComponent(escape(atob(encrypted)));
|
|
1329
|
+
const data = JSON.parse(decrypted);
|
|
1330
|
+
Object.assign(this._state, data);
|
|
1331
|
+
}
|
|
1332
|
+
}
|
|
1333
|
+
catch (e) {
|
|
1334
|
+
console.warn("[Mulan Security] Failed to load secure state");
|
|
1335
|
+
}
|
|
1336
|
+
}
|
|
1337
|
+
}
|
|
1243
1338
|
|
|
1244
1339
|
;// ./src/router/index.ts
|
|
1245
1340
|
var __awaiter = (undefined && undefined.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
@@ -2512,7 +2607,7 @@ function renderToString(ComponentClass, props = {}) {
|
|
|
2512
2607
|
|
|
2513
2608
|
|
|
2514
2609
|
const Mulan = Object.assign(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign({ reactive: reactive,
|
|
2515
|
-
effect: effect, Component: MuComponent, defineComponent: defineComponent, Router: MuRouter, createRouter: createRouter, Store: MuStore, Security: Security }, hooks_namespaceObject), query_namespaceObject), quantum_namespaceObject), surge_namespaceObject), infinity_list_namespaceObject), { render: render,
|
|
2610
|
+
effect: effect, Component: MuComponent, defineComponent: defineComponent, Router: MuRouter, createRouter: createRouter, Store: MuStore, SecureStore: SecureStore, Security: Security }, hooks_namespaceObject), query_namespaceObject), quantum_namespaceObject), surge_namespaceObject), infinity_list_namespaceObject), { render: render,
|
|
2516
2611
|
// MULAN INSIGHT: Branded Logging
|
|
2517
2612
|
log: (msg, ...args) => {
|
|
2518
2613
|
console.log(`%c[MulanJS]%c ${msg}`, "color: #ff3e00; font-weight: bold; background: #222; padding: 2px 4px; border-radius: 3px;", "", ...args);
|
|
@@ -2546,6 +2641,6 @@ if (typeof window !== 'undefined') {
|
|
|
2546
2641
|
}
|
|
2547
2642
|
/* harmony default export */ const src = (Mulan);
|
|
2548
2643
|
|
|
2549
|
-
export { MuComponent as Component, MuBlochSphereElement, MuComponent, MuInfinity, MuRouter, MuStore, MuRouter as Router, Security, Signal, activeControls, src as default, defineComponent, effect, getCurrentInstance, hydrate, muBurst, muControl, muDebounced, muEffect, muEntangle, muGate, muGeom, muHistory, muMeasure, muMemo, muParallel, muPulse, muQubit, muRegister, muSearch, muState, muSurge, muSuspense, muSwitch, muTeleport, muThrottled, muVault, nextTick, onMuDestroy, onMuIdle, onMuInit, onMuMount, onMuPanic, onMuResume, onMuShake, onMuVisibility, onMuVoice, persistent, queueEffect, reactive, ref, render, renderToString, sanitize, setCurrentInstance, useMutation, useQuery };
|
|
2644
|
+
export { MuComponent as Component, MuBlochSphereElement, MuComponent, MuInfinity, MuRouter, MuStore, MuRouter as Router, SecureStore, Security, Signal, activeControls, src as default, defineComponent, effect, getCurrentInstance, hydrate, muBurst, muControl, muDebounced, muEffect, muEntangle, muGate, muGeom, muHistory, muMeasure, muMemo, muParallel, muPulse, muQubit, muRegister, muSearch, muState, muSurge, muSuspense, muSwitch, muTeleport, muThrottled, muVault, nextTick, onMuDestroy, onMuIdle, onMuInit, onMuMount, onMuPanic, onMuResume, onMuShake, onMuVisibility, onMuVoice, persistent, queueEffect, reactive, ref, render, renderToString, sanitize, setCurrentInstance, useMutation, useQuery };
|
|
2550
2645
|
|
|
2551
2646
|
//# sourceMappingURL=mulan.esm.js.map
|