@pipeup/share 0.8.2 → 0.9.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli.js CHANGED
@@ -164,7 +164,7 @@ function n(e3) {
164
164
  let t2 = e3;
165
165
  return "{" + Object.keys(t2).filter((e4) => void 0 !== t2[e4]).sort().map((e4) => JSON.stringify(e4) + ":" + n(t2[e4])).join(",") + "}";
166
166
  }
167
- var a = /^[A-Za-z0-9_-]{43}$/;
167
+ var o = /^[A-Za-z0-9_-]{43}$/;
168
168
  var s = /* @__PURE__ */ new Map();
169
169
  async function d() {
170
170
  let t2 = await crypto.subtle.generateKey({ name: "Ed25519" }, false, ["sign", "verify"]);
@@ -192,84 +192,85 @@ var f = (e3) => {
192
192
  };
193
193
  var m = "AI assistant";
194
194
  var g = (e3) => e3 === m || e3.startsWith(`${m} `);
195
- var y = 1e4;
196
- var w = 2 ** 40;
197
- var b = 2 ** 47;
198
- var x = 1e4;
199
- var v = /^[0-9a-f]{8}$/;
200
- var k = /^[A-Za-z0-9_-]{43}$/;
201
- var A = /^(?:[^\s@<>"]{1,64}@[^\s@<>"]{1,190}\.[^\s@<>"]{2,24}|gh:[A-Za-z0-9-]{1,39})$/;
202
- var E = /^(?:[A-Za-z0-9_-]{43}|(?:host|gh):[A-Za-z0-9._@-]{1,64})$/;
203
- var $ = /^[A-Za-z0-9_-]{43}$/;
204
- var S = /* @__PURE__ */ new Set(["create", "reply", "edit", "delete", "resolve", "reopen", "addressed", "react", "unreact", "seen", "contact", "uncontact"]);
205
- var M = /^(?:\p{Regional_Indicator}{2}|[#*0-9]\uFE0F?\u20E3|\p{Extended_Pictographic}(?:\uFE0F|\p{Emoji_Modifier})?(?:\u200D\p{Extended_Pictographic}(?:\uFE0F|\p{Emoji_Modifier})?)*)$/u;
206
- var C = (e3) => "string" == typeof e3 && M.test(e3) && [...e3].length <= 16;
207
- async function N(e3, t2) {
195
+ var y = (e3) => `${m} \xB7 ${e3.replace(/\s+/g, " ").trim() || "Agent"}`.slice(0, 80).trim();
196
+ var b = 1e4;
197
+ var x = 2 ** 40;
198
+ var v = 2 ** 47;
199
+ var k = 1e4;
200
+ var A = /^[0-9a-f]{8}$/;
201
+ var E = /^[A-Za-z0-9_-]{43}$/;
202
+ var $ = /^(?:[^\s@<>"]{1,64}@[^\s@<>"]{1,190}\.[^\s@<>"]{2,24}|gh:[A-Za-z0-9-]{1,39})$/;
203
+ var S = /^(?:[A-Za-z0-9_-]{43}|(?:host|gh):[A-Za-z0-9._@-]{1,64})$/;
204
+ var M = /^[A-Za-z0-9_-]{43}$/;
205
+ var C = /* @__PURE__ */ new Set(["create", "reply", "edit", "delete", "resolve", "reopen", "addressed", "react", "unreact", "seen", "contact", "uncontact"]);
206
+ var N = /^(?:\p{Regional_Indicator}{2}|[#*0-9]\uFE0F?\u20E3|\p{Extended_Pictographic}(?:\uFE0F|\p{Emoji_Modifier})?(?:\u200D\p{Extended_Pictographic}(?:\uFE0F|\p{Emoji_Modifier})?)*)$/u;
207
+ var O = (e3) => "string" == typeof e3 && N.test(e3) && [...e3].length <= 16;
208
+ async function q(e3, t2) {
208
209
  if (e3.author !== t2.publicKey) throw new Error("pipeup: an op must be signed by its author");
209
210
  return { body: e3, sig: await l(t2, r(n(e3))) };
210
211
  }
211
- var O = (e3, t2) => "string" == typeof e3 && e3.length <= t2;
212
- var q = (e3) => !!e3 && "object" == typeof e3;
213
- var j = (e3) => "number" == typeof e3 && Number.isFinite(e3) && e3 >= 0 && e3 <= 1;
214
- function P2(e3) {
215
- if (!q(e3)) return false;
216
- let { id: t2, path: r2, fingerprint: n2, snapshot: i, quote: o, point: a2, view: s2 } = e3;
217
- if (!(O(r2, 2e3) && O(i, 500) && "string" == typeof n2 && v.test(n2) && (void 0 === t2 || O(t2, 200) && "" !== t2) && (void 0 === o || q(o) && O(o.exact, x) && "" !== o.exact && O(o.prefix, 64) && O(o.suffix, 64)) && (void 0 === a2 || q(a2) && j(a2.x) && j(a2.y)))) return false;
212
+ var j = (e3, t2) => "string" == typeof e3 && e3.length <= t2;
213
+ var P2 = (e3) => !!e3 && "object" == typeof e3;
214
+ var T = (e3) => "number" == typeof e3 && Number.isFinite(e3) && e3 >= 0 && e3 <= 1;
215
+ function I(e3) {
216
+ if (!P2(e3)) return false;
217
+ let { id: t2, path: r2, fingerprint: n2, snapshot: i, quote: a, point: o2, view: s2 } = e3;
218
+ if (!(j(r2, 2e3) && j(i, 500) && "string" == typeof n2 && A.test(n2) && (void 0 === t2 || j(t2, 200) && "" !== t2) && (void 0 === a || P2(a) && j(a.exact, k) && "" !== a.exact && j(a.prefix, 64) && j(a.suffix, 64)) && (void 0 === o2 || P2(o2) && T(o2.x) && T(o2.y)))) return false;
218
219
  if (void 0 !== s2) {
219
- if (!q(s2) || Array.isArray(s2)) return false;
220
+ if (!P2(s2) || Array.isArray(s2)) return false;
220
221
  let e4 = Object.entries(s2);
221
- if (e4.length > 16 || !e4.every(([e5, t3]) => e5.length <= 64 && O(t3, 200))) return false;
222
+ if (e4.length > 16 || !e4.every(([e5, t3]) => e5.length <= 64 && j(t3, 200))) return false;
222
223
  }
223
224
  return true;
224
225
  }
225
- function T(e3) {
226
- if (!q(e3)) return false;
226
+ function F(e3) {
227
+ if (!P2(e3)) return false;
227
228
  let { body: t2, sig: r2 } = e3;
228
- if ("string" != typeof r2 || !q(t2) || JSON.stringify({ body: t2, sig: r2 }).length > 262144) return false;
229
+ if ("string" != typeof r2 || !P2(t2) || JSON.stringify({ body: t2, sig: r2 }).length > 262144) return false;
229
230
  let n2 = t2;
230
- if (1 !== n2.v || "string" != typeof n2.id || !k.test(n2.id) || !S.has(n2.kind) || !O(n2.doc, 64) || "" === n2.doc || "string" != typeof n2.thread || !k.test(n2.thread) || "string" != typeof n2.author || !$.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 > w || "number" != typeof n2.at || !Number.isSafeInteger(n2.at) || n2.at < 0 || n2.at > b || void 0 !== n2.text && (!O(n2.text, y) || n2.text !== n2.text.trim()) || void 0 !== n2.target && ("string" != typeof n2.target || !k.test(n2.target)) || ("create" === n2.kind || "reply" === n2.kind || "edit" === n2.kind || "addressed" === n2.kind) && !n2.text || ("reply" === n2.kind || "edit" === n2.kind || "delete" === n2.kind) && !n2.target) return false;
231
+ if (1 !== n2.v || "string" != typeof n2.id || !E.test(n2.id) || !C.has(n2.kind) || !j(n2.doc, 64) || "" === n2.doc || "string" != typeof n2.thread || !E.test(n2.thread) || "string" != typeof n2.author || !M.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 > x || "number" != typeof n2.at || !Number.isSafeInteger(n2.at) || n2.at < 0 || n2.at > v || void 0 !== n2.text && (!j(n2.text, b) || n2.text !== n2.text.trim()) || void 0 !== n2.target && ("string" != typeof n2.target || !E.test(n2.target)) || ("create" === n2.kind || "reply" === n2.kind || "edit" === n2.kind || "addressed" === n2.kind) && !n2.text || ("reply" === n2.kind || "edit" === n2.kind || "delete" === n2.kind) && !n2.target) return false;
231
232
  if (void 0 !== n2.mentions) {
232
233
  if ("create" !== n2.kind && "reply" !== n2.kind && "edit" !== n2.kind || !Array.isArray(n2.mentions) || n2.mentions.length > 20) return false;
233
234
  let e4 = n2.text?.length ?? 0;
234
235
  for (let t3 of n2.mentions) {
235
- if (!q(t3) || !Number.isSafeInteger(t3.start) || !Number.isSafeInteger(t3.end)) return false;
236
+ if (!P2(t3) || !Number.isSafeInteger(t3.start) || !Number.isSafeInteger(t3.end)) return false;
236
237
  let { start: r3, end: n3, ref: i } = t3;
237
- if (r3 < 0 || n3 <= r3 || n3 > e4 || "string" != typeof i || !E.test(i)) return false;
238
+ if (r3 < 0 || n3 <= r3 || n3 > e4 || "string" != typeof i || !S.test(i)) return false;
238
239
  }
239
240
  }
240
- return !(!("contact" !== n2.kind || "string" == typeof n2.text && A.test(n2.text)) || "seen" === n2.kind && !n2.target || !("react" !== n2.kind && "unreact" !== n2.kind || n2.target && C(n2.text)) || !("create" !== n2.kind || n2.id === n2.thread && P2(n2.anchor)));
241
+ return !(!("contact" !== n2.kind || "string" == typeof n2.text && $.test(n2.text)) || "seen" === n2.kind && !n2.target || !("react" !== n2.kind && "unreact" !== n2.kind || n2.target && O(n2.text)) || !("create" !== n2.kind || n2.id === n2.thread && I(n2.anchor)));
241
242
  }
242
- function I(i) {
243
+ function L(i) {
243
244
  return (async function(r2, n2, i2) {
244
- if (!a.test(r2)) return false;
245
+ if (!o.test(r2)) return false;
245
246
  try {
246
247
  if (e(t(r2)) !== r2) return false;
247
- let o = s.get(r2);
248
- if (!o) {
249
- s.size >= 512 && s.delete(s.keys().next().value), o = crypto.subtle.importKey("raw", t(r2), { name: "Ed25519" }, true, ["verify"]), s.set(r2, o);
250
- let e3 = o;
248
+ let a = s.get(r2);
249
+ if (!a) {
250
+ s.size >= 512 && s.delete(s.keys().next().value), a = crypto.subtle.importKey("raw", t(r2), { name: "Ed25519" }, true, ["verify"]), s.set(r2, a);
251
+ let e3 = a;
251
252
  e3.catch(() => {
252
253
  s.get(r2) === e3 && s.delete(r2);
253
254
  });
254
255
  }
255
- return await crypto.subtle.verify({ name: "Ed25519" }, await o, t(i2), n2);
256
+ return await crypto.subtle.verify({ name: "Ed25519" }, await a, t(i2), n2);
256
257
  } catch {
257
258
  return false;
258
259
  }
259
260
  })(i.body.author, r(n(i.body)), i.sig);
260
261
  }
261
- function F(e3, t2) {
262
+ function D(e3, t2) {
262
263
  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;
263
264
  }
264
- function L(e3, t2, r2, n2, i, o) {
265
- let a2 = { id: e3, author: t2, name: r2, text: n2, at: i, edited: false, deleted: false, replies: [], reactions: [] };
266
- return o?.length && (a2.mentions = o), a2;
265
+ function U(e3, t2, r2, n2, i, a) {
266
+ let o2 = { id: e3, author: t2, name: r2, text: n2, at: i, edited: false, deleted: false, replies: [], reactions: [] };
267
+ return a?.length && (o2.mentions = a), o2;
267
268
  }
268
- async function R(t2) {
269
- let i = { ...t2, id: void 0, thread: "create" === t2.kind ? void 0 : t2.thread }, o = await crypto.subtle.digest("SHA-256", r(n(i)));
270
- return e(new Uint8Array(o));
269
+ async function B(t2) {
270
+ let i = { ...t2, id: void 0, thread: "create" === t2.kind ? void 0 : t2.thread }, a = await crypto.subtle.digest("SHA-256", r(n(i)));
271
+ return e(new Uint8Array(a));
271
272
  }
272
- var D = class {
273
+ var _ = class {
273
274
  constructor(e3) {
274
275
  this.doc = e3;
275
276
  }
@@ -286,10 +287,10 @@ var D = class {
286
287
  threads() {
287
288
  return (function(e3) {
288
289
  let t2 = /* @__PURE__ */ new Map(), r2 = /* @__PURE__ */ new Map(), n2 = /* @__PURE__ */ new Map();
289
- for (let { body: i2 } of [...e3].sort(F)) {
290
- if (i2.name && n2.set(i2.author, i2.name), "create" === i2.kind) {
290
+ for (let { body: i2 } of [...e3].sort(D)) {
291
+ if (i2.name && !g(i2.name) && n2.set(i2.author, i2.name), "create" === i2.kind) {
291
292
  if (t2.has(i2.id) || !i2.anchor || void 0 === i2.text) continue;
292
- let e5 = L(i2.id, i2.author, i2.name, i2.text, i2.at, i2.mentions);
293
+ let e5 = U(i2.id, i2.author, i2.name, i2.text, i2.at, i2.mentions);
293
294
  t2.set(i2.id, { id: i2.id, anchor: i2.anchor, root: e5, resolved: false }), r2.set(i2.id, { comment: e5, thread: i2.id });
294
295
  continue;
295
296
  }
@@ -303,47 +304,47 @@ var D = class {
303
304
  void 0 !== i2.text && (e4.addressed = { text: i2.text, author: i2.author, name: i2.name, at: i2.at });
304
305
  continue;
305
306
  }
306
- let o2 = i2.target ? r2.get(i2.target) : void 0;
307
- if (o2 && o2.thread === i2.thread) {
307
+ let a2 = i2.target ? r2.get(i2.target) : void 0;
308
+ if (a2 && a2.thread === i2.thread) {
308
309
  if ("reply" === i2.kind) {
309
310
  if (r2.has(i2.id) || void 0 === i2.text) continue;
310
- let t3 = L(i2.id, i2.author, i2.name, i2.text, i2.at, i2.mentions);
311
+ let t3 = U(i2.id, i2.author, i2.name, i2.text, i2.at, i2.mentions);
311
312
  e4.root.replies.push(t3), r2.set(i2.id, { comment: t3, thread: i2.thread });
312
313
  continue;
313
314
  }
314
315
  if ("seen" === i2.kind) {
315
- let e5 = o2.comment.seenBy ??= [];
316
+ let e5 = a2.comment.seenBy ??= [];
316
317
  e5.includes(i2.author) || e5.push(i2.author);
317
318
  continue;
318
319
  }
319
320
  if ("react" === i2.kind || "unreact" === i2.kind) {
320
- if (void 0 === i2.text || o2.comment.deleted) continue;
321
- let e5 = o2.comment.reactions, t3 = e5.find((e6) => e6.emoji === i2.text);
321
+ if (void 0 === i2.text || a2.comment.deleted) continue;
322
+ let e5 = a2.comment.reactions, t3 = e5.find((e6) => e6.emoji === i2.text);
322
323
  if ("react" === i2.kind) {
323
324
  let r3 = { author: i2.author, name: i2.name };
324
325
  t3 ? t3.by.some((e6) => e6.author === i2.author) || t3.by.push(r3) : e5.length < 12 && e5.push({ emoji: i2.text, by: [r3] });
325
326
  } else t3 && (t3.by = t3.by.filter((e6) => e6.author !== i2.author), t3.by.length || e5.splice(e5.indexOf(t3), 1));
326
327
  continue;
327
328
  }
328
- i2.author !== o2.comment.author || o2.comment.deleted || ("edit" === i2.kind && void 0 !== i2.text && (o2.comment.text = i2.text, o2.comment.edited = true, i2.mentions ? o2.comment.mentions = i2.mentions : delete o2.comment.mentions), "delete" === i2.kind && (o2.comment.text = "", o2.comment.deleted = true, o2.comment.reactions = [], delete o2.comment.mentions));
329
+ i2.author !== a2.comment.author || a2.comment.deleted || ("edit" === i2.kind && void 0 !== i2.text && (a2.comment.text = i2.text, a2.comment.edited = true, i2.mentions ? a2.comment.mentions = i2.mentions : delete a2.comment.mentions), "delete" === i2.kind && (a2.comment.text = "", a2.comment.deleted = true, a2.comment.reactions = [], delete a2.comment.mentions));
329
330
  }
330
331
  }
331
332
  for (let { comment: e4 } of r2.values()) {
332
333
  e4.name || (e4.unnamed = true, e4.name = n2.get(e4.author) ?? "");
333
334
  for (let t3 of e4.reactions) for (let e5 of t3.by) e5.name ||= n2.get(e5.author) ?? "";
334
335
  }
335
- let i = /* @__PURE__ */ new Map(), o = (e4, t3) => {
336
+ let i = /* @__PURE__ */ new Map(), a = (e4, t3) => {
336
337
  let r3 = f({ author: e4, name: t3 }).toLowerCase();
337
338
  (i.get(r3) ?? i.set(r3, /* @__PURE__ */ new Set()).get(r3)).add(e4);
338
339
  };
339
340
  for (let { comment: e4 } of r2.values()) {
340
- o(e4.author, e4.name);
341
- for (let t3 of e4.reactions) for (let e5 of t3.by) o(e5.author, e5.name);
341
+ a(e4.author, e4.name);
342
+ for (let t3 of e4.reactions) for (let e5 of t3.by) a(e5.author, e5.name);
342
343
  }
343
- let a2 = (e4, t3) => (i.get(f({ author: e4, name: t3 }).toLowerCase())?.size ?? 0) > 1;
344
+ let o2 = (e4, t3) => !g(t3) && (i.get(f({ author: e4, name: t3 }).toLowerCase())?.size ?? 0) > 1;
344
345
  for (let { comment: e4 } of r2.values()) {
345
- a2(e4.author, e4.name) && (e4.alike = true);
346
- for (let t3 of e4.reactions) for (let e5 of t3.by) a2(e5.author, e5.name) && (e5.alike = true);
346
+ o2(e4.author, e4.name) && (e4.alike = true);
347
+ for (let t3 of e4.reactions) for (let e5 of t3.by) o2(e5.author, e5.name) && (e5.alike = true);
347
348
  }
348
349
  return [...t2.values()];
349
350
  })(this.ops.values());
@@ -351,80 +352,80 @@ var D = class {
351
352
  async add(e3) {
352
353
  let t2 = [];
353
354
  for (let r2 of e3) {
354
- if (!T(r2) || r2.body.doc !== this.doc || this.ops.has(r2.body.id) || r2.body.id !== await R(r2.body) || !await I(r2)) continue;
355
+ if (!F(r2) || r2.body.doc !== this.doc || this.ops.has(r2.body.id) || r2.body.id !== await B(r2.body) || !await L(r2)) continue;
355
356
  let e4 = { body: r2.body, sig: r2.sig };
356
357
  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);
357
358
  }
358
359
  return t2;
359
360
  }
360
361
  async append(e3, t2, r2) {
361
- 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, w), at: Math.min(Math.max(Date.now(), "create" === r2.kind ? (this.createAt.get(e3.publicKey) ?? 0) + 1 : (this.threadAt.get(r2.thread) ?? 0) + 1), b) };
362
- n2.id = await R(n2);
362
+ 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, x), at: Math.min(Math.max(Date.now(), "create" === r2.kind ? (this.createAt.get(e3.publicKey) ?? 0) + 1 : (this.threadAt.get(r2.thread) ?? 0) + 1), v) };
363
+ n2.id = await B(n2);
363
364
  let i = this.ops.get(n2.id);
364
365
  if (i) return i;
365
366
  "create" === n2.kind && (n2.thread = n2.id);
366
- let [o] = await this.add([await N(n2, e3)]);
367
- if (!o) throw new Error("pipeup: could not record this change");
368
- return o;
367
+ let [a] = await this.add([await q(n2, e3)]);
368
+ if (!a) throw new Error("pipeup: could not record this change");
369
+ return a;
369
370
  }
370
371
  };
371
- var U = /^([A-Za-z0-9_-]{16}):([A-Za-z0-9_-]{43})$/;
372
- function B() {
372
+ var z = /^([A-Za-z0-9_-]{16}):([A-Za-z0-9_-]{43})$/;
373
+ function H() {
373
374
  return `${(function(t2 = 16) {
374
375
  return e(crypto.getRandomValues(new Uint8Array(t2)));
375
376
  })(12)}:${e(crypto.getRandomValues(new Uint8Array(32)))}`;
376
377
  }
377
- async function _(e3) {
378
- let r2 = U.exec(e3.trim()), n2 = r2?.[1], i = r2?.[2];
378
+ async function K(e3) {
379
+ let r2 = z.exec(e3.trim()), n2 = r2?.[1], i = r2?.[2];
379
380
  if (!n2 || !i) throw new Error('pipeup: data-pipeup-doc must look like "<id>:<key>", as made by newDocumentAttribute()');
380
381
  return { id: n2, key: await crypto.subtle.importKey("raw", t(i), { name: "AES-GCM" }, false, ["encrypt", "decrypt"]) };
381
382
  }
382
- async function z(t2, n2, i) {
383
- let o = crypto.getRandomValues(new Uint8Array(12)), a2 = await crypto.subtle.encrypt({ name: "AES-GCM", iv: o, additionalData: r(i) }, t2, r(n2));
384
- return { iv: e(o), data: e(new Uint8Array(a2)) };
383
+ async function G(t2, n2, i) {
384
+ let a = crypto.getRandomValues(new Uint8Array(12)), o2 = await crypto.subtle.encrypt({ name: "AES-GCM", iv: a, additionalData: r(i) }, t2, r(n2));
385
+ return { iv: e(a), data: e(new Uint8Array(o2)) };
385
386
  }
386
- var H = (e3) => `pipeup-file:${e3}`;
387
- async function K(e3, n2, i) {
387
+ var Z = (e3) => `pipeup-file:${e3}`;
388
+ async function J(e3, n2, i) {
388
389
  if (e3.length > 5e6) throw new Error("pipeup: this feedback file is too large");
389
- let o, a2, s2;
390
+ let a, o2, s2;
390
391
  try {
391
- o = JSON.parse(e3);
392
+ a = JSON.parse(e3);
392
393
  } catch {
393
394
  throw new Error("pipeup: this is not an Pipeup feedback file");
394
395
  }
395
- if (!o || "object" != typeof o || 1 !== o.pipeup || "string" != typeof o.doc) throw new Error("pipeup: this is not an Pipeup feedback file");
396
- if (o.doc !== n2) throw new Error("pipeup: this feedback is for a different document");
397
- if (!o.sealed) return Array.isArray(o.ops) ? o.ops : [];
396
+ if (!a || "object" != typeof a || 1 !== a.pipeup || "string" != typeof a.doc) throw new Error("pipeup: this is not an Pipeup feedback file");
397
+ if (a.doc !== n2) throw new Error("pipeup: this feedback is for a different document");
398
+ if (!a.sealed) return Array.isArray(a.ops) ? a.ops : [];
398
399
  if (!i) throw new Error("pipeup: this feedback is sealed, and this page has no document key");
399
- if ("string" != typeof o.iv || "string" != typeof o.data) throw new Error("pipeup: this is not an Pipeup feedback file");
400
+ if ("string" != typeof a.iv || "string" != typeof a.data) throw new Error("pipeup: this is not an Pipeup feedback file");
400
401
  try {
401
- a2 = await (async function(e4, n3, i2) {
402
+ o2 = await (async function(e4, n3, i2) {
402
403
  try {
403
- let o2 = await crypto.subtle.decrypt({ name: "AES-GCM", iv: t(n3.iv), additionalData: r(i2) }, e4, t(n3.data));
404
- return new TextDecoder().decode(o2);
404
+ let a2 = await crypto.subtle.decrypt({ name: "AES-GCM", iv: t(n3.iv), additionalData: r(i2) }, e4, t(n3.data));
405
+ return new TextDecoder().decode(a2);
405
406
  } catch {
406
407
  throw new Error("pipeup: this feedback could not be opened with this document");
407
408
  }
408
- })(i, { iv: o.iv, data: o.data }, H(n2));
409
+ })(i, { iv: a.iv, data: a.data }, Z(n2));
409
410
  } catch {
410
411
  throw new Error("pipeup: this feedback could not be opened with this document's key");
411
412
  }
412
413
  try {
413
- s2 = JSON.parse(a2);
414
+ s2 = JSON.parse(o2);
414
415
  } catch {
415
416
  throw new Error("pipeup: this is not an Pipeup feedback file");
416
417
  }
417
418
  return Array.isArray(s2) ? s2 : [];
418
419
  }
419
- var G = /^[a-z][a-z0-9-]{1,23}\/[a-z][a-z0-9-]{0,31}$/;
420
- var Z = class extends Error {
420
+ var V = /^[a-z][a-z0-9-]{1,23}\/[a-z][a-z0-9-]{0,31}$/;
421
+ var W = class extends Error {
421
422
  constructor(e3, t2, r2 = 1) {
422
423
  super("pipeup: shown here, but not saved yet"), this.id = e3, this.cause = t2, this.count = r2, this.name = "UnsavedChangeError";
423
424
  }
424
425
  };
425
- var J = class e2 {
426
+ var Q = class e2 {
426
427
  constructor(e3, t2) {
427
- this.log = e3, this.options = t2, this.displayName = t2.name.trim() ? Q(t2.name) : "";
428
+ this.log = e3, this.options = t2, this.displayName = t2.name.trim() ? ee(t2.name) : "";
428
429
  }
429
430
  listeners = /* @__PURE__ */ new Set();
430
431
  cache = [];
@@ -434,10 +435,10 @@ var J = class e2 {
434
435
  unsaved = [];
435
436
  static async open(t2) {
436
437
  if ("string" != typeof t2.doc || "" === t2.doc || t2.doc.length > 64) throw new Error("pipeup: the document id must be 1 to 64 characters");
437
- let r2 = new D(t2.doc), n2 = await t2.store.load(t2.doc), i = n2.length - (await r2.add(n2)).length;
438
+ let r2 = new _(t2.doc), n2 = await t2.store.load(t2.doc), i = n2.length - (await r2.add(n2)).length;
438
439
  i && console.warn(`pipeup: ${i} saved change${1 === i ? "" : "s"} on this page couldn't be read; kept as saved`);
439
- let o = new e2(r2, t2);
440
- return o.refresh(false), o;
440
+ let a = new e2(r2, t2);
441
+ return a.refresh(false), a;
441
442
  }
442
443
  get id() {
443
444
  return this.options.doc;
@@ -449,7 +450,7 @@ var J = class e2 {
449
450
  return this.displayName;
450
451
  }
451
452
  set name(e3) {
452
- this.displayName = Q(e3), this.refresh(true, [], "");
453
+ this.displayName = ee(e3), this.refresh(true, [], "");
453
454
  }
454
455
  threads() {
455
456
  return this.cache;
@@ -461,15 +462,15 @@ var J = class e2 {
461
462
  return this.listeners.add(e3), () => this.listeners.delete(e3);
462
463
  }
463
464
  comment(e3, t2, r2) {
464
- return this.enqueue(() => this.write({ kind: "create", anchor: e3, text: V(t2), ...r2?.length ? { mentions: r2 } : {} }));
465
+ return this.enqueue(() => this.write({ kind: "create", anchor: e3, text: X(t2), ...r2?.length ? { mentions: r2 } : {} }));
465
466
  }
466
467
  reply(e3, t2, r2) {
467
- return this.enqueue(() => this.write({ kind: "reply", thread: this.find(e3).thread, target: e3, text: V(t2), ...r2?.length ? { mentions: r2 } : {} }));
468
+ return this.enqueue(() => this.write({ kind: "reply", thread: this.find(e3).thread, target: e3, text: X(t2), ...r2?.length ? { mentions: r2 } : {} }));
468
469
  }
469
470
  edit(e3, t2, r2) {
470
471
  return this.enqueue(async () => {
471
472
  let { thread: n2 } = this.mine(e3);
472
- await this.write({ kind: "edit", thread: n2, target: e3, text: V(t2), ...r2?.length ? { mentions: r2 } : {} });
473
+ await this.write({ kind: "edit", thread: n2, target: e3, text: X(t2), ...r2?.length ? { mentions: r2 } : {} });
473
474
  });
474
475
  }
475
476
  remove(e3) {
@@ -480,7 +481,7 @@ var J = class e2 {
480
481
  }
481
482
  contact(e3) {
482
483
  let t2 = e3.trim();
483
- return A.test(t2) ? this.enqueue(async () => {
484
+ return $.test(t2) ? this.enqueue(async () => {
484
485
  await this.write({ kind: "contact", thread: this.me, text: t2 });
485
486
  }) : Promise.reject(new Error("pipeup: that isn't an email address or a GitHub name"));
486
487
  }
@@ -491,7 +492,7 @@ var J = class e2 {
491
492
  }
492
493
  contacts() {
493
494
  let e3 = /* @__PURE__ */ new Map();
494
- for (let { body: t2 } of [...this.log.all()].sort(F)) "contact" === t2.kind && t2.text ? e3.set(t2.author, t2.text) : "uncontact" === t2.kind && e3.delete(t2.author);
495
+ for (let { body: t2 } of [...this.log.all()].sort(D)) "contact" === t2.kind && t2.text ? e3.set(t2.author, t2.text) : "uncontact" === t2.kind && e3.delete(t2.author);
495
496
  return e3;
496
497
  }
497
498
  get portable() {
@@ -513,12 +514,12 @@ var J = class e2 {
513
514
  }
514
515
  react(e3, t2) {
515
516
  return this.enqueue(async () => {
516
- await this.write({ kind: "react", thread: this.find(e3).thread, target: e3, text: W(t2) });
517
+ await this.write({ kind: "react", thread: this.find(e3).thread, target: e3, text: Y(t2) });
517
518
  });
518
519
  }
519
520
  unreact(e3, t2) {
520
521
  return this.enqueue(async () => {
521
- await this.write({ kind: "unreact", thread: this.find(e3).thread, target: e3, text: W(t2) });
522
+ await this.write({ kind: "unreact", thread: this.find(e3).thread, target: e3, text: Y(t2) });
522
523
  });
523
524
  }
524
525
  resolve(e3) {
@@ -531,8 +532,14 @@ var J = class e2 {
531
532
  await this.write({ kind: "reopen", thread: this.thread(e3) });
532
533
  });
533
534
  }
535
+ paste(e3, t2, r2, n2) {
536
+ return this.enqueue(async () => {
537
+ let i = this.thread(e3), a = y(t2), o2 = this.cache.find((e4) => e4.id === i).root.id;
538
+ await this.write({ kind: "reply", thread: i, target: o2, text: X(r2) }, a), n2?.trim() && await this.write({ kind: "addressed", thread: i, text: X(n2) }, a);
539
+ });
540
+ }
534
541
  sign(e3, t2) {
535
- if (!G.test(e3)) throw new Error('pipeup: a signing purpose looks like "<add-on id>/<name>"');
542
+ if (!V.test(e3)) throw new Error('pipeup: a signing purpose looks like "<add-on id>/<name>"');
536
543
  return l(this.options.identity, r(`pipeup:${e3}
537
544
  ${t2}`));
538
545
  }
@@ -541,12 +548,12 @@ ${t2}`));
541
548
  }
542
549
  exportFile() {
543
550
  return (async function(e3, t2, r2) {
544
- let n2 = r2 ? { pipeup: 1, doc: e3, sealed: true, ...await z(r2, JSON.stringify(t2), H(e3)) } : { pipeup: 1, doc: e3, sealed: false, ops: t2 };
551
+ let n2 = r2 ? { pipeup: 1, doc: e3, sealed: true, ...await G(r2, JSON.stringify(t2), Z(e3)) } : { pipeup: 1, doc: e3, sealed: false, ops: t2 };
545
552
  return JSON.stringify(n2, null, 2);
546
553
  })(this.options.doc, this.log.all(), this.options.key);
547
554
  }
548
555
  async importFile(e3) {
549
- return this.merge(await K(e3, this.options.doc, this.options.key), "file");
556
+ return this.merge(await J(e3, this.options.doc, this.options.key), "file");
550
557
  }
551
558
  merge(e3, t2) {
552
559
  return e3.length > 5e3 ? Promise.reject(new RangeError("pipeup: too many changes to merge at once")) : this.enqueue(async () => {
@@ -555,7 +562,7 @@ ${t2}`));
555
562
  try {
556
563
  await this.persist();
557
564
  } catch (e4) {
558
- throw r2.length > 0 ? new Z(r2[0].body.id, e4, r2.length) : e4;
565
+ throw r2.length > 0 ? new W(r2[0].body.id, e4, r2.length) : e4;
559
566
  }
560
567
  return r2.length;
561
568
  });
@@ -565,15 +572,15 @@ ${t2}`));
565
572
  return this.e = t2.catch(() => {
566
573
  }), t2;
567
574
  }
568
- async write(e3) {
569
- let t2 = await this.log.append(this.options.identity, this.displayName, e3);
570
- this.unsaved.push(t2), this.refresh(true, [t2], "local");
575
+ async write(e3, t2 = this.displayName) {
576
+ let r2 = await this.log.append(this.options.identity, t2, e3);
577
+ this.unsaved.push(r2), this.refresh(true, [r2], "local");
571
578
  try {
572
579
  await this.persist();
573
580
  } catch (e4) {
574
- throw new Z(t2.body.id, e4);
581
+ throw new W(r2.body.id, e4);
575
582
  }
576
- return t2.body.id;
583
+ return r2.body.id;
577
584
  }
578
585
  async persist() {
579
586
  if (0 === this.unsaved.length) return;
@@ -608,23 +615,23 @@ ${t2}`));
608
615
  return e3;
609
616
  }
610
617
  };
611
- function V(e3) {
618
+ function X(e3) {
612
619
  let t2 = e3.trim();
613
620
  if (!t2) throw new Error("pipeup: a comment needs some words");
614
- if (t2.length > y) throw new Error(`pipeup: comments are limited to ${y} characters`);
621
+ if (t2.length > b) throw new Error(`pipeup: comments are limited to ${b} characters`);
615
622
  return t2;
616
623
  }
617
- function W(e3) {
618
- if (!C(e3)) throw new Error("pipeup: a reaction is one emoji");
624
+ function Y(e3) {
625
+ if (!O(e3)) throw new Error("pipeup: a reaction is one emoji");
619
626
  return e3;
620
627
  }
621
- function Q(e3) {
628
+ function ee(e3) {
622
629
  let t2 = e3.replace(/\s+/g, " ").trim();
623
630
  if (!t2 || t2.length > 80) throw new Error("pipeup: choose a name of 1 to 80 characters");
624
631
  if (g(t2)) throw new Error("pipeup: that name is kept for AI replies; choose another");
625
632
  return t2;
626
633
  }
627
- var X = class {
634
+ var te = class {
628
635
  docs = /* @__PURE__ */ new Map();
629
636
  profile = null;
630
637
  async load(e3) {
@@ -731,15 +738,15 @@ var retryAfter = (res, fallback = 10) => {
731
738
  const n2 = Number(res.headers.get("Retry-After"));
732
739
  return n2 > 0 ? Math.min(n2, 3600) : fallback;
733
740
  };
734
- var idsOf = (ops) => ops.map((o) => o?.body?.id).filter((i) => typeof i === "string");
741
+ var idsOf = (ops) => ops.map((o2) => o2?.body?.id).filter((i) => typeof i === "string");
735
742
 
736
743
  // share/src/mailbox.ts
737
744
  var MAX_BODY = 524288;
738
745
  var MAX_PAGES = 1e3;
739
746
  var batchId = async (ct) => toB64u(await sha256(utf8(ct))).slice(0, 22);
740
747
  var Mailbox = class {
741
- constructor(a2, l2, f2, signal) {
742
- this.a = a2;
748
+ constructor(a, l2, f2, signal) {
749
+ this.a = a;
743
750
  this.l = l2;
744
751
  this.f = f2;
745
752
  this.signal = signal;
@@ -769,10 +776,10 @@ var Mailbox = class {
769
776
  if (typeof b2?.id !== "string" || typeof b2.ct !== "string" || this.seen.has(b2.id)) continue;
770
777
  this.seen.add(b2.id);
771
778
  const bytes = fromText(b2.ct);
772
- const o = bytes && await open(this.l, "share", bytes);
773
- if (!o) continue;
774
- out.push(o);
775
- for (const id of idsOf(o.ops)) this.ids.add(id);
779
+ const o2 = bytes && await open(this.l, "share", bytes);
780
+ if (!o2) continue;
781
+ out.push(o2);
782
+ for (const id of idsOf(o2.ops)) this.ids.add(id);
776
783
  }
777
784
  if (typeof j2.next === "string") this.cursor = j2.next;
778
785
  this.expires = typeof j2.expires === "string" ? Date.parse(j2.expires) || null : null;
@@ -782,7 +789,7 @@ var Mailbox = class {
782
789
  }
783
790
  /** The POST for these ops. A retry of the same ops reuses its sealed text and id, so the server collapses it. */
784
791
  async req(ops) {
785
- const key = ops.map((o) => o.body.id).join();
792
+ const key = ops.map((o2) => o2.body.id).join();
786
793
  if (this.memo?.key !== key) {
787
794
  const ct2 = toText(await seal(this.l, "share", ops));
788
795
  this.memo = { key, ct: ct2, id: await batchId(ct2) };
@@ -858,15 +865,15 @@ async function readPaste(f2, base, id, signal) {
858
865
  return { j: j2, size, ttl: typeof ttl === "number" && ttl > 0 ? ttl * 1e3 : null };
859
866
  }
860
867
  var PrivateBin = class {
861
- constructor(a2, l2, f2, signal, gen, onGen = () => {
868
+ constructor(a, l2, f2, signal, gen, onGen = () => {
862
869
  }) {
863
- this.a = a2;
870
+ this.a = a;
864
871
  this.l = l2;
865
872
  this.f = f2;
866
873
  this.signal = signal;
867
874
  this.onGen = onGen;
868
- this.head = gen || a2.paste;
869
- this.trail.push(a2.paste);
875
+ this.head = gen || a.paste;
876
+ this.trail.push(a.paste);
870
877
  }
871
878
  ids = /* @__PURE__ */ new Set();
872
879
  expires = null;
@@ -1034,17 +1041,17 @@ function parseArgs(argv) {
1034
1041
  const flags = /* @__PURE__ */ new Map();
1035
1042
  const rest = [];
1036
1043
  for (let i = 0; i < argv.length; i++) {
1037
- const a2 = argv[i];
1038
- if (a2 === "-h") flags.set("help", true);
1039
- else if (a2.startsWith("--")) {
1040
- const [name, inline] = a2.slice(2).split(/=(.*)/s, 2);
1044
+ const a = argv[i];
1045
+ if (a === "-h") flags.set("help", true);
1046
+ else if (a.startsWith("--")) {
1047
+ const [name, inline] = a.slice(2).split(/=(.*)/s, 2);
1041
1048
  if (WITH_VALUE.has(name)) {
1042
1049
  const v2 = inline ?? argv[++i];
1043
1050
  if (v2 === void 0 || v2.startsWith("--")) throw new UsageError(`--${name} needs a value`);
1044
1051
  flags.set(name, v2);
1045
1052
  } else if (["mailbox", "new-doc", "help"].includes(name)) flags.set(name, true);
1046
1053
  else throw new UsageError(`I don't know the option --${name}`);
1047
- } else rest.push(a2);
1054
+ } else rest.push(a);
1048
1055
  }
1049
1056
  return { command: rest[0], file: rest[1], flags };
1050
1057
  }
@@ -1083,21 +1090,21 @@ async function patiently(io, run2) {
1083
1090
  }
1084
1091
  function server(value, mailbox) {
1085
1092
  if (typeof value !== "string") throw new UsageError("--server needs the address of the service");
1086
- const a2 = parseShare(
1093
+ const a = parseShare(
1087
1094
  mailbox ? `${value.replace(/\/+$/, "")}/m/${"x".repeat(22)}#pm1.${"x".repeat(43)}` : `${value}?${"x".repeat(16)}#${"x".repeat(43)}`,
1088
1095
  true
1089
1096
  );
1090
- if (a2.kind === "off")
1097
+ if (a.kind === "off")
1091
1098
  throw new UsageError("--server must be an https: address (http://localhost is allowed for development)");
1092
1099
  const u2 = new URL(value);
1093
1100
  return mailbox ? value.replace(/\/+$/, "") : u2.origin + u2.pathname;
1094
1101
  }
1095
1102
  async function feedbackOps(file, docAttr, io) {
1096
- const { id, key } = await _(docAttr);
1097
- const doc = await J.open({
1103
+ const { id, key } = await K(docAttr);
1104
+ const doc = await Q.open({
1098
1105
  doc: id,
1099
1106
  key,
1100
- store: new X(),
1107
+ store: new te(),
1101
1108
  identity: await d(),
1102
1109
  name: ""
1103
1110
  });
@@ -1124,11 +1131,11 @@ Run the same command with --new-doc and I will write a fresh one into the page.
1124
1131
  );
1125
1132
  throw new UsageError("the page needs a document identity");
1126
1133
  }
1127
- docAttr = B();
1134
+ docAttr = H();
1128
1135
  html = setAttribute(html, "data-pipeup-doc", docAttr);
1129
1136
  io.out("Gave the page a new document identity (data-pipeup-doc).");
1130
1137
  }
1131
- const { id } = await _(docAttr).catch(() => {
1138
+ const { id } = await K(docAttr).catch(() => {
1132
1139
  throw new UsageError("data-pipeup-doc in the page isn't a valid document identity");
1133
1140
  });
1134
1141
  const from = typeof flags.get("from") === "string" ? flags.get("from") : null;
@@ -1195,32 +1202,32 @@ Run the same command with --new-doc and I will write a fresh one into the page.
1195
1202
  }
1196
1203
  async function addressOf(file, io) {
1197
1204
  const html = await io.read(file);
1198
- const a2 = parseShare(readAttribute(html, "data-pipeup-share"), true);
1199
- if (a2.kind === "off") throw new UsageError(`${file}: ${a2.reason}`);
1205
+ const a = parseShare(readAttribute(html, "data-pipeup-share"), true);
1206
+ if (a.kind === "off") throw new UsageError(`${file}: ${a.reason}`);
1200
1207
  const docAttr = readAttribute(html, "data-pipeup-doc");
1201
- const doc = docAttr ? (await _(docAttr).catch(() => null))?.id : null;
1208
+ const doc = docAttr ? (await K(docAttr).catch(() => null))?.id : null;
1202
1209
  if (!doc) throw new UsageError(`${file} has no valid data-pipeup-doc`);
1203
- return { html, a: a2, l: ladder(doc, a2.key) };
1210
+ return { html, a, l: ladder(doc, a.key) };
1204
1211
  }
1205
1212
  async function stop(file, flags, io) {
1206
1213
  const key = flags.get("key");
1207
1214
  if (typeof key !== "string") throw new UsageError("stop needs --key with the stop key that create printed");
1208
- const { a: a2, l: l2 } = await addressOf(file, io);
1209
- if (a2.kind === "mailbox") {
1210
- const res = await io.fetch(a2.mailbox, { method: "DELETE", headers: { Authorization: `Bearer ${key}` } });
1215
+ const { a, l: l2 } = await addressOf(file, io);
1216
+ if (a.kind === "mailbox") {
1217
+ const res = await io.fetch(a.mailbox, { method: "DELETE", headers: { Authorization: `Bearer ${key}` } });
1211
1218
  if (res.status === 403) throw new Error("That isn't this mailbox's stop key, so nothing was deleted.");
1212
1219
  if (res.status === 404) throw new Error("The shared copy is already gone.");
1213
1220
  if (res.status !== 204 && res.status !== 200)
1214
1221
  throw new Error(`The server answered ${res.status}, so I can't say it was deleted.`);
1215
1222
  io.out("Deleted the shared copy. Everyone keeps the comments they already have.");
1216
1223
  } else {
1217
- const b2 = new PrivateBin(a2, l2, io.fetch);
1224
+ const b2 = new PrivateBin(a, l2, io.fetch);
1218
1225
  const later = [];
1219
1226
  await b2.read().catch(() => {
1220
1227
  });
1221
1228
  for (const id of b2.trail.slice(1))
1222
- later.push({ id, ttl: (await readPaste(io.fetch, a2.base, id).catch(() => null))?.ttl ?? null });
1223
- const res = await deletePaste(io.fetch, a2.base, a2.paste, key);
1229
+ later.push({ id, ttl: (await readPaste(io.fetch, a.base, id).catch(() => null))?.ttl ?? null });
1230
+ const res = await deletePaste(io.fetch, a.base, a.paste, key);
1224
1231
  const j2 = await res.json().catch(() => ({}));
1225
1232
  if (j2.status !== 0)
1226
1233
  throw new Error(
@@ -1244,17 +1251,17 @@ async function stop(file, flags, io) {
1244
1251
  );
1245
1252
  }
1246
1253
  async function update(file, io) {
1247
- const { html, a: a2, l: l2 } = await addressOf(file, io);
1248
- if (a2.kind === "mailbox") return io.out("A mailbox has no newer copies, so there is nothing to update.");
1249
- const b2 = new PrivateBin(a2, l2, io.fetch);
1254
+ const { html, a, l: l2 } = await addressOf(file, io);
1255
+ if (a.kind === "mailbox") return io.out("A mailbox has no newer copies, so there is nothing to update.");
1256
+ const b2 = new PrivateBin(a, l2, io.fetch);
1250
1257
  await b2.read().catch((e3) => {
1251
1258
  throw new Error(
1252
1259
  `I couldn't read the shared copy: ${e3.message === "gone" ? "it is gone" : e3.message}`
1253
1260
  );
1254
1261
  });
1255
- if (b2.head === a2.paste) return io.out("The page already points at the newest copy.");
1262
+ if (b2.head === a.paste) return io.out("The page already points at the newest copy.");
1256
1263
  const fragment = new URL(readAttribute(html, "data-pipeup-share")).hash;
1257
- await io.write(file, setAttribute(html, "data-pipeup-share", `${a2.base}?${b2.head}${fragment}`));
1264
+ await io.write(file, setAttribute(html, "data-pipeup-share", `${a.base}?${b2.head}${fragment}`));
1258
1265
  io.out(`Pointed ${file} at the newest copy, so new reviewers don't have to walk through the older ones.`);
1259
1266
  }
1260
1267
  async function run(argv, io) {