@formstr/mcp 0.1.1 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +1885 -596
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -766,7 +766,7 @@ var require_validation = __commonJS({
|
|
|
766
766
|
var require_receiver = __commonJS({
|
|
767
767
|
"../../node_modules/.pnpm/ws@8.21.0/node_modules/ws/lib/receiver.js"(exports2, module2) {
|
|
768
768
|
"use strict";
|
|
769
|
-
var { Writable } = require("stream");
|
|
769
|
+
var { Writable: Writable2 } = require("stream");
|
|
770
770
|
var PerMessageDeflate2 = require_permessage_deflate();
|
|
771
771
|
var {
|
|
772
772
|
BINARY_TYPES,
|
|
@@ -784,7 +784,7 @@ var require_receiver = __commonJS({
|
|
|
784
784
|
var GET_DATA = 4;
|
|
785
785
|
var INFLATING = 5;
|
|
786
786
|
var DEFER_EVENT = 6;
|
|
787
|
-
var Receiver2 = class extends
|
|
787
|
+
var Receiver2 = class extends Writable2 {
|
|
788
788
|
/**
|
|
789
789
|
* Creates a Receiver instance.
|
|
790
790
|
*
|
|
@@ -22056,243 +22056,6 @@ async function validateEvent2(event, url, method, body) {
|
|
|
22056
22056
|
return true;
|
|
22057
22057
|
}
|
|
22058
22058
|
|
|
22059
|
-
// ../../node_modules/.pnpm/@noble+hashes@2.0.1/node_modules/@noble/hashes/pbkdf2.js
|
|
22060
|
-
function pbkdf2Init(hash, _password, _salt, _opts) {
|
|
22061
|
-
ahash(hash);
|
|
22062
|
-
const opts = checkOpts({ dkLen: 32, asyncTick: 10 }, _opts);
|
|
22063
|
-
const { c, dkLen, asyncTick } = opts;
|
|
22064
|
-
anumber(c, "c");
|
|
22065
|
-
anumber(dkLen, "dkLen");
|
|
22066
|
-
anumber(asyncTick, "asyncTick");
|
|
22067
|
-
if (c < 1)
|
|
22068
|
-
throw new Error("iterations (c) must be >= 1");
|
|
22069
|
-
const password = kdfInputToBytes(_password, "password");
|
|
22070
|
-
const salt = kdfInputToBytes(_salt, "salt");
|
|
22071
|
-
const DK = new Uint8Array(dkLen);
|
|
22072
|
-
const PRF = hmac.create(hash, password);
|
|
22073
|
-
const PRFSalt = PRF._cloneInto().update(salt);
|
|
22074
|
-
return { c, dkLen, asyncTick, DK, PRF, PRFSalt };
|
|
22075
|
-
}
|
|
22076
|
-
function pbkdf2Output(PRF, PRFSalt, DK, prfW, u) {
|
|
22077
|
-
PRF.destroy();
|
|
22078
|
-
PRFSalt.destroy();
|
|
22079
|
-
if (prfW)
|
|
22080
|
-
prfW.destroy();
|
|
22081
|
-
clean(u);
|
|
22082
|
-
return DK;
|
|
22083
|
-
}
|
|
22084
|
-
function pbkdf2(hash, password, salt, opts) {
|
|
22085
|
-
const { c, dkLen, DK, PRF, PRFSalt } = pbkdf2Init(hash, password, salt, opts);
|
|
22086
|
-
let prfW;
|
|
22087
|
-
const arr = new Uint8Array(4);
|
|
22088
|
-
const view = createView(arr);
|
|
22089
|
-
const u = new Uint8Array(PRF.outputLen);
|
|
22090
|
-
for (let ti = 1, pos = 0; pos < dkLen; ti++, pos += PRF.outputLen) {
|
|
22091
|
-
const Ti = DK.subarray(pos, pos + PRF.outputLen);
|
|
22092
|
-
view.setInt32(0, ti, false);
|
|
22093
|
-
(prfW = PRFSalt._cloneInto(prfW)).update(arr).digestInto(u);
|
|
22094
|
-
Ti.set(u.subarray(0, Ti.length));
|
|
22095
|
-
for (let ui = 1; ui < c; ui++) {
|
|
22096
|
-
PRF._cloneInto(prfW).update(u).digestInto(u);
|
|
22097
|
-
for (let i4 = 0; i4 < Ti.length; i4++)
|
|
22098
|
-
Ti[i4] ^= u[i4];
|
|
22099
|
-
}
|
|
22100
|
-
}
|
|
22101
|
-
return pbkdf2Output(PRF, PRFSalt, DK, prfW, u);
|
|
22102
|
-
}
|
|
22103
|
-
|
|
22104
|
-
// ../../node_modules/.pnpm/@noble+hashes@2.0.1/node_modules/@noble/hashes/scrypt.js
|
|
22105
|
-
function XorAndSalsa(prev, pi, input, ii, out, oi) {
|
|
22106
|
-
let y00 = prev[pi++] ^ input[ii++], y01 = prev[pi++] ^ input[ii++];
|
|
22107
|
-
let y02 = prev[pi++] ^ input[ii++], y03 = prev[pi++] ^ input[ii++];
|
|
22108
|
-
let y04 = prev[pi++] ^ input[ii++], y05 = prev[pi++] ^ input[ii++];
|
|
22109
|
-
let y06 = prev[pi++] ^ input[ii++], y07 = prev[pi++] ^ input[ii++];
|
|
22110
|
-
let y08 = prev[pi++] ^ input[ii++], y09 = prev[pi++] ^ input[ii++];
|
|
22111
|
-
let y10 = prev[pi++] ^ input[ii++], y11 = prev[pi++] ^ input[ii++];
|
|
22112
|
-
let y12 = prev[pi++] ^ input[ii++], y13 = prev[pi++] ^ input[ii++];
|
|
22113
|
-
let y14 = prev[pi++] ^ input[ii++], y15 = prev[pi++] ^ input[ii++];
|
|
22114
|
-
let x00 = y00, x01 = y01, x02 = y02, x03 = y03, x04 = y04, x05 = y05, x06 = y06, x07 = y07, x08 = y08, x09 = y09, x10 = y10, x11 = y11, x12 = y12, x13 = y13, x14 = y14, x15 = y15;
|
|
22115
|
-
for (let i4 = 0; i4 < 8; i4 += 2) {
|
|
22116
|
-
x04 ^= rotl(x00 + x12 | 0, 7);
|
|
22117
|
-
x08 ^= rotl(x04 + x00 | 0, 9);
|
|
22118
|
-
x12 ^= rotl(x08 + x04 | 0, 13);
|
|
22119
|
-
x00 ^= rotl(x12 + x08 | 0, 18);
|
|
22120
|
-
x09 ^= rotl(x05 + x01 | 0, 7);
|
|
22121
|
-
x13 ^= rotl(x09 + x05 | 0, 9);
|
|
22122
|
-
x01 ^= rotl(x13 + x09 | 0, 13);
|
|
22123
|
-
x05 ^= rotl(x01 + x13 | 0, 18);
|
|
22124
|
-
x14 ^= rotl(x10 + x06 | 0, 7);
|
|
22125
|
-
x02 ^= rotl(x14 + x10 | 0, 9);
|
|
22126
|
-
x06 ^= rotl(x02 + x14 | 0, 13);
|
|
22127
|
-
x10 ^= rotl(x06 + x02 | 0, 18);
|
|
22128
|
-
x03 ^= rotl(x15 + x11 | 0, 7);
|
|
22129
|
-
x07 ^= rotl(x03 + x15 | 0, 9);
|
|
22130
|
-
x11 ^= rotl(x07 + x03 | 0, 13);
|
|
22131
|
-
x15 ^= rotl(x11 + x07 | 0, 18);
|
|
22132
|
-
x01 ^= rotl(x00 + x03 | 0, 7);
|
|
22133
|
-
x02 ^= rotl(x01 + x00 | 0, 9);
|
|
22134
|
-
x03 ^= rotl(x02 + x01 | 0, 13);
|
|
22135
|
-
x00 ^= rotl(x03 + x02 | 0, 18);
|
|
22136
|
-
x06 ^= rotl(x05 + x04 | 0, 7);
|
|
22137
|
-
x07 ^= rotl(x06 + x05 | 0, 9);
|
|
22138
|
-
x04 ^= rotl(x07 + x06 | 0, 13);
|
|
22139
|
-
x05 ^= rotl(x04 + x07 | 0, 18);
|
|
22140
|
-
x11 ^= rotl(x10 + x09 | 0, 7);
|
|
22141
|
-
x08 ^= rotl(x11 + x10 | 0, 9);
|
|
22142
|
-
x09 ^= rotl(x08 + x11 | 0, 13);
|
|
22143
|
-
x10 ^= rotl(x09 + x08 | 0, 18);
|
|
22144
|
-
x12 ^= rotl(x15 + x14 | 0, 7);
|
|
22145
|
-
x13 ^= rotl(x12 + x15 | 0, 9);
|
|
22146
|
-
x14 ^= rotl(x13 + x12 | 0, 13);
|
|
22147
|
-
x15 ^= rotl(x14 + x13 | 0, 18);
|
|
22148
|
-
}
|
|
22149
|
-
out[oi++] = y00 + x00 | 0;
|
|
22150
|
-
out[oi++] = y01 + x01 | 0;
|
|
22151
|
-
out[oi++] = y02 + x02 | 0;
|
|
22152
|
-
out[oi++] = y03 + x03 | 0;
|
|
22153
|
-
out[oi++] = y04 + x04 | 0;
|
|
22154
|
-
out[oi++] = y05 + x05 | 0;
|
|
22155
|
-
out[oi++] = y06 + x06 | 0;
|
|
22156
|
-
out[oi++] = y07 + x07 | 0;
|
|
22157
|
-
out[oi++] = y08 + x08 | 0;
|
|
22158
|
-
out[oi++] = y09 + x09 | 0;
|
|
22159
|
-
out[oi++] = y10 + x10 | 0;
|
|
22160
|
-
out[oi++] = y11 + x11 | 0;
|
|
22161
|
-
out[oi++] = y12 + x12 | 0;
|
|
22162
|
-
out[oi++] = y13 + x13 | 0;
|
|
22163
|
-
out[oi++] = y14 + x14 | 0;
|
|
22164
|
-
out[oi++] = y15 + x15 | 0;
|
|
22165
|
-
}
|
|
22166
|
-
function BlockMix(input, ii, out, oi, r) {
|
|
22167
|
-
let head = oi + 0;
|
|
22168
|
-
let tail = oi + 16 * r;
|
|
22169
|
-
for (let i4 = 0; i4 < 16; i4++)
|
|
22170
|
-
out[tail + i4] = input[ii + (2 * r - 1) * 16 + i4];
|
|
22171
|
-
for (let i4 = 0; i4 < r; i4++, head += 16, ii += 16) {
|
|
22172
|
-
XorAndSalsa(out, tail, input, ii, out, head);
|
|
22173
|
-
if (i4 > 0)
|
|
22174
|
-
tail += 16;
|
|
22175
|
-
XorAndSalsa(out, head, input, ii += 16, out, tail);
|
|
22176
|
-
}
|
|
22177
|
-
}
|
|
22178
|
-
function scryptInit(password, salt, _opts) {
|
|
22179
|
-
const opts = checkOpts({
|
|
22180
|
-
dkLen: 32,
|
|
22181
|
-
asyncTick: 10,
|
|
22182
|
-
maxmem: 1024 ** 3 + 1024
|
|
22183
|
-
}, _opts);
|
|
22184
|
-
const { N, r, p, dkLen, asyncTick, maxmem, onProgress } = opts;
|
|
22185
|
-
anumber(N, "N");
|
|
22186
|
-
anumber(r, "r");
|
|
22187
|
-
anumber(p, "p");
|
|
22188
|
-
anumber(dkLen, "dkLen");
|
|
22189
|
-
anumber(asyncTick, "asyncTick");
|
|
22190
|
-
anumber(maxmem, "maxmem");
|
|
22191
|
-
if (onProgress !== void 0 && typeof onProgress !== "function")
|
|
22192
|
-
throw new Error("progressCb must be a function");
|
|
22193
|
-
const blockSize = 128 * r;
|
|
22194
|
-
const blockSize32 = blockSize / 4;
|
|
22195
|
-
const pow32 = Math.pow(2, 32);
|
|
22196
|
-
if (N <= 1 || (N & N - 1) !== 0 || N > pow32)
|
|
22197
|
-
throw new Error('"N" expected a power of 2, and 2^1 <= N <= 2^32');
|
|
22198
|
-
if (p < 1 || p > (pow32 - 1) * 32 / blockSize)
|
|
22199
|
-
throw new Error('"p" expected integer 1..((2^32 - 1) * 32) / (128 * r)');
|
|
22200
|
-
if (dkLen < 1 || dkLen > (pow32 - 1) * 32)
|
|
22201
|
-
throw new Error('"dkLen" expected integer 1..(2^32 - 1) * 32');
|
|
22202
|
-
const memUsed = blockSize * (N + p);
|
|
22203
|
-
if (memUsed > maxmem)
|
|
22204
|
-
throw new Error('"maxmem" limit was hit, expected 128*r*(N+p) <= "maxmem"=' + maxmem);
|
|
22205
|
-
const B = pbkdf2(sha256, password, salt, { c: 1, dkLen: blockSize * p });
|
|
22206
|
-
const B32 = u32(B);
|
|
22207
|
-
const V = u32(new Uint8Array(blockSize * N));
|
|
22208
|
-
const tmp = u32(new Uint8Array(blockSize));
|
|
22209
|
-
let blockMixCb = () => {
|
|
22210
|
-
};
|
|
22211
|
-
if (onProgress) {
|
|
22212
|
-
const totalBlockMix = 2 * N * p;
|
|
22213
|
-
const callbackPer = Math.max(Math.floor(totalBlockMix / 1e4), 1);
|
|
22214
|
-
let blockMixCnt = 0;
|
|
22215
|
-
blockMixCb = () => {
|
|
22216
|
-
blockMixCnt++;
|
|
22217
|
-
if (onProgress && (!(blockMixCnt % callbackPer) || blockMixCnt === totalBlockMix))
|
|
22218
|
-
onProgress(blockMixCnt / totalBlockMix);
|
|
22219
|
-
};
|
|
22220
|
-
}
|
|
22221
|
-
return { N, r, p, dkLen, blockSize32, V, B32, B, tmp, blockMixCb, asyncTick };
|
|
22222
|
-
}
|
|
22223
|
-
function scryptOutput(password, dkLen, B, V, tmp) {
|
|
22224
|
-
const res = pbkdf2(sha256, password, B, { c: 1, dkLen });
|
|
22225
|
-
clean(B, V, tmp);
|
|
22226
|
-
return res;
|
|
22227
|
-
}
|
|
22228
|
-
function scrypt(password, salt, opts) {
|
|
22229
|
-
const { N, r, p, dkLen, blockSize32, V, B32, B, tmp, blockMixCb } = scryptInit(password, salt, opts);
|
|
22230
|
-
swap32IfBE(B32);
|
|
22231
|
-
for (let pi = 0; pi < p; pi++) {
|
|
22232
|
-
const Pi = blockSize32 * pi;
|
|
22233
|
-
for (let i4 = 0; i4 < blockSize32; i4++)
|
|
22234
|
-
V[i4] = B32[Pi + i4];
|
|
22235
|
-
for (let i4 = 0, pos = 0; i4 < N - 1; i4++) {
|
|
22236
|
-
BlockMix(V, pos, V, pos += blockSize32, r);
|
|
22237
|
-
blockMixCb();
|
|
22238
|
-
}
|
|
22239
|
-
BlockMix(V, (N - 1) * blockSize32, B32, Pi, r);
|
|
22240
|
-
blockMixCb();
|
|
22241
|
-
for (let i4 = 0; i4 < N; i4++) {
|
|
22242
|
-
const j = (B32[Pi + blockSize32 - 16] & N - 1) >>> 0;
|
|
22243
|
-
for (let k = 0; k < blockSize32; k++)
|
|
22244
|
-
tmp[k] = B32[Pi + k] ^ V[j * blockSize32 + k];
|
|
22245
|
-
BlockMix(tmp, 0, B32, Pi, r);
|
|
22246
|
-
blockMixCb();
|
|
22247
|
-
}
|
|
22248
|
-
}
|
|
22249
|
-
swap32IfBE(B32);
|
|
22250
|
-
return scryptOutput(password, dkLen, B, V, tmp);
|
|
22251
|
-
}
|
|
22252
|
-
|
|
22253
|
-
// ../../node_modules/.pnpm/nostr-tools@2.23.3_typescript@5.9.3/node_modules/nostr-tools/lib/esm/nip49.js
|
|
22254
|
-
var Bech32MaxSize2 = 5e3;
|
|
22255
|
-
function encodeBech322(prefix, data) {
|
|
22256
|
-
let words = bech32.toWords(data);
|
|
22257
|
-
return bech32.encode(prefix, words, Bech32MaxSize2);
|
|
22258
|
-
}
|
|
22259
|
-
function encodeBytes2(prefix, bytes) {
|
|
22260
|
-
return encodeBech322(prefix, bytes);
|
|
22261
|
-
}
|
|
22262
|
-
function encrypt3(sec, password, logn = 16, ksb = 2) {
|
|
22263
|
-
let salt = randomBytes(16);
|
|
22264
|
-
let n = 2 ** logn;
|
|
22265
|
-
let key = scrypt(password.normalize("NFKC"), salt, { N: n, r: 8, p: 1, dkLen: 32 });
|
|
22266
|
-
let nonce = randomBytes(24);
|
|
22267
|
-
let aad = Uint8Array.from([ksb]);
|
|
22268
|
-
let xc2p1 = xchacha20poly1305(key, nonce, aad);
|
|
22269
|
-
let ciphertext = xc2p1.encrypt(sec);
|
|
22270
|
-
let b = concatBytes(Uint8Array.from([2]), Uint8Array.from([logn]), salt, nonce, aad, ciphertext);
|
|
22271
|
-
return encodeBytes2("ncryptsec", b);
|
|
22272
|
-
}
|
|
22273
|
-
function decrypt3(ncryptsec, password) {
|
|
22274
|
-
let { prefix, words } = bech32.decode(ncryptsec, Bech32MaxSize2);
|
|
22275
|
-
if (prefix !== "ncryptsec") {
|
|
22276
|
-
throw new Error(`invalid prefix ${prefix}, expected 'ncryptsec'`);
|
|
22277
|
-
}
|
|
22278
|
-
let b = new Uint8Array(bech32.fromWords(words));
|
|
22279
|
-
let version2 = b[0];
|
|
22280
|
-
if (version2 !== 2) {
|
|
22281
|
-
throw new Error(`invalid version ${version2}, expected 0x02`);
|
|
22282
|
-
}
|
|
22283
|
-
let logn = b[1];
|
|
22284
|
-
let n = 2 ** logn;
|
|
22285
|
-
let salt = b.slice(2, 2 + 16);
|
|
22286
|
-
let nonce = b.slice(2 + 16, 2 + 16 + 24);
|
|
22287
|
-
let ksb = b[2 + 16 + 24];
|
|
22288
|
-
let aad = Uint8Array.from([ksb]);
|
|
22289
|
-
let ciphertext = b.slice(2 + 16 + 24 + 1);
|
|
22290
|
-
let key = scrypt(password.normalize("NFKC"), salt, { N: n, r: 8, p: 1, dkLen: 32 });
|
|
22291
|
-
let xc2p1 = xchacha20poly1305(key, nonce, aad);
|
|
22292
|
-
let sec = xc2p1.decrypt(ciphertext);
|
|
22293
|
-
return sec;
|
|
22294
|
-
}
|
|
22295
|
-
|
|
22296
22059
|
// ../../node_modules/.pnpm/nostr-tools@2.23.3_typescript@5.9.3/node_modules/nostr-tools/lib/esm/nip46.js
|
|
22297
22060
|
var verifiedSymbol2 = /* @__PURE__ */ Symbol("verified");
|
|
22298
22061
|
var isRecord2 = (obj) => obj instanceof Object;
|
|
@@ -22468,14 +22231,14 @@ function decodePayload2(payload) {
|
|
|
22468
22231
|
mac: data.subarray(-32)
|
|
22469
22232
|
};
|
|
22470
22233
|
}
|
|
22471
|
-
function
|
|
22234
|
+
function encrypt3(plaintext, conversationKey, nonce = randomBytes(32)) {
|
|
22472
22235
|
const { chacha_key, chacha_nonce, hmac_key } = getMessageKeys2(conversationKey, nonce);
|
|
22473
22236
|
const padded = pad2(plaintext);
|
|
22474
22237
|
const ciphertext = chacha20(chacha_key, chacha_nonce, padded);
|
|
22475
22238
|
const mac = hmacAad2(hmac_key, ciphertext, nonce);
|
|
22476
22239
|
return base64.encode(concatBytes(new Uint8Array([2]), nonce, ciphertext, mac));
|
|
22477
22240
|
}
|
|
22478
|
-
function
|
|
22241
|
+
function decrypt3(payload, conversationKey) {
|
|
22479
22242
|
const { nonce, ciphertext, mac } = decodePayload2(payload);
|
|
22480
22243
|
const { chacha_key, chacha_nonce, hmac_key } = getMessageKeys2(conversationKey, nonce);
|
|
22481
22244
|
const calculatedMac = hmacAad2(hmac_key, ciphertext, nonce);
|
|
@@ -23426,7 +23189,7 @@ var BunkerSigner = class {
|
|
|
23426
23189
|
onevent: async (event) => {
|
|
23427
23190
|
try {
|
|
23428
23191
|
const tempConvKey = getConversationKey2(clientSecretKey, event.pubkey);
|
|
23429
|
-
const decryptedContent =
|
|
23192
|
+
const decryptedContent = decrypt3(event.content, tempConvKey);
|
|
23430
23193
|
const response = JSON.parse(decryptedContent);
|
|
23431
23194
|
if (response.result === uri.searchParams.get("secret")) {
|
|
23432
23195
|
sub.close();
|
|
@@ -23469,7 +23232,7 @@ var BunkerSigner = class {
|
|
|
23469
23232
|
},
|
|
23470
23233
|
{
|
|
23471
23234
|
onevent: async (event) => {
|
|
23472
|
-
const o = JSON.parse(
|
|
23235
|
+
const o = JSON.parse(decrypt3(event.content, convKey));
|
|
23473
23236
|
const { id, result, error: error2 } = o;
|
|
23474
23237
|
if (result === "auth_url" && waitingForAuth[id]) {
|
|
23475
23238
|
delete waitingForAuth[id];
|
|
@@ -23531,7 +23294,7 @@ var BunkerSigner = class {
|
|
|
23531
23294
|
this.setupSubscription();
|
|
23532
23295
|
this.serial++;
|
|
23533
23296
|
const id = `${this.idPrefix}-${this.serial}`;
|
|
23534
|
-
const encryptedContent =
|
|
23297
|
+
const encryptedContent = encrypt3(JSON.stringify({ id, method, params }), this.conversationKey);
|
|
23535
23298
|
const verifiedEvent = finalizeEvent2(
|
|
23536
23299
|
{
|
|
23537
23300
|
kind: NostrConnect2,
|
|
@@ -23586,7 +23349,244 @@ var BunkerSigner = class {
|
|
|
23586
23349
|
}
|
|
23587
23350
|
};
|
|
23588
23351
|
|
|
23589
|
-
// ../../node_modules/.pnpm/@
|
|
23352
|
+
// ../../node_modules/.pnpm/@noble+hashes@2.0.1/node_modules/@noble/hashes/pbkdf2.js
|
|
23353
|
+
function pbkdf2Init(hash, _password, _salt, _opts) {
|
|
23354
|
+
ahash(hash);
|
|
23355
|
+
const opts = checkOpts({ dkLen: 32, asyncTick: 10 }, _opts);
|
|
23356
|
+
const { c, dkLen, asyncTick } = opts;
|
|
23357
|
+
anumber(c, "c");
|
|
23358
|
+
anumber(dkLen, "dkLen");
|
|
23359
|
+
anumber(asyncTick, "asyncTick");
|
|
23360
|
+
if (c < 1)
|
|
23361
|
+
throw new Error("iterations (c) must be >= 1");
|
|
23362
|
+
const password = kdfInputToBytes(_password, "password");
|
|
23363
|
+
const salt = kdfInputToBytes(_salt, "salt");
|
|
23364
|
+
const DK = new Uint8Array(dkLen);
|
|
23365
|
+
const PRF = hmac.create(hash, password);
|
|
23366
|
+
const PRFSalt = PRF._cloneInto().update(salt);
|
|
23367
|
+
return { c, dkLen, asyncTick, DK, PRF, PRFSalt };
|
|
23368
|
+
}
|
|
23369
|
+
function pbkdf2Output(PRF, PRFSalt, DK, prfW, u) {
|
|
23370
|
+
PRF.destroy();
|
|
23371
|
+
PRFSalt.destroy();
|
|
23372
|
+
if (prfW)
|
|
23373
|
+
prfW.destroy();
|
|
23374
|
+
clean(u);
|
|
23375
|
+
return DK;
|
|
23376
|
+
}
|
|
23377
|
+
function pbkdf2(hash, password, salt, opts) {
|
|
23378
|
+
const { c, dkLen, DK, PRF, PRFSalt } = pbkdf2Init(hash, password, salt, opts);
|
|
23379
|
+
let prfW;
|
|
23380
|
+
const arr = new Uint8Array(4);
|
|
23381
|
+
const view = createView(arr);
|
|
23382
|
+
const u = new Uint8Array(PRF.outputLen);
|
|
23383
|
+
for (let ti = 1, pos = 0; pos < dkLen; ti++, pos += PRF.outputLen) {
|
|
23384
|
+
const Ti = DK.subarray(pos, pos + PRF.outputLen);
|
|
23385
|
+
view.setInt32(0, ti, false);
|
|
23386
|
+
(prfW = PRFSalt._cloneInto(prfW)).update(arr).digestInto(u);
|
|
23387
|
+
Ti.set(u.subarray(0, Ti.length));
|
|
23388
|
+
for (let ui = 1; ui < c; ui++) {
|
|
23389
|
+
PRF._cloneInto(prfW).update(u).digestInto(u);
|
|
23390
|
+
for (let i4 = 0; i4 < Ti.length; i4++)
|
|
23391
|
+
Ti[i4] ^= u[i4];
|
|
23392
|
+
}
|
|
23393
|
+
}
|
|
23394
|
+
return pbkdf2Output(PRF, PRFSalt, DK, prfW, u);
|
|
23395
|
+
}
|
|
23396
|
+
|
|
23397
|
+
// ../../node_modules/.pnpm/@noble+hashes@2.0.1/node_modules/@noble/hashes/scrypt.js
|
|
23398
|
+
function XorAndSalsa(prev, pi, input, ii, out, oi) {
|
|
23399
|
+
let y00 = prev[pi++] ^ input[ii++], y01 = prev[pi++] ^ input[ii++];
|
|
23400
|
+
let y02 = prev[pi++] ^ input[ii++], y03 = prev[pi++] ^ input[ii++];
|
|
23401
|
+
let y04 = prev[pi++] ^ input[ii++], y05 = prev[pi++] ^ input[ii++];
|
|
23402
|
+
let y06 = prev[pi++] ^ input[ii++], y07 = prev[pi++] ^ input[ii++];
|
|
23403
|
+
let y08 = prev[pi++] ^ input[ii++], y09 = prev[pi++] ^ input[ii++];
|
|
23404
|
+
let y10 = prev[pi++] ^ input[ii++], y11 = prev[pi++] ^ input[ii++];
|
|
23405
|
+
let y12 = prev[pi++] ^ input[ii++], y13 = prev[pi++] ^ input[ii++];
|
|
23406
|
+
let y14 = prev[pi++] ^ input[ii++], y15 = prev[pi++] ^ input[ii++];
|
|
23407
|
+
let x00 = y00, x01 = y01, x02 = y02, x03 = y03, x04 = y04, x05 = y05, x06 = y06, x07 = y07, x08 = y08, x09 = y09, x10 = y10, x11 = y11, x12 = y12, x13 = y13, x14 = y14, x15 = y15;
|
|
23408
|
+
for (let i4 = 0; i4 < 8; i4 += 2) {
|
|
23409
|
+
x04 ^= rotl(x00 + x12 | 0, 7);
|
|
23410
|
+
x08 ^= rotl(x04 + x00 | 0, 9);
|
|
23411
|
+
x12 ^= rotl(x08 + x04 | 0, 13);
|
|
23412
|
+
x00 ^= rotl(x12 + x08 | 0, 18);
|
|
23413
|
+
x09 ^= rotl(x05 + x01 | 0, 7);
|
|
23414
|
+
x13 ^= rotl(x09 + x05 | 0, 9);
|
|
23415
|
+
x01 ^= rotl(x13 + x09 | 0, 13);
|
|
23416
|
+
x05 ^= rotl(x01 + x13 | 0, 18);
|
|
23417
|
+
x14 ^= rotl(x10 + x06 | 0, 7);
|
|
23418
|
+
x02 ^= rotl(x14 + x10 | 0, 9);
|
|
23419
|
+
x06 ^= rotl(x02 + x14 | 0, 13);
|
|
23420
|
+
x10 ^= rotl(x06 + x02 | 0, 18);
|
|
23421
|
+
x03 ^= rotl(x15 + x11 | 0, 7);
|
|
23422
|
+
x07 ^= rotl(x03 + x15 | 0, 9);
|
|
23423
|
+
x11 ^= rotl(x07 + x03 | 0, 13);
|
|
23424
|
+
x15 ^= rotl(x11 + x07 | 0, 18);
|
|
23425
|
+
x01 ^= rotl(x00 + x03 | 0, 7);
|
|
23426
|
+
x02 ^= rotl(x01 + x00 | 0, 9);
|
|
23427
|
+
x03 ^= rotl(x02 + x01 | 0, 13);
|
|
23428
|
+
x00 ^= rotl(x03 + x02 | 0, 18);
|
|
23429
|
+
x06 ^= rotl(x05 + x04 | 0, 7);
|
|
23430
|
+
x07 ^= rotl(x06 + x05 | 0, 9);
|
|
23431
|
+
x04 ^= rotl(x07 + x06 | 0, 13);
|
|
23432
|
+
x05 ^= rotl(x04 + x07 | 0, 18);
|
|
23433
|
+
x11 ^= rotl(x10 + x09 | 0, 7);
|
|
23434
|
+
x08 ^= rotl(x11 + x10 | 0, 9);
|
|
23435
|
+
x09 ^= rotl(x08 + x11 | 0, 13);
|
|
23436
|
+
x10 ^= rotl(x09 + x08 | 0, 18);
|
|
23437
|
+
x12 ^= rotl(x15 + x14 | 0, 7);
|
|
23438
|
+
x13 ^= rotl(x12 + x15 | 0, 9);
|
|
23439
|
+
x14 ^= rotl(x13 + x12 | 0, 13);
|
|
23440
|
+
x15 ^= rotl(x14 + x13 | 0, 18);
|
|
23441
|
+
}
|
|
23442
|
+
out[oi++] = y00 + x00 | 0;
|
|
23443
|
+
out[oi++] = y01 + x01 | 0;
|
|
23444
|
+
out[oi++] = y02 + x02 | 0;
|
|
23445
|
+
out[oi++] = y03 + x03 | 0;
|
|
23446
|
+
out[oi++] = y04 + x04 | 0;
|
|
23447
|
+
out[oi++] = y05 + x05 | 0;
|
|
23448
|
+
out[oi++] = y06 + x06 | 0;
|
|
23449
|
+
out[oi++] = y07 + x07 | 0;
|
|
23450
|
+
out[oi++] = y08 + x08 | 0;
|
|
23451
|
+
out[oi++] = y09 + x09 | 0;
|
|
23452
|
+
out[oi++] = y10 + x10 | 0;
|
|
23453
|
+
out[oi++] = y11 + x11 | 0;
|
|
23454
|
+
out[oi++] = y12 + x12 | 0;
|
|
23455
|
+
out[oi++] = y13 + x13 | 0;
|
|
23456
|
+
out[oi++] = y14 + x14 | 0;
|
|
23457
|
+
out[oi++] = y15 + x15 | 0;
|
|
23458
|
+
}
|
|
23459
|
+
function BlockMix(input, ii, out, oi, r) {
|
|
23460
|
+
let head = oi + 0;
|
|
23461
|
+
let tail = oi + 16 * r;
|
|
23462
|
+
for (let i4 = 0; i4 < 16; i4++)
|
|
23463
|
+
out[tail + i4] = input[ii + (2 * r - 1) * 16 + i4];
|
|
23464
|
+
for (let i4 = 0; i4 < r; i4++, head += 16, ii += 16) {
|
|
23465
|
+
XorAndSalsa(out, tail, input, ii, out, head);
|
|
23466
|
+
if (i4 > 0)
|
|
23467
|
+
tail += 16;
|
|
23468
|
+
XorAndSalsa(out, head, input, ii += 16, out, tail);
|
|
23469
|
+
}
|
|
23470
|
+
}
|
|
23471
|
+
function scryptInit(password, salt, _opts) {
|
|
23472
|
+
const opts = checkOpts({
|
|
23473
|
+
dkLen: 32,
|
|
23474
|
+
asyncTick: 10,
|
|
23475
|
+
maxmem: 1024 ** 3 + 1024
|
|
23476
|
+
}, _opts);
|
|
23477
|
+
const { N, r, p, dkLen, asyncTick, maxmem, onProgress } = opts;
|
|
23478
|
+
anumber(N, "N");
|
|
23479
|
+
anumber(r, "r");
|
|
23480
|
+
anumber(p, "p");
|
|
23481
|
+
anumber(dkLen, "dkLen");
|
|
23482
|
+
anumber(asyncTick, "asyncTick");
|
|
23483
|
+
anumber(maxmem, "maxmem");
|
|
23484
|
+
if (onProgress !== void 0 && typeof onProgress !== "function")
|
|
23485
|
+
throw new Error("progressCb must be a function");
|
|
23486
|
+
const blockSize = 128 * r;
|
|
23487
|
+
const blockSize32 = blockSize / 4;
|
|
23488
|
+
const pow32 = Math.pow(2, 32);
|
|
23489
|
+
if (N <= 1 || (N & N - 1) !== 0 || N > pow32)
|
|
23490
|
+
throw new Error('"N" expected a power of 2, and 2^1 <= N <= 2^32');
|
|
23491
|
+
if (p < 1 || p > (pow32 - 1) * 32 / blockSize)
|
|
23492
|
+
throw new Error('"p" expected integer 1..((2^32 - 1) * 32) / (128 * r)');
|
|
23493
|
+
if (dkLen < 1 || dkLen > (pow32 - 1) * 32)
|
|
23494
|
+
throw new Error('"dkLen" expected integer 1..(2^32 - 1) * 32');
|
|
23495
|
+
const memUsed = blockSize * (N + p);
|
|
23496
|
+
if (memUsed > maxmem)
|
|
23497
|
+
throw new Error('"maxmem" limit was hit, expected 128*r*(N+p) <= "maxmem"=' + maxmem);
|
|
23498
|
+
const B = pbkdf2(sha256, password, salt, { c: 1, dkLen: blockSize * p });
|
|
23499
|
+
const B32 = u32(B);
|
|
23500
|
+
const V = u32(new Uint8Array(blockSize * N));
|
|
23501
|
+
const tmp = u32(new Uint8Array(blockSize));
|
|
23502
|
+
let blockMixCb = () => {
|
|
23503
|
+
};
|
|
23504
|
+
if (onProgress) {
|
|
23505
|
+
const totalBlockMix = 2 * N * p;
|
|
23506
|
+
const callbackPer = Math.max(Math.floor(totalBlockMix / 1e4), 1);
|
|
23507
|
+
let blockMixCnt = 0;
|
|
23508
|
+
blockMixCb = () => {
|
|
23509
|
+
blockMixCnt++;
|
|
23510
|
+
if (onProgress && (!(blockMixCnt % callbackPer) || blockMixCnt === totalBlockMix))
|
|
23511
|
+
onProgress(blockMixCnt / totalBlockMix);
|
|
23512
|
+
};
|
|
23513
|
+
}
|
|
23514
|
+
return { N, r, p, dkLen, blockSize32, V, B32, B, tmp, blockMixCb, asyncTick };
|
|
23515
|
+
}
|
|
23516
|
+
function scryptOutput(password, dkLen, B, V, tmp) {
|
|
23517
|
+
const res = pbkdf2(sha256, password, B, { c: 1, dkLen });
|
|
23518
|
+
clean(B, V, tmp);
|
|
23519
|
+
return res;
|
|
23520
|
+
}
|
|
23521
|
+
function scrypt(password, salt, opts) {
|
|
23522
|
+
const { N, r, p, dkLen, blockSize32, V, B32, B, tmp, blockMixCb } = scryptInit(password, salt, opts);
|
|
23523
|
+
swap32IfBE(B32);
|
|
23524
|
+
for (let pi = 0; pi < p; pi++) {
|
|
23525
|
+
const Pi = blockSize32 * pi;
|
|
23526
|
+
for (let i4 = 0; i4 < blockSize32; i4++)
|
|
23527
|
+
V[i4] = B32[Pi + i4];
|
|
23528
|
+
for (let i4 = 0, pos = 0; i4 < N - 1; i4++) {
|
|
23529
|
+
BlockMix(V, pos, V, pos += blockSize32, r);
|
|
23530
|
+
blockMixCb();
|
|
23531
|
+
}
|
|
23532
|
+
BlockMix(V, (N - 1) * blockSize32, B32, Pi, r);
|
|
23533
|
+
blockMixCb();
|
|
23534
|
+
for (let i4 = 0; i4 < N; i4++) {
|
|
23535
|
+
const j = (B32[Pi + blockSize32 - 16] & N - 1) >>> 0;
|
|
23536
|
+
for (let k = 0; k < blockSize32; k++)
|
|
23537
|
+
tmp[k] = B32[Pi + k] ^ V[j * blockSize32 + k];
|
|
23538
|
+
BlockMix(tmp, 0, B32, Pi, r);
|
|
23539
|
+
blockMixCb();
|
|
23540
|
+
}
|
|
23541
|
+
}
|
|
23542
|
+
swap32IfBE(B32);
|
|
23543
|
+
return scryptOutput(password, dkLen, B, V, tmp);
|
|
23544
|
+
}
|
|
23545
|
+
|
|
23546
|
+
// ../../node_modules/.pnpm/nostr-tools@2.23.3_typescript@5.9.3/node_modules/nostr-tools/lib/esm/nip49.js
|
|
23547
|
+
var Bech32MaxSize2 = 5e3;
|
|
23548
|
+
function encodeBech322(prefix, data) {
|
|
23549
|
+
let words = bech32.toWords(data);
|
|
23550
|
+
return bech32.encode(prefix, words, Bech32MaxSize2);
|
|
23551
|
+
}
|
|
23552
|
+
function encodeBytes2(prefix, bytes) {
|
|
23553
|
+
return encodeBech322(prefix, bytes);
|
|
23554
|
+
}
|
|
23555
|
+
function encrypt4(sec, password, logn = 16, ksb = 2) {
|
|
23556
|
+
let salt = randomBytes(16);
|
|
23557
|
+
let n = 2 ** logn;
|
|
23558
|
+
let key = scrypt(password.normalize("NFKC"), salt, { N: n, r: 8, p: 1, dkLen: 32 });
|
|
23559
|
+
let nonce = randomBytes(24);
|
|
23560
|
+
let aad = Uint8Array.from([ksb]);
|
|
23561
|
+
let xc2p1 = xchacha20poly1305(key, nonce, aad);
|
|
23562
|
+
let ciphertext = xc2p1.encrypt(sec);
|
|
23563
|
+
let b = concatBytes(Uint8Array.from([2]), Uint8Array.from([logn]), salt, nonce, aad, ciphertext);
|
|
23564
|
+
return encodeBytes2("ncryptsec", b);
|
|
23565
|
+
}
|
|
23566
|
+
function decrypt4(ncryptsec, password) {
|
|
23567
|
+
let { prefix, words } = bech32.decode(ncryptsec, Bech32MaxSize2);
|
|
23568
|
+
if (prefix !== "ncryptsec") {
|
|
23569
|
+
throw new Error(`invalid prefix ${prefix}, expected 'ncryptsec'`);
|
|
23570
|
+
}
|
|
23571
|
+
let b = new Uint8Array(bech32.fromWords(words));
|
|
23572
|
+
let version2 = b[0];
|
|
23573
|
+
if (version2 !== 2) {
|
|
23574
|
+
throw new Error(`invalid version ${version2}, expected 0x02`);
|
|
23575
|
+
}
|
|
23576
|
+
let logn = b[1];
|
|
23577
|
+
let n = 2 ** logn;
|
|
23578
|
+
let salt = b.slice(2, 2 + 16);
|
|
23579
|
+
let nonce = b.slice(2 + 16, 2 + 16 + 24);
|
|
23580
|
+
let ksb = b[2 + 16 + 24];
|
|
23581
|
+
let aad = Uint8Array.from([ksb]);
|
|
23582
|
+
let ciphertext = b.slice(2 + 16 + 24 + 1);
|
|
23583
|
+
let key = scrypt(password.normalize("NFKC"), salt, { N: n, r: 8, p: 1, dkLen: 32 });
|
|
23584
|
+
let xc2p1 = xchacha20poly1305(key, nonce, aad);
|
|
23585
|
+
let sec = xc2p1.decrypt(ciphertext);
|
|
23586
|
+
return sec;
|
|
23587
|
+
}
|
|
23588
|
+
|
|
23589
|
+
// ../../node_modules/.pnpm/@formstr+signer@0.2.2_typescript@5.9.3/node_modules/@formstr/signer/dist/index.js
|
|
23590
23590
|
var DEFAULT_PREFIX = "@formstr/signer:";
|
|
23591
23591
|
function localStorageAdapter(prefix = DEFAULT_PREFIX) {
|
|
23592
23592
|
const ls = () => {
|
|
@@ -23645,16 +23645,16 @@ var LocalSigner = class {
|
|
|
23645
23645
|
}
|
|
23646
23646
|
};
|
|
23647
23647
|
function encryptSecretKey(secretKey, passphrase) {
|
|
23648
|
-
return
|
|
23648
|
+
return encrypt4(secretKey, passphrase);
|
|
23649
23649
|
}
|
|
23650
23650
|
function decryptNcryptsec(ncryptsec, passphrase) {
|
|
23651
|
-
return
|
|
23651
|
+
return decrypt4(ncryptsec, passphrase);
|
|
23652
23652
|
}
|
|
23653
23653
|
function generateAccount(passphrase) {
|
|
23654
23654
|
const secretKey = generateSecretKey();
|
|
23655
23655
|
const pubkey = getPublicKey(secretKey);
|
|
23656
23656
|
const npub2 = nip19_exports.npubEncode(pubkey);
|
|
23657
|
-
const ncryptsec =
|
|
23657
|
+
const ncryptsec = encrypt4(secretKey, passphrase);
|
|
23658
23658
|
return { secretKey, pubkey, npub: npub2, ncryptsec };
|
|
23659
23659
|
}
|
|
23660
23660
|
function getWindowNostr() {
|
|
@@ -23696,10 +23696,15 @@ var ExtensionSigner = class {
|
|
|
23696
23696
|
};
|
|
23697
23697
|
var BunkerSigner2 = class {
|
|
23698
23698
|
#delegate;
|
|
23699
|
-
|
|
23699
|
+
#cachedUserPubkey;
|
|
23700
|
+
constructor(delegate, cachedUserPubkey) {
|
|
23700
23701
|
this.#delegate = delegate;
|
|
23702
|
+
this.#cachedUserPubkey = cachedUserPubkey ?? null;
|
|
23701
23703
|
}
|
|
23702
23704
|
getPublicKey() {
|
|
23705
|
+
if (this.#cachedUserPubkey !== null) {
|
|
23706
|
+
return Promise.resolve(this.#cachedUserPubkey);
|
|
23707
|
+
}
|
|
23703
23708
|
return this.#delegate.getPublicKey();
|
|
23704
23709
|
}
|
|
23705
23710
|
signEvent(event) {
|
|
@@ -23775,7 +23780,7 @@ async function connectWithBunkerUri(uri, options = {}) {
|
|
|
23775
23780
|
options.onRelayMismatch
|
|
23776
23781
|
);
|
|
23777
23782
|
return {
|
|
23778
|
-
signer: new BunkerSigner2(tools),
|
|
23783
|
+
signer: new BunkerSigner2(tools, pubkey),
|
|
23779
23784
|
pubkey,
|
|
23780
23785
|
pointer: { ...pointer, relays: resolvedRelays },
|
|
23781
23786
|
clientSecretKey
|
|
@@ -23811,7 +23816,7 @@ function initiateNostrConnect(options) {
|
|
|
23811
23816
|
options.onRelayMismatch
|
|
23812
23817
|
);
|
|
23813
23818
|
return {
|
|
23814
|
-
signer: new BunkerSigner2(tools),
|
|
23819
|
+
signer: new BunkerSigner2(tools, pubkey),
|
|
23815
23820
|
pubkey,
|
|
23816
23821
|
pointer: { ...tools.bp, relays: resolvedRelays },
|
|
23817
23822
|
clientSecretKey
|
|
@@ -23899,28 +23904,57 @@ var AndroidSigner = class {
|
|
|
23899
23904
|
return result;
|
|
23900
23905
|
}
|
|
23901
23906
|
};
|
|
23907
|
+
function describeIdentifier(value) {
|
|
23908
|
+
if (value === null) return "null";
|
|
23909
|
+
if (value === void 0) return "undefined";
|
|
23910
|
+
if (typeof value !== "string") {
|
|
23911
|
+
return `<${typeof value}>`;
|
|
23912
|
+
}
|
|
23913
|
+
if (value.length === 0) return "empty string";
|
|
23914
|
+
const prefix = value.slice(0, 12);
|
|
23915
|
+
const suffix = value.length > 12 ? "\u2026" : "";
|
|
23916
|
+
return `"${prefix}${suffix}" (length=${value.length})`;
|
|
23917
|
+
}
|
|
23918
|
+
var HEX_PUBKEY_RE = /^[0-9a-f]{64}$/i;
|
|
23902
23919
|
async function loginWithAndroidSigner(plugin, packageName) {
|
|
23903
23920
|
if (packageName) {
|
|
23904
23921
|
await plugin.setPackageName(packageName);
|
|
23905
23922
|
}
|
|
23906
|
-
const { npub:
|
|
23923
|
+
const { npub: rawIdentifier, package: pluginPackage } = await plugin.getPublicKey(packageName);
|
|
23907
23924
|
const resolvedPackage = pluginPackage || packageName;
|
|
23908
23925
|
if (!resolvedPackage) {
|
|
23909
23926
|
throw new Error(
|
|
23910
23927
|
"@formstr/signer: android signer did not return a package name and none was supplied"
|
|
23911
23928
|
);
|
|
23912
23929
|
}
|
|
23913
|
-
const
|
|
23914
|
-
if (decoded.type !== "npub") {
|
|
23915
|
-
throw new Error("@formstr/signer: android signer returned a non-npub identifier");
|
|
23916
|
-
}
|
|
23930
|
+
const { pubkey, npub: npub2 } = normalizeAndroidIdentifier(rawIdentifier);
|
|
23917
23931
|
return {
|
|
23918
|
-
signer: new AndroidSigner(plugin, resolvedPackage, npub2,
|
|
23919
|
-
pubkey
|
|
23932
|
+
signer: new AndroidSigner(plugin, resolvedPackage, npub2, pubkey),
|
|
23933
|
+
pubkey,
|
|
23920
23934
|
npub: npub2,
|
|
23921
23935
|
packageName: resolvedPackage
|
|
23922
23936
|
};
|
|
23923
23937
|
}
|
|
23938
|
+
function normalizeAndroidIdentifier(rawIdentifier) {
|
|
23939
|
+
if (typeof rawIdentifier === "string" && HEX_PUBKEY_RE.test(rawIdentifier)) {
|
|
23940
|
+
const pubkey = rawIdentifier.toLowerCase();
|
|
23941
|
+
return { pubkey, npub: nip19_exports.npubEncode(pubkey) };
|
|
23942
|
+
}
|
|
23943
|
+
let decoded;
|
|
23944
|
+
try {
|
|
23945
|
+
decoded = nip19_exports.decode(rawIdentifier);
|
|
23946
|
+
} catch (e) {
|
|
23947
|
+
throw new Error(
|
|
23948
|
+
`@formstr/signer: android signer returned an undecodable identifier (got ${describeIdentifier(rawIdentifier)}): ${e.message}`
|
|
23949
|
+
);
|
|
23950
|
+
}
|
|
23951
|
+
if (decoded.type !== "npub") {
|
|
23952
|
+
throw new Error(
|
|
23953
|
+
`@formstr/signer: android signer returned a non-npub identifier (type=${decoded.type}, got ${describeIdentifier(rawIdentifier)})`
|
|
23954
|
+
);
|
|
23955
|
+
}
|
|
23956
|
+
return { pubkey: decoded.data, npub: rawIdentifier };
|
|
23957
|
+
}
|
|
23924
23958
|
var ACCOUNTS_KEY = "accounts";
|
|
23925
23959
|
var ACTIVE_KEY = "active-pubkey";
|
|
23926
23960
|
var Signer = class {
|
|
@@ -24183,6 +24217,88 @@ var Signer = class {
|
|
|
24183
24217
|
getActiveSigner() {
|
|
24184
24218
|
return this.#activeSigner;
|
|
24185
24219
|
}
|
|
24220
|
+
/**
|
|
24221
|
+
* Silently unlock the active account from persisted state — no user
|
|
24222
|
+
* prompt, no fresh pairing. The package already keeps everything it
|
|
24223
|
+
* needs to reconstruct the runtime signer on disk; this method is the
|
|
24224
|
+
* way to actually use that on cold start instead of re-running each
|
|
24225
|
+
* method's first-time login flow.
|
|
24226
|
+
*
|
|
24227
|
+
* Behavior by method:
|
|
24228
|
+
*
|
|
24229
|
+
* - `extension`: constructs an {@link ExtensionSigner}, which just
|
|
24230
|
+
* proxies to `window.nostr`. No setup roundtrip — individual
|
|
24231
|
+
* operations may still prompt depending on the extension's own
|
|
24232
|
+
* permission state, but unlock itself does not.
|
|
24233
|
+
*
|
|
24234
|
+
* - `nip46`: reuses the stored `clientSecretKey` to construct a
|
|
24235
|
+
* {@link BunkerSigner} against the stored bunker pubkey + relays
|
|
24236
|
+
* via `BunkerSigner.fromBunker`. Deliberately skips the `connect`
|
|
24237
|
+
* request — the remote signer (Amber etc.) approved this client
|
|
24238
|
+
* pubkey on first pairing and re-sending `connect` is what surfaces
|
|
24239
|
+
* a fresh approval prompt every cold start. Requires `options.pool`
|
|
24240
|
+
* so the BunkerSigner has somewhere to listen for responses.
|
|
24241
|
+
* The cached user pubkey is fed into the wrapper so a follow-up
|
|
24242
|
+
* `getPublicKey()` is a memory read, not a relay request.
|
|
24243
|
+
*
|
|
24244
|
+
* - `android`: constructs an {@link AndroidSigner} directly from the
|
|
24245
|
+
* stored `androidPackageName` + `pubkey` + `npub`. Skips the
|
|
24246
|
+
* `getPublicKey` content-provider roundtrip that
|
|
24247
|
+
* {@link loginWithAndroidSigner} performs and that — on Amber —
|
|
24248
|
+
* surfaces as a permission prompt every cold start.
|
|
24249
|
+
*
|
|
24250
|
+
* - `ncryptsec`: returns `null`. There is no silent path — the user's
|
|
24251
|
+
* passphrase isn't (and shouldn't be) persisted. The caller must
|
|
24252
|
+
* drive the passphrase prompt and call {@link loginWithNcryptsec}.
|
|
24253
|
+
*
|
|
24254
|
+
* Returns `null` (without emitting any event or mutating state) when
|
|
24255
|
+
* there is no active account, when the account is missing fields
|
|
24256
|
+
* required to unlock, when `nip46` is the method but no `pool` was
|
|
24257
|
+
* supplied, or when `android` is the method but no plugin is
|
|
24258
|
+
* configured. On success emits the same `login` / `switch` event the
|
|
24259
|
+
* corresponding `loginWith*` would.
|
|
24260
|
+
*/
|
|
24261
|
+
async unlock(options = {}) {
|
|
24262
|
+
const account = this.getActiveAccount();
|
|
24263
|
+
if (!account) return null;
|
|
24264
|
+
switch (account.method) {
|
|
24265
|
+
case "extension": {
|
|
24266
|
+
const signer = new ExtensionSigner();
|
|
24267
|
+
this.#setActive(account, signer);
|
|
24268
|
+
return signer;
|
|
24269
|
+
}
|
|
24270
|
+
case "nip46": {
|
|
24271
|
+
if (!account.nip46) return null;
|
|
24272
|
+
if (!options.pool) return null;
|
|
24273
|
+
const { remoteSignerPubkey, relays, clientSecretKey } = account.nip46;
|
|
24274
|
+
if (!remoteSignerPubkey || !relays.length || !clientSecretKey) {
|
|
24275
|
+
return null;
|
|
24276
|
+
}
|
|
24277
|
+
const tools = BunkerSigner.fromBunker(
|
|
24278
|
+
hexToBytes2(clientSecretKey),
|
|
24279
|
+
{ pubkey: remoteSignerPubkey, relays, secret: null },
|
|
24280
|
+
{ pool: options.pool }
|
|
24281
|
+
);
|
|
24282
|
+
const signer = new BunkerSigner2(tools, account.pubkey);
|
|
24283
|
+
this.#setActive(account, signer);
|
|
24284
|
+
return signer;
|
|
24285
|
+
}
|
|
24286
|
+
case "android": {
|
|
24287
|
+
if (!account.androidPackageName) return null;
|
|
24288
|
+
if (!this.#defaultAndroidPlugin) return null;
|
|
24289
|
+
const signer = new AndroidSigner(
|
|
24290
|
+
this.#defaultAndroidPlugin,
|
|
24291
|
+
account.androidPackageName,
|
|
24292
|
+
account.npub,
|
|
24293
|
+
account.pubkey
|
|
24294
|
+
);
|
|
24295
|
+
this.#setActive(account, signer);
|
|
24296
|
+
return signer;
|
|
24297
|
+
}
|
|
24298
|
+
case "ncryptsec":
|
|
24299
|
+
return null;
|
|
24300
|
+
}
|
|
24301
|
+
}
|
|
24186
24302
|
/**
|
|
24187
24303
|
* Make `pubkey` the active account. Clears the in-memory signer —
|
|
24188
24304
|
* the new account starts **locked** even if it was previously
|
|
@@ -25400,25 +25516,39 @@ function createPatchedPool() {
|
|
|
25400
25516
|
|
|
25401
25517
|
// src/auth/terminal.ts
|
|
25402
25518
|
var readline = __toESM(require("readline"));
|
|
25519
|
+
var import_node_stream = require("stream");
|
|
25403
25520
|
var import_qrcode = __toESM(require_lib());
|
|
25404
25521
|
function createTerminalIo() {
|
|
25405
|
-
const
|
|
25522
|
+
const stderr = process.stderr;
|
|
25523
|
+
let muted = false;
|
|
25524
|
+
const output = new import_node_stream.Writable({
|
|
25525
|
+
write(chunk, _enc, cb) {
|
|
25526
|
+
if (!muted) stderr.write(chunk);
|
|
25527
|
+
cb();
|
|
25528
|
+
}
|
|
25529
|
+
});
|
|
25530
|
+
Object.defineProperties(output, {
|
|
25531
|
+
isTTY: { get: () => stderr.isTTY },
|
|
25532
|
+
columns: { get: () => stderr.columns },
|
|
25533
|
+
rows: { get: () => stderr.rows }
|
|
25534
|
+
});
|
|
25535
|
+
const rl = readline.createInterface({
|
|
25536
|
+
input: process.stdin,
|
|
25537
|
+
output,
|
|
25538
|
+
terminal: Boolean(process.stdin.isTTY)
|
|
25539
|
+
});
|
|
25406
25540
|
return {
|
|
25407
25541
|
prompt(question) {
|
|
25408
25542
|
return new Promise((resolve) => rl.question(question, resolve));
|
|
25409
25543
|
},
|
|
25410
25544
|
promptPassphrase(question) {
|
|
25411
25545
|
return new Promise((resolve) => {
|
|
25412
|
-
|
|
25413
|
-
|
|
25414
|
-
|
|
25415
|
-
muted._writeToOutput = () => {
|
|
25416
|
-
};
|
|
25417
|
-
rl.question("", (answer) => {
|
|
25418
|
-
muted._writeToOutput = original;
|
|
25419
|
-
process.stderr.write("\n");
|
|
25546
|
+
rl.question(question, (answer) => {
|
|
25547
|
+
muted = false;
|
|
25548
|
+
stderr.write("\n");
|
|
25420
25549
|
resolve(answer);
|
|
25421
25550
|
});
|
|
25551
|
+
muted = true;
|
|
25422
25552
|
});
|
|
25423
25553
|
},
|
|
25424
25554
|
close() {
|
|
@@ -26027,15 +26157,29 @@ var EventStore = class {
|
|
|
26027
26157
|
eventsByDTag = /* @__PURE__ */ new Map();
|
|
26028
26158
|
// "kind:pubkey:dtag" → event
|
|
26029
26159
|
deletedIds = /* @__PURE__ */ new Set();
|
|
26160
|
+
// NIP-09 coordinate tombstones: "kind:pubkey:dtag" → newest deletion created_at.
|
|
26161
|
+
// An addressable event is only rejected when its created_at ≤ that time, so a
|
|
26162
|
+
// legitimate re-publish after a delete survives.
|
|
26163
|
+
deletedCoordinates = /* @__PURE__ */ new Map();
|
|
26164
|
+
// Kind-84 participant-removal tombstones.
|
|
26165
|
+
ignoredEventIds = /* @__PURE__ */ new Set();
|
|
26166
|
+
ignoredCoordinates = /* @__PURE__ */ new Set();
|
|
26030
26167
|
subscriptions = [];
|
|
26031
26168
|
/** Store event. Returns false if duplicate or older replaceable. */
|
|
26032
26169
|
store(event) {
|
|
26033
26170
|
if (this.deletedIds.has(event.id))
|
|
26034
26171
|
return false;
|
|
26172
|
+
if (this.ignoredEventIds.has(event.id))
|
|
26173
|
+
return false;
|
|
26035
26174
|
if (this.eventsById.has(event.id))
|
|
26036
26175
|
return false;
|
|
26037
26176
|
if (this.isReplaceable(event.kind) || this.isParameterizedReplaceable(event.kind)) {
|
|
26038
26177
|
const addr = this.getAddress(event);
|
|
26178
|
+
const deletedAt = this.deletedCoordinates.get(addr);
|
|
26179
|
+
if (deletedAt !== void 0 && event.created_at <= deletedAt)
|
|
26180
|
+
return false;
|
|
26181
|
+
if (this.ignoredCoordinates.has(addr))
|
|
26182
|
+
return false;
|
|
26039
26183
|
const existing = this.eventsByDTag.get(addr);
|
|
26040
26184
|
if (existing && existing.created_at >= event.created_at) {
|
|
26041
26185
|
return false;
|
|
@@ -26050,6 +26194,9 @@ var EventStore = class {
|
|
|
26050
26194
|
if (event.kind === 5) {
|
|
26051
26195
|
this.handleDeletion(event);
|
|
26052
26196
|
}
|
|
26197
|
+
if (event.kind === 84) {
|
|
26198
|
+
this.handleParticipantRemoval(event);
|
|
26199
|
+
}
|
|
26053
26200
|
this.eventsById.set(event.id, event);
|
|
26054
26201
|
if (!this.eventsByKind.has(event.kind)) {
|
|
26055
26202
|
this.eventsByKind.set(event.kind, /* @__PURE__ */ new Map());
|
|
@@ -26118,14 +26265,50 @@ var EventStore = class {
|
|
|
26118
26265
|
if (tag[0] === "e" && tag[1]) {
|
|
26119
26266
|
const targetId = tag[1];
|
|
26120
26267
|
const target = this.eventsById.get(targetId);
|
|
26121
|
-
if (target && target.pubkey
|
|
26122
|
-
|
|
26123
|
-
}
|
|
26268
|
+
if (target && target.pubkey !== deletionEvent.pubkey)
|
|
26269
|
+
continue;
|
|
26124
26270
|
this.deletedIds.add(targetId);
|
|
26271
|
+
if (target)
|
|
26272
|
+
this.remove(targetId);
|
|
26125
26273
|
}
|
|
26126
26274
|
if (tag[0] === "a" && tag[1]) {
|
|
26275
|
+
const coordAuthor = tag[1].split(":")[1];
|
|
26276
|
+
if (coordAuthor && coordAuthor !== deletionEvent.pubkey)
|
|
26277
|
+
continue;
|
|
26278
|
+
const prev = this.deletedCoordinates.get(tag[1]) ?? 0;
|
|
26279
|
+
if (deletionEvent.created_at > prev) {
|
|
26280
|
+
this.deletedCoordinates.set(tag[1], deletionEvent.created_at);
|
|
26281
|
+
}
|
|
26127
26282
|
const existing = this.eventsByDTag.get(tag[1]);
|
|
26128
|
-
if (existing && existing.
|
|
26283
|
+
if (existing && existing.created_at <= deletionEvent.created_at) {
|
|
26284
|
+
this.remove(existing.id);
|
|
26285
|
+
this.eventsByDTag.delete(tag[1]);
|
|
26286
|
+
}
|
|
26287
|
+
}
|
|
26288
|
+
}
|
|
26289
|
+
}
|
|
26290
|
+
/**
|
|
26291
|
+
* Process a kind-84 participant removal (a participant opting out of an
|
|
26292
|
+
* event). Unlike NIP-09 there is no same-author rule — any participant
|
|
26293
|
+
* (`p` tag on the target) may remove it for themselves; targets that aren't
|
|
26294
|
+
* cached yet are tombstoned unconditionally, matching the standalone
|
|
26295
|
+
* calendar's EventStore.
|
|
26296
|
+
*/
|
|
26297
|
+
handleParticipantRemoval(removalEvent) {
|
|
26298
|
+
const isParticipant = (target) => target.tags.some((t) => t[0] === "p" && t[1] === removalEvent.pubkey);
|
|
26299
|
+
for (const tag of removalEvent.tags) {
|
|
26300
|
+
if (tag[0] === "e" && tag[1]) {
|
|
26301
|
+
const existing = this.eventsById.get(tag[1]);
|
|
26302
|
+
if (existing) {
|
|
26303
|
+
if (!isParticipant(existing))
|
|
26304
|
+
continue;
|
|
26305
|
+
this.remove(tag[1]);
|
|
26306
|
+
}
|
|
26307
|
+
this.ignoredEventIds.add(tag[1]);
|
|
26308
|
+
} else if (tag[0] === "a" && tag[1]) {
|
|
26309
|
+
this.ignoredCoordinates.add(tag[1]);
|
|
26310
|
+
const existing = this.eventsByDTag.get(tag[1]);
|
|
26311
|
+
if (existing && isParticipant(existing)) {
|
|
26129
26312
|
this.remove(existing.id);
|
|
26130
26313
|
this.eventsByDTag.delete(tag[1]);
|
|
26131
26314
|
}
|
|
@@ -26149,6 +26332,9 @@ var EventStore = class {
|
|
|
26149
26332
|
this.eventsByAuthor.clear();
|
|
26150
26333
|
this.eventsByDTag.clear();
|
|
26151
26334
|
this.deletedIds.clear();
|
|
26335
|
+
this.deletedCoordinates.clear();
|
|
26336
|
+
this.ignoredEventIds.clear();
|
|
26337
|
+
this.ignoredCoordinates.clear();
|
|
26152
26338
|
this.subscriptions = [];
|
|
26153
26339
|
}
|
|
26154
26340
|
get size() {
|
|
@@ -26385,9 +26571,20 @@ var NostrRuntime = class {
|
|
|
26385
26571
|
}
|
|
26386
26572
|
});
|
|
26387
26573
|
}
|
|
26388
|
-
/**
|
|
26389
|
-
|
|
26390
|
-
|
|
26574
|
+
/**
|
|
26575
|
+
* Publish event to relays. Bounded by `timeoutMs`: a relay that never acks must
|
|
26576
|
+
* not hang the caller (e.g. a form submit) forever — best-effort fan-out.
|
|
26577
|
+
*/
|
|
26578
|
+
async publish(relays, event, timeoutMs = 1e4) {
|
|
26579
|
+
let timer;
|
|
26580
|
+
const timeout = new Promise((resolve) => {
|
|
26581
|
+
timer = setTimeout(resolve, timeoutMs);
|
|
26582
|
+
});
|
|
26583
|
+
try {
|
|
26584
|
+
await Promise.race([Promise.allSettled(this.pool.publish(relays, event)), timeout]);
|
|
26585
|
+
} finally {
|
|
26586
|
+
clearTimeout(timer);
|
|
26587
|
+
}
|
|
26391
26588
|
this.eventStore.store(event);
|
|
26392
26589
|
}
|
|
26393
26590
|
/** Close all subscriptions + clear caches. Use in tests; rarely in production. */
|
|
@@ -26451,7 +26648,7 @@ var MODULE_DEFAULT_RELAYS = {
|
|
|
26451
26648
|
"wss://relay.primal.net",
|
|
26452
26649
|
"wss://nos.lol",
|
|
26453
26650
|
"wss://relay.nostr.wirednet.jp",
|
|
26454
|
-
"wss://
|
|
26651
|
+
"wss://nostr-01.yakihonne.com",
|
|
26455
26652
|
"wss://relay.snort.social",
|
|
26456
26653
|
"wss://relay.nostr.band",
|
|
26457
26654
|
"wss://nostr21.com"
|
|
@@ -26683,7 +26880,7 @@ var BlossomClient = class {
|
|
|
26683
26880
|
*/
|
|
26684
26881
|
async upload(data, authEvent, contentType) {
|
|
26685
26882
|
const authHeader = `Nostr ${btoa(JSON.stringify(authEvent))}`;
|
|
26686
|
-
const
|
|
26883
|
+
const sha2564 = await sha256Hex(data);
|
|
26687
26884
|
const response = await fetch(`${this.serverUrl}/upload`, {
|
|
26688
26885
|
method: "PUT",
|
|
26689
26886
|
headers: {
|
|
@@ -26691,7 +26888,7 @@ var BlossomClient = class {
|
|
|
26691
26888
|
"Content-Type": contentType ?? "application/octet-stream",
|
|
26692
26889
|
// BUD-02: lets servers verify the blob and is required by some (e.g.
|
|
26693
26890
|
// the standalone formstr-drive's default servers).
|
|
26694
|
-
"X-SHA-256":
|
|
26891
|
+
"X-SHA-256": sha2564
|
|
26695
26892
|
},
|
|
26696
26893
|
body: data
|
|
26697
26894
|
});
|
|
@@ -26701,26 +26898,26 @@ var BlossomClient = class {
|
|
|
26701
26898
|
const text = await response.text();
|
|
26702
26899
|
try {
|
|
26703
26900
|
const json = JSON.parse(text);
|
|
26704
|
-
const hash = json.sha256 ?? json.x ??
|
|
26901
|
+
const hash = json.sha256 ?? json.x ?? sha2564;
|
|
26705
26902
|
return {
|
|
26706
26903
|
sha256: hash,
|
|
26707
26904
|
url: json.url ?? `${this.serverUrl}/${hash}`,
|
|
26708
26905
|
size: json.size ?? data.byteLength
|
|
26709
26906
|
};
|
|
26710
26907
|
} catch {
|
|
26711
|
-
const hash = text.trim() ||
|
|
26908
|
+
const hash = text.trim() || sha2564;
|
|
26712
26909
|
return { sha256: hash, url: `${this.serverUrl}/${hash}`, size: data.byteLength };
|
|
26713
26910
|
}
|
|
26714
26911
|
}
|
|
26715
26912
|
/**
|
|
26716
26913
|
* BUD-03: Download file blob by SHA-256 hash.
|
|
26717
26914
|
*/
|
|
26718
|
-
async download(
|
|
26915
|
+
async download(sha2564, authEvent) {
|
|
26719
26916
|
const headers = {};
|
|
26720
26917
|
if (authEvent) {
|
|
26721
26918
|
headers["Authorization"] = `Nostr ${btoa(JSON.stringify(authEvent))}`;
|
|
26722
26919
|
}
|
|
26723
|
-
const response = await fetch(`${this.serverUrl}/${
|
|
26920
|
+
const response = await fetch(`${this.serverUrl}/${sha2564}`, { headers });
|
|
26724
26921
|
if (!response.ok) {
|
|
26725
26922
|
throw new Error(`Blossom download failed: ${response.status} ${response.statusText}`);
|
|
26726
26923
|
}
|
|
@@ -26730,9 +26927,9 @@ var BlossomClient = class {
|
|
|
26730
26927
|
/**
|
|
26731
26928
|
* BUD-04: Delete file blob by SHA-256 hash.
|
|
26732
26929
|
*/
|
|
26733
|
-
async delete(
|
|
26930
|
+
async delete(sha2564, authEvent) {
|
|
26734
26931
|
const authHeader = `Nostr ${btoa(JSON.stringify(authEvent))}`;
|
|
26735
|
-
const response = await fetch(`${this.serverUrl}/${
|
|
26932
|
+
const response = await fetch(`${this.serverUrl}/${sha2564}`, {
|
|
26736
26933
|
method: "DELETE",
|
|
26737
26934
|
headers: { Authorization: authHeader }
|
|
26738
26935
|
});
|
|
@@ -26751,18 +26948,18 @@ async function sha256Hex(data) {
|
|
|
26751
26948
|
}
|
|
26752
26949
|
|
|
26753
26950
|
// ../core/dist/blossom/auth.js
|
|
26754
|
-
async function createBlossomAuthEvent(operation,
|
|
26951
|
+
async function createBlossomAuthEvent(operation, sha2564, signer) {
|
|
26755
26952
|
const now2 = Math.floor(Date.now() / 1e3);
|
|
26756
26953
|
const event = {
|
|
26757
26954
|
kind: 24242,
|
|
26758
26955
|
created_at: now2,
|
|
26759
26956
|
tags: [
|
|
26760
26957
|
["t", operation],
|
|
26761
|
-
["x",
|
|
26958
|
+
["x", sha2564],
|
|
26762
26959
|
["expiration", String(now2 + 300)]
|
|
26763
26960
|
// 5 min validity
|
|
26764
26961
|
],
|
|
26765
|
-
content: `Authorize ${operation} for ${
|
|
26962
|
+
content: `Authorize ${operation} for ${sha2564}`
|
|
26766
26963
|
};
|
|
26767
26964
|
return signer.signEvent(event);
|
|
26768
26965
|
}
|
|
@@ -26837,17 +27034,6 @@ async function wrapEvent3(event, signer, recipientPubkey, wrapKind = 1059) {
|
|
|
26837
27034
|
const seal = await createSeal2(rumor, signer, recipientPubkey);
|
|
26838
27035
|
return createWrap2(seal, recipientPubkey, wrapKind);
|
|
26839
27036
|
}
|
|
26840
|
-
async function wrapManyEvents3(event, signer, recipientPubkeys, wrapKind = 1059) {
|
|
26841
|
-
const rumor = createRumor2(event);
|
|
26842
|
-
rumor.pubkey = await signer.getPublicKey();
|
|
26843
|
-
const wraps = [];
|
|
26844
|
-
for (const pubkey of recipientPubkeys) {
|
|
26845
|
-
const seal = await createSeal2(rumor, signer, pubkey);
|
|
26846
|
-
const wrap = await createWrap2(seal, pubkey, wrapKind);
|
|
26847
|
-
wraps.push(wrap);
|
|
26848
|
-
}
|
|
26849
|
-
return wraps;
|
|
26850
|
-
}
|
|
26851
27037
|
async function unwrapEvent3(wrappedEvent, signer) {
|
|
26852
27038
|
if (!signer.nip44Decrypt) {
|
|
26853
27039
|
throw new Error("Signer does not support NIP-44 for unwrap");
|
|
@@ -26865,21 +27051,34 @@ function randomizeTimestamp(timestamp) {
|
|
|
26865
27051
|
|
|
26866
27052
|
// ../core/dist/crypto/nkeys.js
|
|
26867
27053
|
var PREFIX = "nkeys";
|
|
27054
|
+
var BECH32_LIMIT = 2048;
|
|
26868
27055
|
function encodeNKeys(keys) {
|
|
26869
|
-
const
|
|
27056
|
+
const encoder = new TextEncoder();
|
|
27057
|
+
const names = [];
|
|
27058
|
+
const values = [];
|
|
26870
27059
|
for (const [name, value] of Object.entries(keys)) {
|
|
26871
|
-
const nameBytes =
|
|
26872
|
-
|
|
26873
|
-
|
|
26874
|
-
|
|
26875
|
-
|
|
26876
|
-
|
|
26877
|
-
|
|
26878
|
-
|
|
26879
|
-
}
|
|
26880
|
-
const
|
|
26881
|
-
const
|
|
26882
|
-
|
|
27060
|
+
const nameBytes = encoder.encode(name);
|
|
27061
|
+
const valueBytes = encoder.encode(value);
|
|
27062
|
+
if (nameBytes.length > 255)
|
|
27063
|
+
throw new Error(`nkeys: key name too long (${name.length})`);
|
|
27064
|
+
if (valueBytes.length > 255)
|
|
27065
|
+
throw new Error(`nkeys: value too long for key "${name}"`);
|
|
27066
|
+
names.push(nameBytes);
|
|
27067
|
+
values.push(valueBytes);
|
|
27068
|
+
}
|
|
27069
|
+
const tlvBytes = [];
|
|
27070
|
+
for (const nameBytes of names) {
|
|
27071
|
+
tlvBytes.push(0, nameBytes.length, ...nameBytes);
|
|
27072
|
+
}
|
|
27073
|
+
for (const valueBytes of values) {
|
|
27074
|
+
tlvBytes.push(1, valueBytes.length, ...valueBytes);
|
|
27075
|
+
}
|
|
27076
|
+
const words = bech32ToWords(new Uint8Array(tlvBytes));
|
|
27077
|
+
const encoded = bech32Encode(PREFIX, words);
|
|
27078
|
+
if (encoded.length > BECH32_LIMIT) {
|
|
27079
|
+
throw new Error(`nkeys: encoded length ${encoded.length} exceeds ${BECH32_LIMIT}`);
|
|
27080
|
+
}
|
|
27081
|
+
return encoded;
|
|
26883
27082
|
}
|
|
26884
27083
|
var CHARSET = "qpzry9x8gf2tvdw0s3jn54khce6mua7l";
|
|
26885
27084
|
function bech32Encode(prefix, words) {
|
|
@@ -26991,11 +27190,16 @@ async function aesGcmDecrypt(ciphertext, conversationKey) {
|
|
|
26991
27190
|
}
|
|
26992
27191
|
async function encryptFileWithKey(fileBytes) {
|
|
26993
27192
|
const secretKey = generateSecretKey();
|
|
27193
|
+
const privateKeyHex = bytesToHex(secretKey);
|
|
27194
|
+
const ciphertext = await encryptFileWithExistingKey(fileBytes, privateKeyHex);
|
|
27195
|
+
return { ciphertext, privateKeyHex };
|
|
27196
|
+
}
|
|
27197
|
+
async function encryptFileWithExistingKey(fileBytes, privateKeyHex) {
|
|
27198
|
+
const secretKey = hexToBytes(privateKeyHex);
|
|
26994
27199
|
const pubkey = getPublicKey(secretKey);
|
|
26995
27200
|
const conversationKey = nip44_exports.v2.utils.getConversationKey(secretKey, pubkey);
|
|
26996
27201
|
const plaintextBase64 = uint8ArrayToBase64(fileBytes);
|
|
26997
|
-
|
|
26998
|
-
return { ciphertext, privateKeyHex: bytesToHex(secretKey) };
|
|
27202
|
+
return aesGcmEncrypt(plaintextBase64, conversationKey);
|
|
26999
27203
|
}
|
|
27000
27204
|
async function decryptFileWithKey(ciphertext, privateKeyHex) {
|
|
27001
27205
|
const secretKey = hexToBytes(privateKeyHex);
|
|
@@ -27021,23 +27225,23 @@ var KIND_MODULE_MAP = {
|
|
|
27021
27225
|
30168: "forms",
|
|
27022
27226
|
// Form template
|
|
27023
27227
|
// Calendar
|
|
27024
|
-
31922: "calendar",
|
|
27025
|
-
// Date-based calendar event
|
|
27026
27228
|
31923: "calendar",
|
|
27027
|
-
//
|
|
27028
|
-
|
|
27229
|
+
// Public time-based event (NIP-52)
|
|
27230
|
+
32678: "calendar",
|
|
27231
|
+
// Private event
|
|
27232
|
+
32679: "calendar",
|
|
27233
|
+
// Private event (legacy recurring variant, read-only)
|
|
27234
|
+
32123: "calendar",
|
|
27029
27235
|
// Calendar list
|
|
27030
27236
|
// Pages
|
|
27031
|
-
|
|
27032
|
-
//
|
|
27033
|
-
30024: "pages",
|
|
27034
|
-
// Draft article
|
|
27237
|
+
33457: "pages",
|
|
27238
|
+
// Encrypted markdown doc (nostr-docs)
|
|
27035
27239
|
// Drive
|
|
27036
|
-
|
|
27037
|
-
//
|
|
27240
|
+
34578: "drive",
|
|
27241
|
+
// File metadata (formstr-drive)
|
|
27038
27242
|
// Polls
|
|
27039
27243
|
1068: "polls"
|
|
27040
|
-
// Poll event
|
|
27244
|
+
// Poll event (NIP-88)
|
|
27041
27245
|
};
|
|
27042
27246
|
function createRef(_module, kind, pubkey, identifier, relays = []) {
|
|
27043
27247
|
return nip19_exports.naddrEncode({ kind, pubkey, identifier, relays });
|
|
@@ -27184,10 +27388,10 @@ async function unlock(signer, account, deps) {
|
|
|
27184
27388
|
"Stored ncryptsec account is missing its encrypted key. Run `formstr-mcp login`."
|
|
27185
27389
|
);
|
|
27186
27390
|
}
|
|
27187
|
-
const passphrase = deps.passphrase ?? process.env.FORMSTR_MCP_NCRYPTSEC_PASSPHRASE;
|
|
27391
|
+
const passphrase = deps.passphrase ?? process.env.FORMSTR_MCP_NCRYPTSEC_PASSPHRASE ?? (deps.promptPassphrase ? await deps.promptPassphrase("Passphrase to unlock your key: ") : void 0);
|
|
27188
27392
|
if (!passphrase) {
|
|
27189
27393
|
throw new Error(
|
|
27190
|
-
"Set FORMSTR_MCP_NCRYPTSEC_PASSPHRASE to unlock the ncryptsec account at boot."
|
|
27394
|
+
"Set FORMSTR_MCP_NCRYPTSEC_PASSPHRASE to unlock the ncryptsec account at boot (or run in an interactive terminal to be prompted)."
|
|
27191
27395
|
);
|
|
27192
27396
|
}
|
|
27193
27397
|
await signer.loginWithNcryptsec(account.ncryptsec, passphrase);
|
|
@@ -27198,10 +27402,12 @@ async function unlock(signer, account, deps) {
|
|
|
27198
27402
|
throw new Error("Stored nip46 account is missing its session. Run `formstr-mcp login`.");
|
|
27199
27403
|
}
|
|
27200
27404
|
const pool = deps.pool ?? createPatchedPool();
|
|
27201
|
-
await signer.
|
|
27202
|
-
|
|
27203
|
-
|
|
27204
|
-
|
|
27405
|
+
const active = await signer.unlock({ pool });
|
|
27406
|
+
if (!active) {
|
|
27407
|
+
throw new Error(
|
|
27408
|
+
"Could not resume the stored nip46 session (its keys are incomplete). Run `formstr-mcp login` to re-pair."
|
|
27409
|
+
);
|
|
27410
|
+
}
|
|
27205
27411
|
return;
|
|
27206
27412
|
}
|
|
27207
27413
|
throw new Error(
|
|
@@ -31315,6 +31521,7 @@ __export(service_exports, {
|
|
|
31315
31521
|
createForm: () => createForm,
|
|
31316
31522
|
deleteForm: () => deleteForm,
|
|
31317
31523
|
fetchForm: () => fetchForm,
|
|
31524
|
+
fetchFormKeys: () => fetchFormKeys,
|
|
31318
31525
|
fetchFormSummaryFromRef: () => fetchFormSummaryFromRef,
|
|
31319
31526
|
fetchMyForms: () => fetchMyForms,
|
|
31320
31527
|
fetchResponses: () => fetchResponses,
|
|
@@ -31326,34 +31533,328 @@ __export(service_exports, {
|
|
|
31326
31533
|
updateForm: () => updateForm
|
|
31327
31534
|
});
|
|
31328
31535
|
|
|
31329
|
-
// ../../node_modules/.pnpm
|
|
31330
|
-
|
|
31331
|
-
|
|
31332
|
-
|
|
31333
|
-
// ../agent/src/services/forms/keys.ts
|
|
31334
|
-
function makeViewKeySigner(viewKeyHex) {
|
|
31335
|
-
return new LocalSigner2(hexToBytes3(viewKeyHex));
|
|
31536
|
+
// ../../node_modules/.pnpm/@noble+hashes@1.8.0/node_modules/@noble/hashes/esm/utils.js
|
|
31537
|
+
function isBytes4(a) {
|
|
31538
|
+
return a instanceof Uint8Array || ArrayBuffer.isView(a) && a.constructor.name === "Uint8Array";
|
|
31336
31539
|
}
|
|
31337
|
-
function
|
|
31338
|
-
|
|
31540
|
+
function abytes4(b, ...lengths) {
|
|
31541
|
+
if (!isBytes4(b))
|
|
31542
|
+
throw new Error("Uint8Array expected");
|
|
31543
|
+
if (lengths.length > 0 && !lengths.includes(b.length))
|
|
31544
|
+
throw new Error("Uint8Array expected of length " + lengths + ", got length=" + b.length);
|
|
31339
31545
|
}
|
|
31340
|
-
function
|
|
31341
|
-
|
|
31546
|
+
function aexists3(instance, checkFinished = true) {
|
|
31547
|
+
if (instance.destroyed)
|
|
31548
|
+
throw new Error("Hash instance has been destroyed");
|
|
31549
|
+
if (checkFinished && instance.finished)
|
|
31550
|
+
throw new Error("Hash#digest() has already been called");
|
|
31342
31551
|
}
|
|
31343
|
-
function
|
|
31344
|
-
|
|
31345
|
-
|
|
31346
|
-
|
|
31552
|
+
function aoutput3(out, instance) {
|
|
31553
|
+
abytes4(out);
|
|
31554
|
+
const min = instance.outputLen;
|
|
31555
|
+
if (out.length < min) {
|
|
31556
|
+
throw new Error("digestInto() expects output buffer of length at least " + min);
|
|
31557
|
+
}
|
|
31347
31558
|
}
|
|
31348
|
-
function
|
|
31349
|
-
|
|
31350
|
-
|
|
31351
|
-
const out = new Uint8Array(hex.length / 2);
|
|
31352
|
-
for (let i4 = 0; i4 < out.length; i4++) {
|
|
31353
|
-
out[i4] = parseInt(hex.slice(i4 * 2, i4 * 2 + 2), 16);
|
|
31559
|
+
function clean3(...arrays) {
|
|
31560
|
+
for (let i4 = 0; i4 < arrays.length; i4++) {
|
|
31561
|
+
arrays[i4].fill(0);
|
|
31354
31562
|
}
|
|
31355
|
-
return out;
|
|
31356
31563
|
}
|
|
31564
|
+
function createView3(arr) {
|
|
31565
|
+
return new DataView(arr.buffer, arr.byteOffset, arr.byteLength);
|
|
31566
|
+
}
|
|
31567
|
+
function rotr2(word, shift) {
|
|
31568
|
+
return word << 32 - shift | word >>> shift;
|
|
31569
|
+
}
|
|
31570
|
+
function utf8ToBytes2(str) {
|
|
31571
|
+
if (typeof str !== "string")
|
|
31572
|
+
throw new Error("string expected");
|
|
31573
|
+
return new Uint8Array(new TextEncoder().encode(str));
|
|
31574
|
+
}
|
|
31575
|
+
function toBytes(data) {
|
|
31576
|
+
if (typeof data === "string")
|
|
31577
|
+
data = utf8ToBytes2(data);
|
|
31578
|
+
abytes4(data);
|
|
31579
|
+
return data;
|
|
31580
|
+
}
|
|
31581
|
+
var Hash = class {
|
|
31582
|
+
};
|
|
31583
|
+
function createHasher2(hashCons) {
|
|
31584
|
+
const hashC = (msg) => hashCons().update(toBytes(msg)).digest();
|
|
31585
|
+
const tmp = hashCons();
|
|
31586
|
+
hashC.outputLen = tmp.outputLen;
|
|
31587
|
+
hashC.blockLen = tmp.blockLen;
|
|
31588
|
+
hashC.create = () => hashCons();
|
|
31589
|
+
return hashC;
|
|
31590
|
+
}
|
|
31591
|
+
|
|
31592
|
+
// ../../node_modules/.pnpm/@noble+hashes@1.8.0/node_modules/@noble/hashes/esm/_md.js
|
|
31593
|
+
function setBigUint64(view, byteOffset, value, isLE3) {
|
|
31594
|
+
if (typeof view.setBigUint64 === "function")
|
|
31595
|
+
return view.setBigUint64(byteOffset, value, isLE3);
|
|
31596
|
+
const _32n = BigInt(32);
|
|
31597
|
+
const _u32_max = BigInt(4294967295);
|
|
31598
|
+
const wh = Number(value >> _32n & _u32_max);
|
|
31599
|
+
const wl = Number(value & _u32_max);
|
|
31600
|
+
const h = isLE3 ? 4 : 0;
|
|
31601
|
+
const l = isLE3 ? 0 : 4;
|
|
31602
|
+
view.setUint32(byteOffset + h, wh, isLE3);
|
|
31603
|
+
view.setUint32(byteOffset + l, wl, isLE3);
|
|
31604
|
+
}
|
|
31605
|
+
function Chi2(a, b, c) {
|
|
31606
|
+
return a & b ^ ~a & c;
|
|
31607
|
+
}
|
|
31608
|
+
function Maj2(a, b, c) {
|
|
31609
|
+
return a & b ^ a & c ^ b & c;
|
|
31610
|
+
}
|
|
31611
|
+
var HashMD2 = class extends Hash {
|
|
31612
|
+
constructor(blockLen, outputLen, padOffset, isLE3) {
|
|
31613
|
+
super();
|
|
31614
|
+
this.finished = false;
|
|
31615
|
+
this.length = 0;
|
|
31616
|
+
this.pos = 0;
|
|
31617
|
+
this.destroyed = false;
|
|
31618
|
+
this.blockLen = blockLen;
|
|
31619
|
+
this.outputLen = outputLen;
|
|
31620
|
+
this.padOffset = padOffset;
|
|
31621
|
+
this.isLE = isLE3;
|
|
31622
|
+
this.buffer = new Uint8Array(blockLen);
|
|
31623
|
+
this.view = createView3(this.buffer);
|
|
31624
|
+
}
|
|
31625
|
+
update(data) {
|
|
31626
|
+
aexists3(this);
|
|
31627
|
+
data = toBytes(data);
|
|
31628
|
+
abytes4(data);
|
|
31629
|
+
const { view, buffer, blockLen } = this;
|
|
31630
|
+
const len = data.length;
|
|
31631
|
+
for (let pos = 0; pos < len; ) {
|
|
31632
|
+
const take = Math.min(blockLen - this.pos, len - pos);
|
|
31633
|
+
if (take === blockLen) {
|
|
31634
|
+
const dataView = createView3(data);
|
|
31635
|
+
for (; blockLen <= len - pos; pos += blockLen)
|
|
31636
|
+
this.process(dataView, pos);
|
|
31637
|
+
continue;
|
|
31638
|
+
}
|
|
31639
|
+
buffer.set(data.subarray(pos, pos + take), this.pos);
|
|
31640
|
+
this.pos += take;
|
|
31641
|
+
pos += take;
|
|
31642
|
+
if (this.pos === blockLen) {
|
|
31643
|
+
this.process(view, 0);
|
|
31644
|
+
this.pos = 0;
|
|
31645
|
+
}
|
|
31646
|
+
}
|
|
31647
|
+
this.length += data.length;
|
|
31648
|
+
this.roundClean();
|
|
31649
|
+
return this;
|
|
31650
|
+
}
|
|
31651
|
+
digestInto(out) {
|
|
31652
|
+
aexists3(this);
|
|
31653
|
+
aoutput3(out, this);
|
|
31654
|
+
this.finished = true;
|
|
31655
|
+
const { buffer, view, blockLen, isLE: isLE3 } = this;
|
|
31656
|
+
let { pos } = this;
|
|
31657
|
+
buffer[pos++] = 128;
|
|
31658
|
+
clean3(this.buffer.subarray(pos));
|
|
31659
|
+
if (this.padOffset > blockLen - pos) {
|
|
31660
|
+
this.process(view, 0);
|
|
31661
|
+
pos = 0;
|
|
31662
|
+
}
|
|
31663
|
+
for (let i4 = pos; i4 < blockLen; i4++)
|
|
31664
|
+
buffer[i4] = 0;
|
|
31665
|
+
setBigUint64(view, blockLen - 8, BigInt(this.length * 8), isLE3);
|
|
31666
|
+
this.process(view, 0);
|
|
31667
|
+
const oview = createView3(out);
|
|
31668
|
+
const len = this.outputLen;
|
|
31669
|
+
if (len % 4)
|
|
31670
|
+
throw new Error("_sha2: outputLen should be aligned to 32bit");
|
|
31671
|
+
const outLen = len / 4;
|
|
31672
|
+
const state = this.get();
|
|
31673
|
+
if (outLen > state.length)
|
|
31674
|
+
throw new Error("_sha2: outputLen bigger than state");
|
|
31675
|
+
for (let i4 = 0; i4 < outLen; i4++)
|
|
31676
|
+
oview.setUint32(4 * i4, state[i4], isLE3);
|
|
31677
|
+
}
|
|
31678
|
+
digest() {
|
|
31679
|
+
const { buffer, outputLen } = this;
|
|
31680
|
+
this.digestInto(buffer);
|
|
31681
|
+
const res = buffer.slice(0, outputLen);
|
|
31682
|
+
this.destroy();
|
|
31683
|
+
return res;
|
|
31684
|
+
}
|
|
31685
|
+
_cloneInto(to) {
|
|
31686
|
+
to || (to = new this.constructor());
|
|
31687
|
+
to.set(...this.get());
|
|
31688
|
+
const { blockLen, buffer, length, finished, destroyed, pos } = this;
|
|
31689
|
+
to.destroyed = destroyed;
|
|
31690
|
+
to.finished = finished;
|
|
31691
|
+
to.length = length;
|
|
31692
|
+
to.pos = pos;
|
|
31693
|
+
if (length % blockLen)
|
|
31694
|
+
to.buffer.set(buffer);
|
|
31695
|
+
return to;
|
|
31696
|
+
}
|
|
31697
|
+
clone() {
|
|
31698
|
+
return this._cloneInto();
|
|
31699
|
+
}
|
|
31700
|
+
};
|
|
31701
|
+
var SHA256_IV2 = /* @__PURE__ */ Uint32Array.from([
|
|
31702
|
+
1779033703,
|
|
31703
|
+
3144134277,
|
|
31704
|
+
1013904242,
|
|
31705
|
+
2773480762,
|
|
31706
|
+
1359893119,
|
|
31707
|
+
2600822924,
|
|
31708
|
+
528734635,
|
|
31709
|
+
1541459225
|
|
31710
|
+
]);
|
|
31711
|
+
|
|
31712
|
+
// ../../node_modules/.pnpm/@noble+hashes@1.8.0/node_modules/@noble/hashes/esm/sha2.js
|
|
31713
|
+
var SHA256_K2 = /* @__PURE__ */ Uint32Array.from([
|
|
31714
|
+
1116352408,
|
|
31715
|
+
1899447441,
|
|
31716
|
+
3049323471,
|
|
31717
|
+
3921009573,
|
|
31718
|
+
961987163,
|
|
31719
|
+
1508970993,
|
|
31720
|
+
2453635748,
|
|
31721
|
+
2870763221,
|
|
31722
|
+
3624381080,
|
|
31723
|
+
310598401,
|
|
31724
|
+
607225278,
|
|
31725
|
+
1426881987,
|
|
31726
|
+
1925078388,
|
|
31727
|
+
2162078206,
|
|
31728
|
+
2614888103,
|
|
31729
|
+
3248222580,
|
|
31730
|
+
3835390401,
|
|
31731
|
+
4022224774,
|
|
31732
|
+
264347078,
|
|
31733
|
+
604807628,
|
|
31734
|
+
770255983,
|
|
31735
|
+
1249150122,
|
|
31736
|
+
1555081692,
|
|
31737
|
+
1996064986,
|
|
31738
|
+
2554220882,
|
|
31739
|
+
2821834349,
|
|
31740
|
+
2952996808,
|
|
31741
|
+
3210313671,
|
|
31742
|
+
3336571891,
|
|
31743
|
+
3584528711,
|
|
31744
|
+
113926993,
|
|
31745
|
+
338241895,
|
|
31746
|
+
666307205,
|
|
31747
|
+
773529912,
|
|
31748
|
+
1294757372,
|
|
31749
|
+
1396182291,
|
|
31750
|
+
1695183700,
|
|
31751
|
+
1986661051,
|
|
31752
|
+
2177026350,
|
|
31753
|
+
2456956037,
|
|
31754
|
+
2730485921,
|
|
31755
|
+
2820302411,
|
|
31756
|
+
3259730800,
|
|
31757
|
+
3345764771,
|
|
31758
|
+
3516065817,
|
|
31759
|
+
3600352804,
|
|
31760
|
+
4094571909,
|
|
31761
|
+
275423344,
|
|
31762
|
+
430227734,
|
|
31763
|
+
506948616,
|
|
31764
|
+
659060556,
|
|
31765
|
+
883997877,
|
|
31766
|
+
958139571,
|
|
31767
|
+
1322822218,
|
|
31768
|
+
1537002063,
|
|
31769
|
+
1747873779,
|
|
31770
|
+
1955562222,
|
|
31771
|
+
2024104815,
|
|
31772
|
+
2227730452,
|
|
31773
|
+
2361852424,
|
|
31774
|
+
2428436474,
|
|
31775
|
+
2756734187,
|
|
31776
|
+
3204031479,
|
|
31777
|
+
3329325298
|
|
31778
|
+
]);
|
|
31779
|
+
var SHA256_W2 = /* @__PURE__ */ new Uint32Array(64);
|
|
31780
|
+
var SHA256 = class extends HashMD2 {
|
|
31781
|
+
constructor(outputLen = 32) {
|
|
31782
|
+
super(64, outputLen, 8, false);
|
|
31783
|
+
this.A = SHA256_IV2[0] | 0;
|
|
31784
|
+
this.B = SHA256_IV2[1] | 0;
|
|
31785
|
+
this.C = SHA256_IV2[2] | 0;
|
|
31786
|
+
this.D = SHA256_IV2[3] | 0;
|
|
31787
|
+
this.E = SHA256_IV2[4] | 0;
|
|
31788
|
+
this.F = SHA256_IV2[5] | 0;
|
|
31789
|
+
this.G = SHA256_IV2[6] | 0;
|
|
31790
|
+
this.H = SHA256_IV2[7] | 0;
|
|
31791
|
+
}
|
|
31792
|
+
get() {
|
|
31793
|
+
const { A, B, C, D, E, F, G, H } = this;
|
|
31794
|
+
return [A, B, C, D, E, F, G, H];
|
|
31795
|
+
}
|
|
31796
|
+
// prettier-ignore
|
|
31797
|
+
set(A, B, C, D, E, F, G, H) {
|
|
31798
|
+
this.A = A | 0;
|
|
31799
|
+
this.B = B | 0;
|
|
31800
|
+
this.C = C | 0;
|
|
31801
|
+
this.D = D | 0;
|
|
31802
|
+
this.E = E | 0;
|
|
31803
|
+
this.F = F | 0;
|
|
31804
|
+
this.G = G | 0;
|
|
31805
|
+
this.H = H | 0;
|
|
31806
|
+
}
|
|
31807
|
+
process(view, offset) {
|
|
31808
|
+
for (let i4 = 0; i4 < 16; i4++, offset += 4)
|
|
31809
|
+
SHA256_W2[i4] = view.getUint32(offset, false);
|
|
31810
|
+
for (let i4 = 16; i4 < 64; i4++) {
|
|
31811
|
+
const W15 = SHA256_W2[i4 - 15];
|
|
31812
|
+
const W2 = SHA256_W2[i4 - 2];
|
|
31813
|
+
const s0 = rotr2(W15, 7) ^ rotr2(W15, 18) ^ W15 >>> 3;
|
|
31814
|
+
const s1 = rotr2(W2, 17) ^ rotr2(W2, 19) ^ W2 >>> 10;
|
|
31815
|
+
SHA256_W2[i4] = s1 + SHA256_W2[i4 - 7] + s0 + SHA256_W2[i4 - 16] | 0;
|
|
31816
|
+
}
|
|
31817
|
+
let { A, B, C, D, E, F, G, H } = this;
|
|
31818
|
+
for (let i4 = 0; i4 < 64; i4++) {
|
|
31819
|
+
const sigma1 = rotr2(E, 6) ^ rotr2(E, 11) ^ rotr2(E, 25);
|
|
31820
|
+
const T1 = H + sigma1 + Chi2(E, F, G) + SHA256_K2[i4] + SHA256_W2[i4] | 0;
|
|
31821
|
+
const sigma0 = rotr2(A, 2) ^ rotr2(A, 13) ^ rotr2(A, 22);
|
|
31822
|
+
const T2 = sigma0 + Maj2(A, B, C) | 0;
|
|
31823
|
+
H = G;
|
|
31824
|
+
G = F;
|
|
31825
|
+
F = E;
|
|
31826
|
+
E = D + T1 | 0;
|
|
31827
|
+
D = C;
|
|
31828
|
+
C = B;
|
|
31829
|
+
B = A;
|
|
31830
|
+
A = T1 + T2 | 0;
|
|
31831
|
+
}
|
|
31832
|
+
A = A + this.A | 0;
|
|
31833
|
+
B = B + this.B | 0;
|
|
31834
|
+
C = C + this.C | 0;
|
|
31835
|
+
D = D + this.D | 0;
|
|
31836
|
+
E = E + this.E | 0;
|
|
31837
|
+
F = F + this.F | 0;
|
|
31838
|
+
G = G + this.G | 0;
|
|
31839
|
+
H = H + this.H | 0;
|
|
31840
|
+
this.set(A, B, C, D, E, F, G, H);
|
|
31841
|
+
}
|
|
31842
|
+
roundClean() {
|
|
31843
|
+
clean3(SHA256_W2);
|
|
31844
|
+
}
|
|
31845
|
+
destroy() {
|
|
31846
|
+
this.set(0, 0, 0, 0, 0, 0, 0, 0);
|
|
31847
|
+
clean3(this.buffer);
|
|
31848
|
+
}
|
|
31849
|
+
};
|
|
31850
|
+
var sha2562 = /* @__PURE__ */ createHasher2(() => new SHA256());
|
|
31851
|
+
|
|
31852
|
+
// ../../node_modules/.pnpm/@noble+hashes@1.8.0/node_modules/@noble/hashes/esm/sha256.js
|
|
31853
|
+
var sha2563 = sha2562;
|
|
31854
|
+
|
|
31855
|
+
// ../../node_modules/.pnpm/nostr-tools@2.23.3_typescript@5.9.3/node_modules/nostr-tools/lib/esm/utils.js
|
|
31856
|
+
var utf8Decoder7 = new TextDecoder("utf-8");
|
|
31857
|
+
var utf8Encoder7 = new TextEncoder();
|
|
31357
31858
|
|
|
31358
31859
|
// ../agent/src/services/forms/types.ts
|
|
31359
31860
|
var FORM_KINDS = {
|
|
@@ -31375,46 +31876,219 @@ var AnswerType = /* @__PURE__ */ ((AnswerType2) => {
|
|
|
31375
31876
|
AnswerType2["datetime"] = "datetime";
|
|
31376
31877
|
AnswerType2["fileUpload"] = "fileUpload";
|
|
31377
31878
|
AnswerType2["signature"] = "signature";
|
|
31378
|
-
AnswerType2["
|
|
31879
|
+
AnswerType2["multipleChoiceGrid"] = "multipleChoiceGrid";
|
|
31379
31880
|
AnswerType2["checkboxGrid"] = "checkboxGrid";
|
|
31881
|
+
AnswerType2["rating"] = "rating";
|
|
31380
31882
|
AnswerType2["section"] = "section";
|
|
31381
31883
|
return AnswerType2;
|
|
31382
31884
|
})(AnswerType || {});
|
|
31383
31885
|
|
|
31886
|
+
// ../agent/src/services/forms/fieldCodec.ts
|
|
31887
|
+
var PRIMITIVE_BY_TYPE = {
|
|
31888
|
+
["label" /* label */]: "label",
|
|
31889
|
+
["section" /* section */]: "section",
|
|
31890
|
+
["shortText" /* shortText */]: "text",
|
|
31891
|
+
["paragraph" /* paragraph */]: "text",
|
|
31892
|
+
["date" /* date */]: "text",
|
|
31893
|
+
["time" /* time */]: "text",
|
|
31894
|
+
["signature" /* signature */]: "text",
|
|
31895
|
+
["number" /* number */]: "number",
|
|
31896
|
+
["radioButton" /* radioButton */]: "option",
|
|
31897
|
+
["checkboxes" /* checkboxes */]: "option",
|
|
31898
|
+
["dropdown" /* dropdown */]: "option",
|
|
31899
|
+
["fileUpload" /* fileUpload */]: "file",
|
|
31900
|
+
["datetime" /* datetime */]: "datetime",
|
|
31901
|
+
["multipleChoiceGrid" /* multipleChoiceGrid */]: "grid",
|
|
31902
|
+
["checkboxGrid" /* checkboxGrid */]: "grid",
|
|
31903
|
+
["rating" /* rating */]: "rating"
|
|
31904
|
+
};
|
|
31905
|
+
var DEFAULT_TYPE_BY_PRIMITIVE = {
|
|
31906
|
+
text: "shortText" /* shortText */,
|
|
31907
|
+
number: "number" /* number */,
|
|
31908
|
+
option: "radioButton" /* radioButton */,
|
|
31909
|
+
label: "label" /* label */,
|
|
31910
|
+
section: "section" /* section */,
|
|
31911
|
+
file: "fileUpload" /* fileUpload */,
|
|
31912
|
+
datetime: "datetime" /* datetime */,
|
|
31913
|
+
grid: "multipleChoiceGrid" /* multipleChoiceGrid */,
|
|
31914
|
+
rating: "rating" /* rating */
|
|
31915
|
+
};
|
|
31916
|
+
var GRID_TYPES = /* @__PURE__ */ new Set(["multipleChoiceGrid" /* multipleChoiceGrid */, "checkboxGrid" /* checkboxGrid */]);
|
|
31917
|
+
function makeId() {
|
|
31918
|
+
return Math.random().toString(36).slice(2, 8) || "id";
|
|
31919
|
+
}
|
|
31920
|
+
function buildFieldTag(field) {
|
|
31921
|
+
let options = "[]";
|
|
31922
|
+
if (GRID_TYPES.has(field.type)) {
|
|
31923
|
+
const grid = {
|
|
31924
|
+
rows: (field.gridRows ?? []).map((label) => [makeId(), label]),
|
|
31925
|
+
columns: (field.gridCols ?? []).map((label) => [makeId(), label])
|
|
31926
|
+
};
|
|
31927
|
+
options = JSON.stringify(grid);
|
|
31928
|
+
} else if (field.options) {
|
|
31929
|
+
options = JSON.stringify(field.options.map((o) => [o.id, o.label]));
|
|
31930
|
+
}
|
|
31931
|
+
const config2 = { renderElement: field.type };
|
|
31932
|
+
if (field.required !== void 0) config2.required = field.required;
|
|
31933
|
+
if (field.placeholder !== void 0) config2.placeholder = field.placeholder;
|
|
31934
|
+
if (field.type === "rating" /* rating */ && field.maxStars !== void 0) {
|
|
31935
|
+
config2.maxStars = field.maxStars;
|
|
31936
|
+
}
|
|
31937
|
+
if (GRID_TYPES.has(field.type)) {
|
|
31938
|
+
config2.allowMultiplePerRow = field.type === "checkboxGrid" /* checkboxGrid */;
|
|
31939
|
+
}
|
|
31940
|
+
if (field.validation) {
|
|
31941
|
+
const v = field.validation;
|
|
31942
|
+
const rules = {};
|
|
31943
|
+
if (v.min !== void 0) rules.min = { min: v.min };
|
|
31944
|
+
if (v.max !== void 0) rules.max = { max: v.max };
|
|
31945
|
+
if (v.regex !== void 0) rules.regex = { pattern: v.regex, errorMessage: v.regexError ?? "" };
|
|
31946
|
+
if (Object.keys(rules).length > 0) config2.validationRules = rules;
|
|
31947
|
+
}
|
|
31948
|
+
if (field.fileConfig) {
|
|
31949
|
+
const f = field.fileConfig;
|
|
31950
|
+
if (f.blossomServer !== void 0) config2.blossomServer = f.blossomServer;
|
|
31951
|
+
if (f.maxBytes !== void 0) config2.maxFileSize = f.maxBytes / (1024 * 1024);
|
|
31952
|
+
if (f.mimeTypes !== void 0) config2.allowedTypes = f.mimeTypes;
|
|
31953
|
+
}
|
|
31954
|
+
return ["field", field.id, PRIMITIVE_BY_TYPE[field.type], field.label, options, JSON.stringify(config2)];
|
|
31955
|
+
}
|
|
31956
|
+
function isAnswerType(value) {
|
|
31957
|
+
return Object.values(AnswerType).includes(value);
|
|
31958
|
+
}
|
|
31959
|
+
function resolveType(primitive, renderElement) {
|
|
31960
|
+
if (primitive === "section") return "section" /* section */;
|
|
31961
|
+
if (renderElement) {
|
|
31962
|
+
if (renderElement === "multiChoiceGrid") return "multipleChoiceGrid" /* multipleChoiceGrid */;
|
|
31963
|
+
if (isAnswerType(renderElement)) return renderElement;
|
|
31964
|
+
}
|
|
31965
|
+
if (primitive === "multiChoiceGrid") return "multipleChoiceGrid" /* multipleChoiceGrid */;
|
|
31966
|
+
if (isAnswerType(primitive)) return primitive;
|
|
31967
|
+
return DEFAULT_TYPE_BY_PRIMITIVE[primitive] ?? "shortText" /* shortText */;
|
|
31968
|
+
}
|
|
31969
|
+
function parseFieldTag(tag) {
|
|
31970
|
+
const [, id = "", primitive = "text", label = "", optionsJson, configJson] = tag;
|
|
31971
|
+
let config2 = {};
|
|
31972
|
+
if (configJson) {
|
|
31973
|
+
try {
|
|
31974
|
+
const parsed = JSON.parse(configJson);
|
|
31975
|
+
if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) config2 = parsed;
|
|
31976
|
+
} catch {
|
|
31977
|
+
}
|
|
31978
|
+
}
|
|
31979
|
+
const field = {
|
|
31980
|
+
id,
|
|
31981
|
+
type: resolveType(primitive, config2.renderElement),
|
|
31982
|
+
label
|
|
31983
|
+
};
|
|
31984
|
+
let parsedOptions;
|
|
31985
|
+
if (optionsJson) {
|
|
31986
|
+
try {
|
|
31987
|
+
parsedOptions = JSON.parse(optionsJson);
|
|
31988
|
+
} catch {
|
|
31989
|
+
}
|
|
31990
|
+
}
|
|
31991
|
+
if (Array.isArray(parsedOptions) && parsedOptions.length > 0) {
|
|
31992
|
+
field.options = parsedOptions.map(
|
|
31993
|
+
(o) => ({ id: o[0], label: o[1] })
|
|
31994
|
+
);
|
|
31995
|
+
} else if (parsedOptions && typeof parsedOptions === "object") {
|
|
31996
|
+
const grid = parsedOptions;
|
|
31997
|
+
if (Array.isArray(grid.rows)) field.gridRows = grid.rows.map((r) => r[1]);
|
|
31998
|
+
if (Array.isArray(grid.columns)) field.gridCols = grid.columns.map((c) => c[1]);
|
|
31999
|
+
}
|
|
32000
|
+
if (typeof config2.required === "boolean") field.required = config2.required;
|
|
32001
|
+
if (typeof config2.placeholder === "string") field.placeholder = config2.placeholder;
|
|
32002
|
+
if (typeof config2.maxStars === "number") field.maxStars = config2.maxStars;
|
|
32003
|
+
const rules = config2.validationRules;
|
|
32004
|
+
if (rules && typeof rules === "object") {
|
|
32005
|
+
const validation = {};
|
|
32006
|
+
if (typeof rules.range?.min === "number") validation.min = rules.range.min;
|
|
32007
|
+
if (typeof rules.range?.max === "number") validation.max = rules.range.max;
|
|
32008
|
+
if (typeof rules.min?.min === "number") validation.min = rules.min.min;
|
|
32009
|
+
if (typeof rules.max?.max === "number") validation.max = rules.max.max;
|
|
32010
|
+
if (typeof rules.regex?.pattern === "string") {
|
|
32011
|
+
validation.regex = rules.regex.pattern;
|
|
32012
|
+
if (rules.regex.errorMessage) validation.regexError = rules.regex.errorMessage;
|
|
32013
|
+
}
|
|
32014
|
+
if (Object.keys(validation).length > 0) field.validation = validation;
|
|
32015
|
+
}
|
|
32016
|
+
if (config2.blossomServer !== void 0 || config2.maxFileSize !== void 0 || config2.allowedTypes !== void 0) {
|
|
32017
|
+
field.fileConfig = {
|
|
32018
|
+
...typeof config2.blossomServer === "string" && { blossomServer: config2.blossomServer },
|
|
32019
|
+
...typeof config2.maxFileSize === "number" && {
|
|
32020
|
+
maxBytes: config2.maxFileSize * 1024 * 1024
|
|
32021
|
+
},
|
|
32022
|
+
...Array.isArray(config2.allowedTypes) && { mimeTypes: config2.allowedTypes }
|
|
32023
|
+
};
|
|
32024
|
+
}
|
|
32025
|
+
return field;
|
|
32026
|
+
}
|
|
32027
|
+
|
|
32028
|
+
// ../agent/src/services/forms/keys.ts
|
|
32029
|
+
function makeViewKeySigner(viewKeyHex) {
|
|
32030
|
+
return new LocalSigner2(hexToBytes3(viewKeyHex));
|
|
32031
|
+
}
|
|
32032
|
+
function makeSigningKeySigner(signingKeyHex) {
|
|
32033
|
+
return new LocalSigner2(hexToBytes3(signingKeyHex));
|
|
32034
|
+
}
|
|
32035
|
+
function encodeFormKeys(signingKeyHex, viewKeyHex) {
|
|
32036
|
+
return viewKeyHex ? `${signingKeyHex}:${viewKeyHex}` : signingKeyHex;
|
|
32037
|
+
}
|
|
32038
|
+
function decodeFormKeys(segment) {
|
|
32039
|
+
const idx = segment.indexOf(":");
|
|
32040
|
+
if (idx < 0) return { signingKey: segment };
|
|
32041
|
+
return { signingKey: segment.slice(0, idx), viewKey: segment.slice(idx + 1) };
|
|
32042
|
+
}
|
|
32043
|
+
function hexToBytes3(hex) {
|
|
32044
|
+
if (hex.length % 2 !== 0) throw new Error("invalid hex length");
|
|
32045
|
+
if (hex.length > 0 && !/^[0-9a-fA-F]+$/.test(hex)) throw new Error("invalid hex characters");
|
|
32046
|
+
const out = new Uint8Array(hex.length / 2);
|
|
32047
|
+
for (let i4 = 0; i4 < out.length; i4++) {
|
|
32048
|
+
out[i4] = parseInt(hex.slice(i4 * 2, i4 * 2 + 2), 16);
|
|
32049
|
+
}
|
|
32050
|
+
return out;
|
|
32051
|
+
}
|
|
32052
|
+
|
|
31384
32053
|
// ../agent/src/services/forms/service.ts
|
|
32054
|
+
function relaysForForm(formRelays) {
|
|
32055
|
+
return Array.from(/* @__PURE__ */ new Set([...relayManager.getRelaysForModule("forms"), ...formRelays ?? []]));
|
|
32056
|
+
}
|
|
32057
|
+
function buildSpecRows(formId, name, fields, settings) {
|
|
32058
|
+
const rows = [
|
|
32059
|
+
["d", formId],
|
|
32060
|
+
["name", name]
|
|
32061
|
+
];
|
|
32062
|
+
if (settings) rows.push(["settings", JSON.stringify(settings)]);
|
|
32063
|
+
for (const field of fields) rows.push(buildFieldTag(field));
|
|
32064
|
+
return rows;
|
|
32065
|
+
}
|
|
32066
|
+
function buildEncryptedOuterTags(formId, name, relays, settings) {
|
|
32067
|
+
const tags = [["d", formId], ["name", name], ...relays.map((r) => ["relay", r])];
|
|
32068
|
+
const allowed = settings?.allowedResponders ?? [];
|
|
32069
|
+
const pTags = /* @__PURE__ */ new Set([...allowed, ...settings?.collaborators ?? []]);
|
|
32070
|
+
for (const pk of allowed) tags.push(["allowed", pk]);
|
|
32071
|
+
for (const pk of pTags) tags.push(["p", pk]);
|
|
32072
|
+
return tags;
|
|
32073
|
+
}
|
|
31385
32074
|
async function createForm(params) {
|
|
31386
|
-
|
|
31387
|
-
const userPubkey = await signer.getPublicKey();
|
|
32075
|
+
await signerManager.getSigner();
|
|
31388
32076
|
const formId = crypto.randomUUID().slice(0, 8);
|
|
31389
32077
|
const relays = relayManager.getRelaysForModule("forms");
|
|
31390
|
-
const
|
|
31391
|
-
|
|
31392
|
-
|
|
31393
|
-
|
|
31394
|
-
if (params.settings) baseTags.push(["settings", JSON.stringify(params.settings)]);
|
|
31395
|
-
for (const field of params.fields) {
|
|
31396
|
-
baseTags.push(buildFieldTag(field));
|
|
31397
|
-
}
|
|
32078
|
+
const specRows = buildSpecRows(formId, params.name, params.fields, params.settings);
|
|
32079
|
+
const signingKey = generateSecretKey();
|
|
32080
|
+
const signingKeyHex = bytesToHex(signingKey);
|
|
32081
|
+
const signingPubkey = getPublicKey(signingKey);
|
|
31398
32082
|
if (params.encrypt) {
|
|
31399
|
-
const signingKey = generateSecretKey();
|
|
31400
|
-
const signingKeyHex = bytesToHex(signingKey);
|
|
31401
|
-
const signingPubkey = getPublicKey(signingKey);
|
|
31402
32083
|
const viewKey = generateSecretKey();
|
|
31403
32084
|
const viewKeyHex = bytesToHex(viewKey);
|
|
31404
32085
|
const viewPubkey = getPublicKey(viewKey);
|
|
31405
32086
|
const formSigner = new LocalSigner2(signingKey);
|
|
31406
|
-
const
|
|
31407
|
-
const content = await formSigner.nip44Encrypt(viewPubkey, JSON.stringify(fieldTags));
|
|
31408
|
-
const encTags = [
|
|
31409
|
-
["d", formId],
|
|
31410
|
-
["name", params.name],
|
|
31411
|
-
["encryption", "view-key"]
|
|
31412
|
-
];
|
|
31413
|
-
if (params.settings) encTags.push(["settings", JSON.stringify(params.settings)]);
|
|
32087
|
+
const content = await formSigner.nip44Encrypt(viewPubkey, JSON.stringify(specRows));
|
|
31414
32088
|
const event2 = {
|
|
31415
32089
|
kind: FORM_KINDS.template,
|
|
31416
32090
|
created_at: Math.floor(Date.now() / 1e3),
|
|
31417
|
-
tags:
|
|
32091
|
+
tags: buildEncryptedOuterTags(formId, params.name, relays, params.settings),
|
|
31418
32092
|
content
|
|
31419
32093
|
};
|
|
31420
32094
|
const signed2 = finalizeEvent(event2, signingKey);
|
|
@@ -31422,20 +32096,20 @@ async function createForm(params) {
|
|
|
31422
32096
|
await appendToMyFormsList(signingPubkey, formId, relays[0] ?? "", signingKeyHex, viewKeyHex);
|
|
31423
32097
|
return { formId, pubkey: signingPubkey, signingKey: signingKeyHex, viewKey: viewKeyHex };
|
|
31424
32098
|
}
|
|
31425
|
-
|
|
32099
|
+
const tags = [...specRows, ["t", "public"], ...relays.map((r) => ["relay", r])];
|
|
31426
32100
|
const event = {
|
|
31427
32101
|
kind: FORM_KINDS.template,
|
|
31428
32102
|
created_at: Math.floor(Date.now() / 1e3),
|
|
31429
|
-
tags
|
|
32103
|
+
tags,
|
|
31430
32104
|
content: ""
|
|
31431
32105
|
};
|
|
31432
|
-
const signed =
|
|
32106
|
+
const signed = finalizeEvent(event, signingKey);
|
|
31433
32107
|
await nostrRuntime.publish(relays, signed);
|
|
31434
|
-
await appendToMyFormsList(
|
|
31435
|
-
return { formId, pubkey:
|
|
32108
|
+
await appendToMyFormsList(signingPubkey, formId, relays[0] ?? "", signingKeyHex, void 0);
|
|
32109
|
+
return { formId, pubkey: signingPubkey, signingKey: signingKeyHex };
|
|
31436
32110
|
}
|
|
31437
|
-
async function fetchForm(pubkey, formId, viewKey) {
|
|
31438
|
-
const relays =
|
|
32111
|
+
async function fetchForm(pubkey, formId, viewKey, relayHints) {
|
|
32112
|
+
const relays = relaysForForm(relayHints);
|
|
31439
32113
|
const event = await nostrRuntime.fetchOne(relays, {
|
|
31440
32114
|
kinds: [FORM_KINDS.template],
|
|
31441
32115
|
authors: [pubkey],
|
|
@@ -31443,25 +32117,48 @@ async function fetchForm(pubkey, formId, viewKey) {
|
|
|
31443
32117
|
limit: 1
|
|
31444
32118
|
});
|
|
31445
32119
|
if (!event) return null;
|
|
31446
|
-
|
|
31447
|
-
if (
|
|
32120
|
+
let effectiveViewKey = viewKey;
|
|
32121
|
+
if (!effectiveViewKey && event.content && !event.tags.some((t) => t[0] === "field")) {
|
|
32122
|
+
const keys = await fetchFormKeys(pubkey, formId).catch(() => null);
|
|
32123
|
+
effectiveViewKey = keys?.viewKey;
|
|
32124
|
+
}
|
|
32125
|
+
let decryptedRows;
|
|
32126
|
+
if (event.content && effectiveViewKey) {
|
|
31448
32127
|
try {
|
|
31449
|
-
const viewSigner = makeViewKeySigner(
|
|
32128
|
+
const viewSigner = makeViewKeySigner(effectiveViewKey);
|
|
31450
32129
|
const decrypted = await viewSigner.nip44Decrypt(pubkey, event.content);
|
|
31451
|
-
const
|
|
31452
|
-
|
|
31453
|
-
id: t[1],
|
|
31454
|
-
type: t[2],
|
|
31455
|
-
label: t[3],
|
|
31456
|
-
options: t[4] ? safeParseOptions(t[4]) : void 0,
|
|
31457
|
-
required: t[5] ? JSON.parse(t[5])?.required : void 0
|
|
31458
|
-
}));
|
|
32130
|
+
const rows = JSON.parse(decrypted);
|
|
32131
|
+
if (Array.isArray(rows)) decryptedRows = rows;
|
|
31459
32132
|
} catch {
|
|
31460
32133
|
}
|
|
31461
32134
|
}
|
|
31462
|
-
return
|
|
32135
|
+
return parseFormEvent(event, decryptedRows);
|
|
32136
|
+
}
|
|
32137
|
+
function accessGrantAlias(formAuthor, formId, recipient) {
|
|
32138
|
+
return bytesToHex(sha2563(`${FORM_KINDS.template}:${formAuthor}:${formId}:${recipient}`));
|
|
32139
|
+
}
|
|
32140
|
+
async function fetchFormKeys(formAuthor, formId) {
|
|
32141
|
+
const signer = signerManager.getSignerIfAvailable();
|
|
32142
|
+
if (!signer?.nip44Decrypt) return null;
|
|
32143
|
+
const userPub = await signer.getPublicKey();
|
|
32144
|
+
const relays = relayManager.getRelaysForModule("forms");
|
|
32145
|
+
const wraps = await nostrRuntime.querySync(relays, {
|
|
32146
|
+
kinds: [FORM_KINDS.giftWrap],
|
|
32147
|
+
"#p": [accessGrantAlias(formAuthor, formId, userPub)]
|
|
32148
|
+
});
|
|
32149
|
+
for (const wrap of wraps) {
|
|
32150
|
+
try {
|
|
32151
|
+
const seal = JSON.parse(await signer.nip44Decrypt(wrap.pubkey, wrap.content));
|
|
32152
|
+
const rumor = JSON.parse(await signer.nip44Decrypt(seal.pubkey, seal.content));
|
|
32153
|
+
const viewKey = rumor.tags?.find((t) => t[0] === "ViewAccess")?.[1];
|
|
32154
|
+
const signingKey = rumor.tags?.find((t) => t[0] === "EditAccess")?.[1];
|
|
32155
|
+
if (viewKey || signingKey) return { viewKey, signingKey };
|
|
32156
|
+
} catch {
|
|
32157
|
+
}
|
|
32158
|
+
}
|
|
32159
|
+
return null;
|
|
31463
32160
|
}
|
|
31464
|
-
async function submitResponse(formPubkey, formId, responses, encrypt7 = false, overrideSigner) {
|
|
32161
|
+
async function submitResponse(formPubkey, formId, responses, encrypt7 = false, overrideSigner, formRelays) {
|
|
31465
32162
|
const signer = overrideSigner ?? await signerManager.getSigner();
|
|
31466
32163
|
const responseTags = responses.map((r) => ["response", r.fieldId, r.answer, r.metadata ?? ""]);
|
|
31467
32164
|
const tags = [
|
|
@@ -31480,11 +32177,10 @@ async function submitResponse(formPubkey, formId, responses, encrypt7 = false, o
|
|
|
31480
32177
|
content
|
|
31481
32178
|
};
|
|
31482
32179
|
const signed = await signer.signEvent(event);
|
|
31483
|
-
|
|
31484
|
-
await nostrRuntime.publish(relays, signed);
|
|
32180
|
+
await nostrRuntime.publish(relaysForForm(formRelays), signed);
|
|
31485
32181
|
}
|
|
31486
|
-
function subscribeToResponses(formPubkey, formId, onResponse, onEose, signingKey) {
|
|
31487
|
-
const relays =
|
|
32182
|
+
function subscribeToResponses(formPubkey, formId, onResponse, onEose, signingKey, formRelays) {
|
|
32183
|
+
const relays = relaysForForm(formRelays);
|
|
31488
32184
|
const formSigner = signingKey ? makeSigningKeySigner(signingKey) : void 0;
|
|
31489
32185
|
return nostrRuntime.subscribe(
|
|
31490
32186
|
relays,
|
|
@@ -31508,9 +32204,8 @@ function subscribeToResponses(formPubkey, formId, onResponse, onEose, signingKey
|
|
|
31508
32204
|
}
|
|
31509
32205
|
);
|
|
31510
32206
|
}
|
|
31511
|
-
async function fetchResponses(formPubkey, formId, signingKey) {
|
|
31512
|
-
const
|
|
31513
|
-
const events = await nostrRuntime.querySync(relays, {
|
|
32207
|
+
async function fetchResponses(formPubkey, formId, signingKey, formRelays) {
|
|
32208
|
+
const events = await nostrRuntime.querySync(relaysForForm(formRelays), {
|
|
31514
32209
|
kinds: [FORM_KINDS.response],
|
|
31515
32210
|
"#a": [`${FORM_KINDS.template}:${formPubkey}:${formId}`]
|
|
31516
32211
|
});
|
|
@@ -31543,6 +32238,27 @@ async function fetchLatestMyFormsEvent(relays, userPubkey) {
|
|
|
31543
32238
|
null
|
|
31544
32239
|
);
|
|
31545
32240
|
}
|
|
32241
|
+
async function decryptListEntries(signer, userPubkey, content) {
|
|
32242
|
+
let decrypted = "";
|
|
32243
|
+
if (content.includes("?iv=")) {
|
|
32244
|
+
if (!signer.decrypt) throw new Error("Signer cannot decrypt");
|
|
32245
|
+
decrypted = await signer.decrypt(userPubkey, content);
|
|
32246
|
+
} else {
|
|
32247
|
+
decrypted = await nip44SelfDecrypt(signer, content);
|
|
32248
|
+
}
|
|
32249
|
+
const parsed = JSON.parse(decrypted);
|
|
32250
|
+
return Array.isArray(parsed) ? parsed : [];
|
|
32251
|
+
}
|
|
32252
|
+
async function publishMyFormsList(signer, relays, entries) {
|
|
32253
|
+
const encrypted = await nip44SelfEncrypt(signer, JSON.stringify(entries));
|
|
32254
|
+
const event = {
|
|
32255
|
+
kind: FORM_KINDS.myFormsList,
|
|
32256
|
+
created_at: Math.floor(Date.now() / 1e3),
|
|
32257
|
+
tags: [],
|
|
32258
|
+
content: encrypted
|
|
32259
|
+
};
|
|
32260
|
+
await nostrRuntime.publish(relays, await signer.signEvent(event));
|
|
32261
|
+
}
|
|
31546
32262
|
async function fetchMyForms() {
|
|
31547
32263
|
const signer = await signerManager.getSigner();
|
|
31548
32264
|
const userPubkey = await signer.getPublicKey();
|
|
@@ -31551,15 +32267,7 @@ async function fetchMyForms() {
|
|
|
31551
32267
|
let entries = [];
|
|
31552
32268
|
if (listEvent?.content) {
|
|
31553
32269
|
try {
|
|
31554
|
-
|
|
31555
|
-
if (listEvent.content.includes("?iv=")) {
|
|
31556
|
-
if (!signer.decrypt) throw new Error("Signer cannot decrypt");
|
|
31557
|
-
decrypted = await signer.decrypt(userPubkey, listEvent.content);
|
|
31558
|
-
} else {
|
|
31559
|
-
decrypted = await nip44SelfDecrypt(signer, listEvent.content);
|
|
31560
|
-
}
|
|
31561
|
-
const parsed = JSON.parse(decrypted);
|
|
31562
|
-
entries = Array.isArray(parsed) ? parsed : [];
|
|
32270
|
+
entries = await decryptListEntries(signer, userPubkey, listEvent.content);
|
|
31563
32271
|
} catch {
|
|
31564
32272
|
}
|
|
31565
32273
|
}
|
|
@@ -31577,7 +32285,7 @@ async function fetchMyForms() {
|
|
|
31577
32285
|
if (d) eventMap.set(`${evt.pubkey}:${d}`, evt);
|
|
31578
32286
|
}
|
|
31579
32287
|
return entries.filter((e) => e[0] === "f" && e[1]).map((entry) => {
|
|
31580
|
-
const [, coordKey, , keySegment] = entry;
|
|
32288
|
+
const [, coordKey, relayHint, keySegment] = entry;
|
|
31581
32289
|
const [formPubkey, formId] = coordKey.split(":");
|
|
31582
32290
|
if (!formPubkey || !formId) return null;
|
|
31583
32291
|
const evt = eventMap.get(coordKey);
|
|
@@ -31593,7 +32301,8 @@ async function fetchMyForms() {
|
|
|
31593
32301
|
createdAt: evt?.created_at ?? 0,
|
|
31594
32302
|
isEncrypted,
|
|
31595
32303
|
signingKey: keys?.signingKey,
|
|
31596
|
-
viewKey: keys?.viewKey
|
|
32304
|
+
viewKey: keys?.viewKey,
|
|
32305
|
+
relay: relayHint || void 0
|
|
31597
32306
|
};
|
|
31598
32307
|
return summary;
|
|
31599
32308
|
}).filter((s) => s !== null);
|
|
@@ -31606,15 +32315,7 @@ async function appendToMyFormsList(formPubkey, formId, relay, signingKeyHex, vie
|
|
|
31606
32315
|
let entries = [];
|
|
31607
32316
|
if (existing?.content) {
|
|
31608
32317
|
try {
|
|
31609
|
-
|
|
31610
|
-
if (existing.content.includes("?iv=")) {
|
|
31611
|
-
if (!signer.decrypt) throw new Error("Signer cannot decrypt");
|
|
31612
|
-
decrypted = await signer.decrypt(userPubkey, existing.content);
|
|
31613
|
-
} else {
|
|
31614
|
-
decrypted = await nip44SelfDecrypt(signer, existing.content);
|
|
31615
|
-
}
|
|
31616
|
-
const parsed = JSON.parse(decrypted);
|
|
31617
|
-
entries = Array.isArray(parsed) ? parsed : [];
|
|
32318
|
+
entries = await decryptListEntries(signer, userPubkey, existing.content);
|
|
31618
32319
|
} catch {
|
|
31619
32320
|
entries = [];
|
|
31620
32321
|
}
|
|
@@ -31627,15 +32328,7 @@ async function appendToMyFormsList(formPubkey, formId, relay, signingKeyHex, vie
|
|
|
31627
32328
|
const secrets = signingKeyHex ? encodeFormKeys(signingKeyHex, viewKeyHex) : "";
|
|
31628
32329
|
entries.push(["f", coordKey, relay, secrets]);
|
|
31629
32330
|
}
|
|
31630
|
-
|
|
31631
|
-
const listEvent = {
|
|
31632
|
-
kind: FORM_KINDS.myFormsList,
|
|
31633
|
-
created_at: Math.floor(Date.now() / 1e3),
|
|
31634
|
-
tags: [],
|
|
31635
|
-
content: encrypted
|
|
31636
|
-
};
|
|
31637
|
-
const signed = await signer.signEvent(listEvent);
|
|
31638
|
-
await nostrRuntime.publish(relays, signed);
|
|
32331
|
+
await publishMyFormsList(signer, relays, entries);
|
|
31639
32332
|
}
|
|
31640
32333
|
async function saveToMyForms(summaries) {
|
|
31641
32334
|
const signer = await signerManager.getSigner();
|
|
@@ -31643,18 +32336,10 @@ async function saveToMyForms(summaries) {
|
|
|
31643
32336
|
const entries = summaries.map((s) => [
|
|
31644
32337
|
"f",
|
|
31645
32338
|
`${s.pubkey}:${s.id}`,
|
|
31646
|
-
"",
|
|
32339
|
+
s.relay ?? "",
|
|
31647
32340
|
s.signingKey ? encodeFormKeys(s.signingKey, s.viewKey) : ""
|
|
31648
32341
|
]);
|
|
31649
|
-
|
|
31650
|
-
const event = {
|
|
31651
|
-
kind: FORM_KINDS.myFormsList,
|
|
31652
|
-
created_at: Math.floor(Date.now() / 1e3),
|
|
31653
|
-
tags: [],
|
|
31654
|
-
content: encrypted
|
|
31655
|
-
};
|
|
31656
|
-
const signed = await signer.signEvent(event);
|
|
31657
|
-
await nostrRuntime.publish(relays, signed);
|
|
32342
|
+
await publishMyFormsList(signer, relays, entries);
|
|
31658
32343
|
}
|
|
31659
32344
|
async function fetchMyFormsByAuthor(pubkey, relays) {
|
|
31660
32345
|
const filter = {
|
|
@@ -31677,6 +32362,8 @@ async function fetchMyFormsByAuthor(pubkey, relays) {
|
|
|
31677
32362
|
}
|
|
31678
32363
|
async function deleteForm(formId, formPubkey) {
|
|
31679
32364
|
const signer = await signerManager.getSigner();
|
|
32365
|
+
const userPubkey = await signer.getPublicKey();
|
|
32366
|
+
const relays = relayManager.getRelaysForModule("forms");
|
|
31680
32367
|
const coordinate = `${FORM_KINDS.template}:${formPubkey}:${formId}`;
|
|
31681
32368
|
const event = {
|
|
31682
32369
|
kind: 5,
|
|
@@ -31687,58 +32374,60 @@ async function deleteForm(formId, formPubkey) {
|
|
|
31687
32374
|
],
|
|
31688
32375
|
content: "Deleted via Formstr"
|
|
31689
32376
|
};
|
|
31690
|
-
|
|
31691
|
-
const
|
|
31692
|
-
|
|
32377
|
+
await nostrRuntime.publish(relays, await signer.signEvent(event));
|
|
32378
|
+
const listEvent = await fetchLatestMyFormsEvent(relays, userPubkey);
|
|
32379
|
+
if (!listEvent?.content) return;
|
|
32380
|
+
let entries;
|
|
32381
|
+
try {
|
|
32382
|
+
entries = await decryptListEntries(signer, userPubkey, listEvent.content);
|
|
32383
|
+
} catch {
|
|
32384
|
+
return;
|
|
32385
|
+
}
|
|
32386
|
+
const coordKey = `${formPubkey}:${formId}`;
|
|
32387
|
+
const trimmed = entries.filter((e) => e[1] !== coordKey);
|
|
32388
|
+
if (trimmed.length === entries.length) return;
|
|
32389
|
+
await publishMyFormsList(signer, relays, trimmed);
|
|
31693
32390
|
}
|
|
31694
32391
|
async function updateForm(params) {
|
|
31695
32392
|
const relays = relayManager.getRelaysForModule("forms");
|
|
31696
|
-
const
|
|
32393
|
+
const summary = (await fetchMyForms()).find(
|
|
32394
|
+
(f) => f.id === params.formId && f.pubkey === params.pubkey
|
|
32395
|
+
);
|
|
32396
|
+
const existing = await fetchForm(params.pubkey, params.formId, summary?.viewKey);
|
|
31697
32397
|
if (!existing) throw new Error(`Form not found: ${params.formId}`);
|
|
31698
32398
|
const name = params.name ?? existing.name;
|
|
31699
32399
|
const settings = { ...existing.settings, ...params.settings };
|
|
31700
32400
|
const fields = params.fields ?? existing.fields;
|
|
32401
|
+
const specRows = buildSpecRows(params.formId, name, fields, settings);
|
|
31701
32402
|
if (existing.isEncrypted) {
|
|
31702
|
-
const summary = (await fetchMyForms()).find(
|
|
31703
|
-
(f) => f.id === params.formId && f.pubkey === params.pubkey
|
|
31704
|
-
);
|
|
31705
32403
|
if (!summary?.signingKey || !summary?.viewKey) {
|
|
31706
32404
|
throw new Error("Not the form owner or signing key unavailable");
|
|
31707
32405
|
}
|
|
31708
32406
|
const signingKeyBytes = hexToBytes3(summary.signingKey);
|
|
31709
32407
|
const formSigner = makeSigningKeySigner(summary.signingKey);
|
|
31710
32408
|
const viewPubkey = getPublicKey(hexToBytes3(summary.viewKey));
|
|
31711
|
-
const
|
|
31712
|
-
const content = await formSigner.nip44Encrypt(viewPubkey, JSON.stringify(fieldTags));
|
|
31713
|
-
const tags2 = [
|
|
31714
|
-
["d", params.formId],
|
|
31715
|
-
["name", name],
|
|
31716
|
-
["encryption", "view-key"],
|
|
31717
|
-
["settings", JSON.stringify(settings)]
|
|
31718
|
-
];
|
|
32409
|
+
const content = await formSigner.nip44Encrypt(viewPubkey, JSON.stringify(specRows));
|
|
31719
32410
|
const event2 = {
|
|
31720
32411
|
kind: FORM_KINDS.template,
|
|
31721
32412
|
created_at: Math.floor(Date.now() / 1e3),
|
|
31722
|
-
tags:
|
|
32413
|
+
tags: buildEncryptedOuterTags(params.formId, name, relays, settings),
|
|
31723
32414
|
content
|
|
31724
32415
|
};
|
|
31725
32416
|
await nostrRuntime.publish(relays, finalizeEvent(event2, signingKeyBytes));
|
|
31726
32417
|
return;
|
|
31727
32418
|
}
|
|
31728
|
-
const
|
|
31729
|
-
const tags = [
|
|
31730
|
-
["d", params.formId],
|
|
31731
|
-
["name", name],
|
|
31732
|
-
["settings", JSON.stringify(settings)]
|
|
31733
|
-
];
|
|
31734
|
-
for (const field of fields) tags.push(buildFieldTag(field));
|
|
31735
|
-
if (settings.publicForm) tags.push(["t", "public"]);
|
|
32419
|
+
const tags = [...specRows, ["t", "public"], ...relays.map((r) => ["relay", r])];
|
|
31736
32420
|
const event = {
|
|
31737
32421
|
kind: FORM_KINDS.template,
|
|
31738
32422
|
created_at: Math.floor(Date.now() / 1e3),
|
|
31739
32423
|
tags,
|
|
31740
32424
|
content: ""
|
|
31741
32425
|
};
|
|
32426
|
+
if (summary?.signingKey) {
|
|
32427
|
+
await nostrRuntime.publish(relays, finalizeEvent(event, hexToBytes3(summary.signingKey)));
|
|
32428
|
+
return;
|
|
32429
|
+
}
|
|
32430
|
+
const signer = await signerManager.getSigner();
|
|
31742
32431
|
await nostrRuntime.publish(relays, await signer.signEvent(event));
|
|
31743
32432
|
}
|
|
31744
32433
|
async function shareForm(params) {
|
|
@@ -31746,27 +32435,50 @@ async function shareForm(params) {
|
|
|
31746
32435
|
const summary = (await fetchMyForms()).find(
|
|
31747
32436
|
(f) => f.id === params.formId && f.pubkey === params.formPubkey
|
|
31748
32437
|
);
|
|
31749
|
-
if (!summary?.
|
|
31750
|
-
throw new Error("Not the form owner or
|
|
31751
|
-
}
|
|
31752
|
-
const
|
|
31753
|
-
const
|
|
31754
|
-
const
|
|
31755
|
-
const
|
|
31756
|
-
|
|
31757
|
-
|
|
31758
|
-
tags: [
|
|
31759
|
-
["a", coordinate],
|
|
31760
|
-
["viewKey", summary.viewKey]
|
|
31761
|
-
],
|
|
31762
|
-
content: `Formstr form view key for ${naddr}`
|
|
31763
|
-
};
|
|
32438
|
+
if (!summary?.signingKey) {
|
|
32439
|
+
throw new Error("Not the form owner or form keys unavailable");
|
|
32440
|
+
}
|
|
32441
|
+
const signingKeyBytes = hexToBytes3(summary.signingKey);
|
|
32442
|
+
const signingPubkey = getPublicKey(signingKeyBytes);
|
|
32443
|
+
const formSigner = new LocalSigner2(signingKeyBytes);
|
|
32444
|
+
const now2 = () => Math.round(Date.now() / 1e3);
|
|
32445
|
+
const editors = new Set(params.editors ?? []);
|
|
32446
|
+
const targets = [.../* @__PURE__ */ new Set([...params.recipients, ...editors])];
|
|
31764
32447
|
const failed = [];
|
|
31765
32448
|
let published = 0;
|
|
31766
|
-
for (const recipient of
|
|
32449
|
+
for (const recipient of targets) {
|
|
31767
32450
|
try {
|
|
31768
|
-
const
|
|
31769
|
-
|
|
32451
|
+
const accessTags = [];
|
|
32452
|
+
if (editors.has(recipient)) accessTags.push(["EditAccess", summary.signingKey]);
|
|
32453
|
+
if (summary.viewKey) accessTags.push(["ViewAccess", summary.viewKey]);
|
|
32454
|
+
const rumor = {
|
|
32455
|
+
kind: 18,
|
|
32456
|
+
pubkey: signingPubkey,
|
|
32457
|
+
created_at: now2(),
|
|
32458
|
+
content: "",
|
|
32459
|
+
tags: accessTags
|
|
32460
|
+
};
|
|
32461
|
+
rumor.id = getEventHash(rumor);
|
|
32462
|
+
const seal = finalizeEvent(
|
|
32463
|
+
{
|
|
32464
|
+
kind: 13,
|
|
32465
|
+
content: await formSigner.nip44Encrypt(recipient, JSON.stringify(rumor)),
|
|
32466
|
+
created_at: now2(),
|
|
32467
|
+
tags: []
|
|
32468
|
+
},
|
|
32469
|
+
signingKeyBytes
|
|
32470
|
+
);
|
|
32471
|
+
const randomKey = generateSecretKey();
|
|
32472
|
+
const wrap = finalizeEvent(
|
|
32473
|
+
{
|
|
32474
|
+
kind: 1059,
|
|
32475
|
+
content: await new LocalSigner2(randomKey).nip44Encrypt(recipient, JSON.stringify(seal)),
|
|
32476
|
+
created_at: now2(),
|
|
32477
|
+
tags: [["p", accessGrantAlias(signingPubkey, params.formId, recipient)]]
|
|
32478
|
+
},
|
|
32479
|
+
randomKey
|
|
32480
|
+
);
|
|
32481
|
+
await nostrRuntime.publish(relays, wrap);
|
|
31770
32482
|
published++;
|
|
31771
32483
|
} catch {
|
|
31772
32484
|
failed.push(recipient);
|
|
@@ -31790,32 +32502,32 @@ async function importForm(summary) {
|
|
|
31790
32502
|
if (current.some((f) => f.id === summary.id && f.pubkey === summary.pubkey)) return;
|
|
31791
32503
|
await saveToMyForms([...current, summary]);
|
|
31792
32504
|
}
|
|
31793
|
-
function
|
|
31794
|
-
const
|
|
31795
|
-
const
|
|
31796
|
-
|
|
31797
|
-
|
|
31798
|
-
function parseFormEvent(event) {
|
|
31799
|
-
const dTag = event.tags.find((t) => t[0] === "d")?.[1] ?? "";
|
|
31800
|
-
const nameTag = event.tags.find((t) => t[0] === "name")?.[1] ?? "Untitled";
|
|
31801
|
-
const settingsTag = event.tags.find((t) => t[0] === "settings")?.[1];
|
|
32505
|
+
function parseFormEvent(event, decryptedRows) {
|
|
32506
|
+
const merged = decryptedRows ? [...event.tags, ...decryptedRows] : event.tags;
|
|
32507
|
+
const dTag = merged.find((t) => t[0] === "d")?.[1] ?? "";
|
|
32508
|
+
const nameTag = merged.find((t) => t[0] === "name")?.[1] ?? "Untitled";
|
|
32509
|
+
const settingsTag = merged.find((t) => t[0] === "settings")?.[1];
|
|
31802
32510
|
const encTag = event.tags.find((t) => t[0] === "encryption")?.[1];
|
|
31803
|
-
const
|
|
31804
|
-
|
|
31805
|
-
|
|
31806
|
-
|
|
31807
|
-
|
|
31808
|
-
|
|
31809
|
-
|
|
31810
|
-
|
|
32511
|
+
const relays = event.tags.filter((t) => t[0] === "relay" && t[1]).map((t) => t[1]);
|
|
32512
|
+
const fields = merged.filter((t) => t[0] === "field").map(parseFieldTag);
|
|
32513
|
+
const outerHasFields = event.tags.some((t) => t[0] === "field");
|
|
32514
|
+
const isEncrypted = encTag != null ? encTag === "view-key" : event.content.length > 0 && !outerHasFields;
|
|
32515
|
+
let settings = {};
|
|
32516
|
+
if (settingsTag) {
|
|
32517
|
+
try {
|
|
32518
|
+
settings = JSON.parse(settingsTag);
|
|
32519
|
+
} catch {
|
|
32520
|
+
}
|
|
32521
|
+
}
|
|
31811
32522
|
return {
|
|
31812
32523
|
id: dTag,
|
|
31813
32524
|
name: nameTag,
|
|
31814
32525
|
fields,
|
|
31815
|
-
settings
|
|
32526
|
+
settings,
|
|
31816
32527
|
pubkey: event.pubkey,
|
|
31817
32528
|
createdAt: event.created_at,
|
|
31818
32529
|
isEncrypted,
|
|
32530
|
+
...relays.length > 0 && { relays },
|
|
31819
32531
|
event
|
|
31820
32532
|
};
|
|
31821
32533
|
}
|
|
@@ -31831,15 +32543,6 @@ function parseResponseEvent(event) {
|
|
|
31831
32543
|
event
|
|
31832
32544
|
};
|
|
31833
32545
|
}
|
|
31834
|
-
function safeParseOptions(json) {
|
|
31835
|
-
try {
|
|
31836
|
-
const arr = JSON.parse(json);
|
|
31837
|
-
if (!Array.isArray(arr)) return void 0;
|
|
31838
|
-
return arr.map((o) => ({ id: o[0], label: o[1] }));
|
|
31839
|
-
} catch {
|
|
31840
|
-
return void 0;
|
|
31841
|
-
}
|
|
31842
|
-
}
|
|
31843
32546
|
|
|
31844
32547
|
// ../agent/src/services/calendar/service.ts
|
|
31845
32548
|
var service_exports2 = {};
|
|
@@ -31854,9 +32557,14 @@ __export(service_exports2, {
|
|
|
31854
32557
|
fetchCalendarLists: () => fetchCalendarLists,
|
|
31855
32558
|
fetchDeletions: () => fetchDeletions,
|
|
31856
32559
|
fetchInvitationsSync: () => fetchInvitationsSync,
|
|
32560
|
+
fetchParticipantRemovals: () => fetchParticipantRemovals,
|
|
32561
|
+
fetchRelayListsForPubkeys: () => fetchRelayListsForPubkeys,
|
|
32562
|
+
getInvitationInboxRelays: () => getInvitationInboxRelays,
|
|
31857
32563
|
isEventDeleted: () => isEventDeleted,
|
|
32564
|
+
lookupEventViewKey: () => lookupEventViewKey,
|
|
31858
32565
|
moveEventBetweenCalendarLists: () => moveEventBetweenCalendarLists,
|
|
31859
32566
|
parseCalendarEvent: () => parseCalendarEvent,
|
|
32567
|
+
publishParticipantRemovalEvent: () => publishParticipantRemovalEvent,
|
|
31860
32568
|
publishPrivateCalendarEvent: () => publishPrivateCalendarEvent,
|
|
31861
32569
|
publishPublicCalendarEvent: () => publishPublicCalendarEvent,
|
|
31862
32570
|
removeEventFromCalendarList: () => removeEventFromCalendarList,
|
|
@@ -31873,6 +32581,7 @@ function encodeCalendarList(list) {
|
|
|
31873
32581
|
["content", list.description ?? ""],
|
|
31874
32582
|
["color", list.color]
|
|
31875
32583
|
];
|
|
32584
|
+
if (list.notificationPreference === "disabled") tags.push(["notifications", "disabled"]);
|
|
31876
32585
|
for (const ref of list.eventRefs) tags.push(["a", ...ref]);
|
|
31877
32586
|
return tags;
|
|
31878
32587
|
}
|
|
@@ -31880,6 +32589,7 @@ function decodeCalendarList(tags, dTag, eventId) {
|
|
|
31880
32589
|
let title = DEFAULT_TITLE;
|
|
31881
32590
|
let description = "";
|
|
31882
32591
|
let color = DEFAULT_COLOR;
|
|
32592
|
+
let notificationPreference;
|
|
31883
32593
|
const eventRefs = [];
|
|
31884
32594
|
for (const tag of tags) {
|
|
31885
32595
|
if (!Array.isArray(tag) || tag.length === 0) continue;
|
|
@@ -31893,6 +32603,9 @@ function decodeCalendarList(tags, dTag, eventId) {
|
|
|
31893
32603
|
case "color":
|
|
31894
32604
|
color = tag[1] || DEFAULT_COLOR;
|
|
31895
32605
|
break;
|
|
32606
|
+
case "notifications":
|
|
32607
|
+
notificationPreference = tag[1] === "disabled" ? "disabled" : "enabled";
|
|
32608
|
+
break;
|
|
31896
32609
|
case "a":
|
|
31897
32610
|
if (tag[1] === "a") {
|
|
31898
32611
|
const coord = tag[2] ?? "";
|
|
@@ -31911,7 +32624,8 @@ function decodeCalendarList(tags, dTag, eventId) {
|
|
|
31911
32624
|
color,
|
|
31912
32625
|
eventRefs,
|
|
31913
32626
|
createdAt: 0,
|
|
31914
|
-
isVisible: true
|
|
32627
|
+
isVisible: true,
|
|
32628
|
+
notificationPreference
|
|
31915
32629
|
};
|
|
31916
32630
|
}
|
|
31917
32631
|
|
|
@@ -31936,6 +32650,8 @@ var CALENDAR_KINDS = {
|
|
|
31936
32650
|
rsvpGiftWrap: 1055,
|
|
31937
32651
|
rsvpRumor: 55,
|
|
31938
32652
|
participantRemoval: 84,
|
|
32653
|
+
/** Public free/busy list, one per (user, YYYY-MM month). */
|
|
32654
|
+
publicBusyList: 31926,
|
|
31939
32655
|
// Appointment scheduling (Calendly-style booking links).
|
|
31940
32656
|
schedulingPage: 31927,
|
|
31941
32657
|
schedulingPagesList: 32680,
|
|
@@ -32181,13 +32897,14 @@ async function publishPrivateCalendarEvent(draft, calendarId) {
|
|
|
32181
32897
|
const eventData = [
|
|
32182
32898
|
["title", draft.title],
|
|
32183
32899
|
["description", draft.description],
|
|
32184
|
-
["start",
|
|
32185
|
-
["end",
|
|
32900
|
+
["start", Math.floor(draft.begin.getTime() / 1e3)],
|
|
32901
|
+
["end", Math.floor(draft.end.getTime() / 1e3)],
|
|
32186
32902
|
["d", eventId]
|
|
32187
32903
|
];
|
|
32188
32904
|
if (draft.image) eventData.push(["image", draft.image]);
|
|
32189
32905
|
if (draft.location) eventData.push(["location", draft.location]);
|
|
32190
32906
|
for (const cat of draft.categories ?? []) eventData.push(["t", cat]);
|
|
32907
|
+
eventData.push(["p", pubkey]);
|
|
32191
32908
|
for (const p of draft.participants ?? []) eventData.push(["p", p]);
|
|
32192
32909
|
if (draft.startTzid) eventData.push(["start_tzid", draft.startTzid]);
|
|
32193
32910
|
if (draft.endTzid) eventData.push(["end_tzid", draft.endTzid]);
|
|
@@ -32195,7 +32912,12 @@ async function publishPrivateCalendarEvent(draft, calendarId) {
|
|
|
32195
32912
|
eventData.push(["L", "rrule"]);
|
|
32196
32913
|
eventData.push(["l", draft.rrule]);
|
|
32197
32914
|
}
|
|
32198
|
-
if (draft.
|
|
32915
|
+
if (draft.notificationPreference) eventData.push(["notification", draft.notificationPreference]);
|
|
32916
|
+
if (draft.registrationFormRef) {
|
|
32917
|
+
eventData.push(
|
|
32918
|
+
draft.registrationFormViewKey ? ["form", draft.registrationFormRef, draft.registrationFormViewKey] : ["form", draft.registrationFormRef]
|
|
32919
|
+
);
|
|
32920
|
+
}
|
|
32199
32921
|
const viewKeyNsec = draft.viewKey ?? generateViewKey().nsec;
|
|
32200
32922
|
const content = await encryptWithViewKey(viewKeyNsec, JSON.stringify(eventData));
|
|
32201
32923
|
const event = {
|
|
@@ -32210,6 +32932,7 @@ async function publishPrivateCalendarEvent(draft, calendarId) {
|
|
|
32210
32932
|
const relayHint = relays[0] ?? "";
|
|
32211
32933
|
const coordinate = `${CALENDAR_KINDS.privateEvent}:${pubkey}:${eventId}`;
|
|
32212
32934
|
if (draft.participants?.length) {
|
|
32935
|
+
const relayLists = await fetchRelayListsForPubkeys(draft.participants);
|
|
32213
32936
|
for (const participant of draft.participants) {
|
|
32214
32937
|
const wrap = await wrapEvent3(
|
|
32215
32938
|
{
|
|
@@ -32224,7 +32947,7 @@ async function publishPrivateCalendarEvent(draft, calendarId) {
|
|
|
32224
32947
|
participant,
|
|
32225
32948
|
CALENDAR_KINDS.giftWrap
|
|
32226
32949
|
);
|
|
32227
|
-
await nostrRuntime.publish(relays, wrap);
|
|
32950
|
+
await nostrRuntime.publish(relayLists.get(participant) ?? relays, wrap);
|
|
32228
32951
|
}
|
|
32229
32952
|
}
|
|
32230
32953
|
return {
|
|
@@ -32250,9 +32973,37 @@ async function publishPrivateCalendarEvent(draft, calendarId) {
|
|
|
32250
32973
|
startTzid: draft.startTzid,
|
|
32251
32974
|
endTzid: draft.endTzid,
|
|
32252
32975
|
registrationFormRef: draft.registrationFormRef,
|
|
32976
|
+
registrationFormViewKey: draft.registrationFormViewKey,
|
|
32977
|
+
notificationPreference: draft.notificationPreference,
|
|
32253
32978
|
event: signed
|
|
32254
32979
|
};
|
|
32255
32980
|
}
|
|
32981
|
+
async function fetchRelayListsForPubkeys(pubkeys) {
|
|
32982
|
+
const result = /* @__PURE__ */ new Map();
|
|
32983
|
+
if (pubkeys.length === 0) return result;
|
|
32984
|
+
const relays = relayManager.getRelaysForModule("calendar");
|
|
32985
|
+
const events = await nostrRuntime.querySync(relays, { kinds: [10002], authors: pubkeys });
|
|
32986
|
+
const newest = /* @__PURE__ */ new Map();
|
|
32987
|
+
for (const event of events) {
|
|
32988
|
+
const prev = newest.get(event.pubkey);
|
|
32989
|
+
if (!prev || event.created_at > prev.created_at) newest.set(event.pubkey, event);
|
|
32990
|
+
}
|
|
32991
|
+
for (const [pubkey, event] of newest) {
|
|
32992
|
+
const urls = event.tags.filter((t) => t[0] === "r" && t[1]).map((t) => t[1]);
|
|
32993
|
+
if (urls.length > 0) result.set(pubkey, urls);
|
|
32994
|
+
}
|
|
32995
|
+
return result;
|
|
32996
|
+
}
|
|
32997
|
+
async function getInvitationInboxRelays(pubkey) {
|
|
32998
|
+
const relays = relayManager.getRelaysForModule("calendar");
|
|
32999
|
+
try {
|
|
33000
|
+
const configs = await relayManager.fetchUserRelays(pubkey);
|
|
33001
|
+
const readRelays = configs.filter((c) => c.read).map((c) => c.url);
|
|
33002
|
+
return [.../* @__PURE__ */ new Set([...relays, ...readRelays])];
|
|
33003
|
+
} catch {
|
|
33004
|
+
return relays;
|
|
33005
|
+
}
|
|
33006
|
+
}
|
|
32256
33007
|
function subscribeToCalendarEvents(params, onEvent, onEose) {
|
|
32257
33008
|
const relays = relayManager.getRelaysForModule("calendar");
|
|
32258
33009
|
const filter = {
|
|
@@ -32539,6 +33290,42 @@ async function deleteCalendarList(coordinate) {
|
|
|
32539
33290
|
const relays = relayManager.getRelaysForModule("calendar");
|
|
32540
33291
|
await nostrRuntime.publish(relays, signed);
|
|
32541
33292
|
}
|
|
33293
|
+
async function publishParticipantRemovalEvent({
|
|
33294
|
+
kinds,
|
|
33295
|
+
eventIds = [],
|
|
33296
|
+
coordinates = [],
|
|
33297
|
+
reason = ""
|
|
33298
|
+
}) {
|
|
33299
|
+
const signer = await signerManager.getSigner();
|
|
33300
|
+
const tags = [];
|
|
33301
|
+
for (const id of eventIds) tags.push(["e", id]);
|
|
33302
|
+
for (const coord of coordinates) tags.push(["a", coord]);
|
|
33303
|
+
for (const kind of kinds) tags.push(["k", String(kind)]);
|
|
33304
|
+
const event = {
|
|
33305
|
+
kind: CALENDAR_KINDS.participantRemoval,
|
|
33306
|
+
created_at: Math.floor(Date.now() / 1e3),
|
|
33307
|
+
tags,
|
|
33308
|
+
content: reason
|
|
33309
|
+
};
|
|
33310
|
+
const signed = await signer.signEvent(event);
|
|
33311
|
+
const relays = relayManager.getRelaysForModule("calendar");
|
|
33312
|
+
await nostrRuntime.publish(relays, signed);
|
|
33313
|
+
}
|
|
33314
|
+
async function fetchParticipantRemovals(pubkey, relays = relayManager.getRelaysForModule("calendar")) {
|
|
33315
|
+
const ids = /* @__PURE__ */ new Set();
|
|
33316
|
+
const coordinates = /* @__PURE__ */ new Set();
|
|
33317
|
+
const events = await nostrRuntime.querySync(relays, {
|
|
33318
|
+
kinds: [CALENDAR_KINDS.participantRemoval],
|
|
33319
|
+
authors: [pubkey]
|
|
33320
|
+
});
|
|
33321
|
+
for (const ev of events) {
|
|
33322
|
+
for (const tag of ev.tags) {
|
|
33323
|
+
if (tag[0] === "e" && tag[1]) ids.add(tag[1]);
|
|
33324
|
+
else if (tag[0] === "a" && tag[1]) coordinates.add(tag[1]);
|
|
33325
|
+
}
|
|
33326
|
+
}
|
|
33327
|
+
return { ids, coordinates };
|
|
33328
|
+
}
|
|
32542
33329
|
async function parseCalendarEvent(event, viewKey) {
|
|
32543
33330
|
const dTag = event.tags.find((t) => t[0] === "d")?.[1] ?? "";
|
|
32544
33331
|
const isPrivate = event.kind !== CALENDAR_KINDS.publicEvent;
|
|
@@ -32566,7 +33353,10 @@ async function parseCalendarEvent(event, viewKey) {
|
|
|
32566
33353
|
const rrule = tags.find((t) => t[0] === "l" && t[2] === "rrule")?.[1] ?? (hasRruleLabel ? tags.find((t) => t[0] === "l")?.[1] : void 0) ?? tags.find((t) => t[0] === "rrule")?.[1] ?? null;
|
|
32567
33354
|
const startTzid = tags.find((t) => t[0] === "start_tzid")?.[1];
|
|
32568
33355
|
const endTzid = tags.find((t) => t[0] === "end_tzid")?.[1];
|
|
32569
|
-
const
|
|
33356
|
+
const formTag = tags.find((t) => t[0] === "form");
|
|
33357
|
+
const registrationFormRef = formTag?.[1];
|
|
33358
|
+
const registrationFormViewKey = formTag?.[2];
|
|
33359
|
+
const notificationPreference = tags.find((t) => t[0] === "notification")?.[1];
|
|
32570
33360
|
return {
|
|
32571
33361
|
id: dTag,
|
|
32572
33362
|
eventId: event.id,
|
|
@@ -32588,13 +33378,16 @@ async function parseCalendarEvent(event, viewKey) {
|
|
|
32588
33378
|
startTzid,
|
|
32589
33379
|
endTzid,
|
|
32590
33380
|
registrationFormRef,
|
|
33381
|
+
registrationFormViewKey,
|
|
33382
|
+
notificationPreference,
|
|
32591
33383
|
event
|
|
32592
33384
|
};
|
|
32593
33385
|
}
|
|
32594
33386
|
async function fetchInvitationsSync() {
|
|
32595
33387
|
const signer = await signerManager.getSigner();
|
|
32596
33388
|
const pubkey = await signer.getPublicKey();
|
|
32597
|
-
const relays =
|
|
33389
|
+
const relays = await getInvitationInboxRelays(pubkey);
|
|
33390
|
+
const removals = await fetchParticipantRemovals(pubkey, relays);
|
|
32598
33391
|
const wraps = await nostrRuntime.querySync(relays, {
|
|
32599
33392
|
kinds: [CALENDAR_KINDS.giftWrap, CALENDAR_KINDS.rsvpGiftWrap],
|
|
32600
33393
|
"#p": [pubkey]
|
|
@@ -32602,7 +33395,7 @@ async function fetchInvitationsSync() {
|
|
|
32602
33395
|
const seen = /* @__PURE__ */ new Set();
|
|
32603
33396
|
const out = [];
|
|
32604
33397
|
for (const wrap of wraps) {
|
|
32605
|
-
if (seen.has(wrap.id)) continue;
|
|
33398
|
+
if (seen.has(wrap.id) || removals.ids.has(wrap.id)) continue;
|
|
32606
33399
|
seen.add(wrap.id);
|
|
32607
33400
|
const invitation = await extractInvitationFromWrap(wrap);
|
|
32608
33401
|
if (!invitation) continue;
|
|
@@ -32614,6 +33407,15 @@ async function fetchInvitationsSync() {
|
|
|
32614
33407
|
}
|
|
32615
33408
|
return out;
|
|
32616
33409
|
}
|
|
33410
|
+
async function lookupEventViewKey(eventCoordinate) {
|
|
33411
|
+
const lists = await fetchCalendarLists();
|
|
33412
|
+
for (const list of lists) {
|
|
33413
|
+
for (const ref of list.eventRefs) {
|
|
33414
|
+
if (ref[0] === eventCoordinate && ref[2]) return ref[2];
|
|
33415
|
+
}
|
|
33416
|
+
}
|
|
33417
|
+
return void 0;
|
|
33418
|
+
}
|
|
32617
33419
|
|
|
32618
33420
|
// ../agent/src/services/calendar/booking.ts
|
|
32619
33421
|
var booking_exports = {};
|
|
@@ -32624,6 +33426,122 @@ __export(booking_exports, {
|
|
|
32624
33426
|
fetchBookingRequests: () => fetchBookingRequests,
|
|
32625
33427
|
fetchSchedulingPages: () => fetchSchedulingPages
|
|
32626
33428
|
});
|
|
33429
|
+
|
|
33430
|
+
// ../agent/src/services/calendar/busyList.ts
|
|
33431
|
+
var MONTH_KEY_RE = /^\d{4}-\d{2}$/;
|
|
33432
|
+
function busyListMonthKey(value) {
|
|
33433
|
+
const d = typeof value === "number" ? new Date(value) : value;
|
|
33434
|
+
const month = String(d.getUTCMonth() + 1).padStart(2, "0");
|
|
33435
|
+
return `${d.getUTCFullYear()}-${month}`;
|
|
33436
|
+
}
|
|
33437
|
+
function busyListMonthKeysForRange(startMs, endMs) {
|
|
33438
|
+
if (!Number.isFinite(startMs) || !Number.isFinite(endMs)) return [];
|
|
33439
|
+
const start = Math.min(startMs, endMs);
|
|
33440
|
+
const end = Math.max(startMs, endMs);
|
|
33441
|
+
const keys = [];
|
|
33442
|
+
const cursor = new Date(
|
|
33443
|
+
Date.UTC(new Date(start).getUTCFullYear(), new Date(start).getUTCMonth(), 1)
|
|
33444
|
+
);
|
|
33445
|
+
const endMonth = new Date(
|
|
33446
|
+
Date.UTC(new Date(end).getUTCFullYear(), new Date(end).getUTCMonth(), 1)
|
|
33447
|
+
);
|
|
33448
|
+
while (cursor.getTime() <= endMonth.getTime()) {
|
|
33449
|
+
keys.push(busyListMonthKey(cursor));
|
|
33450
|
+
cursor.setUTCMonth(cursor.getUTCMonth() + 1);
|
|
33451
|
+
}
|
|
33452
|
+
return keys;
|
|
33453
|
+
}
|
|
33454
|
+
function busyListToTags(list) {
|
|
33455
|
+
const tags = [
|
|
33456
|
+
["d", list.monthKey],
|
|
33457
|
+
["t", list.monthKey],
|
|
33458
|
+
["t", "busy"]
|
|
33459
|
+
];
|
|
33460
|
+
for (const r of list.ranges) {
|
|
33461
|
+
tags.push(["block", String(Math.floor(r.start / 1e3)), String(Math.floor(r.end / 1e3))]);
|
|
33462
|
+
}
|
|
33463
|
+
return tags;
|
|
33464
|
+
}
|
|
33465
|
+
function parseBusyListEvent(event) {
|
|
33466
|
+
const dTag = event.tags.find((t) => t[0] === "d")?.[1] ?? "";
|
|
33467
|
+
if (!MONTH_KEY_RE.test(dTag)) return null;
|
|
33468
|
+
const ranges = [];
|
|
33469
|
+
for (const tag of event.tags) {
|
|
33470
|
+
if (tag[0] !== "block") continue;
|
|
33471
|
+
const start = Number(tag[1]) * 1e3;
|
|
33472
|
+
const end = Number(tag[2]) * 1e3;
|
|
33473
|
+
if (!Number.isFinite(start) || !Number.isFinite(end) || end <= start) continue;
|
|
33474
|
+
ranges.push({ start, end });
|
|
33475
|
+
}
|
|
33476
|
+
ranges.sort((a, b) => a.start - b.start || a.end - b.end);
|
|
33477
|
+
const deduped = [];
|
|
33478
|
+
for (const r of ranges) {
|
|
33479
|
+
const last = deduped[deduped.length - 1];
|
|
33480
|
+
if (last && last.start === r.start && last.end === r.end) continue;
|
|
33481
|
+
deduped.push(r);
|
|
33482
|
+
}
|
|
33483
|
+
return {
|
|
33484
|
+
user: event.pubkey,
|
|
33485
|
+
monthKey: dTag,
|
|
33486
|
+
ranges: deduped,
|
|
33487
|
+
eventId: event.id,
|
|
33488
|
+
createdAt: event.created_at
|
|
33489
|
+
};
|
|
33490
|
+
}
|
|
33491
|
+
async function fetchBusyListsForUser(pubkey, monthKeys) {
|
|
33492
|
+
if (monthKeys.length === 0) return [];
|
|
33493
|
+
const relays = relayManager.getRelaysForModule("calendar");
|
|
33494
|
+
const events = await nostrRuntime.querySync(relays, {
|
|
33495
|
+
kinds: [CALENDAR_KINDS.publicBusyList],
|
|
33496
|
+
authors: [pubkey],
|
|
33497
|
+
"#d": monthKeys
|
|
33498
|
+
});
|
|
33499
|
+
const newestPerMonth = /* @__PURE__ */ new Map();
|
|
33500
|
+
for (const event of events) {
|
|
33501
|
+
const list = parseBusyListEvent(event);
|
|
33502
|
+
if (!list) continue;
|
|
33503
|
+
const prev = newestPerMonth.get(list.monthKey);
|
|
33504
|
+
if (!prev || list.createdAt > prev.createdAt) newestPerMonth.set(list.monthKey, list);
|
|
33505
|
+
}
|
|
33506
|
+
return [...newestPerMonth.values()];
|
|
33507
|
+
}
|
|
33508
|
+
async function publishBusyList(list) {
|
|
33509
|
+
const signer = await signerManager.getSigner();
|
|
33510
|
+
const event = {
|
|
33511
|
+
kind: CALENDAR_KINDS.publicBusyList,
|
|
33512
|
+
created_at: Math.floor(Date.now() / 1e3),
|
|
33513
|
+
tags: busyListToTags(list),
|
|
33514
|
+
content: ""
|
|
33515
|
+
};
|
|
33516
|
+
const signed = await signer.signEvent(event);
|
|
33517
|
+
const relays = relayManager.getRelaysForModule("calendar");
|
|
33518
|
+
await nostrRuntime.publish(relays, signed);
|
|
33519
|
+
}
|
|
33520
|
+
var sameRange = (a, b) => a.start === b.start && a.end === b.end;
|
|
33521
|
+
async function addBusyRange(range) {
|
|
33522
|
+
const signer = await signerManager.getSigner();
|
|
33523
|
+
const pubkey = await signer.getPublicKey();
|
|
33524
|
+
const monthKeys = busyListMonthKeysForRange(range.start, range.end);
|
|
33525
|
+
const existing = new Map(
|
|
33526
|
+
(await fetchBusyListsForUser(pubkey, monthKeys)).map((l) => [l.monthKey, l])
|
|
33527
|
+
);
|
|
33528
|
+
for (const monthKey of monthKeys) {
|
|
33529
|
+
const list = existing.get(monthKey) ?? {
|
|
33530
|
+
user: pubkey,
|
|
33531
|
+
monthKey,
|
|
33532
|
+
ranges: [],
|
|
33533
|
+
eventId: "",
|
|
33534
|
+
createdAt: 0
|
|
33535
|
+
};
|
|
33536
|
+
if (list.ranges.some((r) => sameRange(r, range))) continue;
|
|
33537
|
+
const ranges = [...list.ranges, { start: range.start, end: range.end }].sort(
|
|
33538
|
+
(a, b) => a.start - b.start || a.end - b.end
|
|
33539
|
+
);
|
|
33540
|
+
await publishBusyList({ ...list, ranges });
|
|
33541
|
+
}
|
|
33542
|
+
}
|
|
33543
|
+
|
|
33544
|
+
// ../agent/src/services/calendar/booking.ts
|
|
32627
33545
|
var BOOKING_HOST = "https://calendar.formstr.app";
|
|
32628
33546
|
async function fetchSchedulingPages() {
|
|
32629
33547
|
const signer = await signerManager.getSigner();
|
|
@@ -32782,6 +33700,10 @@ async function approveBookingRequest(request, calendar) {
|
|
|
32782
33700
|
event.viewKey ?? request.viewKey ?? ""
|
|
32783
33701
|
];
|
|
32784
33702
|
const updatedCalendar = await addEventToCalendarList(calendar, eventRef);
|
|
33703
|
+
try {
|
|
33704
|
+
await addBusyRange({ start: request.start, end: request.end });
|
|
33705
|
+
} catch {
|
|
33706
|
+
}
|
|
32785
33707
|
await sendBookingResponse({
|
|
32786
33708
|
schedulingPageRef: request.schedulingPageRef,
|
|
32787
33709
|
bookerPubkey: request.bookerPubkey,
|
|
@@ -32809,7 +33731,9 @@ var service_exports3 = {};
|
|
|
32809
33731
|
__export(service_exports3, {
|
|
32810
33732
|
addSharedPage: () => addSharedPage,
|
|
32811
33733
|
deletePage: () => deletePage,
|
|
33734
|
+
fetchAllDocMetadata: () => fetchAllDocMetadata,
|
|
32812
33735
|
fetchDeletions: () => fetchDeletions2,
|
|
33736
|
+
fetchDocMetadata: () => fetchDocMetadata,
|
|
32813
33737
|
fetchDocTags: () => fetchDocTags,
|
|
32814
33738
|
fetchMyPages: () => fetchMyPages,
|
|
32815
33739
|
fetchPage: () => fetchPage,
|
|
@@ -32817,17 +33741,22 @@ __export(service_exports3, {
|
|
|
32817
33741
|
fetchSharedPages: () => fetchSharedPages,
|
|
32818
33742
|
generateShareLink: () => generateShareLink,
|
|
32819
33743
|
isPageDeleted: () => isPageDeleted,
|
|
33744
|
+
saveDocMetadata: () => saveDocMetadata,
|
|
32820
33745
|
savePage: () => savePage,
|
|
32821
|
-
|
|
33746
|
+
setDocSharedAs: () => setDocSharedAs,
|
|
32822
33747
|
setDocTags: () => setDocTags,
|
|
33748
|
+
setDocTitle: () => setDocTitle,
|
|
32823
33749
|
sharePage: () => sharePage
|
|
32824
33750
|
});
|
|
32825
33751
|
|
|
32826
33752
|
// ../agent/src/services/pages/types.ts
|
|
32827
33753
|
var PAGES_KINDS = {
|
|
32828
33754
|
document: 33457,
|
|
33755
|
+
/** Legacy super-app shared-with-me list — read-only migration source; upstream
|
|
33756
|
+
* (nostr-docs) has no such kind. Shares now live in kind-34579 doc metadata. */
|
|
32829
33757
|
sharedPagesList: 11234,
|
|
32830
33758
|
docMetadata: 34579,
|
|
33759
|
+
comment: 1494,
|
|
32831
33760
|
crdtOp: 22457
|
|
32832
33761
|
};
|
|
32833
33762
|
|
|
@@ -32894,6 +33823,7 @@ async function fetchMyPages(viewKeys) {
|
|
|
32894
33823
|
authors: [pubkey]
|
|
32895
33824
|
});
|
|
32896
33825
|
const deletions = await fetchDeletions2(relays, [pubkey]);
|
|
33826
|
+
const metadata = await fetchAllDocMetadata().catch(() => /* @__PURE__ */ new Map());
|
|
32897
33827
|
const newest = /* @__PURE__ */ new Map();
|
|
32898
33828
|
for (const ev of events) {
|
|
32899
33829
|
if (isPageDeleted(ev, deletions)) continue;
|
|
@@ -32904,15 +33834,18 @@ async function fetchMyPages(viewKeys) {
|
|
|
32904
33834
|
const summaries = [];
|
|
32905
33835
|
for (const [dTag, ev] of newest) {
|
|
32906
33836
|
const address = `${PAGES_KINDS.document}:${ev.pubkey}:${dTag}`;
|
|
32907
|
-
|
|
32908
|
-
|
|
32909
|
-
|
|
32910
|
-
|
|
32911
|
-
|
|
32912
|
-
|
|
32913
|
-
|
|
32914
|
-
|
|
32915
|
-
|
|
33837
|
+
const meta = metadata.get(address);
|
|
33838
|
+
const viewKey = meta?.viewKey ?? viewKeys?.get(address);
|
|
33839
|
+
let title = meta?.title || `Document ${dTag}`;
|
|
33840
|
+
if (!meta?.title) {
|
|
33841
|
+
try {
|
|
33842
|
+
title = extractTitle(await nip44SelfDecrypt(signer, ev.content));
|
|
33843
|
+
} catch {
|
|
33844
|
+
if (viewKey) {
|
|
33845
|
+
try {
|
|
33846
|
+
title = extractTitle(await decryptWithViewKey2(viewKey, ev.content));
|
|
33847
|
+
} catch {
|
|
33848
|
+
}
|
|
32916
33849
|
}
|
|
32917
33850
|
}
|
|
32918
33851
|
}
|
|
@@ -32923,7 +33856,9 @@ async function fetchMyPages(viewKeys) {
|
|
|
32923
33856
|
pubkey: ev.pubkey,
|
|
32924
33857
|
createdAt: ev.created_at,
|
|
32925
33858
|
isEncrypted: ev.content.length > 0,
|
|
32926
|
-
viewKey
|
|
33859
|
+
viewKey,
|
|
33860
|
+
...Array.isArray(meta?.tags) && meta.tags.length > 0 ? { tags: meta.tags } : {},
|
|
33861
|
+
...meta?.sharedAs ? { sharedAs: meta.sharedAs } : {}
|
|
32927
33862
|
});
|
|
32928
33863
|
}
|
|
32929
33864
|
return summaries;
|
|
@@ -32943,6 +33878,17 @@ async function fetchPage(pubkey, docId, viewKey) {
|
|
|
32943
33878
|
decrypted = true;
|
|
32944
33879
|
} catch {
|
|
32945
33880
|
}
|
|
33881
|
+
if (!decrypted && !viewKey) {
|
|
33882
|
+
try {
|
|
33883
|
+
const meta = await fetchDocMetadata(`${PAGES_KINDS.document}:${pubkey}:${docId}`);
|
|
33884
|
+
if (meta?.viewKey) {
|
|
33885
|
+
content = await decryptWithViewKey2(meta.viewKey, event.content);
|
|
33886
|
+
viewKey = meta.viewKey;
|
|
33887
|
+
decrypted = true;
|
|
33888
|
+
}
|
|
33889
|
+
} catch {
|
|
33890
|
+
}
|
|
33891
|
+
}
|
|
32946
33892
|
return {
|
|
32947
33893
|
id: docId,
|
|
32948
33894
|
address: `${PAGES_KINDS.document}:${event.pubkey}:${docId}`,
|
|
@@ -32957,12 +33903,24 @@ async function fetchPage(pubkey, docId, viewKey) {
|
|
|
32957
33903
|
}
|
|
32958
33904
|
async function deletePage(address) {
|
|
32959
33905
|
const signer = await signerManager.getSigner();
|
|
33906
|
+
const [kindStr, pubkey, dTag] = address.split(":");
|
|
33907
|
+
let versionIds = [];
|
|
33908
|
+
try {
|
|
33909
|
+
const versions = await nostrRuntime.querySync(RELAYS(), {
|
|
33910
|
+
kinds: [Number(kindStr)],
|
|
33911
|
+
authors: [pubkey],
|
|
33912
|
+
"#d": [dTag]
|
|
33913
|
+
});
|
|
33914
|
+
versionIds = versions.map((v) => v.id);
|
|
33915
|
+
} catch {
|
|
33916
|
+
}
|
|
32960
33917
|
const event = {
|
|
32961
33918
|
kind: 5,
|
|
32962
33919
|
created_at: Math.floor(Date.now() / 1e3),
|
|
32963
33920
|
tags: [
|
|
32964
33921
|
["a", address],
|
|
32965
|
-
["k", String(PAGES_KINDS.document)]
|
|
33922
|
+
["k", String(PAGES_KINDS.document)],
|
|
33923
|
+
...versionIds.map((id) => ["e", id])
|
|
32966
33924
|
],
|
|
32967
33925
|
content: "Deleted via Formstr"
|
|
32968
33926
|
};
|
|
@@ -33003,9 +33961,16 @@ function generateShareLink(address, viewKey, editKey) {
|
|
|
33003
33961
|
}
|
|
33004
33962
|
async function sharePage(params) {
|
|
33005
33963
|
const signer = await signerManager.getSigner();
|
|
33006
|
-
const [, , dTag] = params.address.split(":");
|
|
33007
|
-
const
|
|
33008
|
-
|
|
33964
|
+
const [, ownerPubkey, dTag] = params.address.split(":");
|
|
33965
|
+
const originalMeta = await fetchDocMetadata(params.address).catch(() => void 0);
|
|
33966
|
+
if (params.canEdit && originalMeta?.sharedAs) {
|
|
33967
|
+
const sharedMeta = await fetchDocMetadata(originalMeta.sharedAs).catch(() => void 0);
|
|
33968
|
+
if (sharedMeta?.viewKey && sharedMeta.editKey) {
|
|
33969
|
+
return generateShareLink(originalMeta.sharedAs, sharedMeta.viewKey, sharedMeta.editKey);
|
|
33970
|
+
}
|
|
33971
|
+
}
|
|
33972
|
+
const viewKeyHex = params.viewKey ?? originalMeta?.viewKey ?? generateViewKey2().hex;
|
|
33973
|
+
const editKeyHex = params.canEdit ? params.editKey ?? originalMeta?.editKey ?? generateViewKey2().hex : void 0;
|
|
33009
33974
|
const encrypted = await encryptWithViewKey2(viewKeyHex, params.content);
|
|
33010
33975
|
const template = {
|
|
33011
33976
|
kind: PAGES_KINDS.document,
|
|
@@ -33016,9 +33981,36 @@ async function sharePage(params) {
|
|
|
33016
33981
|
const signed = editKeyHex ? finalizeEvent(template, hexToBytes4(editKeyHex)) : await signer.signEvent(template);
|
|
33017
33982
|
await nostrRuntime.publish(RELAYS(), signed);
|
|
33018
33983
|
const newAddress = `${PAGES_KINDS.document}:${signed.pubkey}:${dTag}`;
|
|
33984
|
+
await saveDocMetadata(newAddress, {
|
|
33985
|
+
viewKey: viewKeyHex,
|
|
33986
|
+
...editKeyHex ? { editKey: editKeyHex } : {}
|
|
33987
|
+
});
|
|
33988
|
+
if (editKeyHex && ownerPubkey === await signer.getPublicKey()) {
|
|
33989
|
+
await saveDocMetadata(params.address, { sharedAs: newAddress });
|
|
33990
|
+
}
|
|
33019
33991
|
return generateShareLink(newAddress, viewKeyHex, editKeyHex);
|
|
33020
33992
|
}
|
|
33021
33993
|
async function fetchSharedList() {
|
|
33994
|
+
const metadata = await fetchAllDocMetadata();
|
|
33995
|
+
const entries = [];
|
|
33996
|
+
for (const [address, meta] of metadata) {
|
|
33997
|
+
if (typeof meta.viewKey !== "string" || !meta.viewKey) continue;
|
|
33998
|
+
entries.push(
|
|
33999
|
+
typeof meta.editKey === "string" && meta.editKey ? [address, meta.viewKey, meta.editKey] : [address, meta.viewKey]
|
|
34000
|
+
);
|
|
34001
|
+
}
|
|
34002
|
+
for (const entry of await fetchLegacySharedList()) {
|
|
34003
|
+
const [address, viewKey, editKey] = entry;
|
|
34004
|
+
if (metadata.get(address)?.viewKey) continue;
|
|
34005
|
+
entries.push(entry);
|
|
34006
|
+
try {
|
|
34007
|
+
await saveDocMetadata(address, { viewKey, ...editKey ? { editKey } : {} });
|
|
34008
|
+
} catch {
|
|
34009
|
+
}
|
|
34010
|
+
}
|
|
34011
|
+
return entries;
|
|
34012
|
+
}
|
|
34013
|
+
async function fetchLegacySharedList() {
|
|
33022
34014
|
const signer = await signerManager.getSigner();
|
|
33023
34015
|
const pubkey = await signer.getPublicKey();
|
|
33024
34016
|
const events = await nostrRuntime.querySync(RELAYS(), {
|
|
@@ -33034,30 +34026,19 @@ async function fetchSharedList() {
|
|
|
33034
34026
|
}
|
|
33035
34027
|
return [];
|
|
33036
34028
|
}
|
|
33037
|
-
async function saveSharedList(entries) {
|
|
33038
|
-
const signer = await signerManager.getSigner();
|
|
33039
|
-
const content = await nip44SelfEncrypt(signer, JSON.stringify(entries));
|
|
33040
|
-
const signed = await signer.signEvent({
|
|
33041
|
-
kind: PAGES_KINDS.sharedPagesList,
|
|
33042
|
-
created_at: Math.floor(Date.now() / 1e3),
|
|
33043
|
-
tags: [],
|
|
33044
|
-
content
|
|
33045
|
-
});
|
|
33046
|
-
await nostrRuntime.publish(RELAYS(), signed);
|
|
33047
|
-
}
|
|
33048
34029
|
async function addSharedPage(entry) {
|
|
33049
|
-
const
|
|
33050
|
-
|
|
33051
|
-
next.push(entry);
|
|
33052
|
-
await saveSharedList(next);
|
|
33053
|
-
return next;
|
|
34030
|
+
const [address, viewKey, editKey] = entry;
|
|
34031
|
+
await saveDocMetadata(address, { viewKey, ...editKey ? { editKey } : {} });
|
|
33054
34032
|
}
|
|
33055
34033
|
async function fetchSharedPages() {
|
|
34034
|
+
const signer = await signerManager.getSigner();
|
|
34035
|
+
const userPubkey = await signer.getPublicKey();
|
|
33056
34036
|
const entries = await fetchSharedList();
|
|
33057
34037
|
const out = [];
|
|
33058
34038
|
for (const [address, viewKey, editKey] of entries) {
|
|
33059
34039
|
const [, pubkey, dTag] = address.split(":");
|
|
33060
34040
|
if (!pubkey || !dTag) continue;
|
|
34041
|
+
if (pubkey === userPubkey) continue;
|
|
33061
34042
|
const doc = await fetchPage(pubkey, dTag, viewKey);
|
|
33062
34043
|
if (!doc) continue;
|
|
33063
34044
|
out.push({
|
|
@@ -33074,15 +34055,19 @@ async function fetchSharedPages() {
|
|
|
33074
34055
|
}
|
|
33075
34056
|
return out;
|
|
33076
34057
|
}
|
|
33077
|
-
|
|
33078
|
-
const
|
|
33079
|
-
if (
|
|
34058
|
+
function parseMetadataJson(json) {
|
|
34059
|
+
const parsed = JSON.parse(json);
|
|
34060
|
+
if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
|
|
34061
|
+
return parsed;
|
|
34062
|
+
}
|
|
34063
|
+
return void 0;
|
|
34064
|
+
}
|
|
34065
|
+
async function fetchAllDocMetadata() {
|
|
33080
34066
|
const signer = await signerManager.getSigner();
|
|
33081
34067
|
const pubkey = await signer.getPublicKey();
|
|
33082
34068
|
const events = await nostrRuntime.querySync(RELAYS(), {
|
|
33083
34069
|
kinds: [PAGES_KINDS.docMetadata],
|
|
33084
|
-
authors: [pubkey]
|
|
33085
|
-
"#d": addresses
|
|
34070
|
+
authors: [pubkey]
|
|
33086
34071
|
});
|
|
33087
34072
|
const newest = /* @__PURE__ */ new Map();
|
|
33088
34073
|
for (const ev of events) {
|
|
@@ -33090,18 +34075,37 @@ async function fetchDocTags(addresses) {
|
|
|
33090
34075
|
const prev = newest.get(addr);
|
|
33091
34076
|
if (!prev || ev.created_at > prev.created_at) newest.set(addr, ev);
|
|
33092
34077
|
}
|
|
34078
|
+
const result = /* @__PURE__ */ new Map();
|
|
33093
34079
|
for (const [addr, ev] of newest) {
|
|
33094
34080
|
try {
|
|
33095
|
-
const
|
|
33096
|
-
if (
|
|
34081
|
+
const meta = parseMetadataJson(await nip44SelfDecrypt(signer, ev.content));
|
|
34082
|
+
if (meta) result.set(addr, meta);
|
|
33097
34083
|
} catch {
|
|
33098
34084
|
}
|
|
33099
34085
|
}
|
|
33100
34086
|
return result;
|
|
33101
34087
|
}
|
|
33102
|
-
async function
|
|
34088
|
+
async function fetchDocMetadata(address) {
|
|
33103
34089
|
const signer = await signerManager.getSigner();
|
|
33104
|
-
const
|
|
34090
|
+
const pubkey = await signer.getPublicKey();
|
|
34091
|
+
const events = await nostrRuntime.querySync(RELAYS(), {
|
|
34092
|
+
kinds: [PAGES_KINDS.docMetadata],
|
|
34093
|
+
authors: [pubkey],
|
|
34094
|
+
"#d": [address]
|
|
34095
|
+
});
|
|
34096
|
+
if (events.length === 0) return void 0;
|
|
34097
|
+
const newest = events.reduce((a, b) => b.created_at > a.created_at ? b : a);
|
|
34098
|
+
try {
|
|
34099
|
+
return parseMetadataJson(await nip44SelfDecrypt(signer, newest.content));
|
|
34100
|
+
} catch {
|
|
34101
|
+
return void 0;
|
|
34102
|
+
}
|
|
34103
|
+
}
|
|
34104
|
+
async function saveDocMetadata(address, patch) {
|
|
34105
|
+
const existing = await fetchDocMetadata(address) ?? {};
|
|
34106
|
+
const merged = { ...existing, ...patch };
|
|
34107
|
+
const signer = await signerManager.getSigner();
|
|
34108
|
+
const content = await nip44SelfEncrypt(signer, JSON.stringify(merged));
|
|
33105
34109
|
const signed = await signer.signEvent({
|
|
33106
34110
|
kind: PAGES_KINDS.docMetadata,
|
|
33107
34111
|
created_at: Math.floor(Date.now() / 1e3),
|
|
@@ -33109,6 +34113,41 @@ async function setDocTags(address, tags) {
|
|
|
33109
34113
|
content
|
|
33110
34114
|
});
|
|
33111
34115
|
await nostrRuntime.publish(RELAYS(), signed);
|
|
34116
|
+
return merged;
|
|
34117
|
+
}
|
|
34118
|
+
async function fetchDocTags(addresses) {
|
|
34119
|
+
const result = /* @__PURE__ */ new Map();
|
|
34120
|
+
if (addresses.length === 0) return result;
|
|
34121
|
+
const signer = await signerManager.getSigner();
|
|
34122
|
+
const pubkey = await signer.getPublicKey();
|
|
34123
|
+
const events = await nostrRuntime.querySync(RELAYS(), {
|
|
34124
|
+
kinds: [PAGES_KINDS.docMetadata],
|
|
34125
|
+
authors: [pubkey],
|
|
34126
|
+
"#d": addresses
|
|
34127
|
+
});
|
|
34128
|
+
const newest = /* @__PURE__ */ new Map();
|
|
34129
|
+
for (const ev of events) {
|
|
34130
|
+
const addr = ev.tags.find((t) => t[0] === "d")?.[1] ?? "";
|
|
34131
|
+
const prev = newest.get(addr);
|
|
34132
|
+
if (!prev || ev.created_at > prev.created_at) newest.set(addr, ev);
|
|
34133
|
+
}
|
|
34134
|
+
for (const [addr, ev] of newest) {
|
|
34135
|
+
try {
|
|
34136
|
+
const meta = parseMetadataJson(await nip44SelfDecrypt(signer, ev.content));
|
|
34137
|
+
if (meta && Array.isArray(meta.tags)) result.set(addr, meta.tags);
|
|
34138
|
+
} catch {
|
|
34139
|
+
}
|
|
34140
|
+
}
|
|
34141
|
+
return result;
|
|
34142
|
+
}
|
|
34143
|
+
async function setDocTags(address, tags) {
|
|
34144
|
+
await saveDocMetadata(address, { tags });
|
|
34145
|
+
}
|
|
34146
|
+
async function setDocTitle(address, title) {
|
|
34147
|
+
await saveDocMetadata(address, { title: title || void 0 });
|
|
34148
|
+
}
|
|
34149
|
+
async function setDocSharedAs(address, sharedAs) {
|
|
34150
|
+
await saveDocMetadata(address, { sharedAs });
|
|
33112
34151
|
}
|
|
33113
34152
|
function extractTitle(markdown) {
|
|
33114
34153
|
const firstLine = markdown.trim().split("\n")[0] ?? "";
|
|
@@ -33123,11 +34162,82 @@ function randomId(length) {
|
|
|
33123
34162
|
return result;
|
|
33124
34163
|
}
|
|
33125
34164
|
|
|
34165
|
+
// ../agent/src/services/pages/comments.ts
|
|
34166
|
+
var comments_exports = {};
|
|
34167
|
+
__export(comments_exports, {
|
|
34168
|
+
fetchPageComments: () => fetchPageComments,
|
|
34169
|
+
parsePageComment: () => parsePageComment,
|
|
34170
|
+
publishPageComment: () => publishPageComment
|
|
34171
|
+
});
|
|
34172
|
+
var RELAYS2 = () => relayManager.getRelaysForModule("pages");
|
|
34173
|
+
async function publishPageComment(draft, viewKey, docAddress, docEventId) {
|
|
34174
|
+
const signer = await signerManager.getSigner();
|
|
34175
|
+
const innerTags = [
|
|
34176
|
+
["content", draft.content],
|
|
34177
|
+
["type", draft.type]
|
|
34178
|
+
];
|
|
34179
|
+
if (draft.quote !== void 0) innerTags.push(["quote", draft.quote]);
|
|
34180
|
+
if (draft.context !== void 0) {
|
|
34181
|
+
innerTags.push(["context", draft.context.prefix, draft.context.suffix]);
|
|
34182
|
+
}
|
|
34183
|
+
const docOwnerPubkey = docAddress.split(":")[1];
|
|
34184
|
+
const event = {
|
|
34185
|
+
kind: PAGES_KINDS.comment,
|
|
34186
|
+
created_at: Math.floor(Date.now() / 1e3),
|
|
34187
|
+
content: await encryptWithViewKey2(viewKey, JSON.stringify(innerTags)),
|
|
34188
|
+
tags: [
|
|
34189
|
+
["a", docAddress],
|
|
34190
|
+
["e", docEventId],
|
|
34191
|
+
["p", docOwnerPubkey]
|
|
34192
|
+
]
|
|
34193
|
+
};
|
|
34194
|
+
const signed = await signer.signEvent(event);
|
|
34195
|
+
await nostrRuntime.publish(RELAYS2(), signed);
|
|
34196
|
+
return signed;
|
|
34197
|
+
}
|
|
34198
|
+
async function parsePageComment(event, viewKey) {
|
|
34199
|
+
try {
|
|
34200
|
+
const inner = JSON.parse(await decryptWithViewKey2(viewKey, event.content));
|
|
34201
|
+
if (!Array.isArray(inner)) return void 0;
|
|
34202
|
+
const rows = inner;
|
|
34203
|
+
const find = (name) => rows.find((r) => Array.isArray(r) && r[0] === name);
|
|
34204
|
+
const content = find("content")?.[1];
|
|
34205
|
+
if (typeof content !== "string") return void 0;
|
|
34206
|
+
const type = find("type")?.[1] === "suggestion" ? "suggestion" : "comment";
|
|
34207
|
+
const quote = find("quote")?.[1];
|
|
34208
|
+
const contextRow = find("context");
|
|
34209
|
+
return {
|
|
34210
|
+
id: event.id,
|
|
34211
|
+
author: event.pubkey,
|
|
34212
|
+
createdAt: event.created_at,
|
|
34213
|
+
content,
|
|
34214
|
+
type,
|
|
34215
|
+
...quote !== void 0 ? { quote } : {},
|
|
34216
|
+
...contextRow ? { context: { prefix: contextRow[1] ?? "", suffix: contextRow[2] ?? "" } } : {}
|
|
34217
|
+
};
|
|
34218
|
+
} catch {
|
|
34219
|
+
return void 0;
|
|
34220
|
+
}
|
|
34221
|
+
}
|
|
34222
|
+
async function fetchPageComments(docAddress, viewKey) {
|
|
34223
|
+
const events = await nostrRuntime.querySync(RELAYS2(), {
|
|
34224
|
+
kinds: [PAGES_KINDS.comment],
|
|
34225
|
+
"#a": [docAddress]
|
|
34226
|
+
});
|
|
34227
|
+
const out = [];
|
|
34228
|
+
for (const event of events) {
|
|
34229
|
+
const comment = await parsePageComment(event, viewKey);
|
|
34230
|
+
if (comment) out.push(comment);
|
|
34231
|
+
}
|
|
34232
|
+
return out.sort((a, b) => a.createdAt - b.createdAt);
|
|
34233
|
+
}
|
|
34234
|
+
|
|
33126
34235
|
// ../agent/src/services/drive/service.ts
|
|
33127
34236
|
var service_exports4 = {};
|
|
33128
34237
|
__export(service_exports4, {
|
|
33129
34238
|
deleteFile: () => deleteFile,
|
|
33130
34239
|
downloadFile: () => downloadFile,
|
|
34240
|
+
downloadPreview: () => downloadPreview,
|
|
33131
34241
|
extractFolders: () => extractFolders,
|
|
33132
34242
|
fetchBlossomServers: () => fetchBlossomServers,
|
|
33133
34243
|
fetchFileIndex: () => fetchFileIndex,
|
|
@@ -33143,8 +34253,8 @@ var DRIVE_KINDS = {
|
|
|
33143
34253
|
fileMetadata: 34578
|
|
33144
34254
|
};
|
|
33145
34255
|
var DEFAULT_BLOSSOM_SERVERS = [
|
|
33146
|
-
"https://blossom.primal.net",
|
|
33147
34256
|
"https://nostr.download",
|
|
34257
|
+
"https://blossom.primal.net",
|
|
33148
34258
|
"https://blossom.oxtr.dev"
|
|
33149
34259
|
];
|
|
33150
34260
|
|
|
@@ -33159,6 +34269,21 @@ async function uploadFile(params) {
|
|
|
33159
34269
|
const authEvent = await createBlossomAuthEvent("upload", await sha256Hex2(encryptedBytes), signer);
|
|
33160
34270
|
const blossom = new BlossomClient(server);
|
|
33161
34271
|
const result = await blossom.upload(encryptedBytes, authEvent, params.file.type);
|
|
34272
|
+
let previewHash;
|
|
34273
|
+
if (params.preview) {
|
|
34274
|
+
try {
|
|
34275
|
+
const encryptedPreview = new TextEncoder().encode(
|
|
34276
|
+
await encryptFileWithExistingKey(params.preview, privateKeyHex)
|
|
34277
|
+
);
|
|
34278
|
+
const previewAuth = await createBlossomAuthEvent(
|
|
34279
|
+
"upload",
|
|
34280
|
+
await sha256Hex2(encryptedPreview),
|
|
34281
|
+
signer
|
|
34282
|
+
);
|
|
34283
|
+
previewHash = (await blossom.upload(encryptedPreview, previewAuth, "image/webp")).sha256;
|
|
34284
|
+
} catch {
|
|
34285
|
+
}
|
|
34286
|
+
}
|
|
33162
34287
|
const metadata = {
|
|
33163
34288
|
name: params.file.name,
|
|
33164
34289
|
hash: result.sha256,
|
|
@@ -33167,11 +34292,26 @@ async function uploadFile(params) {
|
|
|
33167
34292
|
folder: params.folder ?? "/",
|
|
33168
34293
|
uploadedAt: Date.now(),
|
|
33169
34294
|
server,
|
|
33170
|
-
|
|
34295
|
+
...previewHash ? { previewHash } : {},
|
|
34296
|
+
encryptionKey: privateKeyHex,
|
|
34297
|
+
encryptionAlgorithm: "aes-gcm"
|
|
33171
34298
|
};
|
|
33172
34299
|
await saveFileMetadata(metadata);
|
|
33173
34300
|
return metadata;
|
|
33174
34301
|
}
|
|
34302
|
+
async function downloadPreview(metadata) {
|
|
34303
|
+
if (!metadata.previewHash) return null;
|
|
34304
|
+
const blossom = new BlossomClient(metadata.server);
|
|
34305
|
+
let authEvent;
|
|
34306
|
+
try {
|
|
34307
|
+
const signer = await signerManager.getSigner();
|
|
34308
|
+
authEvent = await createBlossomAuthEvent("get", metadata.previewHash, signer);
|
|
34309
|
+
} catch {
|
|
34310
|
+
}
|
|
34311
|
+
const encryptedBytes = await blossom.download(metadata.previewHash, authEvent);
|
|
34312
|
+
const ciphertext = new TextDecoder().decode(encryptedBytes);
|
|
34313
|
+
return decryptFileWithKey(ciphertext, metadata.encryptionKey);
|
|
34314
|
+
}
|
|
33175
34315
|
async function downloadFile(metadata) {
|
|
33176
34316
|
const blossom = new BlossomClient(metadata.server);
|
|
33177
34317
|
let authEvent;
|
|
@@ -33215,7 +34355,11 @@ async function fetchFileIndex() {
|
|
|
33215
34355
|
}
|
|
33216
34356
|
async function saveFileMetadata(metadata) {
|
|
33217
34357
|
const signer = await signerManager.getSigner();
|
|
33218
|
-
const
|
|
34358
|
+
const full = {
|
|
34359
|
+
...metadata,
|
|
34360
|
+
encryptionAlgorithm: metadata.encryptionAlgorithm ?? "aes-gcm"
|
|
34361
|
+
};
|
|
34362
|
+
const encrypted = await nip44SelfEncrypt(signer, JSON.stringify(full));
|
|
33219
34363
|
const event = {
|
|
33220
34364
|
kind: DRIVE_KINDS.fileMetadata,
|
|
33221
34365
|
created_at: Math.floor(Date.now() / 1e3),
|
|
@@ -33311,6 +34455,28 @@ __export(service_exports5, {
|
|
|
33311
34455
|
submitPollResponse: () => submitPollResponse
|
|
33312
34456
|
});
|
|
33313
34457
|
|
|
34458
|
+
// ../agent/src/services/polls/pow.ts
|
|
34459
|
+
function minePollEvent(unsigned, difficulty) {
|
|
34460
|
+
const event = unsigned;
|
|
34461
|
+
const nonceTag = ["nonce", "0", difficulty.toString()];
|
|
34462
|
+
event.tags.push(nonceTag);
|
|
34463
|
+
event.tags.push(["W", difficulty.toString()]);
|
|
34464
|
+
let count = 0;
|
|
34465
|
+
for (; ; ) {
|
|
34466
|
+
const now2 = Math.floor(Date.now() / 1e3);
|
|
34467
|
+
if (now2 !== event.created_at) {
|
|
34468
|
+
count = 0;
|
|
34469
|
+
event.created_at = now2;
|
|
34470
|
+
}
|
|
34471
|
+
nonceTag[1] = (++count).toString();
|
|
34472
|
+
event.id = getEventHash(event);
|
|
34473
|
+
if (nip13_exports.getPow(event.id) >= difficulty) return event;
|
|
34474
|
+
}
|
|
34475
|
+
}
|
|
34476
|
+
function hasValidPow(event, difficulty) {
|
|
34477
|
+
return nip13_exports.getPow(event.id) >= difficulty;
|
|
34478
|
+
}
|
|
34479
|
+
|
|
33314
34480
|
// ../agent/src/services/polls/types.ts
|
|
33315
34481
|
var POLLS_KINDS = {
|
|
33316
34482
|
poll: 1068,
|
|
@@ -33365,7 +34531,7 @@ async function createPoll(draft) {
|
|
|
33365
34531
|
function withModuleRelays(pollRelays) {
|
|
33366
34532
|
return Array.from(/* @__PURE__ */ new Set([...pollRelays ?? [], ...relayManager.getRelaysForModule("polls")]));
|
|
33367
34533
|
}
|
|
33368
|
-
async function submitPollResponse(pollId, pollAuthor, selectedOptionIds, pollRelays) {
|
|
34534
|
+
async function submitPollResponse(pollId, pollAuthor, selectedOptionIds, pollRelays, powDifficulty) {
|
|
33369
34535
|
const signer = await signerManager.getSigner();
|
|
33370
34536
|
const relays = withModuleRelays(pollRelays);
|
|
33371
34537
|
const tags = [
|
|
@@ -33375,12 +34541,22 @@ async function submitPollResponse(pollId, pollAuthor, selectedOptionIds, pollRel
|
|
|
33375
34541
|
for (const optionId of selectedOptionIds) {
|
|
33376
34542
|
tags.push(["response", optionId]);
|
|
33377
34543
|
}
|
|
33378
|
-
|
|
34544
|
+
let event = {
|
|
33379
34545
|
kind: POLLS_KINDS.response,
|
|
33380
34546
|
created_at: Math.floor(Date.now() / 1e3),
|
|
33381
34547
|
tags,
|
|
33382
34548
|
content: ""
|
|
33383
34549
|
};
|
|
34550
|
+
if (powDifficulty && powDifficulty > 0) {
|
|
34551
|
+
const unsigned = { ...event, pubkey: await signer.getPublicKey() };
|
|
34552
|
+
const mined = minePollEvent(unsigned, powDifficulty);
|
|
34553
|
+
event = {
|
|
34554
|
+
kind: mined.kind,
|
|
34555
|
+
created_at: mined.created_at,
|
|
34556
|
+
tags: mined.tags,
|
|
34557
|
+
content: mined.content
|
|
34558
|
+
};
|
|
34559
|
+
}
|
|
33384
34560
|
const signed = await signer.signEvent(event);
|
|
33385
34561
|
await nostrRuntime.publish(relays, signed);
|
|
33386
34562
|
}
|
|
@@ -33428,11 +34604,12 @@ async function fetchPoll(eventId) {
|
|
|
33428
34604
|
function resultRelays(poll) {
|
|
33429
34605
|
return withModuleRelays(poll.relays);
|
|
33430
34606
|
}
|
|
33431
|
-
function latestResponsesByVoter(events, deleted) {
|
|
34607
|
+
function latestResponsesByVoter(events, deleted, powDifficulty = 0) {
|
|
33432
34608
|
const latest = /* @__PURE__ */ new Map();
|
|
33433
34609
|
for (const e of events) {
|
|
33434
34610
|
if (isPollDeleted(e, deleted)) continue;
|
|
33435
34611
|
if (!e.tags.some((t) => t[0] === "response")) continue;
|
|
34612
|
+
if (powDifficulty > 0 && !hasValidPow(e, powDifficulty)) continue;
|
|
33436
34613
|
const prev = latest.get(e.pubkey);
|
|
33437
34614
|
if (!prev || e.created_at > prev.created_at) latest.set(e.pubkey, e);
|
|
33438
34615
|
}
|
|
@@ -33450,11 +34627,13 @@ async function fetchPollResults(poll) {
|
|
|
33450
34627
|
const events = await nostrRuntime.querySync(relays, {
|
|
33451
34628
|
kinds: [POLLS_KINDS.response, POLLS_KINDS.responseLegacy],
|
|
33452
34629
|
"#e": [poll.id],
|
|
33453
|
-
...poll.endsAt ? { until: poll.endsAt } : {}
|
|
34630
|
+
...poll.endsAt ? { until: poll.endsAt } : {},
|
|
34631
|
+
// PoW polls: upstream queries votes by their ["W", difficulty] tag.
|
|
34632
|
+
...poll.powDifficulty ? { "#W": [String(poll.powDifficulty)] } : {}
|
|
33454
34633
|
});
|
|
33455
34634
|
const authors = Array.from(new Set(events.map((e) => e.pubkey)));
|
|
33456
34635
|
const deleted = await fetchDeletions3(relays, authors);
|
|
33457
|
-
return computeResults(latestResponsesByVoter(events, deleted));
|
|
34636
|
+
return computeResults(latestResponsesByVoter(events, deleted, poll.powDifficulty ?? 0));
|
|
33458
34637
|
}
|
|
33459
34638
|
async function fetchRecentPolls(limit = 20) {
|
|
33460
34639
|
const relays = relayManager.getRelaysForModule("polls");
|
|
@@ -33523,7 +34702,7 @@ function computeResults(responses) {
|
|
|
33523
34702
|
for (const [pubkey, selected] of responses) {
|
|
33524
34703
|
for (const optionId of selected) {
|
|
33525
34704
|
const existing = counts.get(optionId) ?? [];
|
|
33526
|
-
existing.push(pubkey);
|
|
34705
|
+
if (!existing.includes(pubkey)) existing.push(pubkey);
|
|
33527
34706
|
counts.set(optionId, existing);
|
|
33528
34707
|
}
|
|
33529
34708
|
}
|
|
@@ -33816,11 +34995,12 @@ function buildCalendarTools() {
|
|
|
33816
34995
|
server.registerTool(
|
|
33817
34996
|
"rsvp_event",
|
|
33818
34997
|
{
|
|
33819
|
-
description: "RSVP to a calendar event on your identity. Optionally suggest a new time (suggestedStart/suggestedEnd, unix seconds) and add a note (comment). Requires confirm:true.",
|
|
34998
|
+
description: "RSVP to a calendar event on your identity. Optionally suggest a new time (suggestedStart/suggestedEnd, unix seconds) and add a note (comment). For private events pass the event's viewKey (nsec) if known \u2014 otherwise it is looked up from your calendar lists. Requires confirm:true.",
|
|
33820
34999
|
inputSchema: {
|
|
33821
35000
|
eventCoordinate: external_exports.string(),
|
|
33822
35001
|
status: external_exports.enum(["accepted", "declined", "tentative"]),
|
|
33823
35002
|
isPrivate: external_exports.boolean().optional(),
|
|
35003
|
+
viewKey: external_exports.string().optional(),
|
|
33824
35004
|
suggestedStart: external_exports.number().optional(),
|
|
33825
35005
|
suggestedEnd: external_exports.number().optional(),
|
|
33826
35006
|
comment: external_exports.string().optional(),
|
|
@@ -33831,6 +35011,7 @@ function buildCalendarTools() {
|
|
|
33831
35011
|
eventCoordinate,
|
|
33832
35012
|
status,
|
|
33833
35013
|
isPrivate,
|
|
35014
|
+
viewKey,
|
|
33834
35015
|
suggestedStart,
|
|
33835
35016
|
suggestedEnd,
|
|
33836
35017
|
comment,
|
|
@@ -33838,16 +35019,13 @@ function buildCalendarTools() {
|
|
|
33838
35019
|
}) => {
|
|
33839
35020
|
const blocked = requireConfirm("rsvp_event", { confirm }, `sends "${status}" RSVP`);
|
|
33840
35021
|
if (blocked) return blocked;
|
|
33841
|
-
|
|
33842
|
-
if (
|
|
33843
|
-
await
|
|
33844
|
-
suggestedStart,
|
|
33845
|
-
suggestedEnd,
|
|
33846
|
-
comment
|
|
33847
|
-
});
|
|
33848
|
-
} else {
|
|
33849
|
-
await rsvp_exports.rsvpToEvent(eventCoordinate, status, Boolean(isPrivate));
|
|
35022
|
+
let key = viewKey;
|
|
35023
|
+
if (isPrivate && !key) {
|
|
35024
|
+
key = await service_exports2.lookupEventViewKey(eventCoordinate);
|
|
33850
35025
|
}
|
|
35026
|
+
const hasExtra = suggestedStart !== void 0 || suggestedEnd !== void 0 || comment !== void 0;
|
|
35027
|
+
const extra = hasExtra ? { suggestedStart, suggestedEnd, comment } : void 0;
|
|
35028
|
+
await rsvp_exports.rsvpToEvent(eventCoordinate, status, Boolean(isPrivate), extra, key);
|
|
33851
35029
|
return ok(`RSVP "${status}" sent.`);
|
|
33852
35030
|
}
|
|
33853
35031
|
);
|
|
@@ -33887,6 +35065,9 @@ function buildCalendarTools() {
|
|
|
33887
35065
|
rrule: args.rrule ?? existing.repeat.rrule ?? void 0,
|
|
33888
35066
|
startTzid: args.startTzid ?? existing.startTzid,
|
|
33889
35067
|
registrationFormRef: existing.registrationFormRef,
|
|
35068
|
+
registrationFormViewKey: existing.registrationFormViewKey,
|
|
35069
|
+
notificationPreference: existing.notificationPreference,
|
|
35070
|
+
viewKey: existing.viewKey,
|
|
33890
35071
|
existingId: existing.id
|
|
33891
35072
|
};
|
|
33892
35073
|
const event = existing.isPrivate ? await service_exports2.publishPrivateCalendarEvent(draft, existing.calendarId ?? "default") : await service_exports2.publishPublicCalendarEvent(draft);
|
|
@@ -33926,6 +35107,8 @@ function buildCalendarTools() {
|
|
|
33926
35107
|
rrule: existing.repeat.rrule ?? void 0,
|
|
33927
35108
|
startTzid: existing.startTzid,
|
|
33928
35109
|
registrationFormRef: formRef,
|
|
35110
|
+
notificationPreference: existing.notificationPreference,
|
|
35111
|
+
viewKey: existing.viewKey,
|
|
33929
35112
|
existingId: existing.id
|
|
33930
35113
|
};
|
|
33931
35114
|
const event = existing.isPrivate ? await service_exports2.publishPrivateCalendarEvent(draft, existing.calendarId ?? "default") : await service_exports2.publishPublicCalendarEvent(draft);
|
|
@@ -34208,8 +35391,13 @@ function normalizePubkeyList(values) {
|
|
|
34208
35391
|
return values.map((v) => typeof v === "string" ? normalizePubkey(v) : null).filter((p) => !!p);
|
|
34209
35392
|
}
|
|
34210
35393
|
var ANSWER_TYPES = new Set(Object.values(AnswerType));
|
|
35394
|
+
var LEGACY_TYPE_ALIASES = {
|
|
35395
|
+
multiChoiceGrid: "multipleChoiceGrid" /* multipleChoiceGrid */
|
|
35396
|
+
};
|
|
34211
35397
|
function coerceType(type) {
|
|
34212
|
-
|
|
35398
|
+
if (!type) return "shortText" /* shortText */;
|
|
35399
|
+
if (LEGACY_TYPE_ALIASES[type]) return LEGACY_TYPE_ALIASES[type];
|
|
35400
|
+
return ANSWER_TYPES.has(type) ? type : "shortText" /* shortText */;
|
|
34213
35401
|
}
|
|
34214
35402
|
function normalizeOptions(options) {
|
|
34215
35403
|
if (!options) return void 0;
|
|
@@ -34229,7 +35417,8 @@ function aiFieldsToFormFields(value) {
|
|
|
34229
35417
|
validation: f.validation,
|
|
34230
35418
|
gridRows: f.gridRows,
|
|
34231
35419
|
gridCols: f.gridCols,
|
|
34232
|
-
fileConfig: f.fileConfig
|
|
35420
|
+
fileConfig: f.fileConfig,
|
|
35421
|
+
maxStars: f.maxStars
|
|
34233
35422
|
}));
|
|
34234
35423
|
}
|
|
34235
35424
|
|
|
@@ -34253,6 +35442,7 @@ var fieldShape = external_exports.object({
|
|
|
34253
35442
|
}).optional(),
|
|
34254
35443
|
gridRows: external_exports.array(external_exports.string()).optional(),
|
|
34255
35444
|
gridCols: external_exports.array(external_exports.string()).optional(),
|
|
35445
|
+
maxStars: external_exports.number().optional(),
|
|
34256
35446
|
fileConfig: external_exports.object({
|
|
34257
35447
|
blossomServer: external_exports.string().optional(),
|
|
34258
35448
|
maxBytes: external_exports.number().optional(),
|
|
@@ -34351,7 +35541,13 @@ ${form.settings.description}`);
|
|
|
34351
35541
|
const signingKey = mine.find(
|
|
34352
35542
|
(f) => f.pubkey === formAuthorPubkey && f.id === formId
|
|
34353
35543
|
)?.signingKey;
|
|
34354
|
-
const
|
|
35544
|
+
const template = await service_exports.fetchForm(formAuthorPubkey, formId);
|
|
35545
|
+
const responses = await service_exports.fetchResponses(
|
|
35546
|
+
formAuthorPubkey,
|
|
35547
|
+
formId,
|
|
35548
|
+
signingKey,
|
|
35549
|
+
template?.relays
|
|
35550
|
+
);
|
|
34355
35551
|
const blocks = responses.map((r) => {
|
|
34356
35552
|
const when = new Date(r.createdAt * 1e3).toISOString();
|
|
34357
35553
|
const answers = r.responses.length ? r.responses.map((a) => `- ${a.fieldId}: ${a.answer}`).join("\n") : r.wasEncrypted ? "_(encrypted \u2014 you are not the form owner)_" : "_(no answers)_";
|
|
@@ -34466,24 +35662,32 @@ To let collaborators decrypt it, run \`share_form\` with their npubs.` : ""),
|
|
|
34466
35662
|
},
|
|
34467
35663
|
{
|
|
34468
35664
|
name: "share_form",
|
|
34469
|
-
description: "Share an encrypted form's view key with collaborators via NIP-59 gift-wrap so they can decrypt it. Requires confirm:true.",
|
|
35665
|
+
description: "Share an encrypted form's view key with collaborators via NIP-59 gift-wrap so they can decrypt it. Pubkeys in `editors` additionally receive the signing key (edit access). Requires confirm:true.",
|
|
34470
35666
|
inputSchema: {
|
|
34471
35667
|
formId: external_exports.string(),
|
|
34472
35668
|
formPubkey: external_exports.string(),
|
|
34473
35669
|
recipients: external_exports.array(external_exports.string()),
|
|
35670
|
+
editors: external_exports.array(external_exports.string()).optional(),
|
|
34474
35671
|
confirm: external_exports.boolean().optional()
|
|
34475
35672
|
},
|
|
34476
35673
|
write: true,
|
|
34477
|
-
handler: async ({ formId, formPubkey, recipients, confirm }) => {
|
|
35674
|
+
handler: async ({ formId, formPubkey, recipients, editors, confirm }) => {
|
|
34478
35675
|
const recipientHex = normalizePubkeyList(recipients);
|
|
34479
|
-
|
|
35676
|
+
const editorHex = normalizePubkeyList(editors ?? []);
|
|
35677
|
+
if (recipientHex.length === 0 && editorHex.length === 0)
|
|
35678
|
+
return fail("No valid recipients provided.", "BAD_INPUT");
|
|
34480
35679
|
const blocked = requireConfirm(
|
|
34481
35680
|
"share_form",
|
|
34482
35681
|
{ confirm },
|
|
34483
|
-
`gift-wraps the
|
|
35682
|
+
`gift-wraps the access keys of form ${formId} to ${recipientHex.length + editorHex.length} recipient(s)`
|
|
34484
35683
|
);
|
|
34485
35684
|
if (blocked) return blocked;
|
|
34486
|
-
const result = await service_exports.shareForm({
|
|
35685
|
+
const result = await service_exports.shareForm({
|
|
35686
|
+
formId,
|
|
35687
|
+
formPubkey,
|
|
35688
|
+
recipients: recipientHex,
|
|
35689
|
+
editors: editorHex
|
|
35690
|
+
});
|
|
34487
35691
|
const failedNote = result.failed.length ? ` (${result.failed.length} failed)` : "";
|
|
34488
35692
|
return ok(`Shared view key with ${result.published} recipient(s)${failedNote}.`, {
|
|
34489
35693
|
published: result.published,
|
|
@@ -34527,6 +35731,7 @@ To let collaborators decrypt it, run \`share_form\` with their npubs.` : ""),
|
|
|
34527
35731
|
`publicly submits ${answers.length} answer(s) to form ${formId}`
|
|
34528
35732
|
);
|
|
34529
35733
|
if (blocked) return blocked;
|
|
35734
|
+
const template = await service_exports.fetchForm(formAuthorPubkey, formId);
|
|
34530
35735
|
await service_exports.submitResponse(
|
|
34531
35736
|
formAuthorPubkey,
|
|
34532
35737
|
formId,
|
|
@@ -34535,7 +35740,9 @@ To let collaborators decrypt it, run \`share_form\` with their npubs.` : ""),
|
|
|
34535
35740
|
answer: a.answer,
|
|
34536
35741
|
metadata: a.metadata
|
|
34537
35742
|
})),
|
|
34538
|
-
Boolean(encrypt7)
|
|
35743
|
+
Boolean(encrypt7),
|
|
35744
|
+
void 0,
|
|
35745
|
+
template?.relays
|
|
34539
35746
|
);
|
|
34540
35747
|
return ok(`Submitted ${answers.length} answer(s) to form ${formId}.`);
|
|
34541
35748
|
}
|
|
@@ -34590,7 +35797,7 @@ function buildPagesTools() {
|
|
|
34590
35797
|
server.registerTool(
|
|
34591
35798
|
"list_shared_pages",
|
|
34592
35799
|
{
|
|
34593
|
-
description: "List documents others have shared with you (kind-
|
|
35800
|
+
description: "List documents others have shared with you (kind-34579 doc-metadata entries carrying a viewKey).",
|
|
34594
35801
|
inputSchema: {}
|
|
34595
35802
|
},
|
|
34596
35803
|
async () => {
|
|
@@ -34615,6 +35822,25 @@ function buildPagesTools() {
|
|
|
34615
35822
|
return ok("Tags fetched.", { address, tags: map.get(address) ?? [] });
|
|
34616
35823
|
}
|
|
34617
35824
|
);
|
|
35825
|
+
server.registerTool(
|
|
35826
|
+
"list_page_comments",
|
|
35827
|
+
{
|
|
35828
|
+
description: "List the inline comments/suggestions on a shared document (kind 1494; needs the doc's viewKey).",
|
|
35829
|
+
inputSchema: { address: external_exports.string(), viewKey: external_exports.string() }
|
|
35830
|
+
},
|
|
35831
|
+
async ({ address, viewKey }) => {
|
|
35832
|
+
const comments = await comments_exports.fetchPageComments(address, viewKey);
|
|
35833
|
+
return ok(`${comments.length} comment(s).`, {
|
|
35834
|
+
comments: comments.map((c) => ({
|
|
35835
|
+
author: c.author,
|
|
35836
|
+
createdAt: c.createdAt,
|
|
35837
|
+
type: c.type,
|
|
35838
|
+
content: c.content,
|
|
35839
|
+
quote: c.quote
|
|
35840
|
+
}))
|
|
35841
|
+
});
|
|
35842
|
+
}
|
|
35843
|
+
);
|
|
34618
35844
|
server.registerTool(
|
|
34619
35845
|
"create_page",
|
|
34620
35846
|
{
|
|
@@ -34721,6 +35947,44 @@ function buildPagesTools() {
|
|
|
34721
35947
|
});
|
|
34722
35948
|
}
|
|
34723
35949
|
);
|
|
35950
|
+
server.registerTool(
|
|
35951
|
+
"add_page_comment",
|
|
35952
|
+
{
|
|
35953
|
+
description: "Add an inline comment or suggestion to a shared document (kind 1494). Requires confirm:true.",
|
|
35954
|
+
inputSchema: {
|
|
35955
|
+
address: external_exports.string(),
|
|
35956
|
+
eventId: external_exports.string(),
|
|
35957
|
+
viewKey: external_exports.string(),
|
|
35958
|
+
content: external_exports.string(),
|
|
35959
|
+
type: external_exports.enum(["comment", "suggestion"]).optional(),
|
|
35960
|
+
quote: external_exports.string().optional(),
|
|
35961
|
+
confirm: external_exports.boolean().optional()
|
|
35962
|
+
}
|
|
35963
|
+
},
|
|
35964
|
+
async ({
|
|
35965
|
+
address,
|
|
35966
|
+
eventId,
|
|
35967
|
+
viewKey,
|
|
35968
|
+
content,
|
|
35969
|
+
type,
|
|
35970
|
+
quote,
|
|
35971
|
+
confirm
|
|
35972
|
+
}) => {
|
|
35973
|
+
const blocked = requireConfirm(
|
|
35974
|
+
"add_page_comment",
|
|
35975
|
+
{ confirm },
|
|
35976
|
+
`publishes a comment on ${address}`
|
|
35977
|
+
);
|
|
35978
|
+
if (blocked) return blocked;
|
|
35979
|
+
const event = await comments_exports.publishPageComment(
|
|
35980
|
+
{ content, type: type ?? "comment", ...quote !== void 0 ? { quote } : {} },
|
|
35981
|
+
viewKey,
|
|
35982
|
+
address,
|
|
35983
|
+
eventId
|
|
35984
|
+
);
|
|
35985
|
+
return ok("Comment published.", { id: event.id });
|
|
35986
|
+
}
|
|
35987
|
+
);
|
|
34724
35988
|
return tools;
|
|
34725
35989
|
}
|
|
34726
35990
|
|
|
@@ -34857,7 +36121,13 @@ function buildPollsTools() {
|
|
|
34857
36121
|
if (blocked) return blocked;
|
|
34858
36122
|
const poll = await service_exports5.fetchPoll(pollEventId);
|
|
34859
36123
|
if (!poll) return fail("Poll not found.");
|
|
34860
|
-
await service_exports5.submitPollResponse(
|
|
36124
|
+
await service_exports5.submitPollResponse(
|
|
36125
|
+
pollEventId,
|
|
36126
|
+
poll.pubkey,
|
|
36127
|
+
optionIds,
|
|
36128
|
+
poll.relays,
|
|
36129
|
+
poll.powDifficulty
|
|
36130
|
+
);
|
|
34861
36131
|
return ok(`Voted on poll ${pollEventId}.`);
|
|
34862
36132
|
}
|
|
34863
36133
|
);
|
|
@@ -45086,7 +46356,7 @@ function adapt(r) {
|
|
|
45086
46356
|
};
|
|
45087
46357
|
}
|
|
45088
46358
|
function buildServer(ctx) {
|
|
45089
|
-
const server = new McpServer({ name: "formstr", version: "0.1.
|
|
46359
|
+
const server = new McpServer({ name: "formstr", version: "0.1.0" });
|
|
45090
46360
|
for (const t of toolRegistry) {
|
|
45091
46361
|
if (t.write && !ctx.allowWrites) continue;
|
|
45092
46362
|
server.registerTool(
|
|
@@ -45106,7 +46376,17 @@ async function startStdio(ctx) {
|
|
|
45106
46376
|
// src/index.ts
|
|
45107
46377
|
async function runServer(cli) {
|
|
45108
46378
|
const cfg = resolveConfig(cli, process.env);
|
|
45109
|
-
const
|
|
46379
|
+
const deps = process.stdin.isTTY ? {
|
|
46380
|
+
promptPassphrase: async (question) => {
|
|
46381
|
+
const io = createTerminalIo();
|
|
46382
|
+
try {
|
|
46383
|
+
return await io.promptPassphrase(question);
|
|
46384
|
+
} finally {
|
|
46385
|
+
io.close();
|
|
46386
|
+
}
|
|
46387
|
+
}
|
|
46388
|
+
} : {};
|
|
46389
|
+
const account = await bootstrap({ account: cfg.account, relays: cfg.relays }, deps);
|
|
45110
46390
|
console.error(
|
|
45111
46391
|
`formstr-mcp: signed in as ${account.npub} (${account.method}), writes ${cfg.allowWrites ? "ENABLED" : "disabled"}`
|
|
45112
46392
|
);
|
|
@@ -45115,13 +46395,14 @@ async function runServer(cli) {
|
|
|
45115
46395
|
}
|
|
45116
46396
|
async function runLogin(cli) {
|
|
45117
46397
|
const io = createTerminalIo();
|
|
46398
|
+
const pool = createPatchedPool();
|
|
45118
46399
|
try {
|
|
45119
46400
|
const account = await doLogin({
|
|
45120
46401
|
signer: await buildMcpSigner(),
|
|
45121
46402
|
prompt: io.prompt,
|
|
45122
46403
|
promptPassphrase: io.promptPassphrase,
|
|
45123
46404
|
printQr,
|
|
45124
|
-
pool
|
|
46405
|
+
pool,
|
|
45125
46406
|
relays: cli.relays
|
|
45126
46407
|
});
|
|
45127
46408
|
console.error(
|
|
@@ -45129,6 +46410,10 @@ async function runLogin(cli) {
|
|
|
45129
46410
|
);
|
|
45130
46411
|
} finally {
|
|
45131
46412
|
io.close();
|
|
46413
|
+
try {
|
|
46414
|
+
pool.destroy();
|
|
46415
|
+
} catch {
|
|
46416
|
+
}
|
|
45132
46417
|
}
|
|
45133
46418
|
}
|
|
45134
46419
|
async function main() {
|
|
@@ -45136,18 +46421,18 @@ async function main() {
|
|
|
45136
46421
|
switch (cli.command) {
|
|
45137
46422
|
case "login":
|
|
45138
46423
|
await runLogin(cli);
|
|
45139
|
-
return;
|
|
46424
|
+
return cli.command;
|
|
45140
46425
|
case "logout": {
|
|
45141
46426
|
await doLogout(await buildMcpSigner(), cli.account);
|
|
45142
46427
|
console.error("formstr-mcp: signed out.");
|
|
45143
|
-
return;
|
|
46428
|
+
return cli.command;
|
|
45144
46429
|
}
|
|
45145
46430
|
case "whoami": {
|
|
45146
46431
|
const who = whoami(await buildMcpSigner());
|
|
45147
46432
|
console.error(
|
|
45148
46433
|
who ? `formstr-mcp: ${who.npub} (${who.method})` : "formstr-mcp: not signed in."
|
|
45149
46434
|
);
|
|
45150
|
-
return;
|
|
46435
|
+
return cli.command;
|
|
45151
46436
|
}
|
|
45152
46437
|
case "accounts": {
|
|
45153
46438
|
const signer = await buildMcpSigner();
|
|
@@ -45155,26 +46440,30 @@ async function main() {
|
|
|
45155
46440
|
const accounts = listAccounts(signer);
|
|
45156
46441
|
if (accounts.length === 0) {
|
|
45157
46442
|
console.error("formstr-mcp: no accounts. Run `formstr-mcp login`.");
|
|
45158
|
-
return;
|
|
46443
|
+
return cli.command;
|
|
45159
46444
|
}
|
|
45160
46445
|
for (const a of accounts) {
|
|
45161
46446
|
const marker = active && a.pubkey === active.pubkey ? "* " : " ";
|
|
45162
46447
|
console.error(`${marker}${a.npub} (${a.method})`);
|
|
45163
46448
|
}
|
|
45164
|
-
return;
|
|
46449
|
+
return cli.command;
|
|
45165
46450
|
}
|
|
45166
46451
|
case "run":
|
|
45167
46452
|
default:
|
|
45168
46453
|
await runServer(cli);
|
|
46454
|
+
return "run";
|
|
45169
46455
|
}
|
|
45170
46456
|
}
|
|
45171
|
-
main().
|
|
46457
|
+
main().then((command) => {
|
|
46458
|
+
if (command !== "run") process.exit(0);
|
|
46459
|
+
}).catch((err) => {
|
|
45172
46460
|
console.error("formstr-mcp: fatal:", err instanceof Error ? err.message : err);
|
|
45173
46461
|
process.exit(1);
|
|
45174
46462
|
});
|
|
45175
46463
|
/*! Bundled license information:
|
|
45176
46464
|
|
|
45177
46465
|
@noble/hashes/utils.js:
|
|
46466
|
+
@noble/hashes/esm/utils.js:
|
|
45178
46467
|
(*! noble-hashes - MIT License (c) 2022 Paul Miller (paulmillr.com) *)
|
|
45179
46468
|
|
|
45180
46469
|
@noble/curves/utils.js:
|