@darajs/core 1.29.6 → 1.29.7

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.
Files changed (38) hide show
  1. package/dist/api/http.d.ts.map +1 -1
  2. package/dist/api/http.js +14 -0
  3. package/dist/api/http.js.map +1 -1
  4. package/dist/{dara_core-1.29.6-py3-none-any.whl → dara_core-1.29.7-py3-none-any.whl} +0 -0
  5. package/dist/router/fetching.d.ts.map +1 -1
  6. package/dist/router/fetching.js +57 -32
  7. package/dist/router/fetching.js.map +1 -1
  8. package/dist/shared/context/variable-context.d.ts +5 -0
  9. package/dist/shared/context/variable-context.d.ts.map +1 -1
  10. package/dist/shared/context/variable-context.js.map +1 -1
  11. package/dist/shared/dynamic-component/dynamic-component.d.ts.map +1 -1
  12. package/dist/shared/dynamic-component/dynamic-component.js +10 -5
  13. package/dist/shared/dynamic-component/dynamic-component.js.map +1 -1
  14. package/dist/shared/interactivity/derived-variable.d.ts +14 -8
  15. package/dist/shared/interactivity/derived-variable.d.ts.map +1 -1
  16. package/dist/shared/interactivity/derived-variable.js +175 -126
  17. package/dist/shared/interactivity/derived-variable.js.map +1 -1
  18. package/dist/shared/interactivity/polling.d.ts +116 -0
  19. package/dist/shared/interactivity/polling.d.ts.map +1 -0
  20. package/dist/shared/interactivity/polling.js +723 -0
  21. package/dist/shared/interactivity/polling.js.map +1 -0
  22. package/dist/shared/interactivity/store.d.ts +6 -0
  23. package/dist/shared/interactivity/store.d.ts.map +1 -1
  24. package/dist/shared/interactivity/store.js +21 -1
  25. package/dist/shared/interactivity/store.js.map +1 -1
  26. package/dist/shared/interactivity/stream-variable.d.ts +1 -1
  27. package/dist/shared/interactivity/stream-variable.d.ts.map +1 -1
  28. package/dist/shared/interactivity/stream-variable.js +106 -41
  29. package/dist/shared/interactivity/stream-variable.js.map +1 -1
  30. package/dist/shared/interactivity/use-server-component.d.ts +9 -0
  31. package/dist/shared/interactivity/use-server-component.d.ts.map +1 -1
  32. package/dist/shared/interactivity/use-server-component.js +130 -77
  33. package/dist/shared/interactivity/use-server-component.js.map +1 -1
  34. package/dist/shared/interactivity/use-variable.d.ts.map +1 -1
  35. package/dist/shared/interactivity/use-variable.js +2 -2
  36. package/dist/shared/interactivity/use-variable.js.map +1 -1
  37. package/dist/umd/dara.core.umd.cjs +1064 -387
  38. package/package.json +9 -9
@@ -2992,7 +2992,7 @@
2992
2992
  var { applyAtomValueWrites: applyAtomValueWrites$1 } = Recoil_RecoilValueInterface;
2993
2993
  var { releaseScheduledRetainablesNow: releaseScheduledRetainablesNow$1 } = Recoil_Retention;
2994
2994
  var { freshSnapshot: freshSnapshot$1 } = Recoil_Snapshot$1;
2995
- var { useCallback: useCallback$27, useContext: useContext$16, useEffect: useEffect$54, useMemo: useMemo$32, useRef: useRef$1$2, useState: useState$48 } = react.default;
2995
+ var { useCallback: useCallback$27, useContext: useContext$16, useEffect: useEffect$55, useMemo: useMemo$32, useRef: useRef$1$2, useState: useState$48 } = react.default;
2996
2996
  function notInAContext() {
2997
2997
  throw Recoil_err$2("This component must be used inside a <RecoilRoot> component.");
2998
2998
  }
@@ -3079,13 +3079,13 @@
3079
3079
  const storeRef = useStoreRef();
3080
3080
  const [, setState] = useState$48([]);
3081
3081
  setNotifyBatcherOfChange(() => setState({}));
3082
- useEffect$54(() => {
3082
+ useEffect$55(() => {
3083
3083
  setNotifyBatcherOfChange(() => setState({}));
3084
3084
  return () => {
3085
3085
  setNotifyBatcherOfChange(() => {});
3086
3086
  };
3087
3087
  }, [setNotifyBatcherOfChange]);
3088
- useEffect$54(() => {
3088
+ useEffect$55(() => {
3089
3089
  Recoil_Queue.enqueueExecution("Batcher", () => {
3090
3090
  endBatch(storeRef.current);
3091
3091
  });
@@ -3190,7 +3190,7 @@
3190
3190
  if (storeProp != null) storeRef.current = storeProp;
3191
3191
  storeStateRef = Recoil_useRefInitOnce(() => initializeState_DEPRECATED != null ? initialStoreState_DEPRECATED(storeRef.current, initializeState_DEPRECATED) : initializeState != null ? initialStoreState(initializeState) : makeEmptyStoreState$2());
3192
3192
  const mutableSource = useMemo$32(() => createMutableSource$1 === null || createMutableSource$1 === void 0 ? void 0 : createMutableSource$1(storeStateRef, () => storeStateRef.current.currentTree.version), [storeStateRef]);
3193
- useEffect$54(() => {
3193
+ useEffect$55(() => {
3194
3194
  const store = storeRef.current;
3195
3195
  for (const atomKey of new Set(store.getState().knownAtoms)) initializeNode$2(store, atomKey, "get");
3196
3196
  return () => {
@@ -11932,48 +11932,6 @@
11932
11932
  return isFunction(resultSelector) ? mergeMap(project, resultSelector, 1) : mergeMap(project, 1);
11933
11933
  }
11934
11934
  //#endregion
11935
- //#region ../../node_modules/.pnpm/rxjs@7.8.1/node_modules/rxjs/dist/esm5/internal/operators/debounceTime.js
11936
- function debounceTime(dueTime, scheduler) {
11937
- if (scheduler === void 0) scheduler = asyncScheduler;
11938
- return operate(function(source, subscriber) {
11939
- var activeTask = null;
11940
- var lastValue = null;
11941
- var lastTime = null;
11942
- var emit = function() {
11943
- if (activeTask) {
11944
- activeTask.unsubscribe();
11945
- activeTask = null;
11946
- var value = lastValue;
11947
- lastValue = null;
11948
- subscriber.next(value);
11949
- }
11950
- };
11951
- function emitWhenIdle() {
11952
- var targetTime = lastTime + dueTime;
11953
- var now = scheduler.now();
11954
- if (now < targetTime) {
11955
- activeTask = this.schedule(void 0, targetTime - now);
11956
- subscriber.add(activeTask);
11957
- return;
11958
- }
11959
- emit();
11960
- }
11961
- source.subscribe(createOperatorSubscriber(subscriber, function(value) {
11962
- lastValue = value;
11963
- lastTime = scheduler.now();
11964
- if (!activeTask) {
11965
- activeTask = scheduler.schedule(emitWhenIdle, dueTime);
11966
- subscriber.add(activeTask);
11967
- }
11968
- }, function() {
11969
- emit();
11970
- subscriber.complete();
11971
- }, void 0, function() {
11972
- lastValue = activeTask = null;
11973
- }));
11974
- });
11975
- }
11976
- //#endregion
11977
11935
  //#region ../../node_modules/.pnpm/rxjs@7.8.1/node_modules/rxjs/dist/esm5/internal/operators/take.js
11978
11936
  function take(count) {
11979
11937
  return count <= 0 ? function() {
@@ -12022,106 +11980,6 @@
12022
11980
  });
12023
11981
  }
12024
11982
  //#endregion
12025
- //#region ../../node_modules/.pnpm/rxjs@7.8.1/node_modules/rxjs/dist/esm5/internal/operators/share.js
12026
- function share(options) {
12027
- if (options === void 0) options = {};
12028
- var _a = options.connector, connector = _a === void 0 ? function() {
12029
- return new Subject();
12030
- } : _a, _b = options.resetOnError, resetOnError = _b === void 0 ? true : _b, _c = options.resetOnComplete, resetOnComplete = _c === void 0 ? true : _c, _d = options.resetOnRefCountZero, resetOnRefCountZero = _d === void 0 ? true : _d;
12031
- return function(wrapperSource) {
12032
- var connection;
12033
- var resetConnection;
12034
- var subject;
12035
- var refCount = 0;
12036
- var hasCompleted = false;
12037
- var hasErrored = false;
12038
- var cancelReset = function() {
12039
- resetConnection === null || resetConnection === void 0 || resetConnection.unsubscribe();
12040
- resetConnection = void 0;
12041
- };
12042
- var reset = function() {
12043
- cancelReset();
12044
- connection = subject = void 0;
12045
- hasCompleted = hasErrored = false;
12046
- };
12047
- var resetAndUnsubscribe = function() {
12048
- var conn = connection;
12049
- reset();
12050
- conn === null || conn === void 0 || conn.unsubscribe();
12051
- };
12052
- return operate(function(source, subscriber) {
12053
- refCount++;
12054
- if (!hasErrored && !hasCompleted) cancelReset();
12055
- var dest = subject = subject !== null && subject !== void 0 ? subject : connector();
12056
- subscriber.add(function() {
12057
- refCount--;
12058
- if (refCount === 0 && !hasErrored && !hasCompleted) resetConnection = handleReset(resetAndUnsubscribe, resetOnRefCountZero);
12059
- });
12060
- dest.subscribe(subscriber);
12061
- if (!connection && refCount > 0) {
12062
- connection = new SafeSubscriber({
12063
- next: function(value) {
12064
- return dest.next(value);
12065
- },
12066
- error: function(err) {
12067
- hasErrored = true;
12068
- cancelReset();
12069
- resetConnection = handleReset(reset, resetOnError, err);
12070
- dest.error(err);
12071
- },
12072
- complete: function() {
12073
- hasCompleted = true;
12074
- cancelReset();
12075
- resetConnection = handleReset(reset, resetOnComplete);
12076
- dest.complete();
12077
- }
12078
- });
12079
- innerFrom(source).subscribe(connection);
12080
- }
12081
- })(wrapperSource);
12082
- };
12083
- }
12084
- function handleReset(reset, on) {
12085
- var args = [];
12086
- for (var _i = 2; _i < arguments.length; _i++) args[_i - 2] = arguments[_i];
12087
- if (on === true) {
12088
- reset();
12089
- return;
12090
- }
12091
- if (on === false) return;
12092
- var onSubscriber = new SafeSubscriber({ next: function() {
12093
- onSubscriber.unsubscribe();
12094
- reset();
12095
- } });
12096
- return innerFrom(on.apply(void 0, __spreadArray([], __read(args)))).subscribe(onSubscriber);
12097
- }
12098
- //#endregion
12099
- //#region ../../node_modules/.pnpm/rxjs@7.8.1/node_modules/rxjs/dist/esm5/internal/operators/switchMap.js
12100
- function switchMap(project, resultSelector) {
12101
- return operate(function(source, subscriber) {
12102
- var innerSubscriber = null;
12103
- var index = 0;
12104
- var isComplete = false;
12105
- var checkComplete = function() {
12106
- return isComplete && !innerSubscriber && subscriber.complete();
12107
- };
12108
- source.subscribe(createOperatorSubscriber(subscriber, function(value) {
12109
- innerSubscriber === null || innerSubscriber === void 0 || innerSubscriber.unsubscribe();
12110
- var innerIndex = 0;
12111
- var outerIndex = index++;
12112
- innerFrom(project(value, outerIndex)).subscribe(innerSubscriber = createOperatorSubscriber(subscriber, function(innerValue) {
12113
- return subscriber.next(resultSelector ? resultSelector(value, innerValue, outerIndex, innerIndex++) : innerValue);
12114
- }, function() {
12115
- innerSubscriber = null;
12116
- checkComplete();
12117
- }));
12118
- }, function() {
12119
- isComplete = true;
12120
- checkComplete();
12121
- }));
12122
- });
12123
- }
12124
- //#endregion
12125
11983
  //#region ../../node_modules/.pnpm/rxjs@7.8.1/node_modules/rxjs/dist/esm5/internal/operators/takeWhile.js
12126
11984
  function takeWhile(predicate, inclusive) {
12127
11985
  if (inclusive === void 0) inclusive = false;
@@ -17646,14 +17504,14 @@
17646
17504
  * earlier React versions.
17647
17505
  * @see https://floating-ui.com/docs/react-utils#useid
17648
17506
  */
17649
- var useId$1 = SafeReact.useId || useFloatingId;
17507
+ var useId$2 = SafeReact.useId || useFloatingId;
17650
17508
  /**
17651
17509
  * Renders a pointing arrow triangle.
17652
17510
  * @see https://floating-ui.com/docs/FloatingArrow
17653
17511
  */
17654
17512
  var FloatingArrow = /*#__PURE__*/ react$3.forwardRef(function FloatingArrow(props, ref) {
17655
17513
  const { context: { placement, elements: { floating }, middlewareData: { arrow, shift } }, width = 14, height = 7, tipRadius = 0, strokeWidth = 0, staticOffset, stroke, d, style: { transform, ...restStyle } = {}, ...rest } = props;
17656
- const clipPathId = useId$1();
17514
+ const clipPathId = useId$2();
17657
17515
  const [isRTL, setIsRTL] = react$3.useState(false);
17658
17516
  index(() => {
17659
17517
  if (!floating) return;
@@ -18142,7 +18000,7 @@
18142
18000
  function useFloatingPortalNode(props) {
18143
18001
  if (props === void 0) props = {};
18144
18002
  const { id, root } = props;
18145
- const uniqueId = useId$1();
18003
+ const uniqueId = useId$2();
18146
18004
  const portalContext = usePortalContext();
18147
18005
  const [portalNode, setPortalNode] = react$3.useState(null);
18148
18006
  const portalNodeRef = react$3.useRef(null);
@@ -18571,7 +18429,7 @@
18571
18429
  }
18572
18430
  function useFloatingRootContext(options) {
18573
18431
  const { open = false, onOpenChange: onOpenChangeProp, elements: elementsProp } = options;
18574
- const floatingId = useId$1();
18432
+ const floatingId = useId$2();
18575
18433
  const dataRef = react$3.useRef({});
18576
18434
  const [events] = react$3.useState(() => createPubSub());
18577
18435
  const nested = useFloatingParentNodeId() != null;
@@ -18874,7 +18732,7 @@
18874
18732
  const { open, floatingId } = context;
18875
18733
  const { enabled = true, role = "dialog" } = props;
18876
18734
  const ariaRole = (_componentRoleToAriaR = componentRoleToAriaRoleMap.get(role)) != null ? _componentRoleToAriaR : role;
18877
- const referenceId = useId$1();
18735
+ const referenceId = useId$2();
18878
18736
  const isNested = useFloatingParentNodeId() != null;
18879
18737
  const reference = react$3.useMemo(() => {
18880
18738
  if (ariaRole === "tooltip" || role === "label") return { ["aria-" + (role === "label" ? "labelledby" : "describedby")]: open ? floatingId : void 0 };
@@ -51835,6 +51693,17 @@
51835
51693
  //#endregion
51836
51694
  //#region js/api/http.tsx
51837
51695
  var import_cloneDeep = /* @__PURE__ */ __toESM(require_cloneDeep(), 1);
51696
+ var signalIds = /* @__PURE__ */ new WeakMap();
51697
+ var nextSignalId = 1;
51698
+ function getSignalId(signal) {
51699
+ let id = signalIds.get(signal);
51700
+ if (id === void 0) {
51701
+ id = nextSignalId;
51702
+ nextSignalId += 1;
51703
+ signalIds.set(signal, id);
51704
+ }
51705
+ return id;
51706
+ }
51838
51707
  /**
51839
51708
  * Serializable form of RequestExtras.
51840
51709
  * Required to use for e.g. recoil params as they need to be serializable.
@@ -51863,6 +51732,10 @@
51863
51732
  toJSON() {
51864
51733
  const serializable = this.toSerializable();
51865
51734
  if (!serializable) return null;
51735
+ if (this.extras.signal) return JSON.stringify({
51736
+ ...serializable,
51737
+ signal: getSignalId(this.extras.signal)
51738
+ });
51866
51739
  return JSON.stringify(serializable);
51867
51740
  }
51868
51741
  };
@@ -69856,11 +69729,611 @@
69856
69729
  return identifier;
69857
69730
  }
69858
69731
  //#endregion
69732
+ //#region js/shared/interactivity/polling.tsx
69733
+ var DEFAULT_JITTER_RATIO = .1;
69734
+ var MAX_BACKOFF_MS = 6e4;
69735
+ var POLL_FORCE_KEY_PREFIX = "__dara_poll__:";
69736
+ var retryAfterByError = /* @__PURE__ */ new WeakMap();
69737
+ /** Throw an AbortError when an old run attempts to publish a result. */
69738
+ function assertCurrentRun(handle) {
69739
+ if (!handle.isCurrent() || handle.signal.aborted) throw new DOMException("The request was superseded", "AbortError");
69740
+ }
69741
+ /** Check whether an error represents intentional request cancellation. */
69742
+ function isAbortError(error) {
69743
+ return error instanceof DOMException && error.name === "AbortError" || typeof error === "object" && error !== null && "name" in error && error.name === "AbortError";
69744
+ }
69745
+ /** Read Retry-After saved at the HTTP response seam. */
69746
+ function getRetryAfterMs(error) {
69747
+ return typeof error === "object" && error !== null ? retryAfterByError.get(error) : void 0;
69748
+ }
69749
+ /**
69750
+ * Coordinates non-overlapping, fixed-delay polling for request identities.
69751
+ *
69752
+ * A request identity includes the rendered variable/component identity and its
69753
+ * serialized request extras. Multiple React consumers of the same identity
69754
+ * share one timer and one active request generation.
69755
+ */
69756
+ var Poller = class {
69757
+ #clearTimeout;
69758
+ #entries = /* @__PURE__ */ new Map();
69759
+ #getVisibilityState;
69760
+ #jitterRatio;
69761
+ #now;
69762
+ #random;
69763
+ #setTimeout;
69764
+ #visibilityTarget;
69765
+ #owners = /* @__PURE__ */ new Map();
69766
+ #listeningForVisibility = false;
69767
+ constructor(options = {}) {
69768
+ this.#clearTimeout = options.clearTimeout ?? ((timer) => clearTimeout(timer));
69769
+ this.#getVisibilityState = options.getVisibilityState ?? (() => typeof document === "undefined" ? "visible" : document.visibilityState);
69770
+ this.#jitterRatio = options.jitterRatio ?? DEFAULT_JITTER_RATIO;
69771
+ this.#now = options.now ?? (() => Date.now());
69772
+ this.#random = options.random ?? (() => Math.random());
69773
+ this.#setTimeout = options.setTimeout ?? ((callback, delay) => setTimeout(callback, delay));
69774
+ this.#visibilityTarget = options.visibilityTarget ?? (typeof document === "undefined" ? void 0 : document);
69775
+ }
69776
+ /**
69777
+ * Register one rendered polling consumer.
69778
+ *
69779
+ * The returned cleanup releases the consumer. The final cleanup aborts the
69780
+ * owned request on the next macrotask so React StrictMode can immediately
69781
+ * reacquire the same identity without cancelling useful work.
69782
+ */
69783
+ subscribe(key, intervalSeconds, refresh) {
69784
+ const intervalMs = (intervalSeconds ?? 0) * 1e3;
69785
+ if (!Number.isFinite(intervalMs) || !(intervalMs > 0)) return () => {};
69786
+ const entry = this.#getOrCreateEntry(key);
69787
+ const oldIntervalMs = entry.subscribers.size > 0 ? this.#getIntervalMs(entry) : void 0;
69788
+ if (entry.disposeTimer !== void 0) {
69789
+ this.#clearTimeout(entry.disposeTimer);
69790
+ entry.disposeTimer = void 0;
69791
+ }
69792
+ const subscriberId = Symbol(key);
69793
+ entry.subscribers.set(subscriberId, {
69794
+ intervalMs,
69795
+ refresh
69796
+ });
69797
+ this.#startVisibilityListener();
69798
+ if (entry.subscribers.size === 1 && entry.state.kind === "idle" && entry.timer === void 0) this.#schedulePoll(key, entry);
69799
+ else if (entry.timer !== void 0 && entry.failureCount === 0 && oldIntervalMs !== void 0 && intervalMs < oldIntervalMs) {
69800
+ const remaining = Math.max(0, (entry.nextRunAt ?? this.#now()) - this.#now());
69801
+ this.#schedule(key, entry, Math.min(remaining, this.#withJitter(intervalMs)));
69802
+ }
69803
+ return () => {
69804
+ const removedIntervalMs = this.#getIntervalMs(entry);
69805
+ entry.subscribers.delete(subscriberId);
69806
+ if (entry.subscribers.size > 0) {
69807
+ if (entry.timer !== void 0 && entry.failureCount === 0 && this.#getIntervalMs(entry) > removedIntervalMs) this.#schedulePoll(key, entry);
69808
+ return;
69809
+ }
69810
+ this.#clearTimer(entry);
69811
+ entry.disposeTimer = this.#setTimeout(() => {
69812
+ entry.disposeTimer = void 0;
69813
+ if (entry.subscribers.size > 0) return;
69814
+ if (entry.owners.size > 0) return;
69815
+ if (this.#entries.get(key) !== entry) return;
69816
+ if (entry.state.kind === "running") {
69817
+ entry.state.run.controller.abort();
69818
+ entry.state.run.detachExternalSignal?.();
69819
+ entry.state.run.end();
69820
+ }
69821
+ this.#entries.delete(key);
69822
+ this.#stopVisibilityListenerIfIdle();
69823
+ }, 0);
69824
+ };
69825
+ }
69826
+ /**
69827
+ * Claim a key during render so Suspense cannot skip its ownership effect.
69828
+ *
69829
+ * A later owner commit prunes claims left by an abandoned render.
69830
+ */
69831
+ claimKey(ownerId, hookId, key) {
69832
+ const owner = this.#getOrCreateOwner(ownerId);
69833
+ if (owner.hooks.get(hookId) === key) return;
69834
+ const oldKey = owner.claims.get(hookId);
69835
+ owner.claims.set(hookId, key);
69836
+ this.#getOrCreateEntry(key).owners.add(ownerId);
69837
+ if (oldKey !== void 0 && oldKey !== key && !this.#ownerHasKey(owner, oldKey)) this.#dropOwnedKey(ownerId, oldKey);
69838
+ }
69839
+ /** Apply the hook claims collected by one committed owner render. */
69840
+ commitOwner(ownerId, claims) {
69841
+ const owner = this.#getOrCreateOwner(ownerId);
69842
+ if (owner.disposeTimer !== void 0) {
69843
+ this.#clearTimeout(owner.disposeTimer);
69844
+ owner.disposeTimer = void 0;
69845
+ }
69846
+ const droppedClaims = /* @__PURE__ */ new Set();
69847
+ for (const [hookId, key] of owner.claims) if (claims.get(hookId) !== key) {
69848
+ owner.claims.delete(hookId);
69849
+ droppedClaims.add(key);
69850
+ }
69851
+ const nextRenderKeys = /* @__PURE__ */ new Set();
69852
+ for (const key of new Set(claims.values())) {
69853
+ this.#getOrCreateEntry(key).owners.add(ownerId);
69854
+ if (!this.#hasHookForKey(owner, key) && !this.#hasClaimForKey(owner, key)) nextRenderKeys.add(key);
69855
+ }
69856
+ const oldRenderKeys = owner.renderKeys;
69857
+ owner.renderKeys = nextRenderKeys;
69858
+ for (const key of oldRenderKeys) if (!nextRenderKeys.has(key) && !this.#hasHookForKey(owner, key)) this.#dropOwnedKey(ownerId, key);
69859
+ for (const key of droppedClaims) if (!this.#ownerHasKey(owner, key)) this.#dropOwnedKey(ownerId, key);
69860
+ }
69861
+ /** Keep one key after its hook commits. */
69862
+ mountKey(ownerId, hookId, key) {
69863
+ const owner = this.#getOrCreateOwner(ownerId);
69864
+ if (owner.disposeTimer !== void 0) {
69865
+ this.#clearTimeout(owner.disposeTimer);
69866
+ owner.disposeTimer = void 0;
69867
+ }
69868
+ const timer = owner.timers.get(hookId);
69869
+ if (timer !== void 0) {
69870
+ this.#clearTimeout(timer);
69871
+ owner.timers.delete(hookId);
69872
+ }
69873
+ const oldKey = owner.hooks.get(hookId);
69874
+ owner.hooks.set(hookId, key);
69875
+ owner.claims.delete(hookId);
69876
+ owner.renderKeys.delete(key);
69877
+ this.#getOrCreateEntry(key).owners.add(ownerId);
69878
+ if (oldKey !== void 0 && oldKey !== key && !this.#ownerHasKey(owner, oldKey)) this.#dropOwnedKey(ownerId, oldKey);
69879
+ }
69880
+ /** Drop a committed hook key after the StrictMode remount window. */
69881
+ unmountKey(ownerId, hookId, key) {
69882
+ const owner = this.#owners.get(ownerId);
69883
+ if (!owner || owner.timers.has(hookId)) return;
69884
+ const timer = this.#setTimeout(() => {
69885
+ owner.timers.delete(hookId);
69886
+ if (owner.hooks.get(hookId) !== key) return;
69887
+ owner.hooks.delete(hookId);
69888
+ if (!this.#ownerHasKey(owner, key)) this.#dropOwnedKey(ownerId, key);
69889
+ this.#stopVisibilityListenerIfIdle();
69890
+ }, 0);
69891
+ owner.timers.set(hookId, timer);
69892
+ }
69893
+ /** Release a rendered owner after the StrictMode remount window. */
69894
+ releaseOwner(ownerId) {
69895
+ const owner = this.#owners.get(ownerId);
69896
+ if (!owner || owner.disposeTimer !== void 0) return;
69897
+ owner.disposeTimer = this.#setTimeout(() => this.#dropOwner(ownerId, owner), 0);
69898
+ }
69899
+ /**
69900
+ * Run one request for a polling identity.
69901
+ *
69902
+ * Matching callers share one promise. Dependency runs replace older work,
69903
+ * while a poll that arrives during a run leaves one follow-up refresh.
69904
+ */
69905
+ run({ cause, inputKey, key, read, signal, work, write }) {
69906
+ const entry = this.#entries.get(key);
69907
+ const running = entry?.state.kind === "running" ? entry.state.run : void 0;
69908
+ if (running?.cause === cause && running.inputKey === inputKey && running.result) return running.result;
69909
+ const handle = this.#start(key, cause, signal, inputKey);
69910
+ const result = this.#runWork({
69911
+ cause,
69912
+ handle,
69913
+ read,
69914
+ work,
69915
+ write
69916
+ });
69917
+ const state = this.#entries.get(key)?.state;
69918
+ if (state?.kind === "running" && handle.isCurrent()) state.run.result = result;
69919
+ return result;
69920
+ }
69921
+ #start(key, cause, externalSignal, inputKey) {
69922
+ const entry = this.#getOrCreateEntry(key);
69923
+ if (entry.state.kind === "running") {
69924
+ const running = entry.state.run;
69925
+ if (cause === "poll") {
69926
+ entry.runAgain = true;
69927
+ const abortedController = new AbortController();
69928
+ abortedController.abort();
69929
+ return {
69930
+ signal: abortedController.signal,
69931
+ finish: () => {},
69932
+ isCurrent: () => false,
69933
+ waitForNewer: () => this.#waitForNewer(key, entry.generation)
69934
+ };
69935
+ }
69936
+ running.controller.abort();
69937
+ running.detachExternalSignal?.();
69938
+ running.end();
69939
+ }
69940
+ this.#clearTimer(entry);
69941
+ const generation = ++entry.generation;
69942
+ const controller = new AbortController();
69943
+ let end = () => {};
69944
+ const activeRun = {
69945
+ cause,
69946
+ controller,
69947
+ done: new Promise((resolve) => {
69948
+ end = resolve;
69949
+ }),
69950
+ end,
69951
+ generation,
69952
+ inputKey
69953
+ };
69954
+ entry.state = {
69955
+ kind: "running",
69956
+ run: activeRun
69957
+ };
69958
+ if (externalSignal && typeof externalSignal.addEventListener === "function") if (externalSignal.aborted) controller.abort(externalSignal.reason);
69959
+ else {
69960
+ const abortFromExternalSignal = () => controller.abort(externalSignal.reason);
69961
+ externalSignal.addEventListener("abort", abortFromExternalSignal, { once: true });
69962
+ activeRun.detachExternalSignal = () => externalSignal.removeEventListener("abort", abortFromExternalSignal);
69963
+ }
69964
+ return this.#createRunHandle(key, activeRun);
69965
+ }
69966
+ #createRunHandle(key, activeRun) {
69967
+ let finished = false;
69968
+ return {
69969
+ signal: activeRun.controller.signal,
69970
+ finish: (outcome) => {
69971
+ if (finished) return;
69972
+ finished = true;
69973
+ this.#finishRun(key, activeRun.generation, outcome);
69974
+ },
69975
+ isCurrent: () => {
69976
+ const state = this.#entries.get(key)?.state;
69977
+ return state?.kind === "running" && state.run.generation === activeRun.generation;
69978
+ },
69979
+ waitForNewer: () => this.#waitForNewer(key, activeRun.generation)
69980
+ };
69981
+ }
69982
+ async #runWork({ cause, handle, read, work, write }) {
69983
+ let outcome = { status: "success" };
69984
+ try {
69985
+ assertCurrentRun(handle);
69986
+ const value = await work(handle.signal);
69987
+ assertCurrentRun(handle);
69988
+ write(value);
69989
+ return value;
69990
+ } catch (error) {
69991
+ outcome = isAbortError(error) ? { status: "aborted" } : {
69992
+ status: "error",
69993
+ retryAfterMs: getRetryAfterMs(error)
69994
+ };
69995
+ const previous = read?.();
69996
+ if (isAbortError(error) && previous?.found) {
69997
+ await handle.waitForNewer();
69998
+ const latest = read?.();
69999
+ return latest?.found ? latest.value : previous.value;
70000
+ }
70001
+ if (cause === "poll" && previous?.found) return previous.value;
70002
+ throw error;
70003
+ } finally {
70004
+ handle.finish(outcome);
70005
+ }
70006
+ }
70007
+ /** Refresh now, or keep one refresh while busy. */
70008
+ runNow(key) {
70009
+ const entry = this.#entries.get(key);
70010
+ if (!entry || entry.subscribers.size === 0) return;
70011
+ if (this.#getVisibilityState() === "hidden") {
70012
+ entry.runOnShow = true;
70013
+ return;
70014
+ }
70015
+ if (entry.state.kind !== "idle") {
70016
+ entry.runAgain = true;
70017
+ return;
70018
+ }
70019
+ this.#clearTimer(entry);
70020
+ entry.state = { kind: "starting" };
70021
+ this.#getSubscriber(entry)?.refresh();
70022
+ }
70023
+ /** Abort and remove every polling identity. Intended for test isolation. */
70024
+ clear() {
70025
+ for (const entry of this.#entries.values()) {
70026
+ this.#clearTimer(entry);
70027
+ if (entry.disposeTimer !== void 0) this.#clearTimeout(entry.disposeTimer);
70028
+ if (entry.state.kind === "running") {
70029
+ entry.state.run.controller.abort();
70030
+ entry.state.run.detachExternalSignal?.();
70031
+ entry.state.run.end();
70032
+ }
70033
+ }
70034
+ for (const owner of this.#owners.values()) {
70035
+ if (owner.disposeTimer !== void 0) this.#clearTimeout(owner.disposeTimer);
70036
+ for (const timer of owner.timers.values()) this.#clearTimeout(timer);
70037
+ }
70038
+ this.#owners.clear();
70039
+ this.#entries.clear();
70040
+ this.#stopVisibilityListenerIfIdle();
70041
+ }
70042
+ /** Current time according to the injected clock. */
70043
+ now() {
70044
+ return this.#now();
70045
+ }
70046
+ #finishRun(key, generation, outcome) {
70047
+ const entry = this.#entries.get(key);
70048
+ if (!entry || entry.state.kind !== "running" || entry.state.run.generation !== generation) return;
70049
+ entry.state.run.detachExternalSignal?.();
70050
+ entry.state.run.end();
70051
+ entry.state = { kind: "idle" };
70052
+ if (entry.subscribers.size === 0) {
70053
+ if (entry.owners.size === 0) {
70054
+ this.#entries.delete(key);
70055
+ this.#stopVisibilityListenerIfIdle();
70056
+ }
70057
+ return;
70058
+ }
70059
+ if (outcome.status === "success") {
70060
+ entry.failureCount = 0;
70061
+ entry.nextRunAt = void 0;
70062
+ } else if (outcome.status === "error") {
70063
+ entry.failureCount += 1;
70064
+ entry.runAgain = false;
70065
+ const baseDelay = this.#getIntervalMs(entry);
70066
+ const exponentialDelay = Math.min(baseDelay * 2 ** (entry.failureCount - 1), MAX_BACKOFF_MS);
70067
+ const jitteredDelay = Math.min(this.#withJitter(exponentialDelay), MAX_BACKOFF_MS);
70068
+ const backoffDelay = Math.max(jitteredDelay, outcome.retryAfterMs ?? 0);
70069
+ this.#schedule(key, entry, backoffDelay);
70070
+ }
70071
+ if (this.#getVisibilityState() === "hidden") {
70072
+ entry.runOnShow = true;
70073
+ return;
70074
+ }
70075
+ if (outcome.status === "success") {
70076
+ if (entry.runAgain || entry.runOnShow) {
70077
+ entry.runAgain = false;
70078
+ entry.runOnShow = false;
70079
+ this.runNow(key);
70080
+ return;
70081
+ }
70082
+ this.#schedulePoll(key, entry);
70083
+ return;
70084
+ }
70085
+ if (outcome.status === "aborted") if (entry.runAgain) {
70086
+ entry.runAgain = false;
70087
+ this.runNow(key);
70088
+ } else this.#schedulePoll(key, entry);
70089
+ }
70090
+ async #waitForNewer(key, generation) {
70091
+ let seenGeneration = generation;
70092
+ while (true) {
70093
+ const state = this.#entries.get(key)?.state;
70094
+ const activeRun = state?.kind === "running" ? state.run : void 0;
70095
+ if (!activeRun || activeRun.generation <= seenGeneration) return;
70096
+ seenGeneration = activeRun.generation;
70097
+ await activeRun.done;
70098
+ }
70099
+ }
70100
+ #getIntervalMs(entry) {
70101
+ return Math.min(...Array.from(entry.subscribers.values(), (subscriber) => subscriber.intervalMs));
70102
+ }
70103
+ #getOrCreateEntry(key) {
70104
+ let entry = this.#entries.get(key);
70105
+ if (!entry) {
70106
+ entry = {
70107
+ failureCount: 0,
70108
+ generation: 0,
70109
+ owners: /* @__PURE__ */ new Set(),
70110
+ runAgain: false,
70111
+ runOnShow: false,
70112
+ state: { kind: "idle" },
70113
+ subscribers: /* @__PURE__ */ new Map()
70114
+ };
70115
+ this.#entries.set(key, entry);
70116
+ }
70117
+ return entry;
70118
+ }
70119
+ #getSubscriber(entry) {
70120
+ return Array.from(entry.subscribers.values()).sort((a, b) => a.intervalMs - b.intervalMs)[0];
70121
+ }
70122
+ #getOrCreateOwner(ownerId) {
70123
+ let owner = this.#owners.get(ownerId);
70124
+ if (!owner) {
70125
+ const newOwner = {
70126
+ claims: /* @__PURE__ */ new Map(),
70127
+ hooks: /* @__PURE__ */ new Map(),
70128
+ renderKeys: /* @__PURE__ */ new Set(),
70129
+ timers: /* @__PURE__ */ new Map()
70130
+ };
70131
+ owner = newOwner;
70132
+ this.#owners.set(ownerId, newOwner);
70133
+ }
70134
+ return owner;
70135
+ }
70136
+ #dropOwnedKey(ownerId, key) {
70137
+ const entry = this.#entries.get(key);
70138
+ if (!entry) return;
70139
+ entry.owners.delete(ownerId);
70140
+ if (entry.owners.size > 0 || entry.subscribers.size > 0) return;
70141
+ this.#clearTimer(entry);
70142
+ if (entry.state.kind === "running") {
70143
+ entry.state.run.controller.abort();
70144
+ entry.state.run.detachExternalSignal?.();
70145
+ entry.state.run.end();
70146
+ }
70147
+ this.#entries.delete(key);
70148
+ }
70149
+ #dropOwner(ownerId, owner) {
70150
+ if (this.#owners.get(ownerId) !== owner) return;
70151
+ this.#owners.delete(ownerId);
70152
+ for (const timer of owner.timers.values()) this.#clearTimeout(timer);
70153
+ const keys = /* @__PURE__ */ new Set([
70154
+ ...owner.claims.values(),
70155
+ ...owner.renderKeys,
70156
+ ...owner.hooks.values()
70157
+ ]);
70158
+ for (const key of keys) this.#dropOwnedKey(ownerId, key);
70159
+ this.#stopVisibilityListenerIfIdle();
70160
+ }
70161
+ #hasClaimForKey(owner, key) {
70162
+ return Array.from(owner.claims.values()).some((claimKey) => claimKey === key);
70163
+ }
70164
+ #hasHookForKey(owner, key) {
70165
+ return Array.from(owner.hooks.values()).some((hookKey) => hookKey === key);
70166
+ }
70167
+ #ownerHasKey(owner, key) {
70168
+ return owner.renderKeys.has(key) || this.#hasHookForKey(owner, key) || this.#hasClaimForKey(owner, key);
70169
+ }
70170
+ #schedulePoll(key, entry) {
70171
+ this.#schedule(key, entry, this.#withJitter(this.#getIntervalMs(entry)));
70172
+ }
70173
+ #schedule(key, entry, delay) {
70174
+ this.#clearTimer(entry);
70175
+ entry.nextRunAt = this.#now() + delay;
70176
+ if (this.#getVisibilityState() === "hidden") {
70177
+ entry.runOnShow = true;
70178
+ return;
70179
+ }
70180
+ entry.timer = this.#setTimeout(() => {
70181
+ entry.timer = void 0;
70182
+ entry.nextRunAt = void 0;
70183
+ this.runNow(key);
70184
+ }, delay);
70185
+ }
70186
+ #clearTimer(entry, clearNextRun = true) {
70187
+ if (entry.timer !== void 0) {
70188
+ this.#clearTimeout(entry.timer);
70189
+ entry.timer = void 0;
70190
+ }
70191
+ if (clearNextRun) entry.nextRunAt = void 0;
70192
+ }
70193
+ #withJitter(delay) {
70194
+ const multiplier = 1 - this.#jitterRatio + this.#random() * this.#jitterRatio * 2;
70195
+ return Math.max(0, delay * multiplier);
70196
+ }
70197
+ #handleVisibilityChange = () => {
70198
+ const hidden = this.#getVisibilityState() === "hidden";
70199
+ for (const [key, entry] of this.#entries) {
70200
+ if (hidden) {
70201
+ entry.runOnShow = entry.subscribers.size > 0;
70202
+ if (entry.timer !== void 0) this.#clearTimer(entry, entry.failureCount === 0);
70203
+ continue;
70204
+ }
70205
+ if (!entry.runOnShow || entry.subscribers.size === 0) continue;
70206
+ entry.runOnShow = false;
70207
+ const delay = Math.max(0, (entry.nextRunAt ?? this.#now()) - this.#now());
70208
+ if (delay > 0) this.#schedule(key, entry, delay);
70209
+ else this.runNow(key);
70210
+ }
70211
+ };
70212
+ #startVisibilityListener() {
70213
+ if (this.#listeningForVisibility || !this.#visibilityTarget) return;
70214
+ this.#visibilityTarget.addEventListener("visibilitychange", this.#handleVisibilityChange);
70215
+ this.#listeningForVisibility = true;
70216
+ }
70217
+ #stopVisibilityListenerIfIdle() {
70218
+ if (!this.#listeningForVisibility || this.#entries.size > 0 || !this.#visibilityTarget) return;
70219
+ this.#visibilityTarget.removeEventListener("visibilitychange", this.#handleVisibilityChange);
70220
+ this.#listeningForVisibility = false;
70221
+ }
70222
+ };
70223
+ var poller = new Poller();
70224
+ /**
70225
+ * Register fixed-delay polling for a request identity.
70226
+ *
70227
+ * `refresh` only invalidates the corresponding selector. Request lifecycle,
70228
+ * backpressure, retries, and cancellation remain owned by the poller.
70229
+ */
70230
+ function usePolling(key, intervalSeconds, refresh) {
70231
+ const refreshRef = useLatestRef$3(refresh);
70232
+ (0, react$3.useEffect)(() => poller.subscribe(key, intervalSeconds, () => refreshRef.current()), [
70233
+ intervalSeconds,
70234
+ key,
70235
+ refreshRef
70236
+ ]);
70237
+ }
70238
+ /**
70239
+ * Create a render-local map of hooks to polling keys.
70240
+ *
70241
+ * The commit drops claims left by hooks that did not render.
70242
+ */
70243
+ function usePollScope() {
70244
+ const id = (0, react$3.useId)();
70245
+ const claims = /* @__PURE__ */ new Map();
70246
+ (0, react$3.useLayoutEffect)(() => {
70247
+ poller.commitOwner(id, claims);
70248
+ });
70249
+ (0, react$3.useLayoutEffect)(() => () => poller.releaseOwner(id), [id]);
70250
+ return {
70251
+ claims,
70252
+ id
70253
+ };
70254
+ }
70255
+ /**
70256
+ * Keep one request key for a rendered hook.
70257
+ *
70258
+ * The hook must claim the key during render because an initial suspended render
70259
+ * runs no effect. The claim only marks ownership; it starts no work. The passive
70260
+ * effect keeps the claim after commit and stays mounted when Suspense hides an
70261
+ * existing tree.
70262
+ */
70263
+ function usePollKey(scope, key) {
70264
+ const hookId = (0, react$3.useId)();
70265
+ scope?.claims.set(hookId, key);
70266
+ const ownerId = scope?.id;
70267
+ if (ownerId) poller.claimKey(ownerId, hookId, key);
70268
+ (0, react$3.useEffect)(() => {
70269
+ if (!ownerId) return;
70270
+ poller.mountKey(ownerId, hookId, key);
70271
+ return () => poller.unmountKey(ownerId, hookId, key);
70272
+ }, [
70273
+ hookId,
70274
+ key,
70275
+ ownerId
70276
+ ]);
70277
+ }
70278
+ /** Run one request using the production poller. */
70279
+ function runPoll(run) {
70280
+ return poller.run(run);
70281
+ }
70282
+ /** Create a force key that identifies a poller-owned refresh. */
70283
+ function createPollForceKey() {
70284
+ return `${POLL_FORCE_KEY_PREFIX}${globalThis.crypto?.randomUUID?.() ?? String(Math.random())}`;
70285
+ }
70286
+ /** Check whether a selector force key originated from the poller. */
70287
+ function isPollForceKey(forceKey) {
70288
+ return forceKey?.startsWith(POLL_FORCE_KEY_PREFIX) ?? false;
70289
+ }
70290
+ /** Extract Retry-After as a non-negative delay in milliseconds. */
70291
+ function parseRetryAfter(response, now = poller.now()) {
70292
+ const value = response.headers.get("Retry-After");
70293
+ if (!value) return;
70294
+ const seconds = Number(value);
70295
+ if (Number.isFinite(seconds) && seconds >= 0) return seconds * 1e3;
70296
+ const retryAt = Date.parse(value);
70297
+ if (Number.isNaN(retryAt)) return;
70298
+ return Math.max(0, retryAt - now);
70299
+ }
70300
+ /** Keep Retry-After beside an error without changing the error object. */
70301
+ function markRetryAfter(error, response) {
70302
+ const delay = parseRetryAfter(response);
70303
+ if (delay !== void 0 && typeof error === "object" && error !== null) retryAfterByError.set(error, delay);
70304
+ return error;
70305
+ }
70306
+ /** Await a promise while preserving ownership of request cancellation. */
70307
+ async function waitOrAbort(promise, signal) {
70308
+ if (!signal) return promise;
70309
+ if (signal.aborted) throw new DOMException("The request was aborted", "AbortError");
70310
+ return new Promise((resolve, reject) => {
70311
+ const abort = () => {
70312
+ signal.removeEventListener("abort", abort);
70313
+ reject(new DOMException("The request was aborted", "AbortError"));
70314
+ };
70315
+ signal.addEventListener("abort", abort, { once: true });
70316
+ promise.then((value) => {
70317
+ signal.removeEventListener("abort", abort);
70318
+ resolve(value);
70319
+ }, (error) => {
70320
+ signal.removeEventListener("abort", abort);
70321
+ reject(error);
70322
+ });
70323
+ });
70324
+ }
70325
+ /** Clear production polling state. Intended for test isolation. */
70326
+ function clearPolling_TEST() {
70327
+ poller.clear();
70328
+ }
70329
+ //#endregion
69859
70330
  //#region js/shared/interactivity/store.tsx
69860
70331
  /**
69861
70332
  * Key -> atom
69862
70333
  */
69863
70334
  var atomRegistry = /* @__PURE__ */ new Map();
70335
+ /** Request identity -> polling-only trigger atom. */
70336
+ var pollingTriggerRegistry = /* @__PURE__ */ new Map();
69864
70337
  /**
69865
70338
  * Key -> atom family
69866
70339
  */
@@ -69896,6 +70369,19 @@
69896
70369
  */
69897
70370
  var depsRegistry = /* @__PURE__ */ new Map();
69898
70371
  /**
70372
+ * Get the trigger used to refresh exactly one selector/request-extras identity.
70373
+ */
70374
+ function getOrRegisterPollingTrigger(requestKey) {
70375
+ if (!pollingTriggerRegistry.has(requestKey)) pollingTriggerRegistry.set(requestKey, Recoil_index_8({
70376
+ default: {
70377
+ force_key: null,
70378
+ inc: 0
70379
+ },
70380
+ key: `_POLLING_TRIGGER_${requestKey}`
70381
+ }));
70382
+ return pollingTriggerRegistry.get(requestKey);
70383
+ }
70384
+ /**
69899
70385
  * Registry key types that do not use 'nested' in their key
69900
70386
  */
69901
70387
  var SHARED_KEY_TYPES = ["result-selector", "derived-selector"];
@@ -69914,8 +70400,10 @@
69914
70400
  * Clear registries - to be used in tests only.
69915
70401
  */
69916
70402
  function clearRegistries_TEST() {
70403
+ clearPolling_TEST();
69917
70404
  for (const registry of [
69918
70405
  atomRegistry,
70406
+ pollingTriggerRegistry,
69919
70407
  atomFamilyRegistry,
69920
70408
  atomFamilyMembersRegistry,
69921
70409
  selectorRegistry,
@@ -86223,24 +86711,8 @@ ${String(error)}`;
86223
86711
  module.exports = set;
86224
86712
  }));
86225
86713
  //#endregion
86226
- //#region js/shared/utils/use-interval.tsx
86227
- var import_set = /* @__PURE__ */ __toESM(require_set(), 1);
86228
- /**
86229
- * Helper hook that runs a function after given intervals
86230
- *
86231
- * @param callback the function to run after each interval
86232
- * @param delay the delay in seconds between each interval
86233
- */
86234
- function useInterval(callback, delay) {
86235
- (0, react$3.useEffect)(() => {
86236
- if (delay) {
86237
- const id = setInterval(callback, delay * 1e3);
86238
- return () => clearInterval(id);
86239
- }
86240
- }, useDeepCompare([delay, callback]));
86241
- }
86242
- //#endregion
86243
86714
  //#region js/shared/utils/deferred.tsx
86715
+ var import_set = /* @__PURE__ */ __toESM(require_set(), 1);
86244
86716
  var DeferredImpl = class {
86245
86717
  #resolve;
86246
86718
  #reject;
@@ -86382,7 +86854,7 @@ ${String(error)}`;
86382
86854
  * - `values`, values to pass in the request
86383
86855
  * - `wsClient`, websocket client
86384
86856
  */
86385
- async function fetchDerivedVariable({ cache, extras, force_key, variableUid, values, wsClient }) {
86857
+ async function fetchDerivedVariable({ cache, extras, force_key, signal, variableUid, values, wsClient }) {
86386
86858
  const cacheControl = cache === null ? { "cache-control": "none" } : void 0;
86387
86859
  const ws_channel = await wsClient.getChannel();
86388
86860
  const res = await request(`/api/core/derived-variable/${variableUid}`, {
@@ -86393,34 +86865,50 @@ ${String(error)}`;
86393
86865
  }),
86394
86866
  headers: { ...cacheControl },
86395
86867
  method: HTTP_METHOD.POST
86396
- }, extras);
86868
+ }, extras, { signal });
86397
86869
  await handleAuthErrors(res, { authenticationFailureRedirect: "login" });
86398
- await validateResponse(res, `Failed to fetch the derived variable with uid: ${variableUid}`);
86870
+ try {
86871
+ await validateResponse(res, `Failed to fetch the derived variable with uid: ${variableUid}`);
86872
+ } catch (error) {
86873
+ throw markRetryAfter(error, res);
86874
+ }
86399
86875
  return res.json();
86400
86876
  }
86877
+ var pendingFetches = /* @__PURE__ */ new Map();
86401
86878
  /**
86402
- * Add a debounced version of the fetch so as to not overload the backend on startup. This needs to be cached per uid
86403
- * so that we only debounce calls to the same DerivedVariable. Debouncing is done with rxjs as everything here is
86404
- * promise based and async
86879
+ * Wait 10 ms so matching selector reads share one fetch. A running fetch stays separate.
86405
86880
  */
86406
- var debouncedFetchSubjects = {};
86407
- var debouncedFetchCache = {};
86408
- async function debouncedFetchDerivedVariable({ variableUid, selectorKey, values, wsClient, extras, cache, force_key }) {
86409
- if (!debouncedFetchSubjects[selectorKey]) {
86410
- debouncedFetchSubjects[selectorKey] = new BehaviorSubject(null);
86411
- debouncedFetchCache[selectorKey] = debouncedFetchSubjects[selectorKey].pipe(filter((args) => !!args), debounceTime(10), switchMap((args) => from(fetchDerivedVariable(args))), share());
86412
- }
86413
- debouncedFetchSubjects[selectorKey].next({
86414
- cache,
86415
- extras,
86416
- force_key,
86417
- selectorKey,
86418
- values,
86419
- variableUid,
86420
- wsClient
86881
+ function startPendingFetch(selectorKey, pending) {
86882
+ if (pendingFetches.get(selectorKey) !== pending) return;
86883
+ pendingFetches.delete(selectorKey);
86884
+ fetchDerivedVariable(pending.args).then((response) => {
86885
+ for (const waiter of pending.waiters) waiter.resolve(response);
86886
+ }, (error) => {
86887
+ for (const waiter of pending.waiters) waiter.reject(error);
86421
86888
  });
86889
+ }
86890
+ async function debouncedFetchDerivedVariable(args) {
86422
86891
  return new Promise((resolve, reject) => {
86423
- debouncedFetchCache[selectorKey].pipe(take(1)).subscribe(resolve, reject);
86892
+ const pending = pendingFetches.get(args.selectorKey);
86893
+ if (pending) {
86894
+ if (pending.timer !== void 0) clearTimeout(pending.timer);
86895
+ pending.args = args;
86896
+ pending.waiters.push({
86897
+ reject,
86898
+ resolve
86899
+ });
86900
+ pending.timer = setTimeout(() => startPendingFetch(args.selectorKey, pending), 10);
86901
+ return;
86902
+ }
86903
+ const next = {
86904
+ args,
86905
+ waiters: [{
86906
+ reject,
86907
+ resolve
86908
+ }]
86909
+ };
86910
+ next.timer = setTimeout(() => startPendingFetch(args.selectorKey, next), 10);
86911
+ pendingFetches.set(args.selectorKey, next);
86424
86912
  });
86425
86913
  }
86426
86914
  /**
@@ -86502,9 +86990,11 @@ ${String(error)}`;
86502
86990
  * @param resolvedVariables resolved values of dependant variables - turned into primitives and Resolved forms
86503
86991
  * @param get getter function to resolve atoms to values
86504
86992
  * @param triggerList list of trigger info objects
86505
- * @param triggers list of triggers to register as dependencies; first one is expected to be the self-trigger
86993
+ * @param selfTriggers triggers owned by this request identity
86994
+ * @param childTriggers triggers owned by nested variables
86506
86995
  */
86507
- function resolveDerivedValue({ key, variables, deps, resolvedVariables, resolutionStrategy, triggerList, triggers }) {
86996
+ function resolveDerivedValue({ key, variables, deps, resolvedVariables, resolutionStrategy, triggerList, selfTriggers, childTriggers }) {
86997
+ const triggers = [...selfTriggers, ...childTriggers];
86508
86998
  /**
86509
86999
  * Array of values:
86510
87000
  * - primitive values are resolved to themselves
@@ -86565,16 +87055,17 @@ ${String(error)}`;
86565
87055
  };
86566
87056
  }
86567
87057
  const previousTriggerCounters = previousEntry.args.slice(previousEntry.args.length - triggers.length);
87058
+ const dependenciesChanged = !(0, import_isEqual.default)(previousEntry.args.slice(0, -triggers.length), relevantValues.slice(0, -triggers.length));
86568
87059
  let selfTriggerForceKey = null;
86569
- for (const [idx, triggerValue] of triggers.entries())
87060
+ for (const [idx, triggerValue] of dependenciesChanged ? [] : triggers.entries())
86570
87061
  /**
86571
87062
  * If any of the nested trigger value has changed (this execution was caused by a trigger)
86572
87063
  * handle the force_key appropriately
86573
87064
  */
86574
87065
  if (triggerValue.inc !== previousTriggerCounters[idx]) {
86575
- if (idx === 0) selfTriggerForceKey = triggerValue.force_key;
87066
+ if (idx < selfTriggers.length) selfTriggerForceKey = triggerValue.force_key;
86576
87067
  else if (triggerValue.force_key) {
86577
- const triggerInfo = triggerList[idx - 1];
87068
+ const triggerInfo = triggerList[idx - selfTriggers.length];
86578
87069
  if (triggerInfo.path.length === 0) selfTriggerForceKey = triggerValue.force_key;
86579
87070
  else (0, import_set.default)(values, [...triggerInfo.path, "force_key"], triggerValue.force_key);
86580
87071
  }
@@ -86622,9 +87113,9 @@ ${String(error)}`;
86622
87113
  }));
86623
87114
  const selfTrigger = get(getOrRegisterTrigger(variable));
86624
87115
  const selectorKey = key + extrasSerializable.toJSON();
87116
+ const pollingTrigger = get(getOrRegisterPollingTrigger(getRegistryKey(variable, "derived-selector") + extrasSerializable.toJSON()));
86625
87117
  const triggerList = buildTriggerList(variable.variables);
86626
- const triggers = registerChildTriggers(triggerList, get);
86627
- triggers.unshift(selfTrigger);
87118
+ const childTriggers = registerChildTriggers(triggerList, get);
86628
87119
  return resolveDerivedValue({
86629
87120
  key: selectorKey,
86630
87121
  variables: variable.variables,
@@ -86635,7 +87126,8 @@ ${String(error)}`;
86635
87126
  get
86636
87127
  },
86637
87128
  triggerList,
86638
- triggers
87129
+ selfTriggers: [selfTrigger, pollingTrigger],
87130
+ childTriggers
86639
87131
  });
86640
87132
  },
86641
87133
  key: nanoid$1()
@@ -86669,68 +87161,104 @@ ${String(error)}`;
86669
87161
  error.selectorExtras = extrasSerializable.toJSON();
86670
87162
  throw error;
86671
87163
  };
86672
- const handleError = (func) => {
86673
- try {
86674
- return func();
86675
- } catch (e) {
86676
- throwError(e);
86677
- }
86678
- };
86679
87164
  let derivedResult = get(getOrRegisterDerivedVariableResult(variable, wsClient, taskContext, extrasSerializable.extras));
86680
87165
  if (derivedResult.type === "previous") return derivedResult.entry.result;
86681
87166
  const { extras } = extrasSerializable;
86682
- let variableResponse = null;
86683
- let shouldFetchTask = false;
86684
- if (derivedResult.type === "cached") try {
86685
- const response = await derivedResult.response.getValue();
86686
- shouldFetchTask = true;
86687
- if (!response.ok) throwError(new Error(response.value));
86688
- variableResponse = response.value;
86689
- derivedResult = derivedResult.currentResult;
86690
- } catch (e) {
86691
- throwError(e);
86692
- }
86693
- else variableResponse = await handleError(() => debouncedFetchDerivedVariable({
86694
- cache: variable.cache,
86695
- extras,
86696
- force_key: derivedResult.selfTriggerForceKey,
86697
- selectorKey,
86698
- values: normalizeRequest(cleanArgs(derivedResult.values), variable.variables),
86699
- variableUid: variable.uid,
86700
- wsClient
86701
- }));
86702
- let variableValue = NOT_SET$1;
86703
- taskContext.cleanupRunningTasks(variable.uid);
86704
- if (isTaskResponse(variableResponse)) {
86705
- const taskId = variableResponse.task_id;
86706
- if (shouldFetchTask) try {
86707
- const taskResult = await fetchTaskResult(taskId, extras);
86708
- if (taskResult.status === "ok") variableValue = taskResult.result;
86709
- } catch (e) {
86710
- throwError(e);
87167
+ const currentResult = derivedResult.type === "current" ? derivedResult : void 0;
87168
+ const pollRequest = isPollForceKey(currentResult?.selfTriggerForceKey);
87169
+ const inputKey = currentResult ? JSON.stringify({
87170
+ forceKey: currentResult.selfTriggerForceKey,
87171
+ values: currentResult.values
87172
+ }) : void 0;
87173
+ const fetchValue = async (signal) => {
87174
+ let variableResponse = null;
87175
+ let shouldFetchTask = false;
87176
+ if (derivedResult.type === "cached") {
87177
+ const response = await derivedResult.response.getValue();
87178
+ shouldFetchTask = true;
87179
+ if (!response.ok) throwError(new Error(response.value));
87180
+ variableResponse = response.value;
87181
+ derivedResult = derivedResult.currentResult;
87182
+ } else {
87183
+ signal.addEventListener("abort", () => taskContext.cleanupRunningTasks(variable.uid), { once: true });
87184
+ variableResponse = await debouncedFetchDerivedVariable({
87185
+ cache: variable.cache,
87186
+ extras,
87187
+ force_key: currentResult.selfTriggerForceKey,
87188
+ selectorKey,
87189
+ signal,
87190
+ values: normalizeRequest(cleanArgs(currentResult.values), variable.variables),
87191
+ variableUid: variable.uid,
87192
+ wsClient
87193
+ });
86711
87194
  }
86712
- if (variableValue === NOT_SET$1) {
86713
- taskContext.startTask(taskId, variable.uid, getRegistryKey(variable, "trigger"));
86714
- try {
86715
- await wsClient.waitForTask(taskId);
86716
- } catch (e) {
86717
- if (e instanceof TaskError) throwError(e);
86718
- return null;
86719
- } finally {
86720
- taskContext.endTask(taskId);
87195
+ signal?.throwIfAborted();
87196
+ let variableValue = NOT_SET$1;
87197
+ taskContext.cleanupRunningTasks(variable.uid);
87198
+ if (isTaskResponse(variableResponse)) {
87199
+ const taskId = variableResponse.task_id;
87200
+ if (shouldFetchTask) {
87201
+ const taskResult = await fetchTaskResult(taskId, {
87202
+ ...extras,
87203
+ signal
87204
+ });
87205
+ if (taskResult.status === "ok") variableValue = taskResult.result;
86721
87206
  }
86722
- variableValue = await handleError(async () => {
86723
- const result = await fetchTaskResult(taskId, extras);
87207
+ if (variableValue === NOT_SET$1) {
87208
+ taskContext.startTask(taskId, variable.uid, getRegistryKey(variable, "trigger"));
87209
+ try {
87210
+ await waitOrAbort(wsClient.waitForTask(taskId), signal);
87211
+ } catch (e) {
87212
+ if (e instanceof TaskError || isAbortError(e)) throw e;
87213
+ return null;
87214
+ } finally {
87215
+ taskContext.endTask(taskId);
87216
+ }
87217
+ const result = await fetchTaskResult(taskId, {
87218
+ ...extras,
87219
+ signal
87220
+ });
86724
87221
  if (result.status === "not_found") throw new Error("Task result not found");
86725
- return result.result;
86726
- });
86727
- }
86728
- } else variableValue = variableResponse.value;
86729
- depsRegistry.set(derivedResult.depsKey, {
86730
- args: derivedResult.relevantValues,
86731
- result: variableValue
86732
- });
86733
- return variableValue;
87222
+ variableValue = result.result;
87223
+ }
87224
+ } else variableValue = variableResponse.value;
87225
+ return variableValue;
87226
+ };
87227
+ if (!currentResult) try {
87228
+ const variableValue = await fetchValue();
87229
+ depsRegistry.set(derivedResult.depsKey, {
87230
+ args: derivedResult.relevantValues,
87231
+ result: variableValue
87232
+ });
87233
+ return variableValue;
87234
+ } catch (error) {
87235
+ return throwError(error);
87236
+ }
87237
+ const runResult = currentResult;
87238
+ try {
87239
+ return await runPoll({
87240
+ cause: pollRequest ? "poll" : "dependency",
87241
+ inputKey,
87242
+ key: selectorKey,
87243
+ read: () => {
87244
+ const saved = depsRegistry.get(runResult.depsKey);
87245
+ return saved ? {
87246
+ found: true,
87247
+ value: saved.result
87248
+ } : { found: false };
87249
+ },
87250
+ signal: extras.signal ?? void 0,
87251
+ work: fetchValue,
87252
+ write: (variableValue) => {
87253
+ depsRegistry.set(runResult.depsKey, {
87254
+ args: runResult.relevantValues,
87255
+ result: variableValue
87256
+ });
87257
+ }
87258
+ });
87259
+ } catch (error) {
87260
+ return throwError(error);
87261
+ }
86734
87262
  },
86735
87263
  key: nanoid$1()
86736
87264
  }));
@@ -86782,7 +87310,7 @@ ${String(error)}`;
86782
87310
  * Otherwise, returns an object with values so be sent to the backend
86783
87311
  * and handles to resolve the cached promise to the result.
86784
87312
  */
86785
- function preloadDerivedValue({ key, variables, deps, triggerList, triggers, snapshot, params }) {
87313
+ function preloadDerivedValue({ key, variables, deps, triggerList, selfTriggers, childTriggers, snapshot, params }) {
86786
87314
  const derivedResult = resolveDerivedValue({
86787
87315
  key,
86788
87316
  variables,
@@ -86794,7 +87322,8 @@ ${String(error)}`;
86794
87322
  params
86795
87323
  },
86796
87324
  triggerList,
86797
- triggers
87325
+ selfTriggers,
87326
+ childTriggers
86798
87327
  });
86799
87328
  if (derivedResult.type === "previous") return null;
86800
87329
  return {
@@ -86807,16 +87336,16 @@ ${String(error)}`;
86807
87336
  */
86808
87337
  function preloadDerivedVariable(variable, snapshot, params) {
86809
87338
  const key = getRegistryKey(variable, "result-selector") + new RequestExtrasSerializable({}).toJSON();
86810
- const triggerList = [...buildTriggerList(variable.variables), {
86811
- path: [],
86812
- variable
86813
- }];
86814
- const triggers = triggerList.map((ti) => resolveTriggerStatic(getOrRegisterTrigger(ti.variable), snapshot));
87339
+ const requestKey = getRegistryKey(variable, "derived-selector") + new RequestExtrasSerializable({}).toJSON();
87340
+ const triggerList = buildTriggerList(variable.variables);
87341
+ const selfTriggers = [resolveTriggerStatic(getOrRegisterTrigger(variable), snapshot), resolveTriggerStatic(getOrRegisterPollingTrigger(requestKey), snapshot)];
87342
+ const childTriggers = triggerList.map((ti) => resolveTriggerStatic(getOrRegisterTrigger(ti.variable), snapshot));
86815
87343
  return preloadDerivedValue({
86816
87344
  key,
86817
87345
  variables: variable.variables,
86818
87346
  deps: variable.deps,
86819
- triggers,
87347
+ selfTriggers,
87348
+ childTriggers,
86820
87349
  triggerList,
86821
87350
  snapshot,
86822
87351
  params
@@ -86830,14 +87359,17 @@ ${String(error)}`;
86830
87359
  * @param taskContext global task context
86831
87360
  * @param search search query
86832
87361
  * @param extras request extras to be merged into the options
87362
+ * @param pollScope render-local scope for requests started before commit
86833
87363
  */
86834
- function useDerivedVariable(variable, WsClient, taskContext, extras, pollingInterval) {
87364
+ function useDerivedVariable(variable, WsClient, taskContext, extras, pollingInterval, pollScope) {
86835
87365
  const dvSelector = getOrRegisterDerivedVariable(variable, WsClient, taskContext, extras);
86836
- const triggerUpdates = Recoil_index_24((0, react$3.useMemo)(() => getOrRegisterTrigger(variable), []));
86837
- useInterval((0, react$3.useCallback)((force = true) => triggerUpdates((val) => ({
86838
- force_key: force ? nanoid$1() : null,
87366
+ const pollingKey = getRegistryKey(variable, "derived-selector") + new RequestExtrasSerializable(extras).toJSON();
87367
+ usePollKey(pollScope, pollingKey);
87368
+ const triggerUpdates = Recoil_index_24((0, react$3.useMemo)(() => getOrRegisterPollingTrigger(pollingKey), [pollingKey]));
87369
+ usePolling(pollingKey, pollingInterval, (0, react$3.useCallback)(() => triggerUpdates((val) => ({
87370
+ force_key: createPollForceKey(),
86839
87371
  inc: val.inc + 1
86840
- })), [triggerUpdates]), pollingInterval);
87372
+ })), [triggerUpdates]));
86841
87373
  return dvSelector;
86842
87374
  }
86843
87375
  //#endregion
@@ -87856,6 +88388,37 @@ ${String(error)}`;
87856
88388
  * This allows Recoil to properly release instances when components unmount.
87857
88389
  */
87858
88390
  var streamSelectorFamilyRegistry = /* @__PURE__ */ new Map();
88391
+ var STREAM_EVENT_TYPES = /* @__PURE__ */ new Set([
88392
+ "add",
88393
+ "remove",
88394
+ "clear",
88395
+ "replace",
88396
+ "json_snapshot",
88397
+ "json_patch",
88398
+ "reconnect",
88399
+ "error"
88400
+ ]);
88401
+ /**
88402
+ * Parse an SSE message into a supported StreamEvent.
88403
+ *
88404
+ * Comment-only SSE frames are delivered by fetch-event-source as messages with
88405
+ * empty data. They are transport heartbeats rather than application events.
88406
+ */
88407
+ function parseStreamEventMessage(message) {
88408
+ if (message.data.trim() === "") return null;
88409
+ let parsed;
88410
+ try {
88411
+ parsed = JSON.parse(message.data);
88412
+ } catch (parseError) {
88413
+ console.error("Failed to parse SSE event:", parseError, message.data);
88414
+ return null;
88415
+ }
88416
+ if (parsed === null || typeof parsed !== "object" || !("type" in parsed) || typeof parsed.type !== "string" || !STREAM_EVENT_TYPES.has(parsed.type)) {
88417
+ console.error("Unsupported SSE event:", parsed);
88418
+ return null;
88419
+ }
88420
+ return parsed;
88421
+ }
87859
88422
  /**
87860
88423
  * Extract a key from an item using the key_accessor path.
87861
88424
  *
@@ -87997,12 +88560,17 @@ ${String(error)}`;
87997
88560
  * @returns The value to expose to components
87998
88561
  */
87999
88562
  function getStreamValue(state, keyAccessor) {
88563
+ if (state.status === "error") throw new UserError(state.error ?? "Stream failed");
88000
88564
  if (keyAccessor !== null && state.data !== null && typeof state.data === "object" && !Array.isArray(state.data)) return Object.values(state.data);
88001
88565
  return state.data;
88002
88566
  }
88003
88567
  var MAX_RETRIES = 5;
88004
88568
  var BASE_DELAY_MS = 1e3;
88005
88569
  var MAX_DELAY_MS = 3e4;
88570
+ /** Error that should stop the SSE connection rather than be retried. */
88571
+ var FatalStreamError = class extends Error {};
88572
+ /** Error that should be handled by the SSE retry policy. */
88573
+ var RetriableStreamError = class extends Error {};
88006
88574
  /**
88007
88575
  * Calculate exponential backoff delay.
88008
88576
  */
@@ -88032,52 +88600,62 @@ ${String(error)}`;
88032
88600
  let retryCount = 0;
88033
88601
  let isFirstMessage = true;
88034
88602
  let currentState = INITIAL_CONNECTED_STATE;
88603
+ let terminalErrorReported = false;
88035
88604
  const normalizedValues = normalizeRequest(params.resolvedValues, params.variables);
88605
+ const reportTerminalError = (error) => {
88606
+ if (terminalErrorReported) return;
88607
+ terminalErrorReported = true;
88608
+ callbacks.onError(error instanceof Error ? error.message : String(error));
88609
+ };
88036
88610
  fetchEventSource(`/api/core/stream/${params.uid}`, {
88611
+ ...params.extras,
88037
88612
  method: HTTP_METHOD.POST,
88038
88613
  body: JSON.stringify({ values: normalizedValues }),
88039
88614
  signal: controller.signal,
88040
88615
  onopen: async (response) => {
88041
- if (response.ok) {
88042
- retryCount = 0;
88043
- return;
88044
- }
88616
+ if (response.ok) return;
88045
88617
  if (await handleAuthErrors(response, { authenticationFailureRedirect: "login" })) controller.abort();
88046
88618
  throw /* @__PURE__ */ new Error(`Stream request failed: ${response.status} ${response.statusText}`);
88047
88619
  },
88048
88620
  onmessage: (msg) => {
88049
- let event;
88050
- try {
88051
- event = JSON.parse(msg.data);
88052
- } catch (parseError) {
88053
- console.error("Failed to parse SSE event:", parseError, msg.data);
88054
- return;
88055
- }
88621
+ const event = parseStreamEventMessage(msg);
88622
+ if (event === null) return;
88056
88623
  if (event.type === "reconnect") {
88057
88624
  console.info("StreamVariable: Server requested reconnect, reconnecting...");
88058
- throw new Error("Server requested reconnect");
88625
+ throw new RetriableStreamError("Server requested reconnect");
88059
88626
  }
88060
- currentState = applyStreamEvent(currentState, event, params.keyAccessor);
88627
+ if (event.type === "error") throw new FatalStreamError(typeof event.data === "string" ? event.data : "Unknown error");
88628
+ const nextState = applyStreamEvent(currentState, event, params.keyAccessor);
88629
+ if (nextState === currentState || nextState.status === "error") throw new FatalStreamError(nextState.error ?? `Stream event "${event.type}" could not be applied`);
88630
+ retryCount = 0;
88631
+ currentState = nextState;
88061
88632
  if (isFirstMessage) {
88062
88633
  isFirstMessage = false;
88063
88634
  callbacks.onFirstData(currentState);
88064
88635
  } else callbacks.onUpdate(currentState);
88065
88636
  },
88066
88637
  onerror: (err) => {
88067
- if (controller.signal.aborted) return;
88638
+ if (controller.signal.aborted) throw err;
88639
+ if (err instanceof FatalStreamError) {
88640
+ reportTerminalError(err);
88641
+ throw err;
88642
+ }
88068
88643
  retryCount++;
88069
88644
  if (retryCount > MAX_RETRIES) {
88070
- callbacks.onError(err instanceof Error ? err.message : String(err));
88071
- return;
88645
+ reportTerminalError(err);
88646
+ throw err;
88072
88647
  }
88073
88648
  const delay = getBackoffDelay(retryCount - 1);
88074
88649
  console.warn(`Stream connection failed, retrying in ${delay}ms (attempt ${retryCount}/${MAX_RETRIES})...`);
88075
88650
  return delay;
88076
88651
  },
88077
- onclose: () => {},
88652
+ onclose: () => {
88653
+ throw new RetriableStreamError("Stream closed unexpectedly");
88654
+ },
88078
88655
  fetch: request,
88079
- ...params.extras,
88080
88656
  headers: params.extras.headers
88657
+ }).catch((error) => {
88658
+ if (!controller.signal.aborted) reportTerminalError(error);
88081
88659
  });
88082
88660
  return {
88083
88661
  cleanup: () => {
@@ -88098,10 +88676,8 @@ ${String(error)}`;
88098
88676
  return ({ setSelf }) => {
88099
88677
  const params = deserializeAtomParams(atomKey);
88100
88678
  let resolveInitialData = null;
88101
- let rejectInitialData = null;
88102
- setSelf(new Promise((resolve, reject) => {
88679
+ setSelf(new Promise((resolve) => {
88103
88680
  resolveInitialData = resolve;
88104
- rejectInitialData = reject;
88105
88681
  }));
88106
88682
  const startConnection = () => {
88107
88683
  return startStreamConnection(params, {
@@ -88109,7 +88685,6 @@ ${String(error)}`;
88109
88685
  if (resolveInitialData) {
88110
88686
  resolveInitialData(state);
88111
88687
  resolveInitialData = null;
88112
- rejectInitialData = null;
88113
88688
  }
88114
88689
  setSelf(state);
88115
88690
  },
@@ -88117,15 +88692,16 @@ ${String(error)}`;
88117
88692
  setSelf(state);
88118
88693
  },
88119
88694
  onError: (error) => {
88120
- if (rejectInitialData) {
88121
- rejectInitialData(new Error(error));
88122
- resolveInitialData = null;
88123
- rejectInitialData = null;
88124
- } else setSelf({
88695
+ const errorState = {
88125
88696
  data: void 0,
88126
88697
  status: "error",
88127
88698
  error
88128
- });
88699
+ };
88700
+ if (resolveInitialData) {
88701
+ resolveInitialData(errorState);
88702
+ resolveInitialData = null;
88703
+ }
88704
+ setSelf(errorState);
88129
88705
  }
88130
88706
  });
88131
88707
  };
@@ -89599,6 +90175,22 @@ ${String(error)}`;
89599
90175
  return theme;
89600
90176
  }
89601
90177
  //#endregion
90178
+ //#region js/shared/utils/use-interval.tsx
90179
+ /**
90180
+ * Helper hook that runs a function after given intervals
90181
+ *
90182
+ * @param callback the function to run after each interval
90183
+ * @param delay the delay in seconds between each interval
90184
+ */
90185
+ function useInterval(callback, delay) {
90186
+ (0, react$3.useEffect)(() => {
90187
+ if (delay) {
90188
+ const id = setInterval(callback, delay * 1e3);
90189
+ return () => clearInterval(id);
90190
+ }
90191
+ }, useDeepCompare([delay, callback]));
90192
+ }
90193
+ //#endregion
89602
90194
  //#region js/shared/utils/use-previous.tsx
89603
90195
  /**
89604
90196
  * A helper hook to keep track of the previous value of a variable.
@@ -90571,6 +91163,12 @@ ${String(error)}`;
90571
91163
  return key;
90572
91164
  }
90573
91165
  /**
91166
+ * Generate the request identity used for polling and cancellation.
91167
+ */
91168
+ function getServerComponentRequestKey(uid, loopInstanceUid, extras) {
91169
+ return getComponentRegistryKey(uid, false, loopInstanceUid) + new RequestExtrasSerializable(extras).toJSON();
91170
+ }
91171
+ /**
90574
91172
  * Fetch a component from the backend, expects a component instance to be returned.
90575
91173
  *
90576
91174
  * @param component the component to fetch
@@ -90579,7 +91177,7 @@ ${String(error)}`;
90579
91177
  * @param extras request extras to be merged into the options
90580
91178
  * @param wsClient websocket client
90581
91179
  */
90582
- async function fetchFunctionComponent(component, values, uid, extras, wsClient) {
91180
+ async function fetchFunctionComponent(component, values, uid, extras, wsClient, signal) {
90583
91181
  const ws_channel = await wsClient.getChannel();
90584
91182
  const res = await request(`/api/core/components/${component}`, {
90585
91183
  body: JSON.stringify({
@@ -90588,9 +91186,13 @@ ${String(error)}`;
90588
91186
  ws_channel
90589
91187
  }),
90590
91188
  method: HTTP_METHOD.POST
90591
- }, extras);
91189
+ }, extras, { signal });
90592
91190
  await handleAuthErrors(res, { authenticationFailureRedirect: "login" });
90593
- await validateResponse(res, `Failed to fetch the component: ${component}`);
91191
+ try {
91192
+ await validateResponse(res, `Failed to fetch the component: ${component}`);
91193
+ } catch (error) {
91194
+ throw markRetryAfter(error, res);
91195
+ }
90594
91196
  return await res.json();
90595
91197
  }
90596
91198
  function getOrRegisterComponentTrigger(uid, loop_instance_uid) {
@@ -90626,25 +91228,19 @@ ${String(error)}`;
90626
91228
  error.selectorExtras = extrasSerializable.toJSON();
90627
91229
  throw error;
90628
91230
  };
90629
- const handleError = (func) => {
90630
- try {
90631
- return func();
90632
- } catch (e) {
90633
- throwError(e);
90634
- }
90635
- };
91231
+ const selectorKey = key + extrasSerializable.toJSON();
90636
91232
  const resolvedKwargs = await Promise.all(Object.entries(dynamicKwargs).map(async ([k, value]) => {
90637
91233
  return [k, isVariable(value) ? await resolveVariable(value, wsClient, taskContext, currentExtras) : value];
90638
91234
  })).then((entries) => Object.fromEntries(entries));
90639
91235
  const resolvedKwargsList = Object.values(resolvedKwargs);
90640
91236
  const kwargsList = Object.values(dynamicKwargs);
90641
91237
  const selfTrigger = get(getOrRegisterComponentTrigger(uid, loop_instance_uid));
91238
+ const pollingTrigger = get(getOrRegisterPollingTrigger(selectorKey));
90642
91239
  const triggerList = buildTriggerList(kwargsList);
90643
- const triggers = registerChildTriggers(triggerList, get);
90644
- triggers.unshift(selfTrigger);
91240
+ const childTriggers = registerChildTriggers(triggerList, get);
90645
91241
  const { extras } = extrasSerializable;
90646
91242
  let derivedResult = resolveDerivedValue({
90647
- key,
91243
+ key: selectorKey,
90648
91244
  variables: kwargsList,
90649
91245
  deps: kwargsList,
90650
91246
  resolvedVariables: resolvedKwargsList,
@@ -90653,59 +91249,97 @@ ${String(error)}`;
90653
91249
  get
90654
91250
  },
90655
91251
  triggerList,
90656
- triggers
91252
+ selfTriggers: [selfTrigger, pollingTrigger],
91253
+ childTriggers
90657
91254
  });
90658
91255
  if (derivedResult.type === "previous") return derivedResult.entry.result;
90659
- let result = NOT_SET;
90660
- let shouldFetchTask = false;
90661
- if (derivedResult.type === "cached") try {
90662
- const response = await derivedResult.response.getValue();
90663
- shouldFetchTask = true;
90664
- if (!response.ok) throwError(new Error(response.value));
90665
- result = response.value;
90666
- derivedResult = derivedResult.currentResult;
90667
- } catch (e) {
90668
- throwError(e);
90669
- }
90670
- else {
90671
- const kwargValues = cleanKwargs(Object.keys(dynamicKwargs).reduce((acc, k, idx) => {
90672
- acc[k] = derivedResult.values[idx];
90673
- return acc;
90674
- }, {}));
90675
- result = await handleError(() => fetchFunctionComponent(name, normalizeRequest(kwargValues, dynamicKwargs), uid, extras, wsClient));
90676
- }
90677
- taskContext.cleanupRunningTasks(key);
90678
- if (isTaskResponse$1(result)) {
90679
- const taskId = result.task_id;
90680
- result = NOT_SET;
90681
- if (shouldFetchTask) try {
90682
- const taskResult = await fetchTaskResult(taskId, extras);
90683
- if (taskResult.status === "ok") result = taskResult.result;
90684
- } catch (e) {
90685
- throwError(e);
90686
- }
90687
- if (result === NOT_SET) {
90688
- taskContext.startTask(taskId, key, getComponentRegistryKey(uid, true));
90689
- try {
90690
- await wsClient.waitForTask(taskId);
90691
- } catch (e) {
90692
- throwError(e);
90693
- } finally {
90694
- taskContext.endTask(taskId);
91256
+ const currentResult = derivedResult.type === "current" ? derivedResult : void 0;
91257
+ const pollRequest = isPollForceKey(currentResult?.selfTriggerForceKey);
91258
+ const inputKey = currentResult ? JSON.stringify({
91259
+ forceKey: currentResult.selfTriggerForceKey,
91260
+ values: currentResult.values
91261
+ }) : void 0;
91262
+ const fetchComponent = async (signal) => {
91263
+ let result = NOT_SET;
91264
+ let shouldFetchTask = false;
91265
+ if (derivedResult.type === "cached") {
91266
+ const response = await derivedResult.response.getValue();
91267
+ shouldFetchTask = true;
91268
+ if (!response.ok) throwError(new Error(response.value));
91269
+ result = response.value;
91270
+ derivedResult = derivedResult.currentResult;
91271
+ } else {
91272
+ signal.addEventListener("abort", () => taskContext.cleanupRunningTasks(key), { once: true });
91273
+ result = await fetchFunctionComponent(name, normalizeRequest(cleanKwargs(Object.keys(dynamicKwargs).reduce((acc, k, idx) => {
91274
+ acc[k] = currentResult.values[idx];
91275
+ return acc;
91276
+ }, {})), dynamicKwargs), uid, extras, wsClient, signal);
91277
+ }
91278
+ signal?.throwIfAborted();
91279
+ taskContext.cleanupRunningTasks(key);
91280
+ if (isTaskResponse$1(result)) {
91281
+ const taskId = result.task_id;
91282
+ result = NOT_SET;
91283
+ if (shouldFetchTask) {
91284
+ const taskResult = await fetchTaskResult(taskId, {
91285
+ ...extras,
91286
+ signal
91287
+ });
91288
+ if (taskResult.status === "ok") result = taskResult.result;
91289
+ }
91290
+ if (result === NOT_SET) {
91291
+ taskContext.startTask(taskId, key, getComponentRegistryKey(uid, true));
91292
+ try {
91293
+ await waitOrAbort(wsClient.waitForTask(taskId), signal);
91294
+ } finally {
91295
+ taskContext.endTask(taskId);
91296
+ }
91297
+ const response = await fetchTaskResult(taskId, {
91298
+ ...extras,
91299
+ signal
91300
+ });
91301
+ if (response.status === "not_found") throw new Error("Task result not found");
91302
+ result = response.result;
90695
91303
  }
90696
- result = await handleError(async () => {
90697
- const res = await fetchTaskResult(taskId, extras);
90698
- if (res.status === "not_found") throw new Error("Task result not found");
90699
- return res.result;
90700
- });
90701
91304
  }
91305
+ if (result !== NOT_SET && result !== null) result = denormalize(result.data, result.lookup);
91306
+ return result;
91307
+ };
91308
+ if (!currentResult) try {
91309
+ const result = await fetchComponent();
91310
+ depsRegistry.set(derivedResult.depsKey, {
91311
+ args: derivedResult.relevantValues,
91312
+ result
91313
+ });
91314
+ return result;
91315
+ } catch (error) {
91316
+ return throwError(error);
91317
+ }
91318
+ const runResult = currentResult;
91319
+ try {
91320
+ return await runPoll({
91321
+ cause: pollRequest ? "poll" : "dependency",
91322
+ inputKey,
91323
+ key: selectorKey,
91324
+ read: () => {
91325
+ const saved = depsRegistry.get(runResult.depsKey);
91326
+ return saved ? {
91327
+ found: true,
91328
+ value: saved.result
91329
+ } : { found: false };
91330
+ },
91331
+ signal: extras.signal ?? void 0,
91332
+ work: fetchComponent,
91333
+ write: (result) => {
91334
+ depsRegistry.set(runResult.depsKey, {
91335
+ args: runResult.relevantValues,
91336
+ result
91337
+ });
91338
+ }
91339
+ });
91340
+ } catch (error) {
91341
+ return throwError(error);
90702
91342
  }
90703
- if (result !== NOT_SET && result !== null) result = denormalize(result.data, result.lookup);
90704
- depsRegistry.set(key, {
90705
- args: derivedResult.relevantValues,
90706
- result
90707
- });
90708
- return result;
90709
91343
  },
90710
91344
  key
90711
91345
  }));
@@ -90717,7 +91351,7 @@ ${String(error)}`;
90717
91351
  return selectorInstance;
90718
91352
  }
90719
91353
  function preloadServerComponent(component, snapshot, params) {
90720
- const key = getComponentRegistryKey(component.uid, false, component.loop_instance_uid);
91354
+ const key = getServerComponentRequestKey(component.uid, component.loop_instance_uid, {});
90721
91355
  const kwargsList = Object.values(component.props.dynamic_kwargs);
90722
91356
  const triggerList = buildTriggerList(kwargsList);
90723
91357
  return preloadDerivedValue({
@@ -90725,7 +91359,8 @@ ${String(error)}`;
90725
91359
  variables: kwargsList,
90726
91360
  deps: kwargsList,
90727
91361
  triggerList,
90728
- triggers: [...triggerList.map((ti) => resolveTriggerStatic(getOrRegisterTrigger(ti.variable), snapshot)), resolveTriggerStatic(getOrRegisterComponentTrigger(component.uid), snapshot)],
91362
+ selfTriggers: [resolveTriggerStatic(getOrRegisterComponentTrigger(component.uid, component.loop_instance_uid), snapshot), resolveTriggerStatic(getOrRegisterPollingTrigger(key), snapshot)],
91363
+ childTriggers: triggerList.map((ti) => resolveTriggerStatic(getOrRegisterTrigger(ti.variable), snapshot)),
90729
91364
  snapshot,
90730
91365
  params
90731
91366
  });
@@ -90743,6 +91378,8 @@ ${String(error)}`;
90743
91378
  const { client: wsClient } = (0, react$3.useContext)(websocketCtx);
90744
91379
  const taskContext = useTaskContext();
90745
91380
  const variablesContext = (0, react$3.useContext)(variablesCtx);
91381
+ const requestKey = getServerComponentRequestKey(uid, loop_instance_uid, extras);
91382
+ usePollKey(variablesContext?.pollScope, requestKey);
90746
91383
  const bus = useEventBus();
90747
91384
  variablesContext?.variables.current.add(getComponentRegistryKey(uid));
90748
91385
  (0, react$3.useEffect)(() => {
@@ -90782,6 +91419,18 @@ ${String(error)}`;
90782
91419
  }));
90783
91420
  }, [uid]);
90784
91421
  }
91422
+ /**
91423
+ * Refresh one server-component/request-extras identity for polling.
91424
+ */
91425
+ function usePollServerComponent(uid, loopInstanceUid, extras) {
91426
+ const requestKey = getServerComponentRequestKey(uid, loopInstanceUid, extras);
91427
+ return Recoil_index_31(({ set }) => () => {
91428
+ set(getOrRegisterPollingTrigger(requestKey), (triggerIndexValue) => ({
91429
+ force_key: createPollForceKey(),
91430
+ inc: triggerIndexValue.inc + 1
91431
+ }));
91432
+ }, [requestKey]);
91433
+ }
90785
91434
  //#endregion
90786
91435
  //#region js/shared/center/center.tsx
90787
91436
  var Center = dist_default.div`
@@ -91477,6 +92126,10 @@ ${String(error)}`;
91477
92126
  }
91478
92127
  const { hasRunningTasks, cleanupRunningTasks } = useTaskContext();
91479
92128
  const variables = (0, react$3.useRef)(/* @__PURE__ */ new Set());
92129
+ const variableContext = {
92130
+ pollScope: usePollScope(),
92131
+ variables
92132
+ };
91480
92133
  (0, react$3.useEffect)(() => {
91481
92134
  return () => {
91482
92135
  if (variables.current.size > 0 && hasRunningTasks()) cleanupRunningTasks(...variables.current.values());
@@ -91491,7 +92144,7 @@ ${String(error)}`;
91491
92144
  ...fallbackProps
91492
92145
  }),
91493
92146
  onReset: onResetErrorBoundary
91494
- }, /* @__PURE__ */ React.createElement(fallbackCtx.Provider, { value: { suspend } }, /* @__PURE__ */ React.createElement(variablesCtx.Provider, { value: { variables } }, /* @__PURE__ */ React.createElement(react$3.Suspense, { fallback }, component))));
92147
+ }, /* @__PURE__ */ React.createElement(fallbackCtx.Provider, { value: { suspend } }, /* @__PURE__ */ React.createElement(variablesCtx.Provider, { value: variableContext }, /* @__PURE__ */ React.createElement(react$3.Suspense, { fallback }, component))));
91495
92148
  }
91496
92149
  function useResolveDynamicKwargPollingIntervals(dynamicKwargs) {
91497
92150
  return (0, react$3.useMemo)(() => {
@@ -91516,9 +92169,12 @@ ${String(error)}`;
91516
92169
  function PythonWrapper(props) {
91517
92170
  const component = useServerComponent(props.name, props.uid, props.dynamic_kwargs, props.component.loop_instance_uid);
91518
92171
  const refresh = useRefreshServerComponent(props.uid, props.component.loop_instance_uid);
92172
+ const extras = useRequestExtras();
92173
+ const poll = usePollServerComponent(props.uid, props.component.loop_instance_uid, extras);
91519
92174
  const [componentPollingInterval] = useVariable(props.polling_interval ?? null);
91520
92175
  const resolvedKwargPollingIntervals = useResolveDynamicKwargPollingIntervals(props.dynamic_kwargs);
91521
- useInterval(refresh, (0, react$3.useMemo)(() => computePollingInterval(resolvedKwargPollingIntervals, componentPollingInterval), [resolvedKwargPollingIntervals, componentPollingInterval]));
92176
+ const pollingInterval = (0, react$3.useMemo)(() => computePollingInterval(resolvedKwargPollingIntervals, componentPollingInterval), [resolvedKwargPollingIntervals, componentPollingInterval]);
92177
+ usePolling(getServerComponentRequestKey(props.uid, props.component.loop_instance_uid, extras), pollingInterval, poll);
91522
92178
  if (component === null) return null;
91523
92179
  if (isRawString(component)) return /* @__PURE__ */ React.createElement(React.Fragment, null, component.props.content);
91524
92180
  if (isInvalidComponent(component)) return /* @__PURE__ */ React.createElement(ErrorDisplay$1, {
@@ -92289,24 +92945,49 @@ ${String(error)}`;
92289
92945
  * @param signal AbortSignal to abort the generator
92290
92946
  */
92291
92947
  async function* ndjson(response, signal) {
92948
+ if (!response.body) throw new Error("Route response body is missing");
92292
92949
  const reader = response.body.getReader();
92293
92950
  const newline = /\r?\n/;
92294
92951
  const decoder = new TextDecoder();
92295
92952
  let buffer = "";
92296
- while (true) {
92297
- if (signal?.aborted) throw new DOMException("The operation was aborted", "AbortError");
92298
- const { done, value } = await reader.read();
92299
- if (done) {
92300
- if (buffer.length > 0) yield JSON.parse(buffer);
92301
- return;
92953
+ let cancelPromise;
92954
+ const abortError = () => new DOMException("The operation was aborted", "AbortError");
92955
+ const cancel = (reason) => {
92956
+ cancelPromise ??= reader.cancel(reason).catch(() => void 0);
92957
+ return cancelPromise;
92958
+ };
92959
+ const abort = () => {
92960
+ cancel(signal?.reason ?? abortError());
92961
+ };
92962
+ signal?.addEventListener("abort", abort, { once: true });
92963
+ try {
92964
+ while (true) {
92965
+ if (signal?.aborted) throw abortError();
92966
+ const { done, value } = await reader.read();
92967
+ if (signal?.aborted) throw abortError();
92968
+ if (done) {
92969
+ if (buffer.length > 0) yield JSON.parse(buffer);
92970
+ return;
92971
+ }
92972
+ const chunk = decoder.decode(value, { stream: true });
92973
+ buffer += chunk;
92974
+ const parts = buffer.split(newline);
92975
+ buffer = parts.pop();
92976
+ for (const part of parts) yield JSON.parse(part);
92302
92977
  }
92303
- const chunk = decoder.decode(value, { stream: true });
92304
- buffer += chunk;
92305
- const parts = buffer.split(newline);
92306
- buffer = parts.pop();
92307
- for (const part of parts) yield JSON.parse(part);
92978
+ } catch (error) {
92979
+ await cancel(error);
92980
+ throw error;
92981
+ } finally {
92982
+ signal?.removeEventListener("abort", abort);
92983
+ reader.releaseLock();
92308
92984
  }
92309
92985
  }
92986
+ function rejectPending(handle, error) {
92987
+ if (handle.status !== "pending") return;
92988
+ handle.getValue().catch(() => void 0);
92989
+ handle.reject(error);
92990
+ }
92310
92991
  /**
92311
92992
  * Fetch route data from the server.
92312
92993
  *
@@ -92394,8 +93075,6 @@ ${String(error)}`;
92394
93075
  if (!response.ok) throw new LoaderError((await response.json()).detail);
92395
93076
  const template = deferred();
92396
93077
  const onLoadActions = deferred();
92397
- const resolvedDvs = /* @__PURE__ */ new Set();
92398
- const resolvedPyComponents = /* @__PURE__ */ new Set();
92399
93078
  queueMicrotask(async () => {
92400
93079
  try {
92401
93080
  for await (const data of ndjson(response, signal)) {
@@ -92405,20 +93084,14 @@ ${String(error)}`;
92405
93084
  template.resolve(component);
92406
93085
  }
92407
93086
  if (chunk.type === "actions") onLoadActions.resolve(actions.flatMap((a) => isAnnotatedAction(a) ? chunk.actions[a.uid] : a));
92408
- if (chunk.type === "derived_variable") {
92409
- dvHandlesByUid[chunk.uid]?.handle.resolve(chunk.result);
92410
- resolvedDvs.add(chunk.uid);
92411
- }
92412
- if (chunk.type === "py_component") {
92413
- pyHandlesByUid[chunk.uid]?.handle.resolve(chunk.result);
92414
- resolvedPyComponents.add(chunk.uid);
92415
- }
93087
+ if (chunk.type === "derived_variable") dvHandlesByUid[chunk.uid]?.handle.resolve(chunk.result);
93088
+ if (chunk.type === "py_component") pyHandlesByUid[chunk.uid]?.handle.resolve(chunk.result);
92416
93089
  }
92417
93090
  } catch (e) {
92418
- template.reject(e);
92419
- onLoadActions.reject(e);
92420
- for (const [uid, handle] of Object.entries(dvHandlesByUid)) if (!resolvedDvs.has(uid)) handle.handle.reject(e);
92421
- for (const [uid, handle] of Object.entries(pyHandlesByUid)) if (!resolvedPyComponents.has(uid)) handle.handle.reject(e);
93091
+ rejectPending(template, e);
93092
+ rejectPending(onLoadActions, e);
93093
+ for (const handle of Object.values(dvHandlesByUid)) rejectPending(handle.handle, e);
93094
+ for (const handle of Object.values(pyHandlesByUid)) rejectPending(handle.handle, e);
92422
93095
  }
92423
93096
  });
92424
93097
  const [templateValue, onLoadActionsValue] = await Promise.all([template.getValue(), onLoadActions.getValue()]);
@@ -92951,7 +93624,7 @@ ${String(error)}`;
92951
93624
  useStreamSubscription((0, react$3.useMemo)(() => findStreamVariables(variable).map((s) => s.uid), [variable.uid]), extras);
92952
93625
  if (isDerivedVariable(variable)) {
92953
93626
  const [pollingInterval] = useVariable(variable.polling_interval ?? null, { suspend: false });
92954
- const selectorLoadable = Recoil_index_28(useDerivedVariable(variable, wsClient, taskContext, extras, pollingInterval ?? void 0));
93627
+ const selectorLoadable = Recoil_index_28(useDerivedVariable(variable, wsClient, taskContext, extras, pollingInterval ?? void 0, variablesContext?.pollScope));
92955
93628
  (0, react$3.useEffect)(() => {
92956
93629
  if (selectorLoadable.state !== "loading") bus.publish("DERIVED_VARIABLE_LOADED", {
92957
93630
  variable,
@@ -92962,7 +93635,7 @@ ${String(error)}`;
92962
93635
  }
92963
93636
  if (isSwitchVariable(variable)) return [useSwitchVariable(variable), warnUpdateOnDerivedState];
92964
93637
  if (isStateVariable(variable)) {
92965
- const parentLoadable = Recoil_index_28(useDerivedVariable(variable.parent_variable, wsClient, taskContext, extras));
93638
+ const parentLoadable = Recoil_index_28(useDerivedVariable(variable.parent_variable, wsClient, taskContext, extras, void 0, variablesContext?.pollScope));
92966
93639
  let stateValue;
92967
93640
  switch (variable.property_name) {
92968
93641
  case "loading":
@@ -128015,8 +128688,10 @@ while (n === a[++i] && n === a[++i] && n === a[++i] && n === a[++i] && n === a[+
128015
128688
  exports.getOrRegisterDerivedVariable = getOrRegisterDerivedVariable;
128016
128689
  exports.getOrRegisterDerivedVariableResult = getOrRegisterDerivedVariableResult;
128017
128690
  exports.getOrRegisterDerivedVariableValue = getOrRegisterDerivedVariableValue;
128691
+ exports.getOrRegisterPollingTrigger = getOrRegisterPollingTrigger;
128018
128692
  exports.getOrRegisterServerVariable = getOrRegisterServerVariable;
128019
128693
  exports.getRegistryKey = getRegistryKey;
128694
+ exports.getServerComponentRequestKey = getServerComponentRequestKey;
128020
128695
  exports.getSessionIdentifier = getSessionIdentifier;
128021
128696
  exports.getTabularVariableValue = getTabularVariableValue;
128022
128697
  exports.getVariableHookSignature = getVariableHookSignature;
@@ -128053,6 +128728,7 @@ while (n === a[++i] && n === a[++i] && n === a[++i] && n === a[++i] && n === a[+
128053
128728
  exports.onSessionIdChange = onSessionIdChange;
128054
128729
  exports.parseLoginReferrer = parseLoginReferrer;
128055
128730
  exports.parseRawCss = parseRawCss;
128731
+ exports.pollingTriggerRegistry = pollingTriggerRegistry;
128056
128732
  exports.preloadDerivedValue = preloadDerivedValue;
128057
128733
  exports.preloadDerivedVariable = preloadDerivedVariable;
128058
128734
  exports.preloadServerComponent = preloadServerComponent;
@@ -128086,6 +128762,7 @@ while (n === a[++i] && n === a[++i] && n === a[++i] && n === a[++i] && n === a[+
128086
128762
  exports.useFetchTabularDerivedVariable = useFetchTabularDerivedVariable;
128087
128763
  exports.useFetchTabularServerVariable = useFetchTabularServerVariable;
128088
128764
  exports.useInterval = useInterval;
128765
+ exports.usePollServerComponent = usePollServerComponent;
128089
128766
  exports.usePreloadRoute = usePreloadRoute;
128090
128767
  exports.usePrevious = usePrevious;
128091
128768
  exports.useRefreshSelector = useRefreshSelector;