@mulanjs/mulanjs 1.0.1-dev.20260227135307 → 1.0.1-dev.20260227173253

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 (52) hide show
  1. package/dist/compiler/ast-parser.d.ts +48 -0
  2. package/dist/compiler/ast-parser.js +54 -9
  3. package/dist/compiler/compiler.d.ts +9 -0
  4. package/dist/compiler/compiler.js +45 -2
  5. package/dist/compiler/dom-compiler.d.ts +7 -0
  6. package/dist/compiler/dom-compiler.js +90 -33
  7. package/dist/compiler/script-compiler.d.ts +11 -0
  8. package/dist/compiler/script-compiler.js +108 -116
  9. package/dist/compiler/sfc-parser.d.ts +21 -0
  10. package/dist/compiler/ssr-compiler.d.ts +7 -0
  11. package/dist/compiler/ssr-compiler.js +142 -0
  12. package/dist/compiler/style-compiler.d.ts +8 -0
  13. package/dist/compiler/template-compiler.d.ts +8 -0
  14. package/dist/components/bloch-sphere.js +9 -3
  15. package/dist/components/infinity-list.js +7 -1
  16. package/dist/core/component.js +66 -15
  17. package/dist/core/hooks.js +53 -29
  18. package/dist/core/quantum.js +30 -17
  19. package/dist/core/query.js +11 -6
  20. package/dist/core/reactive.js +88 -7
  21. package/dist/core/renderer.js +9 -8
  22. package/dist/core/ssr.js +50 -0
  23. package/dist/core/surge.js +7 -2
  24. package/dist/core/vault.js +9 -5
  25. package/dist/index.js +63 -27
  26. package/dist/mulan.esm.js +187 -19
  27. package/dist/mulan.esm.js.map +1 -1
  28. package/dist/mulan.js +1890 -1590
  29. package/dist/mulan.js.map +1 -1
  30. package/dist/router/index.js +17 -10
  31. package/dist/security/sanitizer.js +5 -1
  32. package/dist/store/index.js +9 -5
  33. package/dist/types/ast-parser.d.ts +2 -0
  34. package/dist/types/compiler/ast-parser.d.ts +2 -0
  35. package/dist/types/compiler/compiler.d.ts +1 -0
  36. package/dist/types/compiler/ssr-compiler.d.ts +7 -0
  37. package/dist/types/compiler.d.ts +1 -0
  38. package/dist/types/components/bloch-sphere.d.ts +3 -1
  39. package/dist/types/components/infinity-list.d.ts +3 -1
  40. package/dist/types/core/component.d.ts +14 -0
  41. package/dist/types/core/reactive.d.ts +5 -1
  42. package/dist/types/core/renderer.d.ts +0 -1
  43. package/dist/types/core/ssr.d.ts +9 -0
  44. package/dist/types/index.d.ts +1 -0
  45. package/dist/types/ssr-compiler.d.ts +7 -0
  46. package/package.json +1 -1
  47. package/src/compiler/ast-parser.ts +62 -10
  48. package/src/compiler/compiler.ts +46 -1
  49. package/src/compiler/dom-compiler.ts +100 -34
  50. package/src/compiler/script-compiler.ts +117 -126
  51. package/src/compiler/ssr-compiler.ts +157 -0
  52. package/src/loader/index.js +12 -19
@@ -0,0 +1,50 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.renderToString = void 0;
4
+ /**
5
+ * Renders a Mulan component to a static HTML string with a resumability envelope.
6
+ */
7
+ function renderToString(ComponentClass, props = {}) {
8
+ // 1. Initialize component in a virtual container (not used for DOM)
9
+ // On server, we mock the container or just pass a dummy object
10
+ const dummyContainer = {
11
+ querySelector: () => null,
12
+ querySelectorAll: () => [],
13
+ appendChild: () => { },
14
+ removeChild: () => { },
15
+ getAttribute: () => null
16
+ };
17
+ const instance = new ComponentClass(dummyContainer);
18
+ // Pass props
19
+ Object.assign(instance, props);
20
+ // 2. Render to HTML
21
+ if (typeof instance.renderToString !== 'function') {
22
+ throw new Error(`Component ${ComponentClass.name} was not compiled for SSR.`);
23
+ }
24
+ const html = instance.renderToString();
25
+ // 3. Extract State for Resumability
26
+ // We only want to serialize data that was exposed in setup()
27
+ // For now, we'll serialize any property on the instance that isn't internal
28
+ const state = {};
29
+ for (const key in instance) {
30
+ if (key.startsWith('_') || key === 'container' || key === 'state' || typeof instance[key] === 'function')
31
+ continue;
32
+ const value = instance[key];
33
+ // Handle signals specifically
34
+ if (value && typeof value === 'object' && 'value' in value) {
35
+ state[key] = value.value;
36
+ }
37
+ else {
38
+ state[key] = value;
39
+ }
40
+ }
41
+ // 4. Construct Resumability Envelope
42
+ const stateScript = `<script type="mulan/state" data-mu-uid="${instance.$uid}">${JSON.stringify(state)}</script>`;
43
+ const envelope = `<div data-mu-root="${instance.$uid}">${html}${stateScript}</div>`;
44
+ return {
45
+ html,
46
+ state,
47
+ envelope
48
+ };
49
+ }
50
+ exports.renderToString = renderToString;
@@ -1,9 +1,12 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.muSurge = exports.muBurst = void 0;
1
4
  /**
2
5
  * muBurst - Adaptive Non-blocking Iterator
3
6
  * Processes large arrays in batches within a frame budget (typically 8-16ms)
4
7
  * to keep the UI responsive while executing at near-native loop speeds.
5
8
  */
6
- export function muBurst(array, callback, options = {}) {
9
+ function muBurst(array, callback, options = {}) {
7
10
  const { chunkSize = 1000, timeout = 8, onProgress } = options;
8
11
  return new Promise((resolve) => {
9
12
  let index = 0;
@@ -31,12 +34,13 @@ export function muBurst(array, callback, options = {}) {
31
34
  process();
32
35
  });
33
36
  }
37
+ exports.muBurst = muBurst;
34
38
  /**
35
39
  * muSurge - Truly Parallel Execution
36
40
  * Distributes work across CPU cores using Web Workers.
37
41
  * Logic must be serializable.
38
42
  */
39
- export function muSurge(array, taskFn, onProgress) {
43
+ function muSurge(array, taskFn, onProgress) {
40
44
  const n = navigator.hardwareConcurrency || 4;
41
45
  const chunkSize = Math.ceil(array.length / n);
42
46
  const results = new Array(array.length);
@@ -85,3 +89,4 @@ export function muSurge(array, taskFn, onProgress) {
85
89
  }
86
90
  });
87
91
  }
92
+ exports.muSurge = muSurge;
@@ -1,9 +1,12 @@
1
- import { muEffect } from './hooks';
2
- import { reactive } from './reactive';
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.persistent = void 0;
4
+ const hooks_1 = require("./hooks");
5
+ const reactive_1 = require("./reactive");
3
6
  /**
4
7
  * Mulan Vault: The World's First Native Persistent State Primitive.
5
8
  */
6
- export function persistent(key, initialValue, options = {}) {
9
+ function persistent(key, initialValue, options = {}) {
7
10
  const storage = options.storage || window.localStorage;
8
11
  // 1. Load from Storage
9
12
  const stored = storage.getItem(key);
@@ -18,9 +21,9 @@ export function persistent(key, initialValue, options = {}) {
18
21
  }
19
22
  // 2. Create Reactive State (Follow muState pattern for consistency)
20
23
  const isObject = typeof startVal === 'object' && startVal !== null;
21
- const state = isObject ? reactive(startVal) : reactive({ value: startVal });
24
+ const state = isObject ? (0, reactive_1.reactive)(startVal) : (0, reactive_1.reactive)({ value: startVal });
22
25
  // 3. Auto-Save on Change
23
- muEffect(() => {
26
+ (0, hooks_1.muEffect)(() => {
24
27
  try {
25
28
  const payload = isObject ? state : state.value;
26
29
  const toSave = JSON.stringify(payload);
@@ -55,3 +58,4 @@ export function persistent(key, initialValue, options = {}) {
55
58
  }
56
59
  return state;
57
60
  }
61
+ exports.persistent = persistent;
package/dist/index.js CHANGED
@@ -1,30 +1,66 @@
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 './core/surge';
12
- export * from './components/bloch-sphere';
13
- export * from './components/infinity-list';
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
19
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
20
+ };
21
+ var __importStar = (this && this.__importStar) || function (mod) {
22
+ if (mod && mod.__esModule) return mod;
23
+ var result = {};
24
+ if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
25
+ __setModuleDefault(result, mod);
26
+ return result;
27
+ };
28
+ Object.defineProperty(exports, "__esModule", { value: true });
29
+ exports.MuStore = exports.Router = exports.MuRouter = exports.defineComponent = exports.Component = exports.MuComponent = void 0;
30
+ __exportStar(require("./core/reactive"), exports);
31
+ var component_1 = require("./core/component");
32
+ Object.defineProperty(exports, "MuComponent", { enumerable: true, get: function () { return component_1.MuComponent; } });
33
+ Object.defineProperty(exports, "Component", { enumerable: true, get: function () { return component_1.MuComponent; } });
34
+ Object.defineProperty(exports, "defineComponent", { enumerable: true, get: function () { return component_1.defineComponent; } });
35
+ __exportStar(require("./core/renderer"), exports);
36
+ var index_1 = require("./router/index");
37
+ Object.defineProperty(exports, "MuRouter", { enumerable: true, get: function () { return index_1.MuRouter; } });
38
+ Object.defineProperty(exports, "Router", { enumerable: true, get: function () { return index_1.MuRouter; } });
39
+ var index_2 = require("./store/index");
40
+ Object.defineProperty(exports, "MuStore", { enumerable: true, get: function () { return index_2.MuStore; } });
41
+ __exportStar(require("./security/sanitizer"), exports);
42
+ __exportStar(require("./core/hooks"), exports);
43
+ __exportStar(require("./core/query"), exports);
44
+ __exportStar(require("./core/vault"), exports);
45
+ __exportStar(require("./core/quantum"), exports);
46
+ __exportStar(require("./core/surge"), exports);
47
+ __exportStar(require("./components/bloch-sphere"), exports);
48
+ __exportStar(require("./components/infinity-list"), exports);
49
+ __exportStar(require("./core/ssr"), exports);
14
50
  // Global Mulan Object for non-module usage
15
- import { reactive, effect } from './core/reactive';
16
- import { MuComponent, defineComponent } from './core/component';
17
- import { MuRouter, createRouter } from './router/index';
18
- import { MuStore } from './store/index';
19
- import { Security } from './security/sanitizer';
20
- import * as Hooks from './core/hooks';
21
- import * as Query from './core/query';
22
- import { render } from './core/renderer';
23
- import * as Quantum from './core/quantum';
24
- import * as Surge from './core/surge';
25
- import * as InfinityList from './components/infinity-list';
26
- const Mulan = Object.assign(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign({ reactive,
27
- effect, Component: MuComponent, defineComponent, Router: MuRouter, createRouter, Store: MuStore, Security: Security }, Hooks), Query), Quantum), Surge), InfinityList), { render,
51
+ const reactive_1 = require("./core/reactive");
52
+ const component_2 = require("./core/component");
53
+ const index_3 = require("./router/index");
54
+ const index_4 = require("./store/index");
55
+ const sanitizer_1 = require("./security/sanitizer");
56
+ const Hooks = __importStar(require("./core/hooks"));
57
+ const Query = __importStar(require("./core/query"));
58
+ const renderer_1 = require("./core/renderer");
59
+ const Quantum = __importStar(require("./core/quantum"));
60
+ const Surge = __importStar(require("./core/surge"));
61
+ const InfinityList = __importStar(require("./components/infinity-list"));
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,
28
64
  // MULAN INSIGHT: Branded Logging
29
65
  log: (msg, ...args) => {
30
66
  console.log(`%c[MulanJS]%c ${msg}`, "color: #ff3e00; font-weight: bold; background: #222; padding: 2px 4px; border-radius: 3px;", "", ...args);
@@ -56,4 +92,4 @@ if (typeof window !== 'undefined') {
56
92
  if (typeof window !== 'undefined') {
57
93
  window.Mulan = Mulan;
58
94
  }
59
- export default Mulan;
95
+ exports.default = Mulan;
package/dist/mulan.esm.js CHANGED
@@ -106,6 +106,59 @@ __webpack_require__.d(infinity_list_namespaceObject, {
106
106
  let activeEffect = null;
107
107
  let activeEffectRunner = null;
108
108
  const targetMap = new WeakMap();
109
+ // --- Mulan Quantum Scheduler (Time-Slicing) ---
110
+ // Assign unique IDs to effects for basic topological sorting (lower IDs run first)
111
+ let effectIdCounter = 0;
112
+ const pendingEffects = new Set();
113
+ let isScheduling = false;
114
+ const TIME_BUDGET = 8; // 8ms frame budget for 60FPS lock
115
+ function runScheduler() {
116
+ if (pendingEffects.size === 0) {
117
+ isScheduling = false;
118
+ return;
119
+ }
120
+ const start = typeof performance !== 'undefined' ? performance.now() : Date.now();
121
+ // Convert to array and sort to ensure parent effects run before children (Topological Push-Pull approximation)
122
+ const sortedEffects = Array.from(pendingEffects).sort((a, b) => {
123
+ return (a._id || 0) - (b._id || 0);
124
+ });
125
+ for (const fn of sortedEffects) {
126
+ pendingEffects.delete(fn);
127
+ fn();
128
+ const now = typeof performance !== 'undefined' ? performance.now() : Date.now();
129
+ if (now - start > TIME_BUDGET) {
130
+ break; // Yield to browser
131
+ }
132
+ }
133
+ if (pendingEffects.size > 0) {
134
+ if (typeof MessageChannel !== 'undefined') {
135
+ const channel = new MessageChannel();
136
+ channel.port1.onmessage = runScheduler;
137
+ channel.port2.postMessage(null);
138
+ }
139
+ else {
140
+ setTimeout(runScheduler, 0);
141
+ }
142
+ }
143
+ else {
144
+ isScheduling = false;
145
+ }
146
+ }
147
+ function queueEffect(fn) {
148
+ pendingEffects.add(fn);
149
+ if (!isScheduling) {
150
+ isScheduling = true;
151
+ if (typeof Promise !== 'undefined') {
152
+ Promise.resolve().then(runScheduler);
153
+ }
154
+ else {
155
+ setTimeout(runScheduler, 0);
156
+ }
157
+ }
158
+ }
159
+ function nextTick() {
160
+ return Promise.resolve();
161
+ }
109
162
  // --- Signal Core (The Engine) ---
110
163
  class Signal {
111
164
  constructor(initialValue) {
@@ -125,17 +178,25 @@ class Signal {
125
178
  }
126
179
  }
127
180
  notify() {
128
- this._subscribers.forEach(fn => fn());
181
+ this._subscribers.forEach(fn => {
182
+ if (fn._sync) {
183
+ fn();
184
+ }
185
+ else {
186
+ queueEffect(fn);
187
+ }
188
+ });
129
189
  }
130
190
  }
131
191
  // --- Compatibility Layer (The Surface) ---
132
- function effect(fn, targetNode) {
192
+ function effect(fn, targetNode, options = {}) {
133
193
  let stopped = false;
194
+ const id = ++effectIdCounter;
134
195
  const run = () => {
135
196
  if (stopped)
136
197
  return;
137
198
  const prevRunner = activeEffectRunner;
138
- activeEffectRunner = { run, node: targetNode };
199
+ activeEffectRunner = { run, node: targetNode, id };
139
200
  try {
140
201
  fn();
141
202
  }
@@ -143,9 +204,13 @@ function effect(fn, targetNode) {
143
204
  activeEffectRunner = prevRunner;
144
205
  }
145
206
  };
207
+ // Attach ID for topological sorting
208
+ run._id = id;
209
+ run._sync = options.sync;
146
210
  run();
147
211
  return () => {
148
212
  stopped = true;
213
+ pendingEffects.delete(run);
149
214
  };
150
215
  }
151
216
  function track(target, key) {
@@ -167,7 +232,14 @@ function trigger(target, key) {
167
232
  return;
168
233
  const dep = depsMap.get(key);
169
234
  if (dep) {
170
- dep.forEach((fn) => fn());
235
+ dep.forEach((fn) => {
236
+ if (fn._sync) {
237
+ fn(); // Run synchronously if explicitly requested (e.g. for muMemo)
238
+ }
239
+ else {
240
+ queueEffect(fn); // Push to Quantum Scheduler
241
+ }
242
+ });
171
243
  }
172
244
  }
173
245
  /**
@@ -311,11 +383,6 @@ function hydrate(template, container) {
311
383
  }
312
384
  // Future: Attach event listeners here if we had a mechanism for it.
313
385
  }
314
- function renderToString(template) {
315
- // SSR Function: returns the HTML string for the server to send.
316
- // Can include additional sanitization or metadata injection here.
317
- return template;
318
- }
319
386
  function sanitize(str) {
320
387
  // Check if we are in a browser environment
321
388
  if (typeof document !== 'undefined') {
@@ -775,6 +842,8 @@ class MuComponent {
775
842
  this._effects = [];
776
843
  this._domEffects = [];
777
844
  this._isDestroyed = false;
845
+ this._isResuming = false; // Quantum Resumability Flag
846
+ this._resumeRoot = null;
778
847
  this._propsQueue = [];
779
848
  this._eventQueue = [];
780
849
  // --- MulanJS List Reconciliation Engine (No-VDOM) ---
@@ -786,6 +855,26 @@ class MuComponent {
786
855
  this.container = container;
787
856
  this.state = {};
788
857
  this.$uid = 'mu_' + Math.random().toString(36).substr(2, 9);
858
+ // MULAN INSIGHT: Quantum Resumability Detection
859
+ if (typeof window !== 'undefined' && container) {
860
+ const rootAttr = container.getAttribute('data-mu-root');
861
+ const stateScript = container.querySelector('script[type="mulan/state"]');
862
+ if (rootAttr || stateScript) {
863
+ console.log(`%c[Mulan Quantum]%c Resuming component from server state...`, "color: #00ffcc; font-weight: bold;", "");
864
+ this._isResuming = true;
865
+ this.$uid = rootAttr || this.$uid;
866
+ if (stateScript) {
867
+ try {
868
+ const serverState = JSON.parse(stateScript.textContent || '{}');
869
+ // Inject server state into this instance
870
+ Object.assign(this, serverState);
871
+ }
872
+ catch (e) {
873
+ console.error("[Mulan Quantum] Failed to parse server state:", e);
874
+ }
875
+ }
876
+ }
877
+ }
789
878
  // MULAN INSIGHT: Global Registry for Debugging
790
879
  if (typeof window !== 'undefined') {
791
880
  const global = window;
@@ -846,14 +935,38 @@ class MuComponent {
846
935
  }
847
936
  mount() {
848
937
  console.log(`[Mulan Cycle] Mounting component ${this.$uid}`);
849
- // The main render effect (legacy strings fallback / macro structure)
850
- const stop = effect(() => {
851
- console.log(`[Mulan Reactivity] Triggering macro-update for ${this.$uid}`);
852
- this.update();
853
- });
854
- this._effects.push(stop);
938
+ if (this._isResuming) {
939
+ // Quantum Resumability: Skip initial render, just attach effects to existing DOM
940
+ console.log(`[Mulan Quantum] Skipping initial render, recovering DOM nodes...`);
941
+ this._resume();
942
+ }
943
+ else {
944
+ // Standard Hydration/Mount
945
+ const stop = effect(() => {
946
+ console.log(`[Mulan Reactivity] Triggering macro-update for ${this.$uid}`);
947
+ this.update();
948
+ });
949
+ this._effects.push(stop);
950
+ }
855
951
  this.onMount();
856
952
  }
953
+ /**
954
+ * Internal method to execute the resumability pass.
955
+ * Overridden by compiler-generated code.
956
+ */
957
+ _resume() {
958
+ // Clear queues
959
+ this._propsQueue = [];
960
+ this._eventQueue = [];
961
+ // Call the template with resumption context
962
+ // In a real implementation, the compiler will inject 'recovery' instructions
963
+ this._recoveryMode = true;
964
+ this.template();
965
+ this._recoveryMode = false;
966
+ // Flush bindings (events/props) to existing nodes
967
+ this.flushProps();
968
+ this.flushEvents();
969
+ }
857
970
  // New helper for the compiler to register a fine-grained DOM property effect
858
971
  _bindEffect(fn, targetNode) {
859
972
  const stop = effect(fn, targetNode);
@@ -1349,8 +1462,10 @@ const createRouter = (options) => {
1349
1462
  };
1350
1463
  // --- Web Component: <mu-link> ---
1351
1464
  // Usage: <mu-link to="/about">About Us</mu-link>
1465
+ const MuLinkBase = typeof HTMLElement !== 'undefined' ? HTMLElement : class {
1466
+ };
1352
1467
  if (typeof window !== 'undefined' && !customElements.get('mu-link')) {
1353
- class MuLink extends HTMLElement {
1468
+ class MuLink extends MuLinkBase {
1354
1469
  constructor() {
1355
1470
  super();
1356
1471
  this.addEventListener('click', (e) => {
@@ -1953,7 +2068,9 @@ function muSurge(array, taskFn, onProgress) {
1953
2068
 
1954
2069
  ;// ./src/components/bloch-sphere.ts
1955
2070
 
1956
- class MuBlochSphereElement extends HTMLElement {
2071
+ const MuBlochBase = typeof HTMLElement !== 'undefined' ? HTMLElement : class {
2072
+ };
2073
+ class MuBlochSphereElement extends MuBlochBase {
1957
2074
  static get observedAttributes() {
1958
2075
  return ['size'];
1959
2076
  }
@@ -2206,7 +2323,9 @@ if (typeof customElements !== 'undefined') {
2206
2323
  }
2207
2324
 
2208
2325
  ;// ./src/components/infinity-list.ts
2209
- class MuInfinity extends HTMLElement {
2326
+ const MuInfinityBase = typeof HTMLElement !== 'undefined' ? HTMLElement : class {
2327
+ };
2328
+ class MuInfinity extends MuInfinityBase {
2210
2329
  constructor() {
2211
2330
  super();
2212
2331
  this._items = [];
@@ -2317,6 +2436,54 @@ if (typeof customElements !== 'undefined' && !customElements.get('mu-infinity'))
2317
2436
  customElements.define('mu-infinity', MuInfinity);
2318
2437
  }
2319
2438
 
2439
+ ;// ./src/core/ssr.ts
2440
+ /**
2441
+ * Renders a Mulan component to a static HTML string with a resumability envelope.
2442
+ */
2443
+ function renderToString(ComponentClass, props = {}) {
2444
+ // 1. Initialize component in a virtual container (not used for DOM)
2445
+ // On server, we mock the container or just pass a dummy object
2446
+ const dummyContainer = {
2447
+ querySelector: () => null,
2448
+ querySelectorAll: () => [],
2449
+ appendChild: () => { },
2450
+ removeChild: () => { },
2451
+ getAttribute: () => null
2452
+ };
2453
+ const instance = new ComponentClass(dummyContainer);
2454
+ // Pass props
2455
+ Object.assign(instance, props);
2456
+ // 2. Render to HTML
2457
+ if (typeof instance.renderToString !== 'function') {
2458
+ throw new Error(`Component ${ComponentClass.name} was not compiled for SSR.`);
2459
+ }
2460
+ const html = instance.renderToString();
2461
+ // 3. Extract State for Resumability
2462
+ // We only want to serialize data that was exposed in setup()
2463
+ // For now, we'll serialize any property on the instance that isn't internal
2464
+ const state = {};
2465
+ for (const key in instance) {
2466
+ if (key.startsWith('_') || key === 'container' || key === 'state' || typeof instance[key] === 'function')
2467
+ continue;
2468
+ const value = instance[key];
2469
+ // Handle signals specifically
2470
+ if (value && typeof value === 'object' && 'value' in value) {
2471
+ state[key] = value.value;
2472
+ }
2473
+ else {
2474
+ state[key] = value;
2475
+ }
2476
+ }
2477
+ // 4. Construct Resumability Envelope
2478
+ const stateScript = `<script type="mulan/state" data-mu-uid="${instance.$uid}">${JSON.stringify(state)}</script>`;
2479
+ const envelope = `<div data-mu-root="${instance.$uid}">${html}${stateScript}</div>`;
2480
+ return {
2481
+ html,
2482
+ state,
2483
+ envelope
2484
+ };
2485
+ }
2486
+
2320
2487
  ;// ./src/index.ts
2321
2488
 
2322
2489
 
@@ -2331,6 +2498,7 @@ if (typeof customElements !== 'undefined' && !customElements.get('mu-infinity'))
2331
2498
 
2332
2499
 
2333
2500
 
2501
+
2334
2502
  // Global Mulan Object for non-module usage
2335
2503
 
2336
2504
 
@@ -2378,6 +2546,6 @@ if (typeof window !== 'undefined') {
2378
2546
  }
2379
2547
  /* harmony default export */ const src = (Mulan);
2380
2548
 
2381
- 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, onMuDestroy, onMuIdle, onMuInit, onMuMount, onMuPanic, onMuResume, onMuShake, onMuVisibility, onMuVoice, persistent, reactive, ref, render, renderToString, sanitize, setCurrentInstance, useMutation, useQuery };
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 };
2382
2550
 
2383
2551
  //# sourceMappingURL=mulan.esm.js.map