@vacantthinker/firefox-addon-framework-easy 2026.625.1220 → 2026.625.1620

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.
@@ -1,2 +1,37 @@
1
- export {};
1
+ import { BaseObjectORM } from './BaseObjectORM';
2
+ /**
3
+ * Abstract class for ORMs that store an Array of items (T[]).
4
+ * Includes atomic mutation methods to prevent race conditions.
5
+ */
6
+ export declare abstract class BaseArrayORM<T> extends BaseObjectORM<T[]> {
7
+ private mutationQueue;
8
+ protected constructor(prefix: string, id: string);
9
+ /**
10
+ * Retrieves the current array. Returns a copy to prevent accidental
11
+ * by-reference mutations outside the ORM.
12
+ */
13
+ getArray(): Promise<T[]>;
14
+ /**
15
+ * Safely appends a new item to the array without race conditions.
16
+ */
17
+ push(item: T): Promise<void>;
18
+ /**
19
+ * Safely appends multiple items.
20
+ */
21
+ pushMany(items: T[]): Promise<void>;
22
+ /**
23
+ * Removes items that match the provided predicate function.
24
+ * @returns {Promise<number>} The number of items removed.
25
+ */
26
+ remove(predicate: (item: T) => boolean): Promise<number>;
27
+ /**
28
+ * Completely clears the array.
29
+ */
30
+ clearArray(): Promise<void>;
31
+ /**
32
+ * Internal mechanism to queue array mutations sequentially.
33
+ * Guarantees that concurrent pushes do not result in lost updates.
34
+ */
35
+ private mutateArray;
36
+ }
2
37
  //# sourceMappingURL=BaseArrayORM.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"BaseArrayORM.d.ts","sourceRoot":"","sources":["../src/BaseArrayORM.ts"],"names":[],"mappings":""}
1
+ {"version":3,"file":"BaseArrayORM.d.ts","sourceRoot":"","sources":["../src/BaseArrayORM.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAEhD;;;GAGG;AACH,8BAAsB,YAAY,CAAC,CAAC,CAAE,SAAQ,aAAa,CAAC,CAAC,EAAE,CAAC;IAG9D,OAAO,CAAC,aAAa,CAAoC;IAEzD,SAAS,aAAa,MAAM,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM;IAMhD;;;OAGG;IACU,QAAQ,IAAI,OAAO,CAAC,CAAC,EAAE,CAAC;IAKrC;;OAEG;IACU,IAAI,CAAC,IAAI,EAAE,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC;IAOzC;;OAEG;IACU,QAAQ,CAAC,KAAK,EAAE,CAAC,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC;IAMhD;;;OAGG;IACU,MAAM,CAAC,SAAS,EAAE,CAAC,IAAI,EAAE,CAAC,KAAK,OAAO,GAAG,OAAO,CAAC,MAAM,CAAC;IAWrE;;OAEG;IACU,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;IAIxC;;;OAGG;YACW,WAAW;CAuB1B"}
@@ -1,86 +1,84 @@
1
- import { stoOpCheck, stoOpGet, stoOpRem, stoOpSet } from './opStorage';
1
+ import { BaseObjectORM } from './BaseObjectORM';
2
2
  /**
3
- * Abstract base class BaseORM.
4
- * Provides encapsulated CRUD operations for JSON-serializable
5
- * Key-Value pairs. Uses Generics (T) to ensure type safety for
6
- * the stored object structure.
3
+ * Abstract class for ORMs that store an Array of items (T[]).
4
+ * Includes atomic mutation methods to prevent race conditions.
7
5
  */
8
- // FIX: Expand constraint to 'any[]' so TabMessageStorageData (an
9
- // array of tuples) is permitted.
10
- class BaseArrayORM {
11
- id;
12
- storageKey;
13
- defaultValue;
14
- // The Mutex "Lock" for preventing race conditions during
15
- // initialization
16
- initPromise = null;
17
- constructor(prefix, id, defaultValue = []) {
18
- if (new.target === BaseArrayORM) {
19
- throw new TypeError('Cannot construct BaseArayORM' +
20
- ' instances directly (Abstract Class).');
21
- }
22
- if (!prefix || !id) {
23
- throw new Error('Both prefix and id must be specified.');
24
- }
25
- this.id = id;
26
- const formattedPrefix = prefix.endsWith(' ') ?
27
- prefix :
28
- `${prefix} `;
29
- this.storageKey = `${formattedPrefix}${id}`;
30
- this.defaultValue = structuredClone(defaultValue);
6
+ export class BaseArrayORM extends BaseObjectORM {
7
+ // A promise queue acting as a Mutex to serialize array mutations
8
+ mutationQueue = Promise.resolve();
9
+ constructor(prefix, id) {
10
+ // Correctly initialize with an empty array.
11
+ // BaseObjectORM accepts 'any[]' so this is type-safe.
12
+ super(prefix, id, []);
31
13
  }
32
14
  /**
33
- * Retrieve the value associated with the bound key.
34
- * @returns {Promise<T>}
15
+ * Retrieves the current array. Returns a copy to prevent accidental
16
+ * by-reference mutations outside the ORM.
35
17
  */
36
- async get() {
37
- if (!(await this.exists())) {
38
- // Calls the lock-protected initialization instead of
39
- // initDefaultObject directly
40
- await this.safeInit();
41
- }
42
- return (await stoOpGet(this.storageKey));
18
+ async getArray() {
19
+ const data = await this.get();
20
+ return Array.isArray(data) ? [...data] : [];
43
21
  }
44
22
  /**
45
- * Overwrite the value of the bound key completely.
46
- * @param {T} value
47
- * @returns {Promise<void>}
23
+ * Safely appends a new item to the array without race conditions.
48
24
  */
49
- async set(value) {
50
- await stoOpSet(this.storageKey, value ?? this.defaultValue);
25
+ async push(item) {
26
+ return this.mutateArray(async (currentArray) => {
27
+ currentArray.push(item);
28
+ return currentArray;
29
+ });
51
30
  }
52
31
  /**
53
- * Wipe the bound key from storage.
54
- * @returns {Promise<T>}
32
+ * Safely appends multiple items.
55
33
  */
56
- async delete() {
57
- const previousValue = await this.get();
58
- await stoOpRem(this.storageKey);
59
- return previousValue;
34
+ async pushMany(items) {
35
+ return this.mutateArray(async (currentArray) => {
36
+ return currentArray.concat(items);
37
+ });
60
38
  }
61
39
  /**
62
- * Safely initialize the default object. Prevents multiple
63
- * concurrent requests from writing the default value
64
- * simultaneously.
40
+ * Removes items that match the provided predicate function.
41
+ * @returns {Promise<number>} The number of items removed.
65
42
  */
66
- async safeInit() {
67
- // If an initialization is already in progress, wait for it
68
- if (this.initPromise) {
69
- return this.initPromise;
70
- }
71
- // Start initialization and store the Promise as the lock
72
- this.initPromise = this.initDefaultObject()
73
- .finally(() => {
74
- // Clear the lock whether the initialization succeeds or
75
- // fails
76
- this.initPromise = null;
43
+ async remove(predicate) {
44
+ let removedCount = 0;
45
+ await this.mutateArray(async (currentArray) => {
46
+ const initialLength = currentArray.length;
47
+ const filtered = currentArray.filter((item) => !predicate(item));
48
+ removedCount = initialLength - filtered.length;
49
+ return filtered;
77
50
  });
78
- return this.initPromise;
51
+ return removedCount;
79
52
  }
80
- async exists() {
81
- return await stoOpCheck(this.storageKey);
53
+ /**
54
+ * Completely clears the array.
55
+ */
56
+ async clearArray() {
57
+ await this.set([]);
82
58
  }
83
- async initDefaultObject() {
84
- await stoOpSet(this.storageKey, this.defaultValue);
59
+ /**
60
+ * Internal mechanism to queue array mutations sequentially.
61
+ * Guarantees that concurrent pushes do not result in lost updates.
62
+ */
63
+ async mutateArray(mutator) {
64
+ this.mutationQueue = this.mutationQueue.then(async () => {
65
+ try {
66
+ let currentData = await this.get();
67
+ // Data integrity fallback
68
+ if (!Array.isArray(currentData)) {
69
+ console.warn(`BaseArrayORM: Invalid data type for ${this.storageKey}. Resetting to Array.`);
70
+ currentData = [];
71
+ }
72
+ const updatedArray = await mutator(currentData);
73
+ await this.set(updatedArray);
74
+ }
75
+ catch (error) {
76
+ console.error(`BaseArrayORM: Failed to mutate array for ${this.storageKey}`, error);
77
+ throw error;
78
+ }
79
+ }).catch(() => {
80
+ // Prevents queue deadlocks on individual transaction failures
81
+ });
82
+ return this.mutationQueue;
85
83
  }
86
84
  }
@@ -1,15 +1,35 @@
1
1
  import { BaseObjectORM } from './BaseObjectORM';
2
+ interface BooleanState {
3
+ state: boolean;
4
+ }
2
5
  /**
3
- * Abstract class for ORMs that store Map<string, V> data.
4
- * Automatically handles the conversion between internal
5
- * Record<string, V> and Map<string, V>.
6
+ * Abstract class for ORMs that store a single boolean state.
7
+ * Optimized to remove Map overhead and prevent race conditions.
6
8
  */
7
- export declare abstract class BaseOneBooleanORM extends BaseObjectORM<Record<string, boolean>> {
8
- private readonly state;
9
+ export declare abstract class BaseOneBooleanORM extends BaseObjectORM<BooleanState> {
10
+ private readonly stateKey;
11
+ private writeLock;
9
12
  protected constructor(prefix: string, id: string);
13
+ /**
14
+ * Retrieves the current boolean value.
15
+ */
10
16
  getValue(): Promise<boolean>;
17
+ /**
18
+ * Direct overwrite of the boolean value.
19
+ * Queued to prevent overwriting a concurrent toggle/update
20
+ * operation.
21
+ */
11
22
  setValue(value: boolean): Promise<void>;
12
- private getMap;
13
- private setMap;
23
+ /**
24
+ * Safely toggles or updates the value based on the previous
25
+ * state. This guarantees no race conditions during
26
+ * Read-Modify-Write cycles.
27
+ */
28
+ protected updateValue(updater: (prevValue: boolean) => boolean): Promise<void>;
29
+ /**
30
+ * Internal mechanism to queue state changes sequentially.
31
+ */
32
+ private atomicUpdate;
14
33
  }
34
+ export {};
15
35
  //# sourceMappingURL=BaseOneBooleanORM.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"BaseOneBooleanORM.d.ts","sourceRoot":"","sources":["../src/BaseOneBooleanORM.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,aAAa,EAAC,MAAM,iBAAiB,CAAC;AAE9C;;;;GAIG;AACH,8BAAsB,iBAAkB,SAAQ,aAAa,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACpF,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAmB;IAEzC,SAAS,aAAa,MAAM,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM;IAKnC,QAAQ;IAKR,QAAQ,CAAC,KAAK,EAAE,OAAO;YAMtB,MAAM;YAKN,MAAM;CAGrB"}
1
+ {"version":3,"file":"BaseOneBooleanORM.d.ts","sourceRoot":"","sources":["../src/BaseOneBooleanORM.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,aAAa,EAAC,MAAM,iBAAiB,CAAC;AAG9C,UAAU,YAAY;IACpB,KAAK,EAAE,OAAO,CAAC;CAChB;AAED;;;GAGG;AACH,8BAAsB,iBAAkB,SAAQ,aAAa,CAAC,YAAY,CAAC;IACzE,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAW;IAIpC,OAAO,CAAC,SAAS,CAAoC;IAErD,SAAS,aAAa,MAAM,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM;IAKhD;;OAEG;IACU,QAAQ,IAAI,OAAO,CAAC,OAAO,CAAC;IAKzC;;;;OAIG;IACU,QAAQ,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC;IAIpD;;;;OAIG;cACa,WAAW,CAAC,OAAO,EAAE,CAAC,SAAS,EAAE,OAAO,KAAK,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC;IAIpF;;OAEG;YACW,YAAY;CAoB3B"}
@@ -1,29 +1,59 @@
1
1
  import { BaseObjectORM } from './BaseObjectORM';
2
2
  /**
3
- * Abstract class for ORMs that store Map<string, V> data.
4
- * Automatically handles the conversion between internal
5
- * Record<string, V> and Map<string, V>.
3
+ * Abstract class for ORMs that store a single boolean state.
4
+ * Optimized to remove Map overhead and prevent race conditions.
6
5
  */
7
6
  export class BaseOneBooleanORM extends BaseObjectORM {
8
- state = "state";
7
+ stateKey = 'state';
8
+ // A promise queue acting as a Mutex to serialize write
9
+ // operations
10
+ writeLock = Promise.resolve();
9
11
  constructor(prefix, id) {
10
- super(prefix, id, { "state": false });
11
- // todo here cannot use this.state, why?
12
+ // Pass the default state directly to the parent
13
+ super(prefix, id, { state: false });
12
14
  }
15
+ /**
16
+ * Retrieves the current boolean value.
17
+ */
13
18
  async getValue() {
14
- const map = await this.getMap();
15
- return map.get(this.state) || false;
19
+ const data = await this.get();
20
+ return data?.[this.stateKey] ?? false;
16
21
  }
22
+ /**
23
+ * Direct overwrite of the boolean value.
24
+ * Queued to prevent overwriting a concurrent toggle/update
25
+ * operation.
26
+ */
17
27
  async setValue(value) {
18
- const map = await this.getMap();
19
- map.set(this.state, value);
20
- await this.setMap(map);
28
+ return this.atomicUpdate(() => value);
21
29
  }
22
- async getMap() {
23
- const data = await this.get();
24
- return new Map(Object.entries(data || {}));
30
+ /**
31
+ * Safely toggles or updates the value based on the previous
32
+ * state. This guarantees no race conditions during
33
+ * Read-Modify-Write cycles.
34
+ */
35
+ async updateValue(updater) {
36
+ return this.atomicUpdate(updater);
25
37
  }
26
- async setMap(map) {
27
- await this.set(Object.fromEntries(map));
38
+ /**
39
+ * Internal mechanism to queue state changes sequentially.
40
+ */
41
+ async atomicUpdate(updater) {
42
+ this.writeLock = this.writeLock.then(async () => {
43
+ try {
44
+ const currentData = await this.get();
45
+ const currentValue = currentData?.[this.stateKey] ?? false;
46
+ const newValue = updater(currentValue);
47
+ await this.set({ [this.stateKey]: newValue });
48
+ }
49
+ catch (error) {
50
+ console.error(`BaseOneBooleanORM: Failed to update state for ${this.storageKey}`, error);
51
+ throw error;
52
+ }
53
+ }).catch(() => {
54
+ // Catch prevents a single failure from permanently
55
+ // breaking the queue chain
56
+ });
57
+ return this.writeLock;
28
58
  }
29
59
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vacantthinker/firefox-addon-framework-easy",
3
- "version": "2026.0625.1220",
3
+ "version": "2026.0625.1620",
4
4
  "description": "",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",