@neopress/cli 4.4.0 → 4.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/dist/bin.cjs +328 -7
  2. package/dist/index.js +175 -5
  3. package/package.json +6 -3
package/dist/bin.cjs CHANGED
@@ -24893,6 +24893,7 @@ function serializeRedirect(r) {
24893
24893
  siteId: r.site_id,
24894
24894
  source: r.source,
24895
24895
  destination: r.destination,
24896
+ mode: r.mode,
24896
24897
  redirectType: r.redirect_type,
24897
24898
  includeChildren: r.include_children,
24898
24899
  preservePath: r.preserve_path,
@@ -24944,6 +24945,30 @@ function serializeHeadshot(h) {
24944
24945
  updatedAt: h.updated_at
24945
24946
  };
24946
24947
  }
24948
+ function serializeLogo(l) {
24949
+ return {
24950
+ id: l.id,
24951
+ imageUrl: l.image_url,
24952
+ width: l.width,
24953
+ height: l.height,
24954
+ aspectRatio: l.aspect_ratio,
24955
+ mimeType: l.mime_type,
24956
+ byteSize: l.byte_size,
24957
+ type: l.type,
24958
+ font: l.font,
24959
+ color: l.color,
24960
+ hue: l.hue,
24961
+ tone: l.tone,
24962
+ toneScore: l.tone_score,
24963
+ name: l.name,
24964
+ variant: l.variant,
24965
+ sha256: l.sha256,
24966
+ tags: l.tags ?? [],
24967
+ isActive: l.is_active,
24968
+ createdAt: l.created_at,
24969
+ updatedAt: l.updated_at
24970
+ };
24971
+ }
24947
24972
  function serializeSite(site) {
24948
24973
  return {
24949
24974
  id: site.id,
@@ -25093,7 +25118,8 @@ var COLLECTION_FIELD_TYPES = [
25093
25118
  "checkbox",
25094
25119
  "radio",
25095
25120
  "multi_checkbox",
25096
- "consent"
25121
+ "consent",
25122
+ "place"
25097
25123
  ];
25098
25124
  var COLLECTION_FIELD_TYPE_ALIASES = {
25099
25125
  boolean: "bool",
@@ -38971,12 +38997,10 @@ var COLLECTION_PRESET_CONTRACTS = {
38971
38997
  schema: {
38972
38998
  title: titleField("Name"),
38973
38999
  slug: slugField(),
38974
- image: field("image", "Image", "image"),
38975
- address: field("address", "Address", "text"),
38976
- city: field("city", "City", "text"),
39000
+ location: field("location", "Location", "place"),
38977
39001
  description: field("description", "Description", "content")
38978
39002
  },
38979
- lockedFieldIds: ["title", "slug", "image"]
39003
+ lockedFieldIds: ["title", "slug", "location"]
38980
39004
  },
38981
39005
  category: {
38982
39006
  schema: {
@@ -40416,6 +40440,12 @@ var SiteEndpoint = class {
40416
40440
  };
40417
40441
 
40418
40442
  // ../sdk/dist/endpoints/redirects.js
40443
+ var DASHBOARD_ONLY_REWRITE_MESSAGE = "Rewrite proxy rules can only be managed in the dashboard.";
40444
+ function rejectModeParam(data) {
40445
+ if (data && typeof data === "object" && Object.prototype.hasOwnProperty.call(data, "mode")) {
40446
+ throw new NeopressApiError("REDIRECT_RULE_DASHBOARD_ONLY", DASHBOARD_ONLY_REWRITE_MESSAGE, 400);
40447
+ }
40448
+ }
40419
40449
  var RedirectsEndpoint = class {
40420
40450
  client;
40421
40451
  constructor(client) {
@@ -40430,6 +40460,7 @@ var RedirectsEndpoint = class {
40430
40460
  return (data ?? []).map((r) => serializeRedirect(r));
40431
40461
  }
40432
40462
  async create(data) {
40463
+ rejectModeParam(data);
40433
40464
  const values = {
40434
40465
  site_id: this.client.siteIdNumber,
40435
40466
  source: data.source,
@@ -40445,7 +40476,21 @@ var RedirectsEndpoint = class {
40445
40476
  throw new NeopressApiError("DB_ERROR", error48.message, 0, error48);
40446
40477
  return serializeRedirect(row);
40447
40478
  }
40479
+ async assertRedirectRuleWritable(ruleId) {
40480
+ const { data, error: error48 } = await this.client.db.from("redirect_rules").select("id, mode").eq("site_id", this.client.siteIdNumber).eq("id", ruleId).maybeSingle();
40481
+ if (error48)
40482
+ throw new NeopressApiError("DB_ERROR", error48.message, 0, error48);
40483
+ if (!data) {
40484
+ throw new NeopressApiError("REDIRECT_RULE_NOT_FOUND", `Redirect rule ${ruleId} not found for this site`, 404);
40485
+ }
40486
+ const row = data;
40487
+ if (row.mode === "proxy") {
40488
+ throw new NeopressApiError("REDIRECT_RULE_DASHBOARD_ONLY", DASHBOARD_ONLY_REWRITE_MESSAGE, 400);
40489
+ }
40490
+ }
40448
40491
  async update(ruleId, data) {
40492
+ rejectModeParam(data);
40493
+ await this.assertRedirectRuleWritable(ruleId);
40449
40494
  const values = {};
40450
40495
  if ("source" in data)
40451
40496
  values.source = data.source;
@@ -40467,6 +40512,7 @@ var RedirectsEndpoint = class {
40467
40512
  return serializeRedirect(row);
40468
40513
  }
40469
40514
  async delete(ruleId) {
40515
+ await this.assertRedirectRuleWritable(ruleId);
40470
40516
  const { error: error48 } = await this.client.db.from("redirect_rules").delete().eq("site_id", this.client.siteIdNumber).eq("id", ruleId);
40471
40517
  if (error48)
40472
40518
  throw new NeopressApiError("DB_ERROR", error48.message, 0, error48);
@@ -40785,6 +40831,128 @@ var HeadshotsEndpoint = class {
40785
40831
  }
40786
40832
  };
40787
40833
 
40834
+ // ../sdk/dist/endpoints/logos.js
40835
+ var LogosEndpoint = class {
40836
+ client;
40837
+ constructor(client) {
40838
+ this.client = client;
40839
+ }
40840
+ async list(params) {
40841
+ const { page, limit, offset } = this.client.resolvePagination(params);
40842
+ let query = this.client.db.from("logo_pool").select("*", { count: "exact" });
40843
+ if (params?.type)
40844
+ query = query.eq("type", params.type);
40845
+ if (params?.tone)
40846
+ query = query.eq("tone", params.tone);
40847
+ if (params?.font)
40848
+ query = query.eq("font", params.font);
40849
+ if (params?.hue !== void 0)
40850
+ query = query.eq("hue", params.hue);
40851
+ if (params?.isActive !== void 0)
40852
+ query = query.eq("is_active", params.isActive);
40853
+ if (params?.order) {
40854
+ query = query.order("created_at", { ascending: params.order === "asc" });
40855
+ } else {
40856
+ query = query.order("type", { ascending: true }).order("hue", { ascending: true }).order("name", { ascending: true });
40857
+ }
40858
+ const { data, error: error48, count } = await query.range(offset, offset + limit - 1);
40859
+ if (error48)
40860
+ throw new NeopressApiError("DB_ERROR", error48.message, 0, error48);
40861
+ return {
40862
+ data: (data ?? []).map((r) => serializeLogo(r)),
40863
+ pagination: this.client.paginationMeta(page, limit, offset, count ?? 0)
40864
+ };
40865
+ }
40866
+ async get(id) {
40867
+ const { data, error: error48 } = await this.client.db.from("logo_pool").select("*").eq("id", id).single();
40868
+ if (error48)
40869
+ throw new NeopressApiError("DB_ERROR", error48.message, 0, error48);
40870
+ return serializeLogo(data);
40871
+ }
40872
+ async create(params) {
40873
+ const values = {
40874
+ image_url: params.imageUrl,
40875
+ type: params.type,
40876
+ font: params.font,
40877
+ color: params.color,
40878
+ hue: params.hue,
40879
+ tone: params.tone,
40880
+ name: params.name
40881
+ };
40882
+ if (params.toneScore !== void 0)
40883
+ values.tone_score = params.toneScore;
40884
+ if (params.variant !== void 0)
40885
+ values.variant = params.variant;
40886
+ if (params.sha256 !== void 0)
40887
+ values.sha256 = params.sha256;
40888
+ if (params.width !== void 0)
40889
+ values.width = params.width;
40890
+ if (params.height !== void 0)
40891
+ values.height = params.height;
40892
+ if (params.aspectRatio !== void 0)
40893
+ values.aspect_ratio = params.aspectRatio;
40894
+ if (params.mimeType !== void 0)
40895
+ values.mime_type = params.mimeType;
40896
+ if (params.byteSize !== void 0)
40897
+ values.byte_size = params.byteSize;
40898
+ if (params.tags !== void 0)
40899
+ values.tags = params.tags;
40900
+ if (params.isActive !== void 0)
40901
+ values.is_active = params.isActive;
40902
+ const { data, error: error48 } = await this.client.db.from("logo_pool").insert(values).select().single();
40903
+ if (error48)
40904
+ throw new NeopressApiError("DB_ERROR", error48.message, 0, error48);
40905
+ return serializeLogo(data);
40906
+ }
40907
+ async update(id, params) {
40908
+ const values = {};
40909
+ if (params.imageUrl !== void 0)
40910
+ values.image_url = params.imageUrl;
40911
+ if (params.type !== void 0)
40912
+ values.type = params.type;
40913
+ if (params.font !== void 0)
40914
+ values.font = params.font;
40915
+ if (params.color !== void 0)
40916
+ values.color = params.color;
40917
+ if (params.hue !== void 0)
40918
+ values.hue = params.hue;
40919
+ if (params.tone !== void 0)
40920
+ values.tone = params.tone;
40921
+ if (params.name !== void 0)
40922
+ values.name = params.name;
40923
+ if (params.toneScore !== void 0)
40924
+ values.tone_score = params.toneScore;
40925
+ if (params.variant !== void 0)
40926
+ values.variant = params.variant;
40927
+ if (params.sha256 !== void 0)
40928
+ values.sha256 = params.sha256;
40929
+ if (params.width !== void 0)
40930
+ values.width = params.width;
40931
+ if (params.height !== void 0)
40932
+ values.height = params.height;
40933
+ if (params.aspectRatio !== void 0)
40934
+ values.aspect_ratio = params.aspectRatio;
40935
+ if (params.mimeType !== void 0)
40936
+ values.mime_type = params.mimeType;
40937
+ if (params.byteSize !== void 0)
40938
+ values.byte_size = params.byteSize;
40939
+ if (params.tags !== void 0)
40940
+ values.tags = params.tags;
40941
+ if (params.isActive !== void 0)
40942
+ values.is_active = params.isActive;
40943
+ const { data, error: error48 } = await this.client.db.from("logo_pool").update(values).eq("id", id).select().single();
40944
+ if (error48)
40945
+ throw new NeopressApiError("DB_ERROR", error48.message, 0, error48);
40946
+ return serializeLogo(data);
40947
+ }
40948
+ async delete(id) {
40949
+ const { error: error48 } = await this.client.db.from("logo_pool").delete().eq("id", id);
40950
+ if (error48)
40951
+ throw new NeopressApiError("DB_ERROR", error48.message, 0, error48);
40952
+ return { id, deleted: true };
40953
+ }
40954
+ };
40955
+
40788
40956
  // ../sdk/dist/client.js
40789
40957
  var NeopressClient = class {
40790
40958
  baseUrl;
@@ -40806,6 +40974,7 @@ var NeopressClient = class {
40806
40974
  analytics;
40807
40975
  templates;
40808
40976
  headshots;
40977
+ logos;
40809
40978
  constructor(options) {
40810
40979
  this.baseUrl = (options.baseUrl || "https://app.neopress.ai").replace(/\/$/, "");
40811
40980
  this.accessToken = options.accessToken || "";
@@ -40825,6 +40994,7 @@ var NeopressClient = class {
40825
40994
  this.analytics = new AnalyticsEndpoint(this);
40826
40995
  this.templates = new TemplatesEndpoint(this);
40827
40996
  this.headshots = new HeadshotsEndpoint(this);
40997
+ this.logos = new LogosEndpoint(this);
40828
40998
  }
40829
40999
  get siteBasePath() {
40830
41000
  return `/api/v1/sites/${this.siteId}`;
@@ -41842,7 +42012,7 @@ Examples:
41842
42012
  var AGE_BANDS = ["young", "middle"];
41843
42013
  var GENDERS = ["male", "female"];
41844
42014
  var ETHNICITIES = ["asian", "white", "black", "latino"];
41845
- var ATTIRES = ["formal"];
42015
+ var ATTIRES = ["formal", "casual"];
41846
42016
  function validateEnum(value, allowed, flag) {
41847
42017
  if (value !== void 0 && !allowed.includes(value)) {
41848
42018
  fail(`${flag} must be one of: ${allowed.join(", ")}`);
@@ -41974,6 +42144,156 @@ Pass at least one field. --active/--inactive toggle is_active; --tags replaces t
41974
42144
  });
41975
42145
  }
41976
42146
 
42147
+ // src/commands/logos.ts
42148
+ var TYPES = ["wordmark", "lockup", "signature"];
42149
+ var TONES = ["playful", "neutral", "serious"];
42150
+ function validateEnum2(value, allowed, flag) {
42151
+ if (value !== void 0 && !allowed.includes(value)) {
42152
+ fail(`${flag} must be one of: ${allowed.join(", ")}`);
42153
+ }
42154
+ }
42155
+ function parseNonNegativeInt2(raw, flag) {
42156
+ if (raw === void 0) return void 0;
42157
+ const value = Number(raw);
42158
+ if (!Number.isInteger(value) || value < 0) {
42159
+ fail(`${flag} must be a non-negative integer`);
42160
+ }
42161
+ return value;
42162
+ }
42163
+ function parseHue(raw) {
42164
+ if (raw === void 0) return void 0;
42165
+ const value = Number(raw);
42166
+ if (!Number.isInteger(value) || value < 0 || value > 11) {
42167
+ fail("--hue must be an integer 0-11 (12-bucket hue wheel)");
42168
+ }
42169
+ return value;
42170
+ }
42171
+ function registerLogoCommands(program3) {
42172
+ const logos = program3.command("logos").description("Manage the shared logo pool (super-admin only)").addHelpText("after", `
42173
+ Examples:
42174
+ $ neopress logos list --type lockup --tone playful
42175
+ $ neopress logos create --image-url https://cdn/x.webp --type wordmark --font geometric --color '#4f46e5' --hue 8 --tone neutral --name Northwind
42176
+ $ neopress logos update 12 --inactive
42177
+ The pool is global and RLS-gated: only the super-admin account can read or write it. No active site is needed.`);
42178
+ logos.command("list").description("List logo pool entries").option("--type <type>", `Filter by type (${TYPES.join("/")})`).option("--tone <tone>", `Filter by tone (${TONES.join("/")})`).option("--font <font>", "Filter by font family").option("--hue <n>", "Filter by hue bucket (0-11)").option("--active", "Only active entries").option("--inactive", "Only inactive entries").option("--order <asc|desc>", ORDER_OPTION_DESC).option("--page <n>", "Page number", "1").option("--limit <n>", "Results per page", "20").addHelpText("after", `
42179
+ Examples:
42180
+ $ neopress logos list
42181
+ $ neopress logos list --type signature --tone serious --active
42182
+ Filters are equality matches on the pool's diversity axes; results are paginated.`).action(async (options) => {
42183
+ validateEnum2(options.type, TYPES, "--type");
42184
+ validateEnum2(options.tone, TONES, "--tone");
42185
+ if (options.active && options.inactive) {
42186
+ fail("Use only one of --active or --inactive.");
42187
+ }
42188
+ const hue = parseHue(options.hue);
42189
+ const params = {
42190
+ page: parseInt(options.page, 10),
42191
+ limit: parseInt(options.limit, 10),
42192
+ order: parseOrder(options.order),
42193
+ type: options.type,
42194
+ tone: options.tone,
42195
+ font: options.font
42196
+ };
42197
+ if (hue !== void 0) params.hue = hue;
42198
+ if (options.active) params.isActive = true;
42199
+ else if (options.inactive) params.isActive = false;
42200
+ const client = await getGlobalClientAsync();
42201
+ const res = await client.logos.list(params);
42202
+ output(res);
42203
+ });
42204
+ logos.command("get <id>").description("Get a logo pool entry").action(async (id) => {
42205
+ const client = await getGlobalClientAsync();
42206
+ const data = await client.logos.get(parseInt(id, 10));
42207
+ output(data);
42208
+ });
42209
+ logos.command("create").description("Add a logo to the pool").requiredOption("--image-url <url>", "Public image URL").requiredOption("--type <type>", `Type (${TYPES.join("/")})`).requiredOption("--font <font>", "Font family, e.g. geometric").requiredOption("--color <hex>", "Brand ink hex, e.g. #4f46e5").requiredOption("--hue <n>", "Hue bucket (0-11)").requiredOption("--tone <tone>", `Tone (${TONES.join("/")})`).requiredOption("--name <name>", "Fictional brand name").option("--tone-score <n>", "Authored tone score (provenance)").option("--variant <variant>", "Variant descriptor, e.g. lk-mark7-left-duo").option("--sha256 <hash>", "Content hash").option("--width <n>", "Image width in px").option("--height <n>", "Image height in px").option("--aspect-ratio <ratio>", "Aspect ratio, e.g. 4:1").option("--mime-type <type>", "MIME type, e.g. image/webp").option("--byte-size <n>", "File size in bytes").option("--tags <csv>", "Comma-separated tags").option("--inactive", "Create as inactive (default active)").addHelpText("after", `
42210
+ Examples:
42211
+ $ neopress logos create --image-url https://cdn/a.webp --type lockup --font grotesk --color '#0d9488' --hue 5 --tone neutral --name Kestrel
42212
+ image_url is unique. The DB rejects out-of-range type/tone/hue values.`).action(async (options) => {
42213
+ validateEnum2(options.type, TYPES, "--type");
42214
+ validateEnum2(options.tone, TONES, "--tone");
42215
+ const hue = parseHue(options.hue);
42216
+ const params = {
42217
+ imageUrl: options.imageUrl,
42218
+ type: options.type,
42219
+ font: options.font,
42220
+ color: options.color,
42221
+ hue,
42222
+ tone: options.tone,
42223
+ name: options.name
42224
+ };
42225
+ if (options.toneScore !== void 0) {
42226
+ const n = Number(options.toneScore);
42227
+ if (Number.isNaN(n)) fail("--tone-score must be a number");
42228
+ params.toneScore = n;
42229
+ }
42230
+ if (options.variant) params.variant = options.variant;
42231
+ if (options.sha256) params.sha256 = options.sha256;
42232
+ const width = parseNonNegativeInt2(options.width, "--width");
42233
+ if (width !== void 0) params.width = width;
42234
+ const height = parseNonNegativeInt2(options.height, "--height");
42235
+ if (height !== void 0) params.height = height;
42236
+ if (options.aspectRatio) params.aspectRatio = options.aspectRatio;
42237
+ if (options.mimeType) params.mimeType = options.mimeType;
42238
+ const byteSize = parseNonNegativeInt2(options.byteSize, "--byte-size");
42239
+ if (byteSize !== void 0) params.byteSize = byteSize;
42240
+ if (options.tags) params.tags = String(options.tags).split(",").map((t) => t.trim()).filter(Boolean);
42241
+ if (options.inactive) params.isActive = false;
42242
+ const client = await getGlobalClientAsync();
42243
+ const data = await client.logos.create(params);
42244
+ output(data);
42245
+ });
42246
+ logos.command("update <id>").description("Update a logo pool entry").option("--image-url <url>", "Public image URL").option("--type <type>", `Type (${TYPES.join("/")})`).option("--font <font>", "Font family").option("--color <hex>", "Brand ink hex").option("--hue <n>", "Hue bucket (0-11)").option("--tone <tone>", `Tone (${TONES.join("/")})`).option("--name <name>", "Fictional brand name").option("--tone-score <n>", "Authored tone score").option("--variant <variant>", "Variant descriptor").option("--sha256 <hash>", "Content hash").option("--width <n>", "Image width in px").option("--height <n>", "Image height in px").option("--aspect-ratio <ratio>", "Aspect ratio, e.g. 4:1").option("--mime-type <type>", "MIME type, e.g. image/webp").option("--byte-size <n>", "File size in bytes").option("--tags <csv>", "Comma-separated tags (replaces existing)").option("--active", "Mark active").option("--inactive", "Mark inactive").addHelpText("after", `
42247
+ Examples:
42248
+ $ neopress logos update 12 --inactive
42249
+ $ neopress logos update 12 --tone playful --tags studio,flat
42250
+ Pass at least one field. --active/--inactive toggle is_active; --tags replaces the tag list.`).action(async (id, options) => {
42251
+ validateEnum2(options.type, TYPES, "--type");
42252
+ validateEnum2(options.tone, TONES, "--tone");
42253
+ if (options.active && options.inactive) {
42254
+ fail("Use only one of --active or --inactive.");
42255
+ }
42256
+ const params = {};
42257
+ if (options.imageUrl) params.imageUrl = options.imageUrl;
42258
+ if (options.type) params.type = options.type;
42259
+ if (options.font) params.font = options.font;
42260
+ if (options.color) params.color = options.color;
42261
+ const hue = parseHue(options.hue);
42262
+ if (hue !== void 0) params.hue = hue;
42263
+ if (options.tone) params.tone = options.tone;
42264
+ if (options.name) params.name = options.name;
42265
+ if (options.toneScore !== void 0) {
42266
+ const n = Number(options.toneScore);
42267
+ if (Number.isNaN(n)) fail("--tone-score must be a number");
42268
+ params.toneScore = n;
42269
+ }
42270
+ if (options.variant) params.variant = options.variant;
42271
+ if (options.sha256) params.sha256 = options.sha256;
42272
+ const width = parseNonNegativeInt2(options.width, "--width");
42273
+ if (width !== void 0) params.width = width;
42274
+ const height = parseNonNegativeInt2(options.height, "--height");
42275
+ if (height !== void 0) params.height = height;
42276
+ if (options.aspectRatio) params.aspectRatio = options.aspectRatio;
42277
+ if (options.mimeType) params.mimeType = options.mimeType;
42278
+ const byteSize = parseNonNegativeInt2(options.byteSize, "--byte-size");
42279
+ if (byteSize !== void 0) params.byteSize = byteSize;
42280
+ if (options.tags) params.tags = String(options.tags).split(",").map((t) => t.trim()).filter(Boolean);
42281
+ if (options.active) params.isActive = true;
42282
+ else if (options.inactive) params.isActive = false;
42283
+ if (Object.keys(params).length === 0) {
42284
+ fail("No fields to update.");
42285
+ }
42286
+ const client = await getGlobalClientAsync();
42287
+ const data = await client.logos.update(parseInt(id, 10), params);
42288
+ output(data);
42289
+ });
42290
+ logos.command("delete <id>").description("Delete a logo pool entry (hard delete)").action(async (id) => {
42291
+ const client = await getGlobalClientAsync();
42292
+ await client.logos.delete(parseInt(id, 10));
42293
+ ok(`Logo ${id} deleted`);
42294
+ });
42295
+ }
42296
+
41977
42297
  // src/commands/guide.ts
41978
42298
  function describeOption(opt) {
41979
42299
  const info = { flags: opt.flags, description: opt.description || "" };
@@ -42058,7 +42378,7 @@ function registerGuideCommands(program3) {
42058
42378
 
42059
42379
  // src/bin.ts
42060
42380
  var program2 = new Command();
42061
- program2.name("neopress").description("Neopress CLI \u2014 manage your site from the terminal").version("4.4.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) => {
42381
+ program2.name("neopress").description("Neopress CLI \u2014 manage your site from the terminal").version("4.6.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) => {
42062
42382
  const opts = thisCommand.optsWithGlobals();
42063
42383
  if (opts.site) setSiteOverride(String(opts.site));
42064
42384
  if (opts.json || !process.stdout.isTTY) setJsonMode(true);
@@ -42077,6 +42397,7 @@ registerEntryReferenceCommands(program2);
42077
42397
  registerAnalyticsCommands(program2);
42078
42398
  registerTemplateCommands(program2);
42079
42399
  registerHeadshotCommands(program2);
42400
+ registerLogoCommands(program2);
42080
42401
  registerGuideCommands(program2);
42081
42402
  program2.addHelpText(
42082
42403
  "after",
package/dist/index.js CHANGED
@@ -21115,6 +21115,7 @@ function serializeRedirect(r) {
21115
21115
  siteId: r.site_id,
21116
21116
  source: r.source,
21117
21117
  destination: r.destination,
21118
+ mode: r.mode,
21118
21119
  redirectType: r.redirect_type,
21119
21120
  includeChildren: r.include_children,
21120
21121
  preservePath: r.preserve_path,
@@ -21166,6 +21167,30 @@ function serializeHeadshot(h) {
21166
21167
  updatedAt: h.updated_at
21167
21168
  };
21168
21169
  }
21170
+ function serializeLogo(l) {
21171
+ return {
21172
+ id: l.id,
21173
+ imageUrl: l.image_url,
21174
+ width: l.width,
21175
+ height: l.height,
21176
+ aspectRatio: l.aspect_ratio,
21177
+ mimeType: l.mime_type,
21178
+ byteSize: l.byte_size,
21179
+ type: l.type,
21180
+ font: l.font,
21181
+ color: l.color,
21182
+ hue: l.hue,
21183
+ tone: l.tone,
21184
+ toneScore: l.tone_score,
21185
+ name: l.name,
21186
+ variant: l.variant,
21187
+ sha256: l.sha256,
21188
+ tags: l.tags ?? [],
21189
+ isActive: l.is_active,
21190
+ createdAt: l.created_at,
21191
+ updatedAt: l.updated_at
21192
+ };
21193
+ }
21169
21194
  function serializeSite(site) {
21170
21195
  return {
21171
21196
  id: site.id,
@@ -21315,7 +21340,8 @@ var COLLECTION_FIELD_TYPES = [
21315
21340
  "checkbox",
21316
21341
  "radio",
21317
21342
  "multi_checkbox",
21318
- "consent"
21343
+ "consent",
21344
+ "place"
21319
21345
  ];
21320
21346
  var COLLECTION_FIELD_TYPE_ALIASES = {
21321
21347
  boolean: "bool",
@@ -35193,12 +35219,10 @@ var COLLECTION_PRESET_CONTRACTS = {
35193
35219
  schema: {
35194
35220
  title: titleField("Name"),
35195
35221
  slug: slugField(),
35196
- image: field("image", "Image", "image"),
35197
- address: field("address", "Address", "text"),
35198
- city: field("city", "City", "text"),
35222
+ location: field("location", "Location", "place"),
35199
35223
  description: field("description", "Description", "content")
35200
35224
  },
35201
- lockedFieldIds: ["title", "slug", "image"]
35225
+ lockedFieldIds: ["title", "slug", "location"]
35202
35226
  },
35203
35227
  category: {
35204
35228
  schema: {
@@ -36638,6 +36662,12 @@ var SiteEndpoint = class {
36638
36662
  };
36639
36663
 
36640
36664
  // ../sdk/dist/endpoints/redirects.js
36665
+ var DASHBOARD_ONLY_REWRITE_MESSAGE = "Rewrite proxy rules can only be managed in the dashboard.";
36666
+ function rejectModeParam(data) {
36667
+ if (data && typeof data === "object" && Object.prototype.hasOwnProperty.call(data, "mode")) {
36668
+ throw new NeopressApiError("REDIRECT_RULE_DASHBOARD_ONLY", DASHBOARD_ONLY_REWRITE_MESSAGE, 400);
36669
+ }
36670
+ }
36641
36671
  var RedirectsEndpoint = class {
36642
36672
  client;
36643
36673
  constructor(client) {
@@ -36652,6 +36682,7 @@ var RedirectsEndpoint = class {
36652
36682
  return (data ?? []).map((r) => serializeRedirect(r));
36653
36683
  }
36654
36684
  async create(data) {
36685
+ rejectModeParam(data);
36655
36686
  const values = {
36656
36687
  site_id: this.client.siteIdNumber,
36657
36688
  source: data.source,
@@ -36667,7 +36698,21 @@ var RedirectsEndpoint = class {
36667
36698
  throw new NeopressApiError("DB_ERROR", error48.message, 0, error48);
36668
36699
  return serializeRedirect(row);
36669
36700
  }
36701
+ async assertRedirectRuleWritable(ruleId) {
36702
+ const { data, error: error48 } = await this.client.db.from("redirect_rules").select("id, mode").eq("site_id", this.client.siteIdNumber).eq("id", ruleId).maybeSingle();
36703
+ if (error48)
36704
+ throw new NeopressApiError("DB_ERROR", error48.message, 0, error48);
36705
+ if (!data) {
36706
+ throw new NeopressApiError("REDIRECT_RULE_NOT_FOUND", `Redirect rule ${ruleId} not found for this site`, 404);
36707
+ }
36708
+ const row = data;
36709
+ if (row.mode === "proxy") {
36710
+ throw new NeopressApiError("REDIRECT_RULE_DASHBOARD_ONLY", DASHBOARD_ONLY_REWRITE_MESSAGE, 400);
36711
+ }
36712
+ }
36670
36713
  async update(ruleId, data) {
36714
+ rejectModeParam(data);
36715
+ await this.assertRedirectRuleWritable(ruleId);
36671
36716
  const values = {};
36672
36717
  if ("source" in data)
36673
36718
  values.source = data.source;
@@ -36689,6 +36734,7 @@ var RedirectsEndpoint = class {
36689
36734
  return serializeRedirect(row);
36690
36735
  }
36691
36736
  async delete(ruleId) {
36737
+ await this.assertRedirectRuleWritable(ruleId);
36692
36738
  const { error: error48 } = await this.client.db.from("redirect_rules").delete().eq("site_id", this.client.siteIdNumber).eq("id", ruleId);
36693
36739
  if (error48)
36694
36740
  throw new NeopressApiError("DB_ERROR", error48.message, 0, error48);
@@ -37007,6 +37053,128 @@ var HeadshotsEndpoint = class {
37007
37053
  }
37008
37054
  };
37009
37055
 
37056
+ // ../sdk/dist/endpoints/logos.js
37057
+ var LogosEndpoint = class {
37058
+ client;
37059
+ constructor(client) {
37060
+ this.client = client;
37061
+ }
37062
+ async list(params) {
37063
+ const { page, limit, offset } = this.client.resolvePagination(params);
37064
+ let query = this.client.db.from("logo_pool").select("*", { count: "exact" });
37065
+ if (params?.type)
37066
+ query = query.eq("type", params.type);
37067
+ if (params?.tone)
37068
+ query = query.eq("tone", params.tone);
37069
+ if (params?.font)
37070
+ query = query.eq("font", params.font);
37071
+ if (params?.hue !== void 0)
37072
+ query = query.eq("hue", params.hue);
37073
+ if (params?.isActive !== void 0)
37074
+ query = query.eq("is_active", params.isActive);
37075
+ if (params?.order) {
37076
+ query = query.order("created_at", { ascending: params.order === "asc" });
37077
+ } else {
37078
+ query = query.order("type", { ascending: true }).order("hue", { ascending: true }).order("name", { ascending: true });
37079
+ }
37080
+ const { data, error: error48, count } = await query.range(offset, offset + limit - 1);
37081
+ if (error48)
37082
+ throw new NeopressApiError("DB_ERROR", error48.message, 0, error48);
37083
+ return {
37084
+ data: (data ?? []).map((r) => serializeLogo(r)),
37085
+ pagination: this.client.paginationMeta(page, limit, offset, count ?? 0)
37086
+ };
37087
+ }
37088
+ async get(id) {
37089
+ const { data, error: error48 } = await this.client.db.from("logo_pool").select("*").eq("id", id).single();
37090
+ if (error48)
37091
+ throw new NeopressApiError("DB_ERROR", error48.message, 0, error48);
37092
+ return serializeLogo(data);
37093
+ }
37094
+ async create(params) {
37095
+ const values = {
37096
+ image_url: params.imageUrl,
37097
+ type: params.type,
37098
+ font: params.font,
37099
+ color: params.color,
37100
+ hue: params.hue,
37101
+ tone: params.tone,
37102
+ name: params.name
37103
+ };
37104
+ if (params.toneScore !== void 0)
37105
+ values.tone_score = params.toneScore;
37106
+ if (params.variant !== void 0)
37107
+ values.variant = params.variant;
37108
+ if (params.sha256 !== void 0)
37109
+ values.sha256 = params.sha256;
37110
+ if (params.width !== void 0)
37111
+ values.width = params.width;
37112
+ if (params.height !== void 0)
37113
+ values.height = params.height;
37114
+ if (params.aspectRatio !== void 0)
37115
+ values.aspect_ratio = params.aspectRatio;
37116
+ if (params.mimeType !== void 0)
37117
+ values.mime_type = params.mimeType;
37118
+ if (params.byteSize !== void 0)
37119
+ values.byte_size = params.byteSize;
37120
+ if (params.tags !== void 0)
37121
+ values.tags = params.tags;
37122
+ if (params.isActive !== void 0)
37123
+ values.is_active = params.isActive;
37124
+ const { data, error: error48 } = await this.client.db.from("logo_pool").insert(values).select().single();
37125
+ if (error48)
37126
+ throw new NeopressApiError("DB_ERROR", error48.message, 0, error48);
37127
+ return serializeLogo(data);
37128
+ }
37129
+ async update(id, params) {
37130
+ const values = {};
37131
+ if (params.imageUrl !== void 0)
37132
+ values.image_url = params.imageUrl;
37133
+ if (params.type !== void 0)
37134
+ values.type = params.type;
37135
+ if (params.font !== void 0)
37136
+ values.font = params.font;
37137
+ if (params.color !== void 0)
37138
+ values.color = params.color;
37139
+ if (params.hue !== void 0)
37140
+ values.hue = params.hue;
37141
+ if (params.tone !== void 0)
37142
+ values.tone = params.tone;
37143
+ if (params.name !== void 0)
37144
+ values.name = params.name;
37145
+ if (params.toneScore !== void 0)
37146
+ values.tone_score = params.toneScore;
37147
+ if (params.variant !== void 0)
37148
+ values.variant = params.variant;
37149
+ if (params.sha256 !== void 0)
37150
+ values.sha256 = params.sha256;
37151
+ if (params.width !== void 0)
37152
+ values.width = params.width;
37153
+ if (params.height !== void 0)
37154
+ values.height = params.height;
37155
+ if (params.aspectRatio !== void 0)
37156
+ values.aspect_ratio = params.aspectRatio;
37157
+ if (params.mimeType !== void 0)
37158
+ values.mime_type = params.mimeType;
37159
+ if (params.byteSize !== void 0)
37160
+ values.byte_size = params.byteSize;
37161
+ if (params.tags !== void 0)
37162
+ values.tags = params.tags;
37163
+ if (params.isActive !== void 0)
37164
+ values.is_active = params.isActive;
37165
+ const { data, error: error48 } = await this.client.db.from("logo_pool").update(values).eq("id", id).select().single();
37166
+ if (error48)
37167
+ throw new NeopressApiError("DB_ERROR", error48.message, 0, error48);
37168
+ return serializeLogo(data);
37169
+ }
37170
+ async delete(id) {
37171
+ const { error: error48 } = await this.client.db.from("logo_pool").delete().eq("id", id);
37172
+ if (error48)
37173
+ throw new NeopressApiError("DB_ERROR", error48.message, 0, error48);
37174
+ return { id, deleted: true };
37175
+ }
37176
+ };
37177
+
37010
37178
  // ../sdk/dist/client.js
37011
37179
  var NeopressClient = class {
37012
37180
  baseUrl;
@@ -37028,6 +37196,7 @@ var NeopressClient = class {
37028
37196
  analytics;
37029
37197
  templates;
37030
37198
  headshots;
37199
+ logos;
37031
37200
  constructor(options) {
37032
37201
  this.baseUrl = (options.baseUrl || "https://app.neopress.ai").replace(/\/$/, "");
37033
37202
  this.accessToken = options.accessToken || "";
@@ -37047,6 +37216,7 @@ var NeopressClient = class {
37047
37216
  this.analytics = new AnalyticsEndpoint(this);
37048
37217
  this.templates = new TemplatesEndpoint(this);
37049
37218
  this.headshots = new HeadshotsEndpoint(this);
37219
+ this.logos = new LogosEndpoint(this);
37050
37220
  }
37051
37221
  get siteBasePath() {
37052
37222
  return `/api/v1/sites/${this.siteId}`;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@neopress/cli",
3
- "version": "4.4.0",
3
+ "version": "4.6.0",
4
4
  "description": "Neopress CLI — manage your Neopress site from the terminal",
5
5
  "type": "module",
6
6
  "keywords": [
@@ -21,14 +21,17 @@
21
21
  "dist",
22
22
  "README.md"
23
23
  ],
24
+ "engines": {
25
+ "node": ">=24"
26
+ },
24
27
  "publishConfig": {
25
28
  "access": "public"
26
29
  },
27
30
  "devDependencies": {
28
- "@types/node": "^22.0.0",
31
+ "@types/node": "^24",
29
32
  "commander": "^13.0.0",
30
33
  "tsup": "^8.5.1",
31
- "typescript": "^5.7.0",
34
+ "typescript": "^5.9.3",
32
35
  "@neopress/sdk": "0.4.0"
33
36
  },
34
37
  "scripts": {