pubblue 0.1.1 → 0.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.
Files changed (2) hide show
  1. package/dist/index.js +62 -51
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -7,7 +7,7 @@ import { createInterface } from "readline/promises";
7
7
  import { Command } from "commander";
8
8
 
9
9
  // src/lib/api.ts
10
- var PublishApiClient = class {
10
+ var PubApiClient = class {
11
11
  constructor(baseUrl, apiKey) {
12
12
  this.baseUrl = baseUrl;
13
13
  this.apiKey = apiKey;
@@ -28,14 +28,14 @@ var PublishApiClient = class {
28
28
  }
29
29
  return data;
30
30
  }
31
- async publish(opts) {
32
- return this.request("/api/v1/publish", {
31
+ async create(opts) {
32
+ return this.request("/api/v1/publications", {
33
33
  method: "POST",
34
34
  body: JSON.stringify(opts)
35
35
  });
36
36
  }
37
37
  async get(slug) {
38
- const data = await this.request(`/api/v1/publications?slug=${encodeURIComponent(slug)}`);
38
+ const data = await this.request(`/api/v1/publications/${encodeURIComponent(slug)}`);
39
39
  return data.publication;
40
40
  }
41
41
  async list() {
@@ -43,13 +43,14 @@ var PublishApiClient = class {
43
43
  return data.publications;
44
44
  }
45
45
  async update(opts) {
46
- return this.request("/api/v1/publications", {
46
+ const { slug, ...body } = opts;
47
+ return this.request(`/api/v1/publications/${encodeURIComponent(slug)}`, {
47
48
  method: "PATCH",
48
- body: JSON.stringify(opts)
49
+ body: JSON.stringify(body)
49
50
  });
50
51
  }
51
52
  async remove(slug) {
52
- await this.request(`/api/v1/publications?slug=${encodeURIComponent(slug)}`, {
53
+ await this.request(`/api/v1/publications/${encodeURIComponent(slug)}`, {
53
54
  method: "DELETE"
54
55
  });
55
56
  }
@@ -113,7 +114,7 @@ function getConfig(homeDir) {
113
114
  var program = new Command();
114
115
  function createClient() {
115
116
  const config = getConfig();
116
- return new PublishApiClient(config.baseUrl, config.apiKey);
117
+ return new PubApiClient(config.baseUrl, config.apiKey);
117
118
  }
118
119
  async function readFromStdin() {
119
120
  const chunks = [];
@@ -122,10 +123,6 @@ async function readFromStdin() {
122
123
  }
123
124
  return Buffer.concat(chunks).toString("utf-8").trim();
124
125
  }
125
- function printPublishResult(result) {
126
- const verb = result.updated ? "Updated" : "Published";
127
- console.log(`${verb}: ${result.url}`);
128
- }
129
126
  function formatVisibility(isPublic) {
130
127
  return isPublic ? "public" : "private";
131
128
  }
@@ -160,7 +157,18 @@ async function resolveConfigureApiKey(opts) {
160
157
  }
161
158
  return readApiKeyFromPrompt();
162
159
  }
163
- program.name("pubblue").description("Publish static content and get shareable URLs").version("0.1.0");
160
+ function readFile(filePath) {
161
+ const resolved = path2.resolve(filePath);
162
+ if (!fs2.existsSync(resolved)) {
163
+ console.error(`File not found: ${resolved}`);
164
+ process.exit(1);
165
+ }
166
+ return {
167
+ content: fs2.readFileSync(resolved, "utf-8"),
168
+ basename: path2.basename(resolved)
169
+ };
170
+ }
171
+ program.name("pubblue").description("Publish static content and get shareable URLs").version("0.2.0");
164
172
  program.command("configure").description("Configure the CLI with your API key").option("--api-key <key>", "Your API key (less secure: appears in shell history)").option("--api-key-stdin", "Read API key from stdin").action(async (opts) => {
165
173
  try {
166
174
  const apiKey = await resolveConfigureApiKey(opts);
@@ -172,43 +180,37 @@ program.command("configure").description("Configure the CLI with your API key").
172
180
  process.exit(1);
173
181
  }
174
182
  });
175
- program.command("publish").description("Publish a file").argument("<file>", "Path to the file to publish").option("--slug <slug>", "Custom slug for the URL").option("--title <title>", "Title for the publication").option("--private", "Make the publication private").action(async (file, opts) => {
176
- const client = createClient();
177
- const filePath = path2.resolve(file);
178
- if (!fs2.existsSync(filePath)) {
179
- console.error(`File not found: ${filePath}`);
180
- process.exit(1);
181
- }
182
- const content = fs2.readFileSync(filePath, "utf-8");
183
- const filename = path2.basename(filePath);
184
- const result = await client.publish({
185
- filename,
186
- content,
187
- title: opts.title,
188
- slug: opts.slug,
189
- isPublic: !opts.private
190
- });
191
- printPublishResult(result);
192
- });
193
- program.command("publish-content").description("Publish content directly from stdin or argument").requiredOption("--filename <name>", "Filename (determines content type, e.g. page.html)").option("--content <content>", "Content string (if not provided, reads from stdin)").option("--slug <slug>", "Custom slug for the URL").option("--title <title>", "Title for the publication").option("--private", "Make the publication private").action(
194
- async (opts) => {
183
+ program.command("create").description("Create a new publication").argument("[file]", "Path to the file (reads stdin if omitted)").option("--slug <slug>", "Custom slug for the URL").option("--title <title>", "Title for the publication").option("--public", "Make the publication public (default: private)").option("--private", "Make the publication private (this is the default)").action(
184
+ async (fileArg, opts) => {
195
185
  const client = createClient();
196
- const content = opts.content ?? await readFromStdin();
197
- const result = await client.publish({
198
- filename: opts.filename,
186
+ const filePath = fileArg;
187
+ let content;
188
+ let filename;
189
+ if (filePath) {
190
+ const file = readFile(filePath);
191
+ content = file.content;
192
+ filename = file.basename;
193
+ } else {
194
+ content = await readFromStdin();
195
+ }
196
+ const result = await client.create({
199
197
  content,
198
+ filename,
200
199
  title: opts.title,
201
200
  slug: opts.slug,
202
- isPublic: !opts.private
201
+ isPublic: opts.public ?? false
203
202
  });
204
- printPublishResult(result);
203
+ console.log(`Created: ${result.url}`);
205
204
  }
206
205
  );
207
- program.command("get").description("Get details of a publication").argument("<slug>", "Slug of the publication").action(async (slug) => {
206
+ program.command("get").description("Get details of a publication").argument("<slug>", "Slug of the publication").option("--content", "Output raw content to stdout (no metadata, pipeable)").action(async (slug, opts) => {
208
207
  const client = createClient();
209
208
  const pub = await client.get(slug);
209
+ if (opts.content) {
210
+ process.stdout.write(pub.content);
211
+ return;
212
+ }
210
213
  console.log(` Slug: ${pub.slug}`);
211
- console.log(` File: ${pub.filename}`);
212
214
  console.log(` Type: ${pub.contentType}`);
213
215
  if (pub.title) console.log(` Title: ${pub.title}`);
214
216
  console.log(` Status: ${formatVisibility(pub.isPublic)}`);
@@ -216,16 +218,25 @@ program.command("get").description("Get details of a publication").argument("<sl
216
218
  console.log(` Updated: ${new Date(pub.updatedAt).toLocaleDateString()}`);
217
219
  console.log(` Size: ${pub.content.length} bytes`);
218
220
  });
219
- program.command("update").description("Update publication metadata").argument("<slug>", "Slug of the publication to update").option("--title <title>", "New title").option("--public", "Make the publication public").option("--private", "Make the publication private").action(async (slug, opts) => {
220
- const client = createClient();
221
- let isPublic;
222
- if (opts.public) isPublic = true;
223
- else if (opts.private) isPublic = false;
224
- const result = await client.update({ slug, title: opts.title, isPublic });
225
- console.log(`Updated: ${result.slug}`);
226
- if (result.title) console.log(` Title: ${result.title}`);
227
- console.log(` Status: ${formatVisibility(result.isPublic)}`);
228
- });
221
+ program.command("update").description("Update a publication's content and/or metadata").argument("<slug>", "Slug of the publication to update").option("--file <file>", "New content from file").option("--title <title>", "New title").option("--public", "Make the publication public").option("--private", "Make the publication private").action(
222
+ async (slug, opts) => {
223
+ const client = createClient();
224
+ let content;
225
+ let filename;
226
+ if (opts.file) {
227
+ const file = readFile(opts.file);
228
+ content = file.content;
229
+ filename = file.basename;
230
+ }
231
+ let isPublic;
232
+ if (opts.public) isPublic = true;
233
+ else if (opts.private) isPublic = false;
234
+ const result = await client.update({ slug, content, filename, title: opts.title, isPublic });
235
+ console.log(`Updated: ${result.slug}`);
236
+ if (result.title) console.log(` Title: ${result.title}`);
237
+ console.log(` Status: ${formatVisibility(result.isPublic)}`);
238
+ }
239
+ );
229
240
  program.command("list").description("List your publications").action(async () => {
230
241
  const client = createClient();
231
242
  const pubs = await client.list();
@@ -236,7 +247,7 @@ program.command("list").description("List your publications").action(async () =>
236
247
  for (const pub of pubs) {
237
248
  const date = new Date(pub.createdAt).toLocaleDateString();
238
249
  console.log(
239
- ` ${pub.slug} ${pub.filename} [${pub.contentType}] ${formatVisibility(pub.isPublic)} ${date}`
250
+ ` ${pub.slug} [${pub.contentType}] ${formatVisibility(pub.isPublic)} ${date}`
240
251
  );
241
252
  }
242
253
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pubblue",
3
- "version": "0.1.1",
3
+ "version": "0.2.0",
4
4
  "description": "CLI tool for publishing static content via pub.blue",
5
5
  "type": "module",
6
6
  "bin": {