@askrjs/askr 0.0.1 → 0.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (50) hide show
  1. package/README.md +18 -10
  2. package/dist/chunk-KR6HG7HF.js +38 -0
  3. package/dist/chunk-KR6HG7HF.js.map +1 -0
  4. package/dist/{chunk-L7RL4LYV.js → chunk-MIPES65F.js} +1486 -1905
  5. package/dist/chunk-MIPES65F.js.map +1 -0
  6. package/dist/{chunk-HIWJVOS4.js → chunk-PFOLLB6A.js} +38 -17
  7. package/dist/chunk-PFOLLB6A.js.map +1 -0
  8. package/dist/chunk-QECQ2TF6.js +28 -0
  9. package/dist/chunk-QECQ2TF6.js.map +1 -0
  10. package/dist/{chunk-UUM5W2RM.js → chunk-RJWOOUYV.js} +2 -2
  11. package/dist/chunk-RJWOOUYV.js.map +1 -0
  12. package/dist/index.cjs +1760 -1972
  13. package/dist/index.cjs.map +1 -1
  14. package/dist/index.d.cts +52 -40
  15. package/dist/index.d.ts +52 -40
  16. package/dist/index.js +226 -52
  17. package/dist/index.js.map +1 -1
  18. package/dist/jsx/jsx-dev-runtime.cjs +9 -3
  19. package/dist/jsx/jsx-dev-runtime.cjs.map +1 -1
  20. package/dist/jsx/jsx-dev-runtime.d.cts +4 -9
  21. package/dist/jsx/jsx-dev-runtime.d.ts +4 -9
  22. package/dist/jsx/jsx-dev-runtime.js +10 -4
  23. package/dist/jsx/jsx-dev-runtime.js.map +1 -1
  24. package/dist/jsx/jsx-runtime.cjs +14 -5
  25. package/dist/jsx/jsx-runtime.cjs.map +1 -1
  26. package/dist/jsx/jsx-runtime.d.cts +9 -6
  27. package/dist/jsx/jsx-runtime.d.ts +9 -6
  28. package/dist/jsx/jsx-runtime.js +6 -2
  29. package/dist/{navigate-NLQOZQGM.js → navigate-SDZNA2ZE.js} +5 -5
  30. package/dist/{route-TVYWYCEJ.js → route-P5YQBT4T.js} +4 -4
  31. package/dist/{ssr-4ELUFK65.js → ssr-65K3IJ6B.js} +9 -5
  32. package/dist/{types-DUDmnzD8.d.cts → types-DLTViI21.d.cts} +15 -3
  33. package/dist/{types-DUDmnzD8.d.ts → types-DLTViI21.d.ts} +15 -3
  34. package/package.json +5 -3
  35. package/src/jsx/index.ts +4 -0
  36. package/src/jsx/jsx-dev-runtime.ts +7 -10
  37. package/src/jsx/jsx-runtime.ts +23 -11
  38. package/src/jsx/types.ts +22 -3
  39. package/src/jsx/utils.ts +19 -0
  40. package/dist/chunk-4CV4JOE5.js +0 -27
  41. package/dist/chunk-HIWJVOS4.js.map +0 -1
  42. package/dist/chunk-L7RL4LYV.js.map +0 -1
  43. package/dist/chunk-UUM5W2RM.js.map +0 -1
  44. package/dist/chunk-YNH3D4KW.js +0 -29
  45. package/dist/chunk-YNH3D4KW.js.map +0 -1
  46. package/dist/ssr-4ELUFK65.js.map +0 -1
  47. package/src/jsx/react-jsx-runtime.d.ts +0 -0
  48. /package/dist/{chunk-4CV4JOE5.js.map → navigate-SDZNA2ZE.js.map} +0 -0
  49. /package/dist/{navigate-NLQOZQGM.js.map → route-P5YQBT4T.js.map} +0 -0
  50. /package/dist/{route-TVYWYCEJ.js.map → ssr-65K3IJ6B.js.map} +0 -0
package/dist/index.js CHANGED
@@ -2,7 +2,7 @@ import {
2
2
  initializeNavigation,
3
3
  navigate,
4
4
  registerAppInstance
5
- } from "./chunk-UUM5W2RM.js";
5
+ } from "./chunk-RJWOOUYV.js";
6
6
  import {
7
7
  SSRDataMissingError,
8
8
  collectResources,
@@ -15,7 +15,7 @@ import {
15
15
  renderToStringSyncForUrl,
16
16
  resolveResources,
17
17
  throwSSRDataMissing
18
- } from "./chunk-HIWJVOS4.js";
18
+ } from "./chunk-PFOLLB6A.js";
19
19
  import {
20
20
  cleanupComponent,
21
21
  clearRoutes,
@@ -32,36 +32,41 @@ import {
32
32
  globalScheduler,
33
33
  init_component,
34
34
  init_context,
35
- init_dom,
36
- init_fastlane,
35
+ init_fastlane_shared,
37
36
  init_invariant,
38
37
  init_logger,
38
+ init_renderer,
39
39
  init_scheduler,
40
40
  invariant,
41
41
  isBulkCommitActive,
42
42
  logger,
43
43
  mountComponent,
44
44
  readContext,
45
+ registerMountOperation,
45
46
  removeAllListeners,
46
47
  route,
47
48
  scheduleEventHandler,
48
49
  setServerLocation,
49
50
  unloadNamespace,
50
51
  withAsyncResourceContext
51
- } from "./chunk-L7RL4LYV.js";
52
+ } from "./chunk-MIPES65F.js";
52
53
  import {
53
- Fragment,
54
+ Fragment as Fragment2,
54
55
  init_jsx_runtime,
55
56
  jsx,
56
57
  jsxs
57
- } from "./chunk-YNH3D4KW.js";
58
- import "./chunk-4CV4JOE5.js";
58
+ } from "./chunk-KR6HG7HF.js";
59
+ import {
60
+ ELEMENT_TYPE,
61
+ Fragment,
62
+ init_types
63
+ } from "./chunk-QECQ2TF6.js";
59
64
 
60
65
  // src/runtime/state.ts
61
66
  init_scheduler();
62
67
  init_component();
63
68
  init_invariant();
64
- init_fastlane();
69
+ init_fastlane_shared();
65
70
  function state(initialValue) {
66
71
  const instance = getCurrentInstance();
67
72
  if (!instance) {
@@ -117,7 +122,7 @@ function createStateCell(initialValue, instance) {
117
122
  }
118
123
  read._readers = readers;
119
124
  read._owner = instance;
120
- read.set = (newValue) => {
125
+ read.set = (newValueOrUpdater) => {
121
126
  const currentInst = getCurrentInstance();
122
127
  if (currentInst !== null && process.env.NODE_ENV !== "production") {
123
128
  throw new Error(
@@ -127,6 +132,13 @@ function createStateCell(initialValue, instance) {
127
132
  if (currentInst !== null && process.env.NODE_ENV === "production") {
128
133
  return;
129
134
  }
135
+ let newValue;
136
+ if (typeof newValueOrUpdater === "function") {
137
+ const updater = newValueOrUpdater;
138
+ newValue = updater(value);
139
+ } else {
140
+ newValue = newValueOrUpdater;
141
+ }
130
142
  if (Object.is(value, newValue)) return;
131
143
  if (isBulkCommitActive()) {
132
144
  value = newValue;
@@ -157,8 +169,8 @@ function createStateCell(initialValue, instance) {
157
169
  );
158
170
  if (ownerShouldEnqueue && !instance.hasPendingUpdate) {
159
171
  instance.hasPendingUpdate = true;
160
- const task = instance._pendingFlushTask;
161
- if (task) globalScheduler.enqueue(task);
172
+ const task2 = instance._pendingFlushTask;
173
+ if (task2) globalScheduler.enqueue(task2);
162
174
  else
163
175
  globalScheduler.enqueue(() => {
164
176
  instance.hasPendingUpdate = false;
@@ -253,7 +265,14 @@ var ResourceCell = class {
253
265
  this.pending = false;
254
266
  this.error = err;
255
267
  try {
256
- logger.error("[Askr] Async resource error:", err);
268
+ if (this.ownerName) {
269
+ logger.error(
270
+ `[Askr] Async resource error in ${this.ownerName}:`,
271
+ err
272
+ );
273
+ } else {
274
+ logger.error("[Askr] Async resource error:", err);
275
+ }
257
276
  } catch {
258
277
  }
259
278
  this.notifySubscribers();
@@ -269,6 +288,17 @@ var ResourceCell = class {
269
288
  }
270
289
  };
271
290
 
291
+ // src/shared/derive_cache.ts
292
+ var deriveCacheMap = /* @__PURE__ */ new WeakMap();
293
+ function getDeriveCache(instance) {
294
+ let cache = deriveCacheMap.get(instance);
295
+ if (!cache) {
296
+ cache = /* @__PURE__ */ new Map();
297
+ deriveCacheMap.set(instance, cache);
298
+ }
299
+ return cache;
300
+ }
301
+
272
302
  // src/runtime/operations.ts
273
303
  function resource(fn, deps = []) {
274
304
  const instance = getCurrentComponentInstance();
@@ -339,6 +369,7 @@ function resource(fn, deps = []) {
339
369
  if (!h.cell) {
340
370
  const frame = getCurrentContextFrame();
341
371
  const cell2 = new ResourceCell(fn, deps, frame);
372
+ cell2.ownerName = inst.fn?.name || "<anonymous>";
342
373
  h.cell = cell2;
343
374
  h.snapshot = cell2.snapshot;
344
375
  const unsubscribe = cell2.subscribe(() => {
@@ -401,34 +432,100 @@ function resource(fn, deps = []) {
401
432
  }
402
433
  return h.snapshot;
403
434
  }
435
+ function derive(source, map) {
436
+ if (map === void 0 && typeof source === "function") {
437
+ const value2 = source();
438
+ if (value2 == null) return null;
439
+ const instance2 = getCurrentComponentInstance();
440
+ if (!instance2) {
441
+ return value2;
442
+ }
443
+ const cache2 = getDeriveCache(instance2);
444
+ if (cache2.has(value2)) return cache2.get(value2);
445
+ cache2.set(value2, value2);
446
+ return value2;
447
+ }
448
+ let value;
449
+ if (typeof source === "function" && !("value" in source)) {
450
+ value = source();
451
+ } else {
452
+ value = source?.value ?? source;
453
+ }
454
+ if (value == null) return null;
455
+ const instance = getCurrentComponentInstance();
456
+ if (!instance) {
457
+ return map(value);
458
+ }
459
+ const cache = getDeriveCache(instance);
460
+ if (cache.has(value)) {
461
+ return cache.get(value);
462
+ }
463
+ const result = map(value);
464
+ cache.set(value, result);
465
+ return result;
466
+ }
467
+ function task(fn) {
468
+ const ownerIsRoot = getCurrentComponentInstance()?.isRoot ?? false;
469
+ registerMountOperation(async () => {
470
+ if (!ownerIsRoot) {
471
+ throw new Error("[Askr] task() may only be used in root components");
472
+ }
473
+ return await fn();
474
+ });
475
+ }
404
476
 
405
- // src/app/createApp.ts
477
+ // src/boot/index.ts
406
478
  init_component();
407
479
  init_scheduler();
408
480
  init_logger();
409
- init_dom();
481
+ init_renderer();
410
482
  var componentIdCounter = 0;
411
483
  var instancesByRoot = /* @__PURE__ */ new WeakMap();
412
484
  var CLEANUP_SYMBOL = /* @__PURE__ */ Symbol.for("__tempoCleanup__");
413
- function createApp(config) {
414
- if (!config || typeof config !== "object") {
415
- throw new Error("createApp requires a config object");
416
- }
417
- if ("routes" in config) {
418
- throw new Error(
419
- "The `createApp` API is removed. Use `createSPA({ root, routes })` for routed apps, or `hydrateSPA({ root, routes })` for SSR hydration."
420
- );
421
- }
422
- const appCfg = config;
423
- createIsland({
424
- root: appCfg.root,
425
- component: appCfg.component
426
- });
427
- }
428
485
  function attachCleanupForRoot(rootElement, instance) {
429
486
  rootElement[CLEANUP_SYMBOL] = () => {
430
- removeAllListeners(rootElement);
431
- cleanupComponent(instance);
487
+ const errors = [];
488
+ try {
489
+ removeAllListeners(rootElement);
490
+ } catch (e) {
491
+ errors.push(e);
492
+ }
493
+ try {
494
+ const descendants = rootElement.querySelectorAll("*");
495
+ for (const d of Array.from(descendants)) {
496
+ try {
497
+ const inst = d.__ASKR_INSTANCE;
498
+ if (inst) {
499
+ try {
500
+ cleanupComponent(inst);
501
+ } catch (err) {
502
+ errors.push(err);
503
+ }
504
+ try {
505
+ delete d.__ASKR_INSTANCE;
506
+ } catch (err) {
507
+ errors.push(err);
508
+ }
509
+ }
510
+ } catch (err) {
511
+ errors.push(err);
512
+ }
513
+ }
514
+ } catch (e) {
515
+ errors.push(e);
516
+ }
517
+ try {
518
+ cleanupComponent(instance);
519
+ } catch (e) {
520
+ errors.push(e);
521
+ }
522
+ if (errors.length > 0) {
523
+ if (instance.cleanupStrict) {
524
+ throw new AggregateError(errors, `cleanup failed for app root`);
525
+ } else if (process.env.NODE_ENV !== "production") {
526
+ for (const err of errors) logger.warn("[Askr] cleanup error:", err);
527
+ }
528
+ }
432
529
  };
433
530
  try {
434
531
  const descriptor = Object.getOwnPropertyDescriptor(rootElement, "innerHTML") || Object.getOwnPropertyDescriptor(
@@ -442,8 +539,20 @@ function attachCleanupForRoot(rootElement, instance) {
442
539
  } : void 0,
443
540
  set: function(value) {
444
541
  if (value === "" && instancesByRoot.get(this) === instance) {
445
- removeAllListeners(rootElement);
446
- cleanupComponent(instance);
542
+ try {
543
+ removeAllListeners(rootElement);
544
+ } catch (e) {
545
+ if (instance.cleanupStrict) throw e;
546
+ if (process.env.NODE_ENV !== "production")
547
+ logger.warn("[Askr] cleanup error:", e);
548
+ }
549
+ try {
550
+ cleanupComponent(instance);
551
+ } catch (e) {
552
+ if (instance.cleanupStrict) throw e;
553
+ if (process.env.NODE_ENV !== "production")
554
+ logger.warn("[Askr] cleanup error:", e);
555
+ }
447
556
  }
448
557
  if (descriptor.set) {
449
558
  return descriptor.set.call(this, value);
@@ -455,19 +564,27 @@ function attachCleanupForRoot(rootElement, instance) {
455
564
  } catch {
456
565
  }
457
566
  }
458
- function mountOrUpdate(rootElement, componentFn) {
567
+ function mountOrUpdate(rootElement, componentFn, options) {
459
568
  const existingCleanup = rootElement[CLEANUP_SYMBOL];
460
569
  if (existingCleanup) existingCleanup();
461
570
  let instance = instancesByRoot.get(rootElement);
462
571
  if (instance) {
463
572
  removeAllListeners(rootElement);
464
- cleanupComponent(instance);
573
+ try {
574
+ cleanupComponent(instance);
575
+ } catch (e) {
576
+ if (process.env.NODE_ENV !== "production")
577
+ logger.warn("[Askr] prior cleanup threw:", e);
578
+ }
465
579
  instance.fn = componentFn;
466
580
  instance.evaluationGeneration++;
467
581
  instance.mounted = false;
468
582
  instance.expectedStateIndices = [];
469
583
  instance.firstRenderComplete = false;
470
584
  instance.isRoot = true;
585
+ if (options && typeof options.cleanupStrict === "boolean") {
586
+ instance.cleanupStrict = options.cleanupStrict;
587
+ }
471
588
  } else {
472
589
  const componentId = String(++componentIdCounter);
473
590
  instance = createComponentInstance(
@@ -478,6 +595,9 @@ function mountOrUpdate(rootElement, componentFn) {
478
595
  );
479
596
  instancesByRoot.set(rootElement, instance);
480
597
  instance.isRoot = true;
598
+ if (options && typeof options.cleanupStrict === "boolean") {
599
+ instance.cleanupStrict = options.cleanupStrict;
600
+ }
481
601
  }
482
602
  attachCleanupForRoot(rootElement, instance);
483
603
  mountComponent(instance);
@@ -497,7 +617,9 @@ function createIsland(config) {
497
617
  "createIsland does not accept routes; use createSPA for routed apps"
498
618
  );
499
619
  }
500
- mountOrUpdate(rootElement, config.component);
620
+ mountOrUpdate(rootElement, config.component, {
621
+ cleanupStrict: config.cleanupStrict
622
+ });
501
623
  }
502
624
  async function createSPA(config) {
503
625
  if (!config || typeof config !== "object") {
@@ -510,7 +632,7 @@ async function createSPA(config) {
510
632
  }
511
633
  const rootElement = typeof config.root === "string" ? document.getElementById(config.root) : config.root;
512
634
  if (!rootElement) throw new Error(`Root element not found: ${config.root}`);
513
- const { clearRoutes: clearRoutes2, route: route2, lockRouteRegistration, resolveRoute } = await import("./route-TVYWYCEJ.js");
635
+ const { clearRoutes: clearRoutes2, route: route2, lockRouteRegistration, resolveRoute } = await import("./route-P5YQBT4T.js");
514
636
  clearRoutes2();
515
637
  for (const r of config.routes) {
516
638
  route2(r.path, r.handler, r.namespace);
@@ -524,14 +646,18 @@ async function createSPA(config) {
524
646
  `createSPA: no route found for current path (${path}). Mounting empty placeholder; navigation will activate routes when requested.`
525
647
  );
526
648
  }
527
- mountOrUpdate(rootElement, () => ({ type: "div", children: [] }));
649
+ mountOrUpdate(rootElement, () => ({ type: "div", children: [] }), {
650
+ cleanupStrict: false
651
+ });
528
652
  const instance2 = instancesByRoot.get(rootElement);
529
653
  if (!instance2) throw new Error("Internal error: app instance missing");
530
654
  registerAppInstance(instance2, path);
531
655
  initializeNavigation();
532
656
  return;
533
657
  }
534
- mountOrUpdate(rootElement, resolved.handler);
658
+ mountOrUpdate(rootElement, resolved.handler, {
659
+ cleanupStrict: false
660
+ });
535
661
  const instance = instancesByRoot.get(rootElement);
536
662
  if (!instance) throw new Error("Internal error: app instance missing");
537
663
  registerAppInstance(instance, path);
@@ -555,7 +681,7 @@ async function hydrateSPA(config) {
555
681
  setServerLocation: setServerLocation2,
556
682
  lockRouteRegistration,
557
683
  resolveRoute
558
- } = await import("./route-TVYWYCEJ.js");
684
+ } = await import("./route-P5YQBT4T.js");
559
685
  clearRoutes2();
560
686
  for (const r of config.routes) {
561
687
  route2(r.path, r.handler, r.namespace);
@@ -567,7 +693,7 @@ async function hydrateSPA(config) {
567
693
  if (!resolved) {
568
694
  throw new Error(`hydrateSPA: no route found for current path (${path}).`);
569
695
  }
570
- const { renderToStringSync: renderToStringSync2 } = await import("./ssr-4ELUFK65.js");
696
+ const { renderToStringSync: renderToStringSync2 } = await import("./ssr-65K3IJ6B.js");
571
697
  const expectedHTML = renderToStringSync2(() => {
572
698
  const out = resolved.handler(resolved.params);
573
699
  return out ?? {
@@ -584,8 +710,10 @@ async function hydrateSPA(config) {
584
710
  "[Askr] Hydration mismatch detected. Server HTML does not match expected server-render output."
585
711
  );
586
712
  }
587
- mountOrUpdate(rootElement, resolved.handler);
588
- const { registerAppInstance: registerAppInstance2, initializeNavigation: initializeNavigation2 } = await import("./navigate-NLQOZQGM.js");
713
+ mountOrUpdate(rootElement, resolved.handler, {
714
+ cleanupStrict: false
715
+ });
716
+ const { registerAppInstance: registerAppInstance2, initializeNavigation: initializeNavigation2 } = await import("./navigate-SDZNA2ZE.js");
589
717
  const instance = instancesByRoot.get(rootElement);
590
718
  if (!instance) throw new Error("Internal error: app instance missing");
591
719
  registerAppInstance2(instance, path);
@@ -606,11 +734,6 @@ function hasApp(root) {
606
734
  return instancesByRoot.has(rootElement);
607
735
  }
608
736
 
609
- // src/router/layouts.ts
610
- function layout(Layout) {
611
- return (children) => Layout({ children });
612
- }
613
-
614
737
  // src/components/Link.tsx
615
738
  function Link({ href, children }) {
616
739
  return {
@@ -635,11 +758,59 @@ function Link({ href, children }) {
635
758
  };
636
759
  }
637
760
 
761
+ // src/foundations/layout.ts
762
+ function layout(Layout) {
763
+ return (children, props) => Layout({ ...props, children });
764
+ }
765
+
766
+ // src/foundations/slot.ts
767
+ init_logger();
768
+
769
+ // src/jsx/index.ts
770
+ init_types();
771
+
772
+ // src/jsx/utils.ts
773
+ init_types();
774
+ function isElement(value) {
775
+ return typeof value === "object" && value !== null && value.$$typeof === ELEMENT_TYPE;
776
+ }
777
+ function cloneElement(element, props) {
778
+ return {
779
+ ...element,
780
+ props: { ...element.props, ...props }
781
+ };
782
+ }
783
+
784
+ // src/foundations/slot.ts
785
+ function Slot(props) {
786
+ if (props.asChild) {
787
+ const { children, ...rest } = props;
788
+ if (isElement(children)) {
789
+ return cloneElement(children, rest);
790
+ }
791
+ logger.warn("<Slot asChild> expects a single JSX element child.");
792
+ return null;
793
+ }
794
+ return { type: Fragment, props: { children: props.children } };
795
+ }
796
+
797
+ // src/foundations/portal.ts
798
+ function definePortal() {
799
+ const slot = createPortalSlot();
800
+ function PortalHost() {
801
+ return slot.read();
802
+ }
803
+ PortalHost.render = function PortalRender(props) {
804
+ slot.write(props.children);
805
+ return null;
806
+ };
807
+ return PortalHost;
808
+ }
809
+
638
810
  // src/index.ts
639
811
  init_jsx_runtime();
640
812
  if (typeof globalThis !== "undefined") {
641
813
  const g = globalThis;
642
- if (!g.createApp) g.createApp = createApp;
643
814
  if (!g.createIsland) g.createIsland = createIsland;
644
815
  if (!g.createSPA) g.createSPA = createSPA;
645
816
  if (!g.hydrateSPA) g.hydrateSPA = hydrateSPA;
@@ -648,15 +819,17 @@ if (typeof globalThis !== "undefined") {
648
819
  if (!g.navigate) g.navigate = navigate;
649
820
  }
650
821
  export {
651
- Fragment,
822
+ Fragment2 as Fragment,
652
823
  Link,
824
+ Slot,
653
825
  cleanupApp,
654
826
  clearRoutes,
655
827
  collectResources,
656
- createApp,
657
828
  createIsland,
658
829
  createSPA,
659
830
  defineContext,
831
+ definePortal,
832
+ derive,
660
833
  getLoadedNamespaces,
661
834
  getNamespaceRoutes,
662
835
  getRoutes,
@@ -678,6 +851,7 @@ export {
678
851
  scheduleEventHandler,
679
852
  setServerLocation,
680
853
  state,
854
+ task,
681
855
  unloadNamespace
682
856
  };
683
857
  //# sourceMappingURL=index.js.map