@flattype/models 1.2.0 → 1.3.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.
Files changed (2) hide show
  1. package/README.md +54 -3
  2. package/package.json +3 -3
package/README.md CHANGED
@@ -16,6 +16,7 @@
16
16
  <a href="https://www.npmjs.com/package/@flattype/core"><img src="https://img.shields.io/npm/v/@flattype/core?label=%40flattype%2Fcore&color=8b6cff" alt="npm @flattype/core"></a>
17
17
  <a href="https://www.npmjs.com/package/@flattype/models"><img src="https://img.shields.io/npm/v/@flattype/models?label=%40flattype%2Fmodels&color=8b6cff" alt="npm @flattype/models"></a>
18
18
  <a href="https://www.npmjs.com/package/@flattype/http"><img src="https://img.shields.io/npm/v/@flattype/http?label=%40flattype%2Fhttp&color=8b6cff" alt="npm @flattype/http"></a>
19
+ <a href="https://www.npmjs.com/package/@flattype/react"><img src="https://img.shields.io/npm/v/@flattype/react?label=%40flattype%2Freact&color=8b6cff" alt="npm @flattype/react"></a>
19
20
  <a href="https://github.com/karammm/flattype/actions/workflows/ci.yml"><img src="https://github.com/karammm/flattype/actions/workflows/ci.yml/badge.svg" alt="CI"></a>
20
21
  <img src="https://img.shields.io/badge/core-3.7_KB_min%2Bgz-2fd4b2" alt="3.7 KB min+gz">
21
22
  <img src="https://img.shields.io/badge/dependencies-0-2fd4b2" alt="No third-party dependencies">
@@ -27,6 +28,7 @@
27
28
  <a href="#the-format"><b>Format</b></a> ·
28
29
  <a href="#typed-models"><b>Models</b></a> ·
29
30
  <a href="#http"><b>HTTP</b></a> ·
31
+ <a href="#react"><b>React</b></a> ·
30
32
  <a href="#benchmarks"><b>Benchmarks</b></a> ·
31
33
  <a href="https://github.com/karammm/flattype/blob/main/CHANGELOG.md"><b>Changelog</b></a> ·
32
34
  <a href="https://github.com/karammm/flattype/blob/main/ROADMAP.md"><b>Roadmap</b></a>
@@ -35,10 +37,10 @@
35
37
  <p align="center">
36
38
  <a href="https://github.com/karammm/flattype/blob/main/docs/assets/flattype-intro.mp4">
37
39
  <img src="https://raw.githubusercontent.com/karammm/flattype/main/docs/assets/flattype-intro.gif" width="820"
38
- alt="FlatType.js in 52 seconds: an API response encoded to Flat Notation, how tables and dot paths keep it small, typed models mapped from snake_case JSON, an Express server answering in Flat Notation or JSON, and the size comparison with JSON and TOON">
40
+ alt="FlatType.js in 62 seconds: an API response encoded to Flat Notation, how tables and dot paths keep it small, typed models mapped from snake_case JSON, an Express server answering in Flat Notation or JSON, React hooks in a real app, and the size comparison with JSON and TOON">
39
41
  </a>
40
42
  <br>
41
- <sub>▶ <a href="https://github.com/karammm/flattype/blob/main/docs/assets/flattype-intro.mp4">Watch the 52-second intro in full quality</a>. Every result shown is real output, generated by <a href="https://github.com/karammm/flattype/blob/main/scripts/video/record.mjs"><code>scripts/video/record.mjs</code></a>.</sub>
43
+ <sub>▶ <a href="https://github.com/karammm/flattype/blob/main/docs/assets/flattype-intro.mp4">Watch the 62-second intro in full quality</a>. Every result shown is real output, generated by <a href="https://github.com/karammm/flattype/blob/main/scripts/video/record.mjs"><code>scripts/video/record.mjs</code></a>.</sub>
42
44
  </p>
43
45
 
44
46
  ---
@@ -97,6 +99,14 @@ app.use(flatExpress()); // server: res.json() answers in Flat Notation when the
97
99
  const users = await flatFetch("/api/users", { model: User, list: true }); // client: User[]
98
100
  ```
99
101
 
102
+ And in React:
103
+
104
+ ```tsx
105
+ import { useFlat } from "@flattype/react";
106
+
107
+ const { data: users, loading, error } = useFlat("/api/users", { model: User, list: true }); // User[] | undefined
108
+ ```
109
+
100
110
  ## Why FlatType
101
111
 
102
112
  - **About half the size on list payloads.** A list of 1,000 users is 45% smaller than minified JSON and 50% smaller than TOON, because keys are written once and nested fields are flattened into the table header.
@@ -113,9 +123,10 @@ const users = await flatFetch("/api/users", { model: User, list: true }); // cli
113
123
  | [`@flattype/core`](https://github.com/karammm/flattype/blob/main/packages/core) | `encode`, `decode`, `createDecoder`, `flatten`, `unflatten`, `stats` | 3.7 KB |
114
124
  | [`@flattype/models`](https://github.com/karammm/flattype/blob/main/packages/models) | `defineModel`, `infer`, `toSource`: typed models from JSON or Flat Notation | +3.2 KB |
115
125
  | [`@flattype/http`](https://github.com/karammm/flattype/blob/main/packages/http) | `flatFetch`, `createClient`, `flatAxios`, `streamRows`, and `flatExpress` / `flatFastify` / `flatHono` | +2.3 KB |
126
+ | [`@flattype/react`](https://github.com/karammm/flattype/blob/main/packages/react) | `useFlat`, `useFlatSuspense`, `useFlatStream`, `useModel`, `FlatProvider` | +1.4 KB |
116
127
  | [`@flattype/shared`](https://github.com/karammm/flattype/blob/main/packages/shared) | Shared TypeScript types | types only |
117
128
 
118
- React, Vue, Angular and Svelte bindings, Claude helpers and a CLI are planned. See the [roadmap](https://github.com/karammm/flattype/blob/main/ROADMAP.md).
129
+ Vue, Angular and Svelte bindings, Claude helpers and a CLI are planned. See the [roadmap](https://github.com/karammm/flattype/blob/main/ROADMAP.md).
119
130
 
120
131
  ## The format
121
132
 
@@ -242,6 +253,46 @@ for await (const { path, index, value } of streamRows("/api/export")) { // rows
242
253
 
243
254
  A JSON-only server works with every client helper: the response is just read as JSON.
244
255
 
256
+ ## React
257
+
258
+ ```bash
259
+ npm install @flattype/react @flattype/models
260
+ ```
261
+
262
+ ```tsx
263
+ import { FlatProvider, useFlat, useFlatStream, useFlatSuspense } from "@flattype/react";
264
+
265
+ <FlatProvider baseURL="/api" headers={{ authorization: `Bearer ${token}` }}>
266
+ <App />
267
+ </FlatProvider>;
268
+
269
+ function Users() {
270
+ const { data, error, loading, refetch } = useFlat("/users", { model: User, list: true });
271
+ if (error) return <ErrorMessage error={error} />; // HttpError, ModelError or a network error
272
+ if (!data) return <Spinner />;
273
+ return <UserList users={data} onRefresh={refetch} />; // data: User[]
274
+ }
275
+
276
+ function Profile({ id }: { id: number }) {
277
+ const { data: user } = useFlatSuspense(`/users/${id}`, { model: User }); // inside <Suspense>
278
+ return <h2>{user.fullName}</h2>; // user: User, never undefined
279
+ }
280
+
281
+ function Export() {
282
+ const { rows, done } = useFlatStream("/export", { model: Row, table: "rows" });
283
+ return <Table rows={rows} footer={done ? "Done" : `Loading… ${rows.length}`} />; // rows appear while downloading
284
+ }
285
+ ```
286
+
287
+ | Hook | Returns | Notes |
288
+ | --- | --- | --- |
289
+ | `useFlat(url, options)` | `{ data, error, loading, refetch }` | A new URL aborts the old request. Old data stays while the next loads. `url: null` or `enabled: false` skips the request |
290
+ | `useFlatSuspense(url, options)` | `{ data, refetch }` | Suspends, sends errors to an error boundary, and caches by URL (one request for many components) |
291
+ | `useFlatStream(url, options)` | `{ rows, done, error, restart }` | One render per network chunk. `table` picks one table by path |
292
+ | `useModel(data, Model, { list })` | the mapped value | Memoized. For data from props, stores or sockets |
293
+
294
+ Works with React 18 and 19, in StrictMode and with any server. A JSON-only API works too. A runnable app with Playwright tests in three browsers is in [`examples/react-app`](https://github.com/karammm/flattype/blob/main/examples/react-app).
295
+
245
296
  ## Benchmarks
246
297
 
247
298
  `pnpm compare` on the fixtures in [`fixtures/`](https://github.com/karammm/flattype/blob/main/fixtures/index.mjs) (Node 24, Apple Silicon):
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@flattype/models",
3
- "version": "1.2.0",
3
+ "version": "1.3.0",
4
4
  "description": "Typed models for API data: key mapping, coercion and defaults, from JSON or Flat Notation.",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -33,8 +33,8 @@
33
33
  "flattype"
34
34
  ],
35
35
  "dependencies": {
36
- "@flattype/shared": "1.2.0",
37
- "@flattype/core": "1.2.0"
36
+ "@flattype/core": "1.3.0",
37
+ "@flattype/shared": "1.3.0"
38
38
  },
39
39
  "publishConfig": {
40
40
  "access": "public"