@pipeup/share 0.9.0 → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.js +183 -169
- package/dist/pipeup+share.min.js +2 -2
- package/dist/share.esm.js +1 -1
- package/dist/share.headless.js +1 -1
- package/dist/share.min.js +1 -1
- package/package.json +2 -2
package/dist/cli.js
CHANGED
|
@@ -147,130 +147,133 @@ var P = 2n ** 256n - 2n ** 32n - 977n;
|
|
|
147
147
|
// ../pipeup/dist/pipeup.core.js
|
|
148
148
|
function e(e3) {
|
|
149
149
|
let t2 = "";
|
|
150
|
-
for (let
|
|
150
|
+
for (let n2 of e3) t2 += String.fromCharCode(n2);
|
|
151
151
|
return btoa(t2).replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
|
|
152
152
|
}
|
|
153
153
|
function t(e3) {
|
|
154
|
-
let t2 = atob(e3.replace(/-/g, "+").replace(/_/g, "/")),
|
|
155
|
-
for (let e4 = 0; e4 < t2.length; e4++)
|
|
156
|
-
return
|
|
154
|
+
let t2 = atob(e3.replace(/-/g, "+").replace(/_/g, "/")), n2 = new Uint8Array(t2.length);
|
|
155
|
+
for (let e4 = 0; e4 < t2.length; e4++) n2[e4] = t2.charCodeAt(e4);
|
|
156
|
+
return n2;
|
|
157
157
|
}
|
|
158
|
-
function
|
|
158
|
+
function n(e3) {
|
|
159
159
|
return new TextEncoder().encode(e3);
|
|
160
160
|
}
|
|
161
|
-
function
|
|
161
|
+
function r(e3) {
|
|
162
162
|
if (null === e3 || "object" != typeof e3) return JSON.stringify(e3);
|
|
163
|
-
if (Array.isArray(e3)) return "[" + e3.map(
|
|
163
|
+
if (Array.isArray(e3)) return "[" + e3.map(r).join(",") + "]";
|
|
164
164
|
let t2 = e3;
|
|
165
|
-
return "{" + Object.keys(t2).filter((e4) => void 0 !== t2[e4]).sort().map((e4) => JSON.stringify(e4) + ":" +
|
|
165
|
+
return "{" + Object.keys(t2).filter((e4) => void 0 !== t2[e4]).sort().map((e4) => JSON.stringify(e4) + ":" + r(t2[e4])).join(",") + "}";
|
|
166
166
|
}
|
|
167
167
|
var o = /^[A-Za-z0-9_-]{43}$/;
|
|
168
168
|
var s = /* @__PURE__ */ new Map();
|
|
169
|
-
async function
|
|
169
|
+
async function l() {
|
|
170
170
|
let t2 = await crypto.subtle.generateKey({ name: "Ed25519" }, false, ["sign", "verify"]);
|
|
171
171
|
return { publicKey: e(new Uint8Array(await crypto.subtle.exportKey("raw", t2.publicKey))), privateKey: t2.privateKey };
|
|
172
172
|
}
|
|
173
|
-
async function
|
|
174
|
-
let
|
|
175
|
-
return e(new Uint8Array(
|
|
173
|
+
async function d(t2, n2) {
|
|
174
|
+
let r2 = await crypto.subtle.sign({ name: "Ed25519" }, t2.privateKey, n2);
|
|
175
|
+
return e(new Uint8Array(r2));
|
|
176
176
|
}
|
|
177
177
|
var u = ["Otter", "Fox", "Owl", "Bear", "Rabbit"];
|
|
178
|
-
var
|
|
179
|
-
function
|
|
178
|
+
var h = ["Red", "Orange", "Yellow", "Green", "Teal", "Blue", "Purple", "Pink", "Brown", "Grey"];
|
|
179
|
+
function c(e3) {
|
|
180
180
|
let t2 = 2166136261;
|
|
181
|
-
for (let
|
|
181
|
+
for (let n2 = 0; n2 < e3.length; n2++) t2 = Math.imul(t2 ^ e3.charCodeAt(n2), 16777619);
|
|
182
182
|
return t2 = Math.imul(t2 ^ t2 >>> 16, 2246822507), t2 = Math.imul(t2 ^ t2 >>> 13, 3266489909), (t2 ^ t2 >>> 16) >>> 0;
|
|
183
183
|
}
|
|
184
|
-
var p = (e3) => `${
|
|
184
|
+
var p = (e3) => `${h[((e4) => Math.floor(c(e4) / u.length) % h.length)(e3)]} ${u[((e4) => c(e4) % u.length)(e3)]}`;
|
|
185
185
|
var f = (e3) => {
|
|
186
186
|
let t2 = e3.name.replace(/^AI assistant \xb7 /, "") || p(e3.author);
|
|
187
187
|
return e3.alike ? `${t2} \xB7 ${(function(e4) {
|
|
188
|
-
let t3 =
|
|
189
|
-
for (let e5 = 0; e5 < 4; e5++, t3 >>>= 5)
|
|
190
|
-
return
|
|
188
|
+
let t3 = c(`id:${e4}`), n2 = "";
|
|
189
|
+
for (let e5 = 0; e5 < 4; e5++, t3 >>>= 5) n2 += "0123456789ABCDEFGHJKMNPQRSTVWXYZ"[31 & t3];
|
|
190
|
+
return n2;
|
|
191
191
|
})(e3.author)}` : t2;
|
|
192
192
|
};
|
|
193
193
|
var m = "AI assistant";
|
|
194
194
|
var g = (e3) => e3 === m || e3.startsWith(`${m} `);
|
|
195
195
|
var y = (e3) => `${m} \xB7 ${e3.replace(/\s+/g, " ").trim() || "Agent"}`.slice(0, 80).trim();
|
|
196
196
|
var b = 1e4;
|
|
197
|
-
var
|
|
198
|
-
var
|
|
197
|
+
var v = 2 ** 40;
|
|
198
|
+
var x = 2 ** 47;
|
|
199
199
|
var k = 1e4;
|
|
200
|
-
var A =
|
|
201
|
-
var
|
|
202
|
-
var
|
|
203
|
-
var
|
|
204
|
-
var
|
|
205
|
-
var C =
|
|
206
|
-
var N = /^(
|
|
207
|
-
var O =
|
|
208
|
-
|
|
200
|
+
var A = 200;
|
|
201
|
+
var $ = /* @__PURE__ */ new Set(["h", "p", "img", "button", "link", "field", "media", "box"]);
|
|
202
|
+
var E = /* @__PURE__ */ new Set(["confirmed", "moved", "gone"]);
|
|
203
|
+
var M = /^[0-9a-f]{8}$/;
|
|
204
|
+
var S = /^[A-Za-z0-9_-]{43}$/;
|
|
205
|
+
var C = /^(?:[^\s@<>"]{1,64}@[^\s@<>"]{1,190}\.[^\s@<>"]{2,24}|gh:[A-Za-z0-9-]{1,39})$/;
|
|
206
|
+
var N = /^(?:[A-Za-z0-9_-]{43}|(?:host|gh):[A-Za-z0-9._@-]{1,64})$/;
|
|
207
|
+
var O = /^[A-Za-z0-9_-]{43}$/;
|
|
208
|
+
var q = /* @__PURE__ */ new Set(["create", "reply", "edit", "delete", "resolve", "reopen", "addressed", "react", "unreact", "seen", "contact", "uncontact", "place"]);
|
|
209
|
+
var j = /^(?:\p{Regional_Indicator}{2}|[#*0-9]\uFE0F?\u20E3|\p{Extended_Pictographic}(?:\uFE0F|\p{Emoji_Modifier})?(?:\u200D\p{Extended_Pictographic}(?:\uFE0F|\p{Emoji_Modifier})?)*)$/u;
|
|
210
|
+
var P2 = (e3) => "string" == typeof e3 && j.test(e3) && [...e3].length <= 16;
|
|
211
|
+
async function T(e3, t2) {
|
|
209
212
|
if (e3.author !== t2.publicKey) throw new Error("pipeup: an op must be signed by its author");
|
|
210
|
-
return { body: e3, sig: await
|
|
213
|
+
return { body: e3, sig: await d(t2, n(r(e3))) };
|
|
211
214
|
}
|
|
212
|
-
var
|
|
213
|
-
var
|
|
214
|
-
var
|
|
215
|
-
function
|
|
216
|
-
if (!
|
|
217
|
-
let { id: t2, path:
|
|
218
|
-
if (!(
|
|
215
|
+
var I = (e3, t2) => "string" == typeof e3 && e3.length <= t2;
|
|
216
|
+
var L = (e3) => !!e3 && "object" == typeof e3;
|
|
217
|
+
var F = (e3) => "number" == typeof e3 && Number.isFinite(e3) && e3 >= 0 && e3 <= 1;
|
|
218
|
+
function R(e3) {
|
|
219
|
+
if (!L(e3)) return false;
|
|
220
|
+
let { id: t2, path: n2, fingerprint: r2, snapshot: i, quote: a, point: o2, view: s2, kind: l2, name: d2, heads: u2, y: h2, lost: c2 } = e3;
|
|
221
|
+
if (!(I(n2, 2e3) && I(i, 500) && "string" == typeof r2 && M.test(r2) && (void 0 === t2 || I(t2, 200) && "" !== t2) && (void 0 === a || L(a) && I(a.exact, k) && "" !== a.exact && I(a.prefix, 64) && I(a.suffix, 64)) && (void 0 === o2 || L(o2) && F(o2.x) && F(o2.y)))) return false;
|
|
219
222
|
if (void 0 !== s2) {
|
|
220
|
-
if (!
|
|
223
|
+
if (!L(s2) || Array.isArray(s2)) return false;
|
|
221
224
|
let e4 = Object.entries(s2);
|
|
222
|
-
if (e4.length > 16 || !e4.every(([e5, t3]) => e5.length <= 64 &&
|
|
225
|
+
if (e4.length > 16 || !e4.every(([e5, t3]) => e5.length <= 64 && I(t3, 200))) return false;
|
|
223
226
|
}
|
|
224
|
-
return true;
|
|
227
|
+
return !(void 0 !== l2 && !$.has(l2) || void 0 !== d2 && !I(d2, A) || void 0 !== u2 && (!Array.isArray(u2) || u2.length > 3 || !u2.every((e4) => I(e4, 120))) || void 0 !== h2 && !F(h2) || void 0 !== c2 && true !== c2);
|
|
225
228
|
}
|
|
226
|
-
function
|
|
227
|
-
if (!
|
|
228
|
-
let { body: t2, sig:
|
|
229
|
-
if ("string" != typeof
|
|
230
|
-
let
|
|
231
|
-
if (1 !==
|
|
232
|
-
if (void 0 !==
|
|
233
|
-
if ("create" !==
|
|
234
|
-
let e4 =
|
|
235
|
-
for (let t3 of
|
|
236
|
-
if (!
|
|
237
|
-
let { start:
|
|
238
|
-
if (
|
|
229
|
+
function D(e3) {
|
|
230
|
+
if (!L(e3)) return false;
|
|
231
|
+
let { body: t2, sig: n2 } = e3;
|
|
232
|
+
if ("string" != typeof n2 || !L(t2) || JSON.stringify({ body: t2, sig: n2 }).length > 262144) return false;
|
|
233
|
+
let r2 = t2;
|
|
234
|
+
if (1 !== r2.v || "string" != typeof r2.id || !S.test(r2.id) || !q.has(r2.kind) || !I(r2.doc, 64) || "" === r2.doc || "string" != typeof r2.thread || !S.test(r2.thread) || "string" != typeof r2.author || !O.test(r2.author) || "string" != typeof r2.name || r2.name.length > 80 || r2.name !== r2.name.trim() || "number" != typeof r2.clock || !Number.isSafeInteger(r2.clock) || r2.clock < 1 || r2.clock > v || "number" != typeof r2.at || !Number.isSafeInteger(r2.at) || r2.at < 0 || r2.at > x || void 0 !== r2.text && (!I(r2.text, b) || r2.text !== r2.text.trim()) || void 0 !== r2.target && ("string" != typeof r2.target || !S.test(r2.target)) || ("create" === r2.kind || "reply" === r2.kind || "edit" === r2.kind || "addressed" === r2.kind) && !r2.text || ("reply" === r2.kind || "edit" === r2.kind || "delete" === r2.kind) && !r2.target) return false;
|
|
235
|
+
if (void 0 !== r2.mentions) {
|
|
236
|
+
if ("create" !== r2.kind && "reply" !== r2.kind && "edit" !== r2.kind || !Array.isArray(r2.mentions) || r2.mentions.length > 20) return false;
|
|
237
|
+
let e4 = r2.text?.length ?? 0;
|
|
238
|
+
for (let t3 of r2.mentions) {
|
|
239
|
+
if (!L(t3) || !Number.isSafeInteger(t3.start) || !Number.isSafeInteger(t3.end)) return false;
|
|
240
|
+
let { start: n3, end: r3, ref: i } = t3;
|
|
241
|
+
if (n3 < 0 || r3 <= n3 || r3 > e4 || "string" != typeof i || !N.test(i)) return false;
|
|
239
242
|
}
|
|
240
243
|
}
|
|
241
|
-
return
|
|
244
|
+
return !!(("contact" !== r2.kind || "string" == typeof r2.text && C.test(r2.text)) && ("seen" !== r2.kind || r2.target) && ("react" !== r2.kind && "unreact" !== r2.kind || r2.target && P2(r2.text)) && ("create" !== r2.kind || r2.id === r2.thread && R(r2.anchor)) && ("place" !== r2.kind || R(r2.anchor) && E.has(r2.text)));
|
|
242
245
|
}
|
|
243
|
-
function
|
|
244
|
-
return (async function(
|
|
245
|
-
if (!o.test(
|
|
246
|
+
function U(i) {
|
|
247
|
+
return (async function(n2, r2, i2) {
|
|
248
|
+
if (!o.test(n2)) return false;
|
|
246
249
|
try {
|
|
247
|
-
if (e(t(
|
|
248
|
-
let a = s.get(
|
|
250
|
+
if (e(t(n2)) !== n2) return false;
|
|
251
|
+
let a = s.get(n2);
|
|
249
252
|
if (!a) {
|
|
250
|
-
s.size >= 512 && s.delete(s.keys().next().value), a = crypto.subtle.importKey("raw", t(
|
|
253
|
+
s.size >= 512 && s.delete(s.keys().next().value), a = crypto.subtle.importKey("raw", t(n2), { name: "Ed25519" }, true, ["verify"]), s.set(n2, a);
|
|
251
254
|
let e3 = a;
|
|
252
255
|
e3.catch(() => {
|
|
253
|
-
s.get(
|
|
256
|
+
s.get(n2) === e3 && s.delete(n2);
|
|
254
257
|
});
|
|
255
258
|
}
|
|
256
|
-
return await crypto.subtle.verify({ name: "Ed25519" }, await a, t(i2),
|
|
259
|
+
return await crypto.subtle.verify({ name: "Ed25519" }, await a, t(i2), r2);
|
|
257
260
|
} catch {
|
|
258
261
|
return false;
|
|
259
262
|
}
|
|
260
|
-
})(i.body.author, r(
|
|
263
|
+
})(i.body.author, n(r(i.body)), i.sig);
|
|
261
264
|
}
|
|
262
|
-
function
|
|
265
|
+
function _(e3, t2) {
|
|
263
266
|
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;
|
|
264
267
|
}
|
|
265
|
-
function
|
|
266
|
-
let o2 = { id: e3, author: t2, name:
|
|
268
|
+
function z(e3, t2, n2, r2, i, a) {
|
|
269
|
+
let o2 = { id: e3, author: t2, name: n2, text: r2, at: i, edited: false, deleted: false, replies: [], reactions: [] };
|
|
267
270
|
return a?.length && (o2.mentions = a), o2;
|
|
268
271
|
}
|
|
269
|
-
async function
|
|
270
|
-
let i = { ...t2, id: void 0, thread: "create" === t2.kind ? void 0 : t2.thread }, a = await crypto.subtle.digest("SHA-256", r(
|
|
272
|
+
async function H(t2) {
|
|
273
|
+
let i = { ...t2, id: void 0, thread: "create" === t2.kind ? void 0 : t2.thread }, a = await crypto.subtle.digest("SHA-256", n(r(i)));
|
|
271
274
|
return e(new Uint8Array(a));
|
|
272
275
|
}
|
|
273
|
-
var
|
|
276
|
+
var K = class {
|
|
274
277
|
constructor(e3) {
|
|
275
278
|
this.doc = e3;
|
|
276
279
|
}
|
|
@@ -286,12 +289,12 @@ var _ = class {
|
|
|
286
289
|
}
|
|
287
290
|
threads() {
|
|
288
291
|
return (function(e3) {
|
|
289
|
-
let t2 = /* @__PURE__ */ new Map(),
|
|
290
|
-
for (let { body: i2 } of [...e3].sort(
|
|
291
|
-
if (i2.name && !g(i2.name) &&
|
|
292
|
+
let t2 = /* @__PURE__ */ new Map(), n2 = /* @__PURE__ */ new Map(), r2 = /* @__PURE__ */ new Map();
|
|
293
|
+
for (let { body: i2 } of [...e3].sort(_)) {
|
|
294
|
+
if (i2.name && !g(i2.name) && r2.set(i2.author, i2.name), "create" === i2.kind) {
|
|
292
295
|
if (t2.has(i2.id) || !i2.anchor || void 0 === i2.text) continue;
|
|
293
|
-
let e5 =
|
|
294
|
-
t2.set(i2.id, { id: i2.id, anchor: i2.anchor, root: e5, resolved: false }),
|
|
296
|
+
let e5 = z(i2.id, i2.author, i2.name, i2.text, i2.at, i2.mentions);
|
|
297
|
+
t2.set(i2.id, { id: i2.id, anchor: i2.anchor, root: e5, resolved: false }), n2.set(i2.id, { comment: e5, thread: i2.id });
|
|
295
298
|
continue;
|
|
296
299
|
}
|
|
297
300
|
let e4 = t2.get(i2.thread);
|
|
@@ -300,16 +303,21 @@ var _ = class {
|
|
|
300
303
|
e4.resolved = "resolve" === i2.kind, "reopen" === i2.kind && delete e4.addressed;
|
|
301
304
|
continue;
|
|
302
305
|
}
|
|
306
|
+
if ("place" === i2.kind) {
|
|
307
|
+
if (!i2.anchor) continue;
|
|
308
|
+
e4.anchor = i2.anchor, e4.placed = { how: i2.text, author: i2.author, name: i2.name, at: i2.at };
|
|
309
|
+
continue;
|
|
310
|
+
}
|
|
303
311
|
if ("addressed" === i2.kind) {
|
|
304
312
|
void 0 !== i2.text && (e4.addressed = { text: i2.text, author: i2.author, name: i2.name, at: i2.at });
|
|
305
313
|
continue;
|
|
306
314
|
}
|
|
307
|
-
let a2 = i2.target ?
|
|
315
|
+
let a2 = i2.target ? n2.get(i2.target) : void 0;
|
|
308
316
|
if (a2 && a2.thread === i2.thread) {
|
|
309
317
|
if ("reply" === i2.kind) {
|
|
310
|
-
if (
|
|
311
|
-
let t3 =
|
|
312
|
-
e4.root.replies.push(t3),
|
|
318
|
+
if (n2.has(i2.id) || void 0 === i2.text) continue;
|
|
319
|
+
let t3 = z(i2.id, i2.author, i2.name, i2.text, i2.at, i2.mentions);
|
|
320
|
+
e4.root.replies.push(t3), n2.set(i2.id, { comment: t3, thread: i2.thread });
|
|
313
321
|
continue;
|
|
314
322
|
}
|
|
315
323
|
if ("seen" === i2.kind) {
|
|
@@ -321,28 +329,28 @@ var _ = class {
|
|
|
321
329
|
if (void 0 === i2.text || a2.comment.deleted) continue;
|
|
322
330
|
let e5 = a2.comment.reactions, t3 = e5.find((e6) => e6.emoji === i2.text);
|
|
323
331
|
if ("react" === i2.kind) {
|
|
324
|
-
let
|
|
325
|
-
t3 ? t3.by.some((e6) => e6.author === i2.author) || t3.by.push(
|
|
332
|
+
let n3 = { author: i2.author, name: i2.name };
|
|
333
|
+
t3 ? t3.by.some((e6) => e6.author === i2.author) || t3.by.push(n3) : e5.length < 12 && e5.push({ emoji: i2.text, by: [n3] });
|
|
326
334
|
} else t3 && (t3.by = t3.by.filter((e6) => e6.author !== i2.author), t3.by.length || e5.splice(e5.indexOf(t3), 1));
|
|
327
335
|
continue;
|
|
328
336
|
}
|
|
329
337
|
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));
|
|
330
338
|
}
|
|
331
339
|
}
|
|
332
|
-
for (let { comment: e4 } of
|
|
333
|
-
e4.name || (e4.unnamed = true, e4.name =
|
|
334
|
-
for (let t3 of e4.reactions) for (let e5 of t3.by) e5.name ||=
|
|
340
|
+
for (let { comment: e4 } of n2.values()) {
|
|
341
|
+
e4.name || (e4.unnamed = true, e4.name = r2.get(e4.author) ?? "");
|
|
342
|
+
for (let t3 of e4.reactions) for (let e5 of t3.by) e5.name ||= r2.get(e5.author) ?? "";
|
|
335
343
|
}
|
|
336
344
|
let i = /* @__PURE__ */ new Map(), a = (e4, t3) => {
|
|
337
|
-
let
|
|
338
|
-
(i.get(
|
|
345
|
+
let n3 = f({ author: e4, name: t3 }).toLowerCase();
|
|
346
|
+
(i.get(n3) ?? i.set(n3, /* @__PURE__ */ new Set()).get(n3)).add(e4);
|
|
339
347
|
};
|
|
340
|
-
for (let { comment: e4 } of
|
|
348
|
+
for (let { comment: e4 } of n2.values()) {
|
|
341
349
|
a(e4.author, e4.name);
|
|
342
350
|
for (let t3 of e4.reactions) for (let e5 of t3.by) a(e5.author, e5.name);
|
|
343
351
|
}
|
|
344
352
|
let o2 = (e4, t3) => !g(t3) && (i.get(f({ author: e4, name: t3 }).toLowerCase())?.size ?? 0) > 1;
|
|
345
|
-
for (let { comment: e4 } of
|
|
353
|
+
for (let { comment: e4 } of n2.values()) {
|
|
346
354
|
o2(e4.author, e4.name) && (e4.alike = true);
|
|
347
355
|
for (let t3 of e4.reactions) for (let e5 of t3.by) o2(e5.author, e5.name) && (e5.alike = true);
|
|
348
356
|
}
|
|
@@ -351,41 +359,41 @@ var _ = class {
|
|
|
351
359
|
}
|
|
352
360
|
async add(e3) {
|
|
353
361
|
let t2 = [];
|
|
354
|
-
for (let
|
|
355
|
-
if (!
|
|
356
|
-
let e4 = { body:
|
|
362
|
+
for (let n2 of e3) {
|
|
363
|
+
if (!D(n2) || n2.body.doc !== this.doc || this.ops.has(n2.body.id) || n2.body.id !== await H(n2.body) || !await U(n2)) continue;
|
|
364
|
+
let e4 = { body: n2.body, sig: n2.sig };
|
|
357
365
|
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);
|
|
358
366
|
}
|
|
359
367
|
return t2;
|
|
360
368
|
}
|
|
361
|
-
async append(e3, t2,
|
|
362
|
-
let
|
|
363
|
-
|
|
364
|
-
let i = this.ops.get(
|
|
369
|
+
async append(e3, t2, n2) {
|
|
370
|
+
let r2 = { v: 1, ...n2, id: "", thread: "create" === n2.kind ? "" : n2.thread, doc: this.doc, author: e3.publicKey, name: t2, clock: Math.min(this.clock + 1, v), at: Math.min(Math.max(Date.now(), "create" === n2.kind ? (this.createAt.get(e3.publicKey) ?? 0) + 1 : (this.threadAt.get(n2.thread) ?? 0) + 1), x) };
|
|
371
|
+
r2.id = await H(r2);
|
|
372
|
+
let i = this.ops.get(r2.id);
|
|
365
373
|
if (i) return i;
|
|
366
|
-
"create" ===
|
|
367
|
-
let [a] = await this.add([await
|
|
374
|
+
"create" === r2.kind && (r2.thread = r2.id);
|
|
375
|
+
let [a] = await this.add([await T(r2, e3)]);
|
|
368
376
|
if (!a) throw new Error("pipeup: could not record this change");
|
|
369
377
|
return a;
|
|
370
378
|
}
|
|
371
379
|
};
|
|
372
|
-
var
|
|
373
|
-
function
|
|
380
|
+
var G = /^([A-Za-z0-9_-]{16}):([A-Za-z0-9_-]{43})$/;
|
|
381
|
+
function Z() {
|
|
374
382
|
return `${(function(t2 = 16) {
|
|
375
383
|
return e(crypto.getRandomValues(new Uint8Array(t2)));
|
|
376
384
|
})(12)}:${e(crypto.getRandomValues(new Uint8Array(32)))}`;
|
|
377
385
|
}
|
|
378
|
-
async function
|
|
379
|
-
let
|
|
380
|
-
if (!
|
|
381
|
-
return { id:
|
|
386
|
+
async function J(e3) {
|
|
387
|
+
let n2 = G.exec(e3.trim()), r2 = n2?.[1], i = n2?.[2];
|
|
388
|
+
if (!r2 || !i) throw new Error('pipeup: data-pipeup-doc must look like "<id>:<key>", as made by newDocumentAttribute()');
|
|
389
|
+
return { id: r2, key: await crypto.subtle.importKey("raw", t(i), { name: "AES-GCM" }, false, ["encrypt", "decrypt"]) };
|
|
382
390
|
}
|
|
383
|
-
async function
|
|
384
|
-
let a = crypto.getRandomValues(new Uint8Array(12)), o2 = await crypto.subtle.encrypt({ name: "AES-GCM", iv: a, additionalData:
|
|
391
|
+
async function V(t2, r2, i) {
|
|
392
|
+
let a = crypto.getRandomValues(new Uint8Array(12)), o2 = await crypto.subtle.encrypt({ name: "AES-GCM", iv: a, additionalData: n(i) }, t2, n(r2));
|
|
385
393
|
return { iv: e(a), data: e(new Uint8Array(o2)) };
|
|
386
394
|
}
|
|
387
|
-
var
|
|
388
|
-
async function
|
|
395
|
+
var W = (e3) => `pipeup-file:${e3}`;
|
|
396
|
+
async function Q(e3, r2, i) {
|
|
389
397
|
if (e3.length > 5e6) throw new Error("pipeup: this feedback file is too large");
|
|
390
398
|
let a, o2, s2;
|
|
391
399
|
try {
|
|
@@ -394,19 +402,19 @@ async function J(e3, n2, i) {
|
|
|
394
402
|
throw new Error("pipeup: this is not an Pipeup feedback file");
|
|
395
403
|
}
|
|
396
404
|
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 !==
|
|
405
|
+
if (a.doc !== r2) throw new Error("pipeup: this feedback is for a different document");
|
|
398
406
|
if (!a.sealed) return Array.isArray(a.ops) ? a.ops : [];
|
|
399
407
|
if (!i) throw new Error("pipeup: this feedback is sealed, and this page has no document key");
|
|
400
408
|
if ("string" != typeof a.iv || "string" != typeof a.data) throw new Error("pipeup: this is not an Pipeup feedback file");
|
|
401
409
|
try {
|
|
402
|
-
o2 = await (async function(e4,
|
|
410
|
+
o2 = await (async function(e4, r3, i2) {
|
|
403
411
|
try {
|
|
404
|
-
let a2 = await crypto.subtle.decrypt({ name: "AES-GCM", iv: t(
|
|
412
|
+
let a2 = await crypto.subtle.decrypt({ name: "AES-GCM", iv: t(r3.iv), additionalData: n(i2) }, e4, t(r3.data));
|
|
405
413
|
return new TextDecoder().decode(a2);
|
|
406
414
|
} catch {
|
|
407
415
|
throw new Error("pipeup: this feedback could not be opened with this document");
|
|
408
416
|
}
|
|
409
|
-
})(i, { iv: a.iv, data: a.data },
|
|
417
|
+
})(i, { iv: a.iv, data: a.data }, W(r2));
|
|
410
418
|
} catch {
|
|
411
419
|
throw new Error("pipeup: this feedback could not be opened with this document's key");
|
|
412
420
|
}
|
|
@@ -417,15 +425,15 @@ async function J(e3, n2, i) {
|
|
|
417
425
|
}
|
|
418
426
|
return Array.isArray(s2) ? s2 : [];
|
|
419
427
|
}
|
|
420
|
-
var
|
|
421
|
-
var
|
|
422
|
-
constructor(e3, t2,
|
|
423
|
-
super("pipeup: shown here, but not saved yet"), this.id = e3, this.cause = t2, this.count =
|
|
428
|
+
var X = /^[a-z][a-z0-9-]{1,23}\/[a-z][a-z0-9-]{0,31}$/;
|
|
429
|
+
var Y = class extends Error {
|
|
430
|
+
constructor(e3, t2, n2 = 1) {
|
|
431
|
+
super("pipeup: shown here, but not saved yet"), this.id = e3, this.cause = t2, this.count = n2, this.name = "UnsavedChangeError";
|
|
424
432
|
}
|
|
425
433
|
};
|
|
426
|
-
var
|
|
434
|
+
var ee = class e2 {
|
|
427
435
|
constructor(e3, t2) {
|
|
428
|
-
this.log = e3, this.options = t2, this.displayName = t2.name.trim() ?
|
|
436
|
+
this.log = e3, this.options = t2, this.displayName = t2.name.trim() ? re(t2.name) : "";
|
|
429
437
|
}
|
|
430
438
|
listeners = /* @__PURE__ */ new Set();
|
|
431
439
|
cache = [];
|
|
@@ -435,9 +443,9 @@ var Q = class e2 {
|
|
|
435
443
|
unsaved = [];
|
|
436
444
|
static async open(t2) {
|
|
437
445
|
if ("string" != typeof t2.doc || "" === t2.doc || t2.doc.length > 64) throw new Error("pipeup: the document id must be 1 to 64 characters");
|
|
438
|
-
let
|
|
446
|
+
let n2 = new K(t2.doc), r2 = await t2.store.load(t2.doc), i = r2.length - (await n2.add(r2)).length;
|
|
439
447
|
i && console.warn(`pipeup: ${i} saved change${1 === i ? "" : "s"} on this page couldn't be read; kept as saved`);
|
|
440
|
-
let a = new e2(
|
|
448
|
+
let a = new e2(n2, t2);
|
|
441
449
|
return a.refresh(false), a;
|
|
442
450
|
}
|
|
443
451
|
get id() {
|
|
@@ -450,7 +458,7 @@ var Q = class e2 {
|
|
|
450
458
|
return this.displayName;
|
|
451
459
|
}
|
|
452
460
|
set name(e3) {
|
|
453
|
-
this.displayName =
|
|
461
|
+
this.displayName = re(e3), this.refresh(true, [], "");
|
|
454
462
|
}
|
|
455
463
|
threads() {
|
|
456
464
|
return this.cache;
|
|
@@ -461,16 +469,22 @@ var Q = class e2 {
|
|
|
461
469
|
onChange(e3) {
|
|
462
470
|
return this.listeners.add(e3), () => this.listeners.delete(e3);
|
|
463
471
|
}
|
|
464
|
-
comment(e3, t2,
|
|
465
|
-
return this.enqueue(() => this.write({ kind: "create", anchor: e3, text:
|
|
472
|
+
comment(e3, t2, n2) {
|
|
473
|
+
return this.enqueue(() => this.write({ kind: "create", anchor: e3, text: te(t2), ...n2?.length ? { mentions: n2 } : {} }));
|
|
474
|
+
}
|
|
475
|
+
place(e3, t2, n2) {
|
|
476
|
+
return this.enqueue(async () => {
|
|
477
|
+
let { thread: r2 } = this.find(e3), i = "gone" === n2 ? { ...t2, lost: true } : t2;
|
|
478
|
+
await this.write({ kind: "place", thread: r2, anchor: i, text: n2 });
|
|
479
|
+
});
|
|
466
480
|
}
|
|
467
|
-
reply(e3, t2,
|
|
468
|
-
return this.enqueue(() => this.write({ kind: "reply", thread: this.find(e3).thread, target: e3, text:
|
|
481
|
+
reply(e3, t2, n2) {
|
|
482
|
+
return this.enqueue(() => this.write({ kind: "reply", thread: this.find(e3).thread, target: e3, text: te(t2), ...n2?.length ? { mentions: n2 } : {} }));
|
|
469
483
|
}
|
|
470
|
-
edit(e3, t2,
|
|
484
|
+
edit(e3, t2, n2) {
|
|
471
485
|
return this.enqueue(async () => {
|
|
472
|
-
let { thread:
|
|
473
|
-
await this.write({ kind: "edit", thread:
|
|
486
|
+
let { thread: r2 } = this.mine(e3);
|
|
487
|
+
await this.write({ kind: "edit", thread: r2, target: e3, text: te(t2), ...n2?.length ? { mentions: n2 } : {} });
|
|
474
488
|
});
|
|
475
489
|
}
|
|
476
490
|
remove(e3) {
|
|
@@ -481,7 +495,7 @@ var Q = class e2 {
|
|
|
481
495
|
}
|
|
482
496
|
contact(e3) {
|
|
483
497
|
let t2 = e3.trim();
|
|
484
|
-
return
|
|
498
|
+
return C.test(t2) ? this.enqueue(async () => {
|
|
485
499
|
await this.write({ kind: "contact", thread: this.me, text: t2 });
|
|
486
500
|
}) : Promise.reject(new Error("pipeup: that isn't an email address or a GitHub name"));
|
|
487
501
|
}
|
|
@@ -492,7 +506,7 @@ var Q = class e2 {
|
|
|
492
506
|
}
|
|
493
507
|
contacts() {
|
|
494
508
|
let e3 = /* @__PURE__ */ new Map();
|
|
495
|
-
for (let { body: t2 } of [...this.log.all()].sort(
|
|
509
|
+
for (let { body: t2 } of [...this.log.all()].sort(_)) "contact" === t2.kind && t2.text ? e3.set(t2.author, t2.text) : "uncontact" === t2.kind && e3.delete(t2.author);
|
|
496
510
|
return e3;
|
|
497
511
|
}
|
|
498
512
|
get portable() {
|
|
@@ -501,8 +515,8 @@ var Q = class e2 {
|
|
|
501
515
|
async seed() {
|
|
502
516
|
let e3 = this.options.identity.privateKey;
|
|
503
517
|
if (!e3.extractable) return null;
|
|
504
|
-
let { d:
|
|
505
|
-
return
|
|
518
|
+
let { d: n2 } = await crypto.subtle.exportKey("jwk", e3);
|
|
519
|
+
return n2 ? t(n2) : null;
|
|
506
520
|
}
|
|
507
521
|
seen(e3) {
|
|
508
522
|
return this.enqueue(async () => {
|
|
@@ -514,12 +528,12 @@ var Q = class e2 {
|
|
|
514
528
|
}
|
|
515
529
|
react(e3, t2) {
|
|
516
530
|
return this.enqueue(async () => {
|
|
517
|
-
await this.write({ kind: "react", thread: this.find(e3).thread, target: e3, text:
|
|
531
|
+
await this.write({ kind: "react", thread: this.find(e3).thread, target: e3, text: ne(t2) });
|
|
518
532
|
});
|
|
519
533
|
}
|
|
520
534
|
unreact(e3, t2) {
|
|
521
535
|
return this.enqueue(async () => {
|
|
522
|
-
await this.write({ kind: "unreact", thread: this.find(e3).thread, target: e3, text:
|
|
536
|
+
await this.write({ kind: "unreact", thread: this.find(e3).thread, target: e3, text: ne(t2) });
|
|
523
537
|
});
|
|
524
538
|
}
|
|
525
539
|
resolve(e3) {
|
|
@@ -532,39 +546,39 @@ var Q = class e2 {
|
|
|
532
546
|
await this.write({ kind: "reopen", thread: this.thread(e3) });
|
|
533
547
|
});
|
|
534
548
|
}
|
|
535
|
-
paste(e3, t2,
|
|
549
|
+
paste(e3, t2, n2, r2) {
|
|
536
550
|
return this.enqueue(async () => {
|
|
537
551
|
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:
|
|
552
|
+
await this.write({ kind: "reply", thread: i, target: o2, text: te(n2) }, a), r2?.trim() && await this.write({ kind: "addressed", thread: i, text: te(r2) }, a);
|
|
539
553
|
});
|
|
540
554
|
}
|
|
541
555
|
sign(e3, t2) {
|
|
542
|
-
if (!
|
|
543
|
-
return
|
|
556
|
+
if (!X.test(e3)) throw new Error('pipeup: a signing purpose looks like "<add-on id>/<name>"');
|
|
557
|
+
return d(this.options.identity, n(`pipeup:${e3}
|
|
544
558
|
${t2}`));
|
|
545
559
|
}
|
|
546
560
|
flush() {
|
|
547
561
|
return this.enqueue(() => this.persist());
|
|
548
562
|
}
|
|
549
563
|
exportFile() {
|
|
550
|
-
return (async function(e3, t2,
|
|
551
|
-
let
|
|
552
|
-
return JSON.stringify(
|
|
564
|
+
return (async function(e3, t2, n2) {
|
|
565
|
+
let r2 = n2 ? { pipeup: 1, doc: e3, sealed: true, ...await V(n2, JSON.stringify(t2), W(e3)) } : { pipeup: 1, doc: e3, sealed: false, ops: t2 };
|
|
566
|
+
return JSON.stringify(r2, null, 2);
|
|
553
567
|
})(this.options.doc, this.log.all(), this.options.key);
|
|
554
568
|
}
|
|
555
569
|
async importFile(e3) {
|
|
556
|
-
return this.merge(await
|
|
570
|
+
return this.merge(await Q(e3, this.options.doc, this.options.key), "file");
|
|
557
571
|
}
|
|
558
572
|
merge(e3, t2) {
|
|
559
573
|
return e3.length > 5e3 ? Promise.reject(new RangeError("pipeup: too many changes to merge at once")) : this.enqueue(async () => {
|
|
560
|
-
let
|
|
561
|
-
this.unsaved.push(...
|
|
574
|
+
let n2 = await this.log.add([...e3]);
|
|
575
|
+
this.unsaved.push(...n2), n2.length > 0 && this.refresh(true, n2, t2);
|
|
562
576
|
try {
|
|
563
577
|
await this.persist();
|
|
564
578
|
} catch (e4) {
|
|
565
|
-
throw
|
|
579
|
+
throw n2.length > 0 ? new Y(n2[0].body.id, e4, n2.length) : e4;
|
|
566
580
|
}
|
|
567
|
-
return
|
|
581
|
+
return n2.length;
|
|
568
582
|
});
|
|
569
583
|
}
|
|
570
584
|
enqueue(e3) {
|
|
@@ -573,29 +587,29 @@ ${t2}`));
|
|
|
573
587
|
}), t2;
|
|
574
588
|
}
|
|
575
589
|
async write(e3, t2 = this.displayName) {
|
|
576
|
-
let
|
|
577
|
-
this.unsaved.push(
|
|
590
|
+
let n2 = await this.log.append(this.options.identity, t2, e3);
|
|
591
|
+
this.unsaved.push(n2), this.refresh(true, [n2], "local");
|
|
578
592
|
try {
|
|
579
593
|
await this.persist();
|
|
580
594
|
} catch (e4) {
|
|
581
|
-
throw new
|
|
595
|
+
throw new Y(n2.body.id, e4);
|
|
582
596
|
}
|
|
583
|
-
return
|
|
597
|
+
return n2.body.id;
|
|
584
598
|
}
|
|
585
599
|
async persist() {
|
|
586
600
|
if (0 === this.unsaved.length) return;
|
|
587
601
|
let e3 = [...this.unsaved];
|
|
588
602
|
await this.options.store.append(this.options.doc, e3), this.unsaved = this.unsaved.filter((t2) => !e3.includes(t2));
|
|
589
603
|
}
|
|
590
|
-
refresh(e3, t2 = [],
|
|
604
|
+
refresh(e3, t2 = [], n2 = "") {
|
|
591
605
|
this.cache = this.log.threads(), this.comments.clear();
|
|
592
|
-
let
|
|
606
|
+
let r2 = (e4, t3) => {
|
|
593
607
|
e4.unnamed && e4.author === this.me && this.displayName && (e4.name = this.displayName), this.comments.set(e4.id, { comment: e4, thread: t3 });
|
|
594
|
-
for (let
|
|
608
|
+
for (let n3 of e4.replies) r2(n3, t3);
|
|
595
609
|
};
|
|
596
|
-
for (let e4 of this.cache)
|
|
610
|
+
for (let e4 of this.cache) r2(e4.root, e4.id);
|
|
597
611
|
if (e3) for (let e4 of this.listeners) try {
|
|
598
|
-
e4(this.cache, t2,
|
|
612
|
+
e4(this.cache, t2, n2);
|
|
599
613
|
} catch (e5) {
|
|
600
614
|
globalThis.reportError?.(e5);
|
|
601
615
|
}
|
|
@@ -615,32 +629,32 @@ ${t2}`));
|
|
|
615
629
|
return e3;
|
|
616
630
|
}
|
|
617
631
|
};
|
|
618
|
-
function
|
|
632
|
+
function te(e3) {
|
|
619
633
|
let t2 = e3.trim();
|
|
620
634
|
if (!t2) throw new Error("pipeup: a comment needs some words");
|
|
621
635
|
if (t2.length > b) throw new Error(`pipeup: comments are limited to ${b} characters`);
|
|
622
636
|
return t2;
|
|
623
637
|
}
|
|
624
|
-
function
|
|
625
|
-
if (!
|
|
638
|
+
function ne(e3) {
|
|
639
|
+
if (!P2(e3)) throw new Error("pipeup: a reaction is one emoji");
|
|
626
640
|
return e3;
|
|
627
641
|
}
|
|
628
|
-
function
|
|
642
|
+
function re(e3) {
|
|
629
643
|
let t2 = e3.replace(/\s+/g, " ").trim();
|
|
630
644
|
if (!t2 || t2.length > 80) throw new Error("pipeup: choose a name of 1 to 80 characters");
|
|
631
645
|
if (g(t2)) throw new Error("pipeup: that name is kept for AI replies; choose another");
|
|
632
646
|
return t2;
|
|
633
647
|
}
|
|
634
|
-
var
|
|
648
|
+
var ie = class {
|
|
635
649
|
docs = /* @__PURE__ */ new Map();
|
|
636
650
|
profile = null;
|
|
637
651
|
async load(e3) {
|
|
638
652
|
return [...this.docs.get(e3)?.values() ?? []];
|
|
639
653
|
}
|
|
640
654
|
async append(e3, t2) {
|
|
641
|
-
let
|
|
642
|
-
|
|
643
|
-
for (let e4 of t2)
|
|
655
|
+
let n2 = this.docs.get(e3);
|
|
656
|
+
n2 || this.docs.set(e3, n2 = /* @__PURE__ */ new Map());
|
|
657
|
+
for (let e4 of t2) n2.set(e4.body.id, e4);
|
|
644
658
|
}
|
|
645
659
|
async loadProfile() {
|
|
646
660
|
return this.profile;
|
|
@@ -1100,12 +1114,12 @@ function server(value, mailbox) {
|
|
|
1100
1114
|
return mailbox ? value.replace(/\/+$/, "") : u2.origin + u2.pathname;
|
|
1101
1115
|
}
|
|
1102
1116
|
async function feedbackOps(file, docAttr, io) {
|
|
1103
|
-
const { id, key } = await
|
|
1104
|
-
const doc = await
|
|
1117
|
+
const { id, key } = await J(docAttr);
|
|
1118
|
+
const doc = await ee.open({
|
|
1105
1119
|
doc: id,
|
|
1106
1120
|
key,
|
|
1107
|
-
store: new
|
|
1108
|
-
identity: await
|
|
1121
|
+
store: new ie(),
|
|
1122
|
+
identity: await l(),
|
|
1109
1123
|
name: ""
|
|
1110
1124
|
});
|
|
1111
1125
|
try {
|
|
@@ -1131,11 +1145,11 @@ Run the same command with --new-doc and I will write a fresh one into the page.
|
|
|
1131
1145
|
);
|
|
1132
1146
|
throw new UsageError("the page needs a document identity");
|
|
1133
1147
|
}
|
|
1134
|
-
docAttr =
|
|
1148
|
+
docAttr = Z();
|
|
1135
1149
|
html = setAttribute(html, "data-pipeup-doc", docAttr);
|
|
1136
1150
|
io.out("Gave the page a new document identity (data-pipeup-doc).");
|
|
1137
1151
|
}
|
|
1138
|
-
const { id } = await
|
|
1152
|
+
const { id } = await J(docAttr).catch(() => {
|
|
1139
1153
|
throw new UsageError("data-pipeup-doc in the page isn't a valid document identity");
|
|
1140
1154
|
});
|
|
1141
1155
|
const from = typeof flags.get("from") === "string" ? flags.get("from") : null;
|
|
@@ -1205,7 +1219,7 @@ async function addressOf(file, io) {
|
|
|
1205
1219
|
const a = parseShare(readAttribute(html, "data-pipeup-share"), true);
|
|
1206
1220
|
if (a.kind === "off") throw new UsageError(`${file}: ${a.reason}`);
|
|
1207
1221
|
const docAttr = readAttribute(html, "data-pipeup-doc");
|
|
1208
|
-
const doc = docAttr ? (await
|
|
1222
|
+
const doc = docAttr ? (await J(docAttr).catch(() => null))?.id : null;
|
|
1209
1223
|
if (!doc) throw new UsageError(`${file} has no valid data-pipeup-doc`);
|
|
1210
1224
|
return { html, a, l: ladder(doc, a.key) };
|
|
1211
1225
|
}
|