@jsenv/navi 0.29.53 → 0.29.54

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.
@@ -13091,8 +13091,7 @@ const setActionPrivateProperties = (action, properties) => {
13091
13091
  * the screen that will is often not even mounted — a route action runs before
13092
13092
  * its page renders, which is precisely the case a guess made at failure time
13093
13093
  * gets wrong. So nothing is guessed. The error is let go, and whoever displays
13094
- * it SAYS so by marking it; what is still unmarked once the DOM has had its
13095
- * chance was displayed by nobody, and only that is reported as unhandled.
13094
+ * it SAYS so by marking it; what nobody ever took is reported as unhandled.
13096
13095
  *
13097
13096
  * The mark is `__handled_by__`, the same one the jsenv supervisor reads to stay
13098
13097
  * out of the way of an error the app is already showing — one mark, one meaning:
@@ -13112,22 +13111,58 @@ const errorIsDisplayed = (error) => {
13112
13111
  };
13113
13112
 
13114
13113
  /**
13115
- * Reported from a macrotask: every render that could display the error
13116
- * Preact's own queue, a Suspense boundary settling on the failure, the error
13117
- * boundary above it — happens in microtasks, so by the time this runs the
13118
- * answer is final. A screen that would display the error much later than that
13119
- * (mounted by something slower than a render) is reported anyway; it is the
13120
- * one case where this says "nobody" a bit too early, and the report is then a
13121
- * duplicate of what the screen shows rather than a lie about it.
13122
- *
13123
- * Rethrown rather than logged: an error nobody shows is an unhandled error, and
13114
+ * A render has read this error it is now the render tree's business, not this
13115
+ * module's, and there is nothing left to report.
13116
+ *
13117
+ * Whatever the reader does with it is already covered without any deadline: it
13118
+ * displays it (and marks it), or it throws it, and a thrown error either finds a
13119
+ * boundary that displays it or reaches window on its own `preact/debug`
13120
+ * re-throws every error a boundary caught, and an unbounded one aborts the
13121
+ * render loudly. Reporting it here as well would be a second voice saying the
13122
+ * same thing, always the wrong one, since this module cannot see which of those
13123
+ * happened.
13124
+ */
13125
+ const errorTakenByRenderSet = new WeakSet();
13126
+ const markErrorAsTakenByRender = (error) => {
13127
+ if (error && typeof error === "object") {
13128
+ errorTakenByRenderSet.add(error);
13129
+ }
13130
+ };
13131
+
13132
+ /**
13133
+ * When the answer "nobody took it" is final.
13134
+ *
13135
+ * The floor is one macrotask: every render that could take the error — Preact's
13136
+ * queue, a Suspense boundary settling on the failure, the boundary above it —
13137
+ * happens in microtasks.
13138
+ *
13139
+ * That floor is enough for an action failing under a page that is already on
13140
+ * screen, and far too early for a route action: it fails ON the url change,
13141
+ * before its page exists, and that page cannot render until the routing that
13142
+ * asked for the data is over. Measured on an offline navigation, the screen
13143
+ * displaying the error arrived ~12ms after this deadline — so the app was told
13144
+ * it had displayed nothing while it was displaying it.
13145
+ *
13146
+ * The browser integration knows when the document has stopped moving and hands
13147
+ * that over here (see installReportDeadlineExtension); nothing else does, and
13148
+ * this module stays free of the DOM. Waiting longer costs nothing now that a
13149
+ * read is enough to call this off: what still reaches the report was read by no
13150
+ * render at all, and a late report about that is as good as a prompt one.
13151
+ */
13152
+ let waitForDocumentSettled = null;
13153
+ const installReportDeadlineExtension = (fn) => {
13154
+ waitForDocumentSettled = fn;
13155
+ };
13156
+
13157
+ /**
13158
+ * Rethrown rather than logged: an error nobody took is an unhandled error, and
13124
13159
  * the runtime already knows what to do with those (window "error" event, jsenv
13125
13160
  * overlay in dev). Same trick preact/debug uses for the same reason.
13126
13161
  */
13127
13162
  const errorReportedSet = new WeakSet();
13128
13163
  const reportErrorIfNobodyDisplaysIt = (error, { action } = {}) => {
13129
- setTimeout(() => {
13130
- if (errorIsDisplayed(error)) {
13164
+ const decide = () => {
13165
+ if (errorIsDisplayed(error) || errorTakenByRenderSet.has(error)) {
13131
13166
  return;
13132
13167
  }
13133
13168
  if (error && typeof error === "object") {
@@ -13143,6 +13178,19 @@ const reportErrorIfNobodyDisplaysIt = (error, { action } = {}) => {
13143
13178
  error.action = action;
13144
13179
  }
13145
13180
  throw error;
13181
+ };
13182
+
13183
+ setTimeout(() => {
13184
+ if (errorIsDisplayed(error) || errorTakenByRenderSet.has(error)) {
13185
+ // Already taken within the microtasks that followed the failure: the
13186
+ // common case, and there is nothing to wait for.
13187
+ return;
13188
+ }
13189
+ if (waitForDocumentSettled) {
13190
+ waitForDocumentSettled(decide);
13191
+ return;
13192
+ }
13193
+ decide();
13146
13194
  });
13147
13195
  };
13148
13196
 
@@ -22102,6 +22150,39 @@ const browserIntegration = setupBrowserIntegrationViaHistory({
22102
22150
  isRouting: () => Boolean(updateRoutes),
22103
22151
  });
22104
22152
 
22153
+ /**
22154
+ * How long an error that nothing displayed is given before it is called
22155
+ * unhandled (see action_error_report.js, which knows the rule but not the DOM).
22156
+ *
22157
+ * A route action fails ON the url change, before its page exists: it is the
22158
+ * routing itself that will bring what displays the error, so the answer is only
22159
+ * final once the document has stopped moving AND the frame that paints what it
22160
+ * brought has been through. Anything faster tells an app displaying "you are
22161
+ * offline" that it displayed nothing.
22162
+ */
22163
+ installReportDeadlineExtension((decide) => {
22164
+ const whenPainted = () => {
22165
+ // The frame that paints what routing brought, then the microtasks after it:
22166
+ // a render claiming the error is on either side of that paint, never later.
22167
+ requestAnimationFrame(() => {
22168
+ setTimeout(decide);
22169
+ });
22170
+ };
22171
+ if (!documentIsBusySignal.peek()) {
22172
+ whenPainted();
22173
+ return;
22174
+ }
22175
+ // Busy right now, so the synchronous first callback of subscribe() says
22176
+ // "busy" and is skipped; what unsubscribes below is a later one.
22177
+ const unsubscribe = documentIsBusySignal.subscribe((documentIsBusy) => {
22178
+ if (documentIsBusy) {
22179
+ return;
22180
+ }
22181
+ unsubscribe();
22182
+ whenPainted();
22183
+ });
22184
+ });
22185
+
22105
22186
  setOnAllRouteReady((v) => {
22106
22187
  updateRoutes = v;
22107
22188
  browserIntegration.init();
@@ -35861,6 +35942,10 @@ const useActionAsyncData = (action, {
35861
35942
  throw dismissedPromise;
35862
35943
  }
35863
35944
  const actionError = action.errorSignal.peek();
35945
+ // A render has it now, whichever way it goes from here (see
35946
+ // action_error_report.js): displayed below, or thrown to a boundary that
35947
+ // displays it — and if none does, the throw reaches window on its own.
35948
+ markErrorAsTakenByRender(actionError);
35864
35949
  if (errorEffect === "use") {
35865
35950
  // Handed to the component, which is what displays it from here on
35866
35951
  // (see action_error_report.js)
@@ -71839,5 +71924,5 @@ const UserSvg = () => jsx("svg", {
71839
71924
  })
71840
71925
  });
71841
71926
 
71842
- export { ActionRenderer, ActiveKeyboardShortcuts, Address, Badge, BadgeCount, BadgeList, Binder, Box, Button, ButtonCopyToClipboard, Caption, CardLayout, CheckSvg, CheckboxGroup, CloseSvg, Code, Col, Colgroup, Color, ConstructionSvg, ControlGroup, DaySpin, Details, Dialog, Editable, ErrorBoundary, ErrorBoundaryContext, ExclamationSvg, EyeClosedSvg, EyeSvg, Field, FixedBar, Form, Group, Head, HeartSvg, HomeSvg, Icon, Image, Input, InputDuration, Interpolate, Label, Link, LinkAnchorSvg, LinkBlankTargetSvg, LinkCurrentSvg, List, ListItem, ListItemGroup, ListItems, Loading, LoadingDotsSvg, LoadingIndicator, LoadingIndicatorFluid, LoadingOutline, MessageBox, Meter, Nav, NaviDebug, NumberSpin, Paragraph, Picker, Popover, Popup, Quantity, RadioGroup, Route, RouteTravel, RowNumberCol, RowNumberTableCell, SVGMaskOverlay, SearchSvg, Select, SelectableInput, SelectionContext, Separator, SettingsSvg, SidePanel, Slide, SlideContainer, Spin, SpinGroup, StarSvg, SummaryMarker, Svg, Table, TableCell, Tbody, Text, TextBox, Textarea, TextareaCharCount, Thead, Time, TimeRangeSpin, TimeSpin, Title, Tr, UITransition, Unit, UserSvg, ViewportLayout, Wheel, WheelGroup, WheelItem, actionRunEffect, anyMatchingRouteSignal, applySearch, arraySignalMembership, compareTwoJsValues, createAction, createAvailableConstraint, createI18n, createRequestCanceller, createSearch, createSelectionKeyboardShortcuts, createSlot, defineInteractionDetector, defineNaviConfirmPopupOptions, detectHorizontalOverflow, enableDebugActions, enableDebugOnDocumentLoading, ensureDocumentStartViewTransition, filterTableSelection, formatDatetime, formatDay, formatDayRelative, formatMonth, formatNumber, formatTime, formatTimeRelative, getNowHours, getNowHoursRoundedToStep, interpolateText, isCellSelected, isColumnSelected, isRowSelected, isScrolling, isToday, languagesSignal, localStorageSignal, moveArrayItemByIndex, navBack, navForward, navIntegratedVia, navTo, naviI18n, openCallout, rawUrlPart, registerGlobalConstraint, reload, rerunActions, resource, route, routeAction, scrollActivitySignal, setBaseUrl, setPreferredLanguage, setSupportedLanguages, setUrlTargetOptions, setupRoutes, smallTouchScreenSignal, stateSignal, stopLoad, stringifyTableSelectionValue, swapArrayItemByIndex, syncOwnedResourceToSignals, syncResourceToSignals, triggerNaviCommand, updateActions, useActionStatus, useArraySignalMembership, useAsyncData, useCalloutRequestClose, useCancelPrevious, useCellGridFromRows, useConstraintValidityState, useDependenciesDiff, useDisplayedLayoutEffect, useDocumentResource, useDocumentState, useDocumentUrl, useEditionController, useFocusGroup, useInputGroup, useKeyboardShortcuts, useNavState, useOrderedColumns, usePopupMode, useRouteStatus, useRunOnMount, useSearchText, useSelectableElement, useSelectionController, useSignalSync, useSlideValue, useStateArray, useTitleLevel, useUrlSearchParam, useUrlTargetId, valueInLocalStorage, windowWidthSignal };
71927
+ export { ActionRenderer, ActiveKeyboardShortcuts, Address, Badge, BadgeCount, BadgeList, Binder, Box, Button, ButtonCopyToClipboard, Caption, CardLayout, CheckSvg, CheckboxGroup, CloseSvg, Code, Col, Colgroup, Color, ConstructionSvg, ControlGroup, DaySpin, Details, Dialog, Editable, ErrorBoundary, ErrorBoundaryContext, ExclamationSvg, EyeClosedSvg, EyeSvg, Field, FixedBar, Form, Group, Head, HeartSvg, HomeSvg, Icon, Image, Input, InputDuration, Interpolate, Label, Link, LinkAnchorSvg, LinkBlankTargetSvg, LinkCurrentSvg, List, ListItem, ListItemGroup, ListItems, Loading, LoadingDotsSvg, LoadingIndicator, LoadingIndicatorFluid, LoadingOutline, MessageBox, Meter, Nav, NaviDebug, NumberSpin, Paragraph, Picker, Popover, Popup, Quantity, RadioGroup, Route, RouteTravel, RowNumberCol, RowNumberTableCell, SVGMaskOverlay, SearchSvg, Select, SelectableInput, SelectionContext, Separator, SettingsSvg, SidePanel, Slide, SlideContainer, Spin, SpinGroup, StarSvg, SummaryMarker, Svg, Table, TableCell, Tbody, Text, TextBox, Textarea, TextareaCharCount, Thead, Time, TimeRangeSpin, TimeSpin, Title, Tr, UITransition, Unit, UserSvg, ViewportLayout, Wheel, WheelGroup, WheelItem, actionRunEffect, anyMatchingRouteSignal, applySearch, arraySignalMembership, compareTwoJsValues, createAction, createAvailableConstraint, createI18n, createRequestCanceller, createSearch, createSelectionKeyboardShortcuts, createSlot, defineInteractionDetector, defineNaviConfirmPopupOptions, detectHorizontalOverflow, enableDebugActions, enableDebugOnDocumentLoading, ensureDocumentStartViewTransition, errorIsDisplayed, filterTableSelection, formatDatetime, formatDay, formatDayRelative, formatMonth, formatNumber, formatTime, formatTimeRelative, getNowHours, getNowHoursRoundedToStep, interpolateText, isCellSelected, isColumnSelected, isRowSelected, isScrolling, isToday, languagesSignal, localStorageSignal, markErrorAsDisplayedBy, moveArrayItemByIndex, navBack, navForward, navIntegratedVia, navTo, naviI18n, openCallout, rawUrlPart, registerGlobalConstraint, reload, rerunActions, resource, route, routeAction, scrollActivitySignal, setBaseUrl, setPreferredLanguage, setSupportedLanguages, setUrlTargetOptions, setupRoutes, smallTouchScreenSignal, stateSignal, stopLoad, stringifyTableSelectionValue, swapArrayItemByIndex, syncOwnedResourceToSignals, syncResourceToSignals, triggerNaviCommand, updateActions, useActionStatus, useArraySignalMembership, useAsyncData, useCalloutRequestClose, useCancelPrevious, useCellGridFromRows, useConstraintValidityState, useDependenciesDiff, useDisplayedLayoutEffect, useDocumentResource, useDocumentState, useDocumentUrl, useEditionController, useFocusGroup, useInputGroup, useKeyboardShortcuts, useNavState, useOrderedColumns, usePopupMode, useRouteStatus, useRunOnMount, useSearchText, useSelectableElement, useSelectionController, useSignalSync, useSlideValue, useStateArray, useTitleLevel, useUrlSearchParam, useUrlTargetId, valueInLocalStorage, windowWidthSignal };
71843
71928
  //# sourceMappingURL=jsenv_navi.js.map