@hyperyai/sdk 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (102) hide show
  1. package/LICENSE +13 -0
  2. package/README.md +391 -0
  3. package/dist/components/AuthButton.d.ts +51 -0
  4. package/dist/components/AuthButton.js +60 -0
  5. package/dist/components/AuthModal.d.ts +20 -0
  6. package/dist/components/AuthModal.js +62 -0
  7. package/dist/components/BuyButton.d.ts +47 -0
  8. package/dist/components/BuyButton.js +74 -0
  9. package/dist/components/ErrorBoundary.d.ts +13 -0
  10. package/dist/components/ErrorBoundary.js +24 -0
  11. package/dist/components/HyperyModals.d.ts +30 -0
  12. package/dist/components/HyperyModals.js +30 -0
  13. package/dist/components/InsufficientCreditsAlert.d.ts +11 -0
  14. package/dist/components/InsufficientCreditsAlert.js +12 -0
  15. package/dist/components/ModernAuthForm.d.ts +52 -0
  16. package/dist/components/ModernAuthForm.js +83 -0
  17. package/dist/components/RestrictionModal.d.ts +43 -0
  18. package/dist/components/RestrictionModal.js +167 -0
  19. package/dist/components/SignIn.d.ts +26 -0
  20. package/dist/components/SignIn.js +47 -0
  21. package/dist/components/SignInForm.d.ts +41 -0
  22. package/dist/components/SignInForm.js +86 -0
  23. package/dist/components/SignUp.d.ts +26 -0
  24. package/dist/components/SignUp.js +52 -0
  25. package/dist/components/SpendingLimitAlert.d.ts +12 -0
  26. package/dist/components/SpendingLimitAlert.js +14 -0
  27. package/dist/components/UserButton.d.ts +26 -0
  28. package/dist/components/UserButton.js +35 -0
  29. package/dist/components/UserProfile.d.ts +22 -0
  30. package/dist/components/UserProfile.js +26 -0
  31. package/dist/components/WorkspaceSwitcher.d.ts +29 -0
  32. package/dist/components/WorkspaceSwitcher.js +66 -0
  33. package/dist/components/control.d.ts +64 -0
  34. package/dist/components/control.js +89 -0
  35. package/dist/components/ui/dialog.d.ts +19 -0
  36. package/dist/components/ui/dialog.js +53 -0
  37. package/dist/hooks/index.d.ts +22 -0
  38. package/dist/hooks/index.js +23 -0
  39. package/dist/hooks/useBuyerWallet.d.ts +37 -0
  40. package/dist/hooks/useBuyerWallet.js +66 -0
  41. package/dist/hooks/useCheckout.d.ts +27 -0
  42. package/dist/hooks/useCheckout.js +246 -0
  43. package/dist/hooks/useError.d.ts +19 -0
  44. package/dist/hooks/useError.js +36 -0
  45. package/dist/hooks/useMarketplace.d.ts +50 -0
  46. package/dist/hooks/useMarketplace.js +69 -0
  47. package/dist/hooks/useMemberships.d.ts +71 -0
  48. package/dist/hooks/useMemberships.js +138 -0
  49. package/dist/hooks/useWallet.d.ts +62 -0
  50. package/dist/hooks/useWallet.js +123 -0
  51. package/dist/index.d.ts +55 -0
  52. package/dist/index.js +52 -0
  53. package/dist/lib/context.d.ts +50 -0
  54. package/dist/lib/context.js +409 -0
  55. package/dist/lib/oauth.d.ts +49 -0
  56. package/dist/lib/oauth.js +149 -0
  57. package/dist/lib/parse-error.d.ts +45 -0
  58. package/dist/lib/parse-error.js +185 -0
  59. package/dist/lib/parse-stream.d.ts +43 -0
  60. package/dist/lib/parse-stream.js +89 -0
  61. package/dist/lib/popup.d.ts +42 -0
  62. package/dist/lib/popup.js +80 -0
  63. package/dist/lib/storage.d.ts +43 -0
  64. package/dist/lib/storage.js +125 -0
  65. package/dist/lib/utils.d.ts +8 -0
  66. package/dist/lib/utils.js +11 -0
  67. package/dist/types/index.d.ts +191 -0
  68. package/dist/types/index.js +4 -0
  69. package/package.json +78 -0
  70. package/src/components/AuthButton.tsx +123 -0
  71. package/src/components/AuthModal.tsx +240 -0
  72. package/src/components/BuyButton.tsx +150 -0
  73. package/src/components/ErrorBoundary.tsx +97 -0
  74. package/src/components/HyperyModals.tsx +83 -0
  75. package/src/components/InsufficientCreditsAlert.tsx +73 -0
  76. package/src/components/ModernAuthForm.tsx +322 -0
  77. package/src/components/RestrictionModal.tsx +373 -0
  78. package/src/components/SignIn.tsx +84 -0
  79. package/src/components/SignInForm.tsx +256 -0
  80. package/src/components/SignUp.tsx +86 -0
  81. package/src/components/SpendingLimitAlert.tsx +91 -0
  82. package/src/components/UserButton.tsx +106 -0
  83. package/src/components/UserProfile.tsx +106 -0
  84. package/src/components/WorkspaceSwitcher.tsx +199 -0
  85. package/src/components/control.tsx +133 -0
  86. package/src/components/ui/dialog.tsx +151 -0
  87. package/src/hooks/index.ts +65 -0
  88. package/src/hooks/useBuyerWallet.ts +117 -0
  89. package/src/hooks/useCheckout.ts +312 -0
  90. package/src/hooks/useError.ts +60 -0
  91. package/src/hooks/useMarketplace.ts +129 -0
  92. package/src/hooks/useMemberships.ts +203 -0
  93. package/src/hooks/useWallet.ts +170 -0
  94. package/src/index.ts +147 -0
  95. package/src/lib/context.tsx +478 -0
  96. package/src/lib/oauth.ts +215 -0
  97. package/src/lib/parse-error.ts +224 -0
  98. package/src/lib/parse-stream.ts +121 -0
  99. package/src/lib/popup.ts +98 -0
  100. package/src/lib/storage.ts +140 -0
  101. package/src/lib/utils.ts +14 -0
  102. package/src/types/index.ts +216 -0
@@ -0,0 +1,41 @@
1
+ /**
2
+ * SignInForm Component
3
+ * Embedded login form with email/password and social OAuth
4
+ * Authenticates directly with the Hypery without extra redirects
5
+ */
6
+ import React from 'react';
7
+ export interface SignInFormProps {
8
+ /** Custom CSS class */
9
+ className?: string;
10
+ /** Show card styling */
11
+ showCard?: boolean;
12
+ /** Show title and description */
13
+ showTitle?: boolean;
14
+ /** Custom title */
15
+ title?: string;
16
+ /** Custom description */
17
+ description?: string;
18
+ /** Show social OAuth buttons (GitHub, Google) */
19
+ showSocial?: boolean;
20
+ /** Show email/password form */
21
+ showEmailPassword?: boolean;
22
+ /** Callback after successful sign in */
23
+ onSuccess?: () => void;
24
+ /** Callback on error */
25
+ onError?: (error: string) => void;
26
+ }
27
+ /**
28
+ * Embedded sign-in form component
29
+ * Provides email/password and OAuth authentication
30
+ *
31
+ * @example
32
+ * ```tsx
33
+ * <SignInForm
34
+ * showCard
35
+ * showTitle
36
+ * showSocial
37
+ * onSuccess={() => console.log('Signed in!')}
38
+ * />
39
+ * ```
40
+ */
41
+ export declare function SignInForm({ className, showCard, showTitle, title, description, showSocial, showEmailPassword, onSuccess, onError, }: SignInFormProps): React.JSX.Element;
@@ -0,0 +1,86 @@
1
+ /**
2
+ * SignInForm Component
3
+ * Embedded login form with email/password and social OAuth
4
+ * Authenticates directly with the Hypery without extra redirects
5
+ */
6
+ 'use client';
7
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
8
+ import { useState } from 'react';
9
+ import { useHyperyAuth } from '../lib/context';
10
+ /**
11
+ * Embedded sign-in form component
12
+ * Provides email/password and OAuth authentication
13
+ *
14
+ * @example
15
+ * ```tsx
16
+ * <SignInForm
17
+ * showCard
18
+ * showTitle
19
+ * showSocial
20
+ * onSuccess={() => console.log('Signed in!')}
21
+ * />
22
+ * ```
23
+ */
24
+ export function SignInForm({ className, showCard = true, showTitle = true, title = 'Sign in to continue', description = 'Choose your preferred sign-in method', showSocial = true, showEmailPassword = true, onSuccess, onError, }) {
25
+ const { login, signUp } = useHyperyAuth();
26
+ const [isLoading, setIsLoading] = useState(false);
27
+ const [loadingProvider, setLoadingProvider] = useState(null);
28
+ const [email, setEmail] = useState('');
29
+ const [password, setPassword] = useState('');
30
+ const [error, setError] = useState('');
31
+ // Handle OAuth sign-in with social providers
32
+ // This directly initiates the OAuth flow with the gateway
33
+ const handleSocialSignIn = (provider) => {
34
+ setLoadingProvider(provider);
35
+ setError('');
36
+ try {
37
+ // The login() function will redirect to the gateway's OAuth flow
38
+ // If the user is already authenticated with the provider,
39
+ // they'll only need to authorize the OAuth app
40
+ login();
41
+ if (onSuccess) {
42
+ onSuccess();
43
+ }
44
+ }
45
+ catch (err) {
46
+ const errorMessage = err instanceof Error ? err.message : `${provider} sign in failed`;
47
+ setError(errorMessage);
48
+ if (onError) {
49
+ onError(errorMessage);
50
+ }
51
+ setLoadingProvider(null);
52
+ }
53
+ };
54
+ const handleEmailSignIn = async (e) => {
55
+ e.preventDefault();
56
+ setIsLoading(true);
57
+ setError('');
58
+ // Validate
59
+ if (!email || !password) {
60
+ setError('Please enter both email and password');
61
+ setIsLoading(false);
62
+ return;
63
+ }
64
+ if (password.length < 6) {
65
+ setError('Password must be at least 6 characters');
66
+ setIsLoading(false);
67
+ return;
68
+ }
69
+ // For now, redirect to OAuth flow
70
+ // In the future, this could call a direct auth API
71
+ setError('Direct email login not yet supported. Please use the sign-in button.');
72
+ setIsLoading(false);
73
+ };
74
+ const containerClasses = showCard
75
+ ? 'bg-white rounded-lg shadow-md p-8 max-w-md mx-auto'
76
+ : '';
77
+ return (_jsxs("div", { className: `${containerClasses} ${className || ''}`, children: [showTitle && (_jsxs("div", { className: "text-center mb-6", children: [_jsx("h2", { className: "text-2xl font-bold mb-2", children: title }), _jsx("p", { className: "text-gray-600", children: description })] })), error && (_jsx("div", { className: "bg-red-50 border border-red-200 text-red-800 px-4 py-3 rounded mb-4 text-sm", children: error })), showSocial && (_jsxs("div", { className: "space-y-2 mb-6", children: [_jsx("button", { onClick: () => handleSocialSignIn('github'), disabled: !!loadingProvider, className: "w-full bg-[#24292F] hover:bg-[#1B1F23] text-white py-2 px-3 rounded flex items-center justify-center gap-2 text-sm font-medium transition-colors disabled:opacity-50", type: "button", children: loadingProvider === 'github' ? (_jsx("span", { children: "Connecting..." })) : (_jsxs(_Fragment, { children: [_jsx("svg", { className: "w-4 h-4", fill: "currentColor", viewBox: "0 0 24 24", children: _jsx("path", { fillRule: "evenodd", d: "M12 2C6.477 2 2 6.484 2 12.017c0 4.425 2.865 8.18 6.839 9.504.5.092.682-.217.682-.483 0-.237-.008-.868-.013-1.703-2.782.605-3.369-1.343-3.369-1.343-.454-1.158-1.11-1.466-1.11-1.466-.908-.62.069-.608.069-.608 1.003.07 1.531 1.032 1.531 1.032.892 1.53 2.341 1.088 2.91.832.092-.647.35-1.088.636-1.338-2.22-.253-4.555-1.113-4.555-4.951 0-1.093.39-1.988 1.029-2.688-.103-.253-.446-1.272.098-2.65 0 0 .84-.27 2.75 1.026A9.564 9.564 0 0112 6.844c.85.004 1.705.115 2.504.337 1.909-1.296 2.747-1.027 2.747-1.027.546 1.379.202 2.398.1 2.651.64.7 1.028 1.595 1.028 2.688 0 3.848-2.339 4.695-4.566 4.943.359.309.678.92.678 1.855 0 1.338-.012 2.419-.012 2.747 0 .268.18.58.688.482A10.019 10.019 0 0022 12.017C22 6.484 17.522 2 12 2z", clipRule: "evenodd" }) }), _jsx("span", { children: "Continue with GitHub" })] })) }), _jsx("button", { onClick: () => handleSocialSignIn('google'), disabled: !!loadingProvider, className: "w-full bg-white hover:bg-gray-50 text-gray-700 py-2 px-3 rounded flex items-center justify-center gap-2 text-sm font-medium border border-gray-300 transition-colors disabled:opacity-50", type: "button", children: loadingProvider === 'google' ? (_jsx("span", { children: "Connecting..." })) : (_jsxs(_Fragment, { children: [_jsxs("svg", { className: "w-4 h-4", viewBox: "0 0 24 24", children: [_jsx("path", { fill: "#4285F4", d: "M22.56 12.25c0-.78-.07-1.53-.2-2.25H12v4.26h5.92c-.26 1.37-1.04 2.53-2.21 3.31v2.77h3.57c2.08-1.92 3.28-4.74 3.28-8.09z" }), _jsx("path", { fill: "#34A853", d: "M12 23c2.97 0 5.46-.98 7.28-2.66l-3.57-2.77c-.98.66-2.23 1.06-3.71 1.06-2.86 0-5.29-1.93-6.16-4.53H2.18v2.84C3.99 20.53 7.7 23 12 23z" }), _jsx("path", { fill: "#FBBC05", d: "M5.84 14.09c-.22-.66-.35-1.36-.35-2.09s.13-1.43.35-2.09V7.07H2.18C1.43 8.55 1 10.22 1 12s.43 3.45 1.18 4.93l2.85-2.22.81-.62z" }), _jsx("path", { fill: "#EA4335", d: "M12 5.38c1.62 0 3.06.56 4.21 1.64l3.15-3.15C17.45 2.09 14.97 1 12 1 7.7 1 3.99 3.47 2.18 7.07l3.66 2.84c.87-2.6 3.3-4.53 6.16-4.53z" })] }), _jsx("span", { children: "Continue with Google" })] })) })] })), showSocial && showEmailPassword && (_jsxs("div", { className: "relative mb-6", children: [_jsx("div", { className: "absolute inset-0 flex items-center", children: _jsx("div", { className: "w-full border-t border-gray-300" }) }), _jsx("div", { className: "relative flex justify-center text-xs uppercase", children: _jsx("span", { className: "bg-white px-3 text-gray-500", children: "Or continue with email" }) })] })), showEmailPassword && (_jsxs("form", { onSubmit: handleEmailSignIn, className: "space-y-4 mb-6", children: [_jsxs("div", { children: [_jsx("label", { htmlFor: "email", className: "block text-sm font-medium text-gray-700 mb-1.5", children: "Email" }), _jsx("input", { id: "email", type: "email", value: email, onChange: (e) => setEmail(e.target.value), disabled: isLoading || !!loadingProvider, className: "w-full px-3 py-2 border border-gray-300 rounded focus:ring-2 focus:ring-blue-500 focus:border-transparent disabled:bg-gray-100 disabled:cursor-not-allowed text-[15px]", placeholder: "you@example.com" })] }), _jsxs("div", { children: [_jsx("label", { htmlFor: "password", className: "block text-sm font-medium text-gray-700 mb-1.5", children: "Password" }), _jsx("input", { id: "password", type: "password", value: password, onChange: (e) => setPassword(e.target.value), disabled: isLoading || !!loadingProvider, className: "w-full px-3 py-2 border border-gray-300 rounded focus:ring-2 focus:ring-blue-500 focus:border-transparent disabled:bg-gray-100 disabled:cursor-not-allowed text-[15px]", placeholder: "Enter your password" })] }), _jsx("button", { type: "submit", disabled: isLoading || !!loadingProvider, className: "w-full bg-blue-600 text-white py-2.5 px-4 rounded font-medium hover:bg-blue-700 transition-colors disabled:opacity-50 disabled:cursor-not-allowed text-[15px]", children: isLoading ? 'Signing in...' : 'Sign in' })] })), _jsx("div", { className: "text-center", children: _jsxs("p", { className: "text-sm text-gray-600", children: ["Don't have an account?", ' ', _jsx("button", { onClick: () => {
78
+ // Use signUp if available (forces account selection), otherwise fallback to login
79
+ if (signUp) {
80
+ signUp();
81
+ }
82
+ else {
83
+ login();
84
+ }
85
+ }, className: "text-blue-600 hover:text-blue-700 font-medium", type: "button", children: "Sign up" })] }) })] }));
86
+ }
@@ -0,0 +1,26 @@
1
+ /**
2
+ * SignUp Component
3
+ * Button to initiate the sign-up flow via OAuth
4
+ */
5
+ import React from 'react';
6
+ export interface SignUpProps {
7
+ /** Custom button text */
8
+ buttonText?: string;
9
+ /** Custom CSS class */
10
+ className?: string;
11
+ /** Button style variant */
12
+ variant?: 'primary' | 'secondary' | 'outline';
13
+ /** Callback after sign up initiated */
14
+ onSignUpStart?: () => void;
15
+ /** Custom redirect URL after sign up */
16
+ redirectUrl?: string;
17
+ }
18
+ /**
19
+ * Sign up button component
20
+ *
21
+ * @example
22
+ * ```tsx
23
+ * <SignUp buttonText="Get Started" />
24
+ * ```
25
+ */
26
+ export declare function SignUp({ buttonText, className, variant, onSignUpStart, redirectUrl, }: SignUpProps): React.JSX.Element;
@@ -0,0 +1,52 @@
1
+ /**
2
+ * SignUp Component
3
+ * Button to initiate the sign-up flow via OAuth
4
+ */
5
+ 'use client';
6
+ import { jsx as _jsx } from "react/jsx-runtime";
7
+ import { useHyperyAuth } from '../lib/context';
8
+ /**
9
+ * Sign up button component
10
+ *
11
+ * @example
12
+ * ```tsx
13
+ * <SignUp buttonText="Get Started" />
14
+ * ```
15
+ */
16
+ export function SignUp({ buttonText = 'Sign up', className, variant = 'primary', onSignUpStart, redirectUrl, }) {
17
+ const { signUp, login } = useHyperyAuth();
18
+ const handleSignUp = () => {
19
+ if (onSignUpStart) {
20
+ onSignUpStart();
21
+ }
22
+ // Use signUp if available (forces account selection), otherwise fallback to login
23
+ if (signUp) {
24
+ signUp();
25
+ }
26
+ else {
27
+ login();
28
+ }
29
+ };
30
+ // Default styles based on variant
31
+ const getVariantStyles = () => {
32
+ switch (variant) {
33
+ case 'secondary':
34
+ return 'bg-gray-600 hover:bg-gray-700 text-white';
35
+ case 'outline':
36
+ return 'border-2 border-blue-600 text-blue-600 hover:bg-blue-50';
37
+ default:
38
+ return 'bg-blue-600 hover:bg-blue-700 text-white';
39
+ }
40
+ };
41
+ const defaultStyles = `
42
+ inline-flex items-center justify-center
43
+ px-6 py-2.5
44
+ rounded-lg
45
+ font-medium
46
+ transition-colors
47
+ focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-2
48
+ disabled:opacity-50 disabled:cursor-not-allowed
49
+ ${getVariantStyles()}
50
+ `.replace(/\s+/g, ' ').trim();
51
+ return (_jsx("button", { onClick: handleSignUp, className: className || defaultStyles, type: "button", children: buttonText }));
52
+ }
@@ -0,0 +1,12 @@
1
+ import { ParsedError } from '../types';
2
+ export interface SpendingLimitAlertProps {
3
+ error: ParsedError;
4
+ onRetry?: () => void;
5
+ onUpgradeLimits?: () => void;
6
+ className?: string;
7
+ }
8
+ /**
9
+ * Alert component for spending limit errors
10
+ * Displays a user-friendly message with retry and upgrade options
11
+ */
12
+ export declare function SpendingLimitAlert({ error, onRetry, onUpgradeLimits, className, }: SpendingLimitAlertProps): import("react").JSX.Element | null;
@@ -0,0 +1,14 @@
1
+ 'use client';
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import { formatTimeUntilReset } from '../lib/parse-error';
4
+ /**
5
+ * Alert component for spending limit errors
6
+ * Displays a user-friendly message with retry and upgrade options
7
+ */
8
+ export function SpendingLimitAlert({ error, onRetry, onUpgradeLimits, className = '', }) {
9
+ if (!error.isSpendingLimit)
10
+ return null;
11
+ const data = error.data;
12
+ const resetTime = data.resetsAt ? formatTimeUntilReset(data.resetsAt) : null;
13
+ return (_jsx("div", { className: `rounded-lg border border-orange-200 bg-orange-50 p-4 ${className}`, role: "alert", children: _jsxs("div", { className: "flex items-start gap-3", children: [_jsx("div", { className: "flex-shrink-0", children: _jsx("svg", { className: "h-5 w-5 text-orange-400", viewBox: "0 0 20 20", fill: "currentColor", "aria-hidden": "true", children: _jsx("path", { fillRule: "evenodd", d: "M8.485 2.495c.673-1.167 2.357-1.167 3.03 0l6.28 10.875c.673 1.167-.17 2.625-1.516 2.625H3.72c-1.347 0-2.189-1.458-1.515-2.625L8.485 2.495zM10 5a.75.75 0 01.75.75v3.5a.75.75 0 01-1.5 0v-3.5A.75.75 0 0110 5zm0 9a1 1 0 100-2 1 1 0 000 2z", clipRule: "evenodd" }) }) }), _jsxs("div", { className: "flex-1", children: [_jsx("h3", { className: "text-sm font-medium text-orange-800", children: "Spending Limit Reached" }), _jsxs("div", { className: "mt-2 text-sm text-orange-700", children: [_jsx("p", { children: error.message }), data.limitType && (_jsxs("p", { className: "mt-1", children: [_jsx("strong", { className: "capitalize", children: data.limitType }), " limit:", ' ', data.current || 0, " / ", data.limit, " credits used"] })), resetTime && (_jsxs("p", { className: "mt-1", children: ["Your limit will reset ", _jsx("strong", { children: resetTime })] }))] }), _jsxs("div", { className: "mt-4 flex gap-3", children: [onRetry && (_jsx("button", { type: "button", onClick: onRetry, className: "text-sm font-medium text-orange-800 hover:text-orange-900", children: "Try again" })), onUpgradeLimits && (_jsx("button", { type: "button", onClick: onUpgradeLimits, className: "text-sm font-medium text-orange-800 hover:text-orange-900 underline", children: "Increase limits \u2192" }))] })] })] }) }));
14
+ }
@@ -0,0 +1,26 @@
1
+ /**
2
+ * User Button Component
3
+ * Similar to Clerk's <UserButton />
4
+ */
5
+ import React from 'react';
6
+ import { useUser } from '../lib/context';
7
+ export interface UserButtonProps {
8
+ /** Show user info */
9
+ showUserInfo?: boolean;
10
+ /** Custom className for styling */
11
+ className?: string;
12
+ /** Avatar size */
13
+ size?: 'sm' | 'md' | 'lg';
14
+ /** Render custom dropdown */
15
+ renderDropdown?: (user: NonNullable<ReturnType<typeof useUser>['user']>, logout: () => void) => React.ReactNode;
16
+ }
17
+ /**
18
+ * User button with avatar and dropdown menu
19
+ * Usually placed in the top-right corner of your layout
20
+ *
21
+ * @example
22
+ * ```tsx
23
+ * <UserButton showUserInfo />
24
+ * ```
25
+ */
26
+ export declare function UserButton({ showUserInfo, className, size, renderDropdown, }: UserButtonProps): React.JSX.Element | null;
@@ -0,0 +1,35 @@
1
+ /**
2
+ * User Button Component
3
+ * Similar to Clerk's <UserButton />
4
+ */
5
+ 'use client';
6
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
7
+ import { useState } from 'react';
8
+ import { useUser, useHyperyAuth } from '../lib/context';
9
+ /**
10
+ * User button with avatar and dropdown menu
11
+ * Usually placed in the top-right corner of your layout
12
+ *
13
+ * @example
14
+ * ```tsx
15
+ * <UserButton showUserInfo />
16
+ * ```
17
+ */
18
+ export function UserButton({ showUserInfo = false, className, size = 'md', renderDropdown, }) {
19
+ const { user, isLoading } = useUser();
20
+ const { logout } = useHyperyAuth();
21
+ const [isOpen, setIsOpen] = useState(false);
22
+ if (isLoading || !user) {
23
+ return null;
24
+ }
25
+ const sizeMap = {
26
+ sm: 'w-8 h-8 text-sm',
27
+ md: 'w-10 h-10 text-base',
28
+ lg: 'w-12 h-12 text-lg',
29
+ };
30
+ const handleLogout = async () => {
31
+ setIsOpen(false);
32
+ await logout();
33
+ };
34
+ return (_jsxs("div", { className: `relative ${className || ''}`, children: [_jsx("button", { onClick: () => setIsOpen(!isOpen), className: `${sizeMap[size]} rounded-full overflow-hidden bg-gradient-to-br from-blue-500 to-purple-600 flex items-center justify-center text-white font-semibold hover:opacity-90 transition-opacity`, type: "button", "aria-label": "User menu", children: user.image ? (_jsx("img", { src: user.image, alt: user.name, className: "w-full h-full object-cover" })) : (user.name.charAt(0).toUpperCase()) }), isOpen && (_jsxs(_Fragment, { children: [_jsx("div", { className: "fixed inset-0 z-10", onClick: () => setIsOpen(false) }), _jsx("div", { className: "absolute right-0 mt-2 w-64 bg-white rounded-lg shadow-lg z-20 py-2", children: renderDropdown ? (renderDropdown(user, handleLogout)) : (_jsxs(_Fragment, { children: [showUserInfo && (_jsxs("div", { className: "px-4 py-3 border-b", children: [_jsx("p", { className: "font-semibold", children: user.name }), _jsx("p", { className: "text-sm text-gray-500", children: user.email })] })), _jsx("button", { onClick: handleLogout, className: "w-full text-left px-4 py-2 hover:bg-gray-50 text-sm", type: "button", children: "Sign out" })] })) })] }))] }));
35
+ }
@@ -0,0 +1,22 @@
1
+ /**
2
+ * UserProfile Component
3
+ * Display user profile information in a card format
4
+ */
5
+ import React from 'react';
6
+ export interface UserProfileProps {
7
+ /** Show extended profile information */
8
+ showExtended?: boolean;
9
+ /** Custom CSS class */
10
+ className?: string;
11
+ /** Show loading state */
12
+ showLoading?: boolean;
13
+ }
14
+ /**
15
+ * User profile card component
16
+ *
17
+ * @example
18
+ * ```tsx
19
+ * <UserProfile showExtended />
20
+ * ```
21
+ */
22
+ export declare function UserProfile({ showExtended, className, showLoading, }: UserProfileProps): React.JSX.Element | null;
@@ -0,0 +1,26 @@
1
+ /**
2
+ * UserProfile Component
3
+ * Display user profile information in a card format
4
+ */
5
+ 'use client';
6
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
7
+ import { useUser } from '../lib/context';
8
+ /**
9
+ * User profile card component
10
+ *
11
+ * @example
12
+ * ```tsx
13
+ * <UserProfile showExtended />
14
+ * ```
15
+ */
16
+ export function UserProfile({ showExtended = true, className, showLoading = true, }) {
17
+ const { user, isLoading } = useUser();
18
+ if (isLoading && showLoading) {
19
+ return (_jsx("div", { className: className || 'bg-white rounded-lg shadow p-6', children: _jsx("div", { className: "animate-pulse", children: _jsxs("div", { className: "flex items-center space-x-4", children: [_jsx("div", { className: "w-16 h-16 bg-gray-200 rounded-full" }), _jsxs("div", { className: "flex-1 space-y-2", children: [_jsx("div", { className: "h-4 bg-gray-200 rounded w-3/4" }), _jsx("div", { className: "h-3 bg-gray-200 rounded w-1/2" })] })] }) }) }));
20
+ }
21
+ if (!user) {
22
+ return null;
23
+ }
24
+ const defaultStyles = 'bg-white rounded-lg shadow p-6';
25
+ return (_jsxs("div", { className: className || defaultStyles, children: [_jsxs("div", { className: "flex items-start space-x-4", children: [user.image ? (_jsx("img", { src: user.image, alt: user.name, className: "w-16 h-16 rounded-full object-cover" })) : (_jsx("div", { className: "w-16 h-16 bg-gradient-to-br from-blue-600 to-purple-600 rounded-full flex items-center justify-center text-white text-2xl font-bold", children: user.name.charAt(0).toUpperCase() })), _jsxs("div", { className: "flex-1 min-w-0", children: [_jsx("h3", { className: "text-xl font-semibold text-gray-900 truncate", children: user.name }), _jsx("p", { className: "text-sm text-gray-600 truncate", children: user.email }), showExtended && (_jsx("div", { className: "mt-4 space-y-2", children: _jsxs("div", { className: "flex items-center justify-between text-sm", children: [_jsx("span", { className: "text-gray-500", children: "User ID" }), _jsx("code", { className: "text-xs bg-gray-100 px-2 py-1 rounded font-mono", children: user.id })] }) }))] })] }), showExtended && (_jsx("div", { className: "mt-6 pt-6 border-t border-gray-200", children: _jsxs("div", { className: "flex items-center justify-between", children: [_jsx("span", { className: "text-sm text-gray-500", children: "Profile Status" }), _jsx("span", { className: "inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium bg-green-100 text-green-800", children: "Active" })] }) }))] }));
26
+ }
@@ -0,0 +1,29 @@
1
+ /**
2
+ * <WorkspaceSwitcher /> — drop-in dropdown that lists every workspace the
3
+ * user belongs to (across all orgs/teams) and switches the active one.
4
+ *
5
+ * Designed for the top-bar of consumer apps. Headless-ish: ships with
6
+ * sensible default styles via tailwind utility classes but they can be
7
+ * fully overridden via `className`.
8
+ *
9
+ * Example:
10
+ * <WorkspaceSwitcher
11
+ * onSwitched={(teamId, workspaceId) => router.refresh()}
12
+ * />
13
+ *
14
+ * The component groups workspaces by team. Personal team is labelled
15
+ * "Personal" rather than the literal "{Name}'s Workspace" team name to
16
+ * keep the switcher compact.
17
+ */
18
+ import React from 'react';
19
+ export interface WorkspaceSwitcherProps {
20
+ /** Called after a successful switch — typically `router.refresh()`. */
21
+ onSwitched?: (teamId: string, workspaceId: string) => void;
22
+ /** Override the Hypery base URL (defaults to NEXT_PUBLIC_GATEWAY_URL). */
23
+ gatewayUrl?: string;
24
+ /** Extra classes appended to the trigger button. */
25
+ className?: string;
26
+ /** Optional aria-label for the trigger. */
27
+ ariaLabel?: string;
28
+ }
29
+ export declare function WorkspaceSwitcher({ onSwitched, gatewayUrl, className, ariaLabel, }: WorkspaceSwitcherProps): React.JSX.Element | null;
@@ -0,0 +1,66 @@
1
+ /**
2
+ * <WorkspaceSwitcher /> — drop-in dropdown that lists every workspace the
3
+ * user belongs to (across all orgs/teams) and switches the active one.
4
+ *
5
+ * Designed for the top-bar of consumer apps. Headless-ish: ships with
6
+ * sensible default styles via tailwind utility classes but they can be
7
+ * fully overridden via `className`.
8
+ *
9
+ * Example:
10
+ * <WorkspaceSwitcher
11
+ * onSwitched={(teamId, workspaceId) => router.refresh()}
12
+ * />
13
+ *
14
+ * The component groups workspaces by team. Personal team is labelled
15
+ * "Personal" rather than the literal "{Name}'s Workspace" team name to
16
+ * keep the switcher compact.
17
+ */
18
+ 'use client';
19
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
20
+ import { useCallback, useState } from 'react';
21
+ import { ChevronsUpDown, Check, Building2, User as UserIcon } from 'lucide-react';
22
+ import { useHyperyAuth } from '../lib/context';
23
+ import { useMemberships, setActiveWorkspace, } from '../hooks/useMemberships';
24
+ export function WorkspaceSwitcher({ onSwitched, gatewayUrl, className = '', ariaLabel = 'Switch workspace', }) {
25
+ const { getAccessToken } = useHyperyAuth();
26
+ const { data, isLoading, reload } = useMemberships();
27
+ const [open, setOpen] = useState(false);
28
+ const [switching, setSwitching] = useState(null);
29
+ const activeWorkspaceId = data?.activeWorkspaceId ?? null;
30
+ // Resolve the currently-active entry for the trigger label.
31
+ const flat = data?.memberships.flatMap((m) => m.workspaces.map((w) => ({ membership: m, workspace: w }))) ?? [];
32
+ const activeEntry = flat.find((e) => e.workspace.id === activeWorkspaceId) ?? flat[0];
33
+ const handleSwitch = useCallback(async (teamId, workspaceId) => {
34
+ setSwitching(workspaceId);
35
+ try {
36
+ await setActiveWorkspace({
37
+ teamId,
38
+ workspaceId,
39
+ getAccessToken,
40
+ gatewayUrl,
41
+ });
42
+ await reload();
43
+ setOpen(false);
44
+ onSwitched?.(teamId, workspaceId);
45
+ }
46
+ catch (err) {
47
+ console.error('[WorkspaceSwitcher] switch failed:', err);
48
+ }
49
+ finally {
50
+ setSwitching(null);
51
+ }
52
+ }, [getAccessToken, gatewayUrl, onSwitched, reload]);
53
+ if (isLoading && !data) {
54
+ return (_jsxs("button", { type: "button", disabled: true, className: `inline-flex items-center gap-2 rounded-md border border-zinc-200 dark:border-zinc-800 bg-white dark:bg-zinc-900 px-3 py-1.5 text-sm text-zinc-500 ${className}`, children: [_jsx("span", { className: "size-4 animate-pulse rounded-sm bg-zinc-300 dark:bg-zinc-700" }), "Loading workspaces\u2026"] }));
55
+ }
56
+ if (!data || data.memberships.length === 0) {
57
+ return null;
58
+ }
59
+ return (_jsxs("div", { className: "relative inline-block text-left", children: [_jsxs("button", { type: "button", onClick: () => setOpen((v) => !v), "aria-label": ariaLabel, "aria-haspopup": "listbox", "aria-expanded": open, className: `inline-flex items-center gap-2 rounded-md border border-zinc-200 dark:border-zinc-800 bg-white dark:bg-zinc-900 px-3 py-1.5 text-sm font-medium text-zinc-900 dark:text-zinc-100 hover:bg-zinc-50 dark:hover:bg-zinc-800 focus:outline-none focus:ring-2 focus:ring-blue-500 ${className}`, children: [activeEntry?.membership.team.isPersonal ? (_jsx(UserIcon, { className: "h-4 w-4 text-zinc-500", "aria-hidden": true })) : (_jsx(Building2, { className: "h-4 w-4 text-zinc-500", "aria-hidden": true })), _jsx("span", { className: "truncate max-w-[180px]", children: activeEntry ? (_jsxs(_Fragment, { children: [_jsx("span", { className: "text-zinc-500", children: activeEntry.membership.team.isPersonal
60
+ ? 'Personal'
61
+ : activeEntry.membership.team.name }), _jsx("span", { className: "mx-1.5 text-zinc-300 dark:text-zinc-600", children: "\u00B7" }), _jsx("span", { children: activeEntry.workspace.name })] })) : ('Select workspace') }), _jsx(ChevronsUpDown, { className: "h-3.5 w-3.5 text-zinc-400", "aria-hidden": true })] }), open && (_jsxs(_Fragment, { children: [_jsx("button", { type: "button", "aria-hidden": true, tabIndex: -1, onClick: () => setOpen(false), className: "fixed inset-0 z-40 cursor-default" }), _jsx("div", { role: "listbox", className: "absolute z-50 mt-1 max-h-[28rem] w-72 overflow-y-auto rounded-md border border-zinc-200 dark:border-zinc-800 bg-white dark:bg-zinc-900 shadow-lg p-1", children: data.memberships.map((m) => (_jsxs("div", { className: "py-1", children: [_jsxs("div", { className: "px-2 pt-1 pb-1 text-[10px] font-semibold uppercase tracking-wider text-zinc-500 flex items-center gap-1.5", children: [m.team.isPersonal ? (_jsx(UserIcon, { className: "h-3 w-3" })) : (_jsx(Building2, { className: "h-3 w-3" })), m.team.isPersonal ? 'Personal' : m.team.name] }), m.workspaces.map((w) => {
62
+ const isActive = w.id === activeWorkspaceId;
63
+ const isSwitching = switching === w.id;
64
+ return (_jsxs("button", { type: "button", role: "option", "aria-selected": isActive, disabled: isSwitching, onClick: () => handleSwitch(m.team.id, w.id), className: `flex w-full items-center justify-between gap-2 rounded-sm px-2 py-1.5 text-sm text-left hover:bg-zinc-100 dark:hover:bg-zinc-800 ${isActive ? 'bg-zinc-50 dark:bg-zinc-800/60' : ''} disabled:opacity-50`, children: [_jsxs("span", { className: "flex items-center gap-1.5 truncate", children: [w.icon && _jsx("span", { "aria-hidden": true, children: w.icon }), _jsx("span", { className: "truncate", children: w.name }), w.isDefault && (_jsx("span", { className: "ml-1 text-[9px] uppercase tracking-wider text-zinc-400", children: "default" }))] }), isActive && (_jsx(Check, { className: "h-3.5 w-3.5 text-blue-600" }))] }, w.id));
65
+ })] }, m.team.id))) })] }))] }));
66
+ }
@@ -0,0 +1,64 @@
1
+ /**
2
+ * Control Components
3
+ * Similar to Clerk's <SignedIn />, <SignedOut />, etc.
4
+ */
5
+ import type { ReactNode } from 'react';
6
+ export interface SignedInProps {
7
+ children: ReactNode;
8
+ /** Fallback content to show while loading */
9
+ fallback?: ReactNode;
10
+ }
11
+ /**
12
+ * Only renders children when user is authenticated
13
+ *
14
+ * @example
15
+ * ```tsx
16
+ * <SignedIn>
17
+ * <Dashboard />
18
+ * </SignedIn>
19
+ * ```
20
+ */
21
+ export declare function SignedIn({ children, fallback }: SignedInProps): ReactNode;
22
+ export interface SignedOutProps {
23
+ children: ReactNode;
24
+ /** Fallback content to show while loading */
25
+ fallback?: ReactNode;
26
+ }
27
+ /**
28
+ * Only renders children when user is NOT authenticated
29
+ *
30
+ * @example
31
+ * ```tsx
32
+ * <SignedOut>
33
+ * <SignIn />
34
+ * </SignedOut>
35
+ * ```
36
+ */
37
+ export declare function SignedOut({ children, fallback }: SignedOutProps): ReactNode;
38
+ /**
39
+ * Redirects to sign in when user is not authenticated
40
+ *
41
+ * @example
42
+ * ```tsx
43
+ * <RedirectToSignIn />
44
+ * ```
45
+ */
46
+ export declare function RedirectToSignIn(): null;
47
+ export interface ProtectProps {
48
+ children: ReactNode;
49
+ /** Fallback to show when not authenticated */
50
+ fallback?: ReactNode;
51
+ /** Custom redirect logic */
52
+ onUnauthenticated?: () => void;
53
+ }
54
+ /**
55
+ * Protects content - redirects to sign in if not authenticated
56
+ *
57
+ * @example
58
+ * ```tsx
59
+ * <Protect fallback={<SignIn />}>
60
+ * <ProtectedContent />
61
+ * </Protect>
62
+ * ```
63
+ */
64
+ export declare function Protect({ children, fallback, onUnauthenticated, }: ProtectProps): ReactNode;
@@ -0,0 +1,89 @@
1
+ /**
2
+ * Control Components
3
+ * Similar to Clerk's <SignedIn />, <SignedOut />, etc.
4
+ */
5
+ 'use client';
6
+ import { useHyperyAuth } from '../lib/context';
7
+ /**
8
+ * Only renders children when user is authenticated
9
+ *
10
+ * @example
11
+ * ```tsx
12
+ * <SignedIn>
13
+ * <Dashboard />
14
+ * </SignedIn>
15
+ * ```
16
+ */
17
+ export function SignedIn({ children, fallback }) {
18
+ const { isAuthenticated, isLoading } = useHyperyAuth();
19
+ if (isLoading) {
20
+ return fallback || null;
21
+ }
22
+ return isAuthenticated ? children : null;
23
+ }
24
+ /**
25
+ * Only renders children when user is NOT authenticated
26
+ *
27
+ * @example
28
+ * ```tsx
29
+ * <SignedOut>
30
+ * <SignIn />
31
+ * </SignedOut>
32
+ * ```
33
+ */
34
+ export function SignedOut({ children, fallback }) {
35
+ const { isAuthenticated, isLoading } = useHyperyAuth();
36
+ if (isLoading) {
37
+ return fallback || null;
38
+ }
39
+ return !isAuthenticated ? children : null;
40
+ }
41
+ /**
42
+ * Redirects to sign in when user is not authenticated
43
+ *
44
+ * @example
45
+ * ```tsx
46
+ * <RedirectToSignIn />
47
+ * ```
48
+ */
49
+ export function RedirectToSignIn() {
50
+ const { login, isLoading, isAuthenticated } = useHyperyAuth();
51
+ if (!isLoading && !isAuthenticated) {
52
+ login();
53
+ }
54
+ return null;
55
+ }
56
+ /**
57
+ * Protects content - redirects to sign in if not authenticated
58
+ *
59
+ * @example
60
+ * ```tsx
61
+ * <Protect fallback={<SignIn />}>
62
+ * <ProtectedContent />
63
+ * </Protect>
64
+ * ```
65
+ */
66
+ export function Protect({ children, fallback, onUnauthenticated, }) {
67
+ const { isAuthenticated, isLoading, login, isLoggingOut } = useHyperyAuth();
68
+ if (isLoading) {
69
+ return fallback || null;
70
+ }
71
+ // Don't trigger login if we're in the middle of logging out
72
+ if (!isAuthenticated && !isLoggingOut) {
73
+ if (onUnauthenticated) {
74
+ onUnauthenticated();
75
+ return null;
76
+ }
77
+ if (fallback) {
78
+ return fallback;
79
+ }
80
+ // Default: initiate login
81
+ login();
82
+ return null;
83
+ }
84
+ // If logging out, show fallback or nothing
85
+ if (isLoggingOut) {
86
+ return fallback || null;
87
+ }
88
+ return children;
89
+ }
@@ -0,0 +1,19 @@
1
+ import * as React from "react";
2
+ import * as DialogPrimitive from "@radix-ui/react-dialog";
3
+ declare const Dialog: React.FC<DialogPrimitive.DialogProps>;
4
+ declare const DialogTrigger: React.ForwardRefExoticComponent<DialogPrimitive.DialogTriggerProps & React.RefAttributes<HTMLButtonElement>>;
5
+ declare const DialogPortal: React.FC<DialogPrimitive.DialogPortalProps>;
6
+ declare const DialogClose: React.ForwardRefExoticComponent<DialogPrimitive.DialogCloseProps & React.RefAttributes<HTMLButtonElement>>;
7
+ declare const DialogOverlay: React.ForwardRefExoticComponent<Omit<DialogPrimitive.DialogOverlayProps & React.RefAttributes<HTMLDivElement>, "ref"> & React.RefAttributes<HTMLDivElement>>;
8
+ declare const DialogContent: React.ForwardRefExoticComponent<Omit<DialogPrimitive.DialogContentProps & React.RefAttributes<HTMLDivElement>, "ref"> & React.RefAttributes<HTMLDivElement>>;
9
+ declare const DialogHeader: {
10
+ ({ className, ...props }: React.HTMLAttributes<HTMLDivElement>): React.JSX.Element;
11
+ displayName: string;
12
+ };
13
+ declare const DialogFooter: {
14
+ ({ className, ...props }: React.HTMLAttributes<HTMLDivElement>): React.JSX.Element;
15
+ displayName: string;
16
+ };
17
+ declare const DialogTitle: React.ForwardRefExoticComponent<Omit<DialogPrimitive.DialogTitleProps & React.RefAttributes<HTMLHeadingElement>, "ref"> & React.RefAttributes<HTMLHeadingElement>>;
18
+ declare const DialogDescription: React.ForwardRefExoticComponent<Omit<DialogPrimitive.DialogDescriptionProps & React.RefAttributes<HTMLParagraphElement>, "ref"> & React.RefAttributes<HTMLParagraphElement>>;
19
+ export { Dialog, DialogPortal, DialogOverlay, DialogTrigger, DialogClose, DialogContent, DialogHeader, DialogFooter, DialogTitle, DialogDescription, };