From 4eecc8c3e21b9ffd7d77c5da05150a5cec308eb4 Mon Sep 17 00:00:00 2001 From: Auke van Slooten Date: Fri, 15 Dec 2023 09:19:30 +0100 Subject: [PATCH] return empty response if token fetch/refresh fails, stops the current request fixed saving state in stateMap removed incorrect response_type param in access token request only add scope to request if it is set --- dist/everything.js | 2 +- dist/everything.js.map | 2 +- src/mw/oauth2.mjs | 42 +++++++++++++++++++++++++----------------- 3 files changed, 27 insertions(+), 19 deletions(-) diff --git a/dist/everything.js b/dist/everything.js index 1fc8798..2b25891 100644 --- a/dist/everything.js +++ b/dist/everything.js @@ -1,2 +1,2 @@ -function e(e,t,o,n){Object.defineProperty(e,t,{get:o,set:n,enumerable:!0,configurable:!0})}var t=globalThis,o={},n={},s=t.parcelRequireea2c;null==s&&((s=function(e){if(e in o)return o[e].exports;if(e in n){var t=n[e];delete n[e];var s={id:e,exports:{}};return o[e]=s,t.call(s.exports,s,s.exports),s.exports}var a=Error("Cannot find module '"+e+"'");throw a.code="MODULE_NOT_FOUND",a}).register=function(e,t){n[e]=t},t.parcelRequireea2c=s),(0,s.register)("hkeot",function(t,o){e(t.exports,"symbols",()=>s),e(t.exports,"request",()=>u),e(t.exports,"metroError",()=>y),e(t.exports,"response",()=>l),e(t.exports,"client",()=>i),e(t.exports,"url",()=>h),e(t.exports,"formdata",()=>function e(...t){var o=new FormData;for(let e of t)if(e instanceof FormData)for(let t of e.entries())o.append(t[0],t[1]);else if(e&&"object"==typeof e)for(let t of Object.entries(e))if(Array.isArray(t[1]))for(let e of t[1])o.append(t[0],e);else o.append(t[0],t[1]);else throw new y("metro.formdata: unknown option type, only FormData or Object supported",e);return Object.freeze(o),new Proxy(o,{get:(t,o,n)=>{switch(o){case s.isProxy:return!0;case s.source:return t;case"with":return function(...o){return e(t,...o)};case"toString":case"toJSON":return function(){return t[o]()}}return t[o]}})}),e(t.exports,"trace",()=>w);let n="https://metro.muze.nl/details/",s={isProxy:Symbol("isProxy"),source:Symbol("source")};class a{#e={url:"undefined"!=typeof window?window.location:"https://localhost"};#t=["get","post","put","delete","patch","head","options","query"];static tracers={};constructor(...e){for(let t of e)if("string"==typeof t||t instanceof String)this.#e.url=""+t;else if(t instanceof a)Object.assign(this.#e,t.#e);else if(t instanceof Function)this.#r([t]);else if(t&&"object"==typeof t)for(let e in t)"middlewares"==e?this.#r(t[e]):"function"==typeof t[e]?this.#e[e]=t[e](this.#e[e],this.#e):this.#e[e]=t[e];for(let e of(this.#e.verbs&&(this.#t=this.#e.verbs,delete this.#e.verbs),this.#t))this[e]=async function(...t){return this.#o(u(this.#e,...t,{method:e.toUpperCase()}))};Object.freeze(this)}#r(e){"function"==typeof e&&(e=[e]);let t=e.findIndex(e=>"function"!=typeof e);if(t>=0)throw y("metro.client: middlewares must be a function or an array of functions "+n+"client/invalid-middlewares-value/",e[t]);Array.isArray(this.#e.middlewares)||(this.#e.middlewares=[]),this.#e.middlewares=this.#e.middlewares.concat(e)}#o(e){let t;if(!e.url)throw y("metro.client."+r.method.toLowerCase()+": Missing url parameter "+n+"client/missing-url-param/",e);let o=[async e=>(e[s.isProxy]&&(e=e[s.source]),l(await fetch(e)))].concat(this.#e?.middlewares?.slice()||[]);for(let e of(this.#e,o))t=function(e,t){return async function(o){let n;let s=Object.values(a.tracers);for(let e of s)e.request&&e.request.call(e,o);for(let a of(n=await t(o,e),s))a.response&&a.response.call(a,n);return n}}(t,e);return t(e)}with(...e){return new a(this,...e)}}function i(...e){return new a(...e)}function c(e,t){let o=t.body;return o||(o=null===e?new ReadableStream:e instanceof ReadableStream?e:e instanceof Blob?e.stream():new ReadableStream({start(t){let o;switch(typeof e){case"object":if("function"==typeof e.toString)o=e.toString();else if(e instanceof FormData)o=new URLSearchParams(e).toString();else if(e instanceof ArrayBuffer||ArrayBuffer.isView(e))o=e;else throw y("Cannot convert body to ReadableStream",e);break;case"string":case"number":case"boolean":o=e;break;default:throw y("Cannot convert body to ReadableStream",e)}t.enqueue(o),t.close()}})),new Proxy(o,{get(t,o,n){switch(o){case s.isProxy:return!0;case s.source:return e;case"toString":return function(){return""+e}}return"object"==typeof e&&o in e?"function"==typeof e[o]?function(...t){return e[o].apply(e,t)}:e[o]:o in t&&"toString"!=o?"function"==typeof t[o]?function(...e){return t[o].apply(t,e)}:t[o]:void 0},has:(t,o)=>o in e,ownKeys:t=>Reflect.ownKeys(e),getOwnPropertyDescriptor:(t,o)=>Object.getOwnPropertyDescriptor(e,o)})}function u(...e){let t={url:"undefined"!=typeof window?window.location:"https://localhost/",duplex:"half"};for(let o of e)"string"==typeof o||o instanceof URL||o instanceof URLSearchParams?t.url=h(t.url,o):o&&"object"==typeof o&&Object.assign(t,function(e,t){let o=t||{};for(let n of(!o.url&&t.url&&(o.url=t.url),["method","headers","body","mode","credentials","cache","redirect","referrer","referrerPolicy","integrity","keepalive","signal","priority","url"]))"function"==typeof e[n]?e[n](o[n],o):void 0!==e[n]&&("url"==n?o.url=h(o.url,e.url):o[n]=e[n]);return o}(o,t));let o=t.body;!o||"object"!=typeof o||o instanceof String||o instanceof ReadableStream||o instanceof Blob||o instanceof ArrayBuffer||o instanceof DataView||o instanceof FormData||o instanceof URLSearchParams||"undefined"!=typeof TypedArray&&o instanceof TypedArray||(t.body=JSON.stringify(o));let n=new Request(t.url,t);return Object.freeze(n),new Proxy(n,{get(e,t,n){switch(t){case s.source:return e;case s.isProxy:return!0;case"with":return function(...t){return u(e,...t)};case"toString":case"toJSON":case"blob":case"text":case"json":return function(){return e[t].apply(e)};case"body":if(o||(o=e.body),o){if(o[s.isProxy])return o;return c(o,e)}}return e[t]}})}function f(e,t){let o=t||{};for(let n of(!o.url&&t.url&&(o.url=t.url),["status","statusText","headers","body","url","type","redirected"]))"function"==typeof e[n]?e[n](o[n],o):void 0!==e[n]&&("url"==n?o.url=new URL(e.url,o.url||"https://localhost/"):o[n]=e[n]);return o}function l(...e){let t={};for(let o of e)"string"==typeof o?t.body=o:o instanceof Response?Object.assign(t,f(o,t)):o&&"object"==typeof o&&(o instanceof FormData||o instanceof Blob||o instanceof ArrayBuffer||o instanceof DataView||o instanceof ReadableStream||o instanceof URLSearchParams||o instanceof String||"undefined"!=typeof TypedArray&&o instanceof TypedArray?t.body=o:Object.assign(t,f(o,t)));let o=new Response(t.body,t);return Object.freeze(o),new Proxy(o,{get(e,o,n){switch(o){case s.isProxy:return!0;case s.source:return e;case"with":return function(...t){return l(e,...t)};case"body":if(!t.body)return c("",e);if(t.body[s.isProxy])return t.body;return c(t.body,e);case"ok":return e.status>=200&&e.status<400;case"headers":return e.headers;default:if(o in t&&"toString"!=o)return t[o];if(o in e&&"toString"!=o){if("function"==typeof e[o])return function(...t){return e[o].apply(e,t)};return e[o]}}}})}function p(e,t){"function"==typeof t?t(e.searchParams,e):(t=new URLSearchParams(t)).forEach((t,o)=>{e.searchParams.append(o,t)})}function h(...e){let t=["hash","host","hostname","href","password","pathname","port","protocol","username","search","searchParams"],o=new URL("https://localhost/");for(let s of e)if("string"==typeof s||s instanceof String)o=new URL(s,o);else if(s instanceof URL||"undefined"!=typeof Location&&s instanceof Location)o=new URL(s);else if(s instanceof URLSearchParams)p(o,s);else if(s&&"object"==typeof s)for(let a in s)if("search"==a)"function"==typeof s.search?s.search(o.search,o):o.search=new URLSearchParams(s.search);else if("searchParams"==a)p(o,s.searchParams);else{if(!t.includes(a))throw y("metro.url: unknown url parameter "+n+"url/unknown-param-name/",a);if("function"==typeof s[a])s[a](o[a],o);else if("string"==typeof s[a]||s[a]instanceof String||"number"==typeof s[a]||s[a]instanceof Number||"boolean"==typeof s[a]||s[a]instanceof Boolean)o[a]=""+s[a];else if("object"==typeof s[a]&&s[a].toString)o[a]=s[a].toString();else throw y("metro.url: unsupported value for "+a+" "+n+"url/unsupported-param-value/",e[a])}else throw y("metro.url: unsupported option value "+n+"url/unsupported-option-value/",s);return Object.freeze(o),new Proxy(o,{get(e,t,o){switch(t){case s.isProxy:return!0;case s.source:return e;case"with":return function(...t){return h(e,...t)};case"toString":case"toJSON":return function(){return e[t]()}}return e[t]}})}let d={error:(e,...t)=>{console.error("Ⓜ️ ",e,...t)},info:(e,...t)=>{console.info("Ⓜ️ ",e,...t)},group:e=>{console.group("Ⓜ️ "+e)},groupEnd:e=>{console.groupEnd("Ⓜ️ "+e)}};function y(e,...t){return d.error(e,...t),Error(e,...t)}let w={add(e,t){a.tracers[e]=t},delete(e){delete a.tracers[e]},clear(){a.tracers={}},group(){let e=0;return{request:t=>{e++,d.group(e),d.info(t?.url,t)},response:t=>{d.info(t?.body?t.body[s.source]:null,t),d.groupEnd(e),e--}}}}});var a=s("hkeot"),i={};e(i,"enable",()=>u),e(i,"disable",()=>f),e(i,"fails",()=>l),e(i,"check",()=>p),e(i,"optional",()=>h),e(i,"oneOf",()=>d);let c=!1;function u(){c=!0}function f(){c=!1}function l(e,t){let o=[];if(t instanceof RegExp){if(Array.isArray(e)){let n=e.findIndex(e=>l(e,t));n>-1&&o.push("data["+n+"] does not match pattern")}else t.test(e)||o.push("data does not match pattern "+t)}else if(t instanceof Function)t(e)&&o.push("data does not match function");else if(t&&"object"==typeof t){if(Array.isArray(e)){let n=e.findIndex(e=>l(e,t));n>-1&&o.push("data["+n+"] does not match pattern")}else if(e&&"object"==typeof e){e instanceof URLSearchParams&&(e=Object.fromEntries(e));let n=o[o.length-1];for(let[s,a]of Object.entries(t)){let t=l(e[s],a);t&&(n&&"string"!=typeof n||(n={},o.push(n)),n[s]=t.problems)}}else o.push("data is not an object, pattern is")}else t!=e&&o.push("data does not equal "+t);return!!o.length&&o}function p(e,t){if(!c)return;let o=l(e,t);if(o)throw new y(o,e)}function h(e){return function(t){return null!=t&&void 0!==t&&l(t,e)}}function d(...e){return function(t){for(let o of e)if(!l(t,o))return!1;return["data does not match oneOf patterns"]}}class y{constructor(e,...t){this.problems=e,this.details=t,console.trace()}}function w(e){return e=Object.assign({reviver:null,replacer:null,space:""},e),async(t,o)=>{["POST","PUT","PATCH","QUERY"].includes(t.method)?(t=t.with({headers:{"Content-Type":"application/json",Accept:"application/json"}})).body&&"object"==typeof t.body[a.symbols.source]&&(t=t.with({body:JSON.stringify(t.body[a.symbols.source],e.replacer,e.space)})):t=t.with({headers:{Accept:"application/json"}});let n=await o(t),s=JSON.parse(await n.text(),e.reviver);return n.with({body:s})}}var a=(s("hkeot"),s("hkeot"));window.metro=a,window.assert=i,window.metro.mw={jsonmw:w,oauth2:function(e){let t={tokens:new Map,state:"undefined"!=typeof localStorage?localStorage:new Map,endpoints:{},callbacks:{},client:a.client().with(w()),client_id:"",client_secret:"",redirect_uri:"",grant_type:"authorization_code",force_authorization:!1};for(let o in e){switch(o){case"access_token":case"authorization_code":case"refresh_token":t.tokens.set(o,e[o]);break;case"client":case"client_id":case"client_secret":case"grant_type":case"force_authorization":case"redirect_uri":t[o]=e[o];break;case"state":case"tokens":if("function"==typeof e[o].set&&"function"==typeof e[o].get&&"function"==typeof e[o].has)t[o]=e[o];else if("tokens"==o&&"object"==typeof e.tokens)for(let o in e.tokens)t.tokens.set(o,e.tokens[o]);else throw a.metroError("metro/mw/oauth2: incorrect value for "+o);break;case"endpoints":for(let t in e.endpoints)if("authorize"!=t&&"token"!=t)throw a.metroError('Unknown endpoint, choose one of "authorize" or "token"',t);Object.assign(t.endpoints,e.endpoints);break;case"callbacks":for(let t in e.callbacks)if("authorize"!=t)throw a.metroError('Unknown callback, choose one of "authorize"',t);Object.assign(t.callbacks,e.callbacks);break;default:throw a.metroError("Unknown oauth2mw option ",o)}t.redirect_uri||(t.redirect_uri="undefined"!=typeof window?window.location?.href:""),t.redirect_uri&&(t.redirect_uri=a.url(t.redirect_uri).with("?metroRedirect=true"))}return async function(e,n){if(t.force_authorization)return o(e,n);let s=await n(e);if(s.ok)return s;switch(s.status){case 400:case 401:return o(e,n)}return s};async function o(e,i){if(function(){if("undefined"!=typeof window&&window?.location){let e,o,n,s=a.url(window.location);if(s.searchParams.has("code"))n=s.searchParams,s=s.with({search:""}),history.pushState({},"",s.href);else if(s.hash){let e=s.hash.substr(1);n=new URLSearchParams("?"+e),s=s.with({hash:""}),history.pushState({},"",s.href)}if(n){e=n.get("code"),o=n.get("state");let s=t.state.get("metro/state");if(!o||o!==s)return;e&&t.tokens.set("authorization_code",e)}}}(),!t.tokens.has("access_token"))return await n(e),o(e,i);if(function(e){if(e.oauth2&&e.oauth2.tokens&&e.oauth2.tokens.has("access_token")){let t=new Date,o=e.oauth2.tokens.get("access_token");return t.getTime()>o.expires.getTime()}return!1}(e))return await s(e),o(e,i);{let o=t.tokens.get("access_token");return i(e=a.request(e,{headers:{Authorization:o.type+" "+o.value}}))}}async function n(e){if("authorization_code"===t.grant_type&&!t.tokens.has("authorization_code")){let e=function(){if(!t.endpoints.authorize)throw a.metroError("oauth2mw: Missing options.endpoints.authorize url");let e=a.url(t.endpoints.authorize,{hash:""});return p(t,{client_id:/.+/,redirect_uri:/.+/,scope:/.*/}),a.url(e,{search:{response_type:"code",client_id:t.client_id,redirect_uri:t.redirect_uri,scope:t.scope,state:function(e){let o="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789",n="",s=0;for(;s<40;)n+=o.charAt(Math.floor(Math.random()*o.length)),s++;return t.state.set(n),n}(0)}})}();if(!t.callbacks.authorize||"function"!=typeof t.callbacks.authorize)throw a.metroError("oauth2mw: oauth2 with grant_type:authorization_code requires a callback function in client options.oauth2.callbacks.authorize");let o=await t.callbacks.authorize(e);o&&t.tokens.set("authorization_code",o)}let o=i(),n=await t.client.get(o);if(!n.ok)throw a.metroError(n.status+":"+n.statusText,await n.text());let s=await n.json();return t.tokens.set("access_token",{value:s.access_token,expires:c(s.expires_in),type:s.token_type,scope:s.scope}),s.refresh_token&&t.tokens.set("refresh_token",s.refresh_token),s}async function s(e,o){let n=i("refresh_token"),s=await t.client.get(n);if(!s.ok)throw a.metroError(res.status+":"+res.statusText,await res.text());let u=await s.json();return t.tokens.set("access_token",{value:u.access_token,expires:c(u.expires_in),type:u.token_type,scope:u.scope}),u.refresh_token&&t.tokens.set("refresh_token",u.refresh_token),u}function i(e=null){if(p(t,{client_id:/.+/,client_secret:/.+/,redirect_uri:/.+/}),!t.endpoints.token)throw a.metroError("oauth2mw: Missing options.endpoints.token url");let o=a.url(t.endpoints.token,{hash:""}),n={grant_type:e||t.grant_type,client_id:t.client_id,client_secret:t.client_secret};switch(t.scope&&(n.scope=t.scope),t.grant_type){case"authorization_code":n.redirect_uri=t.redirect_uri,n.code=t.tokens.get("authorization_code"),n.response_type="token";break;case"client_credentials":case"refresh_token":throw Error("Not yet implemented")}return a.request(o,{method:"GET",url:{searchParams:n}})}function c(e){if(e instanceof Date)return new Date(e.getTime());if("number"==typeof e){let t=new Date;return t.setSeconds(t.getSeconds()+e),t}throw TypeError("Unknown expires type "+e)}}}; +function e(e,t,o,n){Object.defineProperty(e,t,{get:o,set:n,enumerable:!0,configurable:!0})}var t=globalThis,o={},n={},s=t.parcelRequireea2c;null==s&&((s=function(e){if(e in o)return o[e].exports;if(e in n){var t=n[e];delete n[e];var s={id:e,exports:{}};return o[e]=s,t.call(s.exports,s,s.exports),s.exports}var a=Error("Cannot find module '"+e+"'");throw a.code="MODULE_NOT_FOUND",a}).register=function(e,t){n[e]=t},t.parcelRequireea2c=s),(0,s.register)("hkeot",function(t,o){e(t.exports,"symbols",()=>s),e(t.exports,"request",()=>u),e(t.exports,"metroError",()=>y),e(t.exports,"response",()=>f),e(t.exports,"client",()=>i),e(t.exports,"url",()=>h),e(t.exports,"formdata",()=>function e(...t){var o=new FormData;for(let e of t)if(e instanceof FormData)for(let t of e.entries())o.append(t[0],t[1]);else if(e&&"object"==typeof e)for(let t of Object.entries(e))if(Array.isArray(t[1]))for(let e of t[1])o.append(t[0],e);else o.append(t[0],t[1]);else throw new y("metro.formdata: unknown option type, only FormData or Object supported",e);return Object.freeze(o),new Proxy(o,{get:(t,o,n)=>{switch(o){case s.isProxy:return!0;case s.source:return t;case"with":return function(...o){return e(t,...o)};case"toString":case"toJSON":return function(){return t[o]()}}return t[o]}})}),e(t.exports,"trace",()=>w);let n="https://metro.muze.nl/details/",s={isProxy:Symbol("isProxy"),source:Symbol("source")};class a{#e={url:"undefined"!=typeof window?window.location:"https://localhost"};#t=["get","post","put","delete","patch","head","options","query"];static tracers={};constructor(...e){for(let t of e)if("string"==typeof t||t instanceof String)this.#e.url=""+t;else if(t instanceof a)Object.assign(this.#e,t.#e);else if(t instanceof Function)this.#r([t]);else if(t&&"object"==typeof t)for(let e in t)"middlewares"==e?this.#r(t[e]):"function"==typeof t[e]?this.#e[e]=t[e](this.#e[e],this.#e):this.#e[e]=t[e];for(let e of(this.#e.verbs&&(this.#t=this.#e.verbs,delete this.#e.verbs),this.#t))this[e]=async function(...t){return this.#o(u(this.#e,...t,{method:e.toUpperCase()}))};Object.freeze(this)}#r(e){"function"==typeof e&&(e=[e]);let t=e.findIndex(e=>"function"!=typeof e);if(t>=0)throw y("metro.client: middlewares must be a function or an array of functions "+n+"client/invalid-middlewares-value/",e[t]);Array.isArray(this.#e.middlewares)||(this.#e.middlewares=[]),this.#e.middlewares=this.#e.middlewares.concat(e)}#o(e){let t;if(!e.url)throw y("metro.client."+r.method.toLowerCase()+": Missing url parameter "+n+"client/missing-url-param/",e);let o=[async e=>(e[s.isProxy]&&(e=e[s.source]),f(await fetch(e)))].concat(this.#e?.middlewares?.slice()||[]);for(let e of(this.#e,o))t=function(e,t){return async function(o){let n;let s=Object.values(a.tracers);for(let e of s)e.request&&e.request.call(e,o);for(let a of(n=await t(o,e),s))a.response&&a.response.call(a,n);return n}}(t,e);return t(e)}with(...e){return new a(this,...e)}}function i(...e){return new a(...e)}function c(e,t){let o=t.body;return o||(o=null===e?new ReadableStream:e instanceof ReadableStream?e:e instanceof Blob?e.stream():new ReadableStream({start(t){let o;switch(typeof e){case"object":if("function"==typeof e.toString)o=e.toString();else if(e instanceof FormData)o=new URLSearchParams(e).toString();else if(e instanceof ArrayBuffer||ArrayBuffer.isView(e))o=e;else throw y("Cannot convert body to ReadableStream",e);break;case"string":case"number":case"boolean":o=e;break;default:throw y("Cannot convert body to ReadableStream",e)}t.enqueue(o),t.close()}})),new Proxy(o,{get(t,o,n){switch(o){case s.isProxy:return!0;case s.source:return e;case"toString":return function(){return""+e}}return"object"==typeof e&&o in e?"function"==typeof e[o]?function(...t){return e[o].apply(e,t)}:e[o]:o in t&&"toString"!=o?"function"==typeof t[o]?function(...e){return t[o].apply(t,e)}:t[o]:void 0},has:(t,o)=>o in e,ownKeys:t=>Reflect.ownKeys(e),getOwnPropertyDescriptor:(t,o)=>Object.getOwnPropertyDescriptor(e,o)})}function u(...e){let t={url:"undefined"!=typeof window?window.location:"https://localhost/",duplex:"half"};for(let o of e)"string"==typeof o||o instanceof URL||o instanceof URLSearchParams?t.url=h(t.url,o):o&&"object"==typeof o&&Object.assign(t,function(e,t){let o=t||{};for(let n of(!o.url&&t.url&&(o.url=t.url),["method","headers","body","mode","credentials","cache","redirect","referrer","referrerPolicy","integrity","keepalive","signal","priority","url"]))"function"==typeof e[n]?e[n](o[n],o):void 0!==e[n]&&("url"==n?o.url=h(o.url,e.url):o[n]=e[n]);return o}(o,t));let o=t.body;!o||"object"!=typeof o||o instanceof String||o instanceof ReadableStream||o instanceof Blob||o instanceof ArrayBuffer||o instanceof DataView||o instanceof FormData||o instanceof URLSearchParams||"undefined"!=typeof TypedArray&&o instanceof TypedArray||(t.body=JSON.stringify(o));let n=new Request(t.url,t);return Object.freeze(n),new Proxy(n,{get(e,t,n){switch(t){case s.source:return e;case s.isProxy:return!0;case"with":return function(...t){return u(e,...t)};case"toString":case"toJSON":case"blob":case"text":case"json":return function(){return e[t].apply(e)};case"body":if(o||(o=e.body),o){if(o[s.isProxy])return o;return c(o,e)}}return e[t]}})}function l(e,t){let o=t||{};for(let n of(!o.url&&t.url&&(o.url=t.url),["status","statusText","headers","body","url","type","redirected"]))"function"==typeof e[n]?e[n](o[n],o):void 0!==e[n]&&("url"==n?o.url=new URL(e.url,o.url||"https://localhost/"):o[n]=e[n]);return o}function f(...e){let t={};for(let o of e)"string"==typeof o?t.body=o:o instanceof Response?Object.assign(t,l(o,t)):o&&"object"==typeof o&&(o instanceof FormData||o instanceof Blob||o instanceof ArrayBuffer||o instanceof DataView||o instanceof ReadableStream||o instanceof URLSearchParams||o instanceof String||"undefined"!=typeof TypedArray&&o instanceof TypedArray?t.body=o:Object.assign(t,l(o,t)));let o=new Response(t.body,t);return Object.freeze(o),new Proxy(o,{get(e,o,n){switch(o){case s.isProxy:return!0;case s.source:return e;case"with":return function(...t){return f(e,...t)};case"body":if(!t.body)return c("",e);if(t.body[s.isProxy])return t.body;return c(t.body,e);case"ok":return e.status>=200&&e.status<400;case"headers":return e.headers;default:if(o in t&&"toString"!=o)return t[o];if(o in e&&"toString"!=o){if("function"==typeof e[o])return function(...t){return e[o].apply(e,t)};return e[o]}}}})}function p(e,t){"function"==typeof t?t(e.searchParams,e):(t=new URLSearchParams(t)).forEach((t,o)=>{e.searchParams.append(o,t)})}function h(...e){let t=["hash","host","hostname","href","password","pathname","port","protocol","username","search","searchParams"],o=new URL("https://localhost/");for(let s of e)if("string"==typeof s||s instanceof String)o=new URL(s,o);else if(s instanceof URL||"undefined"!=typeof Location&&s instanceof Location)o=new URL(s);else if(s instanceof URLSearchParams)p(o,s);else if(s&&"object"==typeof s)for(let a in s)if("search"==a)"function"==typeof s.search?s.search(o.search,o):o.search=new URLSearchParams(s.search);else if("searchParams"==a)p(o,s.searchParams);else{if(!t.includes(a))throw y("metro.url: unknown url parameter "+n+"url/unknown-param-name/",a);if("function"==typeof s[a])s[a](o[a],o);else if("string"==typeof s[a]||s[a]instanceof String||"number"==typeof s[a]||s[a]instanceof Number||"boolean"==typeof s[a]||s[a]instanceof Boolean)o[a]=""+s[a];else if("object"==typeof s[a]&&s[a].toString)o[a]=s[a].toString();else throw y("metro.url: unsupported value for "+a+" "+n+"url/unsupported-param-value/",e[a])}else throw y("metro.url: unsupported option value "+n+"url/unsupported-option-value/",s);return Object.freeze(o),new Proxy(o,{get(e,t,o){switch(t){case s.isProxy:return!0;case s.source:return e;case"with":return function(...t){return h(e,...t)};case"toString":case"toJSON":return function(){return e[t]()}}return e[t]}})}let d={error:(e,...t)=>{console.error("Ⓜ️ ",e,...t)},info:(e,...t)=>{console.info("Ⓜ️ ",e,...t)},group:e=>{console.group("Ⓜ️ "+e)},groupEnd:e=>{console.groupEnd("Ⓜ️ "+e)}};function y(e,...t){return d.error(e,...t),Error(e,...t)}let w={add(e,t){a.tracers[e]=t},delete(e){delete a.tracers[e]},clear(){a.tracers={}},group(){let e=0;return{request:t=>{e++,d.group(e),d.info(t?.url,t)},response:t=>{d.info(t?.body?t.body[s.source]:null,t),d.groupEnd(e),e--}}}}});var a=s("hkeot"),i={};e(i,"enable",()=>u),e(i,"disable",()=>l),e(i,"fails",()=>f),e(i,"check",()=>p),e(i,"optional",()=>h),e(i,"oneOf",()=>d);let c=!1;function u(){c=!0}function l(){c=!1}function f(e,t){let o=[];if(t instanceof RegExp){if(Array.isArray(e)){let n=e.findIndex(e=>f(e,t));n>-1&&o.push("data["+n+"] does not match pattern")}else t.test(e)||o.push("data does not match pattern "+t)}else if(t instanceof Function)t(e)&&o.push("data does not match function");else if(t&&"object"==typeof t){if(Array.isArray(e)){let n=e.findIndex(e=>f(e,t));n>-1&&o.push("data["+n+"] does not match pattern")}else if(e&&"object"==typeof e){e instanceof URLSearchParams&&(e=Object.fromEntries(e));let n=o[o.length-1];for(let[s,a]of Object.entries(t)){let t=f(e[s],a);t&&(n&&"string"!=typeof n||(n={},o.push(n)),n[s]=t.problems)}}else o.push("data is not an object, pattern is")}else t!=e&&o.push("data does not equal "+t);return!!o.length&&o}function p(e,t){if(!c)return;let o=f(e,t);if(o)throw new y(o,e)}function h(e){return function(t){return null!=t&&void 0!==t&&f(t,e)}}function d(...e){return function(t){for(let o of e)if(!f(t,o))return!1;return["data does not match oneOf patterns"]}}class y{constructor(e,...t){this.problems=e,this.details=t,console.trace()}}function w(e){return e=Object.assign({reviver:null,replacer:null,space:""},e),async(t,o)=>{["POST","PUT","PATCH","QUERY"].includes(t.method)?(t=t.with({headers:{"Content-Type":"application/json",Accept:"application/json"}})).body&&"object"==typeof t.body[a.symbols.source]&&(t=t.with({body:JSON.stringify(t.body[a.symbols.source],e.replacer,e.space)})):t=t.with({headers:{Accept:"application/json"}});let n=await o(t),s=JSON.parse(await n.text(),e.reviver);return n.with({body:s})}}var a=(s("hkeot"),s("hkeot"));window.metro=a,window.assert=i,window.metro.mw={jsonmw:w,oauth2:function(e){let t;if("undefined"!=typeof localStorage)t={get:()=>localStorage.getItem("metro/state"),has:()=>localStorage.getItem("metro/state"),set:e=>localStorage.setItem("metro/state",e)};else{let e=new Map;t={get:()=>e.get("metro/state"),has:()=>e.get("metro/state"),set:t=>e.set("metro/state",t)}}let o={tokens:new Map,state:t,endpoints:{},callbacks:{},client:a.client().with(w()),client_id:"",client_secret:"",redirect_uri:"",grant_type:"authorization_code",force_authorization:!1};for(let t in e){switch(t){case"access_token":case"authorization_code":case"refresh_token":o.tokens.set(t,e[t]);break;case"client":case"client_id":case"client_secret":case"grant_type":case"force_authorization":case"redirect_uri":o[t]=e[t];break;case"state":case"tokens":if("function"==typeof e[t].set&&"function"==typeof e[t].get&&"function"==typeof e[t].has)o[t]=e[t];else if("tokens"==t&&"object"==typeof e.tokens)for(let t in e.tokens)o.tokens.set(t,e.tokens[t]);else throw a.metroError("metro/mw/oauth2: incorrect value for "+t);break;case"endpoints":for(let t in e.endpoints)if("authorize"!=t&&"token"!=t)throw a.metroError('Unknown endpoint, choose one of "authorize" or "token"',t);Object.assign(o.endpoints,e.endpoints);break;case"callbacks":for(let t in e.callbacks)if("authorize"!=t)throw a.metroError('Unknown callback, choose one of "authorize"',t);Object.assign(o.callbacks,e.callbacks);break;default:throw a.metroError("Unknown oauth2mw option ",t)}o.redirect_uri||(o.redirect_uri="undefined"!=typeof window?window.location?.href:""),o.redirect_uri&&(o.redirect_uri=a.url(o.redirect_uri).with("?metroRedirect=true"))}return async function(e,t){if(o.force_authorization)return n(e,t);let s=await t(e);if(s.ok)return s;switch(s.status){case 400:case 401:return n(e,t)}return s};async function n(e,t){if(function(){if("undefined"!=typeof window&&window?.location){let e,t,n,s=a.url(window.location);if(s.searchParams.has("code"))n=s.searchParams,s=s.with({search:""}),history.pushState({},"",s.href);else if(s.hash){let e=s.hash.substr(1);n=new URLSearchParams("?"+e),s=s.with({hash:""}),history.pushState({},"",s.href)}if(n){e=n.get("code"),t=n.get("state");let s=o.state.get("metro/state");if(!t||t!==s)return;e&&o.tokens.set("authorization_code",e)}}}(),o.tokens.has("access_token")){if(function(e){if(e.oauth2&&e.oauth2.tokens&&e.oauth2.tokens.has("access_token")){let t=new Date,o=e.oauth2.tokens.get("access_token");return t.getTime()>o.expires.getTime()}return!1}(e))return await i(e)?n(e,t):a.response("false");{let n=o.tokens.get("access_token");return t(e=a.request(e,{headers:{Authorization:n.type+" "+n.value}}))}}return await s(e)?n(e,t):a.response("false")}async function s(e){if("authorization_code"===o.grant_type&&!o.tokens.has("authorization_code")){let e=function(){if(!o.endpoints.authorize)throw a.metroError("oauth2mw: Missing options.endpoints.authorize url");let e=a.url(o.endpoints.authorize,{hash:""});p(o,{client_id:/.+/,redirect_uri:/.+/,scope:/.*/});let t={response_type:"code",client_id:o.client_id,redirect_uri:o.redirect_uri,state:function(e){let t="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789",n="",s=0;for(;s<40;)n+=t.charAt(Math.floor(Math.random()*t.length)),s++;return o.state.set(n),n}(0)};return o.scope&&(t.scope=o.scope),a.url(e,{search:t})}();if(!o.callbacks.authorize||"function"!=typeof o.callbacks.authorize)throw a.metroError("oauth2mw: oauth2 with grant_type:authorization_code requires a callback function in client options.oauth2.callbacks.authorize");let t=await o.callbacks.authorize(e);if(!t)return a.response(!1);o.tokens.set("authorization_code",t)}let t=c(),n=await o.client.get(t);if(!n.ok)throw a.metroError(n.status+":"+n.statusText,await n.text());let s=await n.json();return o.tokens.set("access_token",{value:s.access_token,expires:u(s.expires_in),type:s.token_type,scope:s.scope}),s.refresh_token&&o.tokens.set("refresh_token",s.refresh_token),s}async function i(e,t){let n=c("refresh_token"),s=await o.client.get(n);if(!s.ok)throw a.metroError(s.status+":"+s.statusText,await s.text());let i=await s.json();return o.tokens.set("access_token",{value:i.access_token,expires:u(i.expires_in),type:i.token_type,scope:i.scope}),i.refresh_token&&o.tokens.set("refresh_token",i.refresh_token),i}function c(e=null){if(p(o,{client_id:/.+/,client_secret:/.+/,redirect_uri:/.+/}),!o.endpoints.token)throw a.metroError("oauth2mw: Missing options.endpoints.token url");let t=a.url(o.endpoints.token,{hash:""}),n={grant_type:e||o.grant_type,client_id:o.client_id,client_secret:o.client_secret};switch(o.scope&&(n.scope=o.scope),o.grant_type){case"authorization_code":n.redirect_uri=o.redirect_uri,n.code=o.tokens.get("authorization_code");break;case"client_credentials":case"refresh_token":throw Error("Not yet implemented")}return a.request(t,{method:"GET",url:{searchParams:n}})}function u(e){if(e instanceof Date)return new Date(e.getTime());if("number"==typeof e){let t=new Date;return t.setSeconds(t.getSeconds()+e),t}throw TypeError("Unknown expires type "+e)}}}; //# sourceMappingURL=everything.js.map diff --git a/dist/everything.js.map b/dist/everything.js.map index 0bded57..4396453 100644 --- a/dist/everything.js.map +++ b/dist/everything.js.map @@ -1 +1 @@ -{"mappings":"A,S,E,C,C,C,C,C,C,C,E,O,c,C,E,E,C,I,E,I,E,W,C,E,a,C,C,E,C,I,E,W,E,C,E,E,C,E,E,E,iB,A,O,I,A,C,E,S,C,E,G,K,E,O,C,C,E,C,O,C,G,K,E,C,I,E,C,C,E,A,Q,C,C,E,C,I,E,C,G,E,Q,C,C,E,O,C,C,E,C,E,E,I,C,E,O,C,E,E,O,E,E,O,A,C,I,E,A,M,uB,E,I,O,E,I,C,mB,C,C,E,Q,C,S,C,C,C,E,C,C,E,C,C,E,E,iB,C,G,A,C,E,E,Q,A,E,Q,S,C,C,C,E,E,E,O,C,U,I,G,E,E,O,C,U,I,G,E,E,O,C,a,I,G,E,E,O,C,W,I,G,E,E,O,C,S,I,G,E,E,O,C,M,I,G,E,E,O,C,W,IC2gBO,SAAS,EAAS,GAAG,CAAO,EAClC,IAAI,EAAS,IAAI,SACjB,IAAK,IAAI,KAAU,EAClB,GAAI,aAAkB,SACrB,IAAK,IAAI,KAAS,EAAO,OAAO,GAC/B,EAAO,MAAM,CAAC,CAAK,CAAC,EAAE,CAAC,CAAK,CAAC,EAAE,OAE1B,GAAI,GAAU,AAAiB,UAAjB,OAAO,EAC3B,IAAK,IAAI,KAAS,OAAO,OAAO,CAAC,GAChC,GAAI,MAAM,OAAO,CAAC,CAAK,CAAC,EAAE,EACzB,IAAK,IAAI,KAAS,CAAK,CAAC,EAAE,CACzB,EAAO,MAAM,CAAC,CAAK,CAAC,EAAE,CAAE,QAGzB,EAAO,MAAM,CAAC,CAAK,CAAC,EAAE,CAAC,CAAK,CAAC,EAAE,OAIjC,MAAM,IAAI,EAAW,yEAAyE,GAIhG,OADA,OAAO,MAAM,CAAC,GACP,IAAI,MAAM,EAAQ,CACxB,IAAK,CAAC,EAAO,EAAK,KACjB,OAAO,GACN,KAAK,EAAQ,OAAO,CACnB,MAAO,CAAA,CAER,MAAK,EAAQ,MAAM,CAClB,OAAO,CAER,KAAK,OACJ,OAAO,SAAS,GAAG,CAAO,EACzB,OAAO,EAAS,KAAW,EAC5B,CAED,KAAK,WACL,IAAK,SACJ,OAAO,WACN,OAAO,CAAM,CAAC,EAAK,EACpB,CAEF,CACA,OAAO,CAAM,CAAC,EAAK,AACpB,CACD,EACD,G,E,E,O,C,Q,I,GAzjBA,IAAM,EAAW,iCAEJ,EAAU,CACtB,QAAS,OAAO,WAChB,OAAQ,OAAO,SAChB,CAEA,OAAM,EACL,CAAC,CAAO,CAAG,CACV,IAAK,AAAiB,aAAjB,OAAO,OAAwB,OAAO,QAAQ,CAAG,mBACvD,CAAC,AACD,EAAC,CAAK,CAAG,CAAC,MAAM,OAAO,MAAM,SAAS,QAAQ,OAAO,UAAU,QAAQ,AAAA,AAEvE,QAAO,QAAU,CAAC,CAAC,AAEnB,aAAY,GAAG,CAAO,CAAE,CACvB,IAAK,IAAI,KAAU,EAClB,GAAI,AAAiB,UAAjB,OAAO,GAAsB,aAAkB,OAClD,IAAI,CAAC,CAAC,CAAO,CAAC,GAAG,CAAG,GAAG,OACjB,GAAI,aAAkB,EAC5B,OAAO,MAAM,CAAC,IAAI,CAAC,CAAC,CAAO,CAAE,EAAO,CAAC,CAAO,OACtC,GAAI,aAAkB,SAC5B,IAAI,CAAC,CAAC,CAAc,CAAC,CAAC,EAAO,OACvB,GAAI,GAAU,AAAiB,UAAjB,OAAO,EAC3B,IAAK,IAAI,KAAS,EACb,AAAS,eAAT,EACH,IAAI,CAAC,CAAC,CAAc,CAAC,CAAM,CAAC,EAAM,EACxB,AAAwB,YAAxB,OAAO,CAAM,CAAC,EAAM,CAC9B,IAAI,CAAC,CAAC,CAAO,CAAC,EAAM,CAAG,CAAM,CAAC,EAAM,CAAC,IAAI,CAAC,CAAC,CAAO,CAAC,EAAM,CAAE,IAAI,CAAC,CAAC,CAAO,EAExE,IAAI,CAAC,CAAC,CAAO,CAAC,EAAM,CAAG,CAAM,CAAC,EAAM,CAUxC,IAAK,IAAM,KALP,IAAI,CAAC,CAAC,CAAO,CAAC,KAAK,GACtB,IAAI,CAAC,CAAC,CAAK,CAAG,IAAI,CAAC,CAAC,CAAO,CAAC,KAAK,CACjC,OAAO,IAAI,CAAC,CAAC,CAAO,CAAC,KAAK,EAGR,IAAI,CAAC,CAAC,CAAK,EAC7B,IAAI,CAAC,EAAK,CAAG,eAAe,GAAG,CAAO,EACrC,OAAO,IAAI,CAAC,CAAC,CAAK,CAAC,EAClB,IAAI,CAAC,CAAC,CAAO,IACV,EACH,CAAC,OAAQ,EAAK,WAAW,EAAE,GAE7B,EAED,OAAO,MAAM,CAAC,IAAI,CACnB,CAEA,CAAC,CAAc,CAAC,CAAW,EACA,YAAtB,OAAO,GACV,CAAA,EAAc,CAAE,EAAa,AAAA,EAE9B,IAAI,EAAQ,EAAY,SAAS,CAAC,AAAA,GAAK,AAAY,YAAZ,OAAO,GAC9C,GAAI,GAAO,EACV,MAAM,EAAW,yEACf,EAAS,oCAAqC,CAAW,CAAC,EAAM,EAE9D,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC,CAAO,CAAC,WAAW,GAC3C,CAAA,IAAI,CAAC,CAAC,CAAO,CAAC,WAAW,CAAG,EAAE,AAAF,EAE7B,IAAI,CAAC,CAAC,CAAO,CAAC,WAAW,CAAG,IAAI,CAAC,CAAC,CAAO,CAAC,WAAW,CAAC,MAAM,CAAC,EAC9D,CAEA,CAAC,CAAK,CAAC,CAAG,MAgBL,EAfJ,GAAI,CAAC,EAAI,GAAG,CACX,MAAM,EAAW,gBAAgB,EAAE,MAAM,CAAC,WAAW,GAAG,2BAA2B,EAAS,4BAA6B,GAW1H,IAAI,EAAc,CATD,MAAO,IACnB,CAAG,CAAC,EAAQ,OAAO,CAAC,EAIvB,CAAA,EAAM,CAAG,CAAC,EAAQ,MAAM,CAAC,AAAD,EAElB,EAAS,MAAM,MAAM,KAEC,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAO,EAAE,aAAa,SAAW,EAAE,EAI/E,IAAK,IAAI,KAHK,IAAI,CAAC,CAAC,CAAO,CAGJ,GACtB,EAAO,SAAU,CAAI,CAAE,CAAU,EAChC,OAAO,eAAe,CAAG,MACpB,EACJ,IAAI,EAAU,OAAO,MAAM,CAAC,EAAO,OAAO,EAC1C,IAAI,IAAI,KAAU,EACb,EAAO,OAAO,EACjB,EAAO,OAAO,CAAC,IAAI,CAAC,EAAQ,GAI9B,IAAI,IAAI,KADR,EAAM,MAAM,EAAW,EAAK,GACV,GACb,EAAO,QAAQ,EAClB,EAAO,QAAQ,CAAC,IAAI,CAAC,EAAQ,GAG/B,OAAO,CACR,CACD,EAAG,EAAM,GAEV,OAAO,EAAK,EACb,CAEA,KAAK,GAAG,CAAO,CAAE,CAChB,OAAO,IAAI,EAAO,IAAI,IAAK,EAC5B,CACD,CAEO,SAAS,EAAO,GAAG,CAAO,EAChC,OAAO,IAAI,KAAU,EACtB,CAwBA,SAAS,EAAU,CAAI,CAAE,CAAC,EACzB,IAAI,EAAS,EAAE,IAAI,CA8CnB,OA7CK,IAKH,EADG,AAAS,OAAT,EACM,IAAI,eACH,aAAgB,eACjB,EACC,aAAgB,KACjB,EAAK,MAAM,GAEX,IAAI,eAAe,CAC3B,MAAM,CAAU,EACf,IAAI,EACJ,OAAO,OAAO,GACb,IAAK,SACJ,GAAI,AAAwB,YAAxB,OAAO,EAAK,QAAQ,CAEvB,EAAQ,EAAK,QAAQ,QACf,GAAI,aAAgB,SAC1B,EAAQ,IAAI,gBAAgB,GAAM,QAAQ,QACpC,GAAI,aAAgB,aACvB,YAAY,MAAM,CAAC,GAGtB,EAAQ,OAER,MAAM,EAAW,wCAAyC,GAE5D,KACA,KAAK,SACL,IAAK,SACL,IAAK,UACJ,EAAQ,EACT,KACA,SACC,MAAM,EAAW,wCAAyC,EAE5D,CACA,EAAW,OAAO,CAAC,GACnB,EAAW,KAAK,EACjB,CACD,IAGK,IAAI,MAAM,EAAQ,CACxB,IAAI,CAAM,CAAE,CAAI,CAAE,CAAQ,EACzB,OAAQ,GACP,KAAK,EAAQ,OAAO,CACnB,MAAO,CAAA,CAER,MAAK,EAAQ,MAAM,CAClB,OAAO,CAER,KAAK,WACJ,OAAO,WACN,MAAO,GAAG,CACX,CAEF,OACA,AAAI,AAAe,UAAf,OAAO,GACN,KAAQ,EACX,AAAI,AAAqB,YAArB,OAAO,CAAI,CAAC,EAAK,CACb,SAAS,GAAG,CAAI,EACtB,OAAO,CAAI,CAAC,EAAK,CAAC,KAAK,CAAC,EAAM,EAC/B,EAEM,CAAI,CAAC,EAAK,CAGf,KAAQ,GAAU,AAAQ,YAAR,EAGrB,AAAI,AAAuB,YAAvB,OAAO,CAAM,CAAC,EAAK,CACf,SAAS,GAAG,CAAI,EACtB,OAAO,CAAM,CAAC,EAAK,CAAC,KAAK,CAAC,EAAQ,EACnC,EAEM,CAAM,CAAC,EAAK,OAErB,EACA,IAAA,CAAI,EAAQ,IACJ,KAAQ,EAEhB,QAAA,AAAQ,GACA,QAAQ,OAAO,CAAC,GAExB,yBAAA,CAAyB,EAAQ,IACzB,OAAO,wBAAwB,CAAC,EAAK,EAE9C,EACD,CAwBO,SAAS,EAAQ,GAAG,CAAO,EAIjC,IAAI,EAAgB,CACnB,IAAK,AAAiB,aAAjB,OAAO,OAAwB,OAAO,QAAQ,CAAG,qBACtD,OAAQ,MACT,EACA,IAAK,IAAI,KAAU,EACd,AAAiB,UAAjB,OAAO,GACP,aAAkB,KAClB,aAAkB,gBAErB,EAAc,GAAG,CAAG,EAAI,EAAc,GAAG,CAAE,GACjC,GAAU,AAAiB,UAAjB,OAAO,GAC3B,OAAO,MAAM,CAAC,EAAe,AArChC,SAA0B,CAAG,CAAE,CAAO,EACrC,IAAI,EAAS,GAAW,CAAC,EAKzB,IAAI,IAAI,KAJJ,CAAC,EAAO,GAAG,EAAI,EAAQ,GAAG,EAC7B,CAAA,EAAO,GAAG,CAAG,EAAQ,GAAG,AAAH,EAGN,CAAC,SAAS,UAAU,OAAO,OAAO,cAAc,QAAQ,WACvE,WAAW,iBAAiB,YAAY,YAAY,SACpD,WAAW,MAAM,EACb,AAAoB,YAApB,OAAO,CAAG,CAAC,EAAK,CACnB,CAAG,CAAC,EAAK,CAAC,CAAM,CAAC,EAAK,CAAE,GACM,KAAA,IAAb,CAAG,CAAC,EAAK,GACtB,AAAQ,OAAR,EACH,EAAO,GAAG,CAAG,EAAI,EAAO,GAAG,CAAE,EAAI,GAAG,EAEpC,CAAM,CAAC,EAAK,CAAG,CAAG,CAAC,EAAK,EAI3B,OAAO,CACR,EAiBiD,EAAQ,IAGxD,IAAI,EAAO,EAAc,IAAI,EACzB,GACC,AAAe,UAAf,OAAO,GACL,aAAgB,QAChB,aAAgB,gBAChB,aAAgB,MAChB,aAAgB,aAChB,aAAgB,UAChB,aAAgB,UAChB,aAAgB,iBACjB,AAAmB,aAAnB,OAAO,YAA6B,aAAgB,YAExD,CAAA,EAAc,IAAI,CAAG,KAAK,SAAS,CAAC,EAVrC,EAaD,IAAI,EAAI,IAAI,QAAQ,EAAc,GAAG,CAAE,GAEvC,OADA,OAAO,MAAM,CAAC,GACP,IAAI,MAAM,EAAG,CACnB,IAAI,CAAM,CAAE,CAAI,CAAE,CAAQ,EACzB,OAAO,GACN,KAAK,EAAQ,MAAM,CAClB,OAAO,CAER,MAAK,EAAQ,OAAO,CACnB,MAAO,CAAA,CAER,KAAK,OACJ,OAAO,SAAS,GAAG,CAAO,EACzB,OAAO,EAAQ,KAAW,EAC3B,CAED,KAAK,WACL,IAAK,SAKL,IAAK,OACL,IAAK,OACL,IAAK,OANJ,OAAO,WACN,OAAO,CAAM,CAAC,EAAK,CAAC,KAAK,CAAC,EAC3B,CASD,KAAK,OAWJ,GAHK,GACJ,CAAA,EAAO,EAAO,IAAI,AAAJ,EAEX,EAAM,CACT,GAAI,CAAI,CAAC,EAAQ,OAAO,CAAC,CACxB,OAAO,EAER,OAAO,EAAU,EAAM,EACxB,CAEF,CACA,OAAO,CAAM,CAAC,EAAK,AACpB,CACD,EACD,CAEA,SAAS,EAAkB,CAAG,CAAE,CAAO,EAEtC,IAAI,EAAS,GAAW,CAAC,EAIzB,IAAI,IAAI,KAHJ,CAAC,EAAO,GAAG,EAAI,EAAQ,GAAG,EAC7B,CAAA,EAAO,GAAG,CAAG,EAAQ,GAAG,AAAH,EAEN,CAAC,SAAS,aAAa,UAAU,OAAO,MAAM,OAAO,aAAa,EAC7E,AAAoB,YAApB,OAAO,CAAG,CAAC,EAAK,CACnB,CAAG,CAAC,EAAK,CAAC,CAAM,CAAC,EAAK,CAAE,GACM,KAAA,IAAb,CAAG,CAAC,EAAK,GACtB,AAAQ,OAAR,EACH,EAAO,GAAG,CAAG,IAAI,IAAI,EAAI,GAAG,CAAE,EAAO,GAAG,EAAI,sBAE5C,CAAM,CAAC,EAAK,CAAG,CAAG,CAAC,EAAK,EAI3B,OAAO,CACR,CAEO,SAAS,EAAS,GAAG,CAAO,EAClC,IAAI,EAAiB,CAAC,EACtB,IAAK,IAAI,KAAU,EACd,AAAiB,UAAjB,OAAO,EACV,EAAe,IAAI,CAAG,EACZ,aAAkB,SAC5B,OAAO,MAAM,CAAC,EAAgB,EAAkB,EAAQ,IAC9C,GAAU,AAAiB,UAAjB,OAAO,IACvB,aAAkB,UAClB,aAAkB,MAClB,aAAkB,aAClB,aAAkB,UAClB,aAAkB,gBAClB,aAAkB,iBAClB,aAAkB,QACjB,AAAqB,aAArB,OAAO,YAA6B,aAAkB,WAE1D,EAAe,IAAI,CAAG,EAEtB,OAAO,MAAM,CAAC,EAAgB,EAAkB,EAAQ,KAI3D,IAAI,EAAI,IAAI,SAAS,EAAe,IAAI,CAAE,GAE1C,OADA,OAAO,MAAM,CAAC,GACP,IAAI,MAAM,EAAG,CACnB,IAAI,CAAM,CAAE,CAAI,CAAE,CAAQ,EACzB,OAAO,GACN,KAAK,EAAQ,OAAO,CACnB,MAAO,CAAA,CAER,MAAK,EAAQ,MAAM,CAClB,OAAO,CAER,KAAK,OACJ,OAAO,SAAS,GAAG,CAAO,EACzB,OAAO,EAAS,KAAW,EAC5B,CAED,KAAK,OACJ,IAAI,EAAe,IAAI,CAMtB,OAAO,EAAU,GAAG,GALpB,GAAI,EAAe,IAAI,CAAC,EAAQ,OAAO,CAAC,CACvC,OAAO,EAAe,IAAI,CAE3B,OAAO,EAAU,EAAe,IAAI,CAAE,EAKxC,KAAK,KACJ,OAAQ,EAAO,MAAM,EAAE,KAAS,EAAO,MAAM,CAAC,GAE/C,KAAK,UACJ,OAAO,EAAO,OAAO,AAEtB,SACC,GAAI,KAAQ,GAAkB,AAAQ,YAAR,EAC7B,OAAO,CAAc,CAAC,EAAK,CAE5B,GAAI,KAAQ,GAAU,AAAQ,YAAR,EAAoB,CAGzC,GAAI,AAAuB,YAAvB,OAAO,CAAM,CAAC,EAAK,CACtB,OAAO,SAAS,GAAG,CAAI,EACtB,OAAO,CAAM,CAAC,EAAK,CAAC,KAAK,CAAC,EAAQ,EACnC,EAED,OAAO,CAAM,CAAC,EAAK,AACpB,CAEF,CAED,CACD,EACD,CAEA,SAAS,EAAmB,CAAG,CAAE,CAAM,EAClC,AAAiB,YAAjB,OAAO,EACT,EAAO,EAAI,YAAY,CAAE,GAG1B,AADA,CAAA,EAAS,IAAI,gBAAgB,EAA7B,EACO,OAAO,CAAC,CAAC,EAAM,KACrB,EAAI,YAAY,CAAC,MAAM,CAAC,EAAK,EAC9B,EAEF,CAEO,SAAS,EAAI,GAAG,CAAO,EAC7B,IAAI,EAAc,CAAC,OAAO,OAAO,WAAW,OAC1C,WAAW,WAAW,OAAO,WAAW,WAAW,SAAS,eAAe,CACzE,EAAI,IAAI,IAAI,sBAChB,IAAK,IAAI,KAAU,EAClB,GAAI,AAAiB,UAAjB,OAAO,GAAsB,aAAkB,OAElD,EAAI,IAAI,IAAI,EAAQ,QACd,GAAI,aAAkB,KACxB,AAAmB,aAAnB,OAAO,UACP,aAAkB,SAEtB,EAAI,IAAI,IAAI,QACN,GAAI,aAAkB,gBAC5B,EAAmB,EAAG,QAChB,GAAI,GAAU,AAAiB,UAAjB,OAAO,EAC3B,IAAK,IAAI,KAAS,EACjB,GAAI,AAAO,UAAP,EACC,AAAwB,YAAxB,OAAO,EAAO,MAAM,CACvB,EAAO,MAAM,CAAC,EAAE,MAAM,CAAE,GAExB,EAAE,MAAM,CAAG,IAAI,gBAAgB,EAAO,MAAM,OAEvC,GAAI,AAAO,gBAAP,EACV,EAAmB,EAAG,EAAO,YAAY,MACnC,CACN,GAAI,CAAC,EAAY,QAAQ,CAAC,GACzB,MAAM,EAAW,oCAAoC,EAAS,0BAA2B,GAE1F,GAAI,AAAwB,YAAxB,OAAO,CAAM,CAAC,EAAM,CACvB,CAAM,CAAC,EAAM,CAAC,CAAC,CAAC,EAAM,CAAE,QAClB,GACN,AAAwB,UAAxB,OAAO,CAAM,CAAC,EAAM,EAAgB,CAAM,CAAC,EAAM,WAAY,QAC1D,AAAwB,UAAxB,OAAO,CAAM,CAAC,EAAM,EAAgB,CAAM,CAAC,EAAM,WAAY,QAC7D,AAAwB,WAAxB,OAAO,CAAM,CAAC,EAAM,EAAiB,CAAM,CAAC,EAAM,WAAY,QAEjE,CAAC,CAAC,EAAM,CAAG,GAAG,CAAM,CAAC,EAAM,MACrB,GAAI,AAAwB,UAAxB,OAAO,CAAM,CAAC,EAAM,EAAgB,CAAM,CAAC,EAAM,CAAC,QAAQ,CACpE,CAAC,CAAC,EAAM,CAAG,CAAM,CAAC,EAAM,CAAC,QAAQ,QAEjC,MAAM,EAAW,oCAAoC,EAAM,IAAI,EAAS,+BAAgC,CAAO,CAAC,EAAM,CAExH,MAGD,MAAM,EAAW,uCAAuC,EAAS,gCAAiC,GAIpG,OADA,OAAO,MAAM,CAAC,GACP,IAAI,MAAM,EAAG,CACnB,IAAI,CAAM,CAAE,CAAI,CAAE,CAAQ,EACzB,OAAO,GACN,KAAK,EAAQ,OAAO,CACnB,MAAO,CAAA,CAER,MAAK,EAAQ,MAAM,CAClB,OAAO,CAER,KAAK,OACJ,OAAO,SAAS,GAAG,CAAO,EACzB,OAAO,EAAI,KAAW,EACvB,CAED,KAAK,WACL,IAAK,SACJ,OAAO,WACN,OAAO,CAAM,CAAC,EAAK,EACpB,CAEF,CACA,OAAO,CAAM,CAAC,EAAK,AACpB,CACD,EACD,CAkDA,IAAM,EAAe,CACpB,MAAO,CAAC,EAAS,GAAG,KACnB,QAAQ,KAAK,CAAC,OAAO,KAAY,EAClC,EACA,KAAM,CAAC,EAAS,GAAG,KAClB,QAAQ,IAAI,CAAC,OAAO,KAAY,EACjC,EACA,MAAO,AAAC,IACP,QAAQ,KAAK,CAAC,OAAO,EACtB,EACA,SAAU,AAAC,IACV,QAAQ,QAAQ,CAAC,OAAO,EACzB,CACD,EAEO,SAAS,EAAW,CAAO,CAAE,GAAG,CAAO,EAE7C,OADA,EAAa,KAAK,CAAC,KAAY,GACxB,AAAI,MAAM,KAAY,EAC9B,CAGO,IAAM,EAAQ,CACpB,IAAI,CAAI,CAAE,CAAM,EACf,EAAO,OAAO,CAAC,EAAK,CAAG,CACxB,EACA,OAAO,CAAI,EACV,OAAO,EAAO,OAAO,CAAC,EAAK,AAC5B,EACA,QACC,EAAO,OAAO,CAAG,CAAC,CACnB,EACA,QACC,IAAI,EAAQ,EACZ,MAAO,CACN,QAAS,AAAC,IACT,IACA,EAAa,KAAK,CAAC,GACnB,EAAa,IAAI,CAAC,GAAK,IAAK,EAC7B,EACA,SAAU,AAAC,IACV,EAAa,IAAI,CAAC,GAAK,KAAO,EAAI,IAAI,CAAC,EAAQ,MAAM,CAAC,CAAE,KAAM,GAC9D,EAAa,QAAQ,CAAC,GACtB,GACD,CACD,CACD,CACD,C,G,I,E,E,S,E,C,E,E,E,S,I,G,E,E,U,I,G,E,E,Q,I,G,E,E,Q,I,G,E,E,W,I,G,E,E,Q,I,GEzmBA,IAAI,EAAU,CAAA,EAEP,SAAS,IACf,EAAU,CAAA,CACX,CAEO,SAAS,IACf,EAAU,CAAA,CACX,CAYO,SAAS,EAAM,CAAI,CAAE,CAAO,EAClC,IAAI,EAAW,EAAE,CACjB,GAAI,aAAmB,QACnB,GAAI,MAAM,OAAO,CAAC,GAAO,CAC3B,IAAI,EAAQ,EAAK,SAAS,CAAC,AAAA,GAAW,EAAM,EAAQ,IACvC,EAAM,IACT,EAAS,IAAI,CAAC,QAAQ,EAAM,2BAEpC,MAAY,EAAQ,IAAI,CAAC,IACrB,EAAS,IAAI,CAAC,+BAA+B,QAE3C,GAAI,aAAmB,SACtB,EAAQ,IACX,EAAS,IAAI,CAAC,qCAEZ,GAAI,GAAW,AAAkB,UAAlB,OAAO,GACzB,GAAI,MAAM,OAAO,CAAC,GAAO,CACrB,IAAI,EAAQ,EAAK,SAAS,CAAC,AAAA,GAAW,EAAM,EAAQ,IAChD,EAAM,IACT,EAAS,IAAI,CAAC,QAAQ,EAAM,2BAEjC,MAAO,GAAI,AAAC,GAAQ,AAAe,UAAf,OAAO,EAEpB,CACF,aAAgB,iBACnB,CAAA,EAAO,OAAO,WAAW,CAAC,EAD3B,EAGA,IAAI,EAAI,CAAQ,CAAC,EAAS,MAAM,CAAC,EAAE,CACnC,IAAK,GAAM,CAAC,EAAM,EAAK,GAAI,OAAO,OAAO,CAAC,GAAU,CAChD,IAAI,EAAS,EAAM,CAAI,CAAC,EAAK,CAAE,GAC3B,IACE,GAAK,AAAY,UAAZ,OAAO,IAChB,EAAI,CAAC,EACL,EAAS,IAAI,CAAC,IAEf,CAAC,CAAC,EAAK,CAAG,EAAO,QAAQ,CAE9B,CACJ,MAhBI,EAAS,IAAI,CAAC,0CAkBd,GAAS,GACZ,EAAS,IAAI,CAAC,uBAAuB,SAGvC,EAAI,EAAS,MAAM,EACX,CAGZ,CAEO,SAAS,EAAM,CAAM,CAAE,CAAI,EACjC,GAAI,CAAC,EACJ,OAED,IAAI,EAAS,EAAM,EAAO,GAC1B,GAAI,EACH,MAAM,IAAI,EAAY,EAAO,EAE/B,CAEO,SAAS,EAAS,CAAO,EAC/B,OAAO,SAAS,CAAI,SACnB,AAAU,MAAN,GAAc,AAAe,KAAA,IAAR,GAGlB,EAAM,EAAM,EACpB,CACD,CAEO,SAAS,EAAM,GAAG,CAAQ,EAChC,OAAO,SAAS,CAAI,EACnB,IAAI,IAAI,KAAW,EAClB,GAAI,CAAC,EAAM,EAAM,GAChB,MAAO,CAAA,EAGT,MAAO,CAAC,qCAAqC,AAC9C,CACD,CAEA,MAAM,EACL,YAAY,CAAQ,CAAE,GAAG,CAAO,CAAE,CACjC,IAAI,CAAC,QAAQ,CAAG,EAChB,IAAI,CAAC,OAAO,CAAG,EACf,QAAQ,KAAK,EACd,CAED,CCzGe,SAAA,EAAgB,CAAO,EAOrC,OANA,EAAU,OAAO,MAAM,CAAC,CACvB,QAAS,KACT,SAAU,KACV,MAAO,EACR,EAAG,GAEI,MAAO,EAAK,KACd,CAAC,OAAO,MAAM,QAAQ,QAAQ,CAAC,QAAQ,CAAC,EAAI,MAAM,EAOjD,AANJ,CAAA,EAAM,EAAI,IAAI,CAAC,CACd,QAAS,CACR,eAAe,mBACH,OAAS,kBACtB,CACD,EAAA,EACQ,IAAI,EAAI,AAAyC,UAAzC,OAAO,EAAI,IAAI,CAAC,EAAA,OAAA,CAAc,MAAM,CAAC,EACpD,CAAA,EAAM,EAAI,IAAI,CAAC,CACd,KAAM,KAAK,SAAS,CAAC,EAAI,IAAI,CAAC,EAAA,OAAA,CAAc,MAAM,CAAC,CAAE,EAAQ,QAAQ,CAAE,EAAQ,KAAK,CACrF,EAAA,EAGD,EAAM,EAAI,IAAI,CAAC,CACd,QAAS,CACF,OAAS,kBAChB,CACD,GAED,IAAI,EAAM,MAAM,EAAK,GAEjB,EAAO,KAAK,KAAK,CADV,MAAM,EAAI,IAAI,GACG,EAAQ,OAAO,EAC3C,OAAO,EAAI,IAAI,CAAC,CACf,KAAM,CACP,EACD,CACD,C,I,G,E,S,E,SF/BA,CAAA,OAAO,KAAK,CAAG,EACf,OAAO,MAAM,CAAG,EAChB,OAAO,KAAK,CAAC,EAAE,CAAG,CACjB,OAAA,EACA,OGLc,SAAkB,CAAO,EAkBvC,IAAM,EAAS,CACd,OAAQ,IAAI,IACZ,MAAQ,AAAwB,aAAxB,OAAO,aAA+B,aAAe,IAAI,IACjE,UAAW,CAAC,EACZ,UAAW,CAAC,EACZ,OAAQ,EAAA,MAAA,GAAe,IAAI,CAAC,AAAA,KAC5B,UAAW,GACX,cAAe,GACf,aAAc,GACd,WAAY,qBACZ,oBAAqB,CAAA,CACtB,EAEA,IAAK,IAAI,KAAU,EAAS,CAC3B,OAAO,GACN,IAAK,eACL,IAAK,qBACL,IAAK,gBACJ,EAAO,MAAM,CAAC,GAAG,CAAC,EAAQ,CAAO,CAAC,EAAO,EAC1C,KAEA,KAAK,SACL,IAAK,YACL,IAAK,gBACL,IAAK,aACL,IAAK,sBACL,IAAK,eACJ,CAAM,CAAC,EAAO,CAAG,CAAO,CAAC,EAAO,CACjC,KACA,KAAK,QACL,IAAK,SACJ,GAAI,AAA8B,YAA9B,OAAO,CAAO,CAAC,EAAO,CAAC,GAAG,EAC7B,AAA8B,YAA9B,OAAO,CAAO,CAAC,EAAO,CAAC,GAAG,EAC1B,AAA8B,YAA9B,OAAO,CAAO,CAAC,EAAO,CAAC,GAAG,CAC1B,CAAM,CAAC,EAAO,CAAG,CAAO,CAAC,EAAO,MAC1B,GAAI,AAAU,UAAV,GAAsB,AAAyB,UAAzB,OAAO,EAAQ,MAAM,CACrD,IAAK,IAAI,KAAS,EAAQ,MAAM,CAC/B,EAAO,MAAM,CAAC,GAAG,CAAC,EAAO,EAAQ,MAAM,CAAC,EAAM,OAG/C,MAAM,EAAA,UAAA,CAAiB,wCAAwC,GAEjE,KACA,KAAK,YACJ,IAAK,IAAI,KAAY,EAAQ,SAAS,CACrC,GAAI,AAAU,aAAV,GAAyB,AAAU,SAAV,EAC5B,MAAM,EAAA,UAAA,CAAiB,yDAAyD,GAGlF,OAAO,MAAM,CAAC,EAAO,SAAS,CAAE,EAAQ,SAAS,EAClD,KACA,KAAK,YACJ,IAAK,IAAI,KAAY,EAAQ,SAAS,CACrC,GAAI,AAAY,aAAZ,EACH,MAAM,EAAA,UAAA,CAAiB,8CAA8C,GAGvE,OAAO,MAAM,CAAC,EAAO,SAAS,CAAE,EAAQ,SAAS,EAClD,KACA,SACC,MAAM,EAAA,UAAA,CAAiB,2BAA2B,EAEpD,CACK,EAAO,YAAY,EACvB,CAAA,EAAO,YAAY,CAAG,AAAkB,aAAlB,OAAO,OAAyB,OAAO,QAAQ,EAAE,KAAO,EAD/E,EAGI,EAAO,YAAY,EACtB,CAAA,EAAO,YAAY,CAAG,EAAA,GAAA,CAAU,EAAO,YAAY,EAAE,IAAI,CAAC,sBAD3D,CAGD,CAEA,OAAO,eAAe,CAAG,CAAE,CAAI,EAC9B,GAAI,EAAO,mBAAmB,CAC7B,OAAO,EAAiB,EAAK,GAE9B,IAAI,EAAM,MAAM,EAAK,GACrB,GAAI,EAAI,EAAE,CACT,OAAO,EAER,OAAO,EAAI,MAAM,EAChB,KAAK,IACL,KAAK,IACJ,OAAO,EAAiB,EAAK,EAE/B,CACA,OAAO,CACR,EAEA,eAAe,EAAiB,CAAG,CAAE,CAAI,EAExC,GADA,AAkBD,WAEC,GAAI,AAAkB,aAAlB,OAAO,QAA0B,QAAQ,SAAU,CACtD,IACI,EAAM,EAAO,EADb,EAAM,EAAA,GAAA,CAAU,OAAO,QAAQ,EAEnC,GAAI,EAAI,YAAY,CAAC,GAAG,CAAC,QACxB,EAAS,EAAI,YAAY,CACzB,EAAM,EAAI,IAAI,CAAC,CAAE,OAAO,EAAG,GAC3B,QAAQ,SAAS,CAAC,CAAC,EAAE,GAAG,EAAI,IAAI,OAC1B,GAAI,EAAI,IAAI,CAAE,CACpB,IAAI,EAAQ,EAAI,IAAI,CAAC,MAAM,CAAC,GAC5B,EAAS,IAAI,gBAAgB,IAAI,GACjC,EAAM,EAAI,IAAI,CAAC,CAAE,KAAK,EAAG,GACzB,QAAQ,SAAS,CAAC,CAAC,EAAE,GAAG,EAAI,IAAI,CACjC,CACA,GAAI,EAAQ,CACX,EAAO,EAAO,GAAG,CAAC,QAClB,EAAQ,EAAO,GAAG,CAAC,SACnB,IAAI,EAAc,EAAO,KAAK,CAAC,GAAG,CAAC,eACnC,GAAI,CAAC,GAAS,IAAQ,EACrB,OAEG,GACH,EAAO,MAAM,CAAC,GAAG,CAAC,qBAAsB,EAE1C,CACD,CACD,IA5CK,CAAC,EAAO,MAAM,CAAC,GAAG,CAAC,gBAEtB,OADA,MAAM,EAAW,GACV,EAAiB,EAAK,GACvB,GAAI,AAqKZ,SAAmB,CAAG,EACrB,GAAI,EAAI,MAAM,EAAI,EAAI,MAAM,CAAC,MAAM,EAAI,EAAI,MAAM,CAAC,MAAM,CAAC,GAAG,CAAC,gBAAiB,CAC7E,IAAI,EAAM,IAAI,KACV,EAAQ,EAAI,MAAM,CAAC,MAAM,CAAC,GAAG,CAAC,gBAClC,OAAO,EAAI,OAAO,GAAK,EAAM,OAAO,CAAC,OAAO,EAC7C,CACA,MAAO,CAAA,CACR,EA5KsB,GAEpB,OADA,MAAM,EAAa,GACZ,EAAiB,EAAK,EACvB,EACN,IAAI,EAAc,EAAO,MAAM,CAAC,GAAG,CAAC,gBAMpC,OAAO,EALP,EAAM,EAAA,OAAA,CAAc,EAAK,CACxB,QAAS,CACR,cAAe,EAAY,IAAI,CAAC,IAAI,EAAY,KAAK,AACtD,CACD,GAED,CACD,CA+BA,eAAe,EAAW,CAAG,EAC5B,GAAI,AAAsB,uBAAtB,EAAO,UAAU,EAA6B,CAAC,EAAO,MAAM,CAAC,GAAG,CAAC,sBAAuB,CAC3F,IAAI,EAAa,AAgDnB,WACC,GAAI,CAAC,EAAO,SAAS,CAAC,SAAS,CAC9B,MAAM,EAAA,UAAA,CAAiB,qDAExB,IAAI,EAAM,EAAA,GAAA,CAAU,EAAO,SAAS,CAAC,SAAS,CAAE,CAAC,KAAM,EAAE,GAMzD,OALA,EAAa,EAAQ,CACpB,UAAW,KACX,aAAc,KACd,MAAO,IACR,GACO,EAAA,GAAA,CAAU,EAAK,CACrB,OAAQ,CACP,cAAe,OACf,UAAe,EAAO,SAAS,CAC/B,aAAe,EAAO,YAAY,CAClC,MAAe,EAAO,KAAK,CAC3B,MAAe,AAKlB,SAAqB,CAAM,EAC1B,IAAM,EAAa,iEACf,EAAc,GACd,EAAU,EACX,KAAO,EATmB,IAUtB,GAAe,EAAW,MAAM,CAAC,KAAK,KAAK,CAAC,KAAK,MAAM,GAAK,EAAW,MAAM,GAC7E,IAGP,OADA,EAAO,KAAK,CAAC,GAAG,CAAC,GACV,CACR,EAf8B,EAC5B,CACD,EACD,IAlEE,GAAI,CAAC,EAAO,SAAS,CAAC,SAAS,EAAI,AAAsC,YAAtC,OAAO,EAAO,SAAS,CAAC,SAAS,CACnE,MAAM,EAAA,UAAA,CAAiB,iIAExB,IAAI,EAAQ,MAAM,EAAO,SAAS,CAAC,SAAS,CAAC,GACzC,GACH,EAAO,MAAM,CAAC,GAAG,CAAC,qBAAsB,EAE1C,CACA,IAAI,EAAW,IACX,EAAW,MAAM,EAAO,MAAM,CAAC,GAAG,CAAC,GACvC,GAAI,CAAC,EAAS,EAAE,CACf,MAAM,EAAA,UAAA,CAAiB,EAAS,MAAM,CAAC,IAAI,EAAS,UAAU,CAAE,MAAM,EAAS,IAAI,IAEpF,IAAI,EAAO,MAAM,EAAS,IAAI,GAU9B,OATA,EAAO,MAAM,CAAC,GAAG,CAAC,eAAgB,CACjC,MAAO,EAAK,YAAY,CACxB,QAAS,EAAW,EAAK,UAAU,EACnC,KAAM,EAAK,UAAU,CACrB,MAAO,EAAK,KAAK,AAClB,GACI,EAAK,aAAa,EACrB,EAAO,MAAM,CAAC,GAAG,CAAC,gBAAiB,EAAK,aAAa,EAE/C,CACR,CAEA,eAAe,EAAa,CAAG,CAAE,CAAI,EAEpC,IAAI,EAAkB,EAAsB,iBACxC,EAAW,MAAM,EAAO,MAAM,CAAC,GAAG,CAAC,GACvC,GAAI,CAAC,EAAS,EAAE,CACf,MAAM,EAAA,UAAA,CAAiB,IAAI,MAAM,CAAC,IAAI,IAAI,UAAU,CAAE,MAAM,IAAI,IAAI,IAErE,IAAI,EAAO,MAAM,EAAS,IAAI,GAU9B,OATA,EAAO,MAAM,CAAC,GAAG,CAAC,eAAgB,CACjC,MAAS,EAAK,YAAY,CAC1B,QAAS,EAAW,EAAK,UAAU,EACnC,KAAS,EAAK,UAAU,CACxB,MAAS,EAAK,KAAK,AACpB,GACI,EAAK,aAAa,EACrB,EAAO,MAAM,CAAC,GAAG,CAAC,gBAAiB,EAAK,aAAa,EAE/C,CACR,CAoCA,SAAS,EAAsB,EAAW,IAAI,EAM7C,GALA,EAAa,EAAQ,CACpB,UAAW,KACX,cAAe,KACf,aAAc,IACf,GACI,CAAC,EAAO,SAAS,CAAC,KAAK,CAC1B,MAAM,EAAA,UAAA,CAAiB,iDAExB,IAAI,EAAM,EAAA,GAAA,CAAU,EAAO,SAAS,CAAC,KAAK,CAAE,CAAC,KAAM,EAAE,GACjD,EAAS,CACZ,WAAe,GAAc,EAAO,UAAU,CAC9C,UAAe,EAAO,SAAS,CAC/B,cAAe,EAAO,aAAa,AACpC,EAIA,OAHI,EAAO,KAAK,EACf,CAAA,EAAO,KAAK,CAAG,EAAO,KAAK,AAAL,EAEhB,EAAO,UAAU,EACvB,IAAK,qBACJ,EAAO,YAAY,CAAG,EAAO,YAAY,CACzC,EAAO,IAAI,CAAG,EAAO,MAAM,CAAC,GAAG,CAAC,sBAChC,EAAO,aAAa,CAAG,QACxB,KACA,KAAK,qBAGL,IAAK,gBAFJ,MAAM,AAAI,MAAM,sBAKlB,CACA,OAAO,EAAA,OAAA,CAAc,EAAK,CACzB,OAAQ,MACR,IAAK,CACJ,aAAc,CACf,CACD,EACD,CAWA,SAAS,EAAW,CAAQ,EAC3B,GAAI,aAAoB,KACvB,OAAO,IAAI,KAAK,EAAS,OAAO,IAEjC,GAAI,AAAoB,UAApB,OAAO,EAAuB,CACjC,IAAI,EAAO,IAAI,KAEf,OADA,EAAK,UAAU,CAAC,EAAK,UAAU,GAAK,GAC7B,CACR,CACA,MAAM,AAAI,UAAU,wBAAwB,EAC7C,CAGD,CHpSA","sources":["","src/metro.mjs","src/everything.mjs","src/assert.mjs","src/mw/json.mjs","src/mw/oauth2.mjs"],"sourcesContent":["\nfunction $parcel$export(e, n, v, s) {\n Object.defineProperty(e, n, {get: v, set: s, enumerable: true, configurable: true});\n}\n\n var $parcel$global = globalThis;\n \nvar $parcel$modules = {};\nvar $parcel$inits = {};\n\nvar parcelRequire = $parcel$global[\"parcelRequireea2c\"];\n\nif (parcelRequire == null) {\n parcelRequire = function(id) {\n if (id in $parcel$modules) {\n return $parcel$modules[id].exports;\n }\n if (id in $parcel$inits) {\n var init = $parcel$inits[id];\n delete $parcel$inits[id];\n var module = {id: id, exports: {}};\n $parcel$modules[id] = module;\n init.call(module.exports, module, module.exports);\n return module.exports;\n }\n var err = new Error(\"Cannot find module '\" + id + \"'\");\n err.code = 'MODULE_NOT_FOUND';\n throw err;\n };\n\n parcelRequire.register = function register(id, init) {\n $parcel$inits[id] = init;\n };\n\n $parcel$global[\"parcelRequireea2c\"] = parcelRequire;\n}\n\nvar parcelRegister = parcelRequire.register;\nparcelRegister(\"hkeot\", function(module, exports) {\n\n$parcel$export(module.exports, \"symbols\", () => $86c8ab3a59b0bae1$export$47616e9f7f5fe113);\n$parcel$export(module.exports, \"request\", () => $86c8ab3a59b0bae1$export$b5fe3f66a567bec0);\n$parcel$export(module.exports, \"metroError\", () => $86c8ab3a59b0bae1$export$7079e2c78c274c66);\n$parcel$export(module.exports, \"response\", () => $86c8ab3a59b0bae1$export$785bb8ef7fad1f74);\n$parcel$export(module.exports, \"client\", () => $86c8ab3a59b0bae1$export$388e0302ca0d9a41);\n$parcel$export(module.exports, \"url\", () => $86c8ab3a59b0bae1$export$128fa18b7194ef);\n$parcel$export(module.exports, \"formdata\", () => $86c8ab3a59b0bae1$export$5de500aade6bf050);\n$parcel$export(module.exports, \"trace\", () => $86c8ab3a59b0bae1$export$357889f174732d38);\nconst $86c8ab3a59b0bae1$var$metroURL = \"https://metro.muze.nl/details/\";\nconst $86c8ab3a59b0bae1$export$47616e9f7f5fe113 = {\n isProxy: Symbol(\"isProxy\"),\n source: Symbol(\"source\")\n};\nclass $86c8ab3a59b0bae1$var$Client {\n #options = {\n url: typeof window != \"undefined\" ? window.location : \"https://localhost\"\n };\n #verbs = [\n \"get\",\n \"post\",\n \"put\",\n \"delete\",\n \"patch\",\n \"head\",\n \"options\",\n \"query\"\n ];\n static tracers = {};\n constructor(...options){\n for (let option of options){\n if (typeof option == \"string\" || option instanceof String) this.#options.url = \"\" + option;\n else if (option instanceof $86c8ab3a59b0bae1$var$Client) Object.assign(this.#options, option.#options);\n else if (option instanceof Function) this.#addMiddlewares([\n option\n ]);\n else if (option && typeof option == \"object\") for(let param in option){\n if (param == \"middlewares\") this.#addMiddlewares(option[param]);\n else if (typeof option[param] == \"function\") this.#options[param] = option[param](this.#options[param], this.#options);\n else this.#options[param] = option[param];\n }\n }\n if (this.#options.verbs) {\n this.#verbs = this.#options.verbs;\n delete this.#options.verbs;\n }\n for (const verb of this.#verbs)this[verb] = async function(...options) {\n return this.#fetch($86c8ab3a59b0bae1$export$b5fe3f66a567bec0(this.#options, ...options, {\n method: verb.toUpperCase()\n }));\n };\n Object.freeze(this);\n }\n #addMiddlewares(middlewares) {\n if (typeof middlewares == \"function\") middlewares = [\n middlewares\n ];\n let index = middlewares.findIndex((m)=>typeof m != \"function\");\n if (index >= 0) throw $86c8ab3a59b0bae1$export$7079e2c78c274c66(\"metro.client: middlewares must be a function or an array of functions \" + $86c8ab3a59b0bae1$var$metroURL + \"client/invalid-middlewares-value/\", middlewares[index]);\n if (!Array.isArray(this.#options.middlewares)) this.#options.middlewares = [];\n this.#options.middlewares = this.#options.middlewares.concat(middlewares);\n }\n #fetch(req) {\n if (!req.url) throw $86c8ab3a59b0bae1$export$7079e2c78c274c66(\"metro.client.\" + r.method.toLowerCase() + \": Missing url parameter \" + $86c8ab3a59b0bae1$var$metroURL + \"client/missing-url-param/\", req);\n let metrofetch = async (req)=>{\n if (req[$86c8ab3a59b0bae1$export$47616e9f7f5fe113.isProxy]) // even though a Proxy is supposed to be 'invisible'\n // fetch() doesn't work with the proxy (in Firefox), \n // you need the actual Request object here\n req = req[$86c8ab3a59b0bae1$export$47616e9f7f5fe113.source];\n return $86c8ab3a59b0bae1$export$785bb8ef7fad1f74(await fetch(req));\n };\n let middlewares = [\n metrofetch\n ].concat(this.#options?.middlewares?.slice() || []);\n let options = this.#options;\n //@TODO: do this once in constructor?\n let next;\n for (let middleware of middlewares)next = function(next, middleware) {\n return async function(req) {\n let res;\n let tracers = Object.values($86c8ab3a59b0bae1$var$Client.tracers);\n for (let tracer of tracers)if (tracer.request) tracer.request.call(tracer, req);\n res = await middleware(req, next);\n for (let tracer of tracers)if (tracer.response) tracer.response.call(tracer, res);\n return res;\n };\n }(next, middleware);\n return next(req);\n }\n with(...options) {\n return new $86c8ab3a59b0bae1$var$Client(this, ...options);\n }\n}\nfunction $86c8ab3a59b0bae1$export$388e0302ca0d9a41(...options) {\n return new $86c8ab3a59b0bae1$var$Client(...options);\n}\nfunction $86c8ab3a59b0bae1$var$appendHeaders(r1, headers) {\n if (!Array.isArray(headers)) headers = [\n headers\n ];\n headers.forEach((header)=>{\n if (typeof header == \"function\") {\n let result = header(r1.headers, r1);\n if (result) {\n if (!Array.isArray(result)) result = [\n result\n ];\n headers = headers.concat(result);\n }\n }\n });\n headers.forEach((header)=>{\n Object.entries(header).forEach(([name, value])=>{\n r1.headers.append(name, value);\n });\n });\n}\nfunction $86c8ab3a59b0bae1$var$bodyProxy(body, r1) {\n let source = r1.body;\n if (!source) {\n //Firefox does not allow access to Request.body (undefined)\n //Chrome and Nodejs do, so mimic the correct (documented)\n //result here\n if (body === null) source = new ReadableStream();\n else if (body instanceof ReadableStream) source = body;\n else if (body instanceof Blob) source = body.stream();\n else source = new ReadableStream({\n start (controller) {\n let chunk;\n switch(typeof body){\n case \"object\":\n if (typeof body.toString == \"function\") // also catches URLSearchParams\n chunk = body.toString();\n else if (body instanceof FormData) chunk = new URLSearchParams(body).toString();\n else if (body instanceof ArrayBuffer || ArrayBuffer.isView(body)) // catchs TypedArrays - e.g. Uint16Array\n chunk = body;\n else throw $86c8ab3a59b0bae1$export$7079e2c78c274c66(\"Cannot convert body to ReadableStream\", body);\n break;\n case \"string\":\n case \"number\":\n case \"boolean\":\n chunk = body;\n break;\n default:\n throw $86c8ab3a59b0bae1$export$7079e2c78c274c66(\"Cannot convert body to ReadableStream\", body);\n }\n controller.enqueue(chunk);\n controller.close();\n }\n });\n }\n return new Proxy(source, {\n get (target, prop, receiver) {\n switch(prop){\n case $86c8ab3a59b0bae1$export$47616e9f7f5fe113.isProxy:\n return true;\n case $86c8ab3a59b0bae1$export$47616e9f7f5fe113.source:\n return body;\n case \"toString\":\n return function() {\n return \"\" + body;\n };\n }\n if (typeof body == \"object\") {\n if (prop in body) {\n if (typeof body[prop] == \"function\") return function(...args) {\n return body[prop].apply(body, args);\n };\n return body[prop];\n }\n }\n if (prop in target && prop != \"toString\") {\n // skipped toString, since it has no usable output\n // and body may have its own toString\n if (typeof target[prop] == \"function\") return function(...args) {\n return target[prop].apply(target, args);\n };\n return target[prop];\n }\n },\n has (target, prop) {\n return prop in body;\n },\n ownKeys (target) {\n return Reflect.ownKeys(body);\n },\n getOwnPropertyDescriptor (target, prop) {\n return Object.getOwnPropertyDescriptor(body, prop);\n }\n });\n}\nfunction $86c8ab3a59b0bae1$var$getRequestParams(req, current) {\n let params = current || {};\n if (!params.url && current.url) params.url = current.url;\n // function to fetch all relevant properties of a Request\n for (let prop of [\n \"method\",\n \"headers\",\n \"body\",\n \"mode\",\n \"credentials\",\n \"cache\",\n \"redirect\",\n \"referrer\",\n \"referrerPolicy\",\n \"integrity\",\n \"keepalive\",\n \"signal\",\n \"priority\",\n \"url\"\n ]){\n if (typeof req[prop] == \"function\") req[prop](params[prop], params);\n else if (typeof req[prop] != \"undefined\") {\n if (prop == \"url\") params.url = $86c8ab3a59b0bae1$export$128fa18b7194ef(params.url, req.url);\n else params[prop] = req[prop];\n }\n }\n return params;\n}\nfunction $86c8ab3a59b0bae1$export$b5fe3f66a567bec0(...options) {\n // the standard Request constructor is a minefield\n // so first gather all the options together into a single\n // javascript object, then set it in one go\n let requestParams = {\n url: typeof window != \"undefined\" ? window.location : \"https://localhost/\",\n duplex: \"half\" // required when setting body to ReadableStream, just set it here by default already\n };\n for (let option of options){\n if (typeof option == \"string\" || option instanceof URL || option instanceof URLSearchParams) requestParams.url = $86c8ab3a59b0bae1$export$128fa18b7194ef(requestParams.url, option);\n else if (option && typeof option == \"object\") Object.assign(requestParams, $86c8ab3a59b0bae1$var$getRequestParams(option, requestParams));\n }\n let body = requestParams.body;\n if (body) {\n if (typeof body == \"object\" && !(body instanceof String) && !(body instanceof ReadableStream) && !(body instanceof Blob) && !(body instanceof ArrayBuffer) && !(body instanceof DataView) && !(body instanceof FormData) && !(body instanceof URLSearchParams) && (typeof TypedArray == \"undefined\" || !(body instanceof TypedArray))) requestParams.body = JSON.stringify(body);\n }\n let r1 = new Request(requestParams.url, requestParams);\n Object.freeze(r1);\n return new Proxy(r1, {\n get (target, prop, receiver) {\n switch(prop){\n case $86c8ab3a59b0bae1$export$47616e9f7f5fe113.source:\n return target;\n case $86c8ab3a59b0bae1$export$47616e9f7f5fe113.isProxy:\n return true;\n case \"with\":\n return function(...options) {\n return $86c8ab3a59b0bae1$export$b5fe3f66a567bec0(target, ...options);\n };\n case \"toString\":\n case \"toJSON\":\n return function() {\n return target[prop].apply(target);\n };\n case \"blob\":\n case \"text\":\n case \"json\":\n return function() {\n return target[prop].apply(target);\n };\n case \"body\":\n // Request.body is always a ReadableStream\n // which is a horrible API, if you want to\n // allow middleware to alter the body\n // so we keep the original body, wrap a Proxy\n // around it to keep the ReadableStream api\n // accessible, but allow access to the original\n // body value as well\n if (!body) body = target.body;\n if (body) {\n if (body[$86c8ab3a59b0bae1$export$47616e9f7f5fe113.isProxy]) return body;\n return $86c8ab3a59b0bae1$var$bodyProxy(body, target);\n }\n break;\n }\n return target[prop];\n }\n });\n}\nfunction $86c8ab3a59b0bae1$var$getResponseParams(res, current) {\n // function to fetch all relevant properties of a Response\n let params = current || {};\n if (!params.url && current.url) params.url = current.url;\n for (let prop of [\n \"status\",\n \"statusText\",\n \"headers\",\n \"body\",\n \"url\",\n \"type\",\n \"redirected\"\n ]){\n if (typeof res[prop] == \"function\") res[prop](params[prop], params);\n else if (typeof res[prop] != \"undefined\") {\n if (prop == \"url\") params.url = new URL(res.url, params.url || \"https://localhost/\");\n else params[prop] = res[prop];\n }\n }\n return params;\n}\nfunction $86c8ab3a59b0bae1$export$785bb8ef7fad1f74(...options) {\n let responseParams = {};\n for (let option of options){\n if (typeof option == \"string\") responseParams.body = option;\n else if (option instanceof Response) Object.assign(responseParams, $86c8ab3a59b0bae1$var$getResponseParams(option, responseParams));\n else if (option && typeof option == \"object\") {\n if (option instanceof FormData || option instanceof Blob || option instanceof ArrayBuffer || option instanceof DataView || option instanceof ReadableStream || option instanceof URLSearchParams || option instanceof String || typeof TypedArray != \"undefined\" && option instanceof TypedArray) responseParams.body = option;\n else Object.assign(responseParams, $86c8ab3a59b0bae1$var$getResponseParams(option, responseParams));\n }\n }\n let r1 = new Response(responseParams.body, responseParams);\n Object.freeze(r1);\n return new Proxy(r1, {\n get (target, prop, receiver) {\n switch(prop){\n case $86c8ab3a59b0bae1$export$47616e9f7f5fe113.isProxy:\n return true;\n case $86c8ab3a59b0bae1$export$47616e9f7f5fe113.source:\n return target;\n case \"with\":\n return function(...options) {\n return $86c8ab3a59b0bae1$export$785bb8ef7fad1f74(target, ...options);\n };\n case \"body\":\n if (responseParams.body) {\n if (responseParams.body[$86c8ab3a59b0bae1$export$47616e9f7f5fe113.isProxy]) return responseParams.body;\n return $86c8ab3a59b0bae1$var$bodyProxy(responseParams.body, target);\n } else return $86c8ab3a59b0bae1$var$bodyProxy(\"\", target);\n break;\n case \"ok\":\n return target.status >= 200 && target.status < 400;\n case \"headers\":\n return target.headers;\n default:\n if (prop in responseParams && prop != \"toString\") return responseParams[prop];\n if (prop in target && prop != \"toString\") {\n // skipped toString, since it has no usable output\n // and body may have its own toString\n if (typeof target[prop] == \"function\") return function(...args) {\n return target[prop].apply(target, args);\n };\n return target[prop];\n }\n break;\n }\n return undefined;\n }\n });\n}\nfunction $86c8ab3a59b0bae1$var$appendSearchParams(url, params) {\n if (typeof params == \"function\") params(url.searchParams, url);\n else {\n params = new URLSearchParams(params);\n params.forEach((value, key)=>{\n url.searchParams.append(key, value);\n });\n }\n}\nfunction $86c8ab3a59b0bae1$export$128fa18b7194ef(...options) {\n let validParams = [\n \"hash\",\n \"host\",\n \"hostname\",\n \"href\",\n \"password\",\n \"pathname\",\n \"port\",\n \"protocol\",\n \"username\",\n \"search\",\n \"searchParams\"\n ];\n let u = new URL(\"https://localhost/\");\n for (let option of options){\n if (typeof option == \"string\" || option instanceof String) // option is a relative or absolute url\n u = new URL(option, u);\n else if (option instanceof URL || typeof Location != \"undefined\" && option instanceof Location) u = new URL(option);\n else if (option instanceof URLSearchParams) $86c8ab3a59b0bae1$var$appendSearchParams(u, option);\n else if (option && typeof option == \"object\") for(let param in option){\n if (param == \"search\") {\n if (typeof option.search == \"function\") option.search(u.search, u);\n else u.search = new URLSearchParams(option.search);\n } else if (param == \"searchParams\") $86c8ab3a59b0bae1$var$appendSearchParams(u, option.searchParams);\n else {\n if (!validParams.includes(param)) throw $86c8ab3a59b0bae1$export$7079e2c78c274c66(\"metro.url: unknown url parameter \" + $86c8ab3a59b0bae1$var$metroURL + \"url/unknown-param-name/\", param);\n if (typeof option[param] == \"function\") option[param](u[param], u);\n else if (typeof option[param] == \"string\" || option[param] instanceof String || typeof option[param] == \"number\" || option[param] instanceof Number || typeof option[param] == \"boolean\" || option[param] instanceof Boolean) u[param] = \"\" + option[param];\n else if (typeof option[param] == \"object\" && option[param].toString) u[param] = option[param].toString();\n else throw $86c8ab3a59b0bae1$export$7079e2c78c274c66(\"metro.url: unsupported value for \" + param + \" \" + $86c8ab3a59b0bae1$var$metroURL + \"url/unsupported-param-value/\", options[param]);\n }\n }\n else throw $86c8ab3a59b0bae1$export$7079e2c78c274c66(\"metro.url: unsupported option value \" + $86c8ab3a59b0bae1$var$metroURL + \"url/unsupported-option-value/\", option);\n }\n Object.freeze(u);\n return new Proxy(u, {\n get (target, prop, receiver) {\n switch(prop){\n case $86c8ab3a59b0bae1$export$47616e9f7f5fe113.isProxy:\n return true;\n case $86c8ab3a59b0bae1$export$47616e9f7f5fe113.source:\n return target;\n case \"with\":\n return function(...options) {\n return $86c8ab3a59b0bae1$export$128fa18b7194ef(target, ...options);\n };\n case \"toString\":\n case \"toJSON\":\n return function() {\n return target[prop]();\n };\n }\n return target[prop];\n }\n });\n}\nfunction $86c8ab3a59b0bae1$export$5de500aade6bf050(...options) {\n var params = new FormData();\n for (let option of options){\n if (option instanceof FormData) for (let entry of option.entries())params.append(entry[0], entry[1]);\n else if (option && typeof option == \"object\") for (let entry of Object.entries(option)){\n if (Array.isArray(entry[1])) for (let value of entry[1])params.append(entry[0], value);\n else params.append(entry[0], entry[1]);\n }\n else throw new $86c8ab3a59b0bae1$export$7079e2c78c274c66(\"metro.formdata: unknown option type, only FormData or Object supported\", option);\n }\n Object.freeze(params);\n return new Proxy(params, {\n get: (target, prop, receiver)=>{\n switch(prop){\n case $86c8ab3a59b0bae1$export$47616e9f7f5fe113.isProxy:\n return true;\n case $86c8ab3a59b0bae1$export$47616e9f7f5fe113.source:\n return target;\n case \"with\":\n return function(...options) {\n return $86c8ab3a59b0bae1$export$5de500aade6bf050(target, ...options);\n };\n case \"toString\":\n case \"toJSON\":\n return function() {\n return target[prop]();\n };\n }\n return target[prop];\n }\n });\n}\nconst $86c8ab3a59b0bae1$var$metroConsole = {\n error: (message, ...details)=>{\n console.error(\"\\u24C2\\uFE0F \", message, ...details);\n },\n info: (message, ...details)=>{\n console.info(\"\\u24C2\\uFE0F \", message, ...details);\n },\n group: (name)=>{\n console.group(\"\\u24C2\\uFE0F \" + name);\n },\n groupEnd: (name)=>{\n console.groupEnd(\"\\u24C2\\uFE0F \" + name);\n }\n};\nfunction $86c8ab3a59b0bae1$export$7079e2c78c274c66(message, ...details) {\n $86c8ab3a59b0bae1$var$metroConsole.error(message, ...details);\n return new Error(message, ...details);\n}\nconst $86c8ab3a59b0bae1$export$357889f174732d38 = {\n add (name, tracer) {\n $86c8ab3a59b0bae1$var$Client.tracers[name] = tracer;\n },\n delete (name) {\n delete $86c8ab3a59b0bae1$var$Client.tracers[name];\n },\n clear () {\n $86c8ab3a59b0bae1$var$Client.tracers = {};\n },\n group () {\n let group = 0;\n return {\n request: (req)=>{\n group++;\n $86c8ab3a59b0bae1$var$metroConsole.group(group);\n $86c8ab3a59b0bae1$var$metroConsole.info(req?.url, req);\n },\n response: (res)=>{\n $86c8ab3a59b0bae1$var$metroConsole.info(res?.body ? res.body[$86c8ab3a59b0bae1$export$47616e9f7f5fe113.source] : null, res);\n $86c8ab3a59b0bae1$var$metroConsole.groupEnd(group);\n group--;\n }\n };\n }\n};\n\n});\n\n\nvar $hkeot = parcelRequire(\"hkeot\");\nvar $2ddd80d1adc2ea42$exports = {};\n\n$parcel$export($2ddd80d1adc2ea42$exports, \"enable\", () => $2ddd80d1adc2ea42$export$d7c4a0dd6a4567e5);\n$parcel$export($2ddd80d1adc2ea42$exports, \"disable\", () => $2ddd80d1adc2ea42$export$e20fbacbb41798b);\n$parcel$export($2ddd80d1adc2ea42$exports, \"fails\", () => $2ddd80d1adc2ea42$export$478159de811fd37d);\n$parcel$export($2ddd80d1adc2ea42$exports, \"check\", () => $2ddd80d1adc2ea42$export$35dc45686fc2dbd7);\n$parcel$export($2ddd80d1adc2ea42$exports, \"optional\", () => $2ddd80d1adc2ea42$export$516e28dec6a4b6d4);\n$parcel$export($2ddd80d1adc2ea42$exports, \"oneOf\", () => $2ddd80d1adc2ea42$export$a9a18ae5ba42aeab);\nlet $2ddd80d1adc2ea42$var$enabled = false;\nfunction $2ddd80d1adc2ea42$export$d7c4a0dd6a4567e5() {\n $2ddd80d1adc2ea42$var$enabled = true;\n}\nfunction $2ddd80d1adc2ea42$export$e20fbacbb41798b() {\n $2ddd80d1adc2ea42$var$enabled = false;\n}\nfunction $2ddd80d1adc2ea42$export$478159de811fd37d(data, pattern) {\n let problems = [];\n if (pattern instanceof RegExp) {\n if (Array.isArray(data)) {\n let index = data.findIndex((element)=>$2ddd80d1adc2ea42$export$478159de811fd37d(element, pattern));\n if (index > -1) problems.push(\"data[\" + index + \"] does not match pattern\");\n } else if (!pattern.test(data)) problems.push(\"data does not match pattern \" + pattern);\n } else if (pattern instanceof Function) {\n if (pattern(data)) problems.push(\"data does not match function\");\n } else if (pattern && typeof pattern == \"object\") {\n if (Array.isArray(data)) {\n let index = data.findIndex((element)=>$2ddd80d1adc2ea42$export$478159de811fd37d(element, pattern));\n if (index > -1) problems.push(\"data[\" + index + \"] does not match pattern\");\n } else if (!data || typeof data != \"object\") problems.push(\"data is not an object, pattern is\");\n else {\n if (data instanceof URLSearchParams) data = Object.fromEntries(data);\n let p = problems[problems.length - 1];\n for (const [wKey, wVal] of Object.entries(pattern)){\n let result = $2ddd80d1adc2ea42$export$478159de811fd37d(data[wKey], wVal);\n if (result) {\n if (!p || typeof p == \"string\") {\n p = {};\n problems.push(p);\n }\n p[wKey] = result.problems;\n }\n }\n }\n } else if (pattern != data) problems.push(\"data does not equal \" + pattern);\n if (problems.length) return problems;\n return false;\n}\nfunction $2ddd80d1adc2ea42$export$35dc45686fc2dbd7(source, test) {\n if (!$2ddd80d1adc2ea42$var$enabled) return;\n let result = $2ddd80d1adc2ea42$export$478159de811fd37d(source, test);\n if (result) throw new $2ddd80d1adc2ea42$var$assertError(result, source);\n}\nfunction $2ddd80d1adc2ea42$export$516e28dec6a4b6d4(pattern) {\n return function(data) {\n if (data == null || typeof data == \"undefined\") return false;\n return $2ddd80d1adc2ea42$export$478159de811fd37d(data, pattern);\n };\n}\nfunction $2ddd80d1adc2ea42$export$a9a18ae5ba42aeab(...patterns) {\n return function(data) {\n for (let pattern of patterns){\n if (!$2ddd80d1adc2ea42$export$478159de811fd37d(data, pattern)) return false;\n }\n return [\n \"data does not match oneOf patterns\"\n ];\n };\n}\nclass $2ddd80d1adc2ea42$var$assertError {\n constructor(problems, ...details){\n this.problems = problems;\n this.details = details;\n console.trace();\n }\n}\n\n\n\nvar $hkeot = parcelRequire(\"hkeot\");\nfunction $9cea4e31d030ec91$export$2e2bcd8739ae039(options) {\n options = Object.assign({\n reviver: null,\n replacer: null,\n space: \"\"\n }, options);\n return async (req, next)=>{\n if ([\n \"POST\",\n \"PUT\",\n \"PATCH\",\n \"QUERY\"\n ].includes(req.method)) {\n req = req.with({\n headers: {\n \"Content-Type\": \"application/json\",\n \"Accept\": \"application/json\"\n }\n });\n if (req.body && typeof req.body[$hkeot.symbols.source] == \"object\") req = req.with({\n body: JSON.stringify(req.body[$hkeot.symbols.source], options.replacer, options.space)\n });\n } else req = req.with({\n headers: {\n \"Accept\": \"application/json\"\n }\n });\n let res = await next(req);\n let body = await res.text();\n let json = JSON.parse(body, options.reviver);\n return res.with({\n body: json\n });\n };\n}\n\n\n\nvar $hkeot = parcelRequire(\"hkeot\");\n\n\nfunction $94580a8710b2e8f9$export$2e2bcd8739ae039(options) {\n let localState;\n if (typeof localStorage !== \"undefined\") localState = {\n get: ()=>localStorage.getItem(\"metro/state\"),\n has: ()=>localStorage.getItem(\"metro/state\"),\n set: (value)=>localStorage.setItem(\"metro/state\", value)\n };\n else {\n let stateMap = new Map();\n localState = {\n get: ()=>stateMap.getItem(\"metro/state\"),\n has: ()=>stateMap.getItem(\"metro/state\"),\n set: (value)=>stateMap.setItem(\"metro/state\", value)\n };\n }\n const oauth2 = {\n tokens: new Map(),\n state: typeof localStorage !== \"undefined\" ? localStorage : new Map(),\n endpoints: {},\n callbacks: {},\n client: $hkeot.client().with((0, $9cea4e31d030ec91$export$2e2bcd8739ae039)()),\n client_id: \"\",\n client_secret: \"\",\n redirect_uri: \"\",\n grant_type: \"authorization_code\",\n force_authorization: false\n };\n for(let option in options){\n switch(option){\n case \"access_token\":\n case \"authorization_code\":\n case \"refresh_token\":\n oauth2.tokens.set(option, options[option]);\n break;\n case \"client\":\n case \"client_id\":\n case \"client_secret\":\n case \"grant_type\":\n case \"force_authorization\":\n case \"redirect_uri\":\n oauth2[option] = options[option];\n break;\n case \"state\":\n case \"tokens\":\n if (typeof options[option].set == \"function\" && typeof options[option].get == \"function\" && typeof options[option].has == \"function\") oauth2[option] = options[option];\n else if (option == \"tokens\" && typeof options.tokens == \"object\") for(let token in options.tokens)oauth2.tokens.set(token, options.tokens[token]);\n else throw $hkeot.metroError(\"metro/mw/oauth2: incorrect value for \" + option);\n break;\n case \"endpoints\":\n for(let endpoint in options.endpoints){\n if (endpoint != \"authorize\" && endpoint != \"token\") throw $hkeot.metroError('Unknown endpoint, choose one of \"authorize\" or \"token\"', endpoint);\n }\n Object.assign(oauth2.endpoints, options.endpoints);\n break;\n case \"callbacks\":\n for(let callback in options.callbacks){\n if (callback != \"authorize\") throw $hkeot.metroError('Unknown callback, choose one of \"authorize\"', callback);\n }\n Object.assign(oauth2.callbacks, options.callbacks);\n break;\n default:\n throw $hkeot.metroError(\"Unknown oauth2mw option \", option);\n }\n if (!oauth2.redirect_uri) oauth2.redirect_uri = typeof window !== \"undefined\" ? window.location?.href : \"\";\n if (oauth2.redirect_uri) oauth2.redirect_uri = $hkeot.url(oauth2.redirect_uri).with(\"?metroRedirect=true\");\n }\n return async function(req, next) {\n if (oauth2.force_authorization) return oauth2authorized(req, next);\n let res1 = await next(req);\n if (res1.ok) return res1;\n switch(res1.status){\n case 400:\n case 401:\n return oauth2authorized(req, next);\n }\n return res1;\n };\n async function oauth2authorized(req, next) {\n getTokensFromLocation();\n if (!oauth2.tokens.has(\"access_token\")) {\n await fetchToken(req);\n return oauth2authorized(req, next);\n } else if (isExpired(req)) {\n await refreshToken(req);\n return oauth2authorized(req, next);\n } else {\n let accessToken = oauth2.tokens.get(\"access_token\");\n req = $hkeot.request(req, {\n headers: {\n Authorization: accessToken.type + \" \" + accessToken.value\n }\n });\n return next(req);\n }\n }\n function getTokensFromLocation() {\n // check if window.location is available and contains tokens\n if (typeof window !== \"undefined\" && window?.location) {\n let url = $hkeot.url(window.location);\n let code, state, params;\n if (url.searchParams.has(\"code\")) {\n params = url.searchParams;\n url = url.with({\n search: \"\"\n });\n history.pushState({}, \"\", url.href);\n } else if (url.hash) {\n let query = url.hash.substr(1);\n params = new URLSearchParams(\"?\" + query);\n url = url.with({\n hash: \"\"\n });\n history.pushState({}, \"\", url.href);\n }\n if (params) {\n code = params.get(\"code\");\n state = params.get(\"state\");\n let storedState = oauth2.state.get(\"metro/state\");\n if (!state || state !== storedState) return;\n if (code) oauth2.tokens.set(\"authorization_code\", code);\n }\n }\n }\n async function fetchToken(req) {\n if (oauth2.grant_type === \"authorization_code\" && !oauth2.tokens.has(\"authorization_code\")) {\n let authReqURL = getAuthTokenURL();\n if (!oauth2.callbacks.authorize || typeof oauth2.callbacks.authorize !== \"function\") throw $hkeot.metroError(\"oauth2mw: oauth2 with grant_type:authorization_code requires a callback function in client options.oauth2.callbacks.authorize\");\n let token = await oauth2.callbacks.authorize(authReqURL);\n if (token) oauth2.tokens.set(\"authorization_code\", token);\n }\n let tokenReq = getAccessTokenRequest();\n let response = await oauth2.client.get(tokenReq);\n if (!response.ok) throw $hkeot.metroError(response.status + \":\" + response.statusText, await response.text());\n let data = await response.json();\n oauth2.tokens.set(\"access_token\", {\n value: data.access_token,\n expires: getExpires(data.expires_in),\n type: data.token_type,\n scope: data.scope\n });\n if (data.refresh_token) oauth2.tokens.set(\"refresh_token\", data.refresh_token);\n return data;\n }\n async function refreshToken(req, next) {\n let refreshTokenReq = getAccessTokenRequest(\"refresh_token\");\n let response = await oauth2.client.get(refreshTokenReq);\n if (!response.ok) throw $hkeot.metroError(res.status + \":\" + res.statusText, await res.text());\n let data = await response.json();\n oauth2.tokens.set(\"access_token\", {\n value: data.access_token,\n expires: getExpires(data.expires_in),\n type: data.token_type,\n scope: data.scope\n });\n if (data.refresh_token) oauth2.tokens.set(\"refresh_token\", data.refresh_token);\n return data;\n }\n function getAuthTokenURL() {\n if (!oauth2.endpoints.authorize) throw $hkeot.metroError(\"oauth2mw: Missing options.endpoints.authorize url\");\n let url = $hkeot.url(oauth2.endpoints.authorize, {\n hash: \"\"\n });\n $2ddd80d1adc2ea42$export$35dc45686fc2dbd7(oauth2, {\n client_id: /.+/,\n redirect_uri: /.+/,\n scope: /.*/\n });\n return $hkeot.url(url, {\n search: {\n response_type: \"code\",\n client_id: oauth2.client_id,\n redirect_uri: oauth2.redirect_uri,\n scope: oauth2.scope,\n state: createState(40)\n }\n });\n }\n function createState(length) {\n const validChars = \"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789\";\n let randomState = \"\";\n let counter = 0;\n while(counter < length){\n randomState += validChars.charAt(Math.floor(Math.random() * validChars.length));\n counter++;\n }\n oauth2.state.set(randomState);\n return randomState;\n }\n function getAccessTokenRequest(grant_type = null) {\n $2ddd80d1adc2ea42$export$35dc45686fc2dbd7(oauth2, {\n client_id: /.+/,\n client_secret: /.+/,\n redirect_uri: /.+/\n });\n if (!oauth2.endpoints.token) throw $hkeot.metroError(\"oauth2mw: Missing options.endpoints.token url\");\n let url = $hkeot.url(oauth2.endpoints.token, {\n hash: \"\"\n });\n let params = {\n grant_type: grant_type || oauth2.grant_type,\n client_id: oauth2.client_id,\n client_secret: oauth2.client_secret\n };\n if (oauth2.scope) params.scope = oauth2.scope;\n switch(oauth2.grant_type){\n case \"authorization_code\":\n params.redirect_uri = oauth2.redirect_uri;\n params.code = oauth2.tokens.get(\"authorization_code\");\n params.response_type = \"token\" // spec #3.1.1\n ;\n break;\n case \"client_credentials\":\n throw new Error(\"Not yet implemented\") // @TODO:\n ;\n case \"refresh_token\":\n throw new Error(\"Not yet implemented\") // @TODO:\n ;\n }\n return $hkeot.request(url, {\n method: \"GET\",\n url: {\n searchParams: params\n }\n });\n }\n function isExpired(req) {\n if (req.oauth2 && req.oauth2.tokens && req.oauth2.tokens.has(\"access_token\")) {\n let now = new Date();\n let token = req.oauth2.tokens.get(\"access_token\");\n return now.getTime() > token.expires.getTime();\n }\n return false;\n }\n function getExpires(duration) {\n if (duration instanceof Date) return new Date(duration.getTime()); // return a copy\n if (typeof duration === \"number\") {\n let date = new Date();\n date.setSeconds(date.getSeconds() + duration);\n return date;\n }\n throw new TypeError(\"Unknown expires type \" + duration);\n }\n}\n\n\nwindow.metro = $hkeot;\nwindow.assert = $2ddd80d1adc2ea42$exports;\nwindow.metro.mw = {\n jsonmw: $9cea4e31d030ec91$export$2e2bcd8739ae039,\n oauth2: $94580a8710b2e8f9$export$2e2bcd8739ae039\n};\n\n\n//# sourceMappingURL=everything.js.map\n","const metroURL = 'https://metro.muze.nl/details/'\n\nexport const symbols = {\n\tisProxy: Symbol('isProxy'),\n\tsource: Symbol('source')\n}\n\nclass Client {\n\t#options = {\n\t\turl: typeof window != 'undefined' ? window.location : 'https://localhost'\n\t}\n\t#verbs = ['get','post','put','delete','patch','head','options','query']\n\n\tstatic tracers = {}\n\n\tconstructor(...options) {\n\t\tfor (let option of options) {\n\t\t\tif (typeof option == 'string' || option instanceof String) {\n\t\t\t\tthis.#options.url = ''+option\n\t\t\t} else if (option instanceof Client) {\n\t\t\t\tObject.assign(this.#options, option.#options)\n\t\t\t} else if (option instanceof Function) {\n\t\t\t\tthis.#addMiddlewares([option])\n\t\t\t} else if (option && typeof option == 'object') {\n\t\t\t\tfor (let param in option) {\n\t\t\t\t\tif (param == 'middlewares') {\n\t\t\t\t\t\tthis.#addMiddlewares(option[param])\n\t\t\t\t\t} else if (typeof option[param] == 'function') {\n\t\t\t\t\t\tthis.#options[param] = option[param](this.#options[param], this.#options)\n\t\t\t\t\t} else {\n\t\t\t\t\t\tthis.#options[param] = option[param]\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tif (this.#options.verbs) {\n\t\t\tthis.#verbs = this.#options.verbs\n\t\t\tdelete this.#options.verbs\n\t\t}\n\n\t\tfor (const verb of this.#verbs) {\n\t\t\tthis[verb] = async function(...options) {\n\t\t\t\treturn this.#fetch(request(\n\t\t\t\t\tthis.#options,\n\t\t\t\t\t...options,\n\t\t\t\t\t{method: verb.toUpperCase()}\n\t\t\t\t))\n\t\t\t}\n\t\t}\n\t\tObject.freeze(this)\n\t}\n\n\t#addMiddlewares(middlewares) {\n\t\tif (typeof middlewares == 'function') {\n\t\t\tmiddlewares = [ middlewares ]\n\t\t}\n\t\tlet index = middlewares.findIndex(m => typeof m != 'function')\n\t\tif (index>=0) {\n\t\t\tthrow metroError('metro.client: middlewares must be a function or an array of functions '\n\t\t\t\t+metroURL+'client/invalid-middlewares-value/', middlewares[index])\n\t\t}\n\t\tif (!Array.isArray(this.#options.middlewares)) {\n\t\t\tthis.#options.middlewares = []\n\t\t}\n\t\tthis.#options.middlewares = this.#options.middlewares.concat(middlewares)\n\t}\n\n\t#fetch(req) {\n\t\tif (!req.url) {\n\t\t\tthrow metroError('metro.client.'+r.method.toLowerCase()+': Missing url parameter '+metroURL+'client/missing-url-param/', req)\n\t\t}\n\t\tlet metrofetch = async (req) => {\n\t\t\tif (req[symbols.isProxy]) {\n\t\t\t\t// even though a Proxy is supposed to be 'invisible'\n\t\t\t\t// fetch() doesn't work with the proxy (in Firefox), \n\t\t\t\t// you need the actual Request object here\n\t\t\t\treq = req[symbols.source]\n\t\t\t}\n\t\t\treturn response(await fetch(req))\n\t\t}\n\t\tlet middlewares = [metrofetch].concat(this.#options?.middlewares?.slice() || [])\n\t\tlet options = this.#options\n\t\t//@TODO: do this once in constructor?\n\t\tlet next\n\t\tfor (let middleware of middlewares) {\n\t\t\tnext = (function(next, middleware) {\n\t\t\t\treturn async function(req) {\n\t\t\t\t\tlet res\n\t\t\t\t\tlet tracers = Object.values(Client.tracers)\n\t\t\t\t\tfor(let tracer of tracers) {\n\t\t\t\t\t\tif (tracer.request) {\n\t\t\t\t\t\t\ttracer.request.call(tracer, req)\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tres = await middleware(req, next)\n\t\t\t\t\tfor(let tracer of tracers) {\n\t\t\t\t\t\tif (tracer.response) {\n\t\t\t\t\t\t\ttracer.response.call(tracer, res)\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\treturn res\n\t\t\t\t}\t\t\t\t\t\t\t\t\n\t\t\t})(next, middleware)\n\t\t}\n\t\treturn next(req)\n\t}\n\n\twith(...options) {\n\t\treturn new Client(this, ...options)\n\t}\n}\n\nexport function client(...options) {\n\treturn new Client(...options)\n}\n\nfunction appendHeaders(r, headers) {\n\tif (!Array.isArray(headers)) {\n\t\theaders = [headers]\n\t}\n\theaders.forEach((header) => {\n\t\tif (typeof header == 'function') {\n\t\t\tlet result = header(r.headers, r)\n\t\t\tif (result) {\n\t\t\t\tif (!Array.isArray(result)) {\n\t\t\t\t\tresult = [result]\n\t\t\t\t}\n\t\t\t\theaders = headers.concat(result)\n\t\t\t}\n\t\t}\n\t})\n\theaders.forEach((header) => {\n\t\tObject.entries(header).forEach(([name,value]) => {\t\t\t\n\t\t\tr.headers.append(name, value)\n\t\t})\n\t})\n}\n\nfunction bodyProxy(body, r) {\n\tlet source = r.body\n\tif (!source) {\n\t\t//Firefox does not allow access to Request.body (undefined)\n\t\t//Chrome and Nodejs do, so mimic the correct (documented)\n\t\t//result here\n\t\tif (body === null) {\n\t\t\tsource = new ReadableStream()\n\t\t} else if (body instanceof ReadableStream) {\n\t\t\tsource = body\n\t\t} else if (body instanceof Blob) {\n\t\t\tsource = body.stream()\n\t\t} else {\n\t\t\tsource = new ReadableStream({\n\t\t\t\tstart(controller) {\n\t\t\t\t\tlet chunk\n\t\t\t\t\tswitch(typeof body) {\n\t\t\t\t\t\tcase 'object':\n\t\t\t\t\t\t\tif (typeof body.toString == 'function') {\n\t\t\t\t\t\t\t\t// also catches URLSearchParams\n\t\t\t\t\t\t\t\tchunk = body.toString()\n\t\t\t\t\t\t\t} else if (body instanceof FormData) {\n\t\t\t\t\t\t\t\tchunk = new URLSearchParams(body).toString()\n\t\t\t\t\t\t\t} else if (body instanceof ArrayBuffer\n\t\t\t\t\t\t\t\t|| ArrayBuffer.isView(body)\n\t\t\t\t\t\t\t) {\n\t\t\t\t\t\t\t\t// catchs TypedArrays - e.g. Uint16Array\n\t\t\t\t\t\t\t\tchunk = body\n\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\tthrow metroError('Cannot convert body to ReadableStream', body)\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\tbreak\n\t\t\t\t\t\tcase 'string':\n\t\t\t\t\t\tcase 'number':\n\t\t\t\t\t\tcase 'boolean':\n\t\t\t\t\t\t\tchunk = body\n\t\t\t\t\t\tbreak\n\t\t\t\t\t\tdefault:\n\t\t\t\t\t\t\tthrow metroError('Cannot convert body to ReadableStream', body)\n\t\t\t\t\t\tbreak\n\t\t\t\t\t}\n\t\t\t\t\tcontroller.enqueue(chunk)\n\t\t\t\t\tcontroller.close()\n\t\t\t\t}\n\t\t\t})\n\t\t}\n\t}\n\treturn new Proxy(source, {\n\t\tget(target, prop, receiver) {\n\t\t\tswitch (prop) {\n\t\t\t\tcase symbols.isProxy:\n\t\t\t\t\treturn true\n\t\t\t\tbreak\n\t\t\t\tcase symbols.source:\n\t\t\t\t\treturn body\n\t\t\t\tbreak\n\t\t\t\tcase 'toString':\n\t\t\t\t\treturn function() {\n\t\t\t\t\t\treturn ''+body\n\t\t\t\t\t}\n\t\t\t\tbreak\n\t\t\t}\n\t\t\tif (typeof body == 'object') {\n\t\t\t\tif (prop in body) {\n\t\t\t\t\tif (typeof body[prop] == 'function') {\n\t\t\t\t\t\treturn function(...args) {\n\t\t\t\t\t\t\treturn body[prop].apply(body, args)\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\treturn body[prop]\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (prop in target && prop != 'toString') {\n\t\t\t\t// skipped toString, since it has no usable output\n\t\t\t\t// and body may have its own toString\n\t\t\t\tif (typeof target[prop] == 'function') {\n\t\t\t\t\treturn function(...args) {\n\t\t\t\t\t\treturn target[prop].apply(target, args)\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\treturn target[prop]\n\t\t\t}\n\t\t},\n\t\thas(target, prop) {\n\t\t\treturn prop in body\n\t\t},\n\t\townKeys(target) {\n\t\t\treturn Reflect.ownKeys(body)\n\t\t},\n\t\tgetOwnPropertyDescriptor(target, prop) {\n\t\t\treturn Object.getOwnPropertyDescriptor(body,prop)\n\t\t}\n\t})\n}\n\nfunction getRequestParams(req, current) {\n\tlet params = current || {}\n\tif (!params.url && current.url) {\n\t\tparams.url = current.url\n\t}\n\t// function to fetch all relevant properties of a Request\n\tfor(let prop of ['method','headers','body','mode','credentials','cache','redirect',\n\t\t'referrer','referrerPolicy','integrity','keepalive','signal',\n\t\t'priority','url']) {\n\t\tif (typeof req[prop] == 'function') {\n\t\t\treq[prop](params[prop], params)\n\t\t} else if (typeof req[prop] != 'undefined') {\n\t\t\tif (prop == 'url') {\n\t\t\t\tparams.url = url(params.url, req.url)\n\t\t\t} else {\n\t\t\t\tparams[prop] = req[prop]\n\t\t\t}\n\t\t}\n\t}\n\treturn params\n}\n\nexport function request(...options) {\n\t// the standard Request constructor is a minefield\n\t// so first gather all the options together into a single\n\t// javascript object, then set it in one go\n\tlet requestParams = {\n\t\turl: typeof window != 'undefined' ? window.location : 'https://localhost/',\n\t\tduplex: 'half' // required when setting body to ReadableStream, just set it here by default already\n\t}\n\tfor (let option of options) {\n\t\tif (typeof option == 'string'\n\t\t\t|| option instanceof URL\n\t\t\t|| option instanceof URLSearchParams\n\t\t) {\n\t\t\trequestParams.url = url(requestParams.url, option)\n\t\t} else if (option && typeof option == 'object') {\n\t\t\tObject.assign(requestParams, getRequestParams(option, requestParams))\n\t\t}\n\t}\n\tlet body = requestParams.body\n\tif (body) {\n\t\tif (typeof body == 'object'\n\t\t\t&& !(body instanceof String)\n\t\t\t&& !(body instanceof ReadableStream)\n\t\t\t&& !(body instanceof Blob)\n\t\t\t&& !(body instanceof ArrayBuffer)\n\t\t\t&& !(body instanceof DataView)\n\t\t\t&& !(body instanceof FormData)\n\t\t\t&& !(body instanceof URLSearchParams)\n\t\t\t&& (typeof TypedArray=='undefined' || !(body instanceof TypedArray))\n\t\t) {\n\t\t\trequestParams.body = JSON.stringify(body)\n\t\t}\n\t}\n\tlet r = new Request(requestParams.url, requestParams)\n\tObject.freeze(r)\n\treturn new Proxy(r, {\n\t\tget(target, prop, receiver) {\n\t\t\tswitch(prop) {\n\t\t\t\tcase symbols.source:\n\t\t\t\t\treturn target\n\t\t\t\tbreak\n\t\t\t\tcase symbols.isProxy:\n\t\t\t\t\treturn true\n\t\t\t\tbreak\n\t\t\t\tcase 'with':\n\t\t\t\t\treturn function(...options) {\n\t\t\t\t\t\treturn request(target, ...options)\n\t\t\t\t\t}\n\t\t\t\tbreak\n\t\t\t\tcase 'toString':\n\t\t\t\tcase 'toJSON':\n\t\t\t\t\treturn function() {\n\t\t\t\t\t\treturn target[prop].apply(target)\n\t\t\t\t\t}\n\t\t\t\tbreak\n\t\t\t\tcase 'blob':\n\t\t\t\tcase 'text':\n\t\t\t\tcase 'json':\n\t\t\t\t\treturn function() {\n\t\t\t\t\t\treturn target[prop].apply(target)\n\t\t\t\t\t}\n\t\t\t\tbreak\n\t\t\t\tcase 'body':\n\t\t\t\t\t// Request.body is always a ReadableStream\n\t\t\t\t\t// which is a horrible API, if you want to\n\t\t\t\t\t// allow middleware to alter the body\n\t\t\t\t\t// so we keep the original body, wrap a Proxy\n\t\t\t\t\t// around it to keep the ReadableStream api\n\t\t\t\t\t// accessible, but allow access to the original\n\t\t\t\t\t// body value as well\n\t\t\t\t\tif (!body) {\n\t\t\t\t\t\tbody = target.body\n\t\t\t\t\t}\n\t\t\t\t\tif (body) {\n\t\t\t\t\t\tif (body[symbols.isProxy]) {\n\t\t\t\t\t\t\treturn body\n\t\t\t\t\t\t}\n\t\t\t\t\t\treturn bodyProxy(body, target)\n\t\t\t\t\t}\n\t\t\t\tbreak\n\t\t\t}\n\t\t\treturn target[prop]\n\t\t}\n\t})\n}\n\nfunction getResponseParams(res, current) {\n\t// function to fetch all relevant properties of a Response\n\tlet params = current || {}\n\tif (!params.url && current.url) {\n\t\tparams.url = current.url\n\t}\n\tfor(let prop of ['status','statusText','headers','body','url','type','redirected']) {\n\t\tif (typeof res[prop] == 'function') {\n\t\t\tres[prop](params[prop], params)\n\t\t} else if (typeof res[prop] != 'undefined') {\n\t\t\tif (prop == 'url') {\n\t\t\t\tparams.url = new URL(res.url, params.url || 'https://localhost/')\n\t\t\t} else {\n\t\t\t\tparams[prop] = res[prop]\n\t\t\t}\n\t\t}\n\t}\n\treturn params\n}\n\nexport function response(...options) {\n\tlet responseParams = {}\n\tfor (let option of options) {\n\t\tif (typeof option == 'string') {\n\t\t\tresponseParams.body = option\n\t\t} else if (option instanceof Response) {\n\t\t\tObject.assign(responseParams, getResponseParams(option, responseParams))\n\t\t} else if (option && typeof option == 'object') {\n\t\t\tif (option instanceof FormData\n\t\t\t\t|| option instanceof Blob\n\t\t\t\t|| option instanceof ArrayBuffer\n\t\t\t\t|| option instanceof DataView\n\t\t\t\t|| option instanceof ReadableStream\n\t\t\t\t|| option instanceof URLSearchParams\n\t\t\t\t|| option instanceof String\n\t\t\t\t|| (typeof TypedArray != 'undefined' && option instanceof TypedArray)\n\t\t\t) {\n\t\t\t\tresponseParams.body = option\n\t\t\t} else {\n\t\t\t\tObject.assign(responseParams, getResponseParams(option, responseParams))\n\t\t\t}\n\t\t}\n\t}\n\tlet r = new Response(responseParams.body, responseParams)\t\n\tObject.freeze(r)\n\treturn new Proxy(r, {\n\t\tget(target, prop, receiver) {\n\t\t\tswitch(prop) {\n\t\t\t\tcase symbols.isProxy:\n\t\t\t\t\treturn true\n\t\t\t\tbreak\n\t\t\t\tcase symbols.source:\n\t\t\t\t\treturn target\n\t\t\t\tbreak\n\t\t\t\tcase 'with':\n\t\t\t\t\treturn function(...options) {\n\t\t\t\t\t\treturn response(target, ...options)\n\t\t\t\t\t}\n\t\t\t\tbreak\n\t\t\t\tcase 'body':\n\t\t\t\t\tif (responseParams.body) {\n\t\t\t\t\t\tif (responseParams.body[symbols.isProxy]) {\n\t\t\t\t\t\t\treturn responseParams.body\n\t\t\t\t\t\t}\n\t\t\t\t\t\treturn bodyProxy(responseParams.body, target)\n\t\t\t\t\t} else {\n\t\t\t\t\t\treturn bodyProxy('',target)\n\t\t\t\t\t}\n\t\t\t\tbreak\n\t\t\t\tcase 'ok':\n\t\t\t\t\treturn (target.status>=200) && (target.status<400)\n\t\t\t\tbreak\n\t\t\t\tcase 'headers':\n\t\t\t\t\treturn target.headers\n\t\t\t\tbreak\n\t\t\t\tdefault:\n\t\t\t\t\tif (prop in responseParams && prop != 'toString') {\n\t\t\t\t\t\treturn responseParams[prop]\n\t\t\t\t\t}\n\t\t\t\t\tif (prop in target && prop != 'toString') {\n\t\t\t\t\t\t// skipped toString, since it has no usable output\n\t\t\t\t\t\t// and body may have its own toString\n\t\t\t\t\t\tif (typeof target[prop] == 'function') {\n\t\t\t\t\t\t\treturn function(...args) {\n\t\t\t\t\t\t\t\treturn target[prop].apply(target, args)\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\treturn target[prop]\n\t\t\t\t\t}\n\t\t\t\tbreak\n\t\t\t}\n\t\t\treturn undefined\n\t\t}\n\t})\n}\n\nfunction appendSearchParams(url, params) {\n\tif (typeof params == 'function') {\n\t\t params(url.searchParams, url)\n\t} else {\n\t\tparams = new URLSearchParams(params)\n\t\tparams.forEach((value,key) => {\n\t\t\turl.searchParams.append(key, value)\n\t\t})\n\t}\n}\n\nexport function url(...options) {\n\tlet validParams = ['hash','host','hostname','href',\n\t\t\t'password','pathname','port','protocol','username','search','searchParams']\n\tlet u = new URL('https://localhost/')\n\tfor (let option of options) {\n\t\tif (typeof option == 'string' || option instanceof String) {\n\t\t\t// option is a relative or absolute url\n\t\t\tu = new URL(option, u)\n\t\t} else if (option instanceof URL \n\t\t\t|| (typeof Location != 'undefined' \n\t\t\t\t&& option instanceof Location)\n\t\t) {\n\t\t\tu = new URL(option)\n\t\t} else if (option instanceof URLSearchParams) {\n\t\t\tappendSearchParams(u, option)\n\t\t} else if (option && typeof option == 'object') {\n\t\t\tfor (let param in option) {\n\t\t\t\tif (param=='search') {\n\t\t\t\t\tif (typeof option.search == 'function') {\n\t\t\t\t\t\toption.search(u.search, u)\n\t\t\t\t\t} else {\n\t\t\t\t\t\tu.search = new URLSearchParams(option.search)\n\t\t\t\t\t}\n\t\t\t\t} else if (param=='searchParams') {\n\t\t\t\t\tappendSearchParams(u, option.searchParams)\n\t\t\t\t} else {\n\t\t\t\t\tif (!validParams.includes(param)) {\n\t\t\t\t\t\tthrow metroError('metro.url: unknown url parameter '+metroURL+'url/unknown-param-name/', param)\n\t\t\t\t\t}\n\t\t\t\t\tif (typeof option[param] == 'function') {\n\t\t\t\t\t\toption[param](u[param], u)\n\t\t\t\t\t} else if (\n\t\t\t\t\t\ttypeof option[param] == 'string' || option[param] instanceof String \n\t\t\t\t\t\t|| typeof option[param] == 'number' || option[param] instanceof Number\n\t\t\t\t\t\t|| typeof option[param] == 'boolean' || option[param] instanceof Boolean\n\t\t\t\t\t) {\n\t\t\t\t\t\tu[param] = ''+option[param]\n\t\t\t\t\t} else if (typeof option[param] == 'object' && option[param].toString) {\n\t\t\t\t\t\tu[param] = option[param].toString()\n\t\t\t\t\t} else {\n\t\t\t\t\t\tthrow metroError('metro.url: unsupported value for '+param+' '+metroURL+'url/unsupported-param-value/', options[param])\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t} else {\n\t\t\tthrow metroError('metro.url: unsupported option value '+metroURL+'url/unsupported-option-value/', option)\n\t\t}\n\t}\n\tObject.freeze(u)\n\treturn new Proxy(u, {\n\t\tget(target, prop, receiver) {\n\t\t\tswitch(prop) {\n\t\t\t\tcase symbols.isProxy:\n\t\t\t\t\treturn true\n\t\t\t\tbreak\n\t\t\t\tcase symbols.source:\n\t\t\t\t\treturn target\n\t\t\t\tbreak\n\t\t\t\tcase 'with':\n\t\t\t\t\treturn function(...options) {\n\t\t\t\t\t\treturn url(target, ...options)\n\t\t\t\t\t}\n\t\t\t\tbreak\n\t\t\t\tcase 'toString':\n\t\t\t\tcase 'toJSON':\n\t\t\t\t\treturn function() {\n\t\t\t\t\t\treturn target[prop]()\n\t\t\t\t\t}\n\t\t\t\tbreak\n\t\t\t}\n\t\t\treturn target[prop]\n\t\t}\n\t})\n}\n\nexport function formdata(...options) {\n\tvar params = new FormData()\n\tfor (let option of options) {\n\t\tif (option instanceof FormData) {\n\t\t\tfor (let entry of option.entries()) {\n\t\t\t\tparams.append(entry[0],entry[1])\n\t\t\t}\n\t\t} else if (option && typeof option == 'object') {\n\t\t\tfor (let entry of Object.entries(option)) {\n\t\t\t\tif (Array.isArray(entry[1])) {\n\t\t\t\t\tfor (let value of entry[1]) {\n\t\t\t\t\t\tparams.append(entry[0], value)\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\tparams.append(entry[0],entry[1])\n\t\t\t\t}\n\t\t\t}\n\t\t} else {\n\t\t\tthrow new metroError('metro.formdata: unknown option type, only FormData or Object supported',option)\n\t\t}\n\t}\n\tObject.freeze(params)\n\treturn new Proxy(params, {\n\t\tget: (target,prop,receiver) => {\n\t\t\tswitch(prop) {\n\t\t\t\tcase symbols.isProxy:\n\t\t\t\t\treturn true\n\t\t\t\tbreak\n\t\t\t\tcase symbols.source:\n\t\t\t\t\treturn target\n\t\t\t\tbreak\n\t\t\t\tcase 'with':\n\t\t\t\t\treturn function(...options) {\n\t\t\t\t\t\treturn formdata(target, ...options)\n\t\t\t\t\t}\n\t\t\t\tbreak\n\t\t\t\tcase 'toString':\n\t\t\t\tcase 'toJSON':\n\t\t\t\t\treturn function() {\n\t\t\t\t\t\treturn target[prop]()\n\t\t\t\t\t}\n\t\t\t\tbreak\n\t\t\t}\n\t\t\treturn target[prop]\n\t\t}\n\t})\n}\n\nconst metroConsole = {\n\terror: (message, ...details) => {\n\t\tconsole.error('Ⓜ️ ',message, ...details)\n\t},\n\tinfo: (message, ...details) => {\n\t\tconsole.info('Ⓜ️ ',message, ...details)\n\t},\n\tgroup: (name) => {\n\t\tconsole.group('Ⓜ️ '+name)\n\t},\n\tgroupEnd: (name) => {\n\t\tconsole.groupEnd('Ⓜ️ '+name)\n\t}\n}\n\nexport function metroError(message, ...details) {\n\tmetroConsole.error(message, ...details)\n\treturn new Error(message, ...details)\n}\n\n\nexport const trace = {\n\tadd(name, tracer) {\n\t\tClient.tracers[name] = tracer\n\t},\n\tdelete(name) {\n\t\tdelete Client.tracers[name]\n\t},\n\tclear() {\n\t\tClient.tracers = {}\n\t},\n\tgroup() {\n\t\tlet group = 0;\n\t\treturn {\n\t\t\trequest: (req) => {\n\t\t\t\tgroup++\n\t\t\t\tmetroConsole.group(group)\n\t\t\t\tmetroConsole.info(req?.url, req)\n\t\t\t},\n\t\t\tresponse: (res) => {\n\t\t\t\tmetroConsole.info(res?.body ? res.body[symbols.source]: null, res)\n\t\t\t\tmetroConsole.groupEnd(group)\n\t\t\t\tgroup--\n\t\t\t}\n\t\t}\n\t}\n}\n","import * as metro from './metro.mjs'\nimport * as assert from './assert.mjs'\nimport jsonmw from './mw/json.mjs'\nimport oauth2 from './mw/oauth2.mjs'\n\nwindow.metro = metro\nwindow.assert = assert\nwindow.metro.mw = {\n\tjsonmw,\n\toauth2\n}","let enabled = false\n\nexport function enable() {\n\tenabled = true\n}\n\nexport function disable() {\n\tenabled = false\n}\n\n/**\n * returns new Boolean(true) if data does not match pattern\n * you can't return new Boolean(false), or at least that evaluates\n * to true, so if the data does match, it returns a primitive false\n * the Boolean(true) has an extra property called 'problems', which is\n * an array with a list of all fields that do not match, and why\n * @param {any} data The data to match\n * @param {any} pattern The pattern to match\n * @return {Array|false} Array with problems if the pattern fails, false\n */\nexport function fails(data, pattern) {\n\tlet problems = []\n\tif (pattern instanceof RegExp) {\n \tif (Array.isArray(data)) {\n\t\t\tlet index = data.findIndex(element => fails(element,pattern))\n if (index>-1) {\n \tproblems.push('data['+index+'] does not match pattern')\n }\n \t} else if (!pattern.test(data)) {\n \tproblems.push('data does not match pattern '+pattern)\n }\n } else if (pattern instanceof Function) {\n if (pattern(data)) {\n \tproblems.push('data does not match function')\n }\n } else if (pattern && typeof pattern == 'object') {\n if (Array.isArray(data)) {\n let index = data.findIndex(element => fails(element,pattern))\n if (index>-1) {\n \tproblems.push('data['+index+'] does not match pattern')\n }\n } else if (!data || typeof data != 'object') {\n \tproblems.push('data is not an object, pattern is')\n } else {\n \tif (data instanceof URLSearchParams) {\n \t\tdata = Object.fromEntries(data)\n \t}\n\t let p = problems[problems.length-1]\n\t for (const [wKey, wVal] of Object.entries(pattern)) {\n\t let result = fails(data[wKey], wVal)\n\t if (result) {\n\t \tif (!p || typeof p == 'string') {\n\t \t\tp = {}\n\t \t\tproblems.push(p)\n\t \t}\n\t \tp[wKey] = result.problems\n\t }\n\t }\n\t }\n } else {\n \tif (pattern!=data) {\n \t\tproblems.push('data does not equal '+pattern)\n \t}\n }\n if (problems.length) {\n \treturn problems\n }\n return false\n}\n\nexport function check(source, test) {\n\tif (!enabled) {\n\t\treturn\n\t}\n\tlet result = fails(source,test)\n\tif (result) {\n\t\tthrow new assertError(result,source)\n\t}\n}\n\nexport function optional(pattern) {\n\treturn function(data) {\n\t\tif (data==null || typeof data == 'undefined') {\n\t\t\treturn false\n\t\t}\n\t\treturn fails(data, pattern)\n\t}\n}\n\nexport function oneOf(...patterns) {\n\treturn function(data) {\n\t\tfor(let pattern of patterns) {\n\t\t\tif (!fails(data, pattern)) {\n\t\t\t\treturn false\n\t\t\t}\n\t\t}\n\t\treturn ['data does not match oneOf patterns']\n\t}\n}\n\nclass assertError {\n\tconstructor(problems, ...details) {\n\t\tthis.problems = problems\n\t\tthis.details = details\n\t\tconsole.trace()\n\t}\n\n}\n\n","import * as metro from '../metro.mjs'\n\nexport default function jsonmw(options) {\n\toptions = Object.assign({\n\t\treviver: null,\n\t\treplacer: null,\n\t\tspace: ''\n\t}, options)\n\n\treturn async (req, next) => {\n\t\tif (['POST','PUT','PATCH','QUERY'].includes(req.method)) {\n\t\t\treq = req.with({\n\t\t\t\theaders: {\n\t\t\t\t\t'Content-Type':'application/json',\n\t 'Accept':'application/json'\n\t\t\t\t}\n\t\t\t})\n\t\t\tif (req.body && typeof req.body[metro.symbols.source] == 'object') {\n\t\t\t\treq = req.with({\n\t\t\t\t\tbody: JSON.stringify(req.body[metro.symbols.source], options.replacer, options.space)\n\t\t\t\t})\n\t\t\t}\n\t\t} else {\n\t\t\treq = req.with({\n\t\t\t\theaders: {\n\t\t\t 'Accept':'application/json'\n\t\t\t\t}\n\t\t\t})\n\t\t}\n\t\tlet res = await next(req)\n\t\tlet body = await res.text()\n\t\tlet json = JSON.parse(body, options.reviver)\n\t\treturn res.with({\n\t\t\tbody: json\n\t\t})\n\t}\n}","import * as metro from '../metro.mjs'\nimport * as assert from '../assert.mjs'\nimport jsonmw from './json.mjs'\n\nexport default function oauth2mw(options) {\n\n\tlet localState\n\tif (typeof localStorage !== 'undefined') {\n\t\tlocalState = {\n\t\t\tget: () => localStorage.getItem('metro/state'),\n\t\t\thas: () => localStorage.getItem('metro/state'),\n\t\t\tset: (value) => localStorage.setItem('metro/state', value)\n\t\t}\n\t} else {\n\t\tlet stateMap = new Map()\n\t \tlocalState = {\n\t\t\tget: () => stateMap.getItem('metro/state'),\n\t\t\thas: () => stateMap.getItem('metro/state'),\n\t\t\tset: (value) => stateMap.setItem('metro/state', value)\t \t\t\n\t \t}\n\t}\n\n\tconst oauth2 = {\n\t\ttokens: new Map(),\n\t\tstate: (typeof localStorage !== 'undefined' ? localStorage : new Map()),\n\t\tendpoints: {},\n\t\tcallbacks: {},\n\t\tclient: metro.client().with(jsonmw()),\n\t\tclient_id: '',\n\t\tclient_secret: '',\n\t\tredirect_uri: '',\n\t\tgrant_type: 'authorization_code',\n\t\tforce_authorization: false\n\t}\n\n\tfor (let option in options) {\n\t\tswitch(option) {\n\t\t\tcase 'access_token':\n\t\t\tcase 'authorization_code':\n\t\t\tcase 'refresh_token':\n\t\t\t\toauth2.tokens.set(option, options[option])\n\t\t\tbreak\n\n\t\t\tcase 'client':\n\t\t\tcase 'client_id':\n\t\t\tcase 'client_secret':\n\t\t\tcase 'grant_type':\n\t\t\tcase 'force_authorization':\n\t\t\tcase 'redirect_uri':\n\t\t\t\toauth2[option] = options[option]\n\t\t\tbreak\n\t\t\tcase 'state':\n\t\t\tcase 'tokens':\n\t\t\t\tif (typeof options[option].set == 'function' && \n\t\t\t\t\ttypeof options[option].get == 'function' && \n\t\t\t\t\ttypeof options[option].has == 'function' ) {\n\t\t\t\t\toauth2[option] = options[option]\n\t\t\t\t} else if (option == 'tokens' && typeof options.tokens == 'object') {\n\t\t\t\t\tfor (let token in options.tokens) {\n\t\t\t\t\t\toauth2.tokens.set(token, options.tokens[token])\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\tthrow metro.metroError('metro/mw/oauth2: incorrect value for '+option)\n\t\t\t\t}\n\t\t\tbreak\n\t\t\tcase 'endpoints':\n\t\t\t\tfor (let endpoint in options.endpoints) {\n\t\t\t\t\tif (endpoint!='authorize' && endpoint!='token') {\n\t\t\t\t\t\tthrow metro.metroError('Unknown endpoint, choose one of \"authorize\" or \"token\"',endpoint)\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tObject.assign(oauth2.endpoints, options.endpoints)\n\t\t\tbreak\n\t\t\tcase 'callbacks':\n\t\t\t\tfor (let callback in options.callbacks) {\n\t\t\t\t\tif (callback != 'authorize') {\n\t\t\t\t\t\tthrow metro.metroError('Unknown callback, choose one of \"authorize\"',callback)\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tObject.assign(oauth2.callbacks, options.callbacks)\n\t\t\tbreak\n\t\t\tdefault:\n\t\t\t\tthrow metro.metroError('Unknown oauth2mw option ',option)\n\t\t\tbreak\n\t\t}\n\t\tif (!oauth2.redirect_uri) {\n\t\t\toauth2.redirect_uri = typeof window !== 'undefined' ? window.location?.href : ''\n\t\t}\n\t\tif (oauth2.redirect_uri) {\n\t\t\toauth2.redirect_uri = metro.url(oauth2.redirect_uri).with('?metroRedirect=true')\n\t\t}\n\t}\n\n\treturn async function(req, next) {\n\t\tif (oauth2.force_authorization) {\n\t\t\treturn oauth2authorized(req, next)\n\t\t}\n\t\tlet res = await next(req)\n\t\tif (res.ok) {\n\t\t\treturn res\n\t\t}\n\t\tswitch(res.status) {\n\t\t\tcase 400:\n\t\t\tcase 401:\n\t\t\t\treturn oauth2authorized(req, next)\n\t\t\tbreak\n\t\t}\n\t\treturn res\n\t}\n\n\tasync function oauth2authorized(req, next) {\n\t\tgetTokensFromLocation()\n\t\tif (!oauth2.tokens.has('access_token')) {\n\t\t\tawait fetchToken(req)\n\t\t\treturn oauth2authorized(req, next)\n\t\t} else if (isExpired(req)) {\n\t\t\tawait refreshToken(req)\n\t\t\treturn oauth2authorized(req, next)\n\t\t} else {\n\t\t\tlet accessToken = oauth2.tokens.get('access_token')\n\t\t\treq = metro.request(req, {\n\t\t\t\theaders: {\n\t\t\t\t\tAuthorization: accessToken.type+' '+accessToken.value\n\t\t\t\t}\n\t\t\t})\n\t\t\treturn next(req)\n\t\t}\n\t}\n\n\tfunction getTokensFromLocation() {\n\t\t// check if window.location is available and contains tokens\n\t\tif (typeof window !== 'undefined' && window?.location) {\n\t\t\tlet url = metro.url(window.location)\n\t\t\tlet code, state, params\n\t\t\tif (url.searchParams.has('code')) {\n\t\t\t\tparams = url.searchParams\n\t\t\t\turl = url.with({ search:'' })\n\t\t\t\thistory.pushState({},'',url.href)\n\t\t\t} else if (url.hash) {\n\t\t\t\tlet query = url.hash.substr(1)\n\t\t\t\tparams = new URLSearchParams('?'+query)\n\t\t\t\turl = url.with({ hash:'' })\n\t\t\t\thistory.pushState({},'',url.href)\n\t\t\t}\n\t\t\tif (params) {\n\t\t\t\tcode = params.get('code')\n\t\t\t\tstate = params.get('state')\n\t\t\t\tlet storedState = oauth2.state.get('metro/state')\n\t\t\t\tif (!state || state!==storedState) {\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t\tif (code) {\n\t\t\t\t\toauth2.tokens.set('authorization_code', code)\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tasync function fetchToken(req) {\n\t\tif (oauth2.grant_type === 'authorization_code' && !oauth2.tokens.has('authorization_code')) {\n\t\t\tlet authReqURL = getAuthTokenURL()\n\t\t\tif (!oauth2.callbacks.authorize || typeof oauth2.callbacks.authorize !== 'function') {\n\t\t\t\tthrow metro.metroError('oauth2mw: oauth2 with grant_type:authorization_code requires a callback function in client options.oauth2.callbacks.authorize')\n\t\t\t}\n\t\t\tlet token = await oauth2.callbacks.authorize(authReqURL)\n\t\t\tif (token) {\n\t\t\t\toauth2.tokens.set('authorization_code', token)\n\t\t\t}\n\t\t}\n\t\tlet tokenReq = getAccessTokenRequest()\n\t\tlet response = await oauth2.client.get(tokenReq)\n\t\tif (!response.ok) {\n\t\t\tthrow metro.metroError(response.status+':'+response.statusText, await response.text())\n\t\t}\n\t\tlet data = await response.json()\n\t\toauth2.tokens.set('access_token', {\n\t\t\tvalue: data.access_token,\n\t\t\texpires: getExpires(data.expires_in),\n\t\t\ttype: data.token_type,\n\t\t\tscope: data.scope\n\t\t})\n\t\tif (data.refresh_token) {\n\t\t\toauth2.tokens.set('refresh_token', data.refresh_token)\n\t\t}\n\t\treturn data\n\t}\n\n\tasync function refreshToken(req, next)\n\t{\n\t\tlet refreshTokenReq = getAccessTokenRequest('refresh_token')\n\t\tlet response = await oauth2.client.get(refreshTokenReq)\n\t\tif (!response.ok) {\n\t\t\tthrow metro.metroError(res.status+':'+res.statusText, await res.text())\n\t\t}\n\t\tlet data = await response.json()\n\t\toauth2.tokens.set('access_token', {\n\t\t\tvalue: data.access_token,\n\t\t\texpires: getExpires(data.expires_in),\n\t\t\ttype: data.token_type,\n\t\t\tscope: data.scope\n\t\t})\n\t\tif (data.refresh_token) {\n\t\t\toauth2.tokens.set('refresh_token', data.refresh_token)\n\t\t}\n\t\treturn data\n\t}\n\n\n\tfunction getAuthTokenURL() {\n\t\tif (!oauth2.endpoints.authorize) {\n\t\t\tthrow metro.metroError('oauth2mw: Missing options.endpoints.authorize url')\n\t\t}\n\t\tlet url = metro.url(oauth2.endpoints.authorize, {hash: ''})\n\t\tassert.check(oauth2, {\n\t\t\tclient_id: /.+/,\n\t\t\tredirect_uri: /.+/,\n\t\t\tscope: /.*/\n\t\t})\n\t\treturn metro.url(url, {\n\t\t\tsearch: {\n\t\t\t\tresponse_type: 'code',\n\t\t\t\tclient_id: oauth2.client_id,\n\t\t\t\tredirect_uri: oauth2.redirect_uri,\n\t\t\t\tscope: oauth2.scope,\n\t\t\t\tstate: createState(40)\n\t\t\t}\n\t\t})\n\t}\n\n\tfunction createState(length) {\n\t\tconst validChars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'\n\t\tlet randomState = ''\n\t\tlet counter = 0\n\t while (counter < length) {\n\t randomState += validChars.charAt(Math.floor(Math.random() * validChars.length))\n\t counter++\n\t }\n\t\toauth2.state.set(randomState)\n\t\treturn randomState\n\t}\n\n\tfunction getAccessTokenRequest(grant_type=null) {\n\t\tassert.check(oauth2, {\n\t\t\tclient_id: /.+/,\n\t\t\tclient_secret: /.+/,\n\t\t\tredirect_uri: /.+/\n\t\t})\n\t\tif (!oauth2.endpoints.token) {\n\t\t\tthrow metro.metroError('oauth2mw: Missing options.endpoints.token url')\n\t\t}\n\t\tlet url = metro.url(oauth2.endpoints.token, {hash: ''})\n\t\tlet params = {\n\t\t\tgrant_type: grant_type || oauth2.grant_type,\n\t\t\tclient_id: oauth2.client_id,\n\t\t\tclient_secret: oauth2.client_secret\n\t\t}\n\t\tif (oauth2.scope) {\n\t\t\tparams.scope = oauth2.scope\n\t\t}\n\t\tswitch(oauth2.grant_type) {\n\t\t\tcase 'authorization_code':\n\t\t\t\tparams.redirect_uri = oauth2.redirect_uri\n\t\t\t\tparams.code = oauth2.tokens.get('authorization_code')\n\t\t\t\tparams.response_type = 'token' // spec #3.1.1\n\t\t\tbreak\n\t\t\tcase 'client_credentials':\n\t\t\t\tthrow new Error('Not yet implemented') // @TODO:\n\t\t\tbreak\n\t\t\tcase 'refresh_token':\n\t\t\t\tthrow new Error('Not yet implemented') // @TODO:\n\t\t\tbreak\n\t\t}\n\t\treturn metro.request(url, {\n\t\t\tmethod: 'GET',\n\t\t\turl: {\n\t\t\t\tsearchParams: params\n\t\t\t}\n\t\t})\n\t}\n\n\tfunction isExpired(req) {\n\t\tif (req.oauth2 && req.oauth2.tokens && req.oauth2.tokens.has('access_token')) {\n\t\t\tlet now = new Date();\n\t\t\tlet token = req.oauth2.tokens.get('access_token')\n\t\t\treturn now.getTime() > token.expires.getTime();\n\t\t}\n\t\treturn false;\n\t}\n\n\tfunction getExpires(duration) {\n\t\tif (duration instanceof Date) {\n\t\t\treturn new Date(duration.getTime()); // return a copy\n\t\t}\n\t\tif (typeof duration === 'number') {\n\t\t\tlet date = new Date();\n\t\t\tdate.setSeconds(date.getSeconds() + duration);\n\t\t\treturn date;\n\t\t}\n\t\tthrow new TypeError('Unknown expires type '+duration);\n\t}\n\n\n}"],"names":["$parcel$export","e","n","v","s","Object","defineProperty","get","set","enumerable","configurable","$parcel$global","globalThis","$parcel$modules","$parcel$inits","parcelRequire","id","exports","init","module","call","err","Error","code","register","parcelRegister","$86c8ab3a59b0bae1$export$47616e9f7f5fe113","$86c8ab3a59b0bae1$export$b5fe3f66a567bec0","$86c8ab3a59b0bae1$export$7079e2c78c274c66","$86c8ab3a59b0bae1$export$785bb8ef7fad1f74","$86c8ab3a59b0bae1$export$388e0302ca0d9a41","$86c8ab3a59b0bae1$export$128fa18b7194ef","$86c8ab3a59b0bae1$export$5de500aade6bf050","options","params","FormData","option","entry","entries","append","Array","isArray","value","freeze","Proxy","target","prop","receiver","isProxy","source","$86c8ab3a59b0bae1$export$357889f174732d38","$86c8ab3a59b0bae1$var$metroURL","Symbol","$86c8ab3a59b0bae1$var$Client","url","window","location","verbs","tracers","constructor","String","assign","Function","addMiddlewares","param","verb","fetch","method","toUpperCase","middlewares","index","findIndex","m","concat","req","next","r","toLowerCase","slice","middleware","res","values","tracer","request","response","with","$86c8ab3a59b0bae1$var$bodyProxy","body","r1","ReadableStream","Blob","stream","start","controller","chunk","toString","URLSearchParams","ArrayBuffer","isView","enqueue","close","args","apply","has","ownKeys","Reflect","getOwnPropertyDescriptor","requestParams","duplex","URL","$86c8ab3a59b0bae1$var$getRequestParams","current","DataView","TypedArray","JSON","stringify","Request","$86c8ab3a59b0bae1$var$getResponseParams","responseParams","Response","status","headers","$86c8ab3a59b0bae1$var$appendSearchParams","searchParams","forEach","key","validParams","u","Location","search","includes","Number","Boolean","$86c8ab3a59b0bae1$var$metroConsole","error","message","details","console","info","group","name","groupEnd","add","delete","clear","$hkeot","$2ddd80d1adc2ea42$exports","$2ddd80d1adc2ea42$export$d7c4a0dd6a4567e5","$2ddd80d1adc2ea42$export$e20fbacbb41798b","$2ddd80d1adc2ea42$export$478159de811fd37d","$2ddd80d1adc2ea42$export$35dc45686fc2dbd7","$2ddd80d1adc2ea42$export$516e28dec6a4b6d4","$2ddd80d1adc2ea42$export$a9a18ae5ba42aeab","$2ddd80d1adc2ea42$var$enabled","data","pattern","problems","RegExp","element","push","test","fromEntries","p","length","wKey","wVal","result","$2ddd80d1adc2ea42$var$assertError","patterns","trace","$9cea4e31d030ec91$export$2e2bcd8739ae039","reviver","replacer","space","symbols","json","parse","text","metro","assert","mw","jsonmw","oauth2","tokens","Map","state","localStorage","endpoints","callbacks","client","client_id","client_secret","redirect_uri","grant_type","force_authorization","token","metroError","endpoint","callback","href","oauth2authorized","res1","ok","getTokensFromLocation","history","pushState","hash","query","substr","storedState","fetchToken","isExpired","now","Date","getTime","expires","refreshToken","accessToken","Authorization","type","authReqURL","getAuthTokenURL","authorize","scope","response_type","createState","validChars","randomState","counter","charAt","Math","floor","random","tokenReq","getAccessTokenRequest","statusText","access_token","getExpires","expires_in","token_type","refresh_token","refreshTokenReq","duration","date","setSeconds","getSeconds","TypeError"],"version":3,"file":"everything.js.map","sourceRoot":"../"} \ No newline at end of file +{"mappings":"A,S,E,C,C,C,C,C,C,C,E,O,c,C,E,E,C,I,E,I,E,W,C,E,a,C,C,E,C,I,E,W,E,C,E,E,C,E,E,E,iB,A,O,I,A,C,E,S,C,E,G,K,E,O,C,C,E,C,O,C,G,K,E,C,I,E,C,C,E,A,Q,C,C,E,C,I,E,C,G,E,Q,C,C,E,O,C,C,E,C,E,E,I,C,E,O,C,E,E,O,E,E,O,A,C,I,E,A,M,uB,E,I,O,E,I,C,mB,C,C,E,Q,C,S,C,C,C,E,C,C,E,C,C,E,E,iB,C,G,A,C,E,E,Q,A,E,Q,S,C,C,C,E,E,E,O,C,U,I,G,E,E,O,C,U,I,G,E,E,O,C,a,I,G,E,E,O,C,W,I,G,E,E,O,C,S,I,G,E,E,O,C,M,I,G,E,E,O,C,W,IC2gBO,SAAS,EAAS,GAAG,CAAO,EAClC,IAAI,EAAS,IAAI,SACjB,IAAK,IAAI,KAAU,EAClB,GAAI,aAAkB,SACrB,IAAK,IAAI,KAAS,EAAO,OAAO,GAC/B,EAAO,MAAM,CAAC,CAAK,CAAC,EAAE,CAAC,CAAK,CAAC,EAAE,OAE1B,GAAI,GAAU,AAAiB,UAAjB,OAAO,EAC3B,IAAK,IAAI,KAAS,OAAO,OAAO,CAAC,GAChC,GAAI,MAAM,OAAO,CAAC,CAAK,CAAC,EAAE,EACzB,IAAK,IAAI,KAAS,CAAK,CAAC,EAAE,CACzB,EAAO,MAAM,CAAC,CAAK,CAAC,EAAE,CAAE,QAGzB,EAAO,MAAM,CAAC,CAAK,CAAC,EAAE,CAAC,CAAK,CAAC,EAAE,OAIjC,MAAM,IAAI,EAAW,yEAAyE,GAIhG,OADA,OAAO,MAAM,CAAC,GACP,IAAI,MAAM,EAAQ,CACxB,IAAK,CAAC,EAAO,EAAK,KACjB,OAAO,GACN,KAAK,EAAQ,OAAO,CACnB,MAAO,CAAA,CAER,MAAK,EAAQ,MAAM,CAClB,OAAO,CAER,KAAK,OACJ,OAAO,SAAS,GAAG,CAAO,EACzB,OAAO,EAAS,KAAW,EAC5B,CAED,KAAK,WACL,IAAK,SACJ,OAAO,WACN,OAAO,CAAM,CAAC,EAAK,EACpB,CAEF,CACA,OAAO,CAAM,CAAC,EAAK,AACpB,CACD,EACD,G,E,E,O,C,Q,I,GAzjBA,IAAM,EAAW,iCAEJ,EAAU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","sources":["","src/metro.mjs","src/everything.mjs","src/assert.mjs","src/mw/json.mjs","src/mw/oauth2.mjs"],"sourcesContent":["\nfunction $parcel$export(e, n, v, s) {\n Object.defineProperty(e, n, {get: v, set: s, enumerable: true, configurable: true});\n}\n\n var $parcel$global = globalThis;\n \nvar $parcel$modules = {};\nvar $parcel$inits = {};\n\nvar parcelRequire = $parcel$global[\"parcelRequireea2c\"];\n\nif (parcelRequire == null) {\n parcelRequire = function(id) {\n if (id in $parcel$modules) {\n return $parcel$modules[id].exports;\n }\n if (id in $parcel$inits) {\n var init = $parcel$inits[id];\n delete $parcel$inits[id];\n var module = {id: id, exports: {}};\n $parcel$modules[id] = module;\n init.call(module.exports, module, module.exports);\n return module.exports;\n }\n var err = new Error(\"Cannot find module '\" + id + \"'\");\n err.code = 'MODULE_NOT_FOUND';\n throw err;\n };\n\n parcelRequire.register = function register(id, init) {\n $parcel$inits[id] = init;\n };\n\n $parcel$global[\"parcelRequireea2c\"] = parcelRequire;\n}\n\nvar parcelRegister = parcelRequire.register;\nparcelRegister(\"hkeot\", function(module, exports) {\n\n$parcel$export(module.exports, \"symbols\", () => $86c8ab3a59b0bae1$export$47616e9f7f5fe113);\n$parcel$export(module.exports, \"request\", () => $86c8ab3a59b0bae1$export$b5fe3f66a567bec0);\n$parcel$export(module.exports, \"metroError\", () => $86c8ab3a59b0bae1$export$7079e2c78c274c66);\n$parcel$export(module.exports, \"response\", () => $86c8ab3a59b0bae1$export$785bb8ef7fad1f74);\n$parcel$export(module.exports, \"client\", () => $86c8ab3a59b0bae1$export$388e0302ca0d9a41);\n$parcel$export(module.exports, \"url\", () => $86c8ab3a59b0bae1$export$128fa18b7194ef);\n$parcel$export(module.exports, \"formdata\", () => $86c8ab3a59b0bae1$export$5de500aade6bf050);\n$parcel$export(module.exports, \"trace\", () => $86c8ab3a59b0bae1$export$357889f174732d38);\nconst $86c8ab3a59b0bae1$var$metroURL = \"https://metro.muze.nl/details/\";\nconst $86c8ab3a59b0bae1$export$47616e9f7f5fe113 = {\n isProxy: Symbol(\"isProxy\"),\n source: Symbol(\"source\")\n};\nclass $86c8ab3a59b0bae1$var$Client {\n #options = {\n url: typeof window != \"undefined\" ? window.location : \"https://localhost\"\n };\n #verbs = [\n \"get\",\n \"post\",\n \"put\",\n \"delete\",\n \"patch\",\n \"head\",\n \"options\",\n \"query\"\n ];\n static tracers = {};\n constructor(...options){\n for (let option of options){\n if (typeof option == \"string\" || option instanceof String) this.#options.url = \"\" + option;\n else if (option instanceof $86c8ab3a59b0bae1$var$Client) Object.assign(this.#options, option.#options);\n else if (option instanceof Function) this.#addMiddlewares([\n option\n ]);\n else if (option && typeof option == \"object\") for(let param in option){\n if (param == \"middlewares\") this.#addMiddlewares(option[param]);\n else if (typeof option[param] == \"function\") this.#options[param] = option[param](this.#options[param], this.#options);\n else this.#options[param] = option[param];\n }\n }\n if (this.#options.verbs) {\n this.#verbs = this.#options.verbs;\n delete this.#options.verbs;\n }\n for (const verb of this.#verbs)this[verb] = async function(...options) {\n return this.#fetch($86c8ab3a59b0bae1$export$b5fe3f66a567bec0(this.#options, ...options, {\n method: verb.toUpperCase()\n }));\n };\n Object.freeze(this);\n }\n #addMiddlewares(middlewares) {\n if (typeof middlewares == \"function\") middlewares = [\n middlewares\n ];\n let index = middlewares.findIndex((m)=>typeof m != \"function\");\n if (index >= 0) throw $86c8ab3a59b0bae1$export$7079e2c78c274c66(\"metro.client: middlewares must be a function or an array of functions \" + $86c8ab3a59b0bae1$var$metroURL + \"client/invalid-middlewares-value/\", middlewares[index]);\n if (!Array.isArray(this.#options.middlewares)) this.#options.middlewares = [];\n this.#options.middlewares = this.#options.middlewares.concat(middlewares);\n }\n #fetch(req) {\n if (!req.url) throw $86c8ab3a59b0bae1$export$7079e2c78c274c66(\"metro.client.\" + r.method.toLowerCase() + \": Missing url parameter \" + $86c8ab3a59b0bae1$var$metroURL + \"client/missing-url-param/\", req);\n let metrofetch = async (req)=>{\n if (req[$86c8ab3a59b0bae1$export$47616e9f7f5fe113.isProxy]) // even though a Proxy is supposed to be 'invisible'\n // fetch() doesn't work with the proxy (in Firefox), \n // you need the actual Request object here\n req = req[$86c8ab3a59b0bae1$export$47616e9f7f5fe113.source];\n return $86c8ab3a59b0bae1$export$785bb8ef7fad1f74(await fetch(req));\n };\n let middlewares = [\n metrofetch\n ].concat(this.#options?.middlewares?.slice() || []);\n let options = this.#options;\n //@TODO: do this once in constructor?\n let next;\n for (let middleware of middlewares)next = function(next, middleware) {\n return async function(req) {\n let res;\n let tracers = Object.values($86c8ab3a59b0bae1$var$Client.tracers);\n for (let tracer of tracers)if (tracer.request) tracer.request.call(tracer, req);\n res = await middleware(req, next);\n for (let tracer of tracers)if (tracer.response) tracer.response.call(tracer, res);\n return res;\n };\n }(next, middleware);\n return next(req);\n }\n with(...options) {\n return new $86c8ab3a59b0bae1$var$Client(this, ...options);\n }\n}\nfunction $86c8ab3a59b0bae1$export$388e0302ca0d9a41(...options) {\n return new $86c8ab3a59b0bae1$var$Client(...options);\n}\nfunction $86c8ab3a59b0bae1$var$appendHeaders(r1, headers) {\n if (!Array.isArray(headers)) headers = [\n headers\n ];\n headers.forEach((header)=>{\n if (typeof header == \"function\") {\n let result = header(r1.headers, r1);\n if (result) {\n if (!Array.isArray(result)) result = [\n result\n ];\n headers = headers.concat(result);\n }\n }\n });\n headers.forEach((header)=>{\n Object.entries(header).forEach(([name, value])=>{\n r1.headers.append(name, value);\n });\n });\n}\nfunction $86c8ab3a59b0bae1$var$bodyProxy(body, r1) {\n let source = r1.body;\n if (!source) {\n //Firefox does not allow access to Request.body (undefined)\n //Chrome and Nodejs do, so mimic the correct (documented)\n //result here\n if (body === null) source = new ReadableStream();\n else if (body instanceof ReadableStream) source = body;\n else if (body instanceof Blob) source = body.stream();\n else source = new ReadableStream({\n start (controller) {\n let chunk;\n switch(typeof body){\n case \"object\":\n if (typeof body.toString == \"function\") // also catches URLSearchParams\n chunk = body.toString();\n else if (body instanceof FormData) chunk = new URLSearchParams(body).toString();\n else if (body instanceof ArrayBuffer || ArrayBuffer.isView(body)) // catchs TypedArrays - e.g. Uint16Array\n chunk = body;\n else throw $86c8ab3a59b0bae1$export$7079e2c78c274c66(\"Cannot convert body to ReadableStream\", body);\n break;\n case \"string\":\n case \"number\":\n case \"boolean\":\n chunk = body;\n break;\n default:\n throw $86c8ab3a59b0bae1$export$7079e2c78c274c66(\"Cannot convert body to ReadableStream\", body);\n }\n controller.enqueue(chunk);\n controller.close();\n }\n });\n }\n return new Proxy(source, {\n get (target, prop, receiver) {\n switch(prop){\n case $86c8ab3a59b0bae1$export$47616e9f7f5fe113.isProxy:\n return true;\n case $86c8ab3a59b0bae1$export$47616e9f7f5fe113.source:\n return body;\n case \"toString\":\n return function() {\n return \"\" + body;\n };\n }\n if (typeof body == \"object\") {\n if (prop in body) {\n if (typeof body[prop] == \"function\") return function(...args) {\n return body[prop].apply(body, args);\n };\n return body[prop];\n }\n }\n if (prop in target && prop != \"toString\") {\n // skipped toString, since it has no usable output\n // and body may have its own toString\n if (typeof target[prop] == \"function\") return function(...args) {\n return target[prop].apply(target, args);\n };\n return target[prop];\n }\n },\n has (target, prop) {\n return prop in body;\n },\n ownKeys (target) {\n return Reflect.ownKeys(body);\n },\n getOwnPropertyDescriptor (target, prop) {\n return Object.getOwnPropertyDescriptor(body, prop);\n }\n });\n}\nfunction $86c8ab3a59b0bae1$var$getRequestParams(req, current) {\n let params = current || {};\n if (!params.url && current.url) params.url = current.url;\n // function to fetch all relevant properties of a Request\n for (let prop of [\n \"method\",\n \"headers\",\n \"body\",\n \"mode\",\n \"credentials\",\n \"cache\",\n \"redirect\",\n \"referrer\",\n \"referrerPolicy\",\n \"integrity\",\n \"keepalive\",\n \"signal\",\n \"priority\",\n \"url\"\n ]){\n if (typeof req[prop] == \"function\") req[prop](params[prop], params);\n else if (typeof req[prop] != \"undefined\") {\n if (prop == \"url\") params.url = $86c8ab3a59b0bae1$export$128fa18b7194ef(params.url, req.url);\n else params[prop] = req[prop];\n }\n }\n return params;\n}\nfunction $86c8ab3a59b0bae1$export$b5fe3f66a567bec0(...options) {\n // the standard Request constructor is a minefield\n // so first gather all the options together into a single\n // javascript object, then set it in one go\n let requestParams = {\n url: typeof window != \"undefined\" ? window.location : \"https://localhost/\",\n duplex: \"half\" // required when setting body to ReadableStream, just set it here by default already\n };\n for (let option of options){\n if (typeof option == \"string\" || option instanceof URL || option instanceof URLSearchParams) requestParams.url = $86c8ab3a59b0bae1$export$128fa18b7194ef(requestParams.url, option);\n else if (option && typeof option == \"object\") Object.assign(requestParams, $86c8ab3a59b0bae1$var$getRequestParams(option, requestParams));\n }\n let body = requestParams.body;\n if (body) {\n if (typeof body == \"object\" && !(body instanceof String) && !(body instanceof ReadableStream) && !(body instanceof Blob) && !(body instanceof ArrayBuffer) && !(body instanceof DataView) && !(body instanceof FormData) && !(body instanceof URLSearchParams) && (typeof TypedArray == \"undefined\" || !(body instanceof TypedArray))) requestParams.body = JSON.stringify(body);\n }\n let r1 = new Request(requestParams.url, requestParams);\n Object.freeze(r1);\n return new Proxy(r1, {\n get (target, prop, receiver) {\n switch(prop){\n case $86c8ab3a59b0bae1$export$47616e9f7f5fe113.source:\n return target;\n case $86c8ab3a59b0bae1$export$47616e9f7f5fe113.isProxy:\n return true;\n case \"with\":\n return function(...options) {\n return $86c8ab3a59b0bae1$export$b5fe3f66a567bec0(target, ...options);\n };\n case \"toString\":\n case \"toJSON\":\n return function() {\n return target[prop].apply(target);\n };\n case \"blob\":\n case \"text\":\n case \"json\":\n return function() {\n return target[prop].apply(target);\n };\n case \"body\":\n // Request.body is always a ReadableStream\n // which is a horrible API, if you want to\n // allow middleware to alter the body\n // so we keep the original body, wrap a Proxy\n // around it to keep the ReadableStream api\n // accessible, but allow access to the original\n // body value as well\n if (!body) body = target.body;\n if (body) {\n if (body[$86c8ab3a59b0bae1$export$47616e9f7f5fe113.isProxy]) return body;\n return $86c8ab3a59b0bae1$var$bodyProxy(body, target);\n }\n break;\n }\n return target[prop];\n }\n });\n}\nfunction $86c8ab3a59b0bae1$var$getResponseParams(res, current) {\n // function to fetch all relevant properties of a Response\n let params = current || {};\n if (!params.url && current.url) params.url = current.url;\n for (let prop of [\n \"status\",\n \"statusText\",\n \"headers\",\n \"body\",\n \"url\",\n \"type\",\n \"redirected\"\n ]){\n if (typeof res[prop] == \"function\") res[prop](params[prop], params);\n else if (typeof res[prop] != \"undefined\") {\n if (prop == \"url\") params.url = new URL(res.url, params.url || \"https://localhost/\");\n else params[prop] = res[prop];\n }\n }\n return params;\n}\nfunction $86c8ab3a59b0bae1$export$785bb8ef7fad1f74(...options) {\n let responseParams = {};\n for (let option of options){\n if (typeof option == \"string\") responseParams.body = option;\n else if (option instanceof Response) Object.assign(responseParams, $86c8ab3a59b0bae1$var$getResponseParams(option, responseParams));\n else if (option && typeof option == \"object\") {\n if (option instanceof FormData || option instanceof Blob || option instanceof ArrayBuffer || option instanceof DataView || option instanceof ReadableStream || option instanceof URLSearchParams || option instanceof String || typeof TypedArray != \"undefined\" && option instanceof TypedArray) responseParams.body = option;\n else Object.assign(responseParams, $86c8ab3a59b0bae1$var$getResponseParams(option, responseParams));\n }\n }\n let r1 = new Response(responseParams.body, responseParams);\n Object.freeze(r1);\n return new Proxy(r1, {\n get (target, prop, receiver) {\n switch(prop){\n case $86c8ab3a59b0bae1$export$47616e9f7f5fe113.isProxy:\n return true;\n case $86c8ab3a59b0bae1$export$47616e9f7f5fe113.source:\n return target;\n case \"with\":\n return function(...options) {\n return $86c8ab3a59b0bae1$export$785bb8ef7fad1f74(target, ...options);\n };\n case \"body\":\n if (responseParams.body) {\n if (responseParams.body[$86c8ab3a59b0bae1$export$47616e9f7f5fe113.isProxy]) return responseParams.body;\n return $86c8ab3a59b0bae1$var$bodyProxy(responseParams.body, target);\n } else return $86c8ab3a59b0bae1$var$bodyProxy(\"\", target);\n break;\n case \"ok\":\n return target.status >= 200 && target.status < 400;\n case \"headers\":\n return target.headers;\n default:\n if (prop in responseParams && prop != \"toString\") return responseParams[prop];\n if (prop in target && prop != \"toString\") {\n // skipped toString, since it has no usable output\n // and body may have its own toString\n if (typeof target[prop] == \"function\") return function(...args) {\n return target[prop].apply(target, args);\n };\n return target[prop];\n }\n break;\n }\n return undefined;\n }\n });\n}\nfunction $86c8ab3a59b0bae1$var$appendSearchParams(url, params) {\n if (typeof params == \"function\") params(url.searchParams, url);\n else {\n params = new URLSearchParams(params);\n params.forEach((value, key)=>{\n url.searchParams.append(key, value);\n });\n }\n}\nfunction $86c8ab3a59b0bae1$export$128fa18b7194ef(...options) {\n let validParams = [\n \"hash\",\n \"host\",\n \"hostname\",\n \"href\",\n \"password\",\n \"pathname\",\n \"port\",\n \"protocol\",\n \"username\",\n \"search\",\n \"searchParams\"\n ];\n let u = new URL(\"https://localhost/\");\n for (let option of options){\n if (typeof option == \"string\" || option instanceof String) // option is a relative or absolute url\n u = new URL(option, u);\n else if (option instanceof URL || typeof Location != \"undefined\" && option instanceof Location) u = new URL(option);\n else if (option instanceof URLSearchParams) $86c8ab3a59b0bae1$var$appendSearchParams(u, option);\n else if (option && typeof option == \"object\") for(let param in option){\n if (param == \"search\") {\n if (typeof option.search == \"function\") option.search(u.search, u);\n else u.search = new URLSearchParams(option.search);\n } else if (param == \"searchParams\") $86c8ab3a59b0bae1$var$appendSearchParams(u, option.searchParams);\n else {\n if (!validParams.includes(param)) throw $86c8ab3a59b0bae1$export$7079e2c78c274c66(\"metro.url: unknown url parameter \" + $86c8ab3a59b0bae1$var$metroURL + \"url/unknown-param-name/\", param);\n if (typeof option[param] == \"function\") option[param](u[param], u);\n else if (typeof option[param] == \"string\" || option[param] instanceof String || typeof option[param] == \"number\" || option[param] instanceof Number || typeof option[param] == \"boolean\" || option[param] instanceof Boolean) u[param] = \"\" + option[param];\n else if (typeof option[param] == \"object\" && option[param].toString) u[param] = option[param].toString();\n else throw $86c8ab3a59b0bae1$export$7079e2c78c274c66(\"metro.url: unsupported value for \" + param + \" \" + $86c8ab3a59b0bae1$var$metroURL + \"url/unsupported-param-value/\", options[param]);\n }\n }\n else throw $86c8ab3a59b0bae1$export$7079e2c78c274c66(\"metro.url: unsupported option value \" + $86c8ab3a59b0bae1$var$metroURL + \"url/unsupported-option-value/\", option);\n }\n Object.freeze(u);\n return new Proxy(u, {\n get (target, prop, receiver) {\n switch(prop){\n case $86c8ab3a59b0bae1$export$47616e9f7f5fe113.isProxy:\n return true;\n case $86c8ab3a59b0bae1$export$47616e9f7f5fe113.source:\n return target;\n case \"with\":\n return function(...options) {\n return $86c8ab3a59b0bae1$export$128fa18b7194ef(target, ...options);\n };\n case \"toString\":\n case \"toJSON\":\n return function() {\n return target[prop]();\n };\n }\n return target[prop];\n }\n });\n}\nfunction $86c8ab3a59b0bae1$export$5de500aade6bf050(...options) {\n var params = new FormData();\n for (let option of options){\n if (option instanceof FormData) for (let entry of option.entries())params.append(entry[0], entry[1]);\n else if (option && typeof option == \"object\") for (let entry of Object.entries(option)){\n if (Array.isArray(entry[1])) for (let value of entry[1])params.append(entry[0], value);\n else params.append(entry[0], entry[1]);\n }\n else throw new $86c8ab3a59b0bae1$export$7079e2c78c274c66(\"metro.formdata: unknown option type, only FormData or Object supported\", option);\n }\n Object.freeze(params);\n return new Proxy(params, {\n get: (target, prop, receiver)=>{\n switch(prop){\n case $86c8ab3a59b0bae1$export$47616e9f7f5fe113.isProxy:\n return true;\n case $86c8ab3a59b0bae1$export$47616e9f7f5fe113.source:\n return target;\n case \"with\":\n return function(...options) {\n return $86c8ab3a59b0bae1$export$5de500aade6bf050(target, ...options);\n };\n case \"toString\":\n case \"toJSON\":\n return function() {\n return target[prop]();\n };\n }\n return target[prop];\n }\n });\n}\nconst $86c8ab3a59b0bae1$var$metroConsole = {\n error: (message, ...details)=>{\n console.error(\"\\u24C2\\uFE0F \", message, ...details);\n },\n info: (message, ...details)=>{\n console.info(\"\\u24C2\\uFE0F \", message, ...details);\n },\n group: (name)=>{\n console.group(\"\\u24C2\\uFE0F \" + name);\n },\n groupEnd: (name)=>{\n console.groupEnd(\"\\u24C2\\uFE0F \" + name);\n }\n};\nfunction $86c8ab3a59b0bae1$export$7079e2c78c274c66(message, ...details) {\n $86c8ab3a59b0bae1$var$metroConsole.error(message, ...details);\n return new Error(message, ...details);\n}\nconst $86c8ab3a59b0bae1$export$357889f174732d38 = {\n add (name, tracer) {\n $86c8ab3a59b0bae1$var$Client.tracers[name] = tracer;\n },\n delete (name) {\n delete $86c8ab3a59b0bae1$var$Client.tracers[name];\n },\n clear () {\n $86c8ab3a59b0bae1$var$Client.tracers = {};\n },\n group () {\n let group = 0;\n return {\n request: (req)=>{\n group++;\n $86c8ab3a59b0bae1$var$metroConsole.group(group);\n $86c8ab3a59b0bae1$var$metroConsole.info(req?.url, req);\n },\n response: (res)=>{\n $86c8ab3a59b0bae1$var$metroConsole.info(res?.body ? res.body[$86c8ab3a59b0bae1$export$47616e9f7f5fe113.source] : null, res);\n $86c8ab3a59b0bae1$var$metroConsole.groupEnd(group);\n group--;\n }\n };\n }\n};\n\n});\n\n\nvar $hkeot = parcelRequire(\"hkeot\");\nvar $2ddd80d1adc2ea42$exports = {};\n\n$parcel$export($2ddd80d1adc2ea42$exports, \"enable\", () => $2ddd80d1adc2ea42$export$d7c4a0dd6a4567e5);\n$parcel$export($2ddd80d1adc2ea42$exports, \"disable\", () => $2ddd80d1adc2ea42$export$e20fbacbb41798b);\n$parcel$export($2ddd80d1adc2ea42$exports, \"fails\", () => $2ddd80d1adc2ea42$export$478159de811fd37d);\n$parcel$export($2ddd80d1adc2ea42$exports, \"check\", () => $2ddd80d1adc2ea42$export$35dc45686fc2dbd7);\n$parcel$export($2ddd80d1adc2ea42$exports, \"optional\", () => $2ddd80d1adc2ea42$export$516e28dec6a4b6d4);\n$parcel$export($2ddd80d1adc2ea42$exports, \"oneOf\", () => $2ddd80d1adc2ea42$export$a9a18ae5ba42aeab);\nlet $2ddd80d1adc2ea42$var$enabled = false;\nfunction $2ddd80d1adc2ea42$export$d7c4a0dd6a4567e5() {\n $2ddd80d1adc2ea42$var$enabled = true;\n}\nfunction $2ddd80d1adc2ea42$export$e20fbacbb41798b() {\n $2ddd80d1adc2ea42$var$enabled = false;\n}\nfunction $2ddd80d1adc2ea42$export$478159de811fd37d(data, pattern) {\n let problems = [];\n if (pattern instanceof RegExp) {\n if (Array.isArray(data)) {\n let index = data.findIndex((element)=>$2ddd80d1adc2ea42$export$478159de811fd37d(element, pattern));\n if (index > -1) problems.push(\"data[\" + index + \"] does not match pattern\");\n } else if (!pattern.test(data)) problems.push(\"data does not match pattern \" + pattern);\n } else if (pattern instanceof Function) {\n if (pattern(data)) problems.push(\"data does not match function\");\n } else if (pattern && typeof pattern == \"object\") {\n if (Array.isArray(data)) {\n let index = data.findIndex((element)=>$2ddd80d1adc2ea42$export$478159de811fd37d(element, pattern));\n if (index > -1) problems.push(\"data[\" + index + \"] does not match pattern\");\n } else if (!data || typeof data != \"object\") problems.push(\"data is not an object, pattern is\");\n else {\n if (data instanceof URLSearchParams) data = Object.fromEntries(data);\n let p = problems[problems.length - 1];\n for (const [wKey, wVal] of Object.entries(pattern)){\n let result = $2ddd80d1adc2ea42$export$478159de811fd37d(data[wKey], wVal);\n if (result) {\n if (!p || typeof p == \"string\") {\n p = {};\n problems.push(p);\n }\n p[wKey] = result.problems;\n }\n }\n }\n } else if (pattern != data) problems.push(\"data does not equal \" + pattern);\n if (problems.length) return problems;\n return false;\n}\nfunction $2ddd80d1adc2ea42$export$35dc45686fc2dbd7(source, test) {\n if (!$2ddd80d1adc2ea42$var$enabled) return;\n let result = $2ddd80d1adc2ea42$export$478159de811fd37d(source, test);\n if (result) throw new $2ddd80d1adc2ea42$var$assertError(result, source);\n}\nfunction $2ddd80d1adc2ea42$export$516e28dec6a4b6d4(pattern) {\n return function(data) {\n if (data == null || typeof data == \"undefined\") return false;\n return $2ddd80d1adc2ea42$export$478159de811fd37d(data, pattern);\n };\n}\nfunction $2ddd80d1adc2ea42$export$a9a18ae5ba42aeab(...patterns) {\n return function(data) {\n for (let pattern of patterns){\n if (!$2ddd80d1adc2ea42$export$478159de811fd37d(data, pattern)) return false;\n }\n return [\n \"data does not match oneOf patterns\"\n ];\n };\n}\nclass $2ddd80d1adc2ea42$var$assertError {\n constructor(problems, ...details){\n this.problems = problems;\n this.details = details;\n console.trace();\n }\n}\n\n\n\nvar $hkeot = parcelRequire(\"hkeot\");\nfunction $9cea4e31d030ec91$export$2e2bcd8739ae039(options) {\n options = Object.assign({\n reviver: null,\n replacer: null,\n space: \"\"\n }, options);\n return async (req, next)=>{\n if ([\n \"POST\",\n \"PUT\",\n \"PATCH\",\n \"QUERY\"\n ].includes(req.method)) {\n req = req.with({\n headers: {\n \"Content-Type\": \"application/json\",\n \"Accept\": \"application/json\"\n }\n });\n if (req.body && typeof req.body[$hkeot.symbols.source] == \"object\") req = req.with({\n body: JSON.stringify(req.body[$hkeot.symbols.source], options.replacer, options.space)\n });\n } else req = req.with({\n headers: {\n \"Accept\": \"application/json\"\n }\n });\n let res = await next(req);\n let body = await res.text();\n let json = JSON.parse(body, options.reviver);\n return res.with({\n body: json\n });\n };\n}\n\n\n\nvar $hkeot = parcelRequire(\"hkeot\");\n\n\nfunction $94580a8710b2e8f9$export$2e2bcd8739ae039(options) {\n let localState;\n if (typeof localStorage !== \"undefined\") localState = {\n get: ()=>localStorage.getItem(\"metro/state\"),\n has: ()=>localStorage.getItem(\"metro/state\"),\n set: (value)=>localStorage.setItem(\"metro/state\", value)\n };\n else {\n let stateMap = new Map();\n localState = {\n get: ()=>stateMap.get(\"metro/state\"),\n has: ()=>stateMap.get(\"metro/state\"),\n set: (value)=>stateMap.set(\"metro/state\", value)\n };\n }\n const oauth2 = {\n tokens: new Map(),\n state: localState,\n endpoints: {},\n callbacks: {},\n client: $hkeot.client().with((0, $9cea4e31d030ec91$export$2e2bcd8739ae039)()),\n client_id: \"\",\n client_secret: \"\",\n redirect_uri: \"\",\n grant_type: \"authorization_code\",\n force_authorization: false\n };\n for(let option in options){\n switch(option){\n case \"access_token\":\n case \"authorization_code\":\n case \"refresh_token\":\n oauth2.tokens.set(option, options[option]);\n break;\n case \"client\":\n case \"client_id\":\n case \"client_secret\":\n case \"grant_type\":\n case \"force_authorization\":\n case \"redirect_uri\":\n oauth2[option] = options[option];\n break;\n case \"state\":\n case \"tokens\":\n if (typeof options[option].set == \"function\" && typeof options[option].get == \"function\" && typeof options[option].has == \"function\") oauth2[option] = options[option];\n else if (option == \"tokens\" && typeof options.tokens == \"object\") for(let token in options.tokens)oauth2.tokens.set(token, options.tokens[token]);\n else throw $hkeot.metroError(\"metro/mw/oauth2: incorrect value for \" + option);\n break;\n case \"endpoints\":\n for(let endpoint in options.endpoints){\n if (endpoint != \"authorize\" && endpoint != \"token\") throw $hkeot.metroError('Unknown endpoint, choose one of \"authorize\" or \"token\"', endpoint);\n }\n Object.assign(oauth2.endpoints, options.endpoints);\n break;\n case \"callbacks\":\n for(let callback in options.callbacks){\n if (callback != \"authorize\") throw $hkeot.metroError('Unknown callback, choose one of \"authorize\"', callback);\n }\n Object.assign(oauth2.callbacks, options.callbacks);\n break;\n default:\n throw $hkeot.metroError(\"Unknown oauth2mw option \", option);\n }\n if (!oauth2.redirect_uri) oauth2.redirect_uri = typeof window !== \"undefined\" ? window.location?.href : \"\";\n if (oauth2.redirect_uri) oauth2.redirect_uri = $hkeot.url(oauth2.redirect_uri).with(\"?metroRedirect=true\");\n }\n return async function(req, next) {\n if (oauth2.force_authorization) return oauth2authorized(req, next);\n let res = await next(req);\n if (res.ok) return res;\n switch(res.status){\n case 400:\n case 401:\n return oauth2authorized(req, next);\n }\n return res;\n };\n async function oauth2authorized(req, next) {\n getTokensFromLocation();\n if (!oauth2.tokens.has(\"access_token\")) {\n let token = await fetchToken(req);\n if (!token) return $hkeot.response(\"false\");\n return oauth2authorized(req, next);\n } else if (isExpired(req)) {\n let token = await refreshToken(req);\n if (!token) return $hkeot.response(\"false\");\n return oauth2authorized(req, next);\n } else {\n let accessToken = oauth2.tokens.get(\"access_token\");\n req = $hkeot.request(req, {\n headers: {\n Authorization: accessToken.type + \" \" + accessToken.value\n }\n });\n return next(req);\n }\n }\n function getTokensFromLocation() {\n // check if window.location is available and contains tokens\n if (typeof window !== \"undefined\" && window?.location) {\n let url = $hkeot.url(window.location);\n let code, state, params;\n if (url.searchParams.has(\"code\")) {\n params = url.searchParams;\n url = url.with({\n search: \"\"\n });\n history.pushState({}, \"\", url.href);\n } else if (url.hash) {\n let query = url.hash.substr(1);\n params = new URLSearchParams(\"?\" + query);\n url = url.with({\n hash: \"\"\n });\n history.pushState({}, \"\", url.href);\n }\n if (params) {\n code = params.get(\"code\");\n state = params.get(\"state\");\n let storedState = oauth2.state.get(\"metro/state\");\n if (!state || state !== storedState) return;\n if (code) oauth2.tokens.set(\"authorization_code\", code);\n }\n }\n }\n async function fetchToken(req) {\n if (oauth2.grant_type === \"authorization_code\" && !oauth2.tokens.has(\"authorization_code\")) {\n let authReqURL = getAuthTokenURL();\n if (!oauth2.callbacks.authorize || typeof oauth2.callbacks.authorize !== \"function\") throw $hkeot.metroError(\"oauth2mw: oauth2 with grant_type:authorization_code requires a callback function in client options.oauth2.callbacks.authorize\");\n let token = await oauth2.callbacks.authorize(authReqURL);\n if (token) oauth2.tokens.set(\"authorization_code\", token);\n else return $hkeot.response(false);\n }\n let tokenReq = getAccessTokenRequest();\n let response = await oauth2.client.get(tokenReq);\n if (!response.ok) throw $hkeot.metroError(response.status + \":\" + response.statusText, await response.text());\n let data = await response.json();\n oauth2.tokens.set(\"access_token\", {\n value: data.access_token,\n expires: getExpires(data.expires_in),\n type: data.token_type,\n scope: data.scope\n });\n if (data.refresh_token) oauth2.tokens.set(\"refresh_token\", data.refresh_token);\n return data;\n }\n async function refreshToken(req, next) {\n let refreshTokenReq = getAccessTokenRequest(\"refresh_token\");\n let response = await oauth2.client.get(refreshTokenReq);\n if (!response.ok) throw $hkeot.metroError(response.status + \":\" + response.statusText, await response.text());\n let data = await response.json();\n oauth2.tokens.set(\"access_token\", {\n value: data.access_token,\n expires: getExpires(data.expires_in),\n type: data.token_type,\n scope: data.scope\n });\n if (data.refresh_token) oauth2.tokens.set(\"refresh_token\", data.refresh_token);\n return data;\n }\n function getAuthTokenURL() {\n if (!oauth2.endpoints.authorize) throw $hkeot.metroError(\"oauth2mw: Missing options.endpoints.authorize url\");\n let url = $hkeot.url(oauth2.endpoints.authorize, {\n hash: \"\"\n });\n $2ddd80d1adc2ea42$export$35dc45686fc2dbd7(oauth2, {\n client_id: /.+/,\n redirect_uri: /.+/,\n scope: /.*/\n });\n let search = {\n response_type: \"code\",\n client_id: oauth2.client_id,\n redirect_uri: oauth2.redirect_uri,\n state: createState(40)\n };\n if (oauth2.scope) search.scope = oauth2.scope;\n return $hkeot.url(url, {\n search: search\n });\n }\n function createState(length) {\n const validChars = \"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789\";\n let randomState = \"\";\n let counter = 0;\n while(counter < length){\n randomState += validChars.charAt(Math.floor(Math.random() * validChars.length));\n counter++;\n }\n oauth2.state.set(randomState);\n return randomState;\n }\n function getAccessTokenRequest(grant_type = null) {\n $2ddd80d1adc2ea42$export$35dc45686fc2dbd7(oauth2, {\n client_id: /.+/,\n client_secret: /.+/,\n redirect_uri: /.+/\n });\n if (!oauth2.endpoints.token) throw $hkeot.metroError(\"oauth2mw: Missing options.endpoints.token url\");\n let url = $hkeot.url(oauth2.endpoints.token, {\n hash: \"\"\n });\n let params = {\n grant_type: grant_type || oauth2.grant_type,\n client_id: oauth2.client_id,\n client_secret: oauth2.client_secret\n };\n if (oauth2.scope) params.scope = oauth2.scope;\n switch(oauth2.grant_type){\n case \"authorization_code\":\n params.redirect_uri = oauth2.redirect_uri;\n params.code = oauth2.tokens.get(\"authorization_code\");\n break;\n case \"client_credentials\":\n throw new Error(\"Not yet implemented\") // @TODO:\n ;\n case \"refresh_token\":\n throw new Error(\"Not yet implemented\") // @TODO:\n ;\n }\n return $hkeot.request(url, {\n method: \"GET\",\n url: {\n searchParams: params\n }\n });\n }\n function isExpired(req) {\n if (req.oauth2 && req.oauth2.tokens && req.oauth2.tokens.has(\"access_token\")) {\n let now = new Date();\n let token = req.oauth2.tokens.get(\"access_token\");\n return now.getTime() > token.expires.getTime();\n }\n return false;\n }\n function getExpires(duration) {\n if (duration instanceof Date) return new Date(duration.getTime()); // return a copy\n if (typeof duration === \"number\") {\n let date = new Date();\n date.setSeconds(date.getSeconds() + duration);\n return date;\n }\n throw new TypeError(\"Unknown expires type \" + duration);\n }\n}\n\n\nwindow.metro = $hkeot;\nwindow.assert = $2ddd80d1adc2ea42$exports;\nwindow.metro.mw = {\n jsonmw: $9cea4e31d030ec91$export$2e2bcd8739ae039,\n oauth2: $94580a8710b2e8f9$export$2e2bcd8739ae039\n};\n\n\n//# sourceMappingURL=everything.js.map\n","const metroURL = 'https://metro.muze.nl/details/'\n\nexport const symbols = {\n\tisProxy: Symbol('isProxy'),\n\tsource: Symbol('source')\n}\n\nclass Client {\n\t#options = {\n\t\turl: typeof window != 'undefined' ? window.location : 'https://localhost'\n\t}\n\t#verbs = ['get','post','put','delete','patch','head','options','query']\n\n\tstatic tracers = {}\n\n\tconstructor(...options) {\n\t\tfor (let option of options) {\n\t\t\tif (typeof option == 'string' || option instanceof String) {\n\t\t\t\tthis.#options.url = ''+option\n\t\t\t} else if (option instanceof Client) {\n\t\t\t\tObject.assign(this.#options, option.#options)\n\t\t\t} else if (option instanceof Function) {\n\t\t\t\tthis.#addMiddlewares([option])\n\t\t\t} else if (option && typeof option == 'object') {\n\t\t\t\tfor (let param in option) {\n\t\t\t\t\tif (param == 'middlewares') {\n\t\t\t\t\t\tthis.#addMiddlewares(option[param])\n\t\t\t\t\t} else if (typeof option[param] == 'function') {\n\t\t\t\t\t\tthis.#options[param] = option[param](this.#options[param], this.#options)\n\t\t\t\t\t} else {\n\t\t\t\t\t\tthis.#options[param] = option[param]\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tif (this.#options.verbs) {\n\t\t\tthis.#verbs = this.#options.verbs\n\t\t\tdelete this.#options.verbs\n\t\t}\n\n\t\tfor (const verb of this.#verbs) {\n\t\t\tthis[verb] = async function(...options) {\n\t\t\t\treturn this.#fetch(request(\n\t\t\t\t\tthis.#options,\n\t\t\t\t\t...options,\n\t\t\t\t\t{method: verb.toUpperCase()}\n\t\t\t\t))\n\t\t\t}\n\t\t}\n\t\tObject.freeze(this)\n\t}\n\n\t#addMiddlewares(middlewares) {\n\t\tif (typeof middlewares == 'function') {\n\t\t\tmiddlewares = [ middlewares ]\n\t\t}\n\t\tlet index = middlewares.findIndex(m => typeof m != 'function')\n\t\tif (index>=0) {\n\t\t\tthrow metroError('metro.client: middlewares must be a function or an array of functions '\n\t\t\t\t+metroURL+'client/invalid-middlewares-value/', middlewares[index])\n\t\t}\n\t\tif (!Array.isArray(this.#options.middlewares)) {\n\t\t\tthis.#options.middlewares = []\n\t\t}\n\t\tthis.#options.middlewares = this.#options.middlewares.concat(middlewares)\n\t}\n\n\t#fetch(req) {\n\t\tif (!req.url) {\n\t\t\tthrow metroError('metro.client.'+r.method.toLowerCase()+': Missing url parameter '+metroURL+'client/missing-url-param/', req)\n\t\t}\n\t\tlet metrofetch = async (req) => {\n\t\t\tif (req[symbols.isProxy]) {\n\t\t\t\t// even though a Proxy is supposed to be 'invisible'\n\t\t\t\t// fetch() doesn't work with the proxy (in Firefox), \n\t\t\t\t// you need the actual Request object here\n\t\t\t\treq = req[symbols.source]\n\t\t\t}\n\t\t\treturn response(await fetch(req))\n\t\t}\n\t\tlet middlewares = [metrofetch].concat(this.#options?.middlewares?.slice() || [])\n\t\tlet options = this.#options\n\t\t//@TODO: do this once in constructor?\n\t\tlet next\n\t\tfor (let middleware of middlewares) {\n\t\t\tnext = (function(next, middleware) {\n\t\t\t\treturn async function(req) {\n\t\t\t\t\tlet res\n\t\t\t\t\tlet tracers = Object.values(Client.tracers)\n\t\t\t\t\tfor(let tracer of tracers) {\n\t\t\t\t\t\tif (tracer.request) {\n\t\t\t\t\t\t\ttracer.request.call(tracer, req)\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tres = await middleware(req, next)\n\t\t\t\t\tfor(let tracer of tracers) {\n\t\t\t\t\t\tif (tracer.response) {\n\t\t\t\t\t\t\ttracer.response.call(tracer, res)\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\treturn res\n\t\t\t\t}\t\t\t\t\t\t\t\t\n\t\t\t})(next, middleware)\n\t\t}\n\t\treturn next(req)\n\t}\n\n\twith(...options) {\n\t\treturn new Client(this, ...options)\n\t}\n}\n\nexport function client(...options) {\n\treturn new Client(...options)\n}\n\nfunction appendHeaders(r, headers) {\n\tif (!Array.isArray(headers)) {\n\t\theaders = [headers]\n\t}\n\theaders.forEach((header) => {\n\t\tif (typeof header == 'function') {\n\t\t\tlet result = header(r.headers, r)\n\t\t\tif (result) {\n\t\t\t\tif (!Array.isArray(result)) {\n\t\t\t\t\tresult = [result]\n\t\t\t\t}\n\t\t\t\theaders = headers.concat(result)\n\t\t\t}\n\t\t}\n\t})\n\theaders.forEach((header) => {\n\t\tObject.entries(header).forEach(([name,value]) => {\t\t\t\n\t\t\tr.headers.append(name, value)\n\t\t})\n\t})\n}\n\nfunction bodyProxy(body, r) {\n\tlet source = r.body\n\tif (!source) {\n\t\t//Firefox does not allow access to Request.body (undefined)\n\t\t//Chrome and Nodejs do, so mimic the correct (documented)\n\t\t//result here\n\t\tif (body === null) {\n\t\t\tsource = new ReadableStream()\n\t\t} else if (body instanceof ReadableStream) {\n\t\t\tsource = body\n\t\t} else if (body instanceof Blob) {\n\t\t\tsource = body.stream()\n\t\t} else {\n\t\t\tsource = new ReadableStream({\n\t\t\t\tstart(controller) {\n\t\t\t\t\tlet chunk\n\t\t\t\t\tswitch(typeof body) {\n\t\t\t\t\t\tcase 'object':\n\t\t\t\t\t\t\tif (typeof body.toString == 'function') {\n\t\t\t\t\t\t\t\t// also catches URLSearchParams\n\t\t\t\t\t\t\t\tchunk = body.toString()\n\t\t\t\t\t\t\t} else if (body instanceof FormData) {\n\t\t\t\t\t\t\t\tchunk = new URLSearchParams(body).toString()\n\t\t\t\t\t\t\t} else if (body instanceof ArrayBuffer\n\t\t\t\t\t\t\t\t|| ArrayBuffer.isView(body)\n\t\t\t\t\t\t\t) {\n\t\t\t\t\t\t\t\t// catchs TypedArrays - e.g. Uint16Array\n\t\t\t\t\t\t\t\tchunk = body\n\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\tthrow metroError('Cannot convert body to ReadableStream', body)\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\tbreak\n\t\t\t\t\t\tcase 'string':\n\t\t\t\t\t\tcase 'number':\n\t\t\t\t\t\tcase 'boolean':\n\t\t\t\t\t\t\tchunk = body\n\t\t\t\t\t\tbreak\n\t\t\t\t\t\tdefault:\n\t\t\t\t\t\t\tthrow metroError('Cannot convert body to ReadableStream', body)\n\t\t\t\t\t\tbreak\n\t\t\t\t\t}\n\t\t\t\t\tcontroller.enqueue(chunk)\n\t\t\t\t\tcontroller.close()\n\t\t\t\t}\n\t\t\t})\n\t\t}\n\t}\n\treturn new Proxy(source, {\n\t\tget(target, prop, receiver) {\n\t\t\tswitch (prop) {\n\t\t\t\tcase symbols.isProxy:\n\t\t\t\t\treturn true\n\t\t\t\tbreak\n\t\t\t\tcase symbols.source:\n\t\t\t\t\treturn body\n\t\t\t\tbreak\n\t\t\t\tcase 'toString':\n\t\t\t\t\treturn function() {\n\t\t\t\t\t\treturn ''+body\n\t\t\t\t\t}\n\t\t\t\tbreak\n\t\t\t}\n\t\t\tif (typeof body == 'object') {\n\t\t\t\tif (prop in body) {\n\t\t\t\t\tif (typeof body[prop] == 'function') {\n\t\t\t\t\t\treturn function(...args) {\n\t\t\t\t\t\t\treturn body[prop].apply(body, args)\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\treturn body[prop]\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (prop in target && prop != 'toString') {\n\t\t\t\t// skipped toString, since it has no usable output\n\t\t\t\t// and body may have its own toString\n\t\t\t\tif (typeof target[prop] == 'function') {\n\t\t\t\t\treturn function(...args) {\n\t\t\t\t\t\treturn target[prop].apply(target, args)\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\treturn target[prop]\n\t\t\t}\n\t\t},\n\t\thas(target, prop) {\n\t\t\treturn prop in body\n\t\t},\n\t\townKeys(target) {\n\t\t\treturn Reflect.ownKeys(body)\n\t\t},\n\t\tgetOwnPropertyDescriptor(target, prop) {\n\t\t\treturn Object.getOwnPropertyDescriptor(body,prop)\n\t\t}\n\t})\n}\n\nfunction getRequestParams(req, current) {\n\tlet params = current || {}\n\tif (!params.url && current.url) {\n\t\tparams.url = current.url\n\t}\n\t// function to fetch all relevant properties of a Request\n\tfor(let prop of ['method','headers','body','mode','credentials','cache','redirect',\n\t\t'referrer','referrerPolicy','integrity','keepalive','signal',\n\t\t'priority','url']) {\n\t\tif (typeof req[prop] == 'function') {\n\t\t\treq[prop](params[prop], params)\n\t\t} else if (typeof req[prop] != 'undefined') {\n\t\t\tif (prop == 'url') {\n\t\t\t\tparams.url = url(params.url, req.url)\n\t\t\t} else {\n\t\t\t\tparams[prop] = req[prop]\n\t\t\t}\n\t\t}\n\t}\n\treturn params\n}\n\nexport function request(...options) {\n\t// the standard Request constructor is a minefield\n\t// so first gather all the options together into a single\n\t// javascript object, then set it in one go\n\tlet requestParams = {\n\t\turl: typeof window != 'undefined' ? window.location : 'https://localhost/',\n\t\tduplex: 'half' // required when setting body to ReadableStream, just set it here by default already\n\t}\n\tfor (let option of options) {\n\t\tif (typeof option == 'string'\n\t\t\t|| option instanceof URL\n\t\t\t|| option instanceof URLSearchParams\n\t\t) {\n\t\t\trequestParams.url = url(requestParams.url, option)\n\t\t} else if (option && typeof option == 'object') {\n\t\t\tObject.assign(requestParams, getRequestParams(option, requestParams))\n\t\t}\n\t}\n\tlet body = requestParams.body\n\tif (body) {\n\t\tif (typeof body == 'object'\n\t\t\t&& !(body instanceof String)\n\t\t\t&& !(body instanceof ReadableStream)\n\t\t\t&& !(body instanceof Blob)\n\t\t\t&& !(body instanceof ArrayBuffer)\n\t\t\t&& !(body instanceof DataView)\n\t\t\t&& !(body instanceof FormData)\n\t\t\t&& !(body instanceof URLSearchParams)\n\t\t\t&& (typeof TypedArray=='undefined' || !(body instanceof TypedArray))\n\t\t) {\n\t\t\trequestParams.body = JSON.stringify(body)\n\t\t}\n\t}\n\tlet r = new Request(requestParams.url, requestParams)\n\tObject.freeze(r)\n\treturn new Proxy(r, {\n\t\tget(target, prop, receiver) {\n\t\t\tswitch(prop) {\n\t\t\t\tcase symbols.source:\n\t\t\t\t\treturn target\n\t\t\t\tbreak\n\t\t\t\tcase symbols.isProxy:\n\t\t\t\t\treturn true\n\t\t\t\tbreak\n\t\t\t\tcase 'with':\n\t\t\t\t\treturn function(...options) {\n\t\t\t\t\t\treturn request(target, ...options)\n\t\t\t\t\t}\n\t\t\t\tbreak\n\t\t\t\tcase 'toString':\n\t\t\t\tcase 'toJSON':\n\t\t\t\t\treturn function() {\n\t\t\t\t\t\treturn target[prop].apply(target)\n\t\t\t\t\t}\n\t\t\t\tbreak\n\t\t\t\tcase 'blob':\n\t\t\t\tcase 'text':\n\t\t\t\tcase 'json':\n\t\t\t\t\treturn function() {\n\t\t\t\t\t\treturn target[prop].apply(target)\n\t\t\t\t\t}\n\t\t\t\tbreak\n\t\t\t\tcase 'body':\n\t\t\t\t\t// Request.body is always a ReadableStream\n\t\t\t\t\t// which is a horrible API, if you want to\n\t\t\t\t\t// allow middleware to alter the body\n\t\t\t\t\t// so we keep the original body, wrap a Proxy\n\t\t\t\t\t// around it to keep the ReadableStream api\n\t\t\t\t\t// accessible, but allow access to the original\n\t\t\t\t\t// body value as well\n\t\t\t\t\tif (!body) {\n\t\t\t\t\t\tbody = target.body\n\t\t\t\t\t}\n\t\t\t\t\tif (body) {\n\t\t\t\t\t\tif (body[symbols.isProxy]) {\n\t\t\t\t\t\t\treturn body\n\t\t\t\t\t\t}\n\t\t\t\t\t\treturn bodyProxy(body, target)\n\t\t\t\t\t}\n\t\t\t\tbreak\n\t\t\t}\n\t\t\treturn target[prop]\n\t\t}\n\t})\n}\n\nfunction getResponseParams(res, current) {\n\t// function to fetch all relevant properties of a Response\n\tlet params = current || {}\n\tif (!params.url && current.url) {\n\t\tparams.url = current.url\n\t}\n\tfor(let prop of ['status','statusText','headers','body','url','type','redirected']) {\n\t\tif (typeof res[prop] == 'function') {\n\t\t\tres[prop](params[prop], params)\n\t\t} else if (typeof res[prop] != 'undefined') {\n\t\t\tif (prop == 'url') {\n\t\t\t\tparams.url = new URL(res.url, params.url || 'https://localhost/')\n\t\t\t} else {\n\t\t\t\tparams[prop] = res[prop]\n\t\t\t}\n\t\t}\n\t}\n\treturn params\n}\n\nexport function response(...options) {\n\tlet responseParams = {}\n\tfor (let option of options) {\n\t\tif (typeof option == 'string') {\n\t\t\tresponseParams.body = option\n\t\t} else if (option instanceof Response) {\n\t\t\tObject.assign(responseParams, getResponseParams(option, responseParams))\n\t\t} else if (option && typeof option == 'object') {\n\t\t\tif (option instanceof FormData\n\t\t\t\t|| option instanceof Blob\n\t\t\t\t|| option instanceof ArrayBuffer\n\t\t\t\t|| option instanceof DataView\n\t\t\t\t|| option instanceof ReadableStream\n\t\t\t\t|| option instanceof URLSearchParams\n\t\t\t\t|| option instanceof String\n\t\t\t\t|| (typeof TypedArray != 'undefined' && option instanceof TypedArray)\n\t\t\t) {\n\t\t\t\tresponseParams.body = option\n\t\t\t} else {\n\t\t\t\tObject.assign(responseParams, getResponseParams(option, responseParams))\n\t\t\t}\n\t\t}\n\t}\n\tlet r = new Response(responseParams.body, responseParams)\t\n\tObject.freeze(r)\n\treturn new Proxy(r, {\n\t\tget(target, prop, receiver) {\n\t\t\tswitch(prop) {\n\t\t\t\tcase symbols.isProxy:\n\t\t\t\t\treturn true\n\t\t\t\tbreak\n\t\t\t\tcase symbols.source:\n\t\t\t\t\treturn target\n\t\t\t\tbreak\n\t\t\t\tcase 'with':\n\t\t\t\t\treturn function(...options) {\n\t\t\t\t\t\treturn response(target, ...options)\n\t\t\t\t\t}\n\t\t\t\tbreak\n\t\t\t\tcase 'body':\n\t\t\t\t\tif (responseParams.body) {\n\t\t\t\t\t\tif (responseParams.body[symbols.isProxy]) {\n\t\t\t\t\t\t\treturn responseParams.body\n\t\t\t\t\t\t}\n\t\t\t\t\t\treturn bodyProxy(responseParams.body, target)\n\t\t\t\t\t} else {\n\t\t\t\t\t\treturn bodyProxy('',target)\n\t\t\t\t\t}\n\t\t\t\tbreak\n\t\t\t\tcase 'ok':\n\t\t\t\t\treturn (target.status>=200) && (target.status<400)\n\t\t\t\tbreak\n\t\t\t\tcase 'headers':\n\t\t\t\t\treturn target.headers\n\t\t\t\tbreak\n\t\t\t\tdefault:\n\t\t\t\t\tif (prop in responseParams && prop != 'toString') {\n\t\t\t\t\t\treturn responseParams[prop]\n\t\t\t\t\t}\n\t\t\t\t\tif (prop in target && prop != 'toString') {\n\t\t\t\t\t\t// skipped toString, since it has no usable output\n\t\t\t\t\t\t// and body may have its own toString\n\t\t\t\t\t\tif (typeof target[prop] == 'function') {\n\t\t\t\t\t\t\treturn function(...args) {\n\t\t\t\t\t\t\t\treturn target[prop].apply(target, args)\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\treturn target[prop]\n\t\t\t\t\t}\n\t\t\t\tbreak\n\t\t\t}\n\t\t\treturn undefined\n\t\t}\n\t})\n}\n\nfunction appendSearchParams(url, params) {\n\tif (typeof params == 'function') {\n\t\t params(url.searchParams, url)\n\t} else {\n\t\tparams = new URLSearchParams(params)\n\t\tparams.forEach((value,key) => {\n\t\t\turl.searchParams.append(key, value)\n\t\t})\n\t}\n}\n\nexport function url(...options) {\n\tlet validParams = ['hash','host','hostname','href',\n\t\t\t'password','pathname','port','protocol','username','search','searchParams']\n\tlet u = new URL('https://localhost/')\n\tfor (let option of options) {\n\t\tif (typeof option == 'string' || option instanceof String) {\n\t\t\t// option is a relative or absolute url\n\t\t\tu = new URL(option, u)\n\t\t} else if (option instanceof URL \n\t\t\t|| (typeof Location != 'undefined' \n\t\t\t\t&& option instanceof Location)\n\t\t) {\n\t\t\tu = new URL(option)\n\t\t} else if (option instanceof URLSearchParams) {\n\t\t\tappendSearchParams(u, option)\n\t\t} else if (option && typeof option == 'object') {\n\t\t\tfor (let param in option) {\n\t\t\t\tif (param=='search') {\n\t\t\t\t\tif (typeof option.search == 'function') {\n\t\t\t\t\t\toption.search(u.search, u)\n\t\t\t\t\t} else {\n\t\t\t\t\t\tu.search = new URLSearchParams(option.search)\n\t\t\t\t\t}\n\t\t\t\t} else if (param=='searchParams') {\n\t\t\t\t\tappendSearchParams(u, option.searchParams)\n\t\t\t\t} else {\n\t\t\t\t\tif (!validParams.includes(param)) {\n\t\t\t\t\t\tthrow metroError('metro.url: unknown url parameter '+metroURL+'url/unknown-param-name/', param)\n\t\t\t\t\t}\n\t\t\t\t\tif (typeof option[param] == 'function') {\n\t\t\t\t\t\toption[param](u[param], u)\n\t\t\t\t\t} else if (\n\t\t\t\t\t\ttypeof option[param] == 'string' || option[param] instanceof String \n\t\t\t\t\t\t|| typeof option[param] == 'number' || option[param] instanceof Number\n\t\t\t\t\t\t|| typeof option[param] == 'boolean' || option[param] instanceof Boolean\n\t\t\t\t\t) {\n\t\t\t\t\t\tu[param] = ''+option[param]\n\t\t\t\t\t} else if (typeof option[param] == 'object' && option[param].toString) {\n\t\t\t\t\t\tu[param] = option[param].toString()\n\t\t\t\t\t} else {\n\t\t\t\t\t\tthrow metroError('metro.url: unsupported value for '+param+' '+metroURL+'url/unsupported-param-value/', options[param])\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t} else {\n\t\t\tthrow metroError('metro.url: unsupported option value '+metroURL+'url/unsupported-option-value/', option)\n\t\t}\n\t}\n\tObject.freeze(u)\n\treturn new Proxy(u, {\n\t\tget(target, prop, receiver) {\n\t\t\tswitch(prop) {\n\t\t\t\tcase symbols.isProxy:\n\t\t\t\t\treturn true\n\t\t\t\tbreak\n\t\t\t\tcase symbols.source:\n\t\t\t\t\treturn target\n\t\t\t\tbreak\n\t\t\t\tcase 'with':\n\t\t\t\t\treturn function(...options) {\n\t\t\t\t\t\treturn url(target, ...options)\n\t\t\t\t\t}\n\t\t\t\tbreak\n\t\t\t\tcase 'toString':\n\t\t\t\tcase 'toJSON':\n\t\t\t\t\treturn function() {\n\t\t\t\t\t\treturn target[prop]()\n\t\t\t\t\t}\n\t\t\t\tbreak\n\t\t\t}\n\t\t\treturn target[prop]\n\t\t}\n\t})\n}\n\nexport function formdata(...options) {\n\tvar params = new FormData()\n\tfor (let option of options) {\n\t\tif (option instanceof FormData) {\n\t\t\tfor (let entry of option.entries()) {\n\t\t\t\tparams.append(entry[0],entry[1])\n\t\t\t}\n\t\t} else if (option && typeof option == 'object') {\n\t\t\tfor (let entry of Object.entries(option)) {\n\t\t\t\tif (Array.isArray(entry[1])) {\n\t\t\t\t\tfor (let value of entry[1]) {\n\t\t\t\t\t\tparams.append(entry[0], value)\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\tparams.append(entry[0],entry[1])\n\t\t\t\t}\n\t\t\t}\n\t\t} else {\n\t\t\tthrow new metroError('metro.formdata: unknown option type, only FormData or Object supported',option)\n\t\t}\n\t}\n\tObject.freeze(params)\n\treturn new Proxy(params, {\n\t\tget: (target,prop,receiver) => {\n\t\t\tswitch(prop) {\n\t\t\t\tcase symbols.isProxy:\n\t\t\t\t\treturn true\n\t\t\t\tbreak\n\t\t\t\tcase symbols.source:\n\t\t\t\t\treturn target\n\t\t\t\tbreak\n\t\t\t\tcase 'with':\n\t\t\t\t\treturn function(...options) {\n\t\t\t\t\t\treturn formdata(target, ...options)\n\t\t\t\t\t}\n\t\t\t\tbreak\n\t\t\t\tcase 'toString':\n\t\t\t\tcase 'toJSON':\n\t\t\t\t\treturn function() {\n\t\t\t\t\t\treturn target[prop]()\n\t\t\t\t\t}\n\t\t\t\tbreak\n\t\t\t}\n\t\t\treturn target[prop]\n\t\t}\n\t})\n}\n\nconst metroConsole = {\n\terror: (message, ...details) => {\n\t\tconsole.error('Ⓜ️ ',message, ...details)\n\t},\n\tinfo: (message, ...details) => {\n\t\tconsole.info('Ⓜ️ ',message, ...details)\n\t},\n\tgroup: (name) => {\n\t\tconsole.group('Ⓜ️ '+name)\n\t},\n\tgroupEnd: (name) => {\n\t\tconsole.groupEnd('Ⓜ️ '+name)\n\t}\n}\n\nexport function metroError(message, ...details) {\n\tmetroConsole.error(message, ...details)\n\treturn new Error(message, ...details)\n}\n\n\nexport const trace = {\n\tadd(name, tracer) {\n\t\tClient.tracers[name] = tracer\n\t},\n\tdelete(name) {\n\t\tdelete Client.tracers[name]\n\t},\n\tclear() {\n\t\tClient.tracers = {}\n\t},\n\tgroup() {\n\t\tlet group = 0;\n\t\treturn {\n\t\t\trequest: (req) => {\n\t\t\t\tgroup++\n\t\t\t\tmetroConsole.group(group)\n\t\t\t\tmetroConsole.info(req?.url, req)\n\t\t\t},\n\t\t\tresponse: (res) => {\n\t\t\t\tmetroConsole.info(res?.body ? res.body[symbols.source]: null, res)\n\t\t\t\tmetroConsole.groupEnd(group)\n\t\t\t\tgroup--\n\t\t\t}\n\t\t}\n\t}\n}\n","import * as metro from './metro.mjs'\nimport * as assert from './assert.mjs'\nimport jsonmw from './mw/json.mjs'\nimport oauth2 from './mw/oauth2.mjs'\n\nwindow.metro = metro\nwindow.assert = assert\nwindow.metro.mw = {\n\tjsonmw,\n\toauth2\n}","let enabled = false\n\nexport function enable() {\n\tenabled = true\n}\n\nexport function disable() {\n\tenabled = false\n}\n\n/**\n * returns new Boolean(true) if data does not match pattern\n * you can't return new Boolean(false), or at least that evaluates\n * to true, so if the data does match, it returns a primitive false\n * the Boolean(true) has an extra property called 'problems', which is\n * an array with a list of all fields that do not match, and why\n * @param {any} data The data to match\n * @param {any} pattern The pattern to match\n * @return {Array|false} Array with problems if the pattern fails, false\n */\nexport function fails(data, pattern) {\n\tlet problems = []\n\tif (pattern instanceof RegExp) {\n \tif (Array.isArray(data)) {\n\t\t\tlet index = data.findIndex(element => fails(element,pattern))\n if (index>-1) {\n \tproblems.push('data['+index+'] does not match pattern')\n }\n \t} else if (!pattern.test(data)) {\n \tproblems.push('data does not match pattern '+pattern)\n }\n } else if (pattern instanceof Function) {\n if (pattern(data)) {\n \tproblems.push('data does not match function')\n }\n } else if (pattern && typeof pattern == 'object') {\n if (Array.isArray(data)) {\n let index = data.findIndex(element => fails(element,pattern))\n if (index>-1) {\n \tproblems.push('data['+index+'] does not match pattern')\n }\n } else if (!data || typeof data != 'object') {\n \tproblems.push('data is not an object, pattern is')\n } else {\n \tif (data instanceof URLSearchParams) {\n \t\tdata = Object.fromEntries(data)\n \t}\n\t let p = problems[problems.length-1]\n\t for (const [wKey, wVal] of Object.entries(pattern)) {\n\t let result = fails(data[wKey], wVal)\n\t if (result) {\n\t \tif (!p || typeof p == 'string') {\n\t \t\tp = {}\n\t \t\tproblems.push(p)\n\t \t}\n\t \tp[wKey] = result.problems\n\t }\n\t }\n\t }\n } else {\n \tif (pattern!=data) {\n \t\tproblems.push('data does not equal '+pattern)\n \t}\n }\n if (problems.length) {\n \treturn problems\n }\n return false\n}\n\nexport function check(source, test) {\n\tif (!enabled) {\n\t\treturn\n\t}\n\tlet result = fails(source,test)\n\tif (result) {\n\t\tthrow new assertError(result,source)\n\t}\n}\n\nexport function optional(pattern) {\n\treturn function(data) {\n\t\tif (data==null || typeof data == 'undefined') {\n\t\t\treturn false\n\t\t}\n\t\treturn fails(data, pattern)\n\t}\n}\n\nexport function oneOf(...patterns) {\n\treturn function(data) {\n\t\tfor(let pattern of patterns) {\n\t\t\tif (!fails(data, pattern)) {\n\t\t\t\treturn false\n\t\t\t}\n\t\t}\n\t\treturn ['data does not match oneOf patterns']\n\t}\n}\n\nclass assertError {\n\tconstructor(problems, ...details) {\n\t\tthis.problems = problems\n\t\tthis.details = details\n\t\tconsole.trace()\n\t}\n\n}\n\n","import * as metro from '../metro.mjs'\n\nexport default function jsonmw(options) {\n\toptions = Object.assign({\n\t\treviver: null,\n\t\treplacer: null,\n\t\tspace: ''\n\t}, options)\n\n\treturn async (req, next) => {\n\t\tif (['POST','PUT','PATCH','QUERY'].includes(req.method)) {\n\t\t\treq = req.with({\n\t\t\t\theaders: {\n\t\t\t\t\t'Content-Type':'application/json',\n\t 'Accept':'application/json'\n\t\t\t\t}\n\t\t\t})\n\t\t\tif (req.body && typeof req.body[metro.symbols.source] == 'object') {\n\t\t\t\treq = req.with({\n\t\t\t\t\tbody: JSON.stringify(req.body[metro.symbols.source], options.replacer, options.space)\n\t\t\t\t})\n\t\t\t}\n\t\t} else {\n\t\t\treq = req.with({\n\t\t\t\theaders: {\n\t\t\t 'Accept':'application/json'\n\t\t\t\t}\n\t\t\t})\n\t\t}\n\t\tlet res = await next(req)\n\t\tlet body = await res.text()\n\t\tlet json = JSON.parse(body, options.reviver)\n\t\treturn res.with({\n\t\t\tbody: json\n\t\t})\n\t}\n}","import * as metro from '../metro.mjs'\nimport * as assert from '../assert.mjs'\nimport jsonmw from './json.mjs'\n\nexport default function oauth2mw(options) {\n\n\tlet localState\n\tif (typeof localStorage !== 'undefined') {\n\t\tlocalState = {\n\t\t\tget: () => localStorage.getItem('metro/state'),\n\t\t\thas: () => localStorage.getItem('metro/state'),\n\t\t\tset: (value) => localStorage.setItem('metro/state', value)\n\t\t}\n\t} else {\n\t\tlet stateMap = new Map()\n\t\tlocalState = {\n\t\t\tget: () => stateMap.get('metro/state'),\n\t\t\thas: () => stateMap.get('metro/state'),\n\t\t\tset: (value) => stateMap.set('metro/state', value)\n\t\t}\n\t}\n\n\tconst oauth2 = {\n\t\ttokens: new Map(),\n\t\tstate: localState,\n\t\tendpoints: {},\n\t\tcallbacks: {},\n\t\tclient: metro.client().with(jsonmw()),\n\t\tclient_id: '',\n\t\tclient_secret: '',\n\t\tredirect_uri: '',\n\t\tgrant_type: 'authorization_code',\n\t\tforce_authorization: false\n\t}\n\n\tfor (let option in options) {\n\t\tswitch(option) {\n\t\t\tcase 'access_token':\n\t\t\tcase 'authorization_code':\n\t\t\tcase 'refresh_token':\n\t\t\t\toauth2.tokens.set(option, options[option])\n\t\t\tbreak\n\n\t\t\tcase 'client':\n\t\t\tcase 'client_id':\n\t\t\tcase 'client_secret':\n\t\t\tcase 'grant_type':\n\t\t\tcase 'force_authorization':\n\t\t\tcase 'redirect_uri':\n\t\t\t\toauth2[option] = options[option]\n\t\t\tbreak\n\t\t\tcase 'state':\n\t\t\tcase 'tokens':\n\t\t\t\tif (typeof options[option].set == 'function' && \n\t\t\t\t\ttypeof options[option].get == 'function' && \n\t\t\t\t\ttypeof options[option].has == 'function' ) {\n\t\t\t\t\toauth2[option] = options[option]\n\t\t\t\t} else if (option == 'tokens' && typeof options.tokens == 'object') {\n\t\t\t\t\tfor (let token in options.tokens) {\n\t\t\t\t\t\toauth2.tokens.set(token, options.tokens[token])\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\tthrow metro.metroError('metro/mw/oauth2: incorrect value for '+option)\n\t\t\t\t}\n\t\t\tbreak\n\t\t\tcase 'endpoints':\n\t\t\t\tfor (let endpoint in options.endpoints) {\n\t\t\t\t\tif (endpoint!='authorize' && endpoint!='token') {\n\t\t\t\t\t\tthrow metro.metroError('Unknown endpoint, choose one of \"authorize\" or \"token\"',endpoint)\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tObject.assign(oauth2.endpoints, options.endpoints)\n\t\t\tbreak\n\t\t\tcase 'callbacks':\n\t\t\t\tfor (let callback in options.callbacks) {\n\t\t\t\t\tif (callback != 'authorize') {\n\t\t\t\t\t\tthrow metro.metroError('Unknown callback, choose one of \"authorize\"',callback)\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tObject.assign(oauth2.callbacks, options.callbacks)\n\t\t\tbreak\n\t\t\tdefault:\n\t\t\t\tthrow metro.metroError('Unknown oauth2mw option ',option)\n\t\t\tbreak\n\t\t}\n\t\tif (!oauth2.redirect_uri) {\n\t\t\toauth2.redirect_uri = typeof window !== 'undefined' ? window.location?.href : ''\n\t\t}\n\t\tif (oauth2.redirect_uri) {\n\t\t\toauth2.redirect_uri = metro.url(oauth2.redirect_uri).with('?metroRedirect=true')\n\t\t}\n\t}\n\n\treturn async function(req, next) {\n\t\tif (oauth2.force_authorization) {\n\t\t\treturn oauth2authorized(req, next)\n\t\t}\n\t\tlet res = await next(req)\n\t\tif (res.ok) {\n\t\t\treturn res\n\t\t}\n\t\tswitch(res.status) {\n\t\t\tcase 400:\n\t\t\tcase 401:\n\t\t\t\treturn oauth2authorized(req, next)\n\t\t\tbreak\n\t\t}\n\t\treturn res\n\t}\n\n\tasync function oauth2authorized(req, next) {\n\t\tgetTokensFromLocation()\n\t\tif (!oauth2.tokens.has('access_token')) {\n\t\t\tlet token = await fetchToken(req)\n\t\t\tif (!token) {\n\t\t\t\treturn metro.response('false')\n\t\t\t}\n\t\t\treturn oauth2authorized(req, next)\n\t\t} else if (isExpired(req)) {\n\t\t\tlet token = await refreshToken(req)\n\t\t\tif (!token) {\n\t\t\t\treturn metro.response('false')\n\t\t\t}\n\t\t\treturn oauth2authorized(req, next)\n\t\t} else {\n\t\t\tlet accessToken = oauth2.tokens.get('access_token')\n\t\t\treq = metro.request(req, {\n\t\t\t\theaders: {\n\t\t\t\t\tAuthorization: accessToken.type+' '+accessToken.value\n\t\t\t\t}\n\t\t\t})\n\t\t\treturn next(req)\n\t\t}\n\t}\n\n\tfunction getTokensFromLocation() {\n\t\t// check if window.location is available and contains tokens\n\t\tif (typeof window !== 'undefined' && window?.location) {\n\t\t\tlet url = metro.url(window.location)\n\t\t\tlet code, state, params\n\t\t\tif (url.searchParams.has('code')) {\n\t\t\t\tparams = url.searchParams\n\t\t\t\turl = url.with({ search:'' })\n\t\t\t\thistory.pushState({},'',url.href)\n\t\t\t} else if (url.hash) {\n\t\t\t\tlet query = url.hash.substr(1)\n\t\t\t\tparams = new URLSearchParams('?'+query)\n\t\t\t\turl = url.with({ hash:'' })\n\t\t\t\thistory.pushState({},'',url.href)\n\t\t\t}\n\t\t\tif (params) {\n\t\t\t\tcode = params.get('code')\n\t\t\t\tstate = params.get('state')\n\t\t\t\tlet storedState = oauth2.state.get('metro/state')\n\t\t\t\tif (!state || state!==storedState) {\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t\tif (code) {\n\t\t\t\t\toauth2.tokens.set('authorization_code', code)\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tasync function fetchToken(req) {\n\t\tif (oauth2.grant_type === 'authorization_code' && !oauth2.tokens.has('authorization_code')) {\n\t\t\tlet authReqURL = getAuthTokenURL()\n\t\t\tif (!oauth2.callbacks.authorize || typeof oauth2.callbacks.authorize !== 'function') {\n\t\t\t\tthrow metro.metroError('oauth2mw: oauth2 with grant_type:authorization_code requires a callback function in client options.oauth2.callbacks.authorize')\n\t\t\t}\n\t\t\tlet token = await oauth2.callbacks.authorize(authReqURL)\n\t\t\tif (token) {\n\t\t\t\toauth2.tokens.set('authorization_code', token)\n\t\t\t} else {\n\t\t\t\treturn metro.response(false)\n\t\t\t}\n\t\t}\n\t\tlet tokenReq = getAccessTokenRequest()\n\t\tlet response = await oauth2.client.get(tokenReq)\n\t\tif (!response.ok) {\n\t\t\tthrow metro.metroError(response.status+':'+response.statusText, await response.text())\n\t\t}\n\t\tlet data = await response.json()\n\t\toauth2.tokens.set('access_token', {\n\t\t\tvalue: data.access_token,\n\t\t\texpires: getExpires(data.expires_in),\n\t\t\ttype: data.token_type,\n\t\t\tscope: data.scope\n\t\t})\n\t\tif (data.refresh_token) {\n\t\t\toauth2.tokens.set('refresh_token', data.refresh_token)\n\t\t}\n\t\treturn data\n\t}\n\n\tasync function refreshToken(req, next)\n\t{\n\t\tlet refreshTokenReq = getAccessTokenRequest('refresh_token')\n\t\tlet response = await oauth2.client.get(refreshTokenReq)\n\t\tif (!response.ok) {\n\t\t\tthrow metro.metroError(response.status+':'+response.statusText, await response.text())\n\t\t}\n\t\tlet data = await response.json()\n\t\toauth2.tokens.set('access_token', {\n\t\t\tvalue: data.access_token,\n\t\t\texpires: getExpires(data.expires_in),\n\t\t\ttype: data.token_type,\n\t\t\tscope: data.scope\n\t\t})\n\t\tif (data.refresh_token) {\n\t\t\toauth2.tokens.set('refresh_token', data.refresh_token)\n\t\t}\n\t\treturn data\n\t}\n\n\n\tfunction getAuthTokenURL() {\n\t\tif (!oauth2.endpoints.authorize) {\n\t\t\tthrow metro.metroError('oauth2mw: Missing options.endpoints.authorize url')\n\t\t}\n\t\tlet url = metro.url(oauth2.endpoints.authorize, {hash: ''})\n\t\tassert.check(oauth2, {\n\t\t\tclient_id: /.+/,\n\t\t\tredirect_uri: /.+/,\n\t\t\tscope: /.*/\n\t\t})\n\t\tlet search = {\n\t\t\tresponse_type: 'code',\n\t\t\tclient_id: oauth2.client_id,\n\t\t\tredirect_uri: oauth2.redirect_uri,\n\t\t\tstate: createState(40)\n\t\t}\n\t\tif (oauth2.scope) {\n\t\t\tsearch.scope = oauth2.scope\n\t\t}\n\t\treturn metro.url(url, { search })\n\t}\n\n\tfunction createState(length) {\n\t\tconst validChars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'\n\t\tlet randomState = ''\n\t\tlet counter = 0\n\t while (counter < length) {\n\t randomState += validChars.charAt(Math.floor(Math.random() * validChars.length))\n\t counter++\n\t }\n\t\toauth2.state.set(randomState)\n\t\treturn randomState\n\t}\n\n\tfunction getAccessTokenRequest(grant_type=null) {\n\t\tassert.check(oauth2, {\n\t\t\tclient_id: /.+/,\n\t\t\tclient_secret: /.+/,\n\t\t\tredirect_uri: /.+/\n\t\t})\n\t\tif (!oauth2.endpoints.token) {\n\t\t\tthrow metro.metroError('oauth2mw: Missing options.endpoints.token url')\n\t\t}\n\t\tlet url = metro.url(oauth2.endpoints.token, {hash: ''})\n\t\tlet params = {\n\t\t\tgrant_type: grant_type || oauth2.grant_type,\n\t\t\tclient_id: oauth2.client_id,\n\t\t\tclient_secret: oauth2.client_secret\n\t\t}\n\t\tif (oauth2.scope) {\n\t\t\tparams.scope = oauth2.scope\n\t\t}\n\t\tswitch(oauth2.grant_type) {\n\t\t\tcase 'authorization_code':\n\t\t\t\tparams.redirect_uri = oauth2.redirect_uri\n\t\t\t\tparams.code = oauth2.tokens.get('authorization_code')\n\t\t\tbreak\n\t\t\tcase 'client_credentials':\n\t\t\t\tthrow new Error('Not yet implemented') // @TODO:\n\t\t\tbreak\n\t\t\tcase 'refresh_token':\n\t\t\t\tthrow new Error('Not yet implemented') // @TODO:\n\t\t\tbreak\n\t\t}\n\t\treturn metro.request(url, {\n\t\t\tmethod: 'GET',\n\t\t\turl: {\n\t\t\t\tsearchParams: params\n\t\t\t}\n\t\t})\n\t}\n\n\tfunction isExpired(req) {\n\t\tif (req.oauth2 && req.oauth2.tokens && req.oauth2.tokens.has('access_token')) {\n\t\t\tlet now = new Date();\n\t\t\tlet token = req.oauth2.tokens.get('access_token')\n\t\t\treturn now.getTime() > token.expires.getTime();\n\t\t}\n\t\treturn false;\n\t}\n\n\tfunction getExpires(duration) {\n\t\tif (duration instanceof Date) {\n\t\t\treturn new Date(duration.getTime()); // return a copy\n\t\t}\n\t\tif (typeof duration === 'number') {\n\t\t\tlet date = new Date();\n\t\t\tdate.setSeconds(date.getSeconds() + duration);\n\t\t\treturn date;\n\t\t}\n\t\tthrow new TypeError('Unknown expires type '+duration);\n\t}\n\n\n}"],"names":["$parcel$export","e","n","v","s","Object","defineProperty","get","set","enumerable","configurable","$parcel$global","globalThis","$parcel$modules","$parcel$inits","parcelRequire","id","exports","init","module","call","err","Error","code","register","parcelRegister","$86c8ab3a59b0bae1$export$47616e9f7f5fe113","$86c8ab3a59b0bae1$export$b5fe3f66a567bec0","$86c8ab3a59b0bae1$export$7079e2c78c274c66","$86c8ab3a59b0bae1$export$785bb8ef7fad1f74","$86c8ab3a59b0bae1$export$388e0302ca0d9a41","$86c8ab3a59b0bae1$export$128fa18b7194ef","$86c8ab3a59b0bae1$export$5de500aade6bf050","options","params","FormData","option","entry","entries","append","Array","isArray","value","freeze","Proxy","target","prop","receiver","isProxy","source","$86c8ab3a59b0bae1$export$357889f174732d38","$86c8ab3a59b0bae1$var$metroURL","Symbol","$86c8ab3a59b0bae1$var$Client","url","window","location","verbs","tracers","constructor","String","assign","Function","addMiddlewares","param","verb","fetch","method","toUpperCase","middlewares","index","findIndex","m","concat","req","next","r","toLowerCase","slice","middleware","res","values","tracer","request","response","with","$86c8ab3a59b0bae1$var$bodyProxy","body","r1","ReadableStream","Blob","stream","start","controller","chunk","toString","URLSearchParams","ArrayBuffer","isView","enqueue","close","args","apply","has","ownKeys","Reflect","getOwnPropertyDescriptor","requestParams","duplex","URL","$86c8ab3a59b0bae1$var$getRequestParams","current","DataView","TypedArray","JSON","stringify","Request","$86c8ab3a59b0bae1$var$getResponseParams","responseParams","Response","status","headers","$86c8ab3a59b0bae1$var$appendSearchParams","searchParams","forEach","key","validParams","u","Location","search","includes","Number","Boolean","$86c8ab3a59b0bae1$var$metroConsole","error","message","details","console","info","group","name","groupEnd","add","delete","clear","$hkeot","$2ddd80d1adc2ea42$exports","$2ddd80d1adc2ea42$export$d7c4a0dd6a4567e5","$2ddd80d1adc2ea42$export$e20fbacbb41798b","$2ddd80d1adc2ea42$export$478159de811fd37d","$2ddd80d1adc2ea42$export$35dc45686fc2dbd7","$2ddd80d1adc2ea42$export$516e28dec6a4b6d4","$2ddd80d1adc2ea42$export$a9a18ae5ba42aeab","$2ddd80d1adc2ea42$var$enabled","data","pattern","problems","RegExp","element","push","test","fromEntries","p","length","wKey","wVal","result","$2ddd80d1adc2ea42$var$assertError","patterns","trace","$9cea4e31d030ec91$export$2e2bcd8739ae039","reviver","replacer","space","symbols","json","parse","text","metro","assert","mw","jsonmw","oauth2","localState","localStorage","getItem","setItem","stateMap","Map","tokens","state","endpoints","callbacks","client","client_id","client_secret","redirect_uri","grant_type","force_authorization","token","metroError","endpoint","callback","href","oauth2authorized","ok","getTokensFromLocation","history","pushState","hash","query","substr","storedState","isExpired","now","Date","getTime","expires","refreshToken","accessToken","Authorization","type","fetchToken","authReqURL","getAuthTokenURL","authorize","scope","response_type","createState","validChars","randomState","counter","charAt","Math","floor","random","tokenReq","getAccessTokenRequest","statusText","access_token","getExpires","expires_in","token_type","refresh_token","refreshTokenReq","duration","date","setSeconds","getSeconds","TypeError"],"version":3,"file":"everything.js.map","sourceRoot":"../"} \ No newline at end of file diff --git a/src/mw/oauth2.mjs b/src/mw/oauth2.mjs index a86955a..8772353 100644 --- a/src/mw/oauth2.mjs +++ b/src/mw/oauth2.mjs @@ -14,15 +14,15 @@ export default function oauth2mw(options) { } else { let stateMap = new Map() localState = { - get: () => stateMap.getItem('metro/state'), - has: () => stateMap.getItem('metro/state'), - set: (value) => stateMap.setItem('metro/state', value) + get: () => stateMap.get('metro/state'), + has: () => stateMap.get('metro/state'), + set: (value) => stateMap.set('metro/state', value) } } const oauth2 = { tokens: new Map(), - state: (typeof localStorage !== 'undefined' ? localStorage : new Map()), + state: localState, endpoints: {}, callbacks: {}, client: metro.client().with(jsonmw()), @@ -111,10 +111,16 @@ export default function oauth2mw(options) { async function oauth2authorized(req, next) { getTokensFromLocation() if (!oauth2.tokens.has('access_token')) { - await fetchToken(req) + let token = await fetchToken(req) + if (!token) { + return metro.response('false') + } return oauth2authorized(req, next) } else if (isExpired(req)) { - await refreshToken(req) + let token = await refreshToken(req) + if (!token) { + return metro.response('false') + } return oauth2authorized(req, next) } else { let accessToken = oauth2.tokens.get('access_token') @@ -165,6 +171,8 @@ export default function oauth2mw(options) { let token = await oauth2.callbacks.authorize(authReqURL) if (token) { oauth2.tokens.set('authorization_code', token) + } else { + return metro.response(false) } } let tokenReq = getAccessTokenRequest() @@ -190,7 +198,7 @@ export default function oauth2mw(options) { let refreshTokenReq = getAccessTokenRequest('refresh_token') let response = await oauth2.client.get(refreshTokenReq) if (!response.ok) { - throw metro.metroError(res.status+':'+res.statusText, await res.text()) + throw metro.metroError(response.status+':'+response.statusText, await response.text()) } let data = await response.json() oauth2.tokens.set('access_token', { @@ -216,15 +224,16 @@ export default function oauth2mw(options) { redirect_uri: /.+/, scope: /.*/ }) - return metro.url(url, { - search: { - response_type: 'code', - client_id: oauth2.client_id, - redirect_uri: oauth2.redirect_uri, - scope: oauth2.scope, - state: createState(40) - } - }) + let search = { + response_type: 'code', + client_id: oauth2.client_id, + redirect_uri: oauth2.redirect_uri, + state: createState(40) + } + if (oauth2.scope) { + search.scope = oauth2.scope + } + return metro.url(url, { search }) } function createState(length) { @@ -261,7 +270,6 @@ export default function oauth2mw(options) { case 'authorization_code': params.redirect_uri = oauth2.redirect_uri params.code = oauth2.tokens.get('authorization_code') - params.response_type = 'token' // spec #3.1.1 break case 'client_credentials': throw new Error('Not yet implemented') // @TODO: