From ca10ea7a3134c0b06dcf7a824afddf06a8a70d84 Mon Sep 17 00:00:00 2001 From: Jordan Ribbink Date: Fri, 24 May 2024 11:42:15 -0700 Subject: [PATCH 1/5] Add support for file and env service key types --- .changeset/big-crews-work.md | 10 +++++ package-lock.json | 15 +------ package.json | 1 - src/config.js | 77 ------------------------------------ src/flow-config.js | 48 ++++++++++++++++++++++ src/index.js | 2 +- src/init.js | 44 ++++++++++++++++++--- src/interaction.js | 3 +- 8 files changed, 100 insertions(+), 100 deletions(-) create mode 100644 .changeset/big-crews-work.md delete mode 100644 src/config.js create mode 100644 src/flow-config.js diff --git a/.changeset/big-crews-work.md b/.changeset/big-crews-work.md new file mode 100644 index 00000000..364fc0d4 --- /dev/null +++ b/.changeset/big-crews-work.md @@ -0,0 +1,10 @@ +--- +"@onflow/flow-js-testing": minor +--- + +Allow loading service key from environment variables and files. + +**BREAKING CHANGES** + +- `getConfigValue` and `set` have been removed as these were just a confusing abstraction above the `@onflow/config` packages +- They have been replaced by exporting they `config` instance directly from the package diff --git a/package-lock.json b/package-lock.json index 50af4d26..c6419ab0 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,16 +1,15 @@ { "name": "@onflow/flow-js-testing", - "version": "0.6.0-stable-cadence.2", + "version": "0.6.0-stable-cadence.3", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "@onflow/flow-js-testing", - "version": "0.6.0-stable-cadence.2", + "version": "0.6.0-stable-cadence.3", "license": "Apache-2.0", "dependencies": { "@onflow/fcl": "1.3.2", - "@onflow/fcl-config": "^0.0.1", "@onflow/flow-cadut": "^0.3.0-stable-cadence.1", "elliptic": "^6.5.4", "esm": "^3.2.25", @@ -3259,11 +3258,6 @@ "node-fetch": "^2.6.7" } }, - "node_modules/@onflow/fcl-config": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/@onflow/fcl-config/-/fcl-config-0.0.1.tgz", - "integrity": "sha512-umvYsAwejX2yGJ5OFxM1dEaKmFEXf+34f4rJfVkfEYztgJqLkUbBkEB8HQsI8M78QUpWkWuNArqwbFvFerBbHA==" - }, "node_modules/@onflow/fcl-core": { "version": "1.9.1", "resolved": "https://registry.npmjs.org/@onflow/fcl-core/-/fcl-core-1.9.1.tgz", @@ -17989,11 +17983,6 @@ "node-fetch": "^2.6.7" } }, - "@onflow/fcl-config": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/@onflow/fcl-config/-/fcl-config-0.0.1.tgz", - "integrity": "sha512-umvYsAwejX2yGJ5OFxM1dEaKmFEXf+34f4rJfVkfEYztgJqLkUbBkEB8HQsI8M78QUpWkWuNArqwbFvFerBbHA==" - }, "@onflow/fcl-core": { "version": "1.9.1", "resolved": "https://registry.npmjs.org/@onflow/fcl-core/-/fcl-core-1.9.1.tgz", diff --git a/package.json b/package.json index d855f79d..86167f14 100644 --- a/package.json +++ b/package.json @@ -56,7 +56,6 @@ }, "dependencies": { "@onflow/fcl": "1.3.2", - "@onflow/fcl-config": "^0.0.1", "@onflow/flow-cadut": "^0.3.0-stable-cadence.1", "elliptic": "^6.5.4", "esm": "^3.2.25", diff --git a/src/config.js b/src/config.js deleted file mode 100644 index e0f08acf..00000000 --- a/src/config.js +++ /dev/null @@ -1,77 +0,0 @@ -/* - * Flow JS Testing - * - * Copyright 2020-2021 Dapper Labs, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import {flowConfig} from "@onflow/fcl-config" -import {config} from "@onflow/fcl" - -/** - * The default compute limit for transactions. - */ -export const DEFAULT_COMPUTE_LIMIT = 9999 - -/** - * Set the default compute limit for transactions. - * - * Previously, providing a compute limit for transactions was optional and - * a fallback existed (DEFAULT_COMPUTE_LIMIT=10). Compute limits may still - * be applied explicitly in a transaction. - * @link https://github.com/onflow/fcl-js/blob/master/packages/sdk/TRANSITIONS.md#0009-deprecate-default-compute-limit - */ -config().put("fcl.limit", DEFAULT_COMPUTE_LIMIT) - -/** - * Get value from provided scope and path. - * @param scope - scope value. - * @param path - value path in config (flow.json) file. - * @param fallback - fallback value. - * @returns {*} - value at specified scope and path. - */ -export const get = (scope, path, fallback) => { - if (typeof path === "string") return get(scope, path.split("/"), fallback) - if (!path.length) return scope - try { - const [head, ...rest] = path - return get(scope[head], rest, fallback) - } catch (_error) { - return fallback - } -} - -/** - * Set globally available config value. - * @param {string} key - key to be used to access stored value. - * @param {string} env - value key in the environment (for example .env file). - * @param {string} conf - value path in config (flow.json) file. - * @param fallback - fallback value to be used if env and conf are absent. - */ -export const set = (key, env, conf, fallback) => { - let value = get(flowConfig(), conf, fallback) - if (!value) { - value = fallback - } - config().put(key, value) -} - -/** - * Returns config value at specified key. - * @param key - key to the value. - * @returns {Promise<*>} - value at specified key. - */ -export const getConfigValue = async key => { - return config().get(key) -} diff --git a/src/flow-config.js b/src/flow-config.js new file mode 100644 index 00000000..69a080b5 --- /dev/null +++ b/src/flow-config.js @@ -0,0 +1,48 @@ +import path from "path" +import fs from "fs" + +const TARGET = "flow.json" +let configPath = null +let config = null + +function isDir(dir) { + return fs.lstatSync(dir).isDirectory() +} + +function listFiles(dir) { + return new Set(fs.readdirSync(dir)) +} + +function parentDir(dir) { + return path.dirname(dir) +} + +function findTarget(dir) { + if (!isDir(dir)) throw new Error(`Not a directory: ${dir}`) + return listFiles(dir).has(TARGET) ? path.resolve(dir, TARGET) : null +} + +export function getConfigPath(dir) { + if (configPath != null) return configPath + + const filePath = findTarget(dir) + if (filePath == null) { + if (dir === parentDir(dir)) { + throw new Error("No flow.json found") + } + return getConfigPath(parentDir(dir)) + } + + configPath = filePath + return configPath +} + +export function flowConfig() { + if (config != null) return config + + const filePath = getConfigPath(process.cwd()) + const content = fs.readFileSync(filePath, "utf8") + config = JSON.parse(content) + + return config +} diff --git a/src/index.js b/src/index.js index 2eb7257a..7d8cb0ad 100644 --- a/src/index.js +++ b/src/index.js @@ -17,7 +17,7 @@ */ export {init} from "./init" -export {set, getConfigValue} from "./config" +export {config} from "@onflow/fcl" export { getTemplate, getScriptCode, diff --git a/src/init.js b/src/init.js index 3cf3cc49..40db5a22 100644 --- a/src/init.js +++ b/src/init.js @@ -16,7 +16,10 @@ * limitations under the License. */ -import {set} from "./config" +import {config} from "@onflow/fcl" +import {flowConfig, getConfigPath} from "./flow-config" + +const DEFAULT_COMPUTE_LIMIT = 9999 /** * Inits framework variables, storing private key of service account and base path @@ -30,12 +33,41 @@ export const init = async (basePath, props = {}) => { pkey = "48a1f554aeebf6bf9fe0d7b5b79d080700b073ee77909973ea0b2f6fbc902", } = props - set("PRIVATE_KEY", process.env.PK, "accounts/emulator-account/key", pkey) - set( + const cfg = flowConfig() + + config().put("PRIVATE_KEY", getServiceKey(cfg), pkey) + config().put( "SERVICE_ADDRESS", - process.env.SERVICE_ADDRESS, - "accounts/emulator-account/address", + cfg?.accounts?.["emulator-account"]?.address, "f8d6e0586b0a20c7" ) - set("BASE_PATH", process.env.BASE_PATH, "testing/paths", basePath) + config().put("BASE_PATH", cfg?.testing?.paths, basePath) + config().put("fcl.limit", DEFAULT_COMPUTE_LIMIT) +} + +function getServiceKey(cfg) { + const value = cfg?.accounts?.["emulator-account"]?.key + if (value) { + if (typeof value === "object") { + switch (value.type) { + case "hex": + return value.privateKey + case "file": + const resovledPath = path.resolve(getConfigPath(), value.location) + return fs.readFileSync(resovledPath, "utf8") + default: + return null + } + } else if (typeof value === "string") { + if (value.startsWith("$")) { + return process.env[value.slice(1)] + } else { + return value + } + } else { + return null + } + } + + return null } diff --git a/src/interaction.js b/src/interaction.js index ad61c0e8..3b80042e 100644 --- a/src/interaction.js +++ b/src/interaction.js @@ -18,7 +18,6 @@ import * as fcl from "@onflow/fcl" import {resolveArguments} from "@onflow/flow-cadut" -import {DEFAULT_COMPUTE_LIMIT} from "./config" import {authorization} from "./crypto" import emulator from "./emulator/emulator" import {getTransactionCode, getScriptCode, defaultsByName} from "./file" @@ -66,7 +65,7 @@ export const extractParameters = ixType => { } // Check that limit is always set - ixLimit = ixLimit || DEFAULT_COMPUTE_LIMIT + ixLimit = ixLimit || (await fcl.config().get("fcl.limit")) if (ixName) { const getIxTemplate = From 5fa82404cd8526d80e2227fe508e321461c7b41d Mon Sep 17 00:00:00 2001 From: Jordan Ribbink Date: Fri, 24 May 2024 11:48:18 -0700 Subject: [PATCH 2/5] fix headers --- src/flow-config.js | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/src/flow-config.js b/src/flow-config.js index 69a080b5..27f1ec7e 100644 --- a/src/flow-config.js +++ b/src/flow-config.js @@ -1,3 +1,21 @@ +/* + * Flow JS Testing + * + * Copyright 2020-2021 Dapper Labs, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + import path from "path" import fs from "fs" From f3454e0a7ca24c5192c8e74baee65afa28a8b2fa Mon Sep 17 00:00:00 2001 From: Jordan Ribbink Date: Fri, 24 May 2024 13:26:50 -0700 Subject: [PATCH 3/5] missing imports --- src/init.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/init.js b/src/init.js index 40db5a22..57da0ed2 100644 --- a/src/init.js +++ b/src/init.js @@ -18,6 +18,8 @@ import {config} from "@onflow/fcl" import {flowConfig, getConfigPath} from "./flow-config" +import path from "path" +import fs from "fs" const DEFAULT_COMPUTE_LIMIT = 9999 From 31cbadbf982553fa638b1cd01ceb24b96e098b98 Mon Sep 17 00:00:00 2001 From: Jordan Ribbink Date: Fri, 24 May 2024 13:40:38 -0700 Subject: [PATCH 4/5] fix tests --- src/emulator/logger.js | 1 + src/init.js | 10 +++++----- test/basic/config.test.js | 9 --------- 3 files changed, 6 insertions(+), 14 deletions(-) delete mode 100644 test/basic/config.test.js diff --git a/src/emulator/logger.js b/src/emulator/logger.js index 526edc20..beb81b85 100644 --- a/src/emulator/logger.js +++ b/src/emulator/logger.js @@ -41,6 +41,7 @@ export class Logger extends EventEmitter { super(options) this.handleMessage = this.handleMessage.bind(this) this.process = null + this.setMaxListeners(100) } /** diff --git a/src/init.js b/src/init.js index 57da0ed2..d0c2cff4 100644 --- a/src/init.js +++ b/src/init.js @@ -37,13 +37,12 @@ export const init = async (basePath, props = {}) => { const cfg = flowConfig() - config().put("PRIVATE_KEY", getServiceKey(cfg), pkey) + config().put("PRIVATE_KEY", getServiceKey(cfg) ?? pkey) config().put( "SERVICE_ADDRESS", - cfg?.accounts?.["emulator-account"]?.address, - "f8d6e0586b0a20c7" + cfg?.accounts?.["emulator-account"]?.address ?? "f8d6e0586b0a20c7" ) - config().put("BASE_PATH", cfg?.testing?.paths, basePath) + config().put("BASE_PATH", cfg?.testing?.paths ?? basePath) config().put("fcl.limit", DEFAULT_COMPUTE_LIMIT) } @@ -55,7 +54,8 @@ function getServiceKey(cfg) { case "hex": return value.privateKey case "file": - const resovledPath = path.resolve(getConfigPath(), value.location) + const configDir = path.dirname(getConfigPath()) + const resovledPath = path.resolve(configDir, value.location) return fs.readFileSync(resovledPath, "utf8") default: return null diff --git a/test/basic/config.test.js b/test/basic/config.test.js deleted file mode 100644 index d2279c19..00000000 --- a/test/basic/config.test.js +++ /dev/null @@ -1,9 +0,0 @@ -import {getConfigValue} from "../../src" - -describe("configuration tests", () => { - test("defaultComputeLimit - set default compute limit", async () => { - const limit = await getConfigValue("fcl.limit") - - expect(limit).toBe(9999) - }) -}) From 549375af9e4725a2ff3b869eb41f1cf6798c2c40 Mon Sep 17 00:00:00 2001 From: Jordan Ribbink Date: Fri, 24 May 2024 13:42:36 -0700 Subject: [PATCH 5/5] fix case block linting --- src/init.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/init.js b/src/init.js index d0c2cff4..c67004ee 100644 --- a/src/init.js +++ b/src/init.js @@ -53,10 +53,11 @@ function getServiceKey(cfg) { switch (value.type) { case "hex": return value.privateKey - case "file": + case "file": { const configDir = path.dirname(getConfigPath()) const resovledPath = path.resolve(configDir, value.location) return fs.readFileSync(resovledPath, "utf8") + } default: return null }