mm-key-vault 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.
- package/README.md +226 -0
- package/dist/api.d.ts +80 -0
- package/dist/components/Dashboard.d.ts +6 -0
- package/dist/components/LoginModal.d.ts +6 -0
- package/dist/index.d.ts +25 -0
- package/dist/mm-key-vault.cjs.js +2 -0
- package/dist/mm-key-vault.cjs.js.map +1 -0
- package/dist/mm-key-vault.esm.js +901 -0
- package/dist/mm-key-vault.esm.js.map +1 -0
- package/package.json +57 -0
package/README.md
ADDED
|
@@ -0,0 +1,226 @@
|
|
|
1
|
+
# 🔐 KeyVault Widget
|
|
2
|
+
|
|
3
|
+
A floating **API Key Vault** widget that you can drop into **Next.js, React, or any website**.
|
|
4
|
+
|
|
5
|
+
- **Login / Signup**
|
|
6
|
+
- **Dashboard listing** (search + sort + load more)
|
|
7
|
+
- **Add key** (platform + api_key)
|
|
8
|
+
- **Edit key** (fetch details, then update)
|
|
9
|
+
- **Copy key** (fetch details, then copy to clipboard)
|
|
10
|
+
|
|
11
|
+
> Backend is currently **hardcoded** to `https://probioticbackend.masterymade.com`.
|
|
12
|
+
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
## Installation
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
npm install mm-key-vault
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
This package uses React as a peer dependency:
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
npm install react react-dom
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
---
|
|
28
|
+
|
|
29
|
+
## Quick start
|
|
30
|
+
|
|
31
|
+
Call `initKeyVault()` once. **Config is optional**; defaults are applied automatically.
|
|
32
|
+
|
|
33
|
+
```ts
|
|
34
|
+
import { initKeyVault } from "mm-key-vault";
|
|
35
|
+
|
|
36
|
+
initKeyVault(); // defaults to bottom-right
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
---
|
|
40
|
+
|
|
41
|
+
## Usage by framework
|
|
42
|
+
|
|
43
|
+
### ⚛️ React (Vite / CRA)
|
|
44
|
+
|
|
45
|
+
Call once (best inside `useEffect` so it runs only in the browser):
|
|
46
|
+
|
|
47
|
+
```tsx
|
|
48
|
+
import { useEffect } from "react";
|
|
49
|
+
import { initKeyVault } from "mm-key-vault";
|
|
50
|
+
|
|
51
|
+
export function KeyVaultBoot() {
|
|
52
|
+
useEffect(() => {
|
|
53
|
+
initKeyVault();
|
|
54
|
+
}, []);
|
|
55
|
+
|
|
56
|
+
return null;
|
|
57
|
+
}
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
Render `<KeyVaultBoot />` anywhere (usually near your app root).
|
|
61
|
+
|
|
62
|
+
---
|
|
63
|
+
|
|
64
|
+
### 🔼 Next.js (App Router, v13+)
|
|
65
|
+
|
|
66
|
+
Create a client component:
|
|
67
|
+
|
|
68
|
+
```tsx
|
|
69
|
+
"use client";
|
|
70
|
+
import { useEffect } from "react";
|
|
71
|
+
import { initKeyVault } from "mm-key-vault";
|
|
72
|
+
|
|
73
|
+
export function KeyVaultProvider() {
|
|
74
|
+
useEffect(() => {
|
|
75
|
+
initKeyVault();
|
|
76
|
+
}, []);
|
|
77
|
+
return null;
|
|
78
|
+
}
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
Include it in `app/layout.tsx`:
|
|
82
|
+
|
|
83
|
+
```tsx
|
|
84
|
+
import { KeyVaultProvider } from "@/components/KeyVaultProvider";
|
|
85
|
+
|
|
86
|
+
export default function RootLayout({ children }: { children: React.ReactNode }) {
|
|
87
|
+
return (
|
|
88
|
+
<html lang="en">
|
|
89
|
+
<body>
|
|
90
|
+
{children}
|
|
91
|
+
<KeyVaultProvider />
|
|
92
|
+
</body>
|
|
93
|
+
</html>
|
|
94
|
+
);
|
|
95
|
+
}
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
---
|
|
99
|
+
|
|
100
|
+
### 📄 Next.js (Pages Router)
|
|
101
|
+
|
|
102
|
+
```tsx
|
|
103
|
+
import { useEffect } from "react";
|
|
104
|
+
import type { AppProps } from "next/app";
|
|
105
|
+
import { initKeyVault } from "mm-key-vault";
|
|
106
|
+
|
|
107
|
+
export default function App({ Component, pageProps }: AppProps) {
|
|
108
|
+
useEffect(() => {
|
|
109
|
+
initKeyVault();
|
|
110
|
+
}, []);
|
|
111
|
+
|
|
112
|
+
return <Component {...pageProps} />;
|
|
113
|
+
}
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
---
|
|
117
|
+
|
|
118
|
+
### 🌐 Vanilla HTML (no framework)
|
|
119
|
+
|
|
120
|
+
For local testing (like `test.html`), you can load the ESM bundle and provide React via an import map:
|
|
121
|
+
|
|
122
|
+
```html
|
|
123
|
+
<script type="importmap">
|
|
124
|
+
{
|
|
125
|
+
"imports": {
|
|
126
|
+
"react": "https://esm.sh/react@18",
|
|
127
|
+
"react-dom": "https://esm.sh/react-dom@18",
|
|
128
|
+
"react-dom/client": "https://esm.sh/react-dom@18/client",
|
|
129
|
+
"react/jsx-runtime":"https://esm.sh/react@18/jsx-runtime"
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
</script>
|
|
133
|
+
|
|
134
|
+
<script type="module">
|
|
135
|
+
import { initKeyVault } from "./dist/mm-key-vault.esm.js";
|
|
136
|
+
initKeyVault();
|
|
137
|
+
<\/script>
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
---
|
|
141
|
+
|
|
142
|
+
## Configuration
|
|
143
|
+
|
|
144
|
+
All options are optional.
|
|
145
|
+
|
|
146
|
+
```ts
|
|
147
|
+
initKeyVault({
|
|
148
|
+
position: "bottom-right",
|
|
149
|
+
offsetX: "24px",
|
|
150
|
+
offsetY: "24px",
|
|
151
|
+
zIndex: 9999,
|
|
152
|
+
});
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
| Option | Type | Default |
|
|
156
|
+
|---|---|---|
|
|
157
|
+
| `position` | `"bottom-right" \| "bottom-left" \| "top-right" \| "top-left" \| "center"` | `"bottom-right"` |
|
|
158
|
+
| `offsetX` | `string` | `"20px"` |
|
|
159
|
+
| `offsetY` | `string` | `"20px"` |
|
|
160
|
+
| `zIndex` | `number` | `9999` |
|
|
161
|
+
|
|
162
|
+
---
|
|
163
|
+
|
|
164
|
+
## Auth + token storage
|
|
165
|
+
|
|
166
|
+
- On successful login, the widget saves the returned token (`data.access_token`) in browser storage.
|
|
167
|
+
- **Remember me**:
|
|
168
|
+
- unchecked → `sessionStorage`
|
|
169
|
+
- checked → `localStorage`
|
|
170
|
+
- On widget open, it checks storage and shows **Dashboard** if token exists; otherwise it shows **Login**.
|
|
171
|
+
|
|
172
|
+
---
|
|
173
|
+
|
|
174
|
+
## API endpoints used
|
|
175
|
+
|
|
176
|
+
Auth:
|
|
177
|
+
|
|
178
|
+
- `POST /auth/login` → expects `data.access_token`
|
|
179
|
+
- `POST /auth/signup`
|
|
180
|
+
|
|
181
|
+
Dashboard listing:
|
|
182
|
+
|
|
183
|
+
- `GET /auth/list_platforms?search=&page=&limit=&sort_by=&order=`
|
|
184
|
+
|
|
185
|
+
Add / details / update:
|
|
186
|
+
|
|
187
|
+
- `POST /auth/add_key` body: `{ platform, api_key }`
|
|
188
|
+
- `GET /auth/get_key/:credential_id`
|
|
189
|
+
- `PUT /auth/update_key/:credential_id` body: `{ platform, api_key }`
|
|
190
|
+
|
|
191
|
+
Errors:
|
|
192
|
+
|
|
193
|
+
- Duplicate platform example: `{ "detail": "Platform already exists" }`
|
|
194
|
+
|
|
195
|
+
---
|
|
196
|
+
|
|
197
|
+
## UI behavior
|
|
198
|
+
|
|
199
|
+
- **Listing**: debounced search, default sort by platform (desc), “Load more”
|
|
200
|
+
- **Copy**: fetches details first, then copies `api_key` to clipboard
|
|
201
|
+
- **Validation** (on Save):
|
|
202
|
+
- platform: required, min 2, max 60
|
|
203
|
+
- api_key: required, min 2, max 200
|
|
204
|
+
|
|
205
|
+
---
|
|
206
|
+
|
|
207
|
+
## Cleanup (optional)
|
|
208
|
+
|
|
209
|
+
```ts
|
|
210
|
+
import { destroyKeyVault } from "mm-key-vault";
|
|
211
|
+
destroyKeyVault();
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
---
|
|
215
|
+
|
|
216
|
+
## Troubleshooting
|
|
217
|
+
|
|
218
|
+
- **Widget not showing**: call `initKeyVault()` only in the browser (React/Next.js: inside `useEffect`).
|
|
219
|
+
- **Next.js SSR crash**: never call `initKeyVault()` at module top-level.
|
|
220
|
+
- **Nothing loads after login**: verify your backend returns `data.access_token`.
|
|
221
|
+
|
|
222
|
+
---
|
|
223
|
+
|
|
224
|
+
## License
|
|
225
|
+
|
|
226
|
+
MIT
|
package/dist/api.d.ts
ADDED
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
export declare function getToken(): string | null;
|
|
2
|
+
export declare function setToken(token: string, remember?: boolean): void;
|
|
3
|
+
export declare function clearToken(): void;
|
|
4
|
+
export declare function isAuthenticated(): boolean;
|
|
5
|
+
export interface SignupPayload {
|
|
6
|
+
email: string;
|
|
7
|
+
password: string;
|
|
8
|
+
callback?: string;
|
|
9
|
+
}
|
|
10
|
+
export interface LoginPayload {
|
|
11
|
+
email: string;
|
|
12
|
+
password: string;
|
|
13
|
+
}
|
|
14
|
+
export interface ApiResponse<T = unknown> {
|
|
15
|
+
status: number;
|
|
16
|
+
message: string;
|
|
17
|
+
data?: T;
|
|
18
|
+
}
|
|
19
|
+
export interface SignupData {
|
|
20
|
+
user_id: string;
|
|
21
|
+
email: string;
|
|
22
|
+
email_verified: boolean;
|
|
23
|
+
}
|
|
24
|
+
export interface LoginData {
|
|
25
|
+
token?: string;
|
|
26
|
+
access_token?: string;
|
|
27
|
+
user_id?: string;
|
|
28
|
+
email?: string;
|
|
29
|
+
}
|
|
30
|
+
export declare function signup(payload: SignupPayload): Promise<ApiResponse<SignupData>>;
|
|
31
|
+
export declare function login(credentials: LoginPayload, remember?: boolean): Promise<ApiResponse<LoginData>>;
|
|
32
|
+
export declare function verifyEmail(token: string): Promise<ApiResponse>;
|
|
33
|
+
export interface ForgotPasswordPayload {
|
|
34
|
+
email: string;
|
|
35
|
+
callback?: string;
|
|
36
|
+
}
|
|
37
|
+
export declare function forgotPassword(payload: ForgotPasswordPayload): Promise<ApiResponse>;
|
|
38
|
+
export interface ResetPasswordPayload {
|
|
39
|
+
token: string;
|
|
40
|
+
new_password: string;
|
|
41
|
+
}
|
|
42
|
+
export declare function resetPassword(payload: ResetPasswordPayload): Promise<ApiResponse>;
|
|
43
|
+
export type SortOrder = "asc" | "desc";
|
|
44
|
+
export interface PlatformRecord {
|
|
45
|
+
id: number;
|
|
46
|
+
platform: string;
|
|
47
|
+
created_at?: string;
|
|
48
|
+
updated_at?: string;
|
|
49
|
+
}
|
|
50
|
+
export interface ListPlatformsParams {
|
|
51
|
+
search?: string;
|
|
52
|
+
page?: number;
|
|
53
|
+
limit?: number;
|
|
54
|
+
sort_by?: string;
|
|
55
|
+
order?: SortOrder;
|
|
56
|
+
}
|
|
57
|
+
export interface ListPlatformsData {
|
|
58
|
+
user_id: string;
|
|
59
|
+
current_page: number;
|
|
60
|
+
total_pages: number;
|
|
61
|
+
has_next_page: boolean;
|
|
62
|
+
has_previous_page: boolean;
|
|
63
|
+
limit: number;
|
|
64
|
+
total_database_count: number;
|
|
65
|
+
result: PlatformRecord[];
|
|
66
|
+
}
|
|
67
|
+
export declare function listPlatforms(params?: ListPlatformsParams): Promise<ApiResponse<ListPlatformsData>>;
|
|
68
|
+
export interface UpsertPlatformPayload {
|
|
69
|
+
platform: string;
|
|
70
|
+
api_key?: string;
|
|
71
|
+
}
|
|
72
|
+
export declare function addKey(payload: Required<Pick<UpsertPlatformPayload, "platform" | "api_key">>): Promise<ApiResponse<{
|
|
73
|
+
platform: string;
|
|
74
|
+
}>>;
|
|
75
|
+
export declare function getKey(credentialId: number): Promise<ApiResponse<{
|
|
76
|
+
platform: string;
|
|
77
|
+
api_key: string;
|
|
78
|
+
}>>;
|
|
79
|
+
export declare function updateKey(id: number, payload: UpsertPlatformPayload): Promise<ApiResponse>;
|
|
80
|
+
export declare function deletePlatform(id: number): Promise<ApiResponse>;
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
type Position = "bottom-right" | "bottom-left" | "top-right" | "top-left" | "center";
|
|
2
|
+
export interface KeyVaultConfig {
|
|
3
|
+
/** Where to place the floating button. Default: "bottom-right" */
|
|
4
|
+
position?: Position;
|
|
5
|
+
/** Horizontal offset from the edge. Default: "20px" */
|
|
6
|
+
offsetX?: string;
|
|
7
|
+
/** Vertical offset from the edge. Default: "20px" */
|
|
8
|
+
offsetY?: string;
|
|
9
|
+
/** CSS z-index of the widget. Default: 9999 */
|
|
10
|
+
zIndex?: number;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Initialize the Key Vault floating widget.
|
|
14
|
+
*
|
|
15
|
+
* ```ts
|
|
16
|
+
* import { initKeyVault } from "keyvault-widget";
|
|
17
|
+
* initKeyVault({ apiBaseUrl: "https://api.example.com" });
|
|
18
|
+
* ```
|
|
19
|
+
*/
|
|
20
|
+
export declare function initKeyVault(config?: KeyVaultConfig): void;
|
|
21
|
+
/**
|
|
22
|
+
* Destroy the Key Vault widget and clean up.
|
|
23
|
+
*/
|
|
24
|
+
export declare function destroyKeyVault(): void;
|
|
25
|
+
export {};
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const e=require("react/jsx-runtime"),s=require("react"),ze=require("react-dom/client"),I="kv_widget_token",Fe="https://probioticbackend.masterymade.com";function ye(){if(typeof window>"u")return null;const o=window.sessionStorage.getItem(I);if(o)try{const a=JSON.parse(o);return typeof a=="string"?a:(a==null?void 0:a.token)||null}catch{return o}const r=window.localStorage.getItem(I);if(!r)return null;try{const a=JSON.parse(r);return typeof a=="string"?a:(a==null?void 0:a.token)||null}catch{return r}}function Ie(o,r=!1){typeof window>"u"||(window.sessionStorage.removeItem(I),window.localStorage.removeItem(I),r?window.localStorage.setItem(I,o):window.sessionStorage.setItem(I,o))}function Re(){typeof window>"u"||(window.sessionStorage.removeItem(I),window.localStorage.removeItem(I))}function ke(){return!!ye()}async function R(o,r={}){const a=ye(),m={"Content-Type":"application/json",...r.headers};a&&(m.Authorization=`Bearer ${a}`);const i=await fetch(`${Fe}${o}`,{...r,headers:m});if(!i.ok){let l=`Request failed (${i.status})`;try{const p=await i.json(),u=p==null?void 0:p.detail;typeof u=="string"?l=u:u&&typeof u=="object"?l=u.message||u.error||(p==null?void 0:p.message)||(p==null?void 0:p.error)||l:l=(p==null?void 0:p.message)||(p==null?void 0:p.error)||l}catch{}throw new Error(l)}if(i.status!==204)return i.json()}async function Ke(o){const r=await R("/auth/signup",{method:"POST",body:JSON.stringify(o)});if(r.status!==1)throw new Error(r.message||"Signup failed");return r}async function Ae(o,r=!1){var i,l;const a=await R("/auth/login",{method:"POST",body:JSON.stringify(o)});if(a.status&&a.status!==1)throw new Error(a.message||"Login failed");const m=((i=a.data)==null?void 0:i.access_token)||((l=a.data)==null?void 0:l.token)||a.token;if(!m)throw new Error("Login succeeded but no token returned by API");return Ie(m,r),a}async function Te(o){return R("/auth/forgot-password",{method:"POST",body:JSON.stringify(o)})}async function _e(o){const{token:r,new_password:a}=o,m=new URLSearchParams({token:r}).toString();return R(`/auth/reset-password?${m}`,{method:"POST",body:JSON.stringify({new_password:a})})}function Me(o){const r=new URLSearchParams;Object.entries(o).forEach(([m,i])=>{i==null||i===""||r.set(m,String(i))});const a=r.toString();return a?`?${a}`:""}async function Oe(o={}){const{search:r,page:a=1,limit:m=10,sort_by:i,order:l="asc"}=o,p=Me({search:r,page:a,limit:m,sort_by:i,order:l});return R(`/auth/list_platforms${p}`)}async function Be(o){return R("/auth/add_key",{method:"POST",body:JSON.stringify(o)})}async function be(o){return R(`/auth/get_key/${o}`)}async function $e(o,r){return R(`/auth/update_key/${o}`,{method:"PUT",body:JSON.stringify(r)})}const ie=({msg:o})=>o?e.jsxs("span",{className:"kv-field-error",children:["⚠ ",o]}):null,Ve=({onLoginSuccess:o})=>{const[r,a]=s.useState("login"),[m,i]=s.useState(!1),[l,p]=s.useState(""),[u,S]=s.useState(""),[b,K]=s.useState(!1),[P,A]=s.useState(!1),[T,le]=s.useState(!1),[Z,O]=s.useState(""),[y,B]=s.useState({email:"",password:""}),[$,de]=s.useState(""),[V,ce]=s.useState(!1),[D,L]=s.useState(""),[Q,h]=s.useState(""),[Y,g]=s.useState({email:""}),[z,q]=s.useState(""),[U,pe]=s.useState(""),[H,F]=s.useState(!1),[_,M]=s.useState(!1),[J,W]=s.useState(""),[X,ee]=s.useState(!1),[ue,te]=s.useState(""),[N,C]=s.useState({email:"",password:""}),[E,se]=s.useState(null),[G,re]=s.useState(""),[ae,oe]=s.useState(""),[ne,n]=s.useState(!1),[f,k]=s.useState(!1),[d,v]=s.useState(!1),[x,w]=s.useState(""),[he,fe]=s.useState(""),ve=t=>t.trim()?t.length<5?"Email must be at least 5 characters":t.length>60?"Email must be at most 60 characters":/\s/.test(t)?"Email must not contain spaces":/^[^\s@]+@[^\s@]+\.[^\s@]{2,}$/.test(t)?/\.\./.test(t)?"Email must not contain consecutive dots":"":"Enter a valid email address":"Email is required",me=t=>t?t.length<8?"Password must be at least 8 characters":t.length>16?"Password must be at most 16 characters":/[A-Z]/.test(t)?/[a-z]/.test(t)?/[0-9]/.test(t)?/[^A-Za-z0-9]/.test(t)?"":"Password must contain at least one special character":"Password must contain at least one number":"Password must contain at least one lowercase letter":"Password must contain at least one uppercase letter":"Password is required",we=()=>{const t=me(G);return t?(w(t),!1):G!==ae?(w("Passwords do not match"),!1):(w(""),!0)};s.useEffect(()=>{if(typeof window>"u")return;const c=new URLSearchParams(window.location.search).get("token");c&&(se(c),i(!1),a("login"))},[]);const je=()=>{const t={email:ve(l),password:me(u)};return B(t),!t.email&&!t.password},Se=()=>{const t={email:ve($)};return g(t),!t.email},Ne=()=>{const t={email:ve(z),password:me(U)};return C(t),!t.email&&!t.password},Ce=async t=>{if(t.preventDefault(),O(""),!!je()){le(!0);try{await Ae({email:l,password:u},P),o()}catch(c){O(c instanceof Error?c.message:"Login failed")}finally{le(!1)}}},Ee=async t=>{if(t.preventDefault(),L(""),h(""),!!Se()){ce(!0);try{const c=window.location.origin,j=await Te({email:$.trim(),callback:c});j.status===0?L(j.message||"Your email address is not verified."):h(j.message||"If your email is registered, you will receive a password reset link.")}catch(c){L(c instanceof Error?c.message:"Request failed")}finally{ce(!1)}}},Pe=async t=>{var c;if(t.preventDefault(),w(""),fe(""),!E){w("Reset link is invalid or has expired.");return}if(we()){v(!0);try{const j=await _e({token:E,new_password:G});if(j.status!==1){w(j.message||"Could not reset password.");return}if(fe(j.message||"Your password has been reset. You can now log in with the new password."),typeof window<"u"&&((c=window.history)!=null&&c.replaceState)){const ge=new URL(window.location.href);ge.searchParams.delete("token"),window.history.replaceState({},"",ge.toString())}setTimeout(()=>{se(null),re(""),oe("")},2e3)}catch(j){w(j instanceof Error?j.message:"Password reset failed")}finally{v(!1)}}},Le=async t=>{if(t.preventDefault(),W(""),!!Ne()){M(!0);try{const c=await Ke({email:z,password:U,callback:window.location.href});te(c.message||"Account created successfully!"),ee(!0)}catch(c){W(c instanceof Error?c.message:"Signup failed")}finally{M(!1)}}};return e.jsxs(e.Fragment,{children:[!m&&!E?e.jsxs("div",{className:"kv-tabs",children:[e.jsx("button",{className:`kv-tab ${r==="login"?"kv-active":""}`,onClick:()=>{a("login"),i(!1),O(""),B({email:"",password:""}),L(""),h(""),g({email:""})},children:"Log In"}),e.jsx("button",{className:`kv-tab ${r==="signup"?"kv-active":""}`,onClick:()=>{a("signup"),W(""),ee(!1),C({email:"",password:""})},children:"Sign Up"})]}):E?e.jsx("div",{className:"kv-forgot-header",children:"Reset Password"}):e.jsx("div",{className:"kv-forgot-header",children:"Forgot Password"}),r==="login"&&!E&&e.jsx(e.Fragment,{children:m?e.jsxs(e.Fragment,{children:[e.jsxs("form",{className:"kv-form",onSubmit:Ee,noValidate:!0,children:[D&&e.jsx("div",{className:"kv-alert kv-alert-error",children:D}),Q&&e.jsx("div",{className:"kv-alert kv-alert-success",children:Q}),e.jsxs("div",{className:"kv-field",children:[e.jsx("label",{className:"kv-label",children:"Email"}),e.jsx("input",{className:`kv-input${Y.email?" kv-input-error":""}`,type:"text",placeholder:"you@example.com",value:$,onChange:t=>{de(t.target.value),Y.email&&g({email:""})}}),e.jsx(ie,{msg:Y.email})]}),e.jsx("button",{className:"kv-btn kv-btn-primary",type:"submit",disabled:V,children:V?e.jsxs(e.Fragment,{children:[e.jsx("span",{className:"kv-spinner"})," Sending…"]}):"Send reset link"})]}),e.jsx("button",{type:"button",className:"kv-btn kv-btn-ghost",style:{width:"100%"},onClick:t=>{t.preventDefault(),t.stopPropagation(),i(!1),L(""),h(""),g({email:""})},children:"Back to login"})]}):e.jsxs("form",{className:"kv-form",onSubmit:Ce,children:[Z&&e.jsx("div",{className:"kv-alert kv-alert-error",children:Z}),e.jsxs("div",{className:"kv-field",children:[e.jsx("label",{className:"kv-label",children:"Email"}),e.jsx("input",{className:`kv-input${y.email?" kv-input-error":""}`,type:"text",placeholder:"you@example.com",value:l,onChange:t=>{p(t.target.value),y.email&&B(c=>({...c,email:""}))}}),e.jsx(ie,{msg:y.email})]}),e.jsxs("div",{className:"kv-field",children:[e.jsx("label",{className:"kv-label",children:"Password"}),e.jsxs("div",{style:{position:"relative"},children:[e.jsx("input",{className:`kv-input${y.password?" kv-input-error":""}`,type:b?"text":"password",placeholder:"••••••••",value:u,onChange:t=>{S(t.target.value),y.password&&B(c=>({...c,password:""}))},style:{paddingRight:40}}),e.jsx("button",{type:"button",onClick:()=>K(t=>!t),"aria-label":b?"Hide password":"Show password",style:{position:"absolute",right:10,top:"50%",transform:"translateY(-50%)",border:"none",background:"transparent",cursor:"pointer",color:"#fff",fontSize:14,padding:0},children:b?"🙈":"👁️"})]}),e.jsx(ie,{msg:y.password})]}),e.jsxs("div",{className:"kv-remember",style:{justifyContent:"space-between"},children:[e.jsxs("div",{style:{display:"flex",alignItems:"center",gap:8},children:[e.jsx("input",{id:"kv-remember-me",type:"checkbox",checked:P,onChange:t=>A(t.target.checked)}),e.jsx("label",{htmlFor:"kv-remember-me",children:"Remember me"})]}),e.jsx("button",{type:"button",className:"kv-btn kv-btn-ghost",style:{padding:"6px 10px",fontSize:12},onClick:()=>{i(!0),de(l),L(""),h(""),g({email:""})},children:"Forgot password?"})]}),e.jsx("button",{className:"kv-btn kv-btn-primary",type:"submit",disabled:T,children:T?e.jsxs(e.Fragment,{children:[e.jsx("span",{className:"kv-spinner"})," Logging in…"]}):"Log In"})]})}),r==="signup"&&!E&&e.jsx(e.Fragment,{children:X?e.jsxs("div",{className:"kv-verify-banner",children:["🎉 ",e.jsx("strong",{children:ue}),e.jsx("br",{}),"Please verify your email before logging in."]}):e.jsxs("form",{className:"kv-form",onSubmit:Le,children:[J&&e.jsx("div",{className:"kv-alert kv-alert-error",children:J}),e.jsxs("div",{className:"kv-field",children:[e.jsx("label",{className:"kv-label",children:"Email"}),e.jsx("input",{className:`kv-input${N.email?" kv-input-error":""}`,type:"text",placeholder:"you@example.com",value:z,onChange:t=>{q(t.target.value),N.email&&C(c=>({...c,email:""}))}}),e.jsx(ie,{msg:N.email})]}),e.jsxs("div",{className:"kv-field",children:[e.jsx("label",{className:"kv-label",children:"Password"}),e.jsxs("div",{style:{position:"relative"},children:[e.jsx("input",{className:`kv-input${N.password?" kv-input-error":""}`,type:H?"text":"password",placeholder:"Min. 8 characters",value:U,onChange:t=>{pe(t.target.value),N.password&&C(c=>({...c,password:""}))},style:{paddingRight:40}}),e.jsx("button",{type:"button",onClick:()=>F(t=>!t),"aria-label":H?"Hide password":"Show password",style:{position:"absolute",right:10,top:"50%",transform:"translateY(-50%)",border:"none",background:"transparent",cursor:"pointer",color:"#fff",fontSize:14,padding:0},children:H?"🙈":"👁️"})]}),e.jsx(ie,{msg:N.password})]}),e.jsx("button",{className:"kv-btn kv-btn-primary",type:"submit",disabled:_,children:_?e.jsxs(e.Fragment,{children:[e.jsx("span",{className:"kv-spinner"})," Creating account…"]}):"Create Account"})]})}),E&&e.jsxs("form",{className:"kv-form",onSubmit:Pe,noValidate:!0,children:[x&&e.jsx("div",{className:"kv-alert kv-alert-error",children:x}),he&&e.jsx("div",{className:"kv-alert kv-alert-success",children:he}),e.jsxs("div",{className:"kv-field",children:[e.jsx("label",{className:"kv-label",children:"New password"}),e.jsxs("div",{style:{position:"relative"},children:[e.jsx("input",{className:"kv-input",type:ne?"text":"password",placeholder:"Enter new password",value:G,onChange:t=>re(t.target.value),style:{paddingRight:40}}),e.jsx("button",{type:"button",onClick:()=>n(t=>!t),"aria-label":ne?"Hide password":"Show password",style:{position:"absolute",right:10,top:"50%",transform:"translateY(-50%)",border:"none",background:"transparent",cursor:"pointer",color:"#fff",fontSize:14,padding:0},children:ne?"🙈":"👁️"})]})]}),e.jsxs("div",{className:"kv-field",children:[e.jsx("label",{className:"kv-label",children:"Confirm password"}),e.jsxs("div",{style:{position:"relative"},children:[e.jsx("input",{className:"kv-input",type:f?"text":"password",placeholder:"Re-enter new password",value:ae,onChange:t=>oe(t.target.value),style:{paddingRight:40}}),e.jsx("button",{type:"button",onClick:()=>k(t=>!t),"aria-label":f?"Hide password":"Show password",style:{position:"absolute",right:10,top:"50%",transform:"translateY(-50%)",border:"none",background:"transparent",cursor:"pointer",color:"#fff",fontSize:14,padding:0},children:f?"🙈":"👁️"})]})]}),e.jsx("button",{className:"kv-btn kv-btn-primary",type:"submit",disabled:d,children:d?e.jsxs(e.Fragment,{children:[e.jsx("span",{className:"kv-spinner"})," Saving…"]}):"Save password"}),e.jsx("button",{type:"button",className:"kv-btn kv-btn-ghost",style:{width:"100%",marginTop:8},onClick:()=>{var t;if(se(null),re(""),oe(""),fe(""),w(""),typeof window<"u"&&((t=window.history)!=null&&t.replaceState)){const c=new URL(window.location.href);c.searchParams.delete("token"),window.history.replaceState({},"",c.toString())}},children:"Back to login"})]})]})},De=()=>e.jsxs("svg",{viewBox:"0 0 24 24",width:14,height:14,fill:"none",stroke:"currentColor",strokeWidth:2,strokeLinecap:"round",strokeLinejoin:"round",children:[e.jsx("path",{d:"M12 20h9"}),e.jsx("path",{d:"M16.5 3.5a2.1 2.1 0 013 3L7 19l-4 1 1-4 12.5-12.5z"})]}),Ye=()=>e.jsxs("svg",{viewBox:"0 0 24 24",width:14,height:14,fill:"none",stroke:"currentColor",strokeWidth:2,strokeLinecap:"round",strokeLinejoin:"round",children:[e.jsx("rect",{x:"9",y:"9",width:"13",height:"13",rx:"2",ry:"2"}),e.jsx("path",{d:"M5 15H4a2 2 0 01-2-2V4a2 2 0 012-2h9a2 2 0 012 2v1"})]}),qe=({off:o})=>e.jsx("svg",{viewBox:"0 0 24 24",width:16,height:16,fill:"none",stroke:"currentColor",strokeWidth:2,strokeLinecap:"round",strokeLinejoin:"round",children:o?e.jsxs(e.Fragment,{children:[e.jsx("path",{d:"M17.94 17.94A10.94 10.94 0 0112 20C7 20 2.73 16.11 1 12c.74-1.77 1.86-3.39 3.29-4.76"}),e.jsx("path",{d:"M10.58 10.58A2 2 0 0012 14a2 2 0 001.42-.58"}),e.jsx("path",{d:"M9.88 5.09A10.94 10.94 0 0112 4c5 0 9.27 3.89 11 8-1.05 2.52-2.86 4.67-5.19 6.18"}),e.jsx("path",{d:"M1 1l22 22"})]}):e.jsxs(e.Fragment,{children:[e.jsx("path",{d:"M1 12s4-8 11-8 11 8 11 8-4 8-11 8S1 12 1 12z"}),e.jsx("circle",{cx:"12",cy:"12",r:"3"})]})}),Ue=({onLogout:o})=>{const[r,a]=s.useState("list"),[m,i]=s.useState(null),[l,p]=s.useState([]),[u,S]=s.useState(!0),[b,K]=s.useState(!1),[P,A]=s.useState(""),[T,le]=s.useState(1),[Z,O]=s.useState(!1),[y,B]=s.useState(""),[$,de]=s.useState(""),[V,ce]=s.useState("platform"),[D,L]=s.useState("desc"),[Q,h]=s.useState(""),[Y,g]=s.useState(""),[z,q]=s.useState(!1),[U,pe]=s.useState(!1),[H,F]=s.useState(""),[_,M]=s.useState({platform:"",apiKey:""}),[J,W]=s.useState(!1),[X,ee]=s.useState(null),[ue,te]=s.useState(null);s.useEffect(()=>{const n=window.setTimeout(()=>de(y.trim()),350);return()=>window.clearTimeout(n)},[y]);const N=s.useMemo(()=>l.length,[l.length]),C=s.useCallback(async n=>{const{page:f,append:k}=n;k?K(!0):S(!0),A("");try{const d=await Oe({search:$||void 0,page:f,limit:10,sort_by:V||void 0,order:D});if(d.status!==1)throw new Error(d.message||"Failed to load platforms");const v=d.data,x=(v==null?void 0:v.result)??[];p(w=>k?[...w,...x]:x),le((v==null?void 0:v.current_page)??f),O(!!(v!=null&&v.has_next_page))}catch(d){A(d instanceof Error?d.message:"Failed to load platforms"),k||(p([]),O(!1))}finally{k?K(!1):S(!1)}},[$,D,V]);s.useEffect(()=>{r==="list"&&C({page:1,append:!1})},[C,r]);const E=async()=>{!Z||b||await C({page:T+1,append:!0})},se=async n=>{var f,k;if(!X){ee(n),te(null);try{const d=await be(n);if(d.status!==1)throw new Error(d.message||"Failed to fetch key");const v=(f=d.data)==null?void 0:f.api_key;if(!v)throw new Error("No api_key returned");if((k=navigator.clipboard)!=null&&k.writeText)await navigator.clipboard.writeText(v);else{const x=document.createElement("textarea");x.value=v,x.style.position="fixed",x.style.left="-9999px",x.style.top="0",document.body.appendChild(x),x.focus(),x.select(),document.execCommand("copy"),x.remove()}te(n),window.setTimeout(()=>te(x=>x===n?null:x),1200)}catch(d){A(d instanceof Error?d.message:"Copy failed")}finally{ee(null)}}},G=()=>{F(""),h(""),g(""),q(!1),i(null),a("add")},re=n=>{F(""),i(n),h(""),g(""),q(!1),M({platform:"",apiKey:""}),a("edit"),W(!0),be(n.id).then(f=>{var k,d;if(f.status!==1)throw new Error(f.message||"Failed to load key details");h(((k=f.data)==null?void 0:k.platform)??n.platform??""),g(((d=f.data)==null?void 0:d.api_key)??"")}).catch(f=>{F(f instanceof Error?f.message:"Failed to load key details"),h(n.platform||""),g("")}).finally(()=>W(!1))},ae=()=>{a("list"),i(null),F(""),h(""),g(""),q(!1),M({platform:"",apiKey:""})},oe=async n=>{n.preventDefault(),F(""),M({platform:"",apiKey:""});const f=Q.trim(),k=Y.trim(),d={platform:"",apiKey:""};if(f?f.length<2?d.platform="Platform must be at least 2 characters":f.length>60&&(d.platform="Platform must be at most 60 characters"):d.platform="Platform is required",k?k.length<2?d.apiKey="API key must be at least 2 characters":k.length>200&&(d.apiKey="API key must be at most 200 characters"):d.apiKey="API key is required",d.platform||d.apiKey){M(d);return}pe(!0);try{if(r==="add"){const v=await Be({platform:f,api_key:k});if(v.status!==1)throw new Error(v.message||"Failed to add key")}else if(r==="edit"&&m){const v=await $e(m.id,{platform:f,api_key:k});if(v.status!==1)throw new Error(v.message||"Failed to update key")}ae(),await C({page:1,append:!1})}catch(v){F(v instanceof Error?v.message:"Save failed")}finally{pe(!1)}},ne=()=>{Re(),o()};return e.jsxs(e.Fragment,{children:[e.jsxs("div",{className:"kv-dash-meta",children:[e.jsxs("span",{className:"kv-badge",children:[N," ",N===1?"Platform":"Platforms"]}),e.jsxs("div",{style:{display:"flex",gap:8,alignItems:"center"},children:[r==="list"&&e.jsx("button",{className:"kv-btn kv-btn-primary",style:{width:"auto",padding:"8px 12px",fontSize:12},onClick:G,children:"Add Key"}),e.jsx("button",{className:"kv-btn kv-btn-ghost",style:{fontSize:12,padding:"5px 12px"},onClick:ne,children:"Sign out"})]})]}),r==="list"&&e.jsxs(e.Fragment,{children:[e.jsxs("div",{className:"kv-toolbar",style:{display:"grid",gridTemplateColumns:"1fr auto auto",gap:10,margin:"6px 0 14px"},children:[e.jsx("input",{className:"kv-input",type:"text",placeholder:"Search platforms…",value:y,onChange:n=>B(n.target.value)}),e.jsxs("select",{className:"kv-input",style:{padding:"10px 12px"},value:V,onChange:n=>ce(n.target.value),children:[e.jsx("option",{value:"",children:"Sort by"}),e.jsx("option",{value:"platform",children:"Platform"}),e.jsx("option",{value:"created_at",children:"Created"}),e.jsx("option",{value:"updated_at",children:"Updated"})]}),e.jsxs("select",{className:"kv-input",style:{padding:"10px 12px"},value:D,onChange:n=>L(n.target.value),children:[e.jsx("option",{value:"asc",children:"Asc"}),e.jsx("option",{value:"desc",children:"Desc"})]})]}),e.jsxs("div",{style:{display:"flex",alignItems:"center",justifyContent:"space-between",gap:12},children:[e.jsx("p",{className:"kv-section-title",children:"Listing"}),u&&e.jsx("span",{style:{fontSize:12,color:"var(--kv-text-muted)"},children:"Loading platforms…"})]}),e.jsxs("div",{className:"kv-list-scroll",children:[e.jsxs("div",{className:"kv-key-list",children:[u&&e.jsx(e.Fragment,{children:Array.from({length:6}).map((n,f)=>e.jsx("div",{className:"kv-key-item kv-skeleton kv-skel-row",children:e.jsxs("div",{style:{display:"flex",flexDirection:"column",gap:10,width:"100%"},children:[e.jsx("div",{className:"kv-skel-line",style:{width:"42%"}}),e.jsx("div",{className:"kv-skel-line",style:{width:"22%",opacity:.75}})]})},`skel-${f}`))}),!u&&P&&e.jsx("div",{className:"kv-alert kv-alert-error",children:P}),!u&&!P&&l.length===0&&e.jsx("div",{className:"kv-empty-state",children:e.jsx("p",{children:"No platforms found."})}),!u&&l.map(n=>e.jsx("div",{className:"kv-key-item",children:e.jsxs("div",{className:"kv-key-info",style:{display:"flex",alignItems:"center",justifyContent:"space-between",gap:12},children:[e.jsxs("div",{style:{minWidth:0},children:[e.jsx("div",{className:"kv-key-service",children:n.platform}),e.jsxs("div",{className:"kv-key-id",children:["ID #",n.id]})]}),e.jsxs("div",{style:{display:"flex",gap:8,alignItems:"center"},children:[e.jsx("button",{className:"kv-btn kv-btn-ghost",style:{padding:"6px 10px",fontSize:12},onClick:()=>re(n),title:"Edit",children:e.jsxs("span",{style:{display:"inline-flex",alignItems:"center",gap:6},children:[e.jsx(De,{})," Edit"]})}),e.jsx("button",{className:"kv-btn kv-btn-ghost",style:{padding:"6px 10px",fontSize:12},onClick:()=>se(n.id),title:"Copy API key",disabled:X===n.id,children:e.jsxs("span",{style:{display:"inline-flex",alignItems:"center",gap:6},children:[X===n.id?e.jsx("span",{className:"kv-spinner"}):e.jsx(Ye,{}),ue===n.id?"Copied":"Copy"]})})]})]})},n.id))]}),!u&&Z&&e.jsx("button",{className:"kv-btn kv-btn-ghost",style:{width:"100%",marginTop:12},onClick:E,disabled:b,children:b?e.jsxs(e.Fragment,{children:[e.jsx("span",{className:"kv-spinner"})," Loading…"]}):"Load more"})]})]}),(r==="add"||r==="edit")&&e.jsxs("div",{className:"kv-add-section",style:{borderTop:"none",paddingTop:0},children:[e.jsxs("div",{style:{display:"flex",alignItems:"center",justifyContent:"space-between",marginBottom:10},children:[e.jsx("p",{className:"kv-section-title",style:{marginBottom:0},children:r==="add"?"Add Key":"Edit Key"}),e.jsx("button",{className:"kv-btn kv-btn-ghost",style:{padding:"6px 10px",fontSize:12},onClick:ae,children:"Back"})]}),H&&e.jsx("div",{className:"kv-alert kv-alert-error",style:{marginBottom:12},children:H}),e.jsxs("form",{className:"kv-form",onSubmit:oe,autoComplete:"off",noValidate:!0,children:[e.jsxs("div",{style:{position:"absolute",left:"-10000px",top:"auto",width:1,height:1,overflow:"hidden"},"aria-hidden":"true",children:[e.jsx("input",{type:"text",name:"username",autoComplete:"username",tabIndex:-1}),e.jsx("input",{type:"password",name:"password",autoComplete:"current-password",tabIndex:-1})]}),e.jsxs("div",{className:"kv-field",children:[e.jsx("label",{className:"kv-label",children:"Platform"}),e.jsx("input",{className:"kv-input",type:"text",placeholder:"e.g. shopify, wordpress",name:"kv_platform",value:Q,onChange:n=>h(n.target.value),autoComplete:"new-password",autoCorrect:"off",autoCapitalize:"none",disabled:J}),_.platform&&e.jsx("div",{className:"kv-field-error",children:_.platform})]}),e.jsxs("div",{className:"kv-field",children:[e.jsx("label",{className:"kv-label",children:"API Key"}),e.jsxs("div",{className:"kv-add-row",children:[e.jsx("input",{className:"kv-input",type:z?"text":"password",placeholder:"Paste API key",name:"kv_api_key",value:Y,onChange:n=>g(n.target.value),autoComplete:"new-password",autoCorrect:"off",autoCapitalize:"none",disabled:J}),e.jsx("button",{className:"kv-btn kv-btn-ghost",type:"button",style:{width:"auto",padding:"11px 14px"},onClick:()=>q(n=>!n),"aria-label":z?"Hide API key":"Show API key",title:z?"Hide":"Show",disabled:J,children:e.jsx(qe,{off:z})})]}),_.apiKey&&e.jsx("div",{className:"kv-field-error",children:_.apiKey})]}),e.jsx("button",{className:"kv-btn kv-btn-primary",type:"submit",disabled:U,children:U?e.jsxs(e.Fragment,{children:[e.jsx("span",{className:"kv-spinner"})," Saving…"]}):"Save"})]})]})]})},He='.kv-root *,.kv-root *:before,.kv-root *:after{box-sizing:border-box;margin:0;padding:0}.kv-root{--kv-primary: #6c63ff;--kv-primary-dark: #5a52d5;--kv-primary-light: #8b85ff;--kv-danger: #e74c3c;--kv-danger-dark: #c0392b;--kv-success: #2ecc71;--kv-bg: #0d0d14;--kv-surface: #16161f;--kv-surface2: #1e1e2a;--kv-border: rgba(255, 255, 255, .08);--kv-text: #f0f0f8;--kv-text-muted: #9090b0;--kv-radius: 14px;--kv-shadow: 0 24px 60px rgba(0, 0, 0, .55);--kv-transition: .2s cubic-bezier(.4, 0, .2, 1);font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Helvetica,Arial,sans-serif;font-size:14px;color:var(--kv-text);line-height:1.5}.kv-fab{position:fixed;width:56px;height:56px;border-radius:50%;border:none;cursor:pointer;background:linear-gradient(135deg,var(--kv-primary),#a78bfa);box-shadow:0 4px 20px #6c63ff80;display:flex;align-items:center;justify-content:center;z-index:var(--kv-z, 9999);transition:transform var(--kv-transition),box-shadow var(--kv-transition);outline:none}.kv-fab:hover{transform:scale(1.1) rotate(8deg);box-shadow:0 8px 28px #6c63ffa6}.kv-fab:active{transform:scale(.96)}.kv-fab svg{width:26px;height:26px;fill:none;stroke:#fff;stroke-width:2;stroke-linecap:round;stroke-linejoin:round}.kv-backdrop{position:fixed;top:0;right:0;bottom:0;left:0;background:#000000a6;-webkit-backdrop-filter:blur(4px);backdrop-filter:blur(4px);z-index:calc(var(--kv-z, 9999) + 1);display:flex;align-items:center;justify-content:center;animation:kv-fade-in .2s ease}@keyframes kv-fade-in{0%{opacity:0}to{opacity:1}}.kv-modal{background:var(--kv-surface);border:1px solid var(--kv-border);border-radius:var(--kv-radius);box-shadow:var(--kv-shadow);width:min(420px,96vw);max-height:90vh;overflow:hidden;display:flex;flex-direction:column;animation:kv-slide-up .25s cubic-bezier(.34,1.56,.64,1);position:relative;transition:height .25s cubic-bezier(.4,0,.2,1)}@keyframes kv-slide-up{0%{opacity:0;transform:translateY(24px) scale(.96)}to{opacity:1;transform:translateY(0) scale(1)}}.kv-modal-header{display:flex;align-items:center;gap:10px;padding:20px 24px 16px;border-bottom:1px solid var(--kv-border)}.kv-modal-header svg{width:28px;height:28px;flex-shrink:0}.kv-modal-title{font-size:18px;font-weight:700;background:linear-gradient(90deg,var(--kv-primary-light),#c4b5fd);-webkit-background-clip:text;-webkit-text-fill-color:transparent;background-clip:text}.kv-close-btn{margin-left:auto;background:transparent;border:none;cursor:pointer;color:var(--kv-text-muted);padding:4px;border-radius:6px;display:flex;align-items:center;justify-content:center;transition:color var(--kv-transition),background var(--kv-transition)}.kv-close-btn:hover{color:var(--kv-text);background:var(--kv-border)}.kv-close-btn svg{width:18px;height:18px}.kv-modal-body{padding:24px;flex:1;min-height:0;overflow:hidden;display:flex;flex-direction:column}.kv-list-scroll{overflow-y:auto;min-height:0;flex:1;padding-right:4px}.kv-tabs{display:flex;gap:2px;background:var(--kv-surface2);border-radius:10px;padding:3px;margin-bottom:24px}.kv-forgot-header{display:flex;align-items:center;justify-content:center;background:var(--kv-surface2);border:1px solid var(--kv-border);border-radius:10px;padding:10px 12px;margin-bottom:24px;font-size:13px;font-weight:700;color:#fff}.kv-tab{flex:1;border:none;background:transparent;padding:8px 0;border-radius:8px;font-size:13px;font-weight:600;cursor:pointer;color:var(--kv-text-muted);transition:all var(--kv-transition)}.kv-tab.kv-active{background:var(--kv-primary);color:#fff;box-shadow:0 2px 8px #6c63ff66}.kv-tab:hover:not(.kv-active){color:var(--kv-text)}.kv-form{display:flex;flex-direction:column;gap:16px}.kv-field{display:flex;flex-direction:column;gap:3px}.kv-label{font-size:12px;font-weight:600;color:var(--kv-text-muted);text-transform:uppercase;letter-spacing:.05em}.kv-input{background:var(--kv-surface2);border:1px solid var(--kv-border);border-radius:10px;padding:11px 14px;font-size:14px;color:var(--kv-text);outline:none;transition:border-color var(--kv-transition),box-shadow var(--kv-transition);width:100%}.kv-input::placeholder{color:var(--kv-text-muted);opacity:.6}.kv-input:focus{border-color:var(--kv-primary);box-shadow:0 0 0 3px #6c63ff26}.kv-input.kv-input-error{border-color:#e74c3c99}.kv-input.kv-input-error:focus{border-color:var(--kv-danger);box-shadow:0 0 0 3px #e74c3c26}.kv-field-error{font-size:11px;color:#ff7b6b;margin-top:1px;display:flex;align-items:center;gap:4px;overflow:hidden;animation:kv-error-in .22s cubic-bezier(.34,1.56,.64,1);transform-origin:top left}@keyframes kv-error-in{0%{opacity:0;transform:translateY(-4px) scaleY(.7);max-height:0}to{opacity:1;transform:translateY(0) scaleY(1);max-height:40px}}.kv-remember{display:flex;align-items:center;gap:8px;margin:4px 0 16px;cursor:pointer}.kv-remember input[type=checkbox]{width:14px;height:14px;accent-color:var(--kv-primary);cursor:pointer}.kv-remember label{font-size:13px;color:var(--kv-text-muted);cursor:pointer;-webkit-user-select:none;user-select:none}.kv-remember:hover label{color:var(--kv-text)}.kv-btn{border:none;border-radius:10px;padding:11px 18px;font-size:14px;font-weight:600;cursor:pointer;transition:all var(--kv-transition);display:inline-flex;align-items:center;justify-content:center;gap:8px;outline:none}.kv-btn:disabled{opacity:.55;cursor:not-allowed}.kv-btn-primary{background:linear-gradient(135deg,var(--kv-primary),#a78bfa);color:#fff;width:100%;box-shadow:0 4px 14px #6c63ff59}.kv-btn-primary:hover:not(:disabled){box-shadow:0 6px 20px #6c63ff80;transform:translateY(-1px)}.kv-btn-danger{background:transparent;color:var(--kv-danger);border:1px solid rgba(231,76,60,.3);padding:6px 12px;font-size:12px;border-radius:8px}.kv-btn-danger:hover:not(:disabled){background:var(--kv-danger);color:#fff;border-color:var(--kv-danger)}.kv-btn-ghost{background:transparent;color:var(--kv-text-muted);border:1px solid var(--kv-border)}.kv-btn-ghost:hover:not(:disabled){color:var(--kv-text);background:var(--kv-surface2)}.kv-alert{border-radius:8px;padding:10px 14px;font-size:13px;font-weight:500}.kv-alert-error{background:#e74c3c1f;border:1px solid rgba(231,76,60,.3);color:#ff7b6b}.kv-alert-success{background:#2ecc711f;border:1px solid rgba(46,204,113,.3);color:#5effa1}.kv-spinner{width:16px;height:16px;border:2px solid rgba(255,255,255,.3);border-top-color:#fff;border-radius:50%;animation:kv-spin .6s linear infinite;flex-shrink:0}@keyframes kv-spin{to{transform:rotate(360deg)}}.kv-dash-meta{display:flex;align-items:center;justify-content:space-between;margin-bottom:20px}.kv-badge{background:#6c63ff26;color:var(--kv-primary-light);border:1px solid rgba(108,99,255,.25);border-radius:20px;padding:3px 10px;font-size:12px;font-weight:600}.kv-section-title{font-size:12px;font-weight:700;color:var(--kv-text-muted);text-transform:uppercase;letter-spacing:.07em;margin-bottom:10px}.kv-key-list{display:flex;flex-direction:column;gap:8px;margin-bottom:20px}.kv-key-item{display:flex;align-items:center;background:var(--kv-surface2);border:1px solid var(--kv-border);border-radius:10px;padding:12px 14px;gap:12px;transition:border-color var(--kv-transition)}.kv-key-item:hover{border-color:#6c63ff4d}.kv-key-icon{width:32px;height:32px;border-radius:8px;background:linear-gradient(135deg,var(--kv-primary),#a78bfa);display:flex;align-items:center;justify-content:center;flex-shrink:0}.kv-key-icon svg{width:16px;height:16px;stroke:#fff;fill:none;stroke-width:2;stroke-linecap:round;stroke-linejoin:round}.kv-key-info{flex:1;min-width:0}.kv-key-service{font-weight:600;font-size:14px;color:var(--kv-text);text-transform:capitalize}.kv-key-id{font-size:11px;color:var(--kv-text-muted);margin-top:2px}.kv-empty-state{text-align:center;padding:28px 0;color:var(--kv-text-muted);font-size:13px}.kv-skeleton{position:relative;overflow:hidden;background:#ffffff0a;border:1px solid var(--kv-border);border-radius:10px}.kv-skeleton:after{content:"";position:absolute;top:0;right:0;bottom:0;left:0;transform:translate(-100%);background:linear-gradient(90deg,transparent,rgba(255,255,255,.08),transparent);animation:kv-shimmer 1.1s ease-in-out infinite}@keyframes kv-shimmer{to{transform:translate(100%)}}.kv-skel-row{height:54px}.kv-skel-line{height:10px;border-radius:999px;background:#ffffff0f}.kv-empty-state svg{width:40px;height:40px;stroke:var(--kv-text-muted);fill:none;stroke-width:1.5;margin-bottom:10px;opacity:.5}.kv-add-section{border-top:1px solid var(--kv-border);padding-top:20px}.kv-add-section .kv-form{gap:12px}.kv-add-row{display:flex;gap:8px}.kv-add-row .kv-btn{flex-shrink:0;padding:11px 16px}.kv-divider{border:none;border-top:1px solid var(--kv-border);margin:20px 0}.kv-modal::-webkit-scrollbar{width:5px}.kv-modal::-webkit-scrollbar-track{background:transparent}.kv-modal::-webkit-scrollbar-thumb{background:var(--kv-border);border-radius:10px}.kv-verify-banner{background:#2ecc711a;border:1px solid rgba(46,204,113,.25);border-radius:10px;padding:12px 14px;font-size:13px;color:#5effa1;text-align:center;line-height:1.6}';function Je(o,r,a){switch(o){case"bottom-right":return{bottom:a,right:r};case"bottom-left":return{bottom:a,left:r};case"top-right":return{top:a,right:r};case"top-left":return{top:a,left:r};case"center":return{top:"50%",left:"50%",transform:"translate(-50%, -50%)"}}}const We=()=>e.jsxs("svg",{viewBox:"0 0 24 24",fill:"none",stroke:"#fff",strokeWidth:2,strokeLinecap:"round",strokeLinejoin:"round",width:26,height:26,children:[e.jsx("rect",{x:3,y:3,width:18,height:18,rx:3,ry:3}),e.jsx("circle",{cx:12,cy:12,r:4}),e.jsx("circle",{cx:12,cy:12,r:1.5}),e.jsx("line",{x1:12,y1:8,x2:12,y2:6}),e.jsx("line",{x1:12,y1:18,x2:12,y2:16}),e.jsx("line",{x1:8,y1:12,x2:6,y2:12}),e.jsx("line",{x1:18,y1:12,x2:16,y2:12})]}),Ge=()=>e.jsx("svg",{viewBox:"0 0 24 24",width:18,height:18,fill:"none",stroke:"currentColor",strokeWidth:2,strokeLinecap:"round",children:e.jsx("path",{d:"M18 6L6 18M6 6l12 12"})}),Ze=({position:o,offsetX:r,offsetY:a,zIndex:m})=>{const[i,l]=s.useState(()=>typeof window<"u"?new URLSearchParams(window.location.search).has("token"):!1),[p,u]=s.useState(()=>ke());s.useEffect(()=>{i&&u(ke())},[i]);const S=Je(o,r,a),b=()=>{u(ke()),l(!0)},K=()=>l(!1),P=()=>u(!0),A=()=>{u(!1),l(!1)};return e.jsxs("div",{className:"kv-root",style:{"--kv-z":m},children:[e.jsx("button",{className:"kv-fab",style:S,onClick:b,"aria-label":"Open Key Vault",title:"Key Vault",children:e.jsx(We,{})}),i&&e.jsx("div",{className:"kv-backdrop",onClick:T=>{T.target===T.currentTarget&&K()},children:e.jsxs("div",{className:"kv-modal",role:"dialog","aria-modal":!0,"aria-label":"Key Vault",children:[e.jsxs("div",{className:"kv-modal-header",children:[e.jsxs("svg",{width:28,height:28,viewBox:"0 0 24 24",fill:"none",strokeWidth:2,strokeLinecap:"round",strokeLinejoin:"round",children:[e.jsx("defs",{children:e.jsxs("linearGradient",{id:"kv-grad",x1:"0",y1:"0",x2:"1",y2:"1",children:[e.jsx("stop",{offset:"0%",stopColor:"#8b85ff"}),e.jsx("stop",{offset:"100%",stopColor:"#c4b5fd"})]})}),e.jsx("rect",{x:3,y:3,width:18,height:18,rx:3,stroke:"url(#kv-grad)"}),e.jsx("circle",{cx:12,cy:12,r:4,stroke:"url(#kv-grad)"}),e.jsx("circle",{cx:12,cy:12,r:1.5,stroke:"url(#kv-grad)"})]}),e.jsx("span",{className:"kv-modal-title",children:"Key Vault"}),e.jsx("button",{className:"kv-close-btn",onClick:K,"aria-label":"Close",children:e.jsx(Ge,{})})]}),e.jsx("div",{className:"kv-modal-body",children:p?e.jsx(Ue,{onLogout:A}):e.jsx(Ve,{onLoginSuccess:P})})]})})]})};let xe=!1;function Qe(o={}){if(xe){console.warn("[keyvault-widget] Already initialized.");return}xe=!0;const{position:r="bottom-right",offsetX:a="20px",offsetY:m="20px",zIndex:i=9999}=o,l=document.createElement("div");l.id="kv-widget-host",document.body.appendChild(l);const p=l.attachShadow({mode:"open"}),u=document.createElement("style");u.textContent=He,p.appendChild(u);const S=document.createElement("div");p.appendChild(S),ze.createRoot(S).render(e.jsx(s.StrictMode,{children:e.jsx(Ze,{position:r,offsetX:a,offsetY:m,zIndex:i})}))}function Xe(){const o=document.getElementById("kv-widget-host");o&&o.remove(),xe=!1}exports.destroyKeyVault=Xe;exports.initKeyVault=Qe;
|
|
2
|
+
//# sourceMappingURL=mm-key-vault.cjs.js.map
|