@sv443-network/userutils 4.2.0 → 5.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +16 -0
- package/README.md +12 -1
- package/dist/index.global.js +47 -12
- package/dist/index.js +46 -11
- package/dist/index.mjs +46 -11
- package/dist/lib/ConfigManager.d.ts +28 -2
- package/dist/lib/SelectorObserver.d.ts +3 -2
- package/dist/lib/misc.d.ts +2 -2
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,21 @@
|
|
|
1
1
|
# @sv443-network/userutils
|
|
2
2
|
|
|
3
|
+
## 5.0.0
|
|
4
|
+
|
|
5
|
+
### Major Changes
|
|
6
|
+
|
|
7
|
+
- c980ff3: `compress()` now uses the same value "string" (unlike previously "base64") for the outputType parameter like `decompress()`
|
|
8
|
+
|
|
9
|
+
### Minor Changes
|
|
10
|
+
|
|
11
|
+
- ca1b596: Added `encodeData()` and `decodeData()` to the ConfigManager options to allow for easy data compression
|
|
12
|
+
|
|
13
|
+
## 4.2.1
|
|
14
|
+
|
|
15
|
+
### Patch Changes
|
|
16
|
+
|
|
17
|
+
- 0462e35: Fixed TS types for overload of SelectorObserver constructor
|
|
18
|
+
|
|
3
19
|
## 4.2.0
|
|
4
20
|
|
|
5
21
|
### Minor Changes
|
package/README.md
CHANGED
|
@@ -873,6 +873,8 @@ The options object has the following properties:
|
|
|
873
873
|
| `defaultConfig` | The default config 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. |
|
|
874
874
|
| `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. |
|
|
875
875
|
| `migrations?` | (Optional) A dictionary of functions that can be used to migrate data from older versions of the configuration 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. |
|
|
876
|
+
| `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 |
|
|
877
|
+
| `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) |
|
|
876
878
|
|
|
877
879
|
<br>
|
|
878
880
|
|
|
@@ -903,7 +905,7 @@ If `loadData()` or `setData()` are called after this, the persistent storage wil
|
|
|
903
905
|
<details><summary><b>Example - click to view</b></summary>
|
|
904
906
|
|
|
905
907
|
```ts
|
|
906
|
-
import { ConfigManager } from "@sv443-network/userutils";
|
|
908
|
+
import { ConfigManager, compress, decompress } from "@sv443-network/userutils";
|
|
907
909
|
|
|
908
910
|
interface MyConfig {
|
|
909
911
|
foo: string;
|
|
@@ -953,6 +955,15 @@ const manager = new ConfigManager({
|
|
|
953
955
|
formatVersion,
|
|
954
956
|
/** Data format migration functions */
|
|
955
957
|
migrations,
|
|
958
|
+
|
|
959
|
+
// Compression example:
|
|
960
|
+
// Adding this will save space at the cost of a little bit of performance while initially loading and saving the data
|
|
961
|
+
// Only both of these properties or none of them should be set
|
|
962
|
+
// Everything else will be handled by the ConfigManager instance
|
|
963
|
+
/** Encode data using the "deflate-raw" algorithm and digests it as a base64 string */
|
|
964
|
+
encodeData: (data) => compress(data, "deflate-raw", "base64"),
|
|
965
|
+
/** Decode the "deflate-raw" encoded data as a base64 string */
|
|
966
|
+
decodeData: (data) => decompress(data, "deflate-raw", "base64"),
|
|
956
967
|
});
|
|
957
968
|
|
|
958
969
|
/** Entrypoint of the userscript */
|
package/dist/index.global.js
CHANGED
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
// ==UserLibrary==
|
|
10
10
|
// @name UserUtils
|
|
11
11
|
// @description Library with various utilities for userscripts - register listeners for when CSS selectors exist, intercept events, manage persistent user configurations, modify the DOM more easily and more
|
|
12
|
-
// @version
|
|
12
|
+
// @version 5.0.0
|
|
13
13
|
// @license MIT
|
|
14
14
|
// @copyright Sv443 (https://github.com/Sv443)
|
|
15
15
|
|
|
@@ -155,11 +155,15 @@ var UserUtils = (function (exports) {
|
|
|
155
155
|
__publicField(this, "defaultConfig");
|
|
156
156
|
__publicField(this, "cachedConfig");
|
|
157
157
|
__publicField(this, "migrations");
|
|
158
|
+
__publicField(this, "encodeData");
|
|
159
|
+
__publicField(this, "decodeData");
|
|
158
160
|
this.id = options.id;
|
|
159
161
|
this.formatVersion = options.formatVersion;
|
|
160
162
|
this.defaultConfig = options.defaultConfig;
|
|
161
163
|
this.cachedConfig = options.defaultConfig;
|
|
162
164
|
this.migrations = options.migrations;
|
|
165
|
+
this.encodeData = options.encodeData;
|
|
166
|
+
this.decodeData = options.decodeData;
|
|
163
167
|
}
|
|
164
168
|
/**
|
|
165
169
|
* Loads the data saved in persistent storage into the in-memory cache and also returns it.
|
|
@@ -175,13 +179,15 @@ var UserUtils = (function (exports) {
|
|
|
175
179
|
yield this.saveDefaultData();
|
|
176
180
|
return this.defaultConfig;
|
|
177
181
|
}
|
|
182
|
+
const isEncoded = yield GM.getValue(`_uucfgenc-${this.id}`, false);
|
|
178
183
|
if (isNaN(gmFmtVer))
|
|
179
184
|
yield GM.setValue(`_uucfgver-${this.id}`, gmFmtVer = this.formatVersion);
|
|
180
|
-
let parsed =
|
|
185
|
+
let parsed = yield this.deserializeData(gmData, isEncoded);
|
|
181
186
|
if (gmFmtVer < this.formatVersion && this.migrations)
|
|
182
187
|
parsed = yield this.runMigrations(parsed, gmFmtVer);
|
|
183
|
-
return this.cachedConfig =
|
|
188
|
+
return this.cachedConfig = parsed;
|
|
184
189
|
} catch (err) {
|
|
190
|
+
console.warn("Error while loading config data, resetting it to the default value.", err);
|
|
185
191
|
yield this.saveDefaultData();
|
|
186
192
|
return this.defaultConfig;
|
|
187
193
|
}
|
|
@@ -197,10 +203,12 @@ var UserUtils = (function (exports) {
|
|
|
197
203
|
/** Saves the data synchronously to the in-memory cache and asynchronously to the persistent storage */
|
|
198
204
|
setData(data) {
|
|
199
205
|
this.cachedConfig = data;
|
|
206
|
+
const useEncoding = Boolean(this.encodeData && this.decodeData);
|
|
200
207
|
return new Promise((resolve) => __async(this, null, function* () {
|
|
201
208
|
yield Promise.all([
|
|
202
|
-
GM.setValue(`_uucfg-${this.id}`,
|
|
203
|
-
GM.setValue(`_uucfgver-${this.id}`, this.formatVersion)
|
|
209
|
+
GM.setValue(`_uucfg-${this.id}`, yield this.serializeData(data, useEncoding)),
|
|
210
|
+
GM.setValue(`_uucfgver-${this.id}`, this.formatVersion),
|
|
211
|
+
GM.setValue(`_uucfgenc-${this.id}`, useEncoding)
|
|
204
212
|
]);
|
|
205
213
|
resolve();
|
|
206
214
|
}));
|
|
@@ -209,10 +217,12 @@ var UserUtils = (function (exports) {
|
|
|
209
217
|
saveDefaultData() {
|
|
210
218
|
return __async(this, null, function* () {
|
|
211
219
|
this.cachedConfig = this.defaultConfig;
|
|
220
|
+
const useEncoding = Boolean(this.encodeData && this.decodeData);
|
|
212
221
|
return new Promise((resolve) => __async(this, null, function* () {
|
|
213
222
|
yield Promise.all([
|
|
214
|
-
GM.setValue(`_uucfg-${this.id}`,
|
|
215
|
-
GM.setValue(`_uucfgver-${this.id}`, this.formatVersion)
|
|
223
|
+
GM.setValue(`_uucfg-${this.id}`, yield this.serializeData(this.defaultConfig, useEncoding)),
|
|
224
|
+
GM.setValue(`_uucfgver-${this.id}`, this.formatVersion),
|
|
225
|
+
GM.setValue(`_uucfgenc-${this.id}`, useEncoding)
|
|
216
226
|
]);
|
|
217
227
|
resolve();
|
|
218
228
|
}));
|
|
@@ -229,7 +239,8 @@ var UserUtils = (function (exports) {
|
|
|
229
239
|
return __async(this, null, function* () {
|
|
230
240
|
yield Promise.all([
|
|
231
241
|
GM.deleteValue(`_uucfg-${this.id}`),
|
|
232
|
-
GM.deleteValue(`_uucfgver-${this.id}`)
|
|
242
|
+
GM.deleteValue(`_uucfgver-${this.id}`),
|
|
243
|
+
GM.deleteValue(`_uucfgenc-${this.id}`)
|
|
233
244
|
]);
|
|
234
245
|
});
|
|
235
246
|
}
|
|
@@ -249,17 +260,41 @@ var UserUtils = (function (exports) {
|
|
|
249
260
|
newData = migRes instanceof Promise ? yield migRes : migRes;
|
|
250
261
|
lastFmtVer = oldFmtVer = ver;
|
|
251
262
|
} catch (err) {
|
|
252
|
-
console.error(`Error while running migration function for format version ${fmtVer}
|
|
263
|
+
console.error(`Error while running migration function for format version '${fmtVer}' - resetting to the default value.`, err);
|
|
264
|
+
yield this.saveDefaultData();
|
|
265
|
+
return this.getData();
|
|
253
266
|
}
|
|
254
267
|
}
|
|
255
268
|
}
|
|
256
269
|
yield Promise.all([
|
|
257
|
-
GM.setValue(`_uucfg-${this.id}`,
|
|
258
|
-
GM.setValue(`_uucfgver-${this.id}`, lastFmtVer)
|
|
270
|
+
GM.setValue(`_uucfg-${this.id}`, yield this.serializeData(newData)),
|
|
271
|
+
GM.setValue(`_uucfgver-${this.id}`, lastFmtVer),
|
|
272
|
+
GM.setValue(`_uucfgenc-${this.id}`, Boolean(this.encodeData && this.decodeData))
|
|
259
273
|
]);
|
|
260
274
|
return newData;
|
|
261
275
|
});
|
|
262
276
|
}
|
|
277
|
+
/** Serializes the data using the optional this.encodeData() and returns it as a string */
|
|
278
|
+
serializeData(data, useEncoding = true) {
|
|
279
|
+
return __async(this, null, function* () {
|
|
280
|
+
const stringData = JSON.stringify(data);
|
|
281
|
+
if (!this.encodeData || !this.decodeData || !useEncoding)
|
|
282
|
+
return stringData;
|
|
283
|
+
const encRes = this.encodeData(stringData);
|
|
284
|
+
if (encRes instanceof Promise)
|
|
285
|
+
return yield encRes;
|
|
286
|
+
return encRes;
|
|
287
|
+
});
|
|
288
|
+
}
|
|
289
|
+
/** Deserializes the data using the optional this.decodeData() and returns it as a JSON object */
|
|
290
|
+
deserializeData(data, useEncoding = true) {
|
|
291
|
+
return __async(this, null, function* () {
|
|
292
|
+
let decRes = this.decodeData && this.encodeData && useEncoding ? this.decodeData(data) : void 0;
|
|
293
|
+
if (decRes instanceof Promise)
|
|
294
|
+
decRes = yield decRes;
|
|
295
|
+
return JSON.parse(decRes != null ? decRes : data);
|
|
296
|
+
});
|
|
297
|
+
}
|
|
263
298
|
/** Copies a JSON-compatible object and loses its internal references */
|
|
264
299
|
deepCopy(obj) {
|
|
265
300
|
return JSON.parse(JSON.stringify(obj));
|
|
@@ -405,7 +440,7 @@ var UserUtils = (function (exports) {
|
|
|
405
440
|
return (_b = (_a = values[argIndex]) != null ? _a : match) == null ? void 0 : _b.toString();
|
|
406
441
|
});
|
|
407
442
|
}
|
|
408
|
-
function compress(input, compressionFormat, outputType = "
|
|
443
|
+
function compress(input, compressionFormat, outputType = "string") {
|
|
409
444
|
return __async(this, null, function* () {
|
|
410
445
|
const byteArray = typeof input === "string" ? new TextEncoder().encode(input) : input;
|
|
411
446
|
const comp = new CompressionStream(compressionFormat);
|
package/dist/index.js
CHANGED
|
@@ -134,11 +134,15 @@ var ConfigManager = class {
|
|
|
134
134
|
__publicField(this, "defaultConfig");
|
|
135
135
|
__publicField(this, "cachedConfig");
|
|
136
136
|
__publicField(this, "migrations");
|
|
137
|
+
__publicField(this, "encodeData");
|
|
138
|
+
__publicField(this, "decodeData");
|
|
137
139
|
this.id = options.id;
|
|
138
140
|
this.formatVersion = options.formatVersion;
|
|
139
141
|
this.defaultConfig = options.defaultConfig;
|
|
140
142
|
this.cachedConfig = options.defaultConfig;
|
|
141
143
|
this.migrations = options.migrations;
|
|
144
|
+
this.encodeData = options.encodeData;
|
|
145
|
+
this.decodeData = options.decodeData;
|
|
142
146
|
}
|
|
143
147
|
/**
|
|
144
148
|
* Loads the data saved in persistent storage into the in-memory cache and also returns it.
|
|
@@ -154,13 +158,15 @@ var ConfigManager = class {
|
|
|
154
158
|
yield this.saveDefaultData();
|
|
155
159
|
return this.defaultConfig;
|
|
156
160
|
}
|
|
161
|
+
const isEncoded = yield GM.getValue(`_uucfgenc-${this.id}`, false);
|
|
157
162
|
if (isNaN(gmFmtVer))
|
|
158
163
|
yield GM.setValue(`_uucfgver-${this.id}`, gmFmtVer = this.formatVersion);
|
|
159
|
-
let parsed =
|
|
164
|
+
let parsed = yield this.deserializeData(gmData, isEncoded);
|
|
160
165
|
if (gmFmtVer < this.formatVersion && this.migrations)
|
|
161
166
|
parsed = yield this.runMigrations(parsed, gmFmtVer);
|
|
162
|
-
return this.cachedConfig =
|
|
167
|
+
return this.cachedConfig = parsed;
|
|
163
168
|
} catch (err) {
|
|
169
|
+
console.warn("Error while loading config data, resetting it to the default value.", err);
|
|
164
170
|
yield this.saveDefaultData();
|
|
165
171
|
return this.defaultConfig;
|
|
166
172
|
}
|
|
@@ -176,10 +182,12 @@ var ConfigManager = class {
|
|
|
176
182
|
/** Saves the data synchronously to the in-memory cache and asynchronously to the persistent storage */
|
|
177
183
|
setData(data) {
|
|
178
184
|
this.cachedConfig = data;
|
|
185
|
+
const useEncoding = Boolean(this.encodeData && this.decodeData);
|
|
179
186
|
return new Promise((resolve) => __async(this, null, function* () {
|
|
180
187
|
yield Promise.all([
|
|
181
|
-
GM.setValue(`_uucfg-${this.id}`,
|
|
182
|
-
GM.setValue(`_uucfgver-${this.id}`, this.formatVersion)
|
|
188
|
+
GM.setValue(`_uucfg-${this.id}`, yield this.serializeData(data, useEncoding)),
|
|
189
|
+
GM.setValue(`_uucfgver-${this.id}`, this.formatVersion),
|
|
190
|
+
GM.setValue(`_uucfgenc-${this.id}`, useEncoding)
|
|
183
191
|
]);
|
|
184
192
|
resolve();
|
|
185
193
|
}));
|
|
@@ -188,10 +196,12 @@ var ConfigManager = class {
|
|
|
188
196
|
saveDefaultData() {
|
|
189
197
|
return __async(this, null, function* () {
|
|
190
198
|
this.cachedConfig = this.defaultConfig;
|
|
199
|
+
const useEncoding = Boolean(this.encodeData && this.decodeData);
|
|
191
200
|
return new Promise((resolve) => __async(this, null, function* () {
|
|
192
201
|
yield Promise.all([
|
|
193
|
-
GM.setValue(`_uucfg-${this.id}`,
|
|
194
|
-
GM.setValue(`_uucfgver-${this.id}`, this.formatVersion)
|
|
202
|
+
GM.setValue(`_uucfg-${this.id}`, yield this.serializeData(this.defaultConfig, useEncoding)),
|
|
203
|
+
GM.setValue(`_uucfgver-${this.id}`, this.formatVersion),
|
|
204
|
+
GM.setValue(`_uucfgenc-${this.id}`, useEncoding)
|
|
195
205
|
]);
|
|
196
206
|
resolve();
|
|
197
207
|
}));
|
|
@@ -208,7 +218,8 @@ var ConfigManager = class {
|
|
|
208
218
|
return __async(this, null, function* () {
|
|
209
219
|
yield Promise.all([
|
|
210
220
|
GM.deleteValue(`_uucfg-${this.id}`),
|
|
211
|
-
GM.deleteValue(`_uucfgver-${this.id}`)
|
|
221
|
+
GM.deleteValue(`_uucfgver-${this.id}`),
|
|
222
|
+
GM.deleteValue(`_uucfgenc-${this.id}`)
|
|
212
223
|
]);
|
|
213
224
|
});
|
|
214
225
|
}
|
|
@@ -228,17 +239,41 @@ var ConfigManager = class {
|
|
|
228
239
|
newData = migRes instanceof Promise ? yield migRes : migRes;
|
|
229
240
|
lastFmtVer = oldFmtVer = ver;
|
|
230
241
|
} catch (err) {
|
|
231
|
-
console.error(`Error while running migration function for format version ${fmtVer}
|
|
242
|
+
console.error(`Error while running migration function for format version '${fmtVer}' - resetting to the default value.`, err);
|
|
243
|
+
yield this.saveDefaultData();
|
|
244
|
+
return this.getData();
|
|
232
245
|
}
|
|
233
246
|
}
|
|
234
247
|
}
|
|
235
248
|
yield Promise.all([
|
|
236
|
-
GM.setValue(`_uucfg-${this.id}`,
|
|
237
|
-
GM.setValue(`_uucfgver-${this.id}`, lastFmtVer)
|
|
249
|
+
GM.setValue(`_uucfg-${this.id}`, yield this.serializeData(newData)),
|
|
250
|
+
GM.setValue(`_uucfgver-${this.id}`, lastFmtVer),
|
|
251
|
+
GM.setValue(`_uucfgenc-${this.id}`, Boolean(this.encodeData && this.decodeData))
|
|
238
252
|
]);
|
|
239
253
|
return newData;
|
|
240
254
|
});
|
|
241
255
|
}
|
|
256
|
+
/** Serializes the data using the optional this.encodeData() and returns it as a string */
|
|
257
|
+
serializeData(data, useEncoding = true) {
|
|
258
|
+
return __async(this, null, function* () {
|
|
259
|
+
const stringData = JSON.stringify(data);
|
|
260
|
+
if (!this.encodeData || !this.decodeData || !useEncoding)
|
|
261
|
+
return stringData;
|
|
262
|
+
const encRes = this.encodeData(stringData);
|
|
263
|
+
if (encRes instanceof Promise)
|
|
264
|
+
return yield encRes;
|
|
265
|
+
return encRes;
|
|
266
|
+
});
|
|
267
|
+
}
|
|
268
|
+
/** Deserializes the data using the optional this.decodeData() and returns it as a JSON object */
|
|
269
|
+
deserializeData(data, useEncoding = true) {
|
|
270
|
+
return __async(this, null, function* () {
|
|
271
|
+
let decRes = this.decodeData && this.encodeData && useEncoding ? this.decodeData(data) : void 0;
|
|
272
|
+
if (decRes instanceof Promise)
|
|
273
|
+
decRes = yield decRes;
|
|
274
|
+
return JSON.parse(decRes != null ? decRes : data);
|
|
275
|
+
});
|
|
276
|
+
}
|
|
242
277
|
/** Copies a JSON-compatible object and loses its internal references */
|
|
243
278
|
deepCopy(obj) {
|
|
244
279
|
return JSON.parse(JSON.stringify(obj));
|
|
@@ -384,7 +419,7 @@ function insertValues(input, ...values) {
|
|
|
384
419
|
return (_b = (_a = values[argIndex]) != null ? _a : match) == null ? void 0 : _b.toString();
|
|
385
420
|
});
|
|
386
421
|
}
|
|
387
|
-
function compress(input, compressionFormat, outputType = "
|
|
422
|
+
function compress(input, compressionFormat, outputType = "string") {
|
|
388
423
|
return __async(this, null, function* () {
|
|
389
424
|
const byteArray = typeof input === "string" ? new TextEncoder().encode(input) : input;
|
|
390
425
|
const comp = new CompressionStream(compressionFormat);
|
package/dist/index.mjs
CHANGED
|
@@ -132,11 +132,15 @@ var ConfigManager = class {
|
|
|
132
132
|
__publicField(this, "defaultConfig");
|
|
133
133
|
__publicField(this, "cachedConfig");
|
|
134
134
|
__publicField(this, "migrations");
|
|
135
|
+
__publicField(this, "encodeData");
|
|
136
|
+
__publicField(this, "decodeData");
|
|
135
137
|
this.id = options.id;
|
|
136
138
|
this.formatVersion = options.formatVersion;
|
|
137
139
|
this.defaultConfig = options.defaultConfig;
|
|
138
140
|
this.cachedConfig = options.defaultConfig;
|
|
139
141
|
this.migrations = options.migrations;
|
|
142
|
+
this.encodeData = options.encodeData;
|
|
143
|
+
this.decodeData = options.decodeData;
|
|
140
144
|
}
|
|
141
145
|
/**
|
|
142
146
|
* Loads the data saved in persistent storage into the in-memory cache and also returns it.
|
|
@@ -152,13 +156,15 @@ var ConfigManager = class {
|
|
|
152
156
|
yield this.saveDefaultData();
|
|
153
157
|
return this.defaultConfig;
|
|
154
158
|
}
|
|
159
|
+
const isEncoded = yield GM.getValue(`_uucfgenc-${this.id}`, false);
|
|
155
160
|
if (isNaN(gmFmtVer))
|
|
156
161
|
yield GM.setValue(`_uucfgver-${this.id}`, gmFmtVer = this.formatVersion);
|
|
157
|
-
let parsed =
|
|
162
|
+
let parsed = yield this.deserializeData(gmData, isEncoded);
|
|
158
163
|
if (gmFmtVer < this.formatVersion && this.migrations)
|
|
159
164
|
parsed = yield this.runMigrations(parsed, gmFmtVer);
|
|
160
|
-
return this.cachedConfig =
|
|
165
|
+
return this.cachedConfig = parsed;
|
|
161
166
|
} catch (err) {
|
|
167
|
+
console.warn("Error while loading config data, resetting it to the default value.", err);
|
|
162
168
|
yield this.saveDefaultData();
|
|
163
169
|
return this.defaultConfig;
|
|
164
170
|
}
|
|
@@ -174,10 +180,12 @@ var ConfigManager = class {
|
|
|
174
180
|
/** Saves the data synchronously to the in-memory cache and asynchronously to the persistent storage */
|
|
175
181
|
setData(data) {
|
|
176
182
|
this.cachedConfig = data;
|
|
183
|
+
const useEncoding = Boolean(this.encodeData && this.decodeData);
|
|
177
184
|
return new Promise((resolve) => __async(this, null, function* () {
|
|
178
185
|
yield Promise.all([
|
|
179
|
-
GM.setValue(`_uucfg-${this.id}`,
|
|
180
|
-
GM.setValue(`_uucfgver-${this.id}`, this.formatVersion)
|
|
186
|
+
GM.setValue(`_uucfg-${this.id}`, yield this.serializeData(data, useEncoding)),
|
|
187
|
+
GM.setValue(`_uucfgver-${this.id}`, this.formatVersion),
|
|
188
|
+
GM.setValue(`_uucfgenc-${this.id}`, useEncoding)
|
|
181
189
|
]);
|
|
182
190
|
resolve();
|
|
183
191
|
}));
|
|
@@ -186,10 +194,12 @@ var ConfigManager = class {
|
|
|
186
194
|
saveDefaultData() {
|
|
187
195
|
return __async(this, null, function* () {
|
|
188
196
|
this.cachedConfig = this.defaultConfig;
|
|
197
|
+
const useEncoding = Boolean(this.encodeData && this.decodeData);
|
|
189
198
|
return new Promise((resolve) => __async(this, null, function* () {
|
|
190
199
|
yield Promise.all([
|
|
191
|
-
GM.setValue(`_uucfg-${this.id}`,
|
|
192
|
-
GM.setValue(`_uucfgver-${this.id}`, this.formatVersion)
|
|
200
|
+
GM.setValue(`_uucfg-${this.id}`, yield this.serializeData(this.defaultConfig, useEncoding)),
|
|
201
|
+
GM.setValue(`_uucfgver-${this.id}`, this.formatVersion),
|
|
202
|
+
GM.setValue(`_uucfgenc-${this.id}`, useEncoding)
|
|
193
203
|
]);
|
|
194
204
|
resolve();
|
|
195
205
|
}));
|
|
@@ -206,7 +216,8 @@ var ConfigManager = class {
|
|
|
206
216
|
return __async(this, null, function* () {
|
|
207
217
|
yield Promise.all([
|
|
208
218
|
GM.deleteValue(`_uucfg-${this.id}`),
|
|
209
|
-
GM.deleteValue(`_uucfgver-${this.id}`)
|
|
219
|
+
GM.deleteValue(`_uucfgver-${this.id}`),
|
|
220
|
+
GM.deleteValue(`_uucfgenc-${this.id}`)
|
|
210
221
|
]);
|
|
211
222
|
});
|
|
212
223
|
}
|
|
@@ -226,17 +237,41 @@ var ConfigManager = class {
|
|
|
226
237
|
newData = migRes instanceof Promise ? yield migRes : migRes;
|
|
227
238
|
lastFmtVer = oldFmtVer = ver;
|
|
228
239
|
} catch (err) {
|
|
229
|
-
console.error(`Error while running migration function for format version ${fmtVer}
|
|
240
|
+
console.error(`Error while running migration function for format version '${fmtVer}' - resetting to the default value.`, err);
|
|
241
|
+
yield this.saveDefaultData();
|
|
242
|
+
return this.getData();
|
|
230
243
|
}
|
|
231
244
|
}
|
|
232
245
|
}
|
|
233
246
|
yield Promise.all([
|
|
234
|
-
GM.setValue(`_uucfg-${this.id}`,
|
|
235
|
-
GM.setValue(`_uucfgver-${this.id}`, lastFmtVer)
|
|
247
|
+
GM.setValue(`_uucfg-${this.id}`, yield this.serializeData(newData)),
|
|
248
|
+
GM.setValue(`_uucfgver-${this.id}`, lastFmtVer),
|
|
249
|
+
GM.setValue(`_uucfgenc-${this.id}`, Boolean(this.encodeData && this.decodeData))
|
|
236
250
|
]);
|
|
237
251
|
return newData;
|
|
238
252
|
});
|
|
239
253
|
}
|
|
254
|
+
/** Serializes the data using the optional this.encodeData() and returns it as a string */
|
|
255
|
+
serializeData(data, useEncoding = true) {
|
|
256
|
+
return __async(this, null, function* () {
|
|
257
|
+
const stringData = JSON.stringify(data);
|
|
258
|
+
if (!this.encodeData || !this.decodeData || !useEncoding)
|
|
259
|
+
return stringData;
|
|
260
|
+
const encRes = this.encodeData(stringData);
|
|
261
|
+
if (encRes instanceof Promise)
|
|
262
|
+
return yield encRes;
|
|
263
|
+
return encRes;
|
|
264
|
+
});
|
|
265
|
+
}
|
|
266
|
+
/** Deserializes the data using the optional this.decodeData() and returns it as a JSON object */
|
|
267
|
+
deserializeData(data, useEncoding = true) {
|
|
268
|
+
return __async(this, null, function* () {
|
|
269
|
+
let decRes = this.decodeData && this.encodeData && useEncoding ? this.decodeData(data) : void 0;
|
|
270
|
+
if (decRes instanceof Promise)
|
|
271
|
+
decRes = yield decRes;
|
|
272
|
+
return JSON.parse(decRes != null ? decRes : data);
|
|
273
|
+
});
|
|
274
|
+
}
|
|
240
275
|
/** Copies a JSON-compatible object and loses its internal references */
|
|
241
276
|
deepCopy(obj) {
|
|
242
277
|
return JSON.parse(JSON.stringify(obj));
|
|
@@ -382,7 +417,7 @@ function insertValues(input, ...values) {
|
|
|
382
417
|
return (_b = (_a = values[argIndex]) != null ? _a : match) == null ? void 0 : _b.toString();
|
|
383
418
|
});
|
|
384
419
|
}
|
|
385
|
-
function compress(input, compressionFormat, outputType = "
|
|
420
|
+
function compress(input, compressionFormat, outputType = "string") {
|
|
386
421
|
return __async(this, null, function* () {
|
|
387
422
|
const byteArray = typeof input === "string" ? new TextEncoder().encode(input) : input;
|
|
388
423
|
const comp = new CompressionStream(compressionFormat);
|
|
@@ -3,7 +3,7 @@ type MigrationFunc = (oldData: any) => any | Promise<any>;
|
|
|
3
3
|
/** Dictionary of format version numbers and the function that migrates to them from the previous whole integer */
|
|
4
4
|
export type ConfigMigrationsDict = Record<number, MigrationFunc>;
|
|
5
5
|
/** Options for the ConfigManager instance */
|
|
6
|
-
export
|
|
6
|
+
export type ConfigManagerOptions<TData> = {
|
|
7
7
|
/** A unique internal ID for this configuration - choose wisely as changing it is not supported yet. */
|
|
8
8
|
id: string;
|
|
9
9
|
/**
|
|
@@ -28,7 +28,27 @@ export interface ConfigManagerOptions<TData> {
|
|
|
28
28
|
* If the current format version is not in the dictionary, no migrations will be run.
|
|
29
29
|
*/
|
|
30
30
|
migrations?: ConfigMigrationsDict;
|
|
31
|
-
}
|
|
31
|
+
} & ({
|
|
32
|
+
/**
|
|
33
|
+
* Function to use to encode the data prior to saving it in persistent storage.
|
|
34
|
+
* If this is specified, make sure to declare {@linkcode decodeData()} as well.
|
|
35
|
+
*
|
|
36
|
+
* You can make use of UserUtils' [`compress()`](https://github.com/Sv443-Network/UserUtils?tab=readme-ov-file#compress) function here to make the data use up less space at the cost of a little bit of performance.
|
|
37
|
+
* @param data The input data as a serialized object (JSON string)
|
|
38
|
+
*/
|
|
39
|
+
encodeData: (data: string) => string | Promise<string>;
|
|
40
|
+
/**
|
|
41
|
+
* Function to use to decode the data after reading it from persistent storage.
|
|
42
|
+
* If this is specified, make sure to declare {@linkcode encodeData()} as well.
|
|
43
|
+
*
|
|
44
|
+
* You can make use of UserUtils' [`decompress()`](https://github.com/Sv443-Network/UserUtils?tab=readme-ov-file#decompress) function here to make the data use up less space at the cost of a little bit of performance.
|
|
45
|
+
* @returns The resulting data as a valid serialized object (JSON string)
|
|
46
|
+
*/
|
|
47
|
+
decodeData: (data: string) => string | Promise<string>;
|
|
48
|
+
} | {
|
|
49
|
+
encodeData?: never;
|
|
50
|
+
decodeData?: never;
|
|
51
|
+
});
|
|
32
52
|
/**
|
|
33
53
|
* Manages a user configuration that is cached in memory and persistently saved across sessions.
|
|
34
54
|
* Supports migrating data from older versions of the configuration to newer ones and populating the cache with default data if no persistent data is found.
|
|
@@ -44,6 +64,8 @@ export declare class ConfigManager<TData = any> {
|
|
|
44
64
|
readonly defaultConfig: TData;
|
|
45
65
|
private cachedConfig;
|
|
46
66
|
private migrations?;
|
|
67
|
+
private encodeData;
|
|
68
|
+
private decodeData;
|
|
47
69
|
/**
|
|
48
70
|
* Creates an instance of ConfigManager to manage a user configuration that is cached in memory and persistently saved across sessions.
|
|
49
71
|
* Supports migrating data from older versions of the configuration to newer ones and populating the cache with default data if no persistent data is found.
|
|
@@ -80,6 +102,10 @@ export declare class ConfigManager<TData = any> {
|
|
|
80
102
|
deleteConfig(): Promise<void>;
|
|
81
103
|
/** Runs all necessary migration functions consecutively - may be overwritten in a subclass */
|
|
82
104
|
protected runMigrations(oldData: any, oldFmtVer: number): Promise<TData>;
|
|
105
|
+
/** Serializes the data using the optional this.encodeData() and returns it as a string */
|
|
106
|
+
private serializeData;
|
|
107
|
+
/** Deserializes the data using the optional this.decodeData() and returns it as a JSON object */
|
|
108
|
+
private deserializeData;
|
|
83
109
|
/** Copies a JSON-compatible object and loses its internal references */
|
|
84
110
|
private deepCopy;
|
|
85
111
|
}
|
|
@@ -26,6 +26,7 @@ export type SelectorObserverOptions = {
|
|
|
26
26
|
/** Whether to ensure the observer is enabled when a new listener is added - default is true */
|
|
27
27
|
enableOnAddListener?: boolean;
|
|
28
28
|
};
|
|
29
|
+
export type SelectorObserverConstructorOptions = MutationObserverInit & SelectorObserverOptions;
|
|
29
30
|
/** Observes the children of the given element for changes */
|
|
30
31
|
export declare class SelectorObserver {
|
|
31
32
|
private enabled;
|
|
@@ -39,13 +40,13 @@ export declare class SelectorObserver {
|
|
|
39
40
|
* @param baseElementSelector The selector of the element to observe
|
|
40
41
|
* @param options Fine-tune what triggers the MutationObserver's checking function - `subtree` and `childList` are set to true by default
|
|
41
42
|
*/
|
|
42
|
-
constructor(baseElementSelector: string, options?:
|
|
43
|
+
constructor(baseElementSelector: string, options?: SelectorObserverConstructorOptions);
|
|
43
44
|
/**
|
|
44
45
|
* Creates a new SelectorObserver that will observe the children of the given base element for changes (only creation and deletion of elements by default)
|
|
45
46
|
* @param baseElement The element to observe
|
|
46
47
|
* @param options Fine-tune what triggers the MutationObserver's checking function - `subtree` and `childList` are set to true by default
|
|
47
48
|
*/
|
|
48
|
-
constructor(baseElement: Element, options?:
|
|
49
|
+
constructor(baseElement: Element, options?: SelectorObserverConstructorOptions);
|
|
49
50
|
private checkAllSelectors;
|
|
50
51
|
private checkSelector;
|
|
51
52
|
private debounce;
|
package/dist/lib/misc.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/** Represents any value that is either a string itself or can be converted to one (implicitly
|
|
1
|
+
/** Represents any value that is either a string itself or can be converted to one (implicitly and explicitly) because it has a toString() method */
|
|
2
2
|
export type Stringifiable = string | {
|
|
3
3
|
toString(): string;
|
|
4
4
|
};
|
|
@@ -43,7 +43,7 @@ export declare function fetchAdvanced(input: RequestInfo | URL, options?: FetchA
|
|
|
43
43
|
*/
|
|
44
44
|
export declare function insertValues(input: string, ...values: Stringifiable[]): string;
|
|
45
45
|
/** Compresses a string or an ArrayBuffer using the provided {@linkcode compressionFormat} and returns it as a base64 string */
|
|
46
|
-
export declare function compress(input: string | ArrayBuffer, compressionFormat: CompressionFormat, outputType?: "
|
|
46
|
+
export declare function compress(input: string | ArrayBuffer, compressionFormat: CompressionFormat, outputType?: "string"): Promise<string>;
|
|
47
47
|
/** Compresses a string or an ArrayBuffer using the provided {@linkcode compressionFormat} and returns it as an ArrayBuffer */
|
|
48
48
|
export declare function compress(input: string | ArrayBuffer, compressionFormat: CompressionFormat, outputType: "arrayBuffer"): Promise<ArrayBuffer>;
|
|
49
49
|
/** Decompresses a previously compressed base64 string or ArrayBuffer, with the format passed by {@linkcode compressionFormat}, converted to a string */
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sv443-network/userutils",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "5.0.0",
|
|
4
4
|
"description": "Library with various utilities for userscripts - register listeners for when CSS selectors exist, intercept events, manage persistent user configurations, modify the DOM more easily and more",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"module": "dist/index.mjs",
|