@botpoison/browser 1.0.0 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.ts CHANGED
@@ -12,7 +12,6 @@ declare global {
12
12
  interface Window {
13
13
  __BOTPOISON_VERSION__: string | undefined;
14
14
  __BOTPOISON_SUBMIT_LISTENER__: boolean | undefined;
15
- __BOTPOISON_SESSION_OPENED__: boolean | undefined;
16
15
  }
17
16
  }
18
17
  type BotpoisonOptions = {
package/dist/index.js CHANGED
@@ -1,4 +1,4 @@
1
- "use strict";var __botpoison=(()=>{var O=Object.defineProperty;var R=Object.getOwnPropertyDescriptor;var U=Object.getOwnPropertyNames;var D=Object.prototype.hasOwnProperty;var M=(t,e)=>{for(var n in e)O(t,n,{get:e[n],enumerable:!0})},F=(t,e,n,o)=>{if(e&&typeof e=="object"||typeof e=="function")for(let r of U(e))!D.call(t,r)&&r!==n&&O(t,r,{get:()=>e[r],enumerable:!(o=R(e,r))||o.enumerable});return t};var K=t=>F(O({},"__esModule",{value:!0}),t);var W={};M(W,{default:()=>y});var u="https://api.botpoison.com",m="_botpoison",_={"Content-Type":"text/plain",Accept:"application/json"};var T=({formElement:t,value:e})=>{let n=t.querySelector(`input[name="${m}"]`);if(!n){let o=t.ownerDocument;n=o.createElement("input"),n.setAttribute("type","hidden"),n.setAttribute("name",m),o.getElementById(m)||n.setAttribute("id",m),t.appendChild(n)}return n.setAttribute("value",e),n},f=({formElement:t,name:e})=>{t.dispatchEvent(new CustomEvent(`botpoison-challenge-${e}`))};var $=t=>new Promise(e=>setTimeout(e,t)),I=t=>{let e="";for(let n of t)e+=n.toString(16).padStart(2,"0");return BigInt(`0x${e}`)},H=t=>{let e=atob(t),n=new Uint8Array(e.length);for(let o=0;o<e.length;o++)n[o]=e.charCodeAt(o);return n},V=(t,e)=>{let n=t.toString(16).padStart(e*2,"0"),o="";for(let r=0;r<n.length;r+=2)o+=String.fromCharCode(parseInt(n.substring(r,r+2),16));return btoa(o)},j=async({nonce:t,modulus:e,byteLength:n})=>{let o=new TextEncoder,r=[],s=0;for(let i=0;s<n;i++){let l=new Uint8Array(await crypto.subtle.digest("SHA-256",o.encode(`${t}:${i}`)));r.push(l),s+=l.length}let c=new Uint8Array(s),a=0;for(let i of r)c.set(i,a),a+=i.length;let p=I(c.subarray(0,n))%e;return p*p%e},G="sundial",q=async({challenge:t,onProgress:e})=>{let{algo:n,nonce:o,modulus:r,squarings:s}=t.payload;if(n!==void 0&&n!==G)throw new Error(`Botpoison: this version cannot solve "${n}" challenges. Upgrade @botpoison/browser.`);let c=H(r),a=I(c),p=c.length;e==null||e(0);let i=await j({nonce:o,modulus:a,byteLength:p});for(let l=0;l<s;l++)i=i*i%a,l%2e4===19999&&(e==null||e(l/s),await $(0));return e==null||e(1),[V(i,p)]},N=q;var w="_botpoison.v2.session.",d,b=new Map,A=()=>{if(d!==void 0)return d;try{let t=window.sessionStorage,e=`${w}probe`;t.setItem(e,"1"),t.removeItem(e),d=t}catch(t){d=null}return d},g=t=>`${w}${t}`,E=t=>{var n;let e=A();if(!e)return b.get(g(t));try{return(n=e.getItem(g(t)))!=null?n:void 0}catch(o){return b.get(g(t))}},C=(t,e)=>{let n=A();if(n)try{n.setItem(g(t),e);return}catch(o){d=null}b.set(g(t),e)};var S,L=(t=u)=>E(t),v=(t,e)=>{let n=e==null?void 0:e.token;typeof n=="string"&&C(t,n)},k=({baseUrl:t=u}={})=>E(t)?Promise.resolve():S||(S=fetch(`${t}/session`,{method:"POST",headers:_,body:"{}"}).then(async e=>{e.ok&&v(t,await e.json())}).catch(()=>{}).finally(()=>{S=void 0}),S),P=({challenge:t,solutions:e,baseUrl:n=u})=>fetch(`${n}/session`,{method:"POST",headers:_,keepalive:!0,body:JSON.stringify({challenge:t,solutions:e,token:E(n)})}).then(async o=>{o.ok&&v(n,await o.json())}).catch(()=>{});var J=()=>typeof location=="undefined"?void 0:location.hostname,h=async({publicKey:t,baseUrl:e=u,onProgress:n})=>{let r=await(await fetch(`${e}/challenge`,{method:"POST",headers:_,body:JSON.stringify({publicKey:t,hostname:J(),version:"1.0.0",token:L(e)})})).json(),s=await N({challenge:r,onProgress:n});return P({challenge:r,solutions:s,baseUrl:e}),{solution:btoa(JSON.stringify({challenge:r,solutions:s}))}};var Q=t=>{if(!t||!t.tagName)return;let e=t;if(e.tagName!=="FORM")return;let n=e,o=n.dataset.botpoisonPublicKey;return o?{formElement:n,publicKey:o}:void 0},B=({documentRef:t,baseUrl:e})=>{let n=o=>{try{let r=Q(o.target);if(!r)return;let{formElement:s,publicKey:c}=r;o.preventDefault(),f({formElement:s,name:"start"}),h({publicKey:c,baseUrl:e}).then(({solution:a})=>{f({formElement:s,name:"success"}),T({formElement:s,value:a}),HTMLFormElement.prototype.submit.call(s)}).catch(a=>{console.error(a),f({formElement:s,name:"error"})})}catch(r){console.error(r)}};return t.addEventListener("submit",n),{dispose:()=>{t.removeEventListener("submit",n)}}};var x=()=>{Y(),z(),X()},y=class{constructor({publicKey:e,baseUrl:n}){this.publicKey=e,this.baseUrl=n}static init(){x()}async challenge(e){let{onProgress:n}=e||{};return h({publicKey:this.publicKey,baseUrl:this.baseUrl,onProgress:n})}},Y=()=>{typeof document!="undefined"&&(window.__BOTPOISON_VERSION__="1.0.0")},z=()=>{typeof document!="undefined"&&(window.__BOTPOISON_SUBMIT_LISTENER__||(window.__BOTPOISON_SUBMIT_LISTENER__=!0,B({documentRef:document})))},X=()=>{if(typeof document=="undefined"||window.__BOTPOISON_SESSION_OPENED__)return;window.__BOTPOISON_SESSION_OPENED__=!0;let t=()=>{k()};typeof requestIdleCallback=="function"?requestIdleCallback(t,{timeout:2e3}):setTimeout(t,0)};x();return K(W);})();
1
+ "use strict";var __botpoison=(()=>{var b=Object.defineProperty;var I=Object.getOwnPropertyDescriptor;var A=Object.getOwnPropertyNames;var C=Object.prototype.hasOwnProperty;var L=(n,e)=>{for(var t in e)b(n,t,{get:e[t],enumerable:!0})},N=(n,e,t,r)=>{if(e&&typeof e=="object"||typeof e=="function")for(let o of A(e))!C.call(n,o)&&o!==t&&b(n,o,{get:()=>e[o],enumerable:!(r=I(e,o))||r.enumerable});return n};var w=n=>N(b({},"__esModule",{value:!0}),n);var H={};L(H,{default:()=>E});var d="https://api.botpoison.com",u="_botpoison",m={"Content-Type":"text/plain",Accept:"application/json"};var f=({formElement:n,value:e})=>{let t=n.querySelector(`input[name="${u}"]`);if(!t){let r=n.ownerDocument;t=r.createElement("input"),t.setAttribute("type","hidden"),t.setAttribute("name",u),r.getElementById(u)||t.setAttribute("id",u),n.appendChild(t)}return t.setAttribute("value",e),t},g=({formElement:n,name:e})=>{n.dispatchEvent(new CustomEvent(`botpoison-challenge-${e}`))};var U=n=>new Promise(e=>setTimeout(e,n)),h=n=>{let e="";for(let t of n)e+=t.toString(16).padStart(2,"0");return BigInt(`0x${e}`)},v=n=>{let e=atob(n),t=new Uint8Array(e.length);for(let r=0;r<e.length;r++)t[r]=e.charCodeAt(r);return t},B=(n,e)=>{let t=n.toString(16).padStart(e*2,"0"),r="";for(let o=0;o<t.length;o+=2)r+=String.fromCharCode(parseInt(t.substring(o,o+2),16));return btoa(r)},R=async({nonce:n,modulus:e,byteLength:t})=>{let r=new TextEncoder,o=[],s=0;for(let l=0;s<t;l++){let p=new Uint8Array(await crypto.subtle.digest("SHA-256",r.encode(`${n}:${l}`)));o.push(p),s+=p.length}let a=new Uint8Array(s),i=0;for(let l of o)a.set(l,i),i+=l.length;let c=h(a.subarray(0,t))%e;return c*c%e},x=async({x:n,modulus:e,squarings:t,onProgress:r})=>{let o=n;for(let s=0;s<t;s++)o=o*o%e,s%2e4===19999&&(r==null||r(s/t),await U(0));return o},P="sundial",M=async({challenge:n,onProgress:e})=>{let{algo:t,nonce:r,modulus:o,squarings:s}=n.payload;if(t!==void 0&&t!==P)throw new Error(`Botpoison: this version cannot solve "${t}" challenges. Upgrade @botpoison/browser.`);let a=v(o),i=h(a),c=a.length;e==null||e(0);let l=await R({nonce:r,modulus:i,byteLength:c}),p=await x({x:l,modulus:i,squarings:s,onProgress:e});return e==null||e(1),[B(p,c)]},S=M;var y=({challenge:n,solutions:e,baseUrl:t=d})=>fetch(`${t}/session`,{method:"POST",headers:m,keepalive:!0,body:JSON.stringify({challenge:n,solutions:e})}).then(()=>{},()=>{});var D=()=>typeof location=="undefined"?void 0:location.hostname,_=async({publicKey:n,baseUrl:e=d,onProgress:t})=>{let o=await(await fetch(`${e}/challenge`,{method:"POST",headers:m,body:JSON.stringify({publicKey:n,hostname:D(),version:"1.1.0"})})).json(),s=await S({challenge:o,onProgress:t});return y({challenge:o,solutions:s,baseUrl:e}),{solution:btoa(JSON.stringify({challenge:o,solutions:s}))}};var k=n=>{if(!n||!n.tagName)return;let e=n;if(e.tagName!=="FORM")return;let t=e,r=t.dataset.botpoisonPublicKey;return r?{formElement:t,publicKey:r}:void 0},O=({documentRef:n,baseUrl:e})=>{let t=r=>{try{let o=k(r.target);if(!o)return;let{formElement:s,publicKey:a}=o;r.preventDefault(),g({formElement:s,name:"start"}),_({publicKey:a,baseUrl:e}).then(({solution:i})=>{g({formElement:s,name:"success"}),f({formElement:s,value:i}),HTMLFormElement.prototype.submit.call(s)}).catch(i=>{console.error(i),g({formElement:s,name:"error"})})}catch(o){console.error(o)}};return n.addEventListener("submit",t),{dispose:()=>{n.removeEventListener("submit",t)}}};var T=()=>{K(),F()},E=class{constructor({publicKey:e,baseUrl:t}){this.publicKey=e,this.baseUrl=t}static init(){T()}async challenge(e){let{onProgress:t}=e||{};return _({publicKey:this.publicKey,baseUrl:this.baseUrl,onProgress:t})}},K=()=>{typeof document!="undefined"&&(window.__BOTPOISON_VERSION__="1.1.0")},F=()=>{typeof document!="undefined"&&(window.__BOTPOISON_SUBMIT_LISTENER__||(window.__BOTPOISON_SUBMIT_LISTENER__=!0,O({documentRef:document})))};T();return w(H);})();
2
2
  (function (root, factory) {
3
3
  if (typeof exports === "object" && typeof module !== "undefined") {
4
4
  module.exports = factory();
package/dist/index.mjs CHANGED
@@ -87,6 +87,22 @@ var deriveX = async ({
87
87
  const x = bytesToBigInt(joined.subarray(0, byteLength)) % modulus;
88
88
  return x * x % modulus;
89
89
  };
90
+ var runChain = async ({
91
+ x,
92
+ modulus,
93
+ squarings,
94
+ onProgress
95
+ }) => {
96
+ let y = x;
97
+ for (let i = 0; i < squarings; i++) {
98
+ y = y * y % modulus;
99
+ if (i % YIELD_INTERVAL === YIELD_INTERVAL - 1) {
100
+ onProgress == null ? void 0 : onProgress(i / squarings);
101
+ await sleep(0);
102
+ }
103
+ }
104
+ return y;
105
+ };
90
106
  var ALGO = "sundial";
91
107
  var computeSolutions = async ({
92
108
  challenge,
@@ -102,96 +118,15 @@ var computeSolutions = async ({
102
118
  const modulus = bytesToBigInt(modulusBytes);
103
119
  const byteLength = modulusBytes.length;
104
120
  onProgress == null ? void 0 : onProgress(0);
105
- let y = await deriveX({ nonce, modulus, byteLength });
106
- for (let i = 0; i < squarings; i++) {
107
- y = y * y % modulus;
108
- if (i % YIELD_INTERVAL === YIELD_INTERVAL - 1) {
109
- onProgress == null ? void 0 : onProgress(i / squarings);
110
- await sleep(0);
111
- }
112
- }
121
+ const x = await deriveX({ nonce, modulus, byteLength });
122
+ const y = await runChain({ x, modulus, squarings, onProgress });
113
123
  onProgress == null ? void 0 : onProgress(1);
114
124
  return [bigIntToBase64(y, byteLength)];
115
125
  };
116
126
  var computeSolutions_default = computeSolutions;
117
127
 
118
- // src/storage.ts
119
- var PREFIX = "_botpoison.v2.session.";
120
- var backing;
121
- var memory = /* @__PURE__ */ new Map();
122
- var getBacking = () => {
123
- if (backing !== void 0) {
124
- return backing;
125
- }
126
- try {
127
- const candidate = window.sessionStorage;
128
- const probe = `${PREFIX}probe`;
129
- candidate.setItem(probe, "1");
130
- candidate.removeItem(probe);
131
- backing = candidate;
132
- } catch (e) {
133
- backing = null;
134
- }
135
- return backing;
136
- };
137
- var keyFor = (baseUrl) => `${PREFIX}${baseUrl}`;
138
- var readSessionToken = (baseUrl) => {
139
- var _a;
140
- const store2 = getBacking();
141
- if (!store2) {
142
- return memory.get(keyFor(baseUrl));
143
- }
144
- try {
145
- return (_a = store2.getItem(keyFor(baseUrl))) != null ? _a : void 0;
146
- } catch (e) {
147
- return memory.get(keyFor(baseUrl));
148
- }
149
- };
150
- var writeSessionToken = (baseUrl, token) => {
151
- const store2 = getBacking();
152
- if (store2) {
153
- try {
154
- store2.setItem(keyFor(baseUrl), token);
155
- return;
156
- } catch (e) {
157
- backing = null;
158
- }
159
- }
160
- memory.set(keyFor(baseUrl), token);
161
- };
162
-
163
- // src/session.ts
164
- var inFlight;
165
- var getSessionToken = (baseUrl = DEFAULT_BASE_URL) => readSessionToken(baseUrl);
166
- var store = (baseUrl, body) => {
167
- const token = body == null ? void 0 : body.token;
168
- if (typeof token === "string") {
169
- writeSessionToken(baseUrl, token);
170
- }
171
- };
172
- var openSession = ({
173
- baseUrl = DEFAULT_BASE_URL
174
- } = {}) => {
175
- if (readSessionToken(baseUrl)) {
176
- return Promise.resolve();
177
- }
178
- if (inFlight) {
179
- return inFlight;
180
- }
181
- inFlight = fetch(`${baseUrl}/session`, {
182
- method: "POST",
183
- headers: SIMPLE_REQUEST_HEADERS,
184
- body: "{}"
185
- }).then(async (response) => {
186
- if (response.ok) {
187
- store(baseUrl, await response.json());
188
- }
189
- }).catch(() => void 0).finally(() => {
190
- inFlight = void 0;
191
- });
192
- return inFlight;
193
- };
194
- var exchangeSolved = ({
128
+ // src/reportWork.ts
129
+ var reportWork = ({
195
130
  challenge,
196
131
  solutions,
197
132
  baseUrl = DEFAULT_BASE_URL
@@ -199,16 +134,11 @@ var exchangeSolved = ({
199
134
  method: "POST",
200
135
  headers: SIMPLE_REQUEST_HEADERS,
201
136
  keepalive: true,
202
- body: JSON.stringify({
203
- challenge,
204
- solutions,
205
- token: readSessionToken(baseUrl)
206
- })
207
- }).then(async (response) => {
208
- if (response.ok) {
209
- store(baseUrl, await response.json());
210
- }
211
- }).catch(() => void 0);
137
+ body: JSON.stringify({ challenge, solutions })
138
+ }).then(
139
+ () => void 0,
140
+ () => void 0
141
+ );
212
142
 
213
143
  // src/runChallenge.ts
214
144
  var hostname = () => typeof location === "undefined" ? void 0 : location.hostname;
@@ -225,8 +155,7 @@ var runChallenge = async ({
225
155
  hostname: hostname(),
226
156
  // Copies of this bundle stay embedded in sites for years, so the API
227
157
  // has to start collecting this long before it can act on it.
228
- version: "1.0.0",
229
- token: getSessionToken(baseUrl)
158
+ version: "1.1.0"
230
159
  })
231
160
  });
232
161
  const challenge = await response.json();
@@ -234,7 +163,7 @@ var runChallenge = async ({
234
163
  challenge,
235
164
  onProgress
236
165
  });
237
- void exchangeSolved({ challenge, solutions, baseUrl });
166
+ void reportWork({ challenge, solutions, baseUrl });
238
167
  const serialized = btoa(
239
168
  JSON.stringify({
240
169
  challenge,
@@ -296,7 +225,6 @@ var createAutoSubmit = ({
296
225
  var init = () => {
297
226
  addVersion();
298
227
  addSubmitListener();
299
- startSession();
300
228
  };
301
229
  var Botpoison = class {
302
230
  constructor({ publicKey, baseUrl }) {
@@ -317,7 +245,7 @@ var Botpoison = class {
317
245
  };
318
246
  var addVersion = () => {
319
247
  if (typeof document !== "undefined") {
320
- window.__BOTPOISON_VERSION__ = "1.0.0";
248
+ window.__BOTPOISON_VERSION__ = "1.1.0";
321
249
  }
322
250
  };
323
251
  var addSubmitListener = () => {
@@ -328,18 +256,6 @@ var addSubmitListener = () => {
328
256
  }
329
257
  }
330
258
  };
331
- var startSession = () => {
332
- if (typeof document === "undefined" || window.__BOTPOISON_SESSION_OPENED__) {
333
- return;
334
- }
335
- window.__BOTPOISON_SESSION_OPENED__ = true;
336
- const open = () => void openSession();
337
- if (typeof requestIdleCallback === "function") {
338
- requestIdleCallback(open, { timeout: 2e3 });
339
- } else {
340
- setTimeout(open, 0);
341
- }
342
- };
343
259
  init();
344
260
  export {
345
261
  Botpoison as default
package/package.json CHANGED
@@ -1,12 +1,7 @@
1
1
  {
2
2
  "name": "@botpoison/browser",
3
+ "version": "1.1.0",
3
4
  "private": false,
4
- "version": "1.0.0",
5
- "main": "./dist/index.js",
6
- "module": "./dist/index.mjs",
7
- "types": "./dist/index.d.ts",
8
- "unpkg": "./dist/index.js",
9
- "jsdelivr": "./dist/index.js",
10
5
  "exports": {
11
6
  ".": {
12
7
  "types": "./dist/index.d.ts",
@@ -15,23 +10,30 @@
15
10
  },
16
11
  "./package.json": "./package.json"
17
12
  },
13
+ "main": "./dist/index.js",
14
+ "jsdelivr": "./dist/index.js",
15
+ "unpkg": "./dist/index.js",
16
+ "module": "./dist/index.mjs",
17
+ "types": "./dist/index.d.ts",
18
18
  "files": [
19
19
  "dist"
20
20
  ],
21
- "engines": {
22
- "node": ">=18"
23
- },
24
21
  "devDependencies": {
25
22
  "@types/node": "^22.20.1",
26
- "happy-dom": "^20.11.1",
23
+ "@vitest/coverage-v8": "^4.1.11",
24
+ "happy-dom": "^20.14.0",
27
25
  "tsup": "^8.5.1",
28
26
  "typescript": "^6.0.3",
29
27
  "vite": "^6.4.3",
30
- "vitest": "^4.1.10"
28
+ "vitest": "^4.1.11"
29
+ },
30
+ "engines": {
31
+ "node": ">=18"
31
32
  },
32
33
  "scripts": {
33
34
  "build": "bash scripts/build.sh",
34
35
  "test": "bash scripts/test.sh",
36
+ "test:coverage": "bash scripts/test.sh --coverage",
35
37
  "typecheck": "bash scripts/typecheck.sh"
36
38
  }
37
39
  }