@orangecheck/sdk 1.16.1 → 1.16.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -217,11 +217,15 @@ function parseCanonicalMessage(msg) {
217
217
  "ack"
218
218
  ]);
219
219
  const extensions = {};
220
+ const keys = /* @__PURE__ */ new Set();
221
+ const repeated = [];
220
222
  for (const line of lines) {
221
223
  const idx = line.indexOf(":");
222
224
  if (idx === -1) continue;
223
225
  const key = line.slice(0, idx).trim().toLowerCase();
224
226
  const val = line.slice(idx + 1).trim();
227
+ if (keys.has(key)) repeated.push(key);
228
+ keys.add(key);
225
229
  if (!coreKeys.has(key) && val) extensions[key] = val;
226
230
  }
227
231
  const network = extensions["network"] || "mainnet";
@@ -230,6 +234,7 @@ function parseCanonicalMessage(msg) {
230
234
  return {
231
235
  core: { address, identities, issued_at },
232
236
  expires,
237
+ repeated,
233
238
  network,
234
239
  extensions,
235
240
  bond: bond !== void 0 && !isNaN(bond) && bond > 0 ? bond : void 0
@@ -371,188 +376,98 @@ async function publishToRelays(event, relays = DEFAULT_RELAYS) {
371
376
  log2.info({ successCount: success.length, failedCount: failed.length }, "Publishing complete");
372
377
  return { success, failed };
373
378
  }
374
- async function queryByAttestationId(attestationId, relays = DEFAULT_RELAYS) {
379
+ var PAGE_LIMIT = 500;
380
+ var MAX_PAGES = 4;
381
+ async function querySubject(filter, relays, label) {
375
382
  const events = [];
376
- log2.info({ attestationId, relayCount: relays.length }, "Querying relays for attestation");
377
383
  const deadlineAt = Date.now() + FANOUT_DEADLINE_MS;
378
- const queryPromises = relays.map(async (relayUrl) => {
379
- let ws = null;
380
- try {
381
- ws = new WebSocket(relayUrl);
382
- const wsRef = ws;
383
- await new Promise((resolve, reject) => {
384
- const timeout = setTimeout(() => {
385
- wsRef.close();
386
- reject(new Error("Query timeout"));
387
- }, budgetFor(deadlineAt));
388
- const cleanup = () => {
389
- clearTimeout(timeout);
390
- wsRef.close();
391
- };
392
- wsRef.onopen = () => {
393
- const subscriptionId = `ochk_${Date.now()}`;
394
- wsRef.send(
395
- JSON.stringify([
396
- "REQ",
397
- subscriptionId,
398
- {
399
- kinds: [30078],
400
- "#d": [attestationId],
401
- limit: 1
384
+ await Promise.allSettled(
385
+ relays.map(async (relayUrl) => {
386
+ let ws = null;
387
+ try {
388
+ ws = new WebSocket(relayUrl);
389
+ const wsRef = ws;
390
+ await new Promise((resolve, reject) => {
391
+ const timeout = setTimeout(() => {
392
+ wsRef.close();
393
+ reject(new Error("Query timeout"));
394
+ }, budgetFor(deadlineAt));
395
+ const seen = /* @__PURE__ */ new Set();
396
+ let page = 0;
397
+ let inPage = 0;
398
+ let newInPage = 0;
399
+ let oldest = Infinity;
400
+ const ask = () => {
401
+ page++;
402
+ inPage = 0;
403
+ newInPage = 0;
404
+ const until = Number.isFinite(oldest) ? { until: oldest } : {};
405
+ wsRef.send(
406
+ JSON.stringify([
407
+ "REQ",
408
+ `ochk_${label}_${Date.now()}_${page}`,
409
+ { ...filter, ...until, limit: PAGE_LIMIT }
410
+ ])
411
+ );
412
+ };
413
+ wsRef.onopen = ask;
414
+ wsRef.onmessage = (msg) => {
415
+ try {
416
+ const data = JSON.parse(msg.data);
417
+ if (data[0] === "EVENT") {
418
+ const event = data[2];
419
+ const key = event.id ?? JSON.stringify(event);
420
+ inPage++;
421
+ if (!seen.has(key)) {
422
+ seen.add(key);
423
+ newInPage++;
424
+ events.push(event);
425
+ }
426
+ if (typeof event.created_at === "number") {
427
+ oldest = Math.min(oldest, event.created_at);
428
+ }
429
+ } else if (data[0] === "EOSE") {
430
+ wsRef.send(JSON.stringify(["CLOSE", data[1]]));
431
+ if (inPage >= PAGE_LIMIT && newInPage > 0 && page < MAX_PAGES) {
432
+ ask();
433
+ } else {
434
+ clearTimeout(timeout);
435
+ wsRef.close();
436
+ resolve();
437
+ }
402
438
  }
403
- ])
404
- );
405
- };
406
- wsRef.onmessage = (msg) => {
407
- try {
408
- const data = JSON.parse(msg.data);
409
- if (data[0] === "EVENT") {
410
- events.push(data[2]);
411
- } else if (data[0] === "EOSE") {
412
- cleanup();
413
- resolve();
439
+ } catch (err) {
440
+ log2.error({ relay: relayUrl, error: err }, "Failed to parse event");
414
441
  }
415
- } catch (err) {
416
- log2.error({ relay: relayUrl, error: err }, "Failed to parse event");
417
- }
418
- };
419
- wsRef.onerror = (err) => {
420
- log2.error({ relay: relayUrl, error: err }, "WebSocket error during query");
421
- cleanup();
422
- reject(err);
423
- };
424
- wsRef.onclose = () => {
425
- clearTimeout(timeout);
426
- };
427
- });
428
- } catch (err) {
429
- log2.error({ relay: relayUrl, error: err }, "Failed to query relay");
430
- } finally {
431
- if (ws && ws.readyState !== WebSocket.CLOSED) {
432
- ws.close();
442
+ };
443
+ wsRef.onerror = (err) => {
444
+ clearTimeout(timeout);
445
+ log2.error({ relay: relayUrl, error: err }, "WebSocket error during query");
446
+ reject(err);
447
+ };
448
+ });
449
+ } catch (err) {
450
+ log2.error({ relay: relayUrl, error: err }, "Failed to query relay");
451
+ } finally {
452
+ if (ws && ws.readyState !== WebSocket.CLOSED) ws.close();
433
453
  }
434
- }
435
- });
436
- await Promise.allSettled(queryPromises);
437
- log2.info({ eventCount: events.length }, "Query complete");
454
+ })
455
+ );
456
+ log2.info({ label, eventCount: events.length }, "Query complete");
438
457
  return events;
439
458
  }
459
+ async function queryByAttestationId(attestationId, relays = DEFAULT_RELAYS) {
460
+ log2.info({ attestationId, relayCount: relays.length }, "Querying relays for attestation");
461
+ return querySubject({ kinds: [30078], "#d": [attestationId] }, relays, "id");
462
+ }
440
463
  async function queryByAddress(address, relays = DEFAULT_RELAYS) {
441
- const events = [];
442
464
  log2.info({ address, relayCount: relays.length }, "Querying relays for address");
443
- const deadlineAt = Date.now() + FANOUT_DEADLINE_MS;
444
- const queryPromises = relays.map(async (relayUrl) => {
445
- try {
446
- const ws = new WebSocket(relayUrl);
447
- await new Promise((resolve, reject) => {
448
- const timeout = setTimeout(() => {
449
- ws.close();
450
- reject(new Error("Query timeout"));
451
- }, budgetFor(deadlineAt));
452
- ws.onopen = () => {
453
- const subscriptionId = `ochk_addr_${Date.now()}`;
454
- ws.send(
455
- JSON.stringify([
456
- "REQ",
457
- subscriptionId,
458
- {
459
- kinds: [30078],
460
- // `#t`, NOT `#address`: NIP-12 relays index
461
- // single-letter tags only, so `#address`
462
- // matched nothing on any relay and this
463
- // function returned empty for every real
464
- // attestation. attest.ochk.io's verifier has
465
- // queried `#t` since the same fix landed
466
- // there; this is the back-port.
467
- "#t": [address],
468
- limit: 50
469
- }
470
- ])
471
- );
472
- };
473
- ws.onmessage = (msg) => {
474
- try {
475
- const data = JSON.parse(msg.data);
476
- if (data[0] === "EVENT") {
477
- events.push(data[2]);
478
- } else if (data[0] === "EOSE") {
479
- clearTimeout(timeout);
480
- ws.close();
481
- resolve();
482
- }
483
- } catch (err) {
484
- log2.error({ relay: relayUrl, error: err }, "Failed to parse event");
485
- }
486
- };
487
- ws.onerror = (err) => {
488
- clearTimeout(timeout);
489
- log2.error({ relay: relayUrl, error: err }, "WebSocket error during query");
490
- reject(err);
491
- };
492
- });
493
- } catch (err) {
494
- log2.error({ relay: relayUrl, error: err }, "Failed to query relay");
495
- }
496
- });
497
- await Promise.allSettled(queryPromises);
498
- log2.info({ eventCount: events.length }, "Query complete");
499
- return events;
465
+ return querySubject({ kinds: [30078], "#t": [address] }, relays, "addr");
500
466
  }
501
467
  async function queryByIdentity(protocol, identifier, relays = DEFAULT_RELAYS) {
502
- const events = [];
503
- const identityTag = `${protocol}:${identifier}`;
504
- const identityTags = protocol === "nostr" ? nostrIdentifierForms(identifier).map((f) => `nostr:${f}`) : [identityTag];
468
+ const identityTags = protocol === "nostr" ? nostrIdentifierForms(identifier).map((f) => `nostr:${f}`) : [`${protocol}:${identifier}`];
505
469
  log2.info({ protocol, identifier, relayCount: relays.length }, "Querying relays for identity");
506
- const deadlineAt = Date.now() + FANOUT_DEADLINE_MS;
507
- const queryPromises = relays.map(async (relayUrl) => {
508
- try {
509
- const ws = new WebSocket(relayUrl);
510
- await new Promise((resolve, reject) => {
511
- const timeout = setTimeout(() => {
512
- ws.close();
513
- reject(new Error("Query timeout"));
514
- }, budgetFor(deadlineAt));
515
- ws.onopen = () => {
516
- const subscriptionId = `ochk_identity_${Date.now()}`;
517
- ws.send(
518
- JSON.stringify([
519
- "REQ",
520
- subscriptionId,
521
- {
522
- kinds: [30078],
523
- "#i": identityTags,
524
- limit: 10
525
- }
526
- ])
527
- );
528
- };
529
- ws.onmessage = (msg) => {
530
- try {
531
- const data = JSON.parse(msg.data);
532
- if (data[0] === "EVENT") {
533
- events.push(data[2]);
534
- } else if (data[0] === "EOSE") {
535
- clearTimeout(timeout);
536
- ws.close();
537
- resolve();
538
- }
539
- } catch (err) {
540
- log2.error({ relay: relayUrl, error: err }, "Failed to parse event");
541
- }
542
- };
543
- ws.onerror = (err) => {
544
- clearTimeout(timeout);
545
- log2.error({ relay: relayUrl, error: err }, "WebSocket error during query");
546
- reject(err);
547
- };
548
- });
549
- } catch (err) {
550
- log2.error({ relay: relayUrl, error: err }, "Failed to query relay");
551
- }
552
- });
553
- await Promise.allSettled(queryPromises);
554
- log2.info({ eventCount: events.length }, "Query complete");
555
- return events;
470
+ return querySubject({ kinds: [30078], "#i": identityTags }, relays, "identity");
556
471
  }
557
472
  async function verifyAttestationEnvelope(envelope) {
558
473
  try {
@@ -579,6 +494,7 @@ function signedEnvelope(envelope) {
579
494
  return null;
580
495
  }
581
496
  if (!parsed.core.address || rfc3339Ms(parsed.core.issued_at) === null) return null;
497
+ if (parsed.repeated.length > 0) return null;
582
498
  const { expires_at: _copy, ...rest } = envelope;
583
499
  return {
584
500
  ...rest,