@bkazemi/verily 0.6.0 → 0.7.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
@@ -9573,15 +9573,18 @@ var Verily = (() => {
9573
9573
  // src/browser.ts
9574
9574
  var browser_exports = {};
9575
9575
  __export(browser_exports, {
9576
+ Absent: () => Absent,
9576
9577
  Refused: () => Refused,
9577
9578
  accountsOf: () => accountsOf,
9578
9579
  attestationLabel: () => attestationLabel,
9579
9580
  dialogPath: () => dialogPath,
9580
9581
  dialogRoute: () => dialogRoute,
9582
+ expired: () => expired,
9581
9583
  externalId: () => externalId,
9582
9584
  externalIdGroups: () => externalIdGroups,
9583
9585
  externalLink: () => externalLink,
9584
9586
  externalName: () => externalName,
9587
+ externalSince: () => externalSince,
9585
9588
  fresh: () => fresh,
9586
9589
  freshnessMs: () => freshnessMs,
9587
9590
  init: () => init,
@@ -9716,6 +9719,8 @@ var Verily = (() => {
9716
9719
  // src/core/index.ts
9717
9720
  var Refused = class extends Error {
9718
9721
  };
9722
+ var Absent = class extends Refused {
9723
+ };
9719
9724
  function isArtifactProvider(provider) {
9720
9725
  return "verify" in provider;
9721
9726
  }
@@ -9729,15 +9734,19 @@ var Verily = (() => {
9729
9734
  return provider.method ?? "oauth";
9730
9735
  }
9731
9736
  var freshnessMs = 7 * 864e5;
9737
+ function expired(record2, now) {
9738
+ return record2.expiresAt <= now;
9739
+ }
9732
9740
  function status(connection, now, freshness = freshnessMs) {
9733
9741
  if (connection.revokedAt !== void 0) return "revoked";
9734
9742
  if (connection.retiredAt !== void 0) return "retired";
9735
- if (now >= connection.expiresAt) return "expired";
9743
+ if (expired(connection, now)) return "expired";
9736
9744
  const main = connection.attestations?.external[0];
9737
9745
  if (main && !fresh(main, now, freshness)) return "unconfirmed";
9738
9746
  return "verified";
9739
9747
  }
9740
9748
  function fresh(attestation, now, freshness = freshnessMs) {
9749
+ if (attestation.absentAt !== void 0) return false;
9741
9750
  return !attestation.artifactUrl || attestation.hosted === true || freshness === Infinity || now < attestation.confirmedAt + freshness;
9742
9751
  }
9743
9752
  function lastProved(evidence) {
@@ -9747,7 +9756,7 @@ var Verily = (() => {
9747
9756
  function statusLabel(evidence, now) {
9748
9757
  if (evidence.status === "revoked") return "Revoked";
9749
9758
  if (evidence.status === "retired") return "Retired";
9750
- if (evidence.status === "expired" || evidence.expiresAt <= now) return "Expired";
9759
+ if (evidence.status === "expired" || expired(evidence, now)) return "Expired";
9751
9760
  return evidence.status === "unconfirmed" ? "Unconfirmed" : "Verified";
9752
9761
  }
9753
9762
  function place(account) {
@@ -9805,6 +9814,9 @@ var Verily = (() => {
9805
9814
  function externalIdGroups(external) {
9806
9815
  return external.kind === "key" ? external.id.match(/.{1,4}/g) ?? void 0 : void 0;
9807
9816
  }
9817
+ function externalSince(external, day) {
9818
+ return typeof external.createdAt === "number" && Number.isFinite(external.createdAt) ? `Joined ${day(external.createdAt)}` : void 0;
9819
+ }
9808
9820
  function externalLink(external) {
9809
9821
  return external.kind === "mailbox" ? void 0 : external.profileUrl;
9810
9822
  }
@@ -10516,7 +10528,7 @@ ${claims(evidence)}`;
10516
10528
  }
10517
10529
 
10518
10530
  // src/version.ts
10519
- var version = "v0.6.0";
10531
+ var version = "v0.7.0";
10520
10532
 
10521
10533
  // src/browser/evidence-dialog.ts
10522
10534
  function stampLink() {
@@ -10554,9 +10566,12 @@ ${claims(evidence)}`;
10554
10566
  .spinner { width: 14px; height: 14px; border: 2px solid currentColor; border-right-color: transparent; border-radius: 50%; animation: spin .7s linear infinite; }
10555
10567
  @keyframes spin { to { transform: rotate(360deg); } }
10556
10568
  @media (prefers-reduced-motion: reduce) { .spinner { animation: none; } }
10557
- .caution { display: inline-block; margin-left: 4px; color: #a15c00; cursor: help; vertical-align: -1.5px; }
10558
- .caution svg { display: block; width: 12px; height: 12px; }
10559
- .bad { color: #b3261e; font-weight: 650; text-decoration: underline dotted; text-underline-offset: 3px; cursor: help; }
10569
+ /* The "signed" pill after the verifier's name, one size smaller than the line it sits on. */
10570
+ .summary .signed { display: inline-block; margin-left: 5px; padding: 0 6px; border: 1px solid #cfdcd3; border-radius: 999px; font-size: 10px; font-weight: 550; line-height: 1.3; text-decoration: none; vertical-align: 1px; }
10571
+ .summary a.signed:hover { background: #f2f5f1; }
10572
+ .summary .signed.bad { border-color: #b3261e; color: #b3261e; font-weight: 650; cursor: help; }
10573
+ .caution { display: inline-block; margin-left: 3px; color: #a15c00; vertical-align: -1.5px; }
10574
+ .caution svg { display: block; width: 10px; height: 10px; }
10560
10575
  .account { padding: 14px 16px; border: 1px solid #e0e6df; border-radius: 10px; margin-top: 12px; }
10561
10576
  .account h3 { display: flex; align-items: center; gap: 6px; margin: 0 0 3px; color: #6b786f; font-size: 11px; font-weight: 550; }
10562
10577
  .account a, .account strong { font-weight: 650; font-size: 14px; }
@@ -10572,7 +10587,13 @@ ${claims(evidence)}`;
10572
10587
  .listing.preferred { border-color: #245f43; color: #245f43; }
10573
10588
  /* Quiet, as its pill is: the surface and the name step back, and the controls do not. */
10574
10589
  .account.retired { background: #f6f8f5; }
10575
- .account.retired > a, .account.retired > strong { color: #6b786f; }
10590
+ .account.retired > a, .account.retired > strong, .account.retired > .named > a, .account.retired > .named > strong { color: #6b786f; }
10591
+ /* The name, then a dot and the account's creation date. The date wraps under a long name. */
10592
+ /* Clipped 4px left of the text, which hides the dot when the date wraps to a new line. */
10593
+ .named { display: flex; flex-wrap: wrap; align-items: baseline; gap: 0 14px; margin-left: -4px; padding-left: 4px; overflow-x: clip; }
10594
+ .since { position: relative; white-space: nowrap; }
10595
+ /* The dot sits in the gap before the date. */
10596
+ .since::before { content: "\xB7"; position: absolute; left: -7px; transform: translateX(-50%); }
10576
10597
  .account.retired .mark { opacity: .45; }
10577
10598
  .group { margin: 20px 0 0; color: #6b786f; font-size: 11px; font-weight: 550; }
10578
10599
  summary.group { display: flex; align-items: center; gap: 4px; width: fit-content; border-radius: 4px; list-style: none; cursor: pointer; }
@@ -10714,12 +10735,34 @@ ${claims(evidence)}`;
10714
10735
  return new Date(time).toLocaleString(void 0, { dateStyle: "medium", timeStyle: "short" });
10715
10736
  }
10716
10737
  function accountCard(heading, name, reference, url, ...extra) {
10738
+ return side(heading, name, reference, url, void 0, extra);
10739
+ }
10740
+ function namedCard(heading, external, ...extra) {
10741
+ return side(
10742
+ heading,
10743
+ externalName(external),
10744
+ // A mailbox's address or a domain is its name already, so there is no second identifier.
10745
+ externalIdGroups(external) ?? externalId(external),
10746
+ externalLink(external),
10747
+ // In UTC, so the day matches the one the verifier's own pages print.
10748
+ externalSince(
10749
+ external,
10750
+ (time) => new Date(time).toLocaleDateString(void 0, { dateStyle: "medium", timeZone: "UTC" })
10751
+ ),
10752
+ extra
10753
+ );
10754
+ }
10755
+ function side(heading, name, reference, url, since, extra) {
10717
10756
  const card = node("section", "", "account");
10718
10757
  const title = node("h3");
10719
10758
  const value = node(url ? "a" : "strong", name);
10720
10759
  title.append(...heading);
10721
10760
  if (value instanceof HTMLAnchorElement) outward(value, url);
10722
- card.append(title, value);
10761
+ if (since) {
10762
+ const named = node("div", "", "named");
10763
+ named.append(value, node("span", since, "muted since"));
10764
+ card.append(title, named);
10765
+ } else card.append(title, value);
10723
10766
  if (typeof reference === "string") card.append(node("div", reference, "muted reference"));
10724
10767
  else if (reference) {
10725
10768
  const groups = node("div", "", "muted reference fingerprint");
@@ -10868,22 +10911,22 @@ ${claims(evidence)}`;
10868
10911
  }
10869
10912
  function signedMark(evidence, later, warned) {
10870
10913
  const mark2 = node("span");
10871
- const link = outward(node("a", "signed"), `${evidence.evidenceUrl}#signed`);
10914
+ const link = outward(node("a", "signed", "signed"), `${evidence.evidenceUrl}#signed`);
10872
10915
  const see = "See the signature (opens in a new tab)";
10873
10916
  const settle = (results) => {
10874
10917
  const first = results[0];
10875
10918
  if (results.some((result) => result.state === "invalid")) {
10876
- const warning = node("span", "invalid signature", "bad");
10919
+ const warning = node("span", "bad signature", "signed bad");
10877
10920
  warning.setAttribute("role", "alert");
10878
10921
  warning.title = `This record does not match the signature ${evidence.verifierName} put on it, so it may have been altered. Do not rely on it.`;
10879
- mark2.replaceChildren(document.createTextNode(" \xB7 "), warning);
10922
+ mark2.replaceChildren(warning);
10880
10923
  warned();
10881
10924
  return;
10882
10925
  }
10883
10926
  if (first?.state === "valid" && results.every((result) => result.state === "valid")) {
10884
- link.textContent = "signed \u2713";
10927
+ link.textContent = "signed";
10885
10928
  link.title = `Signature checked in this browser against the keys ${new URL(evidence.evidenceUrl).host} publishes (key ${first.keyId}). ${see}`;
10886
- mark2.replaceChildren(document.createTextNode(" \xB7 "), link);
10929
+ mark2.replaceChildren(link);
10887
10930
  return;
10888
10931
  }
10889
10932
  const why = results.find((result) => result.state === "unchecked");
@@ -10894,8 +10937,9 @@ ${claims(evidence)}`;
10894
10937
  caution.setAttribute("aria-label", reason);
10895
10938
  caution.append(cautionMark());
10896
10939
  link.textContent = "signed";
10940
+ link.append(caution);
10897
10941
  link.title = `${reason} ${see}`;
10898
- mark2.replaceChildren(document.createTextNode(" \xB7 "), link, caution);
10942
+ mark2.replaceChildren(link);
10899
10943
  if (why) later(() => void signatures(evidence).then(settle));
10900
10944
  };
10901
10945
  void signatures(evidence).then(settle);
@@ -10981,14 +11025,11 @@ ${claims(evidence)}`;
10981
11025
  ];
10982
11026
  if (fold) bar.append(foldToggle([...methods, dates], fold), ...row);
10983
11027
  const logo2 = providerMark(evidence.provider, evidence.attestations.external[0].method);
10984
- const card = accountCard(
11028
+ const card = namedCard(
10985
11029
  // The mark and the name, or just the name. A mark that falls back to writing the name
10986
11030
  // would print it twice here, since this heading writes it either way.
10987
11031
  logo2 ? [logo2, document.createTextNode(provider)] : [document.createTextNode(provider)],
10988
- externalName(evidence.external),
10989
- // A mailbox's address or a domain is its name already, so there is no second identifier.
10990
- externalIdGroups(evidence.external) ?? externalId(evidence.external),
10991
- externalLink(evidence.external),
11032
+ evidence.external,
10992
11033
  // Status first, then how it was shown, then when. The proof explains the state
10993
11034
  // above it, so it cannot sit before that state has been given.
10994
11035
  summary,
@@ -11641,11 +11682,9 @@ ${record2.external.id}`;
11641
11682
  }
11642
11683
  function approve(flow) {
11643
11684
  const logo2 = providerMark(flow.provider.id, flow.provider.method);
11644
- const external = accountCard(
11685
+ const external = namedCard(
11645
11686
  logo2 ? [logo2, document.createTextNode(flow.provider.name)] : [document.createTextNode(flow.provider.name)],
11646
- externalName(flow.external),
11647
- externalIdGroups(flow.external) ?? externalId(flow.external),
11648
- externalLink(flow.external)
11687
+ flow.external
11649
11688
  );
11650
11689
  const parts = [subjectCard(flow.local), linkMark(), external];
11651
11690
  const choice = node("fieldset");
@@ -12192,7 +12231,7 @@ ${record2.external.id}`;
12192
12231
  (k2) => typeof value.local[k2] === "string"
12193
12232
  ) && ["id", "handle", "profileUrl"].every(
12194
12233
  (k2) => typeof value.external[k2] === "string"
12195
- ) && (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
12234
+ ) && (value.local.profileUrl === void 0 || typeof value.local.profileUrl === "string") && (value.external.createdAt === void 0 || typeof value.external.createdAt === "number" && Number.isFinite(value.external.createdAt)) && // A signed record lives beside the record it was made from and nowhere else, since the
12196
12235
  // keys it is checked against are read from where the record lives.
12197
12236
  (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", "domain"].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.
12198
12237
  (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(
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.6.0";
10
+ export declare const version = "v0.7.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.6.0';
10
+ export const version = 'v0.7.0';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bkazemi/verily",
3
- "version": "0.6.0",
3
+ "version": "0.7.0",
4
4
  "description": "Self-hosted account-to-account verification for Node.js",
5
5
  "type": "module",
6
6
  "license": "MIT",