@wirechunk/cli 0.0.8 → 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 +82 -40
  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 = {};
@@ -26588,6 +26597,7 @@ const grantAllUserPlatformPermissions = async ({
26588
26597
  )} on conflict ("platformAdminId", "object", "action") do nothing`
26589
26598
  );
26590
26599
  };
26600
+ const devAdminPlatformId = "ths9gw8";
26591
26601
  const devUserEmail = "dev@example.com";
26592
26602
  const devUserPassword = "password00";
26593
26603
  const platformHandleAvailable = async (handle, db) => !await db.maybeOne(
@@ -26671,19 +26681,30 @@ const bootstrap = async (opts, env2) => {
26671
26681
  error: `Domain "${adminSiteDomain}" is already in use by the platform with ID ${existingSiteForDomain.platformId}`
26672
26682
  };
26673
26683
  }
26674
- const platform = await db2.one(
26675
- sql.type(stringIdSelectSchema)`
26676
- insert into "Platforms" (
26677
- "handle",
26678
- "name"
26679
- )
26680
- values (
26681
- ${handle},
26682
- ${name}
26683
- )
26684
- returning "id"
26685
- `
26686
- );
26684
+ const insertPlatformQuery = opts.dev ? sql.type(stringIdSelectSchema)`
26685
+ insert into "Platforms" (
26686
+ "id",
26687
+ "handle",
26688
+ "name"
26689
+ )
26690
+ values (
26691
+ ${devAdminPlatformId},
26692
+ ${handle},
26693
+ ${name}
26694
+ )
26695
+ returning "id"
26696
+ ` : sql.type(stringIdSelectSchema)`
26697
+ insert into "Platforms" (
26698
+ "handle",
26699
+ "name"
26700
+ )
26701
+ values (
26702
+ ${handle},
26703
+ ${name}
26704
+ )
26705
+ returning "id"
26706
+ `;
26707
+ const platform = await db2.one(insertPlatformQuery);
26687
26708
  const adminSiteId = cleanSmallId();
26688
26709
  await db2.query(
26689
26710
  sql.type(voidSelectSchema)`
@@ -66390,6 +66411,7 @@ const initDb = async (opts, env2) => {
66390
66411
  coreDbUrl: coreDbUrlObject
66391
66412
  });
66392
66413
  };
66414
+ const defaultDevServerImage = "us-docker.pkg.dev/wirechunk/dev-server/core:latest";
66393
66415
  const parseStartFlag = (value, name) => {
66394
66416
  const trimmed = value?.trim();
66395
66417
  if (!trimmed) {
@@ -66402,11 +66424,7 @@ const parseStartFlag = (value, name) => {
66402
66424
  process.exit(1);
66403
66425
  };
66404
66426
  const startCore = async (opts, env2) => {
66405
- const image = env2.WIRECHUNK_CORE_DEV_SERVER_IMAGE;
66406
- if (!image) {
66407
- console.error("Missing WIRECHUNK_CORE_DEV_SERVER_IMAGE in environment");
66408
- process.exit(1);
66409
- }
66427
+ const image = env2.WIRECHUNK_CORE_DEV_SERVER_IMAGE?.trim() || defaultDevServerImage;
66410
66428
  const databaseUrl = env2.WIRECHUNK_CORE_DATABASE_URL_DOCKER || env2.WIRECHUNK_CORE_DATABASE_URL;
66411
66429
  if (!databaseUrl) {
66412
66430
  console.error(
@@ -66474,18 +66492,41 @@ const startCore = async (opts, env2) => {
66474
66492
  process.exit(exitCode);
66475
66493
  }
66476
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
+ };
66477
66507
  const program = new Command().name("wirechunk").option("--verbose", "output debug logging").option(
66478
66508
  "--env-mode <mode>",
66479
- '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'
66480
66510
  ).description(`The official Wirechunk CLI
66481
66511
 
66482
- By default, environment variables are loaded from the .env file in the current working directory,
66483
- then the .env.local file, and then from the environment. Variables from the environment have the
66484
- 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.
66485
66517
 
66486
66518
  Environment variables used by some commands:
66487
66519
  WIRECHUNK_CORE_SERVER_URL (the core admin server URL for commands using the API)
66488
- 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
+ };
66489
66530
  const withOptionsAndEnv = (action) => async (options, cmd) => {
66490
66531
  const mergedOptions = { ...program.opts(), ...options };
66491
66532
  if (mergedOptions.verbose) {
@@ -66494,6 +66535,7 @@ const withOptionsAndEnv = (action) => async (options, cmd) => {
66494
66535
  const env2 = await parseEnv(mergedOptions.envMode);
66495
66536
  return action(mergedOptions, env2);
66496
66537
  };
66538
+ program.command("version").description("print the CLI version").action(withOptions(version));
66497
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));
66498
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(
66499
66541
  "--config-file <string>",
package/package.json CHANGED
@@ -1,22 +1,8 @@
1
1
  {
2
2
  "name": "@wirechunk/cli",
3
- "version": "0.0.8",
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",