@paragraph-com/cli 0.1.0 → 0.1.1

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 (2) hide show
  1. package/dist/index.js +58 -23
  2. package/package.json +4 -4
package/dist/index.js CHANGED
@@ -4741,6 +4741,7 @@ async function validateApiKey(token) {
4741
4741
  const client = createClient(token);
4742
4742
  const me = await client.me.get();
4743
4743
  return {
4744
+ id: me.id,
4744
4745
  name: me.name,
4745
4746
  slug: me.slug,
4746
4747
  customDomain: me.customDomain
@@ -4781,7 +4782,7 @@ async function waitForLogin(sessionId, signal) {
4781
4782
  } catch (err) {
4782
4783
  const msg = err instanceof Error ? err.message : String(err);
4783
4784
  if (msg.includes("404") || msg.includes("Not found")) {
4784
- throw new Error("Login was denied or expired. Please try again.");
4785
+ throw new Error("Login was denied or expired. For non-interactive use, pass the key directly: `paragraph login --token <key>` (get one at paragraph.com/settings \u2192 Publication \u2192 Developer).");
4785
4786
  }
4786
4787
  continue;
4787
4788
  }
@@ -4789,10 +4790,10 @@ async function waitForLogin(sessionId, signal) {
4789
4790
  return status.apiKey;
4790
4791
  }
4791
4792
  if (status.status !== "pending") {
4792
- throw new Error("Login was denied or expired. Please try again.");
4793
+ throw new Error("Login was denied or expired. For non-interactive use, pass the key directly: `paragraph login --token <key>` (get one at paragraph.com/settings \u2192 Publication \u2192 Developer).");
4793
4794
  }
4794
4795
  }
4795
- throw new Error("Login timed out after 5 minutes. Please try again.");
4796
+ throw new Error("Login timed out after 5 minutes. For non-interactive use, pass the key directly: `paragraph login --token <key>` (get one at paragraph.com/settings \u2192 Publication \u2192 Developer).");
4796
4797
  }
4797
4798
  function openBrowser(url) {
4798
4799
  return new Promise((resolve, reject) => {
@@ -6733,8 +6734,11 @@ function extractError(err) {
6733
6734
  const message = data?.message || err.message;
6734
6735
  if (status === 401) {
6735
6736
  return { message: "Unauthorized. Check your API key or run `paragraph login`.", status, code: errorCode(status) };
6737
+ } else if (status === 403) {
6738
+ return { message: "Forbidden. Your API key doesn't have access to this resource. Run `paragraph whoami --json` to verify which publication the key is for.", status, code: errorCode(status) };
6736
6739
  } else if (status === 404) {
6737
- return { message: "Not found. " + (message || ""), status, code: errorCode(status) };
6740
+ const detail = message ? `${message}. ` : "";
6741
+ return { message: `Not found. ${detail}Verify the identifier is correct \u2014 use the matching list command (e.g. \`paragraph post list --json\`, \`paragraph subscriber list --json\`) to find valid values.`, status, code: errorCode(status) };
6738
6742
  } else if (status === 429) {
6739
6743
  return { message: "Rate limited. Please wait and try again.", status, code: errorCode(status) };
6740
6744
  }
@@ -6822,7 +6826,7 @@ Examples:
6822
6826
  chunks.push(chunk);
6823
6827
  }
6824
6828
  token = Buffer.concat(chunks).toString("utf-8").trim();
6825
- if (!token) throw new Error("No API key received on stdin.");
6829
+ if (!token) throw new Error("No API key received on stdin. Pipe the key (e.g. `echo $PARAGRAPH_API_KEY | paragraph login --with-token`) or use --token <key>.");
6826
6830
  } else if (!process.stdin.isTTY) {
6827
6831
  throw new Error(
6828
6832
  "No --token provided and stdin is not a TTY. Use --token <key> or --with-token."
@@ -6877,6 +6881,7 @@ Examples:
6877
6881
  const apiKey = requireApiKey();
6878
6882
  const me = await validateApiKey(apiKey);
6879
6883
  outputData(this, {
6884
+ ID: me.id,
6880
6885
  Name: me.name,
6881
6886
  Slug: me.slug,
6882
6887
  Domain: me.customDomain
@@ -6999,7 +7004,8 @@ var init_zod = __esm({
6999
7004
  }).optional().describe("Farcaster profile information, if linked")
7000
7005
  })).optional().describe("Authors of this post"),
7001
7006
  "authorIds": zod.array(zod.string()).optional().describe("IDs of the authors of this post"),
7002
- "views": zod.number().optional().describe("Total page views. Only included when fetching your own posts via GET /v1/posts")
7007
+ "views": zod.number().optional().describe("Total page views. Only included when fetching your own posts via GET /v1/posts"),
7008
+ "status": zod.enum(["published", "draft", "scheduled", "archived"]).optional().describe("Current publish status. Only set on authenticated endpoints (listOwn, getById for your own post). Use this instead of publishedAt to determine publish state \u2014 publishedAt is preserved across unpublishing.")
7003
7009
  }).describe("The post content"),
7004
7010
  "publication": zod.object({
7005
7011
  "id": zod.string().describe("Unique identifier for the publication"),
@@ -7073,7 +7079,8 @@ var init_zod = __esm({
7073
7079
  }).optional().describe("Farcaster profile information, if linked")
7074
7080
  })).optional().describe("Authors of this post"),
7075
7081
  "authorIds": zod.array(zod.string()).optional().describe("IDs of the authors of this post"),
7076
- "views": zod.number().optional().describe("Total page views. Only included when fetching your own posts via GET /v1/posts")
7082
+ "views": zod.number().optional().describe("Total page views. Only included when fetching your own posts via GET /v1/posts"),
7083
+ "status": zod.enum(["published", "draft", "scheduled", "archived"]).optional().describe("Current publish status. Only set on authenticated endpoints (listOwn, getById for your own post). Use this instead of publishedAt to determine publish state \u2014 publishedAt is preserved across unpublishing.")
7077
7084
  })).describe("Array of items in this page"),
7078
7085
  "pagination": zod.object({
7079
7086
  "cursor": zod.string().optional().describe("Cursor for fetching the next page of results"),
@@ -7124,7 +7131,8 @@ var init_zod = __esm({
7124
7131
  }).optional().describe("Farcaster profile information, if linked")
7125
7132
  })).optional().describe("Authors of this post"),
7126
7133
  "authorIds": zod.array(zod.string()).optional().describe("IDs of the authors of this post"),
7127
- "views": zod.number().optional().describe("Total page views. Only included when fetching your own posts via GET /v1/posts")
7134
+ "views": zod.number().optional().describe("Total page views. Only included when fetching your own posts via GET /v1/posts"),
7135
+ "status": zod.enum(["published", "draft", "scheduled", "archived"]).optional().describe("Current publish status. Only set on authenticated endpoints (listOwn, getById for your own post). Use this instead of publishedAt to determine publish state \u2014 publishedAt is preserved across unpublishing.")
7128
7136
  })).describe("Array of items in this page"),
7129
7137
  "pagination": zod.object({
7130
7138
  "cursor": zod.string().optional().describe("Cursor for fetching the next page of results"),
@@ -7170,7 +7178,8 @@ var init_zod = __esm({
7170
7178
  }).optional().describe("Farcaster profile information, if linked")
7171
7179
  })).optional().describe("Authors of this post"),
7172
7180
  "authorIds": zod.array(zod.string()).optional().describe("IDs of the authors of this post"),
7173
- "views": zod.number().optional().describe("Total page views. Only included when fetching your own posts via GET /v1/posts")
7181
+ "views": zod.number().optional().describe("Total page views. Only included when fetching your own posts via GET /v1/posts"),
7182
+ "status": zod.enum(["published", "draft", "scheduled", "archived"]).optional().describe("Current publish status. Only set on authenticated endpoints (listOwn, getById for your own post). Use this instead of publishedAt to determine publish state \u2014 publishedAt is preserved across unpublishing.")
7174
7183
  });
7175
7184
  updatePostParams = zod.object({
7176
7185
  "postId": zod.string().describe("Unique identifier of the post to update")
@@ -7241,7 +7250,8 @@ var init_zod = __esm({
7241
7250
  }).optional().describe("Farcaster profile information, if linked")
7242
7251
  })).optional().describe("Authors of this post"),
7243
7252
  "authorIds": zod.array(zod.string()).optional().describe("IDs of the authors of this post"),
7244
- "views": zod.number().optional().describe("Total page views. Only included when fetching your own posts via GET /v1/posts")
7253
+ "views": zod.number().optional().describe("Total page views. Only included when fetching your own posts via GET /v1/posts"),
7254
+ "status": zod.enum(["published", "draft", "scheduled", "archived"]).optional().describe("Current publish status. Only set on authenticated endpoints (listOwn, getById for your own post). Use this instead of publishedAt to determine publish state \u2014 publishedAt is preserved across unpublishing.")
7245
7255
  });
7246
7256
  getPostByPublicationSlugAndPostSlugPathPublicationSlugMax = 256;
7247
7257
  getPostByPublicationSlugAndPostSlugPathPostSlugMax = 256;
@@ -7284,7 +7294,8 @@ var init_zod = __esm({
7284
7294
  }).optional().describe("Farcaster profile information, if linked")
7285
7295
  })).optional().describe("Authors of this post"),
7286
7296
  "authorIds": zod.array(zod.string()).optional().describe("IDs of the authors of this post"),
7287
- "views": zod.number().optional().describe("Total page views. Only included when fetching your own posts via GET /v1/posts")
7297
+ "views": zod.number().optional().describe("Total page views. Only included when fetching your own posts via GET /v1/posts"),
7298
+ "status": zod.enum(["published", "draft", "scheduled", "archived"]).optional().describe("Current publish status. Only set on authenticated endpoints (listOwn, getById for your own post). Use this instead of publishedAt to determine publish state \u2014 publishedAt is preserved across unpublishing.")
7288
7299
  });
7289
7300
  createPostBodyTitleMax = 200;
7290
7301
  createPostBodySubtitleMax = 300;
@@ -7348,7 +7359,8 @@ var init_zod = __esm({
7348
7359
  }).optional().describe("Farcaster profile information, if linked")
7349
7360
  })).optional().describe("Authors of this post"),
7350
7361
  "authorIds": zod.array(zod.string()).optional().describe("IDs of the authors of this post"),
7351
- "views": zod.number().optional().describe("Total page views. Only included when fetching your own posts via GET /v1/posts")
7362
+ "views": zod.number().optional().describe("Total page views. Only included when fetching your own posts via GET /v1/posts"),
7363
+ "status": zod.enum(["published", "draft", "scheduled", "archived"]).optional().describe("Current publish status. Only set on authenticated endpoints (listOwn, getById for your own post). Use this instead of publishedAt to determine publish state \u2014 publishedAt is preserved across unpublishing.")
7352
7364
  })).describe("Array of items in this page"),
7353
7365
  "pagination": zod.object({
7354
7366
  "cursor": zod.string().optional().describe("Cursor for fetching the next page of results"),
@@ -7905,7 +7917,7 @@ async function resolveOwnPost(idOrSlug, apiKey) {
7905
7917
  const pub = await validateApiKey2(apiKey);
7906
7918
  const pubSlug = pub.slug;
7907
7919
  if (!pubSlug) {
7908
- throw new Error(`Post not found: ${idOrSlug}`);
7920
+ throw new Error(`Post not found: "${idOrSlug}". Run \`paragraph post list --json\` to see your posts, or use the full \`@publication/slug\` form for posts outside your publication.`);
7909
7921
  }
7910
7922
  return getPostBySlugs(pubSlug, idOrSlug, apiKey);
7911
7923
  }
@@ -7960,7 +7972,7 @@ async function updatePost(idOrSlug, params) {
7960
7972
  await client.posts.update({ id: idOrSlug, ...body });
7961
7973
  return;
7962
7974
  } catch {
7963
- if (!isSlug(idOrSlug)) throw new Error(`Post not found: ${idOrSlug}`);
7975
+ if (!isSlug(idOrSlug)) throw new Error(`Post not found: "${idOrSlug}". Run \`paragraph post list --json\` to see your posts, or use the full \`@publication/slug\` form for posts outside your publication.`);
7964
7976
  }
7965
7977
  await client.posts.update({ slug: idOrSlug, ...body });
7966
7978
  }
@@ -7974,7 +7986,7 @@ async function deletePost(idOrSlug, apiKey) {
7974
7986
  await client.posts.delete({ id: idOrSlug });
7975
7987
  return;
7976
7988
  } catch {
7977
- if (!isSlug(idOrSlug)) throw new Error(`Post not found: ${idOrSlug}`);
7989
+ if (!isSlug(idOrSlug)) throw new Error(`Post not found: "${idOrSlug}". Run \`paragraph post list --json\` to see your posts, or use the full \`@publication/slug\` form for posts outside your publication.`);
7978
7990
  }
7979
7991
  await client.posts.delete({ slug: idOrSlug });
7980
7992
  }
@@ -7985,7 +7997,7 @@ async function updatePostStatus(idOrSlug, status, apiKey, sendNewsletter) {
7985
7997
  await client.posts.update({ id: idOrSlug, ...body });
7986
7998
  return;
7987
7999
  } catch {
7988
- if (!isSlug(idOrSlug)) throw new Error(`Post not found: ${idOrSlug}`);
8000
+ if (!isSlug(idOrSlug)) throw new Error(`Post not found: "${idOrSlug}". Run \`paragraph post list --json\` to see your posts, or use the full \`@publication/slug\` form for posts outside your publication.`);
7989
8001
  }
7990
8002
  await client.posts.update({ slug: idOrSlug, ...body });
7991
8003
  }
@@ -7999,7 +8011,7 @@ async function schedulePost(idOrSlug, scheduledAt, apiKey, sendNewsletter) {
7999
8011
  await client.posts.update({ id: idOrSlug, ...body });
8000
8012
  return;
8001
8013
  } catch {
8002
- if (!isSlug(idOrSlug)) throw new Error(`Post not found: ${idOrSlug}`);
8014
+ if (!isSlug(idOrSlug)) throw new Error(`Post not found: "${idOrSlug}". Run \`paragraph post list --json\` to see your posts, or use the full \`@publication/slug\` form for posts outside your publication.`);
8003
8015
  }
8004
8016
  await client.posts.update({ slug: idOrSlug, ...body });
8005
8017
  }
@@ -8010,7 +8022,7 @@ async function cancelSchedule(idOrSlug, apiKey) {
8010
8022
  await client.posts.update({ id: idOrSlug, ...body });
8011
8023
  return;
8012
8024
  } catch {
8013
- if (!isSlug(idOrSlug)) throw new Error(`Post not found: ${idOrSlug}`);
8025
+ if (!isSlug(idOrSlug)) throw new Error(`Post not found: "${idOrSlug}". Run \`paragraph post list --json\` to see your posts, or use the full \`@publication/slug\` form for posts outside your publication.`);
8014
8026
  }
8015
8027
  await client.posts.update({ slug: idOrSlug, ...body });
8016
8028
  }
@@ -8086,7 +8098,7 @@ var init_prompt = __esm({
8086
8098
  // src/cli/lib/args.ts
8087
8099
  function requireArg(positional, flag, name, flagName = "--id") {
8088
8100
  if (positional && flag && positional !== flag) {
8089
- throw new Error(`Conflicting values for ${name}: "${positional}" (argument) vs "${flag}" (${flagName}).`);
8101
+ throw new Error(`Conflicting values for ${name}: "${positional}" (argument) vs "${flag}" (${flagName}). Pass only one.`);
8090
8102
  }
8091
8103
  const value = positional || flag;
8092
8104
  if (!value) throw new Error(`Missing ${name}. Pass it as an argument or with ${flagName}.`);
@@ -8122,7 +8134,7 @@ async function resolveMarkdown(opts) {
8122
8134
  if (opts.text) return opts.text;
8123
8135
  if (opts.file) {
8124
8136
  if (!fs2.existsSync(opts.file)) {
8125
- throw new Error(`File not found: ${opts.file}`);
8137
+ throw new Error(`File not found: "${opts.file}". Check the path, or use --text <markdown> to pass content inline.`);
8126
8138
  }
8127
8139
  return fs2.readFileSync(opts.file, "utf-8");
8128
8140
  }
@@ -8192,10 +8204,11 @@ Examples:
8192
8204
  limit: parseLimit(opts.limit),
8193
8205
  cursor: opts.cursor
8194
8206
  });
8195
- const headers = ["ID", "Title", "Date"];
8207
+ const headers = ["ID", "Title", "Status", "Date"];
8196
8208
  const rows = result.items.map((p) => [
8197
8209
  p.id,
8198
8210
  p.title,
8211
+ p.status ?? "\u2014",
8199
8212
  formatDate(p)
8200
8213
  ]);
8201
8214
  outputTable(this, headers, rows, result.items, { cursor: result.cursor });
@@ -8234,6 +8247,7 @@ Examples:
8234
8247
  Title: data.title,
8235
8248
  Subtitle: data.subtitle,
8236
8249
  Slug: data.slug,
8250
+ Status: data.status ?? "\u2014",
8237
8251
  Date: formatDate(data),
8238
8252
  Content: preview
8239
8253
  },
@@ -8635,6 +8649,16 @@ async function listSubscribers(apiKey, pagination) {
8635
8649
  }
8636
8650
  async function getSubscriberCount(publicationId) {
8637
8651
  const client = createClient();
8652
+ try {
8653
+ await client.publications.get({ id: publicationId }).single();
8654
+ } catch (err) {
8655
+ if (err instanceof ParagraphApiError && err.status === 404) {
8656
+ throw new Error(
8657
+ `Invalid publication ID "${publicationId}". Run \`paragraph whoami --json\` to get the valid publication ID.`
8658
+ );
8659
+ }
8660
+ throw err;
8661
+ }
8638
8662
  const result = await client.subscribers.getCount({ id: publicationId });
8639
8663
  return result.count || 0;
8640
8664
  }
@@ -8653,6 +8677,7 @@ var init_subscribers = __esm({
8653
8677
  "src/services/subscribers.ts"() {
8654
8678
  "use strict";
8655
8679
  init_zod();
8680
+ init_dist();
8656
8681
  init_client();
8657
8682
  }
8658
8683
  });
@@ -8696,7 +8721,17 @@ Examples:
8696
8721
  $ paragraph subscriber count --publication abc123
8697
8722
  $ paragraph subscriber count abc123 --json`).action(async function(positionalId, opts) {
8698
8723
  try {
8699
- const id = requireArg(positionalId, opts.publication, "publication ID", "--publication");
8724
+ const id = positionalId || opts.publication;
8725
+ if (!id) {
8726
+ throw new Error(
8727
+ "Missing publication ID. Run `paragraph whoami --json` to get the publication ID, then pass it as an argument or with --publication."
8728
+ );
8729
+ }
8730
+ if (positionalId && opts.publication && positionalId !== opts.publication) {
8731
+ throw new Error(
8732
+ `Conflicting values for publication ID: "${positionalId}" (argument) vs "${opts.publication}" (--publication).`
8733
+ );
8734
+ }
8700
8735
  const count = await getSubscriberCount(id);
8701
8736
  outputData(this, { Count: count }, { count });
8702
8737
  } catch (err) {
@@ -8963,7 +8998,7 @@ var init_user = __esm({
8963
8998
  // src/cli/program.ts
8964
8999
  function createProgram() {
8965
9000
  const program2 = new Command();
8966
- program2.name("paragraph").description("CLI for Paragraph").version("0.1.0", "-v, --version").option("--json", "Output as JSON").option("--verbose", "Show detailed output for debugging").exitOverride().configureOutput({
9001
+ program2.name("paragraph").description("CLI for Paragraph").version("0.1.1", "-v, --version").option("--json", "Output as JSON").option("--verbose", "Show detailed output for debugging").exitOverride().configureOutput({
8967
9002
  writeOut: (str) => process.stdout.write(str),
8968
9003
  writeErr: (str) => {
8969
9004
  if (process.argv.includes("--json")) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@paragraph-com/cli",
3
- "version": "0.1.0",
3
+ "version": "0.1.1",
4
4
  "type": "module",
5
5
  "description": "CLI for Paragraph",
6
6
  "repository": {
@@ -43,13 +43,13 @@
43
43
  },
44
44
  "dependencies": {
45
45
  "@inkjs/ui": "^2.0.0",
46
- "@paragraph-com/sdk": "^2.0.0",
47
- "zod": "^3.24.0",
46
+ "@paragraph-com/sdk": "^2.0.1",
48
47
  "cli-table3": "^0.6.5",
49
48
  "commander": "^12.0.0",
50
49
  "ink": "^5.1.0",
51
50
  "picocolors": "^1.1.0",
52
- "react": "^18.3.1"
51
+ "react": "^18.3.1",
52
+ "zod": "^3.24.0"
53
53
  },
54
54
  "devDependencies": {
55
55
  "@types/node": "^20.0.0",