@sv443-network/userutils 8.0.2 → 8.2.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/CHANGELOG.md +17 -0
- package/README.md +319 -95
- package/dist/index.global.js +102 -14
- package/dist/index.js +101 -13
- package/dist/lib/DataStore.d.ts +27 -8
- package/dist/lib/DataStoreSerializer.d.ts +20 -0
- package/dist/lib/crypto.d.ts +3 -2
- package/dist/lib/math.d.ts +16 -5
- package/dist/lib/types.d.ts +7 -0
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,22 @@
|
|
|
1
1
|
# @sv443-network/userutils
|
|
2
2
|
|
|
3
|
+
## 8.2.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- 3fe8b25: Added overload to `mapRange()` that only needs both `max` values and assumes 0 for both `min` values
|
|
8
|
+
- d7e8a31: Added utility type `Prettify` to make complex types more readable
|
|
9
|
+
- 8ec2010: Added `randomCase` parameter to the function `randomId()` (true by default)
|
|
10
|
+
- d9a36d5: Added property `migrateIds` to the constructor of `DataStore` for easier ID migration
|
|
11
|
+
- b2f757e: Added `enhancedEntropy` parameter to the function `randRange()` (false by default)
|
|
12
|
+
|
|
13
|
+
## 8.1.0
|
|
14
|
+
|
|
15
|
+
### Minor Changes
|
|
16
|
+
|
|
17
|
+
- 6296529: Added new DataStoreSerializer methods `loadStoresData()`, `resetStoresData()` and `deleteStoresData()` for parallelized bulk operations on DataStore instances
|
|
18
|
+
- b0bce9c: Added DataStore method `migrateId()` to be able to migrate to a new ID
|
|
19
|
+
|
|
3
20
|
## 8.0.2
|
|
4
21
|
|
|
5
22
|
### Patch Changes
|
package/README.md
CHANGED
|
@@ -78,6 +78,7 @@ View the documentation of previous major releases:
|
|
|
78
78
|
- [`NonEmptyArray`](#nonemptyarray) - any array that should have at least one item
|
|
79
79
|
- [`NonEmptyString`](#nonemptystring) - any string that should have at least one character
|
|
80
80
|
- [`LooseUnion`](#looseunion) - a union that gives autocomplete in the IDE but also allows any other value of the same type
|
|
81
|
+
- [`Prettify`](#prettify) - expands a complex type into a more readable format while keeping functionality the same
|
|
81
82
|
|
|
82
83
|
<br><br>
|
|
83
84
|
|
|
@@ -186,8 +187,9 @@ Additionally, there are the following extra options:
|
|
|
186
187
|
|
|
187
188
|
<br>
|
|
188
189
|
|
|
189
|
-
|
|
190
|
-
`addListener
|
|
190
|
+
### Methods:
|
|
191
|
+
#### `SelectorObserver.addListener()`
|
|
192
|
+
Usage: `SelectorObserver.addListener<TElement = HTMLElement>(selector: string, options: SelectorListenerOptions): void`
|
|
191
193
|
Adds a listener (specified in `options.listener`) for the given selector that will be called once the selector exists in the DOM. It will be passed the element(s) that match the selector as the only argument.
|
|
192
194
|
The listener will be called immediately if the selector already exists in the DOM.
|
|
193
195
|
|
|
@@ -216,45 +218,53 @@ The listener will be called immediately if the selector already exists in the DO
|
|
|
216
218
|
|
|
217
219
|
<br>
|
|
218
220
|
|
|
219
|
-
`enable(
|
|
221
|
+
#### `SelectorObserver.enable()`
|
|
222
|
+
Usage: `SelectorObserver.enable(immediatelyCheckSelectors?: boolean): boolean`
|
|
220
223
|
Enables the observation of the child elements for the first time or if it was disabled before.
|
|
221
224
|
`immediatelyCheckSelectors` is set to true by default, which means all previously registered selectors will be checked. Set to false to only check them on the first detected mutation.
|
|
222
225
|
Returns true if the observation was enabled, false if it was already enabled or the passed `baseElementSelector` couldn't be found.
|
|
223
226
|
|
|
224
227
|
<br>
|
|
225
228
|
|
|
226
|
-
`disable()
|
|
229
|
+
#### `SelectorObserver.disable()`
|
|
230
|
+
Usage: `SelectorObserver.disable(): void`
|
|
227
231
|
Disables the observation of the child elements.
|
|
228
232
|
If selectors are currently being checked, the current selector will be finished before disabling.
|
|
229
233
|
|
|
230
234
|
<br>
|
|
231
235
|
|
|
232
|
-
`isEnabled()
|
|
236
|
+
#### `SelectorObserver.isEnabled()`
|
|
237
|
+
Usage: `SelectorObserver.isEnabled(): boolean`
|
|
233
238
|
Returns whether the observation of the child elements is currently enabled.
|
|
234
239
|
|
|
235
240
|
<br>
|
|
236
241
|
|
|
237
|
-
`clearListeners()
|
|
242
|
+
#### `SelectorObserver.clearListeners()`
|
|
243
|
+
Usage: `SelectorObserver.clearListeners(): void`
|
|
238
244
|
Removes all listeners for all selectors.
|
|
239
245
|
|
|
240
246
|
<br>
|
|
241
247
|
|
|
242
|
-
`removeAllListeners(
|
|
248
|
+
#### `SelectorObserver.removeAllListeners()`
|
|
249
|
+
Usage: `SelectorObserver.removeAllListeners(selector: string): boolean`
|
|
243
250
|
Removes all listeners for the given selector.
|
|
244
251
|
|
|
245
252
|
<br>
|
|
246
253
|
|
|
247
|
-
`removeListener(
|
|
254
|
+
#### `SelectorObserver.removeListener()`
|
|
255
|
+
Usage: `SelectorObserver.removeListener(selector: string, options: SelectorListenerOptions): boolean`
|
|
248
256
|
Removes a specific listener for the given selector and options.
|
|
249
257
|
|
|
250
258
|
<br>
|
|
251
259
|
|
|
252
|
-
`getAllListeners()
|
|
260
|
+
#### `SelectorObserver.getAllListeners()`
|
|
261
|
+
Usage: `SelectorObserver.getAllListeners(): Map<string, SelectorListenerOptions[]>`
|
|
253
262
|
Returns a Map of all selectors and their listeners.
|
|
254
263
|
|
|
255
264
|
<br>
|
|
256
265
|
|
|
257
|
-
`getListeners(
|
|
266
|
+
#### `SelectorObserver.getListeners()`
|
|
267
|
+
Usage: `SelectorObserver.getListeners(selector: string): SelectorListenerOptions[] | undefined`
|
|
258
268
|
Returns all listeners for the given selector or undefined if there are none.
|
|
259
269
|
|
|
260
270
|
<br>
|
|
@@ -921,16 +931,12 @@ clamp(99999, 0, Infinity); // 99999
|
|
|
921
931
|
### mapRange()
|
|
922
932
|
Usage:
|
|
923
933
|
```ts
|
|
924
|
-
mapRange(
|
|
925
|
-
|
|
926
|
-
range1min: number,
|
|
927
|
-
range1max: number,
|
|
928
|
-
range2min: number,
|
|
929
|
-
range2max: number
|
|
930
|
-
): number
|
|
934
|
+
mapRange(value: number, range1min: number, range1max: number, range2min: number, range2max: number): number
|
|
935
|
+
mapRange(value: number, range1max: number, range2max: number): number
|
|
931
936
|
```
|
|
932
937
|
|
|
933
938
|
Maps a number from one range to the spot it would be in another range.
|
|
939
|
+
If only the `max` arguments are passed, the function will set the `min` for both ranges to 0.
|
|
934
940
|
|
|
935
941
|
<details><summary><b>Example - click to view</b></summary>
|
|
936
942
|
|
|
@@ -939,6 +945,7 @@ import { mapRange } from "@sv443-network/userutils";
|
|
|
939
945
|
|
|
940
946
|
mapRange(5, 0, 10, 0, 100); // 50
|
|
941
947
|
mapRange(5, 0, 10, 0, 50); // 25
|
|
948
|
+
mapRange(5, 10, 50); // 25
|
|
942
949
|
|
|
943
950
|
// to calculate a percentage from arbitrary values, use 0 and 100 as the second range
|
|
944
951
|
// for example, if 4 files of a total of 13 were downloaded:
|
|
@@ -951,21 +958,41 @@ mapRange(4, 0, 13, 0, 100); // 30.76923076923077
|
|
|
951
958
|
### randRange()
|
|
952
959
|
Usages:
|
|
953
960
|
```ts
|
|
954
|
-
randRange(min: number, max: number): number
|
|
955
|
-
randRange(max: number): number
|
|
961
|
+
randRange(min: number, max: number, enhancedEntropy?: boolean): number
|
|
962
|
+
randRange(max: number, enhancedEntropy?: boolean): number
|
|
956
963
|
```
|
|
957
964
|
|
|
958
965
|
Returns a random number between `min` and `max` (inclusive).
|
|
959
966
|
If only one argument is passed, it will be used as the `max` value and `min` will be set to 0.
|
|
960
967
|
|
|
968
|
+
If `enhancedEntropy` is set to true (false by default), the [Web Crypto API](https://developer.mozilla.org/en-US/docs/Web/API/Crypto/getRandomValues) is used for generating the random numbers.
|
|
969
|
+
Note that this makes the function call take longer, but the generated IDs will have a higher entropy.
|
|
970
|
+
|
|
961
971
|
<details><summary><b>Example - click to view</b></summary>
|
|
962
972
|
|
|
963
973
|
```ts
|
|
964
974
|
import { randRange } from "@sv443-network/userutils";
|
|
965
975
|
|
|
966
|
-
randRange(0, 10);
|
|
967
|
-
randRange(10, 20);
|
|
968
|
-
randRange(10);
|
|
976
|
+
randRange(0, 10); // 4
|
|
977
|
+
randRange(10, 20); // 17
|
|
978
|
+
randRange(10); // 7
|
|
979
|
+
randRange(0, 10, true); // 4 (the devil is in the details)
|
|
980
|
+
|
|
981
|
+
|
|
982
|
+
function benchmark(enhancedEntropy: boolean) {
|
|
983
|
+
const timestamp = Date.now();
|
|
984
|
+
for(let i = 0; i < 100_000; i++)
|
|
985
|
+
randRange(0, 100, enhancedEntropy);
|
|
986
|
+
console.log(`Generated 100k in ${Date.now() - timestamp}ms`)
|
|
987
|
+
}
|
|
988
|
+
|
|
989
|
+
// using Math.random():
|
|
990
|
+
benchmark(false); // Generated 100k in 90ms
|
|
991
|
+
|
|
992
|
+
// using crypto.getRandomValues():
|
|
993
|
+
benchmark(true); // Generated 100k in 461ms
|
|
994
|
+
|
|
995
|
+
// about a 5x slowdown, but the generated numbers are more entropic
|
|
969
996
|
```
|
|
970
997
|
</details>
|
|
971
998
|
|
|
@@ -995,44 +1022,73 @@ It combines the data of multiple DataStore instances into a single object that c
|
|
|
995
1022
|
The options object has the following properties:
|
|
996
1023
|
| Property | Description |
|
|
997
1024
|
| :-- | :-- |
|
|
998
|
-
| `id` | A unique internal identification string for this instance. If two DataStores share the same ID, they will overwrite each other's data
|
|
1025
|
+
| `id` | A unique internal identification string for this instance. If two DataStores share the same ID, they will overwrite each other's data, so it is recommended that you use a prefix that is unique to your project. |
|
|
999
1026
|
| `defaultData` | The default data to use if no data is saved in persistent storage yet. Until the data is loaded from persistent storage, this will be the data returned by `getData()`. For TypeScript, the type of the data passed here is what will be used for all other methods of the instance. |
|
|
1000
1027
|
| `formatVersion` | An incremental version of the data format. If the format of the data is changed in any way, this number should be incremented, in which case all necessary functions of the migrations dictionary will be run consecutively. Never decrement this number or skip numbers. |
|
|
1001
1028
|
| `migrations?` | (Optional) A dictionary of functions that can be used to migrate data from older versions of the data to newer ones. The keys of the dictionary should be the format version that the functions can migrate to, from the previous whole integer value. The values should be functions that take the data in the old format and return the data in the new format. The functions will be run in order from the oldest to the newest version. If the current format version is not in the dictionary, no migrations will be run. |
|
|
1029
|
+
| `migrateIds?` | (Optional) A string or array of strings that migrate from one or more old IDs to the ID set in the constructor. If no data exist for the old ID(s), nothing will be done, but some time may still pass trying to fetch the non-existent data. The ID migration will be done once per session in the call to [`loadData()`](#datastoreloaddata). |
|
|
1002
1030
|
| `storageMethod?` | (Optional) The method that is used to store the data. Can be `"GM"` (default), `"localStorage"` or `"sessionStorage"`. If you want to store the data in a different way, you can override the methods of the DataStore class. |
|
|
1003
1031
|
| `encodeData?` | (Optional, but required when `decodeData` is set) Function that encodes the data before saving - you can use [compress()](#compress) here to save space at the cost of a little bit of performance |
|
|
1004
1032
|
| `decodeData?` | (Optional, but required when `encodeData` is set) Function that decodes the data when loading - you can use [decompress()](#decompress) here to decode data that was previously compressed with [compress()](#compress) |
|
|
1005
1033
|
|
|
1006
1034
|
<br>
|
|
1007
1035
|
|
|
1008
|
-
|
|
1009
|
-
`loadData()
|
|
1036
|
+
### Methods:
|
|
1037
|
+
#### `DataStore.loadData()`
|
|
1038
|
+
Usage: `loadData(): Promise<TData>`
|
|
1010
1039
|
Asynchronously loads the data from persistent storage and returns it.
|
|
1011
|
-
If no data was saved in persistent storage before, the value of `options.defaultData` will be returned and written to persistent storage.
|
|
1012
|
-
If the
|
|
1013
|
-
|
|
1014
|
-
|
|
1040
|
+
If no data was saved in persistent storage before, the value of `options.defaultData` will be returned and also written to persistent storage before resolving.
|
|
1041
|
+
If the `options.migrateIds` property is present and this is the first time calling this function in this session, the data will be migrated from the old ID(s) to the current one.
|
|
1042
|
+
Then, if the `formatVersion` of the saved data is lower than the current one and the `options.migrations` property is present, the instance will try to migrate the data to the latest format before resolving, updating the in-memory cache and persistent storage.
|
|
1043
|
+
|
|
1044
|
+
<br>
|
|
1045
|
+
|
|
1046
|
+
#### `DataStore.getData()`
|
|
1047
|
+
Usage: `getData(): TData`
|
|
1015
1048
|
Synchronously returns the current data that is stored in the internal cache.
|
|
1016
|
-
If no data was loaded from persistent storage yet using `loadData()`, the value of `options.defaultData` will be returned.
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
`
|
|
1022
|
-
Writes the
|
|
1023
|
-
|
|
1024
|
-
|
|
1049
|
+
If no data was loaded from persistent storage yet using `loadData()`, the value of `options.defaultData` will be returned.
|
|
1050
|
+
|
|
1051
|
+
<br>
|
|
1052
|
+
|
|
1053
|
+
#### `DataStore.setData()`
|
|
1054
|
+
Usage: `setData(data: TData): Promise<void>`
|
|
1055
|
+
Writes the given data synchronously to the internal cache and asynchronously to persistent storage.
|
|
1056
|
+
|
|
1057
|
+
<br>
|
|
1058
|
+
|
|
1059
|
+
#### `DataStore.saveDefaultData()`
|
|
1060
|
+
Usage: `saveDefaultData(): Promise<void>`
|
|
1061
|
+
Writes the default data given in `options.defaultData` synchronously to the internal cache and asynchronously to persistent storage.
|
|
1062
|
+
|
|
1063
|
+
<br>
|
|
1064
|
+
|
|
1065
|
+
#### `DataStore.deleteData()`
|
|
1066
|
+
Usage: `deleteData(): Promise<void>`
|
|
1025
1067
|
Fully deletes the data from persistent storage only.
|
|
1026
1068
|
The internal cache will be left untouched, so any subsequent calls to `getData()` will return the data that was last loaded.
|
|
1027
1069
|
If `loadData()` or `setData()` are called after this, the persistent storage will be populated with the value of `options.defaultData` again.
|
|
1028
1070
|
This is why you should either immediately repopulate the cache and persistent storage or the page should probably be reloaded or closed after this method is called.
|
|
1029
|
-
⚠️ If you want to use this method, the additional directive `@grant GM.deleteValue` is required.
|
|
1030
|
-
|
|
1031
|
-
|
|
1071
|
+
⚠️ If you want to use this method, the additional directive `@grant GM.deleteValue` is required.
|
|
1072
|
+
|
|
1073
|
+
<br>
|
|
1074
|
+
|
|
1075
|
+
#### `DataStore.runMigrations()`
|
|
1076
|
+
Usage: `runMigrations(oldData: any, oldFmtVer: number, resetOnError?: boolean): Promise<TData>`
|
|
1032
1077
|
Runs all necessary migration functions to migrate the given `oldData` to the latest format.
|
|
1033
|
-
If `resetOnError` is set to `false`, the migration will be aborted if an error is thrown and no data will be committed. If it is set to `true` (default) and an error is encountered, it will be suppressed and the `defaultData` will be saved to persistent storage and returned.
|
|
1034
|
-
|
|
1035
|
-
|
|
1078
|
+
If `resetOnError` is set to `false`, the migration will be aborted if an error is thrown and no data will be committed. If it is set to `true` (default) and an error is encountered, it will be suppressed and the `defaultData` will be saved to persistent storage and returned.
|
|
1079
|
+
|
|
1080
|
+
<br>
|
|
1081
|
+
|
|
1082
|
+
#### `DataStore.migrateId()`
|
|
1083
|
+
Usage: `migrateId(oldIds: string | string[]): Promise<void>`
|
|
1084
|
+
Tries to migrate the currently saved persistent data from one or more old IDs to the ID set in the constructor.
|
|
1085
|
+
If no data exist for the old ID(s), nothing will be done, but some time may still pass trying to fetch the non-existent data.
|
|
1086
|
+
Instead of calling this manually, consider setting the `migrateIds` property in the constructor to automatically migrate the data once per session in the call to `loadData()`, unless you know that you need to migrate the ID(s) manually.
|
|
1087
|
+
|
|
1088
|
+
<br>
|
|
1089
|
+
|
|
1090
|
+
#### `DataStore.encodingEnabled()`
|
|
1091
|
+
Usage: `encodingEnabled(): boolean`
|
|
1036
1092
|
Returns `true` if both `options.encodeData` and `options.decodeData` are set, else `false`.
|
|
1037
1093
|
Uses TypeScript's type guard notation for easier use in conditional statements.
|
|
1038
1094
|
|
|
@@ -1085,14 +1141,16 @@ const migrations = {
|
|
|
1085
1141
|
|
|
1086
1142
|
// You probably want to export this instance (or helper functions) so you can use it anywhere in your script:
|
|
1087
1143
|
export const manager = new DataStore({
|
|
1088
|
-
/** A unique ID for this instance
|
|
1144
|
+
/** A unique ID for this instance */
|
|
1089
1145
|
id: "my-userscript-config",
|
|
1090
1146
|
/** Default, initial and fallback data */
|
|
1091
1147
|
defaultData,
|
|
1092
|
-
/** The current version of the data format */
|
|
1148
|
+
/** The current version of the data format - should be a whole number that is only ever incremented */
|
|
1093
1149
|
formatVersion,
|
|
1094
1150
|
/** Data format migration functions called when the formatVersion is increased */
|
|
1095
1151
|
migrations,
|
|
1152
|
+
/** If the data was saved under different ID(s) before, providing them here will make sure the data is migrated to the current ID when `loadData()` is called */
|
|
1153
|
+
migrateIds: ["my-data", "config"],
|
|
1096
1154
|
/**
|
|
1097
1155
|
* Where the data should be stored.
|
|
1098
1156
|
* For example, you could use `"sessionStorage"` to make the data be automatically deleted after the browser session is finished, or use `"localStorage"` if you don't have access to GM storage for some reason.
|
|
@@ -1161,12 +1219,9 @@ The options object has the following properties:
|
|
|
1161
1219
|
|
|
1162
1220
|
<br>
|
|
1163
1221
|
|
|
1164
|
-
|
|
1165
|
-
`
|
|
1166
|
-
|
|
1167
|
-
If no options are passed, the defaults will be used.
|
|
1168
|
-
|
|
1169
|
-
`serialize(): Promise<string>`
|
|
1222
|
+
### Methods:
|
|
1223
|
+
#### `DataStoreSerializer.serialize()`
|
|
1224
|
+
Usage: `serialize(): Promise<string>`
|
|
1170
1225
|
Serializes all DataStore instances passed in the constructor and returns the serialized data as a JSON string.
|
|
1171
1226
|
<details><summary>Click to view the structure of the returned data.</summary>
|
|
1172
1227
|
|
|
@@ -1185,15 +1240,65 @@ Serializes all DataStore instances passed in the constructor and returns the ser
|
|
|
1185
1240
|
]
|
|
1186
1241
|
```
|
|
1187
1242
|
</details>
|
|
1188
|
-
|
|
1189
|
-
|
|
1190
|
-
|
|
1243
|
+
|
|
1244
|
+
<br>
|
|
1245
|
+
|
|
1246
|
+
#### `DataStoreSerializer.deserialize()`
|
|
1247
|
+
Usage: `deserialize(data: string): Promise<void>`
|
|
1248
|
+
Deserializes the given string that was created with `serialize()` and imports the contained data each DataStore instance.
|
|
1191
1249
|
In the process of importing the data, the migrations will be run, if the `formatVersion` property is lower than the one set on the DataStore instance.
|
|
1192
1250
|
|
|
1193
1251
|
If `ensureIntegrity` is set to `true` and the checksum doesn't match, an error will be thrown.
|
|
1194
1252
|
If `ensureIntegrity` is set to `false`, the checksum check will be skipped entirely.
|
|
1195
1253
|
If the `checksum` property is missing on the imported data, the checksum check will also be skipped.
|
|
1196
1254
|
If `encoded` is set to `true`, the data will be decoded using the `decodeData` function set on the DataStore instance.
|
|
1255
|
+
|
|
1256
|
+
<br>
|
|
1257
|
+
|
|
1258
|
+
#### `DataStoreSerializer.loadStoresData()`
|
|
1259
|
+
Usage: `loadStoresData(): PromiseSettledResult<{ id: string, data: object }>[];`
|
|
1260
|
+
Loads the persistent data of the DataStore instances into the in-memory cache of each DataStore instance.
|
|
1261
|
+
Also triggers the migration process if the data format has changed.
|
|
1262
|
+
See the [`DataStore.loadData()`](#datastoreloaddata) method for more information.
|
|
1263
|
+
|
|
1264
|
+
<details><summary>Click to view the structure of the returned data.</summary>
|
|
1265
|
+
|
|
1266
|
+
```jsonc
|
|
1267
|
+
[
|
|
1268
|
+
{
|
|
1269
|
+
"status": "fulfilled",
|
|
1270
|
+
"value": {
|
|
1271
|
+
"id": "foo-data",
|
|
1272
|
+
"data": {
|
|
1273
|
+
"foo": "hello",
|
|
1274
|
+
"bar": "world"
|
|
1275
|
+
}
|
|
1276
|
+
}
|
|
1277
|
+
},
|
|
1278
|
+
{
|
|
1279
|
+
"status": "rejected",
|
|
1280
|
+
"reason": "Checksum mismatch for DataStore with ID \"bar-data\"!\nExpected: 69beefdead420\nHas: abcdef42"
|
|
1281
|
+
}
|
|
1282
|
+
]
|
|
1283
|
+
```
|
|
1284
|
+
|
|
1285
|
+
</details>
|
|
1286
|
+
|
|
1287
|
+
<br>
|
|
1288
|
+
|
|
1289
|
+
#### `DataStoreSerializer.resetStoresData()`
|
|
1290
|
+
Usage: `resetStoresData(): PromiseSettledResult[];`
|
|
1291
|
+
Resets the persistent data of the DataStore instances to their default values.
|
|
1292
|
+
This affects both the in-memory cache and the persistent storage.
|
|
1293
|
+
Any call to `serialize()` will then use the value of `options.defaultData` of the respective DataStore instance.
|
|
1294
|
+
|
|
1295
|
+
<br>
|
|
1296
|
+
|
|
1297
|
+
#### `DataStoreSerializer.deleteStoresData()`
|
|
1298
|
+
Usage: `deleteStoresData(): PromiseSettledResult[];`
|
|
1299
|
+
Deletes the persistent data of the DataStore instances from the set storage method.
|
|
1300
|
+
Leaves the in-memory cache of the DataStore instances untouched.
|
|
1301
|
+
Any call to `setData()` on the instances will recreate their own persistent storage data.
|
|
1197
1302
|
|
|
1198
1303
|
<br>
|
|
1199
1304
|
|
|
@@ -1234,9 +1339,8 @@ const serializer = new DataStoreSerializer([fooStore, barStore], {
|
|
|
1234
1339
|
});
|
|
1235
1340
|
|
|
1236
1341
|
async function exportMyDataPls() {
|
|
1237
|
-
// first, make sure the persistent data of
|
|
1238
|
-
await
|
|
1239
|
-
await barStore.loadData();
|
|
1342
|
+
// first, make sure the persistent data of all stores is loaded into their caches:
|
|
1343
|
+
await serializer.loadStoresData();
|
|
1240
1344
|
|
|
1241
1345
|
// now serialize the data:
|
|
1242
1346
|
const serializedData = await serializer.serialize();
|
|
@@ -1269,11 +1373,11 @@ async function exportMyDataPls() {
|
|
|
1269
1373
|
}
|
|
1270
1374
|
|
|
1271
1375
|
async function importMyDataPls() {
|
|
1272
|
-
// grab the data from the file by using the system file picker or
|
|
1376
|
+
// grab the data from the file by using the system file picker or a text field or something similar
|
|
1273
1377
|
const data = await getDataFromSomewhere();
|
|
1274
1378
|
|
|
1275
1379
|
try {
|
|
1276
|
-
// import the data
|
|
1380
|
+
// import the data and run migrations if necessary
|
|
1277
1381
|
await serializer.deserialize(data);
|
|
1278
1382
|
}
|
|
1279
1383
|
catch(err) {
|
|
@@ -1281,6 +1385,11 @@ async function importMyDataPls() {
|
|
|
1281
1385
|
alert(`Data import failed: ${err}`);
|
|
1282
1386
|
}
|
|
1283
1387
|
}
|
|
1388
|
+
|
|
1389
|
+
async function resetMyDataPls() {
|
|
1390
|
+
// reset the data of all stores in both the cache and the persistent storage
|
|
1391
|
+
await serializer.resetStoresData();
|
|
1392
|
+
}
|
|
1284
1393
|
```
|
|
1285
1394
|
</details>
|
|
1286
1395
|
|
|
@@ -1313,41 +1422,74 @@ The options object has the following properties:
|
|
|
1313
1422
|
| `verticalAlign?: "top" \| "center" \| "bottom"` | (Optional) Where to align or anchor the dialog vertically. Defaults to `"center"`. |
|
|
1314
1423
|
| `strings?: Partial<typeof defaultStrings>` | (Optional) Strings used in the dialog (used for translations). Defaults to the default English strings (importable with the name `defaultStrings`). |
|
|
1315
1424
|
| `dialogCss?: string` | (Optional) CSS to apply to the dialog. Defaults to the default (importable with the name `defaultDialogCss`). |
|
|
1316
|
-
|
|
1317
|
-
|
|
1318
|
-
|
|
1425
|
+
|
|
1426
|
+
<br>
|
|
1427
|
+
|
|
1428
|
+
### Methods:
|
|
1429
|
+
#### `Dialog.open()`
|
|
1430
|
+
Usage: `open(): Promise<void>`
|
|
1319
1431
|
Opens the dialog.
|
|
1320
|
-
|
|
1321
|
-
|
|
1432
|
+
If the dialog is not mounted yet, it will be mounted before opening.
|
|
1433
|
+
|
|
1434
|
+
<br>
|
|
1435
|
+
|
|
1436
|
+
#### `Dialog.close()`
|
|
1437
|
+
Usage: `close(): void`
|
|
1322
1438
|
Closes the dialog.
|
|
1323
|
-
|
|
1324
|
-
|
|
1439
|
+
If `options.destroyOnClose` is set to `true`, [`Dialog.destroy()`](#dialogdestroy) will be called immediately after closing.
|
|
1440
|
+
|
|
1441
|
+
<br>
|
|
1442
|
+
|
|
1443
|
+
#### `Dialog.mount()`
|
|
1444
|
+
Usage: `mount(): Promise<void>`
|
|
1325
1445
|
Mounts the dialog to the DOM by calling the render functions provided in the options object.
|
|
1326
|
-
|
|
1327
|
-
|
|
1328
|
-
|
|
1329
|
-
|
|
1330
|
-
|
|
1331
|
-
`
|
|
1446
|
+
After calling, the dialog will exist in the DOM but will be invisible until [`Dialog.open()`](#dialogopen) is called.
|
|
1447
|
+
Call this before opening the dialog to avoid a rendering delay.
|
|
1448
|
+
|
|
1449
|
+
<br>
|
|
1450
|
+
|
|
1451
|
+
#### `Dialog.unmount()`
|
|
1452
|
+
Usage: `unmount(): void`
|
|
1453
|
+
Closes the dialog first if it's open, then removes it from the DOM.
|
|
1454
|
+
|
|
1455
|
+
<br>
|
|
1456
|
+
|
|
1457
|
+
#### `Dialog.remount()`
|
|
1458
|
+
Usage: `remount(): Promise<void>`
|
|
1332
1459
|
Unmounts and mounts the dialog again.
|
|
1333
1460
|
The render functions in the options object will be called again.
|
|
1334
1461
|
May cause a flickering effect due to the rendering delay.
|
|
1335
|
-
|
|
1336
|
-
|
|
1462
|
+
|
|
1463
|
+
<br>
|
|
1464
|
+
|
|
1465
|
+
#### `Dialog.isOpen()`
|
|
1466
|
+
Usage: `isOpen(): boolean`
|
|
1337
1467
|
Returns `true` if the dialog is open, else `false`.
|
|
1338
|
-
|
|
1339
|
-
|
|
1468
|
+
|
|
1469
|
+
<br>
|
|
1470
|
+
|
|
1471
|
+
#### `Dialog.isMounted()`
|
|
1472
|
+
Usage: `isMounted(): boolean`
|
|
1340
1473
|
Returns `true` if the dialog is mounted, else `false`.
|
|
1341
|
-
|
|
1342
|
-
|
|
1474
|
+
|
|
1475
|
+
<br>
|
|
1476
|
+
|
|
1477
|
+
#### `Dialog.destroy()`
|
|
1478
|
+
Usage: `destroy(): void`
|
|
1343
1479
|
Destroys the dialog.
|
|
1344
|
-
Removes all listeners and unmounts the dialog
|
|
1345
|
-
|
|
1346
|
-
|
|
1480
|
+
Removes all listeners by default and closes and unmounts the dialog.
|
|
1481
|
+
|
|
1482
|
+
<br>
|
|
1483
|
+
|
|
1484
|
+
#### `Dialog.getCurrentDialogId()`
|
|
1485
|
+
Usage: `static getCurrentDialogId(): string`
|
|
1347
1486
|
Static method that returns the ID of the currently open dialog.
|
|
1348
1487
|
Needs to be called without creating an instance of the class.
|
|
1349
|
-
|
|
1350
|
-
|
|
1488
|
+
|
|
1489
|
+
<br>
|
|
1490
|
+
|
|
1491
|
+
#### `Dialog.getOpenDialogs()`
|
|
1492
|
+
Usage: `static getOpenDialogs(): string[]`
|
|
1351
1493
|
Static method that returns an array of the IDs of all open dialogs.
|
|
1352
1494
|
Needs to be called without creating an instance of the class.
|
|
1353
1495
|
|
|
@@ -1392,6 +1534,10 @@ fooDialog.on("close", () => {
|
|
|
1392
1534
|
console.log("Dialog closed");
|
|
1393
1535
|
});
|
|
1394
1536
|
|
|
1537
|
+
fooDialog.on("open", () => {
|
|
1538
|
+
console.log("Currently open dialogs:", Dialog.getOpenDialogs());
|
|
1539
|
+
});
|
|
1540
|
+
|
|
1395
1541
|
fooDialog.open();
|
|
1396
1542
|
```
|
|
1397
1543
|
</details>
|
|
@@ -1471,6 +1617,7 @@ myInstance.on("foo", (bar) => {
|
|
|
1471
1617
|
console.log("foo event (outside):", bar);
|
|
1472
1618
|
});
|
|
1473
1619
|
|
|
1620
|
+
// only works if publicEmit is set to true
|
|
1474
1621
|
myInstance.emit("baz", "hello from the outside");
|
|
1475
1622
|
|
|
1476
1623
|
myInstance.unsubscribeAll();
|
|
@@ -1504,6 +1651,7 @@ myEmitter.once("baz", (qux) => {
|
|
|
1504
1651
|
});
|
|
1505
1652
|
|
|
1506
1653
|
function doStuff() {
|
|
1654
|
+
// only works if publicEmit is set to true
|
|
1507
1655
|
myEmitter.emit("foo", "hello");
|
|
1508
1656
|
myEmitter.emit("baz", 42);
|
|
1509
1657
|
myEmitter.emit("foo", "world");
|
|
@@ -1784,7 +1932,7 @@ run();
|
|
|
1784
1932
|
### randomId()
|
|
1785
1933
|
Usage:
|
|
1786
1934
|
```ts
|
|
1787
|
-
randomId(length?: number, radix?: number, enhancedEntropy?: boolean): string
|
|
1935
|
+
randomId(length?: number, radix?: number, enhancedEntropy?: boolean, randomCase?: boolean): string
|
|
1788
1936
|
```
|
|
1789
1937
|
|
|
1790
1938
|
Generates a random ID of a given length and [radix (base).](https://en.wikipedia.org/wiki/Radix)
|
|
@@ -1794,20 +1942,41 @@ You may change the radix to get digits from different numerical systems.
|
|
|
1794
1942
|
Use 2 for binary, 8 for octal, 10 for decimal, 16 for hexadecimal and 36 for alphanumeric.
|
|
1795
1943
|
|
|
1796
1944
|
If `enhancedEntropy` is set to true (false by default), the [Web Crypto API](https://developer.mozilla.org/en-US/docs/Web/API/Crypto/getRandomValues) is used for generating the random numbers.
|
|
1797
|
-
Note that this
|
|
1945
|
+
Note that this makes the function call take longer, but the generated IDs will have a higher entropy.
|
|
1946
|
+
|
|
1947
|
+
If `randomCase` is set to true (which it is by default), the generated ID will contain both upper and lower case letters.
|
|
1948
|
+
This randomization is also affected by the `enhancedEntropy` setting, unless there are no alphabetic characters in the output in which case it will be skipped.
|
|
1798
1949
|
|
|
1799
|
-
⚠️
|
|
1950
|
+
⚠️ This is not suitable for generating anything related to cryptography! Use [SubtleCrypto's `generateKey()`](https://developer.mozilla.org/en-US/docs/Web/API/SubtleCrypto/generateKey) for that instead.
|
|
1800
1951
|
|
|
1801
1952
|
<details><summary><b>Example - click to view</b></summary>
|
|
1802
1953
|
|
|
1803
1954
|
```ts
|
|
1804
1955
|
import { randomId } from "@sv443-network/userutils";
|
|
1805
1956
|
|
|
1806
|
-
randomId();
|
|
1807
|
-
randomId(10);
|
|
1808
|
-
randomId(10, 2);
|
|
1809
|
-
randomId(10, 10);
|
|
1810
|
-
randomId(10, 36); // "
|
|
1957
|
+
randomId(); // "1bda419a73629d4f" (length 16, radix 16)
|
|
1958
|
+
randomId(10); // "f86cd354a4" (length 10, radix 16)
|
|
1959
|
+
randomId(10, 2); // "1010001101" (length 10, radix 2)
|
|
1960
|
+
randomId(10, 10); // "0183428506" (length 10, radix 10)
|
|
1961
|
+
randomId(10, 36, false, true); // "z46jFPa37R" (length 10, radix 36, random case)
|
|
1962
|
+
|
|
1963
|
+
|
|
1964
|
+
function benchmark(enhancedEntropy: boolean, randomCase: boolean) {
|
|
1965
|
+
const timestamp = Date.now();
|
|
1966
|
+
for(let i = 0; i < 10_000; i++)
|
|
1967
|
+
randomId(16, 36, enhancedEntropy, randomCase);
|
|
1968
|
+
console.log(`Generated 10k in ${Date.now() - timestamp}ms`)
|
|
1969
|
+
}
|
|
1970
|
+
|
|
1971
|
+
// using Math.random():
|
|
1972
|
+
benchmark(false, false); // Generated 10k in 239ms
|
|
1973
|
+
benchmark(false, true); // Generated 10k in 248ms
|
|
1974
|
+
|
|
1975
|
+
// using crypto.getRandomValues():
|
|
1976
|
+
benchmark(true, false); // Generated 10k in 1076ms
|
|
1977
|
+
benchmark(true, true); // Generated 10k in 1054ms
|
|
1978
|
+
|
|
1979
|
+
// 3rd and 4th have a similar time, but in reality the 4th blocks the event loop for much longer
|
|
1811
1980
|
```
|
|
1812
1981
|
</details>
|
|
1813
1982
|
|
|
@@ -2295,7 +2464,7 @@ Usage:
|
|
|
2295
2464
|
NonEmptyArray<TItem = unknown>
|
|
2296
2465
|
```
|
|
2297
2466
|
|
|
2298
|
-
This type describes an array that has at least one item.
|
|
2467
|
+
This generic type describes an array that has at least one item.
|
|
2299
2468
|
Use the generic parameter to specify the type of the items in the array.
|
|
2300
2469
|
|
|
2301
2470
|
<details><summary><b>Example - click to view</b></summary>
|
|
@@ -2325,7 +2494,7 @@ Usage:
|
|
|
2325
2494
|
NonEmptyString<TString extends string>
|
|
2326
2495
|
```
|
|
2327
2496
|
|
|
2328
|
-
This type describes a string that has at least one character.
|
|
2497
|
+
This generic type describes a string that has at least one character.
|
|
2329
2498
|
|
|
2330
2499
|
<details><summary><b>Example - click to view</b></summary>
|
|
2331
2500
|
|
|
@@ -2349,7 +2518,7 @@ Usage:
|
|
|
2349
2518
|
LooseUnion<TUnion extends string | number | object>
|
|
2350
2519
|
```
|
|
2351
2520
|
|
|
2352
|
-
A type that offers autocomplete in the IDE for the passed union but also allows any value of the same type to be passed.
|
|
2521
|
+
A generic type that offers autocomplete in the IDE for the passed union but also allows any value of the same type to be passed.
|
|
2353
2522
|
Supports unions of strings, numbers and objects.
|
|
2354
2523
|
|
|
2355
2524
|
<details><summary><b>Example - click to view</b></summary>
|
|
@@ -2368,6 +2537,61 @@ foo(1); // type error: Argument of type '1' is not assignable to parameter of
|
|
|
2368
2537
|
```
|
|
2369
2538
|
</details>
|
|
2370
2539
|
|
|
2540
|
+
<br>
|
|
2541
|
+
|
|
2542
|
+
## Prettify
|
|
2543
|
+
Usage:
|
|
2544
|
+
```ts
|
|
2545
|
+
Prettify<T>
|
|
2546
|
+
```
|
|
2547
|
+
|
|
2548
|
+
A generic type that makes TypeScript and your IDE display the type in a more readable way.
|
|
2549
|
+
This is especially useful for types that reference other types or are very complex.
|
|
2550
|
+
It will also make a variable show its type's structure instead of just the type name (see example).
|
|
2551
|
+
|
|
2552
|
+
<details><summary><b>Example - click to view</b></summary>
|
|
2553
|
+
|
|
2554
|
+
```ts
|
|
2555
|
+
// tooltip shows all constituent types, leaving you to figure it out yourself:
|
|
2556
|
+
// type Foo = {
|
|
2557
|
+
// a: number;
|
|
2558
|
+
// } & Omit<{
|
|
2559
|
+
// b: string;
|
|
2560
|
+
// c: boolean;
|
|
2561
|
+
// }, "c">
|
|
2562
|
+
type Foo = {
|
|
2563
|
+
a: number;
|
|
2564
|
+
} & Omit<{
|
|
2565
|
+
b: string;
|
|
2566
|
+
c: boolean;
|
|
2567
|
+
}, "c">;
|
|
2568
|
+
|
|
2569
|
+
// tooltip shows just the type name:
|
|
2570
|
+
// const foo: Foo
|
|
2571
|
+
const foo: Foo = {
|
|
2572
|
+
a: 1,
|
|
2573
|
+
b: "2"
|
|
2574
|
+
};
|
|
2575
|
+
|
|
2576
|
+
// tooltip shows the actual type structure:
|
|
2577
|
+
// type Bar = {
|
|
2578
|
+
// a: number;
|
|
2579
|
+
// b: string;
|
|
2580
|
+
// }
|
|
2581
|
+
type Bar = Prettify<Foo>;
|
|
2582
|
+
|
|
2583
|
+
// tooltip again shows the actual type structure:
|
|
2584
|
+
// const bar: {
|
|
2585
|
+
// a: number;
|
|
2586
|
+
// b: string;
|
|
2587
|
+
// }
|
|
2588
|
+
const bar: Bar = {
|
|
2589
|
+
a: 1,
|
|
2590
|
+
b: "2"
|
|
2591
|
+
};
|
|
2592
|
+
```
|
|
2593
|
+
</details>
|
|
2594
|
+
|
|
2371
2595
|
<br><br><br><br>
|
|
2372
2596
|
|
|
2373
2597
|
<!-- #region Footer -->
|
package/dist/index.global.js
CHANGED
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
// ==UserLibrary==
|
|
9
9
|
// @name UserUtils
|
|
10
10
|
// @description Library with various utilities for userscripts - register listeners for when CSS selectors exist, intercept events, create persistent & synchronous data stores, modify the DOM more easily and more
|
|
11
|
-
// @version 8.0
|
|
11
|
+
// @version 8.2.0
|
|
12
12
|
// @license MIT
|
|
13
13
|
// @copyright Sv443 (https://github.com/Sv443)
|
|
14
14
|
|
|
@@ -78,12 +78,18 @@ var UserUtils = (function (exports) {
|
|
|
78
78
|
return Math.max(Math.min(value, max), min);
|
|
79
79
|
}
|
|
80
80
|
function mapRange(value, range1min, range1max, range2min, range2max) {
|
|
81
|
+
if (typeof range2min === "undefined" || range2max === void 0) {
|
|
82
|
+
range2max = range1max;
|
|
83
|
+
range2min = 0;
|
|
84
|
+
range1max = range1min;
|
|
85
|
+
range1min = 0;
|
|
86
|
+
}
|
|
81
87
|
if (Number(range1min) === 0 && Number(range2min) === 0)
|
|
82
88
|
return value * (range2max / range1max);
|
|
83
89
|
return (value - range1min) * ((range2max - range2min) / (range1max - range1min)) + range2min;
|
|
84
90
|
}
|
|
85
91
|
function randRange(...args) {
|
|
86
|
-
let min, max;
|
|
92
|
+
let min, max, enhancedEntropy = false;
|
|
87
93
|
if (typeof args[0] === "number" && typeof args[1] === "number")
|
|
88
94
|
[min, max] = args;
|
|
89
95
|
else if (typeof args[0] === "number" && typeof args[1] !== "number") {
|
|
@@ -91,13 +97,25 @@ var UserUtils = (function (exports) {
|
|
|
91
97
|
[max] = args;
|
|
92
98
|
} else
|
|
93
99
|
throw new TypeError(`Wrong parameter(s) provided - expected: "number" and "number|undefined", got: "${typeof args[0]}" and "${typeof args[1]}"`);
|
|
100
|
+
if (typeof args[2] === "boolean")
|
|
101
|
+
enhancedEntropy = args[2];
|
|
102
|
+
else if (typeof args[1] === "boolean")
|
|
103
|
+
enhancedEntropy = args[1];
|
|
94
104
|
min = Number(min);
|
|
95
105
|
max = Number(max);
|
|
96
106
|
if (isNaN(min) || isNaN(max))
|
|
97
107
|
return NaN;
|
|
98
108
|
if (min > max)
|
|
99
109
|
throw new TypeError(`Parameter "min" can't be bigger than "max"`);
|
|
100
|
-
|
|
110
|
+
if (enhancedEntropy) {
|
|
111
|
+
const uintArr = new Uint8Array(1);
|
|
112
|
+
crypto.getRandomValues(uintArr);
|
|
113
|
+
return Number(Array.from(
|
|
114
|
+
uintArr,
|
|
115
|
+
(v) => Math.round(mapRange(v, 0, 255, min, max)).toString(10).substring(0, 1)
|
|
116
|
+
).join(""));
|
|
117
|
+
} else
|
|
118
|
+
return Math.floor(Math.random() * (max - min + 1)) + min;
|
|
101
119
|
}
|
|
102
120
|
|
|
103
121
|
// lib/array.ts
|
|
@@ -356,19 +374,25 @@ var UserUtils = (function (exports) {
|
|
|
356
374
|
return hashHex;
|
|
357
375
|
});
|
|
358
376
|
}
|
|
359
|
-
function randomId(length = 16, radix = 16, enhancedEntropy = false) {
|
|
377
|
+
function randomId(length = 16, radix = 16, enhancedEntropy = false, randomCase = true) {
|
|
378
|
+
let arr = [];
|
|
379
|
+
const caseArr = randomCase ? [0, 1] : [0];
|
|
360
380
|
if (enhancedEntropy) {
|
|
361
|
-
const
|
|
362
|
-
crypto.getRandomValues(
|
|
363
|
-
|
|
364
|
-
|
|
381
|
+
const uintArr = new Uint8Array(length);
|
|
382
|
+
crypto.getRandomValues(uintArr);
|
|
383
|
+
arr = Array.from(
|
|
384
|
+
uintArr,
|
|
365
385
|
(v) => mapRange(v, 0, 255, 0, radix).toString(radix).substring(0, 1)
|
|
366
|
-
)
|
|
386
|
+
);
|
|
387
|
+
} else {
|
|
388
|
+
arr = Array.from(
|
|
389
|
+
{ length },
|
|
390
|
+
() => Math.floor(Math.random() * radix).toString(radix)
|
|
391
|
+
);
|
|
367
392
|
}
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
).join("");
|
|
393
|
+
if (!arr.some((v) => /[a-zA-Z]/.test(v)))
|
|
394
|
+
return arr.join("");
|
|
395
|
+
return arr.map((v) => caseArr[randRange(0, caseArr.length - 1, enhancedEntropy)] === 1 ? v.toUpperCase() : v).join("");
|
|
372
396
|
}
|
|
373
397
|
|
|
374
398
|
// lib/DataStore.ts
|
|
@@ -392,12 +416,15 @@ var UserUtils = (function (exports) {
|
|
|
392
416
|
__publicField(this, "storageMethod");
|
|
393
417
|
__publicField(this, "cachedData");
|
|
394
418
|
__publicField(this, "migrations");
|
|
419
|
+
__publicField(this, "migrateIds", []);
|
|
395
420
|
var _a;
|
|
396
421
|
this.id = options.id;
|
|
397
422
|
this.formatVersion = options.formatVersion;
|
|
398
423
|
this.defaultData = options.defaultData;
|
|
399
424
|
this.cachedData = options.defaultData;
|
|
400
425
|
this.migrations = options.migrations;
|
|
426
|
+
if (options.migrateIds)
|
|
427
|
+
this.migrateIds = Array.isArray(options.migrateIds) ? options.migrateIds : [options.migrateIds];
|
|
401
428
|
this.storageMethod = (_a = options.storageMethod) != null ? _a : "GM";
|
|
402
429
|
this.encodeData = options.encodeData;
|
|
403
430
|
this.decodeData = options.decodeData;
|
|
@@ -411,6 +438,10 @@ var UserUtils = (function (exports) {
|
|
|
411
438
|
loadData() {
|
|
412
439
|
return __async(this, null, function* () {
|
|
413
440
|
try {
|
|
441
|
+
if (this.migrateIds.length > 0) {
|
|
442
|
+
yield this.migrateId(this.migrateIds);
|
|
443
|
+
this.migrateIds = [];
|
|
444
|
+
}
|
|
414
445
|
const gmData = yield this.getValue(`_uucfg-${this.id}`, JSON.stringify(this.defaultData));
|
|
415
446
|
let gmFmtVer = Number(yield this.getValue(`_uucfgver-${this.id}`, NaN));
|
|
416
447
|
if (typeof gmData !== "string") {
|
|
@@ -478,7 +509,7 @@ var UserUtils = (function (exports) {
|
|
|
478
509
|
* The in-memory cache will be left untouched, so you may still access the data with {@linkcode getData()}
|
|
479
510
|
* Calling {@linkcode loadData()} or {@linkcode setData()} after this method was called will recreate persistent storage with the cached or default data.
|
|
480
511
|
*
|
|
481
|
-
* ⚠️ This requires the additional directive `@grant GM.deleteValue`
|
|
512
|
+
* ⚠️ This requires the additional directive `@grant GM.deleteValue` if the storageMethod is left as the default of `"GM"`
|
|
482
513
|
*/
|
|
483
514
|
deleteData() {
|
|
484
515
|
return __async(this, null, function* () {
|
|
@@ -532,6 +563,31 @@ var UserUtils = (function (exports) {
|
|
|
532
563
|
return this.cachedData = __spreadValues({}, newData);
|
|
533
564
|
});
|
|
534
565
|
}
|
|
566
|
+
/**
|
|
567
|
+
* Tries to migrate the currently saved persistent data from one or more old IDs to the ID set in the constructor.
|
|
568
|
+
* If no data exist for the old ID(s), nothing will be done, but some time may still pass trying to fetch the non-existent data.
|
|
569
|
+
*/
|
|
570
|
+
migrateId(oldIds) {
|
|
571
|
+
return __async(this, null, function* () {
|
|
572
|
+
const ids = Array.isArray(oldIds) ? oldIds : [oldIds];
|
|
573
|
+
yield Promise.all(ids.map((id) => __async(this, null, function* () {
|
|
574
|
+
const data = yield this.getValue(`_uucfg-${id}`, JSON.stringify(this.defaultData));
|
|
575
|
+
const fmtVer = Number(yield this.getValue(`_uucfgver-${id}`, NaN));
|
|
576
|
+
const isEncoded = Boolean(yield this.getValue(`_uucfgenc-${id}`, false));
|
|
577
|
+
if (data === void 0 || isNaN(fmtVer))
|
|
578
|
+
return;
|
|
579
|
+
const parsed = yield this.deserializeData(data, isEncoded);
|
|
580
|
+
yield Promise.allSettled([
|
|
581
|
+
this.setValue(`_uucfg-${this.id}`, yield this.serializeData(parsed)),
|
|
582
|
+
this.setValue(`_uucfgver-${this.id}`, fmtVer),
|
|
583
|
+
this.setValue(`_uucfgenc-${this.id}`, isEncoded),
|
|
584
|
+
this.deleteValue(`_uucfg-${id}`),
|
|
585
|
+
this.deleteValue(`_uucfgver-${id}`),
|
|
586
|
+
this.deleteValue(`_uucfgenc-${id}`)
|
|
587
|
+
]);
|
|
588
|
+
})));
|
|
589
|
+
});
|
|
590
|
+
}
|
|
535
591
|
//#region serialization
|
|
536
592
|
/** Serializes the data using the optional this.encodeData() and returns it as a string */
|
|
537
593
|
serializeData(data, useEncoding = true) {
|
|
@@ -673,6 +729,38 @@ Has: ${checksum}`);
|
|
|
673
729
|
}
|
|
674
730
|
});
|
|
675
731
|
}
|
|
732
|
+
/**
|
|
733
|
+
* Loads the persistent data of the DataStore instances into the in-memory cache.
|
|
734
|
+
* Also triggers the migration process if the data format has changed.
|
|
735
|
+
* @returns Returns a PromiseSettledResult array with the results of each DataStore instance in the format `{ id: string, data: object }`
|
|
736
|
+
*/
|
|
737
|
+
loadStoresData() {
|
|
738
|
+
return __async(this, null, function* () {
|
|
739
|
+
return Promise.allSettled(this.stores.map(
|
|
740
|
+
(store) => __async(this, null, function* () {
|
|
741
|
+
return {
|
|
742
|
+
id: store.id,
|
|
743
|
+
data: yield store.loadData()
|
|
744
|
+
};
|
|
745
|
+
})
|
|
746
|
+
));
|
|
747
|
+
});
|
|
748
|
+
}
|
|
749
|
+
/** Resets the persistent data of the DataStore instances to their default values. */
|
|
750
|
+
resetStoresData() {
|
|
751
|
+
return __async(this, null, function* () {
|
|
752
|
+
return Promise.allSettled(this.stores.map((store) => store.saveDefaultData()));
|
|
753
|
+
});
|
|
754
|
+
}
|
|
755
|
+
/**
|
|
756
|
+
* Deletes the persistent data of the DataStore instances.
|
|
757
|
+
* Leaves the in-memory data untouched.
|
|
758
|
+
*/
|
|
759
|
+
deleteStoresData() {
|
|
760
|
+
return __async(this, null, function* () {
|
|
761
|
+
return Promise.allSettled(this.stores.map((store) => store.deleteData()));
|
|
762
|
+
});
|
|
763
|
+
}
|
|
676
764
|
};
|
|
677
765
|
|
|
678
766
|
// node_modules/nanoevents/index.js
|
package/dist/index.js
CHANGED
|
@@ -58,12 +58,18 @@ function clamp(value, min, max) {
|
|
|
58
58
|
return Math.max(Math.min(value, max), min);
|
|
59
59
|
}
|
|
60
60
|
function mapRange(value, range1min, range1max, range2min, range2max) {
|
|
61
|
+
if (typeof range2min === "undefined" || range2max === void 0) {
|
|
62
|
+
range2max = range1max;
|
|
63
|
+
range2min = 0;
|
|
64
|
+
range1max = range1min;
|
|
65
|
+
range1min = 0;
|
|
66
|
+
}
|
|
61
67
|
if (Number(range1min) === 0 && Number(range2min) === 0)
|
|
62
68
|
return value * (range2max / range1max);
|
|
63
69
|
return (value - range1min) * ((range2max - range2min) / (range1max - range1min)) + range2min;
|
|
64
70
|
}
|
|
65
71
|
function randRange(...args) {
|
|
66
|
-
let min, max;
|
|
72
|
+
let min, max, enhancedEntropy = false;
|
|
67
73
|
if (typeof args[0] === "number" && typeof args[1] === "number")
|
|
68
74
|
[min, max] = args;
|
|
69
75
|
else if (typeof args[0] === "number" && typeof args[1] !== "number") {
|
|
@@ -71,13 +77,25 @@ function randRange(...args) {
|
|
|
71
77
|
[max] = args;
|
|
72
78
|
} else
|
|
73
79
|
throw new TypeError(`Wrong parameter(s) provided - expected: "number" and "number|undefined", got: "${typeof args[0]}" and "${typeof args[1]}"`);
|
|
80
|
+
if (typeof args[2] === "boolean")
|
|
81
|
+
enhancedEntropy = args[2];
|
|
82
|
+
else if (typeof args[1] === "boolean")
|
|
83
|
+
enhancedEntropy = args[1];
|
|
74
84
|
min = Number(min);
|
|
75
85
|
max = Number(max);
|
|
76
86
|
if (isNaN(min) || isNaN(max))
|
|
77
87
|
return NaN;
|
|
78
88
|
if (min > max)
|
|
79
89
|
throw new TypeError(`Parameter "min" can't be bigger than "max"`);
|
|
80
|
-
|
|
90
|
+
if (enhancedEntropy) {
|
|
91
|
+
const uintArr = new Uint8Array(1);
|
|
92
|
+
crypto.getRandomValues(uintArr);
|
|
93
|
+
return Number(Array.from(
|
|
94
|
+
uintArr,
|
|
95
|
+
(v) => Math.round(mapRange(v, 0, 255, min, max)).toString(10).substring(0, 1)
|
|
96
|
+
).join(""));
|
|
97
|
+
} else
|
|
98
|
+
return Math.floor(Math.random() * (max - min + 1)) + min;
|
|
81
99
|
}
|
|
82
100
|
|
|
83
101
|
// lib/array.ts
|
|
@@ -336,19 +354,25 @@ function computeHash(input, algorithm = "SHA-256") {
|
|
|
336
354
|
return hashHex;
|
|
337
355
|
});
|
|
338
356
|
}
|
|
339
|
-
function randomId(length = 16, radix = 16, enhancedEntropy = false) {
|
|
357
|
+
function randomId(length = 16, radix = 16, enhancedEntropy = false, randomCase = true) {
|
|
358
|
+
let arr = [];
|
|
359
|
+
const caseArr = randomCase ? [0, 1] : [0];
|
|
340
360
|
if (enhancedEntropy) {
|
|
341
|
-
const
|
|
342
|
-
crypto.getRandomValues(
|
|
343
|
-
|
|
344
|
-
|
|
361
|
+
const uintArr = new Uint8Array(length);
|
|
362
|
+
crypto.getRandomValues(uintArr);
|
|
363
|
+
arr = Array.from(
|
|
364
|
+
uintArr,
|
|
345
365
|
(v) => mapRange(v, 0, 255, 0, radix).toString(radix).substring(0, 1)
|
|
346
|
-
)
|
|
366
|
+
);
|
|
367
|
+
} else {
|
|
368
|
+
arr = Array.from(
|
|
369
|
+
{ length },
|
|
370
|
+
() => Math.floor(Math.random() * radix).toString(radix)
|
|
371
|
+
);
|
|
347
372
|
}
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
).join("");
|
|
373
|
+
if (!arr.some((v) => /[a-zA-Z]/.test(v)))
|
|
374
|
+
return arr.join("");
|
|
375
|
+
return arr.map((v) => caseArr[randRange(0, caseArr.length - 1, enhancedEntropy)] === 1 ? v.toUpperCase() : v).join("");
|
|
352
376
|
}
|
|
353
377
|
|
|
354
378
|
// lib/DataStore.ts
|
|
@@ -372,12 +396,15 @@ var DataStore = class {
|
|
|
372
396
|
__publicField(this, "storageMethod");
|
|
373
397
|
__publicField(this, "cachedData");
|
|
374
398
|
__publicField(this, "migrations");
|
|
399
|
+
__publicField(this, "migrateIds", []);
|
|
375
400
|
var _a;
|
|
376
401
|
this.id = options.id;
|
|
377
402
|
this.formatVersion = options.formatVersion;
|
|
378
403
|
this.defaultData = options.defaultData;
|
|
379
404
|
this.cachedData = options.defaultData;
|
|
380
405
|
this.migrations = options.migrations;
|
|
406
|
+
if (options.migrateIds)
|
|
407
|
+
this.migrateIds = Array.isArray(options.migrateIds) ? options.migrateIds : [options.migrateIds];
|
|
381
408
|
this.storageMethod = (_a = options.storageMethod) != null ? _a : "GM";
|
|
382
409
|
this.encodeData = options.encodeData;
|
|
383
410
|
this.decodeData = options.decodeData;
|
|
@@ -391,6 +418,10 @@ var DataStore = class {
|
|
|
391
418
|
loadData() {
|
|
392
419
|
return __async(this, null, function* () {
|
|
393
420
|
try {
|
|
421
|
+
if (this.migrateIds.length > 0) {
|
|
422
|
+
yield this.migrateId(this.migrateIds);
|
|
423
|
+
this.migrateIds = [];
|
|
424
|
+
}
|
|
394
425
|
const gmData = yield this.getValue(`_uucfg-${this.id}`, JSON.stringify(this.defaultData));
|
|
395
426
|
let gmFmtVer = Number(yield this.getValue(`_uucfgver-${this.id}`, NaN));
|
|
396
427
|
if (typeof gmData !== "string") {
|
|
@@ -458,7 +489,7 @@ var DataStore = class {
|
|
|
458
489
|
* The in-memory cache will be left untouched, so you may still access the data with {@linkcode getData()}
|
|
459
490
|
* Calling {@linkcode loadData()} or {@linkcode setData()} after this method was called will recreate persistent storage with the cached or default data.
|
|
460
491
|
*
|
|
461
|
-
* ⚠️ This requires the additional directive `@grant GM.deleteValue`
|
|
492
|
+
* ⚠️ This requires the additional directive `@grant GM.deleteValue` if the storageMethod is left as the default of `"GM"`
|
|
462
493
|
*/
|
|
463
494
|
deleteData() {
|
|
464
495
|
return __async(this, null, function* () {
|
|
@@ -512,6 +543,31 @@ var DataStore = class {
|
|
|
512
543
|
return this.cachedData = __spreadValues({}, newData);
|
|
513
544
|
});
|
|
514
545
|
}
|
|
546
|
+
/**
|
|
547
|
+
* Tries to migrate the currently saved persistent data from one or more old IDs to the ID set in the constructor.
|
|
548
|
+
* If no data exist for the old ID(s), nothing will be done, but some time may still pass trying to fetch the non-existent data.
|
|
549
|
+
*/
|
|
550
|
+
migrateId(oldIds) {
|
|
551
|
+
return __async(this, null, function* () {
|
|
552
|
+
const ids = Array.isArray(oldIds) ? oldIds : [oldIds];
|
|
553
|
+
yield Promise.all(ids.map((id) => __async(this, null, function* () {
|
|
554
|
+
const data = yield this.getValue(`_uucfg-${id}`, JSON.stringify(this.defaultData));
|
|
555
|
+
const fmtVer = Number(yield this.getValue(`_uucfgver-${id}`, NaN));
|
|
556
|
+
const isEncoded = Boolean(yield this.getValue(`_uucfgenc-${id}`, false));
|
|
557
|
+
if (data === void 0 || isNaN(fmtVer))
|
|
558
|
+
return;
|
|
559
|
+
const parsed = yield this.deserializeData(data, isEncoded);
|
|
560
|
+
yield Promise.allSettled([
|
|
561
|
+
this.setValue(`_uucfg-${this.id}`, yield this.serializeData(parsed)),
|
|
562
|
+
this.setValue(`_uucfgver-${this.id}`, fmtVer),
|
|
563
|
+
this.setValue(`_uucfgenc-${this.id}`, isEncoded),
|
|
564
|
+
this.deleteValue(`_uucfg-${id}`),
|
|
565
|
+
this.deleteValue(`_uucfgver-${id}`),
|
|
566
|
+
this.deleteValue(`_uucfgenc-${id}`)
|
|
567
|
+
]);
|
|
568
|
+
})));
|
|
569
|
+
});
|
|
570
|
+
}
|
|
515
571
|
//#region serialization
|
|
516
572
|
/** Serializes the data using the optional this.encodeData() and returns it as a string */
|
|
517
573
|
serializeData(data, useEncoding = true) {
|
|
@@ -653,6 +709,38 @@ Has: ${checksum}`);
|
|
|
653
709
|
}
|
|
654
710
|
});
|
|
655
711
|
}
|
|
712
|
+
/**
|
|
713
|
+
* Loads the persistent data of the DataStore instances into the in-memory cache.
|
|
714
|
+
* Also triggers the migration process if the data format has changed.
|
|
715
|
+
* @returns Returns a PromiseSettledResult array with the results of each DataStore instance in the format `{ id: string, data: object }`
|
|
716
|
+
*/
|
|
717
|
+
loadStoresData() {
|
|
718
|
+
return __async(this, null, function* () {
|
|
719
|
+
return Promise.allSettled(this.stores.map(
|
|
720
|
+
(store) => __async(this, null, function* () {
|
|
721
|
+
return {
|
|
722
|
+
id: store.id,
|
|
723
|
+
data: yield store.loadData()
|
|
724
|
+
};
|
|
725
|
+
})
|
|
726
|
+
));
|
|
727
|
+
});
|
|
728
|
+
}
|
|
729
|
+
/** Resets the persistent data of the DataStore instances to their default values. */
|
|
730
|
+
resetStoresData() {
|
|
731
|
+
return __async(this, null, function* () {
|
|
732
|
+
return Promise.allSettled(this.stores.map((store) => store.saveDefaultData()));
|
|
733
|
+
});
|
|
734
|
+
}
|
|
735
|
+
/**
|
|
736
|
+
* Deletes the persistent data of the DataStore instances.
|
|
737
|
+
* Leaves the in-memory data untouched.
|
|
738
|
+
*/
|
|
739
|
+
deleteStoresData() {
|
|
740
|
+
return __async(this, null, function* () {
|
|
741
|
+
return Promise.allSettled(this.stores.map((store) => store.deleteData()));
|
|
742
|
+
});
|
|
743
|
+
}
|
|
656
744
|
};
|
|
657
745
|
var NanoEmitter = class {
|
|
658
746
|
constructor(options = {}) {
|
package/dist/lib/DataStore.d.ts
CHANGED
|
@@ -5,11 +5,15 @@ type MigrationFunc = (oldData: any) => any | Promise<any>;
|
|
|
5
5
|
export type DataMigrationsDict = Record<number, MigrationFunc>;
|
|
6
6
|
/** Options for the DataStore instance */
|
|
7
7
|
export type DataStoreOptions<TData> = {
|
|
8
|
-
/**
|
|
8
|
+
/**
|
|
9
|
+
* A unique internal ID for this data store.
|
|
10
|
+
* To avoid conflicts with other scripts, it is recommended to use a prefix that is unique to your script.
|
|
11
|
+
* If you want to change the ID, you should make use of the {@linkcode DataStore.migrateId()} method.
|
|
12
|
+
*/
|
|
9
13
|
id: string;
|
|
10
14
|
/**
|
|
11
15
|
* The default data object to use if no data is saved in persistent storage yet.
|
|
12
|
-
* Until the data is loaded from persistent storage with
|
|
16
|
+
* Until the data is loaded from persistent storage with {@linkcode DataStore.loadData()}, this will be the data returned by {@linkcode DataStore.getData()}.
|
|
13
17
|
*
|
|
14
18
|
* ⚠️ This has to be an object that can be serialized to JSON using `JSON.stringify()`, so no functions or circular references are allowed, they will cause unexpected behavior.
|
|
15
19
|
*/
|
|
@@ -29,10 +33,17 @@ export type DataStoreOptions<TData> = {
|
|
|
29
33
|
* If the current format version is not in the dictionary, no migrations will be run.
|
|
30
34
|
*/
|
|
31
35
|
migrations?: DataMigrationsDict;
|
|
36
|
+
/**
|
|
37
|
+
* If an ID or multiple IDs are passed here, the data will be migrated from the old ID(s) to the current ID.
|
|
38
|
+
* This will happen once per page load, when {@linkcode DataStore.loadData()} is called.
|
|
39
|
+
* All future calls to {@linkcode DataStore.loadData()} in the session will not check for the old ID(s) anymore.
|
|
40
|
+
* To migrate IDs manually, use the method {@linkcode DataStore.migrateId()} instead.
|
|
41
|
+
*/
|
|
42
|
+
migrateIds?: string | string[];
|
|
32
43
|
/**
|
|
33
44
|
* Where the data should be saved (`"GM"` by default).
|
|
34
|
-
* The protected methods
|
|
35
|
-
*
|
|
45
|
+
* The protected methods {@linkcode DataStore.getValue()}, {@linkcode DataStore.setValue()} and {@linkcode DataStore.deleteValue()} are used to interact with the storage.
|
|
46
|
+
* `"GM"` storage, `"localStorage"` and `"sessionStorage"` are supported out of the box, but in an extended class you can overwrite those methods to implement any other storage method.
|
|
36
47
|
*/
|
|
37
48
|
storageMethod?: "GM" | "localStorage" | "sessionStorage";
|
|
38
49
|
} & ({
|
|
@@ -57,16 +68,18 @@ export type DataStoreOptions<TData> = {
|
|
|
57
68
|
decodeData?: never;
|
|
58
69
|
});
|
|
59
70
|
/**
|
|
60
|
-
* Manages a hybrid synchronous & asynchronous persistent JSON database that is cached in memory and persistently saved across sessions using [GM storage
|
|
71
|
+
* Manages a hybrid synchronous & asynchronous persistent JSON database that is cached in memory and persistently saved across sessions using [GM storage](https://wiki.greasespot.net/GM.setValue) (default), [localStorage](https://developer.mozilla.org/en-US/docs/Web/API/Window/localStorage) or [sessionStorage](https://developer.mozilla.org/en-US/docs/Web/API/Window/sessionStorage).
|
|
61
72
|
* Supports migrating data from older format versions to newer ones and populating the cache with default data if no persistent data is found.
|
|
73
|
+
* Can be overridden to implement any other storage method.
|
|
62
74
|
*
|
|
63
75
|
* All methods are at least `protected`, so you can easily extend this class and overwrite them to use a different storage method or to add additional functionality.
|
|
64
76
|
* Remember that you can call `super.methodName()` in the subclass to access the original method.
|
|
65
77
|
*
|
|
66
|
-
* ⚠️
|
|
78
|
+
* ⚠️ The stored data has to be **serializable using `JSON.stringify()`**, meaning no undefined, circular references, etc. are allowed.
|
|
79
|
+
* ⚠️ If the storageMethod is left as the default of `"GM"` the directives `@grant GM.getValue` and `@grant GM.setValue` are required. If you then also use the method {@linkcode DataStore.deleteData()}, the extra directive `@grant GM.deleteValue` is needed too.
|
|
67
80
|
* ⚠️ Make sure to call {@linkcode loadData()} at least once after creating an instance, or the returned data will be the same as `options.defaultData`
|
|
68
81
|
*
|
|
69
|
-
* @template TData The type of the data that is saved in persistent storage for the currently set format version (will be automatically inferred from `defaultData` if not provided)
|
|
82
|
+
* @template TData The type of the data that is saved in persistent storage for the currently set format version (will be automatically inferred from `defaultData` if not provided)
|
|
70
83
|
*/
|
|
71
84
|
export declare class DataStore<TData extends object = object> {
|
|
72
85
|
readonly id: string;
|
|
@@ -77,6 +90,7 @@ export declare class DataStore<TData extends object = object> {
|
|
|
77
90
|
readonly storageMethod: Required<DataStoreOptions<TData>>["storageMethod"];
|
|
78
91
|
private cachedData;
|
|
79
92
|
private migrations?;
|
|
93
|
+
private migrateIds;
|
|
80
94
|
/**
|
|
81
95
|
* Creates an instance of DataStore to manage a sync & async database that is cached in memory and persistently saved across sessions.
|
|
82
96
|
* Supports migrating data from older versions to newer ones and populating the cache with default data if no persistent data is found.
|
|
@@ -109,7 +123,7 @@ export declare class DataStore<TData extends object = object> {
|
|
|
109
123
|
* The in-memory cache will be left untouched, so you may still access the data with {@linkcode getData()}
|
|
110
124
|
* Calling {@linkcode loadData()} or {@linkcode setData()} after this method was called will recreate persistent storage with the cached or default data.
|
|
111
125
|
*
|
|
112
|
-
* ⚠️ This requires the additional directive `@grant GM.deleteValue`
|
|
126
|
+
* ⚠️ This requires the additional directive `@grant GM.deleteValue` if the storageMethod is left as the default of `"GM"`
|
|
113
127
|
*/
|
|
114
128
|
deleteData(): Promise<void>;
|
|
115
129
|
/** Returns whether encoding and decoding are enabled for this DataStore instance */
|
|
@@ -122,6 +136,11 @@ export declare class DataStore<TData extends object = object> {
|
|
|
122
136
|
* If one of the migrations fails, the data will be reset to the default value if `resetOnError` is set to `true` (default). Otherwise, an error will be thrown and no data will be saved.
|
|
123
137
|
*/
|
|
124
138
|
runMigrations(oldData: any, oldFmtVer: number, resetOnError?: boolean): Promise<TData>;
|
|
139
|
+
/**
|
|
140
|
+
* Tries to migrate the currently saved persistent data from one or more old IDs to the ID set in the constructor.
|
|
141
|
+
* If no data exist for the old ID(s), nothing will be done, but some time may still pass trying to fetch the non-existent data.
|
|
142
|
+
*/
|
|
143
|
+
migrateId(oldIds: string | string[]): Promise<void>;
|
|
125
144
|
/** Serializes the data using the optional this.encodeData() and returns it as a string */
|
|
126
145
|
protected serializeData(data: TData, useEncoding?: boolean): Promise<string>;
|
|
127
146
|
/** Deserializes the data using the optional this.decodeData() and returns it as a JSON object */
|
|
@@ -18,6 +18,13 @@ export type SerializedDataStore = {
|
|
|
18
18
|
/** The checksum of the data - key is not present for data without a checksum */
|
|
19
19
|
checksum?: string;
|
|
20
20
|
};
|
|
21
|
+
/** Result of {@linkcode DataStoreSerializer.loadStoresData()} */
|
|
22
|
+
export type LoadStoresDataResult = {
|
|
23
|
+
/** The ID of the DataStore instance */
|
|
24
|
+
id: string;
|
|
25
|
+
/** The in-memory data object */
|
|
26
|
+
data: object;
|
|
27
|
+
};
|
|
21
28
|
/**
|
|
22
29
|
* Allows for easy serialization and deserialization of multiple DataStore instances.
|
|
23
30
|
*
|
|
@@ -41,4 +48,17 @@ export declare class DataStoreSerializer {
|
|
|
41
48
|
* Also triggers the migration process if the data format has changed.
|
|
42
49
|
*/
|
|
43
50
|
deserialize(serializedData: string): Promise<void>;
|
|
51
|
+
/**
|
|
52
|
+
* Loads the persistent data of the DataStore instances into the in-memory cache.
|
|
53
|
+
* Also triggers the migration process if the data format has changed.
|
|
54
|
+
* @returns Returns a PromiseSettledResult array with the results of each DataStore instance in the format `{ id: string, data: object }`
|
|
55
|
+
*/
|
|
56
|
+
loadStoresData(): Promise<PromiseSettledResult<LoadStoresDataResult>[]>;
|
|
57
|
+
/** Resets the persistent data of the DataStore instances to their default values. */
|
|
58
|
+
resetStoresData(): Promise<PromiseSettledResult<void>[]>;
|
|
59
|
+
/**
|
|
60
|
+
* Deletes the persistent data of the DataStore instances.
|
|
61
|
+
* Leaves the in-memory data untouched.
|
|
62
|
+
*/
|
|
63
|
+
deleteStoresData(): Promise<PromiseSettledResult<void>[]>;
|
|
44
64
|
}
|
package/dist/lib/crypto.d.ts
CHANGED
|
@@ -19,6 +19,7 @@ export declare function computeHash(input: string | ArrayBuffer, algorithm?: str
|
|
|
19
19
|
* ⚠️ Not suitable for generating anything related to cryptography! Use [SubtleCrypto's `generateKey()`](https://developer.mozilla.org/en-US/docs/Web/API/SubtleCrypto/generateKey) for that instead.
|
|
20
20
|
* @param length The length of the ID to generate (defaults to 16)
|
|
21
21
|
* @param radix The [radix](https://en.wikipedia.org/wiki/Radix) of each digit (defaults to 16 which is hexadecimal. Use 2 for binary, 10 for decimal, 36 for alphanumeric, etc.)
|
|
22
|
-
* @param enhancedEntropy If set to true, uses [`crypto.getRandomValues()`](https://developer.mozilla.org/en-US/docs/Web/API/Crypto/getRandomValues) for better cryptographic randomness (this also makes it take
|
|
22
|
+
* @param enhancedEntropy If set to true, uses [`crypto.getRandomValues()`](https://developer.mozilla.org/en-US/docs/Web/API/Crypto/getRandomValues) for better cryptographic randomness (this also makes it take longer to generate)
|
|
23
|
+
* @param randomCase If set to false, the generated ID will be lowercase only - also makes use of the `enhancedEntropy` parameter unless the output doesn't contain letters
|
|
23
24
|
*/
|
|
24
|
-
export declare function randomId(length?: number, radix?: number, enhancedEntropy?: boolean): string;
|
|
25
|
+
export declare function randomId(length?: number, radix?: number, enhancedEntropy?: boolean, randomCase?: boolean): string;
|
package/dist/lib/math.d.ts
CHANGED
|
@@ -1,11 +1,22 @@
|
|
|
1
1
|
/** Ensures the passed {@linkcode value} always stays between {@linkcode min} and {@linkcode max} */
|
|
2
2
|
export declare function clamp(value: number, min: number, max: number): number;
|
|
3
3
|
/**
|
|
4
|
-
* Transforms the value parameter from the numerical range `range1min
|
|
4
|
+
* Transforms the value parameter from the numerical range `range1min` to `range1max` to the numerical range `range2min` to `range2max`
|
|
5
5
|
* For example, you can map the value 2 in the range of 0-5 to the range of 0-10 and you'd get a 4 as a result.
|
|
6
6
|
*/
|
|
7
7
|
export declare function mapRange(value: number, range1min: number, range1max: number, range2min: number, range2max: number): number;
|
|
8
|
-
/**
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
8
|
+
/**
|
|
9
|
+
* Transforms the value parameter from the numerical range `0` to `range1max` to the numerical range `0` to `range2max`
|
|
10
|
+
* For example, you can map the value 2 in the range of 0-5 to the range of 0-10 and you'd get a 4 as a result.
|
|
11
|
+
*/
|
|
12
|
+
export declare function mapRange(value: number, range1max: number, range2max: number): number;
|
|
13
|
+
/**
|
|
14
|
+
* Returns a random number between {@linkcode min} and {@linkcode max} (inclusive)
|
|
15
|
+
* Set {@linkcode enhancedEntropy} to true to use `crypto.getRandomValues()` for better cryptographic randomness (this also makes it take longer to generate)
|
|
16
|
+
*/
|
|
17
|
+
export declare function randRange(min: number, max: number, enhancedEntropy?: boolean): number;
|
|
18
|
+
/**
|
|
19
|
+
* Returns a random number between 0 and {@linkcode max} (inclusive)
|
|
20
|
+
* Set {@linkcode enhancedEntropy} to true to use `crypto.getRandomValues()` for better cryptographic randomness (this also makes it take longer to generate)
|
|
21
|
+
*/
|
|
22
|
+
export declare function randRange(max: number, enhancedEntropy?: boolean): number;
|
package/dist/lib/types.d.ts
CHANGED
|
@@ -15,3 +15,10 @@ export type LooseUnion<TUnion extends string | number | object> = (TUnion) | (TU
|
|
|
15
15
|
* }
|
|
16
16
|
*/
|
|
17
17
|
export type NonEmptyString<TString extends string> = TString extends "" ? never : TString;
|
|
18
|
+
/**
|
|
19
|
+
* Makes the structure of a type more readable by expanding it.
|
|
20
|
+
* This can be useful for debugging or for improving the readability of complex types.
|
|
21
|
+
*/
|
|
22
|
+
export type Prettify<T> = {
|
|
23
|
+
[K in keyof T]: T[K];
|
|
24
|
+
} & {};
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sv443-network/userutils",
|
|
3
3
|
"libName": "UserUtils",
|
|
4
|
-
"version": "8.0
|
|
4
|
+
"version": "8.2.0",
|
|
5
5
|
"description": "Library with various utilities for userscripts - register listeners for when CSS selectors exist, intercept events, create persistent & synchronous data stores, modify the DOM more easily and more",
|
|
6
6
|
"main": "dist/index.js",
|
|
7
7
|
"module": "dist/index.js",
|