@flattype/models 1.4.1 → 1.5.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/README.md +54 -6
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -18,6 +18,7 @@
|
|
|
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
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>
|
|
20
20
|
<a href="https://www.npmjs.com/package/@flattype/vue"><img src="https://img.shields.io/npm/v/@flattype/vue?label=%40flattype%2Fvue&color=8b6cff" alt="npm @flattype/vue"></a>
|
|
21
|
+
<a href="https://www.npmjs.com/package/@flattype/angular"><img src="https://img.shields.io/npm/v/@flattype/angular?label=%40flattype%2Fangular&color=8b6cff" alt="npm @flattype/angular"></a>
|
|
21
22
|
<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>
|
|
22
23
|
<img src="https://img.shields.io/badge/core-3.7_KB_min%2Bgz-2fd4b2" alt="3.7 KB min+gz">
|
|
23
24
|
<img src="https://img.shields.io/badge/dependencies-0-2fd4b2" alt="No third-party dependencies">
|
|
@@ -31,6 +32,7 @@
|
|
|
31
32
|
<a href="#http"><b>HTTP</b></a> ·
|
|
32
33
|
<a href="#react"><b>React</b></a> ·
|
|
33
34
|
<a href="#vue"><b>Vue</b></a> ·
|
|
35
|
+
<a href="#angular"><b>Angular</b></a> ·
|
|
34
36
|
<a href="#benchmarks"><b>Benchmarks</b></a> ·
|
|
35
37
|
<a href="https://github.com/karammm/flattype/blob/main/CHANGELOG.md"><b>Changelog</b></a> ·
|
|
36
38
|
<a href="https://github.com/karammm/flattype/blob/main/ROADMAP.md"><b>Roadmap</b></a>
|
|
@@ -39,10 +41,10 @@
|
|
|
39
41
|
<p align="center">
|
|
40
42
|
<a href="https://github.com/karammm/flattype/blob/main/docs/assets/flattype-intro.mp4">
|
|
41
43
|
<img src="https://raw.githubusercontent.com/karammm/flattype/main/docs/assets/flattype-intro.gif" width="820"
|
|
42
|
-
alt="FlatType.js in
|
|
44
|
+
alt="FlatType.js in 71 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, Vue and Angular in real apps, and the size comparison with JSON and TOON">
|
|
43
45
|
</a>
|
|
44
46
|
<br>
|
|
45
|
-
<sub>▶ <a href="https://github.com/karammm/flattype/blob/main/docs/assets/flattype-intro.mp4">Watch the
|
|
47
|
+
<sub>▶ <a href="https://github.com/karammm/flattype/blob/main/docs/assets/flattype-intro.mp4">Watch the 71-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>
|
|
46
48
|
</p>
|
|
47
49
|
|
|
48
50
|
---
|
|
@@ -101,12 +103,15 @@ app.use(flatExpress()); // server: res.json() answers in Flat Notation when the
|
|
|
101
103
|
const users = await flatFetch("/api/users", { model: User, list: true }); // client: User[]
|
|
102
104
|
```
|
|
103
105
|
|
|
104
|
-
And in React or
|
|
106
|
+
And in React, Vue or Angular:
|
|
105
107
|
|
|
106
108
|
```tsx
|
|
107
109
|
import { useFlat } from "@flattype/react"; // or "@flattype/vue": the same API, with refs
|
|
108
110
|
|
|
109
111
|
const { data: users, loading, error } = useFlat("/api/users", { model: User, list: true }); // User[] | undefined
|
|
112
|
+
|
|
113
|
+
// Angular: signals on top of HttpClient
|
|
114
|
+
users = flatResource(() => "/api/users", { model: User, list: true }); // users.value(): User[] | undefined
|
|
110
115
|
```
|
|
111
116
|
|
|
112
117
|
## Why FlatType
|
|
@@ -126,10 +131,11 @@ const { data: users, loading, error } = useFlat("/api/users", { model: User, lis
|
|
|
126
131
|
| [`@flattype/models`](https://github.com/karammm/flattype/blob/main/packages/models) | `defineModel`, `infer`, `toSource`: typed models from JSON or Flat Notation | +3.2 KB |
|
|
127
132
|
| [`@flattype/http`](https://github.com/karammm/flattype/blob/main/packages/http) | `flatFetch`, `createClient`, `flatAxios`, `streamRows`, and `flatExpress` / `flatFastify` / `flatHono` | +2.3 KB |
|
|
128
133
|
| [`@flattype/react`](https://github.com/karammm/flattype/blob/main/packages/react) | `useFlat`, `useFlatSuspense`, `useFlatStream`, `useModel`, `FlatProvider` | +1.4 KB |
|
|
129
|
-
| [`@flattype/vue`](https://github.com/karammm/flattype/blob/main/packages/vue) | The same composables for Vue 3, with reactive URLs, plus the `createFlat()` plugin | +1.
|
|
134
|
+
| [`@flattype/vue`](https://github.com/karammm/flattype/blob/main/packages/vue) | The same composables for Vue 3, with reactive URLs, plus the `createFlat()` plugin | +1.2 KB |
|
|
135
|
+
| [`@flattype/angular`](https://github.com/karammm/flattype/blob/main/packages/angular) | `flatInterceptor` for HttpClient, the signal-based `flatResource` / `flatStream`, the `flatModel` pipe | +1.8 KB |
|
|
130
136
|
| [`@flattype/shared`](https://github.com/karammm/flattype/blob/main/packages/shared) | Shared TypeScript types | types only |
|
|
131
137
|
|
|
132
|
-
|
|
138
|
+
Svelte bindings, Claude helpers and a CLI are planned. See the [roadmap](https://github.com/karammm/flattype/blob/main/ROADMAP.md).
|
|
133
139
|
|
|
134
140
|
## The format
|
|
135
141
|
|
|
@@ -333,6 +339,48 @@ const { rows, done } = useFlatStream("/export", { model: Row, table: "rows" });
|
|
|
333
339
|
|
|
334
340
|
Vue 3.3+. A runnable app with Playwright tests in three browsers is in [`examples/vue-app`](https://github.com/karammm/flattype/blob/main/examples/vue-app).
|
|
335
341
|
|
|
342
|
+
## Angular
|
|
343
|
+
|
|
344
|
+
```bash
|
|
345
|
+
npm install @flattype/angular @flattype/models
|
|
346
|
+
```
|
|
347
|
+
|
|
348
|
+
```ts
|
|
349
|
+
// main.ts
|
|
350
|
+
bootstrapApplication(AppComponent, {
|
|
351
|
+
providers: [
|
|
352
|
+
provideHttpClient(withInterceptors([flatInterceptor])), // every HttpClient call can read Flat Notation
|
|
353
|
+
provideFlatType({ baseURL: "/api" }),
|
|
354
|
+
],
|
|
355
|
+
});
|
|
356
|
+
```
|
|
357
|
+
|
|
358
|
+
```ts
|
|
359
|
+
@Component({
|
|
360
|
+
imports: [FlatModelPipe],
|
|
361
|
+
template: `
|
|
362
|
+
@for (u of users.value()?.data; track u.id) { <li>{{ u.fullName }}</li> }
|
|
363
|
+
<p>{{ (raw() | flatModel: Address)?.city }}</p>
|
|
364
|
+
<p>{{ events.done() ? "Done" : "Loading… " + events.rows().length }}</p>
|
|
365
|
+
`,
|
|
366
|
+
})
|
|
367
|
+
export class UsersComponent {
|
|
368
|
+
page = signal(1);
|
|
369
|
+
users = flatResource(() => `/users?page=${this.page()}`, { model: UsersPage }); // refetches when page changes
|
|
370
|
+
events = flatStream(() => "/export", { model: Row, table: "rows" }); // rows while downloading
|
|
371
|
+
raw = toSignal(inject(HttpClient).get("/api/address")); // plain HttpClient works too
|
|
372
|
+
}
|
|
373
|
+
```
|
|
374
|
+
|
|
375
|
+
| API | What it does |
|
|
376
|
+
| --- | --- |
|
|
377
|
+
| `flatInterceptor` | Adds `Accept: text/x-flat, application/json` and decodes either format, error bodies included. Skip a request with `FLAT_TYPE_SKIP` in its `HttpContext` |
|
|
378
|
+
| `flatResource(() => url, options)` | `value`, `error` and `isLoading` signals plus `reload()`. Runs on HttpClient and cancels the old request when the URL changes |
|
|
379
|
+
| `flatStream(() => url, options)` | `rows`, `done` and `error` signals plus `restart()`. Uses `fetch`, because HttpClient can't stream |
|
|
380
|
+
| `flatModel` pipe, `mapModel` / `mapModelList` | Model mapping in templates and in RxJS pipelines |
|
|
381
|
+
|
|
382
|
+
Angular 19+ (built with partial compilation, so it works with every later version). A runnable Angular 22 app with Playwright tests in three browsers is in [`examples/angular-app`](https://github.com/karammm/flattype/blob/main/examples/angular-app).
|
|
383
|
+
|
|
336
384
|
## Benchmarks
|
|
337
385
|
|
|
338
386
|
`pnpm compare` on the fixtures in [`fixtures/`](https://github.com/karammm/flattype/blob/main/fixtures/index.mjs) (Node 24, Apple Silicon):
|
|
@@ -364,7 +412,7 @@ pnpm build && pnpm typecheck && pnpm test
|
|
|
364
412
|
pnpm bench # encode/decode vs JSON
|
|
365
413
|
pnpm compare # size and parse time vs JSON and TOON
|
|
366
414
|
pnpm check:size # bundle budgets
|
|
367
|
-
pnpm video # re-render docs/assets/flattype-intro.{mp4,gif} (needs ffmpeg)
|
|
415
|
+
pnpm video # re-render docs/assets/flattype-intro.{mp4,gif} (needs ffmpeg and the Angular example built)
|
|
368
416
|
```
|
|
369
417
|
|
|
370
418
|
This is a pnpm + Turborepo monorepo built with tsup and tested with Vitest and fast-check. Releases use Changesets, and all `@flattype/*` packages share one version number. Every release follows the checklist in [ROADMAP.md](https://github.com/karammm/flattype/blob/main/ROADMAP.md).
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@flattype/models",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.5.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/core": "1.
|
|
37
|
-
"@flattype/shared": "1.
|
|
36
|
+
"@flattype/core": "1.5.0",
|
|
37
|
+
"@flattype/shared": "1.5.0"
|
|
38
38
|
},
|
|
39
39
|
"publishConfig": {
|
|
40
40
|
"access": "public"
|