@venizia/ardor-admin 0.4.8-1 → 0.4.8-3

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
@@ -4,7 +4,7 @@ The [react-admin](https://marmelab.com/react-admin/) adapter of
4
4
  [ARDOR](https://github.com/VENIZIA-AI/ardor): every place the framework touches `ra-core`.
5
5
 
6
6
  ```bash
7
- bun add @venizia/ardor-admin @venizia/ardor-kernel @venizia/ardor-react @venizia/ignis-inversion @venizia/ignis-filter @venizia/ignis-kernel @venizia/ignis-helpers reflect-metadata ra-core ra-i18n-polyglot
7
+ bun add @venizia/ardor-admin @venizia/ardor-kernel @venizia/ardor-react @venizia/ignis-inversion @venizia/ignis-filter @venizia/ignis-kernel @venizia/ignis-helpers reflect-metadata ra-core ra-i18n-polyglot react react-dom react-redux react-router-dom @reduxjs/toolkit @tanstack/react-query
8
8
  ```
9
9
 
10
10
  Most applications install [`@venizia/ardor`](https://www.npmjs.com/package/@venizia/ardor) instead,
@@ -15,11 +15,15 @@ which re-exports this package.
15
15
  | Area | Exports |
16
16
  |---|---|
17
17
  | Data | `DefaultRestDataProvider`, `CountRestDataProvider` |
18
- | Auth | `DefaultAuthProvider` |
18
+ | Auth | `DefaultAuthProvider`, `SessionClearReasons`, `IAuthRejection` |
19
19
  | i18n | `DefaultI18nProvider`, `englishMessages`, `vietnameseMessages` |
20
- | Component | `ArdorApplication` - the `CoreAdmin` root, wired from the container |
21
- | Hooks | `useTranslate`, `useNotifyError`, `useRefreshToken`, `useRequestHeaderLocale` |
22
- | Types | `IDataProvider`, `IAuthProvider`, `II18nProviderOptions`, `IApplication`, `TUseTranslateKeys` |
20
+ | Component | `ArdorApplication` - the `CoreAdmin` root, wired from the container; `ApplicationProviders` |
21
+ | Features | `Features`, `TFeature`, `useFeatures` |
22
+ | Lists | `ListFilterBuilder` |
23
+ | Hooks | `useTranslate`, `useUntypedTranslate`, `useNotifyError`, `useRefreshToken`, `useRequestHeaderLocale`, `useFeatures`, `useDocumentTitle`, `useHtmlLang` |
24
+ | Types | `IDataProvider`, `IAuthProvider`, `II18nProviderOptions`, `IApplication`, `TUseTranslateKeys`, `TI18nSource` |
25
+
26
+ Every export, with its signature, is in the [references](https://ardor.venizia.ai/references/).
23
27
 
24
28
  The data provider speaks the `@venizia/ignis-filter` vocabulary - react-admin pagination, sort and
25
29
  filter are mapped onto `{ where, order, limit, skip, fields, include }`.
@@ -1,3 +1,4 @@
1
+ /** The built-in English messages: react-admin's `ra` catalogue and ARDOR's own keys. */
1
2
  export declare const englishMessages: {
2
3
  ra: {
3
4
  action: {
@@ -1,3 +1,4 @@
1
+ /** The built-in English messages: react-admin's `ra` catalogue and ARDOR's own keys. */
1
2
  export const englishMessages = {
2
3
  ra: {
3
4
  action: {
@@ -1,3 +1,4 @@
1
1
  import type { TranslationMessages } from 'ra-core';
2
+ /** The built-in Vietnamese messages, the same shape as `englishMessages`. */
2
3
  export declare const vietnameseMessages: TranslationMessages;
3
4
  //# sourceMappingURL=vi.d.ts.map
@@ -1,3 +1,4 @@
1
+ /** The built-in Vietnamese messages, the same shape as `englishMessages`. */
1
2
  export const vietnameseMessages = {
2
3
  ra: {
3
4
  action: {
@@ -5,30 +5,46 @@ import type { TExtraRequest } from '@venizia/ignis-kernel/repository';
5
5
  import type { AuthProvider, CoreAdminProps, DataProvider, Locale, ResourceProps } from 'ra-core';
6
6
  import type { ReactNode } from 'react';
7
7
  import type { RouteProps } from 'react-router-dom';
8
- import type { DefaultNetworkRequestService, IDataSourceAuth, ISendParams, ISendResponse, RequestCountData, TConstValue, TRequestMethod, TRequestType } from '@venizia/ardor-kernel';
8
+ import type { DefaultNetworkRequestService, IDataSourceAuth, INetworkResponse, ISendParams, RequestCountData, TConstValue, TRequestMethod, TRequestType } from '@venizia/ardor-kernel';
9
9
  import type { TFeature } from '../features/feature.js';
10
10
  /** What `DefaultRestDataProvider.request` sends: every react-admin method goes through it. */
11
11
  export interface IRestRequestOptions<TResource extends string = string> {
12
+ /** The first path segment, unless `paths` is set. */
12
13
  resource: TResource;
14
+ /** What the response is read as, and what the request is logged as. */
13
15
  type: TRequestType;
16
+ /** The HTTP method. */
14
17
  method: TRequestMethod;
15
- /** Default `[resource]`. */
18
+ /**
19
+ * The path segments of the request.
20
+ * @default [resource]
21
+ */
16
22
  paths?: Array<string>;
23
+ /** The request body; encoded by `bodyType`. */
17
24
  body?: unknown;
18
25
  bodyType?: ISendParams['bodyType'];
26
+ /** The query string. */
19
27
  query?: Record<string, unknown>;
28
+ /** The list extras, sent in a header. */
20
29
  extra?: TExtraRequest;
21
30
  /** Win over the computed headers: a caller that names a header means it. */
22
31
  headers?: HeadersInit;
32
+ /**
33
+ * What the request asks the server to count.
34
+ * @default RequestCountData.DATA_ONLY
35
+ */
23
36
  requestCountData?: TConstValue<typeof RequestCountData>;
24
37
  }
25
38
  /** The nine data methods of react-admin, as ra-core declares them. */
26
39
  export type IReactAdminDataProvider<TResource extends string = string> = Pick<DataProvider<TResource>, 'getList' | 'getOne' | 'getMany' | 'getManyReference' | 'update' | 'updateMany' | 'create' | 'delete' | 'deleteMany'>;
40
+ /** react-admin's data provider with a free-form `send` and access to the network service and its auth. */
27
41
  export interface IDataProvider<TResource extends string = string> extends IReactAdminDataProvider<TResource> {
42
+ /** A request outside react-admin's methods: the same headers and auth, the method and body of `params`. */
28
43
  send: <TResult = unknown>(opts: {
29
44
  resource: TResource;
30
45
  params: ISendParams;
31
- }) => Promise<ISendResponse<TResult>>;
46
+ }) => Promise<INetworkResponse<TResult>>;
47
+ /** The network service every request goes through. */
32
48
  getNetworkService(): DefaultNetworkRequestService;
33
49
  /** Spread into an `HttpDataSource`: the repository then sends what this provider sends. */
34
50
  getDataSourceAuth(): IDataSourceAuth;
@@ -45,7 +61,9 @@ export interface IAuthRejection {
45
61
  logoutUser?: boolean;
46
62
  message?: string | false;
47
63
  }
64
+ /** The auth provider of an ARDOR application: react-admin's methods, the user's roles and a token refresh. */
48
65
  export interface IAuthProvider extends IReactAdminAuthProvider {
66
+ /** The roles of the signed-in user. */
49
67
  getRoles: (params?: unknown) => Promise<Set<string>>;
50
68
  /** `true` when the session was refreshed, `false` when there is no refresh to make. */
51
69
  refreshToken: () => Promise<boolean>;
@@ -56,19 +74,31 @@ export interface IAuthProvider extends IReactAdminAuthProvider {
56
74
  * is the messages). A loader that fails leaves that locale on the English messages.
57
75
  */
58
76
  export type TI18nSource = object | (() => Promise<object>);
77
+ /** What `DefaultI18nProvider` is built from: the message sources and the languages on offer. */
59
78
  export interface II18nProviderOptions {
60
- /** Messages by locale: the application's own over the features', English for a locale with no source or whose loader failed. */
79
+ /**
80
+ * Messages by locale: the application's own over the features', English for a locale with no source or whose loader failed.
81
+ * @default { en: englishMessages }
82
+ */
61
83
  i18nSources?: Record<string, TI18nSource>;
84
+ /**
85
+ * The locales the app offers.
86
+ * @default [{ locale: 'en', name: 'English' }]
87
+ */
62
88
  languages?: Array<Locale>;
63
89
  }
90
+ /** The props of `ArdorApplication`: react-admin's `CoreAdmin` props except `children`, plus the ARDOR ones. */
64
91
  export interface IApplication extends Omit<CoreAdminProps, 'children'> {
92
+ /** The container the providers and the features are resolved from. */
65
93
  container: Container;
66
94
  /**
67
- * The logger `useApplicationLogger()` returns. Absent, a console logger named after the application
95
+ * The logger `useApplicationLogger()` returns. Absent, a console logger named `ArdorApplication`
68
96
  * (IGNIS's, so a provider registered with `LoggerFactory.use` is the one behind it).
69
97
  */
70
98
  logger?: ILogger;
99
+ /** The store the Redux provider of the shell serves. */
71
100
  reduxStore: Store;
101
+ /** Rendered as the `Suspense` fallback and while feature messages for the locale load. */
72
102
  suspense: ReactNode;
73
103
  /** The application's own resources; each feature's are mounted after them. */
74
104
  resources?: Array<ResourceProps>;
@@ -1,4 +1,11 @@
1
1
  import React from 'react';
2
2
  import type { IApplication } from '../common/types.js';
3
+ /**
4
+ * The application shell. It resolves the data, auth and i18n providers from `container`, mounts the
5
+ * `resources` and `routes` of the application and of each feature inside react-admin, and wraps it
6
+ * all in `ApplicationContext.Provider` (`container`, `logger`), the Redux provider and `Suspense`.
7
+ * While a feature's lazy messages for the current locale load, it renders `suspense` instead of
8
+ * react-admin; a failed load is thrown from render. Remaining props go to react-admin's `CoreAdmin`.
9
+ */
3
10
  export declare const ArdorApplication: React.FC<IApplication>;
4
11
  //# sourceMappingURL=application.d.ts.map
@@ -49,6 +49,13 @@ const useFeatureMessagesReady = (opts) => {
49
49
  }
50
50
  return state.isReady;
51
51
  };
52
+ /**
53
+ * The application shell. It resolves the data, auth and i18n providers from `container`, mounts the
54
+ * `resources` and `routes` of the application and of each feature inside react-admin, and wraps it
55
+ * all in `ApplicationContext.Provider` (`container`, `logger`), the Redux provider and `Suspense`.
56
+ * While a feature's lazy messages for the current locale load, it renders `suspense` instead of
57
+ * react-admin; a failed load is thrown from render. Remaining props go to react-admin's `CoreAdmin`.
58
+ */
52
59
  export const ArdorApplication = (props) => {
53
60
  const { container, reduxStore, suspense, logger, resources, routes, features: selected, ...reactAdminProps } = props;
54
61
  // The list the shell passed, else every feature the application bound.
@@ -1,6 +1,7 @@
1
1
  import type { Container } from '@venizia/ignis-inversion';
2
2
  import type { I18nProvider } from 'ra-core';
3
3
  import type { IAuthProvider, IDataProvider } from '../common/index.js';
4
+ /** Resolves the providers `ArdorApplication` hands to react-admin. */
4
5
  export declare class ApplicationProviders {
5
6
  /**
6
7
  * What `ArdorApplication` resolves from the container when it mounts: the one place, so a test of
@@ -1,4 +1,5 @@
1
1
  import { CoreBindings } from '@venizia/ardor-kernel';
2
+ /** Resolves the providers `ArdorApplication` hands to react-admin. */
2
3
  export class ApplicationProviders {
3
4
  /**
4
5
  * What `ArdorApplication` resolves from the container when it mounts: the one place, so a test of
@@ -15,6 +15,7 @@ export type TFeature<TExtension extends object = {}> = IFeatureBase & TExtension
15
15
  /** The application's own `i18nSources` override these. */
16
16
  messages?: TFeatureMessages;
17
17
  };
18
+ /** Defines, reads, mounts and loads the messages of the features an application binds. */
18
19
  export declare class Features {
19
20
  /** Types a feature, keeping the shell's extension. */
20
21
  static define<TExtension extends object = {}>(feature: TFeature<TExtension>): TFeature<TExtension>;
@@ -28,7 +29,9 @@ export declare class Features {
28
29
  */
29
30
  static mount(opts: {
30
31
  features: Array<TFeature>;
32
+ /** @default [] */
31
33
  resources?: Array<ResourceProps>;
34
+ /** @default [] */
32
35
  routes?: Array<RouteProps>;
33
36
  }): {
34
37
  resources: Array<ResourceProps>;
@@ -46,6 +49,7 @@ export declare class Features {
46
49
  static loadMessages(opts: {
47
50
  features: Array<TFeature>;
48
51
  i18nProvider: I18nProvider;
52
+ /** The locale to load. @default i18nProvider.getLocale() */
49
53
  locale?: string;
50
54
  }): Promise<void>;
51
55
  }
@@ -2,6 +2,7 @@ import { getError } from '@venizia/ignis-inversion';
2
2
  import { CoreBindings } from '@venizia/ardor-kernel';
3
3
  import { LazyLocales } from '../providers/i18n-sources.js';
4
4
  import { FeatureMessages } from './messages.js';
5
+ /** Defines, reads, mounts and loads the messages of the features an application binds. */
5
6
  export class Features {
6
7
  /** Types a feature, keeping the shell's extension. */
7
8
  static define(feature) {
@@ -1,8 +1,13 @@
1
1
  type TDocumentTitleSegment = string | false | null | undefined;
2
+ /** What `useDocumentTitle` writes into the tab title, and when. */
2
3
  export interface IUseDocumentTitleOptions {
4
+ /** The screen title, or a list of segments in order; `false`, `null`, `undefined` and empty segments are dropped. */
3
5
  title: TDocumentTitleSegment | Array<TDocumentTitleSegment>;
6
+ /** The last segment of the tab title. */
4
7
  appTitle: string;
8
+ /** Joins the segments. @default ' · ' */
5
9
  separator?: string;
10
+ /** When `false` the call writes no title. @default true */
6
11
  enabled?: boolean;
7
12
  /**
8
13
  * A base title for a layout. It shows only while no other call is mounted, so a screen's title
@@ -1,5 +1,9 @@
1
1
  import type { ApplicationError } from '@venizia/ignis-inversion';
2
2
  import type { NotificationOptions, NotificationType } from 'ra-core';
3
+ /**
4
+ * Returns a stable function that shows an error notification for an `ApplicationError`: the message
5
+ * is its normalized `code`, with its normalized `args` as message arguments. `options` override both.
6
+ */
3
7
  export declare const useNotifyError: () => (error: ApplicationError, options?: NotificationOptions & {
4
8
  type?: NotificationType;
5
9
  }) => void;
@@ -1,5 +1,9 @@
1
1
  import React from 'react';
2
2
  import { useNotify } from 'ra-core';
3
+ /**
4
+ * Returns a stable function that shows an error notification for an `ApplicationError`: the message
5
+ * is its normalized `code`, with its normalized `args` as message arguments. `options` override both.
6
+ */
3
7
  export const useNotifyError = () => {
4
8
  const notify = useNotify();
5
9
  return React.useCallback((error, options) => {
@@ -1,3 +1,7 @@
1
+ /**
2
+ * Returns a function that refreshes the session through the auth provider's `refreshToken` and, once
3
+ * that resolves, invalidates the cached permissions. It rejects when `refreshToken` rejects.
4
+ */
1
5
  export declare const useRefreshToken: () => TRefreshToken;
2
6
  /** `true` when the session was refreshed, `false` when there is no auth provider or no refresh to make. */
3
7
  type TRefreshToken = () => Promise<boolean>;
@@ -3,6 +3,10 @@ import { useQueryClient } from '@tanstack/react-query';
3
3
  import { useAuthProvider } from 'ra-core';
4
4
  import { LoggerFactory } from '@venizia/ignis-helpers/core';
5
5
  const logger = LoggerFactory.getLogger(['useRefreshToken']);
6
+ /**
7
+ * Returns a function that refreshes the session through the auth provider's `refreshToken` and, once
8
+ * that resolves, invalidates the cached permissions. It rejects when `refreshToken` rejects.
9
+ */
6
10
  export const useRefreshToken = () => {
7
11
  const authProvider = useAuthProvider();
8
12
  const queryClient = useQueryClient();
@@ -1,6 +1,14 @@
1
+ /** The header `useRequestHeaderLocale` sends the locale in. */
1
2
  export interface IUseRequestHeaderLocaleOptions {
2
- /** The header the locale is sent in. Default `x-locale`. */
3
+ /**
4
+ * The header the locale is sent in.
5
+ * @default 'x-locale'
6
+ */
3
7
  key?: string;
4
8
  }
9
+ /**
10
+ * Keeps the current react-admin locale in a header of the default REST data provider's network
11
+ * service, re-set on each locale change. `opts.key` defaults to `x-locale`; an empty key falls back to it.
12
+ */
5
13
  export declare const useRequestHeaderLocale: (opts?: IUseRequestHeaderLocaleOptions) => void;
6
14
  //# sourceMappingURL=use-request-header-locale.d.ts.map
@@ -2,6 +2,10 @@ import React from 'react';
2
2
  import { useLocaleState } from 'ra-core';
3
3
  import { CoreBindings, HeaderConstants } from '@venizia/ardor-kernel';
4
4
  import { useInjectable } from '@venizia/ardor-react';
5
+ /**
6
+ * Keeps the current react-admin locale in a header of the default REST data provider's network
7
+ * service, re-set on each locale change. `opts.key` defaults to `x-locale`; an empty key falls back to it.
8
+ */
5
9
  export const useRequestHeaderLocale = (opts) => {
6
10
  const key = opts?.key?.length ? opts.key : HeaderConstants.X_LOCALE;
7
11
  const [locale] = useLocaleState();
@@ -1,13 +1,28 @@
1
1
  import { type I18nProvider, type TranslateFunction } from 'ra-core';
2
2
  import type { TFullPaths } from '@venizia/ardor-kernel';
3
3
  import type { englishMessages } from '../common/locales/index.js';
4
+ /**
5
+ * Augment this interface to add keys to `TUseTranslateKeys` (messages an app adds to the defaults):
6
+ *
7
+ * ```ts
8
+ * declare module '@venizia/ardor' {
9
+ * interface IUseTranslateKeysOverrides {
10
+ * 'app.orders.title': unknown;
11
+ * }
12
+ * }
13
+ * ```
14
+ */
4
15
  export interface IUseTranslateKeysOverrides {
5
16
  }
17
+ /** Every dotted path to a message in the built-in English messages. */
6
18
  export type TUseTranslateKeysDefault = TFullPaths<typeof englishMessages>;
19
+ /** The keys `useTranslate` accepts: the built-in message paths plus the keys added through `IUseTranslateKeysOverrides`. */
7
20
  export type TUseTranslateKeys = TUseTranslateKeysDefault | keyof IUseTranslateKeysOverrides;
8
21
  /** The options react-admin's `translate` takes (`smart_count`, `_` for a default text, ...). */
9
22
  export type TUseTranslateOptions = Parameters<I18nProvider['translate']>[1];
23
+ /** `translate` with the key narrowed to `TUseTranslateKeys`. */
10
24
  export type TUseTranslateFn = (key: TUseTranslateKeys, options?: TUseTranslateOptions) => string;
25
+ /** `translate` as react-admin types it, taking any string key. */
11
26
  export type TUseUntypedTranslateFn = TranslateFunction;
12
27
  /** For a key that exists only at run time (`errors.${code}`); a key written in code belongs to `useTranslate`. */
13
28
  export declare const useUntypedTranslate: () => TUseUntypedTranslateFn;
@@ -18,6 +18,7 @@ export declare class SessionClearReasons {
18
18
  /** `checkAuth` rejected: no token is stored, or the server answered with no data. */
19
19
  static readonly REJECTED = "rejected";
20
20
  }
21
+ /** One of the `SessionClearReasons` values. */
21
22
  export type TSessionClearReason = TStringConstValue<typeof SessionClearReasons>;
22
23
  /**
23
24
  * The options hold data (`paths`); behaviour is in the protected hooks around `login` and the page
@@ -28,6 +29,27 @@ export type TSessionClearReason = TStringConstValue<typeof SessionClearReasons>;
28
29
  * hook that throws, or does not settle in `sessionHookTimeout`, is logged and does not stop the call
29
30
  * that fired it. A hook does not call this provider's methods: they wait behind it. Build one provider
30
31
  * per auth service: a second one listening to the same service calls every hook again.
32
+ *
33
+ * @example
34
+ * ```ts
35
+ * import { type BaseArdorApplication, configuration, CoreBindings, DefaultAuthProvider, inject, provide } from '@venizia/ardor';
36
+ *
37
+ * class AppAuthProvider extends DefaultAuthProvider {
38
+ * protected override get afterLoginPath() {
39
+ * return '/products';
40
+ * }
41
+ * }
42
+ *
43
+ * @configuration()
44
+ * export class AuthConfiguration {
45
+ * constructor(@inject({ key: CoreBindings.APPLICATION_INSTANCE }) private readonly application: BaseArdorApplication) {}
46
+ *
47
+ * @provide({ key: CoreBindings.DEFAULT_AUTH_PROVIDER })
48
+ * authProvider() {
49
+ * return this.application.instantiate(AppAuthProvider).value(this.application);
50
+ * }
51
+ * }
52
+ * ```
31
53
  */
32
54
  export declare class DefaultAuthProvider<TResource extends string = string> extends BaseProvider<IAuthProvider> {
33
55
  protected restDataProvider: IDataProvider<TResource>;
@@ -149,18 +171,50 @@ export declare class DefaultAuthProvider<TResource extends string = string> exte
149
171
  private clearSession;
150
172
  /** Announces the session in the store, when there is one. */
151
173
  private startStoredSession;
152
- /** Typed `Promise<unknown>` so that a subclass override of `login` keeps compiling. */
174
+ /**
175
+ * Posts the sign-in body to `signInPath`, stores the session and resolves `{ ...response,
176
+ * redirectTo }`, where `redirectTo` is `afterLoginPath`. Rejects when the request fails, when the
177
+ * response carries no token or user id, or when `beforeSaveSession` throws; no session is stored
178
+ * then. Typed `Promise<unknown>` so that a subclass override of `login` keeps compiling.
179
+ */
153
180
  login(params: ILoginParams): Promise<unknown>;
181
+ /** Clears the session and resolves. */
154
182
  logout(_params?: unknown): Promise<void>;
183
+ /**
184
+ * Resolves when a token is stored and, if `paths.checkAuth` is set, the server answers with data.
185
+ * Otherwise it ends the session (reason `rejected`) and rejects with `unauthenticatedRejection`;
186
+ * it rejects with the request's error when the check request fails.
187
+ */
155
188
  checkAuth(_params?: unknown): Promise<void>;
189
+ /**
190
+ * Resolves for every error but 401 and 403. A 401 clears the session (unless
191
+ * `unauthenticatedRejection` says `logoutUser: false`) and rejects with that rejection; a 403
192
+ * rejects with `{ redirectTo: unauthorizedPagePath, logoutUser: false }`.
193
+ */
156
194
  checkError(error: unknown): Promise<void>;
195
+ /** Resolves the stored user; rejects when there is no `userId`. */
157
196
  getIdentity(_params?: unknown): Promise<any>;
197
+ /** Resolves with nothing; the roles come from `getRoles`. */
158
198
  getPermissions(_params?: unknown): Promise<void>;
199
+ /** Resolves the roles of the stored session. */
159
200
  getRoles(_params?: unknown): Promise<Set<string>>;
160
201
  /**
161
202
  * Refreshes the session through the network service's `refresh`, the one place a refresh is made:
162
203
  * `true` when it was refreshed, `false` when the service has no refresh to make. The `401`
163
204
  * recovery calls the same method, so one burst of 401s and this call share one refresh.
205
+ *
206
+ * @example
207
+ * ```tsx
208
+ * import { useRefreshToken } from '@venizia/ardor';
209
+ *
210
+ * // The data provider options name the refresh endpoint:
211
+ * // { url: '/api', authRecovery: { refreshTokenPath: '/auth/refresh-token' } }
212
+ * export const RefreshButton = () => {
213
+ * const refreshToken = useRefreshToken();
214
+ *
215
+ * return <button onClick={() => refreshToken()}>Refresh</button>;
216
+ * };
217
+ * ```
164
218
  */
165
219
  refreshToken(): Promise<boolean>;
166
220
  value(container: Container): IAuthProvider;
@@ -42,6 +42,27 @@ const readStatus = (error) => {
42
42
  * hook that throws, or does not settle in `sessionHookTimeout`, is logged and does not stop the call
43
43
  * that fired it. A hook does not call this provider's methods: they wait behind it. Build one provider
44
44
  * per auth service: a second one listening to the same service calls every hook again.
45
+ *
46
+ * @example
47
+ * ```ts
48
+ * import { type BaseArdorApplication, configuration, CoreBindings, DefaultAuthProvider, inject, provide } from '@venizia/ardor';
49
+ *
50
+ * class AppAuthProvider extends DefaultAuthProvider {
51
+ * protected override get afterLoginPath() {
52
+ * return '/products';
53
+ * }
54
+ * }
55
+ *
56
+ * @configuration()
57
+ * export class AuthConfiguration {
58
+ * constructor(@inject({ key: CoreBindings.APPLICATION_INSTANCE }) private readonly application: BaseArdorApplication) {}
59
+ *
60
+ * @provide({ key: CoreBindings.DEFAULT_AUTH_PROVIDER })
61
+ * authProvider() {
62
+ * return this.application.instantiate(AppAuthProvider).value(this.application);
63
+ * }
64
+ * }
65
+ * ```
45
66
  */
46
67
  let DefaultAuthProvider = DefaultAuthProvider_1 = class DefaultAuthProvider extends BaseProvider {
47
68
  constructor(restDataProvider, authProviderOptions, authService, permissionProvider) {
@@ -295,7 +316,12 @@ let DefaultAuthProvider = DefaultAuthProvider_1 = class DefaultAuthProvider exte
295
316
  return this.startSession({ token, user: this.authService.getUser() });
296
317
  }
297
318
  // --- react-admin's auth provider -------------------------------------------------------------
298
- /** Typed `Promise<unknown>` so that a subclass override of `login` keeps compiling. */
319
+ /**
320
+ * Posts the sign-in body to `signInPath`, stores the session and resolves `{ ...response,
321
+ * redirectTo }`, where `redirectTo` is `afterLoginPath`. Rejects when the request fails, when the
322
+ * response carries no token or user id, or when `beforeSaveSession` throws; no session is stored
323
+ * then. Typed `Promise<unknown>` so that a subclass override of `login` keeps compiling.
324
+ */
299
325
  async login(params) {
300
326
  const response = await this.restDataProvider.send({
301
327
  resource: this.signInPath,
@@ -316,9 +342,15 @@ let DefaultAuthProvider = DefaultAuthProvider_1 = class DefaultAuthProvider exte
316
342
  redirectTo: removeDoubleSlashes(`/${this.afterLoginPath}`),
317
343
  };
318
344
  }
345
+ /** Clears the session and resolves. */
319
346
  async logout(_params) {
320
347
  await this.clearSession({ reason: SessionClearReasons.LOGOUT });
321
348
  }
349
+ /**
350
+ * Resolves when a token is stored and, if `paths.checkAuth` is set, the server answers with data.
351
+ * Otherwise it ends the session (reason `rejected`) and rejects with `unauthenticatedRejection`;
352
+ * it rejects with the request's error when the check request fails.
353
+ */
322
354
  async checkAuth(_params) {
323
355
  const token = this.authService.getAuth();
324
356
  if (!token?.value) {
@@ -344,6 +376,11 @@ let DefaultAuthProvider = DefaultAuthProvider_1 = class DefaultAuthProvider exte
344
376
  await this.startStoredSession();
345
377
  return Promise.resolve();
346
378
  }
379
+ /**
380
+ * Resolves for every error but 401 and 403. A 401 clears the session (unless
381
+ * `unauthenticatedRejection` says `logoutUser: false`) and rejects with that rejection; a 403
382
+ * rejects with `{ redirectTo: unauthorizedPagePath, logoutUser: false }`.
383
+ */
347
384
  async checkError(error) {
348
385
  const status = readStatus(error);
349
386
  if (status === 401) {
@@ -361,6 +398,7 @@ let DefaultAuthProvider = DefaultAuthProvider_1 = class DefaultAuthProvider exte
361
398
  }
362
399
  return Promise.resolve();
363
400
  }
401
+ /** Resolves the stored user; rejects when there is no `userId`. */
364
402
  getIdentity(_params) {
365
403
  const user = this.authService.getUser();
366
404
  if (!user?.userId) {
@@ -368,9 +406,11 @@ let DefaultAuthProvider = DefaultAuthProvider_1 = class DefaultAuthProvider exte
368
406
  }
369
407
  return Promise.resolve(user);
370
408
  }
409
+ /** Resolves with nothing; the roles come from `getRoles`. */
371
410
  getPermissions(_params) {
372
411
  return Promise.resolve();
373
412
  }
413
+ /** Resolves the roles of the stored session. */
374
414
  getRoles(_params) {
375
415
  return Promise.resolve(this.authService.getRoles());
376
416
  }
@@ -378,6 +418,19 @@ let DefaultAuthProvider = DefaultAuthProvider_1 = class DefaultAuthProvider exte
378
418
  * Refreshes the session through the network service's `refresh`, the one place a refresh is made:
379
419
  * `true` when it was refreshed, `false` when the service has no refresh to make. The `401`
380
420
  * recovery calls the same method, so one burst of 401s and this call share one refresh.
421
+ *
422
+ * @example
423
+ * ```tsx
424
+ * import { useRefreshToken } from '@venizia/ardor';
425
+ *
426
+ * // The data provider options name the refresh endpoint:
427
+ * // { url: '/api', authRecovery: { refreshTokenPath: '/auth/refresh-token' } }
428
+ * export const RefreshButton = () => {
429
+ * const refreshToken = useRefreshToken();
430
+ *
431
+ * return <button onClick={() => refreshToken()}>Refresh</button>;
432
+ * };
433
+ * ```
381
434
  */
382
435
  async refreshToken() {
383
436
  const isRefreshed = await this.restDataProvider.getNetworkService().refresh();
@@ -3,7 +3,15 @@ import { type TRequestType } from '@venizia/ardor-kernel';
3
3
  import type { TExtraRequest } from '@venizia/ignis-kernel/repository';
4
4
  import type { IListFilter } from './list-filter.js';
5
5
  import { DefaultRestDataProvider } from './rest-data.js';
6
+ /**
7
+ * A `DefaultRestDataProvider` whose list reads take their `total` from the count route
8
+ * (`GET /{resource}/count` with the same `where`) instead of the `Content-Range` header.
9
+ */
6
10
  export declare class CountRestDataProvider<TResource extends string = string> extends DefaultRestDataProvider<TResource> {
11
+ /**
12
+ * Sends the list GET and the count GET together; `total` is the count's `count`, or `0` when the
13
+ * count answers none. Rejects when either request rejects.
14
+ */
7
15
  protected requestList<RecordType extends RaRecord = RaRecord>(opts: {
8
16
  resource: TResource;
9
17
  type: TRequestType;
@@ -1,6 +1,14 @@
1
1
  import { RequestMethods, RequestTypes } from '@venizia/ardor-kernel';
2
2
  import { DefaultRestDataProvider } from './rest-data.js';
3
+ /**
4
+ * A `DefaultRestDataProvider` whose list reads take their `total` from the count route
5
+ * (`GET /{resource}/count` with the same `where`) instead of the `Content-Range` header.
6
+ */
3
7
  export class CountRestDataProvider extends DefaultRestDataProvider {
8
+ /**
9
+ * Sends the list GET and the count GET together; `total` is the count's `count`, or `0` when the
10
+ * count answers none. Rejects when either request rejects.
11
+ */
4
12
  requestList(opts) {
5
13
  const { resource, queryKey, filter } = opts;
6
14
  // The base class reads the rows and keeps the route's list extras as `meta.extra`.
@@ -7,6 +7,26 @@ import { LocaleSources } from './i18n-sources.js';
7
7
  /**
8
8
  * The options hold data (`i18nSources`, `languages`); the hooks are `resolveInitialLocale` and
9
9
  * `composeMessages`, each taking one `opts` object.
10
+ *
11
+ * @example
12
+ * ```ts
13
+ * import { configuration, CoreBindings, englishMessages, provide, vietnameseMessages } from '@venizia/ardor';
14
+ *
15
+ * @configuration()
16
+ * export class I18nConfiguration {
17
+ * @provide({ key: CoreBindings.I18N_PROVIDER_OPTIONS })
18
+ * options() {
19
+ * return {
20
+ * languages: [{ locale: 'en', name: 'English' }, { locale: 'vi', name: 'Tieng Viet' }],
21
+ * i18nSources: {
22
+ * en: englishMessages,
23
+ * // A loader runs the first time the locale is used, such as () => import('./vi').
24
+ * vi: async () => vietnameseMessages,
25
+ * },
26
+ * };
27
+ * }
28
+ * }
29
+ * ```
10
30
  */
11
31
  export declare class DefaultI18nProvider extends BaseProvider<I18nProvider> {
12
32
  protected i18nProviderOptions: II18nProviderOptions;
@@ -15,8 +35,8 @@ export declare class DefaultI18nProvider extends BaseProvider<I18nProvider> {
15
35
  constructor(i18nProviderOptions: II18nProviderOptions, features?: Array<TFeature>);
16
36
  /**
17
37
  * The locale the admin starts in: the browser's language when it is one of `locales`, else `en`.
18
- * Read when the provider is built, not when the module is imported, and not at all outside a
19
- * browser.
38
+ * Read when the provider is built, not when the module is imported. Without a `navigator` the
39
+ * language is `en-US`.
20
40
  */
21
41
  protected resolveInitialLocale(opts: {
22
42
  locales: Array<string>;
@@ -21,6 +21,26 @@ import { LazyLocales, LocaleSources } from './i18n-sources.js';
21
21
  /**
22
22
  * The options hold data (`i18nSources`, `languages`); the hooks are `resolveInitialLocale` and
23
23
  * `composeMessages`, each taking one `opts` object.
24
+ *
25
+ * @example
26
+ * ```ts
27
+ * import { configuration, CoreBindings, englishMessages, provide, vietnameseMessages } from '@venizia/ardor';
28
+ *
29
+ * @configuration()
30
+ * export class I18nConfiguration {
31
+ * @provide({ key: CoreBindings.I18N_PROVIDER_OPTIONS })
32
+ * options() {
33
+ * return {
34
+ * languages: [{ locale: 'en', name: 'English' }, { locale: 'vi', name: 'Tieng Viet' }],
35
+ * i18nSources: {
36
+ * en: englishMessages,
37
+ * // A loader runs the first time the locale is used, such as () => import('./vi').
38
+ * vi: async () => vietnameseMessages,
39
+ * },
40
+ * };
41
+ * }
42
+ * }
43
+ * ```
24
44
  */
25
45
  let DefaultI18nProvider = DefaultI18nProvider_1 = class DefaultI18nProvider extends BaseProvider {
26
46
  constructor(i18nProviderOptions, features = []) {
@@ -34,8 +54,8 @@ let DefaultI18nProvider = DefaultI18nProvider_1 = class DefaultI18nProvider exte
34
54
  }
35
55
  /**
36
56
  * The locale the admin starts in: the browser's language when it is one of `locales`, else `en`.
37
- * Read when the provider is built, not when the module is imported, and not at all outside a
38
- * browser.
57
+ * Read when the provider is built, not when the module is imported. Without a `navigator` the
58
+ * language is `en-US`.
39
59
  */
40
60
  resolveInitialLocale(opts) {
41
61
  const browserLanguage = typeof navigator === 'undefined' ? undefined : navigator.language;
@@ -4,16 +4,20 @@ import { type ICustomParams } from '@venizia/ardor-kernel';
4
4
  /** The IGNIS filter a list request sends. Any other key of the list params is a filter key too. */
5
5
  export interface IListFilter {
6
6
  where: Record<string, unknown>;
7
+ /** Each entry is `'<field> <ASC|DESC>'`. */
7
8
  order?: Array<string>;
8
9
  limit?: number;
10
+ /** IGNIS's offset; `ListFilterBuilder.build` sets this one. */
9
11
  skip?: number;
10
- offset?: number;
11
12
  include?: unknown;
12
13
  fields?: unknown;
14
+ /** Not part of the filter sent: `ListFilterBuilder.build` moves it into the query string. */
13
15
  params?: Record<string, unknown>;
16
+ /** Lifts `limit` and `skip`: the list is not paginated. */
14
17
  noLimit?: boolean;
15
18
  [key: string]: unknown;
16
19
  }
20
+ /** Builds the filter, query and extras of a list request from react-admin's list params. */
17
21
  export declare class ListFilterBuilder {
18
22
  /** `filter.params` as the keys of the query string, as a copy. */
19
23
  static extractQueryParams(opts: {
@@ -1,4 +1,5 @@
1
1
  import { ValueUtility } from '@venizia/ardor-kernel';
2
+ /** Builds the filter, query and extras of a list request from react-admin's list params. */
2
3
  export class ListFilterBuilder {
3
4
  /** `filter.params` as the keys of the query string, as a copy. */
4
5
  static extractQueryParams(opts) {
@@ -36,7 +37,7 @@ export class ListFilterBuilder {
36
37
  }
37
38
  else {
38
39
  const { page = 1, perPage = 0 } = pagination ?? {};
39
- // No `perPage` is no limit. `skip` is IGNIS's offset (`offset` is its alias): one is enough.
40
+ // No `perPage` is no limit. `skip` is IGNIS's offset.
40
41
  if (perPage > 0) {
41
42
  filter['limit'] = perPage;
42
43
  filter['skip'] = (Math.max(page, 1) - 1) * perPage;
@@ -1,9 +1,36 @@
1
1
  import { type Container } from '@venizia/ignis-inversion';
2
2
  import type { CreateParams, CreateResult, DeleteManyParams, DeleteManyResult, DeleteParams, DeleteResult, GetListParams, GetListResult, GetManyParams, GetManyReferenceParams, GetManyReferenceResult, GetManyResult, GetOneParams, GetOneResult, Identifier, QueryFunctionContext, RaRecord, UpdateManyParams, UpdateManyResult, UpdateParams, UpdateResult } from 'ra-core';
3
- import { BaseProvider, DefaultNetworkRequestService, type IApplicationInfo, type INetworkResponse, type ICustomParams, type IRestDataProviderOptions, type ISendParams, type ISendResponse, type TRequestType } from '@venizia/ardor-kernel';
3
+ import { BaseProvider, DefaultNetworkRequestService, type IApplicationInfo, type INetworkResponse, type ICustomParams, type IRestDataProviderOptions, type ISendParams, type TRequestType } from '@venizia/ardor-kernel';
4
4
  import type { TExtraRequest } from '@venizia/ignis-kernel/repository';
5
5
  import type { IDataProvider, IRestRequestOptions } from '../common/index.js';
6
6
  import { type IListFilter } from './list-filter.js';
7
+ /**
8
+ * The react-admin data provider over an IGNIS REST API. Each method takes one `opts` object
9
+ * (`{ resource, params }`) and resolves the result react-admin expects; it rejects with the error
10
+ * the network service throws (a non-2xx response, an empty base URL, an auth failure that cannot be
11
+ * recovered). A subclass overrides the protected hooks (`createNetworkService`, `buildListFilter`,
12
+ * `requestList`).
13
+ *
14
+ * @example
15
+ * ```ts
16
+ * import { type BaseArdorApplication, configuration, CoreBindings, DefaultRestDataProvider, inject, provide } from '@venizia/ardor';
17
+ *
18
+ * @configuration()
19
+ * export class DataConfiguration {
20
+ * constructor(@inject({ key: CoreBindings.APPLICATION_INSTANCE }) private readonly application: BaseArdorApplication) {}
21
+ *
22
+ * @provide({ key: CoreBindings.REST_DATA_PROVIDER_OPTIONS })
23
+ * options() {
24
+ * return { url: '/api', noAuthPaths: ['/auth/sign-in'] };
25
+ * }
26
+ *
27
+ * @provide({ key: CoreBindings.DEFAULT_REST_DATA_PROVIDER })
28
+ * dataProvider() {
29
+ * return this.application.instantiate(DefaultRestDataProvider).value(this.application);
30
+ * }
31
+ * }
32
+ * ```
33
+ */
7
34
  export declare class DefaultRestDataProvider<TResource extends string = string> extends BaseProvider<IDataProvider<TResource>> {
8
35
  protected restDataProviderOptions: IRestDataProviderOptions;
9
36
  protected applicationInfo: IApplicationInfo;
@@ -17,6 +44,7 @@ export declare class DefaultRestDataProvider<TResource extends string = string>
17
44
  */
18
45
  protected createNetworkService(): DefaultNetworkRequestService;
19
46
  protected get networkService(): DefaultNetworkRequestService;
47
+ /** The network service every request of this provider goes through; built on first use. */
20
48
  getNetworkService(): DefaultNetworkRequestService;
21
49
  /**
22
50
  * The ids a bulk write touched, read from the affected rows the server answers (not the ids asked
@@ -70,48 +98,81 @@ export declare class DefaultRestDataProvider<TResource extends string = string>
70
98
  filename?: string;
71
99
  contentDisposition?: string;
72
100
  }>;
101
+ /**
102
+ * `GET /{resource}` with the filter built from the list params in the query. Resolves the rows and
103
+ * `total` (the `Content-Range` total, else the page's row count), plus `meta.extra` when a route
104
+ * answered extras.
105
+ */
73
106
  getList<RecordType extends RaRecord = RaRecord>(opts: {
74
107
  resource: TResource;
75
108
  params: GetListParams & QueryFunctionContext & ICustomParams;
76
109
  }): Promise<GetListResult<RecordType>>;
110
+ /**
111
+ * `GET /{resource}/{id}`, with `params.meta.filter` as the query filter. Resolves `{ data }`.
112
+ */
77
113
  getOne<RecordType extends RaRecord = RaRecord>(opts: {
78
114
  resource: TResource;
79
115
  params: GetOneParams<RecordType> & QueryFunctionContext & ICustomParams;
80
116
  }): Promise<GetOneResult<RecordType>>;
117
+ /**
118
+ * `GET /{resource}` with the ids in `filter.where.id.inq`, merged into `params.meta.filter`.
119
+ * Resolves `{ data }`.
120
+ */
81
121
  getMany<RecordType extends RaRecord = RaRecord>(opts: {
82
122
  resource: TResource;
83
123
  params: GetManyParams<RecordType> & QueryFunctionContext & ICustomParams;
84
124
  }): Promise<GetManyResult<RecordType>>;
125
+ /**
126
+ * As `getList`, with `filter.where[target] = id`. Resolves the rows and `total`.
127
+ */
85
128
  getManyReference<RecordType extends RaRecord = RaRecord>(opts: {
86
129
  resource: TResource;
87
130
  params: GetManyReferenceParams & QueryFunctionContext & ICustomParams;
88
131
  }): Promise<GetManyReferenceResult<RecordType>>;
132
+ /** `PATCH /{resource}/{id}` with `params.data` as the body. Resolves `{ data }`. */
89
133
  update<RecordType extends RaRecord = RaRecord>(opts: {
90
134
  resource: TResource;
91
135
  params: UpdateParams;
92
136
  }): Promise<UpdateResult<RecordType>>;
137
+ /**
138
+ * `PATCH /{resource}` with `{ ...params.data, where: { id: { inq: ids } } }` as the body. Resolves
139
+ * `{ data }`, the ids of the rows the server answered (`undefined` when the answer is not a row
140
+ * array). Rejects when `ids` is empty or `params.data` has a `where` field, before any request.
141
+ */
93
142
  updateMany<RecordType extends RaRecord = RaRecord>(opts: {
94
143
  resource: TResource;
95
144
  params: UpdateManyParams;
96
145
  }): Promise<UpdateManyResult<RecordType>>;
146
+ /** `POST /{resource}` with `params.data` as the body. Resolves `{ data }`, the created record. */
97
147
  create<RecordType extends Omit<RaRecord, 'id'> = Omit<RaRecord, 'id'>, ResultRecordType extends RaRecord = RecordType & {
98
148
  id: Identifier;
99
149
  }>(opts: {
100
150
  resource: TResource;
101
151
  params: CreateParams;
102
152
  }): Promise<CreateResult<ResultRecordType>>;
153
+ /** `DELETE /{resource}/{id}`. Resolves `{ data }`, the record the server answered. */
103
154
  delete<RecordType extends RaRecord = RaRecord>(opts: {
104
155
  resource: TResource;
105
156
  params: DeleteParams<RecordType>;
106
157
  }): Promise<DeleteResult<RecordType>>;
158
+ /**
159
+ * `DELETE /{resource}` with `{ where: { id: { inq: ids } } }` as the body. Resolves `{ data }`, the
160
+ * ids of the rows the server answered (`undefined` when the answer is not a row array). Rejects
161
+ * when `ids` is empty, before any request.
162
+ */
107
163
  deleteMany<RecordType extends RaRecord = RaRecord>(opts: {
108
164
  resource: TResource;
109
165
  params: DeleteManyParams<RecordType>;
110
166
  }): Promise<DeleteManyResult<RecordType>>;
167
+ /**
168
+ * Sends `params.method` to `/{resource}` with the provider's headers and auth; `requestType`
169
+ * defaults to `RequestTypes.SEND`. Resolves the response read by that type. Rejects when
170
+ * `params.method` is missing, before any request.
171
+ */
111
172
  send<TResult = unknown>(opts: {
112
173
  resource: TResource;
113
174
  params: ISendParams;
114
- }): Promise<ISendResponse<TResult>>;
175
+ }): Promise<INetworkResponse<TResult>>;
115
176
  /**
116
177
  * react-admin's data provider contract takes positional arguments, `(resource, params)`: the one
117
178
  * place this class does not take an `opts` object. Each method hands them to the `opts` method.
@@ -14,6 +14,33 @@ var DefaultRestDataProvider_1;
14
14
  import { getError, inject } from '@venizia/ignis-inversion';
15
15
  import { BaseProvider, CoreBindings, DefaultNetworkRequestService, ValueUtility, NetworkHeaders, RequestCountData, RequestMethods, RequestTypes, } from '@venizia/ardor-kernel';
16
16
  import { ListFilterBuilder } from './list-filter.js';
17
+ /**
18
+ * The react-admin data provider over an IGNIS REST API. Each method takes one `opts` object
19
+ * (`{ resource, params }`) and resolves the result react-admin expects; it rejects with the error
20
+ * the network service throws (a non-2xx response, an empty base URL, an auth failure that cannot be
21
+ * recovered). A subclass overrides the protected hooks (`createNetworkService`, `buildListFilter`,
22
+ * `requestList`).
23
+ *
24
+ * @example
25
+ * ```ts
26
+ * import { type BaseArdorApplication, configuration, CoreBindings, DefaultRestDataProvider, inject, provide } from '@venizia/ardor';
27
+ *
28
+ * @configuration()
29
+ * export class DataConfiguration {
30
+ * constructor(@inject({ key: CoreBindings.APPLICATION_INSTANCE }) private readonly application: BaseArdorApplication) {}
31
+ *
32
+ * @provide({ key: CoreBindings.REST_DATA_PROVIDER_OPTIONS })
33
+ * options() {
34
+ * return { url: '/api', noAuthPaths: ['/auth/sign-in'] };
35
+ * }
36
+ *
37
+ * @provide({ key: CoreBindings.DEFAULT_REST_DATA_PROVIDER })
38
+ * dataProvider() {
39
+ * return this.application.instantiate(DefaultRestDataProvider).value(this.application);
40
+ * }
41
+ * }
42
+ * ```
43
+ */
17
44
  let DefaultRestDataProvider = DefaultRestDataProvider_1 = class DefaultRestDataProvider extends BaseProvider {
18
45
  constructor(restDataProviderOptions, applicationInfo) {
19
46
  super({ scope: DefaultRestDataProvider_1.name });
@@ -40,6 +67,7 @@ let DefaultRestDataProvider = DefaultRestDataProvider_1 = class DefaultRestDataP
40
67
  this.cachedNetworkService ??= this.createNetworkService();
41
68
  return this.cachedNetworkService;
42
69
  }
70
+ /** The network service every request of this provider goes through; built on first use. */
43
71
  getNetworkService() {
44
72
  return this.networkService;
45
73
  }
@@ -112,6 +140,11 @@ let DefaultRestDataProvider = DefaultRestDataProvider_1 = class DefaultRestDataP
112
140
  return answered ? { ...rest, meta: { extra: answered } } : rest;
113
141
  });
114
142
  }
143
+ /**
144
+ * `GET /{resource}` with the filter built from the list params in the query. Resolves the rows and
145
+ * `total` (the `Content-Range` total, else the page's row count), plus `meta.extra` when a route
146
+ * answered extras.
147
+ */
115
148
  async getList(opts) {
116
149
  const { resource, params } = opts;
117
150
  const { filter, queryKey, extra } = this.buildListFilter({ params });
@@ -123,6 +156,9 @@ let DefaultRestDataProvider = DefaultRestDataProvider_1 = class DefaultRestDataP
123
156
  extra,
124
157
  });
125
158
  }
159
+ /**
160
+ * `GET /{resource}/{id}`, with `params.meta.filter` as the query filter. Resolves `{ data }`.
161
+ */
126
162
  async getOne(opts) {
127
163
  const { resource, params } = opts;
128
164
  const { params: filterParams, ...filter } = params?.meta?.filter ?? {};
@@ -135,6 +171,10 @@ let DefaultRestDataProvider = DefaultRestDataProvider_1 = class DefaultRestDataP
135
171
  query: { ...queryKey, filter },
136
172
  });
137
173
  }
174
+ /**
175
+ * `GET /{resource}` with the ids in `filter.where.id.inq`, merged into `params.meta.filter`.
176
+ * Resolves `{ data }`.
177
+ */
138
178
  async getMany(opts) {
139
179
  const { resource, params } = opts;
140
180
  const { params: filterParams, ...filter } = params?.meta?.filter ?? {};
@@ -154,6 +194,9 @@ let DefaultRestDataProvider = DefaultRestDataProvider_1 = class DefaultRestDataP
154
194
  },
155
195
  });
156
196
  }
197
+ /**
198
+ * As `getList`, with `filter.where[target] = id`. Resolves the rows and `total`.
199
+ */
157
200
  async getManyReference(opts) {
158
201
  const { resource, params } = opts;
159
202
  const { target, id, ...listParams } = params;
@@ -167,6 +210,7 @@ let DefaultRestDataProvider = DefaultRestDataProvider_1 = class DefaultRestDataP
167
210
  extra,
168
211
  });
169
212
  }
213
+ /** `PATCH /{resource}/{id}` with `params.data` as the body. Resolves `{ data }`. */
170
214
  async update(opts) {
171
215
  const { resource, params } = opts;
172
216
  return this.request({
@@ -177,6 +221,11 @@ let DefaultRestDataProvider = DefaultRestDataProvider_1 = class DefaultRestDataP
177
221
  body: params.data,
178
222
  });
179
223
  }
224
+ /**
225
+ * `PATCH /{resource}` with `{ ...params.data, where: { id: { inq: ids } } }` as the body. Resolves
226
+ * `{ data }`, the ids of the rows the server answered (`undefined` when the answer is not a row
227
+ * array). Rejects when `ids` is empty or `params.data` has a `where` field, before any request.
228
+ */
180
229
  async updateMany(opts) {
181
230
  const { resource, params } = opts;
182
231
  const { ids, data } = params;
@@ -199,6 +248,7 @@ let DefaultRestDataProvider = DefaultRestDataProvider_1 = class DefaultRestDataP
199
248
  return { data: this.toAffectedIds({ rows: result.data }) };
200
249
  });
201
250
  }
251
+ /** `POST /{resource}` with `params.data` as the body. Resolves `{ data }`, the created record. */
202
252
  async create(opts) {
203
253
  const { resource, params } = opts;
204
254
  return this.request({
@@ -208,6 +258,7 @@ let DefaultRestDataProvider = DefaultRestDataProvider_1 = class DefaultRestDataP
208
258
  body: params.data,
209
259
  });
210
260
  }
261
+ /** `DELETE /{resource}/{id}`. Resolves `{ data }`, the record the server answered. */
211
262
  async delete(opts) {
212
263
  const { resource, params } = opts;
213
264
  return this.request({
@@ -217,6 +268,11 @@ let DefaultRestDataProvider = DefaultRestDataProvider_1 = class DefaultRestDataP
217
268
  paths: [resource, `${params.id}`],
218
269
  });
219
270
  }
271
+ /**
272
+ * `DELETE /{resource}` with `{ where: { id: { inq: ids } } }` as the body. Resolves `{ data }`, the
273
+ * ids of the rows the server answered (`undefined` when the answer is not a row array). Rejects
274
+ * when `ids` is empty, before any request.
275
+ */
220
276
  async deleteMany(opts) {
221
277
  const { resource, params } = opts;
222
278
  const { ids } = params;
@@ -233,6 +289,11 @@ let DefaultRestDataProvider = DefaultRestDataProvider_1 = class DefaultRestDataP
233
289
  return { data: this.toAffectedIds({ rows: result.data }) };
234
290
  });
235
291
  }
292
+ /**
293
+ * Sends `params.method` to `/{resource}` with the provider's headers and auth; `requestType`
294
+ * defaults to `RequestTypes.SEND`. Resolves the response read by that type. Rejects when
295
+ * `params.method` is missing, before any request.
296
+ */
236
297
  async send(opts) {
237
298
  const { resource, params } = opts;
238
299
  if (!params?.method) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@venizia/ardor-admin",
3
- "version": "0.4.8-1",
3
+ "version": "0.4.8-3",
4
4
  "description": "ARDOR react-admin adapter - the REST data provider, auth provider and i18n provider wired through IGNIS inversion, the ArdorApplication root component, the translate and notify hooks, and the English and Vietnamese message bundles.",
5
5
  "keywords": [
6
6
  "admin",
@@ -61,8 +61,8 @@
61
61
  "prepublishOnly": "make rebuild"
62
62
  },
63
63
  "dependencies": {
64
- "@venizia/ardor-kernel": "0.4.8-1",
65
- "@venizia/ardor-react": "0.4.8-1"
64
+ "@venizia/ardor-kernel": "0.4.8-3",
65
+ "@venizia/ardor-react": "0.4.8-3"
66
66
  },
67
67
  "devDependencies": {
68
68
  "@happy-dom/global-registrator": "^21.0.4",
@@ -72,11 +72,11 @@
72
72
  "@testing-library/react": "^16.3.3",
73
73
  "@types/bun": "^1.4.3",
74
74
  "@types/react": "^19",
75
- "@venizia/dev-configs": "^0.4.8-0",
76
- "@venizia/ignis-filter": "^0.4.7-0",
77
- "@venizia/ignis-helpers": "^0.4.8-0",
78
- "@venizia/ignis-inversion": "^0.4.7-0",
79
- "@venizia/ignis-kernel": "^0.4.8-0",
75
+ "@venizia/dev-configs": "^0.4.8-2",
76
+ "@venizia/ignis-filter": "^0.4.7-2",
77
+ "@venizia/ignis-helpers": "^0.4.8-2",
78
+ "@venizia/ignis-inversion": "^0.4.7-2",
79
+ "@venizia/ignis-kernel": "^0.4.8-2",
80
80
  "eslint": "^10.13.0",
81
81
  "oxlint": "1.89.0",
82
82
  "oxlint-tsgolint": "7.0.2004",
@@ -94,10 +94,10 @@
94
94
  "peerDependencies": {
95
95
  "@reduxjs/toolkit": ">=2.13.0",
96
96
  "@tanstack/react-query": ">=5.104.5",
97
- "@venizia/ignis-filter": "^0.4.7-0",
98
- "@venizia/ignis-helpers": "^0.4.8-0",
99
- "@venizia/ignis-inversion": "^0.4.7-0",
100
- "@venizia/ignis-kernel": "^0.4.8-0",
97
+ "@venizia/ignis-filter": "^0.4.7-2",
98
+ "@venizia/ignis-helpers": "^0.4.8-2",
99
+ "@venizia/ignis-inversion": "^0.4.7-2",
100
+ "@venizia/ignis-kernel": "^0.4.8-2",
101
101
  "ra-core": ">=5.15.5",
102
102
  "ra-i18n-polyglot": ">=5.15.5",
103
103
  "react": ">=19.3.1",