@orangecheck/auth-client 0.6.0 → 1.1.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/index.js CHANGED
@@ -43,22 +43,20 @@ function buildSignInUrl(cfg, returnTo) {
43
43
  return u.toString();
44
44
  }
45
45
  var SessionContext = React2__namespace.createContext(null);
46
- function defaultSigningMethodFor(address) {
47
- return address.startsWith("did:email:") ? "fedimint_threshold" : "bip322";
48
- }
49
46
  function normalizeAccount(raw) {
50
47
  if (!raw) return null;
51
- const address = raw.btc_address ?? raw.address;
48
+ const didOc = raw.did_oc ?? raw.didOc;
52
49
  const accountId = raw.id ?? raw.account_id ?? raw.accountId;
53
- if (!address || !accountId) return null;
50
+ if (!didOc || !accountId) return null;
54
51
  return {
55
52
  accountId,
56
- address,
57
- didOc: raw.did_oc ?? raw.didOc ?? null,
53
+ didOc,
54
+ primaryBtc: raw.primary_btc ?? raw.primaryBtc ?? null,
55
+ hasEmail: raw.has_email ?? raw.hasEmail ?? false,
58
56
  displayName: raw.display_name ?? raw.displayName ?? null,
59
57
  nostrNpub: raw.nostr_npub ?? raw.nostrNpub ?? null,
60
58
  homeFederation: raw.home_federation_slug ?? raw.homeFederation ?? null,
61
- signingMethod: raw.signing_method ?? raw.signingMethod ?? defaultSigningMethodFor(address)
59
+ signingMethod: raw.signing_method ?? raw.signingMethod ?? null
62
60
  };
63
61
  }
64
62
  function OcSessionProvider({
@@ -156,13 +154,15 @@ function useUniqueId(prefix) {
156
154
  }
157
155
  function OcAccountChip({
158
156
  dashboardUrl = "https://ochk.io/dashboard",
157
+ signInUrl: signInUrlOverride,
159
158
  signInLabel = "sign in",
160
159
  className,
161
160
  triggerClassName,
162
161
  popoverClassName,
163
162
  menuItemClassName
164
163
  }) {
165
- const { status, account, signInUrl, signOut } = useOcSession();
164
+ const { status, account, signInUrl: sessionSignInUrl, signOut } = useOcSession();
165
+ const signInUrl = signInUrlOverride ?? sessionSignInUrl;
166
166
  const [open, setOpen] = React2__namespace.useState(false);
167
167
  const wrapRef = React2__namespace.useRef(null);
168
168
  React2__namespace.useEffect(() => {
@@ -209,7 +209,7 @@ function OcAccountChip({
209
209
  onClick: () => setOpen((v) => !v),
210
210
  "aria-haspopup": "menu",
211
211
  "aria-expanded": open,
212
- "aria-label": `Signed in as ${account.address}. Open account menu.`,
212
+ "aria-label": `Signed in as ${account.didOc}. Open account menu.`,
213
213
  className: triggerClassName,
214
214
  "data-oc-account-chip-trigger": "",
215
215
  style: triggerClassName ? void 0 : {
@@ -227,7 +227,7 @@ function OcAccountChip({
227
227
  },
228
228
  children: [
229
229
  /* @__PURE__ */ jsxRuntime.jsx("span", { "aria-hidden": "true", style: { color: "#22c55e", fontSize: 8 }, children: "\u25CF" }),
230
- /* @__PURE__ */ jsxRuntime.jsx("span", { children: account.displayName ?? shortenAddress(account.address) }),
230
+ /* @__PURE__ */ jsxRuntime.jsx("span", { children: account.displayName ?? shortenAddress(account.didOc) }),
231
231
  /* @__PURE__ */ jsxRuntime.jsx(
232
232
  "svg",
233
233
  {
@@ -308,7 +308,7 @@ function OcAccountChip({
308
308
  wordBreak: "break-all",
309
309
  lineHeight: 1.35
310
310
  },
311
- children: account.address
311
+ children: account.didOc
312
312
  }
313
313
  ),
314
314
  account.displayName ? /* @__PURE__ */ jsxRuntime.jsx(
@@ -419,16 +419,18 @@ function OcSignInButton({
419
419
  label = "sign in with bitcoin",
420
420
  eager = false,
421
421
  className,
422
+ signInUrl: signInUrlOverride,
422
423
  ...rest
423
424
  }) {
424
- const { status, signInUrl } = useOcSession();
425
+ const { status, signInUrl: sessionSignInUrl } = useOcSession();
426
+ const href = signInUrlOverride ?? sessionSignInUrl;
425
427
  if (status === "authenticated") return null;
426
428
  if (!eager && status === "loading") return null;
427
429
  return /* @__PURE__ */ jsxRuntime.jsx(
428
430
  "a",
429
431
  {
430
432
  ...rest,
431
- href: signInUrl,
433
+ href,
432
434
  className,
433
435
  "data-oc-sign-in-button": "",
434
436
  children: label
@@ -443,7 +445,7 @@ function OcAccountPill({
443
445
  }) {
444
446
  const { status, account, signOut } = useOcSession();
445
447
  if (status !== "authenticated" || !account) return null;
446
- const label = render ? render({ address: account.address, displayName: account.displayName }) : account.displayName ?? shortenAddress(account.address);
448
+ const label = render ? render({ address: account.didOc, displayName: account.displayName }) : account.displayName ?? shortenAddress(account.didOc);
447
449
  return /* @__PURE__ */ jsxRuntime.jsxs(
448
450
  "div",
449
451
  {
@@ -485,7 +487,7 @@ function useOcAddressSuggestion(options) {
485
487
  suggestionClassName
486
488
  } = options;
487
489
  const { status, account } = useOcSession();
488
- const sessionAddress = status === "authenticated" ? account?.address ?? null : null;
490
+ const sessionAddress = status === "authenticated" ? account?.primaryBtc ?? null : null;
489
491
  const [open, setOpen] = React2__namespace.useState(false);
490
492
  const [highlighted, setHighlighted] = React2__namespace.useState(false);
491
493
  const blurTimer = React2__namespace.useRef(null);
@@ -617,7 +619,7 @@ var OcAddressInput = React2__namespace.forwardRef(
617
619
  ...rest
618
620
  }, forwardedRef) {
619
621
  const { status, account } = useOcSession();
620
- const sessionAddress = status === "authenticated" ? account?.address ?? null : null;
622
+ const sessionAddress = status === "authenticated" ? account?.primaryBtc ?? null : null;
621
623
  const [open, setOpen] = React2__namespace.useState(false);
622
624
  const [highlighted, setHighlighted] = React2__namespace.useState(false);
623
625
  const innerRef = React2__namespace.useRef(null);
@@ -766,12 +768,516 @@ var OcAddressInput = React2__namespace.forwardRef(
766
768
  );
767
769
  }
768
770
  );
771
+ function safeReturnTo(input) {
772
+ const candidate = input ?? "/";
773
+ if (typeof candidate !== "string") return "/";
774
+ if (!candidate.startsWith("/") || candidate.startsWith("//")) return "/";
775
+ return candidate;
776
+ }
777
+ function hardNavigate(target) {
778
+ if (typeof window === "undefined") return;
779
+ window.location.assign(target);
780
+ }
781
+ function OcSignIn({
782
+ audience,
783
+ returnTo,
784
+ onSuccess,
785
+ authOrigin = "https://ochk.io",
786
+ initialPath = "wallet",
787
+ paths,
788
+ className
789
+ }) {
790
+ const walletEnabled = paths?.wallet ?? true;
791
+ const emailEnabled = paths?.email ?? true;
792
+ const safeReturn = safeReturnTo(returnTo);
793
+ const [path, setPath] = React2__namespace.useState(initialPath);
794
+ const handleSuccess = React2__namespace.useCallback(
795
+ (account) => {
796
+ if (onSuccess) {
797
+ onSuccess(account);
798
+ return;
799
+ }
800
+ hardNavigate(safeReturn);
801
+ },
802
+ [onSuccess, safeReturn]
803
+ );
804
+ if (!walletEnabled && !emailEnabled) {
805
+ return /* @__PURE__ */ jsxRuntime.jsxs(
806
+ "div",
807
+ {
808
+ className,
809
+ "data-oc-signin": "",
810
+ style: {
811
+ padding: "1rem",
812
+ border: "1px solid var(--border, #27272a)",
813
+ color: "var(--foreground, #fafafa)",
814
+ fontFamily: "ui-monospace, SFMono-Regular, monospace",
815
+ fontSize: 12
816
+ },
817
+ children: [
818
+ "no signin paths enabled \u2014 set ",
819
+ /* @__PURE__ */ jsxRuntime.jsx("code", { children: "paths.wallet" }),
820
+ " or",
821
+ " ",
822
+ /* @__PURE__ */ jsxRuntime.jsx("code", { children: "paths.email" }),
823
+ " to ",
824
+ /* @__PURE__ */ jsxRuntime.jsx("code", { children: "true" })
825
+ ]
826
+ }
827
+ );
828
+ }
829
+ const showWallet = walletEnabled && (path === "wallet" || !emailEnabled);
830
+ const showEmail = emailEnabled && (path === "email" || !walletEnabled);
831
+ const bothEnabled = walletEnabled && emailEnabled;
832
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className, "data-oc-signin": "", children: [
833
+ bothEnabled && /* @__PURE__ */ jsxRuntime.jsxs(
834
+ "div",
835
+ {
836
+ role: "tablist",
837
+ "aria-label": "signin method",
838
+ "data-oc-signin-tabs": "",
839
+ style: {
840
+ display: "flex",
841
+ gap: 8,
842
+ marginBottom: 16,
843
+ borderBottom: "1px solid var(--border, #27272a)"
844
+ },
845
+ children: [
846
+ /* @__PURE__ */ jsxRuntime.jsx(
847
+ SigninTab,
848
+ {
849
+ active: path === "wallet",
850
+ onClick: () => setPath("wallet"),
851
+ children: "bitcoin wallet"
852
+ }
853
+ ),
854
+ /* @__PURE__ */ jsxRuntime.jsx(SigninTab, { active: path === "email", onClick: () => setPath("email"), children: "email + otp" })
855
+ ]
856
+ }
857
+ ),
858
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { "data-oc-signin-panel": "", role: "tabpanel", children: [
859
+ showWallet && /* @__PURE__ */ jsxRuntime.jsx(
860
+ WalletFlow,
861
+ {
862
+ authOrigin,
863
+ audience,
864
+ onSuccess: handleSuccess
865
+ }
866
+ ),
867
+ showEmail && /* @__PURE__ */ jsxRuntime.jsx(EmailFlow, { authOrigin, onSuccess: handleSuccess })
868
+ ] })
869
+ ] });
870
+ }
871
+ function SigninTab({
872
+ active,
873
+ onClick,
874
+ children
875
+ }) {
876
+ return /* @__PURE__ */ jsxRuntime.jsx(
877
+ "button",
878
+ {
879
+ type: "button",
880
+ role: "tab",
881
+ "aria-selected": active,
882
+ onClick,
883
+ "data-oc-signin-tab": active ? "active" : "inactive",
884
+ style: {
885
+ padding: "0.6rem 0.875rem",
886
+ background: "transparent",
887
+ border: "none",
888
+ borderBottom: active ? "2px solid var(--primary, #f97316)" : "2px solid transparent",
889
+ color: active ? "var(--foreground, #fafafa)" : "var(--muted-foreground, #a1a1aa)",
890
+ fontFamily: "ui-monospace, SFMono-Regular, monospace",
891
+ fontSize: 11,
892
+ letterSpacing: "0.12em",
893
+ textTransform: "uppercase",
894
+ cursor: "pointer",
895
+ marginBottom: -1
896
+ },
897
+ children
898
+ }
899
+ );
900
+ }
901
+ function WalletFlow({ authOrigin, audience, onSuccess }) {
902
+ const [address, setAddress] = React2__namespace.useState("");
903
+ const [error, setError] = React2__namespace.useState(null);
904
+ const [submitting, setSubmitting] = React2__namespace.useState(false);
905
+ const [stage, setStage] = React2__namespace.useState("enter");
906
+ async function signIn(e) {
907
+ e.preventDefault();
908
+ const addr = address.trim();
909
+ if (!addr) {
910
+ setError("paste a Bitcoin address");
911
+ return;
912
+ }
913
+ setError(null);
914
+ setSubmitting(true);
915
+ setStage("signing");
916
+ try {
917
+ const challengeRes = await fetch(
918
+ `${authOrigin}/api/challenge?addr=${encodeURIComponent(addr)}&audience=${encodeURIComponent(audience)}&purpose=login`
919
+ );
920
+ const challenge = await challengeRes.json();
921
+ if (!challengeRes.ok || !challenge.message || !challenge.nonce) {
922
+ throw new Error(challenge.error ?? "challenge_failed");
923
+ }
924
+ let adapter;
925
+ try {
926
+ const moduleId = "@orangecheck/wallet-adapter";
927
+ adapter = await Function("m", "return import(m)")(
928
+ moduleId
929
+ );
930
+ } catch {
931
+ throw new Error(
932
+ "@orangecheck/wallet-adapter not installed \xB7 add it to your consumer site"
933
+ );
934
+ }
935
+ const wallets = adapter.detectWallets().filter((w) => w.detected && w.id !== "manual");
936
+ if (wallets.length === 0) {
937
+ throw new Error("no BIP-322 wallet extension detected \xB7 install one and refresh");
938
+ }
939
+ const wallet = wallets[0];
940
+ const signer = adapter.getSigner(wallet.id, { address: addr });
941
+ const signature = await signer(challenge.message);
942
+ const res = await fetch(`${authOrigin}/api/auth/signin`, {
943
+ method: "POST",
944
+ credentials: "include",
945
+ headers: { "Content-Type": "application/json" },
946
+ body: JSON.stringify({
947
+ message: challenge.message,
948
+ signature,
949
+ scheme: "bip322",
950
+ expectedNonce: challenge.nonce,
951
+ expectedAudience: audience,
952
+ expectedPurpose: "login"
953
+ })
954
+ });
955
+ const json = await res.json();
956
+ if (!res.ok || !("ok" in json) || !json.ok || !json.account) {
957
+ throw new Error(
958
+ "reason" in json && json.reason || "error" in json && json.error || `verify_failed_${res.status}`
959
+ );
960
+ }
961
+ onSuccess(json.account);
962
+ } catch (err) {
963
+ const msg = err instanceof Error ? err.message : "sign-in failed";
964
+ setError(msg);
965
+ setSubmitting(false);
966
+ setStage("enter");
967
+ }
968
+ }
969
+ return /* @__PURE__ */ jsxRuntime.jsxs("form", { onSubmit: signIn, "data-oc-signin-wallet": "", children: [
970
+ /* @__PURE__ */ jsxRuntime.jsx(FlowHeader, { label: "\xA7 bitcoin wallet", children: "Sign in with any BIP-322-capable Bitcoin wallet (Sparrow, Xverse, Leather, UniSat, Alby, OKX, Phantom). Paste your address, click sign \u2014 your wallet extension prompts for a one-time signature on a short challenge. The address becomes your OC identity. Private key material never leaves your wallet." }),
971
+ /* @__PURE__ */ jsxRuntime.jsx(Label, { children: "bitcoin address" }),
972
+ /* @__PURE__ */ jsxRuntime.jsx(
973
+ "input",
974
+ {
975
+ type: "text",
976
+ value: address,
977
+ onChange: (e) => {
978
+ setAddress(e.target.value);
979
+ if (error) setError(null);
980
+ },
981
+ placeholder: "bc1q\u2026 \xB7 3\u2026 \xB7 1\u2026",
982
+ autoComplete: "off",
983
+ autoCapitalize: "none",
984
+ spellCheck: false,
985
+ required: true,
986
+ "aria-invalid": error ? true : void 0,
987
+ style: inputStyle
988
+ }
989
+ ),
990
+ error && /* @__PURE__ */ jsxRuntime.jsx(ErrorLine, { children: error }),
991
+ /* @__PURE__ */ jsxRuntime.jsx(
992
+ "button",
993
+ {
994
+ type: "submit",
995
+ disabled: submitting || !address.trim(),
996
+ style: submitStyle(submitting || !address.trim()),
997
+ children: stage === "signing" && submitting ? "waiting for wallet\u2026" : "sign challenge \xB7 sign me in \u2192"
998
+ }
999
+ ),
1000
+ /* @__PURE__ */ jsxRuntime.jsx(Hint, { children: "Detection picks the first installed BIP-322-capable extension. Address is the one your wallet will sign for." })
1001
+ ] });
1002
+ }
1003
+ function EmailFlow({ authOrigin, onSuccess }) {
1004
+ const [stage, setStage] = React2__namespace.useState("enter");
1005
+ const [email, setEmail] = React2__namespace.useState("");
1006
+ const [emailError, setEmailError] = React2__namespace.useState(null);
1007
+ const [code, setCode] = React2__namespace.useState("");
1008
+ const [codeError, setCodeError] = React2__namespace.useState(null);
1009
+ const [token, setToken] = React2__namespace.useState(null);
1010
+ const [submitting, setSubmitting] = React2__namespace.useState(false);
1011
+ async function start(e) {
1012
+ e.preventDefault();
1013
+ const trimmed = email.trim().toLowerCase();
1014
+ if (!trimmed || !/.+@.+\..+/.test(trimmed)) {
1015
+ setEmailError("enter a valid email");
1016
+ return;
1017
+ }
1018
+ setEmailError(null);
1019
+ setSubmitting(true);
1020
+ try {
1021
+ const res = await fetch(`${authOrigin}/api/auth/email-otp/start`, {
1022
+ method: "POST",
1023
+ credentials: "include",
1024
+ headers: { "Content-Type": "application/json" },
1025
+ body: JSON.stringify({ email: trimmed })
1026
+ });
1027
+ const json = await res.json();
1028
+ if (!res.ok || !json.token) {
1029
+ throw new Error(json.reason ?? `start failed (${res.status})`);
1030
+ }
1031
+ setToken(json.token);
1032
+ setEmail(trimmed);
1033
+ setStage("code");
1034
+ } catch (err) {
1035
+ setEmailError(err instanceof Error ? err.message : "failed to send code");
1036
+ } finally {
1037
+ setSubmitting(false);
1038
+ }
1039
+ }
1040
+ async function verify(e) {
1041
+ e.preventDefault();
1042
+ if (!token) return;
1043
+ if (code.length !== 6) {
1044
+ setCodeError("6 digits");
1045
+ return;
1046
+ }
1047
+ setCodeError(null);
1048
+ setSubmitting(true);
1049
+ try {
1050
+ const res = await fetch(`${authOrigin}/api/auth/email-otp/verify`, {
1051
+ method: "POST",
1052
+ credentials: "include",
1053
+ headers: { "Content-Type": "application/json" },
1054
+ body: JSON.stringify({ email, code, token })
1055
+ });
1056
+ const json = await res.json();
1057
+ if (!res.ok || !("ok" in json) || !json.ok || !json.account) {
1058
+ throw new Error(
1059
+ "reason" in json && json.reason || "error" in json && json.error || `verify failed (${res.status})`
1060
+ );
1061
+ }
1062
+ onSuccess(json.account);
1063
+ } catch (err) {
1064
+ setCodeError(err instanceof Error ? err.message : "verify failed");
1065
+ } finally {
1066
+ setSubmitting(false);
1067
+ }
1068
+ }
1069
+ if (stage === "enter") {
1070
+ return /* @__PURE__ */ jsxRuntime.jsxs("form", { onSubmit: start, "data-oc-signin-email": "", children: [
1071
+ /* @__PURE__ */ jsxRuntime.jsx(FlowHeader, { label: "\xA7 email + otp", children: "We email you a 6-digit code. No password. The federation provisions a custodial wallet for you in your browser. Best path if you don't have a Bitcoin wallet yet \u2014 graduate to self-custody anytime by adding your BTC address from your account dashboard." }),
1072
+ /* @__PURE__ */ jsxRuntime.jsx(Label, { children: "email" }),
1073
+ /* @__PURE__ */ jsxRuntime.jsx(
1074
+ "input",
1075
+ {
1076
+ type: "email",
1077
+ autoComplete: "email",
1078
+ value: email,
1079
+ onChange: (e) => {
1080
+ setEmail(e.target.value);
1081
+ if (emailError) setEmailError(null);
1082
+ },
1083
+ placeholder: "you@example.com",
1084
+ required: true,
1085
+ "aria-invalid": emailError ? true : void 0,
1086
+ style: inputStyle
1087
+ }
1088
+ ),
1089
+ emailError && /* @__PURE__ */ jsxRuntime.jsx(ErrorLine, { children: emailError }),
1090
+ /* @__PURE__ */ jsxRuntime.jsx("button", { type: "submit", disabled: submitting, style: submitStyle(submitting), children: submitting ? "sending\u2026" : "send one-time code \u2192" }),
1091
+ /* @__PURE__ */ jsxRuntime.jsx(Hint, { children: "OTP delivered by the auth host. Codes expire in 10 minutes and are single-use. Rate-limited 5 starts/hour/IP." })
1092
+ ] });
1093
+ }
1094
+ return /* @__PURE__ */ jsxRuntime.jsxs("form", { onSubmit: verify, "data-oc-signin-email-verify": "", children: [
1095
+ /* @__PURE__ */ jsxRuntime.jsxs(FlowHeader, { label: "\xA7 enter the code", children: [
1096
+ "Sent a 6-digit code to ",
1097
+ /* @__PURE__ */ jsxRuntime.jsx("span", { style: { color: "var(--foreground, #fafafa)" }, children: email }),
1098
+ ". Code expires in 10 minutes."
1099
+ ] }),
1100
+ /* @__PURE__ */ jsxRuntime.jsx(Label, { children: "one-time code" }),
1101
+ /* @__PURE__ */ jsxRuntime.jsx(
1102
+ "input",
1103
+ {
1104
+ type: "text",
1105
+ inputMode: "numeric",
1106
+ pattern: "\\d{6}",
1107
+ maxLength: 6,
1108
+ autoComplete: "one-time-code",
1109
+ value: code,
1110
+ onChange: (e) => {
1111
+ setCode(e.target.value.replace(/\D/g, "").slice(0, 6));
1112
+ if (codeError) setCodeError(null);
1113
+ },
1114
+ placeholder: "6 digits",
1115
+ required: true,
1116
+ autoFocus: true,
1117
+ "aria-invalid": codeError ? true : void 0,
1118
+ style: { ...inputStyle, letterSpacing: "0.4em", fontSize: 16 }
1119
+ }
1120
+ ),
1121
+ codeError && /* @__PURE__ */ jsxRuntime.jsx(ErrorLine, { children: codeError }),
1122
+ /* @__PURE__ */ jsxRuntime.jsx(
1123
+ "button",
1124
+ {
1125
+ type: "submit",
1126
+ disabled: submitting || code.length !== 6,
1127
+ style: submitStyle(submitting || code.length !== 6),
1128
+ children: submitting ? "verifying\u2026" : "verify \xB7 sign me in \u2192"
1129
+ }
1130
+ ),
1131
+ /* @__PURE__ */ jsxRuntime.jsx(
1132
+ "button",
1133
+ {
1134
+ type: "button",
1135
+ onClick: () => {
1136
+ setStage("enter");
1137
+ setCode("");
1138
+ setToken(null);
1139
+ },
1140
+ style: {
1141
+ marginTop: 12,
1142
+ background: "transparent",
1143
+ border: "none",
1144
+ color: "var(--muted-foreground, #a1a1aa)",
1145
+ fontFamily: "ui-monospace, SFMono-Regular, monospace",
1146
+ fontSize: 11,
1147
+ letterSpacing: "0.12em",
1148
+ textTransform: "uppercase",
1149
+ cursor: "pointer",
1150
+ padding: 0
1151
+ },
1152
+ children: "use a different email"
1153
+ }
1154
+ ),
1155
+ /* @__PURE__ */ jsxRuntime.jsx(Hint, { children: "On verify, oc_session is set on Domain=.ochk.io family-wide." })
1156
+ ] });
1157
+ }
1158
+ function FlowHeader({
1159
+ label,
1160
+ children
1161
+ }) {
1162
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { marginBottom: 16 }, children: [
1163
+ /* @__PURE__ */ jsxRuntime.jsx(
1164
+ "div",
1165
+ {
1166
+ style: {
1167
+ color: "var(--primary, #f97316)",
1168
+ fontFamily: "ui-monospace, SFMono-Regular, monospace",
1169
+ fontSize: 10,
1170
+ letterSpacing: "0.18em",
1171
+ textTransform: "uppercase",
1172
+ marginBottom: 6
1173
+ },
1174
+ children: label
1175
+ }
1176
+ ),
1177
+ /* @__PURE__ */ jsxRuntime.jsx(
1178
+ "p",
1179
+ {
1180
+ style: {
1181
+ color: "var(--muted-foreground, #a1a1aa)",
1182
+ fontSize: 13,
1183
+ lineHeight: 1.55,
1184
+ margin: 0
1185
+ },
1186
+ children
1187
+ }
1188
+ )
1189
+ ] });
1190
+ }
1191
+ function Label({ children }) {
1192
+ return /* @__PURE__ */ jsxRuntime.jsx(
1193
+ "label",
1194
+ {
1195
+ style: {
1196
+ display: "block",
1197
+ color: "var(--foreground, #fafafa)",
1198
+ fontFamily: "ui-monospace, SFMono-Regular, monospace",
1199
+ fontSize: 11,
1200
+ letterSpacing: "0.12em",
1201
+ textTransform: "uppercase",
1202
+ marginBottom: 6
1203
+ },
1204
+ children
1205
+ }
1206
+ );
1207
+ }
1208
+ var inputStyle = {
1209
+ width: "100%",
1210
+ padding: "0.55rem 0.75rem",
1211
+ background: "var(--background, #0a0a0a)",
1212
+ color: "var(--foreground, #fafafa)",
1213
+ border: "1px solid var(--input, #27272a)",
1214
+ borderRadius: 6,
1215
+ fontFamily: "ui-monospace, SFMono-Regular, monospace",
1216
+ fontSize: 13,
1217
+ outline: "none"
1218
+ };
1219
+ function submitStyle(disabled) {
1220
+ return {
1221
+ marginTop: 12,
1222
+ padding: "0.6rem 1rem",
1223
+ background: "var(--primary, #f97316)",
1224
+ color: "var(--primary-foreground, #0a0a0a)",
1225
+ border: "none",
1226
+ borderRadius: 6,
1227
+ fontFamily: "ui-monospace, SFMono-Regular, monospace",
1228
+ fontSize: 11,
1229
+ letterSpacing: "0.14em",
1230
+ textTransform: "uppercase",
1231
+ fontWeight: 600,
1232
+ cursor: disabled ? "not-allowed" : "pointer",
1233
+ opacity: disabled ? 0.5 : 1,
1234
+ width: "100%"
1235
+ };
1236
+ }
1237
+ function ErrorLine({ children }) {
1238
+ return /* @__PURE__ */ jsxRuntime.jsx(
1239
+ "p",
1240
+ {
1241
+ role: "alert",
1242
+ style: {
1243
+ marginTop: 6,
1244
+ marginBottom: 0,
1245
+ color: "var(--destructive, #ef4444)",
1246
+ fontFamily: "ui-monospace, SFMono-Regular, monospace",
1247
+ fontSize: 11,
1248
+ letterSpacing: "0.04em"
1249
+ },
1250
+ children
1251
+ }
1252
+ );
1253
+ }
1254
+ function Hint({ children }) {
1255
+ return /* @__PURE__ */ jsxRuntime.jsxs(
1256
+ "p",
1257
+ {
1258
+ style: {
1259
+ marginTop: 12,
1260
+ marginBottom: 0,
1261
+ color: "var(--muted-foreground, #a1a1aa)",
1262
+ fontFamily: "ui-monospace, SFMono-Regular, monospace",
1263
+ fontSize: 10.5,
1264
+ lineHeight: 1.55,
1265
+ opacity: 0.7
1266
+ },
1267
+ children: [
1268
+ "> ",
1269
+ children
1270
+ ]
1271
+ }
1272
+ );
1273
+ }
769
1274
 
770
1275
  exports.DEFAULT_CONFIG = DEFAULT_CONFIG;
771
1276
  exports.OcAccountChip = OcAccountChip;
772
1277
  exports.OcAccountPill = OcAccountPill;
773
1278
  exports.OcAddressInput = OcAddressInput;
774
1279
  exports.OcSessionProvider = OcSessionProvider;
1280
+ exports.OcSignIn = OcSignIn;
775
1281
  exports.OcSignInButton = OcSignInButton;
776
1282
  exports.buildSignInUrl = buildSignInUrl;
777
1283
  exports.useOcAddressSuggestion = useOcAddressSuggestion;