@orangecheck/auth-client 0.1.0 → 0.2.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.d.mts CHANGED
@@ -46,5 +46,14 @@ interface OcAccountPillProps extends React.HTMLAttributes<HTMLDivElement> {
46
46
  }) => React.ReactNode;
47
47
  }
48
48
  declare function OcAccountPill({ dashboardUrl, render, className, ...rest }: OcAccountPillProps): React.ReactElement | null;
49
+ interface OcAddressInputProps extends Omit<React.InputHTMLAttributes<HTMLInputElement>, 'value' | 'onChange'> {
50
+ value: string;
51
+ onValueChange: (value: string) => void;
52
+ suggestionLabel?: string;
53
+ wrapperClassName?: string;
54
+ popoverClassName?: string;
55
+ suggestionClassName?: string;
56
+ }
57
+ declare const OcAddressInput: React.ForwardRefExoticComponent<OcAddressInputProps & React.RefAttributes<HTMLInputElement>>;
49
58
 
50
- export { DEFAULT_CONFIG, type OcAccount, OcAccountPill, type OcAccountPillProps, type OcAuthConfig, OcSessionProvider, type OcSessionState, type OcSessionStatus, OcSignInButton, type OcSignInButtonProps, buildSignInUrl, useOcSession, useOptionalOcSession };
59
+ export { DEFAULT_CONFIG, type OcAccount, OcAccountPill, type OcAccountPillProps, OcAddressInput, type OcAddressInputProps, type OcAuthConfig, OcSessionProvider, type OcSessionState, type OcSessionStatus, OcSignInButton, type OcSignInButtonProps, buildSignInUrl, useOcSession, useOptionalOcSession };
package/dist/index.d.ts CHANGED
@@ -46,5 +46,14 @@ interface OcAccountPillProps extends React.HTMLAttributes<HTMLDivElement> {
46
46
  }) => React.ReactNode;
47
47
  }
48
48
  declare function OcAccountPill({ dashboardUrl, render, className, ...rest }: OcAccountPillProps): React.ReactElement | null;
49
+ interface OcAddressInputProps extends Omit<React.InputHTMLAttributes<HTMLInputElement>, 'value' | 'onChange'> {
50
+ value: string;
51
+ onValueChange: (value: string) => void;
52
+ suggestionLabel?: string;
53
+ wrapperClassName?: string;
54
+ popoverClassName?: string;
55
+ suggestionClassName?: string;
56
+ }
57
+ declare const OcAddressInput: React.ForwardRefExoticComponent<OcAddressInputProps & React.RefAttributes<HTMLInputElement>>;
49
58
 
50
- export { DEFAULT_CONFIG, type OcAccount, OcAccountPill, type OcAccountPillProps, type OcAuthConfig, OcSessionProvider, type OcSessionState, type OcSessionStatus, OcSignInButton, type OcSignInButtonProps, buildSignInUrl, useOcSession, useOptionalOcSession };
59
+ export { DEFAULT_CONFIG, type OcAccount, OcAccountPill, type OcAccountPillProps, OcAddressInput, type OcAddressInputProps, type OcAuthConfig, OcSessionProvider, type OcSessionState, type OcSessionStatus, OcSignInButton, type OcSignInButtonProps, buildSignInUrl, useOcSession, useOptionalOcSession };
package/dist/index.js CHANGED
@@ -136,6 +136,18 @@ function shortenAddress(addr) {
136
136
  if (addr.length <= 12) return addr;
137
137
  return `${addr.slice(0, 6)}\u2026${addr.slice(-4)}`;
138
138
  }
139
+ function shortenAddressMid(addr) {
140
+ if (addr.length <= 16) return addr;
141
+ return `${addr.slice(0, 8)}\u2026${addr.slice(-6)}`;
142
+ }
143
+ function isPrefixOf(value, target) {
144
+ return target.toLowerCase().startsWith(value.toLowerCase());
145
+ }
146
+ var listboxIdCounter = 0;
147
+ function useUniqueId(prefix) {
148
+ const [id] = React__namespace.useState(() => `${prefix}-${++listboxIdCounter}`);
149
+ return id;
150
+ }
139
151
  function OcSignInButton({
140
152
  label = "sign in with bitcoin",
141
153
  eager = false,
@@ -197,9 +209,173 @@ function OcAccountPill({
197
209
  }
198
210
  );
199
211
  }
212
+ var OcAddressInput = React__namespace.forwardRef(
213
+ function OcAddressInput2({
214
+ value,
215
+ onValueChange,
216
+ suggestionLabel = "use your address",
217
+ wrapperClassName,
218
+ popoverClassName,
219
+ suggestionClassName,
220
+ onFocus,
221
+ onBlur,
222
+ onKeyDown,
223
+ ...rest
224
+ }, forwardedRef) {
225
+ const { status, account } = useOcSession();
226
+ const sessionAddress = status === "authenticated" ? account?.address ?? null : null;
227
+ const [open, setOpen] = React__namespace.useState(false);
228
+ const [highlighted, setHighlighted] = React__namespace.useState(false);
229
+ const innerRef = React__namespace.useRef(null);
230
+ const setRef = (node) => {
231
+ innerRef.current = node;
232
+ if (typeof forwardedRef === "function") forwardedRef(node);
233
+ else if (forwardedRef) forwardedRef.current = node;
234
+ };
235
+ const blurTimer = React__namespace.useRef(null);
236
+ const listboxId = useUniqueId("oc-addr-listbox");
237
+ const optionId = `${listboxId}-opt`;
238
+ const valueMatchesSession = sessionAddress != null && value.toLowerCase() === sessionAddress.toLowerCase();
239
+ const canSuggest = sessionAddress != null && sessionAddress.length > 0 && !valueMatchesSession && isPrefixOf(value, sessionAddress);
240
+ const showPopover = open && canSuggest;
241
+ function selectSuggestion() {
242
+ if (!sessionAddress) return;
243
+ onValueChange(sessionAddress);
244
+ setOpen(false);
245
+ setHighlighted(false);
246
+ innerRef.current?.focus();
247
+ }
248
+ function handleFocus(e) {
249
+ if (blurTimer.current != null) {
250
+ window.clearTimeout(blurTimer.current);
251
+ blurTimer.current = null;
252
+ }
253
+ setOpen(true);
254
+ onFocus?.(e);
255
+ }
256
+ function handleBlur(e) {
257
+ blurTimer.current = window.setTimeout(() => {
258
+ setOpen(false);
259
+ setHighlighted(false);
260
+ }, 120);
261
+ onBlur?.(e);
262
+ }
263
+ function handleKeyDown(e) {
264
+ if (showPopover) {
265
+ if (e.key === "ArrowDown") {
266
+ e.preventDefault();
267
+ setHighlighted(true);
268
+ } else if (e.key === "ArrowUp") {
269
+ e.preventDefault();
270
+ setHighlighted(false);
271
+ } else if (e.key === "Escape") {
272
+ e.preventDefault();
273
+ setOpen(false);
274
+ setHighlighted(false);
275
+ } else if (e.key === "Enter" && highlighted) {
276
+ e.preventDefault();
277
+ selectSuggestion();
278
+ }
279
+ }
280
+ onKeyDown?.(e);
281
+ }
282
+ React__namespace.useEffect(() => {
283
+ return () => {
284
+ if (blurTimer.current != null) window.clearTimeout(blurTimer.current);
285
+ };
286
+ }, []);
287
+ return /* @__PURE__ */ jsxRuntime.jsxs(
288
+ "div",
289
+ {
290
+ "data-oc-address-input": "",
291
+ className: wrapperClassName,
292
+ style: { position: "relative" },
293
+ children: [
294
+ /* @__PURE__ */ jsxRuntime.jsx(
295
+ "input",
296
+ {
297
+ ...rest,
298
+ ref: setRef,
299
+ value,
300
+ onChange: (e) => onValueChange(e.target.value),
301
+ onFocus: handleFocus,
302
+ onBlur: handleBlur,
303
+ onKeyDown: handleKeyDown,
304
+ role: "combobox",
305
+ "aria-haspopup": "listbox",
306
+ "aria-expanded": showPopover,
307
+ "aria-controls": showPopover ? listboxId : void 0,
308
+ "aria-activedescendant": highlighted ? optionId : void 0,
309
+ autoComplete: "off",
310
+ spellCheck: false
311
+ }
312
+ ),
313
+ showPopover && sessionAddress && /* @__PURE__ */ jsxRuntime.jsx(
314
+ "div",
315
+ {
316
+ id: listboxId,
317
+ role: "listbox",
318
+ "data-oc-address-popover": "",
319
+ className: popoverClassName,
320
+ style: {
321
+ position: "absolute",
322
+ zIndex: 50,
323
+ top: "calc(100% + 4px)",
324
+ left: 0,
325
+ right: 0
326
+ },
327
+ onMouseDown: (e) => e.preventDefault(),
328
+ children: /* @__PURE__ */ jsxRuntime.jsxs(
329
+ "button",
330
+ {
331
+ type: "button",
332
+ id: optionId,
333
+ role: "option",
334
+ "aria-selected": highlighted,
335
+ "data-oc-address-suggestion": "",
336
+ "data-highlighted": highlighted ? "" : void 0,
337
+ className: suggestionClassName,
338
+ onClick: selectSuggestion,
339
+ onMouseEnter: () => setHighlighted(true),
340
+ onMouseLeave: () => setHighlighted(false),
341
+ style: {
342
+ display: "flex",
343
+ alignItems: "center",
344
+ justifyContent: "space-between",
345
+ gap: "0.75rem",
346
+ width: "100%",
347
+ textAlign: "left",
348
+ cursor: "pointer",
349
+ font: "inherit",
350
+ background: "inherit",
351
+ color: "inherit",
352
+ border: "inherit",
353
+ padding: "inherit"
354
+ },
355
+ children: [
356
+ /* @__PURE__ */ jsxRuntime.jsx("span", { "data-oc-address-suggestion-label": "", children: suggestionLabel }),
357
+ /* @__PURE__ */ jsxRuntime.jsx(
358
+ "span",
359
+ {
360
+ "data-oc-address-suggestion-value": "",
361
+ style: { fontFamily: "ui-monospace, monospace" },
362
+ children: shortenAddressMid(sessionAddress)
363
+ }
364
+ )
365
+ ]
366
+ }
367
+ )
368
+ }
369
+ )
370
+ ]
371
+ }
372
+ );
373
+ }
374
+ );
200
375
 
201
376
  exports.DEFAULT_CONFIG = DEFAULT_CONFIG;
202
377
  exports.OcAccountPill = OcAccountPill;
378
+ exports.OcAddressInput = OcAddressInput;
203
379
  exports.OcSessionProvider = OcSessionProvider;
204
380
  exports.OcSignInButton = OcSignInButton;
205
381
  exports.buildSignInUrl = buildSignInUrl;
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/types.ts","../src/provider.tsx","../src/components.tsx"],"names":["React","jsx","jsxs"],"mappings":"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","file":"index.js","sourcesContent":["export interface OcAccount {\n accountId: string;\n address: string;\n displayName?: string | null;\n nostrNpub?: string | null;\n}\n\nexport type OcSessionStatus = 'loading' | 'authenticated' | 'anonymous' | 'error';\n\nexport interface OcSessionState {\n status: OcSessionStatus;\n account: OcAccount | null;\n /** `null` while loading; an `Error` instance when `status === 'error'`. */\n error: Error | null;\n /** Re-fetch the session. Useful after sign-in/sign-out happens elsewhere. */\n refresh: () => Promise<void>;\n /** Trigger a sign-out. Resolves once the cookie has been cleared. */\n signOut: () => Promise<void>;\n /** URL to navigate to for sign-in on the auth host. */\n signInUrl: string;\n}\n\nexport interface OcAuthConfig {\n /**\n * Origin of the auth host — the subdomain that runs the sign-in UI,\n * issues session cookies, and exposes `/api/auth/me` + `/api/auth/logout`.\n *\n * Defaults to `https://ochk.io`. Override in preview/dev.\n */\n authOrigin?: string;\n /**\n * Path on the auth host that accepts `?return_to=<url>` and drives the\n * BIP-322 sign-in flow. Defaults to `/signin`.\n */\n signInPath?: string;\n /**\n * Local path (same origin as the current app) that exposes the\n * crypto-verified session. If your app ships one at `/api/auth/me`,\n * leave as default. Returns 200 `{ account }` or 401.\n */\n mePath?: string;\n /**\n * Path on the auth host to hit to clear the session cookie.\n * Defaults to `/api/auth/logout`. Called with `credentials: 'include'`\n * so the `.ochk.io` cookie is sent along.\n */\n logoutPath?: string;\n}\n\nexport const DEFAULT_CONFIG: Required<OcAuthConfig> = {\n authOrigin: 'https://ochk.io',\n signInPath: '/signin',\n mePath: '/api/auth/me',\n logoutPath: '/api/auth/logout',\n};\n\nexport function resolveConfig(cfg: OcAuthConfig | undefined): Required<OcAuthConfig> {\n return { ...DEFAULT_CONFIG, ...(cfg ?? {}) };\n}\n\nexport function buildSignInUrl(cfg: Required<OcAuthConfig>, returnTo?: string): string {\n const base = `${cfg.authOrigin}${cfg.signInPath}`;\n if (!returnTo) return base;\n const u = new URL(base);\n u.searchParams.set('return_to', returnTo);\n return u.toString();\n}\n","import * as React from 'react';\n\nimport {\n buildSignInUrl,\n DEFAULT_CONFIG,\n resolveConfig,\n type OcAccount,\n type OcAuthConfig,\n type OcSessionState,\n} from './types';\n\nconst SessionContext = React.createContext<OcSessionState | null>(null);\n\ninterface MeResponse {\n account?: {\n id?: string;\n account_id?: string;\n accountId?: string;\n btc_address?: string;\n address?: string;\n display_name?: string | null;\n displayName?: string | null;\n nostr_npub?: string | null;\n nostrNpub?: string | null;\n };\n}\n\nfunction normalizeAccount(raw: MeResponse['account']): OcAccount | null {\n if (!raw) return null;\n const address = raw.btc_address ?? raw.address;\n const accountId = raw.id ?? raw.account_id ?? raw.accountId;\n if (!address || !accountId) return null;\n return {\n accountId,\n address,\n displayName: raw.display_name ?? raw.displayName ?? null,\n nostrNpub: raw.nostr_npub ?? raw.nostrNpub ?? null,\n };\n}\n\nexport interface OcSessionProviderProps {\n children: React.ReactNode;\n config?: OcAuthConfig;\n /**\n * Optional return URL passed to the sign-in page. Defaults to the\n * current `window.location.href` at click-time.\n */\n defaultReturnTo?: string;\n}\n\n/**\n * Top-level provider that exposes the cross-subdomain oc_session to every\n * component below it. Mount once, near the root of your tree.\n */\nexport function OcSessionProvider({\n children,\n config,\n defaultReturnTo,\n}: OcSessionProviderProps): React.ReactElement {\n const cfg = React.useMemo(() => resolveConfig(config), [config]);\n const [account, setAccount] = React.useState<OcAccount | null>(null);\n const [status, setStatus] = React.useState<OcSessionState['status']>('loading');\n const [error, setError] = React.useState<Error | null>(null);\n\n const refresh = React.useCallback(async () => {\n if (typeof window === 'undefined') return;\n try {\n const res = await fetch(cfg.mePath, {\n method: 'GET',\n credentials: 'include',\n headers: { Accept: 'application/json' },\n });\n if (res.status === 401) {\n setAccount(null);\n setStatus('anonymous');\n setError(null);\n return;\n }\n if (!res.ok) {\n setStatus('error');\n setError(new Error(`me endpoint returned ${res.status}`));\n return;\n }\n const body = (await res.json()) as MeResponse;\n const acct = normalizeAccount(body.account);\n setAccount(acct);\n setStatus(acct ? 'authenticated' : 'anonymous');\n setError(null);\n } catch (err) {\n setStatus('error');\n setError(err instanceof Error ? err : new Error(String(err)));\n }\n }, [cfg.mePath]);\n\n React.useEffect(() => {\n void refresh();\n }, [refresh]);\n\n const signOut = React.useCallback(async () => {\n try {\n await fetch(`${cfg.authOrigin}${cfg.logoutPath}`, {\n method: 'POST',\n credentials: 'include',\n });\n } catch {\n // fall through — we still clear local state so the UI reflects\n // the user's intent even if the server round-trip fails.\n }\n setAccount(null);\n setStatus('anonymous');\n }, [cfg.authOrigin, cfg.logoutPath]);\n\n const value = React.useMemo<OcSessionState>(() => {\n const returnTo =\n defaultReturnTo ?? (typeof window !== 'undefined' ? window.location.href : undefined);\n return {\n status,\n account,\n error,\n refresh,\n signOut,\n signInUrl: buildSignInUrl(cfg, returnTo),\n };\n }, [status, account, error, refresh, signOut, cfg, defaultReturnTo]);\n\n return <SessionContext.Provider value={value}>{children}</SessionContext.Provider>;\n}\n\n/**\n * Access the current cross-subdomain oc_session. Must be called inside\n * an `<OcSessionProvider>`.\n */\nexport function useOcSession(): OcSessionState {\n const ctx = React.useContext(SessionContext);\n if (!ctx) {\n throw new Error(\n '[@orangecheck/auth-client] useOcSession() must be called inside <OcSessionProvider>'\n );\n }\n return ctx;\n}\n\n/**\n * Non-throwing variant — returns `null` if called outside a provider.\n * Useful for libraries that want to read the session *if it exists* but\n * shouldn't crash on apps that haven't opted in.\n */\nexport function useOptionalOcSession(): OcSessionState | null {\n return React.useContext(SessionContext);\n}\n\nexport { DEFAULT_CONFIG };\n","import * as React from 'react';\n\nimport { useOcSession } from './provider';\n\nfunction shortenAddress(addr: string): string {\n if (addr.length <= 12) return addr;\n return `${addr.slice(0, 6)}…${addr.slice(-4)}`;\n}\n\nexport interface OcSignInButtonProps extends React.AnchorHTMLAttributes<HTMLAnchorElement> {\n /** Label shown when no user is signed in. Defaults to `sign in with bitcoin`. */\n label?: string;\n /**\n * When `true`, render an `<a>` even while the session is loading, to\n * avoid layout shift. Defaults to `false` (renders nothing while loading).\n */\n eager?: boolean;\n}\n\n/**\n * Drop-in sign-in button. Renders an anchor that deep-links to the auth\n * host's sign-in page with the current URL as `?return_to=…`.\n *\n * When the user is already authenticated it renders nothing — wrap it in\n * a conditional or use `<OcAccountPill>` as the signed-in affordance.\n */\nexport function OcSignInButton({\n label = 'sign in with bitcoin',\n eager = false,\n className,\n ...rest\n}: OcSignInButtonProps): React.ReactElement | null {\n const { status, signInUrl } = useOcSession();\n if (status === 'authenticated') return null;\n if (!eager && status === 'loading') return null;\n\n return (\n <a\n {...rest}\n href={signInUrl}\n className={className}\n data-oc-sign-in-button=\"\"\n >\n {label}\n </a>\n );\n}\n\nexport interface OcAccountPillProps extends React.HTMLAttributes<HTMLDivElement> {\n /** URL to link the address to. Defaults to the auth origin's `/dashboard`. */\n dashboardUrl?: string;\n /** Override the display text. Defaults to the shortened address. */\n render?: (account: { address: string; displayName?: string | null }) => React.ReactNode;\n}\n\n/**\n * Shows the signed-in user as a short pill: `bc1q…abcd sign out`.\n *\n * Renders nothing while loading or when no user is signed in — pair with\n * `<OcSignInButton>` for the anonymous case.\n */\nexport function OcAccountPill({\n dashboardUrl,\n render,\n className,\n ...rest\n}: OcAccountPillProps): React.ReactElement | null {\n const { status, account, signOut } = useOcSession();\n\n if (status !== 'authenticated' || !account) return null;\n\n const label = render\n ? render({ address: account.address, displayName: account.displayName })\n : (account.displayName ?? shortenAddress(account.address));\n\n return (\n <div\n {...rest}\n className={className}\n data-oc-account-pill=\"\"\n style={{ display: 'inline-flex', alignItems: 'center', gap: '0.5rem', ...(rest.style ?? {}) }}\n >\n {dashboardUrl ? (\n <a href={dashboardUrl}>{label}</a>\n ) : (\n <span>{label}</span>\n )}\n <button\n type=\"button\"\n onClick={() => {\n void signOut();\n }}\n aria-label=\"Sign out\"\n style={{\n background: 'none',\n border: 'none',\n cursor: 'pointer',\n color: 'inherit',\n font: 'inherit',\n padding: 0,\n }}\n >\n sign out\n </button>\n </div>\n );\n}\n"]}
1
+ {"version":3,"sources":["../src/types.ts","../src/provider.tsx","../src/components.tsx"],"names":["React","jsx","React2","jsxs","OcAddressInput"],"mappings":"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","file":"index.js","sourcesContent":["export interface OcAccount {\n accountId: string;\n address: string;\n displayName?: string | null;\n nostrNpub?: string | null;\n}\n\nexport type OcSessionStatus = 'loading' | 'authenticated' | 'anonymous' | 'error';\n\nexport interface OcSessionState {\n status: OcSessionStatus;\n account: OcAccount | null;\n /** `null` while loading; an `Error` instance when `status === 'error'`. */\n error: Error | null;\n /** Re-fetch the session. Useful after sign-in/sign-out happens elsewhere. */\n refresh: () => Promise<void>;\n /** Trigger a sign-out. Resolves once the cookie has been cleared. */\n signOut: () => Promise<void>;\n /** URL to navigate to for sign-in on the auth host. */\n signInUrl: string;\n}\n\nexport interface OcAuthConfig {\n /**\n * Origin of the auth host — the subdomain that runs the sign-in UI,\n * issues session cookies, and exposes `/api/auth/me` + `/api/auth/logout`.\n *\n * Defaults to `https://ochk.io`. Override in preview/dev.\n */\n authOrigin?: string;\n /**\n * Path on the auth host that accepts `?return_to=<url>` and drives the\n * BIP-322 sign-in flow. Defaults to `/signin`.\n */\n signInPath?: string;\n /**\n * Local path (same origin as the current app) that exposes the\n * crypto-verified session. If your app ships one at `/api/auth/me`,\n * leave as default. Returns 200 `{ account }` or 401.\n */\n mePath?: string;\n /**\n * Path on the auth host to hit to clear the session cookie.\n * Defaults to `/api/auth/logout`. Called with `credentials: 'include'`\n * so the `.ochk.io` cookie is sent along.\n */\n logoutPath?: string;\n}\n\nexport const DEFAULT_CONFIG: Required<OcAuthConfig> = {\n authOrigin: 'https://ochk.io',\n signInPath: '/signin',\n mePath: '/api/auth/me',\n logoutPath: '/api/auth/logout',\n};\n\nexport function resolveConfig(cfg: OcAuthConfig | undefined): Required<OcAuthConfig> {\n return { ...DEFAULT_CONFIG, ...(cfg ?? {}) };\n}\n\nexport function buildSignInUrl(cfg: Required<OcAuthConfig>, returnTo?: string): string {\n const base = `${cfg.authOrigin}${cfg.signInPath}`;\n if (!returnTo) return base;\n const u = new URL(base);\n u.searchParams.set('return_to', returnTo);\n return u.toString();\n}\n","import * as React from 'react';\n\nimport {\n buildSignInUrl,\n DEFAULT_CONFIG,\n resolveConfig,\n type OcAccount,\n type OcAuthConfig,\n type OcSessionState,\n} from './types';\n\nconst SessionContext = React.createContext<OcSessionState | null>(null);\n\ninterface MeResponse {\n account?: {\n id?: string;\n account_id?: string;\n accountId?: string;\n btc_address?: string;\n address?: string;\n display_name?: string | null;\n displayName?: string | null;\n nostr_npub?: string | null;\n nostrNpub?: string | null;\n };\n}\n\nfunction normalizeAccount(raw: MeResponse['account']): OcAccount | null {\n if (!raw) return null;\n const address = raw.btc_address ?? raw.address;\n const accountId = raw.id ?? raw.account_id ?? raw.accountId;\n if (!address || !accountId) return null;\n return {\n accountId,\n address,\n displayName: raw.display_name ?? raw.displayName ?? null,\n nostrNpub: raw.nostr_npub ?? raw.nostrNpub ?? null,\n };\n}\n\nexport interface OcSessionProviderProps {\n children: React.ReactNode;\n config?: OcAuthConfig;\n /**\n * Optional return URL passed to the sign-in page. Defaults to the\n * current `window.location.href` at click-time.\n */\n defaultReturnTo?: string;\n}\n\n/**\n * Top-level provider that exposes the cross-subdomain oc_session to every\n * component below it. Mount once, near the root of your tree.\n */\nexport function OcSessionProvider({\n children,\n config,\n defaultReturnTo,\n}: OcSessionProviderProps): React.ReactElement {\n const cfg = React.useMemo(() => resolveConfig(config), [config]);\n const [account, setAccount] = React.useState<OcAccount | null>(null);\n const [status, setStatus] = React.useState<OcSessionState['status']>('loading');\n const [error, setError] = React.useState<Error | null>(null);\n\n const refresh = React.useCallback(async () => {\n if (typeof window === 'undefined') return;\n try {\n const res = await fetch(cfg.mePath, {\n method: 'GET',\n credentials: 'include',\n headers: { Accept: 'application/json' },\n });\n if (res.status === 401) {\n setAccount(null);\n setStatus('anonymous');\n setError(null);\n return;\n }\n if (!res.ok) {\n setStatus('error');\n setError(new Error(`me endpoint returned ${res.status}`));\n return;\n }\n const body = (await res.json()) as MeResponse;\n const acct = normalizeAccount(body.account);\n setAccount(acct);\n setStatus(acct ? 'authenticated' : 'anonymous');\n setError(null);\n } catch (err) {\n setStatus('error');\n setError(err instanceof Error ? err : new Error(String(err)));\n }\n }, [cfg.mePath]);\n\n React.useEffect(() => {\n void refresh();\n }, [refresh]);\n\n const signOut = React.useCallback(async () => {\n try {\n await fetch(`${cfg.authOrigin}${cfg.logoutPath}`, {\n method: 'POST',\n credentials: 'include',\n });\n } catch {\n // fall through — we still clear local state so the UI reflects\n // the user's intent even if the server round-trip fails.\n }\n setAccount(null);\n setStatus('anonymous');\n }, [cfg.authOrigin, cfg.logoutPath]);\n\n const value = React.useMemo<OcSessionState>(() => {\n const returnTo =\n defaultReturnTo ?? (typeof window !== 'undefined' ? window.location.href : undefined);\n return {\n status,\n account,\n error,\n refresh,\n signOut,\n signInUrl: buildSignInUrl(cfg, returnTo),\n };\n }, [status, account, error, refresh, signOut, cfg, defaultReturnTo]);\n\n return <SessionContext.Provider value={value}>{children}</SessionContext.Provider>;\n}\n\n/**\n * Access the current cross-subdomain oc_session. Must be called inside\n * an `<OcSessionProvider>`.\n */\nexport function useOcSession(): OcSessionState {\n const ctx = React.useContext(SessionContext);\n if (!ctx) {\n throw new Error(\n '[@orangecheck/auth-client] useOcSession() must be called inside <OcSessionProvider>'\n );\n }\n return ctx;\n}\n\n/**\n * Non-throwing variant — returns `null` if called outside a provider.\n * Useful for libraries that want to read the session *if it exists* but\n * shouldn't crash on apps that haven't opted in.\n */\nexport function useOptionalOcSession(): OcSessionState | null {\n return React.useContext(SessionContext);\n}\n\nexport { DEFAULT_CONFIG };\n","import * as React from 'react';\n\nimport { useOcSession } from './provider';\n\nfunction shortenAddress(addr: string): string {\n if (addr.length <= 12) return addr;\n return `${addr.slice(0, 6)}…${addr.slice(-4)}`;\n}\n\nfunction shortenAddressMid(addr: string): string {\n if (addr.length <= 16) return addr;\n return `${addr.slice(0, 8)}…${addr.slice(-6)}`;\n}\n\nfunction isPrefixOf(value: string, target: string): boolean {\n return target.toLowerCase().startsWith(value.toLowerCase());\n}\n\nlet listboxIdCounter = 0;\nfunction useUniqueId(prefix: string): string {\n const [id] = React.useState(() => `${prefix}-${++listboxIdCounter}`);\n return id;\n}\n\nexport interface OcSignInButtonProps extends React.AnchorHTMLAttributes<HTMLAnchorElement> {\n /** Label shown when no user is signed in. Defaults to `sign in with bitcoin`. */\n label?: string;\n /**\n * When `true`, render an `<a>` even while the session is loading, to\n * avoid layout shift. Defaults to `false` (renders nothing while loading).\n */\n eager?: boolean;\n}\n\n/**\n * Drop-in sign-in button. Renders an anchor that deep-links to the auth\n * host's sign-in page with the current URL as `?return_to=…`.\n *\n * When the user is already authenticated it renders nothing — wrap it in\n * a conditional or use `<OcAccountPill>` as the signed-in affordance.\n */\nexport function OcSignInButton({\n label = 'sign in with bitcoin',\n eager = false,\n className,\n ...rest\n}: OcSignInButtonProps): React.ReactElement | null {\n const { status, signInUrl } = useOcSession();\n if (status === 'authenticated') return null;\n if (!eager && status === 'loading') return null;\n\n return (\n <a\n {...rest}\n href={signInUrl}\n className={className}\n data-oc-sign-in-button=\"\"\n >\n {label}\n </a>\n );\n}\n\nexport interface OcAccountPillProps extends React.HTMLAttributes<HTMLDivElement> {\n /** URL to link the address to. Defaults to the auth origin's `/dashboard`. */\n dashboardUrl?: string;\n /** Override the display text. Defaults to the shortened address. */\n render?: (account: { address: string; displayName?: string | null }) => React.ReactNode;\n}\n\n/**\n * Shows the signed-in user as a short pill: `bc1q…abcd sign out`.\n *\n * Renders nothing while loading or when no user is signed in — pair with\n * `<OcSignInButton>` for the anonymous case.\n */\nexport function OcAccountPill({\n dashboardUrl,\n render,\n className,\n ...rest\n}: OcAccountPillProps): React.ReactElement | null {\n const { status, account, signOut } = useOcSession();\n\n if (status !== 'authenticated' || !account) return null;\n\n const label = render\n ? render({ address: account.address, displayName: account.displayName })\n : (account.displayName ?? shortenAddress(account.address));\n\n return (\n <div\n {...rest}\n className={className}\n data-oc-account-pill=\"\"\n style={{ display: 'inline-flex', alignItems: 'center', gap: '0.5rem', ...(rest.style ?? {}) }}\n >\n {dashboardUrl ? (\n <a href={dashboardUrl}>{label}</a>\n ) : (\n <span>{label}</span>\n )}\n <button\n type=\"button\"\n onClick={() => {\n void signOut();\n }}\n aria-label=\"Sign out\"\n style={{\n background: 'none',\n border: 'none',\n cursor: 'pointer',\n color: 'inherit',\n font: 'inherit',\n padding: 0,\n }}\n >\n sign out\n </button>\n </div>\n );\n}\n\nexport interface OcAddressInputProps\n extends Omit<React.InputHTMLAttributes<HTMLInputElement>, 'value' | 'onChange'> {\n /** Controlled value. */\n value: string;\n /** Called when value changes — typed by the user OR selected from the popover. */\n onValueChange: (value: string) => void;\n /** Label shown above the suggested address in the popover. Defaults to `use your address`. */\n suggestionLabel?: string;\n /** className applied to the wrapper `<div>`. */\n wrapperClassName?: string;\n /** className applied to the suggestion popover. Style with `[data-oc-address-popover]` otherwise. */\n popoverClassName?: string;\n /** className applied to the suggestion button. Style with `[data-oc-address-suggestion]` otherwise. */\n suggestionClassName?: string;\n}\n\n/**\n * Bitcoin-address `<input>` that, when the user is signed in via `oc_session`,\n * surfaces their address as a one-click suggestion on focus.\n *\n * Behaviour:\n * - On focus, if logged-in AND the typed value is a prefix of the session\n * address (or empty), show a small popover with `bc1q…7ke3` as a clickable\n * suggestion.\n * - Click / Enter on the suggestion fills the field with the full address.\n * - Down-arrow from the input highlights the suggestion; Up-arrow clears the\n * highlight; Escape closes the popover; clicking outside closes the popover.\n * - When the user types something that's no longer a prefix of the session\n * address, the popover hides itself out of the way.\n * - When the field already contains the session address exactly, no popover.\n *\n * Style-agnostic: minimal inline styles for positioning only. Style the parts\n * via `wrapperClassName` / `popoverClassName` / `suggestionClassName`, or via\n * the `[data-oc-address-input]`, `[data-oc-address-popover]`, and\n * `[data-oc-address-suggestion]` data attributes.\n */\nexport const OcAddressInput = React.forwardRef<HTMLInputElement, OcAddressInputProps>(\n function OcAddressInput(\n {\n value,\n onValueChange,\n suggestionLabel = 'use your address',\n wrapperClassName,\n popoverClassName,\n suggestionClassName,\n onFocus,\n onBlur,\n onKeyDown,\n ...rest\n },\n forwardedRef\n ): React.ReactElement {\n const { status, account } = useOcSession();\n const sessionAddress = status === 'authenticated' ? (account?.address ?? null) : null;\n\n const [open, setOpen] = React.useState(false);\n const [highlighted, setHighlighted] = React.useState(false);\n\n const innerRef = React.useRef<HTMLInputElement | null>(null);\n const setRef = (node: HTMLInputElement | null) => {\n innerRef.current = node;\n if (typeof forwardedRef === 'function') forwardedRef(node);\n else if (forwardedRef) forwardedRef.current = node;\n };\n const blurTimer = React.useRef<number | null>(null);\n\n const listboxId = useUniqueId('oc-addr-listbox');\n const optionId = `${listboxId}-opt`;\n\n const valueMatchesSession =\n sessionAddress != null && value.toLowerCase() === sessionAddress.toLowerCase();\n const canSuggest =\n sessionAddress != null &&\n sessionAddress.length > 0 &&\n !valueMatchesSession &&\n isPrefixOf(value, sessionAddress);\n const showPopover = open && canSuggest;\n\n function selectSuggestion() {\n if (!sessionAddress) return;\n onValueChange(sessionAddress);\n setOpen(false);\n setHighlighted(false);\n // Re-focus so the next Tab moves on naturally.\n innerRef.current?.focus();\n }\n\n function handleFocus(e: React.FocusEvent<HTMLInputElement>) {\n if (blurTimer.current != null) {\n window.clearTimeout(blurTimer.current);\n blurTimer.current = null;\n }\n setOpen(true);\n onFocus?.(e);\n }\n\n function handleBlur(e: React.FocusEvent<HTMLInputElement>) {\n // Defer close so a click on the suggestion can register first.\n blurTimer.current = window.setTimeout(() => {\n setOpen(false);\n setHighlighted(false);\n }, 120);\n onBlur?.(e);\n }\n\n function handleKeyDown(e: React.KeyboardEvent<HTMLInputElement>) {\n if (showPopover) {\n if (e.key === 'ArrowDown') {\n e.preventDefault();\n setHighlighted(true);\n } else if (e.key === 'ArrowUp') {\n e.preventDefault();\n setHighlighted(false);\n } else if (e.key === 'Escape') {\n e.preventDefault();\n setOpen(false);\n setHighlighted(false);\n } else if (e.key === 'Enter' && highlighted) {\n e.preventDefault();\n selectSuggestion();\n }\n }\n onKeyDown?.(e);\n }\n\n React.useEffect(() => {\n return () => {\n if (blurTimer.current != null) window.clearTimeout(blurTimer.current);\n };\n }, []);\n\n return (\n <div\n data-oc-address-input=\"\"\n className={wrapperClassName}\n style={{ position: 'relative' }}\n >\n <input\n {...rest}\n ref={setRef}\n value={value}\n onChange={(e) => onValueChange(e.target.value)}\n onFocus={handleFocus}\n onBlur={handleBlur}\n onKeyDown={handleKeyDown}\n role=\"combobox\"\n aria-haspopup=\"listbox\"\n aria-expanded={showPopover}\n aria-controls={showPopover ? listboxId : undefined}\n aria-activedescendant={highlighted ? optionId : undefined}\n autoComplete=\"off\"\n spellCheck={false}\n />\n {showPopover && sessionAddress && (\n <div\n id={listboxId}\n role=\"listbox\"\n data-oc-address-popover=\"\"\n className={popoverClassName}\n style={{\n position: 'absolute',\n zIndex: 50,\n top: 'calc(100% + 4px)',\n left: 0,\n right: 0,\n }}\n // Prevent the input from blurring before the click on the suggestion lands.\n onMouseDown={(e) => e.preventDefault()}\n >\n <button\n type=\"button\"\n id={optionId}\n role=\"option\"\n aria-selected={highlighted}\n data-oc-address-suggestion=\"\"\n data-highlighted={highlighted ? '' : undefined}\n className={suggestionClassName}\n onClick={selectSuggestion}\n onMouseEnter={() => setHighlighted(true)}\n onMouseLeave={() => setHighlighted(false)}\n style={{\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'space-between',\n gap: '0.75rem',\n width: '100%',\n textAlign: 'left',\n cursor: 'pointer',\n font: 'inherit',\n background: 'inherit',\n color: 'inherit',\n border: 'inherit',\n padding: 'inherit',\n }}\n >\n <span data-oc-address-suggestion-label=\"\">{suggestionLabel}</span>\n <span\n data-oc-address-suggestion-value=\"\"\n style={{ fontFamily: 'ui-monospace, monospace' }}\n >\n {shortenAddressMid(sessionAddress)}\n </span>\n </button>\n </div>\n )}\n </div>\n );\n }\n);\n"]}
package/dist/index.mjs CHANGED
@@ -1,5 +1,5 @@
1
1
  import * as React from 'react';
2
- import { jsx, jsxs } from 'react/jsx-runtime';
2
+ import { jsxs, jsx } from 'react/jsx-runtime';
3
3
 
4
4
  // src/provider.tsx
5
5
 
@@ -114,6 +114,18 @@ function shortenAddress(addr) {
114
114
  if (addr.length <= 12) return addr;
115
115
  return `${addr.slice(0, 6)}\u2026${addr.slice(-4)}`;
116
116
  }
117
+ function shortenAddressMid(addr) {
118
+ if (addr.length <= 16) return addr;
119
+ return `${addr.slice(0, 8)}\u2026${addr.slice(-6)}`;
120
+ }
121
+ function isPrefixOf(value, target) {
122
+ return target.toLowerCase().startsWith(value.toLowerCase());
123
+ }
124
+ var listboxIdCounter = 0;
125
+ function useUniqueId(prefix) {
126
+ const [id] = React.useState(() => `${prefix}-${++listboxIdCounter}`);
127
+ return id;
128
+ }
117
129
  function OcSignInButton({
118
130
  label = "sign in with bitcoin",
119
131
  eager = false,
@@ -175,7 +187,170 @@ function OcAccountPill({
175
187
  }
176
188
  );
177
189
  }
190
+ var OcAddressInput = React.forwardRef(
191
+ function OcAddressInput2({
192
+ value,
193
+ onValueChange,
194
+ suggestionLabel = "use your address",
195
+ wrapperClassName,
196
+ popoverClassName,
197
+ suggestionClassName,
198
+ onFocus,
199
+ onBlur,
200
+ onKeyDown,
201
+ ...rest
202
+ }, forwardedRef) {
203
+ const { status, account } = useOcSession();
204
+ const sessionAddress = status === "authenticated" ? account?.address ?? null : null;
205
+ const [open, setOpen] = React.useState(false);
206
+ const [highlighted, setHighlighted] = React.useState(false);
207
+ const innerRef = React.useRef(null);
208
+ const setRef = (node) => {
209
+ innerRef.current = node;
210
+ if (typeof forwardedRef === "function") forwardedRef(node);
211
+ else if (forwardedRef) forwardedRef.current = node;
212
+ };
213
+ const blurTimer = React.useRef(null);
214
+ const listboxId = useUniqueId("oc-addr-listbox");
215
+ const optionId = `${listboxId}-opt`;
216
+ const valueMatchesSession = sessionAddress != null && value.toLowerCase() === sessionAddress.toLowerCase();
217
+ const canSuggest = sessionAddress != null && sessionAddress.length > 0 && !valueMatchesSession && isPrefixOf(value, sessionAddress);
218
+ const showPopover = open && canSuggest;
219
+ function selectSuggestion() {
220
+ if (!sessionAddress) return;
221
+ onValueChange(sessionAddress);
222
+ setOpen(false);
223
+ setHighlighted(false);
224
+ innerRef.current?.focus();
225
+ }
226
+ function handleFocus(e) {
227
+ if (blurTimer.current != null) {
228
+ window.clearTimeout(blurTimer.current);
229
+ blurTimer.current = null;
230
+ }
231
+ setOpen(true);
232
+ onFocus?.(e);
233
+ }
234
+ function handleBlur(e) {
235
+ blurTimer.current = window.setTimeout(() => {
236
+ setOpen(false);
237
+ setHighlighted(false);
238
+ }, 120);
239
+ onBlur?.(e);
240
+ }
241
+ function handleKeyDown(e) {
242
+ if (showPopover) {
243
+ if (e.key === "ArrowDown") {
244
+ e.preventDefault();
245
+ setHighlighted(true);
246
+ } else if (e.key === "ArrowUp") {
247
+ e.preventDefault();
248
+ setHighlighted(false);
249
+ } else if (e.key === "Escape") {
250
+ e.preventDefault();
251
+ setOpen(false);
252
+ setHighlighted(false);
253
+ } else if (e.key === "Enter" && highlighted) {
254
+ e.preventDefault();
255
+ selectSuggestion();
256
+ }
257
+ }
258
+ onKeyDown?.(e);
259
+ }
260
+ React.useEffect(() => {
261
+ return () => {
262
+ if (blurTimer.current != null) window.clearTimeout(blurTimer.current);
263
+ };
264
+ }, []);
265
+ return /* @__PURE__ */ jsxs(
266
+ "div",
267
+ {
268
+ "data-oc-address-input": "",
269
+ className: wrapperClassName,
270
+ style: { position: "relative" },
271
+ children: [
272
+ /* @__PURE__ */ jsx(
273
+ "input",
274
+ {
275
+ ...rest,
276
+ ref: setRef,
277
+ value,
278
+ onChange: (e) => onValueChange(e.target.value),
279
+ onFocus: handleFocus,
280
+ onBlur: handleBlur,
281
+ onKeyDown: handleKeyDown,
282
+ role: "combobox",
283
+ "aria-haspopup": "listbox",
284
+ "aria-expanded": showPopover,
285
+ "aria-controls": showPopover ? listboxId : void 0,
286
+ "aria-activedescendant": highlighted ? optionId : void 0,
287
+ autoComplete: "off",
288
+ spellCheck: false
289
+ }
290
+ ),
291
+ showPopover && sessionAddress && /* @__PURE__ */ jsx(
292
+ "div",
293
+ {
294
+ id: listboxId,
295
+ role: "listbox",
296
+ "data-oc-address-popover": "",
297
+ className: popoverClassName,
298
+ style: {
299
+ position: "absolute",
300
+ zIndex: 50,
301
+ top: "calc(100% + 4px)",
302
+ left: 0,
303
+ right: 0
304
+ },
305
+ onMouseDown: (e) => e.preventDefault(),
306
+ children: /* @__PURE__ */ jsxs(
307
+ "button",
308
+ {
309
+ type: "button",
310
+ id: optionId,
311
+ role: "option",
312
+ "aria-selected": highlighted,
313
+ "data-oc-address-suggestion": "",
314
+ "data-highlighted": highlighted ? "" : void 0,
315
+ className: suggestionClassName,
316
+ onClick: selectSuggestion,
317
+ onMouseEnter: () => setHighlighted(true),
318
+ onMouseLeave: () => setHighlighted(false),
319
+ style: {
320
+ display: "flex",
321
+ alignItems: "center",
322
+ justifyContent: "space-between",
323
+ gap: "0.75rem",
324
+ width: "100%",
325
+ textAlign: "left",
326
+ cursor: "pointer",
327
+ font: "inherit",
328
+ background: "inherit",
329
+ color: "inherit",
330
+ border: "inherit",
331
+ padding: "inherit"
332
+ },
333
+ children: [
334
+ /* @__PURE__ */ jsx("span", { "data-oc-address-suggestion-label": "", children: suggestionLabel }),
335
+ /* @__PURE__ */ jsx(
336
+ "span",
337
+ {
338
+ "data-oc-address-suggestion-value": "",
339
+ style: { fontFamily: "ui-monospace, monospace" },
340
+ children: shortenAddressMid(sessionAddress)
341
+ }
342
+ )
343
+ ]
344
+ }
345
+ )
346
+ }
347
+ )
348
+ ]
349
+ }
350
+ );
351
+ }
352
+ );
178
353
 
179
- export { DEFAULT_CONFIG, OcAccountPill, OcSessionProvider, OcSignInButton, buildSignInUrl, useOcSession, useOptionalOcSession };
354
+ export { DEFAULT_CONFIG, OcAccountPill, OcAddressInput, OcSessionProvider, OcSignInButton, buildSignInUrl, useOcSession, useOptionalOcSession };
180
355
  //# sourceMappingURL=index.mjs.map
181
356
  //# sourceMappingURL=index.mjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/types.ts","../src/provider.tsx","../src/components.tsx"],"names":["jsx"],"mappings":"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","file":"index.mjs","sourcesContent":["export interface OcAccount {\n accountId: string;\n address: string;\n displayName?: string | null;\n nostrNpub?: string | null;\n}\n\nexport type OcSessionStatus = 'loading' | 'authenticated' | 'anonymous' | 'error';\n\nexport interface OcSessionState {\n status: OcSessionStatus;\n account: OcAccount | null;\n /** `null` while loading; an `Error` instance when `status === 'error'`. */\n error: Error | null;\n /** Re-fetch the session. Useful after sign-in/sign-out happens elsewhere. */\n refresh: () => Promise<void>;\n /** Trigger a sign-out. Resolves once the cookie has been cleared. */\n signOut: () => Promise<void>;\n /** URL to navigate to for sign-in on the auth host. */\n signInUrl: string;\n}\n\nexport interface OcAuthConfig {\n /**\n * Origin of the auth host — the subdomain that runs the sign-in UI,\n * issues session cookies, and exposes `/api/auth/me` + `/api/auth/logout`.\n *\n * Defaults to `https://ochk.io`. Override in preview/dev.\n */\n authOrigin?: string;\n /**\n * Path on the auth host that accepts `?return_to=<url>` and drives the\n * BIP-322 sign-in flow. Defaults to `/signin`.\n */\n signInPath?: string;\n /**\n * Local path (same origin as the current app) that exposes the\n * crypto-verified session. If your app ships one at `/api/auth/me`,\n * leave as default. Returns 200 `{ account }` or 401.\n */\n mePath?: string;\n /**\n * Path on the auth host to hit to clear the session cookie.\n * Defaults to `/api/auth/logout`. Called with `credentials: 'include'`\n * so the `.ochk.io` cookie is sent along.\n */\n logoutPath?: string;\n}\n\nexport const DEFAULT_CONFIG: Required<OcAuthConfig> = {\n authOrigin: 'https://ochk.io',\n signInPath: '/signin',\n mePath: '/api/auth/me',\n logoutPath: '/api/auth/logout',\n};\n\nexport function resolveConfig(cfg: OcAuthConfig | undefined): Required<OcAuthConfig> {\n return { ...DEFAULT_CONFIG, ...(cfg ?? {}) };\n}\n\nexport function buildSignInUrl(cfg: Required<OcAuthConfig>, returnTo?: string): string {\n const base = `${cfg.authOrigin}${cfg.signInPath}`;\n if (!returnTo) return base;\n const u = new URL(base);\n u.searchParams.set('return_to', returnTo);\n return u.toString();\n}\n","import * as React from 'react';\n\nimport {\n buildSignInUrl,\n DEFAULT_CONFIG,\n resolveConfig,\n type OcAccount,\n type OcAuthConfig,\n type OcSessionState,\n} from './types';\n\nconst SessionContext = React.createContext<OcSessionState | null>(null);\n\ninterface MeResponse {\n account?: {\n id?: string;\n account_id?: string;\n accountId?: string;\n btc_address?: string;\n address?: string;\n display_name?: string | null;\n displayName?: string | null;\n nostr_npub?: string | null;\n nostrNpub?: string | null;\n };\n}\n\nfunction normalizeAccount(raw: MeResponse['account']): OcAccount | null {\n if (!raw) return null;\n const address = raw.btc_address ?? raw.address;\n const accountId = raw.id ?? raw.account_id ?? raw.accountId;\n if (!address || !accountId) return null;\n return {\n accountId,\n address,\n displayName: raw.display_name ?? raw.displayName ?? null,\n nostrNpub: raw.nostr_npub ?? raw.nostrNpub ?? null,\n };\n}\n\nexport interface OcSessionProviderProps {\n children: React.ReactNode;\n config?: OcAuthConfig;\n /**\n * Optional return URL passed to the sign-in page. Defaults to the\n * current `window.location.href` at click-time.\n */\n defaultReturnTo?: string;\n}\n\n/**\n * Top-level provider that exposes the cross-subdomain oc_session to every\n * component below it. Mount once, near the root of your tree.\n */\nexport function OcSessionProvider({\n children,\n config,\n defaultReturnTo,\n}: OcSessionProviderProps): React.ReactElement {\n const cfg = React.useMemo(() => resolveConfig(config), [config]);\n const [account, setAccount] = React.useState<OcAccount | null>(null);\n const [status, setStatus] = React.useState<OcSessionState['status']>('loading');\n const [error, setError] = React.useState<Error | null>(null);\n\n const refresh = React.useCallback(async () => {\n if (typeof window === 'undefined') return;\n try {\n const res = await fetch(cfg.mePath, {\n method: 'GET',\n credentials: 'include',\n headers: { Accept: 'application/json' },\n });\n if (res.status === 401) {\n setAccount(null);\n setStatus('anonymous');\n setError(null);\n return;\n }\n if (!res.ok) {\n setStatus('error');\n setError(new Error(`me endpoint returned ${res.status}`));\n return;\n }\n const body = (await res.json()) as MeResponse;\n const acct = normalizeAccount(body.account);\n setAccount(acct);\n setStatus(acct ? 'authenticated' : 'anonymous');\n setError(null);\n } catch (err) {\n setStatus('error');\n setError(err instanceof Error ? err : new Error(String(err)));\n }\n }, [cfg.mePath]);\n\n React.useEffect(() => {\n void refresh();\n }, [refresh]);\n\n const signOut = React.useCallback(async () => {\n try {\n await fetch(`${cfg.authOrigin}${cfg.logoutPath}`, {\n method: 'POST',\n credentials: 'include',\n });\n } catch {\n // fall through — we still clear local state so the UI reflects\n // the user's intent even if the server round-trip fails.\n }\n setAccount(null);\n setStatus('anonymous');\n }, [cfg.authOrigin, cfg.logoutPath]);\n\n const value = React.useMemo<OcSessionState>(() => {\n const returnTo =\n defaultReturnTo ?? (typeof window !== 'undefined' ? window.location.href : undefined);\n return {\n status,\n account,\n error,\n refresh,\n signOut,\n signInUrl: buildSignInUrl(cfg, returnTo),\n };\n }, [status, account, error, refresh, signOut, cfg, defaultReturnTo]);\n\n return <SessionContext.Provider value={value}>{children}</SessionContext.Provider>;\n}\n\n/**\n * Access the current cross-subdomain oc_session. Must be called inside\n * an `<OcSessionProvider>`.\n */\nexport function useOcSession(): OcSessionState {\n const ctx = React.useContext(SessionContext);\n if (!ctx) {\n throw new Error(\n '[@orangecheck/auth-client] useOcSession() must be called inside <OcSessionProvider>'\n );\n }\n return ctx;\n}\n\n/**\n * Non-throwing variant — returns `null` if called outside a provider.\n * Useful for libraries that want to read the session *if it exists* but\n * shouldn't crash on apps that haven't opted in.\n */\nexport function useOptionalOcSession(): OcSessionState | null {\n return React.useContext(SessionContext);\n}\n\nexport { DEFAULT_CONFIG };\n","import * as React from 'react';\n\nimport { useOcSession } from './provider';\n\nfunction shortenAddress(addr: string): string {\n if (addr.length <= 12) return addr;\n return `${addr.slice(0, 6)}…${addr.slice(-4)}`;\n}\n\nexport interface OcSignInButtonProps extends React.AnchorHTMLAttributes<HTMLAnchorElement> {\n /** Label shown when no user is signed in. Defaults to `sign in with bitcoin`. */\n label?: string;\n /**\n * When `true`, render an `<a>` even while the session is loading, to\n * avoid layout shift. Defaults to `false` (renders nothing while loading).\n */\n eager?: boolean;\n}\n\n/**\n * Drop-in sign-in button. Renders an anchor that deep-links to the auth\n * host's sign-in page with the current URL as `?return_to=…`.\n *\n * When the user is already authenticated it renders nothing — wrap it in\n * a conditional or use `<OcAccountPill>` as the signed-in affordance.\n */\nexport function OcSignInButton({\n label = 'sign in with bitcoin',\n eager = false,\n className,\n ...rest\n}: OcSignInButtonProps): React.ReactElement | null {\n const { status, signInUrl } = useOcSession();\n if (status === 'authenticated') return null;\n if (!eager && status === 'loading') return null;\n\n return (\n <a\n {...rest}\n href={signInUrl}\n className={className}\n data-oc-sign-in-button=\"\"\n >\n {label}\n </a>\n );\n}\n\nexport interface OcAccountPillProps extends React.HTMLAttributes<HTMLDivElement> {\n /** URL to link the address to. Defaults to the auth origin's `/dashboard`. */\n dashboardUrl?: string;\n /** Override the display text. Defaults to the shortened address. */\n render?: (account: { address: string; displayName?: string | null }) => React.ReactNode;\n}\n\n/**\n * Shows the signed-in user as a short pill: `bc1q…abcd sign out`.\n *\n * Renders nothing while loading or when no user is signed in — pair with\n * `<OcSignInButton>` for the anonymous case.\n */\nexport function OcAccountPill({\n dashboardUrl,\n render,\n className,\n ...rest\n}: OcAccountPillProps): React.ReactElement | null {\n const { status, account, signOut } = useOcSession();\n\n if (status !== 'authenticated' || !account) return null;\n\n const label = render\n ? render({ address: account.address, displayName: account.displayName })\n : (account.displayName ?? shortenAddress(account.address));\n\n return (\n <div\n {...rest}\n className={className}\n data-oc-account-pill=\"\"\n style={{ display: 'inline-flex', alignItems: 'center', gap: '0.5rem', ...(rest.style ?? {}) }}\n >\n {dashboardUrl ? (\n <a href={dashboardUrl}>{label}</a>\n ) : (\n <span>{label}</span>\n )}\n <button\n type=\"button\"\n onClick={() => {\n void signOut();\n }}\n aria-label=\"Sign out\"\n style={{\n background: 'none',\n border: 'none',\n cursor: 'pointer',\n color: 'inherit',\n font: 'inherit',\n padding: 0,\n }}\n >\n sign out\n </button>\n </div>\n );\n}\n"]}
1
+ {"version":3,"sources":["../src/types.ts","../src/provider.tsx","../src/components.tsx"],"names":["React2","jsx","OcAddressInput"],"mappings":"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","file":"index.mjs","sourcesContent":["export interface OcAccount {\n accountId: string;\n address: string;\n displayName?: string | null;\n nostrNpub?: string | null;\n}\n\nexport type OcSessionStatus = 'loading' | 'authenticated' | 'anonymous' | 'error';\n\nexport interface OcSessionState {\n status: OcSessionStatus;\n account: OcAccount | null;\n /** `null` while loading; an `Error` instance when `status === 'error'`. */\n error: Error | null;\n /** Re-fetch the session. Useful after sign-in/sign-out happens elsewhere. */\n refresh: () => Promise<void>;\n /** Trigger a sign-out. Resolves once the cookie has been cleared. */\n signOut: () => Promise<void>;\n /** URL to navigate to for sign-in on the auth host. */\n signInUrl: string;\n}\n\nexport interface OcAuthConfig {\n /**\n * Origin of the auth host — the subdomain that runs the sign-in UI,\n * issues session cookies, and exposes `/api/auth/me` + `/api/auth/logout`.\n *\n * Defaults to `https://ochk.io`. Override in preview/dev.\n */\n authOrigin?: string;\n /**\n * Path on the auth host that accepts `?return_to=<url>` and drives the\n * BIP-322 sign-in flow. Defaults to `/signin`.\n */\n signInPath?: string;\n /**\n * Local path (same origin as the current app) that exposes the\n * crypto-verified session. If your app ships one at `/api/auth/me`,\n * leave as default. Returns 200 `{ account }` or 401.\n */\n mePath?: string;\n /**\n * Path on the auth host to hit to clear the session cookie.\n * Defaults to `/api/auth/logout`. Called with `credentials: 'include'`\n * so the `.ochk.io` cookie is sent along.\n */\n logoutPath?: string;\n}\n\nexport const DEFAULT_CONFIG: Required<OcAuthConfig> = {\n authOrigin: 'https://ochk.io',\n signInPath: '/signin',\n mePath: '/api/auth/me',\n logoutPath: '/api/auth/logout',\n};\n\nexport function resolveConfig(cfg: OcAuthConfig | undefined): Required<OcAuthConfig> {\n return { ...DEFAULT_CONFIG, ...(cfg ?? {}) };\n}\n\nexport function buildSignInUrl(cfg: Required<OcAuthConfig>, returnTo?: string): string {\n const base = `${cfg.authOrigin}${cfg.signInPath}`;\n if (!returnTo) return base;\n const u = new URL(base);\n u.searchParams.set('return_to', returnTo);\n return u.toString();\n}\n","import * as React from 'react';\n\nimport {\n buildSignInUrl,\n DEFAULT_CONFIG,\n resolveConfig,\n type OcAccount,\n type OcAuthConfig,\n type OcSessionState,\n} from './types';\n\nconst SessionContext = React.createContext<OcSessionState | null>(null);\n\ninterface MeResponse {\n account?: {\n id?: string;\n account_id?: string;\n accountId?: string;\n btc_address?: string;\n address?: string;\n display_name?: string | null;\n displayName?: string | null;\n nostr_npub?: string | null;\n nostrNpub?: string | null;\n };\n}\n\nfunction normalizeAccount(raw: MeResponse['account']): OcAccount | null {\n if (!raw) return null;\n const address = raw.btc_address ?? raw.address;\n const accountId = raw.id ?? raw.account_id ?? raw.accountId;\n if (!address || !accountId) return null;\n return {\n accountId,\n address,\n displayName: raw.display_name ?? raw.displayName ?? null,\n nostrNpub: raw.nostr_npub ?? raw.nostrNpub ?? null,\n };\n}\n\nexport interface OcSessionProviderProps {\n children: React.ReactNode;\n config?: OcAuthConfig;\n /**\n * Optional return URL passed to the sign-in page. Defaults to the\n * current `window.location.href` at click-time.\n */\n defaultReturnTo?: string;\n}\n\n/**\n * Top-level provider that exposes the cross-subdomain oc_session to every\n * component below it. Mount once, near the root of your tree.\n */\nexport function OcSessionProvider({\n children,\n config,\n defaultReturnTo,\n}: OcSessionProviderProps): React.ReactElement {\n const cfg = React.useMemo(() => resolveConfig(config), [config]);\n const [account, setAccount] = React.useState<OcAccount | null>(null);\n const [status, setStatus] = React.useState<OcSessionState['status']>('loading');\n const [error, setError] = React.useState<Error | null>(null);\n\n const refresh = React.useCallback(async () => {\n if (typeof window === 'undefined') return;\n try {\n const res = await fetch(cfg.mePath, {\n method: 'GET',\n credentials: 'include',\n headers: { Accept: 'application/json' },\n });\n if (res.status === 401) {\n setAccount(null);\n setStatus('anonymous');\n setError(null);\n return;\n }\n if (!res.ok) {\n setStatus('error');\n setError(new Error(`me endpoint returned ${res.status}`));\n return;\n }\n const body = (await res.json()) as MeResponse;\n const acct = normalizeAccount(body.account);\n setAccount(acct);\n setStatus(acct ? 'authenticated' : 'anonymous');\n setError(null);\n } catch (err) {\n setStatus('error');\n setError(err instanceof Error ? err : new Error(String(err)));\n }\n }, [cfg.mePath]);\n\n React.useEffect(() => {\n void refresh();\n }, [refresh]);\n\n const signOut = React.useCallback(async () => {\n try {\n await fetch(`${cfg.authOrigin}${cfg.logoutPath}`, {\n method: 'POST',\n credentials: 'include',\n });\n } catch {\n // fall through — we still clear local state so the UI reflects\n // the user's intent even if the server round-trip fails.\n }\n setAccount(null);\n setStatus('anonymous');\n }, [cfg.authOrigin, cfg.logoutPath]);\n\n const value = React.useMemo<OcSessionState>(() => {\n const returnTo =\n defaultReturnTo ?? (typeof window !== 'undefined' ? window.location.href : undefined);\n return {\n status,\n account,\n error,\n refresh,\n signOut,\n signInUrl: buildSignInUrl(cfg, returnTo),\n };\n }, [status, account, error, refresh, signOut, cfg, defaultReturnTo]);\n\n return <SessionContext.Provider value={value}>{children}</SessionContext.Provider>;\n}\n\n/**\n * Access the current cross-subdomain oc_session. Must be called inside\n * an `<OcSessionProvider>`.\n */\nexport function useOcSession(): OcSessionState {\n const ctx = React.useContext(SessionContext);\n if (!ctx) {\n throw new Error(\n '[@orangecheck/auth-client] useOcSession() must be called inside <OcSessionProvider>'\n );\n }\n return ctx;\n}\n\n/**\n * Non-throwing variant — returns `null` if called outside a provider.\n * Useful for libraries that want to read the session *if it exists* but\n * shouldn't crash on apps that haven't opted in.\n */\nexport function useOptionalOcSession(): OcSessionState | null {\n return React.useContext(SessionContext);\n}\n\nexport { DEFAULT_CONFIG };\n","import * as React from 'react';\n\nimport { useOcSession } from './provider';\n\nfunction shortenAddress(addr: string): string {\n if (addr.length <= 12) return addr;\n return `${addr.slice(0, 6)}…${addr.slice(-4)}`;\n}\n\nfunction shortenAddressMid(addr: string): string {\n if (addr.length <= 16) return addr;\n return `${addr.slice(0, 8)}…${addr.slice(-6)}`;\n}\n\nfunction isPrefixOf(value: string, target: string): boolean {\n return target.toLowerCase().startsWith(value.toLowerCase());\n}\n\nlet listboxIdCounter = 0;\nfunction useUniqueId(prefix: string): string {\n const [id] = React.useState(() => `${prefix}-${++listboxIdCounter}`);\n return id;\n}\n\nexport interface OcSignInButtonProps extends React.AnchorHTMLAttributes<HTMLAnchorElement> {\n /** Label shown when no user is signed in. Defaults to `sign in with bitcoin`. */\n label?: string;\n /**\n * When `true`, render an `<a>` even while the session is loading, to\n * avoid layout shift. Defaults to `false` (renders nothing while loading).\n */\n eager?: boolean;\n}\n\n/**\n * Drop-in sign-in button. Renders an anchor that deep-links to the auth\n * host's sign-in page with the current URL as `?return_to=…`.\n *\n * When the user is already authenticated it renders nothing — wrap it in\n * a conditional or use `<OcAccountPill>` as the signed-in affordance.\n */\nexport function OcSignInButton({\n label = 'sign in with bitcoin',\n eager = false,\n className,\n ...rest\n}: OcSignInButtonProps): React.ReactElement | null {\n const { status, signInUrl } = useOcSession();\n if (status === 'authenticated') return null;\n if (!eager && status === 'loading') return null;\n\n return (\n <a\n {...rest}\n href={signInUrl}\n className={className}\n data-oc-sign-in-button=\"\"\n >\n {label}\n </a>\n );\n}\n\nexport interface OcAccountPillProps extends React.HTMLAttributes<HTMLDivElement> {\n /** URL to link the address to. Defaults to the auth origin's `/dashboard`. */\n dashboardUrl?: string;\n /** Override the display text. Defaults to the shortened address. */\n render?: (account: { address: string; displayName?: string | null }) => React.ReactNode;\n}\n\n/**\n * Shows the signed-in user as a short pill: `bc1q…abcd sign out`.\n *\n * Renders nothing while loading or when no user is signed in — pair with\n * `<OcSignInButton>` for the anonymous case.\n */\nexport function OcAccountPill({\n dashboardUrl,\n render,\n className,\n ...rest\n}: OcAccountPillProps): React.ReactElement | null {\n const { status, account, signOut } = useOcSession();\n\n if (status !== 'authenticated' || !account) return null;\n\n const label = render\n ? render({ address: account.address, displayName: account.displayName })\n : (account.displayName ?? shortenAddress(account.address));\n\n return (\n <div\n {...rest}\n className={className}\n data-oc-account-pill=\"\"\n style={{ display: 'inline-flex', alignItems: 'center', gap: '0.5rem', ...(rest.style ?? {}) }}\n >\n {dashboardUrl ? (\n <a href={dashboardUrl}>{label}</a>\n ) : (\n <span>{label}</span>\n )}\n <button\n type=\"button\"\n onClick={() => {\n void signOut();\n }}\n aria-label=\"Sign out\"\n style={{\n background: 'none',\n border: 'none',\n cursor: 'pointer',\n color: 'inherit',\n font: 'inherit',\n padding: 0,\n }}\n >\n sign out\n </button>\n </div>\n );\n}\n\nexport interface OcAddressInputProps\n extends Omit<React.InputHTMLAttributes<HTMLInputElement>, 'value' | 'onChange'> {\n /** Controlled value. */\n value: string;\n /** Called when value changes — typed by the user OR selected from the popover. */\n onValueChange: (value: string) => void;\n /** Label shown above the suggested address in the popover. Defaults to `use your address`. */\n suggestionLabel?: string;\n /** className applied to the wrapper `<div>`. */\n wrapperClassName?: string;\n /** className applied to the suggestion popover. Style with `[data-oc-address-popover]` otherwise. */\n popoverClassName?: string;\n /** className applied to the suggestion button. Style with `[data-oc-address-suggestion]` otherwise. */\n suggestionClassName?: string;\n}\n\n/**\n * Bitcoin-address `<input>` that, when the user is signed in via `oc_session`,\n * surfaces their address as a one-click suggestion on focus.\n *\n * Behaviour:\n * - On focus, if logged-in AND the typed value is a prefix of the session\n * address (or empty), show a small popover with `bc1q…7ke3` as a clickable\n * suggestion.\n * - Click / Enter on the suggestion fills the field with the full address.\n * - Down-arrow from the input highlights the suggestion; Up-arrow clears the\n * highlight; Escape closes the popover; clicking outside closes the popover.\n * - When the user types something that's no longer a prefix of the session\n * address, the popover hides itself out of the way.\n * - When the field already contains the session address exactly, no popover.\n *\n * Style-agnostic: minimal inline styles for positioning only. Style the parts\n * via `wrapperClassName` / `popoverClassName` / `suggestionClassName`, or via\n * the `[data-oc-address-input]`, `[data-oc-address-popover]`, and\n * `[data-oc-address-suggestion]` data attributes.\n */\nexport const OcAddressInput = React.forwardRef<HTMLInputElement, OcAddressInputProps>(\n function OcAddressInput(\n {\n value,\n onValueChange,\n suggestionLabel = 'use your address',\n wrapperClassName,\n popoverClassName,\n suggestionClassName,\n onFocus,\n onBlur,\n onKeyDown,\n ...rest\n },\n forwardedRef\n ): React.ReactElement {\n const { status, account } = useOcSession();\n const sessionAddress = status === 'authenticated' ? (account?.address ?? null) : null;\n\n const [open, setOpen] = React.useState(false);\n const [highlighted, setHighlighted] = React.useState(false);\n\n const innerRef = React.useRef<HTMLInputElement | null>(null);\n const setRef = (node: HTMLInputElement | null) => {\n innerRef.current = node;\n if (typeof forwardedRef === 'function') forwardedRef(node);\n else if (forwardedRef) forwardedRef.current = node;\n };\n const blurTimer = React.useRef<number | null>(null);\n\n const listboxId = useUniqueId('oc-addr-listbox');\n const optionId = `${listboxId}-opt`;\n\n const valueMatchesSession =\n sessionAddress != null && value.toLowerCase() === sessionAddress.toLowerCase();\n const canSuggest =\n sessionAddress != null &&\n sessionAddress.length > 0 &&\n !valueMatchesSession &&\n isPrefixOf(value, sessionAddress);\n const showPopover = open && canSuggest;\n\n function selectSuggestion() {\n if (!sessionAddress) return;\n onValueChange(sessionAddress);\n setOpen(false);\n setHighlighted(false);\n // Re-focus so the next Tab moves on naturally.\n innerRef.current?.focus();\n }\n\n function handleFocus(e: React.FocusEvent<HTMLInputElement>) {\n if (blurTimer.current != null) {\n window.clearTimeout(blurTimer.current);\n blurTimer.current = null;\n }\n setOpen(true);\n onFocus?.(e);\n }\n\n function handleBlur(e: React.FocusEvent<HTMLInputElement>) {\n // Defer close so a click on the suggestion can register first.\n blurTimer.current = window.setTimeout(() => {\n setOpen(false);\n setHighlighted(false);\n }, 120);\n onBlur?.(e);\n }\n\n function handleKeyDown(e: React.KeyboardEvent<HTMLInputElement>) {\n if (showPopover) {\n if (e.key === 'ArrowDown') {\n e.preventDefault();\n setHighlighted(true);\n } else if (e.key === 'ArrowUp') {\n e.preventDefault();\n setHighlighted(false);\n } else if (e.key === 'Escape') {\n e.preventDefault();\n setOpen(false);\n setHighlighted(false);\n } else if (e.key === 'Enter' && highlighted) {\n e.preventDefault();\n selectSuggestion();\n }\n }\n onKeyDown?.(e);\n }\n\n React.useEffect(() => {\n return () => {\n if (blurTimer.current != null) window.clearTimeout(blurTimer.current);\n };\n }, []);\n\n return (\n <div\n data-oc-address-input=\"\"\n className={wrapperClassName}\n style={{ position: 'relative' }}\n >\n <input\n {...rest}\n ref={setRef}\n value={value}\n onChange={(e) => onValueChange(e.target.value)}\n onFocus={handleFocus}\n onBlur={handleBlur}\n onKeyDown={handleKeyDown}\n role=\"combobox\"\n aria-haspopup=\"listbox\"\n aria-expanded={showPopover}\n aria-controls={showPopover ? listboxId : undefined}\n aria-activedescendant={highlighted ? optionId : undefined}\n autoComplete=\"off\"\n spellCheck={false}\n />\n {showPopover && sessionAddress && (\n <div\n id={listboxId}\n role=\"listbox\"\n data-oc-address-popover=\"\"\n className={popoverClassName}\n style={{\n position: 'absolute',\n zIndex: 50,\n top: 'calc(100% + 4px)',\n left: 0,\n right: 0,\n }}\n // Prevent the input from blurring before the click on the suggestion lands.\n onMouseDown={(e) => e.preventDefault()}\n >\n <button\n type=\"button\"\n id={optionId}\n role=\"option\"\n aria-selected={highlighted}\n data-oc-address-suggestion=\"\"\n data-highlighted={highlighted ? '' : undefined}\n className={suggestionClassName}\n onClick={selectSuggestion}\n onMouseEnter={() => setHighlighted(true)}\n onMouseLeave={() => setHighlighted(false)}\n style={{\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'space-between',\n gap: '0.75rem',\n width: '100%',\n textAlign: 'left',\n cursor: 'pointer',\n font: 'inherit',\n background: 'inherit',\n color: 'inherit',\n border: 'inherit',\n padding: 'inherit',\n }}\n >\n <span data-oc-address-suggestion-label=\"\">{suggestionLabel}</span>\n <span\n data-oc-address-suggestion-value=\"\"\n style={{ fontFamily: 'ui-monospace, monospace' }}\n >\n {shortenAddressMid(sessionAddress)}\n </span>\n </button>\n </div>\n )}\n </div>\n );\n }\n);\n"]}
package/package.json CHANGED
@@ -1,65 +1,68 @@
1
1
  {
2
- "name": "@orangecheck/auth-client",
3
- "version": "0.1.0",
4
- "description": "React hooks and components for the cross-subdomain oc_session. Drop-in sign-in button, account pill, and useOcSession() hook.",
5
- "keywords": [
6
- "orangecheck",
7
- "bitcoin",
8
- "auth",
9
- "react",
10
- "sso",
11
- "ed25519"
12
- ],
13
- "author": "OrangeCheck",
14
- "license": "MIT",
15
- "homepage": "https://ochk.io",
16
- "repository": {
17
- "type": "git",
18
- "url": "https://github.com/orangecheck/oc-packages.git",
19
- "directory": "auth-client"
20
- },
21
- "bugs": {
22
- "url": "https://github.com/orangecheck/oc-packages/issues"
23
- },
24
- "main": "./dist/index.js",
25
- "module": "./dist/index.mjs",
26
- "types": "./dist/index.d.ts",
27
- "exports": {
28
- ".": {
29
- "types": "./dist/index.d.ts",
30
- "import": "./dist/index.mjs",
31
- "require": "./dist/index.js"
32
- }
33
- },
34
- "files": [
35
- "dist",
36
- "README.md",
37
- "LICENSE"
38
- ],
39
- "scripts": {
40
- "build": "tsup",
41
- "dev": "tsup --watch",
42
- "test": "vitest run",
43
- "type-check": "tsc --noEmit",
44
- "clean": "rm -rf dist",
45
- "prepublishOnly": "npm run clean && npm run build"
46
- },
47
- "peerDependencies": {
48
- "@orangecheck/auth-core": "^0.1.0",
49
- "react": "^18.0.0 || ^19.0.0",
50
- "react-dom": "^18.0.0 || ^19.0.0"
51
- },
52
- "devDependencies": {
53
- "@orangecheck/auth-core": "^0.1.0",
54
- "@testing-library/react": "^16.3.2",
55
- "@types/node": "^22.0.0",
56
- "@types/react": "^18.3.12",
57
- "@types/react-dom": "^18.3.1",
58
- "jsdom": "^29.0.2",
59
- "react": "^18.3.1",
60
- "react-dom": "^18.3.1",
61
- "tsup": "^8.3.5",
62
- "typescript": "^5.6.3",
63
- "vitest": "^3.0.0"
2
+ "name": "@orangecheck/auth-client",
3
+ "version": "0.2.0",
4
+ "description": "React hooks and components for the cross-subdomain oc_session. Drop-in sign-in button, account pill, session-aware address input, and useOcSession() hook.",
5
+ "keywords": [
6
+ "orangecheck",
7
+ "bitcoin",
8
+ "auth",
9
+ "react",
10
+ "sso",
11
+ "ed25519"
12
+ ],
13
+ "author": "OrangeCheck",
14
+ "license": "MIT",
15
+ "homepage": "https://ochk.io",
16
+ "repository": {
17
+ "type": "git",
18
+ "url": "https://github.com/orangecheck/oc-packages.git",
19
+ "directory": "auth-client"
20
+ },
21
+ "bugs": {
22
+ "url": "https://github.com/orangecheck/oc-packages/issues"
23
+ },
24
+ "main": "./dist/index.js",
25
+ "module": "./dist/index.mjs",
26
+ "types": "./dist/index.d.ts",
27
+ "exports": {
28
+ ".": {
29
+ "types": "./dist/index.d.ts",
30
+ "import": "./dist/index.mjs",
31
+ "require": "./dist/index.js"
64
32
  }
33
+ },
34
+ "files": [
35
+ "dist",
36
+ "README.md",
37
+ "LICENSE"
38
+ ],
39
+ "scripts": {
40
+ "build": "tsup",
41
+ "dev": "tsup --watch",
42
+ "test": "vitest run",
43
+ "type-check": "tsc --noEmit",
44
+ "clean": "rm -rf dist",
45
+ "prepublishOnly": "npm run clean && npm run build"
46
+ },
47
+ "peerDependencies": {
48
+ "@orangecheck/auth-core": "^0.1.0",
49
+ "react": "^18.0.0 || ^19.0.0",
50
+ "react-dom": "^18.0.0 || ^19.0.0"
51
+ },
52
+ "devDependencies": {
53
+ "@orangecheck/auth-core": "^0.1.0",
54
+ "@testing-library/react": "^16.3.2",
55
+ "@types/node": "^22.0.0",
56
+ "@types/react": "^18.3.12",
57
+ "@types/react-dom": "^18.3.1",
58
+ "jsdom": "^29.0.2",
59
+ "react": "^18.3.1",
60
+ "react-dom": "^18.3.1",
61
+ "tsup": "^8.3.5",
62
+ "typescript": "^5.6.3",
63
+ "vitest": "^3.0.0"
64
+ },
65
+ "publishConfig": {
66
+ "access": "public"
67
+ }
65
68
  }