@webority/web-core 0.91.0 → 0.93.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -15,8 +15,8 @@ store.
15
15
  | --- | --- |
16
16
  | `api` | `publicClient`, `userClient`, `initUserAuth`, single-flight token refresh, a cross-tab refresh lock, retry of safe requests, the client headers and the minimum-version header reader |
17
17
  | `auth` | the token store (`getToken`, `storeToken`, `removeToken`), the synchronous `hasSession`, the session user, `clearSession` and `addSessionEndedListener`, `hasSessionEndedInTab`, JWT helpers, "keep me signed in" |
18
- | `config` | `setConfig`, `getConfig`, `getConfigValue`: base URL, version, commit, build number, log settings, request timeout, retry count, correlation-id header |
19
- | `errors` | `extractApiError`: any thrown value to `{ code, message, fieldErrors, status, offline }`, with `code` `'network'`, `'timeout'` or `'offline'` when no answer arrived (`offline` is true for all three, and `'offline'` only when the browser reports no network); `apiErrorMessage(error, fallback)`; `isNoResponse` |
18
+ | `config` | `setConfig`, `getConfig`, `getConfigValue`: base URL, version, commit, build number, log settings, request timeout, retry count |
19
+ | `errors` | `extractApiError`: any thrown value to `{ code, message, fieldErrors, status, offline, traceId, diagnostic }`, with `code` `'network'`, `'timeout'` or `'offline'` when no answer arrived (`offline` is true for all three, and `'offline'` only when the browser reports no network); `apiErrorMessage(error, fallback)`; `isNoResponse` |
20
20
  | `formatters` | house date, time, number, percent and money (`formatMinor`) formatters; India Standard Time by default, the viewer's zone on request |
21
21
  | `logger` | levelled `Logger` with secret redaction, and `Logger.requestFailed` for a failed service call |
22
22
  | `network` | `useNetworkStatus` and the online/offline listener |
@@ -55,14 +55,18 @@ initWebority({ baseUrl: settings.apiUrl, appVersion: settings.version, commit: s
55
55
  ```
56
56
 
57
57
  `appBuild` must be an integer the deploy stamps at build time (CI's run number, for example). The
58
- version check compares it with the API's `X-Min-App-Version` as a number; a string build id
58
+ version check compares it with the API's `Min-App-Version` header as a number; a string build id
59
59
  (`<sha>-<time>`) cannot be compared, and without an integer the update prompt never fires.
60
-
61
- Every request carries a fresh `X-Correlation-Id` (a uuid; a retry keeps the id of its first
62
- attempt) and times out after `timeoutMs`. `initWebority` takes `timeoutMs` (default 30000),
63
- `retries` (default 3; 0 turns retrying off) and `correlationIdHeader` (default
64
- `'X-Correlation-Id'`; `null` sends none). A single long call sets its own axios `timeout`. A
65
- `timeoutMs` or `timeout` of 0 means no timeout. `baseUrl: ""` sends every request to the page's own
60
+ Cross-origin, the portal can read `Min-App-Version` and `Retry-After` only when the API lists them
61
+ in `Access-Control-Expose-Headers`.
62
+
63
+ Every request carries a W3C `traceparent` header (`00-<trace id>-<span id>-01`) with a new value per
64
+ call; a retry resends the value of its first attempt, and a request that sets its own `traceparent`
65
+ keeps it. The trace id is the support reference: `ApiError.traceId` is the body's `traceId` when the
66
+ server sends one, else the trace id of the request's `traceparent`. Every request times out after
67
+ `timeoutMs`. `initWebority` takes `timeoutMs` (default 30000) and `retries` (default 3; 0 turns
68
+ retrying off). A single long call sets its own axios `timeout`. A `timeoutMs` or `timeout` of 0
69
+ means no timeout. `baseUrl: ""` sends every request to the page's own
66
70
  origin, for an API answered through a same-origin dev proxy.
67
71
 
68
72
  ```ts
@@ -99,22 +103,22 @@ export const store = configureStore({
99
103
 
100
104
  initUserAuth(store, {
101
105
  logout: resetState,
102
- refresh: { path: "/api/account/refresh", headers: () => ({ "X-Installation-Id": getInstallationId() }) },
106
+ refresh: { path: "/api/account/refresh", headers: () => ({ "Installation-Id": getInstallationId() }) },
103
107
  legacyKeys: { accessToken: "app.accessToken", refreshToken: "app.refreshToken" },
104
108
  });
105
109
  setupApiListeners(store.dispatch);
106
110
  ```
107
111
 
108
- A session ends in one place. When the refresh endpoint refuses the refresh token, or the API reports
109
- the session dead (a 401 with `X-Security-Stamp-Invalid`, a termination code, or a sign-out reason),
110
- the library calls `clearSession('rejected' | 'terminated')` itself and then dispatches `logout`.
111
- Every `addSessionEndedListener((reason, { signOutReason }) => ...)` listener hears it once, with the
112
- server's reason from the `X-Sign-Out-Reason` header (`signOutReasonHeader` renames it; `null` turns it
113
- off). A 401 that names a sign-out reason is a revoked session, so no refresh is tried. Cross-origin,
114
- the API lists the header in `Access-Control-Expose-Headers`.
112
+ A session ends in one place. When the refresh endpoint refuses the refresh token, the library calls
113
+ `clearSession('rejected')`. When the API answers 401 with a body `code` of `session_revoked` or
114
+ `session_expired`, the library calls `clearSession('terminated')` and sends no refresh request. Any
115
+ other 401 takes the refresh path. Either way the library then dispatches `logout`. Every
116
+ `addSessionEndedListener((reason, { code }) => ...)` listener hears the end once. `code` is the body
117
+ code of a terminated session; for a rejected refresh it is the same code when the refusal carried one,
118
+ else `null`. Another tab's sign-out and an app's own `clearSession()` give `null`.
115
119
 
116
120
  A request never runs in a workspace other than the one it was made in. `initUserAuth`'s `accountId`
117
- provider is read once, when a request is made, and sent as `X-Account-Id`; a retry, a replay after a
121
+ provider is read once, when a request is made, and sent as `Account-Id`; a retry, a replay after a
118
122
  refresh and a replay after a session replacement send that same id and never read the provider again.
119
123
  A request refused (401) for a session that has since been replaced is sent again with the stored
120
124
  token only when the provider still names the account it was made in (or neither names one). When the
@@ -179,6 +183,8 @@ body has a code other than `internal_error` and a curated message shows that mes
179
183
  server sent nothing curated, for a panel that shows only the server's own sentence. `isNoResponse(error)`
180
184
  says whether an answer arrived at all; `code` tells a timeout (`TIMEOUT_CODE`) from a network failure
181
185
  while online (`NETWORK_CODE`) and from a browser that reports no network (`OFFLINE_CODE`).
186
+ `diagnostic` holds the server's own text (the body `detail`, else `title`, else a plain-text body, else
187
+ the request's error message) for the logger, never for a screen.
182
188
 
183
189
  Errors raise a toast by default; a thunk or endpoint opts out with `meta: { silent: true }`, the
184
190
  same on web and mobile. `onRejected` gives the product its say over each rejection before the
@@ -199,6 +205,11 @@ errorToastMiddleware({
199
205
  });
200
206
  ```
201
207
 
208
+ An app moves to this contract by running `webority upgrade 0.93.0`. It renames the old `X-` header
209
+ strings to the plain names, `ApiError.detail` to `diagnostic` and `detail.signOutReason` to
210
+ `detail.code`, and lists each removed option (`correlationIdHeader`, `signOutReasonHeader`) and
211
+ constant for a person to delete.
212
+
202
213
  ## Formatters
203
214
 
204
215
  Called with no options, the house formatters print (zone IST, locale en-IN, empty `-`):
@@ -302,7 +313,7 @@ claim: reload only when `!hasRecentlyReloaded() && markReloaded()`.
302
313
  `requestFailed`, `setUser`, `setAttribute`, `trackScreen`, with secrets redacted before anything is
303
314
  printed or forwarded. `Logger.requestFailed(error, { label, expectedStatuses })` logs a failed service
304
315
  call: a cancel as info, an expected status as info (never a console warning), anything else as a recorded error with its
305
- status, method, path (no query string), the server's `code` and `traceId`, and the correlation id.
316
+ status, method, path (no query string), the server's `code` and `traceId`.
306
317
  `setConfig({ logLevel, loggingEnabled })` decides what reaches the console; `setRemoteLogger` forwards
307
318
  info and above (never debug) to an error-reporting service, and errors are forwarded even with logging
308
319
  off. The library strips nothing at runtime. To drop debug calls from a production bundle, mark them pure
@@ -321,7 +332,7 @@ key into `sessionStorage` (`webority.designSample`) and leaves the address as it
321
332
  the stored ticket, so it survives in-app navigation and redirects and ends with the tab.
322
333
 
323
334
  `applyDesignSample(client)` is wired into `userClient` and `publicClient`: every request carries the
324
- `X-Design-Sample` header when a ticket exists and the request does not set one itself. A header the
335
+ `Design-Sample` header when a ticket exists and the request does not set one itself. A header the
325
336
  request sets by hand wins.
326
337
 
327
338
  The ticket is never read in `Production`: `readDesignSampleTicket()` returns `null` there, whatever the
@@ -1 +1 @@
1
- import{getConfigValue as e}from"../config/index.js";var t=`X-Client-Build`,n=`X-Client-Kind`,r=`X-Account-Id`,i=`Browser`,a=()=>{let t=e(`appVersion`);if(!t)return null;let n=e(`commit`);return n?`${t}+${n}`:t},o=(e,t,n)=>{n&&!e.has(t)&&e.set(t,n)},s=e=>{e.interceptors.request.use(e=>(o(e.headers,n,i),o(e.headers,t,a()),e))},c=async e=>(e?await e():null)||null,l=async(e,t)=>{if(e._accountId!==void 0){e._accountId&&e.headers.set(r,e._accountId);return}let n=e.headers.get(r);if(typeof n==`string`&&n!==``){e._accountId=n;return}let i=await c(t);e._accountId=i,i&&e.headers.set(r,i)};export{r as ACCOUNT_ID_HEADER,t as CLIENT_BUILD_HEADER,i as CLIENT_KIND,n as CLIENT_KIND_HEADER,s as applyClientHeaders,a as getClientBuild,c as readAccountId,l as stampAccountId};
1
+ import{getConfigValue as e}from"../config/index.js";var t=`Client-Build`,n=`Client-Kind`,r=`Account-Id`,i=`Browser`,a=()=>{let t=e(`appVersion`);if(!t)return null;let n=e(`commit`);return n?`${t}+${n}`:t},o=(e,t,n)=>{n&&!e.has(t)&&e.set(t,n)},s=e=>{e.interceptors.request.use(e=>(o(e.headers,n,i),o(e.headers,t,a()),e))},c=async e=>(e?await e():null)||null,l=async(e,t)=>{if(e._accountId!==void 0){e._accountId&&e.headers.set(r,e._accountId);return}let n=e.headers.get(r);if(typeof n==`string`&&n!==``){e._accountId=n;return}let i=await c(t);e._accountId=i,i&&e.headers.set(r,i)};export{r as ACCOUNT_ID_HEADER,t as CLIENT_BUILD_HEADER,i as CLIENT_KIND,n as CLIENT_KIND_HEADER,s as applyClientHeaders,a as getClientBuild,c as readAccountId,l as stampAccountId};
@@ -1 +1 @@
1
- import{getConfigValue as e}from"../config/index.js";var t=`designSample`,n=`X-Design-Sample`,r=`webority.designSample`,i=!1,a=()=>{if(e(`environment`)===`Production`)return null;if(!i){i=!0;let e=new URLSearchParams(window.location.search).get(t);e&&sessionStorage.setItem(r,e)}return sessionStorage.getItem(r)},o=e=>{e.interceptors.request.use(e=>{let t=a();return t&&!e.headers.has(`X-Design-Sample`)&&e.headers.set(n,t),e})};export{n as DESIGN_SAMPLE_HEADER,t as DESIGN_SAMPLE_QUERY_KEY,r as DESIGN_SAMPLE_STORAGE_KEY,o as applyDesignSample,a as readDesignSampleTicket};
1
+ import{getConfigValue as e}from"../config/index.js";var t=`designSample`,n=`Design-Sample`,r=`webority.designSample`,i=!1,a=()=>{if(e(`environment`)===`Production`)return null;if(!i){i=!0;let e=new URLSearchParams(window.location.search).get(t);e&&sessionStorage.setItem(r,e)}return sessionStorage.getItem(r)},o=e=>{e.interceptors.request.use(e=>{let t=a();return t&&!e.headers.has(`Design-Sample`)&&e.headers.set(n,t),e})};export{n as DESIGN_SAMPLE_HEADER,t as DESIGN_SAMPLE_QUERY_KEY,r as DESIGN_SAMPLE_STORAGE_KEY,o as applyDesignSample,a as readDesignSampleTicket};
package/dist/api/index.js CHANGED
@@ -1 +1 @@
1
- import{ACCOUNT_ID_HEADER as e,CLIENT_BUILD_HEADER as t,CLIENT_KIND as n,CLIENT_KIND_HEADER as r,getClientBuild as i}from"./clientHeaders.js";import{DESIGN_SAMPLE_HEADER as a,DESIGN_SAMPLE_QUERY_KEY as o,DESIGN_SAMPLE_STORAGE_KEY as s,applyDesignSample as c,readDesignSampleTicket as l}from"./designSample.js";import{MIN_APP_VERSION_HEADER as u,addMinAppVersionListener as d,getMinAppVersion as f}from"./minAppVersion.js";import{applyRequestDefaults as p,newCorrelationId as m}from"./requestDefaults.js";import{WORKSPACE_CHANGED_CODE as h,WorkspaceChangedError as g,isWorkspaceChangedError as _}from"./workspaceChanged.js";import{IDEMPOTENCY_KEY_HEADER as v,attachRetry as y,isNeverSentError as b,isRetryableFailure as x,isRetryableStatus as S,retryAfterMs as C}from"./retry.js";import{REFRESH_LOCK_NAME as w,withCrossTabRefreshLock as T}from"./crossTabRefreshLock.js";import E from"./publicClient.js";import{SIGN_OUT_REASON_HEADER as D,injectStore as O,injectUserAuth as k,refreshAccessToken as A,resetRefreshState as j}from"./tokenRefresh.js";import M,{RequestOfflineError as N,SESSION_TERMINATION_CODES as P}from"./userClient.js";import{initUserAuth as F}from"../initUserAuth.js";export{e as ACCOUNT_ID_HEADER,t as CLIENT_BUILD_HEADER,n as CLIENT_KIND,r as CLIENT_KIND_HEADER,a as DESIGN_SAMPLE_HEADER,o as DESIGN_SAMPLE_QUERY_KEY,s as DESIGN_SAMPLE_STORAGE_KEY,v as IDEMPOTENCY_KEY_HEADER,u as MIN_APP_VERSION_HEADER,w as REFRESH_LOCK_NAME,N as RequestOfflineError,P as SESSION_TERMINATION_CODES,D as SIGN_OUT_REASON_HEADER,h as WORKSPACE_CHANGED_CODE,g as WorkspaceChangedError,d as addMinAppVersionListener,c as applyDesignSample,p as applyRequestDefaults,y as attachRetry,i as getClientBuild,f as getMinAppVersion,F as initUserAuth,O as injectStore,k as injectUserAuth,b as isNeverSentError,x as isRetryableFailure,S as isRetryableStatus,_ as isWorkspaceChangedError,m as newCorrelationId,E as publicClient,l as readDesignSampleTicket,A as refreshAccessToken,j as resetRefreshState,C as retryAfterMs,M as userClient,T as withCrossTabRefreshLock};
1
+ import{TRACEPARENT_HEADER as e,applyRequestDefaults as t,newTraceparent as n}from"./requestDefaults.js";import{ACCOUNT_ID_HEADER as r,CLIENT_BUILD_HEADER as i,CLIENT_KIND as a,CLIENT_KIND_HEADER as o,getClientBuild as s}from"./clientHeaders.js";import{DESIGN_SAMPLE_HEADER as c,DESIGN_SAMPLE_QUERY_KEY as l,DESIGN_SAMPLE_STORAGE_KEY as u,applyDesignSample as d,readDesignSampleTicket as f}from"./designSample.js";import{MIN_APP_VERSION_HEADER as p,addMinAppVersionListener as m,getMinAppVersion as h}from"./minAppVersion.js";import{WORKSPACE_CHANGED_CODE as g,WorkspaceChangedError as _,isWorkspaceChangedError as v}from"./workspaceChanged.js";import{IDEMPOTENCY_KEY_HEADER as y,attachRetry as b,isNeverSentError as x,isRetryableFailure as S,isRetryableStatus as C,retryAfterMs as w}from"./retry.js";import{REFRESH_LOCK_NAME as T,withCrossTabRefreshLock as E}from"./crossTabRefreshLock.js";import D from"./publicClient.js";import{SESSION_EXPIRED_CODE as O,SESSION_REVOKED_CODE as k,injectStore as A,injectUserAuth as j,refreshAccessToken as M,resetRefreshState as N}from"./tokenRefresh.js";import P,{RequestOfflineError as F}from"./userClient.js";import{initUserAuth as I}from"../initUserAuth.js";export{r as ACCOUNT_ID_HEADER,i as CLIENT_BUILD_HEADER,a as CLIENT_KIND,o as CLIENT_KIND_HEADER,c as DESIGN_SAMPLE_HEADER,l as DESIGN_SAMPLE_QUERY_KEY,u as DESIGN_SAMPLE_STORAGE_KEY,y as IDEMPOTENCY_KEY_HEADER,p as MIN_APP_VERSION_HEADER,T as REFRESH_LOCK_NAME,F as RequestOfflineError,O as SESSION_EXPIRED_CODE,k as SESSION_REVOKED_CODE,e as TRACEPARENT_HEADER,g as WORKSPACE_CHANGED_CODE,_ as WorkspaceChangedError,m as addMinAppVersionListener,d as applyDesignSample,t as applyRequestDefaults,b as attachRetry,s as getClientBuild,h as getMinAppVersion,I as initUserAuth,A as injectStore,j as injectUserAuth,x as isNeverSentError,S as isRetryableFailure,C as isRetryableStatus,v as isWorkspaceChangedError,n as newTraceparent,D as publicClient,f as readDesignSampleTicket,M as refreshAccessToken,N as resetRefreshState,w as retryAfterMs,P as userClient,E as withCrossTabRefreshLock};
@@ -1 +1 @@
1
- import{Logger as e}from"../logger/logger.js";var t=`X-Min-App-Version`,n=null,r=new Set,i=()=>n,a=e=>(r.add(e),n!==null&&e(n),()=>{r.delete(e)}),o=e=>{if(!e||typeof e!=`object`)return;let n=e.get;return typeof n==`function`?n.call(e,t):e[t.toLowerCase()]},s=i=>{let a=o(i?.headers);if(a==null||a===``)return;let s=String(a).trim();if(!/^\d+$/.test(s)){e.warn(`[minAppVersion] ignored a non-integer ${t}: ${s}`);return}let c=Number.parseInt(s,10);if(c!==n){n=c;for(let t of[...r])try{t(c)}catch(t){e.error(`[minAppVersion] a listener threw`,t)}}},c=e=>{e.interceptors.response.use(e=>(s(e),e),e=>(s(e?.response),Promise.reject(e)))};export{t as MIN_APP_VERSION_HEADER,a as addMinAppVersionListener,i as getMinAppVersion,c as readMinAppVersion};
1
+ import{Logger as e}from"../logger/logger.js";var t=`Min-App-Version`,n=null,r=new Set,i=()=>n,a=e=>(r.add(e),n!==null&&e(n),()=>{r.delete(e)}),o=e=>{if(!e||typeof e!=`object`)return;let n=e.get;return typeof n==`function`?n.call(e,t):e[t.toLowerCase()]},s=i=>{let a=o(i?.headers);if(a==null||a===``)return;let s=String(a).trim();if(!/^\d+$/.test(s)){e.warn(`[minAppVersion] ignored a non-integer ${t}: ${s}`);return}let c=Number.parseInt(s,10);if(c!==n){n=c;for(let t of[...r])try{t(c)}catch(t){e.error(`[minAppVersion] a listener threw`,t)}}},c=e=>{e.interceptors.response.use(e=>(s(e),e),e=>(s(e?.response),Promise.reject(e)))};export{t as MIN_APP_VERSION_HEADER,a as addMinAppVersionListener,i as getMinAppVersion,c as readMinAppVersion};
@@ -1 +1 @@
1
- import{Logger as e}from"../logger/logger.js";import{applyConfiguredBaseUrl as t}from"./baseUrl.js";import{applyClientHeaders as n}from"./clientHeaders.js";import{applyDesignSample as r}from"./designSample.js";import{readMinAppVersion as i}from"./minAppVersion.js";import{sendFormDataAsMultipart as a}from"./multipart.js";import{applyRequestDefaults as o}from"./requestDefaults.js";import{responseBodyText as s}from"./responseBodyText.js";import{attachRetry as c}from"./retry.js";import l from"axios";var u=l.create({headers:{"Content-Type":`application/json`,Accept:`application/json`}});t(u),o(u),a(u),i(u),c(u),u.interceptors.request.use(t=>(e.info(`Request: ${t.method?.toUpperCase()} ${t.url}`),t),t=>{let n=t instanceof Error?t.message:String(t);return e.error(`Request error:`,n),Promise.reject(t)}),n(u),r(u),u.interceptors.response.use(t=>(e.info(`Response: ${t.status} from ${t.config.url}`),t),t=>{if(l.isCancel(t))return Promise.reject(t);if(l.isAxiosError(t)){let n=t.config;if(n?.skipErrorLog)return Promise.reject(t);t.response?e.error(`Response error: ${s(t.response.data,t.message)}, URL: ${n?.url}, Status: ${t.response.status}`):e.error(`Network error or no response from server: ${t.message}, URL: ${n?.url}`)}else{let n=t instanceof Error?t.message:String(t);e.error(`Unknown response error: ${n}`)}return Promise.reject(t)});export{u as default};
1
+ import{applyRequestDefaults as e}from"./requestDefaults.js";import{Logger as t}from"../logger/logger.js";import{applyConfiguredBaseUrl as n}from"./baseUrl.js";import{applyClientHeaders as r}from"./clientHeaders.js";import{applyDesignSample as i}from"./designSample.js";import{readMinAppVersion as a}from"./minAppVersion.js";import{sendFormDataAsMultipart as o}from"./multipart.js";import{responseBodyText as s}from"./responseBodyText.js";import{attachRetry as c}from"./retry.js";import l from"axios";var u=l.create({headers:{"Content-Type":`application/json`,Accept:`application/json`}});n(u),e(u),o(u),a(u),c(u),u.interceptors.request.use(e=>(t.info(`Request: ${e.method?.toUpperCase()} ${e.url}`),e),e=>{let n=e instanceof Error?e.message:String(e);return t.error(`Request error:`,n),Promise.reject(e)}),r(u),i(u),u.interceptors.response.use(e=>(t.info(`Response: ${e.status} from ${e.config.url}`),e),e=>{if(l.isCancel(e))return Promise.reject(e);if(l.isAxiosError(e)){let n=e.config;if(n?.skipErrorLog)return Promise.reject(e);e.response?t.error(`Response error: ${s(e.response.data,e.message)}, URL: ${n?.url}, Status: ${e.response.status}`):t.error(`Network error or no response from server: ${e.message}, URL: ${n?.url}`)}else{let n=e instanceof Error?e.message:String(e);t.error(`Unknown response error: ${n}`)}return Promise.reject(e)});export{u as default};
@@ -1 +1 @@
1
- import{getConfigValue as e}from"../config/index.js";var t=()=>{let e=globalThis.crypto;if(typeof e?.randomUUID==`function`)return e.randomUUID();let t=new Uint8Array(16);if(typeof e?.getRandomValues==`function`)e.getRandomValues(t);else for(let e=0;e<t.length;e+=1)t[e]=Math.floor(Math.random()*256);t[6]=(t[6]??0)&15|64,t[8]=(t[8]??0)&63|128;let n=Array.from(t,e=>e.toString(16).padStart(2,`0`)).join(``);return`${n.slice(0,8)}-${n.slice(8,12)}-${n.slice(12,16)}-${n.slice(16,20)}-${n.slice(20)}`},n=n=>{n.defaults.timeout=void 0,n.interceptors.request.use(n=>{n.timeout===void 0&&(n.timeout=e(`timeoutMs`));let r=e(`correlationIdHeader`);return r&&!n.headers.has(r)&&n.headers.set(r,t()),n})};export{n as applyRequestDefaults,t as newCorrelationId};
1
+ import{getConfigValue as e}from"../config/index.js";var t=`traceparent`,n=e=>{let t=globalThis.crypto,n=new Uint8Array(e);if(typeof t?.getRandomValues==`function`)t.getRandomValues(n);else for(let e=0;e<n.length;e+=1)n[e]=Math.floor(Math.random()*256);return n.every(e=>e===0)&&(n[n.length-1]=1),Array.from(n,e=>e.toString(16).padStart(2,`0`)).join(``)},r=()=>{let e=n(16);return{header:`00-${e}-${n(8)}-01`,traceId:e}},i=n=>{n.defaults.timeout=void 0,n.interceptors.request.use(n=>(n.timeout===void 0&&(n.timeout=e(`timeoutMs`)),n.headers.has(`traceparent`)||n.headers.set(t,r().header),n))};export{t as TRACEPARENT_HEADER,i as applyRequestDefaults,r as newTraceparent};
package/dist/api/retry.js CHANGED
@@ -1 +1 @@
1
- import{getConfigValue as e}from"../config/index.js";import{isWorkspaceChangedResponse as t}from"./workspaceChanged.js";import n from"axios";var r=`Idempotency-Key`,i=e=>typeof e==`number`&&(e===429||e>=500&&e<=599),a=new Set([`get`,`head`,`options`,`put`,`delete`]),o=new Set([`ECONNREFUSED`,`ENOTFOUND`,`EAI_AGAIN`,`ENETUNREACH`,`EHOSTUNREACH`]),s=e=>!e.response&&typeof e.code==`string`&&o.has(e.code),c=3e4,l=e=>{let t=e.response;if(!t)return null;let n=t.data,r=t.headers,i=typeof r?.get==`function`?r.get(`retry-after`):r?.[`retry-after`];for(let e of[n?.retryAfterSeconds,i]){let t=Number(e);if(e!=null&&Number.isFinite(t)&&t>0)return t*1e3}return null},u=e=>{let t=e?.headers,n=typeof t?.get==`function`?t.get(r):t?.[r];return typeof n==`string`&&n!==``},d=e=>{if(n.isCancel(e)||e.code===`ERR_CANCELED`)return!1;if(s(e))return!0;let t=(e.config?.method??`get`).toLowerCase(),r=a.has(t),o=e.response?.status;if(o===void 0)return r;if(!i(o))return!1;let d=l(e);return d!==null&&d>c?!1:r||(o===429||o===503)&&u(e.config)},f={retryDelayMs:e=>e<=1?0:Math.random()*Math.min(3e4,1e3*2**e),shouldRetry:d,onRetry:()=>void 0},p=(e,t)=>new Promise(n=>{let r=()=>{clearTimeout(i),n(!1)},i=setTimeout(()=>{t?.removeEventListener?.(`abort`,r),n(!0)},e);t?.addEventListener?.(`abort`,r,{once:!0})}),m=(n,r={})=>{n.interceptors.response.use(void 0,async i=>{let a=i,o=a?.config;if(!o||o.retry===!1)return Promise.reject(i);let s=typeof o.retry==`object`?o.retry:{},c={...f,retries:e(`retries`),...r,...s},u=(o.__retryAttempt??0)+1;return t(a)||u>c.retries||!c.shouldRetry(a)||o.signal?.aborted||(o.__retryAttempt=u,o.transformRequest=[e=>e],c.onRetry(u,a),!await p(l(a)??c.retryDelayMs(u),o.signal))?Promise.reject(i):n.request(o)})};export{r as IDEMPOTENCY_KEY_HEADER,m as attachRetry,s as isNeverSentError,d as isRetryableFailure,i as isRetryableStatus,l as retryAfterMs};
1
+ import{getConfigValue as e}from"../config/index.js";import{isWorkspaceChangedResponse as t}from"./workspaceChanged.js";import n from"axios";var r=`Idempotency-Key`,i=e=>typeof e==`number`&&(e===429||e>=500&&e<=599),a=new Set([`get`,`head`,`options`,`put`,`delete`]),o=new Set([`ECONNREFUSED`,`ENOTFOUND`,`EAI_AGAIN`,`ENETUNREACH`,`EHOSTUNREACH`]),s=e=>!e.response&&typeof e.code==`string`&&o.has(e.code),c=3e4,l=e=>{let t=e.response;if(!t)return null;let n=t.headers,r=typeof n?.get==`function`?n.get(`retry-after`):n?.[`retry-after`],i=Number(r);return r!=null&&Number.isFinite(i)&&i>0?i*1e3:null},u=e=>{let t=e?.headers,n=typeof t?.get==`function`?t.get(r):t?.[r];return typeof n==`string`&&n!==``},d=e=>{if(n.isCancel(e)||e.code===`ERR_CANCELED`)return!1;if(s(e))return!0;let t=(e.config?.method??`get`).toLowerCase(),r=a.has(t),o=e.response?.status;if(o===void 0)return r;if(!i(o))return!1;let d=l(e);return d!==null&&d>c?!1:r||(o===429||o===503)&&u(e.config)},f={retryDelayMs:e=>e<=1?0:Math.random()*Math.min(3e4,1e3*2**e),shouldRetry:d,onRetry:()=>void 0},p=(e,t)=>new Promise(n=>{let r=()=>{clearTimeout(i),n(!1)},i=setTimeout(()=>{t?.removeEventListener?.(`abort`,r),n(!0)},e);t?.addEventListener?.(`abort`,r,{once:!0})}),m=(n,r={})=>{n.interceptors.response.use(void 0,async i=>{let a=i,o=a?.config;if(!o||o.retry===!1)return Promise.reject(i);let s=typeof o.retry==`object`?o.retry:{},c={...f,retries:e(`retries`),...r,...s},u=(o.__retryAttempt??0)+1;return t(a)||u>c.retries||!c.shouldRetry(a)||o.signal?.aborted||(o.__retryAttempt=u,o.transformRequest=[e=>e],c.onRetry(u,a),!await p(l(a)??c.retryDelayMs(u),o.signal))?Promise.reject(i):n.request(o)})};export{r as IDEMPOTENCY_KEY_HEADER,m as attachRetry,s as isNeverSentError,d as isRetryableFailure,i as isRetryableStatus,l as retryAfterMs};
@@ -1 +1 @@
1
- import{Logger as e}from"../logger/logger.js";import{ACCESS_TOKEN_KEY as t,REFRESH_TOKEN_KEY as n,clearSession as r,getToken as i,storeToken as a}from"../auth/authStore.js";import{withCrossTabRefreshLock as o}from"./crossTabRefreshLock.js";import s from"./publicClient.js";import c from"axios";var l,u,d=e=>{l=e},f=e=>{u=e},p=null,m=[],h=(e,t=null)=>{m.forEach(({resolve:n,reject:r})=>{e?r(e):t!==null&&n(t)}),m=[]},g=()=>{p=null,h(Error(`[@webority/web-core] Session ended`))},_=e=>e instanceof Error?e.message:typeof e==`string`?e:`Unknown error`,v=()=>{if(!l||!u)throw Error(`User package store is not initialized. Call initUserAuth first.`);return{store:l,auth:u}},y=()=>u?.accountId,b=()=>u?.refresh.path,x=async()=>{let e=v();await e.store.dispatch(e.auth.logout())},S=`X-Sign-Out-Reason`,C=e=>{let t=u?.signOutReasonHeader===void 0?S:u.signOutReasonHeader;if(!t||!e||typeof e!=`object`)return null;let n=e.get,r=typeof n==`function`?n.call(e,t):e[t.toLowerCase()];return typeof r==`string`&&r.trim()!==``?r.trim():null},w=async(e,t)=>{await r(e,{signOutReason:t}),await x()},T=()=>p!==null,E=0,D=Promise.resolve(),O=null,k=()=>{E===0&&(D=new Promise(e=>{O=e})),E+=1;let e=!1;return()=>{e||(e=!0,--E,E===0&&(O?.(),O=null))}},A=()=>E===0?Promise.resolve():D,j=async r=>{let i;try{i=(u?.refresh.readTokens??L)(r)}catch(t){e.error(`A session-replacing response carried no tokens:`,_(t));return}await a(t,i.accessToken,i.accessTokenExpiry),await a(n,i.refreshToken,i.refreshTokenExpiry)},M=async e=>{let t=(await i(`accessToken`))?.token??null;return t!==null&&t!==e?t:null},N=()=>new Promise((e,t)=>{m.push({resolve:e,reject:t})}),P=class e extends Error{constructor(t){super(t),this.name=`SessionEndedError`,Object.setPrototypeOf(this,e.prototype)}},F=e=>e instanceof P||c.isAxiosError(e)&&(e.response?.status===400||e.response?.status===401),I=(e,t)=>{if(typeof e!=`string`||e===``)throw Error(`The refresh response has no "${t}".`);return e},L=e=>{let t=e??{};return{accessToken:I(t.accessToken,`accessToken`),accessTokenExpiry:I(t.accessTokenExpiration,`accessTokenExpiration`),refreshToken:I(t.refreshToken,`refreshToken`),refreshTokenExpiry:I(t.refreshTokenExpiration,`refreshTokenExpiration`)}},R=async r=>{let o=await i(n);if(!o?.token)throw new P(`No refresh token available`);if(Date.parse(o.expiry)<=Date.now())throw new P(`Refresh token expired`);let c={accessToken:(await i(`accessToken`))?.token??null,refreshToken:o.token},l=r.body?await r.body(c):c,u=r.headers?await r.headers():void 0;e.info(`Refreshing the access token`);let{data:d}=await s.post(r.path,l,u?{headers:u}:void 0),f=(r.readTokens??L)(d);await A();let p=(await i(`refreshToken`))?.token===o.token?null:await i(t);return p?.token?(e.info(`Keeping the session that replaced this one during the refresh`),p.token):(await a(t,f.accessToken,f.accessTokenExpiry),await a(n,f.refreshToken,f.refreshTokenExpiry),e.info(`Access token refreshed`),f.accessToken)},z=30*1e3,B=async(n,r)=>{let a=await i(t);return a?.token&&a.token!==r&&Date.parse(a.expiry)>Date.now()+z?(e.info(`Adopting the access token another tab refreshed`),a.token):R(n)},V=()=>{if(p)return p;let t=(async()=>{let t=null;try{let{refresh:e}=v().auth;t=(await i(`accessToken`))?.token??null;let n=await o(()=>B(e,t));return h(null,n),n}catch(n){if(F(n)){await A();let n=await M(t);if(n)return e.info(`The session was replaced during the refresh; continuing with the new one`),h(null,n),n}let r=c.isAxiosError(n)?n.response?.data:void 0;throw e.error(`Token refresh failed:`,r??_(n)),h(n,null),F(n)&&await w(`rejected`,c.isAxiosError(n)?C(n.response?.headers):null),n}})().finally(()=>{p===t&&(p=null)});return p=t,t};export{S as SIGN_OUT_REASON_HEADER,k as beginSessionReplacement,M as currentTokenIfReplaced,x as dispatchLogout,w as endSessionAndLogout,y as getAccountIdProvider,_ as getErrorMessage,b as getRefreshPath,d as injectStore,f as injectUserAuth,T as isRefreshInFlight,N as queueBehindRefresh,C as readSignOutReason,V as refreshAccessToken,g as resetRefreshState,j as storeReplacementSession,A as waitForSessionReplacement};
1
+ import{Logger as e}from"../logger/logger.js";import{ACCESS_TOKEN_KEY as t,REFRESH_TOKEN_KEY as n,clearSession as r,getToken as i,storeToken as a}from"../auth/authStore.js";import{withCrossTabRefreshLock as o}from"./crossTabRefreshLock.js";import s from"./publicClient.js";import c from"axios";var l=`session_revoked`,u=`session_expired`,d,f,p=e=>{d=e},m=e=>{f=e},h=null,g=[],_=(e,t=null)=>{g.forEach(({resolve:n,reject:r})=>{e?r(e):t!==null&&n(t)}),g=[]},v=()=>{h=null,_(Error(`[@webority/web-core] Session ended`))},y=e=>e instanceof Error?e.message:typeof e==`string`?e:`Unknown error`,b=()=>{if(!d||!f)throw Error(`User package store is not initialized. Call initUserAuth first.`);return{store:d,auth:f}},x=()=>f?.accountId,S=()=>f?.refresh.path,C=async()=>{let e=b();await e.store.dispatch(e.auth.logout())},w=async(e,t)=>{await r(e,{code:t}),await C()},T=e=>{let t=e&&typeof e==`object`?e.code:void 0;return t===`session_revoked`||t===`session_expired`?t:null},E=()=>h!==null,D=0,O=Promise.resolve(),k=null,A=()=>{D===0&&(O=new Promise(e=>{k=e})),D+=1;let e=!1;return()=>{e||(e=!0,--D,D===0&&(k?.(),k=null))}},j=()=>D===0?Promise.resolve():O,M=async r=>{let i;try{i=(f?.refresh.readTokens??z)(r)}catch(t){e.error(`A session-replacing response carried no tokens:`,y(t));return}await a(t,i.accessToken,i.accessTokenExpiry),await a(n,i.refreshToken,i.refreshTokenExpiry)},N=async e=>{let t=(await i(`accessToken`))?.token??null;return t!==null&&t!==e?t:null},P=()=>new Promise((e,t)=>{g.push({resolve:e,reject:t})}),F=class e extends Error{constructor(t){super(t),this.name=`SessionEndedError`,Object.setPrototypeOf(this,e.prototype)}},I=e=>e instanceof F||c.isAxiosError(e)&&(e.response?.status===400||e.response?.status===401),L=e=>!c.isAxiosError(e)||e.response?.status!==401?null:T(e.response.data),R=(e,t)=>{if(typeof e!=`string`||e===``)throw Error(`The refresh response has no "${t}".`);return e},z=e=>{let t=e??{};return{accessToken:R(t.accessToken,`accessToken`),accessTokenExpiry:R(t.accessTokenExpiration,`accessTokenExpiration`),refreshToken:R(t.refreshToken,`refreshToken`),refreshTokenExpiry:R(t.refreshTokenExpiration,`refreshTokenExpiration`)}},B=async r=>{let o=await i(n);if(!o?.token)throw new F(`No refresh token available`);if(Date.parse(o.expiry)<=Date.now())throw new F(`Refresh token expired`);let c={accessToken:(await i(`accessToken`))?.token??null,refreshToken:o.token},l=r.body?await r.body(c):c,u=r.headers?await r.headers():void 0;e.info(`Refreshing the access token`);let{data:d}=await s.post(r.path,l,u?{headers:u}:void 0),f=(r.readTokens??z)(d);await j();let p=(await i(`refreshToken`))?.token===o.token?null:await i(t);return p?.token?(e.info(`Keeping the session that replaced this one during the refresh`),p.token):(await a(t,f.accessToken,f.accessTokenExpiry),await a(n,f.refreshToken,f.refreshTokenExpiry),e.info(`Access token refreshed`),f.accessToken)},V=30*1e3,H=async(n,r)=>{let a=await i(t);return a?.token&&a.token!==r&&Date.parse(a.expiry)>Date.now()+V?(e.info(`Adopting the access token another tab refreshed`),a.token):B(n)},U=()=>{if(h)return h;let t=(async()=>{let t=null;try{let{refresh:e}=b().auth;t=(await i(`accessToken`))?.token??null;let n=await o(()=>H(e,t));return _(null,n),n}catch(n){if(I(n)){await j();let n=await N(t);if(n)return e.info(`The session was replaced during the refresh; continuing with the new one`),_(null,n),n}let r=c.isAxiosError(n)?n.response?.data:void 0;throw e.error(`Token refresh failed:`,r??y(n)),_(n,null),I(n)&&await w(`rejected`,L(n)),n}})().finally(()=>{h===t&&(h=null)});return h=t,t};export{u as SESSION_EXPIRED_CODE,l as SESSION_REVOKED_CODE,A as beginSessionReplacement,N as currentTokenIfReplaced,C as dispatchLogout,w as endSessionAndLogout,x as getAccountIdProvider,y as getErrorMessage,S as getRefreshPath,p as injectStore,m as injectUserAuth,E as isRefreshInFlight,P as queueBehindRefresh,U as refreshAccessToken,v as resetRefreshState,T as sessionCodeOf,M as storeReplacementSession,j as waitForSessionReplacement};
@@ -1 +1 @@
1
- import{Logger as e}from"../logger/logger.js";import{ACCESS_TOKEN_KEY as t,getToken as n}from"../auth/authStore.js";import{getLastKnownNetworkStatus as r}from"../network/networkStatus.js";import{applyConfiguredBaseUrl as i}from"./baseUrl.js";import{applyClientHeaders as a,readAccountId as o,stampAccountId as s}from"./clientHeaders.js";import{applyDesignSample as c}from"./designSample.js";import{readMinAppVersion as l}from"./minAppVersion.js";import{sendFormDataAsMultipart as u}from"./multipart.js";import{applyRequestDefaults as d}from"./requestDefaults.js";import{responseBodyText as f}from"./responseBodyText.js";import{WorkspaceChangedError as p,isWorkspaceChangedResponse as m,workspaceChangedFromResponse as h}from"./workspaceChanged.js";import{attachRetry as g}from"./retry.js";import{SIGN_OUT_REASON_HEADER as _,beginSessionReplacement as v,currentTokenIfReplaced as y,endSessionAndLogout as b,getAccountIdProvider as x,getErrorMessage as S,getRefreshPath as C,injectStore as w,injectUserAuth as T,isRefreshInFlight as E,queueBehindRefresh as D,readSignOutReason as O,refreshAccessToken as k,resetRefreshState as A,storeReplacementSession as j,waitForSessionReplacement as M}from"./tokenRefresh.js";import N,{AxiosHeaders as P}from"axios";var F=class e extends Error{constructor(t=`Request blocked: device is offline`){super(t),this.name=`RequestOfflineError`,Object.setPrototypeOf(this,e.prototype)}},I=class e extends Error{constructor(){super(`No access token available`),this.name=`NoAccessTokenError`,Object.setPrototypeOf(this,e.prototype)}},L={TERMINATED:`SESSION_TERMINATED`,EXPIRED:`SESSION_EXPIRED`},R=new Set(Object.values(L)),z=`x-security-stamp-invalid`,B=e=>{if(!e||typeof e!=`object`)return!1;let t=e.get,n=typeof t==`function`?t.call(e,z):e[z];return String(n).toLowerCase()===`true`},V=e=>{if(!e||typeof e!=`object`)return;let t=e,n=t.error,r=[t.code,t.errorCode,n&&typeof n==`object`?n.code:void 0];for(let e of r)if(typeof e==`string`&&R.has(e))return e},H=e=>{e?._endReplacement?.(),e&&(e._endReplacement=void 0)},U=e=>{let t=e.headers instanceof P?e.headers.get(`Authorization`):void 0;return typeof t==`string`&&t.startsWith(`Bearer `)?t.slice(7):null},W=N.create({headers:{"Content-Type":`application/json`}});l(W),g(W);var G=(e,t)=>{e.headers instanceof P?e.headers.set(`Authorization`,`Bearer ${t}`):e.headers=P.from({...e.headers,Authorization:`Bearer ${t}`})},K=e=>{let t=C();return!!t&&!!e?.includes(t)};i(W),d(W),u(W),a(W),c(W),W.interceptors.request.use(async i=>{if(H(i),(await r()).isConnected===!1)return e.warn(`Request blocked: browser is offline. URL: ${i.url}`),Promise.reject(new F);try{if(K(i.url))return i;await s(i,x());let r=await n(t);if(!r?.token)throw new I;let a=Date.now();return Date.parse(r.expiry)<=a+30*1e3?(e.info(`Access token expired or about to expire, refreshing before request`),G(i,await k())):G(i,r.token),i.replacesSession&&(i._endReplacement=v()),i}catch(t){return t instanceof I?e.info(`Request not sent: signed out. URL: ${i.url}`):e.error(`Failed to attach token:`,S(t)),Promise.reject(t)}},t=>(e.error(`Request error:`,S(t)),Promise.reject(t))),W.interceptors.response.use(async e=>{let t=e.config;if(t._endReplacement)try{await j(e.data)}finally{H(t)}return e},async t=>{if(H(t?.config),N.isCancel(t)||t instanceof F||t instanceof I||t instanceof p)return Promise.reject(t);if(!N.isAxiosError(t))return e.error(`Non-axios error in response interceptor: ${S(t)}`),Promise.reject(t);let n=t,r=n.config;if(!n.response)return r?.skipErrorLog||e.error(`Network error or no response from server: ${n.message}, URL: ${r?.url}`),Promise.reject(t);if(m(n))return e.info(`Request refused: the workspace changed after it was made. URL: ${r?.url}`),Promise.reject(h(n));if(n.response.status===401&&r&&!r._replayedWithCurrentToken&&!r.replacesSession&&!K(r.url)&&(await M(),await y(U(r))))return(r._accountId??null)===await o(x())?(e.info(`Session changed while the request was in flight; sending it again. URL: ${r.url}`),r._replayedWithCurrentToken=!0,W(r)):(e.info(`Session moved to another workspace while the request was in flight; not sending it again. URL: ${r.url}`),Promise.reject(new p(void 0,{config:r,cause:t})));if(n.response.status===401&&r&&!r._retry){if(K(r.url))return Promise.reject(t);let i=O(n.response.headers),a=V(n.response.data)??(B(n.response.headers)||i!==null?L.TERMINATED:void 0);if(a)return e.warn(`Session ${a}, logging out without refresh. URL: ${r.url}`),A(),await b(`terminated`,i),Promise.reject(t);if(e.warn(`Unauthorized URL: ${r.url}`),r._retry=!0,E())return D().then(t=>(e.info(`Retrying request after token refresh:`,r.url),G(r,t),W(r))).catch(t=>(t instanceof p||e.error(`Failed to retry request after token refresh:`,S(t)),Promise.reject(t)));try{return G(r,await k()),W(r)}catch(e){return Promise.reject(e)}}return r?.skipErrorLog||e.error(`Response error: ${f(n.response?.data,n.message)}, URL: ${r?.url}, Status: ${n.response.status}`),Promise.reject(t)});export{F as RequestOfflineError,z as SESSION_INVALID_HEADER,L as SESSION_TERMINATION_CODES,_ as SIGN_OUT_REASON_HEADER,W as default,w as injectStore,T as injectUserAuth,A as resetRefreshState};
1
+ import{applyRequestDefaults as e}from"./requestDefaults.js";import{Logger as t}from"../logger/logger.js";import{ACCESS_TOKEN_KEY as n,getToken as r}from"../auth/authStore.js";import{getLastKnownNetworkStatus as i}from"../network/networkStatus.js";import{applyConfiguredBaseUrl as a}from"./baseUrl.js";import{applyClientHeaders as o,readAccountId as s,stampAccountId as c}from"./clientHeaders.js";import{applyDesignSample as l}from"./designSample.js";import{readMinAppVersion as u}from"./minAppVersion.js";import{sendFormDataAsMultipart as d}from"./multipart.js";import{responseBodyText as f}from"./responseBodyText.js";import{WorkspaceChangedError as p,isWorkspaceChangedResponse as m,workspaceChangedFromResponse as h}from"./workspaceChanged.js";import{attachRetry as g}from"./retry.js";import{SESSION_EXPIRED_CODE as _,SESSION_REVOKED_CODE as v,beginSessionReplacement as y,currentTokenIfReplaced as b,endSessionAndLogout as x,getAccountIdProvider as S,getErrorMessage as C,getRefreshPath as w,injectStore as T,injectUserAuth as E,isRefreshInFlight as D,queueBehindRefresh as O,refreshAccessToken as k,resetRefreshState as A,sessionCodeOf as j,storeReplacementSession as M,waitForSessionReplacement as N}from"./tokenRefresh.js";import P,{AxiosHeaders as F}from"axios";var I=class e extends Error{constructor(t=`Request blocked: device is offline`){super(t),this.name=`RequestOfflineError`,Object.setPrototypeOf(this,e.prototype)}},L=class e extends Error{constructor(){super(`No access token available`),this.name=`NoAccessTokenError`,Object.setPrototypeOf(this,e.prototype)}},R=e=>{e?._endReplacement?.(),e&&(e._endReplacement=void 0)},z=e=>{let t=e.headers instanceof F?e.headers.get(`Authorization`):void 0;return typeof t==`string`&&t.startsWith(`Bearer `)?t.slice(7):null},B=P.create({headers:{"Content-Type":`application/json`}});u(B),g(B);var V=(e,t)=>{e.headers instanceof F?e.headers.set(`Authorization`,`Bearer ${t}`):e.headers=F.from({...e.headers,Authorization:`Bearer ${t}`})},H=e=>{let t=w();return!!t&&!!e?.includes(t)};a(B),e(B),d(B),o(B),l(B),B.interceptors.request.use(async e=>{if(R(e),(await i()).isConnected===!1)return t.warn(`Request blocked: browser is offline. URL: ${e.url}`),Promise.reject(new I);try{if(H(e.url))return e;await c(e,S());let i=await r(n);if(!i?.token)throw new L;let a=Date.now();return Date.parse(i.expiry)<=a+30*1e3?(t.info(`Access token expired or about to expire, refreshing before request`),V(e,await k())):V(e,i.token),e.replacesSession&&(e._endReplacement=y()),e}catch(n){return n instanceof L?t.info(`Request not sent: signed out. URL: ${e.url}`):t.error(`Failed to attach token:`,C(n)),Promise.reject(n)}},e=>(t.error(`Request error:`,C(e)),Promise.reject(e))),B.interceptors.response.use(async e=>{let t=e.config;if(t._endReplacement)try{await M(e.data)}finally{R(t)}return e},async e=>{if(R(e?.config),P.isCancel(e)||e instanceof I||e instanceof L||e instanceof p)return Promise.reject(e);if(!P.isAxiosError(e))return t.error(`Non-axios error in response interceptor: ${C(e)}`),Promise.reject(e);let n=e,r=n.config;if(!n.response)return r?.skipErrorLog||t.error(`Network error or no response from server: ${n.message}, URL: ${r?.url}`),Promise.reject(e);if(m(n))return t.info(`Request refused: the workspace changed after it was made. URL: ${r?.url}`),Promise.reject(h(n));if(n.response.status===401&&r&&!r._replayedWithCurrentToken&&!r.replacesSession&&!H(r.url)&&(await N(),await b(z(r))))return(r._accountId??null)===await s(S())?(t.info(`Session changed while the request was in flight; sending it again. URL: ${r.url}`),r._replayedWithCurrentToken=!0,B(r)):(t.info(`Session moved to another workspace while the request was in flight; not sending it again. URL: ${r.url}`),Promise.reject(new p(void 0,{config:r,cause:e})));if(n.response.status===401&&r&&!r._retry){if(H(r.url))return Promise.reject(e);let i=j(n.response.data);if(i!==null)return t.warn(`Session ${i}, logging out without refresh. URL: ${r.url}`),A(),await x(`terminated`,i),Promise.reject(e);if(t.warn(`Unauthorized URL: ${r.url}`),r._retry=!0,D())return O().then(e=>(t.info(`Retrying request after token refresh:`,r.url),V(r,e),B(r))).catch(e=>(e instanceof p||t.error(`Failed to retry request after token refresh:`,C(e)),Promise.reject(e)));try{return V(r,await k()),B(r)}catch(e){return Promise.reject(e)}}return r?.skipErrorLog||t.error(`Response error: ${f(n.response?.data,n.message)}, URL: ${r?.url}, Status: ${n.response.status}`),Promise.reject(e)});export{I as RequestOfflineError,_ as SESSION_EXPIRED_CODE,v as SESSION_REVOKED_CODE,B as default,T as injectStore,E as injectUserAuth,A as resetRefreshState};
@@ -1 +1 @@
1
- var e=`workspace_changed`,t=e=>e&&typeof e==`object`&&!Array.isArray(e)?e:null,n=class t extends Error{code=e;response;config;cause;constructor(e=`This was started in another workspace. Switch back to it and try again.`,n={}){super(e),this.name=`WorkspaceChangedError`,this.response=n.response??{status:409,data:{code:`workspace_changed`,message:e},headers:{}},this.config=n.config,this.cause=n.cause,Object.setPrototypeOf(this,t.prototype)}},r=e=>e instanceof n||typeof e==`object`&&!!e&&(e.name===`WorkspaceChangedError`||e.code===`workspace_changed`),i=e=>e.response?.status===409&&t(e.response.data)?.code===`workspace_changed`,a=e=>{let r=t(e.response?.data)?.message;return new n(typeof r==`string`&&r.trim()!==``?r:void 0,{response:e.response,config:e.config,cause:e})};export{e as WORKSPACE_CHANGED_CODE,n as WorkspaceChangedError,r as isWorkspaceChangedError,i as isWorkspaceChangedResponse,a as workspaceChangedFromResponse};
1
+ var e=`workspace_changed`,t=e=>e&&typeof e==`object`&&!Array.isArray(e)?e:null,n=class t extends Error{code=e;response;config;cause;constructor(e=`This was started in another workspace. Switch back to it and try again.`,n={}){super(e),this.name=`WorkspaceChangedError`,this.response=n.response??{status:409,data:{code:`workspace_changed`,detail:e},headers:{}},this.config=n.config,this.cause=n.cause,Object.setPrototypeOf(this,t.prototype)}},r=e=>e instanceof n||typeof e==`object`&&!!e&&(e.name===`WorkspaceChangedError`||e.code===`workspace_changed`),i=e=>e.response?.status===409&&t(e.response.data)?.code===`workspace_changed`,a=e=>{let r=t(e.response?.data)?.detail;return new n(typeof r==`string`&&r.trim()!==``?r:void 0,{response:e.response,config:e.config,cause:e})};export{e as WORKSPACE_CHANGED_CODE,n as WorkspaceChangedError,r as isWorkspaceChangedError,i as isWorkspaceChangedResponse,a as workspaceChangedFromResponse};
@@ -1 +1 @@
1
- import{Logger as e}from"../logger/logger.js";import{getJWTExpiry as t}from"./jwt.js";var n=`accessToken`,r=`refreshToken`,i=`sessionUser`,a=720*60*60*1e3,o=new Set([n,r,i]),s=null,c=()=>globalThis.localStorage,l=()=>globalThis.sessionStorage,u=(e,t)=>{try{return e().getItem(t)}catch{return null}},d=(e,t)=>{try{e().removeItem(t)}catch{}},f=()=>s===null?u(c,`refreshToken`)!==null||u(c,`accessToken`)!==null:s,p=()=>f()?c:l,m=()=>f()?l:c,h=t=>{s=t;let n=p(),r=m();for(let t of o){let i=u(r,t);if(i!==null)try{n().setItem(t,i),d(r,t)}catch(n){e.error(`[authStore] could not move "${t}" to the chosen store`,n)}}},g=new Set,_=`sessionEnded`,v=()=>u(l,_)!==null,y=(t,n)=>{try{l().setItem(_,t)}catch{}for(let r of[...g])try{r(t,n)}catch(t){e.error(`[authStore] a session-ended listener threw`,t)}},b=e=>{if(e.storageArea!==c())return;let t=e.key===`refreshToken`&&e.oldValue!==null&&e.newValue===null;!(e.key===null||t)||u(l,`refreshToken`)!==null||y(`otherTab`,{signOutReason:null})},x=e=>(g.size===0&&typeof window<`u`&&window.addEventListener(`storage`,b),g.add(e),()=>{g.delete(e),g.size===0&&typeof window<`u`&&window.removeEventListener(`storage`,b)}),S=async(t,n,r)=>{try{p()().setItem(t,JSON.stringify({token:n,expiry:r})),d(m(),t),d(l,_)}catch(n){throw e.error(`Error storing token for key: ${t}`,n),n}},C=e=>{try{let t=JSON.parse(e);return t&&typeof t==`object`&&typeof t.token==`string`&&typeof t.expiry==`string`?t:null}catch{return null}},w=e=>u(l,e)??u(c,e),T=async t=>{let n=w(t);return n===null&&j(t)&&L()&&(n=w(t)),n===null?null:C(n)||(e.warn(`Stored credentials for key "${t}" are not a valid token; clearing them.`),j(t)?await R(`corrupt`,!0):await D(t),null)},E=()=>{w(`refreshToken`)===null&&w(`accessToken`)===null&&L();let e=w(r);if(e!==null&&C(e)!==null)return!0;let t=w(n),i=t===null?null:C(t);if(i===null)return!1;let a=Date.parse(i.expiry);return Number.isNaN(a)||a>Date.now()},D=async e=>{d(c,e),d(l,e)},O=async t=>{try{p()().setItem(i,JSON.stringify(t)),d(m(),i)}catch(t){throw e.error(`Error storing the session user`,t),t}},k=async()=>{let t=w(i);if(t===null)return null;try{return JSON.parse(t)}catch{return e.warn(`The stored session user is not valid JSON; clearing it.`),await A(),null}},A=async()=>{d(c,i),d(l,i)},j=e=>e===`accessToken`||e===`refreshToken`,M=null,N=!1,P=e=>{M=e,N=!1},F=e=>{let t=C(e);if(t)return t;let n=e;try{let t=JSON.parse(e);typeof t==`string`&&(n=t)}catch{}return n.trim()===``?null:{token:n,expiry:null}},I=e=>e.split(`.`).length===3?t(e)?.toISOString()??null:null,L=()=>{if(!M||N)return!1;N=!0;let t=M,a=[c,l].every(e=>u(e,`accessToken`)===null&&u(e,`refreshToken`)===null),o=!1;for(let s of[c,l]){let l=u(s,t.accessToken),f=u(s,t.refreshToken),p=t.sessionUser?u(s,t.sessionUser):null;if(a&&!o&&(l!==null||f!==null))try{let t=l===null?null:F(l),a=f===null?null:F(f);if(t){let e=t.expiry??I(t.token)??new Date().toISOString();s().setItem(n,JSON.stringify({token:t.token,expiry:e}))}if(a){let e=a.expiry??I(a.token)??new Date(Date.now()+2592e6).toISOString();s().setItem(r,JSON.stringify({token:a.token,expiry:e}))}p!==null&&s().setItem(i,p),o=t!==null||a!==null,o&&e.breadcrumb(`[authStore] moved a session from the legacy token keys`,{store:s===c?`localStorage`:`sessionStorage`})}catch(t){e.error(`[authStore] could not move the session from the legacy token keys`,t)}for(let e of[t.accessToken,t.refreshToken,t.sessionUser])e&&d(s,e)}return o},R=async(e,t,i=null)=>{let a=t||await T(`accessToken`)!==null||await T(`refreshToken`)!==null;await D(n),await D(r),await A(),s=null,(a||t)&&y(e,{signOutReason:i})},z=async(e=`signedOut`,t={})=>R(e,!1,t.signOutReason??null);export{n as ACCESS_TOKEN_KEY,a as LEGACY_REFRESH_TOKEN_LIFETIME_MS,r as REFRESH_TOKEN_KEY,i as SESSION_USER_KEY,x as addSessionEndedListener,z as clearSession,f as getKeepSignedIn,k as getSessionUser,T as getToken,E as hasSession,v as hasSessionEndedInTab,A as removeSessionUser,D as removeToken,h as setKeepSignedIn,P as setLegacyTokenKeys,O as storeSessionUser,S as storeToken};
1
+ import{Logger as e}from"../logger/logger.js";import{getJWTExpiry as t}from"./jwt.js";var n=`accessToken`,r=`refreshToken`,i=`sessionUser`,a=720*60*60*1e3,o=new Set([n,r,i]),s=null,c=()=>globalThis.localStorage,l=()=>globalThis.sessionStorage,u=(e,t)=>{try{return e().getItem(t)}catch{return null}},d=(e,t)=>{try{e().removeItem(t)}catch{}},f=()=>s===null?u(c,`refreshToken`)!==null||u(c,`accessToken`)!==null:s,p=()=>f()?c:l,m=()=>f()?l:c,h=t=>{s=t;let n=p(),r=m();for(let t of o){let i=u(r,t);if(i!==null)try{n().setItem(t,i),d(r,t)}catch(n){e.error(`[authStore] could not move "${t}" to the chosen store`,n)}}},g=new Set,_=`sessionEnded`,v=()=>u(l,_)!==null,y=(t,n)=>{try{l().setItem(_,t)}catch{}for(let r of[...g])try{r(t,n)}catch(t){e.error(`[authStore] a session-ended listener threw`,t)}},b=e=>{if(e.storageArea!==c())return;let t=e.key===`refreshToken`&&e.oldValue!==null&&e.newValue===null;!(e.key===null||t)||u(l,`refreshToken`)!==null||y(`otherTab`,{code:null})},x=e=>(g.size===0&&typeof window<`u`&&window.addEventListener(`storage`,b),g.add(e),()=>{g.delete(e),g.size===0&&typeof window<`u`&&window.removeEventListener(`storage`,b)}),S=async(t,n,r)=>{try{p()().setItem(t,JSON.stringify({token:n,expiry:r})),d(m(),t),d(l,_)}catch(n){throw e.error(`Error storing token for key: ${t}`,n),n}},C=e=>{try{let t=JSON.parse(e);return t&&typeof t==`object`&&typeof t.token==`string`&&typeof t.expiry==`string`?t:null}catch{return null}},w=e=>u(l,e)??u(c,e),T=async t=>{let n=w(t);return n===null&&j(t)&&L()&&(n=w(t)),n===null?null:C(n)||(e.warn(`Stored credentials for key "${t}" are not a valid token; clearing them.`),j(t)?await R(`corrupt`,!0):await D(t),null)},E=()=>{w(`refreshToken`)===null&&w(`accessToken`)===null&&L();let e=w(r);if(e!==null&&C(e)!==null)return!0;let t=w(n),i=t===null?null:C(t);if(i===null)return!1;let a=Date.parse(i.expiry);return Number.isNaN(a)||a>Date.now()},D=async e=>{d(c,e),d(l,e)},O=async t=>{try{p()().setItem(i,JSON.stringify(t)),d(m(),i)}catch(t){throw e.error(`Error storing the session user`,t),t}},k=async()=>{let t=w(i);if(t===null)return null;try{return JSON.parse(t)}catch{return e.warn(`The stored session user is not valid JSON; clearing it.`),await A(),null}},A=async()=>{d(c,i),d(l,i)},j=e=>e===`accessToken`||e===`refreshToken`,M=null,N=!1,P=e=>{M=e,N=!1},F=e=>{let t=C(e);if(t)return t;let n=e;try{let t=JSON.parse(e);typeof t==`string`&&(n=t)}catch{}return n.trim()===``?null:{token:n,expiry:null}},I=e=>e.split(`.`).length===3?t(e)?.toISOString()??null:null,L=()=>{if(!M||N)return!1;N=!0;let t=M,a=[c,l].every(e=>u(e,`accessToken`)===null&&u(e,`refreshToken`)===null),o=!1;for(let s of[c,l]){let l=u(s,t.accessToken),f=u(s,t.refreshToken),p=t.sessionUser?u(s,t.sessionUser):null;if(a&&!o&&(l!==null||f!==null))try{let t=l===null?null:F(l),a=f===null?null:F(f);if(t){let e=t.expiry??I(t.token)??new Date().toISOString();s().setItem(n,JSON.stringify({token:t.token,expiry:e}))}if(a){let e=a.expiry??I(a.token)??new Date(Date.now()+2592e6).toISOString();s().setItem(r,JSON.stringify({token:a.token,expiry:e}))}p!==null&&s().setItem(i,p),o=t!==null||a!==null,o&&e.breadcrumb(`[authStore] moved a session from the legacy token keys`,{store:s===c?`localStorage`:`sessionStorage`})}catch(t){e.error(`[authStore] could not move the session from the legacy token keys`,t)}for(let e of[t.accessToken,t.refreshToken,t.sessionUser])e&&d(s,e)}return o},R=async(e,t,i=null)=>{let a=t||await T(`accessToken`)!==null||await T(`refreshToken`)!==null;await D(n),await D(r),await A(),s=null,(a||t)&&y(e,{code:i})},z=async(e=`signedOut`,t={})=>R(e,!1,t.code??null);export{n as ACCESS_TOKEN_KEY,a as LEGACY_REFRESH_TOKEN_LIFETIME_MS,r as REFRESH_TOKEN_KEY,i as SESSION_USER_KEY,x as addSessionEndedListener,z as clearSession,f as getKeepSignedIn,k as getSessionUser,T as getToken,E as hasSession,v as hasSessionEndedInTab,A as removeSessionUser,D as removeToken,h as setKeepSignedIn,P as setLegacyTokenKeys,O as storeSessionUser,S as storeToken};
@@ -1 +1 @@
1
- var e=`warn`,t=3e4,n=3,r=`X-Correlation-Id`,i=`/version.json`,a=3e5,o={baseUrl:null,loggingEnabled:!0,logLevel:e,environment:`Development`,appVersion:null,commit:null,appBuild:null,buildId:null,versionUrl:i,buildCheckIntervalMs:a,timeoutMs:t,retries:3,correlationIdHeader:r,staticAssets:null},s={...o},c=e=>{s={...s,...e}},l=()=>s;function u(e,t){let n=s[e];return n===null?t:n}var d=()=>{s={...o}};export{a as DEFAULT_BUILD_CHECK_INTERVAL_MS,r as DEFAULT_CORRELATION_ID_HEADER,e as DEFAULT_LOG_LEVEL,n as DEFAULT_RETRIES,t as DEFAULT_TIMEOUT_MS,i as DEFAULT_VERSION_URL,l as getConfig,u as getConfigValue,d as resetConfig,c as setConfig};
1
+ var e=`warn`,t=3e4,n=3,r=`/version.json`,i=3e5,a={baseUrl:null,loggingEnabled:!0,logLevel:e,environment:`Development`,appVersion:null,commit:null,appBuild:null,buildId:null,versionUrl:r,buildCheckIntervalMs:i,timeoutMs:t,retries:3,staticAssets:null},o={...a},s=e=>{o={...o,...e}},c=()=>o;function l(e,t){let n=o[e];return n===null?t:n}var u=()=>{o={...a}};export{i as DEFAULT_BUILD_CHECK_INTERVAL_MS,e as DEFAULT_LOG_LEVEL,n as DEFAULT_RETRIES,t as DEFAULT_TIMEOUT_MS,r as DEFAULT_VERSION_URL,c as getConfig,l as getConfigValue,u as resetConfig,s as setConfig};
@@ -1,2 +1,2 @@
1
1
  var e=`Something went wrong on our side. Please try again in a moment.`,t=`You appear to be offline. Check your connection and try again.`,n=`We couldn't reach the server. Check your connection and try again.`,r=`That took too long to respond. Check your connection and try again.`,i=`Something went wrong. Please try again.`,a=`request_canceled`,o=`contract_error`,s=`timeout`,c=`network`,l=`offline`,u=e=>`Request failed (${e})`,d=e=>typeof e==`object`&&!!e&&!Array.isArray(e),f=e=>typeof e==`string`&&e.trim().length>0?e:null,p=e=>e.length>300||/^\s*</.test(e)||e.includes(`
2
- at `)||/\b(Exception|StackTrace):/.test(e)||/\b(System|Microsoft)\.[A-Za-z]+\.[A-Za-z]/.test(e),m=e=>{let t=f(e);return t!==null&&!p(t)?t:null},h=e=>e.replace(/^\$\.?/,``).split(`.`).map(e=>e.charAt(0).toLowerCase()+e.slice(1)).join(`.`),g=e=>{if(Array.isArray(e)){for(let t of e){let e=f(t);if(e!==null)return e}return null}return f(e)},_=(e,t,n)=>{let r=h(t);r===``?e.form??=n:r in e.fields||(e.fields[r]=n)},v=e=>{let t={fields:{},form:null};if(Array.isArray(e)){for(let n of e){if(!d(n))continue;let e=f(n.message);e!==null&&_(t,typeof n.field==`string`?n.field:``,e)}return t}if(!d(e))return t;for(let[n,r]of Object.entries(e)){let e=g(r);e!==null&&_(t,n,e)}return t},y=e=>{let t=e.error;return d(t)?f(t.message):f(t)},b=e=>d(e)&&typeof e.message==`string`&&typeof e.status==`number`&&typeof e.offline==`boolean`&&d(e.fieldErrors),x=e=>({code:null,fieldErrors:{},status:0,offline:!1,traceId:null,detail:null,...e}),S=()=>typeof navigator<`u`&&navigator.onLine===!1,C=e=>{let o=f(e.code),u=f(e.name),d=f(e.message);return u===`CanceledError`||o===`ERR_CANCELED`?x({code:a,message:i,detail:d}):o===`ECONNABORTED`||o===`ETIMEDOUT`?x({code:s,message:r,offline:!0,detail:d}):u===`RequestOfflineError`||o===`ERR_NETWORK`||d===`Network Error`?S()?x({code:l,message:t,offline:!0,detail:d}):x({code:c,message:n,offline:!0,detail:d}):x({message:i,detail:d})};function w(e){if(b(e))return e;if(typeof e==`string`)return x({message:m(e)??`Something went wrong. Please try again.`,detail:e||null});if(!d(e))return x({message:i,detail:e==null?null:String(e)});if(e.isContractError===!0)return x({code:o,message:m(e.message)??`Something went wrong. Please try again.`,detail:f(e.message)});let t=d(e.response)?e.response:null,n=typeof t?.status==`number`?t.status:typeof e.status==`number`?e.status:0,r=t?t.data:e.body;if(n===0&&r==null)return C(e);let a=d(r)?r:null,{fields:s,form:c}=v(a?.errors),l=f(a?.code),p=f(a?.traceId),h=f(a?.message)??f(a?.detail)??(a?y(a):null)??f(a?.title)??f(r)??f(e.message),g;return g=n>=500?(l!==null&&l!==`internal_error`?m(a?.message):null)??`Something went wrong on our side. Please try again in a moment.`:m(Object.values(s)[0])??m(c)??m(a?.message)??m(a?.detail)??(a?m(y(a)):null)??m(a?.title)??m(r)??(n?u(n):`Something went wrong. Please try again.`),x({code:l,message:g,fieldErrors:s,status:n,traceId:p,detail:h})}var T=e=>w(e).offline;function E(e,t){let n=w(e);return n.offline||t!==null&&!t||n.status>=500&&n.message!==`Something went wrong on our side. Please try again in a moment.`?n.message:n.status>=500||n.code===`request_canceled`||n.message===`Something went wrong. Please try again.`||n.message===u(n.status)?t??null:n.message}export{o as CONTRACT_ERROR_CODE,c as NETWORK_CODE,l as OFFLINE_CODE,t as OFFLINE_MESSAGE,a as REQUEST_CANCELED_CODE,e as SERVER_FAILURE_MESSAGE,s as TIMEOUT_CODE,r as TIMEOUT_MESSAGE,i as UNEXPECTED_MESSAGE,n as UNREACHABLE_MESSAGE,E as apiErrorMessage,w as extractApiError,b as isApiError,T as isNoResponse,h as toFieldPath};
2
+ at `)||/\b(Exception|StackTrace):/.test(e)||/\b(System|Microsoft)\.[A-Za-z]+\.[A-Za-z]/.test(e),m=e=>{let t=f(e);return t!==null&&!p(t)?t:null},h=e=>e.replace(/^\$\.?/,``).split(`.`).map(e=>e.charAt(0).toLowerCase()+e.slice(1)).join(`.`),g=e=>{if(Array.isArray(e)){for(let t of e){let e=f(t);if(e!==null)return e}return null}return f(e)},_=(e,t,n)=>{let r=h(t);r===``?e.form??=n:r in e.fields||(e.fields[r]=n)},v=e=>{let t={fields:{},form:null};if(Array.isArray(e)){for(let n of e){if(!d(n))continue;let e=f(n.message);e!==null&&_(t,typeof n.field==`string`?n.field:``,e)}return t}if(!d(e))return t;for(let[n,r]of Object.entries(e)){let e=g(r);e!==null&&_(t,n,e)}return t},y=e=>d(e)&&typeof e.message==`string`&&typeof e.status==`number`&&typeof e.offline==`boolean`&&d(e.fieldErrors),b=e=>({code:null,fieldErrors:{},status:0,offline:!1,traceId:null,diagnostic:null,...e}),x=()=>typeof navigator<`u`&&navigator.onLine===!1,S=e=>{let t=d(e.config)?e.config.headers:void 0;if(!d(t))return null;let n=typeof t.get==`function`?t.get(`traceparent`):t.traceparent??t.Traceparent,r=typeof n==`string`?/^00-([0-9a-f]{32})-[0-9a-f]{16}-[0-9a-f]{2}$/.exec(n):null;return r?r[1]:null},C=e=>{let o=f(e.code),u=f(e.name),d=f(e.message),p=S(e);return u===`CanceledError`||o===`ERR_CANCELED`?b({code:a,message:i,traceId:p,diagnostic:d}):o===`ECONNABORTED`||o===`ETIMEDOUT`?b({code:s,message:r,offline:!0,traceId:p,diagnostic:d}):u===`RequestOfflineError`||o===`ERR_NETWORK`||d===`Network Error`?x()?b({code:l,message:t,offline:!0,traceId:p,diagnostic:d}):b({code:c,message:n,offline:!0,traceId:p,diagnostic:d}):b({message:i,traceId:p,diagnostic:d})};function w(e){if(y(e))return e;if(typeof e==`string`)return b({message:m(e)??`Something went wrong. Please try again.`,diagnostic:e||null});if(!d(e))return b({message:i,diagnostic:e==null?null:String(e)});if(e.isContractError===!0)return b({code:o,message:m(e.message)??`Something went wrong. Please try again.`,diagnostic:f(e.message)});let t=d(e.response)?e.response:null,n=typeof t?.status==`number`?t.status:typeof e.status==`number`?e.status:0,r=t?t.data:e.body;if(n===0&&r==null)return C(e);let a=d(r)?r:null,{fields:s,form:c}=v(a?.errors),l=f(a?.code),p=f(a?.traceId)??S(e),h=f(a?.detail)??f(a?.title)??f(r)??f(e.message),g;return g=n>=500?(l!==null&&l!==`internal_error`?m(a?.detail):null)??`Something went wrong on our side. Please try again in a moment.`:m(Object.values(s)[0])??m(c)??m(a?.detail)??m(a?.title)??m(r)??(n?u(n):`Something went wrong. Please try again.`),b({code:l,message:g,fieldErrors:s,status:n,traceId:p,diagnostic:h})}var T=e=>w(e).offline;function E(e,t){let n=w(e);return n.offline||t!==null&&!t||n.status>=500&&n.message!==`Something went wrong on our side. Please try again in a moment.`?n.message:n.status>=500||n.code===`request_canceled`||n.message===`Something went wrong. Please try again.`||n.message===u(n.status)?t??null:n.message}export{o as CONTRACT_ERROR_CODE,c as NETWORK_CODE,l as OFFLINE_CODE,t as OFFLINE_MESSAGE,a as REQUEST_CANCELED_CODE,e as SERVER_FAILURE_MESSAGE,s as TIMEOUT_CODE,r as TIMEOUT_MESSAGE,i as UNEXPECTED_MESSAGE,n as UNREACHABLE_MESSAGE,E as apiErrorMessage,w as extractApiError,y as isApiError,T as isNoResponse,h as toFieldPath};
package/dist/index.js CHANGED
@@ -1 +1 @@
1
- import{DEFAULT_BUILD_CHECK_INTERVAL_MS as e,DEFAULT_CORRELATION_ID_HEADER as t,DEFAULT_LOG_LEVEL as n,DEFAULT_RETRIES as r,DEFAULT_TIMEOUT_MS as i,DEFAULT_VERSION_URL as a,getConfig as o,getConfigValue as s,resetConfig as c,setConfig as l}from"./config/index.js";import{Logger as u,configureLogger as d,getDeviceContext as f,setDeviceContext as p,setRemoteLogger as m}from"./logger/logger.js";import{decodeJWT as h,getJWTExpiry as g,isJWTExpired as _}from"./auth/jwt.js";import{ACCESS_TOKEN_KEY as v,LEGACY_REFRESH_TOKEN_LIFETIME_MS as y,REFRESH_TOKEN_KEY as b,SESSION_USER_KEY as x,addSessionEndedListener as S,clearSession as C,getKeepSignedIn as w,getSessionUser as T,getToken as E,hasSession as D,hasSessionEndedInTab as O,removeSessionUser as k,removeToken as A,setKeepSignedIn as j,setLegacyTokenKeys as M,storeSessionUser as N,storeToken as P}from"./auth/authStore.js";import{addNetworkStatusListener as F,getNetworkStatus as I,setNetworkStatusImplementation as L,useNetworkStatus as R}from"./network/networkStatus.js";import{ACCOUNT_ID_HEADER as z,CLIENT_BUILD_HEADER as B,CLIENT_KIND as V,CLIENT_KIND_HEADER as H,getClientBuild as U}from"./api/clientHeaders.js";import{DESIGN_SAMPLE_HEADER as W,DESIGN_SAMPLE_QUERY_KEY as G,DESIGN_SAMPLE_STORAGE_KEY as K,applyDesignSample as q,readDesignSampleTicket as J}from"./api/designSample.js";import{MIN_APP_VERSION_HEADER as Y,addMinAppVersionListener as X,getMinAppVersion as Z}from"./api/minAppVersion.js";import{applyRequestDefaults as Q,newCorrelationId as $}from"./api/requestDefaults.js";import{WORKSPACE_CHANGED_CODE as ee,WorkspaceChangedError as te,isWorkspaceChangedError as ne}from"./api/workspaceChanged.js";import{IDEMPOTENCY_KEY_HEADER as re,attachRetry as ie,isNeverSentError as ae,isRetryableFailure as oe,isRetryableStatus as se,retryAfterMs as ce}from"./api/retry.js";import{REFRESH_LOCK_NAME as le,withCrossTabRefreshLock as ue}from"./api/crossTabRefreshLock.js";import de from"./api/publicClient.js";import{SIGN_OUT_REASON_HEADER as fe,injectStore as pe,injectUserAuth as me,refreshAccessToken as he,resetRefreshState as ge}from"./api/tokenRefresh.js";import _e,{RequestOfflineError as ve,SESSION_TERMINATION_CODES as ye}from"./api/userClient.js";import{initUserAuth as be}from"./initUserAuth.js";import{CONTRACT_ERROR_CODE as xe,NETWORK_CODE as Se,OFFLINE_CODE as Ce,OFFLINE_MESSAGE as we,REQUEST_CANCELED_CODE as Te,SERVER_FAILURE_MESSAGE as Ee,TIMEOUT_CODE as De,TIMEOUT_MESSAGE as Oe,UNEXPECTED_MESSAGE as ke,UNREACHABLE_MESSAGE as Ae,apiErrorMessage as je,extractApiError as Me,isApiError as Ne,isNoResponse as Pe,toFieldPath as Fe}from"./errors/extractApiError.js";import{configureFormatters as Ie,getFormatterConfig as Le}from"./formatters/formatConfig.js";import{formatCurrency as Re}from"./formatters/currency.js";import{addDays as ze}from"./formatters/dateMath.js";import{formatDate as Be,formatDateTime as Ve,formatMinor as He,formatNumber as Ue,formatPercent as We,formatRelative as Ge,formatTime as Ke}from"./formatters/house.js";import{initWebority as qe}from"./initSDK.js";import{createApiBaseQuery as Je}from"./query/apiBaseQuery.js";import{APP_API_DEFAULTS as Ye,createAppApi as Xe}from"./query/createAppApi.js";import{setupApiListeners as Ze}from"./query/listeners.js";import{buildListQuery as Qe,getNextPageParam as $e,getPreviousPageParam as et,hasNextPage as tt,hasPreviousPage as nt}from"./query/paging.js";import{LIST_TAG_ID as rt,itemTag as it,listTag as at,providesList as ot,providesPagedList as st}from"./query/tags.js";import{errorToastMiddleware as ct,isSilentRejection as lt}from"./redux/errorToastMiddleware.js";import{createRootReducer as ut,resetState as dt}from"./redux/rootReducer.js";import{SERIALIZABLE_IGNORED_ACTION_PATHS as ft}from"./redux/serializableCheck.js";import{hasRecentlyReloaded as pt,importWithReload as mt,isChunkLoadError as ht,lazyWithReload as gt,markReloaded as _t}from"./router/chunkReload.js";import{hasPermission as vt}from"./router/permissions.js";import{RETURN_TO_PARAM as yt,buildLoginPath as bt,getReturnTo as xt,toSafeReturnTo as St}from"./router/returnTo.js";import{PublicOnly as Ct,RequireAuth as wt,RequirePermission as Tt}from"./router/guards.js";import{publicOnly as Et,requireAuth as Dt,requirePermission as Ot,withGuards as kt}from"./router/loaders.js";import{classifyRouteError as At,useRouteErrorReport as jt}from"./router/routeError.js";import{staticUrl as Mt}from"./static/index.js";import{Storage as Nt,isStorageAvailable as Pt,setStorageImplementation as Ft,syncStorage as It}from"./storage/index.js";import{isBuildBelowMinimum as Lt,parseBuildNumber as Rt}from"./versionCheck/buildNumber.js";import{addDeployedBuildListener as zt,getNewerDeployedBuild as Bt,startDeployedBuildCheck as Vt}from"./versionCheck/deployedBuild.js";import{installReloadOnNavigate as Ht,isUpdateAvailable as Ut,useVersionCheck as Wt}from"./versionCheck/index.js";export{v as ACCESS_TOKEN_KEY,z as ACCOUNT_ID_HEADER,Ye as APP_API_DEFAULTS,B as CLIENT_BUILD_HEADER,V as CLIENT_KIND,H as CLIENT_KIND_HEADER,xe as CONTRACT_ERROR_CODE,e as DEFAULT_BUILD_CHECK_INTERVAL_MS,t as DEFAULT_CORRELATION_ID_HEADER,n as DEFAULT_LOG_LEVEL,r as DEFAULT_RETRIES,i as DEFAULT_TIMEOUT_MS,a as DEFAULT_VERSION_URL,W as DESIGN_SAMPLE_HEADER,G as DESIGN_SAMPLE_QUERY_KEY,K as DESIGN_SAMPLE_STORAGE_KEY,re as IDEMPOTENCY_KEY_HEADER,y as LEGACY_REFRESH_TOKEN_LIFETIME_MS,rt as LIST_TAG_ID,u as Logger,Y as MIN_APP_VERSION_HEADER,Se as NETWORK_CODE,Ce as OFFLINE_CODE,we as OFFLINE_MESSAGE,Ct as PublicOnly,le as REFRESH_LOCK_NAME,b as REFRESH_TOKEN_KEY,Te as REQUEST_CANCELED_CODE,yt as RETURN_TO_PARAM,ve as RequestOfflineError,wt as RequireAuth,Tt as RequirePermission,ft as SERIALIZABLE_IGNORED_ACTION_PATHS,Ee as SERVER_FAILURE_MESSAGE,ye as SESSION_TERMINATION_CODES,x as SESSION_USER_KEY,fe as SIGN_OUT_REASON_HEADER,Nt as Storage,De as TIMEOUT_CODE,Oe as TIMEOUT_MESSAGE,ke as UNEXPECTED_MESSAGE,Ae as UNREACHABLE_MESSAGE,ee as WORKSPACE_CHANGED_CODE,te as WorkspaceChangedError,ze as addDays,zt as addDeployedBuildListener,X as addMinAppVersionListener,F as addNetworkStatusListener,S as addSessionEndedListener,je as apiErrorMessage,q as applyDesignSample,Q as applyRequestDefaults,ie as attachRetry,Qe as buildListQuery,bt as buildLoginPath,At as classifyRouteError,C as clearSession,Ie as configureFormatters,d as configureLogger,Je as createApiBaseQuery,Xe as createAppApi,ut as createRootReducer,h as decodeJWT,ct as errorToastMiddleware,Me as extractApiError,Re as formatCurrency,Be as formatDate,Ve as formatDateTime,He as formatMinor,Ue as formatNumber,We as formatPercent,Ge as formatRelative,Ke as formatTime,U as getClientBuild,o as getConfig,s as getConfigValue,f as getDeviceContext,Le as getFormatterConfig,g as getJWTExpiry,w as getKeepSignedIn,Z as getMinAppVersion,I as getNetworkStatus,Bt as getNewerDeployedBuild,$e as getNextPageParam,et as getPreviousPageParam,xt as getReturnTo,T as getSessionUser,E as getToken,tt as hasNextPage,vt as hasPermission,nt as hasPreviousPage,pt as hasRecentlyReloaded,D as hasSession,O as hasSessionEndedInTab,mt as importWithReload,be as initUserAuth,qe as initWebority,pe as injectStore,me as injectUserAuth,Ht as installReloadOnNavigate,Ne as isApiError,Lt as isBuildBelowMinimum,ht as isChunkLoadError,_ as isJWTExpired,ae as isNeverSentError,Pe as isNoResponse,oe as isRetryableFailure,se as isRetryableStatus,lt as isSilentRejection,Pt as isStorageAvailable,Ut as isUpdateAvailable,ne as isWorkspaceChangedError,it as itemTag,gt as lazyWithReload,at as listTag,_t as markReloaded,$ as newCorrelationId,Rt as parseBuildNumber,ot as providesList,st as providesPagedList,de as publicClient,Et as publicOnly,J as readDesignSampleTicket,he as refreshAccessToken,k as removeSessionUser,A as removeToken,Dt as requireAuth,Ot as requirePermission,c as resetConfig,ge as resetRefreshState,dt as resetState,ce as retryAfterMs,l as setConfig,p as setDeviceContext,j as setKeepSignedIn,M as setLegacyTokenKeys,L as setNetworkStatusImplementation,m as setRemoteLogger,Ft as setStorageImplementation,Ze as setupApiListeners,Vt as startDeployedBuildCheck,Mt as staticUrl,N as storeSessionUser,P as storeToken,It as syncStorage,Fe as toFieldPath,St as toSafeReturnTo,R as useNetworkStatus,jt as useRouteErrorReport,Wt as useVersionCheck,_e as userClient,ue as withCrossTabRefreshLock,kt as withGuards};
1
+ import{DEFAULT_BUILD_CHECK_INTERVAL_MS as e,DEFAULT_LOG_LEVEL as t,DEFAULT_RETRIES as n,DEFAULT_TIMEOUT_MS as r,DEFAULT_VERSION_URL as i,getConfig as a,getConfigValue as o,resetConfig as s,setConfig as c}from"./config/index.js";import{TRACEPARENT_HEADER as l,applyRequestDefaults as u,newTraceparent as d}from"./api/requestDefaults.js";import{Logger as f,configureLogger as p,getDeviceContext as m,setDeviceContext as h,setRemoteLogger as g}from"./logger/logger.js";import{decodeJWT as _,getJWTExpiry as v,isJWTExpired as y}from"./auth/jwt.js";import{ACCESS_TOKEN_KEY as b,LEGACY_REFRESH_TOKEN_LIFETIME_MS as x,REFRESH_TOKEN_KEY as S,SESSION_USER_KEY as C,addSessionEndedListener as w,clearSession as T,getKeepSignedIn as E,getSessionUser as D,getToken as O,hasSession as k,hasSessionEndedInTab as A,removeSessionUser as j,removeToken as M,setKeepSignedIn as N,setLegacyTokenKeys as P,storeSessionUser as F,storeToken as I}from"./auth/authStore.js";import{addNetworkStatusListener as L,getNetworkStatus as R,setNetworkStatusImplementation as z,useNetworkStatus as B}from"./network/networkStatus.js";import{ACCOUNT_ID_HEADER as V,CLIENT_BUILD_HEADER as H,CLIENT_KIND as U,CLIENT_KIND_HEADER as W,getClientBuild as G}from"./api/clientHeaders.js";import{DESIGN_SAMPLE_HEADER as K,DESIGN_SAMPLE_QUERY_KEY as q,DESIGN_SAMPLE_STORAGE_KEY as J,applyDesignSample as Y,readDesignSampleTicket as X}from"./api/designSample.js";import{MIN_APP_VERSION_HEADER as Z,addMinAppVersionListener as Q,getMinAppVersion as $}from"./api/minAppVersion.js";import{WORKSPACE_CHANGED_CODE as ee,WorkspaceChangedError as te,isWorkspaceChangedError as ne}from"./api/workspaceChanged.js";import{IDEMPOTENCY_KEY_HEADER as re,attachRetry as ie,isNeverSentError as ae,isRetryableFailure as oe,isRetryableStatus as se,retryAfterMs as ce}from"./api/retry.js";import{REFRESH_LOCK_NAME as le,withCrossTabRefreshLock as ue}from"./api/crossTabRefreshLock.js";import de from"./api/publicClient.js";import{SESSION_EXPIRED_CODE as fe,SESSION_REVOKED_CODE as pe,injectStore as me,injectUserAuth as he,refreshAccessToken as ge,resetRefreshState as _e}from"./api/tokenRefresh.js";import ve,{RequestOfflineError as ye}from"./api/userClient.js";import{initUserAuth as be}from"./initUserAuth.js";import{CONTRACT_ERROR_CODE as xe,NETWORK_CODE as Se,OFFLINE_CODE as Ce,OFFLINE_MESSAGE as we,REQUEST_CANCELED_CODE as Te,SERVER_FAILURE_MESSAGE as Ee,TIMEOUT_CODE as De,TIMEOUT_MESSAGE as Oe,UNEXPECTED_MESSAGE as ke,UNREACHABLE_MESSAGE as Ae,apiErrorMessage as je,extractApiError as Me,isApiError as Ne,isNoResponse as Pe,toFieldPath as Fe}from"./errors/extractApiError.js";import{configureFormatters as Ie,getFormatterConfig as Le}from"./formatters/formatConfig.js";import{formatCurrency as Re}from"./formatters/currency.js";import{addDays as ze}from"./formatters/dateMath.js";import{formatDate as Be,formatDateTime as Ve,formatMinor as He,formatNumber as Ue,formatPercent as We,formatRelative as Ge,formatTime as Ke}from"./formatters/house.js";import{initWebority as qe}from"./initSDK.js";import{createApiBaseQuery as Je}from"./query/apiBaseQuery.js";import{APP_API_DEFAULTS as Ye,createAppApi as Xe}from"./query/createAppApi.js";import{setupApiListeners as Ze}from"./query/listeners.js";import{buildListQuery as Qe,getNextPageParam as $e,getPreviousPageParam as et,hasNextPage as tt,hasPreviousPage as nt}from"./query/paging.js";import{LIST_TAG_ID as rt,itemTag as it,listTag as at,providesList as ot,providesPagedList as st}from"./query/tags.js";import{errorToastMiddleware as ct,isSilentRejection as lt}from"./redux/errorToastMiddleware.js";import{createRootReducer as ut,resetState as dt}from"./redux/rootReducer.js";import{SERIALIZABLE_IGNORED_ACTION_PATHS as ft}from"./redux/serializableCheck.js";import{hasRecentlyReloaded as pt,importWithReload as mt,isChunkLoadError as ht,lazyWithReload as gt,markReloaded as _t}from"./router/chunkReload.js";import{hasPermission as vt}from"./router/permissions.js";import{RETURN_TO_PARAM as yt,buildLoginPath as bt,getReturnTo as xt,toSafeReturnTo as St}from"./router/returnTo.js";import{PublicOnly as Ct,RequireAuth as wt,RequirePermission as Tt}from"./router/guards.js";import{publicOnly as Et,requireAuth as Dt,requirePermission as Ot,withGuards as kt}from"./router/loaders.js";import{classifyRouteError as At,useRouteErrorReport as jt}from"./router/routeError.js";import{staticUrl as Mt}from"./static/index.js";import{Storage as Nt,isStorageAvailable as Pt,setStorageImplementation as Ft,syncStorage as It}from"./storage/index.js";import{isBuildBelowMinimum as Lt,parseBuildNumber as Rt}from"./versionCheck/buildNumber.js";import{addDeployedBuildListener as zt,getNewerDeployedBuild as Bt,startDeployedBuildCheck as Vt}from"./versionCheck/deployedBuild.js";import{installReloadOnNavigate as Ht,isUpdateAvailable as Ut,useVersionCheck as Wt}from"./versionCheck/index.js";export{b as ACCESS_TOKEN_KEY,V as ACCOUNT_ID_HEADER,Ye as APP_API_DEFAULTS,H as CLIENT_BUILD_HEADER,U as CLIENT_KIND,W as CLIENT_KIND_HEADER,xe as CONTRACT_ERROR_CODE,e as DEFAULT_BUILD_CHECK_INTERVAL_MS,t as DEFAULT_LOG_LEVEL,n as DEFAULT_RETRIES,r as DEFAULT_TIMEOUT_MS,i as DEFAULT_VERSION_URL,K as DESIGN_SAMPLE_HEADER,q as DESIGN_SAMPLE_QUERY_KEY,J as DESIGN_SAMPLE_STORAGE_KEY,re as IDEMPOTENCY_KEY_HEADER,x as LEGACY_REFRESH_TOKEN_LIFETIME_MS,rt as LIST_TAG_ID,f as Logger,Z as MIN_APP_VERSION_HEADER,Se as NETWORK_CODE,Ce as OFFLINE_CODE,we as OFFLINE_MESSAGE,Ct as PublicOnly,le as REFRESH_LOCK_NAME,S as REFRESH_TOKEN_KEY,Te as REQUEST_CANCELED_CODE,yt as RETURN_TO_PARAM,ye as RequestOfflineError,wt as RequireAuth,Tt as RequirePermission,ft as SERIALIZABLE_IGNORED_ACTION_PATHS,Ee as SERVER_FAILURE_MESSAGE,fe as SESSION_EXPIRED_CODE,pe as SESSION_REVOKED_CODE,C as SESSION_USER_KEY,Nt as Storage,De as TIMEOUT_CODE,Oe as TIMEOUT_MESSAGE,l as TRACEPARENT_HEADER,ke as UNEXPECTED_MESSAGE,Ae as UNREACHABLE_MESSAGE,ee as WORKSPACE_CHANGED_CODE,te as WorkspaceChangedError,ze as addDays,zt as addDeployedBuildListener,Q as addMinAppVersionListener,L as addNetworkStatusListener,w as addSessionEndedListener,je as apiErrorMessage,Y as applyDesignSample,u as applyRequestDefaults,ie as attachRetry,Qe as buildListQuery,bt as buildLoginPath,At as classifyRouteError,T as clearSession,Ie as configureFormatters,p as configureLogger,Je as createApiBaseQuery,Xe as createAppApi,ut as createRootReducer,_ as decodeJWT,ct as errorToastMiddleware,Me as extractApiError,Re as formatCurrency,Be as formatDate,Ve as formatDateTime,He as formatMinor,Ue as formatNumber,We as formatPercent,Ge as formatRelative,Ke as formatTime,G as getClientBuild,a as getConfig,o as getConfigValue,m as getDeviceContext,Le as getFormatterConfig,v as getJWTExpiry,E as getKeepSignedIn,$ as getMinAppVersion,R as getNetworkStatus,Bt as getNewerDeployedBuild,$e as getNextPageParam,et as getPreviousPageParam,xt as getReturnTo,D as getSessionUser,O as getToken,tt as hasNextPage,vt as hasPermission,nt as hasPreviousPage,pt as hasRecentlyReloaded,k as hasSession,A as hasSessionEndedInTab,mt as importWithReload,be as initUserAuth,qe as initWebority,me as injectStore,he as injectUserAuth,Ht as installReloadOnNavigate,Ne as isApiError,Lt as isBuildBelowMinimum,ht as isChunkLoadError,y as isJWTExpired,ae as isNeverSentError,Pe as isNoResponse,oe as isRetryableFailure,se as isRetryableStatus,lt as isSilentRejection,Pt as isStorageAvailable,Ut as isUpdateAvailable,ne as isWorkspaceChangedError,it as itemTag,gt as lazyWithReload,at as listTag,_t as markReloaded,d as newTraceparent,Rt as parseBuildNumber,ot as providesList,st as providesPagedList,de as publicClient,Et as publicOnly,X as readDesignSampleTicket,ge as refreshAccessToken,j as removeSessionUser,M as removeToken,Dt as requireAuth,Ot as requirePermission,s as resetConfig,_e as resetRefreshState,dt as resetState,ce as retryAfterMs,c as setConfig,h as setDeviceContext,N as setKeepSignedIn,P as setLegacyTokenKeys,z as setNetworkStatusImplementation,g as setRemoteLogger,Ft as setStorageImplementation,Ze as setupApiListeners,Vt as startDeployedBuildCheck,Mt as staticUrl,F as storeSessionUser,I as storeToken,It as syncStorage,Fe as toFieldPath,St as toSafeReturnTo,B as useNetworkStatus,jt as useRouteErrorReport,Wt as useVersionCheck,ve as userClient,ue as withCrossTabRefreshLock,kt as withGuards};
package/dist/initSDK.js CHANGED
@@ -1 +1 @@
1
- import{DEFAULT_CORRELATION_ID_HEADER as e,setConfig as t}from"./config/index.js";import{Logger as n}from"./logger/logger.js";var r=r=>{if(typeof r.baseUrl!=`string`)throw Error(`baseUrl is required for Webority packages initialization`);t({baseUrl:r.baseUrl,loggingEnabled:r.loggingEnabled??!0,logLevel:r.logLevel??`warn`,environment:r.environment??`Development`,appVersion:r.appVersion??null,commit:r.commit??null,appBuild:r.appBuild??null,buildId:r.buildId??null,versionUrl:r.versionUrl??`/version.json`,buildCheckIntervalMs:r.buildCheckIntervalMs??3e5,timeoutMs:r.timeoutMs??3e4,retries:r.retries??3,correlationIdHeader:r.correlationIdHeader===void 0?e:r.correlationIdHeader,staticAssets:r.staticAssets??null}),n.info(`[@webority/web-core] initialized`)};export{r as initWebority};
1
+ import{setConfig as e}from"./config/index.js";import{Logger as t}from"./logger/logger.js";var n=n=>{if(typeof n.baseUrl!=`string`)throw Error(`baseUrl is required for Webority packages initialization`);e({baseUrl:n.baseUrl,loggingEnabled:n.loggingEnabled??!0,logLevel:n.logLevel??`warn`,environment:n.environment??`Development`,appVersion:n.appVersion??null,commit:n.commit??null,appBuild:n.appBuild??null,buildId:n.buildId??null,versionUrl:n.versionUrl??`/version.json`,buildCheckIntervalMs:n.buildCheckIntervalMs??3e5,timeoutMs:n.timeoutMs??3e4,retries:n.retries??3,staticAssets:n.staticAssets??null}),t.info(`[@webority/web-core] initialized`)};export{n as initWebority};
@@ -1,2 +1,2 @@
1
- import{getConfigValue as e}from"../config/index.js";import{redact as t,redactError as n,redactString as r}from"./redact.js";var i=[`debug`,`info`,`warn`,`error`],a=t=>{let n=e(`logLevel`,`info`);return i.indexOf(t)>=i.indexOf(n)},o=()=>e(`loggingEnabled`,!0),s=null,c=e=>{s=e},l=e=>{if(e)try{e()}catch{}},u=null,d=e=>e==null?null:typeof e==`string`||typeof e==`number`||typeof e==`boolean`?e:String(e),f=e=>{if(u=e,e)for(let[t,n]of Object.entries(e))l(()=>s?.setAttribute?.(t,d(n)))},p=()=>u,m={dedupeWindowMs:5e3,dedupeMaxPerWindow:1,screenHistoryLimit:20},h=null,g=[],_=e=>{m={...m,...e},g.length>m.screenHistoryLimit&&(g=g.slice(g.length-m.screenHistoryLimit))},v=new Map,y=200,b=e=>{let t=e.stack?.split(`
2
- `)[1]?.trim();return t?`${e.message}::${t}`:e.message},x=()=>{for(;v.size>y;){let e=v.keys().next().value;if(e===void 0)return;v.delete(e)}},S=e=>{if(m.dedupeWindowMs<=0)return{forward:!0};let t=Date.now(),n=v.get(e);if(!n||t-n.windowStart>=m.dedupeWindowMs){let r=n?.suppressedCount??0;return v.set(e,{windowStart:t,count:1,suppressedCount:0}),x(),r>0?{forward:!0,suppressedCount:r}:{forward:!0}}return n.count+=1,n.count>m.dedupeMaxPerWindow?(n.suppressedCount+=1,{forward:!1}):{forward:!0}},C=(e,t)=>{let n={...u};return h!==null&&(n.screen=h),t&&(n.suppressedCount=t),{...n,...e}},w=(e,t)=>{let{forward:n,suppressedCount:r}=S(b(e));n&&l(()=>s?.recordError?.(e,C(t,r)))},T=(e,...n)=>{!o()||!a(`debug`)||console.debug(`[DEBUG]: ${r(e)}`,...t(n))},E=(e,...n)=>{let i=r(e),c=t(n);!o()||!a(`info`)||(console.info(`[INFO]: ${i}`,...c),l(()=>s?.log?.(`info`,i,c)))},D=(e,...n)=>{let i=r(e),c=t(n);!o()||!a(`warn`)||(console.warn(`[WARNING]: ${i}`,...c),l(()=>s?.log?.(`warn`,i,c)))},O=(e,...i)=>{let c=r(e),u=t(i);o()&&a(`error`)&&console.error(`[ERROR]: ${c}`,...u),l(()=>s?.log?.(`error`,c,u));let d=i[0];d!==void 0&&w(n(d),{source:`Logger.error`,message:c})},k=(e,n)=>{let i=r(e),c=t(n);o()&&a(`info`)&&console.info(`[BREADCRUMB]: ${i}`,c??``),l(()=>s?.breadcrumb?.(i,c))},A=(e,r)=>{let i=n(e),s=t(r);o()&&a(`error`)&&console.error(`[RECORDED]: ${i.message}`,s??``),w(i,s)},j=e=>typeof e==`object`&&e?e:null,M=(e,t)=>{let n=j(e);if(!n)return null;let r=typeof n.get==`function`?n.get.call(e,t):n[t]??n[t.toLowerCase()];return typeof r==`string`&&r!==``?r:null},N={debug:T,info:E,warn:D,error:O,breadcrumb:k,recordError:A,requestFailed:(n,i={})=>{let{label:c,expectedStatuses:u=[],...d}=i,f=j(n),p=j(f?.config),m=j(f?.response),h=j(m?.data),g=typeof m?.status==`number`?m.status:null,_=typeof p?.method==`string`?p.method.toUpperCase():null,v=typeof p?.url==`string`?p.url.split(`?`)[0]??null:null,y=c??([_,v].filter(Boolean).join(` `)||`Request`);if(f?.name===`CanceledError`||f?.code===`ERR_CANCELED`||f?.__CANCEL__===!0){E(`${y} canceled`);return}if(g!==null&&u.includes(g)){E(`${y} refused (${g})`);return}let b=typeof f?.message==`string`?f.message:n instanceof Error?n.message:null,x=r(g===null?`${y} failed`:`${y} failed (${g})`);o()&&a(`error`)&&console.error(`[ERROR]: ${x}`,r(b??``)),l(()=>s?.log?.(`error`,x,[]));let S=e(`correlationIdHeader`,null),C=t({source:`Logger.requestFailed`,label:y,status:g,method:_,path:v,code:typeof h?.code==`string`?h.code:null,traceId:typeof h?.traceId==`string`?h.traceId:null,correlationId:S?M(p?.headers,S):null,detail:b,...d});w(Error(x),C)},setUser:(e,t)=>{l(()=>s?.setUser?.(e,t))},setAttribute:(e,t)=>{l(()=>s?.setAttribute?.(e,t))},trackScreen:(e,t)=>{e!==h&&(h=e,g.push(e),g.length>m.screenHistoryLimit&&(g=g.slice(g.length-m.screenHistoryLimit)),k(`Screen: ${e}`,t))},getCurrentScreen:()=>h,getScreenHistory:()=>[...g]};export{N as Logger,_ as configureLogger,p as getDeviceContext,f as setDeviceContext,c as setRemoteLogger};
1
+ import{getConfigValue as e}from"../config/index.js";import"../api/requestDefaults.js";import{redact as t,redactError as n,redactString as r}from"./redact.js";var i=[`debug`,`info`,`warn`,`error`],a=t=>{let n=e(`logLevel`,`info`);return i.indexOf(t)>=i.indexOf(n)},o=()=>e(`loggingEnabled`,!0),s=null,c=e=>{s=e},l=e=>{if(e)try{e()}catch{}},u=null,d=e=>e==null?null:typeof e==`string`||typeof e==`number`||typeof e==`boolean`?e:String(e),f=e=>{if(u=e,e)for(let[t,n]of Object.entries(e))l(()=>s?.setAttribute?.(t,d(n)))},p=()=>u,m={dedupeWindowMs:5e3,dedupeMaxPerWindow:1,screenHistoryLimit:20},h=null,g=[],_=e=>{m={...m,...e},g.length>m.screenHistoryLimit&&(g=g.slice(g.length-m.screenHistoryLimit))},v=new Map,y=200,b=e=>{let t=e.stack?.split(`
2
+ `)[1]?.trim();return t?`${e.message}::${t}`:e.message},x=()=>{for(;v.size>y;){let e=v.keys().next().value;if(e===void 0)return;v.delete(e)}},S=e=>{if(m.dedupeWindowMs<=0)return{forward:!0};let t=Date.now(),n=v.get(e);if(!n||t-n.windowStart>=m.dedupeWindowMs){let r=n?.suppressedCount??0;return v.set(e,{windowStart:t,count:1,suppressedCount:0}),x(),r>0?{forward:!0,suppressedCount:r}:{forward:!0}}return n.count+=1,n.count>m.dedupeMaxPerWindow?(n.suppressedCount+=1,{forward:!1}):{forward:!0}},C=(e,t)=>{let n={...u};return h!==null&&(n.screen=h),t&&(n.suppressedCount=t),{...n,...e}},w=(e,t)=>{let{forward:n,suppressedCount:r}=S(b(e));n&&l(()=>s?.recordError?.(e,C(t,r)))},T=(e,...n)=>{!o()||!a(`debug`)||console.debug(`[DEBUG]: ${r(e)}`,...t(n))},E=(e,...n)=>{let i=r(e),c=t(n);!o()||!a(`info`)||(console.info(`[INFO]: ${i}`,...c),l(()=>s?.log?.(`info`,i,c)))},D=(e,...n)=>{let i=r(e),c=t(n);!o()||!a(`warn`)||(console.warn(`[WARNING]: ${i}`,...c),l(()=>s?.log?.(`warn`,i,c)))},O=(e,...i)=>{let c=r(e),u=t(i);o()&&a(`error`)&&console.error(`[ERROR]: ${c}`,...u),l(()=>s?.log?.(`error`,c,u));let d=i[0];d!==void 0&&w(n(d),{source:`Logger.error`,message:c})},k=(e,n)=>{let i=r(e),c=t(n);o()&&a(`info`)&&console.info(`[BREADCRUMB]: ${i}`,c??``),l(()=>s?.breadcrumb?.(i,c))},A=(e,r)=>{let i=n(e),s=t(r);o()&&a(`error`)&&console.error(`[RECORDED]: ${i.message}`,s??``),w(i,s)},j=e=>typeof e==`object`&&e?e:null,M=(e,t)=>{let n=j(e);if(!n)return null;let r=typeof n.get==`function`?n.get.call(e,t):n[t]??n[t.toLowerCase()];return typeof r==`string`&&r!==``?r:null},N=e=>M(e,`traceparent`)?.split(`-`)[1]??null,P={debug:T,info:E,warn:D,error:O,breadcrumb:k,recordError:A,requestFailed:(e,n={})=>{let{label:i,expectedStatuses:c=[],...u}=n,d=j(e),f=j(d?.config),p=j(d?.response),m=j(p?.data),h=typeof p?.status==`number`?p.status:null,g=typeof f?.method==`string`?f.method.toUpperCase():null,_=typeof f?.url==`string`?f.url.split(`?`)[0]??null:null,v=i??([g,_].filter(Boolean).join(` `)||`Request`);if(d?.name===`CanceledError`||d?.code===`ERR_CANCELED`||d?.__CANCEL__===!0){E(`${v} canceled`);return}if(h!==null&&c.includes(h)){E(`${v} refused (${h})`);return}let y=typeof d?.message==`string`?d.message:e instanceof Error?e.message:null,b=r(h===null?`${v} failed`:`${v} failed (${h})`);o()&&a(`error`)&&console.error(`[ERROR]: ${b}`,r(y??``)),l(()=>s?.log?.(`error`,b,[]));let x=t({source:`Logger.requestFailed`,label:v,status:h,method:g,path:_,code:typeof m?.code==`string`?m.code:null,traceId:(typeof m?.traceId==`string`?m.traceId:null)??N(f?.headers),detail:y,...u});w(Error(b),x)},setUser:(e,t)=>{l(()=>s?.setUser?.(e,t))},setAttribute:(e,t)=>{l(()=>s?.setAttribute?.(e,t))},trackScreen:(e,t)=>{e!==h&&(h=e,g.push(e),g.length>m.screenHistoryLimit&&(g=g.slice(g.length-m.screenHistoryLimit)),k(`Screen: ${e}`,t))},getCurrentScreen:()=>h,getScreenHistory:()=>[...g]};export{P as Logger,_ as configureLogger,p as getDeviceContext,f as setDeviceContext,c as setRemoteLogger};
@@ -1,14 +1,14 @@
1
1
  import type { AxiosInstance } from "axios";
2
- export declare const CLIENT_BUILD_HEADER = "X-Client-Build";
3
- export declare const CLIENT_KIND_HEADER = "X-Client-Kind";
4
- export declare const ACCOUNT_ID_HEADER = "X-Account-Id";
2
+ export declare const CLIENT_BUILD_HEADER = "Client-Build";
3
+ export declare const CLIENT_KIND_HEADER = "Client-Kind";
4
+ export declare const ACCOUNT_ID_HEADER = "Account-Id";
5
5
  /** The server picks session rules and the minimum version per kind; the names match its enum. */
6
6
  export type ClientKind = "Browser" | "MobileApp";
7
7
  export declare const CLIENT_KIND: ClientKind;
8
8
  /** `<appVersion>+<commit>`, `<appVersion>` when no commit was stamped, `null` before init. */
9
9
  export declare const getClientBuild: () => string | null;
10
10
  /**
11
- * Stamps X-Client-Kind and X-Client-Build on every request. A value the app
11
+ * Stamps Client-Kind and Client-Build on every request. A value the app
12
12
  * already set (a default header, or a per-request one) wins, so an app that
13
13
  * wired them by hand keeps working unchanged.
14
14
  */
@@ -2,7 +2,7 @@ import type { AxiosInstance } from "axios";
2
2
  /** The page address key a compare or a person opens a staging page with. */
3
3
  export declare const DESIGN_SAMPLE_QUERY_KEY = "designSample";
4
4
  /** The request header that carries the ticket to the product's API; the API's Webority.Delivery reads it. */
5
- export declare const DESIGN_SAMPLE_HEADER = "X-Design-Sample";
5
+ export declare const DESIGN_SAMPLE_HEADER = "Design-Sample";
6
6
  /** sessionStorage key: the ticket outlives in-app navigation and redirects, and ends with the tab. */
7
7
  export declare const DESIGN_SAMPLE_STORAGE_KEY = "webority.designSample";
8
8
  /**
@@ -7,10 +7,10 @@ export { applyDesignSample, DESIGN_SAMPLE_HEADER, DESIGN_SAMPLE_QUERY_KEY, DESIG
7
7
  export type { MinAppVersionListener } from "./minAppVersion";
8
8
  export { addMinAppVersionListener, getMinAppVersion, MIN_APP_VERSION_HEADER } from "./minAppVersion";
9
9
  export { default as publicClient } from "./publicClient";
10
- export { applyRequestDefaults, newCorrelationId } from "./requestDefaults";
10
+ export { applyRequestDefaults, newTraceparent, TRACEPARENT_HEADER } from "./requestDefaults";
11
11
  export type { RetryPolicy } from "./retry";
12
12
  export { attachRetry, IDEMPOTENCY_KEY_HEADER, isNeverSentError, isRetryableFailure, isRetryableStatus, retryAfterMs, } from "./retry";
13
13
  export { refreshAccessToken } from "./tokenRefresh";
14
- export type { RefreshableStore, SessionTerminationCode } from "./userClient";
15
- export { default as userClient, injectStore, injectUserAuth, RequestOfflineError, resetRefreshState, SESSION_TERMINATION_CODES, SIGN_OUT_REASON_HEADER, } from "./userClient";
14
+ export type { RefreshableStore } from "./userClient";
15
+ export { default as userClient, injectStore, injectUserAuth, RequestOfflineError, resetRefreshState, SESSION_EXPIRED_CODE, SESSION_REVOKED_CODE, } from "./userClient";
16
16
  export { isWorkspaceChangedError, WORKSPACE_CHANGED_CODE, WorkspaceChangedError } from "./workspaceChanged";
@@ -5,7 +5,7 @@ import type { AxiosInstance } from "axios";
5
5
  * errors included; cross-origin it is readable only when the API lists it in
6
6
  * `Access-Control-Expose-Headers`.
7
7
  */
8
- export declare const MIN_APP_VERSION_HEADER = "X-Min-App-Version";
8
+ export declare const MIN_APP_VERSION_HEADER = "Min-App-Version";
9
9
  export type MinAppVersionListener = (minAppVersion: number) => void;
10
10
  /** The floor the API last named, or `null` before any response carried one. */
11
11
  export declare const getMinAppVersion: () => number | null;
@@ -1,17 +1,19 @@
1
1
  import type { AxiosInstance } from "axios";
2
+ export declare const TRACEPARENT_HEADER = "traceparent";
2
3
  /**
3
- * A fresh v4 uuid. `crypto.randomUUID` exists only in a secure context (HTTPS or localhost) and
4
- * not at all on Hermes, so the id falls back to `getRandomValues`, then to `Math.random`. A
5
- * correlation id only has to be unique enough to find one request in the logs; it is never a secret.
4
+ * A fresh W3C traceparent, version 00, sampled: the header value and its 32-hex trace id. The ids only have to be unique enough to find one request in the logs; they are never secrets.
6
5
  */
7
- export declare const newCorrelationId: () => string;
6
+ export declare const newTraceparent: () => {
7
+ header: string;
8
+ traceId: string;
9
+ };
8
10
  /**
9
- * Applies the configured timeout and the correlation id per request, read on every send so a
11
+ * Applies the configured timeout and the traceparent per request, read on every send so a
10
12
  * value set after import still applies (the same reason `applyConfiguredBaseUrl` exists).
11
13
  * - `timeoutMs`: used when the request carries no timeout of its own; a request's own axios
12
14
  * `timeout` wins. 0, either way, means no timeout (axios's own meaning).
13
- * - `correlationIdHeader`: a fresh uuid unless the request already carries one. A retry
14
- * resends the same config, so it keeps the id the first attempt went out with.
15
+ * - `traceparent`: a fresh W3C traceparent unless the request already carries one. A retry
16
+ * resends the same config, so it keeps the value the first attempt went out with.
15
17
  *
16
18
  * axios fills a missing `timeout` with its own default of 0, which would make "this request
17
19
  * set none" and "this request asked for none" look alike. The client's default is therefore
@@ -20,9 +20,9 @@ export declare const IDEMPOTENCY_KEY_HEADER = "Idempotency-Key";
20
20
  export declare const isRetryableStatus: (status: number | undefined) => boolean;
21
21
  export declare const isNeverSentError: (error: AxiosError) => boolean;
22
22
  /**
23
- * The wait a refusal named, in milliseconds: the `Retry-After` header (seconds)
24
- * or a `retryAfterSeconds` body field. `null` when it named none. Cross-origin,
25
- * the header is readable only when the API lists it in `Access-Control-Expose-Headers`.
23
+ * The wait a refusal named, in milliseconds: the `Retry-After` header (seconds).
24
+ * `null` when it named none. Cross-origin, the header is readable only when the API
25
+ * lists it in `Access-Control-Expose-Headers`.
26
26
  */
27
27
  export declare const retryAfterMs: (error: AxiosError) => number | null;
28
28
  /**
@@ -1,5 +1,9 @@
1
1
  import { type SessionEndReason } from "../auth/authStore";
2
2
  import type { UserAuthOptions } from "../initUserAuth";
3
+ /** The problem-body `code` of a 401 that means the server revoked the session (a revoked bearer token or a rejected cookie stamp). */
4
+ export declare const SESSION_REVOKED_CODE = "session_revoked";
5
+ /** The problem-body `code` of a 401 that means the session's refresh token has expired. */
6
+ export declare const SESSION_EXPIRED_CODE = "session_expired";
3
7
  /**
4
8
  * The one token-refresh flow in the library, run by userClient's interceptors.
5
9
  * The library calls the refresh endpoint itself, so it can tell a rejected
@@ -34,14 +38,13 @@ export declare const getAccountIdProvider: () => UserAuthOptions["accountId"];
34
38
  /** The refresh endpoint's path, once initUserAuth has run. */
35
39
  export declare const getRefreshPath: () => string | undefined;
36
40
  export declare const dispatchLogout: () => Promise<void>;
37
- export declare const SIGN_OUT_REASON_HEADER = "X-Sign-Out-Reason";
38
- /** The server's sign-out reason from response headers (AxiosHeaders or a plain object), or null. */
39
- export declare const readSignOutReason: (headers: unknown) => string | null;
40
41
  /**
41
42
  * The session is over: clear it (tokens and session user removed, listeners told why, with
42
- * the server's reason), then dispatch the app's logout.
43
+ * the server's code), then dispatch the app's logout.
43
44
  */
44
- export declare const endSessionAndLogout: (reason: SessionEndReason, signOutReason: string | null) => Promise<void>;
45
+ export declare const endSessionAndLogout: (reason: SessionEndReason, code: string | null) => Promise<void>;
46
+ /** The server's session code in a 401 body (`session_revoked`, `session_expired`), or null. */
47
+ export declare const sessionCodeOf: (data: unknown) => string | null;
45
48
  export declare const isRefreshInFlight: () => boolean;
46
49
  /** Opens the replacement window for one flagged request; call the returned function once it settles. */
47
50
  export declare const beginSessionReplacement: () => (() => void);
@@ -1,7 +1,7 @@
1
1
  import { type AxiosInstance } from "axios";
2
2
  import "../types/axios";
3
3
  export type { RefreshableStore } from "./tokenRefresh";
4
- export { injectStore, injectUserAuth, resetRefreshState, SIGN_OUT_REASON_HEADER } from "./tokenRefresh";
4
+ export { injectStore, injectUserAuth, resetRefreshState, SESSION_EXPIRED_CODE, SESSION_REVOKED_CODE } from "./tokenRefresh";
5
5
  /**
6
6
  * Thrown by the request interceptor when the device is offline, before the
7
7
  * request ever reaches the adapter (and therefore the network). Distinct from
@@ -11,27 +11,5 @@ export { injectStore, injectUserAuth, resetRefreshState, SIGN_OUT_REASON_HEADER
11
11
  export declare class RequestOfflineError extends Error {
12
12
  constructor(message?: string);
13
13
  }
14
- /**
15
- * Sub-codes a 401 response body carries when the session itself is dead
16
- * (terminated by an admin, or expired server-side) rather than merely
17
- * out-of-date. These never warrant a refresh attempt — only logout.
18
- */
19
- export declare const SESSION_TERMINATION_CODES: {
20
- readonly TERMINATED: "SESSION_TERMINATED";
21
- readonly EXPIRED: "SESSION_EXPIRED";
22
- };
23
- export type SessionTerminationCode = (typeof SESSION_TERMINATION_CODES)[keyof typeof SESSION_TERMINATION_CODES];
24
- /**
25
- * The header is the AUTHORITATIVE signal, verified against the backend:
26
- * `WeborityJwtMiddleware.ReturnUnauthorized` answers an invalidated session with
27
- * `401` + `X-Security-Stamp-Invalid: true` and a body of
28
- * `{ error: 'Unauthorized', message: '...' }` — no code field at all, and
29
- * `error` is a string rather than an object. An earlier version of this checked
30
- * only body fields and would therefore never have fired against a real server.
31
- *
32
- * The body codes below are kept as a secondary path for any head that does send
33
- * an explicit sub-code; they match on exact strings, so looking is free.
34
- */
35
- export declare const SESSION_INVALID_HEADER = "x-security-stamp-invalid";
36
14
  declare const userClient: AxiosInstance;
37
15
  export default userClient;
@@ -32,6 +32,6 @@ export declare class WorkspaceChangedError extends Error {
32
32
  export declare const isWorkspaceChangedError: (error: unknown) => boolean;
33
33
  /** The API refused the request because the account it names is no longer the session's. */
34
34
  export declare const isWorkspaceChangedResponse: (error: AxiosError) => boolean;
35
- /** The rejection for a 409 `workspace_changed` answer: the server's message when it sent one. */
35
+ /** The rejection for a 409 `workspace_changed` answer: the server's `detail` when it sent one. */
36
36
  export declare const workspaceChangedFromResponse: (error: AxiosError) => WorkspaceChangedError;
37
37
  export {};
@@ -16,20 +16,15 @@ export interface StoredToken {
16
16
  * Why a session ended, handed to every `addSessionEndedListener` listener.
17
17
  * - `signedOut`: the app ended it (the default for `clearSession`).
18
18
  * - `rejected`: the refresh endpoint refused the refresh token.
19
- * - `terminated`: the API reported the session dead (security stamp, admin).
19
+ * - `terminated`: the API reported the session dead (revoked or expired).
20
20
  * - `corrupt`: a stored token could not be read back as a token.
21
21
  * - `otherTab`: web only. Another tab signed out of the shared session.
22
22
  */
23
23
  export type SessionEndReason = "signedOut" | "rejected" | "terminated" | "corrupt" | "otherTab";
24
24
  /** What else is known about a session end, beside its reason. */
25
25
  export interface SessionEndDetail {
26
- /**
27
- * The server's own name for why it ended the session, from the sign-out-reason response
28
- * header (`X-Sign-Out-Reason` by default, `initUserAuth({ signOutReasonHeader })`), on a
29
- * terminated session or a refused refresh. `null` when the server named none, and always
30
- * `null` for `signedOut`, `corrupt` and `otherTab` unless the app passes one.
31
- */
32
- signOutReason: string | null;
26
+ /** The server's session code (`session_revoked`, `session_expired`) when the server ended the session; null when the app or another tab did. */
27
+ code: string | null;
33
28
  }
34
29
  export type SessionEndedListener = (reason: SessionEndReason, detail: SessionEndDetail) => void;
35
30
  /**
@@ -117,6 +112,6 @@ export declare const setLegacyTokenKeys: (keys: LegacyTokenKeys | null) => void;
117
112
  * flow and the app's own sign-out can both call it without a double event.
118
113
  * The library calls it itself with `rejected` when the refresh endpoint refuses
119
114
  * the refresh token and `terminated` when the API reports the session dead,
120
- * with the server's sign-out reason in `detail`.
115
+ * with the server's code in `detail`.
121
116
  */
122
117
  export declare const clearSession: (reason?: SessionEndReason, detail?: Partial<SessionEndDetail>) => Promise<void>;
@@ -17,13 +17,13 @@ export interface Config {
17
17
  logLevel: LogLevel;
18
18
  /** Current runtime environment. */
19
19
  environment: Environment;
20
- /** The portal's user-visible version, e.g. `'1.4.2'`; with `commit` it makes the X-Client-Build header. */
20
+ /** The portal's user-visible version, e.g. `'1.4.2'`; with `commit` it makes the Client-Build header. */
21
21
  appVersion: string | null;
22
22
  /** The short git sha stamped into the build. */
23
23
  commit: string | null;
24
24
  /**
25
25
  * The portal's integer build number, stamped by the deploy. The version check
26
- * compares it with the API's `X-Min-App-Version`.
26
+ * compares it with the API's `Min-App-Version`.
27
27
  */
28
28
  appBuild: number | null;
29
29
  /**
@@ -42,12 +42,6 @@ export interface Config {
42
42
  timeoutMs: number;
43
43
  /** How many times a failed request is resent under the retry rule. 0 turns retrying off. Default 3. */
44
44
  retries: number;
45
- /**
46
- * Header that carries a fresh id (a uuid) on every request, for tracing one request across
47
- * the portal, the API and its logs. A retry keeps the id it first went out with. `null`
48
- * sends none. Default `'X-Correlation-Id'`.
49
- */
50
- correlationIdHeader: string | null;
51
45
  /**
52
46
  * The authored static assets the portal links by key, compiled from the static deployable in `.webority/infra/deployables.json` by the
53
47
  * `weborityStatic` Vite plugin. `staticUrl` reads it. `null` when the portal has no list. Web only.
@@ -61,7 +55,6 @@ export interface Config {
61
55
  export declare const DEFAULT_LOG_LEVEL: LogLevel;
62
56
  export declare const DEFAULT_TIMEOUT_MS = 30000;
63
57
  export declare const DEFAULT_RETRIES = 3;
64
- export declare const DEFAULT_CORRELATION_ID_HEADER = "X-Correlation-Id";
65
58
  export declare const DEFAULT_VERSION_URL = "/version.json";
66
59
  export declare const DEFAULT_BUILD_CHECK_INTERVAL_MS = 300000;
67
60
  /** Set global configuration for all Webority packages. */
@@ -2,19 +2,13 @@
2
2
  * Normalizes any failure a thunk, a service or the RTK Query base query can see into one
3
3
  * `ApiError`. Identical source in @webority/web-core and @webority/mobile-core.
4
4
  *
5
- * Bodies read, newest first: the standard body `{ code, message, traceId, errors }`,
6
- * where `errors` is a ModelState dictionary (`{ Field: ["msg"] }`) or a list of
7
- * `{ field, message, reference }` (a refusal that names its fields),
8
- * ProblemDetails `{ title, detail, errors }` from APIs not yet moved, legacy `{ error }` and
9
- * `{ message }`, and a plain-text body.
5
+ * The body read is the RFC 9457 problem `{ type, title, status, detail, code, traceId, errors }`,
6
+ * where `errors` is a ModelState dictionary (`{ Field: ["msg"] }`) or a list of `{ field, message }`.
10
7
  *
11
- * Message precedence is fixed (react.md): first field error, then `message`, `detail`, a
12
- * legacy `error`, `title`, then `Request failed (<status>)`. `title` is last because it is
13
- * the ProblemDetails category ("Bad Request"), not the curated sentence.
14
- *
15
- * Two things never become `message`: a 5xx body unless it carries a code other than
16
- * `internal_error` and a curated message, and anything that reads like an exception dump.
17
- * The server's text goes on `detail` for the logger instead.
8
+ * Message precedence (react.md): first field error, form error, `detail`, `title`, a plain-text
9
+ * body, then `Request failed (<status>)`. A 5xx shows `detail` only when it carries a code other
10
+ * than `internal_error`. The server's text goes on `diagnostic` for the logger, never the screen.
11
+ * The trace id falls back to the request's own `traceparent`, so a lost request keeps a reference.
18
12
  */
19
13
  export interface ApiError {
20
14
  /** Stable snake_case branch key from the server (`not_found`, `validation_failed`). Branch on it, never render it. */
@@ -30,7 +24,7 @@ export interface ApiError {
30
24
  /** The server's trace id, for a support reference. */
31
25
  traceId: string | null;
32
26
  /** What the server or runtime actually said. For the logger, never for the screen. */
33
- detail: string | null;
27
+ diagnostic: string | null;
34
28
  }
35
29
  export declare const SERVER_FAILURE_MESSAGE = "Something went wrong on our side. Please try again in a moment.";
36
30
  export declare const OFFLINE_MESSAGE = "You appear to be offline. Check your connection and try again.";
@@ -13,7 +13,7 @@ export interface InitConfig {
13
13
  logLevel?: LogLevel;
14
14
  /** Environment. Defaults to `'Development'`. */
15
15
  environment?: Environment;
16
- /** The user-visible version and the short git sha; together they make X-Client-Build. */
16
+ /** The user-visible version and the short git sha; together they make Client-Build. */
17
17
  appVersion?: string;
18
18
  commit?: string;
19
19
  /** The integer build number the deploy stamps; the version check compares it with the API's minimum. */
@@ -28,8 +28,6 @@ export interface InitConfig {
28
28
  timeoutMs?: number;
29
29
  /** Retries under the retry rule. Defaults to 3; 0 turns retrying off. */
30
30
  retries?: number;
31
- /** Header for the per-request correlation id. Defaults to `'X-Correlation-Id'`; `null` sends none. */
32
- correlationIdHeader?: string | null;
33
31
  /** The default export of `virtual:webority-static-assets` (the `weborityStatic` Vite plugin); `staticUrl` reads it. Defaults to `null`. Web only. */
34
32
  staticAssets?: StaticAssetsConfig | null;
35
33
  }
@@ -36,7 +36,7 @@ export interface UserAuthOptions {
36
36
  logout: () => unknown;
37
37
  refresh: TokenRefreshConfig;
38
38
  /**
39
- * The account the signed-in user is working in, sent as `X-Account-Id` on
39
+ * The account the signed-in user is working in, sent as `Account-Id` on
40
40
  * every userClient request. Read once, when the request is made; a retry or
41
41
  * replay sends the same id, so a request never runs in another workspace. A
42
42
  * request whose session moved to another workspace while it was in flight is
@@ -45,14 +45,6 @@ export interface UserAuthOptions {
45
45
  * token alone.
46
46
  */
47
47
  accountId?: AccountIdProvider;
48
- /**
49
- * The response header in which the API names why it ended a session. A 401 carrying it is a
50
- * revoked session: no refresh is tried, the session is cleared as `terminated`, and the
51
- * value reaches every `addSessionEndedListener` listener as `detail.signOutReason`. It is
52
- * read from a refused refresh too. Default `'X-Sign-Out-Reason'`; `null` turns it off.
53
- * Cross-origin, the API must list it in `Access-Control-Expose-Headers`.
54
- */
55
- signOutReasonHeader?: string | null;
56
48
  /**
57
49
  * The keys the app kept its session under before this library. The first token read that
58
50
  * finds the library's keys empty moves a session found there and deletes the old keys, so
@@ -2,7 +2,7 @@
2
2
  * Build-number arithmetic for the server-driven update check, shared word for
3
3
  * word by web-core and mobile-core.
4
4
  *
5
- * The API's `X-Min-App-Version` is the lowest internal build number it still
5
+ * The API's `Min-App-Version` is the lowest internal build number it still
6
6
  * supports for the calling client kind, and the app's own build number is an
7
7
  * integer too (`VERSION_INTERNAL` on mobile, `appBuild` on web). The comparison
8
8
  * is integer against integer, never semver against semver.
@@ -7,7 +7,7 @@ export interface VersionCheckState {
7
7
  updateAvailable: boolean;
8
8
  }
9
9
  /**
10
- * Whether a newer build must be loaded: the minimum the API sends in `X-Min-App-Version`, or a
10
+ * Whether a newer build must be loaded: the minimum the API sends in `Min-App-Version`, or a
11
11
  * newer deployed build found by `startDeployedBuildCheck`. Re-renders the moment either changes.
12
12
  * The "new version" bar that reads this lives in `@webority/ui-react`.
13
13
  */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@webority/web-core",
3
- "version": "0.91.0",
3
+ "version": "0.93.0",
4
4
  "description": "Platform layer for Webority React web portals: HTTP clients with single-flight token refresh, auth store, API error extraction, RTK Query base query, logger, formatters, storage, version check and route guards. No UI.",
5
5
  "license": "SEE LICENSE IN LICENSE",
6
6
  "type": "module",