@async/framework 0.7.0 → 0.8.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 +16 -0
- package/README.md +81 -14
- package/{framework.d.ts → browser.d.ts} +68 -4
- package/{framework.js → browser.js} +587 -127
- package/browser.min.js +1 -0
- package/{framework.ts → browser.ts} +588 -128
- package/{framework.umd.js → browser.umd.js} +587 -127
- package/browser.umd.min.js +1 -0
- package/package.json +45 -30
- package/server.d.ts +640 -0
- package/src/app.js +110 -11
- package/src/async-signal.js +32 -4
- package/src/browser.js +15 -0
- package/src/component.js +42 -7
- package/src/index.js +5 -2
- package/src/loader.js +42 -10
- package/src/request-context.js +40 -0
- package/src/router.js +15 -2
- package/src/scheduler.js +296 -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,321 @@ 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
|
+
inspect() {
|
|
2599
|
+
const counts = {};
|
|
2600
|
+
for (const [phase, queue] of queues) {
|
|
2601
|
+
counts[phase] = queue.filter((job) => !job.canceled).length;
|
|
2602
|
+
}
|
|
2603
|
+
return {
|
|
2604
|
+
strategy,
|
|
2605
|
+
phases: [...phases],
|
|
2606
|
+
pending: counts,
|
|
2607
|
+
scopesDestroyed: destroyedScopes.size,
|
|
2608
|
+
flushing,
|
|
2609
|
+
scheduled
|
|
2610
|
+
};
|
|
2611
|
+
},
|
|
2612
|
+
|
|
2613
|
+
destroy() {
|
|
2614
|
+
destroyed = true;
|
|
2615
|
+
for (const queue of queues.values()) {
|
|
2616
|
+
for (const job of queue) {
|
|
2617
|
+
job.cancel();
|
|
2618
|
+
}
|
|
2619
|
+
queue.length = 0;
|
|
2620
|
+
}
|
|
2621
|
+
keyedJobs.clear();
|
|
2622
|
+
destroyedScopes.clear();
|
|
2623
|
+
}
|
|
2624
|
+
};
|
|
2625
|
+
|
|
2626
|
+
return api;
|
|
2627
|
+
|
|
2628
|
+
function requestFlush() {
|
|
2629
|
+
if (strategy === "manual" || destroyed || flushing || batchDepth > 0 || scheduled) {
|
|
2630
|
+
return;
|
|
2631
|
+
}
|
|
2632
|
+
scheduled = true;
|
|
2633
|
+
scheduleMicrotask(() => {
|
|
2634
|
+
if (!destroyed) {
|
|
2635
|
+
void api.flush();
|
|
2636
|
+
}
|
|
2637
|
+
});
|
|
2638
|
+
}
|
|
2639
|
+
|
|
2640
|
+
async function flushPhase(phase, scope) {
|
|
2641
|
+
const queue = queues.get(phase);
|
|
2642
|
+
const remaining = [];
|
|
2643
|
+
const runnable = [];
|
|
2644
|
+
|
|
2645
|
+
for (const job of queue.splice(0)) {
|
|
2646
|
+
if (job.canceled) {
|
|
2647
|
+
continue;
|
|
2648
|
+
}
|
|
2649
|
+
if (scope !== undefined && job.scope !== scope) {
|
|
2650
|
+
remaining.push(job);
|
|
2651
|
+
continue;
|
|
2652
|
+
}
|
|
2653
|
+
runnable.push(job);
|
|
2654
|
+
}
|
|
2655
|
+
|
|
2656
|
+
queue.push(...remaining);
|
|
2657
|
+
|
|
2658
|
+
for (const job of runnable) {
|
|
2659
|
+
if (job.key) {
|
|
2660
|
+
keyedJobs.delete(job.key);
|
|
2661
|
+
}
|
|
2662
|
+
if (job.canceled || (job.scope !== undefined && destroyedScopes.has(job.scope))) {
|
|
2663
|
+
continue;
|
|
2664
|
+
}
|
|
2665
|
+
try {
|
|
2666
|
+
await job.fn();
|
|
2667
|
+
} catch (error) {
|
|
2668
|
+
if (onError) {
|
|
2669
|
+
onError(error, job);
|
|
2670
|
+
} else {
|
|
2671
|
+
throw error;
|
|
2672
|
+
}
|
|
2673
|
+
}
|
|
2674
|
+
}
|
|
2675
|
+
}
|
|
2676
|
+
|
|
2677
|
+
function hasJobs() {
|
|
2678
|
+
for (const queue of queues.values()) {
|
|
2679
|
+
if (queue.some((job) => !job.canceled)) {
|
|
2680
|
+
return true;
|
|
2681
|
+
}
|
|
2682
|
+
}
|
|
2683
|
+
return false;
|
|
2684
|
+
}
|
|
2685
|
+
|
|
2686
|
+
function hasJobsForScope(scope) {
|
|
2687
|
+
for (const queue of queues.values()) {
|
|
2688
|
+
if (queue.some((job) => !job.canceled && job.scope === scope)) {
|
|
2689
|
+
return true;
|
|
2690
|
+
}
|
|
2691
|
+
}
|
|
2692
|
+
return false;
|
|
2693
|
+
}
|
|
2694
|
+
|
|
2695
|
+
function assertActive() {
|
|
2696
|
+
if (destroyed) {
|
|
2697
|
+
throw new Error("Scheduler has been destroyed.");
|
|
2698
|
+
}
|
|
2699
|
+
}
|
|
2700
|
+
|
|
2701
|
+
function assertPhase(phase) {
|
|
2702
|
+
if (!queues.has(phase)) {
|
|
2703
|
+
throw new Error(`Unknown scheduler phase "${phase}".`);
|
|
2704
|
+
}
|
|
2705
|
+
}
|
|
2706
|
+
|
|
2707
|
+
function scopeKey(scope) {
|
|
2708
|
+
if (scope === undefined) {
|
|
2709
|
+
return "global";
|
|
2710
|
+
}
|
|
2711
|
+
if ((typeof scope === "object" && scope !== null) || typeof scope === "function") {
|
|
2712
|
+
if (!objectScopeIds.has(scope)) {
|
|
2713
|
+
objectScopeIds.set(scope, `scope:${++scopeCounter}`);
|
|
2714
|
+
}
|
|
2715
|
+
return objectScopeIds.get(scope);
|
|
2716
|
+
}
|
|
2717
|
+
return String(scope);
|
|
2718
|
+
}
|
|
2719
|
+
}
|
|
2720
|
+
|
|
2721
|
+
function scheduleMicrotask(fn) {
|
|
2722
|
+
if (typeof queueMicrotask === "function") {
|
|
2723
|
+
queueMicrotask(fn);
|
|
2724
|
+
return;
|
|
2725
|
+
}
|
|
2726
|
+
Promise.resolve().then(fn);
|
|
2727
|
+
}
|
|
2728
|
+
|
|
2729
|
+
function noop() {}
|
|
2730
|
+
return { createScheduler };
|
|
2731
|
+
})();
|
|
2732
|
+
|
|
2420
2733
|
const __loaderModule = (() => {
|
|
2421
2734
|
const { renderComponent } = __componentModule;
|
|
2422
2735
|
const { createHandlerRegistry } = __handlersModule;
|
|
2736
|
+
const { createScheduler } = __schedulerModule;
|
|
2423
2737
|
const { createSignalRegistry, isSignalRef } = __signalsModule;
|
|
2424
2738
|
const { matchAttribute, normalizeAttributeConfig, readAttribute } = __attributesModule;
|
|
2425
2739
|
const inlineBindingPrefix = "__async:inline:";
|
|
2426
2740
|
|
|
2427
|
-
function Loader({ root, signals, handlers, server, router, cache, attributes } = {}) {
|
|
2741
|
+
function Loader({ root, signals, handlers, server, router, cache, attributes, scheduler } = {}) {
|
|
2428
2742
|
const documentRef = root?.ownerDocument ?? root ?? globalThis.document;
|
|
2429
2743
|
const rootNode = root ?? documentRef;
|
|
2430
2744
|
const signalRegistry = signals ?? createSignalRegistry();
|
|
2431
2745
|
const handlerRegistry = handlers ?? createHandlerRegistry();
|
|
2746
|
+
const schedulerInstance = scheduler ?? createScheduler();
|
|
2747
|
+
const ownsScheduler = !scheduler;
|
|
2432
2748
|
const attributeConfig = normalizeAttributeConfig(attributes);
|
|
2433
2749
|
const cleanups = new Set();
|
|
2434
2750
|
const eventBindings = new WeakMap();
|
|
@@ -2449,6 +2765,7 @@ const __loaderModule = (() => {
|
|
|
2449
2765
|
server,
|
|
2450
2766
|
router,
|
|
2451
2767
|
cache,
|
|
2768
|
+
scheduler: schedulerInstance,
|
|
2452
2769
|
attributes: attributeConfig,
|
|
2453
2770
|
|
|
2454
2771
|
start() {
|
|
@@ -2488,6 +2805,7 @@ const __loaderModule = (() => {
|
|
|
2488
2805
|
server: api.server,
|
|
2489
2806
|
router: api.router,
|
|
2490
2807
|
cache: api.cache,
|
|
2808
|
+
scheduler: schedulerInstance,
|
|
2491
2809
|
attributes: attributeConfig
|
|
2492
2810
|
});
|
|
2493
2811
|
cleanupChildren(target);
|
|
@@ -2508,6 +2826,9 @@ const __loaderModule = (() => {
|
|
|
2508
2826
|
runCleanup(cleanup);
|
|
2509
2827
|
}
|
|
2510
2828
|
cleanups.clear();
|
|
2829
|
+
if (ownsScheduler) {
|
|
2830
|
+
schedulerInstance.destroy();
|
|
2831
|
+
}
|
|
2511
2832
|
},
|
|
2512
2833
|
|
|
2513
2834
|
_observeVisible(target, fn) {
|
|
@@ -2525,13 +2846,14 @@ const __loaderModule = (() => {
|
|
|
2525
2846
|
}
|
|
2526
2847
|
};
|
|
2527
2848
|
|
|
2528
|
-
signalRegistry._setContext?.({ server: api.server, router: api.router, loader: api, cache: api.cache });
|
|
2849
|
+
signalRegistry._setContext?.({ server: api.server, router: api.router, loader: api, cache: api.cache, scheduler: schedulerInstance });
|
|
2529
2850
|
api.server?._setContext?.({
|
|
2530
2851
|
signals: signalRegistry,
|
|
2531
2852
|
handlers: handlerRegistry,
|
|
2532
2853
|
loader: api,
|
|
2533
2854
|
router: api.router,
|
|
2534
|
-
cache: api.cache
|
|
2855
|
+
cache: api.cache,
|
|
2856
|
+
scheduler: schedulerInstance
|
|
2535
2857
|
});
|
|
2536
2858
|
|
|
2537
2859
|
function bindEventAttributes(scope) {
|
|
@@ -2563,18 +2885,19 @@ const __loaderModule = (() => {
|
|
|
2563
2885
|
|
|
2564
2886
|
const listener = async (event) => {
|
|
2565
2887
|
try {
|
|
2566
|
-
await handlerRegistry.run(ref, {
|
|
2888
|
+
await schedulerInstance.batch(() => handlerRegistry.run(ref, {
|
|
2567
2889
|
signals: signalRegistry,
|
|
2568
2890
|
handlers: handlerRegistry,
|
|
2569
2891
|
loader: api,
|
|
2570
2892
|
server: api.server,
|
|
2571
2893
|
router: api.router,
|
|
2572
2894
|
cache: api.cache,
|
|
2895
|
+
scheduler: schedulerInstance,
|
|
2573
2896
|
event,
|
|
2574
2897
|
element,
|
|
2575
2898
|
el: element,
|
|
2576
2899
|
root: rootNode
|
|
2577
|
-
});
|
|
2900
|
+
}));
|
|
2578
2901
|
} catch (error) {
|
|
2579
2902
|
dispatchAsyncError(element, error);
|
|
2580
2903
|
}
|
|
@@ -2690,7 +3013,12 @@ const __loaderModule = (() => {
|
|
|
2690
3013
|
|
|
2691
3014
|
const read = () => readBinding(path, options);
|
|
2692
3015
|
apply(read());
|
|
2693
|
-
addCleanup(subscribeBinding(path, () =>
|
|
3016
|
+
addCleanup(subscribeBinding(path, () => {
|
|
3017
|
+
schedulerInstance.enqueue("binding", () => apply(read()), {
|
|
3018
|
+
scope: element,
|
|
3019
|
+
key
|
|
3020
|
+
});
|
|
3021
|
+
}), element);
|
|
2694
3022
|
}
|
|
2695
3023
|
|
|
2696
3024
|
function bindValueWriter(element, path) {
|
|
@@ -2751,7 +3079,12 @@ const __loaderModule = (() => {
|
|
|
2751
3079
|
const state = {
|
|
2752
3080
|
id,
|
|
2753
3081
|
templates,
|
|
2754
|
-
cleanup: signalRegistry.subscribe(`${id}.$status`, () =>
|
|
3082
|
+
cleanup: signalRegistry.subscribe(`${id}.$status`, () => {
|
|
3083
|
+
schedulerInstance.enqueue("binding", () => renderBoundary(boundary), {
|
|
3084
|
+
scope: boundary,
|
|
3085
|
+
key: `boundary:${id}`
|
|
3086
|
+
});
|
|
3087
|
+
})
|
|
2755
3088
|
};
|
|
2756
3089
|
boundaryState.set(boundary, state);
|
|
2757
3090
|
addCleanup(state.cleanup, boundary);
|
|
@@ -2791,7 +3124,7 @@ const __loaderModule = (() => {
|
|
|
2791
3124
|
}
|
|
2792
3125
|
mountedElements.add(element);
|
|
2793
3126
|
for (const ref of refs) {
|
|
2794
|
-
runPseudo(element, ref);
|
|
3127
|
+
scheduleLifecycle(element, () => runPseudo(element, ref), `attach:${ref}`);
|
|
2795
3128
|
}
|
|
2796
3129
|
}
|
|
2797
3130
|
|
|
@@ -2804,7 +3137,7 @@ const __loaderModule = (() => {
|
|
|
2804
3137
|
continue;
|
|
2805
3138
|
}
|
|
2806
3139
|
visibleElements.add(element);
|
|
2807
|
-
addCleanup(observeVisible(element, () => runPseudo(element, ref)), element);
|
|
3140
|
+
addCleanup(observeVisible(element, () => scheduleLifecycle(element, () => runPseudo(element, ref), `visible:${ref}`)), element);
|
|
2808
3141
|
}
|
|
2809
3142
|
}
|
|
2810
3143
|
|
|
@@ -2828,6 +3161,7 @@ const __loaderModule = (() => {
|
|
|
2828
3161
|
server: api.server,
|
|
2829
3162
|
router: api.router,
|
|
2830
3163
|
cache: api.cache,
|
|
3164
|
+
scheduler: schedulerInstance,
|
|
2831
3165
|
element,
|
|
2832
3166
|
el: element,
|
|
2833
3167
|
root: rootNode
|
|
@@ -2846,10 +3180,13 @@ const __loaderModule = (() => {
|
|
|
2846
3180
|
const ownerWindow = target.ownerDocument?.defaultView ?? globalThis;
|
|
2847
3181
|
const Observer = ownerWindow.IntersectionObserver ?? globalThis.IntersectionObserver;
|
|
2848
3182
|
if (!Observer) {
|
|
2849
|
-
|
|
3183
|
+
schedulerInstance.enqueue("lifecycle", () => {
|
|
2850
3184
|
if (!destroyed) {
|
|
2851
3185
|
fn(target);
|
|
2852
3186
|
}
|
|
3187
|
+
}, {
|
|
3188
|
+
scope: target,
|
|
3189
|
+
key: "visible:fallback"
|
|
2853
3190
|
});
|
|
2854
3191
|
return () => {};
|
|
2855
3192
|
}
|
|
@@ -2904,6 +3241,7 @@ const __loaderModule = (() => {
|
|
|
2904
3241
|
}
|
|
2905
3242
|
for (const element of elementsIn(node)) {
|
|
2906
3243
|
runScopedCleanups(element);
|
|
3244
|
+
schedulerInstance.markScopeDestroyed(element);
|
|
2907
3245
|
}
|
|
2908
3246
|
}
|
|
2909
3247
|
|
|
@@ -2927,6 +3265,13 @@ const __loaderModule = (() => {
|
|
|
2927
3265
|
}
|
|
2928
3266
|
}
|
|
2929
3267
|
|
|
3268
|
+
function scheduleLifecycle(element, fn, key) {
|
|
3269
|
+
schedulerInstance.enqueue("lifecycle", fn, {
|
|
3270
|
+
scope: element,
|
|
3271
|
+
key
|
|
3272
|
+
});
|
|
3273
|
+
}
|
|
3274
|
+
|
|
2930
3275
|
return api;
|
|
2931
3276
|
}
|
|
2932
3277
|
|
|
@@ -3257,6 +3602,7 @@ const __partialsModule = (() => {
|
|
|
3257
3602
|
const __routerModule = (() => {
|
|
3258
3603
|
const { Loader } = __loaderModule;
|
|
3259
3604
|
const { createHandlerRegistry } = __handlersModule;
|
|
3605
|
+
const { createScheduler } = __schedulerModule;
|
|
3260
3606
|
const { createSignalRegistry } = __signalsModule;
|
|
3261
3607
|
const { applyServerResult } = __serverModule;
|
|
3262
3608
|
const { createRegistryStore } = __registryStoreModule;
|
|
@@ -3377,12 +3723,15 @@ const __routerModule = (() => {
|
|
|
3377
3723
|
partials,
|
|
3378
3724
|
fetch: fetchImpl = globalThis.fetch?.bind(globalThis),
|
|
3379
3725
|
routeEndpoint = "/__async/route",
|
|
3380
|
-
attributes
|
|
3726
|
+
attributes,
|
|
3727
|
+
scheduler
|
|
3381
3728
|
} = {}) {
|
|
3382
3729
|
const documentRef = root?.ownerDocument ?? root ?? globalThis.document;
|
|
3383
3730
|
const rootNode = root ?? documentRef;
|
|
3384
3731
|
const signalRegistry = signals ?? loader?.signals ?? createSignalRegistry();
|
|
3385
3732
|
const handlerRegistry = handlers ?? loader?.handlers ?? createHandlerRegistry();
|
|
3733
|
+
const schedulerInstance = scheduler ?? loader?.scheduler ?? createScheduler();
|
|
3734
|
+
const ownsScheduler = !scheduler && !loader?.scheduler;
|
|
3386
3735
|
const attributeConfig = normalizeAttributeConfig(attributes ?? loader?.attributes);
|
|
3387
3736
|
const loaderInstance =
|
|
3388
3737
|
loader ??
|
|
@@ -3392,6 +3741,7 @@ const __routerModule = (() => {
|
|
|
3392
3741
|
handlers: handlerRegistry,
|
|
3393
3742
|
server,
|
|
3394
3743
|
cache,
|
|
3744
|
+
scheduler: schedulerInstance,
|
|
3395
3745
|
attributes: attributeConfig
|
|
3396
3746
|
});
|
|
3397
3747
|
const ownsLoader = !loader;
|
|
@@ -3411,12 +3761,13 @@ const __routerModule = (() => {
|
|
|
3411
3761
|
server,
|
|
3412
3762
|
cache,
|
|
3413
3763
|
partials,
|
|
3764
|
+
scheduler: schedulerInstance,
|
|
3414
3765
|
attributes: attributeConfig,
|
|
3415
3766
|
|
|
3416
3767
|
start() {
|
|
3417
3768
|
assertActive();
|
|
3418
3769
|
loaderInstance.router = api;
|
|
3419
|
-
signalRegistry._setContext?.({ router: api, loader: loaderInstance, server, cache });
|
|
3770
|
+
signalRegistry._setContext?.({ router: api, loader: loaderInstance, server, cache, scheduler: schedulerInstance });
|
|
3420
3771
|
if (ownsLoader) {
|
|
3421
3772
|
loaderInstance.start();
|
|
3422
3773
|
}
|
|
@@ -3480,6 +3831,9 @@ const __routerModule = (() => {
|
|
|
3480
3831
|
cleanup();
|
|
3481
3832
|
}
|
|
3482
3833
|
cleanups.clear();
|
|
3834
|
+
if (ownsScheduler) {
|
|
3835
|
+
schedulerInstance.destroy();
|
|
3836
|
+
}
|
|
3483
3837
|
}
|
|
3484
3838
|
};
|
|
3485
3839
|
|
|
@@ -3585,13 +3939,16 @@ const __routerModule = (() => {
|
|
|
3585
3939
|
loader: loaderInstance,
|
|
3586
3940
|
router: api,
|
|
3587
3941
|
cache,
|
|
3942
|
+
scheduler: schedulerInstance,
|
|
3588
3943
|
abort: navigation?.abort
|
|
3589
3944
|
});
|
|
3945
|
+
await schedulerInstance.flush();
|
|
3590
3946
|
if (!isActiveNavigation(navigation)) {
|
|
3591
3947
|
return;
|
|
3592
3948
|
}
|
|
3593
3949
|
if (result?.html != null && !result.boundary && !result.redirect) {
|
|
3594
3950
|
loaderInstance.swap(boundary, result.html);
|
|
3951
|
+
await schedulerInstance.flush();
|
|
3595
3952
|
}
|
|
3596
3953
|
if (result?.redirect || options.history === false) {
|
|
3597
3954
|
return;
|
|
@@ -3636,6 +3993,7 @@ const __routerModule = (() => {
|
|
|
3636
3993
|
loader: loaderInstance,
|
|
3637
3994
|
server,
|
|
3638
3995
|
cache,
|
|
3996
|
+
scheduler: schedulerInstance,
|
|
3639
3997
|
abort: navigation?.abort
|
|
3640
3998
|
};
|
|
3641
3999
|
}
|
|
@@ -3822,15 +4180,17 @@ const __appModule = (() => {
|
|
|
3822
4180
|
const { Loader } = __loaderModule;
|
|
3823
4181
|
const { createPartialRegistry } = __partialsModule;
|
|
3824
4182
|
const { createRouteRegistry, createRouter } = __routerModule;
|
|
3825
|
-
const {
|
|
4183
|
+
const { createScheduler } = __schedulerModule;
|
|
4184
|
+
const { createServerNamespace } = __serverModule;
|
|
3826
4185
|
const { createSignal, createSignalRegistry } = __signalsModule;
|
|
3827
4186
|
const { createRegistryStore } = __registryStoreModule;
|
|
3828
4187
|
const { attributeName, normalizeAttributeConfig } = __attributesModule;
|
|
3829
4188
|
const registryTypes = new Set(["signal", "handler", "server", "partial", "route", "component"]);
|
|
3830
4189
|
|
|
3831
|
-
function defineApp(initial) {
|
|
4190
|
+
function defineApp(initial, options = {}) {
|
|
3832
4191
|
const registry = createRegistryStore(undefined, { target: "browser" });
|
|
3833
4192
|
const runtimes = new Set();
|
|
4193
|
+
const createRuntime = options.createRuntime ?? createApp;
|
|
3834
4194
|
|
|
3835
4195
|
const app = {
|
|
3836
4196
|
registry,
|
|
@@ -3849,7 +4209,7 @@ const __appModule = (() => {
|
|
|
3849
4209
|
},
|
|
3850
4210
|
|
|
3851
4211
|
start(options = {}) {
|
|
3852
|
-
const runtime =
|
|
4212
|
+
const runtime = createRuntime(app, options).start();
|
|
3853
4213
|
app.runtime = runtime;
|
|
3854
4214
|
return runtime;
|
|
3855
4215
|
},
|
|
@@ -3874,13 +4234,18 @@ const __appModule = (() => {
|
|
|
3874
4234
|
function createApp(appOrDefinition = Async, options = {}) {
|
|
3875
4235
|
const app = isAppHub(appOrDefinition) ? appOrDefinition : defineApp(appOrDefinition ?? {});
|
|
3876
4236
|
const target = options.target ?? "browser";
|
|
4237
|
+
const scheduler = options.scheduler ?? options.loader?.scheduler ?? createScheduler({
|
|
4238
|
+
strategy: target === "server" ? "manual" : "microtask"
|
|
4239
|
+
});
|
|
4240
|
+
const ownsScheduler = !options.scheduler && !options.loader?.scheduler;
|
|
3877
4241
|
const attributes = normalizeAttributeConfig(options.attributes);
|
|
3878
4242
|
const registry = options.registry ?? app.registry.view({ target });
|
|
3879
4243
|
const signals = options.signals ?? createSignalRegistry(undefined, { registry, type: "signal" });
|
|
3880
4244
|
const handlers = options.handlers ?? createHandlerRegistry(undefined, { registry, type: "handler" });
|
|
3881
4245
|
const serverCache = createCacheRegistry(undefined, { registry, type: "cache.server" });
|
|
3882
4246
|
const browserCache = createCacheRegistry(undefined, { registry, type: "cache.browser" });
|
|
3883
|
-
const
|
|
4247
|
+
const serverFactory = options.serverFactory ?? createServerReferenceRegistry;
|
|
4248
|
+
const server = options.server ?? serverFactory(undefined, { registry, type: "server" });
|
|
3884
4249
|
const partials = options.partials ?? createPartialRegistry(undefined, { registry, type: "partial" });
|
|
3885
4250
|
const routes = options.routes ?? createRouteRegistry(undefined, { registry, type: "route" });
|
|
3886
4251
|
const components = options.components ?? createComponentRegistry(undefined, { registry, type: "component" });
|
|
@@ -3908,6 +4273,7 @@ const __appModule = (() => {
|
|
|
3908
4273
|
},
|
|
3909
4274
|
loader,
|
|
3910
4275
|
router,
|
|
4276
|
+
scheduler,
|
|
3911
4277
|
attributes,
|
|
3912
4278
|
|
|
3913
4279
|
start() {
|
|
@@ -3924,12 +4290,13 @@ const __appModule = (() => {
|
|
|
3924
4290
|
handlers,
|
|
3925
4291
|
server,
|
|
3926
4292
|
cache: browserCache,
|
|
4293
|
+
scheduler,
|
|
3927
4294
|
attributes
|
|
3928
4295
|
});
|
|
3929
4296
|
runtime.loader = loader;
|
|
3930
4297
|
|
|
3931
4298
|
configureServerContext({ cache: browserCache });
|
|
3932
|
-
signals._setContext?.({ server, loader, cache: browserCache });
|
|
4299
|
+
signals._setContext?.({ server, loader, cache: browserCache, scheduler });
|
|
3933
4300
|
|
|
3934
4301
|
loader.start();
|
|
3935
4302
|
|
|
@@ -3945,6 +4312,7 @@ const __appModule = (() => {
|
|
|
3945
4312
|
server,
|
|
3946
4313
|
cache: browserCache,
|
|
3947
4314
|
partials,
|
|
4315
|
+
scheduler,
|
|
3948
4316
|
fetch: options.fetch,
|
|
3949
4317
|
routeEndpoint: options.routeEndpoint,
|
|
3950
4318
|
attributes
|
|
@@ -3956,7 +4324,7 @@ const __appModule = (() => {
|
|
|
3956
4324
|
}
|
|
3957
4325
|
} else {
|
|
3958
4326
|
configureServerContext({ cache: serverCache });
|
|
3959
|
-
signals._setContext?.({ server, cache: serverCache });
|
|
4327
|
+
signals._setContext?.({ server, cache: serverCache, scheduler });
|
|
3960
4328
|
}
|
|
3961
4329
|
|
|
3962
4330
|
return runtime;
|
|
@@ -3970,9 +4338,10 @@ const __appModule = (() => {
|
|
|
3970
4338
|
async render(url) {
|
|
3971
4339
|
assertActive();
|
|
3972
4340
|
configureServerContext({ cache: serverCache });
|
|
3973
|
-
signals._setContext?.({ server, cache: serverCache });
|
|
4341
|
+
signals._setContext?.({ server, cache: serverCache, scheduler });
|
|
3974
4342
|
const matched = routes.match(url);
|
|
3975
4343
|
if (!matched) {
|
|
4344
|
+
await scheduler.flush();
|
|
3976
4345
|
return {
|
|
3977
4346
|
html: renderDocument("", { status: 404, signals, browserCache, boundary: options.boundary ?? "route", attributes }),
|
|
3978
4347
|
status: 404,
|
|
@@ -3992,8 +4361,8 @@ const __appModule = (() => {
|
|
|
3992
4361
|
cache: serverCache,
|
|
3993
4362
|
browserCache,
|
|
3994
4363
|
partials,
|
|
3995
|
-
|
|
3996
|
-
|
|
4364
|
+
scheduler,
|
|
4365
|
+
...currentRequestContext()
|
|
3997
4366
|
})
|
|
3998
4367
|
: { html: "" };
|
|
3999
4368
|
|
|
@@ -4006,6 +4375,8 @@ const __appModule = (() => {
|
|
|
4006
4375
|
browserCache.restore(result.cache.browser);
|
|
4007
4376
|
}
|
|
4008
4377
|
|
|
4378
|
+
await scheduler.flush();
|
|
4379
|
+
|
|
4009
4380
|
const status = result.status ?? 200;
|
|
4010
4381
|
return {
|
|
4011
4382
|
html: renderDocument(result.html, { status, signals, browserCache, boundary: result.boundary ?? options.boundary ?? "route", attributes }),
|
|
@@ -4024,6 +4395,9 @@ const __appModule = (() => {
|
|
|
4024
4395
|
router?.destroy?.();
|
|
4025
4396
|
loader?.destroy?.();
|
|
4026
4397
|
signals.destroy?.();
|
|
4398
|
+
if (ownsScheduler) {
|
|
4399
|
+
scheduler.destroy();
|
|
4400
|
+
}
|
|
4027
4401
|
},
|
|
4028
4402
|
|
|
4029
4403
|
_applyUse(normalized) {
|
|
@@ -4044,11 +4418,23 @@ const __appModule = (() => {
|
|
|
4044
4418
|
loader,
|
|
4045
4419
|
router,
|
|
4046
4420
|
cache,
|
|
4047
|
-
|
|
4048
|
-
|
|
4421
|
+
scheduler,
|
|
4422
|
+
requestContext: options.requestContext,
|
|
4423
|
+
...currentRequestContext()
|
|
4049
4424
|
});
|
|
4050
4425
|
}
|
|
4051
4426
|
|
|
4427
|
+
function currentRequestContext() {
|
|
4428
|
+
const context = readRequestContextLike(options.requestContext);
|
|
4429
|
+
return {
|
|
4430
|
+
requestContext: context,
|
|
4431
|
+
request: context.request ?? options.request,
|
|
4432
|
+
headers: context.headers ?? options.headers,
|
|
4433
|
+
cookies: context.cookies ?? options.cookies,
|
|
4434
|
+
locals: context.locals ?? options.locals
|
|
4435
|
+
};
|
|
4436
|
+
}
|
|
4437
|
+
|
|
4052
4438
|
function assertActive() {
|
|
4053
4439
|
if (destroyed) {
|
|
4054
4440
|
throw new Error("Async app runtime has been destroyed.");
|
|
@@ -4202,6 +4588,77 @@ const __appModule = (() => {
|
|
|
4202
4588
|
}
|
|
4203
4589
|
}
|
|
4204
4590
|
|
|
4591
|
+
function createServerReferenceRegistry(initialMap = {}, options = {}) {
|
|
4592
|
+
const registry = options.registry ?? createRegistryStore();
|
|
4593
|
+
const type = options.type ?? "server";
|
|
4594
|
+
const defaults = {};
|
|
4595
|
+
|
|
4596
|
+
const reference = {
|
|
4597
|
+
registry,
|
|
4598
|
+
|
|
4599
|
+
register(id, value) {
|
|
4600
|
+
registry.register(type, id, value);
|
|
4601
|
+
return id;
|
|
4602
|
+
},
|
|
4603
|
+
|
|
4604
|
+
registerMany(map) {
|
|
4605
|
+
for (const [id, value] of Object.entries(map ?? {})) {
|
|
4606
|
+
reference.register(id, value);
|
|
4607
|
+
}
|
|
4608
|
+
return reference;
|
|
4609
|
+
},
|
|
4610
|
+
|
|
4611
|
+
unregister(id) {
|
|
4612
|
+
return registry.unregister(type, id);
|
|
4613
|
+
},
|
|
4614
|
+
|
|
4615
|
+
resolve() {
|
|
4616
|
+
return undefined;
|
|
4617
|
+
},
|
|
4618
|
+
|
|
4619
|
+
async run(id) {
|
|
4620
|
+
throw new Error(`Server command "${id}" cannot run without a server proxy or server registry.`);
|
|
4621
|
+
},
|
|
4622
|
+
|
|
4623
|
+
keys() {
|
|
4624
|
+
return registry.keys(type);
|
|
4625
|
+
},
|
|
4626
|
+
|
|
4627
|
+
entries() {
|
|
4628
|
+
return registry.entries(type);
|
|
4629
|
+
},
|
|
4630
|
+
|
|
4631
|
+
inspect() {
|
|
4632
|
+
return registry.entries(type);
|
|
4633
|
+
},
|
|
4634
|
+
|
|
4635
|
+
_setContext(context = {}) {
|
|
4636
|
+
Object.assign(defaults, context);
|
|
4637
|
+
return reference;
|
|
4638
|
+
},
|
|
4639
|
+
|
|
4640
|
+
_adoptMany() {
|
|
4641
|
+
return reference;
|
|
4642
|
+
}
|
|
4643
|
+
};
|
|
4644
|
+
|
|
4645
|
+
reference.registerMany(initialMap);
|
|
4646
|
+
return createServerNamespace((id, args, context) => reference.run(id, args, context), reference, () => defaults);
|
|
4647
|
+
}
|
|
4648
|
+
|
|
4649
|
+
function readRequestContextLike(store) {
|
|
4650
|
+
if (!store) {
|
|
4651
|
+
return {};
|
|
4652
|
+
}
|
|
4653
|
+
if (typeof store.get === "function") {
|
|
4654
|
+
return store.get() ?? {};
|
|
4655
|
+
}
|
|
4656
|
+
if (typeof store.getStore === "function") {
|
|
4657
|
+
return store.getStore() ?? {};
|
|
4658
|
+
}
|
|
4659
|
+
return {};
|
|
4660
|
+
}
|
|
4661
|
+
|
|
4205
4662
|
function normalizeEntries(type, entries = {}) {
|
|
4206
4663
|
if (type !== "signal") {
|
|
4207
4664
|
return { ...(entries ?? {}) };
|
|
@@ -4310,12 +4767,15 @@ const { createRouteRegistry: createRouteRegistry } = __routerModule;
|
|
|
4310
4767
|
const { createRouter: createRouter } = __routerModule;
|
|
4311
4768
|
const { defineRoute: defineRoute } = __routerModule;
|
|
4312
4769
|
const { route: route } = __routerModule;
|
|
4770
|
+
const { createScheduler: createScheduler } = __schedulerModule;
|
|
4771
|
+
const { applyServerResult: applyServerResult } = __serverModule;
|
|
4313
4772
|
const { createServerProxy: createServerProxy } = __serverModule;
|
|
4314
|
-
const {
|
|
4773
|
+
const { resolveServerCommandArguments: resolveServerCommandArguments } = __serverModule;
|
|
4774
|
+
const { unwrapServerResult: unwrapServerResult } = __serverModule;
|
|
4315
4775
|
const { computed: computed } = __signalsModule;
|
|
4316
4776
|
const { createSignal: createSignal } = __signalsModule;
|
|
4317
4777
|
const { createSignalRegistry: createSignalRegistry } = __signalsModule;
|
|
4318
4778
|
const { effect: effect } = __signalsModule;
|
|
4319
4779
|
const { signal: signal } = __signalsModule;
|
|
4320
4780
|
|
|
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,
|
|
4781
|
+
export { asyncSignal, Async, createApp, defineApp, readSnapshot, attributeName, defineAttributeConfig, 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 };
|