@neopress/cli 4.0.0 → 4.2.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 +109 -0
- package/dist/bin.cjs +697 -117
- package/dist/index.js +207 -44
- package/package.json +12 -2
package/dist/bin.cjs
CHANGED
|
@@ -3387,6 +3387,7 @@ function fail(message, code = 1) {
|
|
|
3387
3387
|
// src/utils/config.ts
|
|
3388
3388
|
var import_node_fs2 = require("fs");
|
|
3389
3389
|
var import_node_path2 = require("path");
|
|
3390
|
+
var import_node_os2 = require("os");
|
|
3390
3391
|
|
|
3391
3392
|
// src/utils/token-store.ts
|
|
3392
3393
|
var import_node_fs = require("fs");
|
|
@@ -3421,31 +3422,55 @@ function clearSession() {
|
|
|
3421
3422
|
// src/utils/config.ts
|
|
3422
3423
|
var PROJECT_CONFIG = ".neopressrc.json";
|
|
3423
3424
|
var WORKSPACE_CONFIG = ".neopress/config.json";
|
|
3424
|
-
function
|
|
3425
|
-
|
|
3426
|
-
|
|
3427
|
-
|
|
3428
|
-
|
|
3429
|
-
|
|
3430
|
-
|
|
3431
|
-
|
|
3432
|
-
|
|
3433
|
-
|
|
3434
|
-
|
|
3425
|
+
function readConfigFileAt(path) {
|
|
3426
|
+
try {
|
|
3427
|
+
const parsed = JSON.parse((0, import_node_fs2.readFileSync)(path, "utf-8"));
|
|
3428
|
+
return {
|
|
3429
|
+
...typeof parsed.siteId === "number" ? { siteId: parsed.siteId } : {},
|
|
3430
|
+
...typeof parsed.baseUrl === "string" ? { baseUrl: parsed.baseUrl } : {}
|
|
3431
|
+
};
|
|
3432
|
+
} catch {
|
|
3433
|
+
return {};
|
|
3434
|
+
}
|
|
3435
|
+
}
|
|
3436
|
+
function locateProjectConfig(startDir = process.cwd()) {
|
|
3437
|
+
const home = (0, import_node_path2.resolve)((0, import_node_os2.homedir)());
|
|
3438
|
+
let dir = (0, import_node_path2.resolve)(startDir);
|
|
3439
|
+
while (true) {
|
|
3440
|
+
let merged = {};
|
|
3441
|
+
let foundPath;
|
|
3442
|
+
for (const rel of [PROJECT_CONFIG, WORKSPACE_CONFIG]) {
|
|
3443
|
+
const p = (0, import_node_path2.join)(dir, rel);
|
|
3444
|
+
const cfg = readConfigFileAt(p);
|
|
3445
|
+
if (Object.keys(cfg).length > 0) {
|
|
3446
|
+
merged = { ...merged, ...cfg };
|
|
3447
|
+
if (!foundPath) foundPath = p;
|
|
3448
|
+
}
|
|
3435
3449
|
}
|
|
3450
|
+
if (Object.keys(merged).length > 0) return { config: merged, path: foundPath };
|
|
3451
|
+
const parent = (0, import_node_path2.dirname)(dir);
|
|
3452
|
+
if (dir === home || parent === dir) break;
|
|
3453
|
+
dir = parent;
|
|
3436
3454
|
}
|
|
3437
|
-
return
|
|
3455
|
+
return { config: {} };
|
|
3456
|
+
}
|
|
3457
|
+
function readProjectConfig() {
|
|
3458
|
+
return locateProjectConfig().config;
|
|
3438
3459
|
}
|
|
3439
3460
|
function writeWorkspaceConfig(next) {
|
|
3440
3461
|
(0, import_node_fs2.mkdirSync)((0, import_node_path2.dirname)(WORKSPACE_CONFIG), { recursive: true });
|
|
3441
3462
|
(0, import_node_fs2.writeFileSync)(WORKSPACE_CONFIG, JSON.stringify(next, null, 2) + "\n", "utf-8");
|
|
3442
3463
|
}
|
|
3443
|
-
function
|
|
3444
|
-
|
|
3445
|
-
|
|
3446
|
-
|
|
3447
|
-
|
|
3448
|
-
|
|
3464
|
+
function writeProjectSiteId(siteId) {
|
|
3465
|
+
let raw = {};
|
|
3466
|
+
try {
|
|
3467
|
+
const parsed = JSON.parse((0, import_node_fs2.readFileSync)(PROJECT_CONFIG, "utf-8"));
|
|
3468
|
+
if (parsed && typeof parsed === "object") raw = parsed;
|
|
3469
|
+
} catch {
|
|
3470
|
+
}
|
|
3471
|
+
const next = { ...raw, siteId };
|
|
3472
|
+
(0, import_node_fs2.writeFileSync)(PROJECT_CONFIG, JSON.stringify(next, null, 2) + "\n", "utf-8");
|
|
3473
|
+
return (0, import_node_path2.resolve)(PROJECT_CONFIG);
|
|
3449
3474
|
}
|
|
3450
3475
|
function getBaseUrl() {
|
|
3451
3476
|
return process.env.NEOPRESS_BASE_URL || readProjectConfig().baseUrl || "https://app.neopress.ai";
|
|
@@ -3461,12 +3486,24 @@ var siteOverride;
|
|
|
3461
3486
|
function setSiteOverride(value) {
|
|
3462
3487
|
siteOverride = value;
|
|
3463
3488
|
}
|
|
3464
|
-
function
|
|
3489
|
+
function resolveSiteTarget() {
|
|
3465
3490
|
if (siteOverride) {
|
|
3466
3491
|
const n = parseInt(siteOverride, 10);
|
|
3467
|
-
|
|
3492
|
+
const value = String(n) === siteOverride ? n : siteOverride;
|
|
3493
|
+
return { value, source: "flag", detail: "--site" };
|
|
3468
3494
|
}
|
|
3469
|
-
|
|
3495
|
+
const envSiteId = process.env.NEOPRESS_SITE_ID;
|
|
3496
|
+
if (envSiteId) return { value: parseInt(envSiteId, 10), source: "env", detail: "NEOPRESS_SITE_ID" };
|
|
3497
|
+
const located = locateProjectConfig();
|
|
3498
|
+
if (typeof located.config.siteId === "number") {
|
|
3499
|
+
return { value: located.config.siteId, source: "project-config", detail: located.path };
|
|
3500
|
+
}
|
|
3501
|
+
const active = loadSession().activeSiteId;
|
|
3502
|
+
if (active) return { value: active, source: "global-active", detail: "sites use" };
|
|
3503
|
+
return { value: void 0, source: "none" };
|
|
3504
|
+
}
|
|
3505
|
+
function getSiteTarget() {
|
|
3506
|
+
return resolveSiteTarget().value;
|
|
3470
3507
|
}
|
|
3471
3508
|
|
|
3472
3509
|
// src/utils/pkce.ts
|
|
@@ -3652,7 +3689,12 @@ function parseImplicitCallbackTokens(callbackUrl) {
|
|
|
3652
3689
|
};
|
|
3653
3690
|
}
|
|
3654
3691
|
function registerAuthCommands(program3) {
|
|
3655
|
-
program3.command("login").description("Authenticate with Neopress").
|
|
3692
|
+
program3.command("login").description("Authenticate with Neopress").addHelpText("after", `
|
|
3693
|
+
Examples:
|
|
3694
|
+
$ neopress login
|
|
3695
|
+
$ neopress login --manual
|
|
3696
|
+
$ neopress login --provider google
|
|
3697
|
+
Default flow opens a browser and listens on a local callback port; use --manual on a headless host to paste the callback URL by hand. After login, run \`neopress sites use <siteId>\` to select a site.`).option("--provider <provider>", "OAuth provider (google)", "google").option("--manual", "Paste the OAuth callback URL manually instead of running a local callback server").action(async (options) => {
|
|
3656
3698
|
console.log(options.manual ? "Starting manual browser login..." : "Opening browser for login...");
|
|
3657
3699
|
const codeVerifier = generateCodeVerifier();
|
|
3658
3700
|
const codeChallenge = generateCodeChallenge(codeVerifier);
|
|
@@ -3754,11 +3796,11 @@ function __rest(s, e) {
|
|
|
3754
3796
|
}
|
|
3755
3797
|
function __awaiter(thisArg, _arguments, P, generator) {
|
|
3756
3798
|
function adopt(value) {
|
|
3757
|
-
return value instanceof P ? value : new P(function(
|
|
3758
|
-
|
|
3799
|
+
return value instanceof P ? value : new P(function(resolve2) {
|
|
3800
|
+
resolve2(value);
|
|
3759
3801
|
});
|
|
3760
3802
|
}
|
|
3761
|
-
return new (P || (P = Promise))(function(
|
|
3803
|
+
return new (P || (P = Promise))(function(resolve2, reject) {
|
|
3762
3804
|
function fulfilled(value) {
|
|
3763
3805
|
try {
|
|
3764
3806
|
step(generator.next(value));
|
|
@@ -3774,7 +3816,7 @@ function __awaiter(thisArg, _arguments, P, generator) {
|
|
|
3774
3816
|
}
|
|
3775
3817
|
}
|
|
3776
3818
|
function step(result) {
|
|
3777
|
-
result.done ?
|
|
3819
|
+
result.done ? resolve2(result.value) : adopt(result.value).then(fulfilled, rejected);
|
|
3778
3820
|
}
|
|
3779
3821
|
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
3780
3822
|
});
|
|
@@ -4145,18 +4187,18 @@ var PostgrestError = class extends Error {
|
|
|
4145
4187
|
}
|
|
4146
4188
|
};
|
|
4147
4189
|
function sleep(ms, signal) {
|
|
4148
|
-
return new Promise((
|
|
4190
|
+
return new Promise((resolve2) => {
|
|
4149
4191
|
if (signal === null || signal === void 0 ? void 0 : signal.aborted) {
|
|
4150
|
-
|
|
4192
|
+
resolve2();
|
|
4151
4193
|
return;
|
|
4152
4194
|
}
|
|
4153
4195
|
const id = setTimeout(() => {
|
|
4154
4196
|
signal === null || signal === void 0 || signal.removeEventListener("abort", onAbort);
|
|
4155
|
-
|
|
4197
|
+
resolve2();
|
|
4156
4198
|
}, ms);
|
|
4157
4199
|
function onAbort() {
|
|
4158
4200
|
clearTimeout(id);
|
|
4159
|
-
|
|
4201
|
+
resolve2();
|
|
4160
4202
|
}
|
|
4161
4203
|
signal === null || signal === void 0 || signal.addEventListener("abort", onAbort);
|
|
4162
4204
|
});
|
|
@@ -12105,15 +12147,15 @@ var RealtimeChannel = class _RealtimeChannel {
|
|
|
12105
12147
|
}
|
|
12106
12148
|
}
|
|
12107
12149
|
} else {
|
|
12108
|
-
return new Promise((
|
|
12150
|
+
return new Promise((resolve2) => {
|
|
12109
12151
|
var _a3, _b2, _c;
|
|
12110
12152
|
const push = this.channelAdapter.push(args.type, args, opts.timeout || this.timeout);
|
|
12111
12153
|
if (args.type === "broadcast" && !((_c = (_b2 = (_a3 = this.params) === null || _a3 === void 0 ? void 0 : _a3.config) === null || _b2 === void 0 ? void 0 : _b2.broadcast) === null || _c === void 0 ? void 0 : _c.ack)) {
|
|
12112
|
-
|
|
12154
|
+
resolve2("ok");
|
|
12113
12155
|
}
|
|
12114
|
-
push.receive("ok", () =>
|
|
12115
|
-
push.receive("error", () =>
|
|
12116
|
-
push.receive("timeout", () =>
|
|
12156
|
+
push.receive("ok", () => resolve2("ok"));
|
|
12157
|
+
push.receive("error", () => resolve2("error"));
|
|
12158
|
+
push.receive("timeout", () => resolve2("timed out"));
|
|
12117
12159
|
});
|
|
12118
12160
|
}
|
|
12119
12161
|
}
|
|
@@ -12138,8 +12180,8 @@ var RealtimeChannel = class _RealtimeChannel {
|
|
|
12138
12180
|
* @category Realtime
|
|
12139
12181
|
*/
|
|
12140
12182
|
async unsubscribe(timeout = this.timeout) {
|
|
12141
|
-
return new Promise((
|
|
12142
|
-
this.channelAdapter.unsubscribe(timeout).receive("ok", () =>
|
|
12183
|
+
return new Promise((resolve2) => {
|
|
12184
|
+
this.channelAdapter.unsubscribe(timeout).receive("ok", () => resolve2("ok")).receive("timeout", () => resolve2("timed out")).receive("error", () => resolve2("error"));
|
|
12143
12185
|
});
|
|
12144
12186
|
}
|
|
12145
12187
|
/**
|
|
@@ -12220,8 +12262,8 @@ var RealtimeChannel = class _RealtimeChannel {
|
|
|
12220
12262
|
}
|
|
12221
12263
|
/** @internal */
|
|
12222
12264
|
_notThisChannelEvent(event, ref) {
|
|
12223
|
-
const { close, error: error48, leave, join:
|
|
12224
|
-
const events = [close, error48, leave,
|
|
12265
|
+
const { close, error: error48, leave, join: join3 } = CHANNEL_EVENTS;
|
|
12266
|
+
const events = [close, error48, leave, join3];
|
|
12225
12267
|
return ref && events.includes(event) && ref !== this.joinPush.ref;
|
|
12226
12268
|
}
|
|
12227
12269
|
/** @internal */
|
|
@@ -12334,11 +12376,11 @@ var SocketAdapter = class {
|
|
|
12334
12376
|
this.socket.connect();
|
|
12335
12377
|
}
|
|
12336
12378
|
disconnect(callback, code, reason, timeout = 1e4) {
|
|
12337
|
-
return new Promise((
|
|
12338
|
-
setTimeout(() =>
|
|
12379
|
+
return new Promise((resolve2) => {
|
|
12380
|
+
setTimeout(() => resolve2("timeout"), timeout);
|
|
12339
12381
|
this.socket.disconnect(() => {
|
|
12340
12382
|
callback();
|
|
12341
|
-
|
|
12383
|
+
resolve2("ok");
|
|
12342
12384
|
}, code, reason);
|
|
12343
12385
|
});
|
|
12344
12386
|
}
|
|
@@ -13752,7 +13794,7 @@ var _getRequestParams = (method, options, parameters, body) => {
|
|
|
13752
13794
|
return _objectSpread22(_objectSpread22({}, params), parameters);
|
|
13753
13795
|
};
|
|
13754
13796
|
async function _handleRequest(fetcher, method, url2, options, parameters, body, namespace) {
|
|
13755
|
-
return new Promise((
|
|
13797
|
+
return new Promise((resolve2, reject) => {
|
|
13756
13798
|
fetcher(url2, _getRequestParams(method, options, parameters, body)).then((result) => {
|
|
13757
13799
|
if (!result.ok) throw result;
|
|
13758
13800
|
if (options === null || options === void 0 ? void 0 : options.noResolveJson) return result;
|
|
@@ -13762,7 +13804,7 @@ async function _handleRequest(fetcher, method, url2, options, parameters, body,
|
|
|
13762
13804
|
if (!contentType || !contentType.includes("application/json")) return {};
|
|
13763
13805
|
}
|
|
13764
13806
|
return result.json();
|
|
13765
|
-
}).then((data) =>
|
|
13807
|
+
}).then((data) => resolve2(data)).catch((error48) => handleError(error48, reject, options, namespace));
|
|
13766
13808
|
});
|
|
13767
13809
|
}
|
|
13768
13810
|
function createFetchApi(namespace = "storage") {
|
|
@@ -24007,11 +24049,11 @@ var DEFAULT_TRACE_PROPAGATION_OPTIONS = {
|
|
|
24007
24049
|
};
|
|
24008
24050
|
function __awaiter2(thisArg, _arguments, P, generator) {
|
|
24009
24051
|
function adopt(value) {
|
|
24010
|
-
return value instanceof P ? value : new P(function(
|
|
24011
|
-
|
|
24052
|
+
return value instanceof P ? value : new P(function(resolve2) {
|
|
24053
|
+
resolve2(value);
|
|
24012
24054
|
});
|
|
24013
24055
|
}
|
|
24014
|
-
return new (P || (P = Promise))(function(
|
|
24056
|
+
return new (P || (P = Promise))(function(resolve2, reject) {
|
|
24015
24057
|
function fulfilled(value) {
|
|
24016
24058
|
try {
|
|
24017
24059
|
step(generator.next(value));
|
|
@@ -24027,7 +24069,7 @@ function __awaiter2(thisArg, _arguments, P, generator) {
|
|
|
24027
24069
|
}
|
|
24028
24070
|
}
|
|
24029
24071
|
function step(result) {
|
|
24030
|
-
result.done ?
|
|
24072
|
+
result.done ? resolve2(result.value) : adopt(result.value).then(fulfilled, rejected);
|
|
24031
24073
|
}
|
|
24032
24074
|
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
24033
24075
|
});
|
|
@@ -24882,6 +24924,27 @@ function serializeTemplate(t) {
|
|
|
24882
24924
|
createdAt: t.created_at
|
|
24883
24925
|
};
|
|
24884
24926
|
}
|
|
24927
|
+
function serializeHeadshot(h) {
|
|
24928
|
+
return {
|
|
24929
|
+
id: h.id,
|
|
24930
|
+
imageUrl: h.image_url,
|
|
24931
|
+
width: h.width,
|
|
24932
|
+
height: h.height,
|
|
24933
|
+
aspectRatio: h.aspect_ratio,
|
|
24934
|
+
mimeType: h.mime_type,
|
|
24935
|
+
byteSize: h.byte_size,
|
|
24936
|
+
ageBand: h.age_band,
|
|
24937
|
+
gender: h.gender,
|
|
24938
|
+
ethnicity: h.ethnicity,
|
|
24939
|
+
attire: h.attire,
|
|
24940
|
+
variationIndex: h.variation_index,
|
|
24941
|
+
gptPrompt: h.gpt_prompt,
|
|
24942
|
+
tags: h.tags ?? [],
|
|
24943
|
+
isActive: h.is_active,
|
|
24944
|
+
createdAt: h.created_at,
|
|
24945
|
+
updatedAt: h.updated_at
|
|
24946
|
+
};
|
|
24947
|
+
}
|
|
24885
24948
|
function serializeSite(site) {
|
|
24886
24949
|
return {
|
|
24887
24950
|
id: site.id,
|
|
@@ -39228,8 +39291,8 @@ var SiteHistoryService = class _SiteHistoryService {
|
|
|
39228
39291
|
const previousLock = _SiteHistoryService.sessionLocks.get(key) ?? Promise.resolve();
|
|
39229
39292
|
let releaseCurrentLock = () => {
|
|
39230
39293
|
};
|
|
39231
|
-
const currentLock = new Promise((
|
|
39232
|
-
releaseCurrentLock =
|
|
39294
|
+
const currentLock = new Promise((resolve2) => {
|
|
39295
|
+
releaseCurrentLock = resolve2;
|
|
39233
39296
|
});
|
|
39234
39297
|
const queuedLock = previousLock.catch(() => {
|
|
39235
39298
|
}).then(() => currentLock);
|
|
@@ -40564,6 +40627,113 @@ var TemplatesEndpoint = class {
|
|
|
40564
40627
|
}
|
|
40565
40628
|
};
|
|
40566
40629
|
|
|
40630
|
+
// ../sdk/dist/endpoints/headshots.js
|
|
40631
|
+
var HeadshotsEndpoint = class {
|
|
40632
|
+
client;
|
|
40633
|
+
constructor(client) {
|
|
40634
|
+
this.client = client;
|
|
40635
|
+
}
|
|
40636
|
+
async list(params) {
|
|
40637
|
+
const { page, limit, offset } = this.client.resolvePagination(params);
|
|
40638
|
+
let query = this.client.db.from("headshot_pool").select("*", { count: "exact" });
|
|
40639
|
+
if (params?.ageBand)
|
|
40640
|
+
query = query.eq("age_band", params.ageBand);
|
|
40641
|
+
if (params?.gender)
|
|
40642
|
+
query = query.eq("gender", params.gender);
|
|
40643
|
+
if (params?.ethnicity)
|
|
40644
|
+
query = query.eq("ethnicity", params.ethnicity);
|
|
40645
|
+
if (params?.attire)
|
|
40646
|
+
query = query.eq("attire", params.attire);
|
|
40647
|
+
if (params?.isActive !== void 0)
|
|
40648
|
+
query = query.eq("is_active", params.isActive);
|
|
40649
|
+
const { data, error: error48, count } = await query.order("age_band", { ascending: true }).order("gender", { ascending: true }).order("ethnicity", { ascending: true }).order("variation_index", { ascending: true }).range(offset, offset + limit - 1);
|
|
40650
|
+
if (error48)
|
|
40651
|
+
throw new NeopressApiError("DB_ERROR", error48.message, 0, error48);
|
|
40652
|
+
return {
|
|
40653
|
+
data: (data ?? []).map((r) => serializeHeadshot(r)),
|
|
40654
|
+
pagination: this.client.paginationMeta(page, limit, offset, count ?? 0)
|
|
40655
|
+
};
|
|
40656
|
+
}
|
|
40657
|
+
async get(id) {
|
|
40658
|
+
const { data, error: error48 } = await this.client.db.from("headshot_pool").select("*").eq("id", id).single();
|
|
40659
|
+
if (error48)
|
|
40660
|
+
throw new NeopressApiError("DB_ERROR", error48.message, 0, error48);
|
|
40661
|
+
return serializeHeadshot(data);
|
|
40662
|
+
}
|
|
40663
|
+
async create(params) {
|
|
40664
|
+
const values = {
|
|
40665
|
+
image_url: params.imageUrl,
|
|
40666
|
+
age_band: params.ageBand,
|
|
40667
|
+
gender: params.gender,
|
|
40668
|
+
ethnicity: params.ethnicity,
|
|
40669
|
+
variation_index: params.variationIndex
|
|
40670
|
+
};
|
|
40671
|
+
if (params.attire !== void 0)
|
|
40672
|
+
values.attire = params.attire;
|
|
40673
|
+
if (params.width !== void 0)
|
|
40674
|
+
values.width = params.width;
|
|
40675
|
+
if (params.height !== void 0)
|
|
40676
|
+
values.height = params.height;
|
|
40677
|
+
if (params.aspectRatio !== void 0)
|
|
40678
|
+
values.aspect_ratio = params.aspectRatio;
|
|
40679
|
+
if (params.mimeType !== void 0)
|
|
40680
|
+
values.mime_type = params.mimeType;
|
|
40681
|
+
if (params.byteSize !== void 0)
|
|
40682
|
+
values.byte_size = params.byteSize;
|
|
40683
|
+
if (params.gptPrompt !== void 0)
|
|
40684
|
+
values.gpt_prompt = params.gptPrompt;
|
|
40685
|
+
if (params.tags !== void 0)
|
|
40686
|
+
values.tags = params.tags;
|
|
40687
|
+
if (params.isActive !== void 0)
|
|
40688
|
+
values.is_active = params.isActive;
|
|
40689
|
+
const { data, error: error48 } = await this.client.db.from("headshot_pool").insert(values).select().single();
|
|
40690
|
+
if (error48)
|
|
40691
|
+
throw new NeopressApiError("DB_ERROR", error48.message, 0, error48);
|
|
40692
|
+
return serializeHeadshot(data);
|
|
40693
|
+
}
|
|
40694
|
+
async update(id, params) {
|
|
40695
|
+
const values = {};
|
|
40696
|
+
if (params.imageUrl !== void 0)
|
|
40697
|
+
values.image_url = params.imageUrl;
|
|
40698
|
+
if (params.ageBand !== void 0)
|
|
40699
|
+
values.age_band = params.ageBand;
|
|
40700
|
+
if (params.gender !== void 0)
|
|
40701
|
+
values.gender = params.gender;
|
|
40702
|
+
if (params.ethnicity !== void 0)
|
|
40703
|
+
values.ethnicity = params.ethnicity;
|
|
40704
|
+
if (params.attire !== void 0)
|
|
40705
|
+
values.attire = params.attire;
|
|
40706
|
+
if (params.variationIndex !== void 0)
|
|
40707
|
+
values.variation_index = params.variationIndex;
|
|
40708
|
+
if (params.width !== void 0)
|
|
40709
|
+
values.width = params.width;
|
|
40710
|
+
if (params.height !== void 0)
|
|
40711
|
+
values.height = params.height;
|
|
40712
|
+
if (params.aspectRatio !== void 0)
|
|
40713
|
+
values.aspect_ratio = params.aspectRatio;
|
|
40714
|
+
if (params.mimeType !== void 0)
|
|
40715
|
+
values.mime_type = params.mimeType;
|
|
40716
|
+
if (params.byteSize !== void 0)
|
|
40717
|
+
values.byte_size = params.byteSize;
|
|
40718
|
+
if (params.gptPrompt !== void 0)
|
|
40719
|
+
values.gpt_prompt = params.gptPrompt;
|
|
40720
|
+
if (params.tags !== void 0)
|
|
40721
|
+
values.tags = params.tags;
|
|
40722
|
+
if (params.isActive !== void 0)
|
|
40723
|
+
values.is_active = params.isActive;
|
|
40724
|
+
const { data, error: error48 } = await this.client.db.from("headshot_pool").update(values).eq("id", id).select().single();
|
|
40725
|
+
if (error48)
|
|
40726
|
+
throw new NeopressApiError("DB_ERROR", error48.message, 0, error48);
|
|
40727
|
+
return serializeHeadshot(data);
|
|
40728
|
+
}
|
|
40729
|
+
async delete(id) {
|
|
40730
|
+
const { error: error48 } = await this.client.db.from("headshot_pool").delete().eq("id", id);
|
|
40731
|
+
if (error48)
|
|
40732
|
+
throw new NeopressApiError("DB_ERROR", error48.message, 0, error48);
|
|
40733
|
+
return { id, deleted: true };
|
|
40734
|
+
}
|
|
40735
|
+
};
|
|
40736
|
+
|
|
40567
40737
|
// ../sdk/dist/client.js
|
|
40568
40738
|
var NeopressClient = class {
|
|
40569
40739
|
baseUrl;
|
|
@@ -40584,6 +40754,7 @@ var NeopressClient = class {
|
|
|
40584
40754
|
entryReferences;
|
|
40585
40755
|
analytics;
|
|
40586
40756
|
templates;
|
|
40757
|
+
headshots;
|
|
40587
40758
|
constructor(options) {
|
|
40588
40759
|
this.baseUrl = (options.baseUrl || "https://app.neopress.ai").replace(/\/$/, "");
|
|
40589
40760
|
this.accessToken = options.accessToken || "";
|
|
@@ -40602,6 +40773,7 @@ var NeopressClient = class {
|
|
|
40602
40773
|
this.entryReferences = new EntryReferencesEndpoint(this);
|
|
40603
40774
|
this.analytics = new AnalyticsEndpoint(this);
|
|
40604
40775
|
this.templates = new TemplatesEndpoint(this);
|
|
40776
|
+
this.headshots = new HeadshotsEndpoint(this);
|
|
40605
40777
|
}
|
|
40606
40778
|
get siteBasePath() {
|
|
40607
40779
|
return `/api/v1/sites/${this.siteId}`;
|
|
@@ -40731,39 +40903,42 @@ async function getClientAsync(siteIdOverride) {
|
|
|
40731
40903
|
const sb = getSupabaseConfig();
|
|
40732
40904
|
return new NeopressClient({ accessToken, siteId, baseUrl: getBaseUrl(), supabaseUrl: sb.url, supabaseAnonKey: sb.anonKey });
|
|
40733
40905
|
}
|
|
40906
|
+
async function getGlobalClientAsync() {
|
|
40907
|
+
const token = process.env.NEOPRESS_ACCESS_TOKEN || await getValidAccessToken();
|
|
40908
|
+
if (!token) {
|
|
40909
|
+
fail("Not authenticated. Run `neopress login` or set NEOPRESS_ACCESS_TOKEN.");
|
|
40910
|
+
}
|
|
40911
|
+
const sb = getSupabaseConfig();
|
|
40912
|
+
return new NeopressClient({ accessToken: token, siteId: 0, baseUrl: getBaseUrl(), supabaseUrl: sb.url, supabaseAnonKey: sb.anonKey });
|
|
40913
|
+
}
|
|
40734
40914
|
|
|
40735
40915
|
// src/commands/sites.ts
|
|
40736
40916
|
function registerSiteCommands(program3) {
|
|
40737
|
-
const sites = program3.command("sites").description("Manage sites")
|
|
40917
|
+
const sites = program3.command("sites").description("Manage sites").addHelpText("after", `
|
|
40918
|
+
Examples:
|
|
40919
|
+
$ neopress sites list
|
|
40920
|
+
$ neopress sites create --name "My Site" --handle my-site --use
|
|
40921
|
+
$ neopress sites create --name "My Site" --handle my-site --pin
|
|
40922
|
+
$ neopress sites use my-site
|
|
40923
|
+
$ neopress sites current
|
|
40924
|
+
Run \`sites use <id|handle>\` to set the global active site, or \`sites create --pin\` to scope a site to the current directory. \`sites current\` shows which site commands will target and why.`);
|
|
40738
40925
|
sites.command("list").description("List accessible sites").action(async () => {
|
|
40739
|
-
const
|
|
40740
|
-
if (!token) {
|
|
40741
|
-
fail("Not authenticated. Run `neopress login`.");
|
|
40742
|
-
}
|
|
40743
|
-
const client = new NeopressClient({
|
|
40744
|
-
accessToken: token,
|
|
40745
|
-
siteId: 0,
|
|
40746
|
-
baseUrl: getBaseUrl()
|
|
40747
|
-
});
|
|
40926
|
+
const client = await getGlobalClientAsync();
|
|
40748
40927
|
const sitesList = await client.site.list();
|
|
40749
40928
|
output(sitesList);
|
|
40750
40929
|
});
|
|
40751
|
-
sites.command("use <siteIdOrHandle>").description("Set active site (ID or handle)").
|
|
40930
|
+
sites.command("use <siteIdOrHandle>").description("Set active site (ID or handle)").addHelpText("after", `
|
|
40931
|
+
Examples:
|
|
40932
|
+
$ neopress sites use 12
|
|
40933
|
+
$ neopress sites use my-site
|
|
40934
|
+
Accepts a numeric site ID or a handle (resolved via \`sites list\`). Sets the active site used by all other commands.`).action(async (siteIdOrHandle) => {
|
|
40752
40935
|
const id = parseInt(siteIdOrHandle, 10);
|
|
40753
40936
|
if (!isNaN(id)) {
|
|
40754
40937
|
setActiveSiteId(id);
|
|
40755
40938
|
ok(`Active site set to ${id}`);
|
|
40756
40939
|
return;
|
|
40757
40940
|
}
|
|
40758
|
-
const
|
|
40759
|
-
if (!token) {
|
|
40760
|
-
fail("Not authenticated. Run `neopress login`.");
|
|
40761
|
-
}
|
|
40762
|
-
const client = new NeopressClient({
|
|
40763
|
-
accessToken: token,
|
|
40764
|
-
siteId: 0,
|
|
40765
|
-
baseUrl: getBaseUrl()
|
|
40766
|
-
});
|
|
40941
|
+
const client = await getGlobalClientAsync();
|
|
40767
40942
|
const sitesList = await client.site.list();
|
|
40768
40943
|
const match = sitesList.find((s) => s.handle === siteIdOrHandle);
|
|
40769
40944
|
if (!match) {
|
|
@@ -40772,37 +40947,51 @@ function registerSiteCommands(program3) {
|
|
|
40772
40947
|
setActiveSiteId(match.id);
|
|
40773
40948
|
ok(`Active site set to ${match.id} (${match.handle})`);
|
|
40774
40949
|
});
|
|
40775
|
-
sites.command("create").description("Create a new site").
|
|
40950
|
+
sites.command("create").description("Create a new site").addHelpText("after", `
|
|
40951
|
+
Examples:
|
|
40952
|
+
$ neopress sites create --name "My Site" --handle my-site
|
|
40953
|
+
$ neopress sites create --prompt "a portfolio for a freelance photographer" --use
|
|
40954
|
+
$ neopress sites create --name Acme --handle acme --language en
|
|
40955
|
+
Pass --prompt to auto-generate name/handle, or supply both --name and --handle. --language sets the default content locale (default en).
|
|
40956
|
+
--use sets the new site as the GLOBAL active site (shared across all directories). --pin instead writes ./.neopressrc.json for THIS directory only, leaving the global active site untouched \u2014 prefer it for parallel/automated runs so concurrent builds don't stomp each other's active site.`).option("--name <name>", "Site name").option("--handle <handle>", "Site handle").option("--prompt <prompt>", "Prompt to generate site name/handle").option("--language <locale>", "Default content locale", "en").option("--use", "Set the created site as the global active site").option("--pin", "Pin the created site to this directory via ./.neopressrc.json (no global state)").action(async (options) => {
|
|
40776
40957
|
if (!options.prompt && !(options.name && options.handle)) {
|
|
40777
40958
|
fail("Provide --prompt or both --name and --handle.");
|
|
40778
40959
|
}
|
|
40779
|
-
|
|
40780
|
-
|
|
40781
|
-
fail("Not authenticated. Run `neopress login`.");
|
|
40960
|
+
if (options.use && options.pin) {
|
|
40961
|
+
fail("Pass only one of --use (global active site) or --pin (this directory only).");
|
|
40782
40962
|
}
|
|
40783
|
-
const client =
|
|
40784
|
-
accessToken: token,
|
|
40785
|
-
siteId: 0,
|
|
40786
|
-
baseUrl: getBaseUrl()
|
|
40787
|
-
});
|
|
40963
|
+
const client = await getGlobalClientAsync();
|
|
40788
40964
|
const site = await client.site.create({
|
|
40789
40965
|
siteName: options.name,
|
|
40790
40966
|
siteHandle: options.handle,
|
|
40791
40967
|
prompt: options.prompt,
|
|
40792
40968
|
language: options.language
|
|
40793
40969
|
});
|
|
40794
|
-
if (options.use)
|
|
40795
|
-
|
|
40796
|
-
|
|
40970
|
+
if (options.use) setActiveSiteId(site.id);
|
|
40971
|
+
let pinnedPath;
|
|
40972
|
+
if (options.pin) pinnedPath = writeProjectSiteId(site.id);
|
|
40797
40973
|
output(site);
|
|
40798
|
-
if (
|
|
40974
|
+
if (!isJsonMode()) {
|
|
40975
|
+
if (options.use) ok(`Active site set to ${site.id}`);
|
|
40976
|
+
if (options.pin) ok(`Pinned site ${site.id} for this directory (${pinnedPath})`);
|
|
40977
|
+
}
|
|
40799
40978
|
});
|
|
40800
40979
|
sites.command("get").description("Get current site info").action(async () => {
|
|
40801
40980
|
const client = await getClientAsync();
|
|
40802
40981
|
const site = await client.site.get();
|
|
40803
40982
|
output(site);
|
|
40804
40983
|
});
|
|
40805
|
-
sites.command("
|
|
40984
|
+
sites.command("current").description("Show which site commands will target, and where it resolved from").addHelpText("after", `
|
|
40985
|
+
Resolution order: --site flag > NEOPRESS_SITE_ID > .neopressrc.json/.neopress/config.json (cwd and up) > global active site (set by \`sites use\`).
|
|
40986
|
+
Local check only \u2014 it does not contact the server. Unlike \`whoami\` (which always reports the global active site), this reports the site your next command will actually hit.`).action(() => {
|
|
40987
|
+
const { value, source, detail } = resolveSiteTarget();
|
|
40988
|
+
output({ siteId: value ?? null, source, resolvedFrom: detail ?? null });
|
|
40989
|
+
});
|
|
40990
|
+
sites.command("update").description("Update site settings").addHelpText("after", `
|
|
40991
|
+
Examples:
|
|
40992
|
+
$ neopress sites update --name "New Name"
|
|
40993
|
+
$ neopress sites update --locale-config '{"locales":["en","ko"],"defaultLocale":"en"}'
|
|
40994
|
+
Updates the active site. --locale-config takes inline JSON. Pass at least one of --name or --locale-config.`).option("--name <name>", "Site name").option("--locale-config <json>", "Locale config JSON").action(async (options) => {
|
|
40806
40995
|
const client = await getClientAsync();
|
|
40807
40996
|
const data = {};
|
|
40808
40997
|
if (options.name) data.name = options.name;
|
|
@@ -40819,7 +41008,11 @@ function registerSiteCommands(program3) {
|
|
|
40819
41008
|
const site = await client.site.update(data);
|
|
40820
41009
|
output(site);
|
|
40821
41010
|
});
|
|
40822
|
-
sites.command("delete <siteIdOrHandle>").description("Delete a site and all its content (workspace admin only)").
|
|
41011
|
+
sites.command("delete <siteIdOrHandle>").description("Delete a site and all its content (workspace admin only)").addHelpText("after", `
|
|
41012
|
+
Examples:
|
|
41013
|
+
$ neopress sites delete my-site
|
|
41014
|
+
$ neopress sites delete 12 --yes
|
|
41015
|
+
Permanently deletes the site and all its content (workspace admin only) \u2014 this is a hard delete, not recoverable. Interactive runs prompt for the id/handle to confirm; --yes is required in non-interactive mode.`).option("--yes", "Skip confirmation (required in non-interactive mode)").action(async (siteIdOrHandle, options) => {
|
|
40823
41016
|
const interactive = process.stdout.isTTY && process.stdin.isTTY;
|
|
40824
41017
|
if (!options.yes && !interactive) {
|
|
40825
41018
|
fail("Refusing to delete without --yes in non-interactive mode.");
|
|
@@ -40828,9 +41021,9 @@ function registerSiteCommands(program3) {
|
|
|
40828
41021
|
const { createInterface } = await import("readline");
|
|
40829
41022
|
const rl = createInterface({ input: process.stdin, output: process.stdout });
|
|
40830
41023
|
const answer = await new Promise(
|
|
40831
|
-
(
|
|
41024
|
+
(resolve2) => rl.question(`Delete site "${siteIdOrHandle}" and ALL its content? Type the id/handle to confirm: `, (a) => {
|
|
40832
41025
|
rl.close();
|
|
40833
|
-
|
|
41026
|
+
resolve2(a.trim());
|
|
40834
41027
|
})
|
|
40835
41028
|
);
|
|
40836
41029
|
if (answer !== siteIdOrHandle) {
|
|
@@ -40878,7 +41071,13 @@ function mergeQueryConfigIntoDraftMeta(draftMetaInput, queryConfigInput) {
|
|
|
40878
41071
|
};
|
|
40879
41072
|
}
|
|
40880
41073
|
function registerPageCommands(program3) {
|
|
40881
|
-
const pages = program3.command("pages").description("Manage pages")
|
|
41074
|
+
const pages = program3.command("pages").description("Manage pages").addHelpText("after", `
|
|
41075
|
+
Examples:
|
|
41076
|
+
$ neopress pages create --path /about --title About --tsx ./about.tsx
|
|
41077
|
+
$ neopress pages update <pageId> --tsx ./about.tsx
|
|
41078
|
+
$ neopress pages compile <pageId>
|
|
41079
|
+
|
|
41080
|
+
Draft content fields (--tsx/--i18n/--draft-meta) need \`neopress publish\` to go live. \`pages delete\` is a soft delete.`);
|
|
40882
41081
|
pages.command("list").description("List pages").option("--status <status>", "Filter by status (draft/published)").option("--page <n>", "Page number", "1").option("--limit <n>", "Results per page", "20").action(async (options) => {
|
|
40883
41082
|
const client = await getClientAsync();
|
|
40884
41083
|
const res = await client.pages.list({
|
|
@@ -40893,7 +41092,17 @@ function registerPageCommands(program3) {
|
|
|
40893
41092
|
const page = await client.pages.get(parseInt(pageId, 10));
|
|
40894
41093
|
output(page);
|
|
40895
41094
|
});
|
|
40896
|
-
pages.command("create").description("Create a new page").requiredOption("--path <path>", "Page path (e.g., /about)").option("--title <title>", "Page title").option("--tsx <file>", "TSX file path").option("--i18n <json>", "Page i18n JSON string or @file path").option("--public-locales <locales>", "Comma-separated locale list or JSON string array").option("--metadata <json>", "Page metadata JSON string or @file path").option("--draft-meta <json>", "Draft runtime metadata JSON string or @file path").option("--query-config <json>", "Query config JSON string or @file path; stored as draftMeta.queryConfig").option("--collection <id>", "Collection ID for dynamic pages").option("--type <type>", "Page type (static/dynamic)", "static").
|
|
41095
|
+
pages.command("create").description("Create a new page").requiredOption("--path <path>", "Page path (e.g., /about)").option("--title <title>", "Page title").option("--tsx <file>", "TSX file path").option("--i18n <json>", "Page i18n JSON string or @file path").option("--public-locales <locales>", "Comma-separated locale list or JSON string array").option("--metadata <json>", "Page metadata JSON string or @file path").option("--draft-meta <json>", "Draft runtime metadata JSON string or @file path").option("--query-config <json>", "Query config JSON string or @file path; stored as draftMeta.queryConfig").option("--collection <id>", "Collection ID for dynamic pages").option("--type <type>", "Page type (static/dynamic)", "static").addHelpText(
|
|
41096
|
+
"after",
|
|
41097
|
+
`
|
|
41098
|
+
Examples:
|
|
41099
|
+
$ neopress pages create --path /about --title About --tsx ./about.tsx
|
|
41100
|
+
$ neopress pages create --path /blog --type dynamic --collection 12 --tsx ./blog.tsx
|
|
41101
|
+
$ neopress pages create --path /about --i18n @i18n.json --public-locales en,ko
|
|
41102
|
+
|
|
41103
|
+
--tsx reads the component from a file. JSON options take inline JSON or @file (e.g. --i18n @i18n.json).
|
|
41104
|
+
Pages are created as drafts \u2014 run \`neopress publish\` to make them live.`
|
|
41105
|
+
).action(async (options) => {
|
|
40897
41106
|
const client = await getClientAsync();
|
|
40898
41107
|
const draftTsx = options.tsx ? (0, import_node_fs3.readFileSync)(options.tsx, "utf-8") : void 0;
|
|
40899
41108
|
const draftI18n = parseJsonInput(options.i18n);
|
|
@@ -40914,7 +41123,13 @@ function registerPageCommands(program3) {
|
|
|
40914
41123
|
});
|
|
40915
41124
|
output(page);
|
|
40916
41125
|
});
|
|
40917
|
-
pages.command("update <pageId>").description("Update a page").
|
|
41126
|
+
pages.command("update <pageId>").description("Update a page").addHelpText("after", `
|
|
41127
|
+
Examples:
|
|
41128
|
+
$ neopress pages update 12 --tsx ./about.tsx
|
|
41129
|
+
$ neopress pages update 12 --title About --path /about-us
|
|
41130
|
+
$ neopress pages update 12 --collection 12 --query-config @query.json
|
|
41131
|
+
|
|
41132
|
+
Pass at least one field flag. --tsx reads the component from a file; JSON options take inline JSON or @file. Draft content (--tsx/--i18n/--draft-meta/--query-config) needs \`neopress publish\` to go live; --title/--path/--collection apply immediately.`).option("--path <path>", "New page path").option("--title <title>", "New title").option("--tsx <file>", "TSX file path").option("--i18n <json>", "Page i18n JSON string or @file path").option("--public-locales <locales>", "Comma-separated locale list or JSON string array").option("--metadata <json>", "Page metadata JSON string or @file path").option("--draft-meta <json>", "Draft runtime metadata JSON string or @file path").option("--query-config <json>", "Query config JSON string or @file path; stored as draftMeta.queryConfig").option("--collection <id>", "Collection ID for dynamic pages").action(async (pageId, options) => {
|
|
40918
41133
|
const client = await getClientAsync();
|
|
40919
41134
|
const data = {};
|
|
40920
41135
|
if (options.path) data.path = options.path;
|
|
@@ -40938,7 +41153,11 @@ function registerPageCommands(program3) {
|
|
|
40938
41153
|
await client.pages.delete(parseInt(pageId, 10));
|
|
40939
41154
|
ok(`Page ${pageId} deleted`);
|
|
40940
41155
|
});
|
|
40941
|
-
pages.command("compile <pageId>").description("Validate TSX compilation").
|
|
41156
|
+
pages.command("compile <pageId>").description("Validate TSX compilation").addHelpText("after", `
|
|
41157
|
+
Examples:
|
|
41158
|
+
$ neopress pages compile 12
|
|
41159
|
+
|
|
41160
|
+
Validates the page's draft TSX and reports compile status \u2014 it does not save or publish.`).action(async (pageId) => {
|
|
40942
41161
|
const client = await getClientAsync();
|
|
40943
41162
|
const result = await client.pages.compile(parseInt(pageId, 10));
|
|
40944
41163
|
output(result);
|
|
@@ -40952,7 +41171,13 @@ function parseJsonInput2(input) {
|
|
|
40952
41171
|
return input.startsWith("@") ? JSON.parse((0, import_node_fs4.readFileSync)(input.slice(1), "utf-8")) : JSON.parse(input);
|
|
40953
41172
|
}
|
|
40954
41173
|
function registerCollectionCommands(program3) {
|
|
40955
|
-
const collections = program3.command("collections").description("Manage collections")
|
|
41174
|
+
const collections = program3.command("collections").description("Manage collections").addHelpText("after", `
|
|
41175
|
+
Examples:
|
|
41176
|
+
$ neopress collections create --name Posts --schema @schema.json
|
|
41177
|
+
$ neopress collections list
|
|
41178
|
+
$ neopress collections update 12 --schema @schema.json
|
|
41179
|
+
|
|
41180
|
+
Collections are identified by numeric id, never name. delete is a soft delete \u2014 the collection is hidden from list/get but its row is retained.`);
|
|
40956
41181
|
collections.command("list").description("List collections").action(async () => {
|
|
40957
41182
|
const client = await getClientAsync();
|
|
40958
41183
|
const data = await client.collections.list();
|
|
@@ -40963,7 +41188,13 @@ function registerCollectionCommands(program3) {
|
|
|
40963
41188
|
const data = await client.collections.get(parseInt(collectionId, 10));
|
|
40964
41189
|
output(data);
|
|
40965
41190
|
});
|
|
40966
|
-
collections.command("create").description("Create a collection").
|
|
41191
|
+
collections.command("create").description("Create a collection").addHelpText("after", `
|
|
41192
|
+
Examples:
|
|
41193
|
+
$ neopress collections create --name Posts
|
|
41194
|
+
$ neopress collections create --name Posts --schema @schema.json
|
|
41195
|
+
$ neopress collections create --name Posts --schema '{"title":{"type":"text"}}'
|
|
41196
|
+
|
|
41197
|
+
--schema takes inline JSON or @file and is keyed by field id. It is written to the draft schema \u2014 publish the site to make it live.`).requiredOption("--name <name>", "Collection name").option("--schema <json>", "Draft schema as JSON string or @file path").action(async (options) => {
|
|
40967
41198
|
const client = await getClientAsync();
|
|
40968
41199
|
const data = await client.collections.create({
|
|
40969
41200
|
name: options.name,
|
|
@@ -40971,7 +41202,12 @@ function registerCollectionCommands(program3) {
|
|
|
40971
41202
|
});
|
|
40972
41203
|
output(data);
|
|
40973
41204
|
});
|
|
40974
|
-
collections.command("update <collectionId>").description("Update a collection").
|
|
41205
|
+
collections.command("update <collectionId>").description("Update a collection").addHelpText("after", `
|
|
41206
|
+
Examples:
|
|
41207
|
+
$ neopress collections update 12 --name Articles
|
|
41208
|
+
$ neopress collections update 12 --schema @schema.json
|
|
41209
|
+
|
|
41210
|
+
Identify the collection by numeric id. Pass at least one of --name or --schema. --schema (inline JSON or @file, field-id keyed) replaces the draft schema; publish the site to make it live.`).option("--name <name>", "Collection name").option("--schema <json>", "Draft schema as JSON string or @file path").action(async (collectionId, options) => {
|
|
40975
41211
|
const client = await getClientAsync();
|
|
40976
41212
|
const data = {};
|
|
40977
41213
|
if (options.name) data.name = options.name;
|
|
@@ -40995,7 +41231,13 @@ function registerCollectionCommands(program3) {
|
|
|
40995
41231
|
// src/commands/entries.ts
|
|
40996
41232
|
var import_node_fs5 = require("fs");
|
|
40997
41233
|
function registerEntryCommands(program3) {
|
|
40998
|
-
const entries = program3.command("entries").description("Manage entries")
|
|
41234
|
+
const entries = program3.command("entries").description("Manage entries").addHelpText("after", `
|
|
41235
|
+
Examples:
|
|
41236
|
+
$ neopress entries list --collection 12 --status published --locale en
|
|
41237
|
+
$ neopress entries create --collection 12 --data @entry.json --title Hello
|
|
41238
|
+
$ neopress entries publish <entryId>
|
|
41239
|
+
|
|
41240
|
+
Entries are created as drafts \u2014 run \`neopress entries publish <entryId>\` to make them live. create/update/delete revalidate the reader cache; delete is a soft delete.`);
|
|
40999
41241
|
entries.command("list").description("List entries in a collection").requiredOption("--collection <id>", "Collection ID").option("--status <status>", "Filter by status").option("--locale <locale>", "Filter by locale").option("--page <n>", "Page number", "1").option("--limit <n>", "Results per page", "20").action(async (options) => {
|
|
41000
41242
|
const client = await getClientAsync();
|
|
41001
41243
|
const res = await client.entries.list(parseInt(options.collection, 10), {
|
|
@@ -41011,7 +41253,15 @@ function registerEntryCommands(program3) {
|
|
|
41011
41253
|
const data = await client.entries.get(parseInt(entryId, 10));
|
|
41012
41254
|
output(data);
|
|
41013
41255
|
});
|
|
41014
|
-
entries.command("create").description("Create an entry").requiredOption("--collection <id>", "Collection ID").option("--data <json>", "Entry data as JSON string or @file path").option("--title <title>", "Entry title").option("--slug <slug>", "Entry slug").option("--locale <locale>", "Entry locale").
|
|
41256
|
+
entries.command("create").description("Create an entry").requiredOption("--collection <id>", "Collection ID").option("--data <json>", "Entry data as JSON string or @file path").option("--title <title>", "Entry title").option("--slug <slug>", "Entry slug").option("--locale <locale>", "Entry locale").addHelpText(
|
|
41257
|
+
"after",
|
|
41258
|
+
`
|
|
41259
|
+
Examples:
|
|
41260
|
+
$ neopress entries create --collection 12 --data '{"body":"Hello"}' --title Hello
|
|
41261
|
+
$ neopress entries create --collection 12 --data @entry.json --locale ko
|
|
41262
|
+
|
|
41263
|
+
--data takes inline JSON or @file. After creating, run \`neopress entries publish <entryId>\` to publish it.`
|
|
41264
|
+
).action(async (options) => {
|
|
41015
41265
|
const client = await getClientAsync();
|
|
41016
41266
|
let data;
|
|
41017
41267
|
if (options.data?.startsWith("@")) {
|
|
@@ -41030,7 +41280,12 @@ function registerEntryCommands(program3) {
|
|
|
41030
41280
|
await client.entries.revalidateReaderCache(entry.id);
|
|
41031
41281
|
output(entry);
|
|
41032
41282
|
});
|
|
41033
|
-
entries.command("update <entryId>").description("Update an entry").
|
|
41283
|
+
entries.command("update <entryId>").description("Update an entry").addHelpText("after", `
|
|
41284
|
+
Examples:
|
|
41285
|
+
$ neopress entries update <entryId> --title "New title"
|
|
41286
|
+
$ neopress entries update <entryId> --data @entry.json --locale ko
|
|
41287
|
+
|
|
41288
|
+
--data takes inline JSON or @file and replaces the entry data. At least one field is required. Updating revalidates the reader cache; publish state is unchanged.`).option("--data <json>", "Entry data as JSON string or @file path").option("--title <title>", "Entry title").option("--slug <slug>", "Entry slug").option("--locale <locale>", "Entry locale").action(async (entryId, options) => {
|
|
41034
41289
|
const client = await getClientAsync();
|
|
41035
41290
|
const updateData = {};
|
|
41036
41291
|
if (options.data) {
|
|
@@ -41071,7 +41326,12 @@ function parseJsonInput3(input) {
|
|
|
41071
41326
|
return input.startsWith("@") ? JSON.parse((0, import_node_fs6.readFileSync)(input.slice(1), "utf-8")) : JSON.parse(input);
|
|
41072
41327
|
}
|
|
41073
41328
|
function registerFormCommands(program3) {
|
|
41074
|
-
const forms = program3.command("forms").description("Manage forms")
|
|
41329
|
+
const forms = program3.command("forms").description("Manage forms").addHelpText("after", `
|
|
41330
|
+
Examples:
|
|
41331
|
+
$ neopress forms create --name Contact --schema @schema.json --layout @layout.json
|
|
41332
|
+
$ neopress forms publish <formId>
|
|
41333
|
+
$ neopress forms responses <formId> --limit 50
|
|
41334
|
+
Forms are created as drafts \u2014 run \`neopress forms publish <formId>\` to make them live. JSON options take inline JSON or @file.`);
|
|
41075
41335
|
forms.command("list").description("List forms").action(async () => {
|
|
41076
41336
|
const client = await getClientAsync();
|
|
41077
41337
|
const data = await client.forms.list();
|
|
@@ -41082,7 +41342,12 @@ function registerFormCommands(program3) {
|
|
|
41082
41342
|
const data = await client.forms.get(parseInt(formId, 10));
|
|
41083
41343
|
output(data);
|
|
41084
41344
|
});
|
|
41085
|
-
forms.command("create").description("Create a form").
|
|
41345
|
+
forms.command("create").description("Create a form").addHelpText("after", `
|
|
41346
|
+
Examples:
|
|
41347
|
+
$ neopress forms create --name Contact
|
|
41348
|
+
$ neopress forms create --name Contact --schema @schema.json --layout @layout.json --i18n @i18n.json
|
|
41349
|
+
$ neopress forms create --name Signup --settings '{"redirectUrl":"/thanks"}'
|
|
41350
|
+
Only --name is required. --schema/--layout/--style/--i18n/--settings each take inline JSON or @file and write the draft state. The form is created as a draft \u2014 run \`neopress forms publish\` to make it live.`).requiredOption("--name <name>", "Form name").option("--schema <json>", "Draft form schema JSON string or @file path").option("--layout <json>", "Draft form layout JSON string or @file path").option("--style <json>", "Draft form style JSON string or @file path").option("--i18n <json>", "Draft form i18n JSON string or @file path").option("--settings <json>", "Form settings JSON string or @file path").action(async (options) => {
|
|
41086
41351
|
const client = await getClientAsync();
|
|
41087
41352
|
const data = await client.forms.create({
|
|
41088
41353
|
name: options.name,
|
|
@@ -41094,7 +41359,11 @@ function registerFormCommands(program3) {
|
|
|
41094
41359
|
});
|
|
41095
41360
|
output(data);
|
|
41096
41361
|
});
|
|
41097
|
-
forms.command("update <formId>").description("Update a form").
|
|
41362
|
+
forms.command("update <formId>").description("Update a form").addHelpText("after", `
|
|
41363
|
+
Examples:
|
|
41364
|
+
$ neopress forms update <formId> --name Contact
|
|
41365
|
+
$ neopress forms update <formId> --schema @schema.json --layout @layout.json
|
|
41366
|
+
Only the supplied fields change; pass at least one of --name/--schema/--layout/--style/--i18n/--settings. JSON options take inline JSON or @file and update the draft state \u2014 run \`neopress forms publish\` to push changes live.`).option("--name <name>", "Form name").option("--schema <json>", "Draft form schema JSON string or @file path").option("--layout <json>", "Draft form layout JSON string or @file path").option("--style <json>", "Draft form style JSON string or @file path").option("--i18n <json>", "Draft form i18n JSON string or @file path").option("--settings <json>", "Form settings JSON string or @file path").action(async (formId, options) => {
|
|
41098
41367
|
const client = await getClientAsync();
|
|
41099
41368
|
const data = {};
|
|
41100
41369
|
if (options.name) data.name = options.name;
|
|
@@ -41109,12 +41378,19 @@ function registerFormCommands(program3) {
|
|
|
41109
41378
|
const updated = await client.forms.update(parseInt(formId, 10), data);
|
|
41110
41379
|
output(updated);
|
|
41111
41380
|
});
|
|
41112
|
-
forms.command("publish <formId>").description("Publish a form").
|
|
41381
|
+
forms.command("publish <formId>").description("Publish a form").addHelpText("after", `
|
|
41382
|
+
Examples:
|
|
41383
|
+
$ neopress forms publish <formId>
|
|
41384
|
+
Copies the form's draft state (schema/layout/style/i18n) to its live state. Required after create/update before the form renders publicly.`).action(async (formId) => {
|
|
41113
41385
|
const client = await getClientAsync();
|
|
41114
41386
|
const result = await client.forms.publish(parseInt(formId, 10));
|
|
41115
41387
|
output(result);
|
|
41116
41388
|
});
|
|
41117
|
-
forms.command("responses <formId>").description("List form responses").
|
|
41389
|
+
forms.command("responses <formId>").description("List form responses").addHelpText("after", `
|
|
41390
|
+
Examples:
|
|
41391
|
+
$ neopress forms responses <formId>
|
|
41392
|
+
$ neopress forms responses <formId> --page 2 --limit 50
|
|
41393
|
+
Returns submitted responses newest-first, paginated (--page/--limit, default page 1, limit 20).`).option("--page <n>", "Page number", "1").option("--limit <n>", "Results per page", "20").action(async (formId, options) => {
|
|
41118
41394
|
const client = await getClientAsync();
|
|
41119
41395
|
const res = await client.forms.listResponses(parseInt(formId, 10), {
|
|
41120
41396
|
page: parseInt(options.page, 10),
|
|
@@ -41133,7 +41409,11 @@ function registerFormCommands(program3) {
|
|
|
41133
41409
|
var import_node_fs7 = require("fs");
|
|
41134
41410
|
var import_node_path3 = require("path");
|
|
41135
41411
|
function registerAssetCommands(program3) {
|
|
41136
|
-
const assets = program3.command("assets").description("Manage assets")
|
|
41412
|
+
const assets = program3.command("assets").description("Manage assets").addHelpText("after", `
|
|
41413
|
+
Examples:
|
|
41414
|
+
$ neopress assets upload ./hero.png --folder images
|
|
41415
|
+
$ neopress assets list --limit 50
|
|
41416
|
+
Upload runs presign \u2192 PUT to storage \u2192 register in one step; content type is inferred from the file extension.`);
|
|
41137
41417
|
assets.command("list").description("List assets").option("--page <n>", "Page number", "1").option("--limit <n>", "Results per page", "20").action(async (options) => {
|
|
41138
41418
|
const client = await getClientAsync();
|
|
41139
41419
|
const res = await client.assets.list({
|
|
@@ -41142,7 +41422,11 @@ function registerAssetCommands(program3) {
|
|
|
41142
41422
|
});
|
|
41143
41423
|
output(res);
|
|
41144
41424
|
});
|
|
41145
|
-
assets.command("upload <filePath>").description("Upload a file (presign \u2192 upload \u2192 register)").
|
|
41425
|
+
assets.command("upload <filePath>").description("Upload a file (presign \u2192 upload \u2192 register)").addHelpText("after", `
|
|
41426
|
+
Examples:
|
|
41427
|
+
$ neopress assets upload ./hero.png
|
|
41428
|
+
$ neopress assets upload ./docs/guide.pdf --folder downloads
|
|
41429
|
+
<filePath> is a local file path; its extension sets the content type. --folder is the storage subfolder (defaults to uploads/); omit it and the asset record's folder is left unset. Prints the registered asset and its public URL.`).option("--folder <folder>", "Target folder path").action(async (filePath, options) => {
|
|
41146
41430
|
const client = await getClientAsync();
|
|
41147
41431
|
const fileName = (0, import_node_path3.basename)(filePath);
|
|
41148
41432
|
const stats = (0, import_node_fs7.statSync)(filePath);
|
|
@@ -41188,7 +41472,13 @@ function registerAssetCommands(program3) {
|
|
|
41188
41472
|
|
|
41189
41473
|
// src/commands/publish.ts
|
|
41190
41474
|
function registerPublishCommands(program3) {
|
|
41191
|
-
const publish = program3.command("publish").description("Publish site or preview changes").
|
|
41475
|
+
const publish = program3.command("publish").description("Publish site or preview changes").addHelpText(
|
|
41476
|
+
"after",
|
|
41477
|
+
`
|
|
41478
|
+
Examples:
|
|
41479
|
+
$ neopress publish preview Show what would change
|
|
41480
|
+
$ neopress publish Publish all pending changes live`
|
|
41481
|
+
).action(async () => {
|
|
41192
41482
|
const client = await getClientAsync();
|
|
41193
41483
|
const result = await client.publish.site();
|
|
41194
41484
|
output(result);
|
|
@@ -41203,13 +41493,22 @@ function registerPublishCommands(program3) {
|
|
|
41203
41493
|
|
|
41204
41494
|
// src/commands/redirects.ts
|
|
41205
41495
|
function registerRedirectCommands(program3) {
|
|
41206
|
-
const redirects = program3.command("redirects").description("Manage redirect rules")
|
|
41496
|
+
const redirects = program3.command("redirects").description("Manage redirect rules").addHelpText("after", `
|
|
41497
|
+
Examples:
|
|
41498
|
+
$ neopress redirects create --source /old --dest /about
|
|
41499
|
+
$ neopress redirects create --source /docs --dest /guide --type 308
|
|
41500
|
+
$ neopress redirects list
|
|
41501
|
+
Rules are created enabled. delete <ruleId> removes a rule permanently.`);
|
|
41207
41502
|
redirects.command("list").description("List redirect rules").action(async () => {
|
|
41208
41503
|
const client = await getClientAsync();
|
|
41209
41504
|
const data = await client.redirects.list();
|
|
41210
41505
|
output(data);
|
|
41211
41506
|
});
|
|
41212
|
-
redirects.command("create").description("Create a redirect rule").
|
|
41507
|
+
redirects.command("create").description("Create a redirect rule").addHelpText("after", `
|
|
41508
|
+
Examples:
|
|
41509
|
+
$ neopress redirects create --source /old --dest /about
|
|
41510
|
+
$ neopress redirects create --source /docs --dest /guide --type 308
|
|
41511
|
+
--source and --dest are both required. --type is 307 (temporary, default) or 308 (permanent). The rule is created enabled.`).requiredOption("--source <path>", "Source path").requiredOption("--dest <path>", "Destination path").option("--type <type>", "Redirect type (307/308)", "307").action(async (options) => {
|
|
41213
41512
|
const client = await getClientAsync();
|
|
41214
41513
|
const rule = await client.redirects.create({
|
|
41215
41514
|
source: options.source,
|
|
@@ -41228,13 +41527,22 @@ function registerRedirectCommands(program3) {
|
|
|
41228
41527
|
// src/commands/layout.ts
|
|
41229
41528
|
var import_node_fs8 = require("fs");
|
|
41230
41529
|
function registerLayoutCommands(program3) {
|
|
41231
|
-
const layout = program3.command("layout").description("Manage site layout")
|
|
41530
|
+
const layout = program3.command("layout").description("Manage site layout").addHelpText("after", `
|
|
41531
|
+
Examples:
|
|
41532
|
+
$ neopress layout get
|
|
41533
|
+
$ neopress layout update --tsx ./layout.tsx --global-css ./globals.css
|
|
41534
|
+
$ neopress layout update --not-found-tsx ./not-found.tsx
|
|
41535
|
+
Layout edits land in draft state \u2014 run \`neopress publish\` to make them live.`);
|
|
41232
41536
|
layout.command("get").description("Get current site layout").action(async () => {
|
|
41233
41537
|
const client = await getClientAsync();
|
|
41234
41538
|
const data = await client.site.getLayout();
|
|
41235
41539
|
output(data);
|
|
41236
41540
|
});
|
|
41237
|
-
layout.command("update").description("Update site layout").
|
|
41541
|
+
layout.command("update").description("Update site layout").addHelpText("after", `
|
|
41542
|
+
Examples:
|
|
41543
|
+
$ neopress layout update --tsx ./layout.tsx
|
|
41544
|
+
$ neopress layout update --tsx ./layout.tsx --not-found-tsx ./not-found.tsx --global-css ./globals.css
|
|
41545
|
+
Each flag reads its content from a file path. Pass at least one of --tsx, --not-found-tsx, or --global-css. Updates write to the draft layout only \u2014 run \`neopress publish\` to make them live.`).option("--tsx <file>", "Layout TSX file path").option("--not-found-tsx <file>", "Not-found page TSX file path").option("--global-css <file>", "Global CSS file path").action(async (options) => {
|
|
41238
41546
|
const client = await getClientAsync();
|
|
41239
41547
|
const data = {};
|
|
41240
41548
|
if (options.tsx) data.draftTsx = (0, import_node_fs8.readFileSync)(options.tsx, "utf-8");
|
|
@@ -41250,7 +41558,12 @@ function registerLayoutCommands(program3) {
|
|
|
41250
41558
|
|
|
41251
41559
|
// src/commands/entry-references.ts
|
|
41252
41560
|
function registerEntryReferenceCommands(program3) {
|
|
41253
|
-
const refs = program3.command("entry-references").description("Manage entry reference relations")
|
|
41561
|
+
const refs = program3.command("entry-references").description("Manage entry reference relations").addHelpText("after", `
|
|
41562
|
+
Examples:
|
|
41563
|
+
$ neopress entry-references create --from-entry 12 --to-entry 34 --field author
|
|
41564
|
+
$ neopress entry-references list --from-entry 12
|
|
41565
|
+
$ neopress entry-references delete <referenceId>
|
|
41566
|
+
--field is a reference field key from the source entry's collection schema. delete is a hard delete and removes the relation immediately.`);
|
|
41254
41567
|
refs.command("list").description("List entry references").option("--from-entry <id>", "Filter by source entry ID").option("--to-entry <id>", "Filter by target entry ID").action(async (options) => {
|
|
41255
41568
|
const client = await getClientAsync();
|
|
41256
41569
|
const data = await client.entryReferences.list({
|
|
@@ -41259,7 +41572,11 @@ function registerEntryReferenceCommands(program3) {
|
|
|
41259
41572
|
});
|
|
41260
41573
|
output(data);
|
|
41261
41574
|
});
|
|
41262
|
-
refs.command("create").description("Create an entry reference").
|
|
41575
|
+
refs.command("create").description("Create an entry reference").addHelpText("after", `
|
|
41576
|
+
Examples:
|
|
41577
|
+
$ neopress entry-references create --from-entry 12 --to-entry 34 --field author
|
|
41578
|
+
$ neopress entry-references create --from-entry 100 --to-entry 7 --field relatedPosts
|
|
41579
|
+
All three flags are required. --field is a reference field key defined in the source entry's collection schema; --from-entry and --to-entry must be numeric entry IDs.`).requiredOption("--from-entry <id>", "Source entry ID").requiredOption("--to-entry <id>", "Target entry ID").requiredOption("--field <key>", "Reference field key from the source collection schema").action(async (options) => {
|
|
41263
41580
|
const client = await getClientAsync();
|
|
41264
41581
|
const fromEntryId = parseInt(options.fromEntry, 10);
|
|
41265
41582
|
const toEntryId = parseInt(options.toEntry, 10);
|
|
@@ -41326,9 +41643,19 @@ function parseSearchConsoleDimensions(raw) {
|
|
|
41326
41643
|
return dimensions;
|
|
41327
41644
|
}
|
|
41328
41645
|
function registerAnalyticsCommands(program3) {
|
|
41329
|
-
const analytics = program3.command("analytics").description("Read site analytics and Search Console data")
|
|
41646
|
+
const analytics = program3.command("analytics").description("Read site analytics and Search Console data").addHelpText("after", `
|
|
41647
|
+
Examples:
|
|
41648
|
+
$ neopress analytics summary --date-from 2026-01-01 --date-to 2026-01-31
|
|
41649
|
+
$ neopress analytics pages --date-from 2026-01-01 --date-to 2026-01-31 --limit 20
|
|
41650
|
+
$ neopress analytics search-console --date-from 2026-01-01 --date-to 2026-01-31 --dimensions query,page
|
|
41651
|
+
All analytics commands are read-only. Convenience commands (summary, pages, sources, forms, crawlers, pageviews) share --date-from/--date-to/--timezone/--limit.`);
|
|
41330
41652
|
addDateOptions(
|
|
41331
|
-
analytics.command("query").description("Run an allowed analytics pipe").
|
|
41653
|
+
analytics.command("query").description("Run an allowed analytics pipe").addHelpText("after", `
|
|
41654
|
+
Examples:
|
|
41655
|
+
$ neopress analytics query --pipe get_top_pages --date-from 2026-01-01 --date-to 2026-01-31
|
|
41656
|
+
$ neopress analytics query --pipe get_pageviews --params '{"device":"mobile"}'
|
|
41657
|
+
$ neopress analytics query --pipe get_top_pages --params @params.json --limit 50
|
|
41658
|
+
--pipe is required. --params takes inline JSON or @file and adds extra pipe params; reserved keys (pipe, site, site_id, timezone, token, q) are ignored.`).requiredOption("--pipe <pipe>", "Analytics pipe name")
|
|
41332
41659
|
).action(async (options) => {
|
|
41333
41660
|
const client = await getClientAsync();
|
|
41334
41661
|
const data = await client.analytics.query({
|
|
@@ -41373,7 +41700,12 @@ function registerAnalyticsCommands(program3) {
|
|
|
41373
41700
|
const client = await getClientAsync();
|
|
41374
41701
|
output(await client.analytics.crawlerSummary(readDateOptions(options)));
|
|
41375
41702
|
});
|
|
41376
|
-
analytics.command("search-console").description("Query Google Search Console performance data").
|
|
41703
|
+
analytics.command("search-console").description("Query Google Search Console performance data").addHelpText("after", `
|
|
41704
|
+
Examples:
|
|
41705
|
+
$ neopress analytics search-console --date-from 2026-01-01 --date-to 2026-01-31
|
|
41706
|
+
$ neopress analytics search-console --date-from 2026-01-01 --date-to 2026-01-31 --dimensions query,page --row-limit 50
|
|
41707
|
+
$ neopress analytics search-console --date-from 2026-01-01 --date-to 2026-01-31 --page-filter https://example.com/about
|
|
41708
|
+
--date-from and --date-to are required. --dimensions is a CSV of query,page,country,device (defaults to query).`).requiredOption("--date-from <date>", "Start date in YYYY-MM-DD").requiredOption("--date-to <date>", "End date in YYYY-MM-DD").option("--dimensions <csv>", "CSV dimensions: query,page,country,device", "query").option("--query-filter <query>", "Exact query filter").option("--page-filter <url>", "Exact page URL filter").option("--row-limit <n>", "Maximum rows to return", "100").action(async (options) => {
|
|
41377
41709
|
const client = await getClientAsync();
|
|
41378
41710
|
const data = await client.analytics.searchConsole({
|
|
41379
41711
|
dateFrom: options.dateFrom,
|
|
@@ -41392,7 +41724,12 @@ function collectPreviewImgUrl(value, previous = []) {
|
|
|
41392
41724
|
return previous.concat(value);
|
|
41393
41725
|
}
|
|
41394
41726
|
function registerTemplateCommands(program3) {
|
|
41395
|
-
const templates = program3.command("templates").description("Manage template metadata for the active site")
|
|
41727
|
+
const templates = program3.command("templates").description("Manage template metadata for the active site").addHelpText("after", `
|
|
41728
|
+
Examples:
|
|
41729
|
+
$ neopress templates mark --name "SaaS Landing" --industry saas --reference-url https://example.com --preview-img-url https://cdn.example.com/1.png
|
|
41730
|
+
$ neopress templates list --industry saas --limit 50
|
|
41731
|
+
$ neopress templates delete
|
|
41732
|
+
\`templates mark\` operates on the active site. \`templates delete\` permanently removes the template metadata AND the connected site \u2014 it is destructive and not recoverable.`);
|
|
41396
41733
|
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) => {
|
|
41397
41734
|
const token = process.env.NEOPRESS_ACCESS_TOKEN || await getValidAccessToken() || void 0;
|
|
41398
41735
|
if (!token) {
|
|
@@ -41411,7 +41748,11 @@ function registerTemplateCommands(program3) {
|
|
|
41411
41748
|
const template = await client.templates.get();
|
|
41412
41749
|
output(template);
|
|
41413
41750
|
});
|
|
41414
|
-
templates.command("mark").description("Mark or update the active site as a template").
|
|
41751
|
+
templates.command("mark").description("Mark or update the active site as a template").addHelpText("after", `
|
|
41752
|
+
Examples:
|
|
41753
|
+
$ neopress templates mark --name "SaaS Landing" --industry saas --reference-url https://example.com --preview-img-url https://cdn.example.com/1.png
|
|
41754
|
+
$ neopress templates mark --name Portfolio --industry creative --reference-url https://example.com --preview-img-url https://cdn.example.com/a.png --preview-img-url https://cdn.example.com/b.png --description "Minimal portfolio"
|
|
41755
|
+
--name, --industry, and --reference-url are all required, and at least one --preview-img-url must be given (repeat the flag for multiple images). Upserts the template metadata for the active site and sets the site status to active; running it again updates the existing template.`).requiredOption("--name <name>", "Template display name").option("--description <description>", "Template description, up to 150 characters").requiredOption("--industry <industry>", "Template industry key").requiredOption(
|
|
41415
41756
|
"--reference-url <url>",
|
|
41416
41757
|
"Reference URL for template provenance"
|
|
41417
41758
|
).option(
|
|
@@ -41437,9 +41778,226 @@ function registerTemplateCommands(program3) {
|
|
|
41437
41778
|
});
|
|
41438
41779
|
}
|
|
41439
41780
|
|
|
41781
|
+
// src/commands/headshots.ts
|
|
41782
|
+
var AGE_BANDS = ["young", "middle"];
|
|
41783
|
+
var GENDERS = ["male", "female"];
|
|
41784
|
+
var ETHNICITIES = ["asian", "white", "black", "latino"];
|
|
41785
|
+
var ATTIRES = ["formal"];
|
|
41786
|
+
function validateEnum(value, allowed, flag) {
|
|
41787
|
+
if (value !== void 0 && !allowed.includes(value)) {
|
|
41788
|
+
fail(`${flag} must be one of: ${allowed.join(", ")}`);
|
|
41789
|
+
}
|
|
41790
|
+
}
|
|
41791
|
+
function parseNonNegativeInt(raw, flag) {
|
|
41792
|
+
if (raw === void 0) return void 0;
|
|
41793
|
+
const value = Number(raw);
|
|
41794
|
+
if (!Number.isInteger(value) || value < 0) {
|
|
41795
|
+
fail(`${flag} must be a non-negative integer`);
|
|
41796
|
+
}
|
|
41797
|
+
return value;
|
|
41798
|
+
}
|
|
41799
|
+
function registerHeadshotCommands(program3) {
|
|
41800
|
+
const headshots = program3.command("headshots").description("Manage the shared headshot pool (super-admin only)").addHelpText("after", `
|
|
41801
|
+
Examples:
|
|
41802
|
+
$ neopress headshots list --gender female --ethnicity asian
|
|
41803
|
+
$ neopress headshots create --image-url https://cdn/x.webp --age-band young --gender male --ethnicity white --variation-index 0
|
|
41804
|
+
$ neopress headshots update 12 --inactive
|
|
41805
|
+
The pool is global and RLS-gated: only the super-admin account can read or write it. No active site is needed.`);
|
|
41806
|
+
headshots.command("list").description("List headshot pool entries").option("--age-band <band>", `Filter by age band (${AGE_BANDS.join("/")})`).option("--gender <gender>", `Filter by gender (${GENDERS.join("/")})`).option("--ethnicity <ethnicity>", `Filter by ethnicity (${ETHNICITIES.join("/")})`).option("--attire <attire>", `Filter by attire (${ATTIRES.join("/")})`).option("--active", "Only active entries").option("--inactive", "Only inactive entries").option("--page <n>", "Page number", "1").option("--limit <n>", "Results per page", "20").addHelpText("after", `
|
|
41807
|
+
Examples:
|
|
41808
|
+
$ neopress headshots list
|
|
41809
|
+
$ neopress headshots list --gender female --age-band middle --active
|
|
41810
|
+
Filters are equality matches on the pool's demographic columns; results are paginated.`).action(async (options) => {
|
|
41811
|
+
validateEnum(options.ageBand, AGE_BANDS, "--age-band");
|
|
41812
|
+
validateEnum(options.gender, GENDERS, "--gender");
|
|
41813
|
+
validateEnum(options.ethnicity, ETHNICITIES, "--ethnicity");
|
|
41814
|
+
validateEnum(options.attire, ATTIRES, "--attire");
|
|
41815
|
+
if (options.active && options.inactive) {
|
|
41816
|
+
fail("Use only one of --active or --inactive.");
|
|
41817
|
+
}
|
|
41818
|
+
const params = {
|
|
41819
|
+
page: parseInt(options.page, 10),
|
|
41820
|
+
limit: parseInt(options.limit, 10),
|
|
41821
|
+
ageBand: options.ageBand,
|
|
41822
|
+
gender: options.gender,
|
|
41823
|
+
ethnicity: options.ethnicity,
|
|
41824
|
+
attire: options.attire
|
|
41825
|
+
};
|
|
41826
|
+
if (options.active) params.isActive = true;
|
|
41827
|
+
else if (options.inactive) params.isActive = false;
|
|
41828
|
+
const client = await getGlobalClientAsync();
|
|
41829
|
+
const res = await client.headshots.list(params);
|
|
41830
|
+
output(res);
|
|
41831
|
+
});
|
|
41832
|
+
headshots.command("get <id>").description("Get a headshot pool entry").action(async (id) => {
|
|
41833
|
+
const client = await getGlobalClientAsync();
|
|
41834
|
+
const data = await client.headshots.get(parseInt(id, 10));
|
|
41835
|
+
output(data);
|
|
41836
|
+
});
|
|
41837
|
+
headshots.command("create").description("Add a headshot to the pool").requiredOption("--image-url <url>", "Public image URL").requiredOption("--age-band <band>", `Age band (${AGE_BANDS.join("/")})`).requiredOption("--gender <gender>", `Gender (${GENDERS.join("/")})`).requiredOption("--ethnicity <ethnicity>", `Ethnicity (${ETHNICITIES.join("/")})`).requiredOption("--variation-index <n>", "Variation index within the demographic cell (>= 0)").option("--attire <attire>", `Attire (${ATTIRES.join("/")}; default formal)`).option("--width <n>", "Image width in px").option("--height <n>", "Image height in px").option("--aspect-ratio <ratio>", "Aspect ratio, e.g. 2:3").option("--mime-type <type>", "MIME type, e.g. image/webp").option("--byte-size <n>", "File size in bytes").option("--gpt-prompt <prompt>", "Generation prompt (for provenance)").option("--tags <csv>", "Comma-separated tags").option("--inactive", "Create as inactive (default active)").addHelpText("after", `
|
|
41838
|
+
Examples:
|
|
41839
|
+
$ neopress headshots create --image-url https://cdn/a.webp --age-band young --gender female --ethnicity asian --variation-index 0
|
|
41840
|
+
$ neopress headshots create --image-url https://cdn/b.webp --age-band middle --gender male --ethnicity black --variation-index 1 --tags suit,studio
|
|
41841
|
+
(age-band, gender, ethnicity, attire, variation-index) must be unique. The DB rejects out-of-range enum values.`).action(async (options) => {
|
|
41842
|
+
validateEnum(options.ageBand, AGE_BANDS, "--age-band");
|
|
41843
|
+
validateEnum(options.gender, GENDERS, "--gender");
|
|
41844
|
+
validateEnum(options.ethnicity, ETHNICITIES, "--ethnicity");
|
|
41845
|
+
validateEnum(options.attire, ATTIRES, "--attire");
|
|
41846
|
+
const variationIndex = parseNonNegativeInt(options.variationIndex, "--variation-index");
|
|
41847
|
+
const params = {
|
|
41848
|
+
imageUrl: options.imageUrl,
|
|
41849
|
+
ageBand: options.ageBand,
|
|
41850
|
+
gender: options.gender,
|
|
41851
|
+
ethnicity: options.ethnicity,
|
|
41852
|
+
variationIndex
|
|
41853
|
+
};
|
|
41854
|
+
if (options.attire) params.attire = options.attire;
|
|
41855
|
+
const width = parseNonNegativeInt(options.width, "--width");
|
|
41856
|
+
if (width !== void 0) params.width = width;
|
|
41857
|
+
const height = parseNonNegativeInt(options.height, "--height");
|
|
41858
|
+
if (height !== void 0) params.height = height;
|
|
41859
|
+
if (options.aspectRatio) params.aspectRatio = options.aspectRatio;
|
|
41860
|
+
if (options.mimeType) params.mimeType = options.mimeType;
|
|
41861
|
+
const byteSize = parseNonNegativeInt(options.byteSize, "--byte-size");
|
|
41862
|
+
if (byteSize !== void 0) params.byteSize = byteSize;
|
|
41863
|
+
if (options.gptPrompt) params.gptPrompt = options.gptPrompt;
|
|
41864
|
+
if (options.tags) params.tags = String(options.tags).split(",").map((t) => t.trim()).filter(Boolean);
|
|
41865
|
+
if (options.inactive) params.isActive = false;
|
|
41866
|
+
const client = await getGlobalClientAsync();
|
|
41867
|
+
const data = await client.headshots.create(params);
|
|
41868
|
+
output(data);
|
|
41869
|
+
});
|
|
41870
|
+
headshots.command("update <id>").description("Update a headshot pool entry").option("--image-url <url>", "Public image URL").option("--age-band <band>", `Age band (${AGE_BANDS.join("/")})`).option("--gender <gender>", `Gender (${GENDERS.join("/")})`).option("--ethnicity <ethnicity>", `Ethnicity (${ETHNICITIES.join("/")})`).option("--attire <attire>", `Attire (${ATTIRES.join("/")})`).option("--variation-index <n>", "Variation index (>= 0)").option("--width <n>", "Image width in px").option("--height <n>", "Image height in px").option("--aspect-ratio <ratio>", "Aspect ratio, e.g. 2:3").option("--mime-type <type>", "MIME type, e.g. image/webp").option("--byte-size <n>", "File size in bytes").option("--gpt-prompt <prompt>", "Generation prompt").option("--tags <csv>", "Comma-separated tags (replaces existing)").option("--active", "Mark active").option("--inactive", "Mark inactive").addHelpText("after", `
|
|
41871
|
+
Examples:
|
|
41872
|
+
$ neopress headshots update 12 --inactive
|
|
41873
|
+
$ neopress headshots update 12 --image-url https://cdn/new.webp --tags suit,studio
|
|
41874
|
+
Pass at least one field. --active/--inactive toggle is_active; --tags replaces the tag list.`).action(async (id, options) => {
|
|
41875
|
+
validateEnum(options.ageBand, AGE_BANDS, "--age-band");
|
|
41876
|
+
validateEnum(options.gender, GENDERS, "--gender");
|
|
41877
|
+
validateEnum(options.ethnicity, ETHNICITIES, "--ethnicity");
|
|
41878
|
+
validateEnum(options.attire, ATTIRES, "--attire");
|
|
41879
|
+
if (options.active && options.inactive) {
|
|
41880
|
+
fail("Use only one of --active or --inactive.");
|
|
41881
|
+
}
|
|
41882
|
+
const params = {};
|
|
41883
|
+
if (options.imageUrl) params.imageUrl = options.imageUrl;
|
|
41884
|
+
if (options.ageBand) params.ageBand = options.ageBand;
|
|
41885
|
+
if (options.gender) params.gender = options.gender;
|
|
41886
|
+
if (options.ethnicity) params.ethnicity = options.ethnicity;
|
|
41887
|
+
if (options.attire) params.attire = options.attire;
|
|
41888
|
+
const variationIndex = parseNonNegativeInt(options.variationIndex, "--variation-index");
|
|
41889
|
+
if (variationIndex !== void 0) params.variationIndex = variationIndex;
|
|
41890
|
+
const width = parseNonNegativeInt(options.width, "--width");
|
|
41891
|
+
if (width !== void 0) params.width = width;
|
|
41892
|
+
const height = parseNonNegativeInt(options.height, "--height");
|
|
41893
|
+
if (height !== void 0) params.height = height;
|
|
41894
|
+
if (options.aspectRatio) params.aspectRatio = options.aspectRatio;
|
|
41895
|
+
if (options.mimeType) params.mimeType = options.mimeType;
|
|
41896
|
+
const byteSize = parseNonNegativeInt(options.byteSize, "--byte-size");
|
|
41897
|
+
if (byteSize !== void 0) params.byteSize = byteSize;
|
|
41898
|
+
if (options.gptPrompt) params.gptPrompt = options.gptPrompt;
|
|
41899
|
+
if (options.tags) params.tags = String(options.tags).split(",").map((t) => t.trim()).filter(Boolean);
|
|
41900
|
+
if (options.active) params.isActive = true;
|
|
41901
|
+
else if (options.inactive) params.isActive = false;
|
|
41902
|
+
if (Object.keys(params).length === 0) {
|
|
41903
|
+
fail("No fields to update.");
|
|
41904
|
+
}
|
|
41905
|
+
const client = await getGlobalClientAsync();
|
|
41906
|
+
const data = await client.headshots.update(parseInt(id, 10), params);
|
|
41907
|
+
output(data);
|
|
41908
|
+
});
|
|
41909
|
+
headshots.command("delete <id>").description("Delete a headshot pool entry (hard delete)").action(async (id) => {
|
|
41910
|
+
const client = await getGlobalClientAsync();
|
|
41911
|
+
await client.headshots.delete(parseInt(id, 10));
|
|
41912
|
+
ok(`Headshot ${id} deleted`);
|
|
41913
|
+
});
|
|
41914
|
+
}
|
|
41915
|
+
|
|
41916
|
+
// src/commands/guide.ts
|
|
41917
|
+
function describeOption(opt) {
|
|
41918
|
+
const info = { flags: opt.flags, description: opt.description || "" };
|
|
41919
|
+
if (opt.defaultValue !== void 0) info.default = opt.defaultValue;
|
|
41920
|
+
return info;
|
|
41921
|
+
}
|
|
41922
|
+
function describeArgument(arg) {
|
|
41923
|
+
return {
|
|
41924
|
+
name: arg.name(),
|
|
41925
|
+
required: arg.required,
|
|
41926
|
+
variadic: arg.variadic,
|
|
41927
|
+
description: arg.description || ""
|
|
41928
|
+
};
|
|
41929
|
+
}
|
|
41930
|
+
function describeCommand(cmd, prefix) {
|
|
41931
|
+
const path = `${prefix} ${cmd.name()}`;
|
|
41932
|
+
return {
|
|
41933
|
+
path,
|
|
41934
|
+
aliases: cmd.aliases(),
|
|
41935
|
+
description: cmd.description(),
|
|
41936
|
+
arguments: cmd.registeredArguments.map(describeArgument),
|
|
41937
|
+
options: cmd.options.map(describeOption),
|
|
41938
|
+
subcommands: cmd.commands.filter((c) => c.name() !== "help").map((c) => describeCommand(c, path))
|
|
41939
|
+
};
|
|
41940
|
+
}
|
|
41941
|
+
function buildGuide(program3) {
|
|
41942
|
+
return {
|
|
41943
|
+
name: program3.name(),
|
|
41944
|
+
version: program3.version() ?? "",
|
|
41945
|
+
description: program3.description(),
|
|
41946
|
+
globalOptions: program3.options.map(describeOption),
|
|
41947
|
+
commands: program3.commands.filter((c) => c.name() !== "help").map((c) => describeCommand(c, program3.name()))
|
|
41948
|
+
};
|
|
41949
|
+
}
|
|
41950
|
+
function pad(s, width) {
|
|
41951
|
+
return s.length >= width ? `${s} ` : s + " ".repeat(width - s.length);
|
|
41952
|
+
}
|
|
41953
|
+
function argSignature(args) {
|
|
41954
|
+
return args.map((a) => {
|
|
41955
|
+
const inner = a.variadic ? `${a.name}...` : a.name;
|
|
41956
|
+
return a.required ? `<${inner}>` : `[${inner}]`;
|
|
41957
|
+
}).join(" ");
|
|
41958
|
+
}
|
|
41959
|
+
function printCommandNode(node, lines, depth) {
|
|
41960
|
+
const indent = " ".repeat(depth * 2);
|
|
41961
|
+
const sig = argSignature(node.arguments);
|
|
41962
|
+
const head2 = `${indent}${node.path}${sig ? ` ${sig}` : ""}`;
|
|
41963
|
+
lines.push(`${pad(head2, 46)}${node.description}`);
|
|
41964
|
+
if (node.subcommands.length === 0) {
|
|
41965
|
+
for (const o of node.options) {
|
|
41966
|
+
const def = o.default !== void 0 ? ` (default: ${JSON.stringify(o.default)})` : "";
|
|
41967
|
+
lines.push(`${pad(`${indent} ${o.flags}`, 46)}${o.description}${def}`);
|
|
41968
|
+
}
|
|
41969
|
+
}
|
|
41970
|
+
for (const sub of node.subcommands) printCommandNode(sub, lines, depth + 1);
|
|
41971
|
+
}
|
|
41972
|
+
function printHuman(guide) {
|
|
41973
|
+
const lines = [];
|
|
41974
|
+
lines.push(`${guide.name} ${guide.version} \u2014 ${guide.description}`);
|
|
41975
|
+
lines.push("");
|
|
41976
|
+
if (guide.globalOptions.length) {
|
|
41977
|
+
lines.push("GLOBAL OPTIONS");
|
|
41978
|
+
for (const o of guide.globalOptions) lines.push(`${pad(` ${o.flags}`, 46)}${o.description}`);
|
|
41979
|
+
lines.push("");
|
|
41980
|
+
}
|
|
41981
|
+
lines.push("COMMANDS");
|
|
41982
|
+
for (const c of guide.commands) printCommandNode(c, lines, 1);
|
|
41983
|
+
lines.push("");
|
|
41984
|
+
lines.push("Run `neopress <command> --help` for details, or `neopress guide --json` for the full surface.");
|
|
41985
|
+
console.log(lines.join("\n"));
|
|
41986
|
+
}
|
|
41987
|
+
function registerGuideCommands(program3) {
|
|
41988
|
+
program3.command("guide").description("Print the full command reference (human tree, or --json for AI tools)").option("--json", "Output the command surface as JSON").action(() => {
|
|
41989
|
+
const guide = buildGuide(program3);
|
|
41990
|
+
if (isJsonMode()) {
|
|
41991
|
+
console.log(JSON.stringify(guide, null, 2));
|
|
41992
|
+
} else {
|
|
41993
|
+
printHuman(guide);
|
|
41994
|
+
}
|
|
41995
|
+
});
|
|
41996
|
+
}
|
|
41997
|
+
|
|
41440
41998
|
// src/bin.ts
|
|
41441
41999
|
var program2 = new Command();
|
|
41442
|
-
program2.name("neopress").description("Neopress CLI \u2014 manage your site from the terminal").version("4.
|
|
42000
|
+
program2.name("neopress").description("Neopress CLI \u2014 manage your site from the terminal").version("4.2.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) => {
|
|
41443
42001
|
const opts = thisCommand.optsWithGlobals();
|
|
41444
42002
|
if (opts.site) setSiteOverride(String(opts.site));
|
|
41445
42003
|
if (opts.json || !process.stdout.isTTY) setJsonMode(true);
|
|
@@ -41457,6 +42015,28 @@ registerLayoutCommands(program2);
|
|
|
41457
42015
|
registerEntryReferenceCommands(program2);
|
|
41458
42016
|
registerAnalyticsCommands(program2);
|
|
41459
42017
|
registerTemplateCommands(program2);
|
|
42018
|
+
registerHeadshotCommands(program2);
|
|
42019
|
+
registerGuideCommands(program2);
|
|
42020
|
+
program2.addHelpText(
|
|
42021
|
+
"after",
|
|
42022
|
+
`
|
|
42023
|
+
Quickstart:
|
|
42024
|
+
$ neopress login Authenticate (or set NEOPRESS_ACCESS_TOKEN)
|
|
42025
|
+
$ neopress sites list See sites you can access
|
|
42026
|
+
$ neopress sites use <id|handle> Pick the active site
|
|
42027
|
+
$ neopress pages list List pages on the active site
|
|
42028
|
+
$ neopress guide Full command reference (add --json for AI tools)
|
|
42029
|
+
|
|
42030
|
+
AI / scripting:
|
|
42031
|
+
Output is JSON automatically when piped or redirected; force it with --json.
|
|
42032
|
+
Run \`neopress guide --json\` to get the entire command surface in one call.
|
|
42033
|
+
|
|
42034
|
+
Env vars:
|
|
42035
|
+
NEOPRESS_ACCESS_TOKEN Auth token (skips \`neopress login\`)
|
|
42036
|
+
NEOPRESS_SITE_ID Default site id (overrides the active site)
|
|
42037
|
+
NEOPRESS_BASE_URL API base URL (defaults to the hosted Neopress app)
|
|
42038
|
+
`
|
|
42039
|
+
);
|
|
41460
42040
|
program2.parseAsync(process.argv).catch((err) => {
|
|
41461
42041
|
if (err?.code) {
|
|
41462
42042
|
console.error(JSON.stringify({ ok: false, error: err.message, code: err.code }));
|