bff-store 0.1.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 (65) hide show
  1. package/.claude/settings.local.json +45 -0
  2. package/CONTEXT.md +53 -0
  3. package/README.md +223 -0
  4. package/dist/cli.js +32577 -0
  5. package/dist/index.d.mts +232 -0
  6. package/dist/index.d.ts +232 -0
  7. package/dist/index.mjs +430 -0
  8. package/dist/package.json +62 -0
  9. package/dist/server/entry.d.mts +94 -0
  10. package/dist/server/entry.d.ts +94 -0
  11. package/dist/server/entry.js +573 -0
  12. package/dist/server/entry.mjs +533 -0
  13. package/dist/server-V7WCW4ZB.mjs +530 -0
  14. package/dist/storage/jsonl-entry.d.mts +42 -0
  15. package/dist/storage/jsonl-entry.d.ts +42 -0
  16. package/dist/storage/jsonl-entry.js +112 -0
  17. package/dist/storage/jsonl-entry.mjs +74 -0
  18. package/dist/storage/mongodb-entry.d.mts +40 -0
  19. package/dist/storage/mongodb-entry.d.ts +40 -0
  20. package/dist/storage/mongodb-entry.js +114 -0
  21. package/dist/storage/mongodb-entry.mjs +86 -0
  22. package/docs/BUG_DIAGNOSIS_REMOTE_STORAGE_OPTIONS.md +104 -0
  23. package/docs/BUG_FIX_REMOTE_STORAGE_OPTIONS.md +63 -0
  24. package/docs/BUG_FIX_SESSION_2026-06-03.md +171 -0
  25. package/docs/IMPLEMENTATION.md +333 -0
  26. package/docs/PLAN.md +153 -0
  27. package/docs/REMOTE_STORAGE_CONFIG.md +125 -0
  28. package/docs/SIDECAR_SERVER.md +184 -0
  29. package/package.json +62 -0
  30. package/scripts/adapt-dist-package.js +33 -0
  31. package/src/atomCreator.ts +76 -0
  32. package/src/createStore.ts +77 -0
  33. package/src/debouncer.ts +84 -0
  34. package/src/index.ts +35 -0
  35. package/src/server/cli.ts +62 -0
  36. package/src/server/entityIdCache.ts +57 -0
  37. package/src/server/entry.ts +12 -0
  38. package/src/server/handlers.ts +271 -0
  39. package/src/server/index.ts +182 -0
  40. package/src/server/router.ts +74 -0
  41. package/src/server.ts +5 -0
  42. package/src/storage/adapters/remoteStorage.ts +70 -0
  43. package/src/storage/base.ts +28 -0
  44. package/src/storage/index.ts +9 -0
  45. package/src/storage/jsonl-entry.ts +9 -0
  46. package/src/storage/jsonl.ts +111 -0
  47. package/src/storage/memory.ts +49 -0
  48. package/src/storage/mongodb-entry.ts +9 -0
  49. package/src/storage/mongodb.ts +132 -0
  50. package/src/storage/protocol.ts +170 -0
  51. package/src/storage/transport.ts +95 -0
  52. package/src/types.ts +76 -0
  53. package/src/useStore.ts +83 -0
  54. package/tests/atomCreator.test.ts +153 -0
  55. package/tests/createStore.test.ts +126 -0
  56. package/tests/debouncer.test.ts +125 -0
  57. package/tests/server.test.ts +158 -0
  58. package/tests/storage/jsonl.test.ts +132 -0
  59. package/tests/storage/memory.test.ts +101 -0
  60. package/tests/storage/mongodb.test.ts +40 -0
  61. package/tests/storage/remoteStorage.test.ts +126 -0
  62. package/tests/useStore.test.tsx +147 -0
  63. package/tsconfig.json +18 -0
  64. package/tsup.config.ts +53 -0
  65. package/vitest.config.ts +14 -0
@@ -0,0 +1,45 @@
1
+ {
2
+ "permissions": {
3
+ "allow": [
4
+ "Bash(npm install:*)",
5
+ "Bash(npm run:*)",
6
+ "Bash(ls -la *.config.* vitest.config.*)",
7
+ "Bash(npm test:*)",
8
+ "Bash(ls -la vitest.config.*)",
9
+ "Bash(node -e ':*)",
10
+ "Bash(awk NR>=54 && NR<=95:*)",
11
+ "Bash(awk NR>=84 && NR<=131:*)",
12
+ "Bash(awk NR>=1 && NR<=35:*)",
13
+ "Bash(awk NR>=94 && NR<=120:*)",
14
+ "Bash(awk NR>=19 && NR<=65:*)",
15
+ "Bash(grep -l \"handlers\" /Users/Admin/Desktop/jotai-state-store/tests/*.ts)",
16
+ "Bash(xargs ls:*)",
17
+ "Bash(grep:*)",
18
+ "Bash(node:*)",
19
+ "Bash(npx vitest:*)",
20
+ "Bash(npx create-next-app@latest . --typescript --eslint --no-tailwind --app --src-dir --no-import-alias --use-npm)",
21
+ "Bash(npm link:*)",
22
+ "Bash(curl -s http://localhost:3847/health)",
23
+ "Bash(curl:*)",
24
+ "Read(//private/tmp/jotai-state-store-data/**)",
25
+ "Bash(cat /tmp/jotai-state-store-data/test-app/*.jsonl)",
26
+ "Bash(npx tsc:*)",
27
+ "Bash(ls /Users/Admin/Desktop/jotai-state-store/dist/*.d.ts)",
28
+ "Bash(npx tsup:*)",
29
+ "Bash(find /Users/Admin/Desktop/jotai-state-store/tests/next_test/node_modules -name \"package.json\" -path \"*/jotai-state-store/*\" -exec cat {} \\\\;)",
30
+ "Bash(find:*)",
31
+ "Bash(ls /Users/Admin/Desktop/jotai-state-store/dist/*.ts)",
32
+ "Read(//Users/Admin/node_modules/jotai-state-store/dist/**)",
33
+ "Bash(ls:*)",
34
+ "Bash(kill 89616)",
35
+ "Bash(python3 -c 'import urllib.parse; print\\(urllib.parse.quote\\(\"mongodb://admin:715705%40Qc123@localhost:27017/jotai_test?directConnection=true&authSource=admin\"\\)\\)')",
36
+ "Bash(python3 -c 'import urllib.parse.quote\\(\"mongodb://admin:715705%40Qc123@localhost:27017/jotai_test?directConnection=true&authSource=admin\"\\)\\)')",
37
+ "Read(//tmp/**)",
38
+ "Bash(kill 68874)",
39
+ "Bash(npm publish:*)",
40
+ "Bash(rg -rn \"jotai-state-store\" --type-list)",
41
+ "Bash(rg -rn \"jotai-state-store\" .)",
42
+ "Bash(xargs sed:*)"
43
+ ]
44
+ }
45
+ }
package/CONTEXT.md ADDED
@@ -0,0 +1,53 @@
1
+ # Domain Context
2
+
3
+ ## Core Concepts
4
+
5
+ ### Store (协调者)
6
+ The central coordinator that manages multiple persisted atoms. Created via `createStore()`, it holds:
7
+ - `entityId` - the unique identifier for this store instance
8
+ - `config` - the atom configuration array
9
+ - `atoms` - map of key → WritableAtom
10
+ - `loadingAtoms` - map of key → loading state atom
11
+
12
+ ### Atom Config (原子配置)
13
+ Configuration for a single persisted state field:
14
+ - `key` - unique identifier within the store
15
+ - `defaultValue` - initial value before loading from storage
16
+ - `type` - optional type hint ('string' | 'number' | 'boolean' | 'array' | 'object')
17
+ - `immediate` - if true, save immediately without debouncing
18
+
19
+ ### Storage Adapter (存储适配器)
20
+ The seam between the store and the underlying persistence layer. Implements the `Storage` interface and provides:
21
+ - `storage` - the Storage implementation
22
+ - `name` - identifier for the adapter type
23
+ - Optional lifecycle methods: `setEntityId()`, `close()`
24
+
25
+ ### Storage (存储接口)
26
+ The minimal interface for persistence:
27
+ - `get<T>(key)` - load value by key
28
+ - `set<T>(key, value)` - save value
29
+ - `remove(key)` - delete value
30
+ - Optional: `getMultiple()`, `setMultiple()` for batch operations
31
+
32
+ ### Debouncer (防抖器)
33
+ Manages delayed execution of save operations. Prevents excessive writes by:
34
+ - Buffering rapid changes
35
+ - Saving after a quiet period (default 800ms)
36
+ - Supporting immediate mode for critical data
37
+
38
+ ## Relationships
39
+
40
+ ```
41
+ Store (coordinates)
42
+ ├── config: AtomConfig[]
43
+ ├── atoms: Map<key, WritableAtom>
44
+ └── storage: StorageAdapter (seam to persistence)
45
+ └── storage: Storage (data interface)
46
+ ```
47
+
48
+ ## Setter Naming Convention
49
+
50
+ For an atom config with key `theme`:
51
+ - Value access: `store.atoms.theme.get()`
52
+ - Setter name: `setTheme` (derived via capitalize)
53
+ - Via hook: `{ theme, setTheme } = useStore(store)`
package/README.md ADDED
@@ -0,0 +1,223 @@
1
+ # bff-store
2
+
3
+ A jotai-based state management library with pluggable storage adapters and built-in BFF (Backend for Frontend) for browser/Next.js environments.
4
+
5
+ ## Features
6
+
7
+ - **Configuration-driven**: Define multiple states via array configuration
8
+ - **Pluggable storage**: Use memory, JSONL files, MongoDB, or remote server
9
+ - **Auto-generated hooks**: React hooks auto-generated from config
10
+ - **Loading states**: Built-in loading state tracking
11
+ - **Debounced saves**: Automatic debouncing for non-critical data
12
+ - **Built-in BFF**: Embedded sidecar API server for browser/Next.js environments
13
+
14
+ ## Architecture
15
+
16
+ ```
17
+ ┌─────────────────────────────────────────────────────────┐
18
+ │ Your Application │
19
+ │ (Next.js/Browser) │
20
+ │ │
21
+ │ useStore() ──► remoteStorage ──► localhost:3847 │
22
+ │ │ │
23
+ │ ▼ │
24
+ │ ┌─────────────────────┐ │
25
+ │ │ BFF (Sidecar) │ │
26
+ │ │ bff-store │ │
27
+ │ │ │ │
28
+ │ │ /storage/get/:key │ │
29
+ │ │ /storage/set/:key │ │
30
+ │ │ /storage/delete │ │
31
+ │ └──────────┬──────────┘ │
32
+ │ │ │
33
+ │ ▼ │
34
+ │ ┌─────────────────────┐ │
35
+ │ │ JSONL / MongoDB │ │
36
+ │ └─────────────────────┘ │
37
+ └─────────────────────────────────────────────────────────┘
38
+ ```
39
+
40
+ ## Installation
41
+
42
+ ```bash
43
+ npm install bff-store
44
+ # or
45
+ pnpm add bff-store
46
+ ```
47
+
48
+ ## Client Usage (Browser / Next.js)
49
+
50
+ BFF Server 会自动启动,客户端只需使用 `remoteStorage()` 并指定存储后端:
51
+
52
+ ```typescript
53
+ import { createStore, useStore, remoteStorage } from 'bff-store';
54
+
55
+ const config = [
56
+ { key: 'theme', defaultValue: 'dark' },
57
+ { key: 'characters', defaultValue: [] },
58
+ ] as const;
59
+
60
+ // 使用 MongoDB 存储
61
+ const store = createStore('my-app', config, {
62
+ storage: remoteStorage({
63
+ backend: 'mongodb',
64
+ mongoUrl: 'mongodb://user:pass@host:27017',
65
+ mongoDb: 'myapp',
66
+ }),
67
+ });
68
+
69
+ // 或使用 JSONL 存储
70
+ // const store = createStore('my-app', config, {
71
+ // storage: remoteStorage({
72
+ // backend: 'jsonl',
73
+ // jsonlDir: '/tmp/my-app-data',
74
+ // }),
75
+ // });
76
+ ```
77
+
78
+ ### 在 React 组件中使用
79
+
80
+ ```typescript
81
+ function App() {
82
+ const { theme, setTheme, isLoading } = useStore(store);
83
+
84
+ if (isLoading) return <div>Loading...</div>;
85
+
86
+ return <input value={theme} onChange={e => setTheme(e.target.value)} />;
87
+ }
88
+ ```
89
+
90
+ ### 自定义 BFF 服务器地址
91
+
92
+ ```typescript
93
+ // 如果 BFF 运行在其他地址
94
+ const adapter = remoteStorage({ baseUrl: 'http://localhost:3847' });
95
+ const adapter = remoteStorage({ entityId: 'user-123' }); // 多租户支持
96
+ ```
97
+
98
+ ### Memory Storage (不持久化)
99
+
100
+ 适用于开发环境或不需要持久化的场景:
101
+
102
+ ```typescript
103
+ import { createStore, useStore, memoryStorage } from 'bff-store';
104
+
105
+ const store = createStore('my-app', config, {
106
+ storage: memoryStorage(), // 不走 BFF,数据仅存在内存
107
+ });
108
+ ```
109
+
110
+ ## Advanced: 手动启动 BFF Server
111
+
112
+ 大多数情况不需要手动启动 BFF,它会自动启动。如需手动控制:
113
+
114
+ ```typescript
115
+ import { startServer } from 'bff-store/server';
116
+
117
+ await startServer({
118
+ port: 3847,
119
+ });
120
+ ```
121
+
122
+ ## Node.js 直接使用 Storage Adapters
123
+
124
+ 如果不通过 BFF,可以直接在 Node.js 中使用存储适配器:
125
+
126
+ ```typescript
127
+ import { createStore } from 'bff-store';
128
+ import { jsonlStorage } from 'bff-store/jsonl';
129
+ import { mongodbStorage } from 'bff-store/mongodb';
130
+
131
+ // 使用 JSONL
132
+ const adapter = jsonlStorage({ dir: './sessions' });
133
+
134
+ // 使用 MongoDB
135
+ const adapter = await mongodbStorage({
136
+ url: 'mongodb://localhost:27017',
137
+ database: 'myapp',
138
+ });
139
+
140
+ const store = createStore('entity-123', config, { storage: adapter });
141
+ ```
142
+
143
+ ## API Endpoints (BFF Server)
144
+
145
+ | Method | Endpoint | Body | Description |
146
+ |--------|----------|------|-------------|
147
+ | GET | `/storage/get/:key?entityId=x` | - | Get value by key |
148
+ | POST | `/storage/set/:key?entityId=x` | `{ value }` | Set value |
149
+ | DELETE | `/storage/delete/:key?entityId=x` | - | Delete key |
150
+ | POST | `/storage/batch-get?entityId=x` | `{ keys: [] }` | Batch get |
151
+ | POST | `/storage/batch-set?entityId=x` | `{ entries: {} }` | Batch set |
152
+ | GET | `/health` | - | Health check |
153
+
154
+ ## API Reference
155
+
156
+ ### `createStore(entityId, config, options)`
157
+
158
+ Creates a store with multiple persisted atoms.
159
+
160
+ - `entityId`: Unique identifier for this store instance
161
+ - `config`: Array of atom configurations
162
+ - `options.storage`: Storage adapter (required)
163
+ - `options.debounceMs`: Debounce delay in ms (default: 800)
164
+
165
+ ### `useStore(store)`
166
+
167
+ React hook to use the store in components.
168
+
169
+ Returns: `{ ...data, ...setters, isLoading }`
170
+
171
+ Setter names are derived by capitalizing the config key:
172
+ - `theme` → `setTheme`
173
+ - `userName` → `setUserName`
174
+
175
+ ### `remoteStorage(options?)`
176
+
177
+ Creates a remote storage adapter for connecting to the BFF server.
178
+
179
+ ```typescript
180
+ // 基本用法 - BFF 使用默认存储后端
181
+ const adapter = remoteStorage();
182
+
183
+ // 指定使用 MongoDB
184
+ const adapter = remoteStorage({
185
+ backend: 'mongodb',
186
+ mongoUrl: 'mongodb://user:pass@host:27017',
187
+ mongoDb: 'myapp',
188
+ });
189
+
190
+ // 指定使用 JSONL
191
+ const adapter = remoteStorage({
192
+ backend: 'jsonl',
193
+ jsonlDir: '/tmp/my-app-data',
194
+ });
195
+ ```
196
+
197
+ - `options.baseUrl`: BFF server URL (default: `http://localhost:3847`)
198
+ - `options.entityId`: Default entityId for all requests
199
+ - `options.backend`: Storage backend type `'mongodb'` or `'jsonl'`
200
+ - `options.mongoUrl`: MongoDB connection URL (required if backend is mongodb)
201
+ - `options.mongoDb`: MongoDB database name (default: `jotai_state_store`)
202
+ - `options.jsonlDir`: JSONL storage directory (required if backend is jsonl)
203
+
204
+ ### `startServer(options)`
205
+
206
+ Starts the BFF server (singleton pattern). Import from `bff-store/server`.
207
+
208
+ - `options.port`: Server port (default: 3847)
209
+
210
+ Note: Storage backend is configured by the client via `remoteStorage()` options, not by the server.
211
+
212
+ ## Package Exports
213
+
214
+ | Export | Description | Environment |
215
+ |--------|-------------|-------------|
216
+ | `bff-store` | Main entry: createStore, useStore, memoryStorage, remoteStorage | Browser + Node.js |
217
+ | `bff-store/jsonl` | JSONL storage adapter | Node.js only |
218
+ | `bff-store/mongodb` | MongoDB storage adapter | Node.js only |
219
+ | `bff-store/server` | BFF server (startServer, Router, etc.) | Node.js only |
220
+
221
+ ## License
222
+
223
+ MIT