New Case Study:See how Anthropic automated 95% of dependency reviews with Socket.Learn More
Socket
Sign inDemoInstall
Socket

@multiplatform.one/cli

Package Overview
Dependencies
Maintainers
0
Versions
61
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@multiplatform.one/cli - npm Package Compare versions

Comparing version 2.1.7 to 2.1.8

types/.tsbuildinfo

31

package.json
{
"name": "@multiplatform.one/cli",
"version": "2.1.7",
"version": "2.1.8",
"author": "BitSpur <support@bitspur.com> (https://bitspur.com)",

@@ -14,11 +14,11 @@ "contributors": [

"source": "src/index.ts",
"types": "lib/index.d.mts",
"types": "types/index.d.ts",
"exports": {
".": {
"import": "./lib/index.mjs",
"types": "./lib/index.d.mts"
"types": "./types/index.d.ts"
},
"./bin/multiplatformOne": {
"import": "./lib/bin/multiplatformOne.mjs",
"types": "./lib/bin/multiplatformOne.d.mts"
"types": "./types/bin/multiplatformOne.d.ts"
},

@@ -34,3 +34,4 @@ "./package.json": "./package.json"

"scripts",
"src"
"src",
"types"
],

@@ -53,16 +54,15 @@ "license": "Apache-2.0",

"devDependencies": {
"@multiplatform.one/utils": "0.1.8",
"@types/inquirer": "^9.0.7",
"@types/node": "~20.12.13",
"tsup": "^8.3.0",
"typescript": "^5.6.2"
"@types/node": "~20.12.14",
"tsup": "^8.3.5",
"typescript": "~5.3.3"
},
"dependencies": {
"axios": "^1.7.7",
"@multiplatform.one/utils": "0.1.9",
"commander": "^9.5.0",
"dotenv": "^16.4.5",
"execa": "^9.4.1",
"dotenv": "^16.4.7",
"execa": "^9.5.2",
"inquirer": "^9.3.7",
"ora": "^8.1.0",
"pg": "^8.13.0"
"ora": "^8.1.1",
"yaml": "^2.7.0"
},

@@ -75,4 +75,5 @@ "transpileModules": [

"scripts": {
"build": "tsup"
"build": "rm -rf lib types 2>/dev/null && tsc -b --emitDeclarationOnly && tsup",
"typecheck": "tsc --noEmit"
}
}

@@ -1,8 +0,8 @@

/**
/*
* File: /src/bin/multiplatformOne.ts
* Project: @multiplatform.one/cli
* File Created: 01-01-1970 00:00:00
* File Created: 10-01-2025 21:02:36
* Author: Clay Risser
* -----
* BitSpur (c) Copyright 2021 - 2024
* BitSpur (c) Copyright 2021 - 2025
*

@@ -27,3 +27,11 @@ * Licensed under the Apache License, Version 2.0 (the "License");

import { fileURLToPath } from "node:url";
import axios from "axios";
import {
formatServiceList,
projectRoot,
waitForApi,
waitForFrappe,
waitForKeycloak,
waitForPostgres,
waitServices,
} from "@multiplatform.one/utils/dev";
import { program } from "commander";

@@ -34,6 +42,6 @@ import dotenv from "dotenv";

import ora from "ora";
import pg from "pg";
import type { CookieCutterConfig } from "../types";
const availableBackends = ["api", "frappe"];
const availableServices = ["api", "frappe", "solana", "ethereum", "sui"];
const defaultDotenvPath = path.resolve(projectRoot, ".env");
const availablePlatforms = [

@@ -43,5 +51,8 @@ "electron",

"keycloak",
"next",
"one",
"storybook",
"storybook-expo",
"vocs",
"vscode",
"webext",
];

@@ -78,9 +89,8 @@

)
.option("-p, --platforms <platforms>", "platforms to keep")
.option("-b, --backends <backends>", "backends to keep")
.option("-p, --platforms <platforms>", "platforms to use")
.option("-s, --services <services>", "services to use")
.argument("[name]", "the name of the project", "")
.description("init multiplatform.one")
.action(async (name, options) => {
let { backends, platforms } = options;
let { services, platforms } = options;
if (

@@ -108,15 +118,14 @@ (

}
if (!backends) {
const backendsResult = (
if (!services) {
const servicesResult = (
await inquirer.prompt([
{
message: "What backends are you using?",
name: "backends",
message: "What services are you using?",
name: "services",
type: "checkbox",
choices: availableBackends.map((name) => ({ name })),
choices: availableServices.map((name) => ({ name })),
},
])
).backends;
backends = backendsResult.join(",");
).services;
services = servicesResult.join(",");
}

@@ -137,3 +146,3 @@ if (!platforms) {

const cookieCutterConfig: CookieCutterConfig = {
default_context: { name, platforms, backends },
default_context: { name, platforms, services },
};

@@ -186,16 +195,16 @@ const cookieCutterConfigFile = path.join(

.option("-p, --platforms <platforms>", "platforms to keep")
.option("-b, --backends <backends>", "backends to keep")
.option("-s, --services <services>", "services to keep")
.description("update multiplatform.one")
.action(async (options) => {
let { backends, platforms } = options;
if (!backends) {
const backendsResult = await inquirer.prompt([
let { services, platforms } = options;
if (!services) {
const servicesResult = await inquirer.prompt([
{
message: "What backends are you using?",
name: "backends",
message: "What services are you using?",
name: "services",
type: "checkbox",
choices: availableBackends.map((name) => ({ name })),
choices: availableServices.map((name) => ({ name })),
},
]);
backends = backendsResult.backends.join(",");
services = servicesResult.services.join(",");
}

@@ -253,3 +262,5 @@ if (!platforms) {

if (name) {
cookieCutterConfig = { default_context: { name, backends, platforms } };
cookieCutterConfig = {
default_context: { name, services, platforms },
};
}

@@ -292,3 +303,2 @@ }

const waitServices = ["api", "frappe", "postgres", "keycloak"];
program

@@ -305,134 +315,389 @@ .command("wait")

.action(async (servicesString, options) => {
dotenv.config({ path: options.dotenv });
dotenv.config({ path: options.dotenv || defaultDotenvPath });
const interval = Number.parseInt(options.interval);
const timeout = Number.parseInt(options.timeout);
const services: string[] = servicesString.split(",");
const unreadyServices = [...services];
const spinner = ora(
`waiting for ${formatServiceList(unreadyServices)}`,
).start();
function updateSpinner(readyService: string) {
unreadyServices.splice(unreadyServices.indexOf(readyService), 1);
spinner.stop();
spinner.succeed(`${readyService} is ready`);
if (!unreadyServices.length) return;
spinner.start(`waiting for ${formatServiceList(unreadyServices)}`);
}
let timeoutId: NodeJS.Timeout;
try {
await Promise.race([
Promise.all(
services.map(async (service) => {
switch (service) {
case "api": {
await waitForApi(interval);
updateSpinner("api");
return;
}
case "frappe": {
await waitForFrappe(interval);
updateSpinner("frappe");
return;
}
case "postgres": {
await waitForPostgres(interval);
updateSpinner("postgres");
return;
}
case "keycloak": {
await waitForKeycloak(interval);
updateSpinner("keycloak");
return;
}
}
ora(
`available services are ${formatServiceList(waitServices)}`,
).fail();
}),
),
new Promise((_, reject) => {
timeoutId = setTimeout(() => reject(new Error("Timeout")), timeout);
}),
]);
await waitWithSpinner(services, { interval, timeout });
} catch (err) {
if (err instanceof Error && err.message === "Timeout") {
spinner.fail(
`${formatServiceList(unreadyServices)} timed out after ${timeout}ms`,
);
} else {
spinner.fail(err);
}
process.exit(1);
} finally {
clearTimeout(timeoutId);
}
});
function formatServiceList(services: string[]): string {
if (services.length === 1) return services[0];
if (services.length === 2) return `${services[0]} and ${services[1]}`;
return `${services.slice(0, -1).join(", ")} and ${services[services.length - 1]}`;
}
program
.command("mesh")
.description("start the mesh server")
.option("-a, --api", "use api", false)
.option("-e, --dotenv <dotenv>", "dotenv file path", ".env")
.option("-f, --frappe", "use frappe", false)
.option("-i, --interval <interval>", "interval to wait for", "1000")
.option("-p, --port <port>", "port to run mesh on", "5002")
.option("-t, --timeout <timeout>", "timeout to wait for", "600000")
.action(async (options) => {
dotenv.config({ path: options.dotenv || defaultDotenvPath });
process.env.UWS_HTTP_MAX_HEADERS_SIZE = "16384";
if (options.frappe || options.api) {
process.env.MESH_API = options.api ? "1" : "0";
process.env.MESH_FRAPPE = options.frappe ? "1" : "0";
}
if (
!(await fs
.stat(path.resolve(projectRoot, "app/main.ts"))
.catch(() => false))
) {
process.env.MESH_APP = "0";
}
if (
!(await fs
.stat(path.resolve(projectRoot, "frappe/package.json"))
.catch(() => false))
) {
process.env.MESH_FRAPPE = "0";
}
const services = [
...(process.env.MESH_API === "1" ? ["api"] : []),
...(process.env.MESH_FRAPPE === "1" ? ["frappe"] : []),
];
if (services.length > 0) {
const interval = Number.parseInt(options.interval);
const timeout = Number.parseInt(options.timeout);
try {
await waitWithSpinner(services, { interval, timeout });
} catch (err) {
process.exit(1);
}
}
await execa(
"mesh",
[
"dev",
"--port",
Number(options.port || process.env.MESH_PORT || 5002).toString(),
],
{
stdio: "inherit",
},
);
});
program.parse(process.argv);
program
.command("build")
.argument(
"[args...]",
`build to run: ${[...availableServices, "packages"].join(", ")} (default: all)`,
)
.description("run build command")
.action(async (args: string[]) => {
args = args.flatMap((arg) => arg.split(","));
const packages = args.includes("packages");
const projects = args.filter((arg) => arg !== "packages");
if ((!projects.length && !packages) || packages) {
await execa(
"turbo",
[
"run",
"build",
"--filter",
"'!./platforms/*'",
"--filter",
"'!./api'",
"--filter",
"'!./solana'",
"--filter",
"'!./ethereum'",
"--filter",
"'!./sui'",
],
{
stdio: "inherit",
shell: true,
cwd: projectRoot,
},
);
}
for (const platform of await fs.readdir("platforms")) {
if (
((!projects.length && !packages) || projects.includes(platform)) &&
(await fs
.access(path.join(projectRoot, "platforms", platform, "package.json"))
.then(
() =>
JSON.parse(
fsSync.readFileSync(
path.join(projectRoot, "platforms", platform, "package.json"),
"utf8",
),
).scripts?.build,
)
.catch(() => false))
) {
await execa("./mkpm", [`${platform}/build`], {
stdio: "inherit",
shell: true,
cwd: projectRoot,
});
}
}
for (const service of availableServices) {
if (
((!projects.length && !packages) || projects.includes(service)) &&
(await fs
.access(path.join(projectRoot, service, "package.json"))
.then(
() =>
JSON.parse(
fsSync.readFileSync(
path.join(projectRoot, service, "package.json"),
"utf8",
),
).scripts?.build,
)
.catch(() => false))
) {
await execa("./mkpm", [`${service}/build`], {
stdio: "inherit",
shell: true,
cwd: projectRoot,
});
}
}
});
async function waitForApi(interval: number) {
try {
const res = await axios.get(
`http://localhost:${process.env.API_PORT || "5001"}/healthz`,
);
if ((res?.status || 500) < 300) {
return;
program
.command("test")
.argument(
"[args...]",
`test to run: ${[...availableServices, "packages"].join(", ")} (default: all)`,
)
.description("run test command")
.action(async (args: string[]) => {
args = args.flatMap((arg) => arg.split(","));
const packages = args.includes("packages");
const projects = args.filter((arg) => arg !== "packages");
if ((!projects.length && !packages) || packages) {
await execa(
"turbo",
[
"run",
"test",
"--filter",
"'!./platforms/*'",
"--filter",
"'!./api'",
"--filter",
"'!./solana'",
"--filter",
"'!./ethereum'",
"--filter",
"'!./sui'",
],
{
stdio: "inherit",
shell: true,
cwd: projectRoot,
},
);
}
} catch (err) {}
await new Promise((resolve) => setTimeout(resolve, interval));
return waitForApi(interval);
}
for (const platform of await fs.readdir("platforms")) {
if (
((!projects.length && !packages) || projects.includes(platform)) &&
(await fs
.access(path.join(projectRoot, "platforms", platform, "package.json"))
.then(
() =>
JSON.parse(
fsSync.readFileSync(
path.join(projectRoot, "platforms", platform, "package.json"),
"utf8",
),
).scripts?.test,
)
.catch(() => false))
) {
await execa("./mkpm", [`${platform}/test`], {
stdio: "inherit",
shell: true,
cwd: projectRoot,
});
}
}
for (const service of availableServices) {
if (
((!projects.length && !packages) || projects.includes(service)) &&
(await fs
.access(path.join(projectRoot, service, "package.json"))
.then(
() =>
JSON.parse(
fsSync.readFileSync(
path.join(projectRoot, service, "package.json"),
"utf8",
),
).scripts?.test,
)
.catch(() => false))
) {
await execa("./mkpm", [`${service}/test`], {
stdio: "inherit",
shell: true,
cwd: projectRoot,
});
}
}
});
async function waitForFrappe(interval: number) {
try {
const res = await axios.get(
`${process.env.FRAPPE_BASE_URL || "http://frappe.localhost"}/api/method/ping`,
);
if ((res?.status || 500) < 300) {
return;
program
.command("check")
.argument("[args...]", "checks to run: spelling, types, lint (default: all)")
.description("run check command")
.action(async (args: string[]) => {
args = args.flatMap((arg) => arg.split(","));
const spelling = !args.length || args.includes("spelling");
const types = !args.length || args.includes("types");
const lint = !args.length || args.includes("lint");
let exitCode = 0;
if (spelling) {
try {
await execa(
"cspell",
[
"--unique",
"`(git ls-files && (git lfs ls-files | cut -d' ' -f3))`",
],
{
stdio: "inherit",
shell: true,
cwd: projectRoot,
},
);
} catch (err) {
if (err instanceof Error && "exitCode" in err) {
exitCode = (err as { exitCode: number }).exitCode;
} else {
exitCode = 1;
}
}
}
} catch (err) {}
await new Promise((resolve) => setTimeout(resolve, interval));
return waitForFrappe(interval);
}
if (types) {
try {
await execa("turbo", ["run", "typecheck"], {
stdio: "inherit",
shell: true,
cwd: projectRoot,
});
} catch (err) {
if (err instanceof Error && "exitCode" in err) {
exitCode = (err as { exitCode: number }).exitCode;
} else {
exitCode = 1;
}
}
}
if (lint) {
try {
await execa(
"biome",
[
"check",
"--fix",
"--unsafe",
"`(git ls-files && (git lfs ls-files | cut -d' ' -f3)) | sort | uniq -u | grep -E '(html)|(s?css)|(md)|(json)|(yaml)|([jt]sx?)$'`",
],
{
stdio: "inherit",
shell: true,
cwd: projectRoot,
},
);
} catch (err) {
if (err instanceof Error && "exitCode" in err) {
exitCode = (err as { exitCode: number }).exitCode;
} else {
exitCode = 1;
}
}
}
process.exit(exitCode);
});
async function waitForPostgres(interval: number) {
const client = new pg.Client({
database: process.env.POSTGRES_DATABASE || "postgres",
host: process.env.POSTGRES_HOSTNAME || "localhost",
password: process.env.POSTGRES_PASSWORD || "postgres",
port: Number.parseInt(process.env.POSTGRES_PORT || "5432"),
user: process.env.POSTGRES_USERNAME || "postgres",
program
.command("count")
.description("count lines of code")
.action(async () => {
await execa(
"cloc",
[
"`(git ls-files && (git lfs ls-files | cut -d' ' -f3)) | sort | uniq -u | grep -E '(html)|(s?css)|(md)|(json)|(yaml)|([jt]sx?)$'`",
],
{
stdio: "inherit",
shell: true,
cwd: projectRoot,
},
);
});
program
.command("generate")
.description("run generate command")
.action(async () => {
await execa("turbo", ["run", "generate"], {
stdio: "inherit",
shell: true,
cwd: projectRoot,
});
});
program.parse(process.argv);
async function waitWithSpinner(
services: string[],
options: { interval?: number; timeout?: number } = {},
) {
const { interval = 1000, timeout = 600000 } = options;
const waitFunctions = {
api: waitForApi,
frappe: waitForFrappe,
postgres: waitForPostgres,
keycloak: waitForKeycloak,
};
const unreadyServices = [...services];
const spinner = ora(
`waiting for ${formatServiceList(unreadyServices)}`,
).start();
function updateSpinner(readyService: string) {
unreadyServices.splice(unreadyServices.indexOf(readyService), 1);
spinner.succeed(`${readyService} is ready`);
if (unreadyServices.length) {
spinner.start(`waiting for ${formatServiceList(unreadyServices)}`);
}
}
let timeoutId: NodeJS.Timeout | undefined;
try {
await client.connect();
while (true) {
try {
await client.query("SELECT 1");
return;
} catch (error) {}
await new Promise((resolve) => setTimeout(resolve, interval));
await Promise.race([
Promise.all(
services.map(async (service) => {
const waitFn = waitFunctions[service];
if (!waitFn) throw new Error(`Unknown service: ${service}`);
await waitFn(interval);
updateSpinner(service);
}),
),
new Promise((_, reject) => {
timeoutId = setTimeout(() => reject(new Error("Timeout")), timeout);
}),
]);
} catch (err) {
const error = err as Error;
if (error.message === "Timeout") {
spinner.fail(
`${formatServiceList(unreadyServices)} timed out after ${timeout}ms`,
);
} else {
spinner.fail(error.message);
}
throw error;
} finally {
await client.end();
clearTimeout(timeoutId);
}
}
async function waitForKeycloak(interval: number) {
try {
const res = await axios.get(
`${process.env.KEYCLOAK_BASE_URL || "http://localhost:8080"}/realms/master/.well-known/openid-configuration`,
);
if ((res?.status || 500) < 300) {
return;
}
} catch (err) {}
await new Promise((resolve) => setTimeout(resolve, interval));
return waitForKeycloak(interval);
}

@@ -1,8 +0,8 @@

/*
/**
* File: /src/types.ts
* Project: @multiplatform.one/cli
* File Created: 23-06-2024 10:13:38
* File Created: 10-01-2025 21:02:36
* Author: Clay Risser
* -----
* BitSpur (c) Copyright 2021 - 2024
* BitSpur (c) Copyright 2021 - 2025
*

@@ -24,3 +24,3 @@ * Licensed under the Apache License, Version 2.0 (the "License");

default_context: {
backends: string;
services: string;
name: string;

@@ -27,0 +27,0 @@ platforms: string;

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc