@nimiq/hub-api
Advanced tools
Comparing version 0.5.0 to 1.0.0
@@ -161,2 +161,22 @@ import { PostMessageRpcClient, RedirectRpcClient } from '@nimiq/rpc'; | ||
} | ||
/** | ||
* Public API | ||
*/ | ||
checkout(request, requestBehavior = this._defaultBehavior) { | ||
return this._request(requestBehavior, RequestType.CHECKOUT, [request]); | ||
} | ||
chooseAddress(request, requestBehavior = this._defaultBehavior) { | ||
return this._request(requestBehavior, RequestType.CHOOSE_ADDRESS, [request]); | ||
} | ||
signTransaction(request, requestBehavior = this._defaultBehavior) { | ||
return this._request(requestBehavior, RequestType.SIGN_TRANSACTION, [request]); | ||
} | ||
signMessage(request, requestBehavior = this._defaultBehavior) { | ||
return this._request(requestBehavior, RequestType.SIGN_MESSAGE, [request]); | ||
} | ||
/** | ||
* Account Management | ||
* | ||
* Only accessible from Nimiq domains. | ||
*/ | ||
onboard(request, requestBehavior = this._defaultBehavior) { | ||
@@ -171,11 +191,2 @@ return this._request(requestBehavior, RequestType.ONBOARD, [request]); | ||
} | ||
chooseAddress(request, requestBehavior = this._defaultBehavior) { | ||
return this._request(requestBehavior, RequestType.CHOOSE_ADDRESS, [request]); | ||
} | ||
signTransaction(request, requestBehavior = this._defaultBehavior) { | ||
return this._request(requestBehavior, RequestType.SIGN_TRANSACTION, [request]); | ||
} | ||
checkout(request, requestBehavior = this._defaultBehavior) { | ||
return this._request(requestBehavior, RequestType.CHECKOUT, [request]); | ||
} | ||
logout(request, requestBehavior = this._defaultBehavior) { | ||
@@ -196,7 +207,4 @@ return this._request(requestBehavior, RequestType.LOGOUT, [request]); | ||
} | ||
signMessage(request, requestBehavior = this._defaultBehavior) { | ||
return this._request(requestBehavior, RequestType.SIGN_MESSAGE, [request]); | ||
} | ||
migrate(requestBehavior = this._defaultBehavior) { | ||
return this._request(requestBehavior, RequestType.MIGRATE, [{ appName: 'Accounts Client' }]); | ||
return this._request(requestBehavior, RequestType.MIGRATE, [{ appName: 'Account list' }]); | ||
} | ||
@@ -203,0 +211,0 @@ /** |
@@ -165,2 +165,22 @@ (function (global, factory) { | ||
} | ||
/** | ||
* Public API | ||
*/ | ||
checkout(request, requestBehavior = this._defaultBehavior) { | ||
return this._request(requestBehavior, RequestType.CHECKOUT, [request]); | ||
} | ||
chooseAddress(request, requestBehavior = this._defaultBehavior) { | ||
return this._request(requestBehavior, RequestType.CHOOSE_ADDRESS, [request]); | ||
} | ||
signTransaction(request, requestBehavior = this._defaultBehavior) { | ||
return this._request(requestBehavior, RequestType.SIGN_TRANSACTION, [request]); | ||
} | ||
signMessage(request, requestBehavior = this._defaultBehavior) { | ||
return this._request(requestBehavior, RequestType.SIGN_MESSAGE, [request]); | ||
} | ||
/** | ||
* Account Management | ||
* | ||
* Only accessible from Nimiq domains. | ||
*/ | ||
onboard(request, requestBehavior = this._defaultBehavior) { | ||
@@ -175,11 +195,2 @@ return this._request(requestBehavior, RequestType.ONBOARD, [request]); | ||
} | ||
chooseAddress(request, requestBehavior = this._defaultBehavior) { | ||
return this._request(requestBehavior, RequestType.CHOOSE_ADDRESS, [request]); | ||
} | ||
signTransaction(request, requestBehavior = this._defaultBehavior) { | ||
return this._request(requestBehavior, RequestType.SIGN_TRANSACTION, [request]); | ||
} | ||
checkout(request, requestBehavior = this._defaultBehavior) { | ||
return this._request(requestBehavior, RequestType.CHECKOUT, [request]); | ||
} | ||
logout(request, requestBehavior = this._defaultBehavior) { | ||
@@ -200,7 +211,4 @@ return this._request(requestBehavior, RequestType.LOGOUT, [request]); | ||
} | ||
signMessage(request, requestBehavior = this._defaultBehavior) { | ||
return this._request(requestBehavior, RequestType.SIGN_MESSAGE, [request]); | ||
} | ||
migrate(requestBehavior = this._defaultBehavior) { | ||
return this._request(requestBehavior, RequestType.MIGRATE, [{ appName: 'Accounts Client' }]); | ||
return this._request(requestBehavior, RequestType.MIGRATE, [{ appName: 'Account list' }]); | ||
} | ||
@@ -207,0 +215,0 @@ /** |
@@ -1,1 +0,1 @@ | ||
class e{static byteLength(t){const[s,r]=e._getLengths(t);return e._byteLength(s,r)}static decode(t){e._initRevLookup();const[s,r]=e._getLengths(t),n=new Uint8Array(e._byteLength(s,r));let i=0;const o=r>0?s-4:s;let a=0;for(;a<o;a+=4){const s=e._revLookup[t.charCodeAt(a)]<<18|e._revLookup[t.charCodeAt(a+1)]<<12|e._revLookup[t.charCodeAt(a+2)]<<6|e._revLookup[t.charCodeAt(a+3)];n[i++]=s>>16&255,n[i++]=s>>8&255,n[i++]=255&s}if(2===r){const s=e._revLookup[t.charCodeAt(a)]<<2|e._revLookup[t.charCodeAt(a+1)]>>4;n[i++]=255&s}if(1===r){const s=e._revLookup[t.charCodeAt(a)]<<10|e._revLookup[t.charCodeAt(a+1)]<<4|e._revLookup[t.charCodeAt(a+2)]>>2;n[i++]=s>>8&255,n[i]=255&s}return n}static encode(t){const s=t.length,r=s%3,n=[];for(let i=0,o=s-r;i<o;i+=16383)n.push(e._encodeChunk(t,i,i+16383>o?o:i+16383));if(1===r){const r=t[s-1];n.push(e._lookup[r>>2]+e._lookup[r<<4&63]+"==")}else if(2===r){const r=(t[s-2]<<8)+t[s-1];n.push(e._lookup[r>>10]+e._lookup[r>>4&63]+e._lookup[r<<2&63]+"=")}return n.join("")}static encodeUrl(t){return e.encode(t).replace(/\//g,"_").replace(/\+/g,"-").replace(/=/g,".")}static decodeUrl(t){return e.decode(t.replace(/_/g,"/").replace(/-/g,"+").replace(/\./g,"="))}static _initRevLookup(){if(0===e._revLookup.length){e._revLookup=[];for(let t=0,s=e._lookup.length;t<s;t++)e._revLookup[e._lookup.charCodeAt(t)]=t;e._revLookup["-".charCodeAt(0)]=62,e._revLookup["_".charCodeAt(0)]=63}}static _getLengths(e){const t=e.length;if(t%4>0)throw new Error("Invalid string. Length must be a multiple of 4");let s=e.indexOf("=");return-1===s&&(s=t),[s,s===t?0:4-s%4]}static _byteLength(e,t){return 3*(e+t)/4-t}static _tripletToBase64(t){return e._lookup[t>>18&63]+e._lookup[t>>12&63]+e._lookup[t>>6&63]+e._lookup[63&t]}static _encodeChunk(t,s,r){const n=[];for(let i=s;i<r;i+=3){const s=(t[i]<<16&16711680)+(t[i+1]<<8&65280)+(255&t[i+2]);n.push(e._tripletToBase64(s))}return n.join("")}}var t,s;e._lookup="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/",e._revLookup=[],function(e){e[e.UINT8_ARRAY=0]="UINT8_ARRAY"}(t||(t={}));class r{static stringify(e){return JSON.stringify(e,r._jsonifyType)}static parse(e){return JSON.parse(e,r._parseType)}static _parseType(s,n){if(n&&n.hasOwnProperty&&n.hasOwnProperty(r.TYPE_SYMBOL)&&n.hasOwnProperty(r.VALUE_SYMBOL))switch(n[r.TYPE_SYMBOL]){case t.UINT8_ARRAY:return e.decode(n[r.VALUE_SYMBOL])}return n}static _jsonifyType(s,n){return n instanceof Uint8Array?r._typedObject(t.UINT8_ARRAY,e.encode(n)):n}static _typedObject(e,t){const s={};return s[r.TYPE_SYMBOL]=e,s[r.VALUE_SYMBOL]=t,s}}r.TYPE_SYMBOL="__",r.VALUE_SYMBOL="v";class n{static generateRandomId(){const e=new Uint32Array(1);return crypto.getRandomValues(e),e[0]}}!function(e){e.OK="ok",e.ERROR="error"}(s||(s={}));const i="<postMessage>";class o{constructor(e=!0){this._store=e?window.sessionStorage:null,this._validIds=new Map,e&&this._restoreIds()}static _decodeIds(e){const t=r.parse(e),s=new Map;for(const e of Object.keys(t)){const r=parseInt(e,10);s.set(isNaN(r)?e:r,t[e])}return s}has(e){return this._validIds.has(e)}getCommand(e){const t=this._validIds.get(e);return t?t[0]:null}getState(e){const t=this._validIds.get(e);return t?t[1]:null}add(e,t,s=null){this._validIds.set(e,[t,s]),this._storeIds()}remove(e){this._validIds.delete(e),this._storeIds()}clear(){this._validIds.clear(),this._store&&this._store.removeItem(o.KEY)}_encodeIds(){const e=Object.create(null);for(const[t,s]of this._validIds)e[t]=s;return r.stringify(e)}_restoreIds(){const e=this._store.getItem(o.KEY);e&&(this._validIds=o._decodeIds(e))}_storeIds(){this._store&&this._store.setItem(o.KEY,this._encodeIds())}}o.KEY="rpcRequests";class a{static receiveRedirectCommand(e){const t=new URL(e.href);if(!document.referrer)return null;const s=new URL(document.referrer),n=new URLSearchParams(t.search),o=new URLSearchParams(t.hash.substring(1));if(!o.has("id"))return null;const c=parseInt(o.get("id"),10);if(o.delete("id"),n.set(a.URL_SEARCHPARAM_NAME,c.toString()),!o.has("command"))return null;const l=o.get("command");if(o.delete("command"),!o.has("returnURL"))return null;const h=o.get("returnURL");o.delete("returnURL");const d=h===i&&(window.opener||window.parent);if(!d&&new URL(h).origin!==s.origin)return null;let u=[];if(o.has("args"))try{u=r.parse(o.get("args"))}catch(e){}return u=Array.isArray(u)?u:[],o.delete("args"),t.search=n.toString(),this._setUrlFragment(t,o),history.replaceState(history.state,"",t.href),{origin:s.origin,data:{id:c,command:l,args:u},returnURL:h,source:d?window.opener||window.parent:null}}static receiveRedirectResponse(e){const t=new URL(e.href);if(!document.referrer)return null;const n=new URL(document.referrer),i=new URLSearchParams(t.search),o=new URLSearchParams(t.hash.substring(1));if(!o.has("id"))return null;const c=parseInt(o.get("id"),10);if(o.delete("id"),i.set(a.URL_SEARCHPARAM_NAME,c.toString()),!o.has("status"))return null;const l=o.get("status")===s.OK?s.OK:s.ERROR;if(o.delete("status"),!o.has("result"))return null;const h=r.parse(o.get("result"));return o.delete("result"),t.search=i.toString(),this._setUrlFragment(t,o),history.replaceState(history.state,"",t.href),{origin:n.origin,data:{id:c,status:l,result:h}}}static prepareRedirectReply(e,t,s){const n=new URL(e.returnURL),i=new URLSearchParams(n.hash.substring(1));return i.set("id",e.id.toString()),i.set("status",t),i.set("result",r.stringify(s)),n.hash=i.toString(),n.href}static prepareRedirectInvocation(e,t,s,n,i){const o=new URL(e),a=new URLSearchParams(o.hash.substring(1));return a.set("id",t.toString()),a.set("returnURL",s),a.set("command",n),Array.isArray(i)&&a.set("args",r.stringify(i)),o.hash=a.toString(),o.href}static _setUrlFragment(e,t){t.toString().endsWith("=")?e.hash=t.toString().slice(0,-1):e.hash=t.toString()}}a.URL_SEARCHPARAM_NAME="rpcId";class c{constructor(e,t=!1){this._allowedOrigin=e,this._waitingRequests=new o(t),this._responseHandlers=new Map,this._preserveRequests=!1}onResponse(e,t,s){this._responseHandlers.set(e,{resolve:t,reject:s})}_receive(e){if(!e.data||!e.data.status||!e.data.id||"*"!==this._allowedOrigin&&e.origin!==this._allowedOrigin)return!1;const t=e.data,r=this._getCallback(t.id),n=this._waitingRequests.getState(t.id);if(r){if(this._preserveRequests||(this._waitingRequests.remove(t.id),this._responseHandlers.delete(t.id)),console.debug("RpcClient RECEIVE",t),t.status===s.OK)r.resolve(t.result,t.id,n);else if(t.status===s.ERROR){const e=new Error(t.result.message);t.result.stack&&(e.stack=t.result.stack),t.result.name&&(e.name=t.result.name),r.reject(e,t.id,n)}return!0}return console.warn("Unknown RPC response:",t),!1}_getCallback(e){if(this._responseHandlers.has(e))return this._responseHandlers.get(e);{const t=this._waitingRequests.getCommand(e);if(t)return this._responseHandlers.get(t)}}}class l extends c{constructor(e,t){super(t),this._serverCloseCheckInterval=-1,this._target=e,this._connectionState=0,this._receiveListener=this._receive.bind(this)}async init(){2!==this._connectionState&&(await this._connect(),window.addEventListener("message",this._receiveListener),-1===this._serverCloseCheckInterval&&(this._serverCloseCheckInterval=window.setInterval(()=>this._checkIfServerClosed(),300)))}async call(e,...t){return this._call({command:e,args:t,id:n.generateRandomId()})}close(){this._connectionState=0,window.removeEventListener("message",this._receiveListener),window.clearInterval(this._serverCloseCheckInterval),this._serverCloseCheckInterval=-1;for(const[e,{reject:t}]of this._responseHandlers){const s=this._waitingRequests.getState(e);t("Connection was closed","number"==typeof e?e:void 0,s)}this._waitingRequests.clear(),this._responseHandlers.clear(),this._target&&this._target.closed&&(this._target=null)}_receive(e){return e.source===this._target&&super._receive(e)}async _call(e){if(!this._target||this._target.closed)throw new Error("Connection was closed.");if(2!==this._connectionState)throw new Error("Client is not connected, call init first");return new Promise((t,s)=>{this._responseHandlers.set(e.id,{resolve:t,reject:s}),this._waitingRequests.add(e.id,e.command),console.debug("RpcClient REQUEST",e.command,e.args),this._target.postMessage(e,this._allowedOrigin)})}_connect(){if(2!==this._connectionState)return this._connectionState=1,new Promise((e,t)=>{const r=t=>{const{source:n,origin:i,data:o}=t;if(n===this._target&&o.status===s.OK&&"pong"===o.result&&1===o.id&&("*"===this._allowedOrigin||i===this._allowedOrigin)){if(o.result.stack){const e=new Error(o.result.message);e.stack=o.result.stack,o.result.name&&(e.name=o.result.name),console.error(e)}window.removeEventListener("message",r),this._connectionState=2,console.log("RpcClient: Connection established"),e(!0)}};window.addEventListener("message",r);const n=()=>{if(2!==this._connectionState){if(0===this._connectionState||this._checkIfServerClosed())return window.removeEventListener("message",r),void t(new Error("Connection was closed"));try{this._target.postMessage({command:"ping",id:1},this._allowedOrigin)}catch(e){console.error(`postMessage failed: ${e}`)}window.setTimeout(n,100)}};window.setTimeout(n,100)})}_checkIfServerClosed(){return!(this._target&&!this._target.closed)&&(this.close(),!0)}}class h extends c{constructor(e,t,s=!0){super(t,!0),this._target=e,this._preserveRequests=s}async init(){const e=a.receiveRedirectResponse(window.location);if(e)return void this._receive(e);if(this._rejectOnBack())return;const t=new URLSearchParams(window.location.search);if(t.has(a.URL_SEARCHPARAM_NAME)){const e=window.sessionStorage.getItem(`response-${t.get(a.URL_SEARCHPARAM_NAME)}`);if(e)return void this._receive(r.parse(e),!1)}}close(){}call(e,t,s=!1,...r){this.callAndSaveLocalState(e,null,t,s,...r)}callAndSaveLocalState(e,t,s,r=!1,...i){const o=n.generateRandomId(),c=a.prepareRedirectInvocation(this._target,o,e,s,i);this._waitingRequests.add(o,s,t),r&&history.replaceState(Object.assign({},history.state,{rpcBackRejectionId:o}),""),console.debug("RpcClient REQUEST",s,i),window.location.href=c}_receive(e,t=!0){const s=super._receive(e);return s&&t&&window.sessionStorage.setItem(`response-${e.data.id}`,r.stringify(e)),s}_rejectOnBack(){if(!history.state||!history.state.rpcBackRejectionId)return!1;const e=history.state.rpcBackRejectionId;history.replaceState(Object.assign({},history.state,{rpcBackRejectionId:null}),"");const t=this._getCallback(e),s=this._waitingRequests.getState(e);if(t){this._preserveRequests||(this._waitingRequests.remove(e),this._responseHandlers.delete(e)),console.debug("RpcClient BACK");const r=new Error("Request aborted");return t.reject(r,e,s),!0}return!1}}class d{constructor(e){this._type=e}static getAllowedOrigin(e){return new URL(e).origin}async request(e,t,s){throw new Error("Not implemented")}}var u,_;!function(e){e[e.REDIRECT=0]="REDIRECT",e[e.POPUP=1]="POPUP",e[e.IFRAME=2]="IFRAME"}(u||(u={}));class g extends d{static withLocalState(e){return new g(void 0,e)}constructor(e,t){super(u.REDIRECT);const s=window.location;if(this._returnUrl=e||`${s.origin}${s.pathname}`,this._localState=t||{},void 0!==this._localState.__command)throw new Error("Invalid localState: Property '__command' is reserved")}async request(e,t,s){const r=d.getAllowedOrigin(e),n=new h(e,r);await n.init();const i=Object.assign({},this._localState,{__command:t});n.callAndSaveLocalState(this._returnUrl,i,t,!0,...s)}}class p extends d{constructor(e=p.DEFAULT_OPTIONS){super(u.POPUP),this._options=e}async request(e,t,s){const r=d.getAllowedOrigin(e),n=this.createPopup(e),i=new l(n,r);await i.init();try{return await i.call(t,...s)}catch(e){throw e}finally{i.close(),n.close()}}createPopup(e){const t=window.open(e,"NimiqAccounts",this._options);if(!t)throw new Error("Failed to open popup");return t}}p.DEFAULT_OPTIONS="";class w extends d{constructor(){super(u.IFRAME),this._iframe=null,this._client=null}async request(e,t,s){if(this._iframe&&this._iframe.src!==`${e}${w.IFRAME_PATH_SUFFIX}`)throw new Error("Hub iframe is already opened with another endpoint");const r=d.getAllowedOrigin(e);if(this._iframe||(this._iframe=await this.createIFrame(e)),!this._iframe.contentWindow)throw new Error(`IFrame contentWindow is ${typeof this._iframe.contentWindow}`);return this._client||(this._client=new l(this._iframe.contentWindow,r),await this._client.init()),await this._client.call(t,...s)}async createIFrame(e){return new Promise((t,s)=>{const r=document.createElement("iframe");r.name="NimiqAccountsIFrame",r.style.display="none",document.body.appendChild(r),r.src=`${e}${w.IFRAME_PATH_SUFFIX}`,r.onload=(()=>t(r)),r.onerror=s})}}w.IFRAME_PATH_SUFFIX="/iframe.html",function(e){e.LIST="list",e.MIGRATE="migrate",e.CHECKOUT="checkout",e.SIGN_MESSAGE="sign-message",e.SIGN_TRANSACTION="sign-transaction",e.ONBOARD="onboard",e.SIGNUP="signup",e.LOGIN="login",e.EXPORT="export",e.CHANGE_PASSWORD="change-password",e.LOGOUT="logout",e.ADD_ADDRESS="add-address",e.RENAME="rename",e.CHOOSE_ADDRESS="choose-address"}(_||(_={}));class R{constructor(e=R.DEFAULT_ENDPOINT,t){this._endpoint=e,this._defaultBehavior=t||new p(`left=${window.innerWidth/2-400},top=75,width=800,height=850,location=yes,dependent=yes`),this._iframeBehavior=new w,this._redirectClient=new h("",d.getAllowedOrigin(this._endpoint))}static get DEFAULT_ENDPOINT(){const e=location.origin.split(".");switch(e.shift(),e.join(".")){case"nimiq.com":return"https://hub.nimiq.com";case"nimiq-testnet.com":return"https://hub.nimiq-testnet.com";default:return"http://localhost:8080"}}checkRedirectResponse(){return this._redirectClient.init()}on(e,t,s){this._redirectClient.onResponse(e,(e,s,r)=>t(e,r),(e,t,r)=>{s&&s(e,r)})}onboard(e,t=this._defaultBehavior){return this._request(t,_.ONBOARD,[e])}signup(e,t=this._defaultBehavior){return this._request(t,_.SIGNUP,[e])}login(e,t=this._defaultBehavior){return this._request(t,_.LOGIN,[e])}chooseAddress(e,t=this._defaultBehavior){return this._request(t,_.CHOOSE_ADDRESS,[e])}signTransaction(e,t=this._defaultBehavior){return this._request(t,_.SIGN_TRANSACTION,[e])}checkout(e,t=this._defaultBehavior){return this._request(t,_.CHECKOUT,[e])}logout(e,t=this._defaultBehavior){return this._request(t,_.LOGOUT,[e])}export(e,t=this._defaultBehavior){return this._request(t,_.EXPORT,[e])}changePassword(e,t=this._defaultBehavior){return this._request(t,_.CHANGE_PASSWORD,[e])}addAddress(e,t=this._defaultBehavior){return this._request(t,_.ADD_ADDRESS,[e])}rename(e,t=this._defaultBehavior){return this._request(t,_.RENAME,[e])}signMessage(e,t=this._defaultBehavior){return this._request(t,_.SIGN_MESSAGE,[e])}migrate(e=this._defaultBehavior){return this._request(e,_.MIGRATE,[{appName:"Accounts Client"}])}list(e=this._iframeBehavior){return this._request(e,_.LIST,[])}_request(e,t,s){return e.request(this._endpoint,t,s)}}R.RequestType=_,R.RedirectRequestBehavior=g,R.MSG_PREFIX="Nimiq Signed Message:\n";export default R; | ||
class e{static byteLength(t){const[s,r]=e._getLengths(t);return e._byteLength(s,r)}static decode(t){e._initRevLookup();const[s,r]=e._getLengths(t),n=new Uint8Array(e._byteLength(s,r));let i=0;const o=r>0?s-4:s;let a=0;for(;a<o;a+=4){const s=e._revLookup[t.charCodeAt(a)]<<18|e._revLookup[t.charCodeAt(a+1)]<<12|e._revLookup[t.charCodeAt(a+2)]<<6|e._revLookup[t.charCodeAt(a+3)];n[i++]=s>>16&255,n[i++]=s>>8&255,n[i++]=255&s}if(2===r){const s=e._revLookup[t.charCodeAt(a)]<<2|e._revLookup[t.charCodeAt(a+1)]>>4;n[i++]=255&s}if(1===r){const s=e._revLookup[t.charCodeAt(a)]<<10|e._revLookup[t.charCodeAt(a+1)]<<4|e._revLookup[t.charCodeAt(a+2)]>>2;n[i++]=s>>8&255,n[i]=255&s}return n}static encode(t){const s=t.length,r=s%3,n=[];for(let i=0,o=s-r;i<o;i+=16383)n.push(e._encodeChunk(t,i,i+16383>o?o:i+16383));if(1===r){const r=t[s-1];n.push(e._lookup[r>>2]+e._lookup[r<<4&63]+"==")}else if(2===r){const r=(t[s-2]<<8)+t[s-1];n.push(e._lookup[r>>10]+e._lookup[r>>4&63]+e._lookup[r<<2&63]+"=")}return n.join("")}static encodeUrl(t){return e.encode(t).replace(/\//g,"_").replace(/\+/g,"-").replace(/=/g,".")}static decodeUrl(t){return e.decode(t.replace(/_/g,"/").replace(/-/g,"+").replace(/\./g,"="))}static _initRevLookup(){if(0===e._revLookup.length){e._revLookup=[];for(let t=0,s=e._lookup.length;t<s;t++)e._revLookup[e._lookup.charCodeAt(t)]=t;e._revLookup["-".charCodeAt(0)]=62,e._revLookup["_".charCodeAt(0)]=63}}static _getLengths(e){const t=e.length;if(t%4>0)throw new Error("Invalid string. Length must be a multiple of 4");let s=e.indexOf("=");return-1===s&&(s=t),[s,s===t?0:4-s%4]}static _byteLength(e,t){return 3*(e+t)/4-t}static _tripletToBase64(t){return e._lookup[t>>18&63]+e._lookup[t>>12&63]+e._lookup[t>>6&63]+e._lookup[63&t]}static _encodeChunk(t,s,r){const n=[];for(let i=s;i<r;i+=3){const s=(t[i]<<16&16711680)+(t[i+1]<<8&65280)+(255&t[i+2]);n.push(e._tripletToBase64(s))}return n.join("")}}var t,s;e._lookup="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/",e._revLookup=[],function(e){e[e.UINT8_ARRAY=0]="UINT8_ARRAY"}(t||(t={}));class r{static stringify(e){return JSON.stringify(e,r._jsonifyType)}static parse(e){return JSON.parse(e,r._parseType)}static _parseType(s,n){if(n&&n.hasOwnProperty&&n.hasOwnProperty(r.TYPE_SYMBOL)&&n.hasOwnProperty(r.VALUE_SYMBOL))switch(n[r.TYPE_SYMBOL]){case t.UINT8_ARRAY:return e.decode(n[r.VALUE_SYMBOL])}return n}static _jsonifyType(s,n){return n instanceof Uint8Array?r._typedObject(t.UINT8_ARRAY,e.encode(n)):n}static _typedObject(e,t){const s={};return s[r.TYPE_SYMBOL]=e,s[r.VALUE_SYMBOL]=t,s}}r.TYPE_SYMBOL="__",r.VALUE_SYMBOL="v";class n{static generateRandomId(){const e=new Uint32Array(1);return crypto.getRandomValues(e),e[0]}}!function(e){e.OK="ok",e.ERROR="error"}(s||(s={}));const i="<postMessage>";class o{constructor(e=!0){this._store=e?window.sessionStorage:null,this._validIds=new Map,e&&this._restoreIds()}static _decodeIds(e){const t=r.parse(e),s=new Map;for(const e of Object.keys(t)){const r=parseInt(e,10);s.set(isNaN(r)?e:r,t[e])}return s}has(e){return this._validIds.has(e)}getCommand(e){const t=this._validIds.get(e);return t?t[0]:null}getState(e){const t=this._validIds.get(e);return t?t[1]:null}add(e,t,s=null){this._validIds.set(e,[t,s]),this._storeIds()}remove(e){this._validIds.delete(e),this._storeIds()}clear(){this._validIds.clear(),this._store&&this._store.removeItem(o.KEY)}_encodeIds(){const e=Object.create(null);for(const[t,s]of this._validIds)e[t]=s;return r.stringify(e)}_restoreIds(){const e=this._store.getItem(o.KEY);e&&(this._validIds=o._decodeIds(e))}_storeIds(){this._store&&this._store.setItem(o.KEY,this._encodeIds())}}o.KEY="rpcRequests";class a{static receiveRedirectCommand(e){const t=new URL(e.href);if(!document.referrer)return null;const s=new URL(document.referrer),n=new URLSearchParams(t.search),o=new URLSearchParams(t.hash.substring(1));if(!o.has("id"))return null;const c=parseInt(o.get("id"),10);if(o.delete("id"),n.set(a.URL_SEARCHPARAM_NAME,c.toString()),!o.has("command"))return null;const l=o.get("command");if(o.delete("command"),!o.has("returnURL"))return null;const h=o.get("returnURL");o.delete("returnURL");const d=h===i&&(window.opener||window.parent);if(!d&&new URL(h).origin!==s.origin)return null;let u=[];if(o.has("args"))try{u=r.parse(o.get("args"))}catch(e){}return u=Array.isArray(u)?u:[],o.delete("args"),t.search=n.toString(),this._setUrlFragment(t,o),history.replaceState(history.state,"",t.href),{origin:s.origin,data:{id:c,command:l,args:u},returnURL:h,source:d?window.opener||window.parent:null}}static receiveRedirectResponse(e){const t=new URL(e.href);if(!document.referrer)return null;const n=new URL(document.referrer),i=new URLSearchParams(t.search),o=new URLSearchParams(t.hash.substring(1));if(!o.has("id"))return null;const c=parseInt(o.get("id"),10);if(o.delete("id"),i.set(a.URL_SEARCHPARAM_NAME,c.toString()),!o.has("status"))return null;const l=o.get("status")===s.OK?s.OK:s.ERROR;if(o.delete("status"),!o.has("result"))return null;const h=r.parse(o.get("result"));return o.delete("result"),t.search=i.toString(),this._setUrlFragment(t,o),history.replaceState(history.state,"",t.href),{origin:n.origin,data:{id:c,status:l,result:h}}}static prepareRedirectReply(e,t,s){const n=new URL(e.returnURL),i=new URLSearchParams(n.hash.substring(1));return i.set("id",e.id.toString()),i.set("status",t),i.set("result",r.stringify(s)),n.hash=i.toString(),n.href}static prepareRedirectInvocation(e,t,s,n,i){const o=new URL(e),a=new URLSearchParams(o.hash.substring(1));return a.set("id",t.toString()),a.set("returnURL",s),a.set("command",n),Array.isArray(i)&&a.set("args",r.stringify(i)),o.hash=a.toString(),o.href}static _setUrlFragment(e,t){t.toString().endsWith("=")?e.hash=t.toString().slice(0,-1):e.hash=t.toString()}}a.URL_SEARCHPARAM_NAME="rpcId";class c{constructor(e,t=!1){this._allowedOrigin=e,this._waitingRequests=new o(t),this._responseHandlers=new Map,this._preserveRequests=!1}onResponse(e,t,s){this._responseHandlers.set(e,{resolve:t,reject:s})}_receive(e){if(!e.data||!e.data.status||!e.data.id||"*"!==this._allowedOrigin&&e.origin!==this._allowedOrigin)return!1;const t=e.data,r=this._getCallback(t.id),n=this._waitingRequests.getState(t.id);if(r){if(this._preserveRequests||(this._waitingRequests.remove(t.id),this._responseHandlers.delete(t.id)),console.debug("RpcClient RECEIVE",t),t.status===s.OK)r.resolve(t.result,t.id,n);else if(t.status===s.ERROR){const e=new Error(t.result.message);t.result.stack&&(e.stack=t.result.stack),t.result.name&&(e.name=t.result.name),r.reject(e,t.id,n)}return!0}return console.warn("Unknown RPC response:",t),!1}_getCallback(e){if(this._responseHandlers.has(e))return this._responseHandlers.get(e);{const t=this._waitingRequests.getCommand(e);if(t)return this._responseHandlers.get(t)}}}class l extends c{constructor(e,t){super(t),this._serverCloseCheckInterval=-1,this._target=e,this._connectionState=0,this._receiveListener=this._receive.bind(this)}async init(){2!==this._connectionState&&(await this._connect(),window.addEventListener("message",this._receiveListener),-1===this._serverCloseCheckInterval&&(this._serverCloseCheckInterval=window.setInterval(()=>this._checkIfServerClosed(),300)))}async call(e,...t){return this._call({command:e,args:t,id:n.generateRandomId()})}close(){this._connectionState=0,window.removeEventListener("message",this._receiveListener),window.clearInterval(this._serverCloseCheckInterval),this._serverCloseCheckInterval=-1;for(const[e,{reject:t}]of this._responseHandlers){const s=this._waitingRequests.getState(e);t("Connection was closed","number"==typeof e?e:void 0,s)}this._waitingRequests.clear(),this._responseHandlers.clear(),this._target&&this._target.closed&&(this._target=null)}_receive(e){return e.source===this._target&&super._receive(e)}async _call(e){if(!this._target||this._target.closed)throw new Error("Connection was closed.");if(2!==this._connectionState)throw new Error("Client is not connected, call init first");return new Promise((t,s)=>{this._responseHandlers.set(e.id,{resolve:t,reject:s}),this._waitingRequests.add(e.id,e.command),console.debug("RpcClient REQUEST",e.command,e.args),this._target.postMessage(e,this._allowedOrigin)})}_connect(){if(2!==this._connectionState)return this._connectionState=1,new Promise((e,t)=>{const r=t=>{const{source:n,origin:i,data:o}=t;if(n===this._target&&o.status===s.OK&&"pong"===o.result&&1===o.id&&("*"===this._allowedOrigin||i===this._allowedOrigin)){if(o.result.stack){const e=new Error(o.result.message);e.stack=o.result.stack,o.result.name&&(e.name=o.result.name),console.error(e)}window.removeEventListener("message",r),this._connectionState=2,console.log("RpcClient: Connection established"),e(!0)}};window.addEventListener("message",r);const n=()=>{if(2!==this._connectionState){if(0===this._connectionState||this._checkIfServerClosed())return window.removeEventListener("message",r),void t(new Error("Connection was closed"));try{this._target.postMessage({command:"ping",id:1},this._allowedOrigin)}catch(e){console.error(`postMessage failed: ${e}`)}window.setTimeout(n,100)}};window.setTimeout(n,100)})}_checkIfServerClosed(){return!(this._target&&!this._target.closed)&&(this.close(),!0)}}class h extends c{constructor(e,t,s=!0){super(t,!0),this._target=e,this._preserveRequests=s}async init(){const e=a.receiveRedirectResponse(window.location);if(e)return void this._receive(e);if(this._rejectOnBack())return;const t=new URLSearchParams(window.location.search);if(t.has(a.URL_SEARCHPARAM_NAME)){const e=window.sessionStorage.getItem(`response-${t.get(a.URL_SEARCHPARAM_NAME)}`);if(e)return void this._receive(r.parse(e),!1)}}close(){}call(e,t,s=!1,...r){this.callAndSaveLocalState(e,null,t,s,...r)}callAndSaveLocalState(e,t,s,r=!1,...i){const o=n.generateRandomId(),c=a.prepareRedirectInvocation(this._target,o,e,s,i);this._waitingRequests.add(o,s,t),r&&history.replaceState(Object.assign({},history.state,{rpcBackRejectionId:o}),""),console.debug("RpcClient REQUEST",s,i),window.location.href=c}_receive(e,t=!0){const s=super._receive(e);return s&&t&&window.sessionStorage.setItem(`response-${e.data.id}`,r.stringify(e)),s}_rejectOnBack(){if(!history.state||!history.state.rpcBackRejectionId)return!1;const e=history.state.rpcBackRejectionId;history.replaceState(Object.assign({},history.state,{rpcBackRejectionId:null}),"");const t=this._getCallback(e),s=this._waitingRequests.getState(e);if(t){this._preserveRequests||(this._waitingRequests.remove(e),this._responseHandlers.delete(e)),console.debug("RpcClient BACK");const r=new Error("Request aborted");return t.reject(r,e,s),!0}return!1}}class d{constructor(e){this._type=e}static getAllowedOrigin(e){return new URL(e).origin}async request(e,t,s){throw new Error("Not implemented")}}var u,_;!function(e){e[e.REDIRECT=0]="REDIRECT",e[e.POPUP=1]="POPUP",e[e.IFRAME=2]="IFRAME"}(u||(u={}));class g extends d{static withLocalState(e){return new g(void 0,e)}constructor(e,t){super(u.REDIRECT);const s=window.location;if(this._returnUrl=e||`${s.origin}${s.pathname}`,this._localState=t||{},void 0!==this._localState.__command)throw new Error("Invalid localState: Property '__command' is reserved")}async request(e,t,s){const r=d.getAllowedOrigin(e),n=new h(e,r);await n.init();const i=Object.assign({},this._localState,{__command:t});n.callAndSaveLocalState(this._returnUrl,i,t,!0,...s)}}class p extends d{constructor(e=p.DEFAULT_OPTIONS){super(u.POPUP),this._options=e}async request(e,t,s){const r=d.getAllowedOrigin(e),n=this.createPopup(e),i=new l(n,r);await i.init();try{return await i.call(t,...s)}catch(e){throw e}finally{i.close(),n.close()}}createPopup(e){const t=window.open(e,"NimiqAccounts",this._options);if(!t)throw new Error("Failed to open popup");return t}}p.DEFAULT_OPTIONS="";class w extends d{constructor(){super(u.IFRAME),this._iframe=null,this._client=null}async request(e,t,s){if(this._iframe&&this._iframe.src!==`${e}${w.IFRAME_PATH_SUFFIX}`)throw new Error("Hub iframe is already opened with another endpoint");const r=d.getAllowedOrigin(e);if(this._iframe||(this._iframe=await this.createIFrame(e)),!this._iframe.contentWindow)throw new Error(`IFrame contentWindow is ${typeof this._iframe.contentWindow}`);return this._client||(this._client=new l(this._iframe.contentWindow,r),await this._client.init()),await this._client.call(t,...s)}async createIFrame(e){return new Promise((t,s)=>{const r=document.createElement("iframe");r.name="NimiqAccountsIFrame",r.style.display="none",document.body.appendChild(r),r.src=`${e}${w.IFRAME_PATH_SUFFIX}`,r.onload=(()=>t(r)),r.onerror=s})}}w.IFRAME_PATH_SUFFIX="/iframe.html",function(e){e.LIST="list",e.MIGRATE="migrate",e.CHECKOUT="checkout",e.SIGN_MESSAGE="sign-message",e.SIGN_TRANSACTION="sign-transaction",e.ONBOARD="onboard",e.SIGNUP="signup",e.LOGIN="login",e.EXPORT="export",e.CHANGE_PASSWORD="change-password",e.LOGOUT="logout",e.ADD_ADDRESS="add-address",e.RENAME="rename",e.CHOOSE_ADDRESS="choose-address"}(_||(_={}));class R{constructor(e=R.DEFAULT_ENDPOINT,t){this._endpoint=e,this._defaultBehavior=t||new p(`left=${window.innerWidth/2-400},top=75,width=800,height=850,location=yes,dependent=yes`),this._iframeBehavior=new w,this._redirectClient=new h("",d.getAllowedOrigin(this._endpoint))}static get DEFAULT_ENDPOINT(){const e=location.origin.split(".");switch(e.shift(),e.join(".")){case"nimiq.com":return"https://hub.nimiq.com";case"nimiq-testnet.com":return"https://hub.nimiq-testnet.com";default:return"http://localhost:8080"}}checkRedirectResponse(){return this._redirectClient.init()}on(e,t,s){this._redirectClient.onResponse(e,(e,s,r)=>t(e,r),(e,t,r)=>{s&&s(e,r)})}checkout(e,t=this._defaultBehavior){return this._request(t,_.CHECKOUT,[e])}chooseAddress(e,t=this._defaultBehavior){return this._request(t,_.CHOOSE_ADDRESS,[e])}signTransaction(e,t=this._defaultBehavior){return this._request(t,_.SIGN_TRANSACTION,[e])}signMessage(e,t=this._defaultBehavior){return this._request(t,_.SIGN_MESSAGE,[e])}onboard(e,t=this._defaultBehavior){return this._request(t,_.ONBOARD,[e])}signup(e,t=this._defaultBehavior){return this._request(t,_.SIGNUP,[e])}login(e,t=this._defaultBehavior){return this._request(t,_.LOGIN,[e])}logout(e,t=this._defaultBehavior){return this._request(t,_.LOGOUT,[e])}export(e,t=this._defaultBehavior){return this._request(t,_.EXPORT,[e])}changePassword(e,t=this._defaultBehavior){return this._request(t,_.CHANGE_PASSWORD,[e])}addAddress(e,t=this._defaultBehavior){return this._request(t,_.ADD_ADDRESS,[e])}rename(e,t=this._defaultBehavior){return this._request(t,_.RENAME,[e])}migrate(e=this._defaultBehavior){return this._request(e,_.MIGRATE,[{appName:"Account list"}])}list(e=this._iframeBehavior){return this._request(e,_.LIST,[])}_request(e,t,s){return e.request(this._endpoint,t,s)}}R.RequestType=_,R.RedirectRequestBehavior=g,R.MSG_PREFIX="Nimiq Signed Message:\n";export default R; |
@@ -1,1 +0,1 @@ | ||
!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?module.exports=t():"function"==typeof define&&define.amd?define(t):(e=e||self).HubApi=t()}(this,function(){"use strict";class e{static byteLength(t){const[s,r]=e._getLengths(t);return e._byteLength(s,r)}static decode(t){e._initRevLookup();const[s,r]=e._getLengths(t),n=new Uint8Array(e._byteLength(s,r));let i=0;const o=r>0?s-4:s;let a=0;for(;a<o;a+=4){const s=e._revLookup[t.charCodeAt(a)]<<18|e._revLookup[t.charCodeAt(a+1)]<<12|e._revLookup[t.charCodeAt(a+2)]<<6|e._revLookup[t.charCodeAt(a+3)];n[i++]=s>>16&255,n[i++]=s>>8&255,n[i++]=255&s}if(2===r){const s=e._revLookup[t.charCodeAt(a)]<<2|e._revLookup[t.charCodeAt(a+1)]>>4;n[i++]=255&s}if(1===r){const s=e._revLookup[t.charCodeAt(a)]<<10|e._revLookup[t.charCodeAt(a+1)]<<4|e._revLookup[t.charCodeAt(a+2)]>>2;n[i++]=s>>8&255,n[i]=255&s}return n}static encode(t){const s=t.length,r=s%3,n=[];for(let i=0,o=s-r;i<o;i+=16383)n.push(e._encodeChunk(t,i,i+16383>o?o:i+16383));if(1===r){const r=t[s-1];n.push(e._lookup[r>>2]+e._lookup[r<<4&63]+"==")}else if(2===r){const r=(t[s-2]<<8)+t[s-1];n.push(e._lookup[r>>10]+e._lookup[r>>4&63]+e._lookup[r<<2&63]+"=")}return n.join("")}static encodeUrl(t){return e.encode(t).replace(/\//g,"_").replace(/\+/g,"-").replace(/=/g,".")}static decodeUrl(t){return e.decode(t.replace(/_/g,"/").replace(/-/g,"+").replace(/\./g,"="))}static _initRevLookup(){if(0===e._revLookup.length){e._revLookup=[];for(let t=0,s=e._lookup.length;t<s;t++)e._revLookup[e._lookup.charCodeAt(t)]=t;e._revLookup["-".charCodeAt(0)]=62,e._revLookup["_".charCodeAt(0)]=63}}static _getLengths(e){const t=e.length;if(t%4>0)throw new Error("Invalid string. Length must be a multiple of 4");let s=e.indexOf("=");return-1===s&&(s=t),[s,s===t?0:4-s%4]}static _byteLength(e,t){return 3*(e+t)/4-t}static _tripletToBase64(t){return e._lookup[t>>18&63]+e._lookup[t>>12&63]+e._lookup[t>>6&63]+e._lookup[63&t]}static _encodeChunk(t,s,r){const n=[];for(let i=s;i<r;i+=3){const s=(t[i]<<16&16711680)+(t[i+1]<<8&65280)+(255&t[i+2]);n.push(e._tripletToBase64(s))}return n.join("")}}var t,s;e._lookup="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/",e._revLookup=[],function(e){e[e.UINT8_ARRAY=0]="UINT8_ARRAY"}(t||(t={}));class r{static stringify(e){return JSON.stringify(e,r._jsonifyType)}static parse(e){return JSON.parse(e,r._parseType)}static _parseType(s,n){if(n&&n.hasOwnProperty&&n.hasOwnProperty(r.TYPE_SYMBOL)&&n.hasOwnProperty(r.VALUE_SYMBOL))switch(n[r.TYPE_SYMBOL]){case t.UINT8_ARRAY:return e.decode(n[r.VALUE_SYMBOL])}return n}static _jsonifyType(s,n){return n instanceof Uint8Array?r._typedObject(t.UINT8_ARRAY,e.encode(n)):n}static _typedObject(e,t){const s={};return s[r.TYPE_SYMBOL]=e,s[r.VALUE_SYMBOL]=t,s}}r.TYPE_SYMBOL="__",r.VALUE_SYMBOL="v";class n{static generateRandomId(){const e=new Uint32Array(1);return crypto.getRandomValues(e),e[0]}}!function(e){e.OK="ok",e.ERROR="error"}(s||(s={}));const i="<postMessage>";class o{constructor(e=!0){this._store=e?window.sessionStorage:null,this._validIds=new Map,e&&this._restoreIds()}static _decodeIds(e){const t=r.parse(e),s=new Map;for(const e of Object.keys(t)){const r=parseInt(e,10);s.set(isNaN(r)?e:r,t[e])}return s}has(e){return this._validIds.has(e)}getCommand(e){const t=this._validIds.get(e);return t?t[0]:null}getState(e){const t=this._validIds.get(e);return t?t[1]:null}add(e,t,s=null){this._validIds.set(e,[t,s]),this._storeIds()}remove(e){this._validIds.delete(e),this._storeIds()}clear(){this._validIds.clear(),this._store&&this._store.removeItem(o.KEY)}_encodeIds(){const e=Object.create(null);for(const[t,s]of this._validIds)e[t]=s;return r.stringify(e)}_restoreIds(){const e=this._store.getItem(o.KEY);e&&(this._validIds=o._decodeIds(e))}_storeIds(){this._store&&this._store.setItem(o.KEY,this._encodeIds())}}o.KEY="rpcRequests";class a{static receiveRedirectCommand(e){const t=new URL(e.href);if(!document.referrer)return null;const s=new URL(document.referrer),n=new URLSearchParams(t.search),o=new URLSearchParams(t.hash.substring(1));if(!o.has("id"))return null;const c=parseInt(o.get("id"),10);if(o.delete("id"),n.set(a.URL_SEARCHPARAM_NAME,c.toString()),!o.has("command"))return null;const l=o.get("command");if(o.delete("command"),!o.has("returnURL"))return null;const h=o.get("returnURL");o.delete("returnURL");const d=h===i&&(window.opener||window.parent);if(!d&&new URL(h).origin!==s.origin)return null;let u=[];if(o.has("args"))try{u=r.parse(o.get("args"))}catch(e){}return u=Array.isArray(u)?u:[],o.delete("args"),t.search=n.toString(),this._setUrlFragment(t,o),history.replaceState(history.state,"",t.href),{origin:s.origin,data:{id:c,command:l,args:u},returnURL:h,source:d?window.opener||window.parent:null}}static receiveRedirectResponse(e){const t=new URL(e.href);if(!document.referrer)return null;const n=new URL(document.referrer),i=new URLSearchParams(t.search),o=new URLSearchParams(t.hash.substring(1));if(!o.has("id"))return null;const c=parseInt(o.get("id"),10);if(o.delete("id"),i.set(a.URL_SEARCHPARAM_NAME,c.toString()),!o.has("status"))return null;const l=o.get("status")===s.OK?s.OK:s.ERROR;if(o.delete("status"),!o.has("result"))return null;const h=r.parse(o.get("result"));return o.delete("result"),t.search=i.toString(),this._setUrlFragment(t,o),history.replaceState(history.state,"",t.href),{origin:n.origin,data:{id:c,status:l,result:h}}}static prepareRedirectReply(e,t,s){const n=new URL(e.returnURL),i=new URLSearchParams(n.hash.substring(1));return i.set("id",e.id.toString()),i.set("status",t),i.set("result",r.stringify(s)),n.hash=i.toString(),n.href}static prepareRedirectInvocation(e,t,s,n,i){const o=new URL(e),a=new URLSearchParams(o.hash.substring(1));return a.set("id",t.toString()),a.set("returnURL",s),a.set("command",n),Array.isArray(i)&&a.set("args",r.stringify(i)),o.hash=a.toString(),o.href}static _setUrlFragment(e,t){t.toString().endsWith("=")?e.hash=t.toString().slice(0,-1):e.hash=t.toString()}}a.URL_SEARCHPARAM_NAME="rpcId";class c{constructor(e,t=!1){this._allowedOrigin=e,this._waitingRequests=new o(t),this._responseHandlers=new Map,this._preserveRequests=!1}onResponse(e,t,s){this._responseHandlers.set(e,{resolve:t,reject:s})}_receive(e){if(!e.data||!e.data.status||!e.data.id||"*"!==this._allowedOrigin&&e.origin!==this._allowedOrigin)return!1;const t=e.data,r=this._getCallback(t.id),n=this._waitingRequests.getState(t.id);if(r){if(this._preserveRequests||(this._waitingRequests.remove(t.id),this._responseHandlers.delete(t.id)),console.debug("RpcClient RECEIVE",t),t.status===s.OK)r.resolve(t.result,t.id,n);else if(t.status===s.ERROR){const e=new Error(t.result.message);t.result.stack&&(e.stack=t.result.stack),t.result.name&&(e.name=t.result.name),r.reject(e,t.id,n)}return!0}return console.warn("Unknown RPC response:",t),!1}_getCallback(e){if(this._responseHandlers.has(e))return this._responseHandlers.get(e);{const t=this._waitingRequests.getCommand(e);if(t)return this._responseHandlers.get(t)}}}class l extends c{constructor(e,t){super(t),this._serverCloseCheckInterval=-1,this._target=e,this._connectionState=0,this._receiveListener=this._receive.bind(this)}async init(){2!==this._connectionState&&(await this._connect(),window.addEventListener("message",this._receiveListener),-1===this._serverCloseCheckInterval&&(this._serverCloseCheckInterval=window.setInterval(()=>this._checkIfServerClosed(),300)))}async call(e,...t){return this._call({command:e,args:t,id:n.generateRandomId()})}close(){this._connectionState=0,window.removeEventListener("message",this._receiveListener),window.clearInterval(this._serverCloseCheckInterval),this._serverCloseCheckInterval=-1;for(const[e,{reject:t}]of this._responseHandlers){const s=this._waitingRequests.getState(e);t("Connection was closed","number"==typeof e?e:void 0,s)}this._waitingRequests.clear(),this._responseHandlers.clear(),this._target&&this._target.closed&&(this._target=null)}_receive(e){return e.source===this._target&&super._receive(e)}async _call(e){if(!this._target||this._target.closed)throw new Error("Connection was closed.");if(2!==this._connectionState)throw new Error("Client is not connected, call init first");return new Promise((t,s)=>{this._responseHandlers.set(e.id,{resolve:t,reject:s}),this._waitingRequests.add(e.id,e.command),console.debug("RpcClient REQUEST",e.command,e.args),this._target.postMessage(e,this._allowedOrigin)})}_connect(){if(2!==this._connectionState)return this._connectionState=1,new Promise((e,t)=>{const r=t=>{const{source:n,origin:i,data:o}=t;if(n===this._target&&o.status===s.OK&&"pong"===o.result&&1===o.id&&("*"===this._allowedOrigin||i===this._allowedOrigin)){if(o.result.stack){const e=new Error(o.result.message);e.stack=o.result.stack,o.result.name&&(e.name=o.result.name),console.error(e)}window.removeEventListener("message",r),this._connectionState=2,console.log("RpcClient: Connection established"),e(!0)}};window.addEventListener("message",r);const n=()=>{if(2!==this._connectionState){if(0===this._connectionState||this._checkIfServerClosed())return window.removeEventListener("message",r),void t(new Error("Connection was closed"));try{this._target.postMessage({command:"ping",id:1},this._allowedOrigin)}catch(e){console.error(`postMessage failed: ${e}`)}window.setTimeout(n,100)}};window.setTimeout(n,100)})}_checkIfServerClosed(){return!(this._target&&!this._target.closed)&&(this.close(),!0)}}class h extends c{constructor(e,t,s=!0){super(t,!0),this._target=e,this._preserveRequests=s}async init(){const e=a.receiveRedirectResponse(window.location);if(e)return void this._receive(e);if(this._rejectOnBack())return;const t=new URLSearchParams(window.location.search);if(t.has(a.URL_SEARCHPARAM_NAME)){const e=window.sessionStorage.getItem(`response-${t.get(a.URL_SEARCHPARAM_NAME)}`);if(e)return void this._receive(r.parse(e),!1)}}close(){}call(e,t,s=!1,...r){this.callAndSaveLocalState(e,null,t,s,...r)}callAndSaveLocalState(e,t,s,r=!1,...i){const o=n.generateRandomId(),c=a.prepareRedirectInvocation(this._target,o,e,s,i);this._waitingRequests.add(o,s,t),r&&history.replaceState(Object.assign({},history.state,{rpcBackRejectionId:o}),""),console.debug("RpcClient REQUEST",s,i),window.location.href=c}_receive(e,t=!0){const s=super._receive(e);return s&&t&&window.sessionStorage.setItem(`response-${e.data.id}`,r.stringify(e)),s}_rejectOnBack(){if(!history.state||!history.state.rpcBackRejectionId)return!1;const e=history.state.rpcBackRejectionId;history.replaceState(Object.assign({},history.state,{rpcBackRejectionId:null}),"");const t=this._getCallback(e),s=this._waitingRequests.getState(e);if(t){this._preserveRequests||(this._waitingRequests.remove(e),this._responseHandlers.delete(e)),console.debug("RpcClient BACK");const r=new Error("Request aborted");return t.reject(r,e,s),!0}return!1}}class d{constructor(e){this._type=e}static getAllowedOrigin(e){return new URL(e).origin}async request(e,t,s){throw new Error("Not implemented")}}var u,_;!function(e){e[e.REDIRECT=0]="REDIRECT",e[e.POPUP=1]="POPUP",e[e.IFRAME=2]="IFRAME"}(u||(u={}));class g extends d{static withLocalState(e){return new g(void 0,e)}constructor(e,t){super(u.REDIRECT);const s=window.location;if(this._returnUrl=e||`${s.origin}${s.pathname}`,this._localState=t||{},void 0!==this._localState.__command)throw new Error("Invalid localState: Property '__command' is reserved")}async request(e,t,s){const r=d.getAllowedOrigin(e),n=new h(e,r);await n.init();const i=Object.assign({},this._localState,{__command:t});n.callAndSaveLocalState(this._returnUrl,i,t,!0,...s)}}class p extends d{constructor(e=p.DEFAULT_OPTIONS){super(u.POPUP),this._options=e}async request(e,t,s){const r=d.getAllowedOrigin(e),n=this.createPopup(e),i=new l(n,r);await i.init();try{return await i.call(t,...s)}catch(e){throw e}finally{i.close(),n.close()}}createPopup(e){const t=window.open(e,"NimiqAccounts",this._options);if(!t)throw new Error("Failed to open popup");return t}}p.DEFAULT_OPTIONS="";class w extends d{constructor(){super(u.IFRAME),this._iframe=null,this._client=null}async request(e,t,s){if(this._iframe&&this._iframe.src!==`${e}${w.IFRAME_PATH_SUFFIX}`)throw new Error("Hub iframe is already opened with another endpoint");const r=d.getAllowedOrigin(e);if(this._iframe||(this._iframe=await this.createIFrame(e)),!this._iframe.contentWindow)throw new Error(`IFrame contentWindow is ${typeof this._iframe.contentWindow}`);return this._client||(this._client=new l(this._iframe.contentWindow,r),await this._client.init()),await this._client.call(t,...s)}async createIFrame(e){return new Promise((t,s)=>{const r=document.createElement("iframe");r.name="NimiqAccountsIFrame",r.style.display="none",document.body.appendChild(r),r.src=`${e}${w.IFRAME_PATH_SUFFIX}`,r.onload=(()=>t(r)),r.onerror=s})}}w.IFRAME_PATH_SUFFIX="/iframe.html",function(e){e.LIST="list",e.MIGRATE="migrate",e.CHECKOUT="checkout",e.SIGN_MESSAGE="sign-message",e.SIGN_TRANSACTION="sign-transaction",e.ONBOARD="onboard",e.SIGNUP="signup",e.LOGIN="login",e.EXPORT="export",e.CHANGE_PASSWORD="change-password",e.LOGOUT="logout",e.ADD_ADDRESS="add-address",e.RENAME="rename",e.CHOOSE_ADDRESS="choose-address"}(_||(_={}));class R{constructor(e=R.DEFAULT_ENDPOINT,t){this._endpoint=e,this._defaultBehavior=t||new p(`left=${window.innerWidth/2-400},top=75,width=800,height=850,location=yes,dependent=yes`),this._iframeBehavior=new w,this._redirectClient=new h("",d.getAllowedOrigin(this._endpoint))}static get DEFAULT_ENDPOINT(){const e=location.origin.split(".");switch(e.shift(),e.join(".")){case"nimiq.com":return"https://hub.nimiq.com";case"nimiq-testnet.com":return"https://hub.nimiq-testnet.com";default:return"http://localhost:8080"}}checkRedirectResponse(){return this._redirectClient.init()}on(e,t,s){this._redirectClient.onResponse(e,(e,s,r)=>t(e,r),(e,t,r)=>{s&&s(e,r)})}onboard(e,t=this._defaultBehavior){return this._request(t,_.ONBOARD,[e])}signup(e,t=this._defaultBehavior){return this._request(t,_.SIGNUP,[e])}login(e,t=this._defaultBehavior){return this._request(t,_.LOGIN,[e])}chooseAddress(e,t=this._defaultBehavior){return this._request(t,_.CHOOSE_ADDRESS,[e])}signTransaction(e,t=this._defaultBehavior){return this._request(t,_.SIGN_TRANSACTION,[e])}checkout(e,t=this._defaultBehavior){return this._request(t,_.CHECKOUT,[e])}logout(e,t=this._defaultBehavior){return this._request(t,_.LOGOUT,[e])}export(e,t=this._defaultBehavior){return this._request(t,_.EXPORT,[e])}changePassword(e,t=this._defaultBehavior){return this._request(t,_.CHANGE_PASSWORD,[e])}addAddress(e,t=this._defaultBehavior){return this._request(t,_.ADD_ADDRESS,[e])}rename(e,t=this._defaultBehavior){return this._request(t,_.RENAME,[e])}signMessage(e,t=this._defaultBehavior){return this._request(t,_.SIGN_MESSAGE,[e])}migrate(e=this._defaultBehavior){return this._request(e,_.MIGRATE,[{appName:"Accounts Client"}])}list(e=this._iframeBehavior){return this._request(e,_.LIST,[])}_request(e,t,s){return e.request(this._endpoint,t,s)}}return R.RequestType=_,R.RedirectRequestBehavior=g,R.MSG_PREFIX="Nimiq Signed Message:\n",R}); | ||
!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?module.exports=t():"function"==typeof define&&define.amd?define(t):(e=e||self).HubApi=t()}(this,function(){"use strict";class e{static byteLength(t){const[s,r]=e._getLengths(t);return e._byteLength(s,r)}static decode(t){e._initRevLookup();const[s,r]=e._getLengths(t),n=new Uint8Array(e._byteLength(s,r));let i=0;const o=r>0?s-4:s;let a=0;for(;a<o;a+=4){const s=e._revLookup[t.charCodeAt(a)]<<18|e._revLookup[t.charCodeAt(a+1)]<<12|e._revLookup[t.charCodeAt(a+2)]<<6|e._revLookup[t.charCodeAt(a+3)];n[i++]=s>>16&255,n[i++]=s>>8&255,n[i++]=255&s}if(2===r){const s=e._revLookup[t.charCodeAt(a)]<<2|e._revLookup[t.charCodeAt(a+1)]>>4;n[i++]=255&s}if(1===r){const s=e._revLookup[t.charCodeAt(a)]<<10|e._revLookup[t.charCodeAt(a+1)]<<4|e._revLookup[t.charCodeAt(a+2)]>>2;n[i++]=s>>8&255,n[i]=255&s}return n}static encode(t){const s=t.length,r=s%3,n=[];for(let i=0,o=s-r;i<o;i+=16383)n.push(e._encodeChunk(t,i,i+16383>o?o:i+16383));if(1===r){const r=t[s-1];n.push(e._lookup[r>>2]+e._lookup[r<<4&63]+"==")}else if(2===r){const r=(t[s-2]<<8)+t[s-1];n.push(e._lookup[r>>10]+e._lookup[r>>4&63]+e._lookup[r<<2&63]+"=")}return n.join("")}static encodeUrl(t){return e.encode(t).replace(/\//g,"_").replace(/\+/g,"-").replace(/=/g,".")}static decodeUrl(t){return e.decode(t.replace(/_/g,"/").replace(/-/g,"+").replace(/\./g,"="))}static _initRevLookup(){if(0===e._revLookup.length){e._revLookup=[];for(let t=0,s=e._lookup.length;t<s;t++)e._revLookup[e._lookup.charCodeAt(t)]=t;e._revLookup["-".charCodeAt(0)]=62,e._revLookup["_".charCodeAt(0)]=63}}static _getLengths(e){const t=e.length;if(t%4>0)throw new Error("Invalid string. Length must be a multiple of 4");let s=e.indexOf("=");return-1===s&&(s=t),[s,s===t?0:4-s%4]}static _byteLength(e,t){return 3*(e+t)/4-t}static _tripletToBase64(t){return e._lookup[t>>18&63]+e._lookup[t>>12&63]+e._lookup[t>>6&63]+e._lookup[63&t]}static _encodeChunk(t,s,r){const n=[];for(let i=s;i<r;i+=3){const s=(t[i]<<16&16711680)+(t[i+1]<<8&65280)+(255&t[i+2]);n.push(e._tripletToBase64(s))}return n.join("")}}var t,s;e._lookup="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/",e._revLookup=[],function(e){e[e.UINT8_ARRAY=0]="UINT8_ARRAY"}(t||(t={}));class r{static stringify(e){return JSON.stringify(e,r._jsonifyType)}static parse(e){return JSON.parse(e,r._parseType)}static _parseType(s,n){if(n&&n.hasOwnProperty&&n.hasOwnProperty(r.TYPE_SYMBOL)&&n.hasOwnProperty(r.VALUE_SYMBOL))switch(n[r.TYPE_SYMBOL]){case t.UINT8_ARRAY:return e.decode(n[r.VALUE_SYMBOL])}return n}static _jsonifyType(s,n){return n instanceof Uint8Array?r._typedObject(t.UINT8_ARRAY,e.encode(n)):n}static _typedObject(e,t){const s={};return s[r.TYPE_SYMBOL]=e,s[r.VALUE_SYMBOL]=t,s}}r.TYPE_SYMBOL="__",r.VALUE_SYMBOL="v";class n{static generateRandomId(){const e=new Uint32Array(1);return crypto.getRandomValues(e),e[0]}}!function(e){e.OK="ok",e.ERROR="error"}(s||(s={}));const i="<postMessage>";class o{constructor(e=!0){this._store=e?window.sessionStorage:null,this._validIds=new Map,e&&this._restoreIds()}static _decodeIds(e){const t=r.parse(e),s=new Map;for(const e of Object.keys(t)){const r=parseInt(e,10);s.set(isNaN(r)?e:r,t[e])}return s}has(e){return this._validIds.has(e)}getCommand(e){const t=this._validIds.get(e);return t?t[0]:null}getState(e){const t=this._validIds.get(e);return t?t[1]:null}add(e,t,s=null){this._validIds.set(e,[t,s]),this._storeIds()}remove(e){this._validIds.delete(e),this._storeIds()}clear(){this._validIds.clear(),this._store&&this._store.removeItem(o.KEY)}_encodeIds(){const e=Object.create(null);for(const[t,s]of this._validIds)e[t]=s;return r.stringify(e)}_restoreIds(){const e=this._store.getItem(o.KEY);e&&(this._validIds=o._decodeIds(e))}_storeIds(){this._store&&this._store.setItem(o.KEY,this._encodeIds())}}o.KEY="rpcRequests";class a{static receiveRedirectCommand(e){const t=new URL(e.href);if(!document.referrer)return null;const s=new URL(document.referrer),n=new URLSearchParams(t.search),o=new URLSearchParams(t.hash.substring(1));if(!o.has("id"))return null;const c=parseInt(o.get("id"),10);if(o.delete("id"),n.set(a.URL_SEARCHPARAM_NAME,c.toString()),!o.has("command"))return null;const l=o.get("command");if(o.delete("command"),!o.has("returnURL"))return null;const h=o.get("returnURL");o.delete("returnURL");const d=h===i&&(window.opener||window.parent);if(!d&&new URL(h).origin!==s.origin)return null;let u=[];if(o.has("args"))try{u=r.parse(o.get("args"))}catch(e){}return u=Array.isArray(u)?u:[],o.delete("args"),t.search=n.toString(),this._setUrlFragment(t,o),history.replaceState(history.state,"",t.href),{origin:s.origin,data:{id:c,command:l,args:u},returnURL:h,source:d?window.opener||window.parent:null}}static receiveRedirectResponse(e){const t=new URL(e.href);if(!document.referrer)return null;const n=new URL(document.referrer),i=new URLSearchParams(t.search),o=new URLSearchParams(t.hash.substring(1));if(!o.has("id"))return null;const c=parseInt(o.get("id"),10);if(o.delete("id"),i.set(a.URL_SEARCHPARAM_NAME,c.toString()),!o.has("status"))return null;const l=o.get("status")===s.OK?s.OK:s.ERROR;if(o.delete("status"),!o.has("result"))return null;const h=r.parse(o.get("result"));return o.delete("result"),t.search=i.toString(),this._setUrlFragment(t,o),history.replaceState(history.state,"",t.href),{origin:n.origin,data:{id:c,status:l,result:h}}}static prepareRedirectReply(e,t,s){const n=new URL(e.returnURL),i=new URLSearchParams(n.hash.substring(1));return i.set("id",e.id.toString()),i.set("status",t),i.set("result",r.stringify(s)),n.hash=i.toString(),n.href}static prepareRedirectInvocation(e,t,s,n,i){const o=new URL(e),a=new URLSearchParams(o.hash.substring(1));return a.set("id",t.toString()),a.set("returnURL",s),a.set("command",n),Array.isArray(i)&&a.set("args",r.stringify(i)),o.hash=a.toString(),o.href}static _setUrlFragment(e,t){t.toString().endsWith("=")?e.hash=t.toString().slice(0,-1):e.hash=t.toString()}}a.URL_SEARCHPARAM_NAME="rpcId";class c{constructor(e,t=!1){this._allowedOrigin=e,this._waitingRequests=new o(t),this._responseHandlers=new Map,this._preserveRequests=!1}onResponse(e,t,s){this._responseHandlers.set(e,{resolve:t,reject:s})}_receive(e){if(!e.data||!e.data.status||!e.data.id||"*"!==this._allowedOrigin&&e.origin!==this._allowedOrigin)return!1;const t=e.data,r=this._getCallback(t.id),n=this._waitingRequests.getState(t.id);if(r){if(this._preserveRequests||(this._waitingRequests.remove(t.id),this._responseHandlers.delete(t.id)),console.debug("RpcClient RECEIVE",t),t.status===s.OK)r.resolve(t.result,t.id,n);else if(t.status===s.ERROR){const e=new Error(t.result.message);t.result.stack&&(e.stack=t.result.stack),t.result.name&&(e.name=t.result.name),r.reject(e,t.id,n)}return!0}return console.warn("Unknown RPC response:",t),!1}_getCallback(e){if(this._responseHandlers.has(e))return this._responseHandlers.get(e);{const t=this._waitingRequests.getCommand(e);if(t)return this._responseHandlers.get(t)}}}class l extends c{constructor(e,t){super(t),this._serverCloseCheckInterval=-1,this._target=e,this._connectionState=0,this._receiveListener=this._receive.bind(this)}async init(){2!==this._connectionState&&(await this._connect(),window.addEventListener("message",this._receiveListener),-1===this._serverCloseCheckInterval&&(this._serverCloseCheckInterval=window.setInterval(()=>this._checkIfServerClosed(),300)))}async call(e,...t){return this._call({command:e,args:t,id:n.generateRandomId()})}close(){this._connectionState=0,window.removeEventListener("message",this._receiveListener),window.clearInterval(this._serverCloseCheckInterval),this._serverCloseCheckInterval=-1;for(const[e,{reject:t}]of this._responseHandlers){const s=this._waitingRequests.getState(e);t("Connection was closed","number"==typeof e?e:void 0,s)}this._waitingRequests.clear(),this._responseHandlers.clear(),this._target&&this._target.closed&&(this._target=null)}_receive(e){return e.source===this._target&&super._receive(e)}async _call(e){if(!this._target||this._target.closed)throw new Error("Connection was closed.");if(2!==this._connectionState)throw new Error("Client is not connected, call init first");return new Promise((t,s)=>{this._responseHandlers.set(e.id,{resolve:t,reject:s}),this._waitingRequests.add(e.id,e.command),console.debug("RpcClient REQUEST",e.command,e.args),this._target.postMessage(e,this._allowedOrigin)})}_connect(){if(2!==this._connectionState)return this._connectionState=1,new Promise((e,t)=>{const r=t=>{const{source:n,origin:i,data:o}=t;if(n===this._target&&o.status===s.OK&&"pong"===o.result&&1===o.id&&("*"===this._allowedOrigin||i===this._allowedOrigin)){if(o.result.stack){const e=new Error(o.result.message);e.stack=o.result.stack,o.result.name&&(e.name=o.result.name),console.error(e)}window.removeEventListener("message",r),this._connectionState=2,console.log("RpcClient: Connection established"),e(!0)}};window.addEventListener("message",r);const n=()=>{if(2!==this._connectionState){if(0===this._connectionState||this._checkIfServerClosed())return window.removeEventListener("message",r),void t(new Error("Connection was closed"));try{this._target.postMessage({command:"ping",id:1},this._allowedOrigin)}catch(e){console.error(`postMessage failed: ${e}`)}window.setTimeout(n,100)}};window.setTimeout(n,100)})}_checkIfServerClosed(){return!(this._target&&!this._target.closed)&&(this.close(),!0)}}class h extends c{constructor(e,t,s=!0){super(t,!0),this._target=e,this._preserveRequests=s}async init(){const e=a.receiveRedirectResponse(window.location);if(e)return void this._receive(e);if(this._rejectOnBack())return;const t=new URLSearchParams(window.location.search);if(t.has(a.URL_SEARCHPARAM_NAME)){const e=window.sessionStorage.getItem(`response-${t.get(a.URL_SEARCHPARAM_NAME)}`);if(e)return void this._receive(r.parse(e),!1)}}close(){}call(e,t,s=!1,...r){this.callAndSaveLocalState(e,null,t,s,...r)}callAndSaveLocalState(e,t,s,r=!1,...i){const o=n.generateRandomId(),c=a.prepareRedirectInvocation(this._target,o,e,s,i);this._waitingRequests.add(o,s,t),r&&history.replaceState(Object.assign({},history.state,{rpcBackRejectionId:o}),""),console.debug("RpcClient REQUEST",s,i),window.location.href=c}_receive(e,t=!0){const s=super._receive(e);return s&&t&&window.sessionStorage.setItem(`response-${e.data.id}`,r.stringify(e)),s}_rejectOnBack(){if(!history.state||!history.state.rpcBackRejectionId)return!1;const e=history.state.rpcBackRejectionId;history.replaceState(Object.assign({},history.state,{rpcBackRejectionId:null}),"");const t=this._getCallback(e),s=this._waitingRequests.getState(e);if(t){this._preserveRequests||(this._waitingRequests.remove(e),this._responseHandlers.delete(e)),console.debug("RpcClient BACK");const r=new Error("Request aborted");return t.reject(r,e,s),!0}return!1}}class d{constructor(e){this._type=e}static getAllowedOrigin(e){return new URL(e).origin}async request(e,t,s){throw new Error("Not implemented")}}var u,_;!function(e){e[e.REDIRECT=0]="REDIRECT",e[e.POPUP=1]="POPUP",e[e.IFRAME=2]="IFRAME"}(u||(u={}));class g extends d{static withLocalState(e){return new g(void 0,e)}constructor(e,t){super(u.REDIRECT);const s=window.location;if(this._returnUrl=e||`${s.origin}${s.pathname}`,this._localState=t||{},void 0!==this._localState.__command)throw new Error("Invalid localState: Property '__command' is reserved")}async request(e,t,s){const r=d.getAllowedOrigin(e),n=new h(e,r);await n.init();const i=Object.assign({},this._localState,{__command:t});n.callAndSaveLocalState(this._returnUrl,i,t,!0,...s)}}class p extends d{constructor(e=p.DEFAULT_OPTIONS){super(u.POPUP),this._options=e}async request(e,t,s){const r=d.getAllowedOrigin(e),n=this.createPopup(e),i=new l(n,r);await i.init();try{return await i.call(t,...s)}catch(e){throw e}finally{i.close(),n.close()}}createPopup(e){const t=window.open(e,"NimiqAccounts",this._options);if(!t)throw new Error("Failed to open popup");return t}}p.DEFAULT_OPTIONS="";class w extends d{constructor(){super(u.IFRAME),this._iframe=null,this._client=null}async request(e,t,s){if(this._iframe&&this._iframe.src!==`${e}${w.IFRAME_PATH_SUFFIX}`)throw new Error("Hub iframe is already opened with another endpoint");const r=d.getAllowedOrigin(e);if(this._iframe||(this._iframe=await this.createIFrame(e)),!this._iframe.contentWindow)throw new Error(`IFrame contentWindow is ${typeof this._iframe.contentWindow}`);return this._client||(this._client=new l(this._iframe.contentWindow,r),await this._client.init()),await this._client.call(t,...s)}async createIFrame(e){return new Promise((t,s)=>{const r=document.createElement("iframe");r.name="NimiqAccountsIFrame",r.style.display="none",document.body.appendChild(r),r.src=`${e}${w.IFRAME_PATH_SUFFIX}`,r.onload=(()=>t(r)),r.onerror=s})}}w.IFRAME_PATH_SUFFIX="/iframe.html",function(e){e.LIST="list",e.MIGRATE="migrate",e.CHECKOUT="checkout",e.SIGN_MESSAGE="sign-message",e.SIGN_TRANSACTION="sign-transaction",e.ONBOARD="onboard",e.SIGNUP="signup",e.LOGIN="login",e.EXPORT="export",e.CHANGE_PASSWORD="change-password",e.LOGOUT="logout",e.ADD_ADDRESS="add-address",e.RENAME="rename",e.CHOOSE_ADDRESS="choose-address"}(_||(_={}));class R{constructor(e=R.DEFAULT_ENDPOINT,t){this._endpoint=e,this._defaultBehavior=t||new p(`left=${window.innerWidth/2-400},top=75,width=800,height=850,location=yes,dependent=yes`),this._iframeBehavior=new w,this._redirectClient=new h("",d.getAllowedOrigin(this._endpoint))}static get DEFAULT_ENDPOINT(){const e=location.origin.split(".");switch(e.shift(),e.join(".")){case"nimiq.com":return"https://hub.nimiq.com";case"nimiq-testnet.com":return"https://hub.nimiq-testnet.com";default:return"http://localhost:8080"}}checkRedirectResponse(){return this._redirectClient.init()}on(e,t,s){this._redirectClient.onResponse(e,(e,s,r)=>t(e,r),(e,t,r)=>{s&&s(e,r)})}checkout(e,t=this._defaultBehavior){return this._request(t,_.CHECKOUT,[e])}chooseAddress(e,t=this._defaultBehavior){return this._request(t,_.CHOOSE_ADDRESS,[e])}signTransaction(e,t=this._defaultBehavior){return this._request(t,_.SIGN_TRANSACTION,[e])}signMessage(e,t=this._defaultBehavior){return this._request(t,_.SIGN_MESSAGE,[e])}onboard(e,t=this._defaultBehavior){return this._request(t,_.ONBOARD,[e])}signup(e,t=this._defaultBehavior){return this._request(t,_.SIGNUP,[e])}login(e,t=this._defaultBehavior){return this._request(t,_.LOGIN,[e])}logout(e,t=this._defaultBehavior){return this._request(t,_.LOGOUT,[e])}export(e,t=this._defaultBehavior){return this._request(t,_.EXPORT,[e])}changePassword(e,t=this._defaultBehavior){return this._request(t,_.CHANGE_PASSWORD,[e])}addAddress(e,t=this._defaultBehavior){return this._request(t,_.ADD_ADDRESS,[e])}rename(e,t=this._defaultBehavior){return this._request(t,_.RENAME,[e])}migrate(e=this._defaultBehavior){return this._request(e,_.MIGRATE,[{appName:"Account list"}])}list(e=this._iframeBehavior){return this._request(e,_.LIST,[])}_request(e,t,s){return e.request(this._endpoint,t,s)}}return R.RequestType=_,R.RedirectRequestBehavior=g,R.MSG_PREFIX="Nimiq Signed Message:\n",R}); |
{ | ||
"name": "@nimiq/hub-api", | ||
"version": "0.5.0", | ||
"version": "1.0.0", | ||
"main": "dist/HubApi.umd.js", | ||
@@ -21,3 +21,4 @@ "module": "dist/HubApi.es.js", | ||
"files": [ | ||
"dist" | ||
"dist", | ||
"types" | ||
], | ||
@@ -34,3 +35,3 @@ "keywords": [ | ||
"scripts": { | ||
"build": "cp ../README.md . && rm -rf dist && tsc && rollup -c", | ||
"build": "cp ../README.md . && rm -rf build && rm -rf dist && tsc && rollup -c", | ||
"lint": "tslint --project tsconfig.json", | ||
@@ -37,0 +38,0 @@ "lintfix": "yarn lint --fix" |
258
README.md
@@ -17,11 +17,4 @@ # Nimiq Hub <!-- omit in toc --> | ||
- [Sign Transaction](#sign-transaction) | ||
- [Signup](#signup) | ||
- [Login](#login) | ||
- [Onboard](#onboard) | ||
- [Logout](#logout) | ||
- [Export](#export) | ||
- [Change Password](#change-password) | ||
- [Add Address](#add-address) | ||
- [Rename](#rename) | ||
- [Sign Message](#sign-message) | ||
- [Account Management](#account-management) | ||
- [Listening for redirect responses](#listening-for-redirect-responses) | ||
@@ -143,10 +136,2 @@ - [Running your own Hub](#running-your-own-hub) | ||
- [Sign Transaction](#sign-transaction) | ||
- [Signup](#signup) | ||
- [Login](#login) | ||
- [Onboard](#onboard) | ||
- [Logout](#logout) | ||
- [Export](#export) | ||
- [Change Password](#change-password) | ||
- [Add Address](#add-address) | ||
- [Rename](#rename) | ||
- [Sign Message](#sign-message) | ||
@@ -338,225 +323,2 @@ | ||
#### Signup | ||
The `signup()` method creates a new account in the **Hub**. The user | ||
will choose an Identicon and optionally set a password. | ||
```javascript | ||
const requestOptions = { | ||
// The name of your app, should be as short as possible. | ||
appName: 'My App', | ||
}; | ||
// All client requests are async and return a promise | ||
const accounts = await hubApi.signup(requestOptions); | ||
``` | ||
The `signup()` method returns a promise which resolves to an array of `Account`s: | ||
```javascript | ||
interface Account { | ||
accountId: string; // Automatically generated account ID | ||
label: string; // The label (name) generated for the account | ||
type: WalletType; // 1 for in-browser multi-address accounts, | ||
// 2 for Ledger hardware accounts | ||
fileExported: boolean; // These two flags signal if the user already | ||
wordsExported: boolean; // has the Login File or the recovery words | ||
addresses: Array<{ // During signup, only one address is added to the account | ||
address: string; // Human-readable address | ||
label: string; // The label (name) of the address | ||
}>; | ||
} | ||
``` | ||
#### Login | ||
The `login()` method allows the user to add an existing account to the | ||
**Hub** by importing their *Login File*, *Recovery Words* or | ||
old *Account Access File*. After an account has been imported, the | ||
**Hub** automatically detects active addresses following the | ||
[BIP44](https://github.com/bitcoin/bips/blob/master/bip-0044.mediawiki#account-discovery) | ||
method. | ||
```javascript | ||
const requestOptions = { | ||
// The name of your app, should be as short as possible. | ||
appName: 'My App', | ||
}; | ||
// All client requests are async and return a promise | ||
const accounts = await hubApi.login(requestOptions); | ||
``` | ||
The `login()` method returns a promise which resolves to an array of `Account`s. | ||
Please see the result type for [`signup()`](#signup) for details. | ||
#### Onboard | ||
The `onboard()` method presents a choice menu between _Signup_, _Login_, and | ||
_Connect Ledger_ to the user and is thus a general purpose onboarding method. | ||
Just like the direct methods, it only requires a simple request object: | ||
```javascript | ||
const requestOptions = { | ||
// The name of your app, should be as short as possible. | ||
appName: 'My App', | ||
}; | ||
// All client requests are async and return a promise | ||
const accounts = await hubApi.onboard(requestOptions); | ||
``` | ||
Since `onboard()` is a wrapper around Signup, Login and Ledger, it also returns an | ||
`Account[]` result type. Please see the result type for [`signup()`](#signup) for | ||
details. | ||
#### Logout | ||
The `logout()` method removes an account from the **Hub**. During the | ||
logout process, the user can export the *Login File* or *Recovery Words* before | ||
the account is deleted. | ||
```javascript | ||
const requestOptions = { | ||
// The name of your app, should be as short as possible. | ||
appName: 'My App', | ||
// The ID of the account that should be removed | ||
accountId: 'xxxxxxxx', | ||
}; | ||
// All client requests are async and return a promise | ||
const logoutResult = await hubApi.logout(requestOptions); | ||
``` | ||
The `logout()` method returns a promise which resolves to a simple object | ||
containing the `success` property, which is always true: | ||
```javascript | ||
{ success: true } | ||
``` | ||
#### Export | ||
Using the `export()` method, a user can retrieve the *Login File* or | ||
*Recovery Words* of an account. | ||
```javascript | ||
const requestOptions = { | ||
// The name of your app, should be as short as possible. | ||
appName: 'My App', | ||
// The ID of the account to export | ||
accountId: 'xxxxxxxx', | ||
// [optional] Limit the export flow to Login File download | ||
// Default: false, | ||
//fileOnly: true, | ||
// [optional] Limit the export flow to Recovery Words export | ||
// Default: false, | ||
//wordsOnly: true, | ||
}; | ||
// All client requests are async and return a promise | ||
const exportResult = await hubApi.export(requestOptions); | ||
``` | ||
The `export()` method returns a promise which resolves to an object that | ||
contains flags for each export type: | ||
```javascript | ||
interface ExportResult { | ||
fileExported: boolean; | ||
wordsExported: boolean; | ||
} | ||
``` | ||
#### Change Password | ||
With the `changePassword()` method, a user can change the password of an account: | ||
```javascript | ||
const requestOptions = { | ||
// The name of your app, should be as short as possible. | ||
appName: 'My App', | ||
// The ID of the account whose password should be changed | ||
accountId: 'xxxxxxxx', | ||
}; | ||
// All client requests are async and return a promise | ||
const result = await hubApi.changePassword(requestOptions); | ||
``` | ||
The `changePassword()` method returns a promise which resolves to a simple object | ||
containing the `success` property, which is always true: | ||
```javascript | ||
{ success: true } | ||
``` | ||
#### Add Address | ||
By using the `addAddress()` method, the user is able to derive and add an additional | ||
address to their account. The method returns the added address and its label. | ||
The method takes a simple request object as its argument: | ||
```javascript | ||
const requestOptions = { | ||
// The name of your app, should be as short as possible. | ||
appName: 'My App', | ||
// The ID of the account to which an address should be added | ||
accountId: 'xxxxxxxx', | ||
}; | ||
// All client requests are async and return a promise | ||
const address = await hubApi.addAddress(requestOptions); | ||
``` | ||
The request's result contains an address string as `address` and a `label`: | ||
```javascript | ||
interface Address { | ||
address: string; // Human-readable address | ||
label: string; // The address's label (name) | ||
} | ||
``` | ||
#### Rename | ||
To rename a user's account or addresses, you can call the `rename()` method. The | ||
UI for the rename action always presents the given account and all its addresses | ||
to the user. By sending an optional address with the request, that address's label | ||
will be already pre-selected for the user. | ||
This method takes the following request object as its only argument: | ||
```javascript | ||
const requestOptions = { | ||
// The name of your app, should be as short as possible. | ||
appName: 'My App', | ||
// The ID of the account which should be renamed, or to which the | ||
// address, which should be renamed, belongs | ||
accountId: 'xxxxxxxx', | ||
// [optional] The human-readable address which should be pre-selected | ||
// for the user to be renamed | ||
address: 'NQxx xxxx xxxx xxxx xxxx xxxx xxxx xxxx xxxx'; | ||
}; | ||
// All client requests are async and return a promise | ||
const account = await hubApi.rename(requestOptions); | ||
``` | ||
Since more than one label can be renamed during the rename request, the result | ||
contains the whole account, including all visible addresses. Please see the | ||
result type for [`signup()`](#signup) for details about the `Account` object. | ||
#### Sign Message | ||
@@ -630,2 +392,10 @@ | ||
### Account Management | ||
Account management functions of the Nimiq Hub, while available on the HubApi, are | ||
not yet accessible by 3rd-party apps, only by the Nimiq Safe. Developers can however | ||
configure their own builds to accept arbitrary origins for these methods. | ||
[Account Management API Documentation](https://github.com/nimiq/hub/wiki/Account-Management-API) | ||
### Listening for redirect responses | ||
@@ -660,3 +430,3 @@ | ||
hubApi.on(HubApi.RequestType.SIGN_TRANSACTION, onSuccess, onError); | ||
hubApi.on(HubApi.RequestType.LOGIN, onSuccess, onError); | ||
hubApi.on(HubApi.RequestType.CHOOSE_ADDRESS, onSuccess, onError); | ||
@@ -680,10 +450,2 @@ // 4. After setup is complete, check for a redirect response | ||
SIGN_TRANSACTION = 'sign-transaction', | ||
SIGNUP = 'signup', | ||
LOGIN = 'login', | ||
ONBOARD = 'onboard', | ||
LOGOUT = 'logout', | ||
EXPORT = 'export', | ||
CHANGE_PASSWORD = 'change-password', | ||
ADD_ADDRESS = 'add-address', | ||
RENAME = 'rename', | ||
SIGN_MESSAGE = 'sign-message', | ||
@@ -690,0 +452,0 @@ } |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
New author
Supply chain riskA new npm collaborator published a version of the package for the first time. New collaborators are usually benign additions to a project, but do indicate a change to the security surface area of a package.
Found 1 instance in 1 package
No v1
QualityPackage is not semver >=1. This means it is not stable and does not support ^ ranges.
Found 1 instance in 1 package
85237
17
982
0
0
520