@neopress/cli 4.3.0 → 4.5.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 +309 -17
  2. package/dist/index.js +150 -7
  3. package/package.json +1 -1
package/dist/bin.cjs CHANGED
@@ -24917,7 +24917,6 @@ function serializeTemplate(t) {
24917
24917
  id: t.id,
24918
24918
  name: t.name,
24919
24919
  description: t.description ?? null,
24920
- industry: t.industry,
24921
24920
  referenceUrl: t.reference_url,
24922
24921
  previewImgUrls: t.preview_img_urls,
24923
24922
  previewVideoUrl: t.preview_video_url ?? null,
@@ -24945,6 +24944,30 @@ function serializeHeadshot(h) {
24945
24944
  updatedAt: h.updated_at
24946
24945
  };
24947
24946
  }
24947
+ function serializeLogo(l) {
24948
+ return {
24949
+ id: l.id,
24950
+ imageUrl: l.image_url,
24951
+ width: l.width,
24952
+ height: l.height,
24953
+ aspectRatio: l.aspect_ratio,
24954
+ mimeType: l.mime_type,
24955
+ byteSize: l.byte_size,
24956
+ type: l.type,
24957
+ font: l.font,
24958
+ color: l.color,
24959
+ hue: l.hue,
24960
+ tone: l.tone,
24961
+ toneScore: l.tone_score,
24962
+ name: l.name,
24963
+ variant: l.variant,
24964
+ sha256: l.sha256,
24965
+ tags: l.tags ?? [],
24966
+ isActive: l.is_active,
24967
+ createdAt: l.created_at,
24968
+ updatedAt: l.updated_at
24969
+ };
24970
+ }
24948
24971
  function serializeSite(site) {
24949
24972
  return {
24950
24973
  id: site.id,
@@ -40435,7 +40458,7 @@ var RedirectsEndpoint = class {
40435
40458
  site_id: this.client.siteIdNumber,
40436
40459
  source: data.source,
40437
40460
  destination: data.destination,
40438
- redirect_type: data.redirectType ?? 307,
40461
+ redirect_type: data.redirectType ?? 308,
40439
40462
  include_children: data.includeChildren ?? false,
40440
40463
  preserve_path: data.preservePath ?? false,
40441
40464
  enabled: data.enabled !== false,
@@ -40648,13 +40671,10 @@ var TemplatesEndpoint = class {
40648
40671
  if (siteIds.length === 0)
40649
40672
  return [];
40650
40673
  const namePrefix = params?.namePrefix?.trim();
40651
- const industry = params?.industry?.trim();
40652
40674
  const limit = Math.min(Math.max(params?.limit ?? 100, 1), 500);
40653
- let query = this.client.db.from("templates").select("id, name, industry, reference_url, preview_img_urls, description, created_at").in("id", siteIds);
40675
+ let query = this.client.db.from("templates").select("id, name, reference_url, preview_img_urls, description, created_at").in("id", siteIds);
40654
40676
  if (namePrefix)
40655
40677
  query = query.ilike("name", `${namePrefix}%`);
40656
- if (industry)
40657
- query = query.eq("industry", industry);
40658
40678
  if (params?.order)
40659
40679
  query = query.order("created_at", { ascending: params.order === "asc" });
40660
40680
  query = query.limit(limit);
@@ -40668,7 +40688,6 @@ var TemplatesEndpoint = class {
40668
40688
  handle: siteMeta.get(siteId)?.handle ?? null,
40669
40689
  siteName: siteMeta.get(siteId)?.name ?? null,
40670
40690
  name: t.name,
40671
- industry: t.industry,
40672
40691
  referenceUrl: t.reference_url,
40673
40692
  previewImgUrls: t.preview_img_urls ?? null,
40674
40693
  description: t.description ?? null,
@@ -40790,6 +40809,128 @@ var HeadshotsEndpoint = class {
40790
40809
  }
40791
40810
  };
40792
40811
 
40812
+ // ../sdk/dist/endpoints/logos.js
40813
+ var LogosEndpoint = class {
40814
+ client;
40815
+ constructor(client) {
40816
+ this.client = client;
40817
+ }
40818
+ async list(params) {
40819
+ const { page, limit, offset } = this.client.resolvePagination(params);
40820
+ let query = this.client.db.from("logo_pool").select("*", { count: "exact" });
40821
+ if (params?.type)
40822
+ query = query.eq("type", params.type);
40823
+ if (params?.tone)
40824
+ query = query.eq("tone", params.tone);
40825
+ if (params?.font)
40826
+ query = query.eq("font", params.font);
40827
+ if (params?.hue !== void 0)
40828
+ query = query.eq("hue", params.hue);
40829
+ if (params?.isActive !== void 0)
40830
+ query = query.eq("is_active", params.isActive);
40831
+ if (params?.order) {
40832
+ query = query.order("created_at", { ascending: params.order === "asc" });
40833
+ } else {
40834
+ query = query.order("type", { ascending: true }).order("hue", { ascending: true }).order("name", { ascending: true });
40835
+ }
40836
+ const { data, error: error48, count } = await query.range(offset, offset + limit - 1);
40837
+ if (error48)
40838
+ throw new NeopressApiError("DB_ERROR", error48.message, 0, error48);
40839
+ return {
40840
+ data: (data ?? []).map((r) => serializeLogo(r)),
40841
+ pagination: this.client.paginationMeta(page, limit, offset, count ?? 0)
40842
+ };
40843
+ }
40844
+ async get(id) {
40845
+ const { data, error: error48 } = await this.client.db.from("logo_pool").select("*").eq("id", id).single();
40846
+ if (error48)
40847
+ throw new NeopressApiError("DB_ERROR", error48.message, 0, error48);
40848
+ return serializeLogo(data);
40849
+ }
40850
+ async create(params) {
40851
+ const values = {
40852
+ image_url: params.imageUrl,
40853
+ type: params.type,
40854
+ font: params.font,
40855
+ color: params.color,
40856
+ hue: params.hue,
40857
+ tone: params.tone,
40858
+ name: params.name
40859
+ };
40860
+ if (params.toneScore !== void 0)
40861
+ values.tone_score = params.toneScore;
40862
+ if (params.variant !== void 0)
40863
+ values.variant = params.variant;
40864
+ if (params.sha256 !== void 0)
40865
+ values.sha256 = params.sha256;
40866
+ if (params.width !== void 0)
40867
+ values.width = params.width;
40868
+ if (params.height !== void 0)
40869
+ values.height = params.height;
40870
+ if (params.aspectRatio !== void 0)
40871
+ values.aspect_ratio = params.aspectRatio;
40872
+ if (params.mimeType !== void 0)
40873
+ values.mime_type = params.mimeType;
40874
+ if (params.byteSize !== void 0)
40875
+ values.byte_size = params.byteSize;
40876
+ if (params.tags !== void 0)
40877
+ values.tags = params.tags;
40878
+ if (params.isActive !== void 0)
40879
+ values.is_active = params.isActive;
40880
+ const { data, error: error48 } = await this.client.db.from("logo_pool").insert(values).select().single();
40881
+ if (error48)
40882
+ throw new NeopressApiError("DB_ERROR", error48.message, 0, error48);
40883
+ return serializeLogo(data);
40884
+ }
40885
+ async update(id, params) {
40886
+ const values = {};
40887
+ if (params.imageUrl !== void 0)
40888
+ values.image_url = params.imageUrl;
40889
+ if (params.type !== void 0)
40890
+ values.type = params.type;
40891
+ if (params.font !== void 0)
40892
+ values.font = params.font;
40893
+ if (params.color !== void 0)
40894
+ values.color = params.color;
40895
+ if (params.hue !== void 0)
40896
+ values.hue = params.hue;
40897
+ if (params.tone !== void 0)
40898
+ values.tone = params.tone;
40899
+ if (params.name !== void 0)
40900
+ values.name = params.name;
40901
+ if (params.toneScore !== void 0)
40902
+ values.tone_score = params.toneScore;
40903
+ if (params.variant !== void 0)
40904
+ values.variant = params.variant;
40905
+ if (params.sha256 !== void 0)
40906
+ values.sha256 = params.sha256;
40907
+ if (params.width !== void 0)
40908
+ values.width = params.width;
40909
+ if (params.height !== void 0)
40910
+ values.height = params.height;
40911
+ if (params.aspectRatio !== void 0)
40912
+ values.aspect_ratio = params.aspectRatio;
40913
+ if (params.mimeType !== void 0)
40914
+ values.mime_type = params.mimeType;
40915
+ if (params.byteSize !== void 0)
40916
+ values.byte_size = params.byteSize;
40917
+ if (params.tags !== void 0)
40918
+ values.tags = params.tags;
40919
+ if (params.isActive !== void 0)
40920
+ values.is_active = params.isActive;
40921
+ const { data, error: error48 } = await this.client.db.from("logo_pool").update(values).eq("id", id).select().single();
40922
+ if (error48)
40923
+ throw new NeopressApiError("DB_ERROR", error48.message, 0, error48);
40924
+ return serializeLogo(data);
40925
+ }
40926
+ async delete(id) {
40927
+ const { error: error48 } = await this.client.db.from("logo_pool").delete().eq("id", id);
40928
+ if (error48)
40929
+ throw new NeopressApiError("DB_ERROR", error48.message, 0, error48);
40930
+ return { id, deleted: true };
40931
+ }
40932
+ };
40933
+
40793
40934
  // ../sdk/dist/client.js
40794
40935
  var NeopressClient = class {
40795
40936
  baseUrl;
@@ -40811,6 +40952,7 @@ var NeopressClient = class {
40811
40952
  analytics;
40812
40953
  templates;
40813
40954
  headshots;
40955
+ logos;
40814
40956
  constructor(options) {
40815
40957
  this.baseUrl = (options.baseUrl || "https://app.neopress.ai").replace(/\/$/, "");
40816
40958
  this.accessToken = options.accessToken || "";
@@ -40830,6 +40972,7 @@ var NeopressClient = class {
40830
40972
  this.analytics = new AnalyticsEndpoint(this);
40831
40973
  this.templates = new TemplatesEndpoint(this);
40832
40974
  this.headshots = new HeadshotsEndpoint(this);
40975
+ this.logos = new LogosEndpoint(this);
40833
40976
  }
40834
40977
  get siteBasePath() {
40835
40978
  return `/api/v1/sites/${this.siteId}`;
@@ -41577,7 +41720,7 @@ Rules are created enabled. delete <ruleId> removes a rule permanently.`);
41577
41720
  Examples:
41578
41721
  $ neopress redirects create --source /old --dest /about
41579
41722
  $ neopress redirects create --source /docs --dest /guide --type 308
41580
- --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) => {
41723
+ --source and --dest are both required. --type is 307 (temporary) or 308 (permanent, default). The rule is created enabled.`).requiredOption("--source <path>", "Source path").requiredOption("--dest <path>", "Destination path").option("--type <type>", "Redirect type (307/308)", "308").action(async (options) => {
41581
41724
  const client = await getClientAsync();
41582
41725
  const rule = await client.redirects.create({
41583
41726
  source: options.source,
@@ -41796,15 +41939,14 @@ function collectPreviewImgUrl(value, previous = []) {
41796
41939
  function registerTemplateCommands(program3) {
41797
41940
  const templates = program3.command("templates").description("Manage template metadata for the active site").addHelpText("after", `
41798
41941
  Examples:
41799
- $ neopress templates mark --name "SaaS Landing" --industry saas --reference-url https://example.com --preview-img-url https://cdn.example.com/1.png
41800
- $ neopress templates list --industry saas --limit 50
41942
+ $ neopress templates mark --name "SaaS Landing" --reference-url https://example.com --preview-img-url https://cdn.example.com/1.png
41943
+ $ neopress templates list --limit 50
41801
41944
  $ neopress templates delete
41802
41945
  \`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.`);
41803
- 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("--order <asc|desc>", ORDER_OPTION_DESC).option("--limit <n>", "Max results (default 100, max 500)").action(async (options) => {
41946
+ templates.command("list").description("List templates across sites you can access").option("--name-prefix <prefix>", "Filter by template name prefix").option("--order <asc|desc>", ORDER_OPTION_DESC).option("--limit <n>", "Max results (default 100, max 500)").action(async (options) => {
41804
41947
  const client = await getGlobalClientAsync();
41805
41948
  const templates2 = await client.templates.list({
41806
41949
  namePrefix: options.namePrefix,
41807
- industry: options.industry,
41808
41950
  order: parseOrder(options.order),
41809
41951
  limit: options.limit ? parseInt(options.limit, 10) : void 0
41810
41952
  });
@@ -41817,9 +41959,9 @@ Examples:
41817
41959
  });
41818
41960
  templates.command("mark").description("Mark or update the active site as a template").addHelpText("after", `
41819
41961
  Examples:
41820
- $ neopress templates mark --name "SaaS Landing" --industry saas --reference-url https://example.com --preview-img-url https://cdn.example.com/1.png
41821
- $ 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"
41822
- --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(
41962
+ $ neopress templates mark --name "SaaS Landing" --reference-url https://example.com --preview-img-url https://cdn.example.com/1.png
41963
+ $ neopress templates mark --name Portfolio --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"
41964
+ --name and --reference-url are 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(
41823
41965
  "--reference-url <url>",
41824
41966
  "Reference URL for template provenance"
41825
41967
  ).option(
@@ -41832,7 +41974,6 @@ Examples:
41832
41974
  const template = await client.templates.mark({
41833
41975
  name: options.name,
41834
41976
  description: options.description,
41835
- industry: options.industry,
41836
41977
  referenceUrl: options.referenceUrl,
41837
41978
  previewImgUrls: options.previewImgUrl.length > 0 ? options.previewImgUrl : void 0
41838
41979
  });
@@ -41981,6 +42122,156 @@ Pass at least one field. --active/--inactive toggle is_active; --tags replaces t
41981
42122
  });
41982
42123
  }
41983
42124
 
42125
+ // src/commands/logos.ts
42126
+ var TYPES = ["wordmark", "lockup", "signature"];
42127
+ var TONES = ["playful", "neutral", "serious"];
42128
+ function validateEnum2(value, allowed, flag) {
42129
+ if (value !== void 0 && !allowed.includes(value)) {
42130
+ fail(`${flag} must be one of: ${allowed.join(", ")}`);
42131
+ }
42132
+ }
42133
+ function parseNonNegativeInt2(raw, flag) {
42134
+ if (raw === void 0) return void 0;
42135
+ const value = Number(raw);
42136
+ if (!Number.isInteger(value) || value < 0) {
42137
+ fail(`${flag} must be a non-negative integer`);
42138
+ }
42139
+ return value;
42140
+ }
42141
+ function parseHue(raw) {
42142
+ if (raw === void 0) return void 0;
42143
+ const value = Number(raw);
42144
+ if (!Number.isInteger(value) || value < 0 || value > 11) {
42145
+ fail("--hue must be an integer 0-11 (12-bucket hue wheel)");
42146
+ }
42147
+ return value;
42148
+ }
42149
+ function registerLogoCommands(program3) {
42150
+ const logos = program3.command("logos").description("Manage the shared logo pool (super-admin only)").addHelpText("after", `
42151
+ Examples:
42152
+ $ neopress logos list --type lockup --tone playful
42153
+ $ neopress logos create --image-url https://cdn/x.webp --type wordmark --font geometric --color '#4f46e5' --hue 8 --tone neutral --name Northwind
42154
+ $ neopress logos update 12 --inactive
42155
+ The pool is global and RLS-gated: only the super-admin account can read or write it. No active site is needed.`);
42156
+ 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", `
42157
+ Examples:
42158
+ $ neopress logos list
42159
+ $ neopress logos list --type signature --tone serious --active
42160
+ Filters are equality matches on the pool's diversity axes; results are paginated.`).action(async (options) => {
42161
+ validateEnum2(options.type, TYPES, "--type");
42162
+ validateEnum2(options.tone, TONES, "--tone");
42163
+ if (options.active && options.inactive) {
42164
+ fail("Use only one of --active or --inactive.");
42165
+ }
42166
+ const hue = parseHue(options.hue);
42167
+ const params = {
42168
+ page: parseInt(options.page, 10),
42169
+ limit: parseInt(options.limit, 10),
42170
+ order: parseOrder(options.order),
42171
+ type: options.type,
42172
+ tone: options.tone,
42173
+ font: options.font
42174
+ };
42175
+ if (hue !== void 0) params.hue = hue;
42176
+ if (options.active) params.isActive = true;
42177
+ else if (options.inactive) params.isActive = false;
42178
+ const client = await getGlobalClientAsync();
42179
+ const res = await client.logos.list(params);
42180
+ output(res);
42181
+ });
42182
+ logos.command("get <id>").description("Get a logo pool entry").action(async (id) => {
42183
+ const client = await getGlobalClientAsync();
42184
+ const data = await client.logos.get(parseInt(id, 10));
42185
+ output(data);
42186
+ });
42187
+ 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", `
42188
+ Examples:
42189
+ $ neopress logos create --image-url https://cdn/a.webp --type lockup --font grotesk --color '#0d9488' --hue 5 --tone neutral --name Kestrel
42190
+ image_url is unique. The DB rejects out-of-range type/tone/hue values.`).action(async (options) => {
42191
+ validateEnum2(options.type, TYPES, "--type");
42192
+ validateEnum2(options.tone, TONES, "--tone");
42193
+ const hue = parseHue(options.hue);
42194
+ const params = {
42195
+ imageUrl: options.imageUrl,
42196
+ type: options.type,
42197
+ font: options.font,
42198
+ color: options.color,
42199
+ hue,
42200
+ tone: options.tone,
42201
+ name: options.name
42202
+ };
42203
+ if (options.toneScore !== void 0) {
42204
+ const n = Number(options.toneScore);
42205
+ if (Number.isNaN(n)) fail("--tone-score must be a number");
42206
+ params.toneScore = n;
42207
+ }
42208
+ if (options.variant) params.variant = options.variant;
42209
+ if (options.sha256) params.sha256 = options.sha256;
42210
+ const width = parseNonNegativeInt2(options.width, "--width");
42211
+ if (width !== void 0) params.width = width;
42212
+ const height = parseNonNegativeInt2(options.height, "--height");
42213
+ if (height !== void 0) params.height = height;
42214
+ if (options.aspectRatio) params.aspectRatio = options.aspectRatio;
42215
+ if (options.mimeType) params.mimeType = options.mimeType;
42216
+ const byteSize = parseNonNegativeInt2(options.byteSize, "--byte-size");
42217
+ if (byteSize !== void 0) params.byteSize = byteSize;
42218
+ if (options.tags) params.tags = String(options.tags).split(",").map((t) => t.trim()).filter(Boolean);
42219
+ if (options.inactive) params.isActive = false;
42220
+ const client = await getGlobalClientAsync();
42221
+ const data = await client.logos.create(params);
42222
+ output(data);
42223
+ });
42224
+ 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", `
42225
+ Examples:
42226
+ $ neopress logos update 12 --inactive
42227
+ $ neopress logos update 12 --tone playful --tags studio,flat
42228
+ Pass at least one field. --active/--inactive toggle is_active; --tags replaces the tag list.`).action(async (id, options) => {
42229
+ validateEnum2(options.type, TYPES, "--type");
42230
+ validateEnum2(options.tone, TONES, "--tone");
42231
+ if (options.active && options.inactive) {
42232
+ fail("Use only one of --active or --inactive.");
42233
+ }
42234
+ const params = {};
42235
+ if (options.imageUrl) params.imageUrl = options.imageUrl;
42236
+ if (options.type) params.type = options.type;
42237
+ if (options.font) params.font = options.font;
42238
+ if (options.color) params.color = options.color;
42239
+ const hue = parseHue(options.hue);
42240
+ if (hue !== void 0) params.hue = hue;
42241
+ if (options.tone) params.tone = options.tone;
42242
+ if (options.name) params.name = options.name;
42243
+ if (options.toneScore !== void 0) {
42244
+ const n = Number(options.toneScore);
42245
+ if (Number.isNaN(n)) fail("--tone-score must be a number");
42246
+ params.toneScore = n;
42247
+ }
42248
+ if (options.variant) params.variant = options.variant;
42249
+ if (options.sha256) params.sha256 = options.sha256;
42250
+ const width = parseNonNegativeInt2(options.width, "--width");
42251
+ if (width !== void 0) params.width = width;
42252
+ const height = parseNonNegativeInt2(options.height, "--height");
42253
+ if (height !== void 0) params.height = height;
42254
+ if (options.aspectRatio) params.aspectRatio = options.aspectRatio;
42255
+ if (options.mimeType) params.mimeType = options.mimeType;
42256
+ const byteSize = parseNonNegativeInt2(options.byteSize, "--byte-size");
42257
+ if (byteSize !== void 0) params.byteSize = byteSize;
42258
+ if (options.tags) params.tags = String(options.tags).split(",").map((t) => t.trim()).filter(Boolean);
42259
+ if (options.active) params.isActive = true;
42260
+ else if (options.inactive) params.isActive = false;
42261
+ if (Object.keys(params).length === 0) {
42262
+ fail("No fields to update.");
42263
+ }
42264
+ const client = await getGlobalClientAsync();
42265
+ const data = await client.logos.update(parseInt(id, 10), params);
42266
+ output(data);
42267
+ });
42268
+ logos.command("delete <id>").description("Delete a logo pool entry (hard delete)").action(async (id) => {
42269
+ const client = await getGlobalClientAsync();
42270
+ await client.logos.delete(parseInt(id, 10));
42271
+ ok(`Logo ${id} deleted`);
42272
+ });
42273
+ }
42274
+
41984
42275
  // src/commands/guide.ts
41985
42276
  function describeOption(opt) {
41986
42277
  const info = { flags: opt.flags, description: opt.description || "" };
@@ -42065,7 +42356,7 @@ function registerGuideCommands(program3) {
42065
42356
 
42066
42357
  // src/bin.ts
42067
42358
  var program2 = new Command();
42068
- program2.name("neopress").description("Neopress CLI \u2014 manage your site from the terminal").version("4.3.0").option("--json", "Output in JSON format (for AI tools and pipes)").option("--site <idOrHandle>", "Target a specific site (overrides active site; not persisted)").option("--no-input", "Non-interactive mode").hook("preAction", (thisCommand) => {
42359
+ program2.name("neopress").description("Neopress CLI \u2014 manage your site from the terminal").version("4.5.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) => {
42069
42360
  const opts = thisCommand.optsWithGlobals();
42070
42361
  if (opts.site) setSiteOverride(String(opts.site));
42071
42362
  if (opts.json || !process.stdout.isTTY) setJsonMode(true);
@@ -42084,6 +42375,7 @@ registerEntryReferenceCommands(program2);
42084
42375
  registerAnalyticsCommands(program2);
42085
42376
  registerTemplateCommands(program2);
42086
42377
  registerHeadshotCommands(program2);
42378
+ registerLogoCommands(program2);
42087
42379
  registerGuideCommands(program2);
42088
42380
  program2.addHelpText(
42089
42381
  "after",
package/dist/index.js CHANGED
@@ -21139,7 +21139,6 @@ function serializeTemplate(t) {
21139
21139
  id: t.id,
21140
21140
  name: t.name,
21141
21141
  description: t.description ?? null,
21142
- industry: t.industry,
21143
21142
  referenceUrl: t.reference_url,
21144
21143
  previewImgUrls: t.preview_img_urls,
21145
21144
  previewVideoUrl: t.preview_video_url ?? null,
@@ -21167,6 +21166,30 @@ function serializeHeadshot(h) {
21167
21166
  updatedAt: h.updated_at
21168
21167
  };
21169
21168
  }
21169
+ function serializeLogo(l) {
21170
+ return {
21171
+ id: l.id,
21172
+ imageUrl: l.image_url,
21173
+ width: l.width,
21174
+ height: l.height,
21175
+ aspectRatio: l.aspect_ratio,
21176
+ mimeType: l.mime_type,
21177
+ byteSize: l.byte_size,
21178
+ type: l.type,
21179
+ font: l.font,
21180
+ color: l.color,
21181
+ hue: l.hue,
21182
+ tone: l.tone,
21183
+ toneScore: l.tone_score,
21184
+ name: l.name,
21185
+ variant: l.variant,
21186
+ sha256: l.sha256,
21187
+ tags: l.tags ?? [],
21188
+ isActive: l.is_active,
21189
+ createdAt: l.created_at,
21190
+ updatedAt: l.updated_at
21191
+ };
21192
+ }
21170
21193
  function serializeSite(site) {
21171
21194
  return {
21172
21195
  id: site.id,
@@ -36657,7 +36680,7 @@ var RedirectsEndpoint = class {
36657
36680
  site_id: this.client.siteIdNumber,
36658
36681
  source: data.source,
36659
36682
  destination: data.destination,
36660
- redirect_type: data.redirectType ?? 307,
36683
+ redirect_type: data.redirectType ?? 308,
36661
36684
  include_children: data.includeChildren ?? false,
36662
36685
  preserve_path: data.preservePath ?? false,
36663
36686
  enabled: data.enabled !== false,
@@ -36870,13 +36893,10 @@ var TemplatesEndpoint = class {
36870
36893
  if (siteIds.length === 0)
36871
36894
  return [];
36872
36895
  const namePrefix = params?.namePrefix?.trim();
36873
- const industry = params?.industry?.trim();
36874
36896
  const limit = Math.min(Math.max(params?.limit ?? 100, 1), 500);
36875
- let query = this.client.db.from("templates").select("id, name, industry, reference_url, preview_img_urls, description, created_at").in("id", siteIds);
36897
+ let query = this.client.db.from("templates").select("id, name, reference_url, preview_img_urls, description, created_at").in("id", siteIds);
36876
36898
  if (namePrefix)
36877
36899
  query = query.ilike("name", `${namePrefix}%`);
36878
- if (industry)
36879
- query = query.eq("industry", industry);
36880
36900
  if (params?.order)
36881
36901
  query = query.order("created_at", { ascending: params.order === "asc" });
36882
36902
  query = query.limit(limit);
@@ -36890,7 +36910,6 @@ var TemplatesEndpoint = class {
36890
36910
  handle: siteMeta.get(siteId)?.handle ?? null,
36891
36911
  siteName: siteMeta.get(siteId)?.name ?? null,
36892
36912
  name: t.name,
36893
- industry: t.industry,
36894
36913
  referenceUrl: t.reference_url,
36895
36914
  previewImgUrls: t.preview_img_urls ?? null,
36896
36915
  description: t.description ?? null,
@@ -37012,6 +37031,128 @@ var HeadshotsEndpoint = class {
37012
37031
  }
37013
37032
  };
37014
37033
 
37034
+ // ../sdk/dist/endpoints/logos.js
37035
+ var LogosEndpoint = class {
37036
+ client;
37037
+ constructor(client) {
37038
+ this.client = client;
37039
+ }
37040
+ async list(params) {
37041
+ const { page, limit, offset } = this.client.resolvePagination(params);
37042
+ let query = this.client.db.from("logo_pool").select("*", { count: "exact" });
37043
+ if (params?.type)
37044
+ query = query.eq("type", params.type);
37045
+ if (params?.tone)
37046
+ query = query.eq("tone", params.tone);
37047
+ if (params?.font)
37048
+ query = query.eq("font", params.font);
37049
+ if (params?.hue !== void 0)
37050
+ query = query.eq("hue", params.hue);
37051
+ if (params?.isActive !== void 0)
37052
+ query = query.eq("is_active", params.isActive);
37053
+ if (params?.order) {
37054
+ query = query.order("created_at", { ascending: params.order === "asc" });
37055
+ } else {
37056
+ query = query.order("type", { ascending: true }).order("hue", { ascending: true }).order("name", { ascending: true });
37057
+ }
37058
+ const { data, error: error48, count } = await query.range(offset, offset + limit - 1);
37059
+ if (error48)
37060
+ throw new NeopressApiError("DB_ERROR", error48.message, 0, error48);
37061
+ return {
37062
+ data: (data ?? []).map((r) => serializeLogo(r)),
37063
+ pagination: this.client.paginationMeta(page, limit, offset, count ?? 0)
37064
+ };
37065
+ }
37066
+ async get(id) {
37067
+ const { data, error: error48 } = await this.client.db.from("logo_pool").select("*").eq("id", id).single();
37068
+ if (error48)
37069
+ throw new NeopressApiError("DB_ERROR", error48.message, 0, error48);
37070
+ return serializeLogo(data);
37071
+ }
37072
+ async create(params) {
37073
+ const values = {
37074
+ image_url: params.imageUrl,
37075
+ type: params.type,
37076
+ font: params.font,
37077
+ color: params.color,
37078
+ hue: params.hue,
37079
+ tone: params.tone,
37080
+ name: params.name
37081
+ };
37082
+ if (params.toneScore !== void 0)
37083
+ values.tone_score = params.toneScore;
37084
+ if (params.variant !== void 0)
37085
+ values.variant = params.variant;
37086
+ if (params.sha256 !== void 0)
37087
+ values.sha256 = params.sha256;
37088
+ if (params.width !== void 0)
37089
+ values.width = params.width;
37090
+ if (params.height !== void 0)
37091
+ values.height = params.height;
37092
+ if (params.aspectRatio !== void 0)
37093
+ values.aspect_ratio = params.aspectRatio;
37094
+ if (params.mimeType !== void 0)
37095
+ values.mime_type = params.mimeType;
37096
+ if (params.byteSize !== void 0)
37097
+ values.byte_size = params.byteSize;
37098
+ if (params.tags !== void 0)
37099
+ values.tags = params.tags;
37100
+ if (params.isActive !== void 0)
37101
+ values.is_active = params.isActive;
37102
+ const { data, error: error48 } = await this.client.db.from("logo_pool").insert(values).select().single();
37103
+ if (error48)
37104
+ throw new NeopressApiError("DB_ERROR", error48.message, 0, error48);
37105
+ return serializeLogo(data);
37106
+ }
37107
+ async update(id, params) {
37108
+ const values = {};
37109
+ if (params.imageUrl !== void 0)
37110
+ values.image_url = params.imageUrl;
37111
+ if (params.type !== void 0)
37112
+ values.type = params.type;
37113
+ if (params.font !== void 0)
37114
+ values.font = params.font;
37115
+ if (params.color !== void 0)
37116
+ values.color = params.color;
37117
+ if (params.hue !== void 0)
37118
+ values.hue = params.hue;
37119
+ if (params.tone !== void 0)
37120
+ values.tone = params.tone;
37121
+ if (params.name !== void 0)
37122
+ values.name = params.name;
37123
+ if (params.toneScore !== void 0)
37124
+ values.tone_score = params.toneScore;
37125
+ if (params.variant !== void 0)
37126
+ values.variant = params.variant;
37127
+ if (params.sha256 !== void 0)
37128
+ values.sha256 = params.sha256;
37129
+ if (params.width !== void 0)
37130
+ values.width = params.width;
37131
+ if (params.height !== void 0)
37132
+ values.height = params.height;
37133
+ if (params.aspectRatio !== void 0)
37134
+ values.aspect_ratio = params.aspectRatio;
37135
+ if (params.mimeType !== void 0)
37136
+ values.mime_type = params.mimeType;
37137
+ if (params.byteSize !== void 0)
37138
+ values.byte_size = params.byteSize;
37139
+ if (params.tags !== void 0)
37140
+ values.tags = params.tags;
37141
+ if (params.isActive !== void 0)
37142
+ values.is_active = params.isActive;
37143
+ const { data, error: error48 } = await this.client.db.from("logo_pool").update(values).eq("id", id).select().single();
37144
+ if (error48)
37145
+ throw new NeopressApiError("DB_ERROR", error48.message, 0, error48);
37146
+ return serializeLogo(data);
37147
+ }
37148
+ async delete(id) {
37149
+ const { error: error48 } = await this.client.db.from("logo_pool").delete().eq("id", id);
37150
+ if (error48)
37151
+ throw new NeopressApiError("DB_ERROR", error48.message, 0, error48);
37152
+ return { id, deleted: true };
37153
+ }
37154
+ };
37155
+
37015
37156
  // ../sdk/dist/client.js
37016
37157
  var NeopressClient = class {
37017
37158
  baseUrl;
@@ -37033,6 +37174,7 @@ var NeopressClient = class {
37033
37174
  analytics;
37034
37175
  templates;
37035
37176
  headshots;
37177
+ logos;
37036
37178
  constructor(options) {
37037
37179
  this.baseUrl = (options.baseUrl || "https://app.neopress.ai").replace(/\/$/, "");
37038
37180
  this.accessToken = options.accessToken || "";
@@ -37052,6 +37194,7 @@ var NeopressClient = class {
37052
37194
  this.analytics = new AnalyticsEndpoint(this);
37053
37195
  this.templates = new TemplatesEndpoint(this);
37054
37196
  this.headshots = new HeadshotsEndpoint(this);
37197
+ this.logos = new LogosEndpoint(this);
37055
37198
  }
37056
37199
  get siteBasePath() {
37057
37200
  return `/api/v1/sites/${this.siteId}`;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@neopress/cli",
3
- "version": "4.3.0",
3
+ "version": "4.5.0",
4
4
  "description": "Neopress CLI — manage your Neopress site from the terminal",
5
5
  "type": "module",
6
6
  "keywords": [