Skip to content
All changes

Breaking

HttpRepository writes and shares the data provider auth; BaseCrudService goes

@venizia/ardor

Changelog - 2026-10-02 ​

HttpRepository writes and shares the data provider auth; BaseCrudService goes ​

Breaking Change

In one line. HttpRepository from @venizia/ardor/repository now writes as well as reads. It shares the data provider's token and its single 401 refresh, and it replaces BaseCrudService, which is removed. ARDOR builds on the IGNIS 0.2.1 prerelease line (next).

What changed ​

  • Writes. HttpRepository re-exports IGNIS connectors 0.2.1-3 unchanged, so it gains the writes:
CallRequest
create({ data })POST /{resource}
updateById({ id, data })PATCH /{resource}/{id}
updateBy({ where, data }) (also updateAll)PATCH /{resource}, where in the body
deleteById({ id })DELETE /{resource}/{id}
deleteBy({ where }) (also deleteAll)DELETE /{resource}, where in the body
  • What a write answers. { count, data }. count comes from the server's x-response-count header, and options: { shouldReturn: false } answers data: null.
  • What a write refuses. An empty bulk where throws before a request is sent. There is no createAll.
  • Ids in the URL. The id is URL-encoded, for reads too.
  • The second type parameter. HttpRepository<E, P = Partial<E>>: P is what a write sends.
  • Any other route. HttpDataSource.request() takes a body and per-request headers on any method, PUT included. HttpDataSource.read() takes method and body too, so a hand-written list route, such as a POST .../list/find, still gets Content-Range parsing.
  • Shared auth. DefaultNetworkRequestService.getDataSourceAuth() returns { authTokenResolver, onUnauthorized } (IDataSourceAuth). Spread it into an HttpDataSource, and the repository sends the data provider's token, including one set with setAuthToken. A burst of 401s across the data provider and any repository calls refreshToken once, and runs onAuthFailure once if that refresh fails. resolveAuthToken() is public: it is the token without a header built around it.
  • Providers are singletons. Framework bindings are declared with @configuration() + @provide({ key }), and registerArtifacts() binds each provided key as lazy and singleton, so one data provider serves react-admin, DefaultAuthProvider, every hook and every datasource. A bare bind().toProvider() in bindContext() is transient: each consumer got its own data provider and network service, so react-admin sent locale=null and a repository request carried no authorization header.
  • Error arguments. A repository error now carries the server's normalized.args, so useNotifyError fills a translated message's placeholders.
  • Peers. The IGNIS peers move to the 0.2.1 line:
PackageBeforeNow
@venizia/ignis-connectors^0.2.0>=0.2.1-3 <0.3.0
@venizia/ignis-kernel^0.2.0>=0.2.1-2 <0.3.0
@venizia/ignis-filter, -helpers^0.2.0>=0.2.1-0 <0.3.0
@venizia/ignis-inversion^0.2.0unchanged

^0.2.0 does not admit a prerelease, so with the old peers a workspace kept a second, older copy of each IGNIS package. The new ranges accept every 0.2.x stable from 0.2.1 on, and refuse 0.3.0.

WARNING

The 0.1.2-0 and 0.1.2-1 prereleases sent a getMany longer than 6,000 encoded characters to POST /{resource}/find. On IGNIS kernel 0.2.1-1 that route skipped a controller's overridden find(), so a tenant-scoped app could read every tenant's rows (IGNIS #92). Do not deploy either prerelease, and do not run a backend on kernel 0.2.1-1 or connectors 0.2.1-2. getMany is a GET to the collection again, however long the list, and IGNIS 0.2.1-3 removes the route. A very long id list answers 414/431 again.

Removed ​

  • BaseCrudService, ICrudServiceOptions, ICrudService, IService and EntityRelationType. BaseCrudService took positional arguments, and its updateAll sent where in the query string, which an IGNIS bulk route answers with a 400. Use an HttpRepository.

Who is affected ​

  • Code that imported BaseCrudService or ICrudService. Extend HttpRepository instead. find({ filter }), findById({ id }), count({ where }), create({ data }), updateById({ id, data }), updateBy({ where, data }) and deleteById({ id }) cover what it did, with options objects. replaceById (PUT) has no verb: send it with dataSource.request({ method: 'PUT', ... }).
  • Every application that binds the default providers with a bare bind() in bindContext(). Move those bindings into a @configuration() class: one @provide({ key }) method per framework key, imported before application.start(). An override of a provided key can stay in bindContext().
  • Applications with an HttpDataSource and auth recovery. Inject the data provider and spread getNetworkService().getDataSourceAuth() into the datasource settings. See auth recovery.
  • Applications on IGNIS 0.2.0. Move @venizia/ignis-connectors to 0.2.1-3, kernel to 0.2.1-2, and filter and helpers to 0.2.1-0, together with ARDOR. Pin these exact versions: until IGNIS 0.2.1 is stable they install from next, and the next tags of inversion and boot still point at old 0.2.0 prereleases.
  • Code that matches a failed read by its message. A failed request now throws with the server's message after the URL, [http][read] 404 | <url> | Ticket not found, and with the server's normalized.code and normalized.args. Match on the status or the code instead.
  • A server-side order entry with more than two tokens, or an empty one, is now a 400 on an IGNIS backend. ARDOR's data provider always sends two (field ASC), so nothing changes there.

See Repositories.