@openkey/sdk 0.8.4 → 0.9.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 +19 -1
- package/dist/index.d.ts +19 -1
- package/dist/index.js +51 -23
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +51 -23
- package/dist/index.mjs.map +1 -1
- package/package.json +3 -3
package/dist/index.d.mts
CHANGED
|
@@ -98,6 +98,21 @@ declare class OpenKey {
|
|
|
98
98
|
connect(opts?: {
|
|
99
99
|
mode?: OpenKeyMode;
|
|
100
100
|
}): Promise<AuthResult>;
|
|
101
|
+
/**
|
|
102
|
+
* Better-auth session token relayed during connect(), or null if the
|
|
103
|
+
* flow did not provide one. Use as a bearer token for API calls made
|
|
104
|
+
* on the user's behalf (e.g. TinyCloud auto-sign bootstrap signing).
|
|
105
|
+
*/
|
|
106
|
+
getSessionToken(): string | null;
|
|
107
|
+
/**
|
|
108
|
+
* Endpoint + bearer token for a TinyCloud auto-sign signing strategy.
|
|
109
|
+
* The endpoint is on the OpenKey API host and only signs requests the
|
|
110
|
+
* server-side bootstrap allowlist permits.
|
|
111
|
+
*/
|
|
112
|
+
tinycloudSigningOptions(): {
|
|
113
|
+
endpoint: string;
|
|
114
|
+
token: string | null;
|
|
115
|
+
};
|
|
101
116
|
/**
|
|
102
117
|
* Link an external wallet to the user's OpenKey account
|
|
103
118
|
* Opens link-wallet widget flow
|
|
@@ -122,9 +137,12 @@ declare class OpenKey {
|
|
|
122
137
|
signTypedData(request: SignTypedDataRequest, opts?: {
|
|
123
138
|
mode?: OpenKeyMode;
|
|
124
139
|
}): Promise<SignResult>;
|
|
140
|
+
private providerCandidates;
|
|
141
|
+
private providerHasAccount;
|
|
125
142
|
/**
|
|
126
143
|
* Find a wallet provider that controls the given address.
|
|
127
|
-
* Checks
|
|
144
|
+
* Checks connected accounts first, then asks the wallet to authorize the
|
|
145
|
+
* app origin if the external key was linked elsewhere.
|
|
128
146
|
*/
|
|
129
147
|
findWalletProvider(targetAddress: string): Promise<EIP1193Provider>;
|
|
130
148
|
private signWithExternalWallet;
|
package/dist/index.d.ts
CHANGED
|
@@ -98,6 +98,21 @@ declare class OpenKey {
|
|
|
98
98
|
connect(opts?: {
|
|
99
99
|
mode?: OpenKeyMode;
|
|
100
100
|
}): Promise<AuthResult>;
|
|
101
|
+
/**
|
|
102
|
+
* Better-auth session token relayed during connect(), or null if the
|
|
103
|
+
* flow did not provide one. Use as a bearer token for API calls made
|
|
104
|
+
* on the user's behalf (e.g. TinyCloud auto-sign bootstrap signing).
|
|
105
|
+
*/
|
|
106
|
+
getSessionToken(): string | null;
|
|
107
|
+
/**
|
|
108
|
+
* Endpoint + bearer token for a TinyCloud auto-sign signing strategy.
|
|
109
|
+
* The endpoint is on the OpenKey API host and only signs requests the
|
|
110
|
+
* server-side bootstrap allowlist permits.
|
|
111
|
+
*/
|
|
112
|
+
tinycloudSigningOptions(): {
|
|
113
|
+
endpoint: string;
|
|
114
|
+
token: string | null;
|
|
115
|
+
};
|
|
101
116
|
/**
|
|
102
117
|
* Link an external wallet to the user's OpenKey account
|
|
103
118
|
* Opens link-wallet widget flow
|
|
@@ -122,9 +137,12 @@ declare class OpenKey {
|
|
|
122
137
|
signTypedData(request: SignTypedDataRequest, opts?: {
|
|
123
138
|
mode?: OpenKeyMode;
|
|
124
139
|
}): Promise<SignResult>;
|
|
140
|
+
private providerCandidates;
|
|
141
|
+
private providerHasAccount;
|
|
125
142
|
/**
|
|
126
143
|
* Find a wallet provider that controls the given address.
|
|
127
|
-
* Checks
|
|
144
|
+
* Checks connected accounts first, then asks the wallet to authorize the
|
|
145
|
+
* app origin if the external key was linked elsewhere.
|
|
128
146
|
*/
|
|
129
147
|
findWalletProvider(targetAddress: string): Promise<EIP1193Provider>;
|
|
130
148
|
private signWithExternalWallet;
|
package/dist/index.js
CHANGED
|
@@ -51,7 +51,7 @@ var IframeModal = class {
|
|
|
51
51
|
const style = document.createElement("style");
|
|
52
52
|
style.textContent = `
|
|
53
53
|
:host{all:initial}
|
|
54
|
-
.ok-backdrop{position:fixed;inset:0;background:rgba(0,0,0,0.
|
|
54
|
+
.ok-backdrop{position:fixed;inset:0;background:rgba(0,0,0,0.42);z-index:999999;display:flex;align-items:${isMobile ? "flex-end" : "center"};justify-content:center;animation:ok-fade-in 150ms ease-out}
|
|
55
55
|
.ok-card{position:relative;background:#fafafa;width:${isMobile ? "100%" : "400px"};border-radius:${isMobile ? "16px 16px 0 0" : "16px"};box-shadow:0 25px 50px -12px rgba(0,0,0,0.25);overflow:hidden;overflow-y:auto;animation:${isMobile ? "ok-slide-up 250ms ease-out" : "ok-scale-in 200ms ease-out"};max-height:90vh}
|
|
56
56
|
.ok-close{position:absolute;top:8px;right:8px;width:24px;height:24px;border:none;background:transparent;color:#6b7280;font-size:18px;cursor:pointer;z-index:1;display:flex;align-items:center;justify-content:center;border-radius:4px}
|
|
57
57
|
.ok-close:hover{color:#111827}
|
|
@@ -85,8 +85,8 @@ var IframeModal = class {
|
|
|
85
85
|
card.appendChild(closeBtn);
|
|
86
86
|
this.iframe = document.createElement("iframe");
|
|
87
87
|
this.iframe.src = opts.url;
|
|
88
|
-
this.iframe.setAttribute("allow", "publickey-credentials-get *; publickey-credentials-create *");
|
|
89
|
-
this.iframe.setAttribute("sandbox", "allow-scripts allow-same-origin allow-forms allow-popups");
|
|
88
|
+
this.iframe.setAttribute("allow", "clipboard-write *; publickey-credentials-get *; publickey-credentials-create *");
|
|
89
|
+
this.iframe.setAttribute("sandbox", "allow-scripts allow-same-origin allow-forms allow-popups allow-popups-to-escape-sandbox");
|
|
90
90
|
card.appendChild(this.iframe);
|
|
91
91
|
backdrop.appendChild(card);
|
|
92
92
|
this.shadow.appendChild(style);
|
|
@@ -135,7 +135,7 @@ var WalletPicker = class {
|
|
|
135
135
|
const style = document.createElement("style");
|
|
136
136
|
style.textContent = `
|
|
137
137
|
:host{all:initial}
|
|
138
|
-
.wp-backdrop{position:fixed;inset:0;background:rgba(0,0,0,0.
|
|
138
|
+
.wp-backdrop{position:fixed;inset:0;background:rgba(0,0,0,0.42);z-index:1000000;display:flex;align-items:center;justify-content:center;animation:wp-fade 150ms ease-out}
|
|
139
139
|
.wp-card{background:#fff;width:340px;border-radius:16px;box-shadow:0 25px 50px -12px rgba(0,0,0,0.25);padding:20px;animation:wp-scale 200ms ease-out}
|
|
140
140
|
.wp-title{font:600 16px/1.3 system-ui,sans-serif;color:#111;margin:0 0 12px}
|
|
141
141
|
.wp-list{list-style:none;margin:0;padding:0;display:flex;flex-direction:column;gap:6px}
|
|
@@ -284,6 +284,25 @@ var OpenKey = class {
|
|
|
284
284
|
this.lastAuth = result;
|
|
285
285
|
return result;
|
|
286
286
|
}
|
|
287
|
+
/**
|
|
288
|
+
* Better-auth session token relayed during connect(), or null if the
|
|
289
|
+
* flow did not provide one. Use as a bearer token for API calls made
|
|
290
|
+
* on the user's behalf (e.g. TinyCloud auto-sign bootstrap signing).
|
|
291
|
+
*/
|
|
292
|
+
getSessionToken() {
|
|
293
|
+
return this.sessionToken;
|
|
294
|
+
}
|
|
295
|
+
/**
|
|
296
|
+
* Endpoint + bearer token for a TinyCloud auto-sign signing strategy.
|
|
297
|
+
* The endpoint is on the OpenKey API host and only signs requests the
|
|
298
|
+
* server-side bootstrap allowlist permits.
|
|
299
|
+
*/
|
|
300
|
+
tinycloudSigningOptions() {
|
|
301
|
+
return {
|
|
302
|
+
endpoint: `${this.oauthHost}/api/delegate/sign`,
|
|
303
|
+
token: this.sessionToken
|
|
304
|
+
};
|
|
305
|
+
}
|
|
287
306
|
/**
|
|
288
307
|
* Link an external wallet to the user's OpenKey account
|
|
289
308
|
* Opens link-wallet widget flow
|
|
@@ -313,31 +332,40 @@ var OpenKey = class {
|
|
|
313
332
|
}
|
|
314
333
|
return this.signTypedDataWithOpenKey(request, opts?.mode);
|
|
315
334
|
}
|
|
335
|
+
providerCandidates() {
|
|
336
|
+
const providers = [];
|
|
337
|
+
if (this.config.externalProvider) {
|
|
338
|
+
providers.push(this.config.externalProvider);
|
|
339
|
+
}
|
|
340
|
+
providers.push(...this.discoveredProviders.map(({ provider }) => provider));
|
|
341
|
+
if (typeof window !== "undefined" && window.ethereum) {
|
|
342
|
+
providers.push(window.ethereum);
|
|
343
|
+
}
|
|
344
|
+
return [...new Set(providers)];
|
|
345
|
+
}
|
|
346
|
+
async providerHasAccount(provider, method, targetAddress) {
|
|
347
|
+
try {
|
|
348
|
+
const accounts = await provider.request({ method });
|
|
349
|
+
return accounts.some((account) => account.toLowerCase() === targetAddress.toLowerCase());
|
|
350
|
+
} catch {
|
|
351
|
+
return false;
|
|
352
|
+
}
|
|
353
|
+
}
|
|
316
354
|
/**
|
|
317
355
|
* Find a wallet provider that controls the given address.
|
|
318
|
-
* Checks
|
|
356
|
+
* Checks connected accounts first, then asks the wallet to authorize the
|
|
357
|
+
* app origin if the external key was linked elsewhere.
|
|
319
358
|
*/
|
|
320
359
|
async findWalletProvider(targetAddress) {
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
try {
|
|
326
|
-
const accounts = await provider.request({ method: "eth_accounts" });
|
|
327
|
-
if (accounts.some((a) => a.toLowerCase() === targetAddress.toLowerCase())) {
|
|
328
|
-
return provider;
|
|
329
|
-
}
|
|
330
|
-
} catch {
|
|
360
|
+
const providers = this.providerCandidates();
|
|
361
|
+
for (const provider of providers) {
|
|
362
|
+
if (await this.providerHasAccount(provider, "eth_accounts", targetAddress)) {
|
|
363
|
+
return provider;
|
|
331
364
|
}
|
|
332
365
|
}
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
const accounts = await provider.request({ method: "eth_accounts" });
|
|
337
|
-
if (accounts.some((a) => a.toLowerCase() === targetAddress.toLowerCase())) {
|
|
338
|
-
return provider;
|
|
339
|
-
}
|
|
340
|
-
} catch {
|
|
366
|
+
for (const provider of providers) {
|
|
367
|
+
if (await this.providerHasAccount(provider, "eth_requestAccounts", targetAddress)) {
|
|
368
|
+
return provider;
|
|
341
369
|
}
|
|
342
370
|
}
|
|
343
371
|
throw new ExternalWalletError("External wallet not found. Connect the wallet that owns this key and try again.");
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts"],"sourcesContent":["// OpenKey SDK - Browser client for third-party apps\n// Provides \"Sign with OpenKey\" functionality via popup or iframe\n\nimport {\n generateCodeVerifier,\n generateCodeChallenge,\n generateState,\n buildAuthorizationUrl,\n} from '@openkey/core';\n\nexport interface EIP1193Provider {\n request(args: { method: string; params?: any[] }): Promise<any>;\n}\n\ninterface EIP6963ProviderInfo {\n uuid: string;\n name: string;\n icon: string;\n rdns: string;\n}\n\ninterface EIP6963ProviderDetail {\n info: EIP6963ProviderInfo;\n provider: EIP1193Provider;\n}\n\nexport type OpenKeyMode = 'iframe' | 'popup' | 'redirect';\n\nexport interface OpenKeyConfig {\n /** OpenKey host URL (default: https://openkey.so) */\n host?: string;\n /** OAuth API host URL (default: derived from host by prefixing 'api.') */\n oauthHost?: string;\n /** App identifier for display */\n appName?: string;\n /** UI mode: 'iframe' (default), 'popup', or 'redirect' */\n mode?: OpenKeyMode;\n /** App-provided wallet provider for external key signing */\n externalProvider?: EIP1193Provider;\n}\n\nexport interface SignMessageRequest {\n message: string;\n keyId?: string; // If not provided, user selects\n}\n\nexport interface SignTypedDataRequest {\n domain: {\n name?: string;\n version?: string;\n chainId?: number;\n verifyingContract?: string;\n };\n types: Record<string, Array<{ name: string; type: string }>>;\n primaryType: string;\n message: Record<string, unknown>;\n keyId?: string;\n}\n\nexport interface SignResult {\n signature: string;\n address: string;\n}\n\nexport interface AuthResult {\n address: string;\n keyId: string;\n keyType: 'MANAGED' | 'EXTERNAL';\n}\n\nexport interface OpenKeyError {\n code: 'USER_CANCELLED' | 'POPUP_BLOCKED' | 'TIMEOUT' | 'NO_KEY' | 'UNAUTHORIZED' | 'UNKNOWN' | 'STATE_MISMATCH';\n message: string;\n}\n\n// ======= OAuth 2.1 Types =======\n\n/** OAuth configuration for third-party apps */\nexport interface OAuthConfig {\n /** OAuth client_id (registered with OpenKey) */\n clientId: string;\n /** Redirect URI (must match registered URI) */\n redirectUri: string;\n /** State parameter for CSRF protection (auto-generated if not provided) */\n state?: string;\n}\n\n/** Result from OAuth authorization */\nexport interface OAuthResult {\n /** Authorization code (exchange for tokens) */\n code: string;\n /** State parameter (verify matches request) */\n state: string;\n}\n\n/** Response from token exchange */\nexport interface OAuthTokenResponse {\n access_token: string;\n token_type: 'Bearer';\n expires_in: number;\n id_token: string;\n scope: string;\n refresh_token?: string;\n}\n\ntype MessageType =\n | { type: 'openkey:auth:request'; appName: string }\n | { type: 'openkey:auth:response'; success: true; address: string; keyId: string; keyType?: 'MANAGED' | 'EXTERNAL'; sessionToken?: string }\n | { type: 'openkey:auth:response'; success: false; error: OpenKeyError }\n | { type: 'openkey:sign:request'; message: string; keyId?: string; sessionToken?: string }\n | { type: 'openkey:sign:response'; success: true; signature: string; address: string }\n | { type: 'openkey:sign:response'; success: false; error: OpenKeyError }\n | { type: 'openkey:signTypedData:request'; data: SignTypedDataRequest; sessionToken?: string }\n | { type: 'openkey:signTypedData:response'; success: true; signature: string; address: string }\n | { type: 'openkey:signTypedData:response'; success: false; error: OpenKeyError }\n | { type: 'openkey:link-wallet:request' }\n | { type: 'openkey:link-wallet:response'; success: true; address: string; keyId: string }\n | { type: 'openkey:link-wallet:response'; success: false; error: OpenKeyError }\n | { type: 'openkey:link-wallet:delegate' }\n | { type: 'openkey:link-wallet:result'; success: true; address: string; keyId: string }\n | { type: 'openkey:link-wallet:result'; success: false; error: OpenKeyError }\n | { type: 'openkey:auth:use-external-wallet' }\n | { type: 'openkey:resize'; height: number }\n | { type: 'openkey:ready' }\n | { type: 'openkey:close' };\n\nconst DEFAULT_HOST = 'https://openkey.so';\nconst POPUP_WIDTH = 400;\nconst POPUP_HEIGHT = 600;\nconst DEFAULT_TIMEOUT = 5 * 60 * 1000; // 5 minutes\nconst IFRAME_READY_TIMEOUT = 3000; // 3 seconds\nconst OAUTH_STORAGE_KEY = 'openkey_oauth';\n\nclass IframeModal {\n private root: HTMLDivElement;\n private shadow: ShadowRoot;\n private iframe: HTMLIFrameElement;\n private onClose: () => void;\n private onMessage: (data: MessageType) => void;\n private messageHandler: (event: MessageEvent) => void;\n private host: string;\n\n constructor(opts: { url: string; host: string; onClose: () => void; onMessage: (data: MessageType) => void }) {\n this.host = opts.host;\n this.onClose = opts.onClose;\n this.onMessage = opts.onMessage;\n\n const isMobile = window.matchMedia('(max-width: 639px)').matches;\n\n this.root = document.createElement('div');\n this.shadow = this.root.attachShadow({ mode: 'closed' });\n\n const style = document.createElement('style');\n style.textContent = `\n :host{all:initial}\n .ok-backdrop{position:fixed;inset:0;background:rgba(0,0,0,0.4);backdrop-filter:blur(4px);z-index:999999;display:flex;align-items:${isMobile ? 'flex-end' : 'center'};justify-content:center;animation:ok-fade-in 150ms ease-out}\n .ok-card{position:relative;background:#fafafa;width:${isMobile ? '100%' : '400px'};border-radius:${isMobile ? '16px 16px 0 0' : '16px'};box-shadow:0 25px 50px -12px rgba(0,0,0,0.25);overflow:hidden;overflow-y:auto;animation:${isMobile ? 'ok-slide-up 250ms ease-out' : 'ok-scale-in 200ms ease-out'};max-height:90vh}\n .ok-close{position:absolute;top:8px;right:8px;width:24px;height:24px;border:none;background:transparent;color:#6b7280;font-size:18px;cursor:pointer;z-index:1;display:flex;align-items:center;justify-content:center;border-radius:4px}\n .ok-close:hover{color:#111827}\n .ok-handle{width:40px;height:4px;background:#d4d4d4;border-radius:2px;margin:8px auto 0}\n iframe{border:none;width:100%;height:400px;display:block;transition:height 200ms ease}\n .ok-backdrop.ok-exit{animation:ok-fade-out 150ms ease-in}\n .ok-backdrop.ok-exit .ok-card{animation:${isMobile ? 'ok-slide-down 200ms ease-in' : 'ok-scale-out 150ms ease-in'}}\n @keyframes ok-fade-in{from{opacity:0}to{opacity:1}}\n @keyframes ok-fade-out{from{opacity:1}to{opacity:0}}\n @keyframes ok-scale-in{from{opacity:0;transform:scale(0.95)}to{opacity:1;transform:scale(1)}}\n @keyframes ok-scale-out{from{opacity:1;transform:scale(1)}to{opacity:0;transform:scale(0.95)}}\n @keyframes ok-slide-up{from{transform:translateY(100%)}to{transform:translateY(0)}}\n @keyframes ok-slide-down{from{transform:translateY(0)}to{transform:translateY(100%)}}\n `;\n\n const backdrop = document.createElement('div');\n backdrop.className = 'ok-backdrop';\n backdrop.addEventListener('click', (e) => {\n if (e.target === backdrop) this.close();\n });\n\n const card = document.createElement('div');\n card.className = 'ok-card';\n\n if (isMobile) {\n const handle = document.createElement('div');\n handle.className = 'ok-handle';\n card.appendChild(handle);\n }\n\n const closeBtn = document.createElement('button');\n closeBtn.className = 'ok-close';\n closeBtn.textContent = '\\u00d7';\n closeBtn.addEventListener('click', () => this.close());\n card.appendChild(closeBtn);\n\n this.iframe = document.createElement('iframe');\n this.iframe.src = opts.url;\n this.iframe.setAttribute('allow', 'publickey-credentials-get *; publickey-credentials-create *');\n this.iframe.setAttribute('sandbox', 'allow-scripts allow-same-origin allow-forms allow-popups');\n card.appendChild(this.iframe);\n\n backdrop.appendChild(card);\n this.shadow.appendChild(style);\n this.shadow.appendChild(backdrop);\n\n this.messageHandler = (event: MessageEvent) => {\n if (event.origin !== this.host) return;\n if (event.source !== this.iframe.contentWindow) return;\n const data = event.data as MessageType;\n if (data.type === 'openkey:resize') {\n const h = Math.min(data.height, Math.floor(window.innerHeight * 0.85));\n this.iframe.style.height = `${h}px`;\n return;\n }\n this.onMessage(data);\n };\n window.addEventListener('message', this.messageHandler);\n document.body.appendChild(this.root);\n }\n\n postMessage(message: object) {\n this.iframe.contentWindow?.postMessage(message, this.host);\n }\n\n destroy() {\n window.removeEventListener('message', this.messageHandler);\n this.root.remove();\n }\n\n private close() {\n const backdrop = this.shadow.querySelector('.ok-backdrop');\n if (backdrop) {\n backdrop.classList.add('ok-exit');\n setTimeout(() => {\n this.destroy();\n this.onClose();\n }, 200);\n } else {\n this.destroy();\n this.onClose();\n }\n }\n}\n\nclass WalletPicker {\n private root: HTMLDivElement;\n private shadow: ShadowRoot;\n\n constructor(opts: { providers: EIP6963ProviderDetail[]; onSelect: (provider: EIP1193Provider) => void; onCancel: () => void }) {\n this.root = document.createElement('div');\n this.shadow = this.root.attachShadow({ mode: 'closed' });\n\n const style = document.createElement('style');\n style.textContent = `\n :host{all:initial}\n .wp-backdrop{position:fixed;inset:0;background:rgba(0,0,0,0.4);backdrop-filter:blur(4px);z-index:1000000;display:flex;align-items:center;justify-content:center;animation:wp-fade 150ms ease-out}\n .wp-card{background:#fff;width:340px;border-radius:16px;box-shadow:0 25px 50px -12px rgba(0,0,0,0.25);padding:20px;animation:wp-scale 200ms ease-out}\n .wp-title{font:600 16px/1.3 system-ui,sans-serif;color:#111;margin:0 0 12px}\n .wp-list{list-style:none;margin:0;padding:0;display:flex;flex-direction:column;gap:6px}\n .wp-item{display:flex;align-items:center;gap:10px;padding:10px 12px;border:1px solid #e5e7eb;border-radius:10px;background:transparent;cursor:pointer;font:14px/1.3 system-ui,sans-serif;color:#111;width:100%;text-align:left;transition:border-color 150ms}\n .wp-item:hover{border-color:#6366f1}\n .wp-icon{width:28px;height:28px;border-radius:6px}\n .wp-empty{font:14px/1.4 system-ui,sans-serif;color:#6b7280;text-align:center;padding:16px 0}\n .wp-cancel{display:block;width:100%;margin-top:12px;padding:8px;border:none;background:transparent;color:#6b7280;font:14px/1.3 system-ui,sans-serif;cursor:pointer;border-radius:8px}\n .wp-cancel:hover{background:#f3f4f6;color:#111}\n @keyframes wp-fade{from{opacity:0}to{opacity:1}}\n @keyframes wp-scale{from{opacity:0;transform:scale(0.95)}to{opacity:1;transform:scale(1)}}\n @media(prefers-color-scheme:dark){\n .wp-card{background:#1a1a1a;box-shadow:0 25px 50px -12px rgba(0,0,0,0.5)}\n .wp-title{color:#f3f4f6}\n .wp-item{border-color:#374151;color:#f3f4f6}\n .wp-item:hover{border-color:#818cf8}\n .wp-empty{color:#9ca3af}\n .wp-cancel{color:#9ca3af}\n .wp-cancel:hover{background:#262626;color:#f3f4f6}\n }\n `;\n\n const backdrop = document.createElement('div');\n backdrop.className = 'wp-backdrop';\n backdrop.addEventListener('click', (e) => { if (e.target === backdrop) { this.destroy(); opts.onCancel(); } });\n\n const card = document.createElement('div');\n card.className = 'wp-card';\n\n const title = document.createElement('h2');\n title.className = 'wp-title';\n title.textContent = 'Select a wallet';\n card.appendChild(title);\n\n if (opts.providers.length === 0) {\n const empty = document.createElement('div');\n empty.className = 'wp-empty';\n empty.textContent = 'No wallets detected';\n card.appendChild(empty);\n } else {\n const list = document.createElement('ul');\n list.className = 'wp-list';\n for (const { info, provider } of opts.providers) {\n const item = document.createElement('button');\n item.className = 'wp-item';\n if (info.icon) {\n const icon = document.createElement('img');\n icon.className = 'wp-icon';\n icon.src = info.icon;\n icon.alt = info.name;\n item.appendChild(icon);\n }\n const name = document.createElement('span');\n name.textContent = info.name;\n item.appendChild(name);\n item.addEventListener('click', () => { this.destroy(); opts.onSelect(provider); });\n list.appendChild(item);\n }\n card.appendChild(list);\n }\n\n const cancel = document.createElement('button');\n cancel.className = 'wp-cancel';\n cancel.textContent = 'Cancel';\n cancel.addEventListener('click', () => { this.destroy(); opts.onCancel(); });\n card.appendChild(cancel);\n\n backdrop.appendChild(card);\n this.shadow.appendChild(style);\n this.shadow.appendChild(backdrop);\n document.body.appendChild(this.root);\n }\n\n destroy() {\n this.root.remove();\n }\n}\n\nfunction showToast(message = 'Opening in new window\\u2026', variant: 'info' | 'error' = 'info') {\n const bg = variant === 'error' ? '#dc2626' : '#1f2937';\n const root = document.createElement('div');\n const shadow = root.attachShadow({ mode: 'closed' });\n shadow.innerHTML = `<style>:host{all:initial}.ok-toast{position:fixed;top:16px;right:16px;z-index:1000000;background:${bg};color:#f9fafb;padding:10px 16px;border-radius:8px;font:14px/1.4 system-ui,sans-serif;box-shadow:0 4px 12px rgba(0,0,0,0.15);animation:ok-t-in 200ms ease-out;max-width:360px}@keyframes ok-t-in{from{opacity:0;transform:translateY(-8px)}to{opacity:1;transform:translateY(0)}}</style><div class=\"ok-toast\">${message}</div>`;\n document.body.appendChild(root);\n setTimeout(() => root.remove(), 4000);\n}\n\nclass ExternalWalletError extends Error {\n constructor(message: string) {\n super(message);\n this.name = 'ExternalWalletError';\n }\n}\n\nexport class OpenKey {\n private host: string;\n private oauthHost: string;\n private appName: string;\n private mode: OpenKeyMode;\n private config: OpenKeyConfig;\n private popup: Window | null = null;\n private lastAuth: AuthResult | null = null;\n private discoveredProviders: EIP6963ProviderDetail[] = [];\n private sessionToken: string | null = null;\n\n constructor(config: OpenKeyConfig = {}) {\n this.config = config;\n this.host = config.host || DEFAULT_HOST;\n this.oauthHost = config.oauthHost || this.deriveOAuthHost(this.host);\n this.appName = config.appName || window.location.hostname;\n this.mode = config.mode ?? 'iframe';\n\n // Listen for EIP-6963 wallet announcements\n if (typeof window !== 'undefined') {\n this.discoveredProviders = [];\n window.addEventListener('eip6963:announceProvider', (event: any) => {\n this.discoveredProviders.push(event.detail);\n });\n window.dispatchEvent(new Event('eip6963:requestProvider'));\n }\n }\n\n /**\n * Derive the OAuth API host from the main host by prefixing 'api.'\n * @param host - The main host URL\n * @returns The derived OAuth API host URL\n */\n private deriveOAuthHost(host: string): string {\n try {\n const url = new URL(host);\n if (url.hostname === 'localhost' || url.hostname === '127.0.0.1') {\n return host.replace(/\\/$/, '');\n }\n url.hostname = 'api.' + url.hostname;\n return url.toString().replace(/\\/$/, '');\n } catch {\n return 'https://api.openkey.so';\n }\n }\n\n /**\n * Connect to OpenKey and get user's wallet address\n * Opens auth flow for user to select/create a key\n */\n async connect(opts?: { mode?: OpenKeyMode }): Promise<AuthResult> {\n const result = await this.openFlow<AuthResult>('connect', {\n type: 'openkey:auth:request',\n appName: this.appName,\n }, opts?.mode);\n this.lastAuth = result;\n return result;\n }\n\n /**\n * Link an external wallet to the user's OpenKey account\n * Opens link-wallet widget flow\n */\n async linkWallet(opts?: { mode?: OpenKeyMode }): Promise<{ address: string; keyId: string }> {\n return this.openFlow<{ address: string; keyId: string }>('link-wallet', {\n type: 'openkey:link-wallet:request',\n }, opts?.mode);\n }\n\n /**\n * Sign a message with the user's OpenKey wallet\n * For external keys, routes directly to the user's wallet provider\n */\n async signMessage(request: SignMessageRequest, opts?: { mode?: OpenKeyMode }): Promise<SignResult> {\n if (this.lastAuth?.keyType === 'EXTERNAL') {\n return this.signWithExternalWallet(request);\n }\n return this.signWithOpenKey(request, opts?.mode);\n }\n\n /**\n * Sign typed data (EIP-712) with the user's OpenKey wallet\n * For external keys, routes directly to the user's wallet provider\n */\n async signTypedData(request: SignTypedDataRequest, opts?: { mode?: OpenKeyMode }): Promise<SignResult> {\n if (this.lastAuth?.keyType === 'EXTERNAL') {\n return this.signTypedDataWithExternalWallet(request);\n }\n return this.signTypedDataWithOpenKey(request, opts?.mode);\n }\n\n /**\n * Find a wallet provider that controls the given address.\n * Checks: 1) app-provided externalProvider, 2) EIP-6963 discovered wallets, 3) window.ethereum\n */\n async findWalletProvider(targetAddress: string): Promise<EIP1193Provider> {\n // 1. Try app-provided externalProvider first\n if (this.config.externalProvider) {\n return this.config.externalProvider;\n }\n\n // 2. Check EIP-6963 discovered wallets silently (no popup)\n for (const { provider } of this.discoveredProviders) {\n try {\n const accounts = await provider.request({ method: 'eth_accounts' }) as string[];\n if (accounts.some(a => a.toLowerCase() === targetAddress.toLowerCase())) {\n return provider;\n }\n } catch {}\n }\n\n // 3. Fall back to window.ethereum silently\n if (typeof window !== 'undefined' && (window as any).ethereum) {\n const provider = (window as any).ethereum as EIP1193Provider;\n try {\n const accounts = await provider.request({ method: 'eth_accounts' }) as string[];\n if (accounts.some(a => a.toLowerCase() === targetAddress.toLowerCase())) {\n return provider;\n }\n } catch {}\n }\n\n throw new ExternalWalletError('External wallet not found. Connect the wallet that owns this key and try again.');\n }\n\n private async signWithExternalWallet(request: SignMessageRequest): Promise<SignResult> {\n let provider: EIP1193Provider;\n try {\n provider = await this.findWalletProvider(this.lastAuth!.address);\n } catch (e) {\n showToast((e as Error).message, 'error');\n throw e;\n }\n try {\n const hexMessage = this.toHex(request.message);\n const signature = await provider.request({\n method: 'personal_sign',\n params: [hexMessage, this.lastAuth!.address],\n });\n return { signature: signature as string, address: this.lastAuth!.address };\n } catch (e: any) {\n const msg = e?.message?.includes('not been authorized')\n ? 'Wallet rejected the request. Approve the connection in your wallet and try again.'\n : e?.message || 'Signing failed';\n showToast(msg, 'error');\n throw new Error(msg);\n }\n }\n\n private async signTypedDataWithExternalWallet(request: SignTypedDataRequest): Promise<SignResult> {\n let provider: EIP1193Provider;\n try {\n provider = await this.findWalletProvider(this.lastAuth!.address);\n } catch (e) {\n showToast((e as Error).message, 'error');\n throw e;\n }\n try {\n const signature = await provider.request({\n method: 'eth_signTypedData_v4',\n params: [this.lastAuth!.address, JSON.stringify(request)],\n });\n return { signature: signature as string, address: this.lastAuth!.address };\n } catch (e: any) {\n const msg = e?.message?.includes('not been authorized')\n ? 'Wallet rejected the request. Approve the connection in your wallet and try again.'\n : e?.message || 'Signing failed';\n showToast(msg, 'error');\n throw new Error(msg);\n }\n }\n\n private signWithOpenKey(request: SignMessageRequest, mode?: OpenKeyMode): Promise<SignResult> {\n return this.openFlow<SignResult>('sign', {\n type: 'openkey:sign:request',\n message: request.message,\n keyId: request.keyId,\n sessionToken: this.sessionToken || undefined,\n }, mode);\n }\n\n private signTypedDataWithOpenKey(request: SignTypedDataRequest, mode?: OpenKeyMode): Promise<SignResult> {\n return this.openFlow<SignResult>('sign-typed-data', {\n type: 'openkey:signTypedData:request',\n data: request,\n sessionToken: this.sessionToken || undefined,\n }, mode);\n }\n\n private toHex(str: string): string {\n return '0x' + Array.from(new TextEncoder().encode(str)).map(b => b.toString(16).padStart(2, '0')).join('');\n }\n\n /**\n * Check if user is already authenticated\n */\n async isConnected(): Promise<boolean> {\n // Check for existing session via API\n try {\n const res = await fetch(`${this.host}/api/auth/session`, {\n credentials: 'include',\n });\n if (!res.ok) return false;\n const data = await res.json();\n return !!data.user;\n } catch {\n return false;\n }\n }\n\n // ======= OAuth 2.1 Provider Methods =======\n\n /**\n * OAuth 2.1 methods for third-party app authentication\n * Use this when your app has registered OAuth client credentials with OpenKey\n */\n oauth = {\n /**\n * Start OAuth authorization flow\n * Opens popup/redirect to OpenKey authorization endpoint\n * @returns Promise that resolves with authorization code after user consent\n */\n connect: async (config: OAuthConfig): Promise<OAuthResult> => {\n // Generate PKCE values\n const verifier = generateCodeVerifier();\n const challenge = await generateCodeChallenge(verifier);\n const state = config.state || generateState();\n\n // Store for later token exchange\n sessionStorage.setItem(\n OAUTH_STORAGE_KEY,\n JSON.stringify({ verifier, state })\n );\n\n // Build authorization URL\n const authUrl = buildAuthorizationUrl({\n host: this.oauthHost,\n clientId: config.clientId,\n redirectUri: config.redirectUri,\n codeChallenge: challenge,\n state,\n scopes: ['openid'],\n });\n\n return this.openOAuthFlow(authUrl, state, config.redirectUri);\n },\n\n /**\n * Exchange authorization code for tokens\n * Call this after receiving the callback with authorization code\n * @param code - Authorization code from callback URL\n * @param config - Same config used for connect()\n * @returns Promise that resolves with access_token, id_token, etc.\n */\n exchangeCode: async (\n code: string,\n config: OAuthConfig\n ): Promise<OAuthTokenResponse> => {\n const stored = sessionStorage.getItem(OAUTH_STORAGE_KEY);\n if (!stored) {\n throw new Error('No PKCE verifier found. Start a new OAuth flow.');\n }\n\n const { verifier } = JSON.parse(stored);\n\n const response = await fetch(`${this.oauthHost}/api/auth/oauth2/token`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/x-www-form-urlencoded',\n },\n body: new URLSearchParams({\n grant_type: 'authorization_code',\n code,\n redirect_uri: config.redirectUri,\n client_id: config.clientId,\n code_verifier: verifier,\n }),\n });\n\n // Clear stored verifier\n sessionStorage.removeItem(OAUTH_STORAGE_KEY);\n\n if (!response.ok) {\n const error = await response.json();\n throw new Error(error.error_description || 'Token exchange failed');\n }\n\n return response.json();\n },\n\n /**\n * Verify state parameter from callback\n * Call this before exchangeCode to prevent CSRF attacks\n * @param receivedState - State parameter from callback URL\n * @returns true if state matches, false otherwise\n */\n verifyState: (receivedState: string): boolean => {\n const stored = sessionStorage.getItem(OAUTH_STORAGE_KEY);\n if (!stored) return false;\n const { state } = JSON.parse(stored);\n return state === receivedState;\n },\n\n /**\n * Parse authorization response from callback URL\n * @param url - Callback URL (defaults to current window.location.href)\n * @returns Parsed code and state, or error\n */\n parseCallback: (\n url?: string\n ): { code: string; state: string } | { error: string; errorDescription?: string } => {\n const urlObj = new URL(url || window.location.href);\n const error = urlObj.searchParams.get('error');\n\n if (error) {\n return {\n error,\n errorDescription: urlObj.searchParams.get('error_description') || undefined,\n };\n }\n\n const code = urlObj.searchParams.get('code');\n const state = urlObj.searchParams.get('state');\n\n if (!code || !state) {\n return { error: 'missing_params', errorDescription: 'Missing code or state parameter' };\n }\n\n return { code, state };\n },\n };\n\n private openOAuthFlow(\n url: string,\n state: string,\n redirectUri: string\n ): Promise<OAuthResult> {\n return new Promise((resolve, reject) => {\n if (this.mode !== 'redirect') {\n this.openOAuthPopup(url, state, redirectUri, resolve, reject);\n } else {\n // Full page redirect - won't resolve, page navigates away\n window.location.href = url;\n }\n });\n }\n\n private openOAuthPopup(\n url: string,\n state: string,\n redirectUri: string,\n resolve: (value: OAuthResult) => void,\n reject: (error: OpenKeyError) => void\n ) {\n const left = window.screenX + (window.outerWidth - POPUP_WIDTH) / 2;\n const top = window.screenY + (window.outerHeight - POPUP_HEIGHT) / 2;\n\n this.popup = window.open(\n url,\n 'openkey-oauth',\n `width=${POPUP_WIDTH},height=${POPUP_HEIGHT},left=${left},top=${top},popup=true`\n );\n\n if (!this.popup) {\n showToast('Popup was blocked. Please allow popups for this site.', 'error');\n reject({\n code: 'POPUP_BLOCKED',\n message: 'Popup was blocked. Please allow popups or use redirect mode.',\n });\n return;\n }\n\n const redirectHost = new URL(redirectUri).origin;\n\n // Poll for redirect back with code\n const pollInterval = setInterval(() => {\n try {\n if (this.popup?.closed) {\n clearInterval(pollInterval);\n clearTimeout(timeout);\n reject({\n code: 'USER_CANCELLED',\n message: 'User closed the popup',\n });\n return;\n }\n\n // Check if redirected to callback URL\n const popupUrl = this.popup?.location?.href;\n if (popupUrl && popupUrl.startsWith(redirectHost)) {\n clearInterval(pollInterval);\n clearTimeout(timeout);\n\n const urlObj = new URL(popupUrl);\n const code = urlObj.searchParams.get('code');\n const returnedState = urlObj.searchParams.get('state');\n const error = urlObj.searchParams.get('error');\n\n this.popup?.close();\n\n if (error) {\n reject({\n code: 'UNAUTHORIZED',\n message: urlObj.searchParams.get('error_description') || error,\n });\n return;\n }\n\n if (returnedState !== state) {\n reject({\n code: 'STATE_MISMATCH',\n message: 'State mismatch - possible CSRF attack',\n });\n return;\n }\n\n if (code) {\n resolve({ code, state: returnedState });\n } else {\n reject({\n code: 'UNAUTHORIZED',\n message: 'Authorization failed - no code returned',\n });\n }\n }\n } catch {\n // Cross-origin - popup still on OpenKey domain, continue polling\n }\n }, 100);\n\n // Timeout\n const timeout = setTimeout(() => {\n clearInterval(pollInterval);\n this.popup?.close();\n reject({\n code: 'TIMEOUT',\n message: 'OAuth flow timed out',\n });\n }, DEFAULT_TIMEOUT);\n }\n\n private resolveMode(override?: OpenKeyMode): OpenKeyMode {\n return override ?? this.mode;\n }\n\n private hasDetectedEoa(): boolean {\n if (this.discoveredProviders.length > 0) return true;\n if (typeof window !== 'undefined' && (window as any).ethereum) return true;\n return false;\n }\n\n private async openFlow<T>(action: string, message: object, modeOverride?: OpenKeyMode): Promise<T> {\n const mode = this.resolveMode(modeOverride);\n const origin = encodeURIComponent(window.location.origin);\n const eoaFlag = action === 'connect' && this.hasDetectedEoa() ? '&hasEoa=true' : '';\n\n if (mode === 'popup') {\n const url = `${this.host}/widget/${action}?origin=${origin}${eoaFlag}`;\n return new Promise((resolve, reject) => this.openPopup(url, message, resolve, reject));\n }\n\n if (mode === 'redirect') {\n const url = `${this.host}/widget/${action}?origin=${origin}${eoaFlag}`;\n window.location.href = url;\n return new Promise(() => {}); // never resolves, page navigates\n }\n\n // iframe mode with auto-fallback\n const url = `${this.host}/widget/embed/${action}?origin=${origin}${eoaFlag}`;\n return this.openIframeModal<T>(url, action, message, origin);\n }\n\n private openIframeModal<T>(url: string, action: string, message: object, origin: string): Promise<T> {\n return new Promise((resolve, reject) => {\n let readyReceived = false;\n let settled = false;\n let modal: IframeModal | null = null;\n\n const settle = (fn: () => void) => {\n if (settled) return;\n settled = true;\n fn();\n };\n\n const cleanup = () => {\n clearTimeout(readyTimeout);\n clearTimeout(overallTimeout);\n modal?.destroy();\n modal = null;\n };\n\n modal = new IframeModal({\n url,\n host: this.host,\n onClose: () => {\n settle(() => {\n clearTimeout(readyTimeout);\n clearTimeout(overallTimeout);\n modal = null;\n reject({ code: 'USER_CANCELLED', message: 'User cancelled the request' } as OpenKeyError);\n });\n },\n onMessage: (data: MessageType) => {\n if (data.type === 'openkey:ready') {\n readyReceived = true;\n modal?.postMessage(message);\n return;\n }\n\n if (data.type === 'openkey:close') {\n settle(() => {\n cleanup();\n reject({ code: 'USER_CANCELLED', message: 'User cancelled the request' } as OpenKeyError);\n });\n return;\n }\n\n if (data.type === 'openkey:link-wallet:delegate') {\n this.handleWalletLinkDelegation(modal!);\n return;\n }\n\n if (data.type === 'openkey:auth:use-external-wallet') {\n cleanup();\n this.handleExternalWalletConnect<T>(resolve, reject);\n return;\n }\n\n if (\n data.type === 'openkey:auth:response' ||\n data.type === 'openkey:sign:response' ||\n data.type === 'openkey:signTypedData:response' ||\n data.type === 'openkey:link-wallet:response'\n ) {\n settle(() => {\n cleanup();\n if (data.success) {\n if (data.type === 'openkey:auth:response') {\n if (data.sessionToken) this.sessionToken = data.sessionToken;\n resolve({ address: data.address, keyId: data.keyId, keyType: data.keyType || 'MANAGED' } as T);\n } else if (data.type === 'openkey:link-wallet:response') {\n resolve({ address: data.address, keyId: data.keyId } as T);\n } else {\n resolve({ signature: data.signature, address: data.address } as T);\n }\n } else {\n reject(data.error);\n }\n });\n }\n },\n });\n\n // Auto-fallback: if no openkey:ready within 3s, fall back to popup\n const readyTimeout = setTimeout(() => {\n if (readyReceived || settled) return;\n cleanup();\n console.warn('OpenKey: iframe blocked by CSP, falling back to popup. Add frame-src https://openkey.so to your CSP.');\n showToast();\n const popupUrl = `${this.host}/widget/${action}?origin=${origin}`;\n this.openPopup(popupUrl, message, (val: any) => settle(() => resolve(val)), (err: any) => settle(() => reject(err)));\n }, IFRAME_READY_TIMEOUT);\n\n // Overall 5-minute timeout\n const overallTimeout = setTimeout(() => {\n settle(() => {\n cleanup();\n reject({ code: 'TIMEOUT', message: 'Request timed out' } as OpenKeyError);\n });\n }, DEFAULT_TIMEOUT);\n });\n }\n\n private handleWalletLinkDelegation(modal: IframeModal) {\n const sendResult = (result: MessageType) => modal.postMessage(result);\n\n new WalletPicker({\n providers: this.discoveredProviders,\n onCancel: () => {\n sendResult({ type: 'openkey:link-wallet:result', success: false, error: { code: 'USER_CANCELLED', message: 'Wallet linking cancelled' } });\n },\n onSelect: async (provider) => {\n try {\n const accounts = await provider.request({ method: 'eth_requestAccounts' }) as string[];\n const address = accounts[0];\n if (!address) throw new Error('No account returned');\n\n // Get challenge from API\n const challengeRes = await fetch(`${this.host}/api/keys/link/challenge`, {\n method: 'POST',\n credentials: 'include',\n });\n if (!challengeRes.ok) throw new Error('Failed to get challenge');\n const { message } = await challengeRes.json();\n\n // Sign challenge with wallet\n const hexMessage = this.toHex(message);\n const signature = await provider.request({\n method: 'personal_sign',\n params: [hexMessage, address],\n }) as string;\n\n // Submit to API\n const linkRes = await fetch(`${this.host}/api/keys/link`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n credentials: 'include',\n body: JSON.stringify({ address, signature, message }),\n });\n if (!linkRes.ok) {\n const err = await linkRes.json();\n throw new Error(err.error || 'Failed to link wallet');\n }\n const { key } = await linkRes.json();\n\n sendResult({ type: 'openkey:link-wallet:result', success: true, address: key.address, keyId: key.id });\n } catch (e: any) {\n sendResult({ type: 'openkey:link-wallet:result', success: false, error: { code: 'UNKNOWN', message: e.message || 'Wallet linking failed' } });\n }\n },\n });\n }\n\n private handleExternalWalletConnect<T>(\n resolve: (value: T) => void,\n reject: (error: OpenKeyError) => void\n ) {\n new WalletPicker({\n providers: this.discoveredProviders,\n onCancel: () => {\n reject({ code: 'USER_CANCELLED', message: 'User cancelled wallet selection' });\n },\n onSelect: async (provider) => {\n try {\n const accounts = await provider.request({ method: 'eth_requestAccounts' }) as string[];\n const address = accounts[0];\n if (!address) throw new Error('No account returned');\n const result = { address, keyId: `external:${address}`, keyType: 'EXTERNAL' as const };\n this.lastAuth = result;\n resolve(result as T);\n } catch (e: any) {\n reject({ code: 'UNKNOWN', message: e.message || 'Failed to connect wallet' });\n }\n },\n });\n }\n\n private openPopup<T>(\n url: string,\n message: object,\n resolve: (value: T) => void,\n reject: (error: OpenKeyError) => void\n ) {\n // Calculate popup position\n const left = window.screenX + (window.outerWidth - POPUP_WIDTH) / 2;\n const top = window.screenY + (window.outerHeight - POPUP_HEIGHT) / 2;\n\n this.popup = window.open(\n url,\n 'openkey',\n `width=${POPUP_WIDTH},height=${POPUP_HEIGHT},left=${left},top=${top},popup=true`\n );\n\n if (!this.popup) {\n showToast('Popup was blocked. Please allow popups for this site.', 'error');\n reject({\n code: 'POPUP_BLOCKED',\n message: 'Popup was blocked. Please allow popups for this site.',\n });\n return;\n }\n\n const cleanup = () => {\n window.removeEventListener('message', handleMessage);\n clearInterval(pollClosed);\n clearTimeout(timeout);\n };\n\n // Poll to detect popup close\n const pollClosed = setInterval(() => {\n if (this.popup?.closed) {\n cleanup();\n reject({\n code: 'USER_CANCELLED',\n message: 'User closed the popup',\n });\n }\n }, 500);\n\n // Timeout\n const timeout = setTimeout(() => {\n cleanup();\n this.popup?.close();\n reject({\n code: 'TIMEOUT',\n message: 'Request timed out',\n });\n }, DEFAULT_TIMEOUT);\n\n // Listen for messages\n const handleMessage = (event: MessageEvent) => {\n if (event.origin !== this.host) return;\n if (event.source !== this.popup) return;\n\n const data = event.data as MessageType;\n\n if (data.type === 'openkey:ready') {\n // Widget is ready, send our request\n this.popup?.postMessage(message, this.host);\n return;\n }\n\n if (data.type === 'openkey:close') {\n cleanup();\n this.popup?.close();\n reject({\n code: 'USER_CANCELLED',\n message: 'User cancelled the request',\n });\n return;\n }\n\n if (data.type === 'openkey:auth:use-external-wallet') {\n cleanup();\n this.popup?.close();\n this.handleExternalWalletConnect<T>(resolve, reject);\n return;\n }\n\n // Handle responses\n if (\n data.type === 'openkey:auth:response' ||\n data.type === 'openkey:sign:response' ||\n data.type === 'openkey:signTypedData:response' ||\n data.type === 'openkey:link-wallet:response'\n ) {\n cleanup();\n this.popup?.close();\n\n if (data.success) {\n if (data.type === 'openkey:auth:response') {\n if (data.sessionToken) this.sessionToken = data.sessionToken;\n resolve({ address: data.address, keyId: data.keyId, keyType: data.keyType || 'MANAGED' } as T);\n } else if (data.type === 'openkey:link-wallet:response') {\n resolve({ address: data.address, keyId: data.keyId } as T);\n } else {\n resolve({ signature: data.signature, address: data.address } as T);\n }\n } else {\n reject(data.error);\n }\n }\n };\n\n window.addEventListener('message', handleMessage);\n }\n\n /**\n * Disconnect and close any open flows\n */\n disconnect() {\n this.popup?.close();\n this.popup = null;\n }\n}\n\n/**\n * EIP-1193 compatible provider that wraps an OpenKey instance.\n * Transparently routes signing to either OpenKey (managed keys) or the user's\n * wallet (external keys).\n */\nexport class OpenKeyProvider implements EIP1193Provider {\n private openkey: OpenKey;\n private address: string;\n private keyId: string;\n private keyType: 'MANAGED' | 'EXTERNAL';\n\n constructor(openkey: OpenKey, authResult: AuthResult) {\n this.openkey = openkey;\n this.address = authResult.address;\n this.keyId = authResult.keyId;\n this.keyType = authResult.keyType;\n }\n\n async request({ method, params }: { method: string; params?: any[] }): Promise<any> {\n switch (method) {\n case 'eth_accounts':\n case 'eth_requestAccounts':\n return [this.address];\n\n case 'eth_chainId':\n return '0x1'; // mainnet\n\n case 'personal_sign': {\n if (this.keyType === 'EXTERNAL') {\n try {\n const provider = await this.openkey.findWalletProvider(this.address);\n return await provider.request({ method, params });\n } catch (e: any) {\n showToast(e?.message || 'External wallet signing failed', 'error');\n throw e;\n }\n }\n // Managed key: route through OpenKey\n const message = this.hexToString(params![0] as string);\n const result = await this.openkey.signMessage({ message, keyId: this.keyId });\n return result.signature;\n }\n\n case 'eth_signTypedData_v4': {\n if (this.keyType === 'EXTERNAL') {\n try {\n const provider = await this.openkey.findWalletProvider(this.address);\n return await provider.request({ method, params });\n } catch (e: any) {\n showToast(e?.message || 'External wallet signing failed', 'error');\n throw e;\n }\n }\n const data = JSON.parse(params![1] as string);\n const result = await this.openkey.signTypedData(data);\n return result.signature;\n }\n\n default:\n throw new Error(`Unsupported method: ${method}`);\n }\n }\n\n private hexToString(hex: string): string {\n const bytes = new Uint8Array(\n (hex.startsWith('0x') ? hex.slice(2) : hex).match(/.{1,2}/g)!.map(b => parseInt(b, 16))\n );\n return new TextDecoder().decode(bytes);\n }\n}\n\n// Default export for convenience\nexport default OpenKey;\n\n// Create singleton instance\nlet defaultInstance: OpenKey | null = null;\n\nexport function getOpenKey(config?: OpenKeyConfig): OpenKey {\n if (!defaultInstance || config) {\n defaultInstance = new OpenKey(config);\n }\n return defaultInstance;\n}\n"],"mappings":"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","names":["url"]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts"],"sourcesContent":["// OpenKey SDK - Browser client for third-party apps\n// Provides \"Sign with OpenKey\" functionality via popup or iframe\n\nimport {\n generateCodeVerifier,\n generateCodeChallenge,\n generateState,\n buildAuthorizationUrl,\n} from '@openkey/core';\n\nexport interface EIP1193Provider {\n request(args: { method: string; params?: any[] }): Promise<any>;\n}\n\ninterface EIP6963ProviderInfo {\n uuid: string;\n name: string;\n icon: string;\n rdns: string;\n}\n\ninterface EIP6963ProviderDetail {\n info: EIP6963ProviderInfo;\n provider: EIP1193Provider;\n}\n\nexport type OpenKeyMode = 'iframe' | 'popup' | 'redirect';\n\nexport interface OpenKeyConfig {\n /** OpenKey host URL (default: https://openkey.so) */\n host?: string;\n /** OAuth API host URL (default: derived from host by prefixing 'api.') */\n oauthHost?: string;\n /** App identifier for display */\n appName?: string;\n /** UI mode: 'iframe' (default), 'popup', or 'redirect' */\n mode?: OpenKeyMode;\n /** App-provided wallet provider for external key signing */\n externalProvider?: EIP1193Provider;\n}\n\nexport interface SignMessageRequest {\n message: string;\n keyId?: string; // If not provided, user selects\n}\n\nexport interface SignTypedDataRequest {\n domain: {\n name?: string;\n version?: string;\n chainId?: number;\n verifyingContract?: string;\n };\n types: Record<string, Array<{ name: string; type: string }>>;\n primaryType: string;\n message: Record<string, unknown>;\n keyId?: string;\n}\n\nexport interface SignResult {\n signature: string;\n address: string;\n}\n\nexport interface AuthResult {\n address: string;\n keyId: string;\n keyType: 'MANAGED' | 'EXTERNAL';\n}\n\nexport interface OpenKeyError {\n code: 'USER_CANCELLED' | 'POPUP_BLOCKED' | 'TIMEOUT' | 'NO_KEY' | 'UNAUTHORIZED' | 'UNKNOWN' | 'STATE_MISMATCH';\n message: string;\n}\n\n// ======= OAuth 2.1 Types =======\n\n/** OAuth configuration for third-party apps */\nexport interface OAuthConfig {\n /** OAuth client_id (registered with OpenKey) */\n clientId: string;\n /** Redirect URI (must match registered URI) */\n redirectUri: string;\n /** State parameter for CSRF protection (auto-generated if not provided) */\n state?: string;\n}\n\n/** Result from OAuth authorization */\nexport interface OAuthResult {\n /** Authorization code (exchange for tokens) */\n code: string;\n /** State parameter (verify matches request) */\n state: string;\n}\n\n/** Response from token exchange */\nexport interface OAuthTokenResponse {\n access_token: string;\n token_type: 'Bearer';\n expires_in: number;\n id_token: string;\n scope: string;\n refresh_token?: string;\n}\n\ntype MessageType =\n | { type: 'openkey:auth:request'; appName: string }\n | { type: 'openkey:auth:response'; success: true; address: string; keyId: string; keyType?: 'MANAGED' | 'EXTERNAL'; sessionToken?: string }\n | { type: 'openkey:auth:response'; success: false; error: OpenKeyError }\n | { type: 'openkey:sign:request'; message: string; keyId?: string; sessionToken?: string }\n | { type: 'openkey:sign:response'; success: true; signature: string; address: string }\n | { type: 'openkey:sign:response'; success: false; error: OpenKeyError }\n | { type: 'openkey:signTypedData:request'; data: SignTypedDataRequest; sessionToken?: string }\n | { type: 'openkey:signTypedData:response'; success: true; signature: string; address: string }\n | { type: 'openkey:signTypedData:response'; success: false; error: OpenKeyError }\n | { type: 'openkey:link-wallet:request' }\n | { type: 'openkey:link-wallet:response'; success: true; address: string; keyId: string }\n | { type: 'openkey:link-wallet:response'; success: false; error: OpenKeyError }\n | { type: 'openkey:link-wallet:delegate' }\n | { type: 'openkey:link-wallet:result'; success: true; address: string; keyId: string }\n | { type: 'openkey:link-wallet:result'; success: false; error: OpenKeyError }\n | { type: 'openkey:auth:use-external-wallet' }\n | { type: 'openkey:resize'; height: number }\n | { type: 'openkey:ready' }\n | { type: 'openkey:close' };\n\nconst DEFAULT_HOST = 'https://openkey.so';\nconst POPUP_WIDTH = 400;\nconst POPUP_HEIGHT = 600;\nconst DEFAULT_TIMEOUT = 5 * 60 * 1000; // 5 minutes\nconst IFRAME_READY_TIMEOUT = 3000; // 3 seconds\nconst OAUTH_STORAGE_KEY = 'openkey_oauth';\n\nclass IframeModal {\n private root: HTMLDivElement;\n private shadow: ShadowRoot;\n private iframe: HTMLIFrameElement;\n private onClose: () => void;\n private onMessage: (data: MessageType) => void;\n private messageHandler: (event: MessageEvent) => void;\n private host: string;\n\n constructor(opts: { url: string; host: string; onClose: () => void; onMessage: (data: MessageType) => void }) {\n this.host = opts.host;\n this.onClose = opts.onClose;\n this.onMessage = opts.onMessage;\n\n const isMobile = window.matchMedia('(max-width: 639px)').matches;\n\n this.root = document.createElement('div');\n this.shadow = this.root.attachShadow({ mode: 'closed' });\n\n const style = document.createElement('style');\n style.textContent = `\n :host{all:initial}\n .ok-backdrop{position:fixed;inset:0;background:rgba(0,0,0,0.42);z-index:999999;display:flex;align-items:${isMobile ? 'flex-end' : 'center'};justify-content:center;animation:ok-fade-in 150ms ease-out}\n .ok-card{position:relative;background:#fafafa;width:${isMobile ? '100%' : '400px'};border-radius:${isMobile ? '16px 16px 0 0' : '16px'};box-shadow:0 25px 50px -12px rgba(0,0,0,0.25);overflow:hidden;overflow-y:auto;animation:${isMobile ? 'ok-slide-up 250ms ease-out' : 'ok-scale-in 200ms ease-out'};max-height:90vh}\n .ok-close{position:absolute;top:8px;right:8px;width:24px;height:24px;border:none;background:transparent;color:#6b7280;font-size:18px;cursor:pointer;z-index:1;display:flex;align-items:center;justify-content:center;border-radius:4px}\n .ok-close:hover{color:#111827}\n .ok-handle{width:40px;height:4px;background:#d4d4d4;border-radius:2px;margin:8px auto 0}\n iframe{border:none;width:100%;height:400px;display:block;transition:height 200ms ease}\n .ok-backdrop.ok-exit{animation:ok-fade-out 150ms ease-in}\n .ok-backdrop.ok-exit .ok-card{animation:${isMobile ? 'ok-slide-down 200ms ease-in' : 'ok-scale-out 150ms ease-in'}}\n @keyframes ok-fade-in{from{opacity:0}to{opacity:1}}\n @keyframes ok-fade-out{from{opacity:1}to{opacity:0}}\n @keyframes ok-scale-in{from{opacity:0;transform:scale(0.95)}to{opacity:1;transform:scale(1)}}\n @keyframes ok-scale-out{from{opacity:1;transform:scale(1)}to{opacity:0;transform:scale(0.95)}}\n @keyframes ok-slide-up{from{transform:translateY(100%)}to{transform:translateY(0)}}\n @keyframes ok-slide-down{from{transform:translateY(0)}to{transform:translateY(100%)}}\n `;\n\n const backdrop = document.createElement('div');\n backdrop.className = 'ok-backdrop';\n backdrop.addEventListener('click', (e) => {\n if (e.target === backdrop) this.close();\n });\n\n const card = document.createElement('div');\n card.className = 'ok-card';\n\n if (isMobile) {\n const handle = document.createElement('div');\n handle.className = 'ok-handle';\n card.appendChild(handle);\n }\n\n const closeBtn = document.createElement('button');\n closeBtn.className = 'ok-close';\n closeBtn.textContent = '\\u00d7';\n closeBtn.addEventListener('click', () => this.close());\n card.appendChild(closeBtn);\n\n this.iframe = document.createElement('iframe');\n this.iframe.src = opts.url;\n this.iframe.setAttribute('allow', 'clipboard-write *; publickey-credentials-get *; publickey-credentials-create *');\n this.iframe.setAttribute('sandbox', 'allow-scripts allow-same-origin allow-forms allow-popups allow-popups-to-escape-sandbox');\n card.appendChild(this.iframe);\n\n backdrop.appendChild(card);\n this.shadow.appendChild(style);\n this.shadow.appendChild(backdrop);\n\n this.messageHandler = (event: MessageEvent) => {\n if (event.origin !== this.host) return;\n if (event.source !== this.iframe.contentWindow) return;\n const data = event.data as MessageType;\n if (data.type === 'openkey:resize') {\n const h = Math.min(data.height, Math.floor(window.innerHeight * 0.85));\n this.iframe.style.height = `${h}px`;\n return;\n }\n this.onMessage(data);\n };\n window.addEventListener('message', this.messageHandler);\n document.body.appendChild(this.root);\n }\n\n postMessage(message: object) {\n this.iframe.contentWindow?.postMessage(message, this.host);\n }\n\n destroy() {\n window.removeEventListener('message', this.messageHandler);\n this.root.remove();\n }\n\n private close() {\n const backdrop = this.shadow.querySelector('.ok-backdrop');\n if (backdrop) {\n backdrop.classList.add('ok-exit');\n setTimeout(() => {\n this.destroy();\n this.onClose();\n }, 200);\n } else {\n this.destroy();\n this.onClose();\n }\n }\n}\n\nclass WalletPicker {\n private root: HTMLDivElement;\n private shadow: ShadowRoot;\n\n constructor(opts: { providers: EIP6963ProviderDetail[]; onSelect: (provider: EIP1193Provider) => void; onCancel: () => void }) {\n this.root = document.createElement('div');\n this.shadow = this.root.attachShadow({ mode: 'closed' });\n\n const style = document.createElement('style');\n style.textContent = `\n :host{all:initial}\n .wp-backdrop{position:fixed;inset:0;background:rgba(0,0,0,0.42);z-index:1000000;display:flex;align-items:center;justify-content:center;animation:wp-fade 150ms ease-out}\n .wp-card{background:#fff;width:340px;border-radius:16px;box-shadow:0 25px 50px -12px rgba(0,0,0,0.25);padding:20px;animation:wp-scale 200ms ease-out}\n .wp-title{font:600 16px/1.3 system-ui,sans-serif;color:#111;margin:0 0 12px}\n .wp-list{list-style:none;margin:0;padding:0;display:flex;flex-direction:column;gap:6px}\n .wp-item{display:flex;align-items:center;gap:10px;padding:10px 12px;border:1px solid #e5e7eb;border-radius:10px;background:transparent;cursor:pointer;font:14px/1.3 system-ui,sans-serif;color:#111;width:100%;text-align:left;transition:border-color 150ms}\n .wp-item:hover{border-color:#6366f1}\n .wp-icon{width:28px;height:28px;border-radius:6px}\n .wp-empty{font:14px/1.4 system-ui,sans-serif;color:#6b7280;text-align:center;padding:16px 0}\n .wp-cancel{display:block;width:100%;margin-top:12px;padding:8px;border:none;background:transparent;color:#6b7280;font:14px/1.3 system-ui,sans-serif;cursor:pointer;border-radius:8px}\n .wp-cancel:hover{background:#f3f4f6;color:#111}\n @keyframes wp-fade{from{opacity:0}to{opacity:1}}\n @keyframes wp-scale{from{opacity:0;transform:scale(0.95)}to{opacity:1;transform:scale(1)}}\n @media(prefers-color-scheme:dark){\n .wp-card{background:#1a1a1a;box-shadow:0 25px 50px -12px rgba(0,0,0,0.5)}\n .wp-title{color:#f3f4f6}\n .wp-item{border-color:#374151;color:#f3f4f6}\n .wp-item:hover{border-color:#818cf8}\n .wp-empty{color:#9ca3af}\n .wp-cancel{color:#9ca3af}\n .wp-cancel:hover{background:#262626;color:#f3f4f6}\n }\n `;\n\n const backdrop = document.createElement('div');\n backdrop.className = 'wp-backdrop';\n backdrop.addEventListener('click', (e) => { if (e.target === backdrop) { this.destroy(); opts.onCancel(); } });\n\n const card = document.createElement('div');\n card.className = 'wp-card';\n\n const title = document.createElement('h2');\n title.className = 'wp-title';\n title.textContent = 'Select a wallet';\n card.appendChild(title);\n\n if (opts.providers.length === 0) {\n const empty = document.createElement('div');\n empty.className = 'wp-empty';\n empty.textContent = 'No wallets detected';\n card.appendChild(empty);\n } else {\n const list = document.createElement('ul');\n list.className = 'wp-list';\n for (const { info, provider } of opts.providers) {\n const item = document.createElement('button');\n item.className = 'wp-item';\n if (info.icon) {\n const icon = document.createElement('img');\n icon.className = 'wp-icon';\n icon.src = info.icon;\n icon.alt = info.name;\n item.appendChild(icon);\n }\n const name = document.createElement('span');\n name.textContent = info.name;\n item.appendChild(name);\n item.addEventListener('click', () => { this.destroy(); opts.onSelect(provider); });\n list.appendChild(item);\n }\n card.appendChild(list);\n }\n\n const cancel = document.createElement('button');\n cancel.className = 'wp-cancel';\n cancel.textContent = 'Cancel';\n cancel.addEventListener('click', () => { this.destroy(); opts.onCancel(); });\n card.appendChild(cancel);\n\n backdrop.appendChild(card);\n this.shadow.appendChild(style);\n this.shadow.appendChild(backdrop);\n document.body.appendChild(this.root);\n }\n\n destroy() {\n this.root.remove();\n }\n}\n\nfunction showToast(message = 'Opening in new window\\u2026', variant: 'info' | 'error' = 'info') {\n const bg = variant === 'error' ? '#dc2626' : '#1f2937';\n const root = document.createElement('div');\n const shadow = root.attachShadow({ mode: 'closed' });\n shadow.innerHTML = `<style>:host{all:initial}.ok-toast{position:fixed;top:16px;right:16px;z-index:1000000;background:${bg};color:#f9fafb;padding:10px 16px;border-radius:8px;font:14px/1.4 system-ui,sans-serif;box-shadow:0 4px 12px rgba(0,0,0,0.15);animation:ok-t-in 200ms ease-out;max-width:360px}@keyframes ok-t-in{from{opacity:0;transform:translateY(-8px)}to{opacity:1;transform:translateY(0)}}</style><div class=\"ok-toast\">${message}</div>`;\n document.body.appendChild(root);\n setTimeout(() => root.remove(), 4000);\n}\n\nclass ExternalWalletError extends Error {\n constructor(message: string) {\n super(message);\n this.name = 'ExternalWalletError';\n }\n}\n\nexport class OpenKey {\n private host: string;\n private oauthHost: string;\n private appName: string;\n private mode: OpenKeyMode;\n private config: OpenKeyConfig;\n private popup: Window | null = null;\n private lastAuth: AuthResult | null = null;\n private discoveredProviders: EIP6963ProviderDetail[] = [];\n private sessionToken: string | null = null;\n\n constructor(config: OpenKeyConfig = {}) {\n this.config = config;\n this.host = config.host || DEFAULT_HOST;\n this.oauthHost = config.oauthHost || this.deriveOAuthHost(this.host);\n this.appName = config.appName || window.location.hostname;\n this.mode = config.mode ?? 'iframe';\n\n // Listen for EIP-6963 wallet announcements\n if (typeof window !== 'undefined') {\n this.discoveredProviders = [];\n window.addEventListener('eip6963:announceProvider', (event: any) => {\n this.discoveredProviders.push(event.detail);\n });\n window.dispatchEvent(new Event('eip6963:requestProvider'));\n }\n }\n\n /**\n * Derive the OAuth API host from the main host by prefixing 'api.'\n * @param host - The main host URL\n * @returns The derived OAuth API host URL\n */\n private deriveOAuthHost(host: string): string {\n try {\n const url = new URL(host);\n if (url.hostname === 'localhost' || url.hostname === '127.0.0.1') {\n return host.replace(/\\/$/, '');\n }\n url.hostname = 'api.' + url.hostname;\n return url.toString().replace(/\\/$/, '');\n } catch {\n return 'https://api.openkey.so';\n }\n }\n\n /**\n * Connect to OpenKey and get user's wallet address\n * Opens auth flow for user to select/create a key\n */\n async connect(opts?: { mode?: OpenKeyMode }): Promise<AuthResult> {\n const result = await this.openFlow<AuthResult>('connect', {\n type: 'openkey:auth:request',\n appName: this.appName,\n }, opts?.mode);\n this.lastAuth = result;\n return result;\n }\n\n /**\n * Better-auth session token relayed during connect(), or null if the\n * flow did not provide one. Use as a bearer token for API calls made\n * on the user's behalf (e.g. TinyCloud auto-sign bootstrap signing).\n */\n getSessionToken(): string | null {\n return this.sessionToken;\n }\n\n /**\n * Endpoint + bearer token for a TinyCloud auto-sign signing strategy.\n * The endpoint is on the OpenKey API host and only signs requests the\n * server-side bootstrap allowlist permits.\n */\n tinycloudSigningOptions(): { endpoint: string; token: string | null } {\n return {\n endpoint: `${this.oauthHost}/api/delegate/sign`,\n token: this.sessionToken,\n };\n }\n\n /**\n * Link an external wallet to the user's OpenKey account\n * Opens link-wallet widget flow\n */\n async linkWallet(opts?: { mode?: OpenKeyMode }): Promise<{ address: string; keyId: string }> {\n return this.openFlow<{ address: string; keyId: string }>('link-wallet', {\n type: 'openkey:link-wallet:request',\n }, opts?.mode);\n }\n\n /**\n * Sign a message with the user's OpenKey wallet\n * For external keys, routes directly to the user's wallet provider\n */\n async signMessage(request: SignMessageRequest, opts?: { mode?: OpenKeyMode }): Promise<SignResult> {\n if (this.lastAuth?.keyType === 'EXTERNAL') {\n return this.signWithExternalWallet(request);\n }\n return this.signWithOpenKey(request, opts?.mode);\n }\n\n /**\n * Sign typed data (EIP-712) with the user's OpenKey wallet\n * For external keys, routes directly to the user's wallet provider\n */\n async signTypedData(request: SignTypedDataRequest, opts?: { mode?: OpenKeyMode }): Promise<SignResult> {\n if (this.lastAuth?.keyType === 'EXTERNAL') {\n return this.signTypedDataWithExternalWallet(request);\n }\n return this.signTypedDataWithOpenKey(request, opts?.mode);\n }\n\n private providerCandidates(): EIP1193Provider[] {\n const providers: EIP1193Provider[] = [];\n if (this.config.externalProvider) {\n providers.push(this.config.externalProvider);\n }\n providers.push(...this.discoveredProviders.map(({ provider }) => provider));\n if (typeof window !== 'undefined' && (window as any).ethereum) {\n providers.push((window as any).ethereum as EIP1193Provider);\n }\n return [...new Set(providers)];\n }\n\n private async providerHasAccount(\n provider: EIP1193Provider,\n method: 'eth_accounts' | 'eth_requestAccounts',\n targetAddress: string\n ): Promise<boolean> {\n try {\n const accounts = await provider.request({ method }) as string[];\n return accounts.some((account) => account.toLowerCase() === targetAddress.toLowerCase());\n } catch {\n return false;\n }\n }\n\n /**\n * Find a wallet provider that controls the given address.\n * Checks connected accounts first, then asks the wallet to authorize the\n * app origin if the external key was linked elsewhere.\n */\n async findWalletProvider(targetAddress: string): Promise<EIP1193Provider> {\n const providers = this.providerCandidates();\n\n for (const provider of providers) {\n if (await this.providerHasAccount(provider, 'eth_accounts', targetAddress)) {\n return provider;\n }\n }\n\n for (const provider of providers) {\n if (await this.providerHasAccount(provider, 'eth_requestAccounts', targetAddress)) {\n return provider;\n }\n }\n\n throw new ExternalWalletError('External wallet not found. Connect the wallet that owns this key and try again.');\n }\n\n private async signWithExternalWallet(request: SignMessageRequest): Promise<SignResult> {\n let provider: EIP1193Provider;\n try {\n provider = await this.findWalletProvider(this.lastAuth!.address);\n } catch (e) {\n showToast((e as Error).message, 'error');\n throw e;\n }\n try {\n const hexMessage = this.toHex(request.message);\n const signature = await provider.request({\n method: 'personal_sign',\n params: [hexMessage, this.lastAuth!.address],\n });\n return { signature: signature as string, address: this.lastAuth!.address };\n } catch (e: any) {\n const msg = e?.message?.includes('not been authorized')\n ? 'Wallet rejected the request. Approve the connection in your wallet and try again.'\n : e?.message || 'Signing failed';\n showToast(msg, 'error');\n throw new Error(msg);\n }\n }\n\n private async signTypedDataWithExternalWallet(request: SignTypedDataRequest): Promise<SignResult> {\n let provider: EIP1193Provider;\n try {\n provider = await this.findWalletProvider(this.lastAuth!.address);\n } catch (e) {\n showToast((e as Error).message, 'error');\n throw e;\n }\n try {\n const signature = await provider.request({\n method: 'eth_signTypedData_v4',\n params: [this.lastAuth!.address, JSON.stringify(request)],\n });\n return { signature: signature as string, address: this.lastAuth!.address };\n } catch (e: any) {\n const msg = e?.message?.includes('not been authorized')\n ? 'Wallet rejected the request. Approve the connection in your wallet and try again.'\n : e?.message || 'Signing failed';\n showToast(msg, 'error');\n throw new Error(msg);\n }\n }\n\n private signWithOpenKey(request: SignMessageRequest, mode?: OpenKeyMode): Promise<SignResult> {\n return this.openFlow<SignResult>('sign', {\n type: 'openkey:sign:request',\n message: request.message,\n keyId: request.keyId,\n sessionToken: this.sessionToken || undefined,\n }, mode);\n }\n\n private signTypedDataWithOpenKey(request: SignTypedDataRequest, mode?: OpenKeyMode): Promise<SignResult> {\n return this.openFlow<SignResult>('sign-typed-data', {\n type: 'openkey:signTypedData:request',\n data: request,\n sessionToken: this.sessionToken || undefined,\n }, mode);\n }\n\n private toHex(str: string): string {\n return '0x' + Array.from(new TextEncoder().encode(str)).map(b => b.toString(16).padStart(2, '0')).join('');\n }\n\n /**\n * Check if user is already authenticated\n */\n async isConnected(): Promise<boolean> {\n // Check for existing session via API\n try {\n const res = await fetch(`${this.host}/api/auth/session`, {\n credentials: 'include',\n });\n if (!res.ok) return false;\n const data = await res.json();\n return !!data.user;\n } catch {\n return false;\n }\n }\n\n // ======= OAuth 2.1 Provider Methods =======\n\n /**\n * OAuth 2.1 methods for third-party app authentication\n * Use this when your app has registered OAuth client credentials with OpenKey\n */\n oauth = {\n /**\n * Start OAuth authorization flow\n * Opens popup/redirect to OpenKey authorization endpoint\n * @returns Promise that resolves with authorization code after user consent\n */\n connect: async (config: OAuthConfig): Promise<OAuthResult> => {\n // Generate PKCE values\n const verifier = generateCodeVerifier();\n const challenge = await generateCodeChallenge(verifier);\n const state = config.state || generateState();\n\n // Store for later token exchange\n sessionStorage.setItem(\n OAUTH_STORAGE_KEY,\n JSON.stringify({ verifier, state })\n );\n\n // Build authorization URL\n const authUrl = buildAuthorizationUrl({\n host: this.oauthHost,\n clientId: config.clientId,\n redirectUri: config.redirectUri,\n codeChallenge: challenge,\n state,\n scopes: ['openid'],\n });\n\n return this.openOAuthFlow(authUrl, state, config.redirectUri);\n },\n\n /**\n * Exchange authorization code for tokens\n * Call this after receiving the callback with authorization code\n * @param code - Authorization code from callback URL\n * @param config - Same config used for connect()\n * @returns Promise that resolves with access_token, id_token, etc.\n */\n exchangeCode: async (\n code: string,\n config: OAuthConfig\n ): Promise<OAuthTokenResponse> => {\n const stored = sessionStorage.getItem(OAUTH_STORAGE_KEY);\n if (!stored) {\n throw new Error('No PKCE verifier found. Start a new OAuth flow.');\n }\n\n const { verifier } = JSON.parse(stored);\n\n const response = await fetch(`${this.oauthHost}/api/auth/oauth2/token`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/x-www-form-urlencoded',\n },\n body: new URLSearchParams({\n grant_type: 'authorization_code',\n code,\n redirect_uri: config.redirectUri,\n client_id: config.clientId,\n code_verifier: verifier,\n }),\n });\n\n // Clear stored verifier\n sessionStorage.removeItem(OAUTH_STORAGE_KEY);\n\n if (!response.ok) {\n const error = await response.json();\n throw new Error(error.error_description || 'Token exchange failed');\n }\n\n return response.json();\n },\n\n /**\n * Verify state parameter from callback\n * Call this before exchangeCode to prevent CSRF attacks\n * @param receivedState - State parameter from callback URL\n * @returns true if state matches, false otherwise\n */\n verifyState: (receivedState: string): boolean => {\n const stored = sessionStorage.getItem(OAUTH_STORAGE_KEY);\n if (!stored) return false;\n const { state } = JSON.parse(stored);\n return state === receivedState;\n },\n\n /**\n * Parse authorization response from callback URL\n * @param url - Callback URL (defaults to current window.location.href)\n * @returns Parsed code and state, or error\n */\n parseCallback: (\n url?: string\n ): { code: string; state: string } | { error: string; errorDescription?: string } => {\n const urlObj = new URL(url || window.location.href);\n const error = urlObj.searchParams.get('error');\n\n if (error) {\n return {\n error,\n errorDescription: urlObj.searchParams.get('error_description') || undefined,\n };\n }\n\n const code = urlObj.searchParams.get('code');\n const state = urlObj.searchParams.get('state');\n\n if (!code || !state) {\n return { error: 'missing_params', errorDescription: 'Missing code or state parameter' };\n }\n\n return { code, state };\n },\n };\n\n private openOAuthFlow(\n url: string,\n state: string,\n redirectUri: string\n ): Promise<OAuthResult> {\n return new Promise((resolve, reject) => {\n if (this.mode !== 'redirect') {\n this.openOAuthPopup(url, state, redirectUri, resolve, reject);\n } else {\n // Full page redirect - won't resolve, page navigates away\n window.location.href = url;\n }\n });\n }\n\n private openOAuthPopup(\n url: string,\n state: string,\n redirectUri: string,\n resolve: (value: OAuthResult) => void,\n reject: (error: OpenKeyError) => void\n ) {\n const left = window.screenX + (window.outerWidth - POPUP_WIDTH) / 2;\n const top = window.screenY + (window.outerHeight - POPUP_HEIGHT) / 2;\n\n this.popup = window.open(\n url,\n 'openkey-oauth',\n `width=${POPUP_WIDTH},height=${POPUP_HEIGHT},left=${left},top=${top},popup=true`\n );\n\n if (!this.popup) {\n showToast('Popup was blocked. Please allow popups for this site.', 'error');\n reject({\n code: 'POPUP_BLOCKED',\n message: 'Popup was blocked. Please allow popups or use redirect mode.',\n });\n return;\n }\n\n const redirectHost = new URL(redirectUri).origin;\n\n // Poll for redirect back with code\n const pollInterval = setInterval(() => {\n try {\n if (this.popup?.closed) {\n clearInterval(pollInterval);\n clearTimeout(timeout);\n reject({\n code: 'USER_CANCELLED',\n message: 'User closed the popup',\n });\n return;\n }\n\n // Check if redirected to callback URL\n const popupUrl = this.popup?.location?.href;\n if (popupUrl && popupUrl.startsWith(redirectHost)) {\n clearInterval(pollInterval);\n clearTimeout(timeout);\n\n const urlObj = new URL(popupUrl);\n const code = urlObj.searchParams.get('code');\n const returnedState = urlObj.searchParams.get('state');\n const error = urlObj.searchParams.get('error');\n\n this.popup?.close();\n\n if (error) {\n reject({\n code: 'UNAUTHORIZED',\n message: urlObj.searchParams.get('error_description') || error,\n });\n return;\n }\n\n if (returnedState !== state) {\n reject({\n code: 'STATE_MISMATCH',\n message: 'State mismatch - possible CSRF attack',\n });\n return;\n }\n\n if (code) {\n resolve({ code, state: returnedState });\n } else {\n reject({\n code: 'UNAUTHORIZED',\n message: 'Authorization failed - no code returned',\n });\n }\n }\n } catch {\n // Cross-origin - popup still on OpenKey domain, continue polling\n }\n }, 100);\n\n // Timeout\n const timeout = setTimeout(() => {\n clearInterval(pollInterval);\n this.popup?.close();\n reject({\n code: 'TIMEOUT',\n message: 'OAuth flow timed out',\n });\n }, DEFAULT_TIMEOUT);\n }\n\n private resolveMode(override?: OpenKeyMode): OpenKeyMode {\n return override ?? this.mode;\n }\n\n private hasDetectedEoa(): boolean {\n if (this.discoveredProviders.length > 0) return true;\n if (typeof window !== 'undefined' && (window as any).ethereum) return true;\n return false;\n }\n\n private async openFlow<T>(action: string, message: object, modeOverride?: OpenKeyMode): Promise<T> {\n const mode = this.resolveMode(modeOverride);\n const origin = encodeURIComponent(window.location.origin);\n const eoaFlag = action === 'connect' && this.hasDetectedEoa() ? '&hasEoa=true' : '';\n\n if (mode === 'popup') {\n const url = `${this.host}/widget/${action}?origin=${origin}${eoaFlag}`;\n return new Promise((resolve, reject) => this.openPopup(url, message, resolve, reject));\n }\n\n if (mode === 'redirect') {\n const url = `${this.host}/widget/${action}?origin=${origin}${eoaFlag}`;\n window.location.href = url;\n return new Promise(() => {}); // never resolves, page navigates\n }\n\n // iframe mode with auto-fallback\n const url = `${this.host}/widget/embed/${action}?origin=${origin}${eoaFlag}`;\n return this.openIframeModal<T>(url, action, message, origin);\n }\n\n private openIframeModal<T>(url: string, action: string, message: object, origin: string): Promise<T> {\n return new Promise((resolve, reject) => {\n let readyReceived = false;\n let settled = false;\n let modal: IframeModal | null = null;\n\n const settle = (fn: () => void) => {\n if (settled) return;\n settled = true;\n fn();\n };\n\n const cleanup = () => {\n clearTimeout(readyTimeout);\n clearTimeout(overallTimeout);\n modal?.destroy();\n modal = null;\n };\n\n modal = new IframeModal({\n url,\n host: this.host,\n onClose: () => {\n settle(() => {\n clearTimeout(readyTimeout);\n clearTimeout(overallTimeout);\n modal = null;\n reject({ code: 'USER_CANCELLED', message: 'User cancelled the request' } as OpenKeyError);\n });\n },\n onMessage: (data: MessageType) => {\n if (data.type === 'openkey:ready') {\n readyReceived = true;\n modal?.postMessage(message);\n return;\n }\n\n if (data.type === 'openkey:close') {\n settle(() => {\n cleanup();\n reject({ code: 'USER_CANCELLED', message: 'User cancelled the request' } as OpenKeyError);\n });\n return;\n }\n\n if (data.type === 'openkey:link-wallet:delegate') {\n this.handleWalletLinkDelegation(modal!);\n return;\n }\n\n if (data.type === 'openkey:auth:use-external-wallet') {\n cleanup();\n this.handleExternalWalletConnect<T>(resolve, reject);\n return;\n }\n\n if (\n data.type === 'openkey:auth:response' ||\n data.type === 'openkey:sign:response' ||\n data.type === 'openkey:signTypedData:response' ||\n data.type === 'openkey:link-wallet:response'\n ) {\n settle(() => {\n cleanup();\n if (data.success) {\n if (data.type === 'openkey:auth:response') {\n if (data.sessionToken) this.sessionToken = data.sessionToken;\n resolve({ address: data.address, keyId: data.keyId, keyType: data.keyType || 'MANAGED' } as T);\n } else if (data.type === 'openkey:link-wallet:response') {\n resolve({ address: data.address, keyId: data.keyId } as T);\n } else {\n resolve({ signature: data.signature, address: data.address } as T);\n }\n } else {\n reject(data.error);\n }\n });\n }\n },\n });\n\n // Auto-fallback: if no openkey:ready within 3s, fall back to popup\n const readyTimeout = setTimeout(() => {\n if (readyReceived || settled) return;\n cleanup();\n console.warn('OpenKey: iframe blocked by CSP, falling back to popup. Add frame-src https://openkey.so to your CSP.');\n showToast();\n const popupUrl = `${this.host}/widget/${action}?origin=${origin}`;\n this.openPopup(popupUrl, message, (val: any) => settle(() => resolve(val)), (err: any) => settle(() => reject(err)));\n }, IFRAME_READY_TIMEOUT);\n\n // Overall 5-minute timeout\n const overallTimeout = setTimeout(() => {\n settle(() => {\n cleanup();\n reject({ code: 'TIMEOUT', message: 'Request timed out' } as OpenKeyError);\n });\n }, DEFAULT_TIMEOUT);\n });\n }\n\n private handleWalletLinkDelegation(modal: IframeModal) {\n const sendResult = (result: MessageType) => modal.postMessage(result);\n\n new WalletPicker({\n providers: this.discoveredProviders,\n onCancel: () => {\n sendResult({ type: 'openkey:link-wallet:result', success: false, error: { code: 'USER_CANCELLED', message: 'Wallet linking cancelled' } });\n },\n onSelect: async (provider) => {\n try {\n const accounts = await provider.request({ method: 'eth_requestAccounts' }) as string[];\n const address = accounts[0];\n if (!address) throw new Error('No account returned');\n\n // Get challenge from API\n const challengeRes = await fetch(`${this.host}/api/keys/link/challenge`, {\n method: 'POST',\n credentials: 'include',\n });\n if (!challengeRes.ok) throw new Error('Failed to get challenge');\n const { message } = await challengeRes.json();\n\n // Sign challenge with wallet\n const hexMessage = this.toHex(message);\n const signature = await provider.request({\n method: 'personal_sign',\n params: [hexMessage, address],\n }) as string;\n\n // Submit to API\n const linkRes = await fetch(`${this.host}/api/keys/link`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n credentials: 'include',\n body: JSON.stringify({ address, signature, message }),\n });\n if (!linkRes.ok) {\n const err = await linkRes.json();\n throw new Error(err.error || 'Failed to link wallet');\n }\n const { key } = await linkRes.json();\n\n sendResult({ type: 'openkey:link-wallet:result', success: true, address: key.address, keyId: key.id });\n } catch (e: any) {\n sendResult({ type: 'openkey:link-wallet:result', success: false, error: { code: 'UNKNOWN', message: e.message || 'Wallet linking failed' } });\n }\n },\n });\n }\n\n private handleExternalWalletConnect<T>(\n resolve: (value: T) => void,\n reject: (error: OpenKeyError) => void\n ) {\n new WalletPicker({\n providers: this.discoveredProviders,\n onCancel: () => {\n reject({ code: 'USER_CANCELLED', message: 'User cancelled wallet selection' });\n },\n onSelect: async (provider) => {\n try {\n const accounts = await provider.request({ method: 'eth_requestAccounts' }) as string[];\n const address = accounts[0];\n if (!address) throw new Error('No account returned');\n const result = { address, keyId: `external:${address}`, keyType: 'EXTERNAL' as const };\n this.lastAuth = result;\n resolve(result as T);\n } catch (e: any) {\n reject({ code: 'UNKNOWN', message: e.message || 'Failed to connect wallet' });\n }\n },\n });\n }\n\n private openPopup<T>(\n url: string,\n message: object,\n resolve: (value: T) => void,\n reject: (error: OpenKeyError) => void\n ) {\n // Calculate popup position\n const left = window.screenX + (window.outerWidth - POPUP_WIDTH) / 2;\n const top = window.screenY + (window.outerHeight - POPUP_HEIGHT) / 2;\n\n this.popup = window.open(\n url,\n 'openkey',\n `width=${POPUP_WIDTH},height=${POPUP_HEIGHT},left=${left},top=${top},popup=true`\n );\n\n if (!this.popup) {\n showToast('Popup was blocked. Please allow popups for this site.', 'error');\n reject({\n code: 'POPUP_BLOCKED',\n message: 'Popup was blocked. Please allow popups for this site.',\n });\n return;\n }\n\n const cleanup = () => {\n window.removeEventListener('message', handleMessage);\n clearInterval(pollClosed);\n clearTimeout(timeout);\n };\n\n // Poll to detect popup close\n const pollClosed = setInterval(() => {\n if (this.popup?.closed) {\n cleanup();\n reject({\n code: 'USER_CANCELLED',\n message: 'User closed the popup',\n });\n }\n }, 500);\n\n // Timeout\n const timeout = setTimeout(() => {\n cleanup();\n this.popup?.close();\n reject({\n code: 'TIMEOUT',\n message: 'Request timed out',\n });\n }, DEFAULT_TIMEOUT);\n\n // Listen for messages\n const handleMessage = (event: MessageEvent) => {\n if (event.origin !== this.host) return;\n if (event.source !== this.popup) return;\n\n const data = event.data as MessageType;\n\n if (data.type === 'openkey:ready') {\n // Widget is ready, send our request\n this.popup?.postMessage(message, this.host);\n return;\n }\n\n if (data.type === 'openkey:close') {\n cleanup();\n this.popup?.close();\n reject({\n code: 'USER_CANCELLED',\n message: 'User cancelled the request',\n });\n return;\n }\n\n if (data.type === 'openkey:auth:use-external-wallet') {\n cleanup();\n this.popup?.close();\n this.handleExternalWalletConnect<T>(resolve, reject);\n return;\n }\n\n // Handle responses\n if (\n data.type === 'openkey:auth:response' ||\n data.type === 'openkey:sign:response' ||\n data.type === 'openkey:signTypedData:response' ||\n data.type === 'openkey:link-wallet:response'\n ) {\n cleanup();\n this.popup?.close();\n\n if (data.success) {\n if (data.type === 'openkey:auth:response') {\n if (data.sessionToken) this.sessionToken = data.sessionToken;\n resolve({ address: data.address, keyId: data.keyId, keyType: data.keyType || 'MANAGED' } as T);\n } else if (data.type === 'openkey:link-wallet:response') {\n resolve({ address: data.address, keyId: data.keyId } as T);\n } else {\n resolve({ signature: data.signature, address: data.address } as T);\n }\n } else {\n reject(data.error);\n }\n }\n };\n\n window.addEventListener('message', handleMessage);\n }\n\n /**\n * Disconnect and close any open flows\n */\n disconnect() {\n this.popup?.close();\n this.popup = null;\n }\n}\n\n/**\n * EIP-1193 compatible provider that wraps an OpenKey instance.\n * Transparently routes signing to either OpenKey (managed keys) or the user's\n * wallet (external keys).\n */\nexport class OpenKeyProvider implements EIP1193Provider {\n private openkey: OpenKey;\n private address: string;\n private keyId: string;\n private keyType: 'MANAGED' | 'EXTERNAL';\n\n constructor(openkey: OpenKey, authResult: AuthResult) {\n this.openkey = openkey;\n this.address = authResult.address;\n this.keyId = authResult.keyId;\n this.keyType = authResult.keyType;\n }\n\n async request({ method, params }: { method: string; params?: any[] }): Promise<any> {\n switch (method) {\n case 'eth_accounts':\n case 'eth_requestAccounts':\n return [this.address];\n\n case 'eth_chainId':\n return '0x1'; // mainnet\n\n case 'personal_sign': {\n if (this.keyType === 'EXTERNAL') {\n try {\n const provider = await this.openkey.findWalletProvider(this.address);\n return await provider.request({ method, params });\n } catch (e: any) {\n showToast(e?.message || 'External wallet signing failed', 'error');\n throw e;\n }\n }\n // Managed key: route through OpenKey\n const message = this.hexToString(params![0] as string);\n const result = await this.openkey.signMessage({ message, keyId: this.keyId });\n return result.signature;\n }\n\n case 'eth_signTypedData_v4': {\n if (this.keyType === 'EXTERNAL') {\n try {\n const provider = await this.openkey.findWalletProvider(this.address);\n return await provider.request({ method, params });\n } catch (e: any) {\n showToast(e?.message || 'External wallet signing failed', 'error');\n throw e;\n }\n }\n const data = JSON.parse(params![1] as string);\n const result = await this.openkey.signTypedData(data);\n return result.signature;\n }\n\n default:\n throw new Error(`Unsupported method: ${method}`);\n }\n }\n\n private hexToString(hex: string): string {\n const bytes = new Uint8Array(\n (hex.startsWith('0x') ? hex.slice(2) : hex).match(/.{1,2}/g)!.map(b => parseInt(b, 16))\n );\n return new TextDecoder().decode(bytes);\n }\n}\n\n// Default export for convenience\nexport default OpenKey;\n\n// Create singleton instance\nlet defaultInstance: OpenKey | null = null;\n\nexport function getOpenKey(config?: OpenKeyConfig): OpenKey {\n if (!defaultInstance || config) {\n defaultInstance = new OpenKey(config);\n }\n return defaultInstance;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA,kBAKO;AAsHP,IAAM,eAAe;AACrB,IAAM,cAAc;AACpB,IAAM,eAAe;AACrB,IAAM,kBAAkB,IAAI,KAAK;AACjC,IAAM,uBAAuB;AAC7B,IAAM,oBAAoB;AAE1B,IAAM,cAAN,MAAkB;AAAA,EACR;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EAER,YAAY,MAAkG;AAC5G,SAAK,OAAO,KAAK;AACjB,SAAK,UAAU,KAAK;AACpB,SAAK,YAAY,KAAK;AAEtB,UAAM,WAAW,OAAO,WAAW,oBAAoB,EAAE;AAEzD,SAAK,OAAO,SAAS,cAAc,KAAK;AACxC,SAAK,SAAS,KAAK,KAAK,aAAa,EAAE,MAAM,SAAS,CAAC;AAEvD,UAAM,QAAQ,SAAS,cAAc,OAAO;AAC5C,UAAM,cAAc;AAAA;AAAA,gHAEwF,WAAW,aAAa,QAAQ;AAAA,4DACpF,WAAW,SAAS,OAAO,kBAAkB,WAAW,kBAAkB,MAAM,4FAA4F,WAAW,+BAA+B,4BAA4B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,gDAM9P,WAAW,gCAAgC,4BAA4B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AASnH,UAAM,WAAW,SAAS,cAAc,KAAK;AAC7C,aAAS,YAAY;AACrB,aAAS,iBAAiB,SAAS,CAAC,MAAM;AACxC,UAAI,EAAE,WAAW,SAAU,MAAK,MAAM;AAAA,IACxC,CAAC;AAED,UAAM,OAAO,SAAS,cAAc,KAAK;AACzC,SAAK,YAAY;AAEjB,QAAI,UAAU;AACZ,YAAM,SAAS,SAAS,cAAc,KAAK;AAC3C,aAAO,YAAY;AACnB,WAAK,YAAY,MAAM;AAAA,IACzB;AAEA,UAAM,WAAW,SAAS,cAAc,QAAQ;AAChD,aAAS,YAAY;AACrB,aAAS,cAAc;AACvB,aAAS,iBAAiB,SAAS,MAAM,KAAK,MAAM,CAAC;AACrD,SAAK,YAAY,QAAQ;AAEzB,SAAK,SAAS,SAAS,cAAc,QAAQ;AAC7C,SAAK,OAAO,MAAM,KAAK;AACvB,SAAK,OAAO,aAAa,SAAS,gFAAgF;AAClH,SAAK,OAAO,aAAa,WAAW,yFAAyF;AAC7H,SAAK,YAAY,KAAK,MAAM;AAE5B,aAAS,YAAY,IAAI;AACzB,SAAK,OAAO,YAAY,KAAK;AAC7B,SAAK,OAAO,YAAY,QAAQ;AAEhC,SAAK,iBAAiB,CAAC,UAAwB;AAC7C,UAAI,MAAM,WAAW,KAAK,KAAM;AAChC,UAAI,MAAM,WAAW,KAAK,OAAO,cAAe;AAChD,YAAM,OAAO,MAAM;AACnB,UAAI,KAAK,SAAS,kBAAkB;AAClC,cAAM,IAAI,KAAK,IAAI,KAAK,QAAQ,KAAK,MAAM,OAAO,cAAc,IAAI,CAAC;AACrE,aAAK,OAAO,MAAM,SAAS,GAAG,CAAC;AAC/B;AAAA,MACF;AACA,WAAK,UAAU,IAAI;AAAA,IACrB;AACA,WAAO,iBAAiB,WAAW,KAAK,cAAc;AACtD,aAAS,KAAK,YAAY,KAAK,IAAI;AAAA,EACrC;AAAA,EAEA,YAAY,SAAiB;AAC3B,SAAK,OAAO,eAAe,YAAY,SAAS,KAAK,IAAI;AAAA,EAC3D;AAAA,EAEA,UAAU;AACR,WAAO,oBAAoB,WAAW,KAAK,cAAc;AACzD,SAAK,KAAK,OAAO;AAAA,EACnB;AAAA,EAEQ,QAAQ;AACd,UAAM,WAAW,KAAK,OAAO,cAAc,cAAc;AACzD,QAAI,UAAU;AACZ,eAAS,UAAU,IAAI,SAAS;AAChC,iBAAW,MAAM;AACf,aAAK,QAAQ;AACb,aAAK,QAAQ;AAAA,MACf,GAAG,GAAG;AAAA,IACR,OAAO;AACL,WAAK,QAAQ;AACb,WAAK,QAAQ;AAAA,IACf;AAAA,EACF;AACF;AAEA,IAAM,eAAN,MAAmB;AAAA,EACT;AAAA,EACA;AAAA,EAER,YAAY,MAAmH;AAC7H,SAAK,OAAO,SAAS,cAAc,KAAK;AACxC,SAAK,SAAS,KAAK,KAAK,aAAa,EAAE,MAAM,SAAS,CAAC;AAEvD,UAAM,QAAQ,SAAS,cAAc,OAAO;AAC5C,UAAM,cAAc;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAyBpB,UAAM,WAAW,SAAS,cAAc,KAAK;AAC7C,aAAS,YAAY;AACrB,aAAS,iBAAiB,SAAS,CAAC,MAAM;AAAE,UAAI,EAAE,WAAW,UAAU;AAAE,aAAK,QAAQ;AAAG,aAAK,SAAS;AAAA,MAAG;AAAA,IAAE,CAAC;AAE7G,UAAM,OAAO,SAAS,cAAc,KAAK;AACzC,SAAK,YAAY;AAEjB,UAAM,QAAQ,SAAS,cAAc,IAAI;AACzC,UAAM,YAAY;AAClB,UAAM,cAAc;AACpB,SAAK,YAAY,KAAK;AAEtB,QAAI,KAAK,UAAU,WAAW,GAAG;AAC/B,YAAM,QAAQ,SAAS,cAAc,KAAK;AAC1C,YAAM,YAAY;AAClB,YAAM,cAAc;AACpB,WAAK,YAAY,KAAK;AAAA,IACxB,OAAO;AACL,YAAM,OAAO,SAAS,cAAc,IAAI;AACxC,WAAK,YAAY;AACjB,iBAAW,EAAE,MAAM,SAAS,KAAK,KAAK,WAAW;AAC/C,cAAM,OAAO,SAAS,cAAc,QAAQ;AAC5C,aAAK,YAAY;AACjB,YAAI,KAAK,MAAM;AACb,gBAAM,OAAO,SAAS,cAAc,KAAK;AACzC,eAAK,YAAY;AACjB,eAAK,MAAM,KAAK;AAChB,eAAK,MAAM,KAAK;AAChB,eAAK,YAAY,IAAI;AAAA,QACvB;AACA,cAAM,OAAO,SAAS,cAAc,MAAM;AAC1C,aAAK,cAAc,KAAK;AACxB,aAAK,YAAY,IAAI;AACrB,aAAK,iBAAiB,SAAS,MAAM;AAAE,eAAK,QAAQ;AAAG,eAAK,SAAS,QAAQ;AAAA,QAAG,CAAC;AACjF,aAAK,YAAY,IAAI;AAAA,MACvB;AACA,WAAK,YAAY,IAAI;AAAA,IACvB;AAEA,UAAM,SAAS,SAAS,cAAc,QAAQ;AAC9C,WAAO,YAAY;AACnB,WAAO,cAAc;AACrB,WAAO,iBAAiB,SAAS,MAAM;AAAE,WAAK,QAAQ;AAAG,WAAK,SAAS;AAAA,IAAG,CAAC;AAC3E,SAAK,YAAY,MAAM;AAEvB,aAAS,YAAY,IAAI;AACzB,SAAK,OAAO,YAAY,KAAK;AAC7B,SAAK,OAAO,YAAY,QAAQ;AAChC,aAAS,KAAK,YAAY,KAAK,IAAI;AAAA,EACrC;AAAA,EAEA,UAAU;AACR,SAAK,KAAK,OAAO;AAAA,EACnB;AACF;AAEA,SAAS,UAAU,UAAU,+BAA+B,UAA4B,QAAQ;AAC9F,QAAM,KAAK,YAAY,UAAU,YAAY;AAC7C,QAAM,OAAO,SAAS,cAAc,KAAK;AACzC,QAAM,SAAS,KAAK,aAAa,EAAE,MAAM,SAAS,CAAC;AACnD,SAAO,YAAY,oGAAoG,EAAE,kTAAkT,OAAO;AAClb,WAAS,KAAK,YAAY,IAAI;AAC9B,aAAW,MAAM,KAAK,OAAO,GAAG,GAAI;AACtC;AAEA,IAAM,sBAAN,cAAkC,MAAM;AAAA,EACtC,YAAY,SAAiB;AAC3B,UAAM,OAAO;AACb,SAAK,OAAO;AAAA,EACd;AACF;AAEO,IAAM,UAAN,MAAc;AAAA,EACX;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,QAAuB;AAAA,EACvB,WAA8B;AAAA,EAC9B,sBAA+C,CAAC;AAAA,EAChD,eAA8B;AAAA,EAEtC,YAAY,SAAwB,CAAC,GAAG;AACtC,SAAK,SAAS;AACd,SAAK,OAAO,OAAO,QAAQ;AAC3B,SAAK,YAAY,OAAO,aAAa,KAAK,gBAAgB,KAAK,IAAI;AACnE,SAAK,UAAU,OAAO,WAAW,OAAO,SAAS;AACjD,SAAK,OAAO,OAAO,QAAQ;AAG3B,QAAI,OAAO,WAAW,aAAa;AACjC,WAAK,sBAAsB,CAAC;AAC5B,aAAO,iBAAiB,4BAA4B,CAAC,UAAe;AAClE,aAAK,oBAAoB,KAAK,MAAM,MAAM;AAAA,MAC5C,CAAC;AACD,aAAO,cAAc,IAAI,MAAM,yBAAyB,CAAC;AAAA,IAC3D;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOQ,gBAAgB,MAAsB;AAC5C,QAAI;AACF,YAAM,MAAM,IAAI,IAAI,IAAI;AACxB,UAAI,IAAI,aAAa,eAAe,IAAI,aAAa,aAAa;AAChE,eAAO,KAAK,QAAQ,OAAO,EAAE;AAAA,MAC/B;AACA,UAAI,WAAW,SAAS,IAAI;AAC5B,aAAO,IAAI,SAAS,EAAE,QAAQ,OAAO,EAAE;AAAA,IACzC,QAAQ;AACN,aAAO;AAAA,IACT;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MAAM,QAAQ,MAAoD;AAChE,UAAM,SAAS,MAAM,KAAK,SAAqB,WAAW;AAAA,MACxD,MAAM;AAAA,MACN,SAAS,KAAK;AAAA,IAChB,GAAG,MAAM,IAAI;AACb,SAAK,WAAW;AAChB,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,kBAAiC;AAC/B,WAAO,KAAK;AAAA,EACd;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,0BAAsE;AACpE,WAAO;AAAA,MACL,UAAU,GAAG,KAAK,SAAS;AAAA,MAC3B,OAAO,KAAK;AAAA,IACd;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MAAM,WAAW,MAA4E;AAC3F,WAAO,KAAK,SAA6C,eAAe;AAAA,MACtE,MAAM;AAAA,IACR,GAAG,MAAM,IAAI;AAAA,EACf;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MAAM,YAAY,SAA6B,MAAoD;AACjG,QAAI,KAAK,UAAU,YAAY,YAAY;AACzC,aAAO,KAAK,uBAAuB,OAAO;AAAA,IAC5C;AACA,WAAO,KAAK,gBAAgB,SAAS,MAAM,IAAI;AAAA,EACjD;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MAAM,cAAc,SAA+B,MAAoD;AACrG,QAAI,KAAK,UAAU,YAAY,YAAY;AACzC,aAAO,KAAK,gCAAgC,OAAO;AAAA,IACrD;AACA,WAAO,KAAK,yBAAyB,SAAS,MAAM,IAAI;AAAA,EAC1D;AAAA,EAEQ,qBAAwC;AAC9C,UAAM,YAA+B,CAAC;AACtC,QAAI,KAAK,OAAO,kBAAkB;AAChC,gBAAU,KAAK,KAAK,OAAO,gBAAgB;AAAA,IAC7C;AACA,cAAU,KAAK,GAAG,KAAK,oBAAoB,IAAI,CAAC,EAAE,SAAS,MAAM,QAAQ,CAAC;AAC1E,QAAI,OAAO,WAAW,eAAgB,OAAe,UAAU;AAC7D,gBAAU,KAAM,OAAe,QAA2B;AAAA,IAC5D;AACA,WAAO,CAAC,GAAG,IAAI,IAAI,SAAS,CAAC;AAAA,EAC/B;AAAA,EAEA,MAAc,mBACZ,UACA,QACA,eACkB;AAClB,QAAI;AACF,YAAM,WAAW,MAAM,SAAS,QAAQ,EAAE,OAAO,CAAC;AAClD,aAAO,SAAS,KAAK,CAAC,YAAY,QAAQ,YAAY,MAAM,cAAc,YAAY,CAAC;AAAA,IACzF,QAAQ;AACN,aAAO;AAAA,IACT;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAM,mBAAmB,eAAiD;AACxE,UAAM,YAAY,KAAK,mBAAmB;AAE1C,eAAW,YAAY,WAAW;AAChC,UAAI,MAAM,KAAK,mBAAmB,UAAU,gBAAgB,aAAa,GAAG;AAC1E,eAAO;AAAA,MACT;AAAA,IACF;AAEA,eAAW,YAAY,WAAW;AAChC,UAAI,MAAM,KAAK,mBAAmB,UAAU,uBAAuB,aAAa,GAAG;AACjF,eAAO;AAAA,MACT;AAAA,IACF;AAEA,UAAM,IAAI,oBAAoB,iFAAiF;AAAA,EACjH;AAAA,EAEA,MAAc,uBAAuB,SAAkD;AACrF,QAAI;AACJ,QAAI;AACF,iBAAW,MAAM,KAAK,mBAAmB,KAAK,SAAU,OAAO;AAAA,IACjE,SAAS,GAAG;AACV,gBAAW,EAAY,SAAS,OAAO;AACvC,YAAM;AAAA,IACR;AACA,QAAI;AACF,YAAM,aAAa,KAAK,MAAM,QAAQ,OAAO;AAC7C,YAAM,YAAY,MAAM,SAAS,QAAQ;AAAA,QACvC,QAAQ;AAAA,QACR,QAAQ,CAAC,YAAY,KAAK,SAAU,OAAO;AAAA,MAC7C,CAAC;AACD,aAAO,EAAE,WAAgC,SAAS,KAAK,SAAU,QAAQ;AAAA,IAC3E,SAAS,GAAQ;AACf,YAAM,MAAM,GAAG,SAAS,SAAS,qBAAqB,IAClD,sFACA,GAAG,WAAW;AAClB,gBAAU,KAAK,OAAO;AACtB,YAAM,IAAI,MAAM,GAAG;AAAA,IACrB;AAAA,EACF;AAAA,EAEA,MAAc,gCAAgC,SAAoD;AAChG,QAAI;AACJ,QAAI;AACF,iBAAW,MAAM,KAAK,mBAAmB,KAAK,SAAU,OAAO;AAAA,IACjE,SAAS,GAAG;AACV,gBAAW,EAAY,SAAS,OAAO;AACvC,YAAM;AAAA,IACR;AACA,QAAI;AACF,YAAM,YAAY,MAAM,SAAS,QAAQ;AAAA,QACvC,QAAQ;AAAA,QACR,QAAQ,CAAC,KAAK,SAAU,SAAS,KAAK,UAAU,OAAO,CAAC;AAAA,MAC1D,CAAC;AACD,aAAO,EAAE,WAAgC,SAAS,KAAK,SAAU,QAAQ;AAAA,IAC3E,SAAS,GAAQ;AACf,YAAM,MAAM,GAAG,SAAS,SAAS,qBAAqB,IAClD,sFACA,GAAG,WAAW;AAClB,gBAAU,KAAK,OAAO;AACtB,YAAM,IAAI,MAAM,GAAG;AAAA,IACrB;AAAA,EACF;AAAA,EAEQ,gBAAgB,SAA6B,MAAyC;AAC5F,WAAO,KAAK,SAAqB,QAAQ;AAAA,MACvC,MAAM;AAAA,MACN,SAAS,QAAQ;AAAA,MACjB,OAAO,QAAQ;AAAA,MACf,cAAc,KAAK,gBAAgB;AAAA,IACrC,GAAG,IAAI;AAAA,EACT;AAAA,EAEQ,yBAAyB,SAA+B,MAAyC;AACvG,WAAO,KAAK,SAAqB,mBAAmB;AAAA,MAClD,MAAM;AAAA,MACN,MAAM;AAAA,MACN,cAAc,KAAK,gBAAgB;AAAA,IACrC,GAAG,IAAI;AAAA,EACT;AAAA,EAEQ,MAAM,KAAqB;AACjC,WAAO,OAAO,MAAM,KAAK,IAAI,YAAY,EAAE,OAAO,GAAG,CAAC,EAAE,IAAI,OAAK,EAAE,SAAS,EAAE,EAAE,SAAS,GAAG,GAAG,CAAC,EAAE,KAAK,EAAE;AAAA,EAC3G;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,cAAgC;AAEpC,QAAI;AACF,YAAM,MAAM,MAAM,MAAM,GAAG,KAAK,IAAI,qBAAqB;AAAA,QACvD,aAAa;AAAA,MACf,CAAC;AACD,UAAI,CAAC,IAAI,GAAI,QAAO;AACpB,YAAM,OAAO,MAAM,IAAI,KAAK;AAC5B,aAAO,CAAC,CAAC,KAAK;AAAA,IAChB,QAAQ;AACN,aAAO;AAAA,IACT;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,QAAQ;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAMN,SAAS,OAAO,WAA8C;AAE5D,YAAM,eAAW,kCAAqB;AACtC,YAAM,YAAY,UAAM,mCAAsB,QAAQ;AACtD,YAAM,QAAQ,OAAO,aAAS,2BAAc;AAG5C,qBAAe;AAAA,QACb;AAAA,QACA,KAAK,UAAU,EAAE,UAAU,MAAM,CAAC;AAAA,MACpC;AAGA,YAAM,cAAU,mCAAsB;AAAA,QACpC,MAAM,KAAK;AAAA,QACX,UAAU,OAAO;AAAA,QACjB,aAAa,OAAO;AAAA,QACpB,eAAe;AAAA,QACf;AAAA,QACA,QAAQ,CAAC,QAAQ;AAAA,MACnB,CAAC;AAED,aAAO,KAAK,cAAc,SAAS,OAAO,OAAO,WAAW;AAAA,IAC9D;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IASA,cAAc,OACZ,MACA,WACgC;AAChC,YAAM,SAAS,eAAe,QAAQ,iBAAiB;AACvD,UAAI,CAAC,QAAQ;AACX,cAAM,IAAI,MAAM,iDAAiD;AAAA,MACnE;AAEA,YAAM,EAAE,SAAS,IAAI,KAAK,MAAM,MAAM;AAEtC,YAAM,WAAW,MAAM,MAAM,GAAG,KAAK,SAAS,0BAA0B;AAAA,QACtE,QAAQ;AAAA,QACR,SAAS;AAAA,UACP,gBAAgB;AAAA,QAClB;AAAA,QACA,MAAM,IAAI,gBAAgB;AAAA,UACxB,YAAY;AAAA,UACZ;AAAA,UACA,cAAc,OAAO;AAAA,UACrB,WAAW,OAAO;AAAA,UAClB,eAAe;AAAA,QACjB,CAAC;AAAA,MACH,CAAC;AAGD,qBAAe,WAAW,iBAAiB;AAE3C,UAAI,CAAC,SAAS,IAAI;AAChB,cAAM,QAAQ,MAAM,SAAS,KAAK;AAClC,cAAM,IAAI,MAAM,MAAM,qBAAqB,uBAAuB;AAAA,MACpE;AAEA,aAAO,SAAS,KAAK;AAAA,IACvB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAQA,aAAa,CAAC,kBAAmC;AAC/C,YAAM,SAAS,eAAe,QAAQ,iBAAiB;AACvD,UAAI,CAAC,OAAQ,QAAO;AACpB,YAAM,EAAE,MAAM,IAAI,KAAK,MAAM,MAAM;AACnC,aAAO,UAAU;AAAA,IACnB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAOA,eAAe,CACb,QACmF;AACnF,YAAM,SAAS,IAAI,IAAI,OAAO,OAAO,SAAS,IAAI;AAClD,YAAM,QAAQ,OAAO,aAAa,IAAI,OAAO;AAE7C,UAAI,OAAO;AACT,eAAO;AAAA,UACL;AAAA,UACA,kBAAkB,OAAO,aAAa,IAAI,mBAAmB,KAAK;AAAA,QACpE;AAAA,MACF;AAEA,YAAM,OAAO,OAAO,aAAa,IAAI,MAAM;AAC3C,YAAM,QAAQ,OAAO,aAAa,IAAI,OAAO;AAE7C,UAAI,CAAC,QAAQ,CAAC,OAAO;AACnB,eAAO,EAAE,OAAO,kBAAkB,kBAAkB,kCAAkC;AAAA,MACxF;AAEA,aAAO,EAAE,MAAM,MAAM;AAAA,IACvB;AAAA,EACF;AAAA,EAEQ,cACN,KACA,OACA,aACsB;AACtB,WAAO,IAAI,QAAQ,CAAC,SAAS,WAAW;AACtC,UAAI,KAAK,SAAS,YAAY;AAC5B,aAAK,eAAe,KAAK,OAAO,aAAa,SAAS,MAAM;AAAA,MAC9D,OAAO;AAEL,eAAO,SAAS,OAAO;AAAA,MACzB;AAAA,IACF,CAAC;AAAA,EACH;AAAA,EAEQ,eACN,KACA,OACA,aACA,SACA,QACA;AACA,UAAM,OAAO,OAAO,WAAW,OAAO,aAAa,eAAe;AAClE,UAAM,MAAM,OAAO,WAAW,OAAO,cAAc,gBAAgB;AAEnE,SAAK,QAAQ,OAAO;AAAA,MAClB;AAAA,MACA;AAAA,MACA,SAAS,WAAW,WAAW,YAAY,SAAS,IAAI,QAAQ,GAAG;AAAA,IACrE;AAEA,QAAI,CAAC,KAAK,OAAO;AACf,gBAAU,yDAAyD,OAAO;AAC1E,aAAO;AAAA,QACL,MAAM;AAAA,QACN,SAAS;AAAA,MACX,CAAC;AACD;AAAA,IACF;AAEA,UAAM,eAAe,IAAI,IAAI,WAAW,EAAE;AAG1C,UAAM,eAAe,YAAY,MAAM;AACrC,UAAI;AACF,YAAI,KAAK,OAAO,QAAQ;AACtB,wBAAc,YAAY;AAC1B,uBAAa,OAAO;AACpB,iBAAO;AAAA,YACL,MAAM;AAAA,YACN,SAAS;AAAA,UACX,CAAC;AACD;AAAA,QACF;AAGA,cAAM,WAAW,KAAK,OAAO,UAAU;AACvC,YAAI,YAAY,SAAS,WAAW,YAAY,GAAG;AACjD,wBAAc,YAAY;AAC1B,uBAAa,OAAO;AAEpB,gBAAM,SAAS,IAAI,IAAI,QAAQ;AAC/B,gBAAM,OAAO,OAAO,aAAa,IAAI,MAAM;AAC3C,gBAAM,gBAAgB,OAAO,aAAa,IAAI,OAAO;AACrD,gBAAM,QAAQ,OAAO,aAAa,IAAI,OAAO;AAE7C,eAAK,OAAO,MAAM;AAElB,cAAI,OAAO;AACT,mBAAO;AAAA,cACL,MAAM;AAAA,cACN,SAAS,OAAO,aAAa,IAAI,mBAAmB,KAAK;AAAA,YAC3D,CAAC;AACD;AAAA,UACF;AAEA,cAAI,kBAAkB,OAAO;AAC3B,mBAAO;AAAA,cACL,MAAM;AAAA,cACN,SAAS;AAAA,YACX,CAAC;AACD;AAAA,UACF;AAEA,cAAI,MAAM;AACR,oBAAQ,EAAE,MAAM,OAAO,cAAc,CAAC;AAAA,UACxC,OAAO;AACL,mBAAO;AAAA,cACL,MAAM;AAAA,cACN,SAAS;AAAA,YACX,CAAC;AAAA,UACH;AAAA,QACF;AAAA,MACF,QAAQ;AAAA,MAER;AAAA,IACF,GAAG,GAAG;AAGN,UAAM,UAAU,WAAW,MAAM;AAC/B,oBAAc,YAAY;AAC1B,WAAK,OAAO,MAAM;AAClB,aAAO;AAAA,QACL,MAAM;AAAA,QACN,SAAS;AAAA,MACX,CAAC;AAAA,IACH,GAAG,eAAe;AAAA,EACpB;AAAA,EAEQ,YAAY,UAAqC;AACvD,WAAO,YAAY,KAAK;AAAA,EAC1B;AAAA,EAEQ,iBAA0B;AAChC,QAAI,KAAK,oBAAoB,SAAS,EAAG,QAAO;AAChD,QAAI,OAAO,WAAW,eAAgB,OAAe,SAAU,QAAO;AACtE,WAAO;AAAA,EACT;AAAA,EAEA,MAAc,SAAY,QAAgB,SAAiB,cAAwC;AACjG,UAAM,OAAO,KAAK,YAAY,YAAY;AAC1C,UAAM,SAAS,mBAAmB,OAAO,SAAS,MAAM;AACxD,UAAM,UAAU,WAAW,aAAa,KAAK,eAAe,IAAI,iBAAiB;AAEjF,QAAI,SAAS,SAAS;AACpB,YAAMA,OAAM,GAAG,KAAK,IAAI,WAAW,MAAM,WAAW,MAAM,GAAG,OAAO;AACpE,aAAO,IAAI,QAAQ,CAAC,SAAS,WAAW,KAAK,UAAUA,MAAK,SAAS,SAAS,MAAM,CAAC;AAAA,IACvF;AAEA,QAAI,SAAS,YAAY;AACvB,YAAMA,OAAM,GAAG,KAAK,IAAI,WAAW,MAAM,WAAW,MAAM,GAAG,OAAO;AACpE,aAAO,SAAS,OAAOA;AACvB,aAAO,IAAI,QAAQ,MAAM;AAAA,MAAC,CAAC;AAAA,IAC7B;AAGA,UAAM,MAAM,GAAG,KAAK,IAAI,iBAAiB,MAAM,WAAW,MAAM,GAAG,OAAO;AAC1E,WAAO,KAAK,gBAAmB,KAAK,QAAQ,SAAS,MAAM;AAAA,EAC7D;AAAA,EAEQ,gBAAmB,KAAa,QAAgB,SAAiB,QAA4B;AACnG,WAAO,IAAI,QAAQ,CAAC,SAAS,WAAW;AACtC,UAAI,gBAAgB;AACpB,UAAI,UAAU;AACd,UAAI,QAA4B;AAEhC,YAAM,SAAS,CAAC,OAAmB;AACjC,YAAI,QAAS;AACb,kBAAU;AACV,WAAG;AAAA,MACL;AAEA,YAAM,UAAU,MAAM;AACpB,qBAAa,YAAY;AACzB,qBAAa,cAAc;AAC3B,eAAO,QAAQ;AACf,gBAAQ;AAAA,MACV;AAEA,cAAQ,IAAI,YAAY;AAAA,QACtB;AAAA,QACA,MAAM,KAAK;AAAA,QACX,SAAS,MAAM;AACb,iBAAO,MAAM;AACX,yBAAa,YAAY;AACzB,yBAAa,cAAc;AAC3B,oBAAQ;AACR,mBAAO,EAAE,MAAM,kBAAkB,SAAS,6BAA6B,CAAiB;AAAA,UAC1F,CAAC;AAAA,QACH;AAAA,QACA,WAAW,CAAC,SAAsB;AAChC,cAAI,KAAK,SAAS,iBAAiB;AACjC,4BAAgB;AAChB,mBAAO,YAAY,OAAO;AAC1B;AAAA,UACF;AAEA,cAAI,KAAK,SAAS,iBAAiB;AACjC,mBAAO,MAAM;AACX,sBAAQ;AACR,qBAAO,EAAE,MAAM,kBAAkB,SAAS,6BAA6B,CAAiB;AAAA,YAC1F,CAAC;AACD;AAAA,UACF;AAEA,cAAI,KAAK,SAAS,gCAAgC;AAChD,iBAAK,2BAA2B,KAAM;AACtC;AAAA,UACF;AAEA,cAAI,KAAK,SAAS,oCAAoC;AACpD,oBAAQ;AACR,iBAAK,4BAA+B,SAAS,MAAM;AACnD;AAAA,UACF;AAEA,cACE,KAAK,SAAS,2BACd,KAAK,SAAS,2BACd,KAAK,SAAS,oCACd,KAAK,SAAS,gCACd;AACA,mBAAO,MAAM;AACX,sBAAQ;AACR,kBAAI,KAAK,SAAS;AAChB,oBAAI,KAAK,SAAS,yBAAyB;AACzC,sBAAI,KAAK,aAAc,MAAK,eAAe,KAAK;AAChD,0BAAQ,EAAE,SAAS,KAAK,SAAS,OAAO,KAAK,OAAO,SAAS,KAAK,WAAW,UAAU,CAAM;AAAA,gBAC/F,WAAW,KAAK,SAAS,gCAAgC;AACvD,0BAAQ,EAAE,SAAS,KAAK,SAAS,OAAO,KAAK,MAAM,CAAM;AAAA,gBAC3D,OAAO;AACL,0BAAQ,EAAE,WAAW,KAAK,WAAW,SAAS,KAAK,QAAQ,CAAM;AAAA,gBACnE;AAAA,cACF,OAAO;AACL,uBAAO,KAAK,KAAK;AAAA,cACnB;AAAA,YACF,CAAC;AAAA,UACH;AAAA,QACF;AAAA,MACF,CAAC;AAGD,YAAM,eAAe,WAAW,MAAM;AACpC,YAAI,iBAAiB,QAAS;AAC9B,gBAAQ;AACR,gBAAQ,KAAK,sGAAsG;AACnH,kBAAU;AACV,cAAM,WAAW,GAAG,KAAK,IAAI,WAAW,MAAM,WAAW,MAAM;AAC/D,aAAK,UAAU,UAAU,SAAS,CAAC,QAAa,OAAO,MAAM,QAAQ,GAAG,CAAC,GAAG,CAAC,QAAa,OAAO,MAAM,OAAO,GAAG,CAAC,CAAC;AAAA,MACrH,GAAG,oBAAoB;AAGvB,YAAM,iBAAiB,WAAW,MAAM;AACtC,eAAO,MAAM;AACX,kBAAQ;AACR,iBAAO,EAAE,MAAM,WAAW,SAAS,oBAAoB,CAAiB;AAAA,QAC1E,CAAC;AAAA,MACH,GAAG,eAAe;AAAA,IACpB,CAAC;AAAA,EACH;AAAA,EAEQ,2BAA2B,OAAoB;AACrD,UAAM,aAAa,CAAC,WAAwB,MAAM,YAAY,MAAM;AAEpE,QAAI,aAAa;AAAA,MACf,WAAW,KAAK;AAAA,MAChB,UAAU,MAAM;AACd,mBAAW,EAAE,MAAM,8BAA8B,SAAS,OAAO,OAAO,EAAE,MAAM,kBAAkB,SAAS,2BAA2B,EAAE,CAAC;AAAA,MAC3I;AAAA,MACA,UAAU,OAAO,aAAa;AAC5B,YAAI;AACF,gBAAM,WAAW,MAAM,SAAS,QAAQ,EAAE,QAAQ,sBAAsB,CAAC;AACzE,gBAAM,UAAU,SAAS,CAAC;AAC1B,cAAI,CAAC,QAAS,OAAM,IAAI,MAAM,qBAAqB;AAGnD,gBAAM,eAAe,MAAM,MAAM,GAAG,KAAK,IAAI,4BAA4B;AAAA,YACvE,QAAQ;AAAA,YACR,aAAa;AAAA,UACf,CAAC;AACD,cAAI,CAAC,aAAa,GAAI,OAAM,IAAI,MAAM,yBAAyB;AAC/D,gBAAM,EAAE,QAAQ,IAAI,MAAM,aAAa,KAAK;AAG5C,gBAAM,aAAa,KAAK,MAAM,OAAO;AACrC,gBAAM,YAAY,MAAM,SAAS,QAAQ;AAAA,YACvC,QAAQ;AAAA,YACR,QAAQ,CAAC,YAAY,OAAO;AAAA,UAC9B,CAAC;AAGD,gBAAM,UAAU,MAAM,MAAM,GAAG,KAAK,IAAI,kBAAkB;AAAA,YACxD,QAAQ;AAAA,YACR,SAAS,EAAE,gBAAgB,mBAAmB;AAAA,YAC9C,aAAa;AAAA,YACb,MAAM,KAAK,UAAU,EAAE,SAAS,WAAW,QAAQ,CAAC;AAAA,UACtD,CAAC;AACD,cAAI,CAAC,QAAQ,IAAI;AACf,kBAAM,MAAM,MAAM,QAAQ,KAAK;AAC/B,kBAAM,IAAI,MAAM,IAAI,SAAS,uBAAuB;AAAA,UACtD;AACA,gBAAM,EAAE,IAAI,IAAI,MAAM,QAAQ,KAAK;AAEnC,qBAAW,EAAE,MAAM,8BAA8B,SAAS,MAAM,SAAS,IAAI,SAAS,OAAO,IAAI,GAAG,CAAC;AAAA,QACvG,SAAS,GAAQ;AACf,qBAAW,EAAE,MAAM,8BAA8B,SAAS,OAAO,OAAO,EAAE,MAAM,WAAW,SAAS,EAAE,WAAW,wBAAwB,EAAE,CAAC;AAAA,QAC9I;AAAA,MACF;AAAA,IACF,CAAC;AAAA,EACH;AAAA,EAEQ,4BACN,SACA,QACA;AACA,QAAI,aAAa;AAAA,MACf,WAAW,KAAK;AAAA,MAChB,UAAU,MAAM;AACd,eAAO,EAAE,MAAM,kBAAkB,SAAS,kCAAkC,CAAC;AAAA,MAC/E;AAAA,MACA,UAAU,OAAO,aAAa;AAC5B,YAAI;AACF,gBAAM,WAAW,MAAM,SAAS,QAAQ,EAAE,QAAQ,sBAAsB,CAAC;AACzE,gBAAM,UAAU,SAAS,CAAC;AAC1B,cAAI,CAAC,QAAS,OAAM,IAAI,MAAM,qBAAqB;AACnD,gBAAM,SAAS,EAAE,SAAS,OAAO,YAAY,OAAO,IAAI,SAAS,WAAoB;AACrF,eAAK,WAAW;AAChB,kBAAQ,MAAW;AAAA,QACrB,SAAS,GAAQ;AACf,iBAAO,EAAE,MAAM,WAAW,SAAS,EAAE,WAAW,2BAA2B,CAAC;AAAA,QAC9E;AAAA,MACF;AAAA,IACF,CAAC;AAAA,EACH;AAAA,EAEQ,UACN,KACA,SACA,SACA,QACA;AAEA,UAAM,OAAO,OAAO,WAAW,OAAO,aAAa,eAAe;AAClE,UAAM,MAAM,OAAO,WAAW,OAAO,cAAc,gBAAgB;AAEnE,SAAK,QAAQ,OAAO;AAAA,MAClB;AAAA,MACA;AAAA,MACA,SAAS,WAAW,WAAW,YAAY,SAAS,IAAI,QAAQ,GAAG;AAAA,IACrE;AAEA,QAAI,CAAC,KAAK,OAAO;AACf,gBAAU,yDAAyD,OAAO;AAC1E,aAAO;AAAA,QACL,MAAM;AAAA,QACN,SAAS;AAAA,MACX,CAAC;AACD;AAAA,IACF;AAEA,UAAM,UAAU,MAAM;AACpB,aAAO,oBAAoB,WAAW,aAAa;AACnD,oBAAc,UAAU;AACxB,mBAAa,OAAO;AAAA,IACtB;AAGA,UAAM,aAAa,YAAY,MAAM;AACnC,UAAI,KAAK,OAAO,QAAQ;AACtB,gBAAQ;AACR,eAAO;AAAA,UACL,MAAM;AAAA,UACN,SAAS;AAAA,QACX,CAAC;AAAA,MACH;AAAA,IACF,GAAG,GAAG;AAGN,UAAM,UAAU,WAAW,MAAM;AAC/B,cAAQ;AACR,WAAK,OAAO,MAAM;AAClB,aAAO;AAAA,QACL,MAAM;AAAA,QACN,SAAS;AAAA,MACX,CAAC;AAAA,IACH,GAAG,eAAe;AAGlB,UAAM,gBAAgB,CAAC,UAAwB;AAC7C,UAAI,MAAM,WAAW,KAAK,KAAM;AAChC,UAAI,MAAM,WAAW,KAAK,MAAO;AAEjC,YAAM,OAAO,MAAM;AAEnB,UAAI,KAAK,SAAS,iBAAiB;AAEjC,aAAK,OAAO,YAAY,SAAS,KAAK,IAAI;AAC1C;AAAA,MACF;AAEA,UAAI,KAAK,SAAS,iBAAiB;AACjC,gBAAQ;AACR,aAAK,OAAO,MAAM;AAClB,eAAO;AAAA,UACL,MAAM;AAAA,UACN,SAAS;AAAA,QACX,CAAC;AACD;AAAA,MACF;AAEA,UAAI,KAAK,SAAS,oCAAoC;AACpD,gBAAQ;AACR,aAAK,OAAO,MAAM;AAClB,aAAK,4BAA+B,SAAS,MAAM;AACnD;AAAA,MACF;AAGA,UACE,KAAK,SAAS,2BACd,KAAK,SAAS,2BACd,KAAK,SAAS,oCACd,KAAK,SAAS,gCACd;AACA,gBAAQ;AACR,aAAK,OAAO,MAAM;AAElB,YAAI,KAAK,SAAS;AAChB,cAAI,KAAK,SAAS,yBAAyB;AACzC,gBAAI,KAAK,aAAc,MAAK,eAAe,KAAK;AAChD,oBAAQ,EAAE,SAAS,KAAK,SAAS,OAAO,KAAK,OAAO,SAAS,KAAK,WAAW,UAAU,CAAM;AAAA,UAC/F,WAAW,KAAK,SAAS,gCAAgC;AACvD,oBAAQ,EAAE,SAAS,KAAK,SAAS,OAAO,KAAK,MAAM,CAAM;AAAA,UAC3D,OAAO;AACL,oBAAQ,EAAE,WAAW,KAAK,WAAW,SAAS,KAAK,QAAQ,CAAM;AAAA,UACnE;AAAA,QACF,OAAO;AACL,iBAAO,KAAK,KAAK;AAAA,QACnB;AAAA,MACF;AAAA,IACF;AAEA,WAAO,iBAAiB,WAAW,aAAa;AAAA,EAClD;AAAA;AAAA;AAAA;AAAA,EAKA,aAAa;AACX,SAAK,OAAO,MAAM;AAClB,SAAK,QAAQ;AAAA,EACf;AACF;AAOO,IAAM,kBAAN,MAAiD;AAAA,EAC9C;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EAER,YAAY,SAAkB,YAAwB;AACpD,SAAK,UAAU;AACf,SAAK,UAAU,WAAW;AAC1B,SAAK,QAAQ,WAAW;AACxB,SAAK,UAAU,WAAW;AAAA,EAC5B;AAAA,EAEA,MAAM,QAAQ,EAAE,QAAQ,OAAO,GAAqD;AAClF,YAAQ,QAAQ;AAAA,MACd,KAAK;AAAA,MACL,KAAK;AACH,eAAO,CAAC,KAAK,OAAO;AAAA,MAEtB,KAAK;AACH,eAAO;AAAA;AAAA,MAET,KAAK,iBAAiB;AACpB,YAAI,KAAK,YAAY,YAAY;AAC/B,cAAI;AACF,kBAAM,WAAW,MAAM,KAAK,QAAQ,mBAAmB,KAAK,OAAO;AACnE,mBAAO,MAAM,SAAS,QAAQ,EAAE,QAAQ,OAAO,CAAC;AAAA,UAClD,SAAS,GAAQ;AACf,sBAAU,GAAG,WAAW,kCAAkC,OAAO;AACjE,kBAAM;AAAA,UACR;AAAA,QACF;AAEA,cAAM,UAAU,KAAK,YAAY,OAAQ,CAAC,CAAW;AACrD,cAAM,SAAS,MAAM,KAAK,QAAQ,YAAY,EAAE,SAAS,OAAO,KAAK,MAAM,CAAC;AAC5E,eAAO,OAAO;AAAA,MAChB;AAAA,MAEA,KAAK,wBAAwB;AAC3B,YAAI,KAAK,YAAY,YAAY;AAC/B,cAAI;AACF,kBAAM,WAAW,MAAM,KAAK,QAAQ,mBAAmB,KAAK,OAAO;AACnE,mBAAO,MAAM,SAAS,QAAQ,EAAE,QAAQ,OAAO,CAAC;AAAA,UAClD,SAAS,GAAQ;AACf,sBAAU,GAAG,WAAW,kCAAkC,OAAO;AACjE,kBAAM;AAAA,UACR;AAAA,QACF;AACA,cAAM,OAAO,KAAK,MAAM,OAAQ,CAAC,CAAW;AAC5C,cAAM,SAAS,MAAM,KAAK,QAAQ,cAAc,IAAI;AACpD,eAAO,OAAO;AAAA,MAChB;AAAA,MAEA;AACE,cAAM,IAAI,MAAM,uBAAuB,MAAM,EAAE;AAAA,IACnD;AAAA,EACF;AAAA,EAEQ,YAAY,KAAqB;AACvC,UAAM,QAAQ,IAAI;AAAA,OACf,IAAI,WAAW,IAAI,IAAI,IAAI,MAAM,CAAC,IAAI,KAAK,MAAM,SAAS,EAAG,IAAI,OAAK,SAAS,GAAG,EAAE,CAAC;AAAA,IACxF;AACA,WAAO,IAAI,YAAY,EAAE,OAAO,KAAK;AAAA,EACvC;AACF;AAGA,IAAO,gBAAQ;AAGf,IAAI,kBAAkC;AAE/B,SAAS,WAAW,QAAiC;AAC1D,MAAI,CAAC,mBAAmB,QAAQ;AAC9B,sBAAkB,IAAI,QAAQ,MAAM;AAAA,EACtC;AACA,SAAO;AACT;","names":["url"]}
|
package/dist/index.mjs
CHANGED
|
@@ -29,7 +29,7 @@ var IframeModal = class {
|
|
|
29
29
|
const style = document.createElement("style");
|
|
30
30
|
style.textContent = `
|
|
31
31
|
:host{all:initial}
|
|
32
|
-
.ok-backdrop{position:fixed;inset:0;background:rgba(0,0,0,0.
|
|
32
|
+
.ok-backdrop{position:fixed;inset:0;background:rgba(0,0,0,0.42);z-index:999999;display:flex;align-items:${isMobile ? "flex-end" : "center"};justify-content:center;animation:ok-fade-in 150ms ease-out}
|
|
33
33
|
.ok-card{position:relative;background:#fafafa;width:${isMobile ? "100%" : "400px"};border-radius:${isMobile ? "16px 16px 0 0" : "16px"};box-shadow:0 25px 50px -12px rgba(0,0,0,0.25);overflow:hidden;overflow-y:auto;animation:${isMobile ? "ok-slide-up 250ms ease-out" : "ok-scale-in 200ms ease-out"};max-height:90vh}
|
|
34
34
|
.ok-close{position:absolute;top:8px;right:8px;width:24px;height:24px;border:none;background:transparent;color:#6b7280;font-size:18px;cursor:pointer;z-index:1;display:flex;align-items:center;justify-content:center;border-radius:4px}
|
|
35
35
|
.ok-close:hover{color:#111827}
|
|
@@ -63,8 +63,8 @@ var IframeModal = class {
|
|
|
63
63
|
card.appendChild(closeBtn);
|
|
64
64
|
this.iframe = document.createElement("iframe");
|
|
65
65
|
this.iframe.src = opts.url;
|
|
66
|
-
this.iframe.setAttribute("allow", "publickey-credentials-get *; publickey-credentials-create *");
|
|
67
|
-
this.iframe.setAttribute("sandbox", "allow-scripts allow-same-origin allow-forms allow-popups");
|
|
66
|
+
this.iframe.setAttribute("allow", "clipboard-write *; publickey-credentials-get *; publickey-credentials-create *");
|
|
67
|
+
this.iframe.setAttribute("sandbox", "allow-scripts allow-same-origin allow-forms allow-popups allow-popups-to-escape-sandbox");
|
|
68
68
|
card.appendChild(this.iframe);
|
|
69
69
|
backdrop.appendChild(card);
|
|
70
70
|
this.shadow.appendChild(style);
|
|
@@ -113,7 +113,7 @@ var WalletPicker = class {
|
|
|
113
113
|
const style = document.createElement("style");
|
|
114
114
|
style.textContent = `
|
|
115
115
|
:host{all:initial}
|
|
116
|
-
.wp-backdrop{position:fixed;inset:0;background:rgba(0,0,0,0.
|
|
116
|
+
.wp-backdrop{position:fixed;inset:0;background:rgba(0,0,0,0.42);z-index:1000000;display:flex;align-items:center;justify-content:center;animation:wp-fade 150ms ease-out}
|
|
117
117
|
.wp-card{background:#fff;width:340px;border-radius:16px;box-shadow:0 25px 50px -12px rgba(0,0,0,0.25);padding:20px;animation:wp-scale 200ms ease-out}
|
|
118
118
|
.wp-title{font:600 16px/1.3 system-ui,sans-serif;color:#111;margin:0 0 12px}
|
|
119
119
|
.wp-list{list-style:none;margin:0;padding:0;display:flex;flex-direction:column;gap:6px}
|
|
@@ -262,6 +262,25 @@ var OpenKey = class {
|
|
|
262
262
|
this.lastAuth = result;
|
|
263
263
|
return result;
|
|
264
264
|
}
|
|
265
|
+
/**
|
|
266
|
+
* Better-auth session token relayed during connect(), or null if the
|
|
267
|
+
* flow did not provide one. Use as a bearer token for API calls made
|
|
268
|
+
* on the user's behalf (e.g. TinyCloud auto-sign bootstrap signing).
|
|
269
|
+
*/
|
|
270
|
+
getSessionToken() {
|
|
271
|
+
return this.sessionToken;
|
|
272
|
+
}
|
|
273
|
+
/**
|
|
274
|
+
* Endpoint + bearer token for a TinyCloud auto-sign signing strategy.
|
|
275
|
+
* The endpoint is on the OpenKey API host and only signs requests the
|
|
276
|
+
* server-side bootstrap allowlist permits.
|
|
277
|
+
*/
|
|
278
|
+
tinycloudSigningOptions() {
|
|
279
|
+
return {
|
|
280
|
+
endpoint: `${this.oauthHost}/api/delegate/sign`,
|
|
281
|
+
token: this.sessionToken
|
|
282
|
+
};
|
|
283
|
+
}
|
|
265
284
|
/**
|
|
266
285
|
* Link an external wallet to the user's OpenKey account
|
|
267
286
|
* Opens link-wallet widget flow
|
|
@@ -291,31 +310,40 @@ var OpenKey = class {
|
|
|
291
310
|
}
|
|
292
311
|
return this.signTypedDataWithOpenKey(request, opts?.mode);
|
|
293
312
|
}
|
|
313
|
+
providerCandidates() {
|
|
314
|
+
const providers = [];
|
|
315
|
+
if (this.config.externalProvider) {
|
|
316
|
+
providers.push(this.config.externalProvider);
|
|
317
|
+
}
|
|
318
|
+
providers.push(...this.discoveredProviders.map(({ provider }) => provider));
|
|
319
|
+
if (typeof window !== "undefined" && window.ethereum) {
|
|
320
|
+
providers.push(window.ethereum);
|
|
321
|
+
}
|
|
322
|
+
return [...new Set(providers)];
|
|
323
|
+
}
|
|
324
|
+
async providerHasAccount(provider, method, targetAddress) {
|
|
325
|
+
try {
|
|
326
|
+
const accounts = await provider.request({ method });
|
|
327
|
+
return accounts.some((account) => account.toLowerCase() === targetAddress.toLowerCase());
|
|
328
|
+
} catch {
|
|
329
|
+
return false;
|
|
330
|
+
}
|
|
331
|
+
}
|
|
294
332
|
/**
|
|
295
333
|
* Find a wallet provider that controls the given address.
|
|
296
|
-
* Checks
|
|
334
|
+
* Checks connected accounts first, then asks the wallet to authorize the
|
|
335
|
+
* app origin if the external key was linked elsewhere.
|
|
297
336
|
*/
|
|
298
337
|
async findWalletProvider(targetAddress) {
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
try {
|
|
304
|
-
const accounts = await provider.request({ method: "eth_accounts" });
|
|
305
|
-
if (accounts.some((a) => a.toLowerCase() === targetAddress.toLowerCase())) {
|
|
306
|
-
return provider;
|
|
307
|
-
}
|
|
308
|
-
} catch {
|
|
338
|
+
const providers = this.providerCandidates();
|
|
339
|
+
for (const provider of providers) {
|
|
340
|
+
if (await this.providerHasAccount(provider, "eth_accounts", targetAddress)) {
|
|
341
|
+
return provider;
|
|
309
342
|
}
|
|
310
343
|
}
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
const accounts = await provider.request({ method: "eth_accounts" });
|
|
315
|
-
if (accounts.some((a) => a.toLowerCase() === targetAddress.toLowerCase())) {
|
|
316
|
-
return provider;
|
|
317
|
-
}
|
|
318
|
-
} catch {
|
|
344
|
+
for (const provider of providers) {
|
|
345
|
+
if (await this.providerHasAccount(provider, "eth_requestAccounts", targetAddress)) {
|
|
346
|
+
return provider;
|
|
319
347
|
}
|
|
320
348
|
}
|
|
321
349
|
throw new ExternalWalletError("External wallet not found. Connect the wallet that owns this key and try again.");
|
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts"],"sourcesContent":["// OpenKey SDK - Browser client for third-party apps\n// Provides \"Sign with OpenKey\" functionality via popup or iframe\n\nimport {\n generateCodeVerifier,\n generateCodeChallenge,\n generateState,\n buildAuthorizationUrl,\n} from '@openkey/core';\n\nexport interface EIP1193Provider {\n request(args: { method: string; params?: any[] }): Promise<any>;\n}\n\ninterface EIP6963ProviderInfo {\n uuid: string;\n name: string;\n icon: string;\n rdns: string;\n}\n\ninterface EIP6963ProviderDetail {\n info: EIP6963ProviderInfo;\n provider: EIP1193Provider;\n}\n\nexport type OpenKeyMode = 'iframe' | 'popup' | 'redirect';\n\nexport interface OpenKeyConfig {\n /** OpenKey host URL (default: https://openkey.so) */\n host?: string;\n /** OAuth API host URL (default: derived from host by prefixing 'api.') */\n oauthHost?: string;\n /** App identifier for display */\n appName?: string;\n /** UI mode: 'iframe' (default), 'popup', or 'redirect' */\n mode?: OpenKeyMode;\n /** App-provided wallet provider for external key signing */\n externalProvider?: EIP1193Provider;\n}\n\nexport interface SignMessageRequest {\n message: string;\n keyId?: string; // If not provided, user selects\n}\n\nexport interface SignTypedDataRequest {\n domain: {\n name?: string;\n version?: string;\n chainId?: number;\n verifyingContract?: string;\n };\n types: Record<string, Array<{ name: string; type: string }>>;\n primaryType: string;\n message: Record<string, unknown>;\n keyId?: string;\n}\n\nexport interface SignResult {\n signature: string;\n address: string;\n}\n\nexport interface AuthResult {\n address: string;\n keyId: string;\n keyType: 'MANAGED' | 'EXTERNAL';\n}\n\nexport interface OpenKeyError {\n code: 'USER_CANCELLED' | 'POPUP_BLOCKED' | 'TIMEOUT' | 'NO_KEY' | 'UNAUTHORIZED' | 'UNKNOWN' | 'STATE_MISMATCH';\n message: string;\n}\n\n// ======= OAuth 2.1 Types =======\n\n/** OAuth configuration for third-party apps */\nexport interface OAuthConfig {\n /** OAuth client_id (registered with OpenKey) */\n clientId: string;\n /** Redirect URI (must match registered URI) */\n redirectUri: string;\n /** State parameter for CSRF protection (auto-generated if not provided) */\n state?: string;\n}\n\n/** Result from OAuth authorization */\nexport interface OAuthResult {\n /** Authorization code (exchange for tokens) */\n code: string;\n /** State parameter (verify matches request) */\n state: string;\n}\n\n/** Response from token exchange */\nexport interface OAuthTokenResponse {\n access_token: string;\n token_type: 'Bearer';\n expires_in: number;\n id_token: string;\n scope: string;\n refresh_token?: string;\n}\n\ntype MessageType =\n | { type: 'openkey:auth:request'; appName: string }\n | { type: 'openkey:auth:response'; success: true; address: string; keyId: string; keyType?: 'MANAGED' | 'EXTERNAL'; sessionToken?: string }\n | { type: 'openkey:auth:response'; success: false; error: OpenKeyError }\n | { type: 'openkey:sign:request'; message: string; keyId?: string; sessionToken?: string }\n | { type: 'openkey:sign:response'; success: true; signature: string; address: string }\n | { type: 'openkey:sign:response'; success: false; error: OpenKeyError }\n | { type: 'openkey:signTypedData:request'; data: SignTypedDataRequest; sessionToken?: string }\n | { type: 'openkey:signTypedData:response'; success: true; signature: string; address: string }\n | { type: 'openkey:signTypedData:response'; success: false; error: OpenKeyError }\n | { type: 'openkey:link-wallet:request' }\n | { type: 'openkey:link-wallet:response'; success: true; address: string; keyId: string }\n | { type: 'openkey:link-wallet:response'; success: false; error: OpenKeyError }\n | { type: 'openkey:link-wallet:delegate' }\n | { type: 'openkey:link-wallet:result'; success: true; address: string; keyId: string }\n | { type: 'openkey:link-wallet:result'; success: false; error: OpenKeyError }\n | { type: 'openkey:auth:use-external-wallet' }\n | { type: 'openkey:resize'; height: number }\n | { type: 'openkey:ready' }\n | { type: 'openkey:close' };\n\nconst DEFAULT_HOST = 'https://openkey.so';\nconst POPUP_WIDTH = 400;\nconst POPUP_HEIGHT = 600;\nconst DEFAULT_TIMEOUT = 5 * 60 * 1000; // 5 minutes\nconst IFRAME_READY_TIMEOUT = 3000; // 3 seconds\nconst OAUTH_STORAGE_KEY = 'openkey_oauth';\n\nclass IframeModal {\n private root: HTMLDivElement;\n private shadow: ShadowRoot;\n private iframe: HTMLIFrameElement;\n private onClose: () => void;\n private onMessage: (data: MessageType) => void;\n private messageHandler: (event: MessageEvent) => void;\n private host: string;\n\n constructor(opts: { url: string; host: string; onClose: () => void; onMessage: (data: MessageType) => void }) {\n this.host = opts.host;\n this.onClose = opts.onClose;\n this.onMessage = opts.onMessage;\n\n const isMobile = window.matchMedia('(max-width: 639px)').matches;\n\n this.root = document.createElement('div');\n this.shadow = this.root.attachShadow({ mode: 'closed' });\n\n const style = document.createElement('style');\n style.textContent = `\n :host{all:initial}\n .ok-backdrop{position:fixed;inset:0;background:rgba(0,0,0,0.4);backdrop-filter:blur(4px);z-index:999999;display:flex;align-items:${isMobile ? 'flex-end' : 'center'};justify-content:center;animation:ok-fade-in 150ms ease-out}\n .ok-card{position:relative;background:#fafafa;width:${isMobile ? '100%' : '400px'};border-radius:${isMobile ? '16px 16px 0 0' : '16px'};box-shadow:0 25px 50px -12px rgba(0,0,0,0.25);overflow:hidden;overflow-y:auto;animation:${isMobile ? 'ok-slide-up 250ms ease-out' : 'ok-scale-in 200ms ease-out'};max-height:90vh}\n .ok-close{position:absolute;top:8px;right:8px;width:24px;height:24px;border:none;background:transparent;color:#6b7280;font-size:18px;cursor:pointer;z-index:1;display:flex;align-items:center;justify-content:center;border-radius:4px}\n .ok-close:hover{color:#111827}\n .ok-handle{width:40px;height:4px;background:#d4d4d4;border-radius:2px;margin:8px auto 0}\n iframe{border:none;width:100%;height:400px;display:block;transition:height 200ms ease}\n .ok-backdrop.ok-exit{animation:ok-fade-out 150ms ease-in}\n .ok-backdrop.ok-exit .ok-card{animation:${isMobile ? 'ok-slide-down 200ms ease-in' : 'ok-scale-out 150ms ease-in'}}\n @keyframes ok-fade-in{from{opacity:0}to{opacity:1}}\n @keyframes ok-fade-out{from{opacity:1}to{opacity:0}}\n @keyframes ok-scale-in{from{opacity:0;transform:scale(0.95)}to{opacity:1;transform:scale(1)}}\n @keyframes ok-scale-out{from{opacity:1;transform:scale(1)}to{opacity:0;transform:scale(0.95)}}\n @keyframes ok-slide-up{from{transform:translateY(100%)}to{transform:translateY(0)}}\n @keyframes ok-slide-down{from{transform:translateY(0)}to{transform:translateY(100%)}}\n `;\n\n const backdrop = document.createElement('div');\n backdrop.className = 'ok-backdrop';\n backdrop.addEventListener('click', (e) => {\n if (e.target === backdrop) this.close();\n });\n\n const card = document.createElement('div');\n card.className = 'ok-card';\n\n if (isMobile) {\n const handle = document.createElement('div');\n handle.className = 'ok-handle';\n card.appendChild(handle);\n }\n\n const closeBtn = document.createElement('button');\n closeBtn.className = 'ok-close';\n closeBtn.textContent = '\\u00d7';\n closeBtn.addEventListener('click', () => this.close());\n card.appendChild(closeBtn);\n\n this.iframe = document.createElement('iframe');\n this.iframe.src = opts.url;\n this.iframe.setAttribute('allow', 'publickey-credentials-get *; publickey-credentials-create *');\n this.iframe.setAttribute('sandbox', 'allow-scripts allow-same-origin allow-forms allow-popups');\n card.appendChild(this.iframe);\n\n backdrop.appendChild(card);\n this.shadow.appendChild(style);\n this.shadow.appendChild(backdrop);\n\n this.messageHandler = (event: MessageEvent) => {\n if (event.origin !== this.host) return;\n if (event.source !== this.iframe.contentWindow) return;\n const data = event.data as MessageType;\n if (data.type === 'openkey:resize') {\n const h = Math.min(data.height, Math.floor(window.innerHeight * 0.85));\n this.iframe.style.height = `${h}px`;\n return;\n }\n this.onMessage(data);\n };\n window.addEventListener('message', this.messageHandler);\n document.body.appendChild(this.root);\n }\n\n postMessage(message: object) {\n this.iframe.contentWindow?.postMessage(message, this.host);\n }\n\n destroy() {\n window.removeEventListener('message', this.messageHandler);\n this.root.remove();\n }\n\n private close() {\n const backdrop = this.shadow.querySelector('.ok-backdrop');\n if (backdrop) {\n backdrop.classList.add('ok-exit');\n setTimeout(() => {\n this.destroy();\n this.onClose();\n }, 200);\n } else {\n this.destroy();\n this.onClose();\n }\n }\n}\n\nclass WalletPicker {\n private root: HTMLDivElement;\n private shadow: ShadowRoot;\n\n constructor(opts: { providers: EIP6963ProviderDetail[]; onSelect: (provider: EIP1193Provider) => void; onCancel: () => void }) {\n this.root = document.createElement('div');\n this.shadow = this.root.attachShadow({ mode: 'closed' });\n\n const style = document.createElement('style');\n style.textContent = `\n :host{all:initial}\n .wp-backdrop{position:fixed;inset:0;background:rgba(0,0,0,0.4);backdrop-filter:blur(4px);z-index:1000000;display:flex;align-items:center;justify-content:center;animation:wp-fade 150ms ease-out}\n .wp-card{background:#fff;width:340px;border-radius:16px;box-shadow:0 25px 50px -12px rgba(0,0,0,0.25);padding:20px;animation:wp-scale 200ms ease-out}\n .wp-title{font:600 16px/1.3 system-ui,sans-serif;color:#111;margin:0 0 12px}\n .wp-list{list-style:none;margin:0;padding:0;display:flex;flex-direction:column;gap:6px}\n .wp-item{display:flex;align-items:center;gap:10px;padding:10px 12px;border:1px solid #e5e7eb;border-radius:10px;background:transparent;cursor:pointer;font:14px/1.3 system-ui,sans-serif;color:#111;width:100%;text-align:left;transition:border-color 150ms}\n .wp-item:hover{border-color:#6366f1}\n .wp-icon{width:28px;height:28px;border-radius:6px}\n .wp-empty{font:14px/1.4 system-ui,sans-serif;color:#6b7280;text-align:center;padding:16px 0}\n .wp-cancel{display:block;width:100%;margin-top:12px;padding:8px;border:none;background:transparent;color:#6b7280;font:14px/1.3 system-ui,sans-serif;cursor:pointer;border-radius:8px}\n .wp-cancel:hover{background:#f3f4f6;color:#111}\n @keyframes wp-fade{from{opacity:0}to{opacity:1}}\n @keyframes wp-scale{from{opacity:0;transform:scale(0.95)}to{opacity:1;transform:scale(1)}}\n @media(prefers-color-scheme:dark){\n .wp-card{background:#1a1a1a;box-shadow:0 25px 50px -12px rgba(0,0,0,0.5)}\n .wp-title{color:#f3f4f6}\n .wp-item{border-color:#374151;color:#f3f4f6}\n .wp-item:hover{border-color:#818cf8}\n .wp-empty{color:#9ca3af}\n .wp-cancel{color:#9ca3af}\n .wp-cancel:hover{background:#262626;color:#f3f4f6}\n }\n `;\n\n const backdrop = document.createElement('div');\n backdrop.className = 'wp-backdrop';\n backdrop.addEventListener('click', (e) => { if (e.target === backdrop) { this.destroy(); opts.onCancel(); } });\n\n const card = document.createElement('div');\n card.className = 'wp-card';\n\n const title = document.createElement('h2');\n title.className = 'wp-title';\n title.textContent = 'Select a wallet';\n card.appendChild(title);\n\n if (opts.providers.length === 0) {\n const empty = document.createElement('div');\n empty.className = 'wp-empty';\n empty.textContent = 'No wallets detected';\n card.appendChild(empty);\n } else {\n const list = document.createElement('ul');\n list.className = 'wp-list';\n for (const { info, provider } of opts.providers) {\n const item = document.createElement('button');\n item.className = 'wp-item';\n if (info.icon) {\n const icon = document.createElement('img');\n icon.className = 'wp-icon';\n icon.src = info.icon;\n icon.alt = info.name;\n item.appendChild(icon);\n }\n const name = document.createElement('span');\n name.textContent = info.name;\n item.appendChild(name);\n item.addEventListener('click', () => { this.destroy(); opts.onSelect(provider); });\n list.appendChild(item);\n }\n card.appendChild(list);\n }\n\n const cancel = document.createElement('button');\n cancel.className = 'wp-cancel';\n cancel.textContent = 'Cancel';\n cancel.addEventListener('click', () => { this.destroy(); opts.onCancel(); });\n card.appendChild(cancel);\n\n backdrop.appendChild(card);\n this.shadow.appendChild(style);\n this.shadow.appendChild(backdrop);\n document.body.appendChild(this.root);\n }\n\n destroy() {\n this.root.remove();\n }\n}\n\nfunction showToast(message = 'Opening in new window\\u2026', variant: 'info' | 'error' = 'info') {\n const bg = variant === 'error' ? '#dc2626' : '#1f2937';\n const root = document.createElement('div');\n const shadow = root.attachShadow({ mode: 'closed' });\n shadow.innerHTML = `<style>:host{all:initial}.ok-toast{position:fixed;top:16px;right:16px;z-index:1000000;background:${bg};color:#f9fafb;padding:10px 16px;border-radius:8px;font:14px/1.4 system-ui,sans-serif;box-shadow:0 4px 12px rgba(0,0,0,0.15);animation:ok-t-in 200ms ease-out;max-width:360px}@keyframes ok-t-in{from{opacity:0;transform:translateY(-8px)}to{opacity:1;transform:translateY(0)}}</style><div class=\"ok-toast\">${message}</div>`;\n document.body.appendChild(root);\n setTimeout(() => root.remove(), 4000);\n}\n\nclass ExternalWalletError extends Error {\n constructor(message: string) {\n super(message);\n this.name = 'ExternalWalletError';\n }\n}\n\nexport class OpenKey {\n private host: string;\n private oauthHost: string;\n private appName: string;\n private mode: OpenKeyMode;\n private config: OpenKeyConfig;\n private popup: Window | null = null;\n private lastAuth: AuthResult | null = null;\n private discoveredProviders: EIP6963ProviderDetail[] = [];\n private sessionToken: string | null = null;\n\n constructor(config: OpenKeyConfig = {}) {\n this.config = config;\n this.host = config.host || DEFAULT_HOST;\n this.oauthHost = config.oauthHost || this.deriveOAuthHost(this.host);\n this.appName = config.appName || window.location.hostname;\n this.mode = config.mode ?? 'iframe';\n\n // Listen for EIP-6963 wallet announcements\n if (typeof window !== 'undefined') {\n this.discoveredProviders = [];\n window.addEventListener('eip6963:announceProvider', (event: any) => {\n this.discoveredProviders.push(event.detail);\n });\n window.dispatchEvent(new Event('eip6963:requestProvider'));\n }\n }\n\n /**\n * Derive the OAuth API host from the main host by prefixing 'api.'\n * @param host - The main host URL\n * @returns The derived OAuth API host URL\n */\n private deriveOAuthHost(host: string): string {\n try {\n const url = new URL(host);\n if (url.hostname === 'localhost' || url.hostname === '127.0.0.1') {\n return host.replace(/\\/$/, '');\n }\n url.hostname = 'api.' + url.hostname;\n return url.toString().replace(/\\/$/, '');\n } catch {\n return 'https://api.openkey.so';\n }\n }\n\n /**\n * Connect to OpenKey and get user's wallet address\n * Opens auth flow for user to select/create a key\n */\n async connect(opts?: { mode?: OpenKeyMode }): Promise<AuthResult> {\n const result = await this.openFlow<AuthResult>('connect', {\n type: 'openkey:auth:request',\n appName: this.appName,\n }, opts?.mode);\n this.lastAuth = result;\n return result;\n }\n\n /**\n * Link an external wallet to the user's OpenKey account\n * Opens link-wallet widget flow\n */\n async linkWallet(opts?: { mode?: OpenKeyMode }): Promise<{ address: string; keyId: string }> {\n return this.openFlow<{ address: string; keyId: string }>('link-wallet', {\n type: 'openkey:link-wallet:request',\n }, opts?.mode);\n }\n\n /**\n * Sign a message with the user's OpenKey wallet\n * For external keys, routes directly to the user's wallet provider\n */\n async signMessage(request: SignMessageRequest, opts?: { mode?: OpenKeyMode }): Promise<SignResult> {\n if (this.lastAuth?.keyType === 'EXTERNAL') {\n return this.signWithExternalWallet(request);\n }\n return this.signWithOpenKey(request, opts?.mode);\n }\n\n /**\n * Sign typed data (EIP-712) with the user's OpenKey wallet\n * For external keys, routes directly to the user's wallet provider\n */\n async signTypedData(request: SignTypedDataRequest, opts?: { mode?: OpenKeyMode }): Promise<SignResult> {\n if (this.lastAuth?.keyType === 'EXTERNAL') {\n return this.signTypedDataWithExternalWallet(request);\n }\n return this.signTypedDataWithOpenKey(request, opts?.mode);\n }\n\n /**\n * Find a wallet provider that controls the given address.\n * Checks: 1) app-provided externalProvider, 2) EIP-6963 discovered wallets, 3) window.ethereum\n */\n async findWalletProvider(targetAddress: string): Promise<EIP1193Provider> {\n // 1. Try app-provided externalProvider first\n if (this.config.externalProvider) {\n return this.config.externalProvider;\n }\n\n // 2. Check EIP-6963 discovered wallets silently (no popup)\n for (const { provider } of this.discoveredProviders) {\n try {\n const accounts = await provider.request({ method: 'eth_accounts' }) as string[];\n if (accounts.some(a => a.toLowerCase() === targetAddress.toLowerCase())) {\n return provider;\n }\n } catch {}\n }\n\n // 3. Fall back to window.ethereum silently\n if (typeof window !== 'undefined' && (window as any).ethereum) {\n const provider = (window as any).ethereum as EIP1193Provider;\n try {\n const accounts = await provider.request({ method: 'eth_accounts' }) as string[];\n if (accounts.some(a => a.toLowerCase() === targetAddress.toLowerCase())) {\n return provider;\n }\n } catch {}\n }\n\n throw new ExternalWalletError('External wallet not found. Connect the wallet that owns this key and try again.');\n }\n\n private async signWithExternalWallet(request: SignMessageRequest): Promise<SignResult> {\n let provider: EIP1193Provider;\n try {\n provider = await this.findWalletProvider(this.lastAuth!.address);\n } catch (e) {\n showToast((e as Error).message, 'error');\n throw e;\n }\n try {\n const hexMessage = this.toHex(request.message);\n const signature = await provider.request({\n method: 'personal_sign',\n params: [hexMessage, this.lastAuth!.address],\n });\n return { signature: signature as string, address: this.lastAuth!.address };\n } catch (e: any) {\n const msg = e?.message?.includes('not been authorized')\n ? 'Wallet rejected the request. Approve the connection in your wallet and try again.'\n : e?.message || 'Signing failed';\n showToast(msg, 'error');\n throw new Error(msg);\n }\n }\n\n private async signTypedDataWithExternalWallet(request: SignTypedDataRequest): Promise<SignResult> {\n let provider: EIP1193Provider;\n try {\n provider = await this.findWalletProvider(this.lastAuth!.address);\n } catch (e) {\n showToast((e as Error).message, 'error');\n throw e;\n }\n try {\n const signature = await provider.request({\n method: 'eth_signTypedData_v4',\n params: [this.lastAuth!.address, JSON.stringify(request)],\n });\n return { signature: signature as string, address: this.lastAuth!.address };\n } catch (e: any) {\n const msg = e?.message?.includes('not been authorized')\n ? 'Wallet rejected the request. Approve the connection in your wallet and try again.'\n : e?.message || 'Signing failed';\n showToast(msg, 'error');\n throw new Error(msg);\n }\n }\n\n private signWithOpenKey(request: SignMessageRequest, mode?: OpenKeyMode): Promise<SignResult> {\n return this.openFlow<SignResult>('sign', {\n type: 'openkey:sign:request',\n message: request.message,\n keyId: request.keyId,\n sessionToken: this.sessionToken || undefined,\n }, mode);\n }\n\n private signTypedDataWithOpenKey(request: SignTypedDataRequest, mode?: OpenKeyMode): Promise<SignResult> {\n return this.openFlow<SignResult>('sign-typed-data', {\n type: 'openkey:signTypedData:request',\n data: request,\n sessionToken: this.sessionToken || undefined,\n }, mode);\n }\n\n private toHex(str: string): string {\n return '0x' + Array.from(new TextEncoder().encode(str)).map(b => b.toString(16).padStart(2, '0')).join('');\n }\n\n /**\n * Check if user is already authenticated\n */\n async isConnected(): Promise<boolean> {\n // Check for existing session via API\n try {\n const res = await fetch(`${this.host}/api/auth/session`, {\n credentials: 'include',\n });\n if (!res.ok) return false;\n const data = await res.json();\n return !!data.user;\n } catch {\n return false;\n }\n }\n\n // ======= OAuth 2.1 Provider Methods =======\n\n /**\n * OAuth 2.1 methods for third-party app authentication\n * Use this when your app has registered OAuth client credentials with OpenKey\n */\n oauth = {\n /**\n * Start OAuth authorization flow\n * Opens popup/redirect to OpenKey authorization endpoint\n * @returns Promise that resolves with authorization code after user consent\n */\n connect: async (config: OAuthConfig): Promise<OAuthResult> => {\n // Generate PKCE values\n const verifier = generateCodeVerifier();\n const challenge = await generateCodeChallenge(verifier);\n const state = config.state || generateState();\n\n // Store for later token exchange\n sessionStorage.setItem(\n OAUTH_STORAGE_KEY,\n JSON.stringify({ verifier, state })\n );\n\n // Build authorization URL\n const authUrl = buildAuthorizationUrl({\n host: this.oauthHost,\n clientId: config.clientId,\n redirectUri: config.redirectUri,\n codeChallenge: challenge,\n state,\n scopes: ['openid'],\n });\n\n return this.openOAuthFlow(authUrl, state, config.redirectUri);\n },\n\n /**\n * Exchange authorization code for tokens\n * Call this after receiving the callback with authorization code\n * @param code - Authorization code from callback URL\n * @param config - Same config used for connect()\n * @returns Promise that resolves with access_token, id_token, etc.\n */\n exchangeCode: async (\n code: string,\n config: OAuthConfig\n ): Promise<OAuthTokenResponse> => {\n const stored = sessionStorage.getItem(OAUTH_STORAGE_KEY);\n if (!stored) {\n throw new Error('No PKCE verifier found. Start a new OAuth flow.');\n }\n\n const { verifier } = JSON.parse(stored);\n\n const response = await fetch(`${this.oauthHost}/api/auth/oauth2/token`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/x-www-form-urlencoded',\n },\n body: new URLSearchParams({\n grant_type: 'authorization_code',\n code,\n redirect_uri: config.redirectUri,\n client_id: config.clientId,\n code_verifier: verifier,\n }),\n });\n\n // Clear stored verifier\n sessionStorage.removeItem(OAUTH_STORAGE_KEY);\n\n if (!response.ok) {\n const error = await response.json();\n throw new Error(error.error_description || 'Token exchange failed');\n }\n\n return response.json();\n },\n\n /**\n * Verify state parameter from callback\n * Call this before exchangeCode to prevent CSRF attacks\n * @param receivedState - State parameter from callback URL\n * @returns true if state matches, false otherwise\n */\n verifyState: (receivedState: string): boolean => {\n const stored = sessionStorage.getItem(OAUTH_STORAGE_KEY);\n if (!stored) return false;\n const { state } = JSON.parse(stored);\n return state === receivedState;\n },\n\n /**\n * Parse authorization response from callback URL\n * @param url - Callback URL (defaults to current window.location.href)\n * @returns Parsed code and state, or error\n */\n parseCallback: (\n url?: string\n ): { code: string; state: string } | { error: string; errorDescription?: string } => {\n const urlObj = new URL(url || window.location.href);\n const error = urlObj.searchParams.get('error');\n\n if (error) {\n return {\n error,\n errorDescription: urlObj.searchParams.get('error_description') || undefined,\n };\n }\n\n const code = urlObj.searchParams.get('code');\n const state = urlObj.searchParams.get('state');\n\n if (!code || !state) {\n return { error: 'missing_params', errorDescription: 'Missing code or state parameter' };\n }\n\n return { code, state };\n },\n };\n\n private openOAuthFlow(\n url: string,\n state: string,\n redirectUri: string\n ): Promise<OAuthResult> {\n return new Promise((resolve, reject) => {\n if (this.mode !== 'redirect') {\n this.openOAuthPopup(url, state, redirectUri, resolve, reject);\n } else {\n // Full page redirect - won't resolve, page navigates away\n window.location.href = url;\n }\n });\n }\n\n private openOAuthPopup(\n url: string,\n state: string,\n redirectUri: string,\n resolve: (value: OAuthResult) => void,\n reject: (error: OpenKeyError) => void\n ) {\n const left = window.screenX + (window.outerWidth - POPUP_WIDTH) / 2;\n const top = window.screenY + (window.outerHeight - POPUP_HEIGHT) / 2;\n\n this.popup = window.open(\n url,\n 'openkey-oauth',\n `width=${POPUP_WIDTH},height=${POPUP_HEIGHT},left=${left},top=${top},popup=true`\n );\n\n if (!this.popup) {\n showToast('Popup was blocked. Please allow popups for this site.', 'error');\n reject({\n code: 'POPUP_BLOCKED',\n message: 'Popup was blocked. Please allow popups or use redirect mode.',\n });\n return;\n }\n\n const redirectHost = new URL(redirectUri).origin;\n\n // Poll for redirect back with code\n const pollInterval = setInterval(() => {\n try {\n if (this.popup?.closed) {\n clearInterval(pollInterval);\n clearTimeout(timeout);\n reject({\n code: 'USER_CANCELLED',\n message: 'User closed the popup',\n });\n return;\n }\n\n // Check if redirected to callback URL\n const popupUrl = this.popup?.location?.href;\n if (popupUrl && popupUrl.startsWith(redirectHost)) {\n clearInterval(pollInterval);\n clearTimeout(timeout);\n\n const urlObj = new URL(popupUrl);\n const code = urlObj.searchParams.get('code');\n const returnedState = urlObj.searchParams.get('state');\n const error = urlObj.searchParams.get('error');\n\n this.popup?.close();\n\n if (error) {\n reject({\n code: 'UNAUTHORIZED',\n message: urlObj.searchParams.get('error_description') || error,\n });\n return;\n }\n\n if (returnedState !== state) {\n reject({\n code: 'STATE_MISMATCH',\n message: 'State mismatch - possible CSRF attack',\n });\n return;\n }\n\n if (code) {\n resolve({ code, state: returnedState });\n } else {\n reject({\n code: 'UNAUTHORIZED',\n message: 'Authorization failed - no code returned',\n });\n }\n }\n } catch {\n // Cross-origin - popup still on OpenKey domain, continue polling\n }\n }, 100);\n\n // Timeout\n const timeout = setTimeout(() => {\n clearInterval(pollInterval);\n this.popup?.close();\n reject({\n code: 'TIMEOUT',\n message: 'OAuth flow timed out',\n });\n }, DEFAULT_TIMEOUT);\n }\n\n private resolveMode(override?: OpenKeyMode): OpenKeyMode {\n return override ?? this.mode;\n }\n\n private hasDetectedEoa(): boolean {\n if (this.discoveredProviders.length > 0) return true;\n if (typeof window !== 'undefined' && (window as any).ethereum) return true;\n return false;\n }\n\n private async openFlow<T>(action: string, message: object, modeOverride?: OpenKeyMode): Promise<T> {\n const mode = this.resolveMode(modeOverride);\n const origin = encodeURIComponent(window.location.origin);\n const eoaFlag = action === 'connect' && this.hasDetectedEoa() ? '&hasEoa=true' : '';\n\n if (mode === 'popup') {\n const url = `${this.host}/widget/${action}?origin=${origin}${eoaFlag}`;\n return new Promise((resolve, reject) => this.openPopup(url, message, resolve, reject));\n }\n\n if (mode === 'redirect') {\n const url = `${this.host}/widget/${action}?origin=${origin}${eoaFlag}`;\n window.location.href = url;\n return new Promise(() => {}); // never resolves, page navigates\n }\n\n // iframe mode with auto-fallback\n const url = `${this.host}/widget/embed/${action}?origin=${origin}${eoaFlag}`;\n return this.openIframeModal<T>(url, action, message, origin);\n }\n\n private openIframeModal<T>(url: string, action: string, message: object, origin: string): Promise<T> {\n return new Promise((resolve, reject) => {\n let readyReceived = false;\n let settled = false;\n let modal: IframeModal | null = null;\n\n const settle = (fn: () => void) => {\n if (settled) return;\n settled = true;\n fn();\n };\n\n const cleanup = () => {\n clearTimeout(readyTimeout);\n clearTimeout(overallTimeout);\n modal?.destroy();\n modal = null;\n };\n\n modal = new IframeModal({\n url,\n host: this.host,\n onClose: () => {\n settle(() => {\n clearTimeout(readyTimeout);\n clearTimeout(overallTimeout);\n modal = null;\n reject({ code: 'USER_CANCELLED', message: 'User cancelled the request' } as OpenKeyError);\n });\n },\n onMessage: (data: MessageType) => {\n if (data.type === 'openkey:ready') {\n readyReceived = true;\n modal?.postMessage(message);\n return;\n }\n\n if (data.type === 'openkey:close') {\n settle(() => {\n cleanup();\n reject({ code: 'USER_CANCELLED', message: 'User cancelled the request' } as OpenKeyError);\n });\n return;\n }\n\n if (data.type === 'openkey:link-wallet:delegate') {\n this.handleWalletLinkDelegation(modal!);\n return;\n }\n\n if (data.type === 'openkey:auth:use-external-wallet') {\n cleanup();\n this.handleExternalWalletConnect<T>(resolve, reject);\n return;\n }\n\n if (\n data.type === 'openkey:auth:response' ||\n data.type === 'openkey:sign:response' ||\n data.type === 'openkey:signTypedData:response' ||\n data.type === 'openkey:link-wallet:response'\n ) {\n settle(() => {\n cleanup();\n if (data.success) {\n if (data.type === 'openkey:auth:response') {\n if (data.sessionToken) this.sessionToken = data.sessionToken;\n resolve({ address: data.address, keyId: data.keyId, keyType: data.keyType || 'MANAGED' } as T);\n } else if (data.type === 'openkey:link-wallet:response') {\n resolve({ address: data.address, keyId: data.keyId } as T);\n } else {\n resolve({ signature: data.signature, address: data.address } as T);\n }\n } else {\n reject(data.error);\n }\n });\n }\n },\n });\n\n // Auto-fallback: if no openkey:ready within 3s, fall back to popup\n const readyTimeout = setTimeout(() => {\n if (readyReceived || settled) return;\n cleanup();\n console.warn('OpenKey: iframe blocked by CSP, falling back to popup. Add frame-src https://openkey.so to your CSP.');\n showToast();\n const popupUrl = `${this.host}/widget/${action}?origin=${origin}`;\n this.openPopup(popupUrl, message, (val: any) => settle(() => resolve(val)), (err: any) => settle(() => reject(err)));\n }, IFRAME_READY_TIMEOUT);\n\n // Overall 5-minute timeout\n const overallTimeout = setTimeout(() => {\n settle(() => {\n cleanup();\n reject({ code: 'TIMEOUT', message: 'Request timed out' } as OpenKeyError);\n });\n }, DEFAULT_TIMEOUT);\n });\n }\n\n private handleWalletLinkDelegation(modal: IframeModal) {\n const sendResult = (result: MessageType) => modal.postMessage(result);\n\n new WalletPicker({\n providers: this.discoveredProviders,\n onCancel: () => {\n sendResult({ type: 'openkey:link-wallet:result', success: false, error: { code: 'USER_CANCELLED', message: 'Wallet linking cancelled' } });\n },\n onSelect: async (provider) => {\n try {\n const accounts = await provider.request({ method: 'eth_requestAccounts' }) as string[];\n const address = accounts[0];\n if (!address) throw new Error('No account returned');\n\n // Get challenge from API\n const challengeRes = await fetch(`${this.host}/api/keys/link/challenge`, {\n method: 'POST',\n credentials: 'include',\n });\n if (!challengeRes.ok) throw new Error('Failed to get challenge');\n const { message } = await challengeRes.json();\n\n // Sign challenge with wallet\n const hexMessage = this.toHex(message);\n const signature = await provider.request({\n method: 'personal_sign',\n params: [hexMessage, address],\n }) as string;\n\n // Submit to API\n const linkRes = await fetch(`${this.host}/api/keys/link`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n credentials: 'include',\n body: JSON.stringify({ address, signature, message }),\n });\n if (!linkRes.ok) {\n const err = await linkRes.json();\n throw new Error(err.error || 'Failed to link wallet');\n }\n const { key } = await linkRes.json();\n\n sendResult({ type: 'openkey:link-wallet:result', success: true, address: key.address, keyId: key.id });\n } catch (e: any) {\n sendResult({ type: 'openkey:link-wallet:result', success: false, error: { code: 'UNKNOWN', message: e.message || 'Wallet linking failed' } });\n }\n },\n });\n }\n\n private handleExternalWalletConnect<T>(\n resolve: (value: T) => void,\n reject: (error: OpenKeyError) => void\n ) {\n new WalletPicker({\n providers: this.discoveredProviders,\n onCancel: () => {\n reject({ code: 'USER_CANCELLED', message: 'User cancelled wallet selection' });\n },\n onSelect: async (provider) => {\n try {\n const accounts = await provider.request({ method: 'eth_requestAccounts' }) as string[];\n const address = accounts[0];\n if (!address) throw new Error('No account returned');\n const result = { address, keyId: `external:${address}`, keyType: 'EXTERNAL' as const };\n this.lastAuth = result;\n resolve(result as T);\n } catch (e: any) {\n reject({ code: 'UNKNOWN', message: e.message || 'Failed to connect wallet' });\n }\n },\n });\n }\n\n private openPopup<T>(\n url: string,\n message: object,\n resolve: (value: T) => void,\n reject: (error: OpenKeyError) => void\n ) {\n // Calculate popup position\n const left = window.screenX + (window.outerWidth - POPUP_WIDTH) / 2;\n const top = window.screenY + (window.outerHeight - POPUP_HEIGHT) / 2;\n\n this.popup = window.open(\n url,\n 'openkey',\n `width=${POPUP_WIDTH},height=${POPUP_HEIGHT},left=${left},top=${top},popup=true`\n );\n\n if (!this.popup) {\n showToast('Popup was blocked. Please allow popups for this site.', 'error');\n reject({\n code: 'POPUP_BLOCKED',\n message: 'Popup was blocked. Please allow popups for this site.',\n });\n return;\n }\n\n const cleanup = () => {\n window.removeEventListener('message', handleMessage);\n clearInterval(pollClosed);\n clearTimeout(timeout);\n };\n\n // Poll to detect popup close\n const pollClosed = setInterval(() => {\n if (this.popup?.closed) {\n cleanup();\n reject({\n code: 'USER_CANCELLED',\n message: 'User closed the popup',\n });\n }\n }, 500);\n\n // Timeout\n const timeout = setTimeout(() => {\n cleanup();\n this.popup?.close();\n reject({\n code: 'TIMEOUT',\n message: 'Request timed out',\n });\n }, DEFAULT_TIMEOUT);\n\n // Listen for messages\n const handleMessage = (event: MessageEvent) => {\n if (event.origin !== this.host) return;\n if (event.source !== this.popup) return;\n\n const data = event.data as MessageType;\n\n if (data.type === 'openkey:ready') {\n // Widget is ready, send our request\n this.popup?.postMessage(message, this.host);\n return;\n }\n\n if (data.type === 'openkey:close') {\n cleanup();\n this.popup?.close();\n reject({\n code: 'USER_CANCELLED',\n message: 'User cancelled the request',\n });\n return;\n }\n\n if (data.type === 'openkey:auth:use-external-wallet') {\n cleanup();\n this.popup?.close();\n this.handleExternalWalletConnect<T>(resolve, reject);\n return;\n }\n\n // Handle responses\n if (\n data.type === 'openkey:auth:response' ||\n data.type === 'openkey:sign:response' ||\n data.type === 'openkey:signTypedData:response' ||\n data.type === 'openkey:link-wallet:response'\n ) {\n cleanup();\n this.popup?.close();\n\n if (data.success) {\n if (data.type === 'openkey:auth:response') {\n if (data.sessionToken) this.sessionToken = data.sessionToken;\n resolve({ address: data.address, keyId: data.keyId, keyType: data.keyType || 'MANAGED' } as T);\n } else if (data.type === 'openkey:link-wallet:response') {\n resolve({ address: data.address, keyId: data.keyId } as T);\n } else {\n resolve({ signature: data.signature, address: data.address } as T);\n }\n } else {\n reject(data.error);\n }\n }\n };\n\n window.addEventListener('message', handleMessage);\n }\n\n /**\n * Disconnect and close any open flows\n */\n disconnect() {\n this.popup?.close();\n this.popup = null;\n }\n}\n\n/**\n * EIP-1193 compatible provider that wraps an OpenKey instance.\n * Transparently routes signing to either OpenKey (managed keys) or the user's\n * wallet (external keys).\n */\nexport class OpenKeyProvider implements EIP1193Provider {\n private openkey: OpenKey;\n private address: string;\n private keyId: string;\n private keyType: 'MANAGED' | 'EXTERNAL';\n\n constructor(openkey: OpenKey, authResult: AuthResult) {\n this.openkey = openkey;\n this.address = authResult.address;\n this.keyId = authResult.keyId;\n this.keyType = authResult.keyType;\n }\n\n async request({ method, params }: { method: string; params?: any[] }): Promise<any> {\n switch (method) {\n case 'eth_accounts':\n case 'eth_requestAccounts':\n return [this.address];\n\n case 'eth_chainId':\n return '0x1'; // mainnet\n\n case 'personal_sign': {\n if (this.keyType === 'EXTERNAL') {\n try {\n const provider = await this.openkey.findWalletProvider(this.address);\n return await provider.request({ method, params });\n } catch (e: any) {\n showToast(e?.message || 'External wallet signing failed', 'error');\n throw e;\n }\n }\n // Managed key: route through OpenKey\n const message = this.hexToString(params![0] as string);\n const result = await this.openkey.signMessage({ message, keyId: this.keyId });\n return result.signature;\n }\n\n case 'eth_signTypedData_v4': {\n if (this.keyType === 'EXTERNAL') {\n try {\n const provider = await this.openkey.findWalletProvider(this.address);\n return await provider.request({ method, params });\n } catch (e: any) {\n showToast(e?.message || 'External wallet signing failed', 'error');\n throw e;\n }\n }\n const data = JSON.parse(params![1] as string);\n const result = await this.openkey.signTypedData(data);\n return result.signature;\n }\n\n default:\n throw new Error(`Unsupported method: ${method}`);\n }\n }\n\n private hexToString(hex: string): string {\n const bytes = new Uint8Array(\n (hex.startsWith('0x') ? hex.slice(2) : hex).match(/.{1,2}/g)!.map(b => parseInt(b, 16))\n );\n return new TextDecoder().decode(bytes);\n }\n}\n\n// Default export for convenience\nexport default OpenKey;\n\n// Create singleton instance\nlet defaultInstance: OpenKey | null = null;\n\nexport function getOpenKey(config?: OpenKeyConfig): OpenKey {\n if (!defaultInstance || config) {\n defaultInstance = new OpenKey(config);\n }\n return defaultInstance;\n}\n"],"mappings":"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","names":["url"]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts"],"sourcesContent":["// OpenKey SDK - Browser client for third-party apps\n// Provides \"Sign with OpenKey\" functionality via popup or iframe\n\nimport {\n generateCodeVerifier,\n generateCodeChallenge,\n generateState,\n buildAuthorizationUrl,\n} from '@openkey/core';\n\nexport interface EIP1193Provider {\n request(args: { method: string; params?: any[] }): Promise<any>;\n}\n\ninterface EIP6963ProviderInfo {\n uuid: string;\n name: string;\n icon: string;\n rdns: string;\n}\n\ninterface EIP6963ProviderDetail {\n info: EIP6963ProviderInfo;\n provider: EIP1193Provider;\n}\n\nexport type OpenKeyMode = 'iframe' | 'popup' | 'redirect';\n\nexport interface OpenKeyConfig {\n /** OpenKey host URL (default: https://openkey.so) */\n host?: string;\n /** OAuth API host URL (default: derived from host by prefixing 'api.') */\n oauthHost?: string;\n /** App identifier for display */\n appName?: string;\n /** UI mode: 'iframe' (default), 'popup', or 'redirect' */\n mode?: OpenKeyMode;\n /** App-provided wallet provider for external key signing */\n externalProvider?: EIP1193Provider;\n}\n\nexport interface SignMessageRequest {\n message: string;\n keyId?: string; // If not provided, user selects\n}\n\nexport interface SignTypedDataRequest {\n domain: {\n name?: string;\n version?: string;\n chainId?: number;\n verifyingContract?: string;\n };\n types: Record<string, Array<{ name: string; type: string }>>;\n primaryType: string;\n message: Record<string, unknown>;\n keyId?: string;\n}\n\nexport interface SignResult {\n signature: string;\n address: string;\n}\n\nexport interface AuthResult {\n address: string;\n keyId: string;\n keyType: 'MANAGED' | 'EXTERNAL';\n}\n\nexport interface OpenKeyError {\n code: 'USER_CANCELLED' | 'POPUP_BLOCKED' | 'TIMEOUT' | 'NO_KEY' | 'UNAUTHORIZED' | 'UNKNOWN' | 'STATE_MISMATCH';\n message: string;\n}\n\n// ======= OAuth 2.1 Types =======\n\n/** OAuth configuration for third-party apps */\nexport interface OAuthConfig {\n /** OAuth client_id (registered with OpenKey) */\n clientId: string;\n /** Redirect URI (must match registered URI) */\n redirectUri: string;\n /** State parameter for CSRF protection (auto-generated if not provided) */\n state?: string;\n}\n\n/** Result from OAuth authorization */\nexport interface OAuthResult {\n /** Authorization code (exchange for tokens) */\n code: string;\n /** State parameter (verify matches request) */\n state: string;\n}\n\n/** Response from token exchange */\nexport interface OAuthTokenResponse {\n access_token: string;\n token_type: 'Bearer';\n expires_in: number;\n id_token: string;\n scope: string;\n refresh_token?: string;\n}\n\ntype MessageType =\n | { type: 'openkey:auth:request'; appName: string }\n | { type: 'openkey:auth:response'; success: true; address: string; keyId: string; keyType?: 'MANAGED' | 'EXTERNAL'; sessionToken?: string }\n | { type: 'openkey:auth:response'; success: false; error: OpenKeyError }\n | { type: 'openkey:sign:request'; message: string; keyId?: string; sessionToken?: string }\n | { type: 'openkey:sign:response'; success: true; signature: string; address: string }\n | { type: 'openkey:sign:response'; success: false; error: OpenKeyError }\n | { type: 'openkey:signTypedData:request'; data: SignTypedDataRequest; sessionToken?: string }\n | { type: 'openkey:signTypedData:response'; success: true; signature: string; address: string }\n | { type: 'openkey:signTypedData:response'; success: false; error: OpenKeyError }\n | { type: 'openkey:link-wallet:request' }\n | { type: 'openkey:link-wallet:response'; success: true; address: string; keyId: string }\n | { type: 'openkey:link-wallet:response'; success: false; error: OpenKeyError }\n | { type: 'openkey:link-wallet:delegate' }\n | { type: 'openkey:link-wallet:result'; success: true; address: string; keyId: string }\n | { type: 'openkey:link-wallet:result'; success: false; error: OpenKeyError }\n | { type: 'openkey:auth:use-external-wallet' }\n | { type: 'openkey:resize'; height: number }\n | { type: 'openkey:ready' }\n | { type: 'openkey:close' };\n\nconst DEFAULT_HOST = 'https://openkey.so';\nconst POPUP_WIDTH = 400;\nconst POPUP_HEIGHT = 600;\nconst DEFAULT_TIMEOUT = 5 * 60 * 1000; // 5 minutes\nconst IFRAME_READY_TIMEOUT = 3000; // 3 seconds\nconst OAUTH_STORAGE_KEY = 'openkey_oauth';\n\nclass IframeModal {\n private root: HTMLDivElement;\n private shadow: ShadowRoot;\n private iframe: HTMLIFrameElement;\n private onClose: () => void;\n private onMessage: (data: MessageType) => void;\n private messageHandler: (event: MessageEvent) => void;\n private host: string;\n\n constructor(opts: { url: string; host: string; onClose: () => void; onMessage: (data: MessageType) => void }) {\n this.host = opts.host;\n this.onClose = opts.onClose;\n this.onMessage = opts.onMessage;\n\n const isMobile = window.matchMedia('(max-width: 639px)').matches;\n\n this.root = document.createElement('div');\n this.shadow = this.root.attachShadow({ mode: 'closed' });\n\n const style = document.createElement('style');\n style.textContent = `\n :host{all:initial}\n .ok-backdrop{position:fixed;inset:0;background:rgba(0,0,0,0.42);z-index:999999;display:flex;align-items:${isMobile ? 'flex-end' : 'center'};justify-content:center;animation:ok-fade-in 150ms ease-out}\n .ok-card{position:relative;background:#fafafa;width:${isMobile ? '100%' : '400px'};border-radius:${isMobile ? '16px 16px 0 0' : '16px'};box-shadow:0 25px 50px -12px rgba(0,0,0,0.25);overflow:hidden;overflow-y:auto;animation:${isMobile ? 'ok-slide-up 250ms ease-out' : 'ok-scale-in 200ms ease-out'};max-height:90vh}\n .ok-close{position:absolute;top:8px;right:8px;width:24px;height:24px;border:none;background:transparent;color:#6b7280;font-size:18px;cursor:pointer;z-index:1;display:flex;align-items:center;justify-content:center;border-radius:4px}\n .ok-close:hover{color:#111827}\n .ok-handle{width:40px;height:4px;background:#d4d4d4;border-radius:2px;margin:8px auto 0}\n iframe{border:none;width:100%;height:400px;display:block;transition:height 200ms ease}\n .ok-backdrop.ok-exit{animation:ok-fade-out 150ms ease-in}\n .ok-backdrop.ok-exit .ok-card{animation:${isMobile ? 'ok-slide-down 200ms ease-in' : 'ok-scale-out 150ms ease-in'}}\n @keyframes ok-fade-in{from{opacity:0}to{opacity:1}}\n @keyframes ok-fade-out{from{opacity:1}to{opacity:0}}\n @keyframes ok-scale-in{from{opacity:0;transform:scale(0.95)}to{opacity:1;transform:scale(1)}}\n @keyframes ok-scale-out{from{opacity:1;transform:scale(1)}to{opacity:0;transform:scale(0.95)}}\n @keyframes ok-slide-up{from{transform:translateY(100%)}to{transform:translateY(0)}}\n @keyframes ok-slide-down{from{transform:translateY(0)}to{transform:translateY(100%)}}\n `;\n\n const backdrop = document.createElement('div');\n backdrop.className = 'ok-backdrop';\n backdrop.addEventListener('click', (e) => {\n if (e.target === backdrop) this.close();\n });\n\n const card = document.createElement('div');\n card.className = 'ok-card';\n\n if (isMobile) {\n const handle = document.createElement('div');\n handle.className = 'ok-handle';\n card.appendChild(handle);\n }\n\n const closeBtn = document.createElement('button');\n closeBtn.className = 'ok-close';\n closeBtn.textContent = '\\u00d7';\n closeBtn.addEventListener('click', () => this.close());\n card.appendChild(closeBtn);\n\n this.iframe = document.createElement('iframe');\n this.iframe.src = opts.url;\n this.iframe.setAttribute('allow', 'clipboard-write *; publickey-credentials-get *; publickey-credentials-create *');\n this.iframe.setAttribute('sandbox', 'allow-scripts allow-same-origin allow-forms allow-popups allow-popups-to-escape-sandbox');\n card.appendChild(this.iframe);\n\n backdrop.appendChild(card);\n this.shadow.appendChild(style);\n this.shadow.appendChild(backdrop);\n\n this.messageHandler = (event: MessageEvent) => {\n if (event.origin !== this.host) return;\n if (event.source !== this.iframe.contentWindow) return;\n const data = event.data as MessageType;\n if (data.type === 'openkey:resize') {\n const h = Math.min(data.height, Math.floor(window.innerHeight * 0.85));\n this.iframe.style.height = `${h}px`;\n return;\n }\n this.onMessage(data);\n };\n window.addEventListener('message', this.messageHandler);\n document.body.appendChild(this.root);\n }\n\n postMessage(message: object) {\n this.iframe.contentWindow?.postMessage(message, this.host);\n }\n\n destroy() {\n window.removeEventListener('message', this.messageHandler);\n this.root.remove();\n }\n\n private close() {\n const backdrop = this.shadow.querySelector('.ok-backdrop');\n if (backdrop) {\n backdrop.classList.add('ok-exit');\n setTimeout(() => {\n this.destroy();\n this.onClose();\n }, 200);\n } else {\n this.destroy();\n this.onClose();\n }\n }\n}\n\nclass WalletPicker {\n private root: HTMLDivElement;\n private shadow: ShadowRoot;\n\n constructor(opts: { providers: EIP6963ProviderDetail[]; onSelect: (provider: EIP1193Provider) => void; onCancel: () => void }) {\n this.root = document.createElement('div');\n this.shadow = this.root.attachShadow({ mode: 'closed' });\n\n const style = document.createElement('style');\n style.textContent = `\n :host{all:initial}\n .wp-backdrop{position:fixed;inset:0;background:rgba(0,0,0,0.42);z-index:1000000;display:flex;align-items:center;justify-content:center;animation:wp-fade 150ms ease-out}\n .wp-card{background:#fff;width:340px;border-radius:16px;box-shadow:0 25px 50px -12px rgba(0,0,0,0.25);padding:20px;animation:wp-scale 200ms ease-out}\n .wp-title{font:600 16px/1.3 system-ui,sans-serif;color:#111;margin:0 0 12px}\n .wp-list{list-style:none;margin:0;padding:0;display:flex;flex-direction:column;gap:6px}\n .wp-item{display:flex;align-items:center;gap:10px;padding:10px 12px;border:1px solid #e5e7eb;border-radius:10px;background:transparent;cursor:pointer;font:14px/1.3 system-ui,sans-serif;color:#111;width:100%;text-align:left;transition:border-color 150ms}\n .wp-item:hover{border-color:#6366f1}\n .wp-icon{width:28px;height:28px;border-radius:6px}\n .wp-empty{font:14px/1.4 system-ui,sans-serif;color:#6b7280;text-align:center;padding:16px 0}\n .wp-cancel{display:block;width:100%;margin-top:12px;padding:8px;border:none;background:transparent;color:#6b7280;font:14px/1.3 system-ui,sans-serif;cursor:pointer;border-radius:8px}\n .wp-cancel:hover{background:#f3f4f6;color:#111}\n @keyframes wp-fade{from{opacity:0}to{opacity:1}}\n @keyframes wp-scale{from{opacity:0;transform:scale(0.95)}to{opacity:1;transform:scale(1)}}\n @media(prefers-color-scheme:dark){\n .wp-card{background:#1a1a1a;box-shadow:0 25px 50px -12px rgba(0,0,0,0.5)}\n .wp-title{color:#f3f4f6}\n .wp-item{border-color:#374151;color:#f3f4f6}\n .wp-item:hover{border-color:#818cf8}\n .wp-empty{color:#9ca3af}\n .wp-cancel{color:#9ca3af}\n .wp-cancel:hover{background:#262626;color:#f3f4f6}\n }\n `;\n\n const backdrop = document.createElement('div');\n backdrop.className = 'wp-backdrop';\n backdrop.addEventListener('click', (e) => { if (e.target === backdrop) { this.destroy(); opts.onCancel(); } });\n\n const card = document.createElement('div');\n card.className = 'wp-card';\n\n const title = document.createElement('h2');\n title.className = 'wp-title';\n title.textContent = 'Select a wallet';\n card.appendChild(title);\n\n if (opts.providers.length === 0) {\n const empty = document.createElement('div');\n empty.className = 'wp-empty';\n empty.textContent = 'No wallets detected';\n card.appendChild(empty);\n } else {\n const list = document.createElement('ul');\n list.className = 'wp-list';\n for (const { info, provider } of opts.providers) {\n const item = document.createElement('button');\n item.className = 'wp-item';\n if (info.icon) {\n const icon = document.createElement('img');\n icon.className = 'wp-icon';\n icon.src = info.icon;\n icon.alt = info.name;\n item.appendChild(icon);\n }\n const name = document.createElement('span');\n name.textContent = info.name;\n item.appendChild(name);\n item.addEventListener('click', () => { this.destroy(); opts.onSelect(provider); });\n list.appendChild(item);\n }\n card.appendChild(list);\n }\n\n const cancel = document.createElement('button');\n cancel.className = 'wp-cancel';\n cancel.textContent = 'Cancel';\n cancel.addEventListener('click', () => { this.destroy(); opts.onCancel(); });\n card.appendChild(cancel);\n\n backdrop.appendChild(card);\n this.shadow.appendChild(style);\n this.shadow.appendChild(backdrop);\n document.body.appendChild(this.root);\n }\n\n destroy() {\n this.root.remove();\n }\n}\n\nfunction showToast(message = 'Opening in new window\\u2026', variant: 'info' | 'error' = 'info') {\n const bg = variant === 'error' ? '#dc2626' : '#1f2937';\n const root = document.createElement('div');\n const shadow = root.attachShadow({ mode: 'closed' });\n shadow.innerHTML = `<style>:host{all:initial}.ok-toast{position:fixed;top:16px;right:16px;z-index:1000000;background:${bg};color:#f9fafb;padding:10px 16px;border-radius:8px;font:14px/1.4 system-ui,sans-serif;box-shadow:0 4px 12px rgba(0,0,0,0.15);animation:ok-t-in 200ms ease-out;max-width:360px}@keyframes ok-t-in{from{opacity:0;transform:translateY(-8px)}to{opacity:1;transform:translateY(0)}}</style><div class=\"ok-toast\">${message}</div>`;\n document.body.appendChild(root);\n setTimeout(() => root.remove(), 4000);\n}\n\nclass ExternalWalletError extends Error {\n constructor(message: string) {\n super(message);\n this.name = 'ExternalWalletError';\n }\n}\n\nexport class OpenKey {\n private host: string;\n private oauthHost: string;\n private appName: string;\n private mode: OpenKeyMode;\n private config: OpenKeyConfig;\n private popup: Window | null = null;\n private lastAuth: AuthResult | null = null;\n private discoveredProviders: EIP6963ProviderDetail[] = [];\n private sessionToken: string | null = null;\n\n constructor(config: OpenKeyConfig = {}) {\n this.config = config;\n this.host = config.host || DEFAULT_HOST;\n this.oauthHost = config.oauthHost || this.deriveOAuthHost(this.host);\n this.appName = config.appName || window.location.hostname;\n this.mode = config.mode ?? 'iframe';\n\n // Listen for EIP-6963 wallet announcements\n if (typeof window !== 'undefined') {\n this.discoveredProviders = [];\n window.addEventListener('eip6963:announceProvider', (event: any) => {\n this.discoveredProviders.push(event.detail);\n });\n window.dispatchEvent(new Event('eip6963:requestProvider'));\n }\n }\n\n /**\n * Derive the OAuth API host from the main host by prefixing 'api.'\n * @param host - The main host URL\n * @returns The derived OAuth API host URL\n */\n private deriveOAuthHost(host: string): string {\n try {\n const url = new URL(host);\n if (url.hostname === 'localhost' || url.hostname === '127.0.0.1') {\n return host.replace(/\\/$/, '');\n }\n url.hostname = 'api.' + url.hostname;\n return url.toString().replace(/\\/$/, '');\n } catch {\n return 'https://api.openkey.so';\n }\n }\n\n /**\n * Connect to OpenKey and get user's wallet address\n * Opens auth flow for user to select/create a key\n */\n async connect(opts?: { mode?: OpenKeyMode }): Promise<AuthResult> {\n const result = await this.openFlow<AuthResult>('connect', {\n type: 'openkey:auth:request',\n appName: this.appName,\n }, opts?.mode);\n this.lastAuth = result;\n return result;\n }\n\n /**\n * Better-auth session token relayed during connect(), or null if the\n * flow did not provide one. Use as a bearer token for API calls made\n * on the user's behalf (e.g. TinyCloud auto-sign bootstrap signing).\n */\n getSessionToken(): string | null {\n return this.sessionToken;\n }\n\n /**\n * Endpoint + bearer token for a TinyCloud auto-sign signing strategy.\n * The endpoint is on the OpenKey API host and only signs requests the\n * server-side bootstrap allowlist permits.\n */\n tinycloudSigningOptions(): { endpoint: string; token: string | null } {\n return {\n endpoint: `${this.oauthHost}/api/delegate/sign`,\n token: this.sessionToken,\n };\n }\n\n /**\n * Link an external wallet to the user's OpenKey account\n * Opens link-wallet widget flow\n */\n async linkWallet(opts?: { mode?: OpenKeyMode }): Promise<{ address: string; keyId: string }> {\n return this.openFlow<{ address: string; keyId: string }>('link-wallet', {\n type: 'openkey:link-wallet:request',\n }, opts?.mode);\n }\n\n /**\n * Sign a message with the user's OpenKey wallet\n * For external keys, routes directly to the user's wallet provider\n */\n async signMessage(request: SignMessageRequest, opts?: { mode?: OpenKeyMode }): Promise<SignResult> {\n if (this.lastAuth?.keyType === 'EXTERNAL') {\n return this.signWithExternalWallet(request);\n }\n return this.signWithOpenKey(request, opts?.mode);\n }\n\n /**\n * Sign typed data (EIP-712) with the user's OpenKey wallet\n * For external keys, routes directly to the user's wallet provider\n */\n async signTypedData(request: SignTypedDataRequest, opts?: { mode?: OpenKeyMode }): Promise<SignResult> {\n if (this.lastAuth?.keyType === 'EXTERNAL') {\n return this.signTypedDataWithExternalWallet(request);\n }\n return this.signTypedDataWithOpenKey(request, opts?.mode);\n }\n\n private providerCandidates(): EIP1193Provider[] {\n const providers: EIP1193Provider[] = [];\n if (this.config.externalProvider) {\n providers.push(this.config.externalProvider);\n }\n providers.push(...this.discoveredProviders.map(({ provider }) => provider));\n if (typeof window !== 'undefined' && (window as any).ethereum) {\n providers.push((window as any).ethereum as EIP1193Provider);\n }\n return [...new Set(providers)];\n }\n\n private async providerHasAccount(\n provider: EIP1193Provider,\n method: 'eth_accounts' | 'eth_requestAccounts',\n targetAddress: string\n ): Promise<boolean> {\n try {\n const accounts = await provider.request({ method }) as string[];\n return accounts.some((account) => account.toLowerCase() === targetAddress.toLowerCase());\n } catch {\n return false;\n }\n }\n\n /**\n * Find a wallet provider that controls the given address.\n * Checks connected accounts first, then asks the wallet to authorize the\n * app origin if the external key was linked elsewhere.\n */\n async findWalletProvider(targetAddress: string): Promise<EIP1193Provider> {\n const providers = this.providerCandidates();\n\n for (const provider of providers) {\n if (await this.providerHasAccount(provider, 'eth_accounts', targetAddress)) {\n return provider;\n }\n }\n\n for (const provider of providers) {\n if (await this.providerHasAccount(provider, 'eth_requestAccounts', targetAddress)) {\n return provider;\n }\n }\n\n throw new ExternalWalletError('External wallet not found. Connect the wallet that owns this key and try again.');\n }\n\n private async signWithExternalWallet(request: SignMessageRequest): Promise<SignResult> {\n let provider: EIP1193Provider;\n try {\n provider = await this.findWalletProvider(this.lastAuth!.address);\n } catch (e) {\n showToast((e as Error).message, 'error');\n throw e;\n }\n try {\n const hexMessage = this.toHex(request.message);\n const signature = await provider.request({\n method: 'personal_sign',\n params: [hexMessage, this.lastAuth!.address],\n });\n return { signature: signature as string, address: this.lastAuth!.address };\n } catch (e: any) {\n const msg = e?.message?.includes('not been authorized')\n ? 'Wallet rejected the request. Approve the connection in your wallet and try again.'\n : e?.message || 'Signing failed';\n showToast(msg, 'error');\n throw new Error(msg);\n }\n }\n\n private async signTypedDataWithExternalWallet(request: SignTypedDataRequest): Promise<SignResult> {\n let provider: EIP1193Provider;\n try {\n provider = await this.findWalletProvider(this.lastAuth!.address);\n } catch (e) {\n showToast((e as Error).message, 'error');\n throw e;\n }\n try {\n const signature = await provider.request({\n method: 'eth_signTypedData_v4',\n params: [this.lastAuth!.address, JSON.stringify(request)],\n });\n return { signature: signature as string, address: this.lastAuth!.address };\n } catch (e: any) {\n const msg = e?.message?.includes('not been authorized')\n ? 'Wallet rejected the request. Approve the connection in your wallet and try again.'\n : e?.message || 'Signing failed';\n showToast(msg, 'error');\n throw new Error(msg);\n }\n }\n\n private signWithOpenKey(request: SignMessageRequest, mode?: OpenKeyMode): Promise<SignResult> {\n return this.openFlow<SignResult>('sign', {\n type: 'openkey:sign:request',\n message: request.message,\n keyId: request.keyId,\n sessionToken: this.sessionToken || undefined,\n }, mode);\n }\n\n private signTypedDataWithOpenKey(request: SignTypedDataRequest, mode?: OpenKeyMode): Promise<SignResult> {\n return this.openFlow<SignResult>('sign-typed-data', {\n type: 'openkey:signTypedData:request',\n data: request,\n sessionToken: this.sessionToken || undefined,\n }, mode);\n }\n\n private toHex(str: string): string {\n return '0x' + Array.from(new TextEncoder().encode(str)).map(b => b.toString(16).padStart(2, '0')).join('');\n }\n\n /**\n * Check if user is already authenticated\n */\n async isConnected(): Promise<boolean> {\n // Check for existing session via API\n try {\n const res = await fetch(`${this.host}/api/auth/session`, {\n credentials: 'include',\n });\n if (!res.ok) return false;\n const data = await res.json();\n return !!data.user;\n } catch {\n return false;\n }\n }\n\n // ======= OAuth 2.1 Provider Methods =======\n\n /**\n * OAuth 2.1 methods for third-party app authentication\n * Use this when your app has registered OAuth client credentials with OpenKey\n */\n oauth = {\n /**\n * Start OAuth authorization flow\n * Opens popup/redirect to OpenKey authorization endpoint\n * @returns Promise that resolves with authorization code after user consent\n */\n connect: async (config: OAuthConfig): Promise<OAuthResult> => {\n // Generate PKCE values\n const verifier = generateCodeVerifier();\n const challenge = await generateCodeChallenge(verifier);\n const state = config.state || generateState();\n\n // Store for later token exchange\n sessionStorage.setItem(\n OAUTH_STORAGE_KEY,\n JSON.stringify({ verifier, state })\n );\n\n // Build authorization URL\n const authUrl = buildAuthorizationUrl({\n host: this.oauthHost,\n clientId: config.clientId,\n redirectUri: config.redirectUri,\n codeChallenge: challenge,\n state,\n scopes: ['openid'],\n });\n\n return this.openOAuthFlow(authUrl, state, config.redirectUri);\n },\n\n /**\n * Exchange authorization code for tokens\n * Call this after receiving the callback with authorization code\n * @param code - Authorization code from callback URL\n * @param config - Same config used for connect()\n * @returns Promise that resolves with access_token, id_token, etc.\n */\n exchangeCode: async (\n code: string,\n config: OAuthConfig\n ): Promise<OAuthTokenResponse> => {\n const stored = sessionStorage.getItem(OAUTH_STORAGE_KEY);\n if (!stored) {\n throw new Error('No PKCE verifier found. Start a new OAuth flow.');\n }\n\n const { verifier } = JSON.parse(stored);\n\n const response = await fetch(`${this.oauthHost}/api/auth/oauth2/token`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/x-www-form-urlencoded',\n },\n body: new URLSearchParams({\n grant_type: 'authorization_code',\n code,\n redirect_uri: config.redirectUri,\n client_id: config.clientId,\n code_verifier: verifier,\n }),\n });\n\n // Clear stored verifier\n sessionStorage.removeItem(OAUTH_STORAGE_KEY);\n\n if (!response.ok) {\n const error = await response.json();\n throw new Error(error.error_description || 'Token exchange failed');\n }\n\n return response.json();\n },\n\n /**\n * Verify state parameter from callback\n * Call this before exchangeCode to prevent CSRF attacks\n * @param receivedState - State parameter from callback URL\n * @returns true if state matches, false otherwise\n */\n verifyState: (receivedState: string): boolean => {\n const stored = sessionStorage.getItem(OAUTH_STORAGE_KEY);\n if (!stored) return false;\n const { state } = JSON.parse(stored);\n return state === receivedState;\n },\n\n /**\n * Parse authorization response from callback URL\n * @param url - Callback URL (defaults to current window.location.href)\n * @returns Parsed code and state, or error\n */\n parseCallback: (\n url?: string\n ): { code: string; state: string } | { error: string; errorDescription?: string } => {\n const urlObj = new URL(url || window.location.href);\n const error = urlObj.searchParams.get('error');\n\n if (error) {\n return {\n error,\n errorDescription: urlObj.searchParams.get('error_description') || undefined,\n };\n }\n\n const code = urlObj.searchParams.get('code');\n const state = urlObj.searchParams.get('state');\n\n if (!code || !state) {\n return { error: 'missing_params', errorDescription: 'Missing code or state parameter' };\n }\n\n return { code, state };\n },\n };\n\n private openOAuthFlow(\n url: string,\n state: string,\n redirectUri: string\n ): Promise<OAuthResult> {\n return new Promise((resolve, reject) => {\n if (this.mode !== 'redirect') {\n this.openOAuthPopup(url, state, redirectUri, resolve, reject);\n } else {\n // Full page redirect - won't resolve, page navigates away\n window.location.href = url;\n }\n });\n }\n\n private openOAuthPopup(\n url: string,\n state: string,\n redirectUri: string,\n resolve: (value: OAuthResult) => void,\n reject: (error: OpenKeyError) => void\n ) {\n const left = window.screenX + (window.outerWidth - POPUP_WIDTH) / 2;\n const top = window.screenY + (window.outerHeight - POPUP_HEIGHT) / 2;\n\n this.popup = window.open(\n url,\n 'openkey-oauth',\n `width=${POPUP_WIDTH},height=${POPUP_HEIGHT},left=${left},top=${top},popup=true`\n );\n\n if (!this.popup) {\n showToast('Popup was blocked. Please allow popups for this site.', 'error');\n reject({\n code: 'POPUP_BLOCKED',\n message: 'Popup was blocked. Please allow popups or use redirect mode.',\n });\n return;\n }\n\n const redirectHost = new URL(redirectUri).origin;\n\n // Poll for redirect back with code\n const pollInterval = setInterval(() => {\n try {\n if (this.popup?.closed) {\n clearInterval(pollInterval);\n clearTimeout(timeout);\n reject({\n code: 'USER_CANCELLED',\n message: 'User closed the popup',\n });\n return;\n }\n\n // Check if redirected to callback URL\n const popupUrl = this.popup?.location?.href;\n if (popupUrl && popupUrl.startsWith(redirectHost)) {\n clearInterval(pollInterval);\n clearTimeout(timeout);\n\n const urlObj = new URL(popupUrl);\n const code = urlObj.searchParams.get('code');\n const returnedState = urlObj.searchParams.get('state');\n const error = urlObj.searchParams.get('error');\n\n this.popup?.close();\n\n if (error) {\n reject({\n code: 'UNAUTHORIZED',\n message: urlObj.searchParams.get('error_description') || error,\n });\n return;\n }\n\n if (returnedState !== state) {\n reject({\n code: 'STATE_MISMATCH',\n message: 'State mismatch - possible CSRF attack',\n });\n return;\n }\n\n if (code) {\n resolve({ code, state: returnedState });\n } else {\n reject({\n code: 'UNAUTHORIZED',\n message: 'Authorization failed - no code returned',\n });\n }\n }\n } catch {\n // Cross-origin - popup still on OpenKey domain, continue polling\n }\n }, 100);\n\n // Timeout\n const timeout = setTimeout(() => {\n clearInterval(pollInterval);\n this.popup?.close();\n reject({\n code: 'TIMEOUT',\n message: 'OAuth flow timed out',\n });\n }, DEFAULT_TIMEOUT);\n }\n\n private resolveMode(override?: OpenKeyMode): OpenKeyMode {\n return override ?? this.mode;\n }\n\n private hasDetectedEoa(): boolean {\n if (this.discoveredProviders.length > 0) return true;\n if (typeof window !== 'undefined' && (window as any).ethereum) return true;\n return false;\n }\n\n private async openFlow<T>(action: string, message: object, modeOverride?: OpenKeyMode): Promise<T> {\n const mode = this.resolveMode(modeOverride);\n const origin = encodeURIComponent(window.location.origin);\n const eoaFlag = action === 'connect' && this.hasDetectedEoa() ? '&hasEoa=true' : '';\n\n if (mode === 'popup') {\n const url = `${this.host}/widget/${action}?origin=${origin}${eoaFlag}`;\n return new Promise((resolve, reject) => this.openPopup(url, message, resolve, reject));\n }\n\n if (mode === 'redirect') {\n const url = `${this.host}/widget/${action}?origin=${origin}${eoaFlag}`;\n window.location.href = url;\n return new Promise(() => {}); // never resolves, page navigates\n }\n\n // iframe mode with auto-fallback\n const url = `${this.host}/widget/embed/${action}?origin=${origin}${eoaFlag}`;\n return this.openIframeModal<T>(url, action, message, origin);\n }\n\n private openIframeModal<T>(url: string, action: string, message: object, origin: string): Promise<T> {\n return new Promise((resolve, reject) => {\n let readyReceived = false;\n let settled = false;\n let modal: IframeModal | null = null;\n\n const settle = (fn: () => void) => {\n if (settled) return;\n settled = true;\n fn();\n };\n\n const cleanup = () => {\n clearTimeout(readyTimeout);\n clearTimeout(overallTimeout);\n modal?.destroy();\n modal = null;\n };\n\n modal = new IframeModal({\n url,\n host: this.host,\n onClose: () => {\n settle(() => {\n clearTimeout(readyTimeout);\n clearTimeout(overallTimeout);\n modal = null;\n reject({ code: 'USER_CANCELLED', message: 'User cancelled the request' } as OpenKeyError);\n });\n },\n onMessage: (data: MessageType) => {\n if (data.type === 'openkey:ready') {\n readyReceived = true;\n modal?.postMessage(message);\n return;\n }\n\n if (data.type === 'openkey:close') {\n settle(() => {\n cleanup();\n reject({ code: 'USER_CANCELLED', message: 'User cancelled the request' } as OpenKeyError);\n });\n return;\n }\n\n if (data.type === 'openkey:link-wallet:delegate') {\n this.handleWalletLinkDelegation(modal!);\n return;\n }\n\n if (data.type === 'openkey:auth:use-external-wallet') {\n cleanup();\n this.handleExternalWalletConnect<T>(resolve, reject);\n return;\n }\n\n if (\n data.type === 'openkey:auth:response' ||\n data.type === 'openkey:sign:response' ||\n data.type === 'openkey:signTypedData:response' ||\n data.type === 'openkey:link-wallet:response'\n ) {\n settle(() => {\n cleanup();\n if (data.success) {\n if (data.type === 'openkey:auth:response') {\n if (data.sessionToken) this.sessionToken = data.sessionToken;\n resolve({ address: data.address, keyId: data.keyId, keyType: data.keyType || 'MANAGED' } as T);\n } else if (data.type === 'openkey:link-wallet:response') {\n resolve({ address: data.address, keyId: data.keyId } as T);\n } else {\n resolve({ signature: data.signature, address: data.address } as T);\n }\n } else {\n reject(data.error);\n }\n });\n }\n },\n });\n\n // Auto-fallback: if no openkey:ready within 3s, fall back to popup\n const readyTimeout = setTimeout(() => {\n if (readyReceived || settled) return;\n cleanup();\n console.warn('OpenKey: iframe blocked by CSP, falling back to popup. Add frame-src https://openkey.so to your CSP.');\n showToast();\n const popupUrl = `${this.host}/widget/${action}?origin=${origin}`;\n this.openPopup(popupUrl, message, (val: any) => settle(() => resolve(val)), (err: any) => settle(() => reject(err)));\n }, IFRAME_READY_TIMEOUT);\n\n // Overall 5-minute timeout\n const overallTimeout = setTimeout(() => {\n settle(() => {\n cleanup();\n reject({ code: 'TIMEOUT', message: 'Request timed out' } as OpenKeyError);\n });\n }, DEFAULT_TIMEOUT);\n });\n }\n\n private handleWalletLinkDelegation(modal: IframeModal) {\n const sendResult = (result: MessageType) => modal.postMessage(result);\n\n new WalletPicker({\n providers: this.discoveredProviders,\n onCancel: () => {\n sendResult({ type: 'openkey:link-wallet:result', success: false, error: { code: 'USER_CANCELLED', message: 'Wallet linking cancelled' } });\n },\n onSelect: async (provider) => {\n try {\n const accounts = await provider.request({ method: 'eth_requestAccounts' }) as string[];\n const address = accounts[0];\n if (!address) throw new Error('No account returned');\n\n // Get challenge from API\n const challengeRes = await fetch(`${this.host}/api/keys/link/challenge`, {\n method: 'POST',\n credentials: 'include',\n });\n if (!challengeRes.ok) throw new Error('Failed to get challenge');\n const { message } = await challengeRes.json();\n\n // Sign challenge with wallet\n const hexMessage = this.toHex(message);\n const signature = await provider.request({\n method: 'personal_sign',\n params: [hexMessage, address],\n }) as string;\n\n // Submit to API\n const linkRes = await fetch(`${this.host}/api/keys/link`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n credentials: 'include',\n body: JSON.stringify({ address, signature, message }),\n });\n if (!linkRes.ok) {\n const err = await linkRes.json();\n throw new Error(err.error || 'Failed to link wallet');\n }\n const { key } = await linkRes.json();\n\n sendResult({ type: 'openkey:link-wallet:result', success: true, address: key.address, keyId: key.id });\n } catch (e: any) {\n sendResult({ type: 'openkey:link-wallet:result', success: false, error: { code: 'UNKNOWN', message: e.message || 'Wallet linking failed' } });\n }\n },\n });\n }\n\n private handleExternalWalletConnect<T>(\n resolve: (value: T) => void,\n reject: (error: OpenKeyError) => void\n ) {\n new WalletPicker({\n providers: this.discoveredProviders,\n onCancel: () => {\n reject({ code: 'USER_CANCELLED', message: 'User cancelled wallet selection' });\n },\n onSelect: async (provider) => {\n try {\n const accounts = await provider.request({ method: 'eth_requestAccounts' }) as string[];\n const address = accounts[0];\n if (!address) throw new Error('No account returned');\n const result = { address, keyId: `external:${address}`, keyType: 'EXTERNAL' as const };\n this.lastAuth = result;\n resolve(result as T);\n } catch (e: any) {\n reject({ code: 'UNKNOWN', message: e.message || 'Failed to connect wallet' });\n }\n },\n });\n }\n\n private openPopup<T>(\n url: string,\n message: object,\n resolve: (value: T) => void,\n reject: (error: OpenKeyError) => void\n ) {\n // Calculate popup position\n const left = window.screenX + (window.outerWidth - POPUP_WIDTH) / 2;\n const top = window.screenY + (window.outerHeight - POPUP_HEIGHT) / 2;\n\n this.popup = window.open(\n url,\n 'openkey',\n `width=${POPUP_WIDTH},height=${POPUP_HEIGHT},left=${left},top=${top},popup=true`\n );\n\n if (!this.popup) {\n showToast('Popup was blocked. Please allow popups for this site.', 'error');\n reject({\n code: 'POPUP_BLOCKED',\n message: 'Popup was blocked. Please allow popups for this site.',\n });\n return;\n }\n\n const cleanup = () => {\n window.removeEventListener('message', handleMessage);\n clearInterval(pollClosed);\n clearTimeout(timeout);\n };\n\n // Poll to detect popup close\n const pollClosed = setInterval(() => {\n if (this.popup?.closed) {\n cleanup();\n reject({\n code: 'USER_CANCELLED',\n message: 'User closed the popup',\n });\n }\n }, 500);\n\n // Timeout\n const timeout = setTimeout(() => {\n cleanup();\n this.popup?.close();\n reject({\n code: 'TIMEOUT',\n message: 'Request timed out',\n });\n }, DEFAULT_TIMEOUT);\n\n // Listen for messages\n const handleMessage = (event: MessageEvent) => {\n if (event.origin !== this.host) return;\n if (event.source !== this.popup) return;\n\n const data = event.data as MessageType;\n\n if (data.type === 'openkey:ready') {\n // Widget is ready, send our request\n this.popup?.postMessage(message, this.host);\n return;\n }\n\n if (data.type === 'openkey:close') {\n cleanup();\n this.popup?.close();\n reject({\n code: 'USER_CANCELLED',\n message: 'User cancelled the request',\n });\n return;\n }\n\n if (data.type === 'openkey:auth:use-external-wallet') {\n cleanup();\n this.popup?.close();\n this.handleExternalWalletConnect<T>(resolve, reject);\n return;\n }\n\n // Handle responses\n if (\n data.type === 'openkey:auth:response' ||\n data.type === 'openkey:sign:response' ||\n data.type === 'openkey:signTypedData:response' ||\n data.type === 'openkey:link-wallet:response'\n ) {\n cleanup();\n this.popup?.close();\n\n if (data.success) {\n if (data.type === 'openkey:auth:response') {\n if (data.sessionToken) this.sessionToken = data.sessionToken;\n resolve({ address: data.address, keyId: data.keyId, keyType: data.keyType || 'MANAGED' } as T);\n } else if (data.type === 'openkey:link-wallet:response') {\n resolve({ address: data.address, keyId: data.keyId } as T);\n } else {\n resolve({ signature: data.signature, address: data.address } as T);\n }\n } else {\n reject(data.error);\n }\n }\n };\n\n window.addEventListener('message', handleMessage);\n }\n\n /**\n * Disconnect and close any open flows\n */\n disconnect() {\n this.popup?.close();\n this.popup = null;\n }\n}\n\n/**\n * EIP-1193 compatible provider that wraps an OpenKey instance.\n * Transparently routes signing to either OpenKey (managed keys) or the user's\n * wallet (external keys).\n */\nexport class OpenKeyProvider implements EIP1193Provider {\n private openkey: OpenKey;\n private address: string;\n private keyId: string;\n private keyType: 'MANAGED' | 'EXTERNAL';\n\n constructor(openkey: OpenKey, authResult: AuthResult) {\n this.openkey = openkey;\n this.address = authResult.address;\n this.keyId = authResult.keyId;\n this.keyType = authResult.keyType;\n }\n\n async request({ method, params }: { method: string; params?: any[] }): Promise<any> {\n switch (method) {\n case 'eth_accounts':\n case 'eth_requestAccounts':\n return [this.address];\n\n case 'eth_chainId':\n return '0x1'; // mainnet\n\n case 'personal_sign': {\n if (this.keyType === 'EXTERNAL') {\n try {\n const provider = await this.openkey.findWalletProvider(this.address);\n return await provider.request({ method, params });\n } catch (e: any) {\n showToast(e?.message || 'External wallet signing failed', 'error');\n throw e;\n }\n }\n // Managed key: route through OpenKey\n const message = this.hexToString(params![0] as string);\n const result = await this.openkey.signMessage({ message, keyId: this.keyId });\n return result.signature;\n }\n\n case 'eth_signTypedData_v4': {\n if (this.keyType === 'EXTERNAL') {\n try {\n const provider = await this.openkey.findWalletProvider(this.address);\n return await provider.request({ method, params });\n } catch (e: any) {\n showToast(e?.message || 'External wallet signing failed', 'error');\n throw e;\n }\n }\n const data = JSON.parse(params![1] as string);\n const result = await this.openkey.signTypedData(data);\n return result.signature;\n }\n\n default:\n throw new Error(`Unsupported method: ${method}`);\n }\n }\n\n private hexToString(hex: string): string {\n const bytes = new Uint8Array(\n (hex.startsWith('0x') ? hex.slice(2) : hex).match(/.{1,2}/g)!.map(b => parseInt(b, 16))\n );\n return new TextDecoder().decode(bytes);\n }\n}\n\n// Default export for convenience\nexport default OpenKey;\n\n// Create singleton instance\nlet defaultInstance: OpenKey | null = null;\n\nexport function getOpenKey(config?: OpenKeyConfig): OpenKey {\n if (!defaultInstance || config) {\n defaultInstance = new OpenKey(config);\n }\n return defaultInstance;\n}\n"],"mappings":"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","names":["url"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@openkey/sdk",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.9.0",
|
|
4
4
|
"main": "./dist/index.js",
|
|
5
5
|
"module": "./dist/index.mjs",
|
|
6
6
|
"types": "./dist/index.d.ts",
|
|
@@ -24,10 +24,10 @@
|
|
|
24
24
|
"typecheck": "tsc --noEmit"
|
|
25
25
|
},
|
|
26
26
|
"dependencies": {
|
|
27
|
-
"@openkey/core": "^0.
|
|
27
|
+
"@openkey/core": "^0.8.8"
|
|
28
28
|
},
|
|
29
29
|
"devDependencies": {
|
|
30
30
|
"tsup": "^8.0.0",
|
|
31
|
-
"typescript": "^
|
|
31
|
+
"typescript": "^6.0.0"
|
|
32
32
|
}
|
|
33
33
|
}
|