@duckity/js 0.2.0 → 0.2.1

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.js CHANGED
@@ -3,4 +3,4 @@
3
3
  * Copyright 2019 Google LLC
4
4
  * SPDX-License-Identifier: Apache-2.0
5
5
  */
6
- const e=Symbol("Comlink.proxy"),t=Symbol("Comlink.endpoint"),n=Symbol("Comlink.releaseProxy"),r=Symbol("Comlink.finalizer"),a=Symbol("Comlink.thrown"),i=e=>"object"==typeof e&&null!==e||"function"==typeof e,s=new Map([["proxy",{canHandle:t=>i(t)&&t[e],serialize(e){const{port1:t,port2:n}=new MessageChannel;return o(e,t),[n,[n]]},deserialize:e=>(e.start(),u(e))}],["throw",{canHandle:e=>i(e)&&a in e,serialize({value:e}){let t;return t=e instanceof Error?{isError:!0,value:{message:e.message,name:e.name,stack:e.stack}}:{isError:!1,value:e},[t,[]]},deserialize(e){if(e.isError)throw Object.assign(new Error(e.value.message),e.value);throw e.value}}]]);function o(t,n=globalThis,i=["*"]){n.addEventListener("message",function s(u){if(!u||!u.data)return;if(!function(e,t){for(const n of e){if(t===n||"*"===n)return!0;if(n instanceof RegExp&&n.test(t))return!0}return!1}(i,u.origin))return void console.warn(`Invalid origin '${u.origin}' for comlink proxy`);const{id:l,type:p,path:f}=Object.assign({path:[]},u.data),g=(u.data.argumentList||[]).map(w);let d;try{const n=f.slice(0,-1).reduce((e,t)=>e[t],t),r=f.reduce((e,t)=>e[t],t);switch(p){case"GET":d=r;break;case"SET":n[f.slice(-1)[0]]=w(u.data.value),d=!0;break;case"APPLY":d=r.apply(n,g);break;case"CONSTRUCT":d=function(t){return Object.assign(t,{[e]:!0})}(new r(...g));break;case"ENDPOINT":{const{port1:e,port2:n}=new MessageChannel;o(t,n),d=function(e,t){return m.set(e,t),e}(e,[e])}break;case"RELEASE":d=void 0;break;default:return}}catch(e){d={value:e,[a]:0}}Promise.resolve(d).catch(e=>({value:e,[a]:0})).then(e=>{const[a,i]=y(e);n.postMessage(Object.assign(Object.assign({},a),{id:l}),i),"RELEASE"===p&&(n.removeEventListener("message",s),c(n),r in t&&"function"==typeof t[r]&&t[r]())}).catch(e=>{const[t,r]=y({value:new TypeError("Unserializable return value"),[a]:0});n.postMessage(Object.assign(Object.assign({},t),{id:l}),r)})}),n.start&&n.start()}function c(e){(function(e){return"MessagePort"===e.constructor.name})(e)&&e.close()}function u(e,t){const n=new Map;return e.addEventListener("message",function(e){const{data:t}=e;if(!t||!t.id)return;const r=n.get(t.id);if(r)try{r(t)}finally{n.delete(t.id)}}),d(e,n,[],t)}function l(e){if(e)throw new Error("Proxy has been released and is not useable")}function p(e){return E(e,new Map,{type:"RELEASE"}).then(()=>{c(e)})}const f=new WeakMap,g="FinalizationRegistry"in globalThis&&new FinalizationRegistry(e=>{const t=(f.get(e)||0)-1;f.set(e,t),0===t&&p(e)});function d(e,r,a=[],i=function(){}){let s=!1;const o=new Proxy(i,{get(t,i){if(l(s),i===n)return()=>{!function(e){g&&g.unregister(e)}(o),p(e),r.clear(),s=!0};if("then"===i){if(0===a.length)return{then:()=>o};const t=E(e,r,{type:"GET",path:a.map(e=>e.toString())}).then(w);return t.then.bind(t)}return d(e,r,[...a,i])},set(t,n,i){l(s);const[o,c]=y(i);return E(e,r,{type:"SET",path:[...a,n].map(e=>e.toString()),value:o},c).then(w)},apply(n,i,o){l(s);const c=a[a.length-1];if(c===t)return E(e,r,{type:"ENDPOINT"}).then(w);if("bind"===c)return d(e,r,a.slice(0,-1));const[u,p]=h(o);return E(e,r,{type:"APPLY",path:a.map(e=>e.toString()),argumentList:u},p).then(w)},construct(t,n){l(s);const[i,o]=h(n);return E(e,r,{type:"CONSTRUCT",path:a.map(e=>e.toString()),argumentList:i},o).then(w)}});return function(e,t){const n=(f.get(t)||0)+1;f.set(t,n),g&&g.register(e,t,e)}(o,e),o}function h(e){const t=e.map(y);return[t.map(e=>e[0]),(n=t.map(e=>e[1]),Array.prototype.concat.apply([],n))];var n}const m=new WeakMap;function y(e){for(const[t,n]of s)if(n.canHandle(e)){const[r,a]=n.serialize(e);return[{type:"HANDLER",name:t,value:r},a]}return[{type:"RAW",value:e},m.get(e)||[]]}function w(e){switch(e.type){case"HANDLER":return s.get(e.name).deserialize(e.value);case"RAW":return e.value}}function E(e,t,n,r){return new Promise(a=>{const i=new Array(4).fill(0).map(()=>Math.floor(Math.random()*Number.MAX_SAFE_INTEGER).toString(16)).join("-");t.set(i,a),e.start&&e.start(),e.postMessage(Object.assign({id:i},n),r)})}var b=u(new Worker(new URL("./worker.js",import.meta.url),{type:"module"}));function v(e,t){return async function(e,t){const n=await fetch(e,t);let r;try{r=await n.json()}catch{r=await n.text()}if(!n.ok)throw new Error(r?.message||"Request failed");return r}(e,{method:"POST",headers:{...t?.headers},...t,body:void 0})}async function k(e,t){t?.api&&t.api.endsWith("/")&&(t.api=t.api.slice(0,-1));let n=await v(`${t?.api||"https://api.duckity.com/d1"}/challenges/${e}/issue`);return await b.solve(n.challenge)}export{k as solve};
6
+ const e=Symbol("Comlink.proxy"),t=Symbol("Comlink.endpoint"),n=Symbol("Comlink.releaseProxy"),r=Symbol("Comlink.finalizer"),a=Symbol("Comlink.thrown"),i=e=>"object"==typeof e&&null!==e||"function"==typeof e,o=new Map([["proxy",{canHandle:t=>i(t)&&t[e],serialize(e){const{port1:t,port2:n}=new MessageChannel;return s(e,t),[n,[n]]},deserialize:e=>(e.start(),u(e))}],["throw",{canHandle:e=>i(e)&&a in e,serialize({value:e}){let t;return t=e instanceof Error?{isError:!0,value:{message:e.message,name:e.name,stack:e.stack}}:{isError:!1,value:e},[t,[]]},deserialize(e){if(e.isError)throw Object.assign(new Error(e.value.message),e.value);throw e.value}}]]);function s(t,n=globalThis,i=["*"]){n.addEventListener("message",function o(u){if(!u||!u.data)return;if(!function(e,t){for(const n of e){if(t===n||"*"===n)return!0;if(n instanceof RegExp&&n.test(t))return!0}return!1}(i,u.origin))return void console.warn(`Invalid origin '${u.origin}' for comlink proxy`);const{id:l,type:p,path:f}=Object.assign({path:[]},u.data),d=(u.data.argumentList||[]).map(w);let g;try{const n=f.slice(0,-1).reduce((e,t)=>e[t],t),r=f.reduce((e,t)=>e[t],t);switch(p){case"GET":g=r;break;case"SET":n[f.slice(-1)[0]]=w(u.data.value),g=!0;break;case"APPLY":g=r.apply(n,d);break;case"CONSTRUCT":g=function(t){return Object.assign(t,{[e]:!0})}(new r(...d));break;case"ENDPOINT":{const{port1:e,port2:n}=new MessageChannel;s(t,n),g=function(e,t){return m.set(e,t),e}(e,[e])}break;case"RELEASE":g=void 0;break;default:return}}catch(e){g={value:e,[a]:0}}Promise.resolve(g).catch(e=>({value:e,[a]:0})).then(e=>{const[a,i]=y(e);n.postMessage(Object.assign(Object.assign({},a),{id:l}),i),"RELEASE"===p&&(n.removeEventListener("message",o),c(n),r in t&&"function"==typeof t[r]&&t[r]())}).catch(e=>{const[t,r]=y({value:new TypeError("Unserializable return value"),[a]:0});n.postMessage(Object.assign(Object.assign({},t),{id:l}),r)})}),n.start&&n.start()}function c(e){(function(e){return"MessagePort"===e.constructor.name})(e)&&e.close()}function u(e,t){const n=new Map;return e.addEventListener("message",function(e){const{data:t}=e;if(!t||!t.id)return;const r=n.get(t.id);if(r)try{r(t)}finally{n.delete(t.id)}}),g(e,n,[],t)}function l(e){if(e)throw new Error("Proxy has been released and is not useable")}function p(e){return E(e,new Map,{type:"RELEASE"}).then(()=>{c(e)})}const f=new WeakMap,d="FinalizationRegistry"in globalThis&&new FinalizationRegistry(e=>{const t=(f.get(e)||0)-1;f.set(e,t),0===t&&p(e)});function g(e,r,a=[],i=function(){}){let o=!1;const s=new Proxy(i,{get(t,i){if(l(o),i===n)return()=>{!function(e){d&&d.unregister(e)}(s),p(e),r.clear(),o=!0};if("then"===i){if(0===a.length)return{then:()=>s};const t=E(e,r,{type:"GET",path:a.map(e=>e.toString())}).then(w);return t.then.bind(t)}return g(e,r,[...a,i])},set(t,n,i){l(o);const[s,c]=y(i);return E(e,r,{type:"SET",path:[...a,n].map(e=>e.toString()),value:s},c).then(w)},apply(n,i,s){l(o);const c=a[a.length-1];if(c===t)return E(e,r,{type:"ENDPOINT"}).then(w);if("bind"===c)return g(e,r,a.slice(0,-1));const[u,p]=h(s);return E(e,r,{type:"APPLY",path:a.map(e=>e.toString()),argumentList:u},p).then(w)},construct(t,n){l(o);const[i,s]=h(n);return E(e,r,{type:"CONSTRUCT",path:a.map(e=>e.toString()),argumentList:i},s).then(w)}});return function(e,t){const n=(f.get(t)||0)+1;f.set(t,n),d&&d.register(e,t,e)}(s,e),s}function h(e){const t=e.map(y);return[t.map(e=>e[0]),(n=t.map(e=>e[1]),Array.prototype.concat.apply([],n))];var n}const m=new WeakMap;function y(e){for(const[t,n]of o)if(n.canHandle(e)){const[r,a]=n.serialize(e);return[{type:"HANDLER",name:t,value:r},a]}return[{type:"RAW",value:e},m.get(e)||[]]}function w(e){switch(e.type){case"HANDLER":return o.get(e.name).deserialize(e.value);case"RAW":return e.value}}function E(e,t,n,r){return new Promise(a=>{const i=new Array(4).fill(0).map(()=>Math.floor(Math.random()*Number.MAX_SAFE_INTEGER).toString(16)).join("-");t.set(i,a),e.start&&e.start(),e.postMessage(Object.assign({id:i},n),r)})}let b,v;function k(e,t){return async function(e,t){const n=await fetch(e,t);let r;try{r=await n.json()}catch{r=await n.text()}if(!n.ok)throw new Error(r?.message||"Request failed");return r}(e,{method:"POST",headers:{...t?.headers},...t,body:void 0})}async function S(e,t){t?.api&&t.api.endsWith("/")&&(t.api=t.api.slice(0,-1));let n=await k(`${t?.api||"https://api.duckity.com/d1"}/challenges/${e}/issue`);return await function(){if("undefined"==typeof window)throw new Error("Worker API can only be used in the browser");return v||(b=new Worker(new URL("./worker.js",import.meta.url),{type:"module"}),v=u(b)),v}().solve(n.challenge)}export{S as solve};
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@duckity/js",
3
3
  "type": "module",
4
- "version": "0.2.0",
4
+ "version": "0.2.1",
5
5
  "module": "src/index.ts",
6
6
  "types": "dist/index.d.ts",
7
7
  "collaborators": [
package/src/index.ts CHANGED
@@ -1,4 +1,4 @@
1
- import wrapper from "./processing/wrapper";
1
+ import { getWorkerApi } from "./processing/wrapper";
2
2
  import { post } from "./requests";
3
3
 
4
4
  /**
@@ -13,19 +13,6 @@ export interface GetDuckityChallengeOptions {
13
13
  * Only update this when self-hosting a Duckling.
14
14
  */
15
15
  api?: string;
16
-
17
- // /**
18
- // * When this is `false`, the client will assume it is allowed to get a challenge the first time
19
- // * one is requested. This may not always be true (when the client has an active penalty or used
20
- // * all of their allowed requests in another session), case in which the client may be penalized.
21
- // *
22
- // * When this is `true`, an extra request will be made to the Duckling API to synchronize the
23
- // * client's state with the server's state. This extra request will not issue a challenge, rather
24
- // * only synchronize the client's state with the server's state. If the client is penalized or has
25
- // * to wait before being allowed to get a challenge, the client will be informed of this. It'll
26
- // * avoid getting it unnecessarily penalized at the cost of an extra request.
27
- // */
28
- // sync?: boolean;
29
16
  }
30
17
 
31
18
  /**
@@ -59,7 +46,7 @@ export async function solve(
59
46
  `${options?.api || "https://api.duckity.com/d1"}/challenges/${protectionProfileId}/issue`,
60
47
  );
61
48
 
62
- let solution = await wrapper.solve(response.challenge);
49
+ let solution = await getWorkerApi().solve(response.challenge);
63
50
 
64
51
  return solution;
65
52
  }
@@ -1,17 +1,29 @@
1
1
  import * as Comlink from "comlink";
2
2
 
3
- /**
4
- * Web Worker that handles the processing of the challenges.
5
- */
6
- const worker = new Worker(new URL("./worker.js", import.meta.url), {
7
- type: "module",
8
- });
3
+ type WorkerApi = {
4
+ solve(challenge: string): Promise<string>;
5
+ };
6
+
7
+ let worker: Worker | undefined;
8
+ let api: Comlink.Remote<WorkerApi> | undefined;
9
9
 
10
10
  /**
11
- * Wrap the worker with Comlink to allow for easy communication between the main thread and the
12
- * worker thread. The worker exposes a `solve` function that takes a challenge string and returns a
11
+ * Wraps the worker with Comlink to allow for easy communication between the main thread and the
12
+ * worker thread. The API exposes a `solve` function that takes a challenge string and returns a
13
13
  * promise that resolves to the solution string.
14
14
  */
15
- export default Comlink.wrap<{
16
- solve(challenge: string): Promise<string>;
17
- }>(worker);
15
+ export function getWorkerApi(): Comlink.Remote<WorkerApi> {
16
+ if (typeof window === "undefined") {
17
+ throw new Error("Worker API can only be used in the browser");
18
+ }
19
+
20
+ if (!api) {
21
+ worker = new Worker(new URL("./worker.js", import.meta.url), {
22
+ type: "module",
23
+ });
24
+
25
+ api = Comlink.wrap<WorkerApi>(worker);
26
+ }
27
+
28
+ return api;
29
+ }