flet-box 1.0.4 → 1.0.6
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 +10 -0
- package/bin/cli.js +23 -7
- package/bin/commands/checkApi.js +761 -0
- package/bin/commands/create.js +77 -5
- package/bin/utils/dtsProps.js +191 -0
- package/bin/utils/moduleExports.js +165 -0
- package/bin/utils/neutralise.js +64 -0
- package/bin/utils/templates.js +366 -27
- package/docs/CONTRIBUTING.md +156 -0
- package/docs/README.md +68 -0
- package/docs/arquitectura.md +164 -0
- package/docs/cli/README.md +542 -0
- package/docs/guides/README.md +33 -0
- package/docs/guides/app-templates.md +197 -0
- package/docs/guides/compatibility.md +95 -0
- package/docs/guides/embedding.md +284 -0
- package/docs/guides/first-app.md +208 -0
- package/docs/guides/frontend-services.md +171 -0
- package/docs/guides/minification-and-protection.md +260 -0
- package/docs/guides/mobile-and-platforms.md +439 -0
- package/docs/guides/online-updates.md +196 -0
- package/docs/guides/router.md +282 -0
- package/docs/guides/state.md +283 -0
- package/docs/guides/syntax-philosophy.md +150 -0
- package/docs/guides/utilities.md +241 -0
- package/docs/guides/widget-structure.md +163 -0
- package/docs/server/README.md +68 -0
- package/docs/server/START_HERE.md +121 -0
- package/docs/server/api.md +225 -0
- package/docs/server/data-services.md +300 -0
- package/docs/server/deployment.md +113 -0
- package/docs/server/security.md +196 -0
- package/docs/services/README.md +79 -0
- package/docs/services/RamStore.md +84 -0
- package/docs/services/Session.md +84 -0
- package/docs/services/Storage.md +88 -0
- package/docs/services/http.md +86 -0
- package/docs/tools/README.md +138 -0
- package/docs/tools/animation.md +87 -0
- package/docs/tools/async-ids-log.md +80 -0
- package/docs/tools/device.md +132 -0
- package/docs/tools/introspection.md +67 -0
- package/docs/tools/lists.md +96 -0
- package/docs/tools/markdown.md +79 -0
- package/docs/tools/reactivity.md +288 -0
- package/docs/tools/state.md +103 -0
- package/docs/tools/styling.md +92 -0
- package/docs/tools/text-and-time.md +89 -0
- package/docs/tools/theme.md +102 -0
- package/docs/tools/validation.md +75 -0
- package/docs/tools/visual-effects.md +84 -0
- package/docs/widget/Accordion.md +144 -0
- package/docs/widget/AdMob.md +144 -0
- package/docs/widget/AdSense.md +133 -0
- package/docs/widget/AdaptiveScaffold.md +105 -0
- package/docs/widget/AlertDialog.md +103 -0
- package/docs/widget/AnimatedBox.md +130 -0
- package/docs/widget/AnimatedText.md +123 -0
- package/docs/widget/AppBar.md +118 -0
- package/docs/widget/Audio.md +135 -0
- package/docs/widget/Avatar.md +119 -0
- package/docs/widget/Badge.md +128 -0
- package/docs/widget/BottomNavigation.md +116 -0
- package/docs/widget/BottomSheet.md +125 -0
- package/docs/widget/Button.md +137 -0
- package/docs/widget/COMMON_PROPS.md +150 -0
- package/docs/widget/Card.md +125 -0
- package/docs/widget/Carousel.md +151 -0
- package/docs/widget/Chart.md +151 -0
- package/docs/widget/Checkbox.md +118 -0
- package/docs/widget/Chip.md +126 -0
- package/docs/widget/CircularBar.md +168 -0
- package/docs/widget/CircularChart.md +164 -0
- package/docs/widget/CodeViewer.md +130 -0
- package/docs/widget/CollapsibleSideBar.md +112 -0
- package/docs/widget/Column.md +129 -0
- package/docs/widget/Container.md +136 -0
- package/docs/widget/DataTable.md +150 -0
- package/docs/widget/Divider.md +109 -0
- package/docs/widget/DraggBox.md +129 -0
- package/docs/widget/Drawer.md +135 -0
- package/docs/widget/DrawerItem.md +98 -0
- package/docs/widget/Dropdown.md +139 -0
- package/docs/widget/DroppBox.md +152 -0
- package/docs/widget/FloatingActionButton.md +120 -0
- package/docs/widget/GridView.md +140 -0
- package/docs/widget/Icon.md +117 -0
- package/docs/widget/Image.md +125 -0
- package/docs/widget/Input.md +151 -0
- package/docs/widget/Inspector.md +92 -0
- package/docs/widget/InstallButton.md +128 -0
- package/docs/widget/ListTile.md +132 -0
- package/docs/widget/ListView.md +138 -0
- package/docs/widget/Markdown.md +175 -0
- package/docs/widget/MatrixRain.md +122 -0
- package/docs/widget/Modal.md +129 -0
- package/docs/widget/Pagination.md +135 -0
- package/docs/widget/ParallaxBox.md +128 -0
- package/docs/widget/ProgressBar.md +130 -0
- package/docs/widget/QRCode.md +117 -0
- package/docs/widget/README.md +188 -0
- package/docs/widget/Radio.md +123 -0
- package/docs/widget/Rating.md +131 -0
- package/docs/widget/Row.md +131 -0
- package/docs/widget/START_HERE.md +146 -0
- package/docs/widget/Scaffold.md +152 -0
- package/docs/widget/Skeleton.md +130 -0
- package/docs/widget/Slider.md +146 -0
- package/docs/widget/SnackBar.md +102 -0
- package/docs/widget/Stack.md +128 -0
- package/docs/widget/Stepper.md +145 -0
- package/docs/widget/Switch.md +118 -0
- package/docs/widget/Tabs.md +124 -0
- package/docs/widget/Text.md +133 -0
- package/docs/widget/Tooltip.md +145 -0
- package/docs/widget/TreeView.md +176 -0
- package/docs/widget/Video.md +127 -0
- package/docs/widget/_template.md +61 -0
- package/package.json +3 -2
- package/src/animations/animate.js +180 -70
- package/src/animations/index.js +1 -0
- package/src/create-index.sh +1 -1
- package/src/index.d.ts +45 -22
- package/src/index.js +1 -0
- package/src/navigations/AdaptiveScaffold.js +11 -2
- package/src/navigations/BottomNavigation.js +10 -3
- package/src/navigations/Tabs.js +6 -2
- package/src/tools/useState.js +54 -63
- package/src/widget-factory/assignProps.js +23 -1
- package/src/widget-factory/processProps.js +10 -3
- package/src/widget-factory/reactiveValue.js +43 -18
- package/src/widget-factory/translateProps.js +777 -901
- package/src/widgets/AlertDialog.js +7 -5
- package/src/widgets/Checkbox.js +9 -7
- package/src/widgets/CircularBar.js +12 -1
- package/src/widgets/FloatingActionButton.js +4 -7
- package/src/widgets/Image.js +5 -7
- package/src/widgets/Input.js +92 -0
- package/src/widgets/ListView.js +73 -29
- package/src/widgets/Pagination.js +6 -3
- package/src/widgets/ProgressBar.js +16 -13
- package/src/widgets/Radio.js +6 -7
- package/src/widgets/Slider.js +23 -4
- package/src/widgets/Stack.js +36 -3
- package/src/widgets/Stepper.js +4 -3
- package/src/widgets/Switch.js +3 -4
- package/src/widgets/TreeView.js +0 -1
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
# Authentication and security
|
|
2
|
+
|
|
3
|
+
## Start securely
|
|
4
|
+
|
|
5
|
+
Use `runSecureServer()` as the default starting point for a real API:
|
|
6
|
+
|
|
7
|
+
```javascript
|
|
8
|
+
import { Api, runSecureServer } from "flet-box-server";
|
|
9
|
+
|
|
10
|
+
const routes = Api({
|
|
11
|
+
"/health": { GET: () => ({ ok: true }) },
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
runSecureServer(routes, {
|
|
15
|
+
port: 3000,
|
|
16
|
+
docs: true,
|
|
17
|
+
rateLimit: { max: 100, windowMs: 60_000 },
|
|
18
|
+
});
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
This enables security middleware, input cleaning, validation, malicious-content blocking, and rate limiting according to the server options.
|
|
22
|
+
|
|
23
|
+
## JWT login
|
|
24
|
+
|
|
25
|
+
The security database supports a password grant through a token handler. A development login request looks like this:
|
|
26
|
+
|
|
27
|
+
```javascript
|
|
28
|
+
const response = await fetch("http://localhost:3000/login", {
|
|
29
|
+
method: "POST",
|
|
30
|
+
headers: { "Content-Type": "application/json" },
|
|
31
|
+
body: JSON.stringify({
|
|
32
|
+
grant_type: "password",
|
|
33
|
+
username: process.env.ADMIN_USERNAME,
|
|
34
|
+
password: process.env.ADMIN_PASSWORD,
|
|
35
|
+
}),
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
const { access_token } = await response.json();
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
Send the token with protected requests:
|
|
42
|
+
|
|
43
|
+
```javascript
|
|
44
|
+
fetch("http://localhost:3000/private", {
|
|
45
|
+
headers: {
|
|
46
|
+
Authorization: `Bearer ${access_token}`,
|
|
47
|
+
},
|
|
48
|
+
});
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
## Protect a route
|
|
52
|
+
|
|
53
|
+
```javascript
|
|
54
|
+
import { authenticate } from "flet-box-server";
|
|
55
|
+
|
|
56
|
+
const routes = Api({
|
|
57
|
+
"/private": {
|
|
58
|
+
GET: {
|
|
59
|
+
handler: ({ req }) => ({
|
|
60
|
+
user: req.user,
|
|
61
|
+
secret: "private data",
|
|
62
|
+
}),
|
|
63
|
+
middleware: [authenticate],
|
|
64
|
+
},
|
|
65
|
+
},
|
|
66
|
+
});
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
`authenticate` rejects missing or invalid bearer tokens with status `401` and adds the verified payload to `req.user`.
|
|
70
|
+
|
|
71
|
+
## Roles
|
|
72
|
+
|
|
73
|
+
Use `hasRole()` after authentication:
|
|
74
|
+
|
|
75
|
+
```javascript
|
|
76
|
+
import { authenticate, hasRole } from "flet-box-server";
|
|
77
|
+
|
|
78
|
+
const routes = Api({
|
|
79
|
+
"/admin": {
|
|
80
|
+
GET: {
|
|
81
|
+
handler: () => ({ area: "admin" }),
|
|
82
|
+
middleware: [authenticate, hasRole("admin")],
|
|
83
|
+
},
|
|
84
|
+
},
|
|
85
|
+
});
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
A user must be authenticated before roles can be checked.
|
|
89
|
+
|
|
90
|
+
## Optional authentication
|
|
91
|
+
|
|
92
|
+
Use `optionalAuth` when a route works for visitors but can provide extra data to logged-in users:
|
|
93
|
+
|
|
94
|
+
```javascript
|
|
95
|
+
import { optionalAuth } from "flet-box-server";
|
|
96
|
+
|
|
97
|
+
middleware: [optionalAuth]
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
## Input sanitization
|
|
101
|
+
|
|
102
|
+
`securityCheck` can:
|
|
103
|
+
|
|
104
|
+
- Check blocked IPs, paths, and user agents.
|
|
105
|
+
- Sanitize request body, query, and path parameters.
|
|
106
|
+
- Apply security headers.
|
|
107
|
+
- Apply CORS rules.
|
|
108
|
+
|
|
109
|
+
Do not treat sanitization as a replacement for validation. Validate the expected type and business rules too.
|
|
110
|
+
|
|
111
|
+
## Malicious-content blocking
|
|
112
|
+
|
|
113
|
+
`blockMalicious` checks body, params, and query values against known suspicious patterns and returns `403` when a pattern is detected.
|
|
114
|
+
|
|
115
|
+
Use it as route middleware when appropriate:
|
|
116
|
+
|
|
117
|
+
```javascript
|
|
118
|
+
middleware: [authenticate, blockMalicious, securityCheck]
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
False positives are possible. Review the accepted input for your application instead of blindly allowing all content.
|
|
122
|
+
|
|
123
|
+
## Schema validation
|
|
124
|
+
|
|
125
|
+
Use `SchemaValidator` for explicit validation:
|
|
126
|
+
|
|
127
|
+
```javascript
|
|
128
|
+
import { SchemaValidator } from "flet-box-server";
|
|
129
|
+
|
|
130
|
+
const validator = new SchemaValidator({
|
|
131
|
+
name: { type: "string", required: true, minLength: 2 },
|
|
132
|
+
age: { type: "number", min: 0 },
|
|
133
|
+
email: { type: "email", required: true },
|
|
134
|
+
});
|
|
135
|
+
|
|
136
|
+
const result = validator.validate({
|
|
137
|
+
name: "Ada",
|
|
138
|
+
age: 36,
|
|
139
|
+
email: "ada@example.com",
|
|
140
|
+
});
|
|
141
|
+
|
|
142
|
+
if (!result.valid) {
|
|
143
|
+
console.log(result.errors);
|
|
144
|
+
}
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
Supported validation concepts include strings, numbers, booleans, email, URL, date, UUID, arrays, objects, required fields, ranges, lengths, enums, defaults, and custom patterns.
|
|
148
|
+
|
|
149
|
+
## Rate limiting
|
|
150
|
+
|
|
151
|
+
Create a route limiter:
|
|
152
|
+
|
|
153
|
+
```javascript
|
|
154
|
+
import { rateLimit } from "flet-box-server";
|
|
155
|
+
|
|
156
|
+
const limiter = rateLimit({
|
|
157
|
+
max: 10,
|
|
158
|
+
windowMs: 60_000,
|
|
159
|
+
message: "Too many requests",
|
|
160
|
+
});
|
|
161
|
+
|
|
162
|
+
const routes = Api({
|
|
163
|
+
"/login": {
|
|
164
|
+
POST: {
|
|
165
|
+
handler: login,
|
|
166
|
+
middleware: [limiter],
|
|
167
|
+
},
|
|
168
|
+
},
|
|
169
|
+
});
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
For multiple server instances, use a shared store such as Redis rather than only an in-memory map.
|
|
173
|
+
|
|
174
|
+
## Security headers and CORS
|
|
175
|
+
|
|
176
|
+
`securityCheck` applies headers such as content-type protection, frame protection, referrer policy, and content security policy.
|
|
177
|
+
|
|
178
|
+
CORS origins can be configured with the environment variable:
|
|
179
|
+
|
|
180
|
+
```bash
|
|
181
|
+
CORS_ORIGINS=https://my-app.example.com,https://admin.example.com
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
Avoid `*` with credentials in production. Use an explicit allowlist.
|
|
185
|
+
|
|
186
|
+
## Production checklist
|
|
187
|
+
|
|
188
|
+
- Set a long random `JWT_SECRET`.
|
|
189
|
+
- Remove hardcoded admin users and passwords.
|
|
190
|
+
- Never commit SMTP, Twilio, Redis, or cloud credentials.
|
|
191
|
+
- Use HTTPS.
|
|
192
|
+
- Restrict CORS origins.
|
|
193
|
+
- Enable validation and rate limiting.
|
|
194
|
+
- Review sanitization false positives.
|
|
195
|
+
- Store verification codes and sessions in a shared store when scaling.
|
|
196
|
+
- Log security events without logging passwords or tokens.
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
# Services: FletBox data & network helpers
|
|
2
|
+
|
|
3
|
+
This directory is the reference index for the services that ship with FletBox — the helpers that connect your app to the **outside world**: browser storage and the network.
|
|
4
|
+
|
|
5
|
+
Services are plain JavaScript functions and objects. You import them from `flet-box`:
|
|
6
|
+
|
|
7
|
+
```javascript
|
|
8
|
+
import { saveData, getData, httpGet, subscribeRam } from "flet-box";
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
> **Services vs. Tools.** *Services* talk to the outside world (storage, network) and may be async or stateful. *Tools* are pure helpers that turn input into a value. Find tools in the [tools index](../tools/README.md).
|
|
12
|
+
|
|
13
|
+
For a task-oriented walkthrough of the three storage layers, read the [Frontend services guide](../guides/frontend-services.md). This index lists everything the framework actually exports today, grouped by layer, and **links to a full reference page for each layer** (every function with its signature and return value). The implementation lives in `src/services/` and every name below is present in `src/index.js`.
|
|
14
|
+
|
|
15
|
+
## The four layers
|
|
16
|
+
|
|
17
|
+
| Page | Layer | Lifetime |
|
|
18
|
+
| --- | --- | --- |
|
|
19
|
+
| [RamStore](RamStore.md) | In-memory reactive state (backs `useState`) | While the page runs |
|
|
20
|
+
| [Session](Session.md) | `sessionStorage` | The tab session |
|
|
21
|
+
| [Storage](Storage.md) | `localStorage` | Until cleared |
|
|
22
|
+
| [HTTP client](http.md) | `fetch`-based network calls | Per request |
|
|
23
|
+
|
|
24
|
+
## RamStore — in-memory reactive state
|
|
25
|
+
|
|
26
|
+
RAM storage, alive while the page runs. Backs `useState`'s keys.
|
|
27
|
+
|
|
28
|
+
- `RamStore` — class/instance access.
|
|
29
|
+
- `saveRam(key, value)`, `getRam(key)`, `getAllRam()`, `getAllRamKeys()`, `hasRam(key)`, `updateRam(key, value)`, `deleteRam(key)`, `clearAllRam()`, `getRamItemCount()`, `isRamAvailable()`.
|
|
30
|
+
- `subscribeRam(callback)` — subscribe to any RAM change; returns an unsubscribe function.
|
|
31
|
+
|
|
32
|
+
> Full detail, examples, and notes → [RamStore reference](RamStore.md).
|
|
33
|
+
|
|
34
|
+
## Session — tab-scoped storage
|
|
35
|
+
|
|
36
|
+
Backed by `sessionStorage`: lives for the tab session, lost when the tab closes.
|
|
37
|
+
|
|
38
|
+
- `Session` — class/instance access.
|
|
39
|
+
- `saveSession(key, value)` (async), `getSession(key)` (async), `getSessionSync(key)`, `updateSession(key, value)`, `deleteSession(key)`, `clearAllSession()`, `hasSession(key)`, `getAllSessionKeys()`, `getAllSessionData()`, `getSessionSize()`, `deleteSessionByPrefix(prefix)`, `deleteSessionBySuffix(suffix)`, `getSessionItemCount()`, `isSessionAvailable()`.
|
|
40
|
+
|
|
41
|
+
> Full detail, examples, and notes → [Session reference](Session.md).
|
|
42
|
+
|
|
43
|
+
## Storage — persistent data
|
|
44
|
+
|
|
45
|
+
Backed by `localStorage`: survives browser restarts until cleared.
|
|
46
|
+
|
|
47
|
+
- `Storage` — class/instance access.
|
|
48
|
+
- `saveData(key, value)` (async), `getData(key)` (async), `getDataSync(key)`, `updateData(key, value)`, `deleteData(key)`, `clearAllData()`, `hasData(key)`, `getAllKeys()`, `getAllData()`, `getStorageSize()`, `deleteDataByPrefix(prefix)`, `deleteDataBySuffix(suffix)`, `getItemCount()`, `isStorageAvailable()`.
|
|
49
|
+
|
|
50
|
+
> Full detail, examples, and notes → [Storage reference](Storage.md).
|
|
51
|
+
|
|
52
|
+
## HTTP client
|
|
53
|
+
|
|
54
|
+
A small `fetch`-based client.
|
|
55
|
+
|
|
56
|
+
- `httpGet(url, options)`, `httpPost(url, options)`, `httpPut(url, options)`, `httpPatch(url, options)`, `httpDelete(url, options)` — all take a single options object with `body`, `params`, `headers`, and `timeout`.
|
|
57
|
+
- `httpRequest(method, url, options)` — generic request; see `HttpRequestOptions` in `src/index.d.ts`.
|
|
58
|
+
|
|
59
|
+
> Full detail, examples, and notes → [HTTP reference](http.md).
|
|
60
|
+
|
|
61
|
+
> **Security.** Never store passwords, private keys, or security secrets in any of these services. Browser storage is readable by anyone with access to the device, and any token in frontend code is visible to the user. Protect sensitive data with server-side authorization.
|
|
62
|
+
|
|
63
|
+
## Where to go next
|
|
64
|
+
|
|
65
|
+
- [Frontend services guide](../guides/frontend-services.md) — the practical walkthrough for storage and HTTP.
|
|
66
|
+
- [Guides index](../guides/README.md) — every FletBox guide in reading order.
|
|
67
|
+
- [State guide](../guides/state.md) — `useState` and RAM-backed reactivity.
|
|
68
|
+
- [Tools index](../tools/README.md) — the pure helper functions.
|
|
69
|
+
- [Widgets](../widget/README.md) — the widget book.
|
|
70
|
+
|
|
71
|
+
---
|
|
72
|
+
|
|
73
|
+
## Continue reading
|
|
74
|
+
|
|
75
|
+
- **Previous:** [Frontend services guide](../guides/frontend-services.md)
|
|
76
|
+
- **Next:** [RamStore](RamStore.md)
|
|
77
|
+
- **Index:** [Guides index](../guides/README.md) · [The FletBox Book](../README.md)
|
|
78
|
+
|
|
79
|
+
You are reading **Chapter 9 · State, Router & Services** (chapter opener).
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
# RamStore
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
`RamStore` is the **in-memory** reactive store. It keeps data in a JavaScript `Map` while the page is open, notifies subscribers when any key changes, and powers `useState` under the hood. Everything is lost when the page reloads — that is its job.
|
|
5
|
+
|
|
6
|
+
## When to use
|
|
7
|
+
- Share live values between widgets (the state engine behind `useState`).
|
|
8
|
+
- Keep temporary UI data — form steps, current filters, draft objects — that must disappear on reload.
|
|
9
|
+
|
|
10
|
+
## Import
|
|
11
|
+
|
|
12
|
+
```javascript
|
|
13
|
+
import { saveRam, getRam, subscribeRam, RamStore } from "flet-box";
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
Every function also exists as a method of the exported `RamStore` object, for an object-style API.
|
|
17
|
+
|
|
18
|
+
## Functions
|
|
19
|
+
|
|
20
|
+
| Function | Signature | Returns | Description |
|
|
21
|
+
| --- | --- | --- | --- |
|
|
22
|
+
| `saveRam` | `saveRam(key, value)` | `boolean` | Store or replace `value` under `key` and notify subscribers. |
|
|
23
|
+
| `getRam` | `getRam(key)` | `T \| null` | Read the value, or `null` if the key does not exist. |
|
|
24
|
+
| `getAllRam` | `getAllRam()` | `Record<string, any>` | Every stored key/value pair. |
|
|
25
|
+
| `getAllRamKeys` | `getAllRamKeys()` | `string[]` | All stored keys. |
|
|
26
|
+
| `hasRam` | `hasRam(key)` | `boolean` | Is the key present? |
|
|
27
|
+
| `updateRam` | `updateRam(key, value)` | `boolean` | Replace the value (same as `saveRam`). |
|
|
28
|
+
| `deleteRam` | `deleteRam(key)` | `boolean` | Remove a key. |
|
|
29
|
+
| `clearAllRam` | `clearAllRam()` | `boolean` | Remove everything. |
|
|
30
|
+
| `subscribeRam` | `subscribeRam(callback)` | `() => void` | Subscribe to changes, returns an unsubscribe function. |
|
|
31
|
+
| `getRamItemCount` | `getRamItemCount()` | `number` | How many keys are stored. |
|
|
32
|
+
| `isRamAvailable` | `isRamAvailable()` | `boolean` | Always `true` in a browser; kept for API symmetry with the other stores. |
|
|
33
|
+
|
|
34
|
+
The subscribe callback receives `(key, newValue, oldValue)`. Use your stored key as the first argument to filter.
|
|
35
|
+
|
|
36
|
+
## Examples
|
|
37
|
+
|
|
38
|
+
### Everyday example
|
|
39
|
+
|
|
40
|
+
```javascript
|
|
41
|
+
import { saveRam, getRam } from "flet-box";
|
|
42
|
+
|
|
43
|
+
saveRam("cart", [{ id: 1 }, { id: 2 }]);
|
|
44
|
+
const cart = getRam("cart");
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
### Full example
|
|
48
|
+
|
|
49
|
+
```javascript
|
|
50
|
+
import { saveRam, subscribeRam, deleteRam } from "flet-box";
|
|
51
|
+
|
|
52
|
+
const unsubscribe = subscribeRam((key, newValue, oldValue) => {
|
|
53
|
+
console.log(`${key}: ${oldValue} → ${newValue}`);
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
saveRam("theme", "dark"); // logs: theme: null → dark
|
|
57
|
+
deleteRam("theme"); // logs: theme: dark → null
|
|
58
|
+
|
|
59
|
+
// stop listening:
|
|
60
|
+
unsubscribe();
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
## Notes
|
|
64
|
+
|
|
65
|
+
- This is the store behind `useState`. When you call `setCount(...)`, FletBox saves through `RamStore` and re-renders registered widgets.
|
|
66
|
+
- Values can be any JSON-safe data: strings, numbers, booleans, arrays, objects.
|
|
67
|
+
- There is no expiration and no persistence. For data that survives a reload, use [Storage](Storage.md).
|
|
68
|
+
- Synchronous and dependency-free: subscribe handlers run in order and errors in one handler never break the others.
|
|
69
|
+
|
|
70
|
+
## Related pages
|
|
71
|
+
- [Session](Session.md) — tab-scoped persistence.
|
|
72
|
+
- [Storage](Storage.md) — persistent storage.
|
|
73
|
+
- [Frontend services guide](../guides/frontend-services.md) — choosing a storage layer.
|
|
74
|
+
- [State guide](../guides/state.md) — `useState` and reactivity.
|
|
75
|
+
|
|
76
|
+
---
|
|
77
|
+
|
|
78
|
+
## Continue reading
|
|
79
|
+
|
|
80
|
+
- **Previous:** [Services index](README.md)
|
|
81
|
+
- **Next:** [Session](Session.md)
|
|
82
|
+
- **Index:** [Services index](README.md) · [The FletBox Book](../README.md)
|
|
83
|
+
|
|
84
|
+
You are reading **Chapter 9 · State, Router & Services** (1 of 4).
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
# Session
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
`Session` is the **tab-scoped** store, backed by `sessionStorage`. Data lives while the tab is open and disappears when the tab or the browser closes. It works with strings, numbers, booleans, arrays, and objects.
|
|
5
|
+
|
|
6
|
+
## When to use
|
|
7
|
+
- Remember something for "this visit only": a cart while the user is on the page, a wizard step, a temporary token (see the security note).
|
|
8
|
+
- Keep data between multiple widgets that must not survive a full page reload more than once.
|
|
9
|
+
|
|
10
|
+
## Import
|
|
11
|
+
|
|
12
|
+
```javascript
|
|
13
|
+
import { saveSession, getSession, Session } from "flet-box";
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
Every function also exists as a method of the exported `Session` object. The API mirrors [RamStore](RamStore.md) and [Storage](Storage.md) so you can swap the layer without rewriting your calls.
|
|
17
|
+
|
|
18
|
+
## Functions
|
|
19
|
+
|
|
20
|
+
| Function | Signature | Returns | Description |
|
|
21
|
+
| --- | --- | --- | --- |
|
|
22
|
+
| `saveSession` | `saveSession(key, value)` | `boolean` | Store `value` under `key` in `sessionStorage`. |
|
|
23
|
+
| `getSession` | `getSession(key)` | `T \| null` | Read the value (async-safe wrapper). |
|
|
24
|
+
| `getSessionSync` | `getSessionSync(key)` | `T \| null` | Read the value synchronously. |
|
|
25
|
+
| `updateSession` | `updateSession(key, value)` | `boolean` | Replace the value. |
|
|
26
|
+
| `deleteSession` | `deleteSession(key)` | `boolean` | Remove one key. |
|
|
27
|
+
| `clearAllSession` | `clearAllSession()` | `boolean` | Remove every key for this tab session. |
|
|
28
|
+
| `hasSession` | `hasSession(key)` | `boolean` | Is the key present? |
|
|
29
|
+
| `getAllSessionKeys` | `getAllSessionKeys()` | `string[]` | All stored keys. |
|
|
30
|
+
| `getAllSessionData` | `getAllSessionData()` | `Record<string, any>` | Every key/value pair. |
|
|
31
|
+
| `getSessionSize` | `getSessionSize()` | `number` | Approximate size in bytes. |
|
|
32
|
+
| `deleteSessionByPrefix` | `deleteSessionByPrefix(prefix)` | `number` | Delete every key starting with `prefix`; returns the count. |
|
|
33
|
+
| `deleteSessionBySuffix` | `deleteSessionBySuffix(suffix)` | `number` | Delete every key ending with `suffix`; returns the count. |
|
|
34
|
+
| `getSessionItemCount` | `getSessionItemCount()` | `number` | How many keys are stored. |
|
|
35
|
+
| `isSessionAvailable` | `isSessionAvailable()` | `boolean` | Is `sessionStorage` available? |
|
|
36
|
+
|
|
37
|
+
## Examples
|
|
38
|
+
|
|
39
|
+
### Everyday example
|
|
40
|
+
|
|
41
|
+
```javascript
|
|
42
|
+
import { saveSession, getSession } from "flet-box";
|
|
43
|
+
|
|
44
|
+
saveSession("wizard-step", 3);
|
|
45
|
+
const step = getSession("wizard-step");
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
### Full example
|
|
49
|
+
|
|
50
|
+
```javascript
|
|
51
|
+
import { saveSession, getSessionSync, deleteSessionByPrefix } from "flet-box";
|
|
52
|
+
|
|
53
|
+
saveSession("form.name", "Ada");
|
|
54
|
+
saveSession("form.age", 36);
|
|
55
|
+
saveSession("draft-note", "hello");
|
|
56
|
+
|
|
57
|
+
getSessionSync("form.name"); // "Ada"
|
|
58
|
+
|
|
59
|
+
// remove all dashboard form keys at once:
|
|
60
|
+
const removed = deleteSessionByPrefix("form.");
|
|
61
|
+
console.log(removed); // 2
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
## Notes
|
|
65
|
+
|
|
66
|
+
- `sessionStorage` survives a *refresh* (F5) but not a new tab or a closed browser.
|
|
67
|
+
- Objects and arrays are serialized (and restored) as JSON automatically.
|
|
68
|
+
- Use `getSessionSync` inside hot paths where you cannot wait for a promise.
|
|
69
|
+
- **Security.** Never store passwords, private keys, or security tokens in browser storage — it is readable by anyone with access to the device. Protect sensitive data with server-side authorization.
|
|
70
|
+
|
|
71
|
+
## Related pages
|
|
72
|
+
- [RamStore](RamStore.md) — the in-memory reactive store.
|
|
73
|
+
- [Storage](Storage.md) — persistent storage.
|
|
74
|
+
- [Frontend services guide](../guides/frontend-services.md) — choosing a storage layer.
|
|
75
|
+
|
|
76
|
+
---
|
|
77
|
+
|
|
78
|
+
## Continue reading
|
|
79
|
+
|
|
80
|
+
- **Previous:** [RamStore](RamStore.md)
|
|
81
|
+
- **Next:** [Storage](Storage.md)
|
|
82
|
+
- **Index:** [Services index](README.md) · [The FletBox Book](../README.md)
|
|
83
|
+
|
|
84
|
+
You are reading **Chapter 9 · State, Router & Services** (2 of 4).
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
# Storage
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
`Storage` is the **persistent** store, backed by `localStorage`. Data survives browser restarts until it is cleared — this is the layer for preferences, drafts, or saved documents. It works with strings, numbers, booleans, arrays, and objects.
|
|
5
|
+
|
|
6
|
+
## When to use
|
|
7
|
+
- Remember settings and user data between visits.
|
|
8
|
+
- Cache what the user has written (drafts, recent items) across reloads.
|
|
9
|
+
- Pair with [Session](Session.md) for short-lived data and [RamStore](RamStore.md) for live reactive state.
|
|
10
|
+
|
|
11
|
+
## Import
|
|
12
|
+
|
|
13
|
+
```javascript
|
|
14
|
+
import { saveData, getData, Storage } from "flet-box";
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
Every function also exists as a method of the exported `Storage` object. The API mirrors [RamStore](RamStore.md) and [Session](Session.md) so you can swap the layer without rewriting your calls.
|
|
18
|
+
|
|
19
|
+
## Functions
|
|
20
|
+
|
|
21
|
+
| Function | Signature | Returns | Description |
|
|
22
|
+
| --- | --- | --- | --- |
|
|
23
|
+
| `saveData` | `saveData(key, value)` | `boolean` | Persist `value` under `key` in `localStorage`. |
|
|
24
|
+
| `getData` | `getData(key)` | `T \| null` | Read the value (async-safe wrapper). |
|
|
25
|
+
| `getDataSync` | `getDataSync(key)` | `T \| null` | Read the value synchronously. |
|
|
26
|
+
| `updateData` | `updateData(key, value)` | `boolean` | Replace the value. |
|
|
27
|
+
| `deleteData` | `deleteData(key)` | `boolean` | Remove one key. |
|
|
28
|
+
| `clearAllData` | `clearAllData()` | `boolean` | Remove every key. |
|
|
29
|
+
| `hasData` | `hasData(key)` | `boolean` | Is the key present? |
|
|
30
|
+
| `getAllKeys` | `getAllKeys()` | `string[]` | All stored keys. |
|
|
31
|
+
| `getAllData` | `getAllData()` | `Record<string, any>` | Every key/value pair. |
|
|
32
|
+
| `getStorageSize` | `getStorageSize()` | `number` | Approximate size in bytes. |
|
|
33
|
+
| `deleteDataByPrefix` | `deleteDataByPrefix(prefix)` | `number` | Delete every key starting with `prefix`; returns the count. |
|
|
34
|
+
| `deleteDataBySuffix` | `deleteDataBySuffix(suffix)` | `number` | Delete every key ending with `suffix`; returns the count. |
|
|
35
|
+
| `getItemCount` | `getItemCount()` | `number` | How many keys are stored. |
|
|
36
|
+
| `isStorageAvailable` | `isStorageAvailable()` | `boolean` | Is `localStorage` available? |
|
|
37
|
+
|
|
38
|
+
## Examples
|
|
39
|
+
|
|
40
|
+
### Everyday example
|
|
41
|
+
|
|
42
|
+
```javascript
|
|
43
|
+
import { saveData, getData } from "flet-box";
|
|
44
|
+
|
|
45
|
+
saveData("settings", { theme: "dark", fontSize: 18 });
|
|
46
|
+
const settings = getData("settings");
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
### Full example
|
|
50
|
+
|
|
51
|
+
```javascript
|
|
52
|
+
import { saveData, getDataSync, hasData, deleteDataByPrefix } from "flet-box";
|
|
53
|
+
|
|
54
|
+
if (!hasData("drafts")) {
|
|
55
|
+
saveData("drafts", []);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
saveData("drafts.1", "WIP chapter");
|
|
59
|
+
saveData("drafts.2", "README draft");
|
|
60
|
+
|
|
61
|
+
getDataSync("drafts.1"); // "WIP chapter"
|
|
62
|
+
|
|
63
|
+
// clean up this feature's keys:
|
|
64
|
+
deleteDataByPrefix("drafts.");
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
## Notes
|
|
68
|
+
|
|
69
|
+
- Data survives restarts and new tabs, until you remove it. It is shared across tabs of the same origin.
|
|
70
|
+
- Objects and arrays are serialized (and restored) as JSON automatically.
|
|
71
|
+
- `localStorage` is limited (about 5 MB per origin) and synchronous — keep the values small.
|
|
72
|
+
- Use `getDataSync` when you need the value immediately.
|
|
73
|
+
- **Security.** Never store passwords, private keys, or security tokens in browser storage — it is readable by anyone with access to the device. Protect sensitive data with server-side authorization.
|
|
74
|
+
|
|
75
|
+
## Related pages
|
|
76
|
+
- [RamStore](RamStore.md) — the in-memory reactive store.
|
|
77
|
+
- [Session](Session.md) — tab-scoped persistence.
|
|
78
|
+
- [Frontend services guide](../guides/frontend-services.md) — choosing a storage layer.
|
|
79
|
+
|
|
80
|
+
---
|
|
81
|
+
|
|
82
|
+
## Continue reading
|
|
83
|
+
|
|
84
|
+
- **Previous:** [Session](Session.md)
|
|
85
|
+
- **Next:** [HTTP client](http.md)
|
|
86
|
+
- **Index:** [Services index](README.md) · [The FletBox Book](../README.md)
|
|
87
|
+
|
|
88
|
+
You are reading **Chapter 9 · State, Router & Services** (3 of 4).
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
# HTTP client
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
FletBox ships a small `fetch`-based HTTP client. Five shortcuts — `httpGet`, `httpPost`, `httpPut`, `httpPatch`, `httpDelete` — and one generic function, `httpRequest`, handle requests with JSON bodies, query parameters, custom headers, and timeouts. Every call returns a `Promise`.
|
|
5
|
+
|
|
6
|
+
## When to use
|
|
7
|
+
- Talk to a REST API from your FletBox app.
|
|
8
|
+
- Stick to one consistent client instead of wrapping `fetch` yourself.
|
|
9
|
+
|
|
10
|
+
## Import
|
|
11
|
+
|
|
12
|
+
```javascript
|
|
13
|
+
import { httpGet, httpPost, httpRequest } from "flet-box";
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
## Options
|
|
17
|
+
|
|
18
|
+
`options` is an object (the type is `HttpRequestOptions`) that extends the browser `RequestInit`:
|
|
19
|
+
|
|
20
|
+
| Option | Type | Description |
|
|
21
|
+
| --- | --- | --- |
|
|
22
|
+
| `body` | any | Request body. Objects/arrays are JSON-stringified automatically when you pass them (set `Content-Type: application/json`). |
|
|
23
|
+
| `headers` | `Record<string, string>` | Extra headers merged with the defaults. |
|
|
24
|
+
| `params` | `Record<string, string \| number \| boolean \| null \| undefined>` | Query parameters appended to the URL. |
|
|
25
|
+
| `timeout` | number | Abort the request after this many ms. |
|
|
26
|
+
| …plus `RequestInit` | — | `method`, `credentials`, `mode`, `signal`, etc. |
|
|
27
|
+
|
|
28
|
+
## Functions
|
|
29
|
+
|
|
30
|
+
| Function | Signature | Returns | Description |
|
|
31
|
+
| --- | --- | --- | --- |
|
|
32
|
+
| `httpRequest` | `httpRequest(method, url, options?)` | `Promise<T>` | Any HTTP method with full options. |
|
|
33
|
+
| `httpGet` | `httpGet(url, options?)` | `Promise<T>` | `GET` shortcut. |
|
|
34
|
+
| `httpPost` | `httpPost(url, options?)` | `Promise<T>` | `POST` shortcut. |
|
|
35
|
+
| `httpPut` | `httpPut(url, options?)` | `Promise<T>` | `PUT` shortcut. |
|
|
36
|
+
| `httpPatch` | `httpPatch(url, options?)` | `Promise<T>` | `PATCH` shortcut. |
|
|
37
|
+
| `httpDelete` | `httpDelete(url, options?)` | `Promise<T>` | `DELETE` shortcut. |
|
|
38
|
+
|
|
39
|
+
## Examples
|
|
40
|
+
|
|
41
|
+
### Everyday example
|
|
42
|
+
|
|
43
|
+
```javascript
|
|
44
|
+
import { httpGet, httpPost } from "flet-box";
|
|
45
|
+
|
|
46
|
+
const users = await httpGet("/api/users");
|
|
47
|
+
const created = await httpPost("/api/users", {
|
|
48
|
+
body: { name: "Ada" },
|
|
49
|
+
headers: { "Content-Type": "application/json" },
|
|
50
|
+
});
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
### Full example
|
|
54
|
+
|
|
55
|
+
```javascript
|
|
56
|
+
import { httpGet } from "flet-box";
|
|
57
|
+
|
|
58
|
+
const result = await httpGet("https://api.example.com/search", {
|
|
59
|
+
params: { q: "fletbox", page: 1, perPage: 20 },
|
|
60
|
+
timeout: 8000, // give up after 8 seconds
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
console.log(result.items);
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
## Notes
|
|
67
|
+
|
|
68
|
+
- Responses are parsed as JSON automatically when possible.
|
|
69
|
+
- `params` values are appended as query strings; `null`/`undefined` values are skipped.
|
|
70
|
+
- A `timeout` aborts the request with an error once the time is reached.
|
|
71
|
+
- The client depends only on the browser `fetch` API — no external library.
|
|
72
|
+
|
|
73
|
+
## Related pages
|
|
74
|
+
- [Frontend services guide](../guides/frontend-services.md) — choosing storage vs. network.
|
|
75
|
+
- [Frontend services](../services/README.md) — the full services map.
|
|
76
|
+
- [Tools](../tools/README.md) — the helper functions (next chapter).
|
|
77
|
+
|
|
78
|
+
---
|
|
79
|
+
|
|
80
|
+
## Continue reading
|
|
81
|
+
|
|
82
|
+
- **Previous:** [Storage](Storage.md)
|
|
83
|
+
- **Next:** [Tools index](../tools/README.md) — Chapter 10
|
|
84
|
+
- **Index:** [Services index](README.md) · [The FletBox Book](../README.md)
|
|
85
|
+
|
|
86
|
+
You are reading **Chapter 9 · State, Router & Services** (4 of 4).
|