effector-storage 5.0.1 → 6.0.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 +76 -11
- package/async-storage/index.cjs +1 -1
- package/async-storage/index.cjs.d.ts +12 -5
- package/async-storage/index.cjs.map +1 -1
- package/async-storage/index.d.ts +12 -5
- package/async-storage/index.js +1 -1
- package/async-storage/index.js.flow +21 -4
- package/async-storage/index.js.map +1 -1
- package/async-storage/package.json +1 -0
- package/core/index.cjs +2 -0
- package/core/index.cjs.d.ts +90 -0
- package/core/index.cjs.map +1 -0
- package/core/index.d.ts +90 -0
- package/core/index.js +2 -0
- package/core/index.js.flow +113 -0
- package/core/index.js.map +1 -0
- package/core/package.json +8 -0
- package/index.cjs +1 -1
- package/index.cjs.d.ts +53 -12
- package/index.cjs.map +1 -1
- package/index.d.ts +53 -12
- package/index.js +1 -1
- package/index.js.flow +60 -10
- package/index.js.map +1 -1
- package/local/index.cjs +1 -1
- package/local/index.cjs.d.ts +36 -11
- package/local/index.cjs.map +1 -1
- package/local/index.d.ts +36 -11
- package/local/index.js +1 -1
- package/local/index.js.flow +40 -9
- package/local/index.js.map +1 -1
- package/local/package.json +1 -0
- package/log/index.cjs +2 -0
- package/log/index.cjs.d.ts +19 -0
- package/log/index.cjs.map +1 -0
- package/log/index.d.ts +19 -0
- package/log/index.js +2 -0
- package/log/index.js.flow +31 -0
- package/log/index.js.map +1 -0
- package/log/package.json +8 -0
- package/memory/index.cjs +1 -1
- package/memory/index.cjs.d.ts +33 -5
- package/memory/index.cjs.map +1 -1
- package/memory/index.d.ts +33 -5
- package/memory/index.js +1 -1
- package/memory/index.js.flow +33 -3
- package/memory/index.js.map +1 -1
- package/memory/package.json +1 -0
- package/nil/index.cjs +1 -1
- package/nil/index.cjs.d.ts +16 -6
- package/nil/index.cjs.map +1 -1
- package/nil/index.d.ts +16 -6
- package/nil/index.js +1 -1
- package/nil/index.js.flow +24 -4
- package/nil/index.js.map +1 -1
- package/nil/package.json +1 -0
- package/package.json +20 -4
- package/query/index.cjs +1 -1
- package/query/index.cjs.d.ts +41 -18
- package/query/index.cjs.map +1 -1
- package/query/index.d.ts +41 -18
- package/query/index.js +1 -1
- package/query/index.js.flow +41 -11
- package/query/index.js.map +1 -1
- package/query/package.json +1 -0
- package/rn/async/index.cjs +1 -1
- package/rn/async/index.cjs.d.ts +31 -9
- package/rn/async/index.cjs.map +1 -1
- package/rn/async/index.d.ts +31 -9
- package/rn/async/index.js +1 -1
- package/rn/async/index.js.flow +35 -7
- package/rn/async/index.js.map +1 -1
- package/rn/async/package.json +1 -0
- package/rn/encrypted/index.cjs +1 -1
- package/rn/encrypted/index.cjs.d.ts +26 -9
- package/rn/encrypted/index.cjs.map +1 -1
- package/rn/encrypted/index.d.ts +26 -9
- package/rn/encrypted/index.js +1 -1
- package/rn/encrypted/index.js.flow +32 -7
- package/rn/encrypted/index.js.map +1 -1
- package/rn/encrypted/package.json +1 -0
- package/session/index.cjs +1 -1
- package/session/index.cjs.d.ts +36 -11
- package/session/index.cjs.map +1 -1
- package/session/index.d.ts +36 -11
- package/session/index.js +1 -1
- package/session/index.js.flow +40 -9
- package/session/index.js.map +1 -1
- package/session/package.json +1 -0
- package/storage/index.cjs +1 -1
- package/storage/index.cjs.d.ts +17 -6
- package/storage/index.cjs.map +1 -1
- package/storage/index.d.ts +17 -6
- package/storage/index.js +1 -1
- package/storage/index.js.flow +24 -5
- package/storage/index.js.map +1 -1
- package/storage/package.json +1 -0
- package/tools/index.cjs +2 -0
- package/tools/index.cjs.d.ts +125 -0
- package/tools/index.cjs.map +1 -0
- package/tools/index.d.ts +125 -0
- package/tools/index.js +2 -0
- package/tools/index.js.flow +101 -0
- package/tools/index.js.map +1 -0
- package/tools/package.json +8 -0
package/README.md
CHANGED
|
@@ -20,11 +20,12 @@ Small module for [Effector](https://github.com/effector/effector) ☄️ to sync
|
|
|
20
20
|
- [with React Native AsyncStorage](#with-react-native-asyncstorage)
|
|
21
21
|
- [with React Native EncryptedStorage](#with-react-native-encryptedstorage)
|
|
22
22
|
- [Usage with domains](#usage-with-domains)
|
|
23
|
-
- [Functional helpers](#functional-helpers)
|
|
24
23
|
- [Formulae](#formulae)
|
|
25
24
|
- [Units](#units)
|
|
26
25
|
- [Options](#options)
|
|
27
26
|
- [Returns](#returns)
|
|
27
|
+
- [Contracts](#contracts)
|
|
28
|
+
- [Notes](#notes)
|
|
28
29
|
- [`createPersist` factory](#createpersist-factory)
|
|
29
30
|
- [Options](#options-1)
|
|
30
31
|
- [Returns](#returns-1)
|
|
@@ -177,7 +178,9 @@ In order to synchronize _something_, you need to specify effector units. Dependi
|
|
|
177
178
|
- `key`? ([_string_]): Key for local/session storage, to store value in. If omitted — `store` name is used. **Note!** If `key` is not specified, `store` _must_ have a `name`! You can use `'effector/babel-plugin'` to have those names automatically.
|
|
178
179
|
- `keyPrefix`? ([_string_]): Prefix, used in adapter, to be concatenated to `key`. By default = `''`.
|
|
179
180
|
- `clock`? ([_Event_] | [_Effect_] | [_Store_]): Unit, if passed – then value from `store`/`source` will be stored in the storage only upon its trigger.
|
|
180
|
-
- `pickup`? ([_Event_] | [_Effect_] | [_Store_]): Unit, which you can specify to update `store` value from storage. **Note!** When you add `pickup`, `persist` _will not_ get initial value from storage automatically!
|
|
181
|
+
- `pickup`? ([_Event_] | [_Effect_] | [_Store_]): Unit, which you can specify to update `store` value from storage. This unit can also set a special context for adapter. **Note!** When you add `pickup`, `persist` _will not_ get initial value from storage automatically!
|
|
182
|
+
- `context`? ([_Event_] | [_Effect_] | [_Store_]): Unit, which can set a special context for adapter.
|
|
183
|
+
- `contract`? ([_Contract_]): Rule to statically validate data from storage.
|
|
181
184
|
- `done`? ([_Event_] | [_Effect_] | [_Store_]): Unit, which will be triggered on each successful read or write from/to storage.<br>
|
|
182
185
|
Payload structure:
|
|
183
186
|
- `key` ([_string_]): Same `key` as above.
|
|
@@ -188,14 +191,14 @@ In order to synchronize _something_, you need to specify effector units. Dependi
|
|
|
188
191
|
Payload structure:
|
|
189
192
|
- `key` ([_string_]): Same `key` as above.
|
|
190
193
|
- `keyPrefix` ([_string_]): Prefix, used in adapter, to be concatenated to `key`. By default = `''`.
|
|
191
|
-
- `operation` (_`'set'`_ | _`'get'`_): Type of operation, read (get)
|
|
194
|
+
- `operation` (_`'set'`_ | _`'get'`_ | _`'validate'`_): Type of operation, read (get), write (set) or validation against contract (validate).
|
|
192
195
|
- `error` ([_Error_]): Error instance
|
|
193
196
|
- `value`? (_any_): In case of _'set'_ operation — value from `store`. In case of _'get'_ operation could contain raw value from storage or could be empty.
|
|
194
197
|
- `finally`? ([_Event_] | [_Effect_] | [_Store_]): Unit, which will be triggered either in case of success or error.<br>
|
|
195
198
|
Payload structure:
|
|
196
199
|
- `key` ([_string_]): Same `key` as above.
|
|
197
200
|
- `keyPrefix` ([_string_]): Prefix, used in adapter, to be concatenated to `key`. By default = `''`.
|
|
198
|
-
- `operation` (_`'set'`_ | _`'get'`_): Type of operation, read (get)
|
|
201
|
+
- `operation` (_`'set'`_ | _`'get'`_ | _`'validate'`_): Type of operation, read (get), write (set) or validation against contract (validate).
|
|
199
202
|
- `status` (_`'done'`_ | _`'fail'`_): Operation status.
|
|
200
203
|
- `error`? ([_Error_]): Error instance, in case of error.
|
|
201
204
|
- `value`? (_any_): Value, in case it is exists (look above).
|
|
@@ -204,6 +207,58 @@ In order to synchronize _something_, you need to specify effector units. Dependi
|
|
|
204
207
|
|
|
205
208
|
- ([_Subscription_]): You can use this subscription to remove store association with storage, if you don't need them to be synced anymore. It is a function.
|
|
206
209
|
|
|
210
|
+
### Contracts
|
|
211
|
+
|
|
212
|
+
You can use `contract` option to validate data from storage. Contract has the following type definition:
|
|
213
|
+
|
|
214
|
+
```typescript
|
|
215
|
+
export type Contract<Data> =
|
|
216
|
+
| ((raw: unknown) => raw is Data)
|
|
217
|
+
| {
|
|
218
|
+
isData: (raw: unknown) => raw is Data
|
|
219
|
+
getErrorMessages: (raw: unknown) => string[]
|
|
220
|
+
}
|
|
221
|
+
```
|
|
222
|
+
|
|
223
|
+
So, it could be simple type guard function in trivial use cases, or more complex object with `isData` type guard and `getErrorMessages` function, which returns array of error messages. This format is fully compatible with [Farfetched contracts](https://farfetched.pages.dev/api/primitives/contract.html), so you can use any adapter from Farfetched ([runtypes](https://farfetched.pages.dev/api/contracts/runtypes.html), [zod](https://farfetched.pages.dev/api/contracts/zod.html), [io-ts](https://farfetched.pages.dev/api/contracts/io-ts.html), [superstruct](https://farfetched.pages.dev/api/contracts/superstruct.html), [typed-contracts](https://farfetched.pages.dev/api/contracts/typed-contracts.html)) with `persist` and `contract` option:
|
|
224
|
+
|
|
225
|
+
```typescript
|
|
226
|
+
// simple type guard
|
|
227
|
+
persist({
|
|
228
|
+
store: $counter,
|
|
229
|
+
key: 'counter',
|
|
230
|
+
contract: (raw): raw is number => typeof raw === 'number',
|
|
231
|
+
})
|
|
232
|
+
```
|
|
233
|
+
|
|
234
|
+
```typescript
|
|
235
|
+
// complex contract with Farfetched adapter
|
|
236
|
+
import { Record, Literal, Number } from 'runtypes'
|
|
237
|
+
import { runtypeContract } from '@farfetched/runtypes'
|
|
238
|
+
|
|
239
|
+
const Asteroid = Record({
|
|
240
|
+
type: Literal('asteroid'),
|
|
241
|
+
mass: Number,
|
|
242
|
+
})
|
|
243
|
+
|
|
244
|
+
persist({
|
|
245
|
+
store: $asteroid,
|
|
246
|
+
key: 'asteroid',
|
|
247
|
+
contract: runtypeContract(Asteroid),
|
|
248
|
+
})
|
|
249
|
+
```
|
|
250
|
+
|
|
251
|
+
There are two gotchas with contracts:
|
|
252
|
+
|
|
253
|
+
1. From `effector-storage` point of view it is absolutely normal, when there is no persisted value in the storage yet. So, `undefined` value is _always valid_, event if contract is not explicitly allows it.
|
|
254
|
+
2. `effector-storage` does not validate data, which is written to the storage. But it will validate it nonetheless, after persisting, so, if you write invalid data to the storage, `fail` will be triggered, but data _will be_ persisted.
|
|
255
|
+
|
|
256
|
+
### Notes
|
|
257
|
+
|
|
258
|
+
Without specifying `pickup` property, calling `persist` will immediately call adapter to get initial value. In case of synchronous storage (like `localStorage` or `sessionStorage`) this action will synchronously set store value, and call `done`/`fail`/`finally` right away. You should take that into account, if you adds some logic on `done`, for example — place `persist` after that logic (see issue [#38](https://github.com/yumauri/effector-storage/issues/38) for more details).
|
|
259
|
+
|
|
260
|
+
You can modify adapter to be asynchronous to mitigate this behavior with [`async`](https://github.com/yumauri/effector-storage/tree/master/src/tools/README.md#async) function.
|
|
261
|
+
|
|
207
262
|
## `createPersist` factory
|
|
208
263
|
|
|
209
264
|
In rare cases you might want to use `createPersist` factory. It allows you to specify some adapter options, like `keyPrefix`.
|
|
@@ -229,7 +284,10 @@ persist({
|
|
|
229
284
|
|
|
230
285
|
### Options
|
|
231
286
|
|
|
287
|
+
- `pickup`? ([_Event_] | [_Effect_] | [_Store_]): Unit, which you can specify to update `store` value from storage. This unit can also set a special context for adapter. **Note!** When you add `pickup`, `persist` _will not_ get initial value from storage automatically!
|
|
288
|
+
- `context`? ([_Event_] | [_Effect_] | [_Store_]): Unit, which can set a special context for adapter.
|
|
232
289
|
- `keyPrefix`? ([_string_]): Key prefix for adapter. It will be concatenated with any `key`, given to returned `persist` function.
|
|
290
|
+
- `contract`? ([_Contract_]): Rule to statically validate data from storage.
|
|
233
291
|
|
|
234
292
|
### Returns
|
|
235
293
|
|
|
@@ -239,7 +297,7 @@ persist({
|
|
|
239
297
|
|
|
240
298
|
`effector-storage` consists of a _core_ module and _adapter_ modules.
|
|
241
299
|
|
|
242
|
-
The core module itself does nothing with actual storage, it just connects effector units to the storage adapter, using
|
|
300
|
+
The core module itself does nothing with actual storage, it just connects effector units to the storage adapter, using couple of _Effects_ and bunch of connections.
|
|
243
301
|
|
|
244
302
|
The storage adapter _gets_ and _sets_ values, and also can asynchronously emit values on storage updates.
|
|
245
303
|
|
|
@@ -258,10 +316,11 @@ Adapter is a function, which is called by the core `persist` function, and has f
|
|
|
258
316
|
```typescript
|
|
259
317
|
interface StorageAdapter {
|
|
260
318
|
<State>(key: string, update: (raw?: any) => any): {
|
|
261
|
-
get(raw?: any): State | Promise<State>
|
|
262
|
-
set(value: State): void
|
|
319
|
+
get(raw?: any, ctx?: any): State | Promise<State>
|
|
320
|
+
set(value: State, ctx?: any): void
|
|
263
321
|
}
|
|
264
322
|
keyArea?: any
|
|
323
|
+
noop?: boolean
|
|
265
324
|
}
|
|
266
325
|
```
|
|
267
326
|
|
|
@@ -273,13 +332,18 @@ interface StorageAdapter {
|
|
|
273
332
|
#### Returns
|
|
274
333
|
|
|
275
334
|
- `{ get, set }` (_{ Function, Function }_): Getter from and setter to storage. These functions are used as Effects handlers, and could be sync or async. Also, you don't have to catch exceptions and errors inside those functions — Effects will do that for you.<br>
|
|
276
|
-
As mentioned above, call of `update` function will trigger `get` function with the same argument. So you can handle cases, when `get` function is called during initial `persist` execution (without arguments), or after external update. Check out [example below](#storage-with-external-updates-example)
|
|
335
|
+
As mentioned above, call of `update` function will trigger `get` function with the same argument. So you can handle cases, when `get` function is called during initial `persist` execution (without arguments), or after external update. Check out [example below](#storage-with-external-updates-example).<br>
|
|
336
|
+
Also getter and setter both accepts optional _context_ as a second argument — it can be any value. This context could be useful, if adapter depends on some external environment, for example, it can contain _Request_ and _Response_ from Express middleware, to get/set cookies from/to. (TODO: isomorphic cookies adapter example).
|
|
277
337
|
|
|
278
338
|
#### keyArea
|
|
279
339
|
|
|
280
340
|
Adapter function can have static field `keyArea` — this could be any value of any type, which should be unique for _keys namespace_. For example, two local storage adapters could have different settings, but both of them uses same _storage area_ — `localStorage`. So, different stores, persisted in local storage with the same key (but possibly with different adapters), should be synced. That is what `keyArea` is responsible for. Value of that field is used as a key in cache `Map`.<br>
|
|
281
341
|
In case it is omitted — adapter instances is used instead.
|
|
282
342
|
|
|
343
|
+
#### noop
|
|
344
|
+
|
|
345
|
+
Marks adapter as "no-op" for [`either`](https://github.com/yumauri/effector-storage/tree/master/src/tools/README.md#either) function.
|
|
346
|
+
|
|
283
347
|
### Synchronous storage adapter example
|
|
284
348
|
|
|
285
349
|
For example, simplified _localStorage_ adapter might looks like this. This is over-simplified example, don't do that in real code, there are no serialization and deserialization, no checks for edge cases. This is just to show an idea.
|
|
@@ -378,10 +442,10 @@ import { persist } from 'effector-storage'
|
|
|
378
442
|
const pickup = createEvent()
|
|
379
443
|
|
|
380
444
|
const adapter = (key, update) => {
|
|
381
|
-
// if `pickup` event was triggered ->
|
|
445
|
+
// if `pickup` event was triggered -> call an `update` function
|
|
382
446
|
// this will call `get` function from below ↓
|
|
383
447
|
// wrapped in Effect, to handle any errors
|
|
384
|
-
|
|
448
|
+
pickup.watch(update)
|
|
385
449
|
return {
|
|
386
450
|
get: () => localStorage.getItem(key),
|
|
387
451
|
set: (value) => localStorage.setItem(key, value),
|
|
@@ -443,7 +507,7 @@ adapter = storage(options)
|
|
|
443
507
|
#### Options
|
|
444
508
|
|
|
445
509
|
- `storage` (_Storage_): Storage to communicate with.
|
|
446
|
-
- `sync`? ([_boolean_]): Add [`'storage'`] event listener or no. Default = `false`.
|
|
510
|
+
- `sync`? ([_boolean_] | 'force'): Add [`'storage'`] event listener or no. Default = `false`. In case of `'force'` value adapter will always read new value from _Storage_, instead of event.
|
|
447
511
|
- `serialize`? (_(value: any) => string_): Custom serialize function. Default = `JSON.stringify`
|
|
448
512
|
- `deserialize`? (_(value: string) => any_): Custom deserialize function. Default = `JSON.parse`
|
|
449
513
|
|
|
@@ -516,3 +580,4 @@ Use this approach with caution, beware of infinite circular updates. To avoid th
|
|
|
516
580
|
[_function_]: https://developer.mozilla.org/en-US/docs/Glossary/Function
|
|
517
581
|
[_boolean_]: https://developer.mozilla.org/en-US/docs/Glossary/Boolean
|
|
518
582
|
[_error_]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error
|
|
583
|
+
[_Contract_]: #contracts
|
package/async-storage/index.cjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
"use strict";
|
|
1
|
+
"use strict";function e({storage:e,serialize:t=JSON.stringify,deserialize:a=JSON.parse}){var r=r=>({async get(){var t=await e().getItem(r);return null===t?void 0:a(t)},async set(a){await e().setItem(r,t(a))}});try{r.keyArea=e()}catch(e){}return r}e.factory=!0,exports.asyncStorage=e;
|
|
2
2
|
//# sourceMappingURL=index.cjs.map
|
|
@@ -1,21 +1,28 @@
|
|
|
1
|
-
|
|
1
|
+
interface StorageAdapter {
|
|
2
|
+
<State>(key: string, update: (raw?: any) => any): {
|
|
3
|
+
get(raw?: any, ctx?: any): State | Promise<State>
|
|
4
|
+
set(value: State, ctx?: any): void
|
|
5
|
+
}
|
|
6
|
+
keyArea?: any
|
|
7
|
+
noop?: boolean
|
|
8
|
+
}
|
|
2
9
|
|
|
3
10
|
interface AsyncStorage {
|
|
4
11
|
getItem: (key: string) => Promise<string | null>
|
|
5
12
|
setItem: (key: string, value: string) => Promise<void>
|
|
6
13
|
}
|
|
7
14
|
interface AsyncStorageConfig {
|
|
8
|
-
storage: AsyncStorage
|
|
15
|
+
storage: () => AsyncStorage
|
|
9
16
|
serialize?: (value: any) => string
|
|
10
17
|
deserialize?: (value: string) => any
|
|
11
18
|
}
|
|
12
|
-
/**
|
|
13
|
-
* Generic `AsyncStorage` adapter factory
|
|
14
|
-
*/
|
|
15
19
|
declare function asyncStorage({
|
|
16
20
|
storage,
|
|
17
21
|
serialize,
|
|
18
22
|
deserialize,
|
|
19
23
|
}: AsyncStorageConfig): StorageAdapter
|
|
24
|
+
declare namespace asyncStorage {
|
|
25
|
+
var factory: true
|
|
26
|
+
}
|
|
20
27
|
|
|
21
28
|
export { AsyncStorage, AsyncStorageConfig, asyncStorage }
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.cjs","sources":["../../src/async-storage/index.ts"],"sourcesContent":["import type { StorageAdapter } from '
|
|
1
|
+
{"version":3,"file":"index.cjs","sources":["../../src/async-storage/index.ts"],"sourcesContent":["import type { StorageAdapter } from '../types'\n\nexport interface AsyncStorage {\n getItem: (key: string) => Promise<string | null>\n setItem: (key: string, value: string) => Promise<void>\n}\n\nexport interface AsyncStorageConfig {\n storage: () => AsyncStorage\n serialize?: (value: any) => string\n deserialize?: (value: string) => any\n}\n\n/**\n * Creates generic `AsyncStorage` adapter\n */\nasyncStorage.factory = true as const\nexport function asyncStorage({\n storage,\n serialize = JSON.stringify,\n deserialize = JSON.parse,\n}: AsyncStorageConfig): StorageAdapter {\n const adapter: StorageAdapter = <State>(key: string) => ({\n async get() {\n const item = await storage().getItem(key)\n return item === null ? undefined : deserialize(item)\n },\n\n async set(value: State) {\n await storage().setItem(key, serialize(value))\n },\n })\n\n try {\n adapter.keyArea = storage()\n } catch (error) {\n // do nothing\n }\n\n return adapter\n}\n"],"names":["asyncStorage","storage","serialize","JSON","stringify","deserialize","parse","adapter","key","async","item","getItem","undefined","value","setItem","keyArea","error","factory"],"mappings":"aAiBO,SAASA,GAAaC,QAC3BA,EAAOC,UACPA,EAAYC,KAAKC,UAASC,YAC1BA,EAAcF,KAAKG,QAEnB,IAAMC,EAAkCC,IAAiB,CACvDC,YACE,IAAMC,QAAaT,IAAUU,QAAQH,GACrC,OAAgB,OAATE,OAAgBE,EAAYP,EAAYK,EAChD,EAEDD,UAAUI,SACFZ,IAAUa,QAAQN,EAAKN,EAAUW,GACzC,IAGF,IACEN,EAAQQ,QAAUd,GACnB,CAAC,MAAOe,GACP,CAGF,OAAOT,CACT,CAxBAP,EAAaiB,SAAU"}
|
package/async-storage/index.d.ts
CHANGED
|
@@ -1,21 +1,28 @@
|
|
|
1
|
-
|
|
1
|
+
interface StorageAdapter {
|
|
2
|
+
<State>(key: string, update: (raw?: any) => any): {
|
|
3
|
+
get(raw?: any, ctx?: any): State | Promise<State>
|
|
4
|
+
set(value: State, ctx?: any): void
|
|
5
|
+
}
|
|
6
|
+
keyArea?: any
|
|
7
|
+
noop?: boolean
|
|
8
|
+
}
|
|
2
9
|
|
|
3
10
|
interface AsyncStorage {
|
|
4
11
|
getItem: (key: string) => Promise<string | null>
|
|
5
12
|
setItem: (key: string, value: string) => Promise<void>
|
|
6
13
|
}
|
|
7
14
|
interface AsyncStorageConfig {
|
|
8
|
-
storage: AsyncStorage
|
|
15
|
+
storage: () => AsyncStorage
|
|
9
16
|
serialize?: (value: any) => string
|
|
10
17
|
deserialize?: (value: string) => any
|
|
11
18
|
}
|
|
12
|
-
/**
|
|
13
|
-
* Generic `AsyncStorage` adapter factory
|
|
14
|
-
*/
|
|
15
19
|
declare function asyncStorage({
|
|
16
20
|
storage,
|
|
17
21
|
serialize,
|
|
18
22
|
deserialize,
|
|
19
23
|
}: AsyncStorageConfig): StorageAdapter
|
|
24
|
+
declare namespace asyncStorage {
|
|
25
|
+
var factory: true
|
|
26
|
+
}
|
|
20
27
|
|
|
21
28
|
export { AsyncStorage, AsyncStorageConfig, asyncStorage }
|
package/async-storage/index.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
function e({storage:e,serialize:t=JSON.stringify,deserialize:a=JSON.parse}){var r=r=>({async get(){var t=await e.getItem(r);return null===t?void 0:a(t)},async set(a){await e.setItem(r,t(a))}});
|
|
1
|
+
function e({storage:e,serialize:t=JSON.stringify,deserialize:a=JSON.parse}){var r=r=>({async get(){var t=await e().getItem(r);return null===t?void 0:a(t)},async set(a){await e().setItem(r,t(a))}});try{r.keyArea=e()}catch(e){}return r}e.factory=!0;export{e as asyncStorage};
|
|
2
2
|
//# sourceMappingURL=index.js.map
|
|
@@ -1,19 +1,36 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Flowtype definitions for index
|
|
3
3
|
* Generated by Flowgen from a Typescript Definition
|
|
4
|
-
* Flowgen v1.
|
|
4
|
+
* Flowgen v1.21.0
|
|
5
5
|
* @flow
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
|
-
|
|
8
|
+
declare interface StorageAdapter {
|
|
9
|
+
<State>(
|
|
10
|
+
key: string,
|
|
11
|
+
update: (raw?: any) => any
|
|
12
|
+
): {
|
|
13
|
+
get(raw?: any, ctx?: any): State | Promise<State>,
|
|
14
|
+
set(value: State, ctx?: any): void,
|
|
15
|
+
...
|
|
16
|
+
};
|
|
17
|
+
keyArea?: any;
|
|
18
|
+
noop?: boolean;
|
|
19
|
+
}
|
|
9
20
|
declare interface AsyncStorage {
|
|
10
21
|
getItem: (key: string) => Promise<string | null>;
|
|
11
22
|
setItem: (key: string, value: string) => Promise<void>;
|
|
12
23
|
}
|
|
13
24
|
declare interface AsyncStorageConfig {
|
|
14
|
-
storage: AsyncStorage;
|
|
25
|
+
storage: () => AsyncStorage;
|
|
15
26
|
serialize?: (value: any) => string;
|
|
16
27
|
deserialize?: (value: string) => any;
|
|
17
28
|
}
|
|
18
|
-
declare
|
|
29
|
+
declare var asyncStorage: typeof npm$namespace$asyncStorage
|
|
30
|
+
|
|
31
|
+
declare var npm$namespace$asyncStorage: {|
|
|
32
|
+
(x: AsyncStorageConfig): StorageAdapter,
|
|
33
|
+
factory: typeof asyncStorage$factory,
|
|
34
|
+
|}
|
|
35
|
+
declare var asyncStorage$factory: true
|
|
19
36
|
declare export { AsyncStorage, AsyncStorageConfig, asyncStorage }
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sources":["../../src/async-storage/index.ts"],"sourcesContent":["import type { StorageAdapter } from '
|
|
1
|
+
{"version":3,"file":"index.js","sources":["../../src/async-storage/index.ts"],"sourcesContent":["import type { StorageAdapter } from '../types'\n\nexport interface AsyncStorage {\n getItem: (key: string) => Promise<string | null>\n setItem: (key: string, value: string) => Promise<void>\n}\n\nexport interface AsyncStorageConfig {\n storage: () => AsyncStorage\n serialize?: (value: any) => string\n deserialize?: (value: string) => any\n}\n\n/**\n * Creates generic `AsyncStorage` adapter\n */\nasyncStorage.factory = true as const\nexport function asyncStorage({\n storage,\n serialize = JSON.stringify,\n deserialize = JSON.parse,\n}: AsyncStorageConfig): StorageAdapter {\n const adapter: StorageAdapter = <State>(key: string) => ({\n async get() {\n const item = await storage().getItem(key)\n return item === null ? undefined : deserialize(item)\n },\n\n async set(value: State) {\n await storage().setItem(key, serialize(value))\n },\n })\n\n try {\n adapter.keyArea = storage()\n } catch (error) {\n // do nothing\n }\n\n return adapter\n}\n"],"names":["asyncStorage","storage","serialize","JSON","stringify","deserialize","parse","adapter","key","async","item","getItem","undefined","value","setItem","keyArea","error","factory"],"mappings":"AAiBO,SAASA,GAAaC,QAC3BA,EAAOC,UACPA,EAAYC,KAAKC,UAASC,YAC1BA,EAAcF,KAAKG,QAEnB,IAAMC,EAAkCC,IAAiB,CACvDC,YACE,IAAMC,QAAaT,IAAUU,QAAQH,GACrC,OAAgB,OAATE,OAAgBE,EAAYP,EAAYK,EAChD,EAEDD,UAAUI,SACFZ,IAAUa,QAAQN,EAAKN,EAAUW,GACzC,IAGF,IACEN,EAAQQ,QAAUd,GACnB,CAAC,MAAOe,GACP,CAGF,OAAOT,CACT,CAxBAP,EAAaiB,SAAU"}
|
package/core/index.cjs
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
"use strict";var e=require("effector"),r=new Map,t=e=>(r,t)=>e(t,r.ref),o=e.createEvent();o.watch((e=>console.error(e.error))),exports.persist=function(a){var{adapter:i,store:f,source:s=f,target:n=f,clock:d=s,done:c,fail:u=o,finally:l,pickup:p,context:v,key:y,keyPrefix:g="",contract:m}=a;if(!i)throw Error("Adapter is not defined");if(!s)throw Error("Store or source is not defined");if(!n)throw Error("Target is not defined");if(!y&&s.shortName===s.id)throw Error("Key or name is not defined");if(s===n&&!e.is.store(s))throw Error("Source must be different from target");void 0===a.def&&e.is.store(s)&&(a.def=s.defaultState);var k="factory"in i?i(a):i,w=y||s.shortName,h=function(t,o){var a=r.get(t);void 0===a&&(a=new Map,r.set(t,a));var i=a.get(o);return void 0!==i||(i=e.createStore(null,{serialize:"ignore"}),a.set(o,i)),i}(k.keyArea||k,g+w),E=e.createNode(),x=()=>e.clearNode(E),P=e=>({status:r="fail",params:t,result:o,error:a})=>"done"===r?{status:r,key:w,keyPrefix:g,operation:e,value:"get"===e?o:t}:{status:r,key:w,keyPrefix:g,operation:e,value:t,error:a};return e.withRegion(E,(()=>{var r=e.createStore({ref:void 0},{serialize:"ignore"}),o=k(g+w,(e=>D(e))),a=e.attach({source:r,effect:t(o.get)}),i=e.attach({source:r,effect:t(o.set)}),f=e.createEffect((e=>r=>!e||void 0===r||("isData"in e?e.isData(r):e(r))?r:(()=>{throw"getErrorMessages"in e?e.getErrorMessages(r):void 0})())(m)),y=e.createEvent(),E=y.filterMap((({status:e,key:r,keyPrefix:t,operation:o,value:a})=>"done"===e?{key:r,keyPrefix:t,operation:o,value:a}:void 0)),x=y.filterMap((({status:e,key:r,keyPrefix:t,operation:o,error:a,value:i})=>"fail"===e?{key:r,keyPrefix:t,operation:o,error:a,value:i}:void 0)),M=e.createEvent(),D=a;r.updates.watch((()=>{D=(r=>{try{return e.scopeBind(r,{safe:!0})}catch(e){return r}})(a)})),e.sample({source:s,clock:d,target:M}),e.guard({source:e.sample(h,M,((e,r)=>[r,e])),filter:([e,r])=>e!==r,target:i.prepend((([e])=>e))}),e.forward({from:[a.doneData,i],to:h}),e.sample({source:e.merge([a.doneData,h]),target:f}),e.forward({from:f.doneData,to:n}),e.forward({from:[a.finally.map(P("get")),i.finally.map(P("set")),f.fail.map(P("validate"))],to:y}),e.forward({from:x,to:u}),c&&e.forward({from:E,to:c}),l&&e.forward({from:y,to:l}),v&&r.on(v,(({ref:e},r)=>({ref:void 0===r?e:r}))),p?(e.forward({from:p,to:a.prepend((()=>{}))}),r.on(p,(({ref:e},r)=>({ref:void 0===r?e:r})))):a()})),x.unsubscribe=x};
|
|
2
|
+
//# sourceMappingURL=index.cjs.map
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import { Unit, Store, Event, Effect, Subscription } from 'effector'
|
|
2
|
+
|
|
3
|
+
interface StorageAdapter {
|
|
4
|
+
<State>(key: string, update: (raw?: any) => any): {
|
|
5
|
+
get(raw?: any, ctx?: any): State | Promise<State>
|
|
6
|
+
set(value: State, ctx?: any): void
|
|
7
|
+
}
|
|
8
|
+
keyArea?: any
|
|
9
|
+
noop?: boolean
|
|
10
|
+
}
|
|
11
|
+
interface StorageAdapterFactory<AdapterConfig> {
|
|
12
|
+
(config?: AdapterConfig): StorageAdapter
|
|
13
|
+
factory: true
|
|
14
|
+
}
|
|
15
|
+
type Contract<Data> =
|
|
16
|
+
| ((raw: unknown) => raw is Data)
|
|
17
|
+
| {
|
|
18
|
+
isData: (raw: unknown) => raw is Data
|
|
19
|
+
getErrorMessages: (raw: unknown) => string[]
|
|
20
|
+
}
|
|
21
|
+
type Done<State> = {
|
|
22
|
+
key: string
|
|
23
|
+
keyPrefix: string
|
|
24
|
+
operation: 'set' | 'get'
|
|
25
|
+
value: State
|
|
26
|
+
}
|
|
27
|
+
type Fail<Err> = {
|
|
28
|
+
key: string
|
|
29
|
+
keyPrefix: string
|
|
30
|
+
operation: 'set' | 'get'
|
|
31
|
+
error: Err
|
|
32
|
+
value?: any
|
|
33
|
+
}
|
|
34
|
+
type Finally<State, Err> =
|
|
35
|
+
| (Done<State> & {
|
|
36
|
+
status: 'done'
|
|
37
|
+
})
|
|
38
|
+
| (Fail<Err> & {
|
|
39
|
+
status: 'fail'
|
|
40
|
+
})
|
|
41
|
+
interface ConfigPersist {
|
|
42
|
+
pickup?: Unit<any>
|
|
43
|
+
context?: Unit<any>
|
|
44
|
+
keyPrefix?: string
|
|
45
|
+
contract?: Contract<any>
|
|
46
|
+
}
|
|
47
|
+
interface ConfigAdapter {
|
|
48
|
+
adapter: StorageAdapter
|
|
49
|
+
}
|
|
50
|
+
interface ConfigAdapterFactory<AdapterConfig> {
|
|
51
|
+
adapter: StorageAdapterFactory<AdapterConfig>
|
|
52
|
+
}
|
|
53
|
+
interface ConfigCommon<State, Err = Error> {
|
|
54
|
+
clock?: Unit<any>
|
|
55
|
+
done?: Unit<Done<State>>
|
|
56
|
+
fail?: Unit<Fail<Err>>
|
|
57
|
+
finally?: Unit<Finally<State, Err>>
|
|
58
|
+
pickup?: Unit<any>
|
|
59
|
+
context?: Unit<any>
|
|
60
|
+
key?: string
|
|
61
|
+
keyPrefix?: string
|
|
62
|
+
contract?: Contract<State | undefined>
|
|
63
|
+
}
|
|
64
|
+
interface ConfigJustStore<State> {
|
|
65
|
+
store: Store<State>
|
|
66
|
+
}
|
|
67
|
+
interface ConfigJustSourceTarget<State> {
|
|
68
|
+
source: Store<State> | Event<State> | Effect<State, any, any>
|
|
69
|
+
target: Store<State> | Event<State> | Effect<State, any, any>
|
|
70
|
+
}
|
|
71
|
+
interface ConfigStore<State, Err = Error>
|
|
72
|
+
extends ConfigCommon<State, Err>,
|
|
73
|
+
ConfigJustStore<State> {}
|
|
74
|
+
interface ConfigSourceTarget<State, Err = Error>
|
|
75
|
+
extends ConfigCommon<State, Err>,
|
|
76
|
+
ConfigJustSourceTarget<State> {}
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Main `persist` function
|
|
80
|
+
*/
|
|
81
|
+
declare function persist<State, Err = Error>(
|
|
82
|
+
config: Partial<
|
|
83
|
+
(ConfigAdapter | ConfigAdapterFactory<any>) &
|
|
84
|
+
ConfigPersist &
|
|
85
|
+
ConfigStore<State, Err> &
|
|
86
|
+
ConfigSourceTarget<State, Err>
|
|
87
|
+
>
|
|
88
|
+
): Subscription
|
|
89
|
+
|
|
90
|
+
export { persist }
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.cjs","sources":["../../src/core/area.ts","../../src/core/index.ts"],"sourcesContent":["import type { Store } from 'effector'\nimport { createStore } from 'effector'\n\n/**\n * Keys areas / namespaces cache\n */\nconst areas = new Map<any, Map<string, Store<any>>>()\n\n/**\n * Get store, responsible for the key in key area / namespace\n */\nexport function getAreaStorage<State>(keyArea: any, key: string): Store<State> {\n let area = areas.get(keyArea)\n if (area === undefined) {\n area = new Map()\n areas.set(keyArea, area)\n }\n\n let store = area.get(key)\n if (store !== undefined) {\n return store\n }\n\n store = createStore(null, { serialize: 'ignore' })\n area.set(key, store)\n\n return store\n}\n","import type { Effect, Subscription } from 'effector'\nimport type {\n ConfigAdapter,\n ConfigAdapterFactory,\n ConfigPersist,\n ConfigSourceTarget,\n ConfigStore,\n Contract,\n Done,\n Fail,\n Finally,\n} from '../types'\nimport {\n attach,\n clearNode,\n createEvent,\n createEffect,\n createNode,\n createStore,\n forward,\n guard,\n is,\n merge,\n sample,\n scopeBind,\n withRegion,\n} from 'effector'\nimport { getAreaStorage } from './area'\n\n// helper function to swap two function arguments\n// end extract current context from ref-box\nconst contextual =\n <T, C, R>(fn: (value: T, ctx?: C) => R) =>\n (ctx: { ref?: C }, value: T) =>\n fn(value, ctx.ref)\n\n// helper function to validate data with contract\nconst contracted =\n <T>(contract?: Contract<T>) =>\n (raw: unknown) =>\n !contract || // no contract -> data is valid\n raw === undefined || // `undefined` is always valid\n ('isData' in contract ? contract.isData(raw) : contract(raw))\n ? (raw as T)\n : (() => {\n throw 'getErrorMessages' in contract\n ? contract.getErrorMessages(raw)\n : undefined\n })()\n\n// helper function for safe bind effects to scope\n// since version 22.4.0 there is `safe` option in `scopeBind`,\n// but as long as effector-storage supports 22.0 this helper is required\nconst safeBind = (fx: Effect<any, any, any>) => {\n try {\n // @ts-expect-error due to old typings in import\n return scopeBind(fx, { safe: true })\n } catch (e) {\n return fx\n }\n}\n\n/**\n * Default sink for unhandled errors\n */\nconst sink = createEvent<Fail<any>>()\nsink.watch((payload) => console.error(payload.error))\n\n/**\n * Main `persist` function\n */\nexport function persist<State, Err = Error>(\n config: Partial<\n (ConfigAdapter | ConfigAdapterFactory<any>) &\n ConfigPersist &\n ConfigStore<State, Err> &\n ConfigSourceTarget<State, Err>\n >\n): Subscription {\n const {\n adapter: adapterOrFactory,\n store,\n source = store,\n target = store,\n clock = source,\n done,\n fail = sink,\n finally: anyway,\n pickup,\n context,\n key: keyName,\n keyPrefix = '',\n contract,\n } = config\n\n if (!adapterOrFactory) {\n throw Error('Adapter is not defined')\n }\n if (!source) {\n throw Error('Store or source is not defined')\n }\n if (!target) {\n throw Error('Target is not defined')\n }\n if (!keyName && source.shortName === (source as any).id) {\n throw Error('Key or name is not defined')\n }\n if (source === target && !is.store(source)) {\n throw Error('Source must be different from target')\n }\n\n // get default value from store, if given\n // this is used in adapter factory\n if ((config as any).def === undefined && is.store(source)) {\n ;(config as any).def = source.defaultState\n }\n\n const adapter =\n 'factory' in adapterOrFactory ? adapterOrFactory(config) : adapterOrFactory\n\n const key = keyName || source.shortName\n const storage = getAreaStorage<State>(\n adapter.keyArea || adapter,\n keyPrefix + key\n )\n const region = createNode()\n const desist = () => clearNode(region)\n\n const op =\n (operation: 'get' | 'set' | 'validate') =>\n ({ status = 'fail', params, result, error }: any): any =>\n status === 'done'\n ? {\n status,\n key,\n keyPrefix,\n operation,\n value: operation === 'get' ? result : params,\n }\n : {\n status,\n key,\n keyPrefix,\n operation,\n value: params,\n error,\n }\n\n // create all auxiliary units and nodes within the region,\n // to be able to remove them all at once on unsubscription\n withRegion(region, () => {\n const ctx = createStore<{ ref: any }>(\n { ref: undefined },\n { serialize: 'ignore' }\n )\n\n const value = adapter<State>(keyPrefix + key, (x) => bindedGet(x))\n\n const getFx = attach({\n source: ctx,\n effect: contextual(value.get),\n }) as any as Effect<void, State, Err>\n\n const setFx = attach({\n source: ctx,\n effect: contextual(value.set),\n }) as any as Effect<State, void, Err>\n\n const validateFx = createEffect<unknown, State>(contracted(contract))\n\n const localAnyway = createEvent<Finally<State, Err>>()\n const localDone = localAnyway.filterMap<Done<State>>(\n ({ status, key, keyPrefix, operation, value }) =>\n status === 'done' ? { key, keyPrefix, operation, value } : undefined\n )\n const localFail = localAnyway.filterMap<Fail<Err>>(\n ({ status, key, keyPrefix, operation, error, value }: any) =>\n status === 'fail'\n ? { key, keyPrefix, operation, error, value }\n : undefined\n )\n\n const trigger = createEvent<State>()\n\n let bindedGet: (raw?: any) => any = getFx\n ctx.updates.watch(() => {\n bindedGet = safeBind(getFx)\n })\n\n sample({\n source,\n // eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n clock: clock!, // `clock` is always defined, as long as `source` is defined\n target: trigger,\n })\n\n guard({\n source: sample(storage, trigger, (current, proposed) => [\n proposed,\n current,\n ]),\n filter: ([proposed, current]) => proposed !== current,\n target: setFx.prepend(([proposed]: State[]) => proposed),\n })\n forward({ from: [getFx.doneData, setFx], to: storage })\n sample({\n source: merge([getFx.doneData, storage]),\n target: validateFx as any,\n })\n forward({ from: validateFx.doneData, to: target })\n\n forward({\n from: [\n getFx.finally.map(op('get')),\n setFx.finally.map(op('set')),\n validateFx.fail.map(op('validate')),\n ],\n to: localAnyway,\n })\n\n forward({ from: localFail, to: fail })\n if (done) forward({ from: localDone, to: done })\n if (anyway) forward({ from: localAnyway, to: anyway })\n\n if (context) {\n ctx.on(context, ({ ref }, payload) => ({\n ref: payload === undefined ? ref : payload,\n }))\n }\n\n if (pickup) {\n // pick up value from storage ONLY on `pickup` update\n forward({ from: pickup, to: getFx.prepend(() => undefined) })\n ctx.on(pickup, ({ ref }, payload) => ({\n ref: payload === undefined ? ref : payload,\n }))\n } else {\n // kick getter to pick up initial value from storage\n getFx()\n }\n })\n\n return (desist.unsubscribe = desist)\n}\n"],"names":["areas","Map","contextual","fn","ctx","value","ref","sink","createEvent","watch","payload","console","error","config","adapter","adapterOrFactory","store","source","target","clock","done","fail","finally","anyway","pickup","context","key","keyName","keyPrefix","contract","Error","shortName","id","is","undefined","def","defaultState","storage","keyArea","area","get","set","createStore","serialize","getAreaStorage","region","createNode","desist","clearNode","op","operation","status","params","result","withRegion","x","bindedGet","getFx","attach","effect","setFx","validateFx","createEffect","raw","isData","getErrorMessages","contracted","localAnyway","localDone","filterMap","localFail","trigger","updates","fx","scopeBind","safe","e","safeBind","sample","guard","current","proposed","filter","prepend","forward","from","doneData","to","merge","map","on","unsubscribe"],"mappings":"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"}
|
package/core/index.d.ts
ADDED
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import { Unit, Store, Event, Effect, Subscription } from 'effector'
|
|
2
|
+
|
|
3
|
+
interface StorageAdapter {
|
|
4
|
+
<State>(key: string, update: (raw?: any) => any): {
|
|
5
|
+
get(raw?: any, ctx?: any): State | Promise<State>
|
|
6
|
+
set(value: State, ctx?: any): void
|
|
7
|
+
}
|
|
8
|
+
keyArea?: any
|
|
9
|
+
noop?: boolean
|
|
10
|
+
}
|
|
11
|
+
interface StorageAdapterFactory<AdapterConfig> {
|
|
12
|
+
(config?: AdapterConfig): StorageAdapter
|
|
13
|
+
factory: true
|
|
14
|
+
}
|
|
15
|
+
type Contract<Data> =
|
|
16
|
+
| ((raw: unknown) => raw is Data)
|
|
17
|
+
| {
|
|
18
|
+
isData: (raw: unknown) => raw is Data
|
|
19
|
+
getErrorMessages: (raw: unknown) => string[]
|
|
20
|
+
}
|
|
21
|
+
type Done<State> = {
|
|
22
|
+
key: string
|
|
23
|
+
keyPrefix: string
|
|
24
|
+
operation: 'set' | 'get'
|
|
25
|
+
value: State
|
|
26
|
+
}
|
|
27
|
+
type Fail<Err> = {
|
|
28
|
+
key: string
|
|
29
|
+
keyPrefix: string
|
|
30
|
+
operation: 'set' | 'get'
|
|
31
|
+
error: Err
|
|
32
|
+
value?: any
|
|
33
|
+
}
|
|
34
|
+
type Finally<State, Err> =
|
|
35
|
+
| (Done<State> & {
|
|
36
|
+
status: 'done'
|
|
37
|
+
})
|
|
38
|
+
| (Fail<Err> & {
|
|
39
|
+
status: 'fail'
|
|
40
|
+
})
|
|
41
|
+
interface ConfigPersist {
|
|
42
|
+
pickup?: Unit<any>
|
|
43
|
+
context?: Unit<any>
|
|
44
|
+
keyPrefix?: string
|
|
45
|
+
contract?: Contract<any>
|
|
46
|
+
}
|
|
47
|
+
interface ConfigAdapter {
|
|
48
|
+
adapter: StorageAdapter
|
|
49
|
+
}
|
|
50
|
+
interface ConfigAdapterFactory<AdapterConfig> {
|
|
51
|
+
adapter: StorageAdapterFactory<AdapterConfig>
|
|
52
|
+
}
|
|
53
|
+
interface ConfigCommon<State, Err = Error> {
|
|
54
|
+
clock?: Unit<any>
|
|
55
|
+
done?: Unit<Done<State>>
|
|
56
|
+
fail?: Unit<Fail<Err>>
|
|
57
|
+
finally?: Unit<Finally<State, Err>>
|
|
58
|
+
pickup?: Unit<any>
|
|
59
|
+
context?: Unit<any>
|
|
60
|
+
key?: string
|
|
61
|
+
keyPrefix?: string
|
|
62
|
+
contract?: Contract<State | undefined>
|
|
63
|
+
}
|
|
64
|
+
interface ConfigJustStore<State> {
|
|
65
|
+
store: Store<State>
|
|
66
|
+
}
|
|
67
|
+
interface ConfigJustSourceTarget<State> {
|
|
68
|
+
source: Store<State> | Event<State> | Effect<State, any, any>
|
|
69
|
+
target: Store<State> | Event<State> | Effect<State, any, any>
|
|
70
|
+
}
|
|
71
|
+
interface ConfigStore<State, Err = Error>
|
|
72
|
+
extends ConfigCommon<State, Err>,
|
|
73
|
+
ConfigJustStore<State> {}
|
|
74
|
+
interface ConfigSourceTarget<State, Err = Error>
|
|
75
|
+
extends ConfigCommon<State, Err>,
|
|
76
|
+
ConfigJustSourceTarget<State> {}
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Main `persist` function
|
|
80
|
+
*/
|
|
81
|
+
declare function persist<State, Err = Error>(
|
|
82
|
+
config: Partial<
|
|
83
|
+
(ConfigAdapter | ConfigAdapterFactory<any>) &
|
|
84
|
+
ConfigPersist &
|
|
85
|
+
ConfigStore<State, Err> &
|
|
86
|
+
ConfigSourceTarget<State, Err>
|
|
87
|
+
>
|
|
88
|
+
): Subscription
|
|
89
|
+
|
|
90
|
+
export { persist }
|
package/core/index.js
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import{createStore as e,createEvent as r,is as o,createNode as t,withRegion as a,attach as i,createEffect as f,sample as n,guard as s,forward as d,merge as u,scopeBind as l,clearNode as c}from"effector";var p=new Map,v=e=>(r,o)=>e(o,r.ref),y=r();function k(k){var{adapter:m,store:g,source:h=g,target:w=g,clock:x=h,done:E,fail:P=y,finally:M,pickup:D,context:b,key:S,keyPrefix:z="",contract:A}=k;if(!m)throw Error("Adapter is not defined");if(!h)throw Error("Store or source is not defined");if(!w)throw Error("Target is not defined");if(!S&&h.shortName===h.id)throw Error("Key or name is not defined");if(h===w&&!o.store(h))throw Error("Source must be different from target");void 0===k.def&&o.store(h)&&(k.def=h.defaultState);var N="factory"in m?m(k):m,K=S||h.shortName,T=function(r,o){var t=p.get(r);void 0===t&&(t=new Map,p.set(r,t));var a=t.get(o);return void 0!==a||(a=e(null,{serialize:"ignore"}),t.set(o,a)),a}(N.keyArea||N,z+K),j=t(),q=()=>c(j),B=e=>({status:r="fail",params:o,result:t,error:a})=>"done"===r?{status:r,key:K,keyPrefix:z,operation:e,value:"get"===e?t:o}:{status:r,key:K,keyPrefix:z,operation:e,value:o,error:a};return a(j,(()=>{var o=e({ref:void 0},{serialize:"ignore"}),t=N(z+K,(e=>S(e))),a=i({source:o,effect:v(t.get)}),c=i({source:o,effect:v(t.set)}),p=f((e=>r=>!e||void 0===r||("isData"in e?e.isData(r):e(r))?r:(()=>{throw"getErrorMessages"in e?e.getErrorMessages(r):void 0})())(A)),y=r(),k=y.filterMap((({status:e,key:r,keyPrefix:o,operation:t,value:a})=>"done"===e?{key:r,keyPrefix:o,operation:t,value:a}:void 0)),m=y.filterMap((({status:e,key:r,keyPrefix:o,operation:t,error:a,value:i})=>"fail"===e?{key:r,keyPrefix:o,operation:t,error:a,value:i}:void 0)),g=r(),S=a;o.updates.watch((()=>{S=(e=>{try{return l(e,{safe:!0})}catch(r){return e}})(a)})),n({source:h,clock:x,target:g}),s({source:n(T,g,((e,r)=>[r,e])),filter:([e,r])=>e!==r,target:c.prepend((([e])=>e))}),d({from:[a.doneData,c],to:T}),n({source:u([a.doneData,T]),target:p}),d({from:p.doneData,to:w}),d({from:[a.finally.map(B("get")),c.finally.map(B("set")),p.fail.map(B("validate"))],to:y}),d({from:m,to:P}),E&&d({from:k,to:E}),M&&d({from:y,to:M}),b&&o.on(b,(({ref:e},r)=>({ref:void 0===r?e:r}))),D?(d({from:D,to:a.prepend((()=>{}))}),o.on(D,(({ref:e},r)=>({ref:void 0===r?e:r})))):a()})),q.unsubscribe=q}y.watch((e=>console.error(e.error)));export{k as persist};
|
|
2
|
+
//# sourceMappingURL=index.js.map
|