bff-store 0.1.0 → 0.1.1
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/.claude/settings.local.json +10 -1
- package/README.md +37 -8
- package/dist/index.d.mts +42 -1
- package/dist/index.d.ts +42 -1
- package/dist/index.mjs +43 -0
- package/dist/package.json +2 -5
- package/dist/server/entry.js +31970 -3
- package/dist/server/entry.mjs +32005 -4
- package/dist/storage/mongodb-entry.js +31978 -1
- package/dist/storage/mongodb-entry.mjs +32003 -2
- package/docs/BUG_FIX_MONGODB_CHILD_PROCESS.md +129 -0
- package/docs/FRONTEND_BACKEND_ISOLATION.md +150 -0
- package/docs/LOCAL_LINK_STRATEGIES.md +117 -0
- package/package.json +6 -6
- package/src/environment.ts +11 -0
- package/src/index.ts +7 -0
- package/src/nodeStore.ts +79 -0
- package/tsconfig.json +1 -0
- package/docs/BUG_DIAGNOSIS_REMOTE_STORAGE_OPTIONS.md +0 -104
- package/docs/BUG_FIX_REMOTE_STORAGE_OPTIONS.md +0 -63
- package/docs/BUG_FIX_SESSION_2026-06-03.md +0 -171
- /package/docs/{SIDECAR_SERVER.md → BFF_SIDECAR_SERVER.md} +0 -0
|
@@ -39,7 +39,16 @@
|
|
|
39
39
|
"Bash(npm publish:*)",
|
|
40
40
|
"Bash(rg -rn \"jotai-state-store\" --type-list)",
|
|
41
41
|
"Bash(rg -rn \"jotai-state-store\" .)",
|
|
42
|
-
"Bash(xargs sed:*)"
|
|
42
|
+
"Bash(xargs sed:*)",
|
|
43
|
+
"Bash(npx tsx:*)",
|
|
44
|
+
"Bash(npm ls:*)",
|
|
45
|
+
"Bash(perl -e 'alarm 5; exec @ARGV' -- node debug-simple.js)",
|
|
46
|
+
"Bash(echo \"exit: $?\")",
|
|
47
|
+
"Bash([ -d node_modules/mongodb ])",
|
|
48
|
+
"Bash(echo \"---mongodb status: $\\([ -d node_modules/mongodb ] && echo 'INSTALLED' || echo 'NOT INSTALLED'\\)\")",
|
|
49
|
+
"Bash(echo \"---mongodb: $\\([ -d node_modules/mongodb ] && echo 'INSTALLED' || echo 'NOT INSTALLED'\\)\")",
|
|
50
|
+
"Bash(xargs kill:*)",
|
|
51
|
+
"Bash(npm start:*)"
|
|
43
52
|
]
|
|
44
53
|
}
|
|
45
54
|
}
|
package/README.md
CHANGED
|
@@ -124,20 +124,49 @@ await startServer({
|
|
|
124
124
|
如果不通过 BFF,可以直接在 Node.js 中使用存储适配器:
|
|
125
125
|
|
|
126
126
|
```typescript
|
|
127
|
-
import {
|
|
127
|
+
import { createNodeStore, getDefaultStore } from 'bff-store';
|
|
128
128
|
import { jsonlStorage } from 'bff-store/jsonl';
|
|
129
129
|
import { mongodbStorage } from 'bff-store/mongodb';
|
|
130
130
|
|
|
131
131
|
// 使用 JSONL
|
|
132
|
-
const
|
|
132
|
+
const store = createNodeStore('entity-123', [
|
|
133
|
+
{ key: 'theme', defaultValue: 'dark' },
|
|
134
|
+
{ key: 'count', defaultValue: 0 },
|
|
135
|
+
], {
|
|
136
|
+
storage: jsonlStorage({ dir: './sessions' }),
|
|
137
|
+
});
|
|
133
138
|
|
|
134
|
-
//
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
139
|
+
// 等待初始加载完成
|
|
140
|
+
await store.waitForLoad();
|
|
141
|
+
|
|
142
|
+
// 使用 jotai getDefaultStore() 读写
|
|
143
|
+
const jotai = getDefaultStore();
|
|
144
|
+
jotai.set(store.atoms.theme, 'light'); // 自动 debounce 持久化
|
|
145
|
+
console.log(jotai.get(store.atoms.count));
|
|
146
|
+
|
|
147
|
+
// 或使用 MongoDB
|
|
148
|
+
const store2 = createNodeStore('entity-456', [
|
|
149
|
+
{ key: 'data', defaultValue: null },
|
|
150
|
+
], {
|
|
151
|
+
storage: await mongodbStorage({
|
|
152
|
+
url: 'mongodb://localhost:27017',
|
|
153
|
+
database: 'myapp',
|
|
154
|
+
}),
|
|
138
155
|
});
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
### 环境检测
|
|
139
159
|
|
|
140
|
-
|
|
160
|
+
```typescript
|
|
161
|
+
import { isNode, isBrowser } from 'bff-store';
|
|
162
|
+
|
|
163
|
+
if (isNode()) {
|
|
164
|
+
// Node.js 环境
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
if (isBrowser()) {
|
|
168
|
+
// 浏览器环境
|
|
169
|
+
}
|
|
141
170
|
```
|
|
142
171
|
|
|
143
172
|
## API Endpoints (BFF Server)
|
|
@@ -213,7 +242,7 @@ Note: Storage backend is configured by the client via `remoteStorage()` options,
|
|
|
213
242
|
|
|
214
243
|
| Export | Description | Environment |
|
|
215
244
|
|--------|-------------|-------------|
|
|
216
|
-
| `bff-store` | Main entry: createStore, useStore, memoryStorage, remoteStorage | Browser + Node.js |
|
|
245
|
+
| `bff-store` | Main entry: createStore, useStore, createNodeStore, isNode, isBrowser, memoryStorage, remoteStorage | Browser + Node.js |
|
|
217
246
|
| `bff-store/jsonl` | JSONL storage adapter | Node.js only |
|
|
218
247
|
| `bff-store/mongodb` | MongoDB storage adapter | Node.js only |
|
|
219
248
|
| `bff-store/server` | BFF server (startServer, Router, etc.) | Node.js only |
|
package/dist/index.d.mts
CHANGED
|
@@ -229,4 +229,45 @@ interface RemoteStorageOptions {
|
|
|
229
229
|
*/
|
|
230
230
|
declare function remoteStorage(options?: RemoteStorageOptions): StorageAdapter;
|
|
231
231
|
|
|
232
|
-
|
|
232
|
+
/**
|
|
233
|
+
* Environment detection utilities
|
|
234
|
+
*/
|
|
235
|
+
declare function isNode(): boolean;
|
|
236
|
+
declare function isBrowser(): boolean;
|
|
237
|
+
|
|
238
|
+
/**
|
|
239
|
+
* Create a store for Node.js environments.
|
|
240
|
+
*
|
|
241
|
+
* @example
|
|
242
|
+
* ```typescript
|
|
243
|
+
* import { jsonlStorage } from 'bff-store/jsonl';
|
|
244
|
+
* import { createNodeStore } from 'bff-store';
|
|
245
|
+
*
|
|
246
|
+
* const store = createNodeStore('entity-123', [
|
|
247
|
+
* { key: 'theme', defaultValue: 'dark' },
|
|
248
|
+
* ], {
|
|
249
|
+
* storage: jsonlStorage({ dir: './sessions' }),
|
|
250
|
+
* });
|
|
251
|
+
*
|
|
252
|
+
* await store.waitForLoad();
|
|
253
|
+
*
|
|
254
|
+
* const jotai = getDefaultStore();
|
|
255
|
+
* jotai.set(store.atoms.theme, 'light');
|
|
256
|
+
* ```
|
|
257
|
+
*/
|
|
258
|
+
declare function createNodeStore(entityId: string, config: AtomConfigs, options: {
|
|
259
|
+
storage: StorageAdapter;
|
|
260
|
+
debounceMs?: number;
|
|
261
|
+
}): {
|
|
262
|
+
/** Atoms to use with getDefaultStore().get/set */
|
|
263
|
+
atoms: StoreAtoms;
|
|
264
|
+
/** Loading state atoms */
|
|
265
|
+
loadingAtoms: StoreLoadingAtoms;
|
|
266
|
+
/**
|
|
267
|
+
* Wait for all atoms to finish loading from storage.
|
|
268
|
+
* Call this after creating the store to ensure data is ready.
|
|
269
|
+
*/
|
|
270
|
+
waitForLoad(): Promise<void>;
|
|
271
|
+
};
|
|
272
|
+
|
|
273
|
+
export { type AsyncStorageFactory, type AtomConfig, type AtomConfigs, type AtomType, HttpTransport, type MemoryStorageOptions, RestStorageProtocol, type Storage, type StorageAdapter, type StorageFactory, type StorageHttpProtocol, type StorageOptions, type Store, type TransportAdapter, type UseStoreReturn, createMemoryStorage, createNodeStore, createPersistedAtom, remoteStorage as createRemoteStorage, createStorageFromTransport, createStorageWithProtocol, createStore, isBrowser, isNode, memoryStorage, remoteStorage, useStore };
|
package/dist/index.d.ts
CHANGED
|
@@ -229,4 +229,45 @@ interface RemoteStorageOptions {
|
|
|
229
229
|
*/
|
|
230
230
|
declare function remoteStorage(options?: RemoteStorageOptions): StorageAdapter;
|
|
231
231
|
|
|
232
|
-
|
|
232
|
+
/**
|
|
233
|
+
* Environment detection utilities
|
|
234
|
+
*/
|
|
235
|
+
declare function isNode(): boolean;
|
|
236
|
+
declare function isBrowser(): boolean;
|
|
237
|
+
|
|
238
|
+
/**
|
|
239
|
+
* Create a store for Node.js environments.
|
|
240
|
+
*
|
|
241
|
+
* @example
|
|
242
|
+
* ```typescript
|
|
243
|
+
* import { jsonlStorage } from 'bff-store/jsonl';
|
|
244
|
+
* import { createNodeStore } from 'bff-store';
|
|
245
|
+
*
|
|
246
|
+
* const store = createNodeStore('entity-123', [
|
|
247
|
+
* { key: 'theme', defaultValue: 'dark' },
|
|
248
|
+
* ], {
|
|
249
|
+
* storage: jsonlStorage({ dir: './sessions' }),
|
|
250
|
+
* });
|
|
251
|
+
*
|
|
252
|
+
* await store.waitForLoad();
|
|
253
|
+
*
|
|
254
|
+
* const jotai = getDefaultStore();
|
|
255
|
+
* jotai.set(store.atoms.theme, 'light');
|
|
256
|
+
* ```
|
|
257
|
+
*/
|
|
258
|
+
declare function createNodeStore(entityId: string, config: AtomConfigs, options: {
|
|
259
|
+
storage: StorageAdapter;
|
|
260
|
+
debounceMs?: number;
|
|
261
|
+
}): {
|
|
262
|
+
/** Atoms to use with getDefaultStore().get/set */
|
|
263
|
+
atoms: StoreAtoms;
|
|
264
|
+
/** Loading state atoms */
|
|
265
|
+
loadingAtoms: StoreLoadingAtoms;
|
|
266
|
+
/**
|
|
267
|
+
* Wait for all atoms to finish loading from storage.
|
|
268
|
+
* Call this after creating the store to ensure data is ready.
|
|
269
|
+
*/
|
|
270
|
+
waitForLoad(): Promise<void>;
|
|
271
|
+
};
|
|
272
|
+
|
|
273
|
+
export { type AsyncStorageFactory, type AtomConfig, type AtomConfigs, type AtomType, HttpTransport, type MemoryStorageOptions, RestStorageProtocol, type Storage, type StorageAdapter, type StorageFactory, type StorageHttpProtocol, type StorageOptions, type Store, type TransportAdapter, type UseStoreReturn, createMemoryStorage, createNodeStore, createPersistedAtom, remoteStorage as createRemoteStorage, createStorageFromTransport, createStorageWithProtocol, createStore, isBrowser, isNode, memoryStorage, remoteStorage, useStore };
|
package/dist/index.mjs
CHANGED
|
@@ -415,15 +415,58 @@ function remoteStorage(options = {}) {
|
|
|
415
415
|
};
|
|
416
416
|
return adapter;
|
|
417
417
|
}
|
|
418
|
+
|
|
419
|
+
// src/environment.ts
|
|
420
|
+
function isNode() {
|
|
421
|
+
return typeof window === "undefined" && typeof process !== "undefined";
|
|
422
|
+
}
|
|
423
|
+
function isBrowser() {
|
|
424
|
+
return typeof window !== "undefined";
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
// src/nodeStore.ts
|
|
428
|
+
import { getDefaultStore as getDefaultStore3 } from "jotai";
|
|
429
|
+
function createNodeStore(entityId, config, options) {
|
|
430
|
+
const store = createStore(entityId, config, options);
|
|
431
|
+
const jotaiStore = getDefaultStore3();
|
|
432
|
+
async function waitForLoad() {
|
|
433
|
+
for (const atom2 of Object.values(store.atoms)) {
|
|
434
|
+
jotaiStore.sub(atom2, () => {
|
|
435
|
+
});
|
|
436
|
+
}
|
|
437
|
+
return new Promise((resolve) => {
|
|
438
|
+
const loadingAtoms = Object.values(store.loadingAtoms);
|
|
439
|
+
const stillLoading = () => loadingAtoms.some((atom2) => jotaiStore.get(atom2));
|
|
440
|
+
if (!stillLoading()) {
|
|
441
|
+
resolve();
|
|
442
|
+
return;
|
|
443
|
+
}
|
|
444
|
+
const interval = setInterval(() => {
|
|
445
|
+
if (!stillLoading()) {
|
|
446
|
+
clearInterval(interval);
|
|
447
|
+
resolve();
|
|
448
|
+
}
|
|
449
|
+
}, 10);
|
|
450
|
+
});
|
|
451
|
+
}
|
|
452
|
+
return {
|
|
453
|
+
atoms: store.atoms,
|
|
454
|
+
loadingAtoms: store.loadingAtoms,
|
|
455
|
+
waitForLoad
|
|
456
|
+
};
|
|
457
|
+
}
|
|
418
458
|
export {
|
|
419
459
|
HttpTransport,
|
|
420
460
|
RestStorageProtocol,
|
|
421
461
|
createMemoryStorage,
|
|
462
|
+
createNodeStore,
|
|
422
463
|
createPersistedAtom,
|
|
423
464
|
remoteStorage as createRemoteStorage,
|
|
424
465
|
createStorageFromTransport,
|
|
425
466
|
createStorageWithProtocol,
|
|
426
467
|
createStore,
|
|
468
|
+
isBrowser,
|
|
469
|
+
isNode,
|
|
427
470
|
memoryStorage,
|
|
428
471
|
remoteStorage,
|
|
429
472
|
useStore
|
package/dist/package.json
CHANGED
|
@@ -8,8 +8,7 @@
|
|
|
8
8
|
"exports": {
|
|
9
9
|
".": {
|
|
10
10
|
"types": "./index.d.ts",
|
|
11
|
-
"import": "./index.mjs"
|
|
12
|
-
"require": "./index.js"
|
|
11
|
+
"import": "./index.mjs"
|
|
13
12
|
},
|
|
14
13
|
"./jsonl": {
|
|
15
14
|
"types": "./storage/jsonl-entry.d.ts",
|
|
@@ -50,13 +49,11 @@
|
|
|
50
49
|
"@types/react": "^19.2.16",
|
|
51
50
|
"jotai": "^2.6.0",
|
|
52
51
|
"jsdom": "^29.1.1",
|
|
52
|
+
"mongodb": "^6.21.0",
|
|
53
53
|
"react": "^18.2.0",
|
|
54
54
|
"react-dom": "^18.2.0",
|
|
55
55
|
"tsup": "^8.0.0",
|
|
56
56
|
"typescript": "^5.0.0",
|
|
57
57
|
"vitest": "^1.0.0"
|
|
58
|
-
},
|
|
59
|
-
"dependencies": {
|
|
60
|
-
"mongodb": "^6.21.0"
|
|
61
58
|
}
|
|
62
59
|
}
|