@async/framework 0.8.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 +6 -0
- package/README.md +41 -0
- package/browser.d.ts +50 -0
- package/browser.js +312 -1
- package/browser.min.js +1 -1
- package/browser.ts +312 -1
- package/browser.umd.js +312 -1
- package/browser.umd.min.js +1 -1
- package/package.json +1 -1
- package/server.d.ts +50 -0
- package/src/boundary-receiver.js +302 -0
- package/src/browser.js +1 -0
- package/src/index.js +1 -0
- package/src/scheduler.js +4 -0
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,12 @@
|
|
|
2
2
|
|
|
3
3
|
## Unreleased
|
|
4
4
|
|
|
5
|
+
## 0.9.0 - 2026-06-17
|
|
6
|
+
|
|
7
|
+
- Added `createBoundaryReceiver(...)` for optional out-of-order boundary patch
|
|
8
|
+
delivery with per-boundary sequence checks, signal/cache effect ordering,
|
|
9
|
+
scheduler flushing, redirects, and destroyed parent-scope filtering.
|
|
10
|
+
|
|
5
11
|
## 0.8.0 - 2026-06-17
|
|
6
12
|
|
|
7
13
|
- Split browser and server entrypoints with `@async/framework/browser`,
|
package/README.md
CHANGED
|
@@ -1050,6 +1050,47 @@ loader.swap(
|
|
|
1050
1050
|
`swap(boundaryId, fragmentOrTemplate)` replaces the boundary contents and
|
|
1051
1051
|
rescans the inserted fragment.
|
|
1052
1052
|
|
|
1053
|
+
When boundary patches can arrive independently, use `createBoundaryReceiver`.
|
|
1054
|
+
It keeps per-boundary sequence state, applies signal/cache effects before the
|
|
1055
|
+
HTML swap, flushes scheduled bindings, and ignores stale child patches after a
|
|
1056
|
+
parent scope is destroyed.
|
|
1057
|
+
|
|
1058
|
+
```js
|
|
1059
|
+
import { createBoundaryReceiver } from "@async/framework/browser";
|
|
1060
|
+
|
|
1061
|
+
const receiver = createBoundaryReceiver({
|
|
1062
|
+
loader: runtime.loader,
|
|
1063
|
+
signals: runtime.signals,
|
|
1064
|
+
cache: runtime.browser.cache,
|
|
1065
|
+
scheduler: runtime.scheduler,
|
|
1066
|
+
router: runtime.router
|
|
1067
|
+
});
|
|
1068
|
+
|
|
1069
|
+
await receiver.apply({
|
|
1070
|
+
boundary: "product",
|
|
1071
|
+
seq: 1,
|
|
1072
|
+
signals: {
|
|
1073
|
+
product: { title: "Keyboard" }
|
|
1074
|
+
},
|
|
1075
|
+
cache: {
|
|
1076
|
+
browser: {
|
|
1077
|
+
"product:sku-1": { title: "Keyboard" }
|
|
1078
|
+
}
|
|
1079
|
+
},
|
|
1080
|
+
html: `
|
|
1081
|
+
<article>
|
|
1082
|
+
<h1 signal:text="product.title"></h1>
|
|
1083
|
+
<button type="button" on:click="server.cart.add(productId)">Add</button>
|
|
1084
|
+
</article>
|
|
1085
|
+
`
|
|
1086
|
+
});
|
|
1087
|
+
```
|
|
1088
|
+
|
|
1089
|
+
Sequence numbers are tracked per boundary: `hero` patch `10` can apply before
|
|
1090
|
+
`reviews` patch `2`, while a later `hero` patch `9` is ignored. The receiver
|
|
1091
|
+
does not add transport management, a transaction log, hydration, or component
|
|
1092
|
+
rerendering.
|
|
1093
|
+
|
|
1053
1094
|
## Examples
|
|
1054
1095
|
|
|
1055
1096
|
| Example | Shows |
|
package/browser.d.ts
CHANGED
|
@@ -75,6 +75,7 @@ export interface Scheduler {
|
|
|
75
75
|
afterFlush(job: () => MaybePromise<unknown>, options?: { scope?: unknown; boundary?: string; key?: string }): Cleanup;
|
|
76
76
|
cancelScope(scope: unknown): this;
|
|
77
77
|
markScopeDestroyed(scope: unknown): this;
|
|
78
|
+
isScopeDestroyed(scope: unknown): boolean;
|
|
78
79
|
destroy(): void;
|
|
79
80
|
inspect(): SchedulerInspection;
|
|
80
81
|
}
|
|
@@ -458,6 +459,53 @@ export interface LoaderInstance {
|
|
|
458
459
|
export type AsyncLoaderOptions = LoaderOptions;
|
|
459
460
|
export type AsyncLoaderInstance = LoaderInstance;
|
|
460
461
|
|
|
462
|
+
export interface BoundaryPatch {
|
|
463
|
+
boundary: string;
|
|
464
|
+
seq: number;
|
|
465
|
+
html?: TemplateLike;
|
|
466
|
+
signals?: Record<string, unknown>;
|
|
467
|
+
cache?: { browser?: Record<string, unknown> };
|
|
468
|
+
redirect?: string;
|
|
469
|
+
error?: unknown;
|
|
470
|
+
parentScope?: string;
|
|
471
|
+
scope?: string;
|
|
472
|
+
meta?: Record<string, unknown>;
|
|
473
|
+
}
|
|
474
|
+
|
|
475
|
+
export type BoundaryApplyResult =
|
|
476
|
+
| { status: "applied"; boundary: string; seq: number }
|
|
477
|
+
| { status: "ignored-stale"; boundary: string; seq: number; lastSeq: number }
|
|
478
|
+
| { status: "ignored-destroyed"; boundary: string; seq: number; parentScope?: string }
|
|
479
|
+
| { status: "redirected"; boundary: string; seq: number; redirect: string }
|
|
480
|
+
| { status: "errored"; boundary: string; seq: number; error: Error };
|
|
481
|
+
|
|
482
|
+
export interface BoundaryReceiverInspection {
|
|
483
|
+
destroyed: boolean;
|
|
484
|
+
boundaries: Record<string, { lastSeq: number; applied: number; ignored: number; errored?: number; lastStatus?: BoundaryApplyResult["status"] }>;
|
|
485
|
+
recent: Array<{ boundary: string; seq: number; status: BoundaryApplyResult["status"]; lastSeq?: number; parentScope?: string; redirect?: string }>;
|
|
486
|
+
}
|
|
487
|
+
|
|
488
|
+
export interface BoundaryReceiverOptions {
|
|
489
|
+
loader: LoaderInstance;
|
|
490
|
+
signals?: SignalRegistry;
|
|
491
|
+
cache?: CacheRegistry;
|
|
492
|
+
scheduler?: Scheduler;
|
|
493
|
+
router?: Router;
|
|
494
|
+
onApply?(result: BoundaryApplyResult, patch: BoundaryPatch): void;
|
|
495
|
+
onIgnore?(result: BoundaryApplyResult, patch: BoundaryPatch): void;
|
|
496
|
+
onError?(error: Error, result: BoundaryApplyResult, patch: BoundaryPatch): void;
|
|
497
|
+
throwOnError?: boolean;
|
|
498
|
+
recentLimit?: number;
|
|
499
|
+
isScopeDestroyed?(scope: string): boolean;
|
|
500
|
+
}
|
|
501
|
+
|
|
502
|
+
export interface BoundaryReceiver {
|
|
503
|
+
apply(patch: BoundaryPatch): Promise<BoundaryApplyResult>;
|
|
504
|
+
inspect(): BoundaryReceiverInspection;
|
|
505
|
+
reset(boundary?: string): this;
|
|
506
|
+
destroy(): void;
|
|
507
|
+
}
|
|
508
|
+
|
|
461
509
|
export interface RegistryStore {
|
|
462
510
|
target: RuntimeTarget;
|
|
463
511
|
register(type: RegistryType, id: string, value: unknown): string;
|
|
@@ -568,6 +616,7 @@ export interface AsyncNamespace extends AppHub {
|
|
|
568
616
|
readSnapshot: typeof readSnapshot;
|
|
569
617
|
attributeName: typeof attributeName;
|
|
570
618
|
defineAttributeConfig: typeof defineAttributeConfig;
|
|
619
|
+
createBoundaryReceiver: typeof createBoundaryReceiver;
|
|
571
620
|
createCacheRegistry: typeof createCacheRegistry;
|
|
572
621
|
defineCache: typeof defineCache;
|
|
573
622
|
component: typeof component;
|
|
@@ -603,6 +652,7 @@ export declare function defineApp(initial?: AppDefinition): AppHub;
|
|
|
603
652
|
export declare function readSnapshot(root?: Document | Element, options?: { attributes?: AttributeConfig }): { signals?: Record<string, unknown>; cache?: { browser?: Record<string, unknown> } };
|
|
604
653
|
export declare function attributeName(attributes: AttributeConfig | undefined, type: keyof NormalizedAttributeConfig, name: string): string;
|
|
605
654
|
export declare function defineAttributeConfig(config?: AttributeConfig): NormalizedAttributeConfig;
|
|
655
|
+
export declare function createBoundaryReceiver(options: BoundaryReceiverOptions): BoundaryReceiver;
|
|
606
656
|
export declare function createCacheRegistry(initialMap?: Record<string, CacheDefinition | CacheDefinitionOptions>, options?: { now?: () => number; registry?: RegistryStore; type?: "cache.browser" | "cache.server" }): CacheRegistry;
|
|
607
657
|
export declare function defineCache(options?: CacheDefinitionOptions): CacheDefinition;
|
|
608
658
|
export declare function component<TProps extends Record<string, unknown> = Record<string, unknown>>(fn: ComponentFunction<TProps>): ComponentFunction<TProps>;
|
package/browser.js
CHANGED
|
@@ -2594,6 +2594,10 @@ const __schedulerModule = (() => {
|
|
|
2594
2594
|
return api;
|
|
2595
2595
|
},
|
|
2596
2596
|
|
|
2597
|
+
isScopeDestroyed(scope) {
|
|
2598
|
+
return scope !== undefined && destroyedScopes.has(scope);
|
|
2599
|
+
},
|
|
2600
|
+
|
|
2597
2601
|
inspect() {
|
|
2598
2602
|
const counts = {};
|
|
2599
2603
|
for (const [phase, queue] of queues) {
|
|
@@ -4709,6 +4713,312 @@ const __appModule = (() => {
|
|
|
4709
4713
|
return { defineApp, createApp, readSnapshot, Async };
|
|
4710
4714
|
})();
|
|
4711
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
|
+
|
|
4712
5022
|
const __delayModule = (() => {
|
|
4713
5023
|
function delay(ms, signal) {
|
|
4714
5024
|
if (signal?.aborted) {
|
|
@@ -4750,6 +5060,7 @@ const { defineApp: defineApp } = __appModule;
|
|
|
4750
5060
|
const { readSnapshot: readSnapshot } = __appModule;
|
|
4751
5061
|
const { attributeName: attributeName } = __attributesModule;
|
|
4752
5062
|
const { defineAttributeConfig: defineAttributeConfig } = __attributesModule;
|
|
5063
|
+
const { createBoundaryReceiver: createBoundaryReceiver } = __boundaryReceiverModule;
|
|
4753
5064
|
const { createCacheRegistry: createCacheRegistry } = __cacheModule;
|
|
4754
5065
|
const { defineCache: defineCache } = __cacheModule;
|
|
4755
5066
|
const { component: component } = __componentModule;
|
|
@@ -4777,4 +5088,4 @@ const { createSignalRegistry: createSignalRegistry } = __signalsModule;
|
|
|
4777
5088
|
const { effect: effect } = __signalsModule;
|
|
4778
5089
|
const { signal: signal } = __signalsModule;
|
|
4779
5090
|
|
|
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 };
|
|
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 };
|