@webority/web-core 0.75.1 → 0.77.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 +5 -4
- package/dist/errors/extractApiError.js +2 -2
- package/dist/errors/index.js +1 -1
- package/dist/formatters/currency.js +1 -1
- package/dist/formatters/house.js +1 -1
- package/dist/index.js +1 -1
- package/dist/lib/devWarn.js +1 -0
- package/dist/types/errors/extractApiError.d.ts +11 -7
- package/dist/types/errors/index.d.ts +1 -1
- package/dist/types/formatters/currency.d.ts +10 -9
- package/dist/types/formatters/house.d.ts +2 -36
- package/dist/types/lib/devWarn.d.ts +2 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -16,7 +16,7 @@ store.
|
|
|
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
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` `'timeout'` or `'
|
|
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` |
|
|
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 |
|
|
@@ -173,11 +173,12 @@ try {
|
|
|
173
173
|
`extractApiError` reads `errors` as a ModelState dictionary or as a list of `{ field, message }`
|
|
174
174
|
entries, both into `fieldErrors` keyed by the camelCase field path. For the sentence a screen shows,
|
|
175
175
|
`apiErrorMessage(error, "We couldn't save the project.")` returns the server's curated message, or
|
|
176
|
-
the screen's fallback when the server said nothing usable (a 5xx
|
|
177
|
-
message when no answer arrived
|
|
176
|
+
the screen's fallback when the server said nothing usable (a 5xx without a curated message, an empty
|
|
177
|
+
body), or the connection message when no answer arrived, which wins over the fallback. A 5xx whose
|
|
178
|
+
body has a code other than `internal_error` and a curated message shows that message. `apiErrorMessage(error, null)` says nothing (returns `null`) when the
|
|
178
179
|
server sent nothing curated, for a panel that shows only the server's own sentence. `isNoResponse(error)`
|
|
179
180
|
says whether an answer arrived at all; `code` tells a timeout (`TIMEOUT_CODE`) from a network failure
|
|
180
|
-
(`NETWORK_CODE`).
|
|
181
|
+
while online (`NETWORK_CODE`) and from a browser that reports no network (`OFFLINE_CODE`).
|
|
181
182
|
|
|
182
183
|
Errors raise a toast by default; a thunk or endpoint opts out with `meta: { silent: true }`, the
|
|
183
184
|
same on web and mobile. `onRejected` gives the product its say over each rejection before the
|
|
@@ -1,2 +1,2 @@
|
|
|
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=`That took too long to respond. Check your connection and try again.`,
|
|
2
|
-
at `)||/\b(Exception|StackTrace):/.test(e)||/\b(System|Microsoft)\.[A-Za-z]+\.[A-Za-z]/.test(e),
|
|
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};
|
package/dist/errors/index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{CONTRACT_ERROR_CODE as e,NETWORK_CODE as t,
|
|
1
|
+
import{CONTRACT_ERROR_CODE as e,NETWORK_CODE as t,OFFLINE_CODE as n,OFFLINE_MESSAGE as r,REQUEST_CANCELED_CODE as i,SERVER_FAILURE_MESSAGE as a,TIMEOUT_CODE as o,TIMEOUT_MESSAGE as s,UNEXPECTED_MESSAGE as c,UNREACHABLE_MESSAGE as l,apiErrorMessage as u,extractApiError as d,isApiError as f,isNoResponse as p,toFieldPath as m}from"./extractApiError.js";export{e as CONTRACT_ERROR_CODE,t as NETWORK_CODE,n as OFFLINE_CODE,r as OFFLINE_MESSAGE,i as REQUEST_CANCELED_CODE,a as SERVER_FAILURE_MESSAGE,o as TIMEOUT_CODE,s as TIMEOUT_MESSAGE,c as UNEXPECTED_MESSAGE,l as UNREACHABLE_MESSAGE,u as apiErrorMessage,d as extractApiError,f as isApiError,p as isNoResponse,m as toFieldPath};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{configuredLocale as
|
|
1
|
+
import{devWarn as e}from"../lib/devWarn.js";import{configuredLocale as t,getFormatterConfig as n,isFormatterConfigured as r,numberSeparators as i,styledNumber as a}from"./formatConfig.js";import{numberFormat as o}from"./intlCache.js";var s=()=>typeof Intl<`u`&&typeof Intl.NumberFormat==`function`,c=(e,t)=>{let{decimal:n,group:r}=i()??{decimal:`.`,group:`,`},a=e<0?`-`:``,[o,s]=Math.abs(e).toFixed(t).split(`.`),c=o.length>3?o.slice(-3):o,l=o.length>3?o.slice(0,-3):``;return a+(l?l.replace(/\B(?=(\d{2})+(?!\d))/g,r)+r+c:c)+(s?`${n}${s}`:``)},l=e=>{if(e==null||typeof e==`string`&&e.trim()===``)return null;let t=typeof e==`number`?e:Number(e);return Number.isFinite(t)?t:null},u=(e,t)=>o(e,{style:`currency`,currency:t}).resolvedOptions().maximumFractionDigits??2,d=(i,d={})=>{let{currency:f,locale:p=t()??`en-IN`,minimumFractionDigits:m,maximumFractionDigits:h,stripSymbol:g=!1,empty:_=r(`locale`)||r(`empty`)?n().empty:``,...v}=d;f||e(`[@webority/web-core] formatCurrency called without options.currency: it prints INR for now and throws from 0.78.0. Pass an ISO 4217 code.`);let y=f||`INR`,b=l(i);if(b===null)return _;if(s())try{let e=h??u(p,y),t=m??(Number.isInteger(b)?0:e),n=a(o(p,{...v,style:`currency`,currency:y,minimumFractionDigits:t,maximumFractionDigits:Math.max(t,e)}),b);return g?n.replace(/[^\d,.\s\-+]/g,``).trim():n}catch{}let x=c(b,m??(Number.isInteger(b)?0:2));return g?x:y===`INR`?`₹${x}`:`${y} ${x}`};export{d as formatCurrency};
|
package/dist/formatters/house.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{configuredLocale as
|
|
1
|
+
import{devWarn as e}from"../lib/devWarn.js";import{configuredLocale as t,getFormatterConfig as n,groupingForLocale as r,numberSeparators as i,styledNumber as a}from"./formatConfig.js";import{dateTimeFormat as o,numberFormat as s,relativeTimeFormat as c}from"./intlCache.js";var l=[`Jan`,`Feb`,`Mar`,`Apr`,`May`,`Jun`,`Jul`,`Aug`,`Sep`,`Oct`,`Nov`,`Dec`],u=330,d=[`IST`,`Asia/Kolkata`,`Asia/Calcutta`],f=/^\d{4}-\d{2}-\d{2}$/,p=e=>e<10?`0${e}`:`${e}`,m=e=>e??n().empty,h=e=>{if(e==null||e===``)return null;let t=e instanceof Date?e:new Date(typeof e==`string`?e.trim():e);return Number.isNaN(t.getTime())?null:t},g=e=>typeof e==`string`&&f.test(e.trim()),_=e=>{if(e===0)return`GMT`;let t=e>0?`+`:`-`,n=Math.abs(e),r=n%60;return`GMT${t}${Math.floor(n/60)}${r===0?``:`:${p(r)}`}`},v=(e,t,n)=>{let r=new Date(e.getTime()+t*6e4);return{year:r.getUTCFullYear(),month:r.getUTCMonth(),day:r.getUTCDate(),hour:r.getUTCHours(),minute:r.getUTCMinutes(),label:n}},ee=(e,t)=>{let n=o(`en-US`,{timeZone:t,year:`numeric`,month:`numeric`,day:`numeric`,hour:`numeric`,minute:`numeric`,hour12:!1}).formatToParts(e),r=e=>Number.parseInt(n.find(t=>t.type===e)?.value??``,10),i=r(`year`),a=r(`month`)-1,s=r(`day`),c=r(`hour`)%24,l=r(`minute`);return{year:i,month:a,day:s,hour:c,minute:l,label:_(Math.round((Date.UTC(i,a,s,c,l)-Math.floor(e.getTime()/6e4)*6e4)/6e4))}},y=(e,t)=>d.includes(t)?v(e,u,`IST`):t===`UTC`?v(e,0,`UTC`):t===`viewer`?{year:e.getFullYear(),month:e.getMonth(),day:e.getDate(),hour:e.getHours(),minute:e.getMinutes(),label:_(-e.getTimezoneOffset())}:ee(e,t),b=e=>e.hourCycle??12,te=e=>`${p(e.day)}-${l[e.month]}-${e.year}`,x=(e,t)=>{let n=p(e.day),r=p(e.month+1),i=String(e.year).padStart(4,`0`);return t===`DayMonthYear`?`${n}/${r}/${i}`:t===`MonthDayYear`?`${r}/${n}/${i}`:`${i}-${r}-${n}`},S=(e,t)=>t===24?`${p(e.hour)}:${p(e.minute)}`:`${e.hour%12||12}:${p(e.minute)} ${e.hour<12?`AM`:`PM`}`,C=(e,t)=>t??!d.includes(e),w=(e,t,n,r)=>C(n,r)?`${e} ${t.label}`:e,T=e=>{if(e!==`viewer`)return d.includes(e)?`Asia/Kolkata`:e},ne=(e,t,n)=>{let r=o(t,{day:`2-digit`,month:`short`,year:`numeric`,timeZone:n}).formatToParts(e),i=e=>r.find(t=>t.type===e)?.value??``;return`${i(`day`)}-${i(`month`).replace(`.`,``)}-${i(`year`)}`},E=(e,r)=>{let i=n().dateOrder??`DayMonthNameYear`;if(i!==`DayMonthNameYear`)return x(y(e,r),i);let a=t();return a?ne(e,a,T(r)):te(y(e,r))},D=(e,t,n,r)=>o(t,{hour:`2-digit`,minute:`2-digit`,timeZone:T(n),timeZoneName:C(n,r.zoneLabel)?`short`:void 0,hourCycle:r.hourCycle===void 0?void 0:r.hourCycle===24?`h23`:`h12`}).format(e),O=(e,t={})=>{let r=h(e);return r?E(r,g(e)?`UTC`:t.zone??n().zone):m(t.empty)},k=(e,r={})=>{let i=h(e);if(!i)return m(r.empty);let a=r.zone??n().zone,o=t();if(o)return D(i,o,a,r);let s=y(i,a);return w(S(s,b(r)),s,a,r.zoneLabel)},A=(e,r={})=>{let i=h(e);if(!i)return m(r.empty);let a=r.zone??n().zone,o=t();if(o)return`${E(i,a)}, ${D(i,o,a,r)}`;let s=y(i,a);return w(`${E(i,a)}, ${S(s,b(r))}`,s,a,r.zoneLabel)},j=1e3,M=60*j,N=60*M,P=24*N,F=7*P,I=30*P,L=365*P,R=[[`year`,L],[`month`,I],[`day`,P],[`hour`,N],[`minute`,M]],z=(e,r={})=>{let i=h(e),a=h(r.now??Date.now());if(!i||!a)return m(r.empty);let o=i.getTime()-a.getTime(),s=Math.abs(o),l=Intl.RelativeTimeFormat,u=t();if((u!==null||r.intl===!0)&&typeof l==`function`){let e=c(l,u??n().locale),[t,r]=R.find(([,e])=>s>=e)??[`second`,j];return e.format(Math.round(o/r),t)}if(s<M)return`just now`;let[d,f]=s<N?[`minute`,M]:s<P?[`hour`,N]:s<F?[`day`,P]:s<I?[`week`,F]:s<L?[`month`,I]:[`year`,L],p=Math.floor(s/f),g=`${p} ${d}${p===1?``:`s`}`;return o<0?`${g} ago`:`in ${g}`},B=e=>{if(e==null||typeof e==`string`&&e.trim()===``)return null;let t=typeof e==`number`?e:Number(e);return Number.isFinite(t)?t:null},V=e=>Math.min(20,Math.max(0,Math.trunc(e))),H=(e,t)=>/e/i.test(String(e))?e*10**t:Number(`${e}e${t}`),U=()=>i()??{decimal:`.`,group:`,`},W=(e,t,n)=>t===`none`||e.length<=3?e:t===`international`?e.replace(/\B(?=(\d{3})+(?!\d))/g,n):`${e.slice(0,-3).replace(/\B(?=(\d{2})+(?!\d))/g,n)}${n}${e.slice(-3)}`,G=()=>typeof Intl<`u`&&typeof Intl.NumberFormat==`function`,K=(e,t)=>{if(G())return s(`en-US`,{useGrouping:!1,minimumFractionDigits:0,maximumFractionDigits:t}).format(e);let n=Math.min(t,15);return H(Math.round(H(e,n)),-n).toFixed(n)},q=(e,t,n,r)=>{let i=Math.max(V(n),V(t)),a=V(t),o=K(Math.abs(e),i),[s=`0`,c=``]=o.split(`.`),l=c.padEnd(a,`0`);for(;l.length>a&&l.endsWith(`0`);)l=l.slice(0,-1);let u=U(),d=W(s,r,u.group)+(l?`${u.decimal}${l}`:``);return e<0&&/[1-9]/.test(o)?`-${d}`:d},J=new Set([`grouping`,`minimumFractionDigits`,`maximumFractionDigits`,`locale`,`empty`,`scale`]),Y=e=>{if(!Object.entries(e).some(([e,t])=>t!==void 0&&!J.has(e)))return null;let{grouping:t,locale:n,empty:r,scale:i,...a}=e;return t===`none`&&a.useGrouping===void 0?{...a,useGrouping:!1}:a},X=e=>e.locale??n().locale,Z=e=>{let n=t();return n===null||e.grouping===`indian`||e.grouping===`international`?null:e.locale??n},Q=(e,t)=>{let n=V(e);return{minimumFractionDigits:n,maximumFractionDigits:Math.max(n,V(t))}},$=e=>e===`none`?{useGrouping:!1}:{},re=(e,t={})=>{let n=B(e);if(n===null)return m(t.empty);let i=Y(t);if(i)return a(s(X(t),i),n);let o=Z(t);return o?a(s(o,{...Q(t.minimumFractionDigits??0,t.maximumFractionDigits??3),...$(t.grouping)}),n):q(n,t.minimumFractionDigits??0,t.maximumFractionDigits??3,t.grouping??r(X(t)))},ie=(e,t={})=>{let n=B(e);if(n===null)return m(t.empty);let i=Y(t);if(i){let e=t.scale===`percent`?H(n,-2):n;return a(s(X(t),{style:`percent`,...i}),e)}let o=Z(t);if(o){let e=t.scale===`percent`?H(n,-2):n;return a(s(o,{style:`percent`,...Q(t.minimumFractionDigits??0,t.maximumFractionDigits??t.minimumFractionDigits??0),...$(t.grouping)}),e)}return`${q(t.scale===`percent`?n:H(n,2),t.minimumFractionDigits??0,t.maximumFractionDigits??t.minimumFractionDigits??0,t.grouping??r(X(t)))}%`},ae={INR:`₹`,USD:`$`,EUR:`€`,GBP:`£`},oe={JPY:0,KRW:0,VND:0,BHD:3,JOD:3,KWD:3,OMR:3,TND:3},se=(t,n={})=>{n.currency||e(`[@webority/web-core] formatMinor called without options.currency: it prints INR for now and throws from 0.78.0. Pass an ISO 4217 code.`);let r=B(t);if(r===null)return m(n.empty);let i=(n.currency||`INR`).toUpperCase(),o=oe[i]??2,c=Math.round(Math.abs(r)),l=String(c).padStart(o+1,`0`),u=l.slice(0,l.length-o),d=l.slice(l.length-o);n.dropZeroDecimals&&/^0*$/.test(d)&&(d=``);let f=Z({grouping:n.grouping});if(f)try{let e=Number(`${r<0&&c!==0?`-`:``}${u}.${l.slice(l.length-o)||`0`}`);return a(s(f,{...n.symbol===!1?{}:{style:`currency`,currency:i},...Q(d?o:0,o),...$(n.grouping)}),e)}catch{}let p=n.grouping??(i===`INR`?`indian`:`international`),h=U(),g=W(u,p,h.group)+(d?`${h.decimal}${d}`:``),_=r<0&&c!==0?`-`:``;if(n.symbol===!1)return`${_}${g}`;let v=ae[i];return v?`${_}${v}${g}`:`${_}${i} ${g}`};export{O as formatDate,A as formatDateTime,se as formatMinor,re as formatNumber,ie as formatPercent,z as formatRelative,k as formatTime};
|
package/dist/index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{DEFAULT_CORRELATION_ID_HEADER as e,DEFAULT_LOG_LEVEL as t,DEFAULT_RETRIES as n,DEFAULT_TIMEOUT_MS as r,getConfig as i,getConfigValue as a,resetConfig as o,setConfig as s}from"./config/index.js";import{Logger as c,configureLogger as l,getDeviceContext as u,setDeviceContext as d,setRemoteLogger as f}from"./logger/logger.js";import{decodeJWT as p,getJWTExpiry as m,isJWTExpired as h}from"./auth/jwt.js";import{ACCESS_TOKEN_KEY as g,LEGACY_REFRESH_TOKEN_LIFETIME_MS as _,REFRESH_TOKEN_KEY as v,SESSION_USER_KEY as y,addSessionEndedListener as b,clearSession as x,getKeepSignedIn as S,getSessionUser as C,getToken as w,hasSession as T,hasSessionEndedInTab as E,removeSessionUser as D,removeToken as O,setKeepSignedIn as k,setLegacyTokenKeys as A,storeSessionUser as j,storeToken as M}from"./auth/authStore.js";import{addNetworkStatusListener as N,getNetworkStatus as P,setNetworkStatusImplementation as F,useNetworkStatus as I}from"./network/networkStatus.js";import{ACCOUNT_ID_HEADER as L,CLIENT_BUILD_HEADER as R,CLIENT_KIND as z,CLIENT_KIND_HEADER as B,getClientBuild as V}from"./api/clientHeaders.js";import{MIN_APP_VERSION_HEADER as H,addMinAppVersionListener as U,getMinAppVersion as W}from"./api/minAppVersion.js";import{applyRequestDefaults as G,newCorrelationId as K}from"./api/requestDefaults.js";import{WORKSPACE_CHANGED_CODE as q,WorkspaceChangedError as J,isWorkspaceChangedError as Y}from"./api/workspaceChanged.js";import{IDEMPOTENCY_KEY_HEADER as X,attachRetry as Z,isNeverSentError as Q,isRetryableFailure as $,isRetryableStatus as ee,retryAfterMs as te}from"./api/retry.js";import{REFRESH_LOCK_NAME as ne,withCrossTabRefreshLock as re}from"./api/crossTabRefreshLock.js";import ie from"./api/publicClient.js";import{SIGN_OUT_REASON_HEADER as ae,injectStore as oe,injectUserAuth as se,refreshAccessToken as ce,resetRefreshState as le}from"./api/tokenRefresh.js";import ue,{RequestOfflineError as de,SESSION_TERMINATION_CODES as fe}from"./api/userClient.js";import{initUserAuth as pe}from"./initUserAuth.js";import{CONTRACT_ERROR_CODE as me,NETWORK_CODE as he,
|
|
1
|
+
import{DEFAULT_CORRELATION_ID_HEADER as e,DEFAULT_LOG_LEVEL as t,DEFAULT_RETRIES as n,DEFAULT_TIMEOUT_MS as r,getConfig as i,getConfigValue as a,resetConfig as o,setConfig as s}from"./config/index.js";import{Logger as c,configureLogger as l,getDeviceContext as u,setDeviceContext as d,setRemoteLogger as f}from"./logger/logger.js";import{decodeJWT as p,getJWTExpiry as m,isJWTExpired as h}from"./auth/jwt.js";import{ACCESS_TOKEN_KEY as g,LEGACY_REFRESH_TOKEN_LIFETIME_MS as _,REFRESH_TOKEN_KEY as v,SESSION_USER_KEY as y,addSessionEndedListener as b,clearSession as x,getKeepSignedIn as S,getSessionUser as C,getToken as w,hasSession as T,hasSessionEndedInTab as E,removeSessionUser as D,removeToken as O,setKeepSignedIn as k,setLegacyTokenKeys as A,storeSessionUser as j,storeToken as M}from"./auth/authStore.js";import{addNetworkStatusListener as N,getNetworkStatus as P,setNetworkStatusImplementation as F,useNetworkStatus as I}from"./network/networkStatus.js";import{ACCOUNT_ID_HEADER as L,CLIENT_BUILD_HEADER as R,CLIENT_KIND as z,CLIENT_KIND_HEADER as B,getClientBuild as V}from"./api/clientHeaders.js";import{MIN_APP_VERSION_HEADER as H,addMinAppVersionListener as U,getMinAppVersion as W}from"./api/minAppVersion.js";import{applyRequestDefaults as G,newCorrelationId as K}from"./api/requestDefaults.js";import{WORKSPACE_CHANGED_CODE as q,WorkspaceChangedError as J,isWorkspaceChangedError as Y}from"./api/workspaceChanged.js";import{IDEMPOTENCY_KEY_HEADER as X,attachRetry as Z,isNeverSentError as Q,isRetryableFailure as $,isRetryableStatus as ee,retryAfterMs as te}from"./api/retry.js";import{REFRESH_LOCK_NAME as ne,withCrossTabRefreshLock as re}from"./api/crossTabRefreshLock.js";import ie from"./api/publicClient.js";import{SIGN_OUT_REASON_HEADER as ae,injectStore as oe,injectUserAuth as se,refreshAccessToken as ce,resetRefreshState as le}from"./api/tokenRefresh.js";import ue,{RequestOfflineError as de,SESSION_TERMINATION_CODES as fe}from"./api/userClient.js";import{initUserAuth as pe}from"./initUserAuth.js";import{CONTRACT_ERROR_CODE as me,NETWORK_CODE as he,OFFLINE_CODE as ge,OFFLINE_MESSAGE as _e,REQUEST_CANCELED_CODE as ve,SERVER_FAILURE_MESSAGE as ye,TIMEOUT_CODE as be,TIMEOUT_MESSAGE as xe,UNEXPECTED_MESSAGE as Se,UNREACHABLE_MESSAGE as Ce,apiErrorMessage as we,extractApiError as Te,isApiError as Ee,isNoResponse as De,toFieldPath as Oe}from"./errors/extractApiError.js";import{configureFormatters as ke,getFormatterConfig as Ae}from"./formatters/formatConfig.js";import{formatCurrency as je}from"./formatters/currency.js";import{addDays as Me}from"./formatters/dateMath.js";import{formatDate as Ne,formatDateTime as Pe,formatMinor as Fe,formatNumber as Ie,formatPercent as Le,formatRelative as Re,formatTime as ze}from"./formatters/house.js";import{initWebority as Be}from"./initSDK.js";import{createApiBaseQuery as Ve}from"./query/apiBaseQuery.js";import{APP_API_DEFAULTS as He,createAppApi as Ue}from"./query/createAppApi.js";import{setupApiListeners as We}from"./query/listeners.js";import{buildListQuery as Ge,getNextPageParam as Ke,getPreviousPageParam as qe,hasNextPage as Je,hasPreviousPage as Ye}from"./query/paging.js";import{LIST_TAG_ID as Xe,itemTag as Ze,listTag as Qe,providesList as $e,providesPagedList as et}from"./query/tags.js";import{errorToastMiddleware as tt,isSilentRejection as nt}from"./redux/errorToastMiddleware.js";import{createRootReducer as rt,resetState as it}from"./redux/rootReducer.js";import{SERIALIZABLE_IGNORED_ACTION_PATHS as at}from"./redux/serializableCheck.js";import{hasRecentlyReloaded as ot,importWithReload as st,isChunkLoadError as ct,lazyWithReload as lt,markReloaded as ut}from"./router/chunkReload.js";import{hasPermission as dt}from"./router/permissions.js";import{RETURN_TO_PARAM as ft,buildLoginPath as pt,getReturnTo as mt,toSafeReturnTo as ht}from"./router/returnTo.js";import{PublicOnly as gt,RequireAuth as _t,RequirePermission as vt}from"./router/guards.js";import{publicOnly as yt,requireAuth as bt,requirePermission as xt,withGuards as St}from"./router/loaders.js";import{classifyRouteError as Ct,useRouteErrorReport as wt}from"./router/routeError.js";import{staticUrl as Tt}from"./static/index.js";import{Storage as Et,isStorageAvailable as Dt,setStorageImplementation as Ot,syncStorage as kt}from"./storage/index.js";import{isBuildBelowMinimum as At,parseBuildNumber as jt}from"./versionCheck/buildNumber.js";import{installReloadOnNavigate as Mt,isUpdateAvailable as Nt,useVersionCheck as Pt}from"./versionCheck/index.js";export{g as ACCESS_TOKEN_KEY,L as ACCOUNT_ID_HEADER,He as APP_API_DEFAULTS,R as CLIENT_BUILD_HEADER,z as CLIENT_KIND,B as CLIENT_KIND_HEADER,me as CONTRACT_ERROR_CODE,e as DEFAULT_CORRELATION_ID_HEADER,t as DEFAULT_LOG_LEVEL,n as DEFAULT_RETRIES,r as DEFAULT_TIMEOUT_MS,X as IDEMPOTENCY_KEY_HEADER,_ as LEGACY_REFRESH_TOKEN_LIFETIME_MS,Xe as LIST_TAG_ID,c as Logger,H as MIN_APP_VERSION_HEADER,he as NETWORK_CODE,ge as OFFLINE_CODE,_e as OFFLINE_MESSAGE,gt as PublicOnly,ne as REFRESH_LOCK_NAME,v as REFRESH_TOKEN_KEY,ve as REQUEST_CANCELED_CODE,ft as RETURN_TO_PARAM,de as RequestOfflineError,_t as RequireAuth,vt as RequirePermission,at as SERIALIZABLE_IGNORED_ACTION_PATHS,ye as SERVER_FAILURE_MESSAGE,fe as SESSION_TERMINATION_CODES,y as SESSION_USER_KEY,ae as SIGN_OUT_REASON_HEADER,Et as Storage,be as TIMEOUT_CODE,xe as TIMEOUT_MESSAGE,Se as UNEXPECTED_MESSAGE,Ce as UNREACHABLE_MESSAGE,q as WORKSPACE_CHANGED_CODE,J as WorkspaceChangedError,Me as addDays,U as addMinAppVersionListener,N as addNetworkStatusListener,b as addSessionEndedListener,we as apiErrorMessage,G as applyRequestDefaults,Z as attachRetry,Ge as buildListQuery,pt as buildLoginPath,Ct as classifyRouteError,x as clearSession,ke as configureFormatters,l as configureLogger,Ve as createApiBaseQuery,Ue as createAppApi,rt as createRootReducer,p as decodeJWT,tt as errorToastMiddleware,Te as extractApiError,je as formatCurrency,Ne as formatDate,Pe as formatDateTime,Fe as formatMinor,Ie as formatNumber,Le as formatPercent,Re as formatRelative,ze as formatTime,V as getClientBuild,i as getConfig,a as getConfigValue,u as getDeviceContext,Ae as getFormatterConfig,m as getJWTExpiry,S as getKeepSignedIn,W as getMinAppVersion,P as getNetworkStatus,Ke as getNextPageParam,qe as getPreviousPageParam,mt as getReturnTo,C as getSessionUser,w as getToken,Je as hasNextPage,dt as hasPermission,Ye as hasPreviousPage,ot as hasRecentlyReloaded,T as hasSession,E as hasSessionEndedInTab,st as importWithReload,pe as initUserAuth,Be as initWebority,oe as injectStore,se as injectUserAuth,Mt as installReloadOnNavigate,Ee as isApiError,At as isBuildBelowMinimum,ct as isChunkLoadError,h as isJWTExpired,Q as isNeverSentError,De as isNoResponse,$ as isRetryableFailure,ee as isRetryableStatus,nt as isSilentRejection,Dt as isStorageAvailable,Nt as isUpdateAvailable,Y as isWorkspaceChangedError,Ze as itemTag,lt as lazyWithReload,Qe as listTag,ut as markReloaded,K as newCorrelationId,jt as parseBuildNumber,$e as providesList,et as providesPagedList,ie as publicClient,yt as publicOnly,ce as refreshAccessToken,D as removeSessionUser,O as removeToken,bt as requireAuth,xt as requirePermission,o as resetConfig,le as resetRefreshState,it as resetState,te as retryAfterMs,s as setConfig,d as setDeviceContext,k as setKeepSignedIn,A as setLegacyTokenKeys,F as setNetworkStatusImplementation,f as setRemoteLogger,Ot as setStorageImplementation,We as setupApiListeners,Tt as staticUrl,j as storeSessionUser,M as storeToken,kt as syncStorage,Oe as toFieldPath,ht as toSafeReturnTo,I as useNetworkStatus,wt as useRouteErrorReport,Pt as useVersionCheck,ue as userClient,re as withCrossTabRefreshLock,St as withGuards};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
function e(e,...t){console.warn(e,...t)}export{e as devWarn};
|
|
@@ -12,9 +12,9 @@
|
|
|
12
12
|
* legacy `error`, `title`, then `Request failed (<status>)`. `title` is last because it is
|
|
13
13
|
* the ProblemDetails category ("Bad Request"), not the curated sentence.
|
|
14
14
|
*
|
|
15
|
-
* Two things never become `message`: a 5xx body
|
|
16
|
-
* and anything that reads like an exception dump.
|
|
17
|
-
* the logger instead.
|
|
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.
|
|
18
18
|
*/
|
|
19
19
|
export interface ApiError {
|
|
20
20
|
/** Stable snake_case branch key from the server (`not_found`, `validation_failed`). Branch on it, never render it. */
|
|
@@ -34,6 +34,7 @@ export interface ApiError {
|
|
|
34
34
|
}
|
|
35
35
|
export declare const SERVER_FAILURE_MESSAGE = "Something went wrong on our side. Please try again in a moment.";
|
|
36
36
|
export declare const OFFLINE_MESSAGE = "You appear to be offline. Check your connection and try again.";
|
|
37
|
+
export declare const UNREACHABLE_MESSAGE = "We couldn't reach the server. Check your connection and try again.";
|
|
37
38
|
export declare const TIMEOUT_MESSAGE = "That took too long to respond. Check your connection and try again.";
|
|
38
39
|
export declare const UNEXPECTED_MESSAGE = "Something went wrong. Please try again.";
|
|
39
40
|
/** `code` for a request the caller cancelled (axios `CanceledError`). Never toasted. */
|
|
@@ -42,8 +43,10 @@ export declare const REQUEST_CANCELED_CODE = "request_canceled";
|
|
|
42
43
|
export declare const CONTRACT_ERROR_CODE = "contract_error";
|
|
43
44
|
/** `code` for a request that got no answer in time (axios `ECONNABORTED` / `ETIMEDOUT`). `offline` is true. */
|
|
44
45
|
export declare const TIMEOUT_CODE = "timeout";
|
|
45
|
-
/** `code` for a request that never reached the server (
|
|
46
|
+
/** `code` for a request that never reached the server while the browser reported a connection (DNS, CORS, a dropped connection). `offline` is true. */
|
|
46
47
|
export declare const NETWORK_CODE = "network";
|
|
48
|
+
/** `code` for a request that never reached the server while the browser reported no network. `offline` is true. */
|
|
49
|
+
export declare const OFFLINE_CODE = "offline";
|
|
47
50
|
/** `Items[0].UnitPrice` -> `items[0].unitPrice`; `$.email` (System.Text.Json path) -> `email`. */
|
|
48
51
|
export declare const toFieldPath: (key: string) => string;
|
|
49
52
|
export declare const isApiError: (value: unknown) => value is ApiError;
|
|
@@ -56,9 +59,10 @@ export declare const isNoResponse: (error: unknown) => boolean;
|
|
|
56
59
|
/**
|
|
57
60
|
* The sentence a screen shows for a failure: the server's own curated message when it sent one,
|
|
58
61
|
* otherwise the screen's `fallback` ("We couldn't save the project."), otherwise the library's
|
|
59
|
-
* generic sentence. A lost answer always reads as
|
|
60
|
-
* connection" is more accurate than any screen's fallback
|
|
61
|
-
* with no usable sentence count as "the server
|
|
62
|
+
* generic sentence. A lost answer always reads as its connection message, because "check your
|
|
63
|
+
* connection" is more accurate than any screen's fallback, and so does a 5xx with a curated body.
|
|
64
|
+
* A 5xx without one, a cancelled request and a body with no usable sentence count as "the server
|
|
65
|
+
* said nothing usable".
|
|
62
66
|
*
|
|
63
67
|
* `fallback: null` is the "say nothing" mode, for a screen that shows only what the server
|
|
64
68
|
* curated (a live panel that keeps its last result): it returns null when the server said
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
export type { ApiError } from "./extractApiError";
|
|
2
|
-
export { apiErrorMessage, CONTRACT_ERROR_CODE, extractApiError, isApiError, isNoResponse, NETWORK_CODE, OFFLINE_MESSAGE, REQUEST_CANCELED_CODE, SERVER_FAILURE_MESSAGE, TIMEOUT_CODE, TIMEOUT_MESSAGE, toFieldPath, UNEXPECTED_MESSAGE, } from "./extractApiError";
|
|
2
|
+
export { apiErrorMessage, CONTRACT_ERROR_CODE, extractApiError, isApiError, isNoResponse, NETWORK_CODE, OFFLINE_CODE, OFFLINE_MESSAGE, REQUEST_CANCELED_CODE, SERVER_FAILURE_MESSAGE, TIMEOUT_CODE, TIMEOUT_MESSAGE, toFieldPath, UNEXPECTED_MESSAGE, UNREACHABLE_MESSAGE, } from "./extractApiError";
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
* `signDisplay`, ...), passed through to Intl.NumberFormat.
|
|
4
4
|
*/
|
|
5
5
|
export interface FormatCurrencyOptions extends Omit<Intl.NumberFormatOptions, "style" | "currency"> {
|
|
6
|
-
/** ISO 4217
|
|
6
|
+
/** ISO 4217 code; pass it on every call, since a call without one warns now and throws from 0.78.0. */
|
|
7
7
|
currency?: string;
|
|
8
8
|
/** BCP-47 locale tag. Defaults to the configured locale, else `'en-IN'` (Indian numbering system). */
|
|
9
9
|
locale?: string;
|
|
@@ -20,9 +20,10 @@ export interface FormatCurrencyOptions extends Omit<Intl.NumberFormatOptions, "s
|
|
|
20
20
|
empty?: string;
|
|
21
21
|
}
|
|
22
22
|
/**
|
|
23
|
-
* Format an amount as currency
|
|
24
|
-
*
|
|
25
|
-
*
|
|
23
|
+
* Format an amount as currency, with Indian numbering (`en-IN`), which matches the standard
|
|
24
|
+
* convention across Webority projects. Pass currency 'INR' on every call: a call without one
|
|
25
|
+
* warns and prints INR for now. With currency 'INR': "₹1,50,000" for 150000, "₹1,234.50" for
|
|
26
|
+
* 1234.5, and `''` for a missing amount.
|
|
26
27
|
* Once the app configures a locale (`configureFormatters({ locale })`), the amount is
|
|
27
28
|
* written in that locale and a missing amount prints the configured placeholder ("-").
|
|
28
29
|
* A configured `numberStyle` sets the decimal mark and group separator; the locale keeps
|
|
@@ -31,10 +32,10 @@ export interface FormatCurrencyOptions extends Omit<Intl.NumberFormatOptions, "s
|
|
|
31
32
|
* use `formatMinor`.
|
|
32
33
|
*
|
|
33
34
|
* @example
|
|
34
|
-
* formatCurrency(150000)
|
|
35
|
-
* formatCurrency(1234.5)
|
|
36
|
-
* formatCurrency(99, { currency: 'USD', locale: 'en-US' })
|
|
37
|
-
* formatCurrency(150000, { stripSymbol: true })
|
|
38
|
-
* formatCurrency(1500000, { notation: 'compact' })
|
|
35
|
+
* formatCurrency(150000, { currency: 'INR' }) // ₹1,50,000
|
|
36
|
+
* formatCurrency(1234.5, { currency: 'INR' }) // ₹1,234.50
|
|
37
|
+
* formatCurrency(99, { currency: 'USD', locale: 'en-US' }) // $99
|
|
38
|
+
* formatCurrency(150000, { currency: 'INR', stripSymbol: true }) // 1,50,000
|
|
39
|
+
* formatCurrency(1500000, { currency: 'INR', notation: 'compact' }) // ₹15L
|
|
39
40
|
*/
|
|
40
41
|
export declare const formatCurrency: (amount: number | string | null | undefined, options?: FormatCurrencyOptions) => string;
|
|
@@ -1,37 +1,3 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* The house formatters: DD-MMM-YYYY dates, IST by default or the viewer's own
|
|
3
|
-
* zone with a label, Indian digit grouping by default, money in minor units,
|
|
4
|
-
* and one empty placeholder. Byte-identical in @webority/mobile-core and
|
|
5
|
-
* @webority/web-core.
|
|
6
|
-
*
|
|
7
|
-
* Same output on Hermes and in every browser is the design constraint, so the
|
|
8
|
-
* text is assembled here rather than by Intl. Engines disagree on month
|
|
9
|
-
* abbreviations ("Sep" or "Sept"), on the space before AM/PM (a plain or a
|
|
10
|
-
* narrow no-break space), on zone names ("IST" or "GMT+5:30") and on which
|
|
11
|
-
* Intl options exist at all (Hermes has no RelativeTimeFormat and no
|
|
12
|
-
* trailingZeroDisplay). IST and the viewer's zone are therefore computed with
|
|
13
|
-
* plain Date arithmetic; Intl is used only to read the wall clock of an
|
|
14
|
-
* explicitly named IANA zone, through formatToParts with numeric fields, to
|
|
15
|
-
* read the locale's 12- or 24-hour clock, and where a caller asks for Intl
|
|
16
|
-
* output itself (Intl number options, `formatRelative({ intl: true })`).
|
|
17
|
-
*
|
|
18
|
-
* Called with no options (house defaults: zone IST, locale en-IN, empty "-"):
|
|
19
|
-
* - formatDate(v) "08-Apr-2026"; formatTime(v) "8:05 PM"; formatDateTime(v) "08-Apr-2026, 8:05 PM";
|
|
20
|
-
* - formatRelative(v) "5 minutes ago", "in 3 days", "just now";
|
|
21
|
-
* - formatNumber(v) "1,23,456.789" (Indian grouping, up to 3 decimals);
|
|
22
|
-
* - formatPercent(0.42) "42%"; formatMinor(15000000) "₹1,50,000.00";
|
|
23
|
-
* - a missing or unreadable value "-".
|
|
24
|
-
*
|
|
25
|
-
* With a configured locale (`configureFormatters({ locale })`), the words and separators come
|
|
26
|
-
* from Intl for that locale and the date order stays DD-MMM-YYYY. For en-IN in the viewer zone:
|
|
27
|
-
* "08-Sept-2026", "08:05 pm", "08-Sept-2026, 08:05 pm IST", "yesterday", "12,34,567.891",
|
|
28
|
-
* "₹1,50,000". For de-DE: "08-Sept-2026", "20:05", "1.234.567,891".
|
|
29
|
-
*
|
|
30
|
-
* A configured `numberStyle` puts its decimal mark and group separator in every number and amount,
|
|
31
|
-
* whichever path wrote it: "1.23.456,789" for `'CommaWithPointGroups'` with the house text. A
|
|
32
|
-
* configured `dateOrder` other than DD-MMM-YYYY writes the date as digits from the wall clock,
|
|
33
|
-
* in every locale: "08/04/2026", "04/08/2026", "2026-04-08".
|
|
34
|
-
*/
|
|
35
1
|
import { type NumberGrouping, type ZoneMode } from "./formatConfig";
|
|
36
2
|
/** A date the house formatters accept; null, undefined and "" read as missing. */
|
|
37
3
|
export type DateValue = Date | string | number | null | undefined;
|
|
@@ -96,7 +62,7 @@ export interface FormatPercentOptions extends FormatNumberOptions {
|
|
|
96
62
|
scale?: "ratio" | "percent";
|
|
97
63
|
}
|
|
98
64
|
export interface FormatMinorOptions {
|
|
99
|
-
/** ISO 4217 code
|
|
65
|
+
/** ISO 4217 code; pass it on every call, since a call without one warns now and throws from 0.78.0. */
|
|
100
66
|
currency?: string;
|
|
101
67
|
/** Defaults to Indian grouping for INR and international grouping for every other currency. */
|
|
102
68
|
grouping?: NumberGrouping;
|
|
@@ -138,7 +104,7 @@ export declare const formatNumber: (value: number | string | null | undefined, o
|
|
|
138
104
|
export declare const formatPercent: (value: number | string | null | undefined, options?: FormatPercentOptions) => string;
|
|
139
105
|
/**
|
|
140
106
|
* Money held in minor units (paise, cents), which is how every API carries
|
|
141
|
-
* it: formatMinor(15000000) gives "₹1,50,000.00". The split into whole and
|
|
107
|
+
* it: formatMinor(15000000, { currency: "INR" }) gives "₹1,50,000.00". The split into whole and
|
|
142
108
|
* fractional units is done on the integer's digits, so no floating-point
|
|
143
109
|
* division can shift a paisa. A fractional input is rounded to the nearest
|
|
144
110
|
* minor unit. A currency without a known symbol prints its code: "AED 1,000.00".
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@webority/web-core",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.77.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",
|