@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/browser.ts CHANGED
@@ -2595,6 +2595,10 @@ const __schedulerModule = (() => {
2595
2595
  return api;
2596
2596
  },
2597
2597
 
2598
+ isScopeDestroyed(scope) {
2599
+ return scope !== undefined && destroyedScopes.has(scope);
2600
+ },
2601
+
2598
2602
  inspect() {
2599
2603
  const counts = {};
2600
2604
  for (const [phase, queue] of queues) {
@@ -4710,6 +4714,312 @@ const __appModule = (() => {
4710
4714
  return { defineApp, createApp, readSnapshot, Async };
4711
4715
  })();
4712
4716
 
4717
+ const __boundaryReceiverModule = (() => {
4718
+ const defaultRecentLimit = 50;
4719
+
4720
+ function createBoundaryReceiver(options = {}) {
4721
+ const loader = options.loader;
4722
+ const signals = options.signals ?? loader?.signals;
4723
+ const cache = options.cache ?? loader?.cache;
4724
+ const scheduler = options.scheduler ?? loader?.scheduler;
4725
+ const router = options.router ?? loader?.router;
4726
+ const recentLimit = options.recentLimit ?? defaultRecentLimit;
4727
+ const throwOnError = options.throwOnError === true;
4728
+ const onApply = typeof options.onApply === "function" ? options.onApply : undefined;
4729
+ const onIgnore = typeof options.onIgnore === "function" ? options.onIgnore : undefined;
4730
+ const onError = typeof options.onError === "function" ? options.onError : undefined;
4731
+ const isScopeDestroyed = typeof options.isScopeDestroyed === "function"
4732
+ ? options.isScopeDestroyed
4733
+ : (scope) => scheduler?.isScopeDestroyed?.(scope) ?? scheduler?.inspectDestroyed?.(scope) ?? false;
4734
+
4735
+ if (!loader || typeof loader.swap !== "function") {
4736
+ throw new TypeError("createBoundaryReceiver(...) requires a loader with swap(boundary, html).");
4737
+ }
4738
+ if (!Number.isInteger(recentLimit) || recentLimit < 0) {
4739
+ throw new TypeError("createBoundaryReceiver(...) recentLimit must be a non-negative integer.");
4740
+ }
4741
+
4742
+ const boundaries = new Map();
4743
+ const recent = [];
4744
+ let destroyed = false;
4745
+
4746
+ const receiver = {
4747
+ async apply(patch) {
4748
+ if (destroyed) {
4749
+ throw new Error("Boundary receiver has been destroyed.");
4750
+ }
4751
+
4752
+ const normalized = validatePatch(patch);
4753
+ const record = boundaryRecord(normalized.boundary);
4754
+ if (normalized.seq <= record.lastSeq) {
4755
+ const result = {
4756
+ status: "ignored-stale",
4757
+ boundary: normalized.boundary,
4758
+ seq: normalized.seq,
4759
+ lastSeq: record.lastSeq
4760
+ };
4761
+ record.ignored += 1;
4762
+ record.lastStatus = result.status;
4763
+ remember(result);
4764
+ onIgnore?.(result, patch);
4765
+ return result;
4766
+ }
4767
+
4768
+ if (normalized.parentScope !== undefined && isScopeDestroyed(normalized.parentScope)) {
4769
+ const result = {
4770
+ status: "ignored-destroyed",
4771
+ boundary: normalized.boundary,
4772
+ seq: normalized.seq,
4773
+ parentScope: normalized.parentScope
4774
+ };
4775
+ record.ignored += 1;
4776
+ record.lastStatus = result.status;
4777
+ remember(result);
4778
+ onIgnore?.(result, patch);
4779
+ return result;
4780
+ }
4781
+
4782
+ record.lastSeq = normalized.seq;
4783
+
4784
+ if (Object.hasOwn(normalized, "error")) {
4785
+ const error = toStableError(normalized.error);
4786
+ const result = {
4787
+ status: "errored",
4788
+ boundary: normalized.boundary,
4789
+ seq: normalized.seq,
4790
+ error
4791
+ };
4792
+ record.errored += 1;
4793
+ record.lastStatus = result.status;
4794
+ remember(result);
4795
+ onError?.(error, result, patch);
4796
+ if (throwOnError) {
4797
+ throw error;
4798
+ }
4799
+ return result;
4800
+ }
4801
+
4802
+ if (normalized.signals) {
4803
+ if (!signals || typeof signals.set !== "function") {
4804
+ throw new Error("Boundary patch includes signals, but no signal registry is available.");
4805
+ }
4806
+ for (const [path, value] of Object.entries(normalized.signals)) {
4807
+ signals.set(path, value);
4808
+ }
4809
+ }
4810
+
4811
+ if (normalized.cache?.browser) {
4812
+ if (!cache || typeof cache.restore !== "function") {
4813
+ throw new Error("Boundary patch includes browser cache, but no cache registry is available.");
4814
+ }
4815
+ cache.restore(normalized.cache.browser);
4816
+ }
4817
+
4818
+ if (normalized.html != null) {
4819
+ loader.swap(normalized.boundary, normalized.html);
4820
+ }
4821
+
4822
+ await flushScheduler(scheduler, normalized.scope);
4823
+
4824
+ if (normalized.redirect) {
4825
+ await followRedirect(normalized.redirect, router, loader);
4826
+ const result = {
4827
+ status: "redirected",
4828
+ boundary: normalized.boundary,
4829
+ seq: normalized.seq,
4830
+ redirect: normalized.redirect
4831
+ };
4832
+ record.applied += 1;
4833
+ record.lastStatus = result.status;
4834
+ remember(result);
4835
+ onApply?.(result, patch);
4836
+ return result;
4837
+ }
4838
+
4839
+ const result = {
4840
+ status: "applied",
4841
+ boundary: normalized.boundary,
4842
+ seq: normalized.seq
4843
+ };
4844
+ record.applied += 1;
4845
+ record.lastStatus = result.status;
4846
+ remember(result);
4847
+ onApply?.(result, patch);
4848
+ return result;
4849
+ },
4850
+
4851
+ inspect() {
4852
+ const snapshot = {};
4853
+ for (const [boundary, record] of boundaries) {
4854
+ snapshot[boundary] = {
4855
+ lastSeq: record.lastSeq,
4856
+ applied: record.applied,
4857
+ ignored: record.ignored,
4858
+ lastStatus: record.lastStatus
4859
+ };
4860
+ if (record.errored > 0) {
4861
+ snapshot[boundary].errored = record.errored;
4862
+ }
4863
+ }
4864
+ return {
4865
+ destroyed,
4866
+ boundaries: snapshot,
4867
+ recent: recent.map((entry) => ({ ...entry }))
4868
+ };
4869
+ },
4870
+
4871
+ reset(boundary) {
4872
+ if (boundary === undefined) {
4873
+ boundaries.clear();
4874
+ recent.length = 0;
4875
+ return receiver;
4876
+ }
4877
+ assertBoundary(boundary);
4878
+ boundaries.delete(boundary);
4879
+ for (let index = recent.length - 1; index >= 0; index -= 1) {
4880
+ if (recent[index].boundary === boundary) {
4881
+ recent.splice(index, 1);
4882
+ }
4883
+ }
4884
+ return receiver;
4885
+ },
4886
+
4887
+ destroy() {
4888
+ destroyed = true;
4889
+ boundaries.clear();
4890
+ recent.length = 0;
4891
+ }
4892
+ };
4893
+
4894
+ return receiver;
4895
+
4896
+ function boundaryRecord(boundary) {
4897
+ if (!boundaries.has(boundary)) {
4898
+ boundaries.set(boundary, {
4899
+ lastSeq: -Infinity,
4900
+ applied: 0,
4901
+ ignored: 0,
4902
+ errored: 0,
4903
+ lastStatus: undefined
4904
+ });
4905
+ }
4906
+ return boundaries.get(boundary);
4907
+ }
4908
+
4909
+ function remember(result) {
4910
+ if (recentLimit === 0) {
4911
+ return;
4912
+ }
4913
+ recent.push(toRecentEntry(result));
4914
+ while (recent.length > recentLimit) {
4915
+ recent.shift();
4916
+ }
4917
+ }
4918
+ }
4919
+
4920
+ function validatePatch(patch) {
4921
+ if (!patch || typeof patch !== "object" || Array.isArray(patch)) {
4922
+ throw new TypeError("receiver.apply(patch) requires a boundary patch object.");
4923
+ }
4924
+
4925
+ assertBoundary(patch.boundary);
4926
+ if (typeof patch.seq !== "number" || !Number.isFinite(patch.seq)) {
4927
+ throw new TypeError("Boundary patch seq must be a finite number.");
4928
+ }
4929
+
4930
+ if (patch.signals !== undefined && !isPlainObject(patch.signals)) {
4931
+ throw new TypeError("Boundary patch signals must be an object.");
4932
+ }
4933
+ if (patch.cache !== undefined && !isPlainObject(patch.cache)) {
4934
+ throw new TypeError("Boundary patch cache must be an object.");
4935
+ }
4936
+ if (patch.cache?.browser !== undefined && !isPlainObject(patch.cache.browser)) {
4937
+ throw new TypeError("Boundary patch cache.browser must be an object.");
4938
+ }
4939
+ if (patch.redirect !== undefined && (typeof patch.redirect !== "string" || patch.redirect.length === 0)) {
4940
+ throw new TypeError("Boundary patch redirect must be a non-empty string.");
4941
+ }
4942
+ if (patch.parentScope !== undefined && typeof patch.parentScope !== "string") {
4943
+ throw new TypeError("Boundary patch parentScope must be a string.");
4944
+ }
4945
+ if (patch.scope !== undefined && typeof patch.scope !== "string") {
4946
+ throw new TypeError("Boundary patch scope must be a string.");
4947
+ }
4948
+
4949
+ const hasHtml = Object.hasOwn(patch, "html") && patch.html != null;
4950
+ const hasSignals = patch.signals && Object.keys(patch.signals).length > 0;
4951
+ const hasBrowserCache = patch.cache?.browser && Object.keys(patch.cache.browser).length > 0;
4952
+ const hasRedirect = Boolean(patch.redirect);
4953
+ const hasError = Object.hasOwn(patch, "error");
4954
+ if (!hasHtml && !hasSignals && !hasBrowserCache && !hasRedirect && !hasError) {
4955
+ throw new TypeError("Boundary patch must include html, signals, cache.browser, redirect, or error.");
4956
+ }
4957
+
4958
+ return patch;
4959
+ }
4960
+
4961
+ function assertBoundary(boundary) {
4962
+ if (typeof boundary !== "string" || boundary.length === 0) {
4963
+ throw new TypeError("Boundary patch boundary must be a non-empty string.");
4964
+ }
4965
+ }
4966
+
4967
+ async function flushScheduler(scheduler, scope) {
4968
+ if (!scheduler) {
4969
+ return;
4970
+ }
4971
+ if (scope !== undefined && typeof scheduler.flushScope === "function") {
4972
+ await scheduler.flushScope(scope);
4973
+ return;
4974
+ }
4975
+ if (typeof scheduler.flush === "function") {
4976
+ await scheduler.flush();
4977
+ }
4978
+ }
4979
+
4980
+ async function followRedirect(redirect, router, loader) {
4981
+ if (router && typeof router.navigate === "function") {
4982
+ await router.navigate(redirect);
4983
+ return;
4984
+ }
4985
+ const location = loader?.root?.ownerDocument?.defaultView?.location ?? globalThis.location;
4986
+ location?.assign?.(redirect);
4987
+ }
4988
+
4989
+ function toStableError(value) {
4990
+ if (value instanceof Error) {
4991
+ return value;
4992
+ }
4993
+ if (value && typeof value === "object" && typeof value.message === "string") {
4994
+ return Object.assign(new Error(value.message), value);
4995
+ }
4996
+ return new Error(String(value));
4997
+ }
4998
+
4999
+ function toRecentEntry(result) {
5000
+ const entry = {
5001
+ boundary: result.boundary,
5002
+ seq: result.seq,
5003
+ status: result.status
5004
+ };
5005
+ if (result.status === "ignored-stale") {
5006
+ entry.lastSeq = result.lastSeq;
5007
+ }
5008
+ if (result.status === "ignored-destroyed" && result.parentScope !== undefined) {
5009
+ entry.parentScope = result.parentScope;
5010
+ }
5011
+ if (result.status === "redirected") {
5012
+ entry.redirect = result.redirect;
5013
+ }
5014
+ return entry;
5015
+ }
5016
+
5017
+ function isPlainObject(value) {
5018
+ return Boolean(value && typeof value === "object" && !Array.isArray(value));
5019
+ }
5020
+ return { createBoundaryReceiver };
5021
+ })();
5022
+
4713
5023
  const __delayModule = (() => {
4714
5024
  function delay(ms, signal) {
4715
5025
  if (signal?.aborted) {
@@ -4751,6 +5061,7 @@ const { defineApp: defineApp } = __appModule;
4751
5061
  const { readSnapshot: readSnapshot } = __appModule;
4752
5062
  const { attributeName: attributeName } = __attributesModule;
4753
5063
  const { defineAttributeConfig: defineAttributeConfig } = __attributesModule;
5064
+ const { createBoundaryReceiver: createBoundaryReceiver } = __boundaryReceiverModule;
4754
5065
  const { createCacheRegistry: createCacheRegistry } = __cacheModule;
4755
5066
  const { defineCache: defineCache } = __cacheModule;
4756
5067
  const { component: component } = __componentModule;
@@ -4778,4 +5089,4 @@ const { createSignalRegistry: createSignalRegistry } = __signalsModule;
4778
5089
  const { effect: effect } = __signalsModule;
4779
5090
  const { signal: signal } = __signalsModule;
4780
5091
 
4781
- export { asyncSignal, Async, createApp, defineApp, readSnapshot, attributeName, defineAttributeConfig, createCacheRegistry, defineCache, component, createComponentRegistry, defineComponent, delay, createHandlerRegistry, html, Loader, AsyncLoader, createPartialRegistry, createRegistryStore, createRouteRegistry, createRouter, defineRoute, route, createScheduler, applyServerResult, createServerProxy, resolveServerCommandArguments, unwrapServerResult, computed, createSignal, createSignalRegistry, effect, signal };
5092
+ export { asyncSignal, Async, createApp, defineApp, readSnapshot, attributeName, defineAttributeConfig, createBoundaryReceiver, createCacheRegistry, defineCache, component, createComponentRegistry, defineComponent, delay, createHandlerRegistry, html, Loader, AsyncLoader, createPartialRegistry, createRegistryStore, createRouteRegistry, createRouter, defineRoute, route, createScheduler, applyServerResult, createServerProxy, resolveServerCommandArguments, unwrapServerResult, computed, createSignal, createSignalRegistry, effect, signal };
package/browser.umd.js CHANGED
@@ -2605,6 +2605,10 @@
2605
2605
  return api;
2606
2606
  },
2607
2607
 
2608
+ isScopeDestroyed(scope) {
2609
+ return scope !== undefined && destroyedScopes.has(scope);
2610
+ },
2611
+
2608
2612
  inspect() {
2609
2613
  const counts = {};
2610
2614
  for (const [phase, queue] of queues) {
@@ -4720,6 +4724,312 @@
4720
4724
  return { defineApp, createApp, readSnapshot, Async };
4721
4725
  })();
4722
4726
 
4727
+ const __boundaryReceiverModule = (() => {
4728
+ const defaultRecentLimit = 50;
4729
+
4730
+ function createBoundaryReceiver(options = {}) {
4731
+ const loader = options.loader;
4732
+ const signals = options.signals ?? loader?.signals;
4733
+ const cache = options.cache ?? loader?.cache;
4734
+ const scheduler = options.scheduler ?? loader?.scheduler;
4735
+ const router = options.router ?? loader?.router;
4736
+ const recentLimit = options.recentLimit ?? defaultRecentLimit;
4737
+ const throwOnError = options.throwOnError === true;
4738
+ const onApply = typeof options.onApply === "function" ? options.onApply : undefined;
4739
+ const onIgnore = typeof options.onIgnore === "function" ? options.onIgnore : undefined;
4740
+ const onError = typeof options.onError === "function" ? options.onError : undefined;
4741
+ const isScopeDestroyed = typeof options.isScopeDestroyed === "function"
4742
+ ? options.isScopeDestroyed
4743
+ : (scope) => scheduler?.isScopeDestroyed?.(scope) ?? scheduler?.inspectDestroyed?.(scope) ?? false;
4744
+
4745
+ if (!loader || typeof loader.swap !== "function") {
4746
+ throw new TypeError("createBoundaryReceiver(...) requires a loader with swap(boundary, html).");
4747
+ }
4748
+ if (!Number.isInteger(recentLimit) || recentLimit < 0) {
4749
+ throw new TypeError("createBoundaryReceiver(...) recentLimit must be a non-negative integer.");
4750
+ }
4751
+
4752
+ const boundaries = new Map();
4753
+ const recent = [];
4754
+ let destroyed = false;
4755
+
4756
+ const receiver = {
4757
+ async apply(patch) {
4758
+ if (destroyed) {
4759
+ throw new Error("Boundary receiver has been destroyed.");
4760
+ }
4761
+
4762
+ const normalized = validatePatch(patch);
4763
+ const record = boundaryRecord(normalized.boundary);
4764
+ if (normalized.seq <= record.lastSeq) {
4765
+ const result = {
4766
+ status: "ignored-stale",
4767
+ boundary: normalized.boundary,
4768
+ seq: normalized.seq,
4769
+ lastSeq: record.lastSeq
4770
+ };
4771
+ record.ignored += 1;
4772
+ record.lastStatus = result.status;
4773
+ remember(result);
4774
+ onIgnore?.(result, patch);
4775
+ return result;
4776
+ }
4777
+
4778
+ if (normalized.parentScope !== undefined && isScopeDestroyed(normalized.parentScope)) {
4779
+ const result = {
4780
+ status: "ignored-destroyed",
4781
+ boundary: normalized.boundary,
4782
+ seq: normalized.seq,
4783
+ parentScope: normalized.parentScope
4784
+ };
4785
+ record.ignored += 1;
4786
+ record.lastStatus = result.status;
4787
+ remember(result);
4788
+ onIgnore?.(result, patch);
4789
+ return result;
4790
+ }
4791
+
4792
+ record.lastSeq = normalized.seq;
4793
+
4794
+ if (Object.hasOwn(normalized, "error")) {
4795
+ const error = toStableError(normalized.error);
4796
+ const result = {
4797
+ status: "errored",
4798
+ boundary: normalized.boundary,
4799
+ seq: normalized.seq,
4800
+ error
4801
+ };
4802
+ record.errored += 1;
4803
+ record.lastStatus = result.status;
4804
+ remember(result);
4805
+ onError?.(error, result, patch);
4806
+ if (throwOnError) {
4807
+ throw error;
4808
+ }
4809
+ return result;
4810
+ }
4811
+
4812
+ if (normalized.signals) {
4813
+ if (!signals || typeof signals.set !== "function") {
4814
+ throw new Error("Boundary patch includes signals, but no signal registry is available.");
4815
+ }
4816
+ for (const [path, value] of Object.entries(normalized.signals)) {
4817
+ signals.set(path, value);
4818
+ }
4819
+ }
4820
+
4821
+ if (normalized.cache?.browser) {
4822
+ if (!cache || typeof cache.restore !== "function") {
4823
+ throw new Error("Boundary patch includes browser cache, but no cache registry is available.");
4824
+ }
4825
+ cache.restore(normalized.cache.browser);
4826
+ }
4827
+
4828
+ if (normalized.html != null) {
4829
+ loader.swap(normalized.boundary, normalized.html);
4830
+ }
4831
+
4832
+ await flushScheduler(scheduler, normalized.scope);
4833
+
4834
+ if (normalized.redirect) {
4835
+ await followRedirect(normalized.redirect, router, loader);
4836
+ const result = {
4837
+ status: "redirected",
4838
+ boundary: normalized.boundary,
4839
+ seq: normalized.seq,
4840
+ redirect: normalized.redirect
4841
+ };
4842
+ record.applied += 1;
4843
+ record.lastStatus = result.status;
4844
+ remember(result);
4845
+ onApply?.(result, patch);
4846
+ return result;
4847
+ }
4848
+
4849
+ const result = {
4850
+ status: "applied",
4851
+ boundary: normalized.boundary,
4852
+ seq: normalized.seq
4853
+ };
4854
+ record.applied += 1;
4855
+ record.lastStatus = result.status;
4856
+ remember(result);
4857
+ onApply?.(result, patch);
4858
+ return result;
4859
+ },
4860
+
4861
+ inspect() {
4862
+ const snapshot = {};
4863
+ for (const [boundary, record] of boundaries) {
4864
+ snapshot[boundary] = {
4865
+ lastSeq: record.lastSeq,
4866
+ applied: record.applied,
4867
+ ignored: record.ignored,
4868
+ lastStatus: record.lastStatus
4869
+ };
4870
+ if (record.errored > 0) {
4871
+ snapshot[boundary].errored = record.errored;
4872
+ }
4873
+ }
4874
+ return {
4875
+ destroyed,
4876
+ boundaries: snapshot,
4877
+ recent: recent.map((entry) => ({ ...entry }))
4878
+ };
4879
+ },
4880
+
4881
+ reset(boundary) {
4882
+ if (boundary === undefined) {
4883
+ boundaries.clear();
4884
+ recent.length = 0;
4885
+ return receiver;
4886
+ }
4887
+ assertBoundary(boundary);
4888
+ boundaries.delete(boundary);
4889
+ for (let index = recent.length - 1; index >= 0; index -= 1) {
4890
+ if (recent[index].boundary === boundary) {
4891
+ recent.splice(index, 1);
4892
+ }
4893
+ }
4894
+ return receiver;
4895
+ },
4896
+
4897
+ destroy() {
4898
+ destroyed = true;
4899
+ boundaries.clear();
4900
+ recent.length = 0;
4901
+ }
4902
+ };
4903
+
4904
+ return receiver;
4905
+
4906
+ function boundaryRecord(boundary) {
4907
+ if (!boundaries.has(boundary)) {
4908
+ boundaries.set(boundary, {
4909
+ lastSeq: -Infinity,
4910
+ applied: 0,
4911
+ ignored: 0,
4912
+ errored: 0,
4913
+ lastStatus: undefined
4914
+ });
4915
+ }
4916
+ return boundaries.get(boundary);
4917
+ }
4918
+
4919
+ function remember(result) {
4920
+ if (recentLimit === 0) {
4921
+ return;
4922
+ }
4923
+ recent.push(toRecentEntry(result));
4924
+ while (recent.length > recentLimit) {
4925
+ recent.shift();
4926
+ }
4927
+ }
4928
+ }
4929
+
4930
+ function validatePatch(patch) {
4931
+ if (!patch || typeof patch !== "object" || Array.isArray(patch)) {
4932
+ throw new TypeError("receiver.apply(patch) requires a boundary patch object.");
4933
+ }
4934
+
4935
+ assertBoundary(patch.boundary);
4936
+ if (typeof patch.seq !== "number" || !Number.isFinite(patch.seq)) {
4937
+ throw new TypeError("Boundary patch seq must be a finite number.");
4938
+ }
4939
+
4940
+ if (patch.signals !== undefined && !isPlainObject(patch.signals)) {
4941
+ throw new TypeError("Boundary patch signals must be an object.");
4942
+ }
4943
+ if (patch.cache !== undefined && !isPlainObject(patch.cache)) {
4944
+ throw new TypeError("Boundary patch cache must be an object.");
4945
+ }
4946
+ if (patch.cache?.browser !== undefined && !isPlainObject(patch.cache.browser)) {
4947
+ throw new TypeError("Boundary patch cache.browser must be an object.");
4948
+ }
4949
+ if (patch.redirect !== undefined && (typeof patch.redirect !== "string" || patch.redirect.length === 0)) {
4950
+ throw new TypeError("Boundary patch redirect must be a non-empty string.");
4951
+ }
4952
+ if (patch.parentScope !== undefined && typeof patch.parentScope !== "string") {
4953
+ throw new TypeError("Boundary patch parentScope must be a string.");
4954
+ }
4955
+ if (patch.scope !== undefined && typeof patch.scope !== "string") {
4956
+ throw new TypeError("Boundary patch scope must be a string.");
4957
+ }
4958
+
4959
+ const hasHtml = Object.hasOwn(patch, "html") && patch.html != null;
4960
+ const hasSignals = patch.signals && Object.keys(patch.signals).length > 0;
4961
+ const hasBrowserCache = patch.cache?.browser && Object.keys(patch.cache.browser).length > 0;
4962
+ const hasRedirect = Boolean(patch.redirect);
4963
+ const hasError = Object.hasOwn(patch, "error");
4964
+ if (!hasHtml && !hasSignals && !hasBrowserCache && !hasRedirect && !hasError) {
4965
+ throw new TypeError("Boundary patch must include html, signals, cache.browser, redirect, or error.");
4966
+ }
4967
+
4968
+ return patch;
4969
+ }
4970
+
4971
+ function assertBoundary(boundary) {
4972
+ if (typeof boundary !== "string" || boundary.length === 0) {
4973
+ throw new TypeError("Boundary patch boundary must be a non-empty string.");
4974
+ }
4975
+ }
4976
+
4977
+ async function flushScheduler(scheduler, scope) {
4978
+ if (!scheduler) {
4979
+ return;
4980
+ }
4981
+ if (scope !== undefined && typeof scheduler.flushScope === "function") {
4982
+ await scheduler.flushScope(scope);
4983
+ return;
4984
+ }
4985
+ if (typeof scheduler.flush === "function") {
4986
+ await scheduler.flush();
4987
+ }
4988
+ }
4989
+
4990
+ async function followRedirect(redirect, router, loader) {
4991
+ if (router && typeof router.navigate === "function") {
4992
+ await router.navigate(redirect);
4993
+ return;
4994
+ }
4995
+ const location = loader?.root?.ownerDocument?.defaultView?.location ?? globalThis.location;
4996
+ location?.assign?.(redirect);
4997
+ }
4998
+
4999
+ function toStableError(value) {
5000
+ if (value instanceof Error) {
5001
+ return value;
5002
+ }
5003
+ if (value && typeof value === "object" && typeof value.message === "string") {
5004
+ return Object.assign(new Error(value.message), value);
5005
+ }
5006
+ return new Error(String(value));
5007
+ }
5008
+
5009
+ function toRecentEntry(result) {
5010
+ const entry = {
5011
+ boundary: result.boundary,
5012
+ seq: result.seq,
5013
+ status: result.status
5014
+ };
5015
+ if (result.status === "ignored-stale") {
5016
+ entry.lastSeq = result.lastSeq;
5017
+ }
5018
+ if (result.status === "ignored-destroyed" && result.parentScope !== undefined) {
5019
+ entry.parentScope = result.parentScope;
5020
+ }
5021
+ if (result.status === "redirected") {
5022
+ entry.redirect = result.redirect;
5023
+ }
5024
+ return entry;
5025
+ }
5026
+
5027
+ function isPlainObject(value) {
5028
+ return Boolean(value && typeof value === "object" && !Array.isArray(value));
5029
+ }
5030
+ return { createBoundaryReceiver };
5031
+ })();
5032
+
4723
5033
  const __delayModule = (() => {
4724
5034
  function delay(ms, signal) {
4725
5035
  if (signal?.aborted) {
@@ -4761,6 +5071,7 @@
4761
5071
  const { readSnapshot: readSnapshot } = __appModule;
4762
5072
  const { attributeName: attributeName } = __attributesModule;
4763
5073
  const { defineAttributeConfig: defineAttributeConfig } = __attributesModule;
5074
+ const { createBoundaryReceiver: createBoundaryReceiver } = __boundaryReceiverModule;
4764
5075
  const { createCacheRegistry: createCacheRegistry } = __cacheModule;
4765
5076
  const { defineCache: defineCache } = __cacheModule;
4766
5077
  const { component: component } = __componentModule;
@@ -4787,7 +5098,7 @@
4787
5098
  const { createSignalRegistry: createSignalRegistry } = __signalsModule;
4788
5099
  const { effect: effect } = __signalsModule;
4789
5100
  const { signal: signal } = __signalsModule;
4790
- const api = { 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 };
5101
+ const api = { 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 };
4791
5102
  assertNoUmdNamespaceConflicts(api, Async);
4792
5103
  Object.assign(Async, api);
4793
5104
  Async.Async = Async;