@bkazemi/verily 0.2.0 → 0.3.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/verily.js CHANGED
@@ -9583,6 +9583,7 @@ var Verily = (() => {
9583
9583
  isArtifactProvider: () => isArtifactProvider,
9584
9584
  isCodeProvider: () => isCodeProvider,
9585
9585
  isRedirectProvider: () => isRedirectProvider,
9586
+ lastProved: () => lastProved,
9586
9587
  localSide: () => localSide,
9587
9588
  presentConnections: () => presentConnections,
9588
9589
  proofTitle: () => proofTitle,
@@ -9651,7 +9652,7 @@ var Verily = (() => {
9651
9652
  });
9652
9653
  await signatures2[0].verified;
9653
9654
  const document2 = JSON.parse(data);
9654
- return document2?.type === "verily-evidence" && document2.version === 1 && typeof document2.issuedAt === "number" ? document2 : void 0;
9655
+ return document2?.type === "verily-evidence" && typeof document2.issuedAt === "number" && (document2.version === 1 || document2.version === 2 && document2.status === "retired" && typeof document2.retiredAt === "number") ? document2 : void 0;
9655
9656
  } catch {
9656
9657
  continue;
9657
9658
  }
@@ -9677,6 +9678,7 @@ var Verily = (() => {
9677
9678
  var freshnessMs = 7 * 864e5;
9678
9679
  function status(connection, now, freshness = freshnessMs) {
9679
9680
  if (connection.revokedAt !== void 0) return "revoked";
9681
+ if (connection.retiredAt !== void 0) return "retired";
9680
9682
  if (now >= connection.expiresAt) return "expired";
9681
9683
  const main = connection.attestations?.external[0];
9682
9684
  if (main && !fresh(main, now, freshness)) return "unconfirmed";
@@ -9685,8 +9687,13 @@ var Verily = (() => {
9685
9687
  function fresh(attestation, now, freshness = freshnessMs) {
9686
9688
  return !attestation.artifactUrl || attestation.hosted === true || freshness === Infinity || now < attestation.confirmedAt + freshness;
9687
9689
  }
9690
+ function lastProved(evidence) {
9691
+ const main = evidence.attestations.external[0];
9692
+ return main.artifactUrl ? main.confirmedAt : evidence.authenticatedAt;
9693
+ }
9688
9694
  function statusLabel(evidence, now) {
9689
9695
  if (evidence.status === "revoked") return "Revoked";
9696
+ if (evidence.status === "retired") return "Retired";
9690
9697
  if (evidence.status === "expired" || evidence.expiresAt <= now) return "Expired";
9691
9698
  return evidence.status === "unconfirmed" ? "Unconfirmed" : "Verified";
9692
9699
  }
@@ -9782,6 +9789,11 @@ var Verily = (() => {
9782
9789
  ["circle", { cx: "8", cy: "8", r: "6.2" }],
9783
9790
  ["path", { d: "M8 4.6V8h2.6" }]
9784
9791
  ]);
9792
+ var boxMark = () => statusMark("box", [
9793
+ ["path", { d: "M2.6 3.8h10.8v2.6H2.6z" }],
9794
+ ["path", { d: "M3.7 6.4v5.8h8.6V6.4" }],
9795
+ ["path", { d: "M6.6 9h2.8" }]
9796
+ ]);
9785
9797
  var dashMark = () => statusMark("dash", [["path", { d: "M4.4 8h7.2" }]]);
9786
9798
 
9787
9799
  // src/browser/provider-mark.ts
@@ -9926,7 +9938,9 @@ var Verily = (() => {
9926
9938
  .peek .via { display: block; margin-top: 6px; font-size: 11px; color: var(--verily-muted, #65726c); }
9927
9939
  .provider { display: block; flex-shrink: 0; width: 14px; height: 14px; }
9928
9940
  .expired .icon { color: #815a12; background: #fbefce; }
9929
- .revoked .icon, .message .icon { color: #626d69; background: #edf0ee; }
9941
+ .revoked .icon, .retired .icon, .message .icon { color: #626d69; background: #edf0ee; }
9942
+ /* Nothing ran out and nothing wants attention: the holder chose this, so it is only quiet. */
9943
+ .retired .name { color: var(--verily-muted, #65726c); }
9930
9944
  .message { color: var(--verily-muted, #65726c); }
9931
9945
  .add { font-weight: 600; }
9932
9946
  @media (prefers-reduced-motion: no-preference) {
@@ -10055,7 +10069,8 @@ var Verily = (() => {
10055
10069
  } = {}) {
10056
10070
  const provider = evidence.providerName;
10057
10071
  const current = evidence.status === "verified" && evidence.expiresAt > Date.now();
10058
- const state = current ? "verified" : evidence.status === "revoked" ? "revoked" : "expired";
10072
+ const retired = evidence.status === "retired";
10073
+ const state = current ? "verified" : retired ? "retired" : evidence.status === "revoked" ? "revoked" : "expired";
10059
10074
  const label = statusLabel(evidence, Date.now());
10060
10075
  const key2 = renderKey(evidence, current, label, more, linked, rows, peek);
10061
10076
  if (intact(element) && shown.get(element) === key2) return null;
@@ -10064,7 +10079,7 @@ var Verily = (() => {
10064
10079
  const unnamed = Math.max(more - rows.length, 0);
10065
10080
  const named = rows.map((row) => `, ${row.providerName} ${externalName(row.external)}`).join("");
10066
10081
  const others = `${named}${unnamed ? ` and ${unnamed} more` : ""}`;
10067
- paintMark(mark2, current ? "current" : "inactive");
10082
+ paintMark(mark2, current ? "current" : retired ? "pending" : "inactive");
10068
10083
  if (linked) {
10069
10084
  badge.href = evidence.evidenceUrl;
10070
10085
  badge.rel = "noreferrer";
@@ -10101,7 +10116,7 @@ var Verily = (() => {
10101
10116
  }
10102
10117
  if (!current) {
10103
10118
  const icon = span("icon", "");
10104
- icon.append(state === "expired" ? clockMark() : dashMark());
10119
+ icon.append(retired ? boxMark() : state === "expired" ? clockMark() : dashMark());
10105
10120
  icon.setAttribute("aria-hidden", "true");
10106
10121
  badge.append(span("label", label), icon);
10107
10122
  }
@@ -10232,6 +10247,7 @@ var Verily = (() => {
10232
10247
  status: _status,
10233
10248
  revokedAt: _revokedAt,
10234
10249
  signedUrl: _signedUrl,
10250
+ mark: _mark,
10235
10251
  links: _links,
10236
10252
  type: _type,
10237
10253
  version: _version,
@@ -10298,11 +10314,23 @@ ${claims(evidence)}`;
10298
10314
  const document2 = await verifySigned(signed, keys);
10299
10315
  if (!document2 || document2.id !== evidence.id || document2.verifierName !== evidence.verifierName || document2.evidenceUrl !== evidence.evidenceUrl || document2.siteName !== evidence.siteName || document2.local.reference !== evidence.local.reference || document2.provider !== evidence.provider || document2.external.id !== evidence.external.id)
10300
10316
  return { state: "invalid" };
10301
- const { type: _type, version: _version, issuedAt: _issuedAt, ...said } = document2;
10317
+ if (document2.version === 2 !== (evidence.status === "retired"))
10318
+ return { state: "unchecked", why: "unreadable" };
10319
+ const {
10320
+ type: _type,
10321
+ version: _version,
10322
+ issuedAt: _issuedAt,
10323
+ status: _status,
10324
+ retiredAt: _retiredAt,
10325
+ mark: _mark,
10326
+ ...said
10327
+ } = document2;
10302
10328
  const record2 = {
10303
10329
  ...said,
10304
10330
  status: evidence.status,
10305
10331
  ...evidence.revokedAt === void 0 ? {} : { revokedAt: evidence.revokedAt },
10332
+ ...document2.version === 2 ? { retiredAt: document2.retiredAt } : {},
10333
+ ...evidence.mark === void 0 ? {} : { mark: evidence.mark },
10306
10334
  signedUrl: evidence.signedUrl
10307
10335
  };
10308
10336
  return drawable(record2) ? { state: "valid", keyId: by2, record: record2 } : { state: "unchecked", why: "unreadable" };
@@ -10336,12 +10364,15 @@ ${claims(evidence)}`;
10336
10364
  if (evidence.signedUrl === void 0) return evidence;
10337
10365
  const key2 = shown2(evidence);
10338
10366
  const signed = signedAs.get(key2);
10339
- if (signed)
10367
+ if (signed) {
10368
+ const { mark: _mark, ...said } = signed;
10340
10369
  return {
10341
- ...signed,
10370
+ ...said,
10342
10371
  status: evidence.status,
10343
- ...evidence.revokedAt === void 0 ? {} : { revokedAt: evidence.revokedAt }
10372
+ ...evidence.revokedAt === void 0 ? {} : { revokedAt: evidence.revokedAt },
10373
+ ...evidence.mark === void 0 ? {} : { mark: evidence.mark }
10344
10374
  };
10375
+ }
10345
10376
  return evidence.status === "verified" && failures.has(key2) ? { ...evidence, status: "unconfirmed" } : evidence;
10346
10377
  }
10347
10378
  function watchSigned(records, changed) {
@@ -10379,6 +10410,7 @@ ${claims(evidence)}`;
10379
10410
  var logo = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="${-pad} ${-26 - pad} ${2637 + 2 * pad} ${916 + 2 * pad}" class="logo" role="img" aria-label="Verily"><rect x="${-pad}" y="${-26 - pad}" width="${2637 + 2 * pad}" height="${916 + 2 * pad}" rx="166" fill="#0d1117"/>` + logoPaths.map(({ d: d2, fill }) => `<path d="${d2}" fill="${fill === "currentColor" ? "#ffffff" : fill}"/>`).join("") + "</svg>";
10380
10411
 
10381
10412
  // src/browser/logo.ts
10413
+ var projectUrl = "https://github.com/bkazemi/verily";
10382
10414
  function verilyLogo() {
10383
10415
  const namespace2 = "http://www.w3.org/2000/svg";
10384
10416
  const svg = document.createElementNS(namespace2, "svg");
@@ -10396,9 +10428,14 @@ ${claims(evidence)}`;
10396
10428
  }
10397
10429
 
10398
10430
  // src/version.ts
10399
- var version = "v0.2.0";
10431
+ var version = "v0.3.0";
10400
10432
 
10401
10433
  // src/browser/evidence-dialog.ts
10434
+ function stampLink() {
10435
+ const link = outward(node("a"), projectUrl);
10436
+ link.append(verilyLogo());
10437
+ return link;
10438
+ }
10402
10439
  var openDialogs = /* @__PURE__ */ new WeakMap();
10403
10440
  var styles2 = `
10404
10441
  * { box-sizing: border-box; }
@@ -10431,6 +10468,14 @@ ${claims(evidence)}`;
10431
10468
  .summary a, .method a, .additional a { font: inherit; }
10432
10469
  .reference { margin-top: 2px; }
10433
10470
  .method { margin-top: 8px; }
10471
+ /* In the corner the heading leaves empty, apart from everything that was checked. */
10472
+ .listing { position: absolute; top: 12px; right: 14px; padding: 1px 8px; border: 1px solid #e0e6df; border-radius: 999px; color: #6b786f; font-size: 11px; font-weight: 550; }
10473
+ .listing.preferred { border-color: #245f43; color: #245f43; }
10474
+ /* Quiet, as its pill is: the surface and the name step back, and the controls do not. */
10475
+ .account.retired { background: #f6f8f5; }
10476
+ .account.retired > a, .account.retired > strong { color: #6b786f; }
10477
+ .account.retired .mark { opacity: .45; }
10478
+ .group { margin: 20px 0 0; color: #6b786f; font-size: 11px; font-weight: 550; }
10434
10479
  .additional { margin-top: 2px; padding-left: 12px; }
10435
10480
  .joiner { display: block; width: 20px; height: 20px; margin: 8px auto -4px; color: #90a096; }
10436
10481
  dl { margin: 16px 0 0; padding-top: 12px; border-top: 1px solid #e5e9e3; display: grid; grid-template-columns: auto 1fr; gap: 5px 16px; font-size: 11px; }
@@ -10443,9 +10488,10 @@ ${claims(evidence)}`;
10443
10488
  .action:disabled { opacity: .6; cursor: progress; }
10444
10489
  .action.danger:hover { border-color: #b3261e; background: #fdecea; color: #b3261e; }
10445
10490
  .row { display: flex; justify-content: end; gap: 8px; margin-top: 16px; }
10446
- .account .row { align-items: center; justify-content: start; margin-top: 12px; }
10491
+ .account .row { align-items: center; justify-content: start; flex-wrap: wrap; margin-top: 12px; }
10447
10492
  .account .action { padding: 5px 10px; font-size: 12px; }
10448
- footer { display: flex; align-items: center; justify-content: start; gap: 6px; margin-top: 14px; color: #9aa9a0; font-size: 11px; }
10493
+ footer { display: flex; align-items: center; justify-content: start; gap: 6px; margin: 20px 0 -8px; color: #9aa9a0; font-size: 11px; }
10494
+ footer a { display: flex; color: inherit; }
10449
10495
  .logo { display: block; height: 13px; }
10450
10496
  ${markStyles}
10451
10497
  `;
@@ -10510,6 +10556,7 @@ ${claims(evidence)}`;
10510
10556
  card.append(...extra);
10511
10557
  return card;
10512
10558
  }
10559
+ var retiringNote = "Retiring keeps this record as history. It will no longer read as verified, and who can read it cannot be changed afterwards.";
10513
10560
  var removable = (evidence) => evidence.links ?? (evidence.status === "revoked" ? [] : [evidence.id]);
10514
10561
  function manageRow(evidence, manage) {
10515
10562
  const row = node("div", "", "row");
@@ -10518,12 +10565,49 @@ ${claims(evidence)}`;
10518
10565
  control.type = "button";
10519
10566
  return control;
10520
10567
  };
10568
+ const [named] = removable(evidence);
10569
+ const { mark: mark2 } = manage;
10570
+ const listable = mark2 !== void 0 && named !== void 0 && !["revoked", "retired"].includes(evidence.status);
10571
+ const list = (label, as2) => {
10572
+ const control = act(label);
10573
+ control.onclick = async () => {
10574
+ for (const other of row.children) other.disabled = true;
10575
+ try {
10576
+ await mark2(named, as2);
10577
+ } catch {
10578
+ offer("That did not go through.");
10579
+ }
10580
+ };
10581
+ return control;
10582
+ };
10521
10583
  const offer = (note = "") => {
10522
10584
  const renew = act("Renew");
10523
10585
  const remove = act("Remove", true);
10524
- renew.onclick = () => manage.connect(evidence.provider);
10586
+ renew.onclick = () => manage.renew && evidence.status !== "revoked" ? manage.renew(
10587
+ evidence.id,
10588
+ evidence.provider,
10589
+ evidence.status === "retired" ? evidence.attestations.external[0].method : void 0
10590
+ ) : manage.connect(evidence.provider);
10525
10591
  remove.onclick = confirm;
10526
- row.replaceChildren(renew, remove, ...note ? [node("span", note, "muted")] : []);
10592
+ const listing = [];
10593
+ if (listable) {
10594
+ const retire = act("Retire");
10595
+ retire.onclick = retiring;
10596
+ listing.push(
10597
+ ...evidence.mark === "preferred" ? [] : [list("Mark as preferred", "preferred")],
10598
+ ...evidence.mark === "unused" ? [] : [list("Mark as unused", "unused")],
10599
+ ...evidence.mark === void 0 ? [] : [list("Mark as current", "current")],
10600
+ retire
10601
+ );
10602
+ }
10603
+ row.replaceChildren(renew, ...listing, remove, ...note ? [node("span", note, "muted")] : []);
10604
+ };
10605
+ const retiring = () => {
10606
+ const cancel = act("Cancel");
10607
+ const sure = list("Retire", "retired");
10608
+ cancel.onclick = () => offer();
10609
+ row.replaceChildren(node("span", retiringNote, "muted"), cancel, sure);
10610
+ cancel.focus();
10527
10611
  };
10528
10612
  const confirm = () => {
10529
10613
  const cancel = act("Cancel");
@@ -10626,11 +10710,15 @@ ${claims(evidence)}`;
10626
10710
  } else attribution.append(document.createTextNode(evidence.verifierName));
10627
10711
  if (evidence.signedUrl) attribution.append(signedMark(evidence, later));
10628
10712
  copy.append(node("div", status2, "state"), attribution);
10629
- summary.append(verificationMark(current ? "current" : "inactive"), copy);
10713
+ const retired = evidence.status === "retired";
10714
+ summary.append(verificationMark(current ? "current" : retired ? "pending" : "inactive"), copy);
10630
10715
  const dates = node("dl");
10631
10716
  const dateRows = [["Approved", evidence.approvedAt]];
10632
10717
  if (evidence.status === "revoked") {
10633
10718
  if (evidence.revokedAt !== void 0) dateRows.push(["Revoked on", evidence.revokedAt]);
10719
+ } else if (retired) {
10720
+ dateRows.push(["Last verified", lastProved(evidence)]);
10721
+ if (evidence.retiredAt !== void 0) dateRows.push(["Retired", evidence.retiredAt]);
10634
10722
  } else {
10635
10723
  dateRows.push([
10636
10724
  evidence.expiresAt > Date.now() ? "Valid until" : "Expired on",
@@ -10638,7 +10726,7 @@ ${claims(evidence)}`;
10638
10726
  ]);
10639
10727
  }
10640
10728
  const main = evidence.attestations.external[0];
10641
- if (main.artifactUrl) dateRows.push(["Last checked", main.confirmedAt]);
10729
+ if (main.artifactUrl && !retired) dateRows.push(["Last checked", main.confirmedAt]);
10642
10730
  for (const [label, time] of dateRows) {
10643
10731
  dates.append(node("dt", label), node("dd", moment(time)));
10644
10732
  }
@@ -10657,19 +10745,22 @@ ${claims(evidence)}`;
10657
10745
  summary,
10658
10746
  ...attestationNote(main, names),
10659
10747
  ...evidence.attestations.external.slice(1).flatMap((a2) => attestationNote(a2, names, true)),
10748
+ ...evidence.status === "revoked" || retired ? [] : evidence.mark === "preferred" ? [node("div", "Preferred", "listing preferred")] : evidence.mark === "unused" ? [node("div", "No longer used", "listing")] : [],
10660
10749
  dates,
10661
10750
  ...manage && removable(evidence).length ? [manageRow(evidence, manage)] : []
10662
10751
  );
10752
+ const surface = retired ? "account retired" : "account";
10753
+ card.className = surface;
10663
10754
  if (evidence.signedUrl) {
10664
10755
  const veiled = [...card.children];
10665
10756
  const checking = node("div", "", "checking");
10666
10757
  checking.setAttribute("role", "status");
10667
10758
  checking.append(node("span", "", "spinner"), document.createTextNode("Checking signature\u2026"));
10668
- card.className = "account veiled";
10759
+ card.className = `${surface} veiled`;
10669
10760
  for (const part of veiled) part.inert = true;
10670
10761
  card.append(checking);
10671
10762
  void signatures(evidence).then(() => {
10672
- card.className = "account";
10763
+ card.className = surface;
10673
10764
  for (const part of veiled) part.inert = false;
10674
10765
  checking.remove();
10675
10766
  });
@@ -10700,11 +10791,16 @@ ${claims(evidence)}`;
10700
10791
  provider: first.providerName
10701
10792
  })
10702
10793
  );
10794
+ const retired = records.filter((record2) => record2.status === "retired");
10703
10795
  content.replaceChildren(
10704
10796
  localCard,
10705
10797
  linkMark(),
10706
- ...records.map((record2) => externalCard(record2, manage, later)),
10798
+ ...records.filter((record2) => record2.status !== "retired").map((record2) => externalCard(record2, manage, later)),
10707
10799
  ...manage ? [addRow(manage)] : [],
10800
+ ...retired.length ? [
10801
+ node("h3", "Retired accounts", "group"),
10802
+ ...retired.map((record2) => externalCard(record2, manage, later))
10803
+ ] : [],
10708
10804
  // Nothing below the cards may name a provider. Approval, method and dates belong to
10709
10805
  // the card they came from, and a second provider on this subject gets its own card.
10710
10806
  node(
@@ -10736,11 +10832,30 @@ ${claims(evidence)}`;
10736
10832
  close.type = "button";
10737
10833
  close.setAttribute("aria-label", "Close verification details");
10738
10834
  content.setAttribute("aria-live", "polite");
10739
- stamp.append(verilyLogo(), node("span", version));
10835
+ stamp.append(stampLink(), node("span", version));
10740
10836
  header.append(heading, close);
10741
10837
  dialog.append(header, content, stamp);
10742
10838
  const removed = /* @__PURE__ */ new Map();
10839
+ const listed = [];
10840
+ const listing = (record2) => JSON.stringify([record2.status, record2.mark, record2.retiredAt, record2.approvedAt]);
10841
+ const listings = (given) => new Map([given].flat().map((record2) => [record2.id, listing(record2)]));
10743
10842
  let held;
10843
+ const relisted = (evidence) => {
10844
+ let record2 = evidence;
10845
+ for (const { ids, as: as2, at: at2 } of listed) {
10846
+ if (["revoked", "retired"].includes(record2.status)) break;
10847
+ if (!ids.includes(record2.id)) {
10848
+ if (as2 === "preferred" && record2.mark === "preferred")
10849
+ record2 = { ...record2, mark: void 0 };
10850
+ continue;
10851
+ }
10852
+ record2 = as2 === "retired" ? (
10853
+ // Its signed form is another document now, to be read with the records to come.
10854
+ { ...record2, status: "retired", retiredAt: at2, mark: void 0, signedUrl: void 0 }
10855
+ ) : { ...record2, mark: as2 === "current" ? void 0 : as2 };
10856
+ }
10857
+ return record2;
10858
+ };
10744
10859
  const actions = manage && {
10745
10860
  // The other dialog opens over this one before this one goes, so the page behind is
10746
10861
  // never uncovered between the two.
@@ -10748,11 +10863,32 @@ ${claims(evidence)}`;
10748
10863
  manage.connect(provider);
10749
10864
  dialog.close();
10750
10865
  },
10866
+ ...manage.renew ? {
10867
+ renew(id, provider, method) {
10868
+ manage.renew(id, provider, method);
10869
+ dialog.close();
10870
+ }
10871
+ } : {},
10751
10872
  async remove(ids) {
10752
10873
  await manage.remove(ids);
10753
10874
  for (const id of ids) removed.set(id, Date.now());
10754
10875
  if (held && dialog.open) draw(held);
10755
- }
10876
+ },
10877
+ ...manage.mark ? {
10878
+ async mark(id, as2) {
10879
+ await manage.mark(id, as2);
10880
+ const account = arrange2([held ?? []].flat()).find(
10881
+ (card) => removable(card).includes(id)
10882
+ );
10883
+ listed.push({
10884
+ ids: account ? removable(account) : [id],
10885
+ as: as2,
10886
+ at: Date.now(),
10887
+ before: listings(held ?? [])
10888
+ });
10889
+ if (held && dialog.open) draw(held);
10890
+ }
10891
+ } : {}
10756
10892
  };
10757
10893
  root.append(dialog);
10758
10894
  document.body.append(host);
@@ -10763,9 +10899,13 @@ ${claims(evidence)}`;
10763
10899
  const retries = /* @__PURE__ */ new Set();
10764
10900
  const draw = (given) => {
10765
10901
  held = given;
10902
+ const now = listings(given);
10903
+ for (const change of [...listed])
10904
+ if (change.ids.some((id) => now.get(id) !== change.before.get(id)))
10905
+ listed.splice(listed.indexOf(change), 1);
10766
10906
  const records = arrange2(
10767
10907
  [given].flat().map(
10768
- (e2) => removed.has(e2.id) && e2.status !== "revoked" ? { ...e2, status: "revoked", revokedAt: removed.get(e2.id) } : standing(e2)
10908
+ (e2) => removed.has(e2.id) && e2.status !== "revoked" ? { ...e2, status: "revoked", revokedAt: removed.get(e2.id) } : relisted(standing(e2))
10769
10909
  )
10770
10910
  );
10771
10911
  const key2 = JSON.stringify(records.map((e2) => [e2, statusLabel(e2, Date.now())]));
@@ -10906,7 +11046,7 @@ ${claims(evidence)}`;
10906
11046
  return element;
10907
11047
  }
10908
11048
  var openDialogs2 = /* @__PURE__ */ new WeakMap();
10909
- function openConnectDialog(opener, api, back, provider) {
11049
+ function openConnectDialog(opener, api, back, provider, renew) {
10910
11050
  const existing = openDialogs2.get(opener);
10911
11051
  if (existing?.open) {
10912
11052
  existing.focus();
@@ -10928,7 +11068,7 @@ ${claims(evidence)}`;
10928
11068
  close.type = "button";
10929
11069
  close.setAttribute("aria-label", "Close");
10930
11070
  content.setAttribute("aria-live", "polite");
10931
- stamp.append(verilyLogo(), node("span", version));
11071
+ stamp.append(stampLink(), node("span", version));
10932
11072
  header.append(heading, close);
10933
11073
  dialog.append(header, content, stamp);
10934
11074
  root.append(dialog);
@@ -11006,7 +11146,11 @@ ${claims(evidence)}`;
11006
11146
  return;
11007
11147
  }
11008
11148
  if (!current(asked)) return;
11009
- const all = methods.methods;
11149
+ const renewing = methods.methods.filter(
11150
+ (m2) => m2.provider === provider && (renew?.method === void 0 || m2.method === renew.method)
11151
+ );
11152
+ if (renew && !renewing.length) renew = void 0;
11153
+ const all = renew ? renewing : methods.methods;
11010
11154
  if (group !== void 0 && !all.some((m2) => m2.provider === group)) group = void 0;
11011
11155
  const count = (provider2) => all.filter((m2) => m2.provider === provider2).length;
11012
11156
  const list = node("div", "", "choices");
@@ -11035,7 +11179,7 @@ ${claims(evidence)}`;
11035
11179
  return;
11036
11180
  }
11037
11181
  }
11038
- void busy(control, () => api.start(choice.provider, choice.method), show);
11182
+ void busy(control, () => api.start(choice.provider, choice.method, renew?.id), show);
11039
11183
  };
11040
11184
  list.append(control);
11041
11185
  }
@@ -11049,7 +11193,7 @@ ${claims(evidence)}`;
11049
11193
  ),
11050
11194
  list
11051
11195
  ];
11052
- if (group !== void 0) {
11196
+ if (group !== void 0 && !renew) {
11053
11197
  const back2 = button("\u2039 All options");
11054
11198
  back2.onclick = () => {
11055
11199
  group = void 0;
@@ -11399,7 +11543,11 @@ ${claims(evidence)}`;
11399
11543
  // Every record the card speaks for, so its signature mark answers for all of them.
11400
11544
  sources: verified.length ? verified : [base]
11401
11545
  };
11402
- }).sort((a2, b2) => a2.connectedAt - b2.connectedAt);
11546
+ }).sort((a2, b2) => place2(a2) - place2(b2) || a2.connectedAt - b2.connectedAt);
11547
+ }
11548
+ function place2(account) {
11549
+ if (account.status === "retired") return 3;
11550
+ return account.mark === "preferred" ? 0 : account.mark === "unused" ? 2 : 1;
11403
11551
  }
11404
11552
  function presentGroup(element, records, load2) {
11405
11553
  const ordered = accounts(records.map(standing));
@@ -11506,7 +11654,12 @@ ${claims(evidence)}`;
11506
11654
  if (typeof data.local.profileUrl === "string") safeUrl(data.local.profileUrl);
11507
11655
  return data;
11508
11656
  },
11509
- start: async (provider, method) => flowView(await ask("/sessions", { kind: "connect", provider, method })),
11657
+ start: async (provider, method, renew) => flowView(
11658
+ await ask(
11659
+ "/sessions",
11660
+ renew ? { kind: "renew", connectionId: renew, provider, method } : { kind: "connect", provider, method }
11661
+ )
11662
+ ),
11510
11663
  read: async (id) => flowView(await ask(`/flows/${encodeURIComponent(id)}?format=json`, void 0, id)),
11511
11664
  submit: async (id, artifact) => flowView(await ask(`/flows/${encodeURIComponent(id)}/submit`, { artifact }, id)),
11512
11665
  async approve(id, visibility, cancel) {
@@ -11550,11 +11703,11 @@ ${claims(evidence)}`;
11550
11703
  * Opens the connect dialog over the current page. Resolves when it closes, with how
11551
11704
  * the last attempt in it ended. Call from a click: a sign-in method opens a window.
11552
11705
  */
11553
- openConnect(opener = document.body, back, provider) {
11706
+ openConnect(opener = document.body, back, provider, renew) {
11554
11707
  if (remote && !handoffUrl)
11555
11708
  throw new Error("A backend on another origin requires a handoff URL");
11556
11709
  session = void 0;
11557
- return openConnectDialog(opener, flows, back, provider);
11710
+ return openConnectDialog(opener, flows, back, provider, renew);
11558
11711
  },
11559
11712
  /**
11560
11713
  * Draws the pill that opens the connect dialog. The host receives a `verily-result`
@@ -11682,6 +11835,14 @@ ${claims(evidence)}`;
11682
11835
  if (remote) session = void 0;
11683
11836
  return ask(`/connections/${encodeURIComponent(id)}/disconnect`, {});
11684
11837
  },
11838
+ /**
11839
+ * Says how the holder would have an account listed, or retires it. Names one record
11840
+ * and acts on the account: every record of it the holder has.
11841
+ */
11842
+ mark(id, as2) {
11843
+ if (remote) session = void 0;
11844
+ return ask(`/connections/${encodeURIComponent(id)}/mark`, { as: as2 });
11845
+ },
11685
11846
  issueShare: (id) => request(`/connections/${encodeURIComponent(id)}/share`, {}),
11686
11847
  revokeShare: (id) => request(`/connections/${encodeURIComponent(id)}/share-revoke`, {})
11687
11848
  };
@@ -11753,7 +11914,8 @@ ${claims(evidence)}`;
11753
11914
  (k2) => typeof value.external[k2] === "string"
11754
11915
  ) && (value.local.profileUrl === void 0 || typeof value.local.profileUrl === "string") && // A signed record lives beside the record it was made from and nowhere else, since the
11755
11916
  // keys it is checked against are read from where the record lives.
11756
- (value.signedUrl === void 0 || value.signedUrl === `${value.evidenceUrl}?format=signed`) && validAttestations(value.attestations) && (value.local.kind === void 0 || typeof value.local.kind === "string") && (value.external.kind === void 0 || ["account", "key", "page", "mailbox"].includes(String(value.external.kind))) && (value.revokedAt === void 0 || typeof value.revokedAt === "number" && Number.isFinite(value.revokedAt)) && ["verified", "unconfirmed", "expired", "revoked"].includes(String(value.status)) && ["public", "unlisted"].includes(String(value.visibility)) && (value.connectedAt === void 0 || typeof value.connectedAt === "number" && Number.isFinite(value.connectedAt)) && ["authenticatedAt", "approvedAt", "expiresAt"].every(
11917
+ (value.signedUrl === void 0 || value.signedUrl === `${value.evidenceUrl}?format=signed`) && validAttestations(value.attestations) && (value.local.kind === void 0 || typeof value.local.kind === "string") && (value.external.kind === void 0 || ["account", "key", "page", "mailbox"].includes(String(value.external.kind))) && (value.revokedAt === void 0 || typeof value.revokedAt === "number" && Number.isFinite(value.revokedAt)) && ["verified", "unconfirmed", "expired", "retired", "revoked"].includes(String(value.status)) && // A retired record stands on its dates, so one that does not say when is not one.
11918
+ (value.status === "retired" ? typeof value.retiredAt === "number" && Number.isFinite(value.retiredAt) : value.retiredAt === void 0) && (value.mark === void 0 || ["preferred", "unused"].includes(String(value.mark))) && ["public", "unlisted"].includes(String(value.visibility)) && (value.connectedAt === void 0 || typeof value.connectedAt === "number" && Number.isFinite(value.connectedAt)) && ["authenticatedAt", "approvedAt", "expiresAt"].every(
11757
11919
  (k2) => typeof value[k2] === "number" && Number.isFinite(value[k2])
11758
11920
  );
11759
11921
  }
@@ -11862,6 +12024,11 @@ ${claims(evidence)}`;
11862
12024
  if (result.outcome === "complete") changed(result);
11863
12025
  });
11864
12026
  },
12027
+ renew: (id, provider, method) => {
12028
+ void client.openConnect(this, () => details(this), provider, { id, method }).then((result) => {
12029
+ if (result.outcome === "complete") changed(result);
12030
+ });
12031
+ },
11865
12032
  // One at a time, each told as it goes: if a later one fails, the host still
11866
12033
  // hears of those that went and reads its records again.
11867
12034
  remove: async (ids2) => {
@@ -11869,6 +12036,10 @@ ${claims(evidence)}`;
11869
12036
  await client.disconnect(id);
11870
12037
  changed({ outcome: "removed", connectionId: id });
11871
12038
  }
12039
+ },
12040
+ mark: async (id, as2) => {
12041
+ await client.mark(id, as2);
12042
+ changed({ outcome: "marked", connectionId: id, as: as2 });
11872
12043
  }
11873
12044
  });
11874
12045
  } else managers.delete(this);
package/dist/version.d.ts CHANGED
@@ -7,4 +7,4 @@
7
7
  * output stays what tsc emitted and nothing has to be substituted into it. A version bump
8
8
  * changes this line with package.json.
9
9
  */
10
- export declare const version = "v0.2.0";
10
+ export declare const version = "v0.3.0";
package/dist/version.js CHANGED
@@ -7,4 +7,4 @@
7
7
  * output stays what tsc emitted and nothing has to be substituted into it. A version bump
8
8
  * changes this line with package.json.
9
9
  */
10
- export const version = 'v0.2.0';
10
+ export const version = 'v0.3.0';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bkazemi/verily",
3
- "version": "0.2.0",
3
+ "version": "0.3.0",
4
4
  "description": "Self-hosted account-to-account verification for Node.js",
5
5
  "type": "module",
6
6
  "license": "MIT",