@markee_team/sdk 0.1.0-alpha.20 → 0.1.0-alpha.21

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -154,6 +154,8 @@ Theme changes update styles in place: drafts, focus, scroll, wallet sessions, an
154
154
 
155
155
  Color tokens: `background`, `surface`, `text`, `muted`, `border`, `inputBackground`, `inputText`, `primary`, `primaryText`, `accent`, `accentText`, `accentSurface`, `accentSurfaceText`, `accentBorder`, `selected`, `selectedText`, `info`, `infoText`, `error`, `errorText`, `success`, `successText`, `link`, `focusRing`, and `overlay`. Set foreground/background pairs together and check your brand's contrast in both modes. Overrides apply over either selected palette; omitted values use that palette's defaults. Invalid CSS color/font values fall back to defaults.
156
156
 
157
+ To match an app completely, override `link`, `focusRing`, `border`, `selected`/`selectedText`, and the accent colors as well as the primary button colors. Otherwise those elements retain the SDK palette. Use the typed theme options; arbitrary custom CSS is not currently supported. The sign’s price badge appears on hover or keyboard focus, and stays visible on touch devices.
158
+
157
159
  Styles are scoped to the modal's Shadow DOM and do not change the host app or its wallet picker. The ConnectKit sample includes light, dark, device, and custom Plum presets.
158
160
 
159
161
  ## Headless API
@@ -173,6 +175,14 @@ For Sale supports create/fund/edit. New message ownership belongs to the caller.
173
175
 
174
176
  For Rent supports message creation, starting/updating/switching/stopping a stream, wrap/unwrap, pool connection/refunds, board-buffer recovery, ranking refresh and settlement. The server builds the complete Superfluid batch, including exact ETHx approval and pool connection. Wallet runway uses the combined CFA and GDA net flow across the wallet, not only the current board. Rental MARKEE comes from actual settled rent, never merely from wrapping or depositing ETH.
175
177
 
178
+ Payment reviews remain visible while the wallet requests confirmation, including network switches. If a review expires when confirming, the modal shows **Refreshing payment details…**, prepares an updated review, and requires another confirmation click. It never automatically sends the refreshed transaction.
179
+
180
+ For Sale reviews are disabled when the entered payment exceeds the loaded ETH balance; the balance uses the error color and the button explains the shortfall. The API also checks network fees before wallet confirmation.
181
+
182
+ For Rent reviews show estimated **MARKEE/month while winning**, using the selected monthly stream rate and current on-chain reward settings. The estimate is not based on the ETH deposit and is not guaranteed; if quoting is unavailable, the modal shows a qualitative reward description. Rental transaction details contain only Network, Recipient, and Wallet; fees stay in the payment summary.
183
+
184
+ Refunds flow automatically when connected to the message’s refund pool. **Collect refund** appears only when the loaded wallet snapshot reports a positive claimable balance for that message’s pool. Board-buffer recovery is separate. Community revenue actions are accessed through **Community accumulated revenue**.
185
+
176
186
  Community activation supports the current council Safe, a current Safe owner, or the configured authorized keeper. Revenue claims support the current Safe or its current owners and always pay the council treasury. Existing outbound Across, Squid and LI.FI routing lives on Markee's server.
177
187
 
178
188
  ## Integration boundaries
@@ -187,7 +197,13 @@ Backend configuration and API reference: [`docs/sdk/implementation.md`](https://
187
197
 
188
198
  ## API endpoint
189
199
 
190
- No API URL or Markee API key is required. The SDK connects to the Markee-hosted API and centralizes on-chain reads, metadata, and transaction preparation. For local development or testing, pass an optional `apiUrl` override to `createMarkee`, `MarkeeClient`, or the React modal. The endpoint used by your installed release is exported as `DEFAULT_MARKEE_API_URL`.
200
+ No API URL or Markee API key is required. The SDK default is:
201
+
202
+ ```text
203
+ https://staging.markee.xyz/api/sdk/v1
204
+ ```
205
+
206
+ Markee hosts this API and centralizes on-chain reads, metadata, and transaction preparation. Staging does not imply test funds: Base placements use real funds. For local development or testing, pass an optional `apiUrl` override to `createMarkee`, `MarkeeClient`, or the React modal. The endpoint used by your installed release is exported as `DEFAULT_MARKEE_API_URL`.
191
207
 
192
208
  ## LLM implementation prompt
193
209
 
@@ -220,8 +236,9 @@ Ask only the remaining unanswered requirements in one concise group:
220
236
  Markee-hosted card checkout without an app wallet (For Sale on Base only)? Inspect
221
237
  existing connectors first; do not add a second wallet context or install a new
222
238
  connector without agreement.
223
- - Should the modal match the app theme or use specific colors, font, radius, and
224
- light/dark/system mode?
239
+ - Should the modal match the app theme or use specific colors, font, panel/card/
240
+ control radii, and light/dark/system mode? Include links, focus rings, borders,
241
+ and selected states when matching the host palette.
225
242
  - What public domain/page will host this integration? Use it as siteUrl for
226
243
  automatic verification. For Vite/client rendering, add the board marker to the
227
244
  static HTML as documented; do not claim localhost is verified.
@@ -244,7 +261,8 @@ Then implement the agreed scope:
244
261
  Otherwise omit wallet. Without a connected app account, the modal shows only
245
262
  Pay, opening Markee-hosted checkout for supported boards. Do not install
246
263
  Privy or collect card details in the host app.
247
- 5. Apply theme options while preserving the built-in modal layout. Handle onEvent
264
+ 5. Apply theme options (including radius, cardRadius, and controlRadius) while
265
+ preserving the built-in modal layout. Handle onEvent
248
266
  if needed; show success only for a confirmed event. Let the SDK manage review,
249
267
  network switching, submission, and verification.
250
268
  6. Verify build/types, loading of the supplied board, automatic strategy selection,
package/dist/client.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import type { Action, Address, AdminOperation, AdminResult, Authorization, BridgeStatus, ClaimQuote, EIP1193Provider, Hex, Placement, PreparedAction, SDKOptions, Snapshot, SiteVerification, TransactionResult } from './types.js';
2
2
  /** Markee-hosted API used by integrations unless overridden for local development. */
3
- export declare const DEFAULT_MARKEE_API_URL = "https://2staging.markee.xyz/api/sdk/v1";
3
+ export declare const DEFAULT_MARKEE_API_URL = "https://staging.markee.xyz/api/sdk/v1";
4
4
  export declare class MarkeeError extends Error {
5
5
  code: string;
6
6
  status?: number | undefined;
package/dist/index.js CHANGED
@@ -1,4 +1,4 @@
1
- var U="https://2staging.markee.xyz/api/sdk/v1",p=class extends Error{constructor(t,n="MARKEE_ERROR",a){super(t);this.code=n;this.status=a;this.name="MarkeeError"}};async function J(){if(typeof window>"u")return[];let r=new Map,e=n=>{let a=n.detail;a?.provider?.request&&typeof a.info?.uuid=="string"&&r.set(a.info.uuid,{uuid:a.info.uuid,name:String(a.info.name).slice(0,80),provider:a.provider})};window.addEventListener("eip6963:announceProvider",e),window.dispatchEvent(new Event("eip6963:requestProvider")),await new Promise(n=>setTimeout(n,150)),window.removeEventListener("eip6963:announceProvider",e);let t=window.ethereum;return!r.size&&t?.request&&r.set("injected",{uuid:"injected",name:"Browser wallet",provider:t}),[...r.values()]}var x=r=>typeof r=="string"&&/^0x[\da-f]{40}$/i.test(r),z=r=>typeof r=="string"&&/^0x[\da-f]{64}$/i.test(r),T=class{constructor(e={}){this.options=e;let t=new URL(e.apiUrl??U);if(t.protocol!=="https:"&&!(t.protocol==="http:"&&["localhost","127.0.0.1","[::1]"].includes(t.hostname)))throw new p("Use an HTTPS Markee API URL (HTTP is allowed on localhost).");this.apiUrl=t.href.replace(/\/$/,""),this.fetcher=e.fetch||globalThis.fetch.bind(globalThis)}apiUrl;fetcher;injected=null;sending=!1;inMemoryPending=[];adminMemory=null;communityReceipts={};async request(e,t,n){let a=await this.fetcher(`${this.apiUrl}/${e}`,{method:t===void 0?"GET":"POST",body:t===void 0?void 0:JSON.stringify(t),headers:t===void 0?void 0:{"Content-Type":"application/json"},credentials:"omit",signal:n||AbortSignal.timeout(55e3)}),i=await a.json().catch(()=>null);if(!a.ok)throw new p(i?.error||`Markee returned HTTP ${a.status}.`,i?.code,a.status);return i}async provider(){return this.options.wallet?this.options.wallet.getProvider():this.injected}async account(){let e=await this.provider();if(!e)return null;let t=await e.request({method:"eth_accounts"});return Array.isArray(t)&&x(t[0])?t[0]:null}async connect(e){let t=await this.provider();if(this.options.wallet)t||(t=await this.options.wallet.connect?.()||null);else{if(t=e||t,!t){let a=await J();if(a.length>1)throw new p("Select a browser wallet.","SELECT_WALLET");t=a[0]?.provider||null}this.injected=t}if(!t)throw new p("Connect a wallet in the app or install a browser wallet to continue.","NO_WALLET");let n=await t.request({method:"eth_requestAccounts"});if(!Array.isArray(n)||!x(n[0]))throw new p("The wallet did not return an account.");return n[0]}verifySite(e,t){return this.request("sites/verify",{placement:e,siteUrl:t})}siteRequests=new Map;registerSite(e){if(!this.options.siteUrl)return;let t=JSON.stringify([e,this.options.siteUrl]);if(this.siteRequests.has(t))return;let n=this.verifySite(e,this.options.siteUrl);this.siteRequests.set(t,n),n.then(a=>this.options.onSiteVerification?.(a),a=>this.options.onSiteVerification?.({verified:!1,url:this.options.siteUrl,message:a instanceof Error?a.message:"Site verification failed."})).catch(()=>{})}async snapshot(e,t,n,a){let i=new URLSearchParams({placement:JSON.stringify(e)});return t&&i.set("account",t),n!==void 0&&i.set("offset",String(n)),this.request(`snapshot?${i}`,void 0,a)}async prepare(e,t){let n=await this.account();if(!n)throw new p("Connect your wallet first.","NOT_CONNECTED");return this.request("prepare",{placement:e,account:n,action:t})}async ensureWallet(e,t){let n=await this.provider();if(!n||(await this.account())?.toLowerCase()!==e.toLowerCase())throw new p("Your wallet account changed. Review this action again.","ACCOUNT_CHANGED");let a=Number(await n.request({method:"eth_chainId"}));if(a!==t&&await n.request({method:"wallet_switchEthereumChain",params:[{chainId:`0x${t.toString(16)}`}]}),a=Number(await n.request({method:"eth_chainId"})),a!==t||(await this.account())?.toLowerCase()!==e.toLowerCase())throw new p("The wallet account or network changed. Review again.","WALLET_CHANGED");return n}async send(e){if(this.sending)throw new p("A wallet request is already in progress.");if(e.expiresAt<=Date.now())throw new p("This review expired. Prepare the action again.","REVIEW_EXPIRED");if(this.pending(e.placement,e.transaction.from))throw new p("A transaction is still pending for this wallet and placement. Check it before submitting again.","PENDING_TRANSACTION");this.sending=!0;try{let n=await this.ensureWallet(e.transaction.from,e.transaction.chainId);if(e.expiresAt<=Date.now())throw new p("This review expired. Prepare the action again.","REVIEW_EXPIRED");let{chainId:a,...i}=e.transaction,s=await n.request({method:"eth_sendTransaction",params:[i]});if(!z(s))throw new p("The wallet returned an unexpected transaction identifier. Check your wallet before retrying.");return this.persist([...this.records(),{preparation:e,hash:s}]),this.options.onEvent?.({type:"submitted",hash:s}),s}catch(n){throw this.options.onEvent?.({type:"error",message:n instanceof Error?n.message:String(n)}),n}finally{this.sending=!1}}async verify(e){let t=await this.request("verify",{id:e.preparation.id,hash:e.hash});return t.status!=="pending"&&(this.persist(this.records().filter(n=>n.hash!==e.hash)),t.status==="confirmed"&&this.options.onEvent?.({type:"confirmed",hash:t.hash})),t}async reconcile(e,t){if(!z(t))throw new p("Enter a valid replacement transaction hash.");let n=await this.request("verify",{id:e.preparation.id,hash:t});return n.status!=="pending"&&this.persist(this.records().filter(a=>a.hash!==e.hash)),n}storageKey(){return`markee:sdk:v1:pending:${this.apiUrl}`}records(){try{if(typeof localStorage>"u")return this.inMemoryPending;let e=JSON.parse(localStorage.getItem(this.storageKey())||"[]");return Array.isArray(e)?e.filter(t=>z(t?.hash)&&typeof t.preparation?.id=="string"&&x(t.preparation?.transaction?.from)&&t.preparation?.placement):[]}catch{return this.inMemoryPending}}persist(e){this.inMemoryPending=e;try{typeof localStorage<"u"&&localStorage.setItem(this.storageKey(),JSON.stringify(e))}catch{}}pending(e,t){return this.records().find(n=>JSON.stringify(n.preparation.placement).toLowerCase()===JSON.stringify(e).toLowerCase()&&n.preparation.transaction.from.toLowerCase()===t.toLowerCase())}async quote(e){return this.request(`community/quote?${new URLSearchParams({chainId:String(e.chainId),community:e.community})}`)}async authorize(e,t){let n=await this.account();if(!n)throw new p("Connect your community council wallet first.");return this.request(`community/${t}`,{action:"challenge",chainId:e.chainId,community:e.community,account:n})}async executeAuthorization(e,t,n){if(this.pendingAuthorization())throw new p("An earlier community authorization is still processing. Check its status first.");let a=t.typedData,s=await(await this.ensureWallet(n,a.domain.chainId)).request({method:"eth_signTypedData_v4",params:[n,JSON.stringify({...a,types:{...a.types,EIP712Domain:[{name:"name",type:"string"},{name:"version",type:"string"},{name:"chainId",type:"uint256"},{name:"verifyingContract",type:"address"}]}})]});if(typeof s!="string"||!/^0x[\da-f]+$/i.test(s))throw new p("Wallet did not return a typed-data signature.");return this.saveAuthorization({kind:e,nonce:t.nonce,signature:s,account:n,community:a.domain.verifyingContract,chainId:a.domain.chainId}),this.resumeAuthorization()}pendingAuthorization(){try{let e=typeof localStorage>"u"?this.adminMemory:JSON.parse(localStorage.getItem(`${this.storageKey()}:admin`)||"null");return e&&["activate","claim"].includes(e.kind)&&x(e.account)&&x(e.community)&&typeof e.nonce=="string"&&typeof e.signature=="string"?e:null}catch{return this.adminMemory}}saveAuthorization(e){this.adminMemory=e;try{typeof localStorage<"u"&&localStorage.setItem(`${this.storageKey()}:admin`,JSON.stringify(e))}catch{}}async resumeAuthorization(){let e=this.pendingAuthorization();if(!e)throw new p("There is no pending community authorization.");let t=await this.request(`community/${e.kind}`,{action:"verify",nonce:e.nonce,signature:e.signature});if(t.status==="complete"&&t.result){let n=`${e.chainId}:${e.community.toLowerCase()}`;this.communityReceipts[n]=t.result;try{typeof localStorage<"u"&&localStorage.setItem(`${this.storageKey()}:community:${n}`,JSON.stringify(t.result))}catch{}}return(t.status==="complete"||t.status==="failed")&&this.saveAuthorization(null),t}communityReceipt(e){let t=`${e.chainId}:${e.community.toLowerCase()}`;try{let n=typeof localStorage>"u"?this.communityReceipts[t]:JSON.parse(localStorage.getItem(`${this.storageKey()}:community:${t}`)||"null");return n&&z(n.transactionHash)?n:null}catch{return this.communityReceipts[t]||null}}bridgeStatus(e,t,n,a){return this.request(`community/status?${new URLSearchParams({protocol:e,transactionHash:t,fromChainId:String(n),toChainId:String(a)})}`)}recordView(e,t,n){return this.request("views",{address:e,message:t,url:n})}};var Q=(r,e)=>`markee:checkout:v1:${r.apiUrl}:${JSON.stringify(e)}`;function R(r,e){try{let t=JSON.parse(localStorage.getItem(Q(r,e))||"null");return t&&typeof t.id=="string"&&/^[a-f0-9]{48}$/.test(t.id)&&/^[a-f0-9]{64}$/.test(t.readToken)&&/^[a-f0-9]{64}$/.test(t.writeToken)&&Number.isFinite(t.expiresAt)?t:null}catch{return null}}async function N(r,e){return r.request("checkout/status",{id:e.id,token:e.readToken})}function C(r,e){try{localStorage.removeItem(Q(r,e))}catch{}}async function Z(r,e,t){let n=r.options.checkoutWindow==="redirect"?null:window.open("about:blank","_blank");n&&(n.opener=null);let a=R(r,e);try{if(a){let s=await N(r,a).catch(o=>{if(o instanceof p&&o.status===404)return C(r,e),a=null,null;throw o});if(s?.result?.status==="confirmed"||s?.result?.status==="reverted")return C(r,e),n?.close(),s.result;a&&s&&a.expiresAt<Date.now()&&["created","ready"].includes(s.status)&&(C(r,e),a=null)}if(!a){a=await r.request("checkout/create",{placement:e,action:t,origin:window.location.origin});try{localStorage.setItem(Q(r,e),JSON.stringify(a))}catch{}}let i=new URL(`/checkout/${a.id}`,a.checkoutOrigin||r.apiUrl);if(i.protocol!=="https:"&&!(i.protocol==="http:"&&["localhost","127.0.0.1"].includes(i.hostname)))throw new Error("Invalid Markee checkout destination.");if(i.hash=new URLSearchParams({token:a.writeToken}).toString(),n)n.location.replace(i.href);else throw window.location.assign(i.href),new Error("Continuing payment on Markee.");for(let s=0;s<1800;s++){let o=await N(r,a);if(o.result&&o.status==="confirmed")return C(r,e),n.close(),o.result;if(o.status==="reverted")throw C(r,e),new Error("Payment reverted. Any unspent funds remain in your Markee wallet.");if(n.closed)throw new Error("Markee checkout closed. Choose Pay again to resume; funding alone does not complete payment.");await new Promise(A=>setTimeout(A,3e3))}throw new Error("Checkout is still pending. Reopen it to check the payment; do not pay again.")}catch(i){throw a||n?.close(),i}}function y(r,e=!1){let t=r.trim();if(!/^\d+(\.\d{0,18})?$/.test(t))throw new Error("Enter an ETH amount with up to 18 decimal places.");let[n,a=""]=t.split("."),i=BigInt(n)*10n**18n+BigInt(a.padEnd(18,"0"));if(!e&&i===0n||i>=2n**256n)throw new Error("Enter a positive amount.");return i.toString()}function l(r,e=6){let t=BigInt(r),n=t<0n?"-":"",a=t<0n?-t:t,i=(a%10n**18n).toString().padStart(18,"0").slice(0,e).replace(/0+$/,"");return a>0n&&a<10n**BigInt(18-e)?`${n}<0.${"0".repeat(e-1)}1`:`${n}${a/10n**18n}${i?`.${i}`:""}`}function E(r){return`${r.slice(0,6)}\u2026${r.slice(-4)}`}function d(r){return String(r).replace(/[&<>"']/g,e=>({"&":"&amp;","<":"&lt;",">":"&gt;",'"':"&quot;","'":"&#39;"})[e])}var F=`
1
+ var U="https://staging.markee.xyz/api/sdk/v1",p=class extends Error{constructor(t,n="MARKEE_ERROR",a){super(t);this.code=n;this.status=a;this.name="MarkeeError"}};async function J(){if(typeof window>"u")return[];let r=new Map,e=n=>{let a=n.detail;a?.provider?.request&&typeof a.info?.uuid=="string"&&r.set(a.info.uuid,{uuid:a.info.uuid,name:String(a.info.name).slice(0,80),provider:a.provider})};window.addEventListener("eip6963:announceProvider",e),window.dispatchEvent(new Event("eip6963:requestProvider")),await new Promise(n=>setTimeout(n,150)),window.removeEventListener("eip6963:announceProvider",e);let t=window.ethereum;return!r.size&&t?.request&&r.set("injected",{uuid:"injected",name:"Browser wallet",provider:t}),[...r.values()]}var x=r=>typeof r=="string"&&/^0x[\da-f]{40}$/i.test(r),z=r=>typeof r=="string"&&/^0x[\da-f]{64}$/i.test(r),T=class{constructor(e={}){this.options=e;let t=new URL(e.apiUrl??U);if(t.protocol!=="https:"&&!(t.protocol==="http:"&&["localhost","127.0.0.1","[::1]"].includes(t.hostname)))throw new p("Use an HTTPS Markee API URL (HTTP is allowed on localhost).");this.apiUrl=t.href.replace(/\/$/,""),this.fetcher=e.fetch||globalThis.fetch.bind(globalThis)}apiUrl;fetcher;injected=null;sending=!1;inMemoryPending=[];adminMemory=null;communityReceipts={};async request(e,t,n){let a=await this.fetcher(`${this.apiUrl}/${e}`,{method:t===void 0?"GET":"POST",body:t===void 0?void 0:JSON.stringify(t),headers:t===void 0?void 0:{"Content-Type":"application/json"},credentials:"omit",signal:n||AbortSignal.timeout(55e3)}),i=await a.json().catch(()=>null);if(!a.ok)throw new p(i?.error||`Markee returned HTTP ${a.status}.`,i?.code,a.status);return i}async provider(){return this.options.wallet?this.options.wallet.getProvider():this.injected}async account(){let e=await this.provider();if(!e)return null;let t=await e.request({method:"eth_accounts"});return Array.isArray(t)&&x(t[0])?t[0]:null}async connect(e){let t=await this.provider();if(this.options.wallet)t||(t=await this.options.wallet.connect?.()||null);else{if(t=e||t,!t){let a=await J();if(a.length>1)throw new p("Select a browser wallet.","SELECT_WALLET");t=a[0]?.provider||null}this.injected=t}if(!t)throw new p("Connect a wallet in the app or install a browser wallet to continue.","NO_WALLET");let n=await t.request({method:"eth_requestAccounts"});if(!Array.isArray(n)||!x(n[0]))throw new p("The wallet did not return an account.");return n[0]}verifySite(e,t){return this.request("sites/verify",{placement:e,siteUrl:t})}siteRequests=new Map;registerSite(e){if(!this.options.siteUrl)return;let t=JSON.stringify([e,this.options.siteUrl]);if(this.siteRequests.has(t))return;let n=this.verifySite(e,this.options.siteUrl);this.siteRequests.set(t,n),n.then(a=>this.options.onSiteVerification?.(a),a=>this.options.onSiteVerification?.({verified:!1,url:this.options.siteUrl,message:a instanceof Error?a.message:"Site verification failed."})).catch(()=>{})}async snapshot(e,t,n,a){let i=new URLSearchParams({placement:JSON.stringify(e)});return t&&i.set("account",t),n!==void 0&&i.set("offset",String(n)),this.request(`snapshot?${i}`,void 0,a)}async prepare(e,t){let n=await this.account();if(!n)throw new p("Connect your wallet first.","NOT_CONNECTED");return this.request("prepare",{placement:e,account:n,action:t})}async ensureWallet(e,t){let n=await this.provider();if(!n||(await this.account())?.toLowerCase()!==e.toLowerCase())throw new p("Your wallet account changed. Review this action again.","ACCOUNT_CHANGED");let a=Number(await n.request({method:"eth_chainId"}));if(a!==t&&await n.request({method:"wallet_switchEthereumChain",params:[{chainId:`0x${t.toString(16)}`}]}),a=Number(await n.request({method:"eth_chainId"})),a!==t||(await this.account())?.toLowerCase()!==e.toLowerCase())throw new p("The wallet account or network changed. Review again.","WALLET_CHANGED");return n}async send(e){if(this.sending)throw new p("A wallet request is already in progress.");if(e.expiresAt<=Date.now())throw new p("This review expired. Prepare the action again.","REVIEW_EXPIRED");if(this.pending(e.placement,e.transaction.from))throw new p("A transaction is still pending for this wallet and placement. Check it before submitting again.","PENDING_TRANSACTION");this.sending=!0;try{let n=await this.ensureWallet(e.transaction.from,e.transaction.chainId);if(e.expiresAt<=Date.now())throw new p("This review expired. Prepare the action again.","REVIEW_EXPIRED");let{chainId:a,...i}=e.transaction,s=await n.request({method:"eth_sendTransaction",params:[i]});if(!z(s))throw new p("The wallet returned an unexpected transaction identifier. Check your wallet before retrying.");return this.persist([...this.records(),{preparation:e,hash:s}]),this.options.onEvent?.({type:"submitted",hash:s}),s}catch(n){throw this.options.onEvent?.({type:"error",message:n instanceof Error?n.message:String(n)}),n}finally{this.sending=!1}}async verify(e){let t=await this.request("verify",{id:e.preparation.id,hash:e.hash});return t.status!=="pending"&&(this.persist(this.records().filter(n=>n.hash!==e.hash)),t.status==="confirmed"&&this.options.onEvent?.({type:"confirmed",hash:t.hash})),t}async reconcile(e,t){if(!z(t))throw new p("Enter a valid replacement transaction hash.");let n=await this.request("verify",{id:e.preparation.id,hash:t});return n.status!=="pending"&&this.persist(this.records().filter(a=>a.hash!==e.hash)),n}storageKey(){return`markee:sdk:v1:pending:${this.apiUrl}`}records(){try{if(typeof localStorage>"u")return this.inMemoryPending;let e=JSON.parse(localStorage.getItem(this.storageKey())||"[]");return Array.isArray(e)?e.filter(t=>z(t?.hash)&&typeof t.preparation?.id=="string"&&x(t.preparation?.transaction?.from)&&t.preparation?.placement):[]}catch{return this.inMemoryPending}}persist(e){this.inMemoryPending=e;try{typeof localStorage<"u"&&localStorage.setItem(this.storageKey(),JSON.stringify(e))}catch{}}pending(e,t){return this.records().find(n=>JSON.stringify(n.preparation.placement).toLowerCase()===JSON.stringify(e).toLowerCase()&&n.preparation.transaction.from.toLowerCase()===t.toLowerCase())}async quote(e){return this.request(`community/quote?${new URLSearchParams({chainId:String(e.chainId),community:e.community})}`)}async authorize(e,t){let n=await this.account();if(!n)throw new p("Connect your community council wallet first.");return this.request(`community/${t}`,{action:"challenge",chainId:e.chainId,community:e.community,account:n})}async executeAuthorization(e,t,n){if(this.pendingAuthorization())throw new p("An earlier community authorization is still processing. Check its status first.");let a=t.typedData,s=await(await this.ensureWallet(n,a.domain.chainId)).request({method:"eth_signTypedData_v4",params:[n,JSON.stringify({...a,types:{...a.types,EIP712Domain:[{name:"name",type:"string"},{name:"version",type:"string"},{name:"chainId",type:"uint256"},{name:"verifyingContract",type:"address"}]}})]});if(typeof s!="string"||!/^0x[\da-f]+$/i.test(s))throw new p("Wallet did not return a typed-data signature.");return this.saveAuthorization({kind:e,nonce:t.nonce,signature:s,account:n,community:a.domain.verifyingContract,chainId:a.domain.chainId}),this.resumeAuthorization()}pendingAuthorization(){try{let e=typeof localStorage>"u"?this.adminMemory:JSON.parse(localStorage.getItem(`${this.storageKey()}:admin`)||"null");return e&&["activate","claim"].includes(e.kind)&&x(e.account)&&x(e.community)&&typeof e.nonce=="string"&&typeof e.signature=="string"?e:null}catch{return this.adminMemory}}saveAuthorization(e){this.adminMemory=e;try{typeof localStorage<"u"&&localStorage.setItem(`${this.storageKey()}:admin`,JSON.stringify(e))}catch{}}async resumeAuthorization(){let e=this.pendingAuthorization();if(!e)throw new p("There is no pending community authorization.");let t=await this.request(`community/${e.kind}`,{action:"verify",nonce:e.nonce,signature:e.signature});if(t.status==="complete"&&t.result){let n=`${e.chainId}:${e.community.toLowerCase()}`;this.communityReceipts[n]=t.result;try{typeof localStorage<"u"&&localStorage.setItem(`${this.storageKey()}:community:${n}`,JSON.stringify(t.result))}catch{}}return(t.status==="complete"||t.status==="failed")&&this.saveAuthorization(null),t}communityReceipt(e){let t=`${e.chainId}:${e.community.toLowerCase()}`;try{let n=typeof localStorage>"u"?this.communityReceipts[t]:JSON.parse(localStorage.getItem(`${this.storageKey()}:community:${t}`)||"null");return n&&z(n.transactionHash)?n:null}catch{return this.communityReceipts[t]||null}}bridgeStatus(e,t,n,a){return this.request(`community/status?${new URLSearchParams({protocol:e,transactionHash:t,fromChainId:String(n),toChainId:String(a)})}`)}recordView(e,t,n){return this.request("views",{address:e,message:t,url:n})}};var Q=(r,e)=>`markee:checkout:v1:${r.apiUrl}:${JSON.stringify(e)}`;function R(r,e){try{let t=JSON.parse(localStorage.getItem(Q(r,e))||"null");return t&&typeof t.id=="string"&&/^[a-f0-9]{48}$/.test(t.id)&&/^[a-f0-9]{64}$/.test(t.readToken)&&/^[a-f0-9]{64}$/.test(t.writeToken)&&Number.isFinite(t.expiresAt)?t:null}catch{return null}}async function N(r,e){return r.request("checkout/status",{id:e.id,token:e.readToken})}function C(r,e){try{localStorage.removeItem(Q(r,e))}catch{}}async function Z(r,e,t){let n=r.options.checkoutWindow==="redirect"?null:window.open("about:blank","_blank");n&&(n.opener=null);let a=R(r,e);try{if(a){let s=await N(r,a).catch(o=>{if(o instanceof p&&o.status===404)return C(r,e),a=null,null;throw o});if(s?.result?.status==="confirmed"||s?.result?.status==="reverted")return C(r,e),n?.close(),s.result;a&&s&&a.expiresAt<Date.now()&&["created","ready"].includes(s.status)&&(C(r,e),a=null)}if(!a){a=await r.request("checkout/create",{placement:e,action:t,origin:window.location.origin});try{localStorage.setItem(Q(r,e),JSON.stringify(a))}catch{}}let i=new URL(`/checkout/${a.id}`,a.checkoutOrigin||r.apiUrl);if(i.protocol!=="https:"&&!(i.protocol==="http:"&&["localhost","127.0.0.1"].includes(i.hostname)))throw new Error("Invalid Markee checkout destination.");if(i.hash=new URLSearchParams({token:a.writeToken}).toString(),n)n.location.replace(i.href);else throw window.location.assign(i.href),new Error("Continuing payment on Markee.");for(let s=0;s<1800;s++){let o=await N(r,a);if(o.result&&o.status==="confirmed")return C(r,e),n.close(),o.result;if(o.status==="reverted")throw C(r,e),new Error("Payment reverted. Any unspent funds remain in your Markee wallet.");if(n.closed)throw new Error("Markee checkout closed. Choose Pay again to resume; funding alone does not complete payment.");await new Promise(A=>setTimeout(A,3e3))}throw new Error("Checkout is still pending. Reopen it to check the payment; do not pay again.")}catch(i){throw a||n?.close(),i}}function y(r,e=!1){let t=r.trim();if(!/^\d+(\.\d{0,18})?$/.test(t))throw new Error("Enter an ETH amount with up to 18 decimal places.");let[n,a=""]=t.split("."),i=BigInt(n)*10n**18n+BigInt(a.padEnd(18,"0"));if(!e&&i===0n||i>=2n**256n)throw new Error("Enter a positive amount.");return i.toString()}function l(r,e=6){let t=BigInt(r),n=t<0n?"-":"",a=t<0n?-t:t,i=(a%10n**18n).toString().padStart(18,"0").slice(0,e).replace(/0+$/,"");return a>0n&&a<10n**BigInt(18-e)?`${n}<0.${"0".repeat(e-1)}1`:`${n}${a/10n**18n}${i?`.${i}`:""}`}function E(r){return`${r.slice(0,6)}\u2026${r.slice(-4)}`}function d(r){return String(r).replace(/[&<>"']/g,e=>({"&":"&amp;","<":"&lt;",">":"&gt;",'"':"&quot;","'":"&#39;"})[e])}var F=`
2
2
  :host{all:initial;font-family:var(--markee-font-family);color:var(--markee-text);font-size:14px;line-height:1.5;color-scheme:var(--markee-color-scheme)}
3
3
 
4
4
  *{box-sizing:border-box}
package/dist/react.js CHANGED
@@ -1,4 +1,4 @@
1
- "use client";import{createElement as N,useEffect as z,useRef as J}from"react";var _="https://2staging.markee.xyz/api/sdk/v1",p=class extends Error{constructor(t,n="MARKEE_ERROR",a){super(t);this.code=n;this.status=a;this.name="MarkeeError"}};async function Z(){if(typeof window>"u")return[];let r=new Map,e=n=>{let a=n.detail;a?.provider?.request&&typeof a.info?.uuid=="string"&&r.set(a.info.uuid,{uuid:a.info.uuid,name:String(a.info.name).slice(0,80),provider:a.provider})};window.addEventListener("eip6963:announceProvider",e),window.dispatchEvent(new Event("eip6963:requestProvider")),await new Promise(n=>setTimeout(n,150)),window.removeEventListener("eip6963:announceProvider",e);let t=window.ethereum;return!r.size&&t?.request&&r.set("injected",{uuid:"injected",name:"Browser wallet",provider:t}),[...r.values()]}var x=r=>typeof r=="string"&&/^0x[\da-f]{40}$/i.test(r),B=r=>typeof r=="string"&&/^0x[\da-f]{64}$/i.test(r),y=class{constructor(e={}){this.options=e;let t=new URL(e.apiUrl??_);if(t.protocol!=="https:"&&!(t.protocol==="http:"&&["localhost","127.0.0.1","[::1]"].includes(t.hostname)))throw new p("Use an HTTPS Markee API URL (HTTP is allowed on localhost).");this.apiUrl=t.href.replace(/\/$/,""),this.fetcher=e.fetch||globalThis.fetch.bind(globalThis)}apiUrl;fetcher;injected=null;sending=!1;inMemoryPending=[];adminMemory=null;communityReceipts={};async request(e,t,n){let a=await this.fetcher(`${this.apiUrl}/${e}`,{method:t===void 0?"GET":"POST",body:t===void 0?void 0:JSON.stringify(t),headers:t===void 0?void 0:{"Content-Type":"application/json"},credentials:"omit",signal:n||AbortSignal.timeout(55e3)}),i=await a.json().catch(()=>null);if(!a.ok)throw new p(i?.error||`Markee returned HTTP ${a.status}.`,i?.code,a.status);return i}async provider(){return this.options.wallet?this.options.wallet.getProvider():this.injected}async account(){let e=await this.provider();if(!e)return null;let t=await e.request({method:"eth_accounts"});return Array.isArray(t)&&x(t[0])?t[0]:null}async connect(e){let t=await this.provider();if(this.options.wallet)t||(t=await this.options.wallet.connect?.()||null);else{if(t=e||t,!t){let a=await Z();if(a.length>1)throw new p("Select a browser wallet.","SELECT_WALLET");t=a[0]?.provider||null}this.injected=t}if(!t)throw new p("Connect a wallet in the app or install a browser wallet to continue.","NO_WALLET");let n=await t.request({method:"eth_requestAccounts"});if(!Array.isArray(n)||!x(n[0]))throw new p("The wallet did not return an account.");return n[0]}verifySite(e,t){return this.request("sites/verify",{placement:e,siteUrl:t})}siteRequests=new Map;registerSite(e){if(!this.options.siteUrl)return;let t=JSON.stringify([e,this.options.siteUrl]);if(this.siteRequests.has(t))return;let n=this.verifySite(e,this.options.siteUrl);this.siteRequests.set(t,n),n.then(a=>this.options.onSiteVerification?.(a),a=>this.options.onSiteVerification?.({verified:!1,url:this.options.siteUrl,message:a instanceof Error?a.message:"Site verification failed."})).catch(()=>{})}async snapshot(e,t,n,a){let i=new URLSearchParams({placement:JSON.stringify(e)});return t&&i.set("account",t),n!==void 0&&i.set("offset",String(n)),this.request(`snapshot?${i}`,void 0,a)}async prepare(e,t){let n=await this.account();if(!n)throw new p("Connect your wallet first.","NOT_CONNECTED");return this.request("prepare",{placement:e,account:n,action:t})}async ensureWallet(e,t){let n=await this.provider();if(!n||(await this.account())?.toLowerCase()!==e.toLowerCase())throw new p("Your wallet account changed. Review this action again.","ACCOUNT_CHANGED");let a=Number(await n.request({method:"eth_chainId"}));if(a!==t&&await n.request({method:"wallet_switchEthereumChain",params:[{chainId:`0x${t.toString(16)}`}]}),a=Number(await n.request({method:"eth_chainId"})),a!==t||(await this.account())?.toLowerCase()!==e.toLowerCase())throw new p("The wallet account or network changed. Review again.","WALLET_CHANGED");return n}async send(e){if(this.sending)throw new p("A wallet request is already in progress.");if(e.expiresAt<=Date.now())throw new p("This review expired. Prepare the action again.","REVIEW_EXPIRED");if(this.pending(e.placement,e.transaction.from))throw new p("A transaction is still pending for this wallet and placement. Check it before submitting again.","PENDING_TRANSACTION");this.sending=!0;try{let n=await this.ensureWallet(e.transaction.from,e.transaction.chainId);if(e.expiresAt<=Date.now())throw new p("This review expired. Prepare the action again.","REVIEW_EXPIRED");let{chainId:a,...i}=e.transaction,s=await n.request({method:"eth_sendTransaction",params:[i]});if(!B(s))throw new p("The wallet returned an unexpected transaction identifier. Check your wallet before retrying.");return this.persist([...this.records(),{preparation:e,hash:s}]),this.options.onEvent?.({type:"submitted",hash:s}),s}catch(n){throw this.options.onEvent?.({type:"error",message:n instanceof Error?n.message:String(n)}),n}finally{this.sending=!1}}async verify(e){let t=await this.request("verify",{id:e.preparation.id,hash:e.hash});return t.status!=="pending"&&(this.persist(this.records().filter(n=>n.hash!==e.hash)),t.status==="confirmed"&&this.options.onEvent?.({type:"confirmed",hash:t.hash})),t}async reconcile(e,t){if(!B(t))throw new p("Enter a valid replacement transaction hash.");let n=await this.request("verify",{id:e.preparation.id,hash:t});return n.status!=="pending"&&this.persist(this.records().filter(a=>a.hash!==e.hash)),n}storageKey(){return`markee:sdk:v1:pending:${this.apiUrl}`}records(){try{if(typeof localStorage>"u")return this.inMemoryPending;let e=JSON.parse(localStorage.getItem(this.storageKey())||"[]");return Array.isArray(e)?e.filter(t=>B(t?.hash)&&typeof t.preparation?.id=="string"&&x(t.preparation?.transaction?.from)&&t.preparation?.placement):[]}catch{return this.inMemoryPending}}persist(e){this.inMemoryPending=e;try{typeof localStorage<"u"&&localStorage.setItem(this.storageKey(),JSON.stringify(e))}catch{}}pending(e,t){return this.records().find(n=>JSON.stringify(n.preparation.placement).toLowerCase()===JSON.stringify(e).toLowerCase()&&n.preparation.transaction.from.toLowerCase()===t.toLowerCase())}async quote(e){return this.request(`community/quote?${new URLSearchParams({chainId:String(e.chainId),community:e.community})}`)}async authorize(e,t){let n=await this.account();if(!n)throw new p("Connect your community council wallet first.");return this.request(`community/${t}`,{action:"challenge",chainId:e.chainId,community:e.community,account:n})}async executeAuthorization(e,t,n){if(this.pendingAuthorization())throw new p("An earlier community authorization is still processing. Check its status first.");let a=t.typedData,s=await(await this.ensureWallet(n,a.domain.chainId)).request({method:"eth_signTypedData_v4",params:[n,JSON.stringify({...a,types:{...a.types,EIP712Domain:[{name:"name",type:"string"},{name:"version",type:"string"},{name:"chainId",type:"uint256"},{name:"verifyingContract",type:"address"}]}})]});if(typeof s!="string"||!/^0x[\da-f]+$/i.test(s))throw new p("Wallet did not return a typed-data signature.");return this.saveAuthorization({kind:e,nonce:t.nonce,signature:s,account:n,community:a.domain.verifyingContract,chainId:a.domain.chainId}),this.resumeAuthorization()}pendingAuthorization(){try{let e=typeof localStorage>"u"?this.adminMemory:JSON.parse(localStorage.getItem(`${this.storageKey()}:admin`)||"null");return e&&["activate","claim"].includes(e.kind)&&x(e.account)&&x(e.community)&&typeof e.nonce=="string"&&typeof e.signature=="string"?e:null}catch{return this.adminMemory}}saveAuthorization(e){this.adminMemory=e;try{typeof localStorage<"u"&&localStorage.setItem(`${this.storageKey()}:admin`,JSON.stringify(e))}catch{}}async resumeAuthorization(){let e=this.pendingAuthorization();if(!e)throw new p("There is no pending community authorization.");let t=await this.request(`community/${e.kind}`,{action:"verify",nonce:e.nonce,signature:e.signature});if(t.status==="complete"&&t.result){let n=`${e.chainId}:${e.community.toLowerCase()}`;this.communityReceipts[n]=t.result;try{typeof localStorage<"u"&&localStorage.setItem(`${this.storageKey()}:community:${n}`,JSON.stringify(t.result))}catch{}}return(t.status==="complete"||t.status==="failed")&&this.saveAuthorization(null),t}communityReceipt(e){let t=`${e.chainId}:${e.community.toLowerCase()}`;try{let n=typeof localStorage>"u"?this.communityReceipts[t]:JSON.parse(localStorage.getItem(`${this.storageKey()}:community:${t}`)||"null");return n&&B(n.transactionHash)?n:null}catch{return this.communityReceipts[t]||null}}bridgeStatus(e,t,n,a){return this.request(`community/status?${new URLSearchParams({protocol:e,transactionHash:t,fromChainId:String(n),toChainId:String(a)})}`)}recordView(e,t,n){return this.request("views",{address:e,message:t,url:n})}};var L=(r,e)=>`markee:checkout:v1:${r.apiUrl}:${JSON.stringify(e)}`;function ee(r,e){try{let t=JSON.parse(localStorage.getItem(L(r,e))||"null");return t&&typeof t.id=="string"&&/^[a-f0-9]{48}$/.test(t.id)&&/^[a-f0-9]{64}$/.test(t.readToken)&&/^[a-f0-9]{64}$/.test(t.writeToken)&&Number.isFinite(t.expiresAt)?t:null}catch{return null}}async function Y(r,e){return r.request("checkout/status",{id:e.id,token:e.readToken})}function C(r,e){try{localStorage.removeItem(L(r,e))}catch{}}async function R(r,e,t){let n=r.options.checkoutWindow==="redirect"?null:window.open("about:blank","_blank");n&&(n.opener=null);let a=ee(r,e);try{if(a){let s=await Y(r,a).catch(o=>{if(o instanceof p&&o.status===404)return C(r,e),a=null,null;throw o});if(s?.result?.status==="confirmed"||s?.result?.status==="reverted")return C(r,e),n?.close(),s.result;a&&s&&a.expiresAt<Date.now()&&["created","ready"].includes(s.status)&&(C(r,e),a=null)}if(!a){a=await r.request("checkout/create",{placement:e,action:t,origin:window.location.origin});try{localStorage.setItem(L(r,e),JSON.stringify(a))}catch{}}let i=new URL(`/checkout/${a.id}`,a.checkoutOrigin||r.apiUrl);if(i.protocol!=="https:"&&!(i.protocol==="http:"&&["localhost","127.0.0.1"].includes(i.hostname)))throw new Error("Invalid Markee checkout destination.");if(i.hash=new URLSearchParams({token:a.writeToken}).toString(),n)n.location.replace(i.href);else throw window.location.assign(i.href),new Error("Continuing payment on Markee.");for(let s=0;s<1800;s++){let o=await Y(r,a);if(o.result&&o.status==="confirmed")return C(r,e),n.close(),o.result;if(o.status==="reverted")throw C(r,e),new Error("Payment reverted. Any unspent funds remain in your Markee wallet.");if(n.closed)throw new Error("Markee checkout closed. Choose Pay again to resume; funding alone does not complete payment.");await new Promise(A=>setTimeout(A,3e3))}throw new Error("Checkout is still pending. Reopen it to check the payment; do not pay again.")}catch(i){throw a||n?.close(),i}}function k(r,e=!1){let t=r.trim();if(!/^\d+(\.\d{0,18})?$/.test(t))throw new Error("Enter an ETH amount with up to 18 decimal places.");let[n,a=""]=t.split("."),i=BigInt(n)*10n**18n+BigInt(a.padEnd(18,"0"));if(!e&&i===0n||i>=2n**256n)throw new Error("Enter a positive amount.");return i.toString()}function l(r,e=6){let t=BigInt(r),n=t<0n?"-":"",a=t<0n?-t:t,i=(a%10n**18n).toString().padStart(18,"0").slice(0,e).replace(/0+$/,"");return a>0n&&a<10n**BigInt(18-e)?`${n}<0.${"0".repeat(e-1)}1`:`${n}${a/10n**18n}${i?`.${i}`:""}`}function E(r){return`${r.slice(0,6)}\u2026${r.slice(-4)}`}function d(r){return String(r).replace(/[&<>"']/g,e=>({"&":"&amp;","<":"&lt;",">":"&gt;",'"':"&quot;","'":"&#39;"})[e])}var F=`
1
+ "use client";import{createElement as N,useEffect as z,useRef as J}from"react";var _="https://staging.markee.xyz/api/sdk/v1",p=class extends Error{constructor(t,n="MARKEE_ERROR",a){super(t);this.code=n;this.status=a;this.name="MarkeeError"}};async function Z(){if(typeof window>"u")return[];let r=new Map,e=n=>{let a=n.detail;a?.provider?.request&&typeof a.info?.uuid=="string"&&r.set(a.info.uuid,{uuid:a.info.uuid,name:String(a.info.name).slice(0,80),provider:a.provider})};window.addEventListener("eip6963:announceProvider",e),window.dispatchEvent(new Event("eip6963:requestProvider")),await new Promise(n=>setTimeout(n,150)),window.removeEventListener("eip6963:announceProvider",e);let t=window.ethereum;return!r.size&&t?.request&&r.set("injected",{uuid:"injected",name:"Browser wallet",provider:t}),[...r.values()]}var x=r=>typeof r=="string"&&/^0x[\da-f]{40}$/i.test(r),B=r=>typeof r=="string"&&/^0x[\da-f]{64}$/i.test(r),y=class{constructor(e={}){this.options=e;let t=new URL(e.apiUrl??_);if(t.protocol!=="https:"&&!(t.protocol==="http:"&&["localhost","127.0.0.1","[::1]"].includes(t.hostname)))throw new p("Use an HTTPS Markee API URL (HTTP is allowed on localhost).");this.apiUrl=t.href.replace(/\/$/,""),this.fetcher=e.fetch||globalThis.fetch.bind(globalThis)}apiUrl;fetcher;injected=null;sending=!1;inMemoryPending=[];adminMemory=null;communityReceipts={};async request(e,t,n){let a=await this.fetcher(`${this.apiUrl}/${e}`,{method:t===void 0?"GET":"POST",body:t===void 0?void 0:JSON.stringify(t),headers:t===void 0?void 0:{"Content-Type":"application/json"},credentials:"omit",signal:n||AbortSignal.timeout(55e3)}),i=await a.json().catch(()=>null);if(!a.ok)throw new p(i?.error||`Markee returned HTTP ${a.status}.`,i?.code,a.status);return i}async provider(){return this.options.wallet?this.options.wallet.getProvider():this.injected}async account(){let e=await this.provider();if(!e)return null;let t=await e.request({method:"eth_accounts"});return Array.isArray(t)&&x(t[0])?t[0]:null}async connect(e){let t=await this.provider();if(this.options.wallet)t||(t=await this.options.wallet.connect?.()||null);else{if(t=e||t,!t){let a=await Z();if(a.length>1)throw new p("Select a browser wallet.","SELECT_WALLET");t=a[0]?.provider||null}this.injected=t}if(!t)throw new p("Connect a wallet in the app or install a browser wallet to continue.","NO_WALLET");let n=await t.request({method:"eth_requestAccounts"});if(!Array.isArray(n)||!x(n[0]))throw new p("The wallet did not return an account.");return n[0]}verifySite(e,t){return this.request("sites/verify",{placement:e,siteUrl:t})}siteRequests=new Map;registerSite(e){if(!this.options.siteUrl)return;let t=JSON.stringify([e,this.options.siteUrl]);if(this.siteRequests.has(t))return;let n=this.verifySite(e,this.options.siteUrl);this.siteRequests.set(t,n),n.then(a=>this.options.onSiteVerification?.(a),a=>this.options.onSiteVerification?.({verified:!1,url:this.options.siteUrl,message:a instanceof Error?a.message:"Site verification failed."})).catch(()=>{})}async snapshot(e,t,n,a){let i=new URLSearchParams({placement:JSON.stringify(e)});return t&&i.set("account",t),n!==void 0&&i.set("offset",String(n)),this.request(`snapshot?${i}`,void 0,a)}async prepare(e,t){let n=await this.account();if(!n)throw new p("Connect your wallet first.","NOT_CONNECTED");return this.request("prepare",{placement:e,account:n,action:t})}async ensureWallet(e,t){let n=await this.provider();if(!n||(await this.account())?.toLowerCase()!==e.toLowerCase())throw new p("Your wallet account changed. Review this action again.","ACCOUNT_CHANGED");let a=Number(await n.request({method:"eth_chainId"}));if(a!==t&&await n.request({method:"wallet_switchEthereumChain",params:[{chainId:`0x${t.toString(16)}`}]}),a=Number(await n.request({method:"eth_chainId"})),a!==t||(await this.account())?.toLowerCase()!==e.toLowerCase())throw new p("The wallet account or network changed. Review again.","WALLET_CHANGED");return n}async send(e){if(this.sending)throw new p("A wallet request is already in progress.");if(e.expiresAt<=Date.now())throw new p("This review expired. Prepare the action again.","REVIEW_EXPIRED");if(this.pending(e.placement,e.transaction.from))throw new p("A transaction is still pending for this wallet and placement. Check it before submitting again.","PENDING_TRANSACTION");this.sending=!0;try{let n=await this.ensureWallet(e.transaction.from,e.transaction.chainId);if(e.expiresAt<=Date.now())throw new p("This review expired. Prepare the action again.","REVIEW_EXPIRED");let{chainId:a,...i}=e.transaction,s=await n.request({method:"eth_sendTransaction",params:[i]});if(!B(s))throw new p("The wallet returned an unexpected transaction identifier. Check your wallet before retrying.");return this.persist([...this.records(),{preparation:e,hash:s}]),this.options.onEvent?.({type:"submitted",hash:s}),s}catch(n){throw this.options.onEvent?.({type:"error",message:n instanceof Error?n.message:String(n)}),n}finally{this.sending=!1}}async verify(e){let t=await this.request("verify",{id:e.preparation.id,hash:e.hash});return t.status!=="pending"&&(this.persist(this.records().filter(n=>n.hash!==e.hash)),t.status==="confirmed"&&this.options.onEvent?.({type:"confirmed",hash:t.hash})),t}async reconcile(e,t){if(!B(t))throw new p("Enter a valid replacement transaction hash.");let n=await this.request("verify",{id:e.preparation.id,hash:t});return n.status!=="pending"&&this.persist(this.records().filter(a=>a.hash!==e.hash)),n}storageKey(){return`markee:sdk:v1:pending:${this.apiUrl}`}records(){try{if(typeof localStorage>"u")return this.inMemoryPending;let e=JSON.parse(localStorage.getItem(this.storageKey())||"[]");return Array.isArray(e)?e.filter(t=>B(t?.hash)&&typeof t.preparation?.id=="string"&&x(t.preparation?.transaction?.from)&&t.preparation?.placement):[]}catch{return this.inMemoryPending}}persist(e){this.inMemoryPending=e;try{typeof localStorage<"u"&&localStorage.setItem(this.storageKey(),JSON.stringify(e))}catch{}}pending(e,t){return this.records().find(n=>JSON.stringify(n.preparation.placement).toLowerCase()===JSON.stringify(e).toLowerCase()&&n.preparation.transaction.from.toLowerCase()===t.toLowerCase())}async quote(e){return this.request(`community/quote?${new URLSearchParams({chainId:String(e.chainId),community:e.community})}`)}async authorize(e,t){let n=await this.account();if(!n)throw new p("Connect your community council wallet first.");return this.request(`community/${t}`,{action:"challenge",chainId:e.chainId,community:e.community,account:n})}async executeAuthorization(e,t,n){if(this.pendingAuthorization())throw new p("An earlier community authorization is still processing. Check its status first.");let a=t.typedData,s=await(await this.ensureWallet(n,a.domain.chainId)).request({method:"eth_signTypedData_v4",params:[n,JSON.stringify({...a,types:{...a.types,EIP712Domain:[{name:"name",type:"string"},{name:"version",type:"string"},{name:"chainId",type:"uint256"},{name:"verifyingContract",type:"address"}]}})]});if(typeof s!="string"||!/^0x[\da-f]+$/i.test(s))throw new p("Wallet did not return a typed-data signature.");return this.saveAuthorization({kind:e,nonce:t.nonce,signature:s,account:n,community:a.domain.verifyingContract,chainId:a.domain.chainId}),this.resumeAuthorization()}pendingAuthorization(){try{let e=typeof localStorage>"u"?this.adminMemory:JSON.parse(localStorage.getItem(`${this.storageKey()}:admin`)||"null");return e&&["activate","claim"].includes(e.kind)&&x(e.account)&&x(e.community)&&typeof e.nonce=="string"&&typeof e.signature=="string"?e:null}catch{return this.adminMemory}}saveAuthorization(e){this.adminMemory=e;try{typeof localStorage<"u"&&localStorage.setItem(`${this.storageKey()}:admin`,JSON.stringify(e))}catch{}}async resumeAuthorization(){let e=this.pendingAuthorization();if(!e)throw new p("There is no pending community authorization.");let t=await this.request(`community/${e.kind}`,{action:"verify",nonce:e.nonce,signature:e.signature});if(t.status==="complete"&&t.result){let n=`${e.chainId}:${e.community.toLowerCase()}`;this.communityReceipts[n]=t.result;try{typeof localStorage<"u"&&localStorage.setItem(`${this.storageKey()}:community:${n}`,JSON.stringify(t.result))}catch{}}return(t.status==="complete"||t.status==="failed")&&this.saveAuthorization(null),t}communityReceipt(e){let t=`${e.chainId}:${e.community.toLowerCase()}`;try{let n=typeof localStorage>"u"?this.communityReceipts[t]:JSON.parse(localStorage.getItem(`${this.storageKey()}:community:${t}`)||"null");return n&&B(n.transactionHash)?n:null}catch{return this.communityReceipts[t]||null}}bridgeStatus(e,t,n,a){return this.request(`community/status?${new URLSearchParams({protocol:e,transactionHash:t,fromChainId:String(n),toChainId:String(a)})}`)}recordView(e,t,n){return this.request("views",{address:e,message:t,url:n})}};var L=(r,e)=>`markee:checkout:v1:${r.apiUrl}:${JSON.stringify(e)}`;function ee(r,e){try{let t=JSON.parse(localStorage.getItem(L(r,e))||"null");return t&&typeof t.id=="string"&&/^[a-f0-9]{48}$/.test(t.id)&&/^[a-f0-9]{64}$/.test(t.readToken)&&/^[a-f0-9]{64}$/.test(t.writeToken)&&Number.isFinite(t.expiresAt)?t:null}catch{return null}}async function Y(r,e){return r.request("checkout/status",{id:e.id,token:e.readToken})}function C(r,e){try{localStorage.removeItem(L(r,e))}catch{}}async function R(r,e,t){let n=r.options.checkoutWindow==="redirect"?null:window.open("about:blank","_blank");n&&(n.opener=null);let a=ee(r,e);try{if(a){let s=await Y(r,a).catch(o=>{if(o instanceof p&&o.status===404)return C(r,e),a=null,null;throw o});if(s?.result?.status==="confirmed"||s?.result?.status==="reverted")return C(r,e),n?.close(),s.result;a&&s&&a.expiresAt<Date.now()&&["created","ready"].includes(s.status)&&(C(r,e),a=null)}if(!a){a=await r.request("checkout/create",{placement:e,action:t,origin:window.location.origin});try{localStorage.setItem(L(r,e),JSON.stringify(a))}catch{}}let i=new URL(`/checkout/${a.id}`,a.checkoutOrigin||r.apiUrl);if(i.protocol!=="https:"&&!(i.protocol==="http:"&&["localhost","127.0.0.1"].includes(i.hostname)))throw new Error("Invalid Markee checkout destination.");if(i.hash=new URLSearchParams({token:a.writeToken}).toString(),n)n.location.replace(i.href);else throw window.location.assign(i.href),new Error("Continuing payment on Markee.");for(let s=0;s<1800;s++){let o=await Y(r,a);if(o.result&&o.status==="confirmed")return C(r,e),n.close(),o.result;if(o.status==="reverted")throw C(r,e),new Error("Payment reverted. Any unspent funds remain in your Markee wallet.");if(n.closed)throw new Error("Markee checkout closed. Choose Pay again to resume; funding alone does not complete payment.");await new Promise(A=>setTimeout(A,3e3))}throw new Error("Checkout is still pending. Reopen it to check the payment; do not pay again.")}catch(i){throw a||n?.close(),i}}function k(r,e=!1){let t=r.trim();if(!/^\d+(\.\d{0,18})?$/.test(t))throw new Error("Enter an ETH amount with up to 18 decimal places.");let[n,a=""]=t.split("."),i=BigInt(n)*10n**18n+BigInt(a.padEnd(18,"0"));if(!e&&i===0n||i>=2n**256n)throw new Error("Enter a positive amount.");return i.toString()}function l(r,e=6){let t=BigInt(r),n=t<0n?"-":"",a=t<0n?-t:t,i=(a%10n**18n).toString().padStart(18,"0").slice(0,e).replace(/0+$/,"");return a>0n&&a<10n**BigInt(18-e)?`${n}<0.${"0".repeat(e-1)}1`:`${n}${a/10n**18n}${i?`.${i}`:""}`}function E(r){return`${r.slice(0,6)}\u2026${r.slice(-4)}`}function d(r){return String(r).replace(/[&<>"']/g,e=>({"&":"&amp;","<":"&lt;",">":"&gt;",'"':"&quot;","'":"&#39;"})[e])}var F=`
2
2
  :host{all:initial;font-family:var(--markee-font-family);color:var(--markee-text);font-size:14px;line-height:1.5;color-scheme:var(--markee-color-scheme)}
3
3
 
4
4
  *{box-sizing:border-box}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@markee_team/sdk",
3
- "version": "0.1.0-alpha.20",
3
+ "version": "0.1.0-alpha.21",
4
4
  "description": "Self-contained Markee modal and API client, with an optional React adapter.",
5
5
  "type": "module",
6
6
  "sideEffects": false,