@emblemvault/auth-sdk 2.3.15 → 2.3.17
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/EmblemAuthSDK.d.ts.map +1 -1
- package/dist/crypto/index.d.ts +50 -0
- package/dist/crypto/index.d.ts.map +1 -0
- package/dist/crypto/index.js +2 -0
- package/dist/crypto/index.js.map +1 -0
- package/dist/crypto/index.mjs +2 -0
- package/dist/crypto/index.mjs.map +1 -0
- package/dist/crypto/types.d.ts +41 -0
- package/dist/crypto/types.d.ts.map +1 -0
- package/dist/emblem-auth.min.js +1 -1
- package/dist/emblem-auth.min.js.map +1 -1
- package/dist/emblem-auth.umd.js +1 -1
- package/dist/emblem-auth.umd.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +1 -1
- package/dist/index.mjs.map +1 -1
- package/dist/signers/ethers.js.map +1 -1
- package/dist/signers/ethers.mjs.map +1 -1
- package/dist/signers/index.js +1 -1
- package/dist/signers/index.js.map +1 -1
- package/dist/signers/index.mjs +1 -1
- package/dist/signers/index.mjs.map +1 -1
- package/dist/signers/validation.d.ts.map +1 -1
- package/dist/signers/viem.js.map +1 -1
- package/dist/signers/viem.mjs.map +1 -1
- package/dist/signers/web3.js.map +1 -1
- package/dist/signers/web3.mjs.map +1 -1
- package/dist/types/auth.d.ts +15 -0
- package/dist/types/auth.d.ts.map +1 -1
- package/dist/types/index.d.ts +1 -0
- package/dist/types/index.d.ts.map +1 -1
- package/package.json +6 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"EmblemAuthSDK.d.ts","sourceRoot":"","sources":["../src/EmblemAuthSDK.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACV,gBAAgB,EAChB,WAAW,EACX,gBAAgB,EAKhB,YAAY,EACZ,gBAAgB,EAChB,SAAS,EACT,GAAG,EAEH,kBAAkB,EAClB,oBAAoB,EACpB,gBAAgB,EAChB,aAAa,EACd,MAAM,SAAS,CAAC;AAIjB,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAC;AAC3D,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAC;AAC3D,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AACxD,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAC;AAE7D,qBAAa,aAAa;IACxB,OAAO,CAAC,QAAQ,CAAC,MAAM,CAIrB;IACF,OAAO,CAAC,OAAO,CAA4B;IAC3C,OAAO,CAAC,YAAY,CAAuB;IAC3C,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAgC;IAC/D,OAAO,CAAC,SAAS,CAA4B;IAC7C,OAAO,CAAC,SAAS,CAAkC;IACnD,OAAO,CAAC,cAAc,CAA6B;IACnD,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAiB;IAC5C,OAAO,CAAC,QAAQ,CAAC,MAAM,CAA8D;IACrF,OAAO,CAAC,gBAAgB,CAA0B;IAClD,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAS;IACpC,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAS;IACtC,OAAO,CAAC,UAAU,CAAuB;gBAE7B,MAAM,EAAE,gBAAgB;IAkDpC,OAAO,CAAC,yBAAyB;IAyCjC;;;OAGG;IACG,kBAAkB,CAAC,MAAM,EAAE,gBAAgB,GAAG,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC;IA8C/E;;;OAGG;IACG,SAAS,CAAC,QAAQ,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC;IA+CvD;;OAEG;IACG,YAAY,CAChB,MAAM,EAAE,kBAAkB,GACzB,OAAO,CAAC;QAAE,OAAO,EAAE,OAAO,CAAC;QAAC,SAAS,CAAC,EAAE,MAAM,CAAC;QAAC,GAAG,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IAqBlE;;OAEG;IACG,cAAc,CAAC,MAAM,EAAE,oBAAoB,GAAG,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC;IA6B/E;;OAEG;IACG,iBAAiB,CAAC,MAAM,EAAE,gBAAgB,GAAG,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC;IA4B9E;;;;;;;;;;;;;;OAcG;IACG,oBAAoB,CAAC,MAAM,EAAE;QAAE,QAAQ,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC;IA2BrF;;OAEG;IACG,aAAa,IAAI,OAAO,CAAC,IAAI,CAAC;IAsDpC;;OAEG;IACH,UAAU,IAAI,WAAW,GAAG,IAAI;IAIhC;;;OAGG;IACH,YAAY,IAAI,MAAM,GAAG,IAAI;IAI7B;;;;;OAKG;IACG,cAAc,IAAI,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC;IA0CnD;;OAEG;IACG,YAAY,IAAI,OAAO,CAAC,SAAS,CAAC;
|
|
1
|
+
{"version":3,"file":"EmblemAuthSDK.d.ts","sourceRoot":"","sources":["../src/EmblemAuthSDK.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import type { EncryptConfig, EncryptResult, DecryptConfig } from './types';
|
|
2
|
+
export type { EncryptConfig, EncryptResult, DecryptConfig } from './types';
|
|
3
|
+
export type { DecryptResult, DecryptBinaryResult } from './types';
|
|
4
|
+
/**
|
|
5
|
+
* Encrypt a string using the Emblem encryption service.
|
|
6
|
+
*
|
|
7
|
+
* If `options.address` or `options.tokenId` are not provided, they will be
|
|
8
|
+
* resolved automatically from the authenticated vault info.
|
|
9
|
+
*
|
|
10
|
+
* @param data - The plaintext string to encrypt
|
|
11
|
+
* @param options - Encryption configuration including auth config
|
|
12
|
+
* @returns The encrypted ciphertext and data hash (needed for decryption)
|
|
13
|
+
*/
|
|
14
|
+
export declare function encrypt(data: string, options: EncryptConfig): Promise<EncryptResult>;
|
|
15
|
+
/**
|
|
16
|
+
* Encrypt binary data (Uint8Array) using the Emblem encryption service.
|
|
17
|
+
*
|
|
18
|
+
* The binary data is Base64-encoded with a marker prefix so that decryptBinary()
|
|
19
|
+
* can distinguish it from plain text and decode it back to a Uint8Array.
|
|
20
|
+
*
|
|
21
|
+
* @param data - The binary data to encrypt
|
|
22
|
+
* @param options - Encryption configuration including auth config
|
|
23
|
+
* @returns The encrypted ciphertext and data hash (needed for decryption)
|
|
24
|
+
*/
|
|
25
|
+
export declare function encryptBinary(data: Uint8Array, options: EncryptConfig): Promise<EncryptResult>;
|
|
26
|
+
/**
|
|
27
|
+
* Decrypt ciphertext using the Emblem decryption service.
|
|
28
|
+
*
|
|
29
|
+
* If `options.address` or `options.tokenId` are not provided, they will be
|
|
30
|
+
* resolved automatically from the authenticated vault info.
|
|
31
|
+
*
|
|
32
|
+
* If the decrypted string starts with the binary marker ("b64:"), the marker is
|
|
33
|
+
* stripped and the raw Base64 string is returned.
|
|
34
|
+
*
|
|
35
|
+
* @param options - Decryption configuration including ciphertext and hash
|
|
36
|
+
* @returns The decrypted plaintext string
|
|
37
|
+
*/
|
|
38
|
+
export declare function decrypt(options: DecryptConfig): Promise<string>;
|
|
39
|
+
/**
|
|
40
|
+
* Decrypt ciphertext and return the result as a Uint8Array.
|
|
41
|
+
*
|
|
42
|
+
* If the decrypted data was originally encrypted with encryptBinary(), the
|
|
43
|
+
* binary marker is detected and the Base64 payload is decoded back to bytes.
|
|
44
|
+
* Otherwise the decrypted string is encoded as UTF-8 bytes as a fallback.
|
|
45
|
+
*
|
|
46
|
+
* @param options - Decryption configuration including ciphertext and hash
|
|
47
|
+
* @returns The decrypted binary data as a Uint8Array
|
|
48
|
+
*/
|
|
49
|
+
export declare function decryptBinary(options: DecryptConfig): Promise<Uint8Array>;
|
|
50
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/crypto/index.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,aAAa,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAK3E,YAAY,EAAE,aAAa,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAC3E,YAAY,EAAE,aAAa,EAAE,mBAAmB,EAAE,MAAM,SAAS,CAAC;AAwClE;;;;;;;;;GASG;AACH,wBAAsB,OAAO,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,aAAa,GAAG,OAAO,CAAC,aAAa,CAAC,CAiC1F;AAED;;;;;;;;;GASG;AACH,wBAAsB,aAAa,CACjC,IAAI,EAAE,UAAU,EAChB,OAAO,EAAE,aAAa,GACrB,OAAO,CAAC,aAAa,CAAC,CAUxB;AAED;;;;;;;;;;;GAWG;AACH,wBAAsB,OAAO,CAAC,OAAO,EAAE,aAAa,GAAG,OAAO,CAAC,MAAM,CAAC,CAyCrE;AAED;;;;;;;;;GASG;AACH,wBAAsB,aAAa,CAAC,OAAO,EAAE,aAAa,GAAG,OAAO,CAAC,UAAU,CAAC,CA2C/E"}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
"use strict";async function t(t,e,r){const n=r.baseUrl??"https://api.emblemvault.ai",o=await async function(t){if("function"==typeof t.getAuthHeaders){const e=await t.getAuthHeaders();if(e&&"object"==typeof e)return e}const e=t.jwt??("function"==typeof t.getJwt?await t.getJwt():void 0)??t.sdk?.getSession()?.authToken??void 0;if(e)return{Authorization:`Bearer ${e}`};if(t.apiKey)return{"x-api-key":t.apiKey};throw new Error("No authentication available: provide jwt, getJwt(), getAuthHeaders(), sdk, or apiKey")}(r),i=await fetch(`${n}${t}`,{method:"POST",headers:{"content-type":"application/json",...o},body:JSON.stringify(e,(t,e)=>"bigint"==typeof e?e.toString():e)});if(!i.ok){const t=await i.text().catch(()=>"");throw new Error(function(t,e){let r=`Emblem signer error ${t}`;return t>=500?r+=": Internal server error":401===t||403===t?r+=": Authentication failed":404===t?r+=": Resource not found":405===t?r+=": Method not allowed":e&&(r+=`: ${e.substring(0,200)}`),r}(i.status,t))}return i.json()}function e(t){const e=!!t.jwt,r="function"==typeof t.getJwt,n="function"==typeof t.getAuthHeaders,o=!!t.sdk&&"function"==typeof t.sdk.getSession,i=!!t.apiKey;if(!(e||r||n||o||i))throw new Error("Authentication required: provide jwt, getJwt(), getAuthHeaders(), sdk, or apiKey");t.baseUrl&&function(t){if(t){if(!t.startsWith("http://")&&!t.startsWith("https://"))throw new Error("baseUrl must be a valid HTTP(S) URL");!t.startsWith("http://")||t.includes("localhost")||t.includes("127.0.0.1")||console.warn("[Emblem Security Warning] baseUrl uses HTTP instead of HTTPS. This is insecure for production use.")}}(t.baseUrl),t.debugSecurity&&console.log("[Emblem Security Debug]",{environment:"undefined"!=typeof window&&"undefined"!=typeof document?"browser":"node",hasBaseUrl:!!t.baseUrl,timestamp:(new Date).toISOString()})}Object.defineProperty(exports,"__esModule",{value:!0});const r="b64:";async function n(e){const r=await async function(e){const r=await t("/vault/info",{},e);if(!r||!r.vaultId||!r.evmAddress)throw new Error("Invalid vault info response: missing required fields");if(!String(r.evmAddress).startsWith("0x"))throw new Error("Invalid evmAddress format in response");return{vaultId:r.vaultId,tokenId:r.vaultId,address:r.address||"",evmAddress:r.evmAddress,created_by:r.created_by}}(e);if(!r.evmAddress)throw new Error("Could not resolve vault EVM address");if(!r.vaultId)throw new Error("Could not resolve vault tokenId");return{address:r.evmAddress,tokenId:r.vaultId}}async function o(r,o){if(!r)throw new Error("Data to encrypt must be a non-empty string");if(!o||!o.config)throw new Error("EncryptConfig with a valid config is required");e(o.config);let{address:i,tokenId:a}=o;if(!i||!a){const t=await n(o.config);i=i??t.address,a=a??t.tokenId}const s=await t("/encrypt",{text:r,address:i,tokenId:a},o.config);if(!s||!s.ciphertext||!s.dataToEncryptHash)throw new Error("Invalid encrypt response: missing ciphertext or dataToEncryptHash");return{ciphertext:s.ciphertext,dataToEncryptHash:s.dataToEncryptHash}}exports.decrypt=async function(o){if(!o||!o.config)throw new Error("DecryptConfig with a valid config is required");if(!o.ciphertext)throw new Error("ciphertext is required for decryption");if(!o.dataToEncryptHash)throw new Error("dataToEncryptHash is required for decryption");e(o.config);let{address:i,tokenId:a}=o;if(!i||!a){const t=await n(o.config);i=i??t.address,a=a??t.tokenId}const s=await t("/decrypt",{address:i,tokenId:a,ciphertext:o.ciphertext,dataToEncryptHash:o.dataToEncryptHash},o.config);if(!s||"string"!=typeof s.decryptedString)throw new Error("Invalid decrypt response: missing decryptedString");let d=s.decryptedString;return d.startsWith(r)&&(d=d.slice(4)),d},exports.decryptBinary=async function(o){if(!o||!o.config)throw new Error("DecryptConfig with a valid config is required");if(!o.ciphertext)throw new Error("ciphertext is required for decryption");if(!o.dataToEncryptHash)throw new Error("dataToEncryptHash is required for decryption");e(o.config);let{address:i,tokenId:a}=o;if(!i||!a){const t=await n(o.config);i=i??t.address,a=a??t.tokenId}const s=await t("/decrypt",{address:i,tokenId:a,ciphertext:o.ciphertext,dataToEncryptHash:o.dataToEncryptHash},o.config);if(!s||"string"!=typeof s.decryptedString)throw new Error("Invalid decrypt response: missing decryptedString");const d=s.decryptedString;if(d.startsWith(r)){return function(t){if("function"==typeof atob){const e=atob(t),r=new Uint8Array(e.length);for(let t=0;t<e.length;t++)r[t]=e.charCodeAt(t);return r}if("undefined"!=typeof Buffer){const e=Buffer.from(t,"base64");return new Uint8Array(e.buffer,e.byteOffset,e.byteLength)}throw new Error("No Base64 decoding method available in this environment")}(d.slice(4))}return(new TextEncoder).encode(d)},exports.encrypt=o,exports.encryptBinary=async function(t,e){if(!(t&&t instanceof Uint8Array))throw new Error("Data must be a Uint8Array");const n=function(t){if("function"==typeof btoa){let e="";for(let r=0;r<t.length;r++)e+=String.fromCharCode(t[r]);return btoa(e)}if("undefined"!=typeof Buffer)return Buffer.from(t).toString("base64");throw new Error("No Base64 encoding method available in this environment")}(t);return o(`${r}${n}`,e)};
|
|
2
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sources":["../../src/signers/http.ts","../../src/signers/validation.ts","../../src/crypto/index.ts","../../src/signers/vault.ts"],"sourcesContent":["import type { SignerConfig } from '../types/signers';\n\nfunction sanitizeErrorMessage(status: number, text: string): string {\n // Sanitize error messages to avoid leaking sensitive server information\n let errorMessage = `Emblem signer error ${status}`;\n\n if (status >= 500) {\n errorMessage += ': Internal server error';\n } else if (status === 401 || status === 403) {\n errorMessage += ': Authentication failed';\n } else if (status === 404) {\n errorMessage += ': Resource not found';\n } else if (status === 405) {\n errorMessage += ': Method not allowed';\n } else if (text) {\n // For 4xx client errors, include limited error details\n errorMessage += `: ${text.substring(0, 200)}`; // Limit to 200 chars\n }\n\n return errorMessage;\n}\n\nasync function resolveAuthHeaders(config: SignerConfig): Promise<Record<string, string>> {\n // Priority: custom headers -> jwt/getJwt/sdk -> apiKey (deprecated)\n if (typeof config.getAuthHeaders === 'function') {\n const h = await config.getAuthHeaders();\n if (h && typeof h === 'object') return h;\n }\n\n const tok =\n config.jwt ??\n (typeof config.getJwt === 'function' ? await config.getJwt() : undefined) ??\n config.sdk?.getSession()?.authToken ??\n undefined;\n\n if (tok) {\n return { Authorization: `Bearer ${tok}` };\n }\n\n // apiKey is deprecated but still supported as fallback\n if (config.apiKey) {\n return { 'x-api-key': config.apiKey };\n }\n\n throw new Error(\n 'No authentication available: provide jwt, getJwt(), getAuthHeaders(), sdk, or apiKey'\n );\n}\n\nexport async function emblemPost<T = unknown>(\n path: string,\n body: unknown,\n config: SignerConfig\n): Promise<T> {\n const baseUrl = config.baseUrl ?? 'https://api.emblemvault.ai';\n const authHeaders = await resolveAuthHeaders(config);\n const res = await fetch(`${baseUrl}${path}`, {\n method: 'POST',\n headers: {\n 'content-type': 'application/json',\n ...authHeaders,\n },\n body: JSON.stringify(body, (_key: string, value: unknown) =>\n typeof value === 'bigint' ? value.toString() : value\n ),\n });\n\n if (!res.ok) {\n const text = await res.text().catch(() => '');\n throw new Error(sanitizeErrorMessage(res.status, text));\n }\n\n return res.json() as Promise<T>;\n}\n\nexport async function emblemGet<T = unknown>(path: string, config: SignerConfig): Promise<T> {\n const baseUrl = config.baseUrl ?? 'https://api.emblemvault.ai';\n const authHeaders = await resolveAuthHeaders(config);\n const res = await fetch(`${baseUrl}${path}`, {\n method: 'GET',\n headers: authHeaders,\n });\n\n if (!res.ok) {\n const text = await res.text().catch(() => '');\n throw new Error(sanitizeErrorMessage(res.status, text));\n }\n\n return res.json() as Promise<T>;\n}\n","import type { SignerConfig } from '../types/signers';\n\n/**\n * Environment detection utilities for warning about unsafe usage patterns\n */\n\n/**\n * Detect if code is running in a browser environment\n */\nexport function isBrowserEnvironment(): boolean {\n return typeof window !== 'undefined' && typeof document !== 'undefined';\n}\n\n/**\n * Check if we're in a Node.js server environment\n */\nexport function isNodeEnvironment(): boolean {\n return (\n typeof process !== 'undefined' && process.versions != null && process.versions.node != null\n );\n}\n\n/**\n * Validate baseUrl format\n */\nexport function validateBaseUrl(baseUrl?: string): void {\n if (!baseUrl) return; // undefined is ok, will use default\n\n if (!baseUrl.startsWith('http://') && !baseUrl.startsWith('https://')) {\n throw new Error('baseUrl must be a valid HTTP(S) URL');\n }\n\n // Warn about http (not https)\n if (\n baseUrl.startsWith('http://') &&\n !baseUrl.includes('localhost') &&\n !baseUrl.includes('127.0.0.1')\n ) {\n console.warn(\n '[Emblem Security Warning] baseUrl uses HTTP instead of HTTPS. This is insecure for production use.'\n );\n }\n}\n\n/**\n * Validate Ethereum address format\n */\nexport function validateEthereumAddress(address: string): void {\n if (!address || typeof address !== 'string') {\n throw new Error('Address is required');\n }\n\n if (!address.startsWith('0x')) {\n throw new Error('Address must start with 0x');\n }\n\n if (!/^0x[0-9a-fA-F]{40}$/.test(address)) {\n throw new Error('Invalid Ethereum address format');\n }\n}\n\n/**\n * Validate vault ID\n */\nexport function validateVaultId(vaultId: string): void {\n if (!vaultId || typeof vaultId !== 'string') {\n throw new Error('vaultId is required');\n }\n\n if (vaultId.trim() === '') {\n throw new Error('vaultId cannot be empty');\n }\n}\n\n/**\n * Safe number conversion with bounds checking\n */\nexport function toSafeNumber(value: unknown, fieldName: string): number {\n const num = Number(value);\n\n if (!Number.isSafeInteger(num)) {\n throw new Error(\n `${fieldName} value ${value} exceeds safe integer range (max: ${Number.MAX_SAFE_INTEGER})`\n );\n }\n\n return num;\n}\n\n/**\n * Extended config with security options\n */\nexport interface SignerSecurityConfig extends SignerConfig {\n /**\n * Enable debug logging for security-related checks\n * @default false\n */\n debugSecurity?: boolean;\n}\n\n/**\n * Validate signer configuration\n */\nexport function validateSignerConfig(config: SignerSecurityConfig): void {\n // Validate auth: require at least one method\n const hasJwt = !!config.jwt;\n const hasGetJwt = typeof config.getJwt === 'function';\n const hasHeaders = typeof config.getAuthHeaders === 'function';\n const hasSdk = !!config.sdk && typeof config.sdk.getSession === 'function';\n const hasApiKey = !!config.apiKey;\n\n if (!hasJwt && !hasGetJwt && !hasHeaders && !hasSdk && !hasApiKey) {\n throw new Error('Authentication required: provide jwt, getJwt(), getAuthHeaders(), sdk, or apiKey');\n }\n\n // Validate baseUrl if provided\n if (config.baseUrl) {\n validateBaseUrl(config.baseUrl);\n }\n\n // Security audit logging\n if (config.debugSecurity) {\n console.log('[Emblem Security Debug]', {\n environment: isBrowserEnvironment() ? 'browser' : 'node',\n hasBaseUrl: !!config.baseUrl,\n timestamp: new Date().toISOString(),\n });\n }\n}\n","import type { SignerConfig } from '../types/signers';\nimport type { EncryptConfig, EncryptResult, DecryptConfig } from './types';\nimport { emblemPost } from '../signers/http';\nimport { validateSignerConfig } from '../signers/validation';\nimport { fetchVaultInfo } from '../signers/vault';\n\nexport type { EncryptConfig, EncryptResult, DecryptConfig } from './types';\nexport type { DecryptResult, DecryptBinaryResult } from './types';\n\n/** Binary marker prefix used to distinguish binary data from plain text */\nconst BINARY_MARKER = 'b64:';\n\n/** Response shape from POST /encrypt */\ninterface EncryptApiResponse {\n success: boolean;\n ciphertext: string;\n dataToEncryptHash: string;\n}\n\n/** Response shape from POST /decrypt */\ninterface DecryptApiResponse {\n success: boolean;\n decryptedString: string;\n}\n\n/**\n * Resolve vault address and tokenId from the signer config.\n * Uses fetchVaultInfo to retrieve the vault's EVM address and vaultId.\n */\nasync function resolveVaultDetails(\n config: SignerConfig\n): Promise<{ address: string; tokenId: string }> {\n const vaultInfo = await fetchVaultInfo(config);\n\n if (!vaultInfo.evmAddress) {\n throw new Error('Could not resolve vault EVM address');\n }\n if (!vaultInfo.vaultId) {\n throw new Error('Could not resolve vault tokenId');\n }\n\n return {\n address: vaultInfo.evmAddress,\n tokenId: vaultInfo.vaultId,\n };\n}\n\n/**\n * Encrypt a string using the Emblem encryption service.\n *\n * If `options.address` or `options.tokenId` are not provided, they will be\n * resolved automatically from the authenticated vault info.\n *\n * @param data - The plaintext string to encrypt\n * @param options - Encryption configuration including auth config\n * @returns The encrypted ciphertext and data hash (needed for decryption)\n */\nexport async function encrypt(data: string, options: EncryptConfig): Promise<EncryptResult> {\n if (!data) {\n throw new Error('Data to encrypt must be a non-empty string');\n }\n if (!options || !options.config) {\n throw new Error('EncryptConfig with a valid config is required');\n }\n\n validateSignerConfig(options.config);\n\n let { address, tokenId } = options;\n\n // Resolve address/tokenId from vault if not explicitly provided\n if (!address || !tokenId) {\n const vaultDetails = await resolveVaultDetails(options.config);\n address = address ?? vaultDetails.address;\n tokenId = tokenId ?? vaultDetails.tokenId;\n }\n\n const response = await emblemPost<EncryptApiResponse>('/encrypt', {\n text: data,\n address,\n tokenId,\n }, options.config);\n\n if (!response || !response.ciphertext || !response.dataToEncryptHash) {\n throw new Error('Invalid encrypt response: missing ciphertext or dataToEncryptHash');\n }\n\n return {\n ciphertext: response.ciphertext,\n dataToEncryptHash: response.dataToEncryptHash,\n };\n}\n\n/**\n * Encrypt binary data (Uint8Array) using the Emblem encryption service.\n *\n * The binary data is Base64-encoded with a marker prefix so that decryptBinary()\n * can distinguish it from plain text and decode it back to a Uint8Array.\n *\n * @param data - The binary data to encrypt\n * @param options - Encryption configuration including auth config\n * @returns The encrypted ciphertext and data hash (needed for decryption)\n */\nexport async function encryptBinary(\n data: Uint8Array,\n options: EncryptConfig\n): Promise<EncryptResult> {\n if (!data || !(data instanceof Uint8Array)) {\n throw new Error('Data must be a Uint8Array');\n }\n\n // Base64-encode the binary data and prepend the marker\n const base64 = uint8ArrayToBase64(data);\n const encoded = `${BINARY_MARKER}${base64}`;\n\n return encrypt(encoded, options);\n}\n\n/**\n * Decrypt ciphertext using the Emblem decryption service.\n *\n * If `options.address` or `options.tokenId` are not provided, they will be\n * resolved automatically from the authenticated vault info.\n *\n * If the decrypted string starts with the binary marker (\"b64:\"), the marker is\n * stripped and the raw Base64 string is returned.\n *\n * @param options - Decryption configuration including ciphertext and hash\n * @returns The decrypted plaintext string\n */\nexport async function decrypt(options: DecryptConfig): Promise<string> {\n if (!options || !options.config) {\n throw new Error('DecryptConfig with a valid config is required');\n }\n if (!options.ciphertext) {\n throw new Error('ciphertext is required for decryption');\n }\n if (!options.dataToEncryptHash) {\n throw new Error('dataToEncryptHash is required for decryption');\n }\n\n validateSignerConfig(options.config);\n\n let { address, tokenId } = options;\n\n // Resolve address/tokenId from vault if not explicitly provided\n if (!address || !tokenId) {\n const vaultDetails = await resolveVaultDetails(options.config);\n address = address ?? vaultDetails.address;\n tokenId = tokenId ?? vaultDetails.tokenId;\n }\n\n const response = await emblemPost<DecryptApiResponse>('/decrypt', {\n address,\n tokenId,\n ciphertext: options.ciphertext,\n dataToEncryptHash: options.dataToEncryptHash,\n }, options.config);\n\n if (!response || typeof response.decryptedString !== 'string') {\n throw new Error('Invalid decrypt response: missing decryptedString');\n }\n\n let result = response.decryptedString;\n\n // Strip binary marker if present (for users who just want the base64 string)\n if (result.startsWith(BINARY_MARKER)) {\n result = result.slice(BINARY_MARKER.length);\n }\n\n return result;\n}\n\n/**\n * Decrypt ciphertext and return the result as a Uint8Array.\n *\n * If the decrypted data was originally encrypted with encryptBinary(), the\n * binary marker is detected and the Base64 payload is decoded back to bytes.\n * Otherwise the decrypted string is encoded as UTF-8 bytes as a fallback.\n *\n * @param options - Decryption configuration including ciphertext and hash\n * @returns The decrypted binary data as a Uint8Array\n */\nexport async function decryptBinary(options: DecryptConfig): Promise<Uint8Array> {\n if (!options || !options.config) {\n throw new Error('DecryptConfig with a valid config is required');\n }\n if (!options.ciphertext) {\n throw new Error('ciphertext is required for decryption');\n }\n if (!options.dataToEncryptHash) {\n throw new Error('dataToEncryptHash is required for decryption');\n }\n\n validateSignerConfig(options.config);\n\n // Perform decryption using the raw API to check the marker ourselves\n let { address, tokenId } = options;\n\n if (!address || !tokenId) {\n const vaultDetails = await resolveVaultDetails(options.config);\n address = address ?? vaultDetails.address;\n tokenId = tokenId ?? vaultDetails.tokenId;\n }\n\n const response = await emblemPost<DecryptApiResponse>('/decrypt', {\n address,\n tokenId,\n ciphertext: options.ciphertext,\n dataToEncryptHash: options.dataToEncryptHash,\n }, options.config);\n\n if (!response || typeof response.decryptedString !== 'string') {\n throw new Error('Invalid decrypt response: missing decryptedString');\n }\n\n const decrypted = response.decryptedString;\n\n // If the binary marker is present, decode the Base64 payload\n if (decrypted.startsWith(BINARY_MARKER)) {\n const base64 = decrypted.slice(BINARY_MARKER.length);\n return base64ToUint8Array(base64);\n }\n\n // Fallback: encode the plain string as UTF-8 bytes\n return new TextEncoder().encode(decrypted);\n}\n\n/* ------------------------------------------------------------------ */\n/* Base64 helpers (environment-agnostic: works in Node and browsers) */\n/* ------------------------------------------------------------------ */\n\nfunction uint8ArrayToBase64(bytes: Uint8Array): string {\n // Use btoa if available (browsers + Node 16+)\n if (typeof btoa === 'function') {\n let binary = '';\n for (let i = 0; i < bytes.length; i++) {\n binary += String.fromCharCode(bytes[i]);\n }\n return btoa(binary);\n }\n\n // Node.js Buffer fallback\n if (typeof Buffer !== 'undefined') {\n return Buffer.from(bytes).toString('base64');\n }\n\n throw new Error('No Base64 encoding method available in this environment');\n}\n\nfunction base64ToUint8Array(base64: string): Uint8Array {\n // Use atob if available (browsers + Node 16+)\n if (typeof atob === 'function') {\n const binary = atob(base64);\n const bytes = new Uint8Array(binary.length);\n for (let i = 0; i < binary.length; i++) {\n bytes[i] = binary.charCodeAt(i);\n }\n return bytes;\n }\n\n // Node.js Buffer fallback\n if (typeof Buffer !== 'undefined') {\n const buf = Buffer.from(base64, 'base64');\n return new Uint8Array(buf.buffer, buf.byteOffset, buf.byteLength);\n }\n\n throw new Error('No Base64 decoding method available in this environment');\n}\n","import type { SignerConfig, SignerVaultInfo, Hex } from '../types/signers';\nimport { emblemPost } from './http';\n\nexport async function fetchVaultInfo(config: SignerConfig): Promise<SignerVaultInfo> {\n // Note: The server only supports POST for /vault/info\n const data: Partial<{\n vaultId: string;\n address: string;\n evmAddress: Hex;\n created_by?: string;\n }> = await emblemPost('/vault/info', {}, config);\n\n // Validate required response data (vaultId + evmAddress are required for EVM)\n if (!data || !data.vaultId || !data.evmAddress) {\n throw new Error('Invalid vault info response: missing required fields');\n }\n\n if (!String(data.evmAddress).startsWith('0x')) {\n throw new Error('Invalid evmAddress format in response');\n }\n\n return {\n vaultId: data.vaultId,\n tokenId: data.vaultId,\n address: data.address || '', // Solana address may be absent; keep optional\n evmAddress: data.evmAddress as Hex,\n created_by: data.created_by,\n };\n}\n"],"names":["async","emblemPost","path","body","config","baseUrl","authHeaders","getAuthHeaders","h","tok","jwt","getJwt","undefined","sdk","getSession","authToken","Authorization","apiKey","Error","resolveAuthHeaders","res","fetch","method","headers","JSON","stringify","_key","value","toString","ok","text","catch","status","errorMessage","substring","sanitizeErrorMessage","json","validateSignerConfig","hasJwt","hasGetJwt","hasHeaders","hasSdk","hasApiKey","startsWith","includes","console","warn","validateBaseUrl","debugSecurity","log","environment","window","document","hasBaseUrl","timestamp","Date","toISOString","BINARY_MARKER","resolveVaultDetails","vaultInfo","data","vaultId","evmAddress","String","tokenId","address","created_by","fetchVaultInfo","encrypt","options","vaultDetails","response","ciphertext","dataToEncryptHash","decryptedString","result","slice","decrypted","base64","atob","binary","bytes","Uint8Array","length","i","charCodeAt","Buffer","buf","from","buffer","byteOffset","byteLength","base64ToUint8Array","TextEncoder","encode","btoa","fromCharCode","uint8ArrayToBase64"],"mappings":"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"}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
async function t(t,e,r){const n=r.baseUrl??"https://api.emblemvault.ai",o=await async function(t){if("function"==typeof t.getAuthHeaders){const e=await t.getAuthHeaders();if(e&&"object"==typeof e)return e}const e=t.jwt??("function"==typeof t.getJwt?await t.getJwt():void 0)??t.sdk?.getSession()?.authToken??void 0;if(e)return{Authorization:`Bearer ${e}`};if(t.apiKey)return{"x-api-key":t.apiKey};throw new Error("No authentication available: provide jwt, getJwt(), getAuthHeaders(), sdk, or apiKey")}(r),i=await fetch(`${n}${t}`,{method:"POST",headers:{"content-type":"application/json",...o},body:JSON.stringify(e,(t,e)=>"bigint"==typeof e?e.toString():e)});if(!i.ok){const t=await i.text().catch(()=>"");throw new Error(function(t,e){let r=`Emblem signer error ${t}`;return t>=500?r+=": Internal server error":401===t||403===t?r+=": Authentication failed":404===t?r+=": Resource not found":405===t?r+=": Method not allowed":e&&(r+=`: ${e.substring(0,200)}`),r}(i.status,t))}return i.json()}function e(t){const e=!!t.jwt,r="function"==typeof t.getJwt,n="function"==typeof t.getAuthHeaders,o=!!t.sdk&&"function"==typeof t.sdk.getSession,i=!!t.apiKey;if(!(e||r||n||o||i))throw new Error("Authentication required: provide jwt, getJwt(), getAuthHeaders(), sdk, or apiKey");t.baseUrl&&function(t){if(t){if(!t.startsWith("http://")&&!t.startsWith("https://"))throw new Error("baseUrl must be a valid HTTP(S) URL");!t.startsWith("http://")||t.includes("localhost")||t.includes("127.0.0.1")||console.warn("[Emblem Security Warning] baseUrl uses HTTP instead of HTTPS. This is insecure for production use.")}}(t.baseUrl),t.debugSecurity&&console.log("[Emblem Security Debug]",{environment:"undefined"!=typeof window&&"undefined"!=typeof document?"browser":"node",hasBaseUrl:!!t.baseUrl,timestamp:(new Date).toISOString()})}const r="b64:";async function n(e){const r=await async function(e){const r=await t("/vault/info",{},e);if(!r||!r.vaultId||!r.evmAddress)throw new Error("Invalid vault info response: missing required fields");if(!String(r.evmAddress).startsWith("0x"))throw new Error("Invalid evmAddress format in response");return{vaultId:r.vaultId,tokenId:r.vaultId,address:r.address||"",evmAddress:r.evmAddress,created_by:r.created_by}}(e);if(!r.evmAddress)throw new Error("Could not resolve vault EVM address");if(!r.vaultId)throw new Error("Could not resolve vault tokenId");return{address:r.evmAddress,tokenId:r.vaultId}}async function o(r,o){if(!r)throw new Error("Data to encrypt must be a non-empty string");if(!o||!o.config)throw new Error("EncryptConfig with a valid config is required");e(o.config);let{address:i,tokenId:a}=o;if(!i||!a){const t=await n(o.config);i=i??t.address,a=a??t.tokenId}const s=await t("/encrypt",{text:r,address:i,tokenId:a},o.config);if(!s||!s.ciphertext||!s.dataToEncryptHash)throw new Error("Invalid encrypt response: missing ciphertext or dataToEncryptHash");return{ciphertext:s.ciphertext,dataToEncryptHash:s.dataToEncryptHash}}async function i(t,e){if(!(t&&t instanceof Uint8Array))throw new Error("Data must be a Uint8Array");const n=function(t){if("function"==typeof btoa){let e="";for(let r=0;r<t.length;r++)e+=String.fromCharCode(t[r]);return btoa(e)}if("undefined"!=typeof Buffer)return Buffer.from(t).toString("base64");throw new Error("No Base64 encoding method available in this environment")}(t);return o(`${r}${n}`,e)}async function a(o){if(!o||!o.config)throw new Error("DecryptConfig with a valid config is required");if(!o.ciphertext)throw new Error("ciphertext is required for decryption");if(!o.dataToEncryptHash)throw new Error("dataToEncryptHash is required for decryption");e(o.config);let{address:i,tokenId:a}=o;if(!i||!a){const t=await n(o.config);i=i??t.address,a=a??t.tokenId}const s=await t("/decrypt",{address:i,tokenId:a,ciphertext:o.ciphertext,dataToEncryptHash:o.dataToEncryptHash},o.config);if(!s||"string"!=typeof s.decryptedString)throw new Error("Invalid decrypt response: missing decryptedString");let d=s.decryptedString;return d.startsWith(r)&&(d=d.slice(4)),d}async function s(o){if(!o||!o.config)throw new Error("DecryptConfig with a valid config is required");if(!o.ciphertext)throw new Error("ciphertext is required for decryption");if(!o.dataToEncryptHash)throw new Error("dataToEncryptHash is required for decryption");e(o.config);let{address:i,tokenId:a}=o;if(!i||!a){const t=await n(o.config);i=i??t.address,a=a??t.tokenId}const s=await t("/decrypt",{address:i,tokenId:a,ciphertext:o.ciphertext,dataToEncryptHash:o.dataToEncryptHash},o.config);if(!s||"string"!=typeof s.decryptedString)throw new Error("Invalid decrypt response: missing decryptedString");const d=s.decryptedString;if(d.startsWith(r)){return function(t){if("function"==typeof atob){const e=atob(t),r=new Uint8Array(e.length);for(let t=0;t<e.length;t++)r[t]=e.charCodeAt(t);return r}if("undefined"!=typeof Buffer){const e=Buffer.from(t,"base64");return new Uint8Array(e.buffer,e.byteOffset,e.byteLength)}throw new Error("No Base64 decoding method available in this environment")}(d.slice(4))}return(new TextEncoder).encode(d)}export{a as decrypt,s as decryptBinary,o as encrypt,i as encryptBinary};
|
|
2
|
+
//# sourceMappingURL=index.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.mjs","sources":["../../src/signers/http.ts","../../src/signers/validation.ts","../../src/crypto/index.ts","../../src/signers/vault.ts"],"sourcesContent":["import type { SignerConfig } from '../types/signers';\n\nfunction sanitizeErrorMessage(status: number, text: string): string {\n // Sanitize error messages to avoid leaking sensitive server information\n let errorMessage = `Emblem signer error ${status}`;\n\n if (status >= 500) {\n errorMessage += ': Internal server error';\n } else if (status === 401 || status === 403) {\n errorMessage += ': Authentication failed';\n } else if (status === 404) {\n errorMessage += ': Resource not found';\n } else if (status === 405) {\n errorMessage += ': Method not allowed';\n } else if (text) {\n // For 4xx client errors, include limited error details\n errorMessage += `: ${text.substring(0, 200)}`; // Limit to 200 chars\n }\n\n return errorMessage;\n}\n\nasync function resolveAuthHeaders(config: SignerConfig): Promise<Record<string, string>> {\n // Priority: custom headers -> jwt/getJwt/sdk -> apiKey (deprecated)\n if (typeof config.getAuthHeaders === 'function') {\n const h = await config.getAuthHeaders();\n if (h && typeof h === 'object') return h;\n }\n\n const tok =\n config.jwt ??\n (typeof config.getJwt === 'function' ? await config.getJwt() : undefined) ??\n config.sdk?.getSession()?.authToken ??\n undefined;\n\n if (tok) {\n return { Authorization: `Bearer ${tok}` };\n }\n\n // apiKey is deprecated but still supported as fallback\n if (config.apiKey) {\n return { 'x-api-key': config.apiKey };\n }\n\n throw new Error(\n 'No authentication available: provide jwt, getJwt(), getAuthHeaders(), sdk, or apiKey'\n );\n}\n\nexport async function emblemPost<T = unknown>(\n path: string,\n body: unknown,\n config: SignerConfig\n): Promise<T> {\n const baseUrl = config.baseUrl ?? 'https://api.emblemvault.ai';\n const authHeaders = await resolveAuthHeaders(config);\n const res = await fetch(`${baseUrl}${path}`, {\n method: 'POST',\n headers: {\n 'content-type': 'application/json',\n ...authHeaders,\n },\n body: JSON.stringify(body, (_key: string, value: unknown) =>\n typeof value === 'bigint' ? value.toString() : value\n ),\n });\n\n if (!res.ok) {\n const text = await res.text().catch(() => '');\n throw new Error(sanitizeErrorMessage(res.status, text));\n }\n\n return res.json() as Promise<T>;\n}\n\nexport async function emblemGet<T = unknown>(path: string, config: SignerConfig): Promise<T> {\n const baseUrl = config.baseUrl ?? 'https://api.emblemvault.ai';\n const authHeaders = await resolveAuthHeaders(config);\n const res = await fetch(`${baseUrl}${path}`, {\n method: 'GET',\n headers: authHeaders,\n });\n\n if (!res.ok) {\n const text = await res.text().catch(() => '');\n throw new Error(sanitizeErrorMessage(res.status, text));\n }\n\n return res.json() as Promise<T>;\n}\n","import type { SignerConfig } from '../types/signers';\n\n/**\n * Environment detection utilities for warning about unsafe usage patterns\n */\n\n/**\n * Detect if code is running in a browser environment\n */\nexport function isBrowserEnvironment(): boolean {\n return typeof window !== 'undefined' && typeof document !== 'undefined';\n}\n\n/**\n * Check if we're in a Node.js server environment\n */\nexport function isNodeEnvironment(): boolean {\n return (\n typeof process !== 'undefined' && process.versions != null && process.versions.node != null\n );\n}\n\n/**\n * Validate baseUrl format\n */\nexport function validateBaseUrl(baseUrl?: string): void {\n if (!baseUrl) return; // undefined is ok, will use default\n\n if (!baseUrl.startsWith('http://') && !baseUrl.startsWith('https://')) {\n throw new Error('baseUrl must be a valid HTTP(S) URL');\n }\n\n // Warn about http (not https)\n if (\n baseUrl.startsWith('http://') &&\n !baseUrl.includes('localhost') &&\n !baseUrl.includes('127.0.0.1')\n ) {\n console.warn(\n '[Emblem Security Warning] baseUrl uses HTTP instead of HTTPS. This is insecure for production use.'\n );\n }\n}\n\n/**\n * Validate Ethereum address format\n */\nexport function validateEthereumAddress(address: string): void {\n if (!address || typeof address !== 'string') {\n throw new Error('Address is required');\n }\n\n if (!address.startsWith('0x')) {\n throw new Error('Address must start with 0x');\n }\n\n if (!/^0x[0-9a-fA-F]{40}$/.test(address)) {\n throw new Error('Invalid Ethereum address format');\n }\n}\n\n/**\n * Validate vault ID\n */\nexport function validateVaultId(vaultId: string): void {\n if (!vaultId || typeof vaultId !== 'string') {\n throw new Error('vaultId is required');\n }\n\n if (vaultId.trim() === '') {\n throw new Error('vaultId cannot be empty');\n }\n}\n\n/**\n * Safe number conversion with bounds checking\n */\nexport function toSafeNumber(value: unknown, fieldName: string): number {\n const num = Number(value);\n\n if (!Number.isSafeInteger(num)) {\n throw new Error(\n `${fieldName} value ${value} exceeds safe integer range (max: ${Number.MAX_SAFE_INTEGER})`\n );\n }\n\n return num;\n}\n\n/**\n * Extended config with security options\n */\nexport interface SignerSecurityConfig extends SignerConfig {\n /**\n * Enable debug logging for security-related checks\n * @default false\n */\n debugSecurity?: boolean;\n}\n\n/**\n * Validate signer configuration\n */\nexport function validateSignerConfig(config: SignerSecurityConfig): void {\n // Validate auth: require at least one method\n const hasJwt = !!config.jwt;\n const hasGetJwt = typeof config.getJwt === 'function';\n const hasHeaders = typeof config.getAuthHeaders === 'function';\n const hasSdk = !!config.sdk && typeof config.sdk.getSession === 'function';\n const hasApiKey = !!config.apiKey;\n\n if (!hasJwt && !hasGetJwt && !hasHeaders && !hasSdk && !hasApiKey) {\n throw new Error('Authentication required: provide jwt, getJwt(), getAuthHeaders(), sdk, or apiKey');\n }\n\n // Validate baseUrl if provided\n if (config.baseUrl) {\n validateBaseUrl(config.baseUrl);\n }\n\n // Security audit logging\n if (config.debugSecurity) {\n console.log('[Emblem Security Debug]', {\n environment: isBrowserEnvironment() ? 'browser' : 'node',\n hasBaseUrl: !!config.baseUrl,\n timestamp: new Date().toISOString(),\n });\n }\n}\n","import type { SignerConfig } from '../types/signers';\nimport type { EncryptConfig, EncryptResult, DecryptConfig } from './types';\nimport { emblemPost } from '../signers/http';\nimport { validateSignerConfig } from '../signers/validation';\nimport { fetchVaultInfo } from '../signers/vault';\n\nexport type { EncryptConfig, EncryptResult, DecryptConfig } from './types';\nexport type { DecryptResult, DecryptBinaryResult } from './types';\n\n/** Binary marker prefix used to distinguish binary data from plain text */\nconst BINARY_MARKER = 'b64:';\n\n/** Response shape from POST /encrypt */\ninterface EncryptApiResponse {\n success: boolean;\n ciphertext: string;\n dataToEncryptHash: string;\n}\n\n/** Response shape from POST /decrypt */\ninterface DecryptApiResponse {\n success: boolean;\n decryptedString: string;\n}\n\n/**\n * Resolve vault address and tokenId from the signer config.\n * Uses fetchVaultInfo to retrieve the vault's EVM address and vaultId.\n */\nasync function resolveVaultDetails(\n config: SignerConfig\n): Promise<{ address: string; tokenId: string }> {\n const vaultInfo = await fetchVaultInfo(config);\n\n if (!vaultInfo.evmAddress) {\n throw new Error('Could not resolve vault EVM address');\n }\n if (!vaultInfo.vaultId) {\n throw new Error('Could not resolve vault tokenId');\n }\n\n return {\n address: vaultInfo.evmAddress,\n tokenId: vaultInfo.vaultId,\n };\n}\n\n/**\n * Encrypt a string using the Emblem encryption service.\n *\n * If `options.address` or `options.tokenId` are not provided, they will be\n * resolved automatically from the authenticated vault info.\n *\n * @param data - The plaintext string to encrypt\n * @param options - Encryption configuration including auth config\n * @returns The encrypted ciphertext and data hash (needed for decryption)\n */\nexport async function encrypt(data: string, options: EncryptConfig): Promise<EncryptResult> {\n if (!data) {\n throw new Error('Data to encrypt must be a non-empty string');\n }\n if (!options || !options.config) {\n throw new Error('EncryptConfig with a valid config is required');\n }\n\n validateSignerConfig(options.config);\n\n let { address, tokenId } = options;\n\n // Resolve address/tokenId from vault if not explicitly provided\n if (!address || !tokenId) {\n const vaultDetails = await resolveVaultDetails(options.config);\n address = address ?? vaultDetails.address;\n tokenId = tokenId ?? vaultDetails.tokenId;\n }\n\n const response = await emblemPost<EncryptApiResponse>('/encrypt', {\n text: data,\n address,\n tokenId,\n }, options.config);\n\n if (!response || !response.ciphertext || !response.dataToEncryptHash) {\n throw new Error('Invalid encrypt response: missing ciphertext or dataToEncryptHash');\n }\n\n return {\n ciphertext: response.ciphertext,\n dataToEncryptHash: response.dataToEncryptHash,\n };\n}\n\n/**\n * Encrypt binary data (Uint8Array) using the Emblem encryption service.\n *\n * The binary data is Base64-encoded with a marker prefix so that decryptBinary()\n * can distinguish it from plain text and decode it back to a Uint8Array.\n *\n * @param data - The binary data to encrypt\n * @param options - Encryption configuration including auth config\n * @returns The encrypted ciphertext and data hash (needed for decryption)\n */\nexport async function encryptBinary(\n data: Uint8Array,\n options: EncryptConfig\n): Promise<EncryptResult> {\n if (!data || !(data instanceof Uint8Array)) {\n throw new Error('Data must be a Uint8Array');\n }\n\n // Base64-encode the binary data and prepend the marker\n const base64 = uint8ArrayToBase64(data);\n const encoded = `${BINARY_MARKER}${base64}`;\n\n return encrypt(encoded, options);\n}\n\n/**\n * Decrypt ciphertext using the Emblem decryption service.\n *\n * If `options.address` or `options.tokenId` are not provided, they will be\n * resolved automatically from the authenticated vault info.\n *\n * If the decrypted string starts with the binary marker (\"b64:\"), the marker is\n * stripped and the raw Base64 string is returned.\n *\n * @param options - Decryption configuration including ciphertext and hash\n * @returns The decrypted plaintext string\n */\nexport async function decrypt(options: DecryptConfig): Promise<string> {\n if (!options || !options.config) {\n throw new Error('DecryptConfig with a valid config is required');\n }\n if (!options.ciphertext) {\n throw new Error('ciphertext is required for decryption');\n }\n if (!options.dataToEncryptHash) {\n throw new Error('dataToEncryptHash is required for decryption');\n }\n\n validateSignerConfig(options.config);\n\n let { address, tokenId } = options;\n\n // Resolve address/tokenId from vault if not explicitly provided\n if (!address || !tokenId) {\n const vaultDetails = await resolveVaultDetails(options.config);\n address = address ?? vaultDetails.address;\n tokenId = tokenId ?? vaultDetails.tokenId;\n }\n\n const response = await emblemPost<DecryptApiResponse>('/decrypt', {\n address,\n tokenId,\n ciphertext: options.ciphertext,\n dataToEncryptHash: options.dataToEncryptHash,\n }, options.config);\n\n if (!response || typeof response.decryptedString !== 'string') {\n throw new Error('Invalid decrypt response: missing decryptedString');\n }\n\n let result = response.decryptedString;\n\n // Strip binary marker if present (for users who just want the base64 string)\n if (result.startsWith(BINARY_MARKER)) {\n result = result.slice(BINARY_MARKER.length);\n }\n\n return result;\n}\n\n/**\n * Decrypt ciphertext and return the result as a Uint8Array.\n *\n * If the decrypted data was originally encrypted with encryptBinary(), the\n * binary marker is detected and the Base64 payload is decoded back to bytes.\n * Otherwise the decrypted string is encoded as UTF-8 bytes as a fallback.\n *\n * @param options - Decryption configuration including ciphertext and hash\n * @returns The decrypted binary data as a Uint8Array\n */\nexport async function decryptBinary(options: DecryptConfig): Promise<Uint8Array> {\n if (!options || !options.config) {\n throw new Error('DecryptConfig with a valid config is required');\n }\n if (!options.ciphertext) {\n throw new Error('ciphertext is required for decryption');\n }\n if (!options.dataToEncryptHash) {\n throw new Error('dataToEncryptHash is required for decryption');\n }\n\n validateSignerConfig(options.config);\n\n // Perform decryption using the raw API to check the marker ourselves\n let { address, tokenId } = options;\n\n if (!address || !tokenId) {\n const vaultDetails = await resolveVaultDetails(options.config);\n address = address ?? vaultDetails.address;\n tokenId = tokenId ?? vaultDetails.tokenId;\n }\n\n const response = await emblemPost<DecryptApiResponse>('/decrypt', {\n address,\n tokenId,\n ciphertext: options.ciphertext,\n dataToEncryptHash: options.dataToEncryptHash,\n }, options.config);\n\n if (!response || typeof response.decryptedString !== 'string') {\n throw new Error('Invalid decrypt response: missing decryptedString');\n }\n\n const decrypted = response.decryptedString;\n\n // If the binary marker is present, decode the Base64 payload\n if (decrypted.startsWith(BINARY_MARKER)) {\n const base64 = decrypted.slice(BINARY_MARKER.length);\n return base64ToUint8Array(base64);\n }\n\n // Fallback: encode the plain string as UTF-8 bytes\n return new TextEncoder().encode(decrypted);\n}\n\n/* ------------------------------------------------------------------ */\n/* Base64 helpers (environment-agnostic: works in Node and browsers) */\n/* ------------------------------------------------------------------ */\n\nfunction uint8ArrayToBase64(bytes: Uint8Array): string {\n // Use btoa if available (browsers + Node 16+)\n if (typeof btoa === 'function') {\n let binary = '';\n for (let i = 0; i < bytes.length; i++) {\n binary += String.fromCharCode(bytes[i]);\n }\n return btoa(binary);\n }\n\n // Node.js Buffer fallback\n if (typeof Buffer !== 'undefined') {\n return Buffer.from(bytes).toString('base64');\n }\n\n throw new Error('No Base64 encoding method available in this environment');\n}\n\nfunction base64ToUint8Array(base64: string): Uint8Array {\n // Use atob if available (browsers + Node 16+)\n if (typeof atob === 'function') {\n const binary = atob(base64);\n const bytes = new Uint8Array(binary.length);\n for (let i = 0; i < binary.length; i++) {\n bytes[i] = binary.charCodeAt(i);\n }\n return bytes;\n }\n\n // Node.js Buffer fallback\n if (typeof Buffer !== 'undefined') {\n const buf = Buffer.from(base64, 'base64');\n return new Uint8Array(buf.buffer, buf.byteOffset, buf.byteLength);\n }\n\n throw new Error('No Base64 decoding method available in this environment');\n}\n","import type { SignerConfig, SignerVaultInfo, Hex } from '../types/signers';\nimport { emblemPost } from './http';\n\nexport async function fetchVaultInfo(config: SignerConfig): Promise<SignerVaultInfo> {\n // Note: The server only supports POST for /vault/info\n const data: Partial<{\n vaultId: string;\n address: string;\n evmAddress: Hex;\n created_by?: string;\n }> = await emblemPost('/vault/info', {}, config);\n\n // Validate required response data (vaultId + evmAddress are required for EVM)\n if (!data || !data.vaultId || !data.evmAddress) {\n throw new Error('Invalid vault info response: missing required fields');\n }\n\n if (!String(data.evmAddress).startsWith('0x')) {\n throw new Error('Invalid evmAddress format in response');\n }\n\n return {\n vaultId: data.vaultId,\n tokenId: data.vaultId,\n address: data.address || '', // Solana address may be absent; keep optional\n evmAddress: data.evmAddress as Hex,\n created_by: data.created_by,\n };\n}\n"],"names":["async","emblemPost","path","body","config","baseUrl","authHeaders","getAuthHeaders","h","tok","jwt","getJwt","undefined","sdk","getSession","authToken","Authorization","apiKey","Error","resolveAuthHeaders","res","fetch","method","headers","JSON","stringify","_key","value","toString","ok","text","catch","status","errorMessage","substring","sanitizeErrorMessage","json","validateSignerConfig","hasJwt","hasGetJwt","hasHeaders","hasSdk","hasApiKey","startsWith","includes","console","warn","validateBaseUrl","debugSecurity","log","environment","window","document","hasBaseUrl","timestamp","Date","toISOString","BINARY_MARKER","resolveVaultDetails","vaultInfo","data","vaultId","evmAddress","String","tokenId","address","created_by","fetchVaultInfo","encrypt","options","vaultDetails","response","ciphertext","dataToEncryptHash","encryptBinary","Uint8Array","base64","bytes","btoa","binary","i","length","fromCharCode","Buffer","from","uint8ArrayToBase64","decrypt","decryptedString","result","slice","decryptBinary","decrypted","atob","charCodeAt","buf","buffer","byteOffset","byteLength","base64ToUint8Array","TextEncoder","encode"],"mappings":"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"}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import type { SignerConfig } from '../types/signers';
|
|
2
|
+
/** Configuration for encryption operations */
|
|
3
|
+
export interface EncryptConfig {
|
|
4
|
+
/** The SignerConfig for authentication (same as signers use) */
|
|
5
|
+
config: SignerConfig;
|
|
6
|
+
/** Ethereum address for access control. Defaults to vault's EVM address if not provided */
|
|
7
|
+
address?: string;
|
|
8
|
+
/** Token ID for namespace isolation. Defaults to vault's tokenId if not provided */
|
|
9
|
+
tokenId?: string;
|
|
10
|
+
}
|
|
11
|
+
/** Result from an encryption operation */
|
|
12
|
+
export interface EncryptResult {
|
|
13
|
+
/** The encrypted ciphertext (Base64 encoded) */
|
|
14
|
+
ciphertext: string;
|
|
15
|
+
/** Hash of the encrypted data, needed for decryption */
|
|
16
|
+
dataToEncryptHash: string;
|
|
17
|
+
}
|
|
18
|
+
/** Configuration for decryption operations */
|
|
19
|
+
export interface DecryptConfig {
|
|
20
|
+
/** The SignerConfig for authentication */
|
|
21
|
+
config: SignerConfig;
|
|
22
|
+
/** The encrypted ciphertext from encrypt() */
|
|
23
|
+
ciphertext: string;
|
|
24
|
+
/** The hash returned from encrypt() */
|
|
25
|
+
dataToEncryptHash: string;
|
|
26
|
+
/** Ethereum address used during encryption. Defaults to vault's EVM address */
|
|
27
|
+
address?: string;
|
|
28
|
+
/** Token ID used during encryption. Defaults to vault's tokenId */
|
|
29
|
+
tokenId?: string;
|
|
30
|
+
}
|
|
31
|
+
/** Result from a decryption operation */
|
|
32
|
+
export interface DecryptResult {
|
|
33
|
+
/** The decrypted plaintext string */
|
|
34
|
+
data: string;
|
|
35
|
+
}
|
|
36
|
+
/** Result from a binary decryption operation */
|
|
37
|
+
export interface DecryptBinaryResult {
|
|
38
|
+
/** The decrypted binary data */
|
|
39
|
+
data: Uint8Array;
|
|
40
|
+
}
|
|
41
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/crypto/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAErD,8CAA8C;AAC9C,MAAM,WAAW,aAAa;IAC5B,gEAAgE;IAChE,MAAM,EAAE,YAAY,CAAC;IACrB,2FAA2F;IAC3F,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,oFAAoF;IACpF,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,0CAA0C;AAC1C,MAAM,WAAW,aAAa;IAC5B,gDAAgD;IAChD,UAAU,EAAE,MAAM,CAAC;IACnB,wDAAwD;IACxD,iBAAiB,EAAE,MAAM,CAAC;CAC3B;AAED,8CAA8C;AAC9C,MAAM,WAAW,aAAa;IAC5B,0CAA0C;IAC1C,MAAM,EAAE,YAAY,CAAC;IACrB,8CAA8C;IAC9C,UAAU,EAAE,MAAM,CAAC;IACnB,uCAAuC;IACvC,iBAAiB,EAAE,MAAM,CAAC;IAC1B,+EAA+E;IAC/E,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,mEAAmE;IACnE,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,yCAAyC;AACzC,MAAM,WAAW,aAAa;IAC5B,qCAAqC;IACrC,IAAI,EAAE,MAAM,CAAC;CACd;AAED,gDAAgD;AAChD,MAAM,WAAW,mBAAmB;IAClC,gCAAgC;IAChC,IAAI,EAAE,UAAU,CAAC;CAClB"}
|
package/dist/emblem-auth.min.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
!function(t,e){"object"==typeof exports&&"undefined"!=typeof module?e(exports):"function"==typeof define&&define.amd?define(["exports"],e):e((t="undefined"!=typeof globalThis?globalThis:t||self).EmblemAuth={})}(this,function(t){"use strict";class e{constructor(t={}){this.session=null,this.timer=null,this.events={},this.consecutiveFailures=0,this.maxBackoffMs=3e4,this.baseBackoffMs=2e3,this.onRefresh=t.onRefresh,this.refreshSkewMs=t.refreshSkewMs??6e4}setSession(t){this.session=t,this.schedule(),this.emit("session",t)}getSession(){return this.session}clear(){this.session=null,this.cancel(),this.emit("session",null)}on(t,e){this.events[t]||(this.events[t]=[]),this.events[t].push(e)}off(t,e){const s=this.events[t];if(s){const t=s.indexOf(e);-1!==t&&s.splice(t,1)}}destroy(){this.cancel(),this.session=null,Object.keys(this.events).forEach(t=>{delete this.events[t]})}emit(t,e){const s=this.events[t];if(s)for(const t of s)try{t(e)}catch(t){}}cancel(){this.timer&&(clearTimeout(this.timer),this.timer=null)}getBackoffDelay(){return Math.min(this.baseBackoffMs*Math.pow(2,Math.max(0,this.consecutiveFailures-1)),this.maxBackoffMs)}scheduleRetry(t){this.cancel();const e=Date.now(),s=t.expiresAt-e;if(s<=0)return void this.emit("sessionExpired",t);const i=Math.min(this.getBackoffDelay(),s-1e3);this.timer=i<=0?setTimeout(()=>{this.emit("sessionExpired",t)},s):setTimeout(async()=>{if(this.onRefresh)try{const e=await this.onRefresh(t);e?.expiresAt&&e.authToken&&e.expiresAt!==t.expiresAt?(this.consecutiveFailures=0,this.setSession(e),this.emit("sessionRefreshed",e)):(this.consecutiveFailures++,Date.now()>=t.expiresAt?this.emit("sessionExpired",t):this.scheduleRetry(t))}catch(e){this.consecutiveFailures++,Date.now()>=t.expiresAt?this.emit("sessionExpired",t):this.scheduleRetry(t)}else Date.now()>=t.expiresAt&&this.emit("sessionExpired",t)},i)}schedule(){this.cancel();const t=this.session;if(!t?.expiresAt)return;const e=Date.now(),s=t.expiresAt-e;if(s<=0)return void this.emit("sessionExpired",t);this.consecutiveFailures=0;const i=Math.max(0,s-this.refreshSkewMs);this.emit("sessionWillRefresh",{inMs:i,ttl:s}),this.timer=setTimeout(async()=>{if(this.onRefresh)try{const e=await this.onRefresh(t);e?.expiresAt&&e.authToken&&e.expiresAt!==t.expiresAt?(this.consecutiveFailures=0,this.setSession(e),this.emit("sessionRefreshed",e)):(this.consecutiveFailures++,Date.now()>=t.expiresAt?this.emit("sessionExpired",t):this.scheduleRetry(t))}catch(e){this.consecutiveFailures++,Date.now()>=t.expiresAt?this.emit("sessionExpired",t):this.scheduleRetry(t)}else Date.now()>=t.expiresAt&&this.emit("sessionExpired",t)},i)}}class s{constructor(t){if(this.session=null,this.pendingNonce=null,this.overlayEl=null,this._iframeEl=null,this.overlayCleanup=null,this.events={},this._cachedVaultInfo=null,this._visitorId=null,!t?.appId)throw new Error("appId is required");if(this.config={...t,authUrl:t.authUrl??"https://auth.emblemvault.ai",apiUrl:t.apiUrl??"https://api.emblemvault.ai",persistSession:t.persistSession??!0},this.storageKey=`emblem_session_${t.appId}`,this.visitorIdKey=`emblem_visitorId_${t.appId}`,this.messageHandler=this.onMessage.bind(this),"undefined"!=typeof window&&window.addEventListener("message",this.messageHandler),this.sessionMgr=new e({onRefresh:async t=>{try{return await this.refreshSession()||t}catch{return t}}}),this.sessionMgr.on("sessionExpired",t=>this.emit("sessionExpired",t)),this.sessionMgr.on("sessionRefreshed",t=>this.emit("sessionRefreshed",t)),this.sessionMgr.on("sessionWillRefresh",t=>this.emit("sessionWillRefresh",t)),this.config.persistSession){const t=this.loadPersistedSession();t&&this.hydrateSession(t),this._visitorId=this.loadPersistedVisitorId()}this.tryConsumeSessionFromHash()}tryConsumeSessionFromHash(){if("undefined"!=typeof window)try{const t=String(window.location.hash||"").replace(/^#/,"");if(!t)return;const e=new URLSearchParams(t).get("emblemAuthSession");if(!e)return;const s=decodeURIComponent(e),i=decodeURIComponent(escape(atob(s))),n=JSON.parse(i);if(n?.appId&&n.appId!==this.config.appId)return void this.authDebug("consumeHash:ignored (appId mismatch)",{expected:this.config.appId,received:n.appId});this.authDebug("consumeHash:accepted",{appId:n?.appId}),this.session=n,this.persistSession(n),this.sessionMgr.setSession(n),this.config.onSuccess?.(n),this.emit("session",n);try{window.history.replaceState(null,"",window.location.pathname+window.location.search)}catch{}}catch(t){this.authDebug("consumeHash:failed",{error:t?.message||String(t)})}}async authenticateWallet(t){const{network:e,message:s,signature:i,publicKey:n,address:r}=t;if(!this.config.apiUrl)throw new Error("apiUrl is required for authenticateWallet");if(!e||!s||!i)throw new Error("network, message, signature are required");const a=`${this.config.apiUrl.replace(/\/$/,"")}/api/auth/wallet/verify-external`,o=await fetch(a,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({appId:this.config.appId,network:e,message:s,signature:i,publicKey:n,address:r})});if(!o.ok){const t=await this.safeJson(o),e=new Error(t?.error||`wallet_verify_${o.status}`);throw e.status=o.status,e.payload=t,e}const c=await o.json(),h=c?.session;return h&&(this.session=h,this.persistSession(h),this.sessionMgr.setSession(h),this.config.onSuccess?.(h),this.emit("session",h)),h}async openOAuth(t){if("undefined"==typeof window)throw new Error("openOAuth() must be called in a browser environment");const e=window.location.origin;this.authDebug("openOAuth:start",{provider:t,origin:e,apiUrl:this.config.apiUrl});const s=await this.getAuthInit({origin:e}),i=s?.nonce||this.randomId(),n=s?.state;this.pendingNonce=i,this.authDebug("openOAuth:init ok",{noncePrefix:String(i).slice(0,8),hasState:!!n,statePrefix:String(n||"").slice(0,16)});const r=this.normalizeBaseUrl(this.config.authUrl,"authUrl"),a=new URL(`${r}/api/auth/oauth/init`);a.searchParams.set("provider",t),a.searchParams.set("state",n),this.authDebug("openOAuth:navigate",{url:a.toString()});const o=window.open(a.toString(),"emblem-auth",this.popupFeatures());if(o)try{o.focus()}catch{}else try{this.authDebug("openOAuth:popup blocked, using same-window navigation"),window.location.assign(a.toString())}catch{const t=new Error("Popup blocked. Please allow popups for this site.");this.emitError(t)}}async sendEmailOtp(t){const e=this.config.apiUrl.replace(/\/$/,""),s=await fetch(`${e}/api/auth/email/send-otp`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({appId:t.appId??this.config.appId,email:t.email,password:t.password})}),i=await s.json().catch(()=>null);if(!s.ok){const t=new Error(i?.error||`email_send_otp_${s.status}`);throw t.status=s.status,t.payload=i,t}return i}async verifyEmailOtp(t){const e=this.config.apiUrl.replace(/\/$/,""),s=await fetch(`${e}/api/auth/email/verify-otp`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({appId:t.appId??this.config.appId,email:t.email,otp:t.otp,password:t.password})}),i=await s.json().catch(()=>null);if(!s.ok){const t=new Error(i?.error||`email_verify_otp_${s.status}`);throw t.status=s.status,t.payload=i,t}const n=i?.session;return n&&(this.session=n,this.persistSession(n),this.sessionMgr.setSession(n),this.emit("session",n)),n}async authenticateEmail(t){const e=this.config.apiUrl.replace(/\/$/,""),s=await fetch(`${e}/api/auth/email/login`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({appId:t.appId??this.config.appId,email:t.email,password:t.password})}),i=await s.json().catch(()=>null);if(!s.ok){const t=new Error(i?.error||`email_login_${s.status}`);throw t.status=s.status,t.payload=i,t}const n=i?.session;return n&&(this.session=n,this.persistSession(n),this.sessionMgr.setSession(n),this.emit("session",n)),n}async authenticatePassword(t){const e=this.config.authUrl.replace(/\/$/,""),s=await fetch(`${e}/api/auth/password/verify`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({appId:this.config.appId,password:t.password})}),i=await s.json().catch(()=>null);if(!s.ok){const t=new Error(i?.error||`password_verify_${s.status}`);throw t.status=s.status,t.payload=i,t}const n=i?.session;return n&&(this.session=n,this.persistSession(n),this.sessionMgr.setSession(n),this.emit("session",n)),n}async openAuthModal(){const t=window.location.origin;let e=null,s=null;try{e=await this.getAuthInit({origin:t})}catch(t){s=t}const i=e?.nonce||this.randomId();this.pendingNonce=i;let n=this.resolveModalUrl({nonce:i,origin:t,state:e?.state});if("origin_not_allowed"===s?.payload?.error)try{const e=new URL("/connect",this.config.authUrl);e.searchParams.set("error","origin_not_allowed"),e.searchParams.set("appId",this.config.appId),e.searchParams.set("origin",t),n=e.toString()}catch{}const r=this.config.modalMode||"auto";let a=!1;if("iframe"===r||"auto"===r)try{a=this.openIframeModal(n)}catch(t){}if(!a){const t=this.popupFeatures();if(!window.open(n,"emblem-auth",t)){const t=new Error("Popup blocked. Please allow popups for this site.");this.emitError(t)}}}getSession(){return this.session}getVisitorId(){return this._visitorId}async refreshSession(){try{if(!this.session)return null;const t=this.tryGetOriginFromConfig();if(!t)return this.session;const e=`${t}/api/auth/refresh`,s=Boolean(this.session.refreshToken),i=await fetch(e,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(s?{refreshToken:this.session.refreshToken}:{}),credentials:"include"});if(!i.ok)return this.session;const n=await i.json(),r=n?.session;return r&&(this.session=r,this.persistSession(r),this.sessionMgr.setSession(r),this.emit("session",r)),this.session}catch{return this.session}}async getVaultInfo(){if(this._cachedVaultInfo)return this._cachedVaultInfo;const t=this.getSession();if(!t?.authToken)throw new Error("No session");if(!this.config.apiUrl)throw new Error("apiUrl is required");const e=this.config.apiUrl.replace(/\/$/,""),s=await fetch(`${e}/vault/info`,{method:"POST",headers:{Authorization:`Bearer ${t.authToken}`,"Content-Type":"application/json"},body:"{}"});if(!s.ok)throw new Error("Failed to fetch vault info");const i=await s.json();return this._cachedVaultInfo=i,i}async getVaultApiKey(){if(!this.config.apiUrl)throw new Error("apiUrl is required");const t=this.getSession();if(!t?.authToken)throw new Error("No active session");const e=this.config.apiUrl.replace(/\/$/,""),s=t.authToken,i=t.user?.vaultId;let n=null;try{const t=await fetch(`${e}/vault/info-complete`,{method:"POST",headers:{Authorization:`Bearer ${s}`}});if(t.ok){const e=await t.json();n=e?.raw?.pkp?.api_key_hash||e?.raw?.pkp?.apiKeyHash||null}}catch{}if(!n)try{const s=t.appId,r=t.user?.identifier||"",a=s?`${s}:${r}`:r;if(a){const t=await fetch(`${e}/api/vaults/${encodeURIComponent(a)}`);if(t.ok){const e=await t.json(),s=Array.isArray(e)?e.find(t=>String(t.tokenId||t.token_id)===String(i))||e[0]:null;n=s?.api_key_hash||s?.apiKeyHash||null}}}catch{}if(!n){const t=await fetch(`${e}/api/vaults/${encodeURIComponent(i)}/api-key`,{method:"POST",headers:{Authorization:`Bearer ${s}`}});if(!t.ok)throw new Error(`gen_key_${t.status}`);const n=await t.json(),r=n?.apiKey||n?.key||null;if(!r)throw new Error("missing_apiKey");return r}const r=await fetch(`${e}/decrypt`,{method:"POST",headers:{Authorization:`Bearer ${s}`,"Content-Type":"application/json"},body:JSON.stringify({tokenId:i,dataToEncryptHash:n})});if(!r.ok)throw new Error(`decrypt_${r.status}`);const a=await r.json(),o=a?.decryptedString||null;if(!o)throw new Error("missing_decrypted");return o}hydrateSession(t){t?.authToken&&(this.session=t,this.persistSession(t),this._cachedVaultInfo=null,this.sessionMgr.setSession(t),this.emit("session",t))}logout(){this.session=null,this.persistSession(null),this._visitorId=null,this.persistVisitorId(null),this._cachedVaultInfo=null,this.sessionMgr.clear(),this.emit("session",null)}on(t,e){this.events[t]||(this.events[t]=[]),this.events[t].push(e)}off(t,e){const s=this.events[t];if(s){const t=s.indexOf(e);-1!==t&&s.splice(t,1)}}async getSignerContext(){const t=this.getSession();if(!t?.authToken)throw new Error("No active session. Call openAuthModal() or authenticateWallet() first.");const e=await this.getVaultInfo();return{config:{baseUrl:this.config.apiUrl,getJwt:()=>this.getSession()?.authToken},vaultInfo:{vaultId:e.vaultId,evmAddress:e.evmAddress||"0x",address:e.solanaAddress||e.address||"",tokenId:e.tokenId,created_by:e.created_by}}}async toViemAccount(){const{toViemAccount:t}=await Promise.resolve().then(function(){return h}),{config:e,vaultInfo:s}=await this.getSignerContext();return t(e,s)}async toEthersWallet(t){const{toEthersWallet:e}=await Promise.resolve().then(function(){return u}),{config:s,vaultInfo:i}=await this.getSignerContext();return e(s,t,i)}async toWeb3Adapter(){const{toWeb3Adapter:t}=await Promise.resolve().then(function(){return y}),{config:e,vaultInfo:s}=await this.getSignerContext();return t(e,s)}async toSolanaWeb3Signer(){const{toSolanaWeb3Signer:t}=await Promise.resolve().then(function(){return m}),{config:e,vaultInfo:s}=await this.getSignerContext();return t(e,s)}async toSolanaKitSigner(){const{toSolanaKitSigner:t}=await Promise.resolve().then(function(){return m}),{config:e,vaultInfo:s}=await this.getSignerContext();return t(e,s)}async toBitcoinSigner(){const{toBitcoinSigner:t,fetchBitcoinVaultInfo:e}=await Promise.resolve().then(function(){return E}),{config:s}=await this.getSignerContext();return t(s,await e(s))}destroy(){"undefined"!=typeof window&&window.removeEventListener("message",this.messageHandler),this.sessionMgr.destroy(),this.closeOverlay(),Object.keys(this.events).forEach(t=>{delete this.events[t]})}resolveModalUrl(t){const e=`${this.config.authUrl.replace(/\/$/,"")}/connect`,s=new URL(e,window.location.href);return s.searchParams.set("appId",this.config.appId),s.searchParams.set("origin",t.origin),s.searchParams.set("nonce",t.nonce),t.state&&s.searchParams.set("state",t.state),s.toString()}authDebugEnabled(){try{const t=window?.localStorage?.getItem?.("AUTH_DEBUG");if("true"===String(t).toLowerCase())return!0}catch{}try{const t="undefined"!=typeof process?process:null,e=t?.env||{},s=e.NEXT_PUBLIC_AUTH_DEBUG??e.AUTH_DEBUG;if(!s)return!1;const i=String(s).toLowerCase().trim();return"1"===i||"true"===i||"yes"===i||"on"===i}catch{return!1}}authDebug(...t){this.authDebugEnabled()}normalizeBaseUrl(t,e){if(!t)throw new Error(`${e} is required`);const s=String(t).trim(),i="undefined"!=typeof window?window.location.href:"http://localhost";try{return new URL(s,i).toString().replace(/\/$/,"")}catch{}try{return new URL(`https://${s.replace(/^\/+/,"")}`).toString().replace(/\/$/,"")}catch{}throw new Error(`${e} must be an absolute URL (e.g. "https://api.emblemvault.ai") or a relative path (e.g. "/")`)}onMessage(t){try{const e=new Set([window.location.origin,this.tryGetOriginFromConfig(),this.tryGetOriginFromApiUrl()].filter(Boolean));if(!e.has(t.origin))return void this.authDebug("onMessage:ignored (origin)",{eventOrigin:t.origin,allowedOrigins:Array.from(e)});const s=t.data;if("emblem-auth-cancelled"===s?.type){if(!this.pendingNonce||s.nonce!==this.pendingNonce)return;return this.pendingNonce=null,this.closeOverlay(),this.config.onCancel&&this.config.onCancel(),void this.emit("cancelled",void 0)}if("emblem-auth-success"!==s?.type)return;if(!this.pendingNonce||s.nonce!==this.pendingNonce)return void this.authDebug("onMessage:ignored (nonce)",{expected:this.pendingNonce,received:s?.nonce,origin:t.origin,type:s?.type});this.pendingNonce=null,this.authDebug("onMessage:accepted",{origin:t.origin});const i=s.session;this.session=i,this.persistSession(i),this.sessionMgr.setSession(i),s.visitorId&&(this._visitorId=s.visitorId,this.persistVisitorId(s.visitorId)),i&&this.config.onSuccess&&this.config.onSuccess(i),this.emit("session",i),this.closeOverlay()}catch(t){this.emitError(t)}}emit(t,e){const s=this.events[t];if(s)for(const t of s)try{t(e)}catch(t){}}emitError(t){this.config.onError?.(t),this.emit("authError",t)}popupFeatures(){const t=Math.max(0,(window.outerHeight-680)/2);return`popup=yes,width=520,height=680,left=${Math.max(0,(window.outerWidth-520)/2)},top=${t}`}randomId(){const t=new Uint8Array(16);if(window.crypto?.getRandomValues)window.crypto.getRandomValues(t);else for(let e=0;e<t.length;e++)t[e]=Math.floor(256*Math.random());return Array.from(t,t=>t.toString(16).padStart(2,"0")).join("")}tryGetOriginFromConfig(){try{if(!this.config.authUrl)return null;const t=this.normalizeBaseUrl(this.config.authUrl,"authUrl");return new URL(t).origin}catch{return null}}tryGetOriginFromApiUrl(){try{if(!this.config.apiUrl)return null;const t=this.normalizeBaseUrl(this.config.apiUrl,"apiUrl");return new URL(t).origin}catch{return null}}async getAuthInit(t){const e=JSON.stringify({appId:this.config.appId,origin:t.origin}),s=async t=>{const s=await fetch(`${t.replace(/\/$/,"")}/api/auth/init`,{method:"POST",headers:{"Content-Type":"application/json"},body:e}),i=await s.json().catch(()=>null);if(!s.ok){const t=new Error(`init ${s.status}`);throw t.status=s.status,t.payload=i||{},t}return i};try{return await s(this.config.authUrl)}catch(t){const e=t;try{return await s(this.config.apiUrl)}catch(t){const s=e;throw s.payload={...e?.payload||{},fallback:t?.payload||void 0},s}}}openIframeModal(t){this.overlayEl&&this.closeOverlay();const e=document.createElement("div");e.setAttribute("data-emblem-overlay",""),e.style.position="fixed",e.style.inset="0",e.style.background="rgba(0,0,0,0.55)",e.style.backdropFilter="blur(6px)",e.style.webkitBackdropFilter="blur(6px)",e.style.zIndex="999999",e.style.display="flex",e.style.alignItems="center",e.style.justifyContent="center",e.style.padding="12px";const s=document.createElement("div");s.style.width="min(520px, 96vw)",s.style.height="min(680px, 92vh)",s.style.background="#12161b",s.style.border="1px solid #222b35",s.style.borderRadius="12px",s.style.boxShadow="0 12px 48px rgba(0,0,0,0.7)",s.style.overflow="hidden",s.style.position="relative",s.style.display="flex",s.style.flexDirection="column";const i=document.createElement("div");i.style.height="52px",i.style.display="flex",i.style.alignItems="center",i.style.justifyContent="space-between",i.style.padding="0 12px",i.style.borderBottom="1px solid rgba(255, 255, 255, 0.06)",i.style.background="#12161b";const n=document.createElement("div");n.textContent="Emblem",n.style.fontFamily="ui-sans-serif, system-ui, -apple-system, Segoe UI, Roboto, Helvetica, Arial",n.style.fontSize="13px",n.style.letterSpacing="0.08em",n.style.textTransform="uppercase",n.style.color="rgba(230, 238, 248, 0.75)";const r=document.createElement("button");r.type="button",r.textContent="×",r.setAttribute("aria-label","Close"),r.setAttribute("title","Close"),r.style.width="40px",r.style.height="40px",r.style.display="flex",r.style.alignItems="center",r.style.justifyContent="center",r.style.background="rgba(255, 255, 255, 0.04)",r.style.color="#e6eef8",r.style.border="1px solid rgba(255, 255, 255, 0.08)",r.style.borderRadius="10px",r.style.fontSize="24px",r.style.lineHeight="1",r.style.cursor="pointer",r.style.userSelect="none",r.onclick=()=>this.cancelAuth(),i.appendChild(n),i.appendChild(r);const a=document.createElement("iframe");a.src=t,a.style.width="100%",a.style.height="100%",a.style.border="0",a.referrerPolicy="no-referrer",a.allow="clipboard-read; clipboard-write;",s.appendChild(i),s.appendChild(a),e.appendChild(s),document.body.appendChild(e),e.addEventListener("click",t=>{t.target===e&&this.cancelAuth()});const o=t=>{"Escape"===t.key&&this.cancelAuth()};return document.addEventListener("keydown",o,{capture:!0}),this.overlayEl=e,this._iframeEl=a,this.overlayCleanup=()=>{document.removeEventListener("keydown",o,{capture:!0})},!0}closeOverlay(){try{this.overlayCleanup?.()}catch{}this.overlayCleanup=null,this.overlayEl?.parentNode&&this.overlayEl.parentNode.removeChild(this.overlayEl),this.overlayEl=null,this._iframeEl=null}cancelAuth(){this.pendingNonce=null,this.closeOverlay(),this.config.onCancel&&this.config.onCancel(),this.emit("cancelled",void 0)}async safeJson(t){try{return await t.json()}catch{return null}}loadPersistedSession(){try{if("undefined"==typeof localStorage)return null;const t=localStorage.getItem(this.storageKey);if(!t)return null;const e=JSON.parse(t);return e?.authToken&&e?.expiresAt?Date.now()>=e.expiresAt?(localStorage.removeItem(this.storageKey),null):e:null}catch{return null}}persistSession(t){try{if("undefined"==typeof localStorage)return;t&&this.config.persistSession?localStorage.setItem(this.storageKey,JSON.stringify(t)):localStorage.removeItem(this.storageKey)}catch{}}loadPersistedVisitorId(){try{return"undefined"==typeof localStorage?null:localStorage.getItem(this.visitorIdKey)}catch{return null}}persistVisitorId(t){try{if("undefined"==typeof localStorage)return;t&&this.config.persistSession?localStorage.setItem(this.visitorIdKey,t):localStorage.removeItem(this.visitorIdKey)}catch{}}}async function i(t,e,s){const i=s.baseUrl??"https://api.emblemvault.ai",n=await async function(t){if("function"==typeof t.getAuthHeaders){const e=await t.getAuthHeaders();if(e&&"object"==typeof e)return e}const e=t.jwt??("function"==typeof t.getJwt?await t.getJwt():void 0)??t.sdk?.getSession()?.authToken??void 0;if(e)return{Authorization:`Bearer ${e}`};if(t.apiKey)return{"x-api-key":t.apiKey};throw new Error("No authentication available: provide jwt, getJwt(), getAuthHeaders(), sdk, or apiKey")}(s),r=await fetch(`${i}${t}`,{method:"POST",headers:{"content-type":"application/json",...n},body:JSON.stringify(e,(t,e)=>"bigint"==typeof e?e.toString():e)});if(!r.ok){const t=await r.text().catch(()=>"");throw new Error(function(t,e){let s=`Emblem signer error ${t}`;return t>=500?s+=": Internal server error":401===t||403===t?s+=": Authentication failed":404===t?s+=": Resource not found":405===t?s+=": Method not allowed":e&&(s+=`: ${e.substring(0,200)}`),s}(r.status,t))}return r.json()}function n(t,e){const s=Number(t);if(!Number.isSafeInteger(s))throw new Error(`${e} value ${t} exceeds safe integer range (max: ${Number.MAX_SAFE_INTEGER})`);return s}function r(t){return"bigint"==typeof t?"0x"+t.toString(16):t}function a(t){const e={...t};return void 0!==e.value&&(e.value=r(e.value)),void 0!==e.gas&&(e.gasLimit=r(e.gas),delete e.gas),void 0!==e.gasLimit&&(e.gasLimit=r(e.gasLimit)),void 0!==e.gasPrice&&(e.gasPrice=r(e.gasPrice)),void 0!==e.maxFeePerGas&&(e.maxFeePerGas=r(e.maxFeePerGas)),void 0!==e.maxPriorityFeePerGas&&(e.maxPriorityFeePerGas=r(e.maxPriorityFeePerGas)),void 0!==e.nonce&&(e.nonce=n(e.nonce,"nonce")),void 0!==e.chainId&&(e.chainId=n(e.chainId,"chainId")),void 0===e.maxFeePerGas&&void 0===e.maxPriorityFeePerGas||(void 0===e.gasPrice&&void 0!==e.maxFeePerGas&&(e.gasPrice=e.maxFeePerGas),delete e.maxFeePerGas,delete e.maxPriorityFeePerGas),delete e.type,delete e.accessList,delete e.account,delete e.chain,delete e.from,e}function o(t){let e="0x";for(let s=0;s<t.length;s++)e+=t[s].toString(16).padStart(2,"0");return e}async function c(t){const e=await i("/vault/info",{},t);if(!e||!e.vaultId||!e.evmAddress)throw new Error("Invalid vault info response: missing required fields");if(!String(e.evmAddress).startsWith("0x"))throw new Error("Invalid evmAddress format in response");return{vaultId:e.vaultId,tokenId:e.vaultId,address:e.address||"",evmAddress:e.evmAddress,created_by:e.created_by}}var h=Object.freeze({__proto__:null,toViemAccount:async function(t,e){const s=e??await c(t),{evmAddress:n,vaultId:r}=s,{toAccount:h}=await import("viem/accounts");return h({address:n,async signMessage({message:e}){let s,n=!1;if("string"==typeof e)s=e,n=!1;else if(e&&void 0!==e.raw){const t=e.raw;s="string"==typeof t?t:o(t),n=!0}else if(e instanceof Uint8Array)s=o(e),n=!1;else{if("string"!=typeof(a=e)||!/^0x[0-9a-fA-F]*$/.test(a))throw new Error(`Unsupported message type: ${typeof e}. Expected string, Uint8Array, or hex string.`);s=e,n=!1}var a;return(await i("/sign-eth-message",{vaultId:r,message:s,raw:n},t)).signature},async signTypedData(e){const{domain:s,types:n,message:a}=e;return(await i("/sign-typed-message",{vaultId:r,domain:s,types:n,message:a},t)).signature},async signTransaction(e,s){const n=a(e);return(await i("/sign-eth-tx",{vaultId:r,transaction:n},t)).signedTransaction}})}});var l,d,u=Object.freeze({__proto__:null,toEthersWallet:async function(t,e,s){let n;try{const t="ethers";n=await import(t)}catch{throw new Error("ethers is required for toEthersWallet(). Install it with: npm install ethers")}const{AbstractSigner:r,resolveAddress:h}=n,l=s??await c(t);class d extends r{constructor(t,e,s){super(e??null),this._address=null,this._vaultId=null,this._chainId=1,this._config=t,s?.address&&(this._address=s.address),s?.vaultId&&(this._vaultId=s.vaultId),s?.chainId&&(this._chainId=s.chainId)}async initialize(){return this._initPromise||(this._initPromise=c(this._config).then(t=>{this._address=t.evmAddress,this._vaultId=t.vaultId}).catch(t=>{throw this._initPromise=void 0,t})),this._initPromise}async getAddress(){return this._address||await this.initialize(),this._address}getVaultId(){if(!this._vaultId)throw new Error("Wallet not initialized. Call initialize() first.");return this._vaultId}setChainId(t){this._chainId=t}getChainId(){return this._chainId}connect(t){if(!t)throw new Error("Provider cannot be null");return new d(this._config,t,{address:this._address??void 0,vaultId:this._vaultId??void 0,chainId:this._chainId})}async signMessage(t){this._vaultId||await this.initialize();const e="string"==typeof t?t:o(t);return(await i("/sign-eth-message",{vaultId:this._vaultId,message:e},this._config)).signature}async signTypedData(t,e,s){this._vaultId||await this.initialize();const n={...e};n&&n.EIP712Domain&&delete n.EIP712Domain;return(await i("/sign-typed-message",{vaultId:this._vaultId,domain:t,types:n,message:s},this._config)).signature}async _signTypedData(t,e,s){return this.signTypedData(t,e,s)}async signTransaction(t){this._vaultId||await this.initialize();const e=t.from,s=await this.getAddress();if(e&&e.toLowerCase()!==s.toLowerCase())throw new Error("transaction from does not match signer address");const n=this.provider?{...await this.populateTransaction(t)}:{...t};if(n.from&&delete n.from,!("to"in n)||!n.to)throw new Error("Transaction must have a 'to' address");if(void 0===n.nonce||null===n.nonce)throw new Error("Transaction must have a nonce");const r=a(n);return(await i("/sign-eth-tx",{vaultId:this._vaultId,transaction:r,options:{chainId:this._chainId}},this._config)).signedTransaction}async sendTransaction(t){if(!this.provider)throw new Error("Provider required to send transaction");const e=await this.signTransaction(t);return await this.provider.broadcastTransaction(e)}async populateTransaction(t){const e={...t};if(!this.provider)throw new Error("Provider required to populate transaction");const s=e.from?await h(e.from,this.provider):await this.getAddress();let i;if(e.chainId)i=BigInt(e.chainId),this._chainId=Number(e.chainId);else{const t=await this.provider.getNetwork();i=t.chainId,this._chainId=Number(t.chainId)}const n=null!=e.nonce?Number(e.nonce):await this.provider.getTransactionCount(s,"pending"),r=e.to?await h(e.to,this.provider):null,a=e.value?BigInt(e.value.toString()):0n;let o;if(e.gasLimit)o=BigInt(e.gasLimit.toString());else try{o=await this.provider.estimateGas({...e,from:s})}catch{o=21000n}let c=null;if(e.gasPrice||2===e.type)e.gasPrice&&(c=BigInt(e.gasPrice.toString()));else{c=(await this.provider.getFeeData()).gasPrice??null}const l={from:s,to:r,value:a,nonce:n,gasLimit:o,data:e.data,chainId:i,type:e.type||void 0};return null!==c&&(l.gasPrice=c),e.maxFeePerGas&&(l.maxFeePerGas=BigInt(e.maxFeePerGas.toString())),e.maxPriorityFeePerGas&&(l.maxPriorityFeePerGas=BigInt(e.maxPriorityFeePerGas.toString())),l}async signAndBroadcast(t,e=!1){if(!this.provider)throw new Error("Provider required to send transaction");const s=await this.signTransaction(t),i=(await this.provider.broadcastTransaction(s)).hash;return e&&await this.provider.waitForTransaction(i),i}}return new d(t,e,{address:l.evmAddress,vaultId:l.vaultId})}});function p(t,e,s,i){if("a"===s&&!i)throw new TypeError("Private accessor was defined without a getter");if("function"==typeof e?t!==e||!i:!e.has(t))throw new TypeError("Cannot read private member from an object whose class did not declare it");return"m"===s?i:"a"===s?i.call(t):i?i.value:e.get(t)}function f(t,e,s,i,n){if("m"===i)throw new TypeError("Private method is not writable");if("a"===i&&!n)throw new TypeError("Private accessor was defined without a setter");if("function"==typeof e?t!==e||!n:!e.has(t))throw new TypeError("Cannot write private member to an object whose class did not declare it");return"a"===i?n.call(t,s):n?n.value=s:e.set(t,s),s}"function"==typeof SuppressedError&&SuppressedError;class g{constructor(t,e,s){l.set(this,void 0),d.set(this,void 0),this.address=t,f(this,l,e,"f"),f(this,d,s,"f")}async signMessage(t){const e="string"==typeof t?t:o(t);return(await i("/sign-eth-message",{vaultId:p(this,l,"f"),message:e},p(this,d,"f"))).signature}async signTypedData(t,e,s){return(await i("/sign-typed-message",{vaultId:p(this,l,"f"),domain:t,types:e,message:s},p(this,d,"f"))).signature}async signTransaction(t){const e=a(t);return{rawTransaction:(await i("/sign-eth-tx",{vaultId:p(this,l,"f"),transaction:e},p(this,d,"f"))).signedTransaction}}}l=new WeakMap,d=new WeakMap;var y=Object.freeze({__proto__:null,EmblemWeb3Adapter:g,toWeb3Adapter:async function(t,e){const s=e??await c(t);return new g(s.evmAddress,s.vaultId,t)}});class w{constructor(t,e){this.publicKey=e.address,this.config=t,this.vaultId=e.vaultId}async signMessage(t){const e="string"==typeof t?(new TextEncoder).encode(t):t,s=btoa(String.fromCharCode(...e)),n=await i("/sign-solana-message",{vaultId:this.vaultId,message:s},this.config);try{const t="undefined"!=typeof window?window:void 0;if(t?.bs58)return t.bs58.decode(n.signature);return Uint8Array.from(atob(n.signature),t=>t.charCodeAt(0))}catch(t){if(n.signature.startsWith("0x")){const t=n.signature.slice(2),e=new Uint8Array(t.length/2);for(let s=0;s<t.length;s+=2)e[s/2]=parseInt(t.substr(s,2),16);return e}throw new Error(`Unable to decode signature format: ${t}`)}}async signTransaction(t){const e=this.serializeTransaction(t),s=await i("/sign-solana-transaction",{vaultId:this.vaultId,transactionToSign:e,broadcast:!1,versionedTransaction:!0},this.config),n=s.serializedSignedTransaction||s.signedTransaction;if(!n)throw new Error("No signed transaction data received from server");return this.deserializeTransaction(n)}serializeTransaction(t){if(t&&"object"==typeof t){if(t.serialize){const e=t.serialize();return btoa(String.fromCharCode(...e))}if(t.instructions||t.recentBlockhash)throw new Error("Cannot serialize unsigned transaction objects. Please use VersionedTransaction.")}return t}deserializeTransaction(t){if("object"==typeof t&&t&&t.serializedSignedTransaction&&(t=t.serializedSignedTransaction),"string"==typeof t)try{const e=atob(t);return new Uint8Array(e.split("").map(t=>t.charCodeAt(0)))}catch(t){throw new Error(`Unable to deserialize transaction response: ${t}`)}return t}getVaultId(){return this.vaultId}async signAllTransactions(t){const e=[];for(const s of t)e.push(await this.signTransaction(s));return e}canSign(t){return t===this.publicKey}async signAndBroadcast(t,e=!0){const s=this.serializeTransaction(t),n=await i("/sign-solana-transaction",{vaultId:this.vaultId,transactionToSign:s,broadcast:e,versionedTransaction:!0},this.config);if(e){if(!n.transactionSignature)throw new Error("No transaction signature received from broadcast");return n.transactionSignature}if(!n.serializedSignedTransaction)throw new Error("No signed transaction data received from server");return n.serializedSignedTransaction}}var m=Object.freeze({__proto__:null,EmblemSolanaSigner:w,toSolanaWeb3Signer:async function(t,e){const s=e??await c(t);return new w(t,s)},toSolanaKitSigner:async function(t,e){const s=e??await c(t);return new w(t,s)}});const v=1e8;class I{constructor(t,e){if(!e.btcPubkey)throw new Error("Bitcoin public key is required in vault info");this.publicKey=e.btcPubkey,this.addresses=e.btcAddresses??{p2pkh:"",p2wpkh:"",p2tr:""},this.config=t,this.vaultId=e.vaultId}async signPsbt(t,e){const{transactionType:s,toSignInputs:n}=e,r=n?.map(t=>({...t,tapLeafHashToSign:this.normalizeToHex(t.tapLeafHashToSign)}));return await i("/sign-btc-transaction",{vaultId:this.vaultId,psbt:t,transactionType:s,toSignInputs:r},this.config)}async signAllPsbts(t){const e=[];for(const{psbt:s,options:i}of t)e.push(await this.signPsbt(s,i));return e}getVaultId(){return this.vaultId}getPublicKey(){return this.publicKey}ownsAddress(t){return t===this.addresses.p2pkh||t===this.addresses.p2wpkh||t===this.addresses.p2tr}getAddress(t="p2wpkh"){switch(t){case"p2pkh":return this.addresses.p2pkh;case"p2wpkh":case"p2sh":default:return this.addresses.p2wpkh;case"p2tr":return this.addresses.p2tr}}normalizeToHex(t){if(null==t)return;if("string"==typeof t)return t;const e=t;let s="";for(let t=0;t<e.length;t++)s+=e[t].toString(16).padStart(2,"0");return s}}async function b(t){const e=await i("/vault/info",{},t);if(!e||!e.vaultId)throw new Error("Invalid vault info response: missing vaultId");if(!e.btcPubkey)throw new Error("Invalid vault info response: missing btcPubkey (Bitcoin public key)");return{vaultId:e.vaultId,address:e.address||"",evmAddress:e.evmAddress||"0x",btcPubkey:e.btcPubkey,btcAddresses:e.btcAddresses,created_by:e.created_by}}function S(t){return t/v}var E=Object.freeze({__proto__:null,SATS_PER_BTC:v,EmblemBitcoinSigner:I,toBitcoinSigner:async function(t,e){const s=e??await b(t);return new I(t,s)},fetchBitcoinVaultInfo:b,detectAddressType:function(t){return t.startsWith("bc1p")?"p2tr":t.startsWith("bc1q")?"p2wpkh":t.startsWith("1")?"p2pkh":t.startsWith("3")?"p2sh":t.startsWith("tb1p")?"p2tr":t.startsWith("tb1q")?"p2wpkh":t.startsWith("m")||t.startsWith("n")?"p2pkh":t.startsWith("2")?"p2sh":"unknown"},satsToBTC:S,btcToSats:function(t){return Math.round(t*v)},formatSats:function(t){return`${t.toLocaleString()} sats (${S(t).toFixed(8)} BTC)`},estimateTransactionSize:function(t,e,s="p2wpkh"){let i;switch(s){case"p2pkh":i=148;break;case"p2tr":i=58;break;default:i=68}return 10+t*i+31*e},calculateFee:function(t,e){return Math.ceil(t*e)},isDust:function(t,e="p2wpkh"){return t<("p2wpkh"===e||"p2tr"===e?294:546)}});t.EmblemAuthSDK=s,t.SessionManager=e,t.default=s,Object.defineProperty(t,"__esModule",{value:!0})});
|
|
1
|
+
!function(t,e){"object"==typeof exports&&"undefined"!=typeof module?e(exports):"function"==typeof define&&define.amd?define(["exports"],e):e((t="undefined"!=typeof globalThis?globalThis:t||self).EmblemAuth={})}(this,function(t){"use strict";class e{constructor(t={}){this.session=null,this.timer=null,this.events={},this.consecutiveFailures=0,this.maxBackoffMs=3e4,this.baseBackoffMs=2e3,this.onRefresh=t.onRefresh,this.refreshSkewMs=t.refreshSkewMs??6e4}setSession(t){this.session=t,this.schedule(),this.emit("session",t)}getSession(){return this.session}clear(){this.session=null,this.cancel(),this.emit("session",null)}on(t,e){this.events[t]||(this.events[t]=[]),this.events[t].push(e)}off(t,e){const s=this.events[t];if(s){const t=s.indexOf(e);-1!==t&&s.splice(t,1)}}destroy(){this.cancel(),this.session=null,Object.keys(this.events).forEach(t=>{delete this.events[t]})}emit(t,e){const s=this.events[t];if(s)for(const t of s)try{t(e)}catch(t){}}cancel(){this.timer&&(clearTimeout(this.timer),this.timer=null)}getBackoffDelay(){return Math.min(this.baseBackoffMs*Math.pow(2,Math.max(0,this.consecutiveFailures-1)),this.maxBackoffMs)}scheduleRetry(t){this.cancel();const e=Date.now(),s=t.expiresAt-e;if(s<=0)return void this.emit("sessionExpired",t);const i=Math.min(this.getBackoffDelay(),s-1e3);this.timer=i<=0?setTimeout(()=>{this.emit("sessionExpired",t)},s):setTimeout(async()=>{if(this.onRefresh)try{const e=await this.onRefresh(t);e?.expiresAt&&e.authToken&&e.expiresAt!==t.expiresAt?(this.consecutiveFailures=0,this.setSession(e),this.emit("sessionRefreshed",e)):(this.consecutiveFailures++,Date.now()>=t.expiresAt?this.emit("sessionExpired",t):this.scheduleRetry(t))}catch(e){this.consecutiveFailures++,Date.now()>=t.expiresAt?this.emit("sessionExpired",t):this.scheduleRetry(t)}else Date.now()>=t.expiresAt&&this.emit("sessionExpired",t)},i)}schedule(){this.cancel();const t=this.session;if(!t?.expiresAt)return;const e=Date.now(),s=t.expiresAt-e;if(s<=0)return void this.emit("sessionExpired",t);this.consecutiveFailures=0;const i=Math.max(0,s-this.refreshSkewMs);this.emit("sessionWillRefresh",{inMs:i,ttl:s}),this.timer=setTimeout(async()=>{if(this.onRefresh)try{const e=await this.onRefresh(t);e?.expiresAt&&e.authToken&&e.expiresAt!==t.expiresAt?(this.consecutiveFailures=0,this.setSession(e),this.emit("sessionRefreshed",e)):(this.consecutiveFailures++,Date.now()>=t.expiresAt?this.emit("sessionExpired",t):this.scheduleRetry(t))}catch(e){this.consecutiveFailures++,Date.now()>=t.expiresAt?this.emit("sessionExpired",t):this.scheduleRetry(t)}else Date.now()>=t.expiresAt&&this.emit("sessionExpired",t)},i)}}class s{constructor(t){if(this.session=null,this.pendingNonce=null,this.overlayEl=null,this._iframeEl=null,this.overlayCleanup=null,this.events={},this._cachedVaultInfo=null,this._visitorId=null,!t?.appId)throw new Error("appId is required");if(this.config={...t,authUrl:t.authUrl??"https://auth.emblemvault.ai",apiUrl:t.apiUrl??"https://api.emblemvault.ai",persistSession:t.persistSession??!0},this.storageKey=`emblem_session_${t.appId}`,this.visitorIdKey=`emblem_visitorId_${t.appId}`,this.messageHandler=this.onMessage.bind(this),"undefined"!=typeof window&&window.addEventListener("message",this.messageHandler),this.sessionMgr=new e({onRefresh:async t=>{try{return await this.refreshSession()||t}catch{return t}}}),this.sessionMgr.on("sessionExpired",t=>this.emit("sessionExpired",t)),this.sessionMgr.on("sessionRefreshed",t=>this.emit("sessionRefreshed",t)),this.sessionMgr.on("sessionWillRefresh",t=>this.emit("sessionWillRefresh",t)),this.config.persistSession){const t=this.loadPersistedSession();t&&this.hydrateSession(t),this._visitorId=this.loadPersistedVisitorId()}this.tryConsumeSessionFromHash()}tryConsumeSessionFromHash(){if("undefined"!=typeof window)try{const t=String(window.location.hash||"").replace(/^#/,"");if(!t)return;const e=new URLSearchParams(t).get("emblemAuthSession");if(!e)return;const s=decodeURIComponent(e),i=decodeURIComponent(escape(atob(s))),n=JSON.parse(i);if(n?.appId&&n.appId!==this.config.appId)return void this.authDebug("consumeHash:ignored (appId mismatch)",{expected:this.config.appId,received:n.appId});this.authDebug("consumeHash:accepted",{appId:n?.appId}),this.session=n,this.persistSession(n),this.sessionMgr.setSession(n),this.config.onSuccess?.(n),this.emit("session",n);try{window.history.replaceState(null,"",window.location.pathname+window.location.search)}catch{}}catch(t){this.authDebug("consumeHash:failed",{error:t?.message||String(t)})}}async authenticateWallet(t){const{network:e,message:s,signature:i,publicKey:n,address:r}=t;if(!this.config.apiUrl)throw new Error("apiUrl is required for authenticateWallet");if(!e||!s||!i)throw new Error("network, message, signature are required");const a=`${this.config.apiUrl.replace(/\/$/,"")}/api/auth/wallet/verify-external`,o=await fetch(a,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({appId:this.config.appId,network:e,message:s,signature:i,publicKey:n,address:r})});if(!o.ok){const t=await this.safeJson(o),e=new Error(t?.error||`wallet_verify_${o.status}`);throw e.status=o.status,e.payload=t,e}const c=await o.json(),h=c?.session;return h&&(this.session=h,this.persistSession(h),this.sessionMgr.setSession(h),this.config.onSuccess?.(h),this.emit("session",h)),h}async openOAuth(t){if("undefined"==typeof window)throw new Error("openOAuth() must be called in a browser environment");const e=window.location.origin;this.authDebug("openOAuth:start",{provider:t,origin:e,apiUrl:this.config.apiUrl});const s=await this.getAuthInit({origin:e}),i=s?.nonce||this.randomId(),n=s?.state;this.pendingNonce=i,this.authDebug("openOAuth:init ok",{noncePrefix:String(i).slice(0,8),hasState:!!n,statePrefix:String(n||"").slice(0,16)});const r=this.normalizeBaseUrl(this.config.authUrl,"authUrl"),a=new URL(`${r}/api/auth/oauth/init`);a.searchParams.set("provider",t),a.searchParams.set("state",n),this.authDebug("openOAuth:navigate",{url:a.toString()});const o=window.open(a.toString(),"emblem-auth",this.popupFeatures());if(o)try{o.focus()}catch{}else try{this.authDebug("openOAuth:popup blocked, using same-window navigation"),window.location.assign(a.toString())}catch{const t=new Error("Popup blocked. Please allow popups for this site.");this.emitError(t)}}async sendEmailOtp(t){const e=this.config.apiUrl.replace(/\/$/,""),s=await fetch(`${e}/api/auth/email/send-otp`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({appId:t.appId??this.config.appId,email:t.email,password:t.password})}),i=await s.json().catch(()=>null);if(!s.ok){const t=new Error(i?.error||`email_send_otp_${s.status}`);throw t.status=s.status,t.payload=i,t}return i}async verifyEmailOtp(t){const e=this.config.apiUrl.replace(/\/$/,""),s=await fetch(`${e}/api/auth/email/verify-otp`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({appId:t.appId??this.config.appId,email:t.email,otp:t.otp,password:t.password})}),i=await s.json().catch(()=>null);if(!s.ok){const t=new Error(i?.error||`email_verify_otp_${s.status}`);throw t.status=s.status,t.payload=i,t}const n=i?.session;return n&&(this.session=n,this.persistSession(n),this.sessionMgr.setSession(n),this.emit("session",n)),n}async authenticateEmail(t){const e=this.config.apiUrl.replace(/\/$/,""),s=await fetch(`${e}/api/auth/email/login`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({appId:t.appId??this.config.appId,email:t.email,password:t.password})}),i=await s.json().catch(()=>null);if(!s.ok){const t=new Error(i?.error||`email_login_${s.status}`);throw t.status=s.status,t.payload=i,t}const n=i?.session;return n&&(this.session=n,this.persistSession(n),this.sessionMgr.setSession(n),this.emit("session",n)),n}async authenticatePassword(t){const e=this.config.authUrl.replace(/\/$/,""),s=await fetch(`${e}/api/auth/password/verify`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({appId:this.config.appId,password:t.password})}),i=await s.json().catch(()=>null);if(!s.ok){const t=new Error(i?.error||`password_verify_${s.status}`);throw t.status=s.status,t.payload=i,t}const n=i?.session;return n&&(this.session=n,this.persistSession(n),this.sessionMgr.setSession(n),this.emit("session",n)),n}async openAuthModal(){const t=window.location.origin;let e=null,s=null;try{e=await this.getAuthInit({origin:t})}catch(t){s=t}const i=e?.nonce||this.randomId();this.pendingNonce=i;let n=this.resolveModalUrl({nonce:i,origin:t,state:e?.state});if("origin_not_allowed"===s?.payload?.error)try{const e=new URL("/connect",this.config.authUrl);e.searchParams.set("error","origin_not_allowed"),e.searchParams.set("appId",this.config.appId),e.searchParams.set("origin",t),n=e.toString()}catch{}const r=this.config.modalMode||"auto";let a=!1;if("iframe"===r||"auto"===r)try{a=this.openIframeModal(n)}catch(t){}if(!a){const t=this.popupFeatures();if(!window.open(n,"emblem-auth",t)){const t=new Error("Popup blocked. Please allow popups for this site.");this.emitError(t)}}}getSession(){return this.session}getVisitorId(){return this._visitorId}async refreshSession(){try{if(!this.session)return null;const t=this.tryGetOriginFromConfig();if(!t)return this.session;const e=`${t}/api/auth/refresh`,s=Boolean(this.session.refreshToken),i=await fetch(e,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(s?{refreshToken:this.session.refreshToken}:{}),credentials:"include"});if(!i.ok)return this.session;const n=await i.json(),r=n?.session;return r&&(this.session=r,this.persistSession(r),this.sessionMgr.setSession(r),this.emit("session",r)),this.session}catch{return this.session}}async getVaultInfo(){if(this._cachedVaultInfo)return this._cachedVaultInfo;const t=this.getSession();if(!t?.authToken)throw new Error("No session");if(!this.config.apiUrl)throw new Error("apiUrl is required");const e=this.config.apiUrl.replace(/\/$/,""),s=await fetch(`${e}/vault/info`,{method:"POST",headers:{Authorization:`Bearer ${t.authToken}`,"Content-Type":"application/json"},body:"{}"});if(!s.ok)throw new Error("Failed to fetch vault info");const i=await s.json(),n={...i,tokenId:i.tokenId||i.vaultId,solanaAddress:i.solanaAddress||i.address};return this._cachedVaultInfo=n,n}async getVaultApiKey(){if(!this.config.apiUrl)throw new Error("apiUrl is required");const t=this.getSession();if(!t?.authToken)throw new Error("No active session");const e=this.config.apiUrl.replace(/\/$/,""),s=t.authToken,i=t.user?.vaultId;let n=null;try{const t=await fetch(`${e}/vault/info-complete`,{method:"POST",headers:{Authorization:`Bearer ${s}`}});if(t.ok){const e=await t.json();n=e?.raw?.pkp?.api_key_hash||e?.raw?.pkp?.apiKeyHash||null}}catch{}if(!n)try{const s=t.appId,r=t.user?.identifier||"",a=s?`${s}:${r}`:r;if(a){const t=await fetch(`${e}/api/vaults/${encodeURIComponent(a)}`);if(t.ok){const e=await t.json(),s=Array.isArray(e)?e.find(t=>String(t.tokenId||t.token_id)===String(i))||e[0]:null;n=s?.api_key_hash||s?.apiKeyHash||null}}}catch{}if(!n){const t=await fetch(`${e}/api/vaults/${encodeURIComponent(i)}/api-key`,{method:"POST",headers:{Authorization:`Bearer ${s}`}});if(!t.ok)throw new Error(`gen_key_${t.status}`);const n=await t.json(),r=n?.apiKey||n?.key||null;if(!r)throw new Error("missing_apiKey");return r}const r=await fetch(`${e}/decrypt`,{method:"POST",headers:{Authorization:`Bearer ${s}`,"Content-Type":"application/json"},body:JSON.stringify({tokenId:i,dataToEncryptHash:n})});if(!r.ok)throw new Error(`decrypt_${r.status}`);const a=await r.json(),o=a?.decryptedString||null;if(!o)throw new Error("missing_decrypted");return o}hydrateSession(t){t?.authToken&&(this.session=t,this.persistSession(t),this._cachedVaultInfo=null,this.sessionMgr.setSession(t),this.emit("session",t))}logout(){this.session=null,this.persistSession(null),this._visitorId=null,this.persistVisitorId(null),this._cachedVaultInfo=null,this.sessionMgr.clear(),this.emit("session",null)}on(t,e){this.events[t]||(this.events[t]=[]),this.events[t].push(e)}off(t,e){const s=this.events[t];if(s){const t=s.indexOf(e);-1!==t&&s.splice(t,1)}}async getSignerContext(){const t=this.getSession();if(!t?.authToken)throw new Error("No active session. Call openAuthModal() or authenticateWallet() first.");const e=await this.getVaultInfo();return{config:{baseUrl:this.config.apiUrl,getJwt:()=>this.getSession()?.authToken},vaultInfo:{vaultId:e.vaultId,evmAddress:e.evmAddress||"0x",address:e.solanaAddress||e.address||"",tokenId:e.tokenId,created_by:e.created_by}}}async toViemAccount(){const{toViemAccount:t}=await Promise.resolve().then(function(){return h}),{config:e,vaultInfo:s}=await this.getSignerContext();return t(e,s)}async toEthersWallet(t){const{toEthersWallet:e}=await Promise.resolve().then(function(){return u}),{config:s,vaultInfo:i}=await this.getSignerContext();return e(s,t,i)}async toWeb3Adapter(){const{toWeb3Adapter:t}=await Promise.resolve().then(function(){return y}),{config:e,vaultInfo:s}=await this.getSignerContext();return t(e,s)}async toSolanaWeb3Signer(){const{toSolanaWeb3Signer:t}=await Promise.resolve().then(function(){return m}),{config:e,vaultInfo:s}=await this.getSignerContext();return t(e,s)}async toSolanaKitSigner(){const{toSolanaKitSigner:t}=await Promise.resolve().then(function(){return m}),{config:e,vaultInfo:s}=await this.getSignerContext();return t(e,s)}async toBitcoinSigner(){const{toBitcoinSigner:t,fetchBitcoinVaultInfo:e}=await Promise.resolve().then(function(){return E}),{config:s}=await this.getSignerContext();return t(s,await e(s))}destroy(){"undefined"!=typeof window&&window.removeEventListener("message",this.messageHandler),this.sessionMgr.destroy(),this.closeOverlay(),Object.keys(this.events).forEach(t=>{delete this.events[t]})}resolveModalUrl(t){const e=`${this.config.authUrl.replace(/\/$/,"")}/connect`,s=new URL(e,window.location.href);return s.searchParams.set("appId",this.config.appId),s.searchParams.set("origin",t.origin),s.searchParams.set("nonce",t.nonce),t.state&&s.searchParams.set("state",t.state),s.toString()}authDebugEnabled(){try{const t=window?.localStorage?.getItem?.("AUTH_DEBUG");if("true"===String(t).toLowerCase())return!0}catch{}try{const t="undefined"!=typeof process?process:null,e=t?.env||{},s=e.NEXT_PUBLIC_AUTH_DEBUG??e.AUTH_DEBUG;if(!s)return!1;const i=String(s).toLowerCase().trim();return"1"===i||"true"===i||"yes"===i||"on"===i}catch{return!1}}authDebug(...t){this.authDebugEnabled()}normalizeBaseUrl(t,e){if(!t)throw new Error(`${e} is required`);const s=String(t).trim(),i="undefined"!=typeof window?window.location.href:"http://localhost";try{return new URL(s,i).toString().replace(/\/$/,"")}catch{}try{return new URL(`https://${s.replace(/^\/+/,"")}`).toString().replace(/\/$/,"")}catch{}throw new Error(`${e} must be an absolute URL (e.g. "https://api.emblemvault.ai") or a relative path (e.g. "/")`)}onMessage(t){try{const e=new Set([window.location.origin,this.tryGetOriginFromConfig(),this.tryGetOriginFromApiUrl()].filter(Boolean));if(!e.has(t.origin))return void this.authDebug("onMessage:ignored (origin)",{eventOrigin:t.origin,allowedOrigins:Array.from(e)});const s=t.data;if("emblem-auth-cancelled"===s?.type){if(!this.pendingNonce||s.nonce!==this.pendingNonce)return;return this.pendingNonce=null,this.closeOverlay(),this.config.onCancel&&this.config.onCancel(),void this.emit("cancelled",void 0)}if("emblem-auth-success"!==s?.type)return;if(!this.pendingNonce||s.nonce!==this.pendingNonce)return void this.authDebug("onMessage:ignored (nonce)",{expected:this.pendingNonce,received:s?.nonce,origin:t.origin,type:s?.type});this.pendingNonce=null,this.authDebug("onMessage:accepted",{origin:t.origin});const i=s.session;this.session=i,this.persistSession(i),this.sessionMgr.setSession(i),s.visitorId&&(this._visitorId=s.visitorId,this.persistVisitorId(s.visitorId)),i&&this.config.onSuccess&&this.config.onSuccess(i),this.emit("session",i),this.closeOverlay()}catch(t){this.emitError(t)}}emit(t,e){const s=this.events[t];if(s)for(const t of s)try{t(e)}catch(t){}}emitError(t){this.config.onError?.(t),this.emit("authError",t)}popupFeatures(){const t=Math.max(0,(window.outerHeight-680)/2);return`popup=yes,width=520,height=680,left=${Math.max(0,(window.outerWidth-520)/2)},top=${t}`}randomId(){const t=new Uint8Array(16);if(window.crypto?.getRandomValues)window.crypto.getRandomValues(t);else for(let e=0;e<t.length;e++)t[e]=Math.floor(256*Math.random());return Array.from(t,t=>t.toString(16).padStart(2,"0")).join("")}tryGetOriginFromConfig(){try{if(!this.config.authUrl)return null;const t=this.normalizeBaseUrl(this.config.authUrl,"authUrl");return new URL(t).origin}catch{return null}}tryGetOriginFromApiUrl(){try{if(!this.config.apiUrl)return null;const t=this.normalizeBaseUrl(this.config.apiUrl,"apiUrl");return new URL(t).origin}catch{return null}}async getAuthInit(t){const e=JSON.stringify({appId:this.config.appId,origin:t.origin}),s=async t=>{const s=await fetch(`${t.replace(/\/$/,"")}/api/auth/init`,{method:"POST",headers:{"Content-Type":"application/json"},body:e}),i=await s.json().catch(()=>null);if(!s.ok){const t=new Error(`init ${s.status}`);throw t.status=s.status,t.payload=i||{},t}return i};try{return await s(this.config.authUrl)}catch(t){const e=t;try{return await s(this.config.apiUrl)}catch(t){const s=e;throw s.payload={...e?.payload||{},fallback:t?.payload||void 0},s}}}openIframeModal(t){this.overlayEl&&this.closeOverlay();const e=document.createElement("div");e.setAttribute("data-emblem-overlay",""),e.style.position="fixed",e.style.inset="0",e.style.background="rgba(0,0,0,0.55)",e.style.backdropFilter="blur(6px)",e.style.webkitBackdropFilter="blur(6px)",e.style.zIndex="999999",e.style.display="flex",e.style.alignItems="center",e.style.justifyContent="center",e.style.padding="12px";const s=document.createElement("div");s.style.width="min(520px, 96vw)",s.style.height="min(680px, 92vh)",s.style.background="#12161b",s.style.border="1px solid #222b35",s.style.borderRadius="12px",s.style.boxShadow="0 12px 48px rgba(0,0,0,0.7)",s.style.overflow="hidden",s.style.position="relative",s.style.display="flex",s.style.flexDirection="column";const i=document.createElement("div");i.style.height="52px",i.style.display="flex",i.style.alignItems="center",i.style.justifyContent="space-between",i.style.padding="0 12px",i.style.borderBottom="1px solid rgba(255, 255, 255, 0.06)",i.style.background="#12161b";const n=document.createElement("div");n.textContent="Emblem",n.style.fontFamily="ui-sans-serif, system-ui, -apple-system, Segoe UI, Roboto, Helvetica, Arial",n.style.fontSize="13px",n.style.letterSpacing="0.08em",n.style.textTransform="uppercase",n.style.color="rgba(230, 238, 248, 0.75)";const r=document.createElement("button");r.type="button",r.textContent="×",r.setAttribute("aria-label","Close"),r.setAttribute("title","Close"),r.style.width="40px",r.style.height="40px",r.style.display="flex",r.style.alignItems="center",r.style.justifyContent="center",r.style.background="rgba(255, 255, 255, 0.04)",r.style.color="#e6eef8",r.style.border="1px solid rgba(255, 255, 255, 0.08)",r.style.borderRadius="10px",r.style.fontSize="24px",r.style.lineHeight="1",r.style.cursor="pointer",r.style.userSelect="none",r.onclick=()=>this.cancelAuth(),i.appendChild(n),i.appendChild(r);const a=document.createElement("iframe");a.src=t,a.style.width="100%",a.style.height="100%",a.style.border="0",a.referrerPolicy="no-referrer",a.allow="clipboard-read; clipboard-write;",s.appendChild(i),s.appendChild(a),e.appendChild(s),document.body.appendChild(e),e.addEventListener("click",t=>{t.target===e&&this.cancelAuth()});const o=t=>{"Escape"===t.key&&this.cancelAuth()};return document.addEventListener("keydown",o,{capture:!0}),this.overlayEl=e,this._iframeEl=a,this.overlayCleanup=()=>{document.removeEventListener("keydown",o,{capture:!0})},!0}closeOverlay(){try{this.overlayCleanup?.()}catch{}this.overlayCleanup=null,this.overlayEl?.parentNode&&this.overlayEl.parentNode.removeChild(this.overlayEl),this.overlayEl=null,this._iframeEl=null}cancelAuth(){this.pendingNonce=null,this.closeOverlay(),this.config.onCancel&&this.config.onCancel(),this.emit("cancelled",void 0)}async safeJson(t){try{return await t.json()}catch{return null}}loadPersistedSession(){try{if("undefined"==typeof localStorage)return null;const t=localStorage.getItem(this.storageKey);if(!t)return null;const e=JSON.parse(t);return e?.authToken&&e?.expiresAt?Date.now()>=e.expiresAt?(localStorage.removeItem(this.storageKey),null):e:null}catch{return null}}persistSession(t){try{if("undefined"==typeof localStorage)return;t&&this.config.persistSession?localStorage.setItem(this.storageKey,JSON.stringify(t)):localStorage.removeItem(this.storageKey)}catch{}}loadPersistedVisitorId(){try{return"undefined"==typeof localStorage?null:localStorage.getItem(this.visitorIdKey)}catch{return null}}persistVisitorId(t){try{if("undefined"==typeof localStorage)return;t&&this.config.persistSession?localStorage.setItem(this.visitorIdKey,t):localStorage.removeItem(this.visitorIdKey)}catch{}}}async function i(t,e,s){const i=s.baseUrl??"https://api.emblemvault.ai",n=await async function(t){if("function"==typeof t.getAuthHeaders){const e=await t.getAuthHeaders();if(e&&"object"==typeof e)return e}const e=t.jwt??("function"==typeof t.getJwt?await t.getJwt():void 0)??t.sdk?.getSession()?.authToken??void 0;if(e)return{Authorization:`Bearer ${e}`};if(t.apiKey)return{"x-api-key":t.apiKey};throw new Error("No authentication available: provide jwt, getJwt(), getAuthHeaders(), sdk, or apiKey")}(s),r=await fetch(`${i}${t}`,{method:"POST",headers:{"content-type":"application/json",...n},body:JSON.stringify(e,(t,e)=>"bigint"==typeof e?e.toString():e)});if(!r.ok){const t=await r.text().catch(()=>"");throw new Error(function(t,e){let s=`Emblem signer error ${t}`;return t>=500?s+=": Internal server error":401===t||403===t?s+=": Authentication failed":404===t?s+=": Resource not found":405===t?s+=": Method not allowed":e&&(s+=`: ${e.substring(0,200)}`),s}(r.status,t))}return r.json()}function n(t,e){const s=Number(t);if(!Number.isSafeInteger(s))throw new Error(`${e} value ${t} exceeds safe integer range (max: ${Number.MAX_SAFE_INTEGER})`);return s}function r(t){return"bigint"==typeof t?"0x"+t.toString(16):t}function a(t){const e={...t};return void 0!==e.value&&(e.value=r(e.value)),void 0!==e.gas&&(e.gasLimit=r(e.gas),delete e.gas),void 0!==e.gasLimit&&(e.gasLimit=r(e.gasLimit)),void 0!==e.gasPrice&&(e.gasPrice=r(e.gasPrice)),void 0!==e.maxFeePerGas&&(e.maxFeePerGas=r(e.maxFeePerGas)),void 0!==e.maxPriorityFeePerGas&&(e.maxPriorityFeePerGas=r(e.maxPriorityFeePerGas)),void 0!==e.nonce&&(e.nonce=n(e.nonce,"nonce")),void 0!==e.chainId&&(e.chainId=n(e.chainId,"chainId")),void 0===e.maxFeePerGas&&void 0===e.maxPriorityFeePerGas||(void 0===e.gasPrice&&void 0!==e.maxFeePerGas&&(e.gasPrice=e.maxFeePerGas),delete e.maxFeePerGas,delete e.maxPriorityFeePerGas),delete e.type,delete e.accessList,delete e.account,delete e.chain,delete e.from,e}function o(t){let e="0x";for(let s=0;s<t.length;s++)e+=t[s].toString(16).padStart(2,"0");return e}async function c(t){const e=await i("/vault/info",{},t);if(!e||!e.vaultId||!e.evmAddress)throw new Error("Invalid vault info response: missing required fields");if(!String(e.evmAddress).startsWith("0x"))throw new Error("Invalid evmAddress format in response");return{vaultId:e.vaultId,tokenId:e.vaultId,address:e.address||"",evmAddress:e.evmAddress,created_by:e.created_by}}var h=Object.freeze({__proto__:null,toViemAccount:async function(t,e){const s=e??await c(t),{evmAddress:n,vaultId:r}=s,{toAccount:h}=await import("viem/accounts");return h({address:n,async signMessage({message:e}){let s,n=!1;if("string"==typeof e)s=e,n=!1;else if(e&&void 0!==e.raw){const t=e.raw;s="string"==typeof t?t:o(t),n=!0}else if(e instanceof Uint8Array)s=o(e),n=!1;else{if("string"!=typeof(a=e)||!/^0x[0-9a-fA-F]*$/.test(a))throw new Error(`Unsupported message type: ${typeof e}. Expected string, Uint8Array, or hex string.`);s=e,n=!1}var a;return(await i("/sign-eth-message",{vaultId:r,message:s,raw:n},t)).signature},async signTypedData(e){const{domain:s,types:n,message:a}=e;return(await i("/sign-typed-message",{vaultId:r,domain:s,types:n,message:a},t)).signature},async signTransaction(e,s){const n=a(e);return(await i("/sign-eth-tx",{vaultId:r,transaction:n},t)).signedTransaction}})}});var l,d,u=Object.freeze({__proto__:null,toEthersWallet:async function(t,e,s){let n;try{const t="ethers";n=await import(t)}catch{throw new Error("ethers is required for toEthersWallet(). Install it with: npm install ethers")}const{AbstractSigner:r,resolveAddress:h}=n,l=s??await c(t);class d extends r{constructor(t,e,s){super(e??null),this._address=null,this._vaultId=null,this._chainId=1,this._config=t,s?.address&&(this._address=s.address),s?.vaultId&&(this._vaultId=s.vaultId),s?.chainId&&(this._chainId=s.chainId)}async initialize(){return this._initPromise||(this._initPromise=c(this._config).then(t=>{this._address=t.evmAddress,this._vaultId=t.vaultId}).catch(t=>{throw this._initPromise=void 0,t})),this._initPromise}async getAddress(){return this._address||await this.initialize(),this._address}getVaultId(){if(!this._vaultId)throw new Error("Wallet not initialized. Call initialize() first.");return this._vaultId}setChainId(t){this._chainId=t}getChainId(){return this._chainId}connect(t){if(!t)throw new Error("Provider cannot be null");return new d(this._config,t,{address:this._address??void 0,vaultId:this._vaultId??void 0,chainId:this._chainId})}async signMessage(t){this._vaultId||await this.initialize();const e="string"==typeof t?t:o(t);return(await i("/sign-eth-message",{vaultId:this._vaultId,message:e},this._config)).signature}async signTypedData(t,e,s){this._vaultId||await this.initialize();const n={...e};n&&n.EIP712Domain&&delete n.EIP712Domain;return(await i("/sign-typed-message",{vaultId:this._vaultId,domain:t,types:n,message:s},this._config)).signature}async _signTypedData(t,e,s){return this.signTypedData(t,e,s)}async signTransaction(t){this._vaultId||await this.initialize();const e=t.from,s=await this.getAddress();if(e&&e.toLowerCase()!==s.toLowerCase())throw new Error("transaction from does not match signer address");const n=this.provider?{...await this.populateTransaction(t)}:{...t};if(n.from&&delete n.from,!("to"in n)||!n.to)throw new Error("Transaction must have a 'to' address");if(void 0===n.nonce||null===n.nonce)throw new Error("Transaction must have a nonce");const r=a(n);return(await i("/sign-eth-tx",{vaultId:this._vaultId,transaction:r,options:{chainId:this._chainId}},this._config)).signedTransaction}async sendTransaction(t){if(!this.provider)throw new Error("Provider required to send transaction");const e=await this.signTransaction(t);return await this.provider.broadcastTransaction(e)}async populateTransaction(t){const e={...t};if(!this.provider)throw new Error("Provider required to populate transaction");const s=e.from?await h(e.from,this.provider):await this.getAddress();let i;if(e.chainId)i=BigInt(e.chainId),this._chainId=Number(e.chainId);else{const t=await this.provider.getNetwork();i=t.chainId,this._chainId=Number(t.chainId)}const n=null!=e.nonce?Number(e.nonce):await this.provider.getTransactionCount(s,"pending"),r=e.to?await h(e.to,this.provider):null,a=e.value?BigInt(e.value.toString()):0n;let o;if(e.gasLimit)o=BigInt(e.gasLimit.toString());else try{o=await this.provider.estimateGas({...e,from:s})}catch{o=21000n}let c=null;if(e.gasPrice||2===e.type)e.gasPrice&&(c=BigInt(e.gasPrice.toString()));else{c=(await this.provider.getFeeData()).gasPrice??null}const l={from:s,to:r,value:a,nonce:n,gasLimit:o,data:e.data,chainId:i,type:e.type||void 0};return null!==c&&(l.gasPrice=c),e.maxFeePerGas&&(l.maxFeePerGas=BigInt(e.maxFeePerGas.toString())),e.maxPriorityFeePerGas&&(l.maxPriorityFeePerGas=BigInt(e.maxPriorityFeePerGas.toString())),l}async signAndBroadcast(t,e=!1){if(!this.provider)throw new Error("Provider required to send transaction");const s=await this.signTransaction(t),i=(await this.provider.broadcastTransaction(s)).hash;return e&&await this.provider.waitForTransaction(i),i}}return new d(t,e,{address:l.evmAddress,vaultId:l.vaultId})}});function p(t,e,s,i){if("a"===s&&!i)throw new TypeError("Private accessor was defined without a getter");if("function"==typeof e?t!==e||!i:!e.has(t))throw new TypeError("Cannot read private member from an object whose class did not declare it");return"m"===s?i:"a"===s?i.call(t):i?i.value:e.get(t)}function f(t,e,s,i,n){if("m"===i)throw new TypeError("Private method is not writable");if("a"===i&&!n)throw new TypeError("Private accessor was defined without a setter");if("function"==typeof e?t!==e||!n:!e.has(t))throw new TypeError("Cannot write private member to an object whose class did not declare it");return"a"===i?n.call(t,s):n?n.value=s:e.set(t,s),s}"function"==typeof SuppressedError&&SuppressedError;class g{constructor(t,e,s){l.set(this,void 0),d.set(this,void 0),this.address=t,f(this,l,e,"f"),f(this,d,s,"f")}async signMessage(t){const e="string"==typeof t?t:o(t);return(await i("/sign-eth-message",{vaultId:p(this,l,"f"),message:e},p(this,d,"f"))).signature}async signTypedData(t,e,s){return(await i("/sign-typed-message",{vaultId:p(this,l,"f"),domain:t,types:e,message:s},p(this,d,"f"))).signature}async signTransaction(t){const e=a(t);return{rawTransaction:(await i("/sign-eth-tx",{vaultId:p(this,l,"f"),transaction:e},p(this,d,"f"))).signedTransaction}}}l=new WeakMap,d=new WeakMap;var y=Object.freeze({__proto__:null,EmblemWeb3Adapter:g,toWeb3Adapter:async function(t,e){const s=e??await c(t);return new g(s.evmAddress,s.vaultId,t)}});class w{constructor(t,e){this.publicKey=e.address,this.config=t,this.vaultId=e.vaultId}async signMessage(t){const e="string"==typeof t?(new TextEncoder).encode(t):t,s=btoa(String.fromCharCode(...e)),n=await i("/sign-solana-message",{vaultId:this.vaultId,message:s},this.config);try{const t="undefined"!=typeof window?window:void 0;if(t?.bs58)return t.bs58.decode(n.signature);return Uint8Array.from(atob(n.signature),t=>t.charCodeAt(0))}catch(t){if(n.signature.startsWith("0x")){const t=n.signature.slice(2),e=new Uint8Array(t.length/2);for(let s=0;s<t.length;s+=2)e[s/2]=parseInt(t.substr(s,2),16);return e}throw new Error(`Unable to decode signature format: ${t}`)}}async signTransaction(t){const e=this.serializeTransaction(t),s=await i("/sign-solana-transaction",{vaultId:this.vaultId,transactionToSign:e,broadcast:!1,versionedTransaction:!0},this.config),n=s.serializedSignedTransaction||s.signedTransaction;if(!n)throw new Error("No signed transaction data received from server");return this.deserializeTransaction(n)}serializeTransaction(t){if(t&&"object"==typeof t){if(t.serialize){const e=t.serialize();return btoa(String.fromCharCode(...e))}if(t.instructions||t.recentBlockhash)throw new Error("Cannot serialize unsigned transaction objects. Please use VersionedTransaction.")}return t}deserializeTransaction(t){if("object"==typeof t&&t&&t.serializedSignedTransaction&&(t=t.serializedSignedTransaction),"string"==typeof t)try{const e=atob(t);return new Uint8Array(e.split("").map(t=>t.charCodeAt(0)))}catch(t){throw new Error(`Unable to deserialize transaction response: ${t}`)}return t}getVaultId(){return this.vaultId}async signAllTransactions(t){const e=[];for(const s of t)e.push(await this.signTransaction(s));return e}canSign(t){return t===this.publicKey}async signAndBroadcast(t,e=!0){const s=this.serializeTransaction(t),n=await i("/sign-solana-transaction",{vaultId:this.vaultId,transactionToSign:s,broadcast:e,versionedTransaction:!0},this.config);if(e){if(!n.transactionSignature)throw new Error("No transaction signature received from broadcast");return n.transactionSignature}if(!n.serializedSignedTransaction)throw new Error("No signed transaction data received from server");return n.serializedSignedTransaction}}var m=Object.freeze({__proto__:null,EmblemSolanaSigner:w,toSolanaWeb3Signer:async function(t,e){const s=e??await c(t);return new w(t,s)},toSolanaKitSigner:async function(t,e){const s=e??await c(t);return new w(t,s)}});const v=1e8;class I{constructor(t,e){if(!e.btcPubkey)throw new Error("Bitcoin public key is required in vault info");this.publicKey=e.btcPubkey,this.addresses=e.btcAddresses??{p2pkh:"",p2wpkh:"",p2tr:""},this.config=t,this.vaultId=e.vaultId}async signPsbt(t,e){const{transactionType:s,toSignInputs:n}=e,r=n?.map(t=>({...t,tapLeafHashToSign:this.normalizeToHex(t.tapLeafHashToSign)}));return await i("/sign-btc-transaction",{vaultId:this.vaultId,psbt:t,transactionType:s,toSignInputs:r},this.config)}async signAllPsbts(t){const e=[];for(const{psbt:s,options:i}of t)e.push(await this.signPsbt(s,i));return e}getVaultId(){return this.vaultId}getPublicKey(){return this.publicKey}ownsAddress(t){return t===this.addresses.p2pkh||t===this.addresses.p2wpkh||t===this.addresses.p2tr}getAddress(t="p2wpkh"){switch(t){case"p2pkh":return this.addresses.p2pkh;case"p2wpkh":case"p2sh":default:return this.addresses.p2wpkh;case"p2tr":return this.addresses.p2tr}}normalizeToHex(t){if(null==t)return;if("string"==typeof t)return t;const e=t;let s="";for(let t=0;t<e.length;t++)s+=e[t].toString(16).padStart(2,"0");return s}}async function b(t){const e=await i("/vault/info",{},t);if(!e||!e.vaultId)throw new Error("Invalid vault info response: missing vaultId");if(!e.btcPubkey)throw new Error("Invalid vault info response: missing btcPubkey (Bitcoin public key)");return{vaultId:e.vaultId,address:e.address||"",evmAddress:e.evmAddress||"0x",btcPubkey:e.btcPubkey,btcAddresses:e.btcAddresses,created_by:e.created_by}}function S(t){return t/v}var E=Object.freeze({__proto__:null,SATS_PER_BTC:v,EmblemBitcoinSigner:I,toBitcoinSigner:async function(t,e){const s=e??await b(t);return new I(t,s)},fetchBitcoinVaultInfo:b,detectAddressType:function(t){return t.startsWith("bc1p")?"p2tr":t.startsWith("bc1q")?"p2wpkh":t.startsWith("1")?"p2pkh":t.startsWith("3")?"p2sh":t.startsWith("tb1p")?"p2tr":t.startsWith("tb1q")?"p2wpkh":t.startsWith("m")||t.startsWith("n")?"p2pkh":t.startsWith("2")?"p2sh":"unknown"},satsToBTC:S,btcToSats:function(t){return Math.round(t*v)},formatSats:function(t){return`${t.toLocaleString()} sats (${S(t).toFixed(8)} BTC)`},estimateTransactionSize:function(t,e,s="p2wpkh"){let i;switch(s){case"p2pkh":i=148;break;case"p2tr":i=58;break;default:i=68}return 10+t*i+31*e},calculateFee:function(t,e){return Math.ceil(t*e)},isDust:function(t,e="p2wpkh"){return t<("p2wpkh"===e||"p2tr"===e?294:546)}});t.EmblemAuthSDK=s,t.SessionManager=e,t.default=s,Object.defineProperty(t,"__esModule",{value:!0})});
|
|
2
2
|
//# sourceMappingURL=emblem-auth.min.js.map
|