🎩 You're Invited:Meet the Socket team at Black Hat in Las Vegas, August 3-6.RSVP
Sign In

@metamask/keyring-sdk

Package Overview
Dependencies
Maintainers
7
Versions
10
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@metamask/keyring-sdk - npm Package Compare versions

Comparing version
2.2.0
to
2.3.0
+95
dist/migration.cjs
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.createMigrations = exports.isVersionedState = exports.VersionedStateStruct = void 0;
const superstruct_1 = require("@metamask/superstruct");
const utils_1 = require("@metamask/utils");
/**
* Superstruct schema for the versioned state envelope.
*/
exports.VersionedStateStruct = (0, superstruct_1.object)({
version: (0, superstruct_1.integer)(),
data: utils_1.JsonStruct,
});
/**
* Type guard to check if a value is a {@link VersionedState} envelope.
*
* @param state - The value to check.
* @returns `true` if the value is a versioned state envelope.
*/
function isVersionedState(state) {
return (0, superstruct_1.is)(state, exports.VersionedStateStruct);
}
exports.isVersionedState = isVersionedState;
/**
* Get the version and data from state, treating unversioned state as version 0.
*
* @param state - The state to check.
* @returns The version and data.
*/
function getVersionAndData(state) {
return isVersionedState(state)
? { version: state.version, data: state.data }
: { version: 0, data: state };
}
/**
* Apply the pending steps of a chain to `state`.
*
* Implements {@link MigrationChain.apply} for the chain built from `steps`.
*
* @param steps - All steps of the chain.
* @param state - The serialized keyring state.
* @returns The migrated state wrapped in a versioned envelope, plus a `migrated` flag.
*/
async function applySteps(steps, state) {
const latestVersion = steps.length;
const { version, data: initialData } = getVersionAndData(state);
if (version < 0) {
throw new Error(`State version ${version} is invalid; it cannot be negative`);
}
if (version > latestVersion) {
throw new Error(`State version ${version} is newer than the latest migration version ${latestVersion}`);
}
const pendingSteps = steps.slice(version);
let data = initialData;
for (const step of pendingSteps) {
(0, superstruct_1.assert)(data, step.inputSchema ?? utils_1.JsonStruct);
data = await step.migrate(data);
(0, superstruct_1.assert)(data, step.outputSchema ?? utils_1.JsonStruct);
}
return {
version: latestVersion,
data,
migrated: pendingSteps.length > 0,
};
}
/**
* Build a {@link MigrationChain} wrapping the given internal steps.
*
* @param steps - The steps accumulated so far.
* @returns A chain exposing `add`, `version`, and `apply`.
*/
function buildChain(steps) {
return {
version: steps.length,
add: (step) => buildChain([...steps, step]),
apply: async (state) => applySteps(steps, state),
};
}
/**
* Start a new, empty migration chain.
*
* @example
* ```typescript
* const migrations = createMigrations()
* .add({ migrate: (data) => ({ count: data.numberOfItems }) })
* .add({ migrate: (data) => ({ ...data, createdAt: Date.now() }) }); // data typed as the first step's output, no cast
*
* const { data } = await migrations.apply(state);
* ```
* @returns An empty chain, typed to accept `Json` as its first step's input.
*/
function createMigrations() {
return buildChain([]);
}
exports.createMigrations = createMigrations;
//# sourceMappingURL=migration.cjs.map
{"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"]}
import type { Infer, Struct } from "@metamask/superstruct";
import type { Json } from "@metamask/utils";
/**
* Superstruct schema for the versioned state envelope.
*/
export declare const VersionedStateStruct: Struct<{
data: Json;
version: number;
}, {
version: Struct<number, null>;
data: Struct<Json, unknown>;
}>;
/**
* Versioned state envelope wrapping the actual keyring data.
*
* After migrations are applied, state is always wrapped in this format. `serialize()`
* should produce this envelope so that subsequent `deserialize()` calls can detect the
* version.
*/
export type VersionedState<Data extends Json = Json> = Omit<Infer<typeof VersionedStateStruct>, 'data'> & {
data: Data;
};
/**
* Return value of {@link MigrationChain.apply}.
*
* Extends {@link VersionedState} with a `migrated` flag that is `true` when at least
* one step was applied during the call. Callers can use this to detect that the
* in-memory state has been upgraded and schedule a persist so the new version is
* written to storage, even when no other state change happens in the session.
*/
export type MigrationResult<Data extends Json = Json> = VersionedState<Data> & {
migrated: boolean;
};
/**
* Type guard to check if a value is a {@link VersionedState} envelope.
*
* @param state - The value to check.
* @returns `true` if the value is a versioned state envelope.
*/
export declare function isVersionedState<State extends Json = Json>(state: State | VersionedState<State>): state is VersionedState<State>;
/**
* A single migration step, added to a {@link MigrationChain} via `.add()`.
*
* `Input` is bound automatically to the chain's current data type when the step is
* passed to `.add()`, so `migrate` receives a correctly typed argument with no manual
* cast.
*/
export type MigrationStep<Input extends Json = Json, Output extends Json = Json> = {
/**
* Transform state from the previous step's output to this step's output.
*
* Receives the raw inner data (not the versioned envelope). May be sync or async to
* support complex operations like re-deriving data from secrets.
*
* @param data - The state data from the previous step.
* @returns The migrated data.
*/
migrate(data: Input): Output | Promise<Output>;
/**
* Optional schema validating this step's input before `migrate` is called. Defaults
* to a generic JSON-shape check when omitted.
*/
inputSchema?: Struct<Input>;
/**
* Optional schema validating this step's output at runtime.
*/
outputSchema?: Struct<Output>;
};
/**
* A chain of migration steps for evolving keyring serialized state across versions.
*
* Steps are versioned by position: the first `.add()` call produces version 1, the
* second version 2, and so on. Create one with {@link createMigrations}.
*/
export type MigrationChain<Data extends Json = Json> = {
/**
* The number of steps added so far. Since steps are versioned by position starting at
* 1, this also doubles as "the latest version" (use it in `serialize()`).
*/
readonly version: number;
/**
* Append a step to the chain.
*
* Returns a new chain typed to `Output`. It does not mutate the chain it's called on,
* so branching from a shared base chain is safe.
*
* `Input` defaults to the chain's current `Data` type. Providing `inputSchema` lets
* TypeScript infer a narrower `Input` (bounded to extend `Data`), so `migrate`
* receives a schema-typed argument when narrowing raw state into a specific shape,
* typically on a chain's first step, where `Data` is `Json`.
*
* @param step - The migration step to append.
* @returns A new chain whose data type is the step's `Output`.
*/
add<Input extends Data = Data, Output extends Json = Json>(step: MigrationStep<Input, Output>): MigrationChain<Output>;
/**
* Apply all pending steps to `state`.
*
* Handles both versioned state (wrapped in `{ version, data }` envelope) and
* unversioned legacy state (treated as version 0).
*
* @param state - The serialized keyring state (from vault or previous serialize).
* @returns The migrated state wrapped in a versioned envelope, plus a `migrated`
* flag.
* @throws If `state`'s version is newer than this chain's latest version, or if a
* step's `inputSchema`/`outputSchema` validation fails.
*/
apply(state: Json): Promise<MigrationResult<Data>>;
};
/**
* Start a new, empty migration chain.
*
* @example
* ```typescript
* const migrations = createMigrations()
* .add({ migrate: (data) => ({ count: data.numberOfItems }) })
* .add({ migrate: (data) => ({ ...data, createdAt: Date.now() }) }); // data typed as the first step's output, no cast
*
* const { data } = await migrations.apply(state);
* ```
* @returns An empty chain, typed to accept `Json` as its first step's input.
*/
export declare function createMigrations(): MigrationChain<Json>;
//# sourceMappingURL=migration.d.cts.map
{"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"}
import type { Infer, Struct } from "@metamask/superstruct";
import type { Json } from "@metamask/utils";
/**
* Superstruct schema for the versioned state envelope.
*/
export declare const VersionedStateStruct: Struct<{
data: Json;
version: number;
}, {
version: Struct<number, null>;
data: Struct<Json, unknown>;
}>;
/**
* Versioned state envelope wrapping the actual keyring data.
*
* After migrations are applied, state is always wrapped in this format. `serialize()`
* should produce this envelope so that subsequent `deserialize()` calls can detect the
* version.
*/
export type VersionedState<Data extends Json = Json> = Omit<Infer<typeof VersionedStateStruct>, 'data'> & {
data: Data;
};
/**
* Return value of {@link MigrationChain.apply}.
*
* Extends {@link VersionedState} with a `migrated` flag that is `true` when at least
* one step was applied during the call. Callers can use this to detect that the
* in-memory state has been upgraded and schedule a persist so the new version is
* written to storage, even when no other state change happens in the session.
*/
export type MigrationResult<Data extends Json = Json> = VersionedState<Data> & {
migrated: boolean;
};
/**
* Type guard to check if a value is a {@link VersionedState} envelope.
*
* @param state - The value to check.
* @returns `true` if the value is a versioned state envelope.
*/
export declare function isVersionedState<State extends Json = Json>(state: State | VersionedState<State>): state is VersionedState<State>;
/**
* A single migration step, added to a {@link MigrationChain} via `.add()`.
*
* `Input` is bound automatically to the chain's current data type when the step is
* passed to `.add()`, so `migrate` receives a correctly typed argument with no manual
* cast.
*/
export type MigrationStep<Input extends Json = Json, Output extends Json = Json> = {
/**
* Transform state from the previous step's output to this step's output.
*
* Receives the raw inner data (not the versioned envelope). May be sync or async to
* support complex operations like re-deriving data from secrets.
*
* @param data - The state data from the previous step.
* @returns The migrated data.
*/
migrate(data: Input): Output | Promise<Output>;
/**
* Optional schema validating this step's input before `migrate` is called. Defaults
* to a generic JSON-shape check when omitted.
*/
inputSchema?: Struct<Input>;
/**
* Optional schema validating this step's output at runtime.
*/
outputSchema?: Struct<Output>;
};
/**
* A chain of migration steps for evolving keyring serialized state across versions.
*
* Steps are versioned by position: the first `.add()` call produces version 1, the
* second version 2, and so on. Create one with {@link createMigrations}.
*/
export type MigrationChain<Data extends Json = Json> = {
/**
* The number of steps added so far. Since steps are versioned by position starting at
* 1, this also doubles as "the latest version" (use it in `serialize()`).
*/
readonly version: number;
/**
* Append a step to the chain.
*
* Returns a new chain typed to `Output`. It does not mutate the chain it's called on,
* so branching from a shared base chain is safe.
*
* `Input` defaults to the chain's current `Data` type. Providing `inputSchema` lets
* TypeScript infer a narrower `Input` (bounded to extend `Data`), so `migrate`
* receives a schema-typed argument when narrowing raw state into a specific shape,
* typically on a chain's first step, where `Data` is `Json`.
*
* @param step - The migration step to append.
* @returns A new chain whose data type is the step's `Output`.
*/
add<Input extends Data = Data, Output extends Json = Json>(step: MigrationStep<Input, Output>): MigrationChain<Output>;
/**
* Apply all pending steps to `state`.
*
* Handles both versioned state (wrapped in `{ version, data }` envelope) and
* unversioned legacy state (treated as version 0).
*
* @param state - The serialized keyring state (from vault or previous serialize).
* @returns The migrated state wrapped in a versioned envelope, plus a `migrated`
* flag.
* @throws If `state`'s version is newer than this chain's latest version, or if a
* step's `inputSchema`/`outputSchema` validation fails.
*/
apply(state: Json): Promise<MigrationResult<Data>>;
};
/**
* Start a new, empty migration chain.
*
* @example
* ```typescript
* const migrations = createMigrations()
* .add({ migrate: (data) => ({ count: data.numberOfItems }) })
* .add({ migrate: (data) => ({ ...data, createdAt: Date.now() }) }); // data typed as the first step's output, no cast
*
* const { data } = await migrations.apply(state);
* ```
* @returns An empty chain, typed to accept `Json` as its first step's input.
*/
export declare function createMigrations(): MigrationChain<Json>;
//# sourceMappingURL=migration.d.mts.map
{"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"}
import { assert, integer, is, object } from "@metamask/superstruct";
import { JsonStruct } from "@metamask/utils";
/**
* Superstruct schema for the versioned state envelope.
*/
export const VersionedStateStruct = object({
version: integer(),
data: JsonStruct,
});
/**
* Type guard to check if a value is a {@link VersionedState} envelope.
*
* @param state - The value to check.
* @returns `true` if the value is a versioned state envelope.
*/
export function isVersionedState(state) {
return is(state, VersionedStateStruct);
}
/**
* Get the version and data from state, treating unversioned state as version 0.
*
* @param state - The state to check.
* @returns The version and data.
*/
function getVersionAndData(state) {
return isVersionedState(state)
? { version: state.version, data: state.data }
: { version: 0, data: state };
}
/**
* Apply the pending steps of a chain to `state`.
*
* Implements {@link MigrationChain.apply} for the chain built from `steps`.
*
* @param steps - All steps of the chain.
* @param state - The serialized keyring state.
* @returns The migrated state wrapped in a versioned envelope, plus a `migrated` flag.
*/
async function applySteps(steps, state) {
const latestVersion = steps.length;
const { version, data: initialData } = getVersionAndData(state);
if (version < 0) {
throw new Error(`State version ${version} is invalid; it cannot be negative`);
}
if (version > latestVersion) {
throw new Error(`State version ${version} is newer than the latest migration version ${latestVersion}`);
}
const pendingSteps = steps.slice(version);
let data = initialData;
for (const step of pendingSteps) {
assert(data, step.inputSchema ?? JsonStruct);
data = await step.migrate(data);
assert(data, step.outputSchema ?? JsonStruct);
}
return {
version: latestVersion,
data,
migrated: pendingSteps.length > 0,
};
}
/**
* Build a {@link MigrationChain} wrapping the given internal steps.
*
* @param steps - The steps accumulated so far.
* @returns A chain exposing `add`, `version`, and `apply`.
*/
function buildChain(steps) {
return {
version: steps.length,
add: (step) => buildChain([...steps, step]),
apply: async (state) => applySteps(steps, state),
};
}
/**
* Start a new, empty migration chain.
*
* @example
* ```typescript
* const migrations = createMigrations()
* .add({ migrate: (data) => ({ count: data.numberOfItems }) })
* .add({ migrate: (data) => ({ ...data, createdAt: Date.now() }) }); // data typed as the first step's output, no cast
*
* const { data } = await migrations.apply(state);
* ```
* @returns An empty chain, typed to accept `Json` as its first step's input.
*/
export function createMigrations() {
return buildChain([]);
}
//# sourceMappingURL=migration.mjs.map
{"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"]}
+15
-1

@@ -10,2 +10,15 @@ # Changelog

## [2.3.0]
### Added
- Add keyring state migration framework ([#505](https://github.com/MetaMask/accounts/pull/505))
- Use `createMigrations().add(...)` to build a chain of versioned migration steps, and `.apply(state)` to migrate the internal state of keyrings
### Changed
- 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))
- 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))
- Bump `@metamask/keyring-utils` from `^3.3.1` to `^4.0.0` ([#600](https://github.com/MetaMask/accounts/pull/600))
## [2.2.0]

@@ -92,3 +105,4 @@

[Unreleased]: https://github.com/MetaMask/accounts/compare/@metamask/keyring-sdk@2.2.0...HEAD
[Unreleased]: https://github.com/MetaMask/accounts/compare/@metamask/keyring-sdk@2.3.0...HEAD
[2.3.0]: https://github.com/MetaMask/accounts/compare/@metamask/keyring-sdk@2.2.0...@metamask/keyring-sdk@2.3.0
[2.2.0]: https://github.com/MetaMask/accounts/compare/@metamask/keyring-sdk@2.1.1...@metamask/keyring-sdk@2.2.0

@@ -95,0 +109,0 @@ [2.1.1]: https://github.com/MetaMask/accounts/compare/@metamask/keyring-sdk@2.1.0...@metamask/keyring-sdk@2.1.1

@@ -18,4 +18,5 @@ "use strict";

__exportStar(require("./keyring-account-registry.cjs"), exports);
__exportStar(require("./migration.cjs"), exports);
__exportStar(require("./mnemonic.cjs"), exports);
__exportStar(require("./eth/index.cjs"), exports);
//# sourceMappingURL=index.cjs.map
+1
-1

@@ -1,1 +0,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"]}
{"version":3,"file":"index.cjs","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,iEAA2C;AAC3C,kDAA4B;AAC5B,iDAA2B;AAC3B,kDAAsB","sourcesContent":["export * from './keyring-account-registry';\nexport * from './migration';\nexport * from './mnemonic';\nexport * from './eth';\n"]}
export * from "./keyring-account-registry.cjs";
export * from "./migration.cjs";
export * from "./mnemonic.cjs";
export * from "./eth/index.cjs";
//# sourceMappingURL=index.d.cts.map

@@ -1,1 +0,1 @@

{"version":3,"file":"index.d.cts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,+CAA2C;AAC3C,+BAA2B;AAC3B,gCAAsB"}
{"version":3,"file":"index.d.cts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,+CAA2C;AAC3C,gCAA4B;AAC5B,+BAA2B;AAC3B,gCAAsB"}
export * from "./keyring-account-registry.mjs";
export * from "./migration.mjs";
export * from "./mnemonic.mjs";
export * from "./eth/index.mjs";
//# sourceMappingURL=index.d.mts.map

@@ -1,1 +0,1 @@

{"version":3,"file":"index.d.mts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,+CAA2C;AAC3C,+BAA2B;AAC3B,gCAAsB"}
{"version":3,"file":"index.d.mts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,+CAA2C;AAC3C,gCAA4B;AAC5B,+BAA2B;AAC3B,gCAAsB"}
export * from "./keyring-account-registry.mjs";
export * from "./migration.mjs";
export * from "./mnemonic.mjs";
export * from "./eth/index.mjs";
//# sourceMappingURL=index.mjs.map

@@ -1,1 +0,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"]}
{"version":3,"file":"index.mjs","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,+CAA2C;AAC3C,gCAA4B;AAC5B,+BAA2B;AAC3B,gCAAsB","sourcesContent":["export * from './keyring-account-registry';\nexport * from './migration';\nexport * from './mnemonic';\nexport * from './eth';\n"]}
{
"name": "@metamask/keyring-sdk",
"version": "2.2.0",
"version": "2.3.0",
"description": "MetaMask Keyring SDK",

@@ -71,6 +71,6 @@ "keywords": [

"@metamask/eth-sig-util": "^8.2.0",
"@metamask/keyring-api": "^23.2.0",
"@metamask/keyring-utils": "^3.3.1",
"@metamask/keyring-api": "^23.6.0",
"@metamask/keyring-utils": "^4.0.0",
"@metamask/scure-bip39": "^2.1.1",
"@metamask/superstruct": "^3.1.0",
"@metamask/superstruct": "^3.4.1",
"@metamask/utils": "^11.11.0",

@@ -77,0 +77,0 @@ "async-mutex": "^0.5.0",