@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
|
@@ -94,7 +94,8 @@ const __asyncSignalModule = (() => {
|
|
|
94
94
|
router: context.router,
|
|
95
95
|
loader: context.loader,
|
|
96
96
|
cache: context.cache,
|
|
97
|
-
abort: activeAbort
|
|
97
|
+
abort: activeAbort,
|
|
98
|
+
scheduler: context.scheduler
|
|
98
99
|
});
|
|
99
100
|
}
|
|
100
101
|
return server;
|
|
@@ -108,6 +109,9 @@ const __asyncSignalModule = (() => {
|
|
|
108
109
|
get cache() {
|
|
109
110
|
return registry._context?.().cache;
|
|
110
111
|
},
|
|
112
|
+
get scheduler() {
|
|
113
|
+
return registry._context?.().scheduler;
|
|
114
|
+
},
|
|
111
115
|
get version() {
|
|
112
116
|
return runVersion;
|
|
113
117
|
},
|
|
@@ -184,11 +188,20 @@ const __asyncSignalModule = (() => {
|
|
|
184
188
|
_bindRegistry(nextRegistry, nextId) {
|
|
185
189
|
registry = nextRegistry;
|
|
186
190
|
registeredId = nextId;
|
|
187
|
-
|
|
191
|
+
const start = () => {
|
|
188
192
|
if (registry === nextRegistry && status === "idle") {
|
|
189
193
|
state.refresh();
|
|
190
194
|
}
|
|
191
|
-
}
|
|
195
|
+
};
|
|
196
|
+
const scheduler = registry._context?.().scheduler;
|
|
197
|
+
if (scheduler) {
|
|
198
|
+
scheduler.enqueue("async", start, {
|
|
199
|
+
scope: registeredId,
|
|
200
|
+
key: `asyncSignal:${registeredId}:initial`
|
|
201
|
+
});
|
|
202
|
+
} else {
|
|
203
|
+
queueMicrotask(start);
|
|
204
|
+
}
|
|
192
205
|
},
|
|
193
206
|
|
|
194
207
|
_dispose() {
|
|
@@ -224,11 +237,26 @@ const __asyncSignalModule = (() => {
|
|
|
224
237
|
for (const dependency of dependencies) {
|
|
225
238
|
const dependencyId = String(dependency).split(".")[0];
|
|
226
239
|
if (dependencyId && dependencyId !== registeredId) {
|
|
227
|
-
dependencyCleanups.add(registry.subscribe(dependency, () =>
|
|
240
|
+
dependencyCleanups.add(registry.subscribe(dependency, () => scheduleRefresh()));
|
|
228
241
|
}
|
|
229
242
|
}
|
|
230
243
|
}
|
|
231
244
|
|
|
245
|
+
function scheduleRefresh() {
|
|
246
|
+
if (activeAbort && !activeAbort.aborted) {
|
|
247
|
+
activeAbort.cancel(new Error(`Async signal "${registeredId}" dependency changed.`));
|
|
248
|
+
}
|
|
249
|
+
const scheduler = registry?._context?.().scheduler;
|
|
250
|
+
if (!scheduler) {
|
|
251
|
+
state.refresh();
|
|
252
|
+
return;
|
|
253
|
+
}
|
|
254
|
+
scheduler.enqueue("async", () => state.refresh(), {
|
|
255
|
+
scope: registeredId,
|
|
256
|
+
key: `asyncSignal:${registeredId}:refresh`
|
|
257
|
+
});
|
|
258
|
+
}
|
|
259
|
+
|
|
232
260
|
function notify() {
|
|
233
261
|
for (const subscriber of [...subscribers]) {
|
|
234
262
|
subscriber(state);
|
|
@@ -865,7 +893,8 @@ const __signalsModule = (() => {
|
|
|
865
893
|
server: registry._context?.().server,
|
|
866
894
|
router: registry._context?.().router,
|
|
867
895
|
loader: registry._context?.().loader,
|
|
868
|
-
cache: registry._context?.().cache
|
|
896
|
+
cache: registry._context?.().cache,
|
|
897
|
+
scheduler: registry._context?.().scheduler
|
|
869
898
|
}));
|
|
870
899
|
});
|
|
871
900
|
}
|
|
@@ -893,6 +922,8 @@ const __signalsModule = (() => {
|
|
|
893
922
|
const registryCleanups = new Map();
|
|
894
923
|
const runtimeContext = {};
|
|
895
924
|
const boundEntries = new Set();
|
|
925
|
+
let subscriptionCounter = 0;
|
|
926
|
+
let effectCounter = 0;
|
|
896
927
|
|
|
897
928
|
const registry = attachRegistryInspection({
|
|
898
929
|
register(id, signalLike) {
|
|
@@ -968,17 +999,21 @@ const __signalsModule = (() => {
|
|
|
968
999
|
return createRef(registry, id);
|
|
969
1000
|
},
|
|
970
1001
|
|
|
971
|
-
subscribe(path, fn) {
|
|
1002
|
+
subscribe(path, fn, options = {}) {
|
|
972
1003
|
if (typeof fn !== "function") {
|
|
973
1004
|
throw new TypeError("subscribe(path, fn) requires a function.");
|
|
974
1005
|
}
|
|
975
1006
|
const parsed = parsePath(path, entries);
|
|
976
1007
|
const entry = requireEntry(entries, parsed.id);
|
|
1008
|
+
const subscriptionId = ++subscriptionCounter;
|
|
977
1009
|
return entry.subscribe(() => {
|
|
978
|
-
fn(registry.get(parsed.path), {
|
|
1010
|
+
scheduleCallback(() => fn(registry.get(parsed.path), {
|
|
979
1011
|
id: parsed.id,
|
|
980
1012
|
path: parsed.path,
|
|
981
1013
|
signal: entry
|
|
1014
|
+
}), {
|
|
1015
|
+
...options,
|
|
1016
|
+
key: options.key ?? `signal:${parsed.path}:${subscriptionId}`
|
|
982
1017
|
});
|
|
983
1018
|
});
|
|
984
1019
|
},
|
|
@@ -996,10 +1031,12 @@ const __signalsModule = (() => {
|
|
|
996
1031
|
return registry.ref(id);
|
|
997
1032
|
},
|
|
998
1033
|
|
|
999
|
-
effect(fn) {
|
|
1034
|
+
effect(fn, options = {}) {
|
|
1000
1035
|
let cleanup;
|
|
1001
1036
|
let dependencyCleanups = [];
|
|
1002
1037
|
let stopped = false;
|
|
1038
|
+
const scheduler = options.scheduler;
|
|
1039
|
+
const effectId = ++effectCounter;
|
|
1003
1040
|
|
|
1004
1041
|
const run = () => {
|
|
1005
1042
|
if (stopped) {
|
|
@@ -1018,10 +1055,22 @@ const __signalsModule = (() => {
|
|
|
1018
1055
|
server: runtimeContext.server,
|
|
1019
1056
|
router: runtimeContext.router,
|
|
1020
1057
|
loader: runtimeContext.loader,
|
|
1021
|
-
cache: runtimeContext.cache
|
|
1058
|
+
cache: runtimeContext.cache,
|
|
1059
|
+
scheduler: runtimeContext.scheduler
|
|
1022
1060
|
}));
|
|
1023
1061
|
cleanup = outcome.value;
|
|
1024
|
-
dependencyCleanups = outcome.dependencies.map((dependency) => registry.subscribe(dependency,
|
|
1062
|
+
dependencyCleanups = outcome.dependencies.map((dependency) => registry.subscribe(dependency, scheduleRun));
|
|
1063
|
+
};
|
|
1064
|
+
|
|
1065
|
+
const scheduleRun = () => {
|
|
1066
|
+
if (!scheduler) {
|
|
1067
|
+
run();
|
|
1068
|
+
return;
|
|
1069
|
+
}
|
|
1070
|
+
scheduler.enqueue(options.phase ?? "effect", run, {
|
|
1071
|
+
scope: options.scope,
|
|
1072
|
+
key: options.key ?? `effect:${effectId}`
|
|
1073
|
+
});
|
|
1025
1074
|
};
|
|
1026
1075
|
|
|
1027
1076
|
run();
|
|
@@ -1098,6 +1147,17 @@ const __signalsModule = (() => {
|
|
|
1098
1147
|
registryCleanups.set(id, cleanup);
|
|
1099
1148
|
}
|
|
1100
1149
|
}
|
|
1150
|
+
|
|
1151
|
+
function scheduleCallback(fn, options = {}) {
|
|
1152
|
+
const scheduler = options.scheduler;
|
|
1153
|
+
if (!scheduler || options.phase === "sync") {
|
|
1154
|
+
return fn();
|
|
1155
|
+
}
|
|
1156
|
+
return scheduler.enqueue(options.phase ?? "effect", fn, {
|
|
1157
|
+
scope: options.scope,
|
|
1158
|
+
key: options.key
|
|
1159
|
+
});
|
|
1160
|
+
}
|
|
1101
1161
|
}
|
|
1102
1162
|
|
|
1103
1163
|
function normalizeSignal(signalLike) {
|
|
@@ -1564,10 +1624,15 @@ const __componentModule = (() => {
|
|
|
1564
1624
|
html,
|
|
1565
1625
|
attach(target) {
|
|
1566
1626
|
for (const hook of attachHooks) {
|
|
1567
|
-
|
|
1568
|
-
|
|
1569
|
-
|
|
1570
|
-
|
|
1627
|
+
runtime.scheduler?.enqueue("lifecycle", () => {
|
|
1628
|
+
const cleanup = hook(target);
|
|
1629
|
+
if (typeof cleanup === "function") {
|
|
1630
|
+
cleanups.push(cleanup);
|
|
1631
|
+
}
|
|
1632
|
+
}, {
|
|
1633
|
+
scope,
|
|
1634
|
+
key: `attach:${attachHooks.indexOf(hook)}`
|
|
1635
|
+
}) ?? runAttachHook(hook, target);
|
|
1571
1636
|
}
|
|
1572
1637
|
},
|
|
1573
1638
|
mount(target) {
|
|
@@ -1575,7 +1640,17 @@ const __componentModule = (() => {
|
|
|
1575
1640
|
},
|
|
1576
1641
|
visible(target, observeVisible) {
|
|
1577
1642
|
for (const hook of visibleHooks) {
|
|
1578
|
-
const cleanup = observeVisible(target,
|
|
1643
|
+
const cleanup = observeVisible(target, () => {
|
|
1644
|
+
runtime.scheduler?.enqueue("lifecycle", () => {
|
|
1645
|
+
const hookCleanup = hook(target);
|
|
1646
|
+
if (typeof hookCleanup === "function") {
|
|
1647
|
+
cleanups.push(hookCleanup);
|
|
1648
|
+
}
|
|
1649
|
+
}, {
|
|
1650
|
+
scope,
|
|
1651
|
+
key: `visible:${visibleHooks.indexOf(hook)}`
|
|
1652
|
+
}) ?? runVisibleHook(hook, target);
|
|
1653
|
+
});
|
|
1579
1654
|
if (typeof cleanup === "function") {
|
|
1580
1655
|
cleanups.push(cleanup);
|
|
1581
1656
|
}
|
|
@@ -1585,6 +1660,7 @@ const __componentModule = (() => {
|
|
|
1585
1660
|
while (destroyHooks.length > 0) {
|
|
1586
1661
|
destroyHooks.pop()?.();
|
|
1587
1662
|
}
|
|
1663
|
+
runtime.scheduler?.markScopeDestroyed(scope);
|
|
1588
1664
|
while (cleanups.length > 0) {
|
|
1589
1665
|
cleanups.pop()?.();
|
|
1590
1666
|
}
|
|
@@ -1593,10 +1669,24 @@ const __componentModule = (() => {
|
|
|
1593
1669
|
}
|
|
1594
1670
|
}
|
|
1595
1671
|
};
|
|
1672
|
+
|
|
1673
|
+
function runAttachHook(hook, target) {
|
|
1674
|
+
const cleanup = hook(target);
|
|
1675
|
+
if (typeof cleanup === "function") {
|
|
1676
|
+
cleanups.push(cleanup);
|
|
1677
|
+
}
|
|
1678
|
+
}
|
|
1679
|
+
|
|
1680
|
+
function runVisibleHook(hook, target) {
|
|
1681
|
+
const cleanup = hook(target);
|
|
1682
|
+
if (typeof cleanup === "function") {
|
|
1683
|
+
cleanups.push(cleanup);
|
|
1684
|
+
}
|
|
1685
|
+
}
|
|
1596
1686
|
}
|
|
1597
1687
|
|
|
1598
1688
|
function createComponentContext({ runtime, scope, cleanups, attachHooks, visibleHooks, destroyHooks, renderScopedTemplate }) {
|
|
1599
|
-
const { signals, handlers, loader, server, router, cache } = runtime;
|
|
1689
|
+
const { signals, handlers, loader, server, router, cache, scheduler } = runtime;
|
|
1600
1690
|
const generatedHandlers = new WeakMap();
|
|
1601
1691
|
let generatedHandlerCounter = 0;
|
|
1602
1692
|
let generatedSignalCounter = 0;
|
|
@@ -1608,6 +1698,7 @@ const __componentModule = (() => {
|
|
|
1608
1698
|
server,
|
|
1609
1699
|
router,
|
|
1610
1700
|
cache,
|
|
1701
|
+
scheduler,
|
|
1611
1702
|
|
|
1612
1703
|
signal(name, initial) {
|
|
1613
1704
|
if (arguments.length === 1) {
|
|
@@ -1652,7 +1743,11 @@ const __componentModule = (() => {
|
|
|
1652
1743
|
},
|
|
1653
1744
|
|
|
1654
1745
|
effect(fn) {
|
|
1655
|
-
const cleanup = signals.effect(() => fn.call(context)
|
|
1746
|
+
const cleanup = signals.effect(() => fn.call(context), {
|
|
1747
|
+
scheduler,
|
|
1748
|
+
phase: "effect",
|
|
1749
|
+
scope
|
|
1750
|
+
});
|
|
1656
1751
|
cleanups.push(cleanup);
|
|
1657
1752
|
return cleanup;
|
|
1658
1753
|
},
|
|
@@ -1774,93 +1869,10 @@ const __componentModule = (() => {
|
|
|
1774
1869
|
})();
|
|
1775
1870
|
|
|
1776
1871
|
const __serverModule = (() => {
|
|
1777
|
-
const { attachRegistryInspection, createRegistryStore } = __registryStoreModule;
|
|
1778
1872
|
const serverEnvelopeKeys = new Set(["value", "signals", "boundary", "html", "redirect", "error"]);
|
|
1779
1873
|
const appliedServerResult = Symbol.for("@async/framework.appliedServerResult");
|
|
1780
1874
|
const appliedServerValues = new WeakSet();
|
|
1781
1875
|
|
|
1782
|
-
function createServerRegistry(initialMap = {}, options = {}) {
|
|
1783
|
-
const registryStore = options.registry ?? createRegistryStore();
|
|
1784
|
-
const type = options.type ?? "server";
|
|
1785
|
-
const entries = registryStore._map(type);
|
|
1786
|
-
const defaults = {};
|
|
1787
|
-
|
|
1788
|
-
const registry = attachRegistryInspection({
|
|
1789
|
-
register(id, fn) {
|
|
1790
|
-
assertServerId(id);
|
|
1791
|
-
if (typeof fn !== "function") {
|
|
1792
|
-
throw new TypeError(`Server function "${id}" must be a function.`);
|
|
1793
|
-
}
|
|
1794
|
-
if (entries.has(id)) {
|
|
1795
|
-
throw new Error(`Server function "${id}" is already registered.`);
|
|
1796
|
-
}
|
|
1797
|
-
entries.set(id, fn);
|
|
1798
|
-
return id;
|
|
1799
|
-
},
|
|
1800
|
-
|
|
1801
|
-
registerMany(map) {
|
|
1802
|
-
for (const [id, fn] of Object.entries(map ?? {})) {
|
|
1803
|
-
registry.register(id, fn);
|
|
1804
|
-
}
|
|
1805
|
-
return registry;
|
|
1806
|
-
},
|
|
1807
|
-
|
|
1808
|
-
unregister(id) {
|
|
1809
|
-
assertServerId(id);
|
|
1810
|
-
return entries.delete(id);
|
|
1811
|
-
},
|
|
1812
|
-
|
|
1813
|
-
resolve(id) {
|
|
1814
|
-
assertServerId(id);
|
|
1815
|
-
return entries.get(id);
|
|
1816
|
-
},
|
|
1817
|
-
|
|
1818
|
-
async run(id, args = [], context = {}) {
|
|
1819
|
-
assertServerId(id);
|
|
1820
|
-
const fn = registry.resolve(id);
|
|
1821
|
-
if (!fn) {
|
|
1822
|
-
throw new Error(`Server function "${id}" is not registered.`);
|
|
1823
|
-
}
|
|
1824
|
-
|
|
1825
|
-
let runContext;
|
|
1826
|
-
const server = createServerNamespace((childId, childArgs, childContext = {}) => {
|
|
1827
|
-
return registry.run(childId, childArgs, { ...runContext, ...childContext });
|
|
1828
|
-
}, {}, () => runContext);
|
|
1829
|
-
|
|
1830
|
-
const mergedContext = {
|
|
1831
|
-
...defaults,
|
|
1832
|
-
...context,
|
|
1833
|
-
cache: defaults.cache ?? context.cache
|
|
1834
|
-
};
|
|
1835
|
-
|
|
1836
|
-
runContext = {
|
|
1837
|
-
...mergedContext,
|
|
1838
|
-
id,
|
|
1839
|
-
args,
|
|
1840
|
-
input: mergedContext.input,
|
|
1841
|
-
signals: createSignalReader(mergedContext.signals),
|
|
1842
|
-
abort: mergedContext.abort,
|
|
1843
|
-
cache: mergedContext.cache,
|
|
1844
|
-
server
|
|
1845
|
-
};
|
|
1846
|
-
|
|
1847
|
-
return fn.call(runContext, ...args);
|
|
1848
|
-
},
|
|
1849
|
-
|
|
1850
|
-
_setContext(context = {}) {
|
|
1851
|
-
Object.assign(defaults, context);
|
|
1852
|
-
return registry;
|
|
1853
|
-
},
|
|
1854
|
-
|
|
1855
|
-
_adoptMany() {
|
|
1856
|
-
return registry;
|
|
1857
|
-
}
|
|
1858
|
-
}, registryStore, type);
|
|
1859
|
-
|
|
1860
|
-
registry.registerMany(initialMap);
|
|
1861
|
-
return createServerNamespace((id, args, context) => registry.run(id, args, context), registry, () => defaults);
|
|
1862
|
-
}
|
|
1863
|
-
|
|
1864
1876
|
function createServerProxy({
|
|
1865
1877
|
endpoint = "/__async/server",
|
|
1866
1878
|
fetch: fetchImpl = globalThis.fetch?.bind(globalThis),
|
|
@@ -1868,13 +1880,14 @@ const __serverModule = (() => {
|
|
|
1868
1880
|
loader,
|
|
1869
1881
|
router,
|
|
1870
1882
|
cache,
|
|
1883
|
+
scheduler,
|
|
1871
1884
|
headers = {}
|
|
1872
1885
|
} = {}) {
|
|
1873
1886
|
if (typeof fetchImpl !== "function") {
|
|
1874
1887
|
throw new TypeError("createServerProxy(...) requires fetch to be available.");
|
|
1875
1888
|
}
|
|
1876
1889
|
|
|
1877
|
-
const defaults = { signals, loader, router, cache };
|
|
1890
|
+
const defaults = { signals, loader, router, cache, scheduler };
|
|
1878
1891
|
|
|
1879
1892
|
async function run(id, args = [], context = {}) {
|
|
1880
1893
|
assertServerId(id);
|
|
@@ -2213,7 +2226,7 @@ const __serverModule = (() => {
|
|
|
2213
2226
|
throw new TypeError("Server function id must be a non-empty string.");
|
|
2214
2227
|
}
|
|
2215
2228
|
}
|
|
2216
|
-
return {
|
|
2229
|
+
return { createServerProxy, resolveServerCommandArguments, applyServerResult, unwrapServerResult, defaultInput, createServerNamespace, createSignalReader, assertServerId };
|
|
2217
2230
|
})();
|
|
2218
2231
|
|
|
2219
2232
|
const __handlersModule = (() => {
|
|
@@ -2416,18 +2429,321 @@ const __handlersModule = (() => {
|
|
|
2416
2429
|
return { createHandlerRegistry, parseHandlerRef, isHandlerToken };
|
|
2417
2430
|
})();
|
|
2418
2431
|
|
|
2432
|
+
const __schedulerModule = (() => {
|
|
2433
|
+
const defaultPhases = ["binding", "lifecycle", "effect", "async", "post"];
|
|
2434
|
+
|
|
2435
|
+
function createScheduler(options = {}) {
|
|
2436
|
+
const phases = [...(options.phases ?? defaultPhases)];
|
|
2437
|
+
const queues = new Map(phases.map((phase) => [phase, []]));
|
|
2438
|
+
const keyedJobs = new Map();
|
|
2439
|
+
const destroyedScopes = new Set();
|
|
2440
|
+
const objectScopeIds = new WeakMap();
|
|
2441
|
+
const onError = typeof options.onError === "function" ? options.onError : undefined;
|
|
2442
|
+
const maxDepth = options.maxDepth ?? 100;
|
|
2443
|
+
const strategy = options.strategy ?? "microtask";
|
|
2444
|
+
let destroyed = false;
|
|
2445
|
+
let flushing = false;
|
|
2446
|
+
let scheduled = false;
|
|
2447
|
+
let batchDepth = 0;
|
|
2448
|
+
let jobCounter = 0;
|
|
2449
|
+
let scopeCounter = 0;
|
|
2450
|
+
|
|
2451
|
+
const api = {
|
|
2452
|
+
strategy,
|
|
2453
|
+
phases,
|
|
2454
|
+
|
|
2455
|
+
batch(fn) {
|
|
2456
|
+
if (typeof fn !== "function") {
|
|
2457
|
+
throw new TypeError("scheduler.batch(fn) requires a function.");
|
|
2458
|
+
}
|
|
2459
|
+
assertActive();
|
|
2460
|
+
batchDepth += 1;
|
|
2461
|
+
let asyncBatch = false;
|
|
2462
|
+
try {
|
|
2463
|
+
const value = fn();
|
|
2464
|
+
if (value && typeof value.then === "function") {
|
|
2465
|
+
asyncBatch = true;
|
|
2466
|
+
return value.finally(() => {
|
|
2467
|
+
batchDepth -= 1;
|
|
2468
|
+
requestFlush();
|
|
2469
|
+
});
|
|
2470
|
+
}
|
|
2471
|
+
return value;
|
|
2472
|
+
} finally {
|
|
2473
|
+
if (!asyncBatch && batchDepth > 0) {
|
|
2474
|
+
batchDepth -= 1;
|
|
2475
|
+
requestFlush();
|
|
2476
|
+
}
|
|
2477
|
+
}
|
|
2478
|
+
},
|
|
2479
|
+
|
|
2480
|
+
enqueue(phase, fn, options = {}) {
|
|
2481
|
+
assertActive();
|
|
2482
|
+
assertPhase(phase);
|
|
2483
|
+
if (typeof fn !== "function") {
|
|
2484
|
+
throw new TypeError("scheduler.enqueue(phase, fn) requires a function.");
|
|
2485
|
+
}
|
|
2486
|
+
const scope = options.scope;
|
|
2487
|
+
if (scope !== undefined && destroyedScopes.has(scope)) {
|
|
2488
|
+
return noop;
|
|
2489
|
+
}
|
|
2490
|
+
|
|
2491
|
+
const dedupeKey = options.key === undefined ? undefined : `${phase}:${scopeKey(scope)}:${String(options.key)}`;
|
|
2492
|
+
if (dedupeKey && keyedJobs.has(dedupeKey)) {
|
|
2493
|
+
return keyedJobs.get(dedupeKey).cancel;
|
|
2494
|
+
}
|
|
2495
|
+
|
|
2496
|
+
const job = {
|
|
2497
|
+
id: ++jobCounter,
|
|
2498
|
+
phase,
|
|
2499
|
+
fn,
|
|
2500
|
+
scope,
|
|
2501
|
+
boundary: options.boundary,
|
|
2502
|
+
key: dedupeKey,
|
|
2503
|
+
canceled: false,
|
|
2504
|
+
cancel() {
|
|
2505
|
+
job.canceled = true;
|
|
2506
|
+
if (job.key) {
|
|
2507
|
+
keyedJobs.delete(job.key);
|
|
2508
|
+
}
|
|
2509
|
+
}
|
|
2510
|
+
};
|
|
2511
|
+
queues.get(phase).push(job);
|
|
2512
|
+
if (job.key) {
|
|
2513
|
+
keyedJobs.set(job.key, job);
|
|
2514
|
+
}
|
|
2515
|
+
requestFlush();
|
|
2516
|
+
return job.cancel;
|
|
2517
|
+
},
|
|
2518
|
+
|
|
2519
|
+
afterFlush(fn, options = {}) {
|
|
2520
|
+
return api.enqueue("post", fn, options);
|
|
2521
|
+
},
|
|
2522
|
+
|
|
2523
|
+
async flush() {
|
|
2524
|
+
assertActive();
|
|
2525
|
+
if (flushing) {
|
|
2526
|
+
return;
|
|
2527
|
+
}
|
|
2528
|
+
scheduled = false;
|
|
2529
|
+
flushing = true;
|
|
2530
|
+
let depth = 0;
|
|
2531
|
+
try {
|
|
2532
|
+
while (hasJobs()) {
|
|
2533
|
+
depth += 1;
|
|
2534
|
+
if (depth > maxDepth) {
|
|
2535
|
+
throw new Error(`Scheduler exceeded maxDepth ${maxDepth}.`);
|
|
2536
|
+
}
|
|
2537
|
+
for (const phase of phases) {
|
|
2538
|
+
await flushPhase(phase);
|
|
2539
|
+
}
|
|
2540
|
+
}
|
|
2541
|
+
} finally {
|
|
2542
|
+
flushing = false;
|
|
2543
|
+
if (hasJobs()) {
|
|
2544
|
+
requestFlush();
|
|
2545
|
+
}
|
|
2546
|
+
}
|
|
2547
|
+
},
|
|
2548
|
+
|
|
2549
|
+
async flushScope(scope) {
|
|
2550
|
+
assertActive();
|
|
2551
|
+
if (flushing) {
|
|
2552
|
+
return;
|
|
2553
|
+
}
|
|
2554
|
+
scheduled = false;
|
|
2555
|
+
flushing = true;
|
|
2556
|
+
let depth = 0;
|
|
2557
|
+
try {
|
|
2558
|
+
while (hasJobsForScope(scope)) {
|
|
2559
|
+
depth += 1;
|
|
2560
|
+
if (depth > maxDepth) {
|
|
2561
|
+
throw new Error(`Scheduler exceeded maxDepth ${maxDepth}.`);
|
|
2562
|
+
}
|
|
2563
|
+
for (const phase of phases) {
|
|
2564
|
+
await flushPhase(phase, scope);
|
|
2565
|
+
}
|
|
2566
|
+
}
|
|
2567
|
+
} finally {
|
|
2568
|
+
flushing = false;
|
|
2569
|
+
if (hasJobs()) {
|
|
2570
|
+
requestFlush();
|
|
2571
|
+
}
|
|
2572
|
+
}
|
|
2573
|
+
},
|
|
2574
|
+
|
|
2575
|
+
cancelScope(scope) {
|
|
2576
|
+
if (scope === undefined) {
|
|
2577
|
+
return api;
|
|
2578
|
+
}
|
|
2579
|
+
for (const queue of queues.values()) {
|
|
2580
|
+
for (const job of queue) {
|
|
2581
|
+
if (job.scope === scope) {
|
|
2582
|
+
job.cancel();
|
|
2583
|
+
}
|
|
2584
|
+
}
|
|
2585
|
+
}
|
|
2586
|
+
return api;
|
|
2587
|
+
},
|
|
2588
|
+
|
|
2589
|
+
markScopeDestroyed(scope) {
|
|
2590
|
+
if (scope !== undefined) {
|
|
2591
|
+
destroyedScopes.add(scope);
|
|
2592
|
+
api.cancelScope(scope);
|
|
2593
|
+
}
|
|
2594
|
+
return api;
|
|
2595
|
+
},
|
|
2596
|
+
|
|
2597
|
+
inspect() {
|
|
2598
|
+
const counts = {};
|
|
2599
|
+
for (const [phase, queue] of queues) {
|
|
2600
|
+
counts[phase] = queue.filter((job) => !job.canceled).length;
|
|
2601
|
+
}
|
|
2602
|
+
return {
|
|
2603
|
+
strategy,
|
|
2604
|
+
phases: [...phases],
|
|
2605
|
+
pending: counts,
|
|
2606
|
+
scopesDestroyed: destroyedScopes.size,
|
|
2607
|
+
flushing,
|
|
2608
|
+
scheduled
|
|
2609
|
+
};
|
|
2610
|
+
},
|
|
2611
|
+
|
|
2612
|
+
destroy() {
|
|
2613
|
+
destroyed = true;
|
|
2614
|
+
for (const queue of queues.values()) {
|
|
2615
|
+
for (const job of queue) {
|
|
2616
|
+
job.cancel();
|
|
2617
|
+
}
|
|
2618
|
+
queue.length = 0;
|
|
2619
|
+
}
|
|
2620
|
+
keyedJobs.clear();
|
|
2621
|
+
destroyedScopes.clear();
|
|
2622
|
+
}
|
|
2623
|
+
};
|
|
2624
|
+
|
|
2625
|
+
return api;
|
|
2626
|
+
|
|
2627
|
+
function requestFlush() {
|
|
2628
|
+
if (strategy === "manual" || destroyed || flushing || batchDepth > 0 || scheduled) {
|
|
2629
|
+
return;
|
|
2630
|
+
}
|
|
2631
|
+
scheduled = true;
|
|
2632
|
+
scheduleMicrotask(() => {
|
|
2633
|
+
if (!destroyed) {
|
|
2634
|
+
void api.flush();
|
|
2635
|
+
}
|
|
2636
|
+
});
|
|
2637
|
+
}
|
|
2638
|
+
|
|
2639
|
+
async function flushPhase(phase, scope) {
|
|
2640
|
+
const queue = queues.get(phase);
|
|
2641
|
+
const remaining = [];
|
|
2642
|
+
const runnable = [];
|
|
2643
|
+
|
|
2644
|
+
for (const job of queue.splice(0)) {
|
|
2645
|
+
if (job.canceled) {
|
|
2646
|
+
continue;
|
|
2647
|
+
}
|
|
2648
|
+
if (scope !== undefined && job.scope !== scope) {
|
|
2649
|
+
remaining.push(job);
|
|
2650
|
+
continue;
|
|
2651
|
+
}
|
|
2652
|
+
runnable.push(job);
|
|
2653
|
+
}
|
|
2654
|
+
|
|
2655
|
+
queue.push(...remaining);
|
|
2656
|
+
|
|
2657
|
+
for (const job of runnable) {
|
|
2658
|
+
if (job.key) {
|
|
2659
|
+
keyedJobs.delete(job.key);
|
|
2660
|
+
}
|
|
2661
|
+
if (job.canceled || (job.scope !== undefined && destroyedScopes.has(job.scope))) {
|
|
2662
|
+
continue;
|
|
2663
|
+
}
|
|
2664
|
+
try {
|
|
2665
|
+
await job.fn();
|
|
2666
|
+
} catch (error) {
|
|
2667
|
+
if (onError) {
|
|
2668
|
+
onError(error, job);
|
|
2669
|
+
} else {
|
|
2670
|
+
throw error;
|
|
2671
|
+
}
|
|
2672
|
+
}
|
|
2673
|
+
}
|
|
2674
|
+
}
|
|
2675
|
+
|
|
2676
|
+
function hasJobs() {
|
|
2677
|
+
for (const queue of queues.values()) {
|
|
2678
|
+
if (queue.some((job) => !job.canceled)) {
|
|
2679
|
+
return true;
|
|
2680
|
+
}
|
|
2681
|
+
}
|
|
2682
|
+
return false;
|
|
2683
|
+
}
|
|
2684
|
+
|
|
2685
|
+
function hasJobsForScope(scope) {
|
|
2686
|
+
for (const queue of queues.values()) {
|
|
2687
|
+
if (queue.some((job) => !job.canceled && job.scope === scope)) {
|
|
2688
|
+
return true;
|
|
2689
|
+
}
|
|
2690
|
+
}
|
|
2691
|
+
return false;
|
|
2692
|
+
}
|
|
2693
|
+
|
|
2694
|
+
function assertActive() {
|
|
2695
|
+
if (destroyed) {
|
|
2696
|
+
throw new Error("Scheduler has been destroyed.");
|
|
2697
|
+
}
|
|
2698
|
+
}
|
|
2699
|
+
|
|
2700
|
+
function assertPhase(phase) {
|
|
2701
|
+
if (!queues.has(phase)) {
|
|
2702
|
+
throw new Error(`Unknown scheduler phase "${phase}".`);
|
|
2703
|
+
}
|
|
2704
|
+
}
|
|
2705
|
+
|
|
2706
|
+
function scopeKey(scope) {
|
|
2707
|
+
if (scope === undefined) {
|
|
2708
|
+
return "global";
|
|
2709
|
+
}
|
|
2710
|
+
if ((typeof scope === "object" && scope !== null) || typeof scope === "function") {
|
|
2711
|
+
if (!objectScopeIds.has(scope)) {
|
|
2712
|
+
objectScopeIds.set(scope, `scope:${++scopeCounter}`);
|
|
2713
|
+
}
|
|
2714
|
+
return objectScopeIds.get(scope);
|
|
2715
|
+
}
|
|
2716
|
+
return String(scope);
|
|
2717
|
+
}
|
|
2718
|
+
}
|
|
2719
|
+
|
|
2720
|
+
function scheduleMicrotask(fn) {
|
|
2721
|
+
if (typeof queueMicrotask === "function") {
|
|
2722
|
+
queueMicrotask(fn);
|
|
2723
|
+
return;
|
|
2724
|
+
}
|
|
2725
|
+
Promise.resolve().then(fn);
|
|
2726
|
+
}
|
|
2727
|
+
|
|
2728
|
+
function noop() {}
|
|
2729
|
+
return { createScheduler };
|
|
2730
|
+
})();
|
|
2731
|
+
|
|
2419
2732
|
const __loaderModule = (() => {
|
|
2420
2733
|
const { renderComponent } = __componentModule;
|
|
2421
2734
|
const { createHandlerRegistry } = __handlersModule;
|
|
2735
|
+
const { createScheduler } = __schedulerModule;
|
|
2422
2736
|
const { createSignalRegistry, isSignalRef } = __signalsModule;
|
|
2423
2737
|
const { matchAttribute, normalizeAttributeConfig, readAttribute } = __attributesModule;
|
|
2424
2738
|
const inlineBindingPrefix = "__async:inline:";
|
|
2425
2739
|
|
|
2426
|
-
function Loader({ root, signals, handlers, server, router, cache, attributes } = {}) {
|
|
2740
|
+
function Loader({ root, signals, handlers, server, router, cache, attributes, scheduler } = {}) {
|
|
2427
2741
|
const documentRef = root?.ownerDocument ?? root ?? globalThis.document;
|
|
2428
2742
|
const rootNode = root ?? documentRef;
|
|
2429
2743
|
const signalRegistry = signals ?? createSignalRegistry();
|
|
2430
2744
|
const handlerRegistry = handlers ?? createHandlerRegistry();
|
|
2745
|
+
const schedulerInstance = scheduler ?? createScheduler();
|
|
2746
|
+
const ownsScheduler = !scheduler;
|
|
2431
2747
|
const attributeConfig = normalizeAttributeConfig(attributes);
|
|
2432
2748
|
const cleanups = new Set();
|
|
2433
2749
|
const eventBindings = new WeakMap();
|
|
@@ -2448,6 +2764,7 @@ const __loaderModule = (() => {
|
|
|
2448
2764
|
server,
|
|
2449
2765
|
router,
|
|
2450
2766
|
cache,
|
|
2767
|
+
scheduler: schedulerInstance,
|
|
2451
2768
|
attributes: attributeConfig,
|
|
2452
2769
|
|
|
2453
2770
|
start() {
|
|
@@ -2487,6 +2804,7 @@ const __loaderModule = (() => {
|
|
|
2487
2804
|
server: api.server,
|
|
2488
2805
|
router: api.router,
|
|
2489
2806
|
cache: api.cache,
|
|
2807
|
+
scheduler: schedulerInstance,
|
|
2490
2808
|
attributes: attributeConfig
|
|
2491
2809
|
});
|
|
2492
2810
|
cleanupChildren(target);
|
|
@@ -2507,6 +2825,9 @@ const __loaderModule = (() => {
|
|
|
2507
2825
|
runCleanup(cleanup);
|
|
2508
2826
|
}
|
|
2509
2827
|
cleanups.clear();
|
|
2828
|
+
if (ownsScheduler) {
|
|
2829
|
+
schedulerInstance.destroy();
|
|
2830
|
+
}
|
|
2510
2831
|
},
|
|
2511
2832
|
|
|
2512
2833
|
_observeVisible(target, fn) {
|
|
@@ -2524,13 +2845,14 @@ const __loaderModule = (() => {
|
|
|
2524
2845
|
}
|
|
2525
2846
|
};
|
|
2526
2847
|
|
|
2527
|
-
signalRegistry._setContext?.({ server: api.server, router: api.router, loader: api, cache: api.cache });
|
|
2848
|
+
signalRegistry._setContext?.({ server: api.server, router: api.router, loader: api, cache: api.cache, scheduler: schedulerInstance });
|
|
2528
2849
|
api.server?._setContext?.({
|
|
2529
2850
|
signals: signalRegistry,
|
|
2530
2851
|
handlers: handlerRegistry,
|
|
2531
2852
|
loader: api,
|
|
2532
2853
|
router: api.router,
|
|
2533
|
-
cache: api.cache
|
|
2854
|
+
cache: api.cache,
|
|
2855
|
+
scheduler: schedulerInstance
|
|
2534
2856
|
});
|
|
2535
2857
|
|
|
2536
2858
|
function bindEventAttributes(scope) {
|
|
@@ -2562,18 +2884,19 @@ const __loaderModule = (() => {
|
|
|
2562
2884
|
|
|
2563
2885
|
const listener = async (event) => {
|
|
2564
2886
|
try {
|
|
2565
|
-
await handlerRegistry.run(ref, {
|
|
2887
|
+
await schedulerInstance.batch(() => handlerRegistry.run(ref, {
|
|
2566
2888
|
signals: signalRegistry,
|
|
2567
2889
|
handlers: handlerRegistry,
|
|
2568
2890
|
loader: api,
|
|
2569
2891
|
server: api.server,
|
|
2570
2892
|
router: api.router,
|
|
2571
2893
|
cache: api.cache,
|
|
2894
|
+
scheduler: schedulerInstance,
|
|
2572
2895
|
event,
|
|
2573
2896
|
element,
|
|
2574
2897
|
el: element,
|
|
2575
2898
|
root: rootNode
|
|
2576
|
-
});
|
|
2899
|
+
}));
|
|
2577
2900
|
} catch (error) {
|
|
2578
2901
|
dispatchAsyncError(element, error);
|
|
2579
2902
|
}
|
|
@@ -2689,7 +3012,12 @@ const __loaderModule = (() => {
|
|
|
2689
3012
|
|
|
2690
3013
|
const read = () => readBinding(path, options);
|
|
2691
3014
|
apply(read());
|
|
2692
|
-
addCleanup(subscribeBinding(path, () =>
|
|
3015
|
+
addCleanup(subscribeBinding(path, () => {
|
|
3016
|
+
schedulerInstance.enqueue("binding", () => apply(read()), {
|
|
3017
|
+
scope: element,
|
|
3018
|
+
key
|
|
3019
|
+
});
|
|
3020
|
+
}), element);
|
|
2693
3021
|
}
|
|
2694
3022
|
|
|
2695
3023
|
function bindValueWriter(element, path) {
|
|
@@ -2750,7 +3078,12 @@ const __loaderModule = (() => {
|
|
|
2750
3078
|
const state = {
|
|
2751
3079
|
id,
|
|
2752
3080
|
templates,
|
|
2753
|
-
cleanup: signalRegistry.subscribe(`${id}.$status`, () =>
|
|
3081
|
+
cleanup: signalRegistry.subscribe(`${id}.$status`, () => {
|
|
3082
|
+
schedulerInstance.enqueue("binding", () => renderBoundary(boundary), {
|
|
3083
|
+
scope: boundary,
|
|
3084
|
+
key: `boundary:${id}`
|
|
3085
|
+
});
|
|
3086
|
+
})
|
|
2754
3087
|
};
|
|
2755
3088
|
boundaryState.set(boundary, state);
|
|
2756
3089
|
addCleanup(state.cleanup, boundary);
|
|
@@ -2790,7 +3123,7 @@ const __loaderModule = (() => {
|
|
|
2790
3123
|
}
|
|
2791
3124
|
mountedElements.add(element);
|
|
2792
3125
|
for (const ref of refs) {
|
|
2793
|
-
runPseudo(element, ref);
|
|
3126
|
+
scheduleLifecycle(element, () => runPseudo(element, ref), `attach:${ref}`);
|
|
2794
3127
|
}
|
|
2795
3128
|
}
|
|
2796
3129
|
|
|
@@ -2803,7 +3136,7 @@ const __loaderModule = (() => {
|
|
|
2803
3136
|
continue;
|
|
2804
3137
|
}
|
|
2805
3138
|
visibleElements.add(element);
|
|
2806
|
-
addCleanup(observeVisible(element, () => runPseudo(element, ref)), element);
|
|
3139
|
+
addCleanup(observeVisible(element, () => scheduleLifecycle(element, () => runPseudo(element, ref), `visible:${ref}`)), element);
|
|
2807
3140
|
}
|
|
2808
3141
|
}
|
|
2809
3142
|
|
|
@@ -2827,6 +3160,7 @@ const __loaderModule = (() => {
|
|
|
2827
3160
|
server: api.server,
|
|
2828
3161
|
router: api.router,
|
|
2829
3162
|
cache: api.cache,
|
|
3163
|
+
scheduler: schedulerInstance,
|
|
2830
3164
|
element,
|
|
2831
3165
|
el: element,
|
|
2832
3166
|
root: rootNode
|
|
@@ -2845,10 +3179,13 @@ const __loaderModule = (() => {
|
|
|
2845
3179
|
const ownerWindow = target.ownerDocument?.defaultView ?? globalThis;
|
|
2846
3180
|
const Observer = ownerWindow.IntersectionObserver ?? globalThis.IntersectionObserver;
|
|
2847
3181
|
if (!Observer) {
|
|
2848
|
-
|
|
3182
|
+
schedulerInstance.enqueue("lifecycle", () => {
|
|
2849
3183
|
if (!destroyed) {
|
|
2850
3184
|
fn(target);
|
|
2851
3185
|
}
|
|
3186
|
+
}, {
|
|
3187
|
+
scope: target,
|
|
3188
|
+
key: "visible:fallback"
|
|
2852
3189
|
});
|
|
2853
3190
|
return () => {};
|
|
2854
3191
|
}
|
|
@@ -2903,6 +3240,7 @@ const __loaderModule = (() => {
|
|
|
2903
3240
|
}
|
|
2904
3241
|
for (const element of elementsIn(node)) {
|
|
2905
3242
|
runScopedCleanups(element);
|
|
3243
|
+
schedulerInstance.markScopeDestroyed(element);
|
|
2906
3244
|
}
|
|
2907
3245
|
}
|
|
2908
3246
|
|
|
@@ -2926,6 +3264,13 @@ const __loaderModule = (() => {
|
|
|
2926
3264
|
}
|
|
2927
3265
|
}
|
|
2928
3266
|
|
|
3267
|
+
function scheduleLifecycle(element, fn, key) {
|
|
3268
|
+
schedulerInstance.enqueue("lifecycle", fn, {
|
|
3269
|
+
scope: element,
|
|
3270
|
+
key
|
|
3271
|
+
});
|
|
3272
|
+
}
|
|
3273
|
+
|
|
2929
3274
|
return api;
|
|
2930
3275
|
}
|
|
2931
3276
|
|
|
@@ -3256,6 +3601,7 @@ const __partialsModule = (() => {
|
|
|
3256
3601
|
const __routerModule = (() => {
|
|
3257
3602
|
const { Loader } = __loaderModule;
|
|
3258
3603
|
const { createHandlerRegistry } = __handlersModule;
|
|
3604
|
+
const { createScheduler } = __schedulerModule;
|
|
3259
3605
|
const { createSignalRegistry } = __signalsModule;
|
|
3260
3606
|
const { applyServerResult } = __serverModule;
|
|
3261
3607
|
const { createRegistryStore } = __registryStoreModule;
|
|
@@ -3376,12 +3722,15 @@ const __routerModule = (() => {
|
|
|
3376
3722
|
partials,
|
|
3377
3723
|
fetch: fetchImpl = globalThis.fetch?.bind(globalThis),
|
|
3378
3724
|
routeEndpoint = "/__async/route",
|
|
3379
|
-
attributes
|
|
3725
|
+
attributes,
|
|
3726
|
+
scheduler
|
|
3380
3727
|
} = {}) {
|
|
3381
3728
|
const documentRef = root?.ownerDocument ?? root ?? globalThis.document;
|
|
3382
3729
|
const rootNode = root ?? documentRef;
|
|
3383
3730
|
const signalRegistry = signals ?? loader?.signals ?? createSignalRegistry();
|
|
3384
3731
|
const handlerRegistry = handlers ?? loader?.handlers ?? createHandlerRegistry();
|
|
3732
|
+
const schedulerInstance = scheduler ?? loader?.scheduler ?? createScheduler();
|
|
3733
|
+
const ownsScheduler = !scheduler && !loader?.scheduler;
|
|
3385
3734
|
const attributeConfig = normalizeAttributeConfig(attributes ?? loader?.attributes);
|
|
3386
3735
|
const loaderInstance =
|
|
3387
3736
|
loader ??
|
|
@@ -3391,6 +3740,7 @@ const __routerModule = (() => {
|
|
|
3391
3740
|
handlers: handlerRegistry,
|
|
3392
3741
|
server,
|
|
3393
3742
|
cache,
|
|
3743
|
+
scheduler: schedulerInstance,
|
|
3394
3744
|
attributes: attributeConfig
|
|
3395
3745
|
});
|
|
3396
3746
|
const ownsLoader = !loader;
|
|
@@ -3410,12 +3760,13 @@ const __routerModule = (() => {
|
|
|
3410
3760
|
server,
|
|
3411
3761
|
cache,
|
|
3412
3762
|
partials,
|
|
3763
|
+
scheduler: schedulerInstance,
|
|
3413
3764
|
attributes: attributeConfig,
|
|
3414
3765
|
|
|
3415
3766
|
start() {
|
|
3416
3767
|
assertActive();
|
|
3417
3768
|
loaderInstance.router = api;
|
|
3418
|
-
signalRegistry._setContext?.({ router: api, loader: loaderInstance, server, cache });
|
|
3769
|
+
signalRegistry._setContext?.({ router: api, loader: loaderInstance, server, cache, scheduler: schedulerInstance });
|
|
3419
3770
|
if (ownsLoader) {
|
|
3420
3771
|
loaderInstance.start();
|
|
3421
3772
|
}
|
|
@@ -3479,6 +3830,9 @@ const __routerModule = (() => {
|
|
|
3479
3830
|
cleanup();
|
|
3480
3831
|
}
|
|
3481
3832
|
cleanups.clear();
|
|
3833
|
+
if (ownsScheduler) {
|
|
3834
|
+
schedulerInstance.destroy();
|
|
3835
|
+
}
|
|
3482
3836
|
}
|
|
3483
3837
|
};
|
|
3484
3838
|
|
|
@@ -3584,13 +3938,16 @@ const __routerModule = (() => {
|
|
|
3584
3938
|
loader: loaderInstance,
|
|
3585
3939
|
router: api,
|
|
3586
3940
|
cache,
|
|
3941
|
+
scheduler: schedulerInstance,
|
|
3587
3942
|
abort: navigation?.abort
|
|
3588
3943
|
});
|
|
3944
|
+
await schedulerInstance.flush();
|
|
3589
3945
|
if (!isActiveNavigation(navigation)) {
|
|
3590
3946
|
return;
|
|
3591
3947
|
}
|
|
3592
3948
|
if (result?.html != null && !result.boundary && !result.redirect) {
|
|
3593
3949
|
loaderInstance.swap(boundary, result.html);
|
|
3950
|
+
await schedulerInstance.flush();
|
|
3594
3951
|
}
|
|
3595
3952
|
if (result?.redirect || options.history === false) {
|
|
3596
3953
|
return;
|
|
@@ -3635,6 +3992,7 @@ const __routerModule = (() => {
|
|
|
3635
3992
|
loader: loaderInstance,
|
|
3636
3993
|
server,
|
|
3637
3994
|
cache,
|
|
3995
|
+
scheduler: schedulerInstance,
|
|
3638
3996
|
abort: navigation?.abort
|
|
3639
3997
|
};
|
|
3640
3998
|
}
|
|
@@ -3821,15 +4179,17 @@ const __appModule = (() => {
|
|
|
3821
4179
|
const { Loader } = __loaderModule;
|
|
3822
4180
|
const { createPartialRegistry } = __partialsModule;
|
|
3823
4181
|
const { createRouteRegistry, createRouter } = __routerModule;
|
|
3824
|
-
const {
|
|
4182
|
+
const { createScheduler } = __schedulerModule;
|
|
4183
|
+
const { createServerNamespace } = __serverModule;
|
|
3825
4184
|
const { createSignal, createSignalRegistry } = __signalsModule;
|
|
3826
4185
|
const { createRegistryStore } = __registryStoreModule;
|
|
3827
4186
|
const { attributeName, normalizeAttributeConfig } = __attributesModule;
|
|
3828
4187
|
const registryTypes = new Set(["signal", "handler", "server", "partial", "route", "component"]);
|
|
3829
4188
|
|
|
3830
|
-
function defineApp(initial) {
|
|
4189
|
+
function defineApp(initial, options = {}) {
|
|
3831
4190
|
const registry = createRegistryStore(undefined, { target: "browser" });
|
|
3832
4191
|
const runtimes = new Set();
|
|
4192
|
+
const createRuntime = options.createRuntime ?? createApp;
|
|
3833
4193
|
|
|
3834
4194
|
const app = {
|
|
3835
4195
|
registry,
|
|
@@ -3848,7 +4208,7 @@ const __appModule = (() => {
|
|
|
3848
4208
|
},
|
|
3849
4209
|
|
|
3850
4210
|
start(options = {}) {
|
|
3851
|
-
const runtime =
|
|
4211
|
+
const runtime = createRuntime(app, options).start();
|
|
3852
4212
|
app.runtime = runtime;
|
|
3853
4213
|
return runtime;
|
|
3854
4214
|
},
|
|
@@ -3873,13 +4233,18 @@ const __appModule = (() => {
|
|
|
3873
4233
|
function createApp(appOrDefinition = Async, options = {}) {
|
|
3874
4234
|
const app = isAppHub(appOrDefinition) ? appOrDefinition : defineApp(appOrDefinition ?? {});
|
|
3875
4235
|
const target = options.target ?? "browser";
|
|
4236
|
+
const scheduler = options.scheduler ?? options.loader?.scheduler ?? createScheduler({
|
|
4237
|
+
strategy: target === "server" ? "manual" : "microtask"
|
|
4238
|
+
});
|
|
4239
|
+
const ownsScheduler = !options.scheduler && !options.loader?.scheduler;
|
|
3876
4240
|
const attributes = normalizeAttributeConfig(options.attributes);
|
|
3877
4241
|
const registry = options.registry ?? app.registry.view({ target });
|
|
3878
4242
|
const signals = options.signals ?? createSignalRegistry(undefined, { registry, type: "signal" });
|
|
3879
4243
|
const handlers = options.handlers ?? createHandlerRegistry(undefined, { registry, type: "handler" });
|
|
3880
4244
|
const serverCache = createCacheRegistry(undefined, { registry, type: "cache.server" });
|
|
3881
4245
|
const browserCache = createCacheRegistry(undefined, { registry, type: "cache.browser" });
|
|
3882
|
-
const
|
|
4246
|
+
const serverFactory = options.serverFactory ?? createServerReferenceRegistry;
|
|
4247
|
+
const server = options.server ?? serverFactory(undefined, { registry, type: "server" });
|
|
3883
4248
|
const partials = options.partials ?? createPartialRegistry(undefined, { registry, type: "partial" });
|
|
3884
4249
|
const routes = options.routes ?? createRouteRegistry(undefined, { registry, type: "route" });
|
|
3885
4250
|
const components = options.components ?? createComponentRegistry(undefined, { registry, type: "component" });
|
|
@@ -3907,6 +4272,7 @@ const __appModule = (() => {
|
|
|
3907
4272
|
},
|
|
3908
4273
|
loader,
|
|
3909
4274
|
router,
|
|
4275
|
+
scheduler,
|
|
3910
4276
|
attributes,
|
|
3911
4277
|
|
|
3912
4278
|
start() {
|
|
@@ -3923,12 +4289,13 @@ const __appModule = (() => {
|
|
|
3923
4289
|
handlers,
|
|
3924
4290
|
server,
|
|
3925
4291
|
cache: browserCache,
|
|
4292
|
+
scheduler,
|
|
3926
4293
|
attributes
|
|
3927
4294
|
});
|
|
3928
4295
|
runtime.loader = loader;
|
|
3929
4296
|
|
|
3930
4297
|
configureServerContext({ cache: browserCache });
|
|
3931
|
-
signals._setContext?.({ server, loader, cache: browserCache });
|
|
4298
|
+
signals._setContext?.({ server, loader, cache: browserCache, scheduler });
|
|
3932
4299
|
|
|
3933
4300
|
loader.start();
|
|
3934
4301
|
|
|
@@ -3944,6 +4311,7 @@ const __appModule = (() => {
|
|
|
3944
4311
|
server,
|
|
3945
4312
|
cache: browserCache,
|
|
3946
4313
|
partials,
|
|
4314
|
+
scheduler,
|
|
3947
4315
|
fetch: options.fetch,
|
|
3948
4316
|
routeEndpoint: options.routeEndpoint,
|
|
3949
4317
|
attributes
|
|
@@ -3955,7 +4323,7 @@ const __appModule = (() => {
|
|
|
3955
4323
|
}
|
|
3956
4324
|
} else {
|
|
3957
4325
|
configureServerContext({ cache: serverCache });
|
|
3958
|
-
signals._setContext?.({ server, cache: serverCache });
|
|
4326
|
+
signals._setContext?.({ server, cache: serverCache, scheduler });
|
|
3959
4327
|
}
|
|
3960
4328
|
|
|
3961
4329
|
return runtime;
|
|
@@ -3969,9 +4337,10 @@ const __appModule = (() => {
|
|
|
3969
4337
|
async render(url) {
|
|
3970
4338
|
assertActive();
|
|
3971
4339
|
configureServerContext({ cache: serverCache });
|
|
3972
|
-
signals._setContext?.({ server, cache: serverCache });
|
|
4340
|
+
signals._setContext?.({ server, cache: serverCache, scheduler });
|
|
3973
4341
|
const matched = routes.match(url);
|
|
3974
4342
|
if (!matched) {
|
|
4343
|
+
await scheduler.flush();
|
|
3975
4344
|
return {
|
|
3976
4345
|
html: renderDocument("", { status: 404, signals, browserCache, boundary: options.boundary ?? "route", attributes }),
|
|
3977
4346
|
status: 404,
|
|
@@ -3991,8 +4360,8 @@ const __appModule = (() => {
|
|
|
3991
4360
|
cache: serverCache,
|
|
3992
4361
|
browserCache,
|
|
3993
4362
|
partials,
|
|
3994
|
-
|
|
3995
|
-
|
|
4363
|
+
scheduler,
|
|
4364
|
+
...currentRequestContext()
|
|
3996
4365
|
})
|
|
3997
4366
|
: { html: "" };
|
|
3998
4367
|
|
|
@@ -4005,6 +4374,8 @@ const __appModule = (() => {
|
|
|
4005
4374
|
browserCache.restore(result.cache.browser);
|
|
4006
4375
|
}
|
|
4007
4376
|
|
|
4377
|
+
await scheduler.flush();
|
|
4378
|
+
|
|
4008
4379
|
const status = result.status ?? 200;
|
|
4009
4380
|
return {
|
|
4010
4381
|
html: renderDocument(result.html, { status, signals, browserCache, boundary: result.boundary ?? options.boundary ?? "route", attributes }),
|
|
@@ -4023,6 +4394,9 @@ const __appModule = (() => {
|
|
|
4023
4394
|
router?.destroy?.();
|
|
4024
4395
|
loader?.destroy?.();
|
|
4025
4396
|
signals.destroy?.();
|
|
4397
|
+
if (ownsScheduler) {
|
|
4398
|
+
scheduler.destroy();
|
|
4399
|
+
}
|
|
4026
4400
|
},
|
|
4027
4401
|
|
|
4028
4402
|
_applyUse(normalized) {
|
|
@@ -4043,11 +4417,23 @@ const __appModule = (() => {
|
|
|
4043
4417
|
loader,
|
|
4044
4418
|
router,
|
|
4045
4419
|
cache,
|
|
4046
|
-
|
|
4047
|
-
|
|
4420
|
+
scheduler,
|
|
4421
|
+
requestContext: options.requestContext,
|
|
4422
|
+
...currentRequestContext()
|
|
4048
4423
|
});
|
|
4049
4424
|
}
|
|
4050
4425
|
|
|
4426
|
+
function currentRequestContext() {
|
|
4427
|
+
const context = readRequestContextLike(options.requestContext);
|
|
4428
|
+
return {
|
|
4429
|
+
requestContext: context,
|
|
4430
|
+
request: context.request ?? options.request,
|
|
4431
|
+
headers: context.headers ?? options.headers,
|
|
4432
|
+
cookies: context.cookies ?? options.cookies,
|
|
4433
|
+
locals: context.locals ?? options.locals
|
|
4434
|
+
};
|
|
4435
|
+
}
|
|
4436
|
+
|
|
4051
4437
|
function assertActive() {
|
|
4052
4438
|
if (destroyed) {
|
|
4053
4439
|
throw new Error("Async app runtime has been destroyed.");
|
|
@@ -4201,6 +4587,77 @@ const __appModule = (() => {
|
|
|
4201
4587
|
}
|
|
4202
4588
|
}
|
|
4203
4589
|
|
|
4590
|
+
function createServerReferenceRegistry(initialMap = {}, options = {}) {
|
|
4591
|
+
const registry = options.registry ?? createRegistryStore();
|
|
4592
|
+
const type = options.type ?? "server";
|
|
4593
|
+
const defaults = {};
|
|
4594
|
+
|
|
4595
|
+
const reference = {
|
|
4596
|
+
registry,
|
|
4597
|
+
|
|
4598
|
+
register(id, value) {
|
|
4599
|
+
registry.register(type, id, value);
|
|
4600
|
+
return id;
|
|
4601
|
+
},
|
|
4602
|
+
|
|
4603
|
+
registerMany(map) {
|
|
4604
|
+
for (const [id, value] of Object.entries(map ?? {})) {
|
|
4605
|
+
reference.register(id, value);
|
|
4606
|
+
}
|
|
4607
|
+
return reference;
|
|
4608
|
+
},
|
|
4609
|
+
|
|
4610
|
+
unregister(id) {
|
|
4611
|
+
return registry.unregister(type, id);
|
|
4612
|
+
},
|
|
4613
|
+
|
|
4614
|
+
resolve() {
|
|
4615
|
+
return undefined;
|
|
4616
|
+
},
|
|
4617
|
+
|
|
4618
|
+
async run(id) {
|
|
4619
|
+
throw new Error(`Server command "${id}" cannot run without a server proxy or server registry.`);
|
|
4620
|
+
},
|
|
4621
|
+
|
|
4622
|
+
keys() {
|
|
4623
|
+
return registry.keys(type);
|
|
4624
|
+
},
|
|
4625
|
+
|
|
4626
|
+
entries() {
|
|
4627
|
+
return registry.entries(type);
|
|
4628
|
+
},
|
|
4629
|
+
|
|
4630
|
+
inspect() {
|
|
4631
|
+
return registry.entries(type);
|
|
4632
|
+
},
|
|
4633
|
+
|
|
4634
|
+
_setContext(context = {}) {
|
|
4635
|
+
Object.assign(defaults, context);
|
|
4636
|
+
return reference;
|
|
4637
|
+
},
|
|
4638
|
+
|
|
4639
|
+
_adoptMany() {
|
|
4640
|
+
return reference;
|
|
4641
|
+
}
|
|
4642
|
+
};
|
|
4643
|
+
|
|
4644
|
+
reference.registerMany(initialMap);
|
|
4645
|
+
return createServerNamespace((id, args, context) => reference.run(id, args, context), reference, () => defaults);
|
|
4646
|
+
}
|
|
4647
|
+
|
|
4648
|
+
function readRequestContextLike(store) {
|
|
4649
|
+
if (!store) {
|
|
4650
|
+
return {};
|
|
4651
|
+
}
|
|
4652
|
+
if (typeof store.get === "function") {
|
|
4653
|
+
return store.get() ?? {};
|
|
4654
|
+
}
|
|
4655
|
+
if (typeof store.getStore === "function") {
|
|
4656
|
+
return store.getStore() ?? {};
|
|
4657
|
+
}
|
|
4658
|
+
return {};
|
|
4659
|
+
}
|
|
4660
|
+
|
|
4204
4661
|
function normalizeEntries(type, entries = {}) {
|
|
4205
4662
|
if (type !== "signal") {
|
|
4206
4663
|
return { ...(entries ?? {}) };
|
|
@@ -4309,12 +4766,15 @@ const { createRouteRegistry: createRouteRegistry } = __routerModule;
|
|
|
4309
4766
|
const { createRouter: createRouter } = __routerModule;
|
|
4310
4767
|
const { defineRoute: defineRoute } = __routerModule;
|
|
4311
4768
|
const { route: route } = __routerModule;
|
|
4769
|
+
const { createScheduler: createScheduler } = __schedulerModule;
|
|
4770
|
+
const { applyServerResult: applyServerResult } = __serverModule;
|
|
4312
4771
|
const { createServerProxy: createServerProxy } = __serverModule;
|
|
4313
|
-
const {
|
|
4772
|
+
const { resolveServerCommandArguments: resolveServerCommandArguments } = __serverModule;
|
|
4773
|
+
const { unwrapServerResult: unwrapServerResult } = __serverModule;
|
|
4314
4774
|
const { computed: computed } = __signalsModule;
|
|
4315
4775
|
const { createSignal: createSignal } = __signalsModule;
|
|
4316
4776
|
const { createSignalRegistry: createSignalRegistry } = __signalsModule;
|
|
4317
4777
|
const { effect: effect } = __signalsModule;
|
|
4318
4778
|
const { signal: signal } = __signalsModule;
|
|
4319
4779
|
|
|
4320
|
-
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,
|
|
4780
|
+
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 };
|