@pipeup/share 0.5.1 → 0.5.2

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/dist/cli.js CHANGED
@@ -7,24 +7,24 @@ import { readFile, writeFile } from "node:fs/promises";
7
7
  var utf8 = (text2) => new TextEncoder().encode(text2);
8
8
  var text = (bytes) => new TextDecoder().decode(bytes);
9
9
  function toB64u(bytes) {
10
- let s = "";
11
- for (let i = 0; i < bytes.length; i += 32768) s += String.fromCharCode(...bytes.subarray(i, i + 32768));
12
- return btoa(s).replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
10
+ let s2 = "";
11
+ for (let i = 0; i < bytes.length; i += 32768) s2 += String.fromCharCode(...bytes.subarray(i, i + 32768));
12
+ return btoa(s2).replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
13
13
  }
14
- function fromB64u(s) {
15
- const std = s.replace(/-/g, "+").replace(/_/g, "/");
14
+ function fromB64u(s2) {
15
+ const std = s2.replace(/-/g, "+").replace(/_/g, "/");
16
16
  const bin = atob(std + "=".repeat((4 - std.length % 4) % 4));
17
- return Uint8Array.from(bin, (c) => c.charCodeAt(0));
17
+ return Uint8Array.from(bin, (c2) => c2.charCodeAt(0));
18
18
  }
19
19
  function toB64(bytes) {
20
- let s = "";
21
- for (let i = 0; i < bytes.length; i += 32768) s += String.fromCharCode(...bytes.subarray(i, i + 32768));
22
- return btoa(s);
20
+ let s2 = "";
21
+ for (let i = 0; i < bytes.length; i += 32768) s2 += String.fromCharCode(...bytes.subarray(i, i + 32768));
22
+ return btoa(s2);
23
23
  }
24
- function fromB64(s) {
25
- return Uint8Array.from(atob(s), (c) => c.charCodeAt(0));
24
+ function fromB64(s2) {
25
+ return Uint8Array.from(atob(s2), (c2) => c2.charCodeAt(0));
26
26
  }
27
- var randomBytes = (n) => crypto.getRandomValues(new Uint8Array(n));
27
+ var randomBytes = (n2) => crypto.getRandomValues(new Uint8Array(n2));
28
28
  async function sha256(data) {
29
29
  return new Uint8Array(await crypto.subtle.digest("SHA-256", data));
30
30
  }
@@ -70,19 +70,19 @@ async function pipe(data, t2, cap = Infinity) {
70
70
  }
71
71
  const out = new Uint8Array(total);
72
72
  let at = 0;
73
- for (const c of chunks2) {
74
- out.set(c, at);
75
- at += c.length;
73
+ for (const c2 of chunks2) {
74
+ out.set(c2, at);
75
+ at += c2.length;
76
76
  }
77
77
  return out;
78
78
  }
79
- var seal = (l, p2, ops) => sealJson(l, p2, { pipeup: 1, doc: l.docId, sealed: false, ops });
80
- async function sealJson(l, p2, value) {
79
+ var seal = (l2, p2, ops) => sealJson(l2, p2, { pipeup: 1, doc: l2.docId, sealed: false, ops });
80
+ async function sealJson(l2, p2, value) {
81
81
  const plain = utf8(JSON.stringify(value));
82
82
  const iv = randomBytes(12);
83
83
  const body = await crypto.subtle.encrypt(
84
- { name: "AES-GCM", iv, additionalData: utf8(l.aad(p2)) },
85
- await l.key(p2),
84
+ { name: "AES-GCM", iv, additionalData: utf8(l2.aad(p2)) },
85
+ await l2.key(p2),
86
86
  await pipe(plain, new CompressionStream("deflate-raw"))
87
87
  );
88
88
  const out = new Uint8Array(13 + body.byteLength);
@@ -91,12 +91,12 @@ async function sealJson(l, p2, value) {
91
91
  out.set(new Uint8Array(body), 13);
92
92
  return out;
93
93
  }
94
- async function openJson(l, p2, bytes) {
94
+ async function openJson(l2, p2, bytes) {
95
95
  try {
96
96
  if (bytes.length < 13 + 16 || bytes[0] !== 1) return null;
97
97
  const plain = await crypto.subtle.decrypt(
98
- { name: "AES-GCM", iv: bytes.slice(1, 13), additionalData: utf8(l.aad(p2)) },
99
- await l.key(p2),
98
+ { name: "AES-GCM", iv: bytes.slice(1, 13), additionalData: utf8(l2.aad(p2)) },
99
+ await l2.key(p2),
100
100
  bytes.slice(13)
101
101
  );
102
102
  return JSON.parse(
@@ -106,25 +106,25 @@ async function openJson(l, p2, bytes) {
106
106
  return null;
107
107
  }
108
108
  }
109
- function asBatch(l, value) {
109
+ function asBatch(l2, value) {
110
110
  const file = value;
111
- if (file?.pipeup !== 1 || file.doc !== l.docId || !Array.isArray(file.ops) || file.ops.length > MAX_OPS)
111
+ if (file?.pipeup !== 1 || file.doc !== l2.docId || !Array.isArray(file.ops) || file.ops.length > MAX_OPS)
112
112
  return null;
113
113
  let newer = 0;
114
114
  for (const op of file.ops) {
115
- const v = op?.body?.v;
116
- if (typeof v === "number" && v !== 1) newer++;
115
+ const v2 = op?.body?.v;
116
+ if (typeof v2 === "number" && v2 !== 1) newer++;
117
117
  }
118
118
  return { ops: file.ops, newer };
119
119
  }
120
- async function open(l, p2, bytes) {
121
- return asBatch(l, await openJson(l, p2, bytes));
120
+ async function open(l2, p2, bytes) {
121
+ return asBatch(l2, await openJson(l2, p2, bytes));
122
122
  }
123
123
  var toText = (bytes) => `pu1.${toB64u(bytes)}`;
124
- var fromText = (s) => {
125
- if (!/^pu1\.[A-Za-z0-9_-]+$/.test(s)) return null;
124
+ var fromText = (s2) => {
125
+ if (!/^pu1\.[A-Za-z0-9_-]+$/.test(s2)) return null;
126
126
  try {
127
- return fromB64u(s.slice(4));
127
+ return fromB64u(s2.slice(4));
128
128
  } catch {
129
129
  return null;
130
130
  }
@@ -145,135 +145,100 @@ var RetryAfter = class extends Error {
145
145
  var P = 2n ** 256n - 2n ** 32n - 977n;
146
146
 
147
147
  // ../pipeup/dist/pipeup.core.js
148
- function f(t2) {
149
- let e = "";
150
- for (let r of t2) e += String.fromCharCode(r);
151
- return btoa(e).replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
148
+ function e(e3) {
149
+ let t2 = "";
150
+ for (let r2 of e3) t2 += String.fromCharCode(r2);
151
+ return btoa(t2).replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
152
152
  }
153
- function g(t2) {
154
- let e = atob(t2.replace(/-/g, "+").replace(/_/g, "/")), r = new Uint8Array(e.length);
155
- for (let n = 0; n < e.length; n++) r[n] = e.charCodeAt(n);
156
- return r;
153
+ function t(e3) {
154
+ let t2 = atob(e3.replace(/-/g, "+").replace(/_/g, "/")), r2 = new Uint8Array(t2.length);
155
+ for (let e4 = 0; e4 < t2.length; e4++) r2[e4] = t2.charCodeAt(e4);
156
+ return r2;
157
157
  }
158
- function J(t2 = 16) {
159
- return f(crypto.getRandomValues(new Uint8Array(t2)));
158
+ function r(e3) {
159
+ return new TextEncoder().encode(e3);
160
160
  }
161
- function m(t2) {
162
- return new TextEncoder().encode(t2);
161
+ function n(e3) {
162
+ if (null === e3 || "object" != typeof e3) return JSON.stringify(e3);
163
+ if (Array.isArray(e3)) return "[" + e3.map(n).join(",") + "]";
164
+ let t2 = e3;
165
+ return "{" + Object.keys(t2).filter((e4) => void 0 !== t2[e4]).sort().map((e4) => JSON.stringify(e4) + ":" + n(t2[e4])).join(",") + "}";
163
166
  }
164
- function x(t2) {
165
- if (t2 === null || typeof t2 != "object") return JSON.stringify(t2);
166
- if (Array.isArray(t2)) return "[" + t2.map(x).join(",") + "]";
167
- let e = t2;
168
- return "{" + Object.keys(e).filter((r) => e[r] !== void 0).sort().map((r) => JSON.stringify(r) + ":" + x(e[r])).join(",") + "}";
167
+ var a = /^[A-Za-z0-9_-]{43}$/;
168
+ var s = /* @__PURE__ */ new Map();
169
+ async function l() {
170
+ let t2 = await crypto.subtle.generateKey({ name: "Ed25519" }, false, ["sign", "verify"]);
171
+ return { publicKey: e(new Uint8Array(await crypto.subtle.exportKey("raw", t2.publicKey))), privateKey: t2.privateKey };
169
172
  }
170
- var Te = /^[A-Za-z0-9_-]{43}$/;
171
- var Ie = 512;
172
- var w = /* @__PURE__ */ new Map();
173
- async function R() {
174
- let t2 = await crypto.subtle.generateKey({ name: "Ed25519" }, false, ["sign", "verify"]), e = new Uint8Array(await crypto.subtle.exportKey("raw", t2.publicKey));
175
- return { publicKey: f(e), privateKey: t2.privateKey };
173
+ async function u(t2, r2) {
174
+ let n2 = await crypto.subtle.sign({ name: "Ed25519" }, t2.privateKey, r2);
175
+ return e(new Uint8Array(n2));
176
176
  }
177
- async function S(t2, e) {
178
- let r = await crypto.subtle.sign({ name: "Ed25519" }, t2.privateKey, e);
179
- return f(new Uint8Array(r));
177
+ var d = 1e4;
178
+ var c = 2 ** 40;
179
+ var h = 2 ** 47;
180
+ var p = 1e4;
181
+ var f = /^[0-9a-f]{8}$/;
182
+ var m = /^[A-Za-z0-9_-]{43}$/;
183
+ var y = /^[A-Za-z0-9_-]{43}$/;
184
+ var g = /* @__PURE__ */ new Set(["create", "reply", "edit", "delete", "resolve", "reopen"]);
185
+ async function w(e3, t2) {
186
+ if (e3.author !== t2.publicKey) throw new Error("pipeup: an op must be signed by its author");
187
+ return { body: e3, sig: await u(t2, r(n(e3))) };
180
188
  }
181
- async function Q(t2, e, r) {
182
- if (!Te.test(t2)) return false;
183
- try {
184
- if (f(g(t2)) !== t2) return false;
185
- let n = w.get(t2);
186
- if (!n) {
187
- w.size >= Ie && w.delete(w.keys().next().value), n = crypto.subtle.importKey("raw", g(t2), { name: "Ed25519" }, true, ["verify"]), w.set(t2, n);
188
- let o = n;
189
- o.catch(() => {
190
- w.get(t2) === o && w.delete(t2);
191
- });
192
- }
193
- return await crypto.subtle.verify({ name: "Ed25519" }, await n, g(r), e);
194
- } catch {
195
- return false;
196
- }
197
- }
198
- var k = 1e4;
199
- var Ce = 2 ** 18;
200
- var D = 2 ** 40;
201
- var L = 2 ** 47;
202
- var p = { doc: 64, path: 2e3, snapshot: 500, anchorId: 200, quote: 1e4, context: 64, viewEntries: 16, viewKey: 64, viewValue: 200 };
203
- var Me = /^[0-9a-f]{8}$/;
204
- var F = /^[A-Za-z0-9_-]{43}$/;
205
- var $e = /^[A-Za-z0-9_-]{43}$/;
206
- var Ne = /* @__PURE__ */ new Set(["create", "reply", "edit", "delete", "resolve", "reopen"]);
207
- async function Y(t2, e) {
208
- if (t2.author !== e.publicKey) throw new Error("pipeup: an op must be signed by its author");
209
- return { body: t2, sig: await S(e, m(x(t2))) };
210
- }
211
- var h = (t2, e) => typeof t2 == "string" && t2.length <= e;
212
- var O = (t2) => !!t2 && typeof t2 == "object";
213
- var V = (t2) => typeof t2 == "number" && Number.isFinite(t2) && t2 >= 0 && t2 <= 1;
214
- function B(t2) {
215
- if (!O(t2)) return false;
216
- let { id: e, path: r, fingerprint: n, snapshot: o, quote: i, point: s, view: a } = t2;
217
- if (!h(r, p.path) || !h(o, p.snapshot) || typeof n != "string" || !Me.test(n) || e !== void 0 && (!h(e, p.anchorId) || e === "") || i !== void 0 && (!O(i) || !h(i.exact, p.quote) || i.exact === "" || !h(i.prefix, p.context) || !h(i.suffix, p.context)) || s !== void 0 && (!O(s) || !V(s.x) || !V(s.y))) return false;
218
- if (a !== void 0) {
219
- if (!O(a) || Array.isArray(a)) return false;
220
- let d = Object.entries(a);
221
- if (d.length > p.viewEntries || !d.every(([c, l]) => c.length <= p.viewKey && h(l, p.viewValue))) return false;
189
+ var b = (e3, t2) => "string" == typeof e3 && e3.length <= t2;
190
+ var x = (e3) => !!e3 && "object" == typeof e3;
191
+ var v = (e3) => "number" == typeof e3 && Number.isFinite(e3) && e3 >= 0 && e3 <= 1;
192
+ function A(e3) {
193
+ if (!x(e3)) return false;
194
+ let { id: t2, path: r2, fingerprint: n2, snapshot: i, quote: o, point: a2, view: s2 } = e3;
195
+ if (!(b(r2, 2e3) && b(i, 500) && "string" == typeof n2 && f.test(n2) && (void 0 === t2 || b(t2, 200) && "" !== t2) && (void 0 === o || x(o) && b(o.exact, p) && "" !== o.exact && b(o.prefix, 64) && b(o.suffix, 64)) && (void 0 === a2 || x(a2) && v(a2.x) && v(a2.y)))) return false;
196
+ if (void 0 !== s2) {
197
+ if (!x(s2) || Array.isArray(s2)) return false;
198
+ let e4 = Object.entries(s2);
199
+ if (e4.length > 16 || !e4.every(([e5, t3]) => e5.length <= 64 && b(t3, 200))) return false;
222
200
  }
223
201
  return true;
224
202
  }
225
- function W(t2) {
226
- if (!O(t2)) return false;
227
- let { body: e, sig: r } = t2;
228
- if (typeof r != "string" || !O(e) || JSON.stringify({ body: e, sig: r }).length > Ce) return false;
229
- let n = e;
230
- return !(n.v !== 1 || typeof n.id != "string" || !F.test(n.id) || !Ne.has(n.kind) || !h(n.doc, p.doc) || n.doc === "" || typeof n.thread != "string" || !F.test(n.thread) || typeof n.author != "string" || !$e.test(n.author) || typeof n.name != "string" || n.name.length > 80 || n.name !== n.name.trim() || typeof n.clock != "number" || !Number.isSafeInteger(n.clock) || n.clock < 1 || n.clock > D || typeof n.at != "number" || !Number.isSafeInteger(n.at) || n.at < 0 || n.at > L || n.text !== void 0 && (!h(n.text, k) || n.text !== n.text.trim()) || n.target !== void 0 && (typeof n.target != "string" || !F.test(n.target)) || (n.kind === "create" || n.kind === "reply" || n.kind === "edit") && !n.text || (n.kind === "reply" || n.kind === "edit" || n.kind === "delete") && !n.target || n.kind === "create" && (n.id !== n.thread || !B(n.anchor)));
231
- }
232
- function ee(t2) {
233
- return Q(t2.body.author, m(x(t2.body)), t2.sig);
234
- }
235
- function te(t2, e) {
236
- return t2.body.clock !== e.body.clock ? t2.body.clock - e.body.clock : t2.body.at !== e.body.at ? t2.body.at - e.body.at : t2.body.author !== e.body.author ? t2.body.author < e.body.author ? -1 : 1 : t2.body.id !== e.body.id ? t2.body.id < e.body.id ? -1 : 1 : 0;
203
+ function E(e3) {
204
+ if (!x(e3)) return false;
205
+ let { body: t2, sig: r2 } = e3;
206
+ if ("string" != typeof r2 || !x(t2) || JSON.stringify({ body: t2, sig: r2 }).length > 262144) return false;
207
+ let n2 = t2;
208
+ return !(1 !== n2.v || "string" != typeof n2.id || !m.test(n2.id) || !g.has(n2.kind) || !b(n2.doc, 64) || "" === n2.doc || "string" != typeof n2.thread || !m.test(n2.thread) || "string" != typeof n2.author || !y.test(n2.author) || "string" != typeof n2.name || n2.name.length > 80 || n2.name !== n2.name.trim() || "number" != typeof n2.clock || !Number.isSafeInteger(n2.clock) || n2.clock < 1 || n2.clock > c || "number" != typeof n2.at || !Number.isSafeInteger(n2.at) || n2.at < 0 || n2.at > h || void 0 !== n2.text && (!b(n2.text, d) || n2.text !== n2.text.trim()) || void 0 !== n2.target && ("string" != typeof n2.target || !m.test(n2.target)) || ("create" === n2.kind || "reply" === n2.kind || "edit" === n2.kind) && !n2.text || ("reply" === n2.kind || "edit" === n2.kind || "delete" === n2.kind) && !n2.target || "create" === n2.kind && (n2.id !== n2.thread || !A(n2.anchor)));
237
209
  }
238
- function re(t2) {
239
- let e = /* @__PURE__ */ new Map(), r = /* @__PURE__ */ new Map(), n = /* @__PURE__ */ new Map();
240
- for (let { body: o } of [...t2].sort(te)) {
241
- if (o.name && n.set(o.author, o.name), o.kind === "create") {
242
- if (e.has(o.id) || !o.anchor || o.text === void 0) continue;
243
- let a = ne(o.id, o.author, o.name, o.text, o.at);
244
- e.set(o.id, { id: o.id, anchor: o.anchor, root: a, resolved: false }), r.set(o.id, { comment: a, thread: o.id });
245
- continue;
246
- }
247
- let i = e.get(o.thread);
248
- if (!i) continue;
249
- if (o.kind === "resolve" || o.kind === "reopen") {
250
- i.resolved = o.kind === "resolve";
251
- continue;
252
- }
253
- let s = o.target ? r.get(o.target) : void 0;
254
- if (!(!s || s.thread !== o.thread)) {
255
- if (o.kind === "reply") {
256
- if (r.has(o.id) || o.text === void 0) continue;
257
- let a = ne(o.id, o.author, o.name, o.text, o.at);
258
- i.root.replies.push(a), r.set(o.id, { comment: a, thread: o.thread });
259
- continue;
210
+ function k(i) {
211
+ return (async function(r2, n2, i2) {
212
+ if (!a.test(r2)) return false;
213
+ try {
214
+ if (e(t(r2)) !== r2) return false;
215
+ let o = s.get(r2);
216
+ if (!o) {
217
+ s.size >= 512 && s.delete(s.keys().next().value), o = crypto.subtle.importKey("raw", t(r2), { name: "Ed25519" }, true, ["verify"]), s.set(r2, o);
218
+ let e3 = o;
219
+ e3.catch(() => {
220
+ s.get(r2) === e3 && s.delete(r2);
221
+ });
260
222
  }
261
- o.author !== s.comment.author || s.comment.deleted || (o.kind === "edit" && o.text !== void 0 && (s.comment.text = o.text, s.comment.edited = true), o.kind === "delete" && (s.comment.text = "", s.comment.deleted = true));
223
+ return await crypto.subtle.verify({ name: "Ed25519" }, await o, t(i2), n2);
224
+ } catch {
225
+ return false;
262
226
  }
263
- }
264
- for (let { comment: o } of r.values()) o.name || (o.unnamed = true, o.name = n.get(o.author) ?? "");
265
- return [...e.values()];
227
+ })(i.body.author, r(n(i.body)), i.sig);
266
228
  }
267
- function ne(t2, e, r, n, o) {
268
- return { id: t2, author: e, name: r, text: n, at: o, edited: false, deleted: false, replies: [] };
229
+ function $(e3, t2) {
230
+ return e3.body.clock !== t2.body.clock ? e3.body.clock - t2.body.clock : e3.body.at !== t2.body.at ? e3.body.at - t2.body.at : e3.body.author !== t2.body.author ? e3.body.author < t2.body.author ? -1 : 1 : e3.body.id !== t2.body.id ? e3.body.id < t2.body.id ? -1 : 1 : 0;
269
231
  }
270
- async function _(t2) {
271
- let e = { ...t2, id: void 0, thread: t2.kind === "create" ? void 0 : t2.thread }, r = await crypto.subtle.digest("SHA-256", m(x(e)));
272
- return f(new Uint8Array(r));
232
+ function M(e3, t2, r2, n2, i) {
233
+ return { id: e3, author: t2, name: r2, text: n2, at: i, edited: false, deleted: false, replies: [] };
273
234
  }
274
- var T = class {
275
- constructor(e) {
276
- this.doc = e;
235
+ async function S(t2) {
236
+ let i = { ...t2, id: void 0, thread: "create" === t2.kind ? void 0 : t2.thread }, o = await crypto.subtle.digest("SHA-256", r(n(i)));
237
+ return e(new Uint8Array(o));
238
+ }
239
+ var C = class {
240
+ constructor(e3) {
241
+ this.doc = e3;
277
242
  }
278
243
  ops = /* @__PURE__ */ new Map();
279
244
  clock = 0;
@@ -286,100 +251,83 @@ var T = class {
286
251
  return [...this.ops.values()];
287
252
  }
288
253
  threads() {
289
- return re(this.ops.values());
290
- }
291
- async add(e) {
292
- let r = [];
293
- for (let n of e) {
294
- if (!W(n) || n.body.doc !== this.doc || this.ops.has(n.body.id) || n.body.id !== await _(n.body) || !await ee(n)) continue;
295
- let o = { body: n.body, sig: n.sig };
296
- this.ops.set(o.body.id, o), this.clock = Math.max(this.clock, o.body.clock), o.body.kind === "create" && this.createAt.set(o.body.author, Math.max(this.createAt.get(o.body.author) ?? 0, o.body.at)), this.threadAt.set(o.body.thread, Math.max(this.threadAt.get(o.body.thread) ?? 0, o.body.at)), r.push(o);
254
+ return (function(e3) {
255
+ let t2 = /* @__PURE__ */ new Map(), r2 = /* @__PURE__ */ new Map(), n2 = /* @__PURE__ */ new Map();
256
+ for (let { body: i } of [...e3].sort($)) {
257
+ if (i.name && n2.set(i.author, i.name), "create" === i.kind) {
258
+ if (t2.has(i.id) || !i.anchor || void 0 === i.text) continue;
259
+ let e5 = M(i.id, i.author, i.name, i.text, i.at);
260
+ t2.set(i.id, { id: i.id, anchor: i.anchor, root: e5, resolved: false }), r2.set(i.id, { comment: e5, thread: i.id });
261
+ continue;
262
+ }
263
+ let e4 = t2.get(i.thread);
264
+ if (!e4) continue;
265
+ if ("resolve" === i.kind || "reopen" === i.kind) {
266
+ e4.resolved = "resolve" === i.kind;
267
+ continue;
268
+ }
269
+ let o = i.target ? r2.get(i.target) : void 0;
270
+ if (o && o.thread === i.thread) {
271
+ if ("reply" === i.kind) {
272
+ if (r2.has(i.id) || void 0 === i.text) continue;
273
+ let t3 = M(i.id, i.author, i.name, i.text, i.at);
274
+ e4.root.replies.push(t3), r2.set(i.id, { comment: t3, thread: i.thread });
275
+ continue;
276
+ }
277
+ i.author !== o.comment.author || o.comment.deleted || ("edit" === i.kind && void 0 !== i.text && (o.comment.text = i.text, o.comment.edited = true), "delete" === i.kind && (o.comment.text = "", o.comment.deleted = true));
278
+ }
279
+ }
280
+ for (let { comment: e4 } of r2.values()) e4.name || (e4.unnamed = true, e4.name = n2.get(e4.author) ?? "");
281
+ return [...t2.values()];
282
+ })(this.ops.values());
283
+ }
284
+ async add(e3) {
285
+ let t2 = [];
286
+ for (let r2 of e3) {
287
+ if (!E(r2) || r2.body.doc !== this.doc || this.ops.has(r2.body.id) || r2.body.id !== await S(r2.body) || !await k(r2)) continue;
288
+ let e4 = { body: r2.body, sig: r2.sig };
289
+ this.ops.set(e4.body.id, e4), this.clock = Math.max(this.clock, e4.body.clock), "create" === e4.body.kind && this.createAt.set(e4.body.author, Math.max(this.createAt.get(e4.body.author) ?? 0, e4.body.at)), this.threadAt.set(e4.body.thread, Math.max(this.threadAt.get(e4.body.thread) ?? 0, e4.body.at)), t2.push(e4);
297
290
  }
298
- return r;
291
+ return t2;
299
292
  }
300
- async append(e, r, n) {
301
- let o = { v: 1, ...n, id: "", thread: n.kind === "create" ? "" : n.thread, doc: this.doc, author: e.publicKey, name: r, clock: Math.min(this.clock + 1, D), at: Math.min(Math.max(Date.now(), n.kind === "create" ? (this.createAt.get(e.publicKey) ?? 0) + 1 : (this.threadAt.get(n.thread) ?? 0) + 1), L) };
302
- o.id = await _(o);
303
- let i = this.ops.get(o.id);
293
+ async append(e3, t2, r2) {
294
+ let n2 = { v: 1, ...r2, id: "", thread: "create" === r2.kind ? "" : r2.thread, doc: this.doc, author: e3.publicKey, name: t2, clock: Math.min(this.clock + 1, c), at: Math.min(Math.max(Date.now(), "create" === r2.kind ? (this.createAt.get(e3.publicKey) ?? 0) + 1 : (this.threadAt.get(r2.thread) ?? 0) + 1), h) };
295
+ n2.id = await S(n2);
296
+ let i = this.ops.get(n2.id);
304
297
  if (i) return i;
305
- o.kind === "create" && (o.thread = o.id);
306
- let [s] = await this.add([await Y(o, e)]);
307
- if (!s) throw new Error("pipeup: could not record this change");
308
- return s;
298
+ "create" === n2.kind && (n2.thread = n2.id);
299
+ let [o] = await this.add([await w(n2, e3)]);
300
+ if (!o) throw new Error("pipeup: could not record this change");
301
+ return o;
309
302
  }
310
303
  };
311
- var Re = /^([A-Za-z0-9_-]{16}):([A-Za-z0-9_-]{43})$/;
312
- function Fe() {
313
- return `${J(12)}:${f(crypto.getRandomValues(new Uint8Array(32)))}`;
304
+ var j = "AI assistant";
305
+ var I = (e3) => e3 === j || e3.startsWith(`${j} `);
306
+ var D = /^([A-Za-z0-9_-]{16}):([A-Za-z0-9_-]{43})$/;
307
+ function F() {
308
+ return `${(function(t2 = 16) {
309
+ return e(crypto.getRandomValues(new Uint8Array(t2)));
310
+ })(12)}:${e(crypto.getRandomValues(new Uint8Array(32)))}`;
314
311
  }
315
- async function De(t2) {
316
- let e = Re.exec(t2.trim()), r = e?.[1], n = e?.[2];
317
- if (!r || !n) throw new Error('pipeup: data-pipeup-doc must look like "<id>:<key>", as made by newDocumentAttribute()');
318
- let o = await crypto.subtle.importKey("raw", g(n), { name: "AES-GCM" }, false, ["encrypt", "decrypt"]);
319
- return { id: r, key: o };
312
+ async function U(e3) {
313
+ let r2 = D.exec(e3.trim()), n2 = r2?.[1], i = r2?.[2];
314
+ if (!n2 || !i) throw new Error('pipeup: data-pipeup-doc must look like "<id>:<key>", as made by newDocumentAttribute()');
315
+ return { id: n2, key: await crypto.subtle.importKey("raw", t(i), { name: "AES-GCM" }, false, ["encrypt", "decrypt"]) };
320
316
  }
321
- async function oe(t2, e, r) {
322
- let n = crypto.getRandomValues(new Uint8Array(12)), o = await crypto.subtle.encrypt({ name: "AES-GCM", iv: n, additionalData: m(r) }, t2, m(e));
323
- return { iv: f(n), data: f(new Uint8Array(o)) };
317
+ async function R(t2, n2, i) {
318
+ let o = crypto.getRandomValues(new Uint8Array(12)), a2 = await crypto.subtle.encrypt({ name: "AES-GCM", iv: o, additionalData: r(i) }, t2, r(n2));
319
+ return { iv: e(o), data: e(new Uint8Array(a2)) };
324
320
  }
325
- async function ie(t2, e, r) {
326
- try {
327
- let n = await crypto.subtle.decrypt({ name: "AES-GCM", iv: g(e.iv), additionalData: m(r) }, t2, g(e.data));
328
- return new TextDecoder().decode(n);
329
- } catch {
330
- throw new Error("pipeup: this feedback could not be opened with this document");
331
- }
332
- }
333
- var Le = 5e6;
334
- var se = (t2) => `pipeup-file:${t2}`;
335
- async function ae(t2, e, r) {
336
- let n = r ? { pipeup: 1, doc: t2, sealed: true, ...await oe(r, JSON.stringify(e), se(t2)) } : { pipeup: 1, doc: t2, sealed: false, ops: e };
337
- return JSON.stringify(n, null, 2);
338
- }
339
- async function de(t2, e, r) {
340
- if (t2.length > Le) throw new Error("pipeup: this feedback file is too large");
341
- let n;
342
- try {
343
- n = JSON.parse(t2);
344
- } catch {
345
- throw new Error("pipeup: this is not an Pipeup feedback file");
346
- }
347
- if (!n || typeof n != "object" || n.pipeup !== 1 || typeof n.doc != "string") throw new Error("pipeup: this is not an Pipeup feedback file");
348
- if (n.doc !== e) throw new Error("pipeup: this feedback is for a different document");
349
- if (!n.sealed) return Array.isArray(n.ops) ? n.ops : [];
350
- if (!r) throw new Error("pipeup: this feedback is sealed, and this page has no document key");
351
- if (typeof n.iv != "string" || typeof n.data != "string") throw new Error("pipeup: this is not an Pipeup feedback file");
352
- let o;
353
- try {
354
- o = await ie(r, { iv: n.iv, data: n.data }, se(e));
355
- } catch {
356
- throw new Error("pipeup: this feedback could not be opened with this document's key");
357
- }
358
- let i;
359
- try {
360
- i = JSON.parse(o);
361
- } catch {
362
- throw new Error("pipeup: this is not an Pipeup feedback file");
363
- }
364
- return Array.isArray(i) ? i : [];
365
- }
366
- var Be = 5e3;
367
- var _e = /^[a-z][a-z0-9-]{1,23}\/[a-z][a-z0-9-]{0,31}$/;
368
- var ce = 80;
369
- var E = class extends Error {
370
- constructor(r, n, o = 1) {
371
- super("pipeup: shown here, but not saved yet");
372
- this.id = r;
373
- this.cause = n;
374
- this.count = o;
375
- this.name = "UnsavedChangeError";
321
+ var H = (e3) => `pipeup-file:${e3}`;
322
+ var L = /^[a-z][a-z0-9-]{1,23}\/[a-z][a-z0-9-]{0,31}$/;
323
+ var z = class extends Error {
324
+ constructor(e3, t2, r2 = 1) {
325
+ super("pipeup: shown here, but not saved yet"), this.id = e3, this.cause = t2, this.count = r2, this.name = "UnsavedChangeError";
376
326
  }
377
327
  };
378
- var K = class t {
379
- constructor(e, r) {
380
- this.log = e;
381
- this.options = r;
382
- this.displayName = r.name.trim() ? pe(r.name) : "";
328
+ var K = class e2 {
329
+ constructor(e3, t2) {
330
+ this.log = e3, this.options = t2, this.displayName = t2.name.trim() ? B(t2.name) : "";
383
331
  }
384
332
  listeners = /* @__PURE__ */ new Set();
385
333
  cache = [];
@@ -387,12 +335,12 @@ var K = class t {
387
335
  displayName;
388
336
  e = Promise.resolve();
389
337
  unsaved = [];
390
- static async open(e) {
391
- if (typeof e.doc != "string" || e.doc === "" || e.doc.length > p.doc) throw new Error(`pipeup: the document id must be 1 to ${p.doc} characters`);
392
- let r = new T(e.doc), n = await e.store.load(e.doc), o = n.length - (await r.add(n)).length;
393
- o && console.warn(`pipeup: ${o} saved change${o === 1 ? "" : "s"} on this page couldn't be read; kept as saved`);
394
- let i = new t(r, e);
395
- return i.refresh(false), i;
338
+ static async open(t2) {
339
+ if ("string" != typeof t2.doc || "" === t2.doc || t2.doc.length > 64) throw new Error("pipeup: the document id must be 1 to 64 characters");
340
+ let r2 = new C(t2.doc), n2 = await t2.store.load(t2.doc), i = n2.length - (await r2.add(n2)).length;
341
+ i && console.warn(`pipeup: ${i} saved change${1 === i ? "" : "s"} on this page couldn't be read; kept as saved`);
342
+ let o = new e2(r2, t2);
343
+ return o.refresh(false), o;
396
344
  }
397
345
  get id() {
398
346
  return this.options.doc;
@@ -403,8 +351,8 @@ var K = class t {
403
351
  get name() {
404
352
  return this.displayName;
405
353
  }
406
- set name(e) {
407
- this.displayName = pe(e), this.refresh(true, [], "");
354
+ set name(e3) {
355
+ this.displayName = B(e3), this.refresh(true, [], "");
408
356
  }
409
357
  threads() {
410
358
  return this.cache;
@@ -412,141 +360,176 @@ var K = class t {
412
360
  ops() {
413
361
  return this.log.all();
414
362
  }
415
- onChange(e) {
416
- return this.listeners.add(e), () => this.listeners.delete(e);
363
+ onChange(e3) {
364
+ return this.listeners.add(e3), () => this.listeners.delete(e3);
417
365
  }
418
- comment(e, r) {
419
- return this.enqueue(() => this.write({ kind: "create", anchor: e, text: U(r) }));
366
+ comment(e3, t2) {
367
+ return this.enqueue(() => this.write({ kind: "create", anchor: e3, text: _(t2) }));
420
368
  }
421
- reply(e, r) {
422
- return this.enqueue(() => this.write({ kind: "reply", thread: this.find(e).thread, target: e, text: U(r) }));
369
+ reply(e3, t2) {
370
+ return this.enqueue(() => this.write({ kind: "reply", thread: this.find(e3).thread, target: e3, text: _(t2) }));
423
371
  }
424
- edit(e, r) {
372
+ edit(e3, t2) {
425
373
  return this.enqueue(async () => {
426
- let { thread: n } = this.mine(e);
427
- await this.write({ kind: "edit", thread: n, target: e, text: U(r) });
374
+ let { thread: r2 } = this.mine(e3);
375
+ await this.write({ kind: "edit", thread: r2, target: e3, text: _(t2) });
428
376
  });
429
377
  }
430
- remove(e) {
378
+ remove(e3) {
431
379
  return this.enqueue(async () => {
432
- let { thread: r } = this.mine(e);
433
- await this.write({ kind: "delete", thread: r, target: e });
380
+ let { thread: t2 } = this.mine(e3);
381
+ await this.write({ kind: "delete", thread: t2, target: e3 });
434
382
  });
435
383
  }
436
- resolve(e) {
384
+ resolve(e3) {
437
385
  return this.enqueue(async () => {
438
- await this.write({ kind: "resolve", thread: this.thread(e) });
386
+ await this.write({ kind: "resolve", thread: this.thread(e3) });
439
387
  });
440
388
  }
441
- reopen(e) {
389
+ reopen(e3) {
442
390
  return this.enqueue(async () => {
443
- await this.write({ kind: "reopen", thread: this.thread(e) });
391
+ await this.write({ kind: "reopen", thread: this.thread(e3) });
444
392
  });
445
393
  }
446
- sign(e, r) {
447
- if (!_e.test(e)) throw new Error('pipeup: a signing purpose looks like "<add-on id>/<name>"');
448
- return S(this.options.identity, m(`pipeup:${e}
449
- ${r}`));
394
+ sign(e3, t2) {
395
+ if (!L.test(e3)) throw new Error('pipeup: a signing purpose looks like "<add-on id>/<name>"');
396
+ return u(this.options.identity, r(`pipeup:${e3}
397
+ ${t2}`));
450
398
  }
451
399
  flush() {
452
400
  return this.enqueue(() => this.persist());
453
401
  }
454
402
  exportFile() {
455
- return ae(this.options.doc, this.log.all(), this.options.key);
456
- }
457
- async importFile(e) {
458
- return this.merge(await de(e, this.options.doc, this.options.key), "file");
403
+ return (async function(e3, t2, r2) {
404
+ let n2 = r2 ? { pipeup: 1, doc: e3, sealed: true, ...await R(r2, JSON.stringify(t2), H(e3)) } : { pipeup: 1, doc: e3, sealed: false, ops: t2 };
405
+ return JSON.stringify(n2, null, 2);
406
+ })(this.options.doc, this.log.all(), this.options.key);
407
+ }
408
+ async importFile(e3) {
409
+ return this.merge(await (async function(e4, n2, i) {
410
+ if (e4.length > 5e6) throw new Error("pipeup: this feedback file is too large");
411
+ let o, a2, s2;
412
+ try {
413
+ o = JSON.parse(e4);
414
+ } catch {
415
+ throw new Error("pipeup: this is not an Pipeup feedback file");
416
+ }
417
+ if (!o || "object" != typeof o || 1 !== o.pipeup || "string" != typeof o.doc) throw new Error("pipeup: this is not an Pipeup feedback file");
418
+ if (o.doc !== n2) throw new Error("pipeup: this feedback is for a different document");
419
+ if (!o.sealed) return Array.isArray(o.ops) ? o.ops : [];
420
+ if (!i) throw new Error("pipeup: this feedback is sealed, and this page has no document key");
421
+ if ("string" != typeof o.iv || "string" != typeof o.data) throw new Error("pipeup: this is not an Pipeup feedback file");
422
+ try {
423
+ a2 = await (async function(e5, n3, i2) {
424
+ try {
425
+ let o2 = await crypto.subtle.decrypt({ name: "AES-GCM", iv: t(n3.iv), additionalData: r(i2) }, e5, t(n3.data));
426
+ return new TextDecoder().decode(o2);
427
+ } catch {
428
+ throw new Error("pipeup: this feedback could not be opened with this document");
429
+ }
430
+ })(i, { iv: o.iv, data: o.data }, H(n2));
431
+ } catch {
432
+ throw new Error("pipeup: this feedback could not be opened with this document's key");
433
+ }
434
+ try {
435
+ s2 = JSON.parse(a2);
436
+ } catch {
437
+ throw new Error("pipeup: this is not an Pipeup feedback file");
438
+ }
439
+ return Array.isArray(s2) ? s2 : [];
440
+ })(e3, this.options.doc, this.options.key), "file");
459
441
  }
460
- merge(e, r) {
461
- return e.length > Be ? Promise.reject(new RangeError("pipeup: too many changes to merge at once")) : this.enqueue(async () => {
462
- let n = await this.log.add([...e]);
463
- this.unsaved.push(...n), n.length > 0 && this.refresh(true, n, r);
442
+ merge(e3, t2) {
443
+ return e3.length > 5e3 ? Promise.reject(new RangeError("pipeup: too many changes to merge at once")) : this.enqueue(async () => {
444
+ let r2 = await this.log.add([...e3]);
445
+ this.unsaved.push(...r2), r2.length > 0 && this.refresh(true, r2, t2);
464
446
  try {
465
447
  await this.persist();
466
- } catch (o) {
467
- throw n.length > 0 ? new E(n[0].body.id, o, n.length) : o;
448
+ } catch (e4) {
449
+ throw r2.length > 0 ? new z(r2[0].body.id, e4, r2.length) : e4;
468
450
  }
469
- return n.length;
451
+ return r2.length;
470
452
  });
471
453
  }
472
- enqueue(e) {
473
- let r = this.e.then(e);
474
- return this.e = r.catch(() => {
475
- }), r;
454
+ enqueue(e3) {
455
+ let t2 = this.e.then(e3);
456
+ return this.e = t2.catch(() => {
457
+ }), t2;
476
458
  }
477
- async write(e) {
478
- let r = await this.log.append(this.options.identity, this.displayName, e);
479
- this.unsaved.push(r), this.refresh(true, [r], "local");
459
+ async write(e3) {
460
+ let t2 = await this.log.append(this.options.identity, this.displayName, e3);
461
+ this.unsaved.push(t2), this.refresh(true, [t2], "local");
480
462
  try {
481
463
  await this.persist();
482
- } catch (n) {
483
- throw new E(r.body.id, n);
464
+ } catch (e4) {
465
+ throw new z(t2.body.id, e4);
484
466
  }
485
- return r.body.id;
467
+ return t2.body.id;
486
468
  }
487
469
  async persist() {
488
- if (this.unsaved.length === 0) return;
489
- let e = [...this.unsaved];
490
- await this.options.store.append(this.options.doc, e), this.unsaved = this.unsaved.filter((r) => !e.includes(r));
470
+ if (0 === this.unsaved.length) return;
471
+ let e3 = [...this.unsaved];
472
+ await this.options.store.append(this.options.doc, e3), this.unsaved = this.unsaved.filter((t2) => !e3.includes(t2));
491
473
  }
492
- refresh(e, r = [], n = "") {
474
+ refresh(e3, t2 = [], r2 = "") {
493
475
  this.cache = this.log.threads(), this.comments.clear();
494
- let o = (i, s) => {
495
- i.unnamed && i.author === this.me && this.displayName && (i.name = this.displayName), this.comments.set(i.id, { comment: i, thread: s });
496
- for (let a of i.replies) o(a, s);
476
+ let n2 = (e4, t3) => {
477
+ e4.unnamed && e4.author === this.me && this.displayName && (e4.name = this.displayName), this.comments.set(e4.id, { comment: e4, thread: t3 });
478
+ for (let r3 of e4.replies) n2(r3, t3);
497
479
  };
498
- for (let i of this.cache) o(i.root, i.id);
499
- if (e) for (let i of this.listeners) try {
500
- i(this.cache, r, n);
501
- } catch (s) {
502
- globalThis.reportError?.(s);
480
+ for (let e4 of this.cache) n2(e4.root, e4.id);
481
+ if (e3) for (let e4 of this.listeners) try {
482
+ e4(this.cache, t2, r2);
483
+ } catch (e5) {
484
+ globalThis.reportError?.(e5);
503
485
  }
504
486
  }
505
- find(e) {
506
- let r = this.comments.get(e);
507
- if (!r) throw new Error("pipeup: there is no comment with that id");
508
- return r;
487
+ find(e3) {
488
+ let t2 = this.comments.get(e3);
489
+ if (!t2) throw new Error("pipeup: there is no comment with that id");
490
+ return t2;
509
491
  }
510
- mine(e) {
511
- let r = this.find(e);
512
- if (r.comment.author !== this.me) throw new Error("pipeup: only the writer can change a comment");
513
- return r;
492
+ mine(e3) {
493
+ let t2 = this.find(e3);
494
+ if (t2.comment.author !== this.me) throw new Error("pipeup: only the writer can change a comment");
495
+ return t2;
514
496
  }
515
- thread(e) {
516
- if (!this.cache.some((r) => r.id === e)) throw new Error("pipeup: there is no thread with that id");
517
- return e;
497
+ thread(e3) {
498
+ if (!this.cache.some((t2) => t2.id === e3)) throw new Error("pipeup: there is no thread with that id");
499
+ return e3;
518
500
  }
519
501
  };
520
- function U(t2) {
521
- let e = t2.trim();
522
- if (!e) throw new Error("pipeup: a comment needs some words");
523
- if (e.length > k) throw new Error(`pipeup: comments are limited to ${k} characters`);
524
- return e;
502
+ function _(e3) {
503
+ let t2 = e3.trim();
504
+ if (!t2) throw new Error("pipeup: a comment needs some words");
505
+ if (t2.length > d) throw new Error(`pipeup: comments are limited to ${d} characters`);
506
+ return t2;
525
507
  }
526
- function pe(t2) {
527
- let e = t2.replace(/\s+/g, " ").trim();
528
- if (!e || e.length > ce) throw new Error(`pipeup: choose a name of 1 to ${ce} characters`);
529
- return e;
508
+ function B(e3) {
509
+ let t2 = e3.replace(/\s+/g, " ").trim();
510
+ if (!t2 || t2.length > 80) throw new Error("pipeup: choose a name of 1 to 80 characters");
511
+ if (I(t2)) throw new Error("pipeup: that name is kept for AI replies; choose another");
512
+ return t2;
530
513
  }
531
- var q = class {
514
+ var G = class {
532
515
  docs = /* @__PURE__ */ new Map();
533
516
  profile = null;
534
- async load(e) {
535
- return [...this.docs.get(e)?.values() ?? []];
517
+ async load(e3) {
518
+ return [...this.docs.get(e3)?.values() ?? []];
536
519
  }
537
- async append(e, r) {
538
- let n = this.docs.get(e);
539
- n || this.docs.set(e, n = /* @__PURE__ */ new Map());
540
- for (let o of r) n.set(o.body.id, o);
520
+ async append(e3, t2) {
521
+ let r2 = this.docs.get(e3);
522
+ r2 || this.docs.set(e3, r2 = /* @__PURE__ */ new Map());
523
+ for (let e4 of t2) r2.set(e4.body.id, e4);
541
524
  }
542
525
  async loadProfile() {
543
526
  return this.profile;
544
527
  }
545
- async saveProfile(e) {
546
- this.profile = e;
528
+ async saveProfile(e3) {
529
+ this.profile = e3;
547
530
  }
548
- async saveProfileIfAbsent(e) {
549
- return this.profile || (this.profile = e), this.profile;
531
+ async saveProfileIfAbsent(e3) {
532
+ return this.profile || (this.profile = e3), this.profile;
550
533
  }
551
534
  };
552
535
 
@@ -603,9 +586,9 @@ var refusal = (status) => {
603
586
  };
604
587
  async function json(res) {
605
588
  const t2 = await res.text();
606
- const v = t2.length < 1e7 && JSON.parse(t2);
607
- if (!v || typeof v !== "object") throw new Error("the answer was not usable");
608
- return [v, t2.length];
589
+ const v2 = t2.length < 1e7 && JSON.parse(t2);
590
+ if (!v2 || typeof v2 !== "object") throw new Error("the answer was not usable");
591
+ return [v2, t2.length];
609
592
  }
610
593
  function chunks(ops, max = 9e5) {
611
594
  const out = [];
@@ -632,8 +615,8 @@ var sleep = (ms, signal) => new Promise((resolve) => {
632
615
  );
633
616
  });
634
617
  var retryAfter = (res, fallback = 10) => {
635
- const n = Number(res.headers.get("Retry-After"));
636
- return n > 0 ? Math.min(n, 3600) : fallback;
618
+ const n2 = Number(res.headers.get("Retry-After"));
619
+ return n2 > 0 ? Math.min(n2, 3600) : fallback;
637
620
  };
638
621
  var idsOf = (ops) => ops.map((o) => o?.body?.id).filter((i) => typeof i === "string");
639
622
 
@@ -642,9 +625,9 @@ var MAX_BODY = 524288;
642
625
  var MAX_PAGES = 1e3;
643
626
  var batchId = async (ct) => toB64u(await sha256(utf8(ct))).slice(0, 22);
644
627
  var Mailbox = class {
645
- constructor(a, l, f2, signal) {
646
- this.a = a;
647
- this.l = l;
628
+ constructor(a2, l2, f2, signal) {
629
+ this.a = a2;
630
+ this.l = l2;
648
631
  this.f = f2;
649
632
  this.signal = signal;
650
633
  }
@@ -660,27 +643,27 @@ var Mailbox = class {
660
643
  let reset = 0;
661
644
  for (let pages = 0; pages < MAX_PAGES; ) {
662
645
  const url = `${this.a.mailbox}/ops${this.cursor ? `?since=${encodeURIComponent(this.cursor)}` : ""}`;
663
- const r = await GET(this.f, url, this.signal);
664
- if (r.status === 404) throw new Problem("gone");
665
- if (r.status === 409 && reset++ < 2) {
646
+ const r2 = await GET(this.f, url, this.signal);
647
+ if (r2.status === 404) throw new Problem("gone");
648
+ if (r2.status === 409 && reset++ < 2) {
666
649
  this.cursor = "";
667
650
  continue;
668
651
  }
669
- if (!r.ok) throw new Error(`HTTP ${r.status}`);
652
+ if (!r2.ok) throw new Error(`HTTP ${r2.status}`);
670
653
  pages++;
671
- const [j] = await json(r);
672
- for (const b of Array.isArray(j.batches) ? j.batches : []) {
673
- if (typeof b?.id !== "string" || typeof b.ct !== "string" || this.seen.has(b.id)) continue;
674
- this.seen.add(b.id);
675
- const bytes = fromText(b.ct);
654
+ const [j2] = await json(r2);
655
+ for (const b2 of Array.isArray(j2.batches) ? j2.batches : []) {
656
+ if (typeof b2?.id !== "string" || typeof b2.ct !== "string" || this.seen.has(b2.id)) continue;
657
+ this.seen.add(b2.id);
658
+ const bytes = fromText(b2.ct);
676
659
  const o = bytes && await open(this.l, "share", bytes);
677
660
  if (!o) continue;
678
661
  out.push(o);
679
662
  for (const id of idsOf(o.ops)) this.ids.add(id);
680
663
  }
681
- if (typeof j.next === "string") this.cursor = j.next;
682
- this.expires = typeof j.expires === "string" ? Date.parse(j.expires) || null : null;
683
- if (j.more !== true) break;
664
+ if (typeof j2.next === "string") this.cursor = j2.next;
665
+ this.expires = typeof j2.expires === "string" ? Date.parse(j2.expires) || null : null;
666
+ if (j2.more !== true) break;
684
667
  }
685
668
  return out;
686
669
  }
@@ -705,18 +688,18 @@ var Mailbox = class {
705
688
  await this.one(part.slice(mid));
706
689
  };
707
690
  if (init.body.length > MAX_BODY && part.length > 1) return split();
708
- const r = await this.f(url, { ...init, signal: this.signal });
709
- const s = r.status;
710
- if (s === 200 || s === 201 || s === 400) return;
711
- if (s === 413 && part.length > 1) return split();
712
- const refused = refusal(s);
691
+ const r2 = await this.f(url, { ...init, signal: this.signal });
692
+ const s2 = r2.status;
693
+ if (s2 === 200 || s2 === 201 || s2 === 400) return;
694
+ if (s2 === 413 && part.length > 1) return split();
695
+ const refused = refusal(s2);
713
696
  if (refused) throw refused;
714
- if (s === 429) {
715
- const [body] = await json(r).catch(() => [{}]);
716
- const n = Number(body.retryAfter);
717
- throw new RetryAfter(r.headers.get("Retry-After") ? retryAfter(r) : n > 0 ? Math.min(n, 3600) : 10);
697
+ if (s2 === 429) {
698
+ const [body] = await json(r2).catch(() => [{}]);
699
+ const n2 = Number(body.retryAfter);
700
+ throw new RetryAfter(r2.headers.get("Retry-After") ? retryAfter(r2) : n2 > 0 ? Math.min(n2, 3600) : 10);
718
701
  }
719
- throw new Error(`HTTP ${s}`);
702
+ throw new Error(`HTTP ${s2}`);
720
703
  }
721
704
  };
722
705
 
@@ -735,42 +718,42 @@ var commentBody = (paste, sealed) => ({
735
718
  async function answer(res) {
736
719
  if (res.status === 429) throw new RetryAfter(retryAfter(res));
737
720
  if (!res.ok) throw new Error(`HTTP ${res.status}`);
738
- const [j] = await json(res);
739
- if (j.status === 0) return j;
740
- const n = Number(/\d+/.exec(String(j.message ?? ""))?.[0]);
741
- throw new RetryAfter(n >= 1 && n <= 3600 ? n : 30, true);
721
+ const [j2] = await json(res);
722
+ if (j2.status === 0) return j2;
723
+ const n2 = Number(/\d+/.exec(String(j2.message ?? ""))?.[0]);
724
+ throw new RetryAfter(n2 >= 1 && n2 <= 3600 ? n2 : 30, true);
742
725
  }
743
- async function createPaste(f2, base, l, expire = "never", signal) {
744
- const ct = toB64(await seal(l, "share", []));
745
- const j = await answer(
726
+ async function createPaste(f2, base, l2, expire = "never", signal) {
727
+ const ct = toB64(await seal(l2, "share", []));
728
+ const j2 = await answer(
746
729
  await f2(base, { ...POST({ v: 2, adata: [spec(), "plaintext", 1, 0], ct, meta: { expire } }), signal })
747
730
  );
748
- if (typeof j.id !== "string" || typeof j.deletetoken !== "string")
731
+ if (typeof j2.id !== "string" || typeof j2.deletetoken !== "string")
749
732
  throw new Error("the answer had no paste id");
750
- return { id: j.id, deleteToken: j.deletetoken };
733
+ return { id: j2.id, deleteToken: j2.deletetoken };
751
734
  }
752
735
  async function deletePaste(f2, base, id, token) {
753
736
  return f2(base, POST({ pasteid: id, deletetoken: token }));
754
737
  }
755
738
  async function readPaste(f2, base, id, signal) {
756
- const r = await GET(f2, `${base}?${id}`, signal);
757
- if (r.status === 404) return null;
758
- if (!r.ok) throw new Error(`HTTP ${r.status}`);
759
- const [j, size] = await json(r);
760
- if (j.status !== 0) return null;
761
- const ttl = j.meta?.time_to_live;
762
- return { j, size, ttl: typeof ttl === "number" && ttl > 0 ? ttl * 1e3 : null };
739
+ const r2 = await GET(f2, `${base}?${id}`, signal);
740
+ if (r2.status === 404) return null;
741
+ if (!r2.ok) throw new Error(`HTTP ${r2.status}`);
742
+ const [j2, size] = await json(r2);
743
+ if (j2.status !== 0) return null;
744
+ const ttl = j2.meta?.time_to_live;
745
+ return { j: j2, size, ttl: typeof ttl === "number" && ttl > 0 ? ttl * 1e3 : null };
763
746
  }
764
747
  var PrivateBin = class {
765
- constructor(a, l, f2, signal, gen, onGen = () => {
748
+ constructor(a2, l2, f2, signal, gen, onGen = () => {
766
749
  }) {
767
- this.a = a;
768
- this.l = l;
750
+ this.a = a2;
751
+ this.l = l2;
769
752
  this.f = f2;
770
753
  this.signal = signal;
771
754
  this.onGen = onGen;
772
- this.head = gen || a.paste;
773
- this.trail.push(a.paste);
755
+ this.head = gen || a2.paste;
756
+ this.trail.push(a2.paste);
774
757
  }
775
758
  ids = /* @__PURE__ */ new Set();
776
759
  expires = null;
@@ -784,27 +767,27 @@ var PrivateBin = class {
784
767
  seen = /* @__PURE__ */ new Map();
785
768
  async scan(comments, out) {
786
769
  let next;
787
- for (const c of Array.isArray(comments) ? comments : []) {
788
- if (typeof c?.id !== "string" || typeof c.ct !== "string") continue;
789
- let n = this.seen.get(c.id);
790
- if (n === void 0) {
791
- n = null;
770
+ for (const c2 of Array.isArray(comments) ? comments : []) {
771
+ if (typeof c2?.id !== "string" || typeof c2.ct !== "string") continue;
772
+ let n2 = this.seen.get(c2.id);
773
+ if (n2 === void 0) {
774
+ n2 = null;
792
775
  let bytes = null;
793
776
  try {
794
- if (c.ct.length < 14e5) bytes = fromB64(c.ct);
777
+ if (c2.ct.length < 14e5) bytes = fromB64(c2.ct);
795
778
  } catch {
796
779
  }
797
- const v = bytes && await openJson(this.l, "share", bytes);
798
- const nx = v?.next;
799
- const b = typeof nx === "string" ? null : asBatch(this.l, v);
800
- if (typeof nx === "string" && NEXT.test(nx)) n = nx;
801
- else if (b) {
802
- out.push(b);
803
- for (const id of idsOf(b.ops)) this.ids.add(id);
780
+ const v2 = bytes && await openJson(this.l, "share", bytes);
781
+ const nx = v2?.next;
782
+ const b2 = typeof nx === "string" ? null : asBatch(this.l, v2);
783
+ if (typeof nx === "string" && NEXT.test(nx)) n2 = nx;
784
+ else if (b2) {
785
+ out.push(b2);
786
+ for (const id of idsOf(b2.ops)) this.ids.add(id);
804
787
  }
805
- this.seen.set(c.id, n);
788
+ this.seen.set(c2.id, n2);
806
789
  }
807
- next ??= n ?? void 0;
790
+ next ??= n2 ?? void 0;
808
791
  }
809
792
  return next;
810
793
  }
@@ -815,8 +798,8 @@ var PrivateBin = class {
815
798
  let fell = false;
816
799
  let got = false;
817
800
  for (let hops = 0; ; ) {
818
- const r = await readPaste(this.f, this.a.base, id, this.signal);
819
- if (!r) {
801
+ const r2 = await readPaste(this.f, this.a.base, id, this.signal);
802
+ if (!r2) {
820
803
  if (got) break;
821
804
  if (!fell && id !== this.a.paste) {
822
805
  fell = true;
@@ -833,11 +816,11 @@ var PrivateBin = class {
833
816
  this.moved = true;
834
817
  this.onGen(id);
835
818
  }
836
- const comments = r.j.comments;
819
+ const comments = r2.j.comments;
837
820
  const next = await this.scan(comments, out);
838
- this.expires = r.ttl && Date.now() + r.ttl;
821
+ this.expires = r2.ttl && Date.now() + r2.ttl;
839
822
  const first = (Array.isArray(comments) ? comments[0]?.ct?.length : 0) ?? 0;
840
- this.big = !next && r.size > ROLL_BYTES && r.size > 2 * first;
823
+ this.big = !next && r2.size > ROLL_BYTES && r2.size > 2 * first;
841
824
  if (!next || ++hops >= MAX_HOPS) break;
842
825
  id = next;
843
826
  }
@@ -864,9 +847,9 @@ var PrivateBin = class {
864
847
  for (let tries = 0; ; tries++) {
865
848
  try {
866
849
  return await run2();
867
- } catch (e) {
868
- if (!(e instanceof RetryAfter) || tries > 5 || this.signal?.aborted) throw e;
869
- await sleep(e.seconds * 1e3 * (1 + Math.random() * 0.2), this.signal);
850
+ } catch (e3) {
851
+ if (!(e3 instanceof RetryAfter) || tries > 5 || this.signal?.aborted) throw e3;
852
+ await sleep(e3.seconds * 1e3 * (1 + Math.random() * 0.2), this.signal);
870
853
  }
871
854
  }
872
855
  };
@@ -904,9 +887,9 @@ function setAttribute(html, name, value) {
904
887
  const old = attr(name).exec(tag);
905
888
  let next;
906
889
  if (old) {
907
- const q2 = old[3][0] === "'" ? "'" : '"';
908
- const v = q2 === "'" ? value.replace(/&/g, "&amp;").replace(/'/g, "&#39;") : escaped;
909
- next = tag.slice(0, old.index) + `${old[1]}${name}${old[2]}${q2}${v}${q2}` + tag.slice(old.index + old[0].length);
890
+ const q = old[3][0] === "'" ? "'" : '"';
891
+ const v2 = q === "'" ? value.replace(/&/g, "&amp;").replace(/'/g, "&#39;") : escaped;
892
+ next = tag.slice(0, old.index) + `${old[1]}${name}${old[2]}${q}${v2}${q}` + tag.slice(old.index + old[0].length);
910
893
  } else {
911
894
  const at = tag.length - 1;
912
895
  next = `${tag.slice(0, at)} ${name}="${escaped}"${tag.slice(at)}`;
@@ -921,13 +904,13 @@ var dateWords = (ms) => new Date(ms).toLocaleDateString("en-GB", {
921
904
  timeZone: "UTC"
922
905
  });
923
906
  function spanWords(ms) {
924
- const n = (x2, unit) => `${x2} ${unit}${x2 === 1 ? "" : "s"}`;
925
- if (ms < 36e5) return n(Math.max(1, Math.round(ms / 6e4)), "minute");
926
- if (ms < 2 * DAY) return n(Math.round(ms / 36e5), "hour");
927
- if (ms < 6.5 * DAY) return n(Math.round(ms / DAY), "day");
928
- if (ms < 60 * DAY) return n(Math.round(ms / (7 * DAY)), "week");
929
- if (ms < 730 * DAY) return n(Math.round(ms / (30 * DAY)), "month");
930
- return n(Math.round(ms / (365 * DAY)), "year");
907
+ const n2 = (x2, unit) => `${x2} ${unit}${x2 === 1 ? "" : "s"}`;
908
+ if (ms < 36e5) return n2(Math.max(1, Math.round(ms / 6e4)), "minute");
909
+ if (ms < 2 * DAY) return n2(Math.round(ms / 36e5), "hour");
910
+ if (ms < 6.5 * DAY) return n2(Math.round(ms / DAY), "day");
911
+ if (ms < 60 * DAY) return n2(Math.round(ms / (7 * DAY)), "week");
912
+ if (ms < 730 * DAY) return n2(Math.round(ms / (30 * DAY)), "month");
913
+ return n2(Math.round(ms / (365 * DAY)), "year");
931
914
  }
932
915
  function keepWords(host, ttlMs, now = Date.now()) {
933
916
  if (ttlMs === null) return `${host} keeps this shared copy until it is deleted.`;
@@ -938,17 +921,17 @@ function parseArgs(argv) {
938
921
  const flags = /* @__PURE__ */ new Map();
939
922
  const rest = [];
940
923
  for (let i = 0; i < argv.length; i++) {
941
- const a = argv[i];
942
- if (a === "-h") flags.set("help", true);
943
- else if (a.startsWith("--")) {
944
- const [name, inline] = a.slice(2).split(/=(.*)/s, 2);
924
+ const a2 = argv[i];
925
+ if (a2 === "-h") flags.set("help", true);
926
+ else if (a2.startsWith("--")) {
927
+ const [name, inline] = a2.slice(2).split(/=(.*)/s, 2);
945
928
  if (WITH_VALUE.has(name)) {
946
- const v = inline ?? argv[++i];
947
- if (v === void 0 || v.startsWith("--")) throw new UsageError(`--${name} needs a value`);
948
- flags.set(name, v);
929
+ const v2 = inline ?? argv[++i];
930
+ if (v2 === void 0 || v2.startsWith("--")) throw new UsageError(`--${name} needs a value`);
931
+ flags.set(name, v2);
949
932
  } else if (["mailbox", "new-doc", "help"].includes(name)) flags.set(name, true);
950
933
  else throw new UsageError(`I don't know the option --${name}`);
951
- } else rest.push(a);
934
+ } else rest.push(a2);
952
935
  }
953
936
  return { command: rest[0], file: rest[1], flags };
954
937
  }
@@ -979,37 +962,37 @@ async function patiently(io, run2) {
979
962
  for (let tries = 0; ; tries++) {
980
963
  try {
981
964
  return await run2();
982
- } catch (e) {
983
- if (!(e instanceof RetryAfter) || tries > 8) throw e;
984
- await wait(io, e.seconds * 1e3 + 500);
965
+ } catch (e3) {
966
+ if (!(e3 instanceof RetryAfter) || tries > 8) throw e3;
967
+ await wait(io, e3.seconds * 1e3 + 500);
985
968
  }
986
969
  }
987
970
  }
988
971
  function server(value, mailbox) {
989
972
  if (typeof value !== "string") throw new UsageError("--server needs the address of the service");
990
- const a = parseShare(
973
+ const a2 = parseShare(
991
974
  mailbox ? `${value.replace(/\/+$/, "")}/m/${"x".repeat(22)}#pm1.${"x".repeat(43)}` : `${value}?${"x".repeat(16)}#${"x".repeat(43)}`,
992
975
  true
993
976
  );
994
- if (a.kind === "off")
977
+ if (a2.kind === "off")
995
978
  throw new UsageError("--server must be an https: address (http://localhost is allowed for development)");
996
- const u = new URL(value);
997
- return mailbox ? value.replace(/\/+$/, "") : u.origin + u.pathname;
979
+ const u2 = new URL(value);
980
+ return mailbox ? value.replace(/\/+$/, "") : u2.origin + u2.pathname;
998
981
  }
999
982
  async function feedbackOps(file, docAttr, io) {
1000
- const { id, key } = await De(docAttr);
983
+ const { id, key } = await U(docAttr);
1001
984
  const doc = await K.open({
1002
985
  doc: id,
1003
986
  key,
1004
- store: new q(),
1005
- identity: await R(),
987
+ store: new G(),
988
+ identity: await l(),
1006
989
  name: ""
1007
990
  });
1008
991
  try {
1009
992
  await doc.importFile(await io.read(file));
1010
- } catch (e) {
993
+ } catch (e3) {
1011
994
  throw new Error(
1012
- `I couldn't read ${file} as this page's feedback: ${e.message.replace(/^pipeup: /, "")}`
995
+ `I couldn't read ${file} as this page's feedback: ${e3.message.replace(/^pipeup: /, "")}`
1013
996
  );
1014
997
  }
1015
998
  return [...doc.ops()];
@@ -1028,18 +1011,18 @@ Run the same command with --new-doc and I will write a fresh one into the page.
1028
1011
  );
1029
1012
  throw new UsageError("the page needs a document identity");
1030
1013
  }
1031
- docAttr = Fe();
1014
+ docAttr = F();
1032
1015
  html = setAttribute(html, "data-pipeup-doc", docAttr);
1033
1016
  io.out("Gave the page a new document identity (data-pipeup-doc).");
1034
1017
  }
1035
- const { id } = await De(docAttr).catch(() => {
1018
+ const { id } = await U(docAttr).catch(() => {
1036
1019
  throw new UsageError("data-pipeup-doc in the page isn't a valid document identity");
1037
1020
  });
1038
1021
  const from = typeof flags.get("from") === "string" ? flags.get("from") : null;
1039
1022
  const ops = from ? await feedbackOps(from, docAttr, io) : [];
1040
1023
  const room = randomBytes(32);
1041
1024
  const key = toB64u(room);
1042
- const l = ladder(id, room);
1025
+ const l2 = ladder(id, room);
1043
1026
  const had = readAttribute(html, "data-pipeup-share");
1044
1027
  let address;
1045
1028
  let stopKey;
@@ -1052,31 +1035,31 @@ Run the same command with --new-doc and I will write a fresh one into the page.
1052
1035
  headers: create2 ? { Authorization: `Bearer ${create2}` } : {},
1053
1036
  body: JSON.stringify({ v: 1 })
1054
1037
  });
1055
- const j = await res.json().catch(() => ({}));
1038
+ const j2 = await res.json().catch(() => ({}));
1056
1039
  if (res.status === 401 || res.status === 403)
1057
1040
  throw new Error(
1058
1041
  `${host} wouldn't make a mailbox. It wants a create token: set PIPEUP_MAILBOX_CREATE_TOKEN and run again.`
1059
1042
  );
1060
- if (res.status !== 201 || typeof j.mailbox !== "string" || typeof j.stop !== "string")
1043
+ if (res.status !== 201 || typeof j2.mailbox !== "string" || typeof j2.stop !== "string")
1061
1044
  throw new Error(`${host} wouldn't make a mailbox (it answered ${res.status}).`);
1062
- const token = typeof j.token === "string" ? j.token : null;
1063
- address = `${base}/m/${j.mailbox}#pm1.${key}${token ? `.${token}` : ""}`;
1064
- stopKey = j.stop;
1065
- backend = new Mailbox({ mailbox: `${base}/m/${j.mailbox}`, ...token ? { token } : {} }, l, io.fetch);
1066
- const until = typeof j.expires === "string" ? Date.parse(j.expires) : NaN;
1067
- const keep = j.keep === "last-write" ? ", and longer each time a comment is added" : "";
1045
+ const token = typeof j2.token === "string" ? j2.token : null;
1046
+ address = `${base}/m/${j2.mailbox}#pm1.${key}${token ? `.${token}` : ""}`;
1047
+ stopKey = j2.stop;
1048
+ backend = new Mailbox({ mailbox: `${base}/m/${j2.mailbox}`, ...token ? { token } : {} }, l2, io.fetch);
1049
+ const until = typeof j2.expires === "string" ? Date.parse(j2.expires) : NaN;
1050
+ const keep = j2.keep === "last-write" ? ", and longer each time a comment is added" : "";
1068
1051
  io.out(
1069
1052
  Number.isNaN(until) ? `${host} keeps this shared copy until it is deleted.` : `${host} keeps this shared copy until ${dateWords(until)}${keep}.`
1070
1053
  );
1071
- const lim = j.limits;
1054
+ const lim = j2.limits;
1072
1055
  if (lim?.mailbox) io.out(`It holds up to ${Math.round(lim.mailbox / 1048576)} MB of comments.`);
1073
1056
  } else {
1074
- const made = await patiently(io, () => createPaste(io.fetch, base, l, "never")).catch((e) => {
1075
- throw new Error(`${host} wouldn't make a shared copy: ${e.message}`);
1057
+ const made = await patiently(io, () => createPaste(io.fetch, base, l2, "never")).catch((e3) => {
1058
+ throw new Error(`${host} wouldn't make a shared copy: ${e3.message}`);
1076
1059
  });
1077
1060
  address = `${base}?${made.id}#${key}`;
1078
1061
  stopKey = made.deleteToken;
1079
- backend = new PrivateBin({ base, paste: made.id }, l, io.fetch);
1062
+ backend = new PrivateBin({ base, paste: made.id }, l2, io.fetch);
1080
1063
  const back = await readPaste(io.fetch, base, made.id).catch(() => null);
1081
1064
  if (!back)
1082
1065
  throw new Error(
@@ -1099,34 +1082,34 @@ Run the same command with --new-doc and I will write a fresh one into the page.
1099
1082
  }
1100
1083
  async function addressOf(file, io) {
1101
1084
  const html = await io.read(file);
1102
- const a = parseShare(readAttribute(html, "data-pipeup-share"), true);
1103
- if (a.kind === "off") throw new UsageError(`${file}: ${a.reason}`);
1085
+ const a2 = parseShare(readAttribute(html, "data-pipeup-share"), true);
1086
+ if (a2.kind === "off") throw new UsageError(`${file}: ${a2.reason}`);
1104
1087
  const docAttr = readAttribute(html, "data-pipeup-doc");
1105
- const doc = docAttr ? (await De(docAttr).catch(() => null))?.id : null;
1088
+ const doc = docAttr ? (await U(docAttr).catch(() => null))?.id : null;
1106
1089
  if (!doc) throw new UsageError(`${file} has no valid data-pipeup-doc`);
1107
- return { html, a, l: ladder(doc, a.key) };
1090
+ return { html, a: a2, l: ladder(doc, a2.key) };
1108
1091
  }
1109
1092
  async function stop(file, flags, io) {
1110
1093
  const key = flags.get("key");
1111
1094
  if (typeof key !== "string") throw new UsageError("stop needs --key with the stop key that create printed");
1112
- const { a, l } = await addressOf(file, io);
1113
- if (a.kind === "mailbox") {
1114
- const res = await io.fetch(a.mailbox, { method: "DELETE", headers: { Authorization: `Bearer ${key}` } });
1095
+ const { a: a2, l: l2 } = await addressOf(file, io);
1096
+ if (a2.kind === "mailbox") {
1097
+ const res = await io.fetch(a2.mailbox, { method: "DELETE", headers: { Authorization: `Bearer ${key}` } });
1115
1098
  if (res.status === 403) throw new Error("That isn't this mailbox's stop key, so nothing was deleted.");
1116
1099
  if (res.status === 404) throw new Error("The shared copy is already gone.");
1117
1100
  if (res.status !== 204 && res.status !== 200)
1118
1101
  throw new Error(`The server answered ${res.status}, so I can't say it was deleted.`);
1119
1102
  io.out("Deleted the shared copy. Everyone keeps the comments they already have.");
1120
1103
  } else {
1121
- const b = new PrivateBin(a, l, io.fetch);
1104
+ const b2 = new PrivateBin(a2, l2, io.fetch);
1122
1105
  const later = [];
1123
- await b.read().catch(() => {
1106
+ await b2.read().catch(() => {
1124
1107
  });
1125
- for (const id of b.trail.slice(1))
1126
- later.push({ id, ttl: (await readPaste(io.fetch, a.base, id).catch(() => null))?.ttl ?? null });
1127
- const res = await deletePaste(io.fetch, a.base, a.paste, key);
1128
- const j = await res.json().catch(() => ({}));
1129
- if (j.status !== 0)
1108
+ for (const id of b2.trail.slice(1))
1109
+ later.push({ id, ttl: (await readPaste(io.fetch, a2.base, id).catch(() => null))?.ttl ?? null });
1110
+ const res = await deletePaste(io.fetch, a2.base, a2.paste, key);
1111
+ const j2 = await res.json().catch(() => ({}));
1112
+ if (j2.status !== 0)
1130
1113
  throw new Error(
1131
1114
  "That isn't this shared copy's stop key (or it is already gone), so nothing was deleted."
1132
1115
  );
@@ -1148,17 +1131,17 @@ async function stop(file, flags, io) {
1148
1131
  );
1149
1132
  }
1150
1133
  async function update(file, io) {
1151
- const { html, a, l } = await addressOf(file, io);
1152
- if (a.kind === "mailbox") return io.out("A mailbox has no newer copies, so there is nothing to update.");
1153
- const b = new PrivateBin(a, l, io.fetch);
1154
- await b.read().catch((e) => {
1134
+ const { html, a: a2, l: l2 } = await addressOf(file, io);
1135
+ if (a2.kind === "mailbox") return io.out("A mailbox has no newer copies, so there is nothing to update.");
1136
+ const b2 = new PrivateBin(a2, l2, io.fetch);
1137
+ await b2.read().catch((e3) => {
1155
1138
  throw new Error(
1156
- `I couldn't read the shared copy: ${e.message === "gone" ? "it is gone" : e.message}`
1139
+ `I couldn't read the shared copy: ${e3.message === "gone" ? "it is gone" : e3.message}`
1157
1140
  );
1158
1141
  });
1159
- if (b.head === a.paste) return io.out("The page already points at the newest copy.");
1142
+ if (b2.head === a2.paste) return io.out("The page already points at the newest copy.");
1160
1143
  const fragment = new URL(readAttribute(html, "data-pipeup-share")).hash;
1161
- await io.write(file, setAttribute(html, "data-pipeup-share", `${a.base}?${b.head}${fragment}`));
1144
+ await io.write(file, setAttribute(html, "data-pipeup-share", `${a2.base}?${b2.head}${fragment}`));
1162
1145
  io.out(`Pointed ${file} at the newest copy, so new reviewers don't have to walk through the older ones.`);
1163
1146
  }
1164
1147
  async function run(argv, io) {
@@ -1175,19 +1158,19 @@ async function run(argv, io) {
1175
1158
  else if (command === "stop") await stop(file, flags, io);
1176
1159
  else await update(file, io);
1177
1160
  return 0;
1178
- } catch (e) {
1179
- if (e instanceof UsageError) {
1180
- io.err(`${e.message.replace(/\.$/, "")}. Try: share --help`);
1161
+ } catch (e3) {
1162
+ if (e3 instanceof UsageError) {
1163
+ io.err(`${e3.message.replace(/\.$/, "")}. Try: share --help`);
1181
1164
  return 2;
1182
1165
  }
1183
- io.err(e.message);
1166
+ io.err(e3.message);
1184
1167
  return 1;
1185
1168
  }
1186
1169
  }
1187
1170
 
1188
1171
  // share/src/cli.ts
1189
1172
  process.exitCode = await run(process.argv.slice(2), {
1190
- fetch: (i, n) => fetch(i, n),
1173
+ fetch: (i, n2) => fetch(i, n2),
1191
1174
  env: process.env,
1192
1175
  read: (p2) => readFile(p2, "utf8"),
1193
1176
  write: (p2, t2) => writeFile(p2, t2),