@metamask-previews/storage-service 1.0.0-preview-f5c5aecd → 1.0.0-preview-81c9cf83

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.
@@ -0,0 +1 @@
1
+ {"version":3,"file":"StorageService-method-action-types.cjs","sourceRoot":"","sources":["../src/StorageService-method-action-types.ts"],"names":[],"mappings":";AAAA;;;GAGG","sourcesContent":["/**\n * This file is auto generated by `scripts/generate-method-action-types.ts`.\n * Do not edit manually.\n */\n\nimport type { StorageService } from './StorageService';\n\n/**\n * Store large data in storage.\n *\n * ⚠️ **Designed for large values (100KB+), not many small ones.**\n * Each storage operation has I/O overhead. For best performance,\n * store one large object rather than many small key-value pairs.\n *\n * @example Good: Store entire cache as one value\n * ```typescript\n * await service.setItem('TokenList', 'cache', { '0x1': [...], '0x38': [...] });\n * ```\n *\n * @example Avoid: Many small values\n * ```typescript\n * // ❌ Don't do this - too many small writes\n * await service.setItem('TokenList', 'cache:0x1', [...]);\n * await service.setItem('TokenList', 'cache:0x38', [...]);\n * ```\n *\n * @param namespace - Controller namespace (e.g., 'SnapController').\n * @param key - Storage key (e.g., 'npm:@metamask/example-snap:sourceCode').\n * @param value - Data to store (should be 100KB+ for optimal use).\n */\nexport type StorageServiceSetItemAction = {\n type: `StorageService:setItem`;\n handler: StorageService['setItem'];\n};\n\n/**\n * Retrieve data from storage.\n *\n * Returns `unknown` since there's no schema validation.\n * Callers should validate or cast the result to the expected type.\n *\n * @param namespace - Controller namespace (e.g., 'SnapController').\n * @param key - Storage key (e.g., 'npm:@metamask/example-snap:sourceCode').\n * @returns Parsed data or null if not found. Type is `unknown` - caller must validate.\n */\nexport type StorageServiceGetItemAction = {\n type: `StorageService:getItem`;\n handler: StorageService['getItem'];\n};\n\n/**\n * Remove data from storage.\n *\n * @param namespace - Controller namespace (e.g., 'SnapController').\n * @param key - Storage key (e.g., 'npm:@metamask/example-snap:sourceCode').\n */\nexport type StorageServiceRemoveItemAction = {\n type: `StorageService:removeItem`;\n handler: StorageService['removeItem'];\n};\n\n/**\n * Get all keys for a namespace.\n * Delegates to storage adapter which handles filtering.\n *\n * @param namespace - Controller namespace (e.g., 'SnapController').\n * @returns Array of keys (without prefix) for this namespace.\n */\nexport type StorageServiceGetAllKeysAction = {\n type: `StorageService:getAllKeys`;\n handler: StorageService['getAllKeys'];\n};\n\n/**\n * Clear all data for a namespace.\n *\n * @param namespace - Controller namespace (e.g., 'SnapController').\n */\nexport type StorageServiceClearAction = {\n type: `StorageService:clear`;\n handler: StorageService['clear'];\n};\n\n/**\n * Union of all StorageService action types.\n */\nexport type StorageServiceMethodActions =\n | StorageServiceSetItemAction\n | StorageServiceGetItemAction\n | StorageServiceRemoveItemAction\n | StorageServiceGetAllKeysAction\n | StorageServiceClearAction;\n"]}
@@ -0,0 +1,81 @@
1
+ /**
2
+ * This file is auto generated by `scripts/generate-method-action-types.ts`.
3
+ * Do not edit manually.
4
+ */
5
+ import type { StorageService } from "./StorageService.cjs";
6
+ /**
7
+ * Store large data in storage.
8
+ *
9
+ * ⚠️ **Designed for large values (100KB+), not many small ones.**
10
+ * Each storage operation has I/O overhead. For best performance,
11
+ * store one large object rather than many small key-value pairs.
12
+ *
13
+ * @example Good: Store entire cache as one value
14
+ * ```typescript
15
+ * await service.setItem('TokenList', 'cache', { '0x1': [...], '0x38': [...] });
16
+ * ```
17
+ *
18
+ * @example Avoid: Many small values
19
+ * ```typescript
20
+ * // ❌ Don't do this - too many small writes
21
+ * await service.setItem('TokenList', 'cache:0x1', [...]);
22
+ * await service.setItem('TokenList', 'cache:0x38', [...]);
23
+ * ```
24
+ *
25
+ * @param namespace - Controller namespace (e.g., 'SnapController').
26
+ * @param key - Storage key (e.g., 'npm:@metamask/example-snap:sourceCode').
27
+ * @param value - Data to store (should be 100KB+ for optimal use).
28
+ */
29
+ export type StorageServiceSetItemAction = {
30
+ type: `StorageService:setItem`;
31
+ handler: StorageService['setItem'];
32
+ };
33
+ /**
34
+ * Retrieve data from storage.
35
+ *
36
+ * Returns `unknown` since there's no schema validation.
37
+ * Callers should validate or cast the result to the expected type.
38
+ *
39
+ * @param namespace - Controller namespace (e.g., 'SnapController').
40
+ * @param key - Storage key (e.g., 'npm:@metamask/example-snap:sourceCode').
41
+ * @returns Parsed data or null if not found. Type is `unknown` - caller must validate.
42
+ */
43
+ export type StorageServiceGetItemAction = {
44
+ type: `StorageService:getItem`;
45
+ handler: StorageService['getItem'];
46
+ };
47
+ /**
48
+ * Remove data from storage.
49
+ *
50
+ * @param namespace - Controller namespace (e.g., 'SnapController').
51
+ * @param key - Storage key (e.g., 'npm:@metamask/example-snap:sourceCode').
52
+ */
53
+ export type StorageServiceRemoveItemAction = {
54
+ type: `StorageService:removeItem`;
55
+ handler: StorageService['removeItem'];
56
+ };
57
+ /**
58
+ * Get all keys for a namespace.
59
+ * Delegates to storage adapter which handles filtering.
60
+ *
61
+ * @param namespace - Controller namespace (e.g., 'SnapController').
62
+ * @returns Array of keys (without prefix) for this namespace.
63
+ */
64
+ export type StorageServiceGetAllKeysAction = {
65
+ type: `StorageService:getAllKeys`;
66
+ handler: StorageService['getAllKeys'];
67
+ };
68
+ /**
69
+ * Clear all data for a namespace.
70
+ *
71
+ * @param namespace - Controller namespace (e.g., 'SnapController').
72
+ */
73
+ export type StorageServiceClearAction = {
74
+ type: `StorageService:clear`;
75
+ handler: StorageService['clear'];
76
+ };
77
+ /**
78
+ * Union of all StorageService action types.
79
+ */
80
+ export type StorageServiceMethodActions = StorageServiceSetItemAction | StorageServiceGetItemAction | StorageServiceRemoveItemAction | StorageServiceGetAllKeysAction | StorageServiceClearAction;
81
+ //# sourceMappingURL=StorageService-method-action-types.d.cts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"StorageService-method-action-types.d.cts","sourceRoot":"","sources":["../src/StorageService-method-action-types.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,cAAc,EAAE,6BAAyB;AAEvD;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,MAAM,MAAM,2BAA2B,GAAG;IACxC,IAAI,EAAE,wBAAwB,CAAC;IAC/B,OAAO,EAAE,cAAc,CAAC,SAAS,CAAC,CAAC;CACpC,CAAC;AAEF;;;;;;;;;GASG;AACH,MAAM,MAAM,2BAA2B,GAAG;IACxC,IAAI,EAAE,wBAAwB,CAAC;IAC/B,OAAO,EAAE,cAAc,CAAC,SAAS,CAAC,CAAC;CACpC,CAAC;AAEF;;;;;GAKG;AACH,MAAM,MAAM,8BAA8B,GAAG;IAC3C,IAAI,EAAE,2BAA2B,CAAC;IAClC,OAAO,EAAE,cAAc,CAAC,YAAY,CAAC,CAAC;CACvC,CAAC;AAEF;;;;;;GAMG;AACH,MAAM,MAAM,8BAA8B,GAAG;IAC3C,IAAI,EAAE,2BAA2B,CAAC;IAClC,OAAO,EAAE,cAAc,CAAC,YAAY,CAAC,CAAC;CACvC,CAAC;AAEF;;;;GAIG;AACH,MAAM,MAAM,yBAAyB,GAAG;IACtC,IAAI,EAAE,sBAAsB,CAAC;IAC7B,OAAO,EAAE,cAAc,CAAC,OAAO,CAAC,CAAC;CAClC,CAAC;AAEF;;GAEG;AACH,MAAM,MAAM,2BAA2B,GACnC,2BAA2B,GAC3B,2BAA2B,GAC3B,8BAA8B,GAC9B,8BAA8B,GAC9B,yBAAyB,CAAC"}
@@ -0,0 +1,81 @@
1
+ /**
2
+ * This file is auto generated by `scripts/generate-method-action-types.ts`.
3
+ * Do not edit manually.
4
+ */
5
+ import type { StorageService } from "./StorageService.mjs";
6
+ /**
7
+ * Store large data in storage.
8
+ *
9
+ * ⚠️ **Designed for large values (100KB+), not many small ones.**
10
+ * Each storage operation has I/O overhead. For best performance,
11
+ * store one large object rather than many small key-value pairs.
12
+ *
13
+ * @example Good: Store entire cache as one value
14
+ * ```typescript
15
+ * await service.setItem('TokenList', 'cache', { '0x1': [...], '0x38': [...] });
16
+ * ```
17
+ *
18
+ * @example Avoid: Many small values
19
+ * ```typescript
20
+ * // ❌ Don't do this - too many small writes
21
+ * await service.setItem('TokenList', 'cache:0x1', [...]);
22
+ * await service.setItem('TokenList', 'cache:0x38', [...]);
23
+ * ```
24
+ *
25
+ * @param namespace - Controller namespace (e.g., 'SnapController').
26
+ * @param key - Storage key (e.g., 'npm:@metamask/example-snap:sourceCode').
27
+ * @param value - Data to store (should be 100KB+ for optimal use).
28
+ */
29
+ export type StorageServiceSetItemAction = {
30
+ type: `StorageService:setItem`;
31
+ handler: StorageService['setItem'];
32
+ };
33
+ /**
34
+ * Retrieve data from storage.
35
+ *
36
+ * Returns `unknown` since there's no schema validation.
37
+ * Callers should validate or cast the result to the expected type.
38
+ *
39
+ * @param namespace - Controller namespace (e.g., 'SnapController').
40
+ * @param key - Storage key (e.g., 'npm:@metamask/example-snap:sourceCode').
41
+ * @returns Parsed data or null if not found. Type is `unknown` - caller must validate.
42
+ */
43
+ export type StorageServiceGetItemAction = {
44
+ type: `StorageService:getItem`;
45
+ handler: StorageService['getItem'];
46
+ };
47
+ /**
48
+ * Remove data from storage.
49
+ *
50
+ * @param namespace - Controller namespace (e.g., 'SnapController').
51
+ * @param key - Storage key (e.g., 'npm:@metamask/example-snap:sourceCode').
52
+ */
53
+ export type StorageServiceRemoveItemAction = {
54
+ type: `StorageService:removeItem`;
55
+ handler: StorageService['removeItem'];
56
+ };
57
+ /**
58
+ * Get all keys for a namespace.
59
+ * Delegates to storage adapter which handles filtering.
60
+ *
61
+ * @param namespace - Controller namespace (e.g., 'SnapController').
62
+ * @returns Array of keys (without prefix) for this namespace.
63
+ */
64
+ export type StorageServiceGetAllKeysAction = {
65
+ type: `StorageService:getAllKeys`;
66
+ handler: StorageService['getAllKeys'];
67
+ };
68
+ /**
69
+ * Clear all data for a namespace.
70
+ *
71
+ * @param namespace - Controller namespace (e.g., 'SnapController').
72
+ */
73
+ export type StorageServiceClearAction = {
74
+ type: `StorageService:clear`;
75
+ handler: StorageService['clear'];
76
+ };
77
+ /**
78
+ * Union of all StorageService action types.
79
+ */
80
+ export type StorageServiceMethodActions = StorageServiceSetItemAction | StorageServiceGetItemAction | StorageServiceRemoveItemAction | StorageServiceGetAllKeysAction | StorageServiceClearAction;
81
+ //# sourceMappingURL=StorageService-method-action-types.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"StorageService-method-action-types.d.mts","sourceRoot":"","sources":["../src/StorageService-method-action-types.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,cAAc,EAAE,6BAAyB;AAEvD;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,MAAM,MAAM,2BAA2B,GAAG;IACxC,IAAI,EAAE,wBAAwB,CAAC;IAC/B,OAAO,EAAE,cAAc,CAAC,SAAS,CAAC,CAAC;CACpC,CAAC;AAEF;;;;;;;;;GASG;AACH,MAAM,MAAM,2BAA2B,GAAG;IACxC,IAAI,EAAE,wBAAwB,CAAC;IAC/B,OAAO,EAAE,cAAc,CAAC,SAAS,CAAC,CAAC;CACpC,CAAC;AAEF;;;;;GAKG;AACH,MAAM,MAAM,8BAA8B,GAAG;IAC3C,IAAI,EAAE,2BAA2B,CAAC;IAClC,OAAO,EAAE,cAAc,CAAC,YAAY,CAAC,CAAC;CACvC,CAAC;AAEF;;;;;;GAMG;AACH,MAAM,MAAM,8BAA8B,GAAG;IAC3C,IAAI,EAAE,2BAA2B,CAAC;IAClC,OAAO,EAAE,cAAc,CAAC,YAAY,CAAC,CAAC;CACvC,CAAC;AAEF;;;;GAIG;AACH,MAAM,MAAM,yBAAyB,GAAG;IACtC,IAAI,EAAE,sBAAsB,CAAC;IAC7B,OAAO,EAAE,cAAc,CAAC,OAAO,CAAC,CAAC;CAClC,CAAC;AAEF;;GAEG;AACH,MAAM,MAAM,2BAA2B,GACnC,2BAA2B,GAC3B,2BAA2B,GAC3B,8BAA8B,GAC9B,8BAA8B,GAC9B,yBAAyB,CAAC"}
@@ -0,0 +1,6 @@
1
+ /**
2
+ * This file is auto generated by `scripts/generate-method-action-types.ts`.
3
+ * Do not edit manually.
4
+ */
5
+ export {};
6
+ //# sourceMappingURL=StorageService-method-action-types.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"StorageService-method-action-types.mjs","sourceRoot":"","sources":["../src/StorageService-method-action-types.ts"],"names":[],"mappings":"AAAA;;;GAGG","sourcesContent":["/**\n * This file is auto generated by `scripts/generate-method-action-types.ts`.\n * Do not edit manually.\n */\n\nimport type { StorageService } from './StorageService';\n\n/**\n * Store large data in storage.\n *\n * ⚠️ **Designed for large values (100KB+), not many small ones.**\n * Each storage operation has I/O overhead. For best performance,\n * store one large object rather than many small key-value pairs.\n *\n * @example Good: Store entire cache as one value\n * ```typescript\n * await service.setItem('TokenList', 'cache', { '0x1': [...], '0x38': [...] });\n * ```\n *\n * @example Avoid: Many small values\n * ```typescript\n * // ❌ Don't do this - too many small writes\n * await service.setItem('TokenList', 'cache:0x1', [...]);\n * await service.setItem('TokenList', 'cache:0x38', [...]);\n * ```\n *\n * @param namespace - Controller namespace (e.g., 'SnapController').\n * @param key - Storage key (e.g., 'npm:@metamask/example-snap:sourceCode').\n * @param value - Data to store (should be 100KB+ for optimal use).\n */\nexport type StorageServiceSetItemAction = {\n type: `StorageService:setItem`;\n handler: StorageService['setItem'];\n};\n\n/**\n * Retrieve data from storage.\n *\n * Returns `unknown` since there's no schema validation.\n * Callers should validate or cast the result to the expected type.\n *\n * @param namespace - Controller namespace (e.g., 'SnapController').\n * @param key - Storage key (e.g., 'npm:@metamask/example-snap:sourceCode').\n * @returns Parsed data or null if not found. Type is `unknown` - caller must validate.\n */\nexport type StorageServiceGetItemAction = {\n type: `StorageService:getItem`;\n handler: StorageService['getItem'];\n};\n\n/**\n * Remove data from storage.\n *\n * @param namespace - Controller namespace (e.g., 'SnapController').\n * @param key - Storage key (e.g., 'npm:@metamask/example-snap:sourceCode').\n */\nexport type StorageServiceRemoveItemAction = {\n type: `StorageService:removeItem`;\n handler: StorageService['removeItem'];\n};\n\n/**\n * Get all keys for a namespace.\n * Delegates to storage adapter which handles filtering.\n *\n * @param namespace - Controller namespace (e.g., 'SnapController').\n * @returns Array of keys (without prefix) for this namespace.\n */\nexport type StorageServiceGetAllKeysAction = {\n type: `StorageService:getAllKeys`;\n handler: StorageService['getAllKeys'];\n};\n\n/**\n * Clear all data for a namespace.\n *\n * @param namespace - Controller namespace (e.g., 'SnapController').\n */\nexport type StorageServiceClearAction = {\n type: `StorageService:clear`;\n handler: StorageService['clear'];\n};\n\n/**\n * Union of all StorageService action types.\n */\nexport type StorageServiceMethodActions =\n | StorageServiceSetItemAction\n | StorageServiceGetItemAction\n | StorageServiceRemoveItemAction\n | StorageServiceGetAllKeysAction\n | StorageServiceClearAction;\n"]}
@@ -15,6 +15,14 @@ Object.defineProperty(exports, "__esModule", { value: true });
15
15
  exports.StorageService = void 0;
16
16
  const InMemoryStorageAdapter_1 = require("./InMemoryStorageAdapter.cjs");
17
17
  const types_1 = require("./types.cjs");
18
+ // === MESSENGER ===
19
+ const MESSENGER_EXPOSED_METHODS = [
20
+ 'setItem',
21
+ 'getItem',
22
+ 'removeItem',
23
+ 'getAllKeys',
24
+ 'clear',
25
+ ];
18
26
  /**
19
27
  * StorageService provides a platform-agnostic way for controllers to store
20
28
  * large, infrequently accessed data outside of memory/Redux state.
@@ -55,11 +63,12 @@ const types_1 = require("./types.cjs");
55
63
  * }
56
64
  *
57
65
  * async getSnapSourceCode(snapId: string): Promise<string | null> {
58
- * return await this.messenger.call(
66
+ * const result = await this.messenger.call(
59
67
  * 'StorageService:getItem',
60
68
  * 'SnapController',
61
69
  * `${snapId}:sourceCode`,
62
70
  * );
71
+ * return result as string | null; // Caller must validate/cast
63
72
  * }
64
73
  * }
65
74
  * ```
@@ -113,19 +122,30 @@ class StorageService {
113
122
  'Data will be lost on restart. Provide a storage adapter for persistence.');
114
123
  }
115
124
  // Register messenger actions
116
- __classPrivateFieldGet(this, _StorageService_messenger, "f").registerActionHandler(`${types_1.SERVICE_NAME}:setItem`, this.setItem.bind(this));
117
- __classPrivateFieldGet(this, _StorageService_messenger, "f").registerActionHandler(`${types_1.SERVICE_NAME}:getItem`, this.getItem.bind(this));
118
- __classPrivateFieldGet(this, _StorageService_messenger, "f").registerActionHandler(`${types_1.SERVICE_NAME}:removeItem`, this.removeItem.bind(this));
119
- __classPrivateFieldGet(this, _StorageService_messenger, "f").registerActionHandler(`${types_1.SERVICE_NAME}:getAllKeys`, this.getAllKeys.bind(this));
120
- __classPrivateFieldGet(this, _StorageService_messenger, "f").registerActionHandler(`${types_1.SERVICE_NAME}:clear`, this.clear.bind(this));
125
+ __classPrivateFieldGet(this, _StorageService_messenger, "f").registerMethodActionHandlers(this, MESSENGER_EXPOSED_METHODS);
121
126
  }
122
127
  /**
123
- * Store data in storage.
128
+ * Store large data in storage.
129
+ *
130
+ * ⚠️ **Designed for large values (100KB+), not many small ones.**
131
+ * Each storage operation has I/O overhead. For best performance,
132
+ * store one large object rather than many small key-value pairs.
133
+ *
134
+ * @example Good: Store entire cache as one value
135
+ * ```typescript
136
+ * await service.setItem('TokenList', 'cache', { '0x1': [...], '0x38': [...] });
137
+ * ```
138
+ *
139
+ * @example Avoid: Many small values
140
+ * ```typescript
141
+ * // ❌ Don't do this - too many small writes
142
+ * await service.setItem('TokenList', 'cache:0x1', [...]);
143
+ * await service.setItem('TokenList', 'cache:0x38', [...]);
144
+ * ```
124
145
  *
125
146
  * @param namespace - Controller namespace (e.g., 'SnapController').
126
147
  * @param key - Storage key (e.g., 'npm:@metamask/example-snap:sourceCode').
127
- * @param value - Data to store (will be JSON stringified).
128
- * @template T - The type of the value being stored.
148
+ * @param value - Data to store (should be 100KB+ for optimal use).
129
149
  */
130
150
  async setItem(namespace, key, value) {
131
151
  // Adapter handles serialization and wrapping with metadata
@@ -138,15 +158,16 @@ class StorageService {
138
158
  /**
139
159
  * Retrieve data from storage.
140
160
  *
161
+ * Returns `unknown` since there's no schema validation.
162
+ * Callers should validate or cast the result to the expected type.
163
+ *
141
164
  * @param namespace - Controller namespace (e.g., 'SnapController').
142
165
  * @param key - Storage key (e.g., 'npm:@metamask/example-snap:sourceCode').
143
- * @returns Parsed data or null if not found.
144
- * @template T - The type of the value being retrieved.
166
+ * @returns Parsed data or null if not found. Type is `unknown` - caller must validate.
145
167
  */
146
168
  async getItem(namespace, key) {
147
169
  // Adapter handles deserialization and unwrapping
148
- const result = await __classPrivateFieldGet(this, _StorageService_storage, "f").getItem(namespace, key);
149
- return result;
170
+ return await __classPrivateFieldGet(this, _StorageService_storage, "f").getItem(namespace, key);
150
171
  }
151
172
  /**
152
173
  * Remove data from storage.
@@ -157,10 +178,6 @@ class StorageService {
157
178
  async removeItem(namespace, key) {
158
179
  // Adapter builds full storage key (e.g., mobile: 'storageService:namespace:key')
159
180
  await __classPrivateFieldGet(this, _StorageService_storage, "f").removeItem(namespace, key);
160
- // Publish event so other controllers can react to removal
161
- // Event type: StorageService:itemRemoved:namespace
162
- // Payload: [key]
163
- __classPrivateFieldGet(this, _StorageService_messenger, "f").publish(`${types_1.SERVICE_NAME}:itemRemoved:${namespace}`, key);
164
181
  }
165
182
  /**
166
183
  * Get all keys for a namespace.
@@ -174,7 +191,6 @@ class StorageService {
174
191
  }
175
192
  /**
176
193
  * Clear all data for a namespace.
177
- * Delegates to storage adapter which handles clearing.
178
194
  *
179
195
  * @param namespace - Controller namespace (e.g., 'SnapController').
180
196
  */
@@ -1 +1 @@
1
- {"version":3,"file":"StorageService.cjs","sourceRoot":"","sources":["../src/StorageService.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;AAAA,yEAAkE;AAMlE,uCAAuC;AAEvC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsEG;AACH,MAAa,cAAc;IAgBzB;;;;;;;OAOG;IACH,YAAY,EAAE,SAAS,EAAE,OAAO,EAAyB;QAlBzD;;WAEG;QACM,4CAAoC;QAE7C;;WAEG;QACM,0CAAyB;QAWhC,IAAI,CAAC,IAAI,GAAG,oBAAY,CAAC;QACzB,uBAAA,IAAI,6BAAc,SAAS,MAAA,CAAC;QAC5B,uBAAA,IAAI,2BAAY,OAAO,IAAI,IAAI,+CAAsB,EAAE,MAAA,CAAC;QAExD,uDAAuD;QACvD,IAAI,CAAC,OAAO,EAAE,CAAC;YACb,OAAO,CAAC,IAAI,CACV,GAAG,oBAAY,0DAA0D;gBACvE,0EAA0E,CAC7E,CAAC;QACJ,CAAC;QAED,6BAA6B;QAC7B,uBAAA,IAAI,iCAAW,CAAC,qBAAqB,CACnC,GAAG,oBAAY,UAAU,EACzB,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,CACxB,CAAC;QACF,uBAAA,IAAI,iCAAW,CAAC,qBAAqB,CACnC,GAAG,oBAAY,UAAU,EACzB,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,CACxB,CAAC;QACF,uBAAA,IAAI,iCAAW,CAAC,qBAAqB,CACnC,GAAG,oBAAY,aAAa,EAC5B,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,CAC3B,CAAC;QACF,uBAAA,IAAI,iCAAW,CAAC,qBAAqB,CACnC,GAAG,oBAAY,aAAa,EAC5B,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,CAC3B,CAAC;QACF,uBAAA,IAAI,iCAAW,CAAC,qBAAqB,CACnC,GAAG,oBAAY,QAAQ,EACvB,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CACtB,CAAC;IACJ,CAAC;IAED;;;;;;;OAOG;IACH,KAAK,CAAC,OAAO,CAAI,SAAiB,EAAE,GAAW,EAAE,KAAQ;QACvD,2DAA2D;QAC3D,MAAM,uBAAA,IAAI,+BAAS,CAAC,OAAO,CAAC,SAAS,EAAE,GAAG,EAAE,KAAc,CAAC,CAAC;QAE5D,0DAA0D;QAC1D,+CAA+C;QAC/C,wBAAwB;QACxB,uBAAA,IAAI,iCAAW,CAAC,OAAO,CACrB,GAAG,oBAAY,YAAY,SAAS,EAAgD,EACpF,KAAK,EACL,GAAG,CACJ,CAAC;IACJ,CAAC;IAED;;;;;;;OAOG;IACH,KAAK,CAAC,OAAO,CAAI,SAAiB,EAAE,GAAW;QAC7C,iDAAiD;QACjD,MAAM,MAAM,GAAG,MAAM,uBAAA,IAAI,+BAAS,CAAC,OAAO,CAAC,SAAS,EAAE,GAAG,CAAC,CAAC;QAC3D,OAAO,MAAkB,CAAC;IAC5B,CAAC;IAED;;;;;OAKG;IACH,KAAK,CAAC,UAAU,CAAC,SAAiB,EAAE,GAAW;QAC7C,iFAAiF;QACjF,MAAM,uBAAA,IAAI,+BAAS,CAAC,UAAU,CAAC,SAAS,EAAE,GAAG,CAAC,CAAC;QAE/C,0DAA0D;QAC1D,mDAAmD;QACnD,iBAAiB;QACjB,uBAAA,IAAI,iCAAW,CAAC,OAAO,CACrB,GAAG,oBAAY,gBAAgB,SAAS,EAAoD,EAC5F,GAAG,CACJ,CAAC;IACJ,CAAC;IAED;;;;;;OAMG;IACH,KAAK,CAAC,UAAU,CAAC,SAAiB;QAChC,OAAO,MAAM,uBAAA,IAAI,+BAAS,CAAC,UAAU,CAAC,SAAS,CAAC,CAAC;IACnD,CAAC;IAED;;;;;OAKG;IACH,KAAK,CAAC,KAAK,CAAC,SAAiB;QAC3B,MAAM,uBAAA,IAAI,+BAAS,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC;IACvC,CAAC;CACF;AAvID,wCAuIC","sourcesContent":["import { InMemoryStorageAdapter } from './InMemoryStorageAdapter';\nimport type {\n StorageAdapter,\n StorageServiceMessenger,\n StorageServiceOptions,\n} from './types';\nimport { SERVICE_NAME } from './types';\n\n/**\n * StorageService provides a platform-agnostic way for controllers to store\n * large, infrequently accessed data outside of memory/Redux state.\n *\n * **Use cases:**\n * - Snap source code (6+ MB that's rarely accessed)\n * - Token metadata caches (4+ MB of cached data)\n * - Large cached responses from APIs\n * - Any data > 100 KB that's not frequently accessed\n *\n * **Benefits:**\n * - Reduces memory usage (data stays on disk)\n * - Faster Redux persist (less data to serialize)\n * - Faster app startup (less data to parse)\n * - Lazy loading (data loaded only when needed)\n *\n * **Platform Support:**\n * - Mobile: FilesystemStorage adapter\n * - Extension: IndexedDB adapter\n * - Tests/Dev: InMemoryStorageAdapter (default)\n *\n * @example Using the service via messenger\n *\n * ```typescript\n * // In a controller\n * type AllowedActions =\n * | StorageServiceSetItemAction\n * | StorageServiceGetItemAction;\n *\n * class SnapController extends BaseController {\n * async storeSnapSourceCode(snapId: string, sourceCode: string) {\n * await this.messenger.call(\n * 'StorageService:setItem',\n * 'SnapController',\n * `${snapId}:sourceCode`,\n * sourceCode,\n * );\n * }\n *\n * async getSnapSourceCode(snapId: string): Promise<string | null> {\n * return await this.messenger.call(\n * 'StorageService:getItem',\n * 'SnapController',\n * `${snapId}:sourceCode`,\n * );\n * }\n * }\n * ```\n *\n * @example Initializing in a client\n *\n * ```typescript\n * // Mobile\n * const service = new StorageService({\n * messenger: storageServiceMessenger,\n * storage: filesystemStorageAdapter, // Platform-specific\n * });\n *\n * // Extension\n * const service = new StorageService({\n * messenger: storageServiceMessenger,\n * storage: indexedDBAdapter, // Platform-specific\n * });\n *\n * // Tests (uses in-memory by default)\n * const service = new StorageService({\n * messenger: storageServiceMessenger,\n * // No storage - uses InMemoryStorageAdapter\n * });\n * ```\n */\nexport class StorageService {\n /**\n * The name of the service.\n */\n readonly name: typeof SERVICE_NAME;\n\n /**\n * The messenger suited for this service.\n */\n readonly #messenger: StorageServiceMessenger;\n\n /**\n * The storage adapter for persisting data.\n */\n readonly #storage: StorageAdapter;\n\n /**\n * Constructs a new StorageService.\n *\n * @param options - The options.\n * @param options.messenger - The messenger suited for this service.\n * @param options.storage - Storage adapter for persisting data.\n * If not provided, uses InMemoryStorageAdapter (data lost on restart).\n */\n constructor({ messenger, storage }: StorageServiceOptions) {\n this.name = SERVICE_NAME;\n this.#messenger = messenger;\n this.#storage = storage ?? new InMemoryStorageAdapter();\n\n // Warn if using in-memory storage (data won't persist)\n if (!storage) {\n console.warn(\n `${SERVICE_NAME}: No storage adapter provided. Using in-memory storage. ` +\n 'Data will be lost on restart. Provide a storage adapter for persistence.',\n );\n }\n\n // Register messenger actions\n this.#messenger.registerActionHandler(\n `${SERVICE_NAME}:setItem`,\n this.setItem.bind(this),\n );\n this.#messenger.registerActionHandler(\n `${SERVICE_NAME}:getItem`,\n this.getItem.bind(this),\n );\n this.#messenger.registerActionHandler(\n `${SERVICE_NAME}:removeItem`,\n this.removeItem.bind(this),\n );\n this.#messenger.registerActionHandler(\n `${SERVICE_NAME}:getAllKeys`,\n this.getAllKeys.bind(this),\n );\n this.#messenger.registerActionHandler(\n `${SERVICE_NAME}:clear`,\n this.clear.bind(this),\n );\n }\n\n /**\n * Store data in storage.\n *\n * @param namespace - Controller namespace (e.g., 'SnapController').\n * @param key - Storage key (e.g., 'npm:@metamask/example-snap:sourceCode').\n * @param value - Data to store (will be JSON stringified).\n * @template T - The type of the value being stored.\n */\n async setItem<T>(namespace: string, key: string, value: T): Promise<void> {\n // Adapter handles serialization and wrapping with metadata\n await this.#storage.setItem(namespace, key, value as never);\n\n // Publish event so other controllers can react to changes\n // Event type: StorageService:itemSet:namespace\n // Payload: [value, key]\n this.#messenger.publish(\n `${SERVICE_NAME}:itemSet:${namespace}` as `${typeof SERVICE_NAME}:itemSet:${string}`,\n value,\n key,\n );\n }\n\n /**\n * Retrieve data from storage.\n *\n * @param namespace - Controller namespace (e.g., 'SnapController').\n * @param key - Storage key (e.g., 'npm:@metamask/example-snap:sourceCode').\n * @returns Parsed data or null if not found.\n * @template T - The type of the value being retrieved.\n */\n async getItem<T>(namespace: string, key: string): Promise<T | null> {\n // Adapter handles deserialization and unwrapping\n const result = await this.#storage.getItem(namespace, key);\n return result as T | null;\n }\n\n /**\n * Remove data from storage.\n *\n * @param namespace - Controller namespace (e.g., 'SnapController').\n * @param key - Storage key (e.g., 'npm:@metamask/example-snap:sourceCode').\n */\n async removeItem(namespace: string, key: string): Promise<void> {\n // Adapter builds full storage key (e.g., mobile: 'storageService:namespace:key')\n await this.#storage.removeItem(namespace, key);\n\n // Publish event so other controllers can react to removal\n // Event type: StorageService:itemRemoved:namespace\n // Payload: [key]\n this.#messenger.publish(\n `${SERVICE_NAME}:itemRemoved:${namespace}` as `${typeof SERVICE_NAME}:itemRemoved:${string}`,\n key,\n );\n }\n\n /**\n * Get all keys for a namespace.\n * Delegates to storage adapter which handles filtering.\n *\n * @param namespace - Controller namespace (e.g., 'SnapController').\n * @returns Array of keys (without prefix) for this namespace.\n */\n async getAllKeys(namespace: string): Promise<string[]> {\n return await this.#storage.getAllKeys(namespace);\n }\n\n /**\n * Clear all data for a namespace.\n * Delegates to storage adapter which handles clearing.\n *\n * @param namespace - Controller namespace (e.g., 'SnapController').\n */\n async clear(namespace: string): Promise<void> {\n await this.#storage.clear(namespace);\n }\n}\n"]}
1
+ {"version":3,"file":"StorageService.cjs","sourceRoot":"","sources":["../src/StorageService.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;AAAA,yEAAkE;AAMlE,uCAAuC;AAEvC,oBAAoB;AAEpB,MAAM,yBAAyB,GAAG;IAChC,SAAS;IACT,SAAS;IACT,YAAY;IACZ,YAAY;IACZ,OAAO;CACC,CAAC;AAEX;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAuEG;AACH,MAAa,cAAc;IAgBzB;;;;;;;OAOG;IACH,YAAY,EAAE,SAAS,EAAE,OAAO,EAAyB;QAlBzD;;WAEG;QACM,4CAAoC;QAE7C;;WAEG;QACM,0CAAyB;QAWhC,IAAI,CAAC,IAAI,GAAG,oBAAY,CAAC;QACzB,uBAAA,IAAI,6BAAc,SAAS,MAAA,CAAC;QAC5B,uBAAA,IAAI,2BAAY,OAAO,IAAI,IAAI,+CAAsB,EAAE,MAAA,CAAC;QAExD,uDAAuD;QACvD,IAAI,CAAC,OAAO,EAAE,CAAC;YACb,OAAO,CAAC,IAAI,CACV,GAAG,oBAAY,0DAA0D;gBACvE,0EAA0E,CAC7E,CAAC;QACJ,CAAC;QAED,6BAA6B;QAC7B,uBAAA,IAAI,iCAAW,CAAC,4BAA4B,CAC1C,IAAI,EACJ,yBAAyB,CAC1B,CAAC;IACJ,CAAC;IAED;;;;;;;;;;;;;;;;;;;;;;OAsBG;IACH,KAAK,CAAC,OAAO,CAAC,SAAiB,EAAE,GAAW,EAAE,KAAc;QAC1D,2DAA2D;QAC3D,MAAM,uBAAA,IAAI,+BAAS,CAAC,OAAO,CAAC,SAAS,EAAE,GAAG,EAAE,KAAK,CAAC,CAAC;QAEnD,0DAA0D;QAC1D,+CAA+C;QAC/C,wBAAwB;QACxB,uBAAA,IAAI,iCAAW,CAAC,OAAO,CACrB,GAAG,oBAAY,YAAY,SAAS,EAAW,EAC/C,KAAK,EACL,GAAG,CACJ,CAAC;IACJ,CAAC;IAED;;;;;;;;;OASG;IACH,KAAK,CAAC,OAAO,CAAC,SAAiB,EAAE,GAAW;QAC1C,iDAAiD;QACjD,OAAO,MAAM,uBAAA,IAAI,+BAAS,CAAC,OAAO,CAAC,SAAS,EAAE,GAAG,CAAC,CAAC;IACrD,CAAC;IAED;;;;;OAKG;IACH,KAAK,CAAC,UAAU,CAAC,SAAiB,EAAE,GAAW;QAC7C,iFAAiF;QACjF,MAAM,uBAAA,IAAI,+BAAS,CAAC,UAAU,CAAC,SAAS,EAAE,GAAG,CAAC,CAAC;IACjD,CAAC;IAED;;;;;;OAMG;IACH,KAAK,CAAC,UAAU,CAAC,SAAiB;QAChC,OAAO,MAAM,uBAAA,IAAI,+BAAS,CAAC,UAAU,CAAC,SAAS,CAAC,CAAC;IACnD,CAAC;IAED;;;;OAIG;IACH,KAAK,CAAC,KAAK,CAAC,SAAiB;QAC3B,MAAM,uBAAA,IAAI,+BAAS,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC;IACvC,CAAC;CACF;AA9HD,wCA8HC","sourcesContent":["import { InMemoryStorageAdapter } from './InMemoryStorageAdapter';\nimport type {\n StorageAdapter,\n StorageServiceMessenger,\n StorageServiceOptions,\n} from './types';\nimport { SERVICE_NAME } from './types';\n\n// === MESSENGER ===\n\nconst MESSENGER_EXPOSED_METHODS = [\n 'setItem',\n 'getItem',\n 'removeItem',\n 'getAllKeys',\n 'clear',\n] as const;\n\n/**\n * StorageService provides a platform-agnostic way for controllers to store\n * large, infrequently accessed data outside of memory/Redux state.\n *\n * **Use cases:**\n * - Snap source code (6+ MB that's rarely accessed)\n * - Token metadata caches (4+ MB of cached data)\n * - Large cached responses from APIs\n * - Any data > 100 KB that's not frequently accessed\n *\n * **Benefits:**\n * - Reduces memory usage (data stays on disk)\n * - Faster Redux persist (less data to serialize)\n * - Faster app startup (less data to parse)\n * - Lazy loading (data loaded only when needed)\n *\n * **Platform Support:**\n * - Mobile: FilesystemStorage adapter\n * - Extension: IndexedDB adapter\n * - Tests/Dev: InMemoryStorageAdapter (default)\n *\n * @example Using the service via messenger\n *\n * ```typescript\n * // In a controller\n * type AllowedActions =\n * | StorageServiceSetItemAction\n * | StorageServiceGetItemAction;\n *\n * class SnapController extends BaseController {\n * async storeSnapSourceCode(snapId: string, sourceCode: string) {\n * await this.messenger.call(\n * 'StorageService:setItem',\n * 'SnapController',\n * `${snapId}:sourceCode`,\n * sourceCode,\n * );\n * }\n *\n * async getSnapSourceCode(snapId: string): Promise<string | null> {\n * const result = await this.messenger.call(\n * 'StorageService:getItem',\n * 'SnapController',\n * `${snapId}:sourceCode`,\n * );\n * return result as string | null; // Caller must validate/cast\n * }\n * }\n * ```\n *\n * @example Initializing in a client\n *\n * ```typescript\n * // Mobile\n * const service = new StorageService({\n * messenger: storageServiceMessenger,\n * storage: filesystemStorageAdapter, // Platform-specific\n * });\n *\n * // Extension\n * const service = new StorageService({\n * messenger: storageServiceMessenger,\n * storage: indexedDBAdapter, // Platform-specific\n * });\n *\n * // Tests (uses in-memory by default)\n * const service = new StorageService({\n * messenger: storageServiceMessenger,\n * // No storage - uses InMemoryStorageAdapter\n * });\n * ```\n */\nexport class StorageService {\n /**\n * The name of the service.\n */\n readonly name: typeof SERVICE_NAME;\n\n /**\n * The messenger suited for this service.\n */\n readonly #messenger: StorageServiceMessenger;\n\n /**\n * The storage adapter for persisting data.\n */\n readonly #storage: StorageAdapter;\n\n /**\n * Constructs a new StorageService.\n *\n * @param options - The options.\n * @param options.messenger - The messenger suited for this service.\n * @param options.storage - Storage adapter for persisting data.\n * If not provided, uses InMemoryStorageAdapter (data lost on restart).\n */\n constructor({ messenger, storage }: StorageServiceOptions) {\n this.name = SERVICE_NAME;\n this.#messenger = messenger;\n this.#storage = storage ?? new InMemoryStorageAdapter();\n\n // Warn if using in-memory storage (data won't persist)\n if (!storage) {\n console.warn(\n `${SERVICE_NAME}: No storage adapter provided. Using in-memory storage. ` +\n 'Data will be lost on restart. Provide a storage adapter for persistence.',\n );\n }\n\n // Register messenger actions\n this.#messenger.registerMethodActionHandlers(\n this,\n MESSENGER_EXPOSED_METHODS,\n );\n }\n\n /**\n * Store large data in storage.\n *\n * ⚠️ **Designed for large values (100KB+), not many small ones.**\n * Each storage operation has I/O overhead. For best performance,\n * store one large object rather than many small key-value pairs.\n *\n * @example Good: Store entire cache as one value\n * ```typescript\n * await service.setItem('TokenList', 'cache', { '0x1': [...], '0x38': [...] });\n * ```\n *\n * @example Avoid: Many small values\n * ```typescript\n * // ❌ Don't do this - too many small writes\n * await service.setItem('TokenList', 'cache:0x1', [...]);\n * await service.setItem('TokenList', 'cache:0x38', [...]);\n * ```\n *\n * @param namespace - Controller namespace (e.g., 'SnapController').\n * @param key - Storage key (e.g., 'npm:@metamask/example-snap:sourceCode').\n * @param value - Data to store (should be 100KB+ for optimal use).\n */\n async setItem(namespace: string, key: string, value: unknown): Promise<void> {\n // Adapter handles serialization and wrapping with metadata\n await this.#storage.setItem(namespace, key, value);\n\n // Publish event so other controllers can react to changes\n // Event type: StorageService:itemSet:namespace\n // Payload: [value, key]\n this.#messenger.publish(\n `${SERVICE_NAME}:itemSet:${namespace}` as const,\n value,\n key,\n );\n }\n\n /**\n * Retrieve data from storage.\n *\n * Returns `unknown` since there's no schema validation.\n * Callers should validate or cast the result to the expected type.\n *\n * @param namespace - Controller namespace (e.g., 'SnapController').\n * @param key - Storage key (e.g., 'npm:@metamask/example-snap:sourceCode').\n * @returns Parsed data or null if not found. Type is `unknown` - caller must validate.\n */\n async getItem(namespace: string, key: string): Promise<unknown> {\n // Adapter handles deserialization and unwrapping\n return await this.#storage.getItem(namespace, key);\n }\n\n /**\n * Remove data from storage.\n *\n * @param namespace - Controller namespace (e.g., 'SnapController').\n * @param key - Storage key (e.g., 'npm:@metamask/example-snap:sourceCode').\n */\n async removeItem(namespace: string, key: string): Promise<void> {\n // Adapter builds full storage key (e.g., mobile: 'storageService:namespace:key')\n await this.#storage.removeItem(namespace, key);\n }\n\n /**\n * Get all keys for a namespace.\n * Delegates to storage adapter which handles filtering.\n *\n * @param namespace - Controller namespace (e.g., 'SnapController').\n * @returns Array of keys (without prefix) for this namespace.\n */\n async getAllKeys(namespace: string): Promise<string[]> {\n return await this.#storage.getAllKeys(namespace);\n }\n\n /**\n * Clear all data for a namespace.\n *\n * @param namespace - Controller namespace (e.g., 'SnapController').\n */\n async clear(namespace: string): Promise<void> {\n await this.#storage.clear(namespace);\n }\n}\n"]}
@@ -40,11 +40,12 @@ import { SERVICE_NAME } from "./types.cjs";
40
40
  * }
41
41
  *
42
42
  * async getSnapSourceCode(snapId: string): Promise<string | null> {
43
- * return await this.messenger.call(
43
+ * const result = await this.messenger.call(
44
44
  * 'StorageService:getItem',
45
45
  * 'SnapController',
46
46
  * `${snapId}:sourceCode`,
47
47
  * );
48
+ * return result as string | null; // Caller must validate/cast
48
49
  * }
49
50
  * }
50
51
  * ```
@@ -87,23 +88,40 @@ export declare class StorageService {
87
88
  */
88
89
  constructor({ messenger, storage }: StorageServiceOptions);
89
90
  /**
90
- * Store data in storage.
91
+ * Store large data in storage.
92
+ *
93
+ * ⚠️ **Designed for large values (100KB+), not many small ones.**
94
+ * Each storage operation has I/O overhead. For best performance,
95
+ * store one large object rather than many small key-value pairs.
96
+ *
97
+ * @example Good: Store entire cache as one value
98
+ * ```typescript
99
+ * await service.setItem('TokenList', 'cache', { '0x1': [...], '0x38': [...] });
100
+ * ```
101
+ *
102
+ * @example Avoid: Many small values
103
+ * ```typescript
104
+ * // ❌ Don't do this - too many small writes
105
+ * await service.setItem('TokenList', 'cache:0x1', [...]);
106
+ * await service.setItem('TokenList', 'cache:0x38', [...]);
107
+ * ```
91
108
  *
92
109
  * @param namespace - Controller namespace (e.g., 'SnapController').
93
110
  * @param key - Storage key (e.g., 'npm:@metamask/example-snap:sourceCode').
94
- * @param value - Data to store (will be JSON stringified).
95
- * @template T - The type of the value being stored.
111
+ * @param value - Data to store (should be 100KB+ for optimal use).
96
112
  */
97
- setItem<T>(namespace: string, key: string, value: T): Promise<void>;
113
+ setItem(namespace: string, key: string, value: unknown): Promise<void>;
98
114
  /**
99
115
  * Retrieve data from storage.
100
116
  *
117
+ * Returns `unknown` since there's no schema validation.
118
+ * Callers should validate or cast the result to the expected type.
119
+ *
101
120
  * @param namespace - Controller namespace (e.g., 'SnapController').
102
121
  * @param key - Storage key (e.g., 'npm:@metamask/example-snap:sourceCode').
103
- * @returns Parsed data or null if not found.
104
- * @template T - The type of the value being retrieved.
122
+ * @returns Parsed data or null if not found. Type is `unknown` - caller must validate.
105
123
  */
106
- getItem<T>(namespace: string, key: string): Promise<T | null>;
124
+ getItem(namespace: string, key: string): Promise<unknown>;
107
125
  /**
108
126
  * Remove data from storage.
109
127
  *
@@ -121,7 +139,6 @@ export declare class StorageService {
121
139
  getAllKeys(namespace: string): Promise<string[]>;
122
140
  /**
123
141
  * Clear all data for a namespace.
124
- * Delegates to storage adapter which handles clearing.
125
142
  *
126
143
  * @param namespace - Controller namespace (e.g., 'SnapController').
127
144
  */
@@ -1 +1 @@
1
- {"version":3,"file":"StorageService.d.cts","sourceRoot":"","sources":["../src/StorageService.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAGV,qBAAqB,EACtB,oBAAgB;AACjB,OAAO,EAAE,YAAY,EAAE,oBAAgB;AAEvC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsEG;AACH,qBAAa,cAAc;;IACzB;;OAEG;IACH,QAAQ,CAAC,IAAI,EAAE,OAAO,YAAY,CAAC;IAYnC;;;;;;;OAOG;gBACS,EAAE,SAAS,EAAE,OAAO,EAAE,EAAE,qBAAqB;IAoCzD;;;;;;;OAOG;IACG,OAAO,CAAC,CAAC,EAAE,SAAS,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC;IAczE;;;;;;;OAOG;IACG,OAAO,CAAC,CAAC,EAAE,SAAS,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,CAAC,GAAG,IAAI,CAAC;IAMnE;;;;;OAKG;IACG,UAAU,CAAC,SAAS,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAa/D;;;;;;OAMG;IACG,UAAU,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC;IAItD;;;;;OAKG;IACG,KAAK,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;CAG9C"}
1
+ {"version":3,"file":"StorageService.d.cts","sourceRoot":"","sources":["../src/StorageService.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAGV,qBAAqB,EACtB,oBAAgB;AACjB,OAAO,EAAE,YAAY,EAAE,oBAAgB;AAYvC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAuEG;AACH,qBAAa,cAAc;;IACzB;;OAEG;IACH,QAAQ,CAAC,IAAI,EAAE,OAAO,YAAY,CAAC;IAYnC;;;;;;;OAOG;gBACS,EAAE,SAAS,EAAE,OAAO,EAAE,EAAE,qBAAqB;IAoBzD;;;;;;;;;;;;;;;;;;;;;;OAsBG;IACG,OAAO,CAAC,SAAS,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC;IAc5E;;;;;;;;;OASG;IACG,OAAO,CAAC,SAAS,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAK/D;;;;;OAKG;IACG,UAAU,CAAC,SAAS,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAK/D;;;;;;OAMG;IACG,UAAU,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC;IAItD;;;;OAIG;IACG,KAAK,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;CAG9C"}
@@ -40,11 +40,12 @@ import { SERVICE_NAME } from "./types.mjs";
40
40
  * }
41
41
  *
42
42
  * async getSnapSourceCode(snapId: string): Promise<string | null> {
43
- * return await this.messenger.call(
43
+ * const result = await this.messenger.call(
44
44
  * 'StorageService:getItem',
45
45
  * 'SnapController',
46
46
  * `${snapId}:sourceCode`,
47
47
  * );
48
+ * return result as string | null; // Caller must validate/cast
48
49
  * }
49
50
  * }
50
51
  * ```
@@ -87,23 +88,40 @@ export declare class StorageService {
87
88
  */
88
89
  constructor({ messenger, storage }: StorageServiceOptions);
89
90
  /**
90
- * Store data in storage.
91
+ * Store large data in storage.
92
+ *
93
+ * ⚠️ **Designed for large values (100KB+), not many small ones.**
94
+ * Each storage operation has I/O overhead. For best performance,
95
+ * store one large object rather than many small key-value pairs.
96
+ *
97
+ * @example Good: Store entire cache as one value
98
+ * ```typescript
99
+ * await service.setItem('TokenList', 'cache', { '0x1': [...], '0x38': [...] });
100
+ * ```
101
+ *
102
+ * @example Avoid: Many small values
103
+ * ```typescript
104
+ * // ❌ Don't do this - too many small writes
105
+ * await service.setItem('TokenList', 'cache:0x1', [...]);
106
+ * await service.setItem('TokenList', 'cache:0x38', [...]);
107
+ * ```
91
108
  *
92
109
  * @param namespace - Controller namespace (e.g., 'SnapController').
93
110
  * @param key - Storage key (e.g., 'npm:@metamask/example-snap:sourceCode').
94
- * @param value - Data to store (will be JSON stringified).
95
- * @template T - The type of the value being stored.
111
+ * @param value - Data to store (should be 100KB+ for optimal use).
96
112
  */
97
- setItem<T>(namespace: string, key: string, value: T): Promise<void>;
113
+ setItem(namespace: string, key: string, value: unknown): Promise<void>;
98
114
  /**
99
115
  * Retrieve data from storage.
100
116
  *
117
+ * Returns `unknown` since there's no schema validation.
118
+ * Callers should validate or cast the result to the expected type.
119
+ *
101
120
  * @param namespace - Controller namespace (e.g., 'SnapController').
102
121
  * @param key - Storage key (e.g., 'npm:@metamask/example-snap:sourceCode').
103
- * @returns Parsed data or null if not found.
104
- * @template T - The type of the value being retrieved.
122
+ * @returns Parsed data or null if not found. Type is `unknown` - caller must validate.
105
123
  */
106
- getItem<T>(namespace: string, key: string): Promise<T | null>;
124
+ getItem(namespace: string, key: string): Promise<unknown>;
107
125
  /**
108
126
  * Remove data from storage.
109
127
  *
@@ -121,7 +139,6 @@ export declare class StorageService {
121
139
  getAllKeys(namespace: string): Promise<string[]>;
122
140
  /**
123
141
  * Clear all data for a namespace.
124
- * Delegates to storage adapter which handles clearing.
125
142
  *
126
143
  * @param namespace - Controller namespace (e.g., 'SnapController').
127
144
  */
@@ -1 +1 @@
1
- {"version":3,"file":"StorageService.d.mts","sourceRoot":"","sources":["../src/StorageService.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAGV,qBAAqB,EACtB,oBAAgB;AACjB,OAAO,EAAE,YAAY,EAAE,oBAAgB;AAEvC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsEG;AACH,qBAAa,cAAc;;IACzB;;OAEG;IACH,QAAQ,CAAC,IAAI,EAAE,OAAO,YAAY,CAAC;IAYnC;;;;;;;OAOG;gBACS,EAAE,SAAS,EAAE,OAAO,EAAE,EAAE,qBAAqB;IAoCzD;;;;;;;OAOG;IACG,OAAO,CAAC,CAAC,EAAE,SAAS,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC;IAczE;;;;;;;OAOG;IACG,OAAO,CAAC,CAAC,EAAE,SAAS,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,CAAC,GAAG,IAAI,CAAC;IAMnE;;;;;OAKG;IACG,UAAU,CAAC,SAAS,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAa/D;;;;;;OAMG;IACG,UAAU,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC;IAItD;;;;;OAKG;IACG,KAAK,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;CAG9C"}
1
+ {"version":3,"file":"StorageService.d.mts","sourceRoot":"","sources":["../src/StorageService.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAGV,qBAAqB,EACtB,oBAAgB;AACjB,OAAO,EAAE,YAAY,EAAE,oBAAgB;AAYvC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAuEG;AACH,qBAAa,cAAc;;IACzB;;OAEG;IACH,QAAQ,CAAC,IAAI,EAAE,OAAO,YAAY,CAAC;IAYnC;;;;;;;OAOG;gBACS,EAAE,SAAS,EAAE,OAAO,EAAE,EAAE,qBAAqB;IAoBzD;;;;;;;;;;;;;;;;;;;;;;OAsBG;IACG,OAAO,CAAC,SAAS,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC;IAc5E;;;;;;;;;OASG;IACG,OAAO,CAAC,SAAS,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAK/D;;;;;OAKG;IACG,UAAU,CAAC,SAAS,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAK/D;;;;;;OAMG;IACG,UAAU,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC;IAItD;;;;OAIG;IACG,KAAK,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;CAG9C"}
@@ -12,6 +12,14 @@ var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (
12
12
  var _StorageService_messenger, _StorageService_storage;
13
13
  import { InMemoryStorageAdapter } from "./InMemoryStorageAdapter.mjs";
14
14
  import { SERVICE_NAME } from "./types.mjs";
15
+ // === MESSENGER ===
16
+ const MESSENGER_EXPOSED_METHODS = [
17
+ 'setItem',
18
+ 'getItem',
19
+ 'removeItem',
20
+ 'getAllKeys',
21
+ 'clear',
22
+ ];
15
23
  /**
16
24
  * StorageService provides a platform-agnostic way for controllers to store
17
25
  * large, infrequently accessed data outside of memory/Redux state.
@@ -52,11 +60,12 @@ import { SERVICE_NAME } from "./types.mjs";
52
60
  * }
53
61
  *
54
62
  * async getSnapSourceCode(snapId: string): Promise<string | null> {
55
- * return await this.messenger.call(
63
+ * const result = await this.messenger.call(
56
64
  * 'StorageService:getItem',
57
65
  * 'SnapController',
58
66
  * `${snapId}:sourceCode`,
59
67
  * );
68
+ * return result as string | null; // Caller must validate/cast
60
69
  * }
61
70
  * }
62
71
  * ```
@@ -110,19 +119,30 @@ export class StorageService {
110
119
  'Data will be lost on restart. Provide a storage adapter for persistence.');
111
120
  }
112
121
  // Register messenger actions
113
- __classPrivateFieldGet(this, _StorageService_messenger, "f").registerActionHandler(`${SERVICE_NAME}:setItem`, this.setItem.bind(this));
114
- __classPrivateFieldGet(this, _StorageService_messenger, "f").registerActionHandler(`${SERVICE_NAME}:getItem`, this.getItem.bind(this));
115
- __classPrivateFieldGet(this, _StorageService_messenger, "f").registerActionHandler(`${SERVICE_NAME}:removeItem`, this.removeItem.bind(this));
116
- __classPrivateFieldGet(this, _StorageService_messenger, "f").registerActionHandler(`${SERVICE_NAME}:getAllKeys`, this.getAllKeys.bind(this));
117
- __classPrivateFieldGet(this, _StorageService_messenger, "f").registerActionHandler(`${SERVICE_NAME}:clear`, this.clear.bind(this));
122
+ __classPrivateFieldGet(this, _StorageService_messenger, "f").registerMethodActionHandlers(this, MESSENGER_EXPOSED_METHODS);
118
123
  }
119
124
  /**
120
- * Store data in storage.
125
+ * Store large data in storage.
126
+ *
127
+ * ⚠️ **Designed for large values (100KB+), not many small ones.**
128
+ * Each storage operation has I/O overhead. For best performance,
129
+ * store one large object rather than many small key-value pairs.
130
+ *
131
+ * @example Good: Store entire cache as one value
132
+ * ```typescript
133
+ * await service.setItem('TokenList', 'cache', { '0x1': [...], '0x38': [...] });
134
+ * ```
135
+ *
136
+ * @example Avoid: Many small values
137
+ * ```typescript
138
+ * // ❌ Don't do this - too many small writes
139
+ * await service.setItem('TokenList', 'cache:0x1', [...]);
140
+ * await service.setItem('TokenList', 'cache:0x38', [...]);
141
+ * ```
121
142
  *
122
143
  * @param namespace - Controller namespace (e.g., 'SnapController').
123
144
  * @param key - Storage key (e.g., 'npm:@metamask/example-snap:sourceCode').
124
- * @param value - Data to store (will be JSON stringified).
125
- * @template T - The type of the value being stored.
145
+ * @param value - Data to store (should be 100KB+ for optimal use).
126
146
  */
127
147
  async setItem(namespace, key, value) {
128
148
  // Adapter handles serialization and wrapping with metadata
@@ -135,15 +155,16 @@ export class StorageService {
135
155
  /**
136
156
  * Retrieve data from storage.
137
157
  *
158
+ * Returns `unknown` since there's no schema validation.
159
+ * Callers should validate or cast the result to the expected type.
160
+ *
138
161
  * @param namespace - Controller namespace (e.g., 'SnapController').
139
162
  * @param key - Storage key (e.g., 'npm:@metamask/example-snap:sourceCode').
140
- * @returns Parsed data or null if not found.
141
- * @template T - The type of the value being retrieved.
163
+ * @returns Parsed data or null if not found. Type is `unknown` - caller must validate.
142
164
  */
143
165
  async getItem(namespace, key) {
144
166
  // Adapter handles deserialization and unwrapping
145
- const result = await __classPrivateFieldGet(this, _StorageService_storage, "f").getItem(namespace, key);
146
- return result;
167
+ return await __classPrivateFieldGet(this, _StorageService_storage, "f").getItem(namespace, key);
147
168
  }
148
169
  /**
149
170
  * Remove data from storage.
@@ -154,10 +175,6 @@ export class StorageService {
154
175
  async removeItem(namespace, key) {
155
176
  // Adapter builds full storage key (e.g., mobile: 'storageService:namespace:key')
156
177
  await __classPrivateFieldGet(this, _StorageService_storage, "f").removeItem(namespace, key);
157
- // Publish event so other controllers can react to removal
158
- // Event type: StorageService:itemRemoved:namespace
159
- // Payload: [key]
160
- __classPrivateFieldGet(this, _StorageService_messenger, "f").publish(`${SERVICE_NAME}:itemRemoved:${namespace}`, key);
161
178
  }
162
179
  /**
163
180
  * Get all keys for a namespace.
@@ -171,7 +188,6 @@ export class StorageService {
171
188
  }
172
189
  /**
173
190
  * Clear all data for a namespace.
174
- * Delegates to storage adapter which handles clearing.
175
191
  *
176
192
  * @param namespace - Controller namespace (e.g., 'SnapController').
177
193
  */