@async/framework 0.7.0 → 0.9.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.
- package/CHANGELOG.md +22 -0
- package/README.md +122 -14
- package/{framework.d.ts → browser.d.ts} +118 -4
- package/{framework.js → browser.js} +898 -127
- package/browser.min.js +1 -0
- package/{framework.ts → browser.ts} +899 -128
- package/{framework.umd.js → browser.umd.js} +898 -127
- package/browser.umd.min.js +1 -0
- package/package.json +45 -30
- package/server.d.ts +690 -0
- package/src/app.js +110 -11
- package/src/async-signal.js +32 -4
- package/src/boundary-receiver.js +302 -0
- package/src/browser.js +16 -0
- package/src/component.js +42 -7
- package/src/index.js +6 -2
- package/src/loader.js +42 -10
- package/src/request-context.js +40 -0
- package/src/router.js +15 -2
- package/src/scheduler.js +300 -0
- package/src/server-entry.js +20 -0
- package/src/server-registry.js +97 -0
- package/src/server.js +5 -88
- package/src/signals.js +38 -6
- package/framework.min.js +0 -3820
- package/framework.umd.min.js +0 -3843
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// Generated by scripts/build-framework-bundle.js. Do not edit by hand.
|
|
2
2
|
// @ts-nocheck
|
|
3
|
-
// Bundled TypeScript source entry for TS-aware runtimes and higher-layer tooling.
|
|
3
|
+
// Bundled browser TypeScript source entry for TS-aware runtimes and higher-layer tooling.
|
|
4
4
|
|
|
5
5
|
const __asyncSignalModule = (() => {
|
|
6
6
|
const asyncSignalKind = Symbol.for("@async/framework.asyncSignal");
|
|
@@ -95,7 +95,8 @@ const __asyncSignalModule = (() => {
|
|
|
95
95
|
router: context.router,
|
|
96
96
|
loader: context.loader,
|
|
97
97
|
cache: context.cache,
|
|
98
|
-
abort: activeAbort
|
|
98
|
+
abort: activeAbort,
|
|
99
|
+
scheduler: context.scheduler
|
|
99
100
|
});
|
|
100
101
|
}
|
|
101
102
|
return server;
|
|
@@ -109,6 +110,9 @@ const __asyncSignalModule = (() => {
|
|
|
109
110
|
get cache() {
|
|
110
111
|
return registry._context?.().cache;
|
|
111
112
|
},
|
|
113
|
+
get scheduler() {
|
|
114
|
+
return registry._context?.().scheduler;
|
|
115
|
+
},
|
|
112
116
|
get version() {
|
|
113
117
|
return runVersion;
|
|
114
118
|
},
|
|
@@ -185,11 +189,20 @@ const __asyncSignalModule = (() => {
|
|
|
185
189
|
_bindRegistry(nextRegistry, nextId) {
|
|
186
190
|
registry = nextRegistry;
|
|
187
191
|
registeredId = nextId;
|
|
188
|
-
|
|
192
|
+
const start = () => {
|
|
189
193
|
if (registry === nextRegistry && status === "idle") {
|
|
190
194
|
state.refresh();
|
|
191
195
|
}
|
|
192
|
-
}
|
|
196
|
+
};
|
|
197
|
+
const scheduler = registry._context?.().scheduler;
|
|
198
|
+
if (scheduler) {
|
|
199
|
+
scheduler.enqueue("async", start, {
|
|
200
|
+
scope: registeredId,
|
|
201
|
+
key: `asyncSignal:${registeredId}:initial`
|
|
202
|
+
});
|
|
203
|
+
} else {
|
|
204
|
+
queueMicrotask(start);
|
|
205
|
+
}
|
|
193
206
|
},
|
|
194
207
|
|
|
195
208
|
_dispose() {
|
|
@@ -225,11 +238,26 @@ const __asyncSignalModule = (() => {
|
|
|
225
238
|
for (const dependency of dependencies) {
|
|
226
239
|
const dependencyId = String(dependency).split(".")[0];
|
|
227
240
|
if (dependencyId && dependencyId !== registeredId) {
|
|
228
|
-
dependencyCleanups.add(registry.subscribe(dependency, () =>
|
|
241
|
+
dependencyCleanups.add(registry.subscribe(dependency, () => scheduleRefresh()));
|
|
229
242
|
}
|
|
230
243
|
}
|
|
231
244
|
}
|
|
232
245
|
|
|
246
|
+
function scheduleRefresh() {
|
|
247
|
+
if (activeAbort && !activeAbort.aborted) {
|
|
248
|
+
activeAbort.cancel(new Error(`Async signal "${registeredId}" dependency changed.`));
|
|
249
|
+
}
|
|
250
|
+
const scheduler = registry?._context?.().scheduler;
|
|
251
|
+
if (!scheduler) {
|
|
252
|
+
state.refresh();
|
|
253
|
+
return;
|
|
254
|
+
}
|
|
255
|
+
scheduler.enqueue("async", () => state.refresh(), {
|
|
256
|
+
scope: registeredId,
|
|
257
|
+
key: `asyncSignal:${registeredId}:refresh`
|
|
258
|
+
});
|
|
259
|
+
}
|
|
260
|
+
|
|
233
261
|
function notify() {
|
|
234
262
|
for (const subscriber of [...subscribers]) {
|
|
235
263
|
subscriber(state);
|
|
@@ -866,7 +894,8 @@ const __signalsModule = (() => {
|
|
|
866
894
|
server: registry._context?.().server,
|
|
867
895
|
router: registry._context?.().router,
|
|
868
896
|
loader: registry._context?.().loader,
|
|
869
|
-
cache: registry._context?.().cache
|
|
897
|
+
cache: registry._context?.().cache,
|
|
898
|
+
scheduler: registry._context?.().scheduler
|
|
870
899
|
}));
|
|
871
900
|
});
|
|
872
901
|
}
|
|
@@ -894,6 +923,8 @@ const __signalsModule = (() => {
|
|
|
894
923
|
const registryCleanups = new Map();
|
|
895
924
|
const runtimeContext = {};
|
|
896
925
|
const boundEntries = new Set();
|
|
926
|
+
let subscriptionCounter = 0;
|
|
927
|
+
let effectCounter = 0;
|
|
897
928
|
|
|
898
929
|
const registry = attachRegistryInspection({
|
|
899
930
|
register(id, signalLike) {
|
|
@@ -969,17 +1000,21 @@ const __signalsModule = (() => {
|
|
|
969
1000
|
return createRef(registry, id);
|
|
970
1001
|
},
|
|
971
1002
|
|
|
972
|
-
subscribe(path, fn) {
|
|
1003
|
+
subscribe(path, fn, options = {}) {
|
|
973
1004
|
if (typeof fn !== "function") {
|
|
974
1005
|
throw new TypeError("subscribe(path, fn) requires a function.");
|
|
975
1006
|
}
|
|
976
1007
|
const parsed = parsePath(path, entries);
|
|
977
1008
|
const entry = requireEntry(entries, parsed.id);
|
|
1009
|
+
const subscriptionId = ++subscriptionCounter;
|
|
978
1010
|
return entry.subscribe(() => {
|
|
979
|
-
fn(registry.get(parsed.path), {
|
|
1011
|
+
scheduleCallback(() => fn(registry.get(parsed.path), {
|
|
980
1012
|
id: parsed.id,
|
|
981
1013
|
path: parsed.path,
|
|
982
1014
|
signal: entry
|
|
1015
|
+
}), {
|
|
1016
|
+
...options,
|
|
1017
|
+
key: options.key ?? `signal:${parsed.path}:${subscriptionId}`
|
|
983
1018
|
});
|
|
984
1019
|
});
|
|
985
1020
|
},
|
|
@@ -997,10 +1032,12 @@ const __signalsModule = (() => {
|
|
|
997
1032
|
return registry.ref(id);
|
|
998
1033
|
},
|
|
999
1034
|
|
|
1000
|
-
effect(fn) {
|
|
1035
|
+
effect(fn, options = {}) {
|
|
1001
1036
|
let cleanup;
|
|
1002
1037
|
let dependencyCleanups = [];
|
|
1003
1038
|
let stopped = false;
|
|
1039
|
+
const scheduler = options.scheduler;
|
|
1040
|
+
const effectId = ++effectCounter;
|
|
1004
1041
|
|
|
1005
1042
|
const run = () => {
|
|
1006
1043
|
if (stopped) {
|
|
@@ -1019,10 +1056,22 @@ const __signalsModule = (() => {
|
|
|
1019
1056
|
server: runtimeContext.server,
|
|
1020
1057
|
router: runtimeContext.router,
|
|
1021
1058
|
loader: runtimeContext.loader,
|
|
1022
|
-
cache: runtimeContext.cache
|
|
1059
|
+
cache: runtimeContext.cache,
|
|
1060
|
+
scheduler: runtimeContext.scheduler
|
|
1023
1061
|
}));
|
|
1024
1062
|
cleanup = outcome.value;
|
|
1025
|
-
dependencyCleanups = outcome.dependencies.map((dependency) => registry.subscribe(dependency,
|
|
1063
|
+
dependencyCleanups = outcome.dependencies.map((dependency) => registry.subscribe(dependency, scheduleRun));
|
|
1064
|
+
};
|
|
1065
|
+
|
|
1066
|
+
const scheduleRun = () => {
|
|
1067
|
+
if (!scheduler) {
|
|
1068
|
+
run();
|
|
1069
|
+
return;
|
|
1070
|
+
}
|
|
1071
|
+
scheduler.enqueue(options.phase ?? "effect", run, {
|
|
1072
|
+
scope: options.scope,
|
|
1073
|
+
key: options.key ?? `effect:${effectId}`
|
|
1074
|
+
});
|
|
1026
1075
|
};
|
|
1027
1076
|
|
|
1028
1077
|
run();
|
|
@@ -1099,6 +1148,17 @@ const __signalsModule = (() => {
|
|
|
1099
1148
|
registryCleanups.set(id, cleanup);
|
|
1100
1149
|
}
|
|
1101
1150
|
}
|
|
1151
|
+
|
|
1152
|
+
function scheduleCallback(fn, options = {}) {
|
|
1153
|
+
const scheduler = options.scheduler;
|
|
1154
|
+
if (!scheduler || options.phase === "sync") {
|
|
1155
|
+
return fn();
|
|
1156
|
+
}
|
|
1157
|
+
return scheduler.enqueue(options.phase ?? "effect", fn, {
|
|
1158
|
+
scope: options.scope,
|
|
1159
|
+
key: options.key
|
|
1160
|
+
});
|
|
1161
|
+
}
|
|
1102
1162
|
}
|
|
1103
1163
|
|
|
1104
1164
|
function normalizeSignal(signalLike) {
|
|
@@ -1565,10 +1625,15 @@ const __componentModule = (() => {
|
|
|
1565
1625
|
html,
|
|
1566
1626
|
attach(target) {
|
|
1567
1627
|
for (const hook of attachHooks) {
|
|
1568
|
-
|
|
1569
|
-
|
|
1570
|
-
|
|
1571
|
-
|
|
1628
|
+
runtime.scheduler?.enqueue("lifecycle", () => {
|
|
1629
|
+
const cleanup = hook(target);
|
|
1630
|
+
if (typeof cleanup === "function") {
|
|
1631
|
+
cleanups.push(cleanup);
|
|
1632
|
+
}
|
|
1633
|
+
}, {
|
|
1634
|
+
scope,
|
|
1635
|
+
key: `attach:${attachHooks.indexOf(hook)}`
|
|
1636
|
+
}) ?? runAttachHook(hook, target);
|
|
1572
1637
|
}
|
|
1573
1638
|
},
|
|
1574
1639
|
mount(target) {
|
|
@@ -1576,7 +1641,17 @@ const __componentModule = (() => {
|
|
|
1576
1641
|
},
|
|
1577
1642
|
visible(target, observeVisible) {
|
|
1578
1643
|
for (const hook of visibleHooks) {
|
|
1579
|
-
const cleanup = observeVisible(target,
|
|
1644
|
+
const cleanup = observeVisible(target, () => {
|
|
1645
|
+
runtime.scheduler?.enqueue("lifecycle", () => {
|
|
1646
|
+
const hookCleanup = hook(target);
|
|
1647
|
+
if (typeof hookCleanup === "function") {
|
|
1648
|
+
cleanups.push(hookCleanup);
|
|
1649
|
+
}
|
|
1650
|
+
}, {
|
|
1651
|
+
scope,
|
|
1652
|
+
key: `visible:${visibleHooks.indexOf(hook)}`
|
|
1653
|
+
}) ?? runVisibleHook(hook, target);
|
|
1654
|
+
});
|
|
1580
1655
|
if (typeof cleanup === "function") {
|
|
1581
1656
|
cleanups.push(cleanup);
|
|
1582
1657
|
}
|
|
@@ -1586,6 +1661,7 @@ const __componentModule = (() => {
|
|
|
1586
1661
|
while (destroyHooks.length > 0) {
|
|
1587
1662
|
destroyHooks.pop()?.();
|
|
1588
1663
|
}
|
|
1664
|
+
runtime.scheduler?.markScopeDestroyed(scope);
|
|
1589
1665
|
while (cleanups.length > 0) {
|
|
1590
1666
|
cleanups.pop()?.();
|
|
1591
1667
|
}
|
|
@@ -1594,10 +1670,24 @@ const __componentModule = (() => {
|
|
|
1594
1670
|
}
|
|
1595
1671
|
}
|
|
1596
1672
|
};
|
|
1673
|
+
|
|
1674
|
+
function runAttachHook(hook, target) {
|
|
1675
|
+
const cleanup = hook(target);
|
|
1676
|
+
if (typeof cleanup === "function") {
|
|
1677
|
+
cleanups.push(cleanup);
|
|
1678
|
+
}
|
|
1679
|
+
}
|
|
1680
|
+
|
|
1681
|
+
function runVisibleHook(hook, target) {
|
|
1682
|
+
const cleanup = hook(target);
|
|
1683
|
+
if (typeof cleanup === "function") {
|
|
1684
|
+
cleanups.push(cleanup);
|
|
1685
|
+
}
|
|
1686
|
+
}
|
|
1597
1687
|
}
|
|
1598
1688
|
|
|
1599
1689
|
function createComponentContext({ runtime, scope, cleanups, attachHooks, visibleHooks, destroyHooks, renderScopedTemplate }) {
|
|
1600
|
-
const { signals, handlers, loader, server, router, cache } = runtime;
|
|
1690
|
+
const { signals, handlers, loader, server, router, cache, scheduler } = runtime;
|
|
1601
1691
|
const generatedHandlers = new WeakMap();
|
|
1602
1692
|
let generatedHandlerCounter = 0;
|
|
1603
1693
|
let generatedSignalCounter = 0;
|
|
@@ -1609,6 +1699,7 @@ const __componentModule = (() => {
|
|
|
1609
1699
|
server,
|
|
1610
1700
|
router,
|
|
1611
1701
|
cache,
|
|
1702
|
+
scheduler,
|
|
1612
1703
|
|
|
1613
1704
|
signal(name, initial) {
|
|
1614
1705
|
if (arguments.length === 1) {
|
|
@@ -1653,7 +1744,11 @@ const __componentModule = (() => {
|
|
|
1653
1744
|
},
|
|
1654
1745
|
|
|
1655
1746
|
effect(fn) {
|
|
1656
|
-
const cleanup = signals.effect(() => fn.call(context)
|
|
1747
|
+
const cleanup = signals.effect(() => fn.call(context), {
|
|
1748
|
+
scheduler,
|
|
1749
|
+
phase: "effect",
|
|
1750
|
+
scope
|
|
1751
|
+
});
|
|
1657
1752
|
cleanups.push(cleanup);
|
|
1658
1753
|
return cleanup;
|
|
1659
1754
|
},
|
|
@@ -1775,93 +1870,10 @@ const __componentModule = (() => {
|
|
|
1775
1870
|
})();
|
|
1776
1871
|
|
|
1777
1872
|
const __serverModule = (() => {
|
|
1778
|
-
const { attachRegistryInspection, createRegistryStore } = __registryStoreModule;
|
|
1779
1873
|
const serverEnvelopeKeys = new Set(["value", "signals", "boundary", "html", "redirect", "error"]);
|
|
1780
1874
|
const appliedServerResult = Symbol.for("@async/framework.appliedServerResult");
|
|
1781
1875
|
const appliedServerValues = new WeakSet();
|
|
1782
1876
|
|
|
1783
|
-
function createServerRegistry(initialMap = {}, options = {}) {
|
|
1784
|
-
const registryStore = options.registry ?? createRegistryStore();
|
|
1785
|
-
const type = options.type ?? "server";
|
|
1786
|
-
const entries = registryStore._map(type);
|
|
1787
|
-
const defaults = {};
|
|
1788
|
-
|
|
1789
|
-
const registry = attachRegistryInspection({
|
|
1790
|
-
register(id, fn) {
|
|
1791
|
-
assertServerId(id);
|
|
1792
|
-
if (typeof fn !== "function") {
|
|
1793
|
-
throw new TypeError(`Server function "${id}" must be a function.`);
|
|
1794
|
-
}
|
|
1795
|
-
if (entries.has(id)) {
|
|
1796
|
-
throw new Error(`Server function "${id}" is already registered.`);
|
|
1797
|
-
}
|
|
1798
|
-
entries.set(id, fn);
|
|
1799
|
-
return id;
|
|
1800
|
-
},
|
|
1801
|
-
|
|
1802
|
-
registerMany(map) {
|
|
1803
|
-
for (const [id, fn] of Object.entries(map ?? {})) {
|
|
1804
|
-
registry.register(id, fn);
|
|
1805
|
-
}
|
|
1806
|
-
return registry;
|
|
1807
|
-
},
|
|
1808
|
-
|
|
1809
|
-
unregister(id) {
|
|
1810
|
-
assertServerId(id);
|
|
1811
|
-
return entries.delete(id);
|
|
1812
|
-
},
|
|
1813
|
-
|
|
1814
|
-
resolve(id) {
|
|
1815
|
-
assertServerId(id);
|
|
1816
|
-
return entries.get(id);
|
|
1817
|
-
},
|
|
1818
|
-
|
|
1819
|
-
async run(id, args = [], context = {}) {
|
|
1820
|
-
assertServerId(id);
|
|
1821
|
-
const fn = registry.resolve(id);
|
|
1822
|
-
if (!fn) {
|
|
1823
|
-
throw new Error(`Server function "${id}" is not registered.`);
|
|
1824
|
-
}
|
|
1825
|
-
|
|
1826
|
-
let runContext;
|
|
1827
|
-
const server = createServerNamespace((childId, childArgs, childContext = {}) => {
|
|
1828
|
-
return registry.run(childId, childArgs, { ...runContext, ...childContext });
|
|
1829
|
-
}, {}, () => runContext);
|
|
1830
|
-
|
|
1831
|
-
const mergedContext = {
|
|
1832
|
-
...defaults,
|
|
1833
|
-
...context,
|
|
1834
|
-
cache: defaults.cache ?? context.cache
|
|
1835
|
-
};
|
|
1836
|
-
|
|
1837
|
-
runContext = {
|
|
1838
|
-
...mergedContext,
|
|
1839
|
-
id,
|
|
1840
|
-
args,
|
|
1841
|
-
input: mergedContext.input,
|
|
1842
|
-
signals: createSignalReader(mergedContext.signals),
|
|
1843
|
-
abort: mergedContext.abort,
|
|
1844
|
-
cache: mergedContext.cache,
|
|
1845
|
-
server
|
|
1846
|
-
};
|
|
1847
|
-
|
|
1848
|
-
return fn.call(runContext, ...args);
|
|
1849
|
-
},
|
|
1850
|
-
|
|
1851
|
-
_setContext(context = {}) {
|
|
1852
|
-
Object.assign(defaults, context);
|
|
1853
|
-
return registry;
|
|
1854
|
-
},
|
|
1855
|
-
|
|
1856
|
-
_adoptMany() {
|
|
1857
|
-
return registry;
|
|
1858
|
-
}
|
|
1859
|
-
}, registryStore, type);
|
|
1860
|
-
|
|
1861
|
-
registry.registerMany(initialMap);
|
|
1862
|
-
return createServerNamespace((id, args, context) => registry.run(id, args, context), registry, () => defaults);
|
|
1863
|
-
}
|
|
1864
|
-
|
|
1865
1877
|
function createServerProxy({
|
|
1866
1878
|
endpoint = "/__async/server",
|
|
1867
1879
|
fetch: fetchImpl = globalThis.fetch?.bind(globalThis),
|
|
@@ -1869,13 +1881,14 @@ const __serverModule = (() => {
|
|
|
1869
1881
|
loader,
|
|
1870
1882
|
router,
|
|
1871
1883
|
cache,
|
|
1884
|
+
scheduler,
|
|
1872
1885
|
headers = {}
|
|
1873
1886
|
} = {}) {
|
|
1874
1887
|
if (typeof fetchImpl !== "function") {
|
|
1875
1888
|
throw new TypeError("createServerProxy(...) requires fetch to be available.");
|
|
1876
1889
|
}
|
|
1877
1890
|
|
|
1878
|
-
const defaults = { signals, loader, router, cache };
|
|
1891
|
+
const defaults = { signals, loader, router, cache, scheduler };
|
|
1879
1892
|
|
|
1880
1893
|
async function run(id, args = [], context = {}) {
|
|
1881
1894
|
assertServerId(id);
|
|
@@ -2214,7 +2227,7 @@ const __serverModule = (() => {
|
|
|
2214
2227
|
throw new TypeError("Server function id must be a non-empty string.");
|
|
2215
2228
|
}
|
|
2216
2229
|
}
|
|
2217
|
-
return {
|
|
2230
|
+
return { createServerProxy, resolveServerCommandArguments, applyServerResult, unwrapServerResult, defaultInput, createServerNamespace, createSignalReader, assertServerId };
|
|
2218
2231
|
})();
|
|
2219
2232
|
|
|
2220
2233
|
const __handlersModule = (() => {
|
|
@@ -2417,18 +2430,325 @@ const __handlersModule = (() => {
|
|
|
2417
2430
|
return { createHandlerRegistry, parseHandlerRef, isHandlerToken };
|
|
2418
2431
|
})();
|
|
2419
2432
|
|
|
2433
|
+
const __schedulerModule = (() => {
|
|
2434
|
+
const defaultPhases = ["binding", "lifecycle", "effect", "async", "post"];
|
|
2435
|
+
|
|
2436
|
+
function createScheduler(options = {}) {
|
|
2437
|
+
const phases = [...(options.phases ?? defaultPhases)];
|
|
2438
|
+
const queues = new Map(phases.map((phase) => [phase, []]));
|
|
2439
|
+
const keyedJobs = new Map();
|
|
2440
|
+
const destroyedScopes = new Set();
|
|
2441
|
+
const objectScopeIds = new WeakMap();
|
|
2442
|
+
const onError = typeof options.onError === "function" ? options.onError : undefined;
|
|
2443
|
+
const maxDepth = options.maxDepth ?? 100;
|
|
2444
|
+
const strategy = options.strategy ?? "microtask";
|
|
2445
|
+
let destroyed = false;
|
|
2446
|
+
let flushing = false;
|
|
2447
|
+
let scheduled = false;
|
|
2448
|
+
let batchDepth = 0;
|
|
2449
|
+
let jobCounter = 0;
|
|
2450
|
+
let scopeCounter = 0;
|
|
2451
|
+
|
|
2452
|
+
const api = {
|
|
2453
|
+
strategy,
|
|
2454
|
+
phases,
|
|
2455
|
+
|
|
2456
|
+
batch(fn) {
|
|
2457
|
+
if (typeof fn !== "function") {
|
|
2458
|
+
throw new TypeError("scheduler.batch(fn) requires a function.");
|
|
2459
|
+
}
|
|
2460
|
+
assertActive();
|
|
2461
|
+
batchDepth += 1;
|
|
2462
|
+
let asyncBatch = false;
|
|
2463
|
+
try {
|
|
2464
|
+
const value = fn();
|
|
2465
|
+
if (value && typeof value.then === "function") {
|
|
2466
|
+
asyncBatch = true;
|
|
2467
|
+
return value.finally(() => {
|
|
2468
|
+
batchDepth -= 1;
|
|
2469
|
+
requestFlush();
|
|
2470
|
+
});
|
|
2471
|
+
}
|
|
2472
|
+
return value;
|
|
2473
|
+
} finally {
|
|
2474
|
+
if (!asyncBatch && batchDepth > 0) {
|
|
2475
|
+
batchDepth -= 1;
|
|
2476
|
+
requestFlush();
|
|
2477
|
+
}
|
|
2478
|
+
}
|
|
2479
|
+
},
|
|
2480
|
+
|
|
2481
|
+
enqueue(phase, fn, options = {}) {
|
|
2482
|
+
assertActive();
|
|
2483
|
+
assertPhase(phase);
|
|
2484
|
+
if (typeof fn !== "function") {
|
|
2485
|
+
throw new TypeError("scheduler.enqueue(phase, fn) requires a function.");
|
|
2486
|
+
}
|
|
2487
|
+
const scope = options.scope;
|
|
2488
|
+
if (scope !== undefined && destroyedScopes.has(scope)) {
|
|
2489
|
+
return noop;
|
|
2490
|
+
}
|
|
2491
|
+
|
|
2492
|
+
const dedupeKey = options.key === undefined ? undefined : `${phase}:${scopeKey(scope)}:${String(options.key)}`;
|
|
2493
|
+
if (dedupeKey && keyedJobs.has(dedupeKey)) {
|
|
2494
|
+
return keyedJobs.get(dedupeKey).cancel;
|
|
2495
|
+
}
|
|
2496
|
+
|
|
2497
|
+
const job = {
|
|
2498
|
+
id: ++jobCounter,
|
|
2499
|
+
phase,
|
|
2500
|
+
fn,
|
|
2501
|
+
scope,
|
|
2502
|
+
boundary: options.boundary,
|
|
2503
|
+
key: dedupeKey,
|
|
2504
|
+
canceled: false,
|
|
2505
|
+
cancel() {
|
|
2506
|
+
job.canceled = true;
|
|
2507
|
+
if (job.key) {
|
|
2508
|
+
keyedJobs.delete(job.key);
|
|
2509
|
+
}
|
|
2510
|
+
}
|
|
2511
|
+
};
|
|
2512
|
+
queues.get(phase).push(job);
|
|
2513
|
+
if (job.key) {
|
|
2514
|
+
keyedJobs.set(job.key, job);
|
|
2515
|
+
}
|
|
2516
|
+
requestFlush();
|
|
2517
|
+
return job.cancel;
|
|
2518
|
+
},
|
|
2519
|
+
|
|
2520
|
+
afterFlush(fn, options = {}) {
|
|
2521
|
+
return api.enqueue("post", fn, options);
|
|
2522
|
+
},
|
|
2523
|
+
|
|
2524
|
+
async flush() {
|
|
2525
|
+
assertActive();
|
|
2526
|
+
if (flushing) {
|
|
2527
|
+
return;
|
|
2528
|
+
}
|
|
2529
|
+
scheduled = false;
|
|
2530
|
+
flushing = true;
|
|
2531
|
+
let depth = 0;
|
|
2532
|
+
try {
|
|
2533
|
+
while (hasJobs()) {
|
|
2534
|
+
depth += 1;
|
|
2535
|
+
if (depth > maxDepth) {
|
|
2536
|
+
throw new Error(`Scheduler exceeded maxDepth ${maxDepth}.`);
|
|
2537
|
+
}
|
|
2538
|
+
for (const phase of phases) {
|
|
2539
|
+
await flushPhase(phase);
|
|
2540
|
+
}
|
|
2541
|
+
}
|
|
2542
|
+
} finally {
|
|
2543
|
+
flushing = false;
|
|
2544
|
+
if (hasJobs()) {
|
|
2545
|
+
requestFlush();
|
|
2546
|
+
}
|
|
2547
|
+
}
|
|
2548
|
+
},
|
|
2549
|
+
|
|
2550
|
+
async flushScope(scope) {
|
|
2551
|
+
assertActive();
|
|
2552
|
+
if (flushing) {
|
|
2553
|
+
return;
|
|
2554
|
+
}
|
|
2555
|
+
scheduled = false;
|
|
2556
|
+
flushing = true;
|
|
2557
|
+
let depth = 0;
|
|
2558
|
+
try {
|
|
2559
|
+
while (hasJobsForScope(scope)) {
|
|
2560
|
+
depth += 1;
|
|
2561
|
+
if (depth > maxDepth) {
|
|
2562
|
+
throw new Error(`Scheduler exceeded maxDepth ${maxDepth}.`);
|
|
2563
|
+
}
|
|
2564
|
+
for (const phase of phases) {
|
|
2565
|
+
await flushPhase(phase, scope);
|
|
2566
|
+
}
|
|
2567
|
+
}
|
|
2568
|
+
} finally {
|
|
2569
|
+
flushing = false;
|
|
2570
|
+
if (hasJobs()) {
|
|
2571
|
+
requestFlush();
|
|
2572
|
+
}
|
|
2573
|
+
}
|
|
2574
|
+
},
|
|
2575
|
+
|
|
2576
|
+
cancelScope(scope) {
|
|
2577
|
+
if (scope === undefined) {
|
|
2578
|
+
return api;
|
|
2579
|
+
}
|
|
2580
|
+
for (const queue of queues.values()) {
|
|
2581
|
+
for (const job of queue) {
|
|
2582
|
+
if (job.scope === scope) {
|
|
2583
|
+
job.cancel();
|
|
2584
|
+
}
|
|
2585
|
+
}
|
|
2586
|
+
}
|
|
2587
|
+
return api;
|
|
2588
|
+
},
|
|
2589
|
+
|
|
2590
|
+
markScopeDestroyed(scope) {
|
|
2591
|
+
if (scope !== undefined) {
|
|
2592
|
+
destroyedScopes.add(scope);
|
|
2593
|
+
api.cancelScope(scope);
|
|
2594
|
+
}
|
|
2595
|
+
return api;
|
|
2596
|
+
},
|
|
2597
|
+
|
|
2598
|
+
isScopeDestroyed(scope) {
|
|
2599
|
+
return scope !== undefined && destroyedScopes.has(scope);
|
|
2600
|
+
},
|
|
2601
|
+
|
|
2602
|
+
inspect() {
|
|
2603
|
+
const counts = {};
|
|
2604
|
+
for (const [phase, queue] of queues) {
|
|
2605
|
+
counts[phase] = queue.filter((job) => !job.canceled).length;
|
|
2606
|
+
}
|
|
2607
|
+
return {
|
|
2608
|
+
strategy,
|
|
2609
|
+
phases: [...phases],
|
|
2610
|
+
pending: counts,
|
|
2611
|
+
scopesDestroyed: destroyedScopes.size,
|
|
2612
|
+
flushing,
|
|
2613
|
+
scheduled
|
|
2614
|
+
};
|
|
2615
|
+
},
|
|
2616
|
+
|
|
2617
|
+
destroy() {
|
|
2618
|
+
destroyed = true;
|
|
2619
|
+
for (const queue of queues.values()) {
|
|
2620
|
+
for (const job of queue) {
|
|
2621
|
+
job.cancel();
|
|
2622
|
+
}
|
|
2623
|
+
queue.length = 0;
|
|
2624
|
+
}
|
|
2625
|
+
keyedJobs.clear();
|
|
2626
|
+
destroyedScopes.clear();
|
|
2627
|
+
}
|
|
2628
|
+
};
|
|
2629
|
+
|
|
2630
|
+
return api;
|
|
2631
|
+
|
|
2632
|
+
function requestFlush() {
|
|
2633
|
+
if (strategy === "manual" || destroyed || flushing || batchDepth > 0 || scheduled) {
|
|
2634
|
+
return;
|
|
2635
|
+
}
|
|
2636
|
+
scheduled = true;
|
|
2637
|
+
scheduleMicrotask(() => {
|
|
2638
|
+
if (!destroyed) {
|
|
2639
|
+
void api.flush();
|
|
2640
|
+
}
|
|
2641
|
+
});
|
|
2642
|
+
}
|
|
2643
|
+
|
|
2644
|
+
async function flushPhase(phase, scope) {
|
|
2645
|
+
const queue = queues.get(phase);
|
|
2646
|
+
const remaining = [];
|
|
2647
|
+
const runnable = [];
|
|
2648
|
+
|
|
2649
|
+
for (const job of queue.splice(0)) {
|
|
2650
|
+
if (job.canceled) {
|
|
2651
|
+
continue;
|
|
2652
|
+
}
|
|
2653
|
+
if (scope !== undefined && job.scope !== scope) {
|
|
2654
|
+
remaining.push(job);
|
|
2655
|
+
continue;
|
|
2656
|
+
}
|
|
2657
|
+
runnable.push(job);
|
|
2658
|
+
}
|
|
2659
|
+
|
|
2660
|
+
queue.push(...remaining);
|
|
2661
|
+
|
|
2662
|
+
for (const job of runnable) {
|
|
2663
|
+
if (job.key) {
|
|
2664
|
+
keyedJobs.delete(job.key);
|
|
2665
|
+
}
|
|
2666
|
+
if (job.canceled || (job.scope !== undefined && destroyedScopes.has(job.scope))) {
|
|
2667
|
+
continue;
|
|
2668
|
+
}
|
|
2669
|
+
try {
|
|
2670
|
+
await job.fn();
|
|
2671
|
+
} catch (error) {
|
|
2672
|
+
if (onError) {
|
|
2673
|
+
onError(error, job);
|
|
2674
|
+
} else {
|
|
2675
|
+
throw error;
|
|
2676
|
+
}
|
|
2677
|
+
}
|
|
2678
|
+
}
|
|
2679
|
+
}
|
|
2680
|
+
|
|
2681
|
+
function hasJobs() {
|
|
2682
|
+
for (const queue of queues.values()) {
|
|
2683
|
+
if (queue.some((job) => !job.canceled)) {
|
|
2684
|
+
return true;
|
|
2685
|
+
}
|
|
2686
|
+
}
|
|
2687
|
+
return false;
|
|
2688
|
+
}
|
|
2689
|
+
|
|
2690
|
+
function hasJobsForScope(scope) {
|
|
2691
|
+
for (const queue of queues.values()) {
|
|
2692
|
+
if (queue.some((job) => !job.canceled && job.scope === scope)) {
|
|
2693
|
+
return true;
|
|
2694
|
+
}
|
|
2695
|
+
}
|
|
2696
|
+
return false;
|
|
2697
|
+
}
|
|
2698
|
+
|
|
2699
|
+
function assertActive() {
|
|
2700
|
+
if (destroyed) {
|
|
2701
|
+
throw new Error("Scheduler has been destroyed.");
|
|
2702
|
+
}
|
|
2703
|
+
}
|
|
2704
|
+
|
|
2705
|
+
function assertPhase(phase) {
|
|
2706
|
+
if (!queues.has(phase)) {
|
|
2707
|
+
throw new Error(`Unknown scheduler phase "${phase}".`);
|
|
2708
|
+
}
|
|
2709
|
+
}
|
|
2710
|
+
|
|
2711
|
+
function scopeKey(scope) {
|
|
2712
|
+
if (scope === undefined) {
|
|
2713
|
+
return "global";
|
|
2714
|
+
}
|
|
2715
|
+
if ((typeof scope === "object" && scope !== null) || typeof scope === "function") {
|
|
2716
|
+
if (!objectScopeIds.has(scope)) {
|
|
2717
|
+
objectScopeIds.set(scope, `scope:${++scopeCounter}`);
|
|
2718
|
+
}
|
|
2719
|
+
return objectScopeIds.get(scope);
|
|
2720
|
+
}
|
|
2721
|
+
return String(scope);
|
|
2722
|
+
}
|
|
2723
|
+
}
|
|
2724
|
+
|
|
2725
|
+
function scheduleMicrotask(fn) {
|
|
2726
|
+
if (typeof queueMicrotask === "function") {
|
|
2727
|
+
queueMicrotask(fn);
|
|
2728
|
+
return;
|
|
2729
|
+
}
|
|
2730
|
+
Promise.resolve().then(fn);
|
|
2731
|
+
}
|
|
2732
|
+
|
|
2733
|
+
function noop() {}
|
|
2734
|
+
return { createScheduler };
|
|
2735
|
+
})();
|
|
2736
|
+
|
|
2420
2737
|
const __loaderModule = (() => {
|
|
2421
2738
|
const { renderComponent } = __componentModule;
|
|
2422
2739
|
const { createHandlerRegistry } = __handlersModule;
|
|
2740
|
+
const { createScheduler } = __schedulerModule;
|
|
2423
2741
|
const { createSignalRegistry, isSignalRef } = __signalsModule;
|
|
2424
2742
|
const { matchAttribute, normalizeAttributeConfig, readAttribute } = __attributesModule;
|
|
2425
2743
|
const inlineBindingPrefix = "__async:inline:";
|
|
2426
2744
|
|
|
2427
|
-
function Loader({ root, signals, handlers, server, router, cache, attributes } = {}) {
|
|
2745
|
+
function Loader({ root, signals, handlers, server, router, cache, attributes, scheduler } = {}) {
|
|
2428
2746
|
const documentRef = root?.ownerDocument ?? root ?? globalThis.document;
|
|
2429
2747
|
const rootNode = root ?? documentRef;
|
|
2430
2748
|
const signalRegistry = signals ?? createSignalRegistry();
|
|
2431
2749
|
const handlerRegistry = handlers ?? createHandlerRegistry();
|
|
2750
|
+
const schedulerInstance = scheduler ?? createScheduler();
|
|
2751
|
+
const ownsScheduler = !scheduler;
|
|
2432
2752
|
const attributeConfig = normalizeAttributeConfig(attributes);
|
|
2433
2753
|
const cleanups = new Set();
|
|
2434
2754
|
const eventBindings = new WeakMap();
|
|
@@ -2449,6 +2769,7 @@ const __loaderModule = (() => {
|
|
|
2449
2769
|
server,
|
|
2450
2770
|
router,
|
|
2451
2771
|
cache,
|
|
2772
|
+
scheduler: schedulerInstance,
|
|
2452
2773
|
attributes: attributeConfig,
|
|
2453
2774
|
|
|
2454
2775
|
start() {
|
|
@@ -2488,6 +2809,7 @@ const __loaderModule = (() => {
|
|
|
2488
2809
|
server: api.server,
|
|
2489
2810
|
router: api.router,
|
|
2490
2811
|
cache: api.cache,
|
|
2812
|
+
scheduler: schedulerInstance,
|
|
2491
2813
|
attributes: attributeConfig
|
|
2492
2814
|
});
|
|
2493
2815
|
cleanupChildren(target);
|
|
@@ -2508,6 +2830,9 @@ const __loaderModule = (() => {
|
|
|
2508
2830
|
runCleanup(cleanup);
|
|
2509
2831
|
}
|
|
2510
2832
|
cleanups.clear();
|
|
2833
|
+
if (ownsScheduler) {
|
|
2834
|
+
schedulerInstance.destroy();
|
|
2835
|
+
}
|
|
2511
2836
|
},
|
|
2512
2837
|
|
|
2513
2838
|
_observeVisible(target, fn) {
|
|
@@ -2525,13 +2850,14 @@ const __loaderModule = (() => {
|
|
|
2525
2850
|
}
|
|
2526
2851
|
};
|
|
2527
2852
|
|
|
2528
|
-
signalRegistry._setContext?.({ server: api.server, router: api.router, loader: api, cache: api.cache });
|
|
2853
|
+
signalRegistry._setContext?.({ server: api.server, router: api.router, loader: api, cache: api.cache, scheduler: schedulerInstance });
|
|
2529
2854
|
api.server?._setContext?.({
|
|
2530
2855
|
signals: signalRegistry,
|
|
2531
2856
|
handlers: handlerRegistry,
|
|
2532
2857
|
loader: api,
|
|
2533
2858
|
router: api.router,
|
|
2534
|
-
cache: api.cache
|
|
2859
|
+
cache: api.cache,
|
|
2860
|
+
scheduler: schedulerInstance
|
|
2535
2861
|
});
|
|
2536
2862
|
|
|
2537
2863
|
function bindEventAttributes(scope) {
|
|
@@ -2563,18 +2889,19 @@ const __loaderModule = (() => {
|
|
|
2563
2889
|
|
|
2564
2890
|
const listener = async (event) => {
|
|
2565
2891
|
try {
|
|
2566
|
-
await handlerRegistry.run(ref, {
|
|
2892
|
+
await schedulerInstance.batch(() => handlerRegistry.run(ref, {
|
|
2567
2893
|
signals: signalRegistry,
|
|
2568
2894
|
handlers: handlerRegistry,
|
|
2569
2895
|
loader: api,
|
|
2570
2896
|
server: api.server,
|
|
2571
2897
|
router: api.router,
|
|
2572
2898
|
cache: api.cache,
|
|
2899
|
+
scheduler: schedulerInstance,
|
|
2573
2900
|
event,
|
|
2574
2901
|
element,
|
|
2575
2902
|
el: element,
|
|
2576
2903
|
root: rootNode
|
|
2577
|
-
});
|
|
2904
|
+
}));
|
|
2578
2905
|
} catch (error) {
|
|
2579
2906
|
dispatchAsyncError(element, error);
|
|
2580
2907
|
}
|
|
@@ -2690,7 +3017,12 @@ const __loaderModule = (() => {
|
|
|
2690
3017
|
|
|
2691
3018
|
const read = () => readBinding(path, options);
|
|
2692
3019
|
apply(read());
|
|
2693
|
-
addCleanup(subscribeBinding(path, () =>
|
|
3020
|
+
addCleanup(subscribeBinding(path, () => {
|
|
3021
|
+
schedulerInstance.enqueue("binding", () => apply(read()), {
|
|
3022
|
+
scope: element,
|
|
3023
|
+
key
|
|
3024
|
+
});
|
|
3025
|
+
}), element);
|
|
2694
3026
|
}
|
|
2695
3027
|
|
|
2696
3028
|
function bindValueWriter(element, path) {
|
|
@@ -2751,7 +3083,12 @@ const __loaderModule = (() => {
|
|
|
2751
3083
|
const state = {
|
|
2752
3084
|
id,
|
|
2753
3085
|
templates,
|
|
2754
|
-
cleanup: signalRegistry.subscribe(`${id}.$status`, () =>
|
|
3086
|
+
cleanup: signalRegistry.subscribe(`${id}.$status`, () => {
|
|
3087
|
+
schedulerInstance.enqueue("binding", () => renderBoundary(boundary), {
|
|
3088
|
+
scope: boundary,
|
|
3089
|
+
key: `boundary:${id}`
|
|
3090
|
+
});
|
|
3091
|
+
})
|
|
2755
3092
|
};
|
|
2756
3093
|
boundaryState.set(boundary, state);
|
|
2757
3094
|
addCleanup(state.cleanup, boundary);
|
|
@@ -2791,7 +3128,7 @@ const __loaderModule = (() => {
|
|
|
2791
3128
|
}
|
|
2792
3129
|
mountedElements.add(element);
|
|
2793
3130
|
for (const ref of refs) {
|
|
2794
|
-
runPseudo(element, ref);
|
|
3131
|
+
scheduleLifecycle(element, () => runPseudo(element, ref), `attach:${ref}`);
|
|
2795
3132
|
}
|
|
2796
3133
|
}
|
|
2797
3134
|
|
|
@@ -2804,7 +3141,7 @@ const __loaderModule = (() => {
|
|
|
2804
3141
|
continue;
|
|
2805
3142
|
}
|
|
2806
3143
|
visibleElements.add(element);
|
|
2807
|
-
addCleanup(observeVisible(element, () => runPseudo(element, ref)), element);
|
|
3144
|
+
addCleanup(observeVisible(element, () => scheduleLifecycle(element, () => runPseudo(element, ref), `visible:${ref}`)), element);
|
|
2808
3145
|
}
|
|
2809
3146
|
}
|
|
2810
3147
|
|
|
@@ -2828,6 +3165,7 @@ const __loaderModule = (() => {
|
|
|
2828
3165
|
server: api.server,
|
|
2829
3166
|
router: api.router,
|
|
2830
3167
|
cache: api.cache,
|
|
3168
|
+
scheduler: schedulerInstance,
|
|
2831
3169
|
element,
|
|
2832
3170
|
el: element,
|
|
2833
3171
|
root: rootNode
|
|
@@ -2846,10 +3184,13 @@ const __loaderModule = (() => {
|
|
|
2846
3184
|
const ownerWindow = target.ownerDocument?.defaultView ?? globalThis;
|
|
2847
3185
|
const Observer = ownerWindow.IntersectionObserver ?? globalThis.IntersectionObserver;
|
|
2848
3186
|
if (!Observer) {
|
|
2849
|
-
|
|
3187
|
+
schedulerInstance.enqueue("lifecycle", () => {
|
|
2850
3188
|
if (!destroyed) {
|
|
2851
3189
|
fn(target);
|
|
2852
3190
|
}
|
|
3191
|
+
}, {
|
|
3192
|
+
scope: target,
|
|
3193
|
+
key: "visible:fallback"
|
|
2853
3194
|
});
|
|
2854
3195
|
return () => {};
|
|
2855
3196
|
}
|
|
@@ -2904,6 +3245,7 @@ const __loaderModule = (() => {
|
|
|
2904
3245
|
}
|
|
2905
3246
|
for (const element of elementsIn(node)) {
|
|
2906
3247
|
runScopedCleanups(element);
|
|
3248
|
+
schedulerInstance.markScopeDestroyed(element);
|
|
2907
3249
|
}
|
|
2908
3250
|
}
|
|
2909
3251
|
|
|
@@ -2927,6 +3269,13 @@ const __loaderModule = (() => {
|
|
|
2927
3269
|
}
|
|
2928
3270
|
}
|
|
2929
3271
|
|
|
3272
|
+
function scheduleLifecycle(element, fn, key) {
|
|
3273
|
+
schedulerInstance.enqueue("lifecycle", fn, {
|
|
3274
|
+
scope: element,
|
|
3275
|
+
key
|
|
3276
|
+
});
|
|
3277
|
+
}
|
|
3278
|
+
|
|
2930
3279
|
return api;
|
|
2931
3280
|
}
|
|
2932
3281
|
|
|
@@ -3257,6 +3606,7 @@ const __partialsModule = (() => {
|
|
|
3257
3606
|
const __routerModule = (() => {
|
|
3258
3607
|
const { Loader } = __loaderModule;
|
|
3259
3608
|
const { createHandlerRegistry } = __handlersModule;
|
|
3609
|
+
const { createScheduler } = __schedulerModule;
|
|
3260
3610
|
const { createSignalRegistry } = __signalsModule;
|
|
3261
3611
|
const { applyServerResult } = __serverModule;
|
|
3262
3612
|
const { createRegistryStore } = __registryStoreModule;
|
|
@@ -3377,12 +3727,15 @@ const __routerModule = (() => {
|
|
|
3377
3727
|
partials,
|
|
3378
3728
|
fetch: fetchImpl = globalThis.fetch?.bind(globalThis),
|
|
3379
3729
|
routeEndpoint = "/__async/route",
|
|
3380
|
-
attributes
|
|
3730
|
+
attributes,
|
|
3731
|
+
scheduler
|
|
3381
3732
|
} = {}) {
|
|
3382
3733
|
const documentRef = root?.ownerDocument ?? root ?? globalThis.document;
|
|
3383
3734
|
const rootNode = root ?? documentRef;
|
|
3384
3735
|
const signalRegistry = signals ?? loader?.signals ?? createSignalRegistry();
|
|
3385
3736
|
const handlerRegistry = handlers ?? loader?.handlers ?? createHandlerRegistry();
|
|
3737
|
+
const schedulerInstance = scheduler ?? loader?.scheduler ?? createScheduler();
|
|
3738
|
+
const ownsScheduler = !scheduler && !loader?.scheduler;
|
|
3386
3739
|
const attributeConfig = normalizeAttributeConfig(attributes ?? loader?.attributes);
|
|
3387
3740
|
const loaderInstance =
|
|
3388
3741
|
loader ??
|
|
@@ -3392,6 +3745,7 @@ const __routerModule = (() => {
|
|
|
3392
3745
|
handlers: handlerRegistry,
|
|
3393
3746
|
server,
|
|
3394
3747
|
cache,
|
|
3748
|
+
scheduler: schedulerInstance,
|
|
3395
3749
|
attributes: attributeConfig
|
|
3396
3750
|
});
|
|
3397
3751
|
const ownsLoader = !loader;
|
|
@@ -3411,12 +3765,13 @@ const __routerModule = (() => {
|
|
|
3411
3765
|
server,
|
|
3412
3766
|
cache,
|
|
3413
3767
|
partials,
|
|
3768
|
+
scheduler: schedulerInstance,
|
|
3414
3769
|
attributes: attributeConfig,
|
|
3415
3770
|
|
|
3416
3771
|
start() {
|
|
3417
3772
|
assertActive();
|
|
3418
3773
|
loaderInstance.router = api;
|
|
3419
|
-
signalRegistry._setContext?.({ router: api, loader: loaderInstance, server, cache });
|
|
3774
|
+
signalRegistry._setContext?.({ router: api, loader: loaderInstance, server, cache, scheduler: schedulerInstance });
|
|
3420
3775
|
if (ownsLoader) {
|
|
3421
3776
|
loaderInstance.start();
|
|
3422
3777
|
}
|
|
@@ -3480,6 +3835,9 @@ const __routerModule = (() => {
|
|
|
3480
3835
|
cleanup();
|
|
3481
3836
|
}
|
|
3482
3837
|
cleanups.clear();
|
|
3838
|
+
if (ownsScheduler) {
|
|
3839
|
+
schedulerInstance.destroy();
|
|
3840
|
+
}
|
|
3483
3841
|
}
|
|
3484
3842
|
};
|
|
3485
3843
|
|
|
@@ -3585,13 +3943,16 @@ const __routerModule = (() => {
|
|
|
3585
3943
|
loader: loaderInstance,
|
|
3586
3944
|
router: api,
|
|
3587
3945
|
cache,
|
|
3946
|
+
scheduler: schedulerInstance,
|
|
3588
3947
|
abort: navigation?.abort
|
|
3589
3948
|
});
|
|
3949
|
+
await schedulerInstance.flush();
|
|
3590
3950
|
if (!isActiveNavigation(navigation)) {
|
|
3591
3951
|
return;
|
|
3592
3952
|
}
|
|
3593
3953
|
if (result?.html != null && !result.boundary && !result.redirect) {
|
|
3594
3954
|
loaderInstance.swap(boundary, result.html);
|
|
3955
|
+
await schedulerInstance.flush();
|
|
3595
3956
|
}
|
|
3596
3957
|
if (result?.redirect || options.history === false) {
|
|
3597
3958
|
return;
|
|
@@ -3636,6 +3997,7 @@ const __routerModule = (() => {
|
|
|
3636
3997
|
loader: loaderInstance,
|
|
3637
3998
|
server,
|
|
3638
3999
|
cache,
|
|
4000
|
+
scheduler: schedulerInstance,
|
|
3639
4001
|
abort: navigation?.abort
|
|
3640
4002
|
};
|
|
3641
4003
|
}
|
|
@@ -3822,15 +4184,17 @@ const __appModule = (() => {
|
|
|
3822
4184
|
const { Loader } = __loaderModule;
|
|
3823
4185
|
const { createPartialRegistry } = __partialsModule;
|
|
3824
4186
|
const { createRouteRegistry, createRouter } = __routerModule;
|
|
3825
|
-
const {
|
|
4187
|
+
const { createScheduler } = __schedulerModule;
|
|
4188
|
+
const { createServerNamespace } = __serverModule;
|
|
3826
4189
|
const { createSignal, createSignalRegistry } = __signalsModule;
|
|
3827
4190
|
const { createRegistryStore } = __registryStoreModule;
|
|
3828
4191
|
const { attributeName, normalizeAttributeConfig } = __attributesModule;
|
|
3829
4192
|
const registryTypes = new Set(["signal", "handler", "server", "partial", "route", "component"]);
|
|
3830
4193
|
|
|
3831
|
-
function defineApp(initial) {
|
|
4194
|
+
function defineApp(initial, options = {}) {
|
|
3832
4195
|
const registry = createRegistryStore(undefined, { target: "browser" });
|
|
3833
4196
|
const runtimes = new Set();
|
|
4197
|
+
const createRuntime = options.createRuntime ?? createApp;
|
|
3834
4198
|
|
|
3835
4199
|
const app = {
|
|
3836
4200
|
registry,
|
|
@@ -3849,7 +4213,7 @@ const __appModule = (() => {
|
|
|
3849
4213
|
},
|
|
3850
4214
|
|
|
3851
4215
|
start(options = {}) {
|
|
3852
|
-
const runtime =
|
|
4216
|
+
const runtime = createRuntime(app, options).start();
|
|
3853
4217
|
app.runtime = runtime;
|
|
3854
4218
|
return runtime;
|
|
3855
4219
|
},
|
|
@@ -3874,13 +4238,18 @@ const __appModule = (() => {
|
|
|
3874
4238
|
function createApp(appOrDefinition = Async, options = {}) {
|
|
3875
4239
|
const app = isAppHub(appOrDefinition) ? appOrDefinition : defineApp(appOrDefinition ?? {});
|
|
3876
4240
|
const target = options.target ?? "browser";
|
|
4241
|
+
const scheduler = options.scheduler ?? options.loader?.scheduler ?? createScheduler({
|
|
4242
|
+
strategy: target === "server" ? "manual" : "microtask"
|
|
4243
|
+
});
|
|
4244
|
+
const ownsScheduler = !options.scheduler && !options.loader?.scheduler;
|
|
3877
4245
|
const attributes = normalizeAttributeConfig(options.attributes);
|
|
3878
4246
|
const registry = options.registry ?? app.registry.view({ target });
|
|
3879
4247
|
const signals = options.signals ?? createSignalRegistry(undefined, { registry, type: "signal" });
|
|
3880
4248
|
const handlers = options.handlers ?? createHandlerRegistry(undefined, { registry, type: "handler" });
|
|
3881
4249
|
const serverCache = createCacheRegistry(undefined, { registry, type: "cache.server" });
|
|
3882
4250
|
const browserCache = createCacheRegistry(undefined, { registry, type: "cache.browser" });
|
|
3883
|
-
const
|
|
4251
|
+
const serverFactory = options.serverFactory ?? createServerReferenceRegistry;
|
|
4252
|
+
const server = options.server ?? serverFactory(undefined, { registry, type: "server" });
|
|
3884
4253
|
const partials = options.partials ?? createPartialRegistry(undefined, { registry, type: "partial" });
|
|
3885
4254
|
const routes = options.routes ?? createRouteRegistry(undefined, { registry, type: "route" });
|
|
3886
4255
|
const components = options.components ?? createComponentRegistry(undefined, { registry, type: "component" });
|
|
@@ -3908,6 +4277,7 @@ const __appModule = (() => {
|
|
|
3908
4277
|
},
|
|
3909
4278
|
loader,
|
|
3910
4279
|
router,
|
|
4280
|
+
scheduler,
|
|
3911
4281
|
attributes,
|
|
3912
4282
|
|
|
3913
4283
|
start() {
|
|
@@ -3924,12 +4294,13 @@ const __appModule = (() => {
|
|
|
3924
4294
|
handlers,
|
|
3925
4295
|
server,
|
|
3926
4296
|
cache: browserCache,
|
|
4297
|
+
scheduler,
|
|
3927
4298
|
attributes
|
|
3928
4299
|
});
|
|
3929
4300
|
runtime.loader = loader;
|
|
3930
4301
|
|
|
3931
4302
|
configureServerContext({ cache: browserCache });
|
|
3932
|
-
signals._setContext?.({ server, loader, cache: browserCache });
|
|
4303
|
+
signals._setContext?.({ server, loader, cache: browserCache, scheduler });
|
|
3933
4304
|
|
|
3934
4305
|
loader.start();
|
|
3935
4306
|
|
|
@@ -3945,6 +4316,7 @@ const __appModule = (() => {
|
|
|
3945
4316
|
server,
|
|
3946
4317
|
cache: browserCache,
|
|
3947
4318
|
partials,
|
|
4319
|
+
scheduler,
|
|
3948
4320
|
fetch: options.fetch,
|
|
3949
4321
|
routeEndpoint: options.routeEndpoint,
|
|
3950
4322
|
attributes
|
|
@@ -3956,7 +4328,7 @@ const __appModule = (() => {
|
|
|
3956
4328
|
}
|
|
3957
4329
|
} else {
|
|
3958
4330
|
configureServerContext({ cache: serverCache });
|
|
3959
|
-
signals._setContext?.({ server, cache: serverCache });
|
|
4331
|
+
signals._setContext?.({ server, cache: serverCache, scheduler });
|
|
3960
4332
|
}
|
|
3961
4333
|
|
|
3962
4334
|
return runtime;
|
|
@@ -3970,9 +4342,10 @@ const __appModule = (() => {
|
|
|
3970
4342
|
async render(url) {
|
|
3971
4343
|
assertActive();
|
|
3972
4344
|
configureServerContext({ cache: serverCache });
|
|
3973
|
-
signals._setContext?.({ server, cache: serverCache });
|
|
4345
|
+
signals._setContext?.({ server, cache: serverCache, scheduler });
|
|
3974
4346
|
const matched = routes.match(url);
|
|
3975
4347
|
if (!matched) {
|
|
4348
|
+
await scheduler.flush();
|
|
3976
4349
|
return {
|
|
3977
4350
|
html: renderDocument("", { status: 404, signals, browserCache, boundary: options.boundary ?? "route", attributes }),
|
|
3978
4351
|
status: 404,
|
|
@@ -3992,8 +4365,8 @@ const __appModule = (() => {
|
|
|
3992
4365
|
cache: serverCache,
|
|
3993
4366
|
browserCache,
|
|
3994
4367
|
partials,
|
|
3995
|
-
|
|
3996
|
-
|
|
4368
|
+
scheduler,
|
|
4369
|
+
...currentRequestContext()
|
|
3997
4370
|
})
|
|
3998
4371
|
: { html: "" };
|
|
3999
4372
|
|
|
@@ -4006,6 +4379,8 @@ const __appModule = (() => {
|
|
|
4006
4379
|
browserCache.restore(result.cache.browser);
|
|
4007
4380
|
}
|
|
4008
4381
|
|
|
4382
|
+
await scheduler.flush();
|
|
4383
|
+
|
|
4009
4384
|
const status = result.status ?? 200;
|
|
4010
4385
|
return {
|
|
4011
4386
|
html: renderDocument(result.html, { status, signals, browserCache, boundary: result.boundary ?? options.boundary ?? "route", attributes }),
|
|
@@ -4024,6 +4399,9 @@ const __appModule = (() => {
|
|
|
4024
4399
|
router?.destroy?.();
|
|
4025
4400
|
loader?.destroy?.();
|
|
4026
4401
|
signals.destroy?.();
|
|
4402
|
+
if (ownsScheduler) {
|
|
4403
|
+
scheduler.destroy();
|
|
4404
|
+
}
|
|
4027
4405
|
},
|
|
4028
4406
|
|
|
4029
4407
|
_applyUse(normalized) {
|
|
@@ -4044,11 +4422,23 @@ const __appModule = (() => {
|
|
|
4044
4422
|
loader,
|
|
4045
4423
|
router,
|
|
4046
4424
|
cache,
|
|
4047
|
-
|
|
4048
|
-
|
|
4425
|
+
scheduler,
|
|
4426
|
+
requestContext: options.requestContext,
|
|
4427
|
+
...currentRequestContext()
|
|
4049
4428
|
});
|
|
4050
4429
|
}
|
|
4051
4430
|
|
|
4431
|
+
function currentRequestContext() {
|
|
4432
|
+
const context = readRequestContextLike(options.requestContext);
|
|
4433
|
+
return {
|
|
4434
|
+
requestContext: context,
|
|
4435
|
+
request: context.request ?? options.request,
|
|
4436
|
+
headers: context.headers ?? options.headers,
|
|
4437
|
+
cookies: context.cookies ?? options.cookies,
|
|
4438
|
+
locals: context.locals ?? options.locals
|
|
4439
|
+
};
|
|
4440
|
+
}
|
|
4441
|
+
|
|
4052
4442
|
function assertActive() {
|
|
4053
4443
|
if (destroyed) {
|
|
4054
4444
|
throw new Error("Async app runtime has been destroyed.");
|
|
@@ -4202,6 +4592,77 @@ const __appModule = (() => {
|
|
|
4202
4592
|
}
|
|
4203
4593
|
}
|
|
4204
4594
|
|
|
4595
|
+
function createServerReferenceRegistry(initialMap = {}, options = {}) {
|
|
4596
|
+
const registry = options.registry ?? createRegistryStore();
|
|
4597
|
+
const type = options.type ?? "server";
|
|
4598
|
+
const defaults = {};
|
|
4599
|
+
|
|
4600
|
+
const reference = {
|
|
4601
|
+
registry,
|
|
4602
|
+
|
|
4603
|
+
register(id, value) {
|
|
4604
|
+
registry.register(type, id, value);
|
|
4605
|
+
return id;
|
|
4606
|
+
},
|
|
4607
|
+
|
|
4608
|
+
registerMany(map) {
|
|
4609
|
+
for (const [id, value] of Object.entries(map ?? {})) {
|
|
4610
|
+
reference.register(id, value);
|
|
4611
|
+
}
|
|
4612
|
+
return reference;
|
|
4613
|
+
},
|
|
4614
|
+
|
|
4615
|
+
unregister(id) {
|
|
4616
|
+
return registry.unregister(type, id);
|
|
4617
|
+
},
|
|
4618
|
+
|
|
4619
|
+
resolve() {
|
|
4620
|
+
return undefined;
|
|
4621
|
+
},
|
|
4622
|
+
|
|
4623
|
+
async run(id) {
|
|
4624
|
+
throw new Error(`Server command "${id}" cannot run without a server proxy or server registry.`);
|
|
4625
|
+
},
|
|
4626
|
+
|
|
4627
|
+
keys() {
|
|
4628
|
+
return registry.keys(type);
|
|
4629
|
+
},
|
|
4630
|
+
|
|
4631
|
+
entries() {
|
|
4632
|
+
return registry.entries(type);
|
|
4633
|
+
},
|
|
4634
|
+
|
|
4635
|
+
inspect() {
|
|
4636
|
+
return registry.entries(type);
|
|
4637
|
+
},
|
|
4638
|
+
|
|
4639
|
+
_setContext(context = {}) {
|
|
4640
|
+
Object.assign(defaults, context);
|
|
4641
|
+
return reference;
|
|
4642
|
+
},
|
|
4643
|
+
|
|
4644
|
+
_adoptMany() {
|
|
4645
|
+
return reference;
|
|
4646
|
+
}
|
|
4647
|
+
};
|
|
4648
|
+
|
|
4649
|
+
reference.registerMany(initialMap);
|
|
4650
|
+
return createServerNamespace((id, args, context) => reference.run(id, args, context), reference, () => defaults);
|
|
4651
|
+
}
|
|
4652
|
+
|
|
4653
|
+
function readRequestContextLike(store) {
|
|
4654
|
+
if (!store) {
|
|
4655
|
+
return {};
|
|
4656
|
+
}
|
|
4657
|
+
if (typeof store.get === "function") {
|
|
4658
|
+
return store.get() ?? {};
|
|
4659
|
+
}
|
|
4660
|
+
if (typeof store.getStore === "function") {
|
|
4661
|
+
return store.getStore() ?? {};
|
|
4662
|
+
}
|
|
4663
|
+
return {};
|
|
4664
|
+
}
|
|
4665
|
+
|
|
4205
4666
|
function normalizeEntries(type, entries = {}) {
|
|
4206
4667
|
if (type !== "signal") {
|
|
4207
4668
|
return { ...(entries ?? {}) };
|
|
@@ -4253,6 +4714,312 @@ const __appModule = (() => {
|
|
|
4253
4714
|
return { defineApp, createApp, readSnapshot, Async };
|
|
4254
4715
|
})();
|
|
4255
4716
|
|
|
4717
|
+
const __boundaryReceiverModule = (() => {
|
|
4718
|
+
const defaultRecentLimit = 50;
|
|
4719
|
+
|
|
4720
|
+
function createBoundaryReceiver(options = {}) {
|
|
4721
|
+
const loader = options.loader;
|
|
4722
|
+
const signals = options.signals ?? loader?.signals;
|
|
4723
|
+
const cache = options.cache ?? loader?.cache;
|
|
4724
|
+
const scheduler = options.scheduler ?? loader?.scheduler;
|
|
4725
|
+
const router = options.router ?? loader?.router;
|
|
4726
|
+
const recentLimit = options.recentLimit ?? defaultRecentLimit;
|
|
4727
|
+
const throwOnError = options.throwOnError === true;
|
|
4728
|
+
const onApply = typeof options.onApply === "function" ? options.onApply : undefined;
|
|
4729
|
+
const onIgnore = typeof options.onIgnore === "function" ? options.onIgnore : undefined;
|
|
4730
|
+
const onError = typeof options.onError === "function" ? options.onError : undefined;
|
|
4731
|
+
const isScopeDestroyed = typeof options.isScopeDestroyed === "function"
|
|
4732
|
+
? options.isScopeDestroyed
|
|
4733
|
+
: (scope) => scheduler?.isScopeDestroyed?.(scope) ?? scheduler?.inspectDestroyed?.(scope) ?? false;
|
|
4734
|
+
|
|
4735
|
+
if (!loader || typeof loader.swap !== "function") {
|
|
4736
|
+
throw new TypeError("createBoundaryReceiver(...) requires a loader with swap(boundary, html).");
|
|
4737
|
+
}
|
|
4738
|
+
if (!Number.isInteger(recentLimit) || recentLimit < 0) {
|
|
4739
|
+
throw new TypeError("createBoundaryReceiver(...) recentLimit must be a non-negative integer.");
|
|
4740
|
+
}
|
|
4741
|
+
|
|
4742
|
+
const boundaries = new Map();
|
|
4743
|
+
const recent = [];
|
|
4744
|
+
let destroyed = false;
|
|
4745
|
+
|
|
4746
|
+
const receiver = {
|
|
4747
|
+
async apply(patch) {
|
|
4748
|
+
if (destroyed) {
|
|
4749
|
+
throw new Error("Boundary receiver has been destroyed.");
|
|
4750
|
+
}
|
|
4751
|
+
|
|
4752
|
+
const normalized = validatePatch(patch);
|
|
4753
|
+
const record = boundaryRecord(normalized.boundary);
|
|
4754
|
+
if (normalized.seq <= record.lastSeq) {
|
|
4755
|
+
const result = {
|
|
4756
|
+
status: "ignored-stale",
|
|
4757
|
+
boundary: normalized.boundary,
|
|
4758
|
+
seq: normalized.seq,
|
|
4759
|
+
lastSeq: record.lastSeq
|
|
4760
|
+
};
|
|
4761
|
+
record.ignored += 1;
|
|
4762
|
+
record.lastStatus = result.status;
|
|
4763
|
+
remember(result);
|
|
4764
|
+
onIgnore?.(result, patch);
|
|
4765
|
+
return result;
|
|
4766
|
+
}
|
|
4767
|
+
|
|
4768
|
+
if (normalized.parentScope !== undefined && isScopeDestroyed(normalized.parentScope)) {
|
|
4769
|
+
const result = {
|
|
4770
|
+
status: "ignored-destroyed",
|
|
4771
|
+
boundary: normalized.boundary,
|
|
4772
|
+
seq: normalized.seq,
|
|
4773
|
+
parentScope: normalized.parentScope
|
|
4774
|
+
};
|
|
4775
|
+
record.ignored += 1;
|
|
4776
|
+
record.lastStatus = result.status;
|
|
4777
|
+
remember(result);
|
|
4778
|
+
onIgnore?.(result, patch);
|
|
4779
|
+
return result;
|
|
4780
|
+
}
|
|
4781
|
+
|
|
4782
|
+
record.lastSeq = normalized.seq;
|
|
4783
|
+
|
|
4784
|
+
if (Object.hasOwn(normalized, "error")) {
|
|
4785
|
+
const error = toStableError(normalized.error);
|
|
4786
|
+
const result = {
|
|
4787
|
+
status: "errored",
|
|
4788
|
+
boundary: normalized.boundary,
|
|
4789
|
+
seq: normalized.seq,
|
|
4790
|
+
error
|
|
4791
|
+
};
|
|
4792
|
+
record.errored += 1;
|
|
4793
|
+
record.lastStatus = result.status;
|
|
4794
|
+
remember(result);
|
|
4795
|
+
onError?.(error, result, patch);
|
|
4796
|
+
if (throwOnError) {
|
|
4797
|
+
throw error;
|
|
4798
|
+
}
|
|
4799
|
+
return result;
|
|
4800
|
+
}
|
|
4801
|
+
|
|
4802
|
+
if (normalized.signals) {
|
|
4803
|
+
if (!signals || typeof signals.set !== "function") {
|
|
4804
|
+
throw new Error("Boundary patch includes signals, but no signal registry is available.");
|
|
4805
|
+
}
|
|
4806
|
+
for (const [path, value] of Object.entries(normalized.signals)) {
|
|
4807
|
+
signals.set(path, value);
|
|
4808
|
+
}
|
|
4809
|
+
}
|
|
4810
|
+
|
|
4811
|
+
if (normalized.cache?.browser) {
|
|
4812
|
+
if (!cache || typeof cache.restore !== "function") {
|
|
4813
|
+
throw new Error("Boundary patch includes browser cache, but no cache registry is available.");
|
|
4814
|
+
}
|
|
4815
|
+
cache.restore(normalized.cache.browser);
|
|
4816
|
+
}
|
|
4817
|
+
|
|
4818
|
+
if (normalized.html != null) {
|
|
4819
|
+
loader.swap(normalized.boundary, normalized.html);
|
|
4820
|
+
}
|
|
4821
|
+
|
|
4822
|
+
await flushScheduler(scheduler, normalized.scope);
|
|
4823
|
+
|
|
4824
|
+
if (normalized.redirect) {
|
|
4825
|
+
await followRedirect(normalized.redirect, router, loader);
|
|
4826
|
+
const result = {
|
|
4827
|
+
status: "redirected",
|
|
4828
|
+
boundary: normalized.boundary,
|
|
4829
|
+
seq: normalized.seq,
|
|
4830
|
+
redirect: normalized.redirect
|
|
4831
|
+
};
|
|
4832
|
+
record.applied += 1;
|
|
4833
|
+
record.lastStatus = result.status;
|
|
4834
|
+
remember(result);
|
|
4835
|
+
onApply?.(result, patch);
|
|
4836
|
+
return result;
|
|
4837
|
+
}
|
|
4838
|
+
|
|
4839
|
+
const result = {
|
|
4840
|
+
status: "applied",
|
|
4841
|
+
boundary: normalized.boundary,
|
|
4842
|
+
seq: normalized.seq
|
|
4843
|
+
};
|
|
4844
|
+
record.applied += 1;
|
|
4845
|
+
record.lastStatus = result.status;
|
|
4846
|
+
remember(result);
|
|
4847
|
+
onApply?.(result, patch);
|
|
4848
|
+
return result;
|
|
4849
|
+
},
|
|
4850
|
+
|
|
4851
|
+
inspect() {
|
|
4852
|
+
const snapshot = {};
|
|
4853
|
+
for (const [boundary, record] of boundaries) {
|
|
4854
|
+
snapshot[boundary] = {
|
|
4855
|
+
lastSeq: record.lastSeq,
|
|
4856
|
+
applied: record.applied,
|
|
4857
|
+
ignored: record.ignored,
|
|
4858
|
+
lastStatus: record.lastStatus
|
|
4859
|
+
};
|
|
4860
|
+
if (record.errored > 0) {
|
|
4861
|
+
snapshot[boundary].errored = record.errored;
|
|
4862
|
+
}
|
|
4863
|
+
}
|
|
4864
|
+
return {
|
|
4865
|
+
destroyed,
|
|
4866
|
+
boundaries: snapshot,
|
|
4867
|
+
recent: recent.map((entry) => ({ ...entry }))
|
|
4868
|
+
};
|
|
4869
|
+
},
|
|
4870
|
+
|
|
4871
|
+
reset(boundary) {
|
|
4872
|
+
if (boundary === undefined) {
|
|
4873
|
+
boundaries.clear();
|
|
4874
|
+
recent.length = 0;
|
|
4875
|
+
return receiver;
|
|
4876
|
+
}
|
|
4877
|
+
assertBoundary(boundary);
|
|
4878
|
+
boundaries.delete(boundary);
|
|
4879
|
+
for (let index = recent.length - 1; index >= 0; index -= 1) {
|
|
4880
|
+
if (recent[index].boundary === boundary) {
|
|
4881
|
+
recent.splice(index, 1);
|
|
4882
|
+
}
|
|
4883
|
+
}
|
|
4884
|
+
return receiver;
|
|
4885
|
+
},
|
|
4886
|
+
|
|
4887
|
+
destroy() {
|
|
4888
|
+
destroyed = true;
|
|
4889
|
+
boundaries.clear();
|
|
4890
|
+
recent.length = 0;
|
|
4891
|
+
}
|
|
4892
|
+
};
|
|
4893
|
+
|
|
4894
|
+
return receiver;
|
|
4895
|
+
|
|
4896
|
+
function boundaryRecord(boundary) {
|
|
4897
|
+
if (!boundaries.has(boundary)) {
|
|
4898
|
+
boundaries.set(boundary, {
|
|
4899
|
+
lastSeq: -Infinity,
|
|
4900
|
+
applied: 0,
|
|
4901
|
+
ignored: 0,
|
|
4902
|
+
errored: 0,
|
|
4903
|
+
lastStatus: undefined
|
|
4904
|
+
});
|
|
4905
|
+
}
|
|
4906
|
+
return boundaries.get(boundary);
|
|
4907
|
+
}
|
|
4908
|
+
|
|
4909
|
+
function remember(result) {
|
|
4910
|
+
if (recentLimit === 0) {
|
|
4911
|
+
return;
|
|
4912
|
+
}
|
|
4913
|
+
recent.push(toRecentEntry(result));
|
|
4914
|
+
while (recent.length > recentLimit) {
|
|
4915
|
+
recent.shift();
|
|
4916
|
+
}
|
|
4917
|
+
}
|
|
4918
|
+
}
|
|
4919
|
+
|
|
4920
|
+
function validatePatch(patch) {
|
|
4921
|
+
if (!patch || typeof patch !== "object" || Array.isArray(patch)) {
|
|
4922
|
+
throw new TypeError("receiver.apply(patch) requires a boundary patch object.");
|
|
4923
|
+
}
|
|
4924
|
+
|
|
4925
|
+
assertBoundary(patch.boundary);
|
|
4926
|
+
if (typeof patch.seq !== "number" || !Number.isFinite(patch.seq)) {
|
|
4927
|
+
throw new TypeError("Boundary patch seq must be a finite number.");
|
|
4928
|
+
}
|
|
4929
|
+
|
|
4930
|
+
if (patch.signals !== undefined && !isPlainObject(patch.signals)) {
|
|
4931
|
+
throw new TypeError("Boundary patch signals must be an object.");
|
|
4932
|
+
}
|
|
4933
|
+
if (patch.cache !== undefined && !isPlainObject(patch.cache)) {
|
|
4934
|
+
throw new TypeError("Boundary patch cache must be an object.");
|
|
4935
|
+
}
|
|
4936
|
+
if (patch.cache?.browser !== undefined && !isPlainObject(patch.cache.browser)) {
|
|
4937
|
+
throw new TypeError("Boundary patch cache.browser must be an object.");
|
|
4938
|
+
}
|
|
4939
|
+
if (patch.redirect !== undefined && (typeof patch.redirect !== "string" || patch.redirect.length === 0)) {
|
|
4940
|
+
throw new TypeError("Boundary patch redirect must be a non-empty string.");
|
|
4941
|
+
}
|
|
4942
|
+
if (patch.parentScope !== undefined && typeof patch.parentScope !== "string") {
|
|
4943
|
+
throw new TypeError("Boundary patch parentScope must be a string.");
|
|
4944
|
+
}
|
|
4945
|
+
if (patch.scope !== undefined && typeof patch.scope !== "string") {
|
|
4946
|
+
throw new TypeError("Boundary patch scope must be a string.");
|
|
4947
|
+
}
|
|
4948
|
+
|
|
4949
|
+
const hasHtml = Object.hasOwn(patch, "html") && patch.html != null;
|
|
4950
|
+
const hasSignals = patch.signals && Object.keys(patch.signals).length > 0;
|
|
4951
|
+
const hasBrowserCache = patch.cache?.browser && Object.keys(patch.cache.browser).length > 0;
|
|
4952
|
+
const hasRedirect = Boolean(patch.redirect);
|
|
4953
|
+
const hasError = Object.hasOwn(patch, "error");
|
|
4954
|
+
if (!hasHtml && !hasSignals && !hasBrowserCache && !hasRedirect && !hasError) {
|
|
4955
|
+
throw new TypeError("Boundary patch must include html, signals, cache.browser, redirect, or error.");
|
|
4956
|
+
}
|
|
4957
|
+
|
|
4958
|
+
return patch;
|
|
4959
|
+
}
|
|
4960
|
+
|
|
4961
|
+
function assertBoundary(boundary) {
|
|
4962
|
+
if (typeof boundary !== "string" || boundary.length === 0) {
|
|
4963
|
+
throw new TypeError("Boundary patch boundary must be a non-empty string.");
|
|
4964
|
+
}
|
|
4965
|
+
}
|
|
4966
|
+
|
|
4967
|
+
async function flushScheduler(scheduler, scope) {
|
|
4968
|
+
if (!scheduler) {
|
|
4969
|
+
return;
|
|
4970
|
+
}
|
|
4971
|
+
if (scope !== undefined && typeof scheduler.flushScope === "function") {
|
|
4972
|
+
await scheduler.flushScope(scope);
|
|
4973
|
+
return;
|
|
4974
|
+
}
|
|
4975
|
+
if (typeof scheduler.flush === "function") {
|
|
4976
|
+
await scheduler.flush();
|
|
4977
|
+
}
|
|
4978
|
+
}
|
|
4979
|
+
|
|
4980
|
+
async function followRedirect(redirect, router, loader) {
|
|
4981
|
+
if (router && typeof router.navigate === "function") {
|
|
4982
|
+
await router.navigate(redirect);
|
|
4983
|
+
return;
|
|
4984
|
+
}
|
|
4985
|
+
const location = loader?.root?.ownerDocument?.defaultView?.location ?? globalThis.location;
|
|
4986
|
+
location?.assign?.(redirect);
|
|
4987
|
+
}
|
|
4988
|
+
|
|
4989
|
+
function toStableError(value) {
|
|
4990
|
+
if (value instanceof Error) {
|
|
4991
|
+
return value;
|
|
4992
|
+
}
|
|
4993
|
+
if (value && typeof value === "object" && typeof value.message === "string") {
|
|
4994
|
+
return Object.assign(new Error(value.message), value);
|
|
4995
|
+
}
|
|
4996
|
+
return new Error(String(value));
|
|
4997
|
+
}
|
|
4998
|
+
|
|
4999
|
+
function toRecentEntry(result) {
|
|
5000
|
+
const entry = {
|
|
5001
|
+
boundary: result.boundary,
|
|
5002
|
+
seq: result.seq,
|
|
5003
|
+
status: result.status
|
|
5004
|
+
};
|
|
5005
|
+
if (result.status === "ignored-stale") {
|
|
5006
|
+
entry.lastSeq = result.lastSeq;
|
|
5007
|
+
}
|
|
5008
|
+
if (result.status === "ignored-destroyed" && result.parentScope !== undefined) {
|
|
5009
|
+
entry.parentScope = result.parentScope;
|
|
5010
|
+
}
|
|
5011
|
+
if (result.status === "redirected") {
|
|
5012
|
+
entry.redirect = result.redirect;
|
|
5013
|
+
}
|
|
5014
|
+
return entry;
|
|
5015
|
+
}
|
|
5016
|
+
|
|
5017
|
+
function isPlainObject(value) {
|
|
5018
|
+
return Boolean(value && typeof value === "object" && !Array.isArray(value));
|
|
5019
|
+
}
|
|
5020
|
+
return { createBoundaryReceiver };
|
|
5021
|
+
})();
|
|
5022
|
+
|
|
4256
5023
|
const __delayModule = (() => {
|
|
4257
5024
|
function delay(ms, signal) {
|
|
4258
5025
|
if (signal?.aborted) {
|
|
@@ -4294,6 +5061,7 @@ const { defineApp: defineApp } = __appModule;
|
|
|
4294
5061
|
const { readSnapshot: readSnapshot } = __appModule;
|
|
4295
5062
|
const { attributeName: attributeName } = __attributesModule;
|
|
4296
5063
|
const { defineAttributeConfig: defineAttributeConfig } = __attributesModule;
|
|
5064
|
+
const { createBoundaryReceiver: createBoundaryReceiver } = __boundaryReceiverModule;
|
|
4297
5065
|
const { createCacheRegistry: createCacheRegistry } = __cacheModule;
|
|
4298
5066
|
const { defineCache: defineCache } = __cacheModule;
|
|
4299
5067
|
const { component: component } = __componentModule;
|
|
@@ -4310,12 +5078,15 @@ const { createRouteRegistry: createRouteRegistry } = __routerModule;
|
|
|
4310
5078
|
const { createRouter: createRouter } = __routerModule;
|
|
4311
5079
|
const { defineRoute: defineRoute } = __routerModule;
|
|
4312
5080
|
const { route: route } = __routerModule;
|
|
5081
|
+
const { createScheduler: createScheduler } = __schedulerModule;
|
|
5082
|
+
const { applyServerResult: applyServerResult } = __serverModule;
|
|
4313
5083
|
const { createServerProxy: createServerProxy } = __serverModule;
|
|
4314
|
-
const {
|
|
5084
|
+
const { resolveServerCommandArguments: resolveServerCommandArguments } = __serverModule;
|
|
5085
|
+
const { unwrapServerResult: unwrapServerResult } = __serverModule;
|
|
4315
5086
|
const { computed: computed } = __signalsModule;
|
|
4316
5087
|
const { createSignal: createSignal } = __signalsModule;
|
|
4317
5088
|
const { createSignalRegistry: createSignalRegistry } = __signalsModule;
|
|
4318
5089
|
const { effect: effect } = __signalsModule;
|
|
4319
5090
|
const { signal: signal } = __signalsModule;
|
|
4320
5091
|
|
|
4321
|
-
export { asyncSignal, Async, createApp, defineApp, readSnapshot, attributeName, defineAttributeConfig, createCacheRegistry, defineCache, component, createComponentRegistry, defineComponent, delay, createHandlerRegistry, html, Loader, AsyncLoader, createPartialRegistry, createRegistryStore, createRouteRegistry, createRouter, defineRoute, route, createServerProxy,
|
|
5092
|
+
export { asyncSignal, Async, createApp, defineApp, readSnapshot, attributeName, defineAttributeConfig, createBoundaryReceiver, createCacheRegistry, defineCache, component, createComponentRegistry, defineComponent, delay, createHandlerRegistry, html, Loader, AsyncLoader, createPartialRegistry, createRegistryStore, createRouteRegistry, createRouter, defineRoute, route, createScheduler, applyServerResult, createServerProxy, resolveServerCommandArguments, unwrapServerResult, computed, createSignal, createSignalRegistry, effect, signal };
|