@neopress/cli 3.2.0 → 3.3.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/dist/bin.cjs CHANGED
@@ -3380,6 +3380,10 @@ function fail(message, code = 1) {
3380
3380
  process.exit(code);
3381
3381
  }
3382
3382
 
3383
+ // src/utils/config.ts
3384
+ var import_node_fs2 = require("fs");
3385
+ var import_node_path2 = require("path");
3386
+
3383
3387
  // src/utils/token-store.ts
3384
3388
  var import_node_fs = require("fs");
3385
3389
  var import_node_os = require("os");
@@ -3410,6 +3414,57 @@ function clearSession() {
3410
3414
  saveSession({});
3411
3415
  }
3412
3416
 
3417
+ // src/utils/config.ts
3418
+ var PROJECT_CONFIG = ".neopressrc.json";
3419
+ var WORKSPACE_CONFIG = ".neopress/config.json";
3420
+ function readProjectConfig() {
3421
+ let config = {};
3422
+ for (const file of [PROJECT_CONFIG, WORKSPACE_CONFIG]) {
3423
+ try {
3424
+ const parsed = JSON.parse((0, import_node_fs2.readFileSync)(file, "utf-8"));
3425
+ config = {
3426
+ ...config,
3427
+ ...typeof parsed.siteId === "number" ? { siteId: parsed.siteId } : {},
3428
+ ...typeof parsed.baseUrl === "string" ? { baseUrl: parsed.baseUrl } : {}
3429
+ };
3430
+ } catch {
3431
+ }
3432
+ }
3433
+ return config;
3434
+ }
3435
+ function writeWorkspaceConfig(next) {
3436
+ (0, import_node_fs2.mkdirSync)((0, import_node_path2.dirname)(WORKSPACE_CONFIG), { recursive: true });
3437
+ (0, import_node_fs2.writeFileSync)(WORKSPACE_CONFIG, JSON.stringify(next, null, 2) + "\n", "utf-8");
3438
+ }
3439
+ function getSiteId() {
3440
+ const envSiteId = process.env.NEOPRESS_SITE_ID;
3441
+ if (envSiteId) return parseInt(envSiteId, 10);
3442
+ const projectConfig = readProjectConfig();
3443
+ if (projectConfig.siteId) return projectConfig.siteId;
3444
+ return loadSession().activeSiteId;
3445
+ }
3446
+ function getBaseUrl() {
3447
+ return process.env.NEOPRESS_BASE_URL || readProjectConfig().baseUrl || "https://app.neopress.ai";
3448
+ }
3449
+ function setActiveSiteId(siteId) {
3450
+ const session = loadSession();
3451
+ saveSession({ ...session, activeSiteId: siteId });
3452
+ if ((0, import_node_fs2.existsSync)(".neopress") || (0, import_node_fs2.existsSync)(WORKSPACE_CONFIG)) {
3453
+ writeWorkspaceConfig({ ...readProjectConfig(), siteId });
3454
+ }
3455
+ }
3456
+ var siteOverride;
3457
+ function setSiteOverride(value) {
3458
+ siteOverride = value;
3459
+ }
3460
+ function getSiteTarget() {
3461
+ if (siteOverride) {
3462
+ const n = parseInt(siteOverride, 10);
3463
+ return String(n) === siteOverride ? n : siteOverride;
3464
+ }
3465
+ return getSiteId();
3466
+ }
3467
+
3413
3468
  // src/utils/pkce.ts
3414
3469
  var import_node_crypto = require("crypto");
3415
3470
  function generateCodeVerifier() {
@@ -3666,13 +3721,15 @@ ${openUrl}`);
3666
3721
  const accessToken = await getValidAccessToken();
3667
3722
  const now = Math.floor(Date.now() / 1e3);
3668
3723
  const expired = session.tokens.expiresAt <= now;
3724
+ const authenticated = Boolean(accessToken);
3669
3725
  output({
3670
- authenticated: Boolean(accessToken),
3726
+ authenticated,
3671
3727
  method: "oauth",
3672
3728
  userId: session.tokens.userId,
3673
3729
  tokenExpired: expired && !accessToken,
3674
3730
  activeSiteId: session.activeSiteId || null
3675
3731
  });
3732
+ if (!authenticated) process.exitCode = 1;
3676
3733
  return;
3677
3734
  }
3678
3735
  fail("Not authenticated. Run `neopress login`.");
@@ -3941,6 +3998,10 @@ var SiteEndpoint = class {
3941
3998
  const res = await this.client.patch(`${this.client.siteBasePath}/layout`, data);
3942
3999
  return res.data;
3943
4000
  }
4001
+ async delete() {
4002
+ const res = await this.client.delete(this.client.siteBasePath);
4003
+ return res.data;
4004
+ }
3944
4005
  };
3945
4006
 
3946
4007
  // ../sdk/dist/endpoints/redirects.js
@@ -4109,6 +4170,19 @@ var TemplatesEndpoint = class {
4109
4170
  const res = await this.client.delete(this.basePath);
4110
4171
  return res.data;
4111
4172
  }
4173
+ async list(params) {
4174
+ const qs = new URLSearchParams();
4175
+ if (params?.namePrefix)
4176
+ qs.set("namePrefix", params.namePrefix);
4177
+ if (params?.industry)
4178
+ qs.set("industry", params.industry);
4179
+ if (params?.limit != null)
4180
+ qs.set("limit", String(params.limit));
4181
+ const query = qs.toString();
4182
+ const path = query ? `/api/v1/templates?${query}` : "/api/v1/templates";
4183
+ const res = await this.client.get(path);
4184
+ return res.data;
4185
+ }
4112
4186
  };
4113
4187
 
4114
4188
  // ../sdk/dist/client.js
@@ -4204,70 +4278,20 @@ var NeopressClient = class {
4204
4278
  }
4205
4279
  };
4206
4280
 
4207
- // src/utils/config.ts
4208
- var import_node_fs2 = require("fs");
4209
- var import_node_path2 = require("path");
4210
- var PROJECT_CONFIG = ".neopressrc.json";
4211
- var WORKSPACE_CONFIG = ".neopress/config.json";
4212
- function readProjectConfig() {
4213
- let config = {};
4214
- for (const file of [PROJECT_CONFIG, WORKSPACE_CONFIG]) {
4215
- try {
4216
- const parsed = JSON.parse((0, import_node_fs2.readFileSync)(file, "utf-8"));
4217
- config = {
4218
- ...config,
4219
- ...typeof parsed.siteId === "number" ? { siteId: parsed.siteId } : {},
4220
- ...typeof parsed.baseUrl === "string" ? { baseUrl: parsed.baseUrl } : {}
4221
- };
4222
- } catch {
4223
- }
4224
- }
4225
- return config;
4226
- }
4227
- function writeWorkspaceConfig(next) {
4228
- (0, import_node_fs2.mkdirSync)((0, import_node_path2.dirname)(WORKSPACE_CONFIG), { recursive: true });
4229
- (0, import_node_fs2.writeFileSync)(WORKSPACE_CONFIG, JSON.stringify(next, null, 2) + "\n", "utf-8");
4230
- }
4231
- function getSiteId() {
4232
- const envSiteId = process.env.NEOPRESS_SITE_ID;
4233
- if (envSiteId) return parseInt(envSiteId, 10);
4234
- const projectConfig = readProjectConfig();
4235
- if (projectConfig.siteId) return projectConfig.siteId;
4236
- return loadSession().activeSiteId;
4237
- }
4238
- function getBaseUrl() {
4239
- return process.env.NEOPRESS_BASE_URL || readProjectConfig().baseUrl || "https://app.neopress.ai";
4240
- }
4241
- function setActiveSiteId(siteId) {
4242
- const session = loadSession();
4243
- saveSession({ ...session, activeSiteId: siteId });
4244
- if ((0, import_node_fs2.existsSync)(".neopress") || (0, import_node_fs2.existsSync)(WORKSPACE_CONFIG)) {
4245
- writeWorkspaceConfig({ ...readProjectConfig(), siteId });
4246
- }
4247
- }
4248
-
4249
4281
  // src/utils/client.ts
4250
4282
  async function getClientAsync(siteIdOverride) {
4251
- const siteId = siteIdOverride ?? getSiteId();
4283
+ const siteId = siteIdOverride ?? getSiteTarget();
4252
4284
  if (!siteId) {
4253
- fail("No site selected. Run `neopress sites use <siteId>` or set NEOPRESS_SITE_ID.");
4285
+ fail("No site selected. Run `neopress sites use <siteId>`, pass --site, or set NEOPRESS_SITE_ID.");
4254
4286
  }
4255
4287
  if (process.env.NEOPRESS_ACCESS_TOKEN) {
4256
- return new NeopressClient({
4257
- accessToken: process.env.NEOPRESS_ACCESS_TOKEN,
4258
- siteId,
4259
- baseUrl: getBaseUrl()
4260
- });
4288
+ return new NeopressClient({ accessToken: process.env.NEOPRESS_ACCESS_TOKEN, siteId, baseUrl: getBaseUrl() });
4261
4289
  }
4262
4290
  const accessToken = await getValidAccessToken();
4263
4291
  if (!accessToken) {
4264
4292
  fail("Session expired. Run `neopress login` again.");
4265
4293
  }
4266
- return new NeopressClient({
4267
- accessToken,
4268
- siteId,
4269
- baseUrl: getBaseUrl()
4270
- });
4294
+ return new NeopressClient({ accessToken, siteId, baseUrl: getBaseUrl() });
4271
4295
  }
4272
4296
 
4273
4297
  // src/commands/sites.ts
@@ -4357,6 +4381,28 @@ function registerSiteCommands(program3) {
4357
4381
  const site = await client.site.update(data);
4358
4382
  output(site);
4359
4383
  });
4384
+ sites.command("delete <siteIdOrHandle>").description("Delete a site and all its content (workspace admin only)").option("--yes", "Skip confirmation (required in non-interactive mode)").action(async (siteIdOrHandle, options) => {
4385
+ const interactive = process.stdout.isTTY && process.stdin.isTTY;
4386
+ if (!options.yes && !interactive) {
4387
+ fail("Refusing to delete without --yes in non-interactive mode.");
4388
+ }
4389
+ if (!options.yes && interactive) {
4390
+ const { createInterface } = await import("readline");
4391
+ const rl = createInterface({ input: process.stdin, output: process.stdout });
4392
+ const answer = await new Promise(
4393
+ (resolve) => rl.question(`Delete site "${siteIdOrHandle}" and ALL its content? Type the id/handle to confirm: `, (a) => {
4394
+ rl.close();
4395
+ resolve(a.trim());
4396
+ })
4397
+ );
4398
+ if (answer !== siteIdOrHandle) {
4399
+ fail("Confirmation did not match. Aborted.");
4400
+ }
4401
+ }
4402
+ const client = await getClientAsync(siteIdOrHandle);
4403
+ const result = await client.site.delete();
4404
+ output(result);
4405
+ });
4360
4406
  }
4361
4407
 
4362
4408
  // src/commands/pages.ts
@@ -4906,6 +4952,19 @@ function collectPreviewImgUrl(value, previous = []) {
4906
4952
  }
4907
4953
  function registerTemplateCommands(program3) {
4908
4954
  const templates = program3.command("templates").description("Manage template metadata for the active site");
4955
+ templates.command("list").description("List templates across sites you can access").option("--name-prefix <prefix>", "Filter by template name prefix").option("--industry <industry>", "Filter by industry key").option("--limit <n>", "Max results (default 100, max 500)").action(async (options) => {
4956
+ const token = process.env.NEOPRESS_ACCESS_TOKEN || await getValidAccessToken() || void 0;
4957
+ if (!token) {
4958
+ fail("Not authenticated. Run `neopress login`.");
4959
+ }
4960
+ const client = new NeopressClient({ accessToken: token, siteId: 0, baseUrl: getBaseUrl() });
4961
+ const templates2 = await client.templates.list({
4962
+ namePrefix: options.namePrefix,
4963
+ industry: options.industry,
4964
+ limit: options.limit ? parseInt(options.limit, 10) : void 0
4965
+ });
4966
+ output(templates2);
4967
+ });
4909
4968
  templates.command("get").description("Get template metadata for the active site").action(async () => {
4910
4969
  const client = await getClientAsync();
4911
4970
  const template = await client.templates.get();
@@ -4916,7 +4975,7 @@ function registerTemplateCommands(program3) {
4916
4975
  "Reference URL for template provenance"
4917
4976
  ).option(
4918
4977
  "--preview-img-url <url>",
4919
- "Preview image URL. Repeat for multiple images.",
4978
+ "Preview image URL (required \u2014 at least one). Repeat for multiple images.",
4920
4979
  collectPreviewImgUrl,
4921
4980
  []
4922
4981
  ).action(async (options) => {
@@ -4939,9 +4998,10 @@ function registerTemplateCommands(program3) {
4939
4998
 
4940
4999
  // src/bin.ts
4941
5000
  var program2 = new Command();
4942
- program2.name("neopress").description("Neopress CLI \u2014 manage your site from the terminal").version("3.2.0").option("--json", "Output in JSON format (for AI tools and pipes)").option("--no-input", "Non-interactive mode").hook("preAction", (thisCommand) => {
5001
+ program2.name("neopress").description("Neopress CLI \u2014 manage your site from the terminal").version("3.3.0").option("--json", "Output in JSON format (for AI tools and pipes)").option("--site <idOrHandle>", "Target a specific site (overrides active site; not persisted)").option("--no-input", "Non-interactive mode").hook("preAction", (thisCommand) => {
4943
5002
  const opts = thisCommand.optsWithGlobals();
4944
- if (opts.json) setJsonMode(true);
5003
+ if (opts.site) setSiteOverride(String(opts.site));
5004
+ if (opts.json || !process.stdout.isTTY) setJsonMode(true);
4945
5005
  });
4946
5006
  registerAuthCommands(program2);
4947
5007
  registerSiteCommands(program2);
package/dist/index.d.ts CHANGED
@@ -8,12 +8,12 @@ import { NeopressClient } from './client.js';
8
8
  * 2. Stored OAuth access token (with auto-refresh in getClientAsync)
9
9
  */
10
10
 
11
- declare function getClient(siteIdOverride?: number): NeopressClient;
11
+ declare function getClient(siteIdOverride?: number | string): NeopressClient;
12
12
  /**
13
13
  * Get client with guaranteed fresh OAuth token.
14
14
  * Use this for commands that might run after the token expired.
15
15
  */
16
- declare function getClientAsync(siteIdOverride?: number): Promise<NeopressClient>;
16
+ declare function getClientAsync(siteIdOverride?: number | string): Promise<NeopressClient>;
17
17
 
18
18
  declare function getAccessToken(): string | undefined;
19
19
  declare function getSiteId(): number | undefined;
package/dist/index.js CHANGED
@@ -260,6 +260,10 @@ var SiteEndpoint = class {
260
260
  const res = await this.client.patch(`${this.client.siteBasePath}/layout`, data);
261
261
  return res.data;
262
262
  }
263
+ async delete() {
264
+ const res = await this.client.delete(this.client.siteBasePath);
265
+ return res.data;
266
+ }
263
267
  };
264
268
 
265
269
  // ../sdk/dist/endpoints/redirects.js
@@ -428,6 +432,19 @@ var TemplatesEndpoint = class {
428
432
  const res = await this.client.delete(this.basePath);
429
433
  return res.data;
430
434
  }
435
+ async list(params) {
436
+ const qs = new URLSearchParams();
437
+ if (params?.namePrefix)
438
+ qs.set("namePrefix", params.namePrefix);
439
+ if (params?.industry)
440
+ qs.set("industry", params.industry);
441
+ if (params?.limit != null)
442
+ qs.set("limit", String(params.limit));
443
+ const query = qs.toString();
444
+ const path = query ? `/api/v1/templates?${query}` : "/api/v1/templates";
445
+ const res = await this.client.get(path);
446
+ return res.data;
447
+ }
431
448
  };
432
449
 
433
450
  // ../sdk/dist/client.js
@@ -658,45 +675,41 @@ function setActiveSiteId(siteId) {
658
675
  writeWorkspaceConfig({ ...readProjectConfig(), siteId });
659
676
  }
660
677
  }
678
+ var siteOverride;
679
+ function getSiteTarget() {
680
+ if (siteOverride) {
681
+ const n = parseInt(siteOverride, 10);
682
+ return String(n) === siteOverride ? n : siteOverride;
683
+ }
684
+ return getSiteId();
685
+ }
661
686
 
662
687
  // src/utils/client.ts
663
688
  function getClient(siteIdOverride) {
664
689
  const session = loadSession();
665
690
  const accessToken = process.env.NEOPRESS_ACCESS_TOKEN || session.tokens?.accessToken;
666
- const siteId = siteIdOverride ?? getSiteId();
691
+ const siteId = siteIdOverride ?? getSiteTarget();
667
692
  if (!siteId) {
668
- fail("No site selected. Run `neopress sites use <siteId>` or set NEOPRESS_SITE_ID.");
693
+ fail("No site selected. Run `neopress sites use <siteId>`, pass --site, or set NEOPRESS_SITE_ID.");
669
694
  }
670
695
  if (accessToken) {
671
- return new NeopressClient({
672
- accessToken,
673
- siteId,
674
- baseUrl: getBaseUrl()
675
- });
696
+ return new NeopressClient({ accessToken, siteId, baseUrl: getBaseUrl() });
676
697
  }
677
698
  fail("Not authenticated. Run `neopress login` or set NEOPRESS_ACCESS_TOKEN.");
678
699
  }
679
700
  async function getClientAsync(siteIdOverride) {
680
- const siteId = siteIdOverride ?? getSiteId();
701
+ const siteId = siteIdOverride ?? getSiteTarget();
681
702
  if (!siteId) {
682
- fail("No site selected. Run `neopress sites use <siteId>` or set NEOPRESS_SITE_ID.");
703
+ fail("No site selected. Run `neopress sites use <siteId>`, pass --site, or set NEOPRESS_SITE_ID.");
683
704
  }
684
705
  if (process.env.NEOPRESS_ACCESS_TOKEN) {
685
- return new NeopressClient({
686
- accessToken: process.env.NEOPRESS_ACCESS_TOKEN,
687
- siteId,
688
- baseUrl: getBaseUrl()
689
- });
706
+ return new NeopressClient({ accessToken: process.env.NEOPRESS_ACCESS_TOKEN, siteId, baseUrl: getBaseUrl() });
690
707
  }
691
708
  const accessToken = await getValidAccessToken();
692
709
  if (!accessToken) {
693
710
  fail("Session expired. Run `neopress login` again.");
694
711
  }
695
- return new NeopressClient({
696
- accessToken,
697
- siteId,
698
- baseUrl: getBaseUrl()
699
- });
712
+ return new NeopressClient({ accessToken, siteId, baseUrl: getBaseUrl() });
700
713
  }
701
714
  export {
702
715
  clearSession,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@neopress/cli",
3
- "version": "3.2.0",
3
+ "version": "3.3.0",
4
4
  "description": "Neopress CLI — manage your Neopress site from the terminal",
5
5
  "type": "module",
6
6
  "bin": {
@@ -19,7 +19,7 @@
19
19
  "commander": "^13.0.0",
20
20
  "tsup": "^8.5.1",
21
21
  "typescript": "^5.7.0",
22
- "@neopress/sdk": "0.3.1"
22
+ "@neopress/sdk": "0.4.0"
23
23
  },
24
24
  "scripts": {
25
25
  "build": "tsup",