From 690c503c50e0f3503a7b9a3a543348ae6b89357e Mon Sep 17 00:00:00 2001 From: Otavio Jacobi Date: Thu, 19 Dec 2024 15:31:07 -0300 Subject: [PATCH] Move to ESM Change-type: major --- .eslintignore | 2 - .eslintrc.js | 21 --- automation/build-bin.ts | 2 +- automation/capitanodoc/capitanodoc.ts | 2 +- automation/capitanodoc/index.ts | 2 +- automation/capitanodoc/markdown.ts | 2 +- automation/capitanodoc/utils.ts | 2 +- automation/check-doc.ts | 4 +- automation/run.ts | 2 +- automation/utils.ts | 4 +- bin/run.js | 12 +- eslint.config.js | 10 +- package.json | 1 + src/app.ts | 49 +++---- src/auth/index.ts | 8 +- src/auth/server.ts | 10 +- src/auth/utils.ts | 2 +- src/commands/api-key/generate.ts | 6 +- src/commands/api-key/list.ts | 6 +- src/commands/api-key/revoke.ts | 2 +- src/commands/app/create.ts | 4 +- src/commands/block/create.ts | 4 +- src/commands/build/index.ts | 48 ++++--- src/commands/config/generate.ts | 39 +++-- src/commands/config/inject.ts | 6 +- src/commands/config/read.ts | 6 +- src/commands/config/reconfigure.ts | 10 +- src/commands/config/write.ts | 6 +- src/commands/deploy/index.ts | 37 +++-- src/commands/device-type/list.ts | 4 +- src/commands/device/deactivate.ts | 6 +- src/commands/device/detect.ts | 6 +- src/commands/device/identify.ts | 4 +- src/commands/device/index.ts | 10 +- src/commands/device/init.ts | 18 +-- src/commands/device/list.ts | 12 +- src/commands/device/local-mode.ts | 2 +- src/commands/device/logs.ts | 16 +-- src/commands/device/move.ts | 12 +- src/commands/device/note.ts | 8 +- src/commands/device/os-update.ts | 14 +- src/commands/device/pin.ts | 4 +- src/commands/device/public-url.ts | 4 +- src/commands/device/purge.ts | 2 +- src/commands/device/reboot.ts | 4 +- src/commands/device/register.ts | 8 +- src/commands/device/rename.ts | 2 +- src/commands/device/restart.ts | 8 +- src/commands/device/rm.ts | 6 +- src/commands/device/shutdown.ts | 6 +- src/commands/device/ssh.ts | 18 +-- src/commands/device/start-service.ts | 6 +- src/commands/device/stop-service.ts | 6 +- src/commands/device/track-fleet.ts | 2 +- src/commands/device/tunnel.ts | 14 +- src/commands/env/list.ts | 24 ++-- src/commands/env/rename.ts | 8 +- src/commands/env/rm.ts | 10 +- src/commands/env/set.ts | 18 +-- src/commands/fleet/create.ts | 4 +- src/commands/fleet/index.ts | 12 +- src/commands/fleet/list.ts | 4 +- src/commands/fleet/pin.ts | 4 +- src/commands/fleet/purge.ts | 8 +- src/commands/fleet/rename.ts | 14 +- src/commands/fleet/restart.ts | 8 +- src/commands/fleet/rm.ts | 12 +- src/commands/fleet/track-latest.ts | 2 +- src/commands/internal/osinit.ts | 4 +- src/commands/join/index.ts | 12 +- src/commands/leave/index.ts | 8 +- src/commands/local/configure.ts | 6 +- src/commands/local/flash.ts | 8 +- src/commands/login/index.ts | 14 +- src/commands/logout/index.ts | 2 +- src/commands/organization/list.ts | 4 +- src/commands/os/build-config.ts | 8 +- src/commands/os/configure.ts | 47 +++--- src/commands/os/download.ts | 10 +- src/commands/os/initialize.ts | 12 +- src/commands/os/versions.ts | 6 +- src/commands/preload/index.ts | 29 ++-- src/commands/push/index.ts | 28 ++-- src/commands/release/finalize.ts | 4 +- src/commands/release/index.ts | 8 +- src/commands/release/invalidate.ts | 4 +- src/commands/release/list.ts | 10 +- src/commands/release/validate.ts | 4 +- src/commands/settings/index.ts | 2 +- src/commands/ssh-key/add.ts | 2 +- src/commands/ssh-key/index.ts | 4 +- src/commands/ssh-key/list.ts | 2 +- src/commands/ssh-key/rm.ts | 8 +- src/commands/support/index.ts | 17 +-- src/commands/tag/list.ts | 27 ++-- src/commands/tag/rm.ts | 27 ++-- src/commands/tag/set.ts | 27 ++-- src/commands/util/available-drives.ts | 2 +- src/commands/version/index.ts | 4 +- src/commands/whoami/index.ts | 2 +- src/deprecation.ts | 14 +- src/errors.ts | 10 +- src/events.ts | 8 +- src/fast-boot.ts | 19 +-- src/help.ts | 15 +- src/hooks/command-not-found/suggest.ts | 2 +- src/hooks/prerun.ts | 8 +- src/preparser.ts | 8 +- src/utils/application-create.ts | 8 +- src/utils/bootstrap.ts | 5 +- src/utils/cloud.ts | 10 +- src/utils/common-args.ts | 2 +- src/utils/common-flags.ts | 33 ++++- src/utils/compose.ts | 37 ++--- src/utils/compose_ts.ts | 135 +++++++++--------- src/utils/config.ts | 14 +- src/utils/deploy-legacy.ts | 42 +++--- src/utils/device/api.ts | 10 +- src/utils/device/deploy.ts | 30 ++-- src/utils/device/errors.ts | 4 +- src/utils/device/live.ts | 35 +++-- src/utils/device/logs.ts | 14 +- src/utils/device/ssh.ts | 8 +- src/utils/discover.ts | 6 +- src/utils/docker.ts | 6 +- src/utils/env-common.ts | 4 +- src/utils/eol-conversion.ts | 2 +- src/utils/helpers.ts | 19 ++- src/utils/ignore.ts | 10 +- src/utils/image-manager.ts | 6 +- src/utils/lazy.ts | 8 +- src/utils/logger.ts | 6 +- src/utils/normalization.ts | 2 +- src/utils/oclif-utils.ts | 4 + src/utils/patterns.ts | 12 +- src/utils/promote.ts | 20 +-- src/utils/proxy.ts | 2 +- src/utils/qemu.ts | 9 +- src/utils/remote-build.ts | 12 +- src/utils/sdk.ts | 4 +- src/utils/ssh.ts | 12 +- src/utils/sudo.ts | 10 +- src/utils/tty.ts | 2 +- src/utils/tunnel.ts | 2 +- src/utils/umount.ts | 23 +-- src/utils/update.ts | 2 +- src/utils/validation.ts | 2 +- src/utils/version.ts | 8 +- src/utils/which.ts | 6 +- tests/auth/server.spec.ts | 6 +- tests/auth/utils.spec.ts | 2 +- tests/commands/build.spec.ts | 8 +- tests/commands/deploy.spec.ts | 6 +- tests/commands/device-type/list.spec.ts | 2 +- tests/commands/device/device-move.spec.ts | 2 +- tests/commands/device/device.spec.ts | 4 +- tests/commands/device/logs.spec.ts | 2 +- tests/commands/device/ssh.spec.ts | 4 +- tests/commands/env/add.spec.ts | 2 +- tests/commands/env/list.spec.ts | 4 +- tests/commands/env/rename.spec.ts | 2 +- tests/commands/env/rm.spec.ts | 2 +- tests/commands/help.spec.ts | 4 +- tests/commands/os/configure.spec.ts | 2 +- tests/commands/push.spec.ts | 4 +- tests/commands/release.spec.ts | 2 +- tests/commands/tag/set.spec.ts | 2 +- tests/commands/version.spec.ts | 4 +- tests/commands/whoami.spec.ts | 2 +- tests/deprecation.spec.ts | 4 +- tests/docker-build.ts | 14 +- tests/errors.spec.ts | 4 +- tests/helpers.ts | 10 +- tests/nock/balena-api-mock.ts | 4 +- tests/nock/builder-mock.ts | 2 +- tests/nock/docker-mock.ts | 2 +- tests/nock/nock-mock.ts | 2 +- tests/nock/supervisor-mock.ts | 2 +- tests/projects.ts | 2 +- tests/utils/device/live.spec.ts | 8 +- tests/utils/docker.spec.ts | 4 +- tests/utils/eol-conversion.spec.ts | 2 +- tests/utils/helpers.spec.ts | 2 +- .../utils/image-manager/image-manager.spec.ts | 8 +- tests/utils/normalization.spec.ts | 2 +- tests/utils/tarDirectory.spec.ts | 4 +- tests/utils/validation.spec.ts | 2 +- tsconfig.json | 5 +- typings/pkg/index.d.ts | 23 --- typings/windosu/index.d.ts | 3 + 190 files changed, 911 insertions(+), 925 deletions(-) delete mode 100644 .eslintignore delete mode 100644 .eslintrc.js delete mode 100644 typings/pkg/index.d.ts create mode 100644 typings/windosu/index.d.ts diff --git a/.eslintignore b/.eslintignore deleted file mode 100644 index 4ccfee1d6c..0000000000 --- a/.eslintignore +++ /dev/null @@ -1,2 +0,0 @@ -/completion/* -/bin/* \ No newline at end of file diff --git a/.eslintrc.js b/.eslintrc.js deleted file mode 100644 index 67c2bfb833..0000000000 --- a/.eslintrc.js +++ /dev/null @@ -1,21 +0,0 @@ -module.exports = { - extends: ['./node_modules/@balena/lint/config/.eslintrc.js'], - parserOptions: { - project: 'tsconfig.dev.json', - }, - root: true, - rules: { - ignoreDefinitionFiles: 0, - // to avoid the `warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion` - '@typescript-eslint/no-non-null-assertion': 'off', - '@typescript-eslint/no-shadow': 'off', - '@typescript-eslint/no-var-requires': 'off', - 'no-restricted-imports': [ - 'error', - { - paths: ['resin-cli-visuals', 'chalk', 'common-tags', 'resin-cli-form'], - }, - ], - '@typescript-eslint/no-unused-vars': ['error', { argsIgnorePattern: '^_' }], - }, -}; diff --git a/automation/build-bin.ts b/automation/build-bin.ts index b4a06bdec0..cd88430c9f 100644 --- a/automation/build-bin.ts +++ b/automation/build-bin.ts @@ -20,7 +20,7 @@ import { exec, execFile } from 'child_process'; import type { Stats } from 'fs'; import * as fs from 'fs-extra'; import * as klaw from 'klaw'; -import * as path from 'path'; +import path from 'path'; import * as rimraf from 'rimraf'; import { promisify } from 'util'; import { notarize } from '@electron/notarize'; diff --git a/automation/capitanodoc/capitanodoc.ts b/automation/capitanodoc/capitanodoc.ts index 353dfb5266..d8621bf3eb 100644 --- a/automation/capitanodoc/capitanodoc.ts +++ b/automation/capitanodoc/capitanodoc.ts @@ -15,7 +15,7 @@ * limitations under the License. */ -import * as path from 'path'; +import path from 'path'; import { MarkdownFileParser } from './utils'; import { GlobSync } from 'glob'; diff --git a/automation/capitanodoc/index.ts b/automation/capitanodoc/index.ts index baf77a5746..9fac313466 100644 --- a/automation/capitanodoc/index.ts +++ b/automation/capitanodoc/index.ts @@ -14,7 +14,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import * as path from 'path'; +import path from 'path'; import { getCapitanoDoc } from './capitanodoc'; import type { Category, Document, OclifCommand } from './doc-types'; import * as markdown from './markdown'; diff --git a/automation/capitanodoc/markdown.ts b/automation/capitanodoc/markdown.ts index 4bd32bcd1f..8022c325d6 100644 --- a/automation/capitanodoc/markdown.ts +++ b/automation/capitanodoc/markdown.ts @@ -16,7 +16,7 @@ */ import { Parser } from '@oclif/core'; import * as ent from 'ent'; -import * as _ from 'lodash'; +import _ from 'lodash'; import { capitanoizeOclifUsage } from '../../src/utils/oclif-utils'; import type { Category, Document } from './doc-types'; diff --git a/automation/capitanodoc/utils.ts b/automation/capitanodoc/utils.ts index 28875bb461..44c09a1112 100644 --- a/automation/capitanodoc/utils.ts +++ b/automation/capitanodoc/utils.ts @@ -15,7 +15,7 @@ * limitations under the License. */ -import * as fs from 'fs'; +import fs from 'fs'; import * as readline from 'readline'; export class MarkdownFileParser { diff --git a/automation/check-doc.ts b/automation/check-doc.ts index bdc33a493f..70593f79dd 100644 --- a/automation/check-doc.ts +++ b/automation/check-doc.ts @@ -17,9 +17,9 @@ // eslint-disable-next-line no-restricted-imports import { stripIndent } from 'common-tags'; -import * as _ from 'lodash'; +import _ from 'lodash'; import { promises as fs } from 'fs'; -import * as path from 'path'; +import path from 'path'; import { simpleGit } from 'simple-git'; const ROOT = path.normalize(path.join(__dirname, '..')); diff --git a/automation/run.ts b/automation/run.ts index 9e5af74c25..76b81a8f63 100644 --- a/automation/run.ts +++ b/automation/run.ts @@ -15,7 +15,7 @@ * limitations under the License. */ -import * as _ from 'lodash'; +import _ from 'lodash'; import { buildOclifInstaller, diff --git a/automation/utils.ts b/automation/utils.ts index a5dcd2b79e..518758884b 100644 --- a/automation/utils.ts +++ b/automation/utils.ts @@ -16,8 +16,8 @@ */ import { spawn } from 'child_process'; -import * as path from 'path'; -import * as fs from 'fs'; +import path from 'path'; +import fs from 'fs'; import * as whichMod from 'which'; export const ROOT = path.join(__dirname, '..'); diff --git a/bin/run.js b/bin/run.js index d598f1ec3c..c815d7304e 100755 --- a/bin/run.js +++ b/bin/run.js @@ -9,13 +9,15 @@ process.env.OCLIF_TS_NODE = '0'; async function run() { // Use fast-boot to cache require lookups, speeding up startup - await require('../build/fast-boot').start(); + const { start } = await import('../build/fast-boot.js'); + await start(); // Set the desired es version for downstream modules that support it - require('@balena/es-version').set('es2018'); - - // Run the CLI - await require('../build/app').run(undefined, { dir: __dirname }); + (await import('@balena/es-version')).set('es2018'); + // + // // Run the CLI + const { run } = await import('../build/app.js'); + run(undefined, { dir: import.meta.url }); } void run(); diff --git a/eslint.config.js b/eslint.config.js index 6c2ba01e44..1ffc4a261d 100644 --- a/eslint.config.js +++ b/eslint.config.js @@ -1,9 +1,15 @@ -const { FlatCompat } = require('@eslint/eslintrc'); +import { FlatCompat } from '@eslint/eslintrc'; +import { dirname } from 'node:path'; +import { fileURLToPath } from 'node:url'; +import Module from 'node:module'; + +const __dirname = dirname(fileURLToPath(import.meta.url)); +const require = Module.createRequire(import.meta.url); const compat = new FlatCompat({ baseDirectory: __dirname, }); -module.exports = [ +export default [ ...require('@balena/lint/config/eslint.config'), ...compat.config({ parserOptions: { diff --git a/package.json b/package.json index 8908534e01..385f316fed 100644 --- a/package.json +++ b/package.json @@ -9,6 +9,7 @@ "url": "git@github.com:balena-io/balena-cli.git" }, "preferGlobal": true, + "type": "module", "files": [ "bin/.fast-boot.json", "bin/", diff --git a/src/app.ts b/src/app.ts index f2ec228223..1a9024fa18 100644 --- a/src/app.ts +++ b/src/app.ts @@ -15,23 +15,24 @@ * limitations under the License. */ -import * as packageJSON from '../package.json'; -import type { AppOptions } from './preparser'; +import type { AppOptions } from './preparser.js'; import { checkDeletedCommand, preparseArgs, unsupportedFlag, -} from './preparser'; -import { CliSettings } from './utils/bootstrap'; -import { onceAsync } from './utils/lazy'; +} from './preparser.js'; +import { CliSettings } from './utils/bootstrap.js'; +import { onceAsync, getPackageJson } from './utils/lazy.js'; import { run as mainRun, settings } from '@oclif/core'; +const packageJSON = getPackageJson(); + /** * Sentry.io setup * @see https://docs.sentry.io/error-reporting/quickstart/?platform=node */ export const setupSentry = onceAsync(async () => { - const config = await import('./config'); + const config = await import('./config.js'); const Sentry = await import('@sentry/node'); Sentry.init({ autoSessionTracking: false, @@ -51,30 +52,20 @@ export const setupSentry = onceAsync(async () => { async function checkNodeVersion() { const validNodeVersions = packageJSON.engines.node; if (!(await import('semver')).satisfies(process.version, validNodeVersions)) { - const { getNodeEngineVersionWarn } = await import('./utils/messages'); + const { getNodeEngineVersionWarn } = await import('./utils/messages.js'); console.warn(getNodeEngineVersionWarn(process.version, validNodeVersions)); } } /** Setup balena-sdk options that are shared with imported packages */ -function setupBalenaSdkSharedOptions(settings: CliSettings) { - const BalenaSdk = require('balena-sdk') as typeof import('balena-sdk'); +async function setupBalenaSdkSharedOptions(settings: CliSettings) { + const BalenaSdk = await import('balena-sdk'); BalenaSdk.setSharedOptions({ apiUrl: settings.get('apiUrl'), dataDirectory: settings.get('dataDirectory'), }); } -/** - * Addresses the console warning: - * (node:49500) MaxListenersExceededWarning: Possible EventEmitter memory - * leak detected. 11 error listeners added. Use emitter.setMaxListeners() to - * increase limit - */ -export function setMaxListeners(maxListeners: number) { - require('events').EventEmitter.defaultMaxListeners = maxListeners; -} - /** Selected CLI initialization steps */ async function init() { if (process.env.BALENARC_NO_SENTRY) { @@ -89,13 +80,13 @@ async function init() { const settings = new CliSettings(); // Proxy setup should be done early on, before loading balena-sdk - await (await import('./utils/proxy')).setupGlobalHttpProxy(settings); + await (await import('./utils/proxy.js')).setupGlobalHttpProxy(settings); - setupBalenaSdkSharedOptions(settings); + await setupBalenaSdkSharedOptions(settings); // check for CLI updates once a day if (!process.env.BALENARC_OFFLINE_MODE) { - (await import('./utils/update')).notify(); + (await import('./utils/update.js')).notify(); } } @@ -104,7 +95,7 @@ async function oclifRun(command: string[], options: AppOptions) { let deprecationPromise: Promise | undefined; // check and enforce the CLI's deprecation policy if (!(unsupportedFlag || process.env.BALENARC_UNSUPPORTED)) { - const { DeprecationChecker } = await import('./deprecation'); + const { DeprecationChecker } = await import('./deprecation.js'); const deprecationChecker = new DeprecationChecker(packageJSON.version); // warnAndAbortIfDeprecated uses previously cached data only await deprecationChecker.warnAndAbortIfDeprecated(); @@ -147,11 +138,11 @@ async function oclifRun(command: string[], options: AppOptions) { // the try/catch block above, execution does not get past the // Promise.all() call below, but I don't understand why. if (isEEXIT) { - (await import('./fast-boot')).stop(); + (await import('./fast-boot.js')).stop(); } })(!options.noFlush); - const { trackPromise } = await import('./hooks/prerun'); + const { trackPromise } = await import('./hooks/prerun.js'); await Promise.all([trackPromise, deprecationPromise, runPromise]); } @@ -160,7 +151,7 @@ async function oclifRun(command: string[], options: AppOptions) { export async function run(cliArgs = process.argv, options: AppOptions) { try { const { setOfflineModeEnvVars, normalizeEnvVars } = await import( - './utils/bootstrap' + './utils/bootstrap.js' ); setOfflineModeEnvVars(); normalizeEnvVars(); @@ -168,15 +159,15 @@ export async function run(cliArgs = process.argv, options: AppOptions) { await init(); // Look for commands that have been removed and if so, exit with a notice - checkDeletedCommand(cliArgs.slice(2)); + await checkDeletedCommand(cliArgs.slice(2)); const args = await preparseArgs(cliArgs); await oclifRun(args, options); } catch (err) { - await (await import('./errors')).handleError(err); + await (await import('./errors.js')).handleError(err); } finally { try { - (await import('./fast-boot')).stop(); + (await import('./fast-boot.js')).stop(); } catch (e) { if (process.env.DEBUG) { console.error(`[debug] Stopping fast-boot: ${e}`); diff --git a/src/auth/index.ts b/src/auth/index.ts index 2089eaada2..16f1001b65 100644 --- a/src/auth/index.ts +++ b/src/auth/index.ts @@ -14,8 +14,8 @@ See the License for the specific language governing permissions and limitations under the License. */ -import { getBalenaSdk } from '../utils/lazy'; -import { LoginServer } from './server'; +import { getBalenaSdk } from '../utils/lazy.js'; +import { LoginServer } from './server.js'; /** * @module auth @@ -42,7 +42,7 @@ import { LoginServer } from './server'; * console.log("My session token is: #{sessionToken}") */ export async function login({ host = '127.0.0.1', port = 0 }) { - const utils = await import('./utils'); + const utils = await import('./utils.js'); const loginServer = new LoginServer(); const { @@ -55,7 +55,7 @@ export async function login({ host = '127.0.0.1', port = 0 }) { const loginUrl = await utils.getDashboardLoginURL(callbackUrl); console.info(`Opening web browser for URL:\n${loginUrl}`); - const open = await import('open'); + const { default: open } = await import('open'); await open(loginUrl, { wait: false }); const balena = getBalenaSdk(); diff --git a/src/auth/server.ts b/src/auth/server.ts index df7880d4ee..8026454f3c 100644 --- a/src/auth/server.ts +++ b/src/auth/server.ts @@ -14,14 +14,14 @@ See the License for the specific language governing permissions and limitations under the License. */ -import * as bodyParser from 'body-parser'; +import bodyParser from 'body-parser'; import { EventEmitter } from 'events'; -import * as express from 'express'; +import express from 'express'; import type { Socket } from 'net'; -import * as path from 'path'; +import path from 'path'; -import * as utils from './utils'; -import { ExpectedError } from '../errors'; +import * as utils from './utils.js'; +import { ExpectedError } from '../errors.js'; export class LoginServer extends EventEmitter { protected expressApp: express.Express; diff --git a/src/auth/utils.ts b/src/auth/utils.ts index 7956b55b98..f2935f0a16 100644 --- a/src/auth/utils.ts +++ b/src/auth/utils.ts @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -import { getBalenaSdk } from '../utils/lazy'; +import { getBalenaSdk } from '../utils/lazy.js'; /** * Get dashboard CLI login URL diff --git a/src/commands/api-key/generate.ts b/src/commands/api-key/generate.ts index fcdeba0c2a..cffce7faad 100644 --- a/src/commands/api-key/generate.ts +++ b/src/commands/api-key/generate.ts @@ -16,15 +16,15 @@ */ import { Args, Command } from '@oclif/core'; -import { ExpectedError } from '../../errors'; -import { getBalenaSdk, stripIndent } from '../../utils/lazy'; +import { ExpectedError } from '../../errors.js'; +import { getBalenaSdk, stripIndent } from '../../utils/lazy.js'; async function isLoggedInWithJwt() { const balena = getBalenaSdk(); try { const token = await balena.auth.getToken(); const { default: jwtDecode } = await import('jwt-decode'); - jwtDecode(token); + jwtDecode.default(token); return true; } catch { return false; diff --git a/src/commands/api-key/list.ts b/src/commands/api-key/list.ts index 8f802ff7f3..00d548198d 100644 --- a/src/commands/api-key/list.ts +++ b/src/commands/api-key/list.ts @@ -16,8 +16,8 @@ */ import { Flags, Command } from '@oclif/core'; -import * as cf from '../../utils/common-flags'; -import { getBalenaSdk, getVisuals, stripIndent } from '../../utils/lazy'; +import * as cf from '../../utils/common-flags.js'; +import { getBalenaSdk, getVisuals, stripIndent } from '../../utils/lazy.js'; export default class APIKeyListCmd extends Command { public static aliases = ['api-keys']; @@ -45,7 +45,7 @@ export default class APIKeyListCmd extends Command { public async run() { const { flags: options } = await this.parse(APIKeyListCmd); - const { getApplication } = await import('../../utils/sdk'); + const { getApplication } = await import('../../utils/sdk.js'); const actorId = options.fleet ? ( await getApplication(getBalenaSdk(), options.fleet, { diff --git a/src/commands/api-key/revoke.ts b/src/commands/api-key/revoke.ts index adc263930c..7d3856bc4f 100644 --- a/src/commands/api-key/revoke.ts +++ b/src/commands/api-key/revoke.ts @@ -16,7 +16,7 @@ */ import { Args, Command } from '@oclif/core'; -import { getBalenaSdk, stripIndent } from '../../utils/lazy'; +import { getBalenaSdk, stripIndent } from '../../utils/lazy.js'; export default class RevokeCmd extends Command { public static description = stripIndent` diff --git a/src/commands/app/create.ts b/src/commands/app/create.ts index 7ca52f775a..9711340b4c 100644 --- a/src/commands/app/create.ts +++ b/src/commands/app/create.ts @@ -16,7 +16,7 @@ */ import { Flags, Args, Command } from '@oclif/core'; -import { stripIndent } from '../../utils/lazy'; +import { stripIndent } from '../../utils/lazy.js'; export default class AppCreateCmd extends Command { public static description = stripIndent` @@ -71,7 +71,7 @@ export default class AppCreateCmd extends Command { const { args: params, flags: options } = await this.parse(AppCreateCmd); await ( - await import('../../utils/application-create') + await import('../../utils/application-create.js') ).applicationCreateBase('app', options, params); } } diff --git a/src/commands/block/create.ts b/src/commands/block/create.ts index 221f7d2ab7..e1e57ab674 100644 --- a/src/commands/block/create.ts +++ b/src/commands/block/create.ts @@ -16,7 +16,7 @@ */ import { Flags, Args, Command } from '@oclif/core'; -import { stripIndent } from '../../utils/lazy'; +import { stripIndent } from '../../utils/lazy.js'; export default class BlockCreateCmd extends Command { public static description = stripIndent` @@ -71,7 +71,7 @@ export default class BlockCreateCmd extends Command { const { args: params, flags: options } = await this.parse(BlockCreateCmd); await ( - await import('../../utils/application-create') + await import('../../utils/application-create.js') ).applicationCreateBase('block', options, params); } } diff --git a/src/commands/build/index.ts b/src/commands/build/index.ts index 7adf442958..04bf6b8145 100644 --- a/src/commands/build/index.ts +++ b/src/commands/build/index.ts @@ -16,9 +16,9 @@ */ import { Args, Flags, Command } from '@oclif/core'; -import { getBalenaSdk } from '../../utils/lazy'; -import * as cf from '../../utils/common-flags'; -import * as compose from '../../utils/compose'; +import { getBalenaSdk } from '../../utils/lazy.js'; +import * as cf from '../../utils/common-flags.js'; +import * as compose from '../../utils/compose.js'; import type { ApplicationType, BalenaSDK, @@ -30,11 +30,15 @@ import { buildArgDeprecation, dockerignoreHelp, registrySecretsHelp, -} from '../../utils/messages'; -import type { ComposeCliFlags, ComposeOpts } from '../../utils/compose-types'; -import { buildProject, composeCliFlags } from '../../utils/compose_ts'; -import type { BuildOpts, DockerCliFlags } from '../../utils/docker'; -import { dockerCliFlags } from '../../utils/docker'; +} from '../../utils/messages.js'; +import type { + ComposeCliFlags, + ComposeOpts, +} from '../../utils/compose-types.js'; +import { buildProject, composeCliFlags } from '../../utils/compose_ts.js'; +import type { BuildOpts, DockerCliFlags } from '../../utils/docker.js'; +import { dockerCliFlags } from '../../utils/docker.js'; +import type Dockerode from 'dockerode'; type ComposeGenerateOptsParam = Parameters[0]; @@ -103,8 +107,8 @@ ${dockerignoreHelp} public async run() { const { args: params, flags: options } = await this.parse(BuildCmd); - const Logger = await import('../../utils/logger'); - const { checkLoggedInIf } = await import('../../utils/patterns'); + const { default: Logger } = await import('../../utils/logger.js'); + const { checkLoggedInIf } = await import('../../utils/patterns.js'); await checkLoggedInIf(!!options.fleet); @@ -157,14 +161,16 @@ ${dockerignoreHelp} (opts.fleet == null && (opts.arch == null || opts.deviceType == null)) || (opts.fleet != null && (opts.arch != null || opts.deviceType != null)) ) { - const { ExpectedError } = await import('../../errors'); + const { ExpectedError } = await import('../../errors.js'); throw new ExpectedError( 'You must specify either a fleet (-f), or the device type (-d) and optionally the architecture (-A)', ); } // Validate project directory - const { validateProjectDirectory } = await import('../../utils/compose_ts'); + const { validateProjectDirectory } = await import( + '../../utils/compose_ts.js' + ); const { dockerfilePath, registrySecrets } = await validateProjectDirectory( sdk, { @@ -200,7 +206,7 @@ ${dockerignoreHelp} )) as PineTypedResult ).is_of__cpu_architecture[0].slug; } catch (err) { - const { ExpectedError } = await import('../../errors'); + const { ExpectedError } = await import('../../errors.js'); if (err instanceof sdk.errors.BalenaInvalidDeviceType) { let message = err.message; if (!(await sdk.auth.isLoggedIn())) { @@ -217,7 +223,7 @@ ${dockerignoreHelp} protected async getAppAndResolveArch(opts: PrepareBuildOpts) { if (opts.fleet) { - const { getAppWithArch } = await import('../../utils/helpers'); + const { getAppWithArch } = await import('../../utils/helpers.js'); const app = await getAppWithArch(opts.fleet); opts.arch = app.arch; opts.deviceType = app.is_for__device_type[0].slug; @@ -225,8 +231,14 @@ ${dockerignoreHelp} } } - protected async prepareBuild(options: PrepareBuildOpts) { - const { getDocker, generateBuildOpts } = await import('../../utils/docker'); + protected async prepareBuild(options: PrepareBuildOpts): Promise<{ + docker: Dockerode; + buildOpts: BuildOpts; + composeOpts: ComposeOpts; + }> { + const { getDocker, generateBuildOpts } = await import( + '../../utils/docker.js' + ); const [docker, buildOpts, composeOpts] = await Promise.all([ getDocker(options), generateBuildOpts(options), @@ -254,7 +266,7 @@ ${dockerignoreHelp} */ protected async buildProject( docker: import('dockerode'), - logger: import('../../utils/logger'), + logger: import('../../utils/logger.js').default, composeOpts: ComposeOpts, opts: { appType?: Pick; @@ -264,7 +276,7 @@ ${dockerignoreHelp} buildOpts: BuildOpts; }, ) { - const { loadProject } = await import('../../utils/compose_ts'); + const { loadProject } = await import('../../utils/compose_ts.js'); const project = await loadProject( logger, diff --git a/src/commands/config/generate.ts b/src/commands/config/generate.ts index 4376b53f24..89a09208f6 100644 --- a/src/commands/config/generate.ts +++ b/src/commands/config/generate.ts @@ -17,13 +17,13 @@ import { Flags, Command } from '@oclif/core'; import type { Interfaces } from '@oclif/core'; -import * as cf from '../../utils/common-flags'; -import { getBalenaSdk, getCliForm, stripIndent } from '../../utils/lazy'; +import * as cf from '../../utils/common-flags.js'; +import { getBalenaSdk, getCliForm, stripIndent } from '../../utils/lazy.js'; import { applicationIdInfo, devModeInfo, secureBootInfo, -} from '../../utils/messages'; +} from '../../utils/messages.js'; import type { BalenaSDK, PineDeferred } from 'balena-sdk'; export default class ConfigGenerateCmd extends Command { @@ -64,17 +64,14 @@ export default class ConfigGenerateCmd extends Command { description: 'a balenaOS version', required: true, }), - fleet: { ...cf.fleet, exclusive: ['device'] }, + fleet: cf.fleetExclusive(['device']), dev: cf.dev, secureBoot: cf.secureBoot, - device: { - ...cf.device, - exclusive: [ - 'fleet', - 'provisioning-key-name', - 'provisioning-key-expiry-date', - ], - }, + device: cf.deviceExclusive([ + 'fleet', + 'provisioning-key-name', + 'provisioning-key-expiry-date', + ]), deviceApiKey: Flags.string({ description: 'custom device key - note that this is only supported on balenaOS 2.0.3+', @@ -122,7 +119,7 @@ export default class ConfigGenerateCmd extends Command { public static authenticated = true; public async getApplication(balena: BalenaSDK, fleet: string) { - const { getApplication } = await import('../../utils/sdk'); + const { getApplication } = await import('../../utils/sdk.js'); return await getApplication(balena, fleet, { $select: 'slug', $expand: { @@ -148,7 +145,7 @@ export default class ConfigGenerateCmd extends Command { $expand: { is_of__device_type: { $select: 'slug' } }, }); if (!rawDevice.belongs_to__application) { - const { ExpectedError } = await import('../../errors'); + const { ExpectedError } = await import('../../errors.js'); throw new ExpectedError(stripIndent` Device ${options.device} does not appear to belong to an accessible fleet. Try with a different device, or use '--fleet' instead of '--device'.`); @@ -167,14 +164,14 @@ export default class ConfigGenerateCmd extends Command { // Check compatibility if application and deviceType provided if (options.fleet && options.deviceType) { - const helpers = await import('../../utils/helpers'); + const helpers = await import('../../utils/helpers.js'); if ( !(await helpers.areDeviceTypesCompatible( resourceDeviceType, deviceType, )) ) { - const { ExpectedError } = await import('../../errors'); + const { ExpectedError } = await import('../../errors.js'); throw new ExpectedError( `Device type ${options.deviceType} is incompatible with fleet ${options.fleet}`, ); @@ -185,7 +182,7 @@ export default class ConfigGenerateCmd extends Command { await balena.models.config.getDeviceTypeManifestBySlug(deviceType); const { validateSecureBootOptionAndWarn } = await import( - '../../utils/config' + '../../utils/config.js' ); await validateSecureBootOptionAndWarn( options.secureBoot, @@ -207,7 +204,7 @@ export default class ConfigGenerateCmd extends Command { // Generate config const { generateDeviceConfig, generateApplicationConfig } = await import( - '../../utils/config' + '../../utils/config.js' ); let config; @@ -246,7 +243,7 @@ export default class ConfigGenerateCmd extends Command { protected async validateOptions( options: Interfaces.InferredFlags, ) { - const { ExpectedError } = await import('../../errors'); + const { ExpectedError } = await import('../../errors.js'); if (options.device == null && options.fleet == null) { throw new ExpectedError(this.missingDeviceOrAppMessage); @@ -255,9 +252,9 @@ export default class ConfigGenerateCmd extends Command { if (!options.fleet && options.deviceType) { throw new ExpectedError(this.deviceTypeNotAllowedMessage); } - const { normalizeOsVersion } = await import('../../utils/normalization'); + const { normalizeOsVersion } = await import('../../utils/normalization.js'); options.version = normalizeOsVersion(options.version); - const { validateDevOptionAndWarn } = await import('../../utils/config'); + const { validateDevOptionAndWarn } = await import('../../utils/config.js'); await validateDevOptionAndWarn(options.dev, options.version); } } diff --git a/src/commands/config/inject.ts b/src/commands/config/inject.ts index a9d06cb199..4044526427 100644 --- a/src/commands/config/inject.ts +++ b/src/commands/config/inject.ts @@ -16,8 +16,8 @@ */ import { Args, Command } from '@oclif/core'; -import * as cf from '../../utils/common-flags'; -import { getVisuals, stripIndent } from '../../utils/lazy'; +import * as cf from '../../utils/common-flags.js'; +import { getVisuals, stripIndent } from '../../utils/lazy.js'; export default class ConfigInjectCmd extends Command { public static description = stripIndent` @@ -52,7 +52,7 @@ export default class ConfigInjectCmd extends Command { public async run() { const { args: params, flags: options } = await this.parse(ConfigInjectCmd); - const { safeUmount } = await import('../../utils/umount'); + const { safeUmount } = await import('../../utils/umount.js'); const drive = options.drive || (await getVisuals().drive('Select the device/OS drive')); diff --git a/src/commands/config/read.ts b/src/commands/config/read.ts index 644f68f194..95d6160382 100644 --- a/src/commands/config/read.ts +++ b/src/commands/config/read.ts @@ -16,8 +16,8 @@ */ import { Command } from '@oclif/core'; -import * as cf from '../../utils/common-flags'; -import { getVisuals, stripIndent } from '../../utils/lazy'; +import * as cf from '../../utils/common-flags.js'; +import { getVisuals, stripIndent } from '../../utils/lazy.js'; export default class ConfigReadCmd extends Command { public static description = stripIndent` @@ -47,7 +47,7 @@ export default class ConfigReadCmd extends Command { public async run() { const { flags: options } = await this.parse(ConfigReadCmd); - const { safeUmount } = await import('../../utils/umount'); + const { safeUmount } = await import('../../utils/umount.js'); const drive = options.drive || (await getVisuals().drive('Select the device drive')); diff --git a/src/commands/config/reconfigure.ts b/src/commands/config/reconfigure.ts index af01e95923..e955c6570b 100644 --- a/src/commands/config/reconfigure.ts +++ b/src/commands/config/reconfigure.ts @@ -16,8 +16,8 @@ */ import { Flags, Command } from '@oclif/core'; -import * as cf from '../../utils/common-flags'; -import { getVisuals, stripIndent } from '../../utils/lazy'; +import * as cf from '../../utils/common-flags.js'; +import { getVisuals, stripIndent } from '../../utils/lazy.js'; export default class ConfigReconfigureCmd extends Command { public static description = stripIndent` @@ -55,7 +55,7 @@ export default class ConfigReconfigureCmd extends Command { public async run() { const { flags: options } = await this.parse(ConfigReconfigureCmd); - const { safeUmount } = await import('../../utils/umount'); + const { safeUmount } = await import('../../utils/umount.js'); const drive = options.drive || (await getVisuals().drive('Select the device drive')); @@ -66,7 +66,7 @@ export default class ConfigReconfigureCmd extends Command { await safeUmount(drive); if (!uuid) { - const { ExpectedError } = await import('../../errors'); + const { ExpectedError } = await import('../../errors.js'); throw new ExpectedError( `Error: UUID not found in 'config.json' file for '${drive}'`, ); @@ -80,7 +80,7 @@ export default class ConfigReconfigureCmd extends Command { configureCommand.push('--advanced'); } - const { runCommand } = await import('../../utils/helpers'); + const { runCommand } = await import('../../utils/helpers.js'); await runCommand(configureCommand); console.info('Done'); diff --git a/src/commands/config/write.ts b/src/commands/config/write.ts index 4a8d991c8c..969020d1f0 100644 --- a/src/commands/config/write.ts +++ b/src/commands/config/write.ts @@ -16,8 +16,8 @@ */ import { Args, Command } from '@oclif/core'; -import * as cf from '../../utils/common-flags'; -import { getVisuals, stripIndent } from '../../utils/lazy'; +import * as cf from '../../utils/common-flags.js'; +import { getVisuals, stripIndent } from '../../utils/lazy.js'; export default class ConfigWriteCmd extends Command { public static description = stripIndent` @@ -57,7 +57,7 @@ export default class ConfigWriteCmd extends Command { public async run() { const { args: params, flags: options } = await this.parse(ConfigWriteCmd); - const { denyMount, safeUmount } = await import('../../utils/umount'); + const { denyMount, safeUmount } = await import('../../utils/umount.js'); const drive = options.drive || (await getVisuals().drive('Select the device drive')); diff --git a/src/commands/deploy/index.ts b/src/commands/deploy/index.ts index 312edfb41f..7a98ba6a5f 100644 --- a/src/commands/deploy/index.ts +++ b/src/commands/deploy/index.ts @@ -17,30 +17,29 @@ import { Args, Flags, Command } from '@oclif/core'; import type { ImageDescriptor } from '@balena/compose/dist/parse'; -import { ExpectedError } from '../../errors'; -import { getBalenaSdk, getChalk, stripIndent } from '../../utils/lazy'; +import { ExpectedError } from '../../errors.js'; +import { getBalenaSdk, getChalk, stripIndent } from '../../utils/lazy.js'; import { dockerignoreHelp, registrySecretsHelp, buildArgDeprecation, -} from '../../utils/messages'; -import * as ca from '../../utils/common-args'; -import * as compose from '../../utils/compose'; +} from '../../utils/messages.js'; +import * as ca from '../../utils/common-args.js'; +import * as compose from '../../utils/compose.js'; import type { BuiltImage, ComposeCliFlags, ComposeOpts, - Release as ComposeReleaseInfo, -} from '../../utils/compose-types'; -import type { BuildOpts, DockerCliFlags } from '../../utils/docker'; +} from '../../utils/compose-types.js'; +import type { BuildOpts, DockerCliFlags } from '../../utils/docker.js'; import { applyReleaseTagKeysAndValues, buildProject, composeCliFlags, isBuildConfig, parseReleaseTagKeysAndValues, -} from '../../utils/compose_ts'; -import { dockerCliFlags } from '../../utils/docker'; +} from '../../utils/compose_ts.js'; +import { dockerCliFlags } from '../../utils/docker.js'; import type { ApplicationType, DeviceType, Release } from 'balena-sdk'; interface ApplicationWithArch { @@ -149,7 +148,7 @@ ${dockerignoreHelp} (await import('events')).defaultMaxListeners = 1000; - const Logger = await import('../../utils/logger'); + const { default: Logger } = await import('../../utils/logger.js'); const logger = Logger.getLogger(); logger.logDebug('Parsing input...'); @@ -169,7 +168,7 @@ ${dockerignoreHelp} const sdk = getBalenaSdk(); const { getRegistrySecrets, validateProjectDirectory } = await import( - '../../utils/compose_ts' + '../../utils/compose_ts.js' ); const { releaseTagKeys, releaseTagValues } = parseReleaseTagKeysAndValues( @@ -193,10 +192,10 @@ ${dockerignoreHelp} (options as FlagsDef)['registry-secrets'] = registrySecrets; } - const helpers = await import('../../utils/helpers'); + const helpers = await import('../../utils/helpers.js'); const app = await helpers.getAppWithArch(fleet); - const dockerUtils = await import('../../utils/docker'); + const dockerUtils = await import('../../utils/docker.js'); const [docker, buildOpts, composeOpts] = await Promise.all([ dockerUtils.getDocker(options), dockerUtils.generateBuildOpts(options as FlagsDef), @@ -226,7 +225,7 @@ ${dockerignoreHelp} async deployProject( docker: import('dockerode'), - logger: import('../../utils/logger'), + logger: import('../../utils/logger.js').default, composeOpts: ComposeOpts, opts: { app: ApplicationWithArch; // the application instance to deploy to @@ -244,7 +243,7 @@ ${dockerignoreHelp} const doodles = await import('resin-doodles'); const sdk = getBalenaSdk(); const { deployProject: $deployProject, loadProject } = await import( - '../../utils/compose_ts' + '../../utils/compose_ts.js' ); const appType = opts.app.application_type[0]; @@ -315,7 +314,7 @@ ${dockerignoreHelp} builtImagesByService = _.keyBy(builtImages, 'serviceName'); } const images: BuiltImage[] = project.descriptors.map( - (d) => + (d: ImageDescriptor) => builtImagesByService[d.serviceName] ?? { serviceName: d.serviceName, name: (isBuildConfig(d.image) ? d.image.tag : d.image) || '', @@ -324,9 +323,9 @@ ${dockerignoreHelp} }, ); - let release: Release | ComposeReleaseInfo['release']; + let release: Release | Awaited>; if (appType.slug === 'legacy-v1' || appType.slug === 'legacy-v2') { - const { deployLegacy } = require('../../utils/deploy-legacy'); + const { deployLegacy } = await import('../../utils/deploy-legacy.js'); const msg = getChalk().yellow( 'Target fleet requires legacy deploy method.', diff --git a/src/commands/device-type/list.ts b/src/commands/device-type/list.ts index ff3d5dcc32..e5dc7d0404 100644 --- a/src/commands/device-type/list.ts +++ b/src/commands/device-type/list.ts @@ -16,8 +16,8 @@ */ import { Flags, Command } from '@oclif/core'; import type * as BalenaSdk from 'balena-sdk'; -import * as _ from 'lodash'; -import { getBalenaSdk, getVisuals, stripIndent } from '../../utils/lazy'; +import _ from 'lodash'; +import { getBalenaSdk, getVisuals, stripIndent } from '../../utils/lazy.js'; export default class DeviceTypeListCmd extends Command { public static aliases = ['devices supported']; diff --git a/src/commands/device/deactivate.ts b/src/commands/device/deactivate.ts index f0a81631d2..4c6dd65913 100644 --- a/src/commands/device/deactivate.ts +++ b/src/commands/device/deactivate.ts @@ -16,8 +16,8 @@ */ import { Args, Command } from '@oclif/core'; -import * as cf from '../../utils/common-flags'; -import { getBalenaSdk, stripIndent } from '../../utils/lazy'; +import * as cf from '../../utils/common-flags.js'; +import { getBalenaSdk, stripIndent } from '../../utils/lazy.js'; export default class DeviceDeactivateCmd extends Command { public static description = stripIndent` @@ -51,7 +51,7 @@ export default class DeviceDeactivateCmd extends Command { await this.parse(DeviceDeactivateCmd); const balena = getBalenaSdk(); - const patterns = await import('../../utils/patterns'); + const patterns = await import('../../utils/patterns.js'); const uuid = params.uuid; const deactivationWarning = ` diff --git a/src/commands/device/detect.ts b/src/commands/device/detect.ts index 6a4733b61b..0d7d371fd2 100644 --- a/src/commands/device/detect.ts +++ b/src/commands/device/detect.ts @@ -16,7 +16,7 @@ */ import { Flags, Command } from '@oclif/core'; -import { getCliUx, stripIndent } from '../../utils/lazy'; +import { getCliUx, stripIndent } from '../../utils/lazy.js'; export default class DeviceDetectCmd extends Command { public static aliases = ['scan']; @@ -63,10 +63,10 @@ export default class DeviceDetectCmd extends Command { public async run() { const _ = await import('lodash'); const { discoverLocalBalenaOsDevices } = await import( - '../../utils/discover' + '../../utils/discover.js' ); const prettyjson = await import('prettyjson'); - const dockerUtils = await import('../../utils/docker'); + const dockerUtils = await import('../../utils/docker.js'); const dockerPort = 2375; const dockerTimeout = 2000; diff --git a/src/commands/device/identify.ts b/src/commands/device/identify.ts index c3de3ceca7..4b4dfe0321 100644 --- a/src/commands/device/identify.ts +++ b/src/commands/device/identify.ts @@ -16,8 +16,8 @@ */ import { Args, Command } from '@oclif/core'; -import { getBalenaSdk, stripIndent } from '../../utils/lazy'; -import { ExpectedError } from '../../errors'; +import { getBalenaSdk, stripIndent } from '../../utils/lazy.js'; +import { ExpectedError } from '../../errors.js'; export default class DeviceIdentifyCmd extends Command { public static description = stripIndent` diff --git a/src/commands/device/index.ts b/src/commands/device/index.ts index 53e6c7bbbc..2a8cc8991a 100644 --- a/src/commands/device/index.ts +++ b/src/commands/device/index.ts @@ -16,10 +16,10 @@ */ import { Flags, Args, Command } from '@oclif/core'; -import * as cf from '../../utils/common-flags'; -import { expandForAppName } from '../../utils/helpers'; -import { getBalenaSdk, getVisuals, stripIndent } from '../../utils/lazy'; -import { jsonInfo } from '../../utils/messages'; +import * as cf from '../../utils/common-flags.js'; +import { expandForAppName } from '../../utils/helpers.js'; +import { getBalenaSdk, getVisuals, stripIndent } from '../../utils/lazy.js'; +import { jsonInfo } from '../../utils/messages.js'; import type { Application, Release } from 'balena-sdk'; @@ -118,7 +118,7 @@ export default class DeviceCmd extends Command { )) as ExtendedDevice; if (options.view) { - const open = await import('open'); + const { default: open } = await import('open'); const dashboardUrl = balena.models.device.getDashboardUrl(device.uuid); await open(dashboardUrl, { wait: false }); return; diff --git a/src/commands/device/init.ts b/src/commands/device/init.ts index cdb78765d5..4486a260dd 100644 --- a/src/commands/device/init.ts +++ b/src/commands/device/init.ts @@ -16,10 +16,10 @@ */ import { Flags, Command } from '@oclif/core'; -import * as cf from '../../utils/common-flags'; -import { getBalenaSdk, stripIndent } from '../../utils/lazy'; -import { applicationIdInfo } from '../../utils/messages'; -import { runCommand } from '../../utils/helpers'; +import * as cf from '../../utils/common-flags.js'; +import { getBalenaSdk, stripIndent } from '../../utils/lazy.js'; +import { applicationIdInfo } from '../../utils/messages.js'; +import { runCommand } from '../../utils/helpers.js'; interface FlagsDef { fleet?: string; @@ -108,13 +108,13 @@ export default class DeviceInitCmd extends Command { // Imports const { promisify } = await import('util'); - const rimraf = promisify(await import('rimraf')); + const rimraf = promisify((await import('rimraf')).default); const tmp = await import('tmp'); const tmpNameAsync = promisify(tmp.tmpName); tmp.setGracefulCleanup(); - const { downloadOSImage } = await import('../../utils/cloud'); - const { getApplication } = await import('../../utils/sdk'); - const Logger = await import('../../utils/logger'); + const { downloadOSImage } = await import('../../utils/cloud.js'); + const { getApplication } = await import('../../utils/sdk.js'); + const { default: Logger } = await import('../../utils/logger.js'); const logger = Logger.getLogger(); const balena = getBalenaSdk(); @@ -129,7 +129,7 @@ export default class DeviceInitCmd extends Command { }, }, }) - : await (await import('../../utils/patterns')).selectApplication(); + : await (await import('../../utils/patterns.js')).selectApplication(); // Register new device const deviceUuid = balena.models.device.generateUniqueKey(); diff --git a/src/commands/device/list.ts b/src/commands/device/list.ts index 7eea1c1ed4..47bb7ccb73 100644 --- a/src/commands/device/list.ts +++ b/src/commands/device/list.ts @@ -16,10 +16,10 @@ */ import { Command } from '@oclif/core'; -import * as cf from '../../utils/common-flags'; -import { expandForAppName } from '../../utils/helpers'; -import { getBalenaSdk, getVisuals, stripIndent } from '../../utils/lazy'; -import { applicationIdInfo, jsonInfo } from '../../utils/messages'; +import * as cf from '../../utils/common-flags.js'; +import { expandForAppName } from '../../utils/helpers.js'; +import { getBalenaSdk, getVisuals, stripIndent } from '../../utils/lazy.js'; +import { applicationIdInfo, jsonInfo } from '../../utils/messages.js'; import type { Device, PineOptions } from 'balena-sdk'; @@ -78,7 +78,7 @@ export default class DeviceListCmd extends Command { const devices = ( await (async () => { if (options.fleet != null) { - const { getApplication } = await import('../../utils/sdk'); + const { getApplication } = await import('../../utils/sdk.js'); const application = await getApplication(balena, options.fleet, { $select: 'slug', $expand: { @@ -115,7 +115,7 @@ export default class DeviceListCmd extends Command { ]; if (options.json) { - const { pickAndRename } = await import('../../utils/helpers'); + const { pickAndRename } = await import('../../utils/helpers.js'); const mapped = devices.map((device) => pickAndRename(device, fields)); console.log(JSON.stringify(mapped, null, 4)); } else { diff --git a/src/commands/device/local-mode.ts b/src/commands/device/local-mode.ts index 7d3273363d..4255db54b0 100644 --- a/src/commands/device/local-mode.ts +++ b/src/commands/device/local-mode.ts @@ -16,7 +16,7 @@ */ import { Flags, Args, Command } from '@oclif/core'; -import { getBalenaSdk, stripIndent } from '../../utils/lazy'; +import { getBalenaSdk, stripIndent } from '../../utils/lazy.js'; export default class DeviceLocalModeCmd extends Command { public static description = stripIndent` diff --git a/src/commands/device/logs.ts b/src/commands/device/logs.ts index 9af6d1e1c9..0b4ba979da 100644 --- a/src/commands/device/logs.ts +++ b/src/commands/device/logs.ts @@ -16,7 +16,7 @@ */ import { Flags, Args, Command } from '@oclif/core'; -import { getBalenaSdk, stripIndent } from '../../utils/lazy'; +import { getBalenaSdk, stripIndent } from '../../utils/lazy.js'; import type { LogMessage } from 'balena-sdk'; const MAX_RETRY = 1000; @@ -94,14 +94,14 @@ export default class DeviceLogsCmd extends Command { const { args: params, flags: options } = await this.parse(DeviceLogsCmd); const balena = getBalenaSdk(); - const { serviceIdToName } = await import('../../utils/cloud'); + const { serviceIdToName } = await import('../../utils/cloud.js'); const { connectAndDisplayDeviceLogs, displayLogObject } = await import( - '../../utils/device/logs' + '../../utils/device/logs.js' ); const { validateIPAddress, validateDotLocalUrl } = await import( - '../../utils/validation' + '../../utils/validation.js' ); - const Logger = await import('../../utils/logger'); + const { default: Logger } = await import('../../utils/logger.js'); const logger = Logger.getLogger(); @@ -130,13 +130,13 @@ export default class DeviceLogsCmd extends Command { validateDotLocalUrl(params.device) ) { // Logs from local device - const { DeviceAPI } = await import('../../utils/device/api'); + const { DeviceAPI } = await import('../../utils/device/api.js'); const deviceApi = new DeviceAPI(logger, params.device); logger.logDebug('Checking we can access device'); try { await deviceApi.ping(); } catch { - const { ExpectedError } = await import('../../errors'); + const { ExpectedError } = await import('../../errors.js'); throw new ExpectedError( `Cannot access device at address ${params.device}. Device may not be in local mode.`, ); @@ -151,7 +151,7 @@ export default class DeviceLogsCmd extends Command { maxAttempts: 1 + (options['max-retry'] ?? MAX_RETRY), }); } else { - const { checkLoggedIn } = await import('../../utils/patterns'); + const { checkLoggedIn } = await import('../../utils/patterns.js'); // Logs from cloud await checkLoggedIn(); if (options.tail) { diff --git a/src/commands/device/move.ts b/src/commands/device/move.ts index 0300fe7045..608d87a7b0 100644 --- a/src/commands/device/move.ts +++ b/src/commands/device/move.ts @@ -22,10 +22,10 @@ import type { PineOptions, PineTypedResult, } from 'balena-sdk'; -import * as cf from '../../utils/common-flags'; -import { ExpectedError } from '../../errors'; -import { getBalenaSdk, stripIndent } from '../../utils/lazy'; -import { applicationIdInfo } from '../../utils/messages'; +import * as cf from '../../utils/common-flags.js'; +import { ExpectedError } from '../../errors.js'; +import { getBalenaSdk, stripIndent } from '../../utils/lazy.js'; +import { applicationIdInfo } from '../../utils/messages.js'; export default class DeviceMoveCmd extends Command { public static description = stripIndent` @@ -97,7 +97,7 @@ export default class DeviceMoveCmd extends Command { const devices = await this.getDevices(balena, deviceUuids); // Disambiguate application - const { getApplication } = await import('../../utils/sdk'); + const { getApplication } = await import('../../utils/sdk.js'); // Get destination application const application = options.fleet @@ -147,7 +147,7 @@ export default class DeviceMoveCmd extends Command { }) .map((deviceType) => deviceType.id); - const patterns = await import('../../utils/patterns'); + const patterns = await import('../../utils/patterns.js'); try { const application = await patterns.selectApplication( { diff --git a/src/commands/device/note.ts b/src/commands/device/note.ts index cedbdb8113..98bf4cf59a 100644 --- a/src/commands/device/note.ts +++ b/src/commands/device/note.ts @@ -16,9 +16,9 @@ */ import { Flags, Args, Command } from '@oclif/core'; -import { ExpectedError } from '../../errors'; -import * as cf from '../../utils/common-flags'; -import { getBalenaSdk, stripIndent } from '../../utils/lazy'; +import { ExpectedError } from '../../errors.js'; +import * as cf from '../../utils/common-flags.js'; +import { getBalenaSdk, stripIndent } from '../../utils/lazy.js'; export default class DeviceNoteCmd extends Command { public static aliases = ['notes']; @@ -45,7 +45,7 @@ export default class DeviceNoteCmd extends Command { }; public static flags = { - device: { exclusive: ['dev'], ...cf.device }, + device: cf.deviceExclusive(['dev']), dev: Flags.string({ exclusive: ['device'], hidden: true, diff --git a/src/commands/device/os-update.ts b/src/commands/device/os-update.ts index 18dc95ba20..08642e7e7e 100644 --- a/src/commands/device/os-update.ts +++ b/src/commands/device/os-update.ts @@ -16,11 +16,11 @@ */ import { Flags, Args, Command } from '@oclif/core'; -import * as cf from '../../utils/common-flags'; -import { getBalenaSdk, stripIndent, getCliForm } from '../../utils/lazy'; +import * as cf from '../../utils/common-flags.js'; +import { getBalenaSdk, stripIndent, getCliForm } from '../../utils/lazy.js'; import type { Device } from 'balena-sdk'; -import { ExpectedError } from '../../errors'; -import { getExpandedProp } from '../../utils/pine'; +import { ExpectedError } from '../../errors.js'; +import { getExpandedProp } from '../../utils/pine.js'; export default class DeviceOsUpdateCmd extends Command { public static description = stripIndent` @@ -119,7 +119,9 @@ export default class DeviceOsUpdateCmd extends Command { // Get target OS version let targetOsVersion = options.version; if (targetOsVersion != null) { - const { normalizeOsVersion } = await import('../../utils/normalization'); + const { normalizeOsVersion } = await import( + '../../utils/normalization.js' + ); targetOsVersion = normalizeOsVersion(targetOsVersion); if (!hupVersionInfo.versions.includes(targetOsVersion)) { throw new ExpectedError( @@ -155,7 +157,7 @@ export default class DeviceOsUpdateCmd extends Command { currentOsVersion, targetOsVersion, )) === 'takeover'; - const patterns = await import('../../utils/patterns'); + const patterns = await import('../../utils/patterns.js'); // Warn the user if the update requires a takeover if (takeoverRequired) { await patterns.confirm( diff --git a/src/commands/device/pin.ts b/src/commands/device/pin.ts index b786ccb8df..b9cbe85321 100644 --- a/src/commands/device/pin.ts +++ b/src/commands/device/pin.ts @@ -16,8 +16,8 @@ */ import { Args, Command } from '@oclif/core'; -import { getBalenaSdk, stripIndent } from '../../utils/lazy'; -import { getExpandedProp } from '../../utils/pine'; +import { getBalenaSdk, stripIndent } from '../../utils/lazy.js'; +import { getExpandedProp } from '../../utils/pine.js'; export default class DevicePinCmd extends Command { public static description = stripIndent` diff --git a/src/commands/device/public-url.ts b/src/commands/device/public-url.ts index 52f7394bff..4b0bbe6688 100644 --- a/src/commands/device/public-url.ts +++ b/src/commands/device/public-url.ts @@ -16,8 +16,8 @@ */ import { Flags, Args, Command } from '@oclif/core'; -import { ExpectedError } from '../../errors'; -import { getBalenaSdk, stripIndent } from '../../utils/lazy'; +import { ExpectedError } from '../../errors.js'; +import { getBalenaSdk, stripIndent } from '../../utils/lazy.js'; export default class DevicePublicUrlCmd extends Command { public static description = stripIndent` diff --git a/src/commands/device/purge.ts b/src/commands/device/purge.ts index 37cf4a5d97..34f528ccb4 100644 --- a/src/commands/device/purge.ts +++ b/src/commands/device/purge.ts @@ -16,7 +16,7 @@ */ import { Args, Command } from '@oclif/core'; -import { getBalenaSdk, getCliUx, stripIndent } from '../../utils/lazy'; +import { getBalenaSdk, getCliUx, stripIndent } from '../../utils/lazy.js'; export default class DevicePurgeCmd extends Command { public static description = stripIndent` diff --git a/src/commands/device/reboot.ts b/src/commands/device/reboot.ts index 9061b40511..3c3fcaa67a 100644 --- a/src/commands/device/reboot.ts +++ b/src/commands/device/reboot.ts @@ -16,8 +16,8 @@ */ import { Args, Command } from '@oclif/core'; -import * as cf from '../../utils/common-flags'; -import { getBalenaSdk, stripIndent } from '../../utils/lazy'; +import * as cf from '../../utils/common-flags.js'; +import { getBalenaSdk, stripIndent } from '../../utils/lazy.js'; export default class DeviceRebootCmd extends Command { public static description = stripIndent` diff --git a/src/commands/device/register.ts b/src/commands/device/register.ts index fc407b457e..0e8ad32a6d 100644 --- a/src/commands/device/register.ts +++ b/src/commands/device/register.ts @@ -16,9 +16,9 @@ */ import { Flags, Command } from '@oclif/core'; -import * as ca from '../../utils/common-args'; -import { getBalenaSdk, stripIndent } from '../../utils/lazy'; -import { applicationIdInfo } from '../../utils/messages'; +import * as ca from '../../utils/common-args.js'; +import { getBalenaSdk, stripIndent } from '../../utils/lazy.js'; +import { applicationIdInfo } from '../../utils/messages.js'; export default class DeviceRegisterCmd extends Command { public static description = stripIndent` @@ -59,7 +59,7 @@ export default class DeviceRegisterCmd extends Command { const { args: params, flags: options } = await this.parse(DeviceRegisterCmd); - const { getApplication } = await import('../../utils/sdk'); + const { getApplication } = await import('../../utils/sdk.js'); const balena = getBalenaSdk(); diff --git a/src/commands/device/rename.ts b/src/commands/device/rename.ts index f087be8080..2d7681abda 100644 --- a/src/commands/device/rename.ts +++ b/src/commands/device/rename.ts @@ -16,7 +16,7 @@ */ import { Args, Command } from '@oclif/core'; -import { getBalenaSdk, stripIndent, getCliForm } from '../../utils/lazy'; +import { getBalenaSdk, stripIndent, getCliForm } from '../../utils/lazy.js'; export default class DeviceRenameCmd extends Command { public static description = stripIndent` diff --git a/src/commands/device/restart.ts b/src/commands/device/restart.ts index f64d3bd523..19253e1f11 100644 --- a/src/commands/device/restart.ts +++ b/src/commands/device/restart.ts @@ -16,7 +16,7 @@ */ import { Flags, Args, Command } from '@oclif/core'; -import { getBalenaSdk, getCliUx, stripIndent } from '../../utils/lazy'; +import { getBalenaSdk, getCliUx, stripIndent } from '../../utils/lazy.js'; import type { BalenaSDK, DeviceWithServiceDetails, @@ -89,8 +89,8 @@ export default class DeviceRestartCmd extends Command { deviceUuid: string, serviceNames: string[], ) { - const { ExpectedError, instanceOf } = await import('../../errors'); - const { getExpandedProp } = await import('../../utils/pine'); + const { ExpectedError, instanceOf } = await import('../../errors.js'); + const { getExpandedProp } = await import('../../utils/pine.js'); // Get device let device: DeviceWithServiceDetails; @@ -156,7 +156,7 @@ export default class DeviceRestartCmd extends Command { // Note: device.restartApplication throws `BalenaDeviceNotFound: Device not found` if device not online. // Need to use device.get first to distinguish between non-existant and disconnected devices. // Remove this workaround when SDK issue resolved: https://github.com/balena-io/balena-sdk/issues/649 - const { instanceOf, ExpectedError } = await import('../../errors'); + const { instanceOf, ExpectedError } = await import('../../errors.js'); try { const device = await balena.models.device.get(deviceUuid); if (!device.is_online) { diff --git a/src/commands/device/rm.ts b/src/commands/device/rm.ts index be387aa776..00aa4cb093 100644 --- a/src/commands/device/rm.ts +++ b/src/commands/device/rm.ts @@ -16,8 +16,8 @@ */ import { Args, Command } from '@oclif/core'; -import * as cf from '../../utils/common-flags'; -import { getBalenaSdk, stripIndent } from '../../utils/lazy'; +import * as cf from '../../utils/common-flags.js'; +import { getBalenaSdk, stripIndent } from '../../utils/lazy.js'; export default class DeviceRmCmd extends Command { public static description = stripIndent` @@ -52,7 +52,7 @@ export default class DeviceRmCmd extends Command { const { args: params, flags: options } = await this.parse(DeviceRmCmd); const balena = getBalenaSdk(); - const patterns = await import('../../utils/patterns'); + const patterns = await import('../../utils/patterns.js'); // Confirm const uuids = params.uuid.split(','); diff --git a/src/commands/device/shutdown.ts b/src/commands/device/shutdown.ts index a65d7d84b8..8c1682498a 100644 --- a/src/commands/device/shutdown.ts +++ b/src/commands/device/shutdown.ts @@ -16,9 +16,9 @@ */ import { Args, Command } from '@oclif/core'; -import * as cf from '../../utils/common-flags'; -import { getBalenaSdk, stripIndent } from '../../utils/lazy'; -import { ExpectedError } from '../../errors'; +import * as cf from '../../utils/common-flags.js'; +import { getBalenaSdk, stripIndent } from '../../utils/lazy.js'; +import { ExpectedError } from '../../errors.js'; export default class DeviceShutdownCmd extends Command { public static description = stripIndent` diff --git a/src/commands/device/ssh.ts b/src/commands/device/ssh.ts index 7707f446e0..970d8776b7 100644 --- a/src/commands/device/ssh.ts +++ b/src/commands/device/ssh.ts @@ -16,11 +16,11 @@ */ import { Flags, Args, Command } from '@oclif/core'; -import { getBalenaSdk, stripIndent } from '../../utils/lazy'; +import { getBalenaSdk, stripIndent } from '../../utils/lazy.js'; import { parseAsInteger, validateLocalHostnameOrIp, -} from '../../utils/validation'; +} from '../../utils/validation.js'; export default class DeviceSSHCmd extends Command { public static aliases = ['ssh']; @@ -109,7 +109,9 @@ export default class DeviceSSHCmd extends Command { // Local connection if (validateLocalHostnameOrIp(params.fleetOrDevice)) { - const { performLocalDeviceSSH } = await import('../../utils/device/ssh'); + const { performLocalDeviceSSH } = await import( + '../../utils/device/ssh.js' + ); await performLocalDeviceSSH({ hostname: params.fleetOrDevice, port: options.port || 'local', @@ -121,12 +123,12 @@ export default class DeviceSSHCmd extends Command { } // Remote connection - const { getProxyConfig } = await import('../../utils/helpers'); + const { getProxyConfig } = await import('../../utils/helpers.js'); const { getOnlineTargetDeviceUuid, checkLoggedIn, checkNotUsingOfflineMode, - } = await import('../../utils/patterns'); + } = await import('../../utils/patterns.js'); const sdk = getBalenaSdk(); const proxyConfig = getProxyConfig(); @@ -140,7 +142,7 @@ export default class DeviceSSHCmd extends Command { params.fleetOrDevice, ); - const { which } = await import('../../utils/which'); + const { which } = await import('../../utils/which.js'); const [whichProxytunnel, { username }, proxyUrl] = await Promise.all([ useProxy ? which('proxytunnel', false) : undefined, @@ -192,7 +194,7 @@ export default class DeviceSSHCmd extends Command { let containerId: string | undefined; if (params.service != null) { const { getContainerIdForService } = await import( - '../../utils/device/ssh' + '../../utils/device/ssh.js' ); containerId = await getContainerIdForService({ deviceUuid, @@ -210,7 +212,7 @@ export default class DeviceSSHCmd extends Command { } else { accessCommand = `host ${deviceUuid}`; } - const { runRemoteCommand } = await import('../../utils/ssh'); + const { runRemoteCommand } = await import('../../utils/ssh.js'); await runRemoteCommand({ cmd: accessCommand, hostname: `ssh.${proxyUrl}`, diff --git a/src/commands/device/start-service.ts b/src/commands/device/start-service.ts index eba5c71e33..3d36be785f 100644 --- a/src/commands/device/start-service.ts +++ b/src/commands/device/start-service.ts @@ -16,7 +16,7 @@ */ import { Args, Command } from '@oclif/core'; -import { getBalenaSdk, getCliUx, stripIndent } from '../../utils/lazy'; +import { getBalenaSdk, getCliUx, stripIndent } from '../../utils/lazy.js'; import type { BalenaSDK } from 'balena-sdk'; export default class DeviceStartServiceCmd extends Command { @@ -70,8 +70,8 @@ export default class DeviceStartServiceCmd extends Command { deviceUuid: string, serviceNames: string[], ) { - const { ExpectedError } = await import('../../errors'); - const { getExpandedProp } = await import('../../utils/pine'); + const { ExpectedError } = await import('../../errors.js'); + const { getExpandedProp } = await import('../../utils/pine.js'); // Get device const device = await balena.models.device.getWithServiceDetails( diff --git a/src/commands/device/stop-service.ts b/src/commands/device/stop-service.ts index 22f46067dd..05346430f9 100644 --- a/src/commands/device/stop-service.ts +++ b/src/commands/device/stop-service.ts @@ -16,7 +16,7 @@ */ import { Args, Command } from '@oclif/core'; -import { getBalenaSdk, getCliUx, stripIndent } from '../../utils/lazy'; +import { getBalenaSdk, getCliUx, stripIndent } from '../../utils/lazy.js'; import type { BalenaSDK } from 'balena-sdk'; export default class DeviceStopServiceCmd extends Command { @@ -70,8 +70,8 @@ export default class DeviceStopServiceCmd extends Command { deviceUuid: string, serviceNames: string[], ) { - const { ExpectedError } = await import('../../errors'); - const { getExpandedProp } = await import('../../utils/pine'); + const { ExpectedError } = await import('../../errors.js'); + const { getExpandedProp } = await import('../../utils/pine.js'); // Get device const device = await balena.models.device.getWithServiceDetails( diff --git a/src/commands/device/track-fleet.ts b/src/commands/device/track-fleet.ts index f4612a9723..ec78d62c75 100644 --- a/src/commands/device/track-fleet.ts +++ b/src/commands/device/track-fleet.ts @@ -16,7 +16,7 @@ */ import { Args, Command } from '@oclif/core'; -import { getBalenaSdk, stripIndent } from '../../utils/lazy'; +import { getBalenaSdk, stripIndent } from '../../utils/lazy.js'; export default class DeviceTrackFleetCmd extends Command { public static description = stripIndent` diff --git a/src/commands/device/tunnel.ts b/src/commands/device/tunnel.ts index 38d877ea85..a4411ab669 100644 --- a/src/commands/device/tunnel.ts +++ b/src/commands/device/tunnel.ts @@ -20,9 +20,9 @@ import { NoPortsDefinedError, InvalidPortMappingError, ExpectedError, -} from '../../errors'; -import { getBalenaSdk, stripIndent } from '../../utils/lazy'; -import { lowercaseIfSlug } from '../../utils/normalization'; +} from '../../errors.js'; +import { getBalenaSdk, stripIndent } from '../../utils/lazy.js'; +import { lowercaseIfSlug } from '../../utils/normalization.js'; import type { Server, Socket } from 'net'; @@ -94,7 +94,7 @@ export default class DeviceTunnelCmd extends Command { public async run() { const { args: params, flags: options } = await this.parse(DeviceTunnelCmd); - const Logger = await import('../../utils/logger'); + const { default: Logger } = await import('../../utils/logger.js'); const logger = Logger.getLogger(); const sdk = getBalenaSdk(); @@ -122,7 +122,9 @@ export default class DeviceTunnelCmd extends Command { } // Ascertain device uuid - const { getOnlineTargetDeviceUuid } = await import('../../utils/patterns'); + const { getOnlineTargetDeviceUuid } = await import( + '../../utils/patterns.js' + ); const uuid = await getOnlineTargetDeviceUuid(sdk, params.deviceOrFleet); logger.logInfo(`Opening a tunnel to ${uuid}...`); @@ -134,7 +136,7 @@ export default class DeviceTunnelCmd extends Command { .map(async ({ localPort, localAddress, remotePort }) => { try { const { tunnelConnectionToDevice } = await import( - '../../utils/tunnel' + '../../utils/tunnel.js' ); const handler = await tunnelConnectionToDevice(uuid, remotePort, sdk); diff --git a/src/commands/env/list.ts b/src/commands/env/list.ts index 42c122d564..6b28021512 100644 --- a/src/commands/env/list.ts +++ b/src/commands/env/list.ts @@ -17,11 +17,11 @@ import { Flags, Command } from '@oclif/core'; import type { Interfaces } from '@oclif/core'; import type * as SDK from 'balena-sdk'; -import * as _ from 'lodash'; -import { ExpectedError } from '../../errors'; -import * as cf from '../../utils/common-flags'; -import { getBalenaSdk, getVisuals, stripIndent } from '../../utils/lazy'; -import { applicationIdInfo } from '../../utils/messages'; +import _ from 'lodash'; +import { ExpectedError } from '../../errors.js'; +import * as cf from '../../utils/common-flags.js'; +import { getBalenaSdk, getVisuals, stripIndent } from '../../utils/lazy.js'; +import { applicationIdInfo } from '../../utils/messages.js'; type FlagsDef = Interfaces.InferredFlags; @@ -97,16 +97,16 @@ export default class EnvListCmd extends Command { ]; public static flags = { - fleet: { ...cf.fleet, exclusive: ['device'] }, + fleet: cf.fleetExclusive(['device']), config: Flags.boolean({ default: false, char: 'c', description: 'show configuration variables only', exclusive: ['service'], }), - device: { ...cf.device, exclusive: ['fleet'] }, + device: cf.deviceExclusive(['fleet']), json: cf.json, - service: { ...cf.service, exclusive: ['config'] }, + service: cf.serviceExclusive(['config']), }; public async run() { @@ -114,7 +114,7 @@ export default class EnvListCmd extends Command { const variables: EnvironmentVariableInfo[] = []; - const { checkLoggedIn } = await import('../../utils/patterns'); + const { checkLoggedIn } = await import('../../utils/patterns.js'); await checkLoggedIn(); @@ -126,14 +126,14 @@ export default class EnvListCmd extends Command { let fleetSlug: string | undefined = options.fleet ? await ( - await import('../../utils/sdk') + await import('../../utils/sdk.js') ).getFleetSlug(balena, options.fleet) : undefined; let fullUUID: string | undefined; // as oppposed to the short, 7-char UUID if (options.device) { const { getDeviceAndMaybeAppFromUUID } = await import( - '../../utils/cloud' + '../../utils/cloud.js' ); const [device, app] = await getDeviceAndMaybeAppFromUUID( balena, @@ -187,7 +187,7 @@ export default class EnvListCmd extends Command { } if (options.json) { - const { pickAndRename } = await import('../../utils/helpers'); + const { pickAndRename } = await import('../../utils/helpers.js'); const mapped = varArray.map((o) => pickAndRename(o, fields)); this.log(JSON.stringify(mapped, null, 4)); } else { diff --git a/src/commands/env/rename.ts b/src/commands/env/rename.ts index ab977ab7ab..acea192fec 100644 --- a/src/commands/env/rename.ts +++ b/src/commands/env/rename.ts @@ -15,9 +15,9 @@ * limitations under the License. */ import { Args, Command } from '@oclif/core'; -import * as ec from '../../utils/env-common'; -import { getBalenaSdk, stripIndent } from '../../utils/lazy'; -import { parseAsInteger } from '../../utils/validation'; +import * as ec from '../../utils/env-common.js'; +import { getBalenaSdk, stripIndent } from '../../utils/lazy.js'; +import { parseAsInteger } from '../../utils/validation.js'; export default class EnvRenameCmd extends Command { public static description = stripIndent` @@ -59,7 +59,7 @@ export default class EnvRenameCmd extends Command { public async run() { const { args: params, flags: opt } = await this.parse(EnvRenameCmd); - const { checkLoggedIn } = await import('../../utils/patterns'); + const { checkLoggedIn } = await import('../../utils/patterns.js'); await checkLoggedIn(); diff --git a/src/commands/env/rm.ts b/src/commands/env/rm.ts index 819c516147..a324e8a662 100644 --- a/src/commands/env/rm.ts +++ b/src/commands/env/rm.ts @@ -16,9 +16,9 @@ */ import { Flags, Args, Command } from '@oclif/core'; -import * as ec from '../../utils/env-common'; -import { getBalenaSdk, stripIndent } from '../../utils/lazy'; -import { parseAsInteger } from '../../utils/validation'; +import * as ec from '../../utils/env-common.js'; +import { getBalenaSdk, stripIndent } from '../../utils/lazy.js'; +import { parseAsInteger } from '../../utils/validation.js'; export default class EnvRmCmd extends Command { public static description = stripIndent` @@ -65,11 +65,11 @@ export default class EnvRmCmd extends Command { public async run() { const { args: params, flags: opt } = await this.parse(EnvRmCmd); - const { checkLoggedIn } = await import('../../utils/patterns'); + const { checkLoggedIn } = await import('../../utils/patterns.js'); await checkLoggedIn(); - const { confirm } = await import('../../utils/patterns'); + const { confirm } = await import('../../utils/patterns.js'); await confirm( opt.yes || false, 'Are you sure you want to delete the environment variable?', diff --git a/src/commands/env/set.ts b/src/commands/env/set.ts index 6ad8d6a044..da070185df 100644 --- a/src/commands/env/set.ts +++ b/src/commands/env/set.ts @@ -17,10 +17,10 @@ import { Args, Command } from '@oclif/core'; import type * as BalenaSdk from 'balena-sdk'; -import { ExpectedError } from '../../errors'; -import * as cf from '../../utils/common-flags'; -import { getBalenaSdk, stripIndent } from '../../utils/lazy'; -import { applicationIdInfo } from '../../utils/messages'; +import { ExpectedError } from '../../errors.js'; +import * as cf from '../../utils/common-flags.js'; +import { getBalenaSdk, stripIndent } from '../../utils/lazy.js'; +import { applicationIdInfo } from '../../utils/messages.js'; interface FlagsDef { fleet?: string; @@ -95,8 +95,8 @@ export default class EnvSetCmd extends Command { public static strict = false; public static flags = { - fleet: { ...cf.fleet, exclusive: ['device'] }, - device: { ...cf.device, exclusive: ['fleet'] }, + fleet: cf.fleetExclusive(['device']), + device: cf.deviceExclusive(['fleet']), quiet: cf.quiet, service: cf.service, }; @@ -111,7 +111,7 @@ export default class EnvSetCmd extends Command { ); } - const { checkLoggedIn } = await import('../../utils/patterns'); + const { checkLoggedIn } = await import('../../utils/patterns.js'); await checkLoggedIn(); @@ -186,7 +186,7 @@ async function resolveFleetSlugs( fleetOption: string, ) { const fleetSlugs: string[] = []; - const { getFleetSlug } = await import('../../utils/sdk'); + const { getFleetSlug } = await import('../../utils/sdk.js'); for (const appNameOrSlug of fleetOption.split(',')) { try { fleetSlugs.push(await getFleetSlug(balena, appNameOrSlug)); @@ -223,7 +223,7 @@ async function setServiceVars( } } } else if (options.device) { - const { getDeviceAndAppFromUUID } = await import('../../utils/cloud'); + const { getDeviceAndAppFromUUID } = await import('../../utils/cloud.js'); for (const uuid of options.device.split(',')) { let device; let app; diff --git a/src/commands/fleet/create.ts b/src/commands/fleet/create.ts index ebb3cb35f2..a5632104ad 100644 --- a/src/commands/fleet/create.ts +++ b/src/commands/fleet/create.ts @@ -16,7 +16,7 @@ */ import { Flags, Args, Command } from '@oclif/core'; -import { stripIndent } from '../../utils/lazy'; +import { stripIndent } from '../../utils/lazy.js'; export default class FleetCreateCmd extends Command { public static description = stripIndent` @@ -71,7 +71,7 @@ export default class FleetCreateCmd extends Command { const { args: params, flags: options } = await this.parse(FleetCreateCmd); await ( - await import('../../utils/application-create') + await import('../../utils/application-create.js') ).applicationCreateBase('fleet', options, params); } } diff --git a/src/commands/fleet/index.ts b/src/commands/fleet/index.ts index 7080a697c8..502dd7151d 100644 --- a/src/commands/fleet/index.ts +++ b/src/commands/fleet/index.ts @@ -16,10 +16,10 @@ */ import { Flags, Command } from '@oclif/core'; -import * as cf from '../../utils/common-flags'; -import * as ca from '../../utils/common-args'; -import { getBalenaSdk, getVisuals, stripIndent } from '../../utils/lazy'; -import { applicationIdInfo } from '../../utils/messages'; +import * as cf from '../../utils/common-flags.js'; +import * as ca from '../../utils/common-args.js'; +import { getBalenaSdk, getVisuals, stripIndent } from '../../utils/lazy.js'; +import { applicationIdInfo } from '../../utils/messages.js'; export default class FleetCmd extends Command { public static description = stripIndent` @@ -53,7 +53,7 @@ export default class FleetCmd extends Command { public async run() { const { args: params, flags: options } = await this.parse(FleetCmd); - const { getApplication } = await import('../../utils/sdk'); + const { getApplication } = await import('../../utils/sdk.js'); const balena = getBalenaSdk(); @@ -65,7 +65,7 @@ export default class FleetCmd extends Command { }); if (options.view) { - const open = await import('open'); + const { default: open } = await import('open'); const dashboardUrl = balena.models.application.getDashboardUrl( application.id, ); diff --git a/src/commands/fleet/list.ts b/src/commands/fleet/list.ts index 49e84547f9..fd243102f4 100644 --- a/src/commands/fleet/list.ts +++ b/src/commands/fleet/list.ts @@ -16,8 +16,8 @@ */ import type * as BalenaSdk from 'balena-sdk'; -import * as cf from '../../utils/common-flags'; -import { getBalenaSdk, getVisuals, stripIndent } from '../../utils/lazy'; +import * as cf from '../../utils/common-flags.js'; +import { getBalenaSdk, getVisuals, stripIndent } from '../../utils/lazy.js'; import { Command } from '@oclif/core'; interface ExtendedApplication extends ApplicationWithDeviceTypeSlug { diff --git a/src/commands/fleet/pin.ts b/src/commands/fleet/pin.ts index e1665bef82..c403ef9851 100644 --- a/src/commands/fleet/pin.ts +++ b/src/commands/fleet/pin.ts @@ -16,8 +16,8 @@ */ import { Args, Command } from '@oclif/core'; -import { getBalenaSdk, stripIndent } from '../../utils/lazy'; -import { getExpandedProp } from '../../utils/pine'; +import { getBalenaSdk, stripIndent } from '../../utils/lazy.js'; +import { getExpandedProp } from '../../utils/pine.js'; export default class FleetPinCmd extends Command { public static description = stripIndent` diff --git a/src/commands/fleet/purge.ts b/src/commands/fleet/purge.ts index 2bcd396650..41e4008ea8 100644 --- a/src/commands/fleet/purge.ts +++ b/src/commands/fleet/purge.ts @@ -16,9 +16,9 @@ */ import { Command } from '@oclif/core'; -import * as ca from '../../utils/common-args'; -import { getBalenaSdk, stripIndent } from '../../utils/lazy'; -import { applicationIdInfo } from '../../utils/messages'; +import * as ca from '../../utils/common-args.js'; +import { getBalenaSdk, stripIndent } from '../../utils/lazy.js'; +import { applicationIdInfo } from '../../utils/messages.js'; export default class FleetPurgeCmd extends Command { public static description = stripIndent` @@ -44,7 +44,7 @@ export default class FleetPurgeCmd extends Command { public async run() { const { args: params } = await this.parse(FleetPurgeCmd); - const { getApplication } = await import('../../utils/sdk'); + const { getApplication } = await import('../../utils/sdk.js'); const balena = getBalenaSdk(); diff --git a/src/commands/fleet/rename.ts b/src/commands/fleet/rename.ts index a6e03a06d6..a37ca671da 100644 --- a/src/commands/fleet/rename.ts +++ b/src/commands/fleet/rename.ts @@ -16,9 +16,9 @@ */ import { Args, Command } from '@oclif/core'; -import * as ca from '../../utils/common-args'; -import { getBalenaSdk, stripIndent, getCliForm } from '../../utils/lazy'; -import { applicationIdInfo } from '../../utils/messages'; +import * as ca from '../../utils/common-args.js'; +import { getBalenaSdk, stripIndent, getCliForm } from '../../utils/lazy.js'; +import { applicationIdInfo } from '../../utils/messages.js'; export default class FleetRenameCmd extends Command { public static description = stripIndent` @@ -50,13 +50,15 @@ export default class FleetRenameCmd extends Command { public async run() { const { args: params } = await this.parse(FleetRenameCmd); - const { validateApplicationName } = await import('../../utils/validation'); - const { ExpectedError } = await import('../../errors'); + const { validateApplicationName } = await import( + '../../utils/validation.js' + ); + const { ExpectedError } = await import('../../errors.js'); const balena = getBalenaSdk(); // Disambiguate target application (if params.params is a number, it could either be an ID or a numerical name) - const { getApplication } = await import('../../utils/sdk'); + const { getApplication } = await import('../../utils/sdk.js'); const application = await getApplication(balena, params.fleet, { $select: ['id', 'app_name', 'slug'], $expand: { diff --git a/src/commands/fleet/restart.ts b/src/commands/fleet/restart.ts index 9a6c6c9d8c..1a300a023c 100644 --- a/src/commands/fleet/restart.ts +++ b/src/commands/fleet/restart.ts @@ -16,9 +16,9 @@ */ import { Command } from '@oclif/core'; -import * as ca from '../../utils/common-args'; -import { getBalenaSdk, stripIndent } from '../../utils/lazy'; -import { applicationIdInfo } from '../../utils/messages'; +import * as ca from '../../utils/common-args.js'; +import { getBalenaSdk, stripIndent } from '../../utils/lazy.js'; +import { applicationIdInfo } from '../../utils/messages.js'; export default class FleetRestartCmd extends Command { public static description = stripIndent` @@ -43,7 +43,7 @@ export default class FleetRestartCmd extends Command { public async run() { const { args: params } = await this.parse(FleetRestartCmd); - const { getApplication } = await import('../../utils/sdk'); + const { getApplication } = await import('../../utils/sdk.js'); const balena = getBalenaSdk(); diff --git a/src/commands/fleet/rm.ts b/src/commands/fleet/rm.ts index c768b74d9a..311a6f55d5 100644 --- a/src/commands/fleet/rm.ts +++ b/src/commands/fleet/rm.ts @@ -15,10 +15,10 @@ * limitations under the License. */ -import * as cf from '../../utils/common-flags'; -import * as ca from '../../utils/common-args'; -import { getBalenaSdk, stripIndent } from '../../utils/lazy'; -import { applicationIdInfo } from '../../utils/messages'; +import * as cf from '../../utils/common-flags.js'; +import * as ca from '../../utils/common-args.js'; +import { getBalenaSdk, stripIndent } from '../../utils/lazy.js'; +import { applicationIdInfo } from '../../utils/messages.js'; import { Command } from '@oclif/core'; export default class FleetRmCmd extends Command { @@ -51,8 +51,8 @@ export default class FleetRmCmd extends Command { public async run() { const { args: params, flags: options } = await this.parse(FleetRmCmd); - const { confirm } = await import('../../utils/patterns'); - const { getApplication } = await import('../../utils/sdk'); + const { confirm } = await import('../../utils/patterns.js'); + const { getApplication } = await import('../../utils/sdk.js'); const balena = getBalenaSdk(); // Confirm diff --git a/src/commands/fleet/track-latest.ts b/src/commands/fleet/track-latest.ts index 2547d9b2ba..602f10e6f4 100644 --- a/src/commands/fleet/track-latest.ts +++ b/src/commands/fleet/track-latest.ts @@ -16,7 +16,7 @@ */ import { Args, Command } from '@oclif/core'; -import { getBalenaSdk, stripIndent } from '../../utils/lazy'; +import { getBalenaSdk, stripIndent } from '../../utils/lazy.js'; export default class FleetTrackLatestCmd extends Command { public static description = stripIndent` diff --git a/src/commands/internal/osinit.ts b/src/commands/internal/osinit.ts index 4a420ae88b..494db8a866 100644 --- a/src/commands/internal/osinit.ts +++ b/src/commands/internal/osinit.ts @@ -16,7 +16,7 @@ */ import { Args, Command } from '@oclif/core'; -import { stripIndent } from '../../utils/lazy'; +import { stripIndent } from '../../utils/lazy.js'; // 'Internal' commands are called during the execution of other commands. // `osinit` is called during `os initialize` @@ -56,7 +56,7 @@ export default class OsinitCmd extends Command { const config = JSON.parse(params.config); const { getManifest, osProgressHandler } = await import( - '../../utils/helpers' + '../../utils/helpers.js' ); const manifest = await getManifest(params.image, params.type); diff --git a/src/commands/join/index.ts b/src/commands/join/index.ts index 5427cb5762..d4b139c3e3 100644 --- a/src/commands/join/index.ts +++ b/src/commands/join/index.ts @@ -16,10 +16,10 @@ */ import { Args, Flags, Command } from '@oclif/core'; -import * as cf from '../../utils/common-flags'; -import { getBalenaSdk, stripIndent } from '../../utils/lazy'; -import { applicationIdInfo } from '../../utils/messages'; -import { parseAsLocalHostnameOrIp } from '../../utils/validation'; +import * as cf from '../../utils/common-flags.js'; +import { getBalenaSdk, stripIndent } from '../../utils/lazy.js'; +import { applicationIdInfo } from '../../utils/messages.js'; +import { parseAsLocalHostnameOrIp } from '../../utils/validation.js'; export default class JoinCmd extends Command { public static description = stripIndent` @@ -73,9 +73,9 @@ export default class JoinCmd extends Command { public async run() { const { args: params, flags: options } = await this.parse(JoinCmd); - const promote = await import('../../utils/promote'); + const promote = await import('../../utils/promote.js'); const sdk = getBalenaSdk(); - const Logger = await import('../../utils/logger'); + const { default: Logger } = await import('../../utils/logger.js'); const logger = Logger.getLogger(); return promote.join( logger, diff --git a/src/commands/leave/index.ts b/src/commands/leave/index.ts index 123631a8fc..a9b5802939 100644 --- a/src/commands/leave/index.ts +++ b/src/commands/leave/index.ts @@ -16,8 +16,8 @@ */ import { Args, Command } from '@oclif/core'; -import { stripIndent } from '../../utils/lazy'; -import { parseAsLocalHostnameOrIp } from '../../utils/validation'; +import { stripIndent } from '../../utils/lazy.js'; +import { parseAsLocalHostnameOrIp } from '../../utils/validation.js'; export default class LeaveCmd extends Command { public static description = stripIndent` @@ -54,8 +54,8 @@ export default class LeaveCmd extends Command { public async run() { const { args: params } = await this.parse(LeaveCmd); - const promote = await import('../../utils/promote'); - const Logger = await import('../../utils/logger'); + const promote = await import('../../utils/promote.js'); + const { default: Logger } = await import('../../utils/logger.js'); const logger = Logger.getLogger(); return promote.leave(logger, params.deviceIpOrHostname); } diff --git a/src/commands/local/configure.ts b/src/commands/local/configure.ts index 1206edefca..8b925b7d79 100644 --- a/src/commands/local/configure.ts +++ b/src/commands/local/configure.ts @@ -17,7 +17,7 @@ import { Args, Command } from '@oclif/core'; import { promisify } from 'util'; -import { stripIndent } from '../../utils/lazy'; +import { stripIndent } from '../../utils/lazy.js'; export default class LocalConfigureCmd extends Command { public static description = stripIndent` @@ -45,8 +45,8 @@ export default class LocalConfigureCmd extends Command { const { args: params } = await this.parse(LocalConfigureCmd); const reconfix = await import('reconfix'); - const { denyMount, safeUmount } = await import('../../utils/umount'); - const Logger = await import('../../utils/logger'); + const { denyMount, safeUmount } = await import('../../utils/umount.js'); + const { default: Logger } = await import('../../utils/logger.js'); const logger = Logger.getLogger(); diff --git a/src/commands/local/flash.ts b/src/commands/local/flash.ts index 89c097efbc..2bdf19150b 100644 --- a/src/commands/local/flash.ts +++ b/src/commands/local/flash.ts @@ -17,9 +17,9 @@ import { Args, Command } from '@oclif/core'; import type { BlockDevice } from 'etcher-sdk/build/source-destination'; -import { ExpectedError } from '../../errors'; -import * as cf from '../../utils/common-flags'; -import { getChalk, getVisuals, stripIndent } from '../../utils/lazy'; +import { ExpectedError } from '../../errors.js'; +import * as cf from '../../utils/common-flags.js'; +import { getChalk, getVisuals, stripIndent } from '../../utils/lazy.js'; export default class LocalFlashCmd extends Command { public static description = stripIndent` @@ -75,7 +75,7 @@ export default class LocalFlashCmd extends Command { const drive = await this.getDrive(options); - const { confirm } = await import('../../utils/patterns'); + const { confirm } = await import('../../utils/patterns.js'); await confirm( options.yes, 'This will erase the selected drive. Are you sure?', diff --git a/src/commands/login/index.ts b/src/commands/login/index.ts index 2d080bee0e..f72af7b164 100644 --- a/src/commands/login/index.ts +++ b/src/commands/login/index.ts @@ -16,8 +16,8 @@ */ import { Flags, Args, Command } from '@oclif/core'; -import { getBalenaSdk, stripIndent, getCliForm } from '../../utils/lazy'; -import { ExpectedError } from '../../errors'; +import { getBalenaSdk, stripIndent, getCliForm } from '../../utils/lazy.js'; +import { ExpectedError } from '../../errors.js'; import type { WhoamiResult } from 'balena-sdk'; interface FlagsDef { @@ -117,7 +117,7 @@ export default class LoginCmd extends Command { const { flags: options, args: params } = await this.parse(LoginCmd); const balena = getBalenaSdk(); - const messages = await import('../../utils/messages'); + const messages = await import('../../utils/messages.js'); const balenaUrl = await balena.settings.get('balenaUrl'); // Consolidate user/email options @@ -196,20 +196,20 @@ ${messages.reachingOut}`); } // Credentials else if (loginOptions.credentials) { - const patterns = await import('../../utils/patterns'); + const patterns = await import('../../utils/patterns.js'); return patterns.authenticate(loginOptions); } // Web else if (loginOptions.web) { - const auth = await import('../../auth'); + const auth = await import('../../auth/index.js'); await auth.login({ port: loginOptions.port }); return; } else { - const patterns = await import('../../utils/patterns'); + const patterns = await import('../../utils/patterns.js'); // User had not selected login preference, prompt interactively const loginType = await patterns.askLoginType(); if (loginType === 'register') { - const open = await import('open'); + const { default: open } = await import('open'); const signupUrl = `https://dashboard.${balenaUrl}/signup`; await open(signupUrl, { wait: false }); throw new ExpectedError(`Please sign up at ${signupUrl}`); diff --git a/src/commands/logout/index.ts b/src/commands/logout/index.ts index 313db52f3c..41bdfe7ae8 100644 --- a/src/commands/logout/index.ts +++ b/src/commands/logout/index.ts @@ -16,7 +16,7 @@ */ import { Command } from '@oclif/core'; -import { getBalenaSdk, stripIndent } from '../../utils/lazy'; +import { getBalenaSdk, stripIndent } from '../../utils/lazy.js'; export default class LogoutCmd extends Command { public static description = stripIndent` diff --git a/src/commands/organization/list.ts b/src/commands/organization/list.ts index df252d8365..adeb9fb659 100644 --- a/src/commands/organization/list.ts +++ b/src/commands/organization/list.ts @@ -16,7 +16,7 @@ */ import { Command } from '@oclif/core'; -import { getBalenaSdk, getVisuals, stripIndent } from '../../utils/lazy'; +import { getBalenaSdk, getVisuals, stripIndent } from '../../utils/lazy.js'; export default class OrganizationListCmd extends Command { public static aliases = ['orgs']; @@ -34,7 +34,7 @@ export default class OrganizationListCmd extends Command { public async run() { await this.parse(OrganizationListCmd); - const { getOwnOrganizations } = await import('../../utils/sdk'); + const { getOwnOrganizations } = await import('../../utils/sdk.js'); // Get organizations const organizations = await getOwnOrganizations(getBalenaSdk(), { diff --git a/src/commands/os/build-config.ts b/src/commands/os/build-config.ts index 7a15613b59..3848b6357d 100644 --- a/src/commands/os/build-config.ts +++ b/src/commands/os/build-config.ts @@ -16,8 +16,8 @@ */ import { Flags, Args, Command } from '@oclif/core'; -import { getCliForm, stripIndent } from '../../utils/lazy'; -import * as _ from 'lodash'; +import { getCliForm, stripIndent } from '../../utils/lazy.js'; +import _ from 'lodash'; import type { DeviceTypeJson } from 'balena-sdk'; export default class OsBuildConfigCmd extends Command { @@ -77,7 +77,7 @@ export default class OsBuildConfigCmd extends Command { async buildConfig(image: string, deviceTypeSlug: string, advanced: boolean) { advanced = advanced || false; - const { getManifest } = await import('../../utils/helpers'); + const { getManifest } = await import('../../utils/helpers.js'); const deviceTypeManifest = await getManifest(image, deviceTypeSlug); return this.buildConfigForDeviceType(deviceTypeManifest, advanced); @@ -98,7 +98,7 @@ export default class OsBuildConfigCmd extends Command { }); if (advancedGroup != null) { - const { getGroupDefaults } = await import('../../utils/helpers'); + const { getGroupDefaults } = await import('../../utils/helpers.js'); override = getGroupDefaults(advancedGroup); } } diff --git a/src/commands/os/configure.ts b/src/commands/os/configure.ts index c3157c9a42..d13933677e 100644 --- a/src/commands/os/configure.ts +++ b/src/commands/os/configure.ts @@ -19,15 +19,15 @@ import { Flags, Args, Command } from '@oclif/core'; import type { Interfaces } from '@oclif/core'; import type * as BalenaSdk from 'balena-sdk'; import { promisify } from 'util'; -import * as _ from 'lodash'; -import { ExpectedError } from '../../errors'; -import * as cf from '../../utils/common-flags'; -import { getBalenaSdk, stripIndent, getCliForm } from '../../utils/lazy'; +import _ from 'lodash'; +import { ExpectedError } from '../../errors.js'; +import * as cf from '../../utils/common-flags.js'; +import { getBalenaSdk, stripIndent, getCliForm } from '../../utils/lazy.js'; import { applicationIdInfo, devModeInfo, secureBootInfo, -} from '../../utils/messages'; +} from '../../utils/messages.js'; const CONNECTIONS_FOLDER = '/system-connections'; @@ -97,7 +97,7 @@ export default class OsConfigureCmd extends Command { description: 'ask advanced configuration questions (when in interactive mode)', }), - fleet: { ...cf.fleet, exclusive: ['device'] }, + fleet: cf.fleetExclusive(['device']), config: Flags.string({ description: 'path to a pre-generated config.json file to be injected in the OS image', @@ -119,14 +119,11 @@ export default class OsConfigureCmd extends Command { }), dev: cf.dev, secureBoot: cf.secureBoot, - device: { - ...cf.device, - exclusive: [ - 'fleet', - 'provisioning-key-name', - 'provisioning-key-expiry-date', - ], - }, + device: cf.deviceExclusive([ + 'fleet', + 'provisioning-key-name', + 'provisioning-key-expiry-date', + ]), 'device-type': Flags.string({ description: 'device type slug (e.g. "raspberrypi3") to override the fleet device type', @@ -166,10 +163,10 @@ export default class OsConfigureCmd extends Command { const devInit = await import('balena-device-init'); const { promises: fs } = await import('fs'); const { generateDeviceConfig, generateApplicationConfig } = await import( - '../../utils/config' + '../../utils/config.js' ); - const helpers = await import('../../utils/helpers'); - const { getApplication } = await import('../../utils/sdk'); + const helpers = await import('../../utils/helpers.js'); + const { getApplication } = await import('../../utils/sdk.js'); let app: ApplicationWithDeviceTypeSlug | undefined; let device; @@ -201,13 +198,13 @@ export default class OsConfigureCmd extends Command { deviceTypeSlug, ); - let configJson: import('../../utils/config').ImgConfig | undefined; + let configJson: import('../../utils/config.js').ImgConfig | undefined; if (options.config) { const rawConfig = await fs.readFile(options.config, 'utf8'); configJson = JSON.parse(rawConfig); } - const { normalizeOsVersion } = await import('../../utils/normalization'); + const { normalizeOsVersion } = await import('../../utils/normalization.js'); const osVersion = normalizeOsVersion( options.version || (await getOsVersionFromImage( @@ -217,11 +214,11 @@ export default class OsConfigureCmd extends Command { )), ); - const { validateDevOptionAndWarn } = await import('../../utils/config'); + const { validateDevOptionAndWarn } = await import('../../utils/config.js'); await validateDevOptionAndWarn(options.dev, osVersion); const { validateSecureBootOptionAndWarn } = await import( - '../../utils/config' + '../../utils/config.js' ); await validateSecureBootOptionAndWarn( options.secureBoot, @@ -317,7 +314,7 @@ async function validateOptions(options: FlagsDef) { ); } - const { checkLoggedIn } = await import('../../utils/patterns'); + const { checkLoggedIn } = await import('../../utils/patterns.js'); await checkLoggedIn(); } @@ -361,7 +358,7 @@ async function checkDeviceTypeCompatibility( }, ) { if (options['device-type']) { - const helpers = await import('../../utils/helpers'); + const helpers = await import('../../utils/helpers.js'); if ( !(await helpers.areDeviceTypesCompatible( app.is_for__device_type[0].slug, @@ -392,7 +389,7 @@ async function checkDeviceTypeCompatibility( async function askQuestionsForDeviceType( deviceType: BalenaSdk.DeviceTypeJson.DeviceType, options: FlagsDef, - configJson?: import('../../utils/config').ImgConfig, + configJson?: import('../../utils/config.js').ImgConfig, ): Promise { const answerSources: any[] = [ { @@ -415,7 +412,7 @@ async function askQuestionsForDeviceType( isGroup: true, }); if (!_.isEmpty(advancedGroup)) { - const helpers = await import('../../utils/helpers'); + const helpers = await import('../../utils/helpers.js'); answerSources.push(helpers.getGroupDefaults(advancedGroup)); } } diff --git a/src/commands/os/download.ts b/src/commands/os/download.ts index 4635fcdd88..44f61a008c 100644 --- a/src/commands/os/download.ts +++ b/src/commands/os/download.ts @@ -16,7 +16,7 @@ */ import { Flags, Args, Command } from '@oclif/core'; -import { stripIndent } from '../../utils/lazy'; +import { stripIndent } from '../../utils/lazy.js'; export default class OsDownloadCmd extends Command { public static description = stripIndent` @@ -84,14 +84,14 @@ export default class OsDownloadCmd extends Command { // balenaOS ESR versions require user authentication if (options.version) { - const { isESR } = await import('../../utils/image-manager'); + const { isESR } = await import('../../utils/image-manager.js'); if (options.version === 'menu-esr' || isESR(options.version)) { try { - const { checkLoggedIn } = await import('../../utils/patterns'); + const { checkLoggedIn } = await import('../../utils/patterns.js'); await checkLoggedIn(); } catch (e) { const { ExpectedError, NotLoggedInError } = await import( - '../../errors' + '../../errors.js' ); if (e instanceof NotLoggedInError) { throw new ExpectedError(stripIndent` @@ -103,7 +103,7 @@ export default class OsDownloadCmd extends Command { } } - const { downloadOSImage } = await import('../../utils/cloud'); + const { downloadOSImage } = await import('../../utils/cloud.js'); try { await downloadOSImage(params.type, options.output, options.version); diff --git a/src/commands/os/initialize.ts b/src/commands/os/initialize.ts index c6d4b52aef..c5e35bb423 100644 --- a/src/commands/os/initialize.ts +++ b/src/commands/os/initialize.ts @@ -16,8 +16,8 @@ */ import { Args, Command } from '@oclif/core'; -import * as cf from '../../utils/common-flags'; -import { getCliForm, stripIndent } from '../../utils/lazy'; +import * as cf from '../../utils/common-flags.js'; +import { getCliForm, stripIndent } from '../../utils/lazy.js'; const INIT_WARNING_MESSAGE = ` @@ -58,7 +58,7 @@ export default class OsInitializeCmd extends Command { public async run() { const { args: params, flags: options } = await this.parse(OsInitializeCmd); - const { getManifest, sudo } = await import('../../utils/helpers'); + const { getManifest, sudo } = await import('../../utils/helpers.js'); console.info(`Initializing device ${INIT_WARNING_MESSAGE}`); @@ -71,13 +71,13 @@ export default class OsInitializeCmd extends Command { }); if (answers.drive != null) { - const { confirm } = await import('../../utils/patterns'); + const { confirm } = await import('../../utils/patterns.js'); await confirm( options.yes, `This will erase ${answers.drive}. Are you sure?`, `Going to erase ${answers.drive}.`, ); - const { safeUmount } = await import('../../utils/umount'); + const { safeUmount } = await import('../../utils/umount.js'); await safeUmount(answers.drive); } @@ -90,7 +90,7 @@ export default class OsInitializeCmd extends Command { ]); if (answers.drive != null) { - const { safeUmount } = await import('../../utils/umount'); + const { safeUmount } = await import('../../utils/umount.js'); await safeUmount(answers.drive); console.info(`You can safely remove ${answers.drive} now`); } diff --git a/src/commands/os/versions.ts b/src/commands/os/versions.ts index 1937885bcb..ef3fea6f43 100644 --- a/src/commands/os/versions.ts +++ b/src/commands/os/versions.ts @@ -16,7 +16,7 @@ */ import { Flags, Args, Command } from '@oclif/core'; -import { stripIndent } from '../../utils/lazy'; +import { stripIndent } from '../../utils/lazy.js'; export default class OsVersionsCmd extends Command { public static description = stripIndent` @@ -53,7 +53,7 @@ export default class OsVersionsCmd extends Command { const { args: params, flags: options } = await this.parse(OsVersionsCmd); if (options['include-draft']) { - const { warnify } = await import('../../utils/messages'); + const { warnify } = await import('../../utils/messages.js'); console.error( warnify(stripIndent` Using pre-release balenaOS versions is only supported for OS updates @@ -63,7 +63,7 @@ export default class OsVersionsCmd extends Command { } const { formatOsVersion, getOsVersions } = await import( - '../../utils/cloud' + '../../utils/cloud.js' ); const vs = await getOsVersions( params.type, diff --git a/src/commands/preload/index.ts b/src/commands/preload/index.ts index 3e09368528..8ddf524d8d 100644 --- a/src/commands/preload/index.ts +++ b/src/commands/preload/index.ts @@ -15,19 +15,19 @@ * limitations under the License. */ -import { ExpectedError } from '../../errors'; -import * as cf from '../../utils/common-flags'; +import { ExpectedError } from '../../errors.js'; +import * as cf from '../../utils/common-flags.js'; import { getBalenaSdk, getCliForm, getVisuals, stripIndent, -} from '../../utils/lazy'; -import { applicationIdInfo } from '../../utils/messages'; -import { dockerConnectionCliFlags } from '../../utils/docker'; -import { parseAsInteger } from '../../utils/validation'; +} from '../../utils/lazy.js'; +import { applicationIdInfo } from '../../utils/messages.js'; +import { dockerConnectionCliFlags } from '../../utils/docker.js'; +import { parseAsInteger } from '../../utils/validation.js'; import { Flags, Args, Command } from '@oclif/core'; -import * as _ from 'lodash'; +import _ from 'lodash'; import type { Application, BalenaSDK, @@ -37,6 +37,7 @@ import type { Release, } from 'balena-sdk'; import type { Preloader } from 'balena-preload'; +import type { EventEmitter } from 'node:events'; export default class PreloadCmd extends Command { public static description = stripIndent` @@ -138,10 +139,10 @@ Can be repeated to add multiple certificates.\ const { args: params, flags: options } = await this.parse(PreloadCmd); const balena = getBalenaSdk(); - const balenaPreload = await import('balena-preload'); + const { default: balenaPreload } = await import('balena-preload'); const visuals = getVisuals(); - const nodeCleanup = await import('node-cleanup'); - const { instanceOf } = await import('../../errors'); + const { default: nodeCleanup } = await import('node-cleanup'); + const { instanceOf } = await import('../../errors.js'); // Check image file exists try { @@ -165,7 +166,7 @@ Can be repeated to add multiple certificates.\ // Load app here, and use app slug from hereon const fleetSlug: string | undefined = options.fleet ? await ( - await import('../../utils/sdk') + await import('../../utils/sdk.js') ).getFleetSlug(balena, options.fleet) : undefined; @@ -222,7 +223,7 @@ Can be repeated to add multiple certificates.\ } // Get a configured dockerode instance - const dockerUtils = await import('../../utils/docker'); + const dockerUtils = await import('../../utils/docker.js'); const docker = await dockerUtils.getDocker(options); const preloader = new balenaPreload.Preloader( undefined, @@ -236,7 +237,7 @@ Can be repeated to add multiple certificates.\ pinDevice ?? false, certificates, additionalSpace, - ); + ) as Preloader & EventEmitter; let gotSignal = false; @@ -476,7 +477,7 @@ Would you like to disable automatic updates for this fleet now?\ } async getAppWithReleases(balenaSdk: BalenaSDK, slug: string) { - const { getApplication } = await import('../../utils/sdk'); + const { getApplication } = await import('../../utils/sdk.js'); return await getApplication(balenaSdk, slug, { $expand: this.applicationExpandOptions, diff --git a/src/commands/push/index.ts b/src/commands/push/index.ts index 2b8b6e7267..4bb02c5c6d 100644 --- a/src/commands/push/index.ts +++ b/src/commands/push/index.ts @@ -17,16 +17,16 @@ import { Flags, Args, Command } from '@oclif/core'; import type { Interfaces } from '@oclif/core'; -import { getBalenaSdk, stripIndent } from '../../utils/lazy'; -import { dockerignoreHelp, registrySecretsHelp } from '../../utils/messages'; +import { getBalenaSdk, stripIndent } from '../../utils/lazy.js'; +import { dockerignoreHelp, registrySecretsHelp } from '../../utils/messages.js'; import type { BalenaSDK } from 'balena-sdk'; -import { ExpectedError, instanceOf } from '../../errors'; +import { ExpectedError, instanceOf } from '../../errors.js'; import type { RegistrySecrets } from '@balena/compose/dist/multibuild'; -import { lowercaseIfSlug } from '../../utils/normalization'; +import { lowercaseIfSlug } from '../../utils/normalization.js'; import { applyReleaseTagKeysAndValues, parseReleaseTagKeysAndValues, -} from '../../utils/compose_ts'; +} from '../../utils/compose_ts.js'; enum BuildTarget { Cloud, @@ -224,13 +224,15 @@ export default class PushCmd extends Command { public async run() { const { args: params, flags: options } = await this.parse(PushCmd); - const Logger = await import('../../utils/logger'); + const { default: Logger } = await import('../../utils/logger.js'); const logger = Logger.getLogger(); logger.logDebug(`Using build source directory: ${options.source} `); const sdk = getBalenaSdk(); - const { validateProjectDirectory } = await import('../../utils/compose_ts'); + const { validateProjectDirectory } = await import( + '../../utils/compose_ts.js' + ); const { dockerfilePath, registrySecrets } = await validateProjectDirectory( sdk, { @@ -273,8 +275,8 @@ export default class PushCmd extends Command { dockerfilePath: string, registrySecrets: RegistrySecrets, ) { - const remote = await import('../../utils/remote-build'); - const { getApplication } = await import('../../utils/sdk'); + const remote = await import('../../utils/remote-build.js'); + const { getApplication } = await import('../../utils/sdk.js'); // Check for invalid options const localOnlyOptions: Array = [ @@ -293,7 +295,7 @@ export default class PushCmd extends Command { options['release-tag'] ?? [], ); - const { checkLoggedIn } = await import('../../utils/patterns'); + const { checkLoggedIn } = await import('../../utils/patterns.js'); await checkLoggedIn(); const [token, baseUrl] = await Promise.all([ @@ -355,7 +357,7 @@ export default class PushCmd extends Command { 'is only valid when pushing to a fleet', ); - const deviceDeploy = await import('../../utils/device/deploy'); + const deviceDeploy = await import('../../utils/device/deploy.js'); try { await deviceDeploy.deployToDevice({ @@ -375,7 +377,7 @@ export default class PushCmd extends Command { convertEol: !options['noconvert-eol'], }); } catch (e) { - const { BuildError } = await import('../../utils/device/errors'); + const { BuildError } = await import('../../utils/device/errors.js'); if (instanceOf(e, BuildError)) { throw new ExpectedError(e.toString()); } else { @@ -386,7 +388,7 @@ export default class PushCmd extends Command { protected async getBuildTarget(appOrDevice: string): Promise { const { validateLocalHostnameOrIp } = await import( - '../../utils/validation' + '../../utils/validation.js' ); return validateLocalHostnameOrIp(appOrDevice) diff --git a/src/commands/release/finalize.ts b/src/commands/release/finalize.ts index 20276e2e20..806c9dabb9 100644 --- a/src/commands/release/finalize.ts +++ b/src/commands/release/finalize.ts @@ -16,8 +16,8 @@ */ import { Command } from '@oclif/core'; -import { commitOrIdArg } from '.'; -import { getBalenaSdk, stripIndent } from '../../utils/lazy'; +import { commitOrIdArg } from './index.js'; +import { getBalenaSdk, stripIndent } from '../../utils/lazy.js'; export default class ReleaseFinalizeCmd extends Command { public static description = stripIndent` diff --git a/src/commands/release/index.ts b/src/commands/release/index.ts index ae1adfb4cf..f8f0a653e3 100644 --- a/src/commands/release/index.ts +++ b/src/commands/release/index.ts @@ -16,12 +16,12 @@ */ import { Flags, Args, type Interfaces, Command } from '@oclif/core'; -import * as cf from '../../utils/common-flags'; -import { getBalenaSdk, getVisuals, stripIndent } from '../../utils/lazy'; +import * as cf from '../../utils/common-flags.js'; +import { getBalenaSdk, getVisuals, stripIndent } from '../../utils/lazy.js'; import type * as BalenaSdk from 'balena-sdk'; import * as yaml from 'js-yaml'; -import { tryAsInteger } from '../../utils/validation'; -import { jsonInfo } from '../../utils/messages'; +import { tryAsInteger } from '../../utils/validation.js'; +import { jsonInfo } from '../../utils/messages.js'; export const commitOrIdArg = Args.custom({ parse: tryAsInteger, diff --git a/src/commands/release/invalidate.ts b/src/commands/release/invalidate.ts index 42f952c814..1c7e970c28 100644 --- a/src/commands/release/invalidate.ts +++ b/src/commands/release/invalidate.ts @@ -16,8 +16,8 @@ */ import { Command } from '@oclif/core'; -import { commitOrIdArg } from '.'; -import { getBalenaSdk, stripIndent } from '../../utils/lazy'; +import { commitOrIdArg } from './index.js'; +import { getBalenaSdk, stripIndent } from '../../utils/lazy.js'; export default class ReleaseInvalidateCmd extends Command { public static description = stripIndent` diff --git a/src/commands/release/list.ts b/src/commands/release/list.ts index 4c028817b9..4ede26f8ab 100644 --- a/src/commands/release/list.ts +++ b/src/commands/release/list.ts @@ -16,11 +16,11 @@ */ import { Args, Command } from '@oclif/core'; -import * as cf from '../../utils/common-flags'; -import { getBalenaSdk, getVisuals, stripIndent } from '../../utils/lazy'; -import { applicationNameNote } from '../../utils/messages'; +import * as cf from '../../utils/common-flags.js'; +import { getBalenaSdk, getVisuals, stripIndent } from '../../utils/lazy.js'; +import { applicationNameNote } from '../../utils/messages.js'; import type * as BalenaSdk from 'balena-sdk'; -import { jsonInfo } from '../../utils/messages'; +import { jsonInfo } from '../../utils/messages.js'; export default class ReleaseListCmd extends Command { public static aliases = ['releases']; @@ -66,7 +66,7 @@ export default class ReleaseListCmd extends Command { ] satisfies BalenaSdk.PineOptions['$select']; const balena = getBalenaSdk(); - const { getFleetSlug } = await import('../../utils/sdk'); + const { getFleetSlug } = await import('../../utils/sdk.js'); const releases = await balena.models.release.getAllByApplication( await getFleetSlug(balena, params.fleet), diff --git a/src/commands/release/validate.ts b/src/commands/release/validate.ts index 83d3e9ab63..4a50bf9b70 100644 --- a/src/commands/release/validate.ts +++ b/src/commands/release/validate.ts @@ -16,8 +16,8 @@ */ import { Command } from '@oclif/core'; -import { commitOrIdArg } from '.'; -import { getBalenaSdk, stripIndent } from '../../utils/lazy'; +import { commitOrIdArg } from './index.js'; +import { getBalenaSdk, stripIndent } from '../../utils/lazy.js'; export default class ReleaseValidateCmd extends Command { public static description = stripIndent` diff --git a/src/commands/settings/index.ts b/src/commands/settings/index.ts index 6dfaa5bcc6..7770bf4293 100644 --- a/src/commands/settings/index.ts +++ b/src/commands/settings/index.ts @@ -16,7 +16,7 @@ */ import { Command } from '@oclif/core'; -import { getBalenaSdk, stripIndent } from '../../utils/lazy'; +import { getBalenaSdk, stripIndent } from '../../utils/lazy.js'; export default class SettingsCmd extends Command { public static description = stripIndent` diff --git a/src/commands/ssh-key/add.ts b/src/commands/ssh-key/add.ts index 4652274203..d3eb0d2705 100644 --- a/src/commands/ssh-key/add.ts +++ b/src/commands/ssh-key/add.ts @@ -16,7 +16,7 @@ */ import { Args, Command } from '@oclif/core'; -import { getBalenaSdk, stripIndent } from '../../utils/lazy'; +import { getBalenaSdk, stripIndent } from '../../utils/lazy.js'; export default class SSHKeyAddCmd extends Command { public static aliases = ['key add']; diff --git a/src/commands/ssh-key/index.ts b/src/commands/ssh-key/index.ts index 3728658b14..4b02e616d4 100644 --- a/src/commands/ssh-key/index.ts +++ b/src/commands/ssh-key/index.ts @@ -16,8 +16,8 @@ */ import { Args, Command } from '@oclif/core'; -import { getBalenaSdk, getVisuals, stripIndent } from '../../utils/lazy'; -import { parseAsInteger } from '../../utils/validation'; +import { getBalenaSdk, getVisuals, stripIndent } from '../../utils/lazy.js'; +import { parseAsInteger } from '../../utils/validation.js'; export default class SSHKeyCmd extends Command { public static aliases = ['key']; diff --git a/src/commands/ssh-key/list.ts b/src/commands/ssh-key/list.ts index d081e64024..a8b4f7e5f2 100644 --- a/src/commands/ssh-key/list.ts +++ b/src/commands/ssh-key/list.ts @@ -16,7 +16,7 @@ */ import { Command } from '@oclif/core'; -import { getBalenaSdk, getVisuals, stripIndent } from '../../utils/lazy'; +import { getBalenaSdk, getVisuals, stripIndent } from '../../utils/lazy.js'; export default class SSHKeyListCmd extends Command { public static aliases = ['keys', 'key list']; diff --git a/src/commands/ssh-key/rm.ts b/src/commands/ssh-key/rm.ts index ac35ffdde5..30eb0d062d 100644 --- a/src/commands/ssh-key/rm.ts +++ b/src/commands/ssh-key/rm.ts @@ -16,9 +16,9 @@ */ import { Args, Command } from '@oclif/core'; -import * as cf from '../../utils/common-flags'; -import { getBalenaSdk, stripIndent } from '../../utils/lazy'; -import { parseAsInteger } from '../../utils/validation'; +import * as cf from '../../utils/common-flags.js'; +import { getBalenaSdk, stripIndent } from '../../utils/lazy.js'; +import { parseAsInteger } from '../../utils/validation.js'; export default class SSHKeyRmCmd extends Command { public static aliases = ['key rm']; @@ -54,7 +54,7 @@ export default class SSHKeyRmCmd extends Command { public async run() { const { args: params, flags: options } = await this.parse(SSHKeyRmCmd); - const patterns = await import('../../utils/patterns'); + const patterns = await import('../../utils/patterns.js'); await patterns.confirm( options.yes ?? false, diff --git a/src/commands/support/index.ts b/src/commands/support/index.ts index 6c100a2472..a32bb15212 100644 --- a/src/commands/support/index.ts +++ b/src/commands/support/index.ts @@ -16,10 +16,10 @@ */ import { Flags, Args, Command } from '@oclif/core'; -import { ExpectedError } from '../../errors'; -import * as cf from '../../utils/common-flags'; -import { getBalenaSdk, getCliUx, stripIndent } from '../../utils/lazy'; -import { applicationIdInfo } from '../../utils/messages'; +import { ExpectedError } from '../../errors.js'; +import * as cf from '../../utils/common-flags.js'; +import { getBalenaSdk, getCliUx, stripIndent } from '../../utils/lazy.js'; +import { applicationIdInfo } from '../../utils/messages.js'; export default class SupportCmd extends Command { public static description = stripIndent` @@ -56,11 +56,12 @@ export default class SupportCmd extends Command { description: 'comma-separated list (no spaces) of device UUIDs', char: 'd', }), - fleet: { - ...cf.fleet, + fleet: Flags.string({ + char: cf.fleet.char, description: 'comma-separated list (no spaces) of fleet names or slugs (preferred)', - }, + parse: cf.fleet.parse, + }), duration: Flags.string({ description: 'length of time to enable support for, in (h)ours or (d)ays, e.g. 12h, 2d', @@ -112,7 +113,7 @@ export default class SupportCmd extends Command { ux.action.stop(); } - const { getFleetSlug } = await import('../../utils/sdk'); + const { getFleetSlug } = await import('../../utils/sdk.js'); // Process applications for (const appName of appNames) { diff --git a/src/commands/tag/list.ts b/src/commands/tag/list.ts index 40ca940ef4..1484fd56e3 100644 --- a/src/commands/tag/list.ts +++ b/src/commands/tag/list.ts @@ -16,10 +16,10 @@ */ import { Command } from '@oclif/core'; -import { ExpectedError } from '../../errors'; -import * as cf from '../../utils/common-flags'; -import { getBalenaSdk, getVisuals, stripIndent } from '../../utils/lazy'; -import { applicationIdInfo } from '../../utils/messages'; +import { ExpectedError } from '../../errors.js'; +import * as cf from '../../utils/common-flags.js'; +import { getBalenaSdk, getVisuals, stripIndent } from '../../utils/lazy.js'; +import { applicationIdInfo } from '../../utils/messages.js'; export default class TagListCmd extends Command { public static aliases = ['tags']; @@ -42,18 +42,9 @@ export default class TagListCmd extends Command { ]; public static flags = { - fleet: { - ...cf.fleet, - exclusive: ['device', 'release'], - }, - device: { - ...cf.device, - exclusive: ['fleet', 'release'], - }, - release: { - ...cf.release, - exclusive: ['fleet', 'device'], - }, + fleet: cf.fleetExclusive(['device', 'release']), + device: cf.deviceExclusive(['fleet', 'release']), + release: cf.releaseExclusive(['fleet', 'device']), }; public static authenticated = true; @@ -71,7 +62,7 @@ export default class TagListCmd extends Command { let tags; if (options.fleet) { - const { getFleetSlug } = await import('../../utils/sdk'); + const { getFleetSlug } = await import('../../utils/sdk.js'); tags = await balena.models.application.tags.getAllByApplication( await getFleetSlug(balena, options.fleet), ); @@ -81,7 +72,7 @@ export default class TagListCmd extends Command { } if (options.release) { const { disambiguateReleaseParam } = await import( - '../../utils/normalization' + '../../utils/normalization.js' ); const releaseParam = await disambiguateReleaseParam( balena, diff --git a/src/commands/tag/rm.ts b/src/commands/tag/rm.ts index 622b6f35a3..55da85b665 100644 --- a/src/commands/tag/rm.ts +++ b/src/commands/tag/rm.ts @@ -16,9 +16,9 @@ */ import { Args, Command } from '@oclif/core'; -import * as cf from '../../utils/common-flags'; -import { getBalenaSdk, stripIndent } from '../../utils/lazy'; -import { applicationIdInfo } from '../../utils/messages'; +import * as cf from '../../utils/common-flags.js'; +import { getBalenaSdk, stripIndent } from '../../utils/lazy.js'; +import { applicationIdInfo } from '../../utils/messages.js'; export default class TagRmCmd extends Command { public static description = stripIndent` @@ -45,18 +45,9 @@ export default class TagRmCmd extends Command { }; public static flags = { - fleet: { - ...cf.fleet, - exclusive: ['device', 'release'], - }, - device: { - ...cf.device, - exclusive: ['fleet', 'release'], - }, - release: { - ...cf.release, - exclusive: ['fleet', 'device'], - }, + fleet: cf.fleetExclusive(['device', 'release']), + device: cf.deviceExclusive(['fleet', 'release']), + release: cf.releaseExclusive(['fleet', 'device']), }; public static authenticated = true; @@ -68,12 +59,12 @@ export default class TagRmCmd extends Command { // Check user has specified one of application/device/release if (!options.fleet && !options.device && !options.release) { - const { ExpectedError } = await import('../../errors'); + const { ExpectedError } = await import('../../errors.js'); throw new ExpectedError(TagRmCmd.missingResourceMessage); } if (options.fleet) { - const { getFleetSlug } = await import('../../utils/sdk'); + const { getFleetSlug } = await import('../../utils/sdk.js'); return balena.models.application.tags.remove( await getFleetSlug(balena, options.fleet), params.tagKey, @@ -84,7 +75,7 @@ export default class TagRmCmd extends Command { } if (options.release) { const { disambiguateReleaseParam } = await import( - '../../utils/normalization' + '../../utils/normalization.js' ); const releaseParam = await disambiguateReleaseParam( balena, diff --git a/src/commands/tag/set.ts b/src/commands/tag/set.ts index adb79a1eff..49810360e8 100644 --- a/src/commands/tag/set.ts +++ b/src/commands/tag/set.ts @@ -16,9 +16,9 @@ */ import { Args, Command } from '@oclif/core'; -import * as cf from '../../utils/common-flags'; -import { getBalenaSdk, stripIndent } from '../../utils/lazy'; -import { applicationIdInfo } from '../../utils/messages'; +import * as cf from '../../utils/common-flags.js'; +import { getBalenaSdk, stripIndent } from '../../utils/lazy.js'; +import { applicationIdInfo } from '../../utils/messages.js'; export default class TagSetCmd extends Command { public static description = stripIndent` @@ -59,18 +59,9 @@ export default class TagSetCmd extends Command { public static strict = false; public static flags = { - fleet: { - ...cf.fleet, - exclusive: ['device', 'release'], - }, - device: { - ...cf.device, - exclusive: ['fleet', 'release'], - }, - release: { - ...cf.release, - exclusive: ['fleet', 'device'], - }, + fleet: cf.fleetExclusive(['device', 'release']), + device: cf.deviceExclusive(['fleet', 'release']), + release: cf.releaseExclusive(['fleet', 'device']), }; public static authenticated = true; @@ -82,14 +73,14 @@ export default class TagSetCmd extends Command { // Check user has specified one of application/device/release if (!options.fleet && !options.device && !options.release) { - const { ExpectedError } = await import('../../errors'); + const { ExpectedError } = await import('../../errors.js'); throw new ExpectedError(TagSetCmd.missingResourceMessage); } params.value ??= ''; if (options.fleet) { - const { getFleetSlug } = await import('../../utils/sdk'); + const { getFleetSlug } = await import('../../utils/sdk.js'); return balena.models.application.tags.set( await getFleetSlug(balena, options.fleet), params.tagKey, @@ -105,7 +96,7 @@ export default class TagSetCmd extends Command { } if (options.release) { const { disambiguateReleaseParam } = await import( - '../../utils/normalization' + '../../utils/normalization.js' ); const releaseParam = await disambiguateReleaseParam( balena, diff --git a/src/commands/util/available-drives.ts b/src/commands/util/available-drives.ts index d474271815..c990fc5445 100644 --- a/src/commands/util/available-drives.ts +++ b/src/commands/util/available-drives.ts @@ -16,7 +16,7 @@ */ import { Command } from '@oclif/core'; -import { stripIndent, getChalk, getVisuals } from '../../utils/lazy'; +import { stripIndent, getChalk, getVisuals } from '../../utils/lazy.js'; export default class UtilAvailableDrivesCmd extends Command { public static description = stripIndent` diff --git a/src/commands/version/index.ts b/src/commands/version/index.ts index ab2c9663e2..21578acb41 100644 --- a/src/commands/version/index.ts +++ b/src/commands/version/index.ts @@ -16,7 +16,7 @@ */ import { Flags, Command } from '@oclif/core'; -import { stripIndent } from '../../utils/lazy'; +import { stripIndent } from '../../utils/lazy.js'; export interface JsonVersions { 'balena-cli': string; @@ -68,7 +68,7 @@ export default class VersionCmd extends Command { public async run() { const { flags: options } = await this.parse(VersionCmd); const versions: JsonVersions = { - 'balena-cli': (await import('../../../package.json')).version, + 'balena-cli': (await import('../../../package.json')).default.version, 'Node.js': process.version.startsWith('v') ? process.version.slice(1) : process.version, diff --git a/src/commands/whoami/index.ts b/src/commands/whoami/index.ts index 19ff60e504..d3d600bcef 100644 --- a/src/commands/whoami/index.ts +++ b/src/commands/whoami/index.ts @@ -16,7 +16,7 @@ */ import { Command } from '@oclif/core'; -import { getBalenaSdk, getVisuals, stripIndent } from '../../utils/lazy'; +import { getBalenaSdk, getVisuals, stripIndent } from '../../utils/lazy.js'; export default class WhoamiCmd extends Command { public static description = stripIndent` diff --git a/src/deprecation.ts b/src/deprecation.ts index 7a8762bb29..6dca348623 100644 --- a/src/deprecation.ts +++ b/src/deprecation.ts @@ -16,6 +16,9 @@ */ import type { BalenaSettingsStorage } from 'balena-settings-storage'; +import Module from 'node:module'; + +const require = Module.createRequire(import.meta.url); export interface ReleaseTimestampsByVersion { [version: string]: string; // e.g. { '12.0.0': '2021-06-16T12:54:52.000Z' } @@ -106,7 +109,7 @@ export class DeprecationChecker { const url = this.getNpmUrl(version); let response: import('got').Response> | undefined; try { - response = await got(url, { + response = await got.default(url, { responseType: 'json', retry: 0, timeout: 4000, @@ -198,17 +201,16 @@ or release date not available`); const nextMajorDate = new Date(nextMajorDateStr).getTime(); const daysElapsed = Math.trunc((this.now - nextMajorDate) / this.msInDay); if (daysElapsed > this.expiryDays) { - const { ExpectedError } = await import('./errors'); + const { ExpectedError } = await import('./errors.js'); throw new ExpectedError(this.getExpiryMsg(daysElapsed)); } else if (daysElapsed > this.deprecationDays && process.stderr.isTTY) { - console.error(this.getDeprecationMsg(daysElapsed)); + console.error(await this.getDeprecationMsg(daysElapsed)); } } /** Separate function for the benefit of code testing */ - getDeprecationMsg(daysElapsed: number) { - const { warnify } = - require('./utils/messages') as typeof import('./utils/messages'); + async getDeprecationMsg(daysElapsed: number) { + const { warnify } = await import('./utils/messages.js'); return warnify(`\ CLI version ${this.nextMajorVersion} was released ${daysElapsed} days ago: please upgrade. This version of the balena CLI (${this.currentVersion}) will exit with an error diff --git a/src/errors.ts b/src/errors.ts index 228377de69..9d85e3dce5 100644 --- a/src/errors.ts +++ b/src/errors.ts @@ -15,12 +15,12 @@ limitations under the License. */ import type { BalenaError } from 'balena-errors'; -import * as _ from 'lodash'; -import * as os from 'os'; +import _ from 'lodash'; +import os from 'os'; import { TypedError } from 'typed-error'; -import { getChalk, stripIndent } from './utils/lazy'; -import { getHelp } from './utils/messages'; -import { CliSettings } from './utils/bootstrap'; +import { getChalk, stripIndent } from './utils/lazy.js'; +import { getHelp } from './utils/messages.js'; +import { CliSettings } from './utils/bootstrap.js'; export class ExpectedError extends TypedError { public code?: string; diff --git a/src/events.ts b/src/events.ts index aa6dcbed89..c5491a8bfb 100644 --- a/src/events.ts +++ b/src/events.ts @@ -15,8 +15,8 @@ * limitations under the License. */ -import * as packageJSON from '../package.json'; -import { stripIndent } from './utils/lazy'; +import { stripIndent, getPackageJson } from './utils/lazy.js'; +const packageJSON = getPackageJson(); /** * Track balena CLI usage events (product improvement analytics). @@ -44,7 +44,7 @@ export async function trackCommand(commandSignature: string) { scope.setExtra('command', commandSignature); }); } - const { getCachedUsername } = await import('./utils/bootstrap'); + const { getCachedUsername } = await import('./utils/bootstrap.js'); let username: string | undefined; try { username = (await getCachedUsername())?.username; @@ -95,7 +95,7 @@ async function sendEvent(balenaUrl: string, event: string, username?: string) { const url = `https://data.${balenaUrl}/amplitude/2/httpapi`; try { - await got.post(url, { + await got.default.post(url, { json: trackData, retry: 0, timeout: { diff --git a/src/fast-boot.ts b/src/fast-boot.ts index f178fdb6e9..6444907a7e 100644 --- a/src/fast-boot.ts +++ b/src/fast-boot.ts @@ -23,12 +23,13 @@ * from `bin/run.js`, before the CLI's entrypoint in `src/app.ts`. */ -import * as fs from 'fs'; -import * as os from 'os'; -import * as path from 'path'; - -const stat = process.pkg ? fs.statSync : fs.promises.stat; +import fs from 'fs'; +import os from 'os'; +import path from 'path'; +import Module from 'node:module'; +import { getPackageJson } from './utils/lazy.js'; +const require = Module.createRequire(import.meta.url); let fastBootStarted = false; export async function start() { @@ -67,12 +68,12 @@ async function $start() { // a regular user account. const cacheFile = path.join(dataDir, 'cli-module-cache.json'); const root = path.join(__dirname, '..'); - const [, pJson, pStat, nStat] = await Promise.all([ + const [, pStat, nStat] = await Promise.all([ ensureCanWrite(dataDir, cacheFile), - import('../package.json'), - stat(path.join(root, 'package.json'), { bigint: true }), - stat(path.join(root, 'npm-shrinkwrap.json'), { bigint: true }), + fs.promises.stat(path.join(root, 'package.json'), { bigint: true }), + fs.promises.stat(path.join(root, 'npm-shrinkwrap.json'), { bigint: true }), ]); + const pJson = getPackageJson(); // Include timestamps to account for dev-time changes to node_modules const cacheKiller = `${pJson.version}-${pStat.mtimeMs}-${nStat.mtimeMs}`; require('fast-boot2').start({ diff --git a/src/help.ts b/src/help.ts index d9df322595..e70f796e7b 100644 --- a/src/help.ts +++ b/src/help.ts @@ -16,9 +16,9 @@ */ import type { Command } from '@oclif/core'; import { Help } from '@oclif/core'; -import * as indent from 'indent-string'; -import { getChalk } from './utils/lazy'; -import type { ResolvableReturnType } from 'balena-sdk/typings/utils'; +import indent from 'indent-string'; +import { getChalk } from './utils/lazy.js'; +import type { ResolvableReturnType } from 'balena-sdk/typings/utils.js'; // Partially overrides standard implementation of help plugin // https://github.com/oclif/plugin-help/blob/master/src/index.ts @@ -44,7 +44,7 @@ export default class BalenaHelp extends Help { const subject = getHelpSubject(argv); if (!subject) { const verbose = argv.includes('-v') || argv.includes('--verbose'); - console.log(this.getCustomRootHelp(verbose)); + console.log(await this.getCustomRootHelp(verbose)); return; } @@ -83,7 +83,7 @@ export default class BalenaHelp extends Help { console.log(`command ${chalk.cyan.bold(subject)} not found`); } - getCustomRootHelp(showAllCommands: boolean): string { + async getCustomRootHelp(showAllCommands: boolean): Promise { const { bold, cyan } = getChalk(); let commands = this.config.commands; @@ -146,8 +146,9 @@ See: https://git.io/JRHUW#deprecation-policy`, ]; globalOps[0][0] = globalOps[0][0].padEnd(cmdLength); - const { deprecationPolicyNote, reachingOut } = - require('./utils/messages') as typeof import('./utils/messages'); + const { deprecationPolicyNote, reachingOut } = await import( + './utils/messages.js' + ); return [ bold('USAGE'), diff --git a/src/hooks/command-not-found/suggest.ts b/src/hooks/command-not-found/suggest.ts index 834dc00305..952bde9f5a 100644 --- a/src/hooks/command-not-found/suggest.ts +++ b/src/hooks/command-not-found/suggest.ts @@ -16,7 +16,7 @@ */ import type { Hook, Interfaces } from '@oclif/core'; -import { getChalk } from '../../utils/lazy'; +import { getChalk } from '../../utils/lazy.js'; /* A modified version of the command-not-found plugin logic, diff --git a/src/hooks/prerun.ts b/src/hooks/prerun.ts index 7aaa984ce1..97dd7d7dca 100644 --- a/src/hooks/prerun.ts +++ b/src/hooks/prerun.ts @@ -20,8 +20,8 @@ import { type Command, // ux } from '@oclif/core'; -import { InsufficientPrivilegesError } from '../errors'; -import { checkLoggedIn, checkNotUsingOfflineMode } from '../utils/patterns'; +import { InsufficientPrivilegesError } from '../errors.js'; +import { checkLoggedIn, checkNotUsingOfflineMode } from '../utils/patterns.js'; let trackResolve: (result: Promise) => void; @@ -40,7 +40,7 @@ export const trackPromise = new Promise((resolve) => { * - other code needs to execute before check */ const checkElevatedPrivileges = async () => { - const isElevated = await (await import('is-elevated'))(); + const isElevated = await (await import('is-elevated')).default(); if (!isElevated) { throw new InsufficientPrivilegesError( 'You need root/admin privileges to run this command', @@ -108,7 +108,7 @@ const hook: Hook<'prerun'> = async function (options) { } catch (error) { this.error(error); } - const events = await import('../events'); + const events = await import('../events.js'); const cmd = options.Command.id; // Intentionally do not await for the track promise here, in order to diff --git a/src/preparser.ts b/src/preparser.ts index 28857ffb1a..77f4c36f88 100644 --- a/src/preparser.ts +++ b/src/preparser.ts @@ -68,7 +68,7 @@ export async function preparseArgs(argv: string[]): Promise { process.env.BLUEBIRD_LONG_STACK_TRACES = '1'; } - const Logger = await import('./utils/logger'); + const { default: Logger } = await import('./utils/logger.js'); Logger.command = cmdSlice[0]; let args = cmdSlice; @@ -104,8 +104,8 @@ function extractBooleanFlag(argv: string[], flag: string): boolean { * Check whether the command line refers to a command that has been deprecated * and removed and, if so, exit with an informative error message. */ -export function checkDeletedCommand(argvSlice: string[]): void { - const { ExpectedError } = require('./errors') as typeof import('./errors'); +export async function checkDeletedCommand(argvSlice: string[]): Promise { + const { ExpectedError } = await import('./errors.js'); if (argvSlice[0] === 'help') { argvSlice = argvSlice.slice(1); @@ -139,7 +139,7 @@ Please use "balena ${alternative}" instead.`); // Check if this is a space separated 'topic command' style command subcommand (e.g. `end add`) // by comparing with oclif style colon-separated subcommand list (e.g. `env:add`) export async function isSubcommand(args: string[]) { - const { getCommandIdsFromManifest } = await import('./utils/oclif-utils'); + const { getCommandIdsFromManifest } = await import('./utils/oclif-utils.js'); const commandIds = await getCommandIdsFromManifest(); return commandIds.includes(`${args[0] || ''}:${args[1] || ''}`); } diff --git a/src/utils/application-create.ts b/src/utils/application-create.ts index b25acc9827..e0c9c1581f 100644 --- a/src/utils/application-create.ts +++ b/src/utils/application-create.ts @@ -1,5 +1,5 @@ -import { ExpectedError } from '../errors'; -import { getBalenaSdk } from './lazy'; +import { ExpectedError } from '../errors.js'; +import { getBalenaSdk } from './lazy.js'; export interface FlagsDef { organization?: string; @@ -17,12 +17,12 @@ export async function applicationCreateBase( ) { // Ascertain device type const deviceType = - options.type || (await (await import('./patterns')).selectDeviceType()); + options.type || (await (await import('./patterns.js')).selectDeviceType()); // Ascertain organization const organization = options.organization?.toLowerCase() || - (await (await import('./patterns')).getAndSelectOrganization()); + (await (await import('./patterns.js')).getAndSelectOrganization()); // Create application try { diff --git a/src/utils/bootstrap.ts b/src/utils/bootstrap.ts index f4a3213685..4141f172f4 100644 --- a/src/utils/bootstrap.ts +++ b/src/utils/bootstrap.ts @@ -22,6 +22,9 @@ * like Sentry error reporting, preparser, oclif parser and the like. */ +import Module from 'node:module'; +const require = Module.createRequire(import.meta.url); + export class CliSettings { public readonly settings: any; constructor() { @@ -102,7 +105,7 @@ export async function getCachedUsername(): Promise { return cachedUsername; } const [{ getBalenaSdk }, { getStorage }, settings] = await Promise.all([ - import('./lazy'), + import('./lazy.js'), import('balena-settings-storage'), import('balena-settings-client'), ]); diff --git a/src/utils/cloud.ts b/src/utils/cloud.ts index ed01169bc5..f64f76e38b 100644 --- a/src/utils/cloud.ts +++ b/src/utils/cloud.ts @@ -16,10 +16,10 @@ */ import type * as SDK from 'balena-sdk'; -import * as _ from 'lodash'; -import { getBalenaSdk, getCliForm, getVisuals, stripIndent } from './lazy'; +import _ from 'lodash'; +import { getBalenaSdk, getCliForm, getVisuals, stripIndent } from './lazy.js'; -import { ExpectedError } from '../errors'; +import { ExpectedError } from '../errors.js'; export const serviceIdToName = _.memoize( async ( @@ -145,7 +145,7 @@ export async function downloadOSImage( // some ongoing issues with the os download stream. process.env.ZLIB_FLUSH = 'Z_NO_FLUSH'; - const { getStream } = await import('./image-manager'); + const { getStream } = await import('./image-manager.js'); const stream = await getStream(deviceType, OSVersion); const displayVersion = await new Promise((resolve, reject) => { @@ -205,7 +205,7 @@ async function resolveOSVersion( false, ); } - const { normalizeOsVersion } = await import('./normalization'); + const { normalizeOsVersion } = await import('./normalization.js'); version = normalizeOsVersion(version); return version; } diff --git a/src/utils/common-args.ts b/src/utils/common-args.ts index 74ae9baa2e..040541eb60 100644 --- a/src/utils/common-args.ts +++ b/src/utils/common-args.ts @@ -15,7 +15,7 @@ * limitations under the License. */ import { Args } from '@oclif/core'; -import { lowercaseIfSlug } from './normalization'; +import { lowercaseIfSlug } from './normalization.js'; export const fleetRequired = Args.string({ description: 'fleet name or slug (preferred)', diff --git a/src/utils/common-flags.ts b/src/utils/common-flags.ts index ba84db1390..c049a40d62 100644 --- a/src/utils/common-flags.ts +++ b/src/utils/common-flags.ts @@ -16,8 +16,8 @@ */ import { Flags } from '@oclif/core'; -import { stripIndent } from './lazy'; -import { lowercaseIfSlug } from './normalization'; +import { stripIndent } from './lazy.js'; +import { lowercaseIfSlug } from './normalization.js'; export const fleet = Flags.string({ char: 'f', @@ -25,11 +25,26 @@ export const fleet = Flags.string({ parse: lowercaseIfSlug, }); +export const fleetExclusive = (exclusive: string[]) => + Flags.string({ + char: 'f', + description: 'fleet name or slug (preferred)', + parse: lowercaseIfSlug, + exclusive, + }); + export const device = Flags.string({ char: 'd', description: 'device UUID', }); +export const deviceExclusive = (exclusive: string[]) => + Flags.string({ + char: 'd', + description: 'device UUID', + exclusive, + }); + export const quiet = Flags.boolean({ char: 'q', description: 'suppress warning messages', @@ -41,11 +56,25 @@ export const release = Flags.string({ description: 'release id', }); +export const releaseExclusive = (exclusive: string[]) => + Flags.string({ + char: 'r', + description: 'release id', + exclusive, + }); + export const service = Flags.string({ char: 's', description: 'service name', }); +export const serviceExclusive = (exclusive: string[]) => + Flags.string({ + char: 's', + description: 'service name', + exclusive, + }); + export const verbose = Flags.boolean({ char: 'v', description: 'produce verbose output', diff --git a/src/utils/compose.ts b/src/utils/compose.ts index 1d1f5837bc..fb306f7e83 100644 --- a/src/utils/compose.ts +++ b/src/utils/compose.ts @@ -15,10 +15,10 @@ * limitations under the License. */ -import type { Renderer } from './compose_ts'; +import type { Renderer } from './compose_ts.js'; import type * as SDK from 'balena-sdk'; import type Dockerode = require('dockerode'); -import * as path from 'path'; +import path from 'path'; import type { Composition, ImageDescriptor } from '@balena/compose/dist/parse'; import type { RetryParametersObj } from 'pinejs-client-core'; import type { @@ -27,10 +27,13 @@ import type { ComposeProject, Release, TaggedImage, -} from './compose-types'; -import { getChalk } from './lazy'; -import Logger = require('./logger'); +} from './compose-types.js'; +import { getChalk } from './lazy.js'; +import type Logger from './logger.js'; import type { ProgressCallback } from 'docker-progress'; +import type { ReleaseModel } from '@balena/compose/dist/release/models.js'; +import Module from 'node:module'; +const require = Module.createRequire(import.meta.url); export function generateOpts(options: { source?: string; @@ -57,21 +60,21 @@ export function generateOpts(options: { * - composePath: the *absolute* path to the directory containing the compose file * - composeStr: the contents of the compose file, as a string */ -export function createProject( +export async function createProject( composePath: string, composeStr: string, projectName = '', imageTag = '', -): ComposeProject { - const yml = require('js-yaml') as typeof import('js-yaml'); - const compose = - require('@balena/compose/dist/parse') as typeof import('@balena/compose/dist/parse'); +): Promise { + const yml = await import('js-yaml'); + const compose = await import('@balena/compose/dist/parse'); // both methods below may throw. const rawComposition = yml.load(composeStr); const composition = compose.normalize(rawComposition); projectName ||= path.basename(composePath); + const { makeImageName } = await import('./compose_ts.js'); const descriptors = compose.parse(composition).map(function (descr) { // generate an image name based on the project and service names @@ -81,8 +84,6 @@ export function createProject( descr.image.context != null && descr.image.tag == null ) { - const { makeImageName } = - require('./compose_ts') as typeof import('./compose_ts'); descr.image.tag = makeImageName(projectName, descr.serviceName, imageTag); } return descr; @@ -127,7 +128,7 @@ export const createRelease = async function ( composition: Composition, draft: boolean, semver: string | undefined, - contract: import('@balena/compose/dist/release/models').ReleaseModel['contract'], + contract: ReleaseModel['contract'], ): Promise { const _ = require('lodash') as typeof import('lodash'); const crypto = require('crypto') as typeof import('crypto'); @@ -328,7 +329,7 @@ const renderProgressBar = function (percentage: number, stepCount: number) { }; export const pushProgressRenderer = function ( - tty: ReturnType, + tty: ReturnType, prefix: string, ): ProgressCallback & { end: () => void } { const fn: ProgressCallback & { end: () => void } = function (e) { @@ -362,14 +363,14 @@ export class BuildProgressUI implements Renderer { private _spinner; private _runloop: | undefined - | ReturnType; + | ReturnType; // these are to handle window wrapping private _maxLineWidth: undefined | number; private _lineWidths: number[] = []; constructor( - tty: ReturnType, + tty: ReturnType, descriptors: ImageDescriptor[], ) { this._handleEvent = this._handleEvent.bind(this); @@ -410,7 +411,7 @@ export class BuildProgressUI implements Renderer { this._ended = false; this._cancelled = false; this._spinner = ( - require('./compose_ts') as typeof import('./compose_ts') + require('./compose_ts.js') as typeof import('./compose_ts.js') ).createSpinner(); this.streams = streams; @@ -429,7 +430,7 @@ export class BuildProgressUI implements Renderer { this.streams[service].write({ status: 'Preparing...' }); }); this._runloop = ( - require('./compose_ts') as typeof import('./compose_ts') + require('./compose_ts') as typeof import('./compose_ts.js') ).createRunLoop(this._display); this._startTime = Date.now(); } diff --git a/src/utils/compose_ts.ts b/src/utils/compose_ts.ts index f9ba94035a..173566f90e 100644 --- a/src/utils/compose_ts.ts +++ b/src/utils/compose_ts.ts @@ -16,33 +16,31 @@ */ import { Flags } from '@oclif/core'; import type { BalenaSDK } from 'balena-sdk'; -import type { TransposeOptions } from '@balena/compose/dist/emulate'; import type * as Dockerode from 'dockerode'; import { promises as fs } from 'fs'; import * as yaml from 'js-yaml'; -import * as _ from 'lodash'; -import * as path from 'path'; +import _ from 'lodash'; +import path from 'path'; +import type { emulate, multibuild as MultiBuild, parse } from '@balena/compose'; import type { - BuildConfig, - Composition, - ImageDescriptor, -} from '@balena/compose/dist/parse'; -import type * as MultiBuild from '@balena/compose/dist/multibuild'; + ImageModel, + ReleaseModel, +} from '@balena/compose/dist/release/models.js'; import * as semver from 'semver'; import type { Duplex, Readable } from 'stream'; import type { Pack } from 'tar-stream'; -import { ExpectedError } from '../errors'; +import { ExpectedError } from '../errors.js'; import type { BuiltImage, ComposeOpts, ComposeProject, TaggedImage, TarDirectoryOptions, -} from './compose-types'; -import type { DeviceInfo } from './device/api'; -import { getBalenaSdk, getChalk, stripIndent } from './lazy'; -import Logger = require('./logger'); -import { exists } from './which'; +} from './compose-types.js'; +import type { DeviceInfo } from './device/api.js'; +import { getBalenaSdk, getChalk, stripIndent } from './lazy.js'; +import Logger from './logger.js'; +import { exists } from './which.js'; const allowedContractTypes = ['sw.application', 'sw.block']; @@ -117,7 +115,7 @@ export async function loadProject( imageTag?: string, ): Promise { const compose = await import('@balena/compose/dist/parse'); - const { createProject } = await import('./compose'); + const { createProject } = await import('./compose.js'); let composeName: string; let composeStr: string; @@ -153,7 +151,7 @@ export async function loadProject( } } logger.logDebug('Creating project...'); - return createProject( + return await createProject( opts.projectPath, composeStr, opts.projectName, @@ -244,11 +242,11 @@ export interface BuildProjectOpts { logger: Logger; projectPath: string; projectName: string; - composition: Composition; + composition: parse.Composition; arch: string; deviceType: string; emulated: boolean; - buildOpts: import('./docker').BuildOpts; + buildOpts: import('./docker.js').BuildOpts; inlineLogs?: boolean; convertEol: boolean; dockerfilePath?: string; @@ -264,7 +262,7 @@ export async function buildProject( const renderer = await startRenderer({ imageDescriptors, ...opts }); let buildSummaryByService: Dictionary | undefined; try { - const { awaitInterruptibleTask } = await import('./helpers'); + const { awaitInterruptibleTask } = await import('./helpers.js'); const [images, summaryMsgByService] = await awaitInterruptibleTask( $buildProject, imageDescriptors, @@ -279,7 +277,7 @@ export async function buildProject( } async function $buildProject( - imageDescriptors: ImageDescriptor[], + imageDescriptors: parse.ImageDescriptor[], renderer: Renderer, opts: BuildProjectOpts, ): Promise<[BuiltImage[], Dictionary]> { @@ -305,7 +303,7 @@ async function $buildProject( setTaskAttributes({ tasks, imageDescriptorsByServiceName, ...opts }); - const transposeOptArray: Array = + const transposeOptArray: Array = await Promise.all( tasks.map((task) => { // Setup emulation if needed @@ -329,7 +327,7 @@ async function $buildProject( logger.logDebug('Prepared tasks; building...'); - const { BALENA_ENGINE_TMP_PATH } = await import('../config'); + const { BALENA_ENGINE_TMP_PATH } = await import('../config.js'); const builder = await import('@balena/compose/dist/multibuild'); const builtImages = await builder.performBuilds( @@ -351,19 +349,19 @@ async function startRenderer({ inlineLogs, logger, }: { - imageDescriptors: ImageDescriptor[]; + imageDescriptors: parse.ImageDescriptor[]; inlineLogs?: boolean; logger: Logger; }): Promise { let renderer: Renderer; if (inlineLogs) { - renderer = new (await import('./compose')).BuildProgressInline( + renderer = new (await import('./compose.js')).BuildProgressInline( logger.streams['build'], imageDescriptors, ); } else { - const tty = (await import('./tty'))(process.stdout); - renderer = new (await import('./compose')).BuildProgressUI( + const tty = (await import('./tty.js')).default(process.stdout); + renderer = new (await import('./compose.js')).BuildProgressUI( tty, imageDescriptors, ); @@ -383,11 +381,11 @@ async function installQemuIfNeeded({ arch: string; docker: Dockerode; emulated: boolean; - imageDescriptors: ImageDescriptor[]; + imageDescriptors: parse.ImageDescriptor[]; logger: Logger; projectPath: string; }): Promise { - const qemu = await import('./qemu'); + const qemu = await import('./qemu.js'); const needsQemu = await qemu.installQemuIfNeeded( emulated, logger, @@ -430,8 +428,8 @@ function setTaskAttributes({ projectName, }: { tasks: BuildTaskPlus[]; - buildOpts: import('./docker').BuildOpts; - imageDescriptorsByServiceName: Dictionary; + buildOpts: import('./docker.js').BuildOpts; + imageDescriptorsByServiceName: Dictionary; projectName: string; }) { for (const task of tasks) { @@ -469,8 +467,8 @@ async function qemuTransposeBuildStream({ task: BuildTaskPlus; dockerfilePath?: string; projectPath: string; -}): Promise { - const qemu = await import('./qemu'); +}): Promise { + const qemu = await import('./qemu.js'); const binPath = qemu.qemuPathInContext( path.join(projectPath, task.context ?? ''), ); @@ -482,7 +480,7 @@ async function qemuTransposeBuildStream({ const { toPosixPath } = (await import('@balena/compose/dist/multibuild')) .PathUtils; - const transposeOptions: TransposeOptions = { + const transposeOptions: emulate.TransposeOptions = { hostQemuPath: toPosixPath(binPath), containerQemuPath: `/tmp/${qemu.QEMU_BIN_NAME}`, qemuFileMode: 0o555, @@ -550,7 +548,7 @@ async function inspectBuiltImages({ }: { builtImages: MultiBuild.LocalImage[]; docker: Dockerode; - imageDescriptorsByServiceName: Dictionary; + imageDescriptorsByServiceName: Dictionary; tasks: BuildTaskPlus[]; }): Promise<[BuiltImage[], Dictionary]> { const images: BuiltImage[] = await Promise.all( @@ -583,7 +581,7 @@ async function inspectBuiltImage({ }: { builtImage: MultiBuild.LocalImage; docker: Dockerode; - imageDescriptorsByServiceName: Dictionary; + imageDescriptorsByServiceName: Dictionary; tasks: BuildTaskPlus[]; }): Promise { if (!builtImage.successful) { @@ -678,9 +676,9 @@ async function loadBuildMetatada( */ export async function getServiceDirsFromComposition( sourceDir: string, - composition?: Composition, + composition?: parse.Composition, ): Promise> { - const { createProject } = await import('./compose'); + const { createProject } = await import('./compose.js'); const serviceDirs: Dictionary = {}; if (!composition) { const [, composeStr] = await resolveProject( @@ -689,7 +687,7 @@ export async function getServiceDirsFromComposition( true, ); if (composeStr) { - composition = createProject(sourceDir, composeStr).composition; + composition = (await createProject(sourceDir, composeStr)).composition; } } if (composition?.services) { @@ -698,7 +696,7 @@ export async function getServiceDirsFromComposition( let dir = (typeof service.build === 'string' ? service.build - : service.build?.context) || '.'; + : service.build?.context) || './index.js'; // Convert forward slashes to backslashes on Windows dir = path.normalize(dir); // Make sure the path is relative to the project directory @@ -710,7 +708,7 @@ export async function getServiceDirsFromComposition( // remove './' prefix (or '.\\' on Windows) dir = dir.startsWith(relPrefix) ? dir.slice(2) : dir; - serviceDirs[serviceName] = dir || '.'; + serviceDirs[serviceName] = dir || './index.js'; } } return serviceDirs; @@ -734,8 +732,8 @@ export async function getServiceDirsFromComposition( * @param image The `ImageDescriptor.image` attribute parsed with `@balena/compose/parse` */ export function isBuildConfig( - image: string | BuildConfig, -): image is BuildConfig { + image: string | parse.BuildConfig, +): image is parse.BuildConfig { return image != null && typeof image !== 'string'; } @@ -756,7 +754,7 @@ export async function tarDirectory( preFinalizeCallback, }: TarDirectoryOptions, ): Promise { - const { filterFilesWithDockerignore } = await import('./ignore'); + const { filterFilesWithDockerignore } = await import('./ignore.js'); const { toPosixPath } = (await import('@balena/compose/dist/multibuild')) .PathUtils; @@ -772,7 +770,11 @@ export async function tarDirectory( const serviceDirs = await getServiceDirsFromComposition(dir, composition); const { filteredFileList, dockerignoreFiles } = await filterFilesWithDockerignore(dir, multiDockerignore, serviceDirs); - printDockerignoreWarn(dockerignoreFiles, serviceDirs, multiDockerignore); + await printDockerignoreWarn( + dockerignoreFiles, + serviceDirs, + multiDockerignore, + ); for (const fileStats of filteredFileList) { pack.entry( { @@ -798,21 +800,21 @@ export async function tarDirectory( * @param serviceDirsByService Map of service names to service subdirectories * @param multiDockerignore Whether --multi-dockerignore (-m) was provided */ -function printDockerignoreWarn( - dockerignoreFiles: Array, +async function printDockerignoreWarn( + dockerignoreFiles: Array, serviceDirsByService: Dictionary, multiDockerignore: boolean, ) { - let rootDockerignore: import('./ignore').FileStats | undefined; + let rootDockerignore: import('./ignore.js').FileStats | undefined; const logger = Logger.getLogger(); const relPrefix = '.' + path.sep; const serviceDirs = Object.values(serviceDirsByService || {}); // compute a list of unused .dockerignore files const unusedFiles = dockerignoreFiles.filter( - (dockerignoreStats: import('./ignore').FileStats) => { + (dockerignoreStats: import('./ignore.js').FileStats) => { let dirname = path.dirname(dockerignoreStats.relPath); dirname = dirname.startsWith(relPrefix) ? dirname.slice(2) : dirname; - const isProjectRootDir = !dirname || dirname === '.'; + const isProjectRootDir = !dirname || dirname === './index.js'; if (isProjectRootDir) { rootDockerignore = dockerignoreStats; return false; // a root .dockerignore file is always used @@ -872,7 +874,7 @@ function printDockerignoreWarn( } } if (msg.length) { - const { warnify } = require('./messages') as typeof import('./messages'); + const { warnify } = await import('./messages.js'); logFunc.call(logger, ' \n' + warnify(msg.join('\n'), '')); } } @@ -890,7 +892,7 @@ export async function checkBuildSecretsRequirements( ) { const [metaObj, metaFilename] = await loadBuildMetatada(sourceDir); if (metaObj && !_.isEmpty(metaObj['build-secrets'])) { - const dockerUtils = await import('./docker'); + const dockerUtils = await import('./docker.js'); const isBalenaEngine = await dockerUtils.isBalenaEngine(docker); if (!isBalenaEngine) { throw new ExpectedError(stripIndent` @@ -961,7 +963,7 @@ async function parseRegistrySecrets( * Both `balena build` and `balena deploy` call this function. */ export async function makeBuildTasks( - composition: Composition, + composition: parse.Composition, tarStream: Readable, deviceInfo: DeviceInfo, logger: Logger, @@ -1221,7 +1223,7 @@ async function getTokenForPreviousRepos( taggedImages: TaggedImage[], ): Promise { logger.logDebug('Authorizing push...'); - const { authorizePush, getPreviousRepos } = await import('./compose'); + const { authorizePush, getPreviousRepos } = await import('./compose.js'); const sdk = getBalenaSdk(); const previousRepos = await getPreviousRepos(sdk, logger, appId); @@ -1239,15 +1241,12 @@ async function pushAndUpdateServiceImages( docker: Dockerode, token: string, images: TaggedImage[], - afterEach: ( - serviceImage: import('@balena/compose/dist/release/models').ImageModel, - props: object, - ) => Promise, + afterEach: (serviceImage: ImageModel, props: object) => Promise, ) { const { DockerProgress } = await import('docker-progress'); - const { retry } = await import('./helpers'); - const { pushProgressRenderer } = await import('./compose'); - const tty = (await import('./tty'))(process.stdout); + const { retry } = await import('./helpers.js'); + const { pushProgressRenderer } = await import('./compose.js'); + const tty = (await import('./tty.js')).default(process.stdout); const opts = { authconfig: { registrytoken: token } }; const progress = new DockerProgress({ docker }); const renderer = pushProgressRenderer( @@ -1369,16 +1368,16 @@ export async function deployProject( docker: Dockerode, sdk: BalenaSDK, logger: Logger, - composition: Composition, + composition: parse.Composition, images: BuiltImage[], appId: number, skipLogUpload: boolean, projectPath: string, isDraft: boolean, -): Promise { +): Promise { const releaseMod = await import('@balena/compose/dist/release'); - const { createRelease, tagServiceImages } = await import('./compose'); - const tty = (await import('./tty'))(process.stdout); + const { createRelease, tagServiceImages } = await import('./compose.js'); + const tty = (await import('./tty.js')).default(process.stdout); const prefix = getChalk().cyan('[Info]') + ' '; const spinner = createSpinner(); @@ -1413,7 +1412,7 @@ export async function deployProject( logger.logDebug('Tagging images...'); const taggedImages = await tagServiceImages(docker, images, serviceImages); try { - const { awaitInterruptibleTask } = await import('./helpers'); + const { awaitInterruptibleTask } = await import('./helpers.js'); // awaitInterruptibleTask throws SIGINTError on CTRL-C, // causing the release status to be set to 'failed' await awaitInterruptibleTask(async () => { @@ -1463,7 +1462,7 @@ export function createSpinner() { } async function runSpinner( - tty: ReturnType, + tty: ReturnType, spinner: () => string, msg: string, fn: () => Promise, @@ -1500,9 +1499,7 @@ export function createRunLoop(tick: (...args: any[]) => void) { async function getContractContent( filePath: string, -): Promise< - import('@balena/compose/dist/release/models').ReleaseModel['contract'] -> { +): Promise { let fileContentAsString; try { fileContentAsString = await fs.readFile(filePath, 'utf8'); diff --git a/src/utils/config.ts b/src/utils/config.ts index 28f57c5248..930ca1088a 100644 --- a/src/utils/config.ts +++ b/src/utils/config.ts @@ -15,7 +15,7 @@ limitations under the License. */ import type * as BalenaSdk from 'balena-sdk'; import * as semver from 'balena-semver'; -import { getBalenaSdk, stripIndent } from './lazy'; +import { getBalenaSdk, stripIndent } from './lazy.js'; export interface ImgConfig { applicationName: string; @@ -155,19 +155,19 @@ export function generateDeviceConfig( export async function validateDevOptionAndWarn( dev?: boolean, version?: string, - logger?: import('./logger'), + logger?: import('./logger.js').default, ) { if (!dev) { return; } if (version && /\bprod\b/.test(version)) { - const { ExpectedError } = await import('../errors'); + const { ExpectedError } = await import('../errors.js'); throw new ExpectedError( `Error: The '--dev' option conflicts with production balenaOS version '${version}'`, ); } if (!logger) { - const Logger = await import('./logger'); + const { default: Logger } = await import('./logger.js'); logger = Logger.getLogger(); } logger.logInfo(stripIndent` @@ -187,12 +187,12 @@ export async function validateSecureBootOptionAndWarn( secureBoot: boolean, slug: string, version: string, - logger?: import('./logger'), + logger?: import('./logger.js').default, ) { if (!secureBoot) { return; } - const { ExpectedError } = await import('../errors'); + const { ExpectedError } = await import('../errors.js'); if (!version) { throw new ExpectedError(`Error: No version provided`); } @@ -214,7 +214,7 @@ export async function validateSecureBootOptionAndWarn( }) ) { if (!logger) { - const Logger = await import('./logger'); + const { default: Logger } = await import('./logger.js'); logger = Logger.getLogger(); } logger.logInfo(stripIndent` diff --git a/src/utils/deploy-legacy.ts b/src/utils/deploy-legacy.ts index 2087a1410e..27c0854255 100644 --- a/src/utils/deploy-legacy.ts +++ b/src/utils/deploy-legacy.ts @@ -15,29 +15,29 @@ * limitations under the License. */ -import { getVisuals } from './lazy'; +import { getVisuals } from './lazy.js'; import { promisify } from 'util'; import type * as Dockerode from 'dockerode'; -import type Logger = require('./logger'); +import type Logger from './logger.js'; import type { Request } from 'request'; -const getBuilderPushEndpoint = function ( +const getBuilderPushEndpoint = async function ( baseUrl: string, owner: string, app: string, ) { - const querystring = require('querystring') as typeof import('querystring'); + const querystring = await import('querystring'); const args = querystring.stringify({ owner, app }); return `https://builder.${baseUrl}/v1/push?${args}`; }; -const getBuilderLogPushEndpoint = function ( +const getBuilderLogPushEndpoint = async function ( baseUrl: string, buildId: number, owner: string, app: string, ) { - const querystring = require('querystring') as typeof import('querystring'); + const querystring = await import('querystring'); const args = querystring.stringify({ owner, app, buildId }); return `https://builder.${baseUrl}/v1/pushLogs?${args}`; }; @@ -47,12 +47,12 @@ const getBuilderLogPushEndpoint = function ( * @param {string} imageId * @param {string} bufferFile */ -const bufferImage = function ( +const bufferImage = async function ( docker: Dockerode, imageId: string, bufferFile: string, ): Promise { - const streamUtils = require('./streams') as typeof import('./streams'); + const streamUtils = await import('./streams.js'); const image = docker.getImage(imageId); const sizePromise = image.inspect().then((img) => img.Size); @@ -109,7 +109,7 @@ const uploadToPromise = (uploadRequest: Request, logger: Logger) => /** * @returns {Promise<{ buildId: number }>} */ -const uploadImage = function ( +const uploadImage = async function ( imageStream: NodeJS.ReadableStream & { length: number }, token: string, username: string, @@ -117,10 +117,9 @@ const uploadImage = function ( appName: string, logger: Logger, ): Promise<{ buildId: number }> { - const request = require('request') as typeof import('request'); - const progressStream = - require('progress-stream') as typeof import('progress-stream'); - const zlib = require('zlib') as typeof import('zlib'); + const request = await import('request'); + const { default: progressStream } = await import('progress-stream'); + const { default: zlib } = await import('zlib'); // Need to strip off the newline const progressMessage = logger @@ -142,7 +141,7 @@ const uploadImage = function ( ); const uploadRequest = request.post({ - url: getBuilderPushEndpoint(url, username, appName), + url: await getBuilderPushEndpoint(url, username, appName), headers: { 'Content-Encoding': 'gzip', }, @@ -159,7 +158,7 @@ const uploadImage = function ( return uploadToPromise(uploadRequest, logger); }; -const uploadLogs = function ( +const uploadLogs = async function ( logs: string, token: string, url: string, @@ -167,10 +166,10 @@ const uploadLogs = function ( username: string, appName: string, ) { - const request = require('request') as typeof import('request'); + const request = await import('request'); return request.post({ json: true, - url: getBuilderLogPushEndpoint(url, buildId, username, appName), + url: await getBuilderLogPushEndpoint(url, buildId, username, appName), auth: { bearer: token, }, @@ -196,7 +195,7 @@ export const deployLegacy = async function ( shouldUploadLogs: boolean; }, ): Promise { - const tmp = require('tmp') as typeof import('tmp'); + const tmp = await import('tmp'); const tmpNameAsync = promisify(tmp.tmpName); // Ensure the tmp files gets deleted @@ -208,6 +207,7 @@ export const deployLegacy = async function ( const bufferFile = await tmpNameAsync(); logger.logInfo('Initializing deploy...'); + const fs = await import('fs'); const { buildId } = await bufferImage(docker, imageName, bufferFile) .then((stream) => uploadImage(stream, token, username, url, appName, logger), @@ -217,9 +217,7 @@ export const deployLegacy = async function ( // has occured before any data was written) this call will throw an // ugly error, just suppress it - (require('fs') as typeof import('fs')).promises - .unlink(bufferFile) - .catch(() => undefined), + fs.promises.unlink(bufferFile).catch(() => undefined), ); if (shouldUploadLogs) { @@ -232,7 +230,7 @@ export const deployLegacy = async function ( username, appName, ]); - uploadLogs(...args); + await uploadLogs(...args); } return buildId; diff --git a/src/utils/device/api.ts b/src/utils/device/api.ts index b60ce7a395..70e392448d 100644 --- a/src/utils/device/api.ts +++ b/src/utils/device/api.ts @@ -14,13 +14,13 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import * as _ from 'lodash'; -import * as request from 'request'; +import _ from 'lodash'; +import request from 'request'; import type * as Stream from 'stream'; -import { retry } from '../helpers'; -import Logger = require('../logger'); -import * as ApiErrors from './errors'; +import { retry } from '../helpers.js'; +import type Logger from '../logger.js'; +import * as ApiErrors from './errors.js'; export interface DeviceResponse { [key: string]: any; diff --git a/src/utils/device/deploy.ts b/src/utils/device/deploy.ts index 63b323afc5..8ef3cbf581 100644 --- a/src/utils/device/deploy.ts +++ b/src/utils/device/deploy.ts @@ -15,9 +15,9 @@ * limitations under the License. */ -import * as semver from 'balena-semver'; -import * as Docker from 'dockerode'; -import * as _ from 'lodash'; +import semver from 'balena-semver'; +import Docker from 'dockerode'; +import _ from 'lodash'; import type { Composition } from '@balena/compose/dist/parse'; import type { BuildTask, @@ -27,22 +27,22 @@ import type { import { getAuthConfigObj } from '@balena/compose/dist/multibuild'; import type { Readable } from 'stream'; -import { BALENA_ENGINE_TMP_PATH } from '../../config'; -import { ExpectedError } from '../../errors'; +import { BALENA_ENGINE_TMP_PATH } from '../../config.js'; +import { ExpectedError } from '../../errors.js'; import { checkBuildSecretsRequirements, loadProject, makeBuildTasks, tarDirectory, makeImageName, -} from '../compose_ts'; -import Logger = require('../logger'); -import type { DeviceInfo } from './api'; -import { DeviceAPI } from './api'; -import * as LocalPushErrors from './errors'; -import LivepushManager from './live'; -import { displayBuildLog } from './logs'; -import { stripIndent } from '../lazy'; +} from '../compose_ts.js'; +import Logger from '../logger.js'; +import type { DeviceInfo } from './api.js'; +import { DeviceAPI } from './api.js'; +import * as LocalPushErrors from './errors.js'; +import LivepushManager from './live.js'; +import { displayBuildLog } from './logs.js'; +import { stripIndent } from '../lazy.js'; const LOCAL_APPNAME = 'localapp'; const LOCAL_RELEASEHASH = '10ca12e1ea5e'; @@ -212,7 +212,7 @@ export async function deployToDevice(opts: DeviceDeployOptions): Promise { imageIds = {}; } - const { awaitInterruptibleTask } = await import('../helpers'); + const { awaitInterruptibleTask } = await import('../helpers.js'); const buildTasks = await awaitInterruptibleTask( performBuilds, project.composition, @@ -292,7 +292,7 @@ async function streamDeviceLogs( return; } globalLogger.logInfo('Streaming device logs...'); - const { connectAndDisplayDeviceLogs } = await import('./logs'); + const { connectAndDisplayDeviceLogs } = await import('./logs.js'); return connectAndDisplayDeviceLogs({ deviceApi, logger: globalLogger, diff --git a/src/utils/device/errors.ts b/src/utils/device/errors.ts index 5455a803bf..5f3668a435 100644 --- a/src/utils/device/errors.ts +++ b/src/utils/device/errors.ts @@ -14,9 +14,9 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import * as _ from 'lodash'; +import _ from 'lodash'; -import { ExpectedError } from '../../errors'; +import { ExpectedError } from '../../errors.js'; export interface BuildFailure { error: Error; diff --git a/src/utils/device/live.ts b/src/utils/device/live.ts index 1d607dd1fc..c89cd48c95 100644 --- a/src/utils/device/live.ts +++ b/src/utils/device/live.ts @@ -15,26 +15,25 @@ * limitations under the License. */ -import * as chokidar from 'chokidar'; -import type * as Dockerode from 'dockerode'; -import * as fs from 'fs'; -import Livepush, { ContainerNotRunningError } from 'livepush'; -import * as _ from 'lodash'; -import * as path from 'path'; +import chokidar from 'chokidar'; +import type Dockerode from 'dockerode'; +import fs from 'fs'; +import { Dockerfile, ContainerNotRunningError, Livepush } from 'livepush'; +import _ from 'lodash'; +import path from 'path'; import type { Composition } from '@balena/compose/dist/parse'; import type { BuildTask } from '@balena/compose/dist/multibuild'; -import { instanceOf } from '../../errors'; -import Logger = require('../logger'); +import { instanceOf } from '../../errors.js'; +import type Logger from '../logger.js'; -import { Dockerfile } from 'livepush'; -import type DeviceAPI from './api'; -import type { DeviceInfo, Status } from './api'; -import type { DeviceDeployOptions } from './deploy'; -import { generateTargetState, rebuildSingleTask } from './deploy'; -import { BuildError } from './errors'; -import { getServiceColourFn } from './logs'; -import { delay } from '../helpers'; +import type DeviceAPI from './api.js'; +import type { DeviceInfo, Status } from './api.js'; +import type { DeviceDeployOptions } from './deploy.js'; +import { generateTargetState, rebuildSingleTask } from './deploy.js'; +import { BuildError } from './errors.js'; +import { getServiceColourFn } from './logs.js'; +import { delay } from '../helpers.js'; // How often do we want to check the device state // engine has settled (delay in ms) @@ -108,8 +107,8 @@ export class LivepushManager { this.logger.logLivepush('Device state settled'); // Prepare dockerignore data for file watcher - const { getDockerignoreByService } = await import('../ignore'); - const { getServiceDirsFromComposition } = await import('../compose_ts'); + const { getDockerignoreByService } = await import('../ignore.js'); + const { getServiceDirsFromComposition } = await import('../compose_ts.js'); const rootContext = path.resolve(this.buildContext); const serviceDirsByService = await getServiceDirsFromComposition( this.deployOpts.source, diff --git a/src/utils/device/logs.ts b/src/utils/device/logs.ts index 267ba1f4c1..c3e6590711 100644 --- a/src/utils/device/logs.ts +++ b/src/utils/device/logs.ts @@ -15,12 +15,12 @@ * limitations under the License. */ import ColorHash = require('color-hash'); -import * as _ from 'lodash'; +import _ from 'lodash'; import type { Readable } from 'stream'; -import { getChalk } from '../lazy'; -import Logger = require('../logger'); -import { ExpectedError, SIGINTError } from '../../errors'; +import { getChalk } from '../lazy.js'; +import type Logger from '../logger.js'; +import { ExpectedError, SIGINTError } from '../../errors.js'; class DeviceConnectionLostError extends ExpectedError { public static defaultMsg = 'Connection to device lost'; @@ -62,7 +62,7 @@ async function displayDeviceLogs( system: boolean, filterServices?: string[], ): Promise { - const { addSIGINTHandler } = await import('../helpers'); + const { addSIGINTHandler } = await import('../helpers.js'); const { parse: ndjsonParse } = await import('ndjson'); let gotSignal = false; const handleSignal = () => { @@ -113,7 +113,7 @@ export async function connectAndDisplayDeviceLogs({ filterServices, maxAttempts = 3, }: { - deviceApi: import('./api').DeviceAPI; + deviceApi: import('./api.js').DeviceAPI; logger: Logger; system: boolean; filterServices?: string[]; @@ -125,7 +125,7 @@ export async function connectAndDisplayDeviceLogs({ return displayDeviceLogs(logStream, logger, system, filterServices); } - const { retry } = await import('../../utils/helpers'); + const { retry } = await import('../../utils/helpers.js'); try { await retry({ func: connectAndDisplay, diff --git a/src/utils/device/ssh.ts b/src/utils/device/ssh.ts index 6caff7cb47..e5814f10a7 100644 --- a/src/utils/device/ssh.ts +++ b/src/utils/device/ssh.ts @@ -14,15 +14,15 @@ See the License for the specific language governing permissions and limitations under the License. */ -import { ExpectedError } from '../../errors'; -import { stripIndent } from '../lazy'; +import { ExpectedError } from '../../errors.js'; +import { stripIndent } from '../lazy.js'; -import type { SshRemoteCommandOpts } from '../ssh'; +import type { SshRemoteCommandOpts } from '../ssh.js'; import { findBestUsernameForDevice, getRemoteCommandOutput, runRemoteCommand, -} from '../ssh'; +} from '../ssh.js'; export interface DeviceSSHOpts extends SshRemoteCommandOpts { forceTTY?: boolean; diff --git a/src/utils/discover.ts b/src/utils/discover.ts index 813a5cf410..d29c38501f 100644 --- a/src/utils/discover.ts +++ b/src/utils/discover.ts @@ -1,6 +1,6 @@ -import Bonjour from 'bonjour-service'; +import { Bonjour } from 'bonjour-service'; import type { Service } from 'bonjour-service'; -import * as os from 'os'; +import os from 'os'; interface LocalBalenaOsDevice { address: string; @@ -67,7 +67,7 @@ async function searchBalenaDevicesOnInterface( bind: '0.0.0.0', }, async (err: string | Error) => { - await (await import('../errors')).handleError(err); + await (await import('../errors.js')).handleError(err); }, ); const resinSshServices: Service[] = []; diff --git a/src/utils/docker.ts b/src/utils/docker.ts index 4dedf8515a..ef8cc1b70f 100644 --- a/src/utils/docker.ts +++ b/src/utils/docker.ts @@ -18,8 +18,8 @@ import type * as dockerode from 'dockerode'; import { Flags } from '@oclif/core'; -import { ExpectedError } from '../errors'; -import { parseAsInteger } from './validation'; +import { ExpectedError } from '../errors.js'; +import { parseAsInteger } from './validation.js'; interface BalenaEngineVersion extends dockerode.DockerVersion { Engine?: string; @@ -184,7 +184,7 @@ export async function getDocker( export async function createClient( opts: dockerode.DockerOptions, ): Promise { - const Docker = await import('dockerode'); + const { default: Docker } = await import('dockerode'); return new Docker(opts); } diff --git a/src/utils/env-common.ts b/src/utils/env-common.ts index 845f65a534..85fb35316a 100644 --- a/src/utils/env-common.ts +++ b/src/utils/env-common.ts @@ -16,9 +16,9 @@ */ import { Flags } from '@oclif/core'; -import { stripIndent } from './lazy'; +import { stripIndent } from './lazy.js'; -import { ExpectedError } from '../errors'; +import { ExpectedError } from '../errors.js'; export const booleanConfig = Flags.boolean({ char: 'c', diff --git a/src/utils/eol-conversion.ts b/src/utils/eol-conversion.ts index 114a9e3224..4961168c2a 100644 --- a/src/utils/eol-conversion.ts +++ b/src/utils/eol-conversion.ts @@ -16,7 +16,7 @@ */ import { promises as fs } from 'fs'; -import Logger = require('./logger'); +import Logger from './logger.js'; const globalLogger = Logger.getLogger(); diff --git a/src/utils/helpers.ts b/src/utils/helpers.ts index 80b94efa51..eb61fef543 100644 --- a/src/utils/helpers.ts +++ b/src/utils/helpers.ts @@ -17,10 +17,10 @@ limitations under the License. import type { InitializeEmitter, OperationState } from 'balena-device-init'; import type * as BalenaSdk from 'balena-sdk'; -import * as _ from 'lodash'; +import _ from 'lodash'; import { promisify } from 'util'; -import { getBalenaSdk, getChalk, getVisuals } from './lazy'; +import { getBalenaSdk, getChalk, getVisuals } from './lazy.js'; export function getGroupDefaults(group: { options: Array<{ name: string; default: string | number }>; @@ -77,7 +77,7 @@ export async function sudo( isCLIcmd, }: { stderr?: NodeJS.WritableStream; msg?: string; isCLIcmd?: boolean } = {}, ) { - const { executeWithPrivileges } = await import('./sudo'); + const { executeWithPrivileges } = await import('./sudo.js'); if (process.platform !== 'win32') { console.log( @@ -90,8 +90,7 @@ export async function sudo( } export async function runCommand(commandArgs: string[]): Promise { - const { isSubcommand } = - require('../preparser') as typeof import('../preparser'); + const { isSubcommand } = await import('../preparser.js'); if (await isSubcommand(commandArgs)) { commandArgs = [ commandArgs[0] + ':' + commandArgs[1], @@ -99,7 +98,7 @@ export async function runCommand(commandArgs: string[]): Promise { ]; } - const { run } = require('@oclif/core') as typeof import('@oclif/core'); + const { run } = await import('@oclif/core'); return run(commandArgs) as Promise; } @@ -115,7 +114,7 @@ export async function getManifest( manifest.slug !== deviceType && manifest.slug !== (await sdk.models.deviceType.get(deviceType)).slug ) { - const { ExpectedError } = await import('../errors'); + const { ExpectedError } = await import('../errors.js'); throw new ExpectedError( `The device type of the provided OS image ${manifest.slug}, does not match the expected device type ${deviceType}`, ); @@ -182,7 +181,7 @@ export async function osProgressHandler(step: InitializeEmitter) { } export async function getAppWithArch(applicationName: string) { - const { getApplication } = await import('./sdk'); + const { getApplication } = await import('./sdk.js'); const balena = getBalenaSdk(); const app = await getApplication(balena, applicationName, { $expand: { @@ -239,7 +238,7 @@ export async function retry({ backoffScaler?: number; maxSingleDelayMs?: number; }): Promise { - const { SIGINTError } = await import('../errors'); + const { SIGINTError } = await import('../errors.js'); let delayMs = initialDelayMs; for (let count = 0; count < maxAttempts - 1; count++) { const lastAttemptMs = Date.now(); @@ -438,7 +437,7 @@ export async function awaitInterruptibleTask< const sigintPromise = new Promise((_resolve, reject) => { sigintHandler = () => { const { SIGINTError } = - require('../errors') as typeof import('../errors'); + require('../errors.js') as typeof import('../errors.js'); reject(new SIGINTError('Task aborted on SIGINT signal')); }; addSIGINTHandler(sigintHandler); diff --git a/src/utils/ignore.ts b/src/utils/ignore.ts index dcc8d5a3a9..72705ecb6a 100644 --- a/src/utils/ignore.ts +++ b/src/utils/ignore.ts @@ -14,14 +14,14 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import * as _ from 'lodash'; +import _ from 'lodash'; import type { Stats } from 'fs'; import { promises as fs } from 'fs'; -import * as path from 'path'; +import path from 'path'; import type { Ignore } from '@balena/dockerignore'; -import { ExpectedError } from '../errors'; +import { ExpectedError } from '../errors.js'; export interface FileStats { filePath: string; @@ -104,7 +104,7 @@ export async function getDockerIgnoreInstance( ): Promise { const dockerIgnoreStr = await readDockerIgnoreFile(directory); const $dockerIgnore = (await import('@balena/dockerignore')).default; - const ig = $dockerIgnore({ ignorecase: false }); + const ig = $dockerIgnore.default({ ignorecase: false }); ig.add(['**/.git']); if (dockerIgnoreStr) { @@ -255,7 +255,7 @@ export async function getDockerignoreByService( dockerignoreByService = {}; for (let [serviceName, dir] of Object.entries(serviceDirsByService)) { - dir = multiDockerignore ? dir : '.'; + dir = multiDockerignore ? dir : './index.js'; const absDir = path.resolve(projectDir, dir); if (!cachedDirs[absDir]) { cachedDirs[absDir] = await getDockerIgnoreInstance(absDir); diff --git a/src/utils/image-manager.ts b/src/utils/image-manager.ts index 382c46cc3d..f09a3e3109 100644 --- a/src/utils/image-manager.ts +++ b/src/utils/image-manager.ts @@ -16,7 +16,7 @@ */ import type * as SDK from 'balena-sdk'; -import { getBalenaSdk } from './lazy'; +import { getBalenaSdk } from './lazy.js'; // eslint-disable-next-line no-useless-escape const BALENAOS_VERSION_REGEX = /v?\d+\.\d+\.\d+(\.rev\d+)?((\-|\+).+)?/; @@ -163,7 +163,9 @@ export const getImage = async (deviceType: string, version: string) => { > & { mime: string }; // Default to application/octet-stream if we could not find a more specific mime type - const { getType } = await import('mime'); + const { + default: { getType }, + } = await import('mime'); stream.mime = getType(imagePath) ?? 'application/octet-stream'; return stream; }; diff --git a/src/utils/lazy.ts b/src/utils/lazy.ts index fbcc1ef900..1de0bda540 100644 --- a/src/utils/lazy.ts +++ b/src/utils/lazy.ts @@ -21,6 +21,8 @@ import type { Chalk } from 'chalk'; import type * as visuals from 'resin-cli-visuals'; import type * as CliForm from 'resin-cli-form'; import type { ux } from '@oclif/core'; +import Module from 'node:module'; +const require = Module.createRequire(import.meta.url); // Equivalent of _.once but avoiding the need to import lodash for lazy deps const once = (fn: () => T) => { @@ -57,9 +59,13 @@ export const getCliForm = once( () => require('resin-cli-form') as typeof CliForm, ); -export const getCliUx = once(() => require('@oclif/core/ux').ux as typeof ux); +export const getCliUx: () => typeof ux = once( + () => require('@oclif/core/ux').ux as typeof ux, +); // Directly export stripIndent as we always use it immediately, but importing just `stripIndent` reduces startup time export const stripIndent = // tslint:disable-next-line:no-var-requires require('common-tags/lib/stripIndent') as typeof import('common-tags/lib/stripIndent'); + +export const getPackageJson = once(() => require('../../package.json')); diff --git a/src/utils/logger.ts b/src/utils/logger.ts index e71d8b4674..5881261f14 100644 --- a/src/utils/logger.ts +++ b/src/utils/logger.ts @@ -14,10 +14,10 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import _ = require('lodash'); +import _ from 'lodash'; import { EOL as eol } from 'os'; import { StreamLogger } from 'resin-stream-logger'; -import { getChalk } from './lazy'; +import { getChalk } from './lazy.js'; enum Level { BUILD = 'build', @@ -175,4 +175,4 @@ class Logger { } } -export = Logger; +export default Logger; diff --git a/src/utils/normalization.ts b/src/utils/normalization.ts index a490f0b5da..e38720b2d6 100644 --- a/src/utils/normalization.ts +++ b/src/utils/normalization.ts @@ -16,7 +16,7 @@ */ import type { BalenaSDK } from 'balena-sdk'; -import { ExpectedError } from '../errors'; +import { ExpectedError } from '../errors.js'; /** * Takes a string which may represent one of: diff --git a/src/utils/oclif-utils.ts b/src/utils/oclif-utils.ts index f1f2c9ea13..e1cc527751 100644 --- a/src/utils/oclif-utils.ts +++ b/src/utils/oclif-utils.ts @@ -15,6 +15,10 @@ * limitations under the License. */ +import Module from 'node:module'; + +const require = Module.createRequire(import.meta.url); + /** Convert e.g. 'env set NAME [VALUE]' to 'env set [value]' */ export function capitanoizeOclifUsage( oclifUsage: string | string[] | undefined, diff --git a/src/utils/patterns.ts b/src/utils/patterns.ts index 0add281c4f..36a58cea22 100644 --- a/src/utils/patterns.ts +++ b/src/utils/patterns.ts @@ -29,9 +29,9 @@ import { NotLoggedInError, ExpectedError, NotAvailableInOfflineModeError, -} from '../errors'; -import { getBalenaSdk, stripIndent, getCliForm } from './lazy'; -import validation = require('./validation'); +} from '../errors.js'; +import { getBalenaSdk, stripIndent, getCliForm } from './lazy.js'; +import * as validation from './validation.js'; export function authenticate(options: object): Promise { const balena = getBalenaSdk(); @@ -268,7 +268,7 @@ export async function selectOrganization( } export async function getAndSelectOrganization() { - const { getOwnOrganizations } = await import('./sdk'); + const { getOwnOrganizations } = await import('./sdk.js'); const organizations = await getOwnOrganizations(getBalenaSdk(), { $select: ['name', 'handle'], }); @@ -298,7 +298,7 @@ export async function getOnlineTargetDeviceUuid( sdk: BalenaSDK, fleetOrDevice: string, ) { - const logger = (await import('../utils/logger')).getLogger(); + const logger = (await import('../utils/logger.js')).default.getLogger(); // If looks like UUID, probably device if (validation.validateUuid(fleetOrDevice)) { @@ -333,7 +333,7 @@ export async function getOnlineTargetDeviceUuid( const application = await (async () => { try { logger.logDebug(`Fetching fleet ${fleetOrDevice}`); - const { getApplication } = await import('./sdk'); + const { getApplication } = await import('./sdk.js'); return await getApplication(sdk, fleetOrDevice, { $select: ['id', 'slug'], $expand: { diff --git a/src/utils/promote.ts b/src/utils/promote.ts index 5f84b04515..d1dcf9d78b 100644 --- a/src/utils/promote.ts +++ b/src/utils/promote.ts @@ -16,11 +16,11 @@ */ import type * as BalenaSdk from 'balena-sdk'; -import { ExpectedError, printErrorMessage } from '../errors'; -import { getVisuals, stripIndent, getCliForm } from './lazy'; -import Logger = require('./logger'); -import { confirm } from './patterns'; -import { getLocalDeviceCmdStdout, getDeviceOsRelease } from './ssh'; +import { ExpectedError, printErrorMessage } from '../errors.js'; +import { getVisuals, stripIndent, getCliForm } from './lazy.js'; +import type Logger from './logger.js'; +import { confirm } from './patterns.js'; +import { getLocalDeviceCmdStdout, getDeviceOsRelease } from './ssh.js'; const MIN_BALENAOS_VERSION = 'v2.14.0'; @@ -167,7 +167,7 @@ const dockerPort = 2375; const dockerTimeout = 2000; async function selectLocalBalenaOsDevice(timeout = 4000): Promise { - const { discoverLocalBalenaOsDevices } = await import('../utils/discover'); + const { discoverLocalBalenaOsDevices } = await import('../utils/discover.js'); const { SpinnerPromise } = getVisuals(); const devices = await new SpinnerPromise({ promise: discoverLocalBalenaOsDevices(timeout), @@ -176,7 +176,7 @@ async function selectLocalBalenaOsDevice(timeout = 4000): Promise { }); const responsiveDevices: typeof devices = []; - const Docker = await import('dockerode'); + const { default: Docker } = await import('dockerode'); await Promise.all( devices.map(async function (device) { const address = device?.address; @@ -231,7 +231,7 @@ async function selectAppFromList( applications: ApplicationWithDeviceTypeSlug[], ): Promise { const _ = await import('lodash'); - const { selectFromList } = await import('../utils/patterns'); + const { selectFromList } = await import('../utils/patterns.js'); // Present a list to the user which shows the fully qualified fleet // name (user/fleetname) and allows them to select. @@ -384,7 +384,7 @@ async function createApplication( deviceType: string, name?: string, ): Promise { - const validation = await import('./validation'); + const validation = await import('./validation.js'); let username: string; try { @@ -448,7 +448,7 @@ async function generateApplicationConfig( appUpdatePollInterval?: number; }, ) { - const { generateApplicationConfig: configGen } = await import('./config'); + const { generateApplicationConfig: configGen } = await import('./config.js'); const manifest = await sdk.models.config.getDeviceTypeManifestBySlug( app.is_for__device_type[0].slug, diff --git a/src/utils/proxy.ts b/src/utils/proxy.ts index c4147f5e65..cbc1a10fb7 100644 --- a/src/utils/proxy.ts +++ b/src/utils/proxy.ts @@ -18,7 +18,7 @@ import type { Options as GlobalTunnelNgConfig } from 'global-tunnel-ng'; export type { GlobalTunnelNgConfig }; -import type { CliSettings } from './bootstrap'; +import type { CliSettings } from './bootstrap.js'; type ProxyConfig = string | GlobalTunnelNgConfig; diff --git a/src/utils/qemu.ts b/src/utils/qemu.ts index 0b752e4638..dc4f84fab8 100644 --- a/src/utils/qemu.ts +++ b/src/utils/qemu.ts @@ -17,9 +17,9 @@ import type * as Dockerode from 'dockerode'; -import { ExpectedError } from '../errors'; -import { getBalenaSdk, stripIndent } from './lazy'; -import Logger = require('./logger'); +import { ExpectedError } from '../errors.js'; +import { getBalenaSdk, stripIndent } from './lazy.js'; +import type Logger from './logger.js'; export const QEMU_VERSION = 'v7.0.0+balena1'; export const QEMU_BIN_NAME = 'qemu-execve'; @@ -117,7 +117,8 @@ async function installQemu(arch: string, qemuPath: string) { reject(err as Error); } }); - request(qemuUrl) + request + .default(qemuUrl) .on('error', reject) .pipe(zlib.createGunzip()) .on('error', reject) diff --git a/src/utils/remote-build.ts b/src/utils/remote-build.ts index fd4c3ced9c..f4cd7bc4ab 100644 --- a/src/utils/remote-build.ts +++ b/src/utils/remote-build.ts @@ -16,16 +16,16 @@ limitations under the License. import type { BalenaSDK } from 'balena-sdk'; import * as JSONStream from 'JSONStream'; import * as readline from 'readline'; -import * as request from 'request'; +import request from 'request'; import type { RegistrySecrets } from '@balena/compose/dist/multibuild'; import type * as Stream from 'stream'; import streamToPromise = require('stream-to-promise'); import type { Pack } from 'tar-stream'; -import { ExpectedError, SIGINTError } from '../errors'; -import { tarDirectory } from './compose_ts'; -import { getVisuals, stripIndent } from './lazy'; -import Logger = require('./logger'); +import { ExpectedError, SIGINTError } from '../errors.js'; +import { tarDirectory } from './compose_ts.js'; +import { getVisuals, stripIndent } from './lazy.js'; +import Logger from './logger.js'; const globalLogger = Logger.getLogger(); @@ -126,7 +126,7 @@ export async function startRemoteBuild( } }; - const { addSIGINTHandler } = await import('./helpers'); + const { addSIGINTHandler } = await import('./helpers.js'); addSIGINTHandler(sigintHandler); try { diff --git a/src/utils/sdk.ts b/src/utils/sdk.ts index 0df612df2f..4e95833fc0 100644 --- a/src/utils/sdk.ts +++ b/src/utils/sdk.ts @@ -42,7 +42,7 @@ export async function getApplication( nameOrSlugOrId: string | number, options?: PineOptions, ): Promise { - const { looksLikeFleetSlug } = await import('./validation'); + const { looksLikeFleetSlug } = await import('./validation.js'); const whoamiResult = await sdk.auth.whoami(); const isDeviceActor = whoamiResult?.actorType === 'device'; @@ -97,7 +97,7 @@ export async function getFleetSlug( sdk: BalenaSDK, nameOrSlug: string, ): Promise { - const { looksLikeFleetSlug } = await import('./validation'); + const { looksLikeFleetSlug } = await import('./validation.js'); if (!looksLikeFleetSlug(nameOrSlug)) { // Not a slug: must be an app name. // TODO: revisit this logic when we add support for fleet UUIDs. diff --git a/src/utils/ssh.ts b/src/utils/ssh.ts index 749663f0d5..be75b142ee 100644 --- a/src/utils/ssh.ts +++ b/src/utils/ssh.ts @@ -16,9 +16,9 @@ */ import type { StdioOptions } from 'child_process'; import { spawn } from 'child_process'; -import * as _ from 'lodash'; +import _ from 'lodash'; -import { ExpectedError } from '../errors'; +import { ExpectedError } from '../errors.js'; export class SshPermissionDeniedError extends ExpectedError {} @@ -127,7 +127,7 @@ export async function runRemoteCommand({ } else { ignoreStdin = false; } - const { which } = await import('./which'); + const { which } = await import('./which.js'); const program = await which('ssh'); const args = sshArgsForRemoteCommand({ cmd, @@ -140,7 +140,7 @@ export async function runRemoteCommand({ }); if (process.env.DEBUG) { - const logger = (await import('./logger')).getLogger(); + const logger = (await import('./logger.js')).default.getLogger(); logger.logDebug(`Executing [${program},${args}]`); } @@ -296,11 +296,11 @@ export const findBestUsernameForDevice = _.memoize( if (await isRootUserGood(hostname, port)) { username = 'root'; } else { - const { getCachedUsername } = await import('./bootstrap'); + const { getCachedUsername } = await import('./bootstrap.js'); username = (await getCachedUsername())?.username; } if (!username) { - const { stripIndent } = await import('./lazy'); + const { stripIndent } = await import('./lazy.js'); throw new ExpectedError(stripIndent` SSH authentication failed for 'root@${hostname}'. Please login with 'balena login' for alternative authentication.`); diff --git a/src/utils/sudo.ts b/src/utils/sudo.ts index 55c4222fde..1544ef6ceb 100644 --- a/src/utils/sudo.ts +++ b/src/utils/sudo.ts @@ -17,7 +17,7 @@ import type { ChildProcess, SpawnOptions } from 'child_process'; import { spawn } from 'child_process'; -import { stripIndent } from './lazy'; +import { stripIndent } from './lazy.js'; /** * Execute a child process with admin / superuser privileges, prompting the user for @@ -43,8 +43,8 @@ export async function executeWithPrivileges( isCLIcmd = true, ): Promise { // whether the CLI is already running with admin / super user privileges - const isElevated = await (await import('is-elevated'))(); - const { shellEscape } = await import('./helpers'); + const isElevated = await (await import('is-elevated')).default(); + const { shellEscape } = await import('./helpers.js'); const opts: SpawnOptions = { env: process.env, stdio: ['inherit', 'inherit', stderr ? 'pipe' : 'inherit'], @@ -105,7 +105,7 @@ async function spawnAndPipe( }); } -function windosuExec( +async function windosuExec( escapedArgs: string[], stderr?: NodeJS.WritableStream, ): Promise { @@ -116,5 +116,5 @@ function windosuExec( `; throw new Error(msg); } - return require('windosu').exec(escapedArgs.join(' ')); + return (await import('windosu')).exec(escapedArgs.join(' ')); } diff --git a/src/utils/tty.ts b/src/utils/tty.ts index 43308dbac7..b7cd00f358 100644 --- a/src/utils/tty.ts +++ b/src/utils/tty.ts @@ -25,7 +25,7 @@ const updateWindowSize = () => { process.stdout.on('resize', updateWindowSize); -export = (stream: NodeJS.WriteStream = process.stdout) => { +export default (stream: NodeJS.WriteStream = process.stdout) => { // make sure we get initial metrics updateWindowSize(); diff --git a/src/utils/tunnel.ts b/src/utils/tunnel.ts index 05e83e3d83..1ecdffc009 100644 --- a/src/utils/tunnel.ts +++ b/src/utils/tunnel.ts @@ -17,7 +17,7 @@ import type { BalenaSDK } from 'balena-sdk'; import type { Socket } from 'net'; import * as tls from 'tls'; import { TypedError } from 'typed-error'; -import { ExpectedError } from '../errors'; +import { ExpectedError } from '../errors.js'; const PROXY_CONNECT_TIMEOUT_MS = 10000; diff --git a/src/utils/umount.ts b/src/utils/umount.ts index 335a953690..7aa2470812 100644 --- a/src/utils/umount.ts +++ b/src/utils/umount.ts @@ -26,7 +26,6 @@ */ import * as child_process from 'child_process'; -import * as path from 'path'; import { promisify } from 'util'; const execFile = promisify(child_process.execFile); @@ -39,7 +38,7 @@ export async function umount(device: string): Promise { if (process.platform === 'win32') { return; } - const { sanitizePath, whichBin } = await import('./which'); + const { sanitizePath, whichBin } = await import('./which.js'); // sanitize user's input (regular expression attacks ?) device = sanitizePath(device); const cmd: string[] = []; @@ -48,10 +47,10 @@ export async function umount(device: string): Promise { cmd.push('/usr/sbin/diskutil', 'unmountDisk', 'force', device); } else { // Linux - const glob = promisify(await import('glob')); + const glob = promisify((await import('glob')).default); // '?*' expands a base device path like '/dev/sdb' to an array of paths // like '/dev/sdb1', '/dev/sdb2', ..., '/dev/sdb11', ... (partitions) - // that exist for balenaOS images and are needed as arguments to 'umount' + // that exist for balenaOS images and are needed as arguments to 'umount.js' // on Linux (otherwise, umount produces an error "/dev/sdb: not mounted") const devices = await glob(`${device}?*`, { nodir: true, nonull: true }); cmd.push(await whichBin('umount'), ...devices); @@ -75,7 +74,7 @@ export async function umount(device: string): Promise { } return; } - const { ExpectedError } = await import('../errors'); + const { ExpectedError } = await import('../errors.js'); throw new ExpectedError(msg.join('\n')); } } @@ -92,7 +91,7 @@ export async function isMounted(device: string): Promise { if (!device) { return false; } - const { whichBin } = await import('./which'); + const { whichBin } = await import('./which.js'); const mountCmd = await whichBin('mount'); let stdout = ''; let stderr = ''; @@ -101,7 +100,7 @@ export async function isMounted(device: string): Promise { stdout = proc.stdout; stderr = proc.stderr; } catch (err) { - const { ExpectedError } = await import('../errors'); + const { ExpectedError } = await import('../errors.js'); throw new ExpectedError( `Error executing "${mountCmd}":\n${stderr}\n${err.message}`, ); @@ -131,15 +130,7 @@ export async function denyMount( handler: () => any, opts: { autoMountOnSuccess?: boolean; executablePath?: string } = {}, ) { - const denymount = promisify(await import('denymount')); - if (process.pkg) { - // when running in a standalone pkg install, the 'denymount' - // executable is placed on the same folder as process.execPath - opts.executablePath ||= path.join( - path.dirname(process.execPath), - 'denymount', - ); - } + const denymount = promisify((await import('denymount')).default); const dmHandler = async (cb: (err?: Error) => void) => { let err: Error | undefined; try { diff --git a/src/utils/update.ts b/src/utils/update.ts index b100e9312d..088e629802 100644 --- a/src/utils/update.ts +++ b/src/utils/update.ts @@ -15,7 +15,7 @@ limitations under the License. */ import isRoot = require('is-root'); -import * as UpdateNotifier from 'update-notifier'; +import UpdateNotifier from 'update-notifier'; import packageJSON = require('../../package.json'); diff --git a/src/utils/validation.ts b/src/utils/validation.ts index af58de6883..1e42450c3f 100644 --- a/src/utils/validation.ts +++ b/src/utils/validation.ts @@ -13,7 +13,7 @@ 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 { ExpectedError } from '../errors'; +import { ExpectedError } from '../errors.js'; // Sufficiently good email regex in order not to bring in another dependency. const isValidEmail = (email: string): boolean => { diff --git a/src/utils/version.ts b/src/utils/version.ts index 739b3803bf..45bd787809 100644 --- a/src/utils/version.ts +++ b/src/utils/version.ts @@ -16,8 +16,12 @@ */ import * as semver from 'semver'; -import { version } from '../../package.json'; +import { getPackageJson } from './lazy.js'; +const pJson = getPackageJson(); export function isVersionGTE(v: string): boolean { - return semver.gte(process.env.BALENA_CLI_VERSION_OVERRIDE || version, v); + return semver.gte( + process.env.BALENA_CLI_VERSION_OVERRIDE || pJson.version, + v, + ); } diff --git a/src/utils/which.ts b/src/utils/which.ts index d35b72bb10..65ce4d2150 100644 --- a/src/utils/which.ts +++ b/src/utils/which.ts @@ -16,7 +16,7 @@ */ import { promises as fs, constants } from 'fs'; -import * as path from 'path'; +import path from 'path'; export const { F_OK, R_OK, W_OK, X_OK } = constants; @@ -76,14 +76,14 @@ export async function which( program: string, rejectOnMissing = true, ): Promise { - const whichMod = await import('which'); + const { default: whichMod } = await import('which'); let programPath: string; try { programPath = await whichMod(program); } catch (err) { if (err.code === 'ENOENT') { if (rejectOnMissing) { - const { ExpectedError } = await import('../errors'); + const { ExpectedError } = await import('../errors.js'); throw new ExpectedError( `'${program}' program not found. Is it installed?`, ); diff --git a/tests/auth/server.spec.ts b/tests/auth/server.spec.ts index 02bd2c5989..108456830c 100644 --- a/tests/auth/server.spec.ts +++ b/tests/auth/server.spec.ts @@ -18,9 +18,9 @@ import * as chai from 'chai'; import * as chaiAsPromised from 'chai-as-promised'; import * as ejs from 'ejs'; -import * as fs from 'fs'; -import * as path from 'path'; -import * as request from 'request'; +import fs from 'fs'; +import path from 'path'; +import request from 'request'; import * as sinon from 'sinon'; import { LoginServer } from '../../build/auth/server'; diff --git a/tests/auth/utils.spec.ts b/tests/auth/utils.spec.ts index dd5a733c79..b492f99d2a 100644 --- a/tests/auth/utils.spec.ts +++ b/tests/auth/utils.spec.ts @@ -1,7 +1,7 @@ import { expect } from 'chai'; import * as sinon from 'sinon'; import * as url from 'url'; -import { getBalenaSdk } from '../../build/utils/lazy'; +import { getBalenaSdk } from '../../build/utils/lazy.js'; import tokens from './tokens'; const balena = getBalenaSdk(); diff --git a/tests/commands/build.spec.ts b/tests/commands/build.spec.ts index a9aae8b0a1..4f4b181324 100644 --- a/tests/commands/build.spec.ts +++ b/tests/commands/build.spec.ts @@ -16,16 +16,16 @@ */ import { expect } from 'chai'; -import * as _ from 'lodash'; +import _ from 'lodash'; import * as mock from 'mock-require'; import { promises as fs } from 'fs'; -import * as path from 'path'; +import path from 'path'; -import { stripIndent } from '../../build/utils/lazy'; +import { stripIndent } from '../../build/utils/lazy.js'; import { BalenaAPIMock } from '../nock/balena-api-mock'; import { expectStreamNoCRLF, testDockerBuildStream } from '../docker-build'; import { DockerMock, dockerResponsePath } from '../nock/docker-mock'; -import { cleanOutput, runCommand } from '../helpers'; +import { cleanOutput, runCommand } from '../helpers.js'; import type { ExpectedTarStreamFiles, ExpectedTarStreamFilesByService, diff --git a/tests/commands/deploy.spec.ts b/tests/commands/deploy.spec.ts index 27926c42ef..98c7454a57 100644 --- a/tests/commands/deploy.spec.ts +++ b/tests/commands/deploy.spec.ts @@ -19,15 +19,15 @@ import { intVar } from '@balena/env-parsing'; import type { Request as ReleaseRequest } from '@balena/compose/dist/release'; import { expect } from 'chai'; import { promises as fs } from 'fs'; -import * as _ from 'lodash'; +import _ from 'lodash'; import type * as nock from 'nock'; -import * as path from 'path'; +import path from 'path'; import * as sinon from 'sinon'; import { BalenaAPIMock } from '../nock/balena-api-mock'; import { expectStreamNoCRLF, testDockerBuildStream } from '../docker-build'; import { DockerMock, dockerResponsePath } from '../nock/docker-mock'; -import { cleanOutput, runCommand, switchSentry } from '../helpers'; +import { cleanOutput, runCommand, switchSentry } from '../helpers.js'; import type { ExpectedTarStreamFiles, ExpectedTarStreamFilesByService, diff --git a/tests/commands/device-type/list.spec.ts b/tests/commands/device-type/list.spec.ts index 556b52ef04..d43c55d111 100644 --- a/tests/commands/device-type/list.spec.ts +++ b/tests/commands/device-type/list.spec.ts @@ -18,7 +18,7 @@ import { expect } from 'chai'; import { BalenaAPIMock } from '../../nock/balena-api-mock'; -import { cleanOutput, runCommand } from '../../helpers'; +import { cleanOutput, runCommand } from '../../helpers.js'; describe('balena device-type list', function () { let api: BalenaAPIMock; diff --git a/tests/commands/device/device-move.spec.ts b/tests/commands/device/device-move.spec.ts index aab0699aa8..432f97d4f9 100644 --- a/tests/commands/device/device-move.spec.ts +++ b/tests/commands/device/device-move.spec.ts @@ -17,7 +17,7 @@ import { expect } from 'chai'; import { BalenaAPIMock } from '../../nock/balena-api-mock'; -import { cleanOutput, runCommand } from '../../helpers'; +import { cleanOutput, runCommand } from '../../helpers.js'; describe('balena device move', function () { let api: BalenaAPIMock; diff --git a/tests/commands/device/device.spec.ts b/tests/commands/device/device.spec.ts index 3f283a2db2..b243046fcb 100644 --- a/tests/commands/device/device.spec.ts +++ b/tests/commands/device/device.spec.ts @@ -16,10 +16,10 @@ */ import { expect } from 'chai'; -import * as path from 'path'; +import path from 'path'; import { apiResponsePath, BalenaAPIMock } from '../../nock/balena-api-mock'; -import { cleanOutput, runCommand } from '../../helpers'; +import { cleanOutput, runCommand } from '../../helpers.js'; describe('balena device', function () { let api: BalenaAPIMock; diff --git a/tests/commands/device/logs.spec.ts b/tests/commands/device/logs.spec.ts index 9e13d78543..0bf37dc2cb 100644 --- a/tests/commands/device/logs.spec.ts +++ b/tests/commands/device/logs.spec.ts @@ -18,7 +18,7 @@ import { expect } from 'chai'; import { BalenaAPIMock } from '../../nock/balena-api-mock'; -import { cleanOutput, runCommand } from '../../helpers'; +import { cleanOutput, runCommand } from '../../helpers.js'; import { SupervisorMock } from '../../nock/supervisor-mock'; const itS = process.env.BALENA_CLI_TEST_TYPE === 'standalone' ? it : it.skip; diff --git a/tests/commands/device/ssh.spec.ts b/tests/commands/device/ssh.spec.ts index 21885a1aaf..ba03c0906c 100644 --- a/tests/commands/device/ssh.spec.ts +++ b/tests/commands/device/ssh.spec.ts @@ -21,7 +21,7 @@ import type { Server } from 'net'; import { createServer } from 'net'; import { BalenaAPIMock } from '../../nock/balena-api-mock'; -import { cleanOutput, runCommand } from '../../helpers'; +import { cleanOutput, runCommand } from '../../helpers.js'; // "itSS" means "it() Skip Standalone" const itSS = process.env.BALENA_CLI_TEST_TYPE === 'standalone' ? it.skip : it; @@ -148,7 +148,7 @@ describe('balena device ssh', function () { /** Check whether the 'ssh' tool (executable) exists in the PATH */ async function checkSsh(): Promise { - const { which } = await import('../../../build/utils/which'); + const { which } = await import('../../../build/utils/which.js'); const sshPath = await which('ssh', false); if ((sshPath || '').includes('\\Windows\\System32\\OpenSSH\\ssh')) { // don't use Windows' built-in ssh tool for these test cases diff --git a/tests/commands/env/add.spec.ts b/tests/commands/env/add.spec.ts index 4c91eb9de2..1f3aa2f800 100644 --- a/tests/commands/env/add.spec.ts +++ b/tests/commands/env/add.spec.ts @@ -18,7 +18,7 @@ import { expect } from 'chai'; import { BalenaAPIMock } from '../../nock/balena-api-mock'; -import { runCommand } from '../../helpers'; +import { runCommand } from '../../helpers.js'; describe('balena env set', function () { let api: BalenaAPIMock; diff --git a/tests/commands/env/list.spec.ts b/tests/commands/env/list.spec.ts index a07904128a..d3cce54703 100644 --- a/tests/commands/env/list.spec.ts +++ b/tests/commands/env/list.spec.ts @@ -16,10 +16,10 @@ */ import { expect } from 'chai'; -import { stripIndent } from '../../../build/utils/lazy'; +import { stripIndent } from '../../../build/utils/lazy.js'; import { BalenaAPIMock } from '../../nock/balena-api-mock'; -import { runCommand } from '../../helpers'; +import { runCommand } from '../../helpers.js'; import { randomBytes } from 'node:crypto'; describe('balena env list', function () { diff --git a/tests/commands/env/rename.spec.ts b/tests/commands/env/rename.spec.ts index 78e3cbb1be..8af0da045d 100644 --- a/tests/commands/env/rename.spec.ts +++ b/tests/commands/env/rename.spec.ts @@ -18,7 +18,7 @@ import { expect } from 'chai'; import { BalenaAPIMock } from '../../nock/balena-api-mock'; -import { runCommand } from '../../helpers'; +import { runCommand } from '../../helpers.js'; describe('balena env rename', function () { let api: BalenaAPIMock; diff --git a/tests/commands/env/rm.spec.ts b/tests/commands/env/rm.spec.ts index b4ee159f7f..72fd273944 100644 --- a/tests/commands/env/rm.spec.ts +++ b/tests/commands/env/rm.spec.ts @@ -18,7 +18,7 @@ import { expect } from 'chai'; import { BalenaAPIMock } from '../../nock/balena-api-mock'; -import { runCommand } from '../../helpers'; +import { runCommand } from '../../helpers.js'; describe('balena env rm', function () { let api: BalenaAPIMock; diff --git a/tests/commands/help.spec.ts b/tests/commands/help.spec.ts index 4d0db6473a..3d59af3ac3 100644 --- a/tests/commands/help.spec.ts +++ b/tests/commands/help.spec.ts @@ -18,8 +18,8 @@ import { expect } from 'chai'; import { BalenaAPIMock } from '../nock/balena-api-mock'; -import { cleanOutput, runCommand } from '../helpers'; -import * as messages from '../../build/utils/messages'; +import { cleanOutput, runCommand } from '../helpers.js'; +import * as messages from '../../build/utils/messages.js'; const SIMPLE_HELP = ` USAGE diff --git a/tests/commands/os/configure.spec.ts b/tests/commands/os/configure.spec.ts index 2b3eb2057b..0798cc4b76 100644 --- a/tests/commands/os/configure.spec.ts +++ b/tests/commands/os/configure.spec.ts @@ -18,7 +18,7 @@ import { expect } from 'chai'; import { promises as fs } from 'fs'; import * as process from 'process'; -import { runCommand } from '../../helpers'; +import { runCommand } from '../../helpers.js'; import { promisify } from 'util'; import * as tmp from 'tmp'; import type * as $imagefs from 'balena-image-fs'; diff --git a/tests/commands/push.spec.ts b/tests/commands/push.spec.ts index c1b0036e3a..c3b6ee0b44 100644 --- a/tests/commands/push.spec.ts +++ b/tests/commands/push.spec.ts @@ -17,12 +17,12 @@ import { expect } from 'chai'; import { promises as fs } from 'fs'; -import * as path from 'path'; +import path from 'path'; import { BalenaAPIMock } from '../nock/balena-api-mock'; import { BuilderMock, builderResponsePath } from '../nock/builder-mock'; import { expectStreamNoCRLF, testPushBuildStream } from '../docker-build'; -import { cleanOutput, runCommand } from '../helpers'; +import { cleanOutput, runCommand } from '../helpers.js'; import type { ExpectedTarStreamFiles } from '../projects'; import { addRegSecretsEntries, diff --git a/tests/commands/release.spec.ts b/tests/commands/release.spec.ts index 1ced28ca94..bd1bb591ee 100644 --- a/tests/commands/release.spec.ts +++ b/tests/commands/release.spec.ts @@ -18,7 +18,7 @@ import { expect } from 'chai'; import { BalenaAPIMock } from '../nock/balena-api-mock'; -import { cleanOutput, runCommand } from '../helpers'; +import { cleanOutput, runCommand } from '../helpers.js'; describe('balena release', function () { let api: BalenaAPIMock; diff --git a/tests/commands/tag/set.spec.ts b/tests/commands/tag/set.spec.ts index 2c1067478f..a9fcf11425 100644 --- a/tests/commands/tag/set.spec.ts +++ b/tests/commands/tag/set.spec.ts @@ -18,7 +18,7 @@ import { expect } from 'chai'; import { BalenaAPIMock } from '../../nock/balena-api-mock'; -import { runCommand } from '../../helpers'; +import { runCommand } from '../../helpers.js'; describe('balena tag set', function () { let api: BalenaAPIMock; diff --git a/tests/commands/version.spec.ts b/tests/commands/version.spec.ts index 1cbf6696b8..285c889230 100644 --- a/tests/commands/version.spec.ts +++ b/tests/commands/version.spec.ts @@ -15,10 +15,10 @@ * limitations under the License. */ import { expect } from 'chai'; -import * as fs from 'fs'; +import fs from 'fs'; import { BalenaAPIMock } from '../nock/balena-api-mock'; -import { runCommand } from '../helpers'; +import { runCommand } from '../helpers.js'; const packageJSON = JSON.parse(fs.readFileSync('./package.json', 'utf8')); const nodeVersion = process.version.startsWith('v') diff --git a/tests/commands/whoami.spec.ts b/tests/commands/whoami.spec.ts index 53b0611ae6..ad4c519f92 100644 --- a/tests/commands/whoami.spec.ts +++ b/tests/commands/whoami.spec.ts @@ -17,7 +17,7 @@ import { expect } from 'chai'; import { BalenaAPIMock } from '../nock/balena-api-mock'; -import { cleanOutput, runCommand } from '../helpers'; +import { cleanOutput, runCommand } from '../helpers.js'; describe('balena whoami', function () { let api: BalenaAPIMock; diff --git a/tests/deprecation.spec.ts b/tests/deprecation.spec.ts index d78f8b64c7..0c05104dbb 100644 --- a/tests/deprecation.spec.ts +++ b/tests/deprecation.spec.ts @@ -27,8 +27,8 @@ import type { ReleaseTimestampsByVersion } from '../build/deprecation'; import { DeprecationChecker } from '../build/deprecation'; import { BalenaAPIMock } from './nock/balena-api-mock'; import { NpmMock } from './nock/npm-mock'; -import type { TestOutput } from './helpers'; -import { runCommand } from './helpers'; +import type { TestOutput } from './helpers.js'; +import { runCommand } from './helpers.js'; // "itSS" means "it() Skip Standalone" const itSS = process.env.BALENA_CLI_TEST_TYPE === 'standalone' ? it.skip : it; diff --git a/tests/docker-build.ts b/tests/docker-build.ts index 469f41ebe8..736a17a849 100644 --- a/tests/docker-build.ts +++ b/tests/docker-build.ts @@ -16,9 +16,9 @@ */ import { expect } from 'chai'; -import * as _ from 'lodash'; +import _ from 'lodash'; import { promises as fs } from 'fs'; -import * as path from 'path'; +import path from 'path'; import { PathUtils } from '@balena/compose/dist/multibuild'; import * as sinon from 'sinon'; import { Readable } from 'stream'; @@ -26,8 +26,8 @@ import * as tar from 'tar-stream'; import { streamToBuffer } from 'tar-utils'; import { URL } from 'url'; import { diff } from 'deep-object-diff'; -import { makeImageName } from '../build/utils/compose_ts'; -import { stripIndent } from '../build/utils/lazy'; +import { makeImageName } from '../build/utils/compose_ts.js'; +import { stripIndent } from '../build/utils/lazy.js'; import type { BuilderMock } from './nock/builder-mock'; import type { DockerMock } from './nock/docker-mock'; import { @@ -35,12 +35,12 @@ import { deepJsonParse, deepTemplateReplace, runCommand, -} from './helpers'; +} from './helpers.js'; import type { ExpectedTarStreamFile, ExpectedTarStreamFiles, ExpectedTarStreamFilesByService, -} from './projects'; +} from './projects.js'; /** * Run a few chai.expect() test assertions on a tar stream/buffer produced by @@ -266,6 +266,6 @@ export async function resetDockerignoreCache() { } const ignorePath = '../build/utils/ignore'; delete require.cache[require.resolve(ignorePath)]; - const ignoreMod = rewire(ignorePath); + const ignoreMod = rewire.default(ignorePath); ignoreMod.__set__('dockerignoreByService', null); } diff --git a/tests/errors.spec.ts b/tests/errors.spec.ts index ce9fa8adbc..6a812ec087 100644 --- a/tests/errors.spec.ts +++ b/tests/errors.spec.ts @@ -23,8 +23,8 @@ import { } from 'balena-errors'; import { expect } from 'chai'; import * as sinon from 'sinon'; -import * as ErrorsModule from '../build/errors'; -import { getHelp } from '../build/utils/messages'; +import * as ErrorsModule from '../build/errors.js'; +import { getHelp } from '../build/utils/messages.js'; function red(s: string) { if (process.env.CI) { diff --git a/tests/helpers.ts b/tests/helpers.ts index 39a69f8fe0..f245204a0f 100644 --- a/tests/helpers.ts +++ b/tests/helpers.ts @@ -15,14 +15,14 @@ * limitations under the License. */ -import * as _ from 'lodash'; -import * as path from 'path'; -import * as fs from 'fs'; +import _ from 'lodash'; +import path from 'path'; +import fs from 'fs'; import { createGunzip } from 'zlib'; import * as packageJSON from '../package.json'; -import { getNodeEngineVersionWarn } from '../build/utils/messages'; -import { warnify } from '../build/utils/messages'; +import { getNodeEngineVersionWarn } from '../build/utils/messages.js'; +import { warnify } from '../build/utils/messages.js'; const standalonePath = path.resolve( __dirname, diff --git a/tests/nock/balena-api-mock.ts b/tests/nock/balena-api-mock.ts index 89452f4562..26e054215e 100644 --- a/tests/nock/balena-api-mock.ts +++ b/tests/nock/balena-api-mock.ts @@ -15,8 +15,8 @@ * limitations under the License. */ -import * as _ from 'lodash'; -import * as path from 'path'; +import _ from 'lodash'; +import path from 'path'; import type { ScopeOpts } from './nock-mock'; import { NockMock } from './nock-mock'; diff --git a/tests/nock/builder-mock.ts b/tests/nock/builder-mock.ts index 71450f36b6..138eab266f 100644 --- a/tests/nock/builder-mock.ts +++ b/tests/nock/builder-mock.ts @@ -15,7 +15,7 @@ * limitations under the License. */ -import * as path from 'path'; +import path from 'path'; import * as zlib from 'zlib'; import { NockMock } from './nock-mock'; diff --git a/tests/nock/docker-mock.ts b/tests/nock/docker-mock.ts index 955b44b6f9..450c6851aa 100644 --- a/tests/nock/docker-mock.ts +++ b/tests/nock/docker-mock.ts @@ -15,7 +15,7 @@ * limitations under the License. */ -import * as path from 'path'; +import path from 'path'; import * as qs from 'querystring'; import type { ScopeOpts } from './nock-mock'; diff --git a/tests/nock/nock-mock.ts b/tests/nock/nock-mock.ts index 505359171c..b77dfd7ace 100644 --- a/tests/nock/nock-mock.ts +++ b/tests/nock/nock-mock.ts @@ -16,7 +16,7 @@ */ import * as nock from 'nock'; -import * as fs from 'fs'; +import fs from 'fs'; import { interceptorServerPort } from './proxy-server'; export interface ScopeOpts { diff --git a/tests/nock/supervisor-mock.ts b/tests/nock/supervisor-mock.ts index 0d149f5ed9..d298c92d98 100644 --- a/tests/nock/supervisor-mock.ts +++ b/tests/nock/supervisor-mock.ts @@ -14,7 +14,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import * as path from 'path'; +import path from 'path'; import { Readable } from 'stream'; import type { ScopeOpts } from './nock-mock'; diff --git a/tests/projects.ts b/tests/projects.ts index 3119a320f7..9c913d8f86 100644 --- a/tests/projects.ts +++ b/tests/projects.ts @@ -16,7 +16,7 @@ */ import { promises as fs } from 'fs'; -import * as path from 'path'; +import path from 'path'; import type { Headers } from 'tar-stream'; export interface ExpectedTarStreamFile { diff --git a/tests/utils/device/live.spec.ts b/tests/utils/device/live.spec.ts index 510df946e4..6b8b58e1f8 100644 --- a/tests/utils/device/live.spec.ts +++ b/tests/utils/device/live.spec.ts @@ -18,7 +18,7 @@ import { expect } from 'chai'; import type * as chokidar from 'chokidar'; import { promises as fs } from 'fs'; -import * as path from 'path'; +import path from 'path'; import { promisify } from 'util'; import { LivepushManager } from '../../../src/utils/device/live'; @@ -42,8 +42,8 @@ class MockLivepushManager extends LivepushManager { composition: { version: '2.1', services: {} }, buildTasks: [], docker: {} as import('dockerode'), - api: {} as import('../../../src/utils/device/api').DeviceAPI, - logger: {} as import('../../../src/utils/logger'), + api: {} as import('../../../src/utils/device/api.js').DeviceAPI, + logger: {} as import('../../../src/utils/logger.js'), imageIds: {}, deployOpts: {} as import('../../../src/utils/device/deploy').DeviceDeployOptions, @@ -83,7 +83,7 @@ describeSS('LivepushManager::setupFilesystemWatcher', function () { changedPathHandler: (serviceName: string, changedPath: string) => void, ): Promise> { const { getServiceDirsFromComposition } = await import( - '../../../build/utils/compose_ts' + '../../../build/utils/compose_ts.js' ); const { getDockerignoreByService } = await import( '../../../build/utils/ignore' diff --git a/tests/utils/docker.spec.ts b/tests/utils/docker.spec.ts index fd498c3fc0..f6e23bd73b 100644 --- a/tests/utils/docker.spec.ts +++ b/tests/utils/docker.spec.ts @@ -17,11 +17,11 @@ import { expect } from 'chai'; -import type { DockerConnectionCliFlags } from '../../build/utils/docker'; +import type { DockerConnectionCliFlags } from '../../build/utils/docker.js'; import { generateConnectOpts, getDefaultDockerModemOpts, -} from '../../build/utils/docker'; +} from '../../build/utils/docker.js'; const defaultSocketPath = process.platform === 'win32' diff --git a/tests/utils/eol-conversion.spec.ts b/tests/utils/eol-conversion.spec.ts index 678fdb2d8e..19151e1c2e 100644 --- a/tests/utils/eol-conversion.spec.ts +++ b/tests/utils/eol-conversion.spec.ts @@ -17,7 +17,7 @@ import { expect } from 'chai'; import { promises as fs } from 'fs'; -import * as path from 'path'; +import path from 'path'; import { convertEolInPlace, diff --git a/tests/utils/helpers.spec.ts b/tests/utils/helpers.spec.ts index 88d96a7820..49081f60aa 100644 --- a/tests/utils/helpers.spec.ts +++ b/tests/utils/helpers.spec.ts @@ -17,7 +17,7 @@ import { expect } from 'chai'; -import { getProxyConfig } from '../../build/utils/helpers'; +import { getProxyConfig } from '../../build/utils/helpers.js'; describe('getProxyConfig() function', function () { let originalProxyConfig: [boolean, object | undefined]; diff --git a/tests/utils/image-manager/image-manager.spec.ts b/tests/utils/image-manager/image-manager.spec.ts index 7d56640fcd..4bf1d633d5 100644 --- a/tests/utils/image-manager/image-manager.spec.ts +++ b/tests/utils/image-manager/image-manager.spec.ts @@ -3,11 +3,11 @@ import { expect } from 'chai'; import { stub } from 'sinon'; import * as tmp from 'tmp'; import { delay } from '../../utils'; -import * as fs from 'fs'; +import fs from 'fs'; import * as fsAsync from 'fs/promises'; -import * as stringToStream from 'string-to-stream'; +import stringToStream from 'string-to-stream'; import { Writable as WritableStream } from 'stream'; -import * as imageManager from '../../../build/utils/image-manager'; +import * as imageManager from '../../../build/utils/image-manager.js'; import { resolve, extname } from 'path'; import * as mockFs from 'mock-fs'; import * as rimraf from 'rimraf'; @@ -16,7 +16,7 @@ import * as os from 'os'; // Make sure we're all using literally the same instance of balena-sdk // so we can mock out methods called by the real code -import { getBalenaSdk } from '../../../build/utils/lazy'; +import { getBalenaSdk } from '../../../build/utils/lazy.js'; const balena = getBalenaSdk(); const fsExistsAsync = promisify(fs.exists); diff --git a/tests/utils/normalization.spec.ts b/tests/utils/normalization.spec.ts index 6cbf146a97..6419c05410 100644 --- a/tests/utils/normalization.spec.ts +++ b/tests/utils/normalization.spec.ts @@ -18,7 +18,7 @@ import { BalenaReleaseNotFound } from 'balena-errors'; import { expect } from 'chai'; import * as sinon from 'sinon'; -import { ExpectedError } from '../../build/errors'; +import { ExpectedError } from '../../build/errors.js'; import { disambiguateReleaseParam } from '../../build/utils/normalization'; describe('disambiguateReleaseParam() function', () => { diff --git a/tests/utils/tarDirectory.spec.ts b/tests/utils/tarDirectory.spec.ts index cdf582a654..81e2a69c7c 100644 --- a/tests/utils/tarDirectory.spec.ts +++ b/tests/utils/tarDirectory.spec.ts @@ -16,10 +16,10 @@ */ import { expect } from 'chai'; -import * as path from 'path'; +import path from 'path'; import * as tar from 'tar-stream'; -import { tarDirectory } from '../../build/utils/compose_ts'; +import { tarDirectory } from '../../build/utils/compose_ts.js'; import { setupDockerignoreTestData } from '../projects'; const repoPath = path.normalize(path.join(__dirname, '..', '..')); diff --git a/tests/utils/validation.spec.ts b/tests/utils/validation.spec.ts index 0d77ff5932..8159dc8795 100644 --- a/tests/utils/validation.spec.ts +++ b/tests/utils/validation.spec.ts @@ -17,7 +17,7 @@ import * as chaiAsPromised from 'chai-as-promised'; import * as chai from 'chai'; -import { ExpectedError } from '../../build/errors'; +import { ExpectedError } from '../../build/errors.js'; import * as v from '../../build/utils/validation'; chai.use(chaiAsPromised); diff --git a/tsconfig.json b/tsconfig.json index 8632c46d02..d1599c66a8 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,8 +1,9 @@ { "compilerOptions": { "declaration": true, - "module": "commonjs", - "target": "es2018", + "module": "NodeNext", + "moduleResolution": "NodeNext", + "target": "ES2022", "outDir": "build", "strict": true, "strictPropertyInitialization": false, diff --git a/typings/pkg/index.d.ts b/typings/pkg/index.d.ts deleted file mode 100644 index 21ca7705e5..0000000000 --- a/typings/pkg/index.d.ts +++ /dev/null @@ -1,23 +0,0 @@ -/** - * @license - * Copyright 2019 Balena Ltd. - * - * 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. - */ - -// tslint:disable-next-line:no-namespace -declare namespace NodeJS { - interface Process { - pkg?: boolean; - } -} diff --git a/typings/windosu/index.d.ts b/typings/windosu/index.d.ts new file mode 100644 index 0000000000..7665cc9bf8 --- /dev/null +++ b/typings/windosu/index.d.ts @@ -0,0 +1,3 @@ +declare module 'windosu' { + export function exec(command: string): Promise; +}