pockethost 4.2.0 → 4.2.1

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/CHANGELOG.md CHANGED
@@ -2,6 +2,14 @@
2
2
 
3
3
  Formerly published as `phio`. Versions below 3.0.0 are phio's history.
4
4
 
5
+ ## 4.2.1
6
+
7
+ ### Patch Changes
8
+
9
+ - Removing a package (even the last one) now removes it from the instance. With a `package.json`, `deploy` and `dev`
10
+ tell PocketHost that the deploy owns `node_modules`, so whatever isn't shipped is cleaned up.
11
+ `--no-node-modules` still leaves the instance's `node_modules` alone.
12
+
5
13
  ## 4.2.0
6
14
 
7
15
  ### Minor Changes
package/README.md CHANGED
@@ -117,10 +117,11 @@ Older project files (`.phioconfig`, `package.json` → `pockethost.instanceName`
117
117
  3. Commit: the server swaps the file set in atomically (stopping the instance when anything outside `pb_public`
118
118
  changes) and starts the instance again.
119
119
 
120
- PocketHost doesn't run `npm install`. Instead, when `package.json` has `dependencies`, the CLI ships your production
120
+ PocketHost doesn't run `npm install`. Instead, when your project has a `package.json`, the CLI ships your production
121
121
  `node_modules` with the deploy: the packages in `dependencies` and everything they need, never `devDependencies`.
122
122
  It works with npm, pnpm, Bun and workspaces, and follows symlinks, so the instance gets plain files. Install first
123
- (`npm install` or similar), then deploy. `--no-node-modules` leaves the instance's `node_modules` alone.
123
+ (`npm install` or similar), then deploy. The instance's `node_modules` ends up matching what you shipped, so packages
124
+ you remove (even the last one) are removed there too. `--no-node-modules` leaves the instance's `node_modules` alone.
124
125
 
125
126
  Only `pb_*` folders (never `pb_data`), `package.json`, `bun.lock(b)`, `patches/` and the production `node_modules` are
126
127
  deployed. Files in those folders on the instance that aren't in your project are removed. `.git*` files are never
@@ -160,13 +161,13 @@ Customer docs: https://pockethost.io/docs/cli
160
161
 
161
162
  ## Environment variables
162
163
 
163
- | Variable | Purpose |
164
- | -------- | ------- |
165
- | `POCKETHOST_TOKEN` | Personal access token (CI); overrides the saved one |
166
- | `POCKETHOST_INSTANCE_NAME` | Override linked instance name |
167
- | `POCKETHOST_MOTHERSHIP_URL` | Override mothership API URL |
168
- | `POCKETHOST_HOME` | Override config directory |
169
- | `POCKETHOST_PROJECT_DIR` | Override project root detection |
164
+ | Variable | Purpose |
165
+ | --------------------------- | --------------------------------------------------- |
166
+ | `POCKETHOST_TOKEN` | Personal access token (CI); overrides the saved one |
167
+ | `POCKETHOST_INSTANCE_NAME` | Override linked instance name |
168
+ | `POCKETHOST_MOTHERSHIP_URL` | Override mothership API URL |
169
+ | `POCKETHOST_HOME` | Override config directory |
170
+ | `POCKETHOST_PROJECT_DIR` | Override project root detection |
170
171
 
171
172
  Environment variables take precedence over `.pockethostconfig`. The old `PHIO_*` names still work (with a deprecation
172
173
  warning) and will be removed in a future major version.
package/dist/cli.js CHANGED
@@ -6444,7 +6444,7 @@ function useColor() {
6444
6444
  var program = new Command();
6445
6445
 
6446
6446
  // package.json
6447
- var version = "4.2.0";
6447
+ var version = "4.2.1";
6448
6448
 
6449
6449
  // src/lib/projectRoot.ts
6450
6450
  import { existsSync as existsSync2 } from "fs";
@@ -6755,8 +6755,8 @@ var saveInstanceName = (instanceName) => {
6755
6755
 
6756
6756
  // src/lib/deployLocal.ts
6757
6757
  import { copyFile, mkdir, readdir } from "fs/promises";
6758
- import { existsSync as existsSync5 } from "fs";
6759
- import { dirname as dirname3, join as join4, resolve } from "path";
6758
+ import { existsSync as existsSync6 } from "fs";
6759
+ import { dirname as dirname3, join as join5, resolve } from "path";
6760
6760
 
6761
6761
  // ../../node_modules/.pnpm/pretty-bytes@7.1.0/node_modules/pretty-bytes/index.js
6762
6762
  var BYTE_UNITS = [
@@ -6900,7 +6900,7 @@ function prettyBytes(number, options2) {
6900
6900
 
6901
6901
  // src/lib/deployApi.ts
6902
6902
  import { execFileSync } from "child_process";
6903
- import { lstatSync as lstatSync2 } from "fs";
6903
+ import { existsSync as existsSync5, lstatSync as lstatSync2 } from "fs";
6904
6904
  import { readFile } from "fs/promises";
6905
6905
 
6906
6906
  // ../../node_modules/.pnpm/glob@13.0.6/node_modules/glob/dist/esm/index.min.js
@@ -9888,7 +9888,7 @@ var Ze = Object.assign(Je, { glob: Je, globSync: ts, sync: Ui, globStream: Qe, s
9888
9888
  Ze.glob = Ze;
9889
9889
 
9890
9890
  // src/lib/deployApi.ts
9891
- import { sep as sep3 } from "path";
9891
+ import { join as join4, sep as sep3 } from "path";
9892
9892
  import { gzipSync } from "zlib";
9893
9893
 
9894
9894
  // vendor/ftp-deploy/sftpDeploy.ts
@@ -12868,10 +12868,6 @@ var collectNodeModules = (projectDir) => {
12868
12868
  packages.sort((a, b) => a.path < b.path ? -1 : 1);
12869
12869
  return { files, packages, missing };
12870
12870
  };
12871
- var hasRuntimeDependencies = (projectDir) => {
12872
- const pkg = readPackageJson(projectDir);
12873
- return Object.keys(pkg.dependencies ?? {}).length + Object.keys(pkg.optionalDependencies ?? {}).length > 0;
12874
- };
12875
12871
 
12876
12872
  // src/lib/config.ts
12877
12873
  import { readFileSync as readFileSync4, writeFileSync as writeFileSync2 } from "fs";
@@ -13015,7 +13011,7 @@ var collectLocalFiles = async (include, exclude, cwd = process.cwd(), options2 =
13015
13011
  });
13016
13012
  }
13017
13013
  let nodeModules = null;
13018
- if (options2.nodeModules ?? hasRuntimeDependencies(cwd)) {
13014
+ if (options2.nodeModules ?? existsSync5(join4(cwd, "package.json"))) {
13019
13015
  nodeModules = collectNodeModules(cwd);
13020
13016
  for (const f of nodeModules.files) {
13021
13017
  const data = await readFile(f.source);
@@ -13039,7 +13035,7 @@ var assertNodeModulesComplete = (nm) => {
13039
13035
  var describeNodeModules = (nm) => {
13040
13036
  if (!nm) return [];
13041
13037
  const lines = [
13042
- `\u{1F4E6} node_modules: ${nm.packages.length} package(s), ${nm.files.length} file(s)`
13038
+ nm.packages.length === 0 ? `\u{1F4E6} node_modules: no packages (any on the server will be removed)` : `\u{1F4E6} node_modules: ${nm.packages.length} package(s), ${nm.files.length} file(s)`
13043
13039
  ];
13044
13040
  if (nm.missing.length > 0) {
13045
13041
  lines.push(
@@ -13115,7 +13111,7 @@ var createDeployClient = (instanceName, cred) => {
13115
13111
  base,
13116
13112
  headers,
13117
13113
  whoami: () => call("GET", "/whoami"),
13118
- check: (files) => call("POST", "/check", { files }),
13114
+ check: (files, nodeModules = false) => call("POST", "/check", { files, nodeModules }),
13119
13115
  upload: (bundle) => call(
13120
13116
  "POST",
13121
13117
  "/blobs",
@@ -13170,10 +13166,12 @@ var deployViaApi = async (opts) => {
13170
13166
  uploadedCount += toSend.length;
13171
13167
  uploadedBytes += bytes;
13172
13168
  };
13173
- const { missing } = await client.check(manifest);
13169
+ const managesNodeModules = nodeModules !== null;
13170
+ const { missing } = await client.check(manifest, managesNodeModules);
13174
13171
  await upload(missing);
13175
13172
  const commitBody = {
13176
13173
  files: manifest,
13174
+ nodeModules: managesNodeModules,
13177
13175
  commit: opts.commit ?? detectCommit(cwd),
13178
13176
  message: opts.message ?? "",
13179
13177
  source: detectSource(),
@@ -13212,12 +13210,12 @@ var deployViaApi = async (opts) => {
13212
13210
  // src/lib/deployLocal.ts
13213
13211
  var writeDeploySet = async (files, outDir) => {
13214
13212
  const root = resolve(outDir);
13215
- if (existsSync5(root) && (await readdir(root)).length > 0) {
13213
+ if (existsSync6(root) && (await readdir(root)).length > 0) {
13216
13214
  throw new Error(`${outDir} must be empty or not exist yet`);
13217
13215
  }
13218
13216
  await mkdir(root, { recursive: true });
13219
13217
  for (const f of files) {
13220
- const dest = join4(root, ...f.path.split("/"));
13218
+ const dest = join5(root, ...f.path.split("/"));
13221
13219
  await mkdir(dirname3(dest), { recursive: true });
13222
13220
  await copyFile(f.source, dest);
13223
13221
  }
@@ -15029,7 +15027,7 @@ var shellQuote = (value) => {
15029
15027
  var formatSftpCommand = (connection, sftpBin = "sftp") => [sftpBin, ...buildSftpArgs(connection).map(shellQuote)].join(" ");
15030
15028
 
15031
15029
  // src/lib/deployKey.ts
15032
- import { chmodSync as chmodSync2, existsSync as existsSync6, readFileSync as readFileSync5, writeFileSync as writeFileSync3 } from "fs";
15030
+ import { chmodSync as chmodSync2, existsSync as existsSync7, readFileSync as readFileSync5, writeFileSync as writeFileSync3 } from "fs";
15033
15031
  import { generateKeyPairSync } from "crypto";
15034
15032
 
15035
15033
  // src/lib/sshPublicKey.ts
@@ -15178,7 +15176,7 @@ var migratePkcs8PrivateKeyIfNeeded = (privateKeyPath) => {
15178
15176
  };
15179
15177
  var ensureLocalKeyPair = () => {
15180
15178
  const { privateKeyPath, publicKeyPath } = getDeployKeyPaths();
15181
- if (existsSync6(privateKeyPath) && existsSync6(publicKeyPath)) {
15179
+ if (existsSync7(privateKeyPath) && existsSync7(publicKeyPath)) {
15182
15180
  migratePkcs8PrivateKeyIfNeeded(privateKeyPath);
15183
15181
  return {
15184
15182
  privateKeyPath,
@@ -15360,8 +15358,11 @@ var DeployCommand = () => {
15360
15358
  `Commit SHA to record (default: $GITHUB_SHA or git HEAD)`
15361
15359
  ).option(`-m, --message <message>`, `Note to record with this deploy`).option(
15362
15360
  `--node-modules`,
15363
- `Ship the production node_modules tree (default when package.json has dependencies)`
15364
- ).option(`--no-node-modules`, `Don't ship node_modules`).option(
15361
+ `Ship the production node_modules tree and remove packages no longer used (default with a package.json)`
15362
+ ).option(
15363
+ `--no-node-modules`,
15364
+ `Don't ship node_modules; leave the instance's node_modules alone`
15365
+ ).option(
15365
15366
  `--out <dir>`,
15366
15367
  `Write the deploy set to a local folder instead of deploying`
15367
15368
  ).option(`--dry-run`, `List what would be deployed, deploy nothing`).option(
@@ -15409,8 +15410,8 @@ var DeployCommand = () => {
15409
15410
  };
15410
15411
 
15411
15412
  // src/commands/FilesCommand.ts
15412
- import { existsSync as existsSync7, readdirSync as readdirSync3, statSync as statSync2 } from "fs";
15413
- import { join as join7, relative as relative4, resolve as resolve4, sep as sep4 } from "path";
15413
+ import { existsSync as existsSync8, readdirSync as readdirSync3, statSync as statSync2 } from "fs";
15414
+ import { join as join8, relative as relative4, resolve as resolve4, sep as sep4 } from "path";
15414
15415
 
15415
15416
  // src/lib/filesApi.ts
15416
15417
  import { createReadStream, createWriteStream } from "fs";
@@ -15559,7 +15560,7 @@ var FilesCommand = () => instanceOption(
15559
15560
  if (out.truncated) console.log(`(list truncated)`);
15560
15561
  });
15561
15562
  var isCurrent = (local, e) => {
15562
- if (!existsSync7(local)) return false;
15563
+ if (!existsSync8(local)) return false;
15563
15564
  const st2 = statSync2(local);
15564
15565
  return st2.size === e.size && Math.abs(st2.mtimeMs - e.mtime) < 1e3;
15565
15566
  };
@@ -15596,21 +15597,21 @@ var PullCommand = () => instanceOption(
15596
15597
  )
15597
15598
  );
15598
15599
  }
15599
- const todo = wanted.filter((e) => !isCurrent(join7(dir, e.path), e));
15600
+ const todo = wanted.filter((e) => !isCurrent(join8(dir, e.path), e));
15600
15601
  const bytes = todo.reduce((n7, e) => n7 + e.size, 0);
15601
15602
  console.log(
15602
15603
  `${options2.dryRun ? "Would download" : "Downloading"} ${todo.length} of ${wanted.length} file(s) (${prettyBytes(bytes)}) from ${instanceName} into ${dir}`
15603
15604
  );
15604
15605
  for (const e of todo) {
15605
15606
  if (options2.verbose || options2.dryRun) console.log(` ${e.path}`);
15606
- if (!options2.dryRun) await files.download(e.path, join7(dir, e.path));
15607
+ if (!options2.dryRun) await files.download(e.path, join8(dir, e.path));
15607
15608
  }
15608
15609
  if (!options2.dryRun) console.log(`\u2705 Done.`);
15609
15610
  });
15610
15611
  var walkLocal = (abs) => {
15611
15612
  const st2 = statSync2(abs);
15612
15613
  if (!st2.isDirectory()) return [abs];
15613
- return readdirSync3(abs).filter((n7) => !n7.startsWith(".git")).flatMap((n7) => walkLocal(join7(abs, n7)));
15614
+ return readdirSync3(abs).filter((n7) => !n7.startsWith(".git")).flatMap((n7) => walkLocal(join8(abs, n7)));
15614
15615
  };
15615
15616
  var UploadCommand = () => instanceOption(
15616
15617
  new Command("upload").description(
@@ -15622,7 +15623,7 @@ var UploadCommand = () => instanceOption(
15622
15623
  ).action(async (local, remote, options2) => {
15623
15624
  const instanceName = requireInstance(options2.instance);
15624
15625
  const abs = resolve4(local);
15625
- if (!existsSync7(abs)) throw new Error(`${local} not found`);
15626
+ if (!existsSync8(abs)) throw new Error(`${local} not found`);
15626
15627
  const target = normalizeRemotePath(
15627
15628
  remote ?? relative4(process.cwd(), abs).split(sep4).join("/")
15628
15629
  );
@@ -15674,7 +15675,7 @@ var RmCommand = () => instanceOption(
15674
15675
  });
15675
15676
 
15676
15677
  // src/commands/InfoCommand.ts
15677
- import { existsSync as existsSync8, readFileSync as readFileSync6 } from "fs";
15678
+ import { existsSync as existsSync9, readFileSync as readFileSync6 } from "fs";
15678
15679
 
15679
15680
  // ../../node_modules/.pnpm/@inquirer+core@11.2.1_@types+node@20.19.43/node_modules/@inquirer/core/dist/lib/key.js
15680
15681
  var keybindings = ["emacs", "vim"];
@@ -17569,7 +17570,7 @@ var TokenCommand = () => new Command("token").description(`Show, save or remove
17569
17570
  // src/commands/InfoCommand.ts
17570
17571
  var sshKeyStatus = async () => {
17571
17572
  const { publicKeyPath } = getDeployKeyPaths();
17572
- if (!existsSync8(publicKeyPath))
17573
+ if (!existsSync9(publicKeyPath))
17573
17574
  return `none yet (created the first time you use SFTP)`;
17574
17575
  const fingerprint = fingerprintForPublicKey(
17575
17576
  readFileSync6(publicKeyPath, "utf8").trim()
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pockethost",
3
- "version": "4.2.0",
3
+ "version": "4.2.1",
4
4
  "description": "The PocketHost CLI: deploy, sync, and tail logs for your PocketHost instances",
5
5
  "repository": {
6
6
  "type": "git",