@lark.js/mvc 0.0.4 → 0.0.5

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/index.cjs CHANGED
@@ -22,15 +22,17 @@ var index_exports = {};
22
22
  __export(index_exports, {
23
23
  CALL_BREAK_TIME: () => CALL_BREAK_TIME,
24
24
  Cache: () => Cache,
25
+ CrossSite: () => cross_site_default,
25
26
  EVENT_METHOD_REGEXP: () => EVENT_METHOD_REGEXP,
26
27
  EventDelegator: () => EventDelegator,
27
28
  EventEmitter: () => EventEmitter,
28
29
  Frame: () => Frame,
30
+ FrameVisualBridge: () => FrameVisualBridge,
29
31
  Framework: () => Framework,
30
32
  LARK_VIEW: () => LARK_VIEW,
31
33
  Payload: () => Payload,
32
34
  Platform: () => Platform,
33
- ROUTER_EVENTS: () => ROUTER_EVENTS,
35
+ ROUTER_EVENTS: () => RouterEvents,
34
36
  Router: () => Router,
35
37
  SPLITTER: () => SPLITTER,
36
38
  Service: () => Service,
@@ -44,13 +46,14 @@ __export(index_exports, {
44
46
  applyVdomOps: () => applyVdomOps,
45
47
  assign: () => assign,
46
48
  cell: () => cell,
47
- classExtend: () => classExtend,
48
49
  cloneData: () => cloneData,
49
50
  cloneStore: () => cloneStore,
50
51
  compileTemplate: () => compileTemplate,
52
+ computed: () => computed,
51
53
  createState: () => createState,
52
54
  createVdomRef: () => createVdomRef,
53
55
  defineStore: () => defineStore,
56
+ defineView: () => defineView,
54
57
  delStore: () => delStore,
55
58
  encodeHTML: () => encodeHTML,
56
59
  encodeQ: () => encodeQ,
@@ -58,6 +61,7 @@ __export(index_exports, {
58
61
  encodeURIExtra: () => encodeURIExtra,
59
62
  ensureElementId: () => ensureElementId,
60
63
  extractGlobalVars: () => extractGlobalVars,
64
+ frameworkConfig: () => config,
61
65
  funcWithTry: () => funcWithTry,
62
66
  generateId: () => generateId,
63
67
  getAttribute: () => getAttribute,
@@ -65,8 +69,9 @@ __export(index_exports, {
65
69
  getPlatform: () => getPlatform,
66
70
  getStore: () => getStore,
67
71
  getUseStore: () => getUseStore,
68
- has: () => has,
72
+ hasOwnProperty: () => hasOwnProperty,
69
73
  installFrameVisualizerBridge: () => installFrameVisualizerBridge,
74
+ invalidateViewClass: () => invalidateViewClass,
70
75
  isPlainObject: () => isPlainObject,
71
76
  isPrimitive: () => isPrimitive,
72
77
  isPrimitiveOrFunc: () => isPrimitiveOrFunc,
@@ -85,6 +90,7 @@ __export(index_exports, {
85
90
  observeCell: () => observeCell,
86
91
  parseUri: () => parseUri,
87
92
  registerViewClass: () => registerViewClass,
93
+ resetProjectsMap: () => resetProjectsMap,
88
94
  safeguard: () => safeguard,
89
95
  serializeFrameTree: () => serializeFrameTree,
90
96
  setData: () => setData,
@@ -96,6 +102,7 @@ __export(index_exports, {
96
102
  toUri: () => toUri,
97
103
  translateData: () => translateData,
98
104
  unmark: () => unmark,
105
+ use: () => use,
99
106
  vdomGetCompareKey: () => vdomGetCompareKey,
100
107
  vdomGetNode: () => vdomGetNode,
101
108
  vdomSetAttributes: () => vdomSetAttributes,
@@ -109,12 +116,12 @@ module.exports = __toCommonJS(index_exports);
109
116
  // src/constants.ts
110
117
  var globalCounter = 0;
111
118
  var SPLITTER = "";
112
- var ROUTER_EVENTS = {
119
+ var RouterEvents = {
113
120
  CHANGE: "change",
114
121
  CHANGED: "changed",
115
122
  PAGE_UNLOAD: "page_unload"
116
123
  };
117
- var LARK_KEYS = {
124
+ var LarkInnerKeys = {
118
125
  /** Attribute name: ldk (static key for skipping VDOM diff) */
119
126
  DIFF_KEY: "ldk",
120
127
  /** Attribute name: lak (static attribute key) */
@@ -161,13 +168,13 @@ function syncCounter(val) {
161
168
  }
162
169
  function noop() {
163
170
  }
164
- function has(owner, prop) {
171
+ function hasOwnProperty(owner, prop) {
165
172
  return owner != null && Object.prototype.hasOwnProperty.call(owner, prop);
166
173
  }
167
174
  function keys(obj) {
168
175
  const result = [];
169
176
  for (const p in obj) {
170
- if (has(obj, p)) {
177
+ if (hasOwnProperty(obj, p)) {
171
178
  result.push(p);
172
179
  }
173
180
  }
@@ -177,7 +184,7 @@ function assign(target, ...sources) {
177
184
  for (const source of sources) {
178
185
  if (source) {
179
186
  for (const p in source) {
180
- if (has(source, p)) {
187
+ if (hasOwnProperty(source, p)) {
181
188
  target[p] = source[p];
182
189
  }
183
190
  }
@@ -190,21 +197,22 @@ function funcWithTry(fns, args, context, configError) {
190
197
  let ret;
191
198
  for (const fn of fnArray) {
192
199
  try {
193
- ret = Function.prototype.apply.call(fn, context, args);
200
+ ret = fn.apply(context, args);
194
201
  } catch (e) {
195
202
  configError?.(e);
196
203
  }
197
204
  }
198
205
  return ret;
199
206
  }
207
+ var EMPTY_STRING_SET = /* @__PURE__ */ new Set();
200
208
  function setData(newData, oldData, changedKeys2, excludes) {
201
209
  let changed = false;
202
210
  for (const p in newData) {
203
- if (has(newData, p)) {
211
+ if (hasOwnProperty(newData, p)) {
204
212
  const now2 = newData[p];
205
213
  const old = oldData[p];
206
214
  if ((!isPrimitiveOrFunc(now2) || old !== now2) && !excludes.has(p)) {
207
- changedKeys2[p] = 1;
215
+ changedKeys2.add(p);
208
216
  changed = true;
209
217
  }
210
218
  oldData[p] = now2;
@@ -212,17 +220,25 @@ function setData(newData, oldData, changedKeys2, excludes) {
212
220
  }
213
221
  return changed;
214
222
  }
223
+ function isRefToken(s) {
224
+ if (s.length < 2 || s[0] !== SPLITTER) return false;
225
+ for (let i = 1; i < s.length; i++) {
226
+ const c = s.charCodeAt(i);
227
+ if (c < 48 || c > 57) return false;
228
+ }
229
+ return true;
230
+ }
215
231
  function translateData(data, value) {
216
232
  if (isPrimitive(value)) {
217
233
  const prop = String(value);
218
- if (prop[0] === SPLITTER && has(data, prop)) {
234
+ if (isRefToken(prop) && hasOwnProperty(data, prop)) {
219
235
  return data[prop];
220
236
  }
221
237
  return value;
222
238
  }
223
239
  if (isPlainObject(value) || Array.isArray(value)) {
224
240
  for (const p in value) {
225
- if (has(value, p)) {
241
+ if (hasOwnProperty(value, p)) {
226
242
  const val = value[p];
227
243
  const newVal = translateData(data, val);
228
244
  value[p] = newVal;
@@ -259,38 +275,33 @@ function nodeInside(a, b) {
259
275
  return false;
260
276
  }
261
277
  }
262
- var paramsTemp = {};
263
- function paramsReplacer(_match, name, value) {
264
- try {
265
- paramsTemp[name] = decodeURIComponent(value || "");
266
- } catch {
267
- paramsTemp[name] = value || "";
268
- }
269
- return "";
270
- }
271
278
  function parseUri(uri) {
272
- paramsTemp = {};
279
+ const params = {};
273
280
  const path = uri.replace(URL_QUERY_HASH_REGEXP, "");
274
281
  const pathname = path;
275
282
  const actualPath = uri === pathname && IS_URL_PARAMS.test(pathname) ? "" : pathname;
276
- uri.replace(actualPath, "").replace(URL_PARAM_REGEXP, paramsReplacer);
277
- return {
278
- path: actualPath,
279
- params: { ...paramsTemp }
280
- };
283
+ uri.replace(actualPath, "").replace(URL_PARAM_REGEXP, (_match, name, value) => {
284
+ try {
285
+ params[name] = decodeURIComponent(value || "");
286
+ } catch {
287
+ params[name] = value || "";
288
+ }
289
+ return "";
290
+ });
291
+ return { path: actualPath, params };
281
292
  }
282
293
  var IS_URL_PARAMS = {
283
294
  test(s) {
284
295
  return /(?!^)=|&/.test(s);
285
296
  }
286
297
  };
287
- function toUri(path, params, keepEmptyObject) {
298
+ function toUri(path, params, keepEmpty) {
288
299
  const pairs = [];
289
300
  let hasParams = false;
290
301
  for (const p in params) {
291
- if (has(params, p)) {
302
+ if (hasOwnProperty(params, p)) {
292
303
  const v = String(params[p] ?? "");
293
- if (!keepEmptyObject || v || has(keepEmptyObject, p)) {
304
+ if (!keepEmpty || v || keepEmpty.has(p)) {
294
305
  pairs.push(`${p}=${encodeURIComponent(v)}`);
295
306
  hasParams = true;
296
307
  }
@@ -313,14 +324,6 @@ function toMap(list, key) {
313
324
  function now() {
314
325
  return Date.now ? Date.now() : (/* @__PURE__ */ new Date()).getTime();
315
326
  }
316
- function classExtend(make, base, props, statics) {
317
- const baseProto = base["prototype"] ?? {};
318
- const classProto = Object.create(baseProto);
319
- assign(classProto, props);
320
- Object.assign(make, statics);
321
- classProto.constructor = make;
322
- make["prototype"] = classProto;
323
- }
324
327
 
325
328
  // src/apply-style.ts
326
329
  var injectedStyleIds = /* @__PURE__ */ new Set();
@@ -360,27 +363,35 @@ function applyStyle(styleIdOrPairs, css) {
360
363
  }
361
364
 
362
365
  // src/mark.ts
363
- var DELETED_KEY = SPLITTER + "$delFlag";
364
- var MARK_OBJECT_KEY = SPLITTER + "$markKey";
366
+ var hostStore = /* @__PURE__ */ new WeakMap();
367
+ function getOrCreate(host) {
368
+ let record = hostStore.get(host);
369
+ if (!record) {
370
+ record = { signs: /* @__PURE__ */ new Map(), deleted: false };
371
+ hostStore.set(host, record);
372
+ }
373
+ return record;
374
+ }
365
375
  function mark(host, key) {
366
- let sign = 0;
367
- const hostRecord = host;
368
- if (!hostRecord[DELETED_KEY]) {
369
- const markHost = hostRecord[MARK_OBJECT_KEY] || (hostRecord[MARK_OBJECT_KEY] = {});
370
- if (!Object.prototype.hasOwnProperty.call(markHost, key)) {
371
- markHost[key] = 0;
372
- }
373
- sign = ++markHost[key];
376
+ const record = getOrCreate(host);
377
+ if (record.deleted) {
378
+ return () => false;
374
379
  }
380
+ const sign = (record.signs.get(key) ?? 0) + 1;
381
+ record.signs.set(key, sign);
375
382
  return () => {
376
- const temp = hostRecord[MARK_OBJECT_KEY];
377
- return !!(temp && sign === temp[key]);
383
+ const current = hostStore.get(host);
384
+ return !!current && !current.deleted && current.signs.get(key) === sign;
378
385
  };
379
386
  }
380
387
  function unmark(host) {
381
- const hostRecord = host;
382
- hostRecord[MARK_OBJECT_KEY] = 0;
383
- hostRecord[DELETED_KEY] = 1;
388
+ const record = hostStore.get(host);
389
+ if (record) {
390
+ record.deleted = true;
391
+ record.signs.clear();
392
+ } else {
393
+ hostStore.set(host, { signs: /* @__PURE__ */ new Map(), deleted: true });
394
+ }
384
395
  }
385
396
 
386
397
  // src/safeguard.ts
@@ -426,7 +437,7 @@ function safeguard(data, getter, setter, isRoot) {
426
437
  if (!prefix && getter) {
427
438
  getter(property);
428
439
  }
429
- if (!isRoot && has(target, property) && (Array.isArray(out) || isPlainObject(out))) {
440
+ if (!isRoot && hasOwnProperty(target, property) && (Array.isArray(out) || isPlainObject(out))) {
430
441
  return build(prefix + property + ".", out);
431
442
  }
432
443
  return out;
@@ -515,15 +526,17 @@ var Cache = class {
515
526
  this.lookup.set(prefixedKey, entry);
516
527
  }
517
528
  /**
518
- * Delete a cached entry.
529
+ * Delete a cached entry. Removes it immediately from both the lookup map
530
+ * and the entries array so the GC can reclaim the value without waiting
531
+ * for the next eviction sweep.
519
532
  */
520
533
  del(key) {
521
534
  const prefixedKey = this.prefixKey(key);
522
535
  const entry = this.lookup.get(prefixedKey);
523
536
  if (!entry) return;
524
- entry.frequency = -1;
525
- entry.value = void 0;
526
537
  this.lookup.delete(prefixedKey);
538
+ const idx = this.entries.indexOf(entry);
539
+ if (idx !== -1) this.entries.splice(idx, 1);
527
540
  if (this.onRemove) {
528
541
  this.onRemove(key);
529
542
  }
@@ -548,20 +561,46 @@ var Cache = class {
548
561
  this.entries = [];
549
562
  this.lookup.clear();
550
563
  }
551
- /** Evict least-used entries from cache */
564
+ /**
565
+ * Evict the `bufferSize` worst entries from the cache.
566
+ *
567
+ * Uses single-pass partial selection (O(n·k)) instead of sorting the entire
568
+ * `entries` array (O(n log n)). For the typical `bufferSize = 5` this is
569
+ * effectively a linear scan with at most 5 in-bucket comparisons per
570
+ * iteration — and it avoids mutating the rest of `entries`.
571
+ */
552
572
  evictEntries() {
553
- this.entries.sort(this.comparator);
554
- let count = this.bufferSize;
555
- while (count-- > 0 && this.entries.length > 0) {
556
- const entry = this.entries.pop();
557
- if (entry && entry.frequency > 0) {
558
- this.lookup.delete(this.prefixKey(entry.originalKey));
559
- if (this.onRemove) {
560
- this.onRemove(entry.originalKey);
561
- }
573
+ const entries = this.entries;
574
+ const k = this.bufferSize;
575
+ if (k <= 0 || entries.length === 0) return;
576
+ if (entries.length <= k) {
577
+ for (const e of entries) {
578
+ this.lookup.delete(this.prefixKey(e.originalKey));
579
+ if (this.onRemove) this.onRemove(e.originalKey);
562
580
  }
581
+ this.entries = [];
582
+ return;
583
+ }
584
+ const cmp = this.comparator;
585
+ const worst = [];
586
+ for (const entry of entries) {
587
+ if (worst.length < k) {
588
+ let i = worst.length;
589
+ while (i > 0 && cmp(entry, worst[i - 1]) > 0) i--;
590
+ worst.splice(i, 0, entry);
591
+ } else if (cmp(entry, worst[k - 1]) > 0) {
592
+ worst.pop();
593
+ let i = worst.length;
594
+ while (i > 0 && cmp(entry, worst[i - 1]) > 0) i--;
595
+ worst.splice(i, 0, entry);
596
+ }
597
+ }
598
+ const evictSet = new Set(worst);
599
+ for (const e of worst) {
600
+ this.lookup.delete(this.prefixKey(e.originalKey));
601
+ if (this.onRemove) this.onRemove(e.originalKey);
563
602
  }
564
- this.entries = this.entries.filter((e) => e.frequency !== -1);
603
+ this.entries = entries.filter((e) => !evictSet.has(e));
565
604
  }
566
605
  };
567
606
 
@@ -569,6 +608,10 @@ var Cache = class {
569
608
  var EventEmitter = class {
570
609
  /** Event listeners: prefixed key -> listener array */
571
610
  listeners = /* @__PURE__ */ new Map();
611
+ /** Number of `fire()` calls currently on the stack (re-entrancy depth). */
612
+ firingDepth = 0;
613
+ /** Keys whose listener list needs compaction after firing settles. */
614
+ pendingCompaction;
572
615
  /**
573
616
  * Bind event listener.
574
617
  */
@@ -591,13 +634,23 @@ var EventEmitter = class {
591
634
  const key = SPLITTER + event;
592
635
  if (handler) {
593
636
  const list = this.listeners.get(key);
594
- if (list) {
637
+ if (!list) return this;
638
+ if (this.firingDepth > 0) {
595
639
  for (const listener of list) {
596
640
  if (listener.handler === handler) {
597
641
  listener.handler = noop;
642
+ (this.pendingCompaction ??= /* @__PURE__ */ new Set()).add(key);
643
+ break;
644
+ }
645
+ }
646
+ } else {
647
+ for (let i = 0; i < list.length; i++) {
648
+ if (list[i].handler === handler) {
649
+ list.splice(i, 1);
598
650
  break;
599
651
  }
600
652
  }
653
+ if (list.length === 0) this.listeners.delete(key);
601
654
  }
602
655
  } else {
603
656
  this.listeners.delete(key);
@@ -609,9 +662,9 @@ var EventEmitter = class {
609
662
  return this;
610
663
  }
611
664
  /**
612
- * Fire event, execute all bound handlers.
613
- * Supports executing state management: handlers removed during
614
- * execution are safely handled.
665
+ * Fire event, execute all bound handlers. Safe for re-entrant `off()` calls
666
+ * during dispatch: removed handlers are replaced with noop and compacted
667
+ * after the outermost fire returns.
615
668
  *
616
669
  * @param event - Event name
617
670
  * @param data - Event data (type property added automatically)
@@ -625,38 +678,41 @@ var EventEmitter = class {
625
678
  data = {};
626
679
  }
627
680
  data["type"] = event;
628
- if (list) {
629
- let end = list.length;
630
- const len = end - 1;
631
- while (end--) {
632
- const idx = lastToFirst ? end : len - end;
633
- const listener = list[idx];
634
- if (listener.handler !== noop) {
681
+ this.firingDepth++;
682
+ try {
683
+ if (list) {
684
+ const len = list.length;
685
+ for (let i = 0; i < len; i++) {
686
+ const idx = lastToFirst ? len - 1 - i : i;
687
+ const listener = list[idx];
688
+ if (!listener) continue;
689
+ if (listener.handler === noop) continue;
635
690
  listener.executing = 1;
636
- funcWithTry(
637
- [listener.handler],
638
- [data],
639
- this,
640
- noop
641
- );
691
+ funcWithTry([listener.handler], [data], this, noop);
642
692
  listener.executing = "";
643
- } else if (!listener.executing) {
644
- list.splice(idx, 1);
645
693
  }
646
694
  }
647
- }
648
- const onMethodName = `on${event[0].toUpperCase() + event.slice(1)}`;
649
- const onMethod = this[onMethodName];
650
- if (typeof onMethod === "function") {
651
- funcWithTry(
652
- [onMethod],
653
- [data],
654
- this,
655
- noop
656
- );
657
- }
658
- if (remove) {
659
- this.off(event);
695
+ const onMethodName = `on${event[0].toUpperCase() + event.slice(1)}`;
696
+ const onMethod = this[onMethodName];
697
+ if (typeof onMethod === "function") {
698
+ funcWithTry([onMethod], [data], this, noop);
699
+ }
700
+ if (remove) {
701
+ this.off(event);
702
+ }
703
+ } finally {
704
+ this.firingDepth--;
705
+ if (this.firingDepth === 0 && this.pendingCompaction) {
706
+ for (const k of this.pendingCompaction) {
707
+ const l = this.listeners.get(k);
708
+ if (!l) continue;
709
+ for (let i = l.length - 1; i >= 0; i--) {
710
+ if (l[i].handler === noop) l.splice(i, 1);
711
+ }
712
+ if (l.length === 0) this.listeners.delete(k);
713
+ }
714
+ this.pendingCompaction = void 0;
715
+ }
660
716
  }
661
717
  return this;
662
718
  }
@@ -665,8 +721,8 @@ var EventEmitter = class {
665
721
  // src/state.ts
666
722
  var appData = {};
667
723
  var keyRefCounts = {};
668
- var changedKeys = {};
669
- var stashedChangedKeys = {};
724
+ var changedKeys = /* @__PURE__ */ new Set();
725
+ var stashedChangedKeys = EMPTY_STRING_SET;
670
726
  var dataIsChanged = false;
671
727
  var dataWhereSet = {};
672
728
  var emitter = new EventEmitter();
@@ -677,7 +733,7 @@ function markBooted() {
677
733
  function setupKeysRef(keys2) {
678
734
  const keyList = keys2.split(",");
679
735
  for (const key of keyList) {
680
- if (has(keyRefCounts, key)) {
736
+ if (hasOwnProperty(keyRefCounts, key)) {
681
737
  keyRefCounts[key]++;
682
738
  } else {
683
739
  keyRefCounts[key] = 1;
@@ -687,7 +743,7 @@ function setupKeysRef(keys2) {
687
743
  }
688
744
  function teardownKeysRef(keyList) {
689
745
  for (const key of keyList) {
690
- if (has(keyRefCounts, key)) {
746
+ if (hasOwnProperty(keyRefCounts, key)) {
691
747
  const count = --keyRefCounts[key];
692
748
  if (count <= 0) {
693
749
  Reflect.deleteProperty(keyRefCounts, key);
@@ -699,35 +755,14 @@ function teardownKeysRef(keyList) {
699
755
  }
700
756
  }
701
757
  }
702
- var notifyStarted = 0;
703
- var notifyList = [];
704
- var notifyTimer;
758
+ var warnedKeys = /* @__PURE__ */ new Set();
705
759
  function clearNotify(key) {
706
- for (let i = notifyList.length; i--; ) {
707
- if (notifyList[i]?.key === key) {
708
- notifyList.splice(i, 1);
709
- }
710
- }
711
- }
712
- function doNotify() {
713
- const locker = {};
714
- for (const n of notifyList) {
715
- if (!locker[n.key]) {
716
- console.warn(n.message);
717
- locker[n.key] = 1;
718
- }
719
- }
720
- notifyList.length = 0;
721
- notifyStarted = 0;
760
+ warnedKeys.delete(key);
722
761
  }
723
762
  function delayNotify(key, message) {
724
- clearTimeout(notifyTimer);
725
- notifyStarted = 0;
726
- notifyList.push({ key, message });
727
- if (!notifyStarted) {
728
- notifyStarted = 1;
729
- notifyTimer = setTimeout(doNotify, 500);
730
- }
763
+ if (warnedKeys.has(key)) return;
764
+ warnedKeys.add(key);
765
+ console.warn(message);
731
766
  }
732
767
  var State = {
733
768
  /**
@@ -739,7 +774,7 @@ var State = {
739
774
  return safeguard(
740
775
  result,
741
776
  (dataKey) => {
742
- if (booted && has(dataWhereSet, dataKey) && dataWhereSet[dataKey] !== window.location.pathname) {
777
+ if (booted && hasOwnProperty(dataWhereSet, dataKey) && dataWhereSet[dataKey] !== window.location.pathname) {
743
778
  console.warn(
744
779
  `beware! You get state:"{State}.${dataKey}" where it set by page:${dataWhereSet[dataKey]}`
745
780
  );
@@ -760,7 +795,7 @@ var State = {
760
795
  * Set data to state.
761
796
  */
762
797
  set(data, excludes) {
763
- dataIsChanged = setData(data, appData, changedKeys, excludes || /* @__PURE__ */ new Set()) || dataIsChanged;
798
+ dataIsChanged = setData(data, appData, changedKeys, excludes || EMPTY_STRING_SET) || dataIsChanged;
764
799
  if (typeof window.__lark_Debug !== "undefined" && window.__lark_Debug && booted) {
765
800
  for (const p in data) {
766
801
  dataWhereSet[p] = window.location.pathname;
@@ -777,26 +812,19 @@ var State = {
777
812
  }
778
813
  if (dataIsChanged) {
779
814
  if (typeof window.__lark_Debug !== "undefined" && window.__lark_Debug) {
780
- for (const p in changedKeys) {
781
- if (has(changedKeys, p)) {
782
- clearNotify(p);
783
- }
815
+ for (const p of changedKeys) {
816
+ clearNotify(p);
784
817
  }
785
818
  }
786
819
  dataIsChanged = false;
787
- const keys2 = {};
788
- for (const k in changedKeys) {
789
- if (has(changedKeys, k)) {
790
- keys2[k] = 1;
791
- }
792
- }
820
+ const keys2 = changedKeys;
793
821
  stashedChangedKeys = keys2;
794
- changedKeys = {};
795
- emitter.fire(ROUTER_EVENTS.CHANGED, { keys: keys2 });
822
+ changedKeys = /* @__PURE__ */ new Set();
823
+ emitter.fire(RouterEvents.CHANGED, { keys: keys2 });
796
824
  }
797
825
  },
798
826
  /**
799
- * Get diff of what changed in last digest.
827
+ * Get the set of keys changed in the most recent digest.
800
828
  */
801
829
  diff() {
802
830
  return stashedChangedKeys;
@@ -854,6 +882,7 @@ var cachedDefaultPath;
854
882
  var cachedRewrite;
855
883
  var defaultTitle;
856
884
  var frameworkConfig;
885
+ var beforeEachGuards = [];
857
886
  function createEmptyLocation() {
858
887
  return {
859
888
  href: "",
@@ -1008,7 +1037,7 @@ var Router = {
1008
1037
  document.title = defaultTitle || document.title;
1009
1038
  }
1010
1039
  emitter2.fire(
1011
- ROUTER_EVENTS.CHANGED,
1040
+ RouterEvents.CHANGED,
1012
1041
  lastChanged
1013
1042
  );
1014
1043
  }
@@ -1041,16 +1070,16 @@ var Router = {
1041
1070
  }
1042
1071
  const lPath = lastLocation["path"] || "";
1043
1072
  const lParams = lastLocation["params"];
1044
- const lQuery = {};
1073
+ const lQuery = /* @__PURE__ */ new Set();
1045
1074
  for (const k in lastLocation.query["params"]) {
1046
- if (has(lastLocation.query["params"], k)) {
1047
- lQuery[k] = 1;
1075
+ if (hasOwnProperty(lastLocation.query["params"], k)) {
1076
+ lQuery.add(k);
1048
1077
  }
1049
1078
  }
1050
1079
  if (tPath) {
1051
- if (!has(window, "history")) {
1052
- for (const qKey in lQuery) {
1053
- if (has(lQuery, qKey) && !has(tParams, qKey)) {
1080
+ if (!hasOwnProperty(window, "history")) {
1081
+ for (const qKey of lQuery) {
1082
+ if (!hasOwnProperty(tParams, qKey)) {
1054
1083
  tParams[qKey] = "";
1055
1084
  }
1056
1085
  }
@@ -1059,14 +1088,17 @@ var Router = {
1059
1088
  tPath = lPath;
1060
1089
  tParams = assign({}, lParams, tParams);
1061
1090
  }
1062
- updateUrl(
1063
- tPath,
1064
- tParams,
1065
- lastLocation,
1066
- replace,
1067
- silentFlag,
1068
- lQuery
1069
- );
1091
+ updateUrl(tPath, tParams, lastLocation, replace, silentFlag, lQuery);
1092
+ },
1093
+ /**
1094
+ * Register an async-friendly navigation guard. See `RouterInterface.beforeEach`.
1095
+ */
1096
+ beforeEach(guard) {
1097
+ beforeEachGuards.push(guard);
1098
+ return () => {
1099
+ const idx = beforeEachGuards.indexOf(guard);
1100
+ if (idx !== -1) beforeEachGuards.splice(idx, 1);
1101
+ };
1070
1102
  },
1071
1103
  /**
1072
1104
  * Join multiple path segments into a single path.
@@ -1130,12 +1162,39 @@ var Router = {
1130
1162
  }
1131
1163
  };
1132
1164
  Router.fire(
1133
- ROUTER_EVENTS.CHANGE,
1165
+ RouterEvents.CHANGE,
1134
1166
  changeEvent
1135
1167
  );
1136
- if (!suspend && !changeEvent.p) {
1168
+ if (suspend || changeEvent.p) {
1169
+ return;
1170
+ }
1171
+ if (beforeEachGuards.length === 0) {
1137
1172
  changeEvent.resolve();
1173
+ return;
1138
1174
  }
1175
+ const from = lastLocation;
1176
+ const to = loc;
1177
+ const guards = beforeEachGuards.slice();
1178
+ let chain = Promise.resolve(true);
1179
+ for (const guard of guards) {
1180
+ chain = chain.then((prev) => {
1181
+ if (prev === false) return false;
1182
+ return guard(to, from);
1183
+ });
1184
+ }
1185
+ chain.then(
1186
+ (result) => {
1187
+ if (changeEvent.p) return;
1188
+ if (result === false) {
1189
+ changeEvent.reject();
1190
+ } else {
1191
+ changeEvent.resolve();
1192
+ }
1193
+ },
1194
+ () => {
1195
+ if (!changeEvent.p) changeEvent.reject();
1196
+ }
1197
+ );
1139
1198
  }
1140
1199
  };
1141
1200
  Router.notify = watchChange;
@@ -1143,7 +1202,7 @@ var Router = {
1143
1202
  window.addEventListener("popstate", watchChange);
1144
1203
  window.addEventListener("beforeunload", (domEvent) => {
1145
1204
  const data = {};
1146
- Router.fire(ROUTER_EVENTS.PAGE_UNLOAD, data);
1205
+ Router.fire(RouterEvents.PAGE_UNLOAD, data);
1147
1206
  const msg = data["msg"];
1148
1207
  if (msg) {
1149
1208
  domEvent.returnValue = msg;
@@ -1189,13 +1248,17 @@ function parseEventInfo(eventInfo) {
1189
1248
  }
1190
1249
  function findFrameInfo(current, eventType) {
1191
1250
  const eventInfos = [];
1192
- let begin = current;
1193
1251
  const info = current.getAttribute(`@${eventType}`);
1252
+ const hasSelectorEvents = !!selectorEvents[eventType];
1253
+ if (!info && !hasSelectorEvents) {
1254
+ return eventInfos;
1255
+ }
1256
+ let begin = current;
1194
1257
  let match;
1195
1258
  if (info) {
1196
1259
  match = parseEventInfo(info);
1197
1260
  }
1198
- if (match && !match.id || selectorEvents[eventType]) {
1261
+ if (match && !match.id || hasSelectorEvents) {
1199
1262
  let selectorFrameId = "#";
1200
1263
  let backtrace = 0;
1201
1264
  while (begin && begin !== document.body) {
@@ -1368,7 +1431,7 @@ var EventDelegator = {
1368
1431
  };
1369
1432
 
1370
1433
  // src/vdom.ts
1371
- var WrapMeta = {
1434
+ var wrapMeta = {
1372
1435
  option: [1, "<select multiple>"],
1373
1436
  thead: [1, "<table>"],
1374
1437
  col: [2, "<table><colgroup>"],
@@ -1380,9 +1443,9 @@ var WrapMeta = {
1380
1443
  math: [1, '<math xmlns="' + MATH_NS + '">'],
1381
1444
  _: [0, ""]
1382
1445
  };
1383
- WrapMeta["optgroup"] = WrapMeta["option"];
1384
- WrapMeta["tbody"] = WrapMeta["tfoot"] = WrapMeta["colgroup"] = WrapMeta["caption"] = WrapMeta["thead"];
1385
- WrapMeta["th"] = WrapMeta["td"];
1446
+ wrapMeta["optgroup"] = wrapMeta["option"];
1447
+ wrapMeta["tbody"] = wrapMeta["tfoot"] = wrapMeta["colgroup"] = wrapMeta["caption"] = wrapMeta["thead"];
1448
+ wrapMeta["th"] = wrapMeta["td"];
1386
1449
  var VDoc = document.implementation.createHTMLDocument("");
1387
1450
  var VBase = VDoc.createElement("base");
1388
1451
  VBase.href = document.location.href;
@@ -1393,16 +1456,12 @@ var VDomSpecials = {
1393
1456
  OPTION: ["selected"]
1394
1457
  };
1395
1458
  function vdomUnmountFrames(frame, node) {
1396
- if (node.nodeType === 1) {
1397
- const el = node;
1398
- const id = el.getAttribute("id");
1399
- if (id) {
1400
- frame.unmountZone(id);
1401
- const children = frame.children();
1402
- if (children.includes(id)) {
1403
- frame.unmountFrame(id);
1404
- }
1405
- }
1459
+ if (!(node instanceof Element)) return;
1460
+ const id = node.getAttribute("id");
1461
+ if (!id) return;
1462
+ frame.unmountZone(id);
1463
+ if (frame.children().includes(id)) {
1464
+ frame.unmountFrame(id);
1406
1465
  }
1407
1466
  }
1408
1467
  function vdomGetNode(html, refNode) {
@@ -1417,7 +1476,7 @@ function vdomGetNode(html, refNode) {
1417
1476
  const match = TAG_NAME_REGEXP.exec(html);
1418
1477
  tag = match ? match[1] : "";
1419
1478
  }
1420
- const wrap = WrapMeta[tag] || WrapMeta["_"];
1479
+ const wrap = wrapMeta[tag] || wrapMeta["_"];
1421
1480
  tmp.innerHTML = wrap[1] + html;
1422
1481
  let j = wrap[0];
1423
1482
  while (j--) {
@@ -1434,7 +1493,7 @@ function vdomGetCompareKey(node) {
1434
1493
  }
1435
1494
  let key = el.autoId ? "" : el.getAttribute("id") || void 0;
1436
1495
  if (!key) {
1437
- key = el.getAttribute(LARK_KEYS.DIFF_KEY) || void 0;
1496
+ key = el.getAttribute(LarkInnerKeys.DIFF_KEY) || void 0;
1438
1497
  }
1439
1498
  if (!key) {
1440
1499
  const larkView = el.getAttribute(LARK_VIEW);
@@ -1447,8 +1506,7 @@ function vdomGetCompareKey(node) {
1447
1506
  return key;
1448
1507
  }
1449
1508
  function vdomSpecialDiff(oldNode, newNode) {
1450
- const nodeName = oldNode.nodeName;
1451
- const specials = VDomSpecials[nodeName];
1509
+ const specials = VDomSpecials[oldNode.nodeName];
1452
1510
  if (!specials) return 0;
1453
1511
  const oldEl = oldNode;
1454
1512
  const newEl = newNode;
@@ -1497,13 +1555,17 @@ function vdomSetChildNodes(oldParent, newParent, ref, frame, keys_) {
1497
1555
  let oldNode = oldParent.lastChild;
1498
1556
  let newNode = newParent.firstChild;
1499
1557
  let extra = 0;
1500
- const keyedNodes = {};
1501
- const newKeyedNodes = {};
1558
+ const keyedNodes = /* @__PURE__ */ new Map();
1559
+ const newKeyedNodes = /* @__PURE__ */ new Map();
1502
1560
  while (oldNode) {
1503
1561
  extra++;
1504
1562
  const nodeKey = vdomGetCompareKey(oldNode);
1505
1563
  if (nodeKey) {
1506
- const bucket = keyedNodes[nodeKey] || (keyedNodes[nodeKey] = []);
1564
+ let bucket = keyedNodes.get(nodeKey);
1565
+ if (!bucket) {
1566
+ bucket = [];
1567
+ keyedNodes.set(nodeKey, bucket);
1568
+ }
1507
1569
  bucket.push(oldNode);
1508
1570
  }
1509
1571
  oldNode = oldNode.previousSibling;
@@ -1511,7 +1573,7 @@ function vdomSetChildNodes(oldParent, newParent, ref, frame, keys_) {
1511
1573
  while (newNode) {
1512
1574
  const nodeKey = vdomGetCompareKey(newNode);
1513
1575
  if (nodeKey) {
1514
- newKeyedNodes[nodeKey] = (newKeyedNodes[nodeKey] || 0) + 1;
1576
+ newKeyedNodes.set(nodeKey, (newKeyedNodes.get(nodeKey) ?? 0) + 1);
1515
1577
  }
1516
1578
  newNode = newNode.nextSibling;
1517
1579
  }
@@ -1522,23 +1584,25 @@ function vdomSetChildNodes(oldParent, newParent, ref, frame, keys_) {
1522
1584
  const tempNew = newNode;
1523
1585
  newNode = newNode.nextSibling;
1524
1586
  const nodeKey = vdomGetCompareKey(tempNew);
1525
- let foundNode = nodeKey ? keyedNodes[nodeKey] : void 0;
1587
+ let foundNode = nodeKey ? keyedNodes.get(nodeKey) : void 0;
1526
1588
  if (foundNode && (foundNode = foundNode.slice()) && foundNode.length) {
1527
1589
  const matched = foundNode.pop();
1528
1590
  while (matched !== oldNode) {
1529
- const next = oldNode?.nextSibling ?? null;
1591
+ if (!oldNode) break;
1592
+ const next = oldNode.nextSibling;
1530
1593
  oldParent.appendChild(oldNode);
1531
1594
  oldNode = next;
1532
1595
  }
1533
1596
  oldNode = matched.nextSibling;
1534
- if (nodeKey && newKeyedNodes[nodeKey]) {
1535
- newKeyedNodes[nodeKey]--;
1597
+ if (nodeKey) {
1598
+ const c = newKeyedNodes.get(nodeKey);
1599
+ if (c) newKeyedNodes.set(nodeKey, c - 1);
1536
1600
  }
1537
1601
  vdomSetNode(matched, tempNew, oldParent, ref, frame, keys_);
1538
1602
  } else if (oldNode) {
1539
1603
  const tempOld2 = oldNode;
1540
1604
  const oldKey = vdomGetCompareKey(tempOld2);
1541
- if (oldKey && keyedNodes[oldKey] && newKeyedNodes[oldKey]) {
1605
+ if (oldKey && keyedNodes.has(oldKey) && newKeyedNodes.get(oldKey)) {
1542
1606
  extra++;
1543
1607
  ref.hasChanged = 1;
1544
1608
  ref.domOps.push([8, oldParent, tempNew, tempOld2]);
@@ -1562,17 +1626,21 @@ function vdomSetChildNodes(oldParent, newParent, ref, frame, keys_) {
1562
1626
  }
1563
1627
  }
1564
1628
  function vdomSetNode(oldNode, newNode, oldParent, ref, frame, keys_) {
1565
- if (vdomSpecialDiff(oldNode, newNode) || oldNode.nodeType === 1 && oldNode.hasAttribute(LARK_KEYS.VIEW_KEY) || !(oldNode.isEqualNode && oldNode.isEqualNode(newNode))) {
1629
+ const oldAsEl = oldNode instanceof Element ? oldNode : null;
1630
+ const newAsEl = newNode instanceof Element ? newNode : null;
1631
+ const hasViewKey = !!oldAsEl?.hasAttribute(LarkInnerKeys.VIEW_KEY);
1632
+ const equalAsNodes = oldAsEl !== null && newAsEl !== null && oldAsEl.isEqualNode && oldAsEl.isEqualNode(newAsEl);
1633
+ if (vdomSpecialDiff(oldNode, newNode) || hasViewKey || !equalAsNodes) {
1566
1634
  if (oldNode.nodeType === newNode.nodeType && oldNode.nodeName === newNode.nodeName) {
1567
- if (oldNode.nodeType === 1) {
1568
- const oldEl = oldNode;
1569
- const newEl = newNode;
1570
- const staticKey = newEl.getAttribute(LARK_KEYS.DIFF_KEY);
1571
- if (staticKey && staticKey === oldEl.getAttribute(LARK_KEYS.DIFF_KEY)) {
1635
+ if (oldAsEl !== null && newAsEl !== null) {
1636
+ const oldEl = oldAsEl;
1637
+ const newEl = newAsEl;
1638
+ const staticKey = newEl.getAttribute(LarkInnerKeys.DIFF_KEY);
1639
+ if (staticKey && staticKey === oldEl.getAttribute(LarkInnerKeys.DIFF_KEY)) {
1572
1640
  return;
1573
1641
  }
1574
1642
  const newLarkView = newEl.getAttribute(LARK_VIEW);
1575
- const updateAttribute = !newEl.getAttribute(LARK_KEYS.ATTR_KEY) || newEl.getAttribute(LARK_KEYS.ATTR_KEY) !== oldEl.getAttribute(LARK_KEYS.ATTR_KEY);
1643
+ const updateAttribute = !newEl.getAttribute(LarkInnerKeys.ATTR_KEY) || newEl.getAttribute(LarkInnerKeys.ATTR_KEY) !== oldEl.getAttribute(LarkInnerKeys.ATTR_KEY);
1576
1644
  let updateChildren = true;
1577
1645
  if (newLarkView) {
1578
1646
  const oldFrameId = oldEl.getAttribute("id") || "";
@@ -1673,7 +1741,8 @@ function encodeQ(v) {
1673
1741
  }
1674
1742
 
1675
1743
  // src/updater.ts
1676
- function updaterRef(refData, value, key) {
1744
+ function updaterRef(refDataIn, value, key) {
1745
+ const refData = refDataIn;
1677
1746
  const counter = refData[SPLITTER];
1678
1747
  for (let i = counter; --i; ) {
1679
1748
  key = SPLITTER + i;
@@ -1693,13 +1762,19 @@ var Updater = class {
1693
1762
  /** Ref data for template rendering */
1694
1763
  refData;
1695
1764
  /** Changed keys in current digest cycle */
1696
- changedKeys = {};
1765
+ changedKeys = /* @__PURE__ */ new Set();
1697
1766
  /** Whether data has changed since last digest */
1698
1767
  hasChangedFlag = 0;
1699
- /** Digesting queue: supports re-digest during digest */
1768
+ /**
1769
+ * Digesting queue: supports re-digest during digest.
1770
+ * Holds pending callbacks; `null` is used as a sentinel marking the start
1771
+ * of an active digest cycle, so `runDigest` can detect re-entrant calls.
1772
+ */
1700
1773
  digestingQueue = [];
1701
- /** Snapshot JSON string for altered() detection */
1702
- snapshotJson;
1774
+ /** Monotonically increasing version, bumped each time data actually changes. */
1775
+ version = 0;
1776
+ /** Snapshot of `version` taken by `snapshot()`, used by `altered()`. */
1777
+ snapshotVersion;
1703
1778
  constructor(viewId) {
1704
1779
  this.viewId = viewId;
1705
1780
  this.data = { vId: viewId };
@@ -1727,7 +1802,16 @@ var Updater = class {
1727
1802
  * Returns this for chaining.
1728
1803
  */
1729
1804
  set(data, excludes) {
1730
- this.hasChangedFlag = setData(data, this.data, this.changedKeys, excludes || /* @__PURE__ */ new Set()) || this.hasChangedFlag ? 1 : 0;
1805
+ const changed = setData(
1806
+ data,
1807
+ this.data,
1808
+ this.changedKeys,
1809
+ excludes || EMPTY_STRING_SET
1810
+ );
1811
+ if (changed) {
1812
+ this.version++;
1813
+ this.hasChangedFlag = 1;
1814
+ }
1731
1815
  return this;
1732
1816
  }
1733
1817
  /**
@@ -1763,13 +1847,13 @@ var Updater = class {
1763
1847
  const keys2 = this.changedKeys;
1764
1848
  const changed = this.hasChangedFlag;
1765
1849
  this.hasChangedFlag = 0;
1766
- this.changedKeys = {};
1850
+ this.changedKeys = /* @__PURE__ */ new Set();
1767
1851
  const frame = Frame.get(this.viewId);
1768
1852
  const view = frame?.view;
1769
1853
  const node = getById(this.viewId);
1770
- if (changed && view && node && view.signature > 0) {
1854
+ if (changed && view && node && view.signature > 0 && frame) {
1771
1855
  const template = view.template;
1772
- if (template && typeof template === "function") {
1856
+ if (typeof template === "function") {
1773
1857
  const html = template(
1774
1858
  this.data,
1775
1859
  this.viewId,
@@ -1806,43 +1890,65 @@ var Updater = class {
1806
1890
  }
1807
1891
  }
1808
1892
  /**
1809
- * Save a snapshot of current data for altered() detection.
1893
+ * Save a snapshot of the current data version for `altered()` detection.
1894
+ * Cheap O(1) — records the current monotonic version, no serialization.
1810
1895
  */
1811
1896
  snapshot() {
1812
- this.snapshotJson = JSON.stringify(this.data);
1897
+ this.snapshotVersion = this.version;
1813
1898
  return this;
1814
1899
  }
1815
1900
  /**
1816
- * Check if data has changed since last snapshot.
1901
+ * Check whether data has changed since the last snapshot.
1902
+ * Returns undefined when no snapshot has been taken yet.
1817
1903
  */
1818
1904
  altered() {
1819
- if (this.snapshotJson) {
1820
- return this.snapshotJson !== JSON.stringify(this.data);
1821
- }
1822
- return void 0;
1905
+ if (this.snapshotVersion === void 0) return void 0;
1906
+ return this.version !== this.snapshotVersion;
1823
1907
  }
1824
1908
  /**
1825
- * Translate data references (SPLITTER-prefixed values).
1909
+ * Translate a refData reference back to its original value.
1910
+ *
1911
+ * The ref protocol is `SPLITTER` + ascii decimal digits — the exact format
1912
+ * emitted by `updaterRef`. We require that exact shape so a user-supplied
1913
+ * string that merely begins with SPLITTER is never accidentally resolved
1914
+ * (or mishandled as a "missing ref").
1826
1915
  */
1827
1916
  translate(data) {
1828
- if (typeof data === "string" && data[0] === SPLITTER) {
1829
- return has(this.refData, data) ? this.refData[data] : data;
1917
+ if (typeof data !== "string") return data;
1918
+ if (data.length < 2 || data[0] !== SPLITTER) return data;
1919
+ for (let i = 1; i < data.length; i++) {
1920
+ const c = data.charCodeAt(i);
1921
+ if (c < 48 || c > 57) return data;
1830
1922
  }
1831
- return data;
1923
+ return hasOwnProperty(this.refData, data) ? this.refData[data] : data;
1832
1924
  }
1833
1925
  /**
1834
- * Parse expression with data context.
1926
+ * Resolve a dotted property path against refData.
1927
+ *
1928
+ * Only safe property-path syntax is supported: `a`, `a.b`, `a.b.c`.
1929
+ * Numeric literals (e.g. `1`, `1.5`) are returned as numbers. Anything else
1930
+ * returns `undefined` — we no longer evaluate arbitrary JavaScript via
1931
+ * `new Function`, so the method is CSP-safe and cannot be used as an
1932
+ * injection vector.
1835
1933
  */
1836
1934
  parse(expr) {
1837
- try {
1838
- const fn = new Function("data", `with(data) { return ${expr}; }`);
1839
- return fn(this.refData);
1840
- } catch {
1935
+ const trimmed = expr.trim();
1936
+ if (!trimmed) return void 0;
1937
+ if (/^-?\d+(?:\.\d+)?$/.test(trimmed)) {
1938
+ return Number(trimmed);
1939
+ }
1940
+ if (!/^[A-Za-z_$][\w$]*(?:\.[A-Za-z_$][\w$]*)*$/.test(trimmed)) {
1841
1941
  return void 0;
1842
1942
  }
1943
+ let cur = this.refData;
1944
+ for (const segment of trimmed.split(".")) {
1945
+ if (cur == null || typeof cur !== "object") return void 0;
1946
+ cur = cur[segment];
1947
+ }
1948
+ return cur;
1843
1949
  }
1844
1950
  /**
1845
- * Get changed keys (for external inspection).
1951
+ * Get the set of keys changed since the last digest (for external inspection).
1846
1952
  */
1847
1953
  getChangedKeys() {
1848
1954
  return this.changedKeys;
@@ -1889,30 +1995,31 @@ var View = class _View {
1889
1995
  // ============================================================
1890
1996
  // Getters for prototype-stored event maps
1891
1997
  // ============================================================
1998
+ /** Prototype-stored event maps shape (set by View.prepare). */
1999
+ get protoEventState() {
2000
+ return Object.getPrototypeOf(this);
2001
+ }
1892
2002
  /**
1893
2003
  * Event bitmask map: eventType -> bitmask (1=root, 2=selector).
1894
2004
  * Read from prototype ($evtObjMap) set by View.prepare.
1895
2005
  * Using a getter avoids ES6 class field shadowing the prototype value.
1896
2006
  */
1897
2007
  get eventObjectMap() {
1898
- const proto = Object.getPrototypeOf(this);
1899
- return proto["$evtObjMap"] || {};
2008
+ return this.protoEventState.$evtObjMap ?? {};
1900
2009
  }
1901
2010
  /**
1902
2011
  * Selector event map: eventType -> selector list.
1903
2012
  * Read from prototype ($selMap) set by View.prepare.
1904
2013
  */
1905
2014
  get eventSelectorMap() {
1906
- const proto = Object.getPrototypeOf(this);
1907
- return proto["$selMap"] || {};
2015
+ return this.protoEventState.$selMap ?? {};
1908
2016
  }
1909
2017
  /**
1910
2018
  * Global event list: [{handler, element, eventName, modifiers}].
1911
2019
  * Read from prototype ($globalEvtList) set by View.prepare.
1912
2020
  */
1913
2021
  get globalEventList() {
1914
- const proto = Object.getPrototypeOf(this);
1915
- return proto["$globalEvtList"] || [];
2022
+ return this.protoEventState.$globalEvtList ?? [];
1916
2023
  }
1917
2024
  // ============================================================
1918
2025
  // Instance lifecycle methods
@@ -1947,13 +2054,17 @@ var View = class _View {
1947
2054
  // ============================================================
1948
2055
  // Update methods
1949
2056
  // ============================================================
2057
+ /** Get the owning frame, asserting it has been bound. */
2058
+ get ownerFrame() {
2059
+ return this.owner;
2060
+ }
1950
2061
  /**
1951
2062
  * Notify view that HTML update is about to begin.
1952
2063
  * Unmounts child frames in the update zone.
1953
2064
  */
1954
2065
  beginUpdate(id) {
1955
2066
  if (this.signature > 0 && this.endUpdatePending !== void 0) {
1956
- this.owner.unmountZone(id, true);
2067
+ this.ownerFrame.unmountZone(id, true);
1957
2068
  }
1958
2069
  }
1959
2070
  /**
@@ -1971,7 +2082,7 @@ var View = class _View {
1971
2082
  this.endUpdatePending = 1;
1972
2083
  this.rendered = true;
1973
2084
  }
1974
- const ownerFrame = this.owner;
2085
+ const ownerFrame = this.ownerFrame;
1975
2086
  ownerFrame.mountZone(updateId, inner);
1976
2087
  if (!flag) {
1977
2088
  setTimeout(
@@ -2010,11 +2121,12 @@ var View = class _View {
2010
2121
  const loc = this.locationObserved;
2011
2122
  loc.flag = 1;
2012
2123
  if (typeof params === "object" && !Array.isArray(params)) {
2013
- if (params["path"]) {
2124
+ const opts = params;
2125
+ if (opts["path"]) {
2014
2126
  observePath = true;
2015
2127
  }
2016
- const paramKeys = params["params"];
2017
- if (paramKeys) {
2128
+ const paramKeys = opts["params"];
2129
+ if (typeof paramKeys === "string" || Array.isArray(paramKeys)) {
2018
2130
  params = paramKeys;
2019
2131
  }
2020
2132
  }
@@ -2078,24 +2190,16 @@ var View = class _View {
2078
2190
  */
2079
2191
  leaveTip(message, condition) {
2080
2192
  const changeListener = function(e) {
2081
- const isRouterChange = e.type === ROUTER_EVENTS.CHANGE;
2193
+ const isRouterChange = e.type === RouterEvents.CHANGE;
2082
2194
  const aKey = isRouterChange ? "a" : "b";
2083
2195
  const bKey = isRouterChange ? "b" : "a";
2084
2196
  if (changeListener[aKey]) {
2085
- if (typeof e.prevent === "function") {
2086
- e.prevent();
2087
- }
2088
- if (typeof e.reject === "function") {
2089
- e.reject();
2090
- }
2197
+ e.prevent?.();
2198
+ e.reject?.();
2091
2199
  } else if (condition()) {
2092
- if (typeof e.prevent === "function") {
2093
- e.prevent();
2094
- }
2200
+ e.prevent?.();
2095
2201
  changeListener[bKey] = 1;
2096
- if (typeof e.resolve === "function") {
2097
- e.resolve();
2098
- }
2202
+ e.resolve?.();
2099
2203
  }
2100
2204
  };
2101
2205
  const unloadListener = (e) => {
@@ -2103,14 +2207,12 @@ var View = class _View {
2103
2207
  e["msg"] = message;
2104
2208
  }
2105
2209
  };
2106
- const changeFn = changeListener;
2107
- const unloadFn = unloadListener;
2108
- Router.on(ROUTER_EVENTS.CHANGE, changeFn);
2109
- Router.on(ROUTER_EVENTS.PAGE_UNLOAD, unloadFn);
2110
- this.on("unload", changeFn);
2210
+ Router.on(RouterEvents.CHANGE, changeListener);
2211
+ Router.on(RouterEvents.PAGE_UNLOAD, unloadListener);
2212
+ this.on("unload", changeListener);
2111
2213
  this.on("destroy", () => {
2112
- Router.off(ROUTER_EVENTS.CHANGE, changeFn);
2113
- Router.off(ROUTER_EVENTS.PAGE_UNLOAD, unloadFn);
2214
+ Router.off(RouterEvents.CHANGE, changeListener);
2215
+ Router.off(RouterEvents.PAGE_UNLOAD, unloadListener);
2114
2216
  });
2115
2217
  }
2116
2218
  // ============================================================
@@ -2140,7 +2242,7 @@ var View = class _View {
2140
2242
  _View.mergeMixins(mixins, oView, ctors);
2141
2243
  }
2142
2244
  for (const p in proto) {
2143
- if (!has(proto, p)) continue;
2245
+ if (!hasOwnProperty(proto, p)) continue;
2144
2246
  const currentFn = proto[p];
2145
2247
  if (typeof currentFn !== "function") continue;
2146
2248
  const matches = p.match(VIEW_EVENT_METHOD_REGEXP);
@@ -2186,16 +2288,16 @@ var View = class _View {
2186
2288
  const existingFn = proto[combinedKey];
2187
2289
  if (!existingFn) {
2188
2290
  proto[combinedKey] = currentFn;
2189
- } else {
2291
+ } else if (typeof existingFn === "function") {
2190
2292
  const mixinFn = currentFn;
2191
2293
  const existingMixin = existingFn;
2192
2294
  if (existingMixin.marker) {
2193
2295
  if (mixinFn.marker) {
2194
2296
  proto[combinedKey] = _View.processMixinsSameEvent(
2195
- currentFn,
2196
- existingFn
2297
+ mixinFn,
2298
+ existingMixin
2197
2299
  );
2198
- } else if (has(proto, p)) {
2300
+ } else if (hasOwnProperty(proto, p)) {
2199
2301
  proto[combinedKey] = currentFn;
2200
2302
  }
2201
2303
  }
@@ -2218,7 +2320,7 @@ var View = class _View {
2218
2320
  const selectorObject = view.eventSelectorMap;
2219
2321
  const eventsList = view.globalEventList;
2220
2322
  for (const e in eventsObject) {
2221
- if (has(eventsObject, e)) {
2323
+ if (hasOwnProperty(eventsObject, e)) {
2222
2324
  if (destroy) {
2223
2325
  EventDelegator.unbind(e, !!selectorObject[e]);
2224
2326
  } else {
@@ -2261,7 +2363,7 @@ var View = class _View {
2261
2363
  static destroyAllResources(view, lastly) {
2262
2364
  const cache = view.resources;
2263
2365
  for (const p in cache) {
2264
- if (has(cache, p)) {
2366
+ if (hasOwnProperty(cache, p)) {
2265
2367
  const entry = cache[p];
2266
2368
  if (lastly || entry.destroyOnRender) {
2267
2369
  _View.destroyResource(cache, p, true);
@@ -2291,13 +2393,16 @@ var View = class _View {
2291
2393
  static wrapMethod(proto, fnName, shortKey) {
2292
2394
  const originalFn = proto[fnName];
2293
2395
  if (typeof originalFn !== "function") return;
2396
+ const originalAsFn = originalFn;
2294
2397
  const wrapped = function(...args) {
2295
2398
  if (this.signature > 0) {
2296
2399
  this.signature++;
2297
2400
  this.fire("render");
2298
2401
  _View.destroyAllResources(this, false);
2299
- const instanceFn = typeof this[fnName] === "function" ? this[fnName] : originalFn;
2300
- const fnToCall = instanceFn === wrapped ? originalFn : instanceFn;
2402
+ const lookup = this;
2403
+ const candidate = lookup[fnName];
2404
+ const instanceFn = typeof candidate === "function" ? candidate : originalAsFn;
2405
+ const fnToCall = instanceFn === wrapped ? originalAsFn : instanceFn;
2301
2406
  return funcWithTry(fnToCall, args, this, noop);
2302
2407
  }
2303
2408
  return void 0;
@@ -2311,19 +2416,18 @@ var View = class _View {
2311
2416
  */
2312
2417
  static processMixinsSameEvent(additional, exist) {
2313
2418
  let temp;
2314
- const existMixin = exist;
2315
- if (existMixin.handlerList) {
2316
- temp = existMixin;
2419
+ if (exist.handlerList) {
2420
+ temp = exist;
2317
2421
  } else {
2318
- temp = function(...e) {
2319
- funcWithTry(temp.handlerList ?? [], e, this, noop);
2422
+ const merged = function(...e) {
2423
+ funcWithTry(merged.handlerList ?? [], e, this, noop);
2320
2424
  };
2321
- temp.handlerList = [exist];
2322
- temp.marker = 1;
2425
+ merged.handlerList = [exist];
2426
+ merged.marker = 1;
2427
+ temp = merged;
2323
2428
  }
2324
- const additionalMixin = additional;
2325
2429
  temp.handlerList = (temp.handlerList ?? []).concat(
2326
- additionalMixin.handlerList ?? [additional]
2430
+ additional.handlerList ?? [additional]
2327
2431
  );
2328
2432
  return temp;
2329
2433
  }
@@ -2335,29 +2439,29 @@ var View = class _View {
2335
2439
  const temp = {};
2336
2440
  for (const node of mixins) {
2337
2441
  for (const p in node) {
2338
- if (!has(node, p)) continue;
2442
+ if (!hasOwnProperty(node, p)) continue;
2339
2443
  const fn = node[p];
2444
+ if (typeof fn !== "function") continue;
2445
+ const mixinFn = fn;
2340
2446
  const exist = temp[p];
2341
2447
  if (p === "make") {
2342
- ctors.push(fn);
2448
+ ctors.push(mixinFn);
2343
2449
  continue;
2344
2450
  }
2345
2451
  if (VIEW_EVENT_METHOD_REGEXP.test(p)) {
2346
2452
  if (exist) {
2347
- temp[p] = _View.processMixinsSameEvent(fn, exist);
2453
+ temp[p] = _View.processMixinsSameEvent(mixinFn, exist);
2348
2454
  } else {
2349
- fn.marker = 1;
2350
- temp[p] = fn;
2351
- }
2352
- } else {
2353
- if (!exist) {
2354
- temp[p] = fn;
2455
+ mixinFn.marker = 1;
2456
+ temp[p] = mixinFn;
2355
2457
  }
2458
+ } else if (!exist) {
2459
+ temp[p] = mixinFn;
2356
2460
  }
2357
2461
  }
2358
2462
  }
2359
2463
  for (const p in temp) {
2360
- if (!has(proto, p)) {
2464
+ if (!hasOwnProperty(proto, p)) {
2361
2465
  proto[p] = temp[p];
2362
2466
  }
2363
2467
  }
@@ -2390,19 +2494,20 @@ var View = class _View {
2390
2494
  * - Event method patterns: `'name<click>'` etc.
2391
2495
  */
2392
2496
  static extend(props, statics) {
2393
- props = props || {};
2394
- const make = props["make"];
2497
+ const definedProps = props ?? {};
2498
+ const make = definedProps["make"];
2395
2499
  const ctors = [];
2396
- if (make) {
2500
+ if (typeof make === "function") {
2397
2501
  ctors.push(make);
2398
2502
  }
2399
2503
  const ParentView = this;
2400
2504
  const ChildView = class extends ParentView {
2401
2505
  constructor(nodeId, ownerFrame, initParams, node, mixinCtors) {
2402
2506
  super(nodeId, ownerFrame, initParams, node, []);
2403
- for (const key in props) {
2404
- if (has(props, key) && key !== "make" && key !== "render") {
2405
- this[key] = props[key];
2507
+ const instanceProps = this;
2508
+ for (const key in definedProps) {
2509
+ if (hasOwnProperty(definedProps, key) && key !== "make" && key !== "render") {
2510
+ instanceProps[key] = definedProps[key];
2406
2511
  }
2407
2512
  }
2408
2513
  this.id = nodeId;
@@ -2422,15 +2527,16 @@ var View = class _View {
2422
2527
  }
2423
2528
  };
2424
2529
  const proto = ChildView.prototype;
2425
- for (const key in props) {
2426
- if (has(props, key) && key !== "make") {
2427
- proto[key] = props[key];
2530
+ for (const key in definedProps) {
2531
+ if (hasOwnProperty(definedProps, key) && key !== "make") {
2532
+ proto[key] = definedProps[key];
2428
2533
  }
2429
2534
  }
2430
2535
  if (statics) {
2536
+ const staticTarget = ChildView;
2431
2537
  for (const key in statics) {
2432
- if (has(statics, key)) {
2433
- ChildView[key] = statics[key];
2538
+ if (hasOwnProperty(statics, key)) {
2539
+ staticTarget[key] = statics[key];
2434
2540
  }
2435
2541
  }
2436
2542
  }
@@ -2445,14 +2551,86 @@ var View = class _View {
2445
2551
  return this;
2446
2552
  }
2447
2553
  };
2554
+ function defineView(props, statics) {
2555
+ return View.extend(props, statics);
2556
+ }
2557
+
2558
+ // src/module-loader.ts
2559
+ var config = {
2560
+ rootId: "root",
2561
+ hashbang: "#!",
2562
+ error: (error) => {
2563
+ throw error;
2564
+ }
2565
+ };
2566
+ function use(names, callback) {
2567
+ const nameList = typeof names === "string" ? [names] : names;
2568
+ const loadPromise = (() => {
2569
+ if (config.require) {
2570
+ const result = config.require(nameList);
2571
+ if (result && typeof result.then === "function") {
2572
+ return result;
2573
+ }
2574
+ return Promise.resolve([]);
2575
+ }
2576
+ return Promise.all(
2577
+ nameList.map((name) => {
2578
+ const importPath = name.startsWith(".") || name.startsWith("/") ? name : `./${name}`;
2579
+ return import(
2580
+ /* @vite-ignore */
2581
+ /* webpackIgnore: true */
2582
+ importPath
2583
+ ).then((mod) => {
2584
+ return mod && (mod["__esModule"] || // For Webpack
2585
+ typeof mod["default"] === "function") ? mod["default"] : mod;
2586
+ }).catch((err) => {
2587
+ const errorHandler = config.error;
2588
+ if (errorHandler) {
2589
+ errorHandler(err instanceof Error ? err : new Error(String(err)));
2590
+ }
2591
+ return void 0;
2592
+ });
2593
+ })
2594
+ );
2595
+ })();
2596
+ if (callback) {
2597
+ loadPromise.then((modules) => {
2598
+ callback(...modules);
2599
+ });
2600
+ }
2601
+ return loadPromise;
2602
+ }
2603
+
2604
+ // src/view-registry.ts
2605
+ var viewClassRegistry = {};
2606
+ function getViewClass(path) {
2607
+ return viewClassRegistry[path];
2608
+ }
2609
+ function registerViewClass(viewPath, ViewClass) {
2610
+ const parsed = parseUri(viewPath);
2611
+ const path = parsed.path;
2612
+ if (path) {
2613
+ viewClassRegistry[path] = ViewClass;
2614
+ }
2615
+ }
2616
+ function invalidateViewClass(viewPath) {
2617
+ const parsed = parseUri(viewPath);
2618
+ const path = parsed.path;
2619
+ if (path) {
2620
+ Reflect.deleteProperty(viewClassRegistry, path);
2621
+ }
2622
+ }
2623
+ function getViewClassRegistry() {
2624
+ return viewClassRegistry;
2625
+ }
2448
2626
 
2449
2627
  // src/frame.ts
2450
2628
  var frameRegistry = /* @__PURE__ */ new Map();
2451
2629
  var rootFrame;
2452
2630
  var globalAlter;
2631
+ var MAX_FRAME_POOL = 64;
2453
2632
  var frameCache = [];
2454
2633
  var staticEmitter = new EventEmitter();
2455
- var viewClassRegistry = {};
2456
2634
  var Frame = class _Frame extends EventEmitter {
2457
2635
  /** Frame ID (same as owner DOM element ID) */
2458
2636
  id;
@@ -2467,8 +2645,8 @@ var Frame = class _Frame extends EventEmitter {
2467
2645
  childrenCount = 0;
2468
2646
  /** Ready count (children that have fired 'created') */
2469
2647
  readyCount = 0;
2470
- /** Ready map: id -> 1 */
2471
- readyMap = {};
2648
+ /** Set of child frame IDs that have fired 'created' */
2649
+ readyMap = /* @__PURE__ */ new Set();
2472
2650
  /** View instance */
2473
2651
  viewInstance;
2474
2652
  /** Get view instance (read-only) */
@@ -2539,13 +2717,30 @@ var Frame = class _Frame extends EventEmitter {
2539
2717
  this.viewPath = viewPath;
2540
2718
  const params = parsed["params"];
2541
2719
  translateQuery(pId || this.id, viewPath, params);
2720
+ const initParams = { ...params };
2542
2721
  if (viewInitParams) {
2543
- assign(params, viewInitParams);
2722
+ assign(initParams, viewInitParams);
2544
2723
  }
2545
2724
  const sign = this.signature;
2546
- if (viewClassRegistry[viewClassName]) {
2547
- this.doMountView(viewClassRegistry[viewClassName], params, node, sign);
2725
+ const registered = getViewClass(viewClassName);
2726
+ if (registered) {
2727
+ this.doMountView(registered, initParams, node, sign);
2728
+ return;
2548
2729
  }
2730
+ use(viewClassName, (ViewClass) => {
2731
+ if (sign !== this.signature) return;
2732
+ if (typeof ViewClass === "function") {
2733
+ const ViewClassTyped = ViewClass;
2734
+ registerViewClass(viewClassName, ViewClassTyped);
2735
+ this.doMountView(ViewClassTyped, initParams, node, sign);
2736
+ } else {
2737
+ const error = new Error(`Cannot load view: ${viewClassName}`);
2738
+ const errorHandler = config.error;
2739
+ if (errorHandler) {
2740
+ errorHandler(error);
2741
+ }
2742
+ }
2743
+ });
2549
2744
  }
2550
2745
  /**
2551
2746
  * Internal: actually mount the view after class is loaded.
@@ -2553,14 +2748,8 @@ var Frame = class _Frame extends EventEmitter {
2553
2748
  doMountView(ViewClass, params, node, sign) {
2554
2749
  if (sign !== this.signature) return;
2555
2750
  const mixinCtors = View.prepare(ViewClass);
2556
- const ViewConstructor = ViewClass;
2557
- const view = new ViewConstructor(
2558
- this.id,
2559
- this,
2560
- params,
2561
- node,
2562
- mixinCtors
2563
- );
2751
+ const Ctor = ViewClass;
2752
+ const view = new Ctor(this.id, this, params, node, mixinCtors);
2564
2753
  this.viewInstance = view;
2565
2754
  view.signature = 1;
2566
2755
  View.delegateEvents(view);
@@ -2641,7 +2830,9 @@ var Frame = class _Frame extends EventEmitter {
2641
2830
  frame.unmountView();
2642
2831
  removeFrame(targetId, wasCreated);
2643
2832
  reInitFrameForCache(frame);
2644
- frameCache.push(frame);
2833
+ if (frameCache.length < MAX_FRAME_POOL) {
2834
+ frameCache.push(frame);
2835
+ }
2645
2836
  const parent = frameRegistry.get(pId || "");
2646
2837
  if (parent && parent.childrenMap[targetId]) {
2647
2838
  Reflect.deleteProperty(parent.childrenMap, targetId);
@@ -2660,13 +2851,12 @@ var Frame = class _Frame extends EventEmitter {
2660
2851
  const viewElements = rootEl.querySelectorAll(`[${LARK_VIEW}]`);
2661
2852
  const frames = [];
2662
2853
  viewElements.forEach((el) => {
2663
- const htmlEl = el;
2664
- if (!htmlEl.frameBound) {
2665
- const elId = ensureElementId2(htmlEl);
2666
- htmlEl.frameBound = 1;
2667
- const viewPath = getAttribute(htmlEl, LARK_VIEW);
2668
- frames.push([elId, viewPath]);
2669
- }
2854
+ if (!(el instanceof HTMLElement)) return;
2855
+ if (htmlElIsBound(el)) return;
2856
+ const elId = ensureElementId2(el);
2857
+ el.frameBound = 1;
2858
+ const viewPath = getAttribute(el, LARK_VIEW);
2859
+ frames.push([elId, viewPath]);
2670
2860
  });
2671
2861
  for (const [frameId, viewPath] of frames) {
2672
2862
  this.mountFrame(frameId, viewPath);
@@ -2679,7 +2869,7 @@ var Frame = class _Frame extends EventEmitter {
2679
2869
  */
2680
2870
  unmountZone(zoneId, _inner) {
2681
2871
  for (const childId in this.childrenMap) {
2682
- if (has(this.childrenMap, childId)) {
2872
+ if (hasOwnProperty(this.childrenMap, childId)) {
2683
2873
  if (!zoneId || childId !== zoneId) {
2684
2874
  this.unmountFrame(childId);
2685
2875
  }
@@ -2693,7 +2883,7 @@ var Frame = class _Frame extends EventEmitter {
2693
2883
  children() {
2694
2884
  const result = [];
2695
2885
  for (const id in this.childrenMap) {
2696
- if (has(this.childrenMap, id)) {
2886
+ if (hasOwnProperty(this.childrenMap, id)) {
2697
2887
  result.push(id);
2698
2888
  }
2699
2889
  }
@@ -2720,14 +2910,10 @@ var Frame = class _Frame extends EventEmitter {
2720
2910
  let result;
2721
2911
  const view = this.view;
2722
2912
  if (view && view.rendered) {
2723
- const fn = view[name];
2913
+ const lookup = view;
2914
+ const fn = lookup[name];
2724
2915
  if (typeof fn === "function") {
2725
- result = funcWithTry(
2726
- fn,
2727
- args || [],
2728
- view,
2729
- noop
2730
- );
2916
+ result = funcWithTry(fn, args || [], view, noop);
2731
2917
  }
2732
2918
  } else {
2733
2919
  const key = SPLITTER + name;
@@ -2750,6 +2936,25 @@ var Frame = class _Frame extends EventEmitter {
2750
2936
  }
2751
2937
  return result;
2752
2938
  }
2939
+ /**
2940
+ * Type-safe variant of `invoke`.
2941
+ *
2942
+ * `invoke()` accepts any string and any args, which silently hides
2943
+ * mismatched call sites when a method gets renamed. `invokeTyped` carries
2944
+ * the view's method signature through TypeScript so the compiler catches
2945
+ * those mistakes:
2946
+ *
2947
+ * ```ts
2948
+ * type Home = View & { loadData(id: string): Promise<void> };
2949
+ * frame.invokeTyped<Home, "loadData">("loadData", ["user-1"]);
2950
+ * ```
2951
+ *
2952
+ * Behavior is identical to `invoke` at runtime — same defer / direct-call
2953
+ * paths — so it's a drop-in safer overload.
2954
+ */
2955
+ invokeTyped(name, args) {
2956
+ return this.invoke(name, args);
2957
+ }
2753
2958
  // ============================================================
2754
2959
  // Static methods
2755
2960
  // ============================================================
@@ -2761,8 +2966,25 @@ var Frame = class _Frame extends EventEmitter {
2761
2966
  static getAll() {
2762
2967
  return frameRegistry;
2763
2968
  }
2764
- /** Get or create root frame */
2765
- static root(rootId) {
2969
+ /**
2970
+ * Returns the existing root frame, or `undefined` if none has been created.
2971
+ * Pure getter — never creates a Frame, never touches the DOM.
2972
+ *
2973
+ * Use `Frame.createRoot(id)` to create the root explicitly during framework
2974
+ * boot. For Micro-Frontend hosts that own multiple independent containers,
2975
+ * use `new Frame(containerId)` directly so each MF mount has its own root.
2976
+ */
2977
+ static getRoot() {
2978
+ return rootFrame;
2979
+ }
2980
+ /**
2981
+ * Create (or return) the singleton root frame for this app.
2982
+ *
2983
+ * Idempotent: subsequent calls always return the original root regardless
2984
+ * of `rootId` — so passing a different id later is silently ignored.
2985
+ * `Framework.boot()` is the canonical caller; user code rarely needs this.
2986
+ */
2987
+ static createRoot(rootId) {
2766
2988
  if (!rootFrame) {
2767
2989
  rootId = rootId || "root";
2768
2990
  let rootElement = document.getElementById(rootId);
@@ -2774,6 +2996,17 @@ var Frame = class _Frame extends EventEmitter {
2774
2996
  }
2775
2997
  return rootFrame;
2776
2998
  }
2999
+ /**
3000
+ * @deprecated Use `Frame.getRoot()` for read-only access or
3001
+ * `Frame.createRoot(id)` to create the root explicitly. The single-method
3002
+ * `root()` blurred the distinction and was a common source of bugs in
3003
+ * Micro-Frontend hosts.
3004
+ *
3005
+ * Kept for backward compatibility — behavior unchanged.
3006
+ */
3007
+ static root(rootId) {
3008
+ return _Frame.createRoot(rootId);
3009
+ }
2777
3010
  /** Bind event listener (static) */
2778
3011
  static on(event, handler) {
2779
3012
  staticEmitter.on(event, handler);
@@ -2789,6 +3022,9 @@ var Frame = class _Frame extends EventEmitter {
2789
3022
  staticEmitter.fire(event, data);
2790
3023
  }
2791
3024
  };
3025
+ function htmlElIsBound(element) {
3026
+ return !!element.frameBound;
3027
+ }
2792
3028
  function ensureElementId2(element) {
2793
3029
  const id = element.getAttribute("id");
2794
3030
  if (id) return id;
@@ -2818,8 +3054,8 @@ function notifyCreated(frameInstance) {
2818
3054
  const pId = frameInstance.parentId;
2819
3055
  if (pId) {
2820
3056
  const parent = frameRegistry.get(pId);
2821
- if (parent && !parent.readyMap[frameInstance.id]) {
2822
- parent.readyMap[frameInstance.id] = 1;
3057
+ if (parent && !parent.readyMap.has(frameInstance.id)) {
3058
+ parent.readyMap.add(frameInstance.id);
2823
3059
  parent.readyCount++;
2824
3060
  notifyCreated(parent);
2825
3061
  }
@@ -2834,9 +3070,9 @@ function notifyAlter(frameInstance, data) {
2834
3070
  const pId = frameInstance.parentId;
2835
3071
  if (pId) {
2836
3072
  const parent = frameRegistry.get(pId);
2837
- if (parent && parent.readyMap[frameInstance.id]) {
3073
+ if (parent && parent.readyMap.has(frameInstance.id)) {
2838
3074
  parent.readyCount--;
2839
- Reflect.deleteProperty(parent.readyMap, frameInstance.id);
3075
+ parent.readyMap.delete(frameInstance.id);
2840
3076
  notifyAlter(parent, data);
2841
3077
  }
2842
3078
  }
@@ -2849,7 +3085,7 @@ function reInitFrame(frame, id, parentId) {
2849
3085
  frame["childrenCount"] = 0;
2850
3086
  frame["readyCount"] = 0;
2851
3087
  frame["signature"] = 1;
2852
- frame["readyMap"] = {};
3088
+ frame["readyMap"] = /* @__PURE__ */ new Set();
2853
3089
  frame["invokeList"] = [];
2854
3090
  frameRegistry.set(id, frame);
2855
3091
  }
@@ -2857,7 +3093,7 @@ function reInitFrameForCache(frame) {
2857
3093
  Reflect.set(frame, "id", "");
2858
3094
  frame["_parentId"] = void 0;
2859
3095
  frame["childrenMap"] = {};
2860
- frame["readyMap"] = {};
3096
+ frame["readyMap"] = /* @__PURE__ */ new Set();
2861
3097
  }
2862
3098
  function translateQuery(pId, src, params) {
2863
3099
  const parentFrame = frameRegistry.get(pId);
@@ -2867,22 +3103,138 @@ function translateQuery(pId, src, params) {
2867
3103
  if (!parentRefData) return;
2868
3104
  if (src.indexOf(SPLITTER) > 0) {
2869
3105
  translateData(parentRefData, params);
2870
- if (params[SPLITTER]) {
2871
- assign(
2872
- params,
2873
- params[SPLITTER]
2874
- );
3106
+ const paramsRec = params;
3107
+ const splitterValue = paramsRec[SPLITTER];
3108
+ if (splitterValue && typeof splitterValue === "object") {
3109
+ assign(params, splitterValue);
2875
3110
  Reflect.deleteProperty(params, SPLITTER);
2876
3111
  }
2877
3112
  }
2878
3113
  }
2879
- function registerViewClass(viewPath, ViewClass) {
2880
- const parsed = parseUri(viewPath);
2881
- const path = parsed.path;
2882
- if (path) {
2883
- viewClassRegistry[path] = ViewClass;
3114
+
3115
+ // src/cross-site.ts
3116
+ var preparePromises = {};
3117
+ var projectsMap = null;
3118
+ function loadRemoteView(viewPath, bizCode) {
3119
+ const crossConfigs = config.crossConfigs || window.crossConfigs;
3120
+ const currentName = config.projectName || "";
3121
+ const slashIndex = viewPath.indexOf("/");
3122
+ const projectName = slashIndex > -1 ? viewPath.substring(0, slashIndex) : viewPath;
3123
+ if (projectName === currentName) return Promise.resolve();
3124
+ if (!preparePromises[projectName]) {
3125
+ if (!projectsMap) {
3126
+ const map = toMap(crossConfigs || [], "projectName");
3127
+ projectsMap = map;
3128
+ }
3129
+ const info = projectsMap[projectName];
3130
+ if (!info) {
3131
+ return Promise.reject(
3132
+ new Error(`Cannot find ${projectName} from crossConfigs`)
3133
+ );
3134
+ }
3135
+ preparePromises[projectName] = use(`${projectName}/prepare`).then((modules) => {
3136
+ let mod = modules[0];
3137
+ if (mod && typeof mod === "object" && mod !== null) {
3138
+ const rec = mod;
3139
+ if (rec["__esModule"]) {
3140
+ mod = rec["default"];
3141
+ }
3142
+ }
3143
+ if (typeof mod === "function") {
3144
+ return mod({ bizCode });
3145
+ }
3146
+ return void 0;
3147
+ }).catch((err) => {
3148
+ Reflect.deleteProperty(preparePromises, projectName);
3149
+ throw err;
3150
+ });
2884
3151
  }
3152
+ return preparePromises[projectName];
3153
+ }
3154
+ function resetProjectsMap() {
3155
+ projectsMap = null;
2885
3156
  }
3157
+ var skeletonTemplate = (data, viewId) => {
3158
+ let skeletonHtml = "<div>Loading...</div>";
3159
+ if (data && typeof data === "object") {
3160
+ const candidate = data.skeleton;
3161
+ if (typeof candidate === "string") skeletonHtml = candidate;
3162
+ }
3163
+ return `<div id="mf_${viewId}">${skeletonHtml}</div>`;
3164
+ };
3165
+ var CrossSite = View.extend({
3166
+ /** Skeleton template renders loading state + child container */
3167
+ template: skeletonTemplate,
3168
+ init(params) {
3169
+ this.$sign = 0;
3170
+ this.on("destroy", () => {
3171
+ this.$sign = -1;
3172
+ });
3173
+ this.assign?.(params);
3174
+ },
3175
+ assign(data) {
3176
+ this.$view = typeof data["view"] === "string" ? data["view"] : "";
3177
+ const nested = data["params"];
3178
+ const nestedParams = nested && typeof nested === "object" ? nested : {};
3179
+ this.$params = { ...data, ...nestedParams };
3180
+ this.updater.set({
3181
+ skeleton: data["skeleton"],
3182
+ skeletonParams: data["skeletonParams"] || {},
3183
+ bizCode: data["bizCode"]
3184
+ });
3185
+ if (this.$sign > 0) {
3186
+ this.updateView();
3187
+ }
3188
+ return false;
3189
+ },
3190
+ async updateView() {
3191
+ const sign = ++this.$sign;
3192
+ const stored = this.updater.get();
3193
+ const bizCode = stored.bizCode;
3194
+ try {
3195
+ await loadRemoteView(this.$view, bizCode);
3196
+ } catch (ex) {
3197
+ const node = document.getElementById("mf_" + this.id);
3198
+ if (node) {
3199
+ const err = ex instanceof Error ? ex : new Error(String(ex));
3200
+ node.innerHTML = err.message || String(err);
3201
+ }
3202
+ }
3203
+ if (this.$sign !== sign) return;
3204
+ const mf = Frame.get("mf_" + this.id);
3205
+ const parsedNew = parseUri(this.$view);
3206
+ const newPath = parsedNew.path;
3207
+ const oldPath = mf?.viewPath ? parseUri(mf.viewPath).path : "";
3208
+ const view = mf?.view;
3209
+ if (newPath === oldPath && view && typeof view.assign === "function") {
3210
+ const result = funcWithTry(view.assign, [this.$params], view, noop);
3211
+ if (result) {
3212
+ view.render();
3213
+ }
3214
+ return;
3215
+ }
3216
+ const owner = this.owner;
3217
+ if (owner && typeof owner !== "number") {
3218
+ owner.mountFrame("mf_" + this.id, this.$view, this.$params);
3219
+ }
3220
+ },
3221
+ render() {
3222
+ const params = this.$params;
3223
+ this.updater.digest({
3224
+ skeleton: params?.["skeleton"]
3225
+ });
3226
+ this.updateView();
3227
+ },
3228
+ /**
3229
+ * Invoke a method on the remote view.
3230
+ * Usage: mf.invoke('callView', methodName, ...args)
3231
+ */
3232
+ callView(name, ...args) {
3233
+ const mf = Frame.get("mf_" + this.id);
3234
+ return mf?.invoke(name, args);
3235
+ }
3236
+ });
3237
+ var cross_site_default = CrossSite;
2886
3238
 
2887
3239
  // src/service.ts
2888
3240
  var Payload = class {
@@ -3070,29 +3422,31 @@ var Service = class {
3070
3422
  * Get metadata for an API endpoint.
3071
3423
  */
3072
3424
  static meta(attrs) {
3073
- const name = typeof attrs === "string" ? attrs : attrs["name"];
3074
- return this._metaList[name] || attrs;
3425
+ const name = typeof attrs === "string" ? attrs : String(attrs["name"] ?? "");
3426
+ const known = this._metaList[name];
3427
+ if (known) return known;
3428
+ return attrs;
3075
3429
  }
3076
3430
  /**
3077
3431
  * Create a Payload for an API request.
3078
3432
  */
3079
3433
  static create(attrs) {
3080
3434
  const meta = this.meta(attrs);
3081
- const cache = attrs["cache"] | 0 || meta.cache || 0;
3435
+ const cache = toCacheValue(attrs["cache"]) || meta.cache || 0;
3082
3436
  const entity = new Payload();
3083
3437
  entity.set(meta);
3084
3438
  entity.cacheInfo = {
3085
3439
  name: meta.name,
3086
- after: meta.after,
3087
- cleans: meta.cleanKeys,
3440
+ after: typeof meta.after === "function" ? meta.after : void 0,
3441
+ cleans: typeof meta.cleanKeys === "string" ? meta.cleanKeys : void 0,
3088
3442
  key: cache ? defaultCacheKey(meta, attrs) : "",
3089
3443
  time: 0
3090
3444
  };
3091
- if (typeof attrs === "object" && attrs !== null) {
3445
+ if (attrs !== null) {
3092
3446
  entity.set(attrs);
3093
3447
  }
3094
3448
  const before = meta.before;
3095
- if (before) {
3449
+ if (typeof before === "function") {
3096
3450
  funcWithTry(before, [entity], entity, noop);
3097
3451
  }
3098
3452
  this._staticEmitter.fire("begin", { payload: entity });
@@ -3118,7 +3472,7 @@ var Service = class {
3118
3472
  */
3119
3473
  static cached(attrs) {
3120
3474
  const meta = this.meta(attrs);
3121
- const cache = attrs["cache"] | 0 || meta.cache || 0;
3475
+ const cache = toCacheValue(attrs["cache"]) || meta.cache || 0;
3122
3476
  let cacheKey = "";
3123
3477
  if (cache) {
3124
3478
  cacheKey = defaultCacheKey(meta, attrs);
@@ -3126,7 +3480,8 @@ var Service = class {
3126
3480
  if (cacheKey) {
3127
3481
  const info = this._pendingCacheKeys[cacheKey];
3128
3482
  if (info) {
3129
- return info.entity;
3483
+ const entity = info.entity;
3484
+ return entity instanceof Payload ? entity : void 0;
3130
3485
  }
3131
3486
  const cached = this._payloadCache.get(cacheKey);
3132
3487
  if (cached && cached.cacheInfo) {
@@ -3143,17 +3498,14 @@ var Service = class {
3143
3498
  * Clear cached payloads by endpoint name.
3144
3499
  */
3145
3500
  static clear(names) {
3146
- const nameList = (typeof names === "string" ? names : names.join(",")).split(",");
3147
- const nameSet = {};
3148
- for (const n of nameList) {
3149
- nameSet[n] = 1;
3150
- }
3501
+ const nameSet = new Set(
3502
+ (typeof names === "string" ? names : names.join(",")).split(",")
3503
+ );
3151
3504
  const keysToDelete = [];
3152
3505
  this._payloadCache.forEach((payload) => {
3153
- if (payload?.cacheInfo && nameSet[payload.cacheInfo.name]) {
3154
- if (payload.cacheInfo.key) {
3155
- keysToDelete.push(payload.cacheInfo.key);
3156
- }
3506
+ const info = payload?.cacheInfo;
3507
+ if (info && info.key && nameSet.has(info.name)) {
3508
+ keysToDelete.push(info.key);
3157
3509
  }
3158
3510
  });
3159
3511
  for (const key of keysToDelete) {
@@ -3172,12 +3524,23 @@ var Service = class {
3172
3524
  }
3173
3525
  /**
3174
3526
  * Create a new Service subclass with a custom sync function.
3175
- * Each subclass gets its own per-type state (metaList, cache, etc.)
3176
- * to ensure isolation between different Service types.
3527
+ *
3528
+ * Each subclass gets its OWN copies of every per-type static field
3529
+ * (`_metaList`, `_payloadCache`, `_pendingCacheKeys`, `_syncFn`,
3530
+ * `_staticEmitter`, `_cacheMax`, `_cacheBuffer`) via `static override`.
3531
+ * This is intentional: it ensures that endpoint metadata, cache state,
3532
+ * in-flight dedup keys, and event subscribers are fully isolated between
3533
+ * different Service types, even when one extends another.
3534
+ *
3535
+ * **Do not refactor these `static override` declarations away** — sharing
3536
+ * them through prototype inheritance would let endpoints registered on one
3537
+ * subclass leak into another, and the LFU cache evictions of one type
3538
+ * would race with those of another.
3177
3539
  */
3178
3540
  static extend(newSyncFn, newCacheMax, newCacheBuffer) {
3179
3541
  const ParentService = this;
3180
3542
  class ChildService extends ParentService {
3543
+ // Intentionally per-subclass — see Service.extend doc.
3181
3544
  static _metaList = {};
3182
3545
  static _payloadCache = new Cache({
3183
3546
  maxSize: newCacheMax || ParentService._cacheMax,
@@ -3192,18 +3555,34 @@ var Service = class {
3192
3555
  return ChildService;
3193
3556
  }
3194
3557
  };
3558
+ var metaJsonCache = /* @__PURE__ */ new WeakMap();
3559
+ function getMetaJson(meta) {
3560
+ let cached = metaJsonCache.get(meta);
3561
+ if (cached === void 0) {
3562
+ cached = JSON.stringify(meta);
3563
+ metaJsonCache.set(meta, cached);
3564
+ }
3565
+ return cached;
3566
+ }
3195
3567
  function defaultCacheKey(meta, attrs) {
3196
- return JSON.stringify(attrs) + SPLITTER + JSON.stringify(meta);
3568
+ return JSON.stringify(attrs) + SPLITTER + getMetaJson(meta);
3569
+ }
3570
+ function toCacheValue(v) {
3571
+ if (typeof v === "number") return v | 0;
3572
+ if (typeof v === "string") {
3573
+ const n = Number(v);
3574
+ return Number.isFinite(n) ? n | 0 : 0;
3575
+ }
3576
+ return 0;
3197
3577
  }
3198
3578
  function serviceSend(service, attrs, done, flag, save) {
3199
- if (service["destroyed"]) return;
3200
- if (service["busy"]) {
3201
- service.enqueue(
3202
- serviceSend.bind(null, service, attrs, done, flag, save)
3203
- );
3579
+ if (service.destroyed) return;
3580
+ if (service.busy) {
3581
+ const queued = () => serviceSend(service, attrs, done, flag, save);
3582
+ service.enqueue(queued);
3204
3583
  return;
3205
3584
  }
3206
- service["busy"] = 1;
3585
+ service.busy = 1;
3207
3586
  let attrList;
3208
3587
  if (typeof attrs === "string") {
3209
3588
  attrList = [{ name: attrs }];
@@ -3228,10 +3607,10 @@ function serviceSend(service, attrs, done, flag, save) {
3228
3607
  newPayload = true;
3229
3608
  staticEmitter2.fire("done", { payload });
3230
3609
  }
3231
- if (!service["destroyed"]) {
3610
+ if (!service.destroyed) {
3232
3611
  const finish = requestCount === total;
3233
3612
  if (finish) {
3234
- service["busy"] = 0;
3613
+ service.busy = 0;
3235
3614
  if (flag === FETCH_FLAGS_ALL) {
3236
3615
  doneArr[0] = errorArgs;
3237
3616
  funcWithTry(done, doneArr, service, noop);
@@ -3248,10 +3627,7 @@ function serviceSend(service, attrs, done, flag, save) {
3248
3627
  for (const attr of attrList) {
3249
3628
  if (!attr) continue;
3250
3629
  const attrObj = typeof attr === "string" ? { name: attr } : attr;
3251
- const payloadInfo = service.type.get(
3252
- attrObj,
3253
- save
3254
- );
3630
+ const payloadInfo = service.type.get(attrObj, save);
3255
3631
  const payloadEntity = payloadInfo.entity;
3256
3632
  const cacheKey = payloadEntity.cacheInfo?.key || "";
3257
3633
  const complete = remoteComplete.bind(null, requestCount++);
@@ -3265,15 +3641,13 @@ function serviceSend(service, attrs, done, flag, save) {
3265
3641
  const cacheComplete = () => {
3266
3642
  const list = pendingCacheKeys[cacheKey];
3267
3643
  const entity = list.entity;
3268
- if (entity.cacheInfo) {
3644
+ if (entity instanceof Payload && entity.cacheInfo) {
3269
3645
  entity.cacheInfo.time = now();
3646
+ internals.payloadCache.set(cacheKey, entity);
3270
3647
  }
3271
- internals.payloadCache.set(cacheKey, entity);
3272
3648
  Reflect.deleteProperty(pendingCacheKeys, cacheKey);
3273
3649
  for (const cb of list) {
3274
- if (typeof cb === "function") {
3275
- cb();
3276
- }
3650
+ if (typeof cb === "function") cb();
3277
3651
  }
3278
3652
  };
3279
3653
  syncFn(payloadEntity, cacheComplete);
@@ -3286,12 +3660,14 @@ function serviceSend(service, attrs, done, flag, save) {
3286
3660
  }
3287
3661
  }
3288
3662
 
3289
- // src/frame-visualizer.ts
3290
- var MSG_PING = "LARK_VISUALIZER_PING";
3291
- var MSG_PONG = "LARK_VISUALIZER_PONG";
3292
- var MSG_REQUEST_TREE = "LARK_VISUALIZER_REQUEST_TREE";
3293
- var MSG_TREE = "LARK_VISUALIZER_TREE";
3294
- var MSG_TREE_DELTA = "LARK_VISUALIZER_TREE_DELTA";
3663
+ // src/frame-visual.ts
3664
+ var FrameVisualBridge = {
3665
+ MSG_PING: "LARK_VIS_PING",
3666
+ MSG_PONG: "LARK_VIS_PONG",
3667
+ MSG_REQUEST_TREE: "LARK_VIS_REQUEST_TREE",
3668
+ MSG_TREE: "LARK_VIS_TREE",
3669
+ MSG_TREE_DELTA: "LARK_VIS_TREE_DELTA"
3670
+ };
3295
3671
  function serializeView(view) {
3296
3672
  return {
3297
3673
  id: view.id,
@@ -3331,7 +3707,10 @@ function serializeFrame(frameId) {
3331
3707
  };
3332
3708
  }
3333
3709
  function serializeFrameTree() {
3334
- const root = Frame.root();
3710
+ const root = Frame.getRoot();
3711
+ if (!root) {
3712
+ return { root: null, totalFrames: 0, timestamp: Date.now(), rootId: "" };
3713
+ }
3335
3714
  const rootNode = serializeFrame(root.id);
3336
3715
  let totalFrames = 0;
3337
3716
  const countFrames = (node) => {
@@ -3359,19 +3738,22 @@ function installFrameVisualizerBridge() {
3359
3738
  const data = event.data;
3360
3739
  if (!data || typeof data !== "object") return;
3361
3740
  const type = data.type;
3362
- if (type === MSG_PING) {
3741
+ if (type === FrameVisualBridge.MSG_PING) {
3363
3742
  const source = event.source;
3364
3743
  if (source) {
3365
- source.postMessage({ type: MSG_PONG }, { targetOrigin: "*" });
3744
+ source.postMessage(
3745
+ { type: FrameVisualBridge.MSG_PONG },
3746
+ { targetOrigin: "*" }
3747
+ );
3366
3748
  }
3367
3749
  return;
3368
3750
  }
3369
- if (type === MSG_REQUEST_TREE) {
3751
+ if (type === FrameVisualBridge.MSG_REQUEST_TREE) {
3370
3752
  const tree = serializeFrameTree();
3371
3753
  const source = event.source;
3372
3754
  if (source) {
3373
3755
  source.postMessage(
3374
- { type: MSG_TREE, data: tree },
3756
+ { type: FrameVisualBridge.MSG_TREE, data: tree },
3375
3757
  { targetOrigin: "*" }
3376
3758
  );
3377
3759
  }
@@ -3390,18 +3772,14 @@ function pushTreeUpdate() {
3390
3772
  const treeJson = JSON.stringify(tree);
3391
3773
  if (treeJson !== lastTreeJson) {
3392
3774
  lastTreeJson = treeJson;
3393
- window.parent.postMessage({ type: MSG_TREE_DELTA, data: tree }, "*");
3775
+ window.parent.postMessage(
3776
+ { type: FrameVisualBridge.MSG_TREE_DELTA, data: tree },
3777
+ "*"
3778
+ );
3394
3779
  }
3395
3780
  }
3396
3781
 
3397
3782
  // src/framework.ts
3398
- var config = {
3399
- rootId: "root",
3400
- hashbang: "#!",
3401
- error: (error) => {
3402
- throw error;
3403
- }
3404
- };
3405
3783
  var booted3 = false;
3406
3784
  var taskList = [];
3407
3785
  var taskIndex = 0;
@@ -3450,6 +3828,9 @@ function task(fn, args, context) {
3450
3828
  }
3451
3829
  }
3452
3830
  var dispatcherUpdateTag = 0;
3831
+ function isThenable(value) {
3832
+ return !!value && (typeof value === "object" || typeof value === "function") && typeof value.then === "function";
3833
+ }
3453
3834
  function viewIsObserveChanged(view) {
3454
3835
  const loc = view.locationObserved;
3455
3836
  let result = false;
@@ -3463,7 +3844,7 @@ function viewIsObserveChanged(view) {
3463
3844
  const changedParams = lastChanged2?.params;
3464
3845
  if (changedParams) {
3465
3846
  for (const key of loc.keys) {
3466
- result = has(changedParams, key);
3847
+ result = hasOwnProperty(changedParams, key);
3467
3848
  if (result) break;
3468
3849
  }
3469
3850
  }
@@ -3475,48 +3856,59 @@ function stateIsObserveChanged(view, stateKeys) {
3475
3856
  const observedKeys = view.observedStateKeys;
3476
3857
  if (!observedKeys) return false;
3477
3858
  for (const key of observedKeys) {
3478
- if (has(stateKeys, key)) return true;
3859
+ if (stateKeys.has(key)) return true;
3479
3860
  }
3480
3861
  return false;
3481
3862
  }
3482
3863
  function dispatcherUpdate(frame, stateKeys) {
3483
- const frameInternal = frame;
3484
- const view = frame.view;
3485
- if (!view || frameInternal.dispatcherUpdateTag === dispatcherUpdateTag || view.signature <= 1) {
3486
- return;
3487
- }
3488
- frameInternal.dispatcherUpdateTag = dispatcherUpdateTag;
3489
- const isChanged = stateKeys ? stateIsObserveChanged(view, stateKeys) : viewIsObserveChanged(view);
3490
- let renderPromise;
3491
- if (isChanged) {
3492
- const renderResult = funcWithTry(
3493
- view.renderMethod ?? view.render,
3494
- [],
3495
- view,
3496
- noop
3497
- );
3498
- if (renderResult && typeof renderResult.then === "function") {
3499
- renderPromise = renderResult;
3500
- }
3501
- }
3502
- const children = frame.children();
3503
- const recurse = () => {
3504
- for (const childId of children) {
3505
- const childFrame = Frame.get(childId);
3506
- if (childFrame) {
3507
- dispatcherUpdate(childFrame, stateKeys);
3864
+ const stack = [frame];
3865
+ const drain = (s) => {
3866
+ while (s.length > 0) {
3867
+ const current = s.pop();
3868
+ const tagged = current;
3869
+ const view = current.view;
3870
+ if (!view || tagged.dispatcherUpdateTag === dispatcherUpdateTag || view.signature <= 1) {
3871
+ continue;
3872
+ }
3873
+ tagged.dispatcherUpdateTag = dispatcherUpdateTag;
3874
+ const isChanged = stateKeys ? stateIsObserveChanged(view, stateKeys) : viewIsObserveChanged(view);
3875
+ let renderPromise;
3876
+ if (isChanged) {
3877
+ const renderResult = funcWithTry(
3878
+ view.renderMethod ?? view.render,
3879
+ [],
3880
+ view,
3881
+ noop
3882
+ );
3883
+ if (isThenable(renderResult)) {
3884
+ renderPromise = renderResult;
3885
+ }
3886
+ }
3887
+ const children = current.children();
3888
+ if (renderPromise) {
3889
+ renderPromise.then(() => {
3890
+ const subStack = [];
3891
+ for (let i = children.length - 1; i >= 0; i--) {
3892
+ const child = Frame.get(children[i]);
3893
+ if (child) subStack.push(child);
3894
+ }
3895
+ drain(subStack);
3896
+ });
3897
+ } else {
3898
+ for (let i = children.length - 1; i >= 0; i--) {
3899
+ const child = Frame.get(children[i]);
3900
+ if (child) s.push(child);
3901
+ }
3508
3902
  }
3509
3903
  }
3510
3904
  };
3511
- if (renderPromise) {
3512
- renderPromise.then(recurse);
3513
- } else {
3514
- recurse();
3515
- }
3905
+ drain(stack);
3516
3906
  }
3517
3907
  function dispatcherNotifyChange(e) {
3518
- const rootFrame2 = Frame.root();
3519
- const view = e.view;
3908
+ const rootFrame2 = Frame.getRoot();
3909
+ if (!rootFrame2) return;
3910
+ const routeEvent = e;
3911
+ const view = routeEvent.view;
3520
3912
  if (view) {
3521
3913
  const viewPath = typeof view === "object" && view !== null ? String(view.to || "") : String(view);
3522
3914
  rootFrame2.mountView(viewPath);
@@ -3533,19 +3925,6 @@ function dispatchEvent(target, eventType, eventInit) {
3533
3925
  });
3534
3926
  target.dispatchEvent(event);
3535
3927
  }
3536
- function use(names, callback) {
3537
- if (!config.require) {
3538
- if (callback) callback();
3539
- return;
3540
- }
3541
- const nameList = typeof names === "string" ? [names] : names;
3542
- const result = config.require(nameList);
3543
- if (result && typeof result.then === "function") {
3544
- result.then((modules) => {
3545
- if (callback) callback(modules);
3546
- });
3547
- }
3548
- }
3549
3928
  var WAIT_OK = 1;
3550
3929
  var WAIT_TIMEOUT_OR_NOT_FOUND = 0;
3551
3930
  function waitZoneViewsRendered(viewId, timeout) {
@@ -3568,12 +3947,27 @@ function waitZoneViewsRendered(viewId, timeout) {
3568
3947
  setTimeout(check, 9);
3569
3948
  });
3570
3949
  }
3950
+ function getConfigImpl(key) {
3951
+ if (key === void 0) return config;
3952
+ return config[key];
3953
+ }
3571
3954
  var Framework = {
3572
3955
  // ============================================================
3573
3956
  // Lifecycle
3574
3957
  // ============================================================
3958
+ /** Read framework configuration. See `FrameworkInterface.getConfig`. */
3959
+ getConfig: getConfigImpl,
3575
3960
  /**
3576
- * Get or set framework configuration.
3961
+ * Merge a patch into framework configuration. See `FrameworkInterface.setConfig`.
3962
+ */
3963
+ setConfig(patch) {
3964
+ if (patch && typeof patch === "object") {
3965
+ assign(config, patch);
3966
+ }
3967
+ return config;
3968
+ },
3969
+ /**
3970
+ * @deprecated Use `getConfig()` / `setConfig()`. Behavior unchanged.
3577
3971
  */
3578
3972
  config(cfg) {
3579
3973
  if (!cfg) {
@@ -3594,17 +3988,17 @@ var Framework = {
3594
3988
  }
3595
3989
  Router._setConfig(config);
3596
3990
  EventDelegator.setFrameGetter((id) => Frame.get(id));
3597
- Router.on(ROUTER_EVENTS.CHANGED, (data) => {
3991
+ Router.on(RouterEvents.CHANGED, (data) => {
3598
3992
  if (data) dispatcherNotifyChange(data);
3599
3993
  });
3600
- State.on(ROUTER_EVENTS.CHANGED, (data) => {
3994
+ State.on(RouterEvents.CHANGED, (data) => {
3601
3995
  if (data) dispatcherNotifyChange(data);
3602
3996
  });
3603
3997
  booted3 = true;
3604
3998
  markBooted();
3605
3999
  markRouterBooted();
3606
4000
  installFrameVisualizerBridge();
3607
- const rootFrame2 = Frame.root(config.rootId);
4001
+ const rootFrame2 = Frame.createRoot(config.rootId);
3608
4002
  Router._bind();
3609
4003
  const defaultView = config.defaultView || "";
3610
4004
  if (defaultView && !rootFrame2.view) {
@@ -3659,7 +4053,7 @@ var Framework = {
3659
4053
  /**
3660
4054
  * Check if object has own property.
3661
4055
  */
3662
- has,
4056
+ has: hasOwnProperty,
3663
4057
  /**
3664
4058
  * Get object keys.
3665
4059
  */
@@ -3719,6 +4113,9 @@ if (typeof window !== "undefined") {
3719
4113
  window.__lark_Router = Router;
3720
4114
  window.__lark_Frame = Frame;
3721
4115
  window.__lark_View = View;
4116
+ window.__lark_invalidateViewClass = invalidateViewClass;
4117
+ window.__lark_getViewClassRegistry = getViewClassRegistry;
4118
+ window.__lark_registerViewClass = registerViewClass;
3722
4119
  }
3723
4120
 
3724
4121
  // src/store.ts
@@ -3732,28 +4129,38 @@ var Platform = /* @__PURE__ */ ((Platform2) => {
3732
4129
  var isFunction = (val) => typeof val === "function";
3733
4130
  var isObject = (val) => val !== null && typeof val === "object";
3734
4131
  var isPromise = (val) => isObject(val) && isFunction(val["then"]);
3735
- var hasOwnProperty = (obj, prop) => Object.prototype.hasOwnProperty.call(obj, prop);
3736
- var deepClone = (obj) => {
4132
+ var hasOwnProperty2 = (obj, prop) => Object.prototype.hasOwnProperty.call(obj, prop);
4133
+ var hasStructuredClone = typeof globalThis !== "undefined" && typeof globalThis.structuredClone === "function";
4134
+ var deepCloneFallback = (obj) => {
3737
4135
  if (!obj || !isObject(obj)) return {};
3738
- const newData = Array.isArray(obj) ? [] : Object.create(Object.getPrototypeOf(obj));
4136
+ const newData = Array.isArray(obj) ? [] : {};
3739
4137
  for (const key in obj) {
3740
- if (hasOwnProperty(obj, key)) {
4138
+ if (hasOwnProperty2(obj, key)) {
3741
4139
  const value = obj[key];
3742
- newData[key] = isObject(value) ? deepClone(value) : value;
4140
+ newData[key] = isObject(value) ? deepCloneFallback(value) : value;
3743
4141
  }
3744
4142
  }
3745
4143
  return newData;
3746
4144
  };
4145
+ var deepClone = (obj) => {
4146
+ if (hasStructuredClone) {
4147
+ try {
4148
+ return structuredClone(obj);
4149
+ } catch {
4150
+ return deepCloneFallback(obj);
4151
+ }
4152
+ }
4153
+ return deepCloneFallback(obj);
4154
+ };
3747
4155
  var cloneData = (data) => isObject(data) ? deepClone(data) : data;
3748
4156
  var getDataByKey = (target, key) => {
3749
- let data;
3750
- const rec = target;
3751
- if (key.includes(".")) {
3752
- key.split(".").forEach((k, index) => {
3753
- data = index === 0 ? rec?.[k] : data?.[k];
3754
- });
3755
- } else {
3756
- data = rec?.[key];
4157
+ if (!key.includes(".")) {
4158
+ return target[key];
4159
+ }
4160
+ let data = target;
4161
+ for (const k of key.split(".")) {
4162
+ if (!isObject(data)) return void 0;
4163
+ data = data[k];
3757
4164
  }
3758
4165
  return data;
3759
4166
  };
@@ -3801,17 +4208,18 @@ var Queue = class {
3801
4208
  };
3802
4209
  var addParams2Callback = (cb, params) => {
3803
4210
  if (!cb || !params) return;
3804
- const cbObj = cb;
3805
- if (isObject(cb) && isObject(cbObj["params"])) {
3806
- Object.assign(cbObj["params"], params);
4211
+ const tagged = cb;
4212
+ const existing = tagged.params;
4213
+ if (isObject(existing)) {
4214
+ Object.assign(existing, params);
3807
4215
  } else {
3808
- cbObj["params"] = params;
4216
+ tagged.params = params;
3809
4217
  }
3810
4218
  };
3811
4219
  var runTask = (cb) => {
3812
- const cbObj = cb;
3813
- const params = cbObj["params"];
3814
- delete cbObj["params"];
4220
+ const tagged = cb;
4221
+ const params = tagged.params;
4222
+ delete tagged.params;
3815
4223
  try {
3816
4224
  cb(params);
3817
4225
  } catch {
@@ -3837,7 +4245,9 @@ var ArrMethods = {};
3837
4245
  if (res === -1 || res === false) {
3838
4246
  res = rawMethod.apply(
3839
4247
  this,
3840
- args.map((item) => ProxyCache.get(item) ?? item)
4248
+ args.map(
4249
+ (item) => isObject(item) ? ProxyCache.get(item) ?? item : item
4250
+ )
3841
4251
  );
3842
4252
  }
3843
4253
  return res;
@@ -3855,6 +4265,7 @@ var inArrUpdate = false;
3855
4265
  });
3856
4266
  function needKeepArrItem(target, newVal, key) {
3857
4267
  if (!Array.isArray(target) || !inArrUpdate) return false;
4268
+ if (!isObject(newVal)) return false;
3858
4269
  return getLinkKeys(newVal) === createLinkKeys(target, key);
3859
4270
  }
3860
4271
  var defStateConfig = {
@@ -3866,13 +4277,13 @@ var StateConfigMap = /* @__PURE__ */ new WeakMap();
3866
4277
  var setStateConfig = (target, config2) => {
3867
4278
  if (target && isObject(config2)) StateConfigMap.set(target, config2);
3868
4279
  };
3869
- var getStateConfig = (target, key) => {
4280
+ function getStateConfig(target, key) {
3870
4281
  if (!StateConfigMap.has(target)) {
3871
4282
  return void 0;
3872
4283
  }
3873
4284
  const config2 = StateConfigMap.get(target);
3874
4285
  return key ? config2?.[key] : config2;
3875
- };
4286
+ }
3876
4287
  var isState = (target) => isObject(target) && StateConfigMap.has(target);
3877
4288
  var createLinkKeys = (target, property) => {
3878
4289
  if (!hasLinkKeys(target)) return property;
@@ -3910,7 +4321,7 @@ var needKeep = (key) => {
3910
4321
  };
3911
4322
  var canSetNewVal = (params) => {
3912
4323
  const { property, newVal, oldVal } = params;
3913
- if (hasOwnProperty(params.target, property) && newVal === oldVal)
4324
+ if (hasOwnProperty2(params.target, property) && newVal === oldVal)
3914
4325
  return false;
3915
4326
  return true;
3916
4327
  };
@@ -3922,16 +4333,13 @@ var getNewVal = (params) => {
3922
4333
  if (config2?.shallow) return newVal;
3923
4334
  if (needKeepVal) return newVal;
3924
4335
  const linkKeys = createLinkKeys(target, property);
3925
- const newState = createState(newVal, {
3926
- ...config2,
3927
- linkKeys
3928
- });
4336
+ const newState = createState(newVal, { ...config2, linkKeys });
3929
4337
  if (isPromise(newVal)) handlePromise(newVal, target, property);
3930
4338
  return newState;
3931
4339
  };
3932
4340
  var genPayload = (params) => {
3933
4341
  const { target, property, newVal, oldVal } = params;
3934
- const config2 = getStateConfig(target) || defStateConfig;
4342
+ const config2 = getStateConfig(target) ?? defStateConfig;
3935
4343
  return {
3936
4344
  belong: config2.belong || LARK_GLOBAL,
3937
4345
  target,
@@ -3941,11 +4349,12 @@ var genPayload = (params) => {
3941
4349
  };
3942
4350
  };
3943
4351
  var handlePromise = (child, parent, key) => {
4352
+ const childObj = child;
3944
4353
  child.then((res) => {
3945
4354
  const parentProxy = ProxyCache.get(parent);
3946
4355
  if (parentProxy) {
3947
4356
  const oldVal = parentProxy[key];
3948
- if (ProxyCache.get(child) === oldVal) {
4357
+ if (ProxyCache.get(childObj) === oldVal) {
3949
4358
  parentProxy[key] = res;
3950
4359
  }
3951
4360
  }
@@ -3953,7 +4362,7 @@ var handlePromise = (child, parent, key) => {
3953
4362
  const parentProxy = ProxyCache.get(parent);
3954
4363
  if (parentProxy) {
3955
4364
  const oldVal = parentProxy[key];
3956
- if (ProxyCache.get(child) === oldVal) {
4365
+ if (ProxyCache.get(childObj) === oldVal) {
3957
4366
  parentProxy[key] = err;
3958
4367
  }
3959
4368
  }
@@ -3965,7 +4374,7 @@ var mark2 = (host, key) => {
3965
4374
  let sign;
3966
4375
  if (!host[_deleteKey]) {
3967
4376
  const markHost = host[_markObjKey] || (host[_markObjKey] = {});
3968
- if (!hasOwnProperty(markHost, key)) {
4377
+ if (!hasOwnProperty2(markHost, key)) {
3969
4378
  markHost[key] = 0;
3970
4379
  }
3971
4380
  sign = ++markHost[key];
@@ -4002,7 +4411,7 @@ function createState(initialData, config2) {
4002
4411
  oldVal
4003
4412
  });
4004
4413
  if (!canSet) return true;
4005
- const proxyTarget = receiver || state;
4414
+ const proxyTarget = isObject(receiver) && receiver !== null ? receiver : state;
4006
4415
  newVal = getNewVal({
4007
4416
  target: proxyTarget,
4008
4417
  property: strProp,
@@ -4022,7 +4431,7 @@ function createState(initialData, config2) {
4022
4431
  },
4023
4432
  deleteProperty(target, property) {
4024
4433
  const strProp = property;
4025
- if (!hasOwnProperty(target, strProp)) return true;
4434
+ if (!hasOwnProperty2(target, strProp)) return true;
4026
4435
  const oldVal = Reflect.get(target, property);
4027
4436
  Reflect.deleteProperty(target, property);
4028
4437
  const payload = genPayload({
@@ -4066,11 +4475,8 @@ function shallowSet(target, key, data) {
4066
4475
  keep(key);
4067
4476
  const config2 = getStateConfig(target);
4068
4477
  const linkKeys = createLinkKeys(target, key);
4069
- target[key] = createState(data, {
4070
- ...config2,
4071
- linkKeys,
4072
- shallow: true
4073
- });
4478
+ target[key] = createState(data, { ...config2, linkKeys, shallow: true });
4479
+ return target[key];
4074
4480
  }
4075
4481
  var GlobalDeps = /* @__PURE__ */ new Map();
4076
4482
  function track(payload) {
@@ -4151,8 +4557,22 @@ var _stateKeys = /* @__PURE__ */ Symbol("state-keys");
4151
4557
  var _storeState = /* @__PURE__ */ Symbol("store-state");
4152
4558
  var _storeDefScheduler = /* @__PURE__ */ Symbol("store-def-scheduler");
4153
4559
  var _storeProxy = /* @__PURE__ */ Symbol("fn:store-proxy");
4560
+ var _computedKeys = /* @__PURE__ */ Symbol("store-computed-keys");
4561
+ var COMPUTED_BRAND = /* @__PURE__ */ Symbol("store-computed-brand");
4562
+ function computed(deps, fn) {
4563
+ const marker = {
4564
+ [COMPUTED_BRAND]: true,
4565
+ deps,
4566
+ fn
4567
+ };
4568
+ return marker;
4569
+ }
4570
+ function isComputedMarker(val) {
4571
+ return isObject(val) && val[COMPUTED_BRAND] === true;
4572
+ }
4154
4573
  var BaseStore = class {
4155
4574
  [_storeStatus] = 0 /* BEFORE_CREATE */;
4575
+ [_computedKeys] = /* @__PURE__ */ new Set();
4156
4576
  [_storeDefScheduler] = getDefScheduler;
4157
4577
  [_storeBoot]() {
4158
4578
  this[_storeStatus] = 2 /* ACTIVE */;
@@ -4175,10 +4595,16 @@ var BaseStore = class {
4175
4595
  if (isObject(body)) {
4176
4596
  const state = {};
4177
4597
  const handlers = {};
4598
+ const computedDefs = {};
4599
+ const computedKeys = this[_computedKeys];
4178
4600
  Reflect.ownKeys(body).forEach((key) => {
4179
4601
  const strKey = key;
4180
4602
  const val = body[strKey];
4181
- if (isFunction(val)) {
4603
+ if (isComputedMarker(val)) {
4604
+ computedDefs[strKey] = val;
4605
+ state[strKey] = void 0;
4606
+ computedKeys.add(strKey);
4607
+ } else if (isFunction(val)) {
4182
4608
  if (!excludeFns.includes(strKey)) handlers[strKey] = val;
4183
4609
  } else {
4184
4610
  state[strKey] = val;
@@ -4188,6 +4614,22 @@ var BaseStore = class {
4188
4614
  this[_originState] = cloneData(state);
4189
4615
  this[_stateKeys] = Object.keys(state);
4190
4616
  this[_storeState] = createState(state, { belong: this[_storeName] });
4617
+ if (Object.keys(computedDefs).length > 0) {
4618
+ const belong = this[_storeName];
4619
+ const storeState = this[_storeState];
4620
+ for (const key of Object.keys(computedDefs)) {
4621
+ const def = computedDefs[key];
4622
+ const recompute = () => {
4623
+ storeState[key] = def.fn();
4624
+ };
4625
+ recompute();
4626
+ const trackList = def.deps.map((depKey) => ({
4627
+ key: depKey,
4628
+ cb: recompute
4629
+ }));
4630
+ if (trackList.length > 0) track({ belong, trackList });
4631
+ }
4632
+ }
4191
4633
  }
4192
4634
  }
4193
4635
  constructor(name, config2) {
@@ -4209,18 +4651,21 @@ var BaseStore = class {
4209
4651
  }
4210
4652
  [_storeProxy](toOut = false) {
4211
4653
  const self = this;
4212
- return new Proxy(self, {
4654
+ const proxy = new Proxy(self, {
4213
4655
  get(target, property) {
4214
- if (self[_stateKeys].includes(property)) {
4215
- const val = self[_storeState][property];
4656
+ const strProp = property;
4657
+ if (self[_stateKeys].includes(strProp)) {
4658
+ const val = self[_storeState][strProp];
4216
4659
  return toOut ? cloneData(val) : val;
4217
4660
  }
4218
4661
  return Reflect.get(target, property);
4219
4662
  },
4220
4663
  set(_target, property, val) {
4221
4664
  if (toOut) return true;
4222
- if (self[_stateKeys].includes(property)) {
4223
- self[_storeState][property] = val;
4665
+ const strProp = property;
4666
+ if (self[_computedKeys].has(strProp)) return true;
4667
+ if (self[_stateKeys].includes(strProp)) {
4668
+ self[_storeState][strProp] = val;
4224
4669
  }
4225
4670
  return true;
4226
4671
  },
@@ -4228,11 +4673,14 @@ var BaseStore = class {
4228
4673
  return Reflect.has(target, property) || self[_stateKeys].includes(property);
4229
4674
  }
4230
4675
  });
4676
+ return proxy;
4231
4677
  }
4232
4678
  };
4233
4679
  var LarkUtils = {
4234
4680
  isLarkView(instance) {
4235
- return isObject(instance) && !!instance.updater;
4681
+ if (!isObject(instance)) return false;
4682
+ const updater = instance["updater"];
4683
+ return isObject(updater) && isFunction(updater["set"]) && isFunction(updater["digest"]);
4236
4684
  },
4237
4685
  getRender(view) {
4238
4686
  return view.updater.digest.bind(view.updater);
@@ -4248,41 +4696,45 @@ var getLarkAdapter = (storeName) => ({
4248
4696
  Store: LarkStore,
4249
4697
  useStore: ((view) => {
4250
4698
  const store = getStore(storeName);
4699
+ if (!(store instanceof LarkStore)) return {};
4251
4700
  return store[_storeBoot](view);
4252
4701
  })
4253
4702
  });
4254
- var innerObserveFlags = /* @__PURE__ */ Symbol("store-inner-observe-flags");
4255
- var boundViews = /* @__PURE__ */ Symbol("bound-views");
4703
+ var _innerObserveFlags = /* @__PURE__ */ Symbol("store-inner-observe-flags");
4704
+ var _boundViews = /* @__PURE__ */ Symbol("store-bound-views");
4256
4705
  var LarkStore = class extends BaseStore {
4257
- [boundViews] = /* @__PURE__ */ new Set();
4258
- [innerObserveFlags] = /* @__PURE__ */ new Set();
4706
+ [_boundViews] = /* @__PURE__ */ new Set();
4707
+ [_innerObserveFlags] = /* @__PURE__ */ new Set();
4259
4708
  [_storeBoot](view) {
4260
- if (view && LarkUtils.isLarkView(view) && !this[boundViews].has(view)) {
4261
- this[boundViews].add(view);
4709
+ if (view && LarkUtils.isLarkView(view) && !this[_boundViews].has(view)) {
4710
+ this[_boundViews].add(view);
4262
4711
  LarkUtils.onDestroy(view, () => {
4263
- this[boundViews].delete(view);
4712
+ this[_boundViews].delete(view);
4264
4713
  });
4265
4714
  }
4266
4715
  return super[_storeBoot]();
4267
4716
  }
4268
4717
  [_storeDestroy]() {
4269
- this[boundViews].clear();
4270
- this[innerObserveFlags].clear();
4718
+ this[_boundViews].clear();
4719
+ this[_innerObserveFlags].clear();
4271
4720
  super[_storeDestroy]();
4272
4721
  }
4273
4722
  observe(view, keys2, defCallback) {
4274
4723
  if (this[_storeStatus] !== 2 /* ACTIVE */) return noop;
4275
- let observeKeys = keys2;
4724
+ let observeKeys = Array.isArray(keys2) ? keys2 : [];
4276
4725
  const _view = view;
4277
4726
  const renderFn = _view ? LarkUtils.getRender(_view) : noop;
4278
4727
  const dateSetterFn = _view ? LarkUtils.getDataSetter(_view) : noop;
4279
4728
  const isInnerObserve = !view;
4280
4729
  const innerFlags = /* @__PURE__ */ new Set();
4281
- const storeInnerObserveFlags = this[innerObserveFlags];
4730
+ const storeInnerObserveFlags = this[_innerObserveFlags];
4282
4731
  if (isFunction(keys2)) {
4283
4732
  const res = keys2();
4284
4733
  if (Array.isArray(res)) observeKeys = res;
4285
4734
  }
4735
+ if (keys2 === void 0 && _view && observeKeys.length === 0 && Array.isArray(this[_stateKeys])) {
4736
+ observeKeys = this[_stateKeys].slice();
4737
+ }
4286
4738
  const defSetter = (immediate, key, alias, transform) => () => {
4287
4739
  const stateVal = getDataByKey(this, key);
4288
4740
  let data = { [alias || key]: stateVal };
@@ -4337,11 +4789,12 @@ var getReactAdapter = (storeName) => ({
4337
4789
  Store: ReactStore,
4338
4790
  useStore: (() => {
4339
4791
  const store = getStore(storeName);
4792
+ if (!(store instanceof ReactStore)) return {};
4340
4793
  return store[_storeBoot]();
4341
4794
  })
4342
4795
  });
4343
- var observeSym = /* @__PURE__ */ Symbol("observe");
4344
- var getLastState = /* @__PURE__ */ Symbol("get-last-state");
4796
+ var _observe = /* @__PURE__ */ Symbol("store-observe");
4797
+ var _getLastState = /* @__PURE__ */ Symbol("store-get-last-state");
4345
4798
  var ReactStore = class extends BaseStore {
4346
4799
  stateChangeCount = 0;
4347
4800
  lastCount = 0;
@@ -4355,7 +4808,7 @@ var ReactStore = class extends BaseStore {
4355
4808
  }
4356
4809
  [_storeCreate](body) {
4357
4810
  super[_storeCreate](body);
4358
- this[observeSym](() => {
4811
+ this[_observe](() => {
4359
4812
  this.stateChangeCount += 1;
4360
4813
  });
4361
4814
  }
@@ -4365,7 +4818,7 @@ var ReactStore = class extends BaseStore {
4365
4818
  this.lastCount = currCount;
4366
4819
  return changed;
4367
4820
  }
4368
- [getLastState](handlers) {
4821
+ [_getLastState](handlers) {
4369
4822
  if (this.isStateChanged() || !this.lastState) {
4370
4823
  const state = this[_storeState];
4371
4824
  const immutableState = freezeData(state);
@@ -4373,7 +4826,7 @@ var ReactStore = class extends BaseStore {
4373
4826
  }
4374
4827
  return this.lastState;
4375
4828
  }
4376
- [observeSym](cb) {
4829
+ [_observe](cb) {
4377
4830
  const tasks = this[_stateKeys].map((key) => ({ key, cb }));
4378
4831
  track({ belong: this[_storeName], trackList: tasks });
4379
4832
  return () => clear({ belong: this[_storeName], clearList: tasks });
@@ -4400,6 +4853,7 @@ var getNodeAdapter = (storeName) => ({
4400
4853
  Store: NodeStore,
4401
4854
  useStore: (() => {
4402
4855
  const store = getStore(storeName);
4856
+ if (!(store instanceof NodeStore)) return {};
4403
4857
  return store[_storeBoot]();
4404
4858
  })
4405
4859
  });
@@ -4426,7 +4880,7 @@ var getPlatform = (comp) => {
4426
4880
  if (LarkUtils.isLarkView(comp)) return "lark" /* Lark */;
4427
4881
  return void 0;
4428
4882
  };
4429
- var extendApis = { lazySet, shallowSet };
4883
+ var extendApis = { lazySet, shallowSet, computed };
4430
4884
  var StoreCache = /* @__PURE__ */ new Map();
4431
4885
  function defineStore(name, creator, config2) {
4432
4886
  if (StoreCache.has(name)) {
@@ -4437,15 +4891,20 @@ function defineStore(name, creator, config2) {
4437
4891
  const StoreClass = adapter.Store;
4438
4892
  const useStore = adapter.useStore;
4439
4893
  const store = new StoreClass(name, config2);
4440
- store[_storeCreate](
4441
- creator(store[_innerStore](), extendApis)
4442
- );
4894
+ const innerProxy = store[_innerStore]();
4895
+ const body = creator(innerProxy, extendApis);
4896
+ store[_storeCreate](body);
4443
4897
  Object.defineProperties(useStore, {
4444
4898
  $storeName: { value: name, configurable: true },
4445
4899
  $destroyFn: { value: () => store[_storeDestroy](), configurable: true }
4446
4900
  });
4447
4901
  if (!StoreCache.has(name)) {
4448
- StoreCache.set(name, { store, creator, config: config2, useStore });
4902
+ StoreCache.set(name, {
4903
+ store,
4904
+ creator,
4905
+ config: config2,
4906
+ useStore
4907
+ });
4449
4908
  }
4450
4909
  return useStore;
4451
4910
  }
@@ -4467,7 +4926,7 @@ function getUseStore(name) {
4467
4926
  return void 0;
4468
4927
  }
4469
4928
  function cloneStore(name, useStore, config2) {
4470
- const oldStoreName = useStore["$storeName"];
4929
+ const oldStoreName = useStore.$storeName ?? "";
4471
4930
  const cached = StoreCache.get(oldStoreName);
4472
4931
  const oldStoreCreator = cached?.creator;
4473
4932
  const oldConfig = cached?.config || {};
@@ -4488,16 +4947,12 @@ function isStoreActive(name) {
4488
4947
  }
4489
4948
  var cellCount = 0;
4490
4949
  function cell(data) {
4491
- return createState(data, {
4492
- belong: LARK_GLOBAL,
4493
- linkKeys: `${LARK_GLOBAL}_${cellCount++}`
4494
- });
4950
+ const linkKeys = `${LARK_GLOBAL}_${cellCount++}`;
4951
+ return createState(data, { belong: LARK_GLOBAL, linkKeys });
4495
4952
  }
4496
4953
  function observeCell(state, cb, immediate = true) {
4497
4954
  const linkKeys = getLinkKeys(state);
4498
- if (!linkKeys)
4499
- return () => {
4500
- };
4955
+ if (!linkKeys) return noop;
4501
4956
  const keys2 = linkKeys.split(".");
4502
4957
  const key = keys2[keys2.length - 1];
4503
4958
  const list = [{ key, cb }];
@@ -4506,30 +4961,32 @@ function observeCell(state, cb, immediate = true) {
4506
4961
  return () => clear({ belong: LARK_GLOBAL, clearList: list });
4507
4962
  }
4508
4963
  function multi(useStore) {
4509
- const storeName = useStore["$storeName"];
4964
+ const storeName = useStore.$storeName ?? "";
4510
4965
  const flagSym = `lark-comp-${storeName}`;
4511
4966
  const map = /* @__PURE__ */ new Map();
4512
4967
  let rootViewPath;
4513
4968
  const getFlag = (viewContext) => {
4514
- const owner = viewContext["owner"];
4515
- const viewPath = owner?.["path"] || "";
4516
- const viewId = owner?.["id"] || "";
4969
+ const owner = viewContext.owner;
4970
+ const viewPath = owner?.path ?? "";
4971
+ const viewId = owner?.id ?? "";
4517
4972
  let flag;
4518
4973
  if (viewPath === rootViewPath) {
4519
4974
  flag = `${flagSym}-${viewId}`;
4520
4975
  } else {
4521
- flag = owner?.["viewInitParams"]?.[flagSym];
4976
+ const initParams = owner?.viewInitParams;
4977
+ const candidate = initParams?.[flagSym];
4978
+ flag = typeof candidate === "string" ? candidate : void 0;
4522
4979
  }
4523
- if (owner && isFunction(owner["mountFrame"])) {
4524
- const rawMountFrame = owner["mountFrame"];
4525
- owner["mountFrame"] = (vfId, viewPath2, viewInitParams = {}) => rawMountFrame.call(
4980
+ if (owner && isFunction(owner.mountFrame)) {
4981
+ const rawMountFrame = owner.mountFrame;
4982
+ owner.mountFrame = (frameId, viewPath2, viewInitParams = {}) => rawMountFrame.call(
4526
4983
  owner,
4527
- vfId,
4984
+ frameId,
4528
4985
  viewPath2,
4529
4986
  Object.assign(viewInitParams, { [flagSym]: flag })
4530
4987
  );
4531
4988
  }
4532
- return flag;
4989
+ return flag ?? "";
4533
4990
  };
4534
4991
  const useFn = ((view) => {
4535
4992
  if (!view)
@@ -4537,7 +4994,8 @@ function multi(useStore) {
4537
4994
  "[@lark.js/mvc error] multi: cannot find the view instance"
4538
4995
  );
4539
4996
  const viewCtx = view;
4540
- const flag = viewCtx[flagSym];
4997
+ const tag = viewCtx[flagSym];
4998
+ const flag = typeof tag === "string" ? tag : "";
4541
4999
  if (map.has(flag)) return map.get(flag);
4542
5000
  const newFn = cloneStore(flag, useStore);
4543
5001
  map.set(flag, newFn);
@@ -4546,8 +5004,7 @@ function multi(useStore) {
4546
5004
  const mixinObj = {
4547
5005
  make() {
4548
5006
  if (!rootViewPath) {
4549
- const owner = this["owner"];
4550
- rootViewPath = owner?.["path"] || "";
5007
+ rootViewPath = this.owner?.path ?? "";
4551
5008
  }
4552
5009
  this[flagSym] = getFlag(this);
4553
5010
  }
@@ -4754,7 +5211,7 @@ function convertArtExpression(code, debug, lineNo, blockStack = []) {
4754
5211
  return `${debugPrefix}<%for(${forExpr}){%>`;
4755
5212
  }
4756
5213
  const tokens = code.split(/\s+/);
4757
- const keyword = tokens.shift();
5214
+ const keyword = tokens.shift() ?? "";
4758
5215
  switch (keyword) {
4759
5216
  case "if": {
4760
5217
  blockStack.push({ ctrl: "if", line: lineNo });
@@ -4978,13 +5435,9 @@ function compileToFunction(source, debug, file) {
4978
5435
  }
4979
5436
  const viewIdRegExp = new RegExp(String.fromCharCode(31), "g");
4980
5437
  funcSource = funcSource.replace(viewIdRegExp, `'+$viewId+'`);
4981
- const atRule = hasAtRule ? `if(!$refFn){$refFn=(ref,v,k,f)=>{for(f=ref[$splitter];--f;)if(ref[k=$splitter+f]===v)return k;ref[k=$splitter+ref[$splitter]++]=v;return k;}}` : "";
4982
- const encode = `if(!$strSafe){let $entMap={'&':'amp','<':'lt','>':'gt','"':'#34','\\'':'#39','\`':'#96'},$entReg=/[&<>"'\`]/g,$entFn=m=>'&'+$entMap[m]+';';$strSafe=v=>''+(v==null?'':v);$encHtml=v=>$strSafe(v).replace($entReg,$entFn)}`;
4983
- const encodeURIMore = `if(!$encUri){let $uriMap={'!':'%21','\\'':'%27','(':'%28',')':'%29','*':'%2A'},$uriFn=m=>$uriMap[m],$uriReg=/[!')(*]/g;$encUri=v=>encodeURIComponent($strSafe(v)).replace($uriReg,$uriFn)}`;
4984
- const encodeQuote = `if(!$encQuote){let $qReg=/['"\\\\]/g;$encQuote=v=>$strSafe(v).replace($qReg,'\\\\$&')}`;
5438
+ void hasAtRule;
4985
5439
  const refFallback = "if(!$refAlt)$refAlt=$data;";
4986
- const fns = `${refFallback}${encode}${encodeURIMore}${encodeQuote}${atRule};`;
4987
- const fullSource = `${fns}let $splitter='\\x1e',$tmp,$out=''{{VARS}};${funcSource}return $out`;
5440
+ const fullSource = `${refFallback}let $splitter='\\x1e',$tmp,$out=''{{VARS}};${funcSource}return $out`;
4988
5441
  return `($data,$viewId,$refAlt,$encHtml,$strSafe,$encUri,$refFn,$encQuote)=>{${fullSource}}`;
4989
5442
  }
4990
5443
  function compileTemplate(source, options = {}) {
@@ -4996,15 +5449,12 @@ function compileTemplate(source, options = {}) {
4996
5449
  const funcBody = compileToFunction(finalSource, debug, file);
4997
5450
  const varDeclarations = globalVars.map((key) => `,${key}=$data.${key}`).join("");
4998
5451
  const funcWithVars = funcBody.replace("{{VARS}}", () => varDeclarations);
4999
- return `export default function(data, selfId, refData) {
5452
+ return `import { encHtml as __larkEncHtml, strSafe as __larkStrSafe, encUri as __larkEncUri, encQuote as __larkEncQuote, refFn as __larkRefFn } from "@lark.js/mvc/runtime";
5453
+ export default function(data, viewId, refData) {
5000
5454
  let $data = data || {},
5001
- $viewId = selfId || '';
5455
+ $viewId = viewId || '';
5002
5456
  return (${funcWithVars})($data, $viewId, refData,
5003
- /* $encHtml */ v => String(v == null ? '' : v).replace(/[&<>"'\`]/g, m => '&' + ({'&':'amp','<':'lt','>':'gt','"':'#34',"'":'#39','\`':'#96'})[m] + ';'),
5004
- /* $strSafe */ v => String(v == null ? '' : v),
5005
- /* $encUri */ null,
5006
- /* $refFn */ null,
5007
- /* $encQuote */ null
5457
+ __larkEncHtml, __larkStrSafe, __larkEncUri, __larkRefFn, __larkEncQuote
5008
5458
  );
5009
5459
  }`;
5010
5460
  }
@@ -5129,31 +5579,37 @@ function walkAst(ast, visitors) {
5129
5579
  if (visitors[type]) {
5130
5580
  visitors[type](node);
5131
5581
  }
5582
+ const bag = node;
5132
5583
  for (const key of Object.keys(node)) {
5133
5584
  if (key === "type" || key === "start" || key === "end" || key === "loc" || key === "range")
5134
5585
  continue;
5135
- if (type === "MemberExpression" && key === "property" && !node.computed)
5136
- continue;
5137
- if (type === "ObjectProperty" && key === "key" && !node.computed) {
5138
- continue;
5586
+ if (type === "MemberExpression" && key === "property") {
5587
+ const me = node;
5588
+ if (!me.computed) continue;
5139
5589
  }
5140
- if (type === "ObjectMethod" && key === "key" && !node.computed) {
5141
- continue;
5590
+ if (type === "ObjectProperty" && key === "key") {
5591
+ const op = node;
5592
+ if (!op.computed) continue;
5142
5593
  }
5143
- const child = node[key];
5594
+ if (type === "ObjectMethod" && key === "key") {
5595
+ const om = node;
5596
+ if (!om.computed) continue;
5597
+ }
5598
+ const child = bag[key];
5144
5599
  if (Array.isArray(child)) {
5145
5600
  for (const item of child) {
5146
- if (item && typeof item === "object" && typeof item.type === "string") {
5147
- visit(item);
5148
- }
5601
+ if (isAstNode(item)) visit(item);
5149
5602
  }
5150
- } else if (child && typeof child === "object" && typeof child.type === "string") {
5603
+ } else if (isAstNode(child)) {
5151
5604
  visit(child);
5152
5605
  }
5153
5606
  }
5154
5607
  }
5155
5608
  visit(ast);
5156
5609
  }
5610
+ function isAstNode(v) {
5611
+ return !!v && typeof v === "object" && typeof v.type === "string";
5612
+ }
5157
5613
  var BUILTIN_GLOBALS = {
5158
5614
  // ─── Template runtime helpers (injected by compileToFunction) ───────
5159
5615
  //
@@ -5308,10 +5764,12 @@ var BUILTIN_GLOBAL_SET = new Set(Object.keys(BUILTIN_GLOBALS));
5308
5764
  0 && (module.exports = {
5309
5765
  CALL_BREAK_TIME,
5310
5766
  Cache,
5767
+ CrossSite,
5311
5768
  EVENT_METHOD_REGEXP,
5312
5769
  EventDelegator,
5313
5770
  EventEmitter,
5314
5771
  Frame,
5772
+ FrameVisualBridge,
5315
5773
  Framework,
5316
5774
  LARK_VIEW,
5317
5775
  Payload,
@@ -5330,13 +5788,14 @@ var BUILTIN_GLOBAL_SET = new Set(Object.keys(BUILTIN_GLOBALS));
5330
5788
  applyVdomOps,
5331
5789
  assign,
5332
5790
  cell,
5333
- classExtend,
5334
5791
  cloneData,
5335
5792
  cloneStore,
5336
5793
  compileTemplate,
5794
+ computed,
5337
5795
  createState,
5338
5796
  createVdomRef,
5339
5797
  defineStore,
5798
+ defineView,
5340
5799
  delStore,
5341
5800
  encodeHTML,
5342
5801
  encodeQ,
@@ -5344,6 +5803,7 @@ var BUILTIN_GLOBAL_SET = new Set(Object.keys(BUILTIN_GLOBALS));
5344
5803
  encodeURIExtra,
5345
5804
  ensureElementId,
5346
5805
  extractGlobalVars,
5806
+ frameworkConfig,
5347
5807
  funcWithTry,
5348
5808
  generateId,
5349
5809
  getAttribute,
@@ -5351,8 +5811,9 @@ var BUILTIN_GLOBAL_SET = new Set(Object.keys(BUILTIN_GLOBALS));
5351
5811
  getPlatform,
5352
5812
  getStore,
5353
5813
  getUseStore,
5354
- has,
5814
+ hasOwnProperty,
5355
5815
  installFrameVisualizerBridge,
5816
+ invalidateViewClass,
5356
5817
  isPlainObject,
5357
5818
  isPrimitive,
5358
5819
  isPrimitiveOrFunc,
@@ -5371,6 +5832,7 @@ var BUILTIN_GLOBAL_SET = new Set(Object.keys(BUILTIN_GLOBALS));
5371
5832
  observeCell,
5372
5833
  parseUri,
5373
5834
  registerViewClass,
5835
+ resetProjectsMap,
5374
5836
  safeguard,
5375
5837
  serializeFrameTree,
5376
5838
  setData,
@@ -5382,6 +5844,7 @@ var BUILTIN_GLOBAL_SET = new Set(Object.keys(BUILTIN_GLOBALS));
5382
5844
  toUri,
5383
5845
  translateData,
5384
5846
  unmark,
5847
+ use,
5385
5848
  vdomGetCompareKey,
5386
5849
  vdomGetNode,
5387
5850
  vdomSetAttributes,