@metamask-previews/storage-service 1.0.0-preview-e493d3e8 → 1.0.0-preview-f5c5aecd

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,130 @@
1
+ import type { StorageServiceOptions } from "./types.cjs";
2
+ import { SERVICE_NAME } from "./types.cjs";
3
+ /**
4
+ * StorageService provides a platform-agnostic way for controllers to store
5
+ * large, infrequently accessed data outside of memory/Redux state.
6
+ *
7
+ * **Use cases:**
8
+ * - Snap source code (6+ MB that's rarely accessed)
9
+ * - Token metadata caches (4+ MB of cached data)
10
+ * - Large cached responses from APIs
11
+ * - Any data > 100 KB that's not frequently accessed
12
+ *
13
+ * **Benefits:**
14
+ * - Reduces memory usage (data stays on disk)
15
+ * - Faster Redux persist (less data to serialize)
16
+ * - Faster app startup (less data to parse)
17
+ * - Lazy loading (data loaded only when needed)
18
+ *
19
+ * **Platform Support:**
20
+ * - Mobile: FilesystemStorage adapter
21
+ * - Extension: IndexedDB adapter
22
+ * - Tests/Dev: InMemoryStorageAdapter (default)
23
+ *
24
+ * @example Using the service via messenger
25
+ *
26
+ * ```typescript
27
+ * // In a controller
28
+ * type AllowedActions =
29
+ * | StorageServiceSetItemAction
30
+ * | StorageServiceGetItemAction;
31
+ *
32
+ * class SnapController extends BaseController {
33
+ * async storeSnapSourceCode(snapId: string, sourceCode: string) {
34
+ * await this.messenger.call(
35
+ * 'StorageService:setItem',
36
+ * 'SnapController',
37
+ * `${snapId}:sourceCode`,
38
+ * sourceCode,
39
+ * );
40
+ * }
41
+ *
42
+ * async getSnapSourceCode(snapId: string): Promise<string | null> {
43
+ * return await this.messenger.call(
44
+ * 'StorageService:getItem',
45
+ * 'SnapController',
46
+ * `${snapId}:sourceCode`,
47
+ * );
48
+ * }
49
+ * }
50
+ * ```
51
+ *
52
+ * @example Initializing in a client
53
+ *
54
+ * ```typescript
55
+ * // Mobile
56
+ * const service = new StorageService({
57
+ * messenger: storageServiceMessenger,
58
+ * storage: filesystemStorageAdapter, // Platform-specific
59
+ * });
60
+ *
61
+ * // Extension
62
+ * const service = new StorageService({
63
+ * messenger: storageServiceMessenger,
64
+ * storage: indexedDBAdapter, // Platform-specific
65
+ * });
66
+ *
67
+ * // Tests (uses in-memory by default)
68
+ * const service = new StorageService({
69
+ * messenger: storageServiceMessenger,
70
+ * // No storage - uses InMemoryStorageAdapter
71
+ * });
72
+ * ```
73
+ */
74
+ export declare class StorageService {
75
+ #private;
76
+ /**
77
+ * The name of the service.
78
+ */
79
+ readonly name: typeof SERVICE_NAME;
80
+ /**
81
+ * Constructs a new StorageService.
82
+ *
83
+ * @param options - The options.
84
+ * @param options.messenger - The messenger suited for this service.
85
+ * @param options.storage - Storage adapter for persisting data.
86
+ * If not provided, uses InMemoryStorageAdapter (data lost on restart).
87
+ */
88
+ constructor({ messenger, storage }: StorageServiceOptions);
89
+ /**
90
+ * Store data in storage.
91
+ *
92
+ * @param namespace - Controller namespace (e.g., 'SnapController').
93
+ * @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.
96
+ */
97
+ setItem<T>(namespace: string, key: string, value: T): Promise<void>;
98
+ /**
99
+ * Retrieve data from storage.
100
+ *
101
+ * @param namespace - Controller namespace (e.g., 'SnapController').
102
+ * @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.
105
+ */
106
+ getItem<T>(namespace: string, key: string): Promise<T | null>;
107
+ /**
108
+ * Remove data from storage.
109
+ *
110
+ * @param namespace - Controller namespace (e.g., 'SnapController').
111
+ * @param key - Storage key (e.g., 'npm:@metamask/example-snap:sourceCode').
112
+ */
113
+ removeItem(namespace: string, key: string): Promise<void>;
114
+ /**
115
+ * Get all keys for a namespace.
116
+ * Delegates to storage adapter which handles filtering.
117
+ *
118
+ * @param namespace - Controller namespace (e.g., 'SnapController').
119
+ * @returns Array of keys (without prefix) for this namespace.
120
+ */
121
+ getAllKeys(namespace: string): Promise<string[]>;
122
+ /**
123
+ * Clear all data for a namespace.
124
+ * Delegates to storage adapter which handles clearing.
125
+ *
126
+ * @param namespace - Controller namespace (e.g., 'SnapController').
127
+ */
128
+ clear(namespace: string): Promise<void>;
129
+ }
130
+ //# sourceMappingURL=StorageService.d.cts.map
@@ -0,0 +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"}
@@ -0,0 +1,130 @@
1
+ import type { StorageServiceOptions } from "./types.mjs";
2
+ import { SERVICE_NAME } from "./types.mjs";
3
+ /**
4
+ * StorageService provides a platform-agnostic way for controllers to store
5
+ * large, infrequently accessed data outside of memory/Redux state.
6
+ *
7
+ * **Use cases:**
8
+ * - Snap source code (6+ MB that's rarely accessed)
9
+ * - Token metadata caches (4+ MB of cached data)
10
+ * - Large cached responses from APIs
11
+ * - Any data > 100 KB that's not frequently accessed
12
+ *
13
+ * **Benefits:**
14
+ * - Reduces memory usage (data stays on disk)
15
+ * - Faster Redux persist (less data to serialize)
16
+ * - Faster app startup (less data to parse)
17
+ * - Lazy loading (data loaded only when needed)
18
+ *
19
+ * **Platform Support:**
20
+ * - Mobile: FilesystemStorage adapter
21
+ * - Extension: IndexedDB adapter
22
+ * - Tests/Dev: InMemoryStorageAdapter (default)
23
+ *
24
+ * @example Using the service via messenger
25
+ *
26
+ * ```typescript
27
+ * // In a controller
28
+ * type AllowedActions =
29
+ * | StorageServiceSetItemAction
30
+ * | StorageServiceGetItemAction;
31
+ *
32
+ * class SnapController extends BaseController {
33
+ * async storeSnapSourceCode(snapId: string, sourceCode: string) {
34
+ * await this.messenger.call(
35
+ * 'StorageService:setItem',
36
+ * 'SnapController',
37
+ * `${snapId}:sourceCode`,
38
+ * sourceCode,
39
+ * );
40
+ * }
41
+ *
42
+ * async getSnapSourceCode(snapId: string): Promise<string | null> {
43
+ * return await this.messenger.call(
44
+ * 'StorageService:getItem',
45
+ * 'SnapController',
46
+ * `${snapId}:sourceCode`,
47
+ * );
48
+ * }
49
+ * }
50
+ * ```
51
+ *
52
+ * @example Initializing in a client
53
+ *
54
+ * ```typescript
55
+ * // Mobile
56
+ * const service = new StorageService({
57
+ * messenger: storageServiceMessenger,
58
+ * storage: filesystemStorageAdapter, // Platform-specific
59
+ * });
60
+ *
61
+ * // Extension
62
+ * const service = new StorageService({
63
+ * messenger: storageServiceMessenger,
64
+ * storage: indexedDBAdapter, // Platform-specific
65
+ * });
66
+ *
67
+ * // Tests (uses in-memory by default)
68
+ * const service = new StorageService({
69
+ * messenger: storageServiceMessenger,
70
+ * // No storage - uses InMemoryStorageAdapter
71
+ * });
72
+ * ```
73
+ */
74
+ export declare class StorageService {
75
+ #private;
76
+ /**
77
+ * The name of the service.
78
+ */
79
+ readonly name: typeof SERVICE_NAME;
80
+ /**
81
+ * Constructs a new StorageService.
82
+ *
83
+ * @param options - The options.
84
+ * @param options.messenger - The messenger suited for this service.
85
+ * @param options.storage - Storage adapter for persisting data.
86
+ * If not provided, uses InMemoryStorageAdapter (data lost on restart).
87
+ */
88
+ constructor({ messenger, storage }: StorageServiceOptions);
89
+ /**
90
+ * Store data in storage.
91
+ *
92
+ * @param namespace - Controller namespace (e.g., 'SnapController').
93
+ * @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.
96
+ */
97
+ setItem<T>(namespace: string, key: string, value: T): Promise<void>;
98
+ /**
99
+ * Retrieve data from storage.
100
+ *
101
+ * @param namespace - Controller namespace (e.g., 'SnapController').
102
+ * @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.
105
+ */
106
+ getItem<T>(namespace: string, key: string): Promise<T | null>;
107
+ /**
108
+ * Remove data from storage.
109
+ *
110
+ * @param namespace - Controller namespace (e.g., 'SnapController').
111
+ * @param key - Storage key (e.g., 'npm:@metamask/example-snap:sourceCode').
112
+ */
113
+ removeItem(namespace: string, key: string): Promise<void>;
114
+ /**
115
+ * Get all keys for a namespace.
116
+ * Delegates to storage adapter which handles filtering.
117
+ *
118
+ * @param namespace - Controller namespace (e.g., 'SnapController').
119
+ * @returns Array of keys (without prefix) for this namespace.
120
+ */
121
+ getAllKeys(namespace: string): Promise<string[]>;
122
+ /**
123
+ * Clear all data for a namespace.
124
+ * Delegates to storage adapter which handles clearing.
125
+ *
126
+ * @param namespace - Controller namespace (e.g., 'SnapController').
127
+ */
128
+ clear(namespace: string): Promise<void>;
129
+ }
130
+ //# sourceMappingURL=StorageService.d.mts.map
@@ -0,0 +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"}
@@ -0,0 +1,183 @@
1
+ var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) {
2
+ if (kind === "m") throw new TypeError("Private method is not writable");
3
+ if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
4
+ if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it");
5
+ return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
6
+ };
7
+ var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
8
+ if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
9
+ if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
10
+ return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
11
+ };
12
+ var _StorageService_messenger, _StorageService_storage;
13
+ import { InMemoryStorageAdapter } from "./InMemoryStorageAdapter.mjs";
14
+ import { SERVICE_NAME } from "./types.mjs";
15
+ /**
16
+ * StorageService provides a platform-agnostic way for controllers to store
17
+ * large, infrequently accessed data outside of memory/Redux state.
18
+ *
19
+ * **Use cases:**
20
+ * - Snap source code (6+ MB that's rarely accessed)
21
+ * - Token metadata caches (4+ MB of cached data)
22
+ * - Large cached responses from APIs
23
+ * - Any data > 100 KB that's not frequently accessed
24
+ *
25
+ * **Benefits:**
26
+ * - Reduces memory usage (data stays on disk)
27
+ * - Faster Redux persist (less data to serialize)
28
+ * - Faster app startup (less data to parse)
29
+ * - Lazy loading (data loaded only when needed)
30
+ *
31
+ * **Platform Support:**
32
+ * - Mobile: FilesystemStorage adapter
33
+ * - Extension: IndexedDB adapter
34
+ * - Tests/Dev: InMemoryStorageAdapter (default)
35
+ *
36
+ * @example Using the service via messenger
37
+ *
38
+ * ```typescript
39
+ * // In a controller
40
+ * type AllowedActions =
41
+ * | StorageServiceSetItemAction
42
+ * | StorageServiceGetItemAction;
43
+ *
44
+ * class SnapController extends BaseController {
45
+ * async storeSnapSourceCode(snapId: string, sourceCode: string) {
46
+ * await this.messenger.call(
47
+ * 'StorageService:setItem',
48
+ * 'SnapController',
49
+ * `${snapId}:sourceCode`,
50
+ * sourceCode,
51
+ * );
52
+ * }
53
+ *
54
+ * async getSnapSourceCode(snapId: string): Promise<string | null> {
55
+ * return await this.messenger.call(
56
+ * 'StorageService:getItem',
57
+ * 'SnapController',
58
+ * `${snapId}:sourceCode`,
59
+ * );
60
+ * }
61
+ * }
62
+ * ```
63
+ *
64
+ * @example Initializing in a client
65
+ *
66
+ * ```typescript
67
+ * // Mobile
68
+ * const service = new StorageService({
69
+ * messenger: storageServiceMessenger,
70
+ * storage: filesystemStorageAdapter, // Platform-specific
71
+ * });
72
+ *
73
+ * // Extension
74
+ * const service = new StorageService({
75
+ * messenger: storageServiceMessenger,
76
+ * storage: indexedDBAdapter, // Platform-specific
77
+ * });
78
+ *
79
+ * // Tests (uses in-memory by default)
80
+ * const service = new StorageService({
81
+ * messenger: storageServiceMessenger,
82
+ * // No storage - uses InMemoryStorageAdapter
83
+ * });
84
+ * ```
85
+ */
86
+ export class StorageService {
87
+ /**
88
+ * Constructs a new StorageService.
89
+ *
90
+ * @param options - The options.
91
+ * @param options.messenger - The messenger suited for this service.
92
+ * @param options.storage - Storage adapter for persisting data.
93
+ * If not provided, uses InMemoryStorageAdapter (data lost on restart).
94
+ */
95
+ constructor({ messenger, storage }) {
96
+ /**
97
+ * The messenger suited for this service.
98
+ */
99
+ _StorageService_messenger.set(this, void 0);
100
+ /**
101
+ * The storage adapter for persisting data.
102
+ */
103
+ _StorageService_storage.set(this, void 0);
104
+ this.name = SERVICE_NAME;
105
+ __classPrivateFieldSet(this, _StorageService_messenger, messenger, "f");
106
+ __classPrivateFieldSet(this, _StorageService_storage, storage ?? new InMemoryStorageAdapter(), "f");
107
+ // Warn if using in-memory storage (data won't persist)
108
+ if (!storage) {
109
+ console.warn(`${SERVICE_NAME}: No storage adapter provided. Using in-memory storage. ` +
110
+ 'Data will be lost on restart. Provide a storage adapter for persistence.');
111
+ }
112
+ // 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));
118
+ }
119
+ /**
120
+ * Store data in storage.
121
+ *
122
+ * @param namespace - Controller namespace (e.g., 'SnapController').
123
+ * @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.
126
+ */
127
+ async setItem(namespace, key, value) {
128
+ // Adapter handles serialization and wrapping with metadata
129
+ await __classPrivateFieldGet(this, _StorageService_storage, "f").setItem(namespace, key, value);
130
+ // Publish event so other controllers can react to changes
131
+ // Event type: StorageService:itemSet:namespace
132
+ // Payload: [value, key]
133
+ __classPrivateFieldGet(this, _StorageService_messenger, "f").publish(`${SERVICE_NAME}:itemSet:${namespace}`, value, key);
134
+ }
135
+ /**
136
+ * Retrieve data from storage.
137
+ *
138
+ * @param namespace - Controller namespace (e.g., 'SnapController').
139
+ * @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.
142
+ */
143
+ async getItem(namespace, key) {
144
+ // Adapter handles deserialization and unwrapping
145
+ const result = await __classPrivateFieldGet(this, _StorageService_storage, "f").getItem(namespace, key);
146
+ return result;
147
+ }
148
+ /**
149
+ * Remove data from storage.
150
+ *
151
+ * @param namespace - Controller namespace (e.g., 'SnapController').
152
+ * @param key - Storage key (e.g., 'npm:@metamask/example-snap:sourceCode').
153
+ */
154
+ async removeItem(namespace, key) {
155
+ // Adapter builds full storage key (e.g., mobile: 'storageService:namespace:key')
156
+ 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
+ }
162
+ /**
163
+ * Get all keys for a namespace.
164
+ * Delegates to storage adapter which handles filtering.
165
+ *
166
+ * @param namespace - Controller namespace (e.g., 'SnapController').
167
+ * @returns Array of keys (without prefix) for this namespace.
168
+ */
169
+ async getAllKeys(namespace) {
170
+ return await __classPrivateFieldGet(this, _StorageService_storage, "f").getAllKeys(namespace);
171
+ }
172
+ /**
173
+ * Clear all data for a namespace.
174
+ * Delegates to storage adapter which handles clearing.
175
+ *
176
+ * @param namespace - Controller namespace (e.g., 'SnapController').
177
+ */
178
+ async clear(namespace) {
179
+ await __classPrivateFieldGet(this, _StorageService_storage, "f").clear(namespace);
180
+ }
181
+ }
182
+ _StorageService_messenger = new WeakMap(), _StorageService_storage = new WeakMap();
183
+ //# sourceMappingURL=StorageService.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"StorageService.mjs","sourceRoot":"","sources":["../src/StorageService.ts"],"names":[],"mappings":"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","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"]}
package/dist/index.cjs ADDED
@@ -0,0 +1,14 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.STORAGE_KEY_PREFIX = exports.SERVICE_NAME = exports.InMemoryStorageAdapter = exports.StorageService = void 0;
4
+ // Export service class
5
+ var StorageService_1 = require("./StorageService.cjs");
6
+ Object.defineProperty(exports, "StorageService", { enumerable: true, get: function () { return StorageService_1.StorageService; } });
7
+ // Export adapters
8
+ var InMemoryStorageAdapter_1 = require("./InMemoryStorageAdapter.cjs");
9
+ Object.defineProperty(exports, "InMemoryStorageAdapter", { enumerable: true, get: function () { return InMemoryStorageAdapter_1.InMemoryStorageAdapter; } });
10
+ // Export service name and storage key prefix constants
11
+ var types_1 = require("./types.cjs");
12
+ Object.defineProperty(exports, "SERVICE_NAME", { enumerable: true, get: function () { return types_1.SERVICE_NAME; } });
13
+ Object.defineProperty(exports, "STORAGE_KEY_PREFIX", { enumerable: true, get: function () { return types_1.STORAGE_KEY_PREFIX; } });
14
+ //# sourceMappingURL=index.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.cjs","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;AAAA,uBAAuB;AACvB,uDAAkD;AAAzC,gHAAA,cAAc,OAAA;AAEvB,kBAAkB;AAClB,uEAAkE;AAAzD,gIAAA,sBAAsB,OAAA;AAkB/B,uDAAuD;AACvD,qCAA2D;AAAlD,qGAAA,YAAY,OAAA;AAAE,2GAAA,kBAAkB,OAAA","sourcesContent":["// Export service class\nexport { StorageService } from './StorageService';\n\n// Export adapters\nexport { InMemoryStorageAdapter } from './InMemoryStorageAdapter';\n\n// Export types\nexport type {\n StorageAdapter,\n StorageServiceOptions,\n StorageServiceActions,\n StorageServiceEvents,\n StorageServiceMessenger,\n StorageServiceSetItemAction,\n StorageServiceGetItemAction,\n StorageServiceRemoveItemAction,\n StorageServiceGetAllKeysAction,\n StorageServiceClearAction,\n StorageServiceItemSetEvent,\n StorageServiceItemRemovedEvent,\n} from './types';\n\n// Export service name and storage key prefix constants\nexport { SERVICE_NAME, STORAGE_KEY_PREFIX } from './types';\n"]}
@@ -0,0 +1,5 @@
1
+ export { StorageService } from "./StorageService.cjs";
2
+ export { InMemoryStorageAdapter } from "./InMemoryStorageAdapter.cjs";
3
+ export type { StorageAdapter, StorageServiceOptions, StorageServiceActions, StorageServiceEvents, StorageServiceMessenger, StorageServiceSetItemAction, StorageServiceGetItemAction, StorageServiceRemoveItemAction, StorageServiceGetAllKeysAction, StorageServiceClearAction, StorageServiceItemSetEvent, StorageServiceItemRemovedEvent, } from "./types.cjs";
4
+ export { SERVICE_NAME, STORAGE_KEY_PREFIX } from "./types.cjs";
5
+ //# sourceMappingURL=index.d.cts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.cts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,cAAc,EAAE,6BAAyB;AAGlD,OAAO,EAAE,sBAAsB,EAAE,qCAAiC;AAGlE,YAAY,EACV,cAAc,EACd,qBAAqB,EACrB,qBAAqB,EACrB,oBAAoB,EACpB,uBAAuB,EACvB,2BAA2B,EAC3B,2BAA2B,EAC3B,8BAA8B,EAC9B,8BAA8B,EAC9B,yBAAyB,EACzB,0BAA0B,EAC1B,8BAA8B,GAC/B,oBAAgB;AAGjB,OAAO,EAAE,YAAY,EAAE,kBAAkB,EAAE,oBAAgB"}
@@ -0,0 +1,5 @@
1
+ export { StorageService } from "./StorageService.mjs";
2
+ export { InMemoryStorageAdapter } from "./InMemoryStorageAdapter.mjs";
3
+ export type { StorageAdapter, StorageServiceOptions, StorageServiceActions, StorageServiceEvents, StorageServiceMessenger, StorageServiceSetItemAction, StorageServiceGetItemAction, StorageServiceRemoveItemAction, StorageServiceGetAllKeysAction, StorageServiceClearAction, StorageServiceItemSetEvent, StorageServiceItemRemovedEvent, } from "./types.mjs";
4
+ export { SERVICE_NAME, STORAGE_KEY_PREFIX } from "./types.mjs";
5
+ //# sourceMappingURL=index.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.mts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,cAAc,EAAE,6BAAyB;AAGlD,OAAO,EAAE,sBAAsB,EAAE,qCAAiC;AAGlE,YAAY,EACV,cAAc,EACd,qBAAqB,EACrB,qBAAqB,EACrB,oBAAoB,EACpB,uBAAuB,EACvB,2BAA2B,EAC3B,2BAA2B,EAC3B,8BAA8B,EAC9B,8BAA8B,EAC9B,yBAAyB,EACzB,0BAA0B,EAC1B,8BAA8B,GAC/B,oBAAgB;AAGjB,OAAO,EAAE,YAAY,EAAE,kBAAkB,EAAE,oBAAgB"}
package/dist/index.mjs ADDED
@@ -0,0 +1,7 @@
1
+ // Export service class
2
+ export { StorageService } from "./StorageService.mjs";
3
+ // Export adapters
4
+ export { InMemoryStorageAdapter } from "./InMemoryStorageAdapter.mjs";
5
+ // Export service name and storage key prefix constants
6
+ export { SERVICE_NAME, STORAGE_KEY_PREFIX } from "./types.mjs";
7
+ //# sourceMappingURL=index.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.mjs","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,uBAAuB;AACvB,OAAO,EAAE,cAAc,EAAE,6BAAyB;AAElD,kBAAkB;AAClB,OAAO,EAAE,sBAAsB,EAAE,qCAAiC;AAkBlE,uDAAuD;AACvD,OAAO,EAAE,YAAY,EAAE,kBAAkB,EAAE,oBAAgB","sourcesContent":["// Export service class\nexport { StorageService } from './StorageService';\n\n// Export adapters\nexport { InMemoryStorageAdapter } from './InMemoryStorageAdapter';\n\n// Export types\nexport type {\n StorageAdapter,\n StorageServiceOptions,\n StorageServiceActions,\n StorageServiceEvents,\n StorageServiceMessenger,\n StorageServiceSetItemAction,\n StorageServiceGetItemAction,\n StorageServiceRemoveItemAction,\n StorageServiceGetAllKeysAction,\n StorageServiceClearAction,\n StorageServiceItemSetEvent,\n StorageServiceItemRemovedEvent,\n} from './types';\n\n// Export service name and storage key prefix constants\nexport { SERVICE_NAME, STORAGE_KEY_PREFIX } from './types';\n"]}
package/dist/types.cjs ADDED
@@ -0,0 +1,12 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.STORAGE_KEY_PREFIX = exports.SERVICE_NAME = void 0;
4
+ // Service name constant
5
+ exports.SERVICE_NAME = 'StorageService';
6
+ /**
7
+ * Storage key prefix for all keys managed by StorageService.
8
+ * Keys are formatted as: {STORAGE_KEY_PREFIX}{namespace}:{key}
9
+ * Example: 'storageService:SnapController:snap-id:sourceCode'
10
+ */
11
+ exports.STORAGE_KEY_PREFIX = 'storageService:';
12
+ //# sourceMappingURL=types.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.cjs","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":";;;AAuFA,wBAAwB;AACX,QAAA,YAAY,GAAG,gBAAgB,CAAC;AAE7C;;;;GAIG;AACU,QAAA,kBAAkB,GAAG,iBAAiB,CAAC","sourcesContent":["import type { Messenger } from '@metamask/messenger';\n\n/**\n * Platform-agnostic storage adapter interface.\n * Each client (mobile, extension) implements this interface\n * with their preferred storage mechanism.\n *\n * @example Mobile implementation using FilesystemStorage\n * @example Extension implementation using IndexedDB\n * @example Tests using InMemoryStorageAdapter\n */\nexport type StorageAdapter = {\n /**\n * Retrieve an item from storage.\n * Adapter is responsible for building the full storage key.\n *\n * @param namespace - The controller namespace (e.g., 'SnapController').\n * @param key - The data key (e.g., 'snap-id:sourceCode').\n * @returns The value as a string, or null if not found.\n */\n getItem(namespace: string, key: string): Promise<unknown>;\n\n /**\n * Store an item in storage.\n * Adapter is responsible for:\n * - Building the full storage key\n * - Wrapping value with metadata (timestamp, etc.)\n * - Serializing to string (JSON.stringify)\n *\n * @param namespace - The controller namespace (e.g., 'SnapController').\n * @param key - The data key (e.g., 'snap-id:sourceCode').\n * @param value - The value to store (will be wrapped and serialized by adapter).\n */\n setItem(namespace: string, key: string, value: unknown): Promise<void>;\n\n /**\n * Remove an item from storage.\n * Adapter is responsible for building the full storage key.\n *\n * @param namespace - The controller namespace (e.g., 'SnapController').\n * @param key - The data key (e.g., 'snap-id:sourceCode').\n */\n removeItem(namespace: string, key: string): Promise<void>;\n\n /**\n * Get all keys for a specific namespace.\n * Should return keys without the 'storage:namespace:' prefix.\n *\n * Adapter is responsible for:\n * - Filtering keys by prefix: 'storage:{namespace}:'\n * - Stripping the prefix from returned keys\n * - Returning only the key portion after the prefix\n *\n * @param namespace - The namespace to get keys for (e.g., 'SnapController').\n * @returns Array of keys without prefix (e.g., ['snap1:sourceCode', 'snap2:sourceCode']).\n */\n getAllKeys(namespace: string): Promise<string[]>;\n\n /**\n * Clear all items for a specific namespace.\n *\n * Adapter is responsible for:\n * - Finding all keys with prefix: 'storageService:{namespace}:'\n * - Removing all matching keys\n *\n * @param namespace - The namespace to clear (e.g., 'SnapController').\n */\n clear(namespace: string): Promise<void>;\n};\n\n/**\n * Options for constructing a {@link StorageService}.\n */\nexport type StorageServiceOptions = {\n /**\n * The messenger suited for this service.\n */\n messenger: StorageServiceMessenger;\n\n /**\n * Storage adapter for persisting data.\n * If not provided, uses in-memory storage (data lost on restart).\n * Production clients MUST provide a persistent storage adapter.\n */\n storage?: StorageAdapter;\n};\n\n// Service name constant\nexport const SERVICE_NAME = 'StorageService';\n\n/**\n * Storage key prefix for all keys managed by StorageService.\n * Keys are formatted as: {STORAGE_KEY_PREFIX}{namespace}:{key}\n * Example: 'storageService:SnapController:snap-id:sourceCode'\n */\nexport const STORAGE_KEY_PREFIX = 'storageService:';\n\n/**\n * Action for storing data in the storage service.\n */\nexport type StorageServiceSetItemAction = {\n type: `${typeof SERVICE_NAME}:setItem`;\n handler: <T>(namespace: string, key: string, value: T) => Promise<void>;\n};\n\n/**\n * Action for retrieving data from the storage service.\n */\nexport type StorageServiceGetItemAction = {\n type: `${typeof SERVICE_NAME}:getItem`;\n handler: <T>(namespace: string, key: string) => Promise<T | null>;\n};\n\n/**\n * Action for removing data from the storage service.\n */\nexport type StorageServiceRemoveItemAction = {\n type: `${typeof SERVICE_NAME}:removeItem`;\n handler: (namespace: string, key: string) => Promise<void>;\n};\n\n/**\n * Action for getting all keys for a namespace.\n */\nexport type StorageServiceGetAllKeysAction = {\n type: `${typeof SERVICE_NAME}:getAllKeys`;\n handler: (namespace: string) => Promise<string[]>;\n};\n\n/**\n * Action for clearing all data for a namespace.\n */\nexport type StorageServiceClearAction = {\n type: `${typeof SERVICE_NAME}:clear`;\n handler: (namespace: string) => Promise<void>;\n};\n\n/**\n * All actions that {@link StorageService} exposes to other consumers.\n */\nexport type StorageServiceActions =\n | StorageServiceSetItemAction\n | StorageServiceGetItemAction\n | StorageServiceRemoveItemAction\n | StorageServiceGetAllKeysAction\n | StorageServiceClearAction;\n\n/**\n * Event published when a storage item is set.\n * Event type includes namespace only, key passed in payload.\n *\n * @example\n * Subscribe to all changes in TokenListController:\n * messenger.subscribe('StorageService:itemSet:TokenListController', (value, key) => {\n * // value = the data that was set\n * // key = 'cache:0x1', 'cache:0x38', etc.\n * if (key.startsWith('cache:')) {\n * const chainId = key.replace('cache:', '');\n * // React to cache change for specific chain\n * }\n * });\n */\nexport type StorageServiceItemSetEvent = {\n type: `${typeof SERVICE_NAME}:itemSet:${string}`;\n payload: [value: unknown, key: string];\n};\n\n/**\n * Event published when a storage item is removed.\n * Event type includes namespace only, key passed in payload.\n */\nexport type StorageServiceItemRemovedEvent = {\n type: `${typeof SERVICE_NAME}:itemRemoved:${string}`;\n payload: [key: string];\n};\n\n/**\n * All events that {@link StorageService} publishes.\n */\nexport type StorageServiceEvents =\n | StorageServiceItemSetEvent\n | StorageServiceItemRemovedEvent;\n\n/**\n * Actions from other messengers that {@link StorageService} calls.\n */\ntype AllowedActions = never;\n\n/**\n * Events from other messengers that {@link StorageService} subscribes to.\n */\ntype AllowedEvents = never;\n\n/**\n * The messenger restricted to actions and events that\n * {@link StorageService} needs to access.\n */\nexport type StorageServiceMessenger = Messenger<\n typeof SERVICE_NAME,\n StorageServiceActions | AllowedActions,\n StorageServiceEvents | AllowedEvents\n>;\n"]}