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.
Files changed (105) hide show
  1. package/README.md +76 -11
  2. package/async-storage/index.cjs +1 -1
  3. package/async-storage/index.cjs.d.ts +12 -5
  4. package/async-storage/index.cjs.map +1 -1
  5. package/async-storage/index.d.ts +12 -5
  6. package/async-storage/index.js +1 -1
  7. package/async-storage/index.js.flow +21 -4
  8. package/async-storage/index.js.map +1 -1
  9. package/async-storage/package.json +1 -0
  10. package/core/index.cjs +2 -0
  11. package/core/index.cjs.d.ts +90 -0
  12. package/core/index.cjs.map +1 -0
  13. package/core/index.d.ts +90 -0
  14. package/core/index.js +2 -0
  15. package/core/index.js.flow +113 -0
  16. package/core/index.js.map +1 -0
  17. package/core/package.json +8 -0
  18. package/index.cjs +1 -1
  19. package/index.cjs.d.ts +53 -12
  20. package/index.cjs.map +1 -1
  21. package/index.d.ts +53 -12
  22. package/index.js +1 -1
  23. package/index.js.flow +60 -10
  24. package/index.js.map +1 -1
  25. package/local/index.cjs +1 -1
  26. package/local/index.cjs.d.ts +36 -11
  27. package/local/index.cjs.map +1 -1
  28. package/local/index.d.ts +36 -11
  29. package/local/index.js +1 -1
  30. package/local/index.js.flow +40 -9
  31. package/local/index.js.map +1 -1
  32. package/local/package.json +1 -0
  33. package/log/index.cjs +2 -0
  34. package/log/index.cjs.d.ts +19 -0
  35. package/log/index.cjs.map +1 -0
  36. package/log/index.d.ts +19 -0
  37. package/log/index.js +2 -0
  38. package/log/index.js.flow +31 -0
  39. package/log/index.js.map +1 -0
  40. package/log/package.json +8 -0
  41. package/memory/index.cjs +1 -1
  42. package/memory/index.cjs.d.ts +33 -5
  43. package/memory/index.cjs.map +1 -1
  44. package/memory/index.d.ts +33 -5
  45. package/memory/index.js +1 -1
  46. package/memory/index.js.flow +33 -3
  47. package/memory/index.js.map +1 -1
  48. package/memory/package.json +1 -0
  49. package/nil/index.cjs +1 -1
  50. package/nil/index.cjs.d.ts +16 -6
  51. package/nil/index.cjs.map +1 -1
  52. package/nil/index.d.ts +16 -6
  53. package/nil/index.js +1 -1
  54. package/nil/index.js.flow +24 -4
  55. package/nil/index.js.map +1 -1
  56. package/nil/package.json +1 -0
  57. package/package.json +20 -4
  58. package/query/index.cjs +1 -1
  59. package/query/index.cjs.d.ts +41 -18
  60. package/query/index.cjs.map +1 -1
  61. package/query/index.d.ts +41 -18
  62. package/query/index.js +1 -1
  63. package/query/index.js.flow +41 -11
  64. package/query/index.js.map +1 -1
  65. package/query/package.json +1 -0
  66. package/rn/async/index.cjs +1 -1
  67. package/rn/async/index.cjs.d.ts +31 -9
  68. package/rn/async/index.cjs.map +1 -1
  69. package/rn/async/index.d.ts +31 -9
  70. package/rn/async/index.js +1 -1
  71. package/rn/async/index.js.flow +35 -7
  72. package/rn/async/index.js.map +1 -1
  73. package/rn/async/package.json +1 -0
  74. package/rn/encrypted/index.cjs +1 -1
  75. package/rn/encrypted/index.cjs.d.ts +26 -9
  76. package/rn/encrypted/index.cjs.map +1 -1
  77. package/rn/encrypted/index.d.ts +26 -9
  78. package/rn/encrypted/index.js +1 -1
  79. package/rn/encrypted/index.js.flow +32 -7
  80. package/rn/encrypted/index.js.map +1 -1
  81. package/rn/encrypted/package.json +1 -0
  82. package/session/index.cjs +1 -1
  83. package/session/index.cjs.d.ts +36 -11
  84. package/session/index.cjs.map +1 -1
  85. package/session/index.d.ts +36 -11
  86. package/session/index.js +1 -1
  87. package/session/index.js.flow +40 -9
  88. package/session/index.js.map +1 -1
  89. package/session/package.json +1 -0
  90. package/storage/index.cjs +1 -1
  91. package/storage/index.cjs.d.ts +17 -6
  92. package/storage/index.cjs.map +1 -1
  93. package/storage/index.d.ts +17 -6
  94. package/storage/index.js +1 -1
  95. package/storage/index.js.flow +24 -5
  96. package/storage/index.js.map +1 -1
  97. package/storage/package.json +1 -0
  98. package/tools/index.cjs +2 -0
  99. package/tools/index.cjs.d.ts +125 -0
  100. package/tools/index.cjs.map +1 -0
  101. package/tools/index.d.ts +125 -0
  102. package/tools/index.js +2 -0
  103. package/tools/index.js.flow +101 -0
  104. package/tools/index.js.map +1 -0
  105. 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) or write (set).
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) or write (set).
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 two _Effects_ and bunch of _forwards_.
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 -> trigger `update`
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
- forward({ from: pickup, to: update })
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
@@ -1,2 +1,2 @@
1
- "use strict";exports.asyncStorage=function({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))}});return r.keyArea=e,r};
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
- import { StorageAdapter } from '..'
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 '..'\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 * Generic `AsyncStorage` adapter factory\n */\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 adapter.keyArea = storage\n return adapter\n}\n"],"names":["storage","serialize","JSON","stringify","deserialize","parse","adapter","key","async","item","getItem","undefined","value","setItem","keyArea"],"mappings":"kCAgBO,UAAsBA,QAC3BA,EAD2BC,UAE3BA,EAAYC,KAAKC,UAFUC,YAG3BA,EAAcF,KAAKG,QAEnB,IAAMC,EAAkCC,IAAiB,CACvDC,YACE,IAAMC,QAAaT,EAAQU,QAAQH,GACnC,OAAgB,OAATE,OAAgBE,EAAYP,EAAYK,EAHM,EAMvDD,UAAUI,SACFZ,EAAQa,QAAQN,EAAKN,EAAUW,GACtC,IAIH,OADAN,EAAQQ,QAAUd,EACXM,CACR"}
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"}
@@ -1,21 +1,28 @@
1
- import { StorageAdapter } from '..'
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,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))}});return r.keyArea=e,r}export{e as asyncStorage};
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.20.1
4
+ * Flowgen v1.21.0
5
5
  * @flow
6
6
  */
7
7
 
8
- import { StorageAdapter } from '..'
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 function asyncStorage(x: AsyncStorageConfig): StorageAdapter
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 '..'\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 * Generic `AsyncStorage` adapter factory\n */\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 adapter.keyArea = storage\n return adapter\n}\n"],"names":["asyncStorage","storage","serialize","JSON","stringify","deserialize","parse","adapter","key","async","item","getItem","undefined","value","setItem","keyArea"],"mappings":"AAgBO,SAASA,GAAaC,QAC3BA,EAD2BC,UAE3BA,EAAYC,KAAKC,UAFUC,YAG3BA,EAAcF,KAAKG,QAEnB,IAAMC,EAAkCC,IAAiB,CACvDC,YACE,IAAMC,QAAaT,EAAQU,QAAQH,GACnC,OAAgB,OAATE,OAAgBE,EAAYP,EAAYK,EAHM,EAMvDD,UAAUI,SACFZ,EAAQa,QAAQN,EAAKN,EAAUW,GACtC,IAIH,OADAN,EAAQQ,QAAUd,EACXM,CACR"}
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"}
@@ -1,5 +1,6 @@
1
1
  {
2
2
  "type": "module",
3
+ "sideEffects": false,
3
4
  "main": "index.cjs",
4
5
  "module": "index.js",
5
6
  "react-native": "index.js",
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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"}
@@ -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