diff --git a/.yarn/install-state.gz b/.yarn/install-state.gz index 367de94531..0846f6105f 100644 Binary files a/.yarn/install-state.gz and b/.yarn/install-state.gz differ diff --git a/packages/platform-sdk-profiles/src/env.models.ts b/packages/platform-sdk-profiles/src/env.models.ts index 24f7a741f0..cff2b73cd2 100644 --- a/packages/platform-sdk-profiles/src/env.models.ts +++ b/packages/platform-sdk-profiles/src/env.models.ts @@ -17,7 +17,7 @@ export interface EnvironmentOptions { } export interface Storage { - all(): Promise; + all(): Promise>; get(key: string): Promise; @@ -33,3 +33,8 @@ export interface Storage { restore(): Promise; } + +export interface StorageData { + data: object; + profiles: object; +} diff --git a/packages/platform-sdk-profiles/src/env.test.ts b/packages/platform-sdk-profiles/src/env.test.ts index 75468f28ad..756e147721 100644 --- a/packages/platform-sdk-profiles/src/env.test.ts +++ b/packages/platform-sdk-profiles/src/env.test.ts @@ -6,6 +6,7 @@ import { ETH } from "@arkecosystem/platform-sdk-eth"; import nock from "nock"; import { Environment, Identifiers, Profile } from "../src"; +import storageData from "../test/fixtures/env-storage.json"; import { identity } from "../test/fixtures/identity"; import { HttpClient } from "../test/stubs/client"; import { StubStorage } from "../test/stubs/storage"; @@ -106,3 +107,17 @@ it("should create a profile with data and persist it when instructed to do so", expect(newProfile.data().all()).toEqual({ key: "value" }); expect(newProfile.settings().all()).toEqual({ ADVANCED_MODE: "value" }); }); + +it("should boot the environment from fixed data", async () => { + const env = new Environment({ coins: { ARK }, httpClient: new HttpClient(), storage: new StubStorage() }); + await env.bootFromObject(storageData); + + const newProfile = env.profiles().findById("b999d134-7a24-481e-a95d-bc47c543bfc9"); + + expect(newProfile).toBeInstanceOf(Profile); + expect(newProfile.wallets().keys()).toHaveLength(1); + expect(newProfile.contacts().keys()).toHaveLength(1); + expect(newProfile.notifications().keys()).toHaveLength(1); + expect(newProfile.data().all()).toEqual({ key: "value" }); + expect(newProfile.settings().all()).toEqual({ ADVANCED_MODE: "value" }); +}); diff --git a/packages/platform-sdk-profiles/src/env.ts b/packages/platform-sdk-profiles/src/env.ts index b49dab20a8..6dda3bc48d 100644 --- a/packages/platform-sdk-profiles/src/env.ts +++ b/packages/platform-sdk-profiles/src/env.ts @@ -2,7 +2,7 @@ import { Validator, ValidatorSchema } from "@arkecosystem/platform-sdk-support"; import { container } from "./container"; import { Identifiers } from "./container.models"; -import { EnvironmentOptions, Storage, CoinList, CoinType } from "./env.models"; +import { CoinList, CoinType, EnvironmentOptions, Storage, StorageData } from "./env.models"; import { Migrator } from "./migrator"; import { DataRepository } from "./repositories/data-repository"; import { ProfileRepository } from "./repositories/profile-repository"; @@ -23,15 +23,27 @@ export class Environment { * @memberof Environment */ public async boot(): Promise { - const { data, profiles } = await this.validateStorage(); + const { data, profiles } = await container.get(Identifiers.Storage).all(); - if (data) { - this.data().fill(data); - } + const validated: StorageData = await this.validateStorage({ data, profiles }); - if (profiles) { - await this.profiles().fill(profiles); - } + await this.restoreData(validated); + } + + /** + * Load the data from an object. + * + * This has to be manually called and should be used the same as "bootFromStorage" + * with the exception of it not being used in production. This method should only + * be used in testing environments where you want to use a fixed set of data. + * + * @returns {Promise} + * @memberof Environment + */ + public async bootFromObject({ data, profiles }: StorageData): Promise { + const validated: StorageData = await this.validateStorage({ data, profiles }); + + await this.restoreData(validated); } /** @@ -97,7 +109,7 @@ export class Environment { container.set(Identifiers.Coins, options.coins); } - private async validateStorage(): Promise<{ profiles; data }> { + private async validateStorage({ data, profiles }): Promise { const mapRules = (map: object, rule: Function) => Object.keys(map).reduce((newMap, key) => ({ ...newMap, [key]: rule }), {}); @@ -174,9 +186,6 @@ export class Environment { return object({ profiles: object(rules), data: object() }); }); - // @ts-ignore - let { data, profiles } = await container.get(Identifiers.Storage).all(); - if (!data) { data = {}; } @@ -198,4 +207,14 @@ export class Environment { return validated; } + + private async restoreData({ data, profiles }: StorageData): Promise { + if (data) { + this.data().fill(data); + } + + if (profiles) { + await this.profiles().fill(profiles); + } + } } diff --git a/packages/platform-sdk-profiles/src/migrator.ts b/packages/platform-sdk-profiles/src/migrator.ts index d4d1255adb..e8df446079 100644 --- a/packages/platform-sdk-profiles/src/migrator.ts +++ b/packages/platform-sdk-profiles/src/migrator.ts @@ -3,9 +3,9 @@ import semver from "semver"; import { container } from "./container"; import { Identifiers } from "./container.models"; +import { Storage } from "./env.models"; import { DataRepository } from "./repositories/data-repository"; import { ProfileRepository } from "./repositories/profile-repository"; -import { Storage } from "./env.models"; export class Migrator { readonly #profiles: ProfileRepository; diff --git a/packages/platform-sdk-profiles/src/storage/local.ts b/packages/platform-sdk-profiles/src/storage/local.ts index 5828dfa6f8..b496689469 100644 --- a/packages/platform-sdk-profiles/src/storage/local.ts +++ b/packages/platform-sdk-profiles/src/storage/local.ts @@ -16,8 +16,8 @@ export class LocalStorage implements Storage { }); } - public async all(): Promise { - const result: object = {}; + public async all(): Promise> { + const result: Record = {}; for (const key of await this.#storage.keys()) { result[key] = await this.get(key); diff --git a/packages/platform-sdk-profiles/src/storage/null.ts b/packages/platform-sdk-profiles/src/storage/null.ts index bb2580f5d2..89573493d4 100644 --- a/packages/platform-sdk-profiles/src/storage/null.ts +++ b/packages/platform-sdk-profiles/src/storage/null.ts @@ -1,7 +1,7 @@ import { Storage } from "../env.models"; export class NullStorage implements Storage { - public async all(): Promise { + public async all(): Promise> { return {}; } diff --git a/packages/platform-sdk-profiles/test/fixtures/env-storage.json b/packages/platform-sdk-profiles/test/fixtures/env-storage.json new file mode 100644 index 0000000000..0848837409 --- /dev/null +++ b/packages/platform-sdk-profiles/test/fixtures/env-storage.json @@ -0,0 +1,60 @@ +{ + "profiles": { + "b999d134-7a24-481e-a95d-bc47c543bfc9": { + "id": "b999d134-7a24-481e-a95d-bc47c543bfc9", + "name": "John Doe", + "wallets": { + "ac38fe6d-4b67-4ef1-85be-17c5f6841129": { + "id": "ac38fe6d-4b67-4ef1-85be-17c5f6841129", + "coin": "ARK", + "coinConfig": { + "network": { + "id": "devnet", + "name": "Devnet", + "explorer": "https://dexplorer.ark.io/", + "currency": { "ticker": "DARK", "symbol": "DѦ" }, + "crypto": { "slip44": 111 }, + "hosts": [ + "https://dexplorer.ark.io", + "http://167.114.29.51:4003", + "http://167.114.29.52:4003", + "http://167.114.29.53:4003", + "http://167.114.29.54:4003", + "http://167.114.29.55:4003" + ], + "hostsMultiSignature": [], + "voting": { "enabled": true, "singular": true } + } + }, + "network": "devnet", + "address": "D61mfSggzbvQgTUe6JhYKH2doHaqJ3Dyib", + "publicKey": "034151a3ec46b5670a682b0a63394f863587d1bc97483b1b6c70eb58e7f0aed192", + "data": { "BALANCE": {}, "SEQUENCE": {} }, + "settings": { + "AVATAR": "conic-gradient(from 138.92820875068205deg at 10.341003346631878% 56.34369708791203%, #9B2C2C, calc(0 * 100% / 5), transparent 0),conic-gradient(from 501.2404426352248deg at 6.193536608927738% 20.020924742851292%, #FEB2B2, calc(1 * 100% / 5), transparent 0),conic-gradient(from 538.0014084095758deg at 32.870727463865066% 41.693174698534285%, #F6AD55, calc(2 * 100% / 5), transparent 0),conic-gradient(from 86.8716993412581deg at 45.65092691320694% 53.97053076646755%, #2C7A7B, calc(3 * 100% / 5), transparent 0),conic-gradient(from 453.1648835420749deg at 5.017317358847957% 27.456901944771822%, #FC8181, calc(4 * 100% / 5), transparent 0)" + } + } + }, + "contacts": { + "0e147f96-049f-4d89-bad4-ad3341109907": { + "id": "0e147f96-049f-4d89-bad4-ad3341109907", + "name": "Jane Doe", + "starred": false, + "addresses": [] + } + }, + "notifications": { + "b183aef3-2dba-471a-a588-0fcf8f01b645": { + "id": "b183aef3-2dba-471a-a588-0fcf8f01b645", + "icon": "warning", + "name": "Ledger Update Available", + "body": "...", + "action": "Read Changelog" + } + }, + "data": { "key": "value" }, + "settings": { "ADVANCED_MODE": "value" } + } + }, + "data": { "key": "value" } +} diff --git a/packages/platform-sdk-profiles/test/stubs/storage.ts b/packages/platform-sdk-profiles/test/stubs/storage.ts index dac212a950..28d0df9d02 100644 --- a/packages/platform-sdk-profiles/test/stubs/storage.ts +++ b/packages/platform-sdk-profiles/test/stubs/storage.ts @@ -3,7 +3,9 @@ import "jest-extended"; import { readFileSync, writeFileSync } from "fs"; import { resolve } from "path"; -export class StubStorage { +import { Storage } from "../../src/env.models"; + +export class StubStorage implements Storage { readonly #storage; public constructor() { @@ -14,7 +16,7 @@ export class StubStorage { } } - public async all(): Promise { + public async all(): Promise> { return this.#storage; }