@askrjs/askr 0.0.2 → 0.0.4

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 (79) hide show
  1. package/README.md +8 -5
  2. package/dist/chunk-64C7W2AE.js +43 -0
  3. package/dist/chunk-64C7W2AE.js.map +1 -0
  4. package/dist/chunk-6FLMH4EL.js +124 -0
  5. package/dist/chunk-6FLMH4EL.js.map +1 -0
  6. package/dist/chunk-FJUXFA72.js +16 -0
  7. package/dist/chunk-FJUXFA72.js.map +1 -0
  8. package/dist/chunk-SALJX5PZ.js +26 -0
  9. package/dist/{chunk-KR6HG7HF.js.map → chunk-SALJX5PZ.js.map} +1 -1
  10. package/dist/{chunk-RJWOOUYV.js → chunk-VRAEBIJ3.js} +7 -9
  11. package/dist/chunk-VRAEBIJ3.js.map +1 -0
  12. package/dist/chunk-WTFWRSHB.js +98 -0
  13. package/dist/chunk-WTFWRSHB.js.map +1 -0
  14. package/dist/chunk-XHKZGJE3.js +2907 -0
  15. package/dist/chunk-XHKZGJE3.js.map +1 -0
  16. package/dist/chunk-Z5ZSTLYF.js +420 -0
  17. package/dist/chunk-Z5ZSTLYF.js.map +1 -0
  18. package/dist/fx/index.cjs +1193 -0
  19. package/dist/fx/index.cjs.map +1 -0
  20. package/dist/fx/index.d.cts +186 -0
  21. package/dist/fx/index.d.ts +186 -0
  22. package/dist/fx/index.js +418 -0
  23. package/dist/fx/index.js.map +1 -0
  24. package/dist/index.cjs +3020 -3506
  25. package/dist/index.cjs.map +1 -1
  26. package/dist/index.d.cts +74 -364
  27. package/dist/index.d.ts +74 -364
  28. package/dist/index.js +88 -656
  29. package/dist/index.js.map +1 -1
  30. package/dist/jsx/jsx-dev-runtime.cjs +1 -1
  31. package/dist/jsx/jsx-dev-runtime.cjs.map +1 -1
  32. package/dist/jsx/jsx-dev-runtime.d.cts +3 -2
  33. package/dist/jsx/jsx-dev-runtime.d.ts +3 -2
  34. package/dist/jsx/jsx-dev-runtime.js +2 -5
  35. package/dist/jsx/jsx-dev-runtime.js.map +1 -1
  36. package/dist/jsx/jsx-runtime.d.cts +2 -1
  37. package/dist/jsx/jsx-runtime.d.ts +2 -1
  38. package/dist/jsx/jsx-runtime.js +2 -4
  39. package/dist/{types-DLTViI21.d.cts → jsx-AzPM8gMS.d.cts} +6 -21
  40. package/dist/{types-DLTViI21.d.ts → jsx-AzPM8gMS.d.ts} +6 -21
  41. package/dist/navigate-LUVYHYZZ.js +17 -0
  42. package/dist/resources/index.cjs +1200 -0
  43. package/dist/resources/index.cjs.map +1 -0
  44. package/dist/resources/index.d.cts +21 -0
  45. package/dist/resources/index.d.ts +21 -0
  46. package/dist/resources/index.js +278 -0
  47. package/dist/resources/index.js.map +1 -0
  48. package/dist/{route-P5YQBT4T.js → route-BCND6MPK.js} +5 -4
  49. package/dist/router/index.cjs +3247 -0
  50. package/dist/router/index.cjs.map +1 -0
  51. package/dist/router/index.d.cts +64 -0
  52. package/dist/router/index.d.ts +64 -0
  53. package/dist/router/index.js +49 -0
  54. package/dist/router/index.js.map +1 -0
  55. package/dist/router-DaGtH1Sq.d.cts +36 -0
  56. package/dist/router-DaGtH1Sq.d.ts +36 -0
  57. package/dist/ssr/index.cjs +4059 -0
  58. package/dist/ssr/index.cjs.map +1 -0
  59. package/dist/ssr/index.d.cts +123 -0
  60. package/dist/ssr/index.d.ts +123 -0
  61. package/dist/ssr/index.js +666 -0
  62. package/dist/ssr/index.js.map +1 -0
  63. package/dist/types-CZ5sWur5.d.cts +23 -0
  64. package/dist/types-CZHOAiC1.d.ts +23 -0
  65. package/package.json +21 -7
  66. package/src/jsx/types.ts +4 -17
  67. package/dist/chunk-KR6HG7HF.js +0 -38
  68. package/dist/chunk-MIPES65F.js +0 -3023
  69. package/dist/chunk-MIPES65F.js.map +0 -1
  70. package/dist/chunk-PFOLLB6A.js +0 -524
  71. package/dist/chunk-PFOLLB6A.js.map +0 -1
  72. package/dist/chunk-QECQ2TF6.js +0 -28
  73. package/dist/chunk-QECQ2TF6.js.map +0 -1
  74. package/dist/chunk-RJWOOUYV.js.map +0 -1
  75. package/dist/navigate-SDZNA2ZE.js +0 -16
  76. package/dist/ssr-65K3IJ6B.js +0 -28
  77. package/dist/ssr-65K3IJ6B.js.map +0 -1
  78. /package/dist/{navigate-SDZNA2ZE.js.map → navigate-LUVYHYZZ.js.map} +0 -0
  79. /package/dist/{route-P5YQBT4T.js.map → route-BCND6MPK.js.map} +0 -0
package/README.md CHANGED
@@ -65,9 +65,12 @@ function Home() {
65
65
  );
66
66
  }
67
67
 
68
+ ```
68
69
 
69
70
  **Tip:** Prefer functional updates when updating based on previous state: `count.set(prev => prev + 1)`.
70
71
 
72
+ ```ts
73
+
71
74
  function User({ id }: { id: string }) {
72
75
  return (
73
76
  <div>
@@ -131,16 +134,16 @@ Askr doesn’t introduce a new cancellation concept. When work becomes stale (un
131
134
  Example (recommended pattern):
132
135
 
133
136
  ```ts
134
- import { route, resource, getSignal } from '@askrjs/askr';
137
+ import { route, resource } from '@askrjs/askr';
135
138
 
136
139
  function User({ id }: { id: string }) {
137
- const user = resource(async () => {
138
- const res = await fetch(`/api/users/${id}`, { signal: getSignal() });
140
+ const user = resource(async ({ signal }) => {
141
+ const res = await fetch(`/api/users/${id}`, { signal });
139
142
  return res.json();
140
143
  }, [id]);
141
144
 
142
- if (!user) return <div>Loading...</div>;
143
- return <pre>{JSON.stringify(user, null, 2)}</pre>;
145
+ if (user.pending) return <div>Loading...</div>;
146
+ return <pre>{JSON.stringify(user.value, null, 2)}</pre>;
144
147
  }
145
148
 
146
149
  route('/user/{id}', ({ id }) => <User id={id} />);
@@ -0,0 +1,43 @@
1
+ // src/common/ssr-errors.ts
2
+ var SSRDataMissingError = class _SSRDataMissingError extends Error {
3
+ constructor(message = "Server-side rendering requires all data to be available synchronously. This component attempted to use async data during SSR.") {
4
+ super(message);
5
+ this.code = "SSR_DATA_MISSING";
6
+ this.name = "SSRDataMissingError";
7
+ Object.setPrototypeOf(this, _SSRDataMissingError.prototype);
8
+ }
9
+ };
10
+
11
+ // src/runtime/ssr-bridge.ts
12
+ var defaultBridge = {
13
+ getCurrentSSRContext() {
14
+ return null;
15
+ },
16
+ throwSSRDataMissing() {
17
+ throw new Error(
18
+ "[Askr] SSR data missing (SSR bridge not installed). If you are rendering on the server, ensure you are using the askr SSR entrypoints."
19
+ );
20
+ },
21
+ getCurrentRenderData() {
22
+ return null;
23
+ },
24
+ getNextKey() {
25
+ throw new Error(
26
+ "[Askr] getNextKey() called outside SSR render phase (SSR bridge not installed)."
27
+ );
28
+ }
29
+ };
30
+ var bridge = defaultBridge;
31
+ function installSSRBridge(next) {
32
+ bridge = next;
33
+ }
34
+ function getSSRBridge() {
35
+ return bridge;
36
+ }
37
+
38
+ export {
39
+ SSRDataMissingError,
40
+ installSSRBridge,
41
+ getSSRBridge
42
+ };
43
+ //# sourceMappingURL=chunk-64C7W2AE.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/common/ssr-errors.ts","../src/runtime/ssr-bridge.ts"],"sourcesContent":["/**\n * Common call contracts: SSR error types\n */\n\nexport class SSRDataMissingError extends Error {\n readonly code = 'SSR_DATA_MISSING';\n constructor(\n message = 'Server-side rendering requires all data to be available synchronously. This component attempted to use async data during SSR.'\n ) {\n super(message);\n this.name = 'SSRDataMissingError';\n Object.setPrototypeOf(this, SSRDataMissingError.prototype);\n }\n}\n","import type { RenderContext } from '../common/ssr';\n\nexport type SSRBridge = {\n getCurrentSSRContext(): RenderContext | null;\n throwSSRDataMissing(): never;\n\n // Deterministic SSR render-phase data lookup\n getCurrentRenderData(): Record<string, unknown> | null;\n getNextKey(): string;\n};\n\nconst defaultBridge: SSRBridge = {\n getCurrentSSRContext() {\n return null;\n },\n throwSSRDataMissing() {\n throw new Error(\n '[Askr] SSR data missing (SSR bridge not installed). ' +\n 'If you are rendering on the server, ensure you are using the askr SSR entrypoints.'\n );\n },\n getCurrentRenderData() {\n return null;\n },\n getNextKey() {\n throw new Error(\n '[Askr] getNextKey() called outside SSR render phase (SSR bridge not installed).'\n );\n },\n};\n\nlet bridge: SSRBridge = defaultBridge;\n\nexport function installSSRBridge(next: SSRBridge): void {\n bridge = next;\n}\n\nexport function getSSRBridge(): SSRBridge {\n return bridge;\n}\n"],"mappings":";AAIO,IAAM,sBAAN,MAAM,6BAA4B,MAAM;AAAA,EAE7C,YACE,UAAU,iIACV;AACA,UAAM,OAAO;AAJf,SAAS,OAAO;AAKd,SAAK,OAAO;AACZ,WAAO,eAAe,MAAM,qBAAoB,SAAS;AAAA,EAC3D;AACF;;;ACFA,IAAM,gBAA2B;AAAA,EAC/B,uBAAuB;AACrB,WAAO;AAAA,EACT;AAAA,EACA,sBAAsB;AACpB,UAAM,IAAI;AAAA,MACR;AAAA,IAEF;AAAA,EACF;AAAA,EACA,uBAAuB;AACrB,WAAO;AAAA,EACT;AAAA,EACA,aAAa;AACX,UAAM,IAAI;AAAA,MACR;AAAA,IACF;AAAA,EACF;AACF;AAEA,IAAI,SAAoB;AAEjB,SAAS,iBAAiB,MAAuB;AACtD,WAAS;AACX;AAEO,SAAS,eAA0B;AACxC,SAAO;AACT;","names":[]}
@@ -0,0 +1,124 @@
1
+ import {
2
+ getCurrentInstance,
3
+ getNextStateIndex,
4
+ globalScheduler,
5
+ invariant,
6
+ isBulkCommitActive
7
+ } from "./chunk-XHKZGJE3.js";
8
+
9
+ // src/runtime/state.ts
10
+ function state(initialValue) {
11
+ const instance = getCurrentInstance();
12
+ if (!instance) {
13
+ throw new Error(
14
+ "state() can only be called during component render execution. Move state() calls to the top level of your component function."
15
+ );
16
+ }
17
+ const index = getNextStateIndex();
18
+ const stateValues = instance.stateValues;
19
+ if (index < instance.stateIndexCheck) {
20
+ throw new Error(
21
+ `State index violation: state() call at index ${index}, but previously saw index ${instance.stateIndexCheck}. This happens when state() is called conditionally (inside if/for/etc). Move all state() calls to the top level of your component function, before any conditionals.`
22
+ );
23
+ }
24
+ invariant(
25
+ index >= instance.stateIndexCheck,
26
+ "[State] State indices must increase monotonically"
27
+ );
28
+ instance.stateIndexCheck = index;
29
+ if (instance.firstRenderComplete) {
30
+ if (!instance.expectedStateIndices.includes(index)) {
31
+ throw new Error(
32
+ `Hook order violation: state() called at index ${index}, but this index was not in the first render's sequence [${instance.expectedStateIndices.join(", ")}]. This usually means state() is inside a conditional or loop. Move all state() calls to the top level of your component function.`
33
+ );
34
+ }
35
+ } else {
36
+ instance.expectedStateIndices.push(index);
37
+ }
38
+ if (stateValues[index]) {
39
+ const existing = stateValues[index];
40
+ if (existing._owner !== instance) {
41
+ throw new Error(
42
+ `State ownership violation: state() called at index ${index} is owned by a different component instance. State ownership is positional and immutable.`
43
+ );
44
+ }
45
+ return existing;
46
+ }
47
+ const cell = createStateCell(initialValue, instance);
48
+ stateValues[index] = cell;
49
+ return cell;
50
+ }
51
+ function createStateCell(initialValue, instance) {
52
+ let value = initialValue;
53
+ const readers = /* @__PURE__ */ new Map();
54
+ function read() {
55
+ read._hasBeenRead = true;
56
+ const inst = getCurrentInstance();
57
+ if (inst && inst._currentRenderToken !== void 0) {
58
+ if (!inst._pendingReadStates) inst._pendingReadStates = /* @__PURE__ */ new Set();
59
+ inst._pendingReadStates.add(read);
60
+ }
61
+ return value;
62
+ }
63
+ read._readers = readers;
64
+ read._owner = instance;
65
+ read.set = (newValueOrUpdater) => {
66
+ const currentInst = getCurrentInstance();
67
+ if (currentInst !== null) {
68
+ throw new Error(
69
+ `[Askr] state.set() cannot be called during component render. State mutations during render break the actor model and cause infinite loops. Move state updates to event handlers or use conditional rendering instead.`
70
+ );
71
+ }
72
+ let newValue;
73
+ if (typeof newValueOrUpdater === "function") {
74
+ const updater = newValueOrUpdater;
75
+ newValue = updater(value);
76
+ } else {
77
+ newValue = newValueOrUpdater;
78
+ }
79
+ if (Object.is(value, newValue)) return;
80
+ if (isBulkCommitActive()) {
81
+ value = newValue;
82
+ return;
83
+ }
84
+ value = newValue;
85
+ const readersMap = read._readers;
86
+ if (readersMap) {
87
+ for (const [subInst, token] of readersMap) {
88
+ if (subInst.lastRenderToken !== token) continue;
89
+ if (!subInst.hasPendingUpdate) {
90
+ subInst.hasPendingUpdate = true;
91
+ const subTask = subInst._pendingFlushTask;
92
+ if (subTask) globalScheduler.enqueue(subTask);
93
+ else
94
+ globalScheduler.enqueue(() => {
95
+ subInst.hasPendingUpdate = false;
96
+ subInst.notifyUpdate?.();
97
+ });
98
+ }
99
+ }
100
+ }
101
+ const readersMapForOwner = readersMap;
102
+ const ownerRecordedToken = readersMapForOwner?.get(instance);
103
+ const ownerShouldEnqueue = (
104
+ // Normal case: owner read this state in last committed render
105
+ ownerRecordedToken !== void 0 && instance.lastRenderToken === ownerRecordedToken
106
+ );
107
+ if (ownerShouldEnqueue && !instance.hasPendingUpdate) {
108
+ instance.hasPendingUpdate = true;
109
+ const task = instance._pendingFlushTask;
110
+ if (task) globalScheduler.enqueue(task);
111
+ else
112
+ globalScheduler.enqueue(() => {
113
+ instance.hasPendingUpdate = false;
114
+ instance.notifyUpdate?.();
115
+ });
116
+ }
117
+ };
118
+ return read;
119
+ }
120
+
121
+ export {
122
+ state
123
+ };
124
+ //# sourceMappingURL=chunk-6FLMH4EL.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/runtime/state.ts"],"sourcesContent":["/**\n * State primitive for Askr components\n * Optimized for minimal overhead and fast updates\n *\n * INVARIANTS ENFORCED:\n * - state() only callable during component render (currentInstance exists)\n * - state() called at top-level only (indices must be monotonically increasing)\n * - state values persist across re-renders (stored in stateValues array)\n * - state.set() cannot be called during render (causes infinite loops)\n * - state.set() always enqueues through scheduler (never direct mutation)\n * - state.set() callback (notifyUpdate) always available\n */\n\nimport { globalScheduler } from './scheduler';\nimport {\n getCurrentInstance,\n getNextStateIndex,\n type ComponentInstance,\n} from './component';\nimport { invariant } from '../dev/invariant';\nimport { isBulkCommitActive } from './fastlane';\n\n/**\n * State value holder - callable to read, has set method to update\n * @example\n * const count = state(0);\n * count(); // read: 0\n * count.set(1); // write: triggers re-render\n */\nexport interface State<T> {\n (): T;\n set(value: T): void;\n set(updater: (prev: T) => T): void;\n _hasBeenRead?: boolean; // Internal: track if state has been read during render\n _readers?: Map<ComponentInstance, number>; // Internal: map of readers -> last committed token\n}\n\n/**\n * Creates a local state value for a component\n * Optimized for:\n * - O(1) read performance\n * - Minimal allocation per state\n * - Fast scheduler integration\n *\n * IMPORTANT: state() must be called during component render execution.\n * It captures the current component instance from context.\n * Calling outside a component function will throw an error.\n *\n * @example\n * ```ts\n * // ✅ Correct: called during render\n * export function Counter() {\n * const count = state(0);\n * return { type: 'button', children: [count()] };\n * }\n *\n * // ❌ Wrong: called outside component\n * const count = state(0);\n * export function BadComponent() {\n * return { type: 'div' };\n * }\n * ```\n */\nexport function state<T>(initialValue: T): State<T> {\n // INVARIANT: state() must be called during component render\n const instance = getCurrentInstance();\n if (!instance) {\n throw new Error(\n 'state() can only be called during component render execution. ' +\n 'Move state() calls to the top level of your component function.'\n );\n }\n\n const index = getNextStateIndex();\n const stateValues = instance.stateValues;\n\n // INVARIANT: Detect conditional state() calls by validating index order\n // If indices go backward, state() was called conditionally\n if (index < instance.stateIndexCheck) {\n throw new Error(\n `State index violation: state() call at index ${index}, ` +\n `but previously saw index ${instance.stateIndexCheck}. ` +\n `This happens when state() is called conditionally (inside if/for/etc). ` +\n `Move all state() calls to the top level of your component function, ` +\n `before any conditionals.`\n );\n }\n\n // INVARIANT: stateIndexCheck advances monotonically\n invariant(\n index >= instance.stateIndexCheck,\n '[State] State indices must increase monotonically'\n );\n instance.stateIndexCheck = index;\n\n // INVARIANT: On subsequent renders, validate that state calls happen in same order\n if (instance.firstRenderComplete) {\n // Check if this index was expected based on first render\n if (!instance.expectedStateIndices.includes(index)) {\n throw new Error(\n `Hook order violation: state() called at index ${index}, ` +\n `but this index was not in the first render's sequence [${instance.expectedStateIndices.join(', ')}]. ` +\n `This usually means state() is inside a conditional or loop. ` +\n `Move all state() calls to the top level of your component function.`\n );\n }\n } else {\n // First render - record this index in the expected sequence\n instance.expectedStateIndices.push(index);\n }\n\n // INVARIANT: Reuse existing state if it exists (fast path on re-renders)\n // This ensures state identity and persistence and enforces ownership stability\n if (stateValues[index]) {\n const existing = stateValues[index] as State<T> & {\n _owner?: ComponentInstance;\n };\n // Ownership must be stable: the state cell belongs to the instance that\n // created it and must never change. This checks for accidental reuse.\n if (existing._owner !== instance) {\n throw new Error(\n `State ownership violation: state() called at index ${index} is owned by a different component instance. ` +\n `State ownership is positional and immutable.`\n );\n }\n return existing as State<T>;\n }\n\n // Create new state (slow path, only on first render) — delegated to helper\n const cell = createStateCell(initialValue, instance);\n\n // INVARIANT: Store state in instance for persistence across renders\n stateValues[index] = cell;\n\n return cell;\n}\n\n/**\n * Internal helper: create the backing state cell (value + readers + set semantics)\n * This extraction makes it easier to later split hook wiring from storage.\n */\nfunction createStateCell<T>(\n initialValue: T,\n instance: ComponentInstance\n): State<T> {\n let value = initialValue;\n\n // Per-state reader map: component -> last-committed render token\n const readers = new Map<ComponentInstance, number>();\n\n // Use a function as the state object (callable directly)\n function read(): T {\n (read as State<T>)._hasBeenRead = true;\n\n // Record that the current instance read this state during its in-progress render\n const inst = getCurrentInstance();\n if (inst && inst._currentRenderToken !== undefined) {\n if (!inst._pendingReadStates) inst._pendingReadStates = new Set();\n inst._pendingReadStates.add(read as State<T>);\n }\n\n return value;\n }\n\n // Attach the readers map to the callable so other runtime parts can access it\n (read as State<T>)._readers = readers;\n\n // Record explicit ownership of this state cell. Ownership is the component\n // instance that created the state cell and must never change for the life\n // of the cell. We expose this for runtime invariant checks/tests.\n (read as State<T> & { _owner?: ComponentInstance })._owner = instance;\n\n // Attach set method directly to function\n read.set = (newValueOrUpdater: T | ((prev: T) => T)): void => {\n // INVARIANT: State cannot be mutated during component render\n // (when currentInstance is non-null). It must be scheduled for consistency.\n const currentInst = getCurrentInstance();\n if (currentInst !== null) {\n throw new Error(\n `[Askr] state.set() cannot be called during component render. ` +\n `State mutations during render break the actor model and cause infinite loops. ` +\n `Move state updates to event handlers or use conditional rendering instead.`\n );\n }\n\n // Compute new value if an updater was provided\n let newValue: T;\n if (typeof newValueOrUpdater === 'function') {\n // Note: function-valued state cannot be set directly via a function argument;\n // such an argument is treated as a functional updater (this follows the common\n // convention from other libraries). If you need to store a function as state,\n // wrap it in an object.\n const updater = newValueOrUpdater as (prev: T) => T;\n newValue = updater(value);\n } else {\n newValue = newValueOrUpdater as T;\n }\n\n // Skip work if value didn't change\n if (Object.is(value, newValue)) return;\n\n // If a bulk commit is active, update backing value only and DO NOT notify or enqueue.\n // Bulk commits must be side-effect silent with respect to runtime notifications.\n if (isBulkCommitActive()) {\n // In bulk commit mode we must be side-effect free: update backing\n // value only and do not notify, enqueue, or log.\n value = newValue;\n return;\n }\n\n // INVARIANT: Update the value\n value = newValue;\n\n // notifyUpdate may be temporarily unavailable (e.g. during hydration).\n // We intentionally avoid logging here to keep the state mutation path\n // side-effect free. The scheduler will process updates when the system\n // is stable.\n\n // After value change, notify only components that *read* this state in their last committed render\n const readersMap = (read as State<T>)._readers as\n | Map<ComponentInstance, number>\n | undefined;\n if (readersMap) {\n for (const [subInst, token] of readersMap) {\n // Only notify if the component's last committed render token matches the token recorded\n // when it last read this state. This ensures we only wake components that actually\n // observed the state in their most recent render.\n if (subInst.lastRenderToken !== token) continue;\n if (!subInst.hasPendingUpdate) {\n // Log enqueue decision for subInst\n\n subInst.hasPendingUpdate = true;\n const subTask = subInst._pendingFlushTask;\n if (subTask) globalScheduler.enqueue(subTask);\n else\n globalScheduler.enqueue(() => {\n subInst.hasPendingUpdate = false;\n subInst.notifyUpdate?.();\n });\n }\n }\n }\n\n // OPTIMIZATION: Batch state updates from the same component within the same event loop tick\n // Only enqueue the owner component if it actually read this state during its last committed render\n const readersMapForOwner = readersMap;\n const ownerRecordedToken = readersMapForOwner?.get(instance);\n const ownerShouldEnqueue =\n // Normal case: owner read this state in last committed render\n ownerRecordedToken !== undefined &&\n instance.lastRenderToken === ownerRecordedToken;\n\n if (ownerShouldEnqueue && !instance.hasPendingUpdate) {\n instance.hasPendingUpdate = true;\n // INVARIANT: All state updates go through scheduler\n // Use prebound task to avoid allocating a closure per update\n // Fallback to a safe closure if the prebound task is not present\n const task = instance._pendingFlushTask;\n if (task) globalScheduler.enqueue(task);\n else\n globalScheduler.enqueue(() => {\n instance.hasPendingUpdate = false;\n instance.notifyUpdate?.();\n });\n }\n };\n\n return read as State<T>;\n}\n"],"mappings":"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","names":[]}
@@ -0,0 +1,16 @@
1
+ var __defProp = Object.defineProperty;
2
+ var __export = (target, all) => {
3
+ for (var name in all)
4
+ __defProp(target, name, { get: all[name], enumerable: true });
5
+ };
6
+
7
+ // src/common/jsx.ts
8
+ var ELEMENT_TYPE = /* @__PURE__ */ Symbol.for("askr.element");
9
+ var Fragment = /* @__PURE__ */ Symbol.for("askr.fragment");
10
+
11
+ export {
12
+ __export,
13
+ ELEMENT_TYPE,
14
+ Fragment
15
+ };
16
+ //# sourceMappingURL=chunk-FJUXFA72.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/common/jsx.ts"],"sourcesContent":["/**\n * Common call contracts: JSX element shape\n */\n\nimport type { Props } from './props';\n\nexport const ELEMENT_TYPE = Symbol.for('askr.element');\nexport const Fragment = Symbol.for('askr.fragment');\n\nexport interface JSXElement {\n /** Internal element marker (optional for plain vnode objects) */\n $$typeof?: symbol;\n\n /** Element type: string, component, Fragment, etc */\n type: unknown;\n\n /** Props bag */\n props: Props;\n\n /** Optional key (normalized by runtime) */\n key?: string | number | null;\n}\n"],"mappings":";;;;;;;AAMO,IAAM,eAAe,uBAAO,IAAI,cAAc;AAC9C,IAAM,WAAW,uBAAO,IAAI,eAAe;","names":[]}
@@ -0,0 +1,26 @@
1
+ // src/jsx/jsx-runtime.ts
2
+ var ELEMENT_TYPE = /* @__PURE__ */ Symbol.for("askr.element");
3
+ var Fragment = /* @__PURE__ */ Symbol.for("askr.fragment");
4
+ function jsxDEV(type, props, key) {
5
+ return {
6
+ $$typeof: ELEMENT_TYPE,
7
+ type,
8
+ props: props ?? {},
9
+ key: key ?? null
10
+ };
11
+ }
12
+ function jsx(type, props, key) {
13
+ return jsxDEV(type, props, key);
14
+ }
15
+ function jsxs(type, props, key) {
16
+ return jsxDEV(type, props, key);
17
+ }
18
+
19
+ export {
20
+ ELEMENT_TYPE,
21
+ Fragment,
22
+ jsxDEV,
23
+ jsx,
24
+ jsxs
25
+ };
26
+ //# sourceMappingURL=chunk-SALJX5PZ.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/jsx/jsx-runtime.ts"],"sourcesContent":["/**\n * JSX dev runtime\n * Same shape as production runtime, with room for dev warnings.\n */\n\nimport './types';\n\nexport const ELEMENT_TYPE = Symbol.for('askr.element');\nexport const Fragment = Symbol.for('askr.fragment');\n\nexport interface JSXElement {\n $$typeof: symbol;\n type: unknown;\n props: Record<string, unknown>;\n key: string | number | null;\n}\n\nexport function jsxDEV(\n type: unknown,\n props: Record<string, unknown> | null,\n key?: string | number\n): JSXElement {\n return {\n $$typeof: ELEMENT_TYPE,\n type,\n props: props ?? {},\n key: key ?? null,\n };\n}\n\n// Production-style helpers: alias to the DEV factory for now\nexport function jsx(\n type: unknown,\n props: Record<string, unknown> | null,\n key?: string | number\n) {\n return jsxDEV(type, props, key);\n}\n\nexport function jsxs(\n type: unknown,\n props: Record<string, unknown> | null,\n key?: string | number\n) {\n return jsxDEV(type, props, key);\n}\n\n// `Fragment` is already exported above.\n"],"mappings":";;;;;;AAiBO,SAAS,OACd,MACA,OACA,KACY;AACZ,SAAO;AAAA,IACL,UAAU;AAAA,IACV;AAAA,IACA,OAAO,SAAS,CAAC;AAAA,IACjB,KAAK,OAAO;AAAA,EACd;AACF;AAGO,SAAS,IACd,MACA,OACA,KACA;AACA,SAAO,OAAO,MAAM,OAAO,GAAG;AAChC;AAEO,SAAS,KACd,MACA,OACA,KACA;AACA,SAAO,OAAO,MAAM,OAAO,GAAG;AAChC;AA7CA,IAOa,cACA;AARb;AAAA;AAKA;AAEO,IAAM,eAAe,uBAAO,IAAI,cAAc;AAC9C,IAAM,WAAW,uBAAO,IAAI,eAAe;AAAA;AAAA;","names":[]}
1
+ {"version":3,"sources":["../src/jsx/jsx-runtime.ts"],"sourcesContent":["/**\n * JSX dev runtime\n * Same shape as production runtime, with room for dev warnings.\n */\n\nimport './types';\n\nexport const ELEMENT_TYPE = Symbol.for('askr.element');\nexport const Fragment = Symbol.for('askr.fragment');\n\nexport interface JSXElement {\n $$typeof: symbol;\n type: unknown;\n props: Record<string, unknown>;\n key: string | number | null;\n}\n\nexport function jsxDEV(\n type: unknown,\n props: Record<string, unknown> | null,\n key?: string | number\n): JSXElement {\n return {\n $$typeof: ELEMENT_TYPE,\n type,\n props: props ?? {},\n key: key ?? null,\n };\n}\n\n// Production-style helpers: alias to the DEV factory for now\nexport function jsx(\n type: unknown,\n props: Record<string, unknown> | null,\n key?: string | number\n) {\n return jsxDEV(type, props, key);\n}\n\nexport function jsxs(\n type: unknown,\n props: Record<string, unknown> | null,\n key?: string | number\n) {\n return jsxDEV(type, props, key);\n}\n\n// `Fragment` is already exported above.\n"],"mappings":";AAOO,IAAM,eAAe,uBAAO,IAAI,cAAc;AAC9C,IAAM,WAAW,uBAAO,IAAI,eAAe;AAS3C,SAAS,OACd,MACA,OACA,KACY;AACZ,SAAO;AAAA,IACL,UAAU;AAAA,IACV;AAAA,IACA,OAAO,SAAS,CAAC;AAAA,IACjB,KAAK,OAAO;AAAA,EACd;AACF;AAGO,SAAS,IACd,MACA,OACA,KACA;AACA,SAAO,OAAO,MAAM,OAAO,GAAG;AAChC;AAEO,SAAS,KACd,MACA,OACA,KACA;AACA,SAAO,OAAO,MAAM,OAAO,GAAG;AAChC;","names":[]}
@@ -1,16 +1,14 @@
1
1
  import {
2
- cleanupComponent,
3
- init_component,
4
- init_logger,
5
2
  lockRouteRegistration,
6
- logger,
7
- mountComponent,
8
3
  resolveRoute
9
- } from "./chunk-MIPES65F.js";
4
+ } from "./chunk-Z5ZSTLYF.js";
5
+ import {
6
+ cleanupComponent,
7
+ logger,
8
+ mountComponent
9
+ } from "./chunk-XHKZGJE3.js";
10
10
 
11
11
  // src/router/navigate.ts
12
- init_component();
13
- init_logger();
14
12
  var currentInstance = null;
15
13
  function registerAppInstance(instance, _path) {
16
14
  currentInstance = instance;
@@ -81,4 +79,4 @@ export {
81
79
  initializeNavigation,
82
80
  cleanupNavigation
83
81
  };
84
- //# sourceMappingURL=chunk-RJWOOUYV.js.map
82
+ //# sourceMappingURL=chunk-VRAEBIJ3.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/router/navigate.ts"],"sourcesContent":["/**\n * Client-side navigation with History API\n */\n\nimport { resolveRoute, lockRouteRegistration } from './route';\nimport {\n mountComponent,\n cleanupComponent,\n type ComponentInstance,\n} from '../runtime/component';\nimport { logger } from '../dev/logger';\n\n// Global app state for navigation\nlet currentInstance: ComponentInstance | null = null;\n\n/** Register the current app instance (called by createSPA/hydrateSPA). */\nexport function registerAppInstance(\n instance: ComponentInstance,\n _path: string\n): void {\n currentInstance = instance;\n // Lock further route registrations after the app has started — but allow tests to register routes.\n // Enforce only in production to avoid breaking test infra which registers routes dynamically.\n if (process.env.NODE_ENV === 'production') {\n lockRouteRegistration();\n }\n}\n\n/**\n * Navigate to a new path\n * Updates URL, resolves route, and re-mounts app with new handler\n */\nexport function navigate(path: string): void {\n if (typeof window === 'undefined') {\n // SSR context\n return;\n }\n\n // Resolve the new path to a route\n const resolved = resolveRoute(path);\n\n if (!resolved) {\n if (process.env.NODE_ENV !== 'production') {\n logger.warn(`No route found for path: ${path}`);\n }\n return;\n }\n\n // Update browser history\n window.history.pushState({ path }, '', path);\n\n // Re-render with the new route handler and params\n if (currentInstance) {\n // Cleanup previous route (abort pending operations)\n cleanupComponent(currentInstance);\n\n // The route handler IS the component function\n // It takes params as props and renders the route\n currentInstance.fn = resolved.handler as ComponentInstance['fn'];\n currentInstance.props = resolved.params;\n\n // Reset state to prevent leakage from previous route\n // Each route navigation starts completely fresh\n currentInstance.stateValues = [];\n currentInstance.expectedStateIndices = [];\n currentInstance.firstRenderComplete = false;\n currentInstance.stateIndexCheck = -1;\n // Increment generation to invalidate pending async evaluations from previous route\n currentInstance.evaluationGeneration++;\n currentInstance.notifyUpdate = null;\n\n // CRITICAL FIX: Create new AbortController for new route\n // Old controller is already aborted; we need a fresh one for async operations\n currentInstance.abortController = new AbortController();\n\n // Re-execute and re-mount component\n mountComponent(currentInstance);\n }\n}\n\n/**\n * Handle browser back/forward buttons\n */\nfunction handlePopState(_event: PopStateEvent): void {\n const path = window.location.pathname;\n\n if (!currentInstance) {\n return;\n }\n\n const resolved = resolveRoute(path);\n\n if (resolved) {\n // Cleanup old component\n cleanupComponent(currentInstance);\n\n // The route handler IS the component function\n currentInstance.fn = resolved.handler as ComponentInstance['fn'];\n currentInstance.props = resolved.params;\n\n // Reset state to prevent leakage from previous route\n currentInstance.stateValues = [];\n currentInstance.expectedStateIndices = [];\n currentInstance.firstRenderComplete = false;\n currentInstance.stateIndexCheck = -1;\n // Increment generation to invalidate pending async evaluations from previous route\n currentInstance.evaluationGeneration++;\n currentInstance.notifyUpdate = null;\n\n // CRITICAL FIX: Create new AbortController for back/forward navigation\n currentInstance.abortController = new AbortController();\n\n mountComponent(currentInstance);\n }\n}\n\n/**\n * Setup popstate listener for browser navigation\n */\nexport function initializeNavigation(): void {\n if (typeof window !== 'undefined') {\n window.addEventListener('popstate', handlePopState);\n }\n}\n\n/**\n * Cleanup navigation listeners\n */\nexport function cleanupNavigation(): void {\n if (typeof window !== 'undefined') {\n window.removeEventListener('popstate', handlePopState);\n }\n}\n"],"mappings":";;;;;;;;;;;AAaA,IAAI,kBAA4C;AAGzC,SAAS,oBACd,UACA,OACM;AACN,oBAAkB;AAGlB,MAAI,QAAQ,IAAI,aAAa,cAAc;AACzC,0BAAsB;AAAA,EACxB;AACF;AAMO,SAAS,SAAS,MAAoB;AAC3C,MAAI,OAAO,WAAW,aAAa;AAEjC;AAAA,EACF;AAGA,QAAM,WAAW,aAAa,IAAI;AAElC,MAAI,CAAC,UAAU;AACb,QAAI,QAAQ,IAAI,aAAa,cAAc;AACzC,aAAO,KAAK,4BAA4B,IAAI,EAAE;AAAA,IAChD;AACA;AAAA,EACF;AAGA,SAAO,QAAQ,UAAU,EAAE,KAAK,GAAG,IAAI,IAAI;AAG3C,MAAI,iBAAiB;AAEnB,qBAAiB,eAAe;AAIhC,oBAAgB,KAAK,SAAS;AAC9B,oBAAgB,QAAQ,SAAS;AAIjC,oBAAgB,cAAc,CAAC;AAC/B,oBAAgB,uBAAuB,CAAC;AACxC,oBAAgB,sBAAsB;AACtC,oBAAgB,kBAAkB;AAElC,oBAAgB;AAChB,oBAAgB,eAAe;AAI/B,oBAAgB,kBAAkB,IAAI,gBAAgB;AAGtD,mBAAe,eAAe;AAAA,EAChC;AACF;AAKA,SAAS,eAAe,QAA6B;AACnD,QAAM,OAAO,OAAO,SAAS;AAE7B,MAAI,CAAC,iBAAiB;AACpB;AAAA,EACF;AAEA,QAAM,WAAW,aAAa,IAAI;AAElC,MAAI,UAAU;AAEZ,qBAAiB,eAAe;AAGhC,oBAAgB,KAAK,SAAS;AAC9B,oBAAgB,QAAQ,SAAS;AAGjC,oBAAgB,cAAc,CAAC;AAC/B,oBAAgB,uBAAuB,CAAC;AACxC,oBAAgB,sBAAsB;AACtC,oBAAgB,kBAAkB;AAElC,oBAAgB;AAChB,oBAAgB,eAAe;AAG/B,oBAAgB,kBAAkB,IAAI,gBAAgB;AAEtD,mBAAe,eAAe;AAAA,EAChC;AACF;AAKO,SAAS,uBAA6B;AAC3C,MAAI,OAAO,WAAW,aAAa;AACjC,WAAO,iBAAiB,YAAY,cAAc;AAAA,EACpD;AACF;AAKO,SAAS,oBAA0B;AACxC,MAAI,OAAO,WAAW,aAAa;AACjC,WAAO,oBAAoB,YAAY,cAAc;AAAA,EACvD;AACF;","names":[]}
@@ -0,0 +1,98 @@
1
+ import {
2
+ getCurrentComponentInstance,
3
+ logger
4
+ } from "./chunk-XHKZGJE3.js";
5
+
6
+ // src/foundations/portal.tsx
7
+ function definePortal() {
8
+ if (typeof createPortalSlot !== "function") {
9
+ let HostFallback2 = function() {
10
+ if (owner && owner.mounted === false) {
11
+ owner = null;
12
+ pending = void 0;
13
+ }
14
+ const inst = getCurrentComponentInstance();
15
+ if (!owner && inst) owner = inst;
16
+ if (process.env.NODE_ENV !== "production") {
17
+ const ns = globalThis.__ASKR__ || (globalThis.__ASKR__ = {});
18
+ ns.__PORTAL_READS = (ns.__PORTAL_READS || 0) + 1;
19
+ }
20
+ if (process.env.NODE_ENV !== "production") {
21
+ if (inst && owner && inst !== owner && inst.mounted === true) {
22
+ logger.warn(
23
+ "[Portal] multiple mounted hosts detected; first mounted host is owner"
24
+ );
25
+ }
26
+ }
27
+ return inst && owner && inst === owner ? pending : void 0;
28
+ };
29
+ var HostFallback = HostFallback2;
30
+ let owner = null;
31
+ let pending;
32
+ HostFallback2.render = function RenderFallback(props) {
33
+ if (!owner || owner.mounted !== true) return null;
34
+ if (process.env.NODE_ENV !== "production") {
35
+ const ns = globalThis.__ASKR__ || (globalThis.__ASKR__ = {});
36
+ ns.__PORTAL_WRITES = (ns.__PORTAL_WRITES || 0) + 1;
37
+ }
38
+ pending = props.children;
39
+ if (owner.notifyUpdate) owner.notifyUpdate();
40
+ return null;
41
+ };
42
+ return HostFallback2;
43
+ }
44
+ const slot = createPortalSlot();
45
+ function PortalHost() {
46
+ return slot.read();
47
+ }
48
+ PortalHost.render = function PortalRender(props) {
49
+ if (process.env.NODE_ENV !== "production") {
50
+ const ns = globalThis.__ASKR__ || (globalThis.__ASKR__ = {});
51
+ ns.__PORTAL_WRITES = (ns.__PORTAL_WRITES || 0) + 1;
52
+ }
53
+ slot.write(props.children);
54
+ return null;
55
+ };
56
+ return PortalHost;
57
+ }
58
+ var _defaultPortal;
59
+ var _defaultPortalIsFallback = false;
60
+ function ensureDefaultPortal() {
61
+ if (!_defaultPortal) {
62
+ if (typeof createPortalSlot === "function") {
63
+ _defaultPortal = definePortal();
64
+ _defaultPortalIsFallback = false;
65
+ } else {
66
+ _defaultPortal = definePortal();
67
+ _defaultPortalIsFallback = true;
68
+ }
69
+ return _defaultPortal;
70
+ }
71
+ if (_defaultPortalIsFallback && typeof createPortalSlot === "function") {
72
+ const real = definePortal();
73
+ _defaultPortal = real;
74
+ _defaultPortalIsFallback = false;
75
+ }
76
+ if (!_defaultPortalIsFallback && typeof createPortalSlot !== "function") {
77
+ const fallback = definePortal();
78
+ _defaultPortal = fallback;
79
+ _defaultPortalIsFallback = true;
80
+ }
81
+ return _defaultPortal;
82
+ }
83
+ var DefaultPortal = (() => {
84
+ function Host() {
85
+ const v = ensureDefaultPortal()();
86
+ return v === void 0 ? null : v;
87
+ }
88
+ Host.render = function Render(props) {
89
+ ensureDefaultPortal().render(props);
90
+ return null;
91
+ };
92
+ return Host;
93
+ })();
94
+
95
+ export {
96
+ DefaultPortal
97
+ };
98
+ //# sourceMappingURL=chunk-WTFWRSHB.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/foundations/portal.tsx"],"sourcesContent":["/**\n * Portal / Host primitive.\n *\n * A portal is a named render slot within the existing tree.\n * It does NOT create a second tree or touch the DOM directly.\n */\n\nimport { getCurrentComponentInstance } from '../runtime/component';\nimport type { ComponentInstance } from '../runtime/component';\nimport { logger } from '../dev/logger';\n\nexport interface Portal<T = unknown> {\n /** Mount point — rendered exactly once */\n (): unknown;\n\n /** Render content into the portal */\n render(props: { children?: T }): unknown;\n}\n\nexport function definePortal<T = unknown>(): Portal<T> {\n // If the runtime primitive isn't installed yet, provide a no-op fallback.\n // Using `typeof createPortalSlot` is safe even if the identifier is not\n // defined at runtime (it returns 'undefined' rather than throwing).\n if (typeof createPortalSlot !== 'function') {\n // Fallback implementation for environments where the runtime primitive\n // isn't available (tests, SSR).\n //\n // Invariants this fallback tries to maintain:\n // - Always use the *current* host instance (update `owner` each render)\n // - Preserve the last `value` written before host mounts and expose it so\n // it can be flushed into a real portal if/when the runtime installs\n // - Schedule `owner.notifyUpdate()` when a host exists so updates are\n // reflected immediately\n // Fast fallback for module/SSR/test environments.\n // Track a single owner to avoid per-render array scans.\n let owner: ComponentInstance | null = null;\n let pending: T | undefined;\n\n function HostFallback() {\n // Drop owner + pending when owner unmounts to avoid replay.\n if (owner && owner.mounted === false) {\n owner = null;\n pending = undefined;\n }\n\n const inst = getCurrentComponentInstance();\n\n // Capture the first host as the owner.\n // We intentionally do NOT require `mounted === true` here because the\n // host can render before the runtime flips its mounted flag. Capturing\n // early ensures `DefaultPortal.render()` works immediately after mount.\n if (!owner && inst) owner = inst;\n\n /* istanbul ignore if */\n if (process.env.NODE_ENV !== 'production') {\n const ns =\n (globalThis as unknown as { __ASKR__?: Record<string, unknown> })\n .__ASKR__ ||\n ((\n globalThis as unknown as { __ASKR__?: Record<string, unknown> }\n ).__ASKR__ = {} as Record<string, unknown>);\n ns.__PORTAL_READS = ((ns.__PORTAL_READS as number) || 0) + 1;\n }\n\n /* istanbul ignore if */\n if (process.env.NODE_ENV !== 'production') {\n // Minimal dev diagnostics; avoid heavy allocations in the hot path.\n if (inst && owner && inst !== owner && inst.mounted === true) {\n logger.warn(\n '[Portal] multiple mounted hosts detected; first mounted host is owner'\n );\n }\n }\n\n return inst && owner && inst === owner ? (pending as unknown) : undefined;\n }\n\n HostFallback.render = function RenderFallback(props: { children?: T }) {\n // Owner must be fully mounted (mounted === true) to accept writes.\n if (!owner || owner.mounted !== true) return null;\n\n /* istanbul ignore if */\n if (process.env.NODE_ENV !== 'production') {\n const ns =\n (globalThis as unknown as { __ASKR__?: Record<string, unknown> })\n .__ASKR__ ||\n ((\n globalThis as unknown as { __ASKR__?: Record<string, unknown> }\n ).__ASKR__ = {} as Record<string, unknown>);\n ns.__PORTAL_WRITES = ((ns.__PORTAL_WRITES as number) || 0) + 1;\n }\n\n // Update pending value for the live owner\n pending = props.children as T | undefined;\n\n // Schedule an update on the owner so it re-renders\n if (owner.notifyUpdate) owner.notifyUpdate();\n return null;\n };\n\n return HostFallback as Portal<T>;\n }\n\n // Runtime-provided slot implementation\n const slot = createPortalSlot<T>();\n\n function PortalHost() {\n return slot.read();\n }\n\n PortalHost.render = function PortalRender(props: { children?: T }) {\n // Keep counter increment guarded for dev-only behavior\n /* istanbul ignore if */\n if (process.env.NODE_ENV !== 'production') {\n const ns =\n (globalThis as unknown as { __ASKR__?: Record<string, unknown> })\n .__ASKR__ ||\n ((\n globalThis as unknown as { __ASKR__?: Record<string, unknown> }\n ).__ASKR__ = {} as Record<string, unknown>);\n ns.__PORTAL_WRITES = ((ns.__PORTAL_WRITES as number) || 0) + 1;\n }\n slot.write(props.children);\n return null;\n };\n\n return PortalHost as Portal<T>;\n}\n\n// Default portal instance: lazily created wrapper so runtime primitive is not\n// invoked during module initialization (avoids ReferenceError when runtime\n// slot primitive is not yet installed).\nlet _defaultPortal: Portal<unknown> | undefined;\nlet _defaultPortalIsFallback = false;\n\n/**\n * Reset the default portal state. Used by tests to ensure isolation.\n * @internal\n */\nexport function _resetDefaultPortal(): void {\n _defaultPortal = undefined;\n _defaultPortalIsFallback = false;\n}\n\nfunction ensureDefaultPortal(): Portal<unknown> {\n // If a portal hasn't been initialized yet, create a real portal if the\n // runtime primitive exists; otherwise create a fallback. If a fallback\n // was previously created and the runtime primitive becomes available\n // later, replace the fallback with a real portal on first use.\n if (!_defaultPortal) {\n if (typeof createPortalSlot === 'function') {\n _defaultPortal = definePortal<unknown>();\n _defaultPortalIsFallback = false;\n } else {\n // Create a fallback via definePortal so it uses the same owner/pending\n // semantics as the non-default portals (keeps runtime and fallback\n // behavior consistent).\n _defaultPortal = definePortal<unknown>();\n _defaultPortalIsFallback = true;\n }\n return _defaultPortal;\n }\n\n // Replace fallback with real portal once runtime primitive becomes available\n // NOTE: We intentionally do NOT replay pending writes from a fallback.\n // Early writes are dropped by design to avoid replaying invisible UI.\n if (_defaultPortalIsFallback && typeof createPortalSlot === 'function') {\n const real = definePortal<unknown>();\n _defaultPortal = real;\n _defaultPortalIsFallback = false;\n }\n\n // If the runtime primitive is removed (tests may simulate this by\n // deleting `createPortalSlot` between runs), revert to a fallback so\n // subsequent tests observe the appropriate fallback semantics.\n if (!_defaultPortalIsFallback && typeof createPortalSlot !== 'function') {\n const fallback = definePortal<unknown>();\n _defaultPortal = fallback;\n _defaultPortalIsFallback = true;\n }\n\n return _defaultPortal;\n}\n\nexport const DefaultPortal: Portal<unknown> = (() => {\n function Host() {\n // Delegate to the lazily-created portal host (created when runtime is ready)\n // Return null when no pending value exists so the component renders nothing\n // (consistent with SSR which renders Fragment children as empty string)\n const v = ensureDefaultPortal()();\n return v === undefined ? null : v;\n }\n Host.render = function Render(props: { children?: unknown }) {\n ensureDefaultPortal().render(props);\n return null;\n };\n return Host as Portal<unknown>;\n})();\n\n/**\n * NOTE:\n * createPortalSlot is a runtime primitive.\n * It owns scheduling, consistency, and SSR behavior.\n */\ndeclare function createPortalSlot<T>(): {\n read(): unknown;\n write(value: T | undefined): void;\n};\n"],"mappings":";;;;;;AAmBO,SAAS,eAAuC;AAIrD,MAAI,OAAO,qBAAqB,YAAY;AAe1C,QAASA,gBAAT,WAAwB;AAEtB,UAAI,SAAS,MAAM,YAAY,OAAO;AACpC,gBAAQ;AACR,kBAAU;AAAA,MACZ;AAEA,YAAM,OAAO,4BAA4B;AAMzC,UAAI,CAAC,SAAS,KAAM,SAAQ;AAG5B,UAAI,QAAQ,IAAI,aAAa,cAAc;AACzC,cAAM,KACH,WACE,aAED,WACA,WAAW,CAAC;AAChB,WAAG,kBAAmB,GAAG,kBAA6B,KAAK;AAAA,MAC7D;AAGA,UAAI,QAAQ,IAAI,aAAa,cAAc;AAEzC,YAAI,QAAQ,SAAS,SAAS,SAAS,KAAK,YAAY,MAAM;AAC5D,iBAAO;AAAA,YACL;AAAA,UACF;AAAA,QACF;AAAA,MACF;AAEA,aAAO,QAAQ,SAAS,SAAS,QAAS,UAAsB;AAAA,IAClE;AArCS,uBAAAA;AAHT,QAAI,QAAkC;AACtC,QAAI;AAyCJ,IAAAA,cAAa,SAAS,SAAS,eAAe,OAAyB;AAErE,UAAI,CAAC,SAAS,MAAM,YAAY,KAAM,QAAO;AAG7C,UAAI,QAAQ,IAAI,aAAa,cAAc;AACzC,cAAM,KACH,WACE,aAED,WACA,WAAW,CAAC;AAChB,WAAG,mBAAoB,GAAG,mBAA8B,KAAK;AAAA,MAC/D;AAGA,gBAAU,MAAM;AAGhB,UAAI,MAAM,aAAc,OAAM,aAAa;AAC3C,aAAO;AAAA,IACT;AAEA,WAAOA;AAAA,EACT;AAGA,QAAM,OAAO,iBAAoB;AAEjC,WAAS,aAAa;AACpB,WAAO,KAAK,KAAK;AAAA,EACnB;AAEA,aAAW,SAAS,SAAS,aAAa,OAAyB;AAGjE,QAAI,QAAQ,IAAI,aAAa,cAAc;AACzC,YAAM,KACH,WACE,aAED,WACA,WAAW,CAAC;AAChB,SAAG,mBAAoB,GAAG,mBAA8B,KAAK;AAAA,IAC/D;AACA,SAAK,MAAM,MAAM,QAAQ;AACzB,WAAO;AAAA,EACT;AAEA,SAAO;AACT;AAKA,IAAI;AACJ,IAAI,2BAA2B;AAW/B,SAAS,sBAAuC;AAK9C,MAAI,CAAC,gBAAgB;AACnB,QAAI,OAAO,qBAAqB,YAAY;AAC1C,uBAAiB,aAAsB;AACvC,iCAA2B;AAAA,IAC7B,OAAO;AAIL,uBAAiB,aAAsB;AACvC,iCAA2B;AAAA,IAC7B;AACA,WAAO;AAAA,EACT;AAKA,MAAI,4BAA4B,OAAO,qBAAqB,YAAY;AACtE,UAAM,OAAO,aAAsB;AACnC,qBAAiB;AACjB,+BAA2B;AAAA,EAC7B;AAKA,MAAI,CAAC,4BAA4B,OAAO,qBAAqB,YAAY;AACvE,UAAM,WAAW,aAAsB;AACvC,qBAAiB;AACjB,+BAA2B;AAAA,EAC7B;AAEA,SAAO;AACT;AAEO,IAAM,iBAAkC,MAAM;AACnD,WAAS,OAAO;AAId,UAAM,IAAI,oBAAoB,EAAE;AAChC,WAAO,MAAM,SAAY,OAAO;AAAA,EAClC;AACA,OAAK,SAAS,SAAS,OAAO,OAA+B;AAC3D,wBAAoB,EAAE,OAAO,KAAK;AAClC,WAAO;AAAA,EACT;AACA,SAAO;AACT,GAAG;","names":["HostFallback"]}