@mochabug/adapt-web 1.0.1-rc.26 → 1.0.1-rc.27

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/README.md CHANGED
@@ -6,7 +6,7 @@ Embed Adapt automations in any website.
6
6
  npm install @mochabug/adapt-web
7
7
  ```
8
8
 
9
- **CDN base:** `https://cdn.mochabug.com/adapt/web/1.0.1-rc.26/`
9
+ **CDN base:** `https://cdn.mochabug.com/adapt/web/1.0.1-rc.27/`
10
10
 
11
11
  | Bundle | File | Includes |
12
12
  |--------|------|----------|
@@ -20,8 +20,8 @@ npm install @mochabug/adapt-web
20
20
  Bundles merge into a single `MbAdapt` global, so you can combine them. For example, headless + Cap for automations that need proof-of-work but no UI:
21
21
 
22
22
  ```html
23
- <script src="https://cdn.mochabug.com/adapt/web/1.0.1-rc.26/adapt-core.min.js"></script>
24
- <script src="https://cdn.mochabug.com/adapt/web/1.0.1-rc.26/adapt-web.cap.min.js"></script>
23
+ <script src="https://cdn.mochabug.com/adapt/web/1.0.1-rc.27/adapt-core.min.js"></script>
24
+ <script src="https://cdn.mochabug.com/adapt/web/1.0.1-rc.27/adapt-web.cap.min.js"></script>
25
25
  <script>
26
26
  // MbAdapt has exports from both scripts
27
27
  var client = MbAdapt.createAdaptClient(
@@ -43,12 +43,12 @@ Preload the script and load the stylesheet in `<head>` to eliminate flash of uns
43
43
 
44
44
  ```html
45
45
  <head>
46
- <link rel="preload" href="https://cdn.mochabug.com/adapt/web/1.0.1-rc.26/adapt-web.min.js" as="script">
47
- <link rel="stylesheet" href="https://cdn.mochabug.com/adapt/web/1.0.1-rc.26/styles.css">
46
+ <link rel="preload" href="https://cdn.mochabug.com/adapt/web/1.0.1-rc.27/adapt-web.min.js" as="script">
47
+ <link rel="stylesheet" href="https://cdn.mochabug.com/adapt/web/1.0.1-rc.27/styles.css">
48
48
  </head>
49
49
  <body>
50
50
  <adapt-automation automation-id="YOUR_ID" requires-challenge style="height: 600px"></adapt-automation>
51
- <script src="https://cdn.mochabug.com/adapt/web/1.0.1-rc.26/adapt-web.min.js"></script>
51
+ <script src="https://cdn.mochabug.com/adapt/web/1.0.1-rc.27/adapt-web.min.js"></script>
52
52
  </body>
53
53
  ```
54
54
 
@@ -56,12 +56,12 @@ No challenges? Use the core bundle and drop `requires-challenge`:
56
56
 
57
57
  ```html
58
58
  <head>
59
- <link rel="preload" href="https://cdn.mochabug.com/adapt/web/1.0.1-rc.26/adapt-web.core.min.js" as="script">
60
- <link rel="stylesheet" href="https://cdn.mochabug.com/adapt/web/1.0.1-rc.26/styles.css">
59
+ <link rel="preload" href="https://cdn.mochabug.com/adapt/web/1.0.1-rc.27/adapt-web.core.min.js" as="script">
60
+ <link rel="stylesheet" href="https://cdn.mochabug.com/adapt/web/1.0.1-rc.27/styles.css">
61
61
  </head>
62
62
  <body>
63
63
  <adapt-automation automation-id="YOUR_ID" style="height: 600px"></adapt-automation>
64
- <script src="https://cdn.mochabug.com/adapt/web/1.0.1-rc.26/adapt-web.core.min.js"></script>
64
+ <script src="https://cdn.mochabug.com/adapt/web/1.0.1-rc.27/adapt-web.core.min.js"></script>
65
65
  </body>
66
66
  ```
67
67
 
@@ -71,14 +71,14 @@ Just the element and script. CSS is auto-injected at runtime.
71
71
 
72
72
  ```html
73
73
  <adapt-automation automation-id="YOUR_ID" requires-challenge style="height: 600px"></adapt-automation>
74
- <script src="https://cdn.mochabug.com/adapt/web/1.0.1-rc.26/adapt-web.min.js"></script>
74
+ <script src="https://cdn.mochabug.com/adapt/web/1.0.1-rc.27/adapt-web.min.js"></script>
75
75
  ```
76
76
 
77
77
  Without challenges:
78
78
 
79
79
  ```html
80
80
  <adapt-automation automation-id="YOUR_ID" style="height: 600px"></adapt-automation>
81
- <script src="https://cdn.mochabug.com/adapt/web/1.0.1-rc.26/adapt-web.core.min.js"></script>
81
+ <script src="https://cdn.mochabug.com/adapt/web/1.0.1-rc.27/adapt-web.core.min.js"></script>
82
82
  ```
83
83
 
84
84
  ### ESM
@@ -160,12 +160,12 @@ Requires a `client` JS property — set it after the element is in the DOM.
160
160
 
161
161
  ```html
162
162
  <head>
163
- <link rel="preload" href="https://cdn.mochabug.com/adapt/web/1.0.1-rc.26/adapt-web.cap.min.js" as="script">
164
- <link rel="stylesheet" href="https://cdn.mochabug.com/adapt/web/1.0.1-rc.26/styles.css">
163
+ <link rel="preload" href="https://cdn.mochabug.com/adapt/web/1.0.1-rc.27/adapt-web.cap.min.js" as="script">
164
+ <link rel="stylesheet" href="https://cdn.mochabug.com/adapt/web/1.0.1-rc.27/styles.css">
165
165
  </head>
166
166
  <body>
167
167
  <adapt-cap automation-id="YOUR_ID"></adapt-cap>
168
- <script src="https://cdn.mochabug.com/adapt/web/1.0.1-rc.26/adapt-web.cap.min.js"></script>
168
+ <script src="https://cdn.mochabug.com/adapt/web/1.0.1-rc.27/adapt-web.cap.min.js"></script>
169
169
  <script>
170
170
  var el = document.querySelector('adapt-cap');
171
171
  el.client = MbAdapt.createConnectClient({ id: 'YOUR_ID' });
@@ -180,7 +180,7 @@ Requires a `client` JS property — set it after the element is in the DOM.
180
180
 
181
181
  ```html
182
182
  <adapt-cap automation-id="YOUR_ID"></adapt-cap>
183
- <script src="https://cdn.mochabug.com/adapt/web/1.0.1-rc.26/adapt-web.cap.min.js"></script>
183
+ <script src="https://cdn.mochabug.com/adapt/web/1.0.1-rc.27/adapt-web.cap.min.js"></script>
184
184
  <script>
185
185
  var el = document.querySelector('adapt-cap');
186
186
  el.client = MbAdapt.createConnectClient({ id: 'YOUR_ID' });
@@ -1 +1 @@
1
- import{setupCapAdapter,cleanupCapAdapter}from"./cap-adapter.js";import{CAP_WIDGET_CSS}from"./css-cap.js";import"@cap.js/widget";class AdaptCapWidget{constructor(options){this.widgetContainer=null;this.widgetElement=null;this.destroyed=!1;if(!options.automationId)throw new Error('[adapt] AdaptCapWidget requires "automationId".');if(!options.client)throw new Error('[adapt] AdaptCapWidget requires "client". Create one with: createConnectClient({ id: "..." })');if(!options.onSolve)throw new Error('[adapt] AdaptCapWidget requires "onSolve" callback.');this.options=options;const container=typeof options.container=="string"?document.getElementById(options.container):options.container;if(!container)throw new Error(`Container ${typeof options.container=="string"?`with id '${options.container}'`:""} not found`);this.containerElement=container,this.injectStyles(),setupCapAdapter(options.client,options.automationId),this.mountWidget()}injectStyles(){if(getComputedStyle(document.documentElement).getPropertyValue("--mb-adapt-styles-loaded").trim()||document.getElementById("mb-adapt-cap-styles"))return;const style=document.createElement("style");style.id="mb-adapt-cap-styles",style.textContent=CAP_WIDGET_CSS,document.head.appendChild(style)}mountWidget(){this.widgetContainer=document.createElement("div"),this.widgetContainer.className="mb-adapt-cap";const innerContainer=document.createElement("div");if(innerContainer.className="mb-adapt-cap__container",this.widgetElement=document.createElement("cap-widget"),this.widgetElement.setAttribute("data-cap-api-endpoint",`/adapt-cap-${this.options.automationId}/`),this.options.workerCount&&this.widgetElement.setAttribute("data-cap-worker-count",String(this.options.workerCount)),this.options.i18n){const{i18n}=this.options;i18n.verifyingLabel&&this.widgetElement.setAttribute("data-cap-i18n-verifying-label",i18n.verifyingLabel),i18n.initialState&&this.widgetElement.setAttribute("data-cap-i18n-initial-state",i18n.initialState),i18n.solvedLabel&&this.widgetElement.setAttribute("data-cap-i18n-solved-label",i18n.solvedLabel),i18n.errorLabel&&this.widgetElement.setAttribute("data-cap-i18n-error-label",i18n.errorLabel)}this.widgetElement.addEventListener("solve",(e=>{if(this.destroyed)return;const token=e.detail?.token,expiresStr=e.detail?.expires,expires=expiresStr?new Date(expiresStr):new Date;setTimeout(()=>this.destroy(),0),token?this.options.onSolve(token,expires):this.options.onError?.(new Error("No token received from Cap.js"))})),this.widgetElement.addEventListener("error",(e=>{this.destroyed||(console.error("[AdaptCapWidget] Cap.js error:",e.detail),setTimeout(()=>this.destroy(),0),this.options.onError?.(new Error(e.detail?.message||"Cap.js error")))})),innerContainer.appendChild(this.widgetElement),this.widgetContainer.appendChild(innerContainer),this.containerElement.appendChild(this.widgetContainer)}setDarkMode(dark){this.widgetContainer&&(dark?this.widgetContainer.classList.add("mb-adapt-cap--dark"):this.widgetContainer.classList.remove("mb-adapt-cap--dark"))}destroy(){this.destroyed||(this.destroyed=!0,cleanupCapAdapter(),this.widgetContainer&&this.widgetContainer.parentNode&&this.widgetContainer.parentNode.removeChild(this.widgetContainer),this.widgetContainer=null,this.widgetElement=null)}}export{AdaptCapWidget};
1
+ import{setupCapAdapter,cleanupCapAdapter,takeRedeemedChallengeExpiration}from"./cap-adapter.js";import{CAP_WIDGET_CSS}from"./css-cap.js";import"@cap.js/widget";class AdaptCapWidget{constructor(options){this.widgetContainer=null;this.widgetElement=null;this.destroyed=!1;if(!options.automationId)throw new Error('[adapt] AdaptCapWidget requires "automationId".');if(!options.client)throw new Error('[adapt] AdaptCapWidget requires "client". Create one with: createConnectClient({ id: "..." })');if(!options.onSolve)throw new Error('[adapt] AdaptCapWidget requires "onSolve" callback.');this.options=options;const container=typeof options.container=="string"?document.getElementById(options.container):options.container;if(!container)throw new Error(`Container ${typeof options.container=="string"?`with id '${options.container}'`:""} not found`);this.containerElement=container,this.injectStyles(),setupCapAdapter(options.client,options.automationId),this.mountWidget()}injectStyles(){if(getComputedStyle(document.documentElement).getPropertyValue("--mb-adapt-styles-loaded").trim()||document.getElementById("mb-adapt-cap-styles"))return;const style=document.createElement("style");style.id="mb-adapt-cap-styles",style.textContent=CAP_WIDGET_CSS,document.head.appendChild(style)}mountWidget(){this.widgetContainer=document.createElement("div"),this.widgetContainer.className="mb-adapt-cap";const innerContainer=document.createElement("div");if(innerContainer.className="mb-adapt-cap__container",this.widgetElement=document.createElement("cap-widget"),this.widgetElement.setAttribute("data-cap-api-endpoint",`/adapt-cap-${this.options.automationId}/`),this.options.workerCount&&this.widgetElement.setAttribute("data-cap-worker-count",String(this.options.workerCount)),this.options.i18n){const{i18n}=this.options;i18n.verifyingLabel&&this.widgetElement.setAttribute("data-cap-i18n-verifying-label",i18n.verifyingLabel),i18n.initialState&&this.widgetElement.setAttribute("data-cap-i18n-initial-state",i18n.initialState),i18n.solvedLabel&&this.widgetElement.setAttribute("data-cap-i18n-solved-label",i18n.solvedLabel),i18n.errorLabel&&this.widgetElement.setAttribute("data-cap-i18n-error-label",i18n.errorLabel)}this.widgetElement.addEventListener("solve",(e=>{if(this.destroyed)return;const token=e.detail?.token,expiresStr=e.detail?.expires,expires=takeRedeemedChallengeExpiration(this.options.automationId)??(expiresStr?new Date(expiresStr):new Date);setTimeout(()=>this.destroy(),0),token?this.options.onSolve(token,expires):this.options.onError?.(new Error("No token received from Cap.js"))})),this.widgetElement.addEventListener("error",(e=>{this.destroyed||(console.error("[AdaptCapWidget] Cap.js error:",e.detail),setTimeout(()=>this.destroy(),0),this.options.onError?.(new Error(e.detail?.message||"Cap.js error")))})),innerContainer.appendChild(this.widgetElement),this.widgetContainer.appendChild(innerContainer),this.containerElement.appendChild(this.widgetContainer)}setDarkMode(dark){this.widgetContainer&&(dark?this.widgetContainer.classList.add("mb-adapt-cap--dark"):this.widgetContainer.classList.remove("mb-adapt-cap--dark"))}destroy(){this.destroyed||(this.destroyed=!0,cleanupCapAdapter(),this.widgetContainer&&this.widgetContainer.parentNode&&this.widgetContainer.parentNode.removeChild(this.widgetContainer),this.widgetContainer=null,this.widgetElement=null)}}export{AdaptCapWidget};
@@ -1 +1 @@
1
- typeof window<"u"&&!window.CAP_CUSTOM_WASM_URL&&(window.CAP_CUSTOM_WASM_URL=new URL("https://cdn.mochabug.com/adapt/web/1.0.1-rc.26/cap_wasm_bg.wasm",window.location.href).href);import{timestampDate}from"@bufbuild/protobuf/wkt";let currentClient=null,currentAutomationId=null;const verificationTokens=new Map;async function createChallenge(client,id){const response=await client.createChallenge({id});return{count:response.count,size:response.size,difficulty:response.difficulty,expires:response.expires?timestampDate(response.expires):new Date,token:response.token,verificationToken:response.verificationToken}}async function redeemChallenge(client,id,verificationToken,solutions){const response=await client.redeemChallenge({id,verificationToken,solutions});return{token:response.token,expires:response.expires?timestampDate(response.expires):new Date}}typeof window<"u"&&(window.CAP_CUSTOM_FETCH=async(url,options)=>{const urlStr=url.toString();if(urlStr.endsWith("/challenge")){if(!currentClient||!currentAutomationId)return new Response(JSON.stringify({error:"Cap adapter not initialized"}),{status:500,headers:{"Content-Type":"application/json"}});try{const challengeInfo=await createChallenge(currentClient,currentAutomationId);return verificationTokens.set(currentAutomationId,challengeInfo.verificationToken),new Response(JSON.stringify({challenge:{c:challengeInfo.count,s:challengeInfo.size,d:challengeInfo.difficulty},token:challengeInfo.token,expires:challengeInfo.expires.toISOString()}),{status:200,headers:{"Content-Type":"application/json"}})}catch(error){return new Response(JSON.stringify({error:String(error)}),{status:500,headers:{"Content-Type":"application/json"}})}}if(urlStr.endsWith("/redeem")){if(!currentClient||!currentAutomationId)return new Response(JSON.stringify({error:"Cap adapter not initialized"}),{status:500,headers:{"Content-Type":"application/json"}});const verificationToken=verificationTokens.get(currentAutomationId);if(!verificationToken)return new Response(JSON.stringify({error:"No verification token found - challenge must be created first"}),{status:400,headers:{"Content-Type":"application/json"}});try{const solutions=((options?.body?JSON.parse(options.body):{}).solutions||[]).map(s=>BigInt(s)),redeemed=await redeemChallenge(currentClient,currentAutomationId,verificationToken,solutions);return verificationTokens.delete(currentAutomationId),new Response(JSON.stringify({success:!0,token:redeemed.token,expires:redeemed.expires.toISOString()}),{status:200,headers:{"Content-Type":"application/json"}})}catch(error){return new Response(JSON.stringify({error:String(error)}),{status:500,headers:{"Content-Type":"application/json"}})}}return fetch(url,options)});function setupCapAdapter(client,automationId){currentClient=client,currentAutomationId=automationId}function cleanupCapAdapter(){currentAutomationId&&verificationTokens.delete(currentAutomationId),currentClient=null,currentAutomationId=null}export{cleanupCapAdapter,createChallenge,redeemChallenge,setupCapAdapter};
1
+ typeof window<"u"&&!window.CAP_CUSTOM_WASM_URL&&(window.CAP_CUSTOM_WASM_URL=new URL("https://cdn.mochabug.com/adapt/web/1.0.1-rc.27/cap_wasm_bg.wasm",window.location.href).href);import{timestampDate}from"@bufbuild/protobuf/wkt";let currentClient=null,currentAutomationId=null;const verificationTokens=new Map,redeemedChallengeExpirations=new Map;async function createChallenge(client,id){const response=await client.createChallenge({id});return{count:response.count,size:response.size,difficulty:response.difficulty,expires:response.expires?timestampDate(response.expires):new Date,token:response.token,verificationToken:response.verificationToken}}async function redeemChallenge(client,id,verificationToken,solutions){const response=await client.redeemChallenge({id,verificationToken,solutions});return{token:response.token,expires:response.expires?timestampDate(response.expires):new Date}}function takeRedeemedChallengeExpiration(automationId){const expires=redeemedChallengeExpirations.get(automationId)??null;return expires&&redeemedChallengeExpirations.delete(automationId),expires}typeof window<"u"&&(window.CAP_CUSTOM_FETCH=async(url,options)=>{const urlStr=url.toString();if(urlStr.endsWith("/challenge")){if(!currentClient||!currentAutomationId)return new Response(JSON.stringify({error:"Cap adapter not initialized"}),{status:500,headers:{"Content-Type":"application/json"}});try{const challengeInfo=await createChallenge(currentClient,currentAutomationId);return verificationTokens.set(currentAutomationId,challengeInfo.verificationToken),redeemedChallengeExpirations.delete(currentAutomationId),new Response(JSON.stringify({challenge:{c:challengeInfo.count,s:challengeInfo.size,d:challengeInfo.difficulty},token:challengeInfo.token,expires:challengeInfo.expires.toISOString()}),{status:200,headers:{"Content-Type":"application/json"}})}catch(error){return new Response(JSON.stringify({error:String(error)}),{status:500,headers:{"Content-Type":"application/json"}})}}if(urlStr.endsWith("/redeem")){if(!currentClient||!currentAutomationId)return new Response(JSON.stringify({error:"Cap adapter not initialized"}),{status:500,headers:{"Content-Type":"application/json"}});const verificationToken=verificationTokens.get(currentAutomationId);if(!verificationToken)return new Response(JSON.stringify({error:"No verification token found - challenge must be created first"}),{status:400,headers:{"Content-Type":"application/json"}});try{const solutions=((options?.body?JSON.parse(options.body):{}).solutions||[]).map(s=>BigInt(s)),redeemed=await redeemChallenge(currentClient,currentAutomationId,verificationToken,solutions);return redeemedChallengeExpirations.set(currentAutomationId,redeemed.expires),verificationTokens.delete(currentAutomationId),new Response(JSON.stringify({success:!0,token:redeemed.token,expires:redeemed.expires.toISOString()}),{status:200,headers:{"Content-Type":"application/json"}})}catch(error){return new Response(JSON.stringify({error:String(error)}),{status:500,headers:{"Content-Type":"application/json"}})}}return fetch(url,options)});function setupCapAdapter(client,automationId){currentAutomationId&&currentAutomationId!==automationId&&(verificationTokens.delete(currentAutomationId),redeemedChallengeExpirations.delete(currentAutomationId)),currentClient=client,currentAutomationId=automationId,redeemedChallengeExpirations.delete(automationId)}function cleanupCapAdapter(){currentAutomationId&&(verificationTokens.delete(currentAutomationId),redeemedChallengeExpirations.delete(currentAutomationId)),currentClient=null,currentAutomationId=null}export{cleanupCapAdapter,createChallenge,redeemChallenge,setupCapAdapter,takeRedeemedChallengeExpiration};
@@ -23,6 +23,13 @@ export declare function createChallenge(client: AutomationClient, id: string): P
23
23
  * @returns Redeemed challenge with token to use for session start
24
24
  */
25
25
  export declare function redeemChallenge(client: AutomationClient, id: string, verificationToken: string, solutions: bigint[]): Promise<RedeemedChallenge>;
26
+ /**
27
+ * Read and clear the expiration captured from the most recent successful redeem.
28
+ *
29
+ * Cap.js solve events expose the redeemed token but not its expiry timestamp, so
30
+ * the wrapper needs to carry that value across from the redeem response.
31
+ */
32
+ export declare function takeRedeemedChallengeExpiration(automationId: string): Date | null;
26
33
  /**
27
34
  * Set up the Cap.js adapter with the client and automation ID.
28
35
  * Must be called before the Cap.js widget is activated.