@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,12 +1,13 @@
1
- import { t as enqueueRuntimeLane } from "../access-CEA2pOry.js";
2
- import { a as registerCommitOperation, u as routeComponentErrorToBoundary } from "../instance-VAFYVJOa.js";
3
- import { O as ownCleanup, f as getCurrentComponentInstance, h as getSignal, i as claimHookIndex } from "../scope-Cq_iYbTR.js";
4
- import { n as getComponentLifecycleSlot } from "../capabilities-Bbf0mlp9.js";
5
- import { t as createFineGrainedEffect } from "../effect-C3Zsc1k6.js";
6
- import { t as resource } from "../resource-18-sFRl9.js";
7
- import { a as routeActive, i as windowFocused, n as documentVisible, r as resolveListenerTarget, t as timer } from "../timer-C7uqnJVt.js";
8
- import { n as onRouteChange } from "../activity-oy2YFTFF.js";
9
- //#region src/runtime/lifecycle/stream.ts
1
+ import { S as queueTask } from "../instance-BAnfmXOR.js";
2
+ import { c as onCommit, i as currentComponent, n as createSource, o as hookSlot, s as notify, u as readSource } from "../hooks-BimKStr4.js";
3
+ import { a as routeActive, c as watch, i as on, n as windowFocused, o as task, r as capture, s as timer, t as documentVisible } from "../browser-activity-CB8e-V4f.js";
4
+ import { t as resource } from "../resource-CLjB7RBQ.js";
5
+ //#region src/core/api/stream.ts
6
+ /**
7
+ * stream(): a component-owned async iterable. It connects after the render
8
+ * that declared it commits, publishes each value to the components that read
9
+ * its snapshot, and disconnects with the component.
10
+ */
10
11
  function toError(value) {
11
12
  return value instanceof Error ? value : new Error(String(value));
12
13
  }
@@ -15,9 +16,7 @@ function depsEqual(left, right) {
15
16
  }
16
17
  function publish(slot) {
17
18
  if (slot.disposed) return;
18
- try {
19
- slot.owner?.notifyUpdate?.();
20
- } catch {}
19
+ notify(slot.readers);
21
20
  }
22
21
  function setStartingState(slot) {
23
22
  const retained = slot.hasValue;
@@ -29,9 +28,9 @@ function setStartingState(slot) {
29
28
  function returnIterator(generation) {
30
29
  if (generation.returned || !generation.iterator) return;
31
30
  generation.returned = true;
32
- const returnMethod = generation.iterator.return;
33
- if (typeof returnMethod !== "function") return;
34
31
  try {
32
+ const returnMethod = generation.iterator.return;
33
+ if (typeof returnMethod !== "function") return;
35
34
  Promise.resolve(returnMethod.call(generation.iterator)).catch(() => {});
36
35
  } catch {}
37
36
  }
@@ -77,7 +76,9 @@ async function consume(slot, generation, iterable) {
77
76
  }
78
77
  function startSlot(slot) {
79
78
  if (!slot.activated || slot.disposed) return;
80
- stopGeneration(slot.current);
79
+ const previous = slot.current;
80
+ stopGeneration(previous);
81
+ if (slot.disposed || slot.current !== previous) return;
81
82
  slot.explicitlyClosed = false;
82
83
  setStartingState(slot);
83
84
  publish(slot);
@@ -115,16 +116,18 @@ function startSlot(slot) {
115
116
  function queueStart(slot) {
116
117
  if (slot.startQueued || slot.disposed || slot.explicitlyClosed) return;
117
118
  slot.startQueued = true;
118
- enqueueRuntimeLane("post", () => {
119
+ queueTask(() => {
119
120
  slot.startQueued = false;
120
- if (!slot.owner?.notifyUpdate || slot.explicitlyClosed) return;
121
+ if (!slot.owner || slot.owner.disposed || slot.explicitlyClosed) return;
121
122
  startSlot(slot);
122
123
  });
123
124
  }
124
125
  function closeSlot(slot) {
125
126
  if (slot.disposed) return;
126
127
  slot.explicitlyClosed = true;
127
- stopGeneration(slot.current);
128
+ const previous = slot.current;
129
+ stopGeneration(previous);
130
+ if (slot.disposed || slot.current !== previous || !slot.explicitlyClosed) return;
128
131
  slot.current = null;
129
132
  slot.snapshot.status = "closed";
130
133
  slot.snapshot.pending = false;
@@ -161,7 +164,8 @@ function createSlot(source, options) {
161
164
  hasValue: Object.prototype.hasOwnProperty.call(options, "initialValue"),
162
165
  cleanupRegistered: false,
163
166
  startQueued: false,
164
- owner: null
167
+ owner: null,
168
+ readers: createSource()
165
169
  };
166
170
  snapshot.restart = () => {
167
171
  if (slot.disposed) return;
@@ -179,247 +183,44 @@ function disposeSlot(slot) {
179
183
  stopGeneration(slot.current);
180
184
  slot.current = null;
181
185
  slot.owner = null;
182
- if (slot.activated && false);
183
186
  slot.activated = false;
184
187
  }
188
+ function requireStreamOwner() {
189
+ const instance = currentComponent();
190
+ if (!instance) throw new Error("[Askr] stream() must be called during component render inside an app.");
191
+ return instance;
192
+ }
185
193
  function commitSlot(instance, slot) {
186
194
  const depsChanged = !depsEqual(slot.deps, slot.pendingDeps);
187
195
  const firstCommit = !slot.activated;
188
- const wasRunning = slot.current !== null;
189
196
  slot.owner = instance;
190
197
  slot.source = slot.pendingSource;
191
198
  slot.deps = slot.pendingDeps;
192
199
  if (firstCommit) slot.activated = true;
193
200
  if (!slot.cleanupRegistered) {
194
201
  slot.cleanupRegistered = true;
195
- ownCleanup(instance.owner, () => disposeSlot(slot));
202
+ instance.onCleanup(() => disposeSlot(slot));
196
203
  }
197
- if (!slot.explicitlyClosed && (firstCommit || depsChanged && wasRunning)) queueStart(slot);
198
- }
199
- function getStreamSlot(instance, index, source, options) {
200
- const slots = instance.lifecycleSlots ??= [];
201
- const existing = slots[index];
202
- if (existing) {
203
- if (existing.kind !== "stream") throw new Error(`stream() lifecycle order violation: slot ${index} already belongs to ${existing.kind ?? "another primitive"}(). Keep lifecycle primitives in a stable top-level order.`);
204
- return existing;
204
+ if (!slot.explicitlyClosed && (firstCommit || depsChanged)) queueStart(slot);
205
+ }
206
+ function stream(sourceOrGetter, connectOrOptions, drivenOptions) {
207
+ const instance = requireStreamOwner();
208
+ if (typeof connectOrOptions === "function") {
209
+ const value = sourceOrGetter();
210
+ return createStream(instance, (context) => connectOrOptions(value, context), {
211
+ ...drivenOptions,
212
+ deps: [value]
213
+ });
205
214
  }
206
- const slot = createSlot(source, options);
207
- slots[index] = slot;
208
- return slot;
215
+ return createStream(instance, sourceOrGetter, connectOrOptions ?? {});
209
216
  }
210
- /** Subscribe to a streaming data source for the current component's lifetime, with auto reconnect/cleanup. */
211
- function stream(source, options = {}) {
212
- const instance = getCurrentComponentInstance();
213
- if (!instance) return createSnapshot(options);
214
- const slot = getStreamSlot(instance, claimHookIndex(instance, "stream"), source, options);
217
+ function createStream(instance, source, options) {
218
+ const slot = hookSlot(instance, "stream", () => createSlot(source, options));
219
+ readSource(slot.readers);
215
220
  slot.pendingSource = source;
216
221
  slot.pendingDeps = (options.deps ?? []).slice();
217
- if (!instance.ssr) registerCommitOperation(() => commitSlot(instance, slot));
222
+ if (!instance.server) onCommit(instance, () => commitSlot(instance, slot));
218
223
  return slot.snapshot;
219
224
  }
220
225
  //#endregion
221
- //#region src/runtime/lifecycle/listener.ts
222
- function normalizeListenerOptions(options) {
223
- if (options === void 0 || typeof options === "boolean") return options;
224
- return {
225
- ...options.capture !== void 0 ? { capture: options.capture } : {},
226
- ...options.once !== void 0 ? { once: options.once } : {},
227
- ...options.passive !== void 0 ? { passive: options.passive } : {},
228
- ...options.signal !== void 0 ? { signal: options.signal } : {}
229
- };
230
- }
231
- function listenerOptionsEqual(a, b) {
232
- if (a === b) return true;
233
- if (typeof a === "boolean" || typeof b === "boolean") return a === b;
234
- if (!a || !b) return a === b;
235
- return a.capture === b.capture && a.once === b.once && a.passive === b.passive && a.signal === b.signal;
236
- }
237
- function detachListenerSlot(slot) {
238
- if (!slot.attached || !slot.target) return;
239
- slot.target.removeEventListener(slot.event, slot.listener, slot.options);
240
- slot.attached = false;
241
- }
242
- function commitListenerSlot(instance, slot) {
243
- slot.handler = slot.pendingHandler;
244
- const resolvedTarget = resolveListenerTarget(slot.pendingTarget);
245
- if (!slot.attached || slot.target !== resolvedTarget || slot.event !== slot.pendingEvent || !listenerOptionsEqual(slot.options, slot.pendingOptions)) {
246
- detachListenerSlot(slot);
247
- slot.target = resolvedTarget;
248
- slot.event = slot.pendingEvent;
249
- slot.options = slot.pendingOptions;
250
- if (slot.target) {
251
- slot.target.addEventListener(slot.event, slot.listener, slot.options);
252
- slot.attached = true;
253
- }
254
- }
255
- if (!slot.cleanupRegistered) {
256
- slot.cleanupRegistered = true;
257
- ownCleanup(instance.owner, () => {
258
- detachListenerSlot(slot);
259
- slot.cleanupRegistered = false;
260
- });
261
- }
262
- }
263
- /** Attach an owned event listener to `target` for the current component's lifetime. */
264
- function on(target, event, handler, options) {
265
- const instance = getCurrentComponentInstance();
266
- if (!instance) return;
267
- const index = claimHookIndex(instance, "on");
268
- const normalizedOptions = normalizeListenerOptions(options);
269
- const slot = getComponentLifecycleSlot(instance, index, "listener", () => {
270
- const createdSlot = {
271
- kind: "listener",
272
- target: null,
273
- event,
274
- handler,
275
- listener: ((evt) => {
276
- createdSlot.handler.call(createdSlot.target, evt);
277
- }),
278
- options: void 0,
279
- pendingTarget: target,
280
- pendingEvent: event,
281
- pendingHandler: handler,
282
- pendingOptions: normalizedOptions,
283
- attached: false,
284
- cleanupRegistered: false
285
- };
286
- return createdSlot;
287
- });
288
- slot.pendingTarget = target;
289
- slot.pendingEvent = event;
290
- slot.pendingHandler = handler;
291
- slot.pendingOptions = normalizedOptions;
292
- registerCommitOperation(() => {
293
- commitListenerSlot(instance, slot);
294
- });
295
- }
296
- //#endregion
297
- //#region src/runtime/lifecycle/task.ts
298
- /** Runs an owned task after commit. */
299
- function task(fn) {
300
- const instance = getCurrentComponentInstance();
301
- if (!instance) return;
302
- const index = claimHookIndex(instance, "task");
303
- const slot = getComponentLifecycleSlot(instance, index, "task", () => ({
304
- kind: "task",
305
- started: false,
306
- task: fn
307
- }));
308
- if (!slot.started) {
309
- slot.task = fn;
310
- registerCommitOperation(async () => {
311
- if (slot.started) return;
312
- slot.started = true;
313
- return await slot.task();
314
- });
315
- }
316
- }
317
- /**
318
- * Capture the result of a synchronous expression at call time and return a
319
- * thunk that returns the captured value later. This is a low-level helper for
320
- * cases where async continuations need to observe a snapshot of values at the
321
- * moment scheduling occurred.
322
- *
323
- * Usage (public API):
324
- * const snapshot = capture(() => someState());
325
- * Promise.resolve().then(() => { use(snapshot()); });
326
- */
327
- function capture(fn) {
328
- const value = fn();
329
- return () => value;
330
- }
331
- //#endregion
332
- //#region src/runtime/lifecycle/watch.ts
333
- function watchValuesEqual(previous, next) {
334
- if (previous.length !== next.length) return false;
335
- for (let index = 0; index < previous.length; index += 1) if (!Object.is(previous[index], next[index])) return false;
336
- return true;
337
- }
338
- function stopWatchGeneration(slot) {
339
- const controller = slot.controller;
340
- slot.controller = null;
341
- if (controller && !controller.signal.aborted) controller.abort();
342
- const cleanup = slot.cleanup;
343
- slot.cleanup = null;
344
- cleanup?.();
345
- }
346
- function stopWatchSlot(slot) {
347
- stopWatchGeneration(slot);
348
- slot.effect?.cleanup();
349
- slot.effect = null;
350
- }
351
- function reportWatchError(instance, error) {
352
- if (!routeComponentErrorToBoundary(instance, error)) throw error;
353
- }
354
- function commitWatchSlot(instance, slot) {
355
- slot.callback = slot.pendingCallback;
356
- slot.sources = slot.pendingSources;
357
- const compute = () => {
358
- const values = slot.sources.map((source) => source());
359
- return values.length === 1 ? values[0] : values;
360
- };
361
- const observe = (value, previous) => {
362
- stopWatchGeneration(slot);
363
- const controller = new AbortController();
364
- slot.controller = controller;
365
- const initial = !slot.hasObserved;
366
- slot.hasObserved = true;
367
- let result;
368
- try {
369
- result = slot.callback(value, {
370
- initial,
371
- previous,
372
- signal: controller.signal
373
- });
374
- } catch (error) {
375
- reportWatchError(instance, error);
376
- return;
377
- }
378
- if (typeof result === "function") {
379
- slot.cleanup = result;
380
- return;
381
- }
382
- if (result && typeof result.then === "function") Promise.resolve(result).catch((error) => {
383
- if (!controller.signal.aborted) reportWatchError(instance, error);
384
- });
385
- };
386
- if (!slot.effect) slot.effect = createFineGrainedEffect({
387
- lane: "post",
388
- compute,
389
- commit: observe,
390
- equals: (previous, next) => Array.isArray(previous) && Array.isArray(next) ? watchValuesEqual(previous, next) : Object.is(previous, next),
391
- onError: (error) => reportWatchError(instance, error)
392
- });
393
- else slot.effect.updateCompute(compute);
394
- if (!slot.cleanupRegistered) {
395
- slot.cleanupRegistered = true;
396
- ownCleanup(instance.owner, () => {
397
- stopWatchSlot(slot);
398
- slot.cleanupRegistered = false;
399
- });
400
- }
401
- }
402
- function watch(sourceOrSources, callback) {
403
- const instance = getCurrentComponentInstance();
404
- if (!instance) return;
405
- const index = claimHookIndex(instance, "watch");
406
- const sources = Array.isArray(sourceOrSources) ? sourceOrSources : [sourceOrSources];
407
- const slot = getComponentLifecycleSlot(instance, index, "watch", () => ({
408
- kind: "watch",
409
- sources,
410
- pendingSources: sources,
411
- callback,
412
- pendingCallback: callback,
413
- effect: null,
414
- controller: null,
415
- cleanup: null,
416
- cleanupRegistered: false,
417
- hasObserved: false
418
- }));
419
- slot.pendingSources = sources;
420
- slot.pendingCallback = callback;
421
- if (instance.ssr) return;
422
- registerCommitOperation(() => commitWatchSlot(instance, slot));
423
- }
424
- //#endregion
425
- export { capture, documentVisible, getSignal, on, onRouteChange, resource, routeActive, stream, task, timer, watch, windowFocused };
226
+ export { capture, documentVisible, on, resource, routeActive, stream, task, timer, watch, windowFocused };
@@ -60,8 +60,8 @@ import {
60
60
  AuthContext as AuthContext$1,
61
61
  AuthRequirement,
62
62
  AuthRequirement as AuthRequirement$1,
63
- } from '@askrjs/auth';
64
- import { ObjectSchema } from '@askrjs/schema';
63
+ ObjectSchema,
64
+ } from '../peer-types.js';
65
65
  /** A single query-string value accepted by {@link updateRouteQuery}. */
66
66
  type RouteQueryParamValue = string | number | boolean | null | undefined;
67
67
  /** A query-string value, or an array of them for a repeated param. */
@@ -222,6 +222,11 @@ declare function resolveRouteRequest(
222
222
  target: string,
223
223
  options: RouteRequestOptions
224
224
  ): RouteRequestResult | Promise<RouteRequestResult>;
225
+ /** Match a path against a route registry without resolving route policies or loading data. */
226
+ declare function matchRoute(
227
+ pathname: string,
228
+ options: { registry: RouteRegistry }
229
+ ): RouteMatch | null;
225
230
  /**
226
231
  * Run `definition` to declare routes (via `route`/`page`/`group`/`fallback`)
227
232
  * and build a {@link RouteRegistry} to pass to `createSPA`/`hydrateSPA`.
@@ -268,7 +273,7 @@ declare function lazyRouteData<TModule, TData = TModule>(
268
273
  declare function Outlet(): JSXElement;
269
274
  /** Which environment a route's data loader ran (or failed) in. */
270
275
  type RouteDataLoadPhase = 'client' | 'server' | 'ssg';
271
- /** Thrown when a route's `loader` rejects; wraps the original `cause`. */
276
+ /** Rejection of a `lazyRouteData()` loader whose import or `select` failed; wraps the original `cause`. */
272
277
  declare class RouteDataLoadError extends Error {
273
278
  readonly route: string;
274
279
  readonly phase: RouteDataLoadPhase;
@@ -277,9 +282,12 @@ declare class RouteDataLoadError extends Error {
277
282
  }
278
283
  /** Policy decision: allow the route to render. */
279
284
  declare function allow(): AccessAllowDecision;
280
- /** Policy decision: redirect the visitor to `to`. */
285
+ /**
286
+ * Policy decision: redirect the visitor to `to`. A string is a logical path
287
+ * that gains the registry `basePath`; a `to()` destination is used as-is.
288
+ */
281
289
  declare function redirect(
282
- to: string,
290
+ to: string | RouteDestination,
283
291
  init?: {
284
292
  status?: AccessRedirectStatus;
285
293
  replace?: boolean;
@@ -514,6 +522,7 @@ export {
514
522
  isDeferred,
515
523
  lazy,
516
524
  lazyRouteData,
525
+ matchRoute,
517
526
  navigate,
518
527
  notFound,
519
528
  onRouteChange,
@@ -1,13 +1,12 @@
1
- import { n as createRouteRegistry } from "../manifest-D1P3UNWV.js";
2
- import { n as isSafeHref } from "../router-internal-7nuNEHfG.js";
3
- import { t as jsx } from "../jsx-runtime-CPJXAOBF.js";
4
- import { a as serializeRouteMeta, c as getCurrentHref, d as parseTargetUrl, h as syncRegisteredRouteSnapshot, i as resolveRouteMeta, l as getRegisteredAppsSnapshot, m as syncAppRegistrationLocation, n as navigate, p as setCurrentRouteLocation, r as reconcileRouteMeta, s as saveScrollPosition, u as getWindowHref } from "../navigate-prC5V8XV.js";
5
- import { n as onRouteChange, t as currentRoute } from "../activity-oy2YFTFF.js";
6
- import { S as isDeferred, a as resolveRouteRequest, c as Outlet, f as lazy, m as RouteDataLoadError, p as lazyRouteData, s as currentAuth, x as defer } from "../resolution-3DskUkjG.js";
7
- import { b as getActiveRouteBasePath, o as addRouteBasePath } from "../route-matching-CUzZ31gT.js";
8
- import { a as group, c as route, i as fallback, n as resolveDeferredValues, o as index, r as routeData, s as page, t as Resolve } from "../deferred-CbgNhf67.js";
9
- import { i as mergeProps } from "../aria-hKjThHcp.js";
10
- import { t as applyInteractionPolicy } from "../interactions-CTeACdT_.js";
1
+ import { n as jsx } from "../jsx-runtime-C4idqHY0.js";
2
+ import { C as currentRoute, a as nextHistoryIndex, b as syncRegisteredRouteSnapshot, c as reconcileRouteMeta, f as saveScrollPosition, g as parseTargetUrl, h as getWindowHref, i as commitHistoryIndex, l as resolveRouteMeta, m as getRegisteredAppsSnapshot, n as navigate, p as getCurrentHref, r as navigateToPublicHref, u as serializeRouteMeta, v as setCurrentRouteLocation, w as onRouteChange, x as toDocumentUrl, y as syncAppRegistrationLocation } from "../navigate-CP_0Zy5U.js";
3
+ import { f as defer, p as isDeferred } from "../query-registry-WMCN0BJL.js";
4
+ import { M as getActiveRouteBasePath, a as resolveRouteRequest, at as lazyRouteData, b as addLogicalRouteBasePath, c as forbidden, ct as encodePathSegment, d as unauthorized, et as Outlet, f as currentAuth, it as lazy, l as notFound, o as allow, ot as RouteDataLoadError, s as deny, u as redirect, v as matchRoute, x as addRouteBasePath } from "../resolution-Cx82-xjW.js";
5
+ import { n as createRouteRegistry } from "../manifest-CW9gyNBY.js";
6
+ import { a as group, c as route, i as fallback, n as resolveDeferredValues, o as index, r as routeData, s as page, t as Resolve } from "../deferred-bEEHHvic.js";
7
+ import { a as isSafeHref, r as assertPathHrefStaysOnOrigin } from "../url-CnbfpX0K.js";
8
+ import { o as mergeProps } from "../compose-ref-DWzdbxsD.js";
9
+ import { t as applyInteractionPolicy } from "../interactions-D2BoREb-.js";
11
10
  //#region src/router/route-query.ts
12
11
  function getRouteQueryHistoryMode(options) {
13
12
  if (options.history) return options.history;
@@ -34,56 +33,26 @@ function applyRouteQueryUpdates(searchParams, updates) {
34
33
  }
35
34
  function updateRouteQuery(updates, options = {}) {
36
35
  if (typeof window === "undefined") return;
37
- const url = parseTargetUrl(getWindowHref());
36
+ const url = parseTargetUrl("");
37
+ url.hash = window.location.hash;
38
38
  applyRouteQueryUpdates(url.searchParams, updates);
39
39
  const href = `${url.pathname}${url.search}${url.hash}`;
40
40
  if (href === getWindowHref()) return;
41
41
  const historyMode = getRouteQueryHistoryMode(options);
42
42
  if (historyMode === "push") saveScrollPosition(getCurrentHref());
43
43
  const state = window.history.state && typeof window.history.state === "object" ? window.history.state : {};
44
+ const historyIndex = nextHistoryIndex(historyMode);
44
45
  window.history[historyMode === "replace" ? "replaceState" : "pushState"]({
45
46
  ...state,
46
- path: href
47
- }, "", href);
47
+ path: href,
48
+ askrIndex: historyIndex
49
+ }, "", toDocumentUrl(href));
50
+ commitHistoryIndex(historyIndex);
48
51
  setCurrentRouteLocation(url.pathname, href);
49
52
  for (const app of getRegisteredAppsSnapshot()) syncAppRegistrationLocation(app, url.pathname, href);
50
53
  syncRegisteredRouteSnapshot();
51
54
  }
52
55
  //#endregion
53
- //#region src/router/policy.ts
54
- /** Policy decision: allow the route to render. */
55
- function allow() {
56
- return { kind: "allow" };
57
- }
58
- /** Policy decision: redirect the visitor to `to`. */
59
- function redirect(to, init = {}) {
60
- return {
61
- kind: "redirect",
62
- to,
63
- ...init.status ? { status: init.status } : {},
64
- ...init.replace !== void 0 ? { replace: init.replace } : {}
65
- };
66
- }
67
- /** Policy decision: deny the request with the given HTTP status. */
68
- function deny(status) {
69
- return {
70
- kind: "deny",
71
- status
72
- };
73
- }
74
- /** Policy decision: deny with 401 Unauthorized. */
75
- function unauthorized() {
76
- return deny(401);
77
- }
78
- /** Policy decision: deny with 403 Forbidden. */
79
- function forbidden() {
80
- return deny(403);
81
- }
82
- /** Policy decision: deny with 404 Not Found. */
83
- function notFound() {
84
- return deny(404);
85
- }
86
- //#endregion
87
56
  //#region src/router/destination.ts
88
57
  function routeParameterName(segment) {
89
58
  if (segment === "*") return {
@@ -101,7 +70,7 @@ function routeParameterName(segment) {
101
70
  };
102
71
  }
103
72
  function encodeParameter(value, splat) {
104
- return splat ? value.split("/").map((part) => encodeURIComponent(part)).join("/") : encodeURIComponent(value);
73
+ return splat ? value.split("/").map(encodePathSegment).join("/") : encodePathSegment(value);
105
74
  }
106
75
  function buildPath(route, params) {
107
76
  return route.path.split("/").map((segment) => {
@@ -176,18 +145,18 @@ function isSameOriginNavigableHref(href) {
176
145
  * - Composable via mergeProps
177
146
  */
178
147
  function Link({ href: suppliedHref, to, class: className, children, rel, target, "aria-current": ariaCurrent, "aria-label": ariaLabel, onPress, onClick, ...rest }) {
179
- const supplied = to?.href ?? suppliedHref;
180
- const href = supplied ? addRouteBasePath(supplied, getActiveRouteBasePath()) : supplied;
148
+ const href = to?.href ?? (suppliedHref ? addLogicalRouteBasePath(suppliedHref, getActiveRouteBasePath()) : suppliedHref);
181
149
  if (!href) throw new Error("Link requires href or to.");
182
150
  if (!isSafeHref(href)) throw new TypeError("Link href uses an unsafe URL scheme.");
151
+ assertPathHrefStaysOnOrigin(href);
183
152
  const handleNavigation = (e) => {
184
153
  if (e.defaultPrevented) return;
185
154
  const event = e;
186
155
  if ((event.button ?? 0) !== 0 || event.ctrlKey || event.metaKey || event.shiftKey || event.altKey) return;
187
- if (target || !isSameOriginNavigableHref(href)) return;
156
+ if (target && target.toLowerCase() !== "_self" || !isSameOriginNavigableHref(href)) return;
188
157
  if (rest.download !== void 0) return;
189
158
  event.preventDefault();
190
- navigate(href);
159
+ navigateToPublicHref(href);
191
160
  };
192
161
  const interaction = applyInteractionPolicy({
193
162
  isNative: true,
@@ -215,4 +184,4 @@ function Link({ href: suppliedHref, to, class: className, children, rel, target,
215
184
  });
216
185
  }
217
186
  //#endregion
218
- export { Link, Outlet, Resolve, RouteDataLoadError, allow, createRouteRegistry, currentAuth, currentRoute, defer, deny, fallback, forbidden, group, index, isDeferred, lazy, lazyRouteData, navigate, notFound, onRouteChange, page, reconcileRouteMeta, redirect, resolveDeferredValues, resolveRouteMeta, resolveRouteRequest, route, routeData, serializeRouteMeta, to, unauthorized, updateRouteQuery };
187
+ export { Link, Outlet, Resolve, RouteDataLoadError, allow, createRouteRegistry, currentAuth, currentRoute, defer, deny, fallback, forbidden, group, index, isDeferred, lazy, lazyRouteData, matchRoute, navigate, notFound, onRouteChange, page, reconcileRouteMeta, redirect, resolveDeferredValues, resolveRouteMeta, resolveRouteRequest, route, routeData, serializeRouteMeta, to, unauthorized, updateRouteQuery };
@@ -0,0 +1,55 @@
1
+ import { M as getOwner } from "./instance-BAnfmXOR.js";
2
+ import { n as Fragment, t as ELEMENT_TYPE } from "./jsx-DRS-qjiN.js";
3
+ import { i as currentComponent } from "./hooks-BimKStr4.js";
4
+ //#region src/core/api/scope.ts
5
+ /**
6
+ * Lexical scopes. A scope's provider is a component that records its value
7
+ * on its own lifetime; `readScope()` finds the nearest provider by walking up
8
+ * the owner tree from the code that is running.
9
+ */
10
+ function ScopeProvider(props) {
11
+ currentComponent()?.provide(props.scopeKey, props.value);
12
+ if (typeof Node !== "undefined" && props.children instanceof Node) return null;
13
+ return {
14
+ $$typeof: ELEMENT_TYPE,
15
+ type: Fragment,
16
+ props: { children: props.children },
17
+ key: null
18
+ };
19
+ }
20
+ /** Create a scope whose value defaults to `defaultValue`. */
21
+ function defineScope(defaultValue) {
22
+ const key = Symbol("AskrScope");
23
+ const scope = (props) => ({
24
+ $$typeof: ELEMENT_TYPE,
25
+ type: ScopeProvider,
26
+ props: {
27
+ scopeKey: key,
28
+ value: props.value,
29
+ children: props.children
30
+ },
31
+ key: null
32
+ });
33
+ return Object.assign(scope, {
34
+ key,
35
+ defaultValue
36
+ });
37
+ }
38
+ const NOT_FOUND = Symbol("not-found");
39
+ /** Whether `readScope()` can run here (inside a render or owned callback). */
40
+ function isScopeReadable() {
41
+ return getOwner() !== null;
42
+ }
43
+ /** Read the nearest provided value of `scope`, or its default. */
44
+ function readScope(scope) {
45
+ const owner = getOwner();
46
+ if (!owner) throw new Error("readScope() can only be called during component render or async resource execution. Ensure you are calling this from inside your component or resource function.");
47
+ const value = lookup(owner, scope.key);
48
+ return value === NOT_FOUND ? scope.defaultValue : value;
49
+ }
50
+ function lookup(owner, key) {
51
+ for (let o = owner; o; o = o.parent) if (o.context?.has(key)) return o.context.get(key);
52
+ return NOT_FOUND;
53
+ }
54
+ //#endregion
55
+ export { isScopeReadable as n, readScope as r, defineScope as t };
@@ -1,10 +1,4 @@
1
- import { t as notifyReadableSource } from "./notify-DxxuDPeY.js";
2
1
  //#region src/data/shared.ts
3
- function createReadableSource() {
4
- return (() => void 0);
5
- }
6
- /** Re-exported so data cells keep their existing name for the shared fan-out. */
7
- const notifySource = notifyReadableSource;
8
2
  function isAbortError(error, signal) {
9
3
  return signal.aborted || error instanceof Error && error.name === "AbortError" || typeof DOMException !== "undefined" && error instanceof DOMException && error.name === "AbortError";
10
4
  }
@@ -21,4 +15,4 @@ function normalizeAsyncDataError(error, fallbackMessage) {
21
15
  return new Error(error == null ? fallbackMessage : String(error));
22
16
  }
23
17
  //#endregion
24
- export { normalizeAsyncDataError as a, isCurrentAsyncOperation as i, isAbortError as n, notifySource as o, isCurrentAsyncGeneration as r, createReadableSource as t };
18
+ export { normalizeAsyncDataError as i, isCurrentAsyncGeneration as n, isCurrentAsyncOperation as r, isAbortError as t };
@@ -1,4 +1,9 @@
1
- //#region src/runtime/reactivity/snapshot-source.ts
1
+ //#region src/core/api/snapshot.ts
2
+ /**
3
+ * The brand that marks an async snapshot (`resource()`, queries) so
4
+ * `derive(source, map)` can wait for it to settle. The symbol is global so
5
+ * every copy of the package agrees on it.
6
+ */
2
7
  const SNAPSHOT_SOURCE_BRAND = Symbol.for("__ASKR_SNAPSHOT_SOURCE__");
3
8
  function brandSnapshotSource(value) {
4
9
  Object.defineProperty(value, SNAPSHOT_SOURCE_BRAND, {
@@ -9,8 +9,7 @@ import {
9
9
  DocumentRenderArgs,
10
10
  RoutePolicy,
11
11
  } from '../core.js';
12
- import { AuthRequirement } from '@askrjs/auth';
13
- import 'node:fs/promises';
12
+ import { AuthRequirement } from '../peer-types.js';
14
13
  /** Whether an SSG run rebuilds every route (`full`) or only changed ones (`incremental`). */
15
14
  type SSGMode = 'full' | 'incremental';
16
15
  /** Outcome of generating a single route's static HTML. */