@tokenoftrust/storefront-runner 1.4.0 → 1.4.2-rc.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.
Files changed (193) hide show
  1. package/apps/storefront/astro.config.mjs +17 -1
  2. package/apps/storefront/integrations/materialize-guard.mjs +56 -0
  3. package/apps/storefront/migrations-apps/0001_woozy_lyja.sql +22 -0
  4. package/apps/storefront/migrations-apps/0002_good_switch.sql +26 -0
  5. package/apps/storefront/migrations-apps/0003_mute_marauders.sql +12 -0
  6. package/apps/storefront/migrations-apps/meta/0001_snapshot.json +990 -0
  7. package/apps/storefront/migrations-apps/meta/0002_snapshot.json +1160 -0
  8. package/apps/storefront/migrations-apps/meta/0003_snapshot.json +1235 -0
  9. package/apps/storefront/migrations-apps/meta/_journal.json +21 -0
  10. package/apps/storefront/package.json +0 -1
  11. package/apps/storefront/public/js/dashboard-team.js +38 -2
  12. package/apps/storefront/src/components/Seo.astro +65 -1
  13. package/apps/storefront/src/components/admin/AdminBlogDetailRail.astro +878 -0
  14. package/apps/storefront/src/components/admin/AdminBlogTab.astro +1432 -0
  15. package/apps/storefront/src/components/admin/AdminCustomersTab.astro +3 -7
  16. package/apps/storefront/src/components/admin/AdminPublishTab.astro +1756 -1382
  17. package/apps/storefront/src/components/admin/AdminSubscriptionsTab.astro +1 -3
  18. package/apps/storefront/src/components/blog/BlogPaywall.astro +87 -0
  19. package/apps/storefront/src/components/blog/PostAccessBadge.astro +43 -0
  20. package/apps/storefront/src/components/blog/PostGrid.astro +57 -0
  21. package/apps/storefront/src/components/blog/ReactionBar.astro +214 -0
  22. package/apps/storefront/src/layouts/Layout.astro +48 -3
  23. package/apps/storefront/src/lib/activity/alerts.ts +426 -0
  24. package/apps/storefront/src/lib/activity/changeActorAttribution.ts +85 -0
  25. package/apps/storefront/src/lib/activity/deployVersion.ts +120 -0
  26. package/apps/storefront/src/lib/activity/ingest.ts +188 -0
  27. package/apps/storefront/src/lib/activity/ingestAuth.ts +105 -0
  28. package/apps/storefront/src/lib/activity/killSwitch.ts +80 -0
  29. package/apps/storefront/src/lib/activity/query.ts +403 -0
  30. package/apps/storefront/src/lib/activity/recordActivity.ts +101 -0
  31. package/apps/storefront/src/lib/activity/store.ts +120 -0
  32. package/apps/storefront/src/lib/activity/uiActor.ts +150 -0
  33. package/apps/storefront/src/lib/activity/workerCommit.ts +70 -0
  34. package/apps/storefront/src/lib/admin/adminShell.ts +290 -0
  35. package/apps/storefront/src/lib/admin/ai/approvalMode.ts +2 -3
  36. package/apps/storefront/src/lib/admin/ai/audit.ts +3 -5
  37. package/apps/storefront/src/lib/admin/checkoutStyleInput.ts +7 -7
  38. package/apps/storefront/src/lib/admin/checkoutStyleTarget.ts +3 -3
  39. package/apps/storefront/src/lib/admin/orderClient.ts +3 -5
  40. package/apps/storefront/src/lib/admin/services/orders.ts +17 -19
  41. package/apps/storefront/src/lib/admin/viewmodels/aiWorkflows.ts +4 -6
  42. package/apps/storefront/src/lib/admin/viewmodels/settings.ts +1 -1
  43. package/apps/storefront/src/lib/apps/adminService.ts +4 -4
  44. package/apps/storefront/src/lib/apps/adminSession.ts +53 -44
  45. package/apps/storefront/src/lib/apps/apiAuth.ts +2 -2
  46. package/apps/storefront/src/lib/apps/apiRoute.ts +2 -2
  47. package/apps/storefront/src/lib/apps/catalogMapper.ts +1 -1
  48. package/apps/storefront/src/lib/apps/credentials.ts +2 -2
  49. package/apps/storefront/src/lib/apps/gatewayKeys.ts +4 -4
  50. package/apps/storefront/src/lib/apps/healthAggregate.ts +5 -5
  51. package/apps/storefront/src/lib/apps/orders/attributionService.ts +2 -2
  52. package/apps/storefront/src/lib/apps/orders/customerHash.ts +1 -1
  53. package/apps/storefront/src/lib/apps/orders/foxyOrderClient.ts +12 -12
  54. package/apps/storefront/src/lib/apps/orders/idempotency.ts +7 -7
  55. package/apps/storefront/src/lib/apps/orders/orderForwardReceiver.ts +1 -1
  56. package/apps/storefront/src/lib/apps/orders/orderMapper.ts +2 -2
  57. package/apps/storefront/src/lib/apps/orders/ordersStore.ts +6 -6
  58. package/apps/storefront/src/lib/apps/registryService.ts +6 -6
  59. package/apps/storefront/src/lib/apps/scopes.ts +2 -2
  60. package/apps/storefront/src/lib/apps/tokenIssuer.ts +4 -4
  61. package/apps/storefront/src/lib/apps/tokenVerifier.ts +6 -6
  62. package/apps/storefront/src/lib/apps/widgets/eligibility.ts +2 -2
  63. package/apps/storefront/src/lib/apps/widgets/frameProps.ts +3 -3
  64. package/apps/storefront/src/lib/apps/widgets/launchToken.ts +4 -4
  65. package/apps/storefront/src/lib/apps/widgets/placements.ts +2 -2
  66. package/apps/storefront/src/lib/apps/widgets/renderSlot.ts +1 -1
  67. package/apps/storefront/src/lib/auth/adminEntry.ts +9 -9
  68. package/apps/storefront/src/lib/auth/identityToken.ts +6 -14
  69. package/apps/storefront/src/lib/auth/loginGate.ts +75 -13
  70. package/apps/storefront/src/lib/auth/mcpClientAssertion.ts +6 -4
  71. package/apps/storefront/src/lib/auth/operatorSession.ts +113 -0
  72. package/apps/storefront/src/lib/auth/route.ts +44 -4
  73. package/apps/storefront/src/lib/auth/session.ts +7 -8
  74. package/apps/storefront/src/lib/auth/totAccessClient.ts +8 -18
  75. package/apps/storefront/src/lib/basePath.ts +9 -2
  76. package/apps/storefront/src/lib/blog/access.ts +29 -0
  77. package/apps/storefront/src/lib/blog/collection.ts +313 -0
  78. package/apps/storefront/src/lib/blog/markdown.ts +174 -0
  79. package/apps/storefront/src/lib/blog/provider.ts +5 -0
  80. package/apps/storefront/src/lib/blog/reactions.ts +87 -0
  81. package/apps/storefront/src/lib/blog/rss.ts +92 -0
  82. package/apps/storefront/src/lib/blog/teaser.ts +83 -0
  83. package/apps/storefront/src/lib/blog/types.ts +34 -0
  84. package/apps/storefront/src/lib/blog/viewCounts.ts +243 -0
  85. package/apps/storefront/src/lib/d1/catalog.ts +2 -2
  86. package/apps/storefront/src/lib/d1/schema-apps.ts +147 -14
  87. package/apps/storefront/src/lib/dev/activityIngestToken.ts +2 -4
  88. package/apps/storefront/src/lib/dev/activityStore.ts +3 -5
  89. package/apps/storefront/src/lib/dev/apiBase.ts +1 -4
  90. package/apps/storefront/src/lib/dev/cockpitStore.ts +1 -9
  91. package/apps/storefront/src/lib/dev/devDraft.ts +1 -1
  92. package/apps/storefront/src/lib/dev/previewStatus.ts +9 -21
  93. package/apps/storefront/src/lib/dev/rendezvousBroker.ts +9 -24
  94. package/apps/storefront/src/lib/edgeCache.ts +17 -0
  95. package/apps/storefront/src/lib/env.ts +51 -0
  96. package/apps/storefront/src/lib/http/fetchTransport.ts +63 -0
  97. package/apps/storefront/src/lib/i18n.ts +25 -0
  98. package/apps/storefront/src/lib/jsonld.ts +118 -0
  99. package/apps/storefront/src/lib/monitoring/manifest.ts +11 -11
  100. package/apps/storefront/src/lib/newsletter/confirmationEmail.ts +30 -0
  101. package/apps/storefront/src/lib/newsletter/consent.ts +23 -0
  102. package/apps/storefront/src/lib/newsletter/digest.ts +117 -0
  103. package/apps/storefront/src/lib/newsletter/resendClient.ts +79 -0
  104. package/apps/storefront/src/lib/newsletter/send.ts +265 -0
  105. package/apps/storefront/src/lib/newsletter/subscribers.ts +156 -0
  106. package/apps/storefront/src/lib/publish/adminPublishTab.ts +3519 -0
  107. package/apps/storefront/src/lib/publish/apex-readiness.ts +41 -18
  108. package/apps/storefront/src/lib/publish/dispatchHealth.ts +5 -7
  109. package/apps/storefront/src/lib/publish/domainState.ts +22 -13
  110. package/apps/storefront/src/lib/publish/panelPolling.ts +78 -0
  111. package/apps/storefront/src/lib/publish/shipWorkspace.ts +100 -42
  112. package/apps/storefront/src/lib/publish/stageBundleUpload.ts +215 -0
  113. package/apps/storefront/src/lib/rate/kvWindow.ts +53 -0
  114. package/apps/storefront/src/lib/search/index.ts +2 -2
  115. package/apps/storefront/src/lib/seo/alternates.ts +42 -0
  116. package/apps/storefront/src/lib/seo/meta.ts +65 -0
  117. package/apps/storefront/src/lib/social/golive.ts +212 -0
  118. package/apps/storefront/src/lib/social/notify.ts +32 -0
  119. package/apps/storefront/src/lib/social/tokenStore.ts +171 -0
  120. package/apps/storefront/src/lib/the-build/provider.ts +27 -0
  121. package/apps/storefront/src/lib/the-build/readingTime.ts +35 -0
  122. package/apps/storefront/src/lib/the-build/toc.ts +95 -0
  123. package/apps/storefront/src/lib/tot/ToTClient.ts +1 -1
  124. package/apps/storefront/src/lib/tot/d1Client.ts +2 -2
  125. package/apps/storefront/src/lib/tot/totClientInterface.ts +3 -4
  126. package/apps/storefront/src/lib/webhooks/deliveryStore.ts +16 -17
  127. package/apps/storefront/src/middleware/index.ts +130 -2
  128. package/apps/storefront/src/pages/admin/ops-timeline.astro +420 -0
  129. package/apps/storefront/src/pages/admin.astro +52 -1206
  130. package/apps/storefront/src/pages/api/activity.ts +137 -0
  131. package/apps/storefront/src/pages/api/admin/activity-alerts.ts +73 -0
  132. package/apps/storefront/src/pages/api/apps/admin/credentials/rotate.ts +27 -1
  133. package/apps/storefront/src/pages/api/apps/admin/install.ts +26 -1
  134. package/apps/storefront/src/pages/api/apps/admin/resume.ts +24 -1
  135. package/apps/storefront/src/pages/api/apps/admin/suspend.ts +24 -1
  136. package/apps/storefront/src/pages/api/apps/admin/uninstall.ts +25 -1
  137. package/apps/storefront/src/pages/api/apps/admin/update.ts +24 -1
  138. package/apps/storefront/src/pages/api/apps/admin/webhooks/deliveries/[deliveryId]/replay.ts +11 -0
  139. package/apps/storefront/src/pages/api/apps/internal/order-forward.ts +11 -0
  140. package/apps/storefront/src/pages/api/apps/v1/attribution.ts +20 -0
  141. package/apps/storefront/src/pages/api/apps/v1/webhooks/deliveries/[deliveryId]/replay.ts +12 -0
  142. package/apps/storefront/src/pages/api/blog/[collection]/[slug]/react.ts +104 -0
  143. package/apps/storefront/src/pages/api/cache-purge.ts +11 -0
  144. package/apps/storefront/src/pages/api/dashboard/enter-vendor.ts +30 -0
  145. package/apps/storefront/src/pages/api/newsletter/[collection]/subscribe.ts +146 -0
  146. package/apps/storefront/src/pages/api/newsletter/confirm.ts +75 -0
  147. package/apps/storefront/src/pages/api/newsletter/unsubscribe.ts +90 -0
  148. package/apps/storefront/src/pages/api/publish/stage-bundle.ts +70 -0
  149. package/apps/storefront/src/pages/api/rum/vitals.ts +21 -2
  150. package/apps/storefront/src/pages/auth/login.astro +5 -4
  151. package/apps/storefront/src/pages/blog/[slug].astro +96 -16
  152. package/apps/storefront/src/pages/blog/author/[author].astro +140 -0
  153. package/apps/storefront/src/pages/blog/category/[category].astro +67 -0
  154. package/apps/storefront/src/pages/blog/index.astro +2 -0
  155. package/apps/storefront/src/pages/blog/tag/[tag].astro +65 -0
  156. package/apps/storefront/src/pages/cockpit.astro +74 -12
  157. package/apps/storefront/src/pages/dashboard/[appDomain]/team.astro +15 -11
  158. package/apps/storefront/src/pages/search.astro +1 -1
  159. package/apps/storefront/src/pages/sitemap.xml.ts +20 -0
  160. package/apps/storefront/src/pages/the-build/[slug].astro +129 -0
  161. package/apps/storefront/src/pages/the-build/index.astro +146 -0
  162. package/apps/storefront/src/pages/the-build/rss.xml.ts +33 -0
  163. package/apps/storefront/src/styles/admin.css +1080 -0
  164. package/apps/storefront/tsconfig.json +5 -0
  165. package/package.json +1 -1
  166. package/packages/public-runtime/package.json +1 -0
  167. package/packages/public-runtime/src/activity/README.md +146 -0
  168. package/packages/public-runtime/src/activity/catalog.ts +553 -0
  169. package/packages/public-runtime/src/activity/event.ts +168 -0
  170. package/packages/public-runtime/src/activity/index.ts +16 -0
  171. package/packages/public-runtime/src/activity/redaction.ts +263 -0
  172. package/packages/public-runtime/src/candidate-index.ts +13 -0
  173. package/packages/public-runtime/src/catalog-d1.ts +1 -1
  174. package/packages/public-runtime/src/customization-preview.ts +25 -2
  175. package/packages/public-runtime/src/customization-runtime.ts +125 -3
  176. package/packages/public-runtime/src/customization-versioning.ts +10 -0
  177. package/packages/public-runtime/src/index.ts +7 -0
  178. package/packages/public-runtime/src/static-bundle.ts +357 -0
  179. package/packages/public-runtime/src/tenant.ts +36 -8
  180. package/scripts/build/copy-tenant-assets.mjs +14 -4
  181. package/scripts/dev/ai-edit.mjs +1 -1
  182. package/scripts/dev/checkout-watch.mjs +2 -2
  183. package/scripts/dev/file-browser.mjs +2 -4
  184. package/scripts/dev/file-writer.mjs +1 -1
  185. package/scripts/dev/git-status.mjs +2 -2
  186. package/scripts/dev/locate-handler.mjs +3 -3
  187. package/scripts/dev/port-check.mjs +3 -3
  188. package/scripts/dev/publish.mjs +5 -9
  189. package/scripts/dev/shot.mjs +1 -1
  190. package/scripts/dev/unified-diff.mjs +8 -3
  191. package/scripts/tot-dev.mjs +6 -9
  192. package/apps/storefront/src/lib/webhooks/signing.ts +0 -29
  193. package/apps/storefront/src/lib/webhooks/webhookSigningKey.ts +0 -146
@@ -8,6 +8,27 @@
8
8
  "when": 1784820107464,
9
9
  "tag": "0000_fast_millenium_guard",
10
10
  "breakpoints": true
11
+ },
12
+ {
13
+ "idx": 1,
14
+ "version": "6",
15
+ "when": 1787074116807,
16
+ "tag": "0001_woozy_lyja",
17
+ "breakpoints": true
18
+ },
19
+ {
20
+ "idx": 2,
21
+ "version": "6",
22
+ "when": 1787400126075,
23
+ "tag": "0002_good_switch",
24
+ "breakpoints": true
25
+ },
26
+ {
27
+ "idx": 3,
28
+ "version": "6",
29
+ "when": 1787403061681,
30
+ "tag": "0003_mute_marauders",
31
+ "breakpoints": true
11
32
  }
12
33
  ]
13
34
  }
@@ -28,7 +28,6 @@
28
28
  "@fontsource/space-mono": "5.3.0",
29
29
  "@storyblok/astro": "^10.0.0",
30
30
  "@tailwindcss/vite": "^4.3.1",
31
- "@tokenoftrust/private-apps-devkit": "*",
32
31
  "@tot/public-runtime": "*",
33
32
  "astro": "^7.0.3",
34
33
  "fuse.js": "^7.4.2",
@@ -42,11 +42,45 @@
42
42
  btn.title = "Re-send the sign-in email to " + m.developer;
43
43
  btn.addEventListener("click", () => resend(m.developer, btn));
44
44
  act.appendChild(btn);
45
+ if (m.inviteId) {
46
+ const revokeBtn = document.createElement("button");
47
+ revokeBtn.type = "button";
48
+ revokeBtn.className = "rowbtn";
49
+ revokeBtn.textContent = "Revoke";
50
+ revokeBtn.title = "Revoke " + m.developer + "'s access to this vendor";
51
+ revokeBtn.style.marginLeft = ".4rem";
52
+ revokeBtn.addEventListener("click", () => revoke(m.developer, m.inviteId, revokeBtn));
53
+ act.appendChild(revokeBtn);
54
+ }
45
55
  tr.appendChild(dev); tr.appendChild(roles); tr.appendChild(act);
46
56
  membersBody.appendChild(tr);
47
57
  }
48
58
  }
49
59
 
60
+ async function revoke(email, inviteId, btn) {
61
+ if (!confirm("Revoke " + email + "'s access to this vendor?")) return;
62
+ if (btn) btn.disabled = true;
63
+ showMsg("", "Revoking " + email + "'s access…");
64
+ try {
65
+ const res = await fetch("/api/grants/team-revoke", {
66
+ method: "POST",
67
+ headers: { "content-type": "application/json", accept: "application/json" },
68
+ body: JSON.stringify({ tenant, inviteId, email }),
69
+ });
70
+ const body = await res.json().catch(() => ({}));
71
+ if (res.ok) {
72
+ showMsg("ok", "Revoked " + email + "'s access.");
73
+ loadMembers();
74
+ } else {
75
+ showMsg("err", body.error || ("Couldn't revoke (HTTP " + res.status + ")."));
76
+ if (btn) btn.disabled = false;
77
+ }
78
+ } catch (e) {
79
+ showMsg("err", "Couldn't revoke: " + (e && e.message ? e.message : e));
80
+ if (btn) btn.disabled = false;
81
+ }
82
+ }
83
+
50
84
  async function resend(email, btn) {
51
85
  if (btn) btn.disabled = true;
52
86
  showMsg("", "Re-sending the sign-in email to " + email + "…");
@@ -104,8 +138,10 @@
104
138
  btn.disabled = true;
105
139
  showMsg("", "Sending…");
106
140
  try {
107
- // The role selector is present only for ToT staff (#8453); members are
108
- // developer-only. tot20 ignores a non-staff role, so sending it is harmless.
141
+ // The role selector always shows Developer + Contributor (a plain member may
142
+ // self-request Contributor tot20 honors it, handoff
143
+ // 2026-08-22-tot20-contributor-role); Admin/Owner render only for ToT staff
144
+ // (#8453) — tot20 ignores those two from a plain member and pins to developer.
109
145
  const roleEl = $("role");
110
146
  const role = roleEl && roleEl.value ? roleEl.value : undefined;
111
147
  const noteEl = $("note");
@@ -3,6 +3,9 @@
3
3
  * <Seo> — per-page title/meta, Open Graph, Twitter card, canonical, JSON-LD.
4
4
  * (brief §8). Tenant-aware: OG image + site name come from the resolved tenant.
5
5
  */
6
+ import { articleSeoMetaTags, type ArticleMeta } from "@/lib/seo/meta.js";
7
+ import { withXDefault, type Alternate } from "@/lib/seo/alternates.js";
8
+
6
9
  interface JsonLd {
7
10
  [key: string]: unknown;
8
11
  }
@@ -17,6 +20,25 @@ interface Props {
17
20
  noindex?: boolean;
18
21
  /** One or more JSON-LD graphs (Product, BreadcrumbList, Organization…). */
19
22
  jsonLd?: JsonLd | JsonLd[];
23
+ /** Alternate RSS/Atom feeds this page advertises (e.g. a collection's feed). */
24
+ feeds?: { title: string; href: string }[];
25
+ // --- B1.6 article SEO hardening (all additive/optional) ---
26
+ /** Open Graph `article:*` meta; emitted only when `ogType === "article"`. */
27
+ article?: ArticleMeta;
28
+ /** og:image:alt — accessible description of the OG image. */
29
+ imageAlt?: string;
30
+ imageWidth?: number;
31
+ imageHeight?: number;
32
+ twitterSite?: string;
33
+ twitterCreator?: string;
34
+ /** Syndication: when set, REPLACES the derived self-canonical (rel=canonical
35
+ * + og:url) so search engines point at the original. */
36
+ canonicalOverride?: string;
37
+ /** I2 — per-variant `hreflang` alternates for a translated article (self +
38
+ * siblings). When present and non-empty, emits one `<link rel="alternate">`
39
+ * per entry PLUS an `x-default`. Absent/empty ⇒ no alternate links (a
40
+ * singleton post is unchanged). */
41
+ alternates?: Alternate[];
20
42
  }
21
43
 
22
44
  const {
@@ -27,10 +49,29 @@ const {
27
49
  ogImage,
28
50
  noindex = false,
29
51
  jsonLd,
52
+ feeds = [],
53
+ article,
54
+ imageAlt,
55
+ imageWidth,
56
+ imageHeight,
57
+ twitterSite,
58
+ twitterCreator,
59
+ canonicalOverride,
60
+ alternates = [],
30
61
  } = Astro.props;
31
62
 
32
63
  const { tenant, canonicalBase } = Astro.locals;
33
- const canonical = new URL(path, canonicalBase + "/").toString();
64
+ const canonical =
65
+ canonicalOverride ?? new URL(path, canonicalBase + "/").toString();
66
+ const articleMeta = articleSeoMetaTags({
67
+ ogType,
68
+ article,
69
+ imageAlt,
70
+ imageWidth,
71
+ imageHeight,
72
+ twitterSite,
73
+ twitterCreator,
74
+ });
34
75
  // Don't double-append the brand: merchant SEO titles (title_tag) often already
35
76
  // end with the store name.
36
77
  const fullTitle = title.includes(tenant.displayName)
@@ -41,6 +82,7 @@ const image = ogImage
41
82
  : new URL(tenant.theme_tokens?.brand?.ogImage ?? "/brand/northwind-og.svg", canonicalBase + "/").toString();
42
83
 
43
84
  const graphs = jsonLd ? (Array.isArray(jsonLd) ? jsonLd : [jsonLd]) : [];
85
+ const alternateLinks = withXDefault(alternates);
44
86
  ---
45
87
 
46
88
  <title>{fullTitle}</title>
@@ -48,6 +90,18 @@ const graphs = jsonLd ? (Array.isArray(jsonLd) ? jsonLd : [jsonLd]) : [];
48
90
  <link rel="canonical" href={canonical} />
49
91
  {noindex && <meta name="robots" content="noindex,nofollow" />}
50
92
 
93
+ {
94
+ feeds.map((f) => (
95
+ <link rel="alternate" type="application/rss+xml" title={f.title} href={f.href} />
96
+ ))
97
+ }
98
+
99
+ {
100
+ alternateLinks.map((a) => (
101
+ <link rel="alternate" hreflang={a.hreflang} href={a.href} />
102
+ ))
103
+ }
104
+
51
105
  <meta property="og:type" content={ogType} />
52
106
  <meta property="og:site_name" content={tenant.displayName} />
53
107
  <meta property="og:title" content={fullTitle} />
@@ -60,6 +114,16 @@ const graphs = jsonLd ? (Array.isArray(jsonLd) ? jsonLd : [jsonLd]) : [];
60
114
  {description && <meta name="twitter:description" content={description} />}
61
115
  <meta name="twitter:image" content={image} />
62
116
 
117
+ {
118
+ articleMeta.map((t) =>
119
+ t.property ? (
120
+ <meta property={t.property} content={t.content} />
121
+ ) : (
122
+ <meta name={t.name} content={t.content} />
123
+ ),
124
+ )
125
+ }
126
+
63
127
  {
64
128
  graphs.map((g) => (
65
129
  <script