htmlship 0.1.1 → 0.1.3

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/cli.js +53 -53
  2. package/package.json +3 -3
package/dist/cli.js CHANGED
@@ -56,7 +56,7 @@ var VERSION;
56
56
  var init_version = __esm({
57
57
  "src/version.ts"() {
58
58
  "use strict";
59
- VERSION = "0.1.1";
59
+ VERSION = "0.1.3";
60
60
  }
61
61
  });
62
62
 
@@ -90,24 +90,24 @@ var init_client = __esm({
90
90
  if (options.password != null) body["password"] = options.password;
91
91
  if (options.expiresIn != null) body["expires_in"] = options.expiresIn;
92
92
  if (options.parentSlug != null) body["parent_slug"] = options.parentSlug;
93
- return await this.request("POST", "/api/v1/pastes", { body });
93
+ return await this.request("POST", "/api/v1/pages", { body });
94
94
  }
95
95
  async get(slug) {
96
- return await this.request("GET", `/api/v1/pastes/${encodeURIComponent(slug)}`);
96
+ return await this.request("GET", `/api/v1/pages/${encodeURIComponent(slug)}`);
97
97
  }
98
98
  async update(slug, html, ownerKey, options = {}) {
99
99
  const body = { html };
100
100
  if (options.title != null) body["title"] = options.title;
101
101
  return await this.request(
102
102
  "PATCH",
103
- `/api/v1/pastes/${encodeURIComponent(slug)}`,
103
+ `/api/v1/pages/${encodeURIComponent(slug)}`,
104
104
  { body, headers: { "X-Owner-Key": ownerKey } }
105
105
  );
106
106
  }
107
107
  async delete(slug, ownerKey) {
108
108
  await this.request(
109
109
  "DELETE",
110
- `/api/v1/pastes/${encodeURIComponent(slug)}`,
110
+ `/api/v1/pages/${encodeURIComponent(slug)}`,
111
111
  { headers: { "X-Owner-Key": ownerKey }, expectNoBody: true }
112
112
  );
113
113
  }
@@ -121,7 +121,7 @@ var init_client = __esm({
121
121
  if (options.expiresIn != null) body["expires_in"] = options.expiresIn;
122
122
  return await this.request(
123
123
  "POST",
124
- `/api/v1/pastes/${encodeURIComponent(parentSlug)}/version`,
124
+ `/api/v1/pages/${encodeURIComponent(parentSlug)}/version`,
125
125
  { body }
126
126
  );
127
127
  }
@@ -178,7 +178,7 @@ var init_client = __esm({
178
178
  }
179
179
  return text;
180
180
  } catch {
181
- return text;
181
+ return `HTTP ${response.status}`;
182
182
  }
183
183
  } catch {
184
184
  return `HTTP ${response.status}`;
@@ -203,18 +203,18 @@ function buildMcpServer(client) {
203
203
  server.registerTool(
204
204
  "publish_html",
205
205
  {
206
- description: "Publish an HTML document and get a public URL. The owner_key returned is the only credential to update or delete this paste later \u2014 save it.",
206
+ description: "Publish an HTML document and get a public URL. The owner_key returned is the only credential to update or delete this page later \u2014 save it.",
207
207
  inputSchema: {
208
208
  html: z.string().describe("The HTML body to publish."),
209
209
  title: z.string().optional().describe("Optional human-readable title."),
210
- expires_in_seconds: z.number().int().positive().optional().describe("Optional TTL in seconds.")
210
+ expires_in: z.number().int().min(1).max(60 * 24 * 7).optional().describe("Optional TTL in minutes (1\u201310080, i.e. up to 7 days).")
211
211
  }
212
212
  },
213
- async ({ html, title, expires_in_seconds }) => {
213
+ async ({ html, title, expires_in }) => {
214
214
  try {
215
- const paste = await c.publish(html, {
215
+ const page = await c.publish(html, {
216
216
  title: title ?? null,
217
- expiresIn: expires_in_seconds ?? null
217
+ expiresIn: expires_in ?? null
218
218
  });
219
219
  return {
220
220
  content: [
@@ -222,10 +222,10 @@ function buildMcpServer(client) {
222
222
  type: "text",
223
223
  text: JSON.stringify(
224
224
  {
225
- url: paste.url,
226
- slug: paste.slug,
227
- owner_key: paste.owner_key,
228
- expires_at: paste.expires_at
225
+ url: page.url,
226
+ slug: page.slug,
227
+ owner_key: page.owner_key,
228
+ expires_at: page.expires_at
229
229
  },
230
230
  null,
231
231
  2
@@ -241,20 +241,20 @@ function buildMcpServer(client) {
241
241
  server.registerTool(
242
242
  "fetch_html",
243
243
  {
244
- description: "Fetch a paste's metadata. To view the rendered HTML, open the `url` in a browser \u2014 the content is served from a sandboxed subdomain.",
244
+ description: "Fetch a page's metadata. To view the rendered HTML, open the `url` in a browser \u2014 the content is served from a sandboxed subdomain.",
245
245
  inputSchema: {
246
- slug: z.string().describe("The paste's short identifier.")
246
+ slug: z.string().describe("The page's short identifier.")
247
247
  }
248
248
  },
249
249
  async ({ slug }) => {
250
250
  try {
251
- const paste = await c.get(slug);
251
+ const page = await c.get(slug);
252
252
  return {
253
- content: [{ type: "text", text: JSON.stringify(paste, null, 2) }]
253
+ content: [{ type: "text", text: JSON.stringify(page, null, 2) }]
254
254
  };
255
255
  } catch (err) {
256
256
  if (err instanceof NotFoundError) {
257
- return errorResult("fetch_html", new HTMLShipError(`paste '${slug}' not found`));
257
+ return errorResult("fetch_html", new HTMLShipError(`page '${slug}' not found`));
258
258
  }
259
259
  return errorResult("fetch_html", err);
260
260
  }
@@ -263,9 +263,9 @@ function buildMcpServer(client) {
263
263
  server.registerTool(
264
264
  "update_html",
265
265
  {
266
- description: "Replace the HTML for an existing paste. Requires the original owner_key.",
266
+ description: "Replace the HTML for an existing page. Requires the original owner_key.",
267
267
  inputSchema: {
268
- slug: z.string().describe("The paste's short identifier."),
268
+ slug: z.string().describe("The page's short identifier."),
269
269
  html: z.string().describe("The new HTML body."),
270
270
  owner_key: z.string().describe("The owner key returned at publish time."),
271
271
  title: z.string().optional().describe("Optional new title.")
@@ -273,13 +273,13 @@ function buildMcpServer(client) {
273
273
  },
274
274
  async ({ slug, html, owner_key, title }) => {
275
275
  try {
276
- const paste = await c.update(slug, html, owner_key, { title: title ?? null });
276
+ const page = await c.update(slug, html, owner_key, { title: title ?? null });
277
277
  return {
278
278
  content: [
279
279
  {
280
280
  type: "text",
281
281
  text: JSON.stringify(
282
- { url: paste.url, slug: paste.slug, updated_at: paste.updated_at },
282
+ { url: page.url, slug: page.slug, updated_at: page.updated_at },
283
283
  null,
284
284
  2
285
285
  )
@@ -386,7 +386,7 @@ function createKeyStore(overrideDir) {
386
386
 
387
387
  // src/commands/delete.ts
388
388
  function registerDelete(program) {
389
- program.command("delete").description("Soft-delete a paste.").argument("<slug>", "Paste slug").option("--owner-key <key>", "Owner key (defaults to local store)").option("-y, --yes", "Skip confirmation").action(async function(slug, opts) {
389
+ program.command("delete").description("Soft-delete a page.").argument("<slug>", "Page slug").option("--owner-key <key>", "Owner key (defaults to local store)").option("-y, --yes", "Skip confirmation").action(async function(slug, opts) {
390
390
  const keys = createKeyStore();
391
391
  const ownerKey = opts.ownerKey ?? keys.lookupOwnerKey(slug);
392
392
  if (!ownerKey) {
@@ -396,7 +396,7 @@ function registerDelete(program) {
396
396
  }
397
397
  if (!opts.yes) {
398
398
  const rl = createInterface({ input: process.stdin, output: process.stderr });
399
- const answer = await rl.question(`Delete paste '${slug}'? [y/N] `);
399
+ const answer = await rl.question(`Delete page '${slug}'? [y/N] `);
400
400
  rl.close();
401
401
  if (!/^y(es)?$/i.test(answer.trim())) {
402
402
  process.stderr.write("Aborted.\n");
@@ -416,16 +416,16 @@ function registerDelete(program) {
416
416
  init_client();
417
417
  init_errors();
418
418
  function registerGet(program) {
419
- program.command("get").description("Show metadata for a paste.").argument("<slug>", "Paste slug").action(async function(slug) {
419
+ program.command("get").description("Show metadata for a page.").argument("<slug>", "Page slug").action(async function(slug) {
420
420
  const apiUrl = this.parent?.opts()?.apiUrl;
421
421
  const client = new HTMLShipClient({ baseUrl: apiUrl });
422
422
  try {
423
- const paste = await client.get(slug);
424
- process.stdout.write(`${JSON.stringify(paste, null, 2)}
423
+ const page = await client.get(slug);
424
+ process.stdout.write(`${JSON.stringify(page, null, 2)}
425
425
  `);
426
426
  } catch (err) {
427
427
  if (err instanceof NotFoundError) {
428
- throw new HTMLShipError(`paste '${slug}' not found`);
428
+ throw new HTMLShipError(`page '${slug}' not found`);
429
429
  }
430
430
  throw err;
431
431
  }
@@ -436,12 +436,12 @@ function registerGet(program) {
436
436
  init_client();
437
437
  init_errors();
438
438
  function registerListMine(program) {
439
- program.command("list-mine").description("List pastes whose owner keys are saved locally.").option("--limit <n>", "max entries to show", "20").action(async function(opts) {
439
+ program.command("list-mine").description("List pages whose owner keys are saved locally.").option("--limit <n>", "max entries to show", "20").action(async function(opts) {
440
440
  const keys = createKeyStore();
441
441
  const data = keys.load();
442
442
  const entries = Object.entries(data);
443
443
  if (entries.length === 0) {
444
- process.stdout.write(`No saved pastes in ${keys.file}.
444
+ process.stdout.write(`No saved pages in ${keys.file}.
445
445
  `);
446
446
  return;
447
447
  }
@@ -452,13 +452,13 @@ function registerListMine(program) {
452
452
  const rows = await Promise.all(
453
453
  sorted.map(async ([slug, info]) => {
454
454
  try {
455
- const paste = await client.get(slug);
455
+ const page = await client.get(slug);
456
456
  return {
457
457
  slug,
458
458
  url: info.url,
459
- title: paste.title ?? info.title ?? "",
460
- size: `${paste.size_bytes}B`,
461
- views: String(paste.view_count),
459
+ title: page.title ?? info.title ?? "",
460
+ size: `${page.size_bytes}B`,
461
+ views: String(page.view_count),
462
462
  status: "ok"
463
463
  };
464
464
  } catch (err) {
@@ -530,13 +530,13 @@ async function tryClipboardCopy(text) {
530
530
 
531
531
  // src/commands/publish.ts
532
532
  function registerPublish(program) {
533
- program.command("publish").description("Publish an HTML document and get a URL.").argument("[source]", "file path, '-' for stdin (default: stdin if piped)").option("-f, --file <path>", "HTML file path").option("--title <title>", "Optional title").option("--password <password>", "Password-protect the paste").option("--expires-in <seconds>", "Seconds until expiry").option("--no-clipboard", "Don't copy URL to clipboard").option("-q, --quiet", "Print only the URL").action(async function(source, opts) {
533
+ program.command("publish").description("Publish an HTML document and get a URL.").argument("[source]", "file path, '-' for stdin (default: stdin if piped)").option("-f, --file <path>", "HTML file path").option("--title <title>", "Optional title").option("--password <password>", "Password-protect the page").option("--expires-in <minutes>", "Minutes until expiry (1\u201310080, i.e. up to 7 days)").option("--no-clipboard", "Don't copy URL to clipboard").option("-q, --quiet", "Print only the URL").action(async function(source, opts) {
534
534
  const html = readHtmlFromSource(source, opts.file);
535
535
  const apiUrl = this.parent?.opts()?.apiUrl;
536
536
  const client = new HTMLShipClient({ baseUrl: apiUrl });
537
- let paste;
537
+ let page;
538
538
  try {
539
- paste = await client.publish(html, {
539
+ page = await client.publish(html, {
540
540
  title: opts.title ?? null,
541
541
  password: opts.password ?? null,
542
542
  expiresIn: opts.expiresIn ? Number.parseInt(opts.expiresIn, 10) : null
@@ -545,28 +545,28 @@ function registerPublish(program) {
545
545
  throw new HTMLShipError(`publish failed: ${err.message}`);
546
546
  }
547
547
  const keys = createKeyStore();
548
- keys.remember(paste.slug, {
549
- owner_key: paste.owner_key,
550
- url: paste.url,
548
+ keys.remember(page.slug, {
549
+ owner_key: page.owner_key,
550
+ url: page.url,
551
551
  title: opts.title ?? null
552
552
  });
553
553
  if (opts.quiet) {
554
- process.stdout.write(`${paste.url}
554
+ process.stdout.write(`${page.url}
555
555
  `);
556
556
  return;
557
557
  }
558
- process.stdout.write(`${paste.url}
558
+ process.stdout.write(`${page.url}
559
559
  `);
560
- process.stderr.write(`slug: ${paste.slug}
560
+ process.stderr.write(`slug: ${page.slug}
561
561
  `);
562
- process.stderr.write(`owner_key: ${paste.owner_key} (saved to ${keys.file})
562
+ process.stderr.write(`owner_key: ${page.owner_key} (saved to ${keys.file})
563
563
  `);
564
- if (paste.expires_at) {
565
- process.stderr.write(`expires: ${paste.expires_at}
564
+ if (page.expires_at) {
565
+ process.stderr.write(`expires: ${page.expires_at}
566
566
  `);
567
567
  }
568
568
  if (opts.noClipboard !== true) {
569
- const copied = await tryClipboardCopy(paste.url);
569
+ const copied = await tryClipboardCopy(page.url);
570
570
  if (copied) process.stderr.write("(URL copied to clipboard)\n");
571
571
  }
572
572
  });
@@ -576,7 +576,7 @@ function registerPublish(program) {
576
576
  init_client();
577
577
  init_errors();
578
578
  function registerUpdate(program) {
579
- program.command("update").description("Replace HTML for an existing paste.").argument("<slug>", "Paste slug").argument("[source]", "file path, '-' for stdin").option("-f, --file <path>", "HTML file path").option("--title <title>", "Optional new title").option("--owner-key <key>", "Owner key (defaults to local store)").action(async function(slug, source, opts) {
579
+ program.command("update").description("Replace HTML for an existing page.").argument("<slug>", "Page slug").argument("[source]", "file path, '-' for stdin").option("-f, --file <path>", "HTML file path").option("--title <title>", "Optional new title").option("--owner-key <key>", "Owner key (defaults to local store)").action(async function(slug, source, opts) {
580
580
  const html = readHtmlFromSource(source, opts.file);
581
581
  const keys = createKeyStore();
582
582
  const ownerKey = opts.ownerKey ?? keys.lookupOwnerKey(slug);
@@ -587,8 +587,8 @@ function registerUpdate(program) {
587
587
  }
588
588
  const apiUrl = this.parent?.opts()?.apiUrl;
589
589
  const client = new HTMLShipClient({ baseUrl: apiUrl });
590
- const paste = await client.update(slug, html, ownerKey, { title: opts.title ?? null });
591
- process.stdout.write(`${paste.url}
590
+ const page = await client.update(slug, html, ownerKey, { title: opts.title ?? null });
591
+ process.stdout.write(`${page.url}
592
592
  `);
593
593
  });
594
594
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "htmlship",
3
- "version": "0.1.1",
3
+ "version": "0.1.3",
4
4
  "description": "Host and share HTML pages from LLMs and coding agents in one line. CLI + MCP server.",
5
5
  "keywords": [
6
6
  "html",
@@ -16,7 +16,7 @@
16
16
  "homepage": "https://htmlship.com",
17
17
  "repository": {
18
18
  "type": "git",
19
- "url": "https://github.com/htmlship/htmlship.git",
19
+ "url": "git+https://github.com/htmlship/htmlship.git",
20
20
  "directory": "npm"
21
21
  },
22
22
  "license": "MIT",
@@ -26,7 +26,7 @@
26
26
  "node": ">=18"
27
27
  },
28
28
  "bin": {
29
- "htmlship": "./dist/cli.js"
29
+ "htmlship": "dist/cli.js"
30
30
  },
31
31
  "files": [
32
32
  "dist",