@askrjs/askr 0.3.0 → 0.4.0

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 (123) hide show
  1. package/CHANGELOG.md +874 -0
  2. package/README.md +61 -29
  3. package/capabilities.json +19 -9
  4. package/dist/actions/index.js +56 -12
  5. package/dist/benchmark.js +10 -15
  6. package/dist/boot/index.d.ts +3 -2
  7. package/dist/boot/index.js +1 -1
  8. package/dist/boot-DaoTYoCw.js +3989 -0
  9. package/dist/browser-activity-CB8e-V4f.js +220 -0
  10. package/dist/components/index.d.ts +8 -1
  11. package/dist/components/index.js +1 -43
  12. package/dist/{aria-hKjThHcp.js → compose-ref-DWzdbxsD.js} +41 -4
  13. package/dist/control/index.d.ts +2 -0
  14. package/dist/control/index.js +1 -1
  15. package/dist/control-nfpT2fbK.js +209 -0
  16. package/dist/core.d.ts +5 -9
  17. package/dist/csp-nonce-DwGw1A6Q.js +35 -0
  18. package/dist/data/index.js +3 -3
  19. package/dist/{data-2edW0jhF.js → data-BCwClJiF.js} +283 -94
  20. package/dist/data-runtime-C1bFAlba.js +242 -0
  21. package/dist/{deferred-CbgNhf67.js → deferred-bEEHHvic.js} +42 -20
  22. package/dist/domains/actions.d.ts +8 -3
  23. package/dist/domains/component.d.ts +1 -107
  24. package/dist/domains/context.d.ts +0 -15
  25. package/dist/domains/control.d.ts +36 -249
  26. package/dist/domains/data.d.ts +31 -13
  27. package/dist/domains/diagnostics.d.ts +1 -2
  28. package/dist/domains/lifecycle.d.ts +2 -5
  29. package/dist/domains/refs.d.ts +0 -2
  30. package/dist/domains/routing.d.ts +43 -8
  31. package/dist/domains/scheduler.d.ts +1 -76
  32. package/dist/domains/server.d.ts +5 -2
  33. package/dist/domains/state.d.ts +2 -5
  34. package/dist/domains/telemetry.d.ts +0 -2
  35. package/dist/elements.d.ts +214 -51
  36. package/dist/error-boundary-Bpwofwps.js +293 -0
  37. package/dist/foundations/icon/index.d.ts +0 -58
  38. package/dist/foundations/icon/index.js +2 -2
  39. package/dist/foundations/index.js +2 -1
  40. package/dist/foundations/interactions/index.js +1 -1
  41. package/dist/foundations/state/index.d.ts +3 -3
  42. package/dist/foundations/state/index.js +5 -3
  43. package/dist/foundations/structures/index.js +2 -1
  44. package/dist/foundations/utilities/index.d.ts +2 -0
  45. package/dist/foundations/utilities/index.js +1 -2
  46. package/dist/fx/index.d.ts +31 -58
  47. package/dist/fx/index.js +313 -195
  48. package/dist/hooks-BimKStr4.js +202 -0
  49. package/dist/index.d.ts +11 -74
  50. package/dist/index.js +8 -447
  51. package/dist/instance-BAnfmXOR.js +988 -0
  52. package/dist/{interactions-CTeACdT_.js → interactions-D2BoREb-.js} +3 -2
  53. package/dist/jsx-dev-runtime.d.ts +41 -18
  54. package/dist/jsx-dev-runtime.js +1 -6
  55. package/dist/{jsx-runtime-CPJXAOBF.js → jsx-runtime-C4idqHY0.js} +18 -7
  56. package/dist/jsx-runtime.js +1 -1
  57. package/dist/jsx.d.ts +61 -37
  58. package/dist/{manifest-D1P3UNWV.js → manifest-CW9gyNBY.js} +3 -3
  59. package/dist/{navigate-prC5V8XV.js → navigate-CP_0Zy5U.js} +454 -87
  60. package/dist/navigation.d.ts +12 -3
  61. package/dist/peer-types.d.ts +8 -0
  62. package/dist/portal-DuOKfnLa.js +349 -0
  63. package/dist/promise-Dz8iIHAm.js +16 -0
  64. package/dist/query-registry-WMCN0BJL.js +320 -0
  65. package/dist/readable-DFWOsTac.js +21 -0
  66. package/dist/{render-context-B7ohlh6t.js → render-context-DGHnEveC.js} +27 -11
  67. package/dist/render-sync-IC5lMFpq.js +1240 -0
  68. package/dist/resolution-Cx82-xjW.js +1244 -0
  69. package/dist/resource-CLjB7RBQ.js +377 -0
  70. package/dist/resources/index.d.ts +21 -11
  71. package/dist/resources/index.js +45 -244
  72. package/dist/router/index.d.ts +14 -5
  73. package/dist/router/index.js +22 -53
  74. package/dist/scope-CwpVSHVf.js +55 -0
  75. package/dist/{shared-kU8yvryp.js → shared-O2ZnmYAf.js} +1 -7
  76. package/dist/{snapshot-source-An4iKajG.js → snapshot-Cjx4N988.js} +6 -1
  77. package/dist/ssg/index.d.ts +1 -2
  78. package/dist/ssg/index.js +5 -13
  79. package/dist/ssr/index.d.ts +26 -28
  80. package/dist/ssr/index.js +4 -4
  81. package/dist/{ssr-CiNm6Vzl.js → ssr-BJ8ug7zH.js} +133 -122
  82. package/dist/ssr-DoV-vJ-5.js +229 -0
  83. package/dist/state-DWO1KzkX.js +232 -0
  84. package/dist/structures-D4dDMqHX.js +231 -0
  85. package/dist/testing/index.d.ts +8 -4
  86. package/dist/testing/index.js +29 -34
  87. package/dist/url-CnbfpX0K.js +185 -0
  88. package/dist/utilities.d.ts +48 -2
  89. package/dist/verify-hydration-DpVaDnqz.js +152 -0
  90. package/package.json +19 -9
  91. package/dist/access-CEA2pOry.js +0 -1046
  92. package/dist/activity-oy2YFTFF.js +0 -201
  93. package/dist/boot-BMBMWUGI.js +0 -1084
  94. package/dist/capabilities-Bbf0mlp9.js +0 -42
  95. package/dist/compose-ref-v0qGlHoN.js +0 -26
  96. package/dist/control-BR_mrX__.js +0 -173
  97. package/dist/control-C-ApnFs1.js +0 -20
  98. package/dist/csp-nonce-BfFWcd0w.js +0 -173
  99. package/dist/data-runtime-CxoY98lX.js +0 -149
  100. package/dist/default-portal-runtime-DvMvWJVp.js +0 -20
  101. package/dist/dom-renderer.d.ts +0 -77
  102. package/dist/domains/renderer.d.ts +0 -127
  103. package/dist/eager-control.d.ts +0 -8
  104. package/dist/effect-C3Zsc1k6.js +0 -292
  105. package/dist/for-state-BDykeOJL.js +0 -1753
  106. package/dist/instance-VAFYVJOa.js +0 -1027
  107. package/dist/notify-DxxuDPeY.js +0 -266
  108. package/dist/portal-w3oQ6oQU.js +0 -29
  109. package/dist/query-registry-LrYpQsDJ.js +0 -83
  110. package/dist/render-resolved-BC0W7_5b.js +0 -1123
  111. package/dist/renderer-CT0HeY58.js +0 -8623
  112. package/dist/resolution-3DskUkjG.js +0 -577
  113. package/dist/resource-18-sFRl9.js +0 -344
  114. package/dist/route-matching-CUzZ31gT.js +0 -551
  115. package/dist/router-internal-7nuNEHfG.js +0 -36
  116. package/dist/scope-Cq_iYbTR.js +0 -403
  117. package/dist/selector-BSPVkjKP.js +0 -311
  118. package/dist/ssr-EPjwJH5R.js +0 -29
  119. package/dist/state-BXJfudq1.js +0 -91
  120. package/dist/structures-CjEzfj4h.js +0 -654
  121. package/dist/timer-C7uqnJVt.js +0 -85
  122. package/dist/verify-hydration-ikaxotf7.js +0 -27
  123. package/dist/vnode-D24p6IW2.js +0 -7
@@ -1,226 +1,21 @@
1
- import { JSXElementType, JSXElement, Props } from '../elements.js';
1
+ import { JSXElement, Props } from '../elements.js';
2
2
  import '../jsx-globals.js';
3
- import { AuthContext, AuthRequirement } from '@askrjs/auth';
4
- import { InferSchema, ObjectSchema } from '@askrjs/schema';
5
3
  import { state, selector } from './state.js';
6
- import { VNode, RenderableChild, ContextFrame } from './context.js';
7
- import { ComponentInstance, ReadableSource } from './component.js';
8
- import {
9
- DOMRange,
10
- ChildScope,
11
- ChildScopeOwnership,
12
- ChildScopeTransactionSnapshot,
13
- } from './renderer.js';
4
+ import { VNode, RenderableChild } from './context.js';
14
5
  import { on } from './lifecycle.js';
15
6
 
16
- type ForItemSignal<T> = ReadableSource<T> &
17
- (() => T) & {
18
- peek(): T;
19
- set(newValue: T, notifyReaders?: boolean): void;
20
- };
7
+ /** A list, or a getter returning one (`null`/`undefined` render nothing). */
8
+ type ForEachSource<T> = ForEachGetter<T> | ForEachList<T>;
21
9
 
22
- type ForItemPropertySignal = ReadableSource<unknown> &
23
- (() => unknown) & {
24
- peek(): unknown;
25
- set(newValue: unknown, notifyReaders?: boolean): void;
26
- };
10
+ type ForEachGetter<T> = () => readonly T[] | null | undefined;
27
11
 
28
- type ForIndexSignal = ReadableSource<number> &
29
- (() => number) & {
30
- peek(): number;
31
- set(
32
- newValue: number | ((prev: number) => number),
33
- notifyReaders?: boolean
34
- ): void;
35
- };
12
+ /** A list that is not also callable: a `state()` getter is both. */
13
+ type ForEachList<T> = readonly T[] & { readonly call?: never };
36
14
 
37
- interface ReactiveForItemState<T> {
38
- currentItem: T;
39
- itemSignal: ForItemSignal<T> | null;
40
- propertySignals: Map<PropertyKey, ForItemPropertySignal> | null;
41
- coalescedProperties: PropertyKey | PropertyKey[] | null;
42
- coalescedProperty2: PropertyKey | null;
43
- wholeItemRead: boolean;
44
- proxy: T;
45
- }
46
-
47
- interface ForItemInstance<T> {
48
- key: string | number;
49
- item: T;
50
- reactiveItem: T;
51
- reactiveItemState: ReactiveForItemState<T> | null;
52
- indexSignal: ForIndexSignal;
53
- scope: ChildScope;
54
- }
55
-
56
- interface FineGrainedEffectHandle<T> {
57
- cleanup(): void;
58
- updateCompute(nextCompute: () => T): void;
59
- flush(): void;
60
- }
61
-
62
- type ForEachSource<T> = readonly T[] | (() => readonly T[]);
63
-
64
- type ForKeySelector<T> = (item: T, index: number) => string | number;
65
-
66
- type ForRenderItem<T> = (item: T, index: () => number) => VNode;
67
-
68
- type ForCommitStrategy =
69
- | 'APPEND'
70
- | 'INSERT_ONE'
71
- | 'REMOVE_ONE'
72
- | 'TRUNCATE'
73
- | 'NO_REORDER'
74
- | 'SWAP'
75
- | 'FULL_KEYED';
76
-
77
- interface ForState<T> {
78
- kind: 'for';
79
- _contextFrame: ContextFrame | null;
80
- _contextFrameChanged: boolean;
81
- currentItems: readonly T[];
82
- _committedItems: readonly T[];
83
- eachSource: ForEachSource<T>;
84
- fallback: VNode | null;
85
- fallbackScope: ChildScope | null;
86
- items: Map<string | number, ForItemInstance<T>>;
87
- orderedKeys: Array<string | number>;
88
- orderedItems: ForItemInstance<T>[];
89
- orderedVNodes: VNode[];
90
- byFn: ForKeySelector<T>;
91
- renderFn: ForRenderItem<T>;
92
- parentInstance: ComponentInstance | null;
93
- lastCommitStrategy: ForCommitStrategy;
94
- lastRemovedNodes: Node[];
95
- lastRemovedRanges: DOMRange[];
96
- pendingDirtyIndices: number[] | null;
97
- pendingSwapIndices: [number, number] | null;
98
- pendingMoveOnly: boolean;
99
- pendingInsertedIndex: number | null;
100
- pendingRemovedKey: string | number | null;
101
- pendingAppendStart: number | null;
102
- _hasResolvedItemDom: boolean;
103
- _needsSourceReconcile: boolean;
104
- _sourceEffect: FineGrainedEffectHandle<readonly T[]> | null;
105
- _suspendSourceCommit: boolean;
106
- _enqueueBoundaryCommit?: (() => void) | null;
107
- _hasPendingBoundaryCommit?: boolean;
108
- devKeyKinds?: Map<string | number, 'number' | 'string'>;
109
- _transaction?: ForTransaction<T> | null;
110
- _scopeOwnership: ChildScopeOwnership;
111
- }
112
-
113
- interface ForItemTransactionSnapshot<T> {
114
- item: T;
115
- itemSignalExists: boolean;
116
- itemSignalValue: T | undefined;
117
- itemSignalHasBeenRead: boolean;
118
- indexValue: number;
119
- indexHasBeenRead: boolean;
120
- propertySignalStore: Map<PropertyKey, ForItemPropertySignal> | null;
121
- propertySignals: Map<
122
- PropertyKey,
123
- {
124
- signal: ForItemPropertySignal;
125
- value: unknown;
126
- hasBeenRead: boolean;
127
- }
128
- > | null;
129
- scope: ChildScopeTransactionSnapshot;
130
- }
131
-
132
- interface ForTransaction<T> {
133
- collectionSnapshotMode: 'copy' | 'reset-empty' | 'preserve-clear' | 'reuse';
134
- currentItems: readonly T[];
135
- items: Map<string | number, ForItemInstance<T>>;
136
- orderedKeys: Array<string | number>;
137
- orderedItems: ForItemInstance<T>[];
138
- orderedVNodes: VNode[];
139
- fallbackScope: ChildScope | null;
140
- lastCommitStrategy: ForCommitStrategy;
141
- lastRemovedNodes: Node[];
142
- lastRemovedRanges: DOMRange[];
143
- pendingDirtyIndices: number[] | null;
144
- pendingSwapIndices: [number, number] | null;
145
- pendingMoveOnly: boolean;
146
- pendingInsertedIndex: number | null;
147
- pendingRemovedKey: string | number | null;
148
- pendingAppendStart: number | null;
149
- hasResolvedItemDom: boolean;
150
- needsSourceReconcile: boolean;
151
- devKeyKinds?: Map<string | number, 'number' | 'string'>;
152
- itemSnapshots: Map<ForItemInstance<T>, ForItemTransactionSnapshot<T>> | null;
153
- unreadIndexSnapshots: Map<ForIndexSignal, number> | null;
154
- fallbackScopeSnapshot: ChildScopeTransactionSnapshot | null;
155
- removedScopes: ChildScope[] | null;
156
- removedScopeNodes: Node[] | null;
157
- removeAllItems: boolean;
158
- signalEffects: Map<
159
- ReadableSource<unknown>,
160
- {
161
- parentInstance: ComponentInstance | null;
162
- notify: boolean;
163
- skipInstance: ComponentInstance | null;
164
- skipOwnedBy: ComponentInstance | null;
165
- }
166
- > | null;
167
- shouldClearDomUpdateState: boolean;
168
- }
169
-
170
- interface MatchBranch {
171
- key: string | number;
172
- render: () => VNode;
173
- when: unknown;
174
- }
175
-
176
- interface BranchControlStateBase {
177
- _contextFrame: ContextFrame | null;
178
- activeKey: string | number | null;
179
- activeScope: ChildScope | null;
180
- activeVNodes: VNode[];
181
- lastRemovedNodes: Node[];
182
- lastRemovedRanges: DOMRange[];
183
- parentInstance: ComponentInstance | null;
184
- _enqueueBoundaryCommit?: (() => void) | null;
185
- _hasPendingBoundaryCommit?: boolean;
186
- _transaction?: ControlTransaction | null;
187
- }
188
-
189
- interface ShowState extends BranchControlStateBase {
190
- kind: 'show';
191
- fallbackScope: ChildScope | null;
192
- renderFallback: (() => VNode) | null;
193
- renderTruthy: ((value: unknown) => VNode) | (() => VNode);
194
- selectedValue: unknown;
195
- truthyScope: ChildScope | null;
196
- }
197
-
198
- interface CaseState extends BranchControlStateBase {
199
- kind: 'case';
200
- fallback: (() => VNode) | null;
201
- matches: MatchBranch[];
202
- }
203
-
204
- type ControlBoundaryState = ForState<unknown> | ShowState | CaseState;
205
-
206
- type BranchStateSnapshot = {
207
- activeKey: string | number | null;
208
- activeScope: ChildScope | null;
209
- activeVNodes: VNode[];
210
- lastRemovedNodes: Node[];
211
- lastRemovedRanges: DOMRange[];
212
- scopeSnapshots: Map<ChildScope, ChildScopeTransactionSnapshot>;
213
- fallbackScope?: ChildScope | null;
214
- truthyScope?: ChildScope | null;
215
- };
216
-
217
- interface ControlTransaction {
218
- state: ShowState | CaseState;
219
- snapshot: BranchStateSnapshot;
220
- removedScopes: ChildScope[];
221
- shouldClearDomUpdateState: boolean;
222
- registered: boolean;
223
- }
15
+ /** How rows are identified: by a key function, or by position. */
16
+ type ForKeying<T, K extends string | number> =
17
+ | { by: (item: T, index: number) => K; byIndex?: never }
18
+ | { by?: never; byIndex: true };
224
19
 
225
20
  type BoundaryChild = RenderableChild;
226
21
 
@@ -228,32 +23,42 @@ type ForBaseProps<T> = {
228
23
  each: ForEachSource<T>;
229
24
  fallback?: BoundaryChild;
230
25
  /**
231
- * Row renderer. Parent reactive reads must use `selector()` or thunk props;
232
- * closure-captured values are snapshotted when the row is created or
233
- * reconciled; changing the parent source does not rerun an existing row.
26
+ * Row renderer. Existing rows rerun with the latest callback when the parent
27
+ * rerenders, and a reactive read in the callback subscribes that row. Prefer
28
+ * `selector()` or thunk props so only the affected rows or props update.
234
29
  */
235
30
  children: (item: T, index: () => number) => VNode;
236
31
  };
237
32
 
238
- type KeyedForProps<T, K extends string | number> = ForBaseProps<T> & {
239
- by: (item: T, index: number) => K;
240
- byIndex?: never;
241
- };
33
+ type KeyedForProps<T, K extends string | number> = ForBaseProps<T> &
34
+ Extract<ForKeying<T, K>, { byIndex?: never }>;
242
35
 
243
- type IndexedForProps<T> = ForBaseProps<T> & {
244
- by?: never;
245
- byIndex: true;
246
- };
36
+ type IndexedForProps<T> = ForBaseProps<T> &
37
+ Extract<ForKeying<T, string | number>, { byIndex: true }>;
247
38
 
248
39
  /** Props for {@link For}. */
249
40
  type ForProps<T, K extends string | number = string | number> =
250
41
  | KeyedForProps<T, K>
251
42
  | IndexedForProps<T>;
252
43
 
44
+ /**
45
+ * {@link ForProps} with a getter `each`. A `state()` getter is also an array
46
+ * (`[getter, setter]`), so `For` tries this form first and reads it as a getter.
47
+ */
48
+ type ForGetterProps<T, K extends string | number = string | number> = Omit<
49
+ ForBaseProps<T>,
50
+ 'each'
51
+ > & { each: ForEachGetter<T> } & ForKeying<T, K>;
52
+
253
53
  /** Render a keyed or indexed list, reconciling items by key instead of position. */
254
- declare const For: <T, K extends string | number = string | number>(
255
- props: ForProps<T, K>
256
- ) => JSXElement;
54
+ declare const For: {
55
+ <T, K extends string | number = string | number>(
56
+ props: ForGetterProps<T, K>
57
+ ): JSXElement;
58
+ <T, K extends string | number = string | number>(
59
+ props: ForProps<T, K>
60
+ ): JSXElement;
61
+ };
257
62
 
258
63
  type ShowSource<T> = T | (() => T);
259
64
 
@@ -290,26 +95,8 @@ declare function Match(_props: MatchProps): null;
290
95
  /** Render the first matching {@link Match} child (by `when`), or `fallback` if none match. */
291
96
  declare const Case: (props: CaseProps) => JSXElement;
292
97
  export {
293
- ForItemSignal,
294
- ForItemPropertySignal,
295
- ForIndexSignal,
296
- ReactiveForItemState,
297
- ForItemInstance,
298
- FineGrainedEffectHandle,
299
98
  ForEachSource,
300
- ForKeySelector,
301
- ForRenderItem,
302
- ForCommitStrategy,
303
- ForState,
304
- ForItemTransactionSnapshot,
305
- ForTransaction,
306
- MatchBranch,
307
- BranchControlStateBase,
308
- ShowState,
309
- CaseState,
310
- ControlBoundaryState,
311
- BranchStateSnapshot,
312
- ControlTransaction,
99
+ ForGetterProps,
313
100
  BoundaryChild,
314
101
  ForBaseProps,
315
102
  KeyedForProps,
@@ -1,7 +1,5 @@
1
1
  import { JSXElementType, JSXElement, Props } from '../elements.js';
2
2
  import '../jsx-globals.js';
3
- import { AuthContext, AuthRequirement } from '@askrjs/auth';
4
- import { InferSchema, ObjectSchema } from '@askrjs/schema';
5
3
  import { state } from './state.js';
6
4
  import { CoreTelemetry } from './telemetry.js';
7
5
  import { on } from './lifecycle.js';
@@ -17,25 +15,20 @@ type QueryStaleReason = 'aborted' | 'error' | 'inconsistent';
17
15
  interface DataRuntime {
18
16
  readonly queryCache: Map<string, unknown>;
19
17
  readonly queryData: Map<string, unknown>;
20
- /** Test-only query overrides keyed by the canonical query key. */
21
- readonly queryTestOverrides: Map<string, unknown>;
22
- /** Test-only mutation overrides keyed by the canonical mutation key. */
23
- readonly mutationTestOverrides: Map<string, unknown>;
24
18
  }
25
19
 
26
20
  /** Options for {@link createDataRuntime}. */
27
21
  interface DataRuntimeOptions {
28
22
  queryCache?: Map<string, unknown>;
29
23
  queryData?: Map<string, unknown>;
30
- queryTestOverrides?: Map<string, unknown>;
31
- mutationTestOverrides?: Map<string, unknown>;
32
24
  }
33
25
 
34
26
  /** Reusable query definition for {@link defineQuery}: key, fetcher, and freshness checks. */
35
27
  interface QueryDefinition<TInput, TResult extends {}> {
36
28
  readonly key: (input: TInput) => string;
37
29
  readonly fetch: (
38
- context: TInput & {
30
+ input: TInput,
31
+ context: {
39
32
  signal: AbortSignal;
40
33
  }
41
34
  ) => Promise<TResult>;
@@ -279,6 +272,8 @@ type QueryOptions<T> = {
279
272
  runtime?: DataRuntime;
280
273
  initialData?: T;
281
274
  skipInitialFetch?: boolean;
275
+ /** Cache lifetime in milliseconds. Defaults to 0 after component unmount and five minutes for ownerless client queries. */
276
+ gcTime?: number;
282
277
  };
283
278
 
284
279
  /** Options for {@link createMutation}. */
@@ -291,6 +286,15 @@ type MutationOptions<TInput, TResult> = {
291
286
  signal: AbortSignal;
292
287
  }
293
288
  ) => Promise<TResult>;
289
+ /** Apply a synchronous optimistic change. Return a rollback for failure or abort. */
290
+ optimistic?: (
291
+ input: TInput,
292
+ ctx: { signal: AbortSignal }
293
+ ) => void | (() => void);
294
+ /**
295
+ * Query prefixes to invalidate after success, matched by `:`-delimited
296
+ * segment the same way as {@link invalidate}.
297
+ */
294
298
  affects?: (input: TInput, result: TResult) => string[];
295
299
  afterSuccess?: 'invalidate';
296
300
  runtime?: DataRuntime;
@@ -324,15 +328,25 @@ declare function createDataRuntime(options?: DataRuntimeOptions): DataRuntime;
324
328
  /** Get the process-wide default {@link DataRuntime} used when none is provided explicitly. */
325
329
  declare function getDefaultDataRuntime(): DataRuntime;
326
330
 
327
- /** Mark all cached queries whose key starts with `prefix` as stale, triggering a refresh. */
331
+ /**
332
+ * Mark all cached queries under `prefix` as stale, triggering a refresh.
333
+ * Matching is by `:`-delimited segment: a key matches when it equals `prefix`,
334
+ * when `prefix` ends in `:`, or when the key continues `prefix` at a `:`
335
+ * (`'user:1'` matches `user:1:posts` but not `user:10`). Only `:` is a
336
+ * segment boundary; the empty prefix matches every key.
337
+ */
328
338
  declare function invalidate(prefix: string, options?: InvalidateOptions): void;
329
339
 
330
- /** Create a {@link QueryScope} that namespaces keys and invalidations under `namespace`. */
331
- declare function queryScope(namespace: string): QueryScope;
340
+ /** Create a {@link QueryScope} that namespaces keys and can bind invalidations to a runtime. */
341
+ declare function queryScope(
342
+ namespace: string,
343
+ options?: Pick<InvalidateOptions, 'runtime'>
344
+ ): QueryScope;
332
345
 
333
346
  /**
334
347
  * Periodically invalidate queries matching `prefix` on a fixed interval,
335
348
  * optionally gated by active route, document visibility, or window focus.
349
+ * `prefix` matches key segments the same way as {@link invalidate}.
336
350
  */
337
351
  declare function invalidateOnInterval(
338
352
  prefix: string,
@@ -401,7 +415,11 @@ declare function prefetchQuery<TInput, TResult extends {}>(
401
415
  input: TInput
402
416
  ): Promise<boolean>;
403
417
 
404
- /** Extract a runtime's cached query data into a JSON-serializable snapshot, dropping non-serializable values. */
418
+ /**
419
+ * Extract a runtime's cached query data into a JSON-serializable snapshot.
420
+ * Throws a `TypeError` naming the key and path of any value that would not
421
+ * survive JSON transport unchanged (for example a `Date`, `Map`, or bigint).
422
+ */
405
423
  declare function dehydrateDataRuntime(
406
424
  runtime: DataRuntime
407
425
  ): Record<string, unknown>;
@@ -1,8 +1,7 @@
1
1
  import { JSXElementType, JSXElement, Props } from '../elements.js';
2
2
  import '../jsx-globals.js';
3
- import { AuthContext, AuthRequirement } from '@askrjs/auth';
4
- import { InferSchema, ObjectSchema } from '@askrjs/schema';
5
3
 
4
+ /** Options for {@link configureRenderDiagnostics}. */
6
5
  interface RenderDiagnosticsOptions {
7
6
  /** Emit one warning per component instance when a render exceeds the threshold. */
8
7
  slowRenderWarnings?: boolean;
@@ -1,8 +1,5 @@
1
1
  import { JSXElementType, JSXElement, Props } from '../elements.js';
2
2
  import '../jsx-globals.js';
3
- import { AuthContext, AuthRequirement } from '@askrjs/auth';
4
- import { InferSchema, ObjectSchema } from '@askrjs/schema';
5
- import { ReadableSource } from './component.js';
6
3
 
7
4
  /** A gating condition for lifecycle primitives like {@link timer}; `true` means active. */
8
5
  type ActivityPredicate = () => boolean;
@@ -49,7 +46,7 @@ declare function task(
49
46
  ): void;
50
47
 
51
48
  /** A callable reactive source accepted by {@link watch}. */
52
- type WatchSource<T> = ReadableSource<T>;
49
+ type WatchSource<T> = () => T;
53
50
 
54
51
  /** Values inferred from an ordered tuple of {@link WatchSource} accessors. */
55
52
  type WatchValues<TSources extends readonly WatchSource<unknown>[]> = {
@@ -77,7 +74,7 @@ declare function watch<TValue>(
77
74
 
78
75
  /** Observe an ordered tuple of readable sources after commit and whenever an entry changes. */
79
76
  declare function watch<const TSources extends readonly WatchSource<unknown>[]>(
80
- sources: TSources,
77
+ sources: TSources extends WatchSource<unknown> ? never : TSources,
81
78
  callback: WatchCallback<WatchValues<TSources>>
82
79
  ): void;
83
80
 
@@ -1,7 +1,5 @@
1
1
  import { JSXElementType, JSXElement, Props } from '../elements.js';
2
2
  import '../jsx-globals.js';
3
- import { AuthContext, AuthRequirement } from '@askrjs/auth';
4
- import { InferSchema, ObjectSchema } from '@askrjs/schema';
5
3
 
6
4
  /**
7
5
  * Creates a stable holder for an intrinsic element ref.
@@ -1,7 +1,11 @@
1
1
  import { JSXElementType, JSXElement, Props } from '../elements.js';
2
2
  import '../jsx-globals.js';
3
- import { AuthContext, AuthRequirement } from '@askrjs/auth';
4
- import { InferSchema, ObjectSchema } from '@askrjs/schema';
3
+ import {
4
+ AuthContext,
5
+ AuthRequirement,
6
+ InferSchema,
7
+ ObjectSchema,
8
+ } from '../peer-types.js';
5
9
  import { state, selector } from './state.js';
6
10
  import { RenderableChild } from './context.js';
7
11
  import { QueryPrefetchContext } from './data.js';
@@ -133,13 +137,34 @@ type RouteAuthResolver = (
133
137
 
134
138
  /** Auth configuration shared across a route registry or a single route. */
135
139
  interface RouteAuthOptions {
136
- resolve: RouteAuthResolver;
140
+ /**
141
+ * Resolve the identity for a request. When omitted, requests are anonymous
142
+ * unless the caller supplies an identity (for example `authContext` on the
143
+ * server, or an opted-in hydration snapshot for the initial client route).
144
+ */
145
+ resolve?: RouteAuthResolver;
146
+ /**
147
+ * Opt in to sending a minimal identity snapshot to the browser for
148
+ * hydration. Called on the server with the identity that authorized the
149
+ * page. `authenticated`, `principal`, `tenant`, and `scopes` of the result
150
+ * are serialized verbatim into the page, so return only what the client
151
+ * needs; the session is never sent. The client uses the snapshot to resolve
152
+ * the initial route and, without `resolve`, as its identity for
153
+ * navigations. Nothing crosses without this hook.
154
+ */
155
+ dehydrate?: (context: AuthContext) => Omit<AuthContext, 'session'>;
137
156
  loginPath?:
138
157
  | string
139
- | ((context: RouteContext) => string | PromiseLike<string>);
158
+ | RouteDestination
159
+ | ((
160
+ context: RouteContext
161
+ ) => string | RouteDestination | PromiseLike<string | RouteDestination>);
140
162
  authenticatedRedirectTo?:
141
163
  | string
142
- | ((context: RouteContext) => string | PromiseLike<string>);
164
+ | RouteDestination
165
+ | ((
166
+ context: RouteContext
167
+ ) => string | RouteDestination | PromiseLike<string | RouteDestination>);
143
168
  }
144
169
 
145
170
  interface CommonAccessOptions {
@@ -246,14 +271,24 @@ interface RouteRef<
246
271
  readonly __search?: TSearch;
247
272
  }
248
273
 
249
- type RouteRefSearch<TSchema extends ObjectSchema<RouteSearch> | undefined> =
250
- TSchema extends ObjectSchema<RouteSearch>
274
+ type RouteRefSearch<TSchema extends ObjectSchema<RouteSearch> | undefined> = [
275
+ TSchema,
276
+ ] extends [undefined]
277
+ ? RouteSearch
278
+ : TSchema extends ObjectSchema<RouteSearch>
251
279
  ? InferSchema<TSchema>
252
280
  : RouteSearch;
253
281
 
254
- /** A resolved navigation target with a computed `href`, produced by {@link to}. */
282
+ declare const routeDestinationBrand: unique symbol;
283
+
284
+ /**
285
+ * A typed navigation target with a computed public `href`, produced by
286
+ * {@link to}. Branded so that only `to()` creates one: its `href` already
287
+ * includes the registry `basePath` and is never prefixed again.
288
+ */
255
289
  interface RouteDestination {
256
290
  readonly href: string;
291
+ readonly [routeDestinationBrand]: true;
257
292
  }
258
293
 
259
294
  /** Options accepted by the `page()` route-declaration helper. */
@@ -1,79 +1,4 @@
1
- import { JSXElementType, JSXElement, Props } from '../elements.js';
2
1
  import '../jsx-globals.js';
3
- import { AuthContext, AuthRequirement } from '@askrjs/auth';
4
- import { InferSchema, ObjectSchema } from '@askrjs/schema';
5
- import { task } from './lifecycle.js';
6
-
7
- /**
8
- * Serialized update scheduler — safer design (no inline execution, explicit flush)
9
- *
10
- * Key ideas:
11
- * - Never execute a task inline from `enqueue`.
12
- * - `flush()` is explicit and non-reentrant.
13
- * - `runWithSyncProgress()` allows enqueues temporarily but does not run tasks
14
- * inline; it runs `fn` and then does an explicit `flush()`.
15
- * - `waitForFlush()` is race-free with a monotonic `flushVersion`.
16
- */
17
- type Task = () => void;
18
-
19
- type SchedulerLane = 'derived' | 'component' | 'reactive' | 'post';
20
-
21
- type SchedulerBulkCommitProbe = () => boolean;
22
-
23
- declare class Scheduler {
24
- private bulkCommitProbe;
25
- private lanes;
26
- private running;
27
- private inHandler;
28
- private depth;
29
- private executionDepth;
30
- private flushVersion;
31
- private kickScheduled;
32
- private allowSyncProgress;
33
- private waiters;
34
- private taskCount;
35
- setBulkCommitProbe(probe: SchedulerBulkCommitProbe): void;
36
- private isBulkCommitActive;
37
- private hasPendingTasks;
38
- private getPendingTaskCount;
39
- private compactLane;
40
- private scheduleFlushKick;
41
- enqueue(task: Task): void;
42
- enqueueInLane(lane: SchedulerLane, task: Task): void;
43
- flush(): void;
44
- runWithSyncProgress<T>(fn: () => T): T;
45
- waitForFlush(targetVersion?: number, timeoutMs?: number): Promise<void>;
46
- getState(): {
47
- queueLength: number;
48
- running: boolean;
49
- depth: number;
50
- executionDepth: number;
51
- taskCount: number;
52
- flushVersion: number;
53
- laneQueues: {
54
- derived: number;
55
- component: number;
56
- reactive: number;
57
- post: number;
58
- };
59
- inHandler: boolean;
60
- allowSyncProgress: boolean;
61
- };
62
- getFlushVersion(): number;
63
- flushIfQueued(): void;
64
- runInHandlerScope<T>(fn: () => T, flushMode?: 'defer' | 'sync'): T;
65
- setInHandler(v: boolean): void;
66
- isInHandler(): boolean;
67
- isExecuting(): boolean;
68
- clearPendingSyncTasks(): number;
69
- private resolveWaiters;
70
- }
71
2
 
72
3
  declare function scheduleEventHandler(handler: EventListener): EventListener;
73
- export {
74
- Task,
75
- SchedulerLane,
76
- SchedulerBulkCommitProbe,
77
- Scheduler,
78
- scheduleEventHandler,
79
- };
4
+ export { scheduleEventHandler };
@@ -1,7 +1,5 @@
1
1
  import { JSXElementType, JSXElement, Props } from '../elements.js';
2
2
  import '../jsx-globals.js';
3
- import { AuthContext, AuthRequirement } from '@askrjs/auth';
4
- import { InferSchema, ObjectSchema } from '@askrjs/schema';
5
3
  import { RenderableChild, Scope } from './context.js';
6
4
 
7
5
  /**
@@ -83,12 +81,17 @@ interface SSRPortalHostRegistration {
83
81
  interface SSRPortalSlot {
84
82
  hasValue: boolean;
85
83
  value: RenderableChild | undefined;
84
+ writers: Map<
85
+ unknown,
86
+ { owner: unknown; value: RenderableChild | undefined; order: number }
87
+ >;
86
88
  hosts: SSRPortalHostRegistration[];
87
89
  }
88
90
 
89
91
  interface SSRPortalState {
90
92
  slots: Map<object, SSRPortalSlot>;
91
93
  nextHostId: number;
94
+ nextWriteOrder: number;
92
95
  }
93
96
 
94
97
  /** Register request-local CSS produced during SSR without importing the SSR renderer in clients. */
@@ -1,8 +1,5 @@
1
1
  import { JSXElementType, JSXElement, Props } from '../elements.js';
2
2
  import '../jsx-globals.js';
3
- import { AuthContext, AuthRequirement } from '@askrjs/auth';
4
- import { InferSchema, ObjectSchema } from '@askrjs/schema';
5
- import { ReadableSource } from './component.js';
6
3
  import { capture } from './lifecycle.js';
7
4
  import { For } from './control.js';
8
5
 
@@ -13,7 +10,7 @@ import { For } from './control.js';
13
10
  * count(); // read: 0
14
11
  * count.set(1); // write: triggers re-render
15
12
  */
16
- interface State<T> extends ReadableSource<T> {
13
+ interface State<T> {
17
14
  (): T;
18
15
  set(...args: StateSetterArgs<T>): void;
19
16
  [Symbol.iterator](): IterableIterator<StateTuple<T>[number]>;
@@ -72,7 +69,7 @@ type SnapshotSourceBrand = {
72
69
  };
73
70
 
74
71
  /** A reactive derived value produced by {@link derive}; call it to read the current result. */
75
- interface Derived<T> extends ReadableSource<T> {
72
+ interface Derived<T> {
76
73
  (): T;
77
74
  }
78
75