Changelog - 2026-10-25
The network service is split into small parts, and its types are closed
Breaking ChangeIn one line. DefaultNetworkRequestService keeps its constructor and its protected hooks, but the code behind it is in separate classes, the request types no longer accept any key, and the fetcher and the socket client now come from IGNIS.
What changed
- Split into classes.
AuthTokenStore(the one reader and writer of the stored token),RequestBodyEncoder,ResponseReader,AuthRecoveryand, in admin,ListFilterBuilder(react-admin list params to the IGNIS filter, the query and the list extras). The service andDefaultRestDataProviderdelegate to them. A subclass that overridesrefreshToken,onAuthFailureorisNoAuthPathkeeps working;refresh(),convertResponse,readAuthTokenFromStorage(),getRequestProps,doRequestand the protectedauthRecoveryfield stay on the service, andDefaultRestDataProvider.buildListFilterstays a protected hook that delegates toListFilterBuilder, which@venizia/ardor-adminnow exports.IAuthTokenRecord,IDataSourceRequestContext,IDataSourceAuthand the newINetworkResponseare exported from the package root. - New hooks to override.
encodeBody({ bodyType, body })on the service (returns{ body, contentType? }) encodes a body another way.request({ resource, type, method, paths?, body?, bodyType?, query?, extra?, headers?, requestCountData? })onDefaultRestDataProvider(typedIRestRequestOptions) is called by all ten methods; override it to move every method,send()included, to another transport. Headers named inheaderswin over the computed ones. requestListreplacesgetListHelper. The list GET, with the extras a route answered asmeta.extra, is the protectedrequestList({ resource, type, queryKey, filter, extra? }).CountRestDataProvideroverrides it, so itswithoutExtraHeaderworkaround is gone.- The request types name every field.
ISendParamsandIApplicationInfono longer end in[key]: any, so a typo is a compile error instead of a field that is silently dropped.ISendParams.bodyisunknownandqueryisRecord<string, unknown>;extrais named.ISendResponseis theINetworkResponseit duplicated. - The provider types come from ra-core.
IReactAdminDataProvideris the nine data methods of ra-core'sDataProvider, andIReactAdminAuthProviderthe auth methods of itsAuthProvider(withgetPermissionsrequired), so a ra-core upgrade changes them. refreshTokenanswers a boolean.IAuthProvider.refreshToken,DefaultAuthProvider.refreshTokenanduseRefreshTokenarePromise<boolean>:truewhen the session was refreshed,falsewhen there is no refresh to make (useRefreshTokenalso answersfalsewith no auth provider, where it answeredundefined).AnyTypeleaves the signatures.send(),request(),doRequest(),ISendResponseandINetworkResponsedefault tounknowndata (name the type:send<TSignInResponse>(...)); the record generics of the data provider methods default toRaRecord; the auth hooks takeILoginParamsorunknown; the list filter is a namedIListFilter;i18nSourcesisRecord<string, object>; theLoggertakesunknownarguments;useService,useProvider,useComponent,useConfigurationanduseRepositorydefault tounknown.useTranslate()is typed in every case. It returnsTUseTranslateFn, andtranslate()returnsstring. Before, a plainstringkey and a translated text assigned to a key-typed prop both compiled.- The transport is IGNIS's.
DefaultNetworkRequestServicesends throughNodeFetchNetworkRequestfrom@venizia/ignis-helpers/core, withqueryString: { nullish: 'skip', nested: 'json' }(a filter is one JSON parameter and a null is left out). Request behaviour is unchanged: the same query, bodies, headers, timeout with the caller's signal and multipart boundary and redacted debug log; the service passes itsLoggertosend. - The socket client is IGNIS's too. Use
SocketIOClientHelperfrom@venizia/ignis-helpers/socket-io/clientand hand itmodule: { io }from your ownsocket.io-clientimport.socket.io-clientis no longer a peer of ARDOR. - The kernel needs a newer
@venizia/ignis-helpers. The peer range moves to the release that carries the browser-ready fetcher, query-string options and socket client. - The kernel loses
lodash, its only runtime dependency, with the unused parse utilities listed below.
Who is affected
- A subclass of
DefaultNetworkRequestService. No action for the split itself: nothing it overrides changed, except the protected helpers listed under Breaking changes. - A log reader. A corrupt stored token is logged once, as a warning with scope
AuthTokenStore.getAuth()used to log an error under the scopeDefaultAuthService, and also for an empty string; an empty string is now nothing stored. - Code that imports from the file path.
IAuthTokenRecordand the two data source types are no longer declared inbase/services/network-request; import them from the package root. - Code that uses the removed exports, the
./socket-iosub-paths or untypedsend()calls. See below.
Breaking changes
WARNING
Most of this affects a subclass of DefaultNetworkRequestService or DefaultRestDataProvider, code that imports the removed exports, and type-checking. The type changes have no run-time effect; the run-time differences are the useRefreshToken result with no auth provider, the /count request id and the log entry described below.
Protected members removed from DefaultNetworkRequestService. isFileList, encodeFormValue and appendFormDataValue are gone; to change how a body is encoded, override encodeBody. parseFilenameFromContentDisposition is gone; ResponseReader (whose ERROR_ROOT_KEY is the key the data source auth shares) reads the file name of a response with the same rules (filename* before a quoted, before a bare filename). The private members canRecover and refreshing are gone, which matters only to code that reached them through a cast.
getListHelper is gone from DefaultRestDataProvider and CountRestDataProvider: it was public, took a requestProps argument, and is now the protected requestList with extra in its place.
// Before
override getListHelper(opts: { resource; type; queryKey; filter; requestProps }) { ... }
// After
protected override requestList(opts: { resource; type; queryKey; filter; extra? }) { ... }A subclass that overrode the ten methods one by one to change the transport can override request() instead. The /count request of CountRestDataProvider now builds its own headers, so it has its own x-request-id; it shared the list's.
Removed from @venizia/ardor-kernel and @venizia/ardor: the parse utilities. NumberParseMethods, TNumberParseMethod, INTL_0_DIGITS_FORMATTER, INTL_2_DIGITS_FORMATTER, generateUniqueId, toCamelCase, keysToCamelCase, isInteger, isFloat, toInteger, toFloat, toBoolean, toStringDecimal, getNumberValue and parseQueryString. Replace parseQueryString({ search }) with Object.fromEntries(new URLSearchParams(search)); for the rest, use the IGNIS helpers (@venizia/ignis-helpers) or your own.
Removed from the same packages: the fetcher and the socket client. AbstractNetworkFetchableHelper, BaseNetworkRequest, IFetchable, IFetcherRequestOptions, INodeFetchNetworkOptions, INodeFetchRequestOptions, IRequestOptions, ISocketIOClientOptions, NodeFetcher, NodeFetchNetworkRequest, SocketIOClientHelper, TFetcherResponse, TFetcherVariant, TFetcherWorker, TSocketIOEventHandler and toQueryString; and the sub-paths @venizia/ardor-kernel/socket-io and @venizia/ardor/socket-io. Import the fetcher, BaseNetworkRequest, IFetchable, toQueryString and NodeFetchNetworkRequest from @venizia/ignis-helpers/core, and the socket client from @venizia/ignis-helpers/socket-io/client (its handlers receive the payload, not the socket; emit takes data, not message; see Socket.IO client). A service subclass that assigns networkRequest assigns an IGNIS one.
Closed request types. ISendParams loses the index signature and the unused id and file; IApplicationInfo loses the index signature; the unused IRequestProps is removed. Code that passed an extra key to either now fails to compile: delete the key, or carry the value another way (a header in headers, a path in resource).
Type-level changes. Name the type on send() and resolve true from a refreshToken override:
-.send({ resource, params })
-.then((rs: { data: TSignInResponse }) => { /* ... */ resolve(rs); })
+.send<TSignInResponse>({ resource, params })
+.then(rs => { /* ... */ resolve(true); }) // inside new Promise<boolean>(...)- A subclass of
DefaultAuthProviderthat overridesrefreshTokenmust returnPromise<boolean>. - A call to
send()ordoRequest()without a type argument getsunknowndata: pass the type. - A value that is a translated text must not be typed as
TUseTranslateKeys, and a key built at run time must be typed as one.