jotview 0.1.0 → 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.
package/README.md CHANGED
@@ -24,6 +24,7 @@ jotview read markdown from stdin
24
24
 
25
25
  --raw never shorten; always the full /d URL
26
26
  --short always shorten, even when small
27
+ --keep make a shortened link permanent
27
28
  --open open the link in your browser
28
29
  --copy copy the link to your clipboard
29
30
  --base-url <url> override https://jotbins.com
@@ -51,6 +52,7 @@ jotview tells you on stderr when that happens:
51
52
 
52
53
  ```
53
54
  note: uploaded to jotbins to shorten (8768 → 30 chars). use --raw to keep it local.
55
+ note: short link expires after 30 days unused. use --keep to keep it forever.
54
56
  ```
55
57
 
56
58
  **Shortening uploads your document.** The fragment *is* the markdown, so storing
@@ -58,6 +60,12 @@ the URL stores the text. Below the threshold nothing is uploaded and no network
58
60
  request is made at all. Use `--raw` to keep a long document local, accepting a
59
61
  URL too long to paste into most places.
60
62
 
63
+ **Short links clean up after themselves.** One nobody opens for 30 days is
64
+ deleted, with a 60-day window to bring it back from its waiting page. Pass
65
+ `--keep` to make it permanent from the start, or click **Save link** on the
66
+ waiting page any time before then. Full `/d` links are never stored, so they
67
+ never expire.
68
+
61
69
  If the shortener is unreachable or rate-limited, jotview prints the full link
62
70
  and exits 0 — it never fails your pipeline over a shortening problem.
63
71
 
package/package.json CHANGED
@@ -1,15 +1,36 @@
1
1
  {
2
2
  "name": "jotview",
3
- "version": "0.1.0",
3
+ "version": "0.2.0",
4
4
  "description": "Turn a markdown file into a jotbins /d link. Zero dependencies.",
5
5
  "type": "module",
6
- "bin": { "jotview": "bin/jotview.js" },
7
- "files": ["bin", "src", "vectors.json", "README.md"],
8
- "engines": { "node": ">=18" },
9
- "scripts": { "test": "node --test" },
10
- "keywords": ["markdown", "jotbins", "cli", "share"],
6
+ "bin": {
7
+ "jotview": "bin/jotview.js"
8
+ },
9
+ "files": [
10
+ "bin",
11
+ "src",
12
+ "vectors.json",
13
+ "README.md"
14
+ ],
15
+ "engines": {
16
+ "node": ">=18"
17
+ },
18
+ "scripts": {
19
+ "test": "node --test"
20
+ },
21
+ "keywords": [
22
+ "markdown",
23
+ "jotbins",
24
+ "cli",
25
+ "share"
26
+ ],
11
27
  "license": "MIT",
12
- "repository": { "type": "git", "url": "git+https://github.com/jotbins/jotview.git" },
28
+ "repository": {
29
+ "type": "git",
30
+ "url": "git+https://github.com/jotbins/jotview.git"
31
+ },
13
32
  "homepage": "https://github.com/jotbins/jotview#readme",
14
- "bugs": { "url": "https://github.com/jotbins/jotview/issues" }
33
+ "bugs": {
34
+ "url": "https://github.com/jotbins/jotview/issues"
35
+ }
15
36
  }
package/src/cli.js CHANGED
@@ -19,6 +19,7 @@ Usage:
19
19
  Options:
20
20
  --raw never shorten; always the full /d URL
21
21
  --short always shorten, even when small
22
+ --keep make a shortened link permanent
22
23
  --open open the link in your browser
23
24
  --copy copy the link to your clipboard
24
25
  --base-url <url> override ${DEFAULT_BASE_URL}
@@ -28,6 +29,9 @@ Options:
28
29
  Links 2000 characters or fewer are printed as-is and never leave your machine.
29
30
  Longer ones are shortened via surl.jotbins.com, which uploads the document.
30
31
  Use --raw to keep it local regardless of size.
32
+
33
+ Short links are deleted after 30 days unused, unless made with --keep or
34
+ saved from the link's waiting page. Full /d links never expire.
31
35
  `;
32
36
 
33
37
  /**
@@ -35,6 +39,7 @@ Use --raw to keep it local regardless of size.
35
39
  * @property {string|null} file
36
40
  * @property {boolean} raw
37
41
  * @property {boolean} short
42
+ * @property {boolean} keep
38
43
  * @property {boolean} open
39
44
  * @property {boolean} copy
40
45
  * @property {string} baseUrl
@@ -49,7 +54,7 @@ Use --raw to keep it local regardless of size.
49
54
  export function parseArgs(argv) {
50
55
  /** @type {Options} */
51
56
  const opts = {
52
- file: null, raw: false, short: false, open: false, copy: false,
57
+ file: null, raw: false, short: false, keep: false, open: false, copy: false,
53
58
  baseUrl: DEFAULT_BASE_URL, help: false, version: false,
54
59
  };
55
60
  for (let i = 0; i < argv.length; i++) {
@@ -57,6 +62,7 @@ export function parseArgs(argv) {
57
62
  switch (arg) {
58
63
  case "--raw": opts.raw = true; break;
59
64
  case "--short": opts.short = true; break;
65
+ case "--keep": opts.keep = true; break;
60
66
  case "--open": opts.open = true; break;
61
67
  case "--copy": opts.copy = true; break;
62
68
  case "-h": case "--help": opts.help = true; break;
@@ -83,6 +89,9 @@ export function parseArgs(argv) {
83
89
  if (opts.raw && opts.short) {
84
90
  throw new JotviewError("usage", "--raw and --short cannot be combined");
85
91
  }
92
+ if (opts.raw && opts.keep) {
93
+ throw new JotviewError("usage", "--keep has no effect with --raw: full links never expire");
94
+ }
86
95
  if (opts.short && opts.baseUrl !== DEFAULT_BASE_URL) {
87
96
  throw new JotviewError("usage", `--short only works with ${DEFAULT_BASE_URL}`);
88
97
  }
@@ -190,7 +199,7 @@ export async function run(argv, io) {
190
199
  return 0;
191
200
  }
192
201
 
193
- const result = await shorten(rawUrl);
202
+ const result = await shorten(rawUrl, { permanent: opts.keep });
194
203
  let printed = rawUrl;
195
204
  if (result.ok) {
196
205
  printed = result.short;
@@ -198,6 +207,11 @@ export async function run(argv, io) {
198
207
  `note: uploaded to jotbins to shorten (${rawUrl.length} → ` +
199
208
  `${printed.length} chars). use --raw to keep it local.\n`,
200
209
  );
210
+ io.stderr(
211
+ opts.keep
212
+ ? "note: short link kept forever.\n"
213
+ : "note: short link expires after 30 days unused. use --keep to keep it forever.\n",
214
+ );
201
215
  } else {
202
216
  io.stderr(
203
217
  `note: upload to the shortener failed (${result.reason}); using the full ` +
package/src/shorten.js CHANGED
@@ -28,7 +28,9 @@ export function shouldShorten(url, opts) {
28
28
  /**
29
29
  * Shorten a URL. Never throws — the caller falls back to the raw URL.
30
30
  * @param {string} url
31
- * @param {{endpoint?: string}} [options]
31
+ * @param {{endpoint?: string, permanent?: boolean}} [options]
32
+ * `permanent` asks surl for a link that never expires. Left out of the body
33
+ * when false, so the request matches what older surl versions expect.
32
34
  * @returns {Promise<{ok: true, short: string} | {ok: false, reason: string}>}
33
35
  */
34
36
  export async function shorten(url, options = {}) {
@@ -37,7 +39,7 @@ export async function shorten(url, options = {}) {
37
39
  const response = await fetch(endpoint, {
38
40
  method: "POST",
39
41
  headers: { "content-type": "application/json" },
40
- body: JSON.stringify({ url }),
42
+ body: JSON.stringify(options.permanent ? { url, permanent: true } : { url }),
41
43
  signal: AbortSignal.timeout(TIMEOUT_MS),
42
44
  });
43
45
  if (!response.ok) {