@async/framework 0.7.0 → 0.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +22 -0
- package/README.md +122 -14
- package/{framework.d.ts → browser.d.ts} +118 -4
- package/{framework.js → browser.js} +898 -127
- package/browser.min.js +1 -0
- package/{framework.ts → browser.ts} +899 -128
- package/{framework.umd.js → browser.umd.js} +898 -127
- package/browser.umd.min.js +1 -0
- package/package.json +45 -30
- package/server.d.ts +690 -0
- package/src/app.js +110 -11
- package/src/async-signal.js +32 -4
- package/src/boundary-receiver.js +302 -0
- package/src/browser.js +16 -0
- package/src/component.js +42 -7
- package/src/index.js +6 -2
- package/src/loader.js +42 -10
- package/src/request-context.js +40 -0
- package/src/router.js +15 -2
- package/src/scheduler.js +300 -0
- package/src/server-entry.js +20 -0
- package/src/server-registry.js +97 -0
- package/src/server.js +5 -88
- package/src/signals.js +38 -6
- package/framework.min.js +0 -3820
- package/framework.umd.min.js +0 -3843
|
@@ -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,325 @@ 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
|
+
isScopeDestroyed(scope) {
|
|
2598
|
+
return scope !== undefined && destroyedScopes.has(scope);
|
|
2599
|
+
},
|
|
2600
|
+
|
|
2601
|
+
inspect() {
|
|
2602
|
+
const counts = {};
|
|
2603
|
+
for (const [phase, queue] of queues) {
|
|
2604
|
+
counts[phase] = queue.filter((job) => !job.canceled).length;
|
|
2605
|
+
}
|
|
2606
|
+
return {
|
|
2607
|
+
strategy,
|
|
2608
|
+
phases: [...phases],
|
|
2609
|
+
pending: counts,
|
|
2610
|
+
scopesDestroyed: destroyedScopes.size,
|
|
2611
|
+
flushing,
|
|
2612
|
+
scheduled
|
|
2613
|
+
};
|
|
2614
|
+
},
|
|
2615
|
+
|
|
2616
|
+
destroy() {
|
|
2617
|
+
destroyed = true;
|
|
2618
|
+
for (const queue of queues.values()) {
|
|
2619
|
+
for (const job of queue) {
|
|
2620
|
+
job.cancel();
|
|
2621
|
+
}
|
|
2622
|
+
queue.length = 0;
|
|
2623
|
+
}
|
|
2624
|
+
keyedJobs.clear();
|
|
2625
|
+
destroyedScopes.clear();
|
|
2626
|
+
}
|
|
2627
|
+
};
|
|
2628
|
+
|
|
2629
|
+
return api;
|
|
2630
|
+
|
|
2631
|
+
function requestFlush() {
|
|
2632
|
+
if (strategy === "manual" || destroyed || flushing || batchDepth > 0 || scheduled) {
|
|
2633
|
+
return;
|
|
2634
|
+
}
|
|
2635
|
+
scheduled = true;
|
|
2636
|
+
scheduleMicrotask(() => {
|
|
2637
|
+
if (!destroyed) {
|
|
2638
|
+
void api.flush();
|
|
2639
|
+
}
|
|
2640
|
+
});
|
|
2641
|
+
}
|
|
2642
|
+
|
|
2643
|
+
async function flushPhase(phase, scope) {
|
|
2644
|
+
const queue = queues.get(phase);
|
|
2645
|
+
const remaining = [];
|
|
2646
|
+
const runnable = [];
|
|
2647
|
+
|
|
2648
|
+
for (const job of queue.splice(0)) {
|
|
2649
|
+
if (job.canceled) {
|
|
2650
|
+
continue;
|
|
2651
|
+
}
|
|
2652
|
+
if (scope !== undefined && job.scope !== scope) {
|
|
2653
|
+
remaining.push(job);
|
|
2654
|
+
continue;
|
|
2655
|
+
}
|
|
2656
|
+
runnable.push(job);
|
|
2657
|
+
}
|
|
2658
|
+
|
|
2659
|
+
queue.push(...remaining);
|
|
2660
|
+
|
|
2661
|
+
for (const job of runnable) {
|
|
2662
|
+
if (job.key) {
|
|
2663
|
+
keyedJobs.delete(job.key);
|
|
2664
|
+
}
|
|
2665
|
+
if (job.canceled || (job.scope !== undefined && destroyedScopes.has(job.scope))) {
|
|
2666
|
+
continue;
|
|
2667
|
+
}
|
|
2668
|
+
try {
|
|
2669
|
+
await job.fn();
|
|
2670
|
+
} catch (error) {
|
|
2671
|
+
if (onError) {
|
|
2672
|
+
onError(error, job);
|
|
2673
|
+
} else {
|
|
2674
|
+
throw error;
|
|
2675
|
+
}
|
|
2676
|
+
}
|
|
2677
|
+
}
|
|
2678
|
+
}
|
|
2679
|
+
|
|
2680
|
+
function hasJobs() {
|
|
2681
|
+
for (const queue of queues.values()) {
|
|
2682
|
+
if (queue.some((job) => !job.canceled)) {
|
|
2683
|
+
return true;
|
|
2684
|
+
}
|
|
2685
|
+
}
|
|
2686
|
+
return false;
|
|
2687
|
+
}
|
|
2688
|
+
|
|
2689
|
+
function hasJobsForScope(scope) {
|
|
2690
|
+
for (const queue of queues.values()) {
|
|
2691
|
+
if (queue.some((job) => !job.canceled && job.scope === scope)) {
|
|
2692
|
+
return true;
|
|
2693
|
+
}
|
|
2694
|
+
}
|
|
2695
|
+
return false;
|
|
2696
|
+
}
|
|
2697
|
+
|
|
2698
|
+
function assertActive() {
|
|
2699
|
+
if (destroyed) {
|
|
2700
|
+
throw new Error("Scheduler has been destroyed.");
|
|
2701
|
+
}
|
|
2702
|
+
}
|
|
2703
|
+
|
|
2704
|
+
function assertPhase(phase) {
|
|
2705
|
+
if (!queues.has(phase)) {
|
|
2706
|
+
throw new Error(`Unknown scheduler phase "${phase}".`);
|
|
2707
|
+
}
|
|
2708
|
+
}
|
|
2709
|
+
|
|
2710
|
+
function scopeKey(scope) {
|
|
2711
|
+
if (scope === undefined) {
|
|
2712
|
+
return "global";
|
|
2713
|
+
}
|
|
2714
|
+
if ((typeof scope === "object" && scope !== null) || typeof scope === "function") {
|
|
2715
|
+
if (!objectScopeIds.has(scope)) {
|
|
2716
|
+
objectScopeIds.set(scope, `scope:${++scopeCounter}`);
|
|
2717
|
+
}
|
|
2718
|
+
return objectScopeIds.get(scope);
|
|
2719
|
+
}
|
|
2720
|
+
return String(scope);
|
|
2721
|
+
}
|
|
2722
|
+
}
|
|
2723
|
+
|
|
2724
|
+
function scheduleMicrotask(fn) {
|
|
2725
|
+
if (typeof queueMicrotask === "function") {
|
|
2726
|
+
queueMicrotask(fn);
|
|
2727
|
+
return;
|
|
2728
|
+
}
|
|
2729
|
+
Promise.resolve().then(fn);
|
|
2730
|
+
}
|
|
2731
|
+
|
|
2732
|
+
function noop() {}
|
|
2733
|
+
return { createScheduler };
|
|
2734
|
+
})();
|
|
2735
|
+
|
|
2419
2736
|
const __loaderModule = (() => {
|
|
2420
2737
|
const { renderComponent } = __componentModule;
|
|
2421
2738
|
const { createHandlerRegistry } = __handlersModule;
|
|
2739
|
+
const { createScheduler } = __schedulerModule;
|
|
2422
2740
|
const { createSignalRegistry, isSignalRef } = __signalsModule;
|
|
2423
2741
|
const { matchAttribute, normalizeAttributeConfig, readAttribute } = __attributesModule;
|
|
2424
2742
|
const inlineBindingPrefix = "__async:inline:";
|
|
2425
2743
|
|
|
2426
|
-
function Loader({ root, signals, handlers, server, router, cache, attributes } = {}) {
|
|
2744
|
+
function Loader({ root, signals, handlers, server, router, cache, attributes, scheduler } = {}) {
|
|
2427
2745
|
const documentRef = root?.ownerDocument ?? root ?? globalThis.document;
|
|
2428
2746
|
const rootNode = root ?? documentRef;
|
|
2429
2747
|
const signalRegistry = signals ?? createSignalRegistry();
|
|
2430
2748
|
const handlerRegistry = handlers ?? createHandlerRegistry();
|
|
2749
|
+
const schedulerInstance = scheduler ?? createScheduler();
|
|
2750
|
+
const ownsScheduler = !scheduler;
|
|
2431
2751
|
const attributeConfig = normalizeAttributeConfig(attributes);
|
|
2432
2752
|
const cleanups = new Set();
|
|
2433
2753
|
const eventBindings = new WeakMap();
|
|
@@ -2448,6 +2768,7 @@ const __loaderModule = (() => {
|
|
|
2448
2768
|
server,
|
|
2449
2769
|
router,
|
|
2450
2770
|
cache,
|
|
2771
|
+
scheduler: schedulerInstance,
|
|
2451
2772
|
attributes: attributeConfig,
|
|
2452
2773
|
|
|
2453
2774
|
start() {
|
|
@@ -2487,6 +2808,7 @@ const __loaderModule = (() => {
|
|
|
2487
2808
|
server: api.server,
|
|
2488
2809
|
router: api.router,
|
|
2489
2810
|
cache: api.cache,
|
|
2811
|
+
scheduler: schedulerInstance,
|
|
2490
2812
|
attributes: attributeConfig
|
|
2491
2813
|
});
|
|
2492
2814
|
cleanupChildren(target);
|
|
@@ -2507,6 +2829,9 @@ const __loaderModule = (() => {
|
|
|
2507
2829
|
runCleanup(cleanup);
|
|
2508
2830
|
}
|
|
2509
2831
|
cleanups.clear();
|
|
2832
|
+
if (ownsScheduler) {
|
|
2833
|
+
schedulerInstance.destroy();
|
|
2834
|
+
}
|
|
2510
2835
|
},
|
|
2511
2836
|
|
|
2512
2837
|
_observeVisible(target, fn) {
|
|
@@ -2524,13 +2849,14 @@ const __loaderModule = (() => {
|
|
|
2524
2849
|
}
|
|
2525
2850
|
};
|
|
2526
2851
|
|
|
2527
|
-
signalRegistry._setContext?.({ server: api.server, router: api.router, loader: api, cache: api.cache });
|
|
2852
|
+
signalRegistry._setContext?.({ server: api.server, router: api.router, loader: api, cache: api.cache, scheduler: schedulerInstance });
|
|
2528
2853
|
api.server?._setContext?.({
|
|
2529
2854
|
signals: signalRegistry,
|
|
2530
2855
|
handlers: handlerRegistry,
|
|
2531
2856
|
loader: api,
|
|
2532
2857
|
router: api.router,
|
|
2533
|
-
cache: api.cache
|
|
2858
|
+
cache: api.cache,
|
|
2859
|
+
scheduler: schedulerInstance
|
|
2534
2860
|
});
|
|
2535
2861
|
|
|
2536
2862
|
function bindEventAttributes(scope) {
|
|
@@ -2562,18 +2888,19 @@ const __loaderModule = (() => {
|
|
|
2562
2888
|
|
|
2563
2889
|
const listener = async (event) => {
|
|
2564
2890
|
try {
|
|
2565
|
-
await handlerRegistry.run(ref, {
|
|
2891
|
+
await schedulerInstance.batch(() => handlerRegistry.run(ref, {
|
|
2566
2892
|
signals: signalRegistry,
|
|
2567
2893
|
handlers: handlerRegistry,
|
|
2568
2894
|
loader: api,
|
|
2569
2895
|
server: api.server,
|
|
2570
2896
|
router: api.router,
|
|
2571
2897
|
cache: api.cache,
|
|
2898
|
+
scheduler: schedulerInstance,
|
|
2572
2899
|
event,
|
|
2573
2900
|
element,
|
|
2574
2901
|
el: element,
|
|
2575
2902
|
root: rootNode
|
|
2576
|
-
});
|
|
2903
|
+
}));
|
|
2577
2904
|
} catch (error) {
|
|
2578
2905
|
dispatchAsyncError(element, error);
|
|
2579
2906
|
}
|
|
@@ -2689,7 +3016,12 @@ const __loaderModule = (() => {
|
|
|
2689
3016
|
|
|
2690
3017
|
const read = () => readBinding(path, options);
|
|
2691
3018
|
apply(read());
|
|
2692
|
-
addCleanup(subscribeBinding(path, () =>
|
|
3019
|
+
addCleanup(subscribeBinding(path, () => {
|
|
3020
|
+
schedulerInstance.enqueue("binding", () => apply(read()), {
|
|
3021
|
+
scope: element,
|
|
3022
|
+
key
|
|
3023
|
+
});
|
|
3024
|
+
}), element);
|
|
2693
3025
|
}
|
|
2694
3026
|
|
|
2695
3027
|
function bindValueWriter(element, path) {
|
|
@@ -2750,7 +3082,12 @@ const __loaderModule = (() => {
|
|
|
2750
3082
|
const state = {
|
|
2751
3083
|
id,
|
|
2752
3084
|
templates,
|
|
2753
|
-
cleanup: signalRegistry.subscribe(`${id}.$status`, () =>
|
|
3085
|
+
cleanup: signalRegistry.subscribe(`${id}.$status`, () => {
|
|
3086
|
+
schedulerInstance.enqueue("binding", () => renderBoundary(boundary), {
|
|
3087
|
+
scope: boundary,
|
|
3088
|
+
key: `boundary:${id}`
|
|
3089
|
+
});
|
|
3090
|
+
})
|
|
2754
3091
|
};
|
|
2755
3092
|
boundaryState.set(boundary, state);
|
|
2756
3093
|
addCleanup(state.cleanup, boundary);
|
|
@@ -2790,7 +3127,7 @@ const __loaderModule = (() => {
|
|
|
2790
3127
|
}
|
|
2791
3128
|
mountedElements.add(element);
|
|
2792
3129
|
for (const ref of refs) {
|
|
2793
|
-
runPseudo(element, ref);
|
|
3130
|
+
scheduleLifecycle(element, () => runPseudo(element, ref), `attach:${ref}`);
|
|
2794
3131
|
}
|
|
2795
3132
|
}
|
|
2796
3133
|
|
|
@@ -2803,7 +3140,7 @@ const __loaderModule = (() => {
|
|
|
2803
3140
|
continue;
|
|
2804
3141
|
}
|
|
2805
3142
|
visibleElements.add(element);
|
|
2806
|
-
addCleanup(observeVisible(element, () => runPseudo(element, ref)), element);
|
|
3143
|
+
addCleanup(observeVisible(element, () => scheduleLifecycle(element, () => runPseudo(element, ref), `visible:${ref}`)), element);
|
|
2807
3144
|
}
|
|
2808
3145
|
}
|
|
2809
3146
|
|
|
@@ -2827,6 +3164,7 @@ const __loaderModule = (() => {
|
|
|
2827
3164
|
server: api.server,
|
|
2828
3165
|
router: api.router,
|
|
2829
3166
|
cache: api.cache,
|
|
3167
|
+
scheduler: schedulerInstance,
|
|
2830
3168
|
element,
|
|
2831
3169
|
el: element,
|
|
2832
3170
|
root: rootNode
|
|
@@ -2845,10 +3183,13 @@ const __loaderModule = (() => {
|
|
|
2845
3183
|
const ownerWindow = target.ownerDocument?.defaultView ?? globalThis;
|
|
2846
3184
|
const Observer = ownerWindow.IntersectionObserver ?? globalThis.IntersectionObserver;
|
|
2847
3185
|
if (!Observer) {
|
|
2848
|
-
|
|
3186
|
+
schedulerInstance.enqueue("lifecycle", () => {
|
|
2849
3187
|
if (!destroyed) {
|
|
2850
3188
|
fn(target);
|
|
2851
3189
|
}
|
|
3190
|
+
}, {
|
|
3191
|
+
scope: target,
|
|
3192
|
+
key: "visible:fallback"
|
|
2852
3193
|
});
|
|
2853
3194
|
return () => {};
|
|
2854
3195
|
}
|
|
@@ -2903,6 +3244,7 @@ const __loaderModule = (() => {
|
|
|
2903
3244
|
}
|
|
2904
3245
|
for (const element of elementsIn(node)) {
|
|
2905
3246
|
runScopedCleanups(element);
|
|
3247
|
+
schedulerInstance.markScopeDestroyed(element);
|
|
2906
3248
|
}
|
|
2907
3249
|
}
|
|
2908
3250
|
|
|
@@ -2926,6 +3268,13 @@ const __loaderModule = (() => {
|
|
|
2926
3268
|
}
|
|
2927
3269
|
}
|
|
2928
3270
|
|
|
3271
|
+
function scheduleLifecycle(element, fn, key) {
|
|
3272
|
+
schedulerInstance.enqueue("lifecycle", fn, {
|
|
3273
|
+
scope: element,
|
|
3274
|
+
key
|
|
3275
|
+
});
|
|
3276
|
+
}
|
|
3277
|
+
|
|
2929
3278
|
return api;
|
|
2930
3279
|
}
|
|
2931
3280
|
|
|
@@ -3256,6 +3605,7 @@ const __partialsModule = (() => {
|
|
|
3256
3605
|
const __routerModule = (() => {
|
|
3257
3606
|
const { Loader } = __loaderModule;
|
|
3258
3607
|
const { createHandlerRegistry } = __handlersModule;
|
|
3608
|
+
const { createScheduler } = __schedulerModule;
|
|
3259
3609
|
const { createSignalRegistry } = __signalsModule;
|
|
3260
3610
|
const { applyServerResult } = __serverModule;
|
|
3261
3611
|
const { createRegistryStore } = __registryStoreModule;
|
|
@@ -3376,12 +3726,15 @@ const __routerModule = (() => {
|
|
|
3376
3726
|
partials,
|
|
3377
3727
|
fetch: fetchImpl = globalThis.fetch?.bind(globalThis),
|
|
3378
3728
|
routeEndpoint = "/__async/route",
|
|
3379
|
-
attributes
|
|
3729
|
+
attributes,
|
|
3730
|
+
scheduler
|
|
3380
3731
|
} = {}) {
|
|
3381
3732
|
const documentRef = root?.ownerDocument ?? root ?? globalThis.document;
|
|
3382
3733
|
const rootNode = root ?? documentRef;
|
|
3383
3734
|
const signalRegistry = signals ?? loader?.signals ?? createSignalRegistry();
|
|
3384
3735
|
const handlerRegistry = handlers ?? loader?.handlers ?? createHandlerRegistry();
|
|
3736
|
+
const schedulerInstance = scheduler ?? loader?.scheduler ?? createScheduler();
|
|
3737
|
+
const ownsScheduler = !scheduler && !loader?.scheduler;
|
|
3385
3738
|
const attributeConfig = normalizeAttributeConfig(attributes ?? loader?.attributes);
|
|
3386
3739
|
const loaderInstance =
|
|
3387
3740
|
loader ??
|
|
@@ -3391,6 +3744,7 @@ const __routerModule = (() => {
|
|
|
3391
3744
|
handlers: handlerRegistry,
|
|
3392
3745
|
server,
|
|
3393
3746
|
cache,
|
|
3747
|
+
scheduler: schedulerInstance,
|
|
3394
3748
|
attributes: attributeConfig
|
|
3395
3749
|
});
|
|
3396
3750
|
const ownsLoader = !loader;
|
|
@@ -3410,12 +3764,13 @@ const __routerModule = (() => {
|
|
|
3410
3764
|
server,
|
|
3411
3765
|
cache,
|
|
3412
3766
|
partials,
|
|
3767
|
+
scheduler: schedulerInstance,
|
|
3413
3768
|
attributes: attributeConfig,
|
|
3414
3769
|
|
|
3415
3770
|
start() {
|
|
3416
3771
|
assertActive();
|
|
3417
3772
|
loaderInstance.router = api;
|
|
3418
|
-
signalRegistry._setContext?.({ router: api, loader: loaderInstance, server, cache });
|
|
3773
|
+
signalRegistry._setContext?.({ router: api, loader: loaderInstance, server, cache, scheduler: schedulerInstance });
|
|
3419
3774
|
if (ownsLoader) {
|
|
3420
3775
|
loaderInstance.start();
|
|
3421
3776
|
}
|
|
@@ -3479,6 +3834,9 @@ const __routerModule = (() => {
|
|
|
3479
3834
|
cleanup();
|
|
3480
3835
|
}
|
|
3481
3836
|
cleanups.clear();
|
|
3837
|
+
if (ownsScheduler) {
|
|
3838
|
+
schedulerInstance.destroy();
|
|
3839
|
+
}
|
|
3482
3840
|
}
|
|
3483
3841
|
};
|
|
3484
3842
|
|
|
@@ -3584,13 +3942,16 @@ const __routerModule = (() => {
|
|
|
3584
3942
|
loader: loaderInstance,
|
|
3585
3943
|
router: api,
|
|
3586
3944
|
cache,
|
|
3945
|
+
scheduler: schedulerInstance,
|
|
3587
3946
|
abort: navigation?.abort
|
|
3588
3947
|
});
|
|
3948
|
+
await schedulerInstance.flush();
|
|
3589
3949
|
if (!isActiveNavigation(navigation)) {
|
|
3590
3950
|
return;
|
|
3591
3951
|
}
|
|
3592
3952
|
if (result?.html != null && !result.boundary && !result.redirect) {
|
|
3593
3953
|
loaderInstance.swap(boundary, result.html);
|
|
3954
|
+
await schedulerInstance.flush();
|
|
3594
3955
|
}
|
|
3595
3956
|
if (result?.redirect || options.history === false) {
|
|
3596
3957
|
return;
|
|
@@ -3635,6 +3996,7 @@ const __routerModule = (() => {
|
|
|
3635
3996
|
loader: loaderInstance,
|
|
3636
3997
|
server,
|
|
3637
3998
|
cache,
|
|
3999
|
+
scheduler: schedulerInstance,
|
|
3638
4000
|
abort: navigation?.abort
|
|
3639
4001
|
};
|
|
3640
4002
|
}
|
|
@@ -3821,15 +4183,17 @@ const __appModule = (() => {
|
|
|
3821
4183
|
const { Loader } = __loaderModule;
|
|
3822
4184
|
const { createPartialRegistry } = __partialsModule;
|
|
3823
4185
|
const { createRouteRegistry, createRouter } = __routerModule;
|
|
3824
|
-
const {
|
|
4186
|
+
const { createScheduler } = __schedulerModule;
|
|
4187
|
+
const { createServerNamespace } = __serverModule;
|
|
3825
4188
|
const { createSignal, createSignalRegistry } = __signalsModule;
|
|
3826
4189
|
const { createRegistryStore } = __registryStoreModule;
|
|
3827
4190
|
const { attributeName, normalizeAttributeConfig } = __attributesModule;
|
|
3828
4191
|
const registryTypes = new Set(["signal", "handler", "server", "partial", "route", "component"]);
|
|
3829
4192
|
|
|
3830
|
-
function defineApp(initial) {
|
|
4193
|
+
function defineApp(initial, options = {}) {
|
|
3831
4194
|
const registry = createRegistryStore(undefined, { target: "browser" });
|
|
3832
4195
|
const runtimes = new Set();
|
|
4196
|
+
const createRuntime = options.createRuntime ?? createApp;
|
|
3833
4197
|
|
|
3834
4198
|
const app = {
|
|
3835
4199
|
registry,
|
|
@@ -3848,7 +4212,7 @@ const __appModule = (() => {
|
|
|
3848
4212
|
},
|
|
3849
4213
|
|
|
3850
4214
|
start(options = {}) {
|
|
3851
|
-
const runtime =
|
|
4215
|
+
const runtime = createRuntime(app, options).start();
|
|
3852
4216
|
app.runtime = runtime;
|
|
3853
4217
|
return runtime;
|
|
3854
4218
|
},
|
|
@@ -3873,13 +4237,18 @@ const __appModule = (() => {
|
|
|
3873
4237
|
function createApp(appOrDefinition = Async, options = {}) {
|
|
3874
4238
|
const app = isAppHub(appOrDefinition) ? appOrDefinition : defineApp(appOrDefinition ?? {});
|
|
3875
4239
|
const target = options.target ?? "browser";
|
|
4240
|
+
const scheduler = options.scheduler ?? options.loader?.scheduler ?? createScheduler({
|
|
4241
|
+
strategy: target === "server" ? "manual" : "microtask"
|
|
4242
|
+
});
|
|
4243
|
+
const ownsScheduler = !options.scheduler && !options.loader?.scheduler;
|
|
3876
4244
|
const attributes = normalizeAttributeConfig(options.attributes);
|
|
3877
4245
|
const registry = options.registry ?? app.registry.view({ target });
|
|
3878
4246
|
const signals = options.signals ?? createSignalRegistry(undefined, { registry, type: "signal" });
|
|
3879
4247
|
const handlers = options.handlers ?? createHandlerRegistry(undefined, { registry, type: "handler" });
|
|
3880
4248
|
const serverCache = createCacheRegistry(undefined, { registry, type: "cache.server" });
|
|
3881
4249
|
const browserCache = createCacheRegistry(undefined, { registry, type: "cache.browser" });
|
|
3882
|
-
const
|
|
4250
|
+
const serverFactory = options.serverFactory ?? createServerReferenceRegistry;
|
|
4251
|
+
const server = options.server ?? serverFactory(undefined, { registry, type: "server" });
|
|
3883
4252
|
const partials = options.partials ?? createPartialRegistry(undefined, { registry, type: "partial" });
|
|
3884
4253
|
const routes = options.routes ?? createRouteRegistry(undefined, { registry, type: "route" });
|
|
3885
4254
|
const components = options.components ?? createComponentRegistry(undefined, { registry, type: "component" });
|
|
@@ -3907,6 +4276,7 @@ const __appModule = (() => {
|
|
|
3907
4276
|
},
|
|
3908
4277
|
loader,
|
|
3909
4278
|
router,
|
|
4279
|
+
scheduler,
|
|
3910
4280
|
attributes,
|
|
3911
4281
|
|
|
3912
4282
|
start() {
|
|
@@ -3923,12 +4293,13 @@ const __appModule = (() => {
|
|
|
3923
4293
|
handlers,
|
|
3924
4294
|
server,
|
|
3925
4295
|
cache: browserCache,
|
|
4296
|
+
scheduler,
|
|
3926
4297
|
attributes
|
|
3927
4298
|
});
|
|
3928
4299
|
runtime.loader = loader;
|
|
3929
4300
|
|
|
3930
4301
|
configureServerContext({ cache: browserCache });
|
|
3931
|
-
signals._setContext?.({ server, loader, cache: browserCache });
|
|
4302
|
+
signals._setContext?.({ server, loader, cache: browserCache, scheduler });
|
|
3932
4303
|
|
|
3933
4304
|
loader.start();
|
|
3934
4305
|
|
|
@@ -3944,6 +4315,7 @@ const __appModule = (() => {
|
|
|
3944
4315
|
server,
|
|
3945
4316
|
cache: browserCache,
|
|
3946
4317
|
partials,
|
|
4318
|
+
scheduler,
|
|
3947
4319
|
fetch: options.fetch,
|
|
3948
4320
|
routeEndpoint: options.routeEndpoint,
|
|
3949
4321
|
attributes
|
|
@@ -3955,7 +4327,7 @@ const __appModule = (() => {
|
|
|
3955
4327
|
}
|
|
3956
4328
|
} else {
|
|
3957
4329
|
configureServerContext({ cache: serverCache });
|
|
3958
|
-
signals._setContext?.({ server, cache: serverCache });
|
|
4330
|
+
signals._setContext?.({ server, cache: serverCache, scheduler });
|
|
3959
4331
|
}
|
|
3960
4332
|
|
|
3961
4333
|
return runtime;
|
|
@@ -3969,9 +4341,10 @@ const __appModule = (() => {
|
|
|
3969
4341
|
async render(url) {
|
|
3970
4342
|
assertActive();
|
|
3971
4343
|
configureServerContext({ cache: serverCache });
|
|
3972
|
-
signals._setContext?.({ server, cache: serverCache });
|
|
4344
|
+
signals._setContext?.({ server, cache: serverCache, scheduler });
|
|
3973
4345
|
const matched = routes.match(url);
|
|
3974
4346
|
if (!matched) {
|
|
4347
|
+
await scheduler.flush();
|
|
3975
4348
|
return {
|
|
3976
4349
|
html: renderDocument("", { status: 404, signals, browserCache, boundary: options.boundary ?? "route", attributes }),
|
|
3977
4350
|
status: 404,
|
|
@@ -3991,8 +4364,8 @@ const __appModule = (() => {
|
|
|
3991
4364
|
cache: serverCache,
|
|
3992
4365
|
browserCache,
|
|
3993
4366
|
partials,
|
|
3994
|
-
|
|
3995
|
-
|
|
4367
|
+
scheduler,
|
|
4368
|
+
...currentRequestContext()
|
|
3996
4369
|
})
|
|
3997
4370
|
: { html: "" };
|
|
3998
4371
|
|
|
@@ -4005,6 +4378,8 @@ const __appModule = (() => {
|
|
|
4005
4378
|
browserCache.restore(result.cache.browser);
|
|
4006
4379
|
}
|
|
4007
4380
|
|
|
4381
|
+
await scheduler.flush();
|
|
4382
|
+
|
|
4008
4383
|
const status = result.status ?? 200;
|
|
4009
4384
|
return {
|
|
4010
4385
|
html: renderDocument(result.html, { status, signals, browserCache, boundary: result.boundary ?? options.boundary ?? "route", attributes }),
|
|
@@ -4023,6 +4398,9 @@ const __appModule = (() => {
|
|
|
4023
4398
|
router?.destroy?.();
|
|
4024
4399
|
loader?.destroy?.();
|
|
4025
4400
|
signals.destroy?.();
|
|
4401
|
+
if (ownsScheduler) {
|
|
4402
|
+
scheduler.destroy();
|
|
4403
|
+
}
|
|
4026
4404
|
},
|
|
4027
4405
|
|
|
4028
4406
|
_applyUse(normalized) {
|
|
@@ -4043,11 +4421,23 @@ const __appModule = (() => {
|
|
|
4043
4421
|
loader,
|
|
4044
4422
|
router,
|
|
4045
4423
|
cache,
|
|
4046
|
-
|
|
4047
|
-
|
|
4424
|
+
scheduler,
|
|
4425
|
+
requestContext: options.requestContext,
|
|
4426
|
+
...currentRequestContext()
|
|
4048
4427
|
});
|
|
4049
4428
|
}
|
|
4050
4429
|
|
|
4430
|
+
function currentRequestContext() {
|
|
4431
|
+
const context = readRequestContextLike(options.requestContext);
|
|
4432
|
+
return {
|
|
4433
|
+
requestContext: context,
|
|
4434
|
+
request: context.request ?? options.request,
|
|
4435
|
+
headers: context.headers ?? options.headers,
|
|
4436
|
+
cookies: context.cookies ?? options.cookies,
|
|
4437
|
+
locals: context.locals ?? options.locals
|
|
4438
|
+
};
|
|
4439
|
+
}
|
|
4440
|
+
|
|
4051
4441
|
function assertActive() {
|
|
4052
4442
|
if (destroyed) {
|
|
4053
4443
|
throw new Error("Async app runtime has been destroyed.");
|
|
@@ -4201,6 +4591,77 @@ const __appModule = (() => {
|
|
|
4201
4591
|
}
|
|
4202
4592
|
}
|
|
4203
4593
|
|
|
4594
|
+
function createServerReferenceRegistry(initialMap = {}, options = {}) {
|
|
4595
|
+
const registry = options.registry ?? createRegistryStore();
|
|
4596
|
+
const type = options.type ?? "server";
|
|
4597
|
+
const defaults = {};
|
|
4598
|
+
|
|
4599
|
+
const reference = {
|
|
4600
|
+
registry,
|
|
4601
|
+
|
|
4602
|
+
register(id, value) {
|
|
4603
|
+
registry.register(type, id, value);
|
|
4604
|
+
return id;
|
|
4605
|
+
},
|
|
4606
|
+
|
|
4607
|
+
registerMany(map) {
|
|
4608
|
+
for (const [id, value] of Object.entries(map ?? {})) {
|
|
4609
|
+
reference.register(id, value);
|
|
4610
|
+
}
|
|
4611
|
+
return reference;
|
|
4612
|
+
},
|
|
4613
|
+
|
|
4614
|
+
unregister(id) {
|
|
4615
|
+
return registry.unregister(type, id);
|
|
4616
|
+
},
|
|
4617
|
+
|
|
4618
|
+
resolve() {
|
|
4619
|
+
return undefined;
|
|
4620
|
+
},
|
|
4621
|
+
|
|
4622
|
+
async run(id) {
|
|
4623
|
+
throw new Error(`Server command "${id}" cannot run without a server proxy or server registry.`);
|
|
4624
|
+
},
|
|
4625
|
+
|
|
4626
|
+
keys() {
|
|
4627
|
+
return registry.keys(type);
|
|
4628
|
+
},
|
|
4629
|
+
|
|
4630
|
+
entries() {
|
|
4631
|
+
return registry.entries(type);
|
|
4632
|
+
},
|
|
4633
|
+
|
|
4634
|
+
inspect() {
|
|
4635
|
+
return registry.entries(type);
|
|
4636
|
+
},
|
|
4637
|
+
|
|
4638
|
+
_setContext(context = {}) {
|
|
4639
|
+
Object.assign(defaults, context);
|
|
4640
|
+
return reference;
|
|
4641
|
+
},
|
|
4642
|
+
|
|
4643
|
+
_adoptMany() {
|
|
4644
|
+
return reference;
|
|
4645
|
+
}
|
|
4646
|
+
};
|
|
4647
|
+
|
|
4648
|
+
reference.registerMany(initialMap);
|
|
4649
|
+
return createServerNamespace((id, args, context) => reference.run(id, args, context), reference, () => defaults);
|
|
4650
|
+
}
|
|
4651
|
+
|
|
4652
|
+
function readRequestContextLike(store) {
|
|
4653
|
+
if (!store) {
|
|
4654
|
+
return {};
|
|
4655
|
+
}
|
|
4656
|
+
if (typeof store.get === "function") {
|
|
4657
|
+
return store.get() ?? {};
|
|
4658
|
+
}
|
|
4659
|
+
if (typeof store.getStore === "function") {
|
|
4660
|
+
return store.getStore() ?? {};
|
|
4661
|
+
}
|
|
4662
|
+
return {};
|
|
4663
|
+
}
|
|
4664
|
+
|
|
4204
4665
|
function normalizeEntries(type, entries = {}) {
|
|
4205
4666
|
if (type !== "signal") {
|
|
4206
4667
|
return { ...(entries ?? {}) };
|
|
@@ -4252,6 +4713,312 @@ const __appModule = (() => {
|
|
|
4252
4713
|
return { defineApp, createApp, readSnapshot, Async };
|
|
4253
4714
|
})();
|
|
4254
4715
|
|
|
4716
|
+
const __boundaryReceiverModule = (() => {
|
|
4717
|
+
const defaultRecentLimit = 50;
|
|
4718
|
+
|
|
4719
|
+
function createBoundaryReceiver(options = {}) {
|
|
4720
|
+
const loader = options.loader;
|
|
4721
|
+
const signals = options.signals ?? loader?.signals;
|
|
4722
|
+
const cache = options.cache ?? loader?.cache;
|
|
4723
|
+
const scheduler = options.scheduler ?? loader?.scheduler;
|
|
4724
|
+
const router = options.router ?? loader?.router;
|
|
4725
|
+
const recentLimit = options.recentLimit ?? defaultRecentLimit;
|
|
4726
|
+
const throwOnError = options.throwOnError === true;
|
|
4727
|
+
const onApply = typeof options.onApply === "function" ? options.onApply : undefined;
|
|
4728
|
+
const onIgnore = typeof options.onIgnore === "function" ? options.onIgnore : undefined;
|
|
4729
|
+
const onError = typeof options.onError === "function" ? options.onError : undefined;
|
|
4730
|
+
const isScopeDestroyed = typeof options.isScopeDestroyed === "function"
|
|
4731
|
+
? options.isScopeDestroyed
|
|
4732
|
+
: (scope) => scheduler?.isScopeDestroyed?.(scope) ?? scheduler?.inspectDestroyed?.(scope) ?? false;
|
|
4733
|
+
|
|
4734
|
+
if (!loader || typeof loader.swap !== "function") {
|
|
4735
|
+
throw new TypeError("createBoundaryReceiver(...) requires a loader with swap(boundary, html).");
|
|
4736
|
+
}
|
|
4737
|
+
if (!Number.isInteger(recentLimit) || recentLimit < 0) {
|
|
4738
|
+
throw new TypeError("createBoundaryReceiver(...) recentLimit must be a non-negative integer.");
|
|
4739
|
+
}
|
|
4740
|
+
|
|
4741
|
+
const boundaries = new Map();
|
|
4742
|
+
const recent = [];
|
|
4743
|
+
let destroyed = false;
|
|
4744
|
+
|
|
4745
|
+
const receiver = {
|
|
4746
|
+
async apply(patch) {
|
|
4747
|
+
if (destroyed) {
|
|
4748
|
+
throw new Error("Boundary receiver has been destroyed.");
|
|
4749
|
+
}
|
|
4750
|
+
|
|
4751
|
+
const normalized = validatePatch(patch);
|
|
4752
|
+
const record = boundaryRecord(normalized.boundary);
|
|
4753
|
+
if (normalized.seq <= record.lastSeq) {
|
|
4754
|
+
const result = {
|
|
4755
|
+
status: "ignored-stale",
|
|
4756
|
+
boundary: normalized.boundary,
|
|
4757
|
+
seq: normalized.seq,
|
|
4758
|
+
lastSeq: record.lastSeq
|
|
4759
|
+
};
|
|
4760
|
+
record.ignored += 1;
|
|
4761
|
+
record.lastStatus = result.status;
|
|
4762
|
+
remember(result);
|
|
4763
|
+
onIgnore?.(result, patch);
|
|
4764
|
+
return result;
|
|
4765
|
+
}
|
|
4766
|
+
|
|
4767
|
+
if (normalized.parentScope !== undefined && isScopeDestroyed(normalized.parentScope)) {
|
|
4768
|
+
const result = {
|
|
4769
|
+
status: "ignored-destroyed",
|
|
4770
|
+
boundary: normalized.boundary,
|
|
4771
|
+
seq: normalized.seq,
|
|
4772
|
+
parentScope: normalized.parentScope
|
|
4773
|
+
};
|
|
4774
|
+
record.ignored += 1;
|
|
4775
|
+
record.lastStatus = result.status;
|
|
4776
|
+
remember(result);
|
|
4777
|
+
onIgnore?.(result, patch);
|
|
4778
|
+
return result;
|
|
4779
|
+
}
|
|
4780
|
+
|
|
4781
|
+
record.lastSeq = normalized.seq;
|
|
4782
|
+
|
|
4783
|
+
if (Object.hasOwn(normalized, "error")) {
|
|
4784
|
+
const error = toStableError(normalized.error);
|
|
4785
|
+
const result = {
|
|
4786
|
+
status: "errored",
|
|
4787
|
+
boundary: normalized.boundary,
|
|
4788
|
+
seq: normalized.seq,
|
|
4789
|
+
error
|
|
4790
|
+
};
|
|
4791
|
+
record.errored += 1;
|
|
4792
|
+
record.lastStatus = result.status;
|
|
4793
|
+
remember(result);
|
|
4794
|
+
onError?.(error, result, patch);
|
|
4795
|
+
if (throwOnError) {
|
|
4796
|
+
throw error;
|
|
4797
|
+
}
|
|
4798
|
+
return result;
|
|
4799
|
+
}
|
|
4800
|
+
|
|
4801
|
+
if (normalized.signals) {
|
|
4802
|
+
if (!signals || typeof signals.set !== "function") {
|
|
4803
|
+
throw new Error("Boundary patch includes signals, but no signal registry is available.");
|
|
4804
|
+
}
|
|
4805
|
+
for (const [path, value] of Object.entries(normalized.signals)) {
|
|
4806
|
+
signals.set(path, value);
|
|
4807
|
+
}
|
|
4808
|
+
}
|
|
4809
|
+
|
|
4810
|
+
if (normalized.cache?.browser) {
|
|
4811
|
+
if (!cache || typeof cache.restore !== "function") {
|
|
4812
|
+
throw new Error("Boundary patch includes browser cache, but no cache registry is available.");
|
|
4813
|
+
}
|
|
4814
|
+
cache.restore(normalized.cache.browser);
|
|
4815
|
+
}
|
|
4816
|
+
|
|
4817
|
+
if (normalized.html != null) {
|
|
4818
|
+
loader.swap(normalized.boundary, normalized.html);
|
|
4819
|
+
}
|
|
4820
|
+
|
|
4821
|
+
await flushScheduler(scheduler, normalized.scope);
|
|
4822
|
+
|
|
4823
|
+
if (normalized.redirect) {
|
|
4824
|
+
await followRedirect(normalized.redirect, router, loader);
|
|
4825
|
+
const result = {
|
|
4826
|
+
status: "redirected",
|
|
4827
|
+
boundary: normalized.boundary,
|
|
4828
|
+
seq: normalized.seq,
|
|
4829
|
+
redirect: normalized.redirect
|
|
4830
|
+
};
|
|
4831
|
+
record.applied += 1;
|
|
4832
|
+
record.lastStatus = result.status;
|
|
4833
|
+
remember(result);
|
|
4834
|
+
onApply?.(result, patch);
|
|
4835
|
+
return result;
|
|
4836
|
+
}
|
|
4837
|
+
|
|
4838
|
+
const result = {
|
|
4839
|
+
status: "applied",
|
|
4840
|
+
boundary: normalized.boundary,
|
|
4841
|
+
seq: normalized.seq
|
|
4842
|
+
};
|
|
4843
|
+
record.applied += 1;
|
|
4844
|
+
record.lastStatus = result.status;
|
|
4845
|
+
remember(result);
|
|
4846
|
+
onApply?.(result, patch);
|
|
4847
|
+
return result;
|
|
4848
|
+
},
|
|
4849
|
+
|
|
4850
|
+
inspect() {
|
|
4851
|
+
const snapshot = {};
|
|
4852
|
+
for (const [boundary, record] of boundaries) {
|
|
4853
|
+
snapshot[boundary] = {
|
|
4854
|
+
lastSeq: record.lastSeq,
|
|
4855
|
+
applied: record.applied,
|
|
4856
|
+
ignored: record.ignored,
|
|
4857
|
+
lastStatus: record.lastStatus
|
|
4858
|
+
};
|
|
4859
|
+
if (record.errored > 0) {
|
|
4860
|
+
snapshot[boundary].errored = record.errored;
|
|
4861
|
+
}
|
|
4862
|
+
}
|
|
4863
|
+
return {
|
|
4864
|
+
destroyed,
|
|
4865
|
+
boundaries: snapshot,
|
|
4866
|
+
recent: recent.map((entry) => ({ ...entry }))
|
|
4867
|
+
};
|
|
4868
|
+
},
|
|
4869
|
+
|
|
4870
|
+
reset(boundary) {
|
|
4871
|
+
if (boundary === undefined) {
|
|
4872
|
+
boundaries.clear();
|
|
4873
|
+
recent.length = 0;
|
|
4874
|
+
return receiver;
|
|
4875
|
+
}
|
|
4876
|
+
assertBoundary(boundary);
|
|
4877
|
+
boundaries.delete(boundary);
|
|
4878
|
+
for (let index = recent.length - 1; index >= 0; index -= 1) {
|
|
4879
|
+
if (recent[index].boundary === boundary) {
|
|
4880
|
+
recent.splice(index, 1);
|
|
4881
|
+
}
|
|
4882
|
+
}
|
|
4883
|
+
return receiver;
|
|
4884
|
+
},
|
|
4885
|
+
|
|
4886
|
+
destroy() {
|
|
4887
|
+
destroyed = true;
|
|
4888
|
+
boundaries.clear();
|
|
4889
|
+
recent.length = 0;
|
|
4890
|
+
}
|
|
4891
|
+
};
|
|
4892
|
+
|
|
4893
|
+
return receiver;
|
|
4894
|
+
|
|
4895
|
+
function boundaryRecord(boundary) {
|
|
4896
|
+
if (!boundaries.has(boundary)) {
|
|
4897
|
+
boundaries.set(boundary, {
|
|
4898
|
+
lastSeq: -Infinity,
|
|
4899
|
+
applied: 0,
|
|
4900
|
+
ignored: 0,
|
|
4901
|
+
errored: 0,
|
|
4902
|
+
lastStatus: undefined
|
|
4903
|
+
});
|
|
4904
|
+
}
|
|
4905
|
+
return boundaries.get(boundary);
|
|
4906
|
+
}
|
|
4907
|
+
|
|
4908
|
+
function remember(result) {
|
|
4909
|
+
if (recentLimit === 0) {
|
|
4910
|
+
return;
|
|
4911
|
+
}
|
|
4912
|
+
recent.push(toRecentEntry(result));
|
|
4913
|
+
while (recent.length > recentLimit) {
|
|
4914
|
+
recent.shift();
|
|
4915
|
+
}
|
|
4916
|
+
}
|
|
4917
|
+
}
|
|
4918
|
+
|
|
4919
|
+
function validatePatch(patch) {
|
|
4920
|
+
if (!patch || typeof patch !== "object" || Array.isArray(patch)) {
|
|
4921
|
+
throw new TypeError("receiver.apply(patch) requires a boundary patch object.");
|
|
4922
|
+
}
|
|
4923
|
+
|
|
4924
|
+
assertBoundary(patch.boundary);
|
|
4925
|
+
if (typeof patch.seq !== "number" || !Number.isFinite(patch.seq)) {
|
|
4926
|
+
throw new TypeError("Boundary patch seq must be a finite number.");
|
|
4927
|
+
}
|
|
4928
|
+
|
|
4929
|
+
if (patch.signals !== undefined && !isPlainObject(patch.signals)) {
|
|
4930
|
+
throw new TypeError("Boundary patch signals must be an object.");
|
|
4931
|
+
}
|
|
4932
|
+
if (patch.cache !== undefined && !isPlainObject(patch.cache)) {
|
|
4933
|
+
throw new TypeError("Boundary patch cache must be an object.");
|
|
4934
|
+
}
|
|
4935
|
+
if (patch.cache?.browser !== undefined && !isPlainObject(patch.cache.browser)) {
|
|
4936
|
+
throw new TypeError("Boundary patch cache.browser must be an object.");
|
|
4937
|
+
}
|
|
4938
|
+
if (patch.redirect !== undefined && (typeof patch.redirect !== "string" || patch.redirect.length === 0)) {
|
|
4939
|
+
throw new TypeError("Boundary patch redirect must be a non-empty string.");
|
|
4940
|
+
}
|
|
4941
|
+
if (patch.parentScope !== undefined && typeof patch.parentScope !== "string") {
|
|
4942
|
+
throw new TypeError("Boundary patch parentScope must be a string.");
|
|
4943
|
+
}
|
|
4944
|
+
if (patch.scope !== undefined && typeof patch.scope !== "string") {
|
|
4945
|
+
throw new TypeError("Boundary patch scope must be a string.");
|
|
4946
|
+
}
|
|
4947
|
+
|
|
4948
|
+
const hasHtml = Object.hasOwn(patch, "html") && patch.html != null;
|
|
4949
|
+
const hasSignals = patch.signals && Object.keys(patch.signals).length > 0;
|
|
4950
|
+
const hasBrowserCache = patch.cache?.browser && Object.keys(patch.cache.browser).length > 0;
|
|
4951
|
+
const hasRedirect = Boolean(patch.redirect);
|
|
4952
|
+
const hasError = Object.hasOwn(patch, "error");
|
|
4953
|
+
if (!hasHtml && !hasSignals && !hasBrowserCache && !hasRedirect && !hasError) {
|
|
4954
|
+
throw new TypeError("Boundary patch must include html, signals, cache.browser, redirect, or error.");
|
|
4955
|
+
}
|
|
4956
|
+
|
|
4957
|
+
return patch;
|
|
4958
|
+
}
|
|
4959
|
+
|
|
4960
|
+
function assertBoundary(boundary) {
|
|
4961
|
+
if (typeof boundary !== "string" || boundary.length === 0) {
|
|
4962
|
+
throw new TypeError("Boundary patch boundary must be a non-empty string.");
|
|
4963
|
+
}
|
|
4964
|
+
}
|
|
4965
|
+
|
|
4966
|
+
async function flushScheduler(scheduler, scope) {
|
|
4967
|
+
if (!scheduler) {
|
|
4968
|
+
return;
|
|
4969
|
+
}
|
|
4970
|
+
if (scope !== undefined && typeof scheduler.flushScope === "function") {
|
|
4971
|
+
await scheduler.flushScope(scope);
|
|
4972
|
+
return;
|
|
4973
|
+
}
|
|
4974
|
+
if (typeof scheduler.flush === "function") {
|
|
4975
|
+
await scheduler.flush();
|
|
4976
|
+
}
|
|
4977
|
+
}
|
|
4978
|
+
|
|
4979
|
+
async function followRedirect(redirect, router, loader) {
|
|
4980
|
+
if (router && typeof router.navigate === "function") {
|
|
4981
|
+
await router.navigate(redirect);
|
|
4982
|
+
return;
|
|
4983
|
+
}
|
|
4984
|
+
const location = loader?.root?.ownerDocument?.defaultView?.location ?? globalThis.location;
|
|
4985
|
+
location?.assign?.(redirect);
|
|
4986
|
+
}
|
|
4987
|
+
|
|
4988
|
+
function toStableError(value) {
|
|
4989
|
+
if (value instanceof Error) {
|
|
4990
|
+
return value;
|
|
4991
|
+
}
|
|
4992
|
+
if (value && typeof value === "object" && typeof value.message === "string") {
|
|
4993
|
+
return Object.assign(new Error(value.message), value);
|
|
4994
|
+
}
|
|
4995
|
+
return new Error(String(value));
|
|
4996
|
+
}
|
|
4997
|
+
|
|
4998
|
+
function toRecentEntry(result) {
|
|
4999
|
+
const entry = {
|
|
5000
|
+
boundary: result.boundary,
|
|
5001
|
+
seq: result.seq,
|
|
5002
|
+
status: result.status
|
|
5003
|
+
};
|
|
5004
|
+
if (result.status === "ignored-stale") {
|
|
5005
|
+
entry.lastSeq = result.lastSeq;
|
|
5006
|
+
}
|
|
5007
|
+
if (result.status === "ignored-destroyed" && result.parentScope !== undefined) {
|
|
5008
|
+
entry.parentScope = result.parentScope;
|
|
5009
|
+
}
|
|
5010
|
+
if (result.status === "redirected") {
|
|
5011
|
+
entry.redirect = result.redirect;
|
|
5012
|
+
}
|
|
5013
|
+
return entry;
|
|
5014
|
+
}
|
|
5015
|
+
|
|
5016
|
+
function isPlainObject(value) {
|
|
5017
|
+
return Boolean(value && typeof value === "object" && !Array.isArray(value));
|
|
5018
|
+
}
|
|
5019
|
+
return { createBoundaryReceiver };
|
|
5020
|
+
})();
|
|
5021
|
+
|
|
4255
5022
|
const __delayModule = (() => {
|
|
4256
5023
|
function delay(ms, signal) {
|
|
4257
5024
|
if (signal?.aborted) {
|
|
@@ -4293,6 +5060,7 @@ const { defineApp: defineApp } = __appModule;
|
|
|
4293
5060
|
const { readSnapshot: readSnapshot } = __appModule;
|
|
4294
5061
|
const { attributeName: attributeName } = __attributesModule;
|
|
4295
5062
|
const { defineAttributeConfig: defineAttributeConfig } = __attributesModule;
|
|
5063
|
+
const { createBoundaryReceiver: createBoundaryReceiver } = __boundaryReceiverModule;
|
|
4296
5064
|
const { createCacheRegistry: createCacheRegistry } = __cacheModule;
|
|
4297
5065
|
const { defineCache: defineCache } = __cacheModule;
|
|
4298
5066
|
const { component: component } = __componentModule;
|
|
@@ -4309,12 +5077,15 @@ const { createRouteRegistry: createRouteRegistry } = __routerModule;
|
|
|
4309
5077
|
const { createRouter: createRouter } = __routerModule;
|
|
4310
5078
|
const { defineRoute: defineRoute } = __routerModule;
|
|
4311
5079
|
const { route: route } = __routerModule;
|
|
5080
|
+
const { createScheduler: createScheduler } = __schedulerModule;
|
|
5081
|
+
const { applyServerResult: applyServerResult } = __serverModule;
|
|
4312
5082
|
const { createServerProxy: createServerProxy } = __serverModule;
|
|
4313
|
-
const {
|
|
5083
|
+
const { resolveServerCommandArguments: resolveServerCommandArguments } = __serverModule;
|
|
5084
|
+
const { unwrapServerResult: unwrapServerResult } = __serverModule;
|
|
4314
5085
|
const { computed: computed } = __signalsModule;
|
|
4315
5086
|
const { createSignal: createSignal } = __signalsModule;
|
|
4316
5087
|
const { createSignalRegistry: createSignalRegistry } = __signalsModule;
|
|
4317
5088
|
const { effect: effect } = __signalsModule;
|
|
4318
5089
|
const { signal: signal } = __signalsModule;
|
|
4319
5090
|
|
|
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,
|
|
5091
|
+
export { asyncSignal, Async, createApp, defineApp, readSnapshot, attributeName, defineAttributeConfig, createBoundaryReceiver, createCacheRegistry, defineCache, component, createComponentRegistry, defineComponent, delay, createHandlerRegistry, html, Loader, AsyncLoader, createPartialRegistry, createRegistryStore, createRouteRegistry, createRouter, defineRoute, route, createScheduler, applyServerResult, createServerProxy, resolveServerCommandArguments, unwrapServerResult, computed, createSignal, createSignalRegistry, effect, signal };
|