mirror of
https://github.com/trezor/trezor-suite.git
synced 2026-02-20 00:33:07 +01:00
feat(common): implemented increaseOwnerQuotaThunk
This commit is contained in:
committed by
Matěj "Matt" Husák
parent
66c57cc247
commit
4ebd913d43
@@ -13,6 +13,7 @@
|
||||
"@evolu/common": "^7.3.0",
|
||||
"@noble/hashes": "^1.6.1",
|
||||
"@suite-common/suite-sync-storage": "workspace:*",
|
||||
"@suite-common/suite-sync-types": "workspace:*",
|
||||
"@suite-common/suite-types": "workspace:*",
|
||||
"@suite-common/wallet-config": "workspace:*",
|
||||
"@suite-common/wallet-types": "workspace:*",
|
||||
|
||||
29
suite-common/suite-sync-evolu/src/createEvoluErrorHandler.ts
Normal file
29
suite-common/suite-sync-evolu/src/createEvoluErrorHandler.ts
Normal file
@@ -0,0 +1,29 @@
|
||||
import { Evolu } from '@evolu/common';
|
||||
|
||||
import { SuiteSyncErrorHandler } from '@suite-common/suite-sync-types';
|
||||
import { asSuiteSyncOwnerId } from '@suite-common/suite-types';
|
||||
|
||||
export const createEvoluErrorHandler =
|
||||
(evolu: Evolu<any>, errorHandler: SuiteSyncErrorHandler) => () => {
|
||||
const error = evolu.getError();
|
||||
|
||||
// early return if there is no error to handle
|
||||
if (error === null) {
|
||||
return;
|
||||
}
|
||||
|
||||
switch (error.type) {
|
||||
case 'ProtocolQuotaError':
|
||||
errorHandler({
|
||||
type: 'RelayQuotaExceeded',
|
||||
ownerId: asSuiteSyncOwnerId(error.ownerId),
|
||||
});
|
||||
|
||||
return;
|
||||
|
||||
default:
|
||||
errorHandler({ type: 'RelayOther', message: JSON.stringify(error) });
|
||||
|
||||
return;
|
||||
}
|
||||
};
|
||||
@@ -2,9 +2,11 @@ import { Evolu, EvoluDeps, SimpleName, createEvolu } from '@evolu/common';
|
||||
import { sha256 } from '@noble/hashes/sha2';
|
||||
import { bytesToHex } from '@noble/hashes/utils';
|
||||
|
||||
import { SuiteSyncErrorHandler } from '@suite-common/suite-sync-types';
|
||||
import { SuiteSyncOwner } from '@suite-common/suite-types';
|
||||
|
||||
import { createEvoluAppOwnerFromTrezorData } from './createEvoluAppOwnerFromTrezorData';
|
||||
import { createEvoluErrorHandler } from './createEvoluErrorHandler';
|
||||
import { Schema } from './schema';
|
||||
|
||||
// This is a way how to force change of the SQL files. It was useful for development
|
||||
@@ -12,7 +14,10 @@ import { Schema } from './schema';
|
||||
// See: https://www.evolu.dev/docs/faq#how-to-delete-opfs-sqlite-in-browser
|
||||
const VERSION = 7;
|
||||
|
||||
type CreateEvoluInstanceFactoryDeps = EvoluDeps;
|
||||
type CreateEvoluInstanceFactoryDeps = {
|
||||
suiteSyncErrorHandler: SuiteSyncErrorHandler;
|
||||
evoluDeps: EvoluDeps;
|
||||
};
|
||||
|
||||
export type CreateEvoluInstance = (params: {
|
||||
suiteSyncOwner: SuiteSyncOwner;
|
||||
@@ -45,7 +50,7 @@ export const createEvoluInstanceFactory =
|
||||
throw databaseName.error;
|
||||
}
|
||||
|
||||
const evolu = createEvolu(deps)(Schema, {
|
||||
const evolu = createEvolu(deps.evoluDeps)(Schema, {
|
||||
name: databaseName.value,
|
||||
// Intentionally no transport, transport will be passed
|
||||
// later on, so we can change the RelayUrl at any time.
|
||||
@@ -56,10 +61,7 @@ export const createEvoluInstanceFactory =
|
||||
encryptionKey: owner.value.encryptionKey,
|
||||
});
|
||||
|
||||
evolu.subscribeError(() => {
|
||||
const error = evolu.getError();
|
||||
console.error(JSON.stringify(error));
|
||||
});
|
||||
evolu.subscribeError(createEvoluErrorHandler(evolu, deps.suiteSyncErrorHandler));
|
||||
|
||||
return evolu;
|
||||
};
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
},
|
||||
"references": [
|
||||
{ "path": "../suite-sync-storage" },
|
||||
{ "path": "../suite-sync-types" },
|
||||
{ "path": "../suite-types" },
|
||||
{ "path": "../wallet-config" },
|
||||
{ "path": "../wallet-types" },
|
||||
|
||||
@@ -14,11 +14,13 @@
|
||||
"dependencies": {
|
||||
"@reduxjs/toolkit": "2.10.1",
|
||||
"@suite-common/delegated-identity-key": "workspace:*",
|
||||
"@suite-common/redux-utils": "workspace:*",
|
||||
"@suite-common/suite-types": "workspace:*",
|
||||
"@suite-common/suite-utils": "workspace:*",
|
||||
"@suite-common/test-utils": "workspace:*",
|
||||
"@suite-common/wallet-core": "workspace:*",
|
||||
"@suite-common/wallet-types": "workspace:*",
|
||||
"@suite-common/wallet-utils": "workspace:*",
|
||||
"@trezor/connect": "workspace:*",
|
||||
"@trezor/device-utils": "workspace:*",
|
||||
"@trezor/env-utils": "workspace:*",
|
||||
|
||||
@@ -11,6 +11,16 @@ export const DEFAULT_DEVICE_SIZE_QUOTA = 1024 * 1024;
|
||||
*/
|
||||
export const DEFAULT_ACCOUNT_SIZE_QUOTA = Math.round(DEFAULT_DEVICE_SIZE_QUOTA / 100);
|
||||
|
||||
/**
|
||||
* Default increment account size quota that is used for incrementing quota when no account store is left.
|
||||
*/
|
||||
export const DEFAULT_ACCOUNT_INCREMENT_SIZE_QUOTA = DEFAULT_ACCOUNT_SIZE_QUOTA;
|
||||
|
||||
export const DEFAULT_QUOTA_MANAGER_URL = isDevEnv
|
||||
? 'https://suite-sync.suite.sldev.cz/quota-manager/'
|
||||
: 'https://suite-sync.trezor.io/quota-manager/';
|
||||
|
||||
/**
|
||||
* Header used for signing add space to owner requests.
|
||||
*/
|
||||
export const EVOLU_SIGN_ADD_SPACE_TO_OWNER_REQUEST_HEADER = 'EvoluAddSpaceToOwnerV1';
|
||||
|
||||
@@ -8,15 +8,16 @@ import { DelegatedIdentityKey, SuiteSyncOwnerId } from '@suite-common/suite-type
|
||||
import { WalletDescriptor } from '@suite-common/wallet-types';
|
||||
|
||||
import { prepareChallengeSession } from './challenge/prepareChallengeSession';
|
||||
import { DEFAULT_ACCOUNT_SIZE_QUOTA } from './constants';
|
||||
import {
|
||||
DEFAULT_ACCOUNT_SIZE_QUOTA,
|
||||
EVOLU_SIGN_ADD_SPACE_TO_OWNER_REQUEST_HEADER,
|
||||
} from './constants';
|
||||
import { quotaManagerFetchError, quotaManagerOwnerFetched } from './quotaManagerActions';
|
||||
import { selectIsQuotaManagerEnabled, selectQuotaManagerBaseUrl } from './quotaManagerSelectors';
|
||||
import { checkStorageByOwnerId } from './storage/checkStorage';
|
||||
import { transferStorageThunk } from './storage/transferStorageThunk';
|
||||
import { prepareMessageBufferEvoluAddSpaceToOwner } from './util/prepareMessageBufferEvoluAddSpaceToOwner';
|
||||
|
||||
const EVOLU_SIGN_ADD_SPACE_TO_OWNER_REQUEST_HEADER = 'EvoluAddSpaceToOwnerV1';
|
||||
|
||||
type EnsureOwnerHasAllocatedQuotaParams = {
|
||||
ownerId: SuiteSyncOwnerId;
|
||||
walletDescriptor: WalletDescriptor;
|
||||
|
||||
@@ -0,0 +1,91 @@
|
||||
import { Dispatch } from '@reduxjs/toolkit';
|
||||
|
||||
import {
|
||||
getProofOfDelegatedIdentity,
|
||||
getPublicIdentityKeyFromDelegatedKey,
|
||||
} from '@suite-common/delegated-identity-key';
|
||||
import { delegatedIdentityKeyCompositionRoot } from '@suite-common/delegated-identity-key/src/delegatedIdentityKeyCompositionRoot';
|
||||
import { ExtraDependencies } from '@suite-common/redux-utils';
|
||||
import { SuiteSyncOwnerId, asDelegatedIdentityKey } from '@suite-common/suite-types';
|
||||
import { selectSelectedDevice } from '@suite-common/wallet-core';
|
||||
import { isTrezorDeviceWithState, parseDeviceStaticSessionId } from '@suite-common/wallet-utils';
|
||||
import TrezorConnect from '@trezor/connect';
|
||||
|
||||
import { prepareChallengeSession } from './challenge/prepareChallengeSession';
|
||||
import {
|
||||
DEFAULT_ACCOUNT_INCREMENT_SIZE_QUOTA,
|
||||
EVOLU_SIGN_ADD_SPACE_TO_OWNER_REQUEST_HEADER,
|
||||
} from './constants';
|
||||
import { selectIsQuotaManagerEnabled, selectQuotaManagerBaseUrl } from './quotaManagerSelectors';
|
||||
import { transferStorageThunk } from './storage/transferStorageThunk';
|
||||
import { prepareMessageBufferEvoluAddSpaceToOwner } from './util/prepareMessageBufferEvoluAddSpaceToOwner';
|
||||
|
||||
type AllocateMoreOwnerQuotaParams = {
|
||||
ownerId: SuiteSyncOwnerId;
|
||||
};
|
||||
|
||||
export const increaseOwnerQuotaThunk =
|
||||
({ ownerId }: AllocateMoreOwnerQuotaParams) =>
|
||||
async (dispatch: Dispatch, getState: () => any, extra: ExtraDependencies) => {
|
||||
const isQuotaManagerEnabled = selectIsQuotaManagerEnabled(getState());
|
||||
if (!isQuotaManagerEnabled) return;
|
||||
|
||||
const device = selectSelectedDevice(getState());
|
||||
|
||||
if (!device || !isTrezorDeviceWithState(device)) {
|
||||
return;
|
||||
}
|
||||
const { walletDescriptor } = parseDeviceStaticSessionId(device.state.staticSessionId);
|
||||
const quotaManagerBaseUrl = selectQuotaManagerBaseUrl(getState());
|
||||
|
||||
const { ensureDelegatedIdentityKey } = delegatedIdentityKeyCompositionRoot({
|
||||
dispatch,
|
||||
getState,
|
||||
trezorConnect: TrezorConnect,
|
||||
platformEncryption: extra.services.platformEncryption,
|
||||
});
|
||||
|
||||
const delegatedKey = await ensureDelegatedIdentityKey({ device });
|
||||
if (!delegatedKey.success) {
|
||||
return;
|
||||
}
|
||||
|
||||
const delegatedPublicKey = getPublicIdentityKeyFromDelegatedKey(delegatedKey.payload);
|
||||
|
||||
const sessionChallenge = await prepareChallengeSession({
|
||||
baseUrl: quotaManagerBaseUrl,
|
||||
});
|
||||
|
||||
if (!sessionChallenge.success) {
|
||||
return;
|
||||
}
|
||||
|
||||
const proof = getProofOfDelegatedIdentity({
|
||||
delegatedKey: asDelegatedIdentityKey(delegatedKey.payload),
|
||||
header: EVOLU_SIGN_ADD_SPACE_TO_OWNER_REQUEST_HEADER,
|
||||
appendMessageBuffer: prepareMessageBufferEvoluAddSpaceToOwner({
|
||||
ownerId,
|
||||
challenge: sessionChallenge.payload.challenge,
|
||||
size: DEFAULT_ACCOUNT_INCREMENT_SIZE_QUOTA,
|
||||
publicKey: delegatedPublicKey,
|
||||
}),
|
||||
});
|
||||
|
||||
if (!proof.success) {
|
||||
return;
|
||||
}
|
||||
|
||||
dispatch(
|
||||
transferStorageThunk({
|
||||
walletDescriptor,
|
||||
params: {
|
||||
ownerId,
|
||||
size: DEFAULT_ACCOUNT_INCREMENT_SIZE_QUOTA,
|
||||
proof: proof.payload,
|
||||
sessionId: sessionChallenge.payload.sessionId,
|
||||
challenge: sessionChallenge.payload.challenge,
|
||||
publicKey: delegatedPublicKey,
|
||||
},
|
||||
}),
|
||||
);
|
||||
};
|
||||
@@ -7,6 +7,7 @@ export { transferStorageThunk } from './storage/transferStorageThunk';
|
||||
export { prepareChallengeSession } from './challenge/prepareChallengeSession';
|
||||
export { ensureDeviceHasQuotaThunk } from './ensureDeviceHasQuotaThunk';
|
||||
export { ensureOwnerHasAllocatedQuotaThunk } from './ensureOwnerHasAllocatedQuotaThunk';
|
||||
export { increaseOwnerQuotaThunk } from './increaseOwnerQuotaThunk';
|
||||
|
||||
/**
|
||||
* Actions.
|
||||
|
||||
@@ -6,11 +6,13 @@
|
||||
},
|
||||
"references": [
|
||||
{ "path": "../delegated-identity-key" },
|
||||
{ "path": "../redux-utils" },
|
||||
{ "path": "../suite-types" },
|
||||
{ "path": "../suite-utils" },
|
||||
{ "path": "../test-utils" },
|
||||
{ "path": "../wallet-core" },
|
||||
{ "path": "../wallet-types" },
|
||||
{ "path": "../wallet-utils" },
|
||||
{ "path": "../../packages/connect" },
|
||||
{ "path": "../../packages/device-utils" },
|
||||
{ "path": "../../packages/env-utils" },
|
||||
|
||||
14
suite-common/suite-sync-types/src/SuiteSyncErrorHandler.ts
Normal file
14
suite-common/suite-sync-types/src/SuiteSyncErrorHandler.ts
Normal file
@@ -0,0 +1,14 @@
|
||||
import { Dispatch } from '@reduxjs/toolkit';
|
||||
|
||||
import { SuiteSyncOwnerId } from '@suite-common/suite-types';
|
||||
|
||||
export type CreateSuiteSyncErrorHandlerDep = {
|
||||
dispatch: Dispatch;
|
||||
};
|
||||
|
||||
export type RelayQuotaExceededError = { type: 'RelayQuotaExceeded'; ownerId: SuiteSyncOwnerId };
|
||||
export type SuiteSyncOtherError = { type: 'RelayOther'; message: string };
|
||||
|
||||
export type Errors = RelayQuotaExceededError | SuiteSyncOtherError;
|
||||
|
||||
export type SuiteSyncErrorHandler = (error: Errors) => void;
|
||||
@@ -63,3 +63,11 @@ export type {
|
||||
} from './data/updateWalletLabel';
|
||||
|
||||
export type { SuiteSyncAppReloader, SuiteSyncAppReloaderDep } from './suiteSyncAppReloader';
|
||||
|
||||
export type {
|
||||
SuiteSyncErrorHandler,
|
||||
SuiteSyncOtherError,
|
||||
RelayQuotaExceededError,
|
||||
Errors,
|
||||
CreateSuiteSyncErrorHandlerDep,
|
||||
} from './SuiteSyncErrorHandler';
|
||||
|
||||
@@ -4,8 +4,12 @@ import { EnsureDelegatedIdentityKeyDep } from '@suite-common/delegated-identity-
|
||||
import { toGetter } from '@suite-common/dependency-injection';
|
||||
import { PlatformEncryptionDep } from '@suite-common/platform-encryption';
|
||||
import { selectHasDeviceAllowance } from '@suite-common/suite-sync-quota-manager';
|
||||
import { CreateSuiteStorageDep, CreateSuiteSyncOwnerDep } from '@suite-common/suite-sync-storage';
|
||||
import { SuiteSync, SuiteSyncAppReloaderDep } from '@suite-common/suite-sync-types';
|
||||
import { CreateSuiteStorage, CreateSuiteSyncOwnerDep } from '@suite-common/suite-sync-storage';
|
||||
import {
|
||||
SuiteSync,
|
||||
SuiteSyncAppReloaderDep,
|
||||
SuiteSyncErrorHandler,
|
||||
} from '@suite-common/suite-sync-types';
|
||||
import {
|
||||
selectAllDeviceStaticIds,
|
||||
selectDeviceByStaticSessionId,
|
||||
@@ -14,6 +18,7 @@ import {
|
||||
import { StaticSessionId } from '@trezor/connect';
|
||||
|
||||
import { createRefreshSuiteSync } from './createRefreshSuiteSyncKeys';
|
||||
import { createSuiteSyncErrorHandler } from './createSuiteSyncErrorHandler';
|
||||
import { createTurnOffSuiteSync } from './createTurnOffSuiteSync';
|
||||
import { createTurnOnSuiteSync } from './createTurnOnSuiteSync';
|
||||
import { createEnsureSubscribeSuiteSyncData } from './data/createEnsureSuiteSyncData';
|
||||
@@ -39,12 +44,20 @@ import { createSuiteSyncStorageRepository } from './storage/createSuiteSyncStora
|
||||
import { createTurnOffSuiteSyncForWallet } from './storage/createTurnOffSuiteSyncForWallet';
|
||||
import { selectIsSuiteSyncEnabled, selectSuiteSyncRelayUrl } from './suiteSyncSelectors';
|
||||
|
||||
type CreateSuiteStorageFactory = (deps: {
|
||||
suiteSyncErrorHandler: SuiteSyncErrorHandler;
|
||||
}) => CreateSuiteStorage;
|
||||
|
||||
type CreateSuiteStorageFactoryDep = {
|
||||
createSuiteStorageFactory: CreateSuiteStorageFactory;
|
||||
};
|
||||
|
||||
type CreateSuiteSyncCompositionRootDeps = {
|
||||
getState: () => any;
|
||||
dispatch: Dispatch;
|
||||
trezorConnect: RetrieveSuiteSyncOwnerDeps['trezorConnect'];
|
||||
} & EnsureDelegatedIdentityKeyDep &
|
||||
CreateSuiteStorageDep &
|
||||
CreateSuiteStorageFactoryDep &
|
||||
CreateSuiteSyncOwnerDep &
|
||||
PlatformEncryptionDep &
|
||||
SuiteSyncAppReloaderDep;
|
||||
@@ -90,10 +103,16 @@ export const createSuiteSyncCompositionRoot = (
|
||||
selectHasDeviceAllowance(deps.getState(), deviceId ?? null, walletDescriptor),
|
||||
});
|
||||
|
||||
const suiteSyncErrorHandler: SuiteSyncErrorHandler = createSuiteSyncErrorHandler({
|
||||
dispatch: deps.dispatch,
|
||||
});
|
||||
|
||||
const createSuiteStorage = deps.createSuiteStorageFactory({ suiteSyncErrorHandler });
|
||||
|
||||
const ensureStorage = createEnsureStorage({
|
||||
refreshSuiteSyncKeys,
|
||||
suiteSyncStorageRepository,
|
||||
createSuiteStorage: deps.createSuiteStorage,
|
||||
createSuiteStorage,
|
||||
defaultRelayUrl: DEFAULT_SUITE_SYNC_RELAY_URL,
|
||||
getRelayUrl: toGetter(deps.getState, selectSuiteSyncRelayUrl),
|
||||
getDeviceForStaticSessionId,
|
||||
|
||||
26
suite-common/suite-sync/src/createSuiteSyncErrorHandler.ts
Normal file
26
suite-common/suite-sync/src/createSuiteSyncErrorHandler.ts
Normal file
@@ -0,0 +1,26 @@
|
||||
import { increaseOwnerQuotaThunk } from '@suite-common/suite-sync-quota-manager';
|
||||
import {
|
||||
CreateSuiteSyncErrorHandlerDep,
|
||||
Errors,
|
||||
SuiteSyncErrorHandler,
|
||||
} from '@suite-common/suite-sync-types';
|
||||
|
||||
export const createSuiteSyncErrorHandler =
|
||||
(deps: CreateSuiteSyncErrorHandlerDep): SuiteSyncErrorHandler =>
|
||||
(error: Errors) => {
|
||||
switch (error.type) {
|
||||
case 'RelayQuotaExceeded':
|
||||
deps.dispatch(
|
||||
increaseOwnerQuotaThunk({
|
||||
ownerId: error.ownerId,
|
||||
}),
|
||||
);
|
||||
|
||||
return;
|
||||
|
||||
default:
|
||||
console.error('SuiteSync relay error', error.message);
|
||||
|
||||
return;
|
||||
}
|
||||
};
|
||||
@@ -22,14 +22,17 @@ type SuiteSyncNativeCompositionRootDeps = {
|
||||
|
||||
export const createSuiteSyncNativeCompositionRoot = (
|
||||
deps: SuiteSyncNativeCompositionRootDeps,
|
||||
): SuiteSync => {
|
||||
const createEvoluInstance = createEvoluInstanceFactory(evoluReactNativeDeps);
|
||||
const createEvoluStorage = createEvoluStorageFactory({ createEvoluInstance });
|
||||
|
||||
return createSuiteSyncCompositionRoot({
|
||||
): SuiteSync =>
|
||||
createSuiteSyncCompositionRoot({
|
||||
...deps,
|
||||
createSuiteStorage: createEvoluStorage,
|
||||
createSuiteStorageFactory: ({ suiteSyncErrorHandler }) => {
|
||||
const createEvoluInstance = createEvoluInstanceFactory({
|
||||
evoluDeps: evoluReactNativeDeps,
|
||||
suiteSyncErrorHandler,
|
||||
});
|
||||
|
||||
return createEvoluStorageFactory({ createEvoluInstance });
|
||||
},
|
||||
createSuiteSyncOwner: evoluCreateSuiteSyncOwner,
|
||||
reloadApp: reloadAppAsync,
|
||||
});
|
||||
};
|
||||
|
||||
@@ -31,13 +31,18 @@ type SuiteSyncDesktopCompositionRootDeps = {
|
||||
export const createSuiteSyncDesktopCompositionRoot = (
|
||||
deps: SuiteSyncDesktopCompositionRootDeps,
|
||||
): SuiteSync => {
|
||||
// This is the place where we set Evolu as a SuiteSync Storage.
|
||||
const createEvoluInstance = createEvoluInstanceFactory(evoluWebDeps);
|
||||
const createEvoluStorage = createEvoluStorageFactory({ createEvoluInstance });
|
||||
|
||||
// This sets up Evolu as a SuiteSync Storage. We provide a factory that
|
||||
// accepts `suiteSyncErrorHandler` and creates the evolu instance accordingly.
|
||||
const suiteSync = createSuiteSyncCompositionRoot({
|
||||
...deps,
|
||||
createSuiteStorage: createEvoluStorage,
|
||||
createSuiteStorageFactory: ({ suiteSyncErrorHandler }) => {
|
||||
const createEvoluInstance = createEvoluInstanceFactory({
|
||||
evoluDeps: evoluWebDeps,
|
||||
suiteSyncErrorHandler,
|
||||
});
|
||||
|
||||
return createEvoluStorageFactory({ createEvoluInstance });
|
||||
},
|
||||
createSuiteSyncOwner: evoluCreateSuiteSyncOwner,
|
||||
});
|
||||
|
||||
|
||||
16
yarn.lock
16
yarn.lock
@@ -11050,6 +11050,7 @@ __metadata:
|
||||
"@evolu/common": "npm:^7.3.0"
|
||||
"@noble/hashes": "npm:^1.6.1"
|
||||
"@suite-common/suite-sync-storage": "workspace:*"
|
||||
"@suite-common/suite-sync-types": "workspace:*"
|
||||
"@suite-common/suite-types": "workspace:*"
|
||||
"@suite-common/wallet-config": "workspace:*"
|
||||
"@suite-common/wallet-types": "workspace:*"
|
||||
@@ -11063,11 +11064,13 @@ __metadata:
|
||||
dependencies:
|
||||
"@reduxjs/toolkit": "npm:2.10.1"
|
||||
"@suite-common/delegated-identity-key": "workspace:*"
|
||||
"@suite-common/redux-utils": "workspace:*"
|
||||
"@suite-common/suite-types": "workspace:*"
|
||||
"@suite-common/suite-utils": "workspace:*"
|
||||
"@suite-common/test-utils": "workspace:*"
|
||||
"@suite-common/wallet-core": "workspace:*"
|
||||
"@suite-common/wallet-types": "workspace:*"
|
||||
"@suite-common/wallet-utils": "workspace:*"
|
||||
"@trezor/connect": "workspace:*"
|
||||
"@trezor/device-utils": "workspace:*"
|
||||
"@trezor/env-utils": "workspace:*"
|
||||
@@ -16844,16 +16847,7 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@types/react@npm:*, @types/react@npm:>=16":
|
||||
version: 19.2.8
|
||||
resolution: "@types/react@npm:19.2.8"
|
||||
dependencies:
|
||||
csstype: "npm:^3.2.2"
|
||||
checksum: 10/688e7605876e2729c25fdfd2c131d7080cb8e98db528aedccab89005bcbca097a6149fa6e137ae4f1807bdc44220e0c5c7b4a968b5b681dadb7761968bac6de5
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@types/react@npm:19.1.6":
|
||||
"@types/react@npm:*, @types/react@npm:19.1.6, @types/react@npm:>=16":
|
||||
version: 19.1.6
|
||||
resolution: "@types/react@npm:19.1.6"
|
||||
dependencies:
|
||||
@@ -22251,7 +22245,7 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"csstype@npm:^3.0.2, csstype@npm:^3.0.5, csstype@npm:^3.1.2, csstype@npm:^3.1.3, csstype@npm:^3.2.2":
|
||||
"csstype@npm:^3.0.2, csstype@npm:^3.0.5, csstype@npm:^3.1.2, csstype@npm:^3.1.3":
|
||||
version: 3.2.3
|
||||
resolution: "csstype@npm:3.2.3"
|
||||
checksum: 10/ad41baf7e2ffac65ab544d79107bf7cd1a4bb9bab9ac3302f59ab4ba655d5e30942a8ae46e10ba160c6f4ecea464cc95b975ca2fefbdeeacd6ac63f12f99fe1f
|
||||
|
||||
Reference in New Issue
Block a user