ropegeo-common 1.12.11 → 1.12.13

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.
@@ -44,6 +44,12 @@ export type RopeGeoCursorPaginationHttpRequestProps<T = unknown> = {
44
44
  loadMore: () => void;
45
45
  hasMore: boolean;
46
46
  timeoutCountdown: number | null;
47
+ /**
48
+ * Re-runs from the first page while online: aborts any `loadMore`, resets the cursor to the
49
+ * initial `queryParams`, sets `loading` to `true`, clears `errors`, and clears `data` until the
50
+ * new first page resolves. No-op when `isOnline` is `false`.
51
+ */
52
+ reload: () => void;
47
53
  }) => ReactNode;
48
54
  };
49
55
  export declare function RopeGeoCursorPaginationHttpRequest<T = unknown>({ service, method, path, pathParams, queryParams, timeoutAfterSeconds, isOnline, refreshOnReconnect, children, }: RopeGeoCursorPaginationHttpRequestProps<T>): import("react/jsx-runtime").JSX.Element;
@@ -1 +1 @@
1
- {"version":3,"file":"RopeGeoCursorPaginationHttpRequest.d.ts","sourceRoot":"","sources":["../../src/components/RopeGeoCursorPaginationHttpRequest.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AASvC,OAAO,EACL,KAAK,sBAAsB,EAE5B,MAAM,WAAW,CAAC;AACnB,OAAO,EAAE,MAAM,EAAE,OAAO,EAAoB,MAAM,sBAAsB,CAAC;AAsCzE,MAAM,MAAM,uCAAuC,CAAC,CAAC,GAAG,OAAO,IAAI;IACjE,OAAO,EAAE,OAAO,CAAC;IACjB,MAAM,CAAC,EAAE,CAAC,OAAO,MAAM,CAAC,CAAC,MAAM,OAAO,MAAM,CAAC,CAAC;IAC9C,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACpC,WAAW,EAAE,sBAAsB,CAAC;IACpC;;;OAGG;IACH,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B;;;OAGG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB;;;;;;OAMG;IACH,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAC7B;;;;;OAKG;IACH,QAAQ,EAAE,CAAC,IAAI,EAAE;QACf,OAAO,EAAE,OAAO,CAAC;QACjB,WAAW,EAAE,OAAO,CAAC;QACrB;;;WAGG;QACH,UAAU,EAAE,OAAO,CAAC;QACpB,IAAI,EAAE,CAAC,EAAE,GAAG,IAAI,CAAC;QACjB,MAAM,EAAE,KAAK,GAAG,IAAI,CAAC;QACrB,QAAQ,EAAE,MAAM,IAAI,CAAC;QACrB,OAAO,EAAE,OAAO,CAAC;QACjB,gBAAgB,EAAE,MAAM,GAAG,IAAI,CAAC;KACjC,KAAK,SAAS,CAAC;CACjB,CAAC;AAEF,wBAAgB,kCAAkC,CAAC,CAAC,GAAG,OAAO,EAAE,EAC9D,OAAO,EACP,MAAmB,EACnB,IAAI,EACJ,UAAU,EACV,WAAW,EACX,mBAAmB,EACnB,QAAQ,EACR,kBAA0B,EAC1B,QAAQ,GACT,EAAE,uCAAuC,CAAC,CAAC,CAAC,2CA6U5C"}
1
+ {"version":3,"file":"RopeGeoCursorPaginationHttpRequest.d.ts","sourceRoot":"","sources":["../../src/components/RopeGeoCursorPaginationHttpRequest.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAWvC,OAAO,EACL,KAAK,sBAAsB,EAE5B,MAAM,WAAW,CAAC;AACnB,OAAO,EAAE,MAAM,EAAE,OAAO,EAAoB,MAAM,sBAAsB,CAAC;AAsCzE,MAAM,MAAM,uCAAuC,CAAC,CAAC,GAAG,OAAO,IAAI;IACjE,OAAO,EAAE,OAAO,CAAC;IACjB,MAAM,CAAC,EAAE,CAAC,OAAO,MAAM,CAAC,CAAC,MAAM,OAAO,MAAM,CAAC,CAAC;IAC9C,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACpC,WAAW,EAAE,sBAAsB,CAAC;IACpC;;;OAGG;IACH,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B;;;OAGG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB;;;;;;OAMG;IACH,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAC7B;;;;;OAKG;IACH,QAAQ,EAAE,CAAC,IAAI,EAAE;QACf,OAAO,EAAE,OAAO,CAAC;QACjB,WAAW,EAAE,OAAO,CAAC;QACrB;;;WAGG;QACH,UAAU,EAAE,OAAO,CAAC;QACpB,IAAI,EAAE,CAAC,EAAE,GAAG,IAAI,CAAC;QACjB,MAAM,EAAE,KAAK,GAAG,IAAI,CAAC;QACrB,QAAQ,EAAE,MAAM,IAAI,CAAC;QACrB,OAAO,EAAE,OAAO,CAAC;QACjB,gBAAgB,EAAE,MAAM,GAAG,IAAI,CAAC;QAChC;;;;WAIG;QACH,MAAM,EAAE,MAAM,IAAI,CAAC;KACpB,KAAK,SAAS,CAAC;CACjB,CAAC;AAEF,wBAAgB,kCAAkC,CAAC,CAAC,GAAG,OAAO,EAAE,EAC9D,OAAO,EACP,MAAmB,EACnB,IAAI,EACJ,UAAU,EACV,WAAW,EACX,mBAAmB,EACnB,QAAQ,EACR,kBAA0B,EAC1B,QAAQ,GACT,EAAE,uCAAuC,CAAC,CAAC,CAAC,2CAkX5C"}
@@ -38,6 +38,8 @@ function RopeGeoCursorPaginationHttpRequest({ service, method = RopeGeoHttpReque
38
38
  const [errors, setErrors] = (0, react_1.useState)(null);
39
39
  const [timeoutCountdown, setTimeoutCountdown] = (0, react_1.useState)(null);
40
40
  const [hasCommittedOnce, setHasCommittedOnce] = (0, react_1.useState)(false);
41
+ const [reloadTick, setReloadTick] = (0, react_1.useState)(0);
42
+ const pendingReloadRef = (0, react_1.useRef)(false);
41
43
  const errorsRef = (0, react_1.useRef)(errors);
42
44
  const hasCommittedRef = (0, react_1.useRef)(hasCommittedOnce);
43
45
  errorsRef.current = errors;
@@ -57,12 +59,27 @@ function RopeGeoCursorPaginationHttpRequest({ service, method = RopeGeoHttpReque
57
59
  const fullPath = queryString ? `${resolvedPath}?${queryString}` : resolvedPath;
58
60
  return new URL(fullPath, baseUrl).toString();
59
61
  }, [service, path, pathParams]);
62
+ const reload = (0, react_1.useCallback)(() => {
63
+ if (isOnline === false)
64
+ return;
65
+ pendingReloadRef.current = true;
66
+ setReloadTick((n) => n + 1);
67
+ }, [isOnline]);
60
68
  (0, react_1.useEffect)(() => {
61
69
  const online = isOnline !== false;
62
70
  const prevOnline = prevIsOnlineRef.current;
63
71
  const reconnecting = prevOnline === false && online;
64
72
  const keyChanged = lastRequestKeyRef.current !== requestKey;
73
+ const isManualReload = pendingReloadRef.current;
74
+ if (isManualReload) {
75
+ pendingReloadRef.current = false;
76
+ loadMoreAbortRef.current?.abort();
77
+ loadMoreAbortRef.current = null;
78
+ loadingMoreRef.current = false;
79
+ setLoadingMore(false);
80
+ }
65
81
  if (!online) {
82
+ pendingReloadRef.current = false;
66
83
  if (keyChanged) {
67
84
  lastRequestKeyRef.current = requestKey;
68
85
  setData(null);
@@ -87,9 +104,18 @@ function RopeGeoCursorPaginationHttpRequest({ service, method = RopeGeoHttpReque
87
104
  setParams(queryParams);
88
105
  setErrors(null);
89
106
  }
107
+ else if (isManualReload) {
108
+ setHasCommittedOnce(false);
109
+ setData(null);
110
+ setParams(queryParams);
111
+ setErrors(null);
112
+ }
90
113
  if (!keyChanged && reconnecting) {
91
114
  const onlyNoNetwork = errorsRef.current?.message === network_1.NO_NETWORK_MESSAGE;
92
- if (hasCommittedRef.current && onlyNoNetwork && !refreshOnReconnect) {
115
+ if (!isManualReload &&
116
+ hasCommittedRef.current &&
117
+ onlyNoNetwork &&
118
+ !refreshOnReconnect) {
93
119
  setErrors(null);
94
120
  setLoading(false);
95
121
  prevIsOnlineRef.current = true;
@@ -109,7 +135,7 @@ function RopeGeoCursorPaginationHttpRequest({ service, method = RopeGeoHttpReque
109
135
  hasCommittedRef.current &&
110
136
  errorsRef.current?.message === network_1.NO_NETWORK_MESSAGE &&
111
137
  refreshOnReconnect;
112
- if (!keyChanged && !keepStaleDuringFetch) {
138
+ if (!keyChanged && !keepStaleDuringFetch && !isManualReload) {
113
139
  setData(null);
114
140
  setParams(queryParams);
115
141
  }
@@ -142,7 +168,7 @@ function RopeGeoCursorPaginationHttpRequest({ service, method = RopeGeoHttpReque
142
168
  return;
143
169
  const text = await res.text();
144
170
  if (!res.ok) {
145
- setErrors(new Error(`HTTP ${res.status}: ${text || res.statusText}`));
171
+ setErrors(new Error((0, network_1.formatHttpStatusMessage)(res.status, text || res.statusText)));
146
172
  setData(null);
147
173
  setHasCommittedOnce(false);
148
174
  return;
@@ -184,7 +210,7 @@ function RopeGeoCursorPaginationHttpRequest({ service, method = RopeGeoHttpReque
184
210
  if (cancelled)
185
211
  return;
186
212
  if (timedOutRef.current) {
187
- setErrors(new Error(network_1.NETWORK_REQUEST_TIMED_OUT_MESSAGE));
213
+ setErrors(new Error((0, network_1.formatNetworkRequestErrorMessage)(new Error(network_1.NETWORK_REQUEST_TIMED_OUT_MESSAGE))));
188
214
  setData(null);
189
215
  setHasCommittedOnce(false);
190
216
  return;
@@ -195,7 +221,7 @@ function RopeGeoCursorPaginationHttpRequest({ service, method = RopeGeoHttpReque
195
221
  url,
196
222
  error: err instanceof Error ? err.message : String(err),
197
223
  });
198
- setErrors(err instanceof Error ? err : new Error(String(err)));
224
+ setErrors(new Error((0, network_1.formatNetworkRequestErrorMessage)(err)));
199
225
  setData(null);
200
226
  setHasCommittedOnce(false);
201
227
  })
@@ -222,6 +248,7 @@ function RopeGeoCursorPaginationHttpRequest({ service, method = RopeGeoHttpReque
222
248
  isOnline,
223
249
  refreshOnReconnect,
224
250
  requestKey,
251
+ reloadTick,
225
252
  ]);
226
253
  (0, react_1.useEffect)(() => {
227
254
  return () => {
@@ -325,5 +352,6 @@ function RopeGeoCursorPaginationHttpRequest({ service, method = RopeGeoHttpReque
325
352
  loadMore,
326
353
  hasMore,
327
354
  timeoutCountdown,
355
+ reload,
328
356
  }) }));
329
357
  }
@@ -56,6 +56,12 @@ export type RopeGeoHttpRequestProps<T = unknown> = {
56
56
  * after `NETWORK_REQUEST_SLOW_THRESHOLD_MS` from `ropegeo-common/helpers`).
57
57
  */
58
58
  timeoutCountdown: number | null;
59
+ /**
60
+ * Re-runs the current request while online. Sets `loading` to `true`, clears `errors`, and
61
+ * keeps existing `data` visible until the new response resolves (when data was already
62
+ * committed). No-op when `isOnline` is `false`.
63
+ */
64
+ reload: () => void;
59
65
  }) => ReactNode;
60
66
  };
61
67
  export declare function RopeGeoHttpRequest<T = unknown>({ service, method, path, pathParams, queryParams, body, timeoutAfterSeconds, isOnline, refreshOnReconnect, children, }: RopeGeoHttpRequestProps<T>): import("react/jsx-runtime").JSX.Element;
@@ -1 +1 @@
1
- {"version":3,"file":"RopeGeoHttpRequest.d.ts","sourceRoot":"","sources":["../../src/components/RopeGeoHttpRequest.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAWvC,eAAO,MAAM,OAAO;;CAEV,CAAC;AACX,MAAM,MAAM,OAAO,GAAG,CAAC,OAAO,OAAO,CAAC,CAAC,MAAM,OAAO,OAAO,CAAC,CAAC;AAE7D,eAAO,MAAM,MAAM;;;;;CAKT,CAAC;AACX,MAAM,MAAM,MAAM,GAAG,CAAC,OAAO,MAAM,CAAC,CAAC,MAAM,OAAO,MAAM,CAAC,CAAC;AAE1D,eAAO,MAAM,gBAAgB,EAAE,MAAM,CAAC,OAAO,EAAE,MAAM,CAEpD,CAAC;AAmCF,MAAM,MAAM,uBAAuB,CAAC,CAAC,GAAG,OAAO,IAAI;IACjD,OAAO,EAAE,OAAO,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACpC,WAAW,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,SAAS,CAAC,CAAC;IACpE,IAAI,CAAC,EAAE,MAAM,CAAC;IACd;;OAEG;IACH,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B;;;;;OAKG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB;;;;;;OAMG;IACH,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAC7B;;;OAGG;IACH,QAAQ,EAAE,CAAC,IAAI,EAAE;QACf,OAAO,EAAE,OAAO,CAAC;QACjB;;;WAGG;QACH,UAAU,EAAE,OAAO,CAAC;QACpB,IAAI,EAAE,CAAC,GAAG,IAAI,CAAC;QACf,MAAM,EAAE,KAAK,GAAG,IAAI,CAAC;QACrB;;;;WAIG;QACH,gBAAgB,EAAE,MAAM,GAAG,IAAI,CAAC;KACjC,KAAK,SAAS,CAAC;CACjB,CAAC;AAEF,wBAAgB,kBAAkB,CAAC,CAAC,GAAG,OAAO,EAAE,EAC9C,OAAO,EACP,MAAM,EACN,IAAI,EACJ,UAAU,EACV,WAAW,EACX,IAAI,EACJ,mBAAmB,EACnB,QAAQ,EACR,kBAA0B,EAC1B,QAAQ,GACT,EAAE,uBAAuB,CAAC,CAAC,CAAC,2CA0N5B"}
1
+ {"version":3,"file":"RopeGeoHttpRequest.d.ts","sourceRoot":"","sources":["../../src/components/RopeGeoHttpRequest.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAavC,eAAO,MAAM,OAAO;;CAEV,CAAC;AACX,MAAM,MAAM,OAAO,GAAG,CAAC,OAAO,OAAO,CAAC,CAAC,MAAM,OAAO,OAAO,CAAC,CAAC;AAE7D,eAAO,MAAM,MAAM;;;;;CAKT,CAAC;AACX,MAAM,MAAM,MAAM,GAAG,CAAC,OAAO,MAAM,CAAC,CAAC,MAAM,OAAO,MAAM,CAAC,CAAC;AAE1D,eAAO,MAAM,gBAAgB,EAAE,MAAM,CAAC,OAAO,EAAE,MAAM,CAEpD,CAAC;AAmCF,MAAM,MAAM,uBAAuB,CAAC,CAAC,GAAG,OAAO,IAAI;IACjD,OAAO,EAAE,OAAO,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACpC,WAAW,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,SAAS,CAAC,CAAC;IACpE,IAAI,CAAC,EAAE,MAAM,CAAC;IACd;;OAEG;IACH,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B;;;;;OAKG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB;;;;;;OAMG;IACH,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAC7B;;;OAGG;IACH,QAAQ,EAAE,CAAC,IAAI,EAAE;QACf,OAAO,EAAE,OAAO,CAAC;QACjB;;;WAGG;QACH,UAAU,EAAE,OAAO,CAAC;QACpB,IAAI,EAAE,CAAC,GAAG,IAAI,CAAC;QACf,MAAM,EAAE,KAAK,GAAG,IAAI,CAAC;QACrB;;;;WAIG;QACH,gBAAgB,EAAE,MAAM,GAAG,IAAI,CAAC;QAChC;;;;WAIG;QACH,MAAM,EAAE,MAAM,IAAI,CAAC;KACpB,KAAK,SAAS,CAAC;CACjB,CAAC;AAEF,wBAAgB,kBAAkB,CAAC,CAAC,GAAG,OAAO,EAAE,EAC9C,OAAO,EACP,MAAM,EACN,IAAI,EACJ,UAAU,EACV,WAAW,EACX,IAAI,EACJ,mBAAmB,EACnB,QAAQ,EACR,kBAA0B,EAC1B,QAAQ,GACT,EAAE,uBAAuB,CAAC,CAAC,CAAC,2CAuP5B"}
@@ -46,10 +46,18 @@ function RopeGeoHttpRequest({ service, method, path, pathParams, queryParams, bo
46
46
  const [errors, setErrors] = (0, react_1.useState)(null);
47
47
  const [timeoutCountdown, setTimeoutCountdown] = (0, react_1.useState)(null);
48
48
  const [hasCommittedOnce, setHasCommittedOnce] = (0, react_1.useState)(false);
49
+ const [reloadTick, setReloadTick] = (0, react_1.useState)(0);
50
+ const pendingReloadRef = (0, react_1.useRef)(false);
49
51
  const errorsRef = (0, react_1.useRef)(errors);
50
52
  const hasCommittedRef = (0, react_1.useRef)(hasCommittedOnce);
51
53
  errorsRef.current = errors;
52
54
  hasCommittedRef.current = hasCommittedOnce;
55
+ const reload = (0, react_1.useCallback)(() => {
56
+ if (isOnline === false)
57
+ return;
58
+ pendingReloadRef.current = true;
59
+ setReloadTick((n) => n + 1);
60
+ }, [isOnline]);
53
61
  const pathParamsKey = JSON.stringify(pathParams ?? null);
54
62
  const queryParamsKey = JSON.stringify(queryParams ?? null);
55
63
  const bodyKey = body === undefined || body === null
@@ -65,7 +73,12 @@ function RopeGeoHttpRequest({ service, method, path, pathParams, queryParams, bo
65
73
  const prevOnline = prevIsOnlineRef.current;
66
74
  const reconnecting = prevOnline === false && online;
67
75
  const keyChanged = lastRequestKeyRef.current !== requestKey;
76
+ const isManualReload = pendingReloadRef.current;
77
+ if (isManualReload) {
78
+ pendingReloadRef.current = false;
79
+ }
68
80
  if (!online) {
81
+ pendingReloadRef.current = false;
69
82
  if (keyChanged) {
70
83
  lastRequestKeyRef.current = requestKey;
71
84
  setData(null);
@@ -86,7 +99,10 @@ function RopeGeoHttpRequest({ service, method, path, pathParams, queryParams, bo
86
99
  }
87
100
  if (!keyChanged && reconnecting) {
88
101
  const onlyNoNetwork = errorsRef.current?.message === network_1.NO_NETWORK_MESSAGE;
89
- if (hasCommittedRef.current && onlyNoNetwork && !refreshOnReconnect) {
102
+ if (!isManualReload &&
103
+ hasCommittedRef.current &&
104
+ onlyNoNetwork &&
105
+ !refreshOnReconnect) {
90
106
  setErrors(null);
91
107
  setLoading(false);
92
108
  prevIsOnlineRef.current = true;
@@ -106,7 +122,8 @@ function RopeGeoHttpRequest({ service, method, path, pathParams, queryParams, bo
106
122
  hasCommittedRef.current &&
107
123
  errorsRef.current?.message === network_1.NO_NETWORK_MESSAGE &&
108
124
  refreshOnReconnect;
109
- if (!keyChanged && !keepStaleDuringFetch) {
125
+ const keepStaleForManualReload = isManualReload && hasCommittedRef.current;
126
+ if (!keyChanged && !keepStaleDuringFetch && !keepStaleForManualReload) {
110
127
  setData(null);
111
128
  }
112
129
  const policyDispose = timeoutMs == null
@@ -144,7 +161,7 @@ function RopeGeoHttpRequest({ service, method, path, pathParams, queryParams, bo
144
161
  return;
145
162
  const text = await res.text();
146
163
  if (!res.ok) {
147
- setErrors(new Error(`HTTP ${res.status}: ${text || res.statusText}`));
164
+ setErrors(new Error((0, network_1.formatHttpStatusMessage)(res.status, text || res.statusText)));
148
165
  setData(null);
149
166
  setHasCommittedOnce(false);
150
167
  return;
@@ -182,7 +199,7 @@ function RopeGeoHttpRequest({ service, method, path, pathParams, queryParams, bo
182
199
  if (cancelled)
183
200
  return;
184
201
  if (timedOutRef.current) {
185
- setErrors(new Error(network_1.NETWORK_REQUEST_TIMED_OUT_MESSAGE));
202
+ setErrors(new Error((0, network_1.formatNetworkRequestErrorMessage)(new Error(network_1.NETWORK_REQUEST_TIMED_OUT_MESSAGE))));
186
203
  setData(null);
187
204
  setHasCommittedOnce(false);
188
205
  return;
@@ -193,7 +210,7 @@ function RopeGeoHttpRequest({ service, method, path, pathParams, queryParams, bo
193
210
  url,
194
211
  error: err instanceof Error ? err.message : String(err),
195
212
  });
196
- setErrors(err instanceof Error ? err : new Error(String(err)));
213
+ setErrors(new Error((0, network_1.formatNetworkRequestErrorMessage)(err)));
197
214
  setData(null);
198
215
  setHasCommittedOnce(false);
199
216
  })
@@ -220,6 +237,7 @@ function RopeGeoHttpRequest({ service, method, path, pathParams, queryParams, bo
220
237
  isOnline,
221
238
  refreshOnReconnect,
222
239
  requestKey,
240
+ reloadTick,
223
241
  ]);
224
242
  const refreshing = loading && hasCommittedOnce;
225
243
  return ((0, jsx_runtime_1.jsx)(jsx_runtime_1.Fragment, { children: children({
@@ -228,5 +246,6 @@ function RopeGeoHttpRequest({ service, method, path, pathParams, queryParams, bo
228
246
  data,
229
247
  errors,
230
248
  timeoutCountdown,
249
+ reload,
231
250
  }) }));
232
251
  }
@@ -51,6 +51,12 @@ export type RopeGeoPaginationHttpRequestProps<T = unknown> = {
51
51
  errors: Error | null;
52
52
  /** Timeout countdown for the active phase (initial page or current batch); `null` between phases. */
53
53
  timeoutCountdown: number | null;
54
+ /**
55
+ * Re-runs the full pagination pass while online. Sets `loading` to `true`, clears `errors`,
56
+ * and resets progress (`received` / `total` / `data`) until the new pass completes. No-op when
57
+ * `isOnline` is `false`.
58
+ */
59
+ reload: () => void;
54
60
  }) => ReactNode;
55
61
  };
56
62
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"RopeGeoPaginationHttpRequest.d.ts","sourceRoot":"","sources":["../../src/components/RopeGeoPaginationHttpRequest.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAUvC,OAAO,EACL,KAAK,gBAAgB,EAEtB,MAAM,WAAW,CAAC;AACnB,OAAO,EAAE,MAAM,EAAE,OAAO,EAAoB,MAAM,sBAAsB,CAAC;AA8DzE,MAAM,MAAM,iCAAiC,CAAC,CAAC,GAAG,OAAO,IAAI;IAC3D,OAAO,EAAE,OAAO,CAAC;IACjB,MAAM,CAAC,EAAE,CAAC,OAAO,MAAM,CAAC,CAAC,MAAM,OAAO,MAAM,CAAC,CAAC;IAC9C,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACpC,WAAW,EAAE,gBAAgB,CAAC;IAC9B;;;;OAIG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;;OAGG;IACH,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B;;;;;OAKG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB;;;;;;OAMG;IACH,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAC7B,QAAQ,EAAE,CAAC,IAAI,EAAE;QACf,OAAO,EAAE,OAAO,CAAC;QACjB;;;WAGG;QACH,UAAU,EAAE,OAAO,CAAC;QACpB,QAAQ,EAAE,MAAM,CAAC;QACjB,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;QACrB;;;WAGG;QACH,IAAI,EAAE,CAAC,EAAE,GAAG,IAAI,CAAC;QACjB,+FAA+F;QAC/F,MAAM,EAAE,KAAK,GAAG,IAAI,CAAC;QACrB,qGAAqG;QACrG,gBAAgB,EAAE,MAAM,GAAG,IAAI,CAAC;KACjC,KAAK,SAAS,CAAC;CACjB,CAAC;AAEF;;;;;GAKG;AACH,wBAAgB,4BAA4B,CAAC,CAAC,GAAG,OAAO,EAAE,EACxD,OAAO,EACP,MAAmB,EACnB,IAAI,EACJ,UAAU,EACV,WAAW,EACX,SAAc,EACd,mBAAmB,EACnB,QAAQ,EACR,kBAA0B,EAC1B,QAAQ,GACT,EAAE,iCAAiC,CAAC,CAAC,CAAC,2CAqTtC"}
1
+ {"version":3,"file":"RopeGeoPaginationHttpRequest.d.ts","sourceRoot":"","sources":["../../src/components/RopeGeoPaginationHttpRequest.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAYvC,OAAO,EACL,KAAK,gBAAgB,EAEtB,MAAM,WAAW,CAAC;AACnB,OAAO,EAAE,MAAM,EAAE,OAAO,EAAoB,MAAM,sBAAsB,CAAC;AA8DzE,MAAM,MAAM,iCAAiC,CAAC,CAAC,GAAG,OAAO,IAAI;IAC3D,OAAO,EAAE,OAAO,CAAC;IACjB,MAAM,CAAC,EAAE,CAAC,OAAO,MAAM,CAAC,CAAC,MAAM,OAAO,MAAM,CAAC,CAAC;IAC9C,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACpC,WAAW,EAAE,gBAAgB,CAAC;IAC9B;;;;OAIG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;;OAGG;IACH,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B;;;;;OAKG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB;;;;;;OAMG;IACH,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAC7B,QAAQ,EAAE,CAAC,IAAI,EAAE;QACf,OAAO,EAAE,OAAO,CAAC;QACjB;;;WAGG;QACH,UAAU,EAAE,OAAO,CAAC;QACpB,QAAQ,EAAE,MAAM,CAAC;QACjB,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;QACrB;;;WAGG;QACH,IAAI,EAAE,CAAC,EAAE,GAAG,IAAI,CAAC;QACjB,+FAA+F;QAC/F,MAAM,EAAE,KAAK,GAAG,IAAI,CAAC;QACrB,qGAAqG;QACrG,gBAAgB,EAAE,MAAM,GAAG,IAAI,CAAC;QAChC;;;;WAIG;QACH,MAAM,EAAE,MAAM,IAAI,CAAC;KACpB,KAAK,SAAS,CAAC;CACjB,CAAC;AAEF;;;;;GAKG;AACH,wBAAgB,4BAA4B,CAAC,CAAC,GAAG,OAAO,EAAE,EACxD,OAAO,EACP,MAAmB,EACnB,IAAI,EACJ,UAAU,EACV,WAAW,EACX,SAAc,EACd,mBAAmB,EACnB,QAAQ,EACR,kBAA0B,EAC1B,QAAQ,GACT,EAAE,iCAAiC,CAAC,CAAC,CAAC,2CAmVtC"}
@@ -65,6 +65,8 @@ function RopeGeoPaginationHttpRequest({ service, method = RopeGeoHttpRequest_1.M
65
65
  const [errors, setErrors] = (0, react_1.useState)(null);
66
66
  const [timeoutCountdown, setTimeoutCountdown] = (0, react_1.useState)(null);
67
67
  const [hasCommittedOnce, setHasCommittedOnce] = (0, react_1.useState)(false);
68
+ const [reloadTick, setReloadTick] = (0, react_1.useState)(0);
69
+ const pendingReloadRef = (0, react_1.useRef)(false);
68
70
  const errorsRef = (0, react_1.useRef)(errors);
69
71
  const hasCommittedRef = (0, react_1.useRef)(hasCommittedOnce);
70
72
  errorsRef.current = errors;
@@ -75,12 +77,23 @@ function RopeGeoPaginationHttpRequest({ service, method = RopeGeoHttpRequest_1.M
75
77
  const requestKey = (0, react_1.useMemo)(() => `${service}|${method}|${path}|${pathParamsKey}|${queryParamsKey}|${effectiveBatch}|${timeoutAfterSeconds ?? ""}`, [service, method, path, pathParamsKey, queryParamsKey, effectiveBatch, timeoutAfterSeconds]);
76
78
  const prevIsOnlineRef = (0, react_1.useRef)(undefined);
77
79
  const lastRequestKeyRef = (0, react_1.useRef)("");
80
+ const reload = (0, react_1.useCallback)(() => {
81
+ if (isOnline === false)
82
+ return;
83
+ pendingReloadRef.current = true;
84
+ setReloadTick((n) => n + 1);
85
+ }, [isOnline]);
78
86
  (0, react_1.useEffect)(() => {
79
87
  const online = isOnline !== false;
80
88
  const prevOnline = prevIsOnlineRef.current;
81
89
  const reconnecting = prevOnline === false && online;
82
90
  const keyChanged = lastRequestKeyRef.current !== requestKey;
91
+ const isManualReload = pendingReloadRef.current;
92
+ if (isManualReload) {
93
+ pendingReloadRef.current = false;
94
+ }
83
95
  if (!online) {
96
+ pendingReloadRef.current = false;
84
97
  if (keyChanged) {
85
98
  lastRequestKeyRef.current = requestKey;
86
99
  setHasCommittedOnce(false);
@@ -103,9 +116,19 @@ function RopeGeoPaginationHttpRequest({ service, method = RopeGeoHttpRequest_1.M
103
116
  setData(null);
104
117
  setErrors(null);
105
118
  }
119
+ else if (isManualReload) {
120
+ setHasCommittedOnce(false);
121
+ setReceived(0);
122
+ setTotal(null);
123
+ setData(null);
124
+ setErrors(null);
125
+ }
106
126
  if (!keyChanged && reconnecting) {
107
127
  const onlyNoNetwork = errorsRef.current?.message === network_1.NO_NETWORK_MESSAGE;
108
- if (hasCommittedRef.current && onlyNoNetwork && !refreshOnReconnect) {
128
+ if (!isManualReload &&
129
+ hasCommittedRef.current &&
130
+ onlyNoNetwork &&
131
+ !refreshOnReconnect) {
109
132
  setErrors(null);
110
133
  setLoading(false);
111
134
  prevIsOnlineRef.current = true;
@@ -124,7 +147,7 @@ function RopeGeoPaginationHttpRequest({ service, method = RopeGeoHttpRequest_1.M
124
147
  hasCommittedRef.current &&
125
148
  errorsRef.current?.message === network_1.NO_NETWORK_MESSAGE &&
126
149
  refreshOnReconnect;
127
- if (!keyChanged && !keepStaleDuringFetch) {
150
+ if (!keyChanged && !keepStaleDuringFetch && !isManualReload) {
128
151
  setReceived(0);
129
152
  setTotal(null);
130
153
  setData(null);
@@ -204,7 +227,7 @@ function RopeGeoPaginationHttpRequest({ service, method = RopeGeoHttpRequest_1.M
204
227
  const text = await res.text();
205
228
  if (!res.ok) {
206
229
  abortController.abort();
207
- throw new Error(`HTTP ${res.status}: ${text || res.statusText}`);
230
+ throw new Error((0, network_1.formatHttpStatusMessage)(res.status, text || res.statusText));
208
231
  }
209
232
  if (text.length === 0) {
210
233
  abortController.abort();
@@ -238,7 +261,7 @@ function RopeGeoPaginationHttpRequest({ service, method = RopeGeoHttpRequest_1.M
238
261
  catch (err) {
239
262
  if (pageNum !== 1 && merged != null && merged.consumeDidTimeout()) {
240
263
  abortController.abort();
241
- throw new Error(network_1.NETWORK_REQUEST_TIMED_OUT_MESSAGE);
264
+ throw new Error((0, network_1.formatNetworkRequestErrorMessage)(new Error(network_1.NETWORK_REQUEST_TIMED_OUT_MESSAGE)));
242
265
  }
243
266
  throw err;
244
267
  }
@@ -301,7 +324,7 @@ function RopeGeoPaginationHttpRequest({ service, method = RopeGeoHttpRequest_1.M
301
324
  console.error("[RopeGeoPaginationHttpRequest] Request failed", {
302
325
  error: err instanceof Error ? err.message : String(err),
303
326
  });
304
- setErrors(err instanceof Error ? err : new Error(String(err)));
327
+ setErrors(new Error((0, network_1.formatNetworkRequestErrorMessage)(err)));
305
328
  setData(null);
306
329
  setHasCommittedOnce(false);
307
330
  }
@@ -326,6 +349,7 @@ function RopeGeoPaginationHttpRequest({ service, method = RopeGeoHttpRequest_1.M
326
349
  isOnline,
327
350
  refreshOnReconnect,
328
351
  requestKey,
352
+ reloadTick,
329
353
  ]);
330
354
  const refreshing = loading && hasCommittedOnce;
331
355
  return ((0, jsx_runtime_1.jsx)(jsx_runtime_1.Fragment, { children: children({
@@ -336,5 +360,6 @@ function RopeGeoPaginationHttpRequest({ service, method = RopeGeoHttpRequest_1.M
336
360
  data,
337
361
  errors,
338
362
  timeoutCountdown,
363
+ reload,
339
364
  }) }));
340
365
  }
@@ -3,5 +3,5 @@
3
3
  * Published as `ropegeo-common/helpers/network`. Prefer this entry over `ropegeo-common/helpers` in
4
4
  * Metro/RN bundles so the full helpers barrel (S3 folder upload, etc.) is not resolved.
5
5
  */
6
- export { NETWORK_REQUEST_TIMED_OUT_MESSAGE, NO_NETWORK_MESSAGE, installNetworkRequestPolicyTimers, isAbortError, isNetworkRequestTimeoutError, mergeParentSignalWithDeadline, resolveRequestTimeoutMs, type MergedDeadlineHandles, type NetworkRequestPolicyTimerCallbacks, } from "./networkRequestPolicy";
6
+ export { formatHttpStatusMessage, formatNetworkRequestErrorMessage, NETWORK_REQUEST_TIMED_OUT_MESSAGE, NO_NETWORK_MESSAGE, installNetworkRequestPolicyTimers, isAbortError, isNetworkRequestTimeoutError, mergeParentSignalWithDeadline, resolveRequestTimeoutMs, type MergedDeadlineHandles, type NetworkRequestPolicyTimerCallbacks, } from "./networkRequestPolicy";
7
7
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/helpers/network/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EACL,iCAAiC,EACjC,kBAAkB,EAClB,iCAAiC,EACjC,YAAY,EACZ,4BAA4B,EAC5B,6BAA6B,EAC7B,uBAAuB,EACvB,KAAK,qBAAqB,EAC1B,KAAK,kCAAkC,GACxC,MAAM,wBAAwB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/helpers/network/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EACL,uBAAuB,EACvB,gCAAgC,EAChC,iCAAiC,EACjC,kBAAkB,EAClB,iCAAiC,EACjC,YAAY,EACZ,4BAA4B,EAC5B,6BAA6B,EAC7B,uBAAuB,EACvB,KAAK,qBAAqB,EAC1B,KAAK,kCAAkC,GACxC,MAAM,wBAAwB,CAAC"}
@@ -5,8 +5,10 @@
5
5
  * Metro/RN bundles so the full helpers barrel (S3 folder upload, etc.) is not resolved.
6
6
  */
7
7
  Object.defineProperty(exports, "__esModule", { value: true });
8
- exports.resolveRequestTimeoutMs = exports.mergeParentSignalWithDeadline = exports.isNetworkRequestTimeoutError = exports.isAbortError = exports.installNetworkRequestPolicyTimers = exports.NO_NETWORK_MESSAGE = exports.NETWORK_REQUEST_TIMED_OUT_MESSAGE = void 0;
8
+ exports.resolveRequestTimeoutMs = exports.mergeParentSignalWithDeadline = exports.isNetworkRequestTimeoutError = exports.isAbortError = exports.installNetworkRequestPolicyTimers = exports.NO_NETWORK_MESSAGE = exports.NETWORK_REQUEST_TIMED_OUT_MESSAGE = exports.formatNetworkRequestErrorMessage = exports.formatHttpStatusMessage = void 0;
9
9
  var networkRequestPolicy_1 = require("./networkRequestPolicy");
10
+ Object.defineProperty(exports, "formatHttpStatusMessage", { enumerable: true, get: function () { return networkRequestPolicy_1.formatHttpStatusMessage; } });
11
+ Object.defineProperty(exports, "formatNetworkRequestErrorMessage", { enumerable: true, get: function () { return networkRequestPolicy_1.formatNetworkRequestErrorMessage; } });
10
12
  Object.defineProperty(exports, "NETWORK_REQUEST_TIMED_OUT_MESSAGE", { enumerable: true, get: function () { return networkRequestPolicy_1.NETWORK_REQUEST_TIMED_OUT_MESSAGE; } });
11
13
  Object.defineProperty(exports, "NO_NETWORK_MESSAGE", { enumerable: true, get: function () { return networkRequestPolicy_1.NO_NETWORK_MESSAGE; } });
12
14
  Object.defineProperty(exports, "installNetworkRequestPolicyTimers", { enumerable: true, get: function () { return networkRequestPolicy_1.installNetworkRequestPolicyTimers; } });
@@ -3,6 +3,16 @@
3
3
  export declare const NETWORK_REQUEST_TIMED_OUT_MESSAGE = "Network request timed out";
4
4
  /** Use this exact message for client-side offline gating and RN fetch failures treated as offline. */
5
5
  export declare const NO_NETWORK_MESSAGE = "No network connection";
6
+ /**
7
+ * Formats HTTP response failures as user-facing copy (e.g. "500 Internal Server Error").
8
+ * `detail` can be a response body snippet or `statusText`.
9
+ */
10
+ export declare function formatHttpStatusMessage(status: number, detail?: string): string;
11
+ /**
12
+ * Normalizes raw network/request errors into stable user-facing copy.
13
+ * Keeps NO_NETWORK_MESSAGE unchanged for offline gating checks.
14
+ */
15
+ export declare function formatNetworkRequestErrorMessage(error: unknown): string;
6
16
  export declare function isNetworkRequestTimeoutError(e: unknown): boolean;
7
17
  export declare function isAbortError(e: unknown): boolean;
8
18
  /** Milliseconds for `timeoutAfterSeconds` on request components; `null` when timeout is disabled. */
@@ -1 +1 @@
1
- {"version":3,"file":"networkRequestPolicy.d.ts","sourceRoot":"","sources":["../../../src/helpers/network/networkRequestPolicy.ts"],"names":[],"mappings":"AAAA,6EAA6E;AAE7E,8EAA8E;AAC9E,eAAO,MAAM,iCAAiC,8BAA8B,CAAC;AAE7E,sGAAsG;AACtG,eAAO,MAAM,kBAAkB,0BAA0B,CAAC;AAE1D,wBAAgB,4BAA4B,CAAC,CAAC,EAAE,OAAO,GAAG,OAAO,CAEhE;AAED,wBAAgB,YAAY,CAAC,CAAC,EAAE,OAAO,GAAG,OAAO,CAUhD;AAED,qGAAqG;AACrG,wBAAgB,uBAAuB,CAAC,mBAAmB,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CASnF;AAED,MAAM,MAAM,kCAAkC,GAAG;IAC/C,QAAQ,EAAE,MAAM,OAAO,CAAC;IACxB,kBAAkB,EAAE,CAAC,gBAAgB,EAAE,MAAM,KAAK,IAAI,CAAC;IACvD,uBAAuB,EAAE,MAAM,IAAI,CAAC;IACpC,aAAa,EAAE,MAAM,IAAI,CAAC;CAC3B,CAAC;AAEF;;;;GAIG;AACH,wBAAgB,iCAAiC,CAC/C,kBAAkB,EAAE,MAAM,EAC1B,aAAa,EAAE,MAAM,EACrB,SAAS,EAAE,kCAAkC,GAC5C,MAAM,IAAI,CAuCZ;AAED,MAAM,MAAM,qBAAqB,GAAG;IAClC,MAAM,EAAE,WAAW,CAAC;IACpB,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB,iBAAiB,EAAE,MAAM,OAAO,CAAC;CAClC,CAAC;AAEF;;;;GAIG;AACH,wBAAgB,6BAA6B,CAC3C,YAAY,EAAE,WAAW,EACzB,UAAU,EAAE,MAAM,GACjB,qBAAqB,CAqCvB"}
1
+ {"version":3,"file":"networkRequestPolicy.d.ts","sourceRoot":"","sources":["../../../src/helpers/network/networkRequestPolicy.ts"],"names":[],"mappings":"AAAA,6EAA6E;AAE7E,8EAA8E;AAC9E,eAAO,MAAM,iCAAiC,8BAA8B,CAAC;AAE7E,sGAAsG;AACtG,eAAO,MAAM,kBAAkB,0BAA0B,CAAC;AAoB1D;;;GAGG;AACH,wBAAgB,uBAAuB,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM,CAO/E;AAED;;;GAGG;AACH,wBAAgB,gCAAgC,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,CAmBvE;AAED,wBAAgB,4BAA4B,CAAC,CAAC,EAAE,OAAO,GAAG,OAAO,CAEhE;AAED,wBAAgB,YAAY,CAAC,CAAC,EAAE,OAAO,GAAG,OAAO,CAUhD;AAED,qGAAqG;AACrG,wBAAgB,uBAAuB,CAAC,mBAAmB,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CASnF;AAED,MAAM,MAAM,kCAAkC,GAAG;IAC/C,QAAQ,EAAE,MAAM,OAAO,CAAC;IACxB,kBAAkB,EAAE,CAAC,gBAAgB,EAAE,MAAM,KAAK,IAAI,CAAC;IACvD,uBAAuB,EAAE,MAAM,IAAI,CAAC;IACpC,aAAa,EAAE,MAAM,IAAI,CAAC;CAC3B,CAAC;AAEF;;;;GAIG;AACH,wBAAgB,iCAAiC,CAC/C,kBAAkB,EAAE,MAAM,EAC1B,aAAa,EAAE,MAAM,EACrB,SAAS,EAAE,kCAAkC,GAC5C,MAAM,IAAI,CAuCZ;AAED,MAAM,MAAM,qBAAqB,GAAG;IAClC,MAAM,EAAE,WAAW,CAAC;IACpB,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB,iBAAiB,EAAE,MAAM,OAAO,CAAC;CAClC,CAAC;AAEF;;;;GAIG;AACH,wBAAgB,6BAA6B,CAC3C,YAAY,EAAE,WAAW,EACzB,UAAU,EAAE,MAAM,GACjB,qBAAqB,CAqCvB"}
@@ -2,6 +2,8 @@
2
2
  /** Network helpers for optional request deadlines and timeout countdowns. */
3
3
  Object.defineProperty(exports, "__esModule", { value: true });
4
4
  exports.NO_NETWORK_MESSAGE = exports.NETWORK_REQUEST_TIMED_OUT_MESSAGE = void 0;
5
+ exports.formatHttpStatusMessage = formatHttpStatusMessage;
6
+ exports.formatNetworkRequestErrorMessage = formatNetworkRequestErrorMessage;
5
7
  exports.isNetworkRequestTimeoutError = isNetworkRequestTimeoutError;
6
8
  exports.isAbortError = isAbortError;
7
9
  exports.resolveRequestTimeoutMs = resolveRequestTimeoutMs;
@@ -11,6 +13,59 @@ exports.mergeParentSignalWithDeadline = mergeParentSignalWithDeadline;
11
13
  exports.NETWORK_REQUEST_TIMED_OUT_MESSAGE = "Network request timed out";
12
14
  /** Use this exact message for client-side offline gating and RN fetch failures treated as offline. */
13
15
  exports.NO_NETWORK_MESSAGE = "No network connection";
16
+ const HTTP_STATUS_TEXT = {
17
+ 400: "Bad Request",
18
+ 401: "Unauthorized",
19
+ 403: "Forbidden",
20
+ 404: "Not Found",
21
+ 408: "Request Timeout",
22
+ 409: "Conflict",
23
+ 429: "Too Many Requests",
24
+ 500: "Internal Server Error",
25
+ 502: "Bad Gateway",
26
+ 503: "Service Unavailable",
27
+ 504: "Gateway Timeout",
28
+ };
29
+ function firstLineOrEmpty(value) {
30
+ return (value.split("\n")[0] ?? "").trim();
31
+ }
32
+ /**
33
+ * Formats HTTP response failures as user-facing copy (e.g. "500 Internal Server Error").
34
+ * `detail` can be a response body snippet or `statusText`.
35
+ */
36
+ function formatHttpStatusMessage(status, detail) {
37
+ const trimmed = (detail ?? "").trim();
38
+ if (trimmed !== "") {
39
+ const line = firstLineOrEmpty(trimmed);
40
+ return line === "" ? String(status) : `${status} ${line}`;
41
+ }
42
+ return `${status} ${HTTP_STATUS_TEXT[status] ?? "HTTP Error"}`;
43
+ }
44
+ /**
45
+ * Normalizes raw network/request errors into stable user-facing copy.
46
+ * Keeps NO_NETWORK_MESSAGE unchanged for offline gating checks.
47
+ */
48
+ function formatNetworkRequestErrorMessage(error) {
49
+ const raw = error instanceof Error
50
+ ? error.message
51
+ : typeof error === "string"
52
+ ? error
53
+ : String(error ?? "");
54
+ const msg = raw.trim();
55
+ if (msg === "")
56
+ return "Request failed";
57
+ if (msg === exports.NO_NETWORK_MESSAGE)
58
+ return exports.NO_NETWORK_MESSAGE;
59
+ if (msg === exports.NETWORK_REQUEST_TIMED_OUT_MESSAGE)
60
+ return exports.NETWORK_REQUEST_TIMED_OUT_MESSAGE;
61
+ const http = /^HTTP\s+(\d{3})(?::\s*(.*))?$/i.exec(msg);
62
+ if (http != null) {
63
+ const code = Number(http[1]);
64
+ const detail = (http[2] ?? "").trim();
65
+ return formatHttpStatusMessage(code, detail);
66
+ }
67
+ return msg;
68
+ }
14
69
  function isNetworkRequestTimeoutError(e) {
15
70
  return e instanceof Error && e.message === exports.NETWORK_REQUEST_TIMED_OUT_MESSAGE;
16
71
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ropegeo-common",
3
- "version": "1.12.11",
3
+ "version": "1.12.13",
4
4
  "description": "Shared domain models and helpers for RopeGeo and WebScraper",
5
5
  "license": "ISC",
6
6
  "repository": {