@forge-connect/react 1.0.12 → 1.0.13

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.d.cts CHANGED
@@ -119,7 +119,7 @@ interface AuthState {
119
119
  user: User | null;
120
120
  accessToken: string | null;
121
121
  }
122
- type ModalStep = 'method-select' | 'email-login' | 'email-register' | 'email-otp' | 'wallet-connect' | 'oauth' | 'forgot-password' | 'verify-2fa' | 'success' | 'error';
122
+ type ModalStep = 'method-select' | 'email-login' | 'email-register' | 'email-otp' | 'wallet-connect' | 'oauth' | 'forgot-password' | 'verify-2fa' | 'matrica-migration' | 'success' | 'error';
123
123
  interface ModalState {
124
124
  isOpen: boolean;
125
125
  step: ModalStep;
@@ -278,6 +278,28 @@ declare function createApiClient(apiUrl: string): {
278
278
  challengeToken?: string;
279
279
  userId?: string;
280
280
  }>;
281
+ getMatricaMigration(token: string): Promise<{
282
+ matricaUsername: string | null;
283
+ matricaDisplayName: string | null;
284
+ conflicts: {
285
+ wallets: {
286
+ address: string;
287
+ }[];
288
+ socials: {
289
+ provider: "twitter" | "discord" | "telegram";
290
+ externalName: string;
291
+ }[];
292
+ email: {
293
+ email: string;
294
+ } | null;
295
+ };
296
+ }>;
297
+ resolveMatricaMigration(token: string, migrate: boolean): Promise<{
298
+ code?: string;
299
+ accessToken?: string;
300
+ requires2FA?: boolean;
301
+ challengeToken?: string;
302
+ }>;
281
303
  createLinkIntent(token: string): Promise<{
282
304
  intentToken: string;
283
305
  }>;
@@ -506,6 +528,24 @@ interface ForgeConnectContextValue {
506
528
  challengeToken: string | null;
507
529
  verify2FA: (code: string) => Promise<void>;
508
530
  verifyRecoveryCode: (code: string) => Promise<void>;
531
+ matricaMigration: {
532
+ token: string;
533
+ matricaUsername: string | null;
534
+ matricaDisplayName: string | null;
535
+ conflicts: {
536
+ wallets: {
537
+ address: string;
538
+ }[];
539
+ socials: {
540
+ provider: 'twitter' | 'discord' | 'telegram';
541
+ externalName: string;
542
+ }[];
543
+ email: {
544
+ email: string;
545
+ } | null;
546
+ };
547
+ } | null;
548
+ resolveMatricaMigration: (migrate: boolean) => Promise<void>;
509
549
  openModal: () => void;
510
550
  closeModal: () => void;
511
551
  setModalStep: (step: ModalState['step']) => void;
package/dist/index.d.ts CHANGED
@@ -119,7 +119,7 @@ interface AuthState {
119
119
  user: User | null;
120
120
  accessToken: string | null;
121
121
  }
122
- type ModalStep = 'method-select' | 'email-login' | 'email-register' | 'email-otp' | 'wallet-connect' | 'oauth' | 'forgot-password' | 'verify-2fa' | 'success' | 'error';
122
+ type ModalStep = 'method-select' | 'email-login' | 'email-register' | 'email-otp' | 'wallet-connect' | 'oauth' | 'forgot-password' | 'verify-2fa' | 'matrica-migration' | 'success' | 'error';
123
123
  interface ModalState {
124
124
  isOpen: boolean;
125
125
  step: ModalStep;
@@ -278,6 +278,28 @@ declare function createApiClient(apiUrl: string): {
278
278
  challengeToken?: string;
279
279
  userId?: string;
280
280
  }>;
281
+ getMatricaMigration(token: string): Promise<{
282
+ matricaUsername: string | null;
283
+ matricaDisplayName: string | null;
284
+ conflicts: {
285
+ wallets: {
286
+ address: string;
287
+ }[];
288
+ socials: {
289
+ provider: "twitter" | "discord" | "telegram";
290
+ externalName: string;
291
+ }[];
292
+ email: {
293
+ email: string;
294
+ } | null;
295
+ };
296
+ }>;
297
+ resolveMatricaMigration(token: string, migrate: boolean): Promise<{
298
+ code?: string;
299
+ accessToken?: string;
300
+ requires2FA?: boolean;
301
+ challengeToken?: string;
302
+ }>;
281
303
  createLinkIntent(token: string): Promise<{
282
304
  intentToken: string;
283
305
  }>;
@@ -506,6 +528,24 @@ interface ForgeConnectContextValue {
506
528
  challengeToken: string | null;
507
529
  verify2FA: (code: string) => Promise<void>;
508
530
  verifyRecoveryCode: (code: string) => Promise<void>;
531
+ matricaMigration: {
532
+ token: string;
533
+ matricaUsername: string | null;
534
+ matricaDisplayName: string | null;
535
+ conflicts: {
536
+ wallets: {
537
+ address: string;
538
+ }[];
539
+ socials: {
540
+ provider: 'twitter' | 'discord' | 'telegram';
541
+ externalName: string;
542
+ }[];
543
+ email: {
544
+ email: string;
545
+ } | null;
546
+ };
547
+ } | null;
548
+ resolveMatricaMigration: (migrate: boolean) => Promise<void>;
509
549
  openModal: () => void;
510
550
  closeModal: () => void;
511
551
  setModalStep: (step: ModalState['step']) => void;
package/dist/index.js CHANGED
@@ -154,6 +154,15 @@ function buildApiClient(base) {
154
154
  body: { code }
155
155
  });
156
156
  },
157
+ getMatricaMigration(token) {
158
+ return request(`/auth/oauth/matrica/migration/${encodeURIComponent(token)}`);
159
+ },
160
+ resolveMatricaMigration(token, migrate) {
161
+ return request(`/auth/oauth/matrica/migration/${encodeURIComponent(token)}/resolve`, {
162
+ method: "POST",
163
+ body: { migrate }
164
+ });
165
+ },
157
166
  createLinkIntent(token) {
158
167
  return request("/auth/oauth/link-intent", {
159
168
  method: "POST",
@@ -1434,6 +1443,8 @@ function LoginModal() {
1434
1443
  return /* @__PURE__ */ jsx9(ForgotPasswordForm, {});
1435
1444
  case "verify-2fa":
1436
1445
  return /* @__PURE__ */ jsx9(Verify2FAForm, {});
1446
+ case "matrica-migration":
1447
+ return /* @__PURE__ */ jsx9(MatricaMigrationView, {});
1437
1448
  case "oauth":
1438
1449
  return /* @__PURE__ */ jsx9(OAuthLoadingView, {});
1439
1450
  case "success":
@@ -1460,7 +1471,7 @@ function LoginModal() {
1460
1471
  "--fc-accent": config.appearance?.accentColor ?? "#8b5cf6"
1461
1472
  },
1462
1473
  "data-theme": config.appearance?.theme ?? "light",
1463
- children: modal.step === "success" || modal.step === "oauth" ? renderStep() : /* @__PURE__ */ jsxs8(Fragment2, { children: [
1474
+ children: modal.step === "success" || modal.step === "oauth" || modal.step === "matrica-migration" ? renderStep() : /* @__PURE__ */ jsxs8(Fragment2, { children: [
1464
1475
  renderLogo(),
1465
1476
  /* @__PURE__ */ jsx9("h2", { className: "fc-modal-title", children: config.appearance?.title ?? "Log in or sign up" }),
1466
1477
  renderStep(),
@@ -1604,6 +1615,91 @@ function NomuPill() {
1604
1615
  }
1605
1616
  ) });
1606
1617
  }
1618
+ var MigrationIcons = {
1619
+ wallet: /* @__PURE__ */ jsxs8("svg", { width: "16", height: "16", viewBox: "0 0 20 20", fill: "none", children: [
1620
+ /* @__PURE__ */ jsx9("rect", { x: "2", y: "5", width: "16", height: "11", rx: "2", stroke: "currentColor", strokeWidth: "1.6" }),
1621
+ /* @__PURE__ */ jsx9("rect", { x: "13", y: "9", width: "5", height: "3", rx: "1", stroke: "currentColor", strokeWidth: "1.6" })
1622
+ ] }),
1623
+ email: /* @__PURE__ */ jsxs8("svg", { width: "16", height: "16", viewBox: "0 0 20 20", fill: "none", children: [
1624
+ /* @__PURE__ */ jsx9("rect", { x: "2", y: "4", width: "16", height: "12", rx: "2", stroke: "currentColor", strokeWidth: "1.6" }),
1625
+ /* @__PURE__ */ jsx9("path", { d: "M2 6l8 5 8-5", stroke: "currentColor", strokeWidth: "1.6", strokeLinecap: "round" })
1626
+ ] }),
1627
+ twitter: /* @__PURE__ */ jsx9("svg", { width: "14", height: "14", viewBox: "0 0 24 24", fill: "currentColor", children: /* @__PURE__ */ jsx9("path", { d: "M18.244 2.25h3.308l-7.227 8.26 8.502 11.24H16.17l-5.214-6.817L4.99 21.75H1.68l7.73-8.835L1.254 2.25H8.08l4.713 6.231zm-1.161 17.52h1.833L7.084 4.126H5.117z" }) }),
1628
+ discord: /* @__PURE__ */ jsx9("svg", { width: "14", height: "14", viewBox: "0 0 24 24", fill: "currentColor", children: /* @__PURE__ */ jsx9("path", { d: "M20.317 4.37a19.79 19.79 0 0 0-4.885-1.515.07.07 0 0 0-.073.035c-.21.375-.444.864-.608 1.249a18.27 18.27 0 0 0-5.487 0a12.6 12.6 0 0 0-.617-1.25.07.07 0 0 0-.073-.034A19.74 19.74 0 0 0 3.677 4.37a.07.07 0 0 0-.032.027C.533 9.046-.32 13.58.099 18.057a.08.08 0 0 0 .031.057a19.9 19.9 0 0 0 5.993 3.03.08.08 0 0 0 .084-.028a14.1 14.1 0 0 0 1.226-1.994.076.076 0 0 0-.041-.106a13.1 13.1 0 0 1-1.872-.892.077.077 0 0 1-.008-.128a10 10 0 0 0 .372-.292.07.07 0 0 1 .077-.01c3.928 1.793 8.18 1.793 12.062 0a.07.07 0 0 1 .078.01q.181.149.373.292a.077.077 0 0 1-.006.127a12.3 12.3 0 0 1-1.873.893.077.077 0 0 0-.041.107a16 16 0 0 0 1.226 1.993.08.08 0 0 0 .084.028a19.84 19.84 0 0 0 6.002-3.03.08.08 0 0 0 .031-.056c.5-5.177-.838-9.673-3.549-13.66a.06.06 0 0 0-.031-.028M8.02 15.331c-1.182 0-2.157-1.086-2.157-2.419c0-1.332.956-2.418 2.157-2.418c1.21 0 2.176 1.096 2.157 2.418c0 1.333-.956 2.42-2.157 2.42m7.974 0c-1.183 0-2.157-1.086-2.157-2.419c0-1.332.955-2.418 2.157-2.418c1.21 0 2.176 1.096 2.157 2.418c0 1.333-.946 2.42-2.157 2.42" }) }),
1629
+ telegram: /* @__PURE__ */ jsx9("svg", { width: "14", height: "14", viewBox: "0 0 24 24", fill: "currentColor", children: /* @__PURE__ */ jsx9("path", { d: "M11.944 0A12 12 0 0 0 0 12a12 12 0 0 0 12 12a12 12 0 0 0 12-12A12 12 0 0 0 12 0zm4.962 7.224c.1-.002.321.023.465.14a.5.5 0 0 1 .171.325c.016.093.036.306.02.472c-.18 1.898-.962 6.502-1.36 8.627c-.168.9-.499 1.201-.82 1.23c-.696.065-1.225-.46-1.9-.902c-1.056-.693-1.653-1.124-2.678-1.8c-1.185-.78-.417-1.21.258-1.91c.177-.184 3.247-2.977 3.307-3.23c.007-.032.014-.15-.056-.212s-.174-.041-.249-.024q-.16.036-5.061 3.345q-.72.495-1.302.48c-.428-.008-1.252-.241-1.865-.44c-.752-.245-1.349-.374-1.297-.789q.04-.324.893-.663q5.247-2.286 6.998-3.014q3.333-1.386 4.025-1.627q.227-.078.378-.08" }) })
1630
+ };
1631
+ function MatricaMigrationView() {
1632
+ const { matricaMigration, resolveMatricaMigration } = useForgeConnect();
1633
+ const [loading, setLoading] = useState6(null);
1634
+ const [error, setError] = useState6("");
1635
+ if (!matricaMigration) return null;
1636
+ const { conflicts } = matricaMigration;
1637
+ const total = conflicts.wallets.length + conflicts.socials.length + (conflicts.email ? 1 : 0);
1638
+ const handle = async (migrate) => {
1639
+ setLoading(migrate ? "migrate" : "skip");
1640
+ setError("");
1641
+ try {
1642
+ await resolveMatricaMigration(migrate);
1643
+ } catch (err) {
1644
+ setError(err instanceof Error ? err.message : "Something went wrong.");
1645
+ setLoading(null);
1646
+ }
1647
+ };
1648
+ const truncate2 = (s, n = 6) => s.length > n * 2 + 1 ? `${s.slice(0, n)}\u2026${s.slice(-n)}` : s;
1649
+ return /* @__PURE__ */ jsxs8("div", { className: "fc-mig", children: [
1650
+ /* @__PURE__ */ jsxs8("div", { className: "fc-mig-hero", children: [
1651
+ /* @__PURE__ */ jsx9("h2", { className: "fc-modal-title", style: { margin: 0 }, children: "Account already linked" }),
1652
+ /* @__PURE__ */ jsxs8("p", { className: "fc-mig-sub", children: [
1653
+ "Move ",
1654
+ total,
1655
+ " ",
1656
+ total > 1 ? "accounts" : "account",
1657
+ " to Matrica?"
1658
+ ] })
1659
+ ] }),
1660
+ /* @__PURE__ */ jsxs8("ul", { className: "fc-mig-list", children: [
1661
+ conflicts.wallets.map((w) => /* @__PURE__ */ jsxs8("li", { className: "fc-mig-item", children: [
1662
+ /* @__PURE__ */ jsx9("span", { className: "fc-mig-ic", children: MigrationIcons.wallet }),
1663
+ /* @__PURE__ */ jsx9("span", { className: "fc-mig-label", children: "Wallet" }),
1664
+ /* @__PURE__ */ jsx9("span", { className: "fc-mig-value", children: /* @__PURE__ */ jsx9("code", { children: truncate2(w.address) }) })
1665
+ ] }, `w-${w.address}`)),
1666
+ conflicts.socials.map((s) => /* @__PURE__ */ jsxs8("li", { className: "fc-mig-item", children: [
1667
+ /* @__PURE__ */ jsx9("span", { className: "fc-mig-ic", children: MigrationIcons[s.provider] }),
1668
+ /* @__PURE__ */ jsx9("span", { className: "fc-mig-label", style: { textTransform: "capitalize" }, children: s.provider === "twitter" ? "X" : s.provider }),
1669
+ /* @__PURE__ */ jsxs8("span", { className: "fc-mig-value", children: [
1670
+ "@",
1671
+ s.externalName
1672
+ ] })
1673
+ ] }, `s-${s.provider}-${s.externalName}`)),
1674
+ conflicts.email && /* @__PURE__ */ jsxs8("li", { className: "fc-mig-item", children: [
1675
+ /* @__PURE__ */ jsx9("span", { className: "fc-mig-ic", children: MigrationIcons.email }),
1676
+ /* @__PURE__ */ jsx9("span", { className: "fc-mig-label", children: "Email" }),
1677
+ /* @__PURE__ */ jsx9("span", { className: "fc-mig-value", children: conflicts.email.email })
1678
+ ] })
1679
+ ] }),
1680
+ error && /* @__PURE__ */ jsx9("p", { className: "fc-error", children: error }),
1681
+ /* @__PURE__ */ jsx9(
1682
+ "button",
1683
+ {
1684
+ type: "button",
1685
+ className: "fc-btn fc-btn-primary",
1686
+ onClick: () => handle(true),
1687
+ disabled: loading !== null,
1688
+ children: loading === "migrate" ? "Moving\u2026" : `Move ${total > 1 ? "them all" : "it"}`
1689
+ }
1690
+ ),
1691
+ /* @__PURE__ */ jsx9(
1692
+ "button",
1693
+ {
1694
+ type: "button",
1695
+ className: "fc-mig-skip",
1696
+ onClick: () => handle(false),
1697
+ disabled: loading !== null,
1698
+ children: loading === "skip" ? "Skipping\u2026" : "Not now"
1699
+ }
1700
+ )
1701
+ ] });
1702
+ }
1607
1703
  function SuccessView() {
1608
1704
  return /* @__PURE__ */ jsxs8("div", { className: "fc-success", children: [
1609
1705
  /* @__PURE__ */ jsx9("div", { className: "fc-success-icon", children: /* @__PURE__ */ jsxs8("svg", { viewBox: "0 0 52 52", className: "fc-success-check", children: [
@@ -3118,7 +3214,7 @@ function LoginsTab({ onLink, refreshKey }) {
3118
3214
  /* @__PURE__ */ jsx15("p", { className: "fc-account-section-desc", children: "Ways you can sign in to your account." }),
3119
3215
  authMethods?.map((m) => {
3120
3216
  const display = getMethodDisplay(m.provider);
3121
- const detail = m.provider === "email" ? m.providerId : m.provider.endsWith("_wallet") ? truncate(m.providerId) : m.providerId;
3217
+ const detail = m.provider === "email" ? m.providerId : m.provider.endsWith("_wallet") ? truncate(m.providerId) : m.providerUsername ? m.provider === "twitter" || m.provider === "telegram" ? `@${m.providerUsername}` : m.providerUsername : truncate(m.providerId);
3122
3218
  return /* @__PURE__ */ jsxs14("div", { className: "fc-account-item", children: [
3123
3219
  display.iconHtml && /* @__PURE__ */ jsx15(SvgIcon, { svg: display.iconHtml, className: "fc-account-item-icon" }),
3124
3220
  /* @__PURE__ */ jsxs14("div", { className: "fc-account-item-info", children: [
@@ -3836,6 +3932,7 @@ function ForgeConnectProvider({ config, children, onLogin, onLogout, walletAdapt
3836
3932
  const [accountModal, setAccountModal] = useState16({ isOpen: false });
3837
3933
  const [linkModal, setLinkModal] = useState16({ isOpen: false });
3838
3934
  const [challengeToken, setChallengeToken] = useState16(null);
3935
+ const [matricaMigration, setMatricaMigration] = useState16(null);
3839
3936
  const apiRef = useRef9(createApiClient(config.apiUrl));
3840
3937
  const refreshTimerRef = useRef9(null);
3841
3938
  const api = apiRef.current;
@@ -3880,6 +3977,21 @@ function ForgeConnectProvider({ config, children, onLogin, onLogout, walletAdapt
3880
3977
  window.close();
3881
3978
  return;
3882
3979
  }
3980
+ const migrationToken = params.get("fc_migration");
3981
+ if (migrationToken) {
3982
+ try {
3983
+ localStorage.setItem("fc_matrica_migration_pending", migrationToken);
3984
+ } catch {
3985
+ }
3986
+ if (window.opener) {
3987
+ window.opener.postMessage(
3988
+ { type: "fc_matrica_migration", token: migrationToken },
3989
+ window.location.origin
3990
+ );
3991
+ }
3992
+ window.close();
3993
+ return;
3994
+ }
3883
3995
  const authCode = params.get("fc_code");
3884
3996
  if (authCode) {
3885
3997
  try {
@@ -3934,20 +4046,45 @@ function ForgeConnectProvider({ config, children, onLogin, onLogout, walletAdapt
3934
4046
  setModal({ isOpen: false, step: "method-select" });
3935
4047
  }, 1500);
3936
4048
  };
4049
+ const handleMigrationToken = async (token) => {
4050
+ try {
4051
+ localStorage.removeItem("fc_matrica_migration_pending");
4052
+ } catch {
4053
+ }
4054
+ try {
4055
+ const preview = await api.getMatricaMigration(token);
4056
+ setMatricaMigration({ token, ...preview });
4057
+ setModal({ isOpen: true, step: "matrica-migration" });
4058
+ } catch {
4059
+ setModal({ isOpen: true, step: "error" });
4060
+ }
4061
+ };
3937
4062
  const handleMessage = (event) => {
3938
4063
  if (event.origin !== window.location.origin) return;
3939
- if (event.data?.type !== "fc_oauth_code") return;
3940
- const code = event.data.code;
3941
- if (!code) return;
3942
- void handleCode(code);
4064
+ if (event.data?.type === "fc_oauth_code") {
4065
+ const code = event.data.code;
4066
+ if (code) void handleCode(code);
4067
+ return;
4068
+ }
4069
+ if (event.data?.type === "fc_matrica_migration") {
4070
+ const token = event.data.token;
4071
+ if (token) void handleMigrationToken(token);
4072
+ }
3943
4073
  };
3944
4074
  const handleStorage = (event) => {
3945
- if (event.key !== "fc_oauth_code_pending" || !event.newValue) return;
3946
- void handleCode(event.newValue);
4075
+ if (event.key === "fc_oauth_code_pending" && event.newValue) {
4076
+ void handleCode(event.newValue);
4077
+ return;
4078
+ }
4079
+ if (event.key === "fc_matrica_migration_pending" && event.newValue) {
4080
+ void handleMigrationToken(event.newValue);
4081
+ }
3947
4082
  };
3948
4083
  try {
3949
4084
  const pending = localStorage.getItem("fc_oauth_code_pending");
3950
4085
  if (pending) void handleCode(pending);
4086
+ const pendingMigration = localStorage.getItem("fc_matrica_migration_pending");
4087
+ if (pendingMigration) void handleMigrationToken(pendingMigration);
3951
4088
  } catch {
3952
4089
  }
3953
4090
  window.addEventListener("message", handleMessage);
@@ -4167,6 +4304,28 @@ function ForgeConnectProvider({ config, children, onLogin, onLogout, walletAdapt
4167
4304
  setLinkModal({ isOpen: false });
4168
4305
  }, []);
4169
4306
  const getAccessToken = useCallback9(() => auth.accessToken, [auth.accessToken]);
4307
+ const resolveMatricaMigration = useCallback9(async (migrate) => {
4308
+ if (!matricaMigration) return;
4309
+ const res = await api.resolveMatricaMigration(matricaMigration.token, migrate);
4310
+ setMatricaMigration(null);
4311
+ let accessToken = res.accessToken ?? null;
4312
+ let requires2FA = res.requires2FA;
4313
+ let challenge = res.challengeToken;
4314
+ if (res.code) {
4315
+ const exchange = await api.exchangeOAuthCode(res.code);
4316
+ accessToken = exchange.accessToken ?? null;
4317
+ requires2FA = exchange.requires2FA;
4318
+ challenge = exchange.challengeToken;
4319
+ }
4320
+ if (requires2FA && challenge) {
4321
+ setChallengeToken(challenge);
4322
+ setModal({ isOpen: true, step: "verify-2fa" });
4323
+ return;
4324
+ }
4325
+ if (accessToken) {
4326
+ await handleAuthSuccess(accessToken);
4327
+ }
4328
+ }, [api, matricaMigration, handleAuthSuccess]);
4170
4329
  const value = useMemo3(() => ({
4171
4330
  auth,
4172
4331
  modal,
@@ -4187,6 +4346,8 @@ function ForgeConnectProvider({ config, children, onLogin, onLogout, walletAdapt
4187
4346
  challengeToken,
4188
4347
  verify2FA,
4189
4348
  verifyRecoveryCode,
4349
+ matricaMigration,
4350
+ resolveMatricaMigration,
4190
4351
  openModal,
4191
4352
  closeModal,
4192
4353
  setModalStep,
@@ -4220,6 +4381,8 @@ function ForgeConnectProvider({ config, children, onLogin, onLogout, walletAdapt
4220
4381
  verifyEmailToken,
4221
4382
  verify2FA,
4222
4383
  verifyRecoveryCode,
4384
+ matricaMigration,
4385
+ resolveMatricaMigration,
4223
4386
  openModal,
4224
4387
  closeModal,
4225
4388
  setModalStep,