@wirechunk/cli 0.0.9 → 0.1.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.
Files changed (3) hide show
  1. package/README.md +75 -0
  2. package/build/main.js +57 -27
  3. package/package.json +1 -17
package/README.md ADDED
@@ -0,0 +1,75 @@
1
+ # Wirechunk CLI
2
+
3
+ The Wirechunk CLI (`wirechunk`) is the official command-line tool for Wirechunk. It provides essential utilities for platform management and is the primary tool for developing Wirechunk extensions.
4
+
5
+ ## Installation
6
+
7
+ ```
8
+ npm install -D @wirechunk/cli
9
+ ```
10
+
11
+ ## Getting Started with Extension Development
12
+
13
+ The CLI simplifies the extension development workflow by allowing you to run a local instance of the Wirechunk core platform that loads your extension code directly.
14
+
15
+ ### Prerequisites
16
+
17
+ - **Node.js**: Must be version 24+.
18
+ - **Docker**: Required for running the core development server.
19
+
20
+ ### Development Workflow
21
+
22
+ 1. **Configure Environment**:
23
+ Ensure you have a `.env` file with the necessary configuration, including a core database URL (e.g., `WIRECHUNK_CORE_DATABASE_URL`). You can override the core dev server image with `WIRECHUNK_CORE_DEV_SERVER_IMAGE`; otherwise the CLI uses the latest.
24
+
25
+ 2. **Start the Core Server**:
26
+ Run the development server which spins up a Docker container with the Wirechunk platform. It mounts your current working directory inside the container, allowing hot reload for frontend code as you develop.
27
+
28
+ ```
29
+ wirechunk ext-dev start-core
30
+ ```
31
+
32
+ - Adds `-d` to run in detached mode.
33
+ - Exposes port `8080` (Web) and `9001` (Vite).
34
+
35
+ 3. **Create Extension**:
36
+ Register your extension with the platform to generate an ID and configure your environment. If your `extension.json` enables a database, this command will set up the connection details automatically.
37
+
38
+ ```
39
+ wirechunk create-extension --dev
40
+ ```
41
+
42
+ ## Key Commands
43
+
44
+ ### Extension Management
45
+
46
+ - **`wirechunk create-extension`**: Register a new extension on the platform.
47
+ - **`wirechunk create-extension-version`**: Publish a new version of an extension. Uploads configuration and code.
48
+
49
+ ### Platform & User Management
50
+
51
+ - **`wirechunk bootstrap`**: Initialize a new platform.
52
+ - **`wirechunk create-user`**: Create a new user account. Useful for setting up test users or initial admins.
53
+ - **`wirechunk edit-admin`**: Grant or revoke admin privileges for a user on a platform.
54
+
55
+ ### Development Utilities (`ext-dev`)
56
+
57
+ - **`wirechunk ext-dev start-core`**: Starts the local Docker-based development server.
58
+ - **`wirechunk ext-dev init-db`**: Initializes a development database for an extension.
59
+ - **`wirechunk ext-dev get-db-url`**: writes `DATABASE_URL` to `.env.local` (or `.env.<env-mode>.local`) with the extension’s development database connection string.
60
+
61
+ ### Utility
62
+
63
+ - **`wirechunk version`**: Prints the CLI version.
64
+
65
+ ## Configuration
66
+
67
+ The CLI automatically loads environment variables from `.env` and `.env.local` files in your current directory.
68
+
69
+ You can specify a custom environment mode using the `--env-mode` flag:
70
+
71
+ ```
72
+ wirechunk --env-mode test create-user ...
73
+ ```
74
+
75
+ This will load variables from `.env.test` and `.env.test.local` in addition to the standard files.
package/build/main.js CHANGED
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import EventEmitter from "node:events";
3
3
  import require$$1$1, { spawn } from "node:child_process";
4
- import require$$2$2, { resolve as resolve$1 } from "node:path";
4
+ import require$$2$2, { resolve as resolve$1, dirname } from "node:path";
5
5
  import require$$3$1, { readFileSync, existsSync } from "node:fs";
6
6
  import process$2 from "node:process";
7
7
  import os from "node:os";
@@ -31,7 +31,7 @@ import require$$0$d from "os";
31
31
  import require$$1$4 from "tty";
32
32
  import require$$0$e from "constants";
33
33
  import require$$5$1 from "assert";
34
- import require$$2$4 from "node:url";
34
+ import require$$2$4, { fileURLToPath } from "node:url";
35
35
  import require$$2$3 from "node:string_decoder";
36
36
  import require$$0$f from "zlib";
37
37
  var commonjsGlobal = typeof globalThis !== "undefined" ? globalThis : typeof window !== "undefined" ? window : typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : {};
@@ -6834,7 +6834,7 @@ let Doc$1 = class Doc {
6834
6834
  return new F(...args, lines.join("\n"));
6835
6835
  }
6836
6836
  };
6837
- const version$1 = {
6837
+ const version$2 = {
6838
6838
  major: 4,
6839
6839
  minor: 1,
6840
6840
  patch: 13
@@ -6844,7 +6844,7 @@ const $ZodType$1 = /* @__PURE__ */ $constructor$1("$ZodType", (inst, def) => {
6844
6844
  inst ?? (inst = {});
6845
6845
  inst._zod.def = def;
6846
6846
  inst._zod.bag = inst._zod.bag || {};
6847
- inst._zod.version = version$1;
6847
+ inst._zod.version = version$2;
6848
6848
  const checks = [...inst._zod.def.checks ?? []];
6849
6849
  if (inst._zod.traits.has("$ZodCheck")) {
6850
6850
  checks.unshift(inst);
@@ -23897,7 +23897,7 @@ class Doc2 {
23897
23897
  return new F(...args, lines.join("\n"));
23898
23898
  }
23899
23899
  }
23900
- const version = {
23900
+ const version$1 = {
23901
23901
  major: 4,
23902
23902
  minor: 1,
23903
23903
  patch: 13
@@ -23907,7 +23907,7 @@ const $ZodType = /* @__PURE__ */ $constructor("$ZodType", (inst, def) => {
23907
23907
  inst ?? (inst = {});
23908
23908
  inst._zod.def = def;
23909
23909
  inst._zod.bag = inst._zod.bag || {};
23910
- inst._zod.version = version;
23910
+ inst._zod.version = version$1;
23911
23911
  const checks = [...inst._zod.def.checks ?? []];
23912
23912
  if (inst._zod.traits.has("$ZodCheck")) {
23913
23913
  checks.unshift(inst);
@@ -26007,9 +26007,11 @@ function superRefine(fn) {
26007
26007
  const localhostRegex1 = /localhost:\d{2,4}$/;
26008
26008
  const localhostRegex2 = /localhost$/;
26009
26009
  const isLocalhost = (domain) => localhostRegex1.test(domain) || localhostRegex2.test(domain);
26010
+ const envModeSymbol = Symbol("envMode");
26011
+ const mainEnvFilePathSymbol = Symbol("mainEnvFilePath");
26012
+ const mainEnvFileExistsSymbol = Symbol("mainEnvFileExists");
26010
26013
  const envFilePath = ".env";
26011
26014
  const envLocalFilePath = ".env.local";
26012
- const hasEnvFile = existsSync(envFilePath);
26013
26015
  const requireApiToken = (env2) => {
26014
26016
  if (!env2.WIRECHUNK_API_TOKEN) {
26015
26017
  console.error(
@@ -26023,10 +26025,10 @@ const requireCoreDbUrl = (env2) => {
26023
26025
  const url = env2.WIRECHUNK_CORE_DATABASE_URL;
26024
26026
  if (!url) {
26025
26027
  const message = "Missing WIRECHUNK_CORE_DATABASE_URL in environment";
26026
- if (hasEnvFile) {
26028
+ if (env2[mainEnvFileExistsSymbol]) {
26027
26029
  console.error(message);
26028
26030
  } else {
26029
- console.error(`${message}, no ${envFilePath} file found`);
26031
+ console.error(`${message}, no ${env2[mainEnvFilePathSymbol]} file found`);
26030
26032
  }
26031
26033
  process$2.exit(1);
26032
26034
  }
@@ -26045,16 +26047,20 @@ const coreServerUrlFromEnv = (env2) => {
26045
26047
  };
26046
26048
  const parseEnv = async (envMode) => {
26047
26049
  const env2 = {};
26048
- if (hasEnvFile) {
26049
- const envFileRaw = await readFile(envFilePath, "utf8");
26050
- Object.assign(env2, parseEnv$1(envFileRaw));
26051
- }
26050
+ const mainEnvFilePath = envMode ? `.env.${envMode}` : envFilePath;
26051
+ const mainEnvFileExists = existsSync(mainEnvFilePath);
26052
26052
  if (envMode) {
26053
- const modeFilePath = `.env.${envMode}`;
26054
- if (existsSync(modeFilePath)) {
26055
- const modeFileRaw = await readFile(modeFilePath, "utf8");
26053
+ if (existsSync(envFilePath)) {
26054
+ const envFileRaw = await readFile(envFilePath, "utf8");
26055
+ Object.assign(env2, parseEnv$1(envFileRaw));
26056
+ }
26057
+ if (mainEnvFileExists) {
26058
+ const modeFileRaw = await readFile(mainEnvFilePath, "utf8");
26056
26059
  Object.assign(env2, parseEnv$1(modeFileRaw));
26057
26060
  }
26061
+ } else if (mainEnvFileExists) {
26062
+ const envFileRaw = await readFile(mainEnvFilePath, "utf8");
26063
+ Object.assign(env2, parseEnv$1(envFileRaw));
26058
26064
  }
26059
26065
  if (existsSync(envLocalFilePath)) {
26060
26066
  const envLocalFileRaw = await readFile(envLocalFilePath, "utf8");
@@ -26070,7 +26076,10 @@ const parseEnv = async (envMode) => {
26070
26076
  Object.assign(env2, process$2.env);
26071
26077
  return {
26072
26078
  ...env2,
26073
- WIRECHUNK_CORE_SERVER_URL: coreServerUrlFromEnv(env2)
26079
+ WIRECHUNK_CORE_SERVER_URL: coreServerUrlFromEnv(env2),
26080
+ [envModeSymbol]: envMode,
26081
+ [mainEnvFilePathSymbol]: mainEnvFilePath,
26082
+ [mainEnvFileExistsSymbol]: mainEnvFileExists
26074
26083
  };
26075
26084
  };
26076
26085
  var dist$1 = {};
@@ -66402,6 +66411,7 @@ const initDb = async (opts, env2) => {
66402
66411
  coreDbUrl: coreDbUrlObject
66403
66412
  });
66404
66413
  };
66414
+ const defaultDevServerImage = "us-docker.pkg.dev/wirechunk/dev-server/core:latest";
66405
66415
  const parseStartFlag = (value, name) => {
66406
66416
  const trimmed = value?.trim();
66407
66417
  if (!trimmed) {
@@ -66414,11 +66424,7 @@ const parseStartFlag = (value, name) => {
66414
66424
  process.exit(1);
66415
66425
  };
66416
66426
  const startCore = async (opts, env2) => {
66417
- const image = env2.WIRECHUNK_CORE_DEV_SERVER_IMAGE;
66418
- if (!image) {
66419
- console.error("Missing WIRECHUNK_CORE_DEV_SERVER_IMAGE in environment");
66420
- process.exit(1);
66421
- }
66427
+ const image = env2.WIRECHUNK_CORE_DEV_SERVER_IMAGE?.trim() || defaultDevServerImage;
66422
66428
  const databaseUrl = env2.WIRECHUNK_CORE_DATABASE_URL_DOCKER || env2.WIRECHUNK_CORE_DATABASE_URL;
66423
66429
  if (!databaseUrl) {
66424
66430
  console.error(
@@ -66486,18 +66492,41 @@ const startCore = async (opts, env2) => {
66486
66492
  process.exit(exitCode);
66487
66493
  }
66488
66494
  };
66495
+ const hasVersion = (value) => typeof value === "object" && value !== null && "version" in value;
66496
+ const packageJsonPath = resolve$1(dirname(fileURLToPath(import.meta.url)), "../package.json");
66497
+ const getCliVersion = () => {
66498
+ const parsed = JSON.parse(readFileSync(packageJsonPath, "utf8"));
66499
+ if (!hasVersion(parsed) || typeof parsed.version !== "string" || parsed.version.length === 0) {
66500
+ throw new Error("package.json is missing a version string");
66501
+ }
66502
+ return parsed.version;
66503
+ };
66504
+ const version = (_options) => {
66505
+ console.log(getCliVersion());
66506
+ };
66489
66507
  const program = new Command().name("wirechunk").option("--verbose", "output debug logging").option(
66490
66508
  "--env-mode <mode>",
66491
- 'the mode to use for finding .env files to load environment variables, such as "test" to load .env, .env.test, .env.local, and .env.test.local; also for finding config files to include when creating an extension or extension version, such as config.production.json'
66509
+ 'the mode to use for finding .env files to load environment variables, such as "test" to load .env, .env.test, .env.local, and .env.test.local (in that order); also for finding config files to include when creating an extension or extension version, such as config.production.json'
66492
66510
  ).description(`The official Wirechunk CLI
66493
66511
 
66494
- By default, environment variables are loaded from the .env file in the current working directory,
66495
- then the .env.local file, and then from the environment. Variables from the environment have the
66496
- highest precedence.
66512
+ By default, environment variables are loaded from the .env file in the current working directory, then the .env.local file, and then from the environment.
66513
+
66514
+ When --env-mode is used, variables are loaded from .env, then .env.<mode>, then .env.local, then .env.<mode>.local, and finally from the environment.
66515
+
66516
+ Variables loaded later overwrite those loaded earlier. Variables from the environment have the highest precedence.
66497
66517
 
66498
66518
  Environment variables used by some commands:
66499
66519
  WIRECHUNK_CORE_SERVER_URL (the core admin server URL for commands using the API)
66500
- WIRECHUNK_CORE_DATABASE_URL (the core database URL for commands requiring direct database access)`);
66520
+ WIRECHUNK_CORE_DATABASE_URL (the core database URL for commands requiring direct database access)
66521
+ WIRECHUNK_API_TOKEN (the API token for authentication)
66522
+ WIRECHUNK_CORE_JWT_SECRET (the JWT secret for creating new tokens)`);
66523
+ const withOptions = (action) => async (options, cmd) => {
66524
+ const mergedOptions = { ...program.opts(), ...options };
66525
+ if (mergedOptions.verbose) {
66526
+ console.log(`Running ${chalk.green.bold(cmd.name())}`);
66527
+ }
66528
+ return action(mergedOptions);
66529
+ };
66501
66530
  const withOptionsAndEnv = (action) => async (options, cmd) => {
66502
66531
  const mergedOptions = { ...program.opts(), ...options };
66503
66532
  if (mergedOptions.verbose) {
@@ -66506,6 +66535,7 @@ const withOptionsAndEnv = (action) => async (options, cmd) => {
66506
66535
  const env2 = await parseEnv(mergedOptions.envMode);
66507
66536
  return action(mergedOptions, env2);
66508
66537
  };
66538
+ program.command("version").description("print the CLI version").action(withOptions(version));
66509
66539
  program.command("bootstrap").description("create a platform").option("--dev", "bootstrap with development defaults").option("--name <string>", "the name of the platform").option("--handle <string>", "the handle of the platform").option("--admin-site-domain <string>", "the domain of the admin site (dashboard)").action(withOptionsAndEnv(bootstrap));
66510
66540
  program.command("create-extension").description("create an extension").option("--platform-id <string>", "the ID of the platform").option("--name <string>", "the name of the extension").option(
66511
66541
  "--config-file <string>",
package/package.json CHANGED
@@ -1,22 +1,8 @@
1
1
  {
2
2
  "name": "@wirechunk/cli",
3
- "version": "0.0.9",
3
+ "version": "0.1.0",
4
4
  "private": false,
5
5
  "type": "module",
6
- "scripts": {
7
- "lint": "eslint --fix",
8
- "lint:check": "eslint",
9
- "format": "prettier --write .",
10
- "format:check": "prettier --check .",
11
- "typecheck": "tsc",
12
- "typecheck-src": "tsc --skipLibCheck",
13
- "typecheck-src:tsgo": "tsgo --skipLibCheck",
14
- "test": "echo 'no tests yet'",
15
- "build": "npm run build:clean && npm run build:cli",
16
- "build:clean": "rm -rf build",
17
- "build:cli": "vite build",
18
- "prepublishOnly": "npm run typecheck-src && npm run lint:check && npm run build"
19
- },
20
6
  "bin": {
21
7
  "wirechunk": "build/main.js"
22
8
  },
@@ -35,8 +21,6 @@
35
21
  "@commander-js/extra-typings": "^14.0.0",
36
22
  "@graphql-typed-document-node/core": "^3.2.0",
37
23
  "@types/archiver": "^6.0.3",
38
- "@wirechunk/backend-lib": "0.0.0",
39
- "@wirechunk/lib": "0.0.0",
40
24
  "archiver": "^7.0.1",
41
25
  "chalk": "^5.6.2",
42
26
  "commander": "^14.0.2",