@mulanjs/mulanjs 1.0.1-dev.20260212143840

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 (53) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +1 -0
  3. package/dist/compiler/compiler.js +90 -0
  4. package/dist/compiler/script-compiler.js +314 -0
  5. package/dist/compiler/sfc-parser.js +93 -0
  6. package/dist/compiler/style-compiler.js +56 -0
  7. package/dist/compiler/template-compiler.js +442 -0
  8. package/dist/components/bloch-sphere.js +252 -0
  9. package/dist/core/component.js +145 -0
  10. package/dist/core/hooks.js +229 -0
  11. package/dist/core/quantum.js +284 -0
  12. package/dist/core/query.js +63 -0
  13. package/dist/core/reactive.js +105 -0
  14. package/dist/core/renderer.js +70 -0
  15. package/dist/core/vault.js +81 -0
  16. package/dist/index.js +52 -0
  17. package/dist/mulan.esm.js +1948 -0
  18. package/dist/mulan.js +215 -0
  19. package/dist/router/index.js +210 -0
  20. package/dist/security/sanitizer.js +47 -0
  21. package/dist/store/index.js +42 -0
  22. package/dist/types/compiler/compiler.d.ts +7 -0
  23. package/dist/types/compiler/script-compiler.d.ts +8 -0
  24. package/dist/types/compiler/sfc-parser.d.ts +21 -0
  25. package/dist/types/compiler/style-compiler.d.ts +7 -0
  26. package/dist/types/compiler/template-compiler.d.ts +7 -0
  27. package/dist/types/compiler.d.ts +7 -0
  28. package/dist/types/components/bloch-sphere.d.ts +16 -0
  29. package/dist/types/core/component.d.ts +54 -0
  30. package/dist/types/core/hooks.d.ts +49 -0
  31. package/dist/types/core/quantum.d.ts +50 -0
  32. package/dist/types/core/query.d.ts +14 -0
  33. package/dist/types/core/reactive.d.ts +21 -0
  34. package/dist/types/core/renderer.d.ts +4 -0
  35. package/dist/types/core/vault.d.ts +12 -0
  36. package/dist/types/index.d.ts +70 -0
  37. package/dist/types/router/index.d.ts +24 -0
  38. package/dist/types/script-compiler.d.ts +8 -0
  39. package/dist/types/security/sanitizer.d.ts +17 -0
  40. package/dist/types/sfc-parser.d.ts +21 -0
  41. package/dist/types/store/index.d.ts +10 -0
  42. package/dist/types/style-compiler.d.ts +7 -0
  43. package/dist/types/template-compiler.d.ts +7 -0
  44. package/package.json +64 -0
  45. package/src/cli/extensions/mulanjs-vscode-1.0.0.vsix +0 -0
  46. package/src/cli/index.js +600 -0
  47. package/src/compiler/compiler.ts +102 -0
  48. package/src/compiler/script-compiler.ts +336 -0
  49. package/src/compiler/sfc-parser.ts +118 -0
  50. package/src/compiler/style-compiler.ts +66 -0
  51. package/src/compiler/template-compiler.ts +519 -0
  52. package/src/compiler/tsconfig.json +13 -0
  53. package/src/loader/index.js +81 -0
@@ -0,0 +1,284 @@
1
+ import { muState } from './hooks';
2
+ /**
3
+ * Creates a quantum register of size n.
4
+ * State vector will have 2^n amplitudes.
5
+ */
6
+ export function muRegister(n) {
7
+ const numStates = Math.pow(2, n);
8
+ const amplitudes = new Array(numStates).fill(0).map((_, i) => ({
9
+ re: i === 0 ? 1 : 0,
10
+ im: 0
11
+ }));
12
+ return muState({
13
+ value: {
14
+ size: n,
15
+ amplitudes
16
+ }
17
+ });
18
+ }
19
+ /**
20
+ * Backward compatible muQubit (Single Qubit Register)
21
+ */
22
+ export function muQubit(initial = 0) {
23
+ const q = muRegister(1);
24
+ if (initial === 1) {
25
+ muGate(q, 'X', 0);
26
+ }
27
+ // Add compatibility properties for Phase 1 components
28
+ // These properties are getters that dynamically access the amplitudes array
29
+ Object.defineProperty(q.value, 'alpha', { get: () => q.value.amplitudes[0] });
30
+ Object.defineProperty(q.value, 'beta', { get: () => q.value.amplitudes[1] });
31
+ return q;
32
+ }
33
+ /**
34
+ * Internal helper to update register state while maintaining compatibility
35
+ */
36
+ function updateState(reg, newState) {
37
+ if (newState.size === 1) {
38
+ // Re-inject compatibility getters for muQubit users
39
+ Object.defineProperty(newState, 'alpha', {
40
+ get: () => newState.amplitudes[0],
41
+ configurable: true,
42
+ enumerable: true
43
+ });
44
+ Object.defineProperty(newState, 'beta', {
45
+ get: () => newState.amplitudes[1],
46
+ configurable: true,
47
+ enumerable: true
48
+ });
49
+ }
50
+ reg.value = newState;
51
+ }
52
+ export function muGate(reg, type, target = 0, control) {
53
+ const state = reg.value;
54
+ const n = state.size;
55
+ const amplitudes = state.amplitudes;
56
+ const newAmps = amplitudes.map(a => (Object.assign({}, a)));
57
+ // Helper: Check if all control bits are 1
58
+ const checkControl = (index, ctrl) => {
59
+ if (ctrl === undefined)
60
+ return true;
61
+ if (typeof ctrl === 'number') {
62
+ return ((index >> ctrl) & 1) === 1;
63
+ }
64
+ return ctrl.every(c => ((index >> c) & 1) === 1);
65
+ };
66
+ // SWAP Gate (Unique case: affects 2 targets)
67
+ if (type === 'SWAP') {
68
+ const t1 = target;
69
+ const t2 = control; // SWAP uses control arg as second target
70
+ // Iterate only half to avoid double swapping
71
+ for (let i = 0; i < amplitudes.length; i++) {
72
+ const bit1 = (i >> t1) & 1;
73
+ const bit2 = (i >> t2) & 1;
74
+ if (bit1 !== bit2) {
75
+ // Determine the swap partner index
76
+ // If i has (0,1), partner has (1,0) at those positions
77
+ const partner = i ^ (1 << t1) ^ (1 << t2);
78
+ if (i < partner) {
79
+ const temp = newAmps[i];
80
+ newAmps[i] = newAmps[partner];
81
+ newAmps[partner] = temp;
82
+ }
83
+ }
84
+ }
85
+ updateState(reg, Object.assign(Object.assign({}, state), { amplitudes: newAmps }));
86
+ return;
87
+ }
88
+ // Standard Single-Qubit & Controlled Gates
89
+ if (type === 'H') {
90
+ const s = 1 / Math.sqrt(2);
91
+ const processed = new Set();
92
+ for (let i = 0; i < state.amplitudes.length; i++) {
93
+ if (processed.has(i))
94
+ continue;
95
+ // Check Controls first
96
+ if (!checkControl(i, control))
97
+ continue;
98
+ const targetBit = (i >> target) & 1;
99
+ const pairedIndex = targetBit ? (i & ~(1 << target)) : (i | (1 << target));
100
+ const a = state.amplitudes[i];
101
+ const b = state.amplitudes[pairedIndex];
102
+ if (targetBit === 0) {
103
+ newAmps[i] = { re: s * (a.re + b.re), im: s * (a.im + b.im) };
104
+ newAmps[pairedIndex] = { re: s * (a.re - b.re), im: s * (a.im - b.im) };
105
+ }
106
+ else {
107
+ newAmps[pairedIndex] = { re: s * (b.re + a.re), im: s * (b.im + a.im) };
108
+ newAmps[i] = { re: s * (b.re - a.re), im: s * (b.im - a.im) };
109
+ }
110
+ processed.add(i);
111
+ processed.add(pairedIndex);
112
+ }
113
+ }
114
+ else if (type === 'X' || type === 'CNOT') {
115
+ // CNOT is just Controlled-X
116
+ for (let i = 0; i < amplitudes.length; i++) {
117
+ if (!checkControl(i, control))
118
+ continue;
119
+ const targetBit = (i >> target) & 1;
120
+ const pairedIndex = targetBit ? (i & ~(1 << target)) : (i | (1 << target));
121
+ if (i < pairedIndex) {
122
+ const temp = newAmps[i];
123
+ newAmps[i] = newAmps[pairedIndex];
124
+ newAmps[pairedIndex] = temp;
125
+ }
126
+ }
127
+ }
128
+ else if (type === 'Z' || type === 'CZ') {
129
+ // Z and CZ are Phase Flips
130
+ for (let i = 0; i < amplitudes.length; i++) {
131
+ if (!checkControl(i, control))
132
+ continue;
133
+ const targetBit = (i >> target) & 1;
134
+ // Z Gate acts on |1>
135
+ if (targetBit === 1) {
136
+ newAmps[i] = { re: -amplitudes[i].re, im: -amplitudes[i].im };
137
+ }
138
+ }
139
+ }
140
+ else if (type === 'Y') {
141
+ // Y: |0> -> i|1>, |1> -> -i|0>
142
+ for (let i = 0; i < amplitudes.length; i++) {
143
+ if (!checkControl(i, control))
144
+ continue;
145
+ const targetBit = (i >> target) & 1;
146
+ const pairedIndex = targetBit ? (i & ~(1 << target)) : (i | (1 << target));
147
+ if (i < pairedIndex) {
148
+ // We process pairs (i, pairedIndex) where i has 0 at target, paired has 1
149
+ const a = newAmps[i]; // Coeff of |0>
150
+ const b = newAmps[pairedIndex]; // Coeff of |1>
151
+ // New |0> = -i * Old |1>
152
+ newAmps[i] = { re: b.im, im: -b.re };
153
+ // New |1> = i * Old |0>
154
+ newAmps[pairedIndex] = { re: -a.im, im: a.re };
155
+ }
156
+ }
157
+ }
158
+ updateState(reg, Object.assign(Object.assign({}, state), { amplitudes: newAmps }));
159
+ }
160
+ /**
161
+ * Mulan Search Logic (Grover's Operator)
162
+ * Automatically constructs a multi-controlled Phase Flip (Z) for a specific target state.
163
+ * This is the core of the "Quantum Switch" or "Quantum Search" capability.
164
+ * @param reg Quantum Register
165
+ * @param targetState The integer state to "search" and mark (e.g. 2 for |10>)
166
+ */
167
+ export function muSearch(reg, targetState) {
168
+ const n = reg.value.size;
169
+ const controls = [];
170
+ // 1. Identify which bits are 0 and need wrapping with X gates
171
+ // Logic: To mark |010>, we want C-C-Z to trigger on 111.
172
+ // So we apply X to bits that are 0, then C-C-Z, then X again.
173
+ // We treat the last bit as the 'target' for the Z gate, rest as controls
174
+ const targetQubit = n - 1;
175
+ for (let i = 0; i < n; i++) {
176
+ const bit = (targetState >> i) & 1;
177
+ if (i === targetQubit) {
178
+ // If target bit logic requires 0, we flip it to 1 for the Z gate to work
179
+ if (bit === 0)
180
+ muGate(reg, 'X', i);
181
+ }
182
+ else {
183
+ controls.push(i);
184
+ if (bit === 0)
185
+ muGate(reg, 'X', i);
186
+ }
187
+ }
188
+ // 2. Apply Multi-Controlled Z
189
+ muGate(reg, 'Z', targetQubit, controls);
190
+ // 3. Uncompute (Restore 0s)
191
+ for (let i = 0; i < n; i++) {
192
+ const bit = (targetState >> i) & 1;
193
+ if (bit === 0)
194
+ muGate(reg, 'X', i);
195
+ }
196
+ // --- GROVER DIFFUSER (Amplification) ---
197
+ // This flips the probability amplitudes around the mean, boosting the target state.
198
+ // 1. Apply H to all
199
+ for (let i = 0; i < n; i++)
200
+ muGate(reg, 'H', i);
201
+ // 2. Apply X to all
202
+ for (let i = 0; i < n; i++)
203
+ muGate(reg, 'X', i);
204
+ // 3. Multi-Controlled Z (Reflection about |0...0>)
205
+ // We want to flip phase of |11...1> state after X transformation (which corresponds to |00...0> original)
206
+ // Target is last qubit, controls are 0 to n-2
207
+ const diffControls = [];
208
+ for (let i = 0; i < n - 1; i++)
209
+ diffControls.push(i);
210
+ muGate(reg, 'Z', n - 1, diffControls);
211
+ // 4. Uncompute X
212
+ for (let i = 0; i < n; i++)
213
+ muGate(reg, 'X', i);
214
+ // 5. Uncompute H
215
+ for (let i = 0; i < n; i++)
216
+ muGate(reg, 'H', i);
217
+ }
218
+ export function muEntangle(reg, i, j) {
219
+ muGate(reg, 'H', i);
220
+ muGate(reg, 'CNOT', j, i);
221
+ }
222
+ /**
223
+ * Quantum Teleportation Protocol
224
+ * Transfers the state of `msgIdx` to `targetIdx` using `ancillaIdx` as a resource.
225
+ * @param reg Register
226
+ * @param msgIdx The qubit containing the state to teleport (Alice)
227
+ * @param ancillaIdx The helper qubit (Alice's half of entanglement)
228
+ * @param targetIdx The destination qubit (Bob)
229
+ */
230
+ export function muTeleport(reg, msgIdx, ancillaIdx, targetIdx) {
231
+ // 1. Create Bell Pair (Entanglement) between Ancilla and Target
232
+ // Represents the shared link between Alice and Bob
233
+ muEntangle(reg, ancillaIdx, targetIdx);
234
+ // 2. Bell Measurement on Message + Ancilla (Alice's side)
235
+ muGate(reg, 'CNOT', ancillaIdx, msgIdx); // Control: msg, Target: ancilla
236
+ muGate(reg, 'H', msgIdx);
237
+ // 3. Measure Alice's qubits (This collapses them)
238
+ const m1 = muMeasure(reg, msgIdx); // Measures "Z" component
239
+ const m2 = muMeasure(reg, ancillaIdx); // Measures "X" component
240
+ // 4. Classical Communication & Correction (Bob's side)
241
+ // Apply corrections to Target based on measurements
242
+ if (m2 === 1)
243
+ muGate(reg, 'X', targetIdx);
244
+ if (m1 === 1)
245
+ muGate(reg, 'Z', targetIdx);
246
+ }
247
+ /**
248
+ * Measures a specific qubit in the register, collapsing the superposition.
249
+ * @param reg Quantum Register
250
+ * @param target Index of qubit to measure
251
+ * @returns 0 or 1
252
+ */
253
+ export function muMeasure(reg, target = 0) {
254
+ const state = reg.value;
255
+ const amplitudes = state.amplitudes;
256
+ let prob0 = 0;
257
+ // 1. Calculate Probability of |0>
258
+ for (let i = 0; i < amplitudes.length; i++) {
259
+ if (((i >> target) & 1) === 0) {
260
+ const a = amplitudes[i];
261
+ prob0 += (a.re * a.re) + (a.im * a.im);
262
+ }
263
+ }
264
+ // 2. Determine Outcome
265
+ const result = Math.random() < prob0 ? 0 : 1;
266
+ const resultProb = result === 0 ? prob0 : (1 - prob0);
267
+ const normFactor = resultProb > 0 ? (1 / Math.sqrt(resultProb)) : 0;
268
+ // 3. Collapse the State (Wavefunction Collapse)
269
+ const newAmps = amplitudes.map((a, i) => {
270
+ const bit = (i >> target) & 1;
271
+ if (bit !== result) {
272
+ return { re: 0, im: 0 };
273
+ }
274
+ else {
275
+ return { re: a.re * normFactor, im: a.im * normFactor };
276
+ }
277
+ });
278
+ // We need to call updateState to ensure reactivity if specialized getters exist
279
+ // But since this file has updateState internal, we can just call it.
280
+ // However, the internal updateState function needs to be in scope.
281
+ // It is defined at line 60. So we are good.
282
+ updateState(reg, Object.assign(Object.assign({}, state), { amplitudes: newAmps }));
283
+ return result;
284
+ }
@@ -0,0 +1,63 @@
1
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
2
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
3
+ return new (P || (P = Promise))(function (resolve, reject) {
4
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
5
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
6
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
7
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
8
+ });
9
+ };
10
+ import { reactive, effect } from './reactive';
11
+ export function useQuery(queryFn, options = { enabled: true }) {
12
+ const state = reactive({
13
+ data: null,
14
+ isLoading: false,
15
+ error: null
16
+ });
17
+ const execute = () => __awaiter(this, void 0, void 0, function* () {
18
+ state.isLoading = true;
19
+ state.error = null;
20
+ try {
21
+ const result = yield queryFn();
22
+ state.data = result;
23
+ }
24
+ catch (err) {
25
+ state.error = err;
26
+ }
27
+ finally {
28
+ state.isLoading = false;
29
+ }
30
+ });
31
+ if (options.enabled) {
32
+ // Run automatically
33
+ effect(() => {
34
+ // Basic effect wrapper to allow reactivity if queryFn relies on signals
35
+ execute();
36
+ });
37
+ }
38
+ return Object.assign(Object.assign({}, state), { refetch: execute });
39
+ }
40
+ export function useMutation(mutationFn) {
41
+ const state = reactive({
42
+ data: null,
43
+ isLoading: false,
44
+ error: null
45
+ });
46
+ const mutate = (args) => __awaiter(this, void 0, void 0, function* () {
47
+ state.isLoading = true;
48
+ state.error = null;
49
+ try {
50
+ const result = yield mutationFn(args);
51
+ state.data = result;
52
+ return result;
53
+ }
54
+ catch (err) {
55
+ state.error = err;
56
+ throw err;
57
+ }
58
+ finally {
59
+ state.isLoading = false;
60
+ }
61
+ });
62
+ return Object.assign(Object.assign({}, state), { mutate });
63
+ }
@@ -0,0 +1,105 @@
1
+ // MulanJS 2.0: Signal-Powered Reactivity Engine
2
+ // "Compatible Surface, World-Class Engine"
3
+ let activeEffect = null;
4
+ const targetMap = new WeakMap();
5
+ // --- Signal Core (The Engine) ---
6
+ export class Signal {
7
+ constructor(initialValue) {
8
+ this._subscribers = new Set();
9
+ this._value = initialValue;
10
+ }
11
+ get value() {
12
+ if (activeEffect) {
13
+ this._subscribers.add(activeEffect);
14
+ }
15
+ return this._value;
16
+ }
17
+ set value(newValue) {
18
+ if (newValue !== this._value) {
19
+ this._value = newValue;
20
+ this.notify();
21
+ }
22
+ }
23
+ notify() {
24
+ this._subscribers.forEach(fn => fn());
25
+ }
26
+ }
27
+ // --- Compatibility Layer (The Surface) ---
28
+ export function effect(fn) {
29
+ let stopped = false;
30
+ const run = () => {
31
+ if (stopped)
32
+ return;
33
+ const prev = activeEffect;
34
+ activeEffect = run;
35
+ try {
36
+ fn();
37
+ }
38
+ finally {
39
+ activeEffect = prev;
40
+ }
41
+ };
42
+ run();
43
+ return () => {
44
+ stopped = true;
45
+ };
46
+ }
47
+ function track(target, key) {
48
+ if (activeEffect) {
49
+ let depsMap = targetMap.get(target);
50
+ if (!depsMap) {
51
+ targetMap.set(target, (depsMap = new Map()));
52
+ }
53
+ let dep = depsMap.get(key);
54
+ if (!dep) {
55
+ depsMap.set(key, (dep = new Set()));
56
+ }
57
+ dep.add(activeEffect);
58
+ }
59
+ }
60
+ function trigger(target, key) {
61
+ const depsMap = targetMap.get(target);
62
+ if (!depsMap)
63
+ return;
64
+ const dep = depsMap.get(key);
65
+ if (dep) {
66
+ dep.forEach((fn) => fn());
67
+ }
68
+ }
69
+ /**
70
+ * Creates a reactive proxy object (Vue-compatible).
71
+ * Now optimized to respect Mulan Cycle.
72
+ */
73
+ export function reactive(target) {
74
+ return new Proxy(target, {
75
+ get(obj, prop, receiver) {
76
+ // IRON FORTRESS: Prototype Pollution Protection (Read)
77
+ if (prop === '__proto__' || prop === 'constructor' || prop === 'prototype') {
78
+ return undefined;
79
+ }
80
+ track(obj, prop);
81
+ const val = Reflect.get(obj, prop, receiver);
82
+ if (val !== null && typeof val === 'object') {
83
+ return reactive(val);
84
+ }
85
+ return val;
86
+ },
87
+ set(obj, prop, value, receiver) {
88
+ // IRON FORTRESS: Prototype Pollution Protection
89
+ if (prop === '__proto__' || prop === 'constructor' || prop === 'prototype') {
90
+ console.warn(`[Iron Fortress] Blocked attempt to modify dangerous property: ${String(prop)}`);
91
+ return false;
92
+ }
93
+ const result = Reflect.set(obj, prop, value, receiver);
94
+ trigger(obj, prop);
95
+ return result;
96
+ },
97
+ });
98
+ }
99
+ /**
100
+ * Creates a standalone reactive reference.
101
+ * Backed by the Mulan Signal Engine.
102
+ */
103
+ export function ref(value) {
104
+ return new Signal(value);
105
+ }
@@ -0,0 +1,70 @@
1
+ export function render(template, container) {
2
+ // Focus Preservation (The "Mulan Glance" Technique)
3
+ let focusedId = null;
4
+ let selectionStart = null;
5
+ let selectionEnd = null;
6
+ let preservedValue = null;
7
+ if (document.activeElement && container.contains(document.activeElement)) {
8
+ const el = document.activeElement;
9
+ if (el.hasAttribute('data-mu-id')) {
10
+ focusedId = el.getAttribute('data-mu-id');
11
+ if (el instanceof HTMLInputElement || el instanceof HTMLTextAreaElement) {
12
+ selectionStart = el.selectionStart;
13
+ selectionEnd = el.selectionEnd;
14
+ preservedValue = el.value;
15
+ }
16
+ }
17
+ }
18
+ container.innerHTML = template;
19
+ // Restore Focus and Value
20
+ if (focusedId) {
21
+ const el = container.querySelector(`[data-mu-id="${focusedId}"]`);
22
+ if (el) {
23
+ // Restore value first to ensure cursor positioning works correctly
24
+ if (preservedValue !== null && (el instanceof HTMLInputElement || el instanceof HTMLTextAreaElement)) {
25
+ el.value = preservedValue;
26
+ }
27
+ el.focus();
28
+ if ((el instanceof HTMLInputElement || el instanceof HTMLTextAreaElement) && selectionStart !== null) {
29
+ try {
30
+ el.setSelectionRange(selectionStart, selectionEnd);
31
+ }
32
+ catch (e) {
33
+ // input types that don't support selection (e.g. number/email) might throw
34
+ }
35
+ }
36
+ }
37
+ }
38
+ }
39
+ export function hydrate(template, container) {
40
+ // In a string-based framework, hydration is often just "take over".
41
+ // For now, we'll verify if the server content matches (simple check)
42
+ // and then assume control. In a more advanced version, we'd attach listeners without re-rendering.
43
+ if (container.innerHTML.trim() !== template.trim()) {
44
+ console.warn('Hydration Mismatch: Server rendered content differs from Client.');
45
+ container.innerHTML = template; // Fallback to full render
46
+ }
47
+ else {
48
+ // console.log('Hydration Successful.');
49
+ }
50
+ // Future: Attach event listeners here if we had a mechanism for it.
51
+ }
52
+ export function renderToString(template) {
53
+ // SSR Function: returns the HTML string for the server to send.
54
+ // Can include additional sanitization or metadata injection here.
55
+ return template;
56
+ }
57
+ export function sanitize(str) {
58
+ // Check if we are in a browser environment
59
+ if (typeof document !== 'undefined') {
60
+ const temp = document.createElement('div');
61
+ temp.textContent = str;
62
+ return temp.innerHTML;
63
+ }
64
+ // Simple SSR fallback sanitizer (rudimentary)
65
+ return str.replace(/&/g, "&amp;")
66
+ .replace(/</g, "&lt;")
67
+ .replace(/>/g, "&gt;")
68
+ .replace(/"/g, "&quot;")
69
+ .replace(/'/g, "&#039;");
70
+ }
@@ -0,0 +1,81 @@
1
+ import { muEffect } from './hooks';
2
+ import { reactive } from './reactive';
3
+ const MULAN_SECRET = 'b3ast_mulan_s3cur1ty_k3y';
4
+ function beastXOR(str) {
5
+ let result = '';
6
+ for (let i = 0; i < str.length; i++) {
7
+ result += String.fromCharCode(str.charCodeAt(i) ^ MULAN_SECRET.charCodeAt(i % MULAN_SECRET.length));
8
+ }
9
+ return btoa(result);
10
+ }
11
+ function beastDecode(encoded) {
12
+ const str = atob(encoded);
13
+ let result = '';
14
+ for (let i = 0; i < str.length; i++) {
15
+ result += String.fromCharCode(str.charCodeAt(i) ^ MULAN_SECRET.charCodeAt(i % MULAN_SECRET.length));
16
+ }
17
+ return result;
18
+ }
19
+ /**
20
+ * Mulan Vault: The World's First Native Persistent State Primitive.
21
+ * Now fortified with Iron Fortress Obfuscation.
22
+ */
23
+ export function persistent(key, initialValue, options = {}) {
24
+ const storage = options.storage || window.localStorage;
25
+ // 1. Load from Storage
26
+ const stored = storage.getItem(key);
27
+ let startVal = initialValue;
28
+ if (stored) {
29
+ try {
30
+ const raw = options.encrypt ? beastDecode(stored) : stored;
31
+ startVal = JSON.parse(raw);
32
+ }
33
+ catch (e) {
34
+ console.warn(`[Iron Fortress] Corrupt persistent data for key "${key}", resetting.`);
35
+ }
36
+ }
37
+ // 2. Create Reactive State (Follow muState pattern for consistency)
38
+ const isObject = typeof startVal === 'object' && startVal !== null;
39
+ const state = isObject ? reactive(startVal) : reactive({ value: startVal });
40
+ // 3. Auto-Save on Change
41
+ muEffect(() => {
42
+ try {
43
+ const payload = isObject ? state : state.value;
44
+ const raw = JSON.stringify(payload);
45
+ const toSave = options.encrypt ? beastXOR(raw) : raw;
46
+ storage.setItem(key, toSave);
47
+ }
48
+ catch (e) {
49
+ console.error(`[Iron Fortress] Failed to save key "${key}"`);
50
+ }
51
+ });
52
+ // 4. Sync across Tabs
53
+ const sync = (e) => {
54
+ if (e.key === key && e.newValue) {
55
+ try {
56
+ const raw = options.encrypt ? beastDecode(e.newValue) : e.newValue;
57
+ const newVal = JSON.parse(raw);
58
+ if (isObject) {
59
+ Object.assign(state, newVal);
60
+ }
61
+ else {
62
+ state.value = newVal;
63
+ }
64
+ }
65
+ catch (e) { }
66
+ }
67
+ };
68
+ window.addEventListener('storage', sync);
69
+ // Auto-cleanup if used inside a component
70
+ try {
71
+ const { onMuDestroy } = require('./hooks');
72
+ onMuDestroy(() => {
73
+ window.removeEventListener('storage', sync);
74
+ });
75
+ }
76
+ catch (e) {
77
+ // muVault might be used outside component setup in some advanced cases,
78
+ // fallback to manual or no-cleanup if so.
79
+ }
80
+ return state;
81
+ }
package/dist/index.js ADDED
@@ -0,0 +1,52 @@
1
+ export * from './core/reactive';
2
+ export { MuComponent, MuComponent as Component, defineComponent } from './core/component';
3
+ export * from './core/renderer';
4
+ export { MuRouter, MuRouter as Router } from './router/index';
5
+ export { MuStore } from './store/index';
6
+ export * from './security/sanitizer';
7
+ export * from './core/hooks';
8
+ export * from './core/query';
9
+ export * from './core/vault';
10
+ export * from './core/quantum';
11
+ export * from './components/bloch-sphere';
12
+ // Global Mulan Object for non-module usage
13
+ import { reactive, effect } from './core/reactive';
14
+ import { MuComponent, defineComponent } from './core/component';
15
+ import { MuRouter } from './router/index';
16
+ import { MuStore } from './store/index';
17
+ import { Security } from './security/sanitizer';
18
+ import * as Hooks from './core/hooks';
19
+ import * as Query from './core/query';
20
+ import * as Quantum from './core/quantum';
21
+ const Mulan = Object.assign(Object.assign(Object.assign(Object.assign({ reactive,
22
+ effect, Component: MuComponent, defineComponent, Router: MuRouter, Store: MuStore, Security: Security }, Hooks), Query), Quantum), {
23
+ // MULAN INSIGHT: Branded Logging
24
+ log: (msg, ...args) => {
25
+ console.log(`%c[MulanJS]%c ${msg}`, "color: #ff3e00; font-weight: bold; background: #222; padding: 2px 4px; border-radius: 3px;", "", ...args);
26
+ }, warn: (msg, ...args) => {
27
+ console.warn(`%c[MulanJS]%c ${msg}`, "color: #ffcc00; font-weight: bold; background: #222; padding: 2px 4px; border-radius: 3px;", "", ...args);
28
+ }, error: (msg, ...args) => {
29
+ console.error(`%c[MulanJS]%c ${msg}`, "color: #ff0000; font-weight: bold; background: #222; padding: 2px 4px; border-radius: 3px;", "", ...args);
30
+ } });
31
+ // Security: Freeze the object to prevent runtime tampering
32
+ Object.freeze(Mulan);
33
+ Object.freeze(Mulan.Security);
34
+ // MULAN INSIGHT: Initialize Global Registry
35
+ if (typeof window !== 'undefined') {
36
+ window.__MULAN_INSIGHT__ = window.__MULAN_INSIGHT__ || { components: new Map() };
37
+ // MULAN INSIGHT: HMR Support
38
+ window.__MULAN_REFRESH__ = () => {
39
+ var _a;
40
+ const components = (_a = window.__MULAN_INSIGHT__) === null || _a === void 0 ? void 0 : _a.components;
41
+ if (components) {
42
+ components.forEach((comp) => {
43
+ if (comp && typeof comp.update === 'function') {
44
+ // Force refresh
45
+ comp.update();
46
+ }
47
+ });
48
+ }
49
+ };
50
+ }
51
+ window.Mulan = Mulan;
52
+ export default Mulan;