global-store 1.0.0-beta.2 → 1.0.0-beta.20

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 (103) hide show
  1. package/README.md +138 -133
  2. package/dist/compareVersion.d.ts +7 -0
  3. package/dist/createAsyncStore.d.ts +12 -0
  4. package/dist/createStore.d.ts +28 -0
  5. package/dist/global-store.es.js +97 -146
  6. package/dist/global-store.es.js.map +1 -1
  7. package/dist/global-store.es5.js +1 -1
  8. package/dist/global-store.es5.js.map +1 -1
  9. package/dist/global-store.systemjs.js +133 -180
  10. package/dist/global-store.systemjs.js.map +1 -1
  11. package/{src/index.ts → dist/index.d.ts} +1 -2
  12. package/dist/shouldInvokeInitializer.d.ts +2 -0
  13. package/dist/toVersionArray.d.ts +3 -0
  14. package/dist/types.d.ts +9 -0
  15. package/dist/util.d.ts +14 -0
  16. package/index.js.flow +8 -13
  17. package/lib/compareVersion.d.ts +7 -0
  18. package/lib/compareVersion.js +17 -0
  19. package/lib/compareVersion.js.map +1 -0
  20. package/lib/createAsyncStore.d.ts +12 -0
  21. package/lib/createAsyncStore.js +73 -0
  22. package/lib/createAsyncStore.js.map +1 -0
  23. package/lib/createStore.d.ts +16 -12
  24. package/lib/createStore.js +10 -13
  25. package/lib/createStore.js.map +1 -1
  26. package/lib/index.d.ts +1 -2
  27. package/lib/index.js +19 -7
  28. package/lib/index.js.map +1 -1
  29. package/lib/shouldInvokeInitializer.d.ts +2 -0
  30. package/lib/shouldInvokeInitializer.js +18 -0
  31. package/lib/shouldInvokeInitializer.js.map +1 -0
  32. package/lib/toVersionArray.d.ts +3 -0
  33. package/lib/toVersionArray.js +9 -0
  34. package/lib/toVersionArray.js.map +1 -0
  35. package/lib/types.d.ts +9 -7
  36. package/lib/types.js.map +1 -1
  37. package/lib/typesInternal.d.ts +14 -17
  38. package/lib/typesInternal.js.map +1 -1
  39. package/lib/util.d.ts +13 -9
  40. package/lib/util.js +58 -26
  41. package/lib/util.js.map +1 -1
  42. package/libm/compareVersion.d.ts +7 -0
  43. package/libm/compareVersion.js +13 -0
  44. package/libm/compareVersion.js.map +1 -0
  45. package/libm/createAsyncStore.d.ts +12 -0
  46. package/libm/createAsyncStore.js +27 -0
  47. package/libm/createAsyncStore.js.map +1 -0
  48. package/libm/createStore.d.ts +16 -12
  49. package/libm/createStore.js +9 -14
  50. package/libm/createStore.js.map +1 -1
  51. package/libm/index.d.ts +1 -2
  52. package/libm/index.js +2 -2
  53. package/libm/index.js.map +1 -1
  54. package/libm/shouldInvokeInitializer.d.ts +2 -0
  55. package/libm/shouldInvokeInitializer.js +14 -0
  56. package/libm/shouldInvokeInitializer.js.map +1 -0
  57. package/libm/toVersionArray.d.ts +3 -0
  58. package/libm/toVersionArray.js +5 -0
  59. package/libm/toVersionArray.js.map +1 -0
  60. package/libm/types.d.ts +9 -7
  61. package/libm/types.js +1 -0
  62. package/libm/types.js.map +1 -1
  63. package/libm/typesInternal.d.ts +14 -17
  64. package/libm/typesInternal.js +1 -0
  65. package/libm/typesInternal.js.map +1 -1
  66. package/libm/util.d.ts +13 -9
  67. package/libm/util.js +49 -13
  68. package/libm/util.js.map +1 -1
  69. package/package.json +62 -31
  70. package/ts/compareVersion.spec.ts +9 -0
  71. package/ts/compareVersion.ts +14 -0
  72. package/ts/createAsyncStore.spec.ts +142 -0
  73. package/ts/createAsyncStore.ts +31 -0
  74. package/ts/createStore.spec.ts +217 -0
  75. package/ts/createStore.ts +43 -0
  76. package/{src → ts}/index.spec.ts +1 -1
  77. package/ts/index.ts +5 -0
  78. package/ts/shouldInvokeInitializer.spec.ts +41 -0
  79. package/ts/shouldInvokeInitializer.ts +17 -0
  80. package/ts/toVersionArray.ts +8 -0
  81. package/ts/types.ts +12 -0
  82. package/ts/typesInternal.ts +21 -0
  83. package/ts/util.ts +69 -0
  84. package/lib/createReadonlyStore.d.ts +0 -41
  85. package/lib/createReadonlyStore.js +0 -83
  86. package/lib/createReadonlyStore.js.map +0 -1
  87. package/lib/errors.d.ts +0 -9
  88. package/lib/errors.js +0 -41
  89. package/lib/errors.js.map +0 -1
  90. package/libm/createReadonlyStore.d.ts +0 -41
  91. package/libm/createReadonlyStore.js +0 -80
  92. package/libm/createReadonlyStore.js.map +0 -1
  93. package/libm/errors.d.ts +0 -9
  94. package/libm/errors.js +0 -16
  95. package/libm/errors.js.map +0 -1
  96. package/src/createReadonlyStore.spec.ts +0 -162
  97. package/src/createReadonlyStore.ts +0 -116
  98. package/src/createStore.spec.ts +0 -64
  99. package/src/createStore.ts +0 -39
  100. package/src/errors.ts +0 -15
  101. package/src/types.ts +0 -9
  102. package/src/typesInternal.ts +0 -18
  103. package/src/util.ts +0 -27
package/README.md CHANGED
@@ -1,40 +1,35 @@
1
1
  # global-store
2
2
 
3
3
  [![NPM version][npm-image]][npm-url]
4
- [![NPM beta version][npm-beta-image]][npm-url]
5
4
  [![NPM downloads][downloads-image]][downloads-url]
6
5
  ![badge-size-es5-url]
7
- ![badge-size-esnext-url]
8
6
 
9
- [![Circle CI][circleci-image]][circleci-url]
10
- [![Travis CI][travis-image]][travis-url]
7
+ [![GitHub NodeJS][github-nodejs]][github-action-url]
11
8
  [![Codecov][codecov-image]][codecov-url]
12
- [![Coveralls Status][coveralls-image]][coveralls-url]
13
9
 
14
- [![Greenkeeper][greenkeeper-image]][greenkeeper-url]
15
10
  [![Visual Studio Code][vscode-image]][vscode-url]
16
- [![Wallaby.js][wallaby-image]][wallaby-url]
17
11
 
18
- [`global-store`](https://github.com/unional/global-store) provides version stable stores for library.
12
+ [global-store] provides version stable stores for libraries.
19
13
 
20
14
  Once this library reaches `1.0`, it will forever be backward compatible.
21
- Meaning there will never be a breaking change and `2.0` version of this library.
15
+ Meaning there will never be a breaking change or `2.0` version of this library.
22
16
 
23
17
  PLEASE NOTE: This document describes the new `1.0.0-beta` version (finally!! :tada:).
24
18
 
25
19
  For the current stable version, please check out [here](https://github.com/unional/global-store/blob/v0.8.2/README.md).
26
20
 
27
- ## Who need this
21
+ ## Who needs this
28
22
 
29
- - library can be used by other libraries, and
30
- - library with state, and/or
31
- - library wants to protect its state from modification.
23
+ - A library used by other libraries, and
24
+ - A library with state, and/or
25
+ - A library wants to protect its state from modification.
32
26
 
33
27
  ## Why do you need this
34
28
 
35
- If you use a file level variable to store some states,
29
+ If you use a file-level variable to store some states,
36
30
  and your library can be used by other libraries,
37
- the state it stores could scatter around the memory and you will get inconsistent result.
31
+ the state it stores could scatter around the memory,
32
+ and you will get inconsistent results.
38
33
 
39
34
  For example, you have this:
40
35
 
@@ -50,7 +45,7 @@ When your library is used by other libraries,
50
45
  they may use different versions.
51
46
  For example:
52
47
 
53
- ```
48
+ ```sh
54
49
  app
55
50
  - some-library@1.5
56
51
  - your-library@1.0
@@ -60,183 +55,193 @@ app
60
55
  Since the versions are not compatible,
61
56
  both versions of your library are loaded thus two instances of the `registry` variable exist and contain different values.
62
57
 
63
- Solution to this problem is to use some form of global storage such as `process.env` in NodeJS,
64
- and `localStorage` or global variable in browser.
58
+ The solution to this problem is to use some form of global storage such as `global` in NodeJS,
59
+ or global variable in the browser.
65
60
 
66
61
  The problem is that these mechanisms are shared by everything else in the application,
67
62
  completely exposed to everyone,
68
- and there is no mechanism to consolidate your state when they are populated by each version of your library being loaded.
63
+ and there is no mechanism to consolidate or protect your state when they are populated by each version of your library being loaded.
64
+
65
+ These are the problems addressed by [global-store].
69
66
 
70
- These are the problems addressed by [`global-store`](https://github.com/unional/global-store).
67
+ ## Installation
68
+
69
+ ```sh
70
+ npm install global-store
71
+ yarn add global-store
72
+ ```
71
73
 
72
74
  ## API
73
75
 
74
76
  ### createStore()
75
77
 
76
- `createStore()` creates a version stable store.
78
+ Type: `<T>(options: StoreOptions<T>) => Store<T>`
79
+
80
+ Creates a store of type `T`.
81
+
82
+ `T` is inferred by [`initializer`](#StoreOptionsInitializer).
77
83
 
78
84
  ```ts
79
85
  import { createStore } from 'global-store'
80
86
 
81
- const store = createStore(
82
- 'your-module',
83
- 'unique-string',
84
- previous => ({ ...previous, prop1: false, prop2: [] as string[] })
85
- )
87
+ const store = createStore({
88
+ moduleName: 'your-module',
89
+ key: 'some-unique-string',
90
+ version: '1.0.0',
91
+ initializer: (current, versions) => ({
92
+ prop1: false,
93
+ prop2: [] as string[],
94
+ ...current
95
+ })
96
+ })
86
97
 
87
- console.log(store.get().prop1) // false
98
+ console.log(store.value.prop1) // false
88
99
 
89
- store.get().prop1 = true
90
- store.get().prop2.push('a')
91
- console.log(store.get()) // { prop1: true, prop2: ['a'] }
100
+ store.value.prop1 = true
101
+ store.value.prop2.push('a')
102
+ console.log(store.value) // { prop1: true, prop2: ['a'] }
92
103
  ```
93
104
 
94
- #### createStore(moduleName, key, initializer)
95
- - `moduleName: string`: Name of your module. This is typically your npm package name.
96
- - `key: string | symbol`: The `key` should be unique for each store you create.
97
- You can use some random string such as UUID.
98
- You can also use `symbol`, but not that you need to use the `Symbol.for('key')` variant as `Symbol()` does not work for this purpose.
99
- Together with `moduleName`, `key` + `moduleName` forms an unique id to the store.
100
- - `initializer: (previous) => initValue`: initializer to initialize the store.
101
- Since there may be multiple copies of your library loaded,
102
- multiple calls to [`createStore()`](#createStore()) may occur.
103
- For the first call, the `previous` argument will be an empty object.
104
- For subsequence calls, it will be the value returned by the last call.
105
- Since there is no way to control the load order,
106
- [`createStore()`](#createStore()) can be called by a newer version of your libary before an older version.
107
- That means your `initializer` needs to be future proof.
108
- To do that, you should carry over what the previous call have created,
109
- and fill in the pieces your specific version needs.
110
- In addition, you can use a property such as `revisions` or `versions` to help this process.
111
-
112
- #### Store#get()
113
-
114
- Gets the store value.
115
- Also use this to update the store.
105
+ #### StoreOptions#moduleName
116
106
 
117
- ```ts
118
- import { createStore } from 'global-store'
107
+ Type: `string`
119
108
 
120
- const store = createStore(
121
- 'your-module',
122
- 'general:300c47d7-b3a8-43ee-9dea-1e05a7b34240',
123
- p => ({ ...p, a: 1 })
124
- )
109
+ Name of your module.
125
110
 
126
- store.get().a = 2
111
+ This is typically your NPM package name.
112
+ This will be shown if something goes wrong.
127
113
 
128
- console.log(store.get().a) // 2
129
- ```
114
+ #### StoreOptions#key
130
115
 
131
- #### Store#reset()
116
+ Type: optional `string`
132
117
 
133
- Reset the store to its initial value.
118
+ A specific key for each store in your module.
119
+
120
+ You can create multiple stores in your module for different purposes.
121
+ The key for each store needs to be unique.
122
+ And the key has to remain the same across versions.
123
+
124
+ For example, you can use a format like this to make it unique: `<some-purpose>:<UUID>`
125
+
126
+ e.g. `config:d15427a4-75cf-4999-9065-1dc325839a59`
127
+
128
+ `key` + `moduleName` forms a unique ID to the store.
129
+
130
+ `key` will not be shown if something goes wrong.
131
+
132
+ If `key` is not specified, it defaults to the string `default`.
134
133
 
135
- This is used mostly in your test, so that the tests would not interferred each other.
134
+ #### StoreOptions#version
136
135
 
137
- ### createReadonlyStore()
136
+ Type: `StoreVersion = string | number`
138
137
 
139
- `createReadonlyStore()` creates a version stable store that prevents modification.
138
+ The version of the store.
140
139
 
141
- Its signature is the same as [`createStore()`](#createStore()).
142
- The returned `ReadonlyStore` has the following additional features:
140
+ This is used during initialization to determine should the [`StoreOptions#initializer`](#StoreOptionsinitializer) be called (and in what order for [`createAsyncStore()`](#createAsyncStore)).
143
141
 
144
- #### ReadonlyStore#get()
142
+ It will be added to the `processedVersions` argument of the [`StoreOptions#initializer()`](#StoreOptionsinitializer) after it is being called.
145
143
 
146
- When the store is created,
147
- calling `get()` would result in error if `lock()` is not called.
148
- This avoids the store to be used accidentially without protection.
144
+ When specified as a string (recommended),
145
+ it must be in this format: `major.minor.patch`.
149
146
 
150
- #### Readonly#lock()
147
+ When there is a mix of string and numeric versions across different versions of your library,
148
+ the numeric value is compared to the patch number of the string version.
151
149
 
152
- Lock the store, making it read only.
150
+ #### StoreOptions#initializer()
153
151
 
154
- Then the store is locked, the following happens:
152
+ Type: `<T extends StoreValue>(current: StoreValue, processedVersions: StoreVersion[]) => T`
155
153
 
156
- - the value is frozen, making each property read only.
157
- - if the property is an array, it is also frozen,
158
- making it unable to add or remove entry.
159
- - [`get()`](#ReadonlyStore#get()) is open to be used.
160
- - [`reset()`](#ReadonlyStore#reset()) results in error.
161
- - [`getWritable()`](#ReadonlyStore#getWritable()) results in error.
162
- - [`openForTesting()`](#ReadonlyStore#openForTesting()) results in error.
154
+ The function to initialize the store.
163
155
 
164
- `lock()` takes an optional `finalizer` argument.
165
- It can contains properties matching the property names of the store,
166
- where each one is a transform function for that property.
156
+ Since there may be multiple copies of your library loaded,
157
+ multiple calls to the store creation function (e.g. [`createStore()`](#createStore)) may occur.
158
+ For the first call, the `current` argument will be an empty object.
159
+ For subsequence calls, it will be the value returned by the last call.
167
160
 
168
- It allows you to process the store before it is locked.
161
+ The `processedVersions` contains all the versions the have been processed so far.
162
+ You can use it to help determine what do you need to do.
169
163
 
170
- The typical use cases are to validate, clean up, transform, and freeze the values.
164
+ For [`createAsyncStore`](#createAsyncStore),
165
+ the `initializer` function will be called in the order of `version`.
166
+
167
+ For [`createStore`](#createStore),
168
+ since there is no way to control the load order,
169
+ they can be called by a newer version of your library before an older version.
170
+ This means your `initializer` needs to be future-proof.
171
+
172
+ To do that, you should fill in the pieces your specific version needs,
173
+ and carry over whatever is currently available.
174
+
175
+ This is only a general guideline,
176
+ the actual implementation will depend on how you use your store.
177
+
178
+ #### StoreValue
179
+
180
+ Type: `Record<string | symbol, any>`
181
+
182
+ The type of value stored in the stores.
183
+
184
+ Note that the key must be a string or `Symbol.for()` because `Symbol()` cannot be shared across versions.
185
+
186
+ #### Store#value
187
+
188
+ Access to the value in the store.
171
189
 
172
190
  ```ts
173
- import { createReadonlyStore } from 'global-store'
174
-
175
- const store = createStore(
176
- 'your-module',
177
- 'general:ea305f50-c48c-4d18-97ef-4c8e8f130446',
178
- p => ({ ...p, a: 1, b: [], c: {} })
179
- )
180
-
181
- store.lock({
182
- b: values => values.map(v => Object.freeze(v)),
183
- c: value => Object.freeze(value),
184
- prev: value => undefined // make the older version property disappear.
185
- })
191
+ import { createStore } from 'global-store'
192
+
193
+ const store = createStore({ ..., initializer: () => ({ x: 1 })}
194
+
195
+ console.info(store.value.x) // 1
196
+ store.value.x = 2
186
197
  ```
187
198
 
188
- #### ReadonlyStore#getWritable()
199
+ #### Store#reset()
189
200
 
190
- Before the store is locked,
191
- you need a mechanism to access the store and configure it.
192
- `getWritable()` by pass the check and allow you to do that.
201
+ Reset the store to its initial value.
193
202
 
194
- Once the store is locked, calling `getWritable()` results in error.
203
+ This is mostly used in tests so that the tests would not interfere with each other.
195
204
 
196
- #### ReadonlyStore#openForTesting()
205
+ ### createAsyncStore()
197
206
 
198
- During testing,
199
- you need a mechanism to allow the [`get()`](#ReadonlyStore#get()) calls to go through without locking the store.
200
- `openForTesting()` tells the store to turn off all checks so it can be used during test.
207
+ A `async` variant of [`createStore()`](#createStore).
208
+ It will return a promise,
209
+ which will resolve when the [`initializeAsyncStore()`](#initializeAsyncStore) is called.
201
210
 
202
- Due to its power, you should not have any code calling this method except in your test code.
211
+ One benefit of using this over [`createStore()`](#createStore) is that the initializers will be called in the order of `version`.
203
212
 
204
- ## Installation
213
+ This makes initialization much easier to handle.
205
214
 
206
- ```sh
207
- npm install global-store
208
- yarn add global-store
209
- ```
215
+ ### initializeAsyncStore()
216
+
217
+ Calling [`initializeAsyncStore()`](#initializeAsyncStore) will start the initialization process of [`createAsyncStore()`](#createAsyncStore).
218
+
219
+ It takes two arguments:
220
+
221
+ - `moduleName: string`: Name of your module.
222
+ - `key: string`: Optional. Key of the specific store to initialize.
223
+ If omitted, all stores in the module will be initialized.
210
224
 
211
225
  ## Bundling
212
226
 
213
- If your library will be a standalone bundle, make sure to exclude [`global-store`](https://github.com/unional/global-store).
214
- If not, there will be multiple copies of [`global-store`](https://github.com/unional/global-store) loaded and will completely defeat the purpose.
227
+ If your library will be a standalone bundle, make sure to exclude [global-store].
215
228
 
216
- You also should mark [`global-store`](https://github.com/unional/global-store) as a peer dependency and tell people who use your library to include [`global-store`](https://github.com/unional/global-store) as their dependency.
229
+ If not, there will be multiple copies of [global-store] loaded and will completely defeat the purpose.
217
230
 
218
- Any application that eventually uses your library should do the same, install [`global-store`](https://github.com/unional/global-store) as their own dependency.
231
+ Except the consuming application, which will declare [global-store] as a regular dependency,
232
+ all libraries should declare [global-store] as a peer dependency.
219
233
 
220
- [badge-size-es5-url]: http://img.badgesize.io/unional/global-store/master/dist/global-store.es5.js.svg?label=es5_size
221
- [badge-size-esnext-url]: http://img.badgesize.io/unional/global-store/master/dist/global-store.es.js.svg?label=esnext_size
222
- [circleci-image]: https://circleci.com/gh/unional/global-store/tree/master.svg?style=shield
223
- [circleci-url]: https://circleci.com/gh/unional/global-store/tree/master
234
+ [badge-size-es5-url]: http://img.badgesize.io/unional/global-store/master/dist/global-store.es5.js.svg?label=es5_size&compression=gzip
224
235
  [codecov-image]: https://codecov.io/gh/unional/global-store/branch/master/graph/badge.svg
225
236
  [codecov-url]: https://codecov.io/gh/unional/global-store
226
- [coveralls-image]: https://coveralls.io/repos/github/unional/global-store/badge.svg
227
- [coveralls-url]: https://coveralls.io/github/unional/global-store
228
237
  [downloads-image]: https://img.shields.io/npm/dm/global-store.svg?style=flat
229
238
  [downloads-url]: https://npmjs.org/package/global-store
230
- [greenkeeper-image]: https://badges.greenkeeper.io/unional/global-store.svg
231
- [greenkeeper-url]: https://greenkeeper.io/
232
- [npm-beta-image]: https://img.shields.io/npm/v/global-store/beta.svg?style=flat
239
+ [github-nodejs]: https://github.com/unional/global-store/workflows/release/badge.svg
240
+ [github-action-url]: https://github.com/unional/global-store/actions
241
+ [global-store]: https://github.com/unional/global-store
233
242
  [npm-image]: https://img.shields.io/npm/v/global-store.svg?style=flat
234
243
  [npm-url]: https://npmjs.org/package/global-store
235
244
  [downloads-image]: https://img.shields.io/npm/dm/global-store.svg?style=flat
236
245
  [downloads-url]: https://npmjs.org/package/global-store
237
- [travis-image]: https://img.shields.io/travis/unional/global-store/master.svg?style=flat
238
- [travis-url]: https://travis-ci.org/unional/global-store?branch=master
239
246
  [vscode-image]: https://img.shields.io/badge/vscode-ready-green.svg
240
247
  [vscode-url]: https://code.visualstudio.com/
241
- [wallaby-image]: https://img.shields.io/badge/wallaby.js-configured-green.svg
242
- [wallaby-url]: https://wallabyjs.com
@@ -0,0 +1,7 @@
1
+ import { StoreVersion } from './types';
2
+ /**
3
+ * Compare version.
4
+ * Positive when processed > current
5
+ * Negative when processed < current
6
+ */
7
+ export declare function compareVersion(processed: StoreVersion, current: StoreVersion): number;
@@ -0,0 +1,12 @@
1
+ import { Store } from './createStore';
2
+ import { StoreOptions, StoreValue } from './types';
3
+ /**
4
+ * Creates a store of type T asynchronously.
5
+ * @see https://github.com/unional/global-store#createAsyncStore
6
+ */
7
+ export declare function createAsyncStore<T extends StoreValue>({ moduleName, key, version, initializer }: StoreOptions<T>): Promise<Store<T>>;
8
+ /**
9
+ * Initializes the stores for `createAsyncStore()`.
10
+ * @see https://github.com/unional/global-store#initializeAsyncStore
11
+ */
12
+ export declare function initializeAsyncStore(moduleName: string, key?: string): void;
@@ -0,0 +1,28 @@
1
+ import { StoreOptions, StoreValue } from './types';
2
+ export declare type Store<T extends StoreValue> = {
3
+ /**
4
+ * The store value.
5
+ */
6
+ readonly value: T;
7
+ /**
8
+ * Freezes the store value.
9
+ * @param value Optional new store value.
10
+ * If supplied, this value will be freezed and used as the store value.
11
+ * You can use this update the store value and freeze part of it.
12
+ * If not supplied,
13
+ * the original value will be freezed and its array property will also be freezed.
14
+ */
15
+ freeze(value?: {
16
+ [k in keyof T]: Readonly<T[k]>;
17
+ }): void;
18
+ /**
19
+ * Resets the store to its initial value.
20
+ * You should only use this during testing.
21
+ */
22
+ reset(): void;
23
+ };
24
+ /**
25
+ * Creates a store of type T.
26
+ * @see https://www.npmjs.com/package/global-store
27
+ */
28
+ export declare function createStore<T extends StoreValue>({ moduleName, key, version, initializer }: StoreOptions<T>): Store<T>;