@zuplo/cli 1.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1 @@
1
+ # Zuplo CLI
package/dist/cli.js ADDED
@@ -0,0 +1,15 @@
1
+ import * as dotenv from "dotenv";
2
+ dotenv.config();
3
+ import { hideBin } from "yargs/helpers";
4
+ import yargs from "yargs/yargs";
5
+ import deploy from "./cmds/deploy.js";
6
+ import test from "./cmds/test.js";
7
+ void yargs(hideBin(process.argv))
8
+ .env("ZUPLO")
9
+ .version(false)
10
+ .command(deploy)
11
+ .command(test)
12
+ .demandCommand()
13
+ .strictCommands()
14
+ .help().argv;
15
+ //# sourceMappingURL=cli.js.map
@@ -0,0 +1,30 @@
1
+ import { validDeployDirectoryValidator } from "../common/validators/file-system-validator.js";
2
+ import { YargsChecker } from "../common/validators/lib.js";
3
+ import { deploy } from "../deploy/handler.js";
4
+ export default {
5
+ desc: "Deploys current Git branch of the current directory.",
6
+ command: "deploy [--apiKey]",
7
+ builder: (yargs) => {
8
+ return yargs
9
+ .option("apiKey", {
10
+ type: "string",
11
+ describe: "The API Key from Zuplo",
12
+ envVar: "API_KEY",
13
+ })
14
+ .demandOption(["apiKey"])
15
+ .option("dir", {
16
+ type: "string",
17
+ describe: "The directory containing your zup",
18
+ default: ".",
19
+ normalize: true,
20
+ hidden: true,
21
+ })
22
+ .check(async (argv) => {
23
+ return await new YargsChecker(validDeployDirectoryValidator).check(argv.dir);
24
+ });
25
+ },
26
+ handler: async (argv) => {
27
+ await deploy(argv);
28
+ },
29
+ };
30
+ //# sourceMappingURL=deploy.js.map
@@ -0,0 +1,28 @@
1
+ import { validTestDirectoryValidator } from "../common/validators/file-system-validator.js";
2
+ import { YargsChecker } from "../common/validators/lib.js";
3
+ import { test } from "../test/handler.js";
4
+ export default {
5
+ desc: "Runs the tests under /tests against the [endpoint]",
6
+ command: "test [endpoint]",
7
+ builder: (yargs) => {
8
+ return yargs
9
+ .positional("endpoint", {
10
+ type: "string",
11
+ describe: "The URL of the zup to test against",
12
+ })
13
+ .option("dir", {
14
+ type: "string",
15
+ describe: "The directory containing your zup",
16
+ default: ".",
17
+ normalize: true,
18
+ hidden: true,
19
+ })
20
+ .check(async (argv) => {
21
+ return await new YargsChecker(validTestDirectoryValidator).check(argv.dir);
22
+ });
23
+ },
24
+ handler: async (argv) => {
25
+ await test(argv);
26
+ },
27
+ };
28
+ //# sourceMappingURL=test.js.map
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=alias.js.map
@@ -0,0 +1,4 @@
1
+ export const DEPLOYER_METADATA_FILE = "deployer.json";
2
+ export const TEST_IN_FOLDER = "tests";
3
+ export const TEST_OUT_FOLDER = ".zuplo/__tests__";
4
+ //# sourceMappingURL=constants.js.map
@@ -0,0 +1,8 @@
1
+ import * as Pino from "pino";
2
+ export const logger = Pino.pino({
3
+ level: process.env.LOG_LEVEL || "warn",
4
+ transport: {
5
+ target: "pino-pretty",
6
+ },
7
+ });
8
+ //# sourceMappingURL=logger.js.map
@@ -0,0 +1,4 @@
1
+ export function printToConsole(message, ...optionalParams) {
2
+ console.log(message, ...optionalParams);
3
+ }
4
+ //# sourceMappingURL=output.js.map
@@ -0,0 +1,8 @@
1
+ class Settings {
2
+ get ZUPLO_DEVELOPER_API_ENDPOINT() {
3
+ return process.env.ZUPLO_DEVELOPER_API_ENDPOINT ?? "https://dev.zuplo.com";
4
+ }
5
+ }
6
+ const settings = new Settings();
7
+ export default settings;
8
+ //# sourceMappingURL=settings.js.map
@@ -0,0 +1,82 @@
1
+ import fg from "fast-glob";
2
+ import { existsSync } from "node:fs";
3
+ import { simpleGit } from "simple-git";
4
+ import { TEST_IN_FOLDER } from "../constants.js";
5
+ import { CompositeValidator } from "./lib.js";
6
+ export class NotAGitRepoError extends Error {
7
+ constructor() {
8
+ super("Invalid directory: The current directory is not a Git repository.");
9
+ Object.setPrototypeOf(this, NotAGitRepoError.prototype);
10
+ }
11
+ }
12
+ export class NotAZuploProject extends Error {
13
+ constructor() {
14
+ super("Invalid directory: The current directory is not a Zuplo project.");
15
+ Object.setPrototypeOf(this, NotAZuploProject.prototype);
16
+ }
17
+ }
18
+ export class ZuploProjectMissingTests extends Error {
19
+ constructor() {
20
+ super("Invalid directory: The current directory does not contain any tests (*.test.ts) in the /tests folder. Create a at least one test of the form some-name.test.ts");
21
+ Object.setPrototypeOf(this, ZuploProjectMissingTests.prototype);
22
+ }
23
+ }
24
+ export class GitVersionControlValidator {
25
+ async validate(dir) {
26
+ try {
27
+ await simpleGit({ baseDir: dir }).status();
28
+ return { ok: true };
29
+ }
30
+ catch (err) {
31
+ return {
32
+ ok: false,
33
+ error: new NotAGitRepoError(),
34
+ };
35
+ }
36
+ }
37
+ }
38
+ export class ZuploProjectValidator {
39
+ async validate(dir) {
40
+ try {
41
+ if (existsSync(`${dir}/config/routes.json`)) {
42
+ return { ok: true };
43
+ }
44
+ else {
45
+ return {
46
+ ok: false,
47
+ error: new NotAZuploProject(),
48
+ };
49
+ }
50
+ }
51
+ catch (err) {
52
+ return {
53
+ ok: false,
54
+ error: err,
55
+ };
56
+ }
57
+ }
58
+ }
59
+ export class ZuploProjectHasTestsValidator {
60
+ async validate(dir) {
61
+ try {
62
+ if (fg.sync(`${dir}/${TEST_IN_FOLDER}/**/*.test.ts`).length >= 1) {
63
+ return { ok: true };
64
+ }
65
+ else {
66
+ return {
67
+ ok: false,
68
+ error: new ZuploProjectMissingTests(),
69
+ };
70
+ }
71
+ }
72
+ catch (err) {
73
+ return {
74
+ ok: false,
75
+ error: err,
76
+ };
77
+ }
78
+ }
79
+ }
80
+ export const validDeployDirectoryValidator = new CompositeValidator(new GitVersionControlValidator(), new ZuploProjectValidator());
81
+ export const validTestDirectoryValidator = new CompositeValidator(new ZuploProjectValidator(), new ZuploProjectHasTestsValidator());
82
+ //# sourceMappingURL=file-system-validator.js.map
@@ -0,0 +1,31 @@
1
+ export class CompositeValidator {
2
+ validators = new Array();
3
+ constructor(...validators) {
4
+ this.validators = validators;
5
+ }
6
+ async validate(what) {
7
+ for (const rule of this.validators) {
8
+ const result = await rule.validate(what);
9
+ if (!result.ok) {
10
+ return result;
11
+ }
12
+ }
13
+ return { ok: true };
14
+ }
15
+ }
16
+ export class YargsChecker {
17
+ validator;
18
+ constructor(validator) {
19
+ this.validator = validator;
20
+ }
21
+ async check(what) {
22
+ const result = await this.validator.validate(what);
23
+ if (!result.ok) {
24
+ return result.error.message;
25
+ }
26
+ else {
27
+ return true;
28
+ }
29
+ }
30
+ }
31
+ //# sourceMappingURL=lib.js.map
@@ -0,0 +1,93 @@
1
+ import ignore from "ignore";
2
+ import { existsSync, mkdirSync, readFileSync, writeFileSync, } from "node:fs";
3
+ import { join, relative, sep } from "node:path";
4
+ import { simpleGit } from "simple-git";
5
+ import * as tar from "tar";
6
+ import * as temp from "temp";
7
+ import { DEPLOYER_METADATA_FILE } from "../common/constants.js";
8
+ import { logger } from "../common/logger.js";
9
+ export async function archive(dir) {
10
+ const tarball = temp.path({ suffix: ".tar.gz" });
11
+ const ignoreFn = createIgnoreFunction(dir);
12
+ const normalizedDir = join(relative(process.cwd(), dir));
13
+ const metadata = await prepareDeployerMetadata(dir);
14
+ await tar.create({
15
+ gzip: true,
16
+ file: tarball,
17
+ filter: (path, stat) => {
18
+ const stats = stat;
19
+ const normalizedPath = stats.isDirectory()
20
+ ? join(relative(process.cwd(), path), sep)
21
+ : join(relative(process.cwd(), path));
22
+ if (normalizedPath === "/") {
23
+ return true;
24
+ }
25
+ if (normalizedPath === ".zuplo/") {
26
+ return true;
27
+ }
28
+ if (normalizedPath === `.zuplo/${DEPLOYER_METADATA_FILE}`) {
29
+ return true;
30
+ }
31
+ const result = ignoreFn.ignores(normalizedPath);
32
+ logger.trace(`${normalizedPath} ignored: ${result}`);
33
+ return !result;
34
+ },
35
+ }, [normalizedDir]);
36
+ return {
37
+ tarball,
38
+ metadata,
39
+ };
40
+ }
41
+ function createIgnoreFunction(normalizedDir) {
42
+ const baseIgnore = ignore().add(".git/");
43
+ if (existsSync(`${normalizedDir}/.zupignore`)) {
44
+ const zupignorePath = `${normalizedDir}/.zupignore`;
45
+ logger.debug(`Using ${zupignorePath} to filter out files`);
46
+ return baseIgnore.add(readFileSync(zupignorePath).toString());
47
+ }
48
+ else if (existsSync(`${normalizedDir}/.gitignore`)) {
49
+ const gitignorePath = `${normalizedDir}/.gitignore`;
50
+ logger.debug(`Using ${gitignorePath} to filter out files`);
51
+ return baseIgnore.add(readFileSync(gitignorePath).toString());
52
+ }
53
+ else {
54
+ logger.debug("Didn't find a .gitignore or .zupignore file. Defaulting to ignoring .git and node_modules.");
55
+ return baseIgnore.add("node_modules/");
56
+ }
57
+ }
58
+ async function prepareDeployerMetadata(dir) {
59
+ const metadata = await generateMetadata(dir);
60
+ await writeGeneratedMetadata(dir, metadata);
61
+ return metadata;
62
+ }
63
+ async function generateMetadata(dir) {
64
+ const git = simpleGit({ baseDir: dir });
65
+ const status = await git.status();
66
+ if (!status.current) {
67
+ throw new Error("Invalid state: Directory is in detached head state.");
68
+ }
69
+ const branch = status.current.trim();
70
+ const sha = (await git.revparse(["HEAD"])).trim();
71
+ const repoUrl = (await git.listRemote(["--get-url"])).trim();
72
+ return {
73
+ branch,
74
+ repoUrl,
75
+ sha,
76
+ };
77
+ }
78
+ async function writeGeneratedMetadata(dir, metadata) {
79
+ try {
80
+ mkdirSync(`${dir}/.zuplo`);
81
+ }
82
+ catch (err) {
83
+ if (err.code === "EEXIST") {
84
+ }
85
+ else {
86
+ throw err;
87
+ }
88
+ }
89
+ await writeFileSync(`${dir}/.zuplo/${DEPLOYER_METADATA_FILE}`, JSON.stringify(metadata, null, 2), {
90
+ flag: "w",
91
+ });
92
+ }
93
+ //# sourceMappingURL=archive.js.map
@@ -0,0 +1,14 @@
1
+ import { readFileSync, statSync } from "node:fs";
2
+ export async function upload(tarballPath, url) {
3
+ const stats = statSync(tarballPath);
4
+ const fileSizeInBytes = stats.size;
5
+ const bufferContent = readFileSync(tarballPath);
6
+ return fetch(url, {
7
+ method: "PUT",
8
+ headers: {
9
+ "Content-length": fileSizeInBytes.toString(),
10
+ },
11
+ body: bufferContent,
12
+ });
13
+ }
14
+ //# sourceMappingURL=file-upload.js.map
@@ -0,0 +1,48 @@
1
+ import chalk from "chalk";
2
+ import { logger } from "../common/logger.js";
3
+ import { printToConsole } from "../common/output.js";
4
+ import settings from "../common/settings.js";
5
+ import { archive } from "./archive.js";
6
+ import { upload } from "./file-upload.js";
7
+ export async function deploy(argv) {
8
+ const archiveMetadata = await archive(argv.dir);
9
+ logger.info(`Tarball created locally at ${archiveMetadata}`);
10
+ const whoAmIResponse = await fetch(`${settings.ZUPLO_DEVELOPER_API_ENDPOINT}/v1/who-am-i`, {
11
+ method: "GET",
12
+ headers: {
13
+ Authorization: `Bearer ${argv.apiKey}`,
14
+ },
15
+ });
16
+ if (whoAmIResponse.ok) {
17
+ const { account, project } = await whoAmIResponse.json();
18
+ const uploadUrlResponse = await fetch(`${settings.ZUPLO_DEVELOPER_API_ENDPOINT}/v1/accounts/${account}/projects/${project}/sources`, {
19
+ method: "POST",
20
+ headers: {
21
+ Authorization: `Bearer ${argv.apiKey}`,
22
+ },
23
+ });
24
+ if (uploadUrlResponse.ok) {
25
+ const { uploadUrl } = await uploadUrlResponse.json();
26
+ const uploadResponse = await upload(archiveMetadata.tarball, uploadUrl);
27
+ if (uploadResponse.ok) {
28
+ printToConsole(chalk.green.bold(`Deploying the current branch ${archiveMetadata.metadata.branch} to project ${project} on account ${account}...`));
29
+ }
30
+ else {
31
+ logger.error({
32
+ status: uploadResponse.status,
33
+ statusText: uploadResponse.statusText,
34
+ }, "Failed to upload source to cloud storage");
35
+ }
36
+ }
37
+ else {
38
+ logger.error({
39
+ status: uploadUrlResponse.status,
40
+ statusText: uploadUrlResponse.statusText,
41
+ }, "Failed to retrieve uploadUrl");
42
+ }
43
+ }
44
+ else {
45
+ logger.error({ status: whoAmIResponse.status, statusText: whoAmIResponse.statusText }, "Failed to determine who-am-i");
46
+ }
47
+ }
48
+ //# sourceMappingURL=handler.js.map
@@ -0,0 +1,20 @@
1
+ import { TEST_OUT_FOLDER } from "../common/constants.js";
2
+ import { denoTestPrepPlugin } from "./esbuild-plugins/deno-test-prep-plugin.js";
3
+ export function generateBuildOptionsForTest(argv) {
4
+ return {
5
+ outdir: `${argv.dir}/${TEST_OUT_FOLDER}`,
6
+ bundle: true,
7
+ treeShaking: true,
8
+ format: "esm",
9
+ outExtension: {
10
+ ".js": ".ts",
11
+ },
12
+ plugins: [
13
+ denoTestPrepPlugin(argv, {
14
+ "@zuplo/test": "",
15
+ chai: "https://cdn.skypack.dev/chai@4.3.4?dts",
16
+ }),
17
+ ],
18
+ };
19
+ }
20
+ //# sourceMappingURL=esbuild-config.js.map
@@ -0,0 +1,22 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.denoTestPrepPlugin = void 0;
4
+ function denoTestPrepPlugin(options) {
5
+ const aliases = Object.keys(options);
6
+ const re = new RegExp(`^(${aliases.map((x) => escapeRegExp(x)).join("|")})$`);
7
+ return {
8
+ name: "alias",
9
+ setup(build) {
10
+ build.onResolve({ filter: re }, (args) => ({
11
+ path: options[args.path],
12
+ namespace: "deno-url",
13
+ external: true,
14
+ }));
15
+ },
16
+ };
17
+ }
18
+ exports.denoTestPrepPlugin = denoTestPrepPlugin;
19
+ function escapeRegExp(value) {
20
+ return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
21
+ }
22
+ //# sourceMappingURL=alias.js.map
@@ -0,0 +1,81 @@
1
+ export function denoTestPrepPlugin(argv, options) {
2
+ const aliases = Object.keys(options);
3
+ const re = new RegExp(`^(${aliases.map((x) => escapeRegExp(x)).join("|")})$`);
4
+ return {
5
+ name: "alias",
6
+ setup(build) {
7
+ build.onResolve({ filter: re }, (args) => {
8
+ if (/@zuplo\/test/.test(args.path)) {
9
+ return {
10
+ path: args.path,
11
+ namespace: "deno-url",
12
+ };
13
+ }
14
+ else {
15
+ return {
16
+ path: options[args.path],
17
+ namespace: "deno-url",
18
+ external: true,
19
+ };
20
+ }
21
+ });
22
+ build.onLoad({ filter: /.*/, namespace: "deno-url" }, (args) => {
23
+ if (/@zuplo\/test/.test(args.path)) {
24
+ return { contents: generateTestContents(argv), loader: "ts" };
25
+ }
26
+ });
27
+ },
28
+ };
29
+ }
30
+ function escapeRegExp(value) {
31
+ return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
32
+ }
33
+ function generateTestContents(argv) {
34
+ return `
35
+
36
+ export const TestHelper = {
37
+ TEST_URL: "${argv.endpoint ?? undefined}"
38
+ }
39
+
40
+ import {
41
+ afterAll,
42
+ afterEach,
43
+ beforeAll,
44
+ beforeEach,
45
+ describe as originalDescribe,
46
+ it,
47
+ } from "https://deno.land/std@0.151.0/testing/bdd.ts";
48
+
49
+ // We want to be able to disable test sanitizers by default to
50
+ // make tests easier/more familiar to write.
51
+
52
+ function describe<T>(
53
+ name: string,
54
+ fn: () => void | Promise<void>,
55
+ ): TestSuite<T> {
56
+ return originalDescribe(name, {
57
+ sanitizeExit: false,
58
+ sanitizeOps: false,
59
+ sanitizeResources: false,
60
+ }, fn);
61
+ }
62
+
63
+ describe.only = function describeOnly<T>(
64
+ name: string,
65
+ fn: () => void | Promise<void>,
66
+ ): TestSuite<T> {
67
+ return originalDescribe.only(name, fn);
68
+ };
69
+
70
+ describe.ignore = function describeIgnore<T>(
71
+ name: string,
72
+ fn: () => void | Promise<void>,
73
+ ): TestSuite<T> {
74
+ return originalDescribe.ignore(name, fn);
75
+ };
76
+
77
+ export {afterAll, afterEach, beforeAll, beforeEach, describe, it};
78
+
79
+ `;
80
+ }
81
+ //# sourceMappingURL=deno-test-prep-plugin.js.map
@@ -0,0 +1,27 @@
1
+ import fg from "fast-glob";
2
+ import { promisify } from "node:util";
3
+ import rimraf from "rimraf";
4
+ import { TEST_IN_FOLDER, TEST_OUT_FOLDER } from "../common/constants.js";
5
+ import { logger } from "../common/logger.js";
6
+ import { generateBuildOptionsForTest } from "./esbuild-config.js";
7
+ import { runTests } from "./invoke-test.js";
8
+ const rimrafp = promisify(rimraf);
9
+ import esbuild from "esbuild";
10
+ export async function test(argv) {
11
+ await rimrafp(`${argv.dir}/${TEST_OUT_FOLDER}`);
12
+ const result = await esbuild.build({
13
+ ...generateBuildOptionsForTest(argv),
14
+ entryPoints: fg.sync(`${argv.dir}/${TEST_IN_FOLDER}/**/*.test.ts`),
15
+ });
16
+ if (result.warnings.length > 0) {
17
+ logger.debug(result.warnings);
18
+ }
19
+ if (result.errors.length > 0) {
20
+ logger.error(result.errors, `Failed to build the test files in ${argv.dir}/${TEST_IN_FOLDER}`);
21
+ }
22
+ else {
23
+ const { exitCode } = await runTests(argv);
24
+ process.exit(exitCode);
25
+ }
26
+ }
27
+ //# sourceMappingURL=handler.js.map
@@ -0,0 +1,51 @@
1
+ import { execa } from "execa";
2
+ import { existsSync } from "node:fs";
3
+ import { dirname, resolve } from "node:path";
4
+ import { fileURLToPath } from "node:url";
5
+ import { TEST_OUT_FOLDER } from "../common/constants.js";
6
+ import { logger } from "../common/logger.js";
7
+ export class MissingDenoExecutableError extends Error {
8
+ constructor() {
9
+ super("Missing executable: Cannot locate deno executable");
10
+ Object.setPrototypeOf(this, MissingDenoExecutableError.prototype);
11
+ }
12
+ }
13
+ async function locateDenoExecutable() {
14
+ return locateDeno(dirname(fileURLToPath(import.meta.url)));
15
+ }
16
+ async function locateDeno(dir) {
17
+ if (dir === ".") {
18
+ return undefined;
19
+ }
20
+ const pathToDeno = resolve(dir, "node_modules", "deno-bin", "bin", "deno");
21
+ if (await existsSync(pathToDeno)) {
22
+ logger.debug(`Path to deno: ${pathToDeno}`);
23
+ return pathToDeno;
24
+ }
25
+ return locateDeno(dirname(dir));
26
+ }
27
+ export async function runTests(argv) {
28
+ const denoExecutable = await locateDenoExecutable();
29
+ if (denoExecutable) {
30
+ const denoProcess = execa(denoExecutable, [
31
+ "test",
32
+ "--allow-net",
33
+ "--no-check",
34
+ `${argv.dir}/${TEST_OUT_FOLDER}`,
35
+ ]);
36
+ denoProcess.stdout?.pipe(process.stdout);
37
+ denoProcess.stderr?.pipe(process.stderr);
38
+ try {
39
+ const result = await denoProcess;
40
+ return result;
41
+ }
42
+ catch (err) {
43
+ logger.debug(err);
44
+ return { exitCode: err.exitCode };
45
+ }
46
+ }
47
+ else {
48
+ throw new MissingDenoExecutableError();
49
+ }
50
+ }
51
+ //# sourceMappingURL=invoke-test.js.map
@@ -0,0 +1,4 @@
1
+ export function hmm() { }
2
+ hmm.shit = function () { };
3
+ hmm.weird = function () { };
4
+ //# sourceMappingURL=hmm.js.map
package/package.json ADDED
@@ -0,0 +1,61 @@
1
+ {
2
+ "name": "@zuplo/cli",
3
+ "version": "1.4.0",
4
+ "type": "module",
5
+ "repository": "https://github.com/zuplo/cli",
6
+ "author": "Zuplo, Inc.",
7
+ "license": "Copyright 2022",
8
+ "scripts": {
9
+ "build": "tsc --build"
10
+ },
11
+ "engines": {
12
+ "node": ">=18.0.0"
13
+ },
14
+ "bin": {
15
+ "zup": "zup.js",
16
+ "zup-debug": "zup-debug.js"
17
+ },
18
+ "lint-staged": {
19
+ "**/*.{ts,json,md,yml,js,css,html}": [
20
+ "prettier --write"
21
+ ],
22
+ "**/*.{ts,js}": [
23
+ "eslint --cache --fix --ignore-path .eslintignore"
24
+ ]
25
+ },
26
+ "devDependencies": {
27
+ "@types/node": "^18.11.5",
28
+ "@types/rimraf": "^3.0.2",
29
+ "@types/tar": "^6.1.3",
30
+ "@types/temp": "^0.9.1",
31
+ "@types/yargs": "^17.0.13",
32
+ "@typescript-eslint/eslint-plugin": "^5.42.0",
33
+ "@typescript-eslint/parser": "^5.42.0",
34
+ "eslint": "^8.26.0",
35
+ "eslint-config-prettier": "^8.5.0",
36
+ "eslint-plugin-import": "^2.26.0",
37
+ "eslint-plugin-node": "^11.1.0",
38
+ "eslint-plugin-unicorn": "^44.0.2",
39
+ "husky": "^8.0.1",
40
+ "lint-staged": "^13.0.3",
41
+ "prettier": "^2.7.1",
42
+ "prettier-plugin-organize-imports": "^3.1.1",
43
+ "typescript": "^4.8.4"
44
+ },
45
+ "dependencies": {
46
+ "chalk": "^5.1.2",
47
+ "deno-bin": "^1.27.1",
48
+ "dotenv": "^16.0.3",
49
+ "esbuild": "^0.15.13",
50
+ "execa": "^6.1.0",
51
+ "fast-glob": "^3.2.12",
52
+ "ignore": "^5.2.0",
53
+ "pino": "^8.7.0",
54
+ "pino-pretty": "^9.1.1",
55
+ "rimraf": "^3.0.2",
56
+ "simple-git": "^3.14.1",
57
+ "tar": "^6.1.11",
58
+ "temp": "^0.9.4",
59
+ "yargs": "^17.6.0"
60
+ }
61
+ }
package/zup-debug.js ADDED
@@ -0,0 +1,4 @@
1
+ #!/usr/bin/env node --inspect-brk
2
+ /* eslint-disable */
3
+ process.removeAllListeners("warning");
4
+ import "./dist/cli.js";
package/zup.js ADDED
@@ -0,0 +1,4 @@
1
+ #!/usr/bin/env node
2
+ /* eslint-disable */
3
+ process.removeAllListeners("warning");
4
+ import "./dist/cli.js";