@llmnative/react 2.3.0 → 2.4.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/dist/index.js +21 -21
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +3370 -3250
- package/dist/index.mjs.map +1 -1
- package/dist/types/src/I18n.d.ts +2 -0
- package/dist/types/src/components/widgets/grid-core/GridCore.d.ts +1 -1
- package/dist/types/src/components/widgets/grid-core/types.d.ts +2 -0
- package/dist/types/src/components/widgets/grid-core/useGridDBRecords.d.ts +6 -2
- package/dist/types/src/index.d.ts +5 -1
- package/dist/types/src/providers/data/DataProvider.d.ts +29 -0
- package/dist/types/src/providers/data/firebase.d.ts +2 -2
- package/dist/types/src/providers/data/firestore.d.ts +2 -2
- package/dist/types/src/providers/data/query.d.ts +14 -0
- package/dist/types/src/providers/data/useDataSubscription.d.ts +20 -0
- package/llms-full.txt +36 -4
- package/package.json +1 -1
package/dist/types/src/I18n.d.ts
CHANGED
|
@@ -16,6 +16,8 @@ export interface I18nDict {
|
|
|
16
16
|
goHome: string;
|
|
17
17
|
/** The button that opens the menu on a small screen (the header of the scaffold). */
|
|
18
18
|
openNavigation: string;
|
|
19
|
+
/** CR-129 — a read the database refused or lost. */
|
|
20
|
+
loadError: string;
|
|
19
21
|
};
|
|
20
22
|
auth: {
|
|
21
23
|
signIn: string;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import React from "react";
|
|
2
2
|
import { type RecordProps } from "../../../providers/data/DataProvider";
|
|
3
3
|
import { type GridCoreProps } from "./types";
|
|
4
|
-
declare function GridCore<TRecord extends RecordProps>({ records, recordId, sourcePath, columns, actions, form, editDeepLink, header, footer, view, views, sticky, wrapperClassName, cardClassName, bodyClassName, loading, title, before, after, sortable, pagination, selection, onRowClick, reorderable, onReorder, groupBy, searchable, filters, onSave, onDelete, onComplete, audit, onLoad, }: GridCoreProps<TRecord>): React.JSX.Element;
|
|
4
|
+
declare function GridCore<TRecord extends RecordProps>({ records, recordId, sourcePath, columns, actions, form, editDeepLink, header, footer, view, views, sticky, wrapperClassName, cardClassName, bodyClassName, loading, title, before, after, sortable, pagination, selection, onRowClick, reorderable, onReorder, groupBy, searchable, filters, onSave, onDelete, onComplete, audit, onLoad, loadError, }: GridCoreProps<TRecord>): React.JSX.Element;
|
|
5
5
|
export default GridCore;
|
|
@@ -411,6 +411,8 @@ export type GridCoreProps<TRecord extends RecordProps> = GridBaseProps<TRecord>
|
|
|
411
411
|
records: TRecord[];
|
|
412
412
|
recordId: GridRecordKey<TRecord>;
|
|
413
413
|
sourcePath?: string;
|
|
414
|
+
/** CR-129 — the reading of `path` failed: this message replaces the records (and their empty state). */
|
|
415
|
+
loadError?: React.ReactNode;
|
|
414
416
|
};
|
|
415
417
|
export type GridArrayProps<TRecord extends RecordProps> = GridBaseProps<TRecord> & {
|
|
416
418
|
records: TRecord[];
|
|
@@ -1,9 +1,13 @@
|
|
|
1
|
-
import { type DatabaseOptions, type RecordProps } from "../../../providers/data/DataProvider";
|
|
1
|
+
import { type DatabaseOptions, type DataProviderError, type RecordProps } from "../../../providers/data/DataProvider";
|
|
2
2
|
type UseGridDBRecordsArgs = {
|
|
3
3
|
path?: string;
|
|
4
4
|
where?: DatabaseOptions["where"];
|
|
5
5
|
order?: DatabaseOptions["order"];
|
|
6
6
|
fieldMap?: DatabaseOptions["fieldMap"];
|
|
7
7
|
};
|
|
8
|
-
|
|
8
|
+
/** The records of a `Grid` with `path`, live, and why they did not arrive (CR-129). */
|
|
9
|
+
declare function useGridDBRecords<TRecord extends RecordProps>({ path, where, order, fieldMap, }: UseGridDBRecordsArgs): {
|
|
10
|
+
records: TRecord[];
|
|
11
|
+
error: DataProviderError | null;
|
|
12
|
+
};
|
|
9
13
|
export default useGridDBRecords;
|
|
@@ -15,7 +15,11 @@ export type { AppThemeProviderConfig, BuiltInThemeId, CardTheme, ColorScale, Gal
|
|
|
15
15
|
export { AuthButton, useAccessToken, getAccessToken } from './auth';
|
|
16
16
|
export * from './components/auth';
|
|
17
17
|
export { useGlobalVars, getGlobalVars, setGlobalVars, removeGlobalVars } from './Global';
|
|
18
|
-
export type { DataProviderAdapter, FieldValue, RecordProps, RecordArray, DatabaseOptions, DBConfig, ReadOptions, WhereClause, OrderClause, Condition } from './providers/data/DataProvider';
|
|
18
|
+
export type { DataProviderAdapter, FieldValue, RecordProps, RecordArray, DatabaseOptions, DBConfig, ReadOptions, WhereClause, OrderClause, Condition, DataProviderErrorCode } from './providers/data/DataProvider';
|
|
19
|
+
export { DataProviderError } from './providers/data/DataProvider';
|
|
20
|
+
export { toDataProviderError } from './providers/data/query';
|
|
21
|
+
export { useDataSubscription } from './providers/data/useDataSubscription';
|
|
22
|
+
export type { DataSubscriptionOptions, DataSubscriptionState } from './providers/data/useDataSubscription';
|
|
19
23
|
export type { OrderConfig, OrderDirection } from './libs/order';
|
|
20
24
|
export { Order } from './libs/order';
|
|
21
25
|
export { PromptUtils } from './libs/promptUtils';
|
|
@@ -28,6 +28,10 @@ export type Condition = {
|
|
|
28
28
|
gte?: RangeValue;
|
|
29
29
|
nin?: ListValue;
|
|
30
30
|
in?: ListValue;
|
|
31
|
+
/** CR-129 — the field is a list that holds this value (Firestore `array-contains`, Supabase `contains`). */
|
|
32
|
+
contains?: ScalarValue;
|
|
33
|
+
/** CR-129 — the field is a list that holds at least one of these values (Firestore `array-contains-any`, Supabase `overlaps`). */
|
|
34
|
+
containsAny?: ListValue;
|
|
31
35
|
};
|
|
32
36
|
export type WhereClause = {
|
|
33
37
|
[field: string]: Condition | OperatorValue;
|
|
@@ -35,9 +39,32 @@ export type WhereClause = {
|
|
|
35
39
|
export type OrderClause = {
|
|
36
40
|
[field: string]: "asc" | "desc";
|
|
37
41
|
};
|
|
42
|
+
/**
|
|
43
|
+
* CR-129 — why a read failed, the same on every provider: the rules refused it (`permission-denied`), there
|
|
44
|
+
* is no session (`unauthenticated`), the query cannot run as written, e.g. a missing index or an operator the
|
|
45
|
+
* database refuses (`invalid-query`), the database cannot be reached (`unavailable`), or anything else.
|
|
46
|
+
*/
|
|
47
|
+
export type DataProviderErrorCode = 'permission-denied' | 'unauthenticated' | 'invalid-query' | 'unavailable' | 'unknown';
|
|
48
|
+
/** CR-129 — a failed read, normalized from the error of the database (kept in `cause`). */
|
|
49
|
+
export declare class DataProviderError extends Error {
|
|
50
|
+
readonly code: DataProviderErrorCode;
|
|
51
|
+
readonly path?: string;
|
|
52
|
+
readonly cause?: unknown;
|
|
53
|
+
constructor(code: DataProviderErrorCode, message: string, options?: {
|
|
54
|
+
path?: string;
|
|
55
|
+
cause?: unknown;
|
|
56
|
+
});
|
|
57
|
+
}
|
|
38
58
|
export interface DatabaseOptions {
|
|
39
59
|
where?: WhereClause;
|
|
40
60
|
order?: OrderClause;
|
|
61
|
+
/** CR-129 — at most this many records, after `where` and `order`. */
|
|
62
|
+
limit?: number;
|
|
63
|
+
/**
|
|
64
|
+
* CR-129 — called when the database refuses or loses the subscription. Without it the provider logs the
|
|
65
|
+
* error as before; with it the page can say why the data did not arrive.
|
|
66
|
+
*/
|
|
67
|
+
onError?: (error: DataProviderError) => void;
|
|
41
68
|
fieldMap?: Record<string, string>;
|
|
42
69
|
onLoad?: (data: RecordObject) => RecordObject;
|
|
43
70
|
}
|
|
@@ -47,6 +74,8 @@ export interface DBConfig extends DatabaseOptions {
|
|
|
47
74
|
export interface ReadOptions {
|
|
48
75
|
where?: WhereClause;
|
|
49
76
|
order?: OrderClause;
|
|
77
|
+
/** CR-129 — at most this many records, after `where` and `order`. */
|
|
78
|
+
limit?: number;
|
|
50
79
|
toArray?: boolean;
|
|
51
80
|
exception?: boolean;
|
|
52
81
|
}
|
|
@@ -10,13 +10,13 @@ export declare class FirebaseDataProvider implements DataProviderAdapter {
|
|
|
10
10
|
getConfigurationState(): ProviderConfigurationState;
|
|
11
11
|
isConfigured(): boolean;
|
|
12
12
|
readShallow: (path: string, exception?: boolean) => Promise<string[]>;
|
|
13
|
-
read: (path: string, { where, order, toArray, exception }?: ReadOptions) => Promise<any>;
|
|
13
|
+
read: (path: string, { where, order, limit, toArray, exception }?: ReadOptions) => Promise<any>;
|
|
14
14
|
update: (path: string, data: object, exception?: boolean) => Promise<void>;
|
|
15
15
|
set: (path: string, data: object, exception?: boolean) => Promise<void>;
|
|
16
16
|
setChunks: (path: string, data: object, { chunkSize, purge, onProgress }?: SetChunksOptions) => Promise<void>;
|
|
17
17
|
remove: (path: string, exception?: boolean) => Promise<void>;
|
|
18
18
|
count: (path: string) => Promise<number>;
|
|
19
|
-
subscribe: <T extends RecordProps = RecordProps>(path: string | undefined, setRecords: (records: T[]) => void,
|
|
19
|
+
subscribe: <T extends RecordProps = RecordProps>(path: string | undefined, setRecords: (records: T[]) => void, options?: DatabaseOptions) => (() => void);
|
|
20
20
|
}
|
|
21
21
|
declare const _default: FirebaseDataProvider;
|
|
22
22
|
export default _default;
|
|
@@ -23,7 +23,7 @@ export declare class FirestoreDataProvider implements DataProviderAdapter {
|
|
|
23
23
|
dispose: () => Promise<void>;
|
|
24
24
|
getConfigurationState(): ProviderConfigurationState;
|
|
25
25
|
isConfigured(): boolean;
|
|
26
|
-
read: (path: string, { where, order, toArray, exception }?: ReadOptions) => Promise<any>;
|
|
26
|
+
read: (path: string, { where, order, limit, toArray, exception }?: ReadOptions) => Promise<any>;
|
|
27
27
|
set: (path: string, data: object, exception?: boolean) => Promise<void>;
|
|
28
28
|
update: (path: string, data: object, exception?: boolean) => Promise<void>;
|
|
29
29
|
remove: (path: string, exception?: boolean) => Promise<void>;
|
|
@@ -39,7 +39,7 @@ export declare class FirestoreDataProvider implements DataProviderAdapter {
|
|
|
39
39
|
* Firestore inequality filters on a field require the first orderBy() to be
|
|
40
40
|
* on that same field. Pass `order` accordingly to avoid SDK errors.
|
|
41
41
|
*/
|
|
42
|
-
subscribe: <T extends RecordProps = RecordProps>(path: string | undefined, setRecords: (records: T[]) => void,
|
|
42
|
+
subscribe: <T extends RecordProps = RecordProps>(path: string | undefined, setRecords: (records: T[]) => void, options?: DatabaseOptions) => (() => void);
|
|
43
43
|
/**
|
|
44
44
|
* Returns the list of document IDs in a collection without loading document
|
|
45
45
|
* data - the Firestore equivalent of RTDB's ?shallow=true REST endpoint.
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { DataProviderError, type Condition, type DatabaseOptions, type OperatorValue } from './DataProvider';
|
|
2
|
+
/** A `where` value as a `Condition`: a list is `in`, a scalar is `eq`. */
|
|
3
|
+
export declare function toCondition(raw: Condition | OperatorValue): Condition;
|
|
4
|
+
/** Whether `value` (the field of a record) satisfies a condition of `where`. Unknown operators never match. */
|
|
5
|
+
export declare function matchCondition(value: unknown, raw: Condition | OperatorValue): boolean;
|
|
6
|
+
/** The first `limit` items (all of them without a valid limit). */
|
|
7
|
+
export declare function applyLimit<T>(items: T[], limit?: number): T[];
|
|
8
|
+
/** Any error of a database as a `DataProviderError` (an existing one is returned as it is). */
|
|
9
|
+
export declare function toDataProviderError(error: unknown, path?: string): DataProviderError;
|
|
10
|
+
/**
|
|
11
|
+
* Tells the page that a subscription failed: `options.onError` when it is given, else the console as the
|
|
12
|
+
* providers did before CR-129. Returns the normalized error.
|
|
13
|
+
*/
|
|
14
|
+
export declare function reportSubscribeError(options: Pick<DatabaseOptions, 'onError'> | undefined, error: unknown, path?: string): DataProviderError;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { DataProviderError, DatabaseOptions, RecordArray } from './DataProvider';
|
|
2
|
+
export type DataSubscriptionOptions = Pick<DatabaseOptions, 'where' | 'order' | 'limit' | 'fieldMap'> & {
|
|
3
|
+
/** Read nothing (a page still waiting for an id): `loading` false, no records. */
|
|
4
|
+
skip?: boolean;
|
|
5
|
+
/** The name of a provider registered in `providers` (the default one without it). */
|
|
6
|
+
provider?: string;
|
|
7
|
+
};
|
|
8
|
+
export type DataSubscriptionState = {
|
|
9
|
+
records: RecordArray;
|
|
10
|
+
loading: boolean;
|
|
11
|
+
/** Why the data did not arrive (rules, session, query, network), the same on every provider. */
|
|
12
|
+
error: DataProviderError | null;
|
|
13
|
+
};
|
|
14
|
+
/**
|
|
15
|
+
* CR-129 — the records at `path`, live, from the data provider: `{ records, loading, error }`. `loading` is
|
|
16
|
+
* true until the first answer; a subscription the database refuses gives `error` instead of a list that never
|
|
17
|
+
* arrives. `where`, `order` and `limit` are compared by value, so a new object with the same content does not
|
|
18
|
+
* subscribe again.
|
|
19
|
+
*/
|
|
20
|
+
export declare function useDataSubscription(path: string | null | undefined, options?: DataSubscriptionOptions): DataSubscriptionState;
|
package/llms-full.txt
CHANGED
|
@@ -218,9 +218,9 @@ await oauth.getOrganizations(accessToken) // [{ login, avatarUrl, role: 'admin
|
|
|
218
218
|
|
|
219
219
|
```ts
|
|
220
220
|
// DataProviderAdapter
|
|
221
|
-
read(path,
|
|
222
|
-
subscribe(path, callback: (records: RecordArray) => void): () => void
|
|
223
|
-
count?(path
|
|
221
|
+
read(path, { where?, order?, limit?, toArray?, exception? }) / set(path, data, exception?) / update(path, data, exception?) / remove(path, exception?)
|
|
222
|
+
subscribe(path, callback: (records: RecordArray) => void, { where?, order?, limit?, fieldMap?, onLoad?, onError? }): () => void
|
|
223
|
+
count?(path): Promise<number>
|
|
224
224
|
|
|
225
225
|
// StorageProviderAdapter
|
|
226
226
|
upload(file, path): Promise<string|undefined>
|
|
@@ -317,6 +317,35 @@ const creds = useCredentialsProvider()
|
|
|
317
317
|
const token = await creds.getToken('https://www.googleapis.com/auth/solar')
|
|
318
318
|
```
|
|
319
319
|
|
|
320
|
+
### Letture: filtri, `limit`, errori (CR-129)
|
|
321
|
+
|
|
322
|
+
Gli stessi operatori e lo stesso contratto su ogni provider (`firestoreDb`, `supabaseDb`, `dbRealtime`, `mock`):
|
|
323
|
+
l'adapter li traduce nei comandi del database, o li applica nel browser dove il database non li ha.
|
|
324
|
+
|
|
325
|
+
| `where` | Significato | Firestore | Supabase | Realtime DB / Mock |
|
|
326
|
+
|---|---|---|---|---|
|
|
327
|
+
| `{ f: 'x' }` / `{ f: { eq } }` | uguale | `==` | `eq` | server sul campo di `order`, altrimenti browser |
|
|
328
|
+
| `lt` `lte` `gt` `gte` | confronto | `<` … `>=` | `lt` … `gte` | idem |
|
|
329
|
+
| `{ f: ['a','b'] }` / `in`, `nin` | uno dei valori / nessuno | `in` (≤30), `not-in` (≤10) | `in`, `not.in` | browser |
|
|
330
|
+
| `contains: v` | il campo lista contiene `v` | `array-contains` | `contains` | browser |
|
|
331
|
+
| `containsAny: [..]` | contiene almeno uno | `array-contains-any` (≤30) | `overlaps` | browser |
|
|
332
|
+
|
|
333
|
+
`limit: n` (in `read` e `subscribe`) tiene i primi `n` dopo `where` e `order`: Firestore `limit()`, Supabase
|
|
334
|
+
`.limit()`, Realtime Database `limitToFirst`/`limitToLast` (nel browser se restano filtri da applicare lì).
|
|
335
|
+
|
|
336
|
+
Un'iscrizione che il database rifiuta (regole, sessione, indice mancante, rete) arriva a `onError` come
|
|
337
|
+
`DataProviderError` con `code`: `permission-denied` | `unauthenticated` | `invalid-query` | `unavailable` |
|
|
338
|
+
`unknown` (l'errore originale in `cause`). Senza `onError` il provider la scrive in console come prima.
|
|
339
|
+
Un percorso di record (`/users/u1`) segue quel record su ogni provider.
|
|
340
|
+
|
|
341
|
+
```ts
|
|
342
|
+
const { records, loading, error } = useDataSubscription('/registro', { order: { at: 'desc' }, limit: 50 })
|
|
343
|
+
// error?.code === 'permission-denied' → la pagina dice che non può leggere, invece di restare in caricamento
|
|
344
|
+
db.subscribe('/posts', setRecords, { where: { tags: { contains: 'news' } }, limit: 20, onError: (e) => show(e.code) })
|
|
345
|
+
```
|
|
346
|
+
|
|
347
|
+
`Grid` con `path` mostra `common.loadError` al posto delle righe quando la lettura fallisce.
|
|
348
|
+
|
|
320
349
|
### Provider custom
|
|
321
350
|
```ts
|
|
322
351
|
import { DataProviderAdapter, RecordArray } from '@llmnative/react'
|
|
@@ -1473,7 +1502,10 @@ type FieldValue = string | number | boolean | null | undefined | Record<string
|
|
|
1473
1502
|
type RecordArray = RecordProps[]
|
|
1474
1503
|
|
|
1475
1504
|
type OrderConfig = { field: string; dir: 'asc' | 'desc' }
|
|
1476
|
-
type
|
|
1505
|
+
type Condition = { eq?, lt?, lte?, gt?, gte?, in?: list, nin?: list, contains?: scalar, containsAny?: list }
|
|
1506
|
+
type WhereClause = { [field: string]: Condition | scalar | list } // scalar = eq, list = in
|
|
1507
|
+
type OrderClause = { [field: string]: 'asc' | 'desc' }
|
|
1508
|
+
class DataProviderError extends Error { code: 'permission-denied' | 'unauthenticated' | 'invalid-query' | 'unavailable' | 'unknown'; path?: string; cause?: unknown }
|
|
1477
1509
|
|
|
1478
1510
|
interface UIProps {
|
|
1479
1511
|
before?: React.ReactNode
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@llmnative/react",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.4.0",
|
|
4
4
|
"description": "LLM-native React framework for deterministic UI generation. Data-driven by default, schema-driven optional. Ultra-low token consumption — built for AI agents, not just humans.",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"module": "dist/index.mjs",
|