ninepm 0.24.1 → 0.26.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 CHANGED
@@ -6,22 +6,9 @@ This package contains only client-side deploy code. It does not include the 9pm.
6
6
 
7
7
  ## Install
8
8
 
9
- Installer:
10
-
11
- ```sh
12
- curl -fsSL https://9pm.ai/install.sh | bash
13
- ```
14
-
15
- Tarball:
16
-
17
- ```sh
18
- npm install -g https://9pm.ai/downloads/9pm/latest.tgz
19
- ```
20
-
21
- Local early access tarball:
22
-
23
9
  ```sh
24
- npm install -g ./ninepm-0.24.1.tgz
10
+ npm i -g ninepm # persistent `9pm` binary
11
+ npx ninepm <args> # run without installing
25
12
  ```
26
13
 
27
14
  ## Configure
@@ -57,10 +44,10 @@ Check installed vs published CLI version:
57
44
  9pm doctor # surfaces the same drift line alongside credential/account health
58
45
  ```
59
46
 
60
- Upgrade by re-running the installer:
47
+ Upgrade:
61
48
 
62
49
  ```sh
63
- curl -fsSL https://9pm.ai/install.sh | bash
50
+ npm i -g ninepm@latest
64
51
  ```
65
52
 
66
53
  ## Deploy
package/dist/index.d.ts CHANGED
@@ -109,7 +109,7 @@ export interface CreatedServiceToken {
109
109
  clientSecret: string;
110
110
  }
111
111
  export type FetchLike = (input: string | URL | Request, init?: RequestInit) => Promise<Response>;
112
- export declare const CLI_VERSION = "0.24.1";
112
+ export declare const CLI_VERSION = "0.26.0";
113
113
  type CredentialBackend = "macos-keychain" | "windows-dpapi" | "linux-secret-service" | "file-plaintext" | "none";
114
114
  export interface CredentialDiagnostics {
115
115
  platform: NodeJS.Platform;
package/dist/index.js CHANGED
@@ -11,7 +11,7 @@ import { MAX_DEPLOY_DESCRIPTION_LENGTH, normalizeDeployDescription } from "./dep
11
11
  import { assetFileTooLargeMessage, oversizedAssets } from "./deploy-limits.js";
12
12
  import { buildFileManifest, readManifestFile } from "./manifest.js";
13
13
  import { API_KEY_HELP, API_URL_HELP, CLI_CLIENT_ID, DEFAULT_API_URL, reportCliError } from "./cli-config.js";
14
- export const CLI_VERSION = "0.24.1";
14
+ export const CLI_VERSION = "0.26.0";
15
15
  const PUBLIC_DASHBOARD_URL = "https://9pm.ai/dashboard";
16
16
  const TOKEN_SERVICE = "9pm";
17
17
  const TOKEN_ACCOUNT = "default";
@@ -257,7 +257,10 @@ async function runDeploy(initialOptions, slugHolder) {
257
257
  healthPath: options.healthPath ?? null,
258
258
  region: options.region ?? "auto",
259
259
  alwaysOn: options.alwaysOn ?? false,
260
- volumeGb: options.volumeGb ?? 0,
260
+ // Only send volumeGb when the user specified a disk (--volume) or
261
+ // explicitly none (--no-volume). Omitting it lets the server carry the
262
+ // prior deployment's disk forward instead of dropping it.
263
+ ...(options.volumeGb !== undefined ? { volumeGb: options.volumeGb } : {}),
261
264
  ...(options.allowVolumeDestroy ? { allowVolumeDestroy: true } : {}),
262
265
  ...(options.allowNamespaceReset ? { allowNamespaceReset: true } : {}),
263
266
  ...(options.cpus !== undefined ? { cpus: options.cpus } : {}),
@@ -501,7 +504,7 @@ async function doctor(options) {
501
504
  : "up to date";
502
505
  console.log(`CLI: ${versionCheck.current} (latest ${versionCheck.latest.version}, ${status})`);
503
506
  if (versionCheck.comparison === "behind") {
504
- console.log(`Update: curl -fsSL ${normalizeApiUrl(options.apiUrl).replace(/\/$/, "").replace(/\/\/api\./, "//")}/install.sh | bash`);
507
+ console.log("Update: npm i -g ninepm@latest");
505
508
  }
506
509
  }
507
510
  else if (versionError) {
@@ -594,21 +597,16 @@ export async function fetchLatestCliVersion(options) {
594
597
  const controller = new AbortController();
595
598
  const timer = setTimeout(() => controller.abort(), options.timeoutMs ?? 5000);
596
599
  try {
597
- const response = await fetchFn(`${apiUrl}/downloads/9pm/latest.json`, { signal: controller.signal });
600
+ void apiUrl; // updater now sources the public npm registry, not the platform host
601
+ const response = await fetchFn("https://registry.npmjs.org/ninepm/latest", { signal: controller.signal });
598
602
  if (!response.ok) {
599
- throw new Error(`Latest version manifest returned ${response.status}.`);
603
+ throw new Error(`npm registry returned ${response.status} for ninepm.`);
600
604
  }
601
605
  const payload = (await response.json());
602
606
  if (typeof payload.version !== "string" || !payload.version.trim()) {
603
- throw new Error("Latest version manifest is missing version.");
607
+ throw new Error("npm registry response is missing a version.");
604
608
  }
605
- return {
606
- version: payload.version.trim(),
607
- ...(typeof payload.publishedAt === "string" ? { publishedAt: payload.publishedAt } : {}),
608
- ...(typeof payload.tarballSha256 === "string" && /^[0-9a-f]{64}$/i.test(payload.tarballSha256.trim())
609
- ? { tarballSha256: payload.tarballSha256.trim().toLowerCase() }
610
- : {}),
611
- };
609
+ return { version: payload.version.trim() };
612
610
  }
613
611
  finally {
614
612
  clearTimeout(timer);
@@ -958,6 +956,7 @@ const VALID_DEPLOY_FLAGS = new Set([
958
956
  "region",
959
957
  "always-on",
960
958
  "volume",
959
+ "no-volume",
961
960
  "allow-data-wipe",
962
961
  "allow-namespace-reset",
963
962
  "cpus",
@@ -1138,6 +1137,16 @@ export function parseArgs(argv) {
1138
1137
  }
1139
1138
  options.volumeGb = volumeGb;
1140
1139
  }
1140
+ // --no-volume is the explicit "this app has no persistent disk" intent. Omitting
1141
+ // both --volume and --no-volume leaves volumeGb unset, so a redeploy keeps the
1142
+ // app's existing disk; --no-volume sends an explicit 0 to drop it (which the
1143
+ // server refuses without --allow-data-wipe when a disk already exists).
1144
+ if (flags.has("no-volume")) {
1145
+ if (volumeGb !== undefined) {
1146
+ throw new Error("--volume and --no-volume cannot be combined.");
1147
+ }
1148
+ options.volumeGb = 0;
1149
+ }
1141
1150
  const cpus = readIntegerFlag(flags, "cpus");
1142
1151
  if (cpus !== undefined) {
1143
1152
  if (cpus < 1 || cpus > 64) {
@@ -2372,15 +2381,11 @@ async function runLatestCommand(command) {
2372
2381
  return;
2373
2382
  }
2374
2383
  console.log(`Installed: ${check.current}`);
2375
- console.log(`Latest: ${check.latest.version}${check.latest.publishedAt ? ` (published ${check.latest.publishedAt})` : ""}`);
2376
- if (check.latest.tarballSha256) {
2377
- console.log(`SHA-256: ${check.latest.tarballSha256}`);
2378
- }
2384
+ console.log(`Latest: ${check.latest.version}`);
2379
2385
  if (check.comparison === "behind") {
2380
- const installHost = normalizeApiUrl(command.apiUrl).replace(/\/$/, "").replace(/\/\/api\./, "//");
2381
2386
  console.log("");
2382
2387
  console.log("A newer 9pm CLI is available. Update with:");
2383
- console.log(` curl -fsSL ${installHost}/install.sh | bash`);
2388
+ console.log(" npm i -g ninepm@latest (or run ad-hoc via: npx ninepm <args>)");
2384
2389
  }
2385
2390
  else if (check.comparison === "ahead") {
2386
2391
  console.log("Installed version is ahead of the published latest.");
@@ -2440,7 +2445,7 @@ function printUsage() {
2440
2445
  9pm --version
2441
2446
  9pm deploy [directory] --name <site-name> [--slug <slug>] [--description "<note>"] [--with-db] [--with-auth]
2442
2447
  9pm deploy [directory] --runtime worker --entry src/index.js [--with-db]
2443
- 9pm deploy [directory] --runtime container --port 8080 [--health-path /health] [--region auto] [--with-db] [--always-on] [--volume <gb>] [--cpus <n>] [--memory <size>]
2448
+ 9pm deploy [directory] --runtime container --port 8080 [--health-path /health] [--region auto] [--with-db] [--always-on] [--volume <gb> | --no-volume] [--cpus <n>] [--memory <size>]
2444
2449
  9pm deploy [directory] framework projects (Next.js, Vite) are detected and built automatically; --no-build skips
2445
2450
  9pm deploy [directory] --bundle <dir> deploy a pre-built Cloudflare framework bundle (e.g. .open-next)
2446
2451
  9pm deploy [directory] --description "<note>" optional short note shown next to the version in the dashboard
@@ -2498,8 +2503,12 @@ Container deploys:
2498
2503
  disk is mounted and its path is provided via NINEPM_DATA_DIR. Declare what the app needs with
2499
2504
  --cpus <n> and --memory <size> (512m, 2048, 4g); the platform picks a placement that fits.
2500
2505
  All of these may require platform enablement.
2501
- --allow-data-wipe acknowledges that switching an app to a different container placement may
2502
- destroy its existing persistent state; without it such a switch is refused.
2506
+ A redeploy KEEPS the app's existing disk automatically: omit --volume and the current disk is
2507
+ carried forward. To remove the disk on purpose pass --no-volume (and --allow-data-wipe, since it
2508
+ destroys the data). If a disk was previously detached by an old CLI, redeploy with --volume <same
2509
+ gb> --region <same region> to reattach the existing disk (it is reused, not recreated empty).
2510
+ --allow-data-wipe acknowledges that dropping a disk, or switching to a placement that can't keep
2511
+ it, destroys the app's existing persistent state; without it such a deploy is refused.
2503
2512
  --allow-namespace-reset acknowledges that a redeploy may start the app from a fresh, empty
2504
2513
  persistent store when its recorded one can no longer be found; without it such a deploy is refused.
2505
2514
  Regions are provider-neutral: auto, us-east, us-west, europe, asia, south-america, middle-east, oceania, africa.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ninepm",
3
- "version": "0.24.1",
3
+ "version": "0.26.0",
4
4
  "description": "CLI for deploying built apps to 9pm.ai.",
5
5
  "type": "module",
6
6
  "license": "SEE LICENSE IN LICENSE.md",