@metamask/keyring-sdk 2.2.0 → 3.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +29 -1
- package/dist/entropy.cjs +45 -0
- package/dist/entropy.cjs.map +1 -0
- package/dist/entropy.d.cts +39 -0
- package/dist/entropy.d.cts.map +1 -0
- package/dist/entropy.d.mts +39 -0
- package/dist/entropy.d.mts.map +1 -0
- package/dist/entropy.mjs +40 -0
- package/dist/entropy.mjs.map +1 -0
- package/dist/index.cjs +2 -0
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +2 -0
- package/dist/index.d.cts.map +1 -1
- package/dist/index.d.mts +2 -0
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +2 -0
- package/dist/index.mjs.map +1 -1
- package/dist/migration.cjs +95 -0
- package/dist/migration.cjs.map +1 -0
- package/dist/migration.d.cts +124 -0
- package/dist/migration.d.cts.map +1 -0
- package/dist/migration.d.mts +124 -0
- package/dist/migration.d.mts.map +1 -0
- package/dist/migration.mjs +90 -0
- package/dist/migration.mjs.map +1 -0
- package/dist/mnemonic.cjs +15 -6
- package/dist/mnemonic.cjs.map +1 -1
- package/dist/mnemonic.d.cts +7 -0
- package/dist/mnemonic.d.cts.map +1 -1
- package/dist/mnemonic.d.mts +7 -0
- package/dist/mnemonic.d.mts.map +1 -1
- package/dist/mnemonic.mjs +13 -5
- package/dist/mnemonic.mjs.map +1 -1
- package/package.json +6 -5
package/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,32 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [3.0.0]
|
|
11
|
+
|
|
12
|
+
### Added
|
|
13
|
+
|
|
14
|
+
- Add new entropy support ([#603](https://github.com/MetaMask/accounts/pull/603))
|
|
15
|
+
- Add `encodeMnemonicWords` ([#606](https://github.com/MetaMask/accounts/pull/606))
|
|
16
|
+
|
|
17
|
+
### Changed
|
|
18
|
+
|
|
19
|
+
- **BREAKING:** Drop support for Node.js v18 and v20; minimum version is now v22 ([#593](https://github.com/MetaMask/accounts/pull/593))
|
|
20
|
+
- Bump `@metamask/keyring-api` from `^23.6.0` to `^24.0.0` ([#604](https://github.com/MetaMask/accounts/pull/604), [#611](https://github.com/MetaMask/accounts/pull/611))
|
|
21
|
+
- Bump `@metamask/keyring-utils` from `^4.0.0` to `^5.0.0` ([#611](https://github.com/MetaMask/accounts/pull/611))
|
|
22
|
+
|
|
23
|
+
## [2.3.0]
|
|
24
|
+
|
|
25
|
+
### Added
|
|
26
|
+
|
|
27
|
+
- Add keyring state migration framework ([#505](https://github.com/MetaMask/accounts/pull/505))
|
|
28
|
+
- Use `createMigrations().add(...)` to build a chain of versioned migration steps, and `.apply(state)` to migrate the internal state of keyrings
|
|
29
|
+
|
|
30
|
+
### Changed
|
|
31
|
+
|
|
32
|
+
- Bump `@metamask/keyring-api` from `^23.2.0` to `^23.6.0` ([#569](https://github.com/MetaMask/accounts/pull/569), [#583](https://github.com/MetaMask/accounts/pull/583), [#587](https://github.com/MetaMask/accounts/pull/587), [#600](https://github.com/MetaMask/accounts/pull/600))
|
|
33
|
+
- Bump `@metamask/superstruct` from `^3.1.0` to `^3.4.1` ([#580](https://github.com/MetaMask/accounts/pull/580), [#577](https://github.com/MetaMask/accounts/pull/577))
|
|
34
|
+
- Bump `@metamask/keyring-utils` from `^3.3.1` to `^4.0.0` ([#600](https://github.com/MetaMask/accounts/pull/600))
|
|
35
|
+
|
|
10
36
|
## [2.2.0]
|
|
11
37
|
|
|
12
38
|
### Added
|
|
@@ -88,7 +114,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
88
114
|
|
|
89
115
|
- Initial release, extracted from `@metamask/keyring-api` ([#478](https://github.com/MetaMask/accounts/pull/478), [#482](https://github.com/MetaMask/accounts/pull/482))
|
|
90
116
|
|
|
91
|
-
[Unreleased]: https://github.com/MetaMask/accounts/compare/@metamask/keyring-sdk@
|
|
117
|
+
[Unreleased]: https://github.com/MetaMask/accounts/compare/@metamask/keyring-sdk@3.0.0...HEAD
|
|
118
|
+
[3.0.0]: https://github.com/MetaMask/accounts/compare/@metamask/keyring-sdk@2.3.0...@metamask/keyring-sdk@3.0.0
|
|
119
|
+
[2.3.0]: https://github.com/MetaMask/accounts/compare/@metamask/keyring-sdk@2.2.0...@metamask/keyring-sdk@2.3.0
|
|
92
120
|
[2.2.0]: https://github.com/MetaMask/accounts/compare/@metamask/keyring-sdk@2.1.1...@metamask/keyring-sdk@2.2.0
|
|
93
121
|
[2.1.1]: https://github.com/MetaMask/accounts/compare/@metamask/keyring-sdk@2.1.0...@metamask/keyring-sdk@2.1.1
|
|
94
122
|
[2.1.0]: https://github.com/MetaMask/accounts/compare/@metamask/keyring-sdk@2.0.2...@metamask/keyring-sdk@2.1.0
|
package/dist/entropy.cjs
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.toEntropySourceId = exports.fingerprint = void 0;
|
|
4
|
+
const hmac_1 = require("@noble/hashes/hmac");
|
|
5
|
+
const sha2_1 = require("@noble/hashes/sha2");
|
|
6
|
+
const uuid_1 = require("uuid");
|
|
7
|
+
/**
|
|
8
|
+
* Computes a deterministic, non-reversible fingerprint for a piece of entropy.
|
|
9
|
+
*
|
|
10
|
+
* The fingerprint is a UUID v4 seeded from the first 16 bytes of
|
|
11
|
+
* `HMAC-SHA256(key=material, msg='metamask:fingerprint')`.
|
|
12
|
+
*
|
|
13
|
+
* @param material - The raw entropy bytes (e.g. BIP-39 mnemonic bytes).
|
|
14
|
+
* @returns A deterministic UUID v4 string that uniquely identifies the entropy
|
|
15
|
+
* without exposing it.
|
|
16
|
+
*/
|
|
17
|
+
async function fingerprint(material) {
|
|
18
|
+
const message = new TextEncoder().encode('metamask:fingerprint');
|
|
19
|
+
// `@noble/hashes` is synchronous today, but the async signature is kept as a
|
|
20
|
+
// forward-compatible seam: a future migration to the Web Crypto API (or any
|
|
21
|
+
// other async primitive) won't require changes at every call site.
|
|
22
|
+
const digest = (0, hmac_1.hmac)(sha2_1.sha256, material, message);
|
|
23
|
+
return (0, uuid_1.v4)({ random: digest.slice(0, 16) });
|
|
24
|
+
}
|
|
25
|
+
exports.fingerprint = fingerprint;
|
|
26
|
+
/**
|
|
27
|
+
* Computes a stable {@link EntropySourceId} for an entropy source.
|
|
28
|
+
*
|
|
29
|
+
* The ID is formatted as `entropy:{type}:{uuid}`, where
|
|
30
|
+
* the UUID segment is the {@link fingerprint} of `material` when provided, or
|
|
31
|
+
* `'_'` for entropy sources whose secret never leaves the device (e.g. hardware
|
|
32
|
+
* wallets).
|
|
33
|
+
*
|
|
34
|
+
* @param type - The entropy source type (e.g. `'mnemonic'`,
|
|
35
|
+
* `'ledger'`, `'private-key'`).
|
|
36
|
+
* @param material - The raw entropy bytes. Omit for hardware wallets or any
|
|
37
|
+
* entropy source where the secret is not directly accessible.
|
|
38
|
+
* @returns A stable {@link EntropySourceId} string.
|
|
39
|
+
*/
|
|
40
|
+
async function toEntropySourceId(type, material) {
|
|
41
|
+
const entropyFingerprint = material ? await fingerprint(material) : '_';
|
|
42
|
+
return `entropy:${type}:${entropyFingerprint}`;
|
|
43
|
+
}
|
|
44
|
+
exports.toEntropySourceId = toEntropySourceId;
|
|
45
|
+
//# sourceMappingURL=entropy.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"entropy.cjs","sourceRoot":"","sources":["../src/entropy.ts"],"names":[],"mappings":";;;AAAA,6CAA0C;AAC1C,6CAA4C;AAC5C,+BAAkC;AAsBlC;;;;;;;;;GASG;AACI,KAAK,UAAU,WAAW,CAAC,QAAoB;IACpD,MAAM,OAAO,GAAG,IAAI,WAAW,EAAE,CAAC,MAAM,CAAC,sBAAsB,CAAC,CAAC;IACjE,6EAA6E;IAC7E,4EAA4E;IAC5E,mEAAmE;IACnE,MAAM,MAAM,GAAG,IAAA,WAAI,EAAC,aAAM,EAAE,QAAQ,EAAE,OAAO,CAAC,CAAC;IAC/C,OAAO,IAAA,SAAI,EAAC,EAAE,MAAM,EAAE,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,EAAE,CAAC,CAAC;AAC/C,CAAC;AAPD,kCAOC;AAED;;;;;;;;;;;;;GAaG;AACI,KAAK,UAAU,iBAAiB,CACrC,IAAuB,EACvB,QAAqB;IAErB,MAAM,kBAAkB,GAAG,QAAQ,CAAC,CAAC,CAAC,MAAM,WAAW,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC;IACxE,OAAO,WAAW,IAAI,IAAI,kBAAkB,EAAE,CAAC;AACjD,CAAC;AAND,8CAMC","sourcesContent":["import { hmac } from '@noble/hashes/hmac';\nimport { sha256 } from '@noble/hashes/sha2';\nimport { v4 as uuid } from 'uuid';\n\n/**\n * The type of an entropy source.\n */\nexport type EntropySourceType =\n | 'mnemonic'\n | 'ledger'\n | 'trezor'\n | 'qr'\n | 'private-key'\n | 'mpc';\n\n/**\n * Unique identifier for an entropy source.\n *\n * Format: `entropy:{type}:{uuid}` where the UUID is a\n * deterministic fingerprint of the underlying secret, or `'_'` for entropies\n * that cannot be uniquely identified.\n */\nexport type EntropySourceId = `entropy:${EntropySourceType}:${string}`;\n\n/**\n * Computes a deterministic, non-reversible fingerprint for a piece of entropy.\n *\n * The fingerprint is a UUID v4 seeded from the first 16 bytes of\n * `HMAC-SHA256(key=material, msg='metamask:fingerprint')`.\n *\n * @param material - The raw entropy bytes (e.g. BIP-39 mnemonic bytes).\n * @returns A deterministic UUID v4 string that uniquely identifies the entropy\n * without exposing it.\n */\nexport async function fingerprint(material: Uint8Array): Promise<string> {\n const message = new TextEncoder().encode('metamask:fingerprint');\n // `@noble/hashes` is synchronous today, but the async signature is kept as a\n // forward-compatible seam: a future migration to the Web Crypto API (or any\n // other async primitive) won't require changes at every call site.\n const digest = hmac(sha256, material, message);\n return uuid({ random: digest.slice(0, 16) });\n}\n\n/**\n * Computes a stable {@link EntropySourceId} for an entropy source.\n *\n * The ID is formatted as `entropy:{type}:{uuid}`, where\n * the UUID segment is the {@link fingerprint} of `material` when provided, or\n * `'_'` for entropy sources whose secret never leaves the device (e.g. hardware\n * wallets).\n *\n * @param type - The entropy source type (e.g. `'mnemonic'`,\n * `'ledger'`, `'private-key'`).\n * @param material - The raw entropy bytes. Omit for hardware wallets or any\n * entropy source where the secret is not directly accessible.\n * @returns A stable {@link EntropySourceId} string.\n */\nexport async function toEntropySourceId(\n type: EntropySourceType,\n material?: Uint8Array,\n): Promise<EntropySourceId> {\n const entropyFingerprint = material ? await fingerprint(material) : '_';\n return `entropy:${type}:${entropyFingerprint}`;\n}\n"]}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The type of an entropy source.
|
|
3
|
+
*/
|
|
4
|
+
export type EntropySourceType = 'mnemonic' | 'ledger' | 'trezor' | 'qr' | 'private-key' | 'mpc';
|
|
5
|
+
/**
|
|
6
|
+
* Unique identifier for an entropy source.
|
|
7
|
+
*
|
|
8
|
+
* Format: `entropy:{type}:{uuid}` where the UUID is a
|
|
9
|
+
* deterministic fingerprint of the underlying secret, or `'_'` for entropies
|
|
10
|
+
* that cannot be uniquely identified.
|
|
11
|
+
*/
|
|
12
|
+
export type EntropySourceId = `entropy:${EntropySourceType}:${string}`;
|
|
13
|
+
/**
|
|
14
|
+
* Computes a deterministic, non-reversible fingerprint for a piece of entropy.
|
|
15
|
+
*
|
|
16
|
+
* The fingerprint is a UUID v4 seeded from the first 16 bytes of
|
|
17
|
+
* `HMAC-SHA256(key=material, msg='metamask:fingerprint')`.
|
|
18
|
+
*
|
|
19
|
+
* @param material - The raw entropy bytes (e.g. BIP-39 mnemonic bytes).
|
|
20
|
+
* @returns A deterministic UUID v4 string that uniquely identifies the entropy
|
|
21
|
+
* without exposing it.
|
|
22
|
+
*/
|
|
23
|
+
export declare function fingerprint(material: Uint8Array): Promise<string>;
|
|
24
|
+
/**
|
|
25
|
+
* Computes a stable {@link EntropySourceId} for an entropy source.
|
|
26
|
+
*
|
|
27
|
+
* The ID is formatted as `entropy:{type}:{uuid}`, where
|
|
28
|
+
* the UUID segment is the {@link fingerprint} of `material` when provided, or
|
|
29
|
+
* `'_'` for entropy sources whose secret never leaves the device (e.g. hardware
|
|
30
|
+
* wallets).
|
|
31
|
+
*
|
|
32
|
+
* @param type - The entropy source type (e.g. `'mnemonic'`,
|
|
33
|
+
* `'ledger'`, `'private-key'`).
|
|
34
|
+
* @param material - The raw entropy bytes. Omit for hardware wallets or any
|
|
35
|
+
* entropy source where the secret is not directly accessible.
|
|
36
|
+
* @returns A stable {@link EntropySourceId} string.
|
|
37
|
+
*/
|
|
38
|
+
export declare function toEntropySourceId(type: EntropySourceType, material?: Uint8Array): Promise<EntropySourceId>;
|
|
39
|
+
//# sourceMappingURL=entropy.d.cts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"entropy.d.cts","sourceRoot":"","sources":["../src/entropy.ts"],"names":[],"mappings":"AAIA;;GAEG;AACH,MAAM,MAAM,iBAAiB,GACzB,UAAU,GACV,QAAQ,GACR,QAAQ,GACR,IAAI,GACJ,aAAa,GACb,KAAK,CAAC;AAEV;;;;;;GAMG;AACH,MAAM,MAAM,eAAe,GAAG,WAAW,iBAAiB,IAAI,MAAM,EAAE,CAAC;AAEvE;;;;;;;;;GASG;AACH,wBAAsB,WAAW,CAAC,QAAQ,EAAE,UAAU,GAAG,OAAO,CAAC,MAAM,CAAC,CAOvE;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAsB,iBAAiB,CACrC,IAAI,EAAE,iBAAiB,EACvB,QAAQ,CAAC,EAAE,UAAU,GACpB,OAAO,CAAC,eAAe,CAAC,CAG1B"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The type of an entropy source.
|
|
3
|
+
*/
|
|
4
|
+
export type EntropySourceType = 'mnemonic' | 'ledger' | 'trezor' | 'qr' | 'private-key' | 'mpc';
|
|
5
|
+
/**
|
|
6
|
+
* Unique identifier for an entropy source.
|
|
7
|
+
*
|
|
8
|
+
* Format: `entropy:{type}:{uuid}` where the UUID is a
|
|
9
|
+
* deterministic fingerprint of the underlying secret, or `'_'` for entropies
|
|
10
|
+
* that cannot be uniquely identified.
|
|
11
|
+
*/
|
|
12
|
+
export type EntropySourceId = `entropy:${EntropySourceType}:${string}`;
|
|
13
|
+
/**
|
|
14
|
+
* Computes a deterministic, non-reversible fingerprint for a piece of entropy.
|
|
15
|
+
*
|
|
16
|
+
* The fingerprint is a UUID v4 seeded from the first 16 bytes of
|
|
17
|
+
* `HMAC-SHA256(key=material, msg='metamask:fingerprint')`.
|
|
18
|
+
*
|
|
19
|
+
* @param material - The raw entropy bytes (e.g. BIP-39 mnemonic bytes).
|
|
20
|
+
* @returns A deterministic UUID v4 string that uniquely identifies the entropy
|
|
21
|
+
* without exposing it.
|
|
22
|
+
*/
|
|
23
|
+
export declare function fingerprint(material: Uint8Array): Promise<string>;
|
|
24
|
+
/**
|
|
25
|
+
* Computes a stable {@link EntropySourceId} for an entropy source.
|
|
26
|
+
*
|
|
27
|
+
* The ID is formatted as `entropy:{type}:{uuid}`, where
|
|
28
|
+
* the UUID segment is the {@link fingerprint} of `material` when provided, or
|
|
29
|
+
* `'_'` for entropy sources whose secret never leaves the device (e.g. hardware
|
|
30
|
+
* wallets).
|
|
31
|
+
*
|
|
32
|
+
* @param type - The entropy source type (e.g. `'mnemonic'`,
|
|
33
|
+
* `'ledger'`, `'private-key'`).
|
|
34
|
+
* @param material - The raw entropy bytes. Omit for hardware wallets or any
|
|
35
|
+
* entropy source where the secret is not directly accessible.
|
|
36
|
+
* @returns A stable {@link EntropySourceId} string.
|
|
37
|
+
*/
|
|
38
|
+
export declare function toEntropySourceId(type: EntropySourceType, material?: Uint8Array): Promise<EntropySourceId>;
|
|
39
|
+
//# sourceMappingURL=entropy.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"entropy.d.mts","sourceRoot":"","sources":["../src/entropy.ts"],"names":[],"mappings":"AAIA;;GAEG;AACH,MAAM,MAAM,iBAAiB,GACzB,UAAU,GACV,QAAQ,GACR,QAAQ,GACR,IAAI,GACJ,aAAa,GACb,KAAK,CAAC;AAEV;;;;;;GAMG;AACH,MAAM,MAAM,eAAe,GAAG,WAAW,iBAAiB,IAAI,MAAM,EAAE,CAAC;AAEvE;;;;;;;;;GASG;AACH,wBAAsB,WAAW,CAAC,QAAQ,EAAE,UAAU,GAAG,OAAO,CAAC,MAAM,CAAC,CAOvE;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAsB,iBAAiB,CACrC,IAAI,EAAE,iBAAiB,EACvB,QAAQ,CAAC,EAAE,UAAU,GACpB,OAAO,CAAC,eAAe,CAAC,CAG1B"}
|
package/dist/entropy.mjs
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { hmac } from "@noble/hashes/hmac";
|
|
2
|
+
import { sha256 } from "@noble/hashes/sha2";
|
|
3
|
+
import { v4 as uuid } from "uuid";
|
|
4
|
+
/**
|
|
5
|
+
* Computes a deterministic, non-reversible fingerprint for a piece of entropy.
|
|
6
|
+
*
|
|
7
|
+
* The fingerprint is a UUID v4 seeded from the first 16 bytes of
|
|
8
|
+
* `HMAC-SHA256(key=material, msg='metamask:fingerprint')`.
|
|
9
|
+
*
|
|
10
|
+
* @param material - The raw entropy bytes (e.g. BIP-39 mnemonic bytes).
|
|
11
|
+
* @returns A deterministic UUID v4 string that uniquely identifies the entropy
|
|
12
|
+
* without exposing it.
|
|
13
|
+
*/
|
|
14
|
+
export async function fingerprint(material) {
|
|
15
|
+
const message = new TextEncoder().encode('metamask:fingerprint');
|
|
16
|
+
// `@noble/hashes` is synchronous today, but the async signature is kept as a
|
|
17
|
+
// forward-compatible seam: a future migration to the Web Crypto API (or any
|
|
18
|
+
// other async primitive) won't require changes at every call site.
|
|
19
|
+
const digest = hmac(sha256, material, message);
|
|
20
|
+
return uuid({ random: digest.slice(0, 16) });
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Computes a stable {@link EntropySourceId} for an entropy source.
|
|
24
|
+
*
|
|
25
|
+
* The ID is formatted as `entropy:{type}:{uuid}`, where
|
|
26
|
+
* the UUID segment is the {@link fingerprint} of `material` when provided, or
|
|
27
|
+
* `'_'` for entropy sources whose secret never leaves the device (e.g. hardware
|
|
28
|
+
* wallets).
|
|
29
|
+
*
|
|
30
|
+
* @param type - The entropy source type (e.g. `'mnemonic'`,
|
|
31
|
+
* `'ledger'`, `'private-key'`).
|
|
32
|
+
* @param material - The raw entropy bytes. Omit for hardware wallets or any
|
|
33
|
+
* entropy source where the secret is not directly accessible.
|
|
34
|
+
* @returns A stable {@link EntropySourceId} string.
|
|
35
|
+
*/
|
|
36
|
+
export async function toEntropySourceId(type, material) {
|
|
37
|
+
const entropyFingerprint = material ? await fingerprint(material) : '_';
|
|
38
|
+
return `entropy:${type}:${entropyFingerprint}`;
|
|
39
|
+
}
|
|
40
|
+
//# sourceMappingURL=entropy.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"entropy.mjs","sourceRoot":"","sources":["../src/entropy.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,2BAA2B;AAC1C,OAAO,EAAE,MAAM,EAAE,2BAA2B;AAC5C,OAAO,EAAE,EAAE,IAAI,IAAI,EAAE,aAAa;AAsBlC;;;;;;;;;GASG;AACH,MAAM,CAAC,KAAK,UAAU,WAAW,CAAC,QAAoB;IACpD,MAAM,OAAO,GAAG,IAAI,WAAW,EAAE,CAAC,MAAM,CAAC,sBAAsB,CAAC,CAAC;IACjE,6EAA6E;IAC7E,4EAA4E;IAC5E,mEAAmE;IACnE,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,EAAE,QAAQ,EAAE,OAAO,CAAC,CAAC;IAC/C,OAAO,IAAI,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,EAAE,CAAC,CAAC;AAC/C,CAAC;AAED;;;;;;;;;;;;;GAaG;AACH,MAAM,CAAC,KAAK,UAAU,iBAAiB,CACrC,IAAuB,EACvB,QAAqB;IAErB,MAAM,kBAAkB,GAAG,QAAQ,CAAC,CAAC,CAAC,MAAM,WAAW,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC;IACxE,OAAO,WAAW,IAAI,IAAI,kBAAkB,EAAE,CAAC;AACjD,CAAC","sourcesContent":["import { hmac } from '@noble/hashes/hmac';\nimport { sha256 } from '@noble/hashes/sha2';\nimport { v4 as uuid } from 'uuid';\n\n/**\n * The type of an entropy source.\n */\nexport type EntropySourceType =\n | 'mnemonic'\n | 'ledger'\n | 'trezor'\n | 'qr'\n | 'private-key'\n | 'mpc';\n\n/**\n * Unique identifier for an entropy source.\n *\n * Format: `entropy:{type}:{uuid}` where the UUID is a\n * deterministic fingerprint of the underlying secret, or `'_'` for entropies\n * that cannot be uniquely identified.\n */\nexport type EntropySourceId = `entropy:${EntropySourceType}:${string}`;\n\n/**\n * Computes a deterministic, non-reversible fingerprint for a piece of entropy.\n *\n * The fingerprint is a UUID v4 seeded from the first 16 bytes of\n * `HMAC-SHA256(key=material, msg='metamask:fingerprint')`.\n *\n * @param material - The raw entropy bytes (e.g. BIP-39 mnemonic bytes).\n * @returns A deterministic UUID v4 string that uniquely identifies the entropy\n * without exposing it.\n */\nexport async function fingerprint(material: Uint8Array): Promise<string> {\n const message = new TextEncoder().encode('metamask:fingerprint');\n // `@noble/hashes` is synchronous today, but the async signature is kept as a\n // forward-compatible seam: a future migration to the Web Crypto API (or any\n // other async primitive) won't require changes at every call site.\n const digest = hmac(sha256, material, message);\n return uuid({ random: digest.slice(0, 16) });\n}\n\n/**\n * Computes a stable {@link EntropySourceId} for an entropy source.\n *\n * The ID is formatted as `entropy:{type}:{uuid}`, where\n * the UUID segment is the {@link fingerprint} of `material` when provided, or\n * `'_'` for entropy sources whose secret never leaves the device (e.g. hardware\n * wallets).\n *\n * @param type - The entropy source type (e.g. `'mnemonic'`,\n * `'ledger'`, `'private-key'`).\n * @param material - The raw entropy bytes. Omit for hardware wallets or any\n * entropy source where the secret is not directly accessible.\n * @returns A stable {@link EntropySourceId} string.\n */\nexport async function toEntropySourceId(\n type: EntropySourceType,\n material?: Uint8Array,\n): Promise<EntropySourceId> {\n const entropyFingerprint = material ? await fingerprint(material) : '_';\n return `entropy:${type}:${entropyFingerprint}`;\n}\n"]}
|
package/dist/index.cjs
CHANGED
|
@@ -15,6 +15,8 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
|
15
15
|
};
|
|
16
16
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
17
|
__exportStar(require("./keyring-account-registry.cjs"), exports);
|
|
18
|
+
__exportStar(require("./migration.cjs"), exports);
|
|
18
19
|
__exportStar(require("./mnemonic.cjs"), exports);
|
|
20
|
+
__exportStar(require("./entropy.cjs"), exports);
|
|
19
21
|
__exportStar(require("./eth/index.cjs"), exports);
|
|
20
22
|
//# sourceMappingURL=index.cjs.map
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.cjs","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,iEAA2C;AAC3C,iDAA2B;AAC3B,kDAAsB","sourcesContent":["export * from './keyring-account-registry';\nexport * from './mnemonic';\nexport * from './eth';\n"]}
|
|
1
|
+
{"version":3,"file":"index.cjs","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,iEAA2C;AAC3C,kDAA4B;AAC5B,iDAA2B;AAC3B,gDAA0B;AAC1B,kDAAsB","sourcesContent":["export * from './keyring-account-registry';\nexport * from './migration';\nexport * from './mnemonic';\nexport * from './entropy';\nexport * from './eth';\n"]}
|
package/dist/index.d.cts
CHANGED
package/dist/index.d.cts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.cts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,+CAA2C;AAC3C,+BAA2B;AAC3B,gCAAsB"}
|
|
1
|
+
{"version":3,"file":"index.d.cts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,+CAA2C;AAC3C,gCAA4B;AAC5B,+BAA2B;AAC3B,8BAA0B;AAC1B,gCAAsB"}
|
package/dist/index.d.mts
CHANGED
package/dist/index.d.mts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.mts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,+CAA2C;AAC3C,+BAA2B;AAC3B,gCAAsB"}
|
|
1
|
+
{"version":3,"file":"index.d.mts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,+CAA2C;AAC3C,gCAA4B;AAC5B,+BAA2B;AAC3B,8BAA0B;AAC1B,gCAAsB"}
|
package/dist/index.mjs
CHANGED
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.mjs","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,+CAA2C;AAC3C,+BAA2B;AAC3B,gCAAsB","sourcesContent":["export * from './keyring-account-registry';\nexport * from './mnemonic';\nexport * from './eth';\n"]}
|
|
1
|
+
{"version":3,"file":"index.mjs","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,+CAA2C;AAC3C,gCAA4B;AAC5B,+BAA2B;AAC3B,8BAA0B;AAC1B,gCAAsB","sourcesContent":["export * from './keyring-account-registry';\nexport * from './migration';\nexport * from './mnemonic';\nexport * from './entropy';\nexport * from './eth';\n"]}
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.createMigrations = exports.isVersionedState = exports.VersionedStateStruct = void 0;
|
|
4
|
+
const superstruct_1 = require("@metamask/superstruct");
|
|
5
|
+
const utils_1 = require("@metamask/utils");
|
|
6
|
+
/**
|
|
7
|
+
* Superstruct schema for the versioned state envelope.
|
|
8
|
+
*/
|
|
9
|
+
exports.VersionedStateStruct = (0, superstruct_1.object)({
|
|
10
|
+
version: (0, superstruct_1.integer)(),
|
|
11
|
+
data: utils_1.JsonStruct,
|
|
12
|
+
});
|
|
13
|
+
/**
|
|
14
|
+
* Type guard to check if a value is a {@link VersionedState} envelope.
|
|
15
|
+
*
|
|
16
|
+
* @param state - The value to check.
|
|
17
|
+
* @returns `true` if the value is a versioned state envelope.
|
|
18
|
+
*/
|
|
19
|
+
function isVersionedState(state) {
|
|
20
|
+
return (0, superstruct_1.is)(state, exports.VersionedStateStruct);
|
|
21
|
+
}
|
|
22
|
+
exports.isVersionedState = isVersionedState;
|
|
23
|
+
/**
|
|
24
|
+
* Get the version and data from state, treating unversioned state as version 0.
|
|
25
|
+
*
|
|
26
|
+
* @param state - The state to check.
|
|
27
|
+
* @returns The version and data.
|
|
28
|
+
*/
|
|
29
|
+
function getVersionAndData(state) {
|
|
30
|
+
return isVersionedState(state)
|
|
31
|
+
? { version: state.version, data: state.data }
|
|
32
|
+
: { version: 0, data: state };
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Apply the pending steps of a chain to `state`.
|
|
36
|
+
*
|
|
37
|
+
* Implements {@link MigrationChain.apply} for the chain built from `steps`.
|
|
38
|
+
*
|
|
39
|
+
* @param steps - All steps of the chain.
|
|
40
|
+
* @param state - The serialized keyring state.
|
|
41
|
+
* @returns The migrated state wrapped in a versioned envelope, plus a `migrated` flag.
|
|
42
|
+
*/
|
|
43
|
+
async function applySteps(steps, state) {
|
|
44
|
+
const latestVersion = steps.length;
|
|
45
|
+
const { version, data: initialData } = getVersionAndData(state);
|
|
46
|
+
if (version < 0) {
|
|
47
|
+
throw new Error(`State version ${version} is invalid; it cannot be negative`);
|
|
48
|
+
}
|
|
49
|
+
if (version > latestVersion) {
|
|
50
|
+
throw new Error(`State version ${version} is newer than the latest migration version ${latestVersion}`);
|
|
51
|
+
}
|
|
52
|
+
const pendingSteps = steps.slice(version);
|
|
53
|
+
let data = initialData;
|
|
54
|
+
for (const step of pendingSteps) {
|
|
55
|
+
(0, superstruct_1.assert)(data, step.inputSchema ?? utils_1.JsonStruct);
|
|
56
|
+
data = await step.migrate(data);
|
|
57
|
+
(0, superstruct_1.assert)(data, step.outputSchema ?? utils_1.JsonStruct);
|
|
58
|
+
}
|
|
59
|
+
return {
|
|
60
|
+
version: latestVersion,
|
|
61
|
+
data,
|
|
62
|
+
migrated: pendingSteps.length > 0,
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Build a {@link MigrationChain} wrapping the given internal steps.
|
|
67
|
+
*
|
|
68
|
+
* @param steps - The steps accumulated so far.
|
|
69
|
+
* @returns A chain exposing `add`, `version`, and `apply`.
|
|
70
|
+
*/
|
|
71
|
+
function buildChain(steps) {
|
|
72
|
+
return {
|
|
73
|
+
version: steps.length,
|
|
74
|
+
add: (step) => buildChain([...steps, step]),
|
|
75
|
+
apply: async (state) => applySteps(steps, state),
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Start a new, empty migration chain.
|
|
80
|
+
*
|
|
81
|
+
* @example
|
|
82
|
+
* ```typescript
|
|
83
|
+
* const migrations = createMigrations()
|
|
84
|
+
* .add({ migrate: (data) => ({ count: data.numberOfItems }) })
|
|
85
|
+
* .add({ migrate: (data) => ({ ...data, createdAt: Date.now() }) }); // data typed as the first step's output, no cast
|
|
86
|
+
*
|
|
87
|
+
* const { data } = await migrations.apply(state);
|
|
88
|
+
* ```
|
|
89
|
+
* @returns An empty chain, typed to accept `Json` as its first step's input.
|
|
90
|
+
*/
|
|
91
|
+
function createMigrations() {
|
|
92
|
+
return buildChain([]);
|
|
93
|
+
}
|
|
94
|
+
exports.createMigrations = createMigrations;
|
|
95
|
+
//# sourceMappingURL=migration.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"migration.cjs","sourceRoot":"","sources":["../src/migration.ts"],"names":[],"mappings":";;;AACA,uDAAoE;AACpE,2CAA6C;AAG7C;;GAEG;AACU,QAAA,oBAAoB,GAAG,IAAA,oBAAM,EAAC;IACzC,OAAO,EAAE,IAAA,qBAAO,GAAE;IAClB,IAAI,EAAE,kBAAU;CACjB,CAAC,CAAC;AA4BH;;;;;GAKG;AACH,SAAgB,gBAAgB,CAC9B,KAAoC;IAEpC,OAAO,IAAA,gBAAE,EAAC,KAAK,EAAE,4BAAoB,CAAC,CAAC;AACzC,CAAC;AAJD,4CAIC;AAED;;;;;GAKG;AACH,SAAS,iBAAiB,CACxB,KAAoC;IAEpC,OAAO,gBAAgB,CAAC,KAAK,CAAC;QAC5B,CAAC,CAAC,EAAE,OAAO,EAAE,KAAK,CAAC,OAAO,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,EAAE;QAC9C,CAAC,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC;AAClC,CAAC;AA8ED;;;;;;;;GAQG;AACH,KAAK,UAAU,UAAU,CACvB,KAA+B,EAC/B,KAAW;IAEX,MAAM,aAAa,GAAG,KAAK,CAAC,MAAM,CAAC;IACnC,MAAM,EAAE,OAAO,EAAE,IAAI,EAAE,WAAW,EAAE,GAAG,iBAAiB,CAAC,KAAK,CAAC,CAAC;IAEhE,IAAI,OAAO,GAAG,CAAC,EAAE,CAAC;QAChB,MAAM,IAAI,KAAK,CACb,iBAAiB,OAAO,oCAAoC,CAC7D,CAAC;IACJ,CAAC;IAED,IAAI,OAAO,GAAG,aAAa,EAAE,CAAC;QAC5B,MAAM,IAAI,KAAK,CACb,iBAAiB,OAAO,+CAA+C,aAAa,EAAE,CACvF,CAAC;IACJ,CAAC;IAED,MAAM,YAAY,GAAG,KAAK,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;IAC1C,IAAI,IAAI,GAAG,WAAW,CAAC;IAEvB,KAAK,MAAM,IAAI,IAAI,YAAY,EAAE,CAAC;QAChC,IAAA,oBAAM,EAAC,IAAI,EAAE,IAAI,CAAC,WAAW,IAAI,kBAAU,CAAC,CAAC;QAC7C,IAAI,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;QAChC,IAAA,oBAAM,EAAC,IAAI,EAAE,IAAI,CAAC,YAAY,IAAI,kBAAU,CAAC,CAAC;IAChD,CAAC;IAED,OAAO;QACL,OAAO,EAAE,aAAa;QACtB,IAAI;QACJ,QAAQ,EAAE,YAAY,CAAC,MAAM,GAAG,CAAC;KACT,CAAC;AAC7B,CAAC;AAED;;;;;GAKG;AACH,SAAS,UAAU,CACjB,KAA+B;IAE/B,OAAO;QACL,OAAO,EAAE,KAAK,CAAC,MAAM;QACrB,GAAG,EAAE,CACH,IAAkC,EAClC,EAAE,CAAC,UAAU,CAAS,CAAC,GAAG,KAAK,EAAE,IAAgC,CAAC,CAAC;QACrE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,EAAE,CAAC,UAAU,CAAO,KAAK,EAAE,KAAK,CAAC;KACvD,CAAC;AACJ,CAAC;AAED;;;;;;;;;;;;GAYG;AACH,SAAgB,gBAAgB;IAC9B,OAAO,UAAU,CAAO,EAAE,CAAC,CAAC;AAC9B,CAAC;AAFD,4CAEC","sourcesContent":["import type { Infer, Struct } from '@metamask/superstruct';\nimport { assert, integer, is, object } from '@metamask/superstruct';\nimport { JsonStruct } from '@metamask/utils';\nimport type { Json } from '@metamask/utils';\n\n/**\n * Superstruct schema for the versioned state envelope.\n */\nexport const VersionedStateStruct = object({\n version: integer(),\n data: JsonStruct,\n});\n\n/**\n * Versioned state envelope wrapping the actual keyring data.\n *\n * After migrations are applied, state is always wrapped in this format. `serialize()`\n * should produce this envelope so that subsequent `deserialize()` calls can detect the\n * version.\n */\nexport type VersionedState<Data extends Json = Json> = Omit<\n Infer<typeof VersionedStateStruct>,\n 'data'\n> & {\n data: Data;\n};\n\n/**\n * Return value of {@link MigrationChain.apply}.\n *\n * Extends {@link VersionedState} with a `migrated` flag that is `true` when at least\n * one step was applied during the call. Callers can use this to detect that the\n * in-memory state has been upgraded and schedule a persist so the new version is\n * written to storage, even when no other state change happens in the session.\n */\nexport type MigrationResult<Data extends Json = Json> = VersionedState<Data> & {\n migrated: boolean;\n};\n\n/**\n * Type guard to check if a value is a {@link VersionedState} envelope.\n *\n * @param state - The value to check.\n * @returns `true` if the value is a versioned state envelope.\n */\nexport function isVersionedState<State extends Json = Json>(\n state: State | VersionedState<State>,\n): state is VersionedState<State> {\n return is(state, VersionedStateStruct);\n}\n\n/**\n * Get the version and data from state, treating unversioned state as version 0.\n *\n * @param state - The state to check.\n * @returns The version and data.\n */\nfunction getVersionAndData<State extends Json = Json>(\n state: State | VersionedState<State>,\n): VersionedState<State> {\n return isVersionedState(state)\n ? { version: state.version, data: state.data }\n : { version: 0, data: state };\n}\n\n/**\n * A single migration step, added to a {@link MigrationChain} via `.add()`.\n *\n * `Input` is bound automatically to the chain's current data type when the step is\n * passed to `.add()`, so `migrate` receives a correctly typed argument with no manual\n * cast.\n */\nexport type MigrationStep<\n Input extends Json = Json,\n Output extends Json = Json,\n> = {\n /**\n * Transform state from the previous step's output to this step's output.\n *\n * Receives the raw inner data (not the versioned envelope). May be sync or async to\n * support complex operations like re-deriving data from secrets.\n *\n * @param data - The state data from the previous step.\n * @returns The migrated data.\n */\n migrate(data: Input): Output | Promise<Output>;\n /**\n * Optional schema validating this step's input before `migrate` is called. Defaults\n * to a generic JSON-shape check when omitted.\n */\n inputSchema?: Struct<Input>;\n /**\n * Optional schema validating this step's output at runtime.\n */\n outputSchema?: Struct<Output>;\n};\n\n/**\n * A chain of migration steps for evolving keyring serialized state across versions.\n *\n * Steps are versioned by position: the first `.add()` call produces version 1, the\n * second version 2, and so on. Create one with {@link createMigrations}.\n */\nexport type MigrationChain<Data extends Json = Json> = {\n /**\n * The number of steps added so far. Since steps are versioned by position starting at\n * 1, this also doubles as \"the latest version\" (use it in `serialize()`).\n */\n readonly version: number;\n /**\n * Append a step to the chain.\n *\n * Returns a new chain typed to `Output`. It does not mutate the chain it's called on,\n * so branching from a shared base chain is safe.\n *\n * `Input` defaults to the chain's current `Data` type. Providing `inputSchema` lets\n * TypeScript infer a narrower `Input` (bounded to extend `Data`), so `migrate`\n * receives a schema-typed argument when narrowing raw state into a specific shape,\n * typically on a chain's first step, where `Data` is `Json`.\n *\n * @param step - The migration step to append.\n * @returns A new chain whose data type is the step's `Output`.\n */\n add<Input extends Data = Data, Output extends Json = Json>(\n step: MigrationStep<Input, Output>,\n ): MigrationChain<Output>;\n /**\n * Apply all pending steps to `state`.\n *\n * Handles both versioned state (wrapped in `{ version, data }` envelope) and\n * unversioned legacy state (treated as version 0).\n *\n * @param state - The serialized keyring state (from vault or previous serialize).\n * @returns The migrated state wrapped in a versioned envelope, plus a `migrated`\n * flag.\n * @throws If `state`'s version is newer than this chain's latest version, or if a\n * step's `inputSchema`/`outputSchema` validation fails.\n */\n apply(state: Json): Promise<MigrationResult<Data>>;\n};\n\n/**\n * Apply the pending steps of a chain to `state`.\n *\n * Implements {@link MigrationChain.apply} for the chain built from `steps`.\n *\n * @param steps - All steps of the chain.\n * @param state - The serialized keyring state.\n * @returns The migrated state wrapped in a versioned envelope, plus a `migrated` flag.\n */\nasync function applySteps<Data extends Json>(\n steps: readonly MigrationStep[],\n state: Json,\n): Promise<MigrationResult<Data>> {\n const latestVersion = steps.length;\n const { version, data: initialData } = getVersionAndData(state);\n\n if (version < 0) {\n throw new Error(\n `State version ${version} is invalid; it cannot be negative`,\n );\n }\n\n if (version > latestVersion) {\n throw new Error(\n `State version ${version} is newer than the latest migration version ${latestVersion}`,\n );\n }\n\n const pendingSteps = steps.slice(version);\n let data = initialData;\n\n for (const step of pendingSteps) {\n assert(data, step.inputSchema ?? JsonStruct);\n data = await step.migrate(data);\n assert(data, step.outputSchema ?? JsonStruct);\n }\n\n return {\n version: latestVersion,\n data,\n migrated: pendingSteps.length > 0,\n } as MigrationResult<Data>;\n}\n\n/**\n * Build a {@link MigrationChain} wrapping the given internal steps.\n *\n * @param steps - The steps accumulated so far.\n * @returns A chain exposing `add`, `version`, and `apply`.\n */\nfunction buildChain<Data extends Json>(\n steps: readonly MigrationStep[],\n): MigrationChain<Data> {\n return {\n version: steps.length,\n add: <Input extends Data, Output extends Json>(\n step: MigrationStep<Input, Output>,\n ) => buildChain<Output>([...steps, step as unknown as MigrationStep]),\n apply: async (state) => applySteps<Data>(steps, state),\n };\n}\n\n/**\n * Start a new, empty migration chain.\n *\n * @example\n * ```typescript\n * const migrations = createMigrations()\n * .add({ migrate: (data) => ({ count: data.numberOfItems }) })\n * .add({ migrate: (data) => ({ ...data, createdAt: Date.now() }) }); // data typed as the first step's output, no cast\n *\n * const { data } = await migrations.apply(state);\n * ```\n * @returns An empty chain, typed to accept `Json` as its first step's input.\n */\nexport function createMigrations(): MigrationChain<Json> {\n return buildChain<Json>([]);\n}\n"]}
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
import type { Infer, Struct } from "@metamask/superstruct";
|
|
2
|
+
import type { Json } from "@metamask/utils";
|
|
3
|
+
/**
|
|
4
|
+
* Superstruct schema for the versioned state envelope.
|
|
5
|
+
*/
|
|
6
|
+
export declare const VersionedStateStruct: Struct<{
|
|
7
|
+
data: Json;
|
|
8
|
+
version: number;
|
|
9
|
+
}, {
|
|
10
|
+
version: Struct<number, null>;
|
|
11
|
+
data: Struct<Json, unknown>;
|
|
12
|
+
}>;
|
|
13
|
+
/**
|
|
14
|
+
* Versioned state envelope wrapping the actual keyring data.
|
|
15
|
+
*
|
|
16
|
+
* After migrations are applied, state is always wrapped in this format. `serialize()`
|
|
17
|
+
* should produce this envelope so that subsequent `deserialize()` calls can detect the
|
|
18
|
+
* version.
|
|
19
|
+
*/
|
|
20
|
+
export type VersionedState<Data extends Json = Json> = Omit<Infer<typeof VersionedStateStruct>, 'data'> & {
|
|
21
|
+
data: Data;
|
|
22
|
+
};
|
|
23
|
+
/**
|
|
24
|
+
* Return value of {@link MigrationChain.apply}.
|
|
25
|
+
*
|
|
26
|
+
* Extends {@link VersionedState} with a `migrated` flag that is `true` when at least
|
|
27
|
+
* one step was applied during the call. Callers can use this to detect that the
|
|
28
|
+
* in-memory state has been upgraded and schedule a persist so the new version is
|
|
29
|
+
* written to storage, even when no other state change happens in the session.
|
|
30
|
+
*/
|
|
31
|
+
export type MigrationResult<Data extends Json = Json> = VersionedState<Data> & {
|
|
32
|
+
migrated: boolean;
|
|
33
|
+
};
|
|
34
|
+
/**
|
|
35
|
+
* Type guard to check if a value is a {@link VersionedState} envelope.
|
|
36
|
+
*
|
|
37
|
+
* @param state - The value to check.
|
|
38
|
+
* @returns `true` if the value is a versioned state envelope.
|
|
39
|
+
*/
|
|
40
|
+
export declare function isVersionedState<State extends Json = Json>(state: State | VersionedState<State>): state is VersionedState<State>;
|
|
41
|
+
/**
|
|
42
|
+
* A single migration step, added to a {@link MigrationChain} via `.add()`.
|
|
43
|
+
*
|
|
44
|
+
* `Input` is bound automatically to the chain's current data type when the step is
|
|
45
|
+
* passed to `.add()`, so `migrate` receives a correctly typed argument with no manual
|
|
46
|
+
* cast.
|
|
47
|
+
*/
|
|
48
|
+
export type MigrationStep<Input extends Json = Json, Output extends Json = Json> = {
|
|
49
|
+
/**
|
|
50
|
+
* Transform state from the previous step's output to this step's output.
|
|
51
|
+
*
|
|
52
|
+
* Receives the raw inner data (not the versioned envelope). May be sync or async to
|
|
53
|
+
* support complex operations like re-deriving data from secrets.
|
|
54
|
+
*
|
|
55
|
+
* @param data - The state data from the previous step.
|
|
56
|
+
* @returns The migrated data.
|
|
57
|
+
*/
|
|
58
|
+
migrate(data: Input): Output | Promise<Output>;
|
|
59
|
+
/**
|
|
60
|
+
* Optional schema validating this step's input before `migrate` is called. Defaults
|
|
61
|
+
* to a generic JSON-shape check when omitted.
|
|
62
|
+
*/
|
|
63
|
+
inputSchema?: Struct<Input>;
|
|
64
|
+
/**
|
|
65
|
+
* Optional schema validating this step's output at runtime.
|
|
66
|
+
*/
|
|
67
|
+
outputSchema?: Struct<Output>;
|
|
68
|
+
};
|
|
69
|
+
/**
|
|
70
|
+
* A chain of migration steps for evolving keyring serialized state across versions.
|
|
71
|
+
*
|
|
72
|
+
* Steps are versioned by position: the first `.add()` call produces version 1, the
|
|
73
|
+
* second version 2, and so on. Create one with {@link createMigrations}.
|
|
74
|
+
*/
|
|
75
|
+
export type MigrationChain<Data extends Json = Json> = {
|
|
76
|
+
/**
|
|
77
|
+
* The number of steps added so far. Since steps are versioned by position starting at
|
|
78
|
+
* 1, this also doubles as "the latest version" (use it in `serialize()`).
|
|
79
|
+
*/
|
|
80
|
+
readonly version: number;
|
|
81
|
+
/**
|
|
82
|
+
* Append a step to the chain.
|
|
83
|
+
*
|
|
84
|
+
* Returns a new chain typed to `Output`. It does not mutate the chain it's called on,
|
|
85
|
+
* so branching from a shared base chain is safe.
|
|
86
|
+
*
|
|
87
|
+
* `Input` defaults to the chain's current `Data` type. Providing `inputSchema` lets
|
|
88
|
+
* TypeScript infer a narrower `Input` (bounded to extend `Data`), so `migrate`
|
|
89
|
+
* receives a schema-typed argument when narrowing raw state into a specific shape,
|
|
90
|
+
* typically on a chain's first step, where `Data` is `Json`.
|
|
91
|
+
*
|
|
92
|
+
* @param step - The migration step to append.
|
|
93
|
+
* @returns A new chain whose data type is the step's `Output`.
|
|
94
|
+
*/
|
|
95
|
+
add<Input extends Data = Data, Output extends Json = Json>(step: MigrationStep<Input, Output>): MigrationChain<Output>;
|
|
96
|
+
/**
|
|
97
|
+
* Apply all pending steps to `state`.
|
|
98
|
+
*
|
|
99
|
+
* Handles both versioned state (wrapped in `{ version, data }` envelope) and
|
|
100
|
+
* unversioned legacy state (treated as version 0).
|
|
101
|
+
*
|
|
102
|
+
* @param state - The serialized keyring state (from vault or previous serialize).
|
|
103
|
+
* @returns The migrated state wrapped in a versioned envelope, plus a `migrated`
|
|
104
|
+
* flag.
|
|
105
|
+
* @throws If `state`'s version is newer than this chain's latest version, or if a
|
|
106
|
+
* step's `inputSchema`/`outputSchema` validation fails.
|
|
107
|
+
*/
|
|
108
|
+
apply(state: Json): Promise<MigrationResult<Data>>;
|
|
109
|
+
};
|
|
110
|
+
/**
|
|
111
|
+
* Start a new, empty migration chain.
|
|
112
|
+
*
|
|
113
|
+
* @example
|
|
114
|
+
* ```typescript
|
|
115
|
+
* const migrations = createMigrations()
|
|
116
|
+
* .add({ migrate: (data) => ({ count: data.numberOfItems }) })
|
|
117
|
+
* .add({ migrate: (data) => ({ ...data, createdAt: Date.now() }) }); // data typed as the first step's output, no cast
|
|
118
|
+
*
|
|
119
|
+
* const { data } = await migrations.apply(state);
|
|
120
|
+
* ```
|
|
121
|
+
* @returns An empty chain, typed to accept `Json` as its first step's input.
|
|
122
|
+
*/
|
|
123
|
+
export declare function createMigrations(): MigrationChain<Json>;
|
|
124
|
+
//# sourceMappingURL=migration.d.cts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"migration.d.cts","sourceRoot":"","sources":["../src/migration.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,8BAA8B;AAG3D,OAAO,KAAK,EAAE,IAAI,EAAE,wBAAwB;AAE5C;;GAEG;AACH,eAAO,MAAM,oBAAoB;;;;;;EAG/B,CAAC;AAEH;;;;;;GAMG;AACH,MAAM,MAAM,cAAc,CAAC,IAAI,SAAS,IAAI,GAAG,IAAI,IAAI,IAAI,CACzD,KAAK,CAAC,OAAO,oBAAoB,CAAC,EAClC,MAAM,CACP,GAAG;IACF,IAAI,EAAE,IAAI,CAAC;CACZ,CAAC;AAEF;;;;;;;GAOG;AACH,MAAM,MAAM,eAAe,CAAC,IAAI,SAAS,IAAI,GAAG,IAAI,IAAI,cAAc,CAAC,IAAI,CAAC,GAAG;IAC7E,QAAQ,EAAE,OAAO,CAAC;CACnB,CAAC;AAEF;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,SAAS,IAAI,GAAG,IAAI,EACxD,KAAK,EAAE,KAAK,GAAG,cAAc,CAAC,KAAK,CAAC,GACnC,KAAK,IAAI,cAAc,CAAC,KAAK,CAAC,CAEhC;AAgBD;;;;;;GAMG;AACH,MAAM,MAAM,aAAa,CACvB,KAAK,SAAS,IAAI,GAAG,IAAI,EACzB,MAAM,SAAS,IAAI,GAAG,IAAI,IACxB;IACF;;;;;;;;OAQG;IACH,OAAO,CAAC,IAAI,EAAE,KAAK,GAAG,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IAC/C;;;OAGG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC,KAAK,CAAC,CAAC;IAC5B;;OAEG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC;CAC/B,CAAC;AAEF;;;;;GAKG;AACH,MAAM,MAAM,cAAc,CAAC,IAAI,SAAS,IAAI,GAAG,IAAI,IAAI;IACrD;;;OAGG;IACH,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB;;;;;;;;;;;;;OAaG;IACH,GAAG,CAAC,KAAK,SAAS,IAAI,GAAG,IAAI,EAAE,MAAM,SAAS,IAAI,GAAG,IAAI,EACvD,IAAI,EAAE,aAAa,CAAC,KAAK,EAAE,MAAM,CAAC,GACjC,cAAc,CAAC,MAAM,CAAC,CAAC;IAC1B;;;;;;;;;;;OAWG;IACH,KAAK,CAAC,KAAK,EAAE,IAAI,GAAG,OAAO,CAAC,eAAe,CAAC,IAAI,CAAC,CAAC,CAAC;CACpD,CAAC;AAgEF;;;;;;;;;;;;GAYG;AACH,wBAAgB,gBAAgB,IAAI,cAAc,CAAC,IAAI,CAAC,CAEvD"}
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
import type { Infer, Struct } from "@metamask/superstruct";
|
|
2
|
+
import type { Json } from "@metamask/utils";
|
|
3
|
+
/**
|
|
4
|
+
* Superstruct schema for the versioned state envelope.
|
|
5
|
+
*/
|
|
6
|
+
export declare const VersionedStateStruct: Struct<{
|
|
7
|
+
data: Json;
|
|
8
|
+
version: number;
|
|
9
|
+
}, {
|
|
10
|
+
version: Struct<number, null>;
|
|
11
|
+
data: Struct<Json, unknown>;
|
|
12
|
+
}>;
|
|
13
|
+
/**
|
|
14
|
+
* Versioned state envelope wrapping the actual keyring data.
|
|
15
|
+
*
|
|
16
|
+
* After migrations are applied, state is always wrapped in this format. `serialize()`
|
|
17
|
+
* should produce this envelope so that subsequent `deserialize()` calls can detect the
|
|
18
|
+
* version.
|
|
19
|
+
*/
|
|
20
|
+
export type VersionedState<Data extends Json = Json> = Omit<Infer<typeof VersionedStateStruct>, 'data'> & {
|
|
21
|
+
data: Data;
|
|
22
|
+
};
|
|
23
|
+
/**
|
|
24
|
+
* Return value of {@link MigrationChain.apply}.
|
|
25
|
+
*
|
|
26
|
+
* Extends {@link VersionedState} with a `migrated` flag that is `true` when at least
|
|
27
|
+
* one step was applied during the call. Callers can use this to detect that the
|
|
28
|
+
* in-memory state has been upgraded and schedule a persist so the new version is
|
|
29
|
+
* written to storage, even when no other state change happens in the session.
|
|
30
|
+
*/
|
|
31
|
+
export type MigrationResult<Data extends Json = Json> = VersionedState<Data> & {
|
|
32
|
+
migrated: boolean;
|
|
33
|
+
};
|
|
34
|
+
/**
|
|
35
|
+
* Type guard to check if a value is a {@link VersionedState} envelope.
|
|
36
|
+
*
|
|
37
|
+
* @param state - The value to check.
|
|
38
|
+
* @returns `true` if the value is a versioned state envelope.
|
|
39
|
+
*/
|
|
40
|
+
export declare function isVersionedState<State extends Json = Json>(state: State | VersionedState<State>): state is VersionedState<State>;
|
|
41
|
+
/**
|
|
42
|
+
* A single migration step, added to a {@link MigrationChain} via `.add()`.
|
|
43
|
+
*
|
|
44
|
+
* `Input` is bound automatically to the chain's current data type when the step is
|
|
45
|
+
* passed to `.add()`, so `migrate` receives a correctly typed argument with no manual
|
|
46
|
+
* cast.
|
|
47
|
+
*/
|
|
48
|
+
export type MigrationStep<Input extends Json = Json, Output extends Json = Json> = {
|
|
49
|
+
/**
|
|
50
|
+
* Transform state from the previous step's output to this step's output.
|
|
51
|
+
*
|
|
52
|
+
* Receives the raw inner data (not the versioned envelope). May be sync or async to
|
|
53
|
+
* support complex operations like re-deriving data from secrets.
|
|
54
|
+
*
|
|
55
|
+
* @param data - The state data from the previous step.
|
|
56
|
+
* @returns The migrated data.
|
|
57
|
+
*/
|
|
58
|
+
migrate(data: Input): Output | Promise<Output>;
|
|
59
|
+
/**
|
|
60
|
+
* Optional schema validating this step's input before `migrate` is called. Defaults
|
|
61
|
+
* to a generic JSON-shape check when omitted.
|
|
62
|
+
*/
|
|
63
|
+
inputSchema?: Struct<Input>;
|
|
64
|
+
/**
|
|
65
|
+
* Optional schema validating this step's output at runtime.
|
|
66
|
+
*/
|
|
67
|
+
outputSchema?: Struct<Output>;
|
|
68
|
+
};
|
|
69
|
+
/**
|
|
70
|
+
* A chain of migration steps for evolving keyring serialized state across versions.
|
|
71
|
+
*
|
|
72
|
+
* Steps are versioned by position: the first `.add()` call produces version 1, the
|
|
73
|
+
* second version 2, and so on. Create one with {@link createMigrations}.
|
|
74
|
+
*/
|
|
75
|
+
export type MigrationChain<Data extends Json = Json> = {
|
|
76
|
+
/**
|
|
77
|
+
* The number of steps added so far. Since steps are versioned by position starting at
|
|
78
|
+
* 1, this also doubles as "the latest version" (use it in `serialize()`).
|
|
79
|
+
*/
|
|
80
|
+
readonly version: number;
|
|
81
|
+
/**
|
|
82
|
+
* Append a step to the chain.
|
|
83
|
+
*
|
|
84
|
+
* Returns a new chain typed to `Output`. It does not mutate the chain it's called on,
|
|
85
|
+
* so branching from a shared base chain is safe.
|
|
86
|
+
*
|
|
87
|
+
* `Input` defaults to the chain's current `Data` type. Providing `inputSchema` lets
|
|
88
|
+
* TypeScript infer a narrower `Input` (bounded to extend `Data`), so `migrate`
|
|
89
|
+
* receives a schema-typed argument when narrowing raw state into a specific shape,
|
|
90
|
+
* typically on a chain's first step, where `Data` is `Json`.
|
|
91
|
+
*
|
|
92
|
+
* @param step - The migration step to append.
|
|
93
|
+
* @returns A new chain whose data type is the step's `Output`.
|
|
94
|
+
*/
|
|
95
|
+
add<Input extends Data = Data, Output extends Json = Json>(step: MigrationStep<Input, Output>): MigrationChain<Output>;
|
|
96
|
+
/**
|
|
97
|
+
* Apply all pending steps to `state`.
|
|
98
|
+
*
|
|
99
|
+
* Handles both versioned state (wrapped in `{ version, data }` envelope) and
|
|
100
|
+
* unversioned legacy state (treated as version 0).
|
|
101
|
+
*
|
|
102
|
+
* @param state - The serialized keyring state (from vault or previous serialize).
|
|
103
|
+
* @returns The migrated state wrapped in a versioned envelope, plus a `migrated`
|
|
104
|
+
* flag.
|
|
105
|
+
* @throws If `state`'s version is newer than this chain's latest version, or if a
|
|
106
|
+
* step's `inputSchema`/`outputSchema` validation fails.
|
|
107
|
+
*/
|
|
108
|
+
apply(state: Json): Promise<MigrationResult<Data>>;
|
|
109
|
+
};
|
|
110
|
+
/**
|
|
111
|
+
* Start a new, empty migration chain.
|
|
112
|
+
*
|
|
113
|
+
* @example
|
|
114
|
+
* ```typescript
|
|
115
|
+
* const migrations = createMigrations()
|
|
116
|
+
* .add({ migrate: (data) => ({ count: data.numberOfItems }) })
|
|
117
|
+
* .add({ migrate: (data) => ({ ...data, createdAt: Date.now() }) }); // data typed as the first step's output, no cast
|
|
118
|
+
*
|
|
119
|
+
* const { data } = await migrations.apply(state);
|
|
120
|
+
* ```
|
|
121
|
+
* @returns An empty chain, typed to accept `Json` as its first step's input.
|
|
122
|
+
*/
|
|
123
|
+
export declare function createMigrations(): MigrationChain<Json>;
|
|
124
|
+
//# sourceMappingURL=migration.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"migration.d.mts","sourceRoot":"","sources":["../src/migration.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,8BAA8B;AAG3D,OAAO,KAAK,EAAE,IAAI,EAAE,wBAAwB;AAE5C;;GAEG;AACH,eAAO,MAAM,oBAAoB;;;;;;EAG/B,CAAC;AAEH;;;;;;GAMG;AACH,MAAM,MAAM,cAAc,CAAC,IAAI,SAAS,IAAI,GAAG,IAAI,IAAI,IAAI,CACzD,KAAK,CAAC,OAAO,oBAAoB,CAAC,EAClC,MAAM,CACP,GAAG;IACF,IAAI,EAAE,IAAI,CAAC;CACZ,CAAC;AAEF;;;;;;;GAOG;AACH,MAAM,MAAM,eAAe,CAAC,IAAI,SAAS,IAAI,GAAG,IAAI,IAAI,cAAc,CAAC,IAAI,CAAC,GAAG;IAC7E,QAAQ,EAAE,OAAO,CAAC;CACnB,CAAC;AAEF;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,SAAS,IAAI,GAAG,IAAI,EACxD,KAAK,EAAE,KAAK,GAAG,cAAc,CAAC,KAAK,CAAC,GACnC,KAAK,IAAI,cAAc,CAAC,KAAK,CAAC,CAEhC;AAgBD;;;;;;GAMG;AACH,MAAM,MAAM,aAAa,CACvB,KAAK,SAAS,IAAI,GAAG,IAAI,EACzB,MAAM,SAAS,IAAI,GAAG,IAAI,IACxB;IACF;;;;;;;;OAQG;IACH,OAAO,CAAC,IAAI,EAAE,KAAK,GAAG,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IAC/C;;;OAGG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC,KAAK,CAAC,CAAC;IAC5B;;OAEG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC;CAC/B,CAAC;AAEF;;;;;GAKG;AACH,MAAM,MAAM,cAAc,CAAC,IAAI,SAAS,IAAI,GAAG,IAAI,IAAI;IACrD;;;OAGG;IACH,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB;;;;;;;;;;;;;OAaG;IACH,GAAG,CAAC,KAAK,SAAS,IAAI,GAAG,IAAI,EAAE,MAAM,SAAS,IAAI,GAAG,IAAI,EACvD,IAAI,EAAE,aAAa,CAAC,KAAK,EAAE,MAAM,CAAC,GACjC,cAAc,CAAC,MAAM,CAAC,CAAC;IAC1B;;;;;;;;;;;OAWG;IACH,KAAK,CAAC,KAAK,EAAE,IAAI,GAAG,OAAO,CAAC,eAAe,CAAC,IAAI,CAAC,CAAC,CAAC;CACpD,CAAC;AAgEF;;;;;;;;;;;;GAYG;AACH,wBAAgB,gBAAgB,IAAI,cAAc,CAAC,IAAI,CAAC,CAEvD"}
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import { assert, integer, is, object } from "@metamask/superstruct";
|
|
2
|
+
import { JsonStruct } from "@metamask/utils";
|
|
3
|
+
/**
|
|
4
|
+
* Superstruct schema for the versioned state envelope.
|
|
5
|
+
*/
|
|
6
|
+
export const VersionedStateStruct = object({
|
|
7
|
+
version: integer(),
|
|
8
|
+
data: JsonStruct,
|
|
9
|
+
});
|
|
10
|
+
/**
|
|
11
|
+
* Type guard to check if a value is a {@link VersionedState} envelope.
|
|
12
|
+
*
|
|
13
|
+
* @param state - The value to check.
|
|
14
|
+
* @returns `true` if the value is a versioned state envelope.
|
|
15
|
+
*/
|
|
16
|
+
export function isVersionedState(state) {
|
|
17
|
+
return is(state, VersionedStateStruct);
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Get the version and data from state, treating unversioned state as version 0.
|
|
21
|
+
*
|
|
22
|
+
* @param state - The state to check.
|
|
23
|
+
* @returns The version and data.
|
|
24
|
+
*/
|
|
25
|
+
function getVersionAndData(state) {
|
|
26
|
+
return isVersionedState(state)
|
|
27
|
+
? { version: state.version, data: state.data }
|
|
28
|
+
: { version: 0, data: state };
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Apply the pending steps of a chain to `state`.
|
|
32
|
+
*
|
|
33
|
+
* Implements {@link MigrationChain.apply} for the chain built from `steps`.
|
|
34
|
+
*
|
|
35
|
+
* @param steps - All steps of the chain.
|
|
36
|
+
* @param state - The serialized keyring state.
|
|
37
|
+
* @returns The migrated state wrapped in a versioned envelope, plus a `migrated` flag.
|
|
38
|
+
*/
|
|
39
|
+
async function applySteps(steps, state) {
|
|
40
|
+
const latestVersion = steps.length;
|
|
41
|
+
const { version, data: initialData } = getVersionAndData(state);
|
|
42
|
+
if (version < 0) {
|
|
43
|
+
throw new Error(`State version ${version} is invalid; it cannot be negative`);
|
|
44
|
+
}
|
|
45
|
+
if (version > latestVersion) {
|
|
46
|
+
throw new Error(`State version ${version} is newer than the latest migration version ${latestVersion}`);
|
|
47
|
+
}
|
|
48
|
+
const pendingSteps = steps.slice(version);
|
|
49
|
+
let data = initialData;
|
|
50
|
+
for (const step of pendingSteps) {
|
|
51
|
+
assert(data, step.inputSchema ?? JsonStruct);
|
|
52
|
+
data = await step.migrate(data);
|
|
53
|
+
assert(data, step.outputSchema ?? JsonStruct);
|
|
54
|
+
}
|
|
55
|
+
return {
|
|
56
|
+
version: latestVersion,
|
|
57
|
+
data,
|
|
58
|
+
migrated: pendingSteps.length > 0,
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Build a {@link MigrationChain} wrapping the given internal steps.
|
|
63
|
+
*
|
|
64
|
+
* @param steps - The steps accumulated so far.
|
|
65
|
+
* @returns A chain exposing `add`, `version`, and `apply`.
|
|
66
|
+
*/
|
|
67
|
+
function buildChain(steps) {
|
|
68
|
+
return {
|
|
69
|
+
version: steps.length,
|
|
70
|
+
add: (step) => buildChain([...steps, step]),
|
|
71
|
+
apply: async (state) => applySteps(steps, state),
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Start a new, empty migration chain.
|
|
76
|
+
*
|
|
77
|
+
* @example
|
|
78
|
+
* ```typescript
|
|
79
|
+
* const migrations = createMigrations()
|
|
80
|
+
* .add({ migrate: (data) => ({ count: data.numberOfItems }) })
|
|
81
|
+
* .add({ migrate: (data) => ({ ...data, createdAt: Date.now() }) }); // data typed as the first step's output, no cast
|
|
82
|
+
*
|
|
83
|
+
* const { data } = await migrations.apply(state);
|
|
84
|
+
* ```
|
|
85
|
+
* @returns An empty chain, typed to accept `Json` as its first step's input.
|
|
86
|
+
*/
|
|
87
|
+
export function createMigrations() {
|
|
88
|
+
return buildChain([]);
|
|
89
|
+
}
|
|
90
|
+
//# sourceMappingURL=migration.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"migration.mjs","sourceRoot":"","sources":["../src/migration.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,EAAE,EAAE,MAAM,EAAE,8BAA8B;AACpE,OAAO,EAAE,UAAU,EAAE,wBAAwB;AAG7C;;GAEG;AACH,MAAM,CAAC,MAAM,oBAAoB,GAAG,MAAM,CAAC;IACzC,OAAO,EAAE,OAAO,EAAE;IAClB,IAAI,EAAE,UAAU;CACjB,CAAC,CAAC;AA4BH;;;;;GAKG;AACH,MAAM,UAAU,gBAAgB,CAC9B,KAAoC;IAEpC,OAAO,EAAE,CAAC,KAAK,EAAE,oBAAoB,CAAC,CAAC;AACzC,CAAC;AAED;;;;;GAKG;AACH,SAAS,iBAAiB,CACxB,KAAoC;IAEpC,OAAO,gBAAgB,CAAC,KAAK,CAAC;QAC5B,CAAC,CAAC,EAAE,OAAO,EAAE,KAAK,CAAC,OAAO,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,EAAE;QAC9C,CAAC,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC;AAClC,CAAC;AA8ED;;;;;;;;GAQG;AACH,KAAK,UAAU,UAAU,CACvB,KAA+B,EAC/B,KAAW;IAEX,MAAM,aAAa,GAAG,KAAK,CAAC,MAAM,CAAC;IACnC,MAAM,EAAE,OAAO,EAAE,IAAI,EAAE,WAAW,EAAE,GAAG,iBAAiB,CAAC,KAAK,CAAC,CAAC;IAEhE,IAAI,OAAO,GAAG,CAAC,EAAE,CAAC;QAChB,MAAM,IAAI,KAAK,CACb,iBAAiB,OAAO,oCAAoC,CAC7D,CAAC;IACJ,CAAC;IAED,IAAI,OAAO,GAAG,aAAa,EAAE,CAAC;QAC5B,MAAM,IAAI,KAAK,CACb,iBAAiB,OAAO,+CAA+C,aAAa,EAAE,CACvF,CAAC;IACJ,CAAC;IAED,MAAM,YAAY,GAAG,KAAK,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;IAC1C,IAAI,IAAI,GAAG,WAAW,CAAC;IAEvB,KAAK,MAAM,IAAI,IAAI,YAAY,EAAE,CAAC;QAChC,MAAM,CAAC,IAAI,EAAE,IAAI,CAAC,WAAW,IAAI,UAAU,CAAC,CAAC;QAC7C,IAAI,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;QAChC,MAAM,CAAC,IAAI,EAAE,IAAI,CAAC,YAAY,IAAI,UAAU,CAAC,CAAC;IAChD,CAAC;IAED,OAAO;QACL,OAAO,EAAE,aAAa;QACtB,IAAI;QACJ,QAAQ,EAAE,YAAY,CAAC,MAAM,GAAG,CAAC;KACT,CAAC;AAC7B,CAAC;AAED;;;;;GAKG;AACH,SAAS,UAAU,CACjB,KAA+B;IAE/B,OAAO;QACL,OAAO,EAAE,KAAK,CAAC,MAAM;QACrB,GAAG,EAAE,CACH,IAAkC,EAClC,EAAE,CAAC,UAAU,CAAS,CAAC,GAAG,KAAK,EAAE,IAAgC,CAAC,CAAC;QACrE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,EAAE,CAAC,UAAU,CAAO,KAAK,EAAE,KAAK,CAAC;KACvD,CAAC;AACJ,CAAC;AAED;;;;;;;;;;;;GAYG;AACH,MAAM,UAAU,gBAAgB;IAC9B,OAAO,UAAU,CAAO,EAAE,CAAC,CAAC;AAC9B,CAAC","sourcesContent":["import type { Infer, Struct } from '@metamask/superstruct';\nimport { assert, integer, is, object } from '@metamask/superstruct';\nimport { JsonStruct } from '@metamask/utils';\nimport type { Json } from '@metamask/utils';\n\n/**\n * Superstruct schema for the versioned state envelope.\n */\nexport const VersionedStateStruct = object({\n version: integer(),\n data: JsonStruct,\n});\n\n/**\n * Versioned state envelope wrapping the actual keyring data.\n *\n * After migrations are applied, state is always wrapped in this format. `serialize()`\n * should produce this envelope so that subsequent `deserialize()` calls can detect the\n * version.\n */\nexport type VersionedState<Data extends Json = Json> = Omit<\n Infer<typeof VersionedStateStruct>,\n 'data'\n> & {\n data: Data;\n};\n\n/**\n * Return value of {@link MigrationChain.apply}.\n *\n * Extends {@link VersionedState} with a `migrated` flag that is `true` when at least\n * one step was applied during the call. Callers can use this to detect that the\n * in-memory state has been upgraded and schedule a persist so the new version is\n * written to storage, even when no other state change happens in the session.\n */\nexport type MigrationResult<Data extends Json = Json> = VersionedState<Data> & {\n migrated: boolean;\n};\n\n/**\n * Type guard to check if a value is a {@link VersionedState} envelope.\n *\n * @param state - The value to check.\n * @returns `true` if the value is a versioned state envelope.\n */\nexport function isVersionedState<State extends Json = Json>(\n state: State | VersionedState<State>,\n): state is VersionedState<State> {\n return is(state, VersionedStateStruct);\n}\n\n/**\n * Get the version and data from state, treating unversioned state as version 0.\n *\n * @param state - The state to check.\n * @returns The version and data.\n */\nfunction getVersionAndData<State extends Json = Json>(\n state: State | VersionedState<State>,\n): VersionedState<State> {\n return isVersionedState(state)\n ? { version: state.version, data: state.data }\n : { version: 0, data: state };\n}\n\n/**\n * A single migration step, added to a {@link MigrationChain} via `.add()`.\n *\n * `Input` is bound automatically to the chain's current data type when the step is\n * passed to `.add()`, so `migrate` receives a correctly typed argument with no manual\n * cast.\n */\nexport type MigrationStep<\n Input extends Json = Json,\n Output extends Json = Json,\n> = {\n /**\n * Transform state from the previous step's output to this step's output.\n *\n * Receives the raw inner data (not the versioned envelope). May be sync or async to\n * support complex operations like re-deriving data from secrets.\n *\n * @param data - The state data from the previous step.\n * @returns The migrated data.\n */\n migrate(data: Input): Output | Promise<Output>;\n /**\n * Optional schema validating this step's input before `migrate` is called. Defaults\n * to a generic JSON-shape check when omitted.\n */\n inputSchema?: Struct<Input>;\n /**\n * Optional schema validating this step's output at runtime.\n */\n outputSchema?: Struct<Output>;\n};\n\n/**\n * A chain of migration steps for evolving keyring serialized state across versions.\n *\n * Steps are versioned by position: the first `.add()` call produces version 1, the\n * second version 2, and so on. Create one with {@link createMigrations}.\n */\nexport type MigrationChain<Data extends Json = Json> = {\n /**\n * The number of steps added so far. Since steps are versioned by position starting at\n * 1, this also doubles as \"the latest version\" (use it in `serialize()`).\n */\n readonly version: number;\n /**\n * Append a step to the chain.\n *\n * Returns a new chain typed to `Output`. It does not mutate the chain it's called on,\n * so branching from a shared base chain is safe.\n *\n * `Input` defaults to the chain's current `Data` type. Providing `inputSchema` lets\n * TypeScript infer a narrower `Input` (bounded to extend `Data`), so `migrate`\n * receives a schema-typed argument when narrowing raw state into a specific shape,\n * typically on a chain's first step, where `Data` is `Json`.\n *\n * @param step - The migration step to append.\n * @returns A new chain whose data type is the step's `Output`.\n */\n add<Input extends Data = Data, Output extends Json = Json>(\n step: MigrationStep<Input, Output>,\n ): MigrationChain<Output>;\n /**\n * Apply all pending steps to `state`.\n *\n * Handles both versioned state (wrapped in `{ version, data }` envelope) and\n * unversioned legacy state (treated as version 0).\n *\n * @param state - The serialized keyring state (from vault or previous serialize).\n * @returns The migrated state wrapped in a versioned envelope, plus a `migrated`\n * flag.\n * @throws If `state`'s version is newer than this chain's latest version, or if a\n * step's `inputSchema`/`outputSchema` validation fails.\n */\n apply(state: Json): Promise<MigrationResult<Data>>;\n};\n\n/**\n * Apply the pending steps of a chain to `state`.\n *\n * Implements {@link MigrationChain.apply} for the chain built from `steps`.\n *\n * @param steps - All steps of the chain.\n * @param state - The serialized keyring state.\n * @returns The migrated state wrapped in a versioned envelope, plus a `migrated` flag.\n */\nasync function applySteps<Data extends Json>(\n steps: readonly MigrationStep[],\n state: Json,\n): Promise<MigrationResult<Data>> {\n const latestVersion = steps.length;\n const { version, data: initialData } = getVersionAndData(state);\n\n if (version < 0) {\n throw new Error(\n `State version ${version} is invalid; it cannot be negative`,\n );\n }\n\n if (version > latestVersion) {\n throw new Error(\n `State version ${version} is newer than the latest migration version ${latestVersion}`,\n );\n }\n\n const pendingSteps = steps.slice(version);\n let data = initialData;\n\n for (const step of pendingSteps) {\n assert(data, step.inputSchema ?? JsonStruct);\n data = await step.migrate(data);\n assert(data, step.outputSchema ?? JsonStruct);\n }\n\n return {\n version: latestVersion,\n data,\n migrated: pendingSteps.length > 0,\n } as MigrationResult<Data>;\n}\n\n/**\n * Build a {@link MigrationChain} wrapping the given internal steps.\n *\n * @param steps - The steps accumulated so far.\n * @returns A chain exposing `add`, `version`, and `apply`.\n */\nfunction buildChain<Data extends Json>(\n steps: readonly MigrationStep[],\n): MigrationChain<Data> {\n return {\n version: steps.length,\n add: <Input extends Data, Output extends Json>(\n step: MigrationStep<Input, Output>,\n ) => buildChain<Output>([...steps, step as unknown as MigrationStep]),\n apply: async (state) => applySteps<Data>(steps, state),\n };\n}\n\n/**\n * Start a new, empty migration chain.\n *\n * @example\n * ```typescript\n * const migrations = createMigrations()\n * .add({ migrate: (data) => ({ count: data.numberOfItems }) })\n * .add({ migrate: (data) => ({ ...data, createdAt: Date.now() }) }); // data typed as the first step's output, no cast\n *\n * const { data } = await migrations.apply(state);\n * ```\n * @returns An empty chain, typed to accept `Json` as its first step's input.\n */\nexport function createMigrations(): MigrationChain<Json> {\n return buildChain<Json>([]);\n}\n"]}
|
package/dist/mnemonic.cjs
CHANGED
|
@@ -1,21 +1,30 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.encodeMnemonic = void 0;
|
|
3
|
+
exports.encodeMnemonic = exports.encodeMnemonicWords = void 0;
|
|
4
4
|
const english_1 = require("@metamask/scure-bip39/dist/wordlists/english.js");
|
|
5
5
|
/**
|
|
6
|
-
* Encodes a mnemonic as
|
|
6
|
+
* Encodes a mnemonic as a string of words.
|
|
7
7
|
*
|
|
8
8
|
* @param mnemonicIndicesBytes - An array of bytes (16-bit unsigned integers) representing the indices of the words in the mnemonic.
|
|
9
|
-
* @returns
|
|
9
|
+
* @returns A string representing the mnemonic.
|
|
10
10
|
*/
|
|
11
|
-
function
|
|
11
|
+
function encodeMnemonicWords(mnemonicIndicesBytes) {
|
|
12
12
|
const mnemonicIndices = Array.from(
|
|
13
13
|
// Create a new `Uint8Array` to ensure we have a proper view on the buffer
|
|
14
14
|
// without having to worry about `byteOffset` and `byteLength` of
|
|
15
15
|
// the inner buffer.
|
|
16
16
|
new Uint16Array(new Uint8Array(mnemonicIndicesBytes).buffer));
|
|
17
|
-
|
|
18
|
-
|
|
17
|
+
return mnemonicIndices.map((i) => english_1.wordlist[i]).join(' ');
|
|
18
|
+
}
|
|
19
|
+
exports.encodeMnemonicWords = encodeMnemonicWords;
|
|
20
|
+
/**
|
|
21
|
+
* Encodes a mnemonic as an array of bytes (UTF-8).
|
|
22
|
+
*
|
|
23
|
+
* @param mnemonicIndicesBytes - An array of bytes (16-bit unsigned integers) representing the indices of the words in the mnemonic.
|
|
24
|
+
* @returns An array of bytes (UTF-8) representing the mnemonic.
|
|
25
|
+
*/
|
|
26
|
+
function encodeMnemonic(mnemonicIndicesBytes) {
|
|
27
|
+
return Array.from(new TextEncoder().encode(encodeMnemonicWords(mnemonicIndicesBytes)));
|
|
19
28
|
}
|
|
20
29
|
exports.encodeMnemonic = encodeMnemonic;
|
|
21
30
|
//# sourceMappingURL=mnemonic.cjs.map
|
package/dist/mnemonic.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mnemonic.cjs","sourceRoot":"","sources":["../src/mnemonic.ts"],"names":[],"mappings":";;;AAAA,6EAAwE;AAExE;;;;;GAKG;AACH,SAAgB,
|
|
1
|
+
{"version":3,"file":"mnemonic.cjs","sourceRoot":"","sources":["../src/mnemonic.ts"],"names":[],"mappings":";;;AAAA,6EAAwE;AAExE;;;;;GAKG;AACH,SAAgB,mBAAmB,CAAC,oBAAgC;IAClE,MAAM,eAAe,GAAG,KAAK,CAAC,IAAI;IAChC,0EAA0E;IAC1E,iEAAiE;IACjE,oBAAoB;IACpB,IAAI,WAAW,CAAC,IAAI,UAAU,CAAC,oBAAoB,CAAC,CAAC,MAAM,CAAC,CAC7D,CAAC;IACF,OAAO,eAAe,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,kBAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAC3D,CAAC;AARD,kDAQC;AAED;;;;;GAKG;AACH,SAAgB,cAAc,CAAC,oBAAgC;IAC7D,OAAO,KAAK,CAAC,IAAI,CACf,IAAI,WAAW,EAAE,CAAC,MAAM,CAAC,mBAAmB,CAAC,oBAAoB,CAAC,CAAC,CACpE,CAAC;AACJ,CAAC;AAJD,wCAIC","sourcesContent":["import { wordlist } from '@metamask/scure-bip39/dist/wordlists/english';\n\n/**\n * Encodes a mnemonic as a string of words.\n *\n * @param mnemonicIndicesBytes - An array of bytes (16-bit unsigned integers) representing the indices of the words in the mnemonic.\n * @returns A string representing the mnemonic.\n */\nexport function encodeMnemonicWords(mnemonicIndicesBytes: Uint8Array): string {\n const mnemonicIndices = Array.from(\n // Create a new `Uint8Array` to ensure we have a proper view on the buffer\n // without having to worry about `byteOffset` and `byteLength` of\n // the inner buffer.\n new Uint16Array(new Uint8Array(mnemonicIndicesBytes).buffer),\n );\n return mnemonicIndices.map((i) => wordlist[i]).join(' ');\n}\n\n/**\n * Encodes a mnemonic as an array of bytes (UTF-8).\n *\n * @param mnemonicIndicesBytes - An array of bytes (16-bit unsigned integers) representing the indices of the words in the mnemonic.\n * @returns An array of bytes (UTF-8) representing the mnemonic.\n */\nexport function encodeMnemonic(mnemonicIndicesBytes: Uint8Array): number[] {\n return Array.from(\n new TextEncoder().encode(encodeMnemonicWords(mnemonicIndicesBytes)),\n );\n}\n"]}
|
package/dist/mnemonic.d.cts
CHANGED
|
@@ -1,3 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Encodes a mnemonic as a string of words.
|
|
3
|
+
*
|
|
4
|
+
* @param mnemonicIndicesBytes - An array of bytes (16-bit unsigned integers) representing the indices of the words in the mnemonic.
|
|
5
|
+
* @returns A string representing the mnemonic.
|
|
6
|
+
*/
|
|
7
|
+
export declare function encodeMnemonicWords(mnemonicIndicesBytes: Uint8Array): string;
|
|
1
8
|
/**
|
|
2
9
|
* Encodes a mnemonic as an array of bytes (UTF-8).
|
|
3
10
|
*
|
package/dist/mnemonic.d.cts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mnemonic.d.cts","sourceRoot":"","sources":["../src/mnemonic.ts"],"names":[],"mappings":"AAEA;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,oBAAoB,EAAE,UAAU,GAAG,MAAM,EAAE,
|
|
1
|
+
{"version":3,"file":"mnemonic.d.cts","sourceRoot":"","sources":["../src/mnemonic.ts"],"names":[],"mappings":"AAEA;;;;;GAKG;AACH,wBAAgB,mBAAmB,CAAC,oBAAoB,EAAE,UAAU,GAAG,MAAM,CAQ5E;AAED;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,oBAAoB,EAAE,UAAU,GAAG,MAAM,EAAE,CAIzE"}
|
package/dist/mnemonic.d.mts
CHANGED
|
@@ -1,3 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Encodes a mnemonic as a string of words.
|
|
3
|
+
*
|
|
4
|
+
* @param mnemonicIndicesBytes - An array of bytes (16-bit unsigned integers) representing the indices of the words in the mnemonic.
|
|
5
|
+
* @returns A string representing the mnemonic.
|
|
6
|
+
*/
|
|
7
|
+
export declare function encodeMnemonicWords(mnemonicIndicesBytes: Uint8Array): string;
|
|
1
8
|
/**
|
|
2
9
|
* Encodes a mnemonic as an array of bytes (UTF-8).
|
|
3
10
|
*
|
package/dist/mnemonic.d.mts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mnemonic.d.mts","sourceRoot":"","sources":["../src/mnemonic.ts"],"names":[],"mappings":"AAEA;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,oBAAoB,EAAE,UAAU,GAAG,MAAM,EAAE,
|
|
1
|
+
{"version":3,"file":"mnemonic.d.mts","sourceRoot":"","sources":["../src/mnemonic.ts"],"names":[],"mappings":"AAEA;;;;;GAKG;AACH,wBAAgB,mBAAmB,CAAC,oBAAoB,EAAE,UAAU,GAAG,MAAM,CAQ5E;AAED;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,oBAAoB,EAAE,UAAU,GAAG,MAAM,EAAE,CAIzE"}
|
package/dist/mnemonic.mjs
CHANGED
|
@@ -1,17 +1,25 @@
|
|
|
1
1
|
import { wordlist } from "@metamask/scure-bip39/dist/wordlists/english.js";
|
|
2
2
|
/**
|
|
3
|
-
* Encodes a mnemonic as
|
|
3
|
+
* Encodes a mnemonic as a string of words.
|
|
4
4
|
*
|
|
5
5
|
* @param mnemonicIndicesBytes - An array of bytes (16-bit unsigned integers) representing the indices of the words in the mnemonic.
|
|
6
|
-
* @returns
|
|
6
|
+
* @returns A string representing the mnemonic.
|
|
7
7
|
*/
|
|
8
|
-
export function
|
|
8
|
+
export function encodeMnemonicWords(mnemonicIndicesBytes) {
|
|
9
9
|
const mnemonicIndices = Array.from(
|
|
10
10
|
// Create a new `Uint8Array` to ensure we have a proper view on the buffer
|
|
11
11
|
// without having to worry about `byteOffset` and `byteLength` of
|
|
12
12
|
// the inner buffer.
|
|
13
13
|
new Uint16Array(new Uint8Array(mnemonicIndicesBytes).buffer));
|
|
14
|
-
|
|
15
|
-
|
|
14
|
+
return mnemonicIndices.map((i) => wordlist[i]).join(' ');
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Encodes a mnemonic as an array of bytes (UTF-8).
|
|
18
|
+
*
|
|
19
|
+
* @param mnemonicIndicesBytes - An array of bytes (16-bit unsigned integers) representing the indices of the words in the mnemonic.
|
|
20
|
+
* @returns An array of bytes (UTF-8) representing the mnemonic.
|
|
21
|
+
*/
|
|
22
|
+
export function encodeMnemonic(mnemonicIndicesBytes) {
|
|
23
|
+
return Array.from(new TextEncoder().encode(encodeMnemonicWords(mnemonicIndicesBytes)));
|
|
16
24
|
}
|
|
17
25
|
//# sourceMappingURL=mnemonic.mjs.map
|
package/dist/mnemonic.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mnemonic.mjs","sourceRoot":"","sources":["../src/mnemonic.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,wDAAqD;AAExE;;;;;GAKG;AACH,MAAM,UAAU,
|
|
1
|
+
{"version":3,"file":"mnemonic.mjs","sourceRoot":"","sources":["../src/mnemonic.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,wDAAqD;AAExE;;;;;GAKG;AACH,MAAM,UAAU,mBAAmB,CAAC,oBAAgC;IAClE,MAAM,eAAe,GAAG,KAAK,CAAC,IAAI;IAChC,0EAA0E;IAC1E,iEAAiE;IACjE,oBAAoB;IACpB,IAAI,WAAW,CAAC,IAAI,UAAU,CAAC,oBAAoB,CAAC,CAAC,MAAM,CAAC,CAC7D,CAAC;IACF,OAAO,eAAe,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAC3D,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,cAAc,CAAC,oBAAgC;IAC7D,OAAO,KAAK,CAAC,IAAI,CACf,IAAI,WAAW,EAAE,CAAC,MAAM,CAAC,mBAAmB,CAAC,oBAAoB,CAAC,CAAC,CACpE,CAAC;AACJ,CAAC","sourcesContent":["import { wordlist } from '@metamask/scure-bip39/dist/wordlists/english';\n\n/**\n * Encodes a mnemonic as a string of words.\n *\n * @param mnemonicIndicesBytes - An array of bytes (16-bit unsigned integers) representing the indices of the words in the mnemonic.\n * @returns A string representing the mnemonic.\n */\nexport function encodeMnemonicWords(mnemonicIndicesBytes: Uint8Array): string {\n const mnemonicIndices = Array.from(\n // Create a new `Uint8Array` to ensure we have a proper view on the buffer\n // without having to worry about `byteOffset` and `byteLength` of\n // the inner buffer.\n new Uint16Array(new Uint8Array(mnemonicIndicesBytes).buffer),\n );\n return mnemonicIndices.map((i) => wordlist[i]).join(' ');\n}\n\n/**\n * Encodes a mnemonic as an array of bytes (UTF-8).\n *\n * @param mnemonicIndicesBytes - An array of bytes (16-bit unsigned integers) representing the indices of the words in the mnemonic.\n * @returns An array of bytes (UTF-8) representing the mnemonic.\n */\nexport function encodeMnemonic(mnemonicIndicesBytes: Uint8Array): number[] {\n return Array.from(\n new TextEncoder().encode(encodeMnemonicWords(mnemonicIndicesBytes)),\n );\n}\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@metamask/keyring-sdk",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "3.0.0",
|
|
4
4
|
"description": "MetaMask Keyring SDK",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"keyring",
|
|
@@ -68,11 +68,12 @@
|
|
|
68
68
|
"dependencies": {
|
|
69
69
|
"@ethereumjs/tx": "^5.4.0",
|
|
70
70
|
"@metamask/eth-sig-util": "^8.2.0",
|
|
71
|
-
"@metamask/keyring-api": "^
|
|
72
|
-
"@metamask/keyring-utils": "^
|
|
71
|
+
"@metamask/keyring-api": "^24.0.0",
|
|
72
|
+
"@metamask/keyring-utils": "^5.0.0",
|
|
73
73
|
"@metamask/scure-bip39": "^2.1.1",
|
|
74
|
-
"@metamask/superstruct": "^3.1
|
|
74
|
+
"@metamask/superstruct": "^3.4.1",
|
|
75
75
|
"@metamask/utils": "^11.11.0",
|
|
76
|
+
"@noble/hashes": "^1.8.0",
|
|
76
77
|
"async-mutex": "^0.5.0",
|
|
77
78
|
"ethereum-cryptography": "^2.2.1",
|
|
78
79
|
"uuid": "^9.0.1"
|
|
@@ -103,7 +104,7 @@
|
|
|
103
104
|
"directory": "src"
|
|
104
105
|
},
|
|
105
106
|
"engines": {
|
|
106
|
-
"node": "
|
|
107
|
+
"node": ">=22"
|
|
107
108
|
},
|
|
108
109
|
"lavamoat": {
|
|
109
110
|
"allowScripts": {
|