From 83ff0f36401cbf6e95c0a1ceb9fa921a82dc6830 Mon Sep 17 00:00:00 2001 From: Sai Ranjit Tummalapalli <75250487+sairanjitAW@users.noreply.github.com> Date: Tue, 10 May 2022 13:26:55 +0530 Subject: [PATCH] feat(core): add support for postgres wallet type (#699) Signed-off-by: Sai Ranjit Tummalapalli Co-authored-by: Timo Glastra --- .github/workflows/continuous-integration.yml | 2 +- Dockerfile | 17 +++- packages/core/src/types.ts | 4 + packages/core/src/wallet/IndyWallet.ts | 62 ++++++++--- packages/core/tests/helpers.ts | 38 ++++++- packages/core/tests/postgres.test.ts | 98 ++++++++++++++++++ packages/node/package.json | 4 + packages/node/src/PostgresPlugin.ts | 102 +++++++++++++++++++ packages/node/src/index.ts | 10 +- yarn.lock | 76 +++++++++++++- 10 files changed, 392 insertions(+), 21 deletions(-) create mode 100644 packages/core/tests/postgres.test.ts create mode 100644 packages/node/src/PostgresPlugin.ts diff --git a/.github/workflows/continuous-integration.yml b/.github/workflows/continuous-integration.yml index 032546729d..4f4cfed1e3 100644 --- a/.github/workflows/continuous-integration.yml +++ b/.github/workflows/continuous-integration.yml @@ -11,7 +11,7 @@ on: env: TEST_AGENT_PUBLIC_DID_SEED: 000000000000000000000000Trustee9 GENESIS_TXN_PATH: network/genesis/local-genesis.txn - LD_LIBRARY_PATH: /home/runner/work/aries-framework-javascript/indy-sdk/experimental/plugins/postgres_storage/target/release # for Linux + LIB_INDY_STRG_POSTGRES: /home/runner/work/aries-framework-javascript/indy-sdk/experimental/plugins/postgres_storage/target/release # for Linux # Make sure we're not running multiple release steps at the same time as this can give issues with determining the next npm version to release. # Ideally we only add this to the 'release' job so it doesn't limit PR runs, but github can't guarantee the job order in that case: diff --git a/Dockerfile b/Dockerfile index 36d396a3d8..d1c75fecd6 100644 --- a/Dockerfile +++ b/Dockerfile @@ -7,7 +7,9 @@ RUN apt-get update -y && apt-get install -y \ apt-transport-https \ curl \ # Only needed to build indy-sdk - build-essential + build-essential \ + git \ + libzmq3-dev libsodium-dev pkg-config libssl-dev # libindy RUN apt-key adv --keyserver keyserver.ubuntu.com --recv-keys CE7709D068DB5E88 @@ -28,6 +30,19 @@ RUN apt-get update -y && apt-get install -y --allow-unauthenticated \ # Install yarn seperately due to `no-install-recommends` to skip nodejs install RUN apt-get install -y --no-install-recommends yarn +# postgres plugin setup +# install rust and set up rustup +RUN curl https://sh.rustup.rs -sSf | bash -s -- -y +ENV PATH="/root/.cargo/bin:${PATH}" + +# clone indy-sdk and build postgres plugin +RUN git clone https://github.com/hyperledger/indy-sdk.git +WORKDIR /indy-sdk/experimental/plugins/postgres_storage/ +RUN cargo build --release + +# set up library path for postgres plugin +ENV LIB_INDY_STRG_POSTGRES="/indy-sdk/experimental/plugins/postgres_storage/target/release" + FROM base as final # AFJ specifc setup diff --git a/packages/core/src/types.ts b/packages/core/src/types.ts index 6910eabd1d..3524aa2eb7 100644 --- a/packages/core/src/types.ts +++ b/packages/core/src/types.ts @@ -20,6 +20,10 @@ export interface WalletConfig { id: string key: string keyDerivationMethod?: KeyDerivationMethod + storage?: { + type: string + [key: string]: unknown + } } export interface WalletConfigRekey { diff --git a/packages/core/src/wallet/IndyWallet.ts b/packages/core/src/wallet/IndyWallet.ts index 16c418f0ea..3c683e1ef6 100644 --- a/packages/core/src/wallet/IndyWallet.ts +++ b/packages/core/src/wallet/IndyWallet.ts @@ -9,7 +9,7 @@ import type { } from '../types' import type { Buffer } from '../utils/buffer' import type { Wallet, DidInfo, DidConfig } from './Wallet' -import type { default as Indy } from 'indy-sdk' +import type { default as Indy, WalletStorageConfig } from 'indy-sdk' import { Lifecycle, scoped } from 'tsyringe' @@ -67,6 +67,41 @@ export class IndyWallet implements Wallet { return this.walletConfig.id } + private walletStorageConfig(walletConfig: WalletConfig): Indy.WalletConfig { + const walletStorageConfig: Indy.WalletConfig = { + id: walletConfig.id, + storage_type: walletConfig.storage?.type, + } + + if (walletConfig.storage?.config) { + walletStorageConfig.storage_config = walletConfig.storage?.config as WalletStorageConfig + } + + return walletStorageConfig + } + + private walletCredentials( + walletConfig: WalletConfig, + rekey?: string, + rekeyDerivation?: KeyDerivationMethod + ): Indy.OpenWalletCredentials { + const walletCredentials: Indy.OpenWalletCredentials = { + key: walletConfig.key, + key_derivation_method: walletConfig.keyDerivationMethod, + } + if (rekey) { + walletCredentials.rekey = rekey + } + if (rekeyDerivation) { + walletCredentials.rekey_derivation_method = rekeyDerivation + } + if (walletConfig.storage?.credentials) { + walletCredentials.storage_credentials = walletConfig.storage?.credentials as Record + } + + return walletCredentials + } + /** * @throws {WalletDuplicateError} if the wallet already exists * @throws {WalletError} if another error occurs @@ -84,11 +119,7 @@ export class IndyWallet implements Wallet { this.logger.debug(`Creating wallet '${walletConfig.id}' using SQLite storage`) try { - await this.indy.createWallet( - { id: walletConfig.id }, - { key: walletConfig.key, key_derivation_method: walletConfig.keyDerivationMethod } - ) - + await this.indy.createWallet(this.walletStorageConfig(walletConfig), this.walletCredentials(walletConfig)) this.walletConfig = walletConfig // We usually want to create master secret only once, therefore, we can to do so when creating a wallet. @@ -139,7 +170,11 @@ export class IndyWallet implements Wallet { throw new WalletError('Wallet rekey undefined!. Please specify the new wallet key') } await this._open( - { id: walletConfig.id, key: walletConfig.key, keyDerivationMethod: walletConfig.keyDerivationMethod }, + { + id: walletConfig.id, + key: walletConfig.key, + keyDerivationMethod: walletConfig.keyDerivationMethod, + }, walletConfig.rekey, walletConfig.rekeyDerivationMethod ) @@ -162,13 +197,8 @@ export class IndyWallet implements Wallet { try { this.walletHandle = await this.indy.openWallet( - { id: walletConfig.id }, - { - key: walletConfig.key, - rekey: rekey, - key_derivation_method: walletConfig.keyDerivationMethod, - rekey_derivation_method: rekeyDerivation, - } + this.walletStorageConfig(walletConfig), + this.walletCredentials(walletConfig, rekey, rekeyDerivation) ) if (rekey) { this.walletConfig = { ...walletConfig, key: rekey, keyDerivationMethod: rekeyDerivation } @@ -224,8 +254,8 @@ export class IndyWallet implements Wallet { try { await this.indy.deleteWallet( - { id: this.walletConfig.id }, - { key: this.walletConfig.key, key_derivation_method: this.walletConfig.keyDerivationMethod } + this.walletStorageConfig(this.walletConfig), + this.walletCredentials(this.walletConfig) ) } catch (error) { if (isIndyError(error, 'WalletNotFoundError')) { diff --git a/packages/core/tests/helpers.ts b/packages/core/tests/helpers.ts index ae89b5f68e..271d9125db 100644 --- a/packages/core/tests/helpers.ts +++ b/packages/core/tests/helpers.ts @@ -23,7 +23,7 @@ import { catchError, filter, map, timeout } from 'rxjs/operators' import { SubjectInboundTransport } from '../../../tests/transport/SubjectInboundTransport' import { SubjectOutboundTransport } from '../../../tests/transport/SubjectOutboundTransport' -import { agentDependencies } from '../../node/src' +import { agentDependencies, WalletScheme } from '../../node/src' import { PresentationPreview, PresentationPreviewAttribute, @@ -84,6 +84,42 @@ export function getBaseConfig(name: string, extraConfig: Partial = { return { config, agentDependencies } as const } +export function getBasePostgresConfig(name: string, extraConfig: Partial = {}) { + const config: InitConfig = { + label: `Agent: ${name}`, + walletConfig: { + id: `Wallet${name}`, + key: `Key${name}`, + storage: { + type: 'postgres_storage', + config: { + url: 'localhost:5432', + wallet_scheme: WalletScheme.DatabasePerWallet, + }, + credentials: { + account: 'postgres', + password: 'postgres', + admin_account: 'postgres', + admin_password: 'postgres', + }, + }, + }, + publicDidSeed, + autoAcceptConnections: true, + indyLedgers: [ + { + id: `pool-${name}`, + isProduction: false, + genesisPath, + }, + ], + logger: new TestLogger(LogLevel.error, name), + ...extraConfig, + } + + return { config, agentDependencies } as const +} + export function getAgentConfig(name: string, extraConfig: Partial = {}) { const { config, agentDependencies } = getBaseConfig(name, extraConfig) return new AgentConfig(config, agentDependencies) diff --git a/packages/core/tests/postgres.test.ts b/packages/core/tests/postgres.test.ts new file mode 100644 index 0000000000..bc2279ee69 --- /dev/null +++ b/packages/core/tests/postgres.test.ts @@ -0,0 +1,98 @@ +import type { SubjectMessage } from '../../../tests/transport/SubjectInboundTransport' +import type { IndyPostgresStorageConfig } from '../../node/src' +import type { ConnectionRecord } from '../src/modules/connections' + +import { Subject } from 'rxjs' + +import { SubjectInboundTransport } from '../../../tests/transport/SubjectInboundTransport' +import { SubjectOutboundTransport } from '../../../tests/transport/SubjectOutboundTransport' +import { loadPostgresPlugin, WalletScheme } from '../../node/src' +import { Agent } from '../src/agent/Agent' + +import { waitForBasicMessage, getBasePostgresConfig } from './helpers' + +const alicePostgresConfig = getBasePostgresConfig('AgentsAlice', { + endpoints: ['rxjs:alice'], +}) +const bobPostgresConfig = getBasePostgresConfig('AgentsBob', { + endpoints: ['rxjs:bob'], +}) + +describe('postgres agents', () => { + let aliceAgent: Agent + let bobAgent: Agent + let aliceConnection: ConnectionRecord + let bobConnection: ConnectionRecord + + afterAll(async () => { + await bobAgent.shutdown() + await bobAgent.wallet.delete() + await aliceAgent.shutdown() + await aliceAgent.wallet.delete() + }) + + test('make a connection between postgres agents', async () => { + const aliceMessages = new Subject() + const bobMessages = new Subject() + + const subjectMap = { + 'rxjs:alice': aliceMessages, + 'rxjs:bob': bobMessages, + } + + const storageConfig: IndyPostgresStorageConfig = { + type: 'postgres_storage', + config: { + url: 'localhost:5432', + wallet_scheme: WalletScheme.DatabasePerWallet, + }, + credentials: { + account: 'postgres', + password: 'postgres', + admin_account: 'postgres', + admin_password: 'postgres', + }, + } + + // loading the postgres wallet plugin + await loadPostgresPlugin(storageConfig.config, storageConfig.credentials) + + aliceAgent = new Agent(alicePostgresConfig.config, alicePostgresConfig.agentDependencies) + aliceAgent.registerInboundTransport(new SubjectInboundTransport(aliceMessages)) + aliceAgent.registerOutboundTransport(new SubjectOutboundTransport(subjectMap)) + await aliceAgent.initialize() + + bobAgent = new Agent(bobPostgresConfig.config, bobPostgresConfig.agentDependencies) + bobAgent.registerInboundTransport(new SubjectInboundTransport(bobMessages)) + bobAgent.registerOutboundTransport(new SubjectOutboundTransport(subjectMap)) + await bobAgent.initialize() + + const aliceConnectionAtAliceBob = await aliceAgent.connections.createConnection() + const bobConnectionAtBobAlice = await bobAgent.connections.receiveInvitation(aliceConnectionAtAliceBob.invitation) + + aliceConnection = await aliceAgent.connections.returnWhenIsConnected(aliceConnectionAtAliceBob.connectionRecord.id) + bobConnection = await bobAgent.connections.returnWhenIsConnected(bobConnectionAtBobAlice.id) + + expect(aliceConnection).toBeConnectedWith(bobConnection) + expect(bobConnection).toBeConnectedWith(aliceConnection) + }) + + test('send a message to connection', async () => { + const message = 'hello, world' + await aliceAgent.basicMessages.sendMessage(aliceConnection.id, message) + + const basicMessage = await waitForBasicMessage(bobAgent, { + content: message, + }) + + expect(basicMessage.content).toBe(message) + }) + + test('can shutdown and re-initialize the same postgres agent', async () => { + expect(aliceAgent.isInitialized).toBe(true) + await aliceAgent.shutdown() + expect(aliceAgent.isInitialized).toBe(false) + await aliceAgent.initialize() + expect(aliceAgent.isInitialized).toBe(true) + }) +}) diff --git a/packages/node/package.json b/packages/node/package.json index 61df944924..ad137f2003 100644 --- a/packages/node/package.json +++ b/packages/node/package.json @@ -30,14 +30,18 @@ "dependencies": { "@aries-framework/core": "0.1.0", "express": "^4.17.1", + "ffi-napi": "^4.0.3", "indy-sdk": "^1.16.0-dev-1636", "node-fetch": "^2.6.1", + "ref-napi": "^3.0.3", "ws": "^7.5.3" }, "devDependencies": { "@types/express": "^4.17.13", + "@types/ffi-napi": "^4.0.5", "@types/node": "^15.14.4", "@types/node-fetch": "^2.5.10", + "@types/ref-napi": "^3.0.4", "@types/ws": "^7.4.6", "rimraf": "~3.0.2", "typescript": "~4.3.0" diff --git a/packages/node/src/PostgresPlugin.ts b/packages/node/src/PostgresPlugin.ts new file mode 100644 index 0000000000..a707a842cd --- /dev/null +++ b/packages/node/src/PostgresPlugin.ts @@ -0,0 +1,102 @@ +import { Library } from 'ffi-napi' +import fs from 'fs' +import os from 'os' +import path from 'path' +import { types } from 'ref-napi' + +const LIBNAME = 'indystrgpostgres' +const ENV_VAR = 'LIB_INDY_STRG_POSTGRES' + +type Platform = 'darwin' | 'linux' | 'win32' + +type ExtensionMap = Record + +const extensions: ExtensionMap = { + darwin: { prefix: 'lib', extension: '.dylib' }, + linux: { prefix: 'lib', extension: '.so' }, + win32: { extension: '.dll' }, +} + +const libPaths: Record> = { + darwin: ['/usr/local/lib/', '/usr/lib/', '/opt/homebrew/opt/'], + linux: ['/usr/lib/', '/usr/local/lib/'], + win32: ['c:\\windows\\system32\\'], +} + +// Alias for a simple function to check if the path exists +const doesPathExist = fs.existsSync + +const getLibrary = () => { + // Detect OS; darwin, linux and windows are only supported + const platform = os.platform() + + if (platform !== 'linux' && platform !== 'win32' && platform !== 'darwin') + throw new Error(`Unsupported platform: ${platform}. linux, win32 and darwin are supported.`) + + // Get a potential path from the environment variable + const pathFromEnvironment = process.env[ENV_VAR] + + // Get the paths specific to the users operating system + const platformPaths = libPaths[platform] + + // Check if the path from the environment variable is supplied and add it + // We use unshift here so that when we want to get a valid library path this will be the first to resolve + if (pathFromEnvironment) platformPaths.unshift(pathFromEnvironment) + + // Create the path + file + const libraries = platformPaths.map((p) => + path.join(p, `${extensions[platform].prefix ?? ''}${LIBNAME}${extensions[platform].extension}`) + ) + + // Gaurd so we quit if there is no valid path for the library + if (!libraries.some(doesPathExist)) + throw new Error(`Could not find ${LIBNAME} with these paths: ${libraries.join(' ')}`) + + // Get the first valid library + // Casting here as a string because there is a guard of none of the paths + // would be valid + const validLibraryPath = libraries.find((l) => doesPathExist(l)) as string + + return Library(validLibraryPath, { + postgresstorage_init: [types.int, []], + init_storagetype: [types.int, ['string', 'string']], + }) +} + +type NativeIndyPostgres = { + postgresstorage_init: () => number + init_storagetype: (arg0: string, arg1: string) => number +} + +export const indyPostgresStorage = getLibrary() as NativeIndyPostgres + +export interface WalletStorageConfig { + url: string + wallet_scheme: WalletScheme + path?: string +} + +export interface WalletStorageCredentials { + account: string + password: string + admin_account: string + admin_password: string +} + +export enum WalletScheme { + DatabasePerWallet = 'DatabasePerWallet', + MultiWalletSingleTable = 'MultiWalletSingleTable', + MultiWalletSingleTableSharedPool = 'MultiWalletSingleTableSharedPool', +} + +export interface IndyPostgresStorageConfig { + type: 'postgres_storage' + config: WalletStorageConfig + credentials: WalletStorageCredentials +} + +export function loadPostgresPlugin(config: WalletStorageConfig, credentials: WalletStorageCredentials) { + indyPostgresStorage.postgresstorage_init() + indyPostgresStorage.init_storagetype(JSON.stringify(config), JSON.stringify(credentials)) + return true +} diff --git a/packages/node/src/index.ts b/packages/node/src/index.ts index 235c72f520..5e58035b32 100644 --- a/packages/node/src/index.ts +++ b/packages/node/src/index.ts @@ -6,6 +6,7 @@ import fetch from 'node-fetch' import WebSocket from 'ws' import { NodeFileSystem } from './NodeFileSystem' +import { IndyPostgresStorageConfig, loadPostgresPlugin, WalletScheme } from './PostgresPlugin' import { HttpInboundTransport } from './transport/HttpInboundTransport' import { WsInboundTransport } from './transport/WsInboundTransport' @@ -17,4 +18,11 @@ const agentDependencies: AgentDependencies = { indy, } -export { agentDependencies, HttpInboundTransport, WsInboundTransport } +export { + agentDependencies, + HttpInboundTransport, + WsInboundTransport, + loadPostgresPlugin, + IndyPostgresStorageConfig, + WalletScheme, +} diff --git a/yarn.lock b/yarn.lock index 11a9b9dda6..f1ea05bf10 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2261,6 +2261,15 @@ "@types/qs" "*" "@types/serve-static" "*" +"@types/ffi-napi@^4.0.5": + version "4.0.5" + resolved "https://registry.yarnpkg.com/@types/ffi-napi/-/ffi-napi-4.0.5.tgz#0b2dc2d549361947a117d55156ff34fd9632c3df" + integrity sha512-WDPpCcHaPhHmP1FIw3ds/+OLt8bYQ/h3SO7o+8kH771PL21kHVzTwii7+WyMBXMQrBsR6xVU2y7w+h+9ggpaQw== + dependencies: + "@types/node" "*" + "@types/ref-napi" "*" + "@types/ref-struct-di" "*" + "@types/figlet@^1.5.4": version "1.5.4" resolved "https://registry.yarnpkg.com/@types/figlet/-/figlet-1.5.4.tgz#54a426d63e921a9bca44102c5b1b1f206fa56d93" @@ -2409,6 +2418,20 @@ "@types/scheduler" "*" csstype "^3.0.2" +"@types/ref-napi@*", "@types/ref-napi@^3.0.4": + version "3.0.4" + resolved "https://registry.yarnpkg.com/@types/ref-napi/-/ref-napi-3.0.4.tgz#d7edc063b244c85767867ce1167ec2d7051728a1" + integrity sha512-ng8SCmdZbz1GHaW3qgGoX9IaHoIvgMqgBHLe3sv18NbAkHVgnjRW8fJq51VTUm4lnJyLu60q9/002o7qjOg13g== + dependencies: + "@types/node" "*" + +"@types/ref-struct-di@*": + version "1.1.6" + resolved "https://registry.yarnpkg.com/@types/ref-struct-di/-/ref-struct-di-1.1.6.tgz#9775753b24ba5bf248dd66d79d4fdb7cebef6e95" + integrity sha512-+Sa2H3ynDYo2ungR3d5kmNetlkAYNqQVjJvs1k7i6zvo7Zu/qb+OsrXU54RuiOYJCwY9piN+hOd4YRRaiEOqgw== + dependencies: + "@types/ref-napi" "*" + "@types/scheduler@*": version "0.16.2" resolved "https://registry.yarnpkg.com/@types/scheduler/-/scheduler-0.16.2.tgz#1a62f89525723dde24ba1b01b092bf5df8ad4d39" @@ -3988,7 +4011,7 @@ debug@4, debug@^4.0.1, debug@^4.1.0, debug@^4.1.1, debug@^4.3.1, debug@^4.3.3, d dependencies: ms "2.1.2" -debug@^3.2.7: +debug@^3.1.0, debug@^3.2.7: version "3.2.7" resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.7.tgz#72580b7e9145fb39b6676f9c5e5fb100b934179a" integrity sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ== @@ -4783,6 +4806,18 @@ fb-watchman@^2.0.0: dependencies: bser "2.1.1" +ffi-napi@^4.0.3: + version "4.0.3" + resolved "https://registry.yarnpkg.com/ffi-napi/-/ffi-napi-4.0.3.tgz#27a8d42a8ea938457154895c59761fbf1a10f441" + integrity sha512-PMdLCIvDY9mS32RxZ0XGb95sonPRal8aqRhLbeEtWKZTe2A87qRFG9HjOhvG8EX2UmQw5XNRMIOT+1MYlWmdeg== + dependencies: + debug "^4.1.1" + get-uv-event-loop-napi-h "^1.0.5" + node-addon-api "^3.0.0" + node-gyp-build "^4.2.1" + ref-napi "^2.0.1 || ^3.0.2" + ref-struct-di "^1.1.0" + figlet@^1.5.2: version "1.5.2" resolved "https://registry.yarnpkg.com/figlet/-/figlet-1.5.2.tgz#dda34ff233c9a48e36fcff6741aeb5bafe49b634" @@ -5118,6 +5153,18 @@ get-symbol-description@^1.0.0: call-bind "^1.0.2" get-intrinsic "^1.1.1" +get-symbol-from-current-process-h@^1.0.1, get-symbol-from-current-process-h@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/get-symbol-from-current-process-h/-/get-symbol-from-current-process-h-1.0.2.tgz#510af52eaef873f7028854c3377f47f7bb200265" + integrity sha512-syloC6fsCt62ELLrr1VKBM1ggOpMdetX9hTrdW77UQdcApPHLmf7CI7OKcN1c9kYuNxKcDe4iJ4FY9sX3aw2xw== + +get-uv-event-loop-napi-h@^1.0.5: + version "1.0.6" + resolved "https://registry.yarnpkg.com/get-uv-event-loop-napi-h/-/get-uv-event-loop-napi-h-1.0.6.tgz#42b0b06b74c3ed21fbac8e7c72845fdb7a200208" + integrity sha512-t5c9VNR84nRoF+eLiz6wFrEp1SE2Acg0wS+Ysa2zF0eROes+LzOfuTaVHxGy8AbS8rq7FHEJzjnCZo1BupwdJg== + dependencies: + get-symbol-from-current-process-h "^1.0.1" + get-value@^2.0.3, get-value@^2.0.6: version "2.0.6" resolved "https://registry.yarnpkg.com/get-value/-/get-value-2.0.6.tgz#dc15ca1c672387ca76bd37ac0a395ba2042a2c28" @@ -7575,6 +7622,11 @@ nocache@^2.1.0: resolved "https://registry.yarnpkg.com/nocache/-/nocache-2.1.0.tgz#120c9ffec43b5729b1d5de88cd71aa75a0ba491f" integrity sha512-0L9FvHG3nfnnmaEQPjT9xhfN4ISk0A8/2j4M37Np4mcDesJjHgEUfgPhdCyZuFI954tjokaIj/A3NdpFNdEh4Q== +node-addon-api@^3.0.0: + version "3.2.1" + resolved "https://registry.yarnpkg.com/node-addon-api/-/node-addon-api-3.2.1.tgz#81325e0a2117789c0128dab65e7e38f07ceba161" + integrity sha512-mmcei9JghVNDYydghQmeDX8KoAm0FAiYyIcUt/N4nhyAipB17pllZQDOJD2fotxABnt4Mdz+dKTO7eftLg4d0A== + node-dir@^0.1.17: version "0.1.17" resolved "https://registry.yarnpkg.com/node-dir/-/node-dir-0.1.17.tgz#5f5665d93351335caabef8f1c554516cf5f1e4e5" @@ -7589,6 +7641,11 @@ node-fetch@2.6.7, node-fetch@^2.2.0, node-fetch@^2.6.0, node-fetch@^2.6.1, node- dependencies: whatwg-url "^5.0.0" +node-gyp-build@^4.2.1: + version "4.4.0" + resolved "https://registry.yarnpkg.com/node-gyp-build/-/node-gyp-build-4.4.0.tgz#42e99687ce87ddeaf3a10b99dc06abc11021f3f4" + integrity sha512-amJnQCcgtRVw9SvoebO3BKGESClrfXGCUTX9hSn1OuGQTQBOZmVd0Z0OlecpuRksKvbsUqALE8jls/ErClAPuQ== + node-gyp@^5.0.2: version "5.1.1" resolved "https://registry.yarnpkg.com/node-gyp/-/node-gyp-5.1.1.tgz#eb915f7b631c937d282e33aed44cb7a025f62a3e" @@ -8755,6 +8812,23 @@ redent@^3.0.0: indent-string "^4.0.0" strip-indent "^3.0.0" +"ref-napi@^2.0.1 || ^3.0.2", ref-napi@^3.0.3: + version "3.0.3" + resolved "https://registry.yarnpkg.com/ref-napi/-/ref-napi-3.0.3.tgz#e259bfc2bbafb3e169e8cd9ba49037dd00396b22" + integrity sha512-LiMq/XDGcgodTYOMppikEtJelWsKQERbLQsYm0IOOnzhwE9xYZC7x8txNnFC9wJNOkPferQI4vD4ZkC0mDyrOA== + dependencies: + debug "^4.1.1" + get-symbol-from-current-process-h "^1.0.2" + node-addon-api "^3.0.0" + node-gyp-build "^4.2.1" + +ref-struct-di@^1.1.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/ref-struct-di/-/ref-struct-di-1.1.1.tgz#5827b1d3b32372058f177547093db1fe1602dc10" + integrity sha512-2Xyn/0Qgz89VT+++WP0sTosdm9oeowLP23wRJYhG4BFdMUrLj3jhwHZNEytYNYgtPKLNTP3KJX4HEgBvM1/Y2g== + dependencies: + debug "^3.1.0" + reflect-metadata@^0.1.13: version "0.1.13" resolved "https://registry.yarnpkg.com/reflect-metadata/-/reflect-metadata-0.1.13.tgz#67ae3ca57c972a2aa1642b10fe363fe32d49dc08"