@metamask-previews/storage-service 1.0.0-preview-e493d3e8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +22 -0
- package/LICENSE +20 -0
- package/README.md +377 -0
- package/package.json +73 -0
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this project will be documented in this file.
|
|
4
|
+
|
|
5
|
+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
6
|
+
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
|
+
|
|
8
|
+
## [Unreleased]
|
|
9
|
+
|
|
10
|
+
### Added
|
|
11
|
+
|
|
12
|
+
- Initial release of `@metamask/storage-service`
|
|
13
|
+
- Add `StorageService` class for platform-agnostic storage
|
|
14
|
+
- Add `StorageAdapter` interface for platform-specific implementations
|
|
15
|
+
- Add `InMemoryStorageAdapter` as default storage (for tests/dev)
|
|
16
|
+
- Add namespace-based key isolation
|
|
17
|
+
- Add support for `setItem`, `getItem`, `removeItem`, `getAllKeys`, and `clear` operations
|
|
18
|
+
- Add messenger integration for cross-controller communication
|
|
19
|
+
- Add `STORAGE_KEY_PREFIX` constant for consistent key prefixing across adapters
|
|
20
|
+
- Add comprehensive test coverage
|
|
21
|
+
|
|
22
|
+
[Unreleased]: https://github.com/MetaMask/core/
|
package/LICENSE
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 MetaMask
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
package/README.md
ADDED
|
@@ -0,0 +1,377 @@
|
|
|
1
|
+
# `@metamask/storage-service`
|
|
2
|
+
|
|
3
|
+
A platform-agnostic service for storing large, infrequently accessed controller data outside of memory.
|
|
4
|
+
|
|
5
|
+
## Problem
|
|
6
|
+
|
|
7
|
+
Controllers store large, infrequently-accessed data in Redux state, causing:
|
|
8
|
+
- **State bloat**: 10.79 MB total, with 9.94 MB (92%) in just 2 controllers
|
|
9
|
+
- **Slow app startup**: Parsing 10.79 MB on every launch
|
|
10
|
+
- **High memory usage**: All data loaded, even if rarely accessed
|
|
11
|
+
- **Slow persist operations**: Up to 5.95 MB written per controller change
|
|
12
|
+
|
|
13
|
+
**Production measurements** (MetaMask Mobile):
|
|
14
|
+
- SnapController sourceCode: 5.95 MB (55% of state)
|
|
15
|
+
- TokenListController cache: 3.99 MB (37% of state)
|
|
16
|
+
- **Combined**: 9.94 MB in just 2 controllers
|
|
17
|
+
|
|
18
|
+
## Solution
|
|
19
|
+
|
|
20
|
+
`StorageService` provides a messenger-based API for controllers to store large data on disk instead of in memory. Data is loaded lazily only when needed.
|
|
21
|
+
|
|
22
|
+
## Installation
|
|
23
|
+
|
|
24
|
+
`yarn add @metamask/storage-service`
|
|
25
|
+
|
|
26
|
+
or
|
|
27
|
+
|
|
28
|
+
`npm install @metamask/storage-service`
|
|
29
|
+
|
|
30
|
+
## Architecture
|
|
31
|
+
|
|
32
|
+
The service is **platform-agnostic** and accepts an optional `StorageAdapter`:
|
|
33
|
+
|
|
34
|
+
- **With Adapter** (Production): Client provides platform-specific storage
|
|
35
|
+
- Mobile: FilesystemStorage adapter → Data persists
|
|
36
|
+
- Extension: IndexedDB adapter → Data persists
|
|
37
|
+
|
|
38
|
+
- **Without Adapter** (Default): Uses in-memory storage
|
|
39
|
+
- Testing: No setup needed, isolated tests
|
|
40
|
+
- Development: Quick start, no config
|
|
41
|
+
- ⚠️ Data lost on restart
|
|
42
|
+
|
|
43
|
+
## Events
|
|
44
|
+
|
|
45
|
+
StorageService publishes events when data changes, enabling reactive patterns:
|
|
46
|
+
|
|
47
|
+
**Events published**:
|
|
48
|
+
- `StorageService:itemSet:{namespace}` - When data is stored
|
|
49
|
+
- Payload: `[value, key]`
|
|
50
|
+
- `StorageService:itemRemoved:{namespace}` - When data is removed
|
|
51
|
+
- Payload: `[key]`
|
|
52
|
+
|
|
53
|
+
**Example - Subscribe to changes**:
|
|
54
|
+
```typescript
|
|
55
|
+
// In another controller
|
|
56
|
+
this.messenger.subscribe(
|
|
57
|
+
'StorageService:itemSet:ControllerA',
|
|
58
|
+
(value, key) => {
|
|
59
|
+
console.log(`ControllerA stored data: ${key}`);
|
|
60
|
+
// React to changes without coupling
|
|
61
|
+
},
|
|
62
|
+
);
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
## Usage
|
|
66
|
+
|
|
67
|
+
### Via Messenger (Recommended)
|
|
68
|
+
|
|
69
|
+
The service is designed to be used via a messenger, allowing controllers to access storage without direct dependencies.
|
|
70
|
+
|
|
71
|
+
#### 1. Controller Setup
|
|
72
|
+
|
|
73
|
+
```typescript
|
|
74
|
+
import type {
|
|
75
|
+
StorageServiceSetItemAction,
|
|
76
|
+
StorageServiceGetItemAction,
|
|
77
|
+
StorageServiceRemoveItemAction,
|
|
78
|
+
} from '@metamask/storage-service';
|
|
79
|
+
|
|
80
|
+
// Grant access to storage actions
|
|
81
|
+
type AllowedActions =
|
|
82
|
+
| StorageServiceSetItemAction
|
|
83
|
+
| StorageServiceGetItemAction
|
|
84
|
+
| StorageServiceRemoveItemAction;
|
|
85
|
+
|
|
86
|
+
type SnapControllerMessenger = Messenger<
|
|
87
|
+
'SnapController',
|
|
88
|
+
SnapControllerActions | AllowedActions,
|
|
89
|
+
SnapControllerEvents
|
|
90
|
+
>;
|
|
91
|
+
|
|
92
|
+
class SnapController extends BaseController<
|
|
93
|
+
'SnapController',
|
|
94
|
+
SnapControllerState,
|
|
95
|
+
SnapControllerMessenger
|
|
96
|
+
> {
|
|
97
|
+
async storeSnapSourceCode(snapId: string, sourceCode: string) {
|
|
98
|
+
// Store 3.86 MB of source code on disk, not in state
|
|
99
|
+
await this.messenger.call(
|
|
100
|
+
'StorageService:setItem',
|
|
101
|
+
'SnapController',
|
|
102
|
+
`${snapId}:sourceCode`,
|
|
103
|
+
sourceCode,
|
|
104
|
+
);
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
async getSnapSourceCode(snapId: string): Promise<string | null> {
|
|
108
|
+
// Load source code only when snap needs to execute
|
|
109
|
+
return await this.messenger.call(
|
|
110
|
+
'StorageService:getItem',
|
|
111
|
+
'SnapController',
|
|
112
|
+
`${snapId}:sourceCode`,
|
|
113
|
+
);
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
#### 2. Service Initialization (Client)
|
|
119
|
+
|
|
120
|
+
**Mobile:**
|
|
121
|
+
|
|
122
|
+
```typescript
|
|
123
|
+
import {
|
|
124
|
+
StorageService,
|
|
125
|
+
type StorageAdapter,
|
|
126
|
+
STORAGE_KEY_PREFIX,
|
|
127
|
+
} from '@metamask/storage-service';
|
|
128
|
+
import FilesystemStorage from 'redux-persist-filesystem-storage';
|
|
129
|
+
|
|
130
|
+
// Adapters handle key building and serialization
|
|
131
|
+
const mobileStorageAdapter: StorageAdapter = {
|
|
132
|
+
async getItem(namespace: string, key: string) {
|
|
133
|
+
const fullKey = `${STORAGE_KEY_PREFIX}${namespace}:${key}`;
|
|
134
|
+
const serialized = await FilesystemStorage.getItem(fullKey);
|
|
135
|
+
if (!serialized) return null;
|
|
136
|
+
const wrapper = JSON.parse(serialized);
|
|
137
|
+
return wrapper.data;
|
|
138
|
+
},
|
|
139
|
+
async setItem(namespace: string, key: string, value: unknown) {
|
|
140
|
+
const fullKey = `${STORAGE_KEY_PREFIX}${namespace}:${key}`;
|
|
141
|
+
const wrapper = { timestamp: Date.now(), data: value };
|
|
142
|
+
await FilesystemStorage.setItem(fullKey, JSON.stringify(wrapper), Device.isIos());
|
|
143
|
+
},
|
|
144
|
+
async removeItem(namespace: string, key: string) {
|
|
145
|
+
const fullKey = `${STORAGE_KEY_PREFIX}${namespace}:${key}`;
|
|
146
|
+
await FilesystemStorage.removeItem(fullKey);
|
|
147
|
+
},
|
|
148
|
+
async getAllKeys(namespace: string) {
|
|
149
|
+
const prefix = `${STORAGE_KEY_PREFIX}${namespace}:`;
|
|
150
|
+
const allKeys = await FilesystemStorage.getAllKeys();
|
|
151
|
+
return allKeys
|
|
152
|
+
.filter((k: string) => k.startsWith(prefix))
|
|
153
|
+
.map((k: string) => k.slice(prefix.length));
|
|
154
|
+
},
|
|
155
|
+
async clear(namespace: string) {
|
|
156
|
+
const keys = await this.getAllKeys(namespace);
|
|
157
|
+
await Promise.all(keys.map((k) => this.removeItem(namespace, k)));
|
|
158
|
+
},
|
|
159
|
+
};
|
|
160
|
+
|
|
161
|
+
// Initialize service
|
|
162
|
+
const service = new StorageService({
|
|
163
|
+
messenger: storageServiceMessenger,
|
|
164
|
+
storage: mobileStorageAdapter,
|
|
165
|
+
});
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
**Extension:**
|
|
169
|
+
|
|
170
|
+
```typescript
|
|
171
|
+
import {
|
|
172
|
+
StorageService,
|
|
173
|
+
type StorageAdapter,
|
|
174
|
+
STORAGE_KEY_PREFIX,
|
|
175
|
+
} from '@metamask/storage-service';
|
|
176
|
+
|
|
177
|
+
// Adapters handle key building and serialization
|
|
178
|
+
const extensionStorageAdapter: StorageAdapter = {
|
|
179
|
+
async getItem(namespace: string, key: string) {
|
|
180
|
+
const fullKey = `${STORAGE_KEY_PREFIX}${namespace}:${key}`;
|
|
181
|
+
const db = await openDB();
|
|
182
|
+
const serialized = await db.get('storage-service', fullKey);
|
|
183
|
+
if (!serialized) return null;
|
|
184
|
+
const wrapper = JSON.parse(serialized);
|
|
185
|
+
return wrapper.data;
|
|
186
|
+
},
|
|
187
|
+
async setItem(namespace: string, key: string, value: unknown) {
|
|
188
|
+
const fullKey = `${STORAGE_KEY_PREFIX}${namespace}:${key}`;
|
|
189
|
+
const wrapper = { timestamp: Date.now(), data: value };
|
|
190
|
+
const db = await openDB();
|
|
191
|
+
await db.put('storage-service', JSON.stringify(wrapper), fullKey);
|
|
192
|
+
},
|
|
193
|
+
async removeItem(namespace: string, key: string) {
|
|
194
|
+
const fullKey = `${STORAGE_KEY_PREFIX}${namespace}:${key}`;
|
|
195
|
+
const db = await openDB();
|
|
196
|
+
await db.delete('storage-service', fullKey);
|
|
197
|
+
},
|
|
198
|
+
async getAllKeys(namespace: string) {
|
|
199
|
+
const prefix = `${STORAGE_KEY_PREFIX}${namespace}:`;
|
|
200
|
+
const db = await openDB();
|
|
201
|
+
const allKeys = await db.getAllKeys('storage-service');
|
|
202
|
+
return allKeys
|
|
203
|
+
.filter((k: string) => k.startsWith(prefix))
|
|
204
|
+
.map((k: string) => k.slice(prefix.length));
|
|
205
|
+
},
|
|
206
|
+
async clear(namespace: string) {
|
|
207
|
+
const keys = await this.getAllKeys(namespace);
|
|
208
|
+
await Promise.all(keys.map((k) => this.removeItem(namespace, k)));
|
|
209
|
+
},
|
|
210
|
+
};
|
|
211
|
+
|
|
212
|
+
// Initialize service
|
|
213
|
+
const service = new StorageService({
|
|
214
|
+
messenger: storageServiceMessenger,
|
|
215
|
+
storage: extensionStorageAdapter,
|
|
216
|
+
});
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
**Testing:**
|
|
220
|
+
|
|
221
|
+
```typescript
|
|
222
|
+
import { StorageService } from '@metamask/storage-service';
|
|
223
|
+
|
|
224
|
+
// No storage adapter needed - uses in-memory by default
|
|
225
|
+
const service = new StorageService({
|
|
226
|
+
messenger: testMessenger,
|
|
227
|
+
// storage: undefined, // Optional - defaults to InMemoryStorageAdapter
|
|
228
|
+
});
|
|
229
|
+
|
|
230
|
+
// Works immediately, data isolated per test
|
|
231
|
+
await service.setItem('TestController', 'key', 'value');
|
|
232
|
+
```
|
|
233
|
+
|
|
234
|
+
#### 3. Delegate Actions to Controllers
|
|
235
|
+
|
|
236
|
+
```typescript
|
|
237
|
+
rootMessenger.delegate({
|
|
238
|
+
actions: [
|
|
239
|
+
'StorageService:setItem',
|
|
240
|
+
'StorageService:getItem',
|
|
241
|
+
'StorageService:removeItem',
|
|
242
|
+
],
|
|
243
|
+
messenger: snapControllerMessenger,
|
|
244
|
+
});
|
|
245
|
+
```
|
|
246
|
+
|
|
247
|
+
### Direct Usage
|
|
248
|
+
|
|
249
|
+
You can also use the service directly without a messenger:
|
|
250
|
+
|
|
251
|
+
```typescript
|
|
252
|
+
import { StorageService, InMemoryStorageAdapter } from '@metamask/storage-service';
|
|
253
|
+
|
|
254
|
+
const service = new StorageService({
|
|
255
|
+
messenger: myMessenger,
|
|
256
|
+
storage: new InMemoryStorageAdapter(),
|
|
257
|
+
});
|
|
258
|
+
|
|
259
|
+
await service.setItem('MyController', 'myKey', { data: 'value' });
|
|
260
|
+
const data = await service.getItem('MyController', 'myKey');
|
|
261
|
+
```
|
|
262
|
+
|
|
263
|
+
## API
|
|
264
|
+
|
|
265
|
+
### `StorageService`
|
|
266
|
+
|
|
267
|
+
#### `setItem<T>(namespace: string, key: string, value: T): Promise<void>`
|
|
268
|
+
|
|
269
|
+
Store data in storage.
|
|
270
|
+
|
|
271
|
+
- `namespace` - Controller namespace (e.g., 'SnapController')
|
|
272
|
+
- `key` - Storage key (e.g., 'npm:@metamask/bitcoin-wallet-snap:sourceCode')
|
|
273
|
+
- `value` - Data to store (will be JSON stringified)
|
|
274
|
+
|
|
275
|
+
```typescript
|
|
276
|
+
await service.setItem('SnapController', 'snap-id:sourceCode', sourceCode);
|
|
277
|
+
```
|
|
278
|
+
|
|
279
|
+
#### `getItem<T>(namespace: string, key: string): Promise<T | null>`
|
|
280
|
+
|
|
281
|
+
Retrieve data from storage.
|
|
282
|
+
|
|
283
|
+
- `namespace` - Controller namespace
|
|
284
|
+
- `key` - Storage key
|
|
285
|
+
- **Returns**: Parsed data or null if not found
|
|
286
|
+
|
|
287
|
+
```typescript
|
|
288
|
+
const sourceCode = await service.getItem('SnapController', 'snap-id:sourceCode');
|
|
289
|
+
```
|
|
290
|
+
|
|
291
|
+
#### `removeItem(namespace: string, key: string): Promise<void>`
|
|
292
|
+
|
|
293
|
+
Remove data from storage.
|
|
294
|
+
|
|
295
|
+
```typescript
|
|
296
|
+
await service.removeItem('SnapController', 'snap-id:sourceCode');
|
|
297
|
+
```
|
|
298
|
+
|
|
299
|
+
#### `getAllKeys(namespace: string): Promise<string[]>`
|
|
300
|
+
|
|
301
|
+
Get all keys for a namespace (without prefix).
|
|
302
|
+
|
|
303
|
+
```typescript
|
|
304
|
+
const keys = await service.getAllKeys('SnapController');
|
|
305
|
+
// Returns: ['snap-id-1:sourceCode', 'snap-id-2:sourceCode', ...]
|
|
306
|
+
```
|
|
307
|
+
|
|
308
|
+
#### `clear(namespace: string): Promise<void>`
|
|
309
|
+
|
|
310
|
+
Clear all data for a namespace.
|
|
311
|
+
|
|
312
|
+
```typescript
|
|
313
|
+
await service.clear('SnapController');
|
|
314
|
+
```
|
|
315
|
+
|
|
316
|
+
## StorageAdapter Interface
|
|
317
|
+
|
|
318
|
+
Implement this interface to provide platform-specific storage. Adapters are responsible for:
|
|
319
|
+
- Building the full storage key (e.g., `storageService:namespace:key`)
|
|
320
|
+
- Wrapping data with metadata (timestamp) before serialization
|
|
321
|
+
- Serializing/deserializing data (JSON.stringify/parse)
|
|
322
|
+
|
|
323
|
+
```typescript
|
|
324
|
+
export type StorageAdapter = {
|
|
325
|
+
getItem(namespace: string, key: string): Promise<unknown>;
|
|
326
|
+
setItem(namespace: string, key: string, value: unknown): Promise<void>;
|
|
327
|
+
removeItem(namespace: string, key: string): Promise<void>;
|
|
328
|
+
getAllKeys(namespace: string): Promise<string[]>;
|
|
329
|
+
clear(namespace: string): Promise<void>;
|
|
330
|
+
};
|
|
331
|
+
```
|
|
332
|
+
|
|
333
|
+
## When to Use
|
|
334
|
+
|
|
335
|
+
✅ **Use StorageService for:**
|
|
336
|
+
- Large data (> 100 KB)
|
|
337
|
+
- Infrequently accessed data
|
|
338
|
+
- Data that doesn't need to be in Redux state
|
|
339
|
+
- Examples: Snap source code (6 MB), cached API responses (4 MB)
|
|
340
|
+
|
|
341
|
+
❌ **Don't use for:**
|
|
342
|
+
- Frequently accessed data (use controller state)
|
|
343
|
+
- Small data (< 10 KB - overhead not worth it)
|
|
344
|
+
- Data needed for UI rendering
|
|
345
|
+
- Critical data that must be in Redux
|
|
346
|
+
|
|
347
|
+
## Storage Key Format
|
|
348
|
+
|
|
349
|
+
Adapters build keys with prefix: `storageService:{namespace}:{key}`
|
|
350
|
+
|
|
351
|
+
Examples:
|
|
352
|
+
- `storageService:SnapController:npm:@metamask/bitcoin-wallet-snap:sourceCode`
|
|
353
|
+
- `storageService:TokenListController:cache:0x1`
|
|
354
|
+
|
|
355
|
+
This provides:
|
|
356
|
+
- Namespace isolation (prevents collisions)
|
|
357
|
+
- Easy debugging (clear key format)
|
|
358
|
+
- Scoped clearing (clear removes all keys for controller)
|
|
359
|
+
|
|
360
|
+
## Real-World Impact
|
|
361
|
+
|
|
362
|
+
**Production measurements** (MetaMask Mobile):
|
|
363
|
+
|
|
364
|
+
**Per-controller**:
|
|
365
|
+
- SnapController: 5.95 MB sourceCode → 166 KB metadata (97% reduction)
|
|
366
|
+
- TokenListController: 3.99 MB cache → 61 bytes metadata (99.9% reduction)
|
|
367
|
+
|
|
368
|
+
**Combined**:
|
|
369
|
+
- Total state: 10.79 MB → 0.85 MB (**92% reduction**)
|
|
370
|
+
- App startup: 92% less data to parse
|
|
371
|
+
- Memory freed: 9.94 MB
|
|
372
|
+
- Disk I/O: Up to 9.94 MB less per persist operation
|
|
373
|
+
|
|
374
|
+
## Contributing
|
|
375
|
+
|
|
376
|
+
This package is part of a monorepo. Instructions for contributing can be found in the [monorepo README](https://github.com/MetaMask/core#readme).
|
|
377
|
+
|
package/package.json
ADDED
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@metamask-previews/storage-service",
|
|
3
|
+
"version": "1.0.0-preview-e493d3e8",
|
|
4
|
+
"description": "Platform-agnostic service for storing large, infrequently accessed controller data",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"MetaMask",
|
|
7
|
+
"Ethereum",
|
|
8
|
+
"Storage",
|
|
9
|
+
"Service"
|
|
10
|
+
],
|
|
11
|
+
"homepage": "https://github.com/MetaMask/core/tree/main/packages/storage-service#readme",
|
|
12
|
+
"bugs": {
|
|
13
|
+
"url": "https://github.com/MetaMask/core/issues"
|
|
14
|
+
},
|
|
15
|
+
"repository": {
|
|
16
|
+
"type": "git",
|
|
17
|
+
"url": "https://github.com/MetaMask/core.git"
|
|
18
|
+
},
|
|
19
|
+
"license": "MIT",
|
|
20
|
+
"sideEffects": false,
|
|
21
|
+
"exports": {
|
|
22
|
+
".": {
|
|
23
|
+
"import": {
|
|
24
|
+
"types": "./dist/index.d.mts",
|
|
25
|
+
"default": "./dist/index.mjs"
|
|
26
|
+
},
|
|
27
|
+
"require": {
|
|
28
|
+
"types": "./dist/index.d.cts",
|
|
29
|
+
"default": "./dist/index.cjs"
|
|
30
|
+
}
|
|
31
|
+
},
|
|
32
|
+
"./package.json": "./package.json"
|
|
33
|
+
},
|
|
34
|
+
"main": "./dist/index.cjs",
|
|
35
|
+
"types": "./dist/index.d.cts",
|
|
36
|
+
"files": [
|
|
37
|
+
"dist/"
|
|
38
|
+
],
|
|
39
|
+
"scripts": {
|
|
40
|
+
"build": "ts-bridge --project tsconfig.build.json --verbose --clean --no-references",
|
|
41
|
+
"build:all": "ts-bridge --project tsconfig.build.json --verbose --clean",
|
|
42
|
+
"build:docs": "typedoc",
|
|
43
|
+
"changelog:update": "../../scripts/update-changelog.sh @metamask/storage-service",
|
|
44
|
+
"changelog:validate": "../../scripts/validate-changelog.sh @metamask/storage-service",
|
|
45
|
+
"publish:preview": "yarn npm publish --tag preview",
|
|
46
|
+
"since-latest-release": "../../scripts/since-latest-release.sh",
|
|
47
|
+
"test": "NODE_OPTIONS=--experimental-vm-modules jest --reporters=jest-silent-reporter",
|
|
48
|
+
"test:clean": "NODE_OPTIONS=--experimental-vm-modules jest --clearCache",
|
|
49
|
+
"test:verbose": "NODE_OPTIONS=--experimental-vm-modules jest --verbose",
|
|
50
|
+
"test:watch": "NODE_OPTIONS=--experimental-vm-modules jest --watch"
|
|
51
|
+
},
|
|
52
|
+
"dependencies": {
|
|
53
|
+
"@metamask/messenger": "^0.3.0"
|
|
54
|
+
},
|
|
55
|
+
"devDependencies": {
|
|
56
|
+
"@metamask/auto-changelog": "^3.4.4",
|
|
57
|
+
"@ts-bridge/cli": "^0.6.4",
|
|
58
|
+
"@types/jest": "^27.4.1",
|
|
59
|
+
"deepmerge": "^4.2.2",
|
|
60
|
+
"jest": "^27.5.1",
|
|
61
|
+
"ts-jest": "^27.1.4",
|
|
62
|
+
"typedoc": "^0.24.8",
|
|
63
|
+
"typedoc-plugin-missing-exports": "^2.0.0",
|
|
64
|
+
"typescript": "~5.3.3"
|
|
65
|
+
},
|
|
66
|
+
"engines": {
|
|
67
|
+
"node": "^18.18 || >=20"
|
|
68
|
+
},
|
|
69
|
+
"publishConfig": {
|
|
70
|
+
"access": "public",
|
|
71
|
+
"registry": "https://registry.npmjs.org/"
|
|
72
|
+
}
|
|
73
|
+
}
|